diff --git a/.travis.yml b/.travis.yml index 71606e74c..74e5701ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,17 @@ language: cpp compiler: gcc -before_install: - - sudo apt-get update -qq - - sudo apt-get install -y libmysqlclient-dev libperl-dev libboost-dev liblua5.1-0-dev zlib1g-dev +sudo: false +addons: + apt: + packages: + - libmysqlclient-dev + - libperl-dev + - libboost-dev + - liblua5.1-0-dev + - zlib1g-dev script: - cmake -G "Unix Makefiles" -DEQEMU_BUILD_TESTS=ON -DEQEMU_ENABLE_BOTS=ON - - make + - make -j8 - ./bin/tests branches: only: diff --git a/CMakeLists.txt b/CMakeLists.txt index 455b59f22..9e3ebb4ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ #EQEMU_BUILD_LUA #EQEMU_SANITIZE_LUA_LIBS #EQEMU_BUILD_CLIENT_FILES +#EQEMU_USE_MAP_MMFS #EQEMU_MAP_DIR #We set a fairly new version (as of 2013) because I found finding perl was a bit... buggy on older ones @@ -277,6 +278,11 @@ IF(EQEMU_BUILD_LUA) ADD_DEFINITIONS(-DLUA_EQEMU) ENDIF(EQEMU_BUILD_LUA) +OPTION(EQEMU_USE_MAP_MMFS "Create and use Zone Map MMF files." OFF) +IF(EQEMU_USE_MAP_MMFS) + ADD_DEFINITIONS(-DUSE_MAP_MMFS) +ENDIF(EQEMU_USE_MAP_MMFS) + SET(EQEMU_MAP_DIR "./Maps" CACHE STRING "The dir that maps, water maps, and paths are located in.") ADD_DEFINITIONS(-DEQDEBUG=${EQEMU_DEBUG_LEVEL}) diff --git a/README.md b/README.md index 0c973ed43..154703a75 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ EQEmu === -[![Build Status](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) +[![Linux CI](https://travis-ci.org/EQEmu/Server.svg?branch=master)](https://travis-ci.org/EQEmu/Server) +[![Windows CI](https://ci.appveyor.com/api/projects/status/d0cvokm7u732v8vl/branch/master?svg=true)](https://ci.appveyor.com/project/KimLS/server/branch/master) Overview --- diff --git a/changelog.txt b/changelog.txt index 09cd52d88..7647ea8ec 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,466 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 08/14/2016 == +mackal: Implement Linked Spell Reuse Timers + - For whatever reason this is a bit unfriendly, but that's how it is on live. + - Titanium is especially unfriendly with large differences in reuse times (ex higher canni and the first 4) + - Unsure when this went live for spells, but canni was at least linked at OoW launch + +== 08/13/2016 == +Kinglykrab: Implemented optional avoidance cap rules. + - Serves to eliminate God-like characters on custom servers with high item stats + - Rule Names: + - Character:EnableAvoidanceCap (default is false) + - Character:AvoidanceCap (default is 750, beyond 1,000 seems to make characters dodge all attacks) + +== 08/02/2016 == +Uleat: Changed 'SendZoneSpawnsBulk' behavior to use near/far criteria (live-like) when sending packets. + - Zone-to-Zone client loading will see a small decrease in time (less than 10~15%) + - World-to-Zone client loading appears to greatly benefit from this (tested 'devastation' - pre-change: ~22 seconds, post-change: 12~15 seconds) + - This change does not affect the final spawning of mobs in the client + +== 07/31/2016 == +mackal: Implement more spell gems! + - There are a few things still left to due like make dealing with losing gems nice (reset AAs, going to an older client etc) + - Sadly SoF disc release doesn't support gem 10 like one might expect :( + - So changed clients: + - SoD = 10 + - UF = 12 + - RoF/RoF2 = 12. I know the UI supports 16, but the client does not and can cause client crashes + - The quest APIs assume you pass a valid spell gem ... + +== 07/28/2016 == +Uleat: Implemented zone memory-mapped file usage + - Zone map files are converted to pre-loaded binary files, bypassing the (sometimes) time-consuming raw data transform process + - There are three ways to convert files: + -- Do nothing! The zone bootup process will check for a mmf file and load it, if found, or create it after the 'normal' transform process is complete + -- Use the command line option: zone convert_map .map (for singular conversions) + -- Drop the 'convert_maps_to_mmfs.pl' into your server directory and execute it for a batch conversion + -- Note: Any zone maps not pre-converted will be processed once a zone is booted up that does not have one + - To enable this feature, you must have the 'USE_MAP_MMFS' option checked in cmake and have built binaries on that + - To disable this feature, or if you encouter problems, disable the 'USE_MAP_MMFS' option and rebuild your binaries + - This feature will test the validity of your zlib library. If you get errors/crashes upon conversion, then your zlib1.dll is most likely suspect (check our forum for solutions) + +== 07/25/2016 == +mackal: Fix up the SpellBuff struct + - THERE MAYBE BUGS + - there shouldn't though, most of the hackery was from badly named fields causing confusion + +== 07/09/2016 == +Uleat: Important fix for mob pathing + - This should fix failed pathing issues (and high cpu usage for zone.exe) for mobs in affect zones + - Changed variable 'gridno' type from int16 to int32 to reflect actual return value of fetch (values do exceed 32767 aka int16.max) + - Precision loss from int32 to int16 conversion was causing grid id to be changed to quest controlled movement in cases where (gridno & 0x8000 == true) + +== 06/28/2016 == +Noudess: Resurrection effects now block certain buffs like on live. +Noudess: Added message about why spells are blocked (rule based) +Noudess: Added new rule: Client:UseLiveBlockedMessage +Uleat: Fix for bot inventory save failure involving items with unlimited charges + +== 06/13/2016 == +Noudess: Changes personal faction earned min/max to -2000/2000 from -3000/1200 + +== 06/06/2016 == +Uleat: Reworked EQEmuDictionary to use class LookupEntry + +== 06/01/2016 == +Uleat: Implemented EQEmu::TintProfile +Uleat: Implemented EQEmu::TextureProfile + +== 05/31/2016 == +Uleat: Converted enumeration MaterialSlots to EQEmu::textures::TextureSlot + +== 05/28/2016 == +Uleat: Merged client_version and inventory_version into emu_versions files + +== 05/27/2016 == +Uleat: Renamed EQEmu::Item_Struct to EQEmu::ItemBase (and appropriate files) to coincide with new inventory naming conventions + +== 05/25/2016 == +Uleat: Renamed and moved enumeration SkillUseTypes to EQEmu::skill::SkillType - added class EQEmu::SkillProfile, though not implemented at this time +Uleat: Some more work on eq_dictionary + +== 05/21/2016 == +Uleat: Moved struct Item_Struct into namespace EQEmu along with associated enumerations - enumerations into namespace EQEmu::item (run shared_memory) +Uleat: Fixed a few possible crash points in linux builds associated with augments/ornamentations + +== 05/18/2016 == +Uleat: Changed client 'constants' files to 'limits' + +== 05/10/2016 == +Uleat: Converted client translators' 'SerializeItem()' to recursive, single buffer methodology. Titanium SerializeItem() now adds a null term between parent items instead of the invoking function +Uleat: Converted server 'BulkSendInventoryItems()' to use single buffer methodology +Uleat: Added 'ItemInst::Serialize()' overload to make use of the above single buffer methodology + +== 05/08/2016 == +Uleat: Re-coded Titanium client translator 'SerializeItem()' to use coded property assignments over file enumerated ones + +== 04/22/2016 == +Uleat: Reworked ClientVersion into namespace EQEmu; Added InventoryVersion +Uleat: Delinked current inventory slot enumeration and constants from EQEmu::constants and global definition (inv2 pre-work) + +== 04/19/2016 == +Uleat: Changed the recent EQEmu rework to eliminate the nested class design (possible cause of VS2015 update crashes - unverified) +Uleat: Some more inv2 convergence work + +== 04/15/2016 == +Uleat: Reworked EQDictionary into namespace EQEmu + +== 04/08/2016 == +Uleat: Added Heal Rotation HOTs (Heal Override Targets) that can be set for proactive healing (default HR behavior is reactive) +Uleat: Added the ability to save/load/delete Heal Rotations based on targeted member - load is automatic when ^hrcreate is used on a bot that has a saved HR entry + +== 04/07/2016 == +Uleat: Rework of eq_dictionary to facilitate inventory work + +== 04/05/2016 == +Uleat: Moved database query code out of bot.cpp and into the new BotDatabase class + +== 03/25/2016 == +Uleat: Fix for heal rotation 'Stack Overflow' error +Kayen: Defensive procs will now only proc once per attack round (instead of every attack chance). + Live like modifier added that decreases defensive proc chance if you are higher level then your attacker. + +== 03/24/2016 == +Kayen: Fix for AE taunt to use correct range and hate modifier. + Fix for spell effect version of taunt to use correct range. +Uleat: Activation of new 'Bots' command system + - You will need to re-run cmake to capture the file additions and then re-compile your server binaries + - You will also need to manually run eqemu_update.pl and select the bots update option - you should have 2 pending updates: 9001 & 9002 + - The new command system is accessed with the '^' character - start with '^help' and see where that takes you + - More information can be found on the eqemu forums + +== 03/05/2016 == +mackal: Implement extra bind points (secondary recall) + For SE_Gate, base2 is which bind to use (starting at 1) + For SE_BindAffinity, base1 is which bind to set (starting at 1) + For SE_GateCastersBindpoint, base1 is which bind to use (starting at 1) + There was actually no spells that don't send to the main bind, but it uses a base1 of 1 which matches with SE_Gate + This also doesn't break anything + +== 03/01/2016 == +Uleat: Fix for LDoN treasure 'npcs' not leaving a corpse (please report any issues..) + +== 02/29/2016 == +Uleat: Change in AddItemBonuses - now includes ammo slot for skill mods only. Defined SoD- client SkillModMax packet property (client does not show..but, does enforce.) + +== 02/11/2016 == +Hateborne: Added IgnoreSpellDmgLvlRestriction rule (boolean) to ignore the 5 level spread when checking to add SpellDmg + +== 02/10/2016 == +Hateborne: Added FlatItemExtraSpellAmt rule (boolean) to allow SpellDmg on items to be added as raw damage versus scaled. + +== 01/26/2016 == +Uleat: Fix for Berserker 'Piercing' skill issues. Server Admins: If you run custom skill sets, this patch touches the code segments that you will need to modify if you have changed the default berserker 1H-/2H-piercing skill values. +Uleat (Daerath): Fix for precision-loss item weight conversions in older clients. + - WARNING: YOU MUST RE-RUN SHARED_MEMORY.EXE BEFORE STARTING SERVER OR ITEM LOSS WILL OCCUR! + - Note: Cmake must be re-run to include/exclude the required files + +== 01/13/2016 == +Kinglykrab: Modified #flag so you can refresh your target's account status (GM status level) without them having to relog. + - Just target the person whose flag you want to refresh and type #flag. +Uleat: Added itemlink functionality to the #summonitem command. Current use is limited to extracting the item id from the link. + - Invoking by item link '#summonitem Arrow' produces the same result as by item id '#summonitem 8005' + +== 01/12/2016 == +Athrogate: Adding ClearCompassMark() to Lua. + - Lua didn't have ClearCompassMark(). Perl already had this. + +== 01/12/2016 == +Uleat: Fix for tradeskill containers remaining locked after a RoF+ client leaves. Intermediary fix for RoF+ clients accessing tradeskill containers when in use by another player (thanks Natedog!) + +== 12/29/2015 == +Akkadius: Implemented standardized zone controller scripts (Rule Zone, UseZoneController) Defaulted to true + - When a zone boots, it will spawn an invisible npc by the name of zone_controller + - Lua and Perl scripts can be represented with this npc as zone_controller.pl/lua + - This NPC's ID is ruled be define ZONE_CONTROLLER_NPC_ID 10 + - Two EVENT's uniquely are handled with this NPC/controller (They only work with the zone_controller NPC) + - EVENT_SPAWN_ZONE :: All NPC spawns in the zone trigger the controller and pass the following variables: + $spawned_entity_id + $spawned_npc_id + - EVENT_DEATH_ZONE :: All NPC deaths in the zone trigger the controller event and pass the following variables: + $killer_id + $killer_damage + $killer_spell + $killer_skill + $killed_npc_id + +== 12/28/2015 == +Kinglykrab: Added GetInstanceTimer() to Perl and Lua. + - Added GetInstanceTimerByID(instance_id) to Perl and Lua. + - Note: If you do not provide an instance id in the method it defaults to instance id 0 and returns 0 for time remaining. + - Added UpdateZoneHeader(type, value) to Perl and Lua. + - Note: UpdateZoneHeader allows you to manipulate fog color, fog density, and many other zone header settings on the fly in Perl and Lua. + +== 12/21/2015 == +Natedog: Updated item table fields and added a few missing fields for evolving items + -DO NOT implement Heirloom items till the inventory code is fixed to allow placing NO DROP + items in your shared bank. (but item field located on items table) + -NYI - SkillModMax: Max skill point modification from the percent mods. EX: + 100% 2HSlashing (Max 50) - can only increase 2hslash by 50 MAX! (item field located though) +Kinglykrab: Added GetMeleeMitigation() for NPCs and Clients in Perl and Lua. + - This allows you to check total item, spell, and AA melee mitigation contribution. + +== 12/19/2015 == +Kinglykrab: Added many methods to Perl and Lua, list below: + - SeeInvisible() + - SeeInvisibleUndead() + - SeeHide() + - SeeImprovedHide() + - GetNimbusEffect1() - returns first nimbus effect + - GetNimbusEffect2() - returns second nimbus effect + - GetNimbusEffect3() - returns third nimbus effect + - IsTargetable() + - HasShieldEquiped() + - HasTwoHandBluntEquiped() + - HasTwoHanderEquiped() + - GetHerosForgeModel() - returns int32 Hero's Forge model + - IsEliteMaterialItem() - returns uint32 Hero's Forge Model + - GetBaseSize() - returns Mob's base size + - HasOwner() + - IsPet() + - HasPet() + - IsSilenced() + - IsAmnesiad() + +== 12/16/2015 == +Noudess: Repaired issue with Bind Wounds on someone else. Message was not coming out on client (hold still) and a bind wounds on someone already binding their wounds would interrupt their bind and make them stand. Also removed some duplicate messaging. + +== 12/14/2015 == +Kinglykrab: Added IsBlind() and IsFeared() functionality to Perl and Lua. + - Note: Both methods are Mob methods and may be used on NPCs or PCs. +Natedog: Added Discipline functions, UpdateInstanceTimer function, and UnmemSpellBySpellID to lua and perl + -Examples: http://wiki.eqemulator.org/i?M=Pastebin&Paste=BJ0ygmNM + +== 12/07/2015 == +Uleat: Command aliases are no longer handled through the command_add() function. + - To add a command alias, edit the database table `command_settings` - here, you will find three columns: `command`, `access` and `aliases` + - Adding command aliases require that the command contain an entry in `command_settings`.`command` + - Only 'real' commands go inside of the command_init() function in command.cpp .. if you wish to add aliases, you must enter them into the database + - 'Real' commands are loaded first .. then any access/alias data is loaded and applied afterwards + - Duplicate aliases will be ignored .. only the first encountered occurrence will be honored - if it does not conflict with an existing command name + - Aliases should not contain whitespace and should be '|' (pipe) delimited + - The restriction on the number of aliases has been removed .. though each alias will still be limited to the access level of the parent command + - If you need need more name space for aliases, simply edit the `command_settings` table and increase the size of the `aliases` column + - The old `commands` table has been renamed to `commands_old` for reference + - All of the current 'standard' commands have been added to the new `command_settings` table + + - YOU WILL NEED TO VERIFY/IMPORT OLD ACCESS VALUES AS THIS CHANGE REVERTS ALL COMMAND ACCESS VALUES TO THEIR PEQDB DEFAULTS + +== 11/30/2015 == +Uleat: Changed criteria for a few bots scripts from count to null/not null in hopes of fixing special case failures + +== 11/22/2015 == +Uleat: Fix for loginserver project compile failure + +== 11/7/2015 == +Akkadius: Implemented #repopclose [distance in units] - Used for development purposes, defaults to 500 units + - Real case use: Large zones with 700 NPC's and you are making fast quick tweaks to nearby NPC's you can refresh just the NPC's around you instead of all in the zone + - This can be quite the time saver + - This command will depop all NPC's and only respawn the NPC's that are 500 units around you or unless you specify otherwise + +== 11/2/2015 == +Akkadius: Performance boost (exponential) - Adjusted default idle cast check timers in rules + - Spells:AI_IdleNoSpellMinRecast 500 (Now 6000) 6 seconds + - Spells:AI_IdleNoSpellMaxRecast 2000 (Now 60000) 60 seconds + - Database version 9089 will take care of this update automatically only if you used the default values + - The CPU cost of NPC's checking the entire entity list to cast beneficial spells (Heals/Buffs) becomes extremely high when higher NPC count zones exist (Based off of process profiling) + - Distance checks for every single NPC to every single other NPC who are casting beneficial spells occur every .5 - 2 seconds unless npc_spells dictates other values, which most of the time it does not + - Zones that once fluctuated from 1-8% CPU with no activity (Idle but players present) now idle at .5% based on my testings due + to this change in conjunction with the past few performance commits, these are zones that have 600-800 NPC's in them + - These values normally are overidden by the spells table (npc_spells), fields (idle_no_sp_recast_min, idle_no_sp_recast_max) + +== 11/1/2015 == +Akkadius: Made many performance optimizing oriented code changes in the source + - Added Rate limit the rate in which signals are processed for NPC's (.5 seconds instead of .01 seconds) +Akkadius: Added Perl Export Settings which should heavily reduce the Perl footprint + - Normally when any sub EVENT_ gets triggered, all kinds of variables have to get exported every single time an event is triggered and + this can make Perl very slow when events are triggered constantly + - The two most taxing variable exports are the item variables ($itemcount{} $hasitem{} $oncursor{}) and qglobals ($qglobals{}) + - qglobals can pose to be an issue quickly when global qglobals build up, it is highly recommend to use the GetGlobal() and SetGlobal() + methods instead as they don't reference the hashmap $qglobals{} that is rebuilt every single time a sub event is triggered + - A stress test conducted with 10,000 samples shows an excess of time taken to export variables: http://i.imgur.com/NEpW1tS.png + - After the Perl Export Settings table is implemented, and all exports are shut off you see the following test result: + http://i.imgur.com/Du5hth9.png + - The difference of eliminating uneeded exports brings the overhead and footprint of 10,000 triggers from 54 seconds to 2 seconds + - In a 10,000 sample test (10,000 sub event triggers), exporting item variables adds 12 seconds alone, when item variables are only needed in + EVENT_ITEM and EVENT_SAY a majority of the time if at all + - In a 10,000 sample test (10,000 sub event triggers), exporting qglobals with approximately 1,000 global qglobals in the database creates + about 11-20 seconds of delay on its own (Depending on hardware of course) + - I've written a parser that has determined which of these exports are needed in which sub routines and have turned off all of the unneeded + exports in sub routines that do not need them and used it to create the default table that will be installed in the database. + - The export table is called 'perl_event_export_settings' and it resembles the following structure and contains all current 81 EVENTS + - If an entry doesn't exist in this table and a new subroutine is added to the source, all exports will be on by default for that routine + + +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ + | event_id | event_description | export_qglobals | export_mob | export_zone | export_item | export_event | + +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ + | 0 | EVENT_SAY | 1 | 1 | 1 | 1 | 1 | + | 1 | EVENT_ITEM | 1 | 1 | 1 | 0 | 1 | + | 2 | EVENT_DEATH | 1 | 1 | 1 | 0 | 1 | + | 3 | EVENT_SPAWN | 1 | 1 | 1 | 0 | 1 | + | 4 | EVENT_ATTACK | 0 | 1 | 1 | 0 | 1 | + | 5 | EVENT_COMBAT | 1 | 1 | 1 | 0 | 1 | + +----------+-----------------------------------------+-----------------+------------+-------------+-------------+--------------+ + + - If a change is made to this table while the server is live and running, you can hot reload all zone process settings via: + #reloadperlexportsettings + - For those who wonder what "exports" are, they are reference to variables that are made available at runtime of the sub event, such as: + (export_qglobals) (Heavy) : $qglobals https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L916 + (export_item) (Heavy) : $itemcount{} $hasitem{} $oncursor{} https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1103 + (export_zone) : $zoneid, $instanceid, $zoneln etc. https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1083 + (export_mob) : $x, $y, $z, $h, $hpratio etc. https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1032 + (export_event) : (event specific) IE: EVENT_SAY ($text) https://github.com/EQEmu/Server/blob/master/zone/embparser.cpp#L1141 + +== 10/16/2015 == +Uleat: Added command '#bot clearfollowdistance [ | spawned | all ]' to coincide with the activation of the load/save feature for follow_distance + +== 10/13/2015 == +Uleat: Important update to 2015_09_30_bots.sql - fix for orphaned entries causing crashes during the conversion process +Note: Please visit the thread below if you encounter issues during the conversion process + +== 10/12/2015 == +Uleat: Implemented 'bots' database versioning +Note: See thread for more information: http://www.eqemulator.org/forums/showthread.php?t=40091 + +Kayen: Feign death will now break when hit by casted spells, consisted with live. +Implemented suport for AA/spell effect which provides a chance to avoid FD breaking from spells. + +== 10/10/2015 == +Kayen: Updated mechanics to be consistent with live regarding how invisible breaks when the client is the target of a spell. +Invisible will drop whenever a client is hit with a detrimental spell, regardless of if resisted, if it does damage or AOE. +Hide skill now also follows the same rules as above. +Implemented support for Rogue AA - Nerves of Steel which gives a chance for hide NOT to break +when client is hit with an AOE spell. + +== 09/25/2015 == +Uleat: Implemented 'Inventory Snapshot' feature to track online player inventories at timed intervals. +rules: + 'Character:ActiveInvSnapshots' - active (true) or inactive (false - default) + 'Character:InvSnapshotMinIntervalM' - minimum time between snapshots (in minutes) + 'Character:InvSnapshotMinRetryM' - minimum time to attempt a retry after a failed snapshot (in minutes) + 'Character:InvSnapshotHistoryD' - minimum time to keep snapshot entries (in days) +commands: + '#invsnapshot' - Takes a snapshot of target client's inventory (feature active or inactive) + '#clearinvsnapshots [use rule]' - Clears snapshot entries based on bool argument ([true] - honors the 'InvSnapshotHistoryD' rule, [false] - erases all) + +== 08/02/2015 == +Shendare: VS2013 query StringFormat glitches when "%f" is passed for the int GetRunSpeed(). +Shendare: In CreateNewNPCCommand(), the npc_type_id and spawngroupid are created in the database, but never set in the spawn class, so later it can't delete them with #npcspawn remove or #npcspawn delete. + +== 07/27/2015 == +Uleat: Reworked the QS Audit code in Handle_OP_ShopPlayerBuy (\zone\client_packet.cpp) to help eliminate potential for exception errors + +== 07/22/2015 == +mackal: Corrected some hate value calcs based on updated http://www.eqemulator.org/forums/showthread.php?t=39819 + + Rule Aggro:MaxStunProcAggro to Aggro:MaxScalingProcAggro since the cap applies to more than stuns + +== 07/16/2015 == +mackal: Rework spell aggro based on http://www.eqemulator.org/forums/showthread.php?t=39819 + +== 07/15/2015 == +Hateborne: Added optional ability to enforce task level requirements in perl and lua via an added, optional parameter to $client->AssignTask and quest::assigntask. + Use cases: + quest::assigntask(703); # this still assigns the task as normal, no functional change + quest::assigntask(703, 1); # this will assign the task, provided the character meets the db-stored level requirements + $client->AssignTask(703, $npc->GetID()); # still assigns the task as normal, no functional change + $client->AssignTask(703, $npc->GetID(), 1); # this will assign the task, provided the character meets the db-stored level requirements +== 07/06/2015 == +mackal: Implement Triple Attack Skill + Parses showed about rand(1000) for the chance, may need more investigating + Corrected Double Attack chances as well + Running optional 2015_07_06_TripleAttack.sql will set current toons to their max skill + This is optional because the admins might want to go a different route. + +== 07/05/2015 == +mackal: Rewrite NPC combat attack round logic + An NPC "quading" is really just an NPC with innate dual wield that doubles on both hands + The old rules allowed NPCs to hit 6 times in one round + NPCs also seem to have their own skill progression for DW/DA + See: http://www.eqemulator.org/forums/showthread.php?t=38708 + You can set Combat:UseLiveCombatRounds to false to use the old rules + PC Double Attack rates kind of follow the same thing but still needs to be implemented +Kinglykrab: WARNING: summonburriedplayercorpse is now summonburiedplayercorpse, getplayerburriedcorpsecount is now getplayerburiedcorpsecount, summon_burried_player_corpse is now summon_buried_player_corpse, and get_player_burried_corpse_count is now get_player_buried_corpse_count FIX THESE IN YOUR SCRIPTS OR THEY WILL NOT WORK!!!! + Added bot saylinks (thanks Uleat!) + Command aliases for #augmentitem (#aug), #findnpctype (#fn), #findspell (#fs) + Bot command changes: #bot sow -> #bot speed, #bot magepet -> #bot setpet, #bot resurrectme -> #bot resurrect + Changed all occurrences of burried to buried in the code. + client_packet.cpp was referencing old columns in character_corpses, not sure how we didn't already see this before. + +== 7/4/2015 == +mackal: Reworked the activated avoidace skills (riposte, dodge, etc) based on dev quotes + This also fixes the order things are checked (avoidance skills, THEN hit/miss) + Also riposte immunity from the increase riposte chance spell effect. + +== 7/2/2015 == +KLS/Demonstar55: AA system has been rewritten fixing a ton of bugs and extending functionality while making it easier to create new AA points. +KLS/Demonstar55: New tables are needed and so older data will need to be migrated to the new system. +KLS/Demonstar55: The SQL saves the old aa points spent/avail/character_alt_abilities data if any server ops want to do something different than PEQ did with it. +KLS/Demonstar55: Will try to get a wiki entry written up next week some time explaining the system but it's really not hard to follow the db tables in the meantime. + +== 7/1/2015 == +Akkadius: Fix an issue where emote messages would overflow the buffer of 256 by increasing the size and changing some of the initialization +Akkadius: Added a custom Health Update message that will display in the middle of the players screen, to enable this server wide you must enable rule 'Character:MarqueeHPUpdates' + Example: https://www.youtube.com/watch?v=KUVdbPxLIn0 +Akkadius: (Haynar) Fixed some runspeed issues with Perl and LUA scripts +Akkadius: (Haynar) Updated #showstats and #npcstats for new speed calcs to display speeds again in familiar float format. +Akkadius: (Haynar) Improved client movement while AI Controlled, such as feared and charmed. Movement will be much smoother from clients perspective. + +== 06/12/2015 == +Uleat: Adjusted SessionStats to better reflect a sister implementation + +== 06/07/2015 == +Uleat: Implemented optional rule for using disenchanted bags. Action triggers at the same point that temporary items are removed. +Optional SQL: utils/sql/git/optional/2015_06_07_TransformSummonedBagsRule.sql +mackal: changes to AA packets since more fields have been identified +mackal: fix exploit with expendable AAs punching holes in the aa_array and staying around longer than they are welcomed + +== 05/25/2015 == +Akkadius: Implemented disjointed zone based time, this can be triggered via quest methods +Akkadius: Added parameter to LUA and Perl method settime(hour, minute, [update_world = true]) + - If update_world is false, the zone will then unsubscribe itself from regular worldserver time synchronizations + - Basically this localizes the zones time and keeps it from syncing with world updates +Akkadius: Added DB ver 9082 with update to add npc_types texture columns if table does not currently have them + +== 05/22/2015 == +Uleat: Added null-term declaration for character names in ENCODE(OP_CharInfo) - where appropriate + +== 05/20/2015 == +demonstar55: Bard instrument mods should be more consistent with live. Zoning will keep instrument mod for long duration buffs (selo's) + Still need to have procs/doom effects to inherit the instrument mods from their source buff/whatever + +== 05/18/2015 == +KLS: Changed how fishing locates water to hopefully be a bit more accurate at the expense of a bit more cpu power per line cast. + +== 05/15/2015 == +Uleat: Added check to EntityList::CheckSpawnQueue() to bypass dereference if returned iterator is npc_list.end() - should fix the debug assertion failure crash + +== 04/30/2015 == +demonstar55: Implement mob and client melee push + You can set Combat:MeleePush to false to turn off or change Combat:MeleePushChance to increase the chance an NPC can be pushed + PCs are always pushed, need to do more testing to verify. + +== 04/22/2015 == +Uleat: Probable fix for 'Debug Assertion Failure' in Client::GarbleMessage() when calling the 'isalpha' macro. +ref: https://connect.microsoft.com/VisualStudio/feedback/details/932876/calling-isdigit-with-a-signed-char-1-results-in-a-assert-failure-in-debug-compiles + +== 03/29/2015 == +Secrets: Identified the Target Ring fields for RoF/RoF2. +Secrets: Added a perl accessor for the last target ring position received from the client. Usage: $client->GetTargetRingX(), $client->GetTargetRingY(), $client->GetTargetRingZ() + +== 03/12/2015 == +Akkadius: [eqemu_update.pl V7] Add Option 9) LUA Modules - Download latest LUA Modules (Required for Lua) + +== 03/11/2015 == +Akkadius: [eqemu_update.pl] Add Option 7) Plugins - Download latest Perl plugins +Akkadius: [eqemu_update.pl] Add Option 8) Quests - Download latest PEQ quests and stage updates +Akkadius: [eqemu_update.pl] Set version 5 of script + +== 03/10/2015 == +Akkadius: [eqemu_update.pl] Add Option 6) Download Latest map and water files + == 03/04/2015 == Akkadius: Fix Spell Book Deletion @@ -19,7 +480,7 @@ Notes: == 02/23/2015 == Noudess: Allow for a rule to set starting swimming && SenseHeading value. -I moved the swimming override to char create instead of setting it +I moved the swimming override to char create instead of setting it every time a char enters a zone. Also added rules to not ignore, but rather forrce sense heading packets to be @@ -87,7 +548,7 @@ Uleat: Removed 'limbo' from the 'HasItem' series of checks - including lore chec Uleat: Updated command #iteminfo to show light source information and a few other things == 02/05/2015 == -Trevius: Fixed Environmental Damage for RoF2. +Trevius: Fixed Environmental Damage for RoF2. == 02/03/2015 == Trevius: Crashfix for TempName() when numbers are passed at the end of the name. @@ -110,19 +571,19 @@ Akkadius: Add Packet Logging Categories - 39 - Packet: Server -> Client - Logs::Server_Client_Packet - 40 - Packet: Client -> Server Unhandled - Logs::Client_Server_Packet_Unhandled See: http://wiki.eqemulator.org/p?Logging_System_Overhaul#packet-logging - + == 01/31/2015 == Trevius: Fixed FindGroundZ() and GetGroundZ() to once again utilize the X and Y arguments that are passed to them. == 01/30/2015 == Akkadius: Implemented event type "EVENT_ENVIRONMENTAL_DAMAGE" - - This event triggers when taking any sort of environmental damage. Example use: + - This event triggers when taking any sort of environmental damage. Example use: sub EVENT_ENVIRONMENTAL_DAMAGE{ quest::debug("EVENT_ENVIRONMENTAL_DAMAGE"); quest::debug("env_damage is " . $env_damage); quest::debug("env_damage_type is " . $env_damage_type); quest::debug("env_final_damage is " . $env_final_damage); - } + } Result: (Test falling in Velks): http://i.imgur.com/tPRL7yL.png - Implemented LUA counterpart of this same implementation above Akkadius (Bobaski): Add PoK New Merchant sql/git/optional/2015_01_30_poknowledge_spell_vendors.sql @@ -141,7 +602,7 @@ Akkadius: Added Logs::DebugQuest category per request from Trevius (Great idea) quest::debug("This is a test debug message, level 1", 1); quest::debug("This is a test debug message, level 2", 2); quest::debug("This is a test debug message, level 3", 3); - + Result: http://i.imgur.com/6VoafGE.png - Uses traditional logging system to output this category - Required MySQL Source in Database version 9070 @@ -172,7 +633,7 @@ Notes: == 01/22/2015 == Akkadius: Massive Log System overhaul, see: http://wiki.eqemulator.org/p?Logging_System_Overhaul&frm=Main - + == 01/21/2015 == Uleat: Added `light` field to npc_types load query (all six clients tested positive for functionality.) Note: This only affects 'innate' light. Equipment (other) light is still in-work. @@ -214,7 +675,7 @@ Uleat: Added text link translators for OP_Emote Uleat: Added text link translators for OP_FormattedMessage == 01/08/2015 == -Trevius: Added some extra checks and clean-up related to Groups and Mercenaries. +Trevius: Added some extra checks and clean-up related to Groups and Mercenaries. == 01/07/2015 == Uleat: Excluded text link body from message scrambling in Client::GarbleMessage() @@ -386,10 +847,10 @@ Akkadius: Created database revision define, this is located in version.h in comm # empty = If the query results in no results # not_empty = If the query is not empty # 4 = Text to match - - The manifest contains all database updates 'Required' to be made to the schema, and it will contain a working backport all the way back to SVN - + - The manifest contains all database updates 'Required' to be made to the schema, and it will contain a working backport all the way back to SVN - currently it is tested and backported through the beginning of our Github repo - On world bootup or standalone run of db_update.pl, users will be prompted with a simple menu that we will expand upon later: - + ============================================================ EQEmu: Automatic Database Upgrade Check ============================================================ @@ -418,7 +879,7 @@ Database Management Menu (Please Select): Akkadius: Created db_update.pl, placed in utils/scripts folder, used for the automatic database update routine (Linux/Windows) - db_update.pl script created db_version table if not created, if old one is present it will remove it Akkadius: Created db_dumper.pl, placed in utils/scripts folder, used for the automatic database update routine backups and standalone backups (Linux/Windows) -Akkadius: World will now check the db_update.pl script on bootup, if the db_update.pl script is not present, it will fetch it remotely before running - +Akkadius: World will now check the db_update.pl script on bootup, if the db_update.pl script is not present, it will fetch it remotely before running - when db_update.pl is done running, world will continue with bootup == 11/15/2014 == @@ -596,10 +1057,10 @@ Akkadius: Removed #refundaa Akkadius: Removed a lot of debug code for blob conversion Akkadius: Changed status logging for loads/saves to Debug category -== 09/21/2014 == +== 09/21/2014 == Akkadius: Player Profile Blob to Database Conversion - Summary: HUGE difference in database speeds reads/writes and 1:10 datasize difference - - The new character storage engine unlike the character_ table before, is able to properly index data and make use of + - The new character storage engine unlike the character_ table before, is able to properly index data and make use of proper MySQL/MariaDB caching optimizations and performance has increased phenominally PERFORMANCE AND STATISTICS FIGURES (Varies on hardware): - EZ Server Character data size of 2.6GB `character_` table alone now takes up approx 600MB @@ -645,7 +1106,7 @@ Akkadius: Player Profile Blob to Database Conversion SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level); SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); - SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color); + SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color); SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value); SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value); SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id); @@ -656,7 +1117,7 @@ Akkadius: Player Profile Blob to Database Conversion - Deletes: DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); - DeleteCharacterDisc(uint32 character_id, uint32 slot_id); + DeleteCharacterDisc(uint32 character_id, uint32 slot_id); DeleteCharacterBandolier(uint32 character_id, uint32 band_id); DeleteCharacterLeadershipAAs(uint32 character_id); - Now occur all over the code and only trigger when necessary @@ -669,17 +1130,17 @@ Akkadius: Player Profile Blob to Database Conversion - NOTE: These amount of excessive saves have caused scalability issues that cause the `character_` table to hang which causes process hangs that affect the whole server because of the slowness of the `character_` table and the blob not allowing any indexing to occur - All functions that once depended on the `character_` table are now rewritten to appropriately read from the `character_data` table - - Database query errors that occur during conversion or from and load/save/delete character functions are now leveraged via ThrowDBError and logs now go to + - Database query errors that occur during conversion or from and load/save/delete character functions are now leveraged via ThrowDBError and logs now go to Server_Folder_Root/eqemu_query_error_log.txt (You cannot log errors natively through MySQL) - DBASYNC IS NOW COMPLETELY REMOVED - This was mainly for Character data async loads/saves and merchantlist loads - - Side implementations: + - Side implementations: Perl Exports: - quest::crosszonesetentityvariablebynpctypeid(npctype_id, id, m_var) - Sets entity variables world wide with specified npctype_id - quest::crosszonesignalnpcbynpctypeid(npctype_id, data) - Signals all NPC entities world wide with specified npctype_id - $client->GetTaskActivityDoneCount(TaskID, ActivityID) - Gets task activity done count by task id and activity id for client entity - + VIEW TABLE SIZE AFTER CONVERT: - + SELECT CONCAT(table_schema, '.', table_name) as table_name, CONCAT(ROUND(table_rows / 1000000, 2), 'M') rows, CONCAT(ROUND(data_length / ( 1024 * 1024 * 1024 ), 2), 'G') DATA, @@ -806,10 +1267,10 @@ Akkadius: Changed all QS Error related logging to 'QUERYSERV__ERROR' Akkadius: (Natedog) (Crash Fix) Legacy MySQL bug revert for loading AA's COALESCE( from COALESCE ( Akkadius: Implemented Perl Quest objects (LUA still needed to be exported): - quest::qs_send_query("MySQL query") - Will send a raw query to the QueryServ process, useful for custom logging - - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` + - quest::qs_player_event(char_id, event_desc); - Will process a quest type event to table `qs_player_events` Akkadius: Added MySQL Tables - `qs_player_aa_rate_hourly` - - `qs_player_events` + - `qs_player_events` - Source table structures from: - utils\sql\git\queryserv\required\08_23_2014_player_events_and_player_aa_rate_hourly To get the complete QueryServ schema, source from here: @@ -818,7 +1279,7 @@ Akkadius: Added rules for each logging type, source rules here with them enabled - utils\sql\git\queryserv\required\Complete_QueryServ_Rules_Enabled.sql Akkadius: Spawn related logging cleanup Akkadius: General code cleanup -Akkadius: More to come for QueryServ +Akkadius: More to come for QueryServ == 08/22/2014 == Uleat: Rework of Trade::FinishedTrade() and Trade::ResetTrade() to parse items a little more intelligently. @@ -862,8 +1323,8 @@ Uleat (Kingly_Krab): Fix for bot chest armor graphic glitch. (fix also caused Ro == 08/02/2014 == Kayen: Implemented spell_news fields -- npc_no_los (check if LOS is required for spells) -- InCombat, OutofCombat - Used together to restrict spells to only be cast while +- npc_no_los (check if LOS is required for spells) +- InCombat, OutofCombat - Used together to restrict spells to only be cast while in/out of combat (beneficial) or if target is in/out of combat (detrimental). -min_dist, min_dist_mod, max_dist, max_dist_mod - Scales spell power based on targets distance from caster. *This will require further work to fully implement but will work with 90% of live spells as is. @@ -896,7 +1357,7 @@ KLS: Changes to CMake build == 07/10/2014 == -Kayen: Updated table npc_spells to now support defensive and ranged procs. +Kayen: Updated table npc_spells to now support defensive and ranged procs. Note: Proc rate modifier work as it does for spell effects (ie 200 = 200% baseline chance modifier) Table is also now contains 12 AI spell casting variables that can be set to fine tune casting behaviors per spell set. Global default rules have also been added that can further fine tune all content if no specific variables are set. @@ -926,7 +1387,7 @@ Param2: Percent Chance to Hit modifier Param3: Percent Total Damage modifier Kayen: Updated to Chance to Hit code with how bonuses are applied to be consistent for all effects. -Added field to npc_types 'Avoidance' which will modify chance to avoid melee +Added field to npc_types 'Avoidance' which will modify chance to avoid melee Added rules to set max and min chance to hit from melee/ranged (Default 95% / 5%) Required SQL: utils/sql/git/required/2014_07_10_npc_spells.sql @@ -940,7 +1401,7 @@ Sympathetic foci on items with proc rate mod will now benefit from that modifier Sympathetic foci can now be placed on AA's (This should always be slot1 in the AA) Kayen: Implemented SE_IllusionPersistence- Allows illusions to last until you die or the illusion is forcibly removed. Kayen: Added rule 'PreNerftBardAEDot' for SE_BardAEDot to allow it to once again do damage to moving targets. (Set to true) -Kayen: Completely revised SE_SkillProc, SE_LimitToSkill, SE_SkillProcSuccess to overall just work better and more accurately, AA support. +Kayen: Completely revised SE_SkillProc, SE_LimitToSkill, SE_SkillProcSuccess to overall just work better and more accurately, AA support. Required SQL: utils/sql/git/required/2014_07_04_AA_Update.sql @@ -983,7 +1444,7 @@ Optional SQL: utils/sql/git/optiional/2014_06_29_HeadShotRules.sql == 06/17/2014 == Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. -These effects when present in buffs prevent each other from stacking, +These effects when present in buffs prevent each other from stacking, Any effect with B prevents A, C prevents B, D prevents C. Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) @@ -1033,7 +1494,7 @@ KLS: Implemented new map code based on some of Derision's earlier work. Old map == 04/27/2014 == Kayen: Implemented new table 'npc_spells_effects' and 'npc_spells_effects_entires'. Implemented new field in 'npc_spell_effects_id' in npc_types. - + These are used to directly apply spell effect bonuses to NPC's without requirings spells/buffs. Example: Allow an npc to spawn with an innate 50 pt damage shield and a 5% chance to critical hit. @@ -1050,7 +1511,7 @@ cavedude: Added strict column to spawn_events which will prevent an event from e cavedude: Prevented disabled or strict spawn_events from enabling when the zone first boots. cavedude: Fixed the quest function toggle_spawn_event under Perl. -If you're using the quest function toggle_spawn_event (worked on Lua only) it has changed syntax to: +If you're using the quest function toggle_spawn_event (worked on Lua only) it has changed syntax to: toggle_spawn_event(int event_id, bool enable, bool strict, bool reset_base) Required SQL: utils/sql/git/required/2014_04_25_spawn_events.sql @@ -1115,31 +1576,31 @@ Notes: See this thread for more information and to provide feedback: http://www.eqemulator.org/forums/showthread.php?p=229328#post229328 == 04/05/2014 == -Akkadius: Fix for the Fix for the Fix: Rule Combat:OneProcPerWeapon was created so that you can revert to the original proc functionality - for custom servers that have balanced their content around having more than 1 aug proc on weapons. By having this rule set to 'false' you revert this functionality. +Akkadius: Fix for the Fix for the Fix: Rule Combat:OneProcPerWeapon was created so that you can revert to the original proc functionality + for custom servers that have balanced their content around having more than 1 aug proc on weapons. By having this rule set to 'false' you revert this functionality. This rule is set to 'true' by default as the original functionality from Live was intended to be Akkadius: (Performance Adjustment) Removed AsyncLoadVariables from InterserverTimer.Check() in both zone and world. By watching the MySQL general.log file on mass zone idle activity, you can see that the query 'SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= timestamp' is called every 10 seconds. This function is loading - variables that are initially loaded on World and Zone bootup. When running a large amount of zone servers, the amount of MySQL chatter that is produced is enormous and + variables that are initially loaded on World and Zone bootup. When running a large amount of zone servers, the amount of MySQL chatter that is produced is enormous and unnecessary. For example, if I ran 400 zone servers, I would see 3,456,000 unnecessary queries from all idle or active zone processes in a 24 hour interval. Secrets: Added a rule to enable multiple procs from the same weapon's other slots if a proc is deemed to trigger, Defaults to true. If Combat:OneProcPerWeapon is not enabled, we reset the try for that weapon regardless of if we procced or not. This is for some servers that may want to have as many procs triggering from weapons as possible in a single round. - + Optional SQL: utils/sql/git/optional/2014_04_05_ProcRules.sql - + == 04/04/2014 == Kayen: Implemented 'Physical Resists' (Resist Type 9) to be consistent with live based on extensive parsing. - SQL will add new field to npc_types 'PhR' and fill in database with values consistent with observations. + SQL will add new field to npc_types 'PhR' and fill in database with values consistent with observations. Required SQL: utils/sql/git/optional/2014_04_04_PhysicalResists.sql == 04/03/2014 == -Kayen: Implemented live like spell projectiles (ie. Mage Bolts). +Kayen: Implemented live like spell projectiles (ie. Mage Bolts). Optional SQL: utils/sql/git/optional/2014_04_03_SpellProjectileRules.sql Note: The rules in this SQL are for setting the item id for the graphic used by the projectile on different clients. - + == 04/01/2014 == demonstar55: Implemented ability for a merchant to open and close shop. Lua quest functions: e.self:MerchantOpenShop() and e.self:MerchantCloseShop() @@ -1245,7 +1706,7 @@ cavedude: Exported TrainDisc to Lua. Kayen: Implemented SE_FrenziedDevestation - increase critical spell chacnce and 2x mana cost for DD spells Kayen: Fixed SE_SpellProcChance - Now works on spell dervived procs cavedude: Added two new NPC special_abilities. ALWAYS_FLEE, which forces the NPC to always flee ignoring FleeIfNotAlone and FLEE_PERCENT which allows you to change the HP an individual NPC will flee at. If no value is set, the rule is used as normal. -cavedude: Fixed an issue where rectangular roamboxes could cause an NPC to get stuck on a single coord. +cavedude: Fixed an issue where rectangular roamboxes could cause an NPC to get stuck on a single coord. cavedude: Added a new roambox column, mindelay allowing you to have more control over the roambox delay. Uleat: Fix for 'sqrt' failure on vs2010 clients image: Added idle zone timer to save CPU cycles. @@ -1269,7 +1730,7 @@ Required SQL: utils/sql/git/2014_02_20_buff_updates.sql == 02/18/2014 == Kayen: Implemented SE_TriggerOnReqCaster - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) Kayen: Implemented SE_ImprovedTaunt - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y -Kayen: Fixed an error where SE_ChangeAggro was adding its bonus x 2 for spell generated aggro. (this applies also to spell casting subtlety AA reduction) +Kayen: Fixed an error where SE_ChangeAggro was adding its bonus x 2 for spell generated aggro. (this applies also to spell casting subtlety AA reduction) == 02/14/2014 == Kayen: Fixes for buffs not fading under certain conditions in revised numhits system, and other fixes. @@ -1334,9 +1795,9 @@ Kayen: Changed SE_MitigateMeleeDamageSP -> SE_MeleeThresholdGuard Kayen: Implemented SE_SpellThresholdGuard (Partial Spell Rune that only is lowered if spell hits are over X amount of damage) Kayen: Implemented SE_TriggerSpellThreshold (implemented Trigger effect on X amount of spell damage taken) Kayen: Changed SE_ReduceHealing -> SE_FcHealAmtIncoming (focus limited Add/Remove amount of healing on target by X amount) -Kayen: Change SE_CriticalHealChance2 -> SE_CriticalHealDecay -Kayen: Change SE_CriticalHealOverTime2 -> SE_CriticalRegenDecay -Kayen: Implemented SE_CriticalDotDecay +Kayen: Change SE_CriticalHealChance2 -> SE_CriticalHealDecay +Kayen: Change SE_CriticalHealOverTime2 -> SE_CriticalRegenDecay +Kayen: Implemented SE_CriticalDotDecay Note: 'Decay' effects means the chance to critical decays based on the level of the spell using the effect (like focus decay) Kayen: Implemented SE_FfLimitUseMin (focus limit to require a min amount of numhits value) Kayen: Implemented SE_FcLimitUse (focus to increases numhits count by percent) @@ -1359,14 +1820,14 @@ demonstar55: Stuns from beneficial spells (Harvest) ignore immunity demonstar55: Added classes_required to merchantlist (same bitmask as items) == 12/24/2013 == -Secrets (Akkadius): Perl $client->SilentMessage("Message"); addition, this is a pre-req for a Perl plugin I've shared with EQEmu. This function essentially mimics a player speaking with an NPC - which is used in popup window responses -Secrets: Added functionality to Perl for $client->PlayMP3("name of file"). +Secrets (Akkadius): Perl $client->SilentMessage("Message"); addition, this is a pre-req for a Perl plugin I've shared with EQEmu. This function essentially mimics a player speaking with an NPC - which is used in popup window responses +Secrets: Added functionality to Perl for $client->PlayMP3("name of file"). Usage varies, but typically you can place an MP3/WAV/XMI in the EQDir//sounds, pfs, s3d, or root client folder and it will play through this Perl function. Example, $client->PlayMP3("combattheme1.mp3") or $client->PlayMP3("TUTBTrade1.mp3") - All clients except Secrets of Faydwer and 6.2 have their opcodes identified for this function. The struct + supported params is the same throughout versions. + All clients except Secrets of Faydwer and 6.2 have their opcodes identified for this function. The struct + supported params is the same throughout versions. Use $client->PlayMP3 with an invalid sound file to stop playback or simply wait for it to end. KLS: Added functionality to Lua for Client:PlayMP3(filename) KLS: Added functionality to Lua for Client:SendMarqueeMessage(type, priority/opacity, fade_in_time_ms, fade_out_time_ms, duration_ms, msg) - + == 12/16/2013 == Kayen: Implemented SE_ArcheryDoubleAttack (Chance to do an extra archery attack) Kayen: Implemented SE_ShieldEquipDmgMod (Increase damage in primary hand if shield equiped) @@ -1586,7 +2047,7 @@ Param2: Percent of a normal attack damage to deal (default: 100) Param3: Flat damage bonus to add to the rampage attack (default: 0) Param4: Ignore % armor for this attack (default 0) Param5: Ignore flat armor for this attack (default 0) -Param6: Percent of npc's natual crit that can go toward this rampage (default: 100) +Param6: Percent of npc's natual crit that can go toward this rampage (default: 100) Param7: Flat crit bonus on top of npc's natual crit that can go toward this attack (default 0) SPECATK_AREA_RAMPAGE = 4 @@ -1596,7 +2057,7 @@ Param2: Percent of a normal attack damage to deal (default: 100) Param3: Flat damage bonus to add to the rampage attack (default: 0) Param4: Ignore % armor for this attack (default 0) Param5: Ignore flat armor for this attack (default 0) -Param6: Percent of npc's natual crit that can go toward this rampage (default: 100) +Param6: Percent of npc's natual crit that can go toward this rampage (default: 100) Param7: Flat crit bonus on top of npc's natual crit that can go toward this attack (default 0) SPECATK_FLURRY = 5 @@ -1606,7 +2067,7 @@ Param2: Percent of a normal attack damage to deal (default: 100) Param3: Flat damage bonus to add to the flurry attack (default: 0) Param4: Ignore % armor for this attack (default 0) Param5: Ignore flat armor for this attack (default 0) -Param6: Percent of npc's natual crit that can go toward this attack (default: 100) +Param6: Percent of npc's natual crit that can go toward this attack (default: 100) Param7: Flat crit bonus on top of npc's natual crit that can go toward this attack (default 0) Ex: Normal Flurry with 25% proc rate and 100% crit chance that ignores 500 armor. @@ -1693,7 +2154,7 @@ Upgrade notes: -Some item quests have changed in a subtle way, though it's unlikely any quests are impacted and the thread has more information if you found any of your quests broke. As far as I know for example: PEQ didn't have to update any of its nearly 70 item quests. -Cazic Touch (982) no longer shouts the name of the thing it is targeting without a script. -EVENT_DEATH now triggers before the death is complete. For the old functionality you may use EVENT_DEATH_COMPLETE. It might be a good idea to replace all EVENT_DEATH with EVENT_DEATH_COMPLETE in existing spells. - + We sought to minimize changes required but it's still a bit disruptive so take a few minutes when upgrading to make sure everything is correct. Most notably quest::clearhandin was used in some popular plugins to avoid a dupe involved with its code and now that it's gone those will not function if fixes are not applied. == 06/16/2013 == @@ -1790,7 +2251,7 @@ demonstar55: Fixed stacking issues with SE_Limit* (ex. Unholy Aura Discipline an == 03/18/2013 == Bad_Captain: Fixed zone crash due to merc focus effects & tribute. -Bad_Captain: Fixed merc aggro issues when client in melee range & spell recast timers. +Bad_Captain: Fixed merc aggro issues when client in melee range & spell recast timers. Bad_Captain: Added melee DPS spells/disciplines & support. == 03/17/2013 == @@ -1803,9 +2264,9 @@ Derision: Fixed a couple of memory leaks in Rez code. == 03/14/2013 == JJ: (NatedogEZ) Fix for hate list random never selecting last member of hate list. -Bad_Captain: Fixed Merc spell recast timers. +Bad_Captain: Fixed Merc spell recast timers. Bad_Captain: Changed how Mercs add mobs to their hate lists (should prevent IsEngaged() issues). -Bad_Captain: Initial Caster DPS Merc spell casting AI, including initial Merc stance implementation. +Bad_Captain: Initial Caster DPS Merc spell casting AI, including initial Merc stance implementation. Bad_Captain: Mercs now suspend when their owner dies to prevent them being bugged (until it can be fixed). OPTIONAL SQL: 2013_03_14_Merc_Spells.sql @@ -1839,7 +2300,7 @@ REQUIRED SQL: 2013_03_1_Merc_Rules_and_Equipment.sql KLS: Changed how shared memory works: Instead of System V/windows pagefile shared memory we now have shared memory that's backed by the filesystem. What that means is basically instead of EMuSharedMem(shared library) we now have shared_memory(executable), shared memory will be persistent between runs until you delete or reload it using the shared_memory executable. - + STEPS FOR PEOPLE WHO CAN'T BE BOTHERED TO FIGURE IT OUT: 1) Create a directory in the place you run world/zone named shared and make sure files can write there. 2) Run the shared_memory executable from the same place you run world/zone (it's basically doing the loading we would do on startup so will take a moment). @@ -1898,7 +2359,7 @@ Uleat: Changed conversion of bot armor colors from long to unsigned long. Conver cavedude00: Added heading to start_zones Uleat: Fixed the 'nude' bot issue. Mob::texture was not set to the appropriate value and forcing an unclad body model. Uleat: Fixed the show/hide helm feature. Added rebroadcast of packet so that changes take place immediately instead of after zoning. -KLS: Addressed several (completely stupid and inexcusable) bugs in the avoidance code that made it impossible to dodge and parry in certain situations. +KLS: Addressed several (completely stupid and inexcusable) bugs in the avoidance code that made it impossible to dodge and parry in certain situations. As a note: please don't touch the avoidance code if you don't know what you're doing, seriously. Required SQL: utils/sql/svn/2482_required_start_zones.sql @@ -1985,7 +2446,7 @@ Uleat: Fixed a corpse looting issue where the power source item (slot 9999) was Uleat: Power Source items will now report in 'worn' instead of 'inv' when using #peekinv. == 01/20/2013 == -KLS: intN types have changed to more closely reflect C99 and C++11 types: +KLS: intN types have changed to more closely reflect C99 and C++11 types: intN was an unsigned int of N bits -> it is now a signed int of N bits. sintN was a signed int of N bits -> it has been removed in favor of intN. uintN is still unsigned. @@ -2039,7 +2500,7 @@ Trevius: RoF: Disciplines now update without zoning. == 01/12/2013 == Derision: RoF: Personal Tribute and the Pet Buff Window now work. -Derision: Fixed potential crash in SendPetBuffsToClient. +Derision: Fixed potential crash in SendPetBuffsToClient. Derision: RoF: Accounted for the fact the Duplicate Lore item message now includes the item's name. Trevius: RoF: The Task Selector Window is now functional. @@ -2069,7 +2530,7 @@ REQUIRED SQL: utils/sql/svn/2383_required_group_ismerc.sql -- adds ismerc col OPTIONAL SQL: utils/sql/svn/2380_optional_merc_rules.sql -- Contains rules for mercs including rule to enable mercs OPTIONAL SQL: utils/sql/svn/2380_optional_merc_merchant_npctypes_update.sql -- Contains npc_types & spawn updates for merc merchants in PoK OPTIONAL SQL: utils/sql/svn/2380_optional_merc_data.sql -- Contains basic merc data, template info, & merc merchant entries -OPTIONAL SQL: utils/sql/svn/mercs.sql -- Contains merc stats & armor - to be replaced as needed with updated stats, spells, etc. Allows a complete resourcing of file +OPTIONAL SQL: utils/sql/svn/mercs.sql -- Contains merc stats & armor - to be replaced as needed with updated stats, spells, etc. Allows a complete resourcing of file == 01/07/2013 == Trevius: RoF: /who and /who all now function properly. @@ -2226,7 +2687,7 @@ Secrets/Akkadius: Implemented the customary ability to scale an NPC's spell dama This will allow an NPC to do for example 150% of the damage of their damage spells if spellscale is set to '150' 'healscale' field needs to be set to affect heals in a similar manner Both of these can also be accessed via ModifyNPCStat through 'healscale' and 'spellscale' - + REQUIRED SQL: utils/sql/svn/2283_required_npc_changes.sql ==12/06/2012== @@ -2353,7 +2814,7 @@ Kayen: Fix for crippling blow chance, other minor fixes related to bonuses. ==09/20/2012== Kayen: AA dbase table fixes - Archery Mastery, Fury of Magic. -REQUIRED SQL: utils/sql/svn/2215_required_aa_updates +REQUIRED SQL: utils/sql/svn/2215_required_aa_updates ==09/19/2012== KLS: Faction mods (Race, Class, Deity) can now be added on the fly, without adding database columns or editing the code. Source in the database change, run utils/factionmod.pl, and then drop the faction_list table to convert. @@ -2375,7 +2836,7 @@ Kayen: Removed SE_Twinproc - This is not an actual spell effect, Twin proc is no Kayen: Implemented SE_TwoHandBluntBlock - Chance to block when using two hand blunt weapon (similiar to shield block). Kayen: SE_NegateEffect will now negate all AA, item and spell bonuses for the specified effects. Kayen: Added support to allow for certain bonuses to now properly be calculated when cast as debuffs (ie decrease chance to critical hit) -Kayen: Implemented rule to allow certain bonuses to be calculated by adding together the value from each item, instead of taking the highest value. +Kayen: Implemented rule to allow certain bonuses to be calculated by adding together the value from each item, instead of taking the highest value. *Ie. Add together all worn cleave effects, ferocity effects ect. OPTIONAL SQL: utils/sql/svn/2209_optional_additive_bonus_rule.sql (disabled by default) @@ -2402,7 +2863,7 @@ references: http://www.eqemulator.org/forums/showthread.php?t=35604 - CSD Support Patch http://www.eqemulator.org/forums/showthread.php?t=35629 - CSD Bugged Corpse Patch http://www.eqemulator.org/forums/showthread.php?t=35699 - CSD Bandolier Patch - + cavedude: (demonstar55) Damage shields by default will no longer count towards EXP gain. (Rule also added to change this behaviour.) cavedude: (demonstar55) Extended targets should now clear when aggro is lost using skills. cavedude: (demonstar55) AAs with shorter reuse timers should now reset if the cast failed (interrupted.) @@ -2426,7 +2887,7 @@ ENC AA: Total Domination now implemented with bonus SE_CharmBreakChance. SK AA: Soul Abrasion now implemented with bonus SE_ImprovedDamage2. *Many fixes to previously implemented AA effects. -REQUIRED SQL: utils/sql/svn/2208_required_aa_updates +REQUIRED SQL: utils/sql/svn/2208_required_aa_updates OPTIONAL SQL: utils/sql/svn/2208_optional_aa_stacking_rule.sql (If false will disable AA stacking for all clients) OPTIONAL SQL: utils/sql/svn/2208_optional_EnableSoulAbrasionAA *If using an older server spell file (pre SOF), will need to run this to correctly populate the 'spellgroups' field. @@ -2480,11 +2941,11 @@ Kayen: Taunt skill updated to work consistent with live. *Taunt success chance should be accurate to live. Penalty of not being at max skill lv can be adjusted with (RULE: Combat:TauntSkillFalloff) *Live messages for taunt success and failure are now implemented. (Note: Only NPC races that can 'talk' will say the success message). Bad_Captain: Bots- Fixed an issue when with bot spell timers that could lead to a crash. -Kayen: Fixed SQL files from rev2185+ that were not saved as .sql +Kayen: Fixed SQL files from rev2185+ that were not saved as .sql -OPTIONAL SQL: utils/sql/svn/2189_optional_taunt_rules +OPTIONAL SQL: utils/sql/svn/2189_optional_taunt_rules OPTIONAL SQL: utils/sql/svn/2185_optional_NPCFlurryChance_rule (run this again) - + ==08/16/2012== Kayen: Complete revision of the Death Save and Divine Save effects and related bonuses to be consistent with live. *Death Save (Death Pact/DI) will no longer fire on death. It should only fire when less 15% HP but not killed. @@ -2494,7 +2955,7 @@ Kayen: Complete revision of the Death Save and Divine Save effects and related b do a portion of the original heal value. (Ie DI=8000HP with ToTD-3(60%) your heal will be 8000*0.6 = 4800HP) *Implemented functionality for later expansion Death Save effects (Divine Intercession ect) These can add heal value to the base heal which is limited by level (ie Heal 10,0000+8000 if client less then level 80) - + *Divine Save (AA Unfailing Divinity) only fire upon death of client with this effect and is independent of Death Save effect. *Increased ranks of AA only increase the chance of firing upon death. Heal value does NOT increase with rank. *Upon firing you will still recieve the Divine Aura like buff, which now also correctly removes all determental effects. @@ -2516,7 +2977,7 @@ DRU AA: Enchanted root/Viscid Root (was implemented completely wrong), now uses Added RULE: RootBreakFromSpells - Baseline is/was set at 20% chance from nukes. -REQUIRED SQL: utils/sql/svn/2188_required_aa_updates +REQUIRED SQL: utils/sql/svn/2188_required_aa_updates OPTIONAL SQL: utils/sql/svn/2188_optional_miscspelleffect_rules ==08/13/2012== @@ -2528,10 +2989,10 @@ Kayen: Minor update to duel wield, chance bonuses will be correctly applied to b Kayen: Implemented Perl MOB Quest Object SetFlurryChance(value) (ie 50 = 50% chance for NPC flurry if special atk "F") Kayen: Implemented Perl MOB Quest Object GetFlurryChance(value) returns flurry chance. Kayen: Added rule to adjust server wide flurry chance (Default = 20%) *Perl object will override this. - + Following AA effects are now implemented as bonuses: You must update your 'aa_effects' table with 'required_aa_updates.sql' for these to work. MISC AA: Dead Aim, Precision of the Hunter, Scout's Efficiency will now calculate from bonus SE_Accuracy. -MISC AA: Combat Agility line will now calculate from bonus SE_AvoidMeleeChance. (Now implemented through SoD) +MISC AA: Combat Agility line will now calculate from bonus SE_AvoidMeleeChance. (Now implemented through SoD) MISC AA: Combat Stability line will now calculate from bonus SE_CombatStability. (Now implemented through SoD) MISC AA: Double Riposte, Return Kick now calculated from bonus SE_GiveDoubleRiposte. (New AA's implemented that use this) MISC AA: Natural Durability, should be working correctly now from bonus SE_MaxHP. @@ -2541,33 +3002,33 @@ MISC AA: Pet AA's that give flurry chance will now be applied by bonus, SE_PetFl MAG AA: Elemental Agility was incorrectly giving melee mitigation instead of avoidance, to now use SE_PetAvoidance. MAG AA: Elemental Durability will now add to pet max hp with bonus, SE_PetMaxHP. -REQUIRED SQL: utils/sql/svn/2185_required_aa_updates +REQUIRED SQL: utils/sql/svn/2185_required_aa_updates OPTIONAL SQL: utils/sql/svn/2185_optional_NPCFlurryChance_rule ==08/12/2012== Bad_Captain: Fixed an issue when using bots where you would not get xp when your pet did most of the damage and you are not grouped. -Bad_Captain: Added rule to enable receiving xp from bots not in your group. Defaults to false. +Bad_Captain: Added rule to enable receiving xp from bots not in your group. Defaults to false. -OPTIONAL SQL: utils/sql/svn/2183_optional_bot_xp_rule.sql +OPTIONAL SQL: utils/sql/svn/2183_optional_bot_xp_rule.sql ==08/08/2012== -Kayen: Updates to critical hit calcuations to be consistent with live. - *Baseline critical rate is determined by DEX stat (255 dex = 2%),this baseline is then modified by item,spell and AA critical chance bonuses. +Kayen: Updates to critical hit calcuations to be consistent with live. + *Baseline critical rate is determined by DEX stat (255 dex = 2%),this baseline is then modified by item,spell and AA critical chance bonuses. *Pet critical baseline is determined by the rate from AA effects that give pets the ability to critical. (Can not crit w/o this effect) -Kayen: Slay Undead effect will now be working consistent with live. - *Slay rate is no longer effected by critical hit rate, it uses it's own predetermined rates from the spell effect data. - *Damage modification will now be much closer to that of lives utilizing the spell effects damage modifier. +Kayen: Slay Undead effect will now be working consistent with live. + *Slay rate is no longer effected by critical hit rate, it uses it's own predetermined rates from the spell effect data. + *Damage modification will now be much closer to that of lives utilizing the spell effects damage modifier. *Example(AA Slay Undead I - Rate: 225 (2.25%) Damage Mod: 680%) *Note that that spell effects using Slay Undead (Holyforge) will stack with AA and increase the damage and the rate. -Kayen: Crippling Blow's derived from spell effects will now be calculated consistent with live. - *Cippling blow chance is determined by modifying your critical hit chance. - *Example (Savage Onslaught - 200% chance to crippling blow) If you have a base chance to critical hit of 10% +Kayen: Crippling Blow's derived from spell effects will now be calculated consistent with live. + *Cippling blow chance is determined by modifying your critical hit chance. + *Example (Savage Onslaught - 200% chance to crippling blow) If you have a base chance to critical hit of 10% and you score a critical hit, you will then have a 20% chance to crippling blow. Kayen: Fixed effect for AA 'War Cry' will now provide group fear immunity for duration. Kayen: Few new AA's added including shaman Ancestral Aid and Spirit Channeling. - + Following AA effects are now implemented as bonuses: You must update your 'aa_effects' table with 'required_aa_updates.sql' for these to work. -MISC AA: 'Combat Fury', 'Fury of the Ages' will now calculate from bonus SE_CriticalHitChance. +MISC AA: 'Combat Fury', 'Fury of the Ages' will now calculate from bonus SE_CriticalHitChance. MISC AA: 'Veteran's Wrath' will now calculate from bonus SE_CriticalDmgMod. MISC AA: All AA that give pet criticals will be calculated from SE_PetCriticalHit. PAL AA: 'Slay Undead', 'Vanquish Undead' will now calculate from bonus SE_SlayUndead. (Holyforge now works correctly) @@ -2578,7 +3039,7 @@ REQUIRED SQL: utils/sql/svn/2178_required_aa_updates Kayen: Fixes to rev2176 - Double Attack, EndlessQuiver, Run Speed. REQUIRED SQL: utils/sql/svn/2176_required_aa_updates will need to be applied again for Run Speed fix. -==08/05/2012== +==08/05/2012== Kayen: Complete revision of how double attack chance is calculate to be consistent with live. Kayen: Berserker 'Frenzy' skill attack will now function as it does on live. Gives a chance for 1-3 attacks using frenzy skill specific damage. *Note: This will be a considerable nerf to bersekers because it was previously coded to give actual melee rounds using weapon damage. @@ -2586,19 +3047,19 @@ Kayen: Implemented a few miscellaneous new AA's, mostly from DODH. (These will s Kayen: Added almost all remaining spell effects into spdat.h (~90% defined). Kayen: Alternate Advancement Update: In the process of coverting most of the hard coded AA data out of the source and into the 'aa_effects' table using live data. These effects are then reimplemented using the bonus system in the broadest possible way, most of these effects will -also be useable as regular spell/item effects. This will allow developers in the future to adjust,implement and customize AA effects -without requiring source changes. Beware in doing this, many AA effects that were previously either implemented incorrectly or with values +also be useable as regular spell/item effects. This will allow developers in the future to adjust,implement and customize AA effects +without requiring source changes. Beware in doing this, many AA effects that were previously either implemented incorrectly or with values not consistent with live data will be adjusted to be as accurate as possible. Following AA effects are now implemented as bonuses: You must update your 'aa_effects' table with 'required_aa_updates.sql' for these to work. -MISC AA: All innate run speed AA's have been converted to use bonus SE_BaseMovementSpeed. +MISC AA: All innate run speed AA's have been converted to use bonus SE_BaseMovementSpeed. MISC AA: All bind wound related AA have been converted to use bonuses, SE_ImprovedBindWound, SE_MaxBindWound. MISC AA: Shield Block will now be calculated using bonuses, SE_ShieldBlock. MISC AA: Sinister Strike will now correctly allow your off hand weapon to recieve a weapon damage bonus, SE_SecondaryDmgInc. MISC AA: Strengthened Strike/Vicious Smash/Kick Mastery will now accurately to live add skill damage to respective special abilities. MISC AA: StrikeThrough, Tactical Mastery - will now be calculated from bonus, SE_Strikethrough2. MISC AA: Ferocity, Knight's Advantage ect - will now be calculated from bonus SE_DoubleAttackChance. -MISC AA: Harmonious Attacks, Bestial Frenzy - will allow double attack chance using bonus SE_GiveDoubleAttack (any class can be given this) +MISC AA: Harmonious Attacks, Bestial Frenzy - will allow double attack chance using bonus SE_GiveDoubleAttack (any class can be given this) MISC AA: Weapon Affinity, will now use SE_ProcChance. MISC AA: PunishingBlade, SpeedoftheKnight will now allow an extra 2 Handed attack using bonus, SE_ExtraAttackChance. BRD AA: Fleet of Foot will now correctly allow bards to run over the speed cap using, SE_IncreaseRunSpeedCap. @@ -2610,42 +3071,42 @@ RNG AA: Endless Quiver - Implemented as SE_ConsumeProjectile which gives a perc RNG AA: Archery Mastery- Implemented as SE_ArcheryDamageModifier which gives a percent increase to archery attacks. BER AA: Throwing Mastery - Implemented using SE_DamageModifier. BER AA: Blur of Axes, Vicious Frenzy - will now correctly add skill damage to 'Frenzy' skill attacks. -ROG AA: Triple Backstab, SiezedOpportunity, Chaotic Stab - as bonus, SE_TripleBackstab, SE_FrontalBackstabChance,SE_FrontalBackstabMinDmg. +ROG AA: Triple Backstab, SiezedOpportunity, Chaotic Stab - as bonus, SE_TripleBackstab, SE_FrontalBackstabChance,SE_FrontalBackstabMinDmg. REQUIRED SQL: utils/sql/svn/2176_required_aa_updates Optional SQL: utils/sql/svn/2176_optional_FrenzyBonus_rule Optional SQL: utils/sql/svn/2176_optional_aa_expansion_sof_fix (Allow AA to show proper expansion in SOF+ clients) -==08/01/2012== +==08/01/2012== Bad_Captain: Fixed bot compile issue introduced in Rev 2171. Bad_Captain: Integrated Kayen's skill attack code with bots' code, as well as other changes from Rev 2171. ==07/31/2012== Akkadius: (KLS) Fix for global_player.pl synchronization. There was an issue where certain subroutines were not passing as global -==07/26/2012== +==07/26/2012== Kayen: Fixed: SE_ImmuneFleeing - Will now disable fleeing if used after mob begins to run, will not effect fleeing from fear. -Kayen: Implemented Perl MOB Quest Object SetDisableMelee(1=Disabled) - Prevents the ability to auto attack. +Kayen: Implemented Perl MOB Quest Object SetDisableMelee(1=Disabled) - Prevents the ability to auto attack. Kayen: Implemented Perl MOB Quest Object IsMeleeDisabled() Sorvani: corrected build name for queryserv project in all the various build types. - -==07/24/2012== + +==07/24/2012== Kayen: Implemented: SE_HundredHands (incorrectly marked as already implemented) - Increases/Decrease actual weapon delay by % of value. Kayen: Implemented: Missing modifications from the Archery/Throw damage pathways. *SkillAmount/SkillDamageTaken mods, ability to Block/Dodge/Parry ranged attacks (Can not riposte), other new focus/mod effects. -Kayen: Fixed: aaThrowingMastery will no longer be applied 2x per throw. +Kayen: Fixed: aaThrowingMastery will no longer be applied 2x per throw. Kayen: Implemented: Damage bonus to skill attacks from specific armor slot AC (ie KICK from BOOT AC) can adjust with rule 'SpecialAttackACBonus' Kayen: SE_MinDamageModifier should now apply to skill specific effects and to special attacks. Kayen: Implemented: Complete revision of SE_SkillAttack. (+ required various fixes/adjustments to functions related to special attacks) *This spell effect performs a physical attack from a specific skill with a set weapon damage value and chance to hit modifier. *Attacks will now calculate correctly and use their actual respected pathways utilizing all skill specific mods/bonus. -Kayen: Implemented Perl MOB Quest Object DoMeleeSkillAttackDmg(target, weapon_damage, skill, chance_mod, focus, CanRiposte) -Kayen: Implemented Perl MOB Quest Object DoArcheryAttackDmg(target,NULL,NULL, weapon_damage, chance_mod, focus) -Kayen: Implemented Perl MOB Quest Object DoThrowingAttackDmg(target,NULL,NULL, weapon_damage, chance_mod, focus) +Kayen: Implemented Perl MOB Quest Object DoMeleeSkillAttackDmg(target, weapon_damage, skill, chance_mod, focus, CanRiposte) +Kayen: Implemented Perl MOB Quest Object DoArcheryAttackDmg(target,NULL,NULL, weapon_damage, chance_mod, focus) +Kayen: Implemented Perl MOB Quest Object DoThrowingAttackDmg(target,NULL,NULL, weapon_damage, chance_mod, focus) Optional SQL: utils/sql/svn/2171_optional_SpecialAttackACBonus_rule - + ==07/18/2012== Kayen: Implemented NPC Special Attack 'K'. Immune to Dispell. Kayen: Fixed SE_RangedProc to be applied after zoning, calculate proc rate correctly, utilize numhits. @@ -2660,7 +3121,7 @@ Kayen: Implemented: SE_SpellProcChance, SE_CharmBreakChance, SE_BalanceMana, SE_ SE_CriticalHealOverTime2, SE_CriticalHealChance2, SE_SkillDamageAmount2, SE_LimitSpellSkill, SE_LimitClass SE_LimitExcludeSkill, SE_ShieldBlock, SE_BlockBehind Kayen: Implemented: SE_Empathy - A focus limited debuff which causes (spells/skill attacks) cast on target to do +X amount more damage. - *This spell effect is often limited using SE_LimitSpellSkill. + *This spell effect is often limited using SE_LimitSpellSkill. *(Ie. If empathy value is 1000 and limited to evocation, all nukes on target using evoc. will get +1000 damage) Kayen: Implemented: SE_SpellPowerIncrease - Can be used to apply a worn/buff focus effect with limits for... 1) Additional bard instrument modifiers. @@ -2668,16 +3129,16 @@ Kayen: Implemented: SE_SpellPowerIncrease - Can be used to apply a worn/buff foc 3) Increase effectiviess of casted/disc Skill Attacks. 4) General use stackable Healing/Damage focus. 5) Increase the value of melee runes by focus amount. -Kayen: SE_HPtoMana will no longer drain your HP before the spell is finished casting. Effect now handled as a bonus using best value. -Kayen: SE_SpellVulunerability will now correctly calculate and apply the highest value if target has mulitple effects. -Kayen: Fixed an issue where DOTs cast by an NPC on another NPC would not generate hate per tick. Improved how we calc damage from DOTs. +Kayen: SE_HPtoMana will no longer drain your HP before the spell is finished casting. Effect now handled as a bonus using best value. +Kayen: SE_SpellVulunerability will now correctly calculate and apply the highest value if target has mulitple effects. +Kayen: Fixed an issue where DOTs cast by an NPC on another NPC would not generate hate per tick. Improved how we calc damage from DOTs. Kayen: SE_BlockSpellEffect was implemented incorrectly and has been revised to SE_NegateSpellEffect. *It is not meant to block buffs, rather it negates the specific spell bonuses or effects from buffs you already have. *Currently functional with any effect that is handled under bonuses, and focus effects. Kayen: Vastly improved how we handle melee/spell runes/partial mitigation runes ect. Should be significantly more efficient. *Melee/Spell Mitigation runes and ManaAbsorbPercentDamage effects will now use the best mitigation value if multiple effects. Kayen: Improved the process we use to get spell/item focus effects. An initial check if the client has a specific focusType -is done while checking for item/spell bonuses. GetFocusEffect will no longer check all inventory and buff slots every cast for the +is done while checking for item/spell bonuses. GetFocusEffect will no longer check all inventory and buff slots every cast for the focusType if that focusType doesn't exist on the client. This should improve performance since these checks are done 10-20x per cast/proc. ==07/15/2012== @@ -2687,7 +3148,7 @@ Secrets: Fixed an issue with saylinks above 255 characters. If you do want to us Bad_Captain: Fixed another bug that allowed pets to steal xp when using bots. Bad_Captain: Bots: Persisting spell & discipline timers. Bad_Captain: Bots: Bot pets will no longer continuously try to get behind a mob if they are tanking. -Bad_Captain: Bots: Fixed potential duplicate lore item bug when trading with bots. +Bad_Captain: Bots: Fixed potential duplicate lore item bug when trading with bots. Bad_Captain: Bots: Fixed bot compile issue from Rev 2160. Bad_Captain: Bots: Fixed multiple issues with #bot spawn and #bot botgroup load (c0ncrete). Bad_Captain: Bots: Implemented new #bot defensive command for Warriors and Knights. Includes most of the code required to implement disciplines for bots. Requires disc AI & disc lists. @@ -2710,9 +3171,9 @@ Kayen: Updated spdat.h with many new live spell effects that were previously 'un ==07/05/2012== Kayen: Implemented: SE_Manaburn: Drains mana for damage/heal at a defined ratio up to a defined maximum amount of mana. -Kayen: Implemented: SE_CastonNumHitFade: Casts a spell when a buff fades due to its numhits being depleted. +Kayen: Implemented: SE_CastonNumHitFade: Casts a spell when a buff fades due to its numhits being depleted. Kayen: Implemented: support for all remaining live spell effects that use 'numhits'. - Significantly optimized how all spell effects that utilize 'numhits' are handled throughout the source. + Significantly optimized how all spell effects that utilize 'numhits' are handled throughout the source. Kayen: Fixed: SE_DefensiveProc - Proc rate will now be calculated similiar to live. *Spell specific rate modifcations will now work. Kayen: Added Rule: Combat:AvgDefProcsPerMinute (Default = 2.0) Determine defensive procs per minute. Kayen: Added Rule: Combat:DefProcPerMinAgiContrib (Default = 0.075) Determines how much agility effects proc rate. @@ -2720,9 +3181,9 @@ Kayen: Added Rule: Combat:DefProcPerMinAgiContrib (Default = 0.075) Determines h Optional SQL: utils/sql/svn/2159_optional_defensiveproc_rules ==06/29/2012== -Kayen: Implemented Perl NPC Quest Object GetSlowMitigation() -Kayen: Implemented Perl NPC Quest Object GetAttackSpeed() -Kayen: Implemented Perl NPC Quest Object GetAccuracyRating() +Kayen: Implemented Perl NPC Quest Object GetSlowMitigation() +Kayen: Implemented Perl NPC Quest Object GetAttackSpeed() +Kayen: Implemented Perl NPC Quest Object GetAccuracyRating() Kayen: Fixed: Slow Mitigation (was not loading from dbase),optimized its application in source and added lives slow mitigation messages. Slow mitigation Messages: 'slighty' 0.00 - 0.25 'partial' 0.25-0.75 'mostly' 0.75-1 Kayen: Implemented: SE_AttackSpeed4: 'Inhibit Melee' effect works different then regular haste/slow effect @@ -2733,13 +3194,13 @@ Kayen: Added Rule: Spells:CharismaEffectiveness (Default = 10) Deterimes how muc Kayen: Added Rule: Spells:CharmBreakCheckChance (Default = 25) Determines percent chance for a charm break check to occur each buff tick. Kayen: Reworked code to that handles charm breaks/lull to be accurate to live and more functional in general. 1) Each charm buff tick there is a default 25% [Rule.CharmBreakCheckChance] chance to trigger a spell resistance check. - 2) Spell resistance check then adds an additional bonus resist modification based casters Charisma at a default + 2) Spell resistance check then adds an additional bonus resist modification based casters Charisma at a default ratio of 10 CHA per -1 resist mod [Rule.CharismaEffectiveness] 3) If resisted (ie Charm is to break) Total Domination AA is then applied to give another chance to maintain the charm. Kayen: Implemented: SE_AdditionalHeal: Focus Effect that adds an additional heal amount to the casted spell. Kayen: Implemented: SE_CastOnCure: Casts a spell on cured target. Kayen: Implemented: SE_CastOnCurer: Casts a spell on the curer of the target. -Kayen: Modified: Mob::TryFadeEffect to avoid interaction wtih Twinproc effect. +Kayen: Modified: Mob::TryFadeEffect to avoid interaction wtih Twinproc effect. cavedude: (Uleat) Multiple changes and additions to doors, per the forums. Optional SQL: utils/sql/svn/2156_optional_charm_break_rule.sql @@ -2764,8 +3225,8 @@ Kayen: Implemented SE_FF_Damage_Amount - Focus/Buff that adds damage to the cast Kayen: Adjusted SE_SpellDamage to be handled properly as a focus effect. Kayen: Extra damage from Focuses is now calculated correctly for DoTs Kayen: Implemented Perl NPC Quest Object SetSpellFocusDMG(focus amount) - Focus all npc direct/dot damage spells by value -Kayen: Implemented Perl NPC Quest Object SetSpellFocusHeal(focus amount) - Focus all npc healing spells by value -Kayen: Implemented Perl Mob Quest Object ModSkillDmgTaken(skill_num,value) - Set a weakness/bonus of weapon attacks to a Mob +Kayen: Implemented Perl NPC Quest Object SetSpellFocusHeal(focus amount) - Focus all npc healing spells by value +Kayen: Implemented Perl Mob Quest Object ModSkillDmgTaken(skill_num,value) - Set a weakness/bonus of weapon attacks to a Mob - Example: mob can be set to take 5% more damage from blunt weapons - ModSkillDmgTaken(0,5) - Stacks with spell/item bonuses - Setting skill to -1 will effect all skills Kayen: Implemented Perl Mob Quest Object GetModSkillDmgTaken(skill_num) - Returns only the quest skill mod for specified skill @@ -2777,7 +3238,7 @@ Kayen: Implemented Perl Mob Quest Object ModVulnerability(resist type, value) - - Example: mob can be set to take 5% more damage from Fire spells (2,5); - Applied effect will stack with spell buff effects. - If a resist type SPECIFIC and a resist type ALL mod are applied to the same MOB, the SPECIFIC value will be used if spell cast on MOB is the same resist type. -Kayen: Implemented Perl Mob Quest Object GetModVulnerability(resist type) - Return the quest applied value for each resist (ALL = -1) +Kayen: Implemented Perl Mob Quest Object GetModVulnerability(resist type) - Return the quest applied value for each resist (ALL = -1) Optional SQL: utils/sql/svn/2154_optional_rule_spell_procs_resists_falloff.sql @@ -2837,12 +3298,12 @@ Trevius: VoA - The AA Window now populated AAs. AA hotkeys can be created, but sorvani: Bard AE DoTs should now be affected by mods correctly. ==04/19/2012== -cavedude: quest::buryplayercorpse will now despawn corpses in zones other than the client's current location, preventing dupes. +cavedude: quest::buryplayercorpse will now despawn corpses in zones other than the client's current location, preventing dupes. cavedude: Added quest::summonallplayercorpses (same syntax as quest::summonburriedplayercorpse) which will depop and summon all of the player's corpses, buried or not. cavedude: Fixed a bug that caused some summoned corpses to use a static 5 minute decay timer. cavedude: Changed player_corpses_backup schema to match player_corpses. If the rule is enabled, corpse backups will now be created for players that are high enough level to drop items to their corpses. cavedude: Added a rule to determine whether or not to remove player corpse backups older than 2 weeks. -cavedude: #corpse now has options to depop a single player corpse, or every corpse belonging to a single player. +cavedude: #corpse now has options to depop a single player corpse, or every corpse belonging to a single player. cavedude: You can now specify if a faction hit is temporary (is removed when player camps/zones) or whether or not to display the faction hit to the player in-game. If temp in npc_faction_entries is set to: 0 (Default): Faction is permanent, player recieves a message. (Same functionality as we had previously.) @@ -2850,7 +3311,7 @@ If temp in npc_faction_entries is set to: 2: Faction is temporary, player recieves a message. 3: Faction is permanent, but player does not recieve a message. cavedude: Added an optional argument to quest::faction to utilize the functionality and values listed above. -cavedude: Added minlevel and maxlevel to lootdrop_entries. The player credited with the kill (most hate) has their level checked against both columns, and if they are lower than the specified minlevel, or higer than the max, that item entry if it exists is removed from the NPC before it becomes a corpse. +cavedude: Added minlevel and maxlevel to lootdrop_entries. The player credited with the kill (most hate) has their level checked against both columns, and if they are lower than the specified minlevel, or higer than the max, that item entry if it exists is removed from the NPC before it becomes a corpse. cavedude: You can now specify if a NPC automatically repops (rerolls against their spawngroup) or depops after the reverse spawn timer is up. If despawn in spawngroup is set to: 0 (Default): Do not depop or repop, no depop timer is set. (Same functionality as we had previously.) @@ -2943,10 +3404,10 @@ JJ: Removed additional library and include directories from windows projects as Sorvani: Resurrections effects will again be applied to characters who are in a zone where combat is not allowed (GL, PoK etc) when they receive a rez. ==03/19/2012== -Bad_Captain: Bots: A few fixed for #bot stance command +Bad_Captain: Bots: A few fixed for #bot stance command ==03/19/2012== -Bad_Captain: Bots: Implemented bot stances. See forum post. +Bad_Captain: Bots: Implemented bot stances. See forum post. Required SQL: utils/sql/svn/2107_required_bot_stances.sql @@ -3030,11 +3491,11 @@ Reccomended SQL: (ON QueryServ's database, NOT the main db) utils/sql/queryserve Secrets: v90 toolset bugs reported on forums. In order to use Perl 5.14, you MUST upgrade to VS2010 (preferrably ultimate), if you do not have vs2010, it will default to Perl 5.10 and you will be unable to use the much more stable Perl 5.14, an upgrade is reccomended. Secrets: Fixed Windows x64 rulesys bug where it would store them as an x64 version of an int (long long) and mess up the ordering of pointers, resulting in certain rules not loading properly. NOTE: For those having issues compiling vs2010, there will be a guide up shortly to help you set up your dev environment. In the meantime, make sure your "Additional Include" and "Additional Library" paths -are correct and pointing at the right location. Failure to do so will result in mysql header/lib and perl header/lib issues. If you are looking for zlib x64, it's in SVN. +are correct and pointing at the right location. Failure to do so will result in mysql header/lib and perl header/lib issues. If you are looking for zlib x64, it's in SVN. ==11/30/2011== Secrets: Implemented Visual Studio 11 and Visual Studio 10 project/sln files. -Secrets: Added x64 configuration settings to VS11 and VS10 project files/SLN files. +Secrets: Added x64 configuration settings to VS11 and VS10 project files/SLN files. Secrets: Changed WIN32 define to _WINDOWS across the board. In the case where WIN32 is needed over WIN64 (ie; assembly references) there is still WIN32 defines and a new WIN64 define. Secrets: Upgraded ActiveState Perl lib define to 5.14 -- others still work but it is strongly reccomended to use 5.14 as it contains less memory leaks. Secrets: Added Zlib 1.2.3 x64 to the SVN for use with the windows solution files. @@ -3069,7 +3530,7 @@ Lerxst: Fixed crash when calculating random focus effect from an augment when th Also added some bulletproofing in case that isn't the only place an invalid spell id might be passed. ==11/16/2011== -Akkadius: Added the ability to specify doors/objects/ground spawns to load for all versions of the same zone regardless by setting the value to -1. +Akkadius: Added the ability to specify doors/objects/ground spawns to load for all versions of the same zone regardless by setting the value to -1. This reduces serious redundancy of copying the same data over and over for instances. Required SQL: @@ -3277,8 +3738,8 @@ Congdar: update check for Lore ==07/17/2011== Congdar: (pfyon, Criimson)Various bot tweaks Caryatis: Updated My/Showstats window. - -Required SQL: + +Required SQL: utils/sql/svn/1974_required_bot_spells_update ==07/16/2011== @@ -3420,9 +3881,9 @@ JJ: Implemented New Tanaan Crafting Mastery tradeskill AA. Each rank allows an a Note: For servers with players who have tradeskills already above the limit without previously purchasing these AAs will freeze the chance to increase until they purchase the proper amount of NTCM AAs. ==05/24/2011== -KLS: Changed Mob::NPCSpecialAttacks(atk, perm) to Mob::NPCSpecialAttacks(atk, perm, [reset = 1], [remove = 0]). -This should allow one to add and remove flags individually without having to reset everything each time. -ex: +KLS: Changed Mob::NPCSpecialAttacks(atk, perm) to Mob::NPCSpecialAttacks(atk, perm, [reset = 1], [remove = 0]). +This should allow one to add and remove flags individually without having to reset everything each time. +ex: $npc->NPCSpecialAttacks(RQ, 0); //would enable the npc to rampage and quad. $npc->NPCSpecialAttacks(S, 0, 0); //Would enable the NPC to summon as well as rampage and quad by telling it to set S but don't reset the earlier flags. @@ -3434,11 +3895,11 @@ $npc->NPCSpecialAttacks(S, 0, 0, 1); //Would enable the NPC rampage and quad by JJ: (Akkadius) Fixed camera shake usage output. ==05/22/2011== -KLS and Co: +KLS and Co: -All liquid should count for skill ups. --Finished unified quest interface... this is fairly large and will probably have a few problems here and there; report them to me and ill fix them asap. -The goal behind the system is to allow more than one scripting system to work at a time (though with limited interaction due to pre-existing implementation limitation). -This was a feature requested by the Dalaya community as they plan to merge back to the eqemu codebase and clients but are stuck with an old parser and thousands of files +-Finished unified quest interface... this is fairly large and will probably have a few problems here and there; report them to me and ill fix them asap. +The goal behind the system is to allow more than one scripting system to work at a time (though with limited interaction due to pre-existing implementation limitation). +This was a feature requested by the Dalaya community as they plan to merge back to the eqemu codebase and clients but are stuck with an old parser and thousands of files that can't be realistically rewritten in a short time frame. ==05/20/2011== @@ -3467,7 +3928,7 @@ Optional SQL: utils/sql/svn/1889_optional_skill_cap_rule.sql ==05/02/2011== Secrets: Added OP_CameraEffect for Titanium. -Secrets: Added commands: #reloadallrules, #reloadrulesworld, and #camerashake. These default to +Secrets: Added commands: #reloadallrules, #reloadrulesworld, and #camerashake. These default to Secrets: Added optional "global" flag as item 5 in the $mob->CameraEffect() quest object. This does #camerashake, but in quest form. Secrets: #reloadallrules reloads rules in every single zone plus world. #reloadrulesworld reloads the rules in world only. Secrets: #camerashake shakes the camera in every zone with required args intensity and duration. @@ -3787,7 +4248,7 @@ utils/sql/svn/1747_optional_HoT_zone_and_zonepoints.sql For spawns etc, go to the PEQ logs repo for data collected by robregen. -Optional SQL: +Optional SQL: utils/sql/svn/1750_optional_sql_reflect_rule.sql @@ -3800,7 +4261,7 @@ Caryatis: (bad_captain) Removed the level bonus granted to standing mana regen, Caryatis: (bad_captain) Bots have been updated, see forums for complete details(new command: #bot showstats). Caryatis: (Secrets) Haste values can exceed 127%(ie Can o' Whoop Ass). -Optional SQL: +Optional SQL: utils/sql/svn/1746_optional_sql_bot_manaregen ==11/22/2010== @@ -3817,10 +4278,10 @@ Caryatis: Fix for Healrate effect Caryatis: Implemented ManaAbsorbPercentDamage, ReduceSkillTimer, HpToMana and LimitSpellGroup effects. Caryatis: Updated DamageModifier effect to be more robust. -Required SQL: +Required SQL: utils/sql/svn/1737_required_sql_rule_and_aa_update -Optional SQL: +Optional SQL: utils/sql/svn/1736_optional_sql_feral_swipe ==11/14/2010== @@ -3869,7 +4330,7 @@ Caryatis: hStr = Increases endurance pool, endurance regen(25), and the maximum Caryatis: hSta = Increases hit point pool, hit point regen(25), and the maximum amount of hit point regen a character can have(25). Also increases endurance pool, endurance regen(25), and the maximum amount of endurance regen a character can have(25). Caryatis: hAgi = Increases endurance pool, endurance regen(25), and the maximum amount of endurance regen a character can have(25). Also increases the chance to dodge an attack(25), grants a bonus to defense skill(10). Caryatis: hDex = Increases endurance pool, endurance regen(25), and the maximum amount of endurance regen a character can have(25). Also increases damage done by ranged attacks(1), improves chance to successfully assassinate or headshot(10), and improves the chance to riposte, block, and parry incoming attacks(25). -Caryatis: hCha = Improves reaction rolls with some NPCs(25) and increases the amount of faction you gain or lose when faction is adjusted(5). +Caryatis: hCha = Improves reaction rolls with some NPCs(25) and increases the amount of faction you gain or lose when faction is adjusted(5). Caryatis: AA Focus revamped to support new effects Caryatis: Disciplines will no longer be dispelled @@ -3879,7 +4340,7 @@ utils/sql/svn/1719_optional_triggerOnCastAAs.sql ==11/09/2010== Caryatis: Implemented MaxHPChange, SkillDmgTaken, Endurance Pool and Stun Resist. -Optional SQL: +Optional SQL: utils/sql/svn/1717_optional_rule_bash_stun_chance.sql ==11/07/2010== @@ -4058,9 +4519,9 @@ Trevius: (Secrets) Added quest::creategroundobjectfrommodel(modelname, x, y, z, Trevius: (Secrets) quest::creategroundobject(itemid, x, y, z, heading) now returns object ID. Trevius: (Secrets) Added Object List Iteration functions GetObjectByDBID(id), GetObjectByID(id), GetObjectList(). Trevius: (Secrets) exported Objects to Perl with the following commands: - IsGroundSpawn(), Close(), Delete(reset_state=false), StartDecay(), DeleteItem(index), IsObject(), - Save(), SetID(set_id), ClearUser(), DBID(), GetID(), GetX(), GetY(), GetZ(), GetHeading(), VarSave(), - GetType(), SetType(type), GetIcon(), SetIcon(icon), GetItemID(), SetItemID(itemid), SetLocation(x, y, z), + IsGroundSpawn(), Close(), Delete(reset_state=false), StartDecay(), DeleteItem(index), IsObject(), + Save(), SetID(set_id), ClearUser(), DBID(), GetID(), GetX(), GetY(), GetZ(), GetHeading(), VarSave(), + GetType(), SetType(type), GetIcon(), SetIcon(icon), GetItemID(), SetItemID(itemid), SetLocation(x, y, z), SetX(XPos), SetY(YPos), SetZ(ZPos), SetHeading(heading), SetModelName(name), GetModelName(), Repop(), Depop(). ==07/25/2010== @@ -4381,7 +4842,7 @@ KLS: Other merges from spell branch, some more to come. Tell me if there are an ==04/15/2010== cavedude (Leere): Increased the number of tradeskill favorites that can be stored client side to 500. -cavedude (Leere): Fixed avgcoin. +cavedude (Leere): Fixed avgcoin. cavedude (renoofturks): Fixes to SK harm touch. cavedude: Lowered snare movement speed when fleeing to 41% or higher to allow "Snare" to prevent movement at all levels. gaeorn: multiple login server support in world. protocol to update login server account information from within game. "trusted" field for world accounts in loginserver to limit where account updates can come from. in eqemu_config.xml, use to specify first of multiple login servers. increment the number to specify additional login servers. NOTE: be sure to replace the entry or you will be limited to just one login server. MULTIPLE LOGIN SERVERS WILL NOT WORK WITH MINILOGIN. @@ -5166,7 +5627,7 @@ Derision: Fix for mobs in pathing enabled zones fleeing at low health at full ru Derision: Made rule Map:UseClosestZ default to false. Only set true if using azone2 generated maps (specifically those for EQG zones). realityincarnate: Starting cities are now tracked for newly created characters. realityincarnate: Enabled the /setstartcity command for characters without a start city assigned. -realityincarnate: Added $client->SetStartZone and $client->GetStartZone perl commands. +realityincarnate: Added $client->SetStartZone and $client->GetStartZone perl commands. KLS: Petitions will assign id based on character id instead of this stupid desyncing junk. KLS: Max NPC name length increased to 50 characters up from 30. KLS: Save on zone success will now commit immediately instead of possibly delaying. Hopefully will help with some of the situations where people zone to bad locations. @@ -5229,7 +5690,7 @@ KLS: Implemented OP_ClearSurname KLS: (gaeorn) Several 64-bit compile and runtime fixes KLS: (gaeorn) NPC wander back rules. Trevius: #texture will now allow player races to retain armor tint for both PCs and NPCs. -realityincarnate: bug fix for changing max_hp with the modifynpcstat command +realityincarnate: bug fix for changing max_hp with the modifynpcstat command Required SQL: /utils/sql/svn/704_rules.sql @@ -5313,7 +5774,7 @@ Warning: If you do not have a spells_new table yet, you must create one and load After creating the table, you can import or export your spells from the spells_us.txt file by using the scripts: import_spells.pl export_spells.pl - + The easiest way to import your spell file to the table is to move the import_spells.pl file to your main server directory where your spells_us.txt file and your eqemu_config.xml file are. Then run the following command at a command prompt: perl import_spells.pl @@ -5378,7 +5839,7 @@ KLS: Added support for item clicklevel and item clicklevel2 Trevius: Increased spellbook from 400 to 480 in the Player Profile for use with SoF (60 page spell book) Trevius: SoF - Added new functions to SoF.cpp for converting Slot IDs between Titanium and SoF Trevius: SoF - Corrected the location of the spellbook field in the Player Profile to fix an issue with loading spells -WildcardX: Check in of the start of what will become the new BOTS subsystem/framework. This is far from done so just continue to use the existing EQBOTS code you have been using. +WildcardX: Check in of the start of what will become the new BOTS subsystem/framework. This is far from done so just continue to use the existing EQBOTS code you have been using. KLS: Change to dangerous item inst aug creation, hopefully addresses segfault on 64 bit linux. KLS: Hopefully fix for pets not giving adventure credit to players in ldon instances. @@ -5524,7 +5985,7 @@ KLS: Added Rules: (Character, UseXPConScaling), (Character, LightBlueModifier), Derision: Bandolier bug fix. Derision: Equipped items that should confer an extra potion belt slot now do so in Titanium and the 6.2 client (was already working in SoF). Angelox: Bots- (Congdar) fixed Bot illusion / change form spells as to who is affected. -Angelox: Bots- added check to Bot pacify for casting from a distance. +Angelox: Bots- added check to Bot pacify for casting from a distance. ==05/18/2009== @@ -5605,7 +6066,7 @@ Derision: Fixed a bug where a mob aggroed would sometimes appear to run past it' Trevius: (Erde) The Web Tool now shows the name of the process running each Dynamic zone (example: dynamic_01) ==05/06/2009== -Angelox: Bots: Added command '#bot shrinkme' requires Shaman or Beastlord (defaults to Shaman). +Angelox: Bots: Added command '#bot shrinkme' requires Shaman or Beastlord (defaults to Shaman). Derision: Added redux_aa2, redux_rate2 fields to aa_actions. Derision: Improved Hasty Exit should now reduce the reuse time of Escape. Derision: The reuse timer in the AA window now shows the reuse time reduced by applicable AAs. @@ -5666,7 +6127,7 @@ Cripp: Fix for the web interface for those using Perl 5.10. Congdar: Bots - randomized face/hair etc. so they don't all look the same. Fixed Bard AE songs. ==4/30/2009== -Congdar: Bots - bots can now use bows, new command '#bot archery'. Added Ranger archery AA's. Reduced chat mana spam. Tweaked spell ai. Fixed memory leak. Updated '#bot corpse summon'. +Congdar: Bots - bots can now use bows, new command '#bot archery'. Added Ranger archery AA's. Reduced chat mana spam. Tweaked spell ai. Fixed memory leak. Updated '#bot corpse summon'. Derision: SoF - AAs affecting stats now show the correct stats in the client. Derision: Tweaked base resists to match the client. gatorman: Fix for QuickSummoning AA (to include Call of the Hero) @@ -5685,7 +6146,7 @@ Derision: SoF: Ranged attack animations. Derision: When shooting a bow, there is no longer a superfluous 1HS animation. ==4/23/2009== -Trevius: (realityincarnate) Added new quest command quest::varlink(item_id) for putting item links into variables. +Trevius: (realityincarnate) Added new quest command quest::varlink(item_id) for putting item links into variables. Derision: Fix for Tradeskill combines where a LORE ingredient is returned. Derision: Fix for pet names containing spaces losing the space after zoning/camping. Derision: Fixed bug where Return Home sent players bound in Grobb to Qeynos/Unknown Zone. @@ -5704,7 +6165,7 @@ Wolftousen: Rage Volley no longer requires you to have an thrown weapon in your Wolftousen: Rage Volley now uses the proper damage calculation and is not based on the item you have in the ranged slot Wolftousen: Rave Volley can no longer be dodged/blocked/parried/reposted. Wolftousen: Procs from Buffs have been tweaked to go off more often Wolftousen: Players will now receive the "proper" bonus HP for stamina above 255. -Wolftousen: Knight class Tactical Mastery AA was implemented and should now give the strike through message +Wolftousen: Knight class Tactical Mastery AA was implemented and should now give the strike through message renoofturks: Created rule Aggro:StunAggroMod to dial in on aggro of stun based attacks. cavedude: Reverse DS and some DS will now cause aggro on intial cast. realityincarnate: Controllable boats should now work. Please see: http://eqemulator.net/forums/showthread.php?p=167892#post167892 for additonal information. @@ -5880,7 +6341,7 @@ cavedude: Corrected ZEM for AAs. cavedude: (Thanks to demonstar55) Pet Affinity will no longer effect charmed pets. cavedude: (realityincarnate) Bard songs that require instruments will now require them. -Please note: XP gain has pretty much been overhauled. You may need tweak the multiplier rules for your server. +Please note: XP gain has pretty much been overhauled. You may need tweak the multiplier rules for your server. Optional SQL: @@ -5994,7 +6455,7 @@ cybernine186: Optional system to ensure GMs are logging on from a known IP. Trevious: SoF - Drakkin now gain stats from items and weapons now work for combat Trevious: SoF - Drakkin now start with Common Tongue, Dragon and Elder Dragon Languages maxed -Required SQL: utils/sql/svn/340_gm_ips.sql +Required SQL: utils/sql/svn/340_gm_ips.sql ==02/16/2009== Trevius: SoF - The Item Struct should be aligned almost perfectly now. @@ -6105,9 +6566,9 @@ Note: You must move the patch_SoF.conf file from /utils into your server directo ==01/31/2009== Derision: Tweaks to temp merchant list window updates. -cavedude00: Renamed the AugSlotUnk items columns to AugSlotVisible. +cavedude00: Renamed the AugSlotUnk items columns to AugSlotVisible. -Required SQL: utils/sql/svn/292_augslots.sql +Required SQL: utils/sql/svn/292_augslots.sql ==01/29/2009== KLS: VC71 solution files. @@ -6117,7 +6578,7 @@ Angelox: Bots: Added a directory with the BOT Makefiles for Windows and Linux. ==01/27/2009== Derision: Bazaar bug fix. -Angelox: Bots: Added command '#bot runeme' (Enchanter Rune spells) +Angelox: Bots: Added command '#bot runeme' (Enchanter Rune spells) Optional SQL: utils/sql/svn/285_optional_bot_spell_update.sql (removes auto-runes) @@ -6129,7 +6590,7 @@ Derision: Fixed a buffer overflow problem. ==01/19/2009== cavedude00: Increased itemid limit to 120,000. -cavedude00: Meditate will now skill up at a more Live Like speed. +cavedude00: Meditate will now skill up at a more Live Like speed. ==01/18/2009== Derision: Fixed a cause of zone crashes. @@ -6157,7 +6618,7 @@ Derision: Mapped field in LogServer_Struct to allow voice macro window to be ope Derision: Removed code that stole all your money if you logged on with more than 1 million of any denomination of coin on your person. ==01/11/2009== -Angelox: Bots: Added rule 'EQOffline:BotCount' defaults to 5, for desired amount of bots in the group - values are 0-5 (0 means bots are disabled, max limit is 5). +Angelox: Bots: Added rule 'EQOffline:BotCount' defaults to 5, for desired amount of bots in the group - values are 0-5 (0 means bots are disabled, max limit is 5). Derision: Mail/Chatchannels: Added sanity check on packet size in EQPacket::ChatDecode. Derision: Mail/Chatchannels: Increased stream timeout from 45 to 135 seconds. Derision: Mail: Use correct opcodes for sending Headers. **utils/mail_opcodes.conf updated** @@ -6177,7 +6638,7 @@ Angelox: Bots: '#bot sow wolf' should not affect pets anymore. Derision: Chatserver: Added some extra syntax error checking to prevent crashes. Angelox: Bots: Added Wizard class and level check to the '#bot evac' command Angelox: Bots: Added '#bot invis see' for see invisible -Required SQL: +Required SQL: DELETE FROM npc_spells_entries where (npc_spells_id >=701 and npc_spells_id <=712) AND spellid=80; Congdar: Fix NPC::RemoveItem(uint16 item_id) to uint32 to work with items that have id's larger than 65535. '#npcloot remove [itemid]' will now successfully remove items with larger id's from npc loot. Congdar: Bots: Visible gear will now show correctly when trading/equipping bots. @@ -6197,7 +6658,7 @@ Congdar: Bots: update command #bot inventory list Now shows gear as item links Optional SQL: update npc_types set lastname='' where isbot=1; ==01/01/2009== -Angelox: Bots: Added command '#bot sow' (Druid has options) +Angelox: Bots: Added command '#bot sow' (Druid has options) Angelox: Bots: Added command '#bot levitate'. Angelox: Bots: Added command '#bot invis' - (has options). @@ -6510,8 +6971,8 @@ Congdar: Clone NoDrop removal code to NoRent, Lore, NoTrade. Optionally enabled Congdar: Bot code cleanup, method call reduction Congdar: Bot DoubleAttack method is more like clients Congdar: Remove AFK leveling with bots -Angelox: Added command '#Bot evac' for Druid bots -Angelox: Added command '#Bot target calm' for Enchanter or Cleric bots +Angelox: Added command '#Bot evac' for Druid bots +Angelox: Added command '#Bot target calm' for Enchanter or Cleric bots Trevius: Removed the * 10 multiplier from the SE_ProcChance since it isn't needed KLS: Zone appearance should update for players zoning. KLS: Added command #modifynpcstat @@ -6561,7 +7022,7 @@ AndMetal: (seveianrex) Hate w[h]iped on CoH AndMetal: (via Yeahlight) New command: #aggrozone. Requires 100 status by default ==10/19/2008 -Angelox: Added a start to Bot tracking - Thanks Derision for all the help and know-how. +Angelox: Added a start to Bot tracking - Thanks Derision for all the help and know-how. Derision: Altered damage shield message processing to be more like (the same?) as live. Derision: If it exists, damage shield types are read from a new table (damageshieldtypes) Derision: If no entry exists in the table, a default based on resist type is used. @@ -6579,10 +7040,10 @@ KLS: Disarm trap will no longer fail to disarm traps on success. KLS: Increased range on disarm trap slightly. KLS: Change to MakeRandomInt() and MakeRandomFloat() KLS: Int generation be nearly 100% or more faster in most cases and float generation should be slightly faster in most cases -cavedude00: (seveianrex) Slay Undead Fix -cavedude00: (seveianrex) Levitate effect will no longer be removed in cases where you have two stacked lev spells and the first wears off. +cavedude00: (seveianrex) Slay Undead Fix +cavedude00: (seveianrex) Levitate effect will no longer be removed in cases where you have two stacked lev spells and the first wears off. cavedude00: (seveianrex) Hate list will now be cleared following CoH -cavedude00: (seveianrex) Group members will now see tradeskill emotes. +cavedude00: (seveianrex) Group members will now see tradeskill emotes. Required SQL: ALTER TABLE `traps` DROP `spawnchance`; @@ -6689,7 +7150,7 @@ Derision: (Spoon/Andmetal) Rez spells with effectdescnum != 82 or 39067 (6.2 spe Derision: Corrected message when interrupting a spell with Shift-S. Derision: Fix to display Frogloks correctly in /who all and /who all froglok (half of the change came from a post by Theeper on the forums). -Required SQL: +Required SQL: ALTER TABLE `tasks` ADD `minlevel` TINYINT UNSIGNED NOT NULL DEFAULT '0', ADD `maxlevel` TINYINT UNSIGNED NOT NULL DEFAULT '0'; @@ -6745,7 +7206,7 @@ cavedude00: (AndMetal) Slippery Attacks AA cavedude00: (trevius/Derision) Additional IP limiting rules cavedude00: (Congdar) Further PC main and second hand attack fixes cavedude00: (Derision) Fix for percent heals -cavedude00: (Theeper) Fix for quest:itemlink() +cavedude00: (Theeper) Fix for quest:itemlink() cavedude00: (Rocker8956) More work on zone instancing Optional SQL: @@ -6902,7 +7363,7 @@ KLS: (irv0) Fix for out of order ack not being sent in some situations. KLS: (Derision) Pet bar OOC update fix. KLS: Should have made client pets unable to give experience, untested but should work. KLS: Healing aggro should function better for people not on the hate list. -KLS: Some work on public tradeskill objects saving their content between uses. +KLS: Some work on public tradeskill objects saving their content between uses. ==06/22/2008 KLS: Changed world/clientlist.cpp's line endings back to unix style line endings @@ -6977,7 +7438,7 @@ CREATE TABLE `hackers` ( `zone` text, `date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, PRIMARY KEY (`id`) -) AUTO_INCREMENT=8; +) AUTO_INCREMENT=8; ==04/26/2008 KLS: Should have fixed discipline and combat ability timer overlap. @@ -7003,7 +7464,7 @@ Rogean: Fixed #hideme, it won't show you zone in and then disappear anymore. (Re Rogean: Fixed /summon. Rogean: Changes to /who all and GM's: * GM * Tags will no longer show up unless your #gm on - You will not show up to players of lower status if your /anon and #gm on, if your #gm off and /anon you will show up as + You will not show up to players of lower status if your /anon and #gm on, if your #gm off and /anon you will show up as a normal player, regardless of statuses. ==04/09/2008 @@ -7110,7 +7571,7 @@ KLS: Ironed out some quirks between min hit and the AC code that was keeping it KLS: (Knightly)#time should no longer be off by an hour, $zonehour, $zonemin and $zonetime are now exported to perl KLS: Added player quests, player quests are quests designed to be attached to player processes such as zoning and clicking objects. KLS: Player quests are loaded as either 'quests/zonename/player.pl' or as a template in 'quests/template/player.pl' -KLS: Player quests will export qglobals the client should be able to see and the following events are available for player quests: +KLS: Player quests will export qglobals the client should be able to see and the following events are available for player quests: EVENT_TIMER with var $timer EVENT_CLICKDOOR with var $doorid EVENT_LOOT with vars $looted_id and $looted_charges @@ -7238,7 +7699,7 @@ NPC:OOCRegen (Default: 0) KLS: Fixed logic on duration 7 formula.. again. ==12/02/2007 -KLS: Reworked buff duration formula 7 calculations. +KLS: Reworked buff duration formula 7 calculations. KLS: (Cripp)Added (Missing?) pathing z rules. ==11/30/2007 @@ -7352,7 +7813,7 @@ KLS: NPCs should now accept signals while engaged in combat. FatherNitwit: Quick fix for Divine Aura on pets exploit (KingMort) ==10/09/2007 -KLS: Tweaked my AC system a bit, should get less default defense and the system should be much more lienent overall, +KLS: Tweaked my AC system a bit, should get less default defense and the system should be much more lienent overall, goal is to allow people to see more of a benefit from having AC. ==09/24/2007 @@ -7364,7 +7825,7 @@ KLS: Small changes to the order in the getweapondamage code to make it a little KLS: Added a field that allows you to override a factions innate desire to assist their own faction in battle to the npc_faction table Required SQL: -alter table npc_faction add column ignore_primary_assist tinyint(3) not null default 0; +alter table npc_faction add column ignore_primary_assist tinyint(3) not null default 0; ==09/02/2007 KLS: Fixed an issue with items adding stats to NPCs exponentially. @@ -7383,7 +7844,7 @@ KLS: The error in acmod() should no longer complain as much. Required: Opcode files have changed, be sure to update to the latest .conf files. ==08/30/2007 -KLS: Reworked Mob::GetWeaponDamage(), it will now return damage done by any item and NULL and will return a +KLS: Reworked Mob::GetWeaponDamage(), it will now return damage done by any item and NULL and will return a value zero or less if we can't hit a mob with said item KLS: Applied new GetWeaponDamage() to Attack and Special Attack code KLS: Seperated Finishing Blow code to it's own function @@ -7553,8 +8014,8 @@ WildcardX: Area of effect beneficial spells will no longer affect non-player cha ==2/16/2007 KLS: Updating Changelog AA work to be more clear as well as the required SQL. -Required SQL: -alter table altadv_vars add column cost_inc tinyint(4) not null default 0; +Required SQL: +alter table altadv_vars add column cost_inc tinyint(4) not null default 0; Optionally: Source in AA_data.sql @@ -7769,7 +8230,7 @@ CREATE TABLE skill_caps ( ); ==11/07/2006 -KLS: Changed how critical hits work, as a result things that could not crit before like special attacks, now can. +KLS: Changed how critical hits work, as a result things that could not crit before like special attacks, now can. KLS: Cleave like effects should be fixed to do an increase of your already standing chance to critical instead of a flat increase. KLS: Reworked much of the special attack code. KLS: Applied haste to combat skill timers, they should give trouble much less often. @@ -7815,7 +8276,7 @@ FatherNitwit: Tweak for 64 bit pointer support in the item code of the struct st FatherNitwit: More const cleanup in npc.h ==10/22/2006 -FatherNitwit: added EVENT_COMBAT triggered when an NPC engages any form of +FatherNitwit: added EVENT_COMBAT triggered when an NPC engages any form of FatherNitwit: combat and when combat is over. $combat_state signals which. FatherNitwit: Hopefully fixed d_meele_texture FatherNitwit: Cleaned up a lot of const related issues (attrs, AAs, and more) @@ -8124,7 +8585,7 @@ FatherNitwit: Fixed countless rediculous things about guilds. FatherNitwit: Any change in guild state should update in real time now. FatherNitwit: Guild leadership may need re-establishing since it changed from account to char based. FatherNitwit: Guild structure in database has changed significantly. -Note: custom rank stuff is too much work for me to preserve in the DB, since I doubt +Note: custom rank stuff is too much work for me to preserve in the DB, since I doubt anybody uses it, so if you have them, you can figure it out yourself or remake them. Required SQL: ALTER TABLE character_ ADD class TINYINT NOT NULL DEFAULT 0; @@ -8467,7 +8928,7 @@ ALTER TABLE npc_types ADD AGI MEDIUMINT UNSIGNED NOT NULL DEFAULT '75'; ALTER TABLE npc_types ADD _INT MEDIUMINT UNSIGNED NOT NULL DEFAULT '75'; ALTER TABLE npc_types ADD WIS MEDIUMINT UNSIGNED NOT NULL DEFAULT '75'; ALTER TABLE npc_types ADD CHA MEDIUMINT UNSIGNED NOT NULL DEFAULT '75'; - + ==09/23/2005 FatherNitwit: Inverted XY coordinates on in zone objects and ground spawns. FatherNitwit: Maybe fixed quests setting a waypoint in EVENT_WAYPOINT @@ -8631,7 +9092,7 @@ Doodman: New item structure is in: Item fields now match the dump from (utils/load_13thfloor_items.pl) eqitems.13th-floor.org Item table convert script: utils/items-0.6.0-DR2-0.6.1-DR1-convert.sql - + ==01/10/2005 FatherNitwit: Disable sleep() in perl, it is bad news. FatherNitwit: Fixed guild MOTD at login (hopefully). @@ -8901,7 +9362,7 @@ WR Merges: - pets should actually taunt now. - rouge pets should backstab now. - optional: group buffs hit group pets now. -- fixed memory blur chances +- fixed memory blur chances - several minor group tweaks, should make groups more stable - improved duel messages - optional random luclin attributes for NPCs with boring faces @@ -9293,7 +9754,7 @@ kathgar: Fixed, SE_Fear, SE_SpinStun, SE_Charm for fixed duration spells and no Added member bool client to Buff_Struct to aid in above fix Fixed solar's changelog entry where he spelled my name wrong No EQLive fixes in this change -solar: fixed a bug that was causing people to be set as gm when they shouldn't +solar: fixed a bug that was causing people to be set as gm when they shouldn't ==2/15/2004 solar: characters being created are checked for validity now. thanks to @@ -9409,7 +9870,7 @@ solar: Buff fading should work for slots besides the first one now. This will solar: sense heading skill will now improve as you move around ==1/19/2004= -Scorpious2k: fixed faction command for quests +Scorpious2k: fixed faction command for quests LethalEncounter: Fixed a problem with queued cursor items. solar: fixes to #gassign @@ -9464,24 +9925,24 @@ LethalEncounter: Fixed loot messages. LethalEncounter: Fixed loot so right click autoequips correctly now. ==1/4/04== -MYRA: changed to new opcode for follow -MYRA: changed to new opcode for taunt -MYRA: use new (5.x) Status labels in who for telnet connection -MYRA: Added code to depop at end of grid for wander type 4 -MYRA: Added wander type 4 (single run) -MYRA: fixed eval in ExportVar per Eglin -MYRA: corrected spelling for var $uguildrank for event_timer (was $uguildrang) -MYRA: added vars $status & $cumflag per Eglin -MYRA: added vars $mobid & $mlevel per Eglin -MYRA: added missing commands + itemlink to perl -MYRA: added EVAL & KEEPERR to eval per Eglin's recommendation -MYRA: restore missing commands for qst type files & add itemlink -MYRA: fixed comma bug for me command -MYRA: fixed comma bug for echo command -MYRA: fixed comma bug for say command -MYRA: fixed comma bug for emote command -MYRA: fixed comma bug for shout command -MYRA: added itemlink(ItemNumber) command +MYRA: changed to new opcode for follow +MYRA: changed to new opcode for taunt +MYRA: use new (5.x) Status labels in who for telnet connection +MYRA: Added code to depop at end of grid for wander type 4 +MYRA: Added wander type 4 (single run) +MYRA: fixed eval in ExportVar per Eglin +MYRA: corrected spelling for var $uguildrank for event_timer (was $uguildrang) +MYRA: added vars $status & $cumflag per Eglin +MYRA: added vars $mobid & $mlevel per Eglin +MYRA: added missing commands + itemlink to perl +MYRA: added EVAL & KEEPERR to eval per Eglin's recommendation +MYRA: restore missing commands for qst type files & add itemlink +MYRA: fixed comma bug for me command +MYRA: fixed comma bug for echo command +MYRA: fixed comma bug for say command +MYRA: fixed comma bug for emote command +MYRA: fixed comma bug for shout command +MYRA: added itemlink(ItemNumber) command ==1/2/04== @@ -9630,7 +10091,7 @@ solar: HP wasn't being updated to client properly and would fall out of sync LethalEncounter: Fixed a bug in doors that would cause triggered doors to go into an endless loop and crash. ==11/13/03== -kathgar: Fixed a crash when calling ZSList::FindByZoneID() when sending an invalid zone number. +kathgar: Fixed a crash when calling ZSList::FindByZoneID() when sending an invalid zone number. Stack was corrupt in the backtrace, so I am not sure what called it in this way. LethalEncounter: Fixed animation bug with attack. LethalEncounter: Fixed Tradeskills (again) @@ -9664,7 +10125,7 @@ IsEngaged(), so it always returned false, now it uses AutoAttackEnabled() in its Image: Reversed the AICheckCloseSpells if statements, now sanity checks before distance check, uses less CPU usage. ==11/05/03== -LethalEncounter: Updated all of the opcodes that were changed in the patch today. +LethalEncounter: Updated all of the opcodes that were changed in the patch today. LethalEncounter: Refined AA's some, added table to hold the timers for AA's so users can exploit them. Look in db.sql for the table. diff --git a/client_files/export/main.cpp b/client_files/export/main.cpp index 865fbd6d8..2eda87411 100644 --- a/client_files/export/main.cpp +++ b/client_files/export/main.cpp @@ -32,6 +32,7 @@ EQEmuLogSys Log; void ExportSpells(SharedDatabase *db); void ExportSkillCaps(SharedDatabase *db); void ExportBaseData(SharedDatabase *db); +void ExportDBStrings(SharedDatabase *db); int main(int argc, char **argv) { RegisterExecutablePlatform(ExePlatformClientExport); @@ -44,12 +45,12 @@ int main(int argc, char **argv) { return 1; } - const EQEmuConfig *config = EQEmuConfig::get(); + auto Config = EQEmuConfig::get(); SharedDatabase database; Log.Out(Logs::General, Logs::Status, "Connecting to database..."); - if(!database.Connect(config->DatabaseHost.c_str(), config->DatabaseUsername.c_str(), - config->DatabasePassword.c_str(), config->DatabaseDB.c_str(), config->DatabasePort)) { + if(!database.Connect(Config->DatabaseHost.c_str(), Config->DatabaseUsername.c_str(), + Config->DatabasePassword.c_str(), Config->DatabaseDB.c_str(), Config->DatabasePort)) { Log.Out(Logs::General, Logs::Error, "Unable to connect to the database, cannot continue without a " "database connection"); return 1; @@ -62,6 +63,7 @@ int main(int argc, char **argv) { ExportSpells(&database); ExportSkillCaps(&database); ExportBaseData(&database); + ExportDBStrings(&database); Log.CloseFileLogs(); @@ -194,7 +196,38 @@ void ExportBaseData(SharedDatabase *db) { fprintf(f, "%s\n", line.c_str()); } - } else { + } + + fclose(f); +} + +void ExportDBStrings(SharedDatabase *db) { + Log.Out(Logs::General, Logs::Status, "Exporting DB Strings..."); + + FILE *f = fopen("export/dbstr_us.txt", "w"); + if(!f) { + Log.Out(Logs::General, Logs::Error, "Unable to open export/dbstr_us.txt to write, skipping."); + return; + } + + fprintf(f, "Major^Minor^String(New)\n"); + const std::string query = "SELECT * FROM db_str ORDER BY id, type"; + auto results = db->QueryDatabase(query); + if(results.Success()) { + for(auto row = results.begin(); row != results.end(); ++row) { + std::string line; + unsigned int fields = results.ColumnCount(); + for(unsigned int rowIndex = 0; rowIndex < fields; ++rowIndex) { + if(rowIndex != 0) + line.push_back('^'); + + if(row[rowIndex] != nullptr) { + line += row[rowIndex]; + } + } + + fprintf(f, "%s\n", line.c_str()); + } } fclose(f); diff --git a/client_files/import/main.cpp b/client_files/import/main.cpp index 3a2f4154f..defd64f98 100644 --- a/client_files/import/main.cpp +++ b/client_files/import/main.cpp @@ -30,6 +30,7 @@ EQEmuLogSys Log; void ImportSpells(SharedDatabase *db); void ImportSkillCaps(SharedDatabase *db); void ImportBaseData(SharedDatabase *db); +void ImportDBStrings(SharedDatabase *db); int main(int argc, char **argv) { RegisterExecutablePlatform(ExePlatformClientImport); @@ -42,12 +43,12 @@ int main(int argc, char **argv) { return 1; } - const EQEmuConfig *config = EQEmuConfig::get(); + auto Config = EQEmuConfig::get(); SharedDatabase database; Log.Out(Logs::General, Logs::Status, "Connecting to database..."); - if(!database.Connect(config->DatabaseHost.c_str(), config->DatabaseUsername.c_str(), - config->DatabasePassword.c_str(), config->DatabaseDB.c_str(), config->DatabasePort)) { + if(!database.Connect(Config->DatabaseHost.c_str(), Config->DatabaseUsername.c_str(), + Config->DatabasePassword.c_str(), Config->DatabaseDB.c_str(), Config->DatabasePort)) { Log.Out(Logs::General, Logs::Error, "Unable to connect to the database, cannot continue without a " "database connection"); return 1; @@ -59,6 +60,7 @@ int main(int argc, char **argv) { ImportSpells(&database); ImportSkillCaps(&database); ImportBaseData(&database); + ImportDBStrings(&database); Log.CloseFileLogs(); @@ -202,7 +204,6 @@ void ImportSkillCaps(SharedDatabase *db) { continue; } - int class_id, skill_id, level, cap; class_id = atoi(split[0].c_str()); skill_id = atoi(split[1].c_str()); @@ -262,3 +263,56 @@ void ImportBaseData(SharedDatabase *db) { fclose(f); } + +void ImportDBStrings(SharedDatabase *db) { + Log.Out(Logs::General, Logs::Status, "Importing DB Strings..."); + + FILE *f = fopen("import/dbstr_us.txt", "r"); + if(!f) { + Log.Out(Logs::General, Logs::Error, "Unable to open import/dbstr_us.txt to read, skipping."); + return; + } + + std::string delete_sql = "DELETE FROM db_str"; + db->QueryDatabase(delete_sql); + + char buffer[2048]; + bool first = true; + while(fgets(buffer, 2048, f)) { + if(first) { + first = false; + continue; + } + + for(int i = 0; i < 2048; ++i) { + if(buffer[i] == '\n') { + buffer[i] = 0; + break; + } + } + + auto split = SplitString(buffer, '^'); + + if(split.size() < 2) { + continue; + } + + std::string sql; + int id, type; + std::string value; + + id = atoi(split[0].c_str()); + type = atoi(split[1].c_str()); + + if(split.size() >= 3) { + value = ::EscapeString(split[2]); + } + + sql = StringFormat("INSERT INTO db_str(id, type, value) VALUES(%u, %u, '%s')", + id, type, value.c_str()); + + db->QueryDatabase(sql); + } + + fclose(f); +} diff --git a/cmake/FindMySQL.cmake b/cmake/FindMySQL.cmake index 14d08b695..5a7927552 100644 --- a/cmake/FindMySQL.cmake +++ b/cmake/FindMySQL.cmake @@ -21,6 +21,12 @@ IF(MYSQL_ROOT) NAMES mysql.h PATHS ${MYSQL_ROOT}/include PATH_SUFFIXES mysql + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + ) + FIND_PATH(MySQL_INCLUDE_DIR + NAMES mysql.h + PATH_SUFFIXES mysql ) ELSE(MYSQL_ROOT) FIND_PATH(MySQL_INCLUDE_DIR @@ -30,49 +36,46 @@ ELSE(MYSQL_ROOT) ENDIF(MYSQL_ROOT) # Library -SET(MySQL_NAMES mysqlclient_r mysqlclient) +SET(MySQL_NAMES libmysql) IF(MYSQL_ROOT) - FIND_LIBRARY(MySQL_LIBRARY_DEBUG + FIND_LIBRARY(MySQL_LIBRARY NAMES ${MySQL_NAMES} - PATHS ${MYSQL_ROOT}/lib/debug /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 + PATHS ${MYSQL_ROOT}/lib PATH_SUFFIXES mysql + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH ) - - FIND_LIBRARY(MySQL_LIBRARY_RELEASE + + FIND_LIBRARY(MySQL_LIBRARY NAMES ${MySQL_NAMES} - PATHS ${MYSQL_ROOT}/lib /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 PATH_SUFFIXES mysql ) ELSE(MYSQL_ROOT) - FIND_LIBRARY(MySQL_LIBRARY_DEBUG - NAMES ${MySQL_NAMES} - PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 - PATH_SUFFIXES mysql - ) - - FIND_LIBRARY(MySQL_LIBRARY_RELEASE - NAMES ${MySQL_NAMES} + FIND_LIBRARY(MySQL_LIBRARY + NAMES ${MySQL_NAMES} mysqlclient_r mysqlclient PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 PATH_SUFFIXES mysql ) ENDIF(MYSQL_ROOT) -IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE) +IF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) SET(MySQL_FOUND TRUE) - SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} ) -ELSE (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE) + SET( MySQL_LIBRARIES ${MySQL_LIBRARY} ) +ELSE (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) SET(MySQL_FOUND FALSE) SET( MySQL_LIBRARIES ) -ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY_DEBUG AND MySQL_LIBRARY_RELEASE) +ENDIF (MySQL_INCLUDE_DIR AND MySQL_LIBRARY) # handle the QUIETLY and REQUIRED arguments and set MySQL_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(MySQL DEFAULT_MSG MySQL_LIBRARY_DEBUG MySQL_LIBRARY_RELEASE MySQL_INCLUDE_DIR) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MySQL DEFAULT_MSG MySQL_LIBRARY MySQL_INCLUDE_DIR) IF(MySQL_FOUND) - SET( MySQL_LIBRARIES ${MySQL_LIBRARY_DEBUG} ${MySQL_LIBRARY_RELEASE} ) + SET( MySQL_LIBRARY_RELEASE ${MySQL_LIBRARY} ) + SET( MySQL_LIBRARY_DEBUG ${MySQL_LIBRARY} ) + SET( MySQL_LIBRARIES ${MySQL_LIBRARY_RELEASE} ${MySQL_LIBRARY_DEBUG} ) ELSE(MySQL_FOUND) SET( MySQL_LIBRARIES ) ENDIF(MySQL_FOUND) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 21effae1e..6bfb72090 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -11,15 +11,20 @@ SET(common_sources database_conversions.cpp database_instances.cpp dbcore.cpp + deity.cpp + emu_constants.cpp + emu_legacy.cpp + emu_limits.cpp emu_opcodes.cpp emu_tcp_connection.cpp emu_tcp_server.cpp - eq_dictionary.cpp + emu_versions.cpp eqdb.cpp eqdb_res.cpp eqemu_exception.cpp eqemu_config.cpp eqemu_logsys.cpp + eq_limits.cpp eq_packet.cpp eq_stream.cpp eq_stream_factory.cpp @@ -32,7 +37,10 @@ SET(common_sources guilds.cpp ipc_mutex.cpp item.cpp + item_base.cpp + light_source.cpp md5.cpp + memory_buffer.cpp memory_mapped_file.cpp misc.cpp misc_functions.cpp @@ -51,6 +59,7 @@ SET(common_sources races.cpp rdtsc.cpp rulesys.cpp + say_link.cpp serverinfo.cpp shareddb.cpp skills.cpp @@ -59,6 +68,7 @@ SET(common_sources struct_strategy.cpp tcp_connection.cpp tcp_server.cpp + textures.cpp timeoutmgr.cpp timer.cpp unix.cpp @@ -69,11 +79,17 @@ SET(common_sources platform.cpp patches/patches.cpp patches/sod.cpp + patches/sod_limits.cpp patches/sof.cpp + patches/sof_limits.cpp patches/rof.cpp + patches/rof_limits.cpp patches/rof2.cpp + patches/rof2_limits.cpp patches/titanium.cpp + patches/titanium_limits.cpp patches/uf.cpp + patches/uf_limits.cpp SocketLib/Base64.cpp SocketLib/File.cpp SocketLib/HttpdCookies.cpp @@ -106,12 +122,15 @@ SET(common_headers database.h dbcore.h deity.h + emu_constants.h + emu_legacy.h + emu_limits.h emu_opcodes.h emu_oplist.h emu_tcp_connection.h emu_tcp_server.h + emu_versions.h eq_constants.h - eq_dictionary.h eq_packet_structs.h eqdb.h eqdb_res.h @@ -119,6 +138,7 @@ SET(common_headers eqemu_config.h eqemu_config_elements.h eqemu_logsys.h + eq_limits.h eq_packet.h eq_stream.h eq_stream_factory.h @@ -139,13 +159,15 @@ SET(common_headers guilds.h ipc_mutex.h item.h + item_base.h item_fieldlist.h - item_struct.h languages.h + light_source.h linked_list.h loottable.h mail_oplist.h md5.h + memory_buffer.h memory_mapped_file.h misc.h misc_functions.h @@ -168,6 +190,7 @@ SET(common_headers rdtsc.h rulesys.h ruletypes.h + say_link.h seperator.h serverinfo.h servertalk.h @@ -179,6 +202,7 @@ SET(common_headers tcp_basic_server.h tcp_connection.h tcp_server.h + textures.h timeoutmgr.h timer.h types.h @@ -192,37 +216,38 @@ SET(common_headers zone_numbers.h patches/patches.h patches/sod.h - patches/sod_constants.h - patches/sod_itemfields.h +# patches/sod_itemfields.h + patches/sod_limits.h patches/sod_ops.h patches/sod_structs.h patches/sof.h - patches/sof_constants.h - patches/sof_itemfields.h - patches/sof_opcode_list.h +# patches/sof_itemfields.h + patches/sof_limits.h +# patches/sof_opcode_list.h patches/sof_ops.h patches/sof_structs.h patches/ss_declare.h patches/ss_define.h patches/ss_register.h patches/rof.h - patches/rof_constants.h - patches/rof_itemfields.h +# patches/rof_itemfields.h + patches/rof_limits.h patches/rof_ops.h patches/rof_structs.h patches/rof2.h - patches/rof2_constants.h - patches/rof2_itemfields.h +# patches/rof2_itemfields.h + patches/rof2_limits.h patches/rof2_ops.h patches/rof2_structs.h patches/titanium.h - patches/titanium_constants.h - patches/titanium_itemfields.h +# patches/titanium_itemfields_a.h +# patches/titanium_itemfields_b.h + patches/titanium_limits.h patches/titanium_ops.h patches/titanium_structs.h patches/uf.h - patches/uf_constants.h - patches/uf_itemfields.h +# patches/uf_itemfields.h + patches/uf_limits.h patches/uf_ops.h patches/uf_structs.h SocketLib/Base64.h @@ -245,46 +270,53 @@ SET(common_headers SOURCE_GROUP(Patches FILES patches/patches.h patches/sod.h - patches/sod_itemfields.h +# patches/sod_itemfields.h + patches/sod_limits.h patches/sod_ops.h - patches/sod_constants.h patches/sod_structs.h patches/sof.h - patches/sof_itemfields.h - patches/sof_opcode_list.h +# patches/sof_itemfields.h + patches/sof_limits.h +# patches/sof_opcode_list.h patches/sof_ops.h - patches/sof_constants.h patches/sof_structs.h patches/ss_declare.h patches/ss_define.h patches/ss_register.h patches/rof.h - patches/rof_itemfields.h +# patches/rof_itemfields.h + patches/rof_limits.h patches/rof_ops.h - patches/rof_constants.h patches/rof_structs.h patches/rof2.h - patches/rof2_itemfields.h +# patches/rof2_itemfields.h + patches/rof2_limits.h patches/rof2_ops.h - patches/rof2_constants.h patches/rof2_structs.h patches/titanium.h - patches/titanium_itemfields.h +# patches/titanium_itemfields_a.h +# patches/titanium_itemfields_b.h + patches/titanium_limits.h patches/titanium_ops.h - patches/titanium_constants.h patches/titanium_structs.h patches/uf.h - patches/uf_itemfields.h +# patches/uf_itemfields.h + patches/uf_limits.h patches/uf_ops.h - patches/uf_constants.h patches/uf_structs.h patches/patches.cpp patches/sod.cpp + patches/sod_limits.cpp patches/sof.cpp + patches/sof_limits.cpp patches/rof.cpp + patches/rof_limits.cpp patches/rof2.cpp + patches/rof2_limits.cpp patches/titanium.cpp + patches/titanium_limits.cpp patches/uf.cpp + patches/uf_limits.cpp ) SOURCE_GROUP(SocketLib FILES diff --git a/common/base_packet.h b/common/base_packet.h index 027b8d2fb..bdd774aa2 100644 --- a/common/base_packet.h +++ b/common/base_packet.h @@ -22,10 +22,10 @@ #include #include -#ifdef WIN32 +#ifdef _WINDOWS #include - #include #include + #include #else #include #include @@ -67,6 +67,8 @@ public: uint8 ReadUInt8() { uint8 value = *(uint8 *)(pBuffer + _rpos); _rpos += sizeof(uint8); return value; } uint8 ReadUInt8(uint32 Offset) const { uint8 value = *(uint8 *)(pBuffer + Offset); return value; } + uint16 ReadUInt16() { uint16 value = *(uint16 *)(pBuffer + _rpos); _rpos += sizeof(uint16); return value; } + uint16 ReadUInt16(uint32 Offset) const { uint16 value = *(uint16 *)(pBuffer + Offset); return value; } uint32 ReadUInt32() { uint32 value = *(uint32 *)(pBuffer + _rpos); _rpos += sizeof(uint32); return value; } uint32 ReadUInt32(uint32 Offset) const { uint32 value = *(uint32 *)(pBuffer + Offset); return value; } void ReadString(char *str) { uint32 len = static_cast(strlen((char *)(pBuffer + _rpos))) + 1; memcpy(str, pBuffer + _rpos, len); _rpos += len; } diff --git a/common/classes.cpp b/common/classes.cpp index 1f54c9234..58aa56602 100644 --- a/common/classes.cpp +++ b/common/classes.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,275 +18,576 @@ #include "../common/global_define.h" #include "../common/classes.h" -const char* GetEQClassName(uint8 class_, uint8 level) { - switch(class_) { - case WARRIOR: - if (level >= 70) - return "Vanquisher"; - else if (level >= 65) - return "Overlord"; //Baron-Sprite: LEAVE MY CLASSES ALONE. - else if (level >= 60) - return "Warlord"; - else if (level >= 55) - return "Myrmidon"; - else if (level >= 51) - return "Champion"; - else - return "Warrior"; - case CLERIC: - if (level >= 70) - return "Prelate"; - else if (level >= 65) - return "Archon"; - else if (level >= 60) - return "High Priest"; - else if (level >= 55) - return "Templar"; - else if (level >= 51) - return "Vicar"; - else - return "Cleric"; - case PALADIN: - if (level >= 70) - return "Lord"; - else if (level >= 65) - return "Lord Protector"; - else if (level >= 60) - return "Crusader"; - else if (level >= 55) - return "Knight"; - else if (level >= 51) - return "Cavalier"; - else - return "Paladin"; - case RANGER: - if (level >= 70) - return "Plainswalker"; - else if (level >= 65) - return "Forest Stalker"; - else if (level >= 60) - return "Warder"; - else if (level >= 55) - return "Outrider"; - else if (level >= 51) - return "Pathfinder"; - else - return "Ranger"; - case SHADOWKNIGHT: - if (level >= 70) - return "Scourge Knight"; - else if (level >= 65) - return "Dread Lord"; - else if (level >= 60) - return "Grave Lord"; - else if (level >= 55) - return "Revenant"; - else if (level >= 51) - return "Reaver"; - else - return "Shadowknight"; - case DRUID: - if (level >= 70) - return "Natureguard"; - else if (level >= 65) - return "Storm Warden"; - else if (level >= 60) - return "Hierophant"; - else if (level >= 55) - return "Preserver"; - else if (level >= 51) - return "Wanderer"; - else - return "Druid"; - case MONK: - if (level >= 70) - return "Stone Fist"; - else if (level >= 65) - return "Transcendent"; - else if (level >= 60) - return "Grandmaster"; - else if (level >= 55) - return "Master"; - else if (level >= 51) - return "Disciple"; - else - return "Monk"; - case BARD: - if (level >= 70) - return "Performer"; - else if (level >= 65) - return "Maestro"; - else if (level >= 60) - return "Virtuoso"; - else if (level >= 55) - return "Troubadour"; - else if (level >= 51) - return "Minstrel"; - else - return "Bard"; - case ROGUE: - if (level >= 70) - return "Nemesis"; - else if (level >= 65) - return "Deceiver"; - else if (level >= 60) - return "Assassin"; - else if (level >= 55) - return "Blackguard"; - else if (level >= 51) - return "Rake"; - else - return "Rogue"; - case SHAMAN: - if (level >= 70) - return "Soothsayer"; - else if (level >= 65) - return "Prophet"; - else if (level >= 60) - return "Oracle"; - else if (level >= 55) - return "Luminary"; - else if (level >= 51) - return "Mystic"; - else - return "Shaman"; - case NECROMANCER: - if (level >= 70) - return "Wraith"; - else if (level >= 65) - return "Arch Lich"; - else if (level >= 60) - return "Warlock"; - else if (level >= 55) - return "Defiler"; - else if (level >= 51) - return "Heretic"; - else - return "Necromancer"; - case WIZARD: - if (level >= 70) - return "Grand Arcanist"; - else if (level >= 65) - return "Arcanist"; - else if (level >= 60) - return "Sorcerer"; - else if (level >= 55) - return "Evoker"; - else if (level >= 51) - return "Channeler"; - else - return "Wizard"; - case MAGICIAN: - if (level >= 70) - return "Arch Magus"; - else if (level >= 65) - return "Arch Convoker"; - else if (level >= 60) - return "Arch Mage"; - else if (level >= 55) - return "Conjurer"; - if (level >= 51) - return "Elementalist"; - else - return "Magician"; - case ENCHANTER: - if (level >= 70) - return "Bedazzler"; - else if (level >= 65) - return "Coercer"; - else if (level >= 60) - return "Phantasmist"; - else if (level >= 55) - return "Beguiler"; - else if (level >= 51) - return "Illusionist"; - else - return "Enchanter"; - case BEASTLORD: - if (level >= 70) - return "Wildblood"; - else if (level >= 65) - return "Feral Lord"; - else if (level >= 60) - return "Savage Lord"; - else if (level >= 55) - return "Animist"; - else if (level >= 51) - return "Primalist"; - else - return "Beastlord"; - case BERSERKER: - if (level >= 70) - return "Ravager"; - else if (level >= 65) - return "Fury"; - else if (level >= 60) - return "Rager"; - else if (level >= 55) - return "Vehement"; - else if (level >= 51) - return "Brawler"; - else - return "Berserker"; - case BANKER: - if (level >= 70) - return "Master Banker"; - else if (level >= 65) - return "Elder Banker"; - else if (level >= 60) - return "Oldest Banker"; - else if (level >= 55) - return "Older Banker"; - else if (level >= 51) - return "Old Banker"; - else - return "Banker"; - case WARRIORGM: - return "Warrior Guildmaster"; - case CLERICGM: - return "Cleric Guildmaster"; - case PALADINGM: - return "Paladin Guildmaster"; - case RANGERGM: - return "Ranger Guildmaster"; - case SHADOWKNIGHTGM: - return "Shadowknight Guildmaster"; - case DRUIDGM: - return "Druid Guildmaster"; - case MONKGM: - return "Monk Guildmaster"; - case BARDGM: - return "Bard Guildmaster"; - case ROGUEGM: - return "Rogue Guildmaster"; - case SHAMANGM: - return "Shaman Guildmaster"; - case NECROMANCERGM: - return "Necromancer Guildmaster"; - case WIZARDGM: - return "Wizard Guildmaster"; - case MAGICIANGM: - return "Magician Guildmaster"; - case ENCHANTERGM: - return "Enchanter Guildmaster"; - case BEASTLORDGM: - return "Beastlord Guildmaster"; - case BERSERKERGM: - return "Berserker Guildmaster"; - case MERCHANT: - return "Merchant"; - case ADVENTURERECRUITER: - return "Adventure Recruiter"; - case ADVENTUREMERCHANT: - return "Adventure Merchant"; - case CORPSE_CLASS: - return "Corpse Class"; - case TRIBUTE_MASTER: - return "Tribute Master"; - case GUILD_TRIBUTE_MASTER: - return "Guild Tribute Master"; - default: - return "Unknown"; +const char* GetClassIDName(uint8 class_id, uint8 level) +{ + switch (class_id) { + case WARRIOR: + if (level >= 70) + return "Vanquisher"; + else if (level >= 65) + return "Overlord"; //Baron-Sprite: LEAVE MY CLASSES ALONE. + else if (level >= 60) + return "Warlord"; + else if (level >= 55) + return "Myrmidon"; + else if (level >= 51) + return "Champion"; + else + return "Warrior"; + case CLERIC: + if (level >= 70) + return "Prelate"; + else if (level >= 65) + return "Archon"; + else if (level >= 60) + return "High Priest"; + else if (level >= 55) + return "Templar"; + else if (level >= 51) + return "Vicar"; + else + return "Cleric"; + case PALADIN: + if (level >= 70) + return "Lord"; + else if (level >= 65) + return "Lord Protector"; + else if (level >= 60) + return "Crusader"; + else if (level >= 55) + return "Knight"; + else if (level >= 51) + return "Cavalier"; + else + return "Paladin"; + case RANGER: + if (level >= 70) + return "Plainswalker"; + else if (level >= 65) + return "Forest Stalker"; + else if (level >= 60) + return "Warder"; + else if (level >= 55) + return "Outrider"; + else if (level >= 51) + return "Pathfinder"; + else + return "Ranger"; + case SHADOWKNIGHT: + if (level >= 70) + return "Scourge Knight"; + else if (level >= 65) + return "Dread Lord"; + else if (level >= 60) + return "Grave Lord"; + else if (level >= 55) + return "Revenant"; + else if (level >= 51) + return "Reaver"; + else + return "Shadowknight"; + case DRUID: + if (level >= 70) + return "Natureguard"; + else if (level >= 65) + return "Storm Warden"; + else if (level >= 60) + return "Hierophant"; + else if (level >= 55) + return "Preserver"; + else if (level >= 51) + return "Wanderer"; + else + return "Druid"; + case MONK: + if (level >= 70) + return "Stone Fist"; + else if (level >= 65) + return "Transcendent"; + else if (level >= 60) + return "Grandmaster"; + else if (level >= 55) + return "Master"; + else if (level >= 51) + return "Disciple"; + else + return "Monk"; + case BARD: + if (level >= 70) + return "Performer"; + else if (level >= 65) + return "Maestro"; + else if (level >= 60) + return "Virtuoso"; + else if (level >= 55) + return "Troubadour"; + else if (level >= 51) + return "Minstrel"; + else + return "Bard"; + case ROGUE: + if (level >= 70) + return "Nemesis"; + else if (level >= 65) + return "Deceiver"; + else if (level >= 60) + return "Assassin"; + else if (level >= 55) + return "Blackguard"; + else if (level >= 51) + return "Rake"; + else + return "Rogue"; + case SHAMAN: + if (level >= 70) + return "Soothsayer"; + else if (level >= 65) + return "Prophet"; + else if (level >= 60) + return "Oracle"; + else if (level >= 55) + return "Luminary"; + else if (level >= 51) + return "Mystic"; + else + return "Shaman"; + case NECROMANCER: + if (level >= 70) + return "Wraith"; + else if (level >= 65) + return "Arch Lich"; + else if (level >= 60) + return "Warlock"; + else if (level >= 55) + return "Defiler"; + else if (level >= 51) + return "Heretic"; + else + return "Necromancer"; + case WIZARD: + if (level >= 70) + return "Grand Arcanist"; + else if (level >= 65) + return "Arcanist"; + else if (level >= 60) + return "Sorcerer"; + else if (level >= 55) + return "Evoker"; + else if (level >= 51) + return "Channeler"; + else + return "Wizard"; + case MAGICIAN: + if (level >= 70) + return "Arch Magus"; + else if (level >= 65) + return "Arch Convoker"; + else if (level >= 60) + return "Arch Mage"; + else if (level >= 55) + return "Conjurer"; + if (level >= 51) + return "Elementalist"; + else + return "Magician"; + case ENCHANTER: + if (level >= 70) + return "Bedazzler"; + else if (level >= 65) + return "Coercer"; + else if (level >= 60) + return "Phantasmist"; + else if (level >= 55) + return "Beguiler"; + else if (level >= 51) + return "Illusionist"; + else + return "Enchanter"; + case BEASTLORD: + if (level >= 70) + return "Wildblood"; + else if (level >= 65) + return "Feral Lord"; + else if (level >= 60) + return "Savage Lord"; + else if (level >= 55) + return "Animist"; + else if (level >= 51) + return "Primalist"; + else + return "Beastlord"; + case BERSERKER: + if (level >= 70) + return "Ravager"; + else if (level >= 65) + return "Fury"; + else if (level >= 60) + return "Rager"; + else if (level >= 55) + return "Vehement"; + else if (level >= 51) + return "Brawler"; + else + return "Berserker"; + case BANKER: + if (level >= 70) + return "Master Banker"; + else if (level >= 65) + return "Elder Banker"; + else if (level >= 60) + return "Oldest Banker"; + else if (level >= 55) + return "Older Banker"; + else if (level >= 51) + return "Old Banker"; + else + return "Banker"; + case WARRIORGM: + return "Warrior Guildmaster"; + case CLERICGM: + return "Cleric Guildmaster"; + case PALADINGM: + return "Paladin Guildmaster"; + case RANGERGM: + return "Ranger Guildmaster"; + case SHADOWKNIGHTGM: + return "Shadowknight Guildmaster"; + case DRUIDGM: + return "Druid Guildmaster"; + case MONKGM: + return "Monk Guildmaster"; + case BARDGM: + return "Bard Guildmaster"; + case ROGUEGM: + return "Rogue Guildmaster"; + case SHAMANGM: + return "Shaman Guildmaster"; + case NECROMANCERGM: + return "Necromancer Guildmaster"; + case WIZARDGM: + return "Wizard Guildmaster"; + case MAGICIANGM: + return "Magician Guildmaster"; + case ENCHANTERGM: + return "Enchanter Guildmaster"; + case BEASTLORDGM: + return "Beastlord Guildmaster"; + case BERSERKERGM: + return "Berserker Guildmaster"; + case MERCHANT: + return "Merchant"; + case ADVENTURERECRUITER: + return "Adventure Recruiter"; + case ADVENTUREMERCHANT: + return "Adventure Merchant"; + case CORPSE_CLASS: + return "Corpse Class"; + case TRIBUTE_MASTER: + return "Tribute Master"; + case GUILD_TRIBUTE_MASTER: + return "Guild Tribute Master"; + default: + return "Unknown"; } } +const char* GetPlayerClassName(uint32 player_class_value, uint8 level) +{ + return GetClassIDName(GetClassIDFromPlayerClassValue(player_class_value), level); +} + +uint32 GetPlayerClassValue(uint8 class_id) +{ + switch (class_id) { + case WARRIOR: + case CLERIC: + case PALADIN: + case RANGER: + case SHADOWKNIGHT: + case DRUID: + case MONK: + case BARD: + case ROGUE: + case SHAMAN: + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + case BEASTLORD: + case BERSERKER: + return class_id; + default: + return PLAYER_CLASS_UNKNOWN; // watch + } +} + +uint32 GetPlayerClassBit(uint8 class_id) +{ + switch (class_id) { + case WARRIOR: + return PLAYER_CLASS_WARRIOR_BIT; + case CLERIC: + return PLAYER_CLASS_CLERIC_BIT; + case PALADIN: + return PLAYER_CLASS_PALADIN_BIT; + case RANGER: + return PLAYER_CLASS_RANGER_BIT; + case SHADOWKNIGHT: + return PLAYER_CLASS_SHADOWKNIGHT_BIT; + case DRUID: + return PLAYER_CLASS_DRUID_BIT; + case MONK: + return PLAYER_CLASS_MONK_BIT; + case BARD: + return PLAYER_CLASS_BARD_BIT; + case ROGUE: + return PLAYER_CLASS_ROGUE_BIT; + case SHAMAN: + return PLAYER_CLASS_SHAMAN_BIT; + case NECROMANCER: + return PLAYER_CLASS_NECROMANCER_BIT; + case WIZARD: + return PLAYER_CLASS_WIZARD_BIT; + case MAGICIAN: + return PLAYER_CLASS_MAGICIAN_BIT; + case ENCHANTER: + return PLAYER_CLASS_ENCHANTER_BIT; + case BEASTLORD: + return PLAYER_CLASS_BEASTLORD_BIT; + case BERSERKER: + return PLAYER_CLASS_BERSERKER_BIT; + default: + return PLAYER_CLASS_UNKNOWN_BIT; + } +} + +uint8 GetClassIDFromPlayerClassValue(uint32 player_class_value) +{ + switch (player_class_value) { + case PLAYER_CLASS_WARRIOR: + case PLAYER_CLASS_CLERIC: + case PLAYER_CLASS_PALADIN: + case PLAYER_CLASS_RANGER: + case PLAYER_CLASS_SHADOWKNIGHT: + case PLAYER_CLASS_DRUID: + case PLAYER_CLASS_MONK: + case PLAYER_CLASS_BARD: + case PLAYER_CLASS_ROGUE: + case PLAYER_CLASS_SHAMAN: + case PLAYER_CLASS_NECROMANCER: + case PLAYER_CLASS_WIZARD: + case PLAYER_CLASS_MAGICIAN: + case PLAYER_CLASS_ENCHANTER: + case PLAYER_CLASS_BEASTLORD: + case PLAYER_CLASS_BERSERKER: + return player_class_value; + default: + return PLAYER_CLASS_UNKNOWN; // watch + } +} + +uint8 GetClassIDFromPlayerClassBit(uint32 player_class_bit) +{ + switch (player_class_bit) { + case PLAYER_CLASS_WARRIOR_BIT: + return WARRIOR; + case PLAYER_CLASS_CLERIC_BIT: + return CLERIC; + case PLAYER_CLASS_PALADIN_BIT: + return PALADIN; + case PLAYER_CLASS_RANGER_BIT: + return RANGER; + case PLAYER_CLASS_SHADOWKNIGHT_BIT: + return SHADOWKNIGHT; + case PLAYER_CLASS_DRUID_BIT: + return DRUID; + case PLAYER_CLASS_MONK_BIT: + return MONK; + case PLAYER_CLASS_BARD_BIT: + return BARD; + case PLAYER_CLASS_ROGUE_BIT: + return ROGUE; + case PLAYER_CLASS_SHAMAN_BIT: + return SHAMAN; + case PLAYER_CLASS_NECROMANCER_BIT: + return NECROMANCER; + case PLAYER_CLASS_WIZARD_BIT: + return WIZARD; + case PLAYER_CLASS_MAGICIAN_BIT: + return MAGICIAN; + case PLAYER_CLASS_ENCHANTER_BIT: + return ENCHANTER; + case PLAYER_CLASS_BEASTLORD_BIT: + return BEASTLORD; + case PLAYER_CLASS_BERSERKER_BIT: + return BERSERKER; + default: + return PLAYER_CLASS_UNKNOWN; // watch + } +} + +bool IsFighterClass(uint8 class_id) +{ + switch (class_id) { + case WARRIOR: + case PALADIN: + case RANGER: + case SHADOWKNIGHT: + case MONK: + case BARD: + case ROGUE: + case BEASTLORD: + case BERSERKER: + return true; + default: + return false; + } +} + +bool IsSpellFighterClass(uint8 class_id) +{ + switch (class_id) { + case PALADIN: + case RANGER: + case SHADOWKNIGHT: + case BEASTLORD: + return true; + default: + return false; + } +} + +bool IsNonSpellFighterClass(uint8 class_id) +{ + switch (class_id) { + case WARRIOR: + case MONK: + case BARD: + case ROGUE: + case BERSERKER: + return true; + default: + return false; + } +} + +bool IsCasterClass(uint8 class_id) +{ + switch (class_id) { + case CLERIC: + case DRUID: + case SHAMAN: + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return true; + default: + return false; + } +} + +bool IsINTCasterClass(uint8 class_id) +{ + switch (class_id) { + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return true; + default: + return false; + } +} + +bool IsWISCasterClass(uint8 class_id) +{ + switch (class_id) { + case CLERIC: + case DRUID: + case SHAMAN: + return true; + default: + return false; + } +} + +bool IsPlateClass(uint8 class_id) +{ + switch (class_id) { + case WARRIOR: + case CLERIC: + case PALADIN: + case SHADOWKNIGHT: + case BARD: + return true; + default: + return false; + } +} + +bool IsChainClass(uint8 class_id) +{ + switch (class_id) { + case RANGER: + case ROGUE: + case SHAMAN: + case BERSERKER: + return true; + default: + return false; + } +} + +bool IsLeatherClass(uint8 class_id) +{ + switch (class_id) { + case DRUID: + case MONK: + case BEASTLORD: + return true; + default: + return false; + } +} + +bool IsClothClass(uint8 class_id) +{ + switch (class_id) { + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return true; + default: + return false; + } +} + +uint8 ClassArmorType(uint8 class_id) +{ + switch (class_id) { + case WARRIOR: + case CLERIC: + case PALADIN: + case SHADOWKNIGHT: + case BARD: + return ARMOR_TYPE_PLATE; + case RANGER: + case ROGUE: + case SHAMAN: + case BERSERKER: + return ARMOR_TYPE_CHAIN; + case DRUID: + case MONK: + case BEASTLORD: + return ARMOR_TYPE_LEATHER; + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return ARMOR_TYPE_CLOTH; + default: + return ARMOR_TYPE_UNKNOWN; + } +} diff --git a/common/classes.h b/common/classes.h index c2f0c8acf..2ca9a3c4d 100644 --- a/common/classes.h +++ b/common/classes.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -17,26 +17,25 @@ */ #ifndef CLASSES_CH #define CLASSES_CH + #include "../common/types.h" -#define Array_Class_UNKNOWN 0 -#define WARRIOR 1 -#define CLERIC 2 -#define PALADIN 3 -#define RANGER 4 -#define SHADOWKNIGHT 5 -#define DRUID 6 -#define MONK 7 -#define BARD 8 -#define ROGUE 9 -#define SHAMAN 10 -#define NECROMANCER 11 -#define WIZARD 12 -#define MAGICIAN 13 -#define ENCHANTER 14 -#define BEASTLORD 15 -#define BERSERKER 16 -#define PLAYER_CLASS_COUNT 16 // used for array defines, must be the count of playable classes +#define WARRIOR 1 +#define CLERIC 2 +#define PALADIN 3 +#define RANGER 4 +#define SHADOWKNIGHT 5 +#define DRUID 6 +#define MONK 7 +#define BARD 8 +#define ROGUE 9 +#define SHAMAN 10 +#define NECROMANCER 11 +#define WIZARD 12 +#define MAGICIAN 13 +#define ENCHANTER 14 +#define BEASTLORD 15 +#define BERSERKER 16 #define WARRIORGM 20 #define CLERICGM 21 #define PALADINGM 22 @@ -58,33 +57,92 @@ #define DISCORD_MERCHANT 59 #define ADVENTURERECRUITER 60 #define ADVENTUREMERCHANT 61 -#define LDON_TREASURE 62 //objects you can use /open on first seen in LDONs -#define CORPSE_CLASS 62 //only seen on Danvi's Corpse in Akheva so far.. -#define TRIBUTE_MASTER 63 -#define GUILD_TRIBUTE_MASTER 64 //not sure +#define LDON_TREASURE 62 // objects you can use /open on first seen in LDONs +#define CORPSE_CLASS 62 // only seen on Danvi's Corpse in Akheva so far.. +#define TRIBUTE_MASTER 63 +#define GUILD_TRIBUTE_MASTER 64 // not sure #define NORRATHS_KEEPERS_MERCHANT 67 #define DARK_REIGN_MERCHANT 68 #define FELLOWSHIP_MASTER 69 #define ALT_CURRENCY_MERCHANT 70 #define MERCERNARY_MASTER 71 -#define warrior_1 1 -#define monk_1 64 -#define paladin_1 4 -#define shadow_1 16 -#define bard_1 128 -#define cleric_1 2 -#define necromancer_1 1024 -#define ranger_1 8 -#define druid_1 32 -#define mage_1 4096 -#define wizard_1 2048 -#define enchanter_1 8192 -#define rogue_1 256 -#define shaman_1 512 -#define beastlord_1 16384 -#define berserker_1 32768 -#define call_1 65536 -const char* GetEQClassName(uint8 class_, uint8 level = 0); + +// player class values +#define PLAYER_CLASS_UNKNOWN 0 +#define PLAYER_CLASS_WARRIOR 1 +#define PLAYER_CLASS_CLERIC 2 +#define PLAYER_CLASS_PALADIN 3 +#define PLAYER_CLASS_RANGER 4 +#define PLAYER_CLASS_SHADOWKNIGHT 5 +#define PLAYER_CLASS_DRUID 6 +#define PLAYER_CLASS_MONK 7 +#define PLAYER_CLASS_BARD 8 +#define PLAYER_CLASS_ROGUE 9 +#define PLAYER_CLASS_SHAMAN 10 +#define PLAYER_CLASS_NECROMANCER 11 +#define PLAYER_CLASS_WIZARD 12 +#define PLAYER_CLASS_MAGICIAN 13 +#define PLAYER_CLASS_ENCHANTER 14 +#define PLAYER_CLASS_BEASTLORD 15 +#define PLAYER_CLASS_BERSERKER 16 + +#define PLAYER_CLASS_COUNT 16 + + +// player class bits +#define PLAYER_CLASS_UNKNOWN_BIT 0 +#define PLAYER_CLASS_WARRIOR_BIT 1 +#define PLAYER_CLASS_CLERIC_BIT 2 +#define PLAYER_CLASS_PALADIN_BIT 4 +#define PLAYER_CLASS_RANGER_BIT 8 +#define PLAYER_CLASS_SHADOWKNIGHT_BIT 16 +#define PLAYER_CLASS_DRUID_BIT 32 +#define PLAYER_CLASS_MONK_BIT 64 +#define PLAYER_CLASS_BARD_BIT 128 +#define PLAYER_CLASS_ROGUE_BIT 256 +#define PLAYER_CLASS_SHAMAN_BIT 512 +#define PLAYER_CLASS_NECROMANCER_BIT 1024 +#define PLAYER_CLASS_WIZARD_BIT 2048 +#define PLAYER_CLASS_MAGICIAN_BIT 4096 +#define PLAYER_CLASS_ENCHANTER_BIT 8192 +#define PLAYER_CLASS_BEASTLORD_BIT 16384 +#define PLAYER_CLASS_BERSERKER_BIT 32768 + +#define PLAYER_CLASS_ALL_MASK 65535 // was 65536 + + +#define ARMOR_TYPE_UNKNOWN 0 +#define ARMOR_TYPE_CLOTH 1 +#define ARMOR_TYPE_LEATHER 2 +#define ARMOR_TYPE_CHAIN 3 +#define ARMOR_TYPE_PLATE 4 + +#define ARMOR_TYPE_FIRST ARMOR_TYPE_UNKNOWN +#define ARMOR_TYPE_LAST ARMOR_TYPE_PLATE +#define ARMOR_TYPE_COUNT 5 + + +const char* GetClassIDName(uint8 class_id, uint8 level = 0); +const char* GetPlayerClassName(uint32 player_class_value, uint8 level = 0); + +uint32 GetPlayerClassValue(uint8 class_id); +uint32 GetPlayerClassBit(uint8 class_id); + +uint8 GetClassIDFromPlayerClassValue(uint32 player_class_value); +uint8 GetClassIDFromPlayerClassBit(uint32 player_class_bit); + +bool IsFighterClass(uint8 class_id); +bool IsSpellFighterClass(uint8 class_id); +bool IsNonSpellFighterClass(uint8 class_id); +bool IsCasterClass(uint8 class_id); +bool IsINTCasterClass(uint8 class_id); +bool IsWISCasterClass(uint8 class_id); + +bool IsPlateClass(uint8 class_id); +bool IsChainClass(uint8 class_id); +bool IsLeatherClass(uint8 class_id); +bool IsClothClass(uint8 class_id); +uint8 ClassArmorType(uint8 class_id); + #endif - diff --git a/common/clientversions.h b/common/clientversions.h deleted file mode 100644 index 675429eab..000000000 --- a/common/clientversions.h +++ /dev/null @@ -1,153 +0,0 @@ -/* -EQEMu: Everquest Server Emulator - -Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY except by those people which sell it, which -are required to give you total support for your newly bought product; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef CLIENTVERSIONS_H -#define CLIENTVERSIONS_H - -#include "types.h" - -static const uint32 BIT_Client62 = 1; -static const uint32 BIT_Titanium = 2; -static const uint32 BIT_SoF = 4; -static const uint32 BIT_SoD = 8; -static const uint32 BIT_UF = 16; -static const uint32 BIT_RoF = 32; -static const uint32 BIT_RoF2 = 64; - -static const uint32 BIT_TitaniumAndEarlier = 0x00000003; -static const uint32 BIT_SoFAndLater = 0xFFFFFFFC; -static const uint32 BIT_SoDAndLater = 0xFFFFFFF8; -static const uint32 BIT_UFAndLater = 0xFFFFFFF0; -static const uint32 BIT_RoFAndLater = 0xFFFFFFE0; -static const uint32 BIT_RoF2AndLater = 0xFFFFFFC0; -static const uint32 BIT_AllClients = 0xFFFFFFFF; - -enum class ClientVersion -{ - Unknown = 0, - Client62, // Build: 'Aug 4 2005 15:40:59' - Titanium, // Build: 'Oct 31 2005 10:33:37' - SoF, // Build: 'Sep 7 2007 09:11:49' - SoD, // Build: 'Dec 19 2008 15:22:49' - UF, // Build: 'Jun 8 2010 16:44:32' - RoF, // Build: 'Dec 10 2012 17:35:44' - RoF2, // Build: 'May 10 2013 23:30:08' - - MobNPC, - MobMerc, - MobBot, - MobPet, -}; - -#define CLIENT_VERSION_COUNT 12 -#define LAST_PC_CLIENT ClientVersion::RoF2 -#define LAST_NPC_CLIENT ClientVersion::MobPet - - -static const char* ClientVersionName(ClientVersion version) -{ - switch (version) - { - case ClientVersion::Unknown: - return "Unknown"; - case ClientVersion::Client62: - return "Client62"; - case ClientVersion::Titanium: - return "Titanium"; - case ClientVersion::SoF: - return "SoF"; - case ClientVersion::SoD: - return "SoD"; - case ClientVersion::UF: - return "UF"; - case ClientVersion::RoF: - return "RoF"; - case ClientVersion::RoF2: - return "RoF2"; - case ClientVersion::MobNPC: - return "MobNPC"; - case ClientVersion::MobMerc: - return "MobMerc"; - case ClientVersion::MobBot: - return "MobBot"; - case ClientVersion::MobPet: - return "MobPet"; - default: - return " Invalid ClientVersion"; - }; -} - -static uint32 ClientBitFromVersion(ClientVersion clientVersion) -{ - switch (clientVersion) - { - case ClientVersion::Unknown: - case ClientVersion::Client62: - return 0; - case ClientVersion::Titanium: - case ClientVersion::SoF: - case ClientVersion::SoD: - case ClientVersion::UF: - case ClientVersion::RoF: - case ClientVersion::RoF2: - case ClientVersion::MobNPC: - case ClientVersion::MobMerc: - case ClientVersion::MobBot: - case ClientVersion::MobPet: - return ((uint32)1 << (static_cast(clientVersion) - 1)); - default: - return 0; - } -} - -static ClientVersion ClientVersionFromBit(uint32 clientVersionBit) -{ - switch (clientVersionBit) - { - case (uint32)static_cast(ClientVersion::Unknown): - case ((uint32)1 << (static_cast(ClientVersion::Client62) - 1)): - return ClientVersion::Unknown; - case ((uint32)1 << (static_cast(ClientVersion::Titanium) - 1)): - return ClientVersion::Titanium; - case ((uint32)1 << (static_cast(ClientVersion::SoF) - 1)): - return ClientVersion::SoF; - case ((uint32)1 << (static_cast(ClientVersion::SoD) - 1)): - return ClientVersion::SoD; - case ((uint32)1 << (static_cast(ClientVersion::UF) - 1)): - return ClientVersion::UF; - case ((uint32)1 << (static_cast(ClientVersion::RoF) - 1)): - return ClientVersion::RoF; - case ((uint32)1 << (static_cast(ClientVersion::RoF2) - 1)): - return ClientVersion::RoF2; - case ((uint32)1 << (static_cast(ClientVersion::MobNPC) - 1)): - return ClientVersion::MobNPC; - case ((uint32)1 << (static_cast(ClientVersion::MobMerc) - 1)): - return ClientVersion::MobMerc; - case ((uint32)1 << (static_cast(ClientVersion::MobBot) - 1)): - return ClientVersion::MobBot; - case ((uint32)1 << (static_cast(ClientVersion::MobPet) - 1)): - return ClientVersion::MobPet; - default: - return ClientVersion::Unknown; - } -} - -#endif /* CLIENTVERSIONS_H */ diff --git a/common/data_verification.h b/common/data_verification.h index 9da85a579..fe1152cb4 100644 --- a/common/data_verification.h +++ b/common/data_verification.h @@ -1,5 +1,6 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,36 +14,42 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef COMMON_DATA_VERIFICATION_H #define COMMON_DATA_VERIFICATION_H #include + namespace EQEmu { + template + T Clamp(const T& value, const T& lower, const T& upper) { + return std::max(lower, std::min(value, upper)); + } -template -T Clamp(const T& value, const T& lower, const T& upper) { - return std::max(lower, std::min(value, upper)); -} + template + T ClampLower(const T& value, const T& lower) { + return std::max(lower, value); + } -template -T ClampLower(const T& value, const T& lower) { - return std::max(lower, value); -} + template + T ClampUpper(const T& value, const T& upper) { + return std::min(value, upper); + } -template -T ClampUpper(const T& value, const T& upper) { - return std::min(value, upper); -} + template + bool ValueWithin(const T& value, const T& lower, const T& upper) { + return value >= lower && value <= upper; + } -template -bool ValueWithin(const T& value, const T& lower, const T& upper) { - return value >= lower && value <= upper; -} + template + bool ValueWithin(const T1& value, const T2& lower, const T3& upper) { + return value >= (T1)lower && value <= (T1)upper; + } -} +} /*EQEmu*/ -#endif +#endif /*COMMON_DATA_VERIFICATION_H*/ diff --git a/common/database.cpp b/common/database.cpp index 31566d82f..6ecbb75dd 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +49,6 @@ extern Client client; Database::Database () { - DBInitVars(); } /* @@ -57,7 +57,6 @@ Establish a connection to a mysql database with the supplied parameters Database::Database(const char* host, const char* user, const char* passwd, const char* database, uint32 port) { - DBInitVars(); Connect(host, user, passwd, database, port); } @@ -74,25 +73,12 @@ bool Database::Connect(const char* host, const char* user, const char* passwd, c } } -void Database::DBInitVars() { - varcache_array = 0; - varcache_max = 0; - varcache_lastupdate = 0; -} - /* Close the connection to the database */ Database::~Database() { - unsigned int x; - if (varcache_array) { - for (x=0; xbinds[0].zoneId, 0, pp->binds[0].x, pp->binds[0].y, pp->binds[0].z, pp->binds[0].heading, 0, - character_id, pp->binds[4].zoneId, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading, 1 - ); results = QueryDatabase(query); + character_id, pp->binds[1].zoneId, 0, pp->binds[1].x, pp->binds[1].y, pp->binds[1].z, pp->binds[1].heading, 1, + character_id, pp->binds[2].zoneId, 0, pp->binds[2].x, pp->binds[2].y, pp->binds[2].z, pp->binds[2].heading, 2, + character_id, pp->binds[3].zoneId, 0, pp->binds[3].x, pp->binds[3].y, pp->binds[3].z, pp->binds[3].heading, 3, + character_id, pp->binds[4].zoneId, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading, 4 + ); results = QueryDatabase(query); /* Save Skills */ int firstquery = 0; @@ -705,7 +700,7 @@ bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inven /* Insert starting inventory... */ std::string invquery; - for (int16 i=EmuConstants::EQUIPMENT_BEGIN; i<=EmuConstants::BANK_BAGS_END;) { + for (int16 i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= EQEmu::legacy::BANK_BAGS_END;) { const ItemInst* newinv = inv->GetItem(i); if (newinv) { invquery = StringFormat("INSERT INTO `inventory` (charid, slotid, itemid, charges, color) VALUES (%u, %i, %u, %i, %u)", @@ -714,16 +709,16 @@ bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inven auto results = QueryDatabase(invquery); } - if (i == MainCursor) { - i = EmuConstants::GENERAL_BAGS_BEGIN; + if (i == EQEmu::legacy::SlotCursor) { + i = EQEmu::legacy::GENERAL_BAGS_BEGIN; continue; } - else if (i == EmuConstants::CURSOR_BAG_END) { - i = EmuConstants::BANK_BEGIN; + else if (i == EQEmu::legacy::CURSOR_BAG_END) { + i = EQEmu::legacy::BANK_BEGIN; continue; } - else if (i == EmuConstants::BANK_END) { - i = EmuConstants::BANK_BAGS_BEGIN; + else if (i == EQEmu::legacy::BANK_END) { + i = EQEmu::legacy::BANK_BAGS_BEGIN; continue; } i++; @@ -836,7 +831,7 @@ void Database::GetAccountName(uint32 accountid, char* name, uint32* oLSAccountID } -void Database::GetCharName(uint32 char_id, char* name) { +void Database::GetCharName(uint32 char_id, char* name) { std::string query = StringFormat("SELECT `name` FROM `character_data` WHERE id='%i'", char_id); auto results = QueryDatabase(query); @@ -851,145 +846,69 @@ void Database::GetCharName(uint32 char_id, char* name) { } bool Database::LoadVariables() { - char *query = nullptr; - - auto results = QueryDatabase(query, LoadVariables_MQ(&query)); + auto results = QueryDatabase(StringFormat("SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache.last_update)); if (!results.Success()) - { - safe_delete_array(query); return false; - } - - safe_delete_array(query); - return LoadVariables_result(std::move(results)); -} - -uint32 Database::LoadVariables_MQ(char** query) -{ - return MakeAnyLenString(query, "SELECT varname, value, unix_timestamp() FROM variables where unix_timestamp(ts) >= %d", varcache_lastupdate); -} - -// always returns true? not sure about this. -bool Database::LoadVariables_result(MySQLRequestResult results) -{ - uint32 i = 0; - LockMutex lock(&Mvarcache); if (results.RowCount() == 0) return true; - if (!varcache_array) { - varcache_max = results.RowCount(); - varcache_array = new VarCache_Struct*[varcache_max]; - for (i=0; ivarname, row[0]) == 0) { - delete varcache_array[i]; - varcache_array[i] = (VarCache_Struct*) new uint8[sizeof(VarCache_Struct) + strlen(row[1]) + 1]; - strn0cpy(varcache_array[i]->varname, row[0], sizeof(varcache_array[i]->varname)); - strcpy(varcache_array[i]->value, row[1]); - break; - } - } - else { - varcache_array[i] = (VarCache_Struct*) new uint8[sizeof(VarCache_Struct) + strlen(row[1]) + 1]; - strcpy(varcache_array[i]->varname, row[0]); - strcpy(varcache_array[i]->value, row[1]); - break; - } - } + std::string key, value; + for (auto row = results.begin(); row != results.end(); ++row) { + varcache.last_update = atoi(row[2]); // ahh should we be comparing if this is newer? + key = row[0]; + value = row[1]; + std::transform(std::begin(key), std::end(key), std::begin(key), ::tolower); // keys are lower case, DB doesn't have to be + varcache.Add(key, value); } - uint32 max_used = 0; - for (i=0; i max_used) - max_used = i; - } - } - - varcache_max = max_used + 1; - return true; } // Gets variable from 'variables' table -bool Database::GetVariable(const char* varname, char* varvalue, uint16 varvalue_len) { - varvalue[0] = '\0'; +bool Database::GetVariable(std::string varname, std::string &varvalue) +{ + varvalue.clear(); LockMutex lock(&Mvarcache); - if (strlen(varname) <= 1) - return false; - for (uint32 i=0; ivarname, varname) == 0) { - snprintf(varvalue, varvalue_len, "%s", varcache_array[i]->value); - varvalue[varvalue_len-1] = 0; - return true; - } - } - else - return false; + if (varname.empty()) + return false; + + std::transform(std::begin(varname), std::end(varname), std::begin(varname), ::tolower); // all keys are lower case + auto tmp = varcache.Get(varname); + if (tmp) { + varvalue = *tmp; + return true; } return false; } -bool Database::SetVariable(const char* varname_in, const char* varvalue_in) { - - char *varname,*varvalue; - - varname=(char *)malloc(strlen(varname_in)*2+1); - varvalue=(char *)malloc(strlen(varvalue_in)*2+1); - DoEscapeString(varname, varname_in, strlen(varname_in)); - DoEscapeString(varvalue, varvalue_in, strlen(varvalue_in)); - - std::string query = StringFormat("Update variables set value='%s' WHERE varname like '%s'", varvalue, varname); +bool Database::SetVariable(const std::string varname, const std::string &varvalue) +{ + std::string escaped_name = EscapeString(varname); + std::string escaped_value = EscapeString(varvalue); + std::string query = StringFormat("Update variables set value='%s' WHERE varname like '%s'", escaped_value.c_str(), escaped_name.c_str()); auto results = QueryDatabase(query); if (!results.Success()) - { - free(varname); - free(varvalue); return false; - } if (results.RowsAffected() == 1) { LoadVariables(); // refresh cache - free(varname); - free(varvalue); return true; } - query = StringFormat("Insert Into variables (varname, value) values ('%s', '%s')", varname, varvalue); + query = StringFormat("Insert Into variables (varname, value) values ('%s', '%s')", escaped_name.c_str(), escaped_value.c_str()); results = QueryDatabase(query); - free(varname); - free(varvalue); if (results.RowsAffected() != 1) return false; - + LoadVariables(); // refresh cache return true; } @@ -1183,21 +1102,16 @@ bool Database::CheckNameFilter(const char* name, bool surname) { std::string str_name = name; - if(surname) + // the minimum 4 is enforced by the client too + if (!name || strlen(name) < 4) { - // the minimum 4 is enforced by the client too - if(!name || strlen(name) < 3) - { - return false; - } + return false; } - else + + // Given name length is enforced by the client too + if (!surname && strlen(name) > 15) { - // the minimum 4 is enforced by the client too - if(!name || strlen(name) < 4 || strlen(name) > 15) - { - return false; - } + return false; } for (size_t i = 0; i < str_name.size(); i++) @@ -1384,7 +1298,7 @@ bool Database::MoveCharacterToZone(const char* charname, const char* zonename) { } bool Database::MoveCharacterToZone(uint32 iCharID, const char* iZonename) { - std::string query = StringFormat("UPDATE `character_data` SET `zone_id` = %i, `x` = -1, `y` = -1, `z` = -1 WHERE `id` = %i", iZonename, GetZoneID(iZonename), iCharID); + std::string query = StringFormat("UPDATE `character_data` SET `zone_id` = %i, `x` = -1, `y` = -1, `z` = -1 WHERE `id` = %i", GetZoneID(iZonename), iCharID); auto results = QueryDatabase(query); if (!results.Success()) { @@ -1560,11 +1474,12 @@ void Database::SetFirstLogon(uint32 CharID, uint8 firstlogon) { QueryDatabase(query); } -void Database::AddReport(std::string who, std::string against, std::string lines) { - char *escape_str = new char[lines.size()*2+1]; +void Database::AddReport(std::string who, std::string against, std::string lines) +{ + auto escape_str = new char[lines.size() * 2 + 1]; DoEscapeString(escape_str, lines.c_str(), lines.size()); - std::string query = StringFormat("INSERT INTO reports (name, reported, reported_text) VALUES('%s', '%s', '%s')", who.c_str(), against.c_str(), escape_str); + std::string query = StringFormat("INSERT INTO reports (name, reported, reported_text) VALUES('%s', '%s', '%s')", EscapeString(who).c_str(), EscapeString(against).c_str(), escape_str); QueryDatabase(query); safe_delete_array(escape_str); } @@ -2173,3 +2088,51 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) } } } + +void Database::ClearInvSnapshots(bool use_rule) +{ + uint32 del_time = time(nullptr); + if (use_rule) { del_time -= RuleI(Character, InvSnapshotHistoryD) * 86400; } + + std::string query = StringFormat("DELETE FROM inventory_snapshots WHERE time_index <= %lu", (unsigned long)del_time); + QueryDatabase(query); +} + +struct TimeOfDay_Struct Database::LoadTime(time_t &realtime) +{ + + TimeOfDay_Struct eqTime; + std::string query = StringFormat("SELECT minute,hour,day,month,year,realtime FROM eqtime limit 1"); + auto results = QueryDatabase(query); + + if (!results.Success() || results.RowCount() == 0){ + Log.Out(Logs::Detail, Logs::World_Server, "Loading EQ time of day failed. Using defaults."); + eqTime.minute = 0; + eqTime.hour = 9; + eqTime.day = 1; + eqTime.month = 1; + eqTime.year = 3100; + realtime = time(0); + } + else{ + auto row = results.begin(); + + eqTime.minute = atoi(row[0]); + eqTime.hour = atoi(row[1]); + eqTime.day = atoi(row[2]); + eqTime.month = atoi(row[3]); + eqTime.year = atoi(row[4]); + realtime = atoi(row[5]); + } + + return eqTime; +} + +bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year) +{ + std::string query = StringFormat("UPDATE eqtime set minute = %d, hour = %d, day = %d, month = %d, year = %d, realtime = %d limit 1", minute, hour, day, month, year, time(0)); + auto results = QueryDatabase(query); + + return results.Success(); + +} diff --git a/common/database.h b/common/database.h index f3b8ba8c1..ed08484b1 100644 --- a/common/database.h +++ b/common/database.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include "global_define.h" #include "eqemu_logsys.h" + #include "types.h" #include "dbcore.h" #include "linked_list.h" @@ -66,8 +67,14 @@ struct npcDecayTimes_Struct { struct VarCache_Struct { - char varname[26]; - char value[0]; + std::map m_cache; + uint32 last_update; + VarCache_Struct() : last_update(0) { } + void Add(const std::string &key, const std::string &value) { m_cache[key] = value; } + const std::string *Get(const std::string &key) { + auto it = m_cache.find(key); + return (it != m_cache.end() ? &it->second : nullptr); + } }; class PTimerList; @@ -87,7 +94,7 @@ class Database : public DBcore { public: Database(); Database(const char* host, const char* user, const char* passwd, const char* database,uint32 port); - bool Connect(const char* host, const char* user, const char* passwd, const char* database,uint32 port); + bool Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port); ~Database(); /* Character Creation */ @@ -209,17 +216,14 @@ public: /* Database Conversions 'database_conversions.cpp' */ bool CheckDatabaseConversions(); - bool CheckDatabaseConvertBotsPostPPDeblob(); bool CheckDatabaseConvertCorpseDeblob(); bool CheckDatabaseConvertPPDeblob(); /* Database Variables */ - bool GetVariable(const char* varname, char* varvalue, uint16 varvalue_len); - bool SetVariable(const char* varname, const char* varvalue); + bool GetVariable(std::string varname, std::string &varvalue); + bool SetVariable(const std::string varname, const std::string &varvalue); bool LoadVariables(); - uint32 LoadVariables_MQ(char** query); - bool LoadVariables_result(MySQLRequestResult results); /* General Queries */ @@ -241,6 +245,8 @@ public: uint8 GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level); void AddReport(std::string who, std::string against, std::string lines); + struct TimeOfDay_Struct LoadTime(time_t &realtime); + bool SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year); void ClearMerchantTemp(); void ClearPTimers(uint32 charid); void SetFirstLogon(uint32 CharID, uint8 firstlogon); @@ -248,18 +254,16 @@ public: void SetLFP(uint32 CharID, bool LFP); void SetLoginFlags(uint32 CharID, bool LFP, bool LFG, uint8 firstlogon); + void ClearInvSnapshots(bool use_rule = true); + /* EQEmuLogSys */ void LoadLogSettings(EQEmuLogSys::LogSettings* log_settings); private: - void DBInitVars(); - std::map zonename_array; - Mutex Mvarcache; - uint32 varcache_max; - VarCache_Struct** varcache_array; - uint32 varcache_lastupdate; + Mutex Mvarcache; + VarCache_Struct varcache; /* Groups, utility methods. */ void ClearAllGroupLeaders(); diff --git a/common/database_conversions.cpp b/common/database_conversions.cpp index f6c43687f..f6fd6c04a 100644 --- a/common/database_conversions.cpp +++ b/common/database_conversions.cpp @@ -186,7 +186,7 @@ namespace Convert { /*002*/ uint32 HP; /*006*/ uint32 Mana; /*010*/ Convert::SpellBuff_Struct Buffs[BUFF_COUNT]; - /*510*/ uint32 Items[_MaterialCount]; + /*510*/ uint32 Items[EQEmu::textures::TextureCount]; /*546*/ char Name[64]; /*610*/ }; @@ -227,9 +227,9 @@ namespace Convert { /*0304*/ uint8 ability_time_minutes; /*0305*/ uint8 ability_time_hours; //place holder /*0306*/ uint8 unknown0306[6]; // @bp Spacer/Flag? - /*0312*/ uint32 item_material[_MaterialCount]; // Item texture/material of worn/held items + /*0312*/ uint32 item_material[EQEmu::textures::TextureCount]; // Item texture/material of worn/held items /*0348*/ uint8 unknown0348[44]; - /*0392*/ Convert::Color_Struct item_tint[_MaterialCount]; + /*0392*/ Convert::Color_Struct item_tint[EQEmu::textures::TextureCount]; /*0428*/ Convert::AA_Array aa_array[MAX_PP_AA_ARRAY]; /*2348*/ float unknown2384; //seen ~128, ~47 /*2352*/ char servername[32]; // length probably not right @@ -330,7 +330,7 @@ namespace Convert { /*7212*/ uint32 tribute_points; /*7216*/ uint32 unknown7252; /*7220*/ uint32 tribute_active; //1=active - /*7224*/ Convert::Tribute_Struct tributes[EmuConstants::TRIBUTE_SIZE]; + /*7224*/ Convert::Tribute_Struct tributes[EQEmu::legacy::TRIBUTE_SIZE]; /*7264*/ Convert::Disciplines_Struct disciplines; /*7664*/ uint32 recastTimers[MAX_RECAST_TYPES]; // Timers (GMT of last use) /*7744*/ char unknown7780[160]; @@ -470,7 +470,6 @@ static inline void loadbar(unsigned int x, unsigned int n, unsigned int w = 50) bool Database::CheckDatabaseConversions() { CheckDatabaseConvertPPDeblob(); - CheckDatabaseConvertBotsPostPPDeblob(); CheckDatabaseConvertCorpseDeblob(); /* Fetch Automatic Upgrade Script */ @@ -494,7 +493,7 @@ bool Database::CheckDatabaseConversions() { /* Check for a new version of this script, the arg passed would have to be higher than the copy they have downloaded locally and they will re fetch */ - system("perl eqemu_update.pl V 2"); + system("perl eqemu_update.pl V 14"); /* Run Automatic Database Upgrade Script */ system("perl eqemu_update.pl ran_from_world"); @@ -1417,7 +1416,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){ if (rquery != ""){ results = QueryDatabase(rquery); } /* Run Material Color Convert */ first_entry = 0; rquery = ""; - for (i = 0; i < _MaterialCount; i++){ + for (i = 0; i < EQEmu::textures::TextureCount; i++){ if (pp->item_tint[i].color > 0){ if (first_entry != 1){ rquery = StringFormat("REPLACE INTO `character_material` (id, slot, blue, green, red, use_tint, color) VALUES (%u, %u, %u, %u, %u, %u, %u)", character_id, i, pp->item_tint[i].rgb.blue, pp->item_tint[i].rgb.green, pp->item_tint[i].rgb.red, pp->item_tint[i].rgb.use_tint, pp->item_tint[i].color); @@ -1429,7 +1428,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){ if (rquery != ""){ results = QueryDatabase(rquery); } /* Run Tribute Convert */ first_entry = 0; rquery = ""; - for (i = 0; i < EmuConstants::TRIBUTE_SIZE; i++){ + for (i = 0; i < EQEmu::legacy::TRIBUTE_SIZE; i++){ if (pp->tributes[i].tribute > 0 && pp->tributes[i].tribute != 4294967295){ if (first_entry != 1){ rquery = StringFormat("REPLACE INTO `character_tribute` (id, tier, tribute) VALUES (%u, %u, %u)", character_id, pp->tributes[i].tier, pp->tributes[i].tribute); @@ -1491,163 +1490,6 @@ bool Database::CheckDatabaseConvertPPDeblob(){ return true; } -bool Database::CheckDatabaseConvertBotsPostPPDeblob(){ -#ifdef BOTS - int runbotsconvert = 0; - - /* Check For Legacy Bot References */ - std::string rquery = StringFormat("SHOW CREATE VIEW `vwBotCharacterMobs`"); - auto results = QueryDatabase(rquery); - if (results.RowCount() == 1){ - auto row = results.begin(); - std::string table_check = row[1]; - - if (table_check.find("character_data") == -1){ - runbotsconvert = 1; - printf("\n\n::: Legacy Bot Views and Function Detected... \n"); - printf("----------------------------------------------------------\n\n"); - printf(" Database currently has bot view/function linkage to obselete \n"); - printf(" table references and will now be converted...\n\n"); - printf(" It is recommended that you backup your database \n"); - printf(" before continuing the automatic conversion process...\n\n"); - printf("----------------------------------------------------------\n\n"); - std::cout << "Press ENTER to continue....." << std::endl << std::endl; - std::cin.ignore(1); - } - } - - if (runbotsconvert == 1){ - printf("Running bot views/function database conversion... \n"); - - /* Update view `vwbotcharactermobs` */ - rquery = StringFormat("DROP VIEW `vwBotCharacterMobs`;"); - results = QueryDatabase(rquery); - - rquery = StringFormat( - "CREATE VIEW `vwBotCharacterMobs` AS\n" - "SELECT _utf8'C' AS mobtype,\n" // Natedog: '_utf8' - "c.`id`,\n" - "c.`name`,\n" - "c.`class`,\n" - "c.`level`,\n" - "c.`last_login`,\n" - "c.`zone_id`\n" - "FROM `character_data` AS c\n" - "UNION ALL\n" - "SELECT _utf8'B' AS mobtype,\n" // Natedog: '_utf8' - "b.`BotID` AS id,\n" - "b.`Name` AS name,\n" - "b.`Class` AS class,\n" - "b.`BotLevel` AS level,\n" - "0 AS timelaston,\n" - "0 AS zoneid\n" - "FROM bots AS b;" - ); - results = QueryDatabase(rquery); - - - /* Update function `GetMobType` */ - rquery = StringFormat("DROP FUNCTION IF EXISTS `GetMobType`;"); - results = QueryDatabase(rquery); - - rquery = StringFormat( - "CREATE FUNCTION `GetMobType` (mobname VARCHAR(64)) RETURNS CHAR(1)\n" - "BEGIN\n" - " DECLARE Result CHAR(1);\n" - "\n" - " SET Result = NULL;\n" - "\n" - " IF (SELECT COUNT(*) FROM `character_data` WHERE `name` = mobname) > 0 THEN\n" - " SET Result = 'C';\n" - " ELSEIF (SELECT COUNT(*) FROM `bots` WHERE `Name` = mobname) > 0 THEN\n" - " SET Result = 'B';\n" - " END IF;\n " - "\n" - " RETURN Result;\n" - "END" - ); - results = QueryDatabase(rquery); - - - /* Update view `vwgroups` */ - rquery = StringFormat("DROP VIEW IF EXISTS `vwGroups`;"); - results = QueryDatabase(rquery); - - rquery = StringFormat( - "CREATE VIEW `vwGroups` AS\n" - "SELECT g.`groupid` AS groupid,\n" - "GetMobType(g.`name`) AS mobtype,\n" - "g.`name` AS name,\n" - "g.`charid` AS mobid,\n" - "IFNULL(c.`level`, b.`BotLevel`) AS level\n" - "FROM `group_id` AS g\n" - "LEFT JOIN `character_data` AS c ON g.`name` = c.`name`\n" - "LEFT JOIN `bots` AS b ON g.`name` = b.`Name`;" - ); - results = QueryDatabase(rquery); - - - /* Update view `vwbotgroups` */ - rquery = StringFormat("DROP VIEW IF EXISTS `vwBotGroups`;"); - results = QueryDatabase(rquery); - - rquery = StringFormat( - "CREATE VIEW `vwBotGroups` AS\n" - "SELECT g.`BotGroupId`,\n" - "g.`BotGroupName`,\n" - "g.`BotGroupLeaderBotId`,\n" - "b.`Name` AS BotGroupLeaderName,\n" - "b.`BotOwnerCharacterId`,\n" - "c.`name` AS BotOwnerCharacterName\n" - "FROM `botgroup` AS g\n" - "JOIN `bots` AS b ON g.`BotGroupLeaderBotId` = b.`BotID`\n" - "JOIN `character_data` AS c ON b.`BotOwnerCharacterID` = c.`id`\n" - "ORDER BY b.`BotOwnerCharacterId`, g.`BotGroupName`;" - ); - results = QueryDatabase(rquery); - - - /* Update view `vwguildmembers` */ - rquery = StringFormat("DROP VIEW IF EXISTS `vwGuildMembers`;"); - results = QueryDatabase(rquery); - - rquery = StringFormat( - "CREATE VIEW `vwGuildMembers` AS\n" - "SELECT 'C' AS mobtype,\n" - "cm.`char_id`,\n" - "cm.`guild_id`,\n" - "cm.`rank`,\n" - "cm.`tribute_enable`,\n" - "cm.`total_tribute`,\n" - "cm.`last_tribute`,\n" - "cm.`banker`,\n" - "cm.`public_note`,\n" - "cm.`alt`\n" - "FROM `guild_members` AS cm\n" - "UNION ALL\n" - "SELECT 'B' AS mobtype,\n" - "bm.`char_id`,\n" - "bm.`guild_id`,\n" - "bm.`rank`,\n" - "bm.`tribute_enable`,\n" - "bm.`total_tribute`,\n" - "bm.`last_tribute`,\n" - "bm.`banker`,\n" - "bm.`public_note`,\n" - "bm.`alt`\n" - "FROM `botguildmembers` AS bm;" - ); - results = QueryDatabase(rquery); - } - - if (runbotsconvert == 1){ - printf("\n\nBot views/function conversion complete, continuing world bootup...\n"); - } - -#endif - return true; -} - bool Database::CheckDatabaseConvertCorpseDeblob(){ Convert::DBPlayerCorpse_Struct_temp* dbpc; Convert::classic_db_temp::DBPlayerCorpse_Struct_temp* dbpc_c; diff --git a/common/dbcore.cpp b/common/dbcore.cpp index d256f7b42..0fcaa7678 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -98,14 +98,14 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo pStatus = Error; - char *errorBuffer = new char[MYSQL_ERRMSG_SIZE]; + auto errorBuffer = new char[MYSQL_ERRMSG_SIZE]; snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql)); return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32)mysql_errno(&mysql), errorBuffer); } - char *errorBuffer = new char[MYSQL_ERRMSG_SIZE]; + auto errorBuffer = new char[MYSQL_ERRMSG_SIZE]; snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql)); /* Implement Logging at the Root */ @@ -128,7 +128,12 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo MySQLRequestResult requestResult(res, (uint32)mysql_affected_rows(&mysql), rowCount, (uint32)mysql_field_count(&mysql), (uint32)mysql_insert_id(&mysql)); if (Log.log_settings[Logs::MySQLQuery].is_category_enabled == 1) - Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u rows returned)", query, rowCount, requestResult.RowCount()); + { + if ((strncasecmp(query, "select", 6) == 0)) + Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u row%s returned)", query, requestResult.RowCount(), requestResult.RowCount() == 1 ? "" : "s"); + else + Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u row%s affected)", query, requestResult.RowsAffected(), requestResult.RowsAffected() == 1 ? "" : "s"); + } return requestResult; } diff --git a/common/dbcore.h b/common/dbcore.h index b23d58a9e..6fd09218e 100644 --- a/common/dbcore.h +++ b/common/dbcore.h @@ -2,7 +2,7 @@ #define DBCORE_H #ifdef _WINDOWS - #include + #include #include #endif diff --git a/common/deity.cpp b/common/deity.cpp new file mode 100644 index 000000000..b8a2d87d7 --- /dev/null +++ b/common/deity.cpp @@ -0,0 +1,149 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "deity.h" + + +EQEmu::deity::DeityTypeBit EQEmu::deity::ConvertDeityTypeToDeityTypeBit(DeityType deity_type) +{ + switch (deity_type) { + case DeityBertoxxulous: + return bit_DeityBertoxxulous; + case DeityBrellSirilis: + return bit_DeityBrellSirilis; + case DeityCazicThule: + return bit_DeityCazicThule; + case DeityErollisiMarr: + return bit_DeityErollisiMarr; + case DeityBristlebane: + return bit_DeityBristlebane; + case DeityInnoruuk: + return bit_DeityInnoruuk; + case DeityKarana: + return bit_DeityKarana; + case DeityMithanielMarr: + return bit_DeityMithanielMarr; + case DeityPrexus: + return bit_DeityPrexus; + case DeityQuellious: + return bit_DeityQuellious; + case DeityRallosZek: + return bit_DeityRallosZek; + case DeityRodcetNife: + return bit_DeityRodcetNife; + case DeitySolusekRo: + return bit_DeitySolusekRo; + case DeityTheTribunal: + return bit_DeityTheTribunal; + case DeityTunare: + return bit_DeityTunare; + case DeityVeeshan: + return bit_DeityVeeshan; + case DeityAgnostic_LB: + case DeityAgnostic: + return bit_DeityAgnostic; + default: + return bit_DeityAll; + }; +} + +EQEmu::deity::DeityType EQEmu::deity::ConvertDeityTypeBitToDeityType(DeityTypeBit deity_type_bit) +{ + switch (deity_type_bit) { + case bit_DeityAgnostic: + return DeityAgnostic; + case bit_DeityBertoxxulous: + return DeityBertoxxulous; + case bit_DeityBrellSirilis: + return DeityBrellSirilis; + case bit_DeityCazicThule: + return DeityCazicThule; + case bit_DeityErollisiMarr: + return DeityErollisiMarr; + case bit_DeityBristlebane: + return DeityBristlebane; + case bit_DeityInnoruuk: + return DeityInnoruuk; + case bit_DeityKarana: + return DeityKarana; + case bit_DeityMithanielMarr: + return DeityMithanielMarr; + case bit_DeityPrexus: + return DeityPrexus; + case bit_DeityQuellious: + return DeityQuellious; + case bit_DeityRallosZek: + return DeityRallosZek; + case bit_DeityRodcetNife: + return DeityRodcetNife; + case bit_DeitySolusekRo: + return DeitySolusekRo; + case bit_DeityTheTribunal: + return DeityTheTribunal; + case bit_DeityTunare: + return DeityTunare; + case bit_DeityVeeshan: + return DeityVeeshan; + default: + return DeityUnknown; + }; +} + +const char* EQEmu::deity::DeityName(DeityType deity_type) +{ + switch (deity_type) { + case DeityBertoxxulous: + return "Bertoxxulous"; + case DeityBrellSirilis: + return "Brell Serilis"; + case DeityCazicThule: + return "Cazic-Thule"; + case DeityErollisiMarr: + return "Erollisi Marr"; + case DeityBristlebane: + return "Bristlebane"; + case DeityInnoruuk: + return "Innoruuk"; + case DeityKarana: + return "Karana"; + case DeityMithanielMarr: + return "Mithaniel Marr"; + case DeityPrexus: + return "Prexus"; + case DeityQuellious: + return "Quellious"; + case DeityRallosZek: + return "Rallos Zek"; + case DeityRodcetNife: + return "Rodcet Nife"; + case DeitySolusekRo: + return "Solusek Ro"; + case DeityTheTribunal: + return "The Tribunal"; + case DeityTunare: + return "Tunare"; + case DeityVeeshan: + return "Veeshan"; + case DeityAgnostic_LB: + case DeityAgnostic: + return "Agnostic"; + default: + return "Unknown"; + }; +} diff --git a/common/deity.h b/common/deity.h index 486d17263..fa56a9d8f 100644 --- a/common/deity.h +++ b/common/deity.h @@ -1,5 +1,6 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,154 +14,67 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef DEITY_H -#define DEITY_H + +#ifndef COMMON_DEITY_H +#define COMMON_DEITY_H #include "types.h" -#include -// NOTE: This code is not fully implemented since there are no references in the existing code -/* -** Diety types -** -** (ref: eqstr_us.txt) -** -** (Another orphaned enumeration...) -*/ -enum DeityTypes +namespace EQEmu { -/*----*/ DeityUnknown = 0, -/*----*/ DeityAgnostic_LB = 140, -/*3251*/ DeityBertoxxulous = 201, -/*3262*/ DeityBrellSirilis, -/*3253*/ DeityCazicThule, -/*3256*/ DeityErollisiMarr, -/*3252*/ DeityBristlebane, -/*3254*/ DeityInnoruuk, -/*3255*/ DeityKarana, -/*3257*/ DeityMithanielMarr, -/*3259*/ DeityPrexus, -/*3260*/ DeityQuellious, -/*3266*/ DeityRallosZek, -/*3258*/ DeityRodcetNife, -/*3261*/ DeitySolusekRo, -/*3263*/ DeityTheTribunal, -/*3264*/ DeityTunare, -/*3265*/ DeityVeeshan, -/*3250*/ DeityAgnostic = 396 -}; + namespace deity { + enum DeityType { + DeityUnknown = 0, + DeityAgnostic_LB = 140, + DeityBertoxxulous = 201, + DeityBrellSirilis, + DeityCazicThule, + DeityErollisiMarr, + DeityBristlebane, + DeityInnoruuk, + DeityKarana, + DeityMithanielMarr, + DeityPrexus, + DeityQuellious, + DeityRallosZek, + DeityRodcetNife, + DeitySolusekRo, + DeityTheTribunal, + DeityTunare, + DeityVeeshan, + DeityAgnostic = 396 + }; -/* -** Deity type bits -** -** (New orphan, but make use of it!) -*/ -enum DeityTypeBits : uint32 -{ - BIT_DeityAll = 0x00000000, - BIT_DeityAgnostic = 0x00000001, - BIT_DeityBertoxxulous = 0x00000002, - BIT_DeityBrellSirilis = 0x00000004, - BIT_DeityCazicThule = 0x00000008, - BIT_DeityErollisiMarr = 0x00000010, - BIT_DeityBristlebane = 0x00000020, - BIT_DeityInnoruuk = 0x00000040, - BIT_DeityKarana = 0x00000080, - BIT_DeityMithanielMarr = 0x00000100, - BIT_DeityPrexus = 0x00000200, - BIT_DeityQuellious = 0x00000400, - BIT_DeityRallosZek = 0x00000800, - BIT_DeityRodcetNife = 0x00001000, - BIT_DeitySolusekRo = 0x00002000, - BIT_DeityTheTribunal = 0x00004000, - BIT_DeityTunare = 0x00008000, - BIT_DeityVeeshan = 0x00010000 -}; + enum DeityTypeBit : uint32 { + bit_DeityAll = 0x00000000, + bit_DeityAgnostic = 0x00000001, + bit_DeityBertoxxulous = 0x00000002, + bit_DeityBrellSirilis = 0x00000004, + bit_DeityCazicThule = 0x00000008, + bit_DeityErollisiMarr = 0x00000010, + bit_DeityBristlebane = 0x00000020, + bit_DeityInnoruuk = 0x00000040, + bit_DeityKarana = 0x00000080, + bit_DeityMithanielMarr = 0x00000100, + bit_DeityPrexus = 0x00000200, + bit_DeityQuellious = 0x00000400, + bit_DeityRallosZek = 0x00000800, + bit_DeityRodcetNife = 0x00001000, + bit_DeitySolusekRo = 0x00002000, + bit_DeityTheTribunal = 0x00004000, + bit_DeityTunare = 0x00008000, + bit_DeityVeeshan = 0x00010000 + }; -static DeityTypeBits ConvertDeityToBitDeity(DeityTypes deity) -{ - switch(deity) - { - case DeityBertoxxulous: { return BIT_DeityBertoxxulous; } - case DeityBrellSirilis: { return BIT_DeityBrellSirilis; } - case DeityCazicThule: { return BIT_DeityCazicThule; } - case DeityErollisiMarr: { return BIT_DeityErollisiMarr; } - case DeityBristlebane: { return BIT_DeityBristlebane; } - case DeityInnoruuk: { return BIT_DeityInnoruuk; } - case DeityKarana: { return BIT_DeityKarana; } - case DeityMithanielMarr: { return BIT_DeityMithanielMarr; } - case DeityPrexus: { return BIT_DeityPrexus; } - case DeityQuellious: { return BIT_DeityQuellious; } - case DeityRallosZek: { return BIT_DeityRallosZek; } - case DeityRodcetNife: { return BIT_DeityRodcetNife; } - case DeitySolusekRo: { return BIT_DeitySolusekRo; } - case DeityTheTribunal: { return BIT_DeityTheTribunal; } - case DeityTunare: { return BIT_DeityTunare; } - case DeityVeeshan: { return BIT_DeityVeeshan; } - case DeityAgnostic_LB: - case DeityAgnostic: { return BIT_DeityAgnostic; } - default: { break; } - }; + extern DeityTypeBit ConvertDeityTypeToDeityTypeBit(DeityType deity_type); + extern DeityType ConvertDeityTypeBitToDeityType(DeityTypeBit deity_type_bit); + extern const char* DeityName(DeityType deity_type); - return BIT_DeityAll; -}; + } /*deity*/ -static DeityTypes ConvertBitDeityToDeity(DeityTypeBits deity_bit) -{ - switch(deity_bit) - { - case BIT_DeityAgnostic: { return DeityAgnostic; } - case BIT_DeityBertoxxulous: { return DeityBertoxxulous; } - case BIT_DeityBrellSirilis: { return DeityBrellSirilis; } - case BIT_DeityCazicThule: { return DeityCazicThule; } - case BIT_DeityErollisiMarr: { return DeityErollisiMarr; } - case BIT_DeityBristlebane: { return DeityBristlebane; } - case BIT_DeityInnoruuk: { return DeityInnoruuk; } - case BIT_DeityKarana: { return DeityKarana; } - case BIT_DeityMithanielMarr: { return DeityMithanielMarr; } - case BIT_DeityPrexus: { return DeityPrexus; } - case BIT_DeityQuellious: { return DeityQuellious; } - case BIT_DeityRallosZek: { return DeityRallosZek; } - case BIT_DeityRodcetNife: { return DeityRodcetNife; } - case BIT_DeitySolusekRo: { return DeitySolusekRo; } - case BIT_DeityTheTribunal: { return DeityTheTribunal; } - case BIT_DeityTunare: { return DeityTunare; } - case BIT_DeityVeeshan: { return DeityVeeshan; } - default: { break; } - }; +} /*EQEmu*/ - return DeityUnknown; -}; - -static std::string GetDeityName(DeityTypes deity) -{ - switch(deity) - { - case DeityBertoxxulous: { return "Bertoxxulous"; } - case DeityBrellSirilis: { return "Brell Serilis"; } - case DeityCazicThule: { return "Cazic-Thule"; } - case DeityErollisiMarr: { return "Erollisi Marr"; } - case DeityBristlebane: { return "Bristlebane"; } - case DeityInnoruuk: { return "Innoruuk"; } - case DeityKarana: { return "Karana"; } - case DeityMithanielMarr: { return "Mithaniel Marr"; } - case DeityPrexus: { return "Prexus"; } - case DeityQuellious: { return "Quellious"; } - case DeityRallosZek: { return "Rallos Zek"; } - case DeityRodcetNife: { return "Rodcet Nife"; } - case DeitySolusekRo: { return "Solusek Ro"; } - case DeityTheTribunal: { return "The Tribunal"; } - case DeityTunare: { return "Tunare"; } - case DeityVeeshan: { return "Veeshan"; } - case DeityAgnostic_LB: - case DeityAgnostic: { return "Agnostic"; } - default: { break; } - }; - - return "Unknown"; -}; - -#endif +#endif /* COMMON_DEITY_H */ diff --git a/common/emu_constants.cpp b/common/emu_constants.cpp new file mode 100644 index 000000000..a8fa73d1c --- /dev/null +++ b/common/emu_constants.cpp @@ -0,0 +1,20 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "emu_constants.h" diff --git a/common/emu_constants.h b/common/emu_constants.h new file mode 100644 index 000000000..bf8189acc --- /dev/null +++ b/common/emu_constants.h @@ -0,0 +1,70 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_EMU_CONSTANTS_H +#define COMMON_EMU_CONSTANTS_H + +#include "eq_limits.h" +#include "emu_legacy.h" +#include "emu_versions.h" + +#include + + +namespace EQEmu +{ + namespace inventory { + //using namespace RoF2::invtype; + //using namespace RoF2::invslot; + //using namespace RoF2::invbag; + //using namespace RoF2::invaug; + + } /*inventory*/ + + namespace constants { + const EQEmu::versions::ClientVersion CharacterCreationClient = EQEmu::versions::ClientVersion::RoF2; + const size_t CharacterCreationMax = RoF2::constants::CharacterCreationLimit; + + const size_t SayLinkBodySize = RoF2::constants::SayLinkBodySize; + + } /*constants*/ + enum class CastingSlot : uint32 { + Gem1 = 0, + Gem2 = 1, + Gem3 = 2, + Gem4 = 3, + Gem5 = 4, + Gem6 = 5, + Gem7 = 6, + Gem8 = 7, + Gem9 = 8, + Gem10 = 9, + Gem11 = 10, + Gem12 = 11, + MaxGems = 12, + Ability = 20, // HT/LoH for Tit + PotionBelt = 21, // Tit uses a different slot for PB + Item = 22, + Discipline = 23, + AltAbility = 0xFF + }; + +} /*EQEmu*/ + +#endif /*COMMON_EMU_CONSTANTS_H*/ diff --git a/common/emu_legacy.cpp b/common/emu_legacy.cpp new file mode 100644 index 000000000..36cb21c36 --- /dev/null +++ b/common/emu_legacy.cpp @@ -0,0 +1,20 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "emu_legacy.h" diff --git a/common/emu_legacy.h b/common/emu_legacy.h new file mode 100644 index 000000000..98829eae4 --- /dev/null +++ b/common/emu_legacy.h @@ -0,0 +1,256 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_EMU_LEGACY_H +#define COMMON_EMU_LEGACY_H + +#include "types.h" + +#include + + +namespace EQEmu +{ + // this is for perl and other legacy systems + namespace legacy { + enum InventorySlot { + SLOT_CHARM = 0, + SLOT_EAR01 = 1, + SLOT_HEAD = 2, + SLOT_FACE = 3, + SLOT_EAR02 = 4, + SLOT_NECK = 5, + SLOT_SHOULDER = 6, + SLOT_ARMS = 7, + SLOT_BACK = 8, + SLOT_BRACER01 = 9, + SLOT_BRACER02 = 10, + SLOT_RANGE = 11, + SLOT_HANDS = 12, + SLOT_PRIMARY = 13, + SLOT_SECONDARY = 14, + SLOT_RING01 = 15, + SLOT_RING02 = 16, + SLOT_CHEST = 17, + SLOT_LEGS = 18, + SLOT_FEET = 19, + SLOT_WAIST = 20, + SLOT_POWER_SOURCE = 9999, + SLOT_AMMO = 21, + SLOT_GENERAL_1 = 22, + SLOT_GENERAL_2 = 23, + SLOT_GENERAL_3 = 24, + SLOT_GENERAL_4 = 25, + SLOT_GENERAL_5 = 26, + SLOT_GENERAL_6 = 27, + SLOT_GENERAL_7 = 28, + SLOT_GENERAL_8 = 29, + //SLOT_GENERAL_9 = not supported + //SLOT_GENERAL_10 = not supported + SLOT_CURSOR = 30, + SLOT_CURSOR_END = (int16)0xFFFE, // I hope no one is using this... + SLOT_TRADESKILL = 1000, + SLOT_AUGMENT = 1001, + SLOT_INVALID = (int16)0xFFFF, + SLOT_POSSESSIONS_BEGIN = 0, + SLOT_POSSESSIONS_END = 30, + SLOT_EQUIPMENT_BEGIN = 0, + SLOT_EQUIPMENT_END = 21, + SLOT_PERSONAL_BEGIN = 22, + SLOT_PERSONAL_END = 29, + SLOT_PERSONAL_BAGS_BEGIN = 251, + SLOT_PERSONAL_BAGS_END = 330, + SLOT_CURSOR_BAG_BEGIN = 331, + SLOT_CURSOR_BAG_END = 340, + SLOT_TRIBUTE_BEGIN = 400, + SLOT_TRIBUTE_END = 404, + SLOT_BANK_BEGIN = 2000, + SLOT_BANK_END = 2023, + SLOT_BANK_BAGS_BEGIN = 2031, + SLOT_BANK_BAGS_END = 2270, + SLOT_SHARED_BANK_BEGIN = 2500, + SLOT_SHARED_BANK_END = 2501, + SLOT_SHARED_BANK_BAGS_BEGIN = 2531, + SLOT_SHARED_BANK_BAGS_END = 2550, + SLOT_TRADE_BEGIN = 3000, + SLOT_TRADE_END = 3007, + SLOT_TRADE_BAGS_BEGIN = 3031, + SLOT_TRADE_BAGS_END = 3110, + SLOT_WORLD_BEGIN = 4000, + SLOT_WORLD_END = 4009 + }; + + enum InventoryTypes : int16 { + TypePossessions = 0, + TypeBank, + TypeSharedBank, + TypeTrade, + TypeWorld, + TypeLimbo, // 5 + TypeTribute, + TypeTrophyTribute, + TypeGuildTribute, + TypeMerchant, + TypeDeleted, // 10 + TypeCorpse, + TypeBazaar, + TypeInspect, + TypeRealEstate, + TypeViewMODPC, // 15 + TypeViewMODBank, + TypeViewMODSharedBank, + TypeViewMODLimbo, + TypeAltStorage, + TypeArchived, // 20 + TypeMail, + TypeGuildTrophyTribute, + TypeKrono, + TypeOther, + TypeCount + }; + + enum PossessionsSlots : int16 { + SlotCharm = 0, + SlotEar1, + SlotHead, + SlotFace, + SlotEar2, + SlotNeck, // 5 + SlotShoulders, + SlotArms, + SlotBack, + SlotWrist1, + SlotWrist2, // 10 + SlotRange, + SlotHands, + SlotPrimary, + SlotSecondary, + SlotFinger1, // 15 + SlotFinger2, + SlotChest, + SlotLegs, + SlotFeet, + SlotWaist, // 20 + SlotPowerSource = 9999, // temp + SlotAmmo = 21, // temp + SlotGeneral1, + SlotGeneral2, + SlotGeneral3, + SlotGeneral4, // 25 + SlotGeneral5, + SlotGeneral6, + SlotGeneral7, + SlotGeneral8, + //SlotGeneral9, + //SlotGeneral10, + SlotCursor, // 30 + SlotCount + }; + + // these are currently hard-coded for existing inventory system..do not use in place of special client version handlers until ready + static const uint16 TYPE_POSSESSIONS_SIZE = SlotCount; + static const uint16 TYPE_BANK_SIZE = 24; + static const uint16 TYPE_SHARED_BANK_SIZE = 2; + static const uint16 TYPE_TRADE_SIZE = 8; + static const uint16 TYPE_WORLD_SIZE = 10; + static const uint16 TYPE_LIMBO_SIZE = 36; + static const uint16 TYPE_TRIBUTE_SIZE = 5; // (need client values) + static const uint16 TYPE_TROPHY_TRIBUTE_SIZE = 0; + static const uint16 TYPE_GUILD_TRIBUTE_SIZE = 0; + static const uint16 TYPE_MERCHANT_SIZE = 0; + static const uint16 TYPE_DELETED_SIZE = 0; + static const uint16 TYPE_CORPSE_SIZE = SlotCount; // no bitmask use..limits to size of client corpse window (see EQLimits::InventoryMapSize(MapCorpse, + + +namespace EntityLimits +{ + namespace NPC { + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + const size_t InvTypeTradeSize = 4; + + } /*NPC*/ + + namespace NPCMerchant { + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + const size_t InvTypeTradeSize = 4; + + } /*NPCMerchant*/ + + namespace Merc { + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + const size_t InvTypeTradeSize = 4; + + } /*Merc*/ + + namespace Bot { + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + const size_t InvTypeTradeSize = 8; + + } /*Bot*/ + + namespace ClientPet { + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + const size_t InvTypeTradeSize = 4; + + } /*Pet*/ + + namespace NPCPet { + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + const size_t InvTypeTradeSize = 4; + + } /*Pet*/ + + namespace MercPet { + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + const size_t InvTypeTradeSize = 4; + + } /*Pet*/ + + namespace BotPet { + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + const size_t InvTypeTradeSize = 4; + + } /*Pet*/ + +}; /*EntityLimits*/ + +#endif /*COMMON_EMU_LIMITS_H*/ diff --git a/common/emu_oplist.h b/common/emu_oplist.h index 62978655a..6b7c58841 100644 --- a/common/emu_oplist.h +++ b/common/emu_oplist.h @@ -64,6 +64,7 @@ N(OP_BuffRemoveRequest), N(OP_Bug), N(OP_CameraEffect), N(OP_Camp), +N(OP_CancelSneakHide), N(OP_CancelTask), N(OP_CancelTrade), N(OP_CastSpell), @@ -164,6 +165,7 @@ N(OP_FinishTrade), N(OP_FinishWindow), N(OP_FinishWindow2), N(OP_Fishing), +N(OP_Fling), N(OP_FloatListThing), N(OP_Forage), N(OP_ForceFindPerson), @@ -215,6 +217,7 @@ N(OP_GroupUpdate), N(OP_GroupUpdateB), N(OP_GroupUpdateLeaderAA), N(OP_GuildBank), +N(OP_GuildBankItemList), N(OP_GuildCreate), N(OP_GuildDelete), N(OP_GuildDemote), @@ -286,6 +289,7 @@ N(OP_LFGuild), N(OP_LFPCommand), N(OP_LFPGetMatchesRequest), N(OP_LFPGetMatchesResponse), +N(OP_LinkedReuse), N(OP_LoadSpellSet), N(OP_LocInfo), N(OP_LockoutTimerInfo), @@ -348,6 +352,7 @@ N(OP_OpenTributeMaster), N(OP_PDeletePetition), N(OP_PetBuffWindow), N(OP_PetCommands), +N(OP_PetHoTT), N(OP_Petition), N(OP_PetitionBug), N(OP_PetitionCheckIn), @@ -364,6 +369,8 @@ N(OP_PetitionUnCheckout), N(OP_PetitionUpdate), N(OP_PickPocket), N(OP_PlayerProfile), +N(OP_PlayerStateAdd), +N(OP_PlayerStateRemove), N(OP_PlayEverquestRequest), N(OP_PlayEverquestResponse), N(OP_PlayMP3), @@ -519,8 +526,6 @@ N(OP_VetRewardsAvaliable), N(OP_VoiceMacroIn), N(OP_VoiceMacroOut), N(OP_WeaponEquip1), -N(OP_WeaponEquip2), -N(OP_WeaponUnequip2), N(OP_WearChange), N(OP_Weather), N(OP_Weblink), @@ -534,6 +539,8 @@ N(OP_WorldLogout), N(OP_WorldObjectsSent), N(OP_WorldUnknown001), N(OP_XTargetAutoAddHaters), +N(OP_XTargetOpen), +N(OP_XTargetOpenResponse), N(OP_XTargetRequest), N(OP_XTargetResponse), N(OP_YellForHelp), @@ -547,4 +554,5 @@ N(OP_ZoneServerInfo), N(OP_ZoneServerReady), N(OP_ZoneSpawns), N(OP_ZoneUnavail), +N(OP_ResetAA), // mail and chat opcodes located in ../mail_oplist.h diff --git a/common/emu_tcp_connection.cpp b/common/emu_tcp_connection.cpp index a94081364..07f7d8ccf 100644 --- a/common/emu_tcp_connection.cpp +++ b/common/emu_tcp_connection.cpp @@ -479,21 +479,21 @@ void EmuTCPConnection::SendNetErrorPacket(const char* reason) { std::cout << reason; std::cout << "': " << inet_ntoa(in) << ":" << GetPort() << std::endl; #endif - ServerPacket* pack = new ServerPacket(0); - pack->size = 1; - if (reason) - pack->size += strlen(reason) + 1; - pack->pBuffer = new uchar[pack->size]; - memset(pack->pBuffer, 0, pack->size); - pack->pBuffer[0] = 255; - strcpy((char*) &pack->pBuffer[1], reason); - SendPacket(pack); - safe_delete(pack); + auto pack = new ServerPacket(0); + pack->size = 1; + if (reason) + pack->size += strlen(reason) + 1; + pack->pBuffer = new uchar[pack->size]; + memset(pack->pBuffer, 0, pack->size); + pack->pBuffer[0] = 255; + strcpy((char *)&pack->pBuffer[1], reason); + SendPacket(pack); + safe_delete(pack); } void EmuTCPConnection::RemoveRelay(EmuTCPConnection* relay, bool iSendRelayDisconnect) { if (iSendRelayDisconnect) { - ServerPacket* pack = new ServerPacket(0, 5); + auto pack = new ServerPacket(0, 5); pack->pBuffer[0] = 3; *((uint32*) &pack->pBuffer[1]) = relay->GetRemoteID(); SendPacket(pack); @@ -632,7 +632,7 @@ bool EmuTCPConnection::ProcessReceivedDataAsPackets(char* errbuf) { if (base >= recvbuf_used) { safe_delete_array(recvbuf); } else { - uchar* tmpbuf = new uchar[recvbuf_size - base]; + auto tmpbuf = new uchar[recvbuf_size - base]; memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base); safe_delete_array(recvbuf); recvbuf = tmpbuf; @@ -706,7 +706,7 @@ bool EmuTCPConnection::ProcessReceivedDataAsOldPackets(char* errbuf) { safe_delete_array(recvbuf); } else { - uchar* tmpbuf = new uchar[recvbuf_size - base]; + auto tmpbuf = new uchar[recvbuf_size - base]; memcpy(tmpbuf, &recvbuf[base], recvbuf_used - base); safe_delete_array(recvbuf); recvbuf = tmpbuf; @@ -762,7 +762,8 @@ void EmuTCPConnection::ProcessNetworkLayerPacket(ServerPacket* pack) { SendNetErrorPacket("New RelayClient: illegal on outgoing connection"); break; } - EmuTCPConnection* con = new EmuTCPConnection(Server->GetNextID(), Server, this, *((uint32*) data), *((uint32*) &data[4]), *((uint16*) &data[8])); + auto con = new EmuTCPConnection(Server->GetNextID(), Server, this, *((uint32 *)data), + *((uint32 *)&data[4]), *((uint16 *)&data[8])); Server->AddConnection(con); RelayCount++; break; @@ -810,7 +811,7 @@ bool EmuTCPConnection::SendData(bool &sent_something, char* errbuf) { if(sent_something) keepalive_timer.Start(); else if (TCPMode == modePacket && keepalive_timer.Check()) { - ServerPacket* pack = new ServerPacket(0, 0); + auto pack = new ServerPacket(0, 0); SendPacket(pack); safe_delete(pack); #if TCPN_DEBUG >= 5 diff --git a/common/emu_tcp_server.cpp b/common/emu_tcp_server.cpp index 4509c399f..00a241859 100644 --- a/common/emu_tcp_server.cpp +++ b/common/emu_tcp_server.cpp @@ -24,7 +24,7 @@ void EmuTCPServer::Process() { void EmuTCPServer::CreateNewConnection(uint32 ID, SOCKET in_socket, uint32 irIP, uint16 irPort) { - EmuTCPConnection *conn = new EmuTCPConnection(ID, this, in_socket, irIP, irPort, pOldFormat); + auto conn = new EmuTCPConnection(ID, this, in_socket, irIP, irPort, pOldFormat); AddConnection(conn); } diff --git a/common/emu_versions.cpp b/common/emu_versions.cpp new file mode 100644 index 000000000..92766e407 --- /dev/null +++ b/common/emu_versions.cpp @@ -0,0 +1,370 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "emu_versions.h" + + +bool EQEmu::versions::IsValidClientVersion(ClientVersion client_version) +{ + if (client_version <= ClientVersion::Unknown || client_version > LastClientVersion) + return false; + + return true; +} + +EQEmu::versions::ClientVersion EQEmu::versions::ValidateClientVersion(ClientVersion client_version) +{ + if (client_version <= ClientVersion::Unknown || client_version > LastClientVersion) + return ClientVersion::Unknown; + + return client_version; +} + +const char* EQEmu::versions::ClientVersionName(ClientVersion client_version) +{ + switch (client_version) { + case ClientVersion::Unknown: + return "Unknown Version"; + case ClientVersion::Client62: + return "Client 6.2"; + case ClientVersion::Titanium: + return "Titanium"; + case ClientVersion::SoF: + return "SoF"; + case ClientVersion::SoD: + return "SoD"; + case ClientVersion::UF: + return "UF"; + case ClientVersion::RoF: + return "RoF"; + case ClientVersion::RoF2: + return "RoF2"; + default: + return "Invalid Version"; + }; +} + +uint32 EQEmu::versions::ConvertClientVersionToClientVersionBit(ClientVersion client_version) +{ + switch (client_version) { + case ClientVersion::Unknown: + case ClientVersion::Client62: + return bit_Unknown; + case ClientVersion::Titanium: + return bit_Titanium; + case ClientVersion::SoF: + return bit_SoF; + case ClientVersion::SoD: + return bit_SoD; + case ClientVersion::UF: + return bit_UF; + case ClientVersion::RoF: + return bit_RoF; + case ClientVersion::RoF2: + return bit_RoF2; + default: + return bit_Unknown; + } +} + +EQEmu::versions::ClientVersion EQEmu::versions::ConvertClientVersionBitToClientVersion(uint32 client_version_bit) +{ + switch (client_version_bit) { + case (uint32)static_cast(ClientVersion::Unknown) : + case ((uint32)1 << (static_cast(ClientVersion::Client62) - 1)) : + return ClientVersion::Unknown; + case ((uint32)1 << (static_cast(ClientVersion::Titanium) - 1)) : + return ClientVersion::Titanium; + case ((uint32)1 << (static_cast(ClientVersion::SoF) - 1)) : + return ClientVersion::SoF; + case ((uint32)1 << (static_cast(ClientVersion::SoD) - 1)) : + return ClientVersion::SoD; + case ((uint32)1 << (static_cast(ClientVersion::UF) - 1)) : + return ClientVersion::UF; + case ((uint32)1 << (static_cast(ClientVersion::RoF) - 1)) : + return ClientVersion::RoF; + case ((uint32)1 << (static_cast(ClientVersion::RoF2) - 1)) : + return ClientVersion::RoF2; + default: + return ClientVersion::Unknown; + } +} + +uint32 EQEmu::versions::ConvertClientVersionToExpansion(ClientVersion client_version) +{ + switch (client_version) { + case ClientVersion::Unknown: + case ClientVersion::Client62: + case ClientVersion::Titanium: + return 0x000007FFU; + case ClientVersion::SoF: + return 0x00007FFFU; + case ClientVersion::SoD: + return 0x0000FFFFU; + case ClientVersion::UF: + return 0x0001FFFFU; + case ClientVersion::RoF: + case ClientVersion::RoF2: + return 0x000FFFFFU; + default: + return 0; + } +} + +bool EQEmu::versions::IsValidInventoryVersion(InventoryVersion inventory_version) +{ + if (inventory_version <= InventoryVersion::Unknown || inventory_version > LastInventoryVersion) + return false; + + return true; +} + +bool EQEmu::versions::IsValidPCInventoryVersion(InventoryVersion inventory_version) +{ + if (inventory_version <= InventoryVersion::Unknown || inventory_version > LastPCInventoryVersion) + return false; + + return true; +} + +bool EQEmu::versions::IsValidNonPCInventoryVersion(InventoryVersion inventory_version) +{ + if (inventory_version <= LastPCInventoryVersion || inventory_version > LastNonPCInventoryVersion) + return false; + + return true; +} + +bool EQEmu::versions::IsValidOfflinePCInventoryVersion(InventoryVersion inventory_version) +{ + if (inventory_version <= LastNonPCInventoryVersion || inventory_version > LastOfflinePCInventoryVersion) + return false; + + return true; +} + +EQEmu::versions::InventoryVersion EQEmu::versions::ValidateInventoryVersion(InventoryVersion inventory_version) +{ + if (inventory_version <= InventoryVersion::Unknown || inventory_version > LastInventoryVersion) + return InventoryVersion::Unknown; + + return inventory_version; +} + +EQEmu::versions::InventoryVersion EQEmu::versions::ValidatePCInventoryVersion(InventoryVersion inventory_version) +{ + if (inventory_version <= InventoryVersion::Unknown || inventory_version > LastPCInventoryVersion) + return InventoryVersion::Unknown; + + return inventory_version; +} + +EQEmu::versions::InventoryVersion EQEmu::versions::ValidateNonPCInventoryVersion(InventoryVersion inventory_version) +{ + if (inventory_version <= LastPCInventoryVersion || inventory_version > LastNonPCInventoryVersion) + return InventoryVersion::Unknown; + + return inventory_version; +} + +EQEmu::versions::InventoryVersion EQEmu::versions::ValidateOfflinePCInventoryVersion(InventoryVersion inventory_version) +{ + if (inventory_version <= LastNonPCInventoryVersion || inventory_version > LastOfflinePCInventoryVersion) + return InventoryVersion::Unknown; + + return inventory_version; +} + +const char* EQEmu::versions::InventoryVersionName(InventoryVersion inventory_version) +{ + switch (inventory_version) { + case InventoryVersion::Unknown: + return "Unknown Version"; + case InventoryVersion::Client62: + return "Client 6.2"; + case InventoryVersion::Titanium: + return "Titanium"; + case InventoryVersion::SoF: + return "SoF"; + case InventoryVersion::SoD: + return "SoD"; + case InventoryVersion::UF: + return "UF"; + case InventoryVersion::RoF: + return "RoF"; + case InventoryVersion::RoF2: + return "RoF2"; + case InventoryVersion::NPC: + return "NPC"; + case InventoryVersion::NPCMerchant: + return "NPC Merchant"; + case InventoryVersion::Merc: + return "Merc"; + case InventoryVersion::Bot: + return "Bot"; + case InventoryVersion::ClientPet: + return "Client Pet"; + case InventoryVersion::NPCPet: + return "NPC Pet"; + case InventoryVersion::MercPet: + return "Merc Pet"; + case InventoryVersion::BotPet: + return "Bot Pet"; + case InventoryVersion::OfflineTitanium: + return "Offline Titanium"; + case InventoryVersion::OfflineSoF: + return "Offline SoF"; + case InventoryVersion::OfflineSoD: + return "Offline SoD"; + case InventoryVersion::OfflineUF: + return "Offline UF"; + case InventoryVersion::OfflineRoF: + return "Offline RoF"; + case InventoryVersion::OfflineRoF2: + return "Offline RoF2"; + default: + return "Invalid Version"; + }; +} + +EQEmu::versions::ClientVersion EQEmu::versions::ConvertInventoryVersionToClientVersion(InventoryVersion inventory_version) +{ + switch (inventory_version) { + case InventoryVersion::Unknown: + case InventoryVersion::Client62: + return ClientVersion::Unknown; + case InventoryVersion::Titanium: + return ClientVersion::Titanium; + case InventoryVersion::SoF: + return ClientVersion::SoF; + case InventoryVersion::SoD: + return ClientVersion::SoD; + case InventoryVersion::UF: + return ClientVersion::UF; + case InventoryVersion::RoF: + return ClientVersion::RoF; + case InventoryVersion::RoF2: + return ClientVersion::RoF2; + default: + return ClientVersion::Unknown; + } +} + +EQEmu::versions::InventoryVersion EQEmu::versions::ConvertClientVersionToInventoryVersion(ClientVersion client_version) +{ + switch (client_version) { + case ClientVersion::Unknown: + case ClientVersion::Client62: + return InventoryVersion::Unknown; + case ClientVersion::Titanium: + return InventoryVersion::Titanium; + case ClientVersion::SoF: + return InventoryVersion::SoF; + case ClientVersion::SoD: + return InventoryVersion::SoD; + case ClientVersion::UF: + return InventoryVersion::UF; + case ClientVersion::RoF: + return InventoryVersion::RoF; + case ClientVersion::RoF2: + return InventoryVersion::RoF2; + default: + return InventoryVersion::Unknown; + } +} + +EQEmu::versions::InventoryVersion EQEmu::versions::ConvertPCInventoryVersionToOfflinePCInventoryVersion(InventoryVersion inventory_version) +{ + switch (inventory_version) { + case InventoryVersion::Titanium: + return InventoryVersion::OfflineTitanium; + case InventoryVersion::SoF: + return InventoryVersion::OfflineSoF; + case InventoryVersion::SoD: + return InventoryVersion::OfflineSoD; + case InventoryVersion::UF: + return InventoryVersion::OfflineUF; + case InventoryVersion::RoF: + return InventoryVersion::OfflineRoF; + case InventoryVersion::RoF2: + return InventoryVersion::OfflineRoF2; + default: + return InventoryVersion::Unknown; + } +} + +EQEmu::versions::InventoryVersion EQEmu::versions::ConvertOfflinePCInventoryVersionToPCInventoryVersion(InventoryVersion inventory_version) +{ + switch (inventory_version) { + case InventoryVersion::OfflineTitanium: + return InventoryVersion::Titanium; + case InventoryVersion::OfflineSoF: + return InventoryVersion::SoF; + case InventoryVersion::OfflineSoD: + return InventoryVersion::SoD; + case InventoryVersion::OfflineUF: + return InventoryVersion::UF; + case InventoryVersion::OfflineRoF: + return InventoryVersion::RoF; + case InventoryVersion::OfflineRoF2: + return InventoryVersion::RoF2; + default: + return InventoryVersion::Unknown; + } +} + +EQEmu::versions::ClientVersion EQEmu::versions::ConvertOfflinePCInventoryVersionToClientVersion(InventoryVersion inventory_version) +{ + switch (inventory_version) { + case InventoryVersion::OfflineTitanium: + return ClientVersion::Titanium; + case InventoryVersion::OfflineSoF: + return ClientVersion::SoF; + case InventoryVersion::OfflineSoD: + return ClientVersion::SoD; + case InventoryVersion::OfflineUF: + return ClientVersion::UF; + case InventoryVersion::OfflineRoF: + return ClientVersion::RoF; + case InventoryVersion::OfflineRoF2: + return ClientVersion::RoF2; + default: + return ClientVersion::Unknown; + } +} + +EQEmu::versions::InventoryVersion EQEmu::versions::ConvertClientVersionToOfflinePCInventoryVersion(ClientVersion client_version) +{ + switch (client_version) { + case ClientVersion::Titanium: + return InventoryVersion::OfflineTitanium; + case ClientVersion::SoF: + return InventoryVersion::OfflineSoF; + case ClientVersion::SoD: + return InventoryVersion::OfflineSoD; + case ClientVersion::UF: + return InventoryVersion::OfflineUF; + case ClientVersion::RoF: + return InventoryVersion::OfflineRoF; + case ClientVersion::RoF2: + return InventoryVersion::OfflineRoF2; + default: + return InventoryVersion::Unknown; + } +} diff --git a/common/emu_versions.h b/common/emu_versions.h new file mode 100644 index 000000000..8a806e8fc --- /dev/null +++ b/common/emu_versions.h @@ -0,0 +1,130 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_EMU_VERSIONS_H +#define COMMON_EMU_VERSIONS_H + +#include "types.h" + +#include + + +namespace EQEmu +{ + namespace versions { + enum class ClientVersion { + Unknown = 0, + Client62, // Build: 'Aug 4 2005 15:40:59' + Titanium, // Build: 'Oct 31 2005 10:33:37' + SoF, // Build: 'Sep 7 2007 09:11:49' + SoD, // Build: 'Dec 19 2008 15:22:49' + UF, // Build: 'Jun 8 2010 16:44:32' + RoF, // Build: 'Dec 10 2012 17:35:44' + RoF2 // Build: 'May 10 2013 23:30:08' + }; + + enum ClientVersionBit : uint32 { + bit_Unknown = 0, + bit_Client62 = 0x00000001, // unsupported (placeholder for scripts) + bit_Titanium = 0x00000002, + bit_SoF = 0x00000004, + bit_SoD = 0x00000008, + bit_UF = 0x00000010, + bit_RoF = 0x00000020, + bit_RoF2 = 0x00000040, + bit_TitaniumAndEarlier = 0x00000003, + bit_SoFAndEarlier = 0x00000007, + bit_SoDAndEarlier = 0x0000000F, + bit_UFAndEarlier = 0x0000001F, + bit_RoFAndEarlier = 0x0000003F, + bit_SoFAndLater = 0xFFFFFFFC, + bit_SoDAndLater = 0xFFFFFFF8, + bit_UFAndLater = 0xFFFFFFF0, + bit_RoFAndLater = 0xFFFFFFE0, + bit_RoF2AndLater = 0xFFFFFFC0, + bit_AllClients = 0xFFFFFFFF + }; + + const ClientVersion LastClientVersion = ClientVersion::RoF2; + const size_t ClientVersionCount = (static_cast(LastClientVersion) + 1); + + extern bool IsValidClientVersion(ClientVersion client_version); + extern ClientVersion ValidateClientVersion(ClientVersion client_version); + extern const char* ClientVersionName(ClientVersion client_version); + extern uint32 ConvertClientVersionToClientVersionBit(ClientVersion client_version); + extern ClientVersion ConvertClientVersionBitToClientVersion(uint32 client_version_bit); + extern uint32 ConvertClientVersionToExpansion(ClientVersion client_version); + + } /*versions*/ + + namespace versions { + enum class InventoryVersion { + Unknown = 0, + Client62, + Titanium, + SoF, + SoD, + UF, + RoF, + RoF2, + NPC, + NPCMerchant, + Merc, + Bot, + ClientPet, + NPCPet, + MercPet, + BotPet, + OfflineTitanium, + OfflineSoF, + OfflineSoD, + OfflineUF, + OfflineRoF, + OfflineRoF2 + }; + + const InventoryVersion LastInventoryVersion = InventoryVersion::OfflineRoF2; + const InventoryVersion LastPCInventoryVersion = InventoryVersion::RoF2; + const InventoryVersion LastNonPCInventoryVersion = InventoryVersion::BotPet; + const InventoryVersion LastOfflinePCInventoryVersion = InventoryVersion::OfflineRoF2; + const size_t InventoryVersionCount = (static_cast(LastInventoryVersion) + 1); + + extern bool IsValidInventoryVersion(InventoryVersion inventory_version); + extern bool IsValidPCInventoryVersion(InventoryVersion inventory_version); + extern bool IsValidNonPCInventoryVersion(InventoryVersion inventory_version); + extern bool IsValidOfflinePCInventoryVersion(InventoryVersion inventory_version); + + extern InventoryVersion ValidateInventoryVersion(InventoryVersion inventory_version); + extern InventoryVersion ValidatePCInventoryVersion(InventoryVersion inventory_version); + extern InventoryVersion ValidateNonPCInventoryVersion(InventoryVersion inventory_version); + extern InventoryVersion ValidateOfflinePCInventoryVersion(InventoryVersion inventory_version); + + extern const char* InventoryVersionName(InventoryVersion inventory_version); + extern ClientVersion ConvertInventoryVersionToClientVersion(InventoryVersion inventory_version); + extern InventoryVersion ConvertClientVersionToInventoryVersion(ClientVersion client_version); + extern InventoryVersion ConvertPCInventoryVersionToOfflinePCInventoryVersion(InventoryVersion inventory_version); + extern InventoryVersion ConvertOfflinePCInventoryVersionToPCInventoryVersion(InventoryVersion inventory_version); + extern ClientVersion ConvertOfflinePCInventoryVersionToClientVersion(InventoryVersion inventory_version); + extern InventoryVersion ConvertClientVersionToOfflinePCInventoryVersion(ClientVersion client_version); + + } /*versions*/ + +} /*EQEmu*/ + +#endif /*COMMON_EMU_VERSIONS_H*/ diff --git a/common/eq_constants.h b/common/eq_constants.h index 0fec1f223..0fe5ccf48 100644 --- a/common/eq_constants.h +++ b/common/eq_constants.h @@ -1,5 +1,6 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,407 +14,57 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef EQ_CONSTANTS_H -#define EQ_CONSTANTS_H + +#ifndef COMMON_EQ_CONSTANTS_H +#define COMMON_EQ_CONSTANTS_H #include "skills.h" #include "types.h" -/* -** Light Types -** -*/ -enum LightTypes -{ - lightTypeNone = 0, - lightTypeCandle, - lightTypeTorch, - lightTypeTinyGlowingSkull, - lightTypeSmallLantern, - lightTypeSteinOfMoggok, - lightTypeLargeLantern, - lightTypeFlamelessLantern, - lightTypeGlobeOfStars, - lightTypeLightGlobe, - lightTypeLightstone, - lightTypeGreaterLightstone, - lightTypeFireBeetleEye, - lightTypeColdlight, - lightTypeUnknown1, - lightTypeUnknown2 -}; -#define LIGHT_TYPES_COUNT 16 +//SpawnAppearance types: (compared two clients for server-originating types: SoF & RoF2) +#define AT_Die 0 // this causes the client to keel over and zone to bind point (default action) +#define AT_WhoLevel 1 // the level that shows up on /who +//#define AT_2 2 // unknown +#define AT_Invis 3 // 0 = visible, 1 = invisible +#define AT_PVP 4 // 0 = blue, 1 = pvp (red) +#define AT_Light 5 // light type emitted by player (lightstone, shiny shield) +#define AT_Anim 14 // 100=standing, 110=sitting, 111=ducking, 115=feigned, 105=looting +#define AT_Sneak 15 // 0 = normal, 1 = sneaking +#define AT_SpawnID 16 // server to client, sets player spawn id +#define AT_HP 17 // Client->Server, my HP has changed (like regen tic) +#define AT_Linkdead 18 // 0 = normal, 1 = linkdead +#define AT_Levitate 19 // 0=off, 1=flymode, 2=levitate +#define AT_GM 20 // 0 = normal, 1 = GM - all odd numbers seem to make it GM +#define AT_Anon 21 // 0 = normal, 1 = anon, 2 = roleplay +#define AT_GuildID 22 +#define AT_GuildRank 23 // 0=member, 1=officer, 2=leader +#define AT_AFK 24 // 0 = normal, 1 = afk +#define AT_Pet 25 // Param is EntityID of owner, or 0 for when charm breaks +//#define AT_27 27 // unknown +#define AT_Split 28 // 0 = normal, 1 = autosplit on (not showing in SoF+) (client-to-server only) +#define AT_Size 29 // spawn's size (present: SoF, absent: RoF2) +//#define AT_30 30 // unknown +#define AT_NPCName 31 // change PC's name's color to NPC color 0 = normal, 1 = npc name +//#define AT_32 32 // unknown +//#define AT_33 33 // unknown +//#define AT_34 34 // unknown (present: SoF, absent: RoF2) +//#define AT_35 35 // unknown +//#define AT_36 36 // unknown +//#define AT_37 37 // unknown +//#define AT_38 38 // unknown +//#define AT_39 39 // unknown +#define AT_ShowHelm 43 // 0 = hide graphic, 1 = show graphic +#define AT_DamageState 44 // The damage state of a destructible object (0 through 4) +//#define AT_46 46 // unknown +//#define AT_48 48 // unknown +//#define AT_49 49 // unknown +//#define AT_52 52 // (absent: SoF, present: RoF2) (not a replacement for RoF absent 29 or 34) +//#define AT_53 53 // (absent: SoF, present: RoF2) (not a replacement for RoF absent 29 or 34) -/* -** Light Levels -** -*/ -enum LightLevels -{ - lightLevelUnlit = 0, - lightLevelCandle, - lightLevelTorch, - lightLevelSmallMagic, - lightLevelRedLight, - lightLevelBlueLight, - lightLevelSmallLantern, - lightLevelMagicLantern, - lightLevelLargeLantern, - lightLevelLargeMagic, - lightLevelBrilliant -}; - -#define LIGHT_LEVELS_COUNT 11 - -/* -** Item attributes -** -** (There are no grepwin hits other than these declarations... Do they have a use?) -*/ -enum ItemAttributes : uint32 -{ - ItemAttrNone = 0x00000000, - ItemAttrLore = 0x00000001, - ItemAttrArtifact = 0x00000002, - ItemAttrSummoned = 0x00000004, - ItemAttrMagic = 0x00000008, - ItemAttrAugment = 0x00000010, - ItemAttrPendingLore = 0x00000020, - ItemAttrUnknown = 0xFFFFFFFF -}; - -/* -** Item class types -** -*/ -enum ItemClassTypes -{ - ItemClassCommon = 0, - ItemClassContainer, - ItemClassBook, - _ItemClassCount -}; - -/* -** Item use types -** -** (ref: database and eqstr_us.txt) -** -** (Looking at a recent database, it's possible that some of the item values may be off [10-27-2013]) -*/ -enum ItemUseTypes : uint8 -{ -/*9138*/ ItemType1HSlash = 0, -/*9141*/ ItemType2HSlash, -/*9140*/ ItemType1HPiercing, -/*9139*/ ItemType1HBlunt, -/*9142*/ ItemType2HBlunt, -/*5504*/ ItemTypeBow, -/*----*/ ItemTypeUnknown1, -/*----*/ ItemTypeLargeThrowing, -/*5505*/ ItemTypeShield, -/*5506*/ ItemTypeScroll, -/*5507*/ ItemTypeArmor, -/*5508*/ ItemTypeMisc, // a lot of random crap has this item use. -/*7564*/ ItemTypeLockPick, -/*----*/ ItemTypeUnknown2, -/*5509*/ ItemTypeFood, -/*5510*/ ItemTypeDrink, -/*5511*/ ItemTypeLight, -/*5512*/ ItemTypeCombinable, // not all stackable items are this use... -/*5513*/ ItemTypeBandage, -/*----*/ ItemTypeSmallThrowing, -/*----*/ ItemTypeSpell, // spells and tomes -/*5514*/ ItemTypePotion, -/*----*/ ItemTypeUnknown3, -/*0406*/ ItemTypeWindInstrument, -/*0407*/ ItemTypeStringedInstrument, -/*0408*/ ItemTypeBrassInstrument, -/*0405*/ ItemTypePercussionInstrument, -/*5515*/ ItemTypeArrow, -/*----*/ ItemTypeUnknown4, -/*5521*/ ItemTypeJewelry, -/*----*/ ItemTypeSkull, -/*5516*/ ItemTypeBook, // skill-up tomes/books? (would probably need a pp flag if true...) -/*5517*/ ItemTypeNote, -/*5518*/ ItemTypeKey, -/*----*/ ItemTypeCoin, -/*5520*/ ItemType2HPiercing, -/*----*/ ItemTypeFishingPole, -/*----*/ ItemTypeFishingBait, -/*5519*/ ItemTypeAlcohol, -/*----*/ ItemTypeKey2, // keys and satchels?? (questable keys?) -/*----*/ ItemTypeCompass, -/*----*/ ItemTypeUnknown5, -/*----*/ ItemTypePoison, // might be wrong, but includes poisons -/*----*/ ItemTypeUnknown6, -/*----*/ ItemTypeUnknown7, -/*5522*/ ItemTypeMartial, -/*----*/ ItemTypeUnknown8, -/*----*/ ItemTypeUnknown9, -/*----*/ ItemTypeUnknown10, -/*----*/ ItemTypeUnknown11, -/*----*/ ItemTypeSinging, -/*5750*/ ItemTypeAllInstrumentTypes, -/*5776*/ ItemTypeCharm, -/*----*/ ItemTypeDye, -/*----*/ ItemTypeAugmentation, -/*----*/ ItemTypeAugmentationSolvent, -/*----*/ ItemTypeAugmentationDistiller, -/*----*/ ItemTypeUnknown12, -/*----*/ ItemTypeFellowshipKit, -/*----*/ ItemTypeUnknown13, -/*----*/ ItemTypeRecipe, -/*----*/ ItemTypeAdvancedRecipe, -/*----*/ ItemTypeJournal, // only one(1) database entry -/*----*/ ItemTypeAltCurrency, // alt-currency (as opposed to coinage) -/*5881*/ ItemTypePerfectedAugmentationDistiller, -/*----*/ _ItemTypeCount - -/* - Unknowns: - - Mounts? - Ornamentations? - GuildBanners? - Collectible? - Placeable? - (others?) -*/ -}; - -/* -** Augmentation use type bitmasks (1-based) -** -** (ref: dbstr_us.txt) -** -*/ -enum AugmentationUseTypeBitmasks : uint32 { - AugUseNone = 0x00000000, - AugUseGeneralSingleStat = 0x00000001, /*1^16^1 (General: Single Stat)^0*/ - AugUseGeneralMultipleStat = 0x00000002, /*2^16^2 (General: Multiple Stat)^0*/ - AugUseGeneralSpellEffect = 0x00000004, /*3^16^3 (General: Spell Effect)^0*/ - AugUseWeaponGeneral = 0x00000008, /*4^16^4 (Weapon: General)^0*/ - AugUseWeaponElemDamage = 0x00000010, /*5^16^5 (Weapon: Elem Damage)^0*/ - AugUseWeaponBaseDamage = 0x00000020, /*6^16^6 (Weapon: Base Damage)^0*/ - AugUseGeneralGroup = 0x00000040, /*7^16^7 (General: Group)^0*/ - AugUseGeneralRaid = 0x00000080, /*8^16^8 (General: Raid)^0*/ - AugUseGeneralDragonsPoints = 0x00000100, /*9^16^9 (General: Dragons Points)^0*/ - AugUseCraftedCommon = 0x00000200, /*10^16^10 (Crafted: Common)^0*/ - AugUseCraftedGroup1 = 0x00000400, /*11^16^11 (Crafted: Group)^0*/ - AugUseCraftedRaid1 = 0x00000800, /*12^16^12 (Crafted: Raid)^0*/ - AugUseEnergeiacGroup = 0x00001000, /*13^16^13 (Energeiac: Group)^0*/ - AugUseEnergeiacRaid = 0x00002000, /*14^16^14 (Energeiac: Raid)^0*/ - AugUseEmblem = 0x00004000, /*15^16^15 (Emblem)^0*/ - AugUseCraftedGroup2 = 0x00008000, /*16^16^16 (Crafted: Group)^0*/ - AugUseCraftedRaid2 = 0x00010000, /*17^16^17 (Crafted: Raid)^0*/ - AugUseUnknown1 = 0x00020000, /*18^16^18^0*/ - AugUseUnknown2 = 0x00040000, /*19^16^19^0*/ - AugUseOrnamentation = 0x00080000, /*20^16^20 (Ornamentation)^0*/ - AugUseSpecialOrnamentation = 0x00100000, /*21^16^21 (Special Ornamentation)^0*/ - AugUseUnknown3 = 0x00200000, /*22^16^22^0*/ - AugUseUnknown4 = 0x00400000, /*23^16^23^0*/ - AugUseUnknown5 = 0x00800000, /*24^16^24^0*/ - AugUseUnknown6 = 0x01000000, /*25^16^25^0*/ - AugUseUnknown7 = 0x02000000, /*26^16^26^0*/ - AugUseUnknown8 = 0x04000000, /*27^16^27^0*/ - AugUseUnknown9 = 0x08000000, /*28^16^28^0*/ - AugUseUnknown10 = 0x10000000, /*29^16^29^0*/ - AugUseEpic25 = 0x20000000, /*30^16^30^0*/ - AugUseTest = 0x40000000, /*31^16^Test^0*/ // listed as 31^16^31^0 in 5-10 client - AugUseAll = 0xFFFFFFFF -}; - -/* -** Augmentation use types (enumerated) -** -*/ -enum AugmentationUseTypes : uint8 { - AugTypeNone = 0, - AugTypeGeneralSingleStat, - AugTypeGeneralMultipleStat, - AugTypeGeneralSpellEffect, - AugTypeWeaponGeneral, - AugTypeWeaponElemDamage, - AugTypeWeaponBaseDamage, - AugTypeGeneralGroup, - AugTypeGeneralRaid, - AugTypeGeneralDragonsPoints, - AugTypeCraftedCommon, - AugTypeCraftedGroup1, - AugTypeCraftedRaid1, - AugTypeEnergeiacGroup, - AugTypeEnergeiacRaid, - AugTypeEmblem, - AugTypeCraftedGroup2, - AugTypeCraftedRaid2, - AugTypeUnknown1, - AugTypeUnknown2, - AugTypeOrnamentation, - AugTypeSpecialOrnamentation, - AugTypeUnknown3, - AugTypeUnknown4, - AugTypeUnknown5, - AugTypeUnknown6, - AugTypeUnknown7, - AugTypeUnknown8, - AugTypeUnknown9, - AugTypeUnknown10, - AugTypeEpic25, - AugTypeTest, - _AugTypeCount, - AugTypeAll = 255 -}; - -/* -** Augmentation restriction types (in-work) -** -** (ref: eqstr_us.txt) -** -*/ -enum AugmentationRestrictionTypes : uint8 { -/*4690*/ AugRestrAny = 0, -/*9134*/ AugRestrArmor, -/*9135*/ AugRestrWeapons, -/*9136*/ AugRestr1HWeapons, -/*9137*/ AugRestr2HWeapons, -/*9138*/ AugRestr1HSlash, -/*9139*/ AugRestr1HBlunt, -/*9140*/ AugRestrPiercing, -/*9148*/ AugRestrHandToHand, -/*9141*/ AugRestr2HSlash, -/*9142*/ AugRestr2HBlunt, -/*9143*/ AugRestr2HPierce, -/*9144*/ AugRestrBows, -/*9145*/ AugRestrShields, -/*8052*/ AugRestr1HSlash1HBluntOrHandToHand, -/*9200*/ AugRestr1HBluntOrHandToHand, // no listed peq entries - -// these three appear to be post-RoF (12-10-2012) and can not be verified until RoF (05-10-2013) is supported -/*????*/ AugRestrUnknown1, -/*????*/ AugRestrUnknown2, -/*????*/ AugRestrUnknown3, // last value in peq entries - _AugRestrCount - -/*4687*/ //AugTypeAllItems, // ?? unknown atm -/*4688*/ //AugTypePrestige, // ?? unknown atm -/*4689*/ //AugTypeNonPrestige, // ?? unknown atm -}; - -/* -** Container use types -** -** This correlates to world 'object.type' (object.h/Object.cpp) as well as Item_Struct.BagType -** -** (ref: database, web forums and eqstr_us.txt) -*/ -enum ContainerUseTypes : uint8 -{ -/*3400*/ BagTypeSmallBag = 0, -/*3401*/ BagTypeLargeBag, -/*3402*/ BagTypeQuiver, -/*3403*/ BagTypeBeltPouch, -/*3404*/ BagTypeWristPouch, -/*3405*/ BagTypeBackPack, -/*3406*/ BagTypeSmallChest, -/*3407*/ BagTypeLargeChest, -/*----*/ BagTypeBandolier, // <*Database Reference Only> -/*3408*/ BagTypeMedicineBag, -/*3409*/ BagTypeToolBox, -/*3410*/ BagTypeLexicon, -/*3411*/ BagTypeMortar, -/*3412*/ BagTypeSelfDusting, // Quest container (Auto-clear contents?) -/*3413*/ BagTypeMixingBowl, -/*3414*/ BagTypeOven, -/*3415*/ BagTypeSewingKit, -/*3416*/ BagTypeForge, -/*3417*/ BagTypeFletchingKit, -/*3418*/ BagTypeBrewBarrel, -/*3419*/ BagTypeJewelersKit, -/*3420*/ BagTypePotteryWheel, -/*3421*/ BagTypeKiln, -/*3422*/ BagTypeKeymaker, // (no database entries as of peq rev 69) -/*3423*/ BagTypeWizardsLexicon, -/*3424*/ BagTypeMagesLexicon, -/*3425*/ BagTypeNecromancersLexicon, -/*3426*/ BagTypeEnchantersLexicon, -/*----*/ BagTypeUnknown1, // (a coin pouch/purse?) (no database entries as of peq rev 69) -/*----*/ BagTypeConcordanceofResearch, // <*Database Reference Only> -/*3427*/ BagTypeAlwaysWorks, // Quest container (Never-fail combines?) -/*3428*/ BagTypeKoadaDalForge, // High Elf -/*3429*/ BagTypeTeirDalForge, // Dark Elf -/*3430*/ BagTypeOggokForge, // Ogre -/*3431*/ BagTypeStormguardForge, // Dwarf -/*3432*/ BagTypeAkanonForge, // Gnome -/*3433*/ BagTypeNorthmanForge, // Barbarian -/*----*/ BagTypeUnknown2, // (no database entries as of peq rev 69) -/*3434*/ BagTypeCabilisForge, // Iksar -/*3435*/ BagTypeFreeportForge, // Human 1 -/*3436*/ BagTypeRoyalQeynosForge, // Human 2 -/*3439*/ BagTypeHalflingTailoringKit, -/*3438*/ BagTypeErudTailoringKit, -/*3440*/ BagTypeFierDalTailoringKit, // Wood Elf -/*3441*/ BagTypeFierDalFletchingKit, // Wood Elf -/*3437*/ BagTypeIksarPotteryWheel, -/*3442*/ BagTypeTackleBox, -/*3443*/ BagTypeTrollForge, -/*3445*/ BagTypeFierDalForge, // Wood Elf -/*3444*/ BagTypeValeForge, // Halfling -/*3446*/ BagTypeErudForge, -/*----*/ BagTypeTradersSatchel, // <*Database Reference Only> (db: Yellow Trader's Satchel Token?) -/*5785*/ BagTypeGuktaForge, // Froglok (no database entries as of peq rev 69) -/*3359*/ BagTypeAugmentationSealer, -/*----*/ BagTypeIceCreamChurn, // <*Database Reference Only> -/*6325*/ BagTypeTransformationmold, // Ornamentation -/*6340*/ BagTypeDetransformationmold, // Ornamentation Stripper -/*5400*/ BagTypeUnattuner, -/*7684*/ BagTypeTradeskillBag, -/*7692*/ BagTypeCollectibleBag, -/*----*/ _BagTypeCount -}; - -/* -** Item Effect Types -** -*/ -enum { - ET_CombatProc = 0, - ET_ClickEffect = 1, - ET_WornEffect = 2, - ET_Expendable = 3, - ET_EquipClick = 4, - ET_ClickEffect2 = 5, //name unknown - ET_Focus = 6, - ET_Scroll = 7 -}; - -//SpawnAppearance types: -#define AT_Die 0 // this causes the client to keel over and zone to bind point -#define AT_WhoLevel 1 // the level that shows up on /who -#define AT_Invis 3 // 0 = visible, 1 = invisible -#define AT_PVP 4 // 0 = blue, 1 = pvp (red) -#define AT_Light 5 // light type emitted by player (lightstone, shiny shield) -#define AT_Anim 14 // 100=standing, 110=sitting, 111=ducking, 115=feigned, 105=looting -#define AT_Sneak 15 // 0 = normal, 1 = sneaking -#define AT_SpawnID 16 // server to client, sets player spawn id -#define AT_HP 17 // Client->Server, my HP has changed (like regen tic) -#define AT_Linkdead 18 // 0 = normal, 1 = linkdead -#define AT_Levitate 19 // 0=off, 1=flymode, 2=levitate -#define AT_GM 20 // 0 = normal, 1 = GM - all odd numbers seem to make it GM -#define AT_Anon 21 // 0 = normal, 1 = anon, 2 = roleplay -#define AT_GuildID 22 -#define AT_GuildRank 23 // 0=member, 1=officer, 2=leader -#define AT_AFK 24 // 0 = normal, 1 = afk -#define AT_Pet 25 // Param is EntityID of owner, or 0 for when charm breaks -#define AT_Split 28 // 0 = normal, 1 = autosplit on -#define AT_Size 29 // spawn's size -#define AT_NPCName 31 // change PC's name's color to NPC color 0 = normal, 1 = npc name -#define AT_ShowHelm 43 // 0 = do not show helmet graphic, 1 = show graphic -#define AT_DamageState 44 // The damage state of a destructible object (0 through 4) -//#define AT_Trader 300 // Bazzar Trader Mode +//#define AT_Trader 300 // Bazaar Trader Mode (not present in SoF or RoF2) // animations for AT_Anim #define ANIM_FREEZE 102 @@ -519,15 +170,40 @@ typedef enum { #define MT_StrikeThrough 339 #define MT_Stun 340 +// TODO: Really should combine above and below into one + //from showeq enum ChatColor { + /* CC_Default = 0, CC_DarkGrey = 1, CC_DarkGreen = 2, CC_DarkBlue = 3, CC_Purple = 5, CC_LightGrey = 6, + */ + + CC_WhiteSmoke = 0, // FF|F0F0F0 + CC_Green = 2, // FF|008000 + CC_BrightBlue = 3, // FF|0040FF + CC_Magenta = 5, // FF|F000F0 + CC_Gray = 6, // FF|808080 + CC_LightGray = 7, // FF|E0E0E0 + //CC_WhiteSmoke2 = 10, // FF|F0F0F0 + CC_DarkGray = 12, // FF|A0A0A0 + CC_Red = 13, // FF|F00000 + CC_Lime = 14, // FF|00F000 + CC_Yellow = 15, // FF|F0F000 + CC_Blue = 16, // FF|0000F0 + CC_LightNavy = 17, // FF|0000AF + CC_Cyan = 18, // FF|00F0F0 + CC_Black = 20, // FF|000000 + + // any index <= 255 that is not defined above + CC_DimGray = 1, // FF|606060 + CC_Default = 1, + CC_User_Say = 256, CC_User_Tell = 257, CC_User_Group = 258, @@ -723,7 +399,7 @@ static const uint8 DamageTypeUnknown = 0xFF; ** ** (indexed by 'Skill' of SkillUseTypes) */ -static const uint8 SkillDamageTypes[HIGHEST_SKILL + 1] = // change to _SkillServerArraySize once activated +static const uint8 SkillDamageTypes[EQEmu::skills::HIGHEST_SKILL + 1] = // change to _SkillServerArraySize once activated { /*1HBlunt*/ 0, /*1HSlashing*/ 1, @@ -799,29 +475,10 @@ static const uint8 SkillDamageTypes[HIGHEST_SKILL + 1] = // change to _SkillServ /*Intimidation*/ DamageTypeUnknown, /*Berserking*/ DamageTypeUnknown, /*Taunt*/ DamageTypeUnknown, -/*Frenzy*/ 74 //, -// /*RemoveTrap*/ DamageTypeUnknown, // Needs research (set for SenseTrap value) -// /*TripleAttack*/ DamageTypeUnknown, // Needs research (set for DoubleAttack value) -// /*2HPiercing*/ 36 // Needs research (set for 1HPiercing value - similar to slash/blunt) -}; - -/* -** Material use slots -** -*/ -enum MaterialUseSlots : uint8 -{ - MaterialHead = 0, - MaterialChest, - MaterialArms, - MaterialWrist, - MaterialHands, - MaterialLegs, - MaterialFeet, - MaterialPrimary, - MaterialSecondary, - _MaterialCount, - _MaterialInvalid = 255 +/*Frenzy*/ 74, +/*RemoveTrap*/ DamageTypeUnknown, // Needs research (set for SenseTrap value) +/*TripleAttack*/ DamageTypeUnknown, // Needs research (set for DoubleAttack value) +/*2HPiercing*/ 36 // Needs research (set for 1HPiercing value - similar to slash/blunt) }; /* @@ -858,164 +515,16 @@ enum MaterialUseSlots : uint8 ** */ -enum InventoryMapTypes : int16 { - MapPossessions = 0, - MapBank, - MapSharedBank, - MapTrade, - MapWorld, - MapLimbo, - MapTribute, - MapTrophyTribute, - MapGuildTribute, - MapMerchant, - MapDeleted, - MapCorpse, - MapBazaar, - MapInspect, - MapRealEstate, - MapViewMODPC, - MapViewMODBank, - MapViewMODSharedBank, - MapViewMODLimbo, - MapAltStorage, - MapArchived, - MapMail, - MapGuildTrophyTribute, - MapKrono, - MapOther, - _MapCount -}; - -enum InventoryMainTypes : int16 { - MainCharm = 0, - MainEar1, - MainHead, - MainFace, - MainEar2, - MainNeck, - MainShoulders, - MainArms, - MainBack, - MainWrist1, - MainWrist2, - MainRange, - MainHands, - MainPrimary, - MainSecondary, - MainFinger1, - MainFinger2, - MainChest, - MainLegs, - MainFeet, - MainWaist, - MainPowerSource = 9999, // temp - MainAmmo = 21, // temp - MainGeneral1, - MainGeneral2, - MainGeneral3, - MainGeneral4, - MainGeneral5, - MainGeneral6, - MainGeneral7, - MainGeneral8, - //MainGeneral9, - //MainGeneral10, - MainCursor, - _MainCount -}; - #define INVALID_INDEX -1 -#define NOT_USED 0 #define NO_ITEM 0 // yes..these are redundant... but, they help to identify and define what is actually being performed // plus, since they're pre-op's, they don't affect the actual binary size -#define MAP_BEGIN 0 -#define MAIN_BEGIN 0 -#define SUB_BEGIN 0 -#define AUG_BEGIN 0 - -namespace legacy { - // this is for perl and other legacy systems - - typedef enum { - SLOT_CHARM = 0, - SLOT_EAR01 = 1, - SLOT_HEAD = 2, - SLOT_FACE = 3, - SLOT_EAR02 = 4, - SLOT_NECK = 5, - SLOT_SHOULDER = 6, - SLOT_ARMS = 7, - SLOT_BACK = 8, - SLOT_BRACER01 = 9, - SLOT_BRACER02 = 10, - SLOT_RANGE = 11, - SLOT_HANDS = 12, - SLOT_PRIMARY = 13, - SLOT_SECONDARY = 14, - SLOT_RING01 = 15, - SLOT_RING02 = 16, - SLOT_CHEST = 17, - SLOT_LEGS = 18, - SLOT_FEET = 19, - SLOT_WAIST = 20, - SLOT_POWER_SOURCE = 9999, - SLOT_AMMO = 21, - SLOT_GENERAL_1 = 22, - SLOT_GENERAL_2 = 23, - SLOT_GENERAL_3 = 24, - SLOT_GENERAL_4 = 25, - SLOT_GENERAL_5 = 26, - SLOT_GENERAL_6 = 27, - SLOT_GENERAL_7 = 28, - SLOT_GENERAL_8 = 29, - //SLOT_GENERAL_9 = not supported - //SLOT_GENERAL_10 = not supported - SLOT_CURSOR = 30, - SLOT_CURSOR_END = (int16)0xFFFE, // I hope no one is using this... - SLOT_TRADESKILL = 1000, - SLOT_AUGMENT = 1001, - SLOT_INVALID = (int16)0xFFFF, - - SLOT_POSSESSIONS_BEGIN = 0, - SLOT_POSSESSIONS_END = 30, - - SLOT_EQUIPMENT_BEGIN = 0, - SLOT_EQUIPMENT_END = 21, - - SLOT_PERSONAL_BEGIN = 22, - SLOT_PERSONAL_END = 29, - SLOT_PERSONAL_BAGS_BEGIN = 251, - SLOT_PERSONAL_BAGS_END = 330, - - SLOT_CURSOR_BAG_BEGIN = 331, - SLOT_CURSOR_BAG_END = 340, - - SLOT_TRIBUTE_BEGIN = 400, - SLOT_TRIBUTE_END = 404, - - SLOT_BANK_BEGIN = 2000, - SLOT_BANK_END = 2023, - SLOT_BANK_BAGS_BEGIN = 2031, - SLOT_BANK_BAGS_END = 2270, - - SLOT_SHARED_BANK_BEGIN = 2500, - SLOT_SHARED_BANK_END = 2501, - SLOT_SHARED_BANK_BAGS_BEGIN = 2531, - SLOT_SHARED_BANK_BAGS_END = 2550, - - SLOT_TRADE_BEGIN = 3000, - SLOT_TRADE_END = 3007, - SLOT_TRADE_BAGS_BEGIN = 3031, - SLOT_TRADE_BAGS_END = 3110, - - SLOT_WORLD_BEGIN = 4000, - SLOT_WORLD_END = 4009 - } InventorySlot; -} +#define TYPE_BEGIN 0 +#define SLOT_BEGIN 0 +#define SUB_INDEX_BEGIN 0 +#define AUG_INDEX_BEGIN 0 static const uint32 MAX_SPELL_DB_ID_VAL = 65535; -#endif +#endif /*COMMON_EQ_CONSTANTS_H*/ diff --git a/common/eq_dictionary.cpp b/common/eq_dictionary.cpp deleted file mode 100644 index 9bc602aa1..000000000 --- a/common/eq_dictionary.cpp +++ /dev/null @@ -1,943 +0,0 @@ -/* -EQEMu: Everquest Server Emulator - -Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY except by those people which sell it, which -are required to give you total support for your newly bought product; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#include "eq_dictionary.h" -#include "string_util.h" - -// -// class EmuConstants -// -uint16 EmuConstants::InventoryMapSize(int16 indexMap) -{ - switch (indexMap) - { - case MapPossessions: - return MAP_POSSESSIONS_SIZE; - case MapBank: - return MAP_BANK_SIZE; - case MapSharedBank: - return MAP_SHARED_BANK_SIZE; - case MapTrade: - return MAP_TRADE_SIZE; - case MapWorld: - return MAP_WORLD_SIZE; - case MapLimbo: - return MAP_LIMBO_SIZE; - case MapTribute: - return MAP_TRIBUTE_SIZE; - case MapTrophyTribute: - return MAP_TROPHY_TRIBUTE_SIZE; - case MapGuildTribute: - return MAP_GUILD_TRIBUTE_SIZE; - case MapMerchant: - return MAP_MERCHANT_SIZE; - case MapDeleted: - return MAP_DELETED_SIZE; - case MapCorpse: - return MAP_CORPSE_SIZE; - case MapBazaar: - return MAP_BAZAAR_SIZE; - case MapInspect: - return MAP_INSPECT_SIZE; - case MapRealEstate: - return MAP_REAL_ESTATE_SIZE; - case MapViewMODPC: - return MAP_VIEW_MOD_PC_SIZE; - case MapViewMODBank: - return MAP_VIEW_MOD_BANK_SIZE; - case MapViewMODSharedBank: - return MAP_VIEW_MOD_SHARED_BANK_SIZE; - case MapViewMODLimbo: - return MAP_VIEW_MOD_LIMBO_SIZE; - case MapAltStorage: - return MAP_ALT_STORAGE_SIZE; - case MapArchived: - return MAP_ARCHIVED_SIZE; - case MapMail: - return MAP_MAIL_SIZE; - case MapGuildTrophyTribute: - return MAP_GUILD_TROPHY_TRIBUTE_SIZE; - case MapKrono: - return MAP_KRONO_SIZE; - case MapOther: - return MAP_OTHER_SIZE; - default: - return NOT_USED; - } -} - -/* -std::string EmuConstants::InventoryLocationName(Location_Struct location) -{ - // not ready for implementation... - std::string ret_str; - StringFormat(ret_str, "%s, %s, %s, %s", InventoryMapName(location.map), InventoryMainName(location.main), InventorySubName(location.sub), InventoryAugName(location.aug)); - return ret_str; -} -*/ - -std::string EmuConstants::InventoryMapName(int16 indexMap) -{ - switch (indexMap) - { - case INVALID_INDEX: - return "Invalid Map"; - case MapPossessions: - return "Possessions"; - case MapBank: - return "Bank"; - case MapSharedBank: - return "SharedBank"; - case MapTrade: - return "Trade"; - case MapWorld: - return "World"; - case MapLimbo: - return "Limbo"; - case MapTribute: - return "Tribute"; - case MapTrophyTribute: - return "TrophyTribute"; - case MapGuildTribute: - return "GuildTribute"; - case MapMerchant: - return "Merchant"; - case MapDeleted: - return "Deleted"; - case MapCorpse: - return "Corpse"; - case MapBazaar: - return "Bazaar"; - case MapInspect: - return "Inspect"; - case MapRealEstate: - return "RealEstate"; - case MapViewMODPC: - return "ViewMODPC"; - case MapViewMODBank: - return "ViewMODBank"; - case MapViewMODSharedBank: - return "ViewMODSharedBank"; - case MapViewMODLimbo: - return "ViewMODLimbo"; - case MapAltStorage: - return "AltStorage"; - case MapArchived: - return "Archived"; - case MapMail: - return "Mail"; - case MapGuildTrophyTribute: - return "GuildTrophyTribute"; - case MapKrono: - return "Krono"; - case MapOther: - return "Other"; - default: - return "Unknown Map"; - } -} - -std::string EmuConstants::InventoryMainName(int16 indexMain) -{ - switch (indexMain) - { - case INVALID_INDEX: - return "Invalid Main"; - case MainCharm: - return "Charm"; - case MainEar1: - return "Ear1"; - case MainHead: - return "Head"; - case MainFace: - return "Face"; - case MainEar2: - return "Ear2"; - case MainNeck: - return "Neck"; - case MainShoulders: - return "Shoulders"; - case MainArms: - return "Arms"; - case MainBack: - return "Back"; - case MainWrist1: - return "Wrist1"; - case MainWrist2: - return "Wrist2"; - case MainRange: - return "Range"; - case MainHands: - return "Hands"; - case MainPrimary: - return "Primary"; - case MainSecondary: - return "Secondary"; - case MainFinger1: - return "Finger1"; - case MainFinger2: - return "Finger2"; - case MainChest: - return "Chest"; - case MainLegs: - return "Legs"; - case MainFeet: - return "Feet"; - case MainWaist: - return "Waist"; - case MainPowerSource: - return "PowerSource"; - case MainAmmo: - return "Ammo"; - case MainGeneral1: - return "General1"; - case MainGeneral2: - return "General2"; - case MainGeneral3: - return "General3"; - case MainGeneral4: - return "General4"; - case MainGeneral5: - return "General5"; - case MainGeneral6: - return "General6"; - case MainGeneral7: - return "General7"; - case MainGeneral8: - return "General8"; - /* - case MainGeneral9: - return "General9"; - case MainGeneral10: - return "General10"; - */ - case MainCursor: - return "Cursor"; - default: - return "Unknown Main"; - } -} - -std::string EmuConstants::InventorySubName(int16 indexSub) -{ - if (indexSub == INVALID_INDEX) - return "Invalid Sub"; - - if ((uint16)indexSub >= ITEM_CONTAINER_SIZE) - return "Unknown Sub"; - - std::string ret_str; - ret_str = StringFormat("Container%i", (indexSub + 1)); // zero-based index..but, count starts at one - - return ret_str; -} - -std::string EmuConstants::InventoryAugName(int16 indexAug) -{ - if (indexAug == INVALID_INDEX) - return "Invalid Aug"; - - if ((uint16)indexAug >= ITEM_COMMON_SIZE) - return "Unknown Aug"; - - std::string ret_str; - ret_str = StringFormat("Augment%i", (indexAug + 1)); // zero-based index..but, count starts at one - - return ret_str; -} - - -// -// class EQLimits -// -// client validation -bool EQLimits::IsValidPCClientVersion(ClientVersion clientVersion) -{ - if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_PC_CLIENT) - return true; - - return false; -} - -ClientVersion EQLimits::ValidatePCClientVersion(ClientVersion clientVersion) -{ - if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_PC_CLIENT) - return clientVersion; - - return ClientVersion::Unknown; -} - -// npc validation -bool EQLimits::IsValidNPCClientVersion(ClientVersion clientVersion) -{ - if (clientVersion > LAST_PC_CLIENT && clientVersion <= LAST_NPC_CLIENT) - return true; - - return false; -} - -ClientVersion EQLimits::ValidateNPCClientVersion(ClientVersion clientVersion) -{ - if (clientVersion > LAST_PC_CLIENT && clientVersion <= LAST_NPC_CLIENT) - return clientVersion; - - return ClientVersion::Unknown; -} - -// mob validation -bool EQLimits::IsValidMobClientVersion(ClientVersion clientVersion) -{ - if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_NPC_CLIENT) - return true; - - return false; -} - -ClientVersion EQLimits::ValidateMobClientVersion(ClientVersion clientVersion) -{ - if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_NPC_CLIENT) - return clientVersion; - - return ClientVersion::Unknown; -} - -// database -size_t EQLimits::CharacterCreationLimit(ClientVersion clientVersion) -{ - static const size_t local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*Client62*/ NOT_USED, -/*Titanium*/ Titanium::consts::CHARACTER_CREATION_LIMIT, -/*SoF*/ SoF::consts::CHARACTER_CREATION_LIMIT, -/*SoD*/ SoD::consts::CHARACTER_CREATION_LIMIT, -/*UF*/ UF::consts::CHARACTER_CREATION_LIMIT, -/*RoF*/ RoF::consts::CHARACTER_CREATION_LIMIT, -/*RoF2*/ RoF2::consts::CHARACTER_CREATION_LIMIT, - -/*MobNPC*/ NOT_USED, -/*MobMerc*/ NOT_USED, -/*MobBot*/ NOT_USED, -/*MobPet*/ NOT_USED - }; - - return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -// inventory -uint16 EQLimits::InventoryMapSize(int16 indexMap, ClientVersion clientVersion) -{ - // not all maps will have an instantiated container..some are references for queue generators (i.e., bazaar, mail, etc...) - // a zero '0' indicates a needed value..otherwise, change to '_NOTUSED' for a null value so indices requiring research can be identified - // ALL of these values need to be verified before pushing to live - // - // make sure that you transcribe the actual value from 'defaults' to here before updating or client crashes will ensue..and/or... - // insert older clients inside of the progression of client order - // - // MAP_POSSESSIONS_SIZE does not reflect all actual _constants size due to bitmask-use compatibility - // - // when setting NPC-based values, try to adhere to an EmuConstants:: or NOT_USED value to avoid unnecessary issues - - static const uint16 local[_MapCount][CLIENT_VERSION_COUNT] = { - // server and database are sync'd to current MapPossessions's client as set in 'using namespace RoF::slots;' and - // 'EmuConstants::MAP_POSSESSIONS_SIZE' - use/update EquipmentBitmask(), GeneralBitmask() and CursorBitmask() - // for partial range validation checks and 'EmuConstants::MAP_POSSESSIONS_SIZE' for full range iterations - { // local[MainPossessions] -/*Unknown*/ NOT_USED, -/*62*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*Titanium*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*SoF*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*SoD*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*Underfoot*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*RoF*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*RoF2*/ EmuConstants::MAP_POSSESSIONS_SIZE, - -/*NPC*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*Merc*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*Bot*/ EmuConstants::MAP_POSSESSIONS_SIZE, -/*Pet*/ EmuConstants::MAP_POSSESSIONS_SIZE - }, - { // local[MapBank] -/*Unknown*/ NOT_USED, -/*62*/ NOT_USED, -/*Titanium*/ Titanium::consts::MAP_BANK_SIZE, -/*SoF*/ EmuConstants::MAP_BANK_SIZE, -/*SoD*/ EmuConstants::MAP_BANK_SIZE, -/*Underfoot*/ EmuConstants::MAP_BANK_SIZE, -/*RoF*/ EmuConstants::MAP_BANK_SIZE, -/*RoF2*/ EmuConstants::MAP_BANK_SIZE, - -/*NPC*/ NOT_USED, -/*Merc*/ NOT_USED, -/*Bot*/ NOT_USED, -/*Pet*/ NOT_USED - }, - { // local[MapSharedBank] -/*Unknown*/ NOT_USED, -/*62*/ EmuConstants::MAP_SHARED_BANK_SIZE, -/*Titanium*/ EmuConstants::MAP_SHARED_BANK_SIZE, -/*SoF*/ EmuConstants::MAP_SHARED_BANK_SIZE, -/*SoD*/ EmuConstants::MAP_SHARED_BANK_SIZE, -/*Underfoot*/ EmuConstants::MAP_SHARED_BANK_SIZE, -/*RoF*/ EmuConstants::MAP_SHARED_BANK_SIZE, -/*RoF2*/ EmuConstants::MAP_SHARED_BANK_SIZE, - -/*NPC*/ NOT_USED, -/*Merc*/ NOT_USED, -/*Bot*/ NOT_USED, -/*Pet*/ NOT_USED - }, - { // local[MapTrade] -/*Unknown*/ NOT_USED, -/*62*/ EmuConstants::MAP_TRADE_SIZE, -/*Titanium*/ EmuConstants::MAP_TRADE_SIZE, -/*SoF*/ EmuConstants::MAP_TRADE_SIZE, -/*SoD*/ EmuConstants::MAP_TRADE_SIZE, -/*Underfoot*/ EmuConstants::MAP_TRADE_SIZE, -/*RoF*/ EmuConstants::MAP_TRADE_SIZE, -/*RoF2*/ EmuConstants::MAP_TRADE_SIZE, - -/*NPC*/ 4, -/*Merc*/ 4, -/*Bot*/ EmuConstants::MAP_TRADE_SIZE, // client thinks this is another client -/*Pet*/ 4 - }, - { // local[MapWorld] -/*Unknown*/ NOT_USED, -/*62*/ EmuConstants::MAP_WORLD_SIZE, -/*Titanium*/ EmuConstants::MAP_WORLD_SIZE, -/*SoF*/ EmuConstants::MAP_WORLD_SIZE, -/*SoD*/ EmuConstants::MAP_WORLD_SIZE, -/*Underfoot*/ EmuConstants::MAP_WORLD_SIZE, -/*RoF*/ EmuConstants::MAP_WORLD_SIZE, -/*RoF2*/ EmuConstants::MAP_WORLD_SIZE, - -/*NPC*/ NOT_USED, -/*Merc*/ NOT_USED, -/*Bot*/ NOT_USED, -/*Pet*/ NOT_USED - }, - { // local[MapLimbo] -/*Unknown*/ NOT_USED, -/*62*/ EmuConstants::MAP_LIMBO_SIZE, -/*Titanium*/ EmuConstants::MAP_LIMBO_SIZE, -/*SoF*/ EmuConstants::MAP_LIMBO_SIZE, -/*SoD*/ EmuConstants::MAP_LIMBO_SIZE, -/*Underfoot*/ EmuConstants::MAP_LIMBO_SIZE, -/*RoF*/ EmuConstants::MAP_LIMBO_SIZE, -/*RoF2*/ EmuConstants::MAP_LIMBO_SIZE, - -/*NPC*/ NOT_USED, -/*Merc*/ NOT_USED, -/*Bot*/ NOT_USED, -/*Pet*/ NOT_USED - }, - { // local[MapTribute] -/*Unknown*/ NOT_USED, -/*62*/ EmuConstants::MAP_TRIBUTE_SIZE, -/*Titanium*/ EmuConstants::MAP_TRIBUTE_SIZE, -/*SoF*/ EmuConstants::MAP_TRIBUTE_SIZE, -/*SoD*/ EmuConstants::MAP_TRIBUTE_SIZE, -/*Underfoot*/ EmuConstants::MAP_TRIBUTE_SIZE, -/*RoF*/ EmuConstants::MAP_TRIBUTE_SIZE, -/*RoF2*/ EmuConstants::MAP_TRIBUTE_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapTrophyTribute] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_TROPHY_TRIBUTE_SIZE, -/*RoF2*/ EmuConstants::MAP_TROPHY_TRIBUTE_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapGuildTribute] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_GUILD_TRIBUTE_SIZE, -/*RoF2*/ EmuConstants::MAP_GUILD_TRIBUTE_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapMerchant] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_MERCHANT_SIZE, -/*RoF2*/ EmuConstants::MAP_MERCHANT_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapDeleted] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_DELETED_SIZE, -/*RoF2*/ EmuConstants::MAP_DELETED_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapCorpse] -/*Unknown*/ NOT_USED, -/*62*/ NOT_USED, -/*Titanium*/ Titanium::consts::MAP_CORPSE_SIZE, -/*SoF*/ SoF::consts::MAP_CORPSE_SIZE, -/*SoD*/ SoD::consts::MAP_CORPSE_SIZE, -/*Underfoot*/ UF::consts::MAP_CORPSE_SIZE, -/*RoF*/ RoF::consts::MAP_CORPSE_SIZE, -/*RoF2*/ RoF2::consts::MAP_CORPSE_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapBazaar] -/*Unknown*/ NOT_USED, -/*62*/ EmuConstants::MAP_BAZAAR_SIZE, -/*Titanium*/ EmuConstants::MAP_BAZAAR_SIZE, -/*SoF*/ EmuConstants::MAP_BAZAAR_SIZE, -/*SoD*/ EmuConstants::MAP_BAZAAR_SIZE, -/*Underfoot*/ EmuConstants::MAP_BAZAAR_SIZE, -/*RoF*/ EmuConstants::MAP_BAZAAR_SIZE, -/*RoF2*/ EmuConstants::MAP_BAZAAR_SIZE, - -/*NPC*/ 0, // this may need to be 'EmuConstants::MAP_BAZAAR_SIZE' if offline client traders respawn as an npc -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapInspect] -/*Unknown*/ NOT_USED, -/*62*/ NOT_USED, -/*Titanium*/ Titanium::consts::MAP_INSPECT_SIZE, -/*SoF*/ SoF::consts::MAP_INSPECT_SIZE, -/*SoD*/ SoD::consts::MAP_INSPECT_SIZE, -/*Underfoot*/ UF::consts::MAP_INSPECT_SIZE, -/*RoF*/ RoF::consts::MAP_INSPECT_SIZE, -/*RoF2*/ RoF2::consts::MAP_INSPECT_SIZE, - -/*NPC*/ NOT_USED, -/*Merc*/ NOT_USED, -/*Bot*/ NOT_USED, -/*Pet*/ NOT_USED - }, - { // local[MapRealEstate] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_REAL_ESTATE_SIZE, -/*RoF2*/ EmuConstants::MAP_REAL_ESTATE_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapViewMODPC] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_VIEW_MOD_PC_SIZE, -/*RoF2*/ EmuConstants::MAP_VIEW_MOD_PC_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapViewMODBank] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_VIEW_MOD_BANK_SIZE, -/*RoF2*/ EmuConstants::MAP_VIEW_MOD_BANK_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapViewMODSharedBank] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_VIEW_MOD_SHARED_BANK_SIZE, -/*RoF2*/ EmuConstants::MAP_VIEW_MOD_SHARED_BANK_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapViewMODLimbo] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_VIEW_MOD_LIMBO_SIZE, -/*RoF2*/ EmuConstants::MAP_VIEW_MOD_LIMBO_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapAltStorage] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_ALT_STORAGE_SIZE, -/*RoF2*/ EmuConstants::MAP_ALT_STORAGE_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapArchived] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_ARCHIVED_SIZE, -/*RoF2*/ EmuConstants::MAP_ARCHIVED_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapMail] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_MAIL_SIZE, -/*RoF2*/ EmuConstants::MAP_MAIL_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapGuildTrophyTribute] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_GUILD_TROPHY_TRIBUTE_SIZE, -/*RoF2*/ EmuConstants::MAP_GUILD_TROPHY_TRIBUTE_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapKrono] -/*Unknown*/ NOT_USED, -/*62*/ NOT_USED, -/*Titanium*/ NOT_USED, -/*SoF*/ NOT_USED, -/*SoD*/ NOT_USED, -/*Underfoot*/ NOT_USED, -/*RoF*/ EmuConstants::MAP_KRONO_SIZE, -/*RoF2*/ EmuConstants::MAP_KRONO_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }, - { // local[MapOther] -/*Unknown*/ NOT_USED, -/*62*/ 0, -/*Titanium*/ 0, -/*SoF*/ 0, -/*SoD*/ 0, -/*Underfoot*/ 0, -/*RoF*/ EmuConstants::MAP_OTHER_SIZE, -/*RoF2*/ EmuConstants::MAP_OTHER_SIZE, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - } - }; - - if ((uint16)indexMap < _MapCount) - return local[indexMap][static_cast(ValidateMobClientVersion(clientVersion))]; - - return NOT_USED; -} - -uint64 EQLimits::PossessionsBitmask(ClientVersion clientVersion) -{ - // these are for the new inventory system (RoF)..not the current (Ti) one... - // 0x0000000000200000 is SlotPowerSource (SoF+) - // 0x0000000080000000 is SlotGeneral9 (RoF+) - // 0x0000000100000000 is SlotGeneral10 (RoF+) - - static const uint64 local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*62*/ 0x000000027FDFFFFF, -/*Titanium*/ 0x000000027FDFFFFF, -/*SoF*/ 0x000000027FFFFFFF, -/*SoD*/ 0x000000027FFFFFFF, -/*Underfoot*/ 0x000000027FFFFFFF, -/*RoF*/ 0x00000003FFFFFFFF, -/*RoF2*/ 0, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }; - - return NOT_USED; - //return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -uint64 EQLimits::EquipmentBitmask(ClientVersion clientVersion) -{ - static const uint64 local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*62*/ 0x00000000005FFFFF, -/*Titanium*/ 0x00000000005FFFFF, -/*SoF*/ 0x00000000007FFFFF, -/*SoD*/ 0x00000000007FFFFF, -/*Underfoot*/ 0x00000000007FFFFF, -/*RoF*/ 0x00000000007FFFFF, -/*RoF2*/ 0, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }; - - return NOT_USED; - //return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -uint64 EQLimits::GeneralBitmask(ClientVersion clientVersion) -{ - static const uint64 local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*62*/ 0x000000007F800000, -/*Titanium*/ 0x000000007F800000, -/*SoF*/ 0x000000007F800000, -/*SoD*/ 0x000000007F800000, -/*Underfoot*/ 0x000000007F800000, -/*RoF*/ 0x00000001FF800000, -/*RoF2*/ 0, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }; - - return NOT_USED; - //return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -uint64 EQLimits::CursorBitmask(ClientVersion clientVersion) -{ - static const uint64 local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*62*/ 0x0000000200000000, -/*Titanium*/ 0x0000000200000000, -/*SoF*/ 0x0000000200000000, -/*SoD*/ 0x0000000200000000, -/*Underfoot*/ 0x0000000200000000, -/*RoF*/ 0x0000000200000000, -/*RoF2*/ 0, - -/*NPC*/ 0, -/*Merc*/ 0, -/*Bot*/ 0, -/*Pet*/ 0 - }; - - return NOT_USED; - //return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -bool EQLimits::AllowsEmptyBagInBag(ClientVersion clientVersion) -{ - static const bool local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ false, -/*62*/ false, -/*Titanium*/ Titanium::limits::ALLOWS_EMPTY_BAG_IN_BAG, -/*SoF*/ SoF::limits::ALLOWS_EMPTY_BAG_IN_BAG, -/*SoD*/ SoD::limits::ALLOWS_EMPTY_BAG_IN_BAG, -/*Underfoot*/ UF::limits::ALLOWS_EMPTY_BAG_IN_BAG, -/*RoF*/ RoF::limits::ALLOWS_EMPTY_BAG_IN_BAG, -/*RoF2*/ RoF2::limits::ALLOWS_EMPTY_BAG_IN_BAG, - -/*NPC*/ false, -/*Merc*/ false, -/*Bot*/ false, -/*Pet*/ false - }; - - return false; // not implemented - //return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -bool EQLimits::AllowsClickCastFromBag(ClientVersion clientVersion) -{ - static const bool local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ false, -/*62*/ false, -/*Titanium*/ Titanium::limits::ALLOWS_CLICK_CAST_FROM_BAG, -/*SoF*/ SoF::limits::ALLOWS_CLICK_CAST_FROM_BAG, -/*SoD*/ SoD::limits::ALLOWS_CLICK_CAST_FROM_BAG, -/*Underfoot*/ UF::limits::ALLOWS_CLICK_CAST_FROM_BAG, -/*RoF*/ RoF::limits::ALLOWS_CLICK_CAST_FROM_BAG, -/*RoF2*/ RoF2::limits::ALLOWS_CLICK_CAST_FROM_BAG, - -/*NPC*/ false, -/*Merc*/ false, -/*Bot*/ false, -/*Pet*/ false - }; - - return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -// items -uint16 EQLimits::ItemCommonSize(ClientVersion clientVersion) -{ - static const uint16 local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*62*/ EmuConstants::ITEM_COMMON_SIZE, -/*Titanium*/ EmuConstants::ITEM_COMMON_SIZE, -/*SoF*/ EmuConstants::ITEM_COMMON_SIZE, -/*SoD*/ EmuConstants::ITEM_COMMON_SIZE, -/*Underfoot*/ EmuConstants::ITEM_COMMON_SIZE, -/*RoF*/ EmuConstants::ITEM_COMMON_SIZE, -/*RoF2*/ EmuConstants::ITEM_COMMON_SIZE, - -/*NPC*/ EmuConstants::ITEM_COMMON_SIZE, -/*Merc*/ EmuConstants::ITEM_COMMON_SIZE, -/*Bot*/ EmuConstants::ITEM_COMMON_SIZE, -/*Pet*/ EmuConstants::ITEM_COMMON_SIZE - }; - - return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -uint16 EQLimits::ItemContainerSize(ClientVersion clientVersion) -{ - static const uint16 local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*62*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*Titanium*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*SoF*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*SoD*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*Underfoot*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*RoF*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*RoF2*/ EmuConstants::ITEM_CONTAINER_SIZE, - -/*NPC*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*Merc*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*Bot*/ EmuConstants::ITEM_CONTAINER_SIZE, -/*Pet*/ EmuConstants::ITEM_CONTAINER_SIZE - }; - - return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -bool EQLimits::CoinHasWeight(ClientVersion clientVersion) -{ - static const bool local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ true, -/*62*/ true, -/*Titanium*/ Titanium::limits::COIN_HAS_WEIGHT, -/*SoF*/ SoF::limits::COIN_HAS_WEIGHT, -/*SoD*/ SoD::limits::COIN_HAS_WEIGHT, -/*Underfoot*/ UF::limits::COIN_HAS_WEIGHT, -/*RoF*/ RoF::limits::COIN_HAS_WEIGHT, -/*RoF2*/ RoF::limits::COIN_HAS_WEIGHT, - -/*NPC*/ true, -/*Merc*/ true, -/*Bot*/ true, -/*Pet*/ true - }; - - return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} diff --git a/common/eq_dictionary.h b/common/eq_dictionary.h deleted file mode 100644 index 7828dd5cc..000000000 --- a/common/eq_dictionary.h +++ /dev/null @@ -1,205 +0,0 @@ -/* -EQEMu: Everquest Server Emulator - -Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY except by those people which sell it, which -are required to give you total support for your newly bought product; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef EQ_DICTIONARY_H -#define EQ_DICTIONARY_H - -#include "types.h" -#include "eq_constants.h" -#include "clientversions.h" -#include -#include "../common/patches/titanium_constants.h" -#include "../common/patches/sof_constants.h" -#include "../common/patches/sod_constants.h" -#include "../common/patches/uf_constants.h" -#include "../common/patches/rof_constants.h" -#include "../common/patches/rof2_constants.h" - -// *** DO NOT CHANGE without a full understanding of the consequences..the server is set up to use these settings explicitly!! *** -// *** You will cause compilation failures and corrupt your database if partial or incorrect attempts to change them are made!! *** - -// Hard-coded values usually indicate that further research is needed and the values given are from the old (known) system - -// (future use) -//using namespace RoF2::maps; // server inventory maps enumeration (code and database sync'd to reference) -//using namespace RoF::slots; // server possessions slots enumeration (code and database sync'd to reference) - -class EmuConstants -{ - // an immutable value is required to initialize arrays, etc... use this class as a repository for those -public: - // database - static const ClientVersion CHARACTER_CREATION_CLIENT = ClientVersion::RoF2; // adjust according to starting item placement and target client - - static const size_t CHARACTER_CREATION_LIMIT = RoF2::consts::CHARACTER_CREATION_LIMIT; - - // inventory - static uint16 InventoryMapSize(int16 indexMap); - //static std::string InventoryLocationName(Location_Struct location); - static std::string InventoryMapName(int16 indexMap); - static std::string InventoryMainName(int16 indexMain); - static std::string InventorySubName(int16 indexSub); - static std::string InventoryAugName(int16 indexAug); - - // these are currently hard-coded for existing inventory system..do not use in place of special client version handlers until ready - static const uint16 MAP_POSSESSIONS_SIZE = _MainCount; - static const uint16 MAP_BANK_SIZE = 24; - static const uint16 MAP_SHARED_BANK_SIZE = 2; - static const uint16 MAP_TRADE_SIZE = 8; - static const uint16 MAP_WORLD_SIZE = 10; - static const uint16 MAP_LIMBO_SIZE = 36; - static const uint16 MAP_TRIBUTE_SIZE = 5; // (need client values) - static const uint16 MAP_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_GUILD_TRIBUTE_SIZE = 0; - static const uint16 MAP_MERCHANT_SIZE = 0; - static const uint16 MAP_DELETED_SIZE = 0; - static const uint16 MAP_CORPSE_SIZE = _MainCount; // no bitmask use..limits to size of client corpse window (see EQLimits::InventoryMapSize(MapCorpse, (versions::ValidateClientVersion(client_version))]; +} + +static const EQEmu::inventory::LookupEntry inventory_lookup_entries[EQEmu::versions::InventoryVersionCount] = +{ + { // Unknown + ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, + ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, + ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, + ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, + ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, + + ClientUnknown::Null, ClientUnknown::Null, ClientUnknown::Null, + + ClientUnknown::False, ClientUnknown::False, ClientUnknown::False, ClientUnknown::False + }, + { // Client62 + Client62::Null, Client62::Null, Client62::Null, Client62::Null, Client62::Null, + Client62::Null, Client62::Null, Client62::Null, Client62::Null, Client62::Null, + Client62::Null, Client62::Null, Client62::Null, Client62::Null, Client62::Null, + Client62::Null, Client62::Null, Client62::Null, Client62::Null, Client62::Null, + Client62::Null, Client62::Null, Client62::Null, Client62::Null, Client62::Null, + + Client62::Null, Client62::Null, Client62::Null, + + Client62::False, Client62::False, Client62::False, Client62::False + }, + { // Titanium + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*Titanium::invtype::InvTypePossessionsSize,*/ Titanium::invtype::InvTypeBankSize, Titanium::invtype::InvTypeSharedBankSize, Titanium::invtype::InvTypeTradeSize, Titanium::invtype::InvTypeWorldSize, + Titanium::invtype::InvTypeLimboSize, Titanium::invtype::InvTypeTributeSize, Titanium::Null, Titanium::Null, /*Titanium::invtype::InvTypeGuildTributeSize,*/ Titanium::invtype::InvTypeMerchantSize, + Titanium::Null, Titanium::invtype::InvTypeCorpseSize, EQEmu::legacy::TYPE_BAZAAR_SIZE, /*Titanium::invtype::InvTypeBazaarSize,*/ Titanium::invtype::InvTypeInspectSize, Titanium::Null, + Titanium::invtype::InvTypeViewMODPCSize, Titanium::invtype::InvTypeViewMODBankSize, Titanium::invtype::InvTypeViewMODSharedBankSize, Titanium::invtype::InvTypeViewMODLimboSize, Titanium::invtype::InvTypeAltStorageSize, + Titanium::invtype::InvTypeArchivedSize, Titanium::Null, Titanium::Null, Titanium::Null, Titanium::invtype::InvTypeOtherSize, + + Titanium::Null, /*0x000000027FDFFFFF,*/ EQEmu::legacy::ITEM_CONTAINER_SIZE, /*Titanium::invbag::ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*Titanium::invaug::ItemAugSize,*/ + + Titanium::inventory::AllowEmptyBagInBag, Titanium::inventory::AllowClickCastFromBag, Titanium::inventory::ConcatenateInvTypeLimbo, Titanium::inventory::AllowOverLevelEquipment + }, + { // SoF + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*SoF::invtype::InvTypePossessionsSize,*/ SoF::invtype::InvTypeBankSize, SoF::invtype::InvTypeSharedBankSize, SoF::invtype::InvTypeTradeSize, SoF::invtype::InvTypeWorldSize, + SoF::invtype::InvTypeLimboSize, SoF::invtype::InvTypeTributeSize, SoF::Null, SoF::Null, /*SoF::invtype::InvTypeGuildTributeSize,*/ SoF::invtype::InvTypeMerchantSize, + SoF::Null, SoF::invtype::InvTypeCorpseSize, EQEmu::legacy::TYPE_BAZAAR_SIZE, /*SoF::invtype::InvTypeBazaarSize,*/ SoF::invtype::InvTypeInspectSize, SoF::Null, + SoF::invtype::InvTypeViewMODPCSize, SoF::invtype::InvTypeViewMODBankSize, SoF::invtype::InvTypeViewMODSharedBankSize, SoF::invtype::InvTypeViewMODLimboSize, SoF::invtype::InvTypeAltStorageSize, + SoF::invtype::InvTypeArchivedSize, SoF::Null, SoF::Null, SoF::Null, SoF::invtype::InvTypeOtherSize, + + SoF::Null, /*0x000000027FFFFFFF,*/ EQEmu::legacy::ITEM_CONTAINER_SIZE, /*SoF::invbag::ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*SoF::invaug::ItemAugSize,*/ + + SoF::inventory::AllowEmptyBagInBag, SoF::inventory::AllowClickCastFromBag, SoF::inventory::ConcatenateInvTypeLimbo, SoF::inventory::AllowOverLevelEquipment + }, + { // SoD + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*SoD::invtype::InvTypePossessionsSize,*/ SoD::invtype::InvTypeBankSize, SoD::invtype::InvTypeSharedBankSize, SoD::invtype::InvTypeTradeSize, SoD::invtype::InvTypeWorldSize, + SoD::invtype::InvTypeLimboSize, SoD::invtype::InvTypeTributeSize, SoD::Null, SoD::Null, /*SoD::invtype::InvTypeGuildTributeSize,*/ SoD::invtype::InvTypeMerchantSize, + SoD::Null, SoD::invtype::InvTypeCorpseSize, EQEmu::legacy::TYPE_BAZAAR_SIZE, /*SoD::invtype::InvTypeBazaarSize,*/ SoD::invtype::InvTypeInspectSize, SoD::Null, + SoD::invtype::InvTypeViewMODPCSize, SoD::invtype::InvTypeViewMODBankSize, SoD::invtype::InvTypeViewMODSharedBankSize, SoD::invtype::InvTypeViewMODLimboSize, SoD::invtype::InvTypeAltStorageSize, + SoD::invtype::InvTypeArchivedSize, SoD::Null, SoD::Null, SoD::Null, SoD::invtype::InvTypeOtherSize, + + SoD::Null, /*0x000000027FFFFFFF,*/ EQEmu::legacy::ITEM_CONTAINER_SIZE, /*SoD::invbag::ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*SoD::invaug::ItemAugSize,*/ + + SoD::inventory::AllowEmptyBagInBag, SoD::inventory::AllowClickCastFromBag, SoD::inventory::ConcatenateInvTypeLimbo, SoD::inventory::AllowOverLevelEquipment + }, + { // UF + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*UF::invtype::InvTypePossessionsSize,*/ UF::invtype::InvTypeBankSize, UF::invtype::InvTypeSharedBankSize, UF::invtype::InvTypeTradeSize, UF::invtype::InvTypeWorldSize, + UF::invtype::InvTypeLimboSize, UF::invtype::InvTypeTributeSize, UF::Null, UF::Null, /*UF::invtype::InvTypeGuildTributeSize,*/ UF::invtype::InvTypeMerchantSize, + UF::Null, UF::invtype::InvTypeCorpseSize, EQEmu::legacy::TYPE_BAZAAR_SIZE, /*UF::invtype::InvTypeBazaarSize,*/ UF::invtype::InvTypeInspectSize, UF::Null, + UF::invtype::InvTypeViewMODPCSize, UF::invtype::InvTypeViewMODBankSize, UF::invtype::InvTypeViewMODSharedBankSize, UF::invtype::InvTypeViewMODLimboSize, UF::invtype::InvTypeAltStorageSize, + UF::invtype::InvTypeArchivedSize, UF::Null, UF::Null, UF::Null, UF::invtype::InvTypeOtherSize, + + UF::Null, /*0x000000027FFFFFFF,*/ EQEmu::legacy::ITEM_CONTAINER_SIZE, /*UF::invbag::ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*UF::invaug::ItemAugSize,*/ + + UF::inventory::AllowEmptyBagInBag, UF::inventory::AllowClickCastFromBag, UF::inventory::ConcatenateInvTypeLimbo, UF::inventory::AllowOverLevelEquipment + }, + { // RoF + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*RoF::invtype::InvTypePossessionsSize,*/ RoF::invtype::InvTypeBankSize, RoF::invtype::InvTypeSharedBankSize, RoF::invtype::InvTypeTradeSize, RoF::invtype::InvTypeWorldSize, + RoF::invtype::InvTypeLimboSize, RoF::invtype::InvTypeTributeSize, RoF::Null, /*RoF::invtype::InvTypeTrophyTributeSize,*/ RoF::Null, /*RoF::invtype::InvTypeGuildTributeSize,*/ RoF::invtype::InvTypeMerchantSize, + RoF::Null, /*RoF::invtype::InvTypeDeletedSize,*/ RoF::invtype::InvTypeCorpseSize, EQEmu::legacy::TYPE_BAZAAR_SIZE, /*RoF::invtype::InvTypeBazaarSize,*/ RoF::invtype::InvTypeInspectSize, RoF::Null, /*RoF::invtype::InvTypeRealEstateSize,*/ + RoF::invtype::InvTypeViewMODPCSize, RoF::invtype::InvTypeViewMODBankSize, RoF::invtype::InvTypeViewMODSharedBankSize, RoF::invtype::InvTypeViewMODLimboSize, RoF::invtype::InvTypeAltStorageSize, + RoF::invtype::InvTypeArchivedSize, RoF::invtype::InvTypeMailSize, RoF::invtype::InvTypeGuildTrophyTributeSize, RoF::Null, RoF::invtype::InvTypeOtherSize, + + RoF::Null, /*0x00000003FFFFFFFF,*/ EQEmu::legacy::ITEM_CONTAINER_SIZE, /*RoF::invbag::ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*RoF::invaug::ItemAugSize,*/ + + RoF::False, /*RoF::inventory::AllowEmptyBagInBag,*/ RoF::inventory::AllowClickCastFromBag, RoF::inventory::ConcatenateInvTypeLimbo, RoF::inventory::AllowOverLevelEquipment + }, + { // RoF2 + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*RoF2::invtype::InvTypePossessionsSize,*/ RoF2::invtype::InvTypeBankSize, RoF2::invtype::InvTypeSharedBankSize, RoF2::invtype::InvTypeTradeSize, RoF2::invtype::InvTypeWorldSize, + RoF2::invtype::InvTypeLimboSize, RoF2::invtype::InvTypeTributeSize, RoF2::Null, /*RoF2::invtype::InvTypeTrophyTributeSize,*/ RoF2::Null, /*RoF2::invtype::InvTypeGuildTributeSize,*/ RoF2::invtype::InvTypeMerchantSize, + RoF2::Null, /*RoF2::invtype::InvTypeDeletedSize,*/ RoF2::invtype::InvTypeCorpseSize, EQEmu::legacy::TYPE_BAZAAR_SIZE, /*RoF2::invtype::InvTypeBazaarSize,*/ RoF2::invtype::InvTypeInspectSize, RoF2::Null, /*RoF2::invtype::InvTypeRealEstateSize*/ + RoF2::invtype::InvTypeViewMODPCSize, RoF2::invtype::InvTypeViewMODBankSize, RoF2::invtype::InvTypeViewMODSharedBankSize, RoF2::invtype::InvTypeViewMODLimboSize, RoF2::invtype::InvTypeAltStorageSize, + RoF2::invtype::InvTypeArchivedSize, RoF2::invtype::InvTypeMailSize, RoF2::invtype::InvTypeGuildTrophyTributeSize, RoF2::invtype::InvTypeKronoSize, RoF2::invtype::InvTypeOtherSize, + + RoF2::Null, /*0x00000003FFFFFFFF,*/ EQEmu::legacy::ITEM_CONTAINER_SIZE, /*RoF2::invbag::ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*RoF2::invaug::ItemAugSize,*/ + + RoF2::False, /*RoF2::inventory::AllowEmptyBagInBag,*/ RoF2::inventory::AllowClickCastFromBag, RoF2::inventory::ConcatenateInvTypeLimbo, RoF2::inventory::AllowOverLevelEquipment + }, + { // NPC + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*InvTypePossessionsSize,*/ EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::InvTypeTradeSize, EntityLimits::NPC::Null, + EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, + EntityLimits::NPC::Null, EntityLimits::NPC::Null, /*InvTypeCorpseSize,*/ EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, + EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, + EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, EntityLimits::NPC::Null, + + EntityLimits::NPC::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*ItemAugSize,*/ + + EntityLimits::NPC::False, EntityLimits::NPC::False, EntityLimits::NPC::False, EntityLimits::NPC::False + }, + { // NPCMerchant + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*InvTypePossessionsSize,*/ EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::InvTypeTradeSize, EntityLimits::NPCMerchant::Null, + EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, + EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, /*InvTypeCorpseSize,*/ EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, + EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, + EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, EntityLimits::NPCMerchant::Null, + + EntityLimits::NPCMerchant::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*ItemAugSize,*/ + + EntityLimits::NPCMerchant::False, EntityLimits::NPCMerchant::False, EntityLimits::NPCMerchant::False, EntityLimits::NPCMerchant::False + }, + { // Merc + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*InvTypePossessionsSize,*/ EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::InvTypeTradeSize, EntityLimits::Merc::Null, + EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, + EntityLimits::Merc::Null, EntityLimits::Merc::Null, /*InvTypeCorpseSize,*/ EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, + EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, + EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, EntityLimits::Merc::Null, + + EntityLimits::Merc::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*ItemAugSize,*/ + + EntityLimits::Merc::False, EntityLimits::Merc::False, EntityLimits::Merc::False, EntityLimits::Merc::False + }, + { // Bot + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*InvTypePossessionsSize,*/ EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::InvTypeTradeSize, EntityLimits::Bot::Null, + EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, + EntityLimits::Bot::Null, EntityLimits::Bot::Null, /*InvTypeCorpseSize,*/ EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, + EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, + EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, EntityLimits::Bot::Null, + + EntityLimits::Bot::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*ItemAugSize,*/ + + EntityLimits::Bot::False, EntityLimits::Bot::False, EntityLimits::Bot::False, EntityLimits::Bot::False + }, + { // ClientPet + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*InvTypePossessionsSize,*/ EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::InvTypeTradeSize, EntityLimits::ClientPet::Null, + EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, + EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, /*InvTypeCorpseSize,*/ EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, + EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, + EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, EntityLimits::ClientPet::Null, + + EntityLimits::ClientPet::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*ItemAugSize,*/ + + EntityLimits::ClientPet::False, EntityLimits::ClientPet::False, EntityLimits::ClientPet::False, EntityLimits::ClientPet::False + }, + { // NPCPet + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*InvTypePossessionsSize,*/ EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::InvTypeTradeSize, EntityLimits::NPCPet::Null, + EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, + EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, /*InvTypeCorpseSize,*/ EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, + EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, + EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, EntityLimits::NPCPet::Null, + + EntityLimits::NPCPet::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*ItemAugSize,*/ + + EntityLimits::NPCPet::False, EntityLimits::NPCPet::False, EntityLimits::NPCPet::False, EntityLimits::NPCPet::False + }, + { // MercPet + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*InvTypePossessionsSize,*/ EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::InvTypeTradeSize, EntityLimits::MercPet::Null, + EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, + EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, /*InvTypeCorpseSize,*/ EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, + EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, + EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, EntityLimits::MercPet::Null, + + EntityLimits::MercPet::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*ItemAugSize,*/ + + EntityLimits::MercPet::False, EntityLimits::MercPet::False, EntityLimits::MercPet::False, EntityLimits::MercPet::False + }, + { // BotPet + EQEmu::legacy::TYPE_POSSESSIONS_SIZE, /*InvTypePossessionsSize,*/ EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::InvTypeTradeSize, EntityLimits::BotPet::Null, + EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, + EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, /*InvTypeCorpseSize,*/ EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, + EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, + EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, EntityLimits::BotPet::Null, + + EntityLimits::BotPet::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*ItemBagSize,*/ EQEmu::legacy::ITEM_COMMON_SIZE, /*ItemAugSize,*/ + + EntityLimits::BotPet::False, EntityLimits::BotPet::False, EntityLimits::BotPet::False, EntityLimits::BotPet::False + }, + { // OfflineTitanium + Titanium::Null, Titanium::Null, Titanium::Null, Titanium::invtype::InvTypeTradeSize, Titanium::Null, + Titanium::Null, Titanium::Null, Titanium::Null, Titanium::Null, Titanium::invtype::InvTypeMerchantSize, + Titanium::Null, Titanium::Null, Titanium::Null, /*Titanium::invtype::InvTypeBazaarSize,*/ Titanium::invtype::InvTypeInspectSize, Titanium::Null, + Titanium::invtype::InvTypeViewMODPCSize, Titanium::invtype::InvTypeViewMODBankSize, Titanium::invtype::InvTypeViewMODSharedBankSize, Titanium::invtype::InvTypeViewMODLimboSize, Titanium::Null, + Titanium::Null, Titanium::Null, Titanium::Null, Titanium::Null, Titanium::Null, + + Titanium::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*Titanium::Null,*/ Titanium::Null, + + Titanium::False, Titanium::False, Titanium::False, Titanium::False + }, + { // OfflineSoF + SoF::Null, SoF::Null, SoF::Null, SoF::invtype::InvTypeTradeSize, SoF::Null, + SoF::Null, SoF::Null, SoF::Null, SoF::Null, SoF::invtype::InvTypeMerchantSize, + SoF::Null, SoF::Null, SoF::Null, /*SoF::invtype::InvTypeBazaarSize,*/ SoF::invtype::InvTypeInspectSize, SoF::Null, + SoF::invtype::InvTypeViewMODPCSize, SoF::invtype::InvTypeViewMODBankSize, SoF::invtype::InvTypeViewMODSharedBankSize, SoF::invtype::InvTypeViewMODLimboSize, SoF::Null, + SoF::Null, SoF::Null, SoF::Null, SoF::Null, SoF::Null, + + SoF::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*SoF::Null,*/ SoF::Null, + + SoF::False, SoF::False, SoF::False, SoF::False + }, + { // OfflineSoD + SoD::Null, SoD::Null, SoD::Null, SoD::invtype::InvTypeTradeSize, SoD::Null, + SoD::Null, SoD::Null, SoD::Null, SoD::Null, SoD::invtype::InvTypeMerchantSize, + SoD::Null, SoD::Null, SoD::Null, /*SoD::invtype::InvTypeBazaarSize,*/ SoD::invtype::InvTypeInspectSize, SoD::Null, + SoD::invtype::InvTypeViewMODPCSize, SoD::invtype::InvTypeViewMODBankSize, SoD::invtype::InvTypeViewMODSharedBankSize, SoD::invtype::InvTypeViewMODLimboSize, SoD::Null, + SoD::Null, SoD::Null, SoD::Null, SoD::Null, SoD::Null, + + SoD::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*SoD::Null,*/ SoD::Null, + + SoD::False, SoD::False, SoD::False, SoD::False + }, + { // OfflineUF + UF::Null, UF::Null, UF::Null, UF::invtype::InvTypeTradeSize, UF::Null, + UF::Null, UF::Null, UF::Null, UF::Null, UF::invtype::InvTypeMerchantSize, + UF::Null, UF::Null, UF::Null, /*UF::invtype::InvTypeBazaarSize,*/ UF::invtype::InvTypeInspectSize, UF::Null, + UF::invtype::InvTypeViewMODPCSize, UF::invtype::InvTypeViewMODBankSize, UF::invtype::InvTypeViewMODSharedBankSize, UF::invtype::InvTypeViewMODLimboSize, UF::Null, + UF::Null, UF::Null, UF::Null, UF::Null, UF::Null, + + UF::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*UF::Null,*/ UF::Null, + + UF::False, UF::False, UF::False, UF::False + }, + { // OfflineRoF + RoF::Null, RoF::Null, RoF::Null, RoF::invtype::InvTypeTradeSize, RoF::Null, + RoF::Null, RoF::Null, RoF::Null, RoF::Null, RoF::invtype::InvTypeMerchantSize, + RoF::Null, RoF::Null, RoF::Null, /*RoF::invtype::InvTypeBazaarSize,*/ RoF::invtype::InvTypeInspectSize, RoF::Null, + RoF::invtype::InvTypeViewMODPCSize, RoF::invtype::InvTypeViewMODBankSize, RoF::invtype::InvTypeViewMODSharedBankSize, RoF::invtype::InvTypeViewMODLimboSize, RoF::Null, + RoF::Null, RoF::Null, RoF::Null, RoF::Null, RoF::Null, + + RoF::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*RoF::Null,*/ RoF::Null, + + RoF::False, RoF::False, RoF::False, RoF::False + }, + { // OfflineRoF2 + RoF2::Null, RoF2::Null, RoF2::Null, RoF2::invtype::InvTypeTradeSize, RoF2::Null, + RoF2::Null, RoF2::Null, RoF2::Null, RoF2::Null, RoF2::invtype::InvTypeMerchantSize, + RoF2::Null, RoF2::Null, RoF2::Null, /*RoF2::invtype::InvTypeBazaarSize,*/ RoF2::invtype::InvTypeInspectSize, RoF2::Null, + RoF2::invtype::InvTypeViewMODPCSize, RoF2::invtype::InvTypeViewMODBankSize, RoF2::invtype::InvTypeViewMODSharedBankSize, RoF2::invtype::InvTypeViewMODLimboSize, RoF2::Null, + RoF2::Null, RoF2::Null, RoF2::Null, RoF2::Null, RoF2::Null, + + RoF2::Null, EQEmu::legacy::ITEM_CONTAINER_SIZE, /*RoF2::Null,*/ RoF2::Null, + + RoF2::False, RoF2::False, RoF2::False, RoF2::False + } +}; + +const EQEmu::inventory::LookupEntry* EQEmu::inventory::Lookup(versions::InventoryVersion inventory_version) +{ + return &inventory_lookup_entries[static_cast(versions::ValidateInventoryVersion(inventory_version))]; +} + +static const EQEmu::behavior::LookupEntry behavior_lookup_entries[EQEmu::versions::InventoryVersionCount] = +{ + { // Unknown + ClientUnknown::True + }, + { // Client62 + Client62::True + }, + { // Titanium + Titanium::behavior::CoinHasWeight + }, + { // SoF + SoF::behavior::CoinHasWeight + }, + { // SoD + SoD::behavior::CoinHasWeight + }, + { // UF + UF::behavior::CoinHasWeight + }, + { // RoF + RoF::behavior::CoinHasWeight + }, + { // RoF2 + RoF2::behavior::CoinHasWeight + }, + { // NPC + EntityLimits::NPC::True /*CoinHasWeight*/ + }, + { // NPCMerchant + EntityLimits::NPC::True /*CoinHasWeight*/ + }, + { // Merc + EntityLimits::Merc::True /*CoinHasWeight*/ + }, + { // Bot + EntityLimits::Bot::True /*CoinHasWeight*/ + }, + { // ClientPet + EntityLimits::ClientPet::True /*CoinHasWeight*/ + }, + { // NPCPet + EntityLimits::NPCPet::True /*CoinHasWeight*/ + }, + { // MercPet + EntityLimits::MercPet::True /*CoinHasWeight*/ + }, + { // BotPet + EntityLimits::BotPet::True /*CoinHasWeight*/ + }, + { // OfflineTitanium + Titanium::False + }, + { // OfflineSoF + SoF::False + }, + { // OfflineSoD + SoD::False + }, + { // OfflineUF + UF::False + }, + { // OfflineRoF + RoF::False + }, + { // OfflineRoF2 + RoF2::False + } +}; + +const EQEmu::behavior::LookupEntry* EQEmu::behavior::Lookup(versions::InventoryVersion inventory_version) +{ + return &behavior_lookup_entries[static_cast(versions::ValidateInventoryVersion(inventory_version))]; +} diff --git a/common/eq_limits.h b/common/eq_limits.h new file mode 100644 index 000000000..82539f2b1 --- /dev/null +++ b/common/eq_limits.h @@ -0,0 +1,94 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_EQ_LIMITS_H +#define COMMON_EQ_LIMITS_H + +#include "emu_legacy.h" +#include "types.h" +#include "eq_constants.h" +#include "emu_versions.h" +#include "../common/patches/titanium_limits.h" +#include "../common/patches/sof_limits.h" +#include "../common/patches/sod_limits.h" +#include "../common/patches/uf_limits.h" +#include "../common/patches/rof_limits.h" +#include "../common/patches/rof2_limits.h" + + +namespace EQEmu +{ + namespace constants { + class LookupEntry { + public: + size_t CharacterCreationLimit; + }; + + const LookupEntry* Lookup(versions::ClientVersion client_version); + + } /*constants*/ + + namespace inventory { + class LookupEntry { + public: + size_t InventoryTypeSize[legacy::TypeCount]; + + uint64 PossessionsBitmask; + size_t ItemBagSize; + size_t ItemAugSize; + + bool AllowEmptyBagInBag; + bool AllowClickCastFromBag; + bool ConcatenateInvTypeLimbo; + bool AllowOverLevelEquipment; + }; + + const LookupEntry* Lookup(versions::InventoryVersion inventory_version); + + } /*inventory*/ + + namespace behavior { + class LookupEntry { + public: + bool CoinHasWeight; + }; + + const LookupEntry* Lookup(versions::InventoryVersion inventory_version); + + } /*behavior*/ + +} /*EQEmu*/ + +namespace ClientUnknown +{ + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + +} /*ClientUnknown*/ + +namespace Client62 +{ + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + +} /*Client62*/ + +#endif /*COMMON_EQ_LIMITS_H*/ diff --git a/common/eq_packet.cpp b/common/eq_packet.cpp index e01f6a3f8..d7e607d77 100644 --- a/common/eq_packet.cpp +++ b/common/eq_packet.cpp @@ -260,7 +260,7 @@ bool EQProtocolPacket::combine(const EQProtocolPacket *rhs) { bool result=false; if (opcode==OP_Combined && size+rhs->size+5<256) { - unsigned char *tmpbuffer=new unsigned char [size+rhs->size+3]; + auto tmpbuffer = new unsigned char[size + rhs->size + 3]; memcpy(tmpbuffer,pBuffer,size); uint32 offset=size; tmpbuffer[offset++]=rhs->Size(); @@ -270,7 +270,7 @@ bool result=false; pBuffer=tmpbuffer; result=true; } else if (size+rhs->size+7<256) { - unsigned char *tmpbuffer=new unsigned char [size+rhs->size+6]; + auto tmpbuffer = new unsigned char[size + rhs->size + 6]; uint32 offset=0; tmpbuffer[offset++]=Size(); offset+=serialize(tmpbuffer+offset); @@ -457,7 +457,7 @@ EQApplicationPacket *EQApplicationPacket::Copy() const { } EQRawApplicationPacket *EQProtocolPacket::MakeAppPacket() const { - EQRawApplicationPacket *res = new EQRawApplicationPacket(opcode, pBuffer, size); + auto res = new EQRawApplicationPacket(opcode, pBuffer, size); res->copyInfo(this); return(res); } diff --git a/common/eq_packet.h b/common/eq_packet.h index ed90d132a..94c8a1e10 100644 --- a/common/eq_packet.h +++ b/common/eq_packet.h @@ -62,7 +62,7 @@ class EQProtocolPacket : public BasePacket { friend class EQStream; friend class EQStreamPair; public: - EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len) : BasePacket(buf,len), opcode(op) { acked = false; } + EQProtocolPacket(uint16 op, const unsigned char *buf, uint32 len) : BasePacket(buf, len), opcode(op) { acked = false; sent_time = 0; } // EQProtocolPacket(const unsigned char *buf, uint32 len); bool combine(const EQProtocolPacket *rhs); uint32 serialize (unsigned char *dest) const; @@ -70,6 +70,7 @@ public: EQRawApplicationPacket *MakeAppPacket() const; bool acked; + uint32 sent_time; virtual void build_raw_header_dump(char *buffer, uint16 seq=0xffff) const; virtual void build_header_dump(char *buffer) const; diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 57dfe5482..a1b614b97 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,16 +25,17 @@ #include #include #include "../common/version.h" -//#include "../common/item_struct.h" +#include "emu_constants.h" +#include "textures.h" + static const uint32 BUFF_COUNT = 25; +static const uint32 PET_BUFF_COUNT = 30; static const uint32 MAX_MERC = 100; static const uint32 MAX_MERC_GRADES = 10; static const uint32 MAX_MERC_STANCES = 10; static const uint32 BLOCKED_BUFF_COUNT = 20; -//#include "eq_constants.h" -#include "eq_dictionary.h" /* ** Compiler override to ensure @@ -126,37 +127,7 @@ struct LDoNTrapTemplate // All clients translate the character select information to some degree -struct Color_Struct -{ - union { - struct { - uint8 Blue; - uint8 Green; - uint8 Red; - uint8 UseTint; // if there's a tint this is FF - } RGB; - uint32 Color; - }; -}; - -struct EquipStruct -{ - uint32 Material; - uint32 Unknown1; - uint32 EliteMaterial; - uint32 HeroForgeModel; - uint32 Material2; // Same as material? -}; - -struct CharSelectEquip -{ - uint32 Material; - uint32 Unknown1; - uint32 EliteMaterial; - uint32 HeroForgeModel; - uint32 Material2; - Color_Struct Color; -}; +struct CharSelectEquip : EQEmu::Texture_Struct, EQEmu::Tint_Struct {}; // RoF2-based hybrid struct struct CharacterSelectEntry_Struct @@ -171,7 +142,7 @@ struct CharacterSelectEntry_Struct uint16 Instance; uint8 Gender; uint8 Face; - CharSelectEquip Equip[9]; + CharSelectEquip Equip[EQEmu::textures::TextureCount]; uint8 Unknown15; // Seen FF uint8 Unknown19; // Seen FF uint32 DrakkinTattoo; @@ -273,28 +244,14 @@ struct Spawn_Struct { /*0146*/ uint8 beard; // Beard style (not totally, sure but maybe!) /*0147*/ uint8 unknown0147[4]; /*0151*/ uint8 level; // Spawn Level -/*0152*/ uint8 unknown0259[4]; // ***Placeholder +// None = 0, Open = 1, WeaponSheathed = 2, Aggressive = 4, ForcedAggressive = 8, InstrumentEquipped = 16, Stunned = 32, PrimaryWeaponEquipped = 64, SecondaryWeaponEquipped = 128 +/*0152*/ uint32 PlayerState; // Controls animation stuff /*0156*/ uint8 beardcolor; // Beard color /*0157*/ char suffix[32]; // Player's suffix (of Veeshan, etc.) /*0189*/ uint32 petOwnerId; // If this is a pet, the spawn id of owner /*0193*/ uint8 guildrank; // 0=normal, 1=officer, 2=leader /*0194*/ uint8 unknown0194[3]; -/*0197*/ union -{ - struct - { - /*0000*/ EquipStruct equip_helmet; // Equipment: Helmet visual - /*0000*/ EquipStruct equip_chest; // Equipment: Chest visual - /*0000*/ EquipStruct equip_arms; // Equipment: Arms visual - /*0000*/ EquipStruct equip_bracers; // Equipment: Wrist visual - /*0000*/ EquipStruct equip_hands; // Equipment: Hands visual - /*0000*/ EquipStruct equip_legs; // Equipment: Legs visual - /*0000*/ EquipStruct equip_feet; // Equipment: Boots visual - /*0000*/ EquipStruct equip_primary; // Equipment: Main visual - /*0000*/ EquipStruct equip_secondary; // Equipment: Off visual - } equip; - /*0000*/ EquipStruct equipment[_MaterialCount]; -}; +/*0197*/ EQEmu::TextureProfile equipment; /*0233*/ float runspeed; // Speed when running /*0036*/ uint8 afk; // 0=no, 1=afk /*0238*/ uint32 guildID; // Current guild @@ -325,22 +282,7 @@ union /*0340*/ uint32 spawnId; // Spawn Id /*0344*/ uint8 unknown0344[3]; /*0347*/ uint8 IsMercenary; -/*0348*/ union - { - struct - { - /*0348*/ Color_Struct color_helmet; // Color of helmet item - /*0352*/ Color_Struct color_chest; // Color of chest item - /*0356*/ Color_Struct color_arms; // Color of arms item - /*0360*/ Color_Struct color_bracers; // Color of bracers item - /*0364*/ Color_Struct color_hands; // Color of hands item - /*0368*/ Color_Struct color_legs; // Color of legs item - /*0372*/ Color_Struct color_feet; // Color of feet item - /*0376*/ Color_Struct color_primary; // Color of primary item - /*0380*/ Color_Struct color_secondary; // Color of secondary item - } equipment_colors; - /*0348*/ Color_Struct colors[_MaterialCount]; // Array elements correspond to struct equipment_colors above - }; +/*0348*/ EQEmu::TintProfile equipment_tint; /*0384*/ uint8 lfg; // 0=off, 1=lfg on /*0385*/ @@ -366,6 +308,11 @@ union }; +struct PlayerState_Struct { +/*00*/ uint32 spawn_id; +/*04*/ uint32 state; +}; + /* ** New Spawn ** Length: 176 Bytes @@ -440,7 +387,19 @@ struct MemorizeSpell_Struct { uint32 slot; // Spot in the spell book/memorized slot uint32 spell_id; // Spell id (200 or c8 is minor healing, etc) uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming -uint32 unknown12; +uint32 reduction; // lower reuse +}; + +/* +** Linked Spell Reuse Timer +** Length: 12 +** Comes before the OP_Memorize +** Live (maybe TDS steam) has an extra DWORD after timer_id +*/ +struct LinkedSpellReuseTimer_Struct { + uint32 timer_id; // Timer ID of the spell + uint32 end_time; // timestamp of when it will be ready + uint32 start_time; // timestamp of when it started }; /* @@ -473,10 +432,11 @@ struct DeleteSpell_Struct struct ManaChange_Struct { - uint32 new_mana; // New Mana AMount - uint32 stamina; - uint32 spell_id; - uint32 unknown12; +/*00*/ uint32 new_mana; // New Mana AMount +/*04*/ uint32 stamina; +/*08*/ uint32 spell_id; +/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting? +/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like }; struct SwapSpell_Struct @@ -542,30 +502,28 @@ struct SpawnAppearance_Struct // this is used inside profile struct SpellBuff_Struct { -/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; /*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; //not real +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? -- OSX client calls this "activated" /*004*/ uint32 spellid; -/*008*/ uint32 duration; -/*012*/ uint32 counters; -/*016*/ uint32 player_id; //'global' ID of the caster, for wearoff messages -/*020*/ +/*008*/ int32 duration; +/*012*/ uint32 counters; // single book keeping value (counters, rune/vie) +/*016*/ uint32 player_id; // caster ID, pretty sure just zone ID +// extra stuff for newer packets +/*020*/ uint32 num_hits; +/*024*/ float y; // referenced by SPA 441 +/*028*/ float x; // unsure if all buffs get them +/*032*/ float z; // as valid data +/*036*/ }; -struct SpellBuffFade_Struct { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ uint32 duration; -/*016*/ uint32 num_hits; -/*020*/ uint32 unknown020; //prolly global player ID -/*024*/ uint32 slotid; -/*028*/ uint32 bufffade; -/*032*/ +/*004*/ SpellBuff_Struct buff; +/*040*/ uint32 slotid; +/*044*/ uint32 bufffade; +/*048*/ }; // Underfoot & later struct. @@ -578,14 +536,8 @@ struct BuffRemoveRequest_Struct struct PetBuff_Struct { /*000*/ uint32 petid; -/*004*/ uint32 spellid[BUFF_COUNT]; -/*104*/ uint32 unknown700; -/*108*/ uint32 unknown701; -/*112*/ uint32 unknown702; -/*116*/ uint32 unknown703; -/*120*/ uint32 unknown704; -/*124*/ uint32 ticsremaining[BUFF_COUNT]; -/*224*/ uchar unknown705[20]; +/*004*/ uint32 spellid[PET_BUFF_COUNT]; +/*124*/ int32 ticsremaining[PET_BUFF_COUNT]; /*244*/ uint32 buffcount; }; @@ -726,6 +678,7 @@ struct AA_Array { uint32 AA; uint32 value; + uint32 charges; }; @@ -776,7 +729,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[EmuConstants::BANDOLIER_ITEM_COUNT]; + BandolierItem_Struct Items[EQEmu::legacy::BANDOLIER_ITEM_COUNT]; }; //len = 72 @@ -790,7 +743,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[EmuConstants::POTION_BELT_ITEM_COUNT]; + PotionBeltItem_Struct Items[EQEmu::legacy::POTION_BELT_ITEM_COUNT]; }; struct MovePotionToBelt_Struct @@ -881,7 +834,7 @@ struct SuspendedMinion_Struct /*002*/ uint32 HP; /*006*/ uint32 Mana; /*010*/ SpellBuff_Struct Buffs[BUFF_COUNT]; - /*510*/ uint32 Items[_MaterialCount]; + /*510*/ EQEmu::TextureShortProfile Items; /*546*/ char Name[64]; /*610*/ }; @@ -895,7 +848,7 @@ struct SuspendedMinion_Struct */ static const uint32 MAX_PP_LANGUAGE = 28; static const uint32 MAX_PP_SPELLBOOK = 480; // Set for all functions -static const uint32 MAX_PP_MEMSPELL = 9; // Set to latest client so functions can work right +static const uint32 MAX_PP_MEMSPELL = static_cast(EQEmu::CastingSlot::MaxGems); // Set to latest client so functions can work right -- 12 static const uint32 MAX_PP_REF_SPELLBOOK = 480; // Set for Player Profile size retain static const uint32 MAX_PP_REF_MEMSPELL = 9; // Set for Player Profile size retain @@ -976,7 +929,7 @@ struct PlayerProfile_Struct /*0245*/ uint8 guildbanker; /*0246*/ uint8 unknown0246[6]; // /*0252*/ uint32 intoxication; -/*0256*/ uint32 spellSlotRefresh[MAX_PP_REF_MEMSPELL]; //in ms +/*0256*/ uint32 spellSlotRefresh[MAX_PP_MEMSPELL]; //in ms /*0292*/ uint32 abilitySlotRefresh; /*0296*/ uint8 haircolor; // Player hair color /*0297*/ uint8 beardcolor; // Player beard color @@ -989,9 +942,9 @@ struct PlayerProfile_Struct /*0304*/ uint8 ability_time_minutes; /*0305*/ uint8 ability_time_hours; //place holder /*0306*/ uint8 unknown0306[6]; // @bp Spacer/Flag? -/*0312*/ uint32 item_material[_MaterialCount]; // Item texture/material of worn/held items +/*0312*/ EQEmu::TextureShortProfile item_material; // Item texture/material of worn/held items /*0348*/ uint8 unknown0348[44]; -/*0392*/ Color_Struct item_tint[_MaterialCount]; +/*0392*/ EQEmu::TintProfile item_tint; /*0428*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; /*2348*/ float unknown2384; //seen ~128, ~47 /*2352*/ char servername[32]; // length probably not right @@ -1017,7 +970,7 @@ struct PlayerProfile_Struct /*2580*/ uint8 unknown2616[4]; /*2584*/ uint32 spell_book[MAX_PP_REF_SPELLBOOK]; /*4504*/ uint8 unknown4540[128]; // Was [428] all 0xff -/*4632*/ uint32 mem_spells[MAX_PP_REF_MEMSPELL]; +/*4632*/ uint32 mem_spells[MAX_PP_MEMSPELL]; /*4668*/ uint8 unknown4704[32]; // /*4700*/ float y; // Player y position /*4704*/ float x; // Player x position @@ -1092,7 +1045,7 @@ struct PlayerProfile_Struct /*7212*/ uint32 tribute_points; /*7216*/ uint32 unknown7252; /*7220*/ uint32 tribute_active; //1=active -/*7224*/ Tribute_Struct tributes[EmuConstants::TRIBUTE_SIZE]; +/*7224*/ Tribute_Struct tributes[EQEmu::legacy::TRIBUTE_SIZE]; /*7264*/ Disciplines_Struct disciplines; /*7664*/ uint32 recastTimers[MAX_RECAST_TYPES]; // Timers (GMT of last use) /*7744*/ char unknown7780[160]; @@ -1119,7 +1072,7 @@ struct PlayerProfile_Struct /*12800*/ uint32 expAA; /*12804*/ uint32 aapoints; //avaliable, unspent /*12808*/ uint8 unknown12844[36]; -/*12844*/ Bandolier_Struct bandoliers[EmuConstants::BANDOLIERS_SIZE]; +/*12844*/ Bandolier_Struct bandoliers[EQEmu::legacy::BANDOLIERS_SIZE]; /*14124*/ uint8 unknown14160[4506]; /*18630*/ SuspendedMinion_Struct SuspendedMinion; // No longer in use /*19240*/ uint32 timeentitledonaccount; @@ -1160,7 +1113,7 @@ struct TargetReject_Struct { struct PetCommand_Struct { /*000*/ uint32 command; -/*004*/ uint32 unknown; +/*004*/ uint32 target; }; /* @@ -1226,7 +1179,7 @@ struct WearChange_Struct{ /*010*/ uint32 elite_material; // 1 for Drakkin Elite Material /*014*/ uint32 hero_forge_model; // New to VoA /*018*/ uint32 unknown18; // New to RoF -/*022*/ Color_Struct color; +/*022*/ EQEmu::Tint_Struct color; /*026*/ uint8 wear_slot_id; /*027*/ }; @@ -1279,8 +1232,8 @@ struct RequestClientZoneChange_Struct { struct Animation_Struct { /*00*/ uint16 spawnid; -/*02*/ uint8 action; -/*03*/ uint8 value; +/*02*/ uint8 speed; +/*03*/ uint8 action; /*04*/ }; @@ -1318,10 +1271,10 @@ struct CombatDamage_Struct /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 05 */ uint16 spellid; /* 07 */ uint32 damage; -/* 11 */ uint32 unknown11; -/* 15 */ uint32 sequence; // see above notes in Action_Struct -/* 19 */ uint32 unknown19; -/* 23 */ +/* 11 */ float force; +/* 15 */ float meleepush_xy; // see above notes in Action_Struct +/* 19 */ float meleepush_z; +/* 23 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage }; /* @@ -1517,17 +1470,38 @@ struct ExpUpdate_Struct enum ItemPacketType { ItemPacketViewLink = 0x00, + ItemPacketMerchant = 0x64, ItemPacketTradeView = 0x65, ItemPacketLoot = 0x66, ItemPacketTrade = 0x67, ItemPacketCharInventory = 0x69, - ItemPacketSummonItem = 0x6A, - ItemPacketTributeItem = 0x6C, - ItemPacketMerchant = 0x64, + ItemPacketLimbo = 0x6A, ItemPacketWorldContainer = 0x6B, - ItemPacketCharmUpdate = 0x6E, + ItemPacketTributeItem = 0x6C, + ItemPacketGuildTribute = 0x6D, + ItemPacketCharmUpdate = 0x6E, // noted as incorrect ItemPacketInvalid = 0xFF }; + +//enum ItemPacketType +//{ +// ItemPacketMerchant = /*100*/ 0x64, // Titanium+ +// ItemPacketTradeView = /*101*/ 0x65, +// ItemPacketLoot = /*102*/ 0x66, +// ItemPacketTrade = /*103*/ 0x67, +// ItemPacketCharInventory = /*105*/ 0x69, // 105 looks like raw item packet (no appearance update) thru shared bank..110, possibly possessions with appearance update +// ItemPacketLimbo = /*106*/ 0x6A, +// ItemPacketWorldContainer = /*107*/ 0x6B, +// ItemPacketTributeItem = /*108*/ 0x6C, +// ItemPacketGuildTribute = /*109*/ 0x6D, // missing from EQEmu +// ItemPacket10 = /*110*/ 0x6E, +// ItemPacket11 = /*111*/ 0x6F, // UF+ (equipment slots only) (RoF+ checks '(WORD*)slot + 4 != -1' [(WORD*)]slot + 2 would be bag index - if used) (guess) (appearance (over-level) items?) +// ItemPacket12 = /*112*/ 0x70, // RoF+ (causes stat update) (could be TrophyTribute and GuildTrophyTribute together - two case methodology - is it checking for GuildID?) +// ItemPacketMerchantRecovery = /*113*/ 0x71, +// ItemPacket14 = /*115*/ 0x73, (real estate/moving crate?) +// ItemPacket__ = /*xxx*/ 0xXX // switch 'default' - all clients +//}; + struct ItemPacket_Struct { /*00*/ ItemPacketType PacketType; @@ -2098,7 +2072,7 @@ struct AdventureLeaderboard_Struct /*struct Item_Shop_Struct { uint16 merchantid; uint8 itemtype; - Item_Struct item; + EQEmu::ItemBase item; uint8 iss_unknown001[6]; };*/ @@ -2124,7 +2098,7 @@ struct Illusion_Struct { //size: 256 - SoF /*092*/ uint32 drakkin_heritage; // /*096*/ uint32 drakkin_tattoo; // /*100*/ uint32 drakkin_details; // -/*104*/ uint32 armor_tint[_MaterialCount]; // +/*104*/ EQEmu::TintProfile armor_tint; // /*140*/ uint8 eyecolor1; // Field Not Identified in any Illusion Struct /*141*/ uint8 eyecolor2; // Field Not Identified in any Illusion Struct /*142*/ uint8 unknown138[114]; // @@ -2148,24 +2122,24 @@ struct Illusion_Struct_Old { // OP_Sound - Size: 68 struct QuestReward_Struct { -/*000*/ uint32 from_mob; // ID of mob awarding the client -/*004*/ uint32 unknown004; -/*008*/ uint32 unknown008; -/*012*/ uint32 unknown012; -/*016*/ uint32 unknown016; -/*020*/ uint32 unknown020; -/*024*/ uint32 silver; // Gives silver to the client -/*028*/ uint32 gold; // Gives gold to the client -/*032*/ uint32 platinum; // Gives platinum to the client -/*036*/ uint32 unknown036; -/*040*/ uint32 unknown040; -/*044*/ uint32 unknown044; -/*048*/ uint32 unknown048; -/*052*/ uint32 unknown052; -/*056*/ uint32 unknown056; -/*060*/ uint32 unknown060; -/*064*/ uint32 unknown064; -/*068*/ + /*000*/ uint32 mob_id; // ID of mob awarding the client + /*004*/ uint32 target_id; + /*008*/ uint32 exp_reward; + /*012*/ uint32 faction; + /*016*/ int32 faction_mod; + /*020*/ uint32 copper; // Gives copper to the client + /*024*/ uint32 silver; // Gives silver to the client + /*028*/ uint32 gold; // Gives gold to the client + /*032*/ uint32 platinum; // Gives platinum to the client + /*036*/ uint32 item_id; + /*040*/ uint32 unknown040; + /*044*/ uint32 unknown044; + /*048*/ uint32 unknown048; + /*052*/ uint32 unknown052; + /*056*/ uint32 unknown056; + /*060*/ uint32 unknown060; + /*064*/ uint32 unknown064; + /*068*/ }; // Size: 8 @@ -2535,8 +2509,8 @@ struct BookRequest_Struct { */ struct Object_Struct { /*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list -/*08*/ uint16 unknown008; // -/*10*/ uint16 unknown010; // +/*08*/ uint16 size; // +/*10*/ uint16 solidtype; // /*12*/ uint32 drop_id; // Unique object id for zone /*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in /*18*/ uint16 zone_instance; // @@ -3394,27 +3368,6 @@ struct PetitionBug_Struct{ char text[1028]; }; -struct DyeStruct -{ - union - { - struct - { - struct Color_Struct head; - struct Color_Struct chest; - struct Color_Struct arms; - struct Color_Struct wrists; - struct Color_Struct hands; - struct Color_Struct legs; - struct Color_Struct feet; - struct Color_Struct primary; // you can't actually dye this - struct Color_Struct secondary; // or this - } - dyes; - struct Color_Struct dye[_MaterialCount]; - }; -}; - struct ApproveZone_Struct { char name[64]; uint32 zoneid; @@ -3472,8 +3425,8 @@ struct SelectTributeReply_Struct { struct TributeInfo_Struct { uint32 active; //0 == inactive, 1 == active - uint32 tributes[EmuConstants::TRIBUTE_SIZE]; //-1 == NONE - uint32 tiers[EmuConstants::TRIBUTE_SIZE]; //all 00's + uint32 tributes[EQEmu::legacy::TRIBUTE_SIZE]; //-1 == NONE + uint32 tiers[EQEmu::legacy::TRIBUTE_SIZE]; //all 00's uint32 tribute_master_id; }; @@ -4030,7 +3983,7 @@ struct MarkNPC_Struct struct InspectBuffs_Struct { /*000*/ uint32 spell_id[BUFF_COUNT]; -/*100*/ uint32 tics_remaining[BUFF_COUNT]; +/*100*/ int32 tics_remaining[BUFF_COUNT]; }; struct RaidGeneral_Struct { @@ -4218,6 +4171,52 @@ struct UseAA_Struct { uint32 end; }; +//new AA stuff +//reference only +struct AARankInfo_Struct +{ + uint32 id; + int32 upper_hotkey_sid; + int32 lower_hotkey_sid; + int32 title_sid; + int32 desc_sid; + int32 level_req; + int32 cost; + uint32 seq; + uint32 current_level; + uint32 type; + int32 spell; + int32 spell_type; + int32 spell_refresh; + int32 classes; + int32 max_level; + int32 prev_id; + int32 next_id; + int32 total_cost; + int32 expansion; + int32 category; + uint32 charges; + uint8 grant_only; + uint32 total_effects; + uint32 total_prereqs; +}; + +struct AARankPrereq_Struct +{ + int32 aa_id; + int32 points; +}; + +struct AARankEffect_Struct +{ + int32 effect_id; + int32 base1; + int32 base2; + int32 slot; +}; + +//old AA stuff + struct AA_Ability { /*00*/ uint32 skill_id; /*04*/ uint32 base1; @@ -4272,18 +4271,10 @@ struct SendAA_Struct { struct AA_Action { /*00*/ uint32 action; /*04*/ uint32 ability; -/*08*/ uint32 unknown08; +/*08*/ uint32 target_id; /*12*/ uint32 exp_value; }; - -struct AA_Skills { //this should be removed and changed to AA_Array -/*00*/ uint32 aa_skill; // Total AAs Spent -/*04*/ uint32 aa_value; -/*08*/ uint32 unknown08; -/*12*/ -}; - struct AAExpUpdate_Struct { /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*04*/ uint32 aapoints_unspent; @@ -4301,12 +4292,12 @@ struct AltAdvStats_Struct { }; struct PlayerAA_Struct { // Is this still used? - AA_Skills aa_list[MAX_PP_AA_ARRAY]; + AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct AATable_Struct { /*00*/ int32 aa_spent; // Total AAs Spent -/*04*/ AA_Skills aa_list[MAX_PP_AA_ARRAY]; +/*04*/ AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct Weather_Struct { @@ -4685,6 +4676,22 @@ struct GuildBankItemUpdate_Struct /*226*/ uint16 Unknown226; }; +// newer clients (RoF+) send a list that contains 240 entries +// The packets don't actually use all 64 chars in the strings, but we'll just overallocate for these +struct GuildBankItemListEntry_Struct +{ + uint8 vaild; + uint32 permissions; + char whofor[64]; + char donator[64]; + uint32 item_id; + uint32 item_icon; + uint32 quantity; + uint8 allow_merge; // 1 here for non-full stacks + uint8 usable; + char item_name[64]; +}; + struct GuildBankClear_Struct { /*00*/ uint32 Action; @@ -4731,7 +4738,7 @@ struct BuffIconEntry_Struct { uint32 buff_slot; uint32 spell_id; - uint32 tics_remaining; + int32 tics_remaining; uint32 num_hits; }; @@ -4740,6 +4747,8 @@ struct BuffIcon_Struct uint32 entity_id; uint8 all_buffs; uint16 count; + uint8 type; // 0 = self buff window, 1 = self target window, 4 = group, 5 = PC, 7 = NPC + int32 tic_timer; BuffIconEntry_Struct entries[0]; }; @@ -5286,21 +5295,18 @@ struct ClientMarqueeMessage_Struct { typedef std::list ItemList; -struct TextLinkBody_Struct { - // Current server mask: EQClientRoF2 - uint8 unknown_1; /* %1X */ - uint32 item_id; /* %05X */ - uint32 augment_1; /* %05X */ - uint32 augment_2; /* %05X */ - uint32 augment_3; /* %05X */ - uint32 augment_4; /* %05X */ - uint32 augment_5; /* %05X */ - uint32 augment_6; /* %05X */ - uint8 is_evolving; /* %1X */ - uint32 evolve_group; /* %05X */ - uint8 evolve_level; /* %02X */ - uint32 ornament_icon; /* %05X */ - int hash; /* %08X */ + +struct fling_struct { +/* 00 */ uint32 collision; // 0 collision is off, anything else it's on +/* 04 */ int32 travel_time; // ms -- UF we need to calc this, RoF+ -1 auto calcs +/* 08 */ uint8 unk3; // bool, set to 1 has something to do with z-axis or something weird things happen if the new Z is above or equal to yours +/* 09 */ uint8 disable_fall_damage; // 1 you take no fall damage, 0 you take fall damage +/* 10 */ uint8 padding[2]; +/* 12 */ float speed_z; +/* 16 */ float new_y; +/* 20 */ float new_x; +/* 24 */ float new_z; +/* 28 */ }; // Restore structure packing to default diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index be1ae50d4..5a272e201 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -72,8 +72,10 @@ void EQStream::init(bool resetSession) { RateThreshold=RATEBASE/250; DecayRate=DECAYBASE/250; BytesWritten=0; + sent_packet_count = 0; + received_packet_count = 0; SequencedBase = 0; - NextSequencedSend = 0; + AverageDelta = 500; if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) { retransmittimer = Timer::GetCurrentTime(); @@ -84,10 +86,6 @@ void EQStream::init(bool resetSession) { if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { Log.Out(Logs::Detail, Logs::Netcode, _L "init Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq); } - - if(NextSequencedSend > SequencedQueue.size()) { - Log.Out(Logs::Detail, Logs::Netcode, _L "init Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); - } } EQRawApplicationPacket *EQStream::MakeApplicationPacket(EQProtocolPacket *p) @@ -290,10 +288,8 @@ void EQStream::ProcessPacket(EQProtocolPacket *p) } break; case OP_KeepAlive: { -#ifndef COLLECTOR NonSequencedPush(new EQProtocolPacket(p->opcode,p->pBuffer,p->size)); Log.Out(Logs::Detail, Logs::Netcode, _L "Received and queued reply to keep alive" __L); -#endif } break; case OP_Ack: { @@ -302,14 +298,12 @@ void EQStream::ProcessPacket(EQProtocolPacket *p) Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_Ack that was of malformed size" __L); break; } -#ifndef COLLECTOR uint16 seq=ntohs(*(uint16 *)(p->pBuffer)); AckPackets(seq); if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) { retransmittimer = Timer::GetCurrentTime(); } -#endif } break; case OP_SessionRequest: { @@ -318,7 +312,6 @@ void EQStream::ProcessPacket(EQProtocolPacket *p) Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_SessionRequest that was of malformed size" __L); break; } -#ifndef COLLECTOR if (GetState()==ESTABLISHED) { Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_SessionRequest in ESTABLISHED state (%d) streamactive (%i) attempt (%i)" __L, GetState(),streamactive,sessionAttempts); @@ -331,7 +324,6 @@ void EQStream::ProcessPacket(EQProtocolPacket *p) break; } } -#endif sessionAttempts++; // we set established below, so statistics will not be reset for session attempts/stream active. init(GetState()!=ESTABLISHED); @@ -341,10 +333,8 @@ void EQStream::ProcessPacket(EQProtocolPacket *p) SetMaxLen(ntohl(Request->MaxLength)); Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_SessionRequest: session %lu, maxlen %d" __L, (unsigned long)Session, MaxLen); SetState(ESTABLISHED); -#ifndef COLLECTOR Key=0x11223344; SendSessionResponse(); -#endif } break; case OP_SessionResponse: { @@ -410,7 +400,6 @@ void EQStream::ProcessPacket(EQProtocolPacket *p) Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_OutOfOrderAck that was of malformed size" __L); break; } -#ifndef COLLECTOR uint16 seq=ntohs(*(uint16 *)(p->pBuffer)); MOutboundQueue.lock(); @@ -418,36 +407,30 @@ void EQStream::ProcessPacket(EQProtocolPacket *p) Log.Out(Logs::Detail, Logs::Netcode, _L "Pre-OOA Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq); } - if(NextSequencedSend > SequencedQueue.size()) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Pre-OOA Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); - } //if the packet they got out of order is between our last acked packet and the last sent packet, then its valid. if (CompareSequence(SequencedBase,seq) != SeqPast && CompareSequence(NextOutSeq,seq) == SeqPast) { Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_OutOfOrderAck for sequence %d, starting retransmit at the start of our unacked buffer (seq %d, was %d)." __L, - seq, SequencedBase, SequencedBase+NextSequencedSend); + seq, SequencedBase, SequencedBase+SequencedQueue.size()); - bool retransmit_acked_packets = false; - if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) { - retransmit_acked_packets = RETRANSMIT_ACKED_PACKETS; - } - - if(!retransmit_acked_packets) { - uint16 sqsize = SequencedQueue.size(); - uint16 index = seq - SequencedBase; - Log.Out(Logs::Detail, Logs::Netcode, _L "OP_OutOfOrderAck marking packet acked in queue (queue index = %d, queue size = %d)." __L, index, sqsize); - if (index < sqsize) { - std::deque::iterator sitr; - sitr = SequencedQueue.begin(); - sitr += index; - (*sitr)->acked = true; + uint16 sqsize = SequencedQueue.size(); + uint16 index = seq - SequencedBase; + Log.Out(Logs::Detail, Logs::Netcode, _L "OP_OutOfOrderAck marking packet acked in queue (queue index = %d, queue size = %d)." __L, index, sqsize); + if (index < sqsize) { + SequencedQueue[index]->acked = true; + // flag packets for a resend + uint16 count = 0; + uint32 timeout = AverageDelta * 2 + 100; + for (auto sitr = SequencedQueue.begin(); sitr != SequencedQueue.end() && count < index; ++sitr, ++count) { + if (!(*sitr)->acked && (*sitr)->sent_time > 0 && (((*sitr)->sent_time + timeout) < Timer::GetCurrentTime())) { + (*sitr)->sent_time = 0; + Log.Out(Logs::Detail, Logs::Netcode, _L "OP_OutOfOrderAck Flagging packet %d for retransmission" __L, SequencedBase + count); + } } } if(RETRANSMIT_TIMEOUT_MULT) { retransmittimer = Timer::GetCurrentTime(); } - - NextSequencedSend = 0; } else { Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_OutOfOrderAck for out-of-window %d. Window (%d->%d)." __L, seq, SequencedBase, NextOutSeq); } @@ -456,46 +439,49 @@ void EQStream::ProcessPacket(EQProtocolPacket *p) Log.Out(Logs::Detail, Logs::Netcode, _L "Post-OOA Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq); } - if(NextSequencedSend > SequencedQueue.size()) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Post-OOA Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); - } MOutboundQueue.unlock(); -#endif } break; case OP_SessionStatRequest: { - if(p->Size() < sizeof(SessionStats)) + if(p->Size() < sizeof(ClientSessionStats)) { Log.Out(Logs::Detail, Logs::Netcode, _L "Received OP_SessionStatRequest that was of malformed size" __L); break; } -#ifndef COLLECTOR - SessionStats *Stats=(SessionStats *)p->pBuffer; + ClientSessionStats *ClientStats=(ClientSessionStats *)p->pBuffer; Log.Out(Logs::Detail, Logs::Netcode, _L "Received Stats: %lu packets received, %lu packets sent, Deltas: local %lu, (%lu <- %lu -> %lu) remote %lu" __L, - (unsigned long)ntohl(Stats->packets_received), (unsigned long)ntohl(Stats->packets_sent), (unsigned long)ntohl(Stats->last_local_delta), - (unsigned long)ntohl(Stats->low_delta), (unsigned long)ntohl(Stats->average_delta), - (unsigned long)ntohl(Stats->high_delta), (unsigned long)ntohl(Stats->last_remote_delta)); - uint64 x=Stats->packets_received; - Stats->packets_received=Stats->packets_sent; - Stats->packets_sent=x; - NonSequencedPush(new EQProtocolPacket(OP_SessionStatResponse,p->pBuffer,p->size)); - AdjustRates(ntohl(Stats->average_delta)); + (unsigned long)ntohl(ClientStats->packets_received), (unsigned long)ntohl(ClientStats->packets_sent), (unsigned long)ntohl(ClientStats->last_local_delta), + (unsigned long)ntohl(ClientStats->low_delta), (unsigned long)ntohl(ClientStats->average_delta), + (unsigned long)ntohl(ClientStats->high_delta), (unsigned long)ntohl(ClientStats->last_remote_delta)); + + AdjustRates(ntohl(ClientStats->average_delta)); if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) { - if(RETRANSMIT_TIMEOUT_MULT && ntohl(Stats->average_delta)) { + if (RETRANSMIT_TIMEOUT_MULT && ntohl(ClientStats->average_delta)) { //recalculate retransmittimeout using the larger of the last rtt or average rtt, which is multiplied by the rule value - if((ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) > (ntohl(Stats->average_delta) * 2)) { - retransmittimeout = (ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) + if ((ntohl(ClientStats->last_local_delta) + ntohl(ClientStats->last_remote_delta)) > (ntohl(ClientStats->average_delta) * 2)) { + retransmittimeout = (ntohl(ClientStats->last_local_delta) + ntohl(ClientStats->last_remote_delta)) * RETRANSMIT_TIMEOUT_MULT; } else { - retransmittimeout = ntohl(Stats->average_delta) * 2 * RETRANSMIT_TIMEOUT_MULT; + retransmittimeout = ntohl(ClientStats->average_delta) * 2 * RETRANSMIT_TIMEOUT_MULT; } + retransmittimeout += 300; if(retransmittimeout > RETRANSMIT_TIMEOUT_MAX) retransmittimeout = RETRANSMIT_TIMEOUT_MAX; Log.Out(Logs::Detail, Logs::Netcode, _L "Retransmit timeout recalculated to %dms" __L, retransmittimeout); } } -#endif + + ServerSessionStats *ServerStats = (ServerSessionStats *)p->pBuffer; + + //ServerStats->RequestID = ClientStats->RequestID; // no change + ServerStats->ServerTime = htonl(Timer::GetCurrentTime()); + ServerStats->packets_sent_echo = ClientStats->packets_sent; // still in htonll format + ServerStats->packets_received_echo = ClientStats->packets_received; // still in htonll format + ServerStats->packets_sent = htonll(GetPacketsSent()); + ServerStats->packets_received = htonll(GetPacketsReceived()); + + NonSequencedPush(new EQProtocolPacket(OP_SessionStatResponse, p->pBuffer, p->size)); } break; case OP_SessionStatResponse: { @@ -573,16 +559,18 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p) // Convert the EQApplicationPacket to 1 or more EQProtocolPackets if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2) - Log.Out(Logs::Detail, Logs::Netcode, _L "Making oversized packet, len %d" __L, p->size); + Log.Out(Logs::Detail, Logs::Netcode, _L "Making oversized packet, len %d" __L, p->Size()); - unsigned char *tmpbuff=new unsigned char[p->size+3]; + auto tmpbuff = new unsigned char[p->size + 3]; length=p->serialize(opcode, tmpbuff); + if (length != p->Size()) + Log.Out(Logs::Detail, Logs::Netcode, _L "Packet adjustment, len %d to %d" __L, p->Size(), length); - EQProtocolPacket *out=new EQProtocolPacket(OP_Fragment,nullptr,MaxLen-4); - *(uint32 *)(out->pBuffer+2)=htonl(p->Size()); + auto out = new EQProtocolPacket(OP_Fragment, nullptr, MaxLen - 4); + *(uint32 *)(out->pBuffer+2)=htonl(length); used=MaxLen-10; memcpy(out->pBuffer+6,tmpbuff,used); - Log.Out(Logs::Detail, Logs::Netcode, _L "First fragment: used %d/%d. Put size %d in the packet" __L, used, p->size, p->Size()); + Log.Out(Logs::Detail, Logs::Netcode, _L "First fragment: used %d/%d. Payload size %d in the packet" __L, used, length, p->size); SequencedPush(out); @@ -593,16 +581,16 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p) out->size=chunksize+2; SequencedPush(out); used+=chunksize; - Log.Out(Logs::Detail, Logs::Netcode, _L "Subsequent fragment: len %d, used %d/%d." __L, chunksize, used, p->size); + Log.Out(Logs::Detail, Logs::Netcode, _L "Subsequent fragment: len %d, used %d/%d." __L, chunksize, used, length); } delete p; delete[] tmpbuff; } else { - unsigned char *tmpbuff=new unsigned char[p->Size()+3]; + auto tmpbuff = new unsigned char[p->Size() + 3]; length=p->serialize(opcode, tmpbuff+2) + 2; - EQProtocolPacket *out=new EQProtocolPacket(OP_Packet,tmpbuff,length); + auto out = new EQProtocolPacket(OP_Packet, tmpbuff, length); delete[] tmpbuff; SequencedPush(out); @@ -612,42 +600,32 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p) void EQStream::SequencedPush(EQProtocolPacket *p) { -#ifdef COLLECTOR - delete p; -#else MOutboundQueue.lock(); -if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Pre-Push Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq); -} -if(NextSequencedSend > SequencedQueue.size()) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Pre-Push Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); -} + if (uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { + Log.Out(Logs::Detail, Logs::Netcode, _L "Pre-Push Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, + SequencedBase, SequencedQueue.size(), NextOutSeq); + } - Log.Out(Logs::Detail, Logs::Netcode, _L "Pushing sequenced packet %d of length %d. Base Seq is %d." __L, NextOutSeq, p->size, SequencedBase); - *(uint16 *)(p->pBuffer)=htons(NextOutSeq); + Log.Out(Logs::Detail, Logs::Netcode, _L "Pushing sequenced packet %d of length %d. Base Seq is %d." __L, + NextOutSeq, p->size, SequencedBase); + *(uint16 *)(p->pBuffer) = htons(NextOutSeq); SequencedQueue.push_back(p); NextOutSeq++; -if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Push Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq); -} -if(NextSequencedSend > SequencedQueue.size()) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Push Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); -} + if (uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { + Log.Out(Logs::Detail, Logs::Netcode, _L "Push Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, + SequencedBase, SequencedQueue.size(), NextOutSeq); + } + MOutboundQueue.unlock(); -#endif } void EQStream::NonSequencedPush(EQProtocolPacket *p) { -#ifdef COLLECTOR - delete p; -#else MOutboundQueue.lock(); Log.Out(Logs::Detail, Logs::Netcode, _L "Pushing non-sequenced packet of length %d" __L, p->size); NonSequencedQueue.push(p); MOutboundQueue.unlock(); -#endif } void EQStream::SendAck(uint16 seq) @@ -691,21 +669,15 @@ void EQStream::Write(int eq_fd) // Place to hold the base packet t combine into EQProtocolPacket *p=nullptr; - if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) { - // if we have a timeout defined and we have not received an ack recently enough, retransmit from beginning of queue - if (RETRANSMIT_TIMEOUT_MULT && !SequencedQueue.empty() && NextSequencedSend && - (GetState()==ESTABLISHED) && ((retransmittimer+retransmittimeout) < Timer::GetCurrentTime())) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Timeout since last ack received, starting retransmit at the start of our unacked " - "buffer (seq %d, was %d)." __L, SequencedBase, SequencedBase+NextSequencedSend); - NextSequencedSend = 0; - retransmittimer = Timer::GetCurrentTime(); // don't want to endlessly retransmit the first packet - } - } - // Find the next sequenced packet to send from the "queue" sitr = SequencedQueue.begin(); - if (sitr!=SequencedQueue.end()) - sitr += NextSequencedSend; + + uint16 count = 0; + // get to start of packets + while (sitr != SequencedQueue.end() && (*sitr)->sent_time > 0) { + ++sitr; + ++count; + } // Loop until both are empty or MaxSends is reached while(!SeqEmpty || !NonSeqEmpty) { @@ -719,7 +691,7 @@ void EQStream::Write(int eq_fd) Log.Out(Logs::Detail, Logs::Netcode, _L "Starting combined packet with non-seq packet of len %d" __L, p->size); NonSequencedQueue.pop(); } else if (!p->combine(NonSequencedQueue.front())) { - // Tryint to combine this packet with the base didn't work (too big maybe) + // Trying to combine this packet with the base didn't work (too big maybe) // So just send the base packet (we'll try this packet again later) Log.Out(Logs::Detail, Logs::Netcode, _L "Combined packet full at len %d, next non-seq packet is len %d" __L, p->size, (NonSequencedQueue.front())->size); ReadyToSend.push(p); @@ -742,16 +714,9 @@ void EQStream::Write(int eq_fd) NonSeqEmpty=true; } - if (sitr!=SequencedQueue.end()) { - if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Pre-Send Seq NSS=%d Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, NextSequencedSend, SequencedBase, SequencedQueue.size(), NextOutSeq); - } + if (sitr != SequencedQueue.end()) { + uint16 seq_send = SequencedBase + count; //just for logging... - if(NextSequencedSend > SequencedQueue.size()) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Pre-Send Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); - } - uint16 seq_send = SequencedBase + NextSequencedSend; //just for logging... - if(SequencedQueue.empty()) { Log.Out(Logs::Detail, Logs::Netcode, _L "Tried to write a packet with an empty queue (%d is past next out %d)" __L, seq_send, NextOutSeq); SeqEmpty=true; @@ -759,26 +724,32 @@ void EQStream::Write(int eq_fd) } if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) { - if (!RETRANSMIT_ACKED_PACKETS && (*sitr)->acked) { + if ((*sitr)->acked || (*sitr)->sent_time != 0) { + ++sitr; + ++count; + if (p) { + Log.Out(Logs::Detail, Logs::Netcode, _L "Final combined packet not full, len %d" __L, p->size); + ReadyToSend.push(p); + BytesWritten += p->size; + p = nullptr; + } Log.Out(Logs::Detail, Logs::Netcode, _L "Not retransmitting seq packet %d because already marked as acked" __L, seq_send); - sitr++; - NextSequencedSend++; } else if (!p) { // If we don't have a packet to try to combine into, use this one as the base // Copy it first as it will still live until it is acked p=(*sitr)->Copy(); Log.Out(Logs::Detail, Logs::Netcode, _L "Starting combined packet with seq packet %d of len %d" __L, seq_send, p->size); + (*sitr)->sent_time = Timer::GetCurrentTime(); ++sitr; - NextSequencedSend++; + ++count; } else if (!p->combine(*sitr)) { // Trying to combine this packet with the base didn't work (too big maybe) // So just send the base packet (we'll try this packet again later) - Log.Out(Logs::Detail, Logs::Netcode, _L "Combined packet full at len %d, next seq packet %d is len %d" __L, p->size, seq_send, (*sitr)->size); + Log.Out(Logs::Detail, Logs::Netcode, _L "Combined packet full at len %d, next seq packet %d is len %d" __L, p->size, seq_send + 1, (*sitr)->size); ReadyToSend.push(p); BytesWritten+=p->size; p=nullptr; - - if (BytesWritten > threshold) { + if ((*sitr)->opcode != OP_Fragment && BytesWritten > threshold) { // Sent enough this round, lets stop to be fair Log.Out(Logs::Detail, Logs::Netcode, _L "Exceeded write threshold in seq (%d > %d)" __L, BytesWritten, threshold); break; @@ -786,17 +757,28 @@ void EQStream::Write(int eq_fd) } else { // Combine worked Log.Out(Logs::Detail, Logs::Netcode, _L "Combined seq packet %d of len %d, yeilding %d combined." __L, seq_send, (*sitr)->size, p->size); + (*sitr)->sent_time = Timer::GetCurrentTime(); ++sitr; - NextSequencedSend++; + ++count; } } else { - if (!p) { + if ((*sitr)->sent_time != 0) { + ++sitr; + ++count; + if (p) { + Log.Out(Logs::Detail, Logs::Netcode, _L "Final combined packet not full, len %d" __L, p->size); + ReadyToSend.push(p); + BytesWritten += p->size; + p = nullptr; + } + } else if (!p) { // If we don't have a packet to try to combine into, use this one as the base // Copy it first as it will still live until it is acked p=(*sitr)->Copy(); + (*sitr)->sent_time = Timer::GetCurrentTime(); Log.Out(Logs::Detail, Logs::Netcode, _L "Starting combined packet with seq packet %d of len %d" __L, seq_send, p->size); ++sitr; - NextSequencedSend++; + ++count; } else if (!p->combine(*sitr)) { // Trying to combine this packet with the base didn't work (too big maybe) // So just send the base packet (we'll try this packet again later) @@ -812,18 +794,16 @@ void EQStream::Write(int eq_fd) } } else { // Combine worked - Log.Out(Logs::Detail, Logs::Netcode, _L "Combined seq packet %d of len %d, yeilding %d combined." __L, seq_send, (*sitr)->size, p->size); + Log.Out(Logs::Detail, Logs::Netcode, _L "Combined seq packet %d of len %d, yielding %d combined." __L, seq_send, (*sitr)->size, p->size); + (*sitr)->sent_time = Timer::GetCurrentTime(); ++sitr; - NextSequencedSend++; + ++count; } } if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { Log.Out(Logs::Detail, Logs::Netcode, _L "Post send Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq); } - if(NextSequencedSend > SequencedQueue.size()) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Post send Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); - } } else { // No more sequenced packets SeqEmpty=true; @@ -882,9 +862,11 @@ sockaddr_in address; length=p->serialize(buffer); if (p->opcode!=OP_SessionRequest && p->opcode!=OP_SessionResponse) { if (compressed) { + BytesWritten -= p->size; uint32 newlen=EQProtocolPacket::Compress(buffer,length, _tempBuffer, 2048); memcpy(buffer,_tempBuffer,newlen); length=newlen; + BytesWritten += newlen; } if (encoded) { EQProtocolPacket::ChatEncode(buffer,length,Key); @@ -900,7 +882,7 @@ sockaddr_in address; void EQStream::SendSessionResponse() { -EQProtocolPacket *out=new EQProtocolPacket(OP_SessionResponse,nullptr,sizeof(SessionResponse)); + auto out = new EQProtocolPacket(OP_SessionResponse, nullptr, sizeof(SessionResponse)); SessionResponse *Response=(SessionResponse *)out->pBuffer; Response->Session=htonl(Session); Response->MaxLength=htonl(MaxLen); @@ -922,7 +904,7 @@ EQProtocolPacket *out=new EQProtocolPacket(OP_SessionResponse,nullptr,sizeof(Ses void EQStream::SendSessionRequest() { -EQProtocolPacket *out=new EQProtocolPacket(OP_SessionRequest,nullptr,sizeof(SessionRequest)); + auto out = new EQProtocolPacket(OP_SessionRequest, nullptr, sizeof(SessionRequest)); SessionRequest *Request=(SessionRequest *)out->pBuffer; memset(Request,0,sizeof(SessionRequest)); Request->Session=htonl(time(nullptr)); @@ -938,7 +920,7 @@ void EQStream::_SendDisconnect() if(GetState() == CLOSED) return; - EQProtocolPacket *out=new EQProtocolPacket(OP_SessionDisconnect,nullptr,sizeof(uint32)); + auto out = new EQProtocolPacket(OP_SessionDisconnect, nullptr, sizeof(uint32)); *(uint32 *)out->pBuffer=htonl(Session); NonSequencedPush(out); @@ -957,8 +939,8 @@ EQApplicationPacket *EQStream::PopPacket() EQRawApplicationPacket *p=nullptr; MInboundQueue.lock(); - if (InboundQueue.size()) { - std::vector::iterator itr=InboundQueue.begin(); + if (!InboundQueue.empty()) { + auto itr = InboundQueue.begin(); p=*itr; InboundQueue.erase(itr); } @@ -982,8 +964,8 @@ EQRawApplicationPacket *EQStream::PopRawPacket() EQRawApplicationPacket *p=nullptr; MInboundQueue.lock(); - if (InboundQueue.size()) { - std::vector::iterator itr=InboundQueue.begin(); + if (!InboundQueue.empty()) { + auto itr = InboundQueue.begin(); p=*itr; InboundQueue.erase(itr); } @@ -1009,8 +991,8 @@ EQRawApplicationPacket *EQStream::PeekPacket() EQRawApplicationPacket *p=nullptr; MInboundQueue.lock(); - if (InboundQueue.size()) { - std::vector::iterator itr=InboundQueue.begin(); + if (!InboundQueue.empty()) { + auto itr = InboundQueue.begin(); p=*itr; } MInboundQueue.unlock(); @@ -1101,8 +1083,8 @@ EQProtocolPacket *p=nullptr; void EQStream::Process(const unsigned char *buffer, const uint32 length) { -static unsigned char newbuffer[2048]; -uint32 newlength=0; + static unsigned char newbuffer[2048]; + uint32 newlength=0; if (EQProtocolPacket::ValidateCRC(buffer,length,Key)) { if (compressed) { newlength=EQProtocolPacket::Decompress(buffer,length,newbuffer,2048); @@ -1146,13 +1128,6 @@ void EQStream::AckPackets(uint16 seq) std::deque::iterator itr, tmp; MOutboundQueue.lock(); -//do a bit of sanity checking. -if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Pre-Ack Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq); -} -if(NextSequencedSend > SequencedQueue.size()) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Pre-Ack Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); -} SeqOrder ord = CompareSequence(SequencedBase, seq); if(ord == SeqInOrder) { @@ -1168,28 +1143,21 @@ if(NextSequencedSend > SequencedQueue.size()) { //this is a good ack, we get to ack some blocks. seq++; //we stop at the block right after their ack, counting on the wrap of both numbers. while(SequencedBase != seq) { -if(SequencedQueue.empty()) { -Log.Out(Logs::Detail, Logs::Netcode, _L "OUT OF PACKETS acked packet with sequence %lu. Next send is %d before this." __L, (unsigned long)SequencedBase, NextSequencedSend); - SequencedBase = NextOutSeq; - NextSequencedSend = 0; - break; -} - Log.Out(Logs::Detail, Logs::Netcode, _L "Removing acked packet with sequence %lu. Next send is %d before this." __L, (unsigned long)SequencedBase, NextSequencedSend); + if(SequencedQueue.empty()) { + Log.Out(Logs::Detail, Logs::Netcode, _L "OUT OF PACKETS acked packet with sequence %lu. Next send is %d before this." __L, (unsigned long)SequencedBase, SequencedQueue.size()); + SequencedBase = NextOutSeq; + break; + } + Log.Out(Logs::Detail, Logs::Netcode, _L "Removing acked packet with sequence %lu." __L, (unsigned long)SequencedBase); //clean out the acked packet delete SequencedQueue.front(); SequencedQueue.pop_front(); - //adjust our "next" pointer - if(NextSequencedSend > 0) - NextSequencedSend--; //advance the base sequence number to the seq of the block after the one we just got rid of. SequencedBase++; } -if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Post-Ack on %d Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, seq, SequencedBase, SequencedQueue.size(), NextOutSeq); -} -if(NextSequencedSend > SequencedQueue.size()) { - Log.Out(Logs::Detail, Logs::Netcode, _L "Post-Ack Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size()); -} + if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) { + Log.Out(Logs::Detail, Logs::Netcode, _L "Post-Ack on %d Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, seq, SequencedBase, SequencedQueue.size(), NextOutSeq); + } } MOutboundQueue.unlock(); @@ -1367,6 +1335,18 @@ void EQStream::Decay() if (BytesWritten<0) BytesWritten=0; } + // check for any timed out acks + if ((GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) && RETRANSMIT_TIMEOUT_MULT && retransmittimeout) { + int count = 0; + MOutboundQueue.lock(); + for (auto sitr = SequencedQueue.begin(); sitr != SequencedQueue.end(); ++sitr, count++) { + if (!(*sitr)->acked && (*sitr)->sent_time > 0 && ((*sitr)->sent_time + retransmittimeout) < Timer::GetCurrentTime()) { + (*sitr)->sent_time = 0; + Log.Out(Logs::Detail, Logs::Netcode, _L "Timeout exceeded for seq %d. Flagging packet for retransmission" __L, SequencedBase + count); + } + } + MOutboundQueue.unlock(); + } } void EQStream::AdjustRates(uint32 average_delta) @@ -1374,18 +1354,24 @@ void EQStream::AdjustRates(uint32 average_delta) if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) { if (average_delta && (average_delta <= AVERAGE_DELTA_MAX)) { MRate.lock(); + AverageDelta = average_delta; RateThreshold=RATEBASE/average_delta; DecayRate=DECAYBASE/average_delta; + if (BytesWritten > RateThreshold) + BytesWritten = RateThreshold + DecayRate; Log.Out(Logs::Detail, Logs::Netcode, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L, RateThreshold, DecayRate, average_delta); MRate.unlock(); } else { Log.Out(Logs::Detail, Logs::Netcode, _L "Not adjusting data rate because avg delta over max (%d > %d)" __L, average_delta, AVERAGE_DELTA_MAX); + AverageDelta = AVERAGE_DELTA_MAX; } } else { if (average_delta) { MRate.lock(); + AverageDelta = average_delta; + BytesWritten = 0; RateThreshold=RATEBASE/average_delta; DecayRate=DECAYBASE/average_delta; Log.Out(Logs::Detail, Logs::Netcode, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L, diff --git a/common/eq_stream.h b/common/eq_stream.h index 72eb53cdd..d5e78c085 100644 --- a/common/eq_stream.h +++ b/common/eq_stream.h @@ -71,7 +71,7 @@ struct SessionResponse { }; //Deltas are in ms, representing round trip times -struct SessionStats { +struct ClientSessionStats { /*000*/ uint16 RequestID; /*002*/ uint32 last_local_delta; /*006*/ uint32 average_delta; @@ -83,6 +83,16 @@ struct SessionStats { /*038*/ }; +struct ServerSessionStats { +/*000*/ uint16 RequestID; +/*002*/ uint32 ServerTime; +/*006*/ uint64 packets_sent_echo; +/*014*/ uint64 packets_received_echo; +/*022*/ uint64 packets_sent; +/*030*/ uint64 packets_received; +/*038*/ +}; + #pragma pack() class OpcodeManager; @@ -143,7 +153,6 @@ class EQStream : public EQStreamInterface { std::deque SequencedQueue; uint16 NextOutSeq; uint16 SequencedBase; //the sequence number of SequencedQueue[0] - long NextSequencedSend; //index into SequencedQueue Mutex MOutboundQueue; //a buffer we use for compression/decompression @@ -158,10 +167,13 @@ class EQStream : public EQStreamInterface { int32 BytesWritten; + uint64 sent_packet_count; + uint64 received_packet_count; + Mutex MRate; int32 RateThreshold; int32 DecayRate; - + uint32 AverageDelta; OpcodeManager **OpMgr; @@ -265,11 +277,13 @@ class EQStream : public EQStreamInterface { void AddBytesSent(uint32 bytes) { bytes_sent += bytes; + ++sent_packet_count; } void AddBytesRecv(uint32 bytes) { bytes_recv += bytes; + ++received_packet_count; } virtual const uint32 GetBytesSent() const { return bytes_sent; } @@ -288,6 +302,9 @@ class EQStream : public EQStreamInterface { return bytes_recv / (Timer::GetTimeSeconds() - create_time); } + const uint64 GetPacketsSent() { return sent_packet_count; } + const uint64 GetPacketsReceived() { return received_packet_count; } + //used for dynamic stream identification class Signature { public: diff --git a/common/eq_stream_factory.cpp b/common/eq_stream_factory.cpp index f48b0f723..d58995623 100644 --- a/common/eq_stream_factory.cpp +++ b/common/eq_stream_factory.cpp @@ -3,7 +3,7 @@ #include "eq_stream_factory.h" #ifdef _WINDOWS - #include + #include #include #include #include @@ -120,7 +120,7 @@ std::shared_ptr EQStreamFactory::Pop() { std::shared_ptr s = nullptr; MNewStreams.lock(); - if (NewStreams.size()) { + if (!NewStreams.empty()) { s = NewStreams.front(); NewStreams.pop(); s->PutInUse(); @@ -235,7 +235,7 @@ void EQStreamFactory::CheckTimeout() //give it a little time for everybody to finish with it } else { //everybody is done, we can delete it now - std::map, std::shared_ptr>::iterator temp = stream_itr; + auto temp = stream_itr; ++stream_itr; temp->second = nullptr; Streams.erase(temp); @@ -250,8 +250,7 @@ void EQStreamFactory::CheckTimeout() void EQStreamFactory::WriterLoop() { - std::map, std::shared_ptr>::iterator stream_itr; - bool havework=true; + bool havework = true; std::vector> wants_write; std::vector>::iterator cur, end; bool decay = false; @@ -260,7 +259,7 @@ void EQStreamFactory::WriterLoop() WriterRunning = true; DecayTimer.Enable(); - while(sock!=-1) { + while (sock != -1) { MWriterRunning.lock(); if (!WriterRunning) break; @@ -269,34 +268,36 @@ void EQStreamFactory::WriterLoop() havework = false; wants_write.clear(); - decay=DecayTimer.Check(); + decay = DecayTimer.Check(); - //copy streams into a seperate list so we dont have to keep - //MStreams locked while we are writting + // copy streams into a seperate list so we dont have to keep + // MStreams locked while we are writting MStreams.lock(); - for(stream_itr=Streams.begin();stream_itr!=Streams.end();++stream_itr) { + for (auto stream_itr = Streams.begin(); stream_itr != Streams.end(); ++stream_itr) { // If it's time to decay the bytes sent, then let's do it before we try to write if (decay) stream_itr->second->Decay(); - //bullshit checking, to see if this is really happening, GDB seems to think so... - if(stream_itr->second == nullptr) { - fprintf(stderr, "ERROR: nullptr Stream encountered in EQStreamFactory::WriterLoop for: %i:%i", stream_itr->first.first, stream_itr->first.second); + // bullshit checking, to see if this is really happening, GDB seems to think so... + if (stream_itr->second == nullptr) { + fprintf(stderr, + "ERROR: nullptr Stream encountered in EQStreamFactory::WriterLoop for: %i:%i", + stream_itr->first.first, stream_itr->first.second); continue; } if (stream_itr->second->HasOutgoingData()) { - havework=true; + havework = true; stream_itr->second->PutInUse(); wants_write.push_back(stream_itr->second); } } MStreams.unlock(); - //do the actual writes + // do the actual writes cur = wants_write.begin(); end = wants_write.end(); - for(; cur != end; ++cur) { + for (; cur != end; ++cur) { (*cur)->Write(sock); (*cur)->ReleaseFromUse(); } diff --git a/common/eq_stream_ident.cpp b/common/eq_stream_ident.cpp index 4640c75f1..cb0810467 100644 --- a/common/eq_stream_ident.cpp +++ b/common/eq_stream_ident.cpp @@ -1,3 +1,5 @@ +#include + #include "global_define.h" #include "eqemu_logsys.h" #include "eq_stream_ident.h" @@ -25,7 +27,7 @@ EQStreamIdentifier::~EQStreamIdentifier() { } void EQStreamIdentifier::RegisterPatch(const EQStream::Signature &sig, const char *name, OpcodeManager ** opcodes, const StructStrategy *structs) { - Patch *p = new Patch; + auto p = new Patch; p->signature = sig; p->name = name; p->opcodes = opcodes; @@ -156,7 +158,7 @@ EQStreamInterface *EQStreamIdentifier::PopIdentified() { } EQStreamIdentifier::Record::Record(std::shared_ptr s) -: stream(s), +: stream(std::move(s)), expire(STREAM_IDENT_WAIT_MS) { } diff --git a/common/eq_stream_intf.h b/common/eq_stream_intf.h index 68b8ffc96..917a13a86 100644 --- a/common/eq_stream_intf.h +++ b/common/eq_stream_intf.h @@ -4,7 +4,7 @@ //this is the only part of an EQStream that is seen by the application. #include -#include "clientversions.h" +#include "emu_versions.h" typedef enum { ESTABLISHED, @@ -35,7 +35,7 @@ public: virtual const uint32 GetBytesRecieved() const { return 0; } virtual const uint32 GetBytesSentPerSecond() const { return 0; } virtual const uint32 GetBytesRecvPerSecond() const { return 0; } - virtual const ClientVersion GetClientVersion() const { return ClientVersion::Unknown; } + virtual const EQEmu::versions::ClientVersion ClientVersion() const { return EQEmu::versions::ClientVersion::Unknown; } }; #endif /*EQSTREAMINTF_H_*/ diff --git a/common/eq_stream_proxy.cpp b/common/eq_stream_proxy.cpp index 117ae8c94..0c41988e4 100644 --- a/common/eq_stream_proxy.cpp +++ b/common/eq_stream_proxy.cpp @@ -21,9 +21,9 @@ std::string EQStreamProxy::Describe() const { return(m_structs->Describe()); } -const ClientVersion EQStreamProxy::GetClientVersion() const +const EQEmu::versions::ClientVersion EQStreamProxy::ClientVersion() const { - return m_structs->GetClientVersion(); + return m_structs->ClientVersion(); } void EQStreamProxy::QueuePacket(const EQApplicationPacket *p, bool ack_req) { diff --git a/common/eq_stream_proxy.h b/common/eq_stream_proxy.h index 93ad1d884..def543b34 100644 --- a/common/eq_stream_proxy.h +++ b/common/eq_stream_proxy.h @@ -28,7 +28,7 @@ public: virtual void RemoveData(); virtual bool CheckState(EQStreamState state); virtual std::string Describe() const; - virtual const ClientVersion GetClientVersion() const; + virtual const EQEmu::versions::ClientVersion ClientVersion() const; virtual const uint32 GetBytesSent() const; virtual const uint32 GetBytesRecieved() const; diff --git a/common/eqdb.cpp b/common/eqdb.cpp index 2c912afba..a94be7768 100644 --- a/common/eqdb.cpp +++ b/common/eqdb.cpp @@ -63,7 +63,7 @@ EQDBRes * EQDB::query(Const_char *q) { //NOT THREAD SAFE! Const_char *EQDB::escape_string(Const_char *from) { int len = strlen(from); - char *res = new char[len*2+1]; + auto res = new char[len * 2 + 1]; mysql_real_escape_string(mysql_ref,res,from,len); diff --git a/common/eqemu_config.cpp b/common/eqemu_config.cpp index 50ce54248..d9b940e1a 100644 --- a/common/eqemu_config.cpp +++ b/common/eqemu_config.cpp @@ -80,7 +80,7 @@ void EQEmuConfig::do_world(TiXmlElement *ele) sprintf(str, "loginserver%i", ++LoginCount); sub_ele = ele->FirstChildElement(str); if (sub_ele) { - LoginConfig* loginconfig = new LoginConfig; + auto loginconfig = new LoginConfig; text = ParseTextBlock(sub_ele, "host", true); if (text) { loginconfig->LoginHost = text; @@ -277,9 +277,9 @@ void EQEmuConfig::do_files(TiXmlElement *ele) if (text) { OpCodesFile = text; } - text = ParseTextBlock(ele, "eqtime", true); + text = ParseTextBlock(ele, "plugin.pl", true); if (text) { - EQTimeFile = text; + PluginPlFile = text; } } @@ -289,14 +289,45 @@ void EQEmuConfig::do_directories(TiXmlElement *ele) 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 += '/'; } } @@ -431,8 +462,8 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const if (var_name == "OpCodesFile") { return (OpCodesFile); } - if (var_name == "EQTimeFile") { - return (EQTimeFile); + if (var_name == "PluginPlFile") { + return (PluginPlFile); } if (var_name == "MapDir") { return (MapDir); @@ -443,6 +474,18 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const if (var_name == "PluginDir") { return (PluginDir); } + if (var_name == "LuaModuleDir") { + return (LuaModuleDir); + } + if (var_name == "PatchDir") { + return (PatchDir); + } + if (var_name == "SharedMemDir") { + return (SharedMemDir); + } + if (var_name == "LogDir") { + return (LogDir); + } if (var_name == "LogPrefix") { return (LogPrefix); } @@ -504,10 +547,14 @@ void EQEmuConfig::Dump() const std::cout << "WebInterfacePrivKey = " << WebInterfacePrivKey << std::endl; std::cout << "SpellsFile = " << SpellsFile << std::endl; std::cout << "OpCodesFile = " << OpCodesFile << std::endl; - std::cout << "EQTimeFile = " << EQTimeFile << std::endl; + std::cout << "PluginPlFile = " << PluginPlFile << std::endl; std::cout << "MapDir = " << MapDir << std::endl; std::cout << "QuestDir = " << QuestDir << std::endl; std::cout << "PluginDir = " << PluginDir << std::endl; + std::cout << "LuaModuleDir = " << LuaModuleDir << std::endl; + std::cout << "PatchDir = " << PatchDir << std::endl; + std::cout << "SharedMemDir = " << SharedMemDir << std::endl; + std::cout << "LogDir = " << LogDir << std::endl; std::cout << "ZonePortLow = " << ZonePortLow << std::endl; std::cout << "ZonePortHigh = " << ZonePortHigh << std::endl; std::cout << "DefaultStatus = " << (int)DefaultStatus << std::endl; diff --git a/common/eqemu_config.h b/common/eqemu_config.h index 06894ee4a..1d0bedd91 100644 --- a/common/eqemu_config.h +++ b/common/eqemu_config.h @@ -85,12 +85,16 @@ class EQEmuConfig : public XMLParser // From std::string SpellsFile; std::string OpCodesFile; - std::string EQTimeFile; + std::string PluginPlFile; // From std::string MapDir; std::string QuestDir; std::string PluginDir; + std::string LuaModuleDir; + std::string PatchDir; + std::string SharedMemDir; + std::string LogDir; // From std::string LogPrefix; @@ -160,11 +164,16 @@ class EQEmuConfig : public XMLParser // Files SpellsFile = "spells_us.txt"; OpCodesFile = "opcodes.conf"; - EQTimeFile = "eqtime.cfg"; + PluginPlFile = "plugin.pl"; // Dirs - MapDir = "Maps"; - QuestDir = "quests"; - PluginDir = "plugins"; + MapDir = "Maps/"; + QuestDir = "quests/"; + PluginDir = "plugins/"; + LuaModuleDir = "lua_modules/"; + PatchDir = "./"; + SharedMemDir = "shared/"; + LogDir = "logs/"; + // Launcher LogPrefix = "logs/zone-"; LogSuffix = ".log"; diff --git a/common/eqemu_logsys.cpp b/common/eqemu_logsys.cpp index 36176c399..4c0ee1c9f 100644 --- a/common/eqemu_logsys.cpp +++ b/common/eqemu_logsys.cpp @@ -102,6 +102,7 @@ void EQEmuLogSys::LoadLogSettingsDefaults() log_settings[Logs::UCS_Server].log_to_console = Logs::General; log_settings[Logs::Crash].log_to_console = Logs::General; log_settings[Logs::MySQLError].log_to_console = Logs::General; + log_settings[Logs::Login_Server].log_to_console = Logs::General; /* Declare process file names for log writing If there is no process_file_name declared, no log file will be written, simply @@ -116,7 +117,7 @@ void EQEmuLogSys::LoadLogSettingsDefaults() platform_file_name = "ucs"; else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) platform_file_name = "login"; - else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) + else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch) platform_file_name = "launcher"; } diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index a99b3b439..153d61582 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -82,6 +82,7 @@ namespace Logs { Client_Server_Packet_Unhandled, Server_Client_Packet_With_Dump, Client_Server_Packet_With_Dump, + Login_Server, MaxCategoryID /* Don't Remove this*/ }; @@ -130,6 +131,7 @@ namespace Logs { "Packet :: Client -> Server Unhandled", "Packet :: Server -> Client (Dump)", "Packet :: Client -> Server (Dump)", + "Login Server" }; } diff --git a/common/eqtime.cpp b/common/eqtime.cpp index 79301a28f..8ece4ad69 100644 --- a/common/eqtime.cpp +++ b/common/eqtime.cpp @@ -43,19 +43,19 @@ EQTime::EQTime(TimeOfDay_Struct start_eq, time_t start_real) EQTime::EQTime() { - timezone=0; + timezone = 0; memset(&eqTime, 0, sizeof(eqTime)); //Defaults for time TimeOfDay_Struct start; - start.day=1; - start.hour=9; - start.minute=0; - start.month=1; - start.year=3100; + start.day = 1; + start.hour = 9; + start.minute = 0; + start.month = 1; + start.year = 3100; //Set default time zone - timezone=0; + timezone = 0; //Start EQTimer - setEQTimeOfDay(start, time(0)); + SetCurrentEQTimeOfDay(start, time(0)); } EQTime::~EQTime() @@ -67,10 +67,10 @@ EQTime::~EQTime() //Input: Current Time (as a time_t), a pointer to the TimeOfDay_Struct that will be written to. //Output: 0=Error, 1=Sucess -int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeOfDay ) +int EQTime::GetCurrentEQTimeOfDay(time_t timeConvert, struct TimeOfDay_Struct *eqTimeOfDay) { /* check to see if we have a reference time to go by. */ - if( eqTime.start_realtime == 0 ) + if (eqTime.start_realtime == 0) return 0; unsigned long diff = timeConvert - eqTime.start_realtime; @@ -83,7 +83,7 @@ int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeO int32 ntz = timezone; /* The minutes range from 0 - 59 */ - diff += eqTime.start_eqtime.minute + (ntz%60); + diff += eqTime.start_eqtime.minute + (ntz % 60); eqTimeOfDay->minute = diff % 60; diff /= 60; ntz /= 60; @@ -97,24 +97,24 @@ int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeO // // Modify it so that it works from // 0-23 for our calculations - diff += ( eqTime.start_eqtime.hour - 1) + (ntz%24); - eqTimeOfDay->hour = (diff%24) + 1; + diff += (eqTime.start_eqtime.hour - 1) + (ntz % 24); + eqTimeOfDay->hour = (diff % 24) + 1; diff /= 24; ntz /= 24; // The days range from 1-28 // Modify it so that it works from // 0-27 for our calculations - diff += ( eqTime.start_eqtime.day - 1 ) + (ntz%28); - eqTimeOfDay->day = (diff%28) + 1; + diff += (eqTime.start_eqtime.day - 1) + (ntz % 28); + eqTimeOfDay->day = (diff % 28) + 1; diff /= 28; ntz /= 28; // The months range from 1-12 // Modify it so that it works from // 0-11 for our calculations - diff += ( eqTime.start_eqtime.month - 1 ) + (ntz%12); - eqTimeOfDay->month = (diff%12) + 1; + diff += (eqTime.start_eqtime.month - 1) + (ntz % 12); + eqTimeOfDay->month = (diff % 12) + 1; diff /= 12; ntz /= 12; @@ -124,100 +124,34 @@ int EQTime::getEQTimeOfDay( time_t timeConvert, struct TimeOfDay_Struct *eqTimeO } //setEQTimeOfDay -int EQTime::setEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real) +int EQTime::SetCurrentEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real) { - if(start_real==0) + if (start_real == 0) return 0; - eqTime.start_eqtime=start_eq; - eqTime.start_realtime=start_real; + eqTime.start_eqtime = start_eq; + eqTime.start_realtime = start_real; return 1; } -//saveFile and loadFile need to use long for the save datatype... -//For some reason, ifstream/ofstream have problems with EQEmu datatypes in files. -bool EQTime::saveFile(const char *filename) -{ - std::ofstream of; - of.open(filename); - if(!of) - { - Log.Out(Logs::General, Logs::Error, "EQTime::saveFile failed: Unable to open file '%s'", filename); - return false; - } - //Enable for debugging - of << EQT_VERSION << std::endl; - of << (long)eqTime.start_eqtime.day << std::endl; - of << (long)eqTime.start_eqtime.hour << std::endl; - of << (long)eqTime.start_eqtime.minute << std::endl; - of << (long)eqTime.start_eqtime.month << std::endl; - of << eqTime.start_eqtime.year << std::endl; - of << eqTime.start_realtime << std::endl; - of.close(); - return true; -} - -bool EQTime::loadFile(const char *filename) -{ - int version=0; - long in_data=0; - std::ifstream in; - in.open(filename); - if(!in) - { - Log.Out(Logs::General, Logs::Error, "Could not load EQTime file %s", filename); - return false; - } - in >> version; - in.ignore(80, '\n'); - if(version != EQT_VERSION) - { - Log.Out(Logs::General, Logs::Error, "'%s' is NOT a valid EQTime file. File version is %i, EQTime version is %i", filename, version, EQT_VERSION); - return false; - } - //in >> eqTime.start_eqtime.day; - in >> in_data; - in.ignore(80, '\n'); - eqTime.start_eqtime.day = in_data; - //in >> eqTime.start_eqtime.hour; - in >> in_data; - eqTime.start_eqtime.hour = in_data; - in.ignore(80, '\n'); - //in >> eqTime.start_eqtime.minute; - in >> in_data; - in.ignore(80, '\n'); - eqTime.start_eqtime.minute = in_data; - //in >> eqTime.start_eqtime.month; - in >> in_data; - in.ignore(80, '\n'); - eqTime.start_eqtime.month = in_data; - in >> eqTime.start_eqtime.year; - in.ignore(80, '\n'); - in >> eqTime.start_realtime; - //Enable for debugging... - in.close(); - return true; -} - - bool EQTime::IsTimeBefore(TimeOfDay_Struct *base, TimeOfDay_Struct *test) { - if(base->year > test->year) + if (base->year > test->year) return(true); - if(base->year < test->year) + if (base->year < test->year) return(false); //same years - if(base->month > test->month) + if (base->month > test->month) return(true); - if(base->month < test->month) + if (base->month < test->month) return(false); //same month - if(base->day > test->day) + if (base->day > test->day) return(true); - if(base->day < test->day) + if (base->day < test->day) return(false); //same day - if(base->hour > test->hour) + if (base->hour > test->hour) return(true); - if(base->hour < test->hour) + if (base->hour < test->hour) return(false); //same hour... return(base->minute > test->minute); @@ -230,7 +164,7 @@ void EQTime::AddMinutes(uint32 minutes, TimeOfDay_Struct *to) { //minutes start at 0, everything else starts at 1 cur = to->minute; cur += minutes; - if(cur < 60) { + if (cur < 60) { to->minute = cur; return; } @@ -238,29 +172,29 @@ void EQTime::AddMinutes(uint32 minutes, TimeOfDay_Struct *to) { //carry hours cur /= 60; cur += to->hour; - if(cur <= 24) { + if (cur <= 24) { to->hour = cur; return; } - to->hour = ((cur-1) % 24) + 1; + to->hour = ((cur - 1) % 24) + 1; //carry days - cur = (cur-1) / 24; + cur = (cur - 1) / 24; cur += to->day; - if(cur <= 28) { + if (cur <= 28) { to->day = cur; return; } - to->day = ((cur-1) % 28) + 1; + to->day = ((cur - 1) % 28) + 1; //carry months - cur = (cur-1) / 28; + cur = (cur - 1) / 28; cur += to->month; - if(cur <= 12) { + if (cur <= 12) { to->month = cur; return; } - to->month = ((cur-1) % 12) + 1; + to->month = ((cur - 1) % 12) + 1; //carry years - to->year += (cur-1) / 12; + to->year += (cur - 1) / 12; } void EQTime::ToString(TimeOfDay_Struct *t, std::string &str) { @@ -269,5 +203,4 @@ void EQTime::ToString(TimeOfDay_Struct *t, std::string &str) { t->month, t->day, t->year, t->hour, t->minute); buf[127] = '\0'; str = buf; -} - +} \ No newline at end of file diff --git a/common/eqtime.h b/common/eqtime.h index aa608f307..f40b855f6 100644 --- a/common/eqtime.h +++ b/common/eqtime.h @@ -21,8 +21,8 @@ public: ~EQTime(); //Get functions - int getEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(getEQTimeOfDay(time(nullptr), eqTimeOfDay)); } - int getEQTimeOfDay( time_t timeConvert, TimeOfDay_Struct *eqTimeOfDay ); + int GetCurrentEQTimeOfDay( TimeOfDay_Struct *eqTimeOfDay ) { return(GetCurrentEQTimeOfDay(time(nullptr), eqTimeOfDay)); } + int GetCurrentEQTimeOfDay( time_t timeConvert, TimeOfDay_Struct *eqTimeOfDay ); TimeOfDay_Struct getStartEQTime() { return eqTime.start_eqtime; } time_t getStartRealTime() { return eqTime.start_realtime; } uint32 getEQTimeZone() { return timezone; } @@ -30,7 +30,7 @@ public: uint32 getEQTimeZoneMin() { return timezone%60; } //Set functions - int setEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real); + int SetCurrentEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real); void setEQTimeZone(int32 in_timezone) { timezone=in_timezone; } //Time math/logic functions @@ -39,12 +39,6 @@ public: static void ToString(TimeOfDay_Struct *t, std::string &str); - //Database functions - //bool loadDB(Database q); - //bool setDB(Database q); - bool loadFile(const char *filename); - bool saveFile(const char *filename); - private: //This is our reference clock. eqTimeOfDay eqTime; diff --git a/common/extprofile.h b/common/extprofile.h index a8447d4fc..e53480631 100644 --- a/common/extprofile.h +++ b/common/extprofile.h @@ -40,7 +40,7 @@ struct ExtendedProfile_Struct { uint16 old_pet_hp; /* Not Used */ uint16 old_pet_mana; /* Not Used */ SpellBuff_Struct pet_buffs[BUFF_COUNT]; /* Not Used */ - uint32 pet_items[_MaterialCount]; /* Not Used */ + EQEmu::TextureShortProfile pet_items; /* Not Used */ char merc_name[64]; /* Used */ uint32 aa_effects; /* Used */ @@ -54,6 +54,8 @@ struct ExtendedProfile_Struct { uint32 mercTimerRemaining; /* Not Used */ uint8 mercGender; /* Not Used */ int32 mercState; /* Not Used */ + uint32 last_invsnapshot_time; /* Used */ + uint32 next_invsnapshot_time; /* Used */ }; #pragma pack() diff --git a/common/features.h b/common/features.h index 0860788e1..27390e745 100644 --- a/common/features.h +++ b/common/features.h @@ -154,11 +154,12 @@ enum { //reuse times enum { //timer settings, all in milliseconds AImovement_duration = 100, AIthink_duration = 150, - AIscanarea_delay = 500, + AIscanarea_delay = 6000, AIfeignremember_delay = 500, AItarget_check_duration = 500, AIClientScanarea_delay = 750, //used in REVERSE_AGGRO AIassistcheck_delay = 3000, //now often a fighting NPC will yell for help + AI_check_signal_timer_delay = 500, // How often EVENT_SIGNAL checks are processed ClientProximity_interval = 150, CombatEventTimer_expire = 12000, Tribute_duration = 600000, @@ -212,8 +213,8 @@ enum { //some random constants #define MAX_NPC_FACTIONS 20 //individual faction pool -#define MAX_PERSONAL_FACTION 1200 -#define MIN_PERSONAL_FACTION -3000 +#define MAX_PERSONAL_FACTION 2000 +#define MIN_PERSONAL_FACTION -2000 //The Level Cap: //#define LEVEL_CAP RuleI(Character, MaxLevel) //hard cap is 127 @@ -232,6 +233,8 @@ enum { //some random constants #define GROUP_EXP_PER_POINT 1000 #define RAID_EXP_PER_POINT 2000 +#define ZONE_CONTROLLER_NPC_ID 10 + //Some hard coded statuses from commands and other places: enum { minStatusToBeGM = 40, @@ -270,6 +273,9 @@ enum { #define NPC_DEFAULT_LOGGING_ENABLED false +// This is the item ID we use for say links, we use the max that fits in 5 ASCII chars +#define SAYLINK_ITEM_ID 0xFFFFF + /* diff --git a/common/global_define.h b/common/global_define.h index 0c5d32ee9..e27f313af 100644 --- a/common/global_define.h +++ b/common/global_define.h @@ -16,6 +16,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +// WHY IS THIS UP HERE #if defined(_DEBUG) && defined(WIN32) #ifndef _CRTDBG_MAP_ALLOC #include @@ -26,16 +27,9 @@ #ifndef EQDEBUG_H #define EQDEBUG_H -#define _WINSOCKAPI_ //stupid windows, trying to fix the winsock2 vs. winsock issues -#if defined(WIN32) && ( defined(PACKETCOLLECTOR) || defined(COLLECTOR) ) - // Packet Collector on win32 requires winsock.h due to latest pcap.h - // winsock.h must come before windows.h - #include -#endif - #ifdef _WINDOWS - #include #include + #include #endif #endif diff --git a/common/guild_base.cpp b/common/guild_base.cpp index 1416dedf1..ed4b508bc 100644 --- a/common/guild_base.cpp +++ b/common/guild_base.cpp @@ -179,7 +179,7 @@ BaseGuildManager::GuildInfo *BaseGuildManager::_CreateGuild(uint32 guild_id, con } //make the new entry and store it into the map. - GuildInfo *info = new GuildInfo; + auto info = new GuildInfo; info->name = guild_name; info->leader_char_id = leader_char_id; info->minstatus = minstatus; @@ -236,9 +236,9 @@ bool BaseGuildManager::_StoreGuildDB(uint32 guild_id) { results = m_db->QueryDatabase(query); //escape our strings. - char *name_esc = new char[info->name.length()*2+1]; - char *motd_esc = new char[info->motd.length()*2+1]; - char *motd_set_esc = new char[info->motd_setter.length()*2+1]; + auto name_esc = new char[info->name.length() * 2 + 1]; + auto motd_esc = new char[info->motd.length() * 2 + 1]; + auto motd_set_esc = new char[info->motd_setter.length() * 2 + 1]; m_db->DoEscapeString(name_esc, info->name.c_str(), info->name.length()); m_db->DoEscapeString(motd_esc, info->motd.c_str(), info->motd.length()); m_db->DoEscapeString(motd_set_esc, info->motd_setter.c_str(), info->motd_setter.length()); @@ -264,7 +264,7 @@ bool BaseGuildManager::_StoreGuildDB(uint32 guild_id) { for(rank = 0; rank <= GUILD_MAX_RANK; rank++) { const RankInfo &rankInfo = info->ranks[rank]; - char *title_esc = new char[rankInfo.name.length()*2+1]; + auto title_esc = new char[rankInfo.name.length() * 2 + 1]; m_db->DoEscapeString(title_esc, rankInfo.name.c_str(), rankInfo.name.length()); query = StringFormat("INSERT INTO guild_ranks " @@ -564,7 +564,7 @@ bool BaseGuildManager::DBRenameGuild(uint32 guild_id, const char* name) { //escape our strings. uint32 len = strlen(name); - char *esc = new char[len*2+1]; + auto esc = new char[len * 2 + 1]; m_db->DoEscapeString(esc, name, len); //insert the new `guilds` entry @@ -636,8 +636,8 @@ bool BaseGuildManager::DBSetGuildMOTD(uint32 guild_id, const char* motd, const c //escape our strings. uint32 len = strlen(motd); uint32 len2 = strlen(setter); - char *esc = new char[len*2+1]; - char *esc_set = new char[len2*2+1]; + auto esc = new char[len * 2 + 1]; + auto esc_set = new char[len2 * 2 + 1]; m_db->DoEscapeString(esc, motd, len); m_db->DoEscapeString(esc_set, setter, len2); @@ -675,7 +675,7 @@ bool BaseGuildManager::DBSetGuildURL(uint32 GuildID, const char* URL) //escape our strings. uint32 len = strlen(URL); - char *esc = new char[len*2+1]; + auto esc = new char[len * 2 + 1]; m_db->DoEscapeString(esc, URL, len); std::string query = StringFormat("UPDATE guilds SET url='%s' WHERE id=%d", esc, GuildID); @@ -709,7 +709,7 @@ bool BaseGuildManager::DBSetGuildChannel(uint32 GuildID, const char* Channel) //escape our strings. uint32 len = strlen(Channel); - char *esc = new char[len*2+1]; + auto esc = new char[len * 2 + 1]; m_db->DoEscapeString(esc, Channel, len); std::string query = StringFormat("UPDATE guilds SET channel='%s' WHERE id=%d", esc, GuildID); @@ -832,7 +832,7 @@ bool BaseGuildManager::DBSetPublicNote(uint32 charid, const char* note) { //escape our strings. uint32 len = strlen(note); - char *esc = new char[len*2+1]; + auto esc = new char[len * 2 + 1]; m_db->DoEscapeString(esc, note, len); //insert the new `guilds` entry @@ -867,16 +867,16 @@ bool BaseGuildManager::QueryWithLogging(std::string query, const char *errmsg) { //factored out so I dont have to copy this crap. #ifdef BOTS #define GuildMemberBaseQuery \ -"SELECT c.id,c.name,c.class,c.level,c.timelaston,c.zoneid," \ -" g.guild_id,g.rank,g.tribute_enable,g.total_tribute,g.last_tribute," \ -" g.banker,g.public_note,g.alt" \ -" FROM vwBotCharacterMobs AS c LEFT JOIN vwGuildMembers AS g ON c.id=g.char_id AND c.mobtype = g.mobtype " +"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \ +" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \ +" g.`banker`, g.`public_note`, g.`alt`" \ +" FROM `vw_bot_character_mobs` AS c LEFT JOIN `vw_guild_members` AS g ON c.`id` = g.`char_id` AND c.`mob_type` = g.`mob_type` " #else #define GuildMemberBaseQuery \ -"SELECT c.id,c.name,c.class,c.level,c.last_login,c.zone_id," \ -" g.guild_id,g.rank,g.tribute_enable,g.total_tribute,g.last_tribute," \ -" g.banker,g.public_note,g.alt " \ -" FROM `character_data` AS c LEFT JOIN guild_members AS g ON c.id=g.char_id " +"SELECT c.`id`, c.`name`, c.`class`, c.`level`, c.`last_login`, c.`zone_id`," \ +" g.`guild_id`, g.`rank`, g.`tribute_enable`, g.`total_tribute`, g.`last_tribute`," \ +" g.`banker`, g.`public_note`, g.`alt` " \ +" FROM `character_data` AS c LEFT JOIN `guild_members` AS g ON c.`id` = g.`char_id` " #endif static void ProcessGuildMember(MySQLRequestRow row, CharGuildInfo &into) { //fields from `characer_` @@ -918,8 +918,8 @@ bool BaseGuildManager::GetEntireGuild(uint32 guild_id, std::vectorDoEscapeString(esc, char_name, nl); //load up the rank info for each guild. @@ -969,7 +969,7 @@ bool BaseGuildManager::GetCharInfo(uint32 char_id, CharGuildInfo &into) { //load up the rank info for each guild. std::string query; #ifdef BOTS - query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mobtype = 'C'", char_id); + query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d AND c.mob_type = 'C'", char_id); #else query = StringFormat(GuildMemberBaseQuery " WHERE c.id=%d", char_id); #endif @@ -994,7 +994,7 @@ uint8 *BaseGuildManager::MakeGuildList(const char *head_name, uint32 &length) co //dynamic structs will make this a lot less painful. length = sizeof(GuildsList_Struct); - uint8 *buffer = new uint8[length]; + auto buffer = new uint8[length]; //a bit little better than memsetting the whole thing... uint32 r,pos; diff --git a/common/ipc_mutex.cpp b/common/ipc_mutex.cpp index c05fb072c..75e0a63a1 100644 --- a/common/ipc_mutex.cpp +++ b/common/ipc_mutex.cpp @@ -18,7 +18,9 @@ #include "ipc_mutex.h" #ifdef _WINDOWS +#define WIN32_LEAN_AND_MEAN #include +#undef WIN32_LEAN_AND_MEAN #else #include #include @@ -27,7 +29,7 @@ #endif #include "types.h" #include "eqemu_exception.h" - +#include "eqemu_config.h" namespace EQEmu { struct IPCMutex::Implementation { @@ -41,7 +43,8 @@ namespace EQEmu { IPCMutex::IPCMutex(std::string name) : locked_(false) { imp_ = new Implementation; #ifdef _WINDOWS - std::string final_name = "EQEmuMutex_"; + auto Config = EQEmuConfig::get(); + std::string final_name = Config->SharedMemDir + "EQEmuMutex_"; final_name += name; imp_->mut_ = CreateMutex(nullptr, @@ -52,7 +55,8 @@ namespace EQEmu { EQ_EXCEPT("IPC Mutex", "Could not create mutex."); } #else - std::string final_name = name; + auto Config = EQEmuConfig::get(); + std::string final_name = Config->SharedMemDir + name; final_name += ".lock"; #ifdef __DARWIN diff --git a/common/item.cpp b/common/item.cpp index 3e8be66ca..61e7f926a 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,6 +24,8 @@ #include "shareddb.h" #include "string_util.h" +#include "../common/light_source.h" + #include #include @@ -156,66 +158,66 @@ ItemInst* Inventory::GetItem(int16 slot_id) const ItemInst* result = nullptr; // Cursor - if (slot_id == MainCursor) { + if (slot_id == EQEmu::legacy::SlotCursor) { // Cursor slot result = m_cursor.peek_front(); } // Non bag slots - else if (slot_id >= EmuConstants::TRADE_BEGIN && slot_id <= EmuConstants::TRADE_END) { + else if (slot_id >= EQEmu::legacy::TRADE_BEGIN && slot_id <= EQEmu::legacy::TRADE_END) { result = _GetItem(m_trade, slot_id); } - else if (slot_id >= EmuConstants::SHARED_BANK_BEGIN && slot_id <= EmuConstants::SHARED_BANK_END) { + else if (slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id <= EQEmu::legacy::SHARED_BANK_END) { // Shared Bank slots result = _GetItem(m_shbank, slot_id); } - else if (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) { + else if (slot_id >= EQEmu::legacy::BANK_BEGIN && slot_id <= EQEmu::legacy::BANK_END) { // Bank slots result = _GetItem(m_bank, slot_id); } - else if ((slot_id >= EmuConstants::GENERAL_BEGIN && slot_id <= EmuConstants::GENERAL_END)) { + else if ((slot_id >= EQEmu::legacy::GENERAL_BEGIN && slot_id <= EQEmu::legacy::GENERAL_END)) { // Personal inventory slots result = _GetItem(m_inv, slot_id); } - else if ((slot_id >= EmuConstants::EQUIPMENT_BEGIN && slot_id <= EmuConstants::EQUIPMENT_END) || - (slot_id >= EmuConstants::TRIBUTE_BEGIN && slot_id <= EmuConstants::TRIBUTE_END) || (slot_id == MainPowerSource)) { + else if ((slot_id >= EQEmu::legacy::EQUIPMENT_BEGIN && slot_id <= EQEmu::legacy::EQUIPMENT_END) || + (slot_id >= EQEmu::legacy::TRIBUTE_BEGIN && slot_id <= EQEmu::legacy::TRIBUTE_END) || (slot_id == EQEmu::legacy::SlotPowerSource)) { // Equippable slots (on body) result = _GetItem(m_worn, slot_id); } // Inner bag slots - else if (slot_id >= EmuConstants::TRADE_BAGS_BEGIN && slot_id <= EmuConstants::TRADE_BAGS_END) { + else if (slot_id >= EQEmu::legacy::TRADE_BAGS_BEGIN && slot_id <= EQEmu::legacy::TRADE_BAGS_END) { // Trade bag slots ItemInst* inst = _GetItem(m_trade, Inventory::CalcSlotId(slot_id)); - if (inst && inst->IsType(ItemClassContainer)) { + if (inst && inst->IsClassBag()) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } - else if (slot_id >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) { + else if (slot_id >= EQEmu::legacy::SHARED_BANK_BAGS_BEGIN && slot_id <= EQEmu::legacy::SHARED_BANK_BAGS_END) { // Shared Bank bag slots ItemInst* inst = _GetItem(m_shbank, Inventory::CalcSlotId(slot_id)); - if (inst && inst->IsType(ItemClassContainer)) { + if (inst && inst->IsClassBag()) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } - else if (slot_id >= EmuConstants::BANK_BAGS_BEGIN && slot_id <= EmuConstants::BANK_BAGS_END) { + else if (slot_id >= EQEmu::legacy::BANK_BAGS_BEGIN && slot_id <= EQEmu::legacy::BANK_BAGS_END) { // Bank bag slots ItemInst* inst = _GetItem(m_bank, Inventory::CalcSlotId(slot_id)); - if (inst && inst->IsType(ItemClassContainer)) { + if (inst && inst->IsClassBag()) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } - else if (slot_id >= EmuConstants::CURSOR_BAG_BEGIN && slot_id <= EmuConstants::CURSOR_BAG_END) { + else if (slot_id >= EQEmu::legacy::CURSOR_BAG_BEGIN && slot_id <= EQEmu::legacy::CURSOR_BAG_END) { // Cursor bag slots ItemInst* inst = m_cursor.peek_front(); - if (inst && inst->IsType(ItemClassContainer)) { + if (inst && inst->IsClassBag()) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } - else if (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END) { + else if (slot_id >= EQEmu::legacy::GENERAL_BAGS_BEGIN && slot_id <= EQEmu::legacy::GENERAL_BAGS_END) { // Personal inventory bag slots ItemInst* inst = _GetItem(m_inv, Inventory::CalcSlotId(slot_id)); - if (inst && inst->IsType(ItemClassContainer)) { + if (inst && inst->IsClassBag()) { result = inst->GetItem(Inventory::CalcBagIdx(slot_id)); } } @@ -248,7 +250,7 @@ int16 Inventory::PutItem(int16 slot_id, const ItemInst& inst) int16 Inventory::PushCursor(const ItemInst& inst) { m_cursor.push(inst.Clone()); - return MainCursor; + return EQEmu::legacy::SlotCursor; } ItemInst* Inventory::GetCursorItem() @@ -314,7 +316,7 @@ bool Inventory::CheckNoDrop(int16 slot_id) { if (!inst) return false; if (!inst->GetItem()->NoDrop) return true; if (inst->GetItem()->ItemClass == 1) { - for (uint8 i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) { + for (uint8 i = SUB_INDEX_BEGIN; i < EQEmu::legacy::ITEM_CONTAINER_SIZE; i++) { ItemInst* bagitem = GetItem(Inventory::CalcSlotId(slot_id, i)); if (bagitem && !bagitem->GetItem()->NoDrop) return true; @@ -329,37 +331,37 @@ ItemInst* Inventory::PopItem(int16 slot_id) { ItemInst* p = nullptr; - if (slot_id == MainCursor) { + if (slot_id == EQEmu::legacy::SlotCursor) { p = m_cursor.pop(); } - else if ((slot_id >= EmuConstants::EQUIPMENT_BEGIN && slot_id <= EmuConstants::EQUIPMENT_END) || (slot_id == MainPowerSource)) { + else if ((slot_id >= EQEmu::legacy::EQUIPMENT_BEGIN && slot_id <= EQEmu::legacy::EQUIPMENT_END) || (slot_id == EQEmu::legacy::SlotPowerSource)) { p = m_worn[slot_id]; m_worn.erase(slot_id); } - else if ((slot_id >= EmuConstants::GENERAL_BEGIN && slot_id <= EmuConstants::GENERAL_END)) { + else if ((slot_id >= EQEmu::legacy::GENERAL_BEGIN && slot_id <= EQEmu::legacy::GENERAL_END)) { p = m_inv[slot_id]; m_inv.erase(slot_id); } - else if (slot_id >= EmuConstants::TRIBUTE_BEGIN && slot_id <= EmuConstants::TRIBUTE_END) { + else if (slot_id >= EQEmu::legacy::TRIBUTE_BEGIN && slot_id <= EQEmu::legacy::TRIBUTE_END) { p = m_worn[slot_id]; m_worn.erase(slot_id); } - else if (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) { + else if (slot_id >= EQEmu::legacy::BANK_BEGIN && slot_id <= EQEmu::legacy::BANK_END) { p = m_bank[slot_id]; m_bank.erase(slot_id); } - else if (slot_id >= EmuConstants::SHARED_BANK_BEGIN && slot_id <= EmuConstants::SHARED_BANK_END) { + else if (slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id <= EQEmu::legacy::SHARED_BANK_END) { p = m_shbank[slot_id]; m_shbank.erase(slot_id); } - else if (slot_id >= EmuConstants::TRADE_BEGIN && slot_id <= EmuConstants::TRADE_END) { + else if (slot_id >= EQEmu::legacy::TRADE_BEGIN && slot_id <= EQEmu::legacy::TRADE_END) { p = m_trade[slot_id]; m_trade.erase(slot_id); } else { // Is slot inside bag? ItemInst* baginst = GetItem(Inventory::CalcSlotId(slot_id)); - if (baginst != nullptr && baginst->IsType(ItemClassContainer)) { + if (baginst != nullptr && baginst->IsClassBag()) { p = baginst->PopItem(Inventory::CalcBagIdx(slot_id)); } } @@ -368,11 +370,11 @@ ItemInst* Inventory::PopItem(int16 slot_id) return p; } -bool Inventory::HasSpaceForItem(const Item_Struct *ItemToTry, int16 Quantity) { +bool Inventory::HasSpaceForItem(const EQEmu::ItemBase *ItemToTry, int16 Quantity) { if (ItemToTry->Stackable) { - for (int16 i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { + for (int16 i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; i++) { ItemInst* InvItem = GetItem(i); @@ -386,11 +388,11 @@ bool Inventory::HasSpaceForItem(const Item_Struct *ItemToTry, int16 Quantity) { Quantity -= ChargeSlotsLeft; } - if (InvItem && InvItem->IsType(ItemClassContainer)) { + if (InvItem && InvItem->IsClassBag()) { - int16 BaseSlotID = Inventory::CalcSlotId(i, SUB_BEGIN); + int16 BaseSlotID = Inventory::CalcSlotId(i, SUB_INDEX_BEGIN); uint8 BagSize = InvItem->GetItem()->BagSlots; - for (uint8 BagSlot = SUB_BEGIN; BagSlot < BagSize; BagSlot++) { + for (uint8 BagSlot = SUB_INDEX_BEGIN; BagSlot < BagSize; BagSlot++) { InvItem = GetItem(BaseSlotID + BagSlot); @@ -409,7 +411,7 @@ bool Inventory::HasSpaceForItem(const Item_Struct *ItemToTry, int16 Quantity) { } } - for (int16 i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { + for (int16 i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; i++) { ItemInst* InvItem = GetItem(i); @@ -430,13 +432,13 @@ bool Inventory::HasSpaceForItem(const Item_Struct *ItemToTry, int16 Quantity) { } } - else if (InvItem->IsType(ItemClassContainer) && CanItemFitInContainer(ItemToTry, InvItem->GetItem())) { + else if (InvItem->IsClassBag() && CanItemFitInContainer(ItemToTry, InvItem->GetItem())) { - int16 BaseSlotID = Inventory::CalcSlotId(i, SUB_BEGIN); + int16 BaseSlotID = Inventory::CalcSlotId(i, SUB_INDEX_BEGIN); uint8 BagSize = InvItem->GetItem()->BagSlots; - for (uint8 BagSlot = SUB_BEGIN; BagSlotIsType(ItemClassContainer) && inst->GetItem()->BagSize >= min_size) + if (inst && inst->IsClassBag() && inst->GetItem()->BagSize >= min_size) { - if (inst->GetItem()->BagType == BagTypeQuiver && inst->GetItem()->ItemType != ItemTypeArrow) + if (inst->GetItem()->BagType == EQEmu::item::BagTypeQuiver && inst->GetItem()->ItemType != EQEmu::item::ItemTypeArrow) { continue; } - int16 base_slot_id = Inventory::CalcSlotId(i, SUB_BEGIN); + int16 base_slot_id = Inventory::CalcSlotId(i, SUB_INDEX_BEGIN); uint8 slots = inst->GetItem()->BagSlots; uint8 j; - for (j = SUB_BEGIN; jIsType(ItemClassContainer)) { - for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + if (inst->IsClassBag()) { + for (int16 free_slot = EQEmu::legacy::GENERAL_BEGIN; free_slot <= EQEmu::legacy::GENERAL_END; ++free_slot) { if (!m_inv[free_slot]) return free_slot; } - return MainCursor; // return cursor since bags do not stack and will not fit inside other bags..yet...) + return EQEmu::legacy::SlotCursor; // return cursor since bags do not stack and will not fit inside other bags..yet...) } // step 2: find partial room for stackables if (inst->IsStackable()) { - for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + for (int16 free_slot = EQEmu::legacy::GENERAL_BEGIN; free_slot <= EQEmu::legacy::GENERAL_END; ++free_slot) { const ItemInst* main_inst = m_inv[free_slot]; if (!main_inst) @@ -687,14 +689,14 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { return free_slot; } - for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + for (int16 free_slot = EQEmu::legacy::GENERAL_BEGIN; free_slot <= EQEmu::legacy::GENERAL_END; ++free_slot) { const ItemInst* main_inst = m_inv[free_slot]; if (!main_inst) continue; - if (main_inst->IsType(ItemClassContainer)) { // if item-specific containers already have bad items, we won't fix it here... - for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) { + if (main_inst->IsClassBag()) { // if item-specific containers already have bad items, we won't fix it here... + for (uint8 free_bag_slot = SUB_INDEX_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++free_bag_slot) { const ItemInst* sub_inst = main_inst->GetItem(free_bag_slot); if (!sub_inst) @@ -708,14 +710,14 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { } // step 3a: find room for container-specific items (ItemClassArrow) - if (inst->GetItem()->ItemType == ItemTypeArrow) { - for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + if (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow) { + for (int16 free_slot = EQEmu::legacy::GENERAL_BEGIN; free_slot <= EQEmu::legacy::GENERAL_END; ++free_slot) { const ItemInst* main_inst = m_inv[free_slot]; - if (!main_inst || (main_inst->GetItem()->BagType != BagTypeQuiver) || !main_inst->IsType(ItemClassContainer)) + if (!main_inst || (main_inst->GetItem()->BagType != EQEmu::item::BagTypeQuiver) || !main_inst->IsClassBag()) continue; - for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) { + for (uint8 free_bag_slot = SUB_INDEX_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++free_bag_slot) { if (!main_inst->GetItem(free_bag_slot)) return Inventory::CalcSlotId(free_slot, free_bag_slot); } @@ -723,14 +725,14 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { } // step 3b: find room for container-specific items (ItemClassSmallThrowing) - if (inst->GetItem()->ItemType == ItemTypeSmallThrowing) { - for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + if (inst->GetItem()->ItemType == EQEmu::item::ItemTypeSmallThrowing) { + for (int16 free_slot = EQEmu::legacy::GENERAL_BEGIN; free_slot <= EQEmu::legacy::GENERAL_END; ++free_slot) { const ItemInst* main_inst = m_inv[free_slot]; - if (!main_inst || (main_inst->GetItem()->BagType != BagTypeBandolier) || !main_inst->IsType(ItemClassContainer)) + if (!main_inst || (main_inst->GetItem()->BagType != EQEmu::item::BagTypeBandolier) || !main_inst->IsClassBag()) continue; - for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) { + for (uint8 free_bag_slot = SUB_INDEX_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++free_bag_slot) { if (!main_inst->GetItem(free_bag_slot)) return Inventory::CalcSlotId(free_slot, free_bag_slot); } @@ -738,21 +740,21 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { } // step 4: just find an empty slot - for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + for (int16 free_slot = EQEmu::legacy::GENERAL_BEGIN; free_slot <= EQEmu::legacy::GENERAL_END; ++free_slot) { const ItemInst* main_inst = m_inv[free_slot]; if (!main_inst) return free_slot; } - for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) { + for (int16 free_slot = EQEmu::legacy::GENERAL_BEGIN; free_slot <= EQEmu::legacy::GENERAL_END; ++free_slot) { const ItemInst* main_inst = m_inv[free_slot]; - if (main_inst && main_inst->IsType(ItemClassContainer)) { - if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == BagTypeBandolier) || (main_inst->GetItem()->BagType == BagTypeQuiver)) + if (main_inst && main_inst->IsClassBag()) { + if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == EQEmu::item::BagTypeBandolier) || (main_inst->GetItem()->BagType == EQEmu::item::BagTypeQuiver)) continue; - for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) { + for (uint8 free_bag_slot = SUB_INDEX_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++free_bag_slot) { if (!main_inst->GetItem(free_bag_slot)) return Inventory::CalcSlotId(free_slot, free_bag_slot); } @@ -760,7 +762,7 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) { } //return INVALID_INDEX; // everything else pushes to the cursor - return MainCursor; + return EQEmu::legacy::SlotCursor; } // Opposite of below: Get parent bag slot_id from a slot inside of bag @@ -772,20 +774,20 @@ int16 Inventory::CalcSlotId(int16 slot_id) { // parent_slot_id = EmuConstants::BANK_BEGIN + (slot_id - EmuConstants::BANK_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; //else if (slot_id >= 3100 && slot_id <= 3179) should be {3031..3110}..where did this range come from!!? (verified db save range) - if (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END) { - parent_slot_id = EmuConstants::GENERAL_BEGIN + (slot_id - EmuConstants::GENERAL_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; + if (slot_id >= EQEmu::legacy::GENERAL_BAGS_BEGIN && slot_id <= EQEmu::legacy::GENERAL_BAGS_END) { + parent_slot_id = EQEmu::legacy::GENERAL_BEGIN + (slot_id - EQEmu::legacy::GENERAL_BAGS_BEGIN) / EQEmu::legacy::ITEM_CONTAINER_SIZE; } - else if (slot_id >= EmuConstants::CURSOR_BAG_BEGIN && slot_id <= EmuConstants::CURSOR_BAG_END) { - parent_slot_id = MainCursor; + else if (slot_id >= EQEmu::legacy::CURSOR_BAG_BEGIN && slot_id <= EQEmu::legacy::CURSOR_BAG_END) { + parent_slot_id = EQEmu::legacy::SlotCursor; } - else if (slot_id >= EmuConstants::BANK_BAGS_BEGIN && slot_id <= EmuConstants::BANK_BAGS_END) { - parent_slot_id = EmuConstants::BANK_BEGIN + (slot_id - EmuConstants::BANK_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; + else if (slot_id >= EQEmu::legacy::BANK_BAGS_BEGIN && slot_id <= EQEmu::legacy::BANK_BAGS_END) { + parent_slot_id = EQEmu::legacy::BANK_BEGIN + (slot_id - EQEmu::legacy::BANK_BAGS_BEGIN) / EQEmu::legacy::ITEM_CONTAINER_SIZE; } - else if (slot_id >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) { - parent_slot_id = EmuConstants::SHARED_BANK_BEGIN + (slot_id - EmuConstants::SHARED_BANK_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; + else if (slot_id >= EQEmu::legacy::SHARED_BANK_BAGS_BEGIN && slot_id <= EQEmu::legacy::SHARED_BANK_BAGS_END) { + parent_slot_id = EQEmu::legacy::SHARED_BANK_BEGIN + (slot_id - EQEmu::legacy::SHARED_BANK_BAGS_BEGIN) / EQEmu::legacy::ITEM_CONTAINER_SIZE; } - else if (slot_id >= EmuConstants::TRADE_BAGS_BEGIN && slot_id <= EmuConstants::TRADE_BAGS_END) { - parent_slot_id = EmuConstants::TRADE_BEGIN + (slot_id - EmuConstants::TRADE_BAGS_BEGIN) / EmuConstants::ITEM_CONTAINER_SIZE; + else if (slot_id >= EQEmu::legacy::TRADE_BAGS_BEGIN && slot_id <= EQEmu::legacy::TRADE_BAGS_END) { + parent_slot_id = EQEmu::legacy::TRADE_BEGIN + (slot_id - EQEmu::legacy::TRADE_BAGS_BEGIN) / EQEmu::legacy::ITEM_CONTAINER_SIZE; } return parent_slot_id; @@ -798,20 +800,20 @@ int16 Inventory::CalcSlotId(int16 bagslot_id, uint8 bagidx) { int16 slot_id = INVALID_INDEX; - if (bagslot_id == MainCursor || bagslot_id == 8000) { - slot_id = EmuConstants::CURSOR_BAG_BEGIN + bagidx; + if (bagslot_id == EQEmu::legacy::SlotCursor || bagslot_id == 8000) { + slot_id = EQEmu::legacy::CURSOR_BAG_BEGIN + bagidx; } - else if (bagslot_id >= EmuConstants::GENERAL_BEGIN && bagslot_id <= EmuConstants::GENERAL_END) { - slot_id = EmuConstants::GENERAL_BAGS_BEGIN + (bagslot_id - EmuConstants::GENERAL_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE + bagidx; + else if (bagslot_id >= EQEmu::legacy::GENERAL_BEGIN && bagslot_id <= EQEmu::legacy::GENERAL_END) { + slot_id = EQEmu::legacy::GENERAL_BAGS_BEGIN + (bagslot_id - EQEmu::legacy::GENERAL_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE + bagidx; } - else if (bagslot_id >= EmuConstants::BANK_BEGIN && bagslot_id <= EmuConstants::BANK_END) { - slot_id = EmuConstants::BANK_BAGS_BEGIN + (bagslot_id - EmuConstants::BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE + bagidx; + else if (bagslot_id >= EQEmu::legacy::BANK_BEGIN && bagslot_id <= EQEmu::legacy::BANK_END) { + slot_id = EQEmu::legacy::BANK_BAGS_BEGIN + (bagslot_id - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE + bagidx; } - else if (bagslot_id >= EmuConstants::SHARED_BANK_BEGIN && bagslot_id <= EmuConstants::SHARED_BANK_END) { - slot_id = EmuConstants::SHARED_BANK_BAGS_BEGIN + (bagslot_id - EmuConstants::SHARED_BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE + bagidx; + else if (bagslot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && bagslot_id <= EQEmu::legacy::SHARED_BANK_END) { + slot_id = EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + (bagslot_id - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE + bagidx; } - else if (bagslot_id >= EmuConstants::TRADE_BEGIN && bagslot_id <= EmuConstants::TRADE_END) { - slot_id = EmuConstants::TRADE_BAGS_BEGIN + (bagslot_id - EmuConstants::TRADE_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE + bagidx; + else if (bagslot_id >= EQEmu::legacy::TRADE_BEGIN && bagslot_id <= EQEmu::legacy::TRADE_END) { + slot_id = EQEmu::legacy::TRADE_BAGS_BEGIN + (bagslot_id - EQEmu::legacy::TRADE_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE + bagidx; } return slot_id; @@ -824,23 +826,23 @@ uint8 Inventory::CalcBagIdx(int16 slot_id) { //else if (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) // index = (slot_id - EmuConstants::BANK_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; - if (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END) { - index = (slot_id - EmuConstants::GENERAL_BAGS_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; + if (slot_id >= EQEmu::legacy::GENERAL_BAGS_BEGIN && slot_id <= EQEmu::legacy::GENERAL_BAGS_END) { + index = (slot_id - EQEmu::legacy::GENERAL_BAGS_BEGIN) % EQEmu::legacy::ITEM_CONTAINER_SIZE; } - else if (slot_id >= EmuConstants::CURSOR_BAG_BEGIN && slot_id <= EmuConstants::CURSOR_BAG_END) { - index = (slot_id - EmuConstants::CURSOR_BAG_BEGIN); // % EmuConstants::ITEM_CONTAINER_SIZE; - not needed since range is 10 slots + else if (slot_id >= EQEmu::legacy::CURSOR_BAG_BEGIN && slot_id <= EQEmu::legacy::CURSOR_BAG_END) { + index = (slot_id - EQEmu::legacy::CURSOR_BAG_BEGIN); // % EQEmu::legacy::ITEM_CONTAINER_SIZE; - not needed since range is 10 slots } - else if (slot_id >= EmuConstants::BANK_BAGS_BEGIN && slot_id <= EmuConstants::BANK_BAGS_END) { - index = (slot_id - EmuConstants::BANK_BAGS_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; + else if (slot_id >= EQEmu::legacy::BANK_BAGS_BEGIN && slot_id <= EQEmu::legacy::BANK_BAGS_END) { + index = (slot_id - EQEmu::legacy::BANK_BAGS_BEGIN) % EQEmu::legacy::ITEM_CONTAINER_SIZE; } - else if (slot_id >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) { - index = (slot_id - EmuConstants::SHARED_BANK_BAGS_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; + else if (slot_id >= EQEmu::legacy::SHARED_BANK_BAGS_BEGIN && slot_id <= EQEmu::legacy::SHARED_BANK_BAGS_END) { + index = (slot_id - EQEmu::legacy::SHARED_BANK_BAGS_BEGIN) % EQEmu::legacy::ITEM_CONTAINER_SIZE; } - else if (slot_id >= EmuConstants::TRADE_BAGS_BEGIN && slot_id <= EmuConstants::TRADE_BAGS_END) { - index = (slot_id - EmuConstants::TRADE_BAGS_BEGIN) % EmuConstants::ITEM_CONTAINER_SIZE; + else if (slot_id >= EQEmu::legacy::TRADE_BAGS_BEGIN && slot_id <= EQEmu::legacy::TRADE_BAGS_END) { + index = (slot_id - EQEmu::legacy::TRADE_BAGS_BEGIN) % EQEmu::legacy::ITEM_CONTAINER_SIZE; } - else if (slot_id >= EmuConstants::WORLD_BEGIN && slot_id <= EmuConstants::WORLD_END) { - index = (slot_id - EmuConstants::WORLD_BEGIN); // % EmuConstants::ITEM_CONTAINER_SIZE; - not needed since range is 10 slots + else if (slot_id >= EQEmu::legacy::WORLD_BEGIN && slot_id <= EQEmu::legacy::WORLD_END) { + index = (slot_id - EQEmu::legacy::WORLD_BEGIN); // % EQEmu::legacy::ITEM_CONTAINER_SIZE; - not needed since range is 10 slots } return index; @@ -850,24 +852,24 @@ int16 Inventory::CalcSlotFromMaterial(uint8 material) { switch (material) { - case MaterialHead: - return MainHead; - case MaterialChest: - return MainChest; - case MaterialArms: - return MainArms; - case MaterialWrist: - return MainWrist1; // there's 2 bracers, only one bracer material - case MaterialHands: - return MainHands; - case MaterialLegs: - return MainLegs; - case MaterialFeet: - return MainFeet; - case MaterialPrimary: - return MainPrimary; - case MaterialSecondary: - return MainSecondary; + case EQEmu::textures::TextureHead: + return EQEmu::legacy::SlotHead; + case EQEmu::textures::TextureChest: + return EQEmu::legacy::SlotChest; + case EQEmu::textures::TextureArms: + return EQEmu::legacy::SlotArms; + case EQEmu::textures::TextureWrist: + return EQEmu::legacy::SlotWrist1; // there's 2 bracers, only one bracer material + case EQEmu::textures::TextureHands: + return EQEmu::legacy::SlotHands; + case EQEmu::textures::TextureLegs: + return EQEmu::legacy::SlotLegs; + case EQEmu::textures::TextureFeet: + return EQEmu::legacy::SlotFeet; + case EQEmu::textures::TexturePrimary: + return EQEmu::legacy::SlotPrimary; + case EQEmu::textures::TextureSecondary: + return EQEmu::legacy::SlotSecondary; default: return INVALID_INDEX; } @@ -877,31 +879,31 @@ uint8 Inventory::CalcMaterialFromSlot(int16 equipslot) { switch (equipslot) { - case MainHead: - return MaterialHead; - case MainChest: - return MaterialChest; - case MainArms: - return MaterialArms; - case MainWrist1: + case EQEmu::legacy::SlotHead: + return EQEmu::textures::TextureHead; + case EQEmu::legacy::SlotChest: + return EQEmu::textures::TextureChest; + case EQEmu::legacy::SlotArms: + return EQEmu::textures::TextureArms; + case EQEmu::legacy::SlotWrist1: //case SLOT_BRACER02: // non-live behavior - return MaterialWrist; - case MainHands: - return MaterialHands; - case MainLegs: - return MaterialLegs; - case MainFeet: - return MaterialFeet; - case MainPrimary: - return MaterialPrimary; - case MainSecondary: - return MaterialSecondary; + return EQEmu::textures::TextureWrist; + case EQEmu::legacy::SlotHands: + return EQEmu::textures::TextureHands; + case EQEmu::legacy::SlotLegs: + return EQEmu::textures::TextureLegs; + case EQEmu::legacy::SlotFeet: + return EQEmu::textures::TextureFeet; + case EQEmu::legacy::SlotPrimary: + return EQEmu::textures::TexturePrimary; + case EQEmu::legacy::SlotSecondary: + return EQEmu::textures::TextureSecondary; default: - return _MaterialInvalid; + return EQEmu::textures::TextureInvalid; } } -bool Inventory::CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_Struct *Container) { +bool Inventory::CanItemFitInContainer(const EQEmu::ItemBase *ItemToTry, const EQEmu::ItemBase *Container) { if (!ItemToTry || !Container) return false; @@ -909,10 +911,10 @@ bool Inventory::CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_S if (ItemToTry->Size > Container->BagSize) return false; - if ((Container->BagType == BagTypeQuiver) && (ItemToTry->ItemType != ItemTypeArrow)) + if ((Container->BagType == EQEmu::item::BagTypeQuiver) && (ItemToTry->ItemType != EQEmu::item::ItemTypeArrow)) return false; - if ((Container->BagType == BagTypeBandolier) && (ItemToTry->ItemType != ItemTypeSmallThrowing)) + if ((Container->BagType == EQEmu::item::BagTypeBandolier) && (ItemToTry->ItemType != EQEmu::item::ItemTypeSmallThrowing)) return false; return true; @@ -921,13 +923,13 @@ bool Inventory::CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_S bool Inventory::SupportsClickCasting(int16 slot_id) { // there are a few non-potion items that identify as ItemTypePotion..so, we still need to ubiquitously include the equipment range - if ((uint16)slot_id <= EmuConstants::GENERAL_END || slot_id == MainPowerSource) + if ((uint16)slot_id <= EQEmu::legacy::GENERAL_END || slot_id == EQEmu::legacy::SlotPowerSource) { return true; } - else if (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END) + else if (slot_id >= EQEmu::legacy::GENERAL_BAGS_BEGIN && slot_id <= EQEmu::legacy::GENERAL_BAGS_END) { - if (EQLimits::AllowsClickCastFromBag(m_version)) + if (EQEmu::inventory::Lookup(m_inventory_version)->AllowClickCastFromBag) return true; } @@ -936,7 +938,7 @@ bool Inventory::SupportsClickCasting(int16 slot_id) bool Inventory::SupportsPotionBeltCasting(int16 slot_id) { - if ((uint16)slot_id <= EmuConstants::GENERAL_END || slot_id == MainPowerSource || (slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && slot_id <= EmuConstants::GENERAL_BAGS_END)) + if ((uint16)slot_id <= EQEmu::legacy::GENERAL_END || slot_id == EQEmu::legacy::SlotPowerSource || (slot_id >= EQEmu::legacy::GENERAL_BAGS_BEGIN && slot_id <= EQEmu::legacy::GENERAL_BAGS_END)) return true; return false; @@ -945,11 +947,11 @@ bool Inventory::SupportsPotionBeltCasting(int16 slot_id) // Test whether a given slot can support a container item bool Inventory::SupportsContainers(int16 slot_id) { - if ((slot_id == MainCursor) || - (slot_id >= EmuConstants::GENERAL_BEGIN && slot_id <= EmuConstants::GENERAL_END) || - (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) || - (slot_id >= EmuConstants::SHARED_BANK_BEGIN && slot_id <= EmuConstants::SHARED_BANK_END) || - (slot_id >= EmuConstants::TRADE_BEGIN && slot_id <= EmuConstants::TRADE_END) + if ((slot_id == EQEmu::legacy::SlotCursor) || + (slot_id >= EQEmu::legacy::GENERAL_BEGIN && slot_id <= EQEmu::legacy::GENERAL_END) || + (slot_id >= EQEmu::legacy::BANK_BEGIN && slot_id <= EQEmu::legacy::BANK_END) || + (slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id <= EQEmu::legacy::SHARED_BANK_END) || + (slot_id >= EQEmu::legacy::TRADE_BEGIN && slot_id <= EQEmu::legacy::TRADE_END) ) { return true; } @@ -987,7 +989,7 @@ int Inventory::GetSlotByItemInst(ItemInst *inst) { } if (m_cursor.peek_front() == inst) { - return MainCursor; + return EQEmu::legacy::SlotCursor; } return INVALID_INDEX; @@ -998,35 +1000,35 @@ uint8 Inventory::FindBrightestLightType() uint8 brightest_light_type = 0; for (auto iter = m_worn.begin(); iter != m_worn.end(); ++iter) { - if ((iter->first < EmuConstants::EQUIPMENT_BEGIN || iter->first > EmuConstants::EQUIPMENT_END) && iter->first != MainPowerSource) { continue; } - if (iter->first == MainAmmo) { continue; } + if ((iter->first < EQEmu::legacy::EQUIPMENT_BEGIN || iter->first > EQEmu::legacy::EQUIPMENT_END) && iter->first != EQEmu::legacy::SlotPowerSource) { continue; } + if (iter->first == EQEmu::legacy::SlotAmmo) { continue; } auto inst = iter->second; if (inst == nullptr) { continue; } auto item = inst->GetItem(); if (item == nullptr) { continue; } - if (LightProfile_Struct::IsLevelGreater(item->Light, brightest_light_type)) + if (EQEmu::lightsource::IsLevelGreater(item->Light, brightest_light_type)) brightest_light_type = item->Light; } uint8 general_light_type = 0; for (auto iter = m_inv.begin(); iter != m_inv.end(); ++iter) { - if (iter->first < EmuConstants::GENERAL_BEGIN || iter->first > EmuConstants::GENERAL_END) { continue; } + if (iter->first < EQEmu::legacy::GENERAL_BEGIN || iter->first > EQEmu::legacy::GENERAL_END) { continue; } auto inst = iter->second; if (inst == nullptr) { continue; } auto item = inst->GetItem(); if (item == nullptr) { continue; } - if (item->ItemClass != ItemClassCommon) { continue; } + if (!item->IsClassCommon()) { continue; } if (item->Light < 9 || item->Light > 13) { continue; } - if (LightProfile_Struct::TypeToLevel(item->Light)) + if (EQEmu::lightsource::TypeToLevel(item->Light)) general_light_type = item->Light; } - if (LightProfile_Struct::IsLevelGreater(general_light_type, brightest_light_type)) + if (EQEmu::lightsource::IsLevelGreater(general_light_type, brightest_light_type)) brightest_light_type = general_light_type; return brightest_light_type; @@ -1071,7 +1073,7 @@ int Inventory::GetSlotByItemInstCollection(const std::map &col return iter->first; } - if (t_inst && !t_inst->IsType(ItemClassContainer)) { + if (t_inst && !t_inst->IsClassBag()) { for (auto b_iter = t_inst->_cbegin(); b_iter != t_inst->_cend(); ++b_iter) { if (b_iter->second == inst) { return Inventory::CalcSlotId(iter->first, b_iter->first); @@ -1099,7 +1101,7 @@ void Inventory::dumpItemCollection(const std::map &collection) void Inventory::dumpBagContents(ItemInst *inst, std::map::const_iterator *it) { - if (!inst || !inst->IsType(ItemClassContainer)) + if (!inst || !inst->IsClassBag()) return; // Go through bag, if bag @@ -1143,33 +1145,33 @@ int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst) int16 result = INVALID_INDEX; int16 parentSlot = INVALID_INDEX; - if (slot_id == MainCursor) { + if (slot_id == EQEmu::legacy::SlotCursor) { // Replace current item on cursor, if exists m_cursor.pop(); // no memory delete, clients of this function know what they are doing m_cursor.push_front(inst); result = slot_id; } - else if ((slot_id >= EmuConstants::EQUIPMENT_BEGIN && slot_id <= EmuConstants::EQUIPMENT_END) || (slot_id == MainPowerSource)) { + else if ((slot_id >= EQEmu::legacy::EQUIPMENT_BEGIN && slot_id <= EQEmu::legacy::EQUIPMENT_END) || (slot_id == EQEmu::legacy::SlotPowerSource)) { m_worn[slot_id] = inst; result = slot_id; } - else if ((slot_id >= EmuConstants::GENERAL_BEGIN && slot_id <= EmuConstants::GENERAL_END)) { + else if ((slot_id >= EQEmu::legacy::GENERAL_BEGIN && slot_id <= EQEmu::legacy::GENERAL_END)) { m_inv[slot_id] = inst; result = slot_id; } - else if (slot_id >= EmuConstants::TRIBUTE_BEGIN && slot_id <= EmuConstants::TRIBUTE_END) { + else if (slot_id >= EQEmu::legacy::TRIBUTE_BEGIN && slot_id <= EQEmu::legacy::TRIBUTE_END) { m_worn[slot_id] = inst; result = slot_id; } - else if (slot_id >= EmuConstants::BANK_BEGIN && slot_id <= EmuConstants::BANK_END) { + else if (slot_id >= EQEmu::legacy::BANK_BEGIN && slot_id <= EQEmu::legacy::BANK_END) { m_bank[slot_id] = inst; result = slot_id; } - else if (slot_id >= EmuConstants::SHARED_BANK_BEGIN && slot_id <= EmuConstants::SHARED_BANK_END) { + else if (slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id <= EQEmu::legacy::SHARED_BANK_END) { m_shbank[slot_id] = inst; result = slot_id; } - else if (slot_id >= EmuConstants::TRADE_BEGIN && slot_id <= EmuConstants::TRADE_END) { + else if (slot_id >= EQEmu::legacy::TRADE_BEGIN && slot_id <= EQEmu::legacy::TRADE_END) { m_trade[slot_id] = inst; result = slot_id; } @@ -1177,7 +1179,7 @@ int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst) // Slot must be within a bag parentSlot = Inventory::CalcSlotId(slot_id); ItemInst* baginst = GetItem(parentSlot); // Get parent bag - if (baginst && baginst->IsType(ItemClassContainer)) + if (baginst && baginst->IsClassBag()) { baginst->_PutItem(Inventory::CalcBagIdx(slot_id), inst); result = slot_id; @@ -1195,7 +1197,7 @@ int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst) // Internal Method: Checks an inventory bucket for a particular item int16 Inventory::_HasItem(std::map& bucket, uint32 item_id, uint8 quantity) { - uint8 quantity_found = 0; + uint32 quantity_found = 0; for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) { auto inst = iter->second; @@ -1207,12 +1209,12 @@ int16 Inventory::_HasItem(std::map& bucket, uint32 item_id, ui return iter->first; } - for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = AUG_INDEX_BEGIN; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { if (inst->GetAugmentItemID(index) == item_id && quantity <= 1) - return legacy::SLOT_AUGMENT; + return EQEmu::legacy::SLOT_AUGMENT; } - if (!inst->IsType(ItemClassContainer)) { continue; } + if (!inst->IsClassBag()) { continue; } for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; @@ -1224,9 +1226,9 @@ int16 Inventory::_HasItem(std::map& bucket, uint32 item_id, ui return Inventory::CalcSlotId(iter->first, bag_iter->first); } - for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = AUG_INDEX_BEGIN; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { if (bag_inst->GetAugmentItemID(index) == item_id && quantity <= 1) - return legacy::SLOT_AUGMENT; + return EQEmu::legacy::SLOT_AUGMENT; } } } @@ -1243,7 +1245,7 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) // to unintended results. Funtionality should be observed when referencing the return value // of this query - uint8 quantity_found = 0; + uint32 quantity_found = 0; for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) { auto inst = *iter; @@ -1252,15 +1254,15 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) if (inst->GetID() == item_id) { quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) - return MainCursor; + return EQEmu::legacy::SlotCursor; } - for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = AUG_INDEX_BEGIN; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { if (inst->GetAugmentItemID(index) == item_id && quantity <= 1) - return legacy::SLOT_AUGMENT; + return EQEmu::legacy::SLOT_AUGMENT; } - if (!inst->IsType(ItemClassContainer)) { continue; } + if (!inst->IsClassBag()) { continue; } for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; @@ -1269,12 +1271,12 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) if (bag_inst->GetID() == item_id) { quantity_found += (bag_inst->GetCharges() <= 0) ? 1 : bag_inst->GetCharges(); if (quantity_found >= quantity) - return Inventory::CalcSlotId(MainCursor, bag_iter->first); + return Inventory::CalcSlotId(EQEmu::legacy::SlotCursor, bag_iter->first); } - for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = AUG_INDEX_BEGIN; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { if (bag_inst->GetAugmentItemID(index) == item_id && quantity <= 1) - return legacy::SLOT_AUGMENT; + return EQEmu::legacy::SLOT_AUGMENT; } } @@ -1288,25 +1290,25 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) // Internal Method: Checks an inventory bucket for a particular item int16 Inventory::_HasItemByUse(std::map& bucket, uint8 use, uint8 quantity) { - uint8 quantity_found = 0; + uint32 quantity_found = 0; for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) { auto inst = iter->second; if (inst == nullptr) { continue; } - if (inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) { + if (inst->IsClassCommon() && inst->GetItem()->ItemType == use) { quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) return iter->first; } - if (!inst->IsType(ItemClassContainer)) { continue; } + if (!inst->IsClassBag()) { continue; } for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } - if (bag_inst->IsType(ItemClassCommon) && bag_inst->GetItem()->ItemType == use) { + if (bag_inst->IsClassCommon() && bag_inst->GetItem()->ItemType == use) { quantity_found += (bag_inst->GetCharges() <= 0) ? 1 : bag_inst->GetCharges(); if (quantity_found >= quantity) return Inventory::CalcSlotId(iter->first, bag_iter->first); @@ -1320,28 +1322,28 @@ int16 Inventory::_HasItemByUse(std::map& bucket, uint8 use, ui // Internal Method: Checks an inventory queue type bucket for a particular item int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity) { - uint8 quantity_found = 0; + uint32 quantity_found = 0; for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) { auto inst = *iter; if (inst == nullptr) { continue; } - if (inst->IsType(ItemClassCommon) && inst->GetItem()->ItemType == use) { + if (inst->IsClassCommon() && inst->GetItem()->ItemType == use) { quantity_found += (inst->GetCharges() <= 0) ? 1 : inst->GetCharges(); if (quantity_found >= quantity) - return MainCursor; + return EQEmu::legacy::SlotCursor; } - if (!inst->IsType(ItemClassContainer)) { continue; } + if (!inst->IsClassBag()) { continue; } for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } - if (bag_inst->IsType(ItemClassCommon) && bag_inst->GetItem()->ItemType == use) { + if (bag_inst->IsClassCommon() && bag_inst->GetItem()->ItemType == use) { quantity_found += (bag_inst->GetCharges() <= 0) ? 1 : bag_inst->GetCharges(); if (quantity_found >= quantity) - return Inventory::CalcSlotId(MainCursor, bag_iter->first); + return Inventory::CalcSlotId(EQEmu::legacy::SlotCursor, bag_iter->first); } } @@ -1361,29 +1363,29 @@ int16 Inventory::_HasItemByLoreGroup(std::map& bucket, uint32 if (inst->GetItem()->LoreGroup == loregroup) return iter->first; - for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = AUG_INDEX_BEGIN; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { auto aug_inst = inst->GetAugment(index); if (aug_inst == nullptr) { continue; } if (aug_inst->GetItem()->LoreGroup == loregroup) - return legacy::SLOT_AUGMENT; + return EQEmu::legacy::SLOT_AUGMENT; } - if (!inst->IsType(ItemClassContainer)) { continue; } + if (!inst->IsClassBag()) { continue; } for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } - if (bag_inst->IsType(ItemClassCommon) && bag_inst->GetItem()->LoreGroup == loregroup) + if (bag_inst->IsClassCommon() && bag_inst->GetItem()->LoreGroup == loregroup) return Inventory::CalcSlotId(iter->first, bag_iter->first); - for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = AUG_INDEX_BEGIN; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { auto aug_inst = bag_inst->GetAugment(index); if (aug_inst == nullptr) { continue; } if (aug_inst->GetItem()->LoreGroup == loregroup) - return legacy::SLOT_AUGMENT; + return EQEmu::legacy::SLOT_AUGMENT; } } } @@ -1399,31 +1401,31 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) if (inst == nullptr) { continue; } if (inst->GetItem()->LoreGroup == loregroup) - return MainCursor; + return EQEmu::legacy::SlotCursor; - for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = AUG_INDEX_BEGIN; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { auto aug_inst = inst->GetAugment(index); if (aug_inst == nullptr) { continue; } if (aug_inst->GetItem()->LoreGroup == loregroup) - return legacy::SLOT_AUGMENT; + return EQEmu::legacy::SLOT_AUGMENT; } - if (!inst->IsType(ItemClassContainer)) { continue; } + if (!inst->IsClassBag()) { continue; } for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } - if (bag_inst->IsType(ItemClassCommon) && bag_inst->GetItem()->LoreGroup == loregroup) - return Inventory::CalcSlotId(MainCursor, bag_iter->first); + if (bag_inst->IsClassCommon() && bag_inst->GetItem()->LoreGroup == loregroup) + return Inventory::CalcSlotId(EQEmu::legacy::SlotCursor, bag_iter->first); - for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = AUG_INDEX_BEGIN; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { auto aug_inst = bag_inst->GetAugment(index); if (aug_inst == nullptr) { continue; } if (aug_inst->GetItem()->LoreGroup == loregroup) - return legacy::SLOT_AUGMENT; + return EQEmu::legacy::SLOT_AUGMENT; } } @@ -1438,14 +1440,18 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) // // class ItemInst // -ItemInst::ItemInst(const Item_Struct* item, int16 charges) { +ItemInst::ItemInst(const EQEmu::ItemBase* item, int16 charges) { m_use_type = ItemInstNormal; - m_item = item; + if(item) { + m_item = new EQEmu::ItemBase(*item); + } else { + m_item = nullptr; + } m_charges = charges; m_price = 0; m_attuned = false; m_merchantslot = 0; - if(m_item &&m_item->ItemClass == ItemClassCommon) + if (m_item && m_item->IsClassCommon()) m_color = m_item->Color; else m_color = 0; @@ -1467,11 +1473,18 @@ ItemInst::ItemInst(const Item_Struct* item, int16 charges) { ItemInst::ItemInst(SharedDatabase *db, uint32 item_id, int16 charges) { m_use_type = ItemInstNormal; m_item = db->GetItem(item_id); + if(m_item) { + m_item = new EQEmu::ItemBase(*m_item); + } + else { + m_item = nullptr; + } + m_charges = charges; m_price = 0; m_merchantslot = 0; m_attuned=false; - if(m_item && m_item->ItemClass == ItemClassCommon) + if (m_item && m_item->IsClassCommon()) m_color = m_item->Color; else m_color = 0; @@ -1515,7 +1528,11 @@ ItemInst::ItemInst(ItemInstTypes use_type) { ItemInst::ItemInst(const ItemInst& copy) { m_use_type=copy.m_use_type; - m_item=copy.m_item; + if(copy.m_item) + m_item = new EQEmu::ItemBase(*copy.m_item); + else + m_item = nullptr; + m_charges=copy.m_charges; m_price=copy.m_price; m_color=copy.m_color; @@ -1548,7 +1565,7 @@ ItemInst::ItemInst(const ItemInst& copy) m_evolveLvl = copy.m_evolveLvl; m_activated = copy.m_activated; if (copy.m_scaledItem) - m_scaledItem = new Item_Struct(*copy.m_scaledItem); + m_scaledItem = new EQEmu::ItemBase(*copy.m_scaledItem); else m_scaledItem = nullptr; @@ -1568,17 +1585,18 @@ ItemInst::ItemInst(const ItemInst& copy) ItemInst::~ItemInst() { Clear(); + safe_delete(m_item); safe_delete(m_scaledItem); safe_delete(m_evolveInfo); } // Query item type -bool ItemInst::IsType(ItemClassTypes item_class) const +bool ItemInst::IsType(EQEmu::item::ItemClass item_class) const { // IsType() does not protect against 'm_item = nullptr' // Check usage type - if ((m_use_type == ItemInstWorldContainer) && (item_class == ItemClassContainer)) + if ((m_use_type == ItemInstWorldContainer) && (item_class == EQEmu::item::ItemClassBag)) return true; if (!m_item) @@ -1587,6 +1605,21 @@ bool ItemInst::IsType(ItemClassTypes item_class) const return (m_item->ItemClass == item_class); } +bool ItemInst::IsClassCommon() +{ + return (m_item && m_item->IsClassCommon()); +} + +bool ItemInst::IsClassBag() +{ + return (m_item && m_item->IsClassBag()); +} + +bool ItemInst::IsClassBook() +{ + return (m_item && m_item->IsClassBook()); +} + // Is item stackable? bool ItemInst::IsStackable() const { @@ -1624,8 +1657,8 @@ bool ItemInst::IsEquipable(int16 slot_id) const // another "shouldn't do" fix..will be fixed in future updates (requires code and database work) int16 use_slot = INVALID_INDEX; - if (slot_id == MainPowerSource) { use_slot = MainGeneral1; } - if ((uint16)slot_id <= EmuConstants::EQUIPMENT_END) { use_slot = slot_id; } + if (slot_id == EQEmu::legacy::SlotPowerSource) { use_slot = EQEmu::legacy::SlotGeneral1; } + if ((uint16)slot_id <= EQEmu::legacy::EQUIPMENT_END) { use_slot = slot_id; } if (use_slot != INVALID_INDEX) { if (m_item->Slots & (1 << use_slot)) @@ -1640,7 +1673,7 @@ bool ItemInst::IsAugmentable() const if (!m_item) return false; - for (int index = 0; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = 0; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { if (m_item->AugSlotType[index] != NO_ITEM) return true; } @@ -1651,11 +1684,11 @@ bool ItemInst::IsAugmentable() const bool ItemInst::AvailableWearSlot(uint32 aug_wear_slots) const { // TODO: check to see if incoming 'aug_wear_slots' "switches" bit assignments like above... // (if wrong, would only affect MainAmmo and MainPowerSource augments) - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return false; - int index = EmuConstants::EQUIPMENT_BEGIN; - for (; index <= MainGeneral1; ++index) { // MainGeneral1 should be EmuConstants::EQUIPMENT_END + int index = EQEmu::legacy::EQUIPMENT_BEGIN; + for (; index <= EQEmu::legacy::SlotGeneral1; ++index) { // MainGeneral1 should be EQEmu::legacy::EQUIPMENT_END if (m_item->Slots & (1 << index)) { if (aug_wear_slots & (1 << index)) break; @@ -1667,22 +1700,22 @@ bool ItemInst::AvailableWearSlot(uint32 aug_wear_slots) const { int8 ItemInst::AvailableAugmentSlot(int32 augtype) const { - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return INVALID_INDEX; - int index = AUG_BEGIN; - for (; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + int index = AUG_INDEX_BEGIN; + for (; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { if (GetItem(index)) { continue; } if (augtype == -1 || (m_item->AugSlotType[index] && ((1 << (m_item->AugSlotType[index] - 1)) & augtype))) break; } - return (index < EmuConstants::ITEM_COMMON_SIZE) ? index : INVALID_INDEX; + return (index < EQEmu::legacy::ITEM_COMMON_SIZE) ? index : INVALID_INDEX; } bool ItemInst::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const { - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return false; if ((!GetItem(slot) && m_item->AugSlotVisible[slot]) && augtype == -1 || (m_item->AugSlotType[slot] && ((1 << (m_item->AugSlotType[slot] - 1)) & augtype))) { @@ -1767,7 +1800,7 @@ void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent) continue; } - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); if (item == nullptr) { cur = m_contents.erase(cur); continue; @@ -1820,7 +1853,7 @@ uint8 ItemInst::FirstOpenSlot() const return INVALID_INDEX; uint8 slots = m_item->BagSlots, i; - for (i = SUB_BEGIN; i < slots; i++) { + for (i = SUB_INDEX_BEGIN; i < slots; i++) { if (!GetItem(i)) break; } @@ -1830,21 +1863,24 @@ uint8 ItemInst::FirstOpenSlot() const uint8 ItemInst::GetTotalItemCount() const { + if (!m_item) + return 0; + uint8 item_count = 1; - if (m_item && m_item->ItemClass != ItemClassContainer) { return item_count; } + if (m_item && !m_item->IsClassBag()) { return item_count; } - for (int index = SUB_BEGIN; index < m_item->BagSlots; ++index) { if (GetItem(index)) { ++item_count; } } + for (int index = SUB_INDEX_BEGIN; index < m_item->BagSlots; ++index) { if (GetItem(index)) { ++item_count; } } return item_count; } bool ItemInst::IsNoneEmptyContainer() { - if (!m_item || m_item->ItemClass != ItemClassContainer) + if (!m_item || !m_item->IsClassBag()) return false; - for (int index = SUB_BEGIN; index < m_item->BagSlots; ++index) { + for (int index = SUB_INDEX_BEGIN; index < m_item->BagSlots; ++index) { if (GetItem(index)) return true; } @@ -1855,7 +1891,7 @@ bool ItemInst::IsNoneEmptyContainer() // Retrieve augment inside item ItemInst* ItemInst::GetAugment(uint8 slot) const { - if (m_item && m_item->ItemClass == ItemClassCommon) + if (m_item && m_item->IsClassCommon()) return GetItem(slot); return nullptr; @@ -1863,10 +1899,10 @@ ItemInst* ItemInst::GetAugment(uint8 slot) const ItemInst* ItemInst::GetOrnamentationAug(int32 ornamentationAugtype) const { - if (!m_item || m_item->ItemClass != ItemClassCommon) { return nullptr; } + if (!m_item || !m_item->IsClassCommon()) { return nullptr; } if (ornamentationAugtype == 0) { return nullptr; } - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { if (GetAugment(i) && m_item->AugSlotType[i] == ornamentationAugtype) { @@ -1900,7 +1936,7 @@ uint32 ItemInst::GetOrnamentHeroModel(int32 material_slot) const { } bool ItemInst::UpdateOrnamentationInfo() { - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return false; bool ornamentSet = false; @@ -1908,7 +1944,7 @@ bool ItemInst::UpdateOrnamentationInfo() { int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); if (GetOrnamentationAug(ornamentationAugtype)) { - const Item_Struct* ornamentItem; + const EQEmu::ItemBase* ornamentItem; ornamentItem = GetOrnamentationAug(ornamentationAugtype)->GetItem(); if (ornamentItem != nullptr) { @@ -1935,10 +1971,10 @@ bool ItemInst::UpdateOrnamentationInfo() { return ornamentSet; } -bool ItemInst::CanTransform(const Item_Struct *ItemToTry, const Item_Struct *Container, bool AllowAll) { +bool ItemInst::CanTransform(const EQEmu::ItemBase *ItemToTry, const EQEmu::ItemBase *Container, bool AllowAll) { if (!ItemToTry || !Container) return false; - if (ItemToTry->ItemType == ItemTypeArrow || strnlen(Container->CharmFile, 30) == 0) + if (ItemToTry->ItemType == EQEmu::item::ItemTypeArrow || strnlen(Container->CharmFile, 30) == 0) return false; if (AllowAll && strncasecmp(Container->CharmFile, "ITEMTRANSFIGSHIELD", 18) && strncasecmp(Container->CharmFile, "ITEMTransfigBow", 15)) { @@ -1983,7 +2019,7 @@ bool ItemInst::CanTransform(const Item_Struct *ItemToTry, const Item_Struct *Con uint32 ItemInst::GetAugmentItemID(uint8 slot) const { - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return NO_ITEM; return GetItemID(slot); @@ -1992,7 +2028,7 @@ uint32 ItemInst::GetAugmentItemID(uint8 slot) const // Add an augment to the item void ItemInst::PutAugment(uint8 slot, const ItemInst& augment) { - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return; PutItem(slot, augment); @@ -2013,7 +2049,7 @@ void ItemInst::PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id) // Remove augment from item and destroy it void ItemInst::DeleteAugment(uint8 index) { - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return; DeleteItem(index); @@ -2022,7 +2058,7 @@ void ItemInst::DeleteAugment(uint8 index) // Remove augment from item and return it ItemInst* ItemInst::RemoveAugment(uint8 index) { - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return nullptr; return PopItem(index); @@ -2030,10 +2066,10 @@ ItemInst* ItemInst::RemoveAugment(uint8 index) bool ItemInst::IsAugmented() { - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return false; - for (int index = AUG_BEGIN; index < EmuConstants::ITEM_COMMON_SIZE; ++index) { + for (int index = AUG_INDEX_BEGIN; index < EQEmu::legacy::ITEM_COMMON_SIZE; ++index) { if (GetAugmentItemID(index)) return true; } @@ -2044,10 +2080,10 @@ bool ItemInst::IsAugmented() // Has attack/delay? bool ItemInst::IsWeapon() const { - if (!m_item || m_item->ItemClass != ItemClassCommon) + if (!m_item || !m_item->IsClassCommon()) return false; - if (m_item->ItemType == ItemTypeArrow && m_item->Damage != 0) + if (m_item->ItemType == EQEmu::item::ItemTypeArrow && m_item->Damage != 0) return true; else return ((m_item->Damage != 0) && (m_item->Delay != 0)); @@ -2058,9 +2094,9 @@ bool ItemInst::IsAmmo() const if (!m_item) return false; - if ((m_item->ItemType == ItemTypeArrow) || - (m_item->ItemType == ItemTypeLargeThrowing) || - (m_item->ItemType == ItemTypeSmallThrowing) + if ((m_item->ItemType == EQEmu::item::ItemTypeArrow) || + (m_item->ItemType == EQEmu::item::ItemTypeLargeThrowing) || + (m_item->ItemType == EQEmu::item::ItemTypeSmallThrowing) ) { return true; } @@ -2069,7 +2105,7 @@ bool ItemInst::IsAmmo() const } -const Item_Struct* ItemInst::GetItem() const +const EQEmu::ItemBase* ItemInst::GetItem() const { if (!m_item) return nullptr; @@ -2080,7 +2116,7 @@ const Item_Struct* ItemInst::GetItem() const return m_item; } -const Item_Struct* ItemInst::GetUnscaledItem() const +const EQEmu::ItemBase* ItemInst::GetUnscaledItem() const { // No operator calls and defaults to nullptr return m_item; @@ -2088,7 +2124,7 @@ const Item_Struct* ItemInst::GetUnscaledItem() const std::string ItemInst::GetCustomDataString() const { std::string ret_val; - std::map::const_iterator iter = m_custom_data.begin(); + auto iter = m_custom_data.begin(); while (iter != m_custom_data.end()) { if (ret_val.length() > 0) { ret_val += "^"; @@ -2141,7 +2177,7 @@ void ItemInst::SetCustomData(std::string identifier, bool value) { } void ItemInst::DeleteCustomData(std::string identifier) { - std::map::iterator iter = m_custom_data.find(identifier); + auto iter = m_custom_data.find(identifier); if (iter != m_custom_data.end()) { m_custom_data.erase(iter); } @@ -2161,8 +2197,8 @@ bool ItemInst::IsSlotAllowed(int16 slot_id) const { if (!m_item) { return false; } else if (Inventory::SupportsContainers(slot_id)) { return true; } else if (m_item->Slots & (1 << slot_id)) { return true; } - else if (slot_id == MainPowerSource && (m_item->Slots & (1 << 22))) { return true; } // got lazy... - else if (slot_id != MainPowerSource && slot_id > EmuConstants::EQUIPMENT_END) { return true; } + else if (slot_id == EQEmu::legacy::SlotPowerSource && (m_item->Slots & (1 << 22))) { return true; } // got lazy... + else if (slot_id != EQEmu::legacy::SlotPowerSource && slot_id > EQEmu::legacy::EQUIPMENT_END) { return true; } else { return false; } } @@ -2188,10 +2224,10 @@ void ItemInst::ScaleItem() { return; if (m_scaledItem) { - memcpy(m_scaledItem, m_item, sizeof(Item_Struct)); + memcpy(m_scaledItem, m_item, sizeof(EQEmu::ItemBase)); } else { - m_scaledItem = new Item_Struct(*m_item); + m_scaledItem = new EQEmu::ItemBase(*m_item); } float Mult = (float)(GetExp()) / 10000; // scaling is determined by exp, with 10,000 being full stats @@ -2214,11 +2250,12 @@ void ItemInst::ScaleItem() { m_scaledItem->Mana = (int32)((float)m_item->Mana*Mult); m_scaledItem->AC = (int32)((float)m_item->AC*Mult); - m_scaledItem->SkillModValue = (int32)((float)m_item->SkillModValue*Mult); - m_scaledItem->BaneDmgAmt = (int8)((float)m_item->BaneDmgAmt*Mult); - m_scaledItem->BardValue = (int32)((float)m_item->BardValue*Mult); - m_scaledItem->ElemDmgAmt = (uint8)((float)m_item->ElemDmgAmt*Mult); - m_scaledItem->Damage = (uint32)((float)m_item->Damage*Mult); + // check these..some may not need to be modified (really need to check all stats/bonuses) + //m_scaledItem->SkillModValue = (int32)((float)m_item->SkillModValue*Mult); + //m_scaledItem->BaneDmgAmt = (int8)((float)m_item->BaneDmgAmt*Mult); // watch (10 entries with charmfileid) + m_scaledItem->BardValue = (int32)((float)m_item->BardValue*Mult); // watch (no entries with charmfileid) + m_scaledItem->ElemDmgAmt = (uint8)((float)m_item->ElemDmgAmt*Mult); // watch (no entries with charmfileid) + m_scaledItem->Damage = (uint32)((float)m_item->Damage*Mult); // watch m_scaledItem->CombatEffects = (int8)((float)m_item->CombatEffects*Mult); m_scaledItem->Shielding = (int8)((float)m_item->Shielding*Mult); @@ -2306,6 +2343,708 @@ void ItemInst::ClearTimers() { m_timers.clear(); } +int ItemInst::GetItemArmorClass(bool augments) const +{ + int ac = 0; + const auto item = GetItem(); + if (item) { + ac = item->AC; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + ac += GetAugment(i)->GetItemArmorClass(); + } + return ac; +} + +int ItemInst::GetItemElementalDamage(int &magic, int &fire, int &cold, int &poison, int &disease, int &chromatic, int &prismatic, int &physical, int &corruption, bool augments) const +{ + const auto item = GetItem(); + if (item) { + switch (item->ElemDmgType) { + case RESIST_MAGIC: + magic += item->ElemDmgAmt; + break; + case RESIST_FIRE: + fire += item->ElemDmgAmt; + break; + case RESIST_COLD: + cold += item->ElemDmgAmt; + break; + case RESIST_POISON: + poison += item->ElemDmgAmt; + break; + case RESIST_DISEASE: + disease += item->ElemDmgAmt; + break; + case RESIST_CHROMATIC: + chromatic += item->ElemDmgAmt; + break; + case RESIST_PRISMATIC: + prismatic += item->ElemDmgAmt; + break; + case RESIST_PHYSICAL: + physical += item->ElemDmgAmt; + break; + case RESIST_CORRUPTION: + corruption += item->ElemDmgAmt; + break; + } + + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + GetAugment(i)->GetItemElementalDamage(magic, fire, cold, poison, disease, chromatic, prismatic, physical, corruption); + } + return magic + fire + cold + poison + disease + chromatic + prismatic + physical + corruption; +} + +int ItemInst::GetItemElementalFlag(bool augments) const +{ + int flag = 0; + const auto item = GetItem(); + if (item) { + flag = item->ElemDmgType; + if (flag) + return flag; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) { + if (GetAugment(i)) + flag = GetAugment(i)->GetItemElementalFlag(); + if (flag) + return flag; + } + } + } + return flag; +} + +int ItemInst::GetItemElementalDamage(bool augments) const +{ + int damage = 0; + const auto item = GetItem(); + if (item) { + damage = item->ElemDmgAmt; + if (damage) + return damage; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) { + if (GetAugment(i)) + damage = GetAugment(i)->GetItemElementalDamage(); + if (damage) + return damage; + } + } + } + return damage; +} + +int ItemInst::GetItemRecommendedLevel(bool augments) const +{ + int level = 0; + const auto item = GetItem(); + if (item) { + level = item->RecLevel; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) { + int temp = 0; + if (GetAugment(i)) { + temp = GetAugment(i)->GetItemRecommendedLevel(); + if (temp > level) + level = temp; + } + } + } + } + + return level; +} + +int ItemInst::GetItemRequiredLevel(bool augments) const +{ + int level = 0; + const auto item = GetItem(); + if (item) { + level = item->ReqLevel; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) { + int temp = 0; + if (GetAugment(i)) { + temp = GetAugment(i)->GetItemRequiredLevel(); + if (temp > level) + level = temp; + } + } + } + } + + return level; +} + +int ItemInst::GetItemWeaponDamage(bool augments) const +{ + int damage = 0; + const auto item = GetItem(); + if (item) { + damage = item->Damage; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + damage += GetAugment(i)->GetItemWeaponDamage(); + } + } + return damage; +} + +int ItemInst::GetItemBackstabDamage(bool augments) const +{ + int damage = 0; + const auto item = GetItem(); + if (item) { + damage = item->BackstabDmg; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + damage += GetAugment(i)->GetItemBackstabDamage(); + } + } + return damage; +} + +int ItemInst::GetItemBaneDamageBody(bool augments) const +{ + int body = 0; + const auto item = GetItem(); + if (item) { + body = item->BaneDmgBody; + if (body) + return body; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) { + body = GetAugment(i)->GetItemBaneDamageBody(); + if (body) + return body; + } + } + } + return body; +} + +int ItemInst::GetItemBaneDamageRace(bool augments) const +{ + int race = 0; + const auto item = GetItem(); + if (item) { + race = item->BaneDmgRace; + if (race) + return race; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) { + race = GetAugment(i)->GetItemBaneDamageRace(); + if (race) + return race; + } + } + } + return race; +} + +int ItemInst::GetItemBaneDamageBody(bodyType against, bool augments) const +{ + int damage = 0; + const auto item = GetItem(); + if (item) { + if (item->BaneDmgBody == against) + damage += item->BaneDmgAmt; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + damage += GetAugment(i)->GetItemBaneDamageBody(against); + } + } + return damage; +} + +int ItemInst::GetItemBaneDamageRace(uint16 against, bool augments) const +{ + int damage = 0; + const auto item = GetItem(); + if (item) { + if (item->BaneDmgRace == against) + damage += item->BaneDmgRaceAmt; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + damage += GetAugment(i)->GetItemBaneDamageRace(against); + } + } + return damage; +} + +int ItemInst::GetItemMagical(bool augments) const +{ + const auto item = GetItem(); + if (item) { + if (item->Magic) + return 1; + + if (augments) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i) && GetAugment(i)->GetItemMagical()) + return 1; + } + } + return 0; +} + +int ItemInst::GetItemHP(bool augments) const +{ + int hp = 0; + const auto item = GetItem(); + if (item) { + hp = item->HP; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + hp += GetAugment(i)->GetItemHP(); + } + return hp; +} + +int ItemInst::GetItemMana(bool augments) const +{ + int mana = 0; + const auto item = GetItem(); + if (item) { + mana = item->Mana; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + mana += GetAugment(i)->GetItemMana(); + } + return mana; +} + +int ItemInst::GetItemEndur(bool augments) const +{ + int endur = 0; + const auto item = GetItem(); + if (item) { + endur = item->Endur; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + endur += GetAugment(i)->GetItemEndur(); + } + return endur; +} + +int ItemInst::GetItemAttack(bool augments) const +{ + int atk = 0; + const auto item = GetItem(); + if (item) { + atk = item->Attack; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + atk += GetAugment(i)->GetItemAttack(); + } + return atk; +} + +int ItemInst::GetItemStr(bool augments) const +{ + int str = 0; + const auto item = GetItem(); + if (item) { + str = item->AStr; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + str += GetAugment(i)->GetItemStr(); + } + return str; +} + +int ItemInst::GetItemSta(bool augments) const +{ + int sta = 0; + const auto item = GetItem(); + if (item) { + sta = item->ASta; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + sta += GetAugment(i)->GetItemSta(); + } + return sta; +} + +int ItemInst::GetItemDex(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->ADex; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemDex(); + } + return total; +} + +int ItemInst::GetItemAgi(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->AAgi; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemAgi(); + } + return total; +} + +int ItemInst::GetItemInt(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->AInt; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemInt(); + } + return total; +} + +int ItemInst::GetItemWis(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->AWis; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemWis(); + } + return total; +} + +int ItemInst::GetItemCha(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->ACha; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemCha(); + } + return total; +} + +int ItemInst::GetItemMR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->MR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemMR(); + } + return total; +} + +int ItemInst::GetItemFR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->FR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemFR(); + } + return total; +} + +int ItemInst::GetItemCR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->CR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemCR(); + } + return total; +} + +int ItemInst::GetItemPR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->PR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemPR(); + } + return total; +} + +int ItemInst::GetItemDR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->DR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemDR(); + } + return total; +} + +int ItemInst::GetItemCorrup(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->SVCorruption; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemCorrup(); + } + return total; +} + +int ItemInst::GetItemHeroicStr(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicStr; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicStr(); + } + return total; +} + +int ItemInst::GetItemHeroicSta(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicSta; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicSta(); + } + return total; +} + +int ItemInst::GetItemHeroicDex(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicDex; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicDex(); + } + return total; +} + +int ItemInst::GetItemHeroicAgi(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicAgi; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicAgi(); + } + return total; +} + +int ItemInst::GetItemHeroicInt(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicInt; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicInt(); + } + return total; +} + +int ItemInst::GetItemHeroicWis(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicWis; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicWis(); + } + return total; +} + +int ItemInst::GetItemHeroicCha(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicCha; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicCha(); + } + return total; +} + +int ItemInst::GetItemHeroicMR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicMR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicMR(); + } + return total; +} + +int ItemInst::GetItemHeroicFR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicFR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicFR(); + } + return total; +} + +int ItemInst::GetItemHeroicCR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicCR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicCR(); + } + return total; +} + +int ItemInst::GetItemHeroicPR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicPR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicPR(); + } + return total; +} + +int ItemInst::GetItemHeroicDR(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicDR; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicDR(); + } + return total; +} + +int ItemInst::GetItemHeroicCorrup(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->HeroicSVCorrup; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) + total += GetAugment(i)->GetItemHeroicCorrup(); + } + return total; +} + +int ItemInst::GetItemHaste(bool augments) const +{ + int total = 0; + const auto item = GetItem(); + if (item) { + total = item->Haste; + if (augments) + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) + if (GetAugment(i)) { + int temp = GetAugment(i)->GetItemHaste(); + if (temp > total) + total = temp; + } + } + return total; +} // // class EvolveInfo @@ -2332,104 +3071,3 @@ EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 EvolveInfo::~EvolveInfo() { } - - -// -// struct Item_Struct -// -bool Item_Struct::IsEquipable(uint16 Race, uint16 Class_) const -{ - bool IsRace = false; - bool IsClass = false; - - uint32 Classes_ = Classes; - uint32 Races_ = Races; - uint32 Race_ = GetArrayRace(Race); - - for (int CurrentClass = 1; CurrentClass <= PLAYER_CLASS_COUNT; ++CurrentClass) { - if (Classes_ & 1) { - if (CurrentClass == Class_) { - IsClass = true; - break; - } - } - Classes_ >>= 1; - } - - Race_ = (Race_ == 18 ? 16 : Race_); - - for (unsigned int CurrentRace = 1; CurrentRace <= PLAYER_RACE_COUNT; ++CurrentRace) { - if (Races_ & 1) { - if (CurrentRace == Race_) { - IsRace = true; - break; - } - } - Races_ >>= 1; - } - - return (IsRace && IsClass); -} - -// -// struct LightProfile_Struct -// -uint8 LightProfile_Struct::TypeToLevel(uint8 lightType) -{ - switch (lightType) { - case lightTypeGlobeOfStars: - return lightLevelBrilliant; // 10 - case lightTypeFlamelessLantern: - case lightTypeGreaterLightstone: - return lightLevelLargeMagic; // 9 - case lightTypeLargeLantern: - return lightLevelLargeLantern; // 8 - case lightTypeSteinOfMoggok: - case lightTypeLightstone: - return lightLevelMagicLantern; // 7 - case lightTypeSmallLantern: - return lightLevelSmallLantern; // 6 - case lightTypeColdlight: - case lightTypeUnknown2: - return lightLevelBlueLight; // 5 - case lightTypeFireBeetleEye: - case lightTypeUnknown1: - return lightLevelRedLight; // 4 - case lightTypeTinyGlowingSkull: - case lightTypeLightGlobe: - return lightLevelSmallMagic; // 3 - case lightTypeTorch: - return lightLevelTorch; // 2 - case lightLevelCandle: - return lightLevelCandle; // 1 - default: - return lightLevelUnlit; // 0 - } -} - -bool LightProfile_Struct::IsLevelGreater(uint8 leftType, uint8 rightType) -{ - static const uint8 light_levels[LIGHT_TYPES_COUNT] = { - lightLevelUnlit, /* lightTypeNone */ - lightLevelCandle, /* lightTypeCandle */ - lightLevelTorch, /* lightTypeTorch */ - lightLevelSmallMagic, /* lightTypeTinyGlowingSkull */ - lightLevelSmallLantern, /* lightTypeSmallLantern */ - lightLevelMagicLantern, /* lightTypeSteinOfMoggok */ - lightLevelLargeLantern, /* lightTypeLargeLantern */ - lightLevelLargeMagic, /* lightTypeFlamelessLantern */ - lightLevelBrilliant, /* lightTypeGlobeOfStars */ - lightLevelSmallMagic, /* lightTypeLightGlobe */ - lightLevelMagicLantern, /* lightTypeLightstone */ - lightLevelLargeMagic, /* lightTypeGreaterLightstone */ - lightLevelRedLight, /* lightTypeFireBeetleEye */ - lightLevelBlueLight, /* lightTypeColdlight */ - lightLevelRedLight, /* lightTypeUnknown1 */ - lightLevelBlueLight /* lightTypeUnknown2 */ - }; - - if (leftType >= LIGHT_TYPES_COUNT) { leftType = lightTypeNone; } - if (rightType >= LIGHT_TYPES_COUNT) { rightType = lightTypeNone; } - - return (light_levels[leftType] > light_levels[rightType]); -} diff --git a/common/item.h b/common/item.h index a5dd01f95..f20b41fac 100644 --- a/common/item.h +++ b/common/item.h @@ -1,5 +1,6 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,22 +14,26 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 04111-1307 USA */ // @merth notes: // These classes could be optimized with database reads/writes by storing // a status flag indicating how object needs to interact with database -#ifndef __ITEM_H -#define __ITEM_H +#ifndef COMMON_ITEM_H +#define COMMON_ITEM_H + class ItemParse; // Parses item packets class EvolveInfo; // Stores information about an evolving item family #include "../common/eq_constants.h" -#include "../common/item_struct.h" +#include "../common/item_base.h" #include "../common/timer.h" +#include "../common/bodytypes.h" +#include "../common/deity.h" +#include "../common/memory_buffer.h" #include #include @@ -71,6 +76,7 @@ enum { invWhereCursor = 0x20 }; +class ItemInst; // ######################################## // Class: Queue @@ -113,22 +119,23 @@ public: /////////////////////////////// // Public Methods /////////////////////////////// - - Inventory() { m_version = ClientVersion::Unknown; m_versionset = false; } + + Inventory() { m_inventory_version = EQEmu::versions::InventoryVersion::Unknown; m_inventory_version_set = false; } ~Inventory(); - // Inventory v2 creep - bool SetInventoryVersion(ClientVersion version) { - if (!m_versionset) { - m_version = version; - return (m_versionset = true); + // inv2 creep + bool SetInventoryVersion(EQEmu::versions::InventoryVersion inventory_version) { + if (!m_inventory_version_set) { + m_inventory_version = EQEmu::versions::ValidateInventoryVersion(inventory_version); + return (m_inventory_version_set = true); } else { return false; } } + bool SetInventoryVersion(EQEmu::versions::ClientVersion client_version) { return SetInventoryVersion(EQEmu::versions::ConvertClientVersionToInventoryVersion(client_version)); } - ClientVersion GetInventoryVersion() { return m_version; } + EQEmu::versions::InventoryVersion InventoryVersion() { return m_inventory_version; } static void CleanDirty(); static void MarkDirty(ItemInst *inst); @@ -168,7 +175,7 @@ public: ItemInst* PopItem(int16 slot_id); // Check whether there is space for the specified number of the specified item. - bool HasSpaceForItem(const Item_Struct *ItemToTry, int16 Quantity); + bool HasSpaceForItem(const EQEmu::ItemBase *ItemToTry, int16 Quantity); // Check whether item exists in inventory // where argument specifies OR'd list of invWhere constants to look @@ -193,7 +200,7 @@ public: static int16 CalcSlotFromMaterial(uint8 material); static uint8 CalcMaterialFromSlot(int16 equipslot); - static bool CanItemFitInContainer(const Item_Struct *ItemToTry, const Item_Struct *Container); + static bool CanItemFitInContainer(const EQEmu::ItemBase *ItemToTry, const EQEmu::ItemBase *Container); // Test for valid inventory casting slot bool SupportsClickCasting(int16 slot_id); @@ -251,8 +258,8 @@ protected: private: // Active inventory version - ClientVersion m_version; - bool m_versionset; + EQEmu::versions::InventoryVersion m_inventory_version; + bool m_inventory_version_set; }; class SharedDatabase; @@ -270,7 +277,7 @@ public: ///////////////////////// // Constructors/Destructor - ItemInst(const Item_Struct* item = nullptr, int16 charges = 0); + ItemInst(const EQEmu::ItemBase* item = nullptr, int16 charges = 0); ItemInst(SharedDatabase *db, uint32 item_id, int16 charges = 0); @@ -281,7 +288,15 @@ public: ~ItemInst(); // Query item type - bool IsType(ItemClassTypes item_class) const; + bool IsType(EQEmu::item::ItemClass item_class) const; + + bool IsClassCommon(); + bool IsClassBag(); + bool IsClassBook(); + + bool IsClassCommon() const { return const_cast(this)->IsClassCommon(); } + bool IsClassBag() const { return const_cast(this)->IsClassBag(); } + bool IsClassBook() const { return const_cast(this)->IsClassBook(); } // Can item be stacked? bool IsStackable() const; @@ -300,7 +315,7 @@ public: bool IsAugmentSlotAvailable(int32 augtype, uint8 slot) const; inline int32 GetAugmentType() const { return ((m_item) ? m_item->AugType : NO_ITEM); } - inline bool IsExpendable() const { return ((m_item) ? ((m_item->Click.Type == ET_Expendable ) || (m_item->ItemType == ItemTypePotion)) : false); } + inline bool IsExpendable() const { return ((m_item) ? ((m_item->Click.Type == EQEmu::item::ItemEffectExpendable) || (m_item->ItemType == EQEmu::item::ItemTypePotion)) : false); } // // Contents @@ -331,7 +346,7 @@ public: bool IsAugmented(); ItemInst* GetOrnamentationAug(int32 ornamentationAugtype) const; bool UpdateOrnamentationInfo(); - static bool CanTransform(const Item_Struct *ItemToTry, const Item_Struct *Container, bool AllowAll = false); + static bool CanTransform(const EQEmu::ItemBase *ItemToTry, const EQEmu::ItemBase *Container, bool AllowAll = false); // Has attack/delay? bool IsWeapon() const; @@ -340,8 +355,8 @@ public: // Accessors const uint32 GetID() const { return ((m_item) ? m_item->ID : NO_ITEM); } const uint32 GetItemScriptID() const { return ((m_item) ? m_item->ScriptFileID : NO_ITEM); } - const Item_Struct* GetItem() const; - const Item_Struct* GetUnscaledItem() const; + const EQEmu::ItemBase* GetItem() const; + const EQEmu::ItemBase* GetUnscaledItem() const; int16 GetCharges() const { return m_charges; } void SetCharges(int16 charges) { m_charges = charges; } @@ -409,7 +424,9 @@ public: int8 GetMaxEvolveLvl() const; uint32 GetKillsNeeded(uint8 currentlevel); - std::string Serialize(int16 slot_id) const { InternalSerializedItem_Struct s; s.slot_id=slot_id; s.inst=(const void *)this; std::string ser; ser.assign((char *)&s,sizeof(InternalSerializedItem_Struct)); return ser; } + std::string Serialize(int16 slot_id) const { EQEmu::InternalSerializedItem_Struct s; s.slot_id = slot_id; s.inst = (const void*)this; std::string ser; ser.assign((char*)&s, sizeof(EQEmu::InternalSerializedItem_Struct)); return ser; } + void Serialize(EQEmu::OutBuffer& ob, int16 slot_id) const { EQEmu::InternalSerializedItem_Struct isi; isi.slot_id = slot_id; isi.inst = (const void*)this; ob.write((const char*)&isi, sizeof(isi)); } + inline int32 GetSerialNumber() const { return m_SerialNumber; } inline void SetSerialNumber(int32 id) { m_SerialNumber = id; } @@ -418,6 +435,58 @@ public: void StopTimer(std::string name); void ClearTimers(); + // Get a total of a stat, including augs + // These functions should be used in place of other code manually totaling + // to centralize where it is done to make future changes easier (ex. whenever powersources come around) + // and to minimize errors. CalcItemBonuses however doesn't use these in interest of performance + // by default these do not recurse into augs + int GetItemArmorClass(bool augments = false) const; + int GetItemElementalDamage(int &magic, int &fire, int &cold, int &poison, int &disease, int &chromatic, int &prismatic, int &physical, int &corruption, bool augments = false) const; + // These two differ in the fact that they're quick checks (they are checked BEFORE the one above + int GetItemElementalFlag(bool augments = false) const; + int GetItemElementalDamage(bool augments = false) const; + int GetItemRecommendedLevel(bool augments = false) const; + int GetItemRequiredLevel(bool augments = false) const; + int GetItemWeaponDamage(bool augments = false) const; + int GetItemBackstabDamage(bool augments = false) const; + // these two are just quick checks + int GetItemBaneDamageBody(bool augments = false) const; + int GetItemBaneDamageRace(bool augments = false) const; + int GetItemBaneDamageBody(bodyType against, bool augments = false) const; + int GetItemBaneDamageRace(uint16 against, bool augments = false) const; + int GetItemMagical(bool augments = false) const; + int GetItemHP(bool augments = false) const; + int GetItemMana(bool augments = false) const; + int GetItemEndur(bool augments = false) const; + int GetItemAttack(bool augments = false) const; + int GetItemStr(bool augments = false) const; + int GetItemSta(bool augments = false) const; + int GetItemDex(bool augments = false) const; + int GetItemAgi(bool augments = false) const; + int GetItemInt(bool augments = false) const; + int GetItemWis(bool augments = false) const; + int GetItemCha(bool augments = false) const; + int GetItemMR(bool augments = false) const; + int GetItemFR(bool augments = false) const; + int GetItemCR(bool augments = false) const; + int GetItemPR(bool augments = false) const; + int GetItemDR(bool augments = false) const; + int GetItemCorrup(bool augments = false) const; + int GetItemHeroicStr(bool augments = false) const; + int GetItemHeroicSta(bool augments = false) const; + int GetItemHeroicDex(bool augments = false) const; + int GetItemHeroicAgi(bool augments = false) const; + int GetItemHeroicInt(bool augments = false) const; + int GetItemHeroicWis(bool augments = false) const; + int GetItemHeroicCha(bool augments = false) const; + int GetItemHeroicMR(bool augments = false) const; + int GetItemHeroicFR(bool augments = false) const; + int GetItemHeroicCR(bool augments = false) const; + int GetItemHeroicPR(bool augments = false) const; + int GetItemHeroicDR(bool augments = false) const; + int GetItemHeroicCorrup(bool augments = false) const; + int GetItemHaste(bool augments = false) const; + protected: ////////////////////////// // Protected Members @@ -431,7 +500,7 @@ protected: void _PutItem(uint8 index, ItemInst* inst) { m_contents[index] = inst; } ItemInstTypes m_use_type; // Usage type for item - const Item_Struct* m_item; // Ptr to item data + const EQEmu::ItemBase* m_item; // Ptr to item data int16 m_charges; // # of charges for chargeable items uint32 m_price; // Bazaar /trader price uint32 m_color; @@ -443,7 +512,7 @@ protected: uint32 m_exp; int8 m_evolveLvl; bool m_activated; - Item_Struct* m_scaledItem; + EQEmu::ItemBase* m_scaledItem; EvolveInfo* m_evolveInfo; bool m_scaling; uint32 m_ornamenticon; @@ -472,43 +541,4 @@ public: ~EvolveInfo(); }; -struct LightProfile_Struct -{ - /* - Current criteria (light types): - Equipment: { 0 .. 15 } - General: { 9 .. 13 } - - Notes: - - Initial character load and item movement updates use different light source update behaviors - -- Server procedure matches the item movement behavior since most updates occur post-character load - - MainAmmo is not considered when determining light sources - - No 'Sub' or 'Aug' items are recognized as light sources - - Light types '< 9' and '> 13' are not considered for general (carried) light sources - - If values > 0x0F are valid, then assignment limiters will need to be removed - - MainCursor 'appears' to be a valid light source update slot..but, have not experienced updates during debug sessions - - All clients have a bug regarding stackable items (light and sound updates are not processed when picking up an item) - -- The timer-based update cancels out the invalid light source - */ - - static uint8 TypeToLevel(uint8 lightType); - static bool IsLevelGreater(uint8 leftType, uint8 rightType); - - // Light types (classifications) - struct { - uint8 Innate; // Defined by db field `npc_types`.`light` - where appropriate - uint8 Equipment; // Item_Struct::light value of worn/carried equipment - uint8 Spell; // Set value of any light-producing spell (can be modded to mimic equip_light behavior) - uint8 Active; // Highest value of all light sources - } Type; - - // Light levels (intensities) - used to determine which light source should be active - struct { - uint8 Innate; - uint8 Equipment; - uint8 Spell; - uint8 Active; - } Level; -}; - -#endif // #define __ITEM_H +#endif /*COMMON_ITEM_H*/ diff --git a/common/item_base.cpp b/common/item_base.cpp new file mode 100644 index 000000000..c2cef6918 --- /dev/null +++ b/common/item_base.cpp @@ -0,0 +1,209 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "item_base.h" +#include "classes.h" +#include "races.h" +//#include "deity.h" + + +uint32 EQEmu::item::ConvertAugTypeToAugTypeBit(uint8 aug_type) +{ + switch (aug_type) { + case AugTypeGeneralSingleStat: + return bit_AugTypeGeneralSingleStat; + case AugTypeGeneralMultipleStat: + return bit_AugTypeGeneralMultipleStat; + case AugTypeGeneralSpellEffect: + return bit_AugTypeGeneralSpellEffect; + case AugTypeWeaponGeneral: + return bit_AugTypeWeaponGeneral; + case AugTypeWeaponElemDamage: + return bit_AugTypeWeaponElemDamage; + case AugTypeWeaponBaseDamage: + return bit_AugTypeWeaponBaseDamage; + case AugTypeGeneralGroup: + return bit_AugTypeGeneralGroup; + case AugTypeGeneralRaid: + return bit_AugTypeGeneralRaid; + case AugTypeGeneralDragonsPoints: + return bit_AugTypeGeneralDragonsPoints; + case AugTypeCraftedCommon: + return bit_AugTypeCraftedCommon; + case AugTypeCraftedGroup1: + return bit_AugTypeCraftedGroup1; + case AugTypeCraftedRaid1: + return bit_AugTypeCraftedRaid1; + case AugTypeEnergeiacGroup: + return bit_AugTypeEnergeiacGroup; + case AugTypeEnergeiacRaid: + return bit_AugTypeEnergeiacRaid; + case AugTypeEmblem: + return bit_AugTypeEmblem; + case AugTypeCraftedGroup2: + return bit_AugTypeCraftedGroup2; + case AugTypeCraftedRaid2: + return bit_AugTypeCraftedRaid2; + case AugTypeUnknown1: + return bit_AugTypeUnknown1; + case AugTypeUnknown2: + return bit_AugTypeUnknown2; + case AugTypeOrnamentation: + return bit_AugTypeOrnamentation; + case AugTypeSpecialOrnamentation: + return bit_AugTypeSpecialOrnamentation; + case AugTypeUnknown3: + return bit_AugTypeUnknown3; + case AugTypeUnknown4: + return bit_AugTypeUnknown4; + case AugTypeUnknown5: + return bit_AugTypeUnknown5; + case AugTypeUnknown6: + return bit_AugTypeUnknown6; + case AugTypeUnknown7: + return bit_AugTypeUnknown7; + case AugTypeUnknown8: + return bit_AugTypeUnknown8; + case AugTypeUnknown9: + return bit_AugTypeUnknown9; + case AugTypeUnknown10: + return bit_AugTypeUnknown10; + case AugTypeEpic2_5: + return bit_AugTypeEpic2_5; + case AugTypeTest: + return bit_AugTypeTest; + case AugTypeAll: + return bit_AugTypeAll; + default: + return bit_AugTypeNone; + } +} + +uint8 EQEmu::item::ConvertAugTypeBitToAugType(uint32 aug_type_bit) +{ + switch (aug_type_bit) { + case bit_AugTypeGeneralSingleStat: + return AugTypeGeneralSingleStat; + case bit_AugTypeGeneralMultipleStat: + return AugTypeGeneralMultipleStat; + case bit_AugTypeGeneralSpellEffect: + return AugTypeGeneralSpellEffect; + case bit_AugTypeWeaponGeneral: + return AugTypeWeaponGeneral; + case bit_AugTypeWeaponElemDamage: + return AugTypeWeaponElemDamage; + case bit_AugTypeWeaponBaseDamage: + return AugTypeWeaponBaseDamage; + case bit_AugTypeGeneralGroup: + return AugTypeGeneralGroup; + case bit_AugTypeGeneralRaid: + return AugTypeGeneralRaid; + case bit_AugTypeGeneralDragonsPoints: + return AugTypeGeneralDragonsPoints; + case bit_AugTypeCraftedCommon: + return AugTypeCraftedCommon; + case bit_AugTypeCraftedGroup1: + return AugTypeCraftedGroup1; + case bit_AugTypeCraftedRaid1: + return AugTypeCraftedRaid1; + case bit_AugTypeEnergeiacGroup: + return AugTypeEnergeiacGroup; + case bit_AugTypeEnergeiacRaid: + return AugTypeEnergeiacRaid; + case bit_AugTypeEmblem: + return AugTypeEmblem; + case bit_AugTypeCraftedGroup2: + return AugTypeCraftedGroup2; + case bit_AugTypeCraftedRaid2: + return AugTypeCraftedRaid2; + case bit_AugTypeUnknown1: + return AugTypeUnknown1; + case bit_AugTypeUnknown2: + return AugTypeUnknown2; + case bit_AugTypeOrnamentation: + return AugTypeOrnamentation; + case bit_AugTypeSpecialOrnamentation: + return AugTypeSpecialOrnamentation; + case bit_AugTypeUnknown3: + return AugTypeUnknown3; + case bit_AugTypeUnknown4: + return AugTypeUnknown4; + case bit_AugTypeUnknown5: + return AugTypeUnknown5; + case bit_AugTypeUnknown6: + return AugTypeUnknown6; + case bit_AugTypeUnknown7: + return AugTypeUnknown7; + case bit_AugTypeUnknown8: + return AugTypeUnknown8; + case bit_AugTypeUnknown9: + return AugTypeUnknown9; + case bit_AugTypeUnknown10: + return AugTypeUnknown10; + case bit_AugTypeEpic2_5: + return AugTypeEpic2_5; + case bit_AugTypeTest: + return AugTypeTest; + case bit_AugTypeAll: + return AugTypeAll; + default: + return AugTypeNone; + } +} + +bool EQEmu::ItemBase::IsEquipable(uint16 race_id, uint16 class_id) +{ + if (!(Races & GetPlayerRaceBit(race_id))) + return false; + + if (!(Classes & GetPlayerClassBit(GetPlayerClassValue(class_id)))) + return false; + + return true; +} + +bool EQEmu::ItemBase::IsClassCommon() +{ + return (ItemClass == item::ItemClassCommon); +} + +bool EQEmu::ItemBase::IsClassBag() +{ + return (ItemClass == item::ItemClassBag); +} + +bool EQEmu::ItemBase::IsClassBook() +{ + return (ItemClass == item::ItemClassBook); +} + +bool EQEmu::ItemBase::IsType1HWeapon() +{ + return ((ItemType == item::ItemType1HBlunt) || (ItemType == item::ItemType1HSlash) || (ItemType == item::ItemType1HPiercing)); +} + +bool EQEmu::ItemBase::IsType2HWeapon() +{ + return ((ItemType == item::ItemType2HBlunt) || (ItemType == item::ItemType2HSlash) || (ItemType == item::ItemType2HPiercing)); +} + +bool EQEmu::ItemBase::IsTypeShield() +{ + return (ItemType == item::ItemTypeShield); +} diff --git a/common/item_base.h b/common/item_base.h new file mode 100644 index 000000000..1ecba6734 --- /dev/null +++ b/common/item_base.h @@ -0,0 +1,565 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 04111-1307 USA +*/ + +#ifndef COMMON_ITEM_BASE_H +#define COMMON_ITEM_BASE_H + + +/* + * Note: (Doodman) + * This structure has field names that match the DB name exactly. + * Please take care as to not mess this up as it should make + * everyones life (i.e. mine) much easier. And the DB names + * match the field name from the 13th floor (SEQ) item collectors, + * so please maintain that as well. + * + * Note #2: (Doodman) + * UnkXXX fields are left in here for completeness but commented + * out since they are really unknown and since the items are now + * preserialized they should not be needed. Conversly if they + * -are- needed, then they shouldn't be unkown. + * + * Note #3: (Doodman) + * Please take care when adding new found data fields to add them + * to the appropriate structure. Item_Struct has elements that are + * global to all types of items only. + * + * Note #4: (Doodman) + * Made ya look! Ha! + */ + +#include "emu_constants.h" + + +namespace EQEmu +{ + namespace item { + enum ItemAttributeBit : uint32 { + bit_ItemAttributeNone = 0x00000000, + bit_ItemAttributeLore = 0x00000001, + bit_ItemAttributeArtifact = 0x00000002, + bit_ItemAttributeSummoned = 0x00000004, + bit_ItemAttributeMagic = 0x00000008, + bit_ItemAttributeAugment = 0x00000010, + bit_ItemAttributePendingLore = 0x00000020, + bit_ItemAttributeUnknown = 0xFFFFFFFF + }; + + enum ItemClass { + ItemClassCommon = 0, + ItemClassBag, + ItemClassBook, + ItemClassCount + }; + + enum ItemType : uint8 { +/*9138*/ ItemType1HSlash = 0, +/*9141*/ ItemType2HSlash, +/*9140*/ ItemType1HPiercing, +/*9139*/ ItemType1HBlunt, +/*9142*/ ItemType2HBlunt, +/*5504*/ ItemTypeBow, // 5 +/*----*/ ItemTypeUnknown1, +/*----*/ ItemTypeLargeThrowing, +/*5505*/ ItemTypeShield, +/*5506*/ ItemTypeScroll, +/*5507*/ ItemTypeArmor, // 10 +/*5508*/ ItemTypeMisc, // a lot of random crap has this item use. +/*7564*/ ItemTypeLockPick, +/*----*/ ItemTypeUnknown2, +/*5509*/ ItemTypeFood, +/*5510*/ ItemTypeDrink, // 15 +/*5511*/ ItemTypeLight, +/*5512*/ ItemTypeCombinable, // not all stackable items are this use... +/*5513*/ ItemTypeBandage, +/*----*/ ItemTypeSmallThrowing, +/*----*/ ItemTypeSpell, // 20 // spells and tomes +/*5514*/ ItemTypePotion, +/*----*/ ItemTypeUnknown3, +/*0406*/ ItemTypeWindInstrument, +/*0407*/ ItemTypeStringedInstrument, +/*0408*/ ItemTypeBrassInstrument, // 25 +/*0405*/ ItemTypePercussionInstrument, +/*5515*/ ItemTypeArrow, +/*----*/ ItemTypeUnknown4, +/*5521*/ ItemTypeJewelry, +/*----*/ ItemTypeSkull, // 30 +/*5516*/ ItemTypeBook, // skill-up tomes/books? (would probably need a pp flag if true...) +/*5517*/ ItemTypeNote, +/*5518*/ ItemTypeKey, +/*----*/ ItemTypeCoin, +/*5520*/ ItemType2HPiercing, // 35 +/*----*/ ItemTypeFishingPole, +/*----*/ ItemTypeFishingBait, +/*5519*/ ItemTypeAlcohol, +/*----*/ ItemTypeKey2, // keys and satchels?? (questable keys?) +/*----*/ ItemTypeCompass, // 40 +/*----*/ ItemTypeUnknown5, +/*----*/ ItemTypePoison, // might be wrong, but includes poisons +/*----*/ ItemTypeUnknown6, +/*----*/ ItemTypeUnknown7, +/*5522*/ ItemTypeMartial, // 45 +/*----*/ ItemTypeUnknown8, +/*----*/ ItemTypeUnknown9, +/*----*/ ItemTypeUnknown10, +/*----*/ ItemTypeUnknown11, +/*----*/ ItemTypeSinging, // 50 +/*5750*/ ItemTypeAllInstrumentTypes, +/*5776*/ ItemTypeCharm, +/*----*/ ItemTypeDye, +/*----*/ ItemTypeAugmentation, +/*----*/ ItemTypeAugmentationSolvent, // 55 +/*----*/ ItemTypeAugmentationDistiller, +/*----*/ ItemTypeUnknown12, +/*----*/ ItemTypeFellowshipKit, +/*----*/ ItemTypeUnknown13, +/*----*/ ItemTypeRecipe, // 60 +/*----*/ ItemTypeAdvancedRecipe, +/*----*/ ItemTypeJournal, // only one(1) database entry +/*----*/ ItemTypeAltCurrency, // alt-currency (as opposed to coinage) +/*5881*/ ItemTypePerfectedAugmentationDistiller, +/*----*/ ItemTypeCount + +/* + Unknowns: + + Mounts? + Ornamentations? + GuildBanners? + Collectible? + Placeable? + (others?) +*/ + }; + + enum AugTypeBit : uint32 { + bit_AugTypeNone = 0x00000000, + bit_AugTypeGeneralSingleStat = 0x00000001, /*1^16^1 (General: Single Stat)^0*/ + bit_AugTypeGeneralMultipleStat = 0x00000002, /*2^16^2 (General: Multiple Stat)^0*/ + bit_AugTypeGeneralSpellEffect = 0x00000004, /*3^16^3 (General: Spell Effect)^0*/ + bit_AugTypeWeaponGeneral = 0x00000008, /*4^16^4 (Weapon: General)^0*/ + bit_AugTypeWeaponElemDamage = 0x00000010, /*5^16^5 (Weapon: Elem Damage)^0*/ + bit_AugTypeWeaponBaseDamage = 0x00000020, /*6^16^6 (Weapon: Base Damage)^0*/ + bit_AugTypeGeneralGroup = 0x00000040, /*7^16^7 (General: Group)^0*/ + bit_AugTypeGeneralRaid = 0x00000080, /*8^16^8 (General: Raid)^0*/ + bit_AugTypeGeneralDragonsPoints = 0x00000100, /*9^16^9 (General: Dragons Points)^0*/ + bit_AugTypeCraftedCommon = 0x00000200, /*10^16^10 (Crafted: Common)^0*/ + bit_AugTypeCraftedGroup1 = 0x00000400, /*11^16^11 (Crafted: Group)^0*/ + bit_AugTypeCraftedRaid1 = 0x00000800, /*12^16^12 (Crafted: Raid)^0*/ + bit_AugTypeEnergeiacGroup = 0x00001000, /*13^16^13 (Energeiac: Group)^0*/ + bit_AugTypeEnergeiacRaid = 0x00002000, /*14^16^14 (Energeiac: Raid)^0*/ + bit_AugTypeEmblem = 0x00004000, /*15^16^15 (Emblem)^0*/ + bit_AugTypeCraftedGroup2 = 0x00008000, /*16^16^16 (Crafted: Group)^0*/ + bit_AugTypeCraftedRaid2 = 0x00010000, /*17^16^17 (Crafted: Raid)^0*/ + bit_AugTypeUnknown1 = 0x00020000, /*18^16^18^0*/ + bit_AugTypeUnknown2 = 0x00040000, /*19^16^19^0*/ + bit_AugTypeOrnamentation = 0x00080000, /*20^16^20 (Ornamentation)^0*/ + bit_AugTypeSpecialOrnamentation = 0x00100000, /*21^16^21 (Special Ornamentation)^0*/ + bit_AugTypeUnknown3 = 0x00200000, /*22^16^22^0*/ + bit_AugTypeUnknown4 = 0x00400000, /*23^16^23^0*/ + bit_AugTypeUnknown5 = 0x00800000, /*24^16^24^0*/ + bit_AugTypeUnknown6 = 0x01000000, /*25^16^25^0*/ + bit_AugTypeUnknown7 = 0x02000000, /*26^16^26^0*/ + bit_AugTypeUnknown8 = 0x04000000, /*27^16^27^0*/ + bit_AugTypeUnknown9 = 0x08000000, /*28^16^28^0*/ + bit_AugTypeUnknown10 = 0x10000000, /*29^16^29^0*/ + bit_AugTypeEpic2_5 = 0x20000000, /*30^16^30^0*/ + bit_AugTypeTest = 0x40000000, /*31^16^Test^0*/ // listed as 31^16^31^0 in 5-10 client + bit_AugTypeAll = 0xFFFFFFFF + }; + + enum AugType : uint8 { + AugTypeNone = 0, + AugTypeGeneralSingleStat, + AugTypeGeneralMultipleStat, + AugTypeGeneralSpellEffect, + AugTypeWeaponGeneral, + AugTypeWeaponElemDamage, // 5 + AugTypeWeaponBaseDamage, + AugTypeGeneralGroup, + AugTypeGeneralRaid, + AugTypeGeneralDragonsPoints, + AugTypeCraftedCommon, // 10 + AugTypeCraftedGroup1, + AugTypeCraftedRaid1, + AugTypeEnergeiacGroup, + AugTypeEnergeiacRaid, + AugTypeEmblem, // 15 + AugTypeCraftedGroup2, + AugTypeCraftedRaid2, + AugTypeUnknown1, + AugTypeUnknown2, + AugTypeOrnamentation, // 20 + AugTypeSpecialOrnamentation, + AugTypeUnknown3, + AugTypeUnknown4, + AugTypeUnknown5, + AugTypeUnknown6, // 25 + AugTypeUnknown7, + AugTypeUnknown8, + AugTypeUnknown9, + AugTypeUnknown10, + AugTypeEpic2_5, // 30 + AugTypeTest, + AugTypeCount, + AugTypeAll = 255 + }; + + enum AugRestriction : uint8 { +/*4690*/ AugRestrictionAny = 0, +/*9134*/ AugRestrictionArmor, +/*9135*/ AugRestrictionWeapons, +/*9136*/ AugRestriction1HWeapons, +/*9137*/ AugRestriction2HWeapons, +/*9138*/ AugRestriction1HSlash, // 5 +/*9139*/ AugRestriction1HBlunt, +/*9140*/ AugRestrictionPiercing, +/*9148*/ AugRestrictionHandToHand, +/*9141*/ AugRestriction2HSlash, +/*9142*/ AugRestriction2HBlunt, // 10 +/*9143*/ AugRestriction2HPierce, +/*9144*/ AugRestrictionBows, +/*9145*/ AugRestrictionShields, +/*8052*/ AugRestriction1HSlash1HBluntOrHandToHand, +/*9200*/ AugRestriction1HBluntOrHandToHand, // 15 // no listed peq entries + + // these three appear to be post-RoF (12-10-2012) and can not be verified until RoF (05-10-2013) is supported +/*????*/ AugRestrictionUnknown1, +/*????*/ AugRestrictionUnknown2, +/*????*/ AugRestrictionUnknown3, // last value in peq entries + AugRestrictionCount + +/*4687*/ //AugTypeAllItems, // ?? unknown atm +/*4688*/ //AugTypePrestige, // ?? unknown atm +/*4689*/ //AugTypeNonPrestige, // ?? unknown atm + }; + + enum BagType : uint8 { +/*3400*/ BagTypeSmallBag = 0, +/*3401*/ BagTypeLargeBag, +/*3402*/ BagTypeQuiver, +/*3403*/ BagTypeBeltPouch, +/*3404*/ BagTypeWristPouch, +/*3405*/ BagTypeBackPack, // 5 +/*3406*/ BagTypeSmallChest, +/*3407*/ BagTypeLargeChest, +/*----*/ BagTypeBandolier, // <*Database Reference Only> +/*3408*/ BagTypeMedicineBag, +/*3409*/ BagTypeToolBox, // 10 +/*3410*/ BagTypeLexicon, +/*3411*/ BagTypeMortar, +/*3412*/ BagTypeSelfDusting, // Quest container (Auto-clear contents?) +/*3413*/ BagTypeMixingBowl, +/*3414*/ BagTypeOven, // 15 +/*3415*/ BagTypeSewingKit, +/*3416*/ BagTypeForge, +/*3417*/ BagTypeFletchingKit, +/*3418*/ BagTypeBrewBarrel, +/*3419*/ BagTypeJewelersKit, // 20 +/*3420*/ BagTypePotteryWheel, +/*3421*/ BagTypeKiln, +/*3422*/ BagTypeKeymaker, // (no database entries as of peq rev 69) +/*3423*/ BagTypeWizardsLexicon, +/*3424*/ BagTypeMagesLexicon, // 25 +/*3425*/ BagTypeNecromancersLexicon, +/*3426*/ BagTypeEnchantersLexicon, +/*----*/ BagTypeUnknown1, // (a coin pouch/purse?) (no database entries as of peq rev 69) +/*----*/ BagTypeConcordanceofResearch, // <*Database Reference Only> +/*3427*/ BagTypeAlwaysWorks, // 30 // Quest container (Never-fail combines?) +/*3428*/ BagTypeKoadaDalForge, // High Elf +/*3429*/ BagTypeTeirDalForge, // Dark Elf +/*3430*/ BagTypeOggokForge, // Ogre +/*3431*/ BagTypeStormguardForge, // Dwarf +/*3432*/ BagTypeAkanonForge, // 35 // Gnome +/*3433*/ BagTypeNorthmanForge, // Barbarian +/*----*/ BagTypeUnknown2, // (no database entries as of peq rev 69) +/*3434*/ BagTypeCabilisForge, // Iksar +/*3435*/ BagTypeFreeportForge, // Human 1 +/*3436*/ BagTypeRoyalQeynosForge, // 40 // Human 2 +/*3439*/ BagTypeHalflingTailoringKit, +/*3438*/ BagTypeErudTailoringKit, +/*3440*/ BagTypeFierDalTailoringKit, // Wood Elf +/*3441*/ BagTypeFierDalFletchingKit, // Wood Elf +/*3437*/ BagTypeIksarPotteryWheel, // 45 +/*3442*/ BagTypeTackleBox, +/*3443*/ BagTypeTrollForge, +/*3445*/ BagTypeFierDalForge, // Wood Elf +/*3444*/ BagTypeValeForge, // Halfling +/*3446*/ BagTypeErudForge, // 50 +/*----*/ BagTypeTradersSatchel, // <*Database Reference Only> (db: Yellow Trader's Satchel Token?) +/*5785*/ BagTypeGuktaForge, // Froglok (no database entries as of peq rev 69) +/*3359*/ BagTypeAugmentationSealer, +/*----*/ BagTypeIceCreamChurn, // <*Database Reference Only> +/*6325*/ BagTypeTransformationmold, // 55 // Ornamentation +/*6340*/ BagTypeDetransformationmold, // Ornamentation Stripper +/*5400*/ BagTypeUnattuner, +/*7684*/ BagTypeTradeskillBag, +/*7692*/ BagTypeCollectibleBag, +/*----*/ BagTypeCount + }; + + enum ItemEffect { + ItemEffectCombatProc = 0, + ItemEffectClick, + ItemEffectWorn, + ItemEffectExpendable, + ItemEffectEquipClick, + ItemEffectClick2, //5 //name unknown + ItemEffectFocus, + ItemEffectScroll, + ItemEffectCount + }; + + enum ItemSize : uint8 { + ItemSizeTiny = 0, + ItemSizeSmall, + ItemSizeMedium, + ItemSizeLarge, + ItemSizeGiant, + ItemSizeCount + }; + + enum ItemDataType : uint8 { + ItemDataBase = 0, + ItemDataScaling, + ItemDataEvolving, + ItemDataCount + }; + + struct ItemEffect_Struct { + int16 Effect; + uint8 Type; + uint8 Level; + uint8 Level2; + //MaxCharges + //CastTime + //RecastDelay + //RecastType + //ProcRate + }; + + extern uint32 ConvertAugTypeToAugTypeBit(uint8 aug_type); + extern uint8 ConvertAugTypeBitToAugType(uint32 aug_type_bit); + + } /*item*/ + + struct InternalSerializedItem_Struct { + int16 slot_id; + const void * inst; + }; + + struct ItemBase { + // Non packet based fields + uint8 MinStatus; + uint8 ItemDataType; // memset to item::ItemDataBase ('0') during mmf load + + // Packet based fields + uint8 ItemClass; // Item Type: 0=common, 1=container, 2=book + char Name[64]; // Name + char Lore[80]; // Lore Name: *=lore, &=summoned, #=artifact, ~=pending lore + char IDFile[30]; // Visible model + uint32 ID; // Unique ID (also PK for DB) + int32 Weight; // Item weight * 10 + uint8 NoRent; // No Rent: 0=norent, 255=not norent + uint8 NoDrop; // No Drop: 0=nodrop, 255=not nodrop + uint8 Size; // Size: 0=tiny, 1=small, 2=medium, 3=large, 4=giant + uint32 Slots; // Bitfield for which slots this item can be used in + uint32 Price; // Item cost (?) + uint32 Icon; // Icon Number + uint32 LoreGroup; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295) + bool LoreFlag; // This will be true if LoreGroup is non-zero + bool PendingLoreFlag; + bool ArtifactFlag; + bool SummonedFlag; + uint8 FVNoDrop; // Firiona Vie nodrop flag + uint32 Favor; // Individual favor + uint32 GuildFavor; // Guild favor + uint32 PointType; + + //uint32 Unk117; + //uint32 Unk118; + //uint32 Unk121; + //uint32 Unk124; + + uint8 BagType; // 0:Small Bag, 1:Large Bag, 2:Quiver, 3:Belt Pouch ... there are 50 types + uint8 BagSlots; // Number of slots: can only be 2, 4, 6, 8, or 10 + uint8 BagSize; // 0:TINY, 1:SMALL, 2:MEDIUM, 3:LARGE, 4:GIANT + uint8 BagWR; // 0->100 + + bool BenefitFlag; + bool Tradeskills; // Is this a tradeskill item? + int8 CR; // Save vs Cold + int8 DR; // Save vs Disease + int8 PR; // Save vs Poison + int8 MR; // Save vs Magic + int8 FR; // Save vs Fire + int8 AStr; // Strength + int8 ASta; // Stamina + int8 AAgi; // Agility + int8 ADex; // Dexterity + int8 ACha; // Charisma + int8 AInt; // Intelligence + int8 AWis; // Wisdom + int32 HP; // HP + int32 Mana; // Mana + int32 AC; // AC + uint32 Deity; // Bitmask of Deities that can equip this item + //uint32 Unk033 + int32 SkillModValue; // % Mod to skill specified in SkillModType + int32 SkillModMax; // Max skill point modification + uint32 SkillModType; // Type of skill for SkillModValue to apply to + uint32 BaneDmgRace; // Bane Damage Race + int8 BaneDmgAmt; // Bane Damage Body Amount + uint32 BaneDmgBody; // Bane Damage Body + bool Magic; // True=Magic Item, False=not + int32 CastTime_; + uint8 ReqLevel; // Required Level to use item + uint32 BardType; // Bard Skill Type + int32 BardValue; // Bard Skill Amount + int8 Light; // Light + uint8 Delay; // Delay * 10 + uint8 RecLevel; // Recommended level to use item + uint8 RecSkill; // Recommended skill to use item (refers to primary skill of item) + uint8 ElemDmgType; // Elemental Damage Type (1=magic, 2=fire) + uint8 ElemDmgAmt; // Elemental Damage + uint8 Range; // Range of item + uint32 Damage; // Delay between item usage (in 0.1 sec increments) + uint32 Color; // RR GG BB 00 <-- as it appears in pc + uint32 Classes; // Bitfield of classes that can equip item (1 << class#) + uint32 Races; // Bitfield of races that can equip item (1 << race#) + //uint32 Unk054; + int16 MaxCharges; // Maximum charges items can hold: -1 if not a chargeable item + uint8 ItemType; // Item Type/Skill (itemClass* from above) + uint8 Material; // Item material type + uint32 HerosForgeModel;// Hero's Forge Armor Model Type (2-13?) + float SellRate; // Sell rate + //uint32 Unk059; + union { + uint32 Fulfilment; // Food fulfilment (How long it lasts) + uint32 CastTime; // Cast Time for clicky effects, in milliseconds + }; + uint32 EliteMaterial; + int32 ProcRate; + int8 CombatEffects; // PoP: Combat Effects + + int8 Shielding; // PoP: Shielding % + int8 StunResist; // PoP: Stun Resist % + int8 StrikeThrough; // PoP: Strike Through % + uint32 ExtraDmgSkill; + uint32 ExtraDmgAmt; + int8 SpellShield; // PoP: Spell Shield % + int8 Avoidance; // PoP: Avoidance + + int8 Accuracy; // PoP: Accuracy + + uint32 CharmFileID; + int32 FactionMod1; // Faction Mod 1 + int32 FactionMod2; // Faction Mod 2 + int32 FactionMod3; // Faction Mod 3 + int32 FactionMod4; // Faction Mod 4 + int32 FactionAmt1; // Faction Amt 1 + int32 FactionAmt2; // Faction Amt 2 + int32 FactionAmt3; // Faction Amt 3 + int32 FactionAmt4; // Faction Amt 4 + char CharmFile[32]; // ? + uint32 AugType; + uint8 AugSlotType[EQEmu::legacy::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Type + uint8 AugSlotVisible[EQEmu::legacy::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Visible + uint8 AugSlotUnk2[EQEmu::legacy::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Unknown Most likely Powersource related + uint32 LDoNTheme; + uint32 LDoNPrice; + uint32 LDoNSold; + uint32 BaneDmgRaceAmt; + uint32 AugRestrict; + uint32 Endur; + uint32 DotShielding; + uint32 Attack; + uint32 Regen; + uint32 ManaRegen; + uint32 EnduranceRegen; + uint32 Haste; + uint32 DamageShield; + uint32 RecastDelay; + uint32 RecastType; + uint32 AugDistiller; + bool Attuneable; + bool NoPet; + bool PotionBelt; + bool Stackable; + bool NoTransfer; + bool QuestItemFlag; + int16 StackSize; + uint8 PotionBeltSlots; + item::ItemEffect_Struct Click, Proc, Worn, Focus, Scroll, Bard; + + uint8 Book; // 0=Not book, 1=Book + uint32 BookType; + char Filename[33]; // Filename for book data + // Begin SoF Fields + int32 SVCorruption; + uint32 Purity; + uint8 EvolvingItem; + uint32 EvolvingID; + uint8 EvolvingLevel; + uint8 EvolvingMax; + uint32 BackstabDmg; + uint32 DSMitigation; + int32 HeroicStr; + int32 HeroicInt; + int32 HeroicWis; + int32 HeroicAgi; + int32 HeroicDex; + int32 HeroicSta; + int32 HeroicCha; + int32 HeroicMR; + int32 HeroicFR; + int32 HeroicCR; + int32 HeroicDR; + int32 HeroicPR; + int32 HeroicSVCorrup; + int32 HealAmt; + int32 SpellDmg; + uint32 LDoNSellBackRate; + uint32 ScriptFileID; + uint16 ExpendableArrow; + uint32 Clairvoyance; + char ClickName[65]; + char ProcName[65]; + char WornName[65]; + char FocusName[65]; + char ScrollName[65]; + //BardName + + bool IsEquipable(uint16 Race, uint16 Class); + bool IsClassCommon(); + bool IsClassBag(); + bool IsClassBook(); + bool IsType1HWeapon(); + bool IsType2HWeapon(); + bool IsTypeShield(); + + bool IsEquipable(uint16 Race, uint16 Class) const { return const_cast(this)->IsEquipable(Race, Class); } + bool IsClassCommon() const { return const_cast(this)->IsClassCommon(); } + bool IsClassBag() const { return const_cast(this)->IsClassBag(); } + bool IsClassBook() const { return const_cast(this)->IsClassBook(); } + bool IsType1HWeapon() const { return const_cast(this)->IsType1HWeapon(); } + bool IsType2HWeapon() const { return const_cast(this)->IsType2HWeapon(); } + bool IsTypeShield() const { return const_cast(this)->IsTypeShield(); } + }; + +} /*EQEmu*/ + +#endif /*COMMON_ITEM_BASE_H*/ diff --git a/common/item_fieldlist.h b/common/item_fieldlist.h index 1b3fe0cb0..665783498 100644 --- a/common/item_fieldlist.h +++ b/common/item_fieldlist.h @@ -41,6 +41,7 @@ F(ac) F(deity) F(skillmodvalue) F(UNK033) +F(skillmodmax) F(skillmodtype) F(banedmgrace) F(banedmgamt) @@ -172,7 +173,10 @@ F(bardlevel) F(questitemflag) F(svcorruption) F(purity) +F(evoitem) +F(evoid) F(evolvinglevel) +F(evomax) F(backstabdmg) F(dsmitigation) F(heroic_str) diff --git a/common/item_struct.h b/common/item_struct.h deleted file mode 100644 index 3ef26db94..000000000 --- a/common/item_struct.h +++ /dev/null @@ -1,251 +0,0 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 04111-1307 USA -*/ - -#ifndef ITEM_STRUCT_H -#define ITEM_STRUCT_H - -/* - * Note: (Doodman) - * This structure has field names that match the DB name exactly. - * Please take care as to not mess this up as it should make - * everyones life (i.e. mine) much easier. And the DB names - * match the field name from the 13th floor (SEQ) item collectors, - * so please maintain that as well. - * - * Note #2: (Doodman) - * UnkXXX fields are left in here for completeness but commented - * out since they are really unknown and since the items are now - * preserialized they should not be needed. Conversly if they - * -are- needed, then they shouldn't be unkown. - * - * Note #3: (Doodman) - * Please take care when adding new found data fields to add them - * to the appropriate structure. Item_Struct has elements that are - * global to all types of items only. - * - * Note #4: (Doodman) - * Made ya look! Ha! - */ - -//#include "eq_constants.h" -#include "eq_dictionary.h" - -/* -** Child struct of Item_Struct: -** Effect data: Click, Proc, Focus, Worn, Scroll -** -*/ -struct ItemEffect_Struct { - int16 Effect; - uint8 Type; - uint8 Level; - uint8 Level2; - //MaxCharges - //CastTime - //RecastDelay - //RecastType - //ProcRate -}; - -class ItemInst; - -struct InternalSerializedItem_Struct { - int16 slot_id; - const void * inst; -}; - -// use EmuConstants::ITEM_COMMON_SIZE -//#define MAX_AUGMENT_SLOTS 5 - -struct Item_Struct { - bool IsEquipable(uint16 Race, uint16 Class) const; - // Non packet based fields - uint8 MinStatus; - - // Packet based fields - uint8 ItemClass; // Item Type: 0=common, 1=container, 2=book - char Name[64]; // Name - char Lore[80]; // Lore Name: *=lore, &=summoned, #=artifact, ~=pending lore - char IDFile[30]; // Visible model - uint32 ID; // Unique ID (also PK for DB) - uint8 Weight; // Item weight * 10 - uint8 NoRent; // No Rent: 0=norent, 255=not norent - uint8 NoDrop; // No Drop: 0=nodrop, 255=not nodrop - uint8 Size; // Size: 0=tiny, 1=small, 2=medium, 3=large, 4=giant - uint32 Slots; // Bitfield for which slots this item can be used in - uint32 Price; // Item cost (?) - uint32 Icon; // Icon Number - uint32 LoreGroup; // Later items use LoreGroup instead of LoreFlag. we might want to see about changing this to int32 since it is commonly -1 and is constantly being cast from signed (-1) to unsigned (4294967295) - bool LoreFlag; // This will be true if LoreGroup is non-zero - bool PendingLoreFlag; - bool ArtifactFlag; - bool SummonedFlag; - uint8 FVNoDrop; // Firiona Vie nodrop flag - uint32 Favor; // Individual favor - uint32 GuildFavor; // Guild favor - uint32 PointType; - - //uint32 Unk117; - //uint32 Unk118; - //uint32 Unk121; - //uint32 Unk124; - - uint8 BagType; // 0:Small Bag, 1:Large Bag, 2:Quiver, 3:Belt Pouch ... there are 50 types - uint8 BagSlots; // Number of slots: can only be 2, 4, 6, 8, or 10 - uint8 BagSize; // 0:TINY, 1:SMALL, 2:MEDIUM, 3:LARGE, 4:GIANT - uint8 BagWR; // 0->100 - - bool BenefitFlag; - bool Tradeskills; // Is this a tradeskill item? - int8 CR; // Save vs Cold - int8 DR; // Save vs Disease - int8 PR; // Save vs Poison - int8 MR; // Save vs Magic - int8 FR; // Save vs Fire - int8 AStr; // Strength - int8 ASta; // Stamina - int8 AAgi; // Agility - int8 ADex; // Dexterity - int8 ACha; // Charisma - int8 AInt; // Intelligence - int8 AWis; // Wisdom - int32 HP; // HP - int32 Mana; // Mana - int32 AC; // AC - uint32 Deity; // Bitmask of Deities that can equip this item - //uint32 Unk033 - int32 SkillModValue; // % Mod to skill specified in SkillModType - uint32 SkillModType; // Type of skill for SkillModValue to apply to - uint32 BaneDmgRace; // Bane Damage Race - int8 BaneDmgAmt; // Bane Damage Body Amount - uint32 BaneDmgBody; // Bane Damage Body - bool Magic; // True=Magic Item, False=not - int32 CastTime_; - uint8 ReqLevel; // Required Level to use item - uint32 BardType; // Bard Skill Type - int32 BardValue; // Bard Skill Amount - int8 Light; // Light - uint8 Delay; // Delay * 10 - uint8 RecLevel; // Recommended level to use item - uint8 RecSkill; // Recommended skill to use item (refers to primary skill of item) - uint8 ElemDmgType; // Elemental Damage Type (1=magic, 2=fire) - uint8 ElemDmgAmt; // Elemental Damage - uint8 Range; // Range of item - uint32 Damage; // Delay between item usage (in 0.1 sec increments) - uint32 Color; // RR GG BB 00 <-- as it appears in pc - uint32 Classes; // Bitfield of classes that can equip item (1 << class#) - uint32 Races; // Bitfield of races that can equip item (1 << race#) - //uint32 Unk054; - int16 MaxCharges; // Maximum charges items can hold: -1 if not a chargeable item - uint8 ItemType; // Item Type/Skill (itemClass* from above) - uint8 Material; // Item material type - uint32 HerosForgeModel;// Hero's Forge Armor Model Type (2-13?) - float SellRate; // Sell rate - //uint32 Unk059; - union { - uint32 Fulfilment; // Food fulfilment (How long it lasts) - int16 CastTime; // Cast Time for clicky effects, in milliseconds - }; - uint32 EliteMaterial; - int32 ProcRate; - int8 CombatEffects; // PoP: Combat Effects + - int8 Shielding; // PoP: Shielding % - int8 StunResist; // PoP: Stun Resist % - int8 StrikeThrough; // PoP: Strike Through % - uint32 ExtraDmgSkill; - uint32 ExtraDmgAmt; - int8 SpellShield; // PoP: Spell Shield % - int8 Avoidance; // PoP: Avoidance + - int8 Accuracy; // PoP: Accuracy + - uint32 CharmFileID; - int32 FactionMod1; // Faction Mod 1 - int32 FactionMod2; // Faction Mod 2 - int32 FactionMod3; // Faction Mod 3 - int32 FactionMod4; // Faction Mod 4 - int32 FactionAmt1; // Faction Amt 1 - int32 FactionAmt2; // Faction Amt 2 - int32 FactionAmt3; // Faction Amt 3 - int32 FactionAmt4; // Faction Amt 4 - char CharmFile[32]; // ? - uint32 AugType; - uint8 AugSlotType[EmuConstants::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Type - uint8 AugSlotVisible[EmuConstants::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Visible - uint8 AugSlotUnk2[EmuConstants::ITEM_COMMON_SIZE]; // RoF: Augment Slot 1-6 Unknown - uint32 LDoNTheme; - uint32 LDoNPrice; - uint32 LDoNSold; - uint32 BaneDmgRaceAmt; - uint32 AugRestrict; - uint32 Endur; - uint32 DotShielding; - uint32 Attack; - uint32 Regen; - uint32 ManaRegen; - uint32 EnduranceRegen; - uint32 Haste; - uint32 DamageShield; - uint32 RecastDelay; - uint32 RecastType; - uint32 AugDistiller; - bool Attuneable; - bool NoPet; - bool PotionBelt; - bool Stackable; - bool NoTransfer; - bool QuestItemFlag; - int16 StackSize; - uint8 PotionBeltSlots; - ItemEffect_Struct Click, Proc, Worn, Focus, Scroll, Bard; - - uint8 Book; // 0=Not book, 1=Book - uint32 BookType; - char Filename[33]; // Filename for book data - // Begin SoF Fields - int32 SVCorruption; - uint32 Purity; - uint8 EvolvingLevel; - uint32 BackstabDmg; - uint32 DSMitigation; - int32 HeroicStr; - int32 HeroicInt; - int32 HeroicWis; - int32 HeroicAgi; - int32 HeroicDex; - int32 HeroicSta; - int32 HeroicCha; - int32 HeroicMR; - int32 HeroicFR; - int32 HeroicCR; - int32 HeroicDR; - int32 HeroicPR; - int32 HeroicSVCorrup; - int32 HealAmt; - int32 SpellDmg; - uint32 LDoNSellBackRate; - uint32 ScriptFileID; - uint16 ExpendableArrow; - uint32 Clairvoyance; - char ClickName[65]; - char ProcName[65]; - char WornName[65]; - char FocusName[65]; - char ScrollName[65]; - -}; - -#endif diff --git a/common/light_source.cpp b/common/light_source.cpp new file mode 100644 index 000000000..476f315b8 --- /dev/null +++ b/common/light_source.cpp @@ -0,0 +1,99 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "light_source.h" + +#include + + +uint8 EQEmu::lightsource::TypeToLevel(uint8 light_type) +{ + switch (light_type) { + case LightTypeGlobeOfStars: + return LightLevelBrilliant; // 10 + case LightTypeFlamelessLantern: + case LightTypeGreaterLightstone: + return LightLevelLargeMagic; // 9 + case LightTypeLargeLantern: + return LightLevelLargeLantern; // 8 + case LightTypeSteinOfMoggok: + case LightTypeLightstone: + return LightLevelMagicLantern; // 7 + case LightTypeSmallLantern: + return LightLevelSmallLantern; // 6 + case LightTypeColdlight: + case LightTypeUnknown2: + return LightLevelBlueLight; // 5 + case LightTypeFireBeetleEye: + case LightTypeUnknown1: + return LightLevelRedLight; // 4 + case LightTypeTinyGlowingSkull: + case LightTypeLightGlobe: + return LightLevelSmallMagic; // 3 + case LightTypeTorch: + return LightLevelTorch; // 2 + case LightTypeCandle: + return LightLevelCandle; // 1 + default: + return LightLevelUnlit; // 0 + } +} + +bool EQEmu::lightsource::IsLevelGreater(uint8 left_type, uint8 right_type) +{ + static const uint8 light_levels[LightTypeCount] = { + LightLevelUnlit, /* LightTypeNone */ + LightLevelCandle, /* LightTypeCandle */ + LightLevelTorch, /* LightTypeTorch */ + LightLevelSmallMagic, /* LightTypeTinyGlowingSkull */ + LightLevelSmallLantern, /* LightTypeSmallLantern */ + LightLevelMagicLantern, /* LightTypeSteinOfMoggok */ + LightLevelLargeLantern, /* LightTypeLargeLantern */ + LightLevelLargeMagic, /* LightTypeFlamelessLantern */ + LightLevelBrilliant, /* LightTypeGlobeOfStars */ + LightLevelSmallMagic, /* LightTypeLightGlobe */ + LightLevelMagicLantern, /* LightTypeLightstone */ + LightLevelLargeMagic, /* LightTypeGreaterLightstone */ + LightLevelRedLight, /* LightTypeFireBeetleEye */ + LightLevelBlueLight, /* LightTypeColdlight */ + LightLevelRedLight, /* LightTypeUnknown1 */ + LightLevelBlueLight /* LightTypeUnknown2 */ + }; + + if (left_type >= LightTypeCount) { left_type = LightTypeNone; } + if (right_type >= LightTypeCount) { right_type = LightTypeNone; } + + return (light_levels[left_type] > light_levels[right_type]); +} + +EQEmu::LightSource_Struct::LightSource_Struct() +{ + Clear(); +} + +void EQEmu::LightSource_Struct::Clear() +{ + memset(&Slot, 0, (sizeof(uint8) * lightsource::LightCount)); +} + +void EQEmu::LightSourceProfile::Clear() +{ + Type.Clear(); + Level.Clear(); +} diff --git a/common/light_source.h b/common/light_source.h new file mode 100644 index 000000000..a77049e4f --- /dev/null +++ b/common/light_source.h @@ -0,0 +1,115 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_LIGHT_SOURCE_H +#define COMMON_LIGHT_SOURCE_H + +#include "types.h" + + +namespace EQEmu +{ + namespace lightsource { + enum LightSlot { + LightInnate = 0, // Defined by db field `npc_types`.`light` - where appropriate + LightEquipment, // Item_Struct::light value of worn/carried equipment + LightSpell, // Set value of any light-producing spell (can be modded to mimic equip_light behavior) + LightActive, // Highest value of all light sources + LightCount + }; + + enum LightType { + LightTypeNone = 0, + LightTypeCandle, + LightTypeTorch, + LightTypeTinyGlowingSkull, + LightTypeSmallLantern, + LightTypeSteinOfMoggok, // 5 + LightTypeLargeLantern, + LightTypeFlamelessLantern, + LightTypeGlobeOfStars, + LightTypeLightGlobe, + LightTypeLightstone, // 10 + LightTypeGreaterLightstone, + LightTypeFireBeetleEye, + LightTypeColdlight, + LightTypeUnknown1, + LightTypeUnknown2, // 15 + LightTypeCount + }; + + enum LightLevel { + LightLevelUnlit = 0, + LightLevelCandle, + LightLevelTorch, + LightLevelSmallMagic, + LightLevelRedLight, + LightLevelBlueLight, // 5 + LightLevelSmallLantern, + LightLevelMagicLantern, + LightLevelLargeLantern, + LightLevelLargeMagic, + LightLevelBrilliant, // 10 + LightLevelCount + }; + + extern uint8 TypeToLevel(uint8 light_type); + extern bool IsLevelGreater(uint8 left_type, uint8 right_type); + + }; /*lightsource*/ + + struct LightSource_Struct { + uint8 Slot[lightsource::LightCount]; + + LightSource_Struct(); + + void Clear(); + + inline uint8& operator[](lightsource::LightSlot index) { return Slot[index]; } + }; + + struct LightSourceProfile { + /* + Current criteria (light types): + Equipment: { 0 .. 15 } + General: { 9 .. 13 } + + Notes: + - Initial character load and item movement updates use different light source update behaviors + -- Server procedure matches the item movement behavior since most updates occur post-character load + - MainAmmo is not considered when determining light sources + - No 'Sub' or 'Aug' items are recognized as light sources + - Light types '< 9' and '> 13' are not considered for general (carried) light sources + - If values > 0x0F are valid, then assignment limiters will need to be removed + - MainCursor 'appears' to be a valid light source update slot..but, have not experienced updates during debug sessions + - All clients have a bug regarding stackable items (light and sound updates are not processed when picking up an item) + -- The timer-based update cancels out the invalid light source + */ + + LightSource_Struct Type; // Light types (classifications) + LightSource_Struct Level; // Light levels (intensities) - used to determine which light source should be active + + LightSourceProfile() { } + + void Clear(); + }; + +} /*EQEmu*/ + +#endif /*COMMON_LIGHT_SOURCE_H*/ diff --git a/common/memory_buffer.cpp b/common/memory_buffer.cpp new file mode 100644 index 000000000..898851cb3 --- /dev/null +++ b/common/memory_buffer.cpp @@ -0,0 +1,277 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "memory_buffer.h" + + +EQEmu::MemoryBuffer::MemoryBuffer() +{ + buffer_ = nullptr; + size_ = 0; + capacity_ = 0; + read_pos_ = 0; + write_pos_ = 0; +} + +EQEmu::MemoryBuffer::MemoryBuffer(size_t sz) +{ + buffer_ = nullptr; + size_ = 0; + capacity_ = 0; + read_pos_ = 0; + write_pos_ = 0; + Resize(sz); +} + +EQEmu::MemoryBuffer::MemoryBuffer(const MemoryBuffer &other) +{ + if(other.capacity_) { + buffer_ = new uchar[other.capacity_]; + memcpy(buffer_, other.buffer_, other.capacity_); + } else { + buffer_ = nullptr; + } + + size_ = other.size_; + capacity_ = other.capacity_; + write_pos_ = other.write_pos_; + read_pos_ = other.read_pos_; +} + +EQEmu::MemoryBuffer::MemoryBuffer(MemoryBuffer &&other) +{ + uchar *tbuf = other.buffer_; + size_t tsz = other.size_; + size_t tcapacity = other.capacity_; + size_t twrite_pos = other.write_pos_; + size_t tread_pos = other.read_pos_; + + other.buffer_ = nullptr; + other.size_ = 0; + other.capacity_ = 0; + other.read_pos_ = 0; + other.write_pos_ = 0; + + buffer_ = tbuf; + size_ = tsz; + capacity_ = tcapacity; + write_pos_ = twrite_pos; + read_pos_ = tread_pos; +} + +EQEmu::MemoryBuffer& EQEmu::MemoryBuffer::operator=(const MemoryBuffer &other) +{ + if(this == &other) { + return *this; + } + + if(buffer_) { + delete[] buffer_; + } + + if(other.capacity_) { + buffer_ = new uchar[other.capacity_]; + memcpy(buffer_, other.buffer_, other.capacity_); + } + else { + buffer_ = nullptr; + } + + size_ = other.size_; + capacity_ = other.capacity_; + write_pos_ = other.write_pos_; + read_pos_ = other.read_pos_; + return *this; +} + +EQEmu::MemoryBuffer& EQEmu::MemoryBuffer::operator=(MemoryBuffer &&other) +{ + uchar *tbuf = other.buffer_; + size_t tsz = other.size_; + size_t tcapacity = other.capacity_; + size_t twrite_pos = other.write_pos_; + size_t tread_pos = other.read_pos_; + + other.buffer_ = nullptr; + other.size_ = 0; + other.capacity_ = 0; + other.read_pos_ = 0; + other.write_pos_ = 0; + + buffer_ = tbuf; + size_ = tsz; + capacity_ = tcapacity; + write_pos_ = twrite_pos; + read_pos_ = tread_pos; + return *this; +} + +EQEmu::MemoryBuffer& EQEmu::MemoryBuffer::operator+=(const MemoryBuffer &rhs) +{ + if(!rhs.buffer_) { + return *this; + } + + if(buffer_) { + size_t old_size = size_; + Resize(size_ + rhs.size_); + memcpy(&buffer_[old_size], rhs.buffer_, rhs.size_); + } else { + buffer_ = new uchar[rhs.capacity_]; + memcpy(buffer_, rhs.buffer_, rhs.capacity_); + size_ = rhs.size_; + capacity_ = rhs.capacity_; + } + + return *this; +} + +EQEmu::MemoryBuffer::~MemoryBuffer() +{ + Clear(); +} + +uchar& EQEmu::MemoryBuffer::operator[](size_t pos) +{ + return buffer_[pos]; +} + +const uchar& EQEmu::MemoryBuffer::operator[](size_t pos) const +{ + return buffer_[pos]; +} + +bool EQEmu::MemoryBuffer::Empty() +{ + return size_ == 0; +} + +bool EQEmu::MemoryBuffer::Empty() const +{ + return size_ == 0; +} + +size_t EQEmu::MemoryBuffer::Size() +{ + return size_; +} + +size_t EQEmu::MemoryBuffer::Size() const +{ + return size_; +} + +size_t EQEmu::MemoryBuffer::Capacity() +{ + return capacity_; +} + +size_t EQEmu::MemoryBuffer::Capacity() const +{ + return capacity_; +} + +void EQEmu::MemoryBuffer::Resize(size_t sz) +{ + if(!buffer_) { + size_t new_size = sz + 64; + buffer_ = new uchar[new_size]; + capacity_ = new_size; + size_ = sz; + memset(buffer_, 0, capacity_); + return; + } + + if(sz > capacity_) { + size_t new_size = sz + 32; + uchar *temp = new uchar[new_size]; + memcpy(temp, buffer_, capacity_); + delete[] buffer_; + buffer_ = temp; + + capacity_ = new_size; + size_ = sz; + } + else { + size_ = sz; + } +} + +void EQEmu::MemoryBuffer::Clear() +{ + if(buffer_) { + delete[] buffer_; + buffer_ = nullptr; + } + + size_ = 0; + capacity_ = 0; + write_pos_ = 0; + read_pos_ = 0; +} + +void EQEmu::MemoryBuffer::Zero() +{ + if(buffer_) { + memset(buffer_, 0, capacity_); + } +} + +void EQEmu::MemoryBuffer::Write(const char *val, size_t len) +{ + size_t size_needed = write_pos_ + len; + Resize(size_needed); + + memcpy(&buffer_[write_pos_], val, len); + write_pos_ += len; +} + +void EQEmu::MemoryBuffer::Read(uchar *buf, size_t len) +{ + memcpy(buf, &buffer_[read_pos_], len); + read_pos_ += len; +} + +void EQEmu::MemoryBuffer::Read(char *str) +{ + size_t len = strlen((const char*)&buffer_[read_pos_]); + memcpy(str, &buffer_[read_pos_], len); + read_pos_ += len; +} + +void EQEmu::OutBuffer::overwrite(OutBuffer::pos_type position, const char *_Str, std::streamsize _Count) +{ + auto last_pos = tellp(); + seekp(position); + write(_Str, _Count); + seekp(last_pos); +} + +uchar* EQEmu::OutBuffer::detach() +{ + size_t buffer_size = tellp(); + if (buffer_size == 0) + return nullptr; + + auto out_buffer = new uchar[buffer_size]; + memcpy(out_buffer, str().c_str(), buffer_size); + flush(); + + return out_buffer; +} diff --git a/common/memory_buffer.h b/common/memory_buffer.h new file mode 100644 index 000000000..880b860ae --- /dev/null +++ b/common/memory_buffer.h @@ -0,0 +1,134 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_MEMORY_BUFFER +#define COMMON_MEMORY_BUFFER + +#include "types.h" + +#include +#include +#include +#include + + +namespace EQEmu +{ + class MemoryBuffer { + public: + MemoryBuffer(); + MemoryBuffer(size_t sz); + MemoryBuffer(const MemoryBuffer &other); + MemoryBuffer(MemoryBuffer &&other); + MemoryBuffer& operator=(const MemoryBuffer &other); + MemoryBuffer& operator=(MemoryBuffer &&other); + MemoryBuffer& operator+=(const MemoryBuffer &rhs); + friend MemoryBuffer operator+(MemoryBuffer lhs, const MemoryBuffer& rhs) { return lhs += rhs; } + ~MemoryBuffer(); + + uchar& operator[](size_t pos); + const uchar& operator[](size_t pos) const; + + template + operator T*() { + return reinterpret_cast(buffer_); + } + + template + operator T*() const { + return reinterpret_cast(buffer_); + } + + operator bool() { return buffer_ != nullptr; } + operator bool() const { return buffer_ != nullptr; } + + bool Empty(); + bool Empty() const; + size_t Size(); + size_t Size() const; + size_t Capacity(); + size_t Capacity() const; + + void Resize(size_t sz); + void Clear(); + void Zero(); + + template + void Write(T val) { + static_assert(std::is_pod::value, "MemoryBuffer::Write(T val) only works on pod and string types."); + Write((const char*)&val, sizeof(T)); + } + + template + T Read() { + static_assert(std::is_pod::value, "MemoryBuffer::Read() only works on pod and string types."); + T temp; + Read((uchar*)&temp, sizeof(T)); + return temp; + } + + void Write(const std::string &val) { + Write(val.c_str(), val.length()); + Write((uint8)0); + } + + void Write(const char *val) { + size_t len = strlen(val); + Write(val, len); + Write((uint8)0); + } + + std::string ReadString() { + std::string ret; + size_t len = strlen((const char*)&buffer_[read_pos_]); + ret.resize(len); + memcpy(&ret[0], &buffer_[read_pos_], len); + read_pos_ += len + 1; + return ret; + } + + void Write(const char *val, size_t len); + void Read(uchar *buf, size_t len); + void Read(char *str); + + inline size_t GetWritePosition() { return write_pos_; } + inline void SetWritePosition(size_t wp) { write_pos_ = wp; } + inline void WriteSkipBytes(size_t skip) { write_pos_ += skip; } + inline size_t GetReadPosition() { return read_pos_; } + inline void SetReadPosition(size_t rp) { read_pos_ = rp; } + inline void ReadSkipBytes(size_t skip) { read_pos_ += skip; } + + private: + uchar *buffer_; + size_t size_; + size_t capacity_; + size_t write_pos_; + size_t read_pos_; + }; + + class OutBuffer : public std::stringstream { + public: + inline size_t size() { return tellp(); } + void overwrite(OutBuffer::pos_type position, const char *_Str, std::streamsize _Count); + uchar* detach(); + }; + +} /*EQEmu*/ + +#endif /*COMMON_MEMORY_BUFFER*/ diff --git a/common/mutex.h b/common/mutex.h index b1a71c331..48f58bcac 100644 --- a/common/mutex.h +++ b/common/mutex.h @@ -18,7 +18,7 @@ #ifndef MYMUTEX_H #define MYMUTEX_H #ifdef _WINDOWS - #include + #include #include #else #include diff --git a/common/mysql_request_result.h b/common/mysql_request_result.h index 2944f528b..0cc02a366 100644 --- a/common/mysql_request_result.h +++ b/common/mysql_request_result.h @@ -2,7 +2,7 @@ #define MYSQL_REQUEST_RESULT_H #ifdef _WINDOWS - #include + #include #include #endif @@ -10,6 +10,12 @@ #include "types.h" #include "mysql_request_row.h" +#ifdef __FreeBSD__ + #include + #include + #include +#endif + class MySQLRequestResult { private: MYSQL_RES* m_Result; diff --git a/common/mysql_request_row.h b/common/mysql_request_row.h index 06788025d..ddfbddee9 100644 --- a/common/mysql_request_row.h +++ b/common/mysql_request_row.h @@ -2,7 +2,7 @@ #define MYSQL_REQUEST_ROW_H #ifdef _WINDOWS - #include + #include #include #endif diff --git a/common/opcode_dispatch.h b/common/opcode_dispatch.h index 657d9a525..496dcdea3 100644 --- a/common/opcode_dispatch.h +++ b/common/opcode_dispatch.h @@ -146,6 +146,7 @@ INr(OP_GuildDelete); //? IN(OP_GuildPublicNote, GuildUpdate_PublicNote); INz(OP_GetGuildsList); //? IN(OP_SetGuildMOTD, GuildMOTD_Struct); +IN(OP_SetRunMode, SetRunMode_Struct); INz(OP_GuildPeace); //? INz(OP_GuildWar); //? IN(OP_GuildLeader, GuildMakeLeader); @@ -172,7 +173,7 @@ IN(OP_TradeAcceptClick, TradeAccept_Struct); IN(OP_BoardBoat, EntityId_Struct); //not really the struct, just 4 bytes INz(OP_LeaveBoat); //? IN(OP_RandomReq, RandomReq_Struct); -IN(OP_Buff, SpellBuffFade_Struct); +IN(OP_Buff, SpellBuffPacket_Struct); IN(OP_GMHideMe, SpawnAppearance_Struct); IN(OP_GMNameChange, GMName_Struct); IN(OP_GMKill, GMKill_Struct); @@ -414,7 +415,7 @@ OUTv(OP_SendAATable, SendAA_Struct); OUT(OP_AAAction, UseAA_Struct); OUT(OP_Bazaar, BazaarReturnDone_Struct); //alt:OUT(OP_Bazaar, BazaarWelcome_Struct); -OUT(OP_Buff, SpellBuffFade_Struct); +OUT(OP_Buff, SpellBuffPacket_Struct); OUT(OP_ClickObject, ClickObject_Struct); OUT(OP_ClientUpdate, PlayerPositionUpdateServer_Struct); OUT(OP_SpawnPositionUpdate, SpawnPositionUpdate_Struct); diff --git a/common/packet_dump.cpp b/common/packet_dump.cpp index 4ab1fcbef..1e28c2616 100644 --- a/common/packet_dump.cpp +++ b/common/packet_dump.cpp @@ -54,7 +54,7 @@ void DumpPacketHex(const uchar* buf, uint32 size, uint32 cols, uint32 skip) { // Output as HEX char output[4]; int j = 0; - char* ascii = new char[cols+1]; + auto ascii = new char[cols + 1]; memset(ascii, 0, cols+1); uint32 i; for(i=skip; i #include + namespace RoF { static const char *name = "RoF"; static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id, uint8 depth); // server to client inventory location converters - static inline structs::ItemSlotStruct ServerToRoFSlot(uint32 serverSlot); - static inline structs::MainInvItemSlotStruct ServerToRoFMainInvSlot(uint32 serverSlot); + static inline structs::InventorySlot_Struct ServerToRoFSlot(uint32 serverSlot); + static inline structs::TypelessInventorySlot_Struct ServerToRoFTypelessSlot(uint32 serverSlot); static inline uint32 ServerToRoFCorpseSlot(uint32 serverCorpseSlot); // client to server inventory location converters - static inline uint32 RoFToServerSlot(structs::ItemSlotStruct rofSlot); - static inline uint32 RoFToServerMainInvSlot(structs::MainInvItemSlotStruct rofSlot); + static inline uint32 RoFToServerSlot(structs::InventorySlot_Struct rofSlot); + static inline uint32 RoFToServerTypelessSlot(structs::TypelessInventorySlot_Struct rofSlot); static inline uint32 RoFToServerCorpseSlot(uint32 rofCorpseSlot); // server to client text link converter @@ -42,12 +63,17 @@ namespace RoF // client to server text link converter static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink); + static inline CastingSlot ServerToRoFCastingSlot(EQEmu::CastingSlot slot); + static inline EQEmu::CastingSlot RoFToServerCastingSlot(CastingSlot slot); + void Register(EQStreamIdentifier &into) { //create our opcode manager if we havent already if (opcodes == nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; //load up the opcode manager. @@ -77,9 +103,6 @@ namespace RoF signature.first_length = sizeof(structs::ClientZoneEntry_Struct); signature.first_eq_opcode = opcodes->EmuToEQ(OP_ZoneEntry); into.RegisterPatch(signature, pname.c_str(), &opcodes, &struct_strategy); - - - Log.Out(Logs::General, Logs::Netcode, "[IDENTIFY] Registered patch %s", name); } @@ -91,7 +114,9 @@ namespace RoF if (opcodes != nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; if (!opcodes->ReloadOpcodes(opfile.c_str())) { @@ -117,9 +142,9 @@ namespace RoF return(r); } - const ClientVersion Strategy::GetClientVersion() const + const EQEmu::versions::ClientVersion Strategy::ClientVersion() const { - return ClientVersion::RoF; + return EQEmu::versions::ClientVersion::RoF; } #include "ss_define.h" @@ -162,7 +187,7 @@ namespace RoF eq->unknown000 = 1; OUT(npcid); - eq->slot = ServerToRoFMainInvSlot(emu->slot); + eq->inventory_slot = ServerToRoFTypelessSlot(emu->slot); OUT(charges); OUT(sell_price); @@ -180,8 +205,9 @@ namespace RoF if (opcode == 8) { AltCurrencyPopulate_Struct *populate = (AltCurrencyPopulate_Struct*)emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(structs::AltCurrencyPopulate_Struct) - + sizeof(structs::AltCurrencyPopulateEntry_Struct) * populate->count); + auto outapp = new EQApplicationPacket( + OP_AltCurrency, sizeof(structs::AltCurrencyPopulate_Struct) + + sizeof(structs::AltCurrencyPopulateEntry_Struct) * populate->count); structs::AltCurrencyPopulate_Struct *out_populate = (structs::AltCurrencyPopulate_Struct*)outapp->pBuffer; out_populate->opcode = populate->opcode; @@ -199,7 +225,7 @@ namespace RoF dest->FastQueuePacket(&outapp, ack_req); } else { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyUpdate_Struct)); memcpy(outapp->pBuffer, emu_buffer, sizeof(AltCurrencyUpdate_Struct)); dest->FastQueuePacket(&outapp, ack_req); } @@ -214,7 +240,7 @@ namespace RoF SETUP_DIRECT_ENCODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); OUT(merchant_entity_id); - eq->slot_id = ServerToRoFMainInvSlot(emu->slot_id); + eq->inventory_slot = ServerToRoFTypelessSlot(emu->slot_id); OUT(charges); OUT(cost); @@ -227,8 +253,8 @@ namespace RoF SETUP_DIRECT_ENCODE(Animation_Struct, structs::Animation_Struct); OUT(spawnid); - OUT(value); OUT(action); + OUT(speed); FINISH_ENCODE(); } @@ -238,7 +264,7 @@ namespace RoF ENCODE_LENGTH_EXACT(ApplyPoison_Struct); SETUP_DIRECT_ENCODE(ApplyPoison_Struct, structs::ApplyPoison_Struct); - eq->inventorySlot = ServerToRoFMainInvSlot(emu->inventorySlot); + eq->inventory_slot = ServerToRoFTypelessSlot(emu->inventorySlot); OUT(success); FINISH_ENCODE(); @@ -382,22 +408,31 @@ namespace RoF ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - eq->unknown004 = 2; - //eq->level = 80; - //eq->effect = 0; - OUT(level); - OUT(effect); - eq->unknown007 = 0; - eq->unknown008 = 1.0f; - OUT(spellid); - OUT(duration); - eq->playerId = 0x7cde; - OUT(slotid); - OUT(num_hits); + OUT(buff.effect_type); + OUT(buff.level); + // just so we're 100% sure we get a 1.0f ... + eq->buff.bard_modifier = emu->buff.bard_modifier == 10 ? 1.0f : emu->buff.bard_modifier / 10.0f; + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.player_id); + OUT(buff.num_hits); + OUT(buff.y); + OUT(buff.x); + OUT(buff.z); + uint16 buffslot = emu->slotid; + // Not sure if this is needs amending for RoF yet. + if (buffslot >= 25) + { + buffslot += 17; + } + + // TODO: implement slot_data stuff + eq->slotid = buffslot; + if (emu->bufffade == 1) eq->bufffade = 1; else @@ -409,15 +444,15 @@ namespace RoF { outapp = new EQApplicationPacket(OP_BuffCreate, 29); outapp->WriteUInt32(emu->entityid); - outapp->WriteUInt32(0x0271); // Unk + outapp->WriteUInt32(0); // tic timer outapp->WriteUInt8(0); // Type of OP_BuffCreate packet ? outapp->WriteUInt16(1); // 1 buff in this packet - outapp->WriteUInt32(emu->slotid); + outapp->WriteUInt32(buffslot); outapp->WriteUInt32(0xffffffff); // SpellID (0xffff to remove) outapp->WriteUInt32(0); // Duration outapp->WriteUInt32(0); // ? outapp->WriteUInt8(0); // Caster name - outapp->WriteUInt8(0); // Terminating byte + outapp->WriteUInt8(0); // Type } FINISH_ENCODE(); @@ -435,7 +470,7 @@ namespace RoF memset(__packet->pBuffer, 0, sz); __packet->WriteUInt32(emu->entity_id); - __packet->WriteUInt32(0); // PlayerID ? + __packet->WriteUInt32(emu->tic_timer); __packet->WriteUInt8(emu->all_buffs); // 1 indicates all buffs on the player (0 to add or remove a single buff) __packet->WriteUInt16(emu->count); @@ -454,7 +489,7 @@ namespace RoF __packet->WriteUInt32(emu->entries[i].num_hits); // Unknown __packet->WriteString(""); } - __packet->WriteUInt8(!emu->all_buffs); // Unknown + __packet->WriteUInt8(emu->type); // Unknown FINISH_ENCODE(); } @@ -475,13 +510,10 @@ namespace RoF ENCODE_LENGTH_EXACT(CastSpell_Struct); SETUP_DIRECT_ENCODE(CastSpell_Struct, structs::CastSpell_Struct); - if (emu->slot == 10) - eq->slot = 13; - else - OUT(slot); - + eq->slot = static_cast(ServerToRoFCastingSlot(static_cast(emu->slot))); + OUT(spell_id); - eq->inventoryslot = ServerToRoFSlot(emu->inventoryslot); + eq->inventory_slot = ServerToRoFSlot(emu->inventoryslot); //OUT(inventoryslot); OUT(target_id); @@ -531,70 +563,49 @@ namespace RoF ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { - + if (!in->size) { in->size = 4; in->pBuffer = new uchar[in->size]; - - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(EQEmu::InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(EQEmu::InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", - opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); + opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(EQEmu::InternalSerializedItem_Struct)); delete in; - return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + EQEmu::InternalSerializedItem_Struct* eq = (EQEmu::InternalSerializedItem_Struct*)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); - for (int r = 0; r < ItemCount; r++, eq++) { + ob.write((const char*)&item_count, sizeof(uint32)); - uint32 Length = 0; + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ob, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); - - if (Serialized) { - - uchar *OldBuffer = in->pBuffer; - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ob.tellp(); } - delete[] __emu_buffer; + in->size = ob.size(); + in->pBuffer = ob.detach(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -658,7 +669,10 @@ namespace RoF OUT(type); OUT(spellid); OUT(damage); - eq->sequence = emu->sequence; + OUT(force); + OUT(meleepush_xy); + OUT(meleepush_z); + OUT(special); FINISH_ENCODE(); } @@ -702,7 +716,7 @@ namespace RoF { SETUP_VAR_ENCODE(ExpeditionCompass_Struct); ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count); - + OUT(count); for (uint32 i = 0; i < emu->count; ++i) @@ -972,9 +986,9 @@ namespace RoF VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->drop_id); // Some unique id VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading); - VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Normally 0, but seen (float)255.0 as well - VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Unknown - VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 1); // Need to add emu->size to struct + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // X tilt + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Y tilt + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt. VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z); @@ -1042,7 +1056,8 @@ namespace RoF { //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct)); structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); @@ -1060,7 +1075,8 @@ namespace RoF //if(gjs->action == groupActLeave) // Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct)); structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); @@ -1097,7 +1113,7 @@ namespace RoF //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Leadername is %s", gu2->leadersname); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupUpdateB, PacketLength); + auto outapp = new EQApplicationPacket(OP_GroupUpdateB, PacketLength); char *Buffer = (char *)outapp->pBuffer; @@ -1163,7 +1179,8 @@ namespace RoF memcpy(eq->membername, emu->membername, sizeof(eq->membername)); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); GroupLeadershipAAUpdate_Struct *GLAAus = (GroupLeadershipAAUpdate_Struct*)outapp->pBuffer; GLAAus->NPCMarkerID = emu->NPCMarkerID; @@ -1176,6 +1193,54 @@ namespace RoF dest->FastQueuePacket(&outapp); } + ENCODE(OP_GuildBank) + { + auto in = *p; + *p = nullptr; + auto outapp = new EQApplicationPacket(OP_GuildBank, in->size + 4); // all of them are 4 bytes bigger + + // The first action in the enum was removed, everything 1 less + // Normally we cast them to their structs, but there are so many here! will only do when it's easier + switch (in->ReadUInt32()) { + case 10: // GuildBankAcknowledge + outapp->WriteUInt32(9); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + break; + case 5: // GuildBankDeposit (ack) + outapp->WriteUInt32(4); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + outapp->WriteUInt32(in->ReadUInt32()); + break; + case 1: { // GuildBankItemUpdate + auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; + auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; + eq->Action = 0; + OUT(Unknown004); + eq->Unknown08 = 0; + OUT(SlotID); + OUT(Area); + OUT(Unknown012); + OUT(ItemID); + OUT(Icon); + OUT(Quantity); + OUT(Permissions); + OUT(AllowMerge); + OUT(Useable); + OUT_str(ItemName); + OUT_str(Donator); + OUT_str(WhoFor); + OUT(Unknown226); + break; + } + default: + break; + } + delete in; + dest->FastQueuePacket(&outapp); + } + ENCODE(OP_GuildMemberList) { //consume the packet @@ -1249,7 +1314,7 @@ namespace RoF switch (emu_e->rank) { case 0: { e->rank = htonl(5); break; } // GUILD_MEMBER 0 case 1: { e->rank = htonl(3); break; } // GUILD_OFFICER 1 - case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2 + case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2 default: { e->rank = htonl(emu_e->rank); break; } // GUILD_NONE } @@ -1454,29 +1519,31 @@ namespace RoF ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + EQEmu::InternalSerializedItem_Struct* int_struct = (EQEmu::InternalSerializedItem_Struct*)(&__emu_buffer[4]); - if (!serialized) { + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); + + ob.write((const char*)__emu_buffer, 4); + + SerializeItem(ob, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ob.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + in->size = ob.size(); + in->pBuffer = ob.detach(); + delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -1485,7 +1552,7 @@ namespace RoF ENCODE_LENGTH_EXACT(ItemVerifyReply_Struct); SETUP_DIRECT_ENCODE(ItemVerifyReply_Struct, structs::ItemVerifyReply_Struct); - eq->slot = ServerToRoFSlot(emu->slot); + eq->inventory_slot = ServerToRoFSlot(emu->slot); OUT(spell); OUT(target); @@ -1556,7 +1623,8 @@ namespace RoF OUT(new_mana); OUT(stamina); OUT(spell_id); - eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2? + OUT(keepcasting); + eq->slot = -1; // this is spell gem slot. It's -1 in normal operation FINISH_ENCODE(); } @@ -1583,7 +1651,7 @@ namespace RoF PacketSize += sizeof(structs::MercenaryStance_Struct) * emu->Mercs[r].StanceCount; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, PacketSize); + auto outapp = new EQApplicationPacket(OP_MercenaryDataResponse, PacketSize); Buffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercTypeCount); @@ -1945,18 +2013,18 @@ namespace RoF __packet->WriteUInt8(1); // 1 indicates all buffs on the pet (0 to add or remove a single buff) __packet->WriteUInt16(emu->buffcount); - for (uint16 i = 0; i < BUFF_COUNT; ++i) + for (uint16 i = 0; i < PET_BUFF_COUNT; ++i) { if (emu->spellid[i]) { __packet->WriteUInt32(i); __packet->WriteUInt32(emu->spellid[i]); __packet->WriteUInt32(emu->ticsremaining[i]); - __packet->WriteUInt32(0); // Unknown + __packet->WriteUInt32(0); // numhits __packet->WriteString(""); } } - __packet->WriteUInt8(0); // Unknown + __packet->WriteUInt8(0); // some sort of type FINISH_ENCODE(); } @@ -1971,7 +2039,7 @@ namespace RoF uint32 PacketSize = 40000; // Calculate this later - EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayerProfile, PacketSize); + auto outapp = new EQApplicationPacket(OP_PlayerProfile, PacketSize); outapp->WriteUInt32(0); // Checksum, we will update this later outapp->WriteUInt32(0); // Checksum size, we will update this later @@ -2010,9 +2078,9 @@ namespace RoF outapp->WriteUInt32(22); // Equipment count - for (int r = 0; r < 9; r++) + for (int r = EQEmu::textures::TextureBegin; r < EQEmu::textures::TextureCount; r++) { - outapp->WriteUInt32(emu->item_material[r]); + outapp->WriteUInt32(emu->item_material.Slot[r].Material); outapp->WriteUInt32(0); outapp->WriteUInt32(0); outapp->WriteUInt32(0); @@ -2030,9 +2098,9 @@ namespace RoF outapp->WriteUInt32(0); } - outapp->WriteUInt32(9); // Equipment2 count + outapp->WriteUInt32(EQEmu::textures::TextureCount); // Equipment2 count - for (int r = 0; r < 9; r++) + for (int r = EQEmu::textures::TextureBegin; r < EQEmu::textures::TextureCount; r++) { outapp->WriteUInt32(0); outapp->WriteUInt32(0); @@ -2041,21 +2109,21 @@ namespace RoF outapp->WriteUInt32(0); } - outapp->WriteUInt32(9); // Tint Count + outapp->WriteUInt32(EQEmu::textures::TextureCount); // Tint Count for (int r = 0; r < 7; r++) { - outapp->WriteUInt32(emu->item_tint[r].Color); + outapp->WriteUInt32(emu->item_tint.Slot[r].Color); } // Write zeroes for extra two tint values outapp->WriteUInt32(0); outapp->WriteUInt32(0); - outapp->WriteUInt32(9); // Tint2 Count + outapp->WriteUInt32(EQEmu::textures::TextureCount); // Tint2 Count for (int r = 0; r < 7; r++) { - outapp->WriteUInt32(emu->item_tint[r].Color); + outapp->WriteUInt32(emu->item_tint.Slot[r].Color); } // Write zeroes for extra two tint values outapp->WriteUInt32(0); @@ -2118,7 +2186,7 @@ namespace RoF { outapp->WriteUInt32(emu->aa_array[r].AA); outapp->WriteUInt32(emu->aa_array[r].value); - outapp->WriteUInt32(0); + outapp->WriteUInt32(emu->aa_array[r].charges); } // Fill the other 60 AAs with zeroes @@ -2192,22 +2260,23 @@ namespace RoF outapp->WriteUInt32(structs::MAX_PP_MEMSPELL); // Memorised spell slots - for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++) + for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++) // first 12 { outapp->WriteUInt32(emu->mem_spells[r]); } - // zeroes for the rest of the slots + // zeroes for the rest of the slots -- the other 4 which don't work at all! for (uint32 r = 0; r < structs::MAX_PP_MEMSPELL - MAX_PP_MEMSPELL; r++) { outapp->WriteUInt32(0xFFFFFFFFU); } - outapp->WriteUInt32(13); // Unknown count + outapp->WriteUInt32(13); // gem refresh count - for (uint32 r = 0; r < 13; r++) + for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++) { - outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(emu->spellSlotRefresh[r]); // spell gem refresh } + outapp->WriteUInt32(0); // also refresh -- historically HT/LoH :P outapp->WriteUInt8(0); // Unknown @@ -2216,31 +2285,32 @@ namespace RoF for (uint32 r = 0; r < BUFF_COUNT; r++) { float instrument_mod = 0.0f; - uint8 slotid = emu->buffs[r].slotid; + uint8 effect_type = emu->buffs[r].effect_type; uint32 player_id = emu->buffs[r].player_id;; if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0) { instrument_mod = 1.0f + (emu->buffs[r].bard_modifier - 10) / 10.0f; - slotid = 2; + effect_type = 2; player_id = 0x000717fd; } else { - slotid = 0; + effect_type = 0; } - outapp->WriteUInt8(0); // Had this as slot, but always appears to be 0 on live. + // this is different than the client struct for some reason :P + // missing a few things, shuffled around + outapp->WriteUInt8(0); // this is an unknown outapp->WriteFloat(instrument_mod); outapp->WriteUInt32(player_id); outapp->WriteUInt8(0); outapp->WriteUInt32(emu->buffs[r].counters); - //outapp->WriteUInt8(emu->buffs[r].bard_modifier); outapp->WriteUInt32(emu->buffs[r].duration); outapp->WriteUInt8(emu->buffs[r].level); outapp->WriteUInt32(emu->buffs[r].spellid); - outapp->WriteUInt32(slotid); // Only ever seen 2 + outapp->WriteUInt8(effect_type); // Only ever seen 2 + outapp->WriteUInt32(emu->buffs[r].num_hits); outapp->WriteUInt32(0); - outapp->WriteUInt8(0); outapp->WriteUInt32(emu->buffs[r].counters); // Appears twice ? for (uint32 j = 0; j < 44; ++j) @@ -2288,12 +2358,12 @@ namespace RoF outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt32(consts::BANDOLIERS_SIZE); + outapp->WriteUInt32(profile::BandoliersSize); // Copy bandoliers where server and client indexes converge - for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { + for (uint32 r = 0; r < EQEmu::legacy::BANDOLIERS_SIZE && r < profile::BandoliersSize; ++r) { outapp->WriteString(emu->bandoliers[r].Name); - for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true + for (uint32 j = 0; j < profile::BandolierItemCount; ++j) { // Will need adjusting if 'server != client' is ever true outapp->WriteString(emu->bandoliers[r].Items[j].Name); outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID); if (emu->bandoliers[r].Items[j].Icon) { @@ -2306,19 +2376,19 @@ namespace RoF } } // Nullify bandoliers where server and client indexes diverge, with a client bias - for (uint32 r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + for (uint32 r = EQEmu::legacy::BANDOLIERS_SIZE; r < profile::BandoliersSize; ++r) { outapp->WriteString(""); - for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true + for (uint32 j = 0; j < profile::BandolierItemCount; ++j) { // Will need adjusting if 'server != client' is ever true outapp->WriteString(""); outapp->WriteUInt32(0); outapp->WriteSInt32(-1); } } - outapp->WriteUInt32(consts::POTION_BELT_ITEM_COUNT); + outapp->WriteUInt32(profile::PotionBeltSize); // Copy potion belt where server and client indexes converge - for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (uint32 r = 0; r < EQEmu::legacy::POTION_BELT_ITEM_COUNT && r < profile::PotionBeltSize; ++r) { outapp->WriteString(emu->potionbelt.Items[r].Name); outapp->WriteUInt32(emu->potionbelt.Items[r].ID); if (emu->potionbelt.Items[r].Icon) { @@ -2330,7 +2400,7 @@ namespace RoF } } // Nullify potion belt where server and client indexes diverge, with a client bias - for (uint32 r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (uint32 r = EQEmu::legacy::POTION_BELT_ITEM_COUNT; r < profile::PotionBeltSize; ++r) { outapp->WriteString(""); outapp->WriteUInt32(0); outapp->WriteSInt32(-1); @@ -2341,13 +2411,14 @@ namespace RoF outapp->WriteSInt32(234); // Endurance Total ? outapp->WriteSInt32(345); // Mana Total ? - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown + // these are needed to fix display bugs + outapp->WriteUInt32(0x19); // base CR + outapp->WriteUInt32(0x19); // base FR + outapp->WriteUInt32(0x19); // base MR + outapp->WriteUInt32(0xf); // base DR + outapp->WriteUInt32(0xf); // base PR + outapp->WriteUInt32(0xf); // base PhR? + outapp->WriteUInt32(0xf); // base Corrup outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown @@ -2450,9 +2521,9 @@ namespace RoF outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt32(EmuConstants::TRIBUTE_SIZE); + outapp->WriteUInt32(EQEmu::legacy::TRIBUTE_SIZE); - for (uint32 r = 0; r < EmuConstants::TRIBUTE_SIZE; r++) + for (uint32 r = 0; r < EQEmu::legacy::TRIBUTE_SIZE; r++) { outapp->WriteUInt32(emu->tributes[r].tribute); outapp->WriteUInt32(emu->tributes[r].tier); @@ -2643,7 +2714,7 @@ namespace RoF Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Player Profile Packet is %i bytes", outapp->GetWritePosition()); - unsigned char *NewBuffer = new unsigned char[outapp->GetWritePosition()]; + auto NewBuffer = new unsigned char[outapp->GetWritePosition()]; memcpy(NewBuffer, outapp->pBuffer, outapp->GetWritePosition()); safe_delete_array(outapp->pBuffer); outapp->pBuffer = NewBuffer; @@ -2665,7 +2736,7 @@ namespace RoF unsigned char * __emu_buffer = inapp->pBuffer; RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer; general->action = 8; @@ -2688,7 +2759,7 @@ namespace RoF { RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer; add_member->raidGen.action = in_add_member->raidGen.action; @@ -2708,7 +2779,8 @@ namespace RoF else if (raid_gen->action == 35) { RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + strlen(inmotd->motd) + 1); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + + strlen(inmotd->motd) + 1); structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer; outmotd->general.action = inmotd->general.action; @@ -2719,7 +2791,8 @@ namespace RoF else if (raid_gen->action == 14 || raid_gen->action == 30) { RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; outlaa->action = inlaa->action; @@ -2732,7 +2805,7 @@ namespace RoF { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer; strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64); strn0cpy(raid_general->player_name, in_raid_general->player_name, 64); @@ -2768,12 +2841,12 @@ namespace RoF OUT(object_type); OUT(some_id); eq->container_slot = ServerToRoFSlot(emu->unknown1); - structs::ItemSlotStruct RoFSlot; - RoFSlot.SlotType = 8; // Observed + structs::InventorySlot_Struct RoFSlot; + RoFSlot.Type = 8; // Observed RoFSlot.Unknown02 = 0; - RoFSlot.MainSlot = 0xffff; - RoFSlot.SubSlot = 0xffff; - RoFSlot.AugSlot = 0xffff; + RoFSlot.Slot = 0xffff; + RoFSlot.SubIndex = 0xffff; + RoFSlot.AugIndex = 0xffff; RoFSlot.Unknown01 = 0; eq->unknown_slot = RoFSlot; OUT(recipe_id); @@ -2808,7 +2881,7 @@ namespace RoF eq->aa_spent = emu->aa_spent; // These fields may need to be correctly populated at some point - eq->aapoints_assigned = emu->aa_spent + 1; + eq->aapoints_assigned = emu->aa_spent; eq->aa_spent_general = 0; eq->aa_spent_archetype = 0; eq->aa_spent_class = 0; @@ -2816,9 +2889,9 @@ namespace RoF for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i) { - eq->aa_list[i].aa_skill = emu->aa_list[i].aa_skill; - eq->aa_list[i].aa_value = emu->aa_list[i].aa_value; - eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08; + eq->aa_list[i].AA = emu->aa_list[i].AA; + eq->aa_list[i].value = emu->aa_list[i].value; + eq->aa_list[i].charges = emu->aa_list[i].charges; } FINISH_ENCODE(); @@ -2844,57 +2917,81 @@ namespace RoF ENCODE(OP_SendAATable) { - ENCODE_LENGTH_ATLEAST(SendAA_Struct); - SETUP_VAR_ENCODE(SendAA_Struct); - ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); + EQApplicationPacket *inapp = *p; + *p = nullptr; + AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer; - // Check clientver field to verify this AA should be sent for SoF - // clientver 1 is for all clients and 5 is for Live - if (emu->clientver <= 5) - { - OUT(id); - eq->unknown004 = 1; - //eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->title_sid = emu->id - emu->current_level + 1; - //eq->desc_sid = emu->id - emu->current_level + 1; - eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? -1 : (emu->sof_next_skill); - eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? -1 : (emu->sof_next_skill); - eq->title_sid = emu->sof_next_skill; - eq->desc_sid = emu->sof_next_skill; - OUT(class_type); - OUT(cost); - OUT(seq); - OUT(current_level); - eq->unknown037 = 1; // Introduced during HoT - OUT(prereq_skill); - eq->unknown045 = 1; // New Mar 21 2012 - Seen 1 - OUT(prereq_minpoints); - eq->type = emu->sof_type; - OUT(spellid); - eq->unknown057 = 1; // Introduced during HoT - OUT(spell_type); - OUT(spell_refresh); - OUT(classes); - OUT(berserker); - //eq->max_level = emu->sof_max_level; - OUT(max_level); - OUT(last_id); - OUT(next_id); - OUT(cost2); - eq->aa_expansion = emu->aa_expansion; - eq->special_category = emu->special_category; - OUT(total_abilities); - unsigned int r; - for (r = 0; r < emu->total_abilities; r++) { - OUT(abilities[r].skill_id); - OUT(abilities[r].base1); - OUT(abilities[r].base2); - OUT(abilities[r].slot); - } + // the structs::SendAA_Struct includes enough space for 1 prereq which is the min even if it has no prereqs + auto prereq_size = emu->total_prereqs > 1 ? (emu->total_prereqs - 1) * 8 : 0; + auto outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability) + prereq_size); + inapp->SetReadPosition(sizeof(AARankInfo_Struct)+emu->total_effects * sizeof(AARankEffect_Struct)); + + + std::vector skill; + std::vector points; + for(auto i = 0; i < emu->total_prereqs; ++i) { + skill.push_back(inapp->ReadUInt32()); + points.push_back(inapp->ReadUInt32()); } - FINISH_ENCODE(); + outapp->WriteUInt32(emu->id); + outapp->WriteUInt8(1); + outapp->WriteSInt32(emu->upper_hotkey_sid); + outapp->WriteSInt32(emu->lower_hotkey_sid); + outapp->WriteSInt32(emu->title_sid); + outapp->WriteSInt32(emu->desc_sid); + outapp->WriteSInt32(emu->level_req); + outapp->WriteSInt32(emu->cost); + outapp->WriteUInt32(emu->seq); + outapp->WriteUInt32(emu->current_level); + + if(emu->total_prereqs) { + outapp->WriteUInt32(emu->total_prereqs); + for(auto &e : skill) + outapp->WriteSInt32(e); + outapp->WriteUInt32(emu->total_prereqs); + for(auto &e : points) + outapp->WriteSInt32(e); + } + else { + outapp->WriteUInt32(1); + outapp->WriteUInt32(0); + outapp->WriteUInt32(1); + outapp->WriteUInt32(0); + } + + outapp->WriteSInt32(emu->type); + outapp->WriteSInt32(emu->spell); + outapp->WriteSInt32(1); + outapp->WriteSInt32(emu->spell_type); + outapp->WriteSInt32(emu->spell_refresh); + outapp->WriteSInt32(emu->classes); + outapp->WriteSInt32(emu->max_level); + outapp->WriteSInt32(emu->prev_id); + outapp->WriteSInt32(emu->next_id); + outapp->WriteSInt32(emu->total_cost); + outapp->WriteUInt8(0); + outapp->WriteUInt8(emu->grant_only); + outapp->WriteUInt8(0); + outapp->WriteUInt32(emu->charges); + outapp->WriteSInt32(emu->expansion); + outapp->WriteSInt32(emu->category); + outapp->WriteUInt8(0); // shroud + outapp->WriteUInt8(0); // unknown109 + outapp->WriteUInt8(0); // loh + outapp->WriteUInt8(0); // unknown111 + outapp->WriteUInt32(emu->total_effects); + + inapp->SetReadPosition(sizeof(AARankInfo_Struct)); + for(auto i = 0; i < emu->total_effects; ++i) { + outapp->WriteUInt32(inapp->ReadUInt32()); // skill_id + outapp->WriteUInt32(inapp->ReadUInt32()); // base1 + outapp->WriteUInt32(inapp->ReadUInt32()); // base2 + outapp->WriteUInt32(inapp->ReadUInt32()); // slot + } + + dest->FastQueuePacket(&outapp); + delete inapp; } ENCODE(OP_SendCharInfo) @@ -2917,7 +3014,7 @@ namespace RoF size_t names_length = 0; size_t character_count = 0; - for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) { + for (; character_count < emu->CharCount && character_count < constants::SayLinkBodySize; ++character_count) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; names_length += strlen(emu_cse->Name); emu_ptr += sizeof(CharacterSelectEntry_Struct); @@ -2944,11 +3041,12 @@ namespace RoF for (int counter = 0; counter < character_count; ++counter) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address strcpy(eq_cse->Name, emu_cse->Name); - eq_ptr += strlen(eq_cse->Name); - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_ptr += strlen(emu_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset) + eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)] eq_cse->Class = emu_cse->Class; eq_cse->Race = emu_cse->Race; @@ -2960,13 +3058,13 @@ namespace RoF eq_cse->Gender = emu_cse->Gender; eq_cse->Face = emu_cse->Face; - for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) { + for (int equip_index = 0; equip_index < EQEmu::textures::TextureCount; equip_index++) { eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material; eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1; eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial; eq_cse->Equip[equip_index].HeroForgeModel = emu_cse->Equip[equip_index].HeroForgeModel; eq_cse->Equip[equip_index].Material2 = emu_cse->Equip[equip_index].Material2; - eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; + eq_cse->Equip[equip_index].Color = emu_cse->Equip[equip_index].Color; } eq_cse->Unknown15 = emu_cse->Unknown15; @@ -2989,7 +3087,7 @@ namespace RoF eq_cse->Enabled = emu_cse->Enabled; eq_cse->LastLogin = emu_cse->LastLogin; eq_cse->Unknown2 = emu_cse->Unknown2; - + emu_ptr += sizeof(CharacterSelectEntry_Struct); eq_ptr += sizeof(structs::CharacterSelectEntry_Struct); } @@ -3046,7 +3144,7 @@ namespace RoF switch (emu->Rank) { case 0: { eq->Rank = 5; break; } // GUILD_MEMBER 0 case 1: { eq->Rank = 3; break; } // GUILD_OFFICER 1 - case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2 + case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2 default: { eq->Rank = emu->Rank; break; } } @@ -3077,7 +3175,7 @@ namespace RoF SETUP_DIRECT_ENCODE(Merchant_Purchase_Struct, structs::Merchant_Purchase_Struct); OUT(npcid); - eq->itemslot = ServerToRoFMainInvSlot(emu->itemslot); + eq->inventory_slot = ServerToRoFTypelessSlot(emu->itemslot); //OUT(itemslot); OUT(quantity); OUT(price); @@ -3160,7 +3258,7 @@ namespace RoF return; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ChangeSize, sizeof(ChangeSize_Struct)); + auto outapp = new EQApplicationPacket(OP_ChangeSize, sizeof(ChangeSize_Struct)); ChangeSize_Struct *css = (ChangeSize_Struct *)outapp->pBuffer; @@ -3313,7 +3411,7 @@ namespace RoF delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); - + #if 0 // original code EQApplicationPacket *in = *p; *p = nullptr; @@ -3394,7 +3492,7 @@ namespace RoF in->SetReadPosition(0); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_TaskHistoryReply, OutboundPacketSize); + auto outapp = new EQApplicationPacket(OP_TaskHistoryReply, OutboundPacketSize); outapp->WriteUInt32(in->ReadUInt32()); // Task index outapp->WriteUInt32(in->ReadUInt32()); // Activity count @@ -3602,7 +3700,7 @@ namespace RoF ENCODE_LENGTH_EXACT(TributeItem_Struct); SETUP_DIRECT_ENCODE(TributeItem_Struct, structs::TributeItem_Struct); - eq->slot = ServerToRoFSlot(emu->slot); + eq->inventory_slot = ServerToRoFSlot(emu->slot); OUT(quantity); OUT(tribute_master_id); OUT(tribute_points); @@ -3706,7 +3804,7 @@ namespace RoF int Count = wars->playercount; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_WhoAllResponse, in->size + (Count * 4)); + auto outapp = new EQApplicationPacket(OP_WhoAllResponse, in->size + (Count * 4)); char *OutBuffer = (char *)outapp->pBuffer; @@ -3777,7 +3875,7 @@ namespace RoF } ENCODE(OP_ZoneEntry) { ENCODE_FORWARD(OP_ZoneSpawns); } - + ENCODE(OP_ZonePlayerToBind) { SETUP_VAR_ENCODE(ZonePlayerToBind_Struct); @@ -3881,7 +3979,7 @@ namespace RoF SpawnSize = 3; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ZoneEntry, PacketSize); + auto outapp = new EQApplicationPacket(OP_ZoneEntry, PacketSize); Buffer = (char *)outapp->pBuffer; BufferStart = Buffer; VARSTRUCT_ENCODE_STRING(Buffer, emu->name); @@ -3968,8 +4066,8 @@ namespace RoF switch (emu->guildrank) { case 0: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 5); break; } // GUILD_MEMBER 0 case 1: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 3); break; } // GUILD_OFFICER 1 - case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2 - default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } // + case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2 + default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } // } } @@ -3988,7 +4086,7 @@ namespace RoF VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13 - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown14 - Stance 64 = normal 4 = aggressive 40 = stun/mezzed + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17 @@ -3997,24 +4095,24 @@ namespace RoF if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)) { - for (k = 0; k < 9; ++k) + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; ++k) { { - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment_tint.Slot[k].Color); } } - structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer; + structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer; - for (k = 0; k < 9; k++) { - Equipment[k].Material = emu->equipment[k].Material; - Equipment[k].Unknown1 = emu->equipment[k].Unknown1; - Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; - Equipment[k].HeroForgeModel = emu->equipment[k].HeroForgeModel; - Equipment[k].Material2 = emu->equipment[k].Material2; + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; k++) { + Equipment[k].Material = emu->equipment.Slot[k].Material; + Equipment[k].Unknown1 = emu->equipment.Slot[k].Unknown1; + Equipment[k].EliteMaterial = emu->equipment.Slot[k].EliteMaterial; + Equipment[k].HeroForgeModel = emu->equipment.Slot[k].HeroForgeModel; + Equipment[k].Material2 = emu->equipment.Slot[k].Material2; } - Buffer += (sizeof(structs::EquipStruct) * 9); + Buffer += (sizeof(structs::Texture_Struct) * EQEmu::textures::TextureCount); } else { @@ -4024,13 +4122,13 @@ namespace RoF VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment.Primary.Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment.Secondary.Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); @@ -4087,7 +4185,7 @@ namespace RoF SETUP_DIRECT_DECODE(Adventure_Sell_Struct, structs::Adventure_Sell_Struct); IN(npcid); - emu->slot = RoFToServerMainInvSlot(eq->slot); + emu->slot = RoFToServerTypelessSlot(eq->inventory_slot); IN(charges); IN(sell_price); @@ -4100,7 +4198,7 @@ namespace RoF SETUP_DIRECT_DECODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); IN(merchant_entity_id); - emu->slot_id = RoFToServerMainInvSlot(eq->slot_id); + emu->slot_id = RoFToServerTypelessSlot(eq->inventory_slot); IN(charges); IN(cost); @@ -4113,7 +4211,19 @@ namespace RoF SETUP_DIRECT_DECODE(AltCurrencySelectItem_Struct, structs::AltCurrencySelectItem_Struct); IN(merchant_entity_id); - emu->slot_id = RoFToServerMainInvSlot(eq->slot_id); + emu->slot_id = RoFToServerTypelessSlot(eq->inventory_slot); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_Animation) + { + DECODE_LENGTH_EXACT(structs::Animation_Struct); + SETUP_DIRECT_DECODE(Animation_Struct, structs::Animation_Struct); + + IN(spawnid); + IN(action); + IN(speed); FINISH_DIRECT_DECODE(); } @@ -4123,7 +4233,7 @@ namespace RoF DECODE_LENGTH_EXACT(structs::ApplyPoison_Struct); SETUP_DIRECT_DECODE(ApplyPoison_Struct, structs::ApplyPoison_Struct); - emu->inventorySlot = RoFToServerMainInvSlot(eq->inventorySlot); + emu->inventorySlot = RoFToServerTypelessSlot(eq->inventory_slot); IN(success); FINISH_DIRECT_DECODE(); @@ -4192,15 +4302,15 @@ namespace RoF DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct_Live); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - //IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.unknown003); + IN(buff.spellid); + IN(buff.duration); IN(slotid); IN(bufffade); @@ -4226,16 +4336,17 @@ namespace RoF DECODE_LENGTH_EXACT(structs::CastSpell_Struct); SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct); - if (eq->slot == 13) - emu->slot = 10; - else - IN(slot); - + emu->slot = static_cast(RoFToServerCastingSlot(static_cast(eq->slot))); + IN(spell_id); - emu->inventoryslot = RoFToServerSlot(eq->inventoryslot); + emu->inventoryslot = RoFToServerSlot(eq->inventory_slot); //IN(inventoryslot); IN(target_id); + IN(y_pos); + IN(x_pos); + IN(z_pos); + FINISH_DIRECT_DECODE(); } @@ -4356,7 +4467,7 @@ namespace RoF DECODE_LENGTH_EXACT(structs::Consume_Struct); SETUP_DIRECT_DECODE(Consume_Struct, structs::Consume_Struct); - emu->slot = RoFToServerSlot(eq->slot); + emu->slot = RoFToServerSlot(eq->inventory_slot); IN(auto_consumed); IN(type); @@ -4373,7 +4484,7 @@ namespace RoF IN(type); IN(spellid); IN(damage); - emu->sequence = eq->sequence; + IN(meleepush_xy); FINISH_DIRECT_DECODE(); } @@ -4546,6 +4657,92 @@ namespace RoF DECODE_FORWARD(OP_GroupInvite); } + DECODE(OP_GuildBank) + { + // all actions are 1 off due to the removal of one of enums + switch (__packet->ReadUInt32()) { + case 2: {// GuildBankPromote + DECODE_LENGTH_EXACT(structs::GuildBankPromote_Struct); + SETUP_DIRECT_DECODE(GuildBankPromote_Struct, structs::GuildBankPromote_Struct); + emu->Action = 3; + IN(Unknown04); + IN(Slot); + IN(Slot2); + FINISH_DIRECT_DECODE(); + return; + } + case 3: { // GuildBankViewItem + DECODE_LENGTH_EXACT(structs::GuildBankViewItem_Struct); + SETUP_DIRECT_DECODE(GuildBankViewItem_Struct, structs::GuildBankViewItem_Struct); + emu->Action = 4; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Unknown16); + FINISH_DIRECT_DECODE(); + return; + } + case 4: { // GuildBankDeposit + __packet->WriteUInt32(5); + return; + } + case 5: { // GuildBankPermissions + DECODE_LENGTH_EXACT(structs::GuildBankPermissions_Struct); + SETUP_DIRECT_DECODE(GuildBankPermissions_Struct, structs::GuildBankPermissions_Struct); + emu->Action = 6; + IN(Unknown04); + IN(SlotID); + IN(Unknown10); + IN(ItemID); + IN(Permissions); + strn0cpy(emu->MemberName, eq->MemberName, 64); + FINISH_DIRECT_DECODE(); + return; + } + case 6: { // GuildBankWithdraw + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 7; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 7: { // GuildBankSplitStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 8; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 8: { // GuildBankMergeStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 9; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + default: + Log.Out(Logs::Detail, Logs::Netcode, "Unhandled OP_GuildBank action"); + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ + return; + } + } + DECODE(OP_GuildDemote) { DECODE_LENGTH_EXACT(structs::GuildDemoteStruct); @@ -4631,7 +4828,7 @@ namespace RoF IN(item_id); int r; - for (r = 0; r < EmuConstants::ITEM_COMMON_SIZE; r++) { + for (r = 0; r < EQEmu::legacy::ITEM_COMMON_SIZE; r++) { IN(augments[r]); } // Max Augs is now 6, but no code to support that many yet @@ -4646,7 +4843,7 @@ namespace RoF DECODE_LENGTH_EXACT(structs::ItemVerifyRequest_Struct); SETUP_DIRECT_DECODE(ItemVerifyRequest_Struct, structs::ItemVerifyRequest_Struct); - emu->slot = RoFToServerSlot(eq->slot); + emu->slot = RoFToServerSlot(eq->inventory_slot); IN(target); FINISH_DIRECT_DECODE(); @@ -4687,7 +4884,7 @@ namespace RoF SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct); //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Moved item from %u to %u", eq->from_slot.MainSlot, eq->to_slot.MainSlot); - Log.Out(Logs::General, Logs::Netcode, "[RoF] MoveItem SlotType from %i to %i, MainSlot from %i to %i, SubSlot from %i to %i, AugSlot from %i to %i, Unknown01 from %i to %i, Number %u", eq->from_slot.SlotType, eq->to_slot.SlotType, eq->from_slot.MainSlot, eq->to_slot.MainSlot, eq->from_slot.SubSlot, eq->to_slot.SubSlot, eq->from_slot.AugSlot, eq->to_slot.AugSlot, eq->from_slot.Unknown01, eq->to_slot.Unknown01, eq->number_in_stack); + Log.Out(Logs::General, Logs::Netcode, "[RoF] MoveItem SlotType from %i to %i, MainSlot from %i to %i, SubSlot from %i to %i, AugSlot from %i to %i, Unknown01 from %i to %i, Number %u", eq->from_slot.Type, eq->to_slot.Type, eq->from_slot.Slot, eq->to_slot.Slot, eq->from_slot.SubIndex, eq->to_slot.SubIndex, eq->from_slot.AugIndex, eq->to_slot.AugIndex, eq->from_slot.Unknown01, eq->to_slot.Unknown01, eq->number_in_stack); emu->from_slot = RoFToServerSlot(eq->from_slot); emu->to_slot = RoFToServerSlot(eq->to_slot); IN(number_in_stack); @@ -4701,7 +4898,7 @@ namespace RoF SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct); IN(command); - emu->unknown = eq->unknown04; + IN(target); FINISH_DIRECT_DECODE(); } @@ -4836,7 +5033,7 @@ namespace RoF SETUP_DIRECT_DECODE(Merchant_Purchase_Struct, structs::Merchant_Purchase_Struct); IN(npcid); - emu->itemslot = RoFToServerMainInvSlot(eq->itemslot); + emu->itemslot = RoFToServerTypelessSlot(eq->inventory_slot); //IN(itemslot); IN(quantity); IN(price); @@ -4922,7 +5119,7 @@ namespace RoF int16 slot_id = RoFToServerSlot(eq->container_slot); if (slot_id == 4000) { - slot_id = legacy::SLOT_TRADESKILL; // 1000 + slot_id = EQEmu::legacy::SLOT_TRADESKILL; // 1000 } emu->container_slot = slot_id; emu->guildtribute_slot = RoFToServerSlot(eq->guildtribute_slot); // this should only return INVALID_INDEX until implemented @@ -4935,7 +5132,7 @@ namespace RoF DECODE_LENGTH_EXACT(structs::TributeItem_Struct); SETUP_DIRECT_DECODE(TributeItem_Struct, structs::TributeItem_Struct); - emu->slot = RoFToServerSlot(eq->slot); + emu->slot = RoFToServerSlot(eq->inventory_slot); IN(quantity); IN(tribute_master_id); IN(tribute_points); @@ -5011,86 +5208,81 @@ namespace RoF return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); - + const EQEmu::ItemBase *item = inst->GetUnscaledItem(); + RoF::structs::ItemSerializationHeader hdr; //sprintf(hdr.unknown000, "06e0002Y1W00"); snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID); - hdr.stacksize = stackable ? charges : 1; + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 1000) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; - structs::ItemSlotStruct slot_id = ServerToRoFSlot(slot_id_in); + structs::InventorySlot_Struct slot_id = ServerToRoFSlot(slot_id_in); - hdr.slot_type = (merchant_slot == 0) ? slot_id.SlotType : 9; // 9 is merchant 20 is reclaim items? - hdr.main_slot = (merchant_slot == 0) ? slot_id.MainSlot : merchant_slot; - hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubSlot : 0xffff; - hdr.unknown013 = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff; + hdr.slot_type = (inst->GetMerchantSlot() ? invtype::InvTypeMerchant : slot_id.Type); + hdr.main_slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id.Slot); + hdr.sub_slot = (inst->GetMerchantSlot() ? 0xffff : slot_id.SubIndex); + hdr.aug_slot = (inst->GetMerchantSlot() ? 0xffff : slot_id.AugIndex); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - //hdr.merchant_slot = (merchant_slot == 0) ? 1 : 0xffffffff; - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; - hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; - ss.write((const char*)&hdr, sizeof(RoF::structs::ItemSerializationHeader)); + hdr.isEvolving = item->EvolvingItem; - if (item->EvolvingLevel > 0) { + ob.write((const char*)&hdr, sizeof(RoF::structs::ItemSerializationHeader)); + + if (item->EvolvingItem > 0) { RoF::structs::EvolvingItem evotop; + evotop.unknown001 = 0; evotop.unknown002 = 0; evotop.unknown003 = 0; evotop.unknown004 = 0; evotop.evoLevel = item->EvolvingLevel; - evotop.progress = 95.512; + evotop.progress = 0; evotop.Activated = 1; - evotop.evomaxlevel = 7; - ss.write((const char*)&evotop, sizeof(RoF::structs::EvolvingItem)); + evotop.evomaxlevel = item->EvolvingMax; + + ob.write((const char*)&evotop, sizeof(RoF::structs::EvolvingItem)); } + //ORNAMENT IDFILE / ICON + int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); uint32 ornaIcon = 0; uint32 heroModel = 0; - if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) - { - char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); - //Mainhand - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); - //Offhand - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); + if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { ornaIcon = inst->GetOrnamentationIcon(); heroModel = inst->GetOrnamentHeroModel(Inventory::CalcMaterialFromSlot(slot_id_in)); + + char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + + //Mainhand + ob.write(tmp, strlen(tmp)); + ob.write("\0", 1); + + //Offhand + ob.write(tmp, strlen(tmp)); + ob.write("\0", 1); } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); // no main hand Ornamentation - ss.write((const char*)&null_term, sizeof(uint8)); // no off hand Ornamentation + else { + ob.write("\0", 1); // no main hand Ornamentation + ob.write("\0", 1); // no off hand Ornamentation } RoF::structs::ItemSerializationHeaderFinish hdrf; + hdrf.ornamentIcon = ornaIcon; hdrf.unknowna1 = 0xffffffff; hdrf.ornamentHeroModel = heroModel; @@ -5100,40 +5292,22 @@ namespace RoF hdrf.unknowna5 = 0; hdrf.ItemClass = item->ItemClass; - ss.write((const char*)&hdrf, sizeof(RoF::structs::ItemSerializationHeaderFinish)); - + ob.write((const char*)&hdrf, sizeof(RoF::structs::ItemSerializationHeaderFinish)); + if (strlen(item->Name) > 0) - { - ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Name, strlen(item->Name)); + ob.write("\0", 1); if (strlen(item->Lore) > 0) - { - ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Lore, strlen(item->Lore)); + ob.write("\0", 1); if (strlen(item->IDFile) > 0) - { - ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->IDFile, strlen(item->IDFile)); + ob.write("\0", 1); - ss.write((const char*)&null_term, sizeof(uint8)); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody struct is %i bytes", sizeof(RoF::structs::ItemBodyStruct)); + ob.write("\0", 1); + RoF::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(RoF::structs::ItemBodyStruct)); @@ -5175,7 +5349,7 @@ namespace RoF ibs.Races = item->Races; ibs.Deity = item->Deity; ibs.SkillModValue = item->SkillModValue; - ibs.SkillModMax = 0xffffffff; + ibs.SkillModMax = item->SkillModMax; ibs.SkillModType = (int8)(item->SkillModType); ibs.SkillModExtra = 0; ibs.BaneDmgRace = item->BaneDmgRace; @@ -5184,12 +5358,8 @@ namespace RoF ibs.BaneDmgAmt = item->BaneDmgAmt; ibs.Magic = item->Magic; ibs.CastTime_ = item->CastTime_; - ibs.ReqLevel = item->ReqLevel; - if (item->ReqLevel > 100) - ibs.ReqLevel = 100; - ibs.RecLevel = item->RecLevel; - if (item->RecLevel > 100) - ibs.RecLevel = 100; + ibs.ReqLevel = ((item->ReqLevel > 100) ? 100 : item->ReqLevel); + ibs.RecLevel = ((item->RecLevel > 100) ? 100 : item->RecLevel); ibs.RecSkill = item->RecSkill; ibs.BardType = item->BardType; ibs.BardValue = item->BardValue; @@ -5227,20 +5397,13 @@ namespace RoF ibs.FactionAmt4 = item->FactionAmt4; ibs.FactionMod4 = item->FactionMod4; - ss.write((const char*)&ibs, sizeof(RoF::structs::ItemBodyStruct)); + ob.write((const char*)&ibs, sizeof(RoF::structs::ItemBodyStruct)); //charm text if (strlen(item->CharmFile) > 0) - { - ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->CharmFile, strlen(item->CharmFile)); + ob.write("\0", 1); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody secondary struct is %i bytes", sizeof(RoF::structs::ItemSecondaryBodyStruct)); RoF::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(RoF::structs::ItemSecondaryBodyStruct)); @@ -5248,11 +5411,10 @@ namespace RoF isbs.augdistiller = 65535; isbs.augrestrict = item->AugRestrict; - for (int x = AUG_BEGIN; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < invaug::ItemAugSize; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -5269,19 +5431,12 @@ namespace RoF isbs.book = item->Book; isbs.booktype = item->BookType; - ss.write((const char*)&isbs, sizeof(RoF::structs::ItemSecondaryBodyStruct)); + ob.write((const char*)&isbs, sizeof(RoF::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { - ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->Filename, strlen(item->Filename)); + ob.write("\0", 1); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody tertiary struct is %i bytes", sizeof(RoF::structs::ItemTertiaryBodyStruct)); RoF::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(RoF::structs::ItemTertiaryBodyStruct)); @@ -5303,7 +5458,7 @@ namespace RoF itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; @@ -5315,12 +5470,11 @@ namespace RoF itbs.unknown13 = 0; itbs.unknown14 = 0; - ss.write((const char*)&itbs, sizeof(RoF::structs::ItemTertiaryBodyStruct)); + ob.write((const char*)&itbs, sizeof(RoF::structs::ItemTertiaryBodyStruct)); // Effect Structures Broken down to allow variable length strings for effect names int32 effect_unknown = 0; - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody Click effect struct is %i bytes", sizeof(RoF::structs::ClickEffectStruct)); RoF::structs::ClickEffectStruct ices; memset(&ices, 0, sizeof(RoF::structs::ClickEffectStruct)); @@ -5333,21 +5487,14 @@ namespace RoF ices.recast = item->RecastDelay; ices.recast_type = item->RecastType; - ss.write((const char*)&ices, sizeof(RoF::structs::ClickEffectStruct)); + ob.write((const char*)&ices, sizeof(RoF::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { - ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ClickName, strlen(item->ClickName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 + ob.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody proc effect struct is %i bytes", sizeof(RoF::structs::ProcEffectStruct)); RoF::structs::ProcEffectStruct ipes; memset(&ipes, 0, sizeof(RoF::structs::ProcEffectStruct)); @@ -5357,21 +5504,14 @@ namespace RoF ipes.level = item->Proc.Level; ipes.procrate = item->ProcRate; - ss.write((const char*)&ipes, sizeof(RoF::structs::ProcEffectStruct)); + ob.write((const char*)&ipes, sizeof(RoF::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { - ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ProcName, strlen(item->ProcName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody worn effect struct is %i bytes", sizeof(RoF::structs::WornEffectStruct)); RoF::structs::WornEffectStruct iwes; memset(&iwes, 0, sizeof(RoF::structs::WornEffectStruct)); @@ -5380,19 +5520,13 @@ namespace RoF iwes.type = item->Worn.Type; iwes.level = item->Worn.Level; - ss.write((const char*)&iwes, sizeof(RoF::structs::WornEffectStruct)); + ob.write((const char*)&iwes, sizeof(RoF::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { - ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->WornName, strlen(item->WornName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 RoF::structs::WornEffectStruct ifes; memset(&ifes, 0, sizeof(RoF::structs::WornEffectStruct)); @@ -5402,19 +5536,13 @@ namespace RoF ifes.type = item->Focus.Type; ifes.level = item->Focus.Level; - ss.write((const char*)&ifes, sizeof(RoF::structs::WornEffectStruct)); + ob.write((const char*)&ifes, sizeof(RoF::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { - ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->FocusName, strlen(item->FocusName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 RoF::structs::WornEffectStruct ises; memset(&ises, 0, sizeof(RoF::structs::WornEffectStruct)); @@ -5424,19 +5552,13 @@ namespace RoF ises.type = item->Scroll.Type; ises.level = item->Scroll.Level; - ss.write((const char*)&ises, sizeof(RoF::structs::WornEffectStruct)); + ob.write((const char*)&ises, sizeof(RoF::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { - ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ScrollName, strlen(item->ScrollName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // Bard Effect? RoF::structs::WornEffectStruct ibes; @@ -5448,7 +5570,7 @@ namespace RoF ibes.level = 0; //ibes.unknown6 = 0xffffffff; - ss.write((const char*)&ibes, sizeof(RoF::structs::WornEffectStruct)); + ob.write((const char*)&ibes, sizeof(RoF::structs::WornEffectStruct)); /* if(strlen(item->BardName) > 0) @@ -5457,12 +5579,11 @@ namespace RoF ss.write((const char*)&null_term, sizeof(uint8)); } else */ - ss.write((const char*)&null_term, sizeof(uint8)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody Quaternary effect struct is %i bytes", sizeof(RoF::structs::ItemQuaternaryBodyStruct)); RoF::structs::ItemQuaternaryBodyStruct iqbs; memset(&iqbs, 0, sizeof(RoF::structs::ItemQuaternaryBodyStruct)); @@ -5488,96 +5609,67 @@ namespace RoF iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - iqbs.clairvoyance = item->Clairvoyance; + iqbs.Clairvoyance = item->Clairvoyance; iqbs.unknown28 = 0; iqbs.unknown30 = 0; iqbs.unknown39 = 1; + + ob.write((const char*)&iqbs, sizeof(RoF::structs::ItemQuaternaryBodyStruct)); - iqbs.subitem_count = 0; + EQEmu::OutBuffer::pos_type count_pos = ob.tellp(); + uint32 subitem_count = 0; - char *SubSerializations[10]; // + ob.write((const char*)&subitem_count, sizeof(uint32)); - uint32 SubLengths[10]; + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; - for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; ++x) { + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; - SubSerializations[x] = nullptr; + ob.write((const char*)&index, sizeof(uint32)); - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); - - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EmuConstants::GENERAL_BEGIN && slot_id_in <= EmuConstants::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EmuConstants::BANK_BEGIN && slot_id_in <= EmuConstants::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EmuConstants::SHARED_BANK_BEGIN && slot_id_in <= EmuConstants::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::SHARED_BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); - } + SerializeItem(ob, sub, SubSlotNumber, (depth + 1)); + ++subitem_count; } - ss.write((const char*)&iqbs, sizeof(RoF::structs::ItemQuaternaryBodyStruct)); - - for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; ++x) { - - if (SubSerializations[x]) { - - ss.write((const char*)&x, sizeof(uint32)); - - ss.write(SubSerializations[x], SubLengths[x]); - - safe_delete_array(SubSerializations[x]); - } - } - - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); - - *length = ss.tellp(); - return item_serial; + if (subitem_count) + ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32)); } - static inline structs::ItemSlotStruct ServerToRoFSlot(uint32 serverSlot) + static inline structs::InventorySlot_Struct ServerToRoFSlot(uint32 serverSlot) { - structs::ItemSlotStruct RoFSlot; - RoFSlot.SlotType = INVALID_INDEX; - RoFSlot.Unknown02 = NOT_USED; - RoFSlot.MainSlot = INVALID_INDEX; - RoFSlot.SubSlot = INVALID_INDEX; - RoFSlot.AugSlot = INVALID_INDEX; - RoFSlot.Unknown01 = NOT_USED; + structs::InventorySlot_Struct RoFSlot; + RoFSlot.Type = INVALID_INDEX; + RoFSlot.Unknown02 = 0; + RoFSlot.Slot = INVALID_INDEX; + RoFSlot.SubIndex = INVALID_INDEX; + RoFSlot.AugIndex = INVALID_INDEX; + RoFSlot.Unknown01 = 0; uint32 TempSlot = 0; - if (serverSlot < 56 || serverSlot == MainPowerSource) { // Main Inventory and Cursor - RoFSlot.SlotType = maps::MapPossessions; - RoFSlot.MainSlot = serverSlot; + if (serverSlot < 56 || serverSlot == EQEmu::legacy::SlotPowerSource) { // Main Inventory and Cursor + RoFSlot.Type = invtype::InvTypePossessions; + RoFSlot.Slot = serverSlot; - if (serverSlot == MainPowerSource) - RoFSlot.MainSlot = slots::MainPowerSource; + if (serverSlot == EQEmu::legacy::SlotPowerSource) + RoFSlot.Slot = invslot::PossessionsPowerSource; - else if (serverSlot >= MainCursor) // Cursor and Extended Corpse Inventory - RoFSlot.MainSlot += 3; + else if (serverSlot >= EQEmu::legacy::SlotCursor) // Cursor and Extended Corpse Inventory + RoFSlot.Slot += 3; - else if (serverSlot >= MainAmmo) // (> 20) - RoFSlot.MainSlot += 1; + else if (serverSlot >= EQEmu::legacy::SlotAmmo) // (> 20) + RoFSlot.Slot += 1; } /*else if (ServerSlot < 51) { // Cursor Buffer @@ -5585,51 +5677,51 @@ namespace RoF RoFSlot.MainSlot = ServerSlot - 31; }*/ - else if (serverSlot >= EmuConstants::GENERAL_BAGS_BEGIN && serverSlot <= EmuConstants::CURSOR_BAG_END) { // (> 250 && < 341) - RoFSlot.SlotType = maps::MapPossessions; + else if (serverSlot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::legacy::CURSOR_BAG_END) { // (> 250 && < 341) + RoFSlot.Type = invtype::InvTypePossessions; TempSlot = serverSlot - 1; - RoFSlot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 2; - RoFSlot.SubSlot = TempSlot - ((RoFSlot.MainSlot + 2) * EmuConstants::ITEM_CONTAINER_SIZE); + RoFSlot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 2; + RoFSlot.SubIndex = TempSlot - ((RoFSlot.Slot + 2) * EQEmu::legacy::ITEM_CONTAINER_SIZE); - if (RoFSlot.MainSlot >= slots::MainGeneral9) // (> 30) - RoFSlot.MainSlot = slots::MainCursor; + if (RoFSlot.Slot >= invslot::PossessionsGeneral9) // (> 30) + RoFSlot.Slot = invslot::PossessionsCursor; } - else if (serverSlot >= EmuConstants::TRIBUTE_BEGIN && serverSlot <= EmuConstants::TRIBUTE_END) { // Tribute - RoFSlot.SlotType = maps::MapTribute; - RoFSlot.MainSlot = serverSlot - EmuConstants::TRIBUTE_BEGIN; + else if (serverSlot >= EQEmu::legacy::TRIBUTE_BEGIN && serverSlot <= EQEmu::legacy::TRIBUTE_END) { // Tribute + RoFSlot.Type = invtype::InvTypeTribute; + RoFSlot.Slot = serverSlot - EQEmu::legacy::TRIBUTE_BEGIN; } - else if (serverSlot >= EmuConstants::BANK_BEGIN && serverSlot <= EmuConstants::BANK_BAGS_END) { - RoFSlot.SlotType = maps::MapBank; - TempSlot = serverSlot - EmuConstants::BANK_BEGIN; - RoFSlot.MainSlot = TempSlot; + else if (serverSlot >= EQEmu::legacy::BANK_BEGIN && serverSlot <= EQEmu::legacy::BANK_BAGS_END) { + RoFSlot.Type = invtype::InvTypeBank; + TempSlot = serverSlot - EQEmu::legacy::BANK_BEGIN; + RoFSlot.Slot = TempSlot; if (TempSlot > 30) { // (> 30) - RoFSlot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 3; - RoFSlot.SubSlot = TempSlot - ((RoFSlot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE); + RoFSlot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 3; + RoFSlot.SubIndex = TempSlot - ((RoFSlot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE); } } - else if (serverSlot >= EmuConstants::SHARED_BANK_BEGIN && serverSlot <= EmuConstants::SHARED_BANK_BAGS_END) { - RoFSlot.SlotType = maps::MapSharedBank; - TempSlot = serverSlot - EmuConstants::SHARED_BANK_BEGIN; - RoFSlot.MainSlot = TempSlot; + else if (serverSlot >= EQEmu::legacy::SHARED_BANK_BEGIN && serverSlot <= EQEmu::legacy::SHARED_BANK_BAGS_END) { + RoFSlot.Type = invtype::InvTypeSharedBank; + TempSlot = serverSlot - EQEmu::legacy::SHARED_BANK_BEGIN; + RoFSlot.Slot = TempSlot; if (TempSlot > 30) { // (> 30) - RoFSlot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 3; - RoFSlot.SubSlot = TempSlot - ((RoFSlot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE); + RoFSlot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 3; + RoFSlot.SubIndex = TempSlot - ((RoFSlot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE); } } - else if (serverSlot >= EmuConstants::TRADE_BEGIN && serverSlot <= EmuConstants::TRADE_BAGS_END) { - RoFSlot.SlotType = maps::MapTrade; - TempSlot = serverSlot - EmuConstants::TRADE_BEGIN; - RoFSlot.MainSlot = TempSlot; + else if (serverSlot >= EQEmu::legacy::TRADE_BEGIN && serverSlot <= EQEmu::legacy::TRADE_BAGS_END) { + RoFSlot.Type = invtype::InvTypeTrade; + TempSlot = serverSlot - EQEmu::legacy::TRADE_BEGIN; + RoFSlot.Slot = TempSlot; if (TempSlot > 30) { - RoFSlot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 3; - RoFSlot.SubSlot = TempSlot - ((RoFSlot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE); + RoFSlot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 3; + RoFSlot.SubIndex = TempSlot - ((RoFSlot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE); } /* @@ -5646,38 +5738,38 @@ namespace RoF */ } - else if (serverSlot >= EmuConstants::WORLD_BEGIN && serverSlot <= EmuConstants::WORLD_END) { - RoFSlot.SlotType = maps::MapWorld; - TempSlot = serverSlot - EmuConstants::WORLD_BEGIN; - RoFSlot.MainSlot = TempSlot; + else if (serverSlot >= EQEmu::legacy::WORLD_BEGIN && serverSlot <= EQEmu::legacy::WORLD_END) { + RoFSlot.Type = invtype::InvTypeWorld; + TempSlot = serverSlot - EQEmu::legacy::WORLD_BEGIN; + RoFSlot.Slot = TempSlot; } - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert Server Slot %i to RoF Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i", serverSlot, RoFSlot.SlotType, RoFSlot.Unknown02, RoFSlot.MainSlot, RoFSlot.SubSlot, RoFSlot.AugSlot, RoFSlot.Unknown01); + Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert Server Slot %i to RoF Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i", serverSlot, RoFSlot.Type, RoFSlot.Unknown02, RoFSlot.Slot, RoFSlot.SubIndex, RoFSlot.AugIndex, RoFSlot.Unknown01); return RoFSlot; } - static inline structs::MainInvItemSlotStruct ServerToRoFMainInvSlot(uint32 serverSlot) + static inline structs::TypelessInventorySlot_Struct ServerToRoFTypelessSlot(uint32 serverSlot) { - structs::MainInvItemSlotStruct RoFSlot; - RoFSlot.MainSlot = INVALID_INDEX; - RoFSlot.SubSlot = INVALID_INDEX; - RoFSlot.AugSlot = INVALID_INDEX; - RoFSlot.Unknown01 = NOT_USED; + structs::TypelessInventorySlot_Struct RoFSlot; + RoFSlot.Slot = INVALID_INDEX; + RoFSlot.SubIndex = INVALID_INDEX; + RoFSlot.AugIndex = INVALID_INDEX; + RoFSlot.Unknown01 = 0; uint32 TempSlot = 0; - if (serverSlot < 56 || serverSlot == MainPowerSource) { // (< 52) - RoFSlot.MainSlot = serverSlot; + if (serverSlot < 56 || serverSlot == EQEmu::legacy::SlotPowerSource) { // (< 52) + RoFSlot.Slot = serverSlot; - if (serverSlot == MainPowerSource) - RoFSlot.MainSlot = slots::MainPowerSource; + if (serverSlot == EQEmu::legacy::SlotPowerSource) + RoFSlot.Slot = invslot::PossessionsPowerSource; - else if (serverSlot >= MainCursor) // Cursor and Extended Corpse Inventory - RoFSlot.MainSlot += 3; + else if (serverSlot >= EQEmu::legacy::SlotCursor) // Cursor and Extended Corpse Inventory + RoFSlot.Slot += 3; - else if (serverSlot >= MainAmmo) // Ammo and Personl Inventory - RoFSlot.MainSlot += 1; + else if (serverSlot >= EQEmu::legacy::SlotAmmo) // Ammo and Personl Inventory + RoFSlot.Slot += 1; /*else if (ServerSlot >= MainCursor) { // Cursor RoFSlot.MainSlot = slots::MainCursor; @@ -5687,13 +5779,13 @@ namespace RoF }*/ } - else if (serverSlot >= EmuConstants::GENERAL_BAGS_BEGIN && serverSlot <= EmuConstants::CURSOR_BAG_END) { + else if (serverSlot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::legacy::CURSOR_BAG_END) { TempSlot = serverSlot - 1; - RoFSlot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 2; - RoFSlot.SubSlot = TempSlot - ((RoFSlot.MainSlot + 2) * EmuConstants::ITEM_CONTAINER_SIZE); + RoFSlot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 2; + RoFSlot.SubIndex = TempSlot - ((RoFSlot.Slot + 2) * EQEmu::legacy::ITEM_CONTAINER_SIZE); } - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert Server Slot %i to RoF Slots: Main %i, Sub %i, Aug %i, Unk1 %i", serverSlot, RoFSlot.MainSlot, RoFSlot.SubSlot, RoFSlot.AugSlot, RoFSlot.Unknown01); + Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert Server Slot %i to RoF Slots: Main %i, Sub %i, Aug %i, Unk1 %i", serverSlot, RoFSlot.Slot, RoFSlot.SubIndex, RoFSlot.AugIndex, RoFSlot.Unknown01); return RoFSlot; } @@ -5703,17 +5795,17 @@ namespace RoF return (serverCorpseSlot + 1); } - static inline uint32 RoFToServerSlot(structs::ItemSlotStruct rofSlot) + static inline uint32 RoFToServerSlot(structs::InventorySlot_Struct rofSlot) { uint32 ServerSlot = INVALID_INDEX; uint32 TempSlot = 0; - if (rofSlot.SlotType == maps::MapPossessions && rofSlot.MainSlot < 57) { // Worn/Personal Inventory and Cursor (< 51) - if (rofSlot.MainSlot == slots::MainPowerSource) - TempSlot = MainPowerSource; + if (rofSlot.Type == invtype::InvTypePossessions && rofSlot.Slot < 57) { // Worn/Personal Inventory and Cursor (< 51) + if (rofSlot.Slot == invslot::PossessionsPowerSource) + TempSlot = EQEmu::legacy::SlotPowerSource; - else if (rofSlot.MainSlot >= slots::MainCursor) // Cursor and Extended Corpse Inventory - TempSlot = rofSlot.MainSlot - 3; + else if (rofSlot.Slot >= invslot::PossessionsCursor) // Cursor and Extended Corpse Inventory + TempSlot = rofSlot.Slot - 3; /*else if (RoFSlot.MainSlot == slots::MainGeneral9 || RoFSlot.MainSlot == slots::MainGeneral10) { // 9th and 10th RoF inventory/corpse slots // Need to figure out what to do when we get these @@ -5726,61 +5818,61 @@ namespace RoF // For now, it's probably best to leave as-is and let this work itself out in the inventory rework. }*/ - else if (rofSlot.MainSlot >= slots::MainAmmo) // Ammo and Main Inventory - TempSlot = rofSlot.MainSlot - 1; + else if (rofSlot.Slot >= invslot::PossessionsAmmo) // Ammo and Main Inventory + TempSlot = rofSlot.Slot - 1; else // Worn Slots - TempSlot = rofSlot.MainSlot; + TempSlot = rofSlot.Slot; - if (rofSlot.SubSlot >= SUB_BEGIN) // Bag Slots - TempSlot = ((TempSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rofSlot.SubSlot + 1; + if (rofSlot.SubIndex >= SUB_INDEX_BEGIN) // Bag Slots + TempSlot = ((TempSlot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rofSlot.SubIndex + 1; ServerSlot = TempSlot; } - else if (rofSlot.SlotType == maps::MapBank) { - TempSlot = EmuConstants::BANK_BEGIN; + else if (rofSlot.Type == invtype::InvTypeBank) { + TempSlot = EQEmu::legacy::BANK_BEGIN; - if (rofSlot.SubSlot >= SUB_BEGIN) - TempSlot += ((rofSlot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rofSlot.SubSlot + 1; + if (rofSlot.SubIndex >= SUB_INDEX_BEGIN) + TempSlot += ((rofSlot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rofSlot.SubIndex + 1; else - TempSlot += rofSlot.MainSlot; + TempSlot += rofSlot.Slot; ServerSlot = TempSlot; } - else if (rofSlot.SlotType == maps::MapSharedBank) { - TempSlot = EmuConstants::SHARED_BANK_BEGIN; + else if (rofSlot.Type == invtype::InvTypeSharedBank) { + TempSlot = EQEmu::legacy::SHARED_BANK_BEGIN; - if (rofSlot.SubSlot >= SUB_BEGIN) - TempSlot += ((rofSlot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rofSlot.SubSlot + 1; + if (rofSlot.SubIndex >= SUB_INDEX_BEGIN) + TempSlot += ((rofSlot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rofSlot.SubIndex + 1; else - TempSlot += rofSlot.MainSlot; + TempSlot += rofSlot.Slot; ServerSlot = TempSlot; } - else if (rofSlot.SlotType == maps::MapTrade) { - TempSlot = EmuConstants::TRADE_BEGIN; + else if (rofSlot.Type == invtype::InvTypeTrade) { + TempSlot = EQEmu::legacy::TRADE_BEGIN; - if (rofSlot.SubSlot >= SUB_BEGIN) - TempSlot += ((rofSlot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rofSlot.SubSlot + 1; + if (rofSlot.SubIndex >= SUB_INDEX_BEGIN) + TempSlot += ((rofSlot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rofSlot.SubIndex + 1; // OLD CODE: - //TempSlot += 100 + (RoFSlot.MainSlot * EmuConstants::ITEM_CONTAINER_SIZE) + RoFSlot.SubSlot; + //TempSlot += 100 + (RoFSlot.MainSlot * EQEmu::legacy::ITEM_CONTAINER_SIZE) + RoFSlot.SubSlot; else - TempSlot += rofSlot.MainSlot; + TempSlot += rofSlot.Slot; ServerSlot = TempSlot; } - else if (rofSlot.SlotType == maps::MapWorld) { - TempSlot = EmuConstants::WORLD_BEGIN; + else if (rofSlot.Type == invtype::InvTypeWorld) { + TempSlot = EQEmu::legacy::WORLD_BEGIN; - if (rofSlot.MainSlot >= SUB_BEGIN) - TempSlot += rofSlot.MainSlot; + if (rofSlot.Slot >= SUB_INDEX_BEGIN) + TempSlot += rofSlot.Slot; ServerSlot = TempSlot; } @@ -5794,26 +5886,26 @@ namespace RoF ServerSlot = TempSlot; }*/ - else if (rofSlot.SlotType == maps::MapGuildTribute) { + else if (rofSlot.Type == invtype::InvTypeGuildTribute) { ServerSlot = INVALID_INDEX; } - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert RoF Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", rofSlot.SlotType, rofSlot.Unknown02, rofSlot.MainSlot, rofSlot.SubSlot, rofSlot.AugSlot, rofSlot.Unknown01, ServerSlot); + Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert RoF Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", rofSlot.Type, rofSlot.Unknown02, rofSlot.Slot, rofSlot.SubIndex, rofSlot.AugIndex, rofSlot.Unknown01, ServerSlot); return ServerSlot; } - static inline uint32 RoFToServerMainInvSlot(structs::MainInvItemSlotStruct rofSlot) + static inline uint32 RoFToServerTypelessSlot(structs::TypelessInventorySlot_Struct rofSlot) { uint32 ServerSlot = INVALID_INDEX; uint32 TempSlot = 0; - if (rofSlot.MainSlot < 57) { // Worn/Personal Inventory and Cursor (< 33) - if (rofSlot.MainSlot == slots::MainPowerSource) - TempSlot = MainPowerSource; + if (rofSlot.Slot < 57) { // Worn/Personal Inventory and Cursor (< 33) + if (rofSlot.Slot == invslot::PossessionsPowerSource) + TempSlot = EQEmu::legacy::SlotPowerSource; - else if (rofSlot.MainSlot >= slots::MainCursor) // Cursor and Extended Corpse Inventory - TempSlot = rofSlot.MainSlot - 3; + else if (rofSlot.Slot >= invslot::PossessionsCursor) // Cursor and Extended Corpse Inventory + TempSlot = rofSlot.Slot - 3; /*else if (RoFSlot.MainSlot == slots::MainGeneral9 || RoFSlot.MainSlot == slots::MainGeneral10) { // 9th and 10th RoF inventory slots // Need to figure out what to do when we get these @@ -5821,19 +5913,19 @@ namespace RoF // Same as above }*/ - else if (rofSlot.MainSlot >= slots::MainAmmo) // Main Inventory and Ammo Slots - TempSlot = rofSlot.MainSlot - 1; + else if (rofSlot.Slot >= invslot::PossessionsAmmo) // Main Inventory and Ammo Slots + TempSlot = rofSlot.Slot - 1; else - TempSlot = rofSlot.MainSlot; + TempSlot = rofSlot.Slot; - if (rofSlot.SubSlot >= SUB_BEGIN) // Bag Slots - TempSlot = ((TempSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rofSlot.SubSlot + 1; + if (rofSlot.SubIndex >= SUB_INDEX_BEGIN) // Bag Slots + TempSlot = ((TempSlot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rofSlot.SubIndex + 1; ServerSlot = TempSlot; } - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert RoF Slots: Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", rofSlot.MainSlot, rofSlot.SubSlot, rofSlot.AugSlot, rofSlot.Unknown01, ServerSlot); + Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert RoF Slots: Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", rofSlot.Slot, rofSlot.SubIndex, rofSlot.AugIndex, rofSlot.Unknown01, ServerSlot); return ServerSlot; } @@ -5845,7 +5937,7 @@ namespace RoF static inline void ServerToRoFTextLink(std::string& rofTextLink, const std::string& serverTextLink) { - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { + if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { rofTextLink = serverTextLink; return; } @@ -5854,7 +5946,7 @@ namespace RoF for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { rofTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -5884,7 +5976,7 @@ namespace RoF static inline void RoFToServerTextLink(std::string& serverTextLink, const std::string& rofTextLink) { - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rofTextLink.find('\x12') == std::string::npos)) { + if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (rofTextLink.find('\x12') == std::string::npos)) { serverTextLink = rofTextLink; return; } @@ -5893,7 +5985,7 @@ namespace RoF for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= constants::SayLinkBodySize) { serverTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -5915,5 +6007,81 @@ namespace RoF } } } -} -// end namespace RoF + + static inline CastingSlot ServerToRoFCastingSlot(EQEmu::CastingSlot slot) + { + switch (slot) { + case EQEmu::CastingSlot::Gem1: + return CastingSlot::Gem1; + case EQEmu::CastingSlot::Gem2: + return CastingSlot::Gem2; + case EQEmu::CastingSlot::Gem3: + return CastingSlot::Gem3; + case EQEmu::CastingSlot::Gem4: + return CastingSlot::Gem4; + case EQEmu::CastingSlot::Gem5: + return CastingSlot::Gem5; + case EQEmu::CastingSlot::Gem6: + return CastingSlot::Gem6; + case EQEmu::CastingSlot::Gem7: + return CastingSlot::Gem7; + case EQEmu::CastingSlot::Gem8: + return CastingSlot::Gem8; + case EQEmu::CastingSlot::Gem9: + return CastingSlot::Gem9; + case EQEmu::CastingSlot::Gem10: + return CastingSlot::Gem10; + case EQEmu::CastingSlot::Gem11: + return CastingSlot::Gem11; + case EQEmu::CastingSlot::Gem12: + return CastingSlot::Gem12; + case EQEmu::CastingSlot::Item: + case EQEmu::CastingSlot::PotionBelt: + return CastingSlot::Item; + case EQEmu::CastingSlot::Discipline: + return CastingSlot::Discipline; + case EQEmu::CastingSlot::AltAbility: + return CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return CastingSlot::Discipline; + } + } + + static inline EQEmu::CastingSlot RoFToServerCastingSlot(CastingSlot slot) + { + switch (slot) { + case CastingSlot::Gem1: + return EQEmu::CastingSlot::Gem1; + case CastingSlot::Gem2: + return EQEmu::CastingSlot::Gem2; + case CastingSlot::Gem3: + return EQEmu::CastingSlot::Gem3; + case CastingSlot::Gem4: + return EQEmu::CastingSlot::Gem4; + case CastingSlot::Gem5: + return EQEmu::CastingSlot::Gem5; + case CastingSlot::Gem6: + return EQEmu::CastingSlot::Gem6; + case CastingSlot::Gem7: + return EQEmu::CastingSlot::Gem7; + case CastingSlot::Gem8: + return EQEmu::CastingSlot::Gem8; + case CastingSlot::Gem9: + return EQEmu::CastingSlot::Gem9; + case CastingSlot::Gem10: + return EQEmu::CastingSlot::Gem10; + case CastingSlot::Gem11: + return EQEmu::CastingSlot::Gem11; + case CastingSlot::Gem12: + return EQEmu::CastingSlot::Gem12; + case CastingSlot::Discipline: + return EQEmu::CastingSlot::Discipline; + case CastingSlot::Item: + return EQEmu::CastingSlot::Item; + case CastingSlot::AltAbility: + return EQEmu::CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return EQEmu::CastingSlot::Discipline; + } + } +} /*RoF*/ diff --git a/common/patches/rof.h b/common/patches/rof.h index 4ac7d3532..146b34f1f 100644 --- a/common/patches/rof.h +++ b/common/patches/rof.h @@ -1,11 +1,31 @@ -#ifndef ROF_H_ -#define ROF_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_ROF_H +#define COMMON_ROF_H #include "../struct_strategy.h" class EQStreamIdentifier; -namespace RoF { +namespace RoF +{ //these are the only public member of this namespace. extern void Register(EQStreamIdentifier &into); @@ -23,13 +43,31 @@ namespace RoF { protected: virtual std::string Describe() const; - virtual const ClientVersion GetClientVersion() const; + virtual const EQEmu::versions::ClientVersion ClientVersion() const; //magic macro to declare our opcode processors #include "ss_declare.h" #include "rof_ops.h" }; -}; + enum class CastingSlot : uint32 { + Gem1 = 0, + Gem2 = 1, + Gem3 = 2, + Gem4 = 3, + Gem5 = 4, + Gem6 = 5, + Gem7 = 6, + Gem8 = 7, + Gem9 = 8, + Gem10 = 9, + Gem11 = 10, + Gem12 = 11, + Item = 12, + Discipline = 13, + AltAbility = 0xFF + }; -#endif /*ROF_H_*/ +}; /*RoF*/ + +#endif /*COMMON_ROF_H*/ diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 9e0bd9c8a..118419f48 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -1,4 +1,24 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #include "../global_define.h" +#include "../eqemu_config.h" #include "../eqemu_logsys.h" #include "rof2.h" #include "../opcodemgr.h" @@ -18,22 +38,23 @@ #include #include + namespace RoF2 { static const char *name = "RoF2"; static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth, ItemPacketType packet_type); + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id, uint8 depth, ItemPacketType packet_type); // server to client inventory location converters - static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 serverSlot, ItemPacketType PacketType = ItemPacketInvalid); - static inline structs::MainInvItemSlotStruct ServerToRoF2MainInvSlot(uint32 serverSlot); + static inline structs::InventorySlot_Struct ServerToRoF2Slot(uint32 serverSlot, ItemPacketType PacketType = ItemPacketInvalid); + static inline structs::TypelessInventorySlot_Struct ServerToRoF2TypelessSlot(uint32 serverSlot); static inline uint32 ServerToRoF2CorpseSlot(uint32 serverCorpseSlot); // client to server inventory location converters - static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct rof2Slot, ItemPacketType PacketType = ItemPacketInvalid); - static inline uint32 RoF2ToServerMainInvSlot(structs::MainInvItemSlotStruct rof2Slot); + static inline uint32 RoF2ToServerSlot(structs::InventorySlot_Struct rof2Slot, ItemPacketType PacketType = ItemPacketInvalid); + static inline uint32 RoF2ToServerTypelessSlot(structs::TypelessInventorySlot_Struct rof2Slot); static inline uint32 RoF2ToServerCorpseSlot(uint32 rof2CorpseSlot); // server to client text link converter @@ -42,12 +63,17 @@ namespace RoF2 // client to server text link converter static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink); + static inline CastingSlot ServerToRoF2CastingSlot(EQEmu::CastingSlot slot); + static inline EQEmu::CastingSlot RoF2ToServerCastingSlot(CastingSlot slot); + void Register(EQStreamIdentifier &into) { //create our opcode manager if we havent already if (opcodes == nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; //load up the opcode manager. @@ -91,7 +117,9 @@ namespace RoF2 if (opcodes != nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; if (!opcodes->ReloadOpcodes(opfile.c_str())) { @@ -117,9 +145,9 @@ namespace RoF2 return(r); } - const ClientVersion Strategy::GetClientVersion() const + const EQEmu::versions::ClientVersion Strategy::ClientVersion() const { - return ClientVersion::RoF2; + return EQEmu::versions::ClientVersion::RoF2; } #include "ss_define.h" @@ -158,7 +186,7 @@ namespace RoF2 eq->exit_url_length = emu->exit_url_length; eq->exit_url_length2 = emu->exit_url_length2; - + FINISH_ENCODE(); } @@ -183,7 +211,7 @@ namespace RoF2 { eq->entries[i] = 1; } - + FINISH_ENCODE(); } @@ -228,7 +256,7 @@ namespace RoF2 eq->unknown000 = 1; OUT(npcid); - eq->slot = ServerToRoF2MainInvSlot(emu->slot); + eq->inventory_slot = ServerToRoF2TypelessSlot(emu->slot); OUT(charges); OUT(sell_price); @@ -246,8 +274,9 @@ namespace RoF2 if (opcode == 8) { AltCurrencyPopulate_Struct *populate = (AltCurrencyPopulate_Struct*)emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(structs::AltCurrencyPopulate_Struct) - + sizeof(structs::AltCurrencyPopulateEntry_Struct) * populate->count); + auto outapp = new EQApplicationPacket( + OP_AltCurrency, sizeof(structs::AltCurrencyPopulate_Struct) + + sizeof(structs::AltCurrencyPopulateEntry_Struct) * populate->count); structs::AltCurrencyPopulate_Struct *out_populate = (structs::AltCurrencyPopulate_Struct*)outapp->pBuffer; out_populate->opcode = populate->opcode; @@ -265,7 +294,7 @@ namespace RoF2 dest->FastQueuePacket(&outapp, ack_req); } else { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyUpdate_Struct)); memcpy(outapp->pBuffer, emu_buffer, sizeof(AltCurrencyUpdate_Struct)); dest->FastQueuePacket(&outapp, ack_req); } @@ -280,7 +309,7 @@ namespace RoF2 SETUP_DIRECT_ENCODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); OUT(merchant_entity_id); - eq->slot_id = ServerToRoF2MainInvSlot(emu->slot_id); + eq->inventory_slot = ServerToRoF2TypelessSlot(emu->slot_id); OUT(charges); OUT(cost); @@ -293,8 +322,8 @@ namespace RoF2 SETUP_DIRECT_ENCODE(Animation_Struct, structs::Animation_Struct); OUT(spawnid); - OUT(value); OUT(action); + OUT(speed); FINISH_ENCODE(); } @@ -304,7 +333,7 @@ namespace RoF2 ENCODE_LENGTH_EXACT(ApplyPoison_Struct); SETUP_DIRECT_ENCODE(ApplyPoison_Struct, structs::ApplyPoison_Struct); - eq->inventorySlot = ServerToRoF2MainInvSlot(emu->inventorySlot); + eq->inventorySlot = ServerToRoF2TypelessSlot(emu->inventorySlot); OUT(success); FINISH_ENCODE(); @@ -448,22 +477,34 @@ namespace RoF2 ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - eq->unknown004 = 2; - //eq->level = 80; - //eq->effect = 0; - OUT(level); - OUT(effect); - eq->unknown007 = 0; - eq->unknown008 = 1.0f; - OUT(spellid); - OUT(duration); - eq->playerId = 0x7cde; - OUT(slotid); - OUT(num_hits); + OUT(buff.effect_type); + OUT(buff.level); + // just so we're 100% sure we get a 1.0f ... + eq->buff.bard_modifier = emu->buff.bard_modifier == 10 ? 1.0f : emu->buff.bard_modifier / 10.0f; + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.player_id); + OUT(buff.num_hits); + OUT(buff.y); + OUT(buff.x); + OUT(buff.z); + uint16 buffslot = emu->slotid; + // Not sure if this is needs amending for RoF2 yet. + if (buffslot >= 25) + { + buffslot += 17; + } + // TODO: We should really just deal with these "server side" + // so we can have clients not limited to other clients. + // This fixes discs, songs were changed to 20 + if (buffslot == 54) + buffslot = 62; + eq->slotid = buffslot; + // TODO: implement slot_data stuff if (emu->bufffade == 1) eq->bufffade = 1; else @@ -475,15 +516,15 @@ namespace RoF2 { outapp = new EQApplicationPacket(OP_BuffCreate, 29); outapp->WriteUInt32(emu->entityid); - outapp->WriteUInt32(0x0271); // Unk + outapp->WriteUInt32(0); // tic timer outapp->WriteUInt8(0); // Type of OP_BuffCreate packet ? outapp->WriteUInt16(1); // 1 buff in this packet - outapp->WriteUInt32(emu->slotid); + outapp->WriteUInt32(buffslot); outapp->WriteUInt32(0xffffffff); // SpellID (0xffff to remove) outapp->WriteUInt32(0); // Duration outapp->WriteUInt32(0); // ? outapp->WriteUInt8(0); // Caster name - outapp->WriteUInt8(0); // Terminating byte + outapp->WriteUInt8(0); // Type } FINISH_ENCODE(); @@ -501,7 +542,7 @@ namespace RoF2 memset(__packet->pBuffer, 0, sz); __packet->WriteUInt32(emu->entity_id); - __packet->WriteUInt32(0); // PlayerID ? + __packet->WriteUInt32(emu->tic_timer); __packet->WriteUInt8(emu->all_buffs); // 1 indicates all buffs on the player (0 to add or remove a single buff) __packet->WriteUInt16(emu->count); @@ -513,6 +554,11 @@ namespace RoF2 { buffslot += 17; } + // TODO: We should really just deal with these "server side" + // so we can have clients not limited to other clients. + // This fixes discs, songs were changed to 20 + if (buffslot == 54) + buffslot = 62; __packet->WriteUInt32(buffslot); __packet->WriteUInt32(emu->entries[i].spell_id); @@ -520,7 +566,7 @@ namespace RoF2 __packet->WriteUInt32(emu->entries[i].num_hits); // Unknown __packet->WriteString(""); } - __packet->WriteUInt8(!emu->all_buffs); // Unknown + __packet->WriteUInt8(emu->type); // Unknown FINISH_ENCODE(); } @@ -541,13 +587,10 @@ namespace RoF2 ENCODE_LENGTH_EXACT(CastSpell_Struct); SETUP_DIRECT_ENCODE(CastSpell_Struct, structs::CastSpell_Struct); - if (emu->slot == 10) - eq->slot = 13; - else - OUT(slot); - + eq->slot = static_cast(ServerToRoF2CastingSlot(static_cast(emu->slot))); + OUT(spell_id); - eq->inventoryslot = ServerToRoF2Slot(emu->inventoryslot); + eq->inventory_slot = ServerToRoF2Slot(emu->inventoryslot); //OUT(inventoryslot); OUT(target_id); @@ -569,7 +612,7 @@ namespace RoF2 //in->size = strlen(emu->sender) + 1 + strlen(emu->targetname) + 1 + strlen(emu->message) + 1 + 36; in->size = strlen(emu->sender) + strlen(emu->targetname) + new_message.length() + 39; - + in->pBuffer = new unsigned char[in->size]; char *OutBuffer = (char *)in->pBuffer; @@ -597,70 +640,49 @@ namespace RoF2 ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { - + if (!in->size) { in->size = 4; in->pBuffer = new uchar[in->size]; - - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(EQEmu::InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(EQEmu::InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", - opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); + opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(EQEmu::InternalSerializedItem_Struct)); delete in; - return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + EQEmu::InternalSerializedItem_Struct* eq = (EQEmu::InternalSerializedItem_Struct*)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); - for (int r = 0; r < ItemCount; r++, eq++) { + ob.write((const char*)&item_count, sizeof(uint32)); - uint32 Length = 0; + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ob, (const ItemInst*)eq->inst, eq->slot_id, 0, ItemPacketCharInventory); + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0, ItemPacketCharInventory); - - if (Serialized) { - - uchar *OldBuffer = in->pBuffer; - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ob.tellp(); } - delete[] __emu_buffer; + in->size = ob.size(); + in->pBuffer = ob.detach(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -724,7 +746,10 @@ namespace RoF2 OUT(type); OUT(spellid); OUT(damage); - eq->sequence = emu->sequence; + OUT(force); + OUT(meleepush_xy); + OUT(meleepush_z); + OUT(special); FINISH_ENCODE(); } @@ -768,7 +793,7 @@ namespace RoF2 { SETUP_VAR_ENCODE(ExpeditionCompass_Struct); ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count); - + OUT(count); for (uint32 i = 0; i < emu->count; ++i) @@ -1038,9 +1063,9 @@ namespace RoF2 VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->drop_id); // Some unique id VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Same for all objects in the zone VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->heading); - VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Normally 0, but seen (float)255.0 as well - VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Unknown - VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 1); // Need to add emu->size to struct + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // X tilt + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); // Y tilt + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt. VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z); @@ -1108,7 +1133,8 @@ namespace RoF2 { //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct)); structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); @@ -1126,7 +1152,8 @@ namespace RoF2 //if(gjs->action == groupActLeave) // Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct)); structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); @@ -1163,7 +1190,7 @@ namespace RoF2 //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Leadername is %s", gu2->leadersname); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupUpdateB, PacketLength); + auto outapp = new EQApplicationPacket(OP_GroupUpdateB, PacketLength); char *Buffer = (char *)outapp->pBuffer; @@ -1229,7 +1256,8 @@ namespace RoF2 memcpy(eq->membername, emu->membername, sizeof(eq->membername)); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); GroupLeadershipAAUpdate_Struct *GLAAus = (GroupLeadershipAAUpdate_Struct*)outapp->pBuffer; GLAAus->NPCMarkerID = emu->NPCMarkerID; @@ -1242,6 +1270,54 @@ namespace RoF2 dest->FastQueuePacket(&outapp); } + ENCODE(OP_GuildBank) + { + auto in = *p; + *p = nullptr; + auto outapp = new EQApplicationPacket(OP_GuildBank, in->size + 4); // all of them are 4 bytes bigger + + // The first action in the enum was removed, everything 1 less + // Normally we cast them to their structs, but there are so many here! will only do when it's easier + switch (in->ReadUInt32()) { + case 10: // GuildBankAcknowledge + outapp->WriteUInt32(9); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + break; + case 5: // GuildBankDeposit (ack) + outapp->WriteUInt32(4); + outapp->WriteUInt32(in->ReadUInt32()); + outapp->WriteUInt32(0); + outapp->WriteUInt32(in->ReadUInt32()); + break; + case 1: { // GuildBankItemUpdate + auto emu = (GuildBankItemUpdate_Struct *)in->pBuffer; + auto eq = (structs::GuildBankItemUpdate_Struct *)outapp->pBuffer; + eq->Action = 0; + OUT(Unknown004); + eq->Unknown08 = 0; + OUT(SlotID); + OUT(Area); + OUT(Unknown012); + OUT(ItemID); + OUT(Icon); + OUT(Quantity); + OUT(Permissions); + OUT(AllowMerge); + OUT(Useable); + OUT_str(ItemName); + OUT_str(Donator); + OUT_str(WhoFor); + OUT(Unknown226); + break; + } + default: + break; + } + delete in; + dest->FastQueuePacket(&outapp); + } + ENCODE(OP_GuildMemberList) { //consume the packet @@ -1315,7 +1391,7 @@ namespace RoF2 switch (emu_e->rank) { case 0: { e->rank = htonl(5); break; } // GUILD_MEMBER 0 case 1: { e->rank = htonl(3); break; } // GUILD_OFFICER 1 - case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2 + case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2 default: { e->rank = htonl(emu_e->rank); break; } // GUILD_NONE } @@ -1520,29 +1596,32 @@ namespace RoF2 ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0, old_item_pkt->PacketType); + ItemPacket_Struct* old_item_pkt = (ItemPacket_Struct*)__emu_buffer; + EQEmu::InternalSerializedItem_Struct* int_struct = (EQEmu::InternalSerializedItem_Struct*)(&__emu_buffer[4]); - if (!serialized) { + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); + + ob.write((const char*)__emu_buffer, 4); + + SerializeItem(ob, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0, old_item_pkt->PacketType); + if (ob.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + + in->size = ob.size(); + in->pBuffer = ob.detach(); delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -1551,7 +1630,7 @@ namespace RoF2 ENCODE_LENGTH_EXACT(ItemVerifyReply_Struct); SETUP_DIRECT_ENCODE(ItemVerifyReply_Struct, structs::ItemVerifyReply_Struct); - eq->slot = ServerToRoF2Slot(emu->slot); + eq->inventory_slot = ServerToRoF2Slot(emu->slot); OUT(spell); OUT(target); @@ -1622,7 +1701,8 @@ namespace RoF2 OUT(new_mana); OUT(stamina); OUT(spell_id); - eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2? + OUT(keepcasting); + eq->slot = -1; // this is spell gem slot. It's -1 in normal operation FINISH_ENCODE(); } @@ -1649,7 +1729,7 @@ namespace RoF2 PacketSize += sizeof(structs::MercenaryStance_Struct) * emu->Mercs[r].StanceCount; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, PacketSize); + auto outapp = new EQApplicationPacket(OP_MercenaryDataResponse, PacketSize); Buffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercTypeCount); @@ -2020,18 +2100,18 @@ namespace RoF2 __packet->WriteUInt8(1); // 1 indicates all buffs on the pet (0 to add or remove a single buff) __packet->WriteUInt16(emu->buffcount); - for (uint16 i = 0; i < BUFF_COUNT; ++i) + for (uint16 i = 0; i < PET_BUFF_COUNT; ++i) { if (emu->spellid[i]) { __packet->WriteUInt32(i); __packet->WriteUInt32(emu->spellid[i]); __packet->WriteUInt32(emu->ticsremaining[i]); - __packet->WriteUInt32(0); // Unknown + __packet->WriteUInt32(0); // num hits __packet->WriteString(""); } } - __packet->WriteUInt8(0); // Unknown + __packet->WriteUInt8(0); // some sort of type FINISH_ENCODE(); } @@ -2046,7 +2126,7 @@ namespace RoF2 uint32 PacketSize = 40000; // Calculate this later - EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayerProfile, PacketSize); + auto outapp = new EQApplicationPacket(OP_PlayerProfile, PacketSize); outapp->WriteUInt32(0); // Checksum, we will update this later outapp->WriteUInt32(0); // Checksum size, we will update this later @@ -2085,9 +2165,9 @@ namespace RoF2 outapp->WriteUInt32(22); // Equipment count - for (int r = 0; r < 9; r++) + for (int r = EQEmu::textures::TextureBegin; r < EQEmu::textures::TextureCount; r++) { - outapp->WriteUInt32(emu->item_material[r]); + outapp->WriteUInt32(emu->item_material.Slot[r].Material); outapp->WriteUInt32(0); outapp->WriteUInt32(0); outapp->WriteUInt32(0); @@ -2105,9 +2185,9 @@ namespace RoF2 outapp->WriteUInt32(0); } - outapp->WriteUInt32(9); // Equipment2 count + outapp->WriteUInt32(EQEmu::textures::TextureCount); // Equipment2 count - for (int r = 0; r < 9; r++) + for (int r = EQEmu::textures::TextureBegin; r < EQEmu::textures::TextureCount; r++) { outapp->WriteUInt32(0); outapp->WriteUInt32(0); @@ -2116,21 +2196,21 @@ namespace RoF2 outapp->WriteUInt32(0); } - outapp->WriteUInt32(9); // Tint Count + outapp->WriteUInt32(EQEmu::textures::TextureCount); // Tint Count for (int r = 0; r < 7; r++) { - outapp->WriteUInt32(emu->item_tint[r].Color); + outapp->WriteUInt32(emu->item_tint.Slot[r].Color); } // Write zeroes for extra two tint values outapp->WriteUInt32(0); outapp->WriteUInt32(0); - outapp->WriteUInt32(9); // Tint2 Count + outapp->WriteUInt32(EQEmu::textures::TextureCount); // Tint2 Count for (int r = 0; r < 7; r++) { - outapp->WriteUInt32(emu->item_tint[r].Color); + outapp->WriteUInt32(emu->item_tint.Slot[r].Color); } // Write zeroes for extra two tint values outapp->WriteUInt32(0); @@ -2193,7 +2273,7 @@ namespace RoF2 { outapp->WriteUInt32(emu->aa_array[r].AA); outapp->WriteUInt32(emu->aa_array[r].value); - outapp->WriteUInt32(0); + outapp->WriteUInt32(emu->aa_array[r].charges); } // Fill the other 60 AAs with zeroes @@ -2267,22 +2347,23 @@ namespace RoF2 outapp->WriteUInt32(structs::MAX_PP_MEMSPELL); // Memorised spell slots - for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++) + for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++) // write first 12 { outapp->WriteUInt32(emu->mem_spells[r]); } - // zeroes for the rest of the slots + // zeroes for the rest of the slots the other 4, which actually don't work on the client at all :D for (uint32 r = 0; r < structs::MAX_PP_MEMSPELL - MAX_PP_MEMSPELL; r++) { outapp->WriteUInt32(0xFFFFFFFFU); } - outapp->WriteUInt32(13); // Unknown count + outapp->WriteUInt32(13); // gem refresh counts - for (uint32 r = 0; r < 13; r++) + for (uint32 r = 0; r < MAX_PP_MEMSPELL; r++) { - outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(emu->spellSlotRefresh[r]); // spell gem refresh } + outapp->WriteUInt32(0); // also refresh -- historically HT/LoH :P outapp->WriteUInt8(0); // Unknown @@ -2291,31 +2372,33 @@ namespace RoF2 for (uint32 r = 0; r < BUFF_COUNT; r++) { float instrument_mod = 0.0f; - uint8 slotid = emu->buffs[r].slotid; + uint8 effect_type = emu->buffs[r].effect_type; uint32 player_id = emu->buffs[r].player_id;; if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0) { instrument_mod = 1.0f + (emu->buffs[r].bard_modifier - 10) / 10.0f; - slotid = 2; + effect_type = 2; player_id = 0x000717fd; } else { - slotid = 0; + effect_type = 0; } - outapp->WriteUInt8(0); // Had this as slot, but always appears to be 0 on live. + + // this is different than the client struct for some reason :P + // missing a few things, shuffled around + outapp->WriteUInt8(0); // this is an unknown outapp->WriteFloat(instrument_mod); outapp->WriteUInt32(player_id); outapp->WriteUInt8(0); outapp->WriteUInt32(emu->buffs[r].counters); - //outapp->WriteUInt8(emu->buffs[r].bard_modifier); outapp->WriteUInt32(emu->buffs[r].duration); outapp->WriteUInt8(emu->buffs[r].level); outapp->WriteUInt32(emu->buffs[r].spellid); - outapp->WriteUInt32(slotid); // Only ever seen 2 + outapp->WriteUInt8(effect_type); // Only ever seen 2 + outapp->WriteUInt32(emu->buffs[r].num_hits); outapp->WriteUInt32(0); - outapp->WriteUInt8(0); outapp->WriteUInt32(emu->buffs[r].counters); // Appears twice ? for (uint32 j = 0; j < 44; ++j) @@ -2362,12 +2445,12 @@ namespace RoF2 outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt32(consts::BANDOLIERS_SIZE); + outapp->WriteUInt32(profile::BandoliersSize); // Copy bandoliers where server and client indexes converge - for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { + for (uint32 r = 0; r < EQEmu::legacy::BANDOLIERS_SIZE && r < profile::BandoliersSize; ++r) { outapp->WriteString(emu->bandoliers[r].Name); - for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true + for (uint32 j = 0; j < profile::BandolierItemCount; ++j) { // Will need adjusting if 'server != client' is ever true outapp->WriteString(emu->bandoliers[r].Items[j].Name); outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID); if (emu->bandoliers[r].Items[j].Icon) { @@ -2380,19 +2463,19 @@ namespace RoF2 } } // Nullify bandoliers where server and client indexes diverge, with a client bias - for (uint32 r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + for (uint32 r = EQEmu::legacy::BANDOLIERS_SIZE; r < profile::BandoliersSize; ++r) { outapp->WriteString(""); - for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true + for (uint32 j = 0; j < profile::BandolierItemCount; ++j) { // Will need adjusting if 'server != client' is ever true outapp->WriteString(""); outapp->WriteUInt32(0); outapp->WriteSInt32(-1); } } - - outapp->WriteUInt32(consts::POTION_BELT_ITEM_COUNT); - + + outapp->WriteUInt32(profile::PotionBeltSize); + // Copy potion belt where server and client indexes converge - for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (uint32 r = 0; r < EQEmu::legacy::POTION_BELT_ITEM_COUNT && r < profile::PotionBeltSize; ++r) { outapp->WriteString(emu->potionbelt.Items[r].Name); outapp->WriteUInt32(emu->potionbelt.Items[r].ID); if (emu->potionbelt.Items[r].Icon) { @@ -2404,7 +2487,7 @@ namespace RoF2 } } // Nullify potion belt where server and client indexes diverge, with a client bias - for (uint32 r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (uint32 r = EQEmu::legacy::POTION_BELT_ITEM_COUNT; r < profile::PotionBeltSize; ++r) { outapp->WriteString(""); outapp->WriteUInt32(0); outapp->WriteSInt32(-1); @@ -2415,13 +2498,14 @@ namespace RoF2 outapp->WriteSInt32(234); // Endurance Total ? outapp->WriteSInt32(345); // Mana Total ? - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown - outapp->WriteUInt32(0); // Unknown + // these are needed to fix display bugs + outapp->WriteUInt32(0x19); // base CR + outapp->WriteUInt32(0x19); // base FR + outapp->WriteUInt32(0x19); // base MR + outapp->WriteUInt32(0xf); // base DR + outapp->WriteUInt32(0xf); // base PR + outapp->WriteUInt32(0xf); // base PhR? + outapp->WriteUInt32(0xf); // base Corrup outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown @@ -2459,7 +2543,8 @@ namespace RoF2 outapp->WriteUInt32(emu->lastlogin); outapp->WriteUInt32(emu->timePlayedMin); outapp->WriteUInt32(emu->timeentitledonaccount); - outapp->WriteUInt32(0x0007ffff); // Expansion bitmask + outapp->WriteUInt32(emu->expansions); + //outapp->WriteUInt32(0x0007ffff); // Expansion bitmask outapp->WriteUInt32(structs::MAX_PP_LANGUAGE); @@ -2486,7 +2571,7 @@ namespace RoF2 outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(emu->gm); outapp->WriteUInt32(emu->guild_id); - + outapp->WriteUInt8(emu->guildrank); // guildrank outapp->WriteUInt32(0); // Unknown outapp->WriteUInt8(0); // Unknown @@ -2519,9 +2604,9 @@ namespace RoF2 outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt32(EmuConstants::TRIBUTE_SIZE); + outapp->WriteUInt32(EQEmu::legacy::TRIBUTE_SIZE); - for (uint32 r = 0; r < EmuConstants::TRIBUTE_SIZE; r++) + for (uint32 r = 0; r < EQEmu::legacy::TRIBUTE_SIZE; r++) { outapp->WriteUInt32(emu->tributes[r].tribute); outapp->WriteUInt32(emu->tributes[r].tier); @@ -2541,12 +2626,12 @@ namespace RoF2 outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown - + for (uint32 r = 0; r < 125; r++) { outapp->WriteUInt8(0); // Unknown } - + outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(emu->currentRadCrystals); @@ -2727,7 +2812,7 @@ namespace RoF2 Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Player Profile Packet is %i bytes", outapp->GetWritePosition()); - unsigned char *NewBuffer = new unsigned char[outapp->GetWritePosition()]; + auto NewBuffer = new unsigned char[outapp->GetWritePosition()]; memcpy(NewBuffer, outapp->pBuffer, outapp->GetWritePosition()); safe_delete_array(outapp->pBuffer); outapp->pBuffer = NewBuffer; @@ -2749,7 +2834,7 @@ namespace RoF2 unsigned char * __emu_buffer = inapp->pBuffer; RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer; general->action = 8; @@ -2772,7 +2857,7 @@ namespace RoF2 { RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer; add_member->raidGen.action = in_add_member->raidGen.action; @@ -2792,7 +2877,8 @@ namespace RoF2 else if (raid_gen->action == 35) { RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + strlen(inmotd->motd) + 1); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + + strlen(inmotd->motd) + 1); structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer; outmotd->general.action = inmotd->general.action; @@ -2803,7 +2889,8 @@ namespace RoF2 else if (raid_gen->action == 14 || raid_gen->action == 30) { RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; outlaa->action = inlaa->action; @@ -2816,7 +2903,7 @@ namespace RoF2 { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer; strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64); strn0cpy(raid_general->player_name, in_raid_general->player_name, 64); @@ -2852,12 +2939,12 @@ namespace RoF2 OUT(object_type); OUT(some_id); eq->container_slot = ServerToRoF2Slot(emu->unknown1); - structs::ItemSlotStruct RoF2Slot; - RoF2Slot.SlotType = 8; // Observed + structs::InventorySlot_Struct RoF2Slot; + RoF2Slot.Type = 8; // Observed RoF2Slot.Unknown02 = 0; - RoF2Slot.MainSlot = 0xffff; - RoF2Slot.SubSlot = 0xffff; - RoF2Slot.AugSlot = 0xffff; + RoF2Slot.Slot = 0xffff; + RoF2Slot.SubIndex = 0xffff; + RoF2Slot.AugIndex = 0xffff; RoF2Slot.Unknown01 = 0; eq->unknown_slot = RoF2Slot; OUT(recipe_id); @@ -2892,7 +2979,7 @@ namespace RoF2 eq->aa_spent = emu->aa_spent; // These fields may need to be correctly populated at some point - eq->aapoints_assigned = emu->aa_spent + 1; + eq->aapoints_assigned = emu->aa_spent; eq->aa_spent_general = 0; eq->aa_spent_archetype = 0; eq->aa_spent_class = 0; @@ -2900,9 +2987,9 @@ namespace RoF2 for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i) { - eq->aa_list[i].aa_skill = emu->aa_list[i].aa_skill; - eq->aa_list[i].aa_value = emu->aa_list[i].aa_value; - eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08; + eq->aa_list[i].AA = emu->aa_list[i].AA; + eq->aa_list[i].value = emu->aa_list[i].value; + eq->aa_list[i].charges = emu->aa_list[i].charges; } FINISH_ENCODE(); @@ -2928,57 +3015,80 @@ namespace RoF2 ENCODE(OP_SendAATable) { - ENCODE_LENGTH_ATLEAST(SendAA_Struct); - SETUP_VAR_ENCODE(SendAA_Struct); - ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); + EQApplicationPacket *inapp = *p; + *p = nullptr; + AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer; + + // the structs::SendAA_Struct includes enough space for 1 prereq which is the min even if it has no prereqs + auto prereq_size = emu->total_prereqs > 1 ? (emu->total_prereqs - 1) * 8 : 0; + auto outapp = new EQApplicationPacket(OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability) + prereq_size); + inapp->SetReadPosition(sizeof(AARankInfo_Struct)+emu->total_effects * sizeof(AARankEffect_Struct)); + - // Check clientver field to verify this AA should be sent for SoF - // clientver 1 is for all clients and 5 is for Live - if (emu->clientver <= 5) - { - OUT(id); - eq->unknown004 = 1; - //eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->title_sid = emu->id - emu->current_level + 1; - //eq->desc_sid = emu->id - emu->current_level + 1; - eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? -1 : (emu->sof_next_skill); - eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? -1 : (emu->sof_next_skill); - eq->title_sid = emu->sof_next_skill; - eq->desc_sid = emu->sof_next_skill; - OUT(class_type); - OUT(cost); - OUT(seq); - OUT(current_level); - eq->unknown037 = 1; // Introduced during HoT - OUT(prereq_skill); - eq->unknown045 = 1; // New Mar 21 2012 - Seen 1 - OUT(prereq_minpoints); - eq->type = emu->sof_type; - OUT(spellid); - eq->unknown057 = 1; // Introduced during HoT - OUT(spell_type); - OUT(spell_refresh); - OUT(classes); - OUT(berserker); - //eq->max_level = emu->sof_max_level; - OUT(max_level); - OUT(last_id); - OUT(next_id); - OUT(cost2); - eq->aa_expansion = emu->aa_expansion; - eq->special_category = emu->special_category; - OUT(total_abilities); - unsigned int r; - for (r = 0; r < emu->total_abilities; r++) { - OUT(abilities[r].skill_id); - OUT(abilities[r].base1); - OUT(abilities[r].base2); - OUT(abilities[r].slot); - } + std::vector skill; + std::vector points; + for(auto i = 0; i < emu->total_prereqs; ++i) { + skill.push_back(inapp->ReadUInt32()); + points.push_back(inapp->ReadUInt32()); } - FINISH_ENCODE(); + outapp->WriteUInt32(emu->id); + outapp->WriteUInt8(1); + outapp->WriteSInt32(emu->upper_hotkey_sid); + outapp->WriteSInt32(emu->lower_hotkey_sid); + outapp->WriteSInt32(emu->title_sid); + outapp->WriteSInt32(emu->desc_sid); + outapp->WriteSInt32(emu->level_req); + outapp->WriteSInt32(emu->cost); + outapp->WriteUInt32(emu->seq); + outapp->WriteUInt32(emu->current_level); + + if (emu->total_prereqs) { + outapp->WriteUInt32(emu->total_prereqs); + for (auto &e : skill) + outapp->WriteSInt32(e); + outapp->WriteUInt32(emu->total_prereqs); + for (auto &e : points) + outapp->WriteSInt32(e); + } else { + outapp->WriteUInt32(1); + outapp->WriteUInt32(0); + outapp->WriteUInt32(1); + outapp->WriteUInt32(0); + } + + outapp->WriteSInt32(emu->type); + outapp->WriteSInt32(emu->spell); + outapp->WriteSInt32(1); + outapp->WriteSInt32(emu->spell_type); + outapp->WriteSInt32(emu->spell_refresh); + outapp->WriteSInt32(emu->classes); + outapp->WriteSInt32(emu->max_level); + outapp->WriteSInt32(emu->prev_id); + outapp->WriteSInt32(emu->next_id); + outapp->WriteSInt32(emu->total_cost); + outapp->WriteUInt8(0); + outapp->WriteUInt8(emu->grant_only); + outapp->WriteUInt8(0); + outapp->WriteUInt32(emu->charges); + outapp->WriteSInt32(emu->expansion); + outapp->WriteSInt32(emu->category); + outapp->WriteUInt8(0); // shroud + outapp->WriteUInt8(0); // unknown109 + outapp->WriteUInt8(0); // loh + outapp->WriteUInt8(0); // unknown111 + outapp->WriteUInt32(emu->total_effects); + + inapp->SetReadPosition(sizeof(AARankInfo_Struct)); + for(auto i = 0; i < emu->total_effects; ++i) { + outapp->WriteUInt32(inapp->ReadUInt32()); // skill_id + outapp->WriteUInt32(inapp->ReadUInt32()); // base1 + outapp->WriteUInt32(inapp->ReadUInt32()); // base2 + outapp->WriteUInt32(inapp->ReadUInt32()); // slot + } + + dest->FastQueuePacket(&outapp); + delete inapp; } ENCODE(OP_SendCharInfo) @@ -3001,7 +3111,7 @@ namespace RoF2 size_t names_length = 0; size_t character_count = 0; - for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) { + for (; character_count < emu->CharCount && character_count < constants::CharacterCreationLimit; ++character_count) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; names_length += strlen(emu_cse->Name); emu_ptr += sizeof(CharacterSelectEntry_Struct); @@ -3028,11 +3138,12 @@ namespace RoF2 for (int counter = 0; counter < character_count; ++counter) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address strcpy(eq_cse->Name, emu_cse->Name); - eq_ptr += strlen(eq_cse->Name); - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_ptr += strlen(emu_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset) + eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)] eq_cse->Class = emu_cse->Class; eq_cse->Race = emu_cse->Race; @@ -3044,13 +3155,13 @@ namespace RoF2 eq_cse->Gender = emu_cse->Gender; eq_cse->Face = emu_cse->Face; - for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) { + for (int equip_index = 0; equip_index < EQEmu::textures::TextureCount; equip_index++) { eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material; eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1; eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial; eq_cse->Equip[equip_index].HeroForgeModel = emu_cse->Equip[equip_index].HeroForgeModel; eq_cse->Equip[equip_index].Material2 = emu_cse->Equip[equip_index].Material2; - eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; + eq_cse->Equip[equip_index].Color = emu_cse->Equip[equip_index].Color; } eq_cse->Unknown15 = emu_cse->Unknown15; @@ -3112,7 +3223,7 @@ namespace RoF2 switch (emu->Rank) { case 0: { eq->Rank = 5; break; } // GUILD_MEMBER 0 case 1: { eq->Rank = 3; break; } // GUILD_OFFICER 1 - case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2 + case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2 default: { eq->Rank = emu->Rank; break; } } @@ -3143,7 +3254,7 @@ namespace RoF2 SETUP_DIRECT_ENCODE(Merchant_Purchase_Struct, structs::Merchant_Purchase_Struct); OUT(npcid); - eq->itemslot = ServerToRoF2MainInvSlot(emu->itemslot); + eq->inventory_slot = ServerToRoF2TypelessSlot(emu->itemslot); //OUT(itemslot); OUT(quantity); OUT(price); @@ -3226,7 +3337,7 @@ namespace RoF2 return; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ChangeSize, sizeof(ChangeSize_Struct)); + auto outapp = new EQApplicationPacket(OP_ChangeSize, sizeof(ChangeSize_Struct)); ChangeSize_Struct *css = (ChangeSize_Struct *)outapp->pBuffer; @@ -3460,7 +3571,7 @@ namespace RoF2 in->SetReadPosition(0); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_TaskHistoryReply, OutboundPacketSize); + auto outapp = new EQApplicationPacket(OP_TaskHistoryReply, OutboundPacketSize); outapp->WriteUInt32(in->ReadUInt32()); // Task index outapp->WriteUInt32(in->ReadUInt32()); // Activity count @@ -3743,7 +3854,7 @@ namespace RoF2 ENCODE_LENGTH_EXACT(TributeItem_Struct); SETUP_DIRECT_ENCODE(TributeItem_Struct, structs::TributeItem_Struct); - eq->slot = ServerToRoF2Slot(emu->slot); + eq->inventory_slot = ServerToRoF2Slot(emu->slot); OUT(quantity); OUT(tribute_master_id); OUT(tribute_points); @@ -3847,7 +3958,7 @@ namespace RoF2 int Count = wars->playercount; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_WhoAllResponse, in->size + (Count * 4)); + auto outapp = new EQApplicationPacket(OP_WhoAllResponse, in->size + (Count * 4)); char *OutBuffer = (char *)outapp->pBuffer; @@ -3918,7 +4029,7 @@ namespace RoF2 } ENCODE(OP_ZoneEntry) { ENCODE_FORWARD(OP_ZoneSpawns); } - + ENCODE(OP_ZonePlayerToBind) { SETUP_VAR_ENCODE(ZonePlayerToBind_Struct); @@ -3994,6 +4105,17 @@ namespace RoF2 if (strlen(emu->suffix)) PacketSize += strlen(emu->suffix) + 1; + if (emu->DestructibleObject || emu->class_ == 62) + { + if (emu->DestructibleObject) + PacketSize = PacketSize - 4; // No bodytype + + PacketSize += 53; // Fixed portion + PacketSize += strlen(emu->DestructibleModel) + 1; + PacketSize += strlen(emu->DestructibleName2) + 1; + PacketSize += strlen(emu->DestructibleString) + 1; + } + bool ShowName = 1; if (emu->bodytype >= 66) { @@ -4022,13 +4144,20 @@ namespace RoF2 SpawnSize = 3; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ZoneEntry, PacketSize); + auto outapp = new EQApplicationPacket(OP_ZoneEntry, PacketSize); Buffer = (char *)outapp->pBuffer; BufferStart = Buffer; VARSTRUCT_ENCODE_STRING(Buffer, emu->name); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spawnId); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->level); - VARSTRUCT_ENCODE_TYPE(float, Buffer, SpawnSize - 0.7); // Eye Height? + if (emu->DestructibleObject) + { + VARSTRUCT_ENCODE_TYPE(float, Buffer, 10); // was int and 0x41200000 + } + else + { + VARSTRUCT_ENCODE_TYPE(float, Buffer, SpawnSize - 0.7); // Eye Height? + } VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->NPC); structs::Spawn_Struct_Bitfields *Bitfields = (structs::Spawn_Struct_Bitfields*)Buffer; @@ -4048,6 +4177,12 @@ namespace RoF2 Bitfields->targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0; Bitfields->showname = ShowName; + if (emu->DestructibleObject) + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x1d600000); + Buffer = Buffer - 4; + } + // Not currently found // Bitfields->statue = 0; // Bitfields->buyer = 0; @@ -4056,21 +4191,66 @@ namespace RoF2 uint8 OtherData = 0; + if (emu->class_ == 62) //LDoN Chest + OtherData = OtherData | 0x04; + if (strlen(emu->title)) OtherData = OtherData | 16; if (strlen(emu->suffix)) OtherData = OtherData | 32; + if (emu->DestructibleObject) + OtherData = OtherData | 0xe1; // Live has 0xe1 for OtherData + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, OtherData); - VARSTRUCT_ENCODE_TYPE(float, Buffer, -1); // unknown3 + if (emu->DestructibleObject) + { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x00000000); + } + else + { + VARSTRUCT_ENCODE_TYPE(float, Buffer, -1); // unknown3 + } VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4 - // Setting this next field to zero will cause a crash. Looking at ShowEQ, if it is zero, the bodytype field is not - // present. Will sort that out later. - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1); // This is a properties count field - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->bodytype); + if (emu->DestructibleObject || emu->class_ == 62) + { + VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleModel); + VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleName2); + VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleString); + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleAppearance); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk1); + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID1); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID2); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID3); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleID4); + + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk2); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk3); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk4); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk5); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk6); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk7); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->DestructibleUnk8); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->DestructibleUnk9); + } + + + if (!emu->DestructibleObject) + { + // Setting this next field to zero will cause a crash. Looking at ShowEQ, if it is zero, the bodytype field is not + // present. Will sort that out later. + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1); // This is a properties count field + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->bodytype); + } + else + { + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); + } VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->curHp); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->haircolor); @@ -4109,8 +4289,8 @@ namespace RoF2 switch (emu->guildrank) { case 0: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 5); break; } // GUILD_MEMBER 0 case 1: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 3); break; } // GUILD_OFFICER 1 - case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2 - default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } // + case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2 + default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } // } } @@ -4133,7 +4313,7 @@ namespace RoF2 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13 - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown14 - Stance 64 = normal 4 = aggressive 40 = stun/mezzed + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17 @@ -4142,24 +4322,24 @@ namespace RoF2 if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)) { - for (k = 0; k < 9; ++k) + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; ++k) { { - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment_tint.Slot[k].Color); } } - structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer; + structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer; - for (k = 0; k < 9; k++) { - Equipment[k].Material = emu->equipment[k].Material; - Equipment[k].Unknown1 = emu->equipment[k].Unknown1; - Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; - Equipment[k].HeroForgeModel = emu->equipment[k].HeroForgeModel; - Equipment[k].Material2 = emu->equipment[k].Material2; + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; k++) { + Equipment[k].Material = emu->equipment.Slot[k].Material; + Equipment[k].Unknown1 = emu->equipment.Slot[k].Unknown1; + Equipment[k].EliteMaterial = emu->equipment.Slot[k].EliteMaterial; + Equipment[k].HeroForgeModel = emu->equipment.Slot[k].HeroForgeModel; + Equipment[k].Material2 = emu->equipment.Slot[k].Material2; } - Buffer += (sizeof(structs::EquipStruct) * 9); + Buffer += (sizeof(structs::Texture_Struct) * EQEmu::textures::TextureCount); } else { @@ -4169,13 +4349,13 @@ namespace RoF2 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment.Primary.Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment.Secondary.Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); @@ -4193,7 +4373,7 @@ namespace RoF2 Position->z = emu->z; Position->animation = emu->animation; Position->deltaY = emu->deltaY; - + Buffer += sizeof(structs::Spawn_Struct_Position); if (strlen(emu->title)) @@ -4225,6 +4405,19 @@ namespace RoF2 delete in; } + ENCODE(OP_CrystalCountUpdate) + { + ENCODE_LENGTH_EXACT(CrystalCountUpdate_Struct); + SETUP_DIRECT_ENCODE(CrystalCountUpdate_Struct, structs::CrystalCountUpdate_Struct); + + OUT(CurrentRadiantCrystals); + OUT(CareerRadiantCrystals); + OUT(CurrentEbonCrystals); + OUT(CareerEbonCrystals); + + FINISH_ENCODE(); + } + // DECODE methods DECODE(OP_AdventureMerchantSell) @@ -4233,7 +4426,7 @@ namespace RoF2 SETUP_DIRECT_DECODE(Adventure_Sell_Struct, structs::Adventure_Sell_Struct); IN(npcid); - emu->slot = RoF2ToServerMainInvSlot(eq->slot); + emu->slot = RoF2ToServerTypelessSlot(eq->inventory_slot); IN(charges); IN(sell_price); @@ -4246,7 +4439,7 @@ namespace RoF2 SETUP_DIRECT_DECODE(AltCurrencySellItem_Struct, structs::AltCurrencySellItem_Struct); IN(merchant_entity_id); - emu->slot_id = RoF2ToServerMainInvSlot(eq->slot_id); + emu->slot_id = RoF2ToServerTypelessSlot(eq->inventory_slot); IN(charges); IN(cost); @@ -4259,7 +4452,19 @@ namespace RoF2 SETUP_DIRECT_DECODE(AltCurrencySelectItem_Struct, structs::AltCurrencySelectItem_Struct); IN(merchant_entity_id); - emu->slot_id = RoF2ToServerMainInvSlot(eq->slot_id); + emu->slot_id = RoF2ToServerTypelessSlot(eq->inventory_slot); + + FINISH_DIRECT_DECODE(); + } + + DECODE(OP_Animation) + { + DECODE_LENGTH_EXACT(structs::Animation_Struct); + SETUP_DIRECT_DECODE(Animation_Struct, structs::Animation_Struct); + + IN(spawnid); + IN(action); + IN(speed); FINISH_DIRECT_DECODE(); } @@ -4269,7 +4474,7 @@ namespace RoF2 DECODE_LENGTH_EXACT(structs::ApplyPoison_Struct); SETUP_DIRECT_DECODE(ApplyPoison_Struct, structs::ApplyPoison_Struct); - emu->inventorySlot = RoF2ToServerMainInvSlot(eq->inventorySlot); + emu->inventorySlot = RoF2ToServerTypelessSlot(eq->inventorySlot); IN(success); FINISH_DIRECT_DECODE(); @@ -4337,15 +4542,15 @@ namespace RoF2 DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct_Live); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Live); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - //IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.unknown003); + IN(buff.spellid); + IN(buff.duration); IN(slotid); IN(bufffade); @@ -4371,15 +4576,15 @@ namespace RoF2 DECODE_LENGTH_EXACT(structs::CastSpell_Struct); SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct); - if (eq->slot == 13) - emu->slot = 10; - else - IN(slot); - + emu->slot = static_cast(RoF2ToServerCastingSlot(static_cast(eq->slot))); + IN(spell_id); - emu->inventoryslot = RoF2ToServerSlot(eq->inventoryslot); + emu->inventoryslot = RoF2ToServerSlot(eq->inventory_slot); //IN(inventoryslot); IN(target_id); + IN(y_pos); + IN(x_pos); + IN(z_pos); FINISH_DIRECT_DECODE(); } @@ -4501,7 +4706,7 @@ namespace RoF2 DECODE_LENGTH_EXACT(structs::Consume_Struct); SETUP_DIRECT_DECODE(Consume_Struct, structs::Consume_Struct); - emu->slot = RoF2ToServerSlot(eq->slot); + emu->slot = RoF2ToServerSlot(eq->inventory_slot); IN(auto_consumed); IN(type); @@ -4518,7 +4723,7 @@ namespace RoF2 IN(type); IN(spellid); IN(damage); - emu->sequence = eq->sequence; + IN(meleepush_xy); FINISH_DIRECT_DECODE(); } @@ -4691,6 +4896,92 @@ namespace RoF2 DECODE_FORWARD(OP_GroupInvite); } + DECODE(OP_GuildBank) + { + // all actions are 1 off due to the removal of one of enums + switch (__packet->ReadUInt32()) { + case 2: {// GuildBankPromote + DECODE_LENGTH_EXACT(structs::GuildBankPromote_Struct); + SETUP_DIRECT_DECODE(GuildBankPromote_Struct, structs::GuildBankPromote_Struct); + emu->Action = 3; + IN(Unknown04); + IN(Slot); + IN(Slot2); + FINISH_DIRECT_DECODE(); + return; + } + case 3: { // GuildBankViewItem + DECODE_LENGTH_EXACT(structs::GuildBankViewItem_Struct); + SETUP_DIRECT_DECODE(GuildBankViewItem_Struct, structs::GuildBankViewItem_Struct); + emu->Action = 4; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Unknown16); + FINISH_DIRECT_DECODE(); + return; + } + case 4: { // GuildBankDeposit + __packet->WriteUInt32(5); + return; + } + case 5: { // GuildBankPermissions + DECODE_LENGTH_EXACT(structs::GuildBankPermissions_Struct); + SETUP_DIRECT_DECODE(GuildBankPermissions_Struct, structs::GuildBankPermissions_Struct); + emu->Action = 6; + IN(Unknown04); + IN(SlotID); + IN(Unknown10); + IN(ItemID); + IN(Permissions); + strn0cpy(emu->MemberName, eq->MemberName, 64); + FINISH_DIRECT_DECODE(); + return; + } + case 6: { // GuildBankWithdraw + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 7; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 7: { // GuildBankSplitStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 8; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + case 8: { // GuildBankMergeStacks + DECODE_LENGTH_EXACT(structs::GuildBankWithdrawItem_Struct); + SETUP_DIRECT_DECODE(GuildBankWithdrawItem_Struct, structs::GuildBankWithdrawItem_Struct); + emu->Action = 9; + IN(Unknown04); + IN(SlotID); + IN(Area); + IN(Unknown12); + IN(Quantity); + FINISH_DIRECT_DECODE(); + return; + } + default: + Log.Out(Logs::Detail, Logs::Netcode, "Unhandled OP_GuildBank action"); + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ + return; + } + } + DECODE(OP_GuildDemote) { DECODE_LENGTH_EXACT(structs::GuildDemoteStruct); @@ -4776,7 +5067,7 @@ namespace RoF2 IN(item_id); int r; - for (r = 0; r < EmuConstants::ITEM_COMMON_SIZE; r++) { + for (r = 0; r < EQEmu::legacy::ITEM_COMMON_SIZE; r++) { IN(augments[r]); } IN(link_hash); @@ -4790,7 +5081,7 @@ namespace RoF2 DECODE_LENGTH_EXACT(structs::ItemVerifyRequest_Struct); SETUP_DIRECT_DECODE(ItemVerifyRequest_Struct, structs::ItemVerifyRequest_Struct); - emu->slot = RoF2ToServerSlot(eq->slot); + emu->slot = RoF2ToServerSlot(eq->inventory_slot); IN(target); FINISH_DIRECT_DECODE(); @@ -4830,7 +5121,7 @@ namespace RoF2 DECODE_LENGTH_EXACT(structs::MoveItem_Struct); SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct); - Log.Out(Logs::General, Logs::Netcode, "[RoF2] MoveItem SlotType from %i to %i, MainSlot from %i to %i, SubSlot from %i to %i, AugSlot from %i to %i, Unknown01 from %i to %i, Number %u", eq->from_slot.SlotType, eq->to_slot.SlotType, eq->from_slot.MainSlot, eq->to_slot.MainSlot, eq->from_slot.SubSlot, eq->to_slot.SubSlot, eq->from_slot.AugSlot, eq->to_slot.AugSlot, eq->from_slot.Unknown01, eq->to_slot.Unknown01, eq->number_in_stack); + Log.Out(Logs::General, Logs::Netcode, "[RoF2] MoveItem SlotType from %i to %i, MainSlot from %i to %i, SubSlot from %i to %i, AugSlot from %i to %i, Unknown01 from %i to %i, Number %u", eq->from_slot.Type, eq->to_slot.Type, eq->from_slot.Slot, eq->to_slot.Slot, eq->from_slot.SubIndex, eq->to_slot.SubIndex, eq->from_slot.AugIndex, eq->to_slot.AugIndex, eq->from_slot.Unknown01, eq->to_slot.Unknown01, eq->number_in_stack); emu->from_slot = RoF2ToServerSlot(eq->from_slot); emu->to_slot = RoF2ToServerSlot(eq->to_slot); IN(number_in_stack); @@ -4844,7 +5135,7 @@ namespace RoF2 SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct); IN(command); - emu->unknown = eq->unknown04; + IN(target); FINISH_DIRECT_DECODE(); } @@ -4979,7 +5270,7 @@ namespace RoF2 SETUP_DIRECT_DECODE(Merchant_Purchase_Struct, structs::Merchant_Purchase_Struct); IN(npcid); - emu->itemslot = RoF2ToServerMainInvSlot(eq->itemslot); + emu->itemslot = RoF2ToServerTypelessSlot(eq->inventory_slot); //IN(itemslot); IN(quantity); IN(price); @@ -5098,7 +5389,7 @@ namespace RoF2 IN(Quantity); Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct (Unknowns) Unknown004 %d, Unknown008 %d, Unknown012 %d, Unknown076 %d, Unknown276 %d", eq->Unknown004, eq->Unknown008, eq->Unknown012, eq->Unknown076, eq->Unknown276); - Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s", + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s", eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, eq->ItemName); FINISH_DIRECT_DECODE(); @@ -5120,7 +5411,7 @@ namespace RoF2 int16 slot_id = RoF2ToServerSlot(eq->container_slot); if (slot_id == 4000) { - slot_id = legacy::SLOT_TRADESKILL; // 1000 + slot_id = EQEmu::legacy::SLOT_TRADESKILL; // 1000 } emu->container_slot = slot_id; emu->guildtribute_slot = RoF2ToServerSlot(eq->guildtribute_slot); // this should only return INVALID_INDEX until implemented @@ -5133,7 +5424,7 @@ namespace RoF2 DECODE_LENGTH_EXACT(structs::TributeItem_Struct); SETUP_DIRECT_DECODE(TributeItem_Struct, structs::TributeItem_Struct); - emu->slot = RoF2ToServerSlot(eq->slot); + emu->slot = RoF2ToServerSlot(eq->inventory_slot); IN(quantity); IN(tribute_master_id); IN(tribute_points); @@ -5209,85 +5500,81 @@ namespace RoF2 return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth, ItemPacketType packet_type) + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id_in, uint8 depth, ItemPacketType packet_type) { - int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); - + const EQEmu::ItemBase *item = inst->GetUnscaledItem(); + RoF2::structs::ItemSerializationHeader hdr; //sprintf(hdr.unknown000, "06e0002Y1W00"); snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID); - hdr.stacksize = stackable ? charges : 1; + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 1000) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; - structs::ItemSlotStruct slot_id = ServerToRoF2Slot(slot_id_in, packet_type); + structs::InventorySlot_Struct slot_id = ServerToRoF2Slot(slot_id_in, packet_type); - hdr.slot_type = (merchant_slot == 0) ? slot_id.SlotType : 9; // 9 is merchant 20 is reclaim items? - hdr.main_slot = (merchant_slot == 0) ? slot_id.MainSlot : merchant_slot; - hdr.sub_slot = (merchant_slot == 0) ? slot_id.SubSlot : 0xffff; - hdr.aug_slot = (merchant_slot == 0) ? slot_id.AugSlot : 0xffff; + hdr.slot_type = (inst->GetMerchantSlot() ? invtype::InvTypeMerchant : slot_id.Type); + hdr.main_slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id.Slot); + hdr.sub_slot = (inst->GetMerchantSlot() ? 0xffff : slot_id.SubIndex); + hdr.aug_slot = (inst->GetMerchantSlot() ? 0xffff : slot_id.AugIndex); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; - hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; - ss.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader)); + hdr.isEvolving = item->EvolvingItem; - if (item->EvolvingLevel > 0) { + ob.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader)); + + if (item->EvolvingItem > 0) { RoF2::structs::EvolvingItem evotop; + evotop.unknown001 = 0; evotop.unknown002 = 0; evotop.unknown003 = 0; evotop.unknown004 = 0; evotop.evoLevel = item->EvolvingLevel; - evotop.progress = 95.512; + evotop.progress = 0; evotop.Activated = 1; - evotop.evomaxlevel = 7; - ss.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem)); + evotop.evomaxlevel = item->EvolvingMax; + + ob.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem)); } + //ORNAMENT IDFILE / ICON + int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); uint32 ornaIcon = 0; uint32 heroModel = 0; - if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) - { - char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); - //Mainhand - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); - //Offhand - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); + if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { ornaIcon = inst->GetOrnamentationIcon(); heroModel = inst->GetOrnamentHeroModel(Inventory::CalcMaterialFromSlot(slot_id_in)); + + char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + + //Mainhand + ob.write(tmp, strlen(tmp)); + ob.write("\0", 1); + + //Offhand + ob.write(tmp, strlen(tmp)); + ob.write("\0", 1); } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); // no main hand Ornamentation - ss.write((const char*)&null_term, sizeof(uint8)); // no off hand Ornamentation + else { + ob.write("\0", 1); // no main hand Ornamentation + ob.write("\0", 1); // no off hand Ornamentation } RoF2::structs::ItemSerializationHeaderFinish hdrf; + hdrf.ornamentIcon = ornaIcon; hdrf.unknowna1 = 0xffffffff; hdrf.ornamentHeroModel = heroModel; @@ -5297,40 +5584,22 @@ namespace RoF2 hdrf.unknowna5 = 0; hdrf.ItemClass = item->ItemClass; - ss.write((const char*)&hdrf, sizeof(RoF2::structs::ItemSerializationHeaderFinish)); + ob.write((const char*)&hdrf, sizeof(RoF2::structs::ItemSerializationHeaderFinish)); if (strlen(item->Name) > 0) - { - ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Name, strlen(item->Name)); + ob.write("\0", 1); if (strlen(item->Lore) > 0) - { - ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Lore, strlen(item->Lore)); + ob.write("\0", 1); if (strlen(item->IDFile) > 0) - { - ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->IDFile, strlen(item->IDFile)); + ob.write("\0", 1); - ss.write((const char*)&null_term, sizeof(uint8)); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody struct is %i bytes", sizeof(RoF2::structs::ItemBodyStruct)); + ob.write("\0", 1); + RoF2::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(RoF2::structs::ItemBodyStruct)); @@ -5372,7 +5641,7 @@ namespace RoF2 ibs.Races = item->Races; ibs.Deity = item->Deity; ibs.SkillModValue = item->SkillModValue; - ibs.SkillModMax = 0xffffffff; + ibs.SkillModMax = item->SkillModMax; ibs.SkillModType = (int8)(item->SkillModType); ibs.SkillModExtra = 0; ibs.BaneDmgRace = item->BaneDmgRace; @@ -5381,12 +5650,8 @@ namespace RoF2 ibs.BaneDmgAmt = item->BaneDmgAmt; ibs.Magic = item->Magic; ibs.CastTime_ = item->CastTime_; - ibs.ReqLevel = item->ReqLevel; - if (item->ReqLevel > 100) - ibs.ReqLevel = 100; - ibs.RecLevel = item->RecLevel; - if (item->RecLevel > 100) - ibs.RecLevel = 100; + ibs.ReqLevel = ((item->ReqLevel > 100) ? 100 : item->ReqLevel); + ibs.RecLevel = ((item->RecLevel > 100) ? 100 : item->RecLevel); ibs.RecSkill = item->RecSkill; ibs.BardType = item->BardType; ibs.BardValue = item->BardValue; @@ -5424,20 +5689,13 @@ namespace RoF2 ibs.FactionAmt4 = item->FactionAmt4; ibs.FactionMod4 = item->FactionMod4; - ss.write((const char*)&ibs, sizeof(RoF2::structs::ItemBodyStruct)); + ob.write((const char*)&ibs, sizeof(RoF2::structs::ItemBodyStruct)); //charm text if (strlen(item->CharmFile) > 0) - { - ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->CharmFile, strlen(item->CharmFile)); + ob.write("\0", 1); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody secondary struct is %i bytes", sizeof(RoF2::structs::ItemSecondaryBodyStruct)); RoF2::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(RoF2::structs::ItemSecondaryBodyStruct)); @@ -5445,11 +5703,10 @@ namespace RoF2 isbs.augrestrict2 = -1; isbs.augrestrict = item->AugRestrict; - for (int x = AUG_BEGIN; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < invaug::ItemAugSize; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -5466,19 +5723,12 @@ namespace RoF2 isbs.book = item->Book; isbs.booktype = item->BookType; - ss.write((const char*)&isbs, sizeof(RoF2::structs::ItemSecondaryBodyStruct)); + ob.write((const char*)&isbs, sizeof(RoF2::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { - ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->Filename, strlen(item->Filename)); + ob.write("\0", 1); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody tertiary struct is %i bytes", sizeof(RoF2::structs::ItemTertiaryBodyStruct)); RoF2::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(RoF2::structs::ItemTertiaryBodyStruct)); @@ -5500,7 +5750,7 @@ namespace RoF2 itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; @@ -5512,12 +5762,11 @@ namespace RoF2 itbs.unknown13 = 0; itbs.unknown14 = 0; - ss.write((const char*)&itbs, sizeof(RoF2::structs::ItemTertiaryBodyStruct)); + ob.write((const char*)&itbs, sizeof(RoF2::structs::ItemTertiaryBodyStruct)); // Effect Structures Broken down to allow variable length strings for effect names int32 effect_unknown = 0; - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody Click effect struct is %i bytes", sizeof(RoF2::structs::ClickEffectStruct)); RoF2::structs::ClickEffectStruct ices; memset(&ices, 0, sizeof(RoF2::structs::ClickEffectStruct)); @@ -5530,21 +5779,14 @@ namespace RoF2 ices.recast = item->RecastDelay; ices.recast_type = item->RecastType; - ss.write((const char*)&ices, sizeof(RoF2::structs::ClickEffectStruct)); + ob.write((const char*)&ices, sizeof(RoF2::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { - ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ClickName, strlen(item->ClickName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 + ob.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody proc effect struct is %i bytes", sizeof(RoF2::structs::ProcEffectStruct)); RoF2::structs::ProcEffectStruct ipes; memset(&ipes, 0, sizeof(RoF2::structs::ProcEffectStruct)); @@ -5554,21 +5796,14 @@ namespace RoF2 ipes.level = item->Proc.Level; ipes.procrate = item->ProcRate; - ss.write((const char*)&ipes, sizeof(RoF2::structs::ProcEffectStruct)); + ob.write((const char*)&ipes, sizeof(RoF2::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { - ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ProcName, strlen(item->ProcName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody worn effect struct is %i bytes", sizeof(RoF2::structs::WornEffectStruct)); RoF2::structs::WornEffectStruct iwes; memset(&iwes, 0, sizeof(RoF2::structs::WornEffectStruct)); @@ -5577,19 +5812,13 @@ namespace RoF2 iwes.type = item->Worn.Type; iwes.level = item->Worn.Level; - ss.write((const char*)&iwes, sizeof(RoF2::structs::WornEffectStruct)); + ob.write((const char*)&iwes, sizeof(RoF2::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { - ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->WornName, strlen(item->WornName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 RoF2::structs::WornEffectStruct ifes; memset(&ifes, 0, sizeof(RoF2::structs::WornEffectStruct)); @@ -5599,19 +5828,13 @@ namespace RoF2 ifes.type = item->Focus.Type; ifes.level = item->Focus.Level; - ss.write((const char*)&ifes, sizeof(RoF2::structs::WornEffectStruct)); + ob.write((const char*)&ifes, sizeof(RoF2::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { - ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->FocusName, strlen(item->FocusName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 RoF2::structs::WornEffectStruct ises; memset(&ises, 0, sizeof(RoF2::structs::WornEffectStruct)); @@ -5621,19 +5844,13 @@ namespace RoF2 ises.type = item->Scroll.Type; ises.level = item->Scroll.Level; - ss.write((const char*)&ises, sizeof(RoF2::structs::WornEffectStruct)); + ob.write((const char*)&ises, sizeof(RoF2::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { - ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ScrollName, strlen(item->ScrollName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // Bard Effect? RoF2::structs::WornEffectStruct ibes; @@ -5645,21 +5862,20 @@ namespace RoF2 ibes.level = item->Bard.Level; //ibes.unknown6 = 0xffffffff; - ss.write((const char*)&ibes, sizeof(RoF2::structs::WornEffectStruct)); + ob.write((const char*)&ibes, sizeof(RoF2::structs::WornEffectStruct)); /* if(strlen(item->BardName) > 0) { - ss.write((const char*)item->BardName, strlen(item->BardName)); - ss.write((const char*)&null_term, sizeof(uint8)); + ob.write((const char*)item->BardName, strlen(item->BardName)); + ob.write((const char*)&null_term, sizeof(uint8)); } else */ - ss.write((const char*)&null_term, sizeof(uint8)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] ItemBody Quaternary effect struct is %i bytes", sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); RoF2::structs::ItemQuaternaryBodyStruct iqbs; memset(&iqbs, 0, sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); @@ -5685,117 +5901,85 @@ namespace RoF2 iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - iqbs.clairvoyance = item->Clairvoyance; + iqbs.Clairvoyance = item->Clairvoyance; //unknown18; //Power Source Capacity or evolve filename? //evolve_string; // Some String, but being evolution related is just a guess iqbs.Heirloom = 0; iqbs.Placeable = 0; - iqbs.unknown28 = -1; iqbs.unknown30 = -1; - iqbs.NoZone = 0; iqbs.NoGround = 0; iqbs.unknown37a = 0; // (guessed position) New to RoF2 iqbs.unknown38 = 0; - iqbs.unknown39 = 1; + + ob.write((const char*)&iqbs, sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); - iqbs.subitem_count = 0; + EQEmu::OutBuffer::pos_type count_pos = ob.tellp(); + uint32 subitem_count = 0; - char *SubSerializations[10]; // + ob.write((const char*)&subitem_count, sizeof(uint32)); - uint32 SubLengths[10]; + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; - for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; ++x) { + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; - SubSerializations[x] = nullptr; + ob.write((const char*)&index, sizeof(uint32)); - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); - - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EmuConstants::GENERAL_BEGIN && slot_id_in <= EmuConstants::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EmuConstants::BANK_BEGIN && slot_id_in <= EmuConstants::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EmuConstants::SHARED_BANK_BEGIN && slot_id_in <= EmuConstants::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::SHARED_BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1, packet_type); - } + SerializeItem(ob, sub, SubSlotNumber, (depth + 1), packet_type); + ++subitem_count; } - ss.write((const char*)&iqbs, sizeof(RoF2::structs::ItemQuaternaryBodyStruct)); - - for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; ++x) { - - if (SubSerializations[x]) { - - ss.write((const char*)&x, sizeof(uint32)); - - ss.write(SubSerializations[x], SubLengths[x]); - - safe_delete_array(SubSerializations[x]); - } - } - - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); - - *length = ss.tellp(); - return item_serial; + if (subitem_count) + ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32)); } - static inline structs::ItemSlotStruct ServerToRoF2Slot(uint32 serverSlot, ItemPacketType PacketType) + static inline structs::InventorySlot_Struct ServerToRoF2Slot(uint32 serverSlot, ItemPacketType PacketType) { - structs::ItemSlotStruct RoF2Slot; - RoF2Slot.SlotType = INVALID_INDEX; - RoF2Slot.Unknown02 = NOT_USED; - RoF2Slot.MainSlot = INVALID_INDEX; - RoF2Slot.SubSlot = INVALID_INDEX; - RoF2Slot.AugSlot = INVALID_INDEX; - RoF2Slot.Unknown01 = NOT_USED; + structs::InventorySlot_Struct RoF2Slot; + RoF2Slot.Type = INVALID_INDEX; + RoF2Slot.Unknown02 = 0; + RoF2Slot.Slot = INVALID_INDEX; + RoF2Slot.SubIndex = INVALID_INDEX; + RoF2Slot.AugIndex = INVALID_INDEX; + RoF2Slot.Unknown01 = 0; uint32 TempSlot = 0; - if (serverSlot < 56 || serverSlot == MainPowerSource) { // Main Inventory and Cursor + if (serverSlot < 56 || serverSlot == EQEmu::legacy::SlotPowerSource) { // Main Inventory and Cursor if (PacketType == ItemPacketLoot) { - RoF2Slot.SlotType = maps::MapCorpse; - RoF2Slot.MainSlot = serverSlot - EmuConstants::CORPSE_BEGIN; + RoF2Slot.Type = invtype::InvTypeCorpse; + RoF2Slot.Slot = serverSlot - EQEmu::legacy::CORPSE_BEGIN; } else { - RoF2Slot.SlotType = maps::MapPossessions; - RoF2Slot.MainSlot = serverSlot; + RoF2Slot.Type = invtype::InvTypePossessions; + RoF2Slot.Slot = serverSlot; } - - if (serverSlot == MainPowerSource) - RoF2Slot.MainSlot = slots::MainPowerSource; - else if (serverSlot >= MainCursor && PacketType != ItemPacketLoot) // Cursor and Extended Corpse Inventory - RoF2Slot.MainSlot += 3; + if (serverSlot == EQEmu::legacy::SlotPowerSource) + RoF2Slot.Slot = invslot::PossessionsPowerSource; - else if (serverSlot >= MainAmmo) // (> 20) - RoF2Slot.MainSlot += 1; + else if (serverSlot >= EQEmu::legacy::SlotCursor && PacketType != ItemPacketLoot) // Cursor and Extended Corpse Inventory + RoF2Slot.Slot += 3; + + else if (serverSlot >= EQEmu::legacy::SlotAmmo) // (> 20) + RoF2Slot.Slot += 1; } /*else if (ServerSlot < 51) { // Cursor Buffer @@ -5803,51 +5987,51 @@ namespace RoF2 RoF2Slot.MainSlot = ServerSlot - 31; }*/ - else if (serverSlot >= EmuConstants::GENERAL_BAGS_BEGIN && serverSlot <= EmuConstants::CURSOR_BAG_END) { // (> 250 && < 341) - RoF2Slot.SlotType = maps::MapPossessions; + else if (serverSlot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::legacy::CURSOR_BAG_END) { // (> 250 && < 341) + RoF2Slot.Type = invtype::InvTypePossessions; TempSlot = serverSlot - 1; - RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 2; - RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 2) * EmuConstants::ITEM_CONTAINER_SIZE); + RoF2Slot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 2; + RoF2Slot.SubIndex = TempSlot - ((RoF2Slot.Slot + 2) * EQEmu::legacy::ITEM_CONTAINER_SIZE); - if (RoF2Slot.MainSlot >= slots::MainGeneral9) // (> 30) - RoF2Slot.MainSlot = slots::MainCursor; + if (RoF2Slot.Slot >= invslot::PossessionsGeneral9) // (> 30) + RoF2Slot.Slot = invslot::PossessionsCursor; } - else if (serverSlot >= EmuConstants::TRIBUTE_BEGIN && serverSlot <= EmuConstants::TRIBUTE_END) { // Tribute - RoF2Slot.SlotType = maps::MapTribute; - RoF2Slot.MainSlot = serverSlot - EmuConstants::TRIBUTE_BEGIN; + else if (serverSlot >= EQEmu::legacy::TRIBUTE_BEGIN && serverSlot <= EQEmu::legacy::TRIBUTE_END) { // Tribute + RoF2Slot.Type = invtype::InvTypeTribute; + RoF2Slot.Slot = serverSlot - EQEmu::legacy::TRIBUTE_BEGIN; } - else if (serverSlot >= EmuConstants::BANK_BEGIN && serverSlot <= EmuConstants::BANK_BAGS_END) { - RoF2Slot.SlotType = maps::MapBank; - TempSlot = serverSlot - EmuConstants::BANK_BEGIN; - RoF2Slot.MainSlot = TempSlot; + else if (serverSlot >= EQEmu::legacy::BANK_BEGIN && serverSlot <= EQEmu::legacy::BANK_BAGS_END) { + RoF2Slot.Type = invtype::InvTypeBank; + TempSlot = serverSlot - EQEmu::legacy::BANK_BEGIN; + RoF2Slot.Slot = TempSlot; if (TempSlot > 30) { // (> 30) - RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 3; - RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE); + RoF2Slot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 3; + RoF2Slot.SubIndex = TempSlot - ((RoF2Slot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE); } } - else if (serverSlot >= EmuConstants::SHARED_BANK_BEGIN && serverSlot <= EmuConstants::SHARED_BANK_BAGS_END) { - RoF2Slot.SlotType = maps::MapSharedBank; - TempSlot = serverSlot - EmuConstants::SHARED_BANK_BEGIN; - RoF2Slot.MainSlot = TempSlot; + else if (serverSlot >= EQEmu::legacy::SHARED_BANK_BEGIN && serverSlot <= EQEmu::legacy::SHARED_BANK_BAGS_END) { + RoF2Slot.Type = invtype::InvTypeSharedBank; + TempSlot = serverSlot - EQEmu::legacy::SHARED_BANK_BEGIN; + RoF2Slot.Slot = TempSlot; if (TempSlot > 30) { // (> 30) - RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 3; - RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE); + RoF2Slot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 3; + RoF2Slot.SubIndex = TempSlot - ((RoF2Slot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE); } } - else if (serverSlot >= EmuConstants::TRADE_BEGIN && serverSlot <= EmuConstants::TRADE_BAGS_END) { - RoF2Slot.SlotType = maps::MapTrade; - TempSlot = serverSlot - EmuConstants::TRADE_BEGIN; - RoF2Slot.MainSlot = TempSlot; + else if (serverSlot >= EQEmu::legacy::TRADE_BEGIN && serverSlot <= EQEmu::legacy::TRADE_BAGS_END) { + RoF2Slot.Type = invtype::InvTypeTrade; + TempSlot = serverSlot - EQEmu::legacy::TRADE_BEGIN; + RoF2Slot.Slot = TempSlot; if (TempSlot > 30) { - RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 3; - RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE); + RoF2Slot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 3; + RoF2Slot.SubIndex = TempSlot - ((RoF2Slot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE); } /* @@ -5864,38 +6048,38 @@ namespace RoF2 */ } - else if (serverSlot >= EmuConstants::WORLD_BEGIN && serverSlot <= EmuConstants::WORLD_END) { - RoF2Slot.SlotType = maps::MapWorld; - TempSlot = serverSlot - EmuConstants::WORLD_BEGIN; - RoF2Slot.MainSlot = TempSlot; + else if (serverSlot >= EQEmu::legacy::WORLD_BEGIN && serverSlot <= EQEmu::legacy::WORLD_END) { + RoF2Slot.Type = invtype::InvTypeWorld; + TempSlot = serverSlot - EQEmu::legacy::WORLD_BEGIN; + RoF2Slot.Slot = TempSlot; } - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert Server Slot %i to RoF2 Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i", serverSlot, RoF2Slot.SlotType, RoF2Slot.Unknown02, RoF2Slot.MainSlot, RoF2Slot.SubSlot, RoF2Slot.AugSlot, RoF2Slot.Unknown01); + Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert Server Slot %i to RoF2 Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i", serverSlot, RoF2Slot.Type, RoF2Slot.Unknown02, RoF2Slot.Slot, RoF2Slot.SubIndex, RoF2Slot.AugIndex, RoF2Slot.Unknown01); return RoF2Slot; } - static inline structs::MainInvItemSlotStruct ServerToRoF2MainInvSlot(uint32 serverSlot) + static inline structs::TypelessInventorySlot_Struct ServerToRoF2TypelessSlot(uint32 serverSlot) { - structs::MainInvItemSlotStruct RoF2Slot; - RoF2Slot.MainSlot = INVALID_INDEX; - RoF2Slot.SubSlot = INVALID_INDEX; - RoF2Slot.AugSlot = INVALID_INDEX; - RoF2Slot.Unknown01 = NOT_USED; + structs::TypelessInventorySlot_Struct RoF2Slot; + RoF2Slot.Slot = INVALID_INDEX; + RoF2Slot.SubIndex = INVALID_INDEX; + RoF2Slot.AugIndex = INVALID_INDEX; + RoF2Slot.Unknown01 = 0; uint32 TempSlot = 0; - if (serverSlot < 56 || serverSlot == MainPowerSource) { // (< 52) - RoF2Slot.MainSlot = serverSlot; + if (serverSlot < 56 || serverSlot == EQEmu::legacy::SlotPowerSource) { // (< 52) + RoF2Slot.Slot = serverSlot; - if (serverSlot == MainPowerSource) - RoF2Slot.MainSlot = slots::MainPowerSource; + if (serverSlot == EQEmu::legacy::SlotPowerSource) + RoF2Slot.Slot = invslot::PossessionsPowerSource; - else if (serverSlot >= MainCursor) // Cursor and Extended Corpse Inventory - RoF2Slot.MainSlot += 3; + else if (serverSlot >= EQEmu::legacy::SlotCursor) // Cursor and Extended Corpse Inventory + RoF2Slot.Slot += 3; - else if (serverSlot >= MainAmmo) // Ammo and Personl Inventory - RoF2Slot.MainSlot += 1; + else if (serverSlot >= EQEmu::legacy::SlotAmmo) // Ammo and Personl Inventory + RoF2Slot.Slot += 1; /*else if (ServerSlot >= MainCursor) { // Cursor RoF2Slot.MainSlot = slots::MainCursor; @@ -5905,33 +6089,33 @@ namespace RoF2 }*/ } - else if (serverSlot >= EmuConstants::GENERAL_BAGS_BEGIN && serverSlot <= EmuConstants::CURSOR_BAG_END) { + else if (serverSlot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::legacy::CURSOR_BAG_END) { TempSlot = serverSlot - 1; - RoF2Slot.MainSlot = int(TempSlot / EmuConstants::ITEM_CONTAINER_SIZE) - 2; - RoF2Slot.SubSlot = TempSlot - ((RoF2Slot.MainSlot + 2) * EmuConstants::ITEM_CONTAINER_SIZE); + RoF2Slot.Slot = int(TempSlot / EQEmu::legacy::ITEM_CONTAINER_SIZE) - 2; + RoF2Slot.SubIndex = TempSlot - ((RoF2Slot.Slot + 2) * EQEmu::legacy::ITEM_CONTAINER_SIZE); } - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert Server Slot %i to RoF2 Slots: Main %i, Sub %i, Aug %i, Unk1 %i", serverSlot, RoF2Slot.MainSlot, RoF2Slot.SubSlot, RoF2Slot.AugSlot, RoF2Slot.Unknown01); + Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert Server Slot %i to RoF2 Slots: Main %i, Sub %i, Aug %i, Unk1 %i", serverSlot, RoF2Slot.Slot, RoF2Slot.SubIndex, RoF2Slot.AugIndex, RoF2Slot.Unknown01); return RoF2Slot; } static inline uint32 ServerToRoF2CorpseSlot(uint32 serverCorpseSlot) { - return (serverCorpseSlot - EmuConstants::CORPSE_BEGIN + 1); + return (serverCorpseSlot - EQEmu::legacy::CORPSE_BEGIN + 1); } - static inline uint32 RoF2ToServerSlot(structs::ItemSlotStruct rof2Slot, ItemPacketType PacketType) + static inline uint32 RoF2ToServerSlot(structs::InventorySlot_Struct rof2Slot, ItemPacketType PacketType) { uint32 ServerSlot = INVALID_INDEX; uint32 TempSlot = 0; - if (rof2Slot.SlotType == maps::MapPossessions && rof2Slot.MainSlot < 57) { // Worn/Personal Inventory and Cursor (< 51) - if (rof2Slot.MainSlot == slots::MainPowerSource) - TempSlot = MainPowerSource; + if (rof2Slot.Type == invtype::InvTypePossessions && rof2Slot.Slot < 57) { // Worn/Personal Inventory and Cursor (< 51) + if (rof2Slot.Slot == invslot::PossessionsPowerSource) + TempSlot = EQEmu::legacy::SlotPowerSource; - else if (rof2Slot.MainSlot >= slots::MainCursor) // Cursor and Extended Corpse Inventory - TempSlot = rof2Slot.MainSlot - 3; + else if (rof2Slot.Slot >= invslot::PossessionsCursor) // Cursor and Extended Corpse Inventory + TempSlot = rof2Slot.Slot - 3; /*else if (RoF2Slot.MainSlot == slots::MainGeneral9 || RoF2Slot.MainSlot == slots::MainGeneral10) { // 9th and 10th RoF2 inventory/corpse slots // Need to figure out what to do when we get these @@ -5944,61 +6128,61 @@ namespace RoF2 // For now, it's probably best to leave as-is and let this work itself out in the inventory rework. }*/ - else if (rof2Slot.MainSlot >= slots::MainAmmo) // Ammo and Main Inventory - TempSlot = rof2Slot.MainSlot - 1; + else if (rof2Slot.Slot >= invslot::PossessionsAmmo) // Ammo and Main Inventory + TempSlot = rof2Slot.Slot - 1; else // Worn Slots - TempSlot = rof2Slot.MainSlot; + TempSlot = rof2Slot.Slot; - if (rof2Slot.SubSlot >= SUB_BEGIN) // Bag Slots - TempSlot = ((TempSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rof2Slot.SubSlot + 1; + if (rof2Slot.SubIndex >= SUB_INDEX_BEGIN) // Bag Slots + TempSlot = ((TempSlot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rof2Slot.SubIndex + 1; ServerSlot = TempSlot; } - else if (rof2Slot.SlotType == maps::MapBank) { - TempSlot = EmuConstants::BANK_BEGIN; + else if (rof2Slot.Type == invtype::InvTypeBank) { + TempSlot = EQEmu::legacy::BANK_BEGIN; - if (rof2Slot.SubSlot >= SUB_BEGIN) - TempSlot += ((rof2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rof2Slot.SubSlot + 1; + if (rof2Slot.SubIndex >= SUB_INDEX_BEGIN) + TempSlot += ((rof2Slot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rof2Slot.SubIndex + 1; else - TempSlot += rof2Slot.MainSlot; + TempSlot += rof2Slot.Slot; ServerSlot = TempSlot; } - else if (rof2Slot.SlotType == maps::MapSharedBank) { - TempSlot = EmuConstants::SHARED_BANK_BEGIN; + else if (rof2Slot.Type == invtype::InvTypeSharedBank) { + TempSlot = EQEmu::legacy::SHARED_BANK_BEGIN; - if (rof2Slot.SubSlot >= SUB_BEGIN) - TempSlot += ((rof2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rof2Slot.SubSlot + 1; + if (rof2Slot.SubIndex >= SUB_INDEX_BEGIN) + TempSlot += ((rof2Slot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rof2Slot.SubIndex + 1; else - TempSlot += rof2Slot.MainSlot; + TempSlot += rof2Slot.Slot; ServerSlot = TempSlot; } - else if (rof2Slot.SlotType == maps::MapTrade) { - TempSlot = EmuConstants::TRADE_BEGIN; + else if (rof2Slot.Type == invtype::InvTypeTrade) { + TempSlot = EQEmu::legacy::TRADE_BEGIN; - if (rof2Slot.SubSlot >= SUB_BEGIN) - TempSlot += ((rof2Slot.MainSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rof2Slot.SubSlot + 1; + if (rof2Slot.SubIndex >= SUB_INDEX_BEGIN) + TempSlot += ((rof2Slot.Slot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rof2Slot.SubIndex + 1; // OLD CODE: //TempSlot += 100 + (RoF2Slot.MainSlot * EmuConstants::ITEM_CONTAINER_SIZE) + RoF2Slot.SubSlot; else - TempSlot += rof2Slot.MainSlot; + TempSlot += rof2Slot.Slot; ServerSlot = TempSlot; } - else if (rof2Slot.SlotType == maps::MapWorld) { - TempSlot = EmuConstants::WORLD_BEGIN; + else if (rof2Slot.Type == invtype::InvTypeWorld) { + TempSlot = EQEmu::legacy::WORLD_BEGIN; - if (rof2Slot.MainSlot >= SUB_BEGIN) - TempSlot += rof2Slot.MainSlot; + if (rof2Slot.Slot >= SUB_INDEX_BEGIN) + TempSlot += rof2Slot.Slot; ServerSlot = TempSlot; } @@ -6012,30 +6196,30 @@ namespace RoF2 ServerSlot = TempSlot; }*/ - else if (rof2Slot.SlotType == maps::MapGuildTribute) { + else if (rof2Slot.Type == invtype::InvTypeGuildTribute) { ServerSlot = INVALID_INDEX; } - else if (rof2Slot.SlotType == maps::MapCorpse) { - ServerSlot = rof2Slot.MainSlot + EmuConstants::CORPSE_BEGIN; + else if (rof2Slot.Type == invtype::InvTypeCorpse) { + ServerSlot = rof2Slot.Slot + EQEmu::legacy::CORPSE_BEGIN; } - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert RoF2 Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", rof2Slot.SlotType, rof2Slot.Unknown02, rof2Slot.MainSlot, rof2Slot.SubSlot, rof2Slot.AugSlot, rof2Slot.Unknown01, ServerSlot); + Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert RoF2 Slots: Type %i, Unk2 %i, Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", rof2Slot.Type, rof2Slot.Unknown02, rof2Slot.Slot, rof2Slot.SubIndex, rof2Slot.AugIndex, rof2Slot.Unknown01, ServerSlot); return ServerSlot; } - static inline uint32 RoF2ToServerMainInvSlot(structs::MainInvItemSlotStruct rof2Slot) + static inline uint32 RoF2ToServerTypelessSlot(structs::TypelessInventorySlot_Struct rof2Slot) { uint32 ServerSlot = INVALID_INDEX; uint32 TempSlot = 0; - if (rof2Slot.MainSlot < 57) { // Worn/Personal Inventory and Cursor (< 33) - if (rof2Slot.MainSlot == slots::MainPowerSource) - TempSlot = MainPowerSource; + if (rof2Slot.Slot < 57) { // Worn/Personal Inventory and Cursor (< 33) + if (rof2Slot.Slot == invslot::PossessionsPowerSource) + TempSlot = EQEmu::legacy::SlotPowerSource; - else if (rof2Slot.MainSlot >= slots::MainCursor) // Cursor and Extended Corpse Inventory - TempSlot = rof2Slot.MainSlot - 3; + else if (rof2Slot.Slot >= invslot::PossessionsCursor) // Cursor and Extended Corpse Inventory + TempSlot = rof2Slot.Slot - 3; /*else if (RoF2Slot.MainSlot == slots::MainGeneral9 || RoF2Slot.MainSlot == slots::MainGeneral10) { // 9th and 10th RoF2 inventory slots // Need to figure out what to do when we get these @@ -6043,31 +6227,31 @@ namespace RoF2 // Same as above }*/ - else if (rof2Slot.MainSlot >= slots::MainAmmo) // Main Inventory and Ammo Slots - TempSlot = rof2Slot.MainSlot - 1; + else if (rof2Slot.Slot >= invslot::PossessionsAmmo) // Main Inventory and Ammo Slots + TempSlot = rof2Slot.Slot - 1; else - TempSlot = rof2Slot.MainSlot; + TempSlot = rof2Slot.Slot; - if (rof2Slot.SubSlot >= SUB_BEGIN) // Bag Slots - TempSlot = ((TempSlot + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + rof2Slot.SubSlot + 1; + if (rof2Slot.SubIndex >= SUB_INDEX_BEGIN) // Bag Slots + TempSlot = ((TempSlot + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + rof2Slot.SubIndex + 1; ServerSlot = TempSlot; } - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert RoF2 Slots: Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", rof2Slot.MainSlot, rof2Slot.SubSlot, rof2Slot.AugSlot, rof2Slot.Unknown01, ServerSlot); + Log.Out(Logs::General, Logs::Netcode, "[ERROR] Convert RoF2 Slots: Main %i, Sub %i, Aug %i, Unk1 %i to Server Slot %i", rof2Slot.Slot, rof2Slot.SubIndex, rof2Slot.AugIndex, rof2Slot.Unknown01, ServerSlot); return ServerSlot; } static inline uint32 RoF2ToServerCorpseSlot(uint32 rof2CorpseSlot) { - return (rof2CorpseSlot + EmuConstants::CORPSE_BEGIN - 1); + return (rof2CorpseSlot + EQEmu::legacy::CORPSE_BEGIN - 1); } static inline void ServerToRoF2TextLink(std::string& rof2TextLink, const std::string& serverTextLink) { - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { + if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { rof2TextLink = serverTextLink; return; } @@ -6076,7 +6260,7 @@ namespace RoF2 for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { rof2TextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -6099,7 +6283,7 @@ namespace RoF2 static inline void RoF2ToServerTextLink(std::string& serverTextLink, const std::string& rof2TextLink) { - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (rof2TextLink.find('\x12') == std::string::npos)) { + if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (rof2TextLink.find('\x12') == std::string::npos)) { serverTextLink = rof2TextLink; return; } @@ -6108,7 +6292,7 @@ namespace RoF2 for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= constants::SayLinkBodySize) { serverTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -6128,5 +6312,81 @@ namespace RoF2 } } } -} -// end namespace RoF2 + + static inline CastingSlot ServerToRoF2CastingSlot(EQEmu::CastingSlot slot) + { + switch (slot) { + case EQEmu::CastingSlot::Gem1: + return CastingSlot::Gem1; + case EQEmu::CastingSlot::Gem2: + return CastingSlot::Gem2; + case EQEmu::CastingSlot::Gem3: + return CastingSlot::Gem3; + case EQEmu::CastingSlot::Gem4: + return CastingSlot::Gem4; + case EQEmu::CastingSlot::Gem5: + return CastingSlot::Gem5; + case EQEmu::CastingSlot::Gem6: + return CastingSlot::Gem6; + case EQEmu::CastingSlot::Gem7: + return CastingSlot::Gem7; + case EQEmu::CastingSlot::Gem8: + return CastingSlot::Gem8; + case EQEmu::CastingSlot::Gem9: + return CastingSlot::Gem9; + case EQEmu::CastingSlot::Gem10: + return CastingSlot::Gem10; + case EQEmu::CastingSlot::Gem11: + return CastingSlot::Gem11; + case EQEmu::CastingSlot::Gem12: + return CastingSlot::Gem12; + case EQEmu::CastingSlot::Item: + case EQEmu::CastingSlot::PotionBelt: + return CastingSlot::Item; + case EQEmu::CastingSlot::Discipline: + return CastingSlot::Discipline; + case EQEmu::CastingSlot::AltAbility: + return CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return CastingSlot::Discipline; + } + } + + static inline EQEmu::CastingSlot RoF2ToServerCastingSlot(CastingSlot slot) + { + switch (slot) { + case CastingSlot::Gem1: + return EQEmu::CastingSlot::Gem1; + case CastingSlot::Gem2: + return EQEmu::CastingSlot::Gem2; + case CastingSlot::Gem3: + return EQEmu::CastingSlot::Gem3; + case CastingSlot::Gem4: + return EQEmu::CastingSlot::Gem4; + case CastingSlot::Gem5: + return EQEmu::CastingSlot::Gem5; + case CastingSlot::Gem6: + return EQEmu::CastingSlot::Gem6; + case CastingSlot::Gem7: + return EQEmu::CastingSlot::Gem7; + case CastingSlot::Gem8: + return EQEmu::CastingSlot::Gem8; + case CastingSlot::Gem9: + return EQEmu::CastingSlot::Gem9; + case CastingSlot::Gem10: + return EQEmu::CastingSlot::Gem10; + case CastingSlot::Gem11: + return EQEmu::CastingSlot::Gem11; + case CastingSlot::Gem12: + return EQEmu::CastingSlot::Gem12; + case CastingSlot::Discipline: + return EQEmu::CastingSlot::Discipline; + case CastingSlot::Item: + return EQEmu::CastingSlot::Item; + case CastingSlot::AltAbility: + return EQEmu::CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return EQEmu::CastingSlot::Discipline; + } + } +} /*RoF2*/ diff --git a/common/patches/rof2.h b/common/patches/rof2.h index 8644473db..4fb94a1d4 100644 --- a/common/patches/rof2.h +++ b/common/patches/rof2.h @@ -1,11 +1,31 @@ -#ifndef ROF2_H_ -#define ROF2_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_ROF2_H +#define COMMON_ROF2_H #include "../struct_strategy.h" class EQStreamIdentifier; -namespace RoF2 { +namespace RoF2 +{ //these are the only public member of this namespace. extern void Register(EQStreamIdentifier &into); @@ -23,13 +43,31 @@ namespace RoF2 { protected: virtual std::string Describe() const; - virtual const ClientVersion GetClientVersion() const; + virtual const EQEmu::versions::ClientVersion ClientVersion() const; //magic macro to declare our opcode processors #include "ss_declare.h" #include "rof2_ops.h" }; -}; + enum class CastingSlot : uint32 { + Gem1 = 0, + Gem2 = 1, + Gem3 = 2, + Gem4 = 3, + Gem5 = 4, + Gem6 = 5, + Gem7 = 6, + Gem8 = 7, + Gem9 = 8, + Gem10 = 9, + Gem11 = 10, + Gem12 = 11, + Item = 12, + Discipline = 13, + AltAbility = 0xFF + }; -#endif /*ROF2_H_*/ +}; /*RoF2*/ + +#endif /*COMMON_ROF2_H*/ diff --git a/common/patches/rof2_constants.h b/common/patches/rof2_constants.h deleted file mode 100644 index 4c8245737..000000000 --- a/common/patches/rof2_constants.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -EQEMu: Everquest Server Emulator - -Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY except by those people which sell it, which -are required to give you total support for your newly bought product; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef ROF2_CONSTANTS_H_ -#define ROF2_CONSTANTS_H_ - -#include "../types.h" - -namespace RoF2 { - namespace maps { - typedef enum : int16 { - MapPossessions = 0, - MapBank, - MapSharedBank, - MapTrade, - MapWorld, - MapLimbo, - MapTribute, - MapTrophyTribute, - MapGuildTribute, - MapMerchant, - MapDeleted, - MapCorpse, - MapBazaar, - MapInspect, - MapRealEstate, - MapViewMODPC, - MapViewMODBank, - MapViewMODSharedBank, - MapViewMODLimbo, - MapAltStorage, - MapArchived, - MapMail, - MapGuildTrophyTribute, - MapKrono, - MapOther, - _MapCount - } InventoryMaps; - } - - namespace slots { - typedef enum : int16 { - MainCharm = 0, - MainEar1, - MainHead, - MainFace, - MainEar2, - MainNeck, - MainShoulders, - MainArms, - MainBack, - MainWrist1, - MainWrist2, - MainRange, - MainHands, - MainPrimary, - MainSecondary, - MainFinger1, - MainFinger2, - MainChest, - MainLegs, - MainFeet, - MainWaist, - MainPowerSource, - MainAmmo, - MainGeneral1, - MainGeneral2, - MainGeneral3, - MainGeneral4, - MainGeneral5, - MainGeneral6, - MainGeneral7, - MainGeneral8, - MainGeneral9, - MainGeneral10, - MainCursor, - _MainCount, - _MainEquipmentBegin = MainCharm, - _MainEquipmentEnd = MainAmmo, - _MainEquipmentCount = (_MainEquipmentEnd - _MainEquipmentBegin + 1), - _MainGeneralBegin = MainGeneral1, - _MainGeneralEnd = MainGeneral10, - _MainGeneralCount = (_MainGeneralEnd - _MainGeneralBegin + 1) - } EquipmentSlots; - } - - namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 12; - - static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; - static const uint16 MAP_BANK_SIZE = 24; - static const uint16 MAP_SHARED_BANK_SIZE = 2; - static const uint16 MAP_TRADE_SIZE = 8; - static const uint16 MAP_WORLD_SIZE = 10; - static const uint16 MAP_LIMBO_SIZE = 36; - static const uint16 MAP_TRIBUTE_SIZE = 0; //? - static const uint16 MAP_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_GUILD_TRIBUTE_SIZE = 0; - static const uint16 MAP_MERCHANT_SIZE = 0; - static const uint16 MAP_DELETED_SIZE = 0; - static const uint16 MAP_CORPSE_SIZE = slots::_MainCount; - static const uint16 MAP_BAZAAR_SIZE = 200; - static const uint16 MAP_INSPECT_SIZE = slots::_MainEquipmentCount; - static const uint16 MAP_REAL_ESTATE_SIZE = 0; - static const uint16 MAP_VIEW_MOD_PC_SIZE = MAP_POSSESSIONS_SIZE; - static const uint16 MAP_VIEW_MOD_BANK_SIZE = MAP_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_SHARED_BANK_SIZE = MAP_SHARED_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_LIMBO_SIZE = MAP_LIMBO_SIZE; - static const uint16 MAP_ALT_STORAGE_SIZE = 0; - static const uint16 MAP_ARCHIVED_SIZE = 0; - static const uint16 MAP_MAIL_SIZE = 0; - static const uint16 MAP_GUILD_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_KRONO_SIZE = NOT_USED; - static const uint16 MAP_OTHER_SIZE = 0; - - // most of these definitions will go away with the structure-based system..this maintains compatibility for now - // (bag slots and main slots beyond Possessions are assigned for compatibility with current server coding) - static const int16 EQUIPMENT_BEGIN = slots::MainCharm; - static const int16 EQUIPMENT_END = slots::MainAmmo; - static const uint16 EQUIPMENT_SIZE = slots::_MainEquipmentCount; - - static const int16 GENERAL_BEGIN = slots::MainGeneral1; - static const int16 GENERAL_END = slots::MainGeneral10; - static const uint16 GENERAL_SIZE = slots::_MainGeneralCount; - static const int16 GENERAL_BAGS_BEGIN = 251; - static const int16 GENERAL_BAGS_END_OFFSET = 99; - static const int16 GENERAL_BAGS_END = GENERAL_BAGS_BEGIN + GENERAL_BAGS_END_OFFSET; - - static const int16 CURSOR = slots::MainCursor; - static const int16 CURSOR_BAG_BEGIN = 351; - static const int16 CURSOR_BAG_END_OFFSET = 9; - static const int16 CURSOR_BAG_END = CURSOR_BAG_BEGIN + CURSOR_BAG_END_OFFSET; - - static const int16 BANK_BEGIN = 2000; - static const int16 BANK_END = 2023; - static const int16 BANK_BAGS_BEGIN = 2031; - static const int16 BANK_BAGS_END_OFFSET = 239; - static const int16 BANK_BAGS_END = BANK_BAGS_BEGIN + BANK_BAGS_END_OFFSET; - - static const int16 SHARED_BANK_BEGIN = 2500; - static const int16 SHARED_BANK_END = 2501; - static const int16 SHARED_BANK_BAGS_BEGIN = 2531; - static const int16 SHARED_BANK_BAGS_END_OFFSET = 19; - static const int16 SHARED_BANK_BAGS_END = SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_END_OFFSET; - - static const int16 TRADE_BEGIN = 3000; - static const int16 TRADE_END = 3007; - static const int16 TRADE_NPC_END = 3003; - static const int16 TRADE_BAGS_BEGIN = 3031; - static const int16 TRADE_BAGS_END_OFFSET = 79; - static const int16 TRADE_BAGS_END = TRADE_BAGS_BEGIN + TRADE_BAGS_END_OFFSET; - - static const int16 WORLD_BEGIN = 4000; - static const int16 WORLD_END = 4009; - - static const int16 TRIBUTE_BEGIN = 400; - static const int16 TRIBUTE_END = 404; - - static const int16 CORPSE_BEGIN = slots::MainGeneral1; - static const int16 CORPSE_END = slots::MainGeneral1 + slots::MainCursor; - - static const uint16 ITEM_COMMON_SIZE = 6; - static const uint16 ITEM_CONTAINER_SIZE = 255; // 255; (server max will be 255..unsure what actual client is - test) - - static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances - static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance - - static const size_t POTION_BELT_ITEM_COUNT = 5; - - static const size_t TEXT_LINK_BODY_LENGTH = 56; - } - - namespace limits { - static const bool ALLOWS_EMPTY_BAG_IN_BAG = true; - static const bool ALLOWS_CLICK_CAST_FROM_BAG = true; - static const bool COIN_HAS_WEIGHT = false; - } - -}; //end namespace RoF2 - -#endif /*ROF2_CONSTANTS_H_*/ - -/* -RoF2 Notes: - ** Structure-based inventory ** -ok Possessions: ( 0, { 0 .. 33 }, -1, -1 ) (Corpse: { 23 .. 56 } [Offset 23]) -ok [Equipment: ( 0, { 0 .. 22 }, -1, -1 )] -ok [General: ( 0, { 23 .. 32 }, -1, -1 )] -ok [Cursor: ( 0, 33, -1, -1 )] - General Bags: ( 0, { 23 .. 32 }, { 0 .. (maxsize - 1) }, -1 ) - Cursor Bags: ( 0, 33, { 0 .. (maxsize - 1) }, -1 ) - - Bank: ( 1, { 0 .. 23 }, -1, -1 ) - Bank Bags: ( 1, { 0 .. 23 }, { 0 .. (maxsize - 1)}, -1 ) - - Shared Bank: ( 2, { 0 .. 1 }, -1, -1 ) - Shared Bank Bags: ( 2, { 0 .. 1 }, { 0 .. (maxsize - 1) }, -1 ) - - Trade: ( 3, { 0 .. 8 }, -1, -1 ) - (Trade Bags: 3031 - 3110 -- server values) - - World: ( 4, { 0 .. 10 }, -1, -1 ) - -*/ diff --git a/common/patches/rof2_limits.cpp b/common/patches/rof2_limits.cpp new file mode 100644 index 000000000..85e15e21d --- /dev/null +++ b/common/patches/rof2_limits.cpp @@ -0,0 +1,284 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "rof2_limits.h" + +#include "../string_util.h" + + +size_t RoF2::invtype::GetInvTypeSize(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + return invtype::InvTypePossessionsSize; + case invtype::InvTypeBank: + return invtype::InvTypeBankSize; + case invtype::InvTypeSharedBank: + return invtype::InvTypeSharedBankSize; + case invtype::InvTypeTrade: + return invtype::InvTypeTradeSize; + case invtype::InvTypeWorld: + return invtype::InvTypeWorldSize; + case invtype::InvTypeLimbo: + return invtype::InvTypeLimboSize; + case invtype::InvTypeTribute: + return invtype::InvTypeTributeSize; + case invtype::InvTypeTrophyTribute: + return invtype::InvTypeTrophyTributeSize; + case invtype::InvTypeGuildTribute: + return invtype::InvTypeGuildTributeSize; + case invtype::InvTypeMerchant: + return invtype::InvTypeMerchantSize; + case invtype::InvTypeDeleted: + return invtype::InvTypeDeletedSize; + case invtype::InvTypeCorpse: + return invtype::InvTypeCorpseSize; + case invtype::InvTypeBazaar: + return invtype::InvTypeBazaarSize; + case invtype::InvTypeInspect: + return invtype::InvTypeInspectSize; + case invtype::InvTypeRealEstate: + return invtype::InvTypeRealEstateSize; + case invtype::InvTypeViewMODPC: + return invtype::InvTypeViewMODPCSize; + case invtype::InvTypeViewMODBank: + return invtype::InvTypeViewMODBankSize; + case invtype::InvTypeViewMODSharedBank: + return invtype::InvTypeViewMODSharedBankSize; + case invtype::InvTypeViewMODLimbo: + return invtype::InvTypeViewMODLimboSize; + case invtype::InvTypeAltStorage: + return invtype::InvTypeAltStorageSize; + case invtype::InvTypeArchived: + return invtype::InvTypeArchivedSize; + case invtype::InvTypeMail: + return invtype::InvTypeMailSize; + case invtype::InvTypeGuildTrophyTribute: + return invtype::InvTypeGuildTrophyTributeSize; + case invtype::InvTypeKrono: + return invtype::InvTypeKronoSize; + case invtype::InvTypeOther: + return invtype::InvTypeOtherSize; + default: + return 0; + } +} + +const char* RoF2::invtype::GetInvTypeName(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypeInvalid: + return "Invalid Type"; + case invtype::InvTypePossessions: + return "Possessions"; + case invtype::InvTypeBank: + return "Bank"; + case invtype::InvTypeSharedBank: + return "Shared Bank"; + case invtype::InvTypeTrade: + return "Trade"; + case invtype::InvTypeWorld: + return "World"; + case invtype::InvTypeLimbo: + return "Limbo"; + case invtype::InvTypeTribute: + return "Tribute"; + case invtype::InvTypeTrophyTribute: + return "Trophy Tribute"; + case invtype::InvTypeGuildTribute: + return "Guild Tribute"; + case invtype::InvTypeMerchant: + return "Merchant"; + case invtype::InvTypeDeleted: + return "Deleted"; + case invtype::InvTypeCorpse: + return "Corpse"; + case invtype::InvTypeBazaar: + return "Bazaar"; + case invtype::InvTypeInspect: + return "Inspect"; + case invtype::InvTypeRealEstate: + return "Real Estate"; + case invtype::InvTypeViewMODPC: + return "View MOD PC"; + case invtype::InvTypeViewMODBank: + return "View MOD Bank"; + case invtype::InvTypeViewMODSharedBank: + return "View MOD Shared Bank"; + case invtype::InvTypeViewMODLimbo: + return "View MOD Limbo"; + case invtype::InvTypeAltStorage: + return "Alt Storage"; + case invtype::InvTypeArchived: + return "Archived"; + case invtype::InvTypeMail: + return "Mail"; + case invtype::InvTypeGuildTrophyTribute: + return "Guild Trophy Tribute"; + case invtype::InvTypeKrono: + return "Krono"; + case invtype::InvTypeOther: + return "Other"; + default: + return "Unknown Type"; + } +} + +bool RoF2::invtype::IsInvTypePersistent(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + case invtype::InvTypeBank: + case invtype::InvTypeSharedBank: + case invtype::InvTypeTrade: + case invtype::InvTypeWorld: + case invtype::InvTypeLimbo: + case invtype::InvTypeTribute: + case invtype::InvTypeTrophyTribute: + case invtype::InvTypeGuildTribute: + return true; + default: + return false; + } +} + +const char* RoF2::invslot::GetInvPossessionsSlotName(int inv_slot) +{ + switch (inv_slot) { + case invslot::InvSlotInvalid: + return "Invalid Slot"; + case invslot::PossessionsCharm: + return "Charm"; + case invslot::PossessionsEar1: + return "Ear 1"; + case invslot::PossessionsHead: + return "Head"; + case invslot::PossessionsFace: + return "Face"; + case invslot::PossessionsEar2: + return "Ear 2"; + case invslot::PossessionsNeck: + return "Neck"; + case invslot::PossessionsShoulders: + return "Shoulders"; + case invslot::PossessionsArms: + return "Arms"; + case invslot::PossessionsBack: + return "Back"; + case invslot::PossessionsWrist1: + return "Wrist 1"; + case invslot::PossessionsWrist2: + return "Wrist 2"; + case invslot::PossessionsRange: + return "Range"; + case invslot::PossessionsHands: + return "Hands"; + case invslot::PossessionsPrimary: + return "Primary"; + case invslot::PossessionsSecondary: + return "Secondary"; + case invslot::PossessionsFinger1: + return "Finger 1"; + case invslot::PossessionsFinger2: + return "Finger 2"; + case invslot::PossessionsChest: + return "Chest"; + case invslot::PossessionsLegs: + return "Legs"; + case invslot::PossessionsFeet: + return "Feet"; + case invslot::PossessionsWaist: + return "Waist"; + case invslot::PossessionsPowerSource: + return "Power Source"; + case invslot::PossessionsAmmo: + return "Ammo"; + case invslot::PossessionsGeneral1: + return "General 1"; + case invslot::PossessionsGeneral2: + return "General 2"; + case invslot::PossessionsGeneral3: + return "General 3"; + case invslot::PossessionsGeneral4: + return "General 4"; + case invslot::PossessionsGeneral5: + return "General 5"; + case invslot::PossessionsGeneral6: + return "General 6"; + case invslot::PossessionsGeneral7: + return "General 7"; + case invslot::PossessionsGeneral8: + return "General 8"; + case invslot::PossessionsGeneral9: + return "General 9"; + case invslot::PossessionsGeneral10: + return "General 10"; + case invslot::PossessionsCursor: + return "Cursor"; + default: + return "Unknown Slot"; + } +} + +const char* RoF2::invslot::GetInvSlotName(int inv_type, int inv_slot) +{ + if (inv_type == invtype::InvTypePossessions) + return invslot::GetInvPossessionsSlotName(inv_slot); + + size_t type_size = invtype::GetInvTypeSize(inv_type); + + if (!type_size || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + if ((size_t)(inv_slot + 1) >= type_size) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* RoF2::invbag::GetInvBagIndexName(int bag_index) +{ + if (bag_index == invbag::InvBagInvalid) + return "Invalid Bag"; + + if ((size_t)bag_index >= invbag::ItemBagSize) + return "Unknown Bag"; + + static std::string ret_str; + ret_str = StringFormat("Bag %i", (bag_index + 1)); + + return ret_str.c_str(); +} + +const char* RoF2::invaug::GetInvAugIndexName(int aug_index) +{ + if (aug_index == invaug::InvAugInvalid) + return "Invalid Augment"; + + if ((size_t)aug_index >= invaug::ItemAugSize) + return "Unknown Augment"; + + static std::string ret_str; + ret_str = StringFormat("Augment %i", (aug_index + 1)); + + return ret_str.c_str(); +} diff --git a/common/patches/rof2_limits.h b/common/patches/rof2_limits.h new file mode 100644 index 000000000..fb2f997ca --- /dev/null +++ b/common/patches/rof2_limits.h @@ -0,0 +1,294 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_ROF2_LIMITS_H +#define COMMON_ROF2_LIMITS_H + +#include "../types.h" +#include "../emu_versions.h" +#include "../skills.h" + + +namespace RoF2 +{ + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + // pre-declarations + namespace inventory { + inline EQEmu::versions::ClientVersion GetInventoryRef() { return EQEmu::versions::ClientVersion::RoF2; } + + } /*inventory*/ + + namespace invtype { + inline EQEmu::versions::ClientVersion GetInvTypeRef() { return EQEmu::versions::ClientVersion::RoF2; } + + enum : int { InvTypeInvalid = -1, InvTypeBegin }; + + enum InventoryType : int { + InvTypePossessions = InvTypeBegin, + InvTypeBank, + InvTypeSharedBank, + InvTypeTrade, + InvTypeWorld, + InvTypeLimbo, + InvTypeTribute, + InvTypeTrophyTribute, + InvTypeGuildTribute, + InvTypeMerchant, + InvTypeDeleted, + InvTypeCorpse, + InvTypeBazaar, + InvTypeInspect, + InvTypeRealEstate, + InvTypeViewMODPC, + InvTypeViewMODBank, + InvTypeViewMODSharedBank, + InvTypeViewMODLimbo, + InvTypeAltStorage, + InvTypeArchived, + InvTypeMail, + InvTypeGuildTrophyTribute, + InvTypeKrono, + InvTypeOther, + InvTypeCount + }; + + } /*invtype*/ + + namespace invslot { + inline EQEmu::versions::ClientVersion GetInvSlotRef() { return EQEmu::versions::ClientVersion::RoF2; } + + enum : int { InvSlotInvalid = -1, InvSlotBegin }; + + enum PossessionsSlot : int { + PossessionsCharm = InvSlotBegin, + PossessionsEar1, + PossessionsHead, + PossessionsFace, + PossessionsEar2, + PossessionsNeck, + PossessionsShoulders, + PossessionsArms, + PossessionsBack, + PossessionsWrist1, + PossessionsWrist2, + PossessionsRange, + PossessionsHands, + PossessionsPrimary, + PossessionsSecondary, + PossessionsFinger1, + PossessionsFinger2, + PossessionsChest, + PossessionsLegs, + PossessionsFeet, + PossessionsWaist, + PossessionsPowerSource, + PossessionsAmmo, + PossessionsGeneral1, + PossessionsGeneral2, + PossessionsGeneral3, + PossessionsGeneral4, + PossessionsGeneral5, + PossessionsGeneral6, + PossessionsGeneral7, + PossessionsGeneral8, + PossessionsGeneral9, + PossessionsGeneral10, + PossessionsCursor, + PossessionsCount + }; + + const int EquipmentBegin = PossessionsCharm; + const int EquipmentEnd = PossessionsAmmo; + const int EquipmentCount = (EquipmentEnd - EquipmentBegin + 1); + + const int GeneralBegin = PossessionsGeneral1; + const int GeneralEnd = PossessionsGeneral10; + const int GeneralCount = (GeneralEnd - GeneralBegin + 1); + + } /*invslot*/ + + namespace invbag { + inline EQEmu::versions::ClientVersion GetInvBagRef() { return EQEmu::versions::ClientVersion::RoF2; } + + enum : int { InvBagInvalid = -1, InvBagBegin }; + + } /*invbag*/ + + namespace invaug { + inline EQEmu::versions::ClientVersion GetInvAugRef() { return EQEmu::versions::ClientVersion::RoF2; } + + enum : int { InvAugInvalid = -1, InvAugBegin }; + + } /*invaug*/ + + namespace item { + inline EQEmu::versions::ClientVersion GetItemRef() { return EQEmu::versions::ClientVersion::RoF2; } + + //enum Unknown : int { // looks like item class..but, RoF has it too - nothing in UF- + // Unknown1 = 0, + // Unknown2 = 1, + // Unknown3 = 2, + // Unknown4 = 5 // krono? + //}; + + enum ItemPacketType : int { + ItemPacketMerchant = 100, + ItemPacketTradeView = 101, + ItemPacketLoot = 102, + ItemPacketTrade = 103, + ItemPacketCharInventory = 105, + ItemPacketLimbo = 106, + ItemPacketWorldContainer = 107, + ItemPacketTributeItem = 108, + ItemPacketGuildTribute = 109, + ItemPacket10 = 110, + ItemPacket11 = 111, + ItemPacket12 = 112, + ItemPacketRecovery = 113, + ItemPacket14 = 115 + }; + + } /*item*/ + + namespace profile { + inline EQEmu::versions::ClientVersion GetProfileRef() { return EQEmu::versions::ClientVersion::RoF2; } + + } /*profile*/ + + namespace constants { + inline EQEmu::versions::ClientVersion GetConstantsRef() { return EQEmu::versions::ClientVersion::RoF2; } + + } /*constants*/ + + namespace behavior { + inline EQEmu::versions::ClientVersion GetBehaviorRef() { return EQEmu::versions::ClientVersion::RoF2; } + + } /*behavior*/ + + namespace skills { + inline EQEmu::versions::ClientVersion GetSkillsRef() { return EQEmu::versions::ClientVersion::RoF2; } + + } /*skills*/ + + + // declarations + namespace inventory { + const bool ConcatenateInvTypeLimbo = false; + + const bool AllowOverLevelEquipment = true; + + const bool AllowEmptyBagInBag = true; + const bool AllowClickCastFromBag = true; + + } /*inventory*/ + + namespace invtype { + const size_t InvTypePossessionsSize = invslot::PossessionsCount; + const size_t InvTypeBankSize = 24; + const size_t InvTypeSharedBankSize = 2; + const size_t InvTypeTradeSize = 8; + const size_t InvTypeWorldSize = 10; + const size_t InvTypeLimboSize = 36; + const size_t InvTypeTributeSize = 5; + const size_t InvTypeTrophyTributeSize = 0;//unknown + const size_t InvTypeGuildTributeSize = 2;//unverified + const size_t InvTypeMerchantSize = 200; + const size_t InvTypeDeletedSize = 0;//unknown - "Recovery Tab" + const size_t InvTypeCorpseSize = InvTypePossessionsSize; + const size_t InvTypeBazaarSize = 200; + const size_t InvTypeInspectSize = invslot::EquipmentCount; + const size_t InvTypeRealEstateSize = 0;//unknown + const size_t InvTypeViewMODPCSize = InvTypePossessionsSize; + const size_t InvTypeViewMODBankSize = InvTypeBankSize; + const size_t InvTypeViewMODSharedBankSize = InvTypeSharedBankSize; + const size_t InvTypeViewMODLimboSize = InvTypeLimboSize; + const size_t InvTypeAltStorageSize = 0;//unknown - "Shroud Bank" + const size_t InvTypeArchivedSize = 0;//unknown + const size_t InvTypeMailSize = 0;//unknown + const size_t InvTypeGuildTrophyTributeSize = 0;//unknown + const size_t InvTypeKronoSize = 0;//unknown + const size_t InvTypeOtherSize = 0;//unknown + + extern size_t GetInvTypeSize(int inv_type); + extern const char* GetInvTypeName(int inv_type); + + extern bool IsInvTypePersistent(int inv_type); + + } /*invtype*/ + + namespace invslot { + extern const char* GetInvPossessionsSlotName(int inv_slot); + extern const char* GetInvSlotName(int inv_type, int inv_slot); + + } /*invslot*/ + + namespace invbag { + const size_t ItemBagSize = 255; // server Size will be 255..unsure what actual client is (test) + + extern const char* GetInvBagIndexName(int bag_index); + + } /*invbag*/ + + namespace invaug { + const size_t ItemAugSize = 6; + + extern const char* GetInvAugIndexName(int aug_index); + + } /*invaug*/ + + namespace item { + + } /*item*/ + + namespace profile { + const size_t TributeSize = invtype::InvTypeTributeSize; + const size_t GuildTributeSize = invtype::InvTypeGuildTributeSize; + + const size_t BandoliersSize = 20; // number of bandolier instances + const size_t BandolierItemCount = 4; // number of equipment slots in bandolier instance + + const size_t PotionBeltSize = 5; + + const size_t SkillArraySize = 100; + + } /*profile*/ + + namespace constants { + const size_t CharacterCreationLimit = 12; + + const size_t SayLinkBodySize = 56; + + } /*constants*/ + + namespace behavior { + const bool CoinHasWeight = false; + + } /*behavior*/ + + namespace skills { + const size_t LastUsableSkill = EQEmu::skills::Skill2HPiercing; + + } /*skills*/ + +}; /*RoF2*/ + +#endif /*COMMON_ROF2_LIMITS_H*/ diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index 4e4400cdf..1ca7063f4 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -1,3 +1,23 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + // out-going packets that require an ENCODE translation: // Begin RoF2 Encodes @@ -57,6 +77,7 @@ E(OP_GroupFollow) E(OP_GroupFollow2) E(OP_GroupInvite) E(OP_GroupUpdate) +E(OP_GuildBank) E(OP_GuildMemberList) E(OP_GuildMemberUpdate) E(OP_GuildsList) @@ -120,10 +141,12 @@ E(OP_ZoneEntry) E(OP_ZonePlayerToBind) E(OP_ZoneServerInfo) E(OP_ZoneSpawns) +E(OP_CrystalCountUpdate) // Begin RoF Decodes D(OP_AdventureMerchantSell) D(OP_AltCurrencySell) D(OP_AltCurrencySellSelection) +D(OP_Animation) D(OP_ApplyPoison) D(OP_AugmentInfo) D(OP_AugmentItem) @@ -151,6 +174,7 @@ D(OP_GroupFollow) D(OP_GroupFollow2) D(OP_GroupInvite) D(OP_GroupInvite2) +D(OP_GuildBank) D(OP_GuildDemote) D(OP_GuildRemove) D(OP_GuildStatus) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 79da918b9..ae4d2c799 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -1,7 +1,28 @@ -#ifndef ROF2_STRUCTS_H_ -#define ROF2_STRUCTS_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) -namespace RoF2 { + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_ROF2_STRUCTS_H +#define COMMON_ROF2_STRUCTS_H + + +namespace RoF2 +{ namespace structs { /* @@ -29,22 +50,24 @@ struct WorldObjectsSent_Struct { }; // New for RoF2 - Size: 12 -struct ItemSlotStruct { -/*000*/ int16 SlotType; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Delete Item = -1 +struct InventorySlot_Struct +{ +/*000*/ int16 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Delete Item = -1 /*002*/ int16 Unknown02; -/*004*/ int16 MainSlot; -/*006*/ int16 SubSlot; -/*008*/ int16 AugSlot; // Guessing - Seen 0xffff +/*004*/ int16 Slot; +/*006*/ int16 SubIndex; +/*008*/ int16 AugIndex; // Guessing - Seen 0xffff /*010*/ int16 Unknown01; // Normally 0 - Seen 13262 when deleting an item, but didn't match item ID /*012*/ }; // New for RoF2 - Used for Merchant_Purchase_Struct // Can't sellfrom other than main inventory so Slot Type is not needed. -struct MainInvItemSlotStruct { -/*000*/ int16 MainSlot; -/*002*/ int16 SubSlot; -/*004*/ int16 AugSlot; +struct TypelessInventorySlot_Struct +{ +/*000*/ int16 Slot; +/*002*/ int16 SubIndex; +/*004*/ int16 AugIndex; /*006*/ int16 Unknown01; /*008*/ }; @@ -140,7 +163,7 @@ struct AdventureInfo { ** Merth: Gave struct a name so gcc 2.96 would compile ** */ -struct Color_Struct +struct Tint_Struct { union { struct { @@ -148,21 +171,65 @@ struct Color_Struct uint8 Green; uint8 Red; uint8 UseTint; // if there's a tint this is FF - } RGB; + }; uint32 Color; }; }; -struct CharSelectEquip +struct TintProfile +{ + union { + struct { + Tint_Struct Head; + Tint_Struct Chest; + Tint_Struct Arms; + Tint_Struct Wrist; + Tint_Struct Hands; + Tint_Struct Legs; + Tint_Struct Feet; + Tint_Struct Primary; + Tint_Struct Secondary; + }; + Tint_Struct Slot[EQEmu::textures::TextureCount]; + }; +}; + +/* +* Visible equiptment. +* Size: 20 Octets +*/ +struct Texture_Struct { uint32 Material; uint32 Unknown1; uint32 EliteMaterial; uint32 HeroForgeModel; - uint32 Material2; - Color_Struct Color; + uint32 Material2; // Same as material? }; +// Needs more research regarding new slots +//struct TextureProfile +//{ +// union { +// struct { +// Texture_Struct Head; +// Texture_Struct Chest; +// Texture_Struct Arms; +// Texture_Struct Wrist; +// Texture_Struct Hands; +// Texture_Struct Legs; +// Texture_Struct Feet; +// Texture_Struct Primary; +// Texture_Struct Secondary; +// }; +// Texture_Struct Slot[EQEmu::textures::TextureCount]; +// }; +// +// TextureProfile(); +//}; + +struct CharSelectEquip : Texture_Struct, Tint_Struct {}; + struct CharacterSelectEntry_Struct { /*0000*/ char Name[1]; // Name null terminated @@ -208,21 +275,6 @@ struct CharacterSelect_Struct /*004*/ CharacterSelectEntry_Struct Entries[0]; }; -/* -* Visible equiptment. -* Size: 20 Octets -*/ -struct EquipStruct -{ - /*00*/ uint32 Material; - /*04*/ uint32 Unknown1; - /*08*/ uint32 EliteMaterial; - /*12*/ uint32 HeroForgeModel; - /*16*/ uint32 Material2; // Same as material? - /*20*/ -}; - - struct Membership_Entry_Struct { /*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300 @@ -416,7 +468,7 @@ struct Spawn_Struct /*0000*/ uint8 unknown12; /*0000*/ uint32 petOwnerId; /*0000*/ uint8 unknown13; -/*0000*/ uint32 unknown14; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed +/*0000*/ uint32 PlayerState; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed /*0000*/ uint32 unknown15; /*0000*/ uint32 unknown16; /*0000*/ uint32 unknown17; @@ -424,39 +476,24 @@ struct Spawn_Struct /*0000*/ uint32 unknown18; /*0000*/ uint32 unknown19; Spawn_Struct_Position Position; -/*0000*/ union - { - struct - { - /*0000*/ Color_Struct color_helmet; // Color of helmet item - /*0000*/ Color_Struct color_chest; // Color of chest item - /*0000*/ Color_Struct color_arms; // Color of arms item - /*0000*/ Color_Struct color_bracers; // Color of bracers item - /*0000*/ Color_Struct color_hands; // Color of hands item - /*0000*/ Color_Struct color_legs; // Color of legs item - /*0000*/ Color_Struct color_feet; // Color of feet item - /*0000*/ Color_Struct color_primary; // Color of primary item - /*0000*/ Color_Struct color_secondary; // Color of secondary item - } equipment_colors; - /*0000*/ Color_Struct colors[9]; // Array elements correspond to struct equipment_colors above - }; +/*0000*/ TintProfile equipment_tint; // skip these bytes if not a valid player race /*0000*/ union { struct { - /*0000*/ EquipStruct equip_helmet; // Equiptment: Helmet visual - /*0000*/ EquipStruct equip_chest; // Equiptment: Chest visual - /*0000*/ EquipStruct equip_arms; // Equiptment: Arms visual - /*0000*/ EquipStruct equip_bracers; // Equiptment: Wrist visual - /*0000*/ EquipStruct equip_hands; // Equiptment: Hands visual - /*0000*/ EquipStruct equip_legs; // Equiptment: Legs visual - /*0000*/ EquipStruct equip_feet; // Equiptment: Boots visual - /*0000*/ EquipStruct equip_primary; // Equiptment: Main visual - /*0000*/ EquipStruct equip_secondary; // Equiptment: Off visual + /*0000*/ Texture_Struct equip_helmet; // Equiptment: Helmet visual + /*0000*/ Texture_Struct equip_chest; // Equiptment: Chest visual + /*0000*/ Texture_Struct equip_arms; // Equiptment: Arms visual + /*0000*/ Texture_Struct equip_bracers; // Equiptment: Wrist visual + /*0000*/ Texture_Struct equip_hands; // Equiptment: Hands visual + /*0000*/ Texture_Struct equip_legs; // Equiptment: Legs visual + /*0000*/ Texture_Struct equip_feet; // Equiptment: Boots visual + /*0000*/ Texture_Struct equip_primary; // Equiptment: Main visual + /*0000*/ Texture_Struct equip_secondary; // Equiptment: Off visual } equip; - /*0000*/ EquipStruct equipment[9]; + /*0000*/ Texture_Struct equipment[9]; }; /*0000*/ //char title[0]; // only read if(hasTitleOrSuffix & 4) @@ -598,7 +635,7 @@ struct MemorizeSpell_Struct { uint32 slot; // Spot in the spell book/memorized slot uint32 spell_id; // Spell id (200 or c8 is minor healing, etc) uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming -uint32 unknown12; +uint32 reduction; // lowers reuse }; /* @@ -631,11 +668,12 @@ struct DeleteSpell_Struct struct ManaChange_Struct { - uint32 new_mana; // New Mana AMount - uint32 stamina; - uint32 spell_id; - uint32 unknown12; - uint32 unknown16; +/*00*/ uint32 new_mana; // New Mana AMount +/*04*/ uint32 stamina; +/*08*/ uint32 spell_id; +/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting? +/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like +/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it }; struct SwapSpell_Struct @@ -656,9 +694,12 @@ struct CastSpell_Struct { /*00*/ uint32 slot; /*04*/ uint32 spell_id; -/*08*/ ItemSlotStruct inventoryslot; // slot for clicky item, Seen unknown of 131 = normal cast +/*08*/ InventorySlot_Struct inventory_slot; // slot for clicky item, Seen unknown of 131 = normal cast /*20*/ uint32 target_id; -/*24*/ uint32 cs_unknown[5]; +/*24*/ uint32 cs_unknown[2]; +/*32*/ float y_pos; +/*36*/ float x_pos; +/*40*/ float z_pos; /*44*/ }; @@ -679,69 +720,31 @@ struct SpawnAppearance_Struct struct SpellBuff_Struct { -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ float unknown004; // Seen 1 for no buff -/*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*009*/ uint32 unknown016; -/*013*/ uint8 bard_modifier; -/*014*/ uint32 duration; -/*018*/ uint8 level; -/*019*/ uint32 spellid; -/*023*/ uint32 counters; -/*027*/ uint8 unknown0028[53]; -/*080*/ -}; - -struct SpellBuff_Struct_Old -{ -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; // not real -/*004*/ float unknown004; // Seen 1 for no buff -/*008*/ uint32 spellid; +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 unknown002; //pretty sure padding now +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ float bard_modifier; +/*008*/ uint32 spellid; /*012*/ uint32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*024*/ uint32 counters; -/*028*/ uint8 unknown0028[60]; +/*016*/ uint32 player_id; // caster ID, pretty sure just zone ID +/*020*/ uint32 num_hits; +/*024*/ float y; // referenced by SPA 441 +/*028*/ float x; // unsure if all buffs get them +/*032*/ float z; // as valid data +/*036*/ uint32 unknown036; +/*040*/ int32 slot_data[12]; // book keeping stuff per slot (counters, rune/vie) /*088*/ }; -// Not functional yet, but this is what the packet looks like on Live -struct SpellBuffFade_Struct_Live { -/*000*/ uint32 entityid; // Player id who cast the buff -/*004*/ uint8 unknown004; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown007; -/*008*/ float unknown008; -/*012*/ uint32 spellid; -/*016*/ uint32 duration; -/*020*/ uint32 playerId; // Global player ID? -/*024*/ uint32 num_hits; -/*028*/ uint8 unknown0028[64]; +struct SpellBuffPacket_Struct { +/*000*/ uint32 entityid; // Player id who cast the buff +/*004*/ SpellBuff_Struct buff; /*092*/ uint32 slotid; /*096*/ uint32 bufffade; /*100*/ }; -struct SpellBuffFade_Struct { -/*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ uint32 duration; -/*016*/ uint32 num_hits; -/*020*/ uint32 unknown020; // Global player ID? -/*024*/ uint32 playerId; // Player id who cast the buff -/*028*/ uint32 slotid; -/*032*/ uint32 bufffade; -/*036*/ -}; - struct BuffRemoveRequest_Struct { /*00*/ uint32 SlotID; @@ -874,7 +877,7 @@ struct AA_Array { uint32 AA; uint32 value; - uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live + uint32 charges; // expendable charges }; struct Disciplines_Struct { @@ -922,13 +925,13 @@ struct BandolierItem_Struct_Old struct Bandolier_Struct { char Name[1]; // Variable Length - BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; + BandolierItem_Struct Items[profile::BandolierItemCount]; }; struct Bandolier_Struct_Old { char Name[32]; - BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; + BandolierItem_Struct Items[profile::BandolierItemCount]; }; struct PotionBeltItem_Struct @@ -948,12 +951,12 @@ struct PotionBeltItem_Struct_Old struct PotionBelt_Struct { - PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; + PotionBeltItem_Struct Items[profile::PotionBeltSize]; }; struct PotionBelt_Struct_Old { - PotionBeltItem_Struct_Old Items[consts::POTION_BELT_ITEM_COUNT]; + PotionBeltItem_Struct_Old Items[profile::PotionBeltSize]; }; struct GroupLeadershipAA_Struct { @@ -1052,38 +1055,38 @@ union { struct { - /*00184*/ EquipStruct equip_helmet; // Equipment: Helmet visual - /*00204*/ EquipStruct equip_chest; // Equipment: Chest visual - /*00224*/ EquipStruct equip_arms; // Equipment: Arms visual - /*00244*/ EquipStruct equip_bracers; // Equipment: Wrist visual - /*00264*/ EquipStruct equip_hands; // Equipment: Hands visual - /*00284*/ EquipStruct equip_legs; // Equipment: Legs visual - /*00304*/ EquipStruct equip_feet; // Equipment: Boots visual - /*00324*/ EquipStruct equip_primary; // Equipment: Main visual - /*00344*/ EquipStruct equip_secondary; // Equipment: Off visual + /*00184*/ Texture_Struct equip_helmet; // Equipment: Helmet visual + /*00204*/ Texture_Struct equip_chest; // Equipment: Chest visual + /*00224*/ Texture_Struct equip_arms; // Equipment: Arms visual + /*00244*/ Texture_Struct equip_bracers; // Equipment: Wrist visual + /*00264*/ Texture_Struct equip_hands; // Equipment: Hands visual + /*00284*/ Texture_Struct equip_legs; // Equipment: Legs visual + /*00304*/ Texture_Struct equip_feet; // Equipment: Boots visual + /*00324*/ Texture_Struct equip_primary; // Equipment: Main visual + /*00344*/ Texture_Struct equip_secondary; // Equipment: Off visual // Below slots are just guesses, but all 0s anyway... - /*00364*/ EquipStruct equip_charm; // Equipment: Non-visual - /*00384*/ EquipStruct equip_ear1; // Equipment: Non-visual - /*00404*/ EquipStruct equip_ear2; // Equipment: Non-visual - /*00424*/ EquipStruct equip_face; // Equipment: Non-visual - /*00444*/ EquipStruct equip_neck; // Equipment: Non-visual - /*00464*/ EquipStruct equip_shoulder; // Equipment: Non-visual - /*00484*/ EquipStruct equip_bracer2; // Equipment: Non-visual - /*00504*/ EquipStruct equip_range; // Equipment: Non-visual - /*00524*/ EquipStruct equip_ring1; // Equipment: Non-visual - /*00544*/ EquipStruct equip_ring2; // Equipment: Non-visual - /*00564*/ EquipStruct equip_waist; // Equipment: Non-visual - /*00584*/ EquipStruct equip_powersource;// Equipment: Non-visual - /*00604*/ EquipStruct equip_ammo; // Equipment: Non-visual + /*00364*/ Texture_Struct equip_charm; // Equipment: Non-visual + /*00384*/ Texture_Struct equip_ear1; // Equipment: Non-visual + /*00404*/ Texture_Struct equip_ear2; // Equipment: Non-visual + /*00424*/ Texture_Struct equip_face; // Equipment: Non-visual + /*00444*/ Texture_Struct equip_neck; // Equipment: Non-visual + /*00464*/ Texture_Struct equip_shoulder; // Equipment: Non-visual + /*00484*/ Texture_Struct equip_bracer2; // Equipment: Non-visual + /*00504*/ Texture_Struct equip_range; // Equipment: Non-visual + /*00524*/ Texture_Struct equip_ring1; // Equipment: Non-visual + /*00544*/ Texture_Struct equip_ring2; // Equipment: Non-visual + /*00564*/ Texture_Struct equip_waist; // Equipment: Non-visual + /*00584*/ Texture_Struct equip_powersource;// Equipment: Non-visual + /*00604*/ Texture_Struct equip_ammo; // Equipment: Non-visual } equip; - /*00184*/ EquipStruct equipment[22]; // Total Slots + /*00184*/ Texture_Struct equipment[22]; // Total Slots }; /*00624*/ uint32 equip2_count; // Seen 9 -/*00628*/ EquipStruct equipment2[_MaterialCount]; // Appears to be Visible slots, but all 0s +/*00628*/ Texture_Struct equipment2[EQEmu::textures::TextureCount]; // Appears to be Visible slots, but all 0s /*00808*/ uint32 tint_count; // Seen 9 -/*00812*/ Color_Struct item_tint[_MaterialCount]; // RR GG BB 00 +/*00812*/ TintProfile item_tint; // RR GG BB 00 /*00848*/ uint32 tint_count2; // Seen 9 -/*00852*/ Color_Struct item_tint2[_MaterialCount]; // RR GG BB 00 +/*00852*/ TintProfile item_tint2; // RR GG BB 00 /*00888*/ uint8 haircolor; // Player hair color /*00889*/ uint8 beardcolor; // Player beard color /*00890*/ uint32 unknown_rof5; // @@ -1163,7 +1166,7 @@ union /*12949*/ uint32 aapoints; // Unspent AA points - Seen 1 /*12953*/ uint16 unknown_rof20; // /*12955*/ uint32 bandolier_count; // Seen 20 -/*12959*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents +/*12959*/ Bandolier_Struct bandoliers[profile::BandoliersSize]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents /*13699*/ uint32 potionbelt_count; // Seen 5 /*13703*/ PotionBelt_Struct potionbelt; // [5] 45 bytes potion belt - (Variable Name Sizes) /*13748*/ int32 unknown_rof21; // Seen -1 @@ -1290,7 +1293,7 @@ struct TargetReject_Struct { struct PetCommand_Struct { /*00*/ uint32 command; -/*04*/ uint32 unknown04; +/*04*/ uint32 target; /*08*/ uint32 unknown08; }; @@ -1359,7 +1362,7 @@ struct WearChange_Struct{ /*010*/ uint32 elite_material; // 1 for Drakkin Elite Material /*014*/ uint32 hero_forge_model; // New to VoA /*018*/ uint32 unknown18; // New to RoF2 -/*022*/ Color_Struct color; +/*022*/ Tint_Struct color; /*026*/ uint8 wear_slot_id; /*027*/ }; @@ -1415,8 +1418,8 @@ struct RequestClientZoneChange_Struct { struct Animation_Struct { /*00*/ uint16 spawnid; -/*02*/ uint8 value; -/*03*/ uint8 action; +/*02*/ uint8 action; +/*03*/ uint8 speed; /*04*/ }; @@ -1481,9 +1484,11 @@ struct CombatDamage_Struct /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 05 */ uint32 spellid; /* 09 */ int32 damage; -/* 13 */ float unknown11; // cd cc cc 3d -/* 17 */ float sequence; // see above notes in Action_Struct -/* 21 */ uint8 unknown19[9]; // was [9] +/* 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] +/* 26 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage /* 30 */ }; @@ -1742,7 +1747,7 @@ struct BulkItemPacket_Struct struct Consume_Struct { -/*000*/ ItemSlotStruct slot; +/*000*/ InventorySlot_Struct inventory_slot; /*012*/ uint32 auto_consumed; // 0xffffffff when auto eating e7030000 when right click /*016*/ uint32 type; // 0x01=Food 0x02=Water /*020*/ uint32 c_unknown1; // Seen 2 @@ -1774,16 +1779,18 @@ struct ItemProperties_Struct { /*008*/ }; -struct DeleteItem_Struct { -/*0000*/ ItemSlotStruct from_slot; -/*0012*/ ItemSlotStruct to_slot; +struct DeleteItem_Struct +{ +/*0000*/ InventorySlot_Struct from_slot; +/*0012*/ InventorySlot_Struct to_slot; /*0024*/ uint32 number_in_stack; /*0028*/ }; -struct MoveItem_Struct { -/*0000*/ ItemSlotStruct from_slot; -/*0012*/ ItemSlotStruct to_slot; +struct MoveItem_Struct +{ +/*0000*/ InventorySlot_Struct from_slot; +/*0012*/ InventorySlot_Struct to_slot; /*0024*/ uint32 number_in_stack; /*0028*/ }; @@ -1854,6 +1861,114 @@ struct GuildUpdate_Struct { GuildsListEntry_Struct entry; }; +struct GuildBankAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +}; + +struct GuildBankDepositAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint32 Fail; //1 = Fail, 0 = Success +}; + +struct GuildBankPromote_Struct +{ +/*00*/ uint32 Action; // 3 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 Slot; +/*16*/ uint32 Slot2; // Always appears to be the same as Slot for Action code 3 +/*20*/ uint32 unknown20; +}; + +struct GuildBankPermissions_Struct +{ +/*00*/ uint32 Action; // 6 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Unknown10; // Saw 1, probably indicating it is the main area rather than deposits +/*12*/ uint32 ItemID; +/*16*/ uint32 Permissions; +/*20*/ char MemberName[64]; +}; + +struct GuildBankViewItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; // 0 = Deposit area, 1 = Main area +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Unknown16; +}; + +struct GuildBankWithdrawItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Quantity; +/*20*/ +}; + +struct GuildBankItemUpdate_Struct +{ + void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, + uint32 inPermissions, uint32 inAllowMerge, bool inUseable) + { + Action = inAction; + Unknown004 = inUnknown004; + SlotID = inSlotID; + Area = inArea; + Unknown012 = inUnknown012; + ItemID = inItemID; + Icon = inIcon; + Quantity = inQuantity; + Permissions = inPermissions; + AllowMerge = inAllowMerge; + Useable = inUseable; + ItemName[0] = '\0'; + Donator[0] = '\0'; + WhoFor[0] = '\0'; + }; + +/*000*/ uint32 Action; +/*004*/ uint32 Unknown004; +/*008*/ uint32 Unknown08; +/*012*/ uint16 SlotID; +/*014*/ uint16 Area; +/*016*/ uint32 Unknown012; +/*020*/ uint32 ItemID; +/*024*/ uint32 Icon; +/*028*/ uint32 Quantity; +/*032*/ uint32 Permissions; +/*036*/ uint8 AllowMerge; +/*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission. +/*038*/ char ItemName[64]; +/*102*/ char Donator[64]; +/*166*/ char WhoFor[64]; +/*230*/ uint16 Unknown226; +}; + +struct GuildBankClear_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 DepositAreaCount; +/*16*/ uint32 MainAreaCount; +}; + /* ** Money Loot ** Length: 22 Bytes @@ -2109,7 +2224,7 @@ struct Merchant_Sell_Struct { struct Merchant_Purchase_Struct { /*000*/ uint32 npcid; // Merchant NPC's entity id -/*004*/ MainInvItemSlotStruct itemslot; +/*004*/ TypelessInventorySlot_Struct inventory_slot; /*012*/ uint32 quantity; /*016*/ uint32 price; /*020*/ @@ -2167,9 +2282,10 @@ struct AltCurrencyUpdate_Struct { //Client -> Server //When an item is selected while the alt currency merchant window is open -struct AltCurrencySelectItem_Struct { +struct AltCurrencySelectItem_Struct +{ /*000*/ uint32 merchant_entity_id; -/*004*/ MainInvItemSlotStruct slot_id; +/*004*/ TypelessInventorySlot_Struct inventory_slot; /*004*/ //uint32 slot_id; /*008*/ uint32 unknown008; /*012*/ uint32 unknown012; @@ -2225,9 +2341,10 @@ struct AltCurrencyReclaim_Struct { /*012*/ uint32 reclaim_flag; //1 = this is reclaim }; -struct AltCurrencySellItem_Struct { +struct AltCurrencySellItem_Struct +{ /*000*/ uint32 merchant_entity_id; -/*004*/ MainInvItemSlotStruct slot_id; +/*004*/ TypelessInventorySlot_Struct inventory_slot; /*004*/ //uint32 slot_id; /*016*/ uint32 charges; /*020*/ uint32 cost; @@ -2243,7 +2360,7 @@ struct Adventure_Purchase_Struct { struct Adventure_Sell_Struct { /*000*/ uint32 unknown000; //0x01 - Stack Size/Charges? /*004*/ uint32 npcid; -/*008*/ MainInvItemSlotStruct slot; +/*008*/ TypelessInventorySlot_Struct inventory_slot; /*016*/ uint32 charges; /*020*/ uint32 sell_price; /*024*/ @@ -2306,7 +2423,7 @@ struct AdventureLeaderboard_Struct /*struct Item_Shop_Struct { uint16 merchantid; uint8 itemtype; - Item_Struct item; + ItemBase item; uint8 iss_unknown001[6]; };*/ @@ -2469,7 +2586,7 @@ struct GroupFollow_Struct { // Live Follow Struct struct InspectBuffs_Struct { /*000*/ uint32 spell_id[BUFF_COUNT]; -/*168*/ uint32 tics_remaining[BUFF_COUNT]; +/*168*/ int32 tics_remaining[BUFF_COUNT]; }; struct LFG_Struct { @@ -2589,9 +2706,9 @@ struct Stun_Struct { // 8 bytes total struct AugmentItem_Struct { /*00*/ uint32 dest_inst_id; // The unique serial number for the item instance that is being augmented /*04*/ uint32 container_index; // Seen 0 -/*08*/ ItemSlotStruct container_slot; // Slot of the item being augmented +/*08*/ InventorySlot_Struct container_slot; // Slot of the item being augmented /*20*/ uint32 augment_index; // Seen 0 -/*24*/ ItemSlotStruct augment_slot; // Slot of the distiller to use (if one applies) +/*24*/ InventorySlot_Struct augment_slot; // Slot of the distiller to use (if one applies) /*36*/ int32 augment_action; // Guessed - 0 = augment, 1 = remove with distiller, 3 = delete aug /*36*/ //int32 augment_slot; /*40*/ @@ -2732,7 +2849,8 @@ struct Object_Struct { /*00*/ uint32 drop_id; // Unique object id for zone /*00*/ uint32 unknown024; // 53 9e f9 7e - same for all objects in the zone? /*00*/ float heading; // heading -/*00*/ float unknown032[2]; // 00 00 00 00 00 00 00 00 +/*00*/ float x_tilt; //Tilt entire object on X axis +/*00*/ float y_tilt; //Tilt entire object on Y axis /*00*/ float size; // Size - default 1 /*00*/ float z; // z coord /*00*/ float x; // x coord @@ -3493,27 +3611,6 @@ struct PetitionBug_Struct{ char text[1028]; }; -struct DyeStruct -{ - union - { - struct - { - struct Color_Struct head; - struct Color_Struct chest; - struct Color_Struct arms; - struct Color_Struct wrists; - struct Color_Struct hands; - struct Color_Struct legs; - struct Color_Struct feet; - struct Color_Struct primary; // you can't actually dye this - struct Color_Struct secondary; // or this - } - dyes; - struct Color_Struct dye[9]; - }; -}; - struct ApproveZone_Struct { char name[64]; uint32 zoneid; @@ -3577,7 +3674,7 @@ struct TributeInfo_Struct { struct TributeItem_Struct { -/*00*/ ItemSlotStruct slot; +/*00*/ InventorySlot_Struct inventory_slot; /*12*/ uint32 quantity; /*16*/ uint32 tribute_master_id; /*20*/ int32 tribute_points; @@ -3614,9 +3711,10 @@ struct Split_Struct ** Used In: OP_TradeSkillCombine ** Last Updated: 01-05-2013 */ -struct NewCombine_Struct { -/*00*/ ItemSlotStruct container_slot; -/*12*/ ItemSlotStruct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8) +struct NewCombine_Struct +{ +/*00*/ InventorySlot_Struct container_slot; +/*12*/ InventorySlot_Struct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8) /*24*/ }; @@ -3655,8 +3753,8 @@ struct RecipeReply_Struct { struct RecipeAutoCombine_Struct { /*00*/ uint32 object_type; /*04*/ uint32 some_id; -/*08*/ ItemSlotStruct container_slot; //echoed in reply - Was uint32 unknown1 -/*20*/ ItemSlotStruct unknown_slot; //echoed in reply +/*08*/ InventorySlot_Struct container_slot; //echoed in reply - Was uint32 unknown1 +/*20*/ InventorySlot_Struct unknown_slot; //echoed in reply /*32*/ uint32 recipe_id; /*36*/ uint32 reply_code; /*40*/ @@ -4186,9 +4284,11 @@ struct Arrow_Struct { /*068*/ uint8 unknown068; /*069*/ uint8 unknown069; /*070*/ uint8 unknown070; -/*071*/ uint8 item_type; -/*072*/ uint8 skill; -/*073*/ uint8 unknown073[16]; +/*071*/ uint8 unknown071; +/*072*/ uint8 unknown072; +/*073*/ uint8 skill; +/*074*/ uint8 item_type; +/*075*/ uint8 unknown075[14]; /*089*/ char model_name[27]; /*116*/ }; @@ -4247,9 +4347,9 @@ struct SendAA_Struct { /*0025*/ uint32 cost; /*0029*/ uint32 seq; /*0033*/ uint32 current_level; //1s, MQ2 calls this AARankRequired -/*0037*/ uint32 unknown037; // Introduced during HoT +/*0037*/ uint32 prereq_skill_count; // mutliple prereqs at least 1, even no prereqs /*0041*/ uint32 prereq_skill; //is < 0, abs() is category # -/*0045*/ uint32 unknown045; // New Mar 21 2012 - Seen 1 +/*0045*/ uint32 prereq_minpoints_count; // mutliple prereqs at least 1, even no prereqs /*0049*/ uint32 prereq_minpoints; //min points in the prereq /*0053*/ uint32 type; /*0057*/ uint32 spellid; @@ -4262,10 +4362,16 @@ struct SendAA_Struct { /*0081*/ uint32 last_id; /*0085*/ uint32 next_id; /*0089*/ uint32 cost2; -/*0093*/ uint8 unknown80[7]; +/*0093*/ uint8 unknown93; +/*0094*/ uint8 grant_only; // VetAAs, progression, etc +/*0095*/ uint8 unknown95; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though +/*0096*/ uint32 expendable_charges; // max charges of the AA /*0100*/ uint32 aa_expansion; /*0104*/ uint32 special_category; -/*0108*/ uint32 unknown0096; +/*0108*/ uint8 shroud; +/*0109*/ uint8 unknown109; +/*0110*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter? +/*0111*/ uint8 unknown111; /*0112*/ uint32 total_abilities; /*0116*/ AA_Ability abilities[0]; }; @@ -4277,17 +4383,11 @@ struct AA_List { struct AA_Action { /*00*/ uint32 action; /*04*/ uint32 ability; -/*08*/ uint32 unknown08; +/*08*/ uint32 target_id; /*12*/ uint32 exp_value; /*16*/ }; -struct AA_Skills { //this should be removed and changed to AA_Array -/*00*/ uint32 aa_skill; // Total AAs Spent -/*04*/ uint32 aa_value; -/*08*/ uint32 unknown08; -/*12*/ -}; struct AAExpUpdate_Struct { /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability @@ -4307,14 +4407,7 @@ struct AltAdvStats_Struct { }; struct PlayerAA_Struct { // Is this still used? - AA_Skills aa_list[MAX_PP_AA_ARRAY]; -}; - -struct AA_Values { -/*00*/ uint32 aa_skill; -/*04*/ uint32 aa_value; -/*08*/ uint32 unknown08; -/*12*/ + AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct AATable_Struct { @@ -4324,7 +4417,7 @@ struct AATable_Struct { /*12*/ uint32 aa_spent_archetype; // Seen 40 /*16*/ uint32 aa_spent_class; // Seen 103 /*20*/ uint32 aa_spent_special; // Seen 0 -/*24*/ AA_Values aa_list[MAX_PP_AA_ARRAY]; +/*24*/ AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct Weather_Struct { @@ -4379,19 +4472,22 @@ struct ExpansionInfo_Struct { /*064*/ uint32 Expansions; }; -struct ApplyPoison_Struct { - MainInvItemSlotStruct inventorySlot; +struct ApplyPoison_Struct +{ + TypelessInventorySlot_Struct inventorySlot; uint32 success; }; -struct ItemVerifyRequest_Struct { -/*000*/ ItemSlotStruct slot; +struct ItemVerifyRequest_Struct +{ +/*000*/ InventorySlot_Struct inventory_slot; /*012*/ uint32 target; // Target Entity ID /*016*/ }; -struct ItemVerifyReply_Struct { -/*000*/ ItemSlotStruct slot; +struct ItemVerifyReply_Struct +{ +/*000*/ InventorySlot_Struct inventory_slot; /*012*/ uint32 spell; // Spell ID to cast if different than item effect /*016*/ uint32 target; // Target Entity ID /*020*/ @@ -4624,7 +4720,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4639,7 +4735,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4676,7 +4772,7 @@ struct ItemQuaternaryBodyStruct int32 HeroicSVCorrup; int32 HealAmt; int32 SpellDmg; - int32 clairvoyance; + int32 Clairvoyance; uint8 unknown18; //Power Source Capacity or evolve filename? uint32 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; @@ -4714,7 +4810,6 @@ struct ItemQuaternaryBodyStruct uint8 unknown37a; // New to RoF2 - Probably variable length string uint8 unknown38; // 0 uint8 unknown39; // 1 - uint32 subitem_count; }; struct AugmentInfo_Struct @@ -4949,7 +5044,17 @@ struct MercenaryMerchantResponse_Struct { /*0004*/ }; - }; //end namespace structs -}; //end namespace RoF2 +// Sent by Server to update character crystals. +struct CrystalCountUpdate_Struct +{ + /*000*/ uint32 CurrentRadiantCrystals; + /*004*/ uint32 CareerRadiantCrystals; + /*008*/ uint32 CurrentEbonCrystals; + /*012*/ uint32 CareerEbonCrystals; +}; -#endif /*ROF2_STRUCTS_H_*/ + }; /*structs*/ + +}; /*RoF2*/ + +#endif /*COMMON_ROF2_STRUCTS_H*/ diff --git a/common/patches/rof_constants.h b/common/patches/rof_constants.h deleted file mode 100644 index 8b5fadbf2..000000000 --- a/common/patches/rof_constants.h +++ /dev/null @@ -1,221 +0,0 @@ -/* -EQEMu: Everquest Server Emulator - -Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY except by those people which sell it, which -are required to give you total support for your newly bought product; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef ROF_CONSTANTS_H_ -#define ROF_CONSTANTS_H_ - -#include "../types.h" - -namespace RoF { - namespace maps { - typedef enum : int16 { - MapPossessions = 0, - MapBank, - MapSharedBank, - MapTrade, - MapWorld, - MapLimbo, - MapTribute, - MapTrophyTribute, - MapGuildTribute, - MapMerchant, - MapDeleted, - MapCorpse, - MapBazaar, - MapInspect, - MapRealEstate, - MapViewMODPC, - MapViewMODBank, - MapViewMODSharedBank, - MapViewMODLimbo, - MapAltStorage, - MapArchived, - MapMail, - MapGuildTrophyTribute, - MapOther, - _MapCount - } InventoryMaps; - } - - namespace slots { - typedef enum : int16 { - MainCharm = 0, - MainEar1, - MainHead, - MainFace, - MainEar2, - MainNeck, - MainShoulders, - MainArms, - MainBack, - MainWrist1, - MainWrist2, - MainRange, - MainHands, - MainPrimary, - MainSecondary, - MainFinger1, - MainFinger2, - MainChest, - MainLegs, - MainFeet, - MainWaist, - MainPowerSource, - MainAmmo, - MainGeneral1, - MainGeneral2, - MainGeneral3, - MainGeneral4, - MainGeneral5, - MainGeneral6, - MainGeneral7, - MainGeneral8, - MainGeneral9, - MainGeneral10, - MainCursor, - _MainCount, - _MainEquipmentBegin = MainCharm, - _MainEquipmentEnd = MainAmmo, - _MainEquipmentCount = (_MainEquipmentEnd - _MainEquipmentBegin + 1), - _MainGeneralBegin = MainGeneral1, - _MainGeneralEnd = MainGeneral10, - _MainGeneralCount = (_MainGeneralEnd - _MainGeneralBegin + 1) - } EquipmentSlots; - } - - namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 12; - - static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; - static const uint16 MAP_BANK_SIZE = 24; - static const uint16 MAP_SHARED_BANK_SIZE = 2; - static const uint16 MAP_TRADE_SIZE = 8; - static const uint16 MAP_WORLD_SIZE = 10; - static const uint16 MAP_LIMBO_SIZE = 36; - static const uint16 MAP_TRIBUTE_SIZE = 0; //? - static const uint16 MAP_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_GUILD_TRIBUTE_SIZE = 0; - static const uint16 MAP_MERCHANT_SIZE = 0; - static const uint16 MAP_DELETED_SIZE = 0; - static const uint16 MAP_CORPSE_SIZE = slots::_MainCount; - static const uint16 MAP_BAZAAR_SIZE = 200; - static const uint16 MAP_INSPECT_SIZE = slots::_MainEquipmentCount; - static const uint16 MAP_REAL_ESTATE_SIZE = 0; - static const uint16 MAP_VIEW_MOD_PC_SIZE = MAP_POSSESSIONS_SIZE; - static const uint16 MAP_VIEW_MOD_BANK_SIZE = MAP_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_SHARED_BANK_SIZE = MAP_SHARED_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_LIMBO_SIZE = MAP_LIMBO_SIZE; - static const uint16 MAP_ALT_STORAGE_SIZE = 0; - static const uint16 MAP_ARCHIVED_SIZE = 0; - static const uint16 MAP_MAIL_SIZE = 0; - static const uint16 MAP_GUILD_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_KRONO_SIZE = NOT_USED; - static const uint16 MAP_OTHER_SIZE = 0; - - // most of these definitions will go away with the structure-based system..this maintains compatibility for now - // (bag slots and main slots beyond Possessions are assigned for compatibility with current server coding) - static const int16 EQUIPMENT_BEGIN = slots::MainCharm; - static const int16 EQUIPMENT_END = slots::MainAmmo; - static const uint16 EQUIPMENT_SIZE = slots::_MainEquipmentCount; - - static const int16 GENERAL_BEGIN = slots::MainGeneral1; - static const int16 GENERAL_END = slots::MainGeneral10; - static const uint16 GENERAL_SIZE = slots::_MainGeneralCount; - static const int16 GENERAL_BAGS_BEGIN = 251; - static const int16 GENERAL_BAGS_END_OFFSET = 99; - static const int16 GENERAL_BAGS_END = GENERAL_BAGS_BEGIN + GENERAL_BAGS_END_OFFSET; - - static const int16 CURSOR = slots::MainCursor; - static const int16 CURSOR_BAG_BEGIN = 351; - static const int16 CURSOR_BAG_END_OFFSET = 9; - static const int16 CURSOR_BAG_END = CURSOR_BAG_BEGIN + CURSOR_BAG_END_OFFSET; - - static const int16 BANK_BEGIN = 2000; - static const int16 BANK_END = 2023; - static const int16 BANK_BAGS_BEGIN = 2031; - static const int16 BANK_BAGS_END_OFFSET = 239; - static const int16 BANK_BAGS_END = BANK_BAGS_BEGIN + BANK_BAGS_END_OFFSET; - - static const int16 SHARED_BANK_BEGIN = 2500; - static const int16 SHARED_BANK_END = 2501; - static const int16 SHARED_BANK_BAGS_BEGIN = 2531; - static const int16 SHARED_BANK_BAGS_END_OFFSET = 19; - static const int16 SHARED_BANK_BAGS_END = SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_END_OFFSET; - - static const int16 TRADE_BEGIN = 3000; - static const int16 TRADE_END = 3007; - static const int16 TRADE_NPC_END = 3003; - static const int16 TRADE_BAGS_BEGIN = 3031; - static const int16 TRADE_BAGS_END_OFFSET = 79; - static const int16 TRADE_BAGS_END = TRADE_BAGS_BEGIN + TRADE_BAGS_END_OFFSET; - - static const int16 WORLD_BEGIN = 4000; - static const int16 WORLD_END = 4009; - - static const int16 TRIBUTE_BEGIN = 400; - static const int16 TRIBUTE_END = 404; - - static const int16 CORPSE_BEGIN = slots::MainGeneral1; - static const int16 CORPSE_END = slots::MainGeneral1 + slots::MainCursor; - - static const uint16 ITEM_COMMON_SIZE = 6; - static const uint16 ITEM_CONTAINER_SIZE = 255; // 255; (server max will be 255..unsure what actual client is - test) - - static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances - static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance - - static const size_t POTION_BELT_ITEM_COUNT = 5; - - static const size_t TEXT_LINK_BODY_LENGTH = 55; - } - - namespace limits { - static const bool ALLOWS_EMPTY_BAG_IN_BAG = true; - static const bool ALLOWS_CLICK_CAST_FROM_BAG = true; - static const bool COIN_HAS_WEIGHT = false; - } - -}; //end namespace RoF - -#endif /*ROF_CONSTANTS_H_*/ - -/* -RoF Notes: - ** Structure-based inventory ** -ok Possessions: ( 0, { 0 .. 33 }, -1, -1 ) (Corpse: { 23 .. 56 } [Offset 23]) -ok [Equipment: ( 0, { 0 .. 22 }, -1, -1 )] -ok [General: ( 0, { 23 .. 32 }, -1, -1 )] -ok [Cursor: ( 0, 33, -1, -1 )] - General Bags: ( 0, { 23 .. 32 }, { 0 .. (maxsize - 1) }, -1 ) - Cursor Bags: ( 0, 33, { 0 .. (maxsize - 1) }, -1 ) - - Bank: ( 1, { 0 .. 23 }, -1, -1 ) - Bank Bags: ( 1, { 0 .. 23 }, { 0 .. (maxsize - 1)}, -1 ) - - Shared Bank: ( 2, { 0 .. 1 }, -1, -1 ) - Shared Bank Bags: ( 2, { 0 .. 1 }, { 0 .. (maxsize - 1) }, -1 ) - - Trade: ( 3, { 0 .. 8 }, -1, -1 ) - (Trade Bags: 3031 - 3110 -- server values) - - World: ( 4, { 0 .. 10 }, -1, -1 ) - -*/ diff --git a/common/patches/rof_limits.cpp b/common/patches/rof_limits.cpp new file mode 100644 index 000000000..c78ffc59d --- /dev/null +++ b/common/patches/rof_limits.cpp @@ -0,0 +1,280 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "rof_limits.h" + +#include "../string_util.h" + + +size_t RoF::invtype::GetInvTypeSize(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + return invtype::InvTypePossessionsSize; + case invtype::InvTypeBank: + return invtype::InvTypeBankSize; + case invtype::InvTypeSharedBank: + return invtype::InvTypeSharedBankSize; + case invtype::InvTypeTrade: + return invtype::InvTypeTradeSize; + case invtype::InvTypeWorld: + return invtype::InvTypeWorldSize; + case invtype::InvTypeLimbo: + return invtype::InvTypeLimboSize; + case invtype::InvTypeTribute: + return invtype::InvTypeTributeSize; + case invtype::InvTypeTrophyTribute: + return invtype::InvTypeTrophyTributeSize; + case invtype::InvTypeGuildTribute: + return invtype::InvTypeGuildTributeSize; + case invtype::InvTypeMerchant: + return invtype::InvTypeMerchantSize; + case invtype::InvTypeDeleted: + return invtype::InvTypeDeletedSize; + case invtype::InvTypeCorpse: + return invtype::InvTypeCorpseSize; + case invtype::InvTypeBazaar: + return invtype::InvTypeBazaarSize; + case invtype::InvTypeInspect: + return invtype::InvTypeInspectSize; + case invtype::InvTypeRealEstate: + return invtype::InvTypeRealEstateSize; + case invtype::InvTypeViewMODPC: + return invtype::InvTypeViewMODPCSize; + case invtype::InvTypeViewMODBank: + return invtype::InvTypeViewMODBankSize; + case invtype::InvTypeViewMODSharedBank: + return invtype::InvTypeViewMODSharedBankSize; + case invtype::InvTypeViewMODLimbo: + return invtype::InvTypeViewMODLimboSize; + case invtype::InvTypeAltStorage: + return invtype::InvTypeAltStorageSize; + case invtype::InvTypeArchived: + return invtype::InvTypeArchivedSize; + case invtype::InvTypeMail: + return invtype::InvTypeMailSize; + case invtype::InvTypeGuildTrophyTribute: + return invtype::InvTypeGuildTrophyTributeSize; + case invtype::InvTypeOther: + return invtype::InvTypeOtherSize; + default: + return 0; + } +} + +const char* RoF::invtype::GetInvTypeName(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypeInvalid: + return "Invalid Type"; + case invtype::InvTypePossessions: + return "Possessions"; + case invtype::InvTypeBank: + return "Bank"; + case invtype::InvTypeSharedBank: + return "Shared Bank"; + case invtype::InvTypeTrade: + return "Trade"; + case invtype::InvTypeWorld: + return "World"; + case invtype::InvTypeLimbo: + return "Limbo"; + case invtype::InvTypeTribute: + return "Tribute"; + case invtype::InvTypeTrophyTribute: + return "Trophy Tribute"; + case invtype::InvTypeGuildTribute: + return "Guild Tribute"; + case invtype::InvTypeMerchant: + return "Merchant"; + case invtype::InvTypeDeleted: + return "Deleted"; + case invtype::InvTypeCorpse: + return "Corpse"; + case invtype::InvTypeBazaar: + return "Bazaar"; + case invtype::InvTypeInspect: + return "Inspect"; + case invtype::InvTypeRealEstate: + return "Real Estate"; + case invtype::InvTypeViewMODPC: + return "View MOD PC"; + case invtype::InvTypeViewMODBank: + return "View MOD Bank"; + case invtype::InvTypeViewMODSharedBank: + return "View MOD Shared Bank"; + case invtype::InvTypeViewMODLimbo: + return "View MOD Limbo"; + case invtype::InvTypeAltStorage: + return "Alt Storage"; + case invtype::InvTypeArchived: + return "Archived"; + case invtype::InvTypeMail: + return "Mail"; + case invtype::InvTypeGuildTrophyTribute: + return "Guild Trophy Tribute"; + case invtype::InvTypeOther: + return "Other"; + default: + return "Unknown Type"; + } +} + +bool RoF::invtype::IsInvTypePersistent(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + case invtype::InvTypeBank: + case invtype::InvTypeSharedBank: + case invtype::InvTypeTrade: + case invtype::InvTypeWorld: + case invtype::InvTypeLimbo: + case invtype::InvTypeTribute: + case invtype::InvTypeTrophyTribute: + case invtype::InvTypeGuildTribute: + return true; + default: + return false; + } +} + +const char* RoF::invslot::GetInvPossessionsSlotName(int inv_slot) +{ + switch (inv_slot) { + case invslot::InvSlotInvalid: + return "Invalid Slot"; + case invslot::PossessionsCharm: + return "Charm"; + case invslot::PossessionsEar1: + return "Ear 1"; + case invslot::PossessionsHead: + return "Head"; + case invslot::PossessionsFace: + return "Face"; + case invslot::PossessionsEar2: + return "Ear 2"; + case invslot::PossessionsNeck: + return "Neck"; + case invslot::PossessionsShoulders: + return "Shoulders"; + case invslot::PossessionsArms: + return "Arms"; + case invslot::PossessionsBack: + return "Back"; + case invslot::PossessionsWrist1: + return "Wrist 1"; + case invslot::PossessionsWrist2: + return "Wrist 2"; + case invslot::PossessionsRange: + return "Range"; + case invslot::PossessionsHands: + return "Hands"; + case invslot::PossessionsPrimary: + return "Primary"; + case invslot::PossessionsSecondary: + return "Secondary"; + case invslot::PossessionsFinger1: + return "Finger 1"; + case invslot::PossessionsFinger2: + return "Finger 2"; + case invslot::PossessionsChest: + return "Chest"; + case invslot::PossessionsLegs: + return "Legs"; + case invslot::PossessionsFeet: + return "Feet"; + case invslot::PossessionsWaist: + return "Waist"; + case invslot::PossessionsPowerSource: + return "Power Source"; + case invslot::PossessionsAmmo: + return "Ammo"; + case invslot::PossessionsGeneral1: + return "General 1"; + case invslot::PossessionsGeneral2: + return "General 2"; + case invslot::PossessionsGeneral3: + return "General 3"; + case invslot::PossessionsGeneral4: + return "General 4"; + case invslot::PossessionsGeneral5: + return "General 5"; + case invslot::PossessionsGeneral6: + return "General 6"; + case invslot::PossessionsGeneral7: + return "General 7"; + case invslot::PossessionsGeneral8: + return "General 8"; + case invslot::PossessionsGeneral9: + return "General 9"; + case invslot::PossessionsGeneral10: + return "General 10"; + case invslot::PossessionsCursor: + return "Cursor"; + default: + return "Unknown Slot"; + } +} + +const char* RoF::invslot::GetInvSlotName(int inv_type, int inv_slot) +{ + if (inv_type == invtype::InvTypePossessions) + return invslot::GetInvPossessionsSlotName(inv_slot); + + size_t type_size = invtype::GetInvTypeSize(inv_type); + + if (!type_size || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + if ((size_t)(inv_slot + 1) >= type_size) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* RoF::invbag::GetInvBagIndexName(int bag_index) +{ + if (bag_index == invbag::InvBagInvalid) + return "Invalid Bag"; + + if ((size_t)bag_index >= invbag::ItemBagSize) + return "Unknown Bag"; + + static std::string ret_str; + ret_str = StringFormat("Bag %i", (bag_index + 1)); + + return ret_str.c_str(); +} + +const char* RoF::invaug::GetInvAugIndexName(int aug_index) +{ + if (aug_index == invaug::InvAugInvalid) + return "Invalid Augment"; + + if ((size_t)aug_index >= invaug::ItemAugSize) + return "Unknown Augment"; + + static std::string ret_str; + ret_str = StringFormat("Augment %i", (aug_index + 1)); + + return ret_str.c_str(); +} diff --git a/common/patches/rof_limits.h b/common/patches/rof_limits.h new file mode 100644 index 000000000..ed0b9a6d0 --- /dev/null +++ b/common/patches/rof_limits.h @@ -0,0 +1,285 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_ROF_LIMITS_H +#define COMMON_ROF_LIMITS_H + +#include "../types.h" +#include "../emu_versions.h" +#include "../skills.h" + + +namespace RoF +{ + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + // pre-declarations + namespace inventory { + inline EQEmu::versions::ClientVersion GetInventoryRef() { return EQEmu::versions::ClientVersion::RoF; } + + } /*inventory*/ + + namespace invtype { + inline EQEmu::versions::ClientVersion GetInvTypeRef() { return EQEmu::versions::ClientVersion::RoF; } + + enum : int { InvTypeInvalid = -1, InvTypeBegin }; + + enum InventoryType : int { + InvTypePossessions = InvTypeBegin, + InvTypeBank, + InvTypeSharedBank, + InvTypeTrade, + InvTypeWorld, + InvTypeLimbo, + InvTypeTribute, + InvTypeTrophyTribute, + InvTypeGuildTribute, + InvTypeMerchant, + InvTypeDeleted, + InvTypeCorpse, + InvTypeBazaar, + InvTypeInspect, + InvTypeRealEstate, + InvTypeViewMODPC, + InvTypeViewMODBank, + InvTypeViewMODSharedBank, + InvTypeViewMODLimbo, + InvTypeAltStorage, + InvTypeArchived, + InvTypeMail, + InvTypeGuildTrophyTribute, + InvTypeOther, + InvTypeCount + }; + + } /*invtype*/ + + namespace invslot { + inline EQEmu::versions::ClientVersion GetInvSlotRef() { return EQEmu::versions::ClientVersion::RoF; } + + enum : int { InvSlotInvalid = -1, InvSlotBegin }; + + enum PossessionsSlot : int { + PossessionsCharm = InvSlotBegin, + PossessionsEar1, + PossessionsHead, + PossessionsFace, + PossessionsEar2, + PossessionsNeck, + PossessionsShoulders, + PossessionsArms, + PossessionsBack, + PossessionsWrist1, + PossessionsWrist2, + PossessionsRange, + PossessionsHands, + PossessionsPrimary, + PossessionsSecondary, + PossessionsFinger1, + PossessionsFinger2, + PossessionsChest, + PossessionsLegs, + PossessionsFeet, + PossessionsWaist, + PossessionsPowerSource, + PossessionsAmmo, + PossessionsGeneral1, + PossessionsGeneral2, + PossessionsGeneral3, + PossessionsGeneral4, + PossessionsGeneral5, + PossessionsGeneral6, + PossessionsGeneral7, + PossessionsGeneral8, + PossessionsGeneral9, + PossessionsGeneral10, + PossessionsCursor, + PossessionsCount + }; + + const int EquipmentBegin = PossessionsCharm; + const int EquipmentEnd = PossessionsAmmo; + const int EquipmentCount = (EquipmentEnd - EquipmentBegin + 1); + + const int GeneralBegin = PossessionsGeneral1; + const int GeneralEnd = PossessionsGeneral10; + const int GeneralCount = (GeneralEnd - GeneralBegin + 1); + + } /*invslot*/ + + namespace invbag { + inline EQEmu::versions::ClientVersion GetInvBagRef() { return EQEmu::versions::ClientVersion::RoF; } + + enum : int { InvBagInvalid = -1, InvBagBegin }; + + } /*invbag*/ + + namespace invaug { + inline EQEmu::versions::ClientVersion GetInvAugRef() { return EQEmu::versions::ClientVersion::RoF; } + + enum : int { InvAugInvalid = -1, InvAugBegin }; + + } /*invaug*/ + + namespace item { + inline EQEmu::versions::ClientVersion GetItemRef() { return EQEmu::versions::ClientVersion::RoF; } + + enum ItemPacketType : int { + ItemPacketMerchant = 100, + ItemPacketTradeView = 101, + ItemPacketLoot = 102, + ItemPacketTrade = 103, + ItemPacketCharInventory = 105, + ItemPacketLimbo = 106, + ItemPacketWorldContainer = 107, + ItemPacketTributeItem = 108, + ItemPacketGuildTribute = 109, + ItemPacket10 = 110, + ItemPacket11 = 111, + ItemPacket12 = 112, + ItemPacketRecovery = 113, + ItemPacket14 = 115 + }; + + } /*item*/ + + namespace profile { + inline EQEmu::versions::ClientVersion GetProfileRef() { return EQEmu::versions::ClientVersion::RoF; } + + } /*profile*/ + + namespace constants { + inline EQEmu::versions::ClientVersion GetConstantsRef() { return EQEmu::versions::ClientVersion::RoF; } + + } /*constants*/ + + namespace behavior { + inline EQEmu::versions::ClientVersion GetBehaviorRef() { return EQEmu::versions::ClientVersion::RoF; } + + } /*behavior*/ + + namespace skills { + inline EQEmu::versions::ClientVersion GetSkillsRef() { return EQEmu::versions::ClientVersion::RoF; } + + } /*skills*/ + + + // declarations + namespace inventory { + const bool ConcatenateInvTypeLimbo = false; + + const bool AllowOverLevelEquipment = true; + + const bool AllowEmptyBagInBag = true; + const bool AllowClickCastFromBag = true; + + } /*inventory*/ + + namespace invtype { + const size_t InvTypePossessionsSize = invslot::PossessionsCount; + const size_t InvTypeBankSize = 24; + const size_t InvTypeSharedBankSize = 2; + const size_t InvTypeTradeSize = 8; + const size_t InvTypeWorldSize = 10; + const size_t InvTypeLimboSize = 36; + const size_t InvTypeTributeSize = 5; + const size_t InvTypeTrophyTributeSize = 0;//unknown + const size_t InvTypeGuildTributeSize = 2;//unverified + const size_t InvTypeMerchantSize = 200; + const size_t InvTypeDeletedSize = 0;//unknown - "Recovery Tab" + const size_t InvTypeCorpseSize = InvTypePossessionsSize; + const size_t InvTypeBazaarSize = 200; + const size_t InvTypeInspectSize = invslot::EquipmentCount; + const size_t InvTypeRealEstateSize = 0;//unknown + const size_t InvTypeViewMODPCSize = InvTypePossessionsSize; + const size_t InvTypeViewMODBankSize = InvTypeBankSize; + const size_t InvTypeViewMODSharedBankSize = InvTypeSharedBankSize; + const size_t InvTypeViewMODLimboSize = InvTypeLimboSize; + const size_t InvTypeAltStorageSize = 0;//unknown - "Shroud Bank" + const size_t InvTypeArchivedSize = 0;//unknown + const size_t InvTypeMailSize = 0;//unknown + const size_t InvTypeGuildTrophyTributeSize = 0;//unknown + const size_t InvTypeOtherSize = 0;//unknown + + extern size_t GetInvTypeSize(int inv_type); + extern const char* GetInvTypeName(int inv_type); + + extern bool IsInvTypePersistent(int inv_type); + + } /*invtype*/ + + namespace invslot { + extern const char* GetInvPossessionsSlotName(int inv_slot); + extern const char* GetInvSlotName(int inv_type, int inv_slot); + + } /*invslot*/ + + namespace invbag { + const size_t ItemBagSize = 255; // server Size will be 255..unsure what actual client is (test) + + extern const char* GetInvBagIndexName(int bag_index); + + } /*invbag*/ + + namespace invaug { + const size_t ItemAugSize = 6; + + extern const char* GetInvAugIndexName(int aug_index); + + } /*invaug*/ + + namespace item { + + } /*item*/ + + namespace profile { + const size_t TributeSize = invtype::InvTypeTributeSize; + const size_t GuildTributeSize = invtype::InvTypeGuildTributeSize; + + const size_t BandoliersSize = 20; // number of bandolier instances + const size_t BandolierItemCount = 4; // number of equipment slots in bandolier instance + + const size_t PotionBeltSize = 5; + + const size_t SkillArraySize = 100; + + } /*profile*/ + + namespace constants { + const size_t CharacterCreationLimit = 12; + + const size_t SayLinkBodySize = 55; + + } /*constants*/ + + namespace behavior { + const bool CoinHasWeight = false; + + } /*behavior*/ + + namespace skills { + const size_t LastUsableSkill = EQEmu::skills::SkillTripleAttack; + + } /*skills*/ + +}; /*RoF*/ + +#endif /*COMMON_ROF_LIMITS_H*/ diff --git a/common/patches/rof_ops.h b/common/patches/rof_ops.h index 08e8647f3..45221cfc5 100644 --- a/common/patches/rof_ops.h +++ b/common/patches/rof_ops.h @@ -1,3 +1,23 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + // out-going packets that require an ENCODE translation: E(OP_Action) E(OP_AdventureMerchantSell) @@ -42,6 +62,7 @@ E(OP_GroupFollow) E(OP_GroupFollow2) E(OP_GroupInvite) E(OP_GroupUpdate) +E(OP_GuildBank) E(OP_GuildMemberList) E(OP_GuildMemberUpdate) E(OP_GuildsList) @@ -109,6 +130,7 @@ E(OP_ZoneSpawns) D(OP_AdventureMerchantSell) D(OP_AltCurrencySell) D(OP_AltCurrencySellSelection) +D(OP_Animation) D(OP_ApplyPoison) D(OP_AugmentInfo) D(OP_AugmentItem) @@ -136,6 +158,7 @@ D(OP_GroupFollow) D(OP_GroupFollow2) D(OP_GroupInvite) D(OP_GroupInvite2) +D(OP_GuildBank) D(OP_GuildDemote) D(OP_GuildRemove) D(OP_GuildStatus) diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index a623c7cf4..74b47c09e 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -1,7 +1,28 @@ -#ifndef ROF_STRUCTS_H_ -#define ROF_STRUCTS_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) -namespace RoF { + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_ROF_STRUCTS_H +#define COMMON_ROF_STRUCTS_H + + +namespace RoF +{ namespace structs { /* @@ -29,22 +50,24 @@ struct WorldObjectsSent_Struct { }; // New for RoF - Size: 12 -struct ItemSlotStruct { -/*000*/ int16 SlotType; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Delete Item = -1 +struct InventorySlot_Struct +{ +/*000*/ int16 Type; // Worn and Normal inventory = 0, Bank = 1, Shared Bank = 2, Delete Item = -1 /*002*/ int16 Unknown02; -/*004*/ int16 MainSlot; -/*006*/ int16 SubSlot; -/*008*/ int16 AugSlot; // Guessing - Seen 0xffff +/*004*/ int16 Slot; +/*006*/ int16 SubIndex; +/*008*/ int16 AugIndex; // Guessing - Seen 0xffff /*010*/ int16 Unknown01; // Normally 0 - Seen 13262 when deleting an item, but didn't match item ID /*012*/ }; // New for RoF - Used for Merchant_Purchase_Struct // Can't sellfrom other than main inventory so Slot Type is not needed. -struct MainInvItemSlotStruct { -/*000*/ int16 MainSlot; -/*002*/ int16 SubSlot; -/*004*/ int16 AugSlot; +struct TypelessInventorySlot_Struct +{ +/*000*/ int16 Slot; +/*002*/ int16 SubIndex; +/*004*/ int16 AugIndex; /*006*/ int16 Unknown01; /*008*/ }; @@ -140,7 +163,7 @@ struct AdventureInfo { ** Merth: Gave struct a name so gcc 2.96 would compile ** */ -struct Color_Struct +struct Tint_Struct { union { struct { @@ -148,21 +171,65 @@ struct Color_Struct uint8 Green; uint8 Red; uint8 UseTint; // if there's a tint this is FF - } RGB; + }; uint32 Color; }; }; -struct CharSelectEquip +struct TintProfile +{ + union { + struct { + Tint_Struct Head; + Tint_Struct Chest; + Tint_Struct Arms; + Tint_Struct Wrist; + Tint_Struct Hands; + Tint_Struct Legs; + Tint_Struct Feet; + Tint_Struct Primary; + Tint_Struct Secondary; + }; + Tint_Struct Slot[EQEmu::textures::TextureCount]; + }; +}; + +/* +* Visible equiptment. +* Size: 20 Octets +*/ +struct Texture_Struct { uint32 Material; uint32 Unknown1; uint32 EliteMaterial; uint32 HeroForgeModel; - uint32 Material2; - Color_Struct Color; + uint32 Material2; // Same as material? }; +// Needs more research regarding new slots +//struct TextureProfile +//{ +// union { +// struct { +// Texture_Struct Head; +// Texture_Struct Chest; +// Texture_Struct Arms; +// Texture_Struct Wrist; +// Texture_Struct Hands; +// Texture_Struct Legs; +// Texture_Struct Feet; +// Texture_Struct Primary; +// Texture_Struct Secondary; +// }; +// Texture_Struct Slot[EQEmu::textures::TextureCount]; +// }; +// +// TextureProfile(); +//}; + +struct CharSelectEquip : Texture_Struct, Tint_Struct {}; + struct CharacterSelectEntry_Struct { /*0000*/ char Name[1]; // Name null terminated @@ -208,21 +275,6 @@ struct CharacterSelect_Struct /*004*/ CharacterSelectEntry_Struct Entries[0]; }; -/* -* Visible equiptment. -* Size: 20 Octets -*/ -struct EquipStruct -{ - /*00*/ uint32 Material; - /*04*/ uint32 Unknown1; - /*08*/ uint32 EliteMaterial; - /*12*/ uint32 HeroForgeModel; - /*16*/ uint32 Material2; // Same as material? - /*20*/ -}; - - struct Membership_Entry_Struct { /*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300 @@ -410,7 +462,7 @@ struct Spawn_Struct /*0000*/ uint8 unknown12; /*0000*/ uint32 petOwnerId; /*0000*/ uint8 unknown13; -/*0000*/ uint32 unknown14; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed +/*0000*/ uint32 PlayerState; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed /*0000*/ uint32 unknown15; /*0000*/ uint32 unknown16; /*0000*/ uint32 unknown17; @@ -418,39 +470,24 @@ struct Spawn_Struct /*0000*/ uint32 unknown18; /*0000*/ uint32 unknown19; Spawn_Struct_Position Position; -/*0000*/ union - { - struct - { - /*0000*/ Color_Struct color_helmet; // Color of helmet item - /*0000*/ Color_Struct color_chest; // Color of chest item - /*0000*/ Color_Struct color_arms; // Color of arms item - /*0000*/ Color_Struct color_bracers; // Color of bracers item - /*0000*/ Color_Struct color_hands; // Color of hands item - /*0000*/ Color_Struct color_legs; // Color of legs item - /*0000*/ Color_Struct color_feet; // Color of feet item - /*0000*/ Color_Struct color_primary; // Color of primary item - /*0000*/ Color_Struct color_secondary; // Color of secondary item - } equipment_colors; - /*0000*/ Color_Struct colors[9]; // Array elements correspond to struct equipment_colors above - }; +/*0000*/ TintProfile equipment_tint; // skip these bytes if not a valid player race /*0000*/ union { struct { - /*0000*/ EquipStruct equip_helmet; // Equiptment: Helmet visual - /*0000*/ EquipStruct equip_chest; // Equiptment: Chest visual - /*0000*/ EquipStruct equip_arms; // Equiptment: Arms visual - /*0000*/ EquipStruct equip_bracers; // Equiptment: Wrist visual - /*0000*/ EquipStruct equip_hands; // Equiptment: Hands visual - /*0000*/ EquipStruct equip_legs; // Equiptment: Legs visual - /*0000*/ EquipStruct equip_feet; // Equiptment: Boots visual - /*0000*/ EquipStruct equip_primary; // Equiptment: Main visual - /*0000*/ EquipStruct equip_secondary; // Equiptment: Off visual + /*0000*/ Texture_Struct equip_helmet; // Equiptment: Helmet visual + /*0000*/ Texture_Struct equip_chest; // Equiptment: Chest visual + /*0000*/ Texture_Struct equip_arms; // Equiptment: Arms visual + /*0000*/ Texture_Struct equip_bracers; // Equiptment: Wrist visual + /*0000*/ Texture_Struct equip_hands; // Equiptment: Hands visual + /*0000*/ Texture_Struct equip_legs; // Equiptment: Legs visual + /*0000*/ Texture_Struct equip_feet; // Equiptment: Boots visual + /*0000*/ Texture_Struct equip_primary; // Equiptment: Main visual + /*0000*/ Texture_Struct equip_secondary; // Equiptment: Off visual } equip; - /*0000*/ EquipStruct equipment[9]; + /*0000*/ Texture_Struct equipment[9]; }; /*0000*/ //char title[0]; // only read if(hasTitleOrSuffix & 4) @@ -587,7 +624,7 @@ struct MemorizeSpell_Struct { uint32 slot; // Spot in the spell book/memorized slot uint32 spell_id; // Spell id (200 or c8 is minor healing, etc) uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming -uint32 unknown12; +uint32 reduction; // lowers reuse }; /* @@ -620,11 +657,12 @@ struct DeleteSpell_Struct struct ManaChange_Struct { - uint32 new_mana; // New Mana AMount - uint32 stamina; - uint32 spell_id; - uint32 unknown12; - uint32 unknown16; +/*00*/ uint32 new_mana; // New Mana AMount +/*04*/ uint32 stamina; +/*08*/ uint32 spell_id; +/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting? +/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like +/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it }; struct SwapSpell_Struct @@ -645,9 +683,12 @@ struct CastSpell_Struct { /*00*/ uint32 slot; /*04*/ uint32 spell_id; -/*08*/ ItemSlotStruct inventoryslot; // slot for clicky item, Seen unknown of 131 = normal cast +/*08*/ InventorySlot_Struct inventory_slot; // slot for clicky item, Seen unknown of 131 = normal cast /*20*/ uint32 target_id; -/*24*/ uint32 cs_unknown[5]; +/*24*/ uint32 cs_unknown[2]; +/*32*/ float y_pos; +/*36*/ float x_pos; +/*40*/ float z_pos; /*44*/ }; @@ -668,69 +709,31 @@ struct SpawnAppearance_Struct struct SpellBuff_Struct { -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ float unknown004; // Seen 1 for no buff -/*005*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*009*/ uint32 unknown016; -/*013*/ uint8 bard_modifier; -/*014*/ uint32 duration; -/*018*/ uint8 level; -/*019*/ uint32 spellid; -/*023*/ uint32 counters; -/*027*/ uint8 unknown0028[53]; -/*080*/ -}; - -struct SpellBuff_Struct_Old -{ -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; // not real -/*004*/ float unknown004; // Seen 1 for no buff -/*008*/ uint32 spellid; +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 unknown002; //pretty sure padding now +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ float bard_modifier; +/*008*/ uint32 spellid; /*012*/ uint32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*024*/ uint32 counters; -/*028*/ uint8 unknown0028[60]; +/*016*/ uint32 player_id; // caster ID, pretty sure just zone ID +/*020*/ uint32 num_hits; +/*024*/ float y; // referenced by SPA 441 +/*028*/ float x; // unsure if all buffs get them +/*032*/ float z; // as valid data +/*036*/ uint32 unknown036; +/*040*/ int32 slot_data[12]; // book keeping stuff per slot (counters, rune/vie) /*088*/ }; -// Not functional yet, but this is what the packet looks like on Live -struct SpellBuffFade_Struct_Live { -/*000*/ uint32 entityid; // Player id who cast the buff -/*004*/ uint8 unknown004; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown007; -/*008*/ float unknown008; -/*012*/ uint32 spellid; -/*016*/ uint32 duration; -/*020*/ uint32 playerId; // Global player ID? -/*024*/ uint32 num_hits; -/*028*/ uint8 unknown0028[64]; +struct SpellBuffPacket_Struct { +/*000*/ uint32 entityid; // Player id who cast the buff +/*004*/ SpellBuff_Struct buff; /*092*/ uint32 slotid; /*096*/ uint32 bufffade; /*100*/ }; -struct SpellBuffFade_Struct { -/*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ uint32 duration; -/*016*/ uint32 num_hits; -/*020*/ uint32 unknown020; // Global player ID? -/*024*/ uint32 playerId; // Player id who cast the buff -/*028*/ uint32 slotid; -/*032*/ uint32 bufffade; -/*036*/ -}; - struct BuffRemoveRequest_Struct { /*00*/ uint32 SlotID; @@ -863,7 +866,7 @@ struct AA_Array { uint32 AA; uint32 value; - uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live + uint32 charges; // expendable charges }; struct Disciplines_Struct { @@ -905,13 +908,13 @@ struct BandolierItem_Struct_Old struct Bandolier_Struct { char Name[1]; // Variable Length - BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; + BandolierItem_Struct Items[profile::BandolierItemCount]; }; struct Bandolier_Struct_Old { char Name[32]; - BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; + BandolierItem_Struct Items[profile::BandolierItemCount]; }; struct PotionBeltItem_Struct @@ -931,12 +934,12 @@ struct PotionBeltItem_Struct_Old struct PotionBelt_Struct { - PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; + PotionBeltItem_Struct Items[profile::PotionBeltSize]; }; struct PotionBelt_Struct_Old { - PotionBeltItem_Struct_Old Items[consts::POTION_BELT_ITEM_COUNT]; + PotionBeltItem_Struct_Old Items[profile::PotionBeltSize]; }; struct GroupLeadershipAA_Struct { @@ -1035,38 +1038,38 @@ union { struct { - /*00184*/ EquipStruct equip_helmet; // Equiptment: Helmet visual - /*00204*/ EquipStruct equip_chest; // Equiptment: Chest visual - /*00224*/ EquipStruct equip_arms; // Equiptment: Arms visual - /*00244*/ EquipStruct equip_bracers; // Equiptment: Wrist visual - /*00264*/ EquipStruct equip_hands; // Equiptment: Hands visual - /*00284*/ EquipStruct equip_legs; // Equiptment: Legs visual - /*00304*/ EquipStruct equip_feet; // Equiptment: Boots visual - /*00324*/ EquipStruct equip_primary; // Equiptment: Main visual - /*00344*/ EquipStruct equip_secondary; // Equiptment: Off visual + /*00184*/ Texture_Struct equip_helmet; // Equiptment: Helmet visual + /*00204*/ Texture_Struct equip_chest; // Equiptment: Chest visual + /*00224*/ Texture_Struct equip_arms; // Equiptment: Arms visual + /*00244*/ Texture_Struct equip_bracers; // Equiptment: Wrist visual + /*00264*/ Texture_Struct equip_hands; // Equiptment: Hands visual + /*00284*/ Texture_Struct equip_legs; // Equiptment: Legs visual + /*00304*/ Texture_Struct equip_feet; // Equiptment: Boots visual + /*00324*/ Texture_Struct equip_primary; // Equiptment: Main visual + /*00344*/ Texture_Struct equip_secondary; // Equiptment: Off visual // Below slots are just guesses, but all 0s anyway... - /*00364*/ EquipStruct equip_charm; // Equiptment: Non-visual - /*00384*/ EquipStruct equip_ear1; // Equiptment: Non-visual - /*00404*/ EquipStruct equip_ear2; // Equiptment: Non-visual - /*00424*/ EquipStruct equip_face; // Equiptment: Non-visual - /*00444*/ EquipStruct equip_neck; // Equiptment: Non-visual - /*00464*/ EquipStruct equip_shoulder; // Equiptment: Non-visual - /*00484*/ EquipStruct equip_bracer2; // Equiptment: Non-visual - /*00504*/ EquipStruct equip_range; // Equiptment: Non-visual - /*00524*/ EquipStruct equip_ring1; // Equiptment: Non-visual - /*00544*/ EquipStruct equip_ring2; // Equiptment: Non-visual - /*00564*/ EquipStruct equip_waist; // Equiptment: Non-visual - /*00584*/ EquipStruct equip_powersource; // Equiptment: Non-visual - /*00604*/ EquipStruct equip_ammo; // Equiptment: Non-visual + /*00364*/ Texture_Struct equip_charm; // Equiptment: Non-visual + /*00384*/ Texture_Struct equip_ear1; // Equiptment: Non-visual + /*00404*/ Texture_Struct equip_ear2; // Equiptment: Non-visual + /*00424*/ Texture_Struct equip_face; // Equiptment: Non-visual + /*00444*/ Texture_Struct equip_neck; // Equiptment: Non-visual + /*00464*/ Texture_Struct equip_shoulder; // Equiptment: Non-visual + /*00484*/ Texture_Struct equip_bracer2; // Equiptment: Non-visual + /*00504*/ Texture_Struct equip_range; // Equiptment: Non-visual + /*00524*/ Texture_Struct equip_ring1; // Equiptment: Non-visual + /*00544*/ Texture_Struct equip_ring2; // Equiptment: Non-visual + /*00564*/ Texture_Struct equip_waist; // Equiptment: Non-visual + /*00584*/ Texture_Struct equip_powersource; // Equiptment: Non-visual + /*00604*/ Texture_Struct equip_ammo; // Equiptment: Non-visual } equip; - /*00184*/ EquipStruct equipment[22]; + /*00184*/ Texture_Struct equipment[22]; }; /*00624*/ uint32 equip2_count; // Seen 9 -/*00628*/ EquipStruct equipment2[9]; // Appears to be Visible slots, but all 0s +/*00628*/ Texture_Struct equipment2[9]; // Appears to be Visible slots, but all 0s /*00808*/ uint32 tint_count; // Seen 9 -/*00812*/ Color_Struct item_tint[9]; // RR GG BB 00 +/*00812*/ TintProfile item_tint; // RR GG BB 00 /*00848*/ uint32 tint_count2; // Seen 9 -/*00852*/ Color_Struct item_tint2[9]; // RR GG BB 00 +/*00852*/ TintProfile item_tint2; // RR GG BB 00 /*00888*/ uint8 haircolor; // Player hair color /*00889*/ uint8 beardcolor; // Player beard color /*00890*/ uint32 unknown_rof5; // @@ -1146,7 +1149,7 @@ union /*12949*/ uint32 aapoints; // Unspent AA points - Seen 1 /*12953*/ uint16 unknown_rof20; // /*12955*/ uint32 bandolier_count; // Seen 20 -/*12959*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents +/*12959*/ Bandolier_Struct bandoliers[profile::BandoliersSize]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents /*13699*/ uint32 potionbelt_count; // Seen 5 /*13703*/ PotionBelt_Struct potionbelt; // [5] 45 bytes potion belt - (Variable Name Sizes) /*13748*/ int32 unknown_rof21; // Seen -1 @@ -1320,7 +1323,7 @@ struct TargetReject_Struct { struct PetCommand_Struct { /*00*/ uint32 command; -/*04*/ uint32 unknown04; +/*04*/ uint32 target; /*08*/ uint32 unknown08; }; @@ -1389,7 +1392,7 @@ struct WearChange_Struct{ /*010*/ uint32 elite_material; // 1 for Drakkin Elite Material /*014*/ uint32 hero_forge_model; // New to VoA /*018*/ uint32 unknown18; // New to RoF -/*022*/ Color_Struct color; +/*022*/ Tint_Struct color; /*026*/ uint8 wear_slot_id; /*027*/ }; @@ -1445,8 +1448,8 @@ struct RequestClientZoneChange_Struct { struct Animation_Struct { /*00*/ uint16 spawnid; -/*02*/ uint8 value; -/*03*/ uint8 action; +/*02*/ uint8 action; +/*03*/ uint8 speed; /*04*/ }; @@ -1511,9 +1514,11 @@ struct CombatDamage_Struct /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 05 */ uint32 spellid; /* 09 */ int32 damage; -/* 13 */ float unknown11; // cd cc cc 3d -/* 17 */ float sequence; // see above notes in Action_Struct -/* 21 */ uint8 unknown19[9]; // was [9] +/* 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] +/* 26 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage /* 30 */ }; @@ -1772,7 +1777,7 @@ struct BulkItemPacket_Struct struct Consume_Struct { -/*000*/ ItemSlotStruct slot; +/*000*/ InventorySlot_Struct inventory_slot; /*012*/ uint32 auto_consumed; // 0xffffffff when auto eating e7030000 when right click /*016*/ uint32 type; // 0x01=Food 0x02=Water /*020*/ uint32 c_unknown1; // Seen 2 @@ -1804,17 +1809,19 @@ struct ItemProperties_Struct { /*008*/ }; -struct DeleteItem_Struct { -/*0000*/ ItemSlotStruct from_slot; -/*0012*/ ItemSlotStruct to_slot; -/*0024*/ uint32 number_in_stack; +struct DeleteItem_Struct +{ +/*0000*/ InventorySlot_Struct from_slot; +/*0012*/ InventorySlot_Struct to_slot; +/*0024*/ uint32 number_in_stack; /*0028*/ }; -struct MoveItem_Struct { -/*0000*/ ItemSlotStruct from_slot; -/*0012*/ ItemSlotStruct to_slot; -/*0024*/ uint32 number_in_stack; +struct MoveItem_Struct +{ +/*0000*/ InventorySlot_Struct from_slot; +/*0012*/ InventorySlot_Struct to_slot; +/*0024*/ uint32 number_in_stack; /*0028*/ }; @@ -1884,6 +1891,114 @@ struct GuildUpdate_Struct { GuildsListEntry_Struct entry; }; +struct GuildBankAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +}; + +struct GuildBankDepositAck_Struct +{ +/*00*/ uint32 Action; // 10 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint32 Fail; //1 = Fail, 0 = Success +}; + +struct GuildBankPromote_Struct +{ +/*00*/ uint32 Action; // 3 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 Slot; +/*16*/ uint32 Slot2; // Always appears to be the same as Slot for Action code 3 +/*20*/ uint32 unknown20; +}; + +struct GuildBankPermissions_Struct +{ +/*00*/ uint32 Action; // 6 +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Unknown10; // Saw 1, probably indicating it is the main area rather than deposits +/*12*/ uint32 ItemID; +/*16*/ uint32 Permissions; +/*20*/ char MemberName[64]; +}; + +struct GuildBankViewItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; // 0 = Deposit area, 1 = Main area +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Unknown16; +}; + +struct GuildBankWithdrawItem_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*08*/ uint16 SlotID; +/*10*/ uint16 Area; +/*12*/ uint32 Unknown12; +/*16*/ uint32 Quantity; +/*20*/ +}; + +struct GuildBankItemUpdate_Struct +{ + void Init(uint32 inAction, uint32 inUnknown004, uint16 inSlotID, uint16 inArea, uint16 inUnknown012, uint32 inItemID, uint32 inIcon, uint32 inQuantity, + uint32 inPermissions, uint32 inAllowMerge, bool inUseable) + { + Action = inAction; + Unknown004 = inUnknown004; + SlotID = inSlotID; + Area = inArea; + Unknown012 = inUnknown012; + ItemID = inItemID; + Icon = inIcon; + Quantity = inQuantity; + Permissions = inPermissions; + AllowMerge = inAllowMerge; + Useable = inUseable; + ItemName[0] = '\0'; + Donator[0] = '\0'; + WhoFor[0] = '\0'; + }; + +/*000*/ uint32 Action; +/*004*/ uint32 Unknown004; +/*008*/ uint32 Unknown08; +/*012*/ uint16 SlotID; +/*014*/ uint16 Area; +/*016*/ uint32 Unknown012; +/*020*/ uint32 ItemID; +/*024*/ uint32 Icon; +/*028*/ uint32 Quantity; +/*032*/ uint32 Permissions; +/*036*/ uint8 AllowMerge; +/*037*/ uint8 Useable; // Used in conjunction with the Public-if-useable permission. +/*038*/ char ItemName[64]; +/*102*/ char Donator[64]; +/*166*/ char WhoFor[64]; +/*230*/ uint16 Unknown226; +}; + +struct GuildBankClear_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint32 Unknown04; +/*08*/ uint32 Unknown08; +/*12*/ uint32 DepositAreaCount; +/*16*/ uint32 MainAreaCount; +}; + /* ** Money Loot ** Length: 22 Bytes @@ -2139,7 +2254,7 @@ struct Merchant_Sell_Struct { struct Merchant_Purchase_Struct { /*000*/ uint32 npcid; // Merchant NPC's entity id -/*004*/ MainInvItemSlotStruct itemslot; +/*004*/ TypelessInventorySlot_Struct inventory_slot; /*012*/ uint32 quantity; /*016*/ uint32 price; /*020*/ @@ -2197,9 +2312,10 @@ struct AltCurrencyUpdate_Struct { //Client -> Server //When an item is selected while the alt currency merchant window is open -struct AltCurrencySelectItem_Struct { +struct AltCurrencySelectItem_Struct +{ /*000*/ uint32 merchant_entity_id; -/*004*/ MainInvItemSlotStruct slot_id; +/*004*/ TypelessInventorySlot_Struct inventory_slot; /*008*/ uint32 unknown008; /*012*/ uint32 unknown012; /*016*/ uint32 unknown016; @@ -2256,7 +2372,7 @@ struct AltCurrencyReclaim_Struct { struct AltCurrencySellItem_Struct { /*000*/ uint32 merchant_entity_id; -/*004*/ MainInvItemSlotStruct slot_id; +/*004*/ TypelessInventorySlot_Struct inventory_slot; /*008*/ uint32 charges; /*012*/ uint32 cost; }; @@ -2271,7 +2387,7 @@ struct Adventure_Purchase_Struct { struct Adventure_Sell_Struct { /*000*/ uint32 unknown000; //0x01 - Stack Size/Charges? /*004*/ uint32 npcid; -/*008*/ MainInvItemSlotStruct slot; +/*008*/ TypelessInventorySlot_Struct inventory_slot; /*016*/ uint32 charges; /*020*/ uint32 sell_price; /*024*/ @@ -2334,7 +2450,7 @@ struct AdventureLeaderboard_Struct /*struct Item_Shop_Struct { uint16 merchantid; uint8 itemtype; - Item_Struct item; + ItemBase item; uint8 iss_unknown001[6]; };*/ @@ -2497,7 +2613,7 @@ struct GroupFollow_Struct { // Live Follow Struct struct InspectBuffs_Struct { /*000*/ uint32 spell_id[BUFF_COUNT]; -/*168*/ uint32 tics_remaining[BUFF_COUNT]; +/*168*/ int32 tics_remaining[BUFF_COUNT]; }; struct LFG_Struct { @@ -2617,9 +2733,9 @@ struct Stun_Struct { // 8 bytes total struct AugmentItem_Struct { /*00*/ uint32 dest_inst_id; // The unique serial number for the item instance that is being augmented /*04*/ uint32 container_index; // Seen 0 -/*08*/ ItemSlotStruct container_slot; // Slot of the item being augmented +/*08*/ InventorySlot_Struct container_slot; // Slot of the item being augmented /*20*/ uint32 augment_index; // Seen 0 -/*24*/ ItemSlotStruct augment_slot; // Slot of the distiller to use (if one applies) +/*24*/ InventorySlot_Struct augment_slot; // Slot of the distiller to use (if one applies) /*36*/ int32 augment_action; // Guessed - 0 = augment, 1 = remove with distiller, 3 = delete aug /*36*/ //int32 augment_slot; /*40*/ @@ -2760,7 +2876,8 @@ struct Object_Struct { /*00*/ uint32 drop_id; // Unique object id for zone /*00*/ uint32 unknown024; // 53 9e f9 7e - same for all objects in the zone? /*00*/ float heading; // heading -/*00*/ float unknown032[2]; // 00 00 00 00 00 00 00 00 +/*00*/ float x_tilt; //Tilt entire object on X axis +/*00*/ float y_tilt; //Tilt entire object on Y axis /*00*/ float size; // Size - default 1 /*00*/ float z; // z coord /*00*/ float x; // x coord @@ -3494,27 +3611,6 @@ struct PetitionBug_Struct{ char text[1028]; }; -struct DyeStruct -{ - union - { - struct - { - struct Color_Struct head; - struct Color_Struct chest; - struct Color_Struct arms; - struct Color_Struct wrists; - struct Color_Struct hands; - struct Color_Struct legs; - struct Color_Struct feet; - struct Color_Struct primary; // you can't actually dye this - struct Color_Struct secondary; // or this - } - dyes; - struct Color_Struct dye[9]; - }; -}; - struct ApproveZone_Struct { char name[64]; uint32 zoneid; @@ -3578,7 +3674,7 @@ struct TributeInfo_Struct { struct TributeItem_Struct { -/*00*/ ItemSlotStruct slot; +/*00*/ InventorySlot_Struct inventory_slot; /*12*/ uint32 quantity; /*16*/ uint32 tribute_master_id; /*20*/ int32 tribute_points; @@ -3615,9 +3711,10 @@ struct Split_Struct ** Used In: OP_TradeSkillCombine ** Last Updated: 01-05-2013 */ -struct NewCombine_Struct { -/*00*/ ItemSlotStruct container_slot; -/*12*/ ItemSlotStruct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8) +struct NewCombine_Struct +{ +/*00*/ InventorySlot_Struct container_slot; +/*12*/ InventorySlot_Struct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8) /*24*/ }; @@ -3653,11 +3750,12 @@ struct RecipeReply_Struct { }; //received and sent back as an ACK with different reply_code -struct RecipeAutoCombine_Struct { +struct RecipeAutoCombine_Struct +{ /*00*/ uint32 object_type; /*04*/ uint32 some_id; -/*08*/ ItemSlotStruct container_slot; //echoed in reply - Was uint32 unknown1 -/*20*/ ItemSlotStruct unknown_slot; //echoed in reply +/*08*/ InventorySlot_Struct container_slot; //echoed in reply - Was uint32 unknown1 +/*20*/ InventorySlot_Struct unknown_slot; //echoed in reply /*32*/ uint32 recipe_id; /*36*/ uint32 reply_code; /*40*/ @@ -4248,9 +4346,9 @@ struct SendAA_Struct { /*0025*/ uint32 cost; /*0029*/ uint32 seq; /*0033*/ uint32 current_level; //1s, MQ2 calls this AARankRequired -/*0037*/ uint32 unknown037; // Introduced during HoT +/*0037*/ uint32 prereq_skill_count; // mutliple prereqs at least 1, even no prereqs /*0041*/ uint32 prereq_skill; //is < 0, abs() is category # -/*0045*/ uint32 unknown045; // New Mar 21 2012 - Seen 1 +/*0045*/ uint32 prereq_minpoints_count; // mutliple prereqs at least 1, even no prereqs /*0049*/ uint32 prereq_minpoints; //min points in the prereq /*0053*/ uint32 type; /*0057*/ uint32 spellid; @@ -4263,10 +4361,16 @@ struct SendAA_Struct { /*0081*/ uint32 last_id; /*0085*/ uint32 next_id; /*0089*/ uint32 cost2; -/*0093*/ uint8 unknown80[7]; +/*0093*/ uint8 unknown93; +/*0094*/ uint8 grant_only; // VetAAs, progression, etc +/*0095*/ uint8 unknown95; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though +/*0096*/ uint32 expendable_charges; // max charges of the AA /*0100*/ uint32 aa_expansion; /*0104*/ uint32 special_category; -/*0108*/ uint32 unknown0096; +/*0108*/ uint8 shroud; +/*0109*/ uint8 unknown109; +/*0110*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter? +/*0111*/ uint8 unknown111; /*0112*/ uint32 total_abilities; /*0116*/ AA_Ability abilities[0]; }; @@ -4278,18 +4382,11 @@ struct AA_List { struct AA_Action { /*00*/ uint32 action; /*04*/ uint32 ability; -/*08*/ uint32 unknown08; +/*08*/ uint32 target_id; /*12*/ uint32 exp_value; /*16*/ }; -struct AA_Skills { //this should be removed and changed to AA_Array -/*00*/ uint32 aa_skill; // Total AAs Spent -/*04*/ uint32 aa_value; -/*08*/ uint32 unknown08; -/*12*/ -}; - struct AAExpUpdate_Struct { /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*04*/ uint32 aapoints_unspent; @@ -4308,14 +4405,7 @@ struct AltAdvStats_Struct { }; struct PlayerAA_Struct { // Is this still used? - AA_Skills aa_list[MAX_PP_AA_ARRAY]; -}; - -struct AA_Values { -/*00*/ uint32 aa_skill; -/*04*/ uint32 aa_value; -/*08*/ uint32 unknown08; -/*12*/ + AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct AATable_Struct { @@ -4325,7 +4415,7 @@ struct AATable_Struct { /*12*/ uint32 aa_spent_archetype; // Seen 40 /*16*/ uint32 aa_spent_class; // Seen 103 /*20*/ uint32 aa_spent_special; // Seen 0 -/*24*/ AA_Values aa_list[MAX_PP_AA_ARRAY]; +/*24*/ AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct Weather_Struct { @@ -4380,19 +4470,22 @@ struct ExpansionInfo_Struct { /*064*/ uint32 Expansions; }; -struct ApplyPoison_Struct { - MainInvItemSlotStruct inventorySlot; +struct ApplyPoison_Struct +{ + TypelessInventorySlot_Struct inventory_slot; uint32 success; }; -struct ItemVerifyRequest_Struct { -/*000*/ ItemSlotStruct slot; +struct ItemVerifyRequest_Struct +{ +/*000*/ InventorySlot_Struct inventory_slot; /*012*/ uint32 target; // Target Entity ID /*016*/ }; -struct ItemVerifyReply_Struct { -/*000*/ ItemSlotStruct slot; +struct ItemVerifyReply_Struct +{ +/*000*/ InventorySlot_Struct inventory_slot; /*012*/ uint32 spell; // Spell ID to cast if different than item effect /*016*/ uint32 target; // Target Entity ID /*020*/ @@ -4414,7 +4507,7 @@ struct ItemSerializationHeader /*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ? /*026*/ uint16 main_slot; /*028*/ uint16 sub_slot; -/*030*/ uint16 unknown013; // 0xffff +/*030*/ uint16 aug_slot; // 0xffff /*032*/ uint32 price; /*036*/ uint32 merchant_slot; //1 if not a merchant item /*040*/ uint32 scaled_value; //0 @@ -4626,7 +4719,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4641,7 +4734,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4678,7 +4771,7 @@ struct ItemQuaternaryBodyStruct int32 HeroicSVCorrup; int32 HealAmt; int32 SpellDmg; - int32 clairvoyance; + int32 Clairvoyance; uint8 unknown18; //Power Source Capacity or evolve filename? uint32 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; @@ -4705,7 +4798,6 @@ struct ItemQuaternaryBodyStruct uint32 unknown_RoF8; uint8 unknown38; // 0 uint8 unknown39; // 1 - uint32 subitem_count; }; struct AugmentInfo_Struct @@ -4940,7 +5032,8 @@ struct MercenaryMerchantResponse_Struct { /*0004*/ }; - }; //end namespace structs -}; //end namespace RoF + }; /*structs*/ -#endif /*ROF_STRUCTS_H_*/ +}; /*RoF*/ + +#endif /*COMMON_ROF_STRUCTS_H*/ diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index adf4ec06f..e23c1ca78 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1,4 +1,24 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #include "../global_define.h" +#include "../eqemu_config.h" #include "../eqemu_logsys.h" #include "sod.h" #include "../opcodemgr.h" @@ -16,13 +36,14 @@ #include #include + namespace SoD { static const char *name = "SoD"; static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id, uint8 depth); // server to client inventory location converters static inline uint32 ServerToSoDSlot(uint32 ServerSlot); @@ -38,12 +59,17 @@ namespace SoD // client to server text link converter static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink); + static inline CastingSlot ServerToSoDCastingSlot(EQEmu::CastingSlot slot); + static inline EQEmu::CastingSlot SoDToServerCastingSlot(CastingSlot slot); + void Register(EQStreamIdentifier &into) { //create our opcode manager if we havent already if (opcodes == nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; //load up the opcode manager. @@ -87,7 +113,9 @@ namespace SoD if (opcodes != nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; if (!opcodes->ReloadOpcodes(opfile.c_str())) { @@ -113,9 +141,9 @@ namespace SoD return(r); } - const ClientVersion Strategy::GetClientVersion() const + const EQEmu::versions::ClientVersion Strategy::ClientVersion() const { - return ClientVersion::SoD; + return EQEmu::versions::ClientVersion::SoD; } #include "ss_define.h" @@ -276,16 +304,17 @@ namespace SoD ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - OUT(slot); - OUT(level); - OUT(effect); - //eq->unknown7 = 10; - OUT(spellid); - OUT(duration); + OUT(buff.effect_type); + OUT(buff.level); + OUT(buff.bard_modifier); + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.counters); + OUT(buff.player_id); OUT(slotid); OUT(bufffade); @@ -335,71 +364,50 @@ namespace SoD ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { - + if (!in->size) { in->size = 4; - in->pBuffer = new uchar[in->size]; - - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); - return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(EQEmu::InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(EQEmu::InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", - opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); + opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(EQEmu::InternalSerializedItem_Struct)); delete in; return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + EQEmu::InternalSerializedItem_Struct* eq = (EQEmu::InternalSerializedItem_Struct*)in->pBuffer; - for (int r = 0; r < ItemCount; r++, eq++) { + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); - uint32 Length = 0; - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); + ob.write((const char*)&item_count, sizeof(uint32)); - if (Serialized) { + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ob, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - uchar *OldBuffer = in->pBuffer; - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ob.tellp(); } + in->size = ob.size(); + in->pBuffer = ob.detach(); + delete[] __emu_buffer; - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); - dest->FastQueuePacket(&in, ack_req); } @@ -446,7 +454,10 @@ namespace SoD OUT(type); OUT(spellid); OUT(damage); - eq->sequence = emu->sequence; + OUT(force); + OUT(meleepush_xy); + OUT(meleepush_z); + OUT(special); FINISH_ENCODE(); } @@ -771,7 +782,8 @@ namespace SoD { //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct)); structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); @@ -789,7 +801,8 @@ namespace SoD //if(gjs->action == groupActLeave) // Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct)); structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); @@ -826,7 +839,7 @@ namespace SoD //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Leadername is %s", gu2->leadersname); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupUpdateB, PacketLength); + auto outapp = new EQApplicationPacket(OP_GroupUpdateB, PacketLength); char *Buffer = (char *)outapp->pBuffer; // Header @@ -890,7 +903,8 @@ namespace SoD memcpy(eq->membername, emu->membername, sizeof(eq->membername)); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); GroupLeadershipAAUpdate_Struct *GLAAus = (GroupLeadershipAAUpdate_Struct*)outapp->pBuffer; GLAAus->NPCMarkerID = emu->NPCMarkerID; @@ -1033,29 +1047,31 @@ namespace SoD ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; + + EQEmu::InternalSerializedItem_Struct* int_struct = (EQEmu::InternalSerializedItem_Struct*)(&__emu_buffer[4]); - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); - if (!serialized) { + ob.write((const char*)__emu_buffer, 4); + + SerializeItem(ob, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ob.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + in->size = ob.size(); + in->pBuffer = ob.detach(); + delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -1123,7 +1139,8 @@ namespace SoD OUT(new_mana); OUT(stamina); OUT(spell_id); - eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2? + OUT(keepcasting); + eq->slot = -1; // this is spell gem slot. It's -1 in normal operation FINISH_ENCODE(); } @@ -1151,7 +1168,7 @@ namespace SoD PacketSize += sizeof(structs::MercenaryStance_Struct) * emu->Mercs[r].StanceCount; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, PacketSize); + auto outapp = new EQApplicationPacket(OP_MercenaryDataResponse, PacketSize); Buffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercTypeCount); @@ -1486,7 +1503,7 @@ namespace SoD VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petid); VARSTRUCT_ENCODE_TYPE(uint16, Buffer, emu->buffcount); - for (unsigned int i = 0; i < BUFF_COUNT; ++i) + for (unsigned int i = 0; i < PET_BUFF_COUNT; ++i) { if (emu->spellid[i]) { @@ -1497,7 +1514,7 @@ namespace SoD } } - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount); // I think this is actually some sort of type delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); @@ -1541,14 +1558,14 @@ namespace SoD OUT(hairstyle); OUT(beard); // OUT(unknown00178[10]); - for (r = 0; r < 9; r++) { - eq->equipment[r].Material = emu->item_material[r]; - eq->equipment[r].Unknown1 = 0; - eq->equipment[r].EliteMaterial = 0; + for (r = EQEmu::textures::TextureBegin; r < EQEmu::textures::TextureCount; r++) { + eq->equipment.Slot[r].Material = emu->item_material.Slot[r].Material; + eq->equipment.Slot[r].Unknown1 = 0; + eq->equipment.Slot[r].EliteMaterial = 0; //eq->colors[r].color = emu->colors[r].color; } for (r = 0; r < 7; r++) { - OUT(item_tint[r].Color); + OUT(item_tint.Slot[r].Color); } // OUT(unknown00224[48]); //NOTE: new client supports 300 AAs, our internal rep/PP @@ -1556,6 +1573,7 @@ namespace SoD for (r = 0; r < MAX_PP_AA_ARRAY; r++) { OUT(aa_array[r].AA); OUT(aa_array[r].value); + OUT(aa_array[r].charges); } // OUT(unknown02220[4]); OUT(mana); @@ -1589,10 +1607,10 @@ namespace SoD OUT(thirst_level); OUT(hunger_level); for (r = 0; r < structs::BUFF_COUNT; r++) { - OUT(buffs[r].slotid); + OUT(buffs[r].effect_type); OUT(buffs[r].level); OUT(buffs[r].bard_modifier); - OUT(buffs[r].effect); + OUT(buffs[r].unknown003); OUT(buffs[r].spellid); OUT(buffs[r].duration); OUT(buffs[r].counters); @@ -1610,18 +1628,18 @@ namespace SoD // OUT(unknown06160[4]); // Copy bandoliers where server and client indexes converge - for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { + for (r = 0; r < EQEmu::legacy::BANDOLIERS_SIZE && r < profile::BandoliersSize; ++r) { OUT_str(bandoliers[r].Name); - for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + for (uint32 k = 0; k < profile::BandolierItemCount; ++k) { // Will need adjusting if 'server != client' is ever true OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } // Nullify bandoliers where server and client indexes diverge, with a client bias - for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + for (r = EQEmu::legacy::BANDOLIERS_SIZE; r < profile::BandoliersSize; ++r) { eq->bandoliers[r].Name[0] = '\0'; - for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + for (uint32 k = 0; k < profile::BandolierItemCount; ++k) { // Will need adjusting if 'server != client' is ever true eq->bandoliers[r].Items[k].ID = 0; eq->bandoliers[r].Items[k].Icon = 0; eq->bandoliers[r].Items[k].Name[0] = '\0'; @@ -1631,13 +1649,13 @@ namespace SoD // OUT(unknown07444[5120]); // Copy potion belt where server and client indexes converge - for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (r = 0; r < EQEmu::legacy::POTION_BELT_ITEM_COUNT && r < profile::PotionBeltSize; ++r) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); } // Nullify potion belt where server and client indexes diverge, with a client bias - for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (r = EQEmu::legacy::POTION_BELT_ITEM_COUNT; r < profile::PotionBeltSize; ++r) { eq->potionbelt.Items[r].ID = 0; eq->potionbelt.Items[r].Icon = 0; eq->potionbelt.Items[r].Name[0] = '\0'; @@ -1674,8 +1692,8 @@ namespace SoD OUT(copper_bank); OUT(platinum_shared); // OUT(unknown13156[84]); - //OUT(expansions); - eq->expansions = 16383; + OUT(expansions); + //eq->expansions = 16383; // OUT(unknown13244[12]); OUT(autosplit); // OUT(unknown13260[16]); @@ -1762,7 +1780,7 @@ namespace SoD unsigned char * __emu_buffer = inapp->pBuffer; RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer; general->action = 8; @@ -1785,7 +1803,7 @@ namespace SoD { RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer; add_member->raidGen.action = in_add_member->raidGen.action; @@ -1805,7 +1823,8 @@ namespace SoD else if (raid_gen->action == 35) { RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + strlen(inmotd->motd) + 1); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + + strlen(inmotd->motd) + 1); structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer; outmotd->general.action = inmotd->general.action; @@ -1816,7 +1835,8 @@ namespace SoD else if (raid_gen->action == 14 || raid_gen->action == 30) { RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; outlaa->action = inlaa->action; @@ -1829,7 +1849,7 @@ namespace SoD { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer; strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64); strn0cpy(raid_general->player_name, in_raid_general->player_name, 64); @@ -1859,54 +1879,57 @@ namespace SoD ENCODE(OP_SendAATable) { - ENCODE_LENGTH_ATLEAST(SendAA_Struct); - SETUP_VAR_ENCODE(SendAA_Struct); - ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); + EQApplicationPacket *inapp = *p; + *p = nullptr; + AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer; - // Check clientver field to verify this AA should be sent for SoF - // clientver 1 is for all clients and 5 is for SoD - if (emu->clientver <= 5) - { - OUT(id); - eq->unknown004 = 1; - //eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->title_sid = emu->id - emu->current_level + 1; - //eq->desc_sid = emu->id - emu->current_level + 1; - eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->sof_next_skill); - eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->sof_next_skill); - eq->title_sid = emu->sof_next_skill; - eq->desc_sid = emu->sof_next_skill; - OUT(class_type); - OUT(cost); - OUT(seq); - OUT(current_level); - OUT(prereq_skill); - OUT(prereq_minpoints); - eq->type = emu->sof_type; - OUT(spellid); - OUT(spell_type); - OUT(spell_refresh); - OUT(classes); - OUT(berserker); - //eq->max_level = emu->sof_max_level; - OUT(max_level); - OUT(last_id); - OUT(next_id); - OUT(cost2); - eq->aa_expansion = emu->aa_expansion; - eq->special_category = emu->special_category; - OUT(total_abilities); - unsigned int r; - for (r = 0; r < emu->total_abilities; r++) { - OUT(abilities[r].skill_id); - OUT(abilities[r].base1); - OUT(abilities[r].base2); - OUT(abilities[r].slot); - } + auto outapp = new EQApplicationPacket( + OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability)); + structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer; + + inapp->SetReadPosition(sizeof(AARankInfo_Struct)); + outapp->SetWritePosition(sizeof(structs::SendAA_Struct)); + + eq->id = emu->id; + eq->unknown004 = 1; + eq->id = emu->id; + eq->hotkey_sid = emu->upper_hotkey_sid; + eq->hotkey_sid2 = emu->lower_hotkey_sid; + eq->desc_sid = emu->desc_sid; + eq->title_sid = emu->title_sid; + eq->class_type = emu->level_req; + eq->cost = emu->cost; + eq->seq = emu->seq; + eq->current_level = emu->current_level; + eq->type = emu->type; + eq->spellid = emu->spell; + eq->spell_type = emu->spell_type; + eq->spell_refresh = emu->spell_refresh; + eq->classes = emu->classes; + eq->max_level = emu->max_level; + eq->last_id = emu->prev_id; + eq->next_id = emu->next_id; + eq->cost2 = emu->total_cost; + eq->grant_only = emu->grant_only; + eq->expendable_charges = emu->charges; + eq->aa_expansion = emu->expansion; + eq->special_category = emu->category; + eq->total_abilities = emu->total_effects; + + for(auto i = 0; i < eq->total_abilities; ++i) { + eq->abilities[i].skill_id = inapp->ReadUInt32(); + eq->abilities[i].base1 = inapp->ReadUInt32(); + eq->abilities[i].base2 = inapp->ReadUInt32(); + eq->abilities[i].slot = inapp->ReadUInt32(); } - FINISH_ENCODE(); + if(emu->total_prereqs > 0) { + eq->prereq_skill = inapp->ReadUInt32(); + eq->prereq_minpoints = inapp->ReadUInt32(); + } + + dest->FastQueuePacket(&outapp); + delete inapp; } ENCODE(OP_SendCharInfo) @@ -1920,8 +1943,8 @@ namespace SoD eq->CharCount = emu->CharCount; eq->TotalChars = emu->TotalChars; - if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) - eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; + if (eq->TotalChars > constants::CharacterCreationLimit) + eq->TotalChars = constants::CharacterCreationLimit; FINISH_ENCODE(); return; @@ -1933,7 +1956,7 @@ namespace SoD size_t names_length = 0; size_t character_count = 0; - for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) { + for (; character_count < emu->CharCount && character_count < constants::CharacterCreationLimit; ++character_count) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; names_length += strlen(emu_cse->Name); emu_ptr += sizeof(CharacterSelectEntry_Struct); @@ -1949,8 +1972,8 @@ namespace SoD eq->CharCount = character_count; eq->TotalChars = emu->TotalChars; - if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) - eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; + if (eq->TotalChars > constants::CharacterCreationLimit) + eq->TotalChars = constants::CharacterCreationLimit; emu_ptr = __emu_buffer; emu_ptr += sizeof(CharacterSelect_Struct); @@ -1960,25 +1983,26 @@ namespace SoD for (int counter = 0; counter < character_count; ++counter) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address eq_cse->Level = emu_cse->Level; eq_cse->HairStyle = emu_cse->HairStyle; eq_cse->Gender = emu_cse->Gender; strcpy(eq_cse->Name, emu_cse->Name); - eq_ptr += strlen(eq_cse->Name); - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_ptr += strlen(emu_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset) + eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)] eq_cse->Beard = emu_cse->Beard; eq_cse->HairColor = emu_cse->HairColor; eq_cse->Face = emu_cse->Face; - for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) { + for (int equip_index = 0; equip_index < EQEmu::textures::TextureCount; equip_index++) { eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material; eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1; eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial; - eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; + eq_cse->Equip[equip_index].Color = emu_cse->Equip[equip_index].Color; } eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile; @@ -2200,25 +2224,6 @@ namespace SoD ptr += sizeof(uint32); ptr += 1; } - /*std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - uint8 write_var8 = 1; - ss.write((const char*)&emu->entity_id, sizeof(uint32)); - ss.write((const char*)&emu->count, sizeof(uint16)); - write_var8 = 0; - for(uint16 i = 0; i < emu->count; ++i) - { - ss.write((const char*)&emu->entries[i].buff_slot, sizeof(uint32)); - ss.write((const char*)&emu->entries[i].spell_id, sizeof(uint32)); - ss.write((const char*)&emu->entries[i].tics_remaining, sizeof(uint32)); - ss.write((const char*)&write_var8, sizeof(uint8)); - } - - __packet->size = ss.str().length(); - __packet->pBuffer = new unsigned char[__packet->size]; - memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size); - */ - FINISH_ENCODE(); } @@ -2359,7 +2364,8 @@ namespace SoD uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward)); *p = nullptr; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count)); + auto outapp_create = + new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward) * count)); uchar *old_data = __emu_buffer; uchar *data = outapp_create->pBuffer; for (unsigned int i = 0; i < count; ++i) @@ -2411,7 +2417,7 @@ namespace SoD int Count = wars->playercount; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_WhoAllResponse, in->size + (Count * 4)); + auto outapp = new EQApplicationPacket(OP_WhoAllResponse, in->size + (Count * 4)); char *OutBuffer = (char *)outapp->pBuffer; @@ -2562,7 +2568,7 @@ namespace SoD float SpawnSize = emu->size; if (!((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))) { - PacketSize -= (sizeof(structs::EquipStruct) * 9); + PacketSize -= (sizeof(structs::Texture_Struct) * EQEmu::textures::TextureCount); if (emu->size == 0) { @@ -2576,7 +2582,7 @@ namespace SoD SpawnSize = 3; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ZoneEntry, PacketSize); + auto outapp = new EQApplicationPacket(OP_ZoneEntry, PacketSize); Buffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_STRING(Buffer, emu->name); @@ -2735,7 +2741,7 @@ namespace SoD VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown12 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13 - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown14 - Stance 64 = normal 4 = aggressive 40 = stun/mezzed + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17 @@ -2759,10 +2765,10 @@ namespace SoD if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)) { - for (k = 0; k < 9; ++k) + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; ++k) { { - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment_tint.Slot[k].Color); } } } @@ -2772,11 +2778,11 @@ namespace SoD VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment.Primary.Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment.Secondary.Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); } @@ -2784,15 +2790,15 @@ namespace SoD if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)) { - structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer; + structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer; - for (k = 0; k < 9; k++) { - Equipment[k].Material = emu->equipment[k].Material; - Equipment[k].Unknown1 = emu->equipment[k].Unknown1; - Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; k++) { + Equipment[k].Material = emu->equipment.Slot[k].Material; + Equipment[k].Unknown1 = emu->equipment.Slot[k].Unknown1; + Equipment[k].EliteMaterial = emu->equipment.Slot[k].EliteMaterial; } - Buffer += (sizeof(structs::EquipStruct) * 9); + Buffer += (sizeof(structs::Texture_Struct) * EQEmu::textures::TextureCount); } if (strlen(emu->title)) { @@ -2906,15 +2912,16 @@ namespace SoD DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.bard_modifier); + IN(buff.spellid); + IN(buff.duration); + IN(buff.counters) IN(slotid); IN(bufffade); @@ -2945,6 +2952,7 @@ namespace SoD DECODE_LENGTH_EXACT(structs::CastSpell_Struct); SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct); + emu->slot = static_cast(SoDToServerCastingSlot(static_cast(eq->slot))); IN(slot); IN(spell_id); emu->inventoryslot = SoDToServerSlot(eq->inventoryslot); @@ -3349,7 +3357,7 @@ namespace SoD default: emu->command = eq->command; } - OUT(unknown); + IN(target); FINISH_DIRECT_DECODE(); } @@ -3543,34 +3551,26 @@ namespace SoD return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); + const EQEmu::ItemBase *item = inst->GetUnscaledItem(); + SoD::structs::ItemSerializationHeader hdr; - hdr.stacksize = stackable ? charges : 1; + + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; int32 slot_id = ServerToSoDSlot(slot_id_in); - hdr.slot = (merchant_slot == 0) ? slot_id : merchant_slot; + hdr.slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; @@ -3580,43 +3580,26 @@ namespace SoD hdr.unknown062 = 0; hdr.ItemClass = item->ItemClass; - ss.write((const char*)&hdr, sizeof(SoD::structs::ItemSerializationHeader)); + ob.write((const char*)&hdr, sizeof(SoD::structs::ItemSerializationHeader)); if (strlen(item->Name) > 0) - { - ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Name, strlen(item->Name)); + ob.write("\0", 1); if (strlen(item->Lore) > 0) - { - ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Lore, strlen(item->Lore)); + ob.write("\0", 1); if (strlen(item->IDFile) > 0) - { - ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->IDFile, strlen(item->IDFile)); + ob.write("\0", 1); SoD::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(SoD::structs::ItemBodyStruct)); ibs.id = item->ID; - ibs.weight = item->Weight; + // weight is uint8 in the struct, and some weights exceed that, so capping at 255. + ibs.weight = ((item->Weight > 255) ? 255 : item->Weight); ibs.norent = item->NoRent; ibs.nodrop = item->NoDrop; ibs.attune = item->Attuneable; @@ -3653,7 +3636,7 @@ namespace SoD ibs.Races = item->Races; ibs.Deity = item->Deity; ibs.SkillModValue = item->SkillModValue; - ibs.unknown6 = 0; + ibs.SkillModMax = item->SkillModMax; ibs.SkillModType = item->SkillModType; ibs.BaneDmgRace = item->BaneDmgRace; ibs.BaneDmgBody = item->BaneDmgBody; @@ -3698,18 +3681,12 @@ namespace SoD ibs.FactionAmt4 = item->FactionAmt4; ibs.FactionMod4 = item->FactionMod4; - ss.write((const char*)&ibs, sizeof(SoD::structs::ItemBodyStruct)); + ob.write((const char*)&ibs, sizeof(SoD::structs::ItemBodyStruct)); //charm text if (strlen(item->CharmFile) > 0) - { - ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->CharmFile, strlen(item->CharmFile)); + ob.write("\0", 1); SoD::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(SoD::structs::ItemSecondaryBodyStruct)); @@ -3717,11 +3694,10 @@ namespace SoD isbs.augtype = item->AugType; isbs.augrestrict = item->AugRestrict; - for (int x = 0; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < invaug::ItemAugSize; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -3738,17 +3714,11 @@ namespace SoD isbs.book = item->Book; isbs.booktype = item->BookType; - ss.write((const char*)&isbs, sizeof(SoD::structs::ItemSecondaryBodyStruct)); + ob.write((const char*)&isbs, sizeof(SoD::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { - ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->Filename, strlen(item->Filename)); + ob.write("\0", 1); SoD::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(SoD::structs::ItemTertiaryBodyStruct)); @@ -3768,11 +3738,11 @@ namespace SoD itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; - ss.write((const char*)&itbs, sizeof(SoD::structs::ItemTertiaryBodyStruct)); + ob.write((const char*)&itbs, sizeof(SoD::structs::ItemTertiaryBodyStruct)); // Effect Structures Broken down to allow variable length strings for effect names int32 effect_unknown = 0; @@ -3789,19 +3759,13 @@ namespace SoD ices.recast = item->RecastDelay; ices.recast_type = item->RecastType; - ss.write((const char*)&ices, sizeof(SoD::structs::ClickEffectStruct)); + ob.write((const char*)&ices, sizeof(SoD::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { - ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ClickName, strlen(item->ClickName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 + ob.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 SoD::structs::ProcEffectStruct ipes; memset(&ipes, 0, sizeof(SoD::structs::ProcEffectStruct)); @@ -3812,19 +3776,13 @@ namespace SoD ipes.level = item->Proc.Level; ipes.procrate = item->ProcRate; - ss.write((const char*)&ipes, sizeof(SoD::structs::ProcEffectStruct)); + ob.write((const char*)&ipes, sizeof(SoD::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { - ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ProcName, strlen(item->ProcName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 SoD::structs::WornEffectStruct iwes; memset(&iwes, 0, sizeof(SoD::structs::WornEffectStruct)); @@ -3834,19 +3792,13 @@ namespace SoD iwes.type = item->Worn.Type; iwes.level = item->Worn.Level; - ss.write((const char*)&iwes, sizeof(SoD::structs::WornEffectStruct)); + ob.write((const char*)&iwes, sizeof(SoD::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { - ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->WornName, strlen(item->WornName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 SoD::structs::WornEffectStruct ifes; memset(&ifes, 0, sizeof(SoD::structs::WornEffectStruct)); @@ -3856,19 +3808,13 @@ namespace SoD ifes.type = item->Focus.Type; ifes.level = item->Focus.Level; - ss.write((const char*)&ifes, sizeof(SoD::structs::WornEffectStruct)); + ob.write((const char*)&ifes, sizeof(SoD::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { - ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->FocusName, strlen(item->FocusName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 SoD::structs::WornEffectStruct ises; memset(&ises, 0, sizeof(SoD::structs::WornEffectStruct)); @@ -3878,19 +3824,13 @@ namespace SoD ises.type = item->Scroll.Type; ises.level = item->Scroll.Level; - ss.write((const char*)&ises, sizeof(SoD::structs::WornEffectStruct)); + ob.write((const char*)&ises, sizeof(SoD::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { - ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ScrollName, strlen(item->ScrollName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects SoD::structs::ItemQuaternaryBodyStruct iqbs; @@ -3918,83 +3858,54 @@ namespace SoD iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - iqbs.clairvoyance = item->Clairvoyance; + iqbs.Clairvoyance = item->Clairvoyance; + + ob.write((const char*)&iqbs, sizeof(SoD::structs::ItemQuaternaryBodyStruct)); - iqbs.subitem_count = 0; + EQEmu::OutBuffer::pos_type count_pos = ob.tellp(); + uint32 subitem_count = 0; - char *SubSerializations[10]; // + ob.write((const char*)&subitem_count, sizeof(uint32)); - uint32 SubLengths[10]; + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; - for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; ++x) { + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; - SubSerializations[x] = nullptr; + ob.write((const char*)&index, sizeof(uint32)); - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); - - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EmuConstants::GENERAL_BEGIN && slot_id_in <= EmuConstants::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EmuConstants::BANK_BEGIN && slot_id_in <= EmuConstants::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EmuConstants::SHARED_BANK_BEGIN && slot_id_in <= EmuConstants::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::SHARED_BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); - } + SerializeItem(ob, sub, SubSlotNumber, (depth + 1)); + ++subitem_count; } - ss.write((const char*)&iqbs, sizeof(SoD::structs::ItemQuaternaryBodyStruct)); - - for (int x = 0; x < 10; ++x) { - - if (SubSerializations[x]) { - - ss.write((const char*)&x, sizeof(uint32)); - - ss.write(SubSerializations[x], SubLengths[x]); - - safe_delete_array(SubSerializations[x]); - } - } - - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); - - *length = ss.tellp(); - return item_serial; + if (subitem_count) + ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32)); } static inline uint32 ServerToSoDSlot(uint32 serverSlot) { uint32 SoDSlot = 0; - if (serverSlot >= MainAmmo && serverSlot <= 53) // Cursor/Ammo/Power Source and Normal Inventory Slots + if (serverSlot >= EQEmu::legacy::SlotAmmo && serverSlot <= 53) // Cursor/Ammo/Power Source and Normal Inventory Slots SoDSlot = serverSlot + 1; - else if (serverSlot >= EmuConstants::GENERAL_BAGS_BEGIN && serverSlot <= EmuConstants::CURSOR_BAG_END) + else if (serverSlot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::legacy::CURSOR_BAG_END) SoDSlot = serverSlot + 11; - else if (serverSlot >= EmuConstants::BANK_BAGS_BEGIN && serverSlot <= EmuConstants::BANK_BAGS_END) + else if (serverSlot >= EQEmu::legacy::BANK_BAGS_BEGIN && serverSlot <= EQEmu::legacy::BANK_BAGS_END) SoDSlot = serverSlot + 1; - else if (serverSlot >= EmuConstants::SHARED_BANK_BAGS_BEGIN && serverSlot <= EmuConstants::SHARED_BANK_BAGS_END) + else if (serverSlot >= EQEmu::legacy::SHARED_BANK_BAGS_BEGIN && serverSlot <= EQEmu::legacy::SHARED_BANK_BAGS_END) SoDSlot = serverSlot + 1; - else if (serverSlot == MainPowerSource) - SoDSlot = slots::MainPowerSource; + else if (serverSlot == EQEmu::legacy::SlotPowerSource) + SoDSlot = invslot::PossessionsPowerSource; else SoDSlot = serverSlot; return SoDSlot; @@ -4010,16 +3921,16 @@ namespace SoD { uint32 ServerSlot = 0; - if (sodSlot >= slots::MainAmmo && sodSlot <= consts::CORPSE_END) // Cursor/Ammo/Power Source and Normal Inventory Slots + if (sodSlot >= invslot::PossessionsAmmo && sodSlot <= invslot::CorpseEnd) // Cursor/Ammo/Power Source and Normal Inventory Slots ServerSlot = sodSlot - 1; - else if (sodSlot >= consts::GENERAL_BAGS_BEGIN && sodSlot <= consts::CURSOR_BAG_END) + else if (sodSlot >= invbag::GeneralBagsBegin && sodSlot <= invbag::CursorBagEnd) ServerSlot = sodSlot - 11; - else if (sodSlot >= consts::BANK_BAGS_BEGIN && sodSlot <= consts::BANK_BAGS_END) + else if (sodSlot >= invbag::BankBagsBegin && sodSlot <= invbag::BankBagsEnd) ServerSlot = sodSlot - 1; - else if (sodSlot >= consts::SHARED_BANK_BAGS_BEGIN && sodSlot <= consts::SHARED_BANK_BAGS_END) + else if (sodSlot >= invbag::SharedBankBagsBegin && sodSlot <= invbag::SharedBankBagsEnd) ServerSlot = sodSlot - 1; - else if (sodSlot == slots::MainPowerSource) - ServerSlot = MainPowerSource; + else if (sodSlot == invslot::PossessionsPowerSource) + ServerSlot = EQEmu::legacy::SlotPowerSource; else ServerSlot = sodSlot; return ServerSlot; @@ -4033,7 +3944,7 @@ namespace SoD static inline void ServerToSoDTextLink(std::string& sodTextLink, const std::string& serverTextLink) { - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { + if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { sodTextLink = serverTextLink; return; } @@ -4042,7 +3953,7 @@ namespace SoD for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { sodTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -4073,7 +3984,7 @@ namespace SoD static inline void SoDToServerTextLink(std::string& serverTextLink, const std::string& sodTextLink) { - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sodTextLink.find('\x12') == std::string::npos)) { + if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (sodTextLink.find('\x12') == std::string::npos)) { serverTextLink = sodTextLink; return; } @@ -4082,7 +3993,7 @@ namespace SoD for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= constants::SayLinkBodySize) { serverTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -4106,5 +4017,73 @@ namespace SoD } } } -} -// end namespace SoD + + static inline CastingSlot ServerToSoDCastingSlot(EQEmu::CastingSlot slot) + { + switch (slot) { + case EQEmu::CastingSlot::Gem1: + return CastingSlot::Gem1; + case EQEmu::CastingSlot::Gem2: + return CastingSlot::Gem2; + case EQEmu::CastingSlot::Gem3: + return CastingSlot::Gem3; + case EQEmu::CastingSlot::Gem4: + return CastingSlot::Gem4; + case EQEmu::CastingSlot::Gem5: + return CastingSlot::Gem5; + case EQEmu::CastingSlot::Gem6: + return CastingSlot::Gem6; + case EQEmu::CastingSlot::Gem7: + return CastingSlot::Gem7; + case EQEmu::CastingSlot::Gem8: + return CastingSlot::Gem8; + case EQEmu::CastingSlot::Gem9: + return CastingSlot::Gem9; + case EQEmu::CastingSlot::Gem10: + return CastingSlot::Gem10; + case EQEmu::CastingSlot::Item: + case EQEmu::CastingSlot::PotionBelt: + return CastingSlot::Item; + case EQEmu::CastingSlot::Discipline: + return CastingSlot::Discipline; + case EQEmu::CastingSlot::AltAbility: + return CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return CastingSlot::Discipline; + } + } + + static inline EQEmu::CastingSlot SoDToServerCastingSlot(CastingSlot slot) + { + switch (slot) { + case CastingSlot::Gem1: + return EQEmu::CastingSlot::Gem1; + case CastingSlot::Gem2: + return EQEmu::CastingSlot::Gem2; + case CastingSlot::Gem3: + return EQEmu::CastingSlot::Gem3; + case CastingSlot::Gem4: + return EQEmu::CastingSlot::Gem4; + case CastingSlot::Gem5: + return EQEmu::CastingSlot::Gem5; + case CastingSlot::Gem6: + return EQEmu::CastingSlot::Gem6; + case CastingSlot::Gem7: + return EQEmu::CastingSlot::Gem7; + case CastingSlot::Gem8: + return EQEmu::CastingSlot::Gem8; + case CastingSlot::Gem9: + return EQEmu::CastingSlot::Gem9; + case CastingSlot::Gem10: + return EQEmu::CastingSlot::Gem10; + case CastingSlot::Discipline: + return EQEmu::CastingSlot::Discipline; + case CastingSlot::Item: + return EQEmu::CastingSlot::Item; + case CastingSlot::AltAbility: + return EQEmu::CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return EQEmu::CastingSlot::Discipline; + } + } +} /*SoD*/ diff --git a/common/patches/sod.h b/common/patches/sod.h index 65d7f951a..5c29e36c0 100644 --- a/common/patches/sod.h +++ b/common/patches/sod.h @@ -1,11 +1,31 @@ -#ifndef SOD_H_ -#define SOD_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_SOD_H +#define COMMON_SOD_H #include "../struct_strategy.h" class EQStreamIdentifier; -namespace SoD { +namespace SoD +{ //these are the only public member of this namespace. extern void Register(EQStreamIdentifier &into); @@ -23,13 +43,29 @@ namespace SoD { protected: virtual std::string Describe() const; - virtual const ClientVersion GetClientVersion() const; + virtual const EQEmu::versions::ClientVersion ClientVersion() const; //magic macro to declare our opcode processors #include "ss_declare.h" #include "sod_ops.h" }; -}; + enum class CastingSlot : uint32 { + Gem1 = 0, + Gem2 = 1, + Gem3 = 2, + Gem4 = 3, + Gem5 = 4, + Gem6 = 5, + Gem7 = 6, + Gem8 = 7, + Gem9 = 8, + Gem10 = 9, + Item = 10, + Discipline = 11, + AltAbility = 0xFF + }; -#endif /*SOD_H_*/ +}; /*SoD*/ + +#endif /*COMMON_SOD_H*/ diff --git a/common/patches/sod_constants.h b/common/patches/sod_constants.h deleted file mode 100644 index 5dad9bb09..000000000 --- a/common/patches/sod_constants.h +++ /dev/null @@ -1,218 +0,0 @@ -/* -EQEMu: Everquest Server Emulator - -Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY except by those people which sell it, which -are required to give you total support for your newly bought product; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef SOD_CONSTANTS_H_ -#define SOD_CONSTANTS_H_ - -#include "../types.h" - -namespace SoD { - namespace maps { - typedef enum : int16 { - // this needs work to match actual client equivilents - MapPossessions = 0, - MapBank, - MapSharedBank, - MapTrade, - MapWorld, - MapLimbo, - MapTribute, - MapTrophyTribute, - MapGuildTribute, - MapMerchant, - MapDeleted, - MapCorpse, - MapBazaar, - MapInspect, - MapRealEstate, - MapViewMODPC, - MapViewMODBank, - MapViewMODSharedBank, - MapViewMODLimbo, - MapAltStorage, - MapArchived, - MapMail, - MapGuildTrophyTribute, - MapOther, - _MapCount - } InventoryMaps; - } - - namespace slots { - typedef enum : int16 { - MainCharm = 0, - MainEar1, - MainHead, - MainFace, - MainEar2, - MainNeck, - MainShoulders, - MainArms, - MainBack, - MainWrist1, - MainWrist2, - MainRange, - MainHands, - MainPrimary, - MainSecondary, - MainFinger1, - MainFinger2, - MainChest, - MainLegs, - MainFeet, - MainWaist, - MainPowerSource, - MainAmmo, - MainGeneral1, - MainGeneral2, - MainGeneral3, - MainGeneral4, - MainGeneral5, - MainGeneral6, - MainGeneral7, - MainGeneral8, - MainCursor, - _MainCount, - _MainEquipmentBegin = MainCharm, - _MainEquipmentEnd = MainAmmo, - _MainEquipmentCount = (_MainEquipmentEnd - _MainEquipmentBegin + 1), - _MainGeneralBegin = MainGeneral1, - _MainGeneralEnd = MainGeneral8, - _MainGeneralCount = (_MainGeneralEnd - _MainGeneralBegin + 1) - } EquipmentSlots; - } - - namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 12; - - static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; - static const uint16 MAP_BANK_SIZE = 24; - static const uint16 MAP_SHARED_BANK_SIZE = 2; - static const uint16 MAP_TRADE_SIZE = 8; - static const uint16 MAP_WORLD_SIZE = 10; - static const uint16 MAP_LIMBO_SIZE = 36; - static const uint16 MAP_TRIBUTE_SIZE = 0; //? - static const uint16 MAP_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_GUILD_TRIBUTE_SIZE = 0; - static const uint16 MAP_MERCHANT_SIZE = 0; - static const uint16 MAP_DELETED_SIZE = 0; - static const uint16 MAP_CORPSE_SIZE = slots::_MainCount; - static const uint16 MAP_BAZAAR_SIZE = 80; - static const uint16 MAP_INSPECT_SIZE = slots::_MainEquipmentCount; - static const uint16 MAP_REAL_ESTATE_SIZE = 0; - static const uint16 MAP_VIEW_MOD_PC_SIZE = MAP_POSSESSIONS_SIZE; - static const uint16 MAP_VIEW_MOD_BANK_SIZE = MAP_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_SHARED_BANK_SIZE = MAP_SHARED_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_LIMBO_SIZE = MAP_LIMBO_SIZE; - static const uint16 MAP_ALT_STORAGE_SIZE = 0; - static const uint16 MAP_ARCHIVED_SIZE = 0; - static const uint16 MAP_MAIL_SIZE = 0; - static const uint16 MAP_GUILD_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_KRONO_SIZE = NOT_USED; - static const uint16 MAP_OTHER_SIZE = 0; - - static const int16 EQUIPMENT_BEGIN = slots::MainCharm; - static const int16 EQUIPMENT_END = slots::MainAmmo; - static const uint16 EQUIPMENT_SIZE = slots::_MainEquipmentCount; - - static const int16 GENERAL_BEGIN = slots::MainGeneral1; - static const int16 GENERAL_END = slots::MainGeneral8; - static const uint16 GENERAL_SIZE = slots::_MainGeneralCount; - static const int16 GENERAL_BAGS_BEGIN = 262; - static const int16 GENERAL_BAGS_END_OFFSET = 79; - static const int16 GENERAL_BAGS_END = GENERAL_BAGS_BEGIN + GENERAL_BAGS_END_OFFSET; - - static const int16 CURSOR = slots::MainCursor; - static const int16 CURSOR_BAG_BEGIN = 342; - static const int16 CURSOR_BAG_END_OFFSET = 9; - static const int16 CURSOR_BAG_END = CURSOR_BAG_BEGIN + CURSOR_BAG_END_OFFSET; - - static const int16 BANK_BEGIN = 2000; - static const int16 BANK_END = 2023; - static const int16 BANK_BAGS_BEGIN = 2032; - static const int16 BANK_BAGS_END_OFFSET = 239; - static const int16 BANK_BAGS_END = BANK_BAGS_BEGIN + BANK_BAGS_END_OFFSET; - - static const int16 SHARED_BANK_BEGIN = 2500; - static const int16 SHARED_BANK_END = 2501; - static const int16 SHARED_BANK_BAGS_BEGIN = 2532; - static const int16 SHARED_BANK_BAGS_END_OFFSET = 19; - static const int16 SHARED_BANK_BAGS_END = SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_END_OFFSET; - - static const int16 TRADE_BEGIN = 3000; - static const int16 TRADE_END = 3007; - static const int16 TRADE_NPC_END = 3003; - static const int16 TRADE_BAGS_BEGIN = 3031; - static const int16 TRADE_BAGS_END_OFFSET = 79; - static const int16 TRADE_BAGS_END = TRADE_BAGS_BEGIN + TRADE_BAGS_END_OFFSET; - - static const int16 WORLD_BEGIN = 4000; - static const int16 WORLD_END = 4009; - - static const int16 TRIBUTE_BEGIN = 400; - static const int16 TRIBUTE_END = 404; - - static const int16 CORPSE_BEGIN = slots::MainGeneral1; - static const int16 CORPSE_END = slots::MainGeneral1 + slots::MainCursor; - - static const uint16 ITEM_COMMON_SIZE = 5; - static const uint16 ITEM_CONTAINER_SIZE = 10; - - static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances - static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance - - static const size_t POTION_BELT_ITEM_COUNT = 5; - - static const size_t TEXT_LINK_BODY_LENGTH = 50; - } - - namespace limits { - static const bool ALLOWS_EMPTY_BAG_IN_BAG = false; - static const bool ALLOWS_CLICK_CAST_FROM_BAG = false; - static const bool COIN_HAS_WEIGHT = false; - } - -}; //end namespace SoD - -#endif /*SOD_CONSTANTS_H_*/ - -/* -SoD Notes: - ** Integer-based inventory ** -ok Possessions: 0 - 31 (Corpse: 23 - 54 [Offset 23]) -ok [Equipment: 0 - 22] -ok [General: 23 - 30] -ok [Cursor: 31] -ok General Bags: 262 - 341 -ok Cursor Bags: 342 - 351 - -ok Bank: 2000 - 2023 -ok Bank Bags: 2032 - 2271 - -ok Shared Bank: 2500 - 2501 -ok Shared Bank Bags: 2532 - 2551 - - Trade: 3000 - 3007 - (Trade Bags: 3031 - 3110 -- server values) - - World: 4000 - 4009 - -*/ diff --git a/common/patches/sod_limits.cpp b/common/patches/sod_limits.cpp new file mode 100644 index 000000000..8ff257665 --- /dev/null +++ b/common/patches/sod_limits.cpp @@ -0,0 +1,272 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "sod_limits.h" + +#include "../string_util.h" + + +size_t SoD::invtype::GetInvTypeSize(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + return invtype::InvTypePossessionsSize; + case invtype::InvTypeBank: + return invtype::InvTypeBankSize; + case invtype::InvTypeSharedBank: + return invtype::InvTypeSharedBankSize; + case invtype::InvTypeTrade: + return invtype::InvTypeTradeSize; + case invtype::InvTypeWorld: + return invtype::InvTypeWorldSize; + case invtype::InvTypeLimbo: + return invtype::InvTypeLimboSize; + case invtype::InvTypeTribute: + return invtype::InvTypeTributeSize; + case invtype::InvTypeGuildTribute: + return invtype::InvTypeGuildTributeSize; + case invtype::InvTypeMerchant: + return invtype::InvTypeMerchantSize; + case invtype::InvTypeCorpse: + return invtype::InvTypeCorpseSize; + case invtype::InvTypeBazaar: + return invtype::InvTypeBazaarSize; + case invtype::InvTypeInspect: + return invtype::InvTypeInspectSize; + case invtype::InvTypeViewMODPC: + return invtype::InvTypeViewMODPCSize; + case invtype::InvTypeViewMODBank: + return invtype::InvTypeViewMODBankSize; + case invtype::InvTypeViewMODSharedBank: + return invtype::InvTypeViewMODSharedBankSize; + case invtype::InvTypeViewMODLimbo: + return invtype::InvTypeViewMODLimboSize; + case invtype::InvTypeAltStorage: + return invtype::InvTypeAltStorageSize; + case invtype::InvTypeArchived: + return invtype::InvTypeArchivedSize; + case invtype::InvTypeOther: + return invtype::InvTypeOtherSize; + default: + return 0; + } +} + +const char* SoD::invtype::GetInvTypeName(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypeInvalid: + return "Invalid Type"; + case invtype::InvTypePossessions: + return "Possessions"; + case invtype::InvTypeBank: + return "Bank"; + case invtype::InvTypeSharedBank: + return "Shared Bank"; + case invtype::InvTypeTrade: + return "Trade"; + case invtype::InvTypeWorld: + return "World"; + case invtype::InvTypeLimbo: + return "Limbo"; + case invtype::InvTypeTribute: + return "Tribute"; + case invtype::InvTypeGuildTribute: + return "Guild Tribute"; + case invtype::InvTypeMerchant: + return "Merchant"; + case invtype::InvTypeCorpse: + return "Corpse"; + case invtype::InvTypeBazaar: + return "Bazaar"; + case invtype::InvTypeInspect: + return "Inspect"; + case invtype::InvTypeViewMODPC: + return "View MOD PC"; + case invtype::InvTypeViewMODBank: + return "View MOD Bank"; + case invtype::InvTypeViewMODSharedBank: + return "View MOD Shared Bank"; + case invtype::InvTypeViewMODLimbo: + return "View MOD Limbo"; + case invtype::InvTypeAltStorage: + return "Alt Storage"; + case invtype::InvTypeArchived: + return "Archived"; + case invtype::InvTypeOther: + return "Other"; + default: + return "Unknown Type"; + } +} + +bool SoD::invtype::IsInvTypePersistent(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + case invtype::InvTypeBank: + case invtype::InvTypeSharedBank: + case invtype::InvTypeTrade: + case invtype::InvTypeWorld: + case invtype::InvTypeLimbo: + case invtype::InvTypeTribute: + case invtype::InvTypeGuildTribute: + return true; + default: + return false; + } +} + +const char* SoD::invslot::GetInvPossessionsSlotName(int inv_slot) +{ + switch (inv_slot) { + case invslot::InvSlotInvalid: + return "Invalid Slot"; + case invslot::PossessionsCharm: + return "Charm"; + case invslot::PossessionsEar1: + return "Ear 1"; + case invslot::PossessionsHead: + return "Head"; + case invslot::PossessionsFace: + return "Face"; + case invslot::PossessionsEar2: + return "Ear 2"; + case invslot::PossessionsNeck: + return "Neck"; + case invslot::PossessionsShoulders: + return "Shoulders"; + case invslot::PossessionsArms: + return "Arms"; + case invslot::PossessionsBack: + return "Back"; + case invslot::PossessionsWrist1: + return "Wrist 1"; + case invslot::PossessionsWrist2: + return "Wrist 2"; + case invslot::PossessionsRange: + return "Range"; + case invslot::PossessionsHands: + return "Hands"; + case invslot::PossessionsPrimary: + return "Primary"; + case invslot::PossessionsSecondary: + return "Secondary"; + case invslot::PossessionsFinger1: + return "Finger 1"; + case invslot::PossessionsFinger2: + return "Finger 2"; + case invslot::PossessionsChest: + return "Chest"; + case invslot::PossessionsLegs: + return "Legs"; + case invslot::PossessionsFeet: + return "Feet"; + case invslot::PossessionsWaist: + return "Waist"; + case invslot::PossessionsPowerSource: + return "Power Source"; + case invslot::PossessionsAmmo: + return "Ammo"; + case invslot::PossessionsGeneral1: + return "General 1"; + case invslot::PossessionsGeneral2: + return "General 2"; + case invslot::PossessionsGeneral3: + return "General 3"; + case invslot::PossessionsGeneral4: + return "General 4"; + case invslot::PossessionsGeneral5: + return "General 5"; + case invslot::PossessionsGeneral6: + return "General 6"; + case invslot::PossessionsGeneral7: + return "General 7"; + case invslot::PossessionsGeneral8: + return "General 8"; + case invslot::PossessionsCursor: + return "Cursor"; + default: + return "Unknown Slot"; + } +} + +const char* SoD::invslot::GetInvCorpseSlotName(int inv_slot) +{ + if (!invtype::GetInvTypeSize(invtype::InvTypeCorpse) || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + // needs work + if ((size_t)(inv_slot + 1) < invslot::CorpseBegin || (size_t)(inv_slot + 1) >= invslot::CorpseEnd) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* SoD::invslot::GetInvSlotName(int inv_type, int inv_slot) +{ + if (inv_type == invtype::InvTypePossessions) + return invslot::GetInvPossessionsSlotName(inv_slot); + else if (inv_type == invtype::InvTypeCorpse) + return invslot::GetInvCorpseSlotName(inv_slot); + + size_t type_size = invtype::GetInvTypeSize(inv_type); + + if (!type_size || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + if ((size_t)(inv_slot + 1) >= type_size) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* SoD::invbag::GetInvBagIndexName(int bag_index) +{ + if (bag_index == invbag::InvBagInvalid) + return "Invalid Bag"; + + if ((size_t)bag_index >= invbag::ItemBagSize) + return "Unknown Bag"; + + static std::string ret_str; + ret_str = StringFormat("Bag %i", (bag_index + 1)); + + return ret_str.c_str(); +} + +const char* SoD::invaug::GetInvAugIndexName(int aug_index) +{ + if (aug_index == invaug::InvAugInvalid) + return "Invalid Augment"; + + if ((size_t)aug_index >= invaug::ItemAugSize) + return "Unknown Augment"; + + static std::string ret_str; + ret_str = StringFormat("Augment %i", (aug_index + 1)); + + return ret_str.c_str(); +} diff --git a/common/patches/sod_limits.h b/common/patches/sod_limits.h new file mode 100644 index 000000000..fa2c29317 --- /dev/null +++ b/common/patches/sod_limits.h @@ -0,0 +1,312 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_SOD_LIMITS_H +#define COMMON_SOD_LIMITS_H + +#include "../types.h" +#include "../emu_versions.h" +#include "../skills.h" + + +namespace SoD +{ + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + // pre-declarations + namespace inventory { + inline EQEmu::versions::ClientVersion GetInventoryRef() { return EQEmu::versions::ClientVersion::SoD; } + + } /*inventory*/ + + namespace invtype { + inline EQEmu::versions::ClientVersion GetInvTypeRef() { return EQEmu::versions::ClientVersion::SoD; } + + enum : int { InvTypeInvalid = -1, InvTypeBegin }; + + enum InventoryType : int { + InvTypePossessions = InvTypeBegin, + InvTypeBank, + InvTypeSharedBank, + InvTypeTrade, + InvTypeWorld, + InvTypeLimbo, + InvTypeTribute, + InvTypeGuildTribute, + InvTypeMerchant, + InvTypeCorpse, + InvTypeBazaar, + InvTypeInspect, + InvTypeViewMODPC, + InvTypeViewMODBank, + InvTypeViewMODSharedBank, + InvTypeViewMODLimbo, + InvTypeAltStorage, + InvTypeArchived, + InvTypeOther, + InvTypeCount + }; + + } /*invtype*/ + + namespace invslot { + inline EQEmu::versions::ClientVersion GetInvSlotRef() { return EQEmu::versions::ClientVersion::SoD; } + + enum : int { InvSlotInvalid = -1, InvSlotBegin }; + + enum PossessionsSlot : int { + PossessionsCharm = InvSlotBegin, + PossessionsEar1, + PossessionsHead, + PossessionsFace, + PossessionsEar2, + PossessionsNeck, + PossessionsShoulders, + PossessionsArms, + PossessionsBack, + PossessionsWrist1, + PossessionsWrist2, + PossessionsRange, + PossessionsHands, + PossessionsPrimary, + PossessionsSecondary, + PossessionsFinger1, + PossessionsFinger2, + PossessionsChest, + PossessionsLegs, + PossessionsFeet, + PossessionsWaist, + PossessionsPowerSource, + PossessionsAmmo, + PossessionsGeneral1, + PossessionsGeneral2, + PossessionsGeneral3, + PossessionsGeneral4, + PossessionsGeneral5, + PossessionsGeneral6, + PossessionsGeneral7, + PossessionsGeneral8, + PossessionsCursor, + PossessionsCount + }; + + const int EquipmentBegin = PossessionsCharm; + const int EquipmentEnd = PossessionsAmmo; + const int EquipmentCount = (EquipmentEnd - EquipmentBegin + 1); + + const int GeneralBegin = PossessionsGeneral1; + const int GeneralEnd = PossessionsGeneral8; + const int GeneralCount = (GeneralEnd - GeneralBegin + 1); + + } /*invslot*/ + + namespace invbag { + inline EQEmu::versions::ClientVersion GetInvBagRef() { return EQEmu::versions::ClientVersion::SoD; } + + enum : int { InvBagInvalid = -1, InvBagBegin }; + + } /*invbag*/ + + namespace invaug { + inline EQEmu::versions::ClientVersion GetInvAugRef() { return EQEmu::versions::ClientVersion::SoD; } + + enum : int { InvAugInvalid = -1, InvAugBegin }; + + } /*invaug*/ + + namespace item { + inline EQEmu::versions::ClientVersion GetItemRef() { return EQEmu::versions::ClientVersion::SoD; } + + enum ItemPacketType : int { + ItemPacketMerchant = 100, + ItemPacketTradeView = 101, + ItemPacketLoot = 102, + ItemPacketTrade = 103, + ItemPacketCharInventory = 105, + ItemPacketLimbo = 106, + ItemPacketWorldContainer = 107, + ItemPacketTributeItem = 108, + ItemPacketGuildTribute = 109, + ItemPacketCharmUpdate = 110 + }; + + } /*item*/ + + namespace profile { + inline EQEmu::versions::ClientVersion GetProfileRef() { return EQEmu::versions::ClientVersion::SoD; } + + } /*profile*/ + + namespace constants { + inline EQEmu::versions::ClientVersion GetConstantsRef() { return EQEmu::versions::ClientVersion::SoD; } + + } /*constants*/ + + namespace behavior { + inline EQEmu::versions::ClientVersion GetBehaviorRef() { return EQEmu::versions::ClientVersion::SoD; } + + } /*behavior*/ + + namespace skills { + inline EQEmu::versions::ClientVersion GetSkillsRef() { return EQEmu::versions::ClientVersion::SoD; } + + } /*skills*/ + + + // declarations + namespace inventory { + const bool ConcatenateInvTypeLimbo = true; + + const bool AllowOverLevelEquipment = false; + + const bool AllowEmptyBagInBag = false; + const bool AllowClickCastFromBag = false; + + } /*inventory*/ + + namespace invtype { + const size_t InvTypePossessionsSize = invslot::PossessionsCount; + const size_t InvTypeBankSize = 24; + const size_t InvTypeSharedBankSize = 2; + const size_t InvTypeTradeSize = 8; + const size_t InvTypeWorldSize = 10; + const size_t InvTypeLimboSize = 36; + const size_t InvTypeTributeSize = 5; + const size_t InvTypeGuildTributeSize = 2; + const size_t InvTypeMerchantSize = 80; + const size_t InvTypeCorpseSize = InvTypePossessionsSize; + const size_t InvTypeBazaarSize = 80; + const size_t InvTypeInspectSize = invslot::EquipmentCount; + const size_t InvTypeViewMODPCSize = InvTypePossessionsSize; + const size_t InvTypeViewMODBankSize = InvTypeBankSize; + const size_t InvTypeViewMODSharedBankSize = InvTypeSharedBankSize; + const size_t InvTypeViewMODLimboSize = InvTypeLimboSize; + const size_t InvTypeAltStorageSize = 0;//unknown - "Shroud Bank" + const size_t InvTypeArchivedSize = 0;//unknown + const size_t InvTypeOtherSize = 0;//unknown + + extern size_t GetInvTypeSize(int inv_type); + extern const char* GetInvTypeName(int inv_type); + + extern bool IsInvTypePersistent(int inv_type); + + } /*invtype*/ + + namespace invslot { + const int BankBegin = 2000; + const int BankEnd = (BankBegin + invtype::InvTypeBankSize) - 1; + + const int SharedBankBegin = 2500; + const int SharedBankEnd = (SharedBankBegin + invtype::InvTypeSharedBankSize) - 1; + + const int TradeBegin = 3000; + const int TradeEnd = (TradeBegin + invtype::InvTypeTradeSize) - 1; + const int TradeNPCEnd = 3003; + + const int WorldBegin = 4000; + const int WorldEnd = (WorldBegin + invtype::InvTypeWorldSize) - 1; + + const int TributeBegin = 400; + const int TributeEnd = (TributeBegin + invtype::InvTypeTributeSize) - 1; + + const int GuildTributeBegin = 450; + const int GuildTributeEnd = (GuildTributeBegin + invtype::InvTypeGuildTributeSize) - 1; + + const int CorpseBegin = invslot::PossessionsGeneral1; + const int CorpseEnd = invslot::PossessionsGeneral1 + invslot::PossessionsCursor; + + extern const char* GetInvPossessionsSlotName(int inv_slot); + extern const char* GetInvCorpseSlotName(int inv_slot); + extern const char* GetInvSlotName(int inv_type, int inv_slot); + + } /*invslot*/ + + namespace invbag { + const size_t ItemBagSize = 10; + + const int GeneralBagsBegin = 262; + const int GeneralBagsSize = invslot::GeneralCount * ItemBagSize; + const int GeneralBagsEnd = (GeneralBagsBegin + GeneralBagsSize) - 1; + + const int CursorBagBegin = 342; + const int CursorBagSize = ItemBagSize; + const int CursorBagEnd = (CursorBagBegin + CursorBagSize) - 1; + + const int BankBagsBegin = 2032; + const int BankBagsSize = (invtype::InvTypeBankSize * ItemBagSize); + const int BankBagsEnd = (BankBagsBegin + BankBagsSize) - 1; + + const int SharedBankBagsBegin = 2532; + const int SharedBankBagsSize = invtype::InvTypeSharedBankSize * ItemBagSize; + const int SharedBankBagsEnd = (SharedBankBagsBegin + SharedBankBagsSize) - 1; + + const int TradeBagsBegin = 3031; + const int TradeBagsSize = invtype::InvTypeTradeSize * ItemBagSize; + const int TradeBagsEnd = (TradeBagsBegin + TradeBagsSize) - 1; + + extern const char* GetInvBagIndexName(int bag_index); + + } /*invbag*/ + + namespace invaug { + const size_t ItemAugSize = 5; + + extern const char* GetInvAugIndexName(int aug_index); + + } /*invaug*/ + + namespace item { + + } /*item*/ + + namespace profile { + const size_t TributeSize = invtype::InvTypeTributeSize; + const size_t GuildTributeSize = invtype::InvTypeGuildTributeSize; + + const size_t BandoliersSize = 20; // number of bandolier instances + const size_t BandolierItemCount = 4; // number of equipment slots in bandolier instance + + const size_t PotionBeltSize = 5; + + const size_t SkillArraySize = 100; + + } /*profile*/ + + namespace constants { + const size_t CharacterCreationLimit = 12; + + const size_t SayLinkBodySize = 50; + + } /*constants*/ + + namespace behavior { + const bool CoinHasWeight = false; + + } /*behavior*/ + + namespace skills { + const size_t LastUsableSkill = EQEmu::skills::SkillTripleAttack; + + } /*skills*/ + +}; /*SoD*/ + +#endif /*COMMON_SOD_LIMITS_H*/ diff --git a/common/patches/sod_ops.h b/common/patches/sod_ops.h index f599885c1..90c28b2eb 100644 --- a/common/patches/sod_ops.h +++ b/common/patches/sod_ops.h @@ -1,3 +1,23 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + // out-going packets that require an ENCODE translation: E(OP_Action) E(OP_AdventureMerchantSell) diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index ef4dd32cb..6a73b7283 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -1,7 +1,28 @@ -#ifndef SOD_STRUCTS_H_ -#define SOD_STRUCTS_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) -namespace SoD { + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_SOD_STRUCTS_H +#define COMMON_SOD_STRUCTS_H + + +namespace SoD +{ namespace structs { @@ -101,7 +122,7 @@ struct AdventureInfo { ** Merth: Gave struct a name so gcc 2.96 would compile ** */ -struct Color_Struct +struct Tint_Struct { union { struct { @@ -109,19 +130,62 @@ struct Color_Struct uint8 Green; uint8 Red; uint8 UseTint; // if there's a tint this is FF - } RGB; + }; uint32 Color; }; }; -struct CharSelectEquip +struct TintProfile +{ + union { + struct { + Tint_Struct Head; + Tint_Struct Chest; + Tint_Struct Arms; + Tint_Struct Wrist; + Tint_Struct Hands; + Tint_Struct Legs; + Tint_Struct Feet; + Tint_Struct Primary; + Tint_Struct Secondary; + }; + Tint_Struct Slot[EQEmu::textures::TextureCount]; + }; +}; + +/* +* Visible equiptment. +* Size: 12 Octets +*/ +struct Texture_Struct { uint32 Material; uint32 Unknown1; uint32 EliteMaterial; - Color_Struct Color; }; +struct TextureProfile +{ + union { + struct { + Texture_Struct Head; + Texture_Struct Chest; + Texture_Struct Arms; + Texture_Struct Wrist; + Texture_Struct Hands; + Texture_Struct Legs; + Texture_Struct Feet; + Texture_Struct Primary; + Texture_Struct Secondary; + }; + Texture_Struct Slot[EQEmu::textures::TextureCount]; + }; + + TextureProfile(); +}; + +struct CharSelectEquip : Texture_Struct, Tint_Struct {}; + struct CharacterSelectEntry_Struct { /*0000*/ uint8 Level; // @@ -131,7 +195,7 @@ struct CharacterSelectEntry_Struct /*0000*/ uint8 Beard; // /*0001*/ uint8 HairColor; // /*0000*/ uint8 Face; // -/*0000*/ CharSelectEquip Equip[9]; +/*0000*/ CharSelectEquip Equip[EQEmu::textures::TextureCount]; /*0000*/ uint32 PrimaryIDFile; // /*0000*/ uint32 SecondaryIDFile; // /*0000*/ uint8 Unknown15; // 0xff @@ -164,19 +228,6 @@ struct CharacterSelect_Struct /*0008*/ CharacterSelectEntry_Struct Entries[0]; }; -/* -* Visible equiptment. -* Size: 12 Octets -*/ -struct EquipStruct -{ -/*00*/ uint32 Material; -/*04*/ uint32 Unknown1; -/*08*/ uint32 EliteMaterial; -/*12*/ -}; - - /* ** Generic Spawn Struct ** Length: 897 Octets @@ -286,47 +337,17 @@ struct Spawn_Struct /*0000*/ uint8 unknown12; /*0000*/ uint32 petOwnerId; /*0000*/ uint8 unknown13; -/*0000*/ uint32 unknown14; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed +/*0000*/ uint32 PlayerState; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed /*0000*/ uint32 unknown15; /*0000*/ uint32 unknown16; /*0000*/ uint32 unknown17; /*0000*/ uint32 unknown18; /*0000*/ uint32 unknown19; Spawn_Struct_Position Position; -/*0000*/ union - { - struct - { - /*0000*/ Color_Struct color_helmet; // Color of helmet item - /*0000*/ Color_Struct color_chest; // Color of chest item - /*0000*/ Color_Struct color_arms; // Color of arms item - /*0000*/ Color_Struct color_bracers; // Color of bracers item - /*0000*/ Color_Struct color_hands; // Color of hands item - /*0000*/ Color_Struct color_legs; // Color of legs item - /*0000*/ Color_Struct color_feet; // Color of feet item - /*0000*/ Color_Struct color_primary; // Color of primary item - /*0000*/ Color_Struct color_secondary; // Color of secondary item - } equipment_colors; - /*0000*/ Color_Struct colors[9]; // Array elements correspond to struct equipment_colors above - }; +/*0000*/ TintProfile equipment_tint; // skip these bytes if not a valid player race -/*0000*/ union - { - struct - { - /*0000*/ EquipStruct equip_helmet; // Equiptment: Helmet visual - /*0000*/ EquipStruct equip_chest; // Equiptment: Chest visual - /*0000*/ EquipStruct equip_arms; // Equiptment: Arms visual - /*0000*/ EquipStruct equip_bracers; // Equiptment: Wrist visual - /*0000*/ EquipStruct equip_hands; // Equiptment: Hands visual - /*0000*/ EquipStruct equip_legs; // Equiptment: Legs visual - /*0000*/ EquipStruct equip_feet; // Equiptment: Boots visual - /*0000*/ EquipStruct equip_primary; // Equiptment: Main visual - /*0000*/ EquipStruct equip_secondary; // Equiptment: Off visual - } equip; - /*0000*/ EquipStruct equipment[9]; - }; +/*0000*/ TextureProfile equipment; /*0000*/ //char title[0]; // only read if(hasTitleOrSuffix & 4) /*0000*/ //char suffix[0]; // only read if(hasTitleOrSuffix & 8) @@ -458,7 +479,7 @@ struct MemorizeSpell_Struct { uint32 slot; // Spot in the spell book/memorized slot uint32 spell_id; // Spell id (200 or c8 is minor healing, etc) uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming -//uint32 unknown12; +uint32 reduction; // lowers reuse }; /* @@ -491,11 +512,12 @@ struct DeleteSpell_Struct struct ManaChange_Struct { - uint32 new_mana; // New Mana AMount - uint32 stamina; - uint32 spell_id; - uint32 unknown12; - uint32 unknown16; +/*00*/ uint32 new_mana; // New Mana AMount +/*04*/ uint32 stamina; +/*08*/ uint32 spell_id; +/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting? +/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like +/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it }; struct SwapSpell_Struct @@ -542,32 +564,22 @@ struct SpawnAppearance_Struct // this is used inside profile struct SpellBuff_Struct { -/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; //not real -/*004*/ uint32 spellid; -/*008*/ uint32 duration; -/*012*/ uint32 counters; -/*016*/ uint32 unknown004; //Might need to be swapped with player_id -/*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 bard_modifier; +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ uint32 spellid; +/*008*/ uint32 duration; +/*012*/ uint32 counters; +/*016*/ uint32 unknown016; +/*020*/ uint32 player_id; // caster ID, pretty sure just zone ID /*024*/ - - }; -struct SpellBuffFade_Struct { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ uint32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 unknown020; //prolly global player ID -/*024*/ uint32 playerId; // Player id who cast the buff +/*004*/ SpellBuff_Struct buff; /*028*/ uint32 slotid; /*032*/ uint32 bufffade; /*036*/ @@ -666,7 +678,7 @@ struct AA_Array { uint32 AA; uint32 value; - uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live + uint32 charges; // expendable }; @@ -705,7 +717,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; + BandolierItem_Struct Items[profile::BandolierItemCount]; }; //len = 72 @@ -719,7 +731,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; + PotionBeltItem_Struct Items[profile::PotionBeltSize]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -882,24 +894,9 @@ struct PlayerProfile_Struct /*00216*/ uint8 hairstyle; // Player hair style /*00217*/ uint8 beard; // Player beard type /*00218*/ uint8 unknown00178[14]; //[10]14 on Live? was 10 -/*00232*/ union - { - struct - { - /*00228*/ EquipStruct equip_helmet; // Equiptment: Helmet visual - /*00240*/ EquipStruct equip_chest; // Equiptment: Chest visual - /*00252*/ EquipStruct equip_arms; // Equiptment: Arms visual - /*00264*/ EquipStruct equip_bracers; // Equiptment: Wrist visual - /*00276*/ EquipStruct equip_hands; // Equiptment: Hands visual - /*00288*/ EquipStruct equip_legs; // Equiptment: Legs visual - /*00300*/ EquipStruct equip_feet; // Equiptment: Boots visual - /*00312*/ EquipStruct equip_primary; // Equiptment: Main visual - /*00324*/ EquipStruct equip_secondary; // Equiptment: Off visual - } equip; - /*00228*/ EquipStruct equipment[9]; //Live Shows [108] for this part - }; +/*00232*/ TextureProfile equipment; /*00340*/ uint8 unknown00224[156]; // Live Shows [160] -/*00496*/ Color_Struct item_tint[9]; // RR GG BB 00 +/*00496*/ TintProfile item_tint; // RR GG BB 00 /*00532*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; // [3600] AAs 12 bytes each /*04132*/ uint32 points; // Unspent Practice points - RELOCATED??? /*04136*/ uint32 mana; // Current mana @@ -939,7 +936,7 @@ struct PlayerProfile_Struct /*08288*/ uint32 aapoints_spent; // Number of spent AA points /*08292*/ uint32 aapoints; // Unspent AA points /*08296*/ uint8 unknown06160[4]; -/*08300*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [6400] bandolier contents +/*08300*/ Bandolier_Struct bandoliers[profile::BandoliersSize]; // [6400] bandolier contents /*14700*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot /*15060*/ uint8 unknown12852[8]; /*15068*/ uint32 available_slots; @@ -1091,7 +1088,7 @@ struct TargetReject_Struct { struct PetCommand_Struct { /*000*/ uint32 command; -/*004*/ uint32 unknown; +/*004*/ uint32 target; }; /* @@ -1156,7 +1153,7 @@ struct WearChange_Struct{ /*002*/ uint32 material; /*006*/ uint32 unknown06; /*010*/ uint32 elite_material; // 1 for Drakkin Elite Material -/*014*/ Color_Struct color; +/*014*/ Tint_Struct color; /*018*/ uint8 wear_slot_id; /*019*/ }; @@ -1205,8 +1202,8 @@ struct RequestClientZoneChange_Struct { struct Animation_Struct { /*00*/ uint16 spawnid; -/*02*/ uint8 action; -/*03*/ uint8 value; +/*02*/ uint8 speed; +/*03*/ uint8 action; /*04*/ }; @@ -1272,9 +1269,11 @@ struct CombatDamage_Struct /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 05 */ uint16 spellid; /* 07 */ int32 damage; -/* 11 */ float unknown11; // cd cc cc 3d -/* 15 */ float sequence; // see above notes in Action_Struct -/* 19 */ uint8 unknown19[9]; // was [9] +/* 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] +/* 24 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage /* 28 */ }; @@ -1972,7 +1971,7 @@ struct AdventureLeaderboard_Struct /*struct Item_Shop_Struct { uint16 merchantid; uint8 itemtype; - Item_Struct item; + ItemBase item; uint8 iss_unknown001[6]; };*/ @@ -3068,27 +3067,6 @@ struct PetitionBug_Struct{ char text[1028]; }; -struct DyeStruct -{ - union - { - struct - { - struct Color_Struct head; - struct Color_Struct chest; - struct Color_Struct arms; - struct Color_Struct wrists; - struct Color_Struct hands; - struct Color_Struct legs; - struct Color_Struct feet; - struct Color_Struct primary; // you can't actually dye this - struct Color_Struct secondary; // or this - } - dyes; - struct Color_Struct dye[9]; - }; -}; - struct ApproveZone_Struct { char name[64]; uint32 zoneid; @@ -3812,16 +3790,21 @@ struct SendAA_Struct { /*0049*/ uint32 spellid; /*0053*/ uint32 spell_type; /*0057*/ uint32 spell_refresh; -/*0061*/ uint16 classes; -/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability +/*0061*/ uint32 classes; /*0065*/ uint32 max_level; /*0069*/ uint32 last_id; /*0073*/ uint32 next_id; /*0077*/ uint32 cost2; -/*0081*/ uint8 unknown80[7]; +/*0081*/ uint8 unknown81; +/*0082*/ uint8 grant_only; // VetAAs, progression, etc +/*0083*/ uint8 unknown83; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though +/*0084*/ uint32 expendable_charges; // max charges of the AA /*0088*/ uint32 aa_expansion; /*0092*/ uint32 special_category; -/*0096*/ uint32 unknown0096; +/*0096*/ uint8 shroud; +/*0097*/ uint8 unknown97; +/*0098*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter? +/*0099*/ uint8 unknown99; /*0100*/ uint32 total_abilities; /*0104*/ AA_Ability abilities[0]; }; @@ -3833,16 +3816,10 @@ struct AA_List { struct AA_Action { /*00*/ uint32 action; /*04*/ uint32 ability; -/*08*/ uint32 unknown08; +/*08*/ uint32 target_id; /*12*/ uint32 exp_value; }; -struct AA_Skills { //this should be removed and changed to AA_Array -/*00*/ uint32 aa_skill; // Total AAs Spent -/*04*/ uint32 aa_value; -/*08*/ uint32 unknown08; -}; - struct AAExpUpdate_Struct { /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*04*/ uint32 aapoints_unspent; @@ -3860,12 +3837,12 @@ struct AltAdvStats_Struct { }; struct PlayerAA_Struct { // Is this still used? - AA_Skills aa_list[MAX_PP_AA_ARRAY]; + AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct AATable_Struct { /*00*/ int32 aa_spent; // Total AAs Spent -/*04*/ AA_Skills aa_list[MAX_PP_AA_ARRAY]; +/*04*/ AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct Weather_Struct { @@ -4005,7 +3982,7 @@ struct ItemBodyStruct uint32 Races; uint32 Deity; int32 SkillModValue; - uint32 unknown6; + uint32 SkillModMax; uint32 SkillModType; uint32 BaneDmgRace; uint32 BaneDmgBody; @@ -4110,7 +4087,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4125,7 +4102,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4183,10 +4160,9 @@ struct ItemQuaternaryBodyStruct int32 HeroicSVCorrup; int32 HealAmt; int32 SpellDmg; - int32 clairvoyance; + int32 Clairvoyance; uint8 unknown18; //Power Source Capacity or evolve filename? uint32 evolve_string; // Some String, but being evolution related is just a guess - uint32 subitem_count; }; struct AugmentInfo_Struct @@ -4428,7 +4404,8 @@ struct MercenaryAssign_Struct { /*0012*/ }; - }; //end namespace structs -}; //end namespace SoD + }; /*structs*/ -#endif /*SOD_STRUCTS_H_*/ +}; /*SoD*/ + +#endif /*COMMON_SOD_STRUCTS_H*/ diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index a7553e7f9..3ab4a7631 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1,4 +1,24 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #include "../global_define.h" +#include "../eqemu_config.h" #include "../eqemu_logsys.h" #include "sof.h" #include "../opcodemgr.h" @@ -16,13 +36,14 @@ #include #include + namespace SoF { static const char *name = "SoF"; static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id, uint8 depth); // server to client inventory location converters static inline uint32 ServerToSoFSlot(uint32 serverSlot); @@ -38,12 +59,17 @@ namespace SoF // client to server text link converter static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink); + static inline CastingSlot ServerToSoFCastingSlot(EQEmu::CastingSlot slot); + static inline EQEmu::CastingSlot SoFToServerCastingSlot(CastingSlot slot, uint32 itemlocation); + void Register(EQStreamIdentifier &into) { //create our opcode manager if we havent already if (opcodes == nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; //load up the opcode manager. @@ -87,7 +113,9 @@ namespace SoF if (opcodes != nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; if (!opcodes->ReloadOpcodes(opfile.c_str())) { @@ -113,9 +141,9 @@ namespace SoF return(r); } - const ClientVersion Strategy::GetClientVersion() const + const EQEmu::versions::ClientVersion Strategy::ClientVersion() const { - return ClientVersion::SoF; + return EQEmu::versions::ClientVersion::SoF; } #include "ss_define.h" @@ -258,16 +286,17 @@ namespace SoF ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - OUT(slot); - OUT(level); - OUT(effect); - //eq->unknown7 = 10; - OUT(spellid); - OUT(duration); + OUT(buff.effect_type); + OUT(buff.level); + OUT(buff.bard_modifier); + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.counters); + OUT(buff.player_id); OUT(slotid); OUT(bufffade); @@ -317,69 +346,50 @@ namespace SoF ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { + if (!in->size) { in->size = 4; in->pBuffer = new uchar[in->size]; - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(EQEmu::InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(EQEmu::InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", - opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); + opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(EQEmu::InternalSerializedItem_Struct)); delete in; return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + EQEmu::InternalSerializedItem_Struct* eq = (EQEmu::InternalSerializedItem_Struct*)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); - for (int r = 0; r < ItemCount; r++, eq++) { + ob.write((const char*)&item_count, sizeof(uint32)); - uint32 Length = 0; + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ob, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); - - if (Serialized) { - uchar *OldBuffer = in->pBuffer; - - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ob.tellp(); } + in->size = ob.size(); + in->pBuffer = ob.detach(); + delete[] __emu_buffer; - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); - dest->FastQueuePacket(&in, ack_req); } @@ -426,7 +436,9 @@ namespace SoF OUT(type); OUT(spellid); OUT(damage); - eq->sequence = emu->sequence; + OUT(force); + OUT(meleepush_xy); + OUT(meleepush_z); FINISH_ENCODE(); } @@ -832,29 +844,31 @@ namespace SoF ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; + + EQEmu::InternalSerializedItem_Struct* int_struct = (EQEmu::InternalSerializedItem_Struct*)(&__emu_buffer[4]); - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); - if (!serialized) { + ob.write((const char*)__emu_buffer, 4); + + SerializeItem(ob, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ob.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + in->size = ob.size(); + in->pBuffer = ob.detach(); + delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -922,7 +936,24 @@ namespace SoF OUT(new_mana); OUT(stamina); OUT(spell_id); - eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2? + OUT(keepcasting); + eq->slot = -1; // this is spell gem slot. It's -1 in normal operation + + FINISH_ENCODE(); + } + + ENCODE(OP_MemorizeSpell) + { + ENCODE_LENGTH_EXACT(MemorizeSpell_Struct); + SETUP_DIRECT_ENCODE(MemorizeSpell_Struct, structs::MemorizeSpell_Struct); + + // Since HT/LoH are translated up, we need to translate down only for memSpellSpellbar case + if (emu->scribing == 3) + eq->slot = static_cast(ServerToSoFCastingSlot(static_cast(emu->slot))); + else + OUT(slot); + OUT(spell_id); + OUT(scribing); FINISH_ENCODE(); } @@ -1147,9 +1178,9 @@ namespace SoF OUT(petid); OUT(buffcount); - int EQBuffSlot = 0; + int EQBuffSlot = 0; // do we really want to shuffle them around like this? - for (uint32 EmuBuffSlot = 0; EmuBuffSlot < BUFF_COUNT; ++EmuBuffSlot) + for (uint32 EmuBuffSlot = 0; EmuBuffSlot < PET_BUFF_COUNT; ++EmuBuffSlot) { if (emu->spellid[EmuBuffSlot]) { @@ -1199,14 +1230,14 @@ namespace SoF OUT(hairstyle); OUT(beard); // OUT(unknown00178[10]); - for (r = 0; r < 9; r++) { - eq->equipment[r].Material = emu->item_material[r]; - eq->equipment[r].Unknown1 = 0; - eq->equipment[r].EliteMaterial = 0; + for (r = EQEmu::textures::TextureBegin; r < EQEmu::textures::TextureCount; r++) { + eq->equipment.Slot[r].Material = emu->item_material.Slot[r].Material; + eq->equipment.Slot[r].Unknown1 = 0; + eq->equipment.Slot[r].EliteMaterial = 0; //eq->colors[r].color = emu->colors[r].color; } for (r = 0; r < 7; r++) { - OUT(item_tint[r].Color); + OUT(item_tint.Slot[r].Color); } // OUT(unknown00224[48]); //NOTE: new client supports 300 AAs, our internal rep/PP @@ -1214,6 +1245,7 @@ namespace SoF for (r = 0; r < MAX_PP_AA_ARRAY; r++) { OUT(aa_array[r].AA); OUT(aa_array[r].value); + OUT(aa_array[r].charges); } // OUT(unknown02220[4]); OUT(mana); @@ -1247,10 +1279,10 @@ namespace SoF OUT(thirst_level); OUT(hunger_level); for (r = 0; r < structs::BUFF_COUNT; r++) { - OUT(buffs[r].slotid); + OUT(buffs[r].effect_type); OUT(buffs[r].level); OUT(buffs[r].bard_modifier); - OUT(buffs[r].effect); + OUT(buffs[r].unknown003); OUT(buffs[r].spellid); OUT(buffs[r].duration); OUT(buffs[r].counters); @@ -1268,18 +1300,18 @@ namespace SoF // OUT(unknown06160[4]); // Copy bandoliers where server and client indexes converge - for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { + for (r = 0; r < EQEmu::legacy::BANDOLIERS_SIZE && r < profile::BandoliersSize; ++r) { OUT_str(bandoliers[r].Name); - for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + for (uint32 k = 0; k < profile::BandolierItemCount; ++k) { // Will need adjusting if 'server != client' is ever true OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } // Nullify bandoliers where server and client indexes diverge, with a client bias - for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + for (r = EQEmu::legacy::BANDOLIERS_SIZE; r < profile::BandoliersSize; ++r) { eq->bandoliers[r].Name[0] = '\0'; - for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + for (uint32 k = 0; k < profile::BandolierItemCount; ++k) { // Will need adjusting if 'server != client' is ever true eq->bandoliers[r].Items[k].ID = 0; eq->bandoliers[r].Items[k].Icon = 0; eq->bandoliers[r].Items[k].Name[0] = '\0'; @@ -1289,13 +1321,13 @@ namespace SoF // OUT(unknown07444[5120]); // Copy potion belt where server and client indexes converge - for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (r = 0; r < EQEmu::legacy::POTION_BELT_ITEM_COUNT && r < profile::PotionBeltSize; ++r) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); } // Nullify potion belt where server and client indexes diverge, with a client bias - for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (r = EQEmu::legacy::POTION_BELT_ITEM_COUNT; r < profile::PotionBeltSize; ++r) { eq->potionbelt.Items[r].ID = 0; eq->potionbelt.Items[r].Icon = 0; eq->potionbelt.Items[r].Name[0] = '\0'; @@ -1332,8 +1364,8 @@ namespace SoF OUT(copper_bank); OUT(platinum_shared); // OUT(unknown13156[84]); - //OUT(expansions); - eq->expansions = 16383; + OUT(expansions); + //eq->expansions = 16383; // OUT(unknown13244[12]); OUT(autosplit); // OUT(unknown13260[16]); @@ -1420,7 +1452,7 @@ namespace SoF unsigned char * __emu_buffer = inapp->pBuffer; RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer; general->action = 8; @@ -1443,7 +1475,7 @@ namespace SoF { RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer; add_member->raidGen.action = in_add_member->raidGen.action; @@ -1463,7 +1495,8 @@ namespace SoF else if (raid_gen->action == 35) { RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + strlen(inmotd->motd) + 1); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + + strlen(inmotd->motd) + 1); structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer; outmotd->general.action = inmotd->general.action; @@ -1474,7 +1507,8 @@ namespace SoF else if (raid_gen->action == 14 || raid_gen->action == 30) { RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; outlaa->action = inlaa->action; @@ -1487,7 +1521,7 @@ namespace SoF { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer; strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64); strn0cpy(raid_general->player_name, in_raid_general->player_name, 64); @@ -1517,55 +1551,57 @@ namespace SoF ENCODE(OP_SendAATable) { - ENCODE_LENGTH_ATLEAST(SendAA_Struct); + EQApplicationPacket *inapp = *p; + *p = nullptr; + AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer; - SETUP_VAR_ENCODE(SendAA_Struct); - ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); + auto outapp = new EQApplicationPacket( + OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability)); + structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer; - // Check clientver field to verify this AA should be sent for SoF - // clientver 1 is for all clients and 4 is for SoF - if (emu->clientver <= 4) - { - OUT(id); - eq->unknown004 = 1; - //eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->title_sid = emu->id - emu->current_level + 1; - //eq->desc_sid = emu->id - emu->current_level + 1; - eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->sof_next_skill); - eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->sof_next_skill); - eq->title_sid = emu->sof_next_skill; - eq->desc_sid = emu->sof_next_skill; - OUT(class_type); - OUT(cost); - OUT(seq); - OUT(current_level); - OUT(prereq_skill); - OUT(prereq_minpoints); - eq->type = emu->sof_type; - OUT(spellid); - OUT(spell_type); - OUT(spell_refresh); - OUT(classes); - OUT(berserker); - //eq->max_level = emu->sof_max_level; - OUT(max_level); - OUT(last_id); - OUT(next_id); - OUT(cost2); - eq->aa_expansion = emu->aa_expansion; - eq->special_category = emu->special_category; - OUT(total_abilities); - unsigned int r; - for (r = 0; r < emu->total_abilities; r++) { - OUT(abilities[r].skill_id); - OUT(abilities[r].base1); - OUT(abilities[r].base2); - OUT(abilities[r].slot); - } + inapp->SetReadPosition(sizeof(AARankInfo_Struct)); + outapp->SetWritePosition(sizeof(structs::SendAA_Struct)); + + eq->id = emu->id; + eq->unknown004 = 1; + eq->id = emu->id; + eq->hotkey_sid = emu->upper_hotkey_sid; + eq->hotkey_sid2 = emu->lower_hotkey_sid; + eq->desc_sid = emu->desc_sid; + eq->title_sid = emu->title_sid; + eq->class_type = emu->level_req; + eq->cost = emu->cost; + eq->seq = emu->seq; + eq->current_level = emu->current_level; + eq->type = emu->type; + eq->spellid = emu->spell; + eq->spell_type = emu->spell_type; + eq->spell_refresh = emu->spell_refresh; + eq->classes = emu->classes; + eq->max_level = emu->max_level; + eq->last_id = emu->prev_id; + eq->next_id = emu->next_id; + eq->cost2 = emu->total_cost; + eq->grant_only = emu->grant_only; + eq->expendable_charges = emu->charges; + eq->aa_expansion = emu->expansion; + eq->special_category = emu->category; + eq->total_abilities = emu->total_effects; + + for(auto i = 0; i < eq->total_abilities; ++i) { + eq->abilities[i].skill_id = inapp->ReadUInt32(); + eq->abilities[i].base1 = inapp->ReadUInt32(); + eq->abilities[i].base2 = inapp->ReadUInt32(); + eq->abilities[i].slot = inapp->ReadUInt32(); } - FINISH_ENCODE(); + if(emu->total_prereqs > 0) { + eq->prereq_skill = inapp->ReadUInt32(); + eq->prereq_minpoints = inapp->ReadUInt32(); + } + + dest->FastQueuePacket(&outapp); + delete inapp; } ENCODE(OP_SendCharInfo) @@ -1579,8 +1615,8 @@ namespace SoF eq->CharCount = emu->CharCount; eq->TotalChars = emu->TotalChars; - if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) - eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; + if (eq->TotalChars > constants::CharacterCreationLimit) + eq->TotalChars = constants::CharacterCreationLimit; FINISH_ENCODE(); return; @@ -1592,7 +1628,7 @@ namespace SoF size_t names_length = 0; size_t character_count = 0; - for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) { + for (; character_count < emu->CharCount && character_count < constants::CharacterCreationLimit; ++character_count) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; names_length += strlen(emu_cse->Name); emu_ptr += sizeof(CharacterSelectEntry_Struct); @@ -1608,8 +1644,8 @@ namespace SoF eq->CharCount = character_count; eq->TotalChars = emu->TotalChars; - if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) - eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; + if (eq->TotalChars > constants::CharacterCreationLimit) + eq->TotalChars = constants::CharacterCreationLimit; emu_ptr = __emu_buffer; emu_ptr += sizeof(CharacterSelect_Struct); @@ -1619,25 +1655,26 @@ namespace SoF for (int counter = 0; counter < character_count; ++counter) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address eq_cse->Level = emu_cse->Level; eq_cse->HairStyle = emu_cse->HairStyle; eq_cse->Gender = emu_cse->Gender; strcpy(eq_cse->Name, emu_cse->Name); - eq_ptr += strlen(eq_cse->Name); - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_ptr += strlen(emu_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset) + eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)] eq_cse->Beard = emu_cse->Beard; eq_cse->HairColor = emu_cse->HairColor; eq_cse->Face = emu_cse->Face; - for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) { + for (int equip_index = 0; equip_index < EQEmu::textures::TextureCount; equip_index++) { eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material; eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1; eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial; - eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; + eq_cse->Equip[equip_index].Color = emu_cse->Equip[equip_index].Color; } eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile; @@ -1945,7 +1982,8 @@ namespace SoF uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward)); *p = nullptr; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count)); + auto outapp_create = + new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward) * count)); uchar *old_data = __emu_buffer; uchar *data = outapp_create->pBuffer; for (uint32 i = 0; i < count; ++i) @@ -2063,11 +2101,11 @@ namespace SoF eq->deity = emu->deity; eq->drakkin_heritage = emu->drakkin_heritage; eq->gender = emu->gender; - for (k = 0; k < 9; k++) { - eq->equipment[k].Material = emu->equipment[k].Material; - eq->equipment[k].Unknown1 = emu->equipment[k].Unknown1; - eq->equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; - eq->colors[k].Color = emu->colors[k].Color; + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; k++) { + eq->equipment.Slot[k].Material = emu->equipment.Slot[k].Material; + eq->equipment.Slot[k].Unknown1 = emu->equipment.Slot[k].Unknown1; + eq->equipment.Slot[k].EliteMaterial = emu->equipment.Slot[k].EliteMaterial; + eq->equipment_tint.Slot[k].Color = emu->equipment_tint.Slot[k].Color; } eq->StandState = emu->StandState; eq->guildID = emu->guildID; @@ -2086,6 +2124,7 @@ namespace SoF eq->runspeed = emu->runspeed; eq->light = emu->light; eq->level = emu->level; + eq->PlayerState = emu->PlayerState; eq->lfg = emu->lfg; eq->hairstyle = emu->hairstyle; eq->haircolor = emu->haircolor; @@ -2128,8 +2167,8 @@ namespace SoF strcpy(eq->name, emu->name); eq->petOwnerId = emu->petOwnerId; eq->pvp = 0; // 0 = non-pvp colored name, 1 = red pvp name - for (k = 0; k < 9; k++) { - eq->colors[k].Color = emu->colors[k].Color; + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; k++) { + eq->equipment_tint.Slot[k].Color = emu->equipment_tint.Slot[k].Color; } eq->anon = emu->anon; eq->face = emu->face; @@ -2325,15 +2364,17 @@ namespace SoF DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.bard_modifier); + IN(buff.spellid); + IN(buff.duration); + IN(buff.counters); + IN(buff.player_id); IN(slotid); IN(bufffade); @@ -2345,7 +2386,7 @@ namespace SoF DECODE_LENGTH_EXACT(structs::CastSpell_Struct); SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct); - IN(slot); + emu->slot = static_cast(SoFToServerCastingSlot(static_cast(eq->slot), eq->inventoryslot)); IN(spell_id); emu->inventoryslot = SoFToServerSlot(eq->inventoryslot); IN(target_id); @@ -2687,7 +2728,7 @@ namespace SoF default: emu->command = eq->command; } - OUT(unknown); + IN(target); FINISH_DIRECT_DECODE(); } @@ -2867,34 +2908,26 @@ namespace SoF return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); + const EQEmu::ItemBase *item = inst->GetUnscaledItem(); + SoF::structs::ItemSerializationHeader hdr; - hdr.stacksize = stackable ? charges : 1; + + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; int32 slot_id = ServerToSoFSlot(slot_id_in); - hdr.slot = (merchant_slot == 0) ? slot_id : merchant_slot; + hdr.slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; @@ -2903,43 +2936,26 @@ namespace SoF hdr.unknown061 = 0; hdr.ItemClass = item->ItemClass; - ss.write((const char*)&hdr, sizeof(SoF::structs::ItemSerializationHeader)); + ob.write((const char*)&hdr, sizeof(SoF::structs::ItemSerializationHeader)); if (strlen(item->Name) > 0) - { - ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Name, strlen(item->Name)); + ob.write("\0", 1); if (strlen(item->Lore) > 0) - { - ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Lore, strlen(item->Lore)); + ob.write("\0", 1); if (strlen(item->IDFile) > 0) - { - ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->IDFile, strlen(item->IDFile)); + ob.write("\0", 1); SoF::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(SoF::structs::ItemBodyStruct)); ibs.id = item->ID; - ibs.weight = item->Weight; + // weight is uint8 in the struct, and some weights exceed that, so capping at 255. + ibs.weight = ((item->Weight > 255) ? 255 : item->Weight); ibs.norent = item->NoRent; ibs.nodrop = item->NoDrop; ibs.attune = item->Attuneable; @@ -2976,7 +2992,7 @@ namespace SoF ibs.Races = item->Races; ibs.Deity = item->Deity; ibs.SkillModValue = item->SkillModValue; - ibs.unknown6 = 0; + ibs.SkillModMax = item->SkillModMax; ibs.SkillModType = item->SkillModType; ibs.BaneDmgRace = item->BaneDmgRace; ibs.BaneDmgBody = item->BaneDmgBody; @@ -3021,18 +3037,12 @@ namespace SoF ibs.FactionAmt4 = item->FactionAmt4; ibs.FactionMod4 = item->FactionMod4; - ss.write((const char*)&ibs, sizeof(SoF::structs::ItemBodyStruct)); + ob.write((const char*)&ibs, sizeof(SoF::structs::ItemBodyStruct)); //charm text if (strlen(item->CharmFile) > 0) - { - ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->CharmFile, strlen(item->CharmFile)); + ob.write("\0", 1); SoF::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(SoF::structs::ItemSecondaryBodyStruct)); @@ -3040,11 +3050,10 @@ namespace SoF isbs.augtype = item->AugType; isbs.augrestrict = item->AugRestrict; - for (int x = 0; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < invaug::ItemAugSize; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -3061,17 +3070,11 @@ namespace SoF isbs.book = item->Book; isbs.booktype = item->BookType; - ss.write((const char*)&isbs, sizeof(SoF::structs::ItemSecondaryBodyStruct)); + ob.write((const char*)&isbs, sizeof(SoF::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { - ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->Filename, strlen(item->Filename)); + ob.write("\0", 1); SoF::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(SoF::structs::ItemTertiaryBodyStruct)); @@ -3091,11 +3094,11 @@ namespace SoF itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; - ss.write((const char*)&itbs, sizeof(SoF::structs::ItemTertiaryBodyStruct)); + ob.write((const char*)&itbs, sizeof(SoF::structs::ItemTertiaryBodyStruct)); // Effect Structures Broken down to allow variable length strings for effect names int32 effect_unknown = 0; @@ -3112,19 +3115,13 @@ namespace SoF ices.recast = item->RecastDelay; ices.recast_type = item->RecastType; - ss.write((const char*)&ices, sizeof(SoF::structs::ClickEffectStruct)); + ob.write((const char*)&ices, sizeof(SoF::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { - ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ClickName, strlen(item->ClickName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 + ob.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 SoF::structs::ProcEffectStruct ipes; memset(&ipes, 0, sizeof(SoF::structs::ProcEffectStruct)); @@ -3135,19 +3132,13 @@ namespace SoF ipes.level = item->Proc.Level; ipes.procrate = item->ProcRate; - ss.write((const char*)&ipes, sizeof(SoF::structs::ProcEffectStruct)); + ob.write((const char*)&ipes, sizeof(SoF::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { - ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ProcName, strlen(item->ProcName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 SoF::structs::WornEffectStruct iwes; memset(&iwes, 0, sizeof(SoF::structs::WornEffectStruct)); @@ -3157,19 +3148,13 @@ namespace SoF iwes.type = item->Worn.Type; iwes.level = item->Worn.Level; - ss.write((const char*)&iwes, sizeof(SoF::structs::WornEffectStruct)); + ob.write((const char*)&iwes, sizeof(SoF::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { - ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->WornName, strlen(item->WornName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 SoF::structs::WornEffectStruct ifes; memset(&ifes, 0, sizeof(SoF::structs::WornEffectStruct)); @@ -3179,19 +3164,13 @@ namespace SoF ifes.type = item->Focus.Type; ifes.level = item->Focus.Level; - ss.write((const char*)&ifes, sizeof(SoF::structs::WornEffectStruct)); + ob.write((const char*)&ifes, sizeof(SoF::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { - ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->FocusName, strlen(item->FocusName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 SoF::structs::WornEffectStruct ises; memset(&ises, 0, sizeof(SoF::structs::WornEffectStruct)); @@ -3201,19 +3180,13 @@ namespace SoF ises.type = item->Scroll.Type; ises.level = item->Scroll.Level; - ss.write((const char*)&ises, sizeof(SoF::structs::WornEffectStruct)); + ob.write((const char*)&ises, sizeof(SoF::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { - ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ScrollName, strlen(item->ScrollName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects SoF::structs::ItemQuaternaryBodyStruct iqbs; @@ -3241,80 +3214,53 @@ namespace SoF iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - //iqbs.clairvoyance = item->Clairvoyance; + + ob.write((const char*)&iqbs, sizeof(SoF::structs::ItemQuaternaryBodyStruct)); - iqbs.subitem_count = 0; + EQEmu::OutBuffer::pos_type count_pos = ob.tellp(); + uint32 subitem_count = 0; - char *SubSerializations[10]; // + ob.write((const char*)&subitem_count, sizeof(uint32)); - uint32 SubLengths[10]; + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; - for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; ++x) { + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; - SubSerializations[x] = nullptr; - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); + ob.write((const char*)&index, sizeof(uint32)); - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EmuConstants::GENERAL_BEGIN && slot_id_in <= EmuConstants::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EmuConstants::BANK_BEGIN && slot_id_in <= EmuConstants::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EmuConstants::SHARED_BANK_BEGIN && slot_id_in <= EmuConstants::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::SHARED_BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); - } + SerializeItem(ob, sub, SubSlotNumber, (depth + 1)); + ++subitem_count; } - ss.write((const char*)&iqbs, sizeof(SoF::structs::ItemQuaternaryBodyStruct)); - - for (int x = 0; x < 10; ++x) { - - if (SubSerializations[x]) { - ss.write((const char*)&x, sizeof(uint32)); - ss.write(SubSerializations[x], SubLengths[x]); - - safe_delete_array(SubSerializations[x]); - } - } - - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); - - *length = ss.tellp(); - return item_serial; + if (subitem_count) + ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32)); } static inline uint32 ServerToSoFSlot(uint32 serverSlot) { uint32 SoFSlot = 0; - if (serverSlot >= MainAmmo && serverSlot <= 53) // Cursor/Ammo/Power Source and Normal Inventory Slots + if (serverSlot >= EQEmu::legacy::SlotAmmo && serverSlot <= 53) // Cursor/Ammo/Power Source and Normal Inventory Slots SoFSlot = serverSlot + 1; - else if (serverSlot >= EmuConstants::GENERAL_BAGS_BEGIN && serverSlot <= EmuConstants::CURSOR_BAG_END) + else if (serverSlot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::legacy::CURSOR_BAG_END) SoFSlot = serverSlot + 11; - else if (serverSlot >= EmuConstants::BANK_BAGS_BEGIN && serverSlot <= EmuConstants::BANK_BAGS_END) + else if (serverSlot >= EQEmu::legacy::BANK_BAGS_BEGIN && serverSlot <= EQEmu::legacy::BANK_BAGS_END) SoFSlot = serverSlot + 1; - else if (serverSlot >= EmuConstants::SHARED_BANK_BAGS_BEGIN && serverSlot <= EmuConstants::SHARED_BANK_BAGS_END) + else if (serverSlot >= EQEmu::legacy::SHARED_BANK_BAGS_BEGIN && serverSlot <= EQEmu::legacy::SHARED_BANK_BAGS_END) SoFSlot = serverSlot + 1; - else if (serverSlot == MainPowerSource) - SoFSlot = slots::MainPowerSource; + else if (serverSlot == EQEmu::legacy::SlotPowerSource) + SoFSlot = invslot::PossessionsPowerSource; else SoFSlot = serverSlot; @@ -3331,16 +3277,16 @@ namespace SoF { uint32 ServerSlot = 0; - if (sofSlot >= slots::MainAmmo && sofSlot <= consts::CORPSE_END) // Cursor/Ammo/Power Source and Normal Inventory Slots + if (sofSlot >= invslot::PossessionsAmmo && sofSlot <= invslot::CorpseEnd) // Cursor/Ammo/Power Source and Normal Inventory Slots ServerSlot = sofSlot - 1; - else if (sofSlot >= consts::GENERAL_BAGS_BEGIN && sofSlot <= consts::CURSOR_BAG_END) + else if (sofSlot >= invbag::GeneralBagsBegin && sofSlot <= invbag::CursorBagEnd) ServerSlot = sofSlot - 11; - else if (sofSlot >= consts::BANK_BAGS_BEGIN && sofSlot <= consts::BANK_BAGS_END) + else if (sofSlot >= invbag::BankBagsBegin && sofSlot <= invbag::BankBagsEnd) ServerSlot = sofSlot - 1; - else if (sofSlot >= consts::SHARED_BANK_BAGS_BEGIN && sofSlot <= consts::SHARED_BANK_BAGS_END) + else if (sofSlot >= invbag::SharedBankBagsBegin && sofSlot <= invbag::SharedBankBagsEnd) ServerSlot = sofSlot - 1; - else if (sofSlot == slots::MainPowerSource) - ServerSlot = MainPowerSource; + else if (sofSlot == invslot::PossessionsPowerSource) + ServerSlot = EQEmu::legacy::SlotPowerSource; else ServerSlot = sofSlot; @@ -3355,7 +3301,7 @@ namespace SoF static inline void ServerToSoFTextLink(std::string& sofTextLink, const std::string& serverTextLink) { - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { + if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { sofTextLink = serverTextLink; return; } @@ -3364,7 +3310,7 @@ namespace SoF for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { sofTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -3395,7 +3341,7 @@ namespace SoF static inline void SoFToServerTextLink(std::string& serverTextLink, const std::string& sofTextLink) { - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (sofTextLink.find('\x12') == std::string::npos)) { + if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (sofTextLink.find('\x12') == std::string::npos)) { serverTextLink = sofTextLink; return; } @@ -3404,7 +3350,7 @@ namespace SoF for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= constants::SayLinkBodySize) { serverTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -3428,5 +3374,76 @@ namespace SoF } } } -} -// end namespace SoF + + static inline CastingSlot ServerToSoFCastingSlot(EQEmu::CastingSlot slot) + { + switch (slot) { + case EQEmu::CastingSlot::Gem1: + return CastingSlot::Gem1; + case EQEmu::CastingSlot::Gem2: + return CastingSlot::Gem2; + case EQEmu::CastingSlot::Gem3: + return CastingSlot::Gem3; + case EQEmu::CastingSlot::Gem4: + return CastingSlot::Gem4; + case EQEmu::CastingSlot::Gem5: + return CastingSlot::Gem5; + case EQEmu::CastingSlot::Gem6: + return CastingSlot::Gem6; + case EQEmu::CastingSlot::Gem7: + return CastingSlot::Gem7; + case EQEmu::CastingSlot::Gem8: + return CastingSlot::Gem8; + case EQEmu::CastingSlot::Gem9: + return CastingSlot::Gem9; + case EQEmu::CastingSlot::Item: + return CastingSlot::Item; + case EQEmu::CastingSlot::PotionBelt: + return CastingSlot::PotionBelt; + case EQEmu::CastingSlot::Discipline: + return CastingSlot::Discipline; + case EQEmu::CastingSlot::AltAbility: + return CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return CastingSlot::Discipline; + } + } + + static inline EQEmu::CastingSlot SoFToServerCastingSlot(CastingSlot slot, uint32 itemlocation) + { + switch (slot) { + case CastingSlot::Gem1: + return EQEmu::CastingSlot::Gem1; + case CastingSlot::Gem2: + return EQEmu::CastingSlot::Gem2; + case CastingSlot::Gem3: + return EQEmu::CastingSlot::Gem3; + case CastingSlot::Gem4: + return EQEmu::CastingSlot::Gem4; + case CastingSlot::Gem5: + return EQEmu::CastingSlot::Gem5; + case CastingSlot::Gem6: + return EQEmu::CastingSlot::Gem6; + case CastingSlot::Gem7: + return EQEmu::CastingSlot::Gem7; + case CastingSlot::Gem8: + return EQEmu::CastingSlot::Gem8; + case CastingSlot::Gem9: + return EQEmu::CastingSlot::Gem9; + case CastingSlot::Ability: + return EQEmu::CastingSlot::Ability; + // Tit uses 10 for item and discipline casting, but items have a valid location + case CastingSlot::Item: + if (itemlocation == INVALID_INDEX) + return EQEmu::CastingSlot::Discipline; + else + return EQEmu::CastingSlot::Item; + case CastingSlot::PotionBelt: + return EQEmu::CastingSlot::PotionBelt; + case CastingSlot::AltAbility: + return EQEmu::CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return EQEmu::CastingSlot::Discipline; + } + } +} /*SoF*/ diff --git a/common/patches/sof.h b/common/patches/sof.h index 6a67009d1..47c023471 100644 --- a/common/patches/sof.h +++ b/common/patches/sof.h @@ -1,11 +1,31 @@ -#ifndef SOF_H_ -#define SOF_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_SOF_H +#define COMMON_SOF_H #include "../struct_strategy.h" class EQStreamIdentifier; -namespace SoF { +namespace SoF +{ //these are the only public member of this namespace. extern void Register(EQStreamIdentifier &into); @@ -23,13 +43,30 @@ namespace SoF { protected: virtual std::string Describe() const; - virtual const ClientVersion GetClientVersion() const; + virtual const EQEmu::versions::ClientVersion ClientVersion() const; //magic macro to declare our opcode processors #include "ss_declare.h" #include "sof_ops.h" }; -}; + enum class CastingSlot : uint32 { + Gem1 = 0, + Gem2 = 1, + Gem3 = 2, + Gem4 = 3, + Gem5 = 4, + Gem6 = 5, + Gem7 = 6, + Gem8 = 7, + Gem9 = 8, + Ability = 9, + Item = 10, + Discipline = 10, + PotionBelt = 11, + AltAbility = 0xFF + }; -#endif /*SOF_H_*/ +}; /*SoF*/ + +#endif /*COMMON_SOF_H*/ diff --git a/common/patches/sof_constants.h b/common/patches/sof_constants.h deleted file mode 100644 index 260722f00..000000000 --- a/common/patches/sof_constants.h +++ /dev/null @@ -1,221 +0,0 @@ -/* -EQEMu: Everquest Server Emulator - -Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY except by those people which sell it, which -are required to give you total support for your newly bought product; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef SOF_CONSTANTS_H_ -#define SOF_CONSTANTS_H_ - -#include "../types.h" - -namespace SoF { - namespace maps { - typedef enum : int16 { - // this needs work to match actual client equivilents - MapPossessions = 0, - MapBank, - MapSharedBank, - MapTrade, - MapWorld, - MapLimbo, - MapTribute, - MapTrophyTribute, - MapGuildTribute, - MapMerchant, - MapDeleted, - MapCorpse, - MapBazaar, - MapInspect, - MapRealEstate, - MapViewMODPC, - MapViewMODBank, - MapViewMODSharedBank, - MapViewMODLimbo, - MapAltStorage, - MapArchived, - MapMail, - MapGuildTrophyTribute, - MapOther, - _MapCount - } InventoryMaps; - } - - namespace slots { - typedef enum : int16 { - MainCharm = 0, - MainEar1, - MainHead, - MainFace, - MainEar2, - MainNeck, - MainShoulders, - MainArms, - MainBack, - MainWrist1, - MainWrist2, - MainRange, - MainHands, - MainPrimary, - MainSecondary, - MainFinger1, - MainFinger2, - MainChest, - MainLegs, - MainFeet, - MainWaist, - MainPowerSource, - MainAmmo, - MainGeneral1, - MainGeneral2, - MainGeneral3, - MainGeneral4, - MainGeneral5, - MainGeneral6, - MainGeneral7, - MainGeneral8, - MainCursor, - _MainCount, - _MainEquipmentBegin = MainCharm, - _MainEquipmentEnd = MainAmmo, - _MainEquipmentCount = (_MainEquipmentEnd - _MainEquipmentBegin + 1), - _MainGeneralBegin = MainGeneral1, - _MainGeneralEnd = MainGeneral8, - _MainGeneralCount = (_MainGeneralEnd - _MainGeneralBegin + 1) - } EquipmentSlots; - } - - namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 12; - - static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; - static const uint16 MAP_BANK_SIZE = 24; - static const uint16 MAP_SHARED_BANK_SIZE = 2; - static const uint16 MAP_TRADE_SIZE = 8; - static const uint16 MAP_WORLD_SIZE = 10; - static const uint16 MAP_LIMBO_SIZE = 36; - static const uint16 MAP_TRIBUTE_SIZE = 0; //? - static const uint16 MAP_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_GUILD_TRIBUTE_SIZE = 0; - static const uint16 MAP_MERCHANT_SIZE = 0; - static const uint16 MAP_DELETED_SIZE = 0; - static const uint16 MAP_CORPSE_SIZE = slots::_MainCount; - static const uint16 MAP_BAZAAR_SIZE = 80; - static const uint16 MAP_INSPECT_SIZE = slots::_MainEquipmentCount; - static const uint16 MAP_REAL_ESTATE_SIZE = 0; - static const uint16 MAP_VIEW_MOD_PC_SIZE = MAP_POSSESSIONS_SIZE; - static const uint16 MAP_VIEW_MOD_BANK_SIZE = MAP_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_SHARED_BANK_SIZE = MAP_SHARED_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_LIMBO_SIZE = MAP_LIMBO_SIZE; - static const uint16 MAP_ALT_STORAGE_SIZE = 0; - static const uint16 MAP_ARCHIVED_SIZE = 0; - static const uint16 MAP_MAIL_SIZE = 0; - static const uint16 MAP_GUILD_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_KRONO_SIZE = NOT_USED; - static const uint16 MAP_OTHER_SIZE = 0; - - static const int16 EQUIPMENT_BEGIN = slots::MainCharm; - static const int16 EQUIPMENT_END = slots::MainAmmo; - static const uint16 EQUIPMENT_SIZE = slots::_MainEquipmentCount; - - static const int16 GENERAL_BEGIN = slots::MainGeneral1; - static const int16 GENERAL_END = slots::MainGeneral8; - static const uint16 GENERAL_SIZE = slots::_MainGeneralCount; - static const int16 GENERAL_BAGS_BEGIN = 262; - static const int16 GENERAL_BAGS_END_OFFSET = 79; - static const int16 GENERAL_BAGS_END = GENERAL_BAGS_BEGIN + GENERAL_BAGS_END_OFFSET; - - static const int16 CURSOR = slots::MainCursor; - static const int16 CURSOR_BAG_BEGIN = 342; - static const int16 CURSOR_BAG_END_OFFSET = 9; - static const int16 CURSOR_BAG_END = CURSOR_BAG_BEGIN + CURSOR_BAG_END_OFFSET; - - static const int16 BANK_BEGIN = 2000; - static const int16 BANK_END = 2023; - static const int16 BANK_BAGS_BEGIN = 2032; - static const int16 BANK_BAGS_END_OFFSET = 239; - static const int16 BANK_BAGS_END = BANK_BAGS_BEGIN + BANK_BAGS_END_OFFSET; - - static const int16 SHARED_BANK_BEGIN = 2500; - static const int16 SHARED_BANK_END = 2501; - static const int16 SHARED_BANK_BAGS_BEGIN = 2532; - static const int16 SHARED_BANK_BAGS_END_OFFSET = 19; - static const int16 SHARED_BANK_BAGS_END = SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_END_OFFSET; - - static const int16 TRADE_BEGIN = 3000; - static const int16 TRADE_END = 3007; - static const int16 TRADE_NPC_END = 3003; - static const int16 TRADE_BAGS_BEGIN = 3031; - static const int16 TRADE_BAGS_END_OFFSET = 79; - static const int16 TRADE_BAGS_END = TRADE_BAGS_BEGIN + TRADE_BAGS_END_OFFSET; - - static const int16 WORLD_BEGIN = 4000; - static const int16 WORLD_END = 4009; - - static const int16 TRIBUTE_BEGIN = 400; - static const int16 TRIBUTE_END = 404; - - static const int16 CORPSE_BEGIN = slots::MainGeneral1; - static const int16 CORPSE_END = slots::MainGeneral1 + slots::MainCursor; - - static const uint16 ITEM_COMMON_SIZE = 5; - static const uint16 ITEM_CONTAINER_SIZE = 10; - - static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances - static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance - - static const size_t POTION_BELT_ITEM_COUNT = 5; - - static const size_t TEXT_LINK_BODY_LENGTH = 50; - } - - namespace limits { - static const bool ALLOWS_EMPTY_BAG_IN_BAG = false; - static const bool ALLOWS_CLICK_CAST_FROM_BAG = false; - static const bool COIN_HAS_WEIGHT = true; - } - -}; //end namespace SoF - -#endif /*SOF_CONSTANTS_H_*/ - -/* -SoF Notes: - ** Integer-based inventory ** -ok Possessions: 0 - 31 (Corpse: 23 - 54 [Offset 23]) -ok [Equipment: 0 - 22] -ok [General: 23 - 30] -ok [Cursor: 31] -ok General Bags: 262 - 341 -ok Cursor Bags: 342 - 351 - -ok Bank: 2000 - 2023 -ok Bank Bags: 2032 - 2271 - -ok Shared Bank: 2500 - 2501 -ok Shared Bank Bags: 2532 - 2551 - - Trade: 3000 - 3007 - (Trade Bags: 3031 - 3110 -- server values) - - World: 4000 - 4009 - -code file reviewed.. - ..SerializeItem() needs work - ..still needs timestamp redirect code -*/ diff --git a/common/patches/sof_limits.cpp b/common/patches/sof_limits.cpp new file mode 100644 index 000000000..b33943905 --- /dev/null +++ b/common/patches/sof_limits.cpp @@ -0,0 +1,272 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "sof_limits.h" + +#include "../string_util.h" + + +size_t SoF::invtype::GetInvTypeSize(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + return invtype::InvTypePossessionsSize; + case invtype::InvTypeBank: + return invtype::InvTypeBankSize; + case invtype::InvTypeSharedBank: + return invtype::InvTypeSharedBankSize; + case invtype::InvTypeTrade: + return invtype::InvTypeTradeSize; + case invtype::InvTypeWorld: + return invtype::InvTypeWorldSize; + case invtype::InvTypeLimbo: + return invtype::InvTypeLimboSize; + case invtype::InvTypeTribute: + return invtype::InvTypeTributeSize; + case invtype::InvTypeGuildTribute: + return invtype::InvTypeGuildTributeSize; + case invtype::InvTypeMerchant: + return invtype::InvTypeMerchantSize; + case invtype::InvTypeCorpse: + return invtype::InvTypeCorpseSize; + case invtype::InvTypeBazaar: + return invtype::InvTypeBazaarSize; + case invtype::InvTypeInspect: + return invtype::InvTypeInspectSize; + case invtype::InvTypeViewMODPC: + return invtype::InvTypeViewMODPCSize; + case invtype::InvTypeViewMODBank: + return invtype::InvTypeViewMODBankSize; + case invtype::InvTypeViewMODSharedBank: + return invtype::InvTypeViewMODSharedBankSize; + case invtype::InvTypeViewMODLimbo: + return invtype::InvTypeViewMODLimboSize; + case invtype::InvTypeAltStorage: + return invtype::InvTypeAltStorageSize; + case invtype::InvTypeArchived: + return invtype::InvTypeArchivedSize; + case invtype::InvTypeOther: + return invtype::InvTypeOtherSize; + default: + return 0; + } +} + +const char* SoF::invtype::GetInvTypeName(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypeInvalid: + return "Invalid Type"; + case invtype::InvTypePossessions: + return "Possessions"; + case invtype::InvTypeBank: + return "Bank"; + case invtype::InvTypeSharedBank: + return "Shared Bank"; + case invtype::InvTypeTrade: + return "Trade"; + case invtype::InvTypeWorld: + return "World"; + case invtype::InvTypeLimbo: + return "Limbo"; + case invtype::InvTypeTribute: + return "Tribute"; + case invtype::InvTypeGuildTribute: + return "Guild Tribute"; + case invtype::InvTypeMerchant: + return "Merchant"; + case invtype::InvTypeCorpse: + return "Corpse"; + case invtype::InvTypeBazaar: + return "Bazaar"; + case invtype::InvTypeInspect: + return "Inspect"; + case invtype::InvTypeViewMODPC: + return "View MOD PC"; + case invtype::InvTypeViewMODBank: + return "View MOD Bank"; + case invtype::InvTypeViewMODSharedBank: + return "View MOD Shared Bank"; + case invtype::InvTypeViewMODLimbo: + return "View MOD Limbo"; + case invtype::InvTypeAltStorage: + return "Alt Storage"; + case invtype::InvTypeArchived: + return "Archived"; + case invtype::InvTypeOther: + return "Other"; + default: + return "Unknown Type"; + } +} + +bool SoF::invtype::IsInvTypePersistent(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + case invtype::InvTypeBank: + case invtype::InvTypeSharedBank: + case invtype::InvTypeTrade: + case invtype::InvTypeWorld: + case invtype::InvTypeLimbo: + case invtype::InvTypeTribute: + case invtype::InvTypeGuildTribute: + return true; + default: + return false; + } +} + +const char* SoF::invslot::GetInvPossessionsSlotName(int inv_slot) +{ + switch (inv_slot) { + case invslot::InvSlotInvalid: + return "Invalid Slot"; + case invslot::PossessionsCharm: + return "Charm"; + case invslot::PossessionsEar1: + return "Ear 1"; + case invslot::PossessionsHead: + return "Head"; + case invslot::PossessionsFace: + return "Face"; + case invslot::PossessionsEar2: + return "Ear 2"; + case invslot::PossessionsNeck: + return "Neck"; + case invslot::PossessionsShoulders: + return "Shoulders"; + case invslot::PossessionsArms: + return "Arms"; + case invslot::PossessionsBack: + return "Back"; + case invslot::PossessionsWrist1: + return "Wrist 1"; + case invslot::PossessionsWrist2: + return "Wrist 2"; + case invslot::PossessionsRange: + return "Range"; + case invslot::PossessionsHands: + return "Hands"; + case invslot::PossessionsPrimary: + return "Primary"; + case invslot::PossessionsSecondary: + return "Secondary"; + case invslot::PossessionsFinger1: + return "Finger 1"; + case invslot::PossessionsFinger2: + return "Finger 2"; + case invslot::PossessionsChest: + return "Chest"; + case invslot::PossessionsLegs: + return "Legs"; + case invslot::PossessionsFeet: + return "Feet"; + case invslot::PossessionsWaist: + return "Waist"; + case invslot::PossessionsPowerSource: + return "Power Source"; + case invslot::PossessionsAmmo: + return "Ammo"; + case invslot::PossessionsGeneral1: + return "General 1"; + case invslot::PossessionsGeneral2: + return "General 2"; + case invslot::PossessionsGeneral3: + return "General 3"; + case invslot::PossessionsGeneral4: + return "General 4"; + case invslot::PossessionsGeneral5: + return "General 5"; + case invslot::PossessionsGeneral6: + return "General 6"; + case invslot::PossessionsGeneral7: + return "General 7"; + case invslot::PossessionsGeneral8: + return "General 8"; + case invslot::PossessionsCursor: + return "Cursor"; + default: + return "Unknown Slot"; + } +} + +const char* SoF::invslot::GetInvCorpseSlotName(int inv_slot) +{ + if (!invtype::GetInvTypeSize(invtype::InvTypeCorpse) || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + // needs work + if ((size_t)(inv_slot + 1) < invslot::CorpseBegin || (size_t)(inv_slot + 1) >= invslot::CorpseEnd) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* SoF::invslot::GetInvSlotName(int inv_type, int inv_slot) +{ + if (inv_type == invtype::InvTypePossessions) + return invslot::GetInvPossessionsSlotName(inv_slot); + else if (inv_type == invtype::InvTypeCorpse) + return invslot::GetInvCorpseSlotName(inv_slot); + + size_t type_size = invtype::GetInvTypeSize(inv_type); + + if (!type_size || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + if ((size_t)(inv_slot + 1) >= type_size) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* SoF::invbag::GetInvBagIndexName(int bag_index) +{ + if (bag_index == invbag::InvBagInvalid) + return "Invalid Bag"; + + if ((size_t)bag_index >= invbag::ItemBagSize) + return "Unknown Bag"; + + static std::string ret_str; + ret_str = StringFormat("Bag %i", (bag_index + 1)); + + return ret_str.c_str(); +} + +const char* SoF::invaug::GetInvAugIndexName(int aug_index) +{ + if (aug_index == invaug::InvAugInvalid) + return "Invalid Augment"; + + if ((size_t)aug_index >= invaug::ItemAugSize) + return "Unknown Augment"; + + static std::string ret_str; + ret_str = StringFormat("Augment %i", (aug_index + 1)); + + return ret_str.c_str(); +} diff --git a/common/patches/sof_limits.h b/common/patches/sof_limits.h new file mode 100644 index 000000000..575df39ba --- /dev/null +++ b/common/patches/sof_limits.h @@ -0,0 +1,312 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_SOF_LIMITS_H +#define COMMON_SOF_LIMITS_H + +#include "../types.h" +#include "../emu_versions.h" +#include "../skills.h" + + +namespace SoF +{ + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + // pre-declarations + namespace inventory { + inline EQEmu::versions::ClientVersion GetInventoryRef() { return EQEmu::versions::ClientVersion::SoF; } + + } /*inventory*/ + + namespace invtype { + inline EQEmu::versions::ClientVersion GetInvTypeRef() { return EQEmu::versions::ClientVersion::SoF; } + + enum : int { InvTypeInvalid = -1, InvTypeBegin }; + + enum InventoryType : int { + InvTypePossessions = InvTypeBegin, + InvTypeBank, + InvTypeSharedBank, + InvTypeTrade, + InvTypeWorld, + InvTypeLimbo, + InvTypeTribute, + InvTypeGuildTribute, + InvTypeMerchant, + InvTypeCorpse, + InvTypeBazaar, + InvTypeInspect, + InvTypeViewMODPC, + InvTypeViewMODBank, + InvTypeViewMODSharedBank, + InvTypeViewMODLimbo, + InvTypeAltStorage, + InvTypeArchived, + InvTypeOther, + InvTypeCount + }; + + } /*invtype*/ + + namespace invslot { + inline EQEmu::versions::ClientVersion GetInvSlotRef() { return EQEmu::versions::ClientVersion::SoF; } + + enum : int { InvSlotInvalid = -1, InvSlotBegin }; + + enum PossessionsSlot : int { + PossessionsCharm = InvSlotBegin, + PossessionsEar1, + PossessionsHead, + PossessionsFace, + PossessionsEar2, + PossessionsNeck, + PossessionsShoulders, + PossessionsArms, + PossessionsBack, + PossessionsWrist1, + PossessionsWrist2, + PossessionsRange, + PossessionsHands, + PossessionsPrimary, + PossessionsSecondary, + PossessionsFinger1, + PossessionsFinger2, + PossessionsChest, + PossessionsLegs, + PossessionsFeet, + PossessionsWaist, + PossessionsPowerSource, + PossessionsAmmo, + PossessionsGeneral1, + PossessionsGeneral2, + PossessionsGeneral3, + PossessionsGeneral4, + PossessionsGeneral5, + PossessionsGeneral6, + PossessionsGeneral7, + PossessionsGeneral8, + PossessionsCursor, + PossessionsCount + }; + + const int EquipmentBegin = PossessionsCharm; + const int EquipmentEnd = PossessionsAmmo; + const int EquipmentCount = (EquipmentEnd - EquipmentBegin + 1); + + const int GeneralBegin = PossessionsGeneral1; + const int GeneralEnd = PossessionsGeneral8; + const int GeneralCount = (GeneralEnd - GeneralBegin + 1); + + } /*invslot*/ + + namespace invbag { + inline EQEmu::versions::ClientVersion GetInvBagRef() { return EQEmu::versions::ClientVersion::SoF; } + + enum : int { InvBagInvalid = -1, InvBagBegin }; + + } /*invbag*/ + + namespace invaug { + inline EQEmu::versions::ClientVersion GetInvAugRef() { return EQEmu::versions::ClientVersion::SoF; } + + enum : int { InvAugInvalid = -1, InvAugBegin }; + + } /*invaug*/ + + namespace item { + inline EQEmu::versions::ClientVersion GetItemRef() { return EQEmu::versions::ClientVersion::SoF; } + + enum ItemPacketType : int { + ItemPacketMerchant = 100, + ItemPacketTradeView = 101, + ItemPacketLoot = 102, + ItemPacketTrade = 103, + ItemPacketCharInventory = 105, + ItemPacketLimbo = 106, + ItemPacketWorldContainer = 107, + ItemPacketTributeItem = 108, + ItemPacketGuildTribute = 109, + ItemPacketCharmUpdate = 110 + }; + + } /*item*/ + + namespace profile { + inline EQEmu::versions::ClientVersion GetProfileRef() { return EQEmu::versions::ClientVersion::SoF; } + + } /*profile*/ + + namespace constants { + inline EQEmu::versions::ClientVersion GetConstantsRef() { return EQEmu::versions::ClientVersion::SoF; } + + } /*constants*/ + + namespace behavior { + inline EQEmu::versions::ClientVersion GetBehaviorRef() { return EQEmu::versions::ClientVersion::SoF; } + + } /*behavior*/ + + namespace skills { + inline EQEmu::versions::ClientVersion GetSkillsRef() { return EQEmu::versions::ClientVersion::SoF; } + + } /*skills*/ + + + // declarations + namespace inventory { + const bool ConcatenateInvTypeLimbo = true; + + const bool AllowOverLevelEquipment = false; + + const bool AllowEmptyBagInBag = false; + const bool AllowClickCastFromBag = false; + + } /*inventory*/ + + namespace invtype { + const size_t InvTypePossessionsSize = invslot::PossessionsCount; + const size_t InvTypeBankSize = 24; + const size_t InvTypeSharedBankSize = 2; + const size_t InvTypeTradeSize = 8; + const size_t InvTypeWorldSize = 10; + const size_t InvTypeLimboSize = 36; + const size_t InvTypeTributeSize = 5; + const size_t InvTypeGuildTributeSize = 2; + const size_t InvTypeMerchantSize = 80; + const size_t InvTypeCorpseSize = InvTypePossessionsSize; + const size_t InvTypeBazaarSize = 80; + const size_t InvTypeInspectSize = invslot::EquipmentCount; + const size_t InvTypeViewMODPCSize = InvTypePossessionsSize; + const size_t InvTypeViewMODBankSize = InvTypeBankSize; + const size_t InvTypeViewMODSharedBankSize = InvTypeSharedBankSize; + const size_t InvTypeViewMODLimboSize = InvTypeLimboSize; + const size_t InvTypeAltStorageSize = 0;//unknown - "Shroud Bank" + const size_t InvTypeArchivedSize = 0;//unknown + const size_t InvTypeOtherSize = 0;//unknown + + extern size_t GetInvTypeSize(int inv_type); + extern const char* GetInvTypeName(int inv_type); + + extern bool IsInvTypePersistent(int inv_type); + + } /*invtype*/ + + namespace invslot { + const int BankBegin = 2000; + const int BankEnd = (BankBegin + invtype::InvTypeBankSize) - 1; + + const int SharedBankBegin = 2500; + const int SharedBankEnd = (SharedBankBegin + invtype::InvTypeSharedBankSize) - 1; + + const int TradeBegin = 3000; + const int TradeEnd = (TradeBegin + invtype::InvTypeTradeSize) - 1; + const int TradeNPCEnd = 3003; + + const int WorldBegin = 4000; + const int WorldEnd = (WorldBegin + invtype::InvTypeWorldSize) - 1; + + const int TributeBegin = 400; + const int TributeEnd = (TributeBegin + invtype::InvTypeTributeSize) - 1; + + const int GuildTributeBegin = 450; + const int GuildTributeEnd = (GuildTributeBegin + invtype::InvTypeGuildTributeSize) - 1; + + const int CorpseBegin = PossessionsGeneral1; + const int CorpseEnd = PossessionsGeneral1 + PossessionsCursor; + + extern const char* GetInvPossessionsSlotName(int inv_slot); + extern const char* GetInvCorpseSlotName(int inv_slot); + extern const char* GetInvSlotName(int inv_type, int inv_slot); + + } /*invslot*/ + + namespace invbag { + const size_t ItemBagSize = 10; + + const int GeneralBagsBegin = 262; + const int GeneralBagsSize = invslot::GeneralCount * ItemBagSize; + const int GeneralBagsEnd = (GeneralBagsBegin + GeneralBagsSize) - 1; + + const int CursorBagBegin = 342; + const int CursorBagSize = ItemBagSize; + const int CursorBagEnd = (CursorBagBegin + CursorBagSize) - 1; + + const int BankBagsBegin = 2032; + const int BankBagsSize = (invtype::InvTypeBankSize * ItemBagSize); + const int BankBagsEnd = (BankBagsBegin + BankBagsSize) - 1; + + const int SharedBankBagsBegin = 2532; + const int SharedBankBagsSize = invtype::InvTypeSharedBankSize * ItemBagSize; + const int SharedBankBagsEnd = (SharedBankBagsBegin + SharedBankBagsSize) - 1; + + const int TradeBagsBegin = 3031; + const int TradeBagsSize = invtype::InvTypeTradeSize * ItemBagSize; + const int TradeBagsEnd = (TradeBagsBegin + TradeBagsSize) - 1; + + extern const char* GetInvBagIndexName(int bag_index); + + } /*invbag*/ + + namespace invaug { + const size_t ItemAugSize = 5; + + extern const char* GetInvAugIndexName(int aug_index); + + } /*invaug*/ + + namespace item { + + } /*item*/ + + namespace profile { + const size_t TributeSize = invtype::InvTypeTributeSize; + const size_t GuildTributeSize = invtype::InvTypeGuildTributeSize; + + const size_t BandoliersSize = 20; // number of bandolier instances + const size_t BandolierItemCount = 4; // number of equipment slots in bandolier instance + + const size_t PotionBeltSize = 5; + + const size_t SkillArraySize = 100; + + } /*profile*/ + + namespace constants { + const size_t CharacterCreationLimit = 12; + + const size_t SayLinkBodySize = 50; + + } /*constants*/ + + namespace behavior { + const bool CoinHasWeight = true; + + } /*behavior*/ + + namespace skills { + const size_t LastUsableSkill = EQEmu::skills::SkillTripleAttack; + + } /*skills*/ + +}; /*SoF*/ + +#endif /*COMMON_SOF_LIMITS_H*/ diff --git a/common/patches/sof_ops.h b/common/patches/sof_ops.h index f7077f05b..68ff402f1 100644 --- a/common/patches/sof_ops.h +++ b/common/patches/sof_ops.h @@ -1,3 +1,23 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + // out-going packets that require an ENCODE translation: E(OP_Action) E(OP_AdventureMerchantSell) @@ -37,6 +57,7 @@ E(OP_LeadershipExpUpdate) E(OP_LogServer) E(OP_LootItem) E(OP_ManaChange) +E(OP_MemorizeSpell) E(OP_MoveItem) E(OP_NewSpawn) E(OP_NewZone) diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index 51dbef1f5..0256132bd 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -1,7 +1,28 @@ -#ifndef SOF_STRUCTS_H_ -#define SOF_STRUCTS_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) -namespace SoF { + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_SOF_STRUCTS_H +#define COMMON_SOF_STRUCTS_H + + +namespace SoF +{ namespace structs { @@ -101,7 +122,7 @@ struct AdventureInfo { ** Merth: Gave struct a name so gcc 2.96 would compile ** */ -struct Color_Struct +struct Tint_Struct { union { struct { @@ -109,19 +130,62 @@ struct Color_Struct uint8 Green; uint8 Red; uint8 UseTint; // if there's a tint this is FF - } RGB; + }; uint32 Color; }; }; -struct CharSelectEquip +struct TintProfile +{ + union { + struct { + Tint_Struct Head; + Tint_Struct Chest; + Tint_Struct Arms; + Tint_Struct Wrist; + Tint_Struct Hands; + Tint_Struct Legs; + Tint_Struct Feet; + Tint_Struct Primary; + Tint_Struct Secondary; + }; + Tint_Struct Slot[EQEmu::textures::TextureCount]; + }; +}; + +/* +* Visible equiptment. +* Size: 12 Octets +*/ +struct Texture_Struct { uint32 Material; uint32 Unknown1; uint32 EliteMaterial; - Color_Struct Color; }; +struct TextureProfile +{ + union { + struct { + Texture_Struct Head; + Texture_Struct Chest; + Texture_Struct Arms; + Texture_Struct Wrist; + Texture_Struct Hands; + Texture_Struct Legs; + Texture_Struct Feet; + Texture_Struct Primary; + Texture_Struct Secondary; + }; + Texture_Struct Slot[EQEmu::textures::TextureCount]; + }; + + TextureProfile(); +}; + +struct CharSelectEquip : Texture_Struct, Tint_Struct {}; + struct CharacterSelectEntry_Struct { /*0000*/ uint8 Level; // @@ -131,7 +195,7 @@ struct CharacterSelectEntry_Struct /*0000*/ uint8 Beard; // /*0001*/ uint8 HairColor; // /*0000*/ uint8 Face; // -/*0000*/ CharSelectEquip Equip[9]; +/*0000*/ CharSelectEquip Equip[EQEmu::textures::TextureCount]; /*0000*/ uint32 PrimaryIDFile; // /*0000*/ uint32 SecondaryIDFile; // /*0000*/ uint8 Unknown15; // 0xff @@ -162,19 +226,6 @@ struct CharacterSelect_Struct /*0008*/ CharacterSelectEntry_Struct Entries[0]; }; -/* -* Visible equiptment. -* Size: 12 Octets -*/ -struct EquipStruct -{ -/*00*/ uint32 Material; -/*04*/ uint32 Unknown1; -/*08*/ uint32 EliteMaterial; -/*12*/ -}; - - /* ** Generic Spawn Struct ** Length: 897 Octets @@ -201,22 +252,7 @@ struct Spawn_Struct { /*0018*/ uint8 unknown0018[4]; // /*0022*/ uint8 gender; // Gender (0=male, 1=female, 2=monster) /*0023*/ uint8 unknown0023[4]; // -/*0027*/ union - { - struct - { - /*0027*/ EquipStruct equip_helmet; // Equiptment: Helmet visual - /*0039*/ EquipStruct equip_chest; // Equiptment: Chest visual - /*0051*/ EquipStruct equip_arms; // Equiptment: Arms visual - /*0063*/ EquipStruct equip_bracers; // Equiptment: Wrist visual - /*0075*/ EquipStruct equip_hands; // Equiptment: Hands visual - /*0087*/ EquipStruct equip_legs; // Equiptment: Legs visual - /*0099*/ EquipStruct equip_feet; // Equiptment: Boots visual - /*0111*/ EquipStruct equip_primary; // Equiptment: Main visual - /*0123*/ EquipStruct equip_secondary; // Equiptment: Off visual - } equip; - /*0027*/ EquipStruct equipment[9]; - }; +/*0027*/ TextureProfile equipment; /*0135*/ uint8 StandState; // Seems to be required to be set to 0x64 for normal animation. /*0136*/ uint8 unknown0136; @@ -241,7 +277,8 @@ struct Spawn_Struct { /*0506*/ uint8 light; // Spawn's lightsource /*0507*/ uint8 unknown0507[4]; /*0511*/ uint8 level; // Spawn Level -/*0512*/ uint8 unknown0512[16]; +/*0512*/ uint32 PlayerState; +/*0516*/ uint8 unknown0516[12]; /*0528*/ uint8 lfg; /*0529*/ uint8 unknown0529[4]; /*0533*/ uint8 hairstyle; // Sets the style of hair @@ -292,22 +329,7 @@ union /*0775*/ char name[64]; // Player's Name /*0839*/ uint32 petOwnerId; // If this is a pet, the spawn id of owner /*0843*/ uint8 pvp; // 0 = normal name color, 2 = PVP name color -/*0844*/ union - { - struct - { - /*0844*/ Color_Struct color_helmet; // Color of helmet item - /*0848*/ Color_Struct color_chest; // Color of chest item - /*0852*/ Color_Struct color_arms; // Color of arms item - /*0856*/ Color_Struct color_bracers; // Color of bracers item - /*0860*/ Color_Struct color_hands; // Color of hands item - /*0864*/ Color_Struct color_legs; // Color of legs item - /*0868*/ Color_Struct color_feet; // Color of feet item - /*0872*/ Color_Struct color_primary; // Color of primary item - /*0876*/ Color_Struct color_secondary; // Color of secondary item - } equipment_colors; - /*0844*/ Color_Struct colors[9]; // Array elements correspond to struct equipment_colors above - }; +/*0844*/ TintProfile equipment_tint; /*0880*/ uint8 anon; // 0=normal, 1=anon, 2=roleplay /*0881*/ uint8 face; /*0882*/ uint8 drakkin_details; // Face Details (Spikes) on Drakkin 0 - 7 @@ -436,7 +458,7 @@ struct MemorizeSpell_Struct { uint32 slot; // Spot in the spell book/memorized slot uint32 spell_id; // Spell id (200 or c8 is minor healing, etc) uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming -//uint32 unknown12; +uint32 reduction; // lowers reuse }; /* @@ -469,11 +491,12 @@ struct DeleteSpell_Struct struct ManaChange_Struct { - uint32 new_mana; // New Mana AMount - uint32 stamina; - uint32 spell_id; - uint32 unknown12; - uint32 unknown16; +/*00*/ uint32 new_mana; // New Mana AMount +/*04*/ uint32 stamina; +/*08*/ uint32 spell_id; +/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting? +/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like +/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it }; struct SwapSpell_Struct @@ -520,32 +543,23 @@ struct SpawnAppearance_Struct // this is used inside profile struct SpellBuff_Struct { -/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; //not real -/*004*/ uint32 spellid; -/*008*/ uint32 duration; -/*012*/ uint32 counters; -/*016*/ uint32 unknown004; //Might need to be swapped with player_id -/*020*/ uint32 player_id; //'global' ID of the caster, for wearoff messages +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 bard_modifier; +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ uint32 spellid; +/*008*/ uint32 duration; +/*012*/ uint32 counters; +/*016*/ uint32 unknown016; +/*020*/ uint32 player_id; // caster ID, pretty sure just zone ID + /*024*/ - - }; -struct SpellBuffFade_Struct { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ uint32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 unknown020; //prolly global player ID -/*024*/ uint32 playerId; // Player id who cast the buff +/*004*/ SpellBuff_Struct buff; /*028*/ uint32 slotid; /*032*/ uint32 bufffade; /*036*/ @@ -644,7 +658,7 @@ struct AA_Array { uint32 AA; uint32 value; - uint32 unknown08; // Looks like AA_Array is now 12 bytes in Live + uint32 charges; // expendable charges }; @@ -683,7 +697,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; + BandolierItem_Struct Items[profile::BandolierItemCount]; }; //len = 72 @@ -697,7 +711,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; + PotionBeltItem_Struct Items[profile::PotionBeltSize]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -860,24 +874,9 @@ struct PlayerProfile_Struct //23576 Octets /*00216*/ uint8 hairstyle; // Player hair style /*00217*/ uint8 beard; // Player beard type /*00218*/ uint8 unknown00178[10]; //[10]14 on Live? -/*00228*/ union - { - struct - { - /*00228*/ EquipStruct equip_helmet; // Equiptment: Helmet visual - /*00240*/ EquipStruct equip_chest; // Equiptment: Chest visual - /*00252*/ EquipStruct equip_arms; // Equiptment: Arms visual - /*00264*/ EquipStruct equip_bracers; // Equiptment: Wrist visual - /*00276*/ EquipStruct equip_hands; // Equiptment: Hands visual - /*00288*/ EquipStruct equip_legs; // Equiptment: Legs visual - /*00300*/ EquipStruct equip_feet; // Equiptment: Boots visual - /*00312*/ EquipStruct equip_primary; // Equiptment: Main visual - /*00324*/ EquipStruct equip_secondary; // Equiptment: Off visual - } equip; - /*00228*/ EquipStruct equipment[9]; //Live Shows [108] for this part - }; +/*00228*/ TextureProfile equipment; /*00336*/ uint8 unknown00224[156]; // Live Shows [160] -/*00496*/ Color_Struct item_tint[9]; // RR GG BB 00 +/*00496*/ TintProfile item_tint; // RR GG BB 00 /*00544*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; // [3600] AAs 12 bytes each /*04132*/ uint32 points; // Unspent Practice points - RELOCATED??? /*04136*/ uint32 mana; // Current mana @@ -916,7 +915,7 @@ struct PlayerProfile_Struct //23576 Octets /*08288*/ uint32 aapoints_spent; // Number of spent AA points /*08292*/ uint32 aapoints; // Unspent AA points /*08296*/ uint8 unknown06160[4]; -/*08300*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [6400] bandolier contents +/*08300*/ Bandolier_Struct bandoliers[profile::BandoliersSize]; // [6400] bandolier contents /*14700*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot /*15060*/ uint8 unknown12852[8]; /*15068*/ uint32 available_slots; @@ -1068,7 +1067,7 @@ struct TargetReject_Struct { struct PetCommand_Struct { /*000*/ uint32 command; -/*004*/ uint32 unknown; +/*004*/ uint32 target; }; /* @@ -1133,7 +1132,7 @@ struct WearChange_Struct{ /*002*/ uint32 material; /*006*/ uint32 unknown06; /*010*/ uint32 elite_material; // 1 for Drakkin Elite Material -/*014*/ Color_Struct color; +/*014*/ Tint_Struct color; /*018*/ uint8 wear_slot_id; /*019*/ }; @@ -1182,8 +1181,8 @@ struct RequestClientZoneChange_Struct { struct Animation_Struct { /*00*/ uint16 spawnid; -/*02*/ uint8 action; -/*03*/ uint8 value; +/*02*/ uint8 speed; +/*03*/ uint8 action; /*04*/ }; @@ -1249,9 +1248,10 @@ struct CombatDamage_Struct /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 05 */ uint16 spellid; /* 07 */ int32 damage; -/* 11 */ float unknown11; // cd cc cc 3d -/* 15 */ float sequence; // see above notes in Action_Struct -/* 19 */ uint8 unknown19[9]; // was [9] +/* 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? /* 28 */ }; @@ -2931,27 +2931,6 @@ struct PetitionBug_Struct{ char text[1028]; }; -struct DyeStruct -{ - union - { - struct - { - struct Color_Struct head; - struct Color_Struct chest; - struct Color_Struct arms; - struct Color_Struct wrists; - struct Color_Struct hands; - struct Color_Struct legs; - struct Color_Struct feet; - struct Color_Struct primary; // you can't actually dye this - struct Color_Struct secondary; // or this - } - dyes; - struct Color_Struct dye[9]; - }; -}; - struct ApproveZone_Struct { char name[64]; uint32 zoneid; @@ -3675,16 +3654,19 @@ struct SendAA_Struct { /*0049*/ uint32 spellid; /*0053*/ uint32 spell_type; /*0057*/ uint32 spell_refresh; -/*0061*/ uint16 classes; -/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability +/*0061*/ uint32 classes; /*0065*/ uint32 max_level; /*0069*/ uint32 last_id; /*0073*/ uint32 next_id; /*0077*/ uint32 cost2; -/*0081*/ uint8 unknown80[7]; +/*0081*/ uint8 unknown81; +/*0082*/ uint8 grant_only; // VetAAs, progression, etc +/*0083*/ uint8 unknown83; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though +/*0084*/ uint32 expendable_charges; // max charges of the AA /*0088*/ uint32 aa_expansion; /*0092*/ uint32 special_category; -/*0096*/ uint16 unknown0096; +/*0096*/ uint8 shroud; +/*0097*/ uint8 unknown97; /*0098*/ uint32 total_abilities; /*0102*/ AA_Ability abilities[0]; }; @@ -3696,16 +3678,10 @@ struct AA_List { struct AA_Action { /*00*/ uint32 action; /*04*/ uint32 ability; -/*08*/ uint32 unknown08; +/*08*/ uint32 target_id; /*12*/ uint32 exp_value; }; -struct AA_Skills { //this should be removed and changed to AA_Array -/*00*/ uint32 aa_skill; // Total AAs Spent -/*04*/ uint32 aa_value; -/*08*/ uint32 unknown08; -}; - struct AAExpUpdate_Struct { /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*04*/ uint32 aapoints_unspent; @@ -3723,12 +3699,12 @@ struct AltAdvStats_Struct { }; struct PlayerAA_Struct { - AA_Skills aa_list[MAX_PP_AA_ARRAY]; + AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct AATable_Struct { /*00*/ int32 aa_spent; // Total AAs Spent -/*04*/ AA_Skills aa_list[MAX_PP_AA_ARRAY]; +/*04*/ AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct Weather_Struct { @@ -3862,7 +3838,7 @@ struct ItemBodyStruct uint32 Races; uint32 Deity; int32 SkillModValue; - uint32 unknown6; + uint32 SkillModMax; uint32 SkillModType; uint32 BaneDmgRace; uint32 BaneDmgBody; @@ -3966,7 +3942,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -3981,7 +3957,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4040,7 +4016,6 @@ struct ItemQuaternaryBodyStruct int32 HealAmt; int32 SpellDmg; uint32 evolve_string; // Some String, but being evolution related is just a guess - uint32 subitem_count; }; struct AugmentInfo_Struct @@ -4135,7 +4110,8 @@ struct AltCurrencySellItem_Struct { /*010*/ uint32 cost; }; - }; //end namespace structs -}; //end namespace SoF + }; /*structs*/ -#endif /*SOF_STRUCTS_H_*/ +}; /*SoF*/ + +#endif /*COMMON_SOF_STRUCTS_H*/ diff --git a/common/patches/ss_declare.h b/common/patches/ss_declare.h index bc8d8f214..b4059f640 100644 --- a/common/patches/ss_declare.h +++ b/common/patches/ss_declare.h @@ -1,6 +1,21 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ #define E(x) static void Encode_##x(EQApplicationPacket **p, std::shared_ptr dest, bool ack_req); #define D(x) static void Decode_##x(EQApplicationPacket *p); - - diff --git a/common/patches/ss_define.h b/common/patches/ss_define.h index 8502d02dd..c5815eac8 100644 --- a/common/patches/ss_define.h +++ b/common/patches/ss_define.h @@ -1,3 +1,21 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ #define ENCODE(x) void Strategy::Encode_##x(EQApplicationPacket **p, std::shared_ptr dest, bool ack_req) #define DECODE(x) void Strategy::Decode_##x(EQApplicationPacket *__packet) @@ -116,6 +134,12 @@ //a shorter assignment for direct mode #undef IN #define IN(x) emu->x = eq->x; +#define IN_str(x) \ + strncpy(emu->x, eq->x, sizeof(emu->x)); \ + emu->x[sizeof(emu->x)-1] = '\0'; +#define IN_array(x, n) \ + for(__i = 0; __i < n; __i++) \ + emu->x[__i] = eq->x[__i]; //call before any premature returns in an encoder using SETUP_DIRECT_DECODE #define FAIL_DIRECT_DECODE() \ @@ -143,14 +167,3 @@ //forward this opcode to another decoder #define DECODE_FORWARD(other_op) \ Decode_##other_op(__packet); - - - - - - - - - - - diff --git a/common/patches/ss_register.h b/common/patches/ss_register.h index b9ada774c..f8613195f 100644 --- a/common/patches/ss_register.h +++ b/common/patches/ss_register.h @@ -1,3 +1,21 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ #define E(x) encoders[x] = Encode_##x; #define D(x) decoders[x] = Decode_##x; diff --git a/common/patches/template.cpp b/common/patches/template.cpp index 5120a2ef2..5e075ea8a 100644 --- a/common/patches/template.cpp +++ b/common/patches/template.cpp @@ -16,7 +16,8 @@ static Strategy struct_strategy; void Register(EQStreamIdentifier &into) { //create our opcode manager if we havent already if(opcodes == NULL) { - string opfile = "patch_"; + string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; //load up the opcode manager. @@ -51,7 +52,8 @@ void Reload() { if(opcodes != NULL) { //TODO: get this file name from the config file - string opfile = "patch_"; + string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; if(!opcodes->ReloadOpcodes(opfile.c_str())) { diff --git a/common/patches/template.h b/common/patches/template.h index 1391516b1..f264cf3fd 100644 --- a/common/patches/template.h +++ b/common/patches/template.h @@ -2,6 +2,7 @@ #define TEMPLATE_H_ #include "../struct_strategy.h" +#include "../eqemu_config_extern.h" class EQStreamIdentifier; diff --git a/common/patches/template_constants.h b/common/patches/template_constants.h deleted file mode 100644 index f8dbc39e8..000000000 --- a/common/patches/template_constants.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef TEMPLATE_CONSTANTS_H_ -#define TEMPLATE_CONSTANTS_H_ - -namespace TEMPLATE { - - // put constants here and #include appropriately - -}; //end namespace TEMPLATE - -#endif /*TEMPLATE_CONSTANTS_H_*/ - - - - - - - - - - diff --git a/common/patches/template_limits.cpp b/common/patches/template_limits.cpp new file mode 100644 index 000000000..273e74a5c --- /dev/null +++ b/common/patches/template_limits.cpp @@ -0,0 +1,18 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ diff --git a/common/patches/template_limits.h b/common/patches/template_limits.h new file mode 100644 index 000000000..54690d3c1 --- /dev/null +++ b/common/patches/template_limits.h @@ -0,0 +1,31 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_TEMPLATE_LIMITS_H +#define COMMON_TEMPLATE_LIMITS_H + + +namespace TEMPLATE +{ + + // put constants here and #include appropriately + +}; /* TEMPLATE */ + +#endif /*COMMON_TEMPLATE_LIMITS_H*/ diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index c8eeea36a..cc10f6487 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -1,4 +1,24 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #include "../global_define.h" +#include "../eqemu_config.h" #include "../eqemu_logsys.h" #include "titanium.h" #include "../opcodemgr.h" @@ -12,15 +32,17 @@ #include "../string_util.h" #include "../item.h" #include "titanium_structs.h" + #include + namespace Titanium { static const char *name = "Titanium"; static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth); + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id_in, uint8 depth); // server to client inventory location converters static inline int16 ServerToTitaniumSlot(uint32 serverSlot); @@ -36,12 +58,17 @@ namespace Titanium // client to server text link converter static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink); + static inline CastingSlot ServerToTitaniumCastingSlot(EQEmu::CastingSlot slot); + static inline EQEmu::CastingSlot TitaniumToServerCastingSlot(CastingSlot slot, uint32 itemlocation); + void Register(EQStreamIdentifier &into) { + auto Config = EQEmuConfig::get(); //create our opcode manager if we havent already if (opcodes == nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; //load up the opcode manager. @@ -85,7 +112,9 @@ namespace Titanium if (opcodes != nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; if (!opcodes->ReloadOpcodes(opfile.c_str())) { @@ -111,9 +140,9 @@ namespace Titanium return(r); } - const ClientVersion Strategy::GetClientVersion() const + const EQEmu::versions::ClientVersion Strategy::ClientVersion() const { - return ClientVersion::Titanium; + return EQEmu::versions::ClientVersion::Titanium; } #include "ss_define.h" @@ -122,7 +151,7 @@ namespace Titanium EAT_ENCODE(OP_GuildMemberLevelUpdate); // added ; EAT_ENCODE(OP_ZoneServerReady); // added ; - + ENCODE(OP_Action) { ENCODE_LENGTH_EXACT(Action_Struct); @@ -228,6 +257,25 @@ namespace Titanium FINISH_ENCODE(); } + ENCODE(OP_Buff) + { + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); + + OUT(entityid); + OUT(buff.effect_type); + OUT(buff.level); + OUT(buff.bard_modifier); + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.counters); + OUT(buff.player_id); + OUT(slotid); + OUT(bufffade); + + FINISH_ENCODE(); + } + ENCODE(OP_ChannelMessage) { EQApplicationPacket *in = *p; @@ -260,45 +308,59 @@ namespace Titanium ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; + uchar* __emu_buffer = in->pBuffer; - int itemcount = in->size / sizeof(InternalSerializedItem_Struct); - if (itemcount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { - Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); + int itemcount = in->size / sizeof(EQEmu::InternalSerializedItem_Struct); + if (itemcount == 0 || (in->size % sizeof(EQEmu::InternalSerializedItem_Struct)) != 0) { + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", + opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(EQEmu::InternalSerializedItem_Struct)); delete in; return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + + EQEmu::InternalSerializedItem_Struct* eq = (EQEmu::InternalSerializedItem_Struct*)in->pBuffer; //do the transform... - int r; - std::string serial_string; - for (r = 0; r < itemcount; r++, eq++) { - uint32 length; - char *serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &length, 0); - if (serialized) { - serial_string.append(serialized, length + 1); - safe_delete_array(serialized); - } - else { - Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); + for (int r = 0; r < itemcount; r++, eq++) { + SerializeItem(ob, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); + + last_pos = ob.tellp(); } - in->size = serial_string.length(); - in->pBuffer = new unsigned char[in->size]; - memcpy(in->pBuffer, serial_string.c_str(), serial_string.length()); - + in->size = ob.size(); + in->pBuffer = ob.detach(); + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } + ENCODE(OP_Damage) + { + ENCODE_LENGTH_EXACT(CombatDamage_Struct); + SETUP_DIRECT_ENCODE(CombatDamage_Struct, structs::CombatDamage_Struct); + + OUT(target); + OUT(source); + OUT(type); + OUT(spellid); + OUT(damage); + OUT(force); + OUT(meleepush_xy); + OUT(meleepush_z); + + FINISH_ENCODE(); + } + ENCODE(OP_DeleteCharge) { ENCODE_FORWARD(OP_MoveItem); } ENCODE(OP_DeleteItem) @@ -326,7 +388,7 @@ namespace Titanium { SETUP_VAR_ENCODE(ExpeditionCompass_Struct); ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count); - + OUT(count); for (uint32 i = 0; i < emu->count; ++i) @@ -700,30 +762,30 @@ namespace Titanium ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + uchar* __emu_buffer = in->pBuffer; + + EQEmu::InternalSerializedItem_Struct* int_struct = (EQEmu::InternalSerializedItem_Struct*)(&__emu_buffer[4]); - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); - if (!serialized) { + ob.write((const char*)__emu_buffer, 4); + + SerializeItem(ob, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ob.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 5; // ItemPacketType + Serialization + \0 - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length + 1); + in->size = ob.size(); + in->pBuffer = ob.detach(); + delete[] __emu_buffer; - safe_delete_array(serialized); dest->FastQueuePacket(&in, ack_req); } @@ -753,7 +815,7 @@ namespace Titanium return; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LFGuild, sizeof(structs::LFGuild_PlayerToggle_Struct)); + auto outapp = new EQApplicationPacket(OP_LFGuild, sizeof(structs::LFGuild_PlayerToggle_Struct)); memcpy(outapp->pBuffer, in->pBuffer, sizeof(structs::LFGuild_PlayerToggle_Struct)); @@ -774,6 +836,22 @@ namespace Titanium FINISH_ENCODE(); } + ENCODE(OP_MemorizeSpell) + { + ENCODE_LENGTH_EXACT(MemorizeSpell_Struct); + SETUP_DIRECT_ENCODE(MemorizeSpell_Struct, structs::MemorizeSpell_Struct); + + // Since HT/LoH are translated up, we need to translate down only for memSpellSpellbar case + if (emu->scribing == 3) + eq->slot = static_cast(ServerToTitaniumCastingSlot(static_cast(emu->slot))); + else + OUT(slot); + OUT(spell_id); + OUT(scribing); + + FINISH_ENCODE(); + } + ENCODE(OP_MoveItem) { ENCODE_LENGTH_EXACT(MoveItem_Struct); @@ -813,9 +891,9 @@ namespace Titanium OUT(petid); OUT(buffcount); - int EQBuffSlot = 0; + int EQBuffSlot = 0; // do we really want to shuffle them around like this? - for (uint32 EmuBuffSlot = 0; EmuBuffSlot < BUFF_COUNT; ++EmuBuffSlot) + for (uint32 EmuBuffSlot = 0; EmuBuffSlot < PET_BUFF_COUNT; ++EmuBuffSlot) { if (emu->spellid[EmuBuffSlot]) { @@ -863,9 +941,9 @@ namespace Titanium OUT(hairstyle); OUT(beard); // OUT(unknown00178[10]); - for (r = 0; r < 9; r++) { - OUT(item_material[r]); - OUT(item_tint[r].Color); + for (r = EQEmu::textures::TextureBegin; r < EQEmu::textures::TextureCount; r++) { + OUT(item_material.Slot[r].Material); + OUT(item_tint.Slot[r].Color); } // OUT(unknown00224[48]); for (r = 0; r < structs::MAX_PP_AA_ARRAY; r++) { @@ -905,10 +983,10 @@ namespace Titanium OUT(thirst_level); OUT(hunger_level); for (r = 0; r < structs::BUFF_COUNT; r++) { - OUT(buffs[r].slotid); + OUT(buffs[r].effect_type); OUT(buffs[r].level); OUT(buffs[r].bard_modifier); - OUT(buffs[r].effect); + OUT(buffs[r].unknown003); OUT(buffs[r].spellid); OUT(buffs[r].duration); OUT(buffs[r].counters); @@ -926,18 +1004,18 @@ namespace Titanium // OUT(unknown06160[4]); // Copy bandoliers where server and client indexes converge - for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { + for (r = 0; r < EQEmu::legacy::BANDOLIERS_SIZE && r < profile::BandoliersSize; ++r) { OUT_str(bandoliers[r].Name); - for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + for (uint32 k = 0; k < profile::BandolierItemCount; ++k) { // Will need adjusting if 'server != client' is ever true OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } // Nullify bandoliers where server and client indexes diverge, with a client bias - for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + for (r = EQEmu::legacy::BANDOLIERS_SIZE; r < profile::BandoliersSize; ++r) { eq->bandoliers[r].Name[0] = '\0'; - for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + for (uint32 k = 0; k < profile::BandolierItemCount; ++k) { // Will need adjusting if 'server != client' is ever true eq->bandoliers[r].Items[k].ID = 0; eq->bandoliers[r].Items[k].Icon = 0; eq->bandoliers[r].Items[k].Name[0] = '\0'; @@ -947,13 +1025,13 @@ namespace Titanium // OUT(unknown07444[5120]); // Copy potion belt where server and client indexes converge - for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (r = 0; r < EQEmu::legacy::POTION_BELT_ITEM_COUNT && r < profile::PotionBeltSize; ++r) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); } // Nullify potion belt where server and client indexes diverge, with a client bias - for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (r = EQEmu::legacy::POTION_BELT_ITEM_COUNT; r < profile::PotionBeltSize; ++r) { eq->potionbelt.Items[r].ID = 0; eq->potionbelt.Items[r].Icon = 0; eq->potionbelt.Items[r].Name[0] = '\0'; @@ -1098,8 +1176,8 @@ namespace Titanium unsigned int r; for (r = 0; r < structs::MAX_PP_AA_ARRAY; r++) { - OUT(aa_list[r].aa_skill); - OUT(aa_list[r].aa_value); + OUT(aa_list[r].AA); + OUT(aa_list[r].value); } FINISH_ENCODE(); @@ -1107,50 +1185,53 @@ namespace Titanium ENCODE(OP_SendAATable) { - ENCODE_LENGTH_ATLEAST(SendAA_Struct); + EQApplicationPacket *inapp = *p; + *p = nullptr; + AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer; - SETUP_VAR_ENCODE(SendAA_Struct); - ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); + auto outapp = new EQApplicationPacket( + OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability)); + structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer; - // Check clientver field to verify this AA should be sent for Titanium - // clientver 1 is for all clients and 3 is for Titanium - if (emu->clientver <= 3) - { - OUT(id); - eq->unknown004 = 1; - eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->id - emu->current_level + 1); - eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->id - emu->current_level + 1); - eq->title_sid = emu->id - emu->current_level + 1; - eq->desc_sid = emu->id - emu->current_level + 1; - OUT(class_type); - OUT(cost); - OUT(seq); - OUT(current_level); - OUT(prereq_skill); - OUT(prereq_minpoints); - OUT(type); - OUT(spellid); - OUT(spell_type); - OUT(spell_refresh); - OUT(classes); - OUT(berserker); - OUT(max_level); - OUT(last_id); - OUT(next_id); - OUT(cost2); - OUT(unknown80[0]); - OUT(unknown80[1]); - OUT(total_abilities); - unsigned int r; - for (r = 0; r < emu->total_abilities; r++) { - OUT(abilities[r].skill_id); - OUT(abilities[r].base1); - OUT(abilities[r].base2); - OUT(abilities[r].slot); - } + inapp->SetReadPosition(sizeof(AARankInfo_Struct)); + outapp->SetWritePosition(sizeof(structs::SendAA_Struct)); + + eq->id = emu->id; + eq->unknown004 = 1; + eq->id = emu->id; + eq->hotkey_sid = emu->upper_hotkey_sid; + eq->hotkey_sid2 = emu->lower_hotkey_sid; + eq->desc_sid = emu->desc_sid; + eq->title_sid = emu->title_sid; + eq->class_type = emu->level_req; + eq->cost = emu->cost; + eq->seq = emu->seq; + eq->current_level = emu->current_level; + eq->type = emu->type; + eq->spellid = emu->spell; + eq->spell_type = emu->spell_type; + eq->spell_refresh = emu->spell_refresh; + eq->classes = emu->classes; + eq->max_level = emu->max_level; + eq->last_id = emu->prev_id; + eq->next_id = emu->next_id; + eq->cost2 = emu->total_cost; + eq->total_abilities = emu->total_effects; + + for(auto i = 0; i < eq->total_abilities; ++i) { + eq->abilities[i].skill_id = inapp->ReadUInt32(); + eq->abilities[i].base1 = inapp->ReadUInt32(); + eq->abilities[i].base2 = inapp->ReadUInt32(); + eq->abilities[i].slot = inapp->ReadUInt32(); } - FINISH_ENCODE(); + if(emu->total_prereqs > 0) { + eq->prereq_skill = inapp->ReadUInt32(); + eq->prereq_minpoints = inapp->ReadUInt32(); + } + + dest->FastQueuePacket(&outapp); + delete inapp; } ENCODE(OP_SendCharInfo) @@ -1180,15 +1261,15 @@ namespace Titanium if (eq->Race[char_index] > 473) eq->Race[char_index] = 1; - for (int index = 0; index < _MaterialCount; ++index) { - eq->CS_Colors[char_index][index].Color = emu_cse->Equip[index].Color.Color; + for (int index = 0; index < EQEmu::textures::TextureCount; ++index) { + eq->CS_Colors[char_index].Slot[index].Color = emu_cse->Equip[index].Color; } eq->BeardColor[char_index] = emu_cse->BeardColor; eq->HairStyle[char_index] = emu_cse->HairStyle; - for (int index = 0; index < _MaterialCount; ++index) { - eq->Equip[char_index][index] = emu_cse->Equip[index].Material; + for (int index = 0; index < EQEmu::textures::TextureCount; ++index) { + eq->Equip[char_index].Slot[index].Material = emu_cse->Equip[index].Material; } eq->SecondaryIDFile[char_index] = emu_cse->SecondaryIDFile; @@ -1217,15 +1298,15 @@ namespace Titanium for (; char_index < 10; ++char_index) { eq->Race[char_index] = 0; - for (int index = 0; index < _MaterialCount; ++index) { - eq->CS_Colors[char_index][index].Color = 0; + for (int index = 0; index < EQEmu::textures::TextureCount; ++index) { + eq->CS_Colors[char_index].Slot[index].Color = 0; } eq->BeardColor[char_index] = 0; eq->HairStyle[char_index] = 0; - for (int index = 0; index < _MaterialCount; ++index) { - eq->Equip[char_index][index] = 0; + for (int index = 0; index < EQEmu::textures::TextureCount; ++index) { + eq->Equip[char_index].Slot[index].Material = 0; } eq->SecondaryIDFile[char_index] = 0; @@ -1308,7 +1389,7 @@ namespace Titanium VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, emu->unknown12[11]); VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str()); - + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -1351,7 +1432,7 @@ namespace Titanium InBuffer += strlen(InBuffer) + 1; memcpy(OutBuffer, InBuffer, sizeof(TaskDescriptionTrailer_Struct)); - + delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); } @@ -1437,7 +1518,8 @@ namespace Titanium uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward)); *p = nullptr; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count)); + auto outapp_create = + new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward) * count)); uchar *old_data = __emu_buffer; uchar *data = outapp_create->pBuffer; for (uint32 i = 0; i < count; ++i) @@ -1549,15 +1631,15 @@ namespace Titanium eq->beardcolor = emu->beardcolor; // eq->unknown0147[4] = emu->unknown0147[4]; eq->level = emu->level; - // eq->unknown0259[4] = emu->unknown0259[4]; + eq->PlayerState = emu->PlayerState; eq->beard = emu->beard; strcpy(eq->suffix, emu->suffix); eq->petOwnerId = emu->petOwnerId; eq->guildrank = emu->guildrank; // eq->unknown0194[3] = emu->unknown0194[3]; - for (k = 0; k < 9; k++) { - eq->equipment[k] = emu->equipment[k].Material; - eq->colors[k].Color = emu->colors[k].Color; + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; k++) { + eq->equipment.Slot[k].Material = emu->equipment.Slot[k].Material; + eq->equipment_tint.Slot[k].Color = emu->equipment_tint.Slot[k].Color; } for (k = 0; k < 8; k++) { eq->set_to_0xFF[k] = 0xFF; @@ -1621,7 +1703,7 @@ namespace Titanium FINISH_DIRECT_DECODE(); } - + DECODE(OP_ApplyPoison) { DECODE_LENGTH_EXACT(structs::ApplyPoison_Struct); @@ -1644,12 +1726,31 @@ namespace Titanium FINISH_DIRECT_DECODE(); } + DECODE(OP_Buff) + { + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); + + IN(entityid); + IN(buff.effect_type); + IN(buff.level); + IN(buff.bard_modifier); + IN(buff.spellid); + IN(buff.duration); + IN(buff.counters); + IN(buff.player_id); + IN(slotid); + IN(bufffade); + + FINISH_DIRECT_DECODE(); + } + DECODE(OP_CastSpell) { DECODE_LENGTH_EXACT(structs::CastSpell_Struct); SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct); - IN(slot); + emu->slot = static_cast(TitaniumToServerCastingSlot(static_cast(eq->slot), eq->inventoryslot)); IN(spell_id); emu->inventoryslot = TitaniumToServerSlot(eq->inventoryslot); IN(target_id); @@ -1942,7 +2043,7 @@ namespace Titanium default: emu->command = eq->command; } - OUT(unknown); + IN(target); FINISH_DIRECT_DECODE(); } @@ -2060,87 +2161,241 @@ namespace Titanium } // file scope helper methods - char *SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - char *serialization = nullptr; - char *instance = nullptr; - const char *protection = (const char *)"\\\\\\\\\\"; - char *sub_items[10] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; - bool stackable = inst->IsStackable(); - int16 slot_id = ServerToTitaniumSlot(slot_id_in); - uint32 merchant_slot = inst->GetMerchantSlot(); - int16 charges = inst->GetCharges(); - const Item_Struct *item = inst->GetUnscaledItem(); - int i; - uint32 sub_length; + const char* protection = "\\\\\\\\\\"; + const EQEmu::ItemBase* item = inst->GetUnscaledItem(); - MakeAnyLenString(&instance, - "%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|", - stackable ? charges : 0, - 0, - //(merchant_slot == 0) ? slot_id : merchant_slot, // change when translator activated - (merchant_slot == 0) ? slot_id_in : merchant_slot, - inst->GetPrice(), - (merchant_slot == 0) ? 1 : inst->GetMerchantCount(), - inst->IsScaling() ? inst->GetExp() / 100 : 0, - //merchant_slot, //instance ID, bullshit for now - (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot, - inst->GetRecastTimestamp(), - (stackable ? ((inst->GetItem()->ItemType == ItemTypePotion) ? 1 : 0) : charges), - inst->IsAttuned() ? 1 : 0, - 0 - ); + ob << StringFormat("%.*s%s", (depth ? (depth - 1) : 0), protection, (depth ? "\"" : "")); // For leading quotes (and protection) if a subitem; + + // Instance data + ob << itoa((inst->IsStackable() ? inst->GetCharges() : 0)); // stack count + ob << '|' << itoa(0); // unknown + ob << '|' << itoa((!inst->GetMerchantSlot() ? slot_id_in : inst->GetMerchantSlot())); // inst slot/merchant slot + ob << '|' << itoa(inst->GetPrice()); // merchant price + ob << '|' << itoa((!inst->GetMerchantSlot() ? 1 : inst->GetMerchantCount())); // inst count/merchant count + ob << '|' << itoa((inst->IsScaling() ? (inst->GetExp() / 100) : 0)); // inst experience + ob << '|' << itoa((!inst->GetMerchantSlot() ? inst->GetSerialNumber() : inst->GetMerchantSlot())); // merchant serial number + ob << '|' << itoa(inst->GetRecastTimestamp()); // recast timestamp + ob << '|' << itoa(((inst->IsStackable() ? ((inst->GetItem()->ItemType == EQEmu::item::ItemTypePotion) ? 1 : 0) : inst->GetCharges()))); // charge count + ob << '|' << itoa((inst->IsAttuned() ? 1 : 0)); // inst attuned + ob << '|' << itoa(0); // unknown + ob << '|'; - for (i = 0; i<10; i++) { - ItemInst *sub = inst->GetItem(i); - if (sub) { - sub_items[i] = SerializeItem(sub, 0, &sub_length, depth + 1); - } + ob << StringFormat("%.*s\"", depth, protection); // Quotes (and protection, if needed) around static data + + // Item data + ob << itoa(item->ItemClass); + ob << '|' << item->Name; + ob << '|' << item->Lore; + ob << '|' << item->IDFile; + ob << '|' << itoa(item->ID); + ob << '|' << itoa(((item->Weight > 255) ? 255 : item->Weight)); + + ob << '|' << itoa(item->NoRent); + ob << '|' << itoa(item->NoDrop); + ob << '|' << itoa(item->Size); + ob << '|' << itoa(item->Slots); + ob << '|' << itoa(item->Price); + ob << '|' << itoa(item->Icon); + ob << '|' << "0"; + ob << '|' << "0"; + ob << '|' << itoa(item->BenefitFlag); + ob << '|' << itoa(item->Tradeskills); + + ob << '|' << itoa(item->CR); + ob << '|' << itoa(item->DR); + ob << '|' << itoa(item->PR); + ob << '|' << itoa(item->MR); + ob << '|' << itoa(item->FR); + + ob << '|' << itoa(item->AStr); + ob << '|' << itoa(item->ASta); + ob << '|' << itoa(item->AAgi); + ob << '|' << itoa(item->ADex); + ob << '|' << itoa(item->ACha); + ob << '|' << itoa(item->AInt); + ob << '|' << itoa(item->AWis); + + ob << '|' << itoa(item->HP); + ob << '|' << itoa(item->Mana); + ob << '|' << itoa(item->AC); + ob << '|' << itoa(item->Deity); + + ob << '|' << itoa(item->SkillModValue); + ob << '|' << itoa(item->SkillModMax); + ob << '|' << itoa(item->SkillModType); + + ob << '|' << itoa(item->BaneDmgRace); + ob << '|' << itoa(item->BaneDmgAmt); + ob << '|' << itoa(item->BaneDmgBody); + + ob << '|' << itoa(item->Magic); + ob << '|' << itoa(item->CastTime_); + ob << '|' << itoa(item->ReqLevel); + ob << '|' << itoa(item->BardType); + ob << '|' << itoa(item->BardValue); + ob << '|' << itoa(item->Light); + ob << '|' << itoa(item->Delay); + + ob << '|' << itoa(item->RecLevel); + ob << '|' << itoa(item->RecSkill); + + ob << '|' << itoa(item->ElemDmgType); + ob << '|' << itoa(item->ElemDmgAmt); + + ob << '|' << itoa(item->Range); + ob << '|' << itoa(item->Damage); + + ob << '|' << itoa(item->Color); + ob << '|' << itoa(item->Classes); + ob << '|' << itoa(item->Races); + ob << '|' << "0"; + + ob << '|' << itoa(item->MaxCharges); + ob << '|' << itoa(item->ItemType); + ob << '|' << itoa(item->Material); + ob << '|' << StringFormat("%f", item->SellRate); + + ob << '|' << "0"; + ob << '|' << itoa(item->CastTime_); + ob << '|' << "0"; + + ob << '|' << itoa(item->ProcRate); + ob << '|' << itoa(item->CombatEffects); + ob << '|' << itoa(item->Shielding); + ob << '|' << itoa(item->StunResist); + ob << '|' << itoa(item->StrikeThrough); + ob << '|' << itoa(item->ExtraDmgSkill); + ob << '|' << itoa(item->ExtraDmgAmt); + ob << '|' << itoa(item->SpellShield); + ob << '|' << itoa(item->Avoidance); + ob << '|' << itoa(item->Accuracy); + + ob << '|' << itoa(item->CharmFileID); + + ob << '|' << itoa(item->FactionMod1); + ob << '|' << itoa(item->FactionMod2); + ob << '|' << itoa(item->FactionMod3); + ob << '|' << itoa(item->FactionMod4); + + ob << '|' << itoa(item->FactionAmt1); + ob << '|' << itoa(item->FactionAmt2); + ob << '|' << itoa(item->FactionAmt3); + ob << '|' << itoa(item->FactionAmt4); + + ob << '|' << item->CharmFile; + + ob << '|' << itoa(item->AugType); + + ob << '|' << itoa(item->AugSlotType[0]); + ob << '|' << itoa(item->AugSlotVisible[0]); + ob << '|' << itoa(item->AugSlotType[1]); + ob << '|' << itoa(item->AugSlotVisible[1]); + ob << '|' << itoa(item->AugSlotType[2]); + ob << '|' << itoa(item->AugSlotVisible[2]); + ob << '|' << itoa(item->AugSlotType[3]); + ob << '|' << itoa(item->AugSlotVisible[3]); + ob << '|' << itoa(item->AugSlotType[4]); + ob << '|' << itoa(item->AugSlotVisible[4]); + + ob << '|' << itoa(item->LDoNTheme); + ob << '|' << itoa(item->LDoNPrice); + ob << '|' << itoa(item->LDoNSold); + + ob << '|' << itoa(item->BagType); + ob << '|' << itoa(item->BagSlots); + ob << '|' << itoa(item->BagSize); + ob << '|' << itoa(item->BagWR); + + ob << '|' << itoa(item->Book); + ob << '|' << itoa(item->BookType); + + ob << '|' << item->Filename; + + ob << '|' << itoa(item->BaneDmgRaceAmt); + ob << '|' << itoa(item->AugRestrict); + ob << '|' << itoa(item->LoreGroup); + ob << '|' << itoa(item->PendingLoreFlag); + ob << '|' << itoa(item->ArtifactFlag); + ob << '|' << itoa(item->SummonedFlag); + + ob << '|' << itoa(item->Favor); + ob << '|' << itoa(item->FVNoDrop); + ob << '|' << itoa(item->Endur); + ob << '|' << itoa(item->DotShielding); + ob << '|' << itoa(item->Attack); + ob << '|' << itoa(item->Regen); + ob << '|' << itoa(item->ManaRegen); + ob << '|' << itoa(item->EnduranceRegen); + ob << '|' << itoa(item->Haste); + ob << '|' << itoa(item->DamageShield); + ob << '|' << itoa(item->RecastDelay); + ob << '|' << itoa(item->RecastType); + ob << '|' << itoa(item->GuildFavor); + + ob << '|' << itoa(item->AugDistiller); + + ob << '|' << "0"; // unknown + ob << '|' << "0"; // unknown + ob << '|' << itoa(item->Attuneable); + ob << '|' << itoa(item->NoPet); + ob << '|' << "0"; // unknown + ob << '|' << itoa(item->PointType); + + ob << '|' << itoa(item->PotionBelt); + ob << '|' << itoa(item->PotionBeltSlots); + ob << '|' << itoa(item->StackSize); + ob << '|' << itoa(item->NoTransfer); + ob << '|' << itoa(item->Stackable); + + ob << '|' << itoa(item->Click.Effect); + ob << '|' << itoa(item->Click.Type); + ob << '|' << itoa(item->Click.Level2); + ob << '|' << itoa(item->Click.Level); + ob << '|' << "0"; // Click name + + ob << '|' << itoa(item->Proc.Effect); + ob << '|' << itoa(item->Proc.Type); + ob << '|' << itoa(item->Proc.Level2); + ob << '|' << itoa(item->Proc.Level); + ob << '|' << "0"; // Proc name + + ob << '|' << itoa(item->Worn.Effect); + ob << '|' << itoa(item->Worn.Type); + ob << '|' << itoa(item->Worn.Level2); + ob << '|' << itoa(item->Worn.Level); + ob << '|' << "0"; // Worn name + + ob << '|' << itoa(item->Focus.Effect); + ob << '|' << itoa(item->Focus.Type); + ob << '|' << itoa(item->Focus.Level2); + ob << '|' << itoa(item->Focus.Level); + ob << '|' << "0"; // Focus name + + ob << '|' << itoa(item->Scroll.Effect); + ob << '|' << itoa(item->Scroll.Type); + ob << '|' << itoa(item->Scroll.Level2); + ob << '|' << itoa(item->Scroll.Level); + ob << '|' << "0"; // Scroll name + + ob << StringFormat("%.*s\"", depth, protection); // Quotes (and protection, if needed) around static data + + // Sub data + for (int index = SUB_INDEX_BEGIN; index < invbag::ItemBagSize; ++index) { + ob << '|'; + + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; + + SerializeItem(ob, sub, 0, (depth + 1)); } - *length = MakeAnyLenString(&serialization, - "%.*s%s" // For leading quotes (and protection) if a subitem; - "%s" // Instance data - "%.*s\"" // Quotes (and protection, if needed) around static data - "%i" // item->ItemClass so we can do |%s instead of %s| -#define I(field) "|%i" -#define C(field) "|%s" -#define S(field) "|%s" -#define F(field) "|%f" -#include "titanium_itemfields.h" - "%.*s\"" // Quotes (and protection, if needed) around static data - "|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s" // Sub items - "%.*s%s" // For trailing quotes (and protection) if a subitem; - , depth ? depth - 1 : 0, protection, (depth) ? "\"" : "" - , instance - , depth, protection - , item->ItemClass -#define I(field) ,item->field -#define C(field) ,field -#define S(field) ,item->field -#define F(field) ,item->field -#include "titanium_itemfields.h" - , depth, protection - , sub_items[0] ? sub_items[0] : "" - , sub_items[1] ? sub_items[1] : "" - , sub_items[2] ? sub_items[2] : "" - , sub_items[3] ? sub_items[3] : "" - , sub_items[4] ? sub_items[4] : "" - , sub_items[5] ? sub_items[5] : "" - , sub_items[6] ? sub_items[6] : "" - , sub_items[7] ? sub_items[7] : "" - , sub_items[8] ? sub_items[8] : "" - , sub_items[9] ? sub_items[9] : "" - , (depth) ? depth - 1 : 0, protection, (depth) ? "\"" : "" - ); + ob << StringFormat("%.*s%s", (depth ? (depth - 1) : 0), protection, (depth ? "\"" : "")); // For trailing quotes (and protection) if a subitem; - for (i = 0; i<10; i++) { - if (sub_items[i]) - safe_delete_array(sub_items[i]); - } - - safe_delete_array(instance); - return serialization; + if (!depth) + ob.write("\0", 1); } static inline int16 ServerToTitaniumSlot(uint32 serverSlot) @@ -2151,7 +2406,7 @@ namespace Titanium return serverSlot; // deprecated } - + static inline int16 ServerToTitaniumCorpseSlot(uint32 serverCorpseSlot) { //int16 TitaniumCorpse; @@ -2166,7 +2421,7 @@ namespace Titanium return titaniumSlot; // deprecated } - + static inline uint32 TitaniumToServerCorpseSlot(int16 titaniumCorpseSlot) { //uint32 ServerCorpse; @@ -2175,7 +2430,7 @@ namespace Titanium static inline void ServerToTitaniumTextLink(std::string& titaniumTextLink, const std::string& serverTextLink) { - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { + if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { titaniumTextLink = serverTextLink; return; } @@ -2184,7 +2439,7 @@ namespace Titanium for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { titaniumTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -2215,7 +2470,7 @@ namespace Titanium static inline void TitaniumToServerTextLink(std::string& serverTextLink, const std::string& titaniumTextLink) { - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (titaniumTextLink.find('\x12') == std::string::npos)) { + if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (titaniumTextLink.find('\x12') == std::string::npos)) { serverTextLink = titaniumTextLink; return; } @@ -2224,7 +2479,7 @@ namespace Titanium for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= constants::SayLinkBodySize) { serverTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -2250,5 +2505,76 @@ namespace Titanium } } } -} -// end namespace Titanium + + static inline CastingSlot ServerToTitaniumCastingSlot(EQEmu::CastingSlot slot) + { + switch (slot) { + case EQEmu::CastingSlot::Gem1: + return CastingSlot::Gem1; + case EQEmu::CastingSlot::Gem2: + return CastingSlot::Gem2; + case EQEmu::CastingSlot::Gem3: + return CastingSlot::Gem3; + case EQEmu::CastingSlot::Gem4: + return CastingSlot::Gem4; + case EQEmu::CastingSlot::Gem5: + return CastingSlot::Gem5; + case EQEmu::CastingSlot::Gem6: + return CastingSlot::Gem6; + case EQEmu::CastingSlot::Gem7: + return CastingSlot::Gem7; + case EQEmu::CastingSlot::Gem8: + return CastingSlot::Gem8; + case EQEmu::CastingSlot::Gem9: + return CastingSlot::Gem9; + case EQEmu::CastingSlot::Item: + return CastingSlot::Item; + case EQEmu::CastingSlot::PotionBelt: + return CastingSlot::PotionBelt; + case EQEmu::CastingSlot::Discipline: + return CastingSlot::Discipline; + case EQEmu::CastingSlot::AltAbility: + return CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return CastingSlot::Discipline; + } + } + + static inline EQEmu::CastingSlot TitaniumToServerCastingSlot(CastingSlot slot, uint32 itemlocation) + { + switch (slot) { + case CastingSlot::Gem1: + return EQEmu::CastingSlot::Gem1; + case CastingSlot::Gem2: + return EQEmu::CastingSlot::Gem2; + case CastingSlot::Gem3: + return EQEmu::CastingSlot::Gem3; + case CastingSlot::Gem4: + return EQEmu::CastingSlot::Gem4; + case CastingSlot::Gem5: + return EQEmu::CastingSlot::Gem5; + case CastingSlot::Gem6: + return EQEmu::CastingSlot::Gem6; + case CastingSlot::Gem7: + return EQEmu::CastingSlot::Gem7; + case CastingSlot::Gem8: + return EQEmu::CastingSlot::Gem8; + case CastingSlot::Gem9: + return EQEmu::CastingSlot::Gem9; + case CastingSlot::Ability: + return EQEmu::CastingSlot::Ability; + // Tit uses 10 for item and discipline casting, but items have a valid location + case CastingSlot::Item: + if (itemlocation == INVALID_INDEX) + return EQEmu::CastingSlot::Discipline; + else + return EQEmu::CastingSlot::Item; + case CastingSlot::PotionBelt: + return EQEmu::CastingSlot::PotionBelt; + case CastingSlot::AltAbility: + return EQEmu::CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return EQEmu::CastingSlot::Discipline; + } + } +} /*Titanium*/ diff --git a/common/patches/titanium.h b/common/patches/titanium.h index 4b5164330..ea68dd59a 100644 --- a/common/patches/titanium.h +++ b/common/patches/titanium.h @@ -1,11 +1,31 @@ -#ifndef TITANIUM_H_ -#define TITANIUM_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_TITANIUM_H +#define COMMON_TITANIUM_H #include "../struct_strategy.h" class EQStreamIdentifier; -namespace Titanium { +namespace Titanium +{ //these are the only public member of this namespace. extern void Register(EQStreamIdentifier &into); @@ -23,13 +43,30 @@ namespace Titanium { protected: virtual std::string Describe() const; - virtual const ClientVersion GetClientVersion() const; + virtual const EQEmu::versions::ClientVersion ClientVersion() const; //magic macro to declare our opcode processors #include "ss_declare.h" #include "titanium_ops.h" }; -}; + enum class CastingSlot : uint32 { + Gem1 = 0, + Gem2 = 1, + Gem3 = 2, + Gem4 = 3, + Gem5 = 4, + Gem6 = 5, + Gem7 = 6, + Gem8 = 7, + Gem9 = 8, + Ability = 9, + Item = 10, + Discipline = 10, + PotionBelt = 11, + AltAbility = 0xFF + }; -#endif /*TITANIUM_H_*/ +}; /*Titanium*/ + +#endif /*COMMON_TITANIUM_H*/ diff --git a/common/patches/titanium_constants.h b/common/patches/titanium_constants.h deleted file mode 100644 index d7e2a4964..000000000 --- a/common/patches/titanium_constants.h +++ /dev/null @@ -1,217 +0,0 @@ -/* -EQEMu: Everquest Server Emulator - -Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY except by those people which sell it, which -are required to give you total support for your newly bought product; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef TITANIUM_CONSTANTS_H_ -#define TITANIUM_CONSTANTS_H_ - -#include "../types.h" - -namespace Titanium { - namespace maps { - typedef enum : int16 { - // this needs work to match actual client equivilents - MapPossessions = 0, - MapBank, - MapSharedBank, - MapTrade, - MapWorld, - MapLimbo, - MapTribute, - MapTrophyTribute, - MapGuildTribute, - MapMerchant, - MapDeleted, - MapCorpse, - MapBazaar, - MapInspect, - MapRealEstate, - MapViewMODPC, - MapViewMODBank, - MapViewMODSharedBank, - MapViewMODLimbo, - MapAltStorage, - MapArchived, - MapMail, - MapGuildTrophyTribute, - MapOther, - _MapCount - } InventoryMaps; - } - - namespace slots { - typedef enum : int16 { - MainCharm = 0, - MainEar1, - MainHead, - MainFace, - MainEar2, - MainNeck, - MainShoulders, - MainArms, - MainBack, - MainWrist1, - MainWrist2, - MainRange, - MainHands, - MainPrimary, - MainSecondary, - MainFinger1, - MainFinger2, - MainChest, - MainLegs, - MainFeet, - MainWaist, - MainAmmo, - MainGeneral1, - MainGeneral2, - MainGeneral3, - MainGeneral4, - MainGeneral5, - MainGeneral6, - MainGeneral7, - MainGeneral8, - MainCursor, - _MainCount, - _MainEquipmentBegin = MainCharm, - _MainEquipmentEnd = MainAmmo, - _MainEquipmentCount = (_MainEquipmentEnd - _MainEquipmentBegin + 1), - _MainGeneralBegin = MainGeneral1, - _MainGeneralEnd = MainGeneral8, - _MainGeneralCount = (_MainGeneralEnd - _MainGeneralBegin + 1) - } EquipmentSlots; - } - - namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 8; // Hard-coded in client - DO NOT ALTER - - static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; - static const uint16 MAP_BANK_SIZE = 16; - static const uint16 MAP_SHARED_BANK_SIZE = 2; - static const uint16 MAP_TRADE_SIZE = 8; - static const uint16 MAP_WORLD_SIZE = 10; - static const uint16 MAP_LIMBO_SIZE = 36; - static const uint16 MAP_TRIBUTE_SIZE = 0; //? - static const uint16 MAP_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_GUILD_TRIBUTE_SIZE = 0; - static const uint16 MAP_MERCHANT_SIZE = 0; - static const uint16 MAP_DELETED_SIZE = 0; - static const uint16 MAP_CORPSE_SIZE = slots::_MainCount; - static const uint16 MAP_BAZAAR_SIZE = 80; - static const uint16 MAP_INSPECT_SIZE = slots::_MainEquipmentCount; - static const uint16 MAP_REAL_ESTATE_SIZE = 0; - static const uint16 MAP_VIEW_MOD_PC_SIZE = MAP_POSSESSIONS_SIZE; - static const uint16 MAP_VIEW_MOD_BANK_SIZE = MAP_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_SHARED_BANK_SIZE = MAP_SHARED_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_LIMBO_SIZE = MAP_LIMBO_SIZE; - static const uint16 MAP_ALT_STORAGE_SIZE = 0; - static const uint16 MAP_ARCHIVED_SIZE = 0; - static const uint16 MAP_MAIL_SIZE = 0; - static const uint16 MAP_GUILD_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_KRONO_SIZE = NOT_USED; - static const uint16 MAP_OTHER_SIZE = 0; - - static const int16 EQUIPMENT_BEGIN = slots::MainCharm; - static const int16 EQUIPMENT_END = slots::MainAmmo; - static const uint16 EQUIPMENT_SIZE = slots::_MainEquipmentCount; - - static const int16 GENERAL_BEGIN = slots::MainGeneral1; - static const int16 GENERAL_END = slots::MainGeneral8; - static const uint16 GENERAL_SIZE = slots::_MainGeneralCount; - static const int16 GENERAL_BAGS_BEGIN = 251; - static const int16 GENERAL_BAGS_END_OFFSET = 79; - static const int16 GENERAL_BAGS_END = GENERAL_BAGS_BEGIN + GENERAL_BAGS_END_OFFSET; - - static const int16 CURSOR = slots::MainCursor; - static const int16 CURSOR_BAG_BEGIN = 331; - static const int16 CURSOR_BAG_END_OFFSET = 9; - static const int16 CURSOR_BAG_END = CURSOR_BAG_BEGIN + CURSOR_BAG_END_OFFSET; - - static const int16 BANK_BEGIN = 2000; - static const int16 BANK_END = 2015; - static const int16 BANK_BAGS_BEGIN = 2031; - static const int16 BANK_BAGS_END_OFFSET = 159; - static const int16 BANK_BAGS_END = BANK_BAGS_BEGIN + BANK_BAGS_END_OFFSET; - - static const int16 SHARED_BANK_BEGIN = 2500; - static const int16 SHARED_BANK_END = 2501; - static const int16 SHARED_BANK_BAGS_BEGIN = 2531; - static const int16 SHARED_BANK_BAGS_END_OFFSET = 19; - static const int16 SHARED_BANK_BAGS_END = SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_END_OFFSET; - - static const int16 TRADE_BEGIN = 3000; - static const int16 TRADE_END = 3007; - static const int16 TRADE_NPC_END = 3003; - static const int16 TRADE_BAGS_BEGIN = 3031; - static const int16 TRADE_BAGS_END_OFFSET = 79; - static const int16 TRADE_BAGS_END = TRADE_BAGS_BEGIN + TRADE_BAGS_END_OFFSET; - - static const int16 WORLD_BEGIN = 4000; - static const int16 WORLD_END = 4009; - - static const int16 TRIBUTE_BEGIN = 400; - static const int16 TRIBUTE_END = 404; - - static const int16 CORPSE_BEGIN = slots::MainGeneral1; - static const int16 CORPSE_END = slots::MainGeneral1 + slots::MainCursor; - - static const uint16 ITEM_COMMON_SIZE = 5; - static const uint16 ITEM_CONTAINER_SIZE = 10; - - static const size_t BANDOLIERS_SIZE = 4; // number of bandolier instances - static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance - - static const size_t POTION_BELT_ITEM_COUNT = 4; - - static const size_t TEXT_LINK_BODY_LENGTH = 45; - } - - namespace limits { - static const bool ALLOWS_EMPTY_BAG_IN_BAG = false; - static const bool ALLOWS_CLICK_CAST_FROM_BAG = false; - static const bool COIN_HAS_WEIGHT = true; - } - -}; //end namespace Titanium - -#endif /*TITANIUM_CONSTANTS_H_*/ - -/* -Titanium Notes: - ** Integer-based inventory ** -ok Possessions: 0 - 30 (Corpse: 22 - 52 [Offset 22]) -ok [Equipment: 0 - 21] -ok [General: 22 - 29] -ok [Cursor: 30] -ok General Bags: 251 - 330 -ok Cursor Bags: 331 - 340 - -ok Bank: 2000 - 2015 -ok Bank Bags: 2031 - 2190 - -ok Shared Bank: 2500 - 2501 -ok Shared Bank Bags: 2531 - 2550 - - Trade: 3000 - 3007 - (Trade Bags: 3031 - 3110 -- server values) - - World: 4000 - 4009 - -*/ diff --git a/common/patches/titanium_limits.cpp b/common/patches/titanium_limits.cpp new file mode 100644 index 000000000..3976e8217 --- /dev/null +++ b/common/patches/titanium_limits.cpp @@ -0,0 +1,270 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "titanium_limits.h" + +#include "../string_util.h" + + +size_t Titanium::invtype::GetInvTypeSize(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + return invtype::InvTypePossessionsSize; + case invtype::InvTypeBank: + return invtype::InvTypeBankSize; + case invtype::InvTypeSharedBank: + return invtype::InvTypeSharedBankSize; + case invtype::InvTypeTrade: + return invtype::InvTypeTradeSize; + case invtype::InvTypeWorld: + return invtype::InvTypeWorldSize; + case invtype::InvTypeLimbo: + return invtype::InvTypeLimboSize; + case invtype::InvTypeTribute: + return invtype::InvTypeTributeSize; + case invtype::InvTypeGuildTribute: + return invtype::InvTypeGuildTributeSize; + case invtype::InvTypeMerchant: + return invtype::InvTypeMerchantSize; + case invtype::InvTypeCorpse: + return invtype::InvTypeCorpseSize; + case invtype::InvTypeBazaar: + return invtype::InvTypeBazaarSize; + case invtype::InvTypeInspect: + return invtype::InvTypeInspectSize; + case invtype::InvTypeViewMODPC: + return invtype::InvTypeViewMODPCSize; + case invtype::InvTypeViewMODBank: + return invtype::InvTypeViewMODBankSize; + case invtype::InvTypeViewMODSharedBank: + return invtype::InvTypeViewMODSharedBankSize; + case invtype::InvTypeViewMODLimbo: + return invtype::InvTypeViewMODLimboSize; + case invtype::InvTypeAltStorage: + return invtype::InvTypeAltStorageSize; + case invtype::InvTypeArchived: + return invtype::InvTypeArchivedSize; + case invtype::InvTypeOther: + return invtype::InvTypeOtherSize; + default: + return 0; + } +} + +const char* Titanium::invtype::GetInvTypeName(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypeInvalid: + return "Invalid Type"; + case invtype::InvTypePossessions: + return "Possessions"; + case invtype::InvTypeBank: + return "Bank"; + case invtype::InvTypeSharedBank: + return "Shared Bank"; + case invtype::InvTypeTrade: + return "Trade"; + case invtype::InvTypeWorld: + return "World"; + case invtype::InvTypeLimbo: + return "Limbo"; + case invtype::InvTypeTribute: + return "Tribute"; + case invtype::InvTypeGuildTribute: + return "Guild Tribute"; + case invtype::InvTypeMerchant: + return "Merchant"; + case invtype::InvTypeCorpse: + return "Corpse"; + case invtype::InvTypeBazaar: + return "Bazaar"; + case invtype::InvTypeInspect: + return "Inspect"; + case invtype::InvTypeViewMODPC: + return "View MOD PC"; + case invtype::InvTypeViewMODBank: + return "View MOD Bank"; + case invtype::InvTypeViewMODSharedBank: + return "View MOD Shared Bank"; + case invtype::InvTypeViewMODLimbo: + return "View MOD Limbo"; + case invtype::InvTypeAltStorage: + return "Alt Storage"; + case invtype::InvTypeArchived: + return "Archived"; + case invtype::InvTypeOther: + return "Other"; + default: + return "Unknown Type"; + } +} + +bool Titanium::invtype::IsInvTypePersistent(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + case invtype::InvTypeBank: + case invtype::InvTypeSharedBank: + case invtype::InvTypeTrade: + case invtype::InvTypeWorld: + case invtype::InvTypeLimbo: + case invtype::InvTypeTribute: + case invtype::InvTypeGuildTribute: + return true; + default: + return false; + } +} + +const char* Titanium::invslot::GetInvPossessionsSlotName(int inv_slot) +{ + switch (inv_slot) { + case invslot::InvSlotInvalid: + return "Invalid Slot"; + case invslot::PossessionsCharm: + return "Charm"; + case invslot::PossessionsEar1: + return "Ear 1"; + case invslot::PossessionsHead: + return "Head"; + case invslot::PossessionsFace: + return "Face"; + case invslot::PossessionsEar2: + return "Ear 2"; + case invslot::PossessionsNeck: + return "Neck"; + case invslot::PossessionsShoulders: + return "Shoulders"; + case invslot::PossessionsArms: + return "Arms"; + case invslot::PossessionsBack: + return "Back"; + case invslot::PossessionsWrist1: + return "Wrist 1"; + case invslot::PossessionsWrist2: + return "Wrist 2"; + case invslot::PossessionsRange: + return "Range"; + case invslot::PossessionsHands: + return "Hands"; + case invslot::PossessionsPrimary: + return "Primary"; + case invslot::PossessionsSecondary: + return "Secondary"; + case invslot::PossessionsFinger1: + return "Finger 1"; + case invslot::PossessionsFinger2: + return "Finger 2"; + case invslot::PossessionsChest: + return "Chest"; + case invslot::PossessionsLegs: + return "Legs"; + case invslot::PossessionsFeet: + return "Feet"; + case invslot::PossessionsWaist: + return "Waist"; + case invslot::PossessionsAmmo: + return "Ammo"; + case invslot::PossessionsGeneral1: + return "General 1"; + case invslot::PossessionsGeneral2: + return "General 2"; + case invslot::PossessionsGeneral3: + return "General 3"; + case invslot::PossessionsGeneral4: + return "General 4"; + case invslot::PossessionsGeneral5: + return "General 5"; + case invslot::PossessionsGeneral6: + return "General 6"; + case invslot::PossessionsGeneral7: + return "General 7"; + case invslot::PossessionsGeneral8: + return "General 8"; + case invslot::PossessionsCursor: + return "Cursor"; + default: + return "Unknown Slot"; + } +} + +const char* Titanium::invslot::GetInvCorpseSlotName(int inv_slot) +{ + if (!invtype::GetInvTypeSize(invtype::InvTypeCorpse) || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + // needs work + if ((size_t)(inv_slot + 1) < invslot::CorpseBegin || (size_t)(inv_slot + 1) >= invslot::CorpseEnd) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* Titanium::invslot::GetInvSlotName(int inv_type, int inv_slot) +{ + if (inv_type == invtype::InvTypePossessions) + return invslot::GetInvPossessionsSlotName(inv_slot); + else if (inv_type == invtype::InvTypeCorpse) + return invslot::GetInvCorpseSlotName(inv_slot); + + size_t type_size = invtype::GetInvTypeSize(inv_type); + + if (!type_size || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + if ((size_t)(inv_slot + 1) >= type_size) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* Titanium::invbag::GetInvBagIndexName(int bag_index) +{ + if (bag_index == invbag::InvBagInvalid) + return "Invalid Bag"; + + if ((size_t)bag_index >= invbag::ItemBagSize) + return "Unknown Bag"; + + static std::string ret_str; + ret_str = StringFormat("Bag %i", (bag_index + 1)); + + return ret_str.c_str(); +} + +const char* Titanium::invaug::GetInvAugIndexName(int aug_index) +{ + if (aug_index == invaug::InvAugInvalid) + return "Invalid Augment"; + + if ((size_t)aug_index >= invaug::ItemAugSize) + return "Unknown Augment"; + + static std::string ret_str; + ret_str = StringFormat("Augment %i", (aug_index + 1)); + + return ret_str.c_str(); +} diff --git a/common/patches/titanium_limits.h b/common/patches/titanium_limits.h new file mode 100644 index 000000000..e631f8492 --- /dev/null +++ b/common/patches/titanium_limits.h @@ -0,0 +1,311 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_TITANIUM_LIMITS_H +#define COMMON_TITANIUM_LIMITS_H + +#include "../types.h" +#include "../emu_versions.h" +#include "../skills.h" + + +namespace Titanium +{ + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + // pre-declarations + namespace inventory { + inline EQEmu::versions::ClientVersion GetInventoryRef() { return EQEmu::versions::ClientVersion::Titanium; } + + } /*inventory*/ + + namespace invtype { + inline EQEmu::versions::ClientVersion GetInvTypeRef() { return EQEmu::versions::ClientVersion::Titanium; } + + enum : int { InvTypeInvalid = -1, InvTypeBegin }; + + enum InventoryType : int { + InvTypePossessions = InvTypeBegin, + InvTypeBank, + InvTypeSharedBank, + InvTypeTrade, + InvTypeWorld, + InvTypeLimbo, + InvTypeTribute, + InvTypeGuildTribute, + InvTypeMerchant, + InvTypeCorpse, + InvTypeBazaar, + InvTypeInspect, + InvTypeViewMODPC, + InvTypeViewMODBank, + InvTypeViewMODSharedBank, + InvTypeViewMODLimbo, + InvTypeAltStorage, + InvTypeArchived, + InvTypeOther, + InvTypeCount + }; + + } /*invtype*/ + + namespace invslot { + inline EQEmu::versions::ClientVersion GetInvSlotRef() { return EQEmu::versions::ClientVersion::Titanium; } + + enum : int { InvSlotInvalid = -1, InvSlotBegin }; + + enum PossessionsSlot : int { + PossessionsCharm = InvSlotBegin, + PossessionsEar1, + PossessionsHead, + PossessionsFace, + PossessionsEar2, + PossessionsNeck, + PossessionsShoulders, + PossessionsArms, + PossessionsBack, + PossessionsWrist1, + PossessionsWrist2, + PossessionsRange, + PossessionsHands, + PossessionsPrimary, + PossessionsSecondary, + PossessionsFinger1, + PossessionsFinger2, + PossessionsChest, + PossessionsLegs, + PossessionsFeet, + PossessionsWaist, + PossessionsAmmo, + PossessionsGeneral1, + PossessionsGeneral2, + PossessionsGeneral3, + PossessionsGeneral4, + PossessionsGeneral5, + PossessionsGeneral6, + PossessionsGeneral7, + PossessionsGeneral8, + PossessionsCursor, + PossessionsCount + }; + + const int EquipmentBegin = PossessionsCharm; + const int EquipmentEnd = PossessionsAmmo; + const int EquipmentCount = (EquipmentEnd - EquipmentBegin + 1); + + const int GeneralBegin = PossessionsGeneral1; + const int GeneralEnd = PossessionsGeneral8; + const int GeneralCount = (GeneralEnd - GeneralBegin + 1); + + } /*invslot*/ + + namespace invbag { + inline EQEmu::versions::ClientVersion GetInvBagRef() { return EQEmu::versions::ClientVersion::Titanium; } + + enum : int { InvBagInvalid = -1, InvBagBegin }; + + } /*invbag*/ + + namespace invaug { + inline EQEmu::versions::ClientVersion GetInvAugRef() { return EQEmu::versions::ClientVersion::Titanium; } + + enum : int { InvAugInvalid = -1, InvAugBegin }; + + } /*invaug*/ + + namespace item { + inline EQEmu::versions::ClientVersion GetItemRef() { return EQEmu::versions::ClientVersion::Titanium; } + + enum ItemPacketType : int { + ItemPacketMerchant = 100, + ItemPacketTradeView = 101, + ItemPacketLoot = 102, + ItemPacketTrade = 103, + ItemPacketCharInventory = 105, + ItemPacketLimbo = 106, + ItemPacketWorldContainer = 107, + ItemPacketTributeItem = 108, + ItemPacketGuildTribute = 109, + ItemPacketCharmUpdate = 110 + }; + + } /*item*/ + + namespace profile { + inline EQEmu::versions::ClientVersion GetProfileRef() { return EQEmu::versions::ClientVersion::Titanium; } + + } /*profile*/ + + namespace constants { + inline EQEmu::versions::ClientVersion GetConstantsRef() { return EQEmu::versions::ClientVersion::Titanium; } + + } /*constants*/ + + namespace behavior { + inline EQEmu::versions::ClientVersion GetBehaviorRef() { return EQEmu::versions::ClientVersion::Titanium; } + + } /*behavior*/ + + namespace skills { + inline EQEmu::versions::ClientVersion GetSkillsRef() { return EQEmu::versions::ClientVersion::Titanium; } + + } /*skills*/ + + + // declarations + namespace inventory { + const bool ConcatenateInvTypeLimbo = true; + + const bool AllowOverLevelEquipment = false; + + const bool AllowEmptyBagInBag = false; + const bool AllowClickCastFromBag = false; + + } /*inventory*/ + + namespace invtype { + const size_t InvTypePossessionsSize = invslot::PossessionsCount; + const size_t InvTypeBankSize = 16; + const size_t InvTypeSharedBankSize = 2; + const size_t InvTypeTradeSize = 8; + const size_t InvTypeWorldSize = 10; + const size_t InvTypeLimboSize = 36; + const size_t InvTypeTributeSize = 5; + const size_t InvTypeGuildTributeSize = 2; + const size_t InvTypeMerchantSize = 80; + const size_t InvTypeCorpseSize = InvTypePossessionsSize; + const size_t InvTypeBazaarSize = 80; + const size_t InvTypeInspectSize = invslot::EquipmentCount; + const size_t InvTypeViewMODPCSize = InvTypePossessionsSize; + const size_t InvTypeViewMODBankSize = InvTypeBankSize; + const size_t InvTypeViewMODSharedBankSize = InvTypeSharedBankSize; + const size_t InvTypeViewMODLimboSize = InvTypeLimboSize; + const size_t InvTypeAltStorageSize = 0;//unknown - "Shroud Bank" + const size_t InvTypeArchivedSize = 0;//unknown + const size_t InvTypeOtherSize = 0;//unknown + + extern size_t GetInvTypeSize(int inv_type); + extern const char* GetInvTypeName(int inv_type); + + extern bool IsInvTypePersistent(int inv_type); + + } /*invtype*/ + + namespace invslot { + const int BankBegin = 2000; + const int BankEnd = (BankBegin + invtype::InvTypeBankSize) - 1; + + const int SharedBankBegin = 2500; + const int SharedBankEnd = (SharedBankBegin + invtype::InvTypeSharedBankSize) - 1; + + const int TradeBegin = 3000; + const int TradeEnd = (TradeBegin + invtype::InvTypeTradeSize) - 1; + const int TradeNPCEnd = 3003; + + const int WorldBegin = 4000; + const int WorldEnd = (WorldBegin + invtype::InvTypeWorldSize) - 1; + + const int TributeBegin = 400; + const int TributeEnd = (TributeBegin + invtype::InvTypeTributeSize) - 1; + + const int GuildTributeBegin = 450; + const int GuildTributeEnd = (GuildTributeBegin + invtype::InvTypeGuildTributeSize) - 1; + + const int CorpseBegin = PossessionsGeneral1; + const int CorpseEnd = PossessionsGeneral1 + PossessionsCursor; + + extern const char* GetInvPossessionsSlotName(int inv_slot); + extern const char* GetInvCorpseSlotName(int inv_slot); + extern const char* GetInvSlotName(int inv_type, int inv_slot); + + } /*invslot*/ + + namespace invbag { + const size_t ItemBagSize = 10; + + const int GeneralBagsBegin = 251; + const int GeneralBagsSize = invslot::GeneralCount * ItemBagSize; + const int GeneralBagsEnd = (GeneralBagsBegin + GeneralBagsSize) - 1; + + const int CursorBagBegin = 331; + const int CursorBagSize = ItemBagSize; + const int CursorBagEnd = (CursorBagBegin + CursorBagSize) - 1; + + const int BankBagsBegin = 2031; + const int BankBagsSize = (invtype::InvTypeBankSize * ItemBagSize); + const int BankBagsEnd = (BankBagsBegin + BankBagsSize) - 1; + + const int SharedBankBagsBegin = 2531; + const int SharedBankBagsSize = invtype::InvTypeSharedBankSize * ItemBagSize; + const int SharedBankBagsEnd = (SharedBankBagsBegin + SharedBankBagsSize) - 1; + + const int TradeBagsBegin = 3031; + const int TradeBagsSize = invtype::InvTypeTradeSize * ItemBagSize; + const int TradeBagsEnd = (TradeBagsBegin + TradeBagsSize) - 1; + + extern const char* GetInvBagIndexName(int bag_index); + + } /*invbag*/ + + namespace invaug { + const size_t ItemAugSize = 5; + + extern const char* GetInvAugIndexName(int aug_index); + + } /*invaug*/ + + namespace item { + + } /*item*/ + + namespace profile { + const size_t TributeSize = invtype::InvTypeTributeSize; + const size_t GuildTributeSize = invtype::InvTypeGuildTributeSize; + + const size_t BandoliersSize = 4; // number of bandolier instances + const size_t BandolierItemCount = 4; // number of equipment slots in bandolier instance + + const size_t PotionBeltSize = 4; + + const size_t SkillArraySize = 100; + + } /*profile*/ + + namespace constants { + const size_t CharacterCreationLimit = 8; // Hard-coded in client - DO NOT ALTER + + const size_t SayLinkBodySize = 45; + + } /*constants*/ + + namespace behavior { + const bool CoinHasWeight = true; + + } /*behavior*/ + + namespace skills { + const size_t LastUsableSkill = EQEmu::skills::SkillFrenzy; + + } /*skills*/ + +}; /*Titanium*/ + +#endif /*COMMON_TITANIUM_LIMITS_H*/ diff --git a/common/patches/titanium_ops.h b/common/patches/titanium_ops.h index 3d8dfbf79..9ca0ba770 100644 --- a/common/patches/titanium_ops.h +++ b/common/patches/titanium_ops.h @@ -1,11 +1,33 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + // out-going packets that require an ENCODE translation: E(OP_Action) E(OP_AdventureMerchantSell) E(OP_ApplyPoison) E(OP_BazaarSearch) E(OP_BecomeTrader) +E(OP_Buff) E(OP_ChannelMessage) E(OP_CharInventory) +E(OP_Damage) E(OP_DeleteCharge) E(OP_DeleteItem) E(OP_DeleteSpawn) @@ -28,6 +50,7 @@ E(OP_ItemPacket) E(OP_LeadershipExpUpdate) E(OP_LFGuild) E(OP_LootItem) +E(OP_MemorizeSpell) E(OP_MoveItem) E(OP_OnLevelMessage) E(OP_PetBuffWindow) @@ -53,6 +76,7 @@ E(OP_ZoneSpawns) D(OP_AdventureMerchantSell) D(OP_ApplyPoison) D(OP_AugmentItem) +D(OP_Buff) D(OP_CastSpell) D(OP_ChannelMessage) D(OP_CharacterCreate) diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index 1c3afd90b..8d258871f 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -1,7 +1,28 @@ -#ifndef TITANIUM_STRUCTS_H_ -#define TITANIUM_STRUCTS_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) -namespace Titanium { + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_TITANIUM_STRUCTS_H +#define COMMON_TITANIUM_STRUCTS_H + + +namespace Titanium +{ namespace structs { @@ -97,7 +118,7 @@ struct AdventureInfo { ** Merth: Gave struct a name so gcc 2.96 would compile ** */ -struct Color_Struct +struct Tint_Struct { union { struct { @@ -105,11 +126,53 @@ struct Color_Struct uint8 Green; uint8 Red; uint8 UseTint; // if there's a tint this is FF - } RGB; + }; uint32 Color; }; }; +struct TintProfile { + union { + struct { + Tint_Struct Head; + Tint_Struct Chest; + Tint_Struct Arms; + Tint_Struct Wrist; + Tint_Struct Hands; + Tint_Struct Legs; + Tint_Struct Feet; + Tint_Struct Primary; + Tint_Struct Secondary; + }; + Tint_Struct Slot[EQEmu::textures::TextureCount]; + }; +}; + +struct Texture_Struct +{ + uint32 Material; +}; + +struct TextureProfile +{ + union { + struct { + Texture_Struct Head; + Texture_Struct Chest; + Texture_Struct Arms; + Texture_Struct Wrist; + Texture_Struct Hands; + Texture_Struct Legs; + Texture_Struct Feet; + Texture_Struct Primary; + Texture_Struct Secondary; + }; + Texture_Struct Slot[EQEmu::textures::TextureCount]; + }; + + TextureProfile(); +}; + /* ** Character Selection Struct ** Length: 1704 Bytes @@ -118,10 +181,10 @@ struct Color_Struct struct CharacterSelect_Struct { /*0000*/ uint32 Race[10]; // Characters Race -/*0040*/ Color_Struct CS_Colors[10][9]; // Characters Equipment Colors +/*0040*/ TintProfile CS_Colors[10]; // Characters Equipment Colors - packet requires length for 10 characters..but, client is limited to 8 /*0400*/ uint8 BeardColor[10]; // Characters beard Color /*0410*/ uint8 HairStyle[10]; // Characters hair style -/*0420*/ uint32 Equip[10][9]; // 0=helm, 1=chest, 2=arm, 3=bracer, 4=hand, 5=leg, 6=boot, 7=melee1, 8=melee2 (Might not be) +/*0420*/ TextureProfile Equip[10]; // Characters texture array /*0780*/ uint32 SecondaryIDFile[10]; // Characters secondary IDFile number /*0820*/ uint8 Unknown820[10]; // 10x ff /*0830*/ uint8 Unknown830[2]; // 2x 00 @@ -212,28 +275,13 @@ struct Spawn_Struct { /*0146*/ uint8 beardcolor; // Beard color /*0147*/ uint8 unknown0147[4]; /*0151*/ uint8 level; // Spawn Level -/*0152*/ uint8 unknown0259[4]; // ***Placeholder +/*0152*/ uint32 PlayerState; // PlayerState controls some animation stuff /*0156*/ uint8 beard; // Beard style /*0157*/ char suffix[32]; // Player's suffix (of Veeshan, etc.) /*0189*/ uint32 petOwnerId; // If this is a pet, the spawn id of owner /*0193*/ uint8 guildrank; // 0=normal, 1=officer, 2=leader /*0194*/ uint8 unknown0194[3]; -/*0197*/ union - { - struct - { - /*0197*/ uint32 equip_helmet; // Equipment: Helmet Visual - /*0201*/ uint32 equip_chest; // Equipment: Chest Visual - /*0205*/ uint32 equip_arms; // Equipment: Arms Visual - /*0209*/ uint32 equip_bracers; // Equipment: Bracers Visual - /*0213*/ uint32 equip_hands; // Equipment: Hands Visual - /*0217*/ uint32 equip_legs; // Equipment: Legs Visual - /*0221*/ uint32 equip_feet; // Equipment: Feet Visual - /*0225*/ uint32 equip_primary; // Equipment: Primary Visual - /*0229*/ uint32 equip_secondary; // Equipment: Secondary Visual - } equip; - /*0197*/ uint32 equipment[9]; // Array elements correspond to struct equipment above - }; +/*0197*/ TextureProfile equipment; /*0233*/ float runspeed; // Speed when running /*0036*/ uint8 afk; // 0=no, 1=afk /*0238*/ uint32 guildID; // Current guild @@ -263,22 +311,7 @@ union }; /*0340*/ uint32 spawnId; // Spawn Id /*0344*/ uint8 unknown0344[4]; -/*0348*/ union - { - struct - { - /*0348*/ Color_Struct color_helmet; // Color of helmet item - /*0352*/ Color_Struct color_chest; // Color of chest item - /*0356*/ Color_Struct color_arms; // Color of arms item - /*0360*/ Color_Struct color_bracers; // Color of bracers item - /*0364*/ Color_Struct color_hands; // Color of hands item - /*0368*/ Color_Struct color_legs; // Color of legs item - /*0372*/ Color_Struct color_feet; // Color of feet item - /*0376*/ Color_Struct color_primary; // Color of primary item - /*0380*/ Color_Struct color_secondary; // Color of secondary item - } equipment_colors; - /*0348*/ Color_Struct colors[9]; // Array elements correspond to struct equipment_colors above - }; +/*0348*/ TintProfile equipment_tint; /*0384*/ uint8 lfg; // 0=off, 1=lfg on /*0385*/ @@ -357,7 +390,7 @@ struct MemorizeSpell_Struct { uint32 slot; // Spot in the spell book/memorized slot uint32 spell_id; // Spell id (200 or c8 is minor healing, etc) uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming -uint32 unknown12; +uint32 reduction; // lowers reuse }; /* @@ -387,13 +420,13 @@ struct DeleteSpell_Struct /*005*/uint8 unknowndss006[3]; /*008*/ }; - struct ManaChange_Struct { - uint32 new_mana; // New Mana AMount - uint32 stamina; - uint32 spell_id; - uint32 unknown12; +/*00*/ uint32 new_mana; // New Mana AMount +/*04*/ uint32 stamina; +/*08*/ uint32 spell_id; +/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting? +/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like }; struct SwapSpell_Struct @@ -440,26 +473,19 @@ struct SpawnAppearance_Struct // this is used inside profile struct SpellBuff_Struct { -/*000*/ uint8 slotid; //badly named... seems to be 2 for a real buff, 0 otherwise +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff /*001*/ uint8 level; /*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; //not real +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? /*004*/ uint32 spellid; -/*008*/ uint32 duration; -/*012*/ uint32 counters; -/*016*/ uint32 player_id; //'global' ID of the caster, for wearoff messages +/*008*/ int32 duration; +/*012*/ uint32 counters; // single book keeping value (counters, rune/vie) +/*016*/ uint32 player_id; // caster ID, pretty sure just zone ID }; -struct SpellBuffFade_Struct { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ uint32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 unknown020; //prolly global player ID +/*004*/ SpellBuff_Struct buff; /*024*/ uint32 slotid; /*028*/ uint32 bufffade; /*032*/ @@ -612,7 +638,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; + BandolierItem_Struct Items[profile::BandolierItemCount]; }; //len = 72 @@ -626,7 +652,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; + PotionBeltItem_Struct Items[profile::PotionBeltSize]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -789,9 +815,9 @@ struct PlayerProfile_Struct /*00176*/ uint8 hairstyle; // Player hair style /*00177*/ uint8 beard; // Player beard type /*00178*/ uint8 unknown00178[10]; -/*00188*/ uint32 item_material[9]; // Item texture/material of worn items +/*00188*/ TextureProfile item_material; // Item texture/material of worn items /*00224*/ uint8 unknown00224[44]; -/*00268*/ Color_Struct item_tint[9]; // RR GG BB 00 +/*00268*/ TintProfile item_tint; // RR GG BB 00 /*00304*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; // AAs /*02224*/ uint32 points; // Unspent Practice points /*02228*/ uint32 mana; // Current mana @@ -830,7 +856,7 @@ struct PlayerProfile_Struct /*06152*/ uint32 aapoints_spent; // Number of spent AA points /*06156*/ uint32 aapoints; // Unspent AA points /*06160*/ uint8 unknown06160[4]; -/*06164*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // bandolier contents +/*06164*/ Bandolier_Struct bandoliers[profile::BandoliersSize]; // bandolier contents /*07444*/ uint8 unknown07444[5120]; /*12564*/ PotionBelt_Struct potionbelt; // potion belt /*12852*/ uint8 unknown12852[8]; @@ -950,7 +976,7 @@ struct TargetReject_Struct { struct PetCommand_Struct { /*000*/ uint32 command; -/*004*/ uint32 unknown; +/*004*/ uint32 target; }; /* @@ -1014,7 +1040,7 @@ struct SpecialMesg_Struct struct WearChange_Struct{ /*000*/ uint16 spawn_id; /*002*/ uint16 material; -/*004*/ Color_Struct color; +/*004*/ Tint_Struct color; /*009*/ uint8 wear_slot_id; }; @@ -1062,8 +1088,8 @@ struct RequestClientZoneChange_Struct { struct Animation_Struct { /*00*/ uint16 spawnid; -/*02*/ uint8 action; -/*03*/ uint8 value; +/*02*/ uint8 speed; +/*03*/ uint8 action; /*04*/ }; @@ -1101,9 +1127,9 @@ struct CombatDamage_Struct /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 05 */ uint16 spellid; /* 07 */ uint32 damage; -/* 11 */ uint32 unknown11; -/* 15 */ uint32 sequence; // see above notes in Action_Struct -/* 19 */ uint32 unknown19; +/* 11 */ float force; +/* 15 */ float meleepush_xy; // see above notes in Action_Struct +/* 19 */ float meleepush_z; /* 23 */ }; @@ -2570,27 +2596,6 @@ struct PetitionBug_Struct{ char text[1028]; }; -struct DyeStruct -{ - union - { - struct - { - struct Color_Struct head; - struct Color_Struct chest; - struct Color_Struct arms; - struct Color_Struct wrists; - struct Color_Struct hands; - struct Color_Struct legs; - struct Color_Struct feet; - struct Color_Struct primary; // you can't actually dye this - struct Color_Struct secondary; // or this - } - dyes; - struct Color_Struct dye[9]; - }; -}; - struct ApproveZone_Struct { char name[64]; uint32 zoneid; @@ -3157,8 +3162,7 @@ struct SendAA_Struct { /*0052*/ uint32 spellid; /*0056*/ uint32 spell_type; /*0060*/ uint32 spell_refresh; -/*0064*/ uint16 classes; -/*0066*/ uint16 berserker; //seems to be 1 if its a berserker ability +/*0064*/ uint32 classes; /*0068*/ uint32 max_level; /*0072*/ uint32 last_id; /*0076*/ uint32 next_id; @@ -3175,15 +3179,10 @@ struct AA_List { struct AA_Action { /*00*/ uint32 action; /*04*/ uint32 ability; -/*08*/ uint32 unknown08; +/*08*/ uint32 target_id; /*12*/ uint32 exp_value; }; -struct AA_Skills { //this should be removed and changed to AA_Array -/*00*/ uint32 aa_skill; -/*04*/ uint32 aa_value; -}; - struct AAExpUpdate_Struct { /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability /*04*/ uint32 aapoints_unspent; @@ -3201,11 +3200,11 @@ struct AltAdvStats_Struct { }; struct PlayerAA_Struct { - AA_Skills aa_list[MAX_PP_AA_ARRAY]; + AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct AATable_Struct { - AA_Skills aa_list[MAX_PP_AA_ARRAY]; + AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct Weather_Struct { @@ -3347,7 +3346,179 @@ struct LFGuild_GuildToggle_Struct /*616*/ }; - }; //end namespace structs -}; //end namespace Titanium +//struct ItemEffect_Struct +//{ +// int16 Effect; +// uint8 Type; +// uint8 Level; +// uint8 Level2; +//}; +// +//struct Item_Struct +//{ +// // "titanium_itemfields_a.h" +// char Name; // "\0" +// char Lore; // "\0" +// char IDFile; // "\0" +// int ID; +// +// int Weight; +// +// // "titanium_itemfields_b.h" +// int NoRent; +// int NoDrop; +// int Size; +// int Slots; +// int Price; +// int Icon; +// char Unk1; // '0' +// char Unk2; // '0' +// int BenefitFlag; +// int Tradeskills; +// int CR; +// int DR; +// int PR; +// int MR; +// int FR; +// int AStr; +// int ASta; +// int AAgi; +// int ADex; +// int ACha; +// int AInt; +// int AWis; +// int HP; +// int Mana; +// int AC; +// int Deity; +// int SkillModValue; +// int SkillModMax; +// int SkillModType; +// int BaneDmgRace; +// int BaneDmgAmt; +// int BaneDmgBody; +// int Magic; +// int CastTime_; +// int ReqLevel; +// int BardType; +// int BardValue; +// int Light; +// int Delay; +// int RecLevel; +// int RecSkill; +// int ElemDmgType; +// int ElemDmgAmt; +// int Range; +// int Damage; +// int Color; +// int Classes; +// int Races; +// char Unk3; // '0' +// int MaxCharges; +// int ItemType; +// int Material; +// int SellRate; +// char Unk4; // '0' +// int _CastTime_; +// char Unk5; // '0' +// int ProcRate; +// int CombatEffects; +// int Shielding; +// int StunResist; +// int StrikeThrough; +// int ExtraDmgSkill; +// int ExtraDmgAmt; +// int SpellShield; +// int Avoidance; +// int Accuracy; +// int CharmFileID; +// int FactionMod1; +// int FactionMod2; +// int FactionMod3; +// int FactionMod4; +// int FactionAmt1; +// int FactionAmt2; +// int FactionAmt3; +// int FactionAmt4; +// char CharmFile; // "\0" +// int AugType; +// +// struct { +// int AugSlotType; +// int AugSlotVisible; +// } AugSlot[5]; +// +// int LDoNTheme; +// int LDoNPrice; +// int LDoNSold; +// int BagType; +// int BagSlots; +// int BagSize; +// int BagWR; +// int Book; +// int BookType; +// char Filename; // "\0" +// int BaneDmgRaceAmt; +// int AugRestrict; +// int LoreGroup; +// int PendingLoreFlag; +// int ArtifactFlag; +// int SummonedFlag; +// int Favor; +// int FVNoDrop; +// int Endur; +// int DotShielding; +// int Attack; +// int Regen; +// int ManaRegen; +// int EnduranceRegen; +// int Haste; +// int DamageShield; +// int RecastDelay; +// int RecastType; +// int GuildFavor; +// int AugDistiller; +// char Unk6; // '0' +// char Unk7; // '0' +// int Attunable; +// int NoPet; +// char Unk8; // '0' +// int PointType; +// int PotionBelt; +// int PotionBeltSlots; +// int StackSize; +// int NoTransfer; +// int Stackable; +// +// int ClickEffect; +// int ClickType; +// int ClickLevel2; +// int ClickLevel; +// char ClickName; // '0' +// int ProcEffect; +// int ProcType; +// int ProcLevel2; +// int ProcLevel; +// char ProcName; // '0' +// int WornEffect; +// int WornType; +// int WornLevel2; +// int WornLevel; +// char WornName; // '0' +// int FocusEffect; +// int FocusType; +// int FocusLevel2; +// int FocusLevel; +// char FocusName; // '0' +// int ScrollEffect; +// int ScrollType; +// int ScrollLevel2; +// int ScrollLevel; +// char ScrollName; // '0' +//}; -#endif /*TITANIUM_STRUCTS_H_*/ + }; /*structs*/ + +}; /*Titanium*/ + +#endif /*COMMON_TITANIUM_STRUCTS_H*/ diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index aafef5896..6a1a03a09 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -1,4 +1,24 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #include "../global_define.h" +#include "../eqemu_config.h" #include "../eqemu_logsys.h" #include "uf.h" #include "../opcodemgr.h" @@ -16,13 +36,14 @@ #include #include + namespace UF { static const char *name = "UF"; static OpcodeManager *opcodes = nullptr; static Strategy struct_strategy; - char* SerializeItem(const ItemInst *inst, int16 slot_id, uint32 *length, uint8 depth); + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id, uint8 depth); // server to client inventory location converters static inline uint32 ServerToUFSlot(uint32 serverSlot); @@ -38,12 +59,17 @@ namespace UF // client to server text link converter static inline void UFToServerTextLink(std::string& serverTextLink, const std::string& ufTextLink); + static inline CastingSlot ServerToUFCastingSlot(EQEmu::CastingSlot slot); + static inline EQEmu::CastingSlot UFToServerCastingSlot(CastingSlot slot); + void Register(EQStreamIdentifier &into) { //create our opcode manager if we havent already if (opcodes == nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; //load up the opcode manager. @@ -87,7 +113,9 @@ namespace UF if (opcodes != nullptr) { //TODO: get this file name from the config file - std::string opfile = "patch_"; + auto Config = EQEmuConfig::get(); + std::string opfile = Config->PatchDir; + opfile += "patch_"; opfile += name; opfile += ".conf"; if (!opcodes->ReloadOpcodes(opfile.c_str())) { @@ -113,9 +141,9 @@ namespace UF return(r); } - const ClientVersion Strategy::GetClientVersion() const + const EQEmu::versions::ClientVersion Strategy::ClientVersion() const { - return ClientVersion::UF; + return EQEmu::versions::ClientVersion::UF; } #include "ss_define.h" @@ -182,8 +210,9 @@ namespace UF if (opcode == 8) { AltCurrencyPopulate_Struct *populate = (AltCurrencyPopulate_Struct*)emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(structs::AltCurrencyPopulate_Struct) - + sizeof(structs::AltCurrencyPopulateEntry_Struct) * populate->count); + auto outapp = new EQApplicationPacket( + OP_AltCurrency, sizeof(structs::AltCurrencyPopulate_Struct) + + sizeof(structs::AltCurrencyPopulateEntry_Struct) * populate->count); structs::AltCurrencyPopulate_Struct *out_populate = (structs::AltCurrencyPopulate_Struct*)outapp->pBuffer; out_populate->opcode = populate->opcode; @@ -200,7 +229,7 @@ namespace UF dest->FastQueuePacket(&outapp, ack_req); } else { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyUpdate_Struct)); memcpy(outapp->pBuffer, emu_buffer, sizeof(AltCurrencyUpdate_Struct)); dest->FastQueuePacket(&outapp, ack_req); } @@ -337,20 +366,29 @@ namespace UF ENCODE(OP_Buff) { - ENCODE_LENGTH_EXACT(SpellBuffFade_Struct); - SETUP_DIRECT_ENCODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Underfoot); + ENCODE_LENGTH_EXACT(SpellBuffPacket_Struct); + SETUP_DIRECT_ENCODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); OUT(entityid); - OUT(slot); - OUT(level); - OUT(effect); - //eq->unknown7 = 10; - OUT(spellid); - OUT(duration); - OUT(slotid); + OUT(buff.effect_type); + OUT(buff.level); + // just so we're 100% sure we get a 1.0f ... + eq->buff.bard_modifier = emu->buff.bard_modifier == 10 ? 1.0f : emu->buff.bard_modifier / 10.0f; + OUT(buff.spellid); + OUT(buff.duration); + OUT(buff.num_hits); + uint16 buffslot = emu->slotid; + if (buffslot >= 25 && buffslot < 37) + { + buffslot += 5; + } + else if (buffslot >= 37) + { + buffslot += 14; + } + // TODO: implement slot_data stuff + eq->slotid = buffslot; OUT(bufffade); // Live (October 2011) sends a 2 rather than 0 when a buff is created, but it doesn't seem to matter. - OUT(num_hits); - eq->unknown008 = 1.0f; FINISH_ENCODE(); } @@ -365,7 +403,7 @@ namespace UF memset(__packet->pBuffer, 0, sz); __packet->WriteUInt32(emu->entity_id); - __packet->WriteUInt32(0); + __packet->WriteUInt32(emu->tic_timer); __packet->WriteUInt8(emu->all_buffs); // 1 = all buffs, 0 = 1 buff __packet->WriteUInt16(emu->count); @@ -387,7 +425,7 @@ namespace UF __packet->WriteUInt32(emu->entries[i].num_hits); __packet->WriteString(""); } - __packet->WriteUInt8(!emu->all_buffs); + __packet->WriteUInt8(emu->type); FINISH_ENCODE(); /* @@ -473,68 +511,50 @@ namespace UF ENCODE(OP_CharInventory) { //consume the packet - EQApplicationPacket *in = *p; - + EQApplicationPacket* in = *p; *p = nullptr; - if (in->size == 0) { - + if (!in->size) { in->size = 4; in->pBuffer = new uchar[in->size]; - *((uint32 *)in->pBuffer) = 0; + memset(in->pBuffer, 0, in->size); dest->FastQueuePacket(&in, ack_req); return; } //store away the emu struct - unsigned char *__emu_buffer = in->pBuffer; - - int ItemCount = in->size / sizeof(InternalSerializedItem_Struct); - - if (ItemCount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) { + uchar* __emu_buffer = in->pBuffer; + int item_count = in->size / sizeof(EQEmu::InternalSerializedItem_Struct); + if (!item_count || (in->size % sizeof(EQEmu::InternalSerializedItem_Struct)) != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", - opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct)); + opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(EQEmu::InternalSerializedItem_Struct)); delete in; return; } - InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer; + EQEmu::InternalSerializedItem_Struct* eq = (EQEmu::InternalSerializedItem_Struct*)in->pBuffer; - in->pBuffer = new uchar[4]; - *(uint32 *)in->pBuffer = ItemCount; - in->size = 4; + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); - for (int r = 0; r < ItemCount; r++, eq++) { + ob.write((const char*)&item_count, sizeof(uint32)); - uint32 Length = 0; - char* Serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &Length, 0); + for (int index = 0; index < item_count; ++index, ++eq) { + SerializeItem(ob, (const ItemInst*)eq->inst, eq->slot_id, 0); + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - if (Serialized) { - - uchar *OldBuffer = in->pBuffer; - in->pBuffer = new uchar[in->size + Length]; - memcpy(in->pBuffer, OldBuffer, in->size); - - safe_delete_array(OldBuffer); - - memcpy(in->pBuffer + in->size, Serialized, Length); - in->size += Length; - - safe_delete_array(Serialized); - } - else { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id); - } + last_pos = ob.tellp(); } + in->size = ob.size(); + in->pBuffer = ob.detach(); + delete[] __emu_buffer; - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Sending inventory to client"); - //Log.Hex(Logs::Netcode, in->pBuffer, in->size); - dest->FastQueuePacket(&in, ack_req); } @@ -581,7 +601,10 @@ namespace UF OUT(type); OUT(spellid); OUT(damage); - eq->sequence = emu->sequence; + OUT(force); + OUT(meleepush_xy); + OUT(meleepush_z); + OUT(special); FINISH_ENCODE(); } @@ -854,9 +877,9 @@ namespace UF // This next field is actually a float. There is a groundspawn in freeportwest (sack of money sitting on some barrels) which requires this // field to be set to (float)255.0 to appear at all, and also the size field below to be 5, to be the correct size. I think SoD has the same // issue. - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown, observed 0 - VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // This appears to be the size field. + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); //X tilt + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, 0); //Y tilt + VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f ); // This appears to be the size field. Hackish logic because some PEQ DB items were corrupt. VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->y); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->x); VARSTRUCT_ENCODE_TYPE(float, OutBuffer, emu->z); @@ -927,7 +950,8 @@ namespace UF { //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupDisbandYou, sizeof(structs::GroupGeneric_Struct)); structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); @@ -946,7 +970,8 @@ namespace UF //if(gjs->action == groupActLeave) // Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Group Leave, yourname = %s, membername = %s", gjs->yourname, gjs->membername); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupDisbandOther, sizeof(structs::GroupGeneric_Struct)); structs::GroupGeneric_Struct *ggs = (structs::GroupGeneric_Struct*)outapp->pBuffer; memcpy(ggs->name1, gjs->yourname, sizeof(ggs->name1)); @@ -983,7 +1008,7 @@ namespace UF //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Leadername is %s", gu2->leadersname); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupUpdateB, PacketLength); + auto outapp = new EQApplicationPacket(OP_GroupUpdateB, PacketLength); char *Buffer = (char *)outapp->pBuffer; @@ -1047,7 +1072,8 @@ namespace UF memcpy(eq->membername, emu->membername, sizeof(eq->membername)); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupLeadershipAAUpdate, sizeof(GroupLeadershipAAUpdate_Struct)); GroupLeadershipAAUpdate_Struct *GLAAus = (GroupLeadershipAAUpdate_Struct*)outapp->pBuffer; GLAAus->NPCMarkerID = emu->NPCMarkerID; @@ -1256,29 +1282,31 @@ namespace UF ENCODE(OP_ItemPacket) { //consume the packet - EQApplicationPacket *in = *p; + EQApplicationPacket* in = *p; *p = nullptr; - unsigned char *__emu_buffer = in->pBuffer; - ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); + //store away the emu struct + uchar* __emu_buffer = in->pBuffer; - uint32 length; - char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0); + EQEmu::InternalSerializedItem_Struct* int_struct = (EQEmu::InternalSerializedItem_Struct*)(&__emu_buffer[4]); - if (!serialized) { + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); + + ob.write((const char*)__emu_buffer, 4); + + SerializeItem(ob, (const ItemInst*)int_struct->inst, int_struct->slot_id, 0); + if (ob.tellp() == last_pos) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); delete in; return; } - in->size = length + 4; - in->pBuffer = new unsigned char[in->size]; - ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - new_item_pkt->PacketType = old_item_pkt->PacketType; - memcpy(new_item_pkt->SerializedItem, serialized, length); + in->size = ob.size(); + in->pBuffer = ob.detach(); + delete[] __emu_buffer; - safe_delete_array(serialized); + dest->FastQueuePacket(&in, ack_req); } @@ -1358,7 +1386,8 @@ namespace UF OUT(new_mana); OUT(stamina); OUT(spell_id); - eq->unknown16 = -1; // Self Interrupt/Success = -1, Fizzle = 1, Other Interrupt = 2? + OUT(keepcasting); + eq->slot = -1; // this is spell gem slot. It's -1 in normal operation FINISH_ENCODE(); } @@ -1385,7 +1414,7 @@ namespace UF PacketSize += sizeof(structs::MercenaryStance_Struct) * emu->Mercs[r].StanceCount; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, PacketSize); + auto outapp = new EQApplicationPacket(OP_MercenaryDataResponse, PacketSize); Buffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->MercTypeCount); @@ -1736,18 +1765,18 @@ namespace UF VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 1); VARSTRUCT_ENCODE_TYPE(uint16, Buffer, emu->buffcount); - for (unsigned int i = 0; i < BUFF_COUNT; ++i) + for (unsigned int i = 0; i < PET_BUFF_COUNT; ++i) { if (emu->spellid[i]) { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, i); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->spellid[i]); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->ticsremaining[i]); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // numhits VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string. Name of the caster of the buff. } } - VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount); + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->buffcount); /// I think this is actually some sort of type delete[] __emu_buffer; dest->FastQueuePacket(&in, ack_req); @@ -1790,23 +1819,26 @@ namespace UF OUT(hairstyle); OUT(beard); // OUT(unknown00178[10]); - for (r = 0; r < 9; r++) { - eq->equipment[r].Material = emu->item_material[r]; - eq->equipment[r].Unknown1 = 0; - eq->equipment[r].EliteMaterial = 0; + for (r = EQEmu::textures::TextureBegin; r < EQEmu::textures::TextureCount; r++) { + eq->equipment.Slot[r].Material = emu->item_material.Slot[r].Material; + eq->equipment.Slot[r].Unknown1 = 0; + eq->equipment.Slot[r].EliteMaterial = 0; //eq->colors[r].color = emu->colors[r].color; } for (r = 0; r < 7; r++) { - OUT(item_tint[r].Color); + OUT(item_tint.Slot[r].Color); } // OUT(unknown00224[48]); //NOTE: new client supports 300 AAs, our internal rep/PP //only supports 240.. for (r = 0; r < MAX_PP_AA_ARRAY; r++) { - OUT(aa_array[r].AA); - OUT(aa_array[r].value); + eq->aa_array[r].AA = emu->aa_array[r].AA; + eq->aa_array[r].value = emu->aa_array[r].value; + eq->aa_array[r].charges = emu->aa_array[r].charges; } + // OUT(unknown02220[4]); + OUT(mana); OUT(cur_hp); OUT(STR); @@ -1839,26 +1871,26 @@ namespace UF OUT(thirst_level); OUT(hunger_level); //PS this needs to be figured out more; but it was 'good enough' - for (r = 0; r < structs::BUFF_COUNT; r++) + for (r = 0; r < BUFF_COUNT; r++) { if (emu->buffs[r].spellid != 0xFFFF && emu->buffs[r].spellid != 0) { - eq->buffs[r].unknown004 = 0x3f800000; - eq->buffs[r].slotid = 2; + eq->buffs[r].bard_modifier = 1.0f + (emu->buffs[r].bard_modifier - 10) / 10.0f; + eq->buffs[r].effect_type= 2; eq->buffs[r].player_id = 0x000717fd; } else { - eq->buffs[r].slotid = 0; + eq->buffs[r].effect_type = 0; + eq->buffs[r].bard_modifier = 1.0f; } - //OUT(buffs[r].slotid); + OUT(buffs[r].effect_type); OUT(buffs[r].level); - //OUT(buffs[r].bard_modifier); - //OUT(buffs[r].effect); + OUT(buffs[r].unknown003); OUT(buffs[r].spellid); OUT(buffs[r].duration); - OUT(buffs[r].counters); - //OUT(buffs[r].player_id); + OUT(buffs[r].num_hits); + OUT(buffs[r].player_id); } for (r = 0; r < MAX_PP_DISCIPLINES; r++) { OUT(disciplines.values[r]); @@ -1872,18 +1904,18 @@ namespace UF // OUT(unknown06160[4]); // Copy bandoliers where server and client indexes converge - for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { + for (r = 0; r < EQEmu::legacy::BANDOLIERS_SIZE && r < profile::BandoliersSize; ++r) { OUT_str(bandoliers[r].Name); - for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + for (uint32 k = 0; k < profile::BandolierItemCount; ++k) { // Will need adjusting if 'server != client' is ever true OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } // Nullify bandoliers where server and client indexes diverge, with a client bias - for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + for (r = EQEmu::legacy::BANDOLIERS_SIZE; r < profile::BandoliersSize; ++r) { eq->bandoliers[r].Name[0] = '\0'; - for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + for (uint32 k = 0; k < profile::BandolierItemCount; ++k) { // Will need adjusting if 'server != client' is ever true eq->bandoliers[r].Items[k].ID = 0; eq->bandoliers[r].Items[k].Icon = 0; eq->bandoliers[r].Items[k].Name[0] = '\0'; @@ -1893,13 +1925,13 @@ namespace UF // OUT(unknown07444[5120]); // Copy potion belt where server and client indexes converge - for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (r = 0; r < EQEmu::legacy::POTION_BELT_ITEM_COUNT && r < profile::PotionBeltSize; ++r) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); } // Nullify potion belt where server and client indexes diverge, with a client bias - for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + for (r = EQEmu::legacy::POTION_BELT_ITEM_COUNT; r < profile::PotionBeltSize; ++r) { eq->potionbelt.Items[r].ID = 0; eq->potionbelt.Items[r].Icon = 0; eq->potionbelt.Items[r].Name[0] = '\0'; @@ -1936,8 +1968,8 @@ namespace UF OUT(copper_bank); OUT(platinum_shared); // OUT(unknown13156[84]); - //OUT(expansions); - eq->expansions = 0xffff; + OUT(expansions); + //eq->expansions = 0x1ffff; // OUT(unknown13244[12]); OUT(autosplit); // OUT(unknown13260[16]); @@ -2024,7 +2056,7 @@ namespace UF unsigned char * __emu_buffer = inapp->pBuffer; RaidCreate_Struct *raid_create = (RaidCreate_Struct*)__emu_buffer; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp_create = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *general = (structs::RaidGeneral_Struct*)outapp_create->pBuffer; general->action = 8; @@ -2047,7 +2079,7 @@ namespace UF { RaidAddMember_Struct* in_add_member = (RaidAddMember_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidAddMember_Struct)); structs::RaidAddMember_Struct *add_member = (structs::RaidAddMember_Struct*)outapp->pBuffer; add_member->raidGen.action = in_add_member->raidGen.action; @@ -2067,7 +2099,8 @@ namespace UF else if (raid_gen->action == 35) { RaidMOTD_Struct *inmotd = (RaidMOTD_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + strlen(inmotd->motd) + 1); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidMOTD_Struct) + + strlen(inmotd->motd) + 1); structs::RaidMOTD_Struct *outmotd = (structs::RaidMOTD_Struct *)outapp->pBuffer; outmotd->general.action = inmotd->general.action; @@ -2078,7 +2111,8 @@ namespace UF else if (raid_gen->action == 14 || raid_gen->action == 30) { RaidLeadershipUpdate_Struct *inlaa = (RaidLeadershipUpdate_Struct *)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidLeadershipUpdate_Struct)); structs::RaidLeadershipUpdate_Struct *outlaa = (structs::RaidLeadershipUpdate_Struct *)outapp->pBuffer; outlaa->action = inlaa->action; @@ -2091,7 +2125,7 @@ namespace UF { RaidGeneral_Struct* in_raid_general = (RaidGeneral_Struct*)__emu_buffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(structs::RaidGeneral_Struct)); structs::RaidGeneral_Struct *raid_general = (structs::RaidGeneral_Struct*)outapp->pBuffer; strn0cpy(raid_general->leader_name, in_raid_general->leader_name, 64); strn0cpy(raid_general->player_name, in_raid_general->player_name, 64); @@ -2125,16 +2159,16 @@ namespace UF eq->aa_spent = emu->aa_spent; eq->aa_assigned = emu->aa_spent; - eq->aa_spent3 = emu->aa_spent; + eq->aa_spent3 = 0; eq->unknown012 = 0; eq->unknown016 = 0; eq->unknown020 = 0; for (uint32 i = 0; i < MAX_PP_AA_ARRAY; ++i) { - eq->aa_list[i].aa_skill = emu->aa_list[i].aa_skill; - eq->aa_list[i].aa_value = emu->aa_list[i].aa_value; - eq->aa_list[i].unknown08 = emu->aa_list[i].unknown08; + eq->aa_list[i].AA = emu->aa_list[i].AA; + eq->aa_list[i].value = emu->aa_list[i].value; + eq->aa_list[i].charges = emu->aa_list[i].charges; } FINISH_ENCODE(); @@ -2142,54 +2176,57 @@ namespace UF ENCODE(OP_SendAATable) { - ENCODE_LENGTH_ATLEAST(SendAA_Struct); - SETUP_VAR_ENCODE(SendAA_Struct); - ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability)); + EQApplicationPacket *inapp = *p; + *p = nullptr; + AARankInfo_Struct *emu = (AARankInfo_Struct*)inapp->pBuffer; - // Check clientver field to verify this AA should be sent for SoF - // clientver 1 is for all clients and 6 is for Underfoot - if (emu->clientver <= 6) - { - OUT(id); - eq->unknown004 = 1; - //eq->hotkey_sid = (emu->hotkey_sid==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->hotkey_sid2 = (emu->hotkey_sid2==4294967295UL)?0:(emu->id - emu->current_level + 1); - //eq->title_sid = emu->id - emu->current_level + 1; - //eq->desc_sid = emu->id - emu->current_level + 1; - eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->sof_next_skill); - eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->sof_next_skill); - eq->title_sid = emu->sof_next_skill; - eq->desc_sid = emu->sof_next_skill; - OUT(class_type); - OUT(cost); - OUT(seq); - OUT(current_level); - OUT(prereq_skill); - OUT(prereq_minpoints); - eq->type = emu->sof_type; - OUT(spellid); - OUT(spell_type); - OUT(spell_refresh); - OUT(classes); - OUT(berserker); - //eq->max_level = emu->sof_max_level; - OUT(max_level); - OUT(last_id); - OUT(next_id); - OUT(cost2); - eq->aa_expansion = emu->aa_expansion; - eq->special_category = emu->special_category; - OUT(total_abilities); - unsigned int r; - for (r = 0; r < emu->total_abilities; r++) { - OUT(abilities[r].skill_id); - OUT(abilities[r].base1); - OUT(abilities[r].base2); - OUT(abilities[r].slot); - } + auto outapp = new EQApplicationPacket( + OP_SendAATable, sizeof(structs::SendAA_Struct) + emu->total_effects * sizeof(structs::AA_Ability)); + structs::SendAA_Struct *eq = (structs::SendAA_Struct*)outapp->pBuffer; + + inapp->SetReadPosition(sizeof(AARankInfo_Struct)); + outapp->SetWritePosition(sizeof(structs::SendAA_Struct)); + + eq->id = emu->id; + eq->unknown004 = 1; + eq->id = emu->id; + eq->hotkey_sid = emu->upper_hotkey_sid; + eq->hotkey_sid2 = emu->lower_hotkey_sid; + eq->desc_sid = emu->desc_sid; + eq->title_sid = emu->title_sid; + eq->class_type = emu->level_req; + eq->cost = emu->cost; + eq->seq = emu->seq; + eq->current_level = emu->current_level; + eq->type = emu->type; + eq->spellid = emu->spell; + eq->spell_type = emu->spell_type; + eq->spell_refresh = emu->spell_refresh; + eq->classes = emu->classes; + eq->max_level = emu->max_level; + eq->last_id = emu->prev_id; + eq->next_id = emu->next_id; + eq->cost2 = emu->total_cost; + eq->grant_only = emu->grant_only; + eq->expendable_charges = emu->charges; + eq->aa_expansion = emu->expansion; + eq->special_category = emu->category; + eq->total_abilities = emu->total_effects; + + for(auto i = 0; i < eq->total_abilities; ++i) { + eq->abilities[i].skill_id = inapp->ReadUInt32(); + eq->abilities[i].base1 = inapp->ReadUInt32(); + eq->abilities[i].base2 = inapp->ReadUInt32(); + eq->abilities[i].slot = inapp->ReadUInt32(); } - FINISH_ENCODE(); + if(emu->total_prereqs > 0) { + eq->prereq_skill = inapp->ReadUInt32(); + eq->prereq_minpoints = inapp->ReadUInt32(); + } + + dest->FastQueuePacket(&outapp); + delete inapp; } ENCODE(OP_SendCharInfo) @@ -2203,8 +2240,8 @@ namespace UF eq->CharCount = emu->CharCount; eq->TotalChars = emu->TotalChars; - if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) - eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; + if (eq->TotalChars > constants::CharacterCreationLimit) + eq->TotalChars = constants::CharacterCreationLimit; // Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars' uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field @@ -2213,14 +2250,14 @@ namespace UF FINISH_ENCODE(); return; } - + unsigned char *emu_ptr = __emu_buffer; emu_ptr += sizeof(CharacterSelect_Struct); CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr; size_t names_length = 0; size_t character_count = 0; - for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) { + for (; character_count < emu->CharCount && character_count < constants::CharacterCreationLimit; ++character_count) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; names_length += strlen(emu_cse->Name); emu_ptr += sizeof(CharacterSelectEntry_Struct); @@ -2236,8 +2273,8 @@ namespace UF eq->CharCount = character_count; eq->TotalChars = emu->TotalChars; - if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) - eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; + if (eq->TotalChars > constants::CharacterCreationLimit) + eq->TotalChars = constants::CharacterCreationLimit; // Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars' in this client uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field @@ -2251,25 +2288,26 @@ namespace UF for (int counter = 0; counter < character_count; ++counter) { emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // base address eq_cse->Level = emu_cse->Level; eq_cse->HairStyle = emu_cse->HairStyle; eq_cse->Gender = emu_cse->Gender; strcpy(eq_cse->Name, emu_cse->Name); - eq_ptr += strlen(eq_cse->Name); - eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + eq_ptr += strlen(emu_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; // offset address (base + name length offset) + eq_cse->Name[0] = '\0'; // (offset)eq_cse->Name[0] = (base)eq_cse->Name[strlen(emu_cse->Name)] eq_cse->Beard = emu_cse->Beard; eq_cse->HairColor = emu_cse->HairColor; eq_cse->Face = emu_cse->Face; - for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) { + for (int equip_index = 0; equip_index < EQEmu::textures::TextureCount; equip_index++) { eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material; eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1; eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial; - eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; + eq_cse->Equip[equip_index].Color = emu_cse->Equip[equip_index].Color; } eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile; @@ -2388,7 +2426,7 @@ namespace UF return; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ChangeSize, sizeof(ChangeSize_Struct)); + auto outapp = new EQApplicationPacket(OP_ChangeSize, sizeof(ChangeSize_Struct)); ChangeSize_Struct *css = (ChangeSize_Struct *)outapp->pBuffer; css->EntityID = sas->spawn_id; @@ -2632,7 +2670,8 @@ namespace UF uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward)); *p = nullptr; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count)); + auto outapp_create = + new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward) * count)); uchar *old_data = __emu_buffer; uchar *data = outapp_create->pBuffer; for (unsigned int i = 0; i < count; ++i) @@ -2684,7 +2723,7 @@ namespace UF int Count = wars->playercount; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_WhoAllResponse, in->size + (Count * 4)); + auto outapp = new EQApplicationPacket(OP_WhoAllResponse, in->size + (Count * 4)); char *OutBuffer = (char *)outapp->pBuffer; @@ -2809,9 +2848,11 @@ namespace UF if (strlen(emu->suffix)) PacketSize += strlen(emu->suffix) + 1; - if (emu->DestructibleObject) + if (emu->DestructibleObject || emu->class_ == 62) { - PacketSize = PacketSize - 4; // No bodytype + if (emu->DestructibleObject) + PacketSize = PacketSize - 4; // No bodytype + PacketSize += 53; // Fixed portion PacketSize += strlen(emu->DestructibleModel) + 1; PacketSize += strlen(emu->DestructibleName2) + 1; @@ -2830,7 +2871,7 @@ namespace UF float SpawnSize = emu->size; if (!((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522))) { - PacketSize -= (sizeof(structs::EquipStruct) * 9); + PacketSize -= (sizeof(structs::Texture_Struct) * EQEmu::textures::TextureCount); if (emu->size == 0) { @@ -2844,7 +2885,7 @@ namespace UF SpawnSize = 3; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ZoneEntry, PacketSize); + auto outapp = new EQApplicationPacket(OP_ZoneEntry, PacketSize); Buffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_STRING(Buffer, emu->name); @@ -2894,6 +2935,9 @@ namespace UF uint8 OtherData = 0; + if (emu->class_ == 62) //Ldon chest + OtherData = OtherData | 0x01; + if (strlen(emu->title)) OtherData = OtherData | 0x04; @@ -2915,7 +2959,7 @@ namespace UF } VARSTRUCT_ENCODE_TYPE(float, Buffer, 0); // unknown4 - if (emu->DestructibleObject) + if (emu->DestructibleObject || emu->class_ == 62) { VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleModel); VARSTRUCT_ENCODE_STRING(Buffer, emu->DestructibleName2); @@ -3003,7 +3047,7 @@ namespace UF VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown12 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->petOwnerId); VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // unknown13 - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown14 - Stance 64 = normal 4 = aggressive 40 = stun/mezzed + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->PlayerState); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown15 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown16 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // unknown17 @@ -3026,10 +3070,10 @@ namespace UF if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)) { - for (k = 0; k < 9; ++k) + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; ++k) { { - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment_tint.Slot[k].Color); } } } @@ -3039,26 +3083,40 @@ namespace UF VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material); + if (emu->equipment.Primary.Material > 99999) { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 63); + } else { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment.Primary.Material); + } + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material); + if (emu->equipment.Secondary.Material > 99999) { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 63); + } else { + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment.Secondary.Material); + } + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); } if ((emu->NPC == 0) || (emu->race <= 12) || (emu->race == 128) || (emu->race == 130) || (emu->race == 330) || (emu->race == 522)) { - structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer; + structs::Texture_Struct *Equipment = (structs::Texture_Struct *)Buffer; - for (k = 0; k < 9; k++) { - Equipment[k].Material = emu->equipment[k].Material; - Equipment[k].Unknown1 = emu->equipment[k].Unknown1; - Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; + for (k = EQEmu::textures::TextureBegin; k < EQEmu::textures::TextureCount; k++) { + if (emu->equipment.Slot[k].Material > 99999) { + Equipment[k].Material = 63; + } else { + Equipment[k].Material = emu->equipment.Slot[k].Material; + } + Equipment[k].Unknown1 = emu->equipment.Slot[k].Unknown1; + Equipment[k].EliteMaterial = emu->equipment.Slot[k].EliteMaterial; } - Buffer += (sizeof(structs::EquipStruct) * 9); + Buffer += (sizeof(structs::Texture_Struct) * EQEmu::textures::TextureCount); } if (strlen(emu->title)) { @@ -3171,15 +3229,15 @@ namespace UF DECODE(OP_Buff) { - DECODE_LENGTH_EXACT(structs::SpellBuffFade_Struct_Underfoot); - SETUP_DIRECT_DECODE(SpellBuffFade_Struct, structs::SpellBuffFade_Struct_Underfoot); + DECODE_LENGTH_EXACT(structs::SpellBuffPacket_Struct); + SETUP_DIRECT_DECODE(SpellBuffPacket_Struct, structs::SpellBuffPacket_Struct); IN(entityid); - IN(slot); - IN(level); - IN(effect); - IN(spellid); - IN(duration); + IN(buff.effect_type); + IN(buff.level); + IN(buff.unknown003); + IN(buff.spellid); + IN(buff.duration); IN(slotid); IN(bufffade); @@ -3205,10 +3263,7 @@ namespace UF DECODE_LENGTH_EXACT(structs::CastSpell_Struct); SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct); - if (eq->slot == 13) - emu->slot = 10; - else - IN(slot); + emu->slot = static_cast(UFToServerCastingSlot(static_cast(eq->slot))); IN(spell_id); emu->inventoryslot = UFToServerSlot(eq->inventoryslot); @@ -3356,7 +3411,7 @@ namespace UF IN(type); IN(spellid); IN(damage); - emu->sequence = eq->sequence; + IN(meleepush_xy); FINISH_DIRECT_DECODE(); } @@ -3599,7 +3654,7 @@ namespace UF SETUP_DIRECT_DECODE(PetCommand_Struct, structs::PetCommand_Struct); IN(command); - IN(unknown); + IN(target); FINISH_DIRECT_DECODE(); } @@ -3794,114 +3849,93 @@ namespace UF return NextItemInstSerialNumber; } - char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth) + void SerializeItem(EQEmu::OutBuffer& ob, const ItemInst *inst, int16 slot_id_in, uint8 depth) { - int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - uint8 null_term = 0; - bool stackable = inst->IsStackable(); - uint32 merchant_slot = inst->GetMerchantSlot(); - uint32 charges = inst->GetCharges(); - if (!stackable && charges > 254) - charges = 0xFFFFFFFF; - - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - const Item_Struct *item = inst->GetUnscaledItem(); - //Log.LogDebugType(Logs::General, Logs::Netcode, "[ERROR] Serialize called for: %s", item->Name); + const EQEmu::ItemBase *item = inst->GetUnscaledItem(); + UF::structs::ItemSerializationHeader hdr; - hdr.stacksize = stackable ? charges : 1; + + hdr.stacksize = (inst->IsStackable() ? ((inst->GetCharges() > 1000) ? 0xFFFFFFFF : inst->GetCharges()) : 1); hdr.unknown004 = 0; int32 slot_id = ServerToUFSlot(slot_id_in); - hdr.slot = (merchant_slot == 0) ? slot_id : merchant_slot; + hdr.slot = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id); hdr.price = inst->GetPrice(); - hdr.merchant_slot = (merchant_slot == 0) ? 1 : inst->GetMerchantCount(); - hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; - hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; + hdr.merchant_slot = (inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1); + hdr.scaled_value = (inst->IsScaling() ? (inst->GetExp() / 100) : 0); + hdr.instance_id = (inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber()); hdr.unknown028 = 0; hdr.last_cast_time = inst->GetRecastTimestamp(); - hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); - hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; + hdr.charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254) ? 0xFFFFFFFF : inst->GetCharges())); + hdr.inst_nodrop = (inst->IsAttuned() ? 1 : 0); hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; - hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; - ss.write((const char*)&hdr, sizeof(UF::structs::ItemSerializationHeader)); + hdr.isEvolving = item->EvolvingItem; - if (item->EvolvingLevel > 0) { + ob.write((const char*)&hdr, sizeof(UF::structs::ItemSerializationHeader)); + + if (item->EvolvingItem > 0) { UF::structs::EvolvingItem evotop; + evotop.unknown001 = 0; evotop.unknown002 = 0; evotop.unknown003 = 0; evotop.unknown004 = 0; evotop.evoLevel = item->EvolvingLevel; - evotop.progress = 95.512; + evotop.progress = 0; evotop.Activated = 1; - evotop.evomaxlevel = 7; - ss.write((const char*)&evotop, sizeof(UF::structs::EvolvingItem)); - } - //ORNAMENT IDFILE / ICON - - uint16 ornaIcon = 0; - if (inst->GetOrnamentationAug(ornamentationAugtype)) { - const Item_Struct *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); - ss.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - ornaIcon = aug_weap->Icon; - } - else if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { - char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); - ss.write(tmp, strlen(tmp)); - ss.write((const char*)&null_term, sizeof(uint8)); - ornaIcon = inst->GetOrnamentationIcon(); - } - else { - ss.write((const char*)&null_term, sizeof(uint8)); //no idfile + evotop.evomaxlevel = item->EvolvingMax; + + ob.write((const char*)&evotop, sizeof(UF::structs::EvolvingItem)); } + //ORNAMENT IDFILE / ICON - + int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); + uint16 ornaIcon = 0; + if (inst->GetOrnamentationAug(ornamentationAugtype)) { + const EQEmu::ItemBase *aug_weap = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); + ornaIcon = aug_weap->Icon; + + ob.write(aug_weap->IDFile, strlen(aug_weap->IDFile)); + } + else if (inst->GetOrnamentationIDFile() && inst->GetOrnamentationIcon()) { + ornaIcon = inst->GetOrnamentationIcon(); + char tmp[30]; memset(tmp, 0x0, 30); sprintf(tmp, "IT%d", inst->GetOrnamentationIDFile()); + + ob.write(tmp, strlen(tmp)); + } + ob.write("\0", 1); + UF::structs::ItemSerializationHeaderFinish hdrf; + hdrf.ornamentIcon = ornaIcon; - hdrf.unknown060 = 0; //This is Always 0.. or it breaks shit.. + hdrf.unknown060 = 0; //This is Always 0.. or it breaks shit.. hdrf.unknown061 = 0; //possibly ornament / special ornament hdrf.isCopied = 0; //Flag for item to be 'Copied' hdrf.ItemClass = item->ItemClass; - ss.write((const char*)&hdrf, sizeof(UF::structs::ItemSerializationHeaderFinish)); + + ob.write((const char*)&hdrf, sizeof(UF::structs::ItemSerializationHeaderFinish)); if (strlen(item->Name) > 0) - { - ss.write(item->Name, strlen(item->Name)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Name, strlen(item->Name)); + ob.write("\0", 1); if (strlen(item->Lore) > 0) - { - ss.write(item->Lore, strlen(item->Lore)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->Lore, strlen(item->Lore)); + ob.write("\0", 1); if (strlen(item->IDFile) > 0) - { - ss.write(item->IDFile, strlen(item->IDFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write(item->IDFile, strlen(item->IDFile)); + ob.write("\0", 1); UF::structs::ItemBodyStruct ibs; memset(&ibs, 0, sizeof(UF::structs::ItemBodyStruct)); ibs.id = item->ID; - ibs.weight = item->Weight; + // weight is uint8 in the struct, and some weights exceed that, so capping at 255. + ibs.weight = ((item->Weight > 255) ? 255 : item->Weight); ibs.norent = item->NoRent; ibs.nodrop = item->NoDrop; ibs.attune = item->Attuneable; @@ -3938,7 +3972,7 @@ namespace UF ibs.Races = item->Races; ibs.Deity = item->Deity; ibs.SkillModValue = item->SkillModValue; - ibs.unknown5 = 0; + ibs.SkillModMax = item->SkillModMax; ibs.SkillModType = item->SkillModType; ibs.BaneDmgRace = item->BaneDmgRace; ibs.BaneDmgBody = item->BaneDmgBody; @@ -3983,18 +4017,12 @@ namespace UF ibs.FactionAmt4 = item->FactionAmt4; ibs.FactionMod4 = item->FactionMod4; - ss.write((const char*)&ibs, sizeof(UF::structs::ItemBodyStruct)); + ob.write((const char*)&ibs, sizeof(UF::structs::ItemBodyStruct)); //charm text if (strlen(item->CharmFile) > 0) - { - ss.write((const char*)item->CharmFile, strlen(item->CharmFile)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->CharmFile, strlen(item->CharmFile)); + ob.write("\0", 1); UF::structs::ItemSecondaryBodyStruct isbs; memset(&isbs, 0, sizeof(UF::structs::ItemSecondaryBodyStruct)); @@ -4002,11 +4030,10 @@ namespace UF isbs.augtype = item->AugType; isbs.augrestrict = item->AugRestrict; - for (int x = 0; x < consts::ITEM_COMMON_SIZE; x++) - { - isbs.augslots[x].type = item->AugSlotType[x]; - isbs.augslots[x].visible = item->AugSlotVisible[x]; - isbs.augslots[x].unknown = item->AugSlotUnk2[x]; + for (int index = 0; index < invaug::ItemAugSize; ++index) { + isbs.augslots[index].type = item->AugSlotType[index]; + isbs.augslots[index].visible = item->AugSlotVisible[index]; + isbs.augslots[index].unknown = item->AugSlotUnk2[index]; } isbs.ldonpoint_type = item->PointType; @@ -4023,17 +4050,11 @@ namespace UF isbs.book = item->Book; isbs.booktype = item->BookType; - ss.write((const char*)&isbs, sizeof(UF::structs::ItemSecondaryBodyStruct)); + ob.write((const char*)&isbs, sizeof(UF::structs::ItemSecondaryBodyStruct)); if (strlen(item->Filename) > 0) - { - ss.write((const char*)item->Filename, strlen(item->Filename)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->Filename, strlen(item->Filename)); + ob.write("\0", 1); UF::structs::ItemTertiaryBodyStruct itbs; memset(&itbs, 0, sizeof(UF::structs::ItemTertiaryBodyStruct)); @@ -4053,11 +4074,11 @@ namespace UF itbs.potion_belt_enabled = item->PotionBelt; itbs.potion_belt_slots = item->PotionBeltSlots; - itbs.stacksize = stackable ? item->StackSize : 0; + itbs.stacksize = (inst->IsStackable() ? item->StackSize : 0); itbs.no_transfer = item->NoTransfer; itbs.expendablearrow = item->ExpendableArrow; - ss.write((const char*)&itbs, sizeof(UF::structs::ItemTertiaryBodyStruct)); + ob.write((const char*)&itbs, sizeof(UF::structs::ItemTertiaryBodyStruct)); // Effect Structures Broken down to allow variable length strings for effect names int32 effect_unknown = 0; @@ -4074,19 +4095,13 @@ namespace UF ices.recast = item->RecastDelay; ices.recast_type = item->RecastType; - ss.write((const char*)&ices, sizeof(UF::structs::ClickEffectStruct)); + ob.write((const char*)&ices, sizeof(UF::structs::ClickEffectStruct)); if (strlen(item->ClickName) > 0) - { - ss.write((const char*)item->ClickName, strlen(item->ClickName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ClickName, strlen(item->ClickName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 + ob.write((const char*)&effect_unknown, sizeof(int32)); // clickunk7 UF::structs::ProcEffectStruct ipes; memset(&ipes, 0, sizeof(UF::structs::ProcEffectStruct)); @@ -4097,19 +4112,13 @@ namespace UF ipes.level = item->Proc.Level; ipes.procrate = item->ProcRate; - ss.write((const char*)&ipes, sizeof(UF::structs::ProcEffectStruct)); + ob.write((const char*)&ipes, sizeof(UF::structs::ProcEffectStruct)); if (strlen(item->ProcName) > 0) - { - ss.write((const char*)item->ProcName, strlen(item->ProcName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ProcName, strlen(item->ProcName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown5 UF::structs::WornEffectStruct iwes; memset(&iwes, 0, sizeof(UF::structs::WornEffectStruct)); @@ -4119,19 +4128,13 @@ namespace UF iwes.type = item->Worn.Type; iwes.level = item->Worn.Level; - ss.write((const char*)&iwes, sizeof(UF::structs::WornEffectStruct)); + ob.write((const char*)&iwes, sizeof(UF::structs::WornEffectStruct)); if (strlen(item->WornName) > 0) - { - ss.write((const char*)item->WornName, strlen(item->WornName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->WornName, strlen(item->WornName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 UF::structs::WornEffectStruct ifes; memset(&ifes, 0, sizeof(UF::structs::WornEffectStruct)); @@ -4141,19 +4144,13 @@ namespace UF ifes.type = item->Focus.Type; ifes.level = item->Focus.Level; - ss.write((const char*)&ifes, sizeof(UF::structs::WornEffectStruct)); + ob.write((const char*)&ifes, sizeof(UF::structs::WornEffectStruct)); if (strlen(item->FocusName) > 0) - { - ss.write((const char*)item->FocusName, strlen(item->FocusName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->FocusName, strlen(item->FocusName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 UF::structs::WornEffectStruct ises; memset(&ises, 0, sizeof(UF::structs::WornEffectStruct)); @@ -4163,19 +4160,13 @@ namespace UF ises.type = item->Scroll.Type; ises.level = item->Scroll.Level; - ss.write((const char*)&ises, sizeof(UF::structs::WornEffectStruct)); + ob.write((const char*)&ises, sizeof(UF::structs::WornEffectStruct)); if (strlen(item->ScrollName) > 0) - { - ss.write((const char*)item->ScrollName, strlen(item->ScrollName)); - ss.write((const char*)&null_term, sizeof(uint8)); - } - else - { - ss.write((const char*)&null_term, sizeof(uint8)); - } + ob.write((const char*)item->ScrollName, strlen(item->ScrollName)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // Bard Effect? UF::structs::WornEffectStruct ibes; @@ -4187,18 +4178,18 @@ namespace UF ibes.level = item->Bard.Level; //ibes.unknown6 = 0xffffffff; - ss.write((const char*)&ibes, sizeof(UF::structs::WornEffectStruct)); + ob.write((const char*)&ibes, sizeof(UF::structs::WornEffectStruct)); /* if(strlen(item->BardName) > 0) { - ss.write((const char*)item->BardName, strlen(item->BardName)); - ss.write((const char*)&null_term, sizeof(uint8)); + ob.write((const char*)item->BardName, strlen(item->BardName)); + ob.write((const char*)&null_term, sizeof(uint8)); } else */ - ss.write((const char*)&null_term, sizeof(uint8)); + ob.write("\0", 1); - ss.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 + ob.write((const char*)&effect_unknown, sizeof(int32)); // unknown6 // End of Effects UF::structs::ItemQuaternaryBodyStruct iqbs; @@ -4226,83 +4217,54 @@ namespace UF iqbs.HeroicSVCorrup = item->HeroicSVCorrup; iqbs.HealAmt = item->HealAmt; iqbs.SpellDmg = item->SpellDmg; - iqbs.clairvoyance = item->Clairvoyance; + iqbs.Clairvoyance = item->Clairvoyance; + + ob.write((const char*)&iqbs, sizeof(UF::structs::ItemQuaternaryBodyStruct)); - iqbs.subitem_count = 0; + EQEmu::OutBuffer::pos_type count_pos = ob.tellp(); + uint32 subitem_count = 0; - char *SubSerializations[10]; // + ob.write((const char*)&subitem_count, sizeof(uint32)); - uint32 SubLengths[10]; + for (uint32 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { + ItemInst* sub = inst->GetItem(index); + if (!sub) + continue; - for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; ++x) { + int SubSlotNumber = INVALID_INDEX; + if (slot_id_in >= EQEmu::legacy::GENERAL_BEGIN && slot_id_in <= EQEmu::legacy::GENERAL_END) + SubSlotNumber = (((slot_id_in + 3) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + index + 1); + else if (slot_id_in >= EQEmu::legacy::BANK_BEGIN && slot_id_in <= EQEmu::legacy::BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::BANK_BAGS_BEGIN + index); + else if (slot_id_in >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::legacy::SHARED_BANK_END) + SubSlotNumber = (((slot_id_in - EQEmu::legacy::SHARED_BANK_BEGIN) * EQEmu::legacy::ITEM_CONTAINER_SIZE) + EQEmu::legacy::SHARED_BANK_BAGS_BEGIN + index); + else + SubSlotNumber = slot_id_in; - SubSerializations[x] = nullptr; + ob.write((const char*)&index, sizeof(uint32)); - const ItemInst* subitem = ((const ItemInst*)inst)->GetItem(x); - - if (subitem) { - - int SubSlotNumber; - - iqbs.subitem_count++; - - if (slot_id_in >= EmuConstants::GENERAL_BEGIN && slot_id_in <= EmuConstants::GENERAL_END) // (< 30) - no cursor? - //SubSlotNumber = (((slot_id_in + 3) * 10) + x + 1); - SubSlotNumber = (((slot_id_in + 3) * EmuConstants::ITEM_CONTAINER_SIZE) + x + 1); - else if (slot_id_in >= EmuConstants::BANK_BEGIN && slot_id_in <= EmuConstants::BANK_END) - //SubSlotNumber = (((slot_id_in - 2000) * 10) + 2030 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::BANK_BAGS_BEGIN + x); - else if (slot_id_in >= EmuConstants::SHARED_BANK_BEGIN && slot_id_in <= EmuConstants::SHARED_BANK_END) - //SubSlotNumber = (((slot_id_in - 2500) * 10) + 2530 + x + 1); - SubSlotNumber = (((slot_id_in - EmuConstants::SHARED_BANK_BEGIN) * EmuConstants::ITEM_CONTAINER_SIZE) + EmuConstants::SHARED_BANK_BAGS_BEGIN + x); - else - SubSlotNumber = slot_id_in; // ??????? - - /* - // TEST CODE: - SubSlotNumber = Inventory::CalcSlotID(slot_id_in, x); - */ - - SubSerializations[x] = SerializeItem(subitem, SubSlotNumber, &SubLengths[x], depth + 1); - } + SerializeItem(ob, sub, SubSlotNumber, (depth + 1)); + ++subitem_count; } - ss.write((const char*)&iqbs, sizeof(UF::structs::ItemQuaternaryBodyStruct)); - - for (int x = 0; x < 10; ++x) { - - if (SubSerializations[x]) { - - ss.write((const char*)&x, sizeof(uint32)); - - ss.write(SubSerializations[x], SubLengths[x]); - - safe_delete_array(SubSerializations[x]); - } - } - - char* item_serial = new char[ss.tellp()]; - memset(item_serial, 0, ss.tellp()); - memcpy(item_serial, ss.str().c_str(), ss.tellp()); - - *length = ss.tellp(); - return item_serial; + if (subitem_count) + ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32)); } static inline uint32 ServerToUFSlot(uint32 serverSlot) { uint32 UnderfootSlot = 0; - if (serverSlot >= MainAmmo && serverSlot <= 53) // Cursor/Ammo/Power Source and Normal Inventory Slots + if (serverSlot >= EQEmu::legacy::SlotAmmo && serverSlot <= 53) // Cursor/Ammo/Power Source and Normal Inventory Slots UnderfootSlot = serverSlot + 1; - else if (serverSlot >= EmuConstants::GENERAL_BAGS_BEGIN && serverSlot <= EmuConstants::CURSOR_BAG_END) + else if (serverSlot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::legacy::CURSOR_BAG_END) UnderfootSlot = serverSlot + 11; - else if (serverSlot >= EmuConstants::BANK_BAGS_BEGIN && serverSlot <= EmuConstants::BANK_BAGS_END) + else if (serverSlot >= EQEmu::legacy::BANK_BAGS_BEGIN && serverSlot <= EQEmu::legacy::BANK_BAGS_END) UnderfootSlot = serverSlot + 1; - else if (serverSlot >= EmuConstants::SHARED_BANK_BAGS_BEGIN && serverSlot <= EmuConstants::SHARED_BANK_BAGS_END) + else if (serverSlot >= EQEmu::legacy::SHARED_BANK_BAGS_BEGIN && serverSlot <= EQEmu::legacy::SHARED_BANK_BAGS_END) UnderfootSlot = serverSlot + 1; - else if (serverSlot == MainPowerSource) - UnderfootSlot = slots::MainPowerSource; + else if (serverSlot == EQEmu::legacy::SlotPowerSource) + UnderfootSlot = invslot::PossessionsPowerSource; else UnderfootSlot = serverSlot; @@ -4319,16 +4281,16 @@ namespace UF { uint32 ServerSlot = 0; - if (ufSlot >= slots::MainAmmo && ufSlot <= consts::CORPSE_END) // Cursor/Ammo/Power Source and Normal Inventory Slots + if (ufSlot >= invslot::PossessionsAmmo && ufSlot <= invslot::CorpseEnd) // Cursor/Ammo/Power Source and Normal Inventory Slots ServerSlot = ufSlot - 1; - else if (ufSlot >= consts::GENERAL_BAGS_BEGIN && ufSlot <= consts::CURSOR_BAG_END) + else if (ufSlot >= invbag::GeneralBagsBegin && ufSlot <= invbag::CursorBagEnd) ServerSlot = ufSlot - 11; - else if (ufSlot >= consts::BANK_BAGS_BEGIN && ufSlot <= consts::BANK_BAGS_END) + else if (ufSlot >= invbag::BankBagsBegin && ufSlot <= invbag::BankBagsEnd) ServerSlot = ufSlot - 1; - else if (ufSlot >= consts::SHARED_BANK_BAGS_BEGIN && ufSlot <= consts::SHARED_BANK_BAGS_END) + else if (ufSlot >= invbag::SharedBankBagsBegin && ufSlot <= invbag::SharedBankBagsEnd) ServerSlot = ufSlot - 1; - else if (ufSlot == slots::MainPowerSource) - ServerSlot = MainPowerSource; + else if (ufSlot == invslot::PossessionsPowerSource) + ServerSlot = EQEmu::legacy::SlotPowerSource; else ServerSlot = ufSlot; @@ -4343,7 +4305,7 @@ namespace UF static inline void ServerToUFTextLink(std::string& ufTextLink, const std::string& serverTextLink) { - if ((consts::TEXT_LINK_BODY_LENGTH == EmuConstants::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { + if ((constants::SayLinkBodySize == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) || (serverTextLink.find('\x12') == std::string::npos)) { ufTextLink = serverTextLink; return; } @@ -4352,7 +4314,7 @@ namespace UF for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= EmuConstants::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= EQEmu::legacy::TEXT_LINK_BODY_LENGTH) { ufTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -4383,7 +4345,7 @@ namespace UF static inline void UFToServerTextLink(std::string& serverTextLink, const std::string& ufTextLink) { - if ((EmuConstants::TEXT_LINK_BODY_LENGTH == consts::TEXT_LINK_BODY_LENGTH) || (ufTextLink.find('\x12') == std::string::npos)) { + if ((EQEmu::legacy::TEXT_LINK_BODY_LENGTH == constants::SayLinkBodySize) || (ufTextLink.find('\x12') == std::string::npos)) { serverTextLink = ufTextLink; return; } @@ -4392,7 +4354,7 @@ namespace UF for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) { if (segment_iter & 1) { - if (segments[segment_iter].length() <= consts::TEXT_LINK_BODY_LENGTH) { + if (segments[segment_iter].length() <= constants::SayLinkBodySize) { serverTextLink.append(segments[segment_iter]); // TODO: log size mismatch error continue; @@ -4416,5 +4378,81 @@ namespace UF } } } -} -// end namespace UF + + static inline CastingSlot ServerToUFCastingSlot(EQEmu::CastingSlot slot) + { + switch (slot) { + case EQEmu::CastingSlot::Gem1: + return CastingSlot::Gem1; + case EQEmu::CastingSlot::Gem2: + return CastingSlot::Gem2; + case EQEmu::CastingSlot::Gem3: + return CastingSlot::Gem3; + case EQEmu::CastingSlot::Gem4: + return CastingSlot::Gem4; + case EQEmu::CastingSlot::Gem5: + return CastingSlot::Gem5; + case EQEmu::CastingSlot::Gem6: + return CastingSlot::Gem6; + case EQEmu::CastingSlot::Gem7: + return CastingSlot::Gem7; + case EQEmu::CastingSlot::Gem8: + return CastingSlot::Gem8; + case EQEmu::CastingSlot::Gem9: + return CastingSlot::Gem9; + case EQEmu::CastingSlot::Gem10: + return CastingSlot::Gem10; + case EQEmu::CastingSlot::Gem11: + return CastingSlot::Gem11; + case EQEmu::CastingSlot::Gem12: + return CastingSlot::Gem12; + case EQEmu::CastingSlot::Item: + case EQEmu::CastingSlot::PotionBelt: + return CastingSlot::Item; + case EQEmu::CastingSlot::Discipline: + return CastingSlot::Discipline; + case EQEmu::CastingSlot::AltAbility: + return CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return CastingSlot::Discipline; + } + } + + static inline EQEmu::CastingSlot UFToServerCastingSlot(CastingSlot slot) + { + switch (slot) { + case CastingSlot::Gem1: + return EQEmu::CastingSlot::Gem1; + case CastingSlot::Gem2: + return EQEmu::CastingSlot::Gem2; + case CastingSlot::Gem3: + return EQEmu::CastingSlot::Gem3; + case CastingSlot::Gem4: + return EQEmu::CastingSlot::Gem4; + case CastingSlot::Gem5: + return EQEmu::CastingSlot::Gem5; + case CastingSlot::Gem6: + return EQEmu::CastingSlot::Gem6; + case CastingSlot::Gem7: + return EQEmu::CastingSlot::Gem7; + case CastingSlot::Gem8: + return EQEmu::CastingSlot::Gem8; + case CastingSlot::Gem9: + return EQEmu::CastingSlot::Gem9; + case CastingSlot::Gem10: + return EQEmu::CastingSlot::Gem10; + case CastingSlot::Gem11: + return EQEmu::CastingSlot::Gem11; + case CastingSlot::Gem12: + return EQEmu::CastingSlot::Gem12; + case CastingSlot::Discipline: + return EQEmu::CastingSlot::Discipline; + case CastingSlot::Item: + return EQEmu::CastingSlot::Item; + case CastingSlot::AltAbility: + return EQEmu::CastingSlot::AltAbility; + default: // we shouldn't have any issues with other slots ... just return something + return EQEmu::CastingSlot::Discipline; + } + } +} /*UF*/ diff --git a/common/patches/uf.h b/common/patches/uf.h index 26e2346a7..1dc5046c3 100644 --- a/common/patches/uf.h +++ b/common/patches/uf.h @@ -1,11 +1,31 @@ -#ifndef UF_H_ -#define UF_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_UF_H +#define COMMON_UF_H #include "../struct_strategy.h" class EQStreamIdentifier; -namespace UF { +namespace UF +{ //these are the only public member of this namespace. extern void Register(EQStreamIdentifier &into); @@ -23,13 +43,31 @@ namespace UF { protected: virtual std::string Describe() const; - virtual const ClientVersion GetClientVersion() const; + virtual const EQEmu::versions::ClientVersion ClientVersion() const; //magic macro to declare our opcode processors #include "ss_declare.h" #include "uf_ops.h" }; -}; + enum class CastingSlot : uint32 { + Gem1 = 0, + Gem2 = 1, + Gem3 = 2, + Gem4 = 3, + Gem5 = 4, + Gem6 = 5, + Gem7 = 6, + Gem8 = 7, + Gem9 = 8, + Gem10 = 9, + Gem11 = 10, + Gem12 = 11, + Item = 12, + Discipline = 13, + AltAbility = 0xFF + }; -#endif /*UF_H_*/ +}; /*UF*/ + +#endif /*COMMON_UF_H*/ diff --git a/common/patches/uf_constants.h b/common/patches/uf_constants.h deleted file mode 100644 index 1a5a4cc44..000000000 --- a/common/patches/uf_constants.h +++ /dev/null @@ -1,218 +0,0 @@ -/* -EQEMu: Everquest Server Emulator - -Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY except by those people which sell it, which -are required to give you total support for your newly bought product; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -#ifndef UF_CONSTANTS_H_ -#define UF_CONSTANTS_H_ - -#include "../types.h" - -namespace UF { - namespace maps { - typedef enum : int16 { - // this needs work to match actual client equivilents - MapPossessions = 0, - MapBank, - MapSharedBank, - MapTrade, - MapWorld, - MapLimbo, - MapTribute, - MapTrophyTribute, - MapGuildTribute, - MapMerchant, - MapDeleted, - MapCorpse, - MapBazaar, - MapInspect, - MapRealEstate, - MapViewMODPC, - MapViewMODBank, - MapViewMODSharedBank, - MapViewMODLimbo, - MapAltStorage, - MapArchived, - MapMail, - MapGuildTrophyTribute, - MapOther, - _MapCount - } InventoryMaps; - } - - namespace slots { - typedef enum : int16 { - MainCharm = 0, - MainEar1, - MainHead, - MainFace, - MainEar2, - MainNeck, - MainShoulders, - MainArms, - MainBack, - MainWrist1, - MainWrist2, - MainRange, - MainHands, - MainPrimary, - MainSecondary, - MainFinger1, - MainFinger2, - MainChest, - MainLegs, - MainFeet, - MainWaist, - MainPowerSource, - MainAmmo, - MainGeneral1, - MainGeneral2, - MainGeneral3, - MainGeneral4, - MainGeneral5, - MainGeneral6, - MainGeneral7, - MainGeneral8, - MainCursor, - _MainCount, - _MainEquipmentBegin = MainCharm, - _MainEquipmentEnd = MainAmmo, - _MainEquipmentCount = (_MainEquipmentEnd - _MainEquipmentBegin + 1), - _MainGeneralBegin = MainGeneral1, - _MainGeneralEnd = MainGeneral8, - _MainGeneralCount = (_MainGeneralEnd - _MainGeneralBegin + 1) - } EquipmentSlots; - } - - namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 12; - - static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; - static const uint16 MAP_BANK_SIZE = 24; - static const uint16 MAP_SHARED_BANK_SIZE = 2; - static const uint16 MAP_TRADE_SIZE = 8; - static const uint16 MAP_WORLD_SIZE = 10; - static const uint16 MAP_LIMBO_SIZE = 36; - static const uint16 MAP_TRIBUTE_SIZE = 0; //? - static const uint16 MAP_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_GUILD_TRIBUTE_SIZE = 0; - static const uint16 MAP_MERCHANT_SIZE = 0; - static const uint16 MAP_DELETED_SIZE = 0; - static const uint16 MAP_CORPSE_SIZE = slots::_MainCount; - static const uint16 MAP_BAZAAR_SIZE = 80; - static const uint16 MAP_INSPECT_SIZE = slots::_MainEquipmentCount; - static const uint16 MAP_REAL_ESTATE_SIZE = 0; - static const uint16 MAP_VIEW_MOD_PC_SIZE = MAP_POSSESSIONS_SIZE; - static const uint16 MAP_VIEW_MOD_BANK_SIZE = MAP_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_SHARED_BANK_SIZE = MAP_SHARED_BANK_SIZE; - static const uint16 MAP_VIEW_MOD_LIMBO_SIZE = MAP_LIMBO_SIZE; - static const uint16 MAP_ALT_STORAGE_SIZE = 0; - static const uint16 MAP_ARCHIVED_SIZE = 0; - static const uint16 MAP_MAIL_SIZE = 0; - static const uint16 MAP_GUILD_TROPHY_TRIBUTE_SIZE = 0; - static const uint16 MAP_KRONO_SIZE = NOT_USED; - static const uint16 MAP_OTHER_SIZE = 0; - - static const int16 EQUIPMENT_BEGIN = slots::MainCharm; - static const int16 EQUIPMENT_END = slots::MainAmmo; - static const uint16 EQUIPMENT_SIZE = slots::_MainEquipmentCount; - - static const int16 GENERAL_BEGIN = slots::MainGeneral1; - static const int16 GENERAL_END = slots::MainGeneral8; - static const uint16 GENERAL_SIZE = slots::_MainGeneralCount; - static const int16 GENERAL_BAGS_BEGIN = 262; - static const int16 GENERAL_BAGS_END_OFFSET = 79; - static const int16 GENERAL_BAGS_END = GENERAL_BAGS_BEGIN + GENERAL_BAGS_END_OFFSET; - - static const int16 CURSOR = slots::MainCursor; - static const int16 CURSOR_BAG_BEGIN = 342; - static const int16 CURSOR_BAG_END_OFFSET = 9; - static const int16 CURSOR_BAG_END = CURSOR_BAG_BEGIN + CURSOR_BAG_END_OFFSET; - - static const int16 BANK_BEGIN = 2000; - static const int16 BANK_END = 2023; - static const int16 BANK_BAGS_BEGIN = 2032; - static const int16 BANK_BAGS_END_OFFSET = 239; - static const int16 BANK_BAGS_END = BANK_BAGS_BEGIN + BANK_BAGS_END_OFFSET; - - static const int16 SHARED_BANK_BEGIN = 2500; - static const int16 SHARED_BANK_END = 2501; - static const int16 SHARED_BANK_BAGS_BEGIN = 2532; - static const int16 SHARED_BANK_BAGS_END_OFFSET = 19; - static const int16 SHARED_BANK_BAGS_END = SHARED_BANK_BAGS_BEGIN + SHARED_BANK_BAGS_END_OFFSET; - - static const int16 TRADE_BEGIN = 3000; - static const int16 TRADE_END = 3007; - static const int16 TRADE_NPC_END = 3003; - static const int16 TRADE_BAGS_BEGIN = 3031; - static const int16 TRADE_BAGS_END_OFFSET = 79; - static const int16 TRADE_BAGS_END = TRADE_BAGS_BEGIN + TRADE_BAGS_END_OFFSET; - - static const int16 WORLD_BEGIN = 4000; - static const int16 WORLD_END = 4009; - - static const int16 TRIBUTE_BEGIN = 400; - static const int16 TRIBUTE_END = 404; - - static const int16 CORPSE_BEGIN = slots::MainGeneral1; - static const int16 CORPSE_END = slots::MainGeneral1 + slots::MainCursor; - - static const uint16 ITEM_COMMON_SIZE = 5; - static const uint16 ITEM_CONTAINER_SIZE = 10; - - static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances - static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance - - static const size_t POTION_BELT_ITEM_COUNT = 5; - - static const size_t TEXT_LINK_BODY_LENGTH = 50; - } - - namespace limits { - static const bool ALLOWS_EMPTY_BAG_IN_BAG = false; - static const bool ALLOWS_CLICK_CAST_FROM_BAG = false; - static const bool COIN_HAS_WEIGHT = false; - } - -}; //end namespace UF - -#endif /*UF_CONSTANTS_H_*/ - -/* -UF Notes: - ** Integer-based inventory ** -ok Possessions: 0 - 31 (Corpse: 23 - 54 [Offset 23]) -ok [Equipment: 0 - 22] -ok [General: 23 - 30] -ok [Cursor: 31] -ok General Bags: 262 - 341 -ok Cursor Bags: 342 - 351 - -ok Bank: 2000 - 2023 -ok Bank Bags: 2032 - 2271 - -ok Shared Bank: 2500 - 2501 -ok Shared Bank Bags: 2532 - 2551 - - Trade: 3000 - 3007 - (Trade Bags: 3031 - 3110 -- server values) - - World: 4000 - 4009 - -*/ diff --git a/common/patches/uf_limits.cpp b/common/patches/uf_limits.cpp new file mode 100644 index 000000000..ae415ddd8 --- /dev/null +++ b/common/patches/uf_limits.cpp @@ -0,0 +1,272 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "uf_limits.h" + +#include "../string_util.h" + + +size_t UF::invtype::GetInvTypeSize(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + return invtype::InvTypePossessionsSize; + case invtype::InvTypeBank: + return invtype::InvTypeBankSize; + case invtype::InvTypeSharedBank: + return invtype::InvTypeSharedBankSize; + case invtype::InvTypeTrade: + return invtype::InvTypeTradeSize; + case invtype::InvTypeWorld: + return invtype::InvTypeWorldSize; + case invtype::InvTypeLimbo: + return invtype::InvTypeLimboSize; + case invtype::InvTypeTribute: + return invtype::InvTypeTributeSize; + case invtype::InvTypeGuildTribute: + return invtype::InvTypeGuildTributeSize; + case invtype::InvTypeMerchant: + return invtype::InvTypeMerchantSize; + case invtype::InvTypeCorpse: + return invtype::InvTypeCorpseSize; + case invtype::InvTypeBazaar: + return invtype::InvTypeBazaarSize; + case invtype::InvTypeInspect: + return invtype::InvTypeInspectSize; + case invtype::InvTypeViewMODPC: + return invtype::InvTypeViewMODPCSize; + case invtype::InvTypeViewMODBank: + return invtype::InvTypeViewMODBankSize; + case invtype::InvTypeViewMODSharedBank: + return invtype::InvTypeViewMODSharedBankSize; + case invtype::InvTypeViewMODLimbo: + return invtype::InvTypeViewMODLimboSize; + case invtype::InvTypeAltStorage: + return invtype::InvTypeAltStorageSize; + case invtype::InvTypeArchived: + return invtype::InvTypeArchivedSize; + case invtype::InvTypeOther: + return invtype::InvTypeOtherSize; + default: + return 0; + } +} + +const char* UF::invtype::GetInvTypeName(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypeInvalid: + return "Invalid Type"; + case invtype::InvTypePossessions: + return "Possessions"; + case invtype::InvTypeBank: + return "Bank"; + case invtype::InvTypeSharedBank: + return "Shared Bank"; + case invtype::InvTypeTrade: + return "Trade"; + case invtype::InvTypeWorld: + return "World"; + case invtype::InvTypeLimbo: + return "Limbo"; + case invtype::InvTypeTribute: + return "Tribute"; + case invtype::InvTypeGuildTribute: + return "Guild Tribute"; + case invtype::InvTypeMerchant: + return "Merchant"; + case invtype::InvTypeCorpse: + return "Corpse"; + case invtype::InvTypeBazaar: + return "Bazaar"; + case invtype::InvTypeInspect: + return "Inspect"; + case invtype::InvTypeViewMODPC: + return "View MOD PC"; + case invtype::InvTypeViewMODBank: + return "View MOD Bank"; + case invtype::InvTypeViewMODSharedBank: + return "View MOD Shared Bank"; + case invtype::InvTypeViewMODLimbo: + return "View MOD Limbo"; + case invtype::InvTypeAltStorage: + return "Alt Storage"; + case invtype::InvTypeArchived: + return "Archived"; + case invtype::InvTypeOther: + return "Other"; + default: + return "Unknown Type"; + } +} + +bool UF::invtype::IsInvTypePersistent(int inv_type) +{ + switch (inv_type) { + case invtype::InvTypePossessions: + case invtype::InvTypeBank: + case invtype::InvTypeSharedBank: + case invtype::InvTypeTrade: + case invtype::InvTypeWorld: + case invtype::InvTypeLimbo: + case invtype::InvTypeTribute: + case invtype::InvTypeGuildTribute: + return true; + default: + return false; + } +} + +const char* UF::invslot::GetInvPossessionsSlotName(int inv_slot) +{ + switch (inv_slot) { + case invslot::InvSlotInvalid: + return "Invalid Slot"; + case invslot::PossessionsCharm: + return "Charm"; + case invslot::PossessionsEar1: + return "Ear 1"; + case invslot::PossessionsHead: + return "Head"; + case invslot::PossessionsFace: + return "Face"; + case invslot::PossessionsEar2: + return "Ear 2"; + case invslot::PossessionsNeck: + return "Neck"; + case invslot::PossessionsShoulders: + return "Shoulders"; + case invslot::PossessionsArms: + return "Arms"; + case invslot::PossessionsBack: + return "Back"; + case invslot::PossessionsWrist1: + return "Wrist 1"; + case invslot::PossessionsWrist2: + return "Wrist 2"; + case invslot::PossessionsRange: + return "Range"; + case invslot::PossessionsHands: + return "Hands"; + case invslot::PossessionsPrimary: + return "Primary"; + case invslot::PossessionsSecondary: + return "Secondary"; + case invslot::PossessionsFinger1: + return "Finger 1"; + case invslot::PossessionsFinger2: + return "Finger 2"; + case invslot::PossessionsChest: + return "Chest"; + case invslot::PossessionsLegs: + return "Legs"; + case invslot::PossessionsFeet: + return "Feet"; + case invslot::PossessionsWaist: + return "Waist"; + case invslot::PossessionsPowerSource: + return "Power Source"; + case invslot::PossessionsAmmo: + return "Ammo"; + case invslot::PossessionsGeneral1: + return "General 1"; + case invslot::PossessionsGeneral2: + return "General 2"; + case invslot::PossessionsGeneral3: + return "General 3"; + case invslot::PossessionsGeneral4: + return "General 4"; + case invslot::PossessionsGeneral5: + return "General 5"; + case invslot::PossessionsGeneral6: + return "General 6"; + case invslot::PossessionsGeneral7: + return "General 7"; + case invslot::PossessionsGeneral8: + return "General 8"; + case invslot::PossessionsCursor: + return "Cursor"; + default: + return "Unknown Slot"; + } +} + +const char* UF::invslot::GetInvCorpseSlotName(int inv_slot) +{ + if (!invtype::GetInvTypeSize(invtype::InvTypeCorpse) || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + // needs work + if ((size_t)(inv_slot + 1) < invslot::CorpseBegin || (size_t)(inv_slot + 1) >= invslot::CorpseEnd) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* UF::invslot::GetInvSlotName(int inv_type, int inv_slot) +{ + if (inv_type == invtype::InvTypePossessions) + return invslot::GetInvPossessionsSlotName(inv_slot); + else if (inv_type == invtype::InvTypeCorpse) + return invslot::GetInvCorpseSlotName(inv_slot); + + size_t type_size = invtype::GetInvTypeSize(inv_type); + + if (!type_size || inv_slot == invslot::InvSlotInvalid) + return "Invalid Slot"; + + if ((size_t)(inv_slot + 1) >= type_size) + return "Unknown Slot"; + + static std::string ret_str; + ret_str = StringFormat("Slot %i", (inv_slot + 1)); + + return ret_str.c_str(); +} + +const char* UF::invbag::GetInvBagIndexName(int bag_index) +{ + if (bag_index == invbag::InvBagInvalid) + return "Invalid Bag"; + + if ((size_t)bag_index >= invbag::ItemBagSize) + return "Unknown Bag"; + + static std::string ret_str; + ret_str = StringFormat("Bag %i", (bag_index + 1)); + + return ret_str.c_str(); +} + +const char* UF::invaug::GetInvAugIndexName(int aug_index) +{ + if (aug_index == invaug::InvAugInvalid) + return "Invalid Augment"; + + if ((size_t)aug_index >= invaug::ItemAugSize) + return "Unknown Augment"; + + static std::string ret_str; + ret_str = StringFormat("Augment %i", (aug_index + 1)); + + return ret_str.c_str(); +} diff --git a/common/patches/uf_limits.h b/common/patches/uf_limits.h new file mode 100644 index 000000000..2e799ac0c --- /dev/null +++ b/common/patches/uf_limits.h @@ -0,0 +1,313 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_UF_LIMITS_H +#define COMMON_UF_LIMITS_H + +#include "../types.h" +#include "../emu_versions.h" +#include "../skills.h" + + +namespace UF +{ + enum : int { Invalid = -1, Null, Safety }; + + enum : bool { False = false, True = true }; + + // pre-declarations + namespace inventory { + inline EQEmu::versions::ClientVersion GetInventoryRef() { return EQEmu::versions::ClientVersion::UF; } + + } /*inventory*/ + + namespace invtype { + inline EQEmu::versions::ClientVersion GetInvTypeRef() { return EQEmu::versions::ClientVersion::UF; } + + enum : int { InvTypeInvalid = -1, InvTypeBegin }; + + enum InventoryType : int { + InvTypePossessions = InvTypeBegin, + InvTypeBank, + InvTypeSharedBank, + InvTypeTrade, + InvTypeWorld, + InvTypeLimbo, + InvTypeTribute, + InvTypeGuildTribute, + InvTypeMerchant, + InvTypeCorpse, + InvTypeBazaar, + InvTypeInspect, + InvTypeViewMODPC, + InvTypeViewMODBank, + InvTypeViewMODSharedBank, + InvTypeViewMODLimbo, + InvTypeAltStorage, + InvTypeArchived, + InvTypeOther, + InvTypeCount + }; + + } /*invtype*/ + + namespace invslot { + inline EQEmu::versions::ClientVersion GetInvSlotRef() { return EQEmu::versions::ClientVersion::UF; } + + enum : int { InvSlotInvalid = -1, InvSlotBegin }; + + enum PossessionsSlot : int { + PossessionsCharm = InvSlotBegin, + PossessionsEar1, + PossessionsHead, + PossessionsFace, + PossessionsEar2, + PossessionsNeck, + PossessionsShoulders, + PossessionsArms, + PossessionsBack, + PossessionsWrist1, + PossessionsWrist2, + PossessionsRange, + PossessionsHands, + PossessionsPrimary, + PossessionsSecondary, + PossessionsFinger1, + PossessionsFinger2, + PossessionsChest, + PossessionsLegs, + PossessionsFeet, + PossessionsWaist, + PossessionsPowerSource, + PossessionsAmmo, + PossessionsGeneral1, + PossessionsGeneral2, + PossessionsGeneral3, + PossessionsGeneral4, + PossessionsGeneral5, + PossessionsGeneral6, + PossessionsGeneral7, + PossessionsGeneral8, + PossessionsCursor, + PossessionsCount + }; + + const int EquipmentBegin = PossessionsCharm; + const int EquipmentEnd = PossessionsAmmo; + const int EquipmentCount = (EquipmentEnd - EquipmentBegin + 1); + + const int GeneralBegin = PossessionsGeneral1; + const int GeneralEnd = PossessionsGeneral8; + const int GeneralCount = (GeneralEnd - GeneralBegin + 1); + + } /*invslot*/ + + namespace invbag { + inline EQEmu::versions::ClientVersion GetInvBagRef() { return EQEmu::versions::ClientVersion::UF; } + + enum : int { InvBagInvalid = -1, InvBagBegin }; + + } /*invbag*/ + + namespace invaug { + inline EQEmu::versions::ClientVersion GetInvAugRef() { return EQEmu::versions::ClientVersion::UF; } + + enum : int { InvAugInvalid = -1, InvAugBegin }; + + } /*invaug*/ + + namespace item { + inline EQEmu::versions::ClientVersion GetItemRef() { return EQEmu::versions::ClientVersion::UF; } + + enum ItemPacketType : int { + ItemPacketMerchant = 100, + ItemPacketTradeView = 101, + ItemPacketLoot = 102, + ItemPacketTrade = 103, + ItemPacketCharInventory = 105, + ItemPacketLimbo = 106, + ItemPacketWorldContainer = 107, + ItemPacketTributeItem = 108, + ItemPacketGuildTribute = 109, + ItemPacketCharmUpdate = 110, + ItemPacket11 = 111 + }; + + } /*item*/ + + namespace profile { + inline EQEmu::versions::ClientVersion GetProfileRef() { return EQEmu::versions::ClientVersion::UF; } + + } /*profile*/ + + namespace constants { + inline EQEmu::versions::ClientVersion GetConstantsRef() { return EQEmu::versions::ClientVersion::UF; } + + } /*constants*/ + + namespace behavior { + inline EQEmu::versions::ClientVersion GetBehaviorRef() { return EQEmu::versions::ClientVersion::UF; } + + } /*behavior*/ + + namespace skills { + inline EQEmu::versions::ClientVersion GetSkillsRef() { return EQEmu::versions::ClientVersion::UF; } + + } /*skills*/ + + + // declarations + namespace inventory { + const bool ConcatenateInvTypeLimbo = true; + + const bool AllowOverLevelEquipment = true; + + const bool AllowEmptyBagInBag = false; + const bool AllowClickCastFromBag = false; + + } /*inventory*/ + + namespace invtype { + const size_t InvTypePossessionsSize = invslot::PossessionsCount; + const size_t InvTypeBankSize = 24; + const size_t InvTypeSharedBankSize = 2; + const size_t InvTypeTradeSize = 8; + const size_t InvTypeWorldSize = 10; + const size_t InvTypeLimboSize = 36; + const size_t InvTypeTributeSize = 5; + const size_t InvTypeGuildTributeSize = 2; + const size_t InvTypeMerchantSize = 80; + const size_t InvTypeCorpseSize = InvTypePossessionsSize; + const size_t InvTypeBazaarSize = 80; + const size_t InvTypeInspectSize = invslot::EquipmentCount; + const size_t InvTypeViewMODPCSize = InvTypePossessionsSize; + const size_t InvTypeViewMODBankSize = InvTypeBankSize; + const size_t InvTypeViewMODSharedBankSize = InvTypeSharedBankSize; + const size_t InvTypeViewMODLimboSize = InvTypeLimboSize; + const size_t InvTypeAltStorageSize = 0;//unknown - "Shroud Bank" + const size_t InvTypeArchivedSize = 0;//unknown + const size_t InvTypeOtherSize = 0;//unknown + + extern size_t GetInvTypeSize(int inv_type); + extern const char* GetInvTypeName(int inv_type); + + extern bool IsInvTypePersistent(int inv_type); + + } /*invtype*/ + + namespace invslot { + const int BankBegin = 2000; + const int BankEnd = (BankBegin + invtype::InvTypeBankSize) - 1; + + const int SharedBankBegin = 2500; + const int SharedBankEnd = (SharedBankBegin + invtype::InvTypeSharedBankSize) - 1; + + const int TradeBegin = 3000; + const int TradeEnd = (TradeBegin + invtype::InvTypeTradeSize) - 1; + const int TradeNPCEnd = 3003; + + const int WorldBegin = 4000; + const int WorldEnd = (WorldBegin + invtype::InvTypeWorldSize) - 1; + + const int TributeBegin = 400; + const int TributeEnd = (TributeBegin + invtype::InvTypeTributeSize) - 1; + + const int GuildTributeBegin = 450; + const int GuildTributeEnd = (GuildTributeBegin + invtype::InvTypeGuildTributeSize) - 1; + + const int CorpseBegin = invslot::PossessionsGeneral1; + const int CorpseEnd = invslot::PossessionsGeneral1 + invslot::PossessionsCursor; + + extern const char* GetInvPossessionsSlotName(int inv_slot); + extern const char* GetInvCorpseSlotName(int inv_slot); + extern const char* GetInvSlotName(int inv_type, int inv_slot); + + } /*invslot*/ + + namespace invbag { + const size_t ItemBagSize = 10; + + const int GeneralBagsBegin = 262; + const int GeneralBagsSize = invslot::GeneralCount * ItemBagSize; + const int GeneralBagsEnd = (GeneralBagsBegin + GeneralBagsSize) - 1; + + const int CursorBagBegin = 342; + const int CursorBagSize = ItemBagSize; + const int CursorBagEnd = (CursorBagBegin + CursorBagSize) - 1; + + const int BankBagsBegin = 2032; + const int BankBagsSize = (invtype::InvTypeBankSize * ItemBagSize); + const int BankBagsEnd = (BankBagsBegin + BankBagsSize) - 1; + + const int SharedBankBagsBegin = 2532; + const int SharedBankBagsSize = invtype::InvTypeSharedBankSize * ItemBagSize; + const int SharedBankBagsEnd = (SharedBankBagsBegin + SharedBankBagsSize) - 1; + + const int TradeBagsBegin = 3031; + const int TradeBagsSize = invtype::InvTypeTradeSize * ItemBagSize; + const int TradeBagsEnd = (TradeBagsBegin + TradeBagsSize) - 1; + + extern const char* GetInvBagIndexName(int bag_index); + + } /*invbag*/ + + namespace invaug { + const size_t ItemAugSize = 5; + + extern const char* GetInvAugIndexName(int aug_index); + + } /*invaug*/ + + namespace item { + + } /*item*/ + + namespace profile { + const size_t TributeSize = invtype::InvTypeTributeSize; + const size_t GuildTributeSize = invtype::InvTypeGuildTributeSize; + + const size_t BandoliersSize = 20; // number of bandolier instances + const size_t BandolierItemCount = 4; // number of equipment slots in bandolier instance + + const size_t PotionBeltSize = 5; + + const size_t SkillArraySize = 100; + + } /*profile*/ + + namespace constants { + const size_t CharacterCreationLimit = 12; + + const size_t SayLinkBodySize = 50; + + } /*constants*/ + + namespace behavior { + const bool CoinHasWeight = false; + + } /*behavior*/ + + namespace skills { + const size_t LastUsableSkill = EQEmu::skills::SkillTripleAttack; + + } /*skills*/ + +}; /*UF*/ + +#endif /*COMMON_UF_LIMITS_H*/ diff --git a/common/patches/uf_ops.h b/common/patches/uf_ops.h index 7f5f500c5..2287f0cd1 100644 --- a/common/patches/uf_ops.h +++ b/common/patches/uf_ops.h @@ -1,3 +1,23 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + // out-going packets that require an ENCODE translation: E(OP_Action) E(OP_AdventureMerchantSell) diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index d7b14b385..46e5b21cb 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -1,11 +1,32 @@ -#ifndef UF_STRUCTS_H_ -#define UF_STRUCTS_H_ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) -namespace UF { + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_UF_STRUCTS_H +#define COMMON_UF_STRUCTS_H + + +namespace UF +{ namespace structs { -static const uint32 BUFF_COUNT = 25; +static const uint32 BUFF_COUNT = 30; /* ** Compiler override to ensure @@ -101,27 +122,70 @@ struct AdventureInfo { ** Merth: Gave struct a name so gcc 2.96 would compile ** */ -struct Color_Struct +struct Tint_Struct { union { struct { - uint8 blue; + uint8 Blue; uint8 Green; uint8 Red; uint8 UseTint; // if there's a tint this is FF - } RGB; + }; uint32 Color; }; }; -struct CharSelectEquip +struct TintProfile +{ + union { + struct { + Tint_Struct Head; + Tint_Struct Chest; + Tint_Struct Arms; + Tint_Struct Wrist; + Tint_Struct Hands; + Tint_Struct Legs; + Tint_Struct Feet; + Tint_Struct Primary; + Tint_Struct Secondary; + }; + Tint_Struct Slot[EQEmu::textures::TextureCount]; + }; +}; + +/* +* Visible equiptment. +* Size: 12 Octets +*/ +struct Texture_Struct { uint32 Material; uint32 Unknown1; uint32 EliteMaterial; - Color_Struct Color; }; +struct TextureProfile +{ + union { + struct { + Texture_Struct Head; + Texture_Struct Chest; + Texture_Struct Arms; + Texture_Struct Wrist; + Texture_Struct Hands; + Texture_Struct Legs; + Texture_Struct Feet; + Texture_Struct Primary; + Texture_Struct Secondary; + }; + Texture_Struct Slot[EQEmu::textures::TextureCount]; + }; + + TextureProfile(); +}; + +struct CharSelectEquip : Texture_Struct, Tint_Struct {}; + struct CharacterSelectEntry_Struct { /*0000*/ uint8 Level; // @@ -131,7 +195,7 @@ struct CharacterSelectEntry_Struct /*0000*/ uint8 Beard; // /*0001*/ uint8 HairColor; // /*0000*/ uint8 Face; // -/*0000*/ CharSelectEquip Equip[9]; +/*0000*/ CharSelectEquip Equip[EQEmu::textures::TextureCount]; /*0000*/ uint32 PrimaryIDFile; // /*0000*/ uint32 SecondaryIDFile; // /*0000*/ uint8 Unknown15; // 0xff @@ -164,19 +228,6 @@ struct CharacterSelect_Struct /*0008*/ CharacterSelectEntry_Struct Entries[0]; }; -/* -* Visible equiptment. -* Size: 12 Octets -*/ -struct EquipStruct -{ -/*00*/ uint32 Material; -/*04*/ uint32 Unknown1; -/*08*/ uint32 EliteMaterial; -/*12*/ -}; - - /* ** Generic Spawn Struct ** Length: 897 Octets @@ -286,47 +337,17 @@ struct Spawn_Struct /*0000*/ uint8 unknown12; /*0000*/ uint32 petOwnerId; /*0000*/ uint8 unknown13; -/*0000*/ uint32 unknown14; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed +/*0000*/ uint32 PlayerState; // Stance 64 = normal 4 = aggressive 40 = stun/mezzed /*0000*/ uint32 unknown15; /*0000*/ uint32 unknown16; /*0000*/ uint32 unknown17; /*0000*/ uint32 unknown18; /*0000*/ uint32 unknown19; Spawn_Struct_Position Position; -/*0000*/ union - { - struct - { - /*0000*/ Color_Struct color_helmet; // Color of helmet item - /*0000*/ Color_Struct color_chest; // Color of chest item - /*0000*/ Color_Struct color_arms; // Color of arms item - /*0000*/ Color_Struct color_bracers; // Color of bracers item - /*0000*/ Color_Struct color_hands; // Color of hands item - /*0000*/ Color_Struct color_legs; // Color of legs item - /*0000*/ Color_Struct color_feet; // Color of feet item - /*0000*/ Color_Struct color_primary; // Color of primary item - /*0000*/ Color_Struct color_secondary; // Color of secondary item - } equipment_colors; - /*0000*/ Color_Struct colors[9]; // Array elements correspond to struct equipment_colors above - }; +/*0000*/ TintProfile equipment_tint; // skip these bytes if not a valid player race -/*0000*/ union - { - struct - { - /*0000*/ EquipStruct equip_helmet; // Equiptment: Helmet visual - /*0000*/ EquipStruct equip_chest; // Equiptment: Chest visual - /*0000*/ EquipStruct equip_arms; // Equiptment: Arms visual - /*0000*/ EquipStruct equip_bracers; // Equiptment: Wrist visual - /*0000*/ EquipStruct equip_hands; // Equiptment: Hands visual - /*0000*/ EquipStruct equip_legs; // Equiptment: Legs visual - /*0000*/ EquipStruct equip_feet; // Equiptment: Boots visual - /*0000*/ EquipStruct equip_primary; // Equiptment: Main visual - /*0000*/ EquipStruct equip_secondary; // Equiptment: Off visual - } equip; - /*0000*/ EquipStruct equipment[9]; - }; +/*0000*/ TextureProfile equipment; /*0000*/ //char title[0]; // only read if(hasTitleOrSuffix & 4) /*0000*/ //char suffix[0]; // only read if(hasTitleOrSuffix & 8) @@ -458,7 +479,7 @@ struct MemorizeSpell_Struct { uint32 slot; // Spot in the spell book/memorized slot uint32 spell_id; // Spell id (200 or c8 is minor healing, etc) uint32 scribing; // 1 if memorizing a spell, set to 0 if scribing to book, 2 if un-memming -//uint32 unknown12; +uint32 reduction; // lowers reuse }; /* @@ -491,11 +512,12 @@ struct DeleteSpell_Struct struct ManaChange_Struct { - uint32 new_mana; // New Mana AMount - uint32 stamina; - uint32 spell_id; - uint32 unknown12; - uint32 unknown16; +/*00*/ uint32 new_mana; // New Mana AMount +/*04*/ uint32 stamina; +/*08*/ uint32 spell_id; +/*12*/ uint8 keepcasting; // won't stop the cast. Change mana while casting? +/*13*/ uint8 padding[3]; // client doesn't read it, garbage data seems like +/*16*/ int32 slot; // -1 for normal usage slot for when we want silent interrupt? I think it does timer stuff or something. Linked Spell Reuse interrupt uses it }; struct SwapSpell_Struct @@ -545,55 +567,28 @@ struct SpawnAppearance_Struct // Size 76 (was 24) struct SpellBuff_Struct { -/*000*/ uint8 slotid; // badly named... seems to be 2 for a real buff, 0 otherwise -/*001*/ uint8 level; -/*002*/ uint8 bard_modifier; -/*003*/ uint8 effect; // not real -/*004*/ uint32 unknown004; // Seen 1 for no buff -/*008*/ uint32 spellid; +/*000*/ uint8 effect_type; // 0 = no buff, 2 = buff, 4 = inverse affects of buff +/*001*/ uint8 level; // Seen 1 for no buff +/*002*/ uint8 unknown002; //pretty sure padding now +/*003*/ uint8 unknown003; // MQ2 used to call this "damage shield" -- don't see client referencing it, so maybe server side DS type tracking? +/*004*/ float bard_modifier; +/*008*/ uint32 spellid; /*012*/ uint32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 player_id; // 'global' ID of the caster, for wearoff messages -/*024*/ uint32 counters; -/*028*/ uint8 unknown0028[48]; -/*076*/ +/*016*/ uint32 num_hits; +/*020*/ uint32 player_id; // caster ID, pretty sure just zone ID +/*024*/ uint32 unknown036; +/*028*/ int32 slot_data[12]; // book keeping stuff per slot (counters, rune/vie) }; // Not functional yet, but this is what the packet looks like on Underfoot -struct SpellBuffFade_Struct_Underfoot { +struct SpellBuffPacket_Struct { /*000*/ uint32 entityid; // Player id who cast the buff -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ float unknown008; -/*012*/ uint32 spellid; -/*016*/ uint32 duration; -/*020*/ uint32 num_hits; -/*024*/ uint32 playerId; // Global player ID? -/*028*/ uint32 unknown020; -/*032*/ uint8 unknown0028[48]; +/*004*/ SpellBuff_Struct buff; /*080*/ uint32 slotid; /*084*/ uint32 bufffade; /*088*/ }; -struct SpellBuffFade_Struct { -/*000*/ uint32 entityid; -/*004*/ uint8 slot; -/*005*/ uint8 level; -/*006*/ uint8 effect; -/*007*/ uint8 unknown7; -/*008*/ uint32 spellid; -/*012*/ uint32 duration; -/*016*/ uint32 unknown016; -/*020*/ uint32 unknown020; // Global player ID? -/*024*/ uint32 playerId; // Player id who cast the buff -/*028*/ uint32 slotid; -/*032*/ uint32 bufffade; -/*036*/ -}; - #if 0 struct BuffIconEntry_Struct { /*000*/ uint32 buff_slot; @@ -713,7 +708,7 @@ struct AA_Array { uint32 AA; uint32 value; - uint32 unknown08; // Looks like AA_Array is now 12 bytes in Underfoot + uint32 charges; // expendable }; @@ -752,7 +747,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; + BandolierItem_Struct Items[profile::BandolierItemCount]; }; //len = 72 @@ -766,7 +761,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; + PotionBeltItem_Struct Items[profile::PotionBeltSize]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -931,24 +926,9 @@ struct PlayerProfile_Struct /*00230*/ uint8 hairstyle; // Player hair style /*00231*/ uint8 beard; // Player beard type /*00232*/ uint8 unknown00232[4]; // was 14 -/*00236*/ union - { - struct - { - /*00236*/ EquipStruct equip_helmet; // Equiptment: Helmet visual - /*00248*/ EquipStruct equip_chest; // Equiptment: Chest visual - /*00260*/ EquipStruct equip_arms; // Equiptment: Arms visual - /*00272*/ EquipStruct equip_bracers; // Equiptment: Wrist visual - /*00284*/ EquipStruct equip_hands; // Equiptment: Hands visual - /*00296*/ EquipStruct equip_legs; // Equiptment: Legs visual - /*00308*/ EquipStruct equip_feet; // Equiptment: Boots visual - /*00320*/ EquipStruct equip_primary; // Equiptment: Main visual - /*00332*/ EquipStruct equip_secondary; // Equiptment: Off visual - } equip; - /*00236*/ EquipStruct equipment[9]; //Underfoot Shows [108] for this part - }; +/*00236*/ TextureProfile equipment; /*00344*/ uint8 unknown00344[168]; // Underfoot Shows [160] -/*00512*/ Color_Struct item_tint[9]; // RR GG BB 00 +/*00512*/ TintProfile item_tint; // RR GG BB 00 /*00548*/ AA_Array aa_array[MAX_PP_AA_ARRAY]; // [3600] AAs 12 bytes each /*04148*/ uint32 points; // Unspent Practice points - RELOCATED??? /*04152*/ uint32 mana; // Current mana @@ -979,8 +959,7 @@ struct PlayerProfile_Struct /*07880*/ uint32 toxicity; // Potion Toxicity (15=too toxic, each potion adds 3) /*07884*/ uint32 thirst_level; // Drink (ticks till next drink) /*07888*/ uint32 hunger_level; // Food (ticks till next eat) -/*07892*/ SpellBuff_Struct buffs[BUFF_COUNT]; // [1900] Buffs currently on the player (30 Max) - (Each Size 76) -/*09792*/ uint8 unknown09792[380]; // BUFF_COUNT has been left at 25. These are the extra 5 buffs in Underfoot +/*07892*/ SpellBuff_Struct buffs[BUFF_COUNT]; // [2280] Buffs currently on the player (30 Max) - (Each Size 76) /*10172*/ Disciplines_Struct disciplines; // [400] Known disciplines /*10972*/ uint32 recastTimers[MAX_RECAST_TYPES]; // Timers (UNIX Time of last use) /*11052*/ uint8 unknown11052[160]; // Some type of Timers @@ -989,7 +968,7 @@ struct PlayerProfile_Struct /*11236*/ uint32 aapoints_spent; // Number of spent AA points /*11240*/ uint32 aapoints; // Unspent AA points /*11244*/ uint8 unknown11244[4]; -/*11248*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [6400] bandolier contents +/*11248*/ Bandolier_Struct bandoliers[profile::BandoliersSize]; // [6400] bandolier contents /*17648*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot /*18008*/ uint8 unknown18008[8]; /*18016*/ uint32 available_slots; @@ -1146,7 +1125,7 @@ struct TargetReject_Struct { struct PetCommand_Struct { /*000*/ uint32 command; -/*004*/ uint32 unknown; +/*004*/ uint32 target; }; /* @@ -1211,7 +1190,7 @@ struct WearChange_Struct{ /*002*/ uint32 material; /*006*/ uint32 unknown06; /*010*/ uint32 elite_material; // 1 for Drakkin Elite Material -/*014*/ Color_Struct color; +/*014*/ Tint_Struct color; /*018*/ uint8 wear_slot_id; /*019*/ }; @@ -1260,8 +1239,8 @@ struct RequestClientZoneChange_Struct { struct Animation_Struct { /*00*/ uint16 spawnid; -/*02*/ uint8 action; -/*03*/ uint8 value; +/*02*/ uint8 speed; +/*03*/ uint8 action; /*04*/ }; @@ -1330,9 +1309,11 @@ struct CombatDamage_Struct /* 04 */ uint8 type; //slashing, etc. 231 (0xE7) for spells /* 05 */ uint16 spellid; /* 07 */ int32 damage; -/* 11 */ float unknown11; // cd cc cc 3d -/* 15 */ float sequence; // see above notes in Action_Struct -/* 19 */ uint8 unknown19[9]; // was [9] +/* 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] +/* 24 */ uint32 special; // 2 = Rampage, 1 = Wild Rampage /* 28 */ }; @@ -2031,7 +2012,7 @@ struct AdventureLeaderboard_Struct /*struct Item_Shop_Struct { uint16 merchantid; uint8 itemtype; - Item_Struct item; + ItemBase item; uint8 iss_unknown001[6]; };*/ @@ -2186,9 +2167,7 @@ struct GroupFollow_Struct { // Underfoot Follow Struct struct InspectBuffs_Struct { /*000*/ uint32 spell_id[BUFF_COUNT]; -/*100*/ uint32 filler100[5]; // BUFF_COUNT is really 30... -/*120*/ uint32 tics_remaining[BUFF_COUNT]; -/*220*/ uint32 filler220[5]; // BUFF_COUNT is really 30... +/*120*/ int32 tics_remaining[BUFF_COUNT]; }; @@ -2448,7 +2427,8 @@ struct Object_Struct { /*20*/ uint32 unknown020; // 00 00 00 00 /*24*/ uint32 unknown024; // 53 9e f9 7e - same for all objects in the zone? /*40*/ float heading; // heading -/*32*/ uint8 unknown032[8]; // 00 00 00 00 00 00 00 00 +/*00*/ float x_tilt; //Tilt entire object on X axis +/*00*/ float y_tilt; //Tilt entire object on Y axis /*28*/ float size; // Size - default 1 /*44*/ float z; // z coord /*48*/ float x; // x coord @@ -3138,27 +3118,6 @@ struct PetitionBug_Struct{ char text[1028]; }; -struct DyeStruct -{ - union - { - struct - { - struct Color_Struct head; - struct Color_Struct chest; - struct Color_Struct arms; - struct Color_Struct wrists; - struct Color_Struct hands; - struct Color_Struct legs; - struct Color_Struct feet; - struct Color_Struct primary; // you can't actually dye this - struct Color_Struct secondary; // or this - } - dyes; - struct Color_Struct dye[9]; - }; -}; - struct ApproveZone_Struct { char name[64]; uint32 zoneid; @@ -3885,16 +3844,21 @@ struct SendAA_Struct { /*0049*/ uint32 spellid; /*0053*/ uint32 spell_type; /*0057*/ uint32 spell_refresh; -/*0061*/ uint16 classes; -/*0063*/ uint16 berserker; //seems to be 1 if its a berserker ability +/*0061*/ uint32 classes; /*0065*/ uint32 max_level; /*0069*/ uint32 last_id; /*0073*/ uint32 next_id; /*0077*/ uint32 cost2; -/*0081*/ uint8 unknown80[7]; +/*0081*/ uint8 unknown81; +/*0082*/ uint8 grant_only; // VetAAs, progression, etc +/*0083*/ uint8 unknown83; // 1 for skill cap increase AAs, Mystical Attuning, and RNG attack inc, doesn't seem to matter though +/*0084*/ uint32 expendable_charges; // max charges of the AA /*0088*/ uint32 aa_expansion; /*0092*/ uint32 special_category; -/*0096*/ uint32 unknown0096; +/*0096*/ uint8 shroud; +/*0097*/ uint8 unknown97; +/*0098*/ uint8 layonhands; // 1 for lay on hands -- doesn't seem to matter? +/*0099*/ uint8 unknown99; /*0100*/ uint32 total_abilities; /*0104*/ AA_Ability abilities[0]; }; @@ -3906,15 +3870,10 @@ struct AA_List { struct AA_Action { /*00*/ uint32 action; /*04*/ uint32 ability; -/*08*/ uint32 unknown08; +/*08*/ uint32 target_id; /*12*/ uint32 exp_value; }; -struct AA_Skills { //this should be removed and changed to AA_Array -/*00*/ uint32 aa_skill; // Total AAs Spent -/*04*/ uint32 aa_value; -/*08*/ uint32 unknown08; -}; struct AAExpUpdate_Struct { /*00*/ uint32 unknown00; //seems to be a value from AA_Action.ability @@ -3933,7 +3892,7 @@ struct AltAdvStats_Struct { }; struct PlayerAA_Struct { // Is this still used? - AA_Skills aa_list[MAX_PP_AA_ARRAY]; + AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct AATable_Struct { @@ -3943,7 +3902,7 @@ struct AATable_Struct { /*12*/ int32 unknown012; /*16*/ int32 unknown016; /*20*/ int32 unknown020; -/*24*/ AA_Skills aa_list[MAX_PP_AA_ARRAY]; +/*24*/ AA_Array aa_list[MAX_PP_AA_ARRAY]; }; struct Weather_Struct { @@ -4101,7 +4060,7 @@ struct ItemBodyStruct uint32 Races; uint32 Deity; int32 SkillModValue; - uint32 unknown5; + uint32 SkillModMax; uint32 SkillModType; uint32 BaneDmgRace; uint32 BaneDmgBody; @@ -4204,7 +4163,7 @@ struct ClickEffectStruct struct ProcEffectStruct { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4219,7 +4178,7 @@ struct ProcEffectStruct struct WornEffectStruct //worn, focus and scroll effect { - uint32 effect; + int32 effect; uint8 level2; uint32 type; uint8 level; @@ -4278,14 +4237,13 @@ struct ItemQuaternaryBodyStruct int32 HeroicSVCorrup; int32 HealAmt; int32 SpellDmg; - int32 clairvoyance; + int32 Clairvoyance; uint8 unknown18; //Power Source Capacity or evolve filename? uint32 evolve_string; // Some String, but being evolution related is just a guess uint8 unknown19; uint32 unknown20; // Bard Stuff? uint32 unknown21; uint32 unknown22; - uint32 subitem_count; }; struct AugmentInfo_Struct @@ -4550,7 +4508,8 @@ struct MercenaryAssign_Struct { /*0012*/ }; - }; //end namespace structs -}; //end namespace UF + }; /*structs*/ -#endif /*UF_STRUCTS_H_*/ +}; /*UF*/ + +#endif /*COMMON_UF_STRUCTS_H*/ diff --git a/common/proc_launcher.cpp b/common/proc_launcher.cpp index d44cc9c46..b59f4e852 100644 --- a/common/proc_launcher.cpp +++ b/common/proc_launcher.cpp @@ -212,7 +212,7 @@ ProcLauncher::ProcRef ProcLauncher::Launch(Spec *&to_launch) { #else //!WIN32 //build argv - char **argv = new char *[it->args.size()+2]; + auto argv = new char *[it->args.size() + 2]; unsigned int r; argv[0] = const_cast(it->program.c_str()); for(r = 1; r <= it->args.size(); r++) { @@ -276,7 +276,7 @@ ProcLauncher::ProcRef ProcLauncher::Launch(Spec *&to_launch) { //if graceful is true, we try to be nice about it if possible bool ProcLauncher::Terminate(const ProcRef &proc, bool graceful) { //we are only willing to kill things we started... - std::map::iterator res = m_running.find(proc); + auto res = m_running.find(proc); if(res == m_running.end()) return(false); diff --git a/common/ptimer.cpp b/common/ptimer.cpp index c7f7b9046..273ac54d0 100644 --- a/common/ptimer.cpp +++ b/common/ptimer.cpp @@ -24,8 +24,8 @@ #include "string_util.h" #ifdef _WINDOWS + #include #include - #include int gettimeofday (timeval *tp, ...); #else #include diff --git a/common/ptimer.h b/common/ptimer.h index d12b6779d..d7398bea3 100644 --- a/common/ptimer.h +++ b/common/ptimer.h @@ -37,9 +37,12 @@ enum { //values for pTimerType pTimerSenseTraps = 12, pTimerDisarmTraps = 13, pTimerDisciplineReuseStart = 14, - pTimerDisciplineReuseEnd = 24, + pTimerDisciplineReuseEnd = 24, // client actually has 20 ids, but still no disc go that high even on live pTimerCombatAbility = 25, - pTimerBeggingPickPocket = 26, + pTimerCombatAbility2 = 26, // RoF2+ Tiger Claw is unlinked from other monk skills, generic in case other classes ever need it + pTimerBeggingPickPocket = 27, + pTimerLinkedSpellReuseStart = 28, + pTimerLinkedSpellReuseEnd = 48, pTimerLayHands = 87, //these IDs are used by client too pTimerHarmTouch = 89, //so dont change them @@ -138,8 +141,4 @@ protected: std::map _list; }; -//code prettying macros -#define AA_Choose3(val, v1, v2, v3) (val==1?v1:(val==2?v2:v3)) -#define AA_Choose5(val, v1, v2, v3, v4, v5) (val==1?v1:(val==2?v2:(val==3?v3:(val==4?v4:v5)))) - #endif diff --git a/common/races.cpp b/common/races.cpp index 6322b50af..7fd88911b 100644 --- a/common/races.cpp +++ b/common/races.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,95 +18,831 @@ #include "../common/races.h" -const char* GetRaceName(uint16 race) { - switch(race) { - case HUMAN: - return "Human"; - case BARBARIAN: - return "Barbarian"; - case ERUDITE: - return "Erudite"; - case WOOD_ELF: - return "Wood Elf"; - case HIGH_ELF: - return "High Elf"; - case DARK_ELF: - return "Dark Elf"; - case HALF_ELF: - return "Half Elf"; - case DWARF: - return "Dwarf"; - case TROLL: - return "Troll"; - case OGRE: - return "Ogre"; - case HALFLING: - return "Halfling"; - case GNOME: - return "Gnome"; - case IKSAR: - return "Iksar"; - case WEREWOLF: - return "Werewolf"; - case SKELETON: - return "Skeleton"; - case ELEMENTAL: - return "Elemental"; - case EYE_OF_ZOMM: - return "Eye of Zomm"; - case WOLF_ELEMENTAL: - return "Wolf Elemental"; - case IKSAR_SKELETON: - return "Iksar Skeleton"; - case VAHSHIR: - return "Vah Shir"; - case FROGLOK: - case FROGLOK2: - return "Froglok"; - case DRAKKIN: - return "Drakkin"; - default: - return "Unknown"; +const char* GetRaceIDName(uint16 race_id) +{ + switch (race_id) { + case HUMAN: + return "Human"; + case BARBARIAN: + return "Barbarian"; + case ERUDITE: + return "Erudite"; + case WOOD_ELF: + return "Wood Elf"; + case HIGH_ELF: + return "High Elf"; + case DARK_ELF: + return "Dark Elf"; + case HALF_ELF: + return "Half Elf"; + case DWARF: + return "Dwarf"; + case TROLL: + return "Troll"; + case OGRE: + return "Ogre"; + case HALFLING: + return "Halfling"; + case GNOME: + return "Gnome"; + case IKSAR: + return "Iksar"; + case WEREWOLF: + return "Werewolf"; + case SKELETON: + return "Skeleton"; + case ELEMENTAL: + return "Elemental"; + case EYE_OF_ZOMM: + return "Eye of Zomm"; + case WOLF_ELEMENTAL: + return "Wolf Elemental"; + case IKSAR_SKELETON: + return "Iksar Skeleton"; + case VAHSHIR: + return "Vah Shir"; + case FROGLOK: + case FROGLOK2: + return "Froglok"; + case DRAKKIN: + return "Drakkin"; + default: + return "Unknown"; } } -uint32 GetArrayRace(uint16 race) { - switch(race) { - case HUMAN: - return Array_Race_HUMAN; - case BARBARIAN: - return Array_Race_BARBARIAN; - case ERUDITE: - return Array_Race_ERUDITE; - case WOOD_ELF: - return Array_Race_WOOD_ELF; - case HIGH_ELF: - return Array_Race_HIGH_ELF; - case DARK_ELF: - return Array_Race_DARK_ELF; - case HALF_ELF: - return Array_Race_HALF_ELF; - case DWARF: - return Array_Race_DWARF; - case TROLL: - return Array_Race_TROLL; - case OGRE: - return Array_Race_OGRE; - case HALFLING: - return Array_Race_HALFLING; - case GNOME: - return Array_Race_GNOME; - case IKSAR: - return Array_Race_IKSAR; - case VAHSHIR: - return Array_Race_VAHSHIR; - case FROGLOK: - case FROGLOK2: - return Array_Race_FROGLOK; - case DRAKKIN: - return Array_Race_DRAKKIN; - default: - return Array_Race_UNKNOWN; +const char* GetPlayerRaceName(uint32 player_race_value) +{ + return GetRaceIDName(GetRaceIDFromPlayerRaceValue(player_race_value)); +} + +uint32 GetPlayerRaceValue(uint16 race_id) +{ + switch (race_id) { + case HUMAN: + case BARBARIAN: + case ERUDITE: + case WOOD_ELF: + case HIGH_ELF: + case DARK_ELF: + case HALF_ELF: + case DWARF: + case TROLL: + case OGRE: + case HALFLING: + case GNOME: + return race_id; + case IKSAR: + return PLAYER_RACE_IKSAR; + case VAHSHIR: + return PLAYER_RACE_VAHSHIR; + case FROGLOK: + case FROGLOK2: + return PLAYER_RACE_FROGLOK; + case DRAKKIN: + return PLAYER_RACE_DRAKKIN; + default: + return PLAYER_RACE_UNKNOWN; // watch } } +uint32 GetPlayerRaceBit(uint16 race_id) +{ + switch (race_id) { + case HUMAN: + return PLAYER_RACE_HUMAN_BIT; + case BARBARIAN: + return PLAYER_RACE_BARBARIAN_BIT; + case ERUDITE: + return PLAYER_RACE_ERUDITE_BIT; + case WOOD_ELF: + return PLAYER_RACE_WOOD_ELF_BIT; + case HIGH_ELF: + return PLAYER_RACE_HIGH_ELF_BIT; + case DARK_ELF: + return PLAYER_RACE_DARK_ELF_BIT; + case HALF_ELF: + return PLAYER_RACE_HALF_ELF_BIT; + case DWARF: + return PLAYER_RACE_DWARF_BIT; + case TROLL: + return PLAYER_RACE_TROLL_BIT; + case OGRE: + return PLAYER_RACE_OGRE_BIT; + case HALFLING: + return PLAYER_RACE_HALFLING_BIT; + case GNOME: + return PLAYER_RACE_GNOME_BIT; + case IKSAR: + return PLAYER_RACE_IKSAR_BIT; + case VAHSHIR: + return PLAYER_RACE_VAHSHIR_BIT; + case FROGLOK: + return PLAYER_RACE_FROGLOK_BIT; + case DRAKKIN: + return PLAYER_RACE_DRAKKIN_BIT; + default: + return PLAYER_RACE_UNKNOWN_BIT; + } +} + +uint16 GetRaceIDFromPlayerRaceValue(uint32 player_race_value) +{ + switch (player_race_value) { + case PLAYER_RACE_HUMAN: + case PLAYER_RACE_BARBARIAN: + case PLAYER_RACE_ERUDITE: + case PLAYER_RACE_WOOD_ELF: + case PLAYER_RACE_HIGH_ELF: + case PLAYER_RACE_DARK_ELF: + case PLAYER_RACE_HALF_ELF: + case PLAYER_RACE_DWARF: + case PLAYER_RACE_TROLL: + case PLAYER_RACE_OGRE: + case PLAYER_RACE_HALFLING: + case PLAYER_RACE_GNOME: + return player_race_value; + case PLAYER_RACE_IKSAR: + return IKSAR; + case PLAYER_RACE_VAHSHIR: + return VAHSHIR; + case PLAYER_RACE_FROGLOK: + return FROGLOK; + case PLAYER_RACE_DRAKKIN: + return DRAKKIN; + default: + return PLAYER_RACE_UNKNOWN; // watch + } +} + +uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit) +{ + switch (player_race_bit) { + case PLAYER_RACE_HUMAN_BIT: + return HUMAN; + case PLAYER_RACE_BARBARIAN_BIT: + return BARBARIAN; + case PLAYER_RACE_ERUDITE_BIT: + return ERUDITE; + case PLAYER_RACE_WOOD_ELF_BIT: + return WOOD_ELF; + case PLAYER_RACE_HIGH_ELF_BIT: + return HIGH_ELF; + case PLAYER_RACE_DARK_ELF_BIT: + return DARK_ELF; + case PLAYER_RACE_HALF_ELF_BIT: + return HALF_ELF; + case PLAYER_RACE_DWARF_BIT: + return DWARF; + case PLAYER_RACE_TROLL_BIT: + return TROLL; + case PLAYER_RACE_OGRE_BIT: + return OGRE; + case PLAYER_RACE_HALFLING_BIT: + return HALFLING; + case PLAYER_RACE_GNOME_BIT: + return GNOME; + case PLAYER_RACE_IKSAR_BIT: + return IKSAR; + case PLAYER_RACE_VAHSHIR_BIT: + return VAHSHIR; + case PLAYER_RACE_FROGLOK_BIT: + return FROGLOK; + case PLAYER_RACE_DRAKKIN_BIT: + return DRAKKIN; + default: + return PLAYER_RACE_UNKNOWN; // watch + } +} + + +// PlayerAppearance prep +#define HUMAN_MALE ((HUMAN << 8) | MALE) +#define HUMAN_FEMALE ((HUMAN << 8) | FEMALE) +#define BARBARIAN_MALE ((BARBARIAN << 8) | MALE) +#define BARBARIAN_FEMALE ((BARBARIAN << 8) | FEMALE) +#define ERUDITE_MALE ((ERUDITE << 8) | MALE) +#define ERUDITE_FEMALE ((ERUDITE << 8) | FEMALE) +#define WOOD_ELF_MALE ((WOOD_ELF << 8) | MALE) +#define WOOD_ELF_FEMALE ((WOOD_ELF << 8) | FEMALE) +#define HIGH_ELF_MALE ((HIGH_ELF << 8) | MALE) +#define HIGH_ELF_FEMALE ((HIGH_ELF << 8) | FEMALE) +#define DARK_ELF_MALE ((DARK_ELF << 8) | MALE) +#define DARK_ELF_FEMALE ((DARK_ELF << 8) | FEMALE) +#define HALF_ELF_MALE ((HALF_ELF << 8) | MALE) +#define HALF_ELF_FEMALE ((HALF_ELF << 8) | FEMALE) +#define DWARF_MALE ((DWARF << 8) | MALE) +#define DWARF_FEMALE ((DWARF << 8) | FEMALE) +#define TROLL_MALE ((TROLL << 8) | MALE) +#define TROLL_FEMALE ((TROLL << 8) | FEMALE) +#define OGRE_MALE ((OGRE << 8) | MALE) +#define OGRE_FEMALE ((OGRE << 8) | FEMALE) +#define HALFLING_MALE ((HALFLING << 8) | MALE) +#define HALFLING_FEMALE ((HALFLING << 8) | FEMALE) +#define GNOME_MALE ((GNOME << 8) | MALE) +#define GNOME_FEMALE ((GNOME << 8) | FEMALE) +#define IKSAR_MALE ((IKSAR << 8) | MALE) +#define IKSAR_FEMALE ((IKSAR << 8) | FEMALE) +#define VAHSHIR_MALE ((VAHSHIR << 8) | MALE) +#define VAHSHIR_FEMALE ((VAHSHIR << 8) | FEMALE) +#define FROGLOK_MALE ((FROGLOK << 8) | MALE) +#define FROGLOK_FEMALE ((FROGLOK << 8) | FEMALE) +#define DRAKKIN_MALE ((DRAKKIN << 8) | MALE) +#define DRAKKIN_FEMALE ((DRAKKIN << 8) | FEMALE) + +#define BINDRG(r, g) (((int)r << 8) | g) + + +bool PlayerAppearance::IsValidBeard(uint16 race_id, uint8 gender_id, uint8 beard_value, bool use_luclin) +{ + if (beard_value == 0xFF) + return true; + + if (use_luclin) { + switch (BINDRG(race_id, gender_id)) { + case DWARF_FEMALE: + if (beard_value <= 1) + return true; + break; + case HIGH_ELF_MALE: + case DARK_ELF_MALE: + case HALF_ELF_MALE: + case DRAKKIN_FEMALE: + if (beard_value <= 3) + return true; + break; + case HUMAN_MALE: + case BARBARIAN_MALE: + case ERUDITE_MALE: + case DWARF_MALE: + case HALFLING_MALE: + case GNOME_MALE: + if (beard_value <= 5) + return true; + break; + case DRAKKIN_MALE: + if (beard_value <= 11) + return true; + break; + default: + break; + } + return false; + } + else { + switch (BINDRG(race_id, gender_id)) { + case DRAKKIN_FEMALE: + if (beard_value <= 3) + return true; + break; + case DRAKKIN_MALE: + if (beard_value <= 11) + return true; + break; + default: + break; + } + return false; + } +} + +bool PlayerAppearance::IsValidBeardColor(uint16 race_id, uint8 gender_id, uint8 beard_color_value, bool use_luclin) +{ + if (beard_color_value == 0xFF) + return true; + + switch (BINDRG(race_id, gender_id)) { + case GNOME_MALE: + if (beard_color_value <= 24) + return true; + break; + case HUMAN_MALE: + case BARBARIAN_MALE: + case ERUDITE_MALE: + case HALF_ELF_MALE: + case DWARF_MALE: + case DWARF_FEMALE: + case HALFLING_MALE: + if (beard_color_value <= 19) + return true; + break; + case DARK_ELF_MALE: + if (beard_color_value >= 13 && beard_color_value <= 18) + return true; + break; + case HIGH_ELF_MALE: + if (beard_color_value <= 14) + return true; + break; + case FROGLOK_MALE: + case FROGLOK_FEMALE: + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if (beard_color_value <= 3) + return true; + break; + default: + break; + } + return false; +} + +bool PlayerAppearance::IsValidDetail(uint16 race_id, uint8 gender_id, uint32 detail_value, bool use_luclin) +{ + if (detail_value == 0xFFFFFFFF) + return true; + + switch (BINDRG(race_id, gender_id)) { + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if (detail_value <= 7) + return true; + break; + default: + break; + } + return false; +} + +bool PlayerAppearance::IsValidEyeColor(uint16 race_id, uint8 gender_id, uint8 eye_color_value, bool use_luclin) +{ + return true; // need valid criteria + + switch (BINDRG(race_id, gender_id)) { + case HUMAN_MALE: + case HUMAN_FEMALE: + case BARBARIAN_MALE: + case BARBARIAN_FEMALE: + case ERUDITE_MALE: + case ERUDITE_FEMALE: + case WOOD_ELF_MALE: + case WOOD_ELF_FEMALE: + case HIGH_ELF_MALE: + case HIGH_ELF_FEMALE: + case DARK_ELF_MALE: + case DARK_ELF_FEMALE: + case HALF_ELF_MALE: + case HALF_ELF_FEMALE: + case DWARF_MALE: + case DWARF_FEMALE: + case OGRE_MALE: + case OGRE_FEMALE: + case HALFLING_MALE: + case HALFLING_FEMALE: + case GNOME_MALE: + case GNOME_FEMALE: + case IKSAR_MALE: + case IKSAR_FEMALE: + case VAHSHIR_MALE: + case VAHSHIR_FEMALE: + if (eye_color_value <= 9) + return true; + break; + case TROLL_MALE: + case TROLL_FEMALE: + if (eye_color_value <= 10) + return true; + break; + case FROGLOK_MALE: + case FROGLOK_FEMALE: + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if (eye_color_value <= 11) + return true; + break; + default: + break; + } + return false; +} + +bool PlayerAppearance::IsValidFace(uint16 race_id, uint8 gender_id, uint8 face_value, bool use_luclin) +{ + if (face_value == 0xFF) + return true; + + switch (BINDRG(race_id, gender_id)) { + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if (face_value <= 6) + return true; + break; + case HUMAN_MALE: + case HUMAN_FEMALE: + case BARBARIAN_MALE: + case BARBARIAN_FEMALE: + case ERUDITE_MALE: + case ERUDITE_FEMALE: + case WOOD_ELF_MALE: + case WOOD_ELF_FEMALE: + case HIGH_ELF_MALE: + case HIGH_ELF_FEMALE: + case DARK_ELF_MALE: + case DARK_ELF_FEMALE: + case HALF_ELF_MALE: + case HALF_ELF_FEMALE: + case DWARF_MALE: + case DWARF_FEMALE: + case TROLL_MALE: + case TROLL_FEMALE: + case OGRE_MALE: + case OGRE_FEMALE: + case HALFLING_MALE: + case HALFLING_FEMALE: + case GNOME_MALE: + case GNOME_FEMALE: + case IKSAR_MALE: + case IKSAR_FEMALE: + case VAHSHIR_MALE: + case VAHSHIR_FEMALE: + if (face_value <= 7) + return true; + break; + case FROGLOK_MALE: + case FROGLOK_FEMALE: + if (face_value <= 9) + return true; + break; + default: + break; + } + return false; +} + +bool PlayerAppearance::IsValidHair(uint16 race_id, uint8 gender_id, uint8 hair_value, bool use_luclin) +{ + if (hair_value == 0xFF) + return true; + + if (use_luclin) { + switch (BINDRG(race_id, gender_id)) { + case HUMAN_MALE: + case HUMAN_FEMALE: + case BARBARIAN_MALE: + case BARBARIAN_FEMALE: + case WOOD_ELF_MALE: + case WOOD_ELF_FEMALE: + case HIGH_ELF_MALE: + case HIGH_ELF_FEMALE: + case DARK_ELF_MALE: + case DARK_ELF_FEMALE: + case HALF_ELF_MALE: + case HALF_ELF_FEMALE: + case DWARF_MALE: + case DWARF_FEMALE: + case TROLL_FEMALE: + case OGRE_FEMALE: + case HALFLING_MALE: + case HALFLING_FEMALE: + case GNOME_MALE: + case GNOME_FEMALE: + if (hair_value <= 3) + return true; + break; + case ERUDITE_MALE: + if (hair_value <= 5) + return true; + break; + case DRAKKIN_FEMALE: + if (hair_value <= 7) + return true; + break; + case ERUDITE_FEMALE: + case DRAKKIN_MALE: + if (hair_value <= 8) + return true; + break; + default: + break; + } + return false; + } + else { + switch (BINDRG(race_id, gender_id)) { + case DRAKKIN_FEMALE: + if (hair_value <= 7) + return true; + break; + case DRAKKIN_MALE: + if (hair_value <= 8) + return true; + break; + default: + break; + } + return false; + } +} + +bool PlayerAppearance::IsValidHairColor(uint16 race_id, uint8 gender_id, uint8 hair_color_value, bool use_luclin) +{ + if (hair_color_value == 0xFF) + return true; + + switch (BINDRG(race_id, gender_id)) { + case GNOME_MALE: + case GNOME_FEMALE: + if (hair_color_value <= 24) + return true; + break; + case TROLL_FEMALE: + case OGRE_FEMALE: + if (hair_color_value <= 23) + return true; + break; + case HUMAN_MALE: + case HUMAN_FEMALE: + case BARBARIAN_MALE: + case BARBARIAN_FEMALE: + case WOOD_ELF_MALE: + case WOOD_ELF_FEMALE: + case HALF_ELF_MALE: + case HALF_ELF_FEMALE: + case DWARF_MALE: + case DWARF_FEMALE: + case HALFLING_MALE: + case HALFLING_FEMALE: + if (hair_color_value <= 19) + return true; + break; + case DARK_ELF_MALE: + case DARK_ELF_FEMALE: + if (hair_color_value >= 13 && hair_color_value <= 18) + return true; + break; + case HIGH_ELF_MALE: + case HIGH_ELF_FEMALE: + if (hair_color_value <= 14) + return true; + break; + case FROGLOK_MALE: + case FROGLOK_FEMALE: + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if (hair_color_value <= 3) + return true; + break; + default: + break; + } + return false; +} + +bool PlayerAppearance::IsValidHead(uint16 race_id, uint8 gender_id, uint8 head_value, bool use_luclin) +{ + if (head_value == 0xFF) + return true; + + if (use_luclin) { + switch (BINDRG(race_id, gender_id)) { + case HUMAN_MALE: + case HUMAN_FEMALE: + case BARBARIAN_MALE: + case BARBARIAN_FEMALE: + case WOOD_ELF_MALE: + case WOOD_ELF_FEMALE: + case HIGH_ELF_MALE: + case HIGH_ELF_FEMALE: + case DARK_ELF_MALE: + case DARK_ELF_FEMALE: + case HALF_ELF_MALE: + case HALF_ELF_FEMALE: + case DWARF_MALE: + case DWARF_FEMALE: + case TROLL_MALE: + case TROLL_FEMALE: + case OGRE_MALE: + case OGRE_FEMALE: + case HALFLING_MALE: + case HALFLING_FEMALE: + case GNOME_MALE: + case GNOME_FEMALE: + case IKSAR_MALE: + case IKSAR_FEMALE: + case VAHSHIR_MALE: + case VAHSHIR_FEMALE: + case FROGLOK_MALE: + case FROGLOK_FEMALE: + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if (head_value <= 3) + return true; + break; + case ERUDITE_MALE: + case ERUDITE_FEMALE: + if (head_value <= 4) + return true; + break; + default: + break; + } + return false; + } + else { + switch (BINDRG(race_id, gender_id)) { + case HUMAN_MALE: + case HUMAN_FEMALE: + case BARBARIAN_MALE: + case BARBARIAN_FEMALE: + case ERUDITE_MALE: + case ERUDITE_FEMALE: + case WOOD_ELF_MALE: + case WOOD_ELF_FEMALE: + case HIGH_ELF_MALE: + case HIGH_ELF_FEMALE: + case DARK_ELF_MALE: + case DARK_ELF_FEMALE: + case HALF_ELF_MALE: + case HALF_ELF_FEMALE: + case DWARF_MALE: + case DWARF_FEMALE: + case TROLL_MALE: + case TROLL_FEMALE: + case OGRE_MALE: + case OGRE_FEMALE: + case HALFLING_MALE: + case HALFLING_FEMALE: + case IKSAR_MALE: + case IKSAR_FEMALE: + case VAHSHIR_MALE: + case VAHSHIR_FEMALE: + case FROGLOK_MALE: + case FROGLOK_FEMALE: + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if (head_value <= 3) + return true; + break; + case GNOME_MALE: + case GNOME_FEMALE: + if (head_value <= 4) + return true; + break; + default: + break; + } + return false; + } +} + +bool PlayerAppearance::IsValidHeritage(uint16 race_id, uint8 gender_id, uint32 heritage_value, bool use_luclin) +{ + if (heritage_value == 0xFFFFFFFF) + return true; + + switch (BINDRG(race_id, gender_id)) { + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if (heritage_value <= 7) // > 5 seems to jumble other features..else, some heritages have 'specialized' features + return true; + break; + default: + break; + } + return false; +} + +bool PlayerAppearance::IsValidTattoo(uint16 race_id, uint8 gender_id, uint32 tattoo_value, bool use_luclin) +{ + if (tattoo_value == 0xFFFFFFFF) + return true; + + switch (BINDRG(race_id, gender_id)) { + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if (tattoo_value <= 7) + return true; + break; + default: + break; + } + return false; +} + +bool PlayerAppearance::IsValidTexture(uint16 race_id, uint8 gender_id, uint8 texture_value, bool use_luclin) +{ + if (texture_value == 0xFF) + return true; + + if (use_luclin) { + switch (BINDRG(race_id, gender_id)) { + case HUMAN_MALE: + case HUMAN_FEMALE: + case IKSAR_MALE: + case IKSAR_FEMALE: + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if ((texture_value >= 10 && texture_value <= 16) || texture_value <= 4) + return true; + break; + case ERUDITE_MALE: + case ERUDITE_FEMALE: + case HIGH_ELF_MALE: + case HIGH_ELF_FEMALE: + case DARK_ELF_MALE: + case DARK_ELF_FEMALE: + case GNOME_MALE: + case GNOME_FEMALE: + case FROGLOK_MALE: + case FROGLOK_FEMALE: + if ((texture_value >= 10 && texture_value <= 16) || texture_value <= 3) + return true; + break; + case BARBARIAN_MALE: + case BARBARIAN_FEMALE: + case WOOD_ELF_MALE: + case WOOD_ELF_FEMALE: + case HALF_ELF_MALE: + case HALF_ELF_FEMALE: + case DWARF_MALE: + case DWARF_FEMALE: + case TROLL_MALE: + case TROLL_FEMALE: + case OGRE_MALE: + case OGRE_FEMALE: + case HALFLING_MALE: + case HALFLING_FEMALE: + case VAHSHIR_MALE: + case VAHSHIR_FEMALE: + if (texture_value <= 3) + return true; + break; + default: + break; + } + return false; + } + else { + switch (BINDRG(race_id, gender_id)) { + case HUMAN_MALE: + case HUMAN_FEMALE: + case ERUDITE_MALE: + case ERUDITE_FEMALE: + case DRAKKIN_MALE: + case DRAKKIN_FEMALE: + if ((texture_value >= 10 && texture_value <= 16) || texture_value <= 4) + return true; + break; + case HIGH_ELF_MALE: + case HIGH_ELF_FEMALE: + case DARK_ELF_MALE: + case DARK_ELF_FEMALE: + case GNOME_MALE: + case GNOME_FEMALE: + case FROGLOK_MALE: + case FROGLOK_FEMALE: + if ((texture_value >= 10 && texture_value <= 16) || texture_value <= 3) + return true; + break; + case VAHSHIR_MALE: + case VAHSHIR_FEMALE: + if (texture_value == 50 || texture_value <= 3) + return true; + break; + case IKSAR_MALE: + case IKSAR_FEMALE: + if (texture_value == 10 || texture_value <= 4) + return true; + break; + case BARBARIAN_MALE: + case BARBARIAN_FEMALE: + case WOOD_ELF_MALE: + case WOOD_ELF_FEMALE: + case HALF_ELF_MALE: + case HALF_ELF_FEMALE: + case DWARF_MALE: + case DWARF_FEMALE: + case TROLL_MALE: + case TROLL_FEMALE: + case OGRE_MALE: + case OGRE_FEMALE: + case HALFLING_MALE: + case HALFLING_FEMALE: + if (texture_value <= 3) + return true; + break; + default: + break; + } + return false; + } +} + +bool PlayerAppearance::IsValidWoad(uint16 race_id, uint8 gender_id, uint8 woad_value, bool use_luclin) +{ + if (woad_value == 0xFF) + return true; + + if (use_luclin) { + switch (BINDRG(race_id, gender_id)) { + case BARBARIAN_MALE: + case BARBARIAN_FEMALE: + if (woad_value <= 8) + return true; + break; + default: + break; + } + } + return false; +} diff --git a/common/races.h b/common/races.h index 2c360e908..d34d9b754 100644 --- a/common/races.h +++ b/common/races.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,90 +15,131 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef RACES_H #define RACES_H #include "../common/types.h" -#include + +#define MALE 0 +#define FEMALE 1 +#define NEUTER 2 //theres a big list straight from the client below. -#define HUMAN 1 -#define BARBARIAN 2 -#define ERUDITE 3 -#define WOOD_ELF 4 -#define HIGH_ELF 5 -#define DARK_ELF 6 -#define HALF_ELF 7 -#define DWARF 8 -#define TROLL 9 -#define OGRE 10 -#define HALFLING 11 -#define GNOME 12 -#define WEREWOLF 14 -#define WOLF 42 -#define BEAR 43 -#define SKELETON 60 -#define TIGER 63 -#define ELEMENTAL 75 -#define ALLIGATOR 91 -#define EYE_OF_ZOMM 108 -#define WOLF_ELEMENTAL 120 -#define INVISIBLE_MAN 127 -#define IKSAR 128 -#define VAHSHIR 130 +#define HUMAN 1 +#define BARBARIAN 2 +#define ERUDITE 3 +#define WOOD_ELF 4 +#define HIGH_ELF 5 +#define DARK_ELF 6 +#define HALF_ELF 7 +#define DWARF 8 +#define TROLL 9 +#define OGRE 10 +#define HALFLING 11 +#define GNOME 12 +#define WEREWOLF 14 +#define WOLF 42 +#define BEAR 43 +#define SKELETON 60 +#define TIGER 63 +#define ELEMENTAL 75 +#define ALLIGATOR 91 +#define OGGOK_CITIZEN 93 +#define EYE_OF_ZOMM 108 +#define WOLF_ELEMENTAL 120 +#define INVISIBLE_MAN 127 +#define IKSAR 128 +#define VAHSHIR 130 #define CONTROLLED_BOAT 141 -#define IKSAR_SKELETON 161 -#define FROGLOK 330 -#define FROGLOK2 74 // Not sure why /who all reports race as 74 for frogloks -#define DRAKKIN 522 // 32768 -#define EMU_RACE_NPC 131069 // was 65533 -#define EMU_RACE_PET 131070 // was 65534 +#define MINOR_ILL_OBJ 142 +#define TREE 143 +#define IKSAR_SKELETON 161 +#define FROGLOK 330 +// TODO: check all clients for (BYTE) usage of '/who all' class and remove FROGLOK2, if possible (330 - 74 = 256 .. WORD->BYTE conversion loss...) +#define FROGLOK2 74 // Not sure why /who all reports race as 74 for frogloks +#define FAIRY 473 +#define DRAKKIN 522 // 32768 +#define EMU_RACE_NPC 131069 // was 65533 +#define EMU_RACE_PET 131070 // was 65534 #define EMU_RACE_UNKNOWN 131071 // was 65535 -#define human_1 1 -#define barbarian_1 2 -#define erudite_1 4 -#define woodelf_1 8 -#define highelf_1 16 -#define darkelf_1 32 -#define halfelf_1 64 -#define dwarf_1 128 -#define troll_1 256 -#define ogre_1 512 -#define halfling_1 1024 -#define gnome_1 2048 -#define iksar_1 4096 -#define vahshir_1 8192 -#define rall_1 16384 //froglok? -#define drakkin_1 32768 +// player race values +#define PLAYER_RACE_UNKNOWN 0 +#define PLAYER_RACE_HUMAN 1 +#define PLAYER_RACE_BARBARIAN 2 +#define PLAYER_RACE_ERUDITE 3 +#define PLAYER_RACE_WOOD_ELF 4 +#define PLAYER_RACE_HIGH_ELF 5 +#define PLAYER_RACE_DARK_ELF 6 +#define PLAYER_RACE_HALF_ELF 7 +#define PLAYER_RACE_DWARF 8 +#define PLAYER_RACE_TROLL 9 +#define PLAYER_RACE_OGRE 10 +#define PLAYER_RACE_HALFLING 11 +#define PLAYER_RACE_GNOME 12 +#define PLAYER_RACE_IKSAR 13 +#define PLAYER_RACE_VAHSHIR 14 +#define PLAYER_RACE_FROGLOK 15 +#define PLAYER_RACE_DRAKKIN 16 -const char* GetRaceName(uint16 race); +#define PLAYER_RACE_COUNT 16 -uint32 GetArrayRace(uint16 race); -inline uint32 GetRaceBitmask(uint16 race) { return uint32(pow(2.0f, float(GetArrayRace(race) - 1))); } -#define Array_Race_UNKNOWN 0 -#define Array_Race_HUMAN 1 -#define Array_Race_BARBARIAN 2 -#define Array_Race_ERUDITE 3 -#define Array_Race_WOOD_ELF 4 -#define Array_Race_HIGH_ELF 5 -#define Array_Race_DARK_ELF 6 -#define Array_Race_HALF_ELF 7 -#define Array_Race_DWARF 8 -#define Array_Race_TROLL 9 -#define Array_Race_OGRE 10 -#define Array_Race_HALFLING 11 -#define Array_Race_GNOME 12 -#define Array_Race_IKSAR 13 -#define Array_Race_VAHSHIR 14 -#define Array_Race_FROGLOK 15 -#define Array_Race_DRAKKIN 16 -#define Array_Race_NPC 17 -#define Array_Race_PET 18 -#define Count_Array_Race 19 // used for array defines, must be the max + 1 -#define PLAYER_RACE_COUNT 16 // The count of all player races +#define PLAYER_RACE_EMU_NPC 17 +#define PLAYER_RACE_EMU_PET 18 +#define PLAYER_RACE_EMU_COUNT 19 + + +// player race bits +#define PLAYER_RACE_UNKNOWN_BIT 0 +#define PLAYER_RACE_HUMAN_BIT 1 +#define PLAYER_RACE_BARBARIAN_BIT 2 +#define PLAYER_RACE_ERUDITE_BIT 4 +#define PLAYER_RACE_WOOD_ELF_BIT 8 +#define PLAYER_RACE_HIGH_ELF_BIT 16 +#define PLAYER_RACE_DARK_ELF_BIT 32 +#define PLAYER_RACE_HALF_ELF_BIT 64 +#define PLAYER_RACE_DWARF_BIT 128 +#define PLAYER_RACE_TROLL_BIT 256 +#define PLAYER_RACE_OGRE_BIT 512 +#define PLAYER_RACE_HALFLING_BIT 1024 +#define PLAYER_RACE_GNOME_BIT 2048 +#define PLAYER_RACE_IKSAR_BIT 4096 +#define PLAYER_RACE_VAHSHIR_BIT 8192 +#define PLAYER_RACE_FROGLOK_BIT 16384 +#define PLAYER_RACE_DRAKKIN_BIT 32768 + +#define PLAYER_RACE_ALL_MASK 65535 + + +const char* GetRaceIDName(uint16 race_id); +const char* GetPlayerRaceName(uint32 player_race_value); + +uint32 GetPlayerRaceValue(uint16 race_id); +uint32 GetPlayerRaceBit(uint16 race_id); + +uint16 GetRaceIDFromPlayerRaceValue(uint32 player_race_value); +uint16 GetRaceIDFromPlayerRaceBit(uint32 player_race_bit); + + +// player race-/gender-based model feature validators +namespace PlayerAppearance +{ + bool IsValidBeard(uint16 race_id, uint8 gender_id, uint8 beard_value, bool use_luclin = true); + bool IsValidBeardColor(uint16 race_id, uint8 gender_id, uint8 beard_color_value, bool use_luclin = true); + bool IsValidDetail(uint16 race_id, uint8 gender_id, uint32 detail_value, bool use_luclin = true); + bool IsValidEyeColor(uint16 race_id, uint8 gender_id, uint8 eye_color_value, bool use_luclin = true); + bool IsValidFace(uint16 race_id, uint8 gender_id, uint8 face_value, bool use_luclin = true); + bool IsValidHair(uint16 race_id, uint8 gender_id, uint8 hair_value, bool use_luclin = true); + bool IsValidHairColor(uint16 race_id, uint8 gender_id, uint8 hair_color_value, bool use_luclin = true); + bool IsValidHead(uint16 race_id, uint8 gender_id, uint8 head_value, bool use_luclin = true); + bool IsValidHeritage(uint16 race_id, uint8 gender_id, uint32 heritage_value, bool use_luclin = true); + bool IsValidTattoo(uint16 race_id, uint8 gender_id, uint32 tattoo_value, bool use_luclin = true); + bool IsValidTexture(uint16 race_id, uint8 gender_id, uint8 texture_value, bool use_luclin = true); + bool IsValidWoad(uint16 race_id, uint8 gender_id, uint8 woad_value, bool use_luclin = true); +} /* diff --git a/common/rulesys.cpp b/common/rulesys.cpp index a53dbcabe..770a1ab97 100644 --- a/common/rulesys.cpp +++ b/common/rulesys.cpp @@ -17,43 +17,14 @@ */ #include "rulesys.h" - #include "database.h" #include "string_util.h" #include #include /* - - FatherNitwit: Added new rules subsystem to allow game rules to be changed - at runtime. more about this will come as time goes on. -FatherNitwit: Added #rules command to manage rules data from in game. -FatherNitwit: Renamed old #rules to #serverrules -FatherNitwit: Moved max level into the rules system (Character:MaxLevel) -Requred SQL: - - - -CREATE TABLE rule_sets ( - ruleset_id TINYINT UNSIGNED NOT NULL auto_increment, - name VARCHAR(255) NOT NULL, - PRIMARY KEY(ruleset_id) -); -INSERT INTO rule_sets VALUES(0, "default"); -UPDATE rule_sets SET ruleset_id=0; - -CREATE TABLE rule_values ( - ruleset_id TINYINT UNSIGNED NOT NULL, - rule_name VARCHAR(64) NOT NULL, - rule_value VARCHAR(10) NOT NULL, - INDEX(ruleset_id), - PRIMARY KEY(ruleset_id,rule_name) -); - - - -Commands: -#rules: + Commands: + #rules: current -> lists current set name switch (set name) -> change set in the DB, but dont reload load (set name) -> load set into this zone without changing the world @@ -94,28 +65,28 @@ RuleManager::RuleManager() } RuleManager::CategoryType RuleManager::FindCategory(const char *catname) { - int r; - for(r = 0; r < _CatCount; r++) { - if(strcasecmp(catname, s_categoryNames[r]) == 0) - return((CategoryType) r); + int i; + for (i = 0; i < _CatCount; i++) { + if (strcasecmp(catname, s_categoryNames[i]) == 0) + return((CategoryType)i); } return(InvalidCategory); } bool RuleManager::ListRules(const char *catname, std::vector &into) { CategoryType cat = InvalidCategory; - if(catname != nullptr) { + if (catname != nullptr) { cat = FindCategory(catname); - if(cat == InvalidCategory) { + if (cat == InvalidCategory) { Log.Out(Logs::Detail, Logs::Rules, "Unable to find category '%s'", catname); return(false); } } - int r; - int rcount = CountRules(); - for(r = 0; r < rcount; r++) { - const RuleInfo &rule = s_RuleInfo[r]; - if(catname == nullptr || cat == rule.category) { + int i; + int rule_count = CountRules(); + for (i = 0; i < rule_count; i++) { + const RuleInfo &rule = s_RuleInfo[i]; + if (catname == nullptr || cat == rule.category) { into.push_back(rule.name); } } @@ -123,15 +94,14 @@ bool RuleManager::ListRules(const char *catname, std::vector &into } bool RuleManager::ListCategories(std::vector &into) { - int r; - for(r = 0; r < _CatCount; r++) { - into.push_back(s_categoryNames[r]); + int i; + for (i = 0; i < _CatCount; i++) { + into.push_back(s_categoryNames[i]); } return(true); } - -bool RuleManager::GetRule(const char *rule_name, std::string &ret_val) { +bool RuleManager::GetRule(const char *rule_name, std::string &return_value) { RuleType type; uint16 index; if (!_FindRule(rule_name, type, index)) @@ -151,12 +121,12 @@ bool RuleManager::GetRule(const char *rule_name, std::string &ret_val) { break; } - ret_val = tmp; + return_value = tmp; return true; } -bool RuleManager::SetRule(const char *rule_name, const char *rule_value, Database *db, bool db_save) { +bool RuleManager::SetRule(const char *rule_name, const char *rule_value, Database *database, bool db_save) { if(rule_name == nullptr || rule_value == nullptr) return(false); @@ -166,25 +136,26 @@ bool RuleManager::SetRule(const char *rule_name, const char *rule_value, Databas return(false); switch(type) { - case IntRule: - m_RuleIntValues [index] = atoi(rule_value); - Log.Out(Logs::Detail, Logs::Rules, "Set rule %s to value %d", rule_name, m_RuleIntValues[index]); - break; - case RealRule: - m_RuleRealValues[index] = atof(rule_value); - Log.Out(Logs::Detail, Logs::Rules, "Set rule %s to value %.13f", rule_name, m_RuleRealValues[index]); - break; - case BoolRule: - uint32 val = 0; - if(!strcasecmp(rule_value, "on") || !strcasecmp(rule_value, "true") || !strcasecmp(rule_value, "yes") || !strcasecmp(rule_value, "enabled") || !strcmp(rule_value, "1")) - val = 1; - m_RuleBoolValues[index] = val; - Log.Out(Logs::Detail, Logs::Rules, "Set rule %s to value %s", rule_name, m_RuleBoolValues[index] == 1 ?"true":"false"); - break; + case IntRule: + m_RuleIntValues[index] = atoi(rule_value); + Log.Out(Logs::Detail, Logs::Rules, "Set rule %s to value %d", rule_name, m_RuleIntValues[index]); + break; + case RealRule: + m_RuleRealValues[index] = atof(rule_value); + Log.Out(Logs::Detail, Logs::Rules, "Set rule %s to value %.13f", rule_name, m_RuleRealValues[index]); + break; + case BoolRule: + uint32 val = 0; + if (!strcasecmp(rule_value, "on") || !strcasecmp(rule_value, "true") || !strcasecmp(rule_value, "yes") || !strcasecmp(rule_value, "enabled") || !strcmp(rule_value, "1")) + val = 1; + + m_RuleBoolValues[index] = val; + Log.Out(Logs::Detail, Logs::Rules, "Set rule %s to value %s", rule_name, m_RuleBoolValues[index] == 1 ? "true" : "false"); + break; } if(db_save) - _SaveRule(db, type, index); + _SaveRule(database, type, index); return(true); } @@ -201,14 +172,14 @@ void RuleManager::ResetRules() { } bool RuleManager::_FindRule(const char *rule_name, RuleType &type_into, uint16 &index_into) { - if(rule_name == nullptr) + if (rule_name == nullptr) return(false); - int r; - int rcount = CountRules(); - for(r = 0; r < rcount; r++) { - const RuleInfo &rule = s_RuleInfo[r]; - if(strcmp(rule_name, rule.name) == 0) { + int i; + int rule_count = CountRules(); + for (i = 0; i < rule_count; i++) { + const RuleInfo &rule = s_RuleInfo[i]; + if (strcmp(rule_name, rule.name) == 0) { type_into = rule.type; index_into = rule.rule_index; return(true); @@ -220,191 +191,197 @@ bool RuleManager::_FindRule(const char *rule_name, RuleType &type_into, uint16 & //assumes index is valid! const char *RuleManager::_GetRuleName(RuleType type, uint16 index) { - switch(type) { - case IntRule: - return(s_RuleInfo[index].name); - case RealRule: - return(s_RuleInfo[index+_IntRuleCount].name); - case BoolRule: - return(s_RuleInfo[index+_IntRuleCount+_RealRuleCount].name); + switch (type) { + case IntRule: + return(s_RuleInfo[index].name); + case RealRule: + return(s_RuleInfo[index + _IntRuleCount].name); + case BoolRule: + return(s_RuleInfo[index + _IntRuleCount + _RealRuleCount].name); } //should never happen return("InvalidRule??"); } -void RuleManager::SaveRules(Database *db, const char *ruleset) { +void RuleManager::SaveRules(Database *database, const char *ruleset_name) { - if(ruleset != nullptr) { + if (ruleset_name != nullptr) { //saving to a specific name - if(m_activeName != ruleset) { + if (m_activeName != ruleset_name) { //a new name... - m_activeRuleset = _FindOrCreateRuleset(db, ruleset); - if(m_activeRuleset == -1) { - Log.Out(Logs::Detail, Logs::Rules, "Unable to find or create rule set %s", ruleset); + m_activeRuleset = _FindOrCreateRuleset(database, ruleset_name); + if (m_activeRuleset == -1) { + Log.Out(Logs::Detail, Logs::Rules, "Unable to find or create rule set %s", ruleset_name); return; } - m_activeName = ruleset; + m_activeName = ruleset_name; } - Log.Out(Logs::Detail, Logs::Rules, "Saving running rules into rule set %s (%d)", ruleset, m_activeRuleset); - } else { + Log.Out(Logs::Detail, Logs::Rules, "Saving running rules into rule set %s (%d)", ruleset_name, m_activeRuleset); + } + else { Log.Out(Logs::Detail, Logs::Rules, "Saving running rules into running rule set %s", m_activeName.c_str(), m_activeRuleset); } - int r; - for(r = 0; r < _IntRuleCount; r++) { - _SaveRule(db, IntRule, r); + int i; + for (i = 0; i < _IntRuleCount; i++) { + _SaveRule(database, IntRule, i); } - for(r = 0; r < _RealRuleCount; r++) { - _SaveRule(db, RealRule, r); + for (i = 0; i < _RealRuleCount; i++) { + _SaveRule(database, RealRule, i); } - for(r = 0; r < _BoolRuleCount; r++) { - _SaveRule(db, BoolRule, r); + for (i = 0; i < _BoolRuleCount; i++) { + _SaveRule(database, BoolRule, i); } } - - -bool RuleManager::LoadRules(Database *db, const char *ruleset) { - - int rsid = GetRulesetID(db, ruleset); - if(rsid < 0) { - Log.Out(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset); +bool RuleManager::LoadRules(Database *database, const char *ruleset_name) { + + int ruleset_id = GetRulesetID(database, ruleset_name); + if (ruleset_id < 0) { + Log.Out(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name); return(false); } - Log.Out(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", ruleset, rsid); + Log.Out(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", ruleset_name, ruleset_id); - m_activeRuleset = rsid; - m_activeName = ruleset; + m_activeRuleset = ruleset_id; + m_activeName = ruleset_name; - std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id=%d", rsid); - auto results = db->QueryDatabase(query); - if (!results.Success()) - { - return false; + /* Load default ruleset values first if we're loading something other than default */ + if (strcasecmp(ruleset_name, "default") != 0){ + std::string default_ruleset_name = "default"; + int default_ruleset_id = GetRulesetID(database, default_ruleset_name.c_str()); + if (default_ruleset_id < 0) { + Log.Out(Logs::Detail, Logs::Rules, "Failed to find default ruleset '%s' for load operation. Canceling.", default_ruleset_name.c_str()); + return(false); + } + Log.Out(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", default_ruleset_name.c_str(), default_ruleset_id); + + std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id = %d", default_ruleset_id); + auto results = database->QueryDatabase(query); + if (!results.Success()) + return false; + + for (auto row = results.begin(); row != results.end(); ++row) + if (!SetRule(row[0], row[1], nullptr, false)) + Log.Out(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]); } - for(auto row = results.begin(); row != results.end(); ++row) - if(!SetRule(row[0], row[1], nullptr, false)) - Log.Out(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]); + std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id=%d", ruleset_id); + auto results = database->QueryDatabase(query); + if (!results.Success()) + return false; + + for (auto row = results.begin(); row != results.end(); ++row) + if (!SetRule(row[0], row[1], nullptr, false)) + Log.Out(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]); return true; } -void RuleManager::_SaveRule(Database *db, RuleType type, uint16 index) { - char vstr[100]; +void RuleManager::_SaveRule(Database *database, RuleType type, uint16 index) { + char value_string[100]; switch(type) { - case IntRule: - sprintf(vstr, "%d", m_RuleIntValues[index]); - break; - case RealRule: - sprintf(vstr, "%.13f", m_RuleRealValues[index]); - break; - case BoolRule: - sprintf(vstr, "%s", m_RuleBoolValues[index]?"true":"false"); - break; + case IntRule: + sprintf(value_string, "%d", m_RuleIntValues[index]); + break; + case RealRule: + sprintf(value_string, "%.13f", m_RuleRealValues[index]); + break; + case BoolRule: + sprintf(value_string, "%s", m_RuleBoolValues[index]?"true":"false"); + break; } std::string query = StringFormat("REPLACE INTO rule_values " "(ruleset_id, rule_name, rule_value) " " VALUES(%d, '%s', '%s')", - m_activeRuleset, _GetRuleName(type, index), vstr); - auto results = db->QueryDatabase(query); + m_activeRuleset, _GetRuleName(type, index), value_string); + auto results = database->QueryDatabase(query); } -int RuleManager::GetRulesetID(Database *db, const char *rulesetname) { +int RuleManager::GetRulesetID(Database *database, const char *ruleset_name) { - uint32 len = strlen(rulesetname); - char* rst = new char[2*len+1]; - db->DoEscapeString(rst, rulesetname, len); + uint32 len = strlen(ruleset_name); + auto rst = new char[2 * len + 1]; + database->DoEscapeString(rst, ruleset_name, len); - std::string query = StringFormat("SELECT ruleset_id FROM rule_sets WHERE name='%s'", rst); - safe_delete_array(rst); - auto results = db->QueryDatabase(query); - if (!results.Success()) { - return -1; - } + std::string query = StringFormat("SELECT ruleset_id FROM rule_sets WHERE name='%s'", rst); + safe_delete_array(rst); + auto results = database->QueryDatabase(query); + if (!results.Success()) + return -1; - if (results.RowCount() == 0) - return -1; + if (results.RowCount() == 0) + return -1; - auto row = results.begin(); + auto row = results.begin(); return atoi(row[0]); } -int RuleManager::_FindOrCreateRuleset(Database *db, const char *ruleset) { +int RuleManager::_FindOrCreateRuleset(Database *database, const char *in_ruleset_name) { - int res = GetRulesetID(db, ruleset); - if(res >= 0) - return res; //found and existing one... + int ruleset_id = GetRulesetID(database, in_ruleset_name); + if (ruleset_id >= 0) + return ruleset_id; //found and existing one... - uint32 len = strlen(ruleset); - char* rst = new char[2*len+1]; - db->DoEscapeString(rst, ruleset, len); + uint32 len = strlen(in_ruleset_name); + auto ruleset_name = new char[2 * len + 1]; + database->DoEscapeString(ruleset_name, in_ruleset_name, len); - std::string query = StringFormat("INSERT INTO rule_sets (ruleset_id, name) VALUES(0, '%s')", rst); - safe_delete_array(rst); - auto results = db->QueryDatabase(query); + std::string query = StringFormat("INSERT INTO rule_sets (ruleset_id, name) VALUES(0, '%s')", ruleset_name); + safe_delete_array(ruleset_name); + auto results = database->QueryDatabase(query); if (!results.Success()) - { return -1; - } - return results.LastInsertedID(); + return results.LastInsertedID(); } -std::string RuleManager::GetRulesetName(Database *db, int id) { - - std::string query = StringFormat("SELECT name FROM rule_sets WHERE ruleset_id=%d", id); - auto results = db->QueryDatabase(query); +std::string RuleManager::GetRulesetName(Database *database, int ruleset_id) { + std::string query = StringFormat("SELECT name FROM rule_sets WHERE ruleset_id=%d", ruleset_id); + auto results = database->QueryDatabase(query); if (!results.Success()) - { - return ""; - } + return ""; if (results.RowCount() == 0) - return ""; + return ""; - auto row = results.begin(); + auto row = results.begin(); return row[0]; } -bool RuleManager::ListRulesets(Database *db, std::map &into) { +bool RuleManager::ListRulesets(Database *database, std::map &into) { //start out with the default set which is always present. into[0] = "default"; - std::string query = "SELECT ruleset_id, name FROM rule_sets"; - auto results = db->QueryDatabase(query); + std::string query = "SELECT ruleset_id, name FROM rule_sets"; + auto results = database->QueryDatabase(query); if (results.Success()) - { return false; - } for (auto row = results.begin(); row != results.end(); ++row) - into[ atoi(row[0]) ] = row[1]; + into[atoi(row[0])] = row[1]; return true; } -int32 RuleManager::GetIntRule(RuleManager::IntType t) const -{ +int32 RuleManager::GetIntRule(RuleManager::IntType t) const{ return(m_RuleIntValues[t]); } -float RuleManager::GetRealRule(RuleManager::RealType t) const -{ +float RuleManager::GetRealRule(RuleManager::RealType t) const{ return(m_RuleRealValues[t]); } -bool RuleManager::GetBoolRule(RuleManager::BoolType t) const -{ +bool RuleManager::GetBoolRule(RuleManager::BoolType t) const{ return (m_RuleBoolValues[t] == 1); } diff --git a/common/ruletypes.h b/common/ruletypes.h index 7894c5ebd..c19ebee45 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -1,5 +1,20 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ #ifndef RULE_CATEGORY #define RULE_CATEGORY(name) @@ -20,587 +35,643 @@ -RULE_CATEGORY( Character ) -RULE_INT ( Character, MaxLevel, 65 ) -RULE_BOOL ( Character, PerCharacterQglobalMaxLevel, false) // This will check for qglobal 'CharMaxLevel' character qglobal (Type 5), if player tries to level beyond that point, it will not go beyond that level -RULE_INT ( Character, MaxExpLevel, 0 ) //Sets the Max Level attainable via Experience -RULE_INT ( Character, DeathExpLossLevel, 10 ) // Any level greater than this will lose exp on death -RULE_INT ( Character, DeathExpLossMaxLevel, 255 ) // Any level greater than this will no longer lose exp on death -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_INT ( Character, CorpseDecayTimeMS, 10800000 ) -RULE_INT ( Character, CorpseResTimeMS, 10800000 ) // time before cant res corpse(3 hours) -RULE_BOOL( Character, LeaveCorpses, true ) -RULE_BOOL( Character, LeaveNakedCorpses, false ) -RULE_INT ( Character, MaxDraggedCorpses, 2 ) -RULE_REAL( Character, DragCorpseDistance, 400) // If the corpse is <= this distance from the player, it won't move -RULE_REAL( Character, ExpMultiplier, 0.5 ) -RULE_REAL( Character, AAExpMultiplier, 0.5 ) -RULE_REAL( Character, GroupExpMultiplier, 0.5 ) -RULE_REAL( Character, RaidExpMultiplier, 0.2 ) -RULE_BOOL( Character, UseXPConScaling, true ) -RULE_INT ( Character, LightBlueModifier, 40 ) -RULE_INT ( Character, BlueModifier, 90 ) -RULE_INT ( Character, WhiteModifier, 100 ) -RULE_INT ( Character, YellowModifier, 125 ) -RULE_INT ( Character, RedModifier, 150 ) -RULE_INT ( Character, AutosaveIntervalS, 300 ) //0=disabled -RULE_INT ( Character, HPRegenMultiplier, 100) -RULE_INT ( Character, ManaRegenMultiplier, 100) -RULE_INT ( Character, EnduranceRegenMultiplier, 100) -RULE_INT ( Character, ConsumptionMultiplier, 100) //item's hunger restored = this value * item's food level, 100 = normal, 50 = people eat 2x as fast, 200 = people eat 2x as slow -RULE_BOOL( Character, HealOnLevel, false) -RULE_BOOL( Character, FeignKillsPet, false) -RULE_INT ( Character, ItemManaRegenCap, 15) -RULE_INT ( Character, ItemHealthRegenCap, 35) -RULE_INT ( Character, ItemDamageShieldCap, 30) -RULE_INT ( Character, ItemAccuracyCap, 150) -RULE_INT ( Character, ItemAvoidanceCap, 100) -RULE_INT ( Character, ItemCombatEffectsCap, 100) -RULE_INT ( Character, ItemShieldingCap, 35) -RULE_INT ( Character, ItemSpellShieldingCap, 35) -RULE_INT ( Character, ItemDoTShieldingCap, 35) -RULE_INT ( Character, ItemStunResistCap, 35) -RULE_INT ( Character, ItemStrikethroughCap, 35) -RULE_INT ( Character, ItemATKCap, 250) -RULE_INT ( Character, ItemHealAmtCap, 250) -RULE_INT ( Character, ItemSpellDmgCap, 250) -RULE_INT ( Character, ItemClairvoyanceCap, 250) -RULE_INT ( Character, ItemDSMitigationCap, 50) -RULE_INT ( Character, ItemEnduranceRegenCap, 15) -RULE_INT ( Character, ItemExtraDmgCap, 150) // Cap for bonuses to melee skills like Bash, Frenzy, etc -RULE_INT ( Character, HasteCap, 100) // Haste cap for non-v3(overhaste) haste. -RULE_INT ( Character, SkillUpModifier, 100) //skill ups are at 100% -RULE_BOOL ( Character, SharedBankPlat, false) //off by default to prevent duping for now -RULE_BOOL ( Character, BindAnywhere, false) -RULE_INT ( Character, RestRegenPercent, 0) // Set to >0 to enable rest state bonus HP and mana regen. -RULE_INT ( Character, RestRegenTimeToActivate, 30) // Time in seconds for rest state regen to kick in. -RULE_INT ( Character, RestRegenRaidTimeToActivate, 300) // Time in seconds for rest state regen to kick in with a raid target. -RULE_BOOL ( Character, RestRegenEndurance, false) // Whether rest regen will work for endurance or not. -RULE_INT ( Character, KillsPerGroupLeadershipAA, 250) // Number of dark blues or above per Group Leadership AA -RULE_INT ( Character, KillsPerRaidLeadershipAA, 250) // Number of dark blues or above per Raid Leadership AA -RULE_INT ( Character, MaxFearDurationForPlayerCharacter, 4) //4 tics, each tic calculates every 6 seconds. -RULE_INT ( Character, MaxCharmDurationForPlayerCharacter, 15) -RULE_INT ( Character, BaseHPRegenBonusRaces, 4352) //a bitmask of race(s) that receive the regen bonus. Iksar (4096) & Troll (256) = 4352. see common/races.h for the bitmask values -RULE_BOOL ( Character, SoDClientUseSoDHPManaEnd, false) // Setting this to true will allow SoD clients to use the SoD HP/Mana/End formulas and previous clients will use the old formulas -RULE_BOOL ( Character, UseRaceClassExpBonuses, true) // Setting this to true will enable Class and Racial experience rate bonuses -RULE_BOOL ( Character, RespawnFromHover, false) // Use Respawn window, or not. -RULE_INT ( Character, RespawnFromHoverTimer, 300) // Respawn Window countdown timer, in SECONDS -RULE_BOOL ( Character, UseNewStatsWindow, true) // New stats window shows everything -RULE_BOOL ( Character, ItemCastsUseFocus, false) // If true, this allows item clickies to use focuses that have limited max levels on them -RULE_INT ( Character, MinStatusForNoDropExemptions, 80) // This allows status x and higher to trade no drop items. -RULE_INT ( Character, SkillCapMaxLevel, 75 ) // Sets the Max Level used for Skill Caps (from skill_caps table). -1 makes it use MaxLevel rule value. It is set to 75 because PEQ only has skillcaps up to that level, and grabbing the players' skill past 75 will return 0, breaking all skills past that level. This helps servers with obsurd level caps (75+ level cap) function without any modifications. -RULE_INT ( Character, StatCap, 0 ) -RULE_BOOL ( Character, CheckCursorEmptyWhenLooting, true ) // If true, a player cannot loot a corpse (player or NPC) with an item on their cursor -RULE_BOOL ( Character, MaintainIntoxicationAcrossZones, true ) // If true, alcohol effects are maintained across zoning and logging out/in. -RULE_BOOL ( Character, EnableDiscoveredItems, true ) // If enabled, it enables EVENT_DISCOVER_ITEM and also saves character names and timestamps for the first time an item is discovered. -RULE_BOOL ( Character, EnableXTargetting, true) // Enable Extended Targetting Window, for users with UF and later clients. -RULE_BOOL ( Character, KeepLevelOverMax, false) // Don't delevel a character that has somehow gone over the level cap -RULE_INT ( Character, FoodLossPerUpdate, 35) // How much food/water you lose per stamina update -RULE_INT ( Character, BaseInstrumentSoftCap, 36) // Softcap for instrument mods, 36 commonly referred to as "3.6" as well. -RULE_INT ( Character, BaseRunSpeedCap, 158) // Base Run Speed Cap, on live it's 158% which will give you a runspeed of 1.580 hard capped to 225. -RULE_INT ( Character, OrnamentationAugmentType, 20) //Ornamentation Augment Type +RULE_CATEGORY(Character) +RULE_INT(Character, MaxLevel, 65) +RULE_BOOL(Character, PerCharacterQglobalMaxLevel, false) // This will check for qglobal 'CharMaxLevel' character qglobal (Type 5), if player tries to level beyond that point, it will not go beyond that level +RULE_INT(Character, MaxExpLevel, 0) //Sets the Max Level attainable via Experience +RULE_INT(Character, DeathExpLossLevel, 10) // Any level greater than this will lose exp on death +RULE_INT(Character, DeathExpLossMaxLevel, 255) // Any level greater than this will no longer lose exp on death +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_INT(Character, CorpseDecayTimeMS, 10800000) +RULE_INT(Character, CorpseResTimeMS, 10800000) // time before cant res corpse(3 hours) +RULE_BOOL(Character, LeaveCorpses, true) +RULE_BOOL(Character, LeaveNakedCorpses, false) +RULE_INT(Character, MaxDraggedCorpses, 2) +RULE_REAL(Character, DragCorpseDistance, 400) // If the corpse is <= this distance from the player, it won't move +RULE_REAL(Character, ExpMultiplier, 0.5) +RULE_REAL(Character, AAExpMultiplier, 0.5) +RULE_REAL(Character, GroupExpMultiplier, 0.5) +RULE_REAL(Character, RaidExpMultiplier, 0.2) +RULE_BOOL(Character, UseXPConScaling, true) +RULE_INT(Character, LightBlueModifier, 40) +RULE_INT(Character, BlueModifier, 90) +RULE_INT(Character, WhiteModifier, 100) +RULE_INT(Character, YellowModifier, 125) +RULE_INT(Character, RedModifier, 150) +RULE_INT(Character, AutosaveIntervalS, 300) //0=disabled +RULE_INT(Character, HPRegenMultiplier, 100) +RULE_INT(Character, ManaRegenMultiplier, 100) +RULE_INT(Character, EnduranceRegenMultiplier, 100) +RULE_INT(Character, ConsumptionMultiplier, 100) //item's hunger restored = this value * item's food level, 100 = normal, 50 = people eat 2x as fast, 200 = people eat 2x as slow +RULE_BOOL(Character, HealOnLevel, false) +RULE_BOOL(Character, FeignKillsPet, false) +RULE_INT(Character, ItemManaRegenCap, 15) +RULE_INT(Character, ItemHealthRegenCap, 35) +RULE_INT(Character, ItemDamageShieldCap, 30) +RULE_INT(Character, ItemAccuracyCap, 150) +RULE_INT(Character, ItemAvoidanceCap, 100) +RULE_INT(Character, ItemCombatEffectsCap, 100) +RULE_INT(Character, ItemShieldingCap, 35) +RULE_INT(Character, ItemSpellShieldingCap, 35) +RULE_INT(Character, ItemDoTShieldingCap, 35) +RULE_INT(Character, ItemStunResistCap, 35) +RULE_INT(Character, ItemStrikethroughCap, 35) +RULE_INT(Character, ItemATKCap, 250) +RULE_INT(Character, ItemHealAmtCap, 250) +RULE_INT(Character, ItemSpellDmgCap, 250) +RULE_INT(Character, ItemClairvoyanceCap, 250) +RULE_INT(Character, ItemDSMitigationCap, 50) +RULE_INT(Character, ItemEnduranceRegenCap, 15) +RULE_INT(Character, ItemExtraDmgCap, 150) // Cap for bonuses to melee skills like Bash, Frenzy, etc +RULE_INT(Character, HasteCap, 100) // Haste cap for non-v3(overhaste) haste. +RULE_INT(Character, SkillUpModifier, 100) //skill ups are at 100% +RULE_BOOL(Character, SharedBankPlat, false) //off by default to prevent duping for now +RULE_BOOL(Character, BindAnywhere, false) +RULE_INT(Character, RestRegenPercent, 0) // Set to >0 to enable rest state bonus HP and mana regen. +RULE_INT(Character, RestRegenTimeToActivate, 30) // Time in seconds for rest state regen to kick in. +RULE_INT(Character, RestRegenRaidTimeToActivate, 300) // Time in seconds for rest state regen to kick in with a raid target. +RULE_BOOL(Character, RestRegenEndurance, false) // Whether rest regen will work for endurance or not. +RULE_INT(Character, KillsPerGroupLeadershipAA, 250) // Number of dark blues or above per Group Leadership AA +RULE_INT(Character, KillsPerRaidLeadershipAA, 250) // Number of dark blues or above per Raid Leadership AA +RULE_INT(Character, MaxFearDurationForPlayerCharacter, 4) //4 tics, each tic calculates every 6 seconds. +RULE_INT(Character, MaxCharmDurationForPlayerCharacter, 15) +RULE_INT(Character, BaseHPRegenBonusRaces, 4352) //a bitmask of race(s) that receive the regen bonus. Iksar (4096) & Troll (256) = 4352. see common/races.h for the bitmask values +RULE_BOOL(Character, SoDClientUseSoDHPManaEnd, false) // Setting this to true will allow SoD clients to use the SoD HP/Mana/End formulas and previous clients will use the old formulas +RULE_BOOL(Character, UseRaceClassExpBonuses, true) // Setting this to true will enable Class and Racial experience rate bonuses +RULE_BOOL(Character, UseOldRaceExpPenalties, false) // Setting this to true will enable racial exp penalties for Iksar, Troll, Ogre, and Barbarian, as well as the bonus for Halflings +RULE_BOOL(Character, UseOldClassExpPenalties, false) // Setting this to true will enable old class exp penalties for Paladin, SK, Ranger, Bard, Monk, Wizard, Enchanter, Magician, and Necromancer, as well as the bonus for Rogues and Warriors +RULE_BOOL(Character, RespawnFromHover, false) // Use Respawn window, or not. +RULE_INT(Character, RespawnFromHoverTimer, 300) // Respawn Window countdown timer, in SECONDS +RULE_BOOL(Character, UseNewStatsWindow, true) // New stats window shows everything +RULE_BOOL(Character, ItemCastsUseFocus, false) // If true, this allows item clickies to use focuses that have limited max levels on them +RULE_INT(Character, MinStatusForNoDropExemptions, 80) // This allows status x and higher to trade no drop items. +RULE_INT(Character, SkillCapMaxLevel, 75) // Sets the Max Level used for Skill Caps (from skill_caps table). -1 makes it use MaxLevel rule value. It is set to 75 because PEQ only has skillcaps up to that level, and grabbing the players' skill past 75 will return 0, breaking all skills past that level. This helps servers with obsurd level caps (75+ level cap) function without any modifications. +RULE_INT(Character, StatCap, 0) +RULE_BOOL(Character, CheckCursorEmptyWhenLooting, true) // If true, a player cannot loot a corpse (player or NPC) with an item on their cursor +RULE_BOOL(Character, MaintainIntoxicationAcrossZones, true) // If true, alcohol effects are maintained across zoning and logging out/in. +RULE_BOOL(Character, EnableDiscoveredItems, true) // If enabled, it enables EVENT_DISCOVER_ITEM and also saves character names and timestamps for the first time an item is discovered. +RULE_BOOL(Character, EnableXTargetting, true) // Enable Extended Targetting Window, for users with UF and later clients. +RULE_BOOL(Character, KeepLevelOverMax, false) // Don't delevel a character that has somehow gone over the level cap +RULE_INT(Character, FoodLossPerUpdate, 35) // How much food/water you lose per stamina update +RULE_INT(Character, BaseInstrumentSoftCap, 36) // Softcap for instrument mods, 36 commonly referred to as "3.6" as well. +RULE_BOOL(Character, UseSpellFileSongCap, true) // When they removed the AA that increased the cap they removed the above and just use the spell field +RULE_INT(Character, BaseRunSpeedCap, 158) // Base Run Speed Cap, on live it's 158% which will give you a runspeed of 1.580 hard capped to 225. +RULE_INT(Character, OrnamentationAugmentType, 20) //Ornamentation Augment Type RULE_REAL(Character, EnvironmentDamageMulipliter, 1) RULE_BOOL(Character, UnmemSpellsOnDeath, true) +RULE_INT(Character, TradeskillUpAlchemy, 2) // Alchemy skillup rate adjust. Lower is faster. +RULE_INT(Character, TradeskillUpBaking, 2) // Baking skillup rate adjust. Lower is faster. +RULE_INT(Character, TradeskillUpBlacksmithing, 2) // Blacksmithing skillup rate adjust. Lower is faster. +RULE_INT(Character, TradeskillUpBrewing, 3) // Brewing skillup rate adjust. Lower is faster. +RULE_INT(Character, TradeskillUpFletching, 2) // Fletching skillup rate adjust. Lower is faster. +RULE_INT(Character, TradeskillUpJewelcrafting, 2) // Jewelcrafting skillup rate adjust. Lower is faster. +RULE_INT(Character, TradeskillUpMakePoison, 2) // Make Poison skillup rate adjust. Lower is faster. +RULE_INT(Character, TradeskillUpPottery, 4) // Pottery skillup rate adjust. Lower is faster. +RULE_INT(Character, TradeskillUpResearch, 1) // Research skillup rate adjust. Lower is faster. +RULE_INT(Character, TradeskillUpTinkering, 2) // Tinkering skillup rate adjust. Lower is faster. +RULE_BOOL(Character, SpamHPUpdates, false) // if your server has stupid amounts of HP that causes client display issues, turn this on! +RULE_BOOL(Character, MarqueeHPUpdates, false) // Will show Health % in center of screen < 100% +RULE_INT(Character, IksarCommonTongue, 95) // 95 By default (live-like?) +RULE_INT(Character, OgreCommonTongue, 95) // 95 By default (live-like?) +RULE_INT(Character, TrollCommonTongue, 95) // 95 By default (live-like?) +RULE_BOOL(Character, ActiveInvSnapshots, false) // Takes a periodic snapshot of inventory contents from online players +RULE_INT(Character, InvSnapshotMinIntervalM, 180) // Minimum time (in minutes) between inventory snapshots +RULE_INT(Character, InvSnapshotMinRetryM, 30) // Time (in minutes) to re-attempt an inventory snapshot after a failure +RULE_INT(Character, InvSnapshotHistoryD, 30) // Time (in days) to keep snapshot entries +RULE_BOOL(Character, RestrictSpellScribing, false) // Restricts spell scribing to allowable races/classes of spell scroll, if true +RULE_BOOL(Character, UseStackablePickPocketing, true) // Allows stackable pickpocketed items to stack instead of only being allowed in empty inventory slots +RULE_BOOL(Character, EnableAvoidanceCap, false) +RULE_INT(Character, AvoidanceCap, 750) // 750 Is a pretty good value, seen people dodge all attacks beyond 1,000 Avoidance RULE_CATEGORY_END() -RULE_CATEGORY( Mercs ) -RULE_INT (Mercs, SuspendIntervalMS, 10000) -RULE_INT (Mercs, UpkeepIntervalMS, 180000) -RULE_INT (Mercs, SuspendIntervalS, 10) -RULE_INT (Mercs, UpkeepIntervalS, 180) -RULE_BOOL (Mercs, AllowMercs, false) -RULE_BOOL (Mercs, ChargeMercPurchaseCost, false) -RULE_BOOL (Mercs, ChargeMercUpkeepCost, false) -RULE_INT (Mercs, AggroRadius, 100) // Determines the distance from which a merc will aggro group member's target(also used to determine the distance at which a healer merc will begin healing a group member) -RULE_INT (Mercs, AggroRadiusPuller, 25) // Determines the distance from which a merc will aggro group member's target, if they have the group role of puller (also used to determine the distance at which a healer merc will begin healing a group member, if they have the group role of puller) -RULE_INT (Mercs, ResurrectRadius, 50) // Determines the distance from which a healer merc will attempt to resurrect a group member's corpse -RULE_INT (Mercs, ScaleRate, 100) +RULE_CATEGORY(Mercs) +RULE_INT(Mercs, SuspendIntervalMS, 10000) +RULE_INT(Mercs, UpkeepIntervalMS, 180000) +RULE_INT(Mercs, SuspendIntervalS, 10) +RULE_INT(Mercs, UpkeepIntervalS, 180) +RULE_BOOL(Mercs, AllowMercs, false) +RULE_BOOL(Mercs, ChargeMercPurchaseCost, false) +RULE_BOOL(Mercs, ChargeMercUpkeepCost, false) +RULE_INT(Mercs, AggroRadius, 100) // Determines the distance from which a merc will aggro group member's target(also used to determine the distance at which a healer merc will begin healing a group member) +RULE_INT(Mercs, AggroRadiusPuller, 25) // Determines the distance from which a merc will aggro group member's target, if they have the group role of puller (also used to determine the distance at which a healer merc will begin healing a group member, if they have the group role of puller) +RULE_INT(Mercs, ResurrectRadius, 50) // Determines the distance from which a healer merc will attempt to resurrect a group member's corpse +RULE_INT(Mercs, ScaleRate, 100) RULE_CATEGORY_END() -RULE_CATEGORY( Guild ) -RULE_INT ( Guild, MaxMembers, 2048 ) -RULE_BOOL ( Guild, PlayerCreationAllowed, false) // Allow players to create a guild using the window in Underfoot+ -RULE_INT ( Guild, PlayerCreationLimit, 1) // Only allow use of the UF+ window if the account has < than this number of guild leaders on it -RULE_INT ( Guild, PlayerCreationRequiredStatus, 0) // Required admin status. -RULE_INT ( Guild, PlayerCreationRequiredLevel, 0) // Required Level of the player attempting to create the guild. -RULE_INT ( Guild, PlayerCreationRequiredTime, 0) // Required Time Entitled On Account (in Minutes) to create the guild. +RULE_CATEGORY(Guild) +RULE_INT(Guild, MaxMembers, 2048) +RULE_BOOL(Guild, PlayerCreationAllowed, false) // Allow players to create a guild using the window in Underfoot+ +RULE_INT(Guild, PlayerCreationLimit, 1) // Only allow use of the UF+ window if the account has < than this number of guild leaders on it +RULE_INT(Guild, PlayerCreationRequiredStatus, 0) // Required admin status. +RULE_INT(Guild, PlayerCreationRequiredLevel, 0) // Required Level of the player attempting to create the guild. +RULE_INT(Guild, PlayerCreationRequiredTime, 0) // Required Time Entitled On Account (in Minutes) to create the guild. RULE_CATEGORY_END() -RULE_CATEGORY( Skills ) -RULE_INT ( Skills, MaxTrainTradeskills, 21 ) -RULE_BOOL ( Skills, UseLimitTradeskillSearchSkillDiff, true ) -RULE_INT ( Skills, MaxTradeskillSearchSkillDiff, 50 ) -RULE_INT ( Skills, MaxTrainSpecializations, 50 ) // Max level a GM trainer will train casting specializations -RULE_INT ( Skills, SwimmingStartValue, 100 ) -RULE_BOOL ( Skills, TrainSenseHeading, false ) -RULE_INT ( Skills, SenseHeadingStartValue, 200 ) +RULE_CATEGORY(Skills) +RULE_INT(Skills, MaxTrainTradeskills, 21) +RULE_BOOL(Skills, UseLimitTradeskillSearchSkillDiff, true) +RULE_INT(Skills, MaxTradeskillSearchSkillDiff, 50) +RULE_INT(Skills, MaxTrainSpecializations, 50) // Max level a GM trainer will train casting specializations +RULE_INT(Skills, SwimmingStartValue, 100) +RULE_BOOL(Skills, TrainSenseHeading, false) +RULE_INT(Skills, SenseHeadingStartValue, 200) RULE_CATEGORY_END() -RULE_CATEGORY( Pets ) -RULE_REAL( Pets, AttackCommandRange, 150 ) -RULE_BOOL( Pets, UnTargetableSwarmPet, false ) +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_CATEGORY_END() -RULE_CATEGORY( GM ) -RULE_INT ( GM, MinStatusToSummonItem, 250) -RULE_INT ( GM, MinStatusToZoneAnywhere, 250 ) +RULE_CATEGORY(GM) +RULE_INT(GM, MinStatusToSummonItem, 250) +RULE_INT(GM, MinStatusToZoneAnywhere, 250) RULE_CATEGORY_END() -RULE_CATEGORY( World ) -RULE_INT ( World, ZoneAutobootTimeoutMS, 60000 ) -RULE_INT ( World, ClientKeepaliveTimeoutMS, 65000 ) -RULE_BOOL ( World, UseBannedIPsTable, false ) // Toggle whether or not to check incoming client connections against the Banned_IPs table. Set this value to false to disable this feature. -RULE_BOOL ( World, EnableTutorialButton, true) -RULE_BOOL ( World, EnableReturnHomeButton, true) -RULE_INT ( World, MaxLevelForTutorial, 10) -RULE_INT ( World, TutorialZoneID, 189) -RULE_INT ( World, GuildBankZoneID, 345) -RULE_INT ( World, MinOfflineTimeToReturnHome, 21600) // 21600 seconds is 6 Hours -RULE_INT ( World, MaxClientsPerIP, -1 ) // Maximum number of clients allowed to connect per IP address if account status is < AddMaxClientsStatus. Default value: -1 (feature disabled) -RULE_INT ( World, ExemptMaxClientsStatus, -1 ) // Exempt accounts from the MaxClientsPerIP and AddMaxClientsStatus rules, if their status is >= this value. Default value: -1 (feature disabled) -RULE_INT ( World, AddMaxClientsPerIP, -1 ) // Maximum number of clients allowed to connect per IP address if account status is < ExemptMaxClientsStatus. Default value: -1 (feature disabled) -RULE_INT ( World, AddMaxClientsStatus, -1 ) // Accounts with status >= this rule will be allowed to use the amount of accounts defined in the AddMaxClientsPerIP. Default value: -1 (feature disabled) -RULE_BOOL ( World, MaxClientsSetByStatus, false) // If True, IP Limiting will be set to the status on the account as long as the status is > MaxClientsPerIP -RULE_BOOL ( World, ClearTempMerchantlist, true) // Clears temp merchant items when world boots. -RULE_BOOL ( World, DeleteStaleCorpeBackups, true) // Deletes stale corpse backups older than 2 weeks. -RULE_INT ( World, AccountSessionLimit, -1 ) //Max number of characters allowed on at once from a single account (-1 is disabled) -RULE_INT ( World, ExemptAccountLimitStatus, -1 ) //Min status required to be exempt from multi-session per account limiting (-1 is disabled) -RULE_BOOL ( World, GMAccountIPList, false) // Check ip list against GM Accounts, AntiHack GM Accounts. -RULE_INT ( World, MinGMAntiHackStatus, 1 ) //Minimum GM status to check against AntiHack list -RULE_INT ( World, SoFStartZoneID, -1 ) //Sets the Starting Zone for SoF Clients separate from Titanium Clients (-1 is disabled) -RULE_INT ( World, TitaniumStartZoneID, -1) //Sets the Starting Zone for Titanium Clients (-1 is disabled). Replaces the old method. -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_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_CATEGORY(World) +RULE_INT(World, ZoneAutobootTimeoutMS, 60000) +RULE_INT(World, ClientKeepaliveTimeoutMS, 65000) +RULE_BOOL(World, UseBannedIPsTable, false) // Toggle whether or not to check incoming client connections against the Banned_IPs table. Set this value to false to disable this feature. +RULE_BOOL(World, EnableTutorialButton, true) +RULE_BOOL(World, EnableReturnHomeButton, true) +RULE_INT(World, MaxLevelForTutorial, 10) +RULE_INT(World, TutorialZoneID, 189) +RULE_INT(World, GuildBankZoneID, 345) +RULE_INT(World, MinOfflineTimeToReturnHome, 21600) // 21600 seconds is 6 Hours +RULE_INT(World, MaxClientsPerIP, -1) // Maximum number of clients allowed to connect per IP address if account status is < AddMaxClientsStatus. Default value: -1 (feature disabled) +RULE_INT(World, ExemptMaxClientsStatus, -1) // Exempt accounts from the MaxClientsPerIP and AddMaxClientsStatus rules, if their status is >= this value. Default value: -1 (feature disabled) +RULE_INT(World, AddMaxClientsPerIP, -1) // Maximum number of clients allowed to connect per IP address if account status is < ExemptMaxClientsStatus. Default value: -1 (feature disabled) +RULE_INT(World, AddMaxClientsStatus, -1) // Accounts with status >= this rule will be allowed to use the amount of accounts defined in the AddMaxClientsPerIP. Default value: -1 (feature disabled) +RULE_BOOL(World, MaxClientsSetByStatus, false) // If True, IP Limiting will be set to the status on the account as long as the status is > MaxClientsPerIP +RULE_BOOL(World, ClearTempMerchantlist, true) // Clears temp merchant items when world boots. +RULE_BOOL(World, DeleteStaleCorpeBackups, true) // Deletes stale corpse backups older than 2 weeks. +RULE_INT(World, AccountSessionLimit, -1) //Max number of characters allowed on at once from a single account (-1 is disabled) +RULE_INT(World, ExemptAccountLimitStatus, -1) //Min status required to be exempt from multi-session per account limiting (-1 is disabled) +RULE_BOOL(World, GMAccountIPList, false) // Check ip list against GM Accounts, AntiHack GM Accounts. +RULE_INT(World, MinGMAntiHackStatus, 1) //Minimum GM status to check against AntiHack list +RULE_INT(World, SoFStartZoneID, -1) //Sets the Starting Zone for SoF Clients separate from Titanium Clients (-1 is disabled) +RULE_INT(World, TitaniumStartZoneID, -1) //Sets the Starting Zone for Titanium Clients (-1 is disabled). Replaces the old method. +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_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) RULE_INT (World, TellQueueSize, 20) RULE_CATEGORY_END() -RULE_CATEGORY( Zone ) -RULE_INT ( Zone, NPCPositonUpdateTicCount, 32 ) //ms between intervals of sending a position update to the entire zone. -RULE_INT ( Zone, ClientLinkdeadMS, 180000) //the time a client remains link dead on the server after a sudden disconnection -RULE_INT ( Zone, GraveyardTimeMS, 1200000) //ms time until a player corpse is moved to a zone's graveyard, if one is specified for the zone -RULE_BOOL ( Zone, EnableShadowrest, 1 ) // enables or disables the shadowrest zone feature for player corpses. Default is turned on. -RULE_BOOL ( Zone, UsePlayerCorpseBackups, true) // Keeps backups of player corpses. -RULE_INT ( Zone, MQWarpExemptStatus, -1 ) // Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature. -RULE_INT ( Zone, MQZoneExemptStatus, -1 ) // Required status level to exempt the MQZoneDetector. Set to -1 to disable this feature. -RULE_INT ( Zone, MQGateExemptStatus, -1 ) // Required status level to exempt the MQGateDetector. Set to -1 to disable this feature. -RULE_INT ( Zone, MQGhostExemptStatus, -1 ) // Required status level to exempt the MGhostDetector. Set to -1 to disable this feature. -RULE_BOOL ( Zone, EnableMQWarpDetector, true ) // Enable the MQWarp Detector. Set to False to disable this feature. -RULE_BOOL ( Zone, EnableMQZoneDetector, true ) // Enable the MQZone Detector. Set to False to disable this feature. -RULE_BOOL ( Zone, EnableMQGateDetector, true ) // Enable the MQGate Detector. Set to False to disable this feature. -RULE_BOOL ( Zone, EnableMQGhostDetector, true ) // Enable the MQGhost Detector. Set to False to disable this feature. -RULE_REAL ( Zone, MQWarpDetectionDistanceFactor, 9.0) //clients move at 4.4 about if in a straight line but with movement and to acct for lag we raise it a bit -RULE_BOOL ( Zone, MarkMQWarpLT, false ) -RULE_INT ( Zone, AutoShutdownDelay, 5000 ) //How long a dynamic zone stays loaded while empty -RULE_INT ( Zone, PEQZoneReuseTime, 900 ) //How long, in seconds, until you can reuse the #peqzone command. -RULE_INT ( Zone, PEQZoneDebuff1, 4454 ) //First debuff casted by #peqzone Default is Cursed Keeper's Blight. -RULE_INT ( Zone, PEQZoneDebuff2, 2209 ) //Second debuff casted by #peqzone Default is Tendrils of Apathy. -RULE_BOOL ( Zone, UsePEQZoneDebuffs, true ) //Will determine if #peqzone will debuff players or not when used. -RULE_REAL ( Zone, HotZoneBonus, 0.75 ) -RULE_INT ( Zone, ReservedInstances, 30 ) //Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running. -RULE_INT ( Zone, EbonCrystalItemID, 40902) -RULE_INT ( Zone, RadiantCrystalItemID, 40903) -RULE_BOOL ( Zone, LevelBasedEXPMods, false) // Allows you to use the level_exp_mods table in consideration to your players EXP hits -RULE_INT ( Zone, WeatherTimer, 600) // Weather timer when no duration is available -RULE_BOOL ( Zone, EnableLoggedOffReplenishments, true) -RULE_INT ( Zone, MinOfflineTimeToReplenishments, 21600) // 21600 seconds is 6 Hours +RULE_CATEGORY(Zone) +RULE_INT(Zone, NPCPositonUpdateTicCount, 32) //ms between intervals of sending a position update to the entire zone. +RULE_INT(Zone, ClientLinkdeadMS, 180000) //the time a client remains link dead on the server after a sudden disconnection +RULE_INT(Zone, GraveyardTimeMS, 1200000) //ms time until a player corpse is moved to a zone's graveyard, if one is specified for the zone +RULE_BOOL(Zone, EnableShadowrest, 1) // enables or disables the shadowrest zone feature for player corpses. Default is turned on. +RULE_BOOL(Zone, UsePlayerCorpseBackups, true) // Keeps backups of player corpses. +RULE_INT(Zone, MQWarpExemptStatus, -1) // Required status level to exempt the MQWarpDetector. Set to -1 to disable this feature. +RULE_INT(Zone, MQZoneExemptStatus, -1) // Required status level to exempt the MQZoneDetector. Set to -1 to disable this feature. +RULE_INT(Zone, MQGateExemptStatus, -1) // Required status level to exempt the MQGateDetector. Set to -1 to disable this feature. +RULE_INT(Zone, MQGhostExemptStatus, -1) // Required status level to exempt the MGhostDetector. Set to -1 to disable this feature. +RULE_BOOL(Zone, EnableMQWarpDetector, true) // Enable the MQWarp Detector. Set to False to disable this feature. +RULE_BOOL(Zone, EnableMQZoneDetector, true) // Enable the MQZone Detector. Set to False to disable this feature. +RULE_BOOL(Zone, EnableMQGateDetector, true) // Enable the MQGate Detector. Set to False to disable this feature. +RULE_BOOL(Zone, EnableMQGhostDetector, true) // Enable the MQGhost Detector. Set to False to disable this feature. +RULE_REAL(Zone, MQWarpDetectionDistanceFactor, 9.0) //clients move at 4.4 about if in a straight line but with movement and to acct for lag we raise it a bit +RULE_BOOL(Zone, MarkMQWarpLT, false) +RULE_INT(Zone, AutoShutdownDelay, 5000) //How long a dynamic zone stays loaded while empty +RULE_INT(Zone, PEQZoneReuseTime, 900) //How long, in seconds, until you can reuse the #peqzone command. +RULE_INT(Zone, PEQZoneDebuff1, 4454) //First debuff casted by #peqzone Default is Cursed Keeper's Blight. +RULE_INT(Zone, PEQZoneDebuff2, 2209) //Second debuff casted by #peqzone Default is Tendrils of Apathy. +RULE_BOOL(Zone, UsePEQZoneDebuffs, true) //Will determine if #peqzone will debuff players or not when used. +RULE_REAL(Zone, HotZoneBonus, 0.75) +RULE_INT(Zone, ReservedInstances, 30) //Will reserve this many instance ids for globals... probably not a good idea to change this while a server is running. +RULE_INT(Zone, EbonCrystalItemID, 40902) +RULE_INT(Zone, RadiantCrystalItemID, 40903) +RULE_BOOL(Zone, LevelBasedEXPMods, false) // Allows you to use the level_exp_mods table in consideration to your players EXP hits +RULE_INT(Zone, WeatherTimer, 600) // Weather timer when no duration is available +RULE_BOOL(Zone, EnableLoggedOffReplenishments, true) +RULE_INT(Zone, MinOfflineTimeToReplenishments, 21600) // 21600 seconds is 6 Hours +RULE_BOOL(Zone, UseZoneController, true) // Enables the ability to use persistent quest based zone controllers (zone_controller.pl/lua) RULE_CATEGORY_END() -RULE_CATEGORY( Map ) +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_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_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_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() -RULE_CATEGORY( Pathing ) +RULE_CATEGORY(Pathing) // Some of these rules may benefit by being made into columns in the zone table, // for instance, in dungeons, the min LOS distances could be substantially lowered. -RULE_BOOL ( Pathing, Aggro, true ) // Enable pathing for aggroed mobs. -RULE_BOOL ( Pathing, AggroReturnToGrid, true ) // Enable pathing for aggroed roaming mobs returning to their previous waypoint. -RULE_BOOL ( Pathing, Guard, true ) // Enable pathing for mobs moving to their guard point. -RULE_BOOL ( Pathing, Find, true ) // Enable pathing for FindPerson requests from the client. -RULE_BOOL ( Pathing, Fear, true ) // Enable pathing for fear -RULE_REAL ( Pathing, ZDiffThreshold, 10) // If a mob las LOS to it's target, it will run to it if the Z difference is < this. -RULE_INT ( Pathing, LOSCheckFrequency, 1000) // A mob will check for LOS to it's target this often (milliseconds). -RULE_INT ( Pathing, RouteUpdateFrequencyShort, 1000) // How often a new route will be calculated if the target has moved. -RULE_INT ( Pathing, RouteUpdateFrequencyLong, 5000) // How often a new route will be calculated if the target has moved. +RULE_BOOL(Pathing, Aggro, true) // Enable pathing for aggroed mobs. +RULE_BOOL(Pathing, AggroReturnToGrid, true) // Enable pathing for aggroed roaming mobs returning to their previous waypoint. +RULE_BOOL(Pathing, Guard, true) // Enable pathing for mobs moving to their guard point. +RULE_BOOL(Pathing, Find, true) // Enable pathing for FindPerson requests from the client. +RULE_BOOL(Pathing, Fear, true) // Enable pathing for fear +RULE_REAL(Pathing, ZDiffThreshold, 10) // If a mob las LOS to it's target, it will run to it if the Z difference is < this. +RULE_INT(Pathing, LOSCheckFrequency, 1000) // A mob will check for LOS to it's target this often (milliseconds). +RULE_INT(Pathing, RouteUpdateFrequencyShort, 1000) // How often a new route will be calculated if the target has moved. +RULE_INT(Pathing, RouteUpdateFrequencyLong, 5000) // How often a new route will be calculated if the target has moved. // When a path has a path node route and it's target changes position, if it has RouteUpdateFrequencyNodeCount or less nodes to go on it's // current path, it will recalculate it's path based on the RouteUpdateFrequencyShort timer, otherwise it will use the // RouteUpdateFrequencyLong timer. -RULE_INT ( Pathing, RouteUpdateFrequencyNodeCount, 5) -RULE_REAL ( Pathing, MinDistanceForLOSCheckShort, 40000) // (NoRoot). While following a path, only check for LOS to target within this distance. -RULE_REAL ( Pathing, MinDistanceForLOSCheckLong, 1000000) // (NoRoot). Min distance when initially attempting to acquire the target. -RULE_INT ( Pathing, MinNodesLeftForLOSCheck, 4) // Only check for LOS when we are down to this many path nodes left to run. +RULE_INT(Pathing, RouteUpdateFrequencyNodeCount, 5) +RULE_REAL(Pathing, MinDistanceForLOSCheckShort, 40000) // (NoRoot). While following a path, only check for LOS to target within this distance. +RULE_REAL(Pathing, MinDistanceForLOSCheckLong, 1000000) // (NoRoot). Min distance when initially attempting to acquire the target. +RULE_INT(Pathing, MinNodesLeftForLOSCheck, 4) // Only check for LOS when we are down to this many path nodes left to run. // This next rule was put in for situations where the mob and it's target may be on different sides of a 'hazard', e.g. a pit // If the mob has LOS to it's target, even though there is a hazard in it's way, it may break off from the node path and run at // the target, only to later detect the hazard and re-acquire a node path. Depending upon the placement of the path nodes, this // can lead to the mob looping. The rule is intended to allow the mob to at least get closer to it's target each time before // checking LOS and trying to head straight for it. -RULE_INT ( Pathing, MinNodesTraversedForLOSCheck, 3) // Only check for LOS after we have traversed this many path nodes. -RULE_INT ( Pathing, CullNodesFromStart, 1) // Checks LOS from Start point to second node for this many nodes and removes first node if there is LOS -RULE_INT ( Pathing, CullNodesFromEnd, 1) // Checks LOS from End point to second to last node for this many nodes and removes last node if there is LOS -RULE_REAL ( Pathing, CandidateNodeRangeXY, 400) // When searching for path start/end nodes, only nodes within this range will be considered. -RULE_REAL ( Pathing, CandidateNodeRangeZ, 10) // When searching for path start/end nodes, only nodes within this range will be considered. +RULE_INT(Pathing, MinNodesTraversedForLOSCheck, 3) // Only check for LOS after we have traversed this many path nodes. +RULE_INT(Pathing, CullNodesFromStart, 1) // Checks LOS from Start point to second node for this many nodes and removes first node if there is LOS +RULE_INT(Pathing, CullNodesFromEnd, 1) // Checks LOS from End point to second to last node for this many nodes and removes last node if there is LOS +RULE_REAL(Pathing, CandidateNodeRangeXY, 400) // When searching for path start/end nodes, only nodes within this range will be considered. +RULE_REAL(Pathing, CandidateNodeRangeZ, 10) // When searching for path start/end nodes, only nodes within this range will be considered. RULE_CATEGORY_END() -RULE_CATEGORY( Watermap ) +RULE_CATEGORY(Watermap) // enable these to use the water detection code. Requires Water Maps generated by awater utility -RULE_BOOL ( Watermap, CheckWaypointsInWaterWhenLoading, false ) // Does not apply BestZ as waypoints are loaded if they are in water -RULE_BOOL ( Watermap, CheckForWaterAtWaypoints, false) // Check if a mob has moved into/out of water when at waypoints and sets flymode -RULE_BOOL ( Watermap, CheckForWaterWhenMoving, false) // Checks if a mob has moved into/out of water each time it's loc is recalculated -RULE_BOOL ( Watermap, CheckForWaterOnSendTo, false) // Checks if a mob has moved into/out of water on SendTo -RULE_BOOL ( Watermap, CheckForWaterWhenFishing, false) // Only lets a player fish near water (if a water map exists for the zone) -RULE_REAL ( Watermap, FishingRodLength, 30) // How far in front of player water must be for fishing to work -RULE_REAL ( Watermap, FishingLineLength, 40) // If water is more than this far below the player, it is considered too far to fish +RULE_BOOL(Watermap, CheckWaypointsInWaterWhenLoading, false) // Does not apply BestZ as waypoints are loaded if they are in water +RULE_BOOL(Watermap, CheckForWaterAtWaypoints, false) // Check if a mob has moved into/out of water when at waypoints and sets flymode +RULE_BOOL(Watermap, CheckForWaterWhenMoving, false) // Checks if a mob has moved into/out of water each time it's loc is recalculated +RULE_BOOL(Watermap, CheckForWaterOnSendTo, false) // Checks if a mob has moved into/out of water on SendTo +RULE_BOOL(Watermap, CheckForWaterWhenFishing, false) // Only lets a player fish near water (if a water map exists for the zone) +RULE_REAL(Watermap, FishingRodLength, 30) // How far in front of player water must be for fishing to work +RULE_REAL(Watermap, FishingLineLength, 100) // If water is more than this far below the player, it is considered too far to fish +RULE_REAL(Watermap, FishingLineStepSize, 1) // Basic step size for fishing calc, too small and it will eat cpu, too large and it will miss potential water RULE_CATEGORY_END() -RULE_CATEGORY( Spells ) -RULE_INT ( Spells, AutoResistDiff, 15) -RULE_REAL ( Spells, ResistChance, 2.0) //chance to resist given no resists and same level -RULE_REAL ( Spells, ResistMod, 0.40) //multiplier, chance to resist = this * ResistAmount -RULE_REAL ( Spells, PartialHitChance, 0.7) //The chance when a spell is resisted that it will partial hit. -RULE_REAL ( Spells, PartialHitChanceFear, 0.25) //The chance when a fear spell is resisted that it will partial hit. -RULE_INT ( Spells, BaseCritChance, 0) //base % chance that everyone has to crit a spell -RULE_INT ( Spells, BaseCritRatio, 100) //base % bonus to damage on a successful spell crit. 100 = 2x damage -RULE_INT ( Spells, WizCritLevel, 12) //level wizards first get spell crits -RULE_INT ( Spells, WizCritChance, 7) //wiz's crit chance, on top of BaseCritChance -RULE_INT ( Spells, WizCritRatio, 0) //wiz's crit bonus, on top of BaseCritRatio (should be 0 for Live-like) -RULE_INT ( Spells, ResistPerLevelDiff, 85) //8.5 resist per level difference. -RULE_INT ( Spells, TranslocateTimeLimit, 0) // If not zero, time in seconds to accept a Translocate. -RULE_INT ( Spells, SacrificeMinLevel, 46) //first level Sacrifice will work on -RULE_INT ( Spells, SacrificeMaxLevel, 69) //last level Sacrifice will work on -RULE_INT ( Spells, SacrificeItemID, 9963) //Item ID of the item Sacrifice will return (defaults to an EE) -RULE_BOOL ( Spells, EnableSpellGlobals, false) // If Enabled, spells check the spell_globals table and compare character data from the quest globals before allowing that spell to scribe with scribespells -RULE_INT ( Spells, MaxBuffSlotsNPC, 25) -RULE_INT ( Spells, MaxSongSlotsNPC, 10) -RULE_INT ( Spells, MaxDiscSlotsNPC, 1) -RULE_INT ( Spells, MaxTotalSlotsNPC, 36) -RULE_INT ( Spells, MaxTotalSlotsPET, 25) // do not set this higher than 25 until the player profile is removed from the blob +RULE_CATEGORY(Spells) +RULE_INT(Spells, AutoResistDiff, 15) +RULE_REAL(Spells, ResistChance, 2.0) //chance to resist given no resists and same level +RULE_REAL(Spells, ResistMod, 0.40) //multiplier, chance to resist = this * ResistAmount +RULE_REAL(Spells, PartialHitChance, 0.7) //The chance when a spell is resisted that it will partial hit. +RULE_REAL(Spells, PartialHitChanceFear, 0.25) //The chance when a fear spell is resisted that it will partial hit. +RULE_INT(Spells, BaseCritChance, 0) //base % chance that everyone has to crit a spell +RULE_INT(Spells, BaseCritRatio, 100) //base % bonus to damage on a successful spell crit. 100 = 2x damage +RULE_INT(Spells, WizCritLevel, 12) //level wizards first get spell crits +RULE_INT(Spells, WizCritChance, 7) //wiz's crit chance, on top of BaseCritChance +RULE_INT(Spells, WizCritRatio, 0) //wiz's crit bonus, on top of BaseCritRatio (should be 0 for Live-like) +RULE_INT(Spells, ResistPerLevelDiff, 85) //8.5 resist per level difference. +RULE_INT(Spells, TranslocateTimeLimit, 0) // If not zero, time in seconds to accept a Translocate. +RULE_INT(Spells, SacrificeMinLevel, 46) //first level Sacrifice will work on +RULE_INT(Spells, SacrificeMaxLevel, 69) //last level Sacrifice will work on +RULE_INT(Spells, SacrificeItemID, 9963) //Item ID of the item Sacrifice will return (defaults to an EE) +RULE_BOOL(Spells, EnableSpellGlobals, false) // If Enabled, spells check the spell_globals table and compare character data from the quest globals before allowing that spell to scribe with scribespells +RULE_INT(Spells, MaxBuffSlotsNPC, 25) +RULE_INT(Spells, MaxSongSlotsNPC, 10) +RULE_INT(Spells, MaxDiscSlotsNPC, 1) +RULE_INT(Spells, MaxTotalSlotsNPC, 36) +RULE_INT(Spells, MaxTotalSlotsPET, 30) // do not set this higher than 25 until the player profile is removed from the blob RULE_BOOL (Spells, EnableBlockedBuffs, true) -RULE_INT ( Spells, ReflectType, 1) //0 = disabled, 1 = single target player spells only, 2 = all player spells, 3 = all single target spells, 4 = all spells -RULE_INT ( Spells, VirusSpreadDistance, 30) // The distance a viral spell will jump to its next victim -RULE_BOOL( Spells, LiveLikeFocusEffects, true) // Determines whether specific healing, dmg and mana reduction focuses are randomized -RULE_INT ( Spells, BaseImmunityLevel, 55) // The level that targets start to be immune to stun, fear and mez spells with a max level of 0. -RULE_BOOL ( Spells, NPCIgnoreBaseImmunity, true) // Whether or not NPCs get to ignore the BaseImmunityLevel for their spells. -RULE_REAL ( Spells, AvgSpellProcsPerMinute, 6.0) //Adjust rate for sympathetic spell procs -RULE_INT ( Spells, ResistFalloff, 67) //Max that level that will adjust our resist chance based on level modifiers -RULE_INT ( Spells, CharismaEffectiveness, 10) // Deterimes how much resist modification charisma applies to charm/pacify checks. Default 10 CHA = -1 resist mod. -RULE_INT ( Spells, CharismaEffectivenessCap, 255) // Deterimes how much resist modification charisma applies to charm/pacify checks. Default 10 CHA = -1 resist mod. -RULE_BOOL ( Spells, CharismaCharmDuration, false) // Allow CHA resist mod to extend charm duration. -RULE_INT ( Spells, CharmBreakCheckChance, 25) //Determines chance for a charm break check to occur each buff tick. -RULE_INT ( Spells, MaxCastTimeReduction, 50) //Max percent your spell cast time can be reduced by spell haste -RULE_INT ( Spells, RootBreakFromSpells, 55) //Chance for root to break when cast on. -RULE_INT ( Spells, DeathSaveCharismaMod, 3) //Determines how much charisma effects chance of death save firing. -RULE_INT ( Spells, DivineInterventionHeal, 8000) //Divine intervention heal amount. -RULE_INT ( Spells, AdditiveBonusWornType, 0) //Calc worn bonuses to add together (instead of taking highest) if set to THIS worn type. (2=Will covert live items automatically) -RULE_BOOL ( Spells, UseCHAScribeHack, false) //ScribeSpells and TrainDiscs quest functions will ignore entries where field 12 is CHA. What's the best way to do this? -RULE_BOOL ( Spells, BuffLevelRestrictions, true) //Buffs will not land on low level toons like live -RULE_INT ( Spells, RootBreakCheckChance, 70) //Determines chance for a root break check to occur each buff tick. -RULE_INT ( Spells, FearBreakCheckChance, 70) //Determines chance for a fear break check to occur each buff tick. -RULE_INT ( Spells, SuccorFailChance, 2) //Determines chance for a succor spell not to teleport an invidual player -RULE_INT ( Spells, FRProjectileItem_Titanium, 1113) // Item id for Titanium clients for Fire 'spell projectile'. -RULE_INT ( Spells, FRProjectileItem_SOF, 80684) // Item id for SOF clients for Fire 'spell projectile'. -RULE_INT ( Spells, FRProjectileItem_NPC, 80684) // Item id for NPC Fire 'spell projectile'. -RULE_BOOL ( Spells, UseLiveSpellProjectileGFX, false) // Use spell projectile graphics set in the spells_new table (player_1). Server must be using UF+ spell file. -RULE_BOOL ( Spells, FocusCombatProcs, false) //Allow all combat procs to receive focus effects. -RULE_BOOL ( Spells, PreNerfBardAEDoT, false) //Allow bard AOE dots to damage targets when moving. -RULE_INT ( Spells, AI_SpellCastFinishedFailRecast, 800) // AI spell recast time(MS) when an spell is cast but fails (ie stunned). -RULE_INT ( Spells, AI_EngagedNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while engaged. (min time in random) -RULE_INT ( Spells, AI_EngagedNoSpellMaxRecast, 1000) // AI spell recast time(MS) check when no spell is cast engaged.(max time in random) -RULE_INT ( Spells, AI_EngagedBeneficialSelfChance, 100) // Chance during first AI Cast check to do a beneficial spell on self. -RULE_INT ( Spells, AI_EngagedBeneficialOtherChance, 25) // Chance during second AI Cast check to do a beneficial spell on others. -RULE_INT ( Spells, AI_EngagedDetrimentalChance, 20) // Chance during third AI Cast check to do a determental spell on others. -RULE_INT ( Spells, AI_PursueNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while chasing target. (min time in random) -RULE_INT ( Spells, AI_PursueNoSpellMaxRecast, 2000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) -RULE_INT ( Spells, AI_PursueDetrimentalChance, 90) // Chance while chasing target to cast a detrimental spell. -RULE_INT ( Spells, AI_IdleNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while idle. (min time in random) -RULE_INT ( Spells, AI_IdleNoSpellMaxRecast, 2000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) -RULE_INT ( Spells, AI_IdleBeneficialChance, 100) // Chance while idle to do a beneficial spell on self or others. -RULE_BOOL ( Spells, SHDProcIDOffByOne, true) // pre June 2009 SHD spell procs were off by 1, they stopped doing this in June 2009 (so UF+ spell files need this false) -RULE_BOOL ( Spells, Jun182014HundredHandsRevamp, false) // this should be true for if you import a spell file newer than June 18, 2014 -RULE_BOOL ( Spells, SwarmPetTargetLock, false) // Use old method of swarm pets target locking till target dies then despawning. -RULE_BOOL ( Spells, NPC_UseFocusFromSpells, true) // Allow npcs to use most spell derived focus effects. -RULE_BOOL ( Spells, NPC_UseFocusFromItems, false) // Allow npcs to use most item derived focus effects. -RULE_BOOL ( Spells, UseAdditiveFocusFromWornSlot, false) // Allows an additive focus effect to be calculated from worn slot. +RULE_INT(Spells, ReflectType, 1) //0 = disabled, 1 = single target player spells only, 2 = all player spells, 3 = all single target spells, 4 = all spells +RULE_INT(Spells, VirusSpreadDistance, 30) // The distance a viral spell will jump to its next victim +RULE_BOOL(Spells, LiveLikeFocusEffects, true) // Determines whether specific healing, dmg and mana reduction focuses are randomized +RULE_INT(Spells, BaseImmunityLevel, 55) // The level that targets start to be immune to stun, fear and mez spells with a max level of 0. +RULE_BOOL(Spells, NPCIgnoreBaseImmunity, true) // Whether or not NPCs get to ignore the BaseImmunityLevel for their spells. +RULE_REAL(Spells, AvgSpellProcsPerMinute, 6.0) //Adjust rate for sympathetic spell procs +RULE_INT(Spells, ResistFalloff, 67) //Max that level that will adjust our resist chance based on level modifiers +RULE_INT(Spells, CharismaEffectiveness, 10) // Deterimes how much resist modification charisma applies to charm/pacify checks. Default 10 CHA = -1 resist mod. +RULE_INT(Spells, CharismaEffectivenessCap, 255) // Deterimes how much resist modification charisma applies to charm/pacify checks. Default 10 CHA = -1 resist mod. +RULE_BOOL(Spells, CharismaCharmDuration, false) // Allow CHA resist mod to extend charm duration. +RULE_INT(Spells, CharmBreakCheckChance, 25) //Determines chance for a charm break check to occur each buff tick. +RULE_INT(Spells, MaxCastTimeReduction, 50) //Max percent your spell cast time can be reduced by spell haste +RULE_INT(Spells, RootBreakFromSpells, 55) //Chance for root to break when cast on. +RULE_INT(Spells, DeathSaveCharismaMod, 3) //Determines how much charisma effects chance of death save firing. +RULE_INT(Spells, DivineInterventionHeal, 8000) //Divine intervention heal amount. +RULE_INT(Spells, AdditiveBonusWornType, 0) //Calc worn bonuses to add together (instead of taking highest) if set to THIS worn type. (2=Will covert live items automatically) +RULE_BOOL(Spells, UseCHAScribeHack, false) //ScribeSpells and TrainDiscs quest functions will ignore entries where field 12 is CHA. What's the best way to do this? +RULE_BOOL(Spells, BuffLevelRestrictions, true) //Buffs will not land on low level toons like live +RULE_INT(Spells, RootBreakCheckChance, 70) //Determines chance for a root break check to occur each buff tick. +RULE_INT(Spells, FearBreakCheckChance, 70) //Determines chance for a fear break check to occur each buff tick. +RULE_INT(Spells, SuccorFailChance, 2) //Determines chance for a succor spell not to teleport an invidual player +RULE_INT(Spells, FRProjectileItem_Titanium, 1113) // Item id for Titanium clients for Fire 'spell projectile'. +RULE_INT(Spells, FRProjectileItem_SOF, 80684) // Item id for SOF clients for Fire 'spell projectile'. +RULE_INT(Spells, FRProjectileItem_NPC, 80684) // Item id for NPC Fire 'spell projectile'. +RULE_BOOL(Spells, UseLiveSpellProjectileGFX, false) // Use spell projectile graphics set in the spells_new table (player_1). Server must be using UF+ spell file. +RULE_BOOL(Spells, FocusCombatProcs, false) //Allow all combat procs to receive focus effects. +RULE_BOOL(Spells, PreNerfBardAEDoT, false) //Allow bard AOE dots to damage targets when moving. +RULE_INT(Spells, AI_SpellCastFinishedFailRecast, 800) // AI spell recast time(MS) when an spell is cast but fails (ie stunned). +RULE_INT(Spells, AI_EngagedNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while engaged. (min time in random) +RULE_INT(Spells, AI_EngagedNoSpellMaxRecast, 1000) // AI spell recast time(MS) check when no spell is cast engaged.(max time in random) +RULE_INT(Spells, AI_EngagedBeneficialSelfChance, 100) // Chance during first AI Cast check to do a beneficial spell on self. +RULE_INT(Spells, AI_EngagedBeneficialOtherChance, 25) // Chance during second AI Cast check to do a beneficial spell on others. +RULE_INT(Spells, AI_EngagedDetrimentalChance, 20) // Chance during third AI Cast check to do a determental spell on others. +RULE_INT(Spells, AI_PursueNoSpellMinRecast, 500) // AI spell recast time(MS) check when no spell is cast while chasing target. (min time in random) +RULE_INT(Spells, AI_PursueNoSpellMaxRecast, 2000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) +RULE_INT(Spells, AI_PursueDetrimentalChance, 90) // Chance while chasing target to cast a detrimental spell. +RULE_INT(Spells, AI_IdleNoSpellMinRecast, 6000) // AI spell recast time(MS) check when no spell is cast while idle. (min time in random) +RULE_INT(Spells, AI_IdleNoSpellMaxRecast, 60000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random) +RULE_INT(Spells, AI_IdleBeneficialChance, 100) // Chance while idle to do a beneficial spell on self or others. +RULE_BOOL(Spells, SHDProcIDOffByOne, true) // pre June 2009 SHD spell procs were off by 1, they stopped doing this in June 2009 (so UF+ spell files need this false) +RULE_BOOL(Spells, Jun182014HundredHandsRevamp, false) // this should be true for if you import a spell file newer than June 18, 2014 +RULE_BOOL(Spells, SwarmPetTargetLock, false) // Use old method of swarm pets target locking till target dies then despawning. +RULE_BOOL(Spells, NPC_UseFocusFromSpells, true) // Allow npcs to use most spell derived focus effects. +RULE_BOOL(Spells, NPC_UseFocusFromItems, false) // Allow npcs to use most item derived focus effects. +RULE_BOOL(Spells, UseAdditiveFocusFromWornSlot, false) // Allows an additive focus effect to be calculated from worn slot. +RULE_BOOL(Spells, AlwaysSendTargetsBuffs, false) // ignore LAA level if true +RULE_BOOL(Spells, FlatItemExtraSpellAmt, false) // allow SpellDmg stat to affect all spells, regardless of cast time/cooldown/etc +RULE_BOOL(Spells, IgnoreSpellDmgLvlRestriction, false) // ignore the 5 level spread on applying SpellDmg +RULE_BOOL(Spells, AllowItemTGB, false) // TGB doesn't work with items on live, custom servers want it though RULE_CATEGORY_END() -RULE_CATEGORY( Combat ) -RULE_INT ( Combat, MeleeBaseCritChance, 0 ) //The base crit chance for non warriors, NOTE: This will apply to NPCs as well -RULE_INT ( Combat, WarBerBaseCritChance, 3 ) //The base crit chance for warriors and berserkers, only applies to clients -RULE_INT ( Combat, BerserkBaseCritChance, 6 ) //The bonus base crit chance you get when you're berserk -RULE_INT ( Combat, NPCBashKickLevel, 6 ) //The level that npcs can KICK/BASH -RULE_INT ( Combat, NPCBashKickStunChance, 15 ) //Percent chance that a bash/kick will stun -RULE_INT ( Combat, RogueCritThrowingChance, 25) //Rogue throwing crit bonus -RULE_INT ( Combat, RogueDeadlyStrikeChance, 80) //Rogue chance throwing from behind crit becomes a deadly strike -RULE_INT ( Combat, RogueDeadlyStrikeMod, 2) //Deadly strike modifier to crit damage -RULE_INT ( Combat, ClientBaseCritChance, 0 ) //The base crit chance for all clients, this will stack with warrior's/zerker's crit chance. -RULE_BOOL ( Combat, UseIntervalAC, true) -RULE_INT ( Combat, PetAttackMagicLevel, 30) -RULE_BOOL ( Combat, EnableFearPathing, true) -RULE_REAL ( Combat, FleeMultiplier, 2.0) // Determines how quickly a NPC will slow down while fleeing. Decrease multiplier to slow NPC down quicker. -RULE_INT ( Combat, FleeHPRatio, 25) //HP % when a NPC begins to flee. -RULE_BOOL ( Combat, FleeIfNotAlone, false) // If false, mobs won't flee if other mobs are in combat with it. -RULE_BOOL ( Combat, AdjustProcPerMinute, true) -RULE_REAL ( Combat, AvgProcsPerMinute, 2.0) -RULE_REAL ( Combat, ProcPerMinDexContrib, 0.075) -RULE_REAL ( Combat, BaseProcChance, 0.035) -RULE_REAL ( Combat, ProcDexDivideBy, 11000) -RULE_BOOL ( Combat, AdjustSpecialProcPerMinute, true) //Set PPM for special abilities like HeadShot (Live does this as of 4-14) -RULE_REAL ( Combat, AvgSpecialProcsPerMinute, 2.0) //Unclear what best value is atm. -RULE_REAL ( Combat, BaseHitChance, 69.0) -RULE_REAL ( Combat, NPCBonusHitChance, 26.0) -RULE_REAL ( Combat, HitFalloffMinor, 5.0) //hit will fall off up to 5% over the initial level range -RULE_REAL ( Combat, HitFalloffModerate, 7.0) //hit will fall off up to 7% over the three levels after the initial level range -RULE_REAL ( Combat, HitFalloffMajor, 50.0) //hit will fall off sharply if we're outside the minor and moderate range -RULE_REAL ( Combat, HitBonusPerLevel, 1.2) //You gain this % of hit for every level you are above your target -RULE_REAL ( Combat, WeaponSkillFalloff, 0.33) //For every weapon skill point that's not maxed you lose this % of hit -RULE_REAL ( Combat, ArcheryHitPenalty, 0.25) //Archery has a hit penalty to try to help balance it with the plethora of long term +hit modifiers for it -RULE_REAL ( Combat, AgiHitFactor, 0.01) -RULE_REAL ( Combat, MinChancetoHit, 5.0) //Minimum % chance to hit with regular melee/ranged -RULE_REAL ( Combat, MaxChancetoHit, 95.0) //Maximum % chance to hit with regular melee/ranged -RULE_INT ( Combat, MinRangedAttackDist, 25) //Minimum Distance to use Ranged Attacks -RULE_BOOL ( Combat, ArcheryBonusRequiresStationary, true) //does the 2x archery bonus chance require a stationary npc -RULE_REAL ( Combat, ArcheryBaseDamageBonus, 1) // % Modifier to Base Archery Damage (.5 = 50% base damage, 1 = 100%, 2 = 200%) -RULE_REAL ( Combat, ArcheryNPCMultiplier, 1.0) // this is multiplied by the regular dmg to get the archery dmg -RULE_BOOL ( Combat, AssistNoTargetSelf, true) //when assisting a target that does not have a target: true = target self, false = leave target as was before assist (false = live like) -RULE_INT ( Combat, MaxRampageTargets, 3) //max number of people hit with rampage -RULE_INT ( Combat, DefaultRampageTargets, 1) // default number of people to hit with rampage -RULE_BOOL ( Combat, RampageHitsTarget, false) // rampage will hit the target if it still has targets left -RULE_INT ( Combat, MaxFlurryHits, 2) //max number of extra hits from flurry -RULE_INT ( Combat, MonkDamageTableBonus, 5) //% bonus monks get to their damage table calcs -RULE_INT ( Combat, FlyingKickBonus, 25) //% Modifier that this skill gets to str and skill bonuses -RULE_INT ( Combat, DragonPunchBonus, 20) //% Modifier that this skill gets to str and skill bonuses -RULE_INT ( Combat, EagleStrikeBonus, 15) //% Modifier that this skill gets to str and skill bonuses -RULE_INT ( Combat, TigerClawBonus, 10) //% Modifier that this skill gets to str and skill bonuses -RULE_INT ( Combat, RoundKickBonus, 5) //% Modifier that this skill gets to str and skill bonuses -RULE_INT ( Combat, FrenzyBonus, 0) //% Modifier to damage -RULE_BOOL ( Combat, ProcTargetOnly, true) //true = procs will only affect our target, false = procs will affect all of our targets -RULE_REAL ( Combat, NPCACFactor, 2.25) -RULE_INT ( Combat, ClothACSoftcap, 75) -RULE_INT ( Combat, LeatherACSoftcap, 100) -RULE_INT ( Combat, MonkACSoftcap, 120) -RULE_INT ( Combat, ChainACSoftcap, 200) -RULE_INT ( Combat, PlateACSoftcap, 300) -RULE_REAL ( Combat, AAMitigationACFactor, 3.0) -RULE_REAL ( Combat, WarriorACSoftcapReturn, 0.45) -RULE_REAL ( Combat, KnightACSoftcapReturn, 0.33) -RULE_REAL ( Combat, LowPlateChainACSoftcapReturn, 0.23) -RULE_REAL ( Combat, LowChainLeatherACSoftcapReturn, 0.17) -RULE_REAL ( Combat, CasterACSoftcapReturn, 0.06) -RULE_REAL ( Combat, MiscACSoftcapReturn, 0.3) -RULE_BOOL ( Combat, OldACSoftcapRules, false) // use old softcaps -RULE_BOOL ( Combat, UseOldDamageIntervalRules, false) // use old damage formulas for everything -RULE_REAL ( Combat, WarACSoftcapReturn, 0.3448) // new AC returns -RULE_REAL ( Combat, ClrRngMnkBrdACSoftcapReturn, 0.3030) -RULE_REAL ( Combat, PalShdACSoftcapReturn, 0.3226) -RULE_REAL ( Combat, DruNecWizEncMagACSoftcapReturn, 0.2000) -RULE_REAL ( Combat, RogShmBstBerACSoftcapReturn, 0.2500) -RULE_REAL ( Combat, SoftcapFactor, 1.88) -RULE_REAL ( Combat, ACthac0Factor, 0.55) -RULE_REAL ( Combat, ACthac20Factor, 0.55) -RULE_INT ( Combat, HitCapPre20, 40) // live has it capped at 40 for whatever dumb reason... this is mainly for custom servers -RULE_INT ( Combat, HitCapPre10, 20) // live has it capped at 20, see above :p -RULE_INT ( Combat, MinHastedDelay, 400) // how fast we can get with haste. -RULE_REAL ( Combat, AvgDefProcsPerMinute, 2.0) -RULE_REAL ( Combat, DefProcPerMinAgiContrib, 0.075) //How much agility contributes to defensive proc rate -RULE_INT ( Combat, SpecialAttackACBonus, 15) //Percent amount of damage per AC gained for certain special attacks (damage = AC*SpecialAttackACBonus/100). -RULE_INT ( Combat, NPCFlurryChance, 20) // Chance for NPC to flurry. +RULE_CATEGORY(Combat) +RULE_INT(Combat, MeleeBaseCritChance, 0) //The base crit chance for non warriors, NOTE: This will apply to NPCs as well +RULE_INT(Combat, WarBerBaseCritChance, 3) //The base crit chance for warriors and berserkers, only applies to clients +RULE_INT(Combat, BerserkBaseCritChance, 6) //The bonus base crit chance you get when you're berserk +RULE_INT(Combat, NPCBashKickLevel, 6) //The level that npcs can KICK/BASH +RULE_INT(Combat, NPCBashKickStunChance, 15) //Percent chance that a bash/kick will stun +RULE_INT(Combat, RogueCritThrowingChance, 25) //Rogue throwing crit bonus +RULE_INT(Combat, RogueDeadlyStrikeChance, 80) //Rogue chance throwing from behind crit becomes a deadly strike +RULE_INT(Combat, RogueDeadlyStrikeMod, 2) //Deadly strike modifier to crit damage +RULE_INT(Combat, ClientBaseCritChance, 0) //The base crit chance for all clients, this will stack with warrior's/zerker's crit chance. +RULE_BOOL(Combat, UseIntervalAC, true) +RULE_INT(Combat, PetAttackMagicLevel, 30) +RULE_BOOL(Combat, EnableFearPathing, true) +RULE_REAL(Combat, FleeMultiplier, 2.0) // Determines how quickly a NPC will slow down while fleeing. Decrease multiplier to slow NPC down quicker. +RULE_INT(Combat, FleeHPRatio, 25) //HP % when a NPC begins to flee. +RULE_BOOL(Combat, FleeIfNotAlone, false) // If false, mobs won't flee if other mobs are in combat with it. +RULE_BOOL(Combat, AdjustProcPerMinute, true) +RULE_REAL(Combat, AvgProcsPerMinute, 2.0) +RULE_REAL(Combat, ProcPerMinDexContrib, 0.075) +RULE_REAL(Combat, BaseProcChance, 0.035) +RULE_REAL(Combat, ProcDexDivideBy, 11000) +RULE_BOOL(Combat, AdjustSpecialProcPerMinute, true) //Set PPM for special abilities like HeadShot (Live does this as of 4-14) +RULE_REAL(Combat, AvgSpecialProcsPerMinute, 2.0) //Unclear what best value is atm. +RULE_REAL(Combat, BaseHitChance, 69.0) +RULE_REAL(Combat, NPCBonusHitChance, 26.0) +RULE_REAL(Combat, HitFalloffMinor, 5.0) //hit will fall off up to 5% over the initial level range +RULE_REAL(Combat, HitFalloffModerate, 7.0) //hit will fall off up to 7% over the three levels after the initial level range +RULE_REAL(Combat, HitFalloffMajor, 50.0) //hit will fall off sharply if we're outside the minor and moderate range +RULE_REAL(Combat, HitBonusPerLevel, 1.2) //You gain this % of hit for every level you are above your target +RULE_REAL(Combat, WeaponSkillFalloff, 0.33) //For every weapon skill point that's not maxed you lose this % of hit +RULE_REAL(Combat, ArcheryHitPenalty, 0.25) //Archery has a hit penalty to try to help balance it with the plethora of long term +hit modifiers for it +RULE_REAL(Combat, AgiHitFactor, 0.01) +RULE_REAL(Combat, MinChancetoHit, 5.0) //Minimum % chance to hit with regular melee/ranged +RULE_REAL(Combat, MaxChancetoHit, 95.0) //Maximum % chance to hit with regular melee/ranged +RULE_INT(Combat, MinRangedAttackDist, 25) //Minimum Distance to use Ranged Attacks +RULE_BOOL(Combat, ArcheryBonusRequiresStationary, true) //does the 2x archery bonus chance require a stationary npc +RULE_REAL(Combat, ArcheryBaseDamageBonus, 1) // % Modifier to Base Archery Damage (.5 = 50% base damage, 1 = 100%, 2 = 200%) +RULE_REAL(Combat, ArcheryNPCMultiplier, 1.0) // this is multiplied by the regular dmg to get the archery dmg +RULE_BOOL(Combat, AssistNoTargetSelf, true) //when assisting a target that does not have a target: true = target self, false = leave target as was before assist (false = live like) +RULE_INT(Combat, MaxRampageTargets, 3) //max number of people hit with rampage +RULE_INT(Combat, DefaultRampageTargets, 1) // default number of people to hit with rampage +RULE_BOOL(Combat, RampageHitsTarget, false) // rampage will hit the target if it still has targets left +RULE_INT(Combat, MaxFlurryHits, 2) //max number of extra hits from flurry +RULE_INT(Combat, MonkDamageTableBonus, 5) //% bonus monks get to their damage table calcs +RULE_INT(Combat, FlyingKickBonus, 25) //% Modifier that this skill gets to str and skill bonuses +RULE_INT(Combat, DragonPunchBonus, 20) //% Modifier that this skill gets to str and skill bonuses +RULE_INT(Combat, EagleStrikeBonus, 15) //% Modifier that this skill gets to str and skill bonuses +RULE_INT(Combat, TigerClawBonus, 10) //% Modifier that this skill gets to str and skill bonuses +RULE_INT(Combat, RoundKickBonus, 5) //% Modifier that this skill gets to str and skill bonuses +RULE_INT(Combat, FrenzyBonus, 0) //% Modifier to damage +RULE_INT(Combat, BackstabBonus, 0) //% Modifier to damage +RULE_BOOL(Combat, ProcTargetOnly, true) //true = procs will only affect our target, false = procs will affect all of our targets +RULE_REAL(Combat, NPCACFactor, 2.25) +RULE_INT(Combat, ClothACSoftcap, 75) +RULE_INT(Combat, LeatherACSoftcap, 100) +RULE_INT(Combat, MonkACSoftcap, 120) +RULE_INT(Combat, ChainACSoftcap, 200) +RULE_INT(Combat, PlateACSoftcap, 300) +RULE_REAL(Combat, AAMitigationACFactor, 3.0) +RULE_REAL(Combat, WarriorACSoftcapReturn, 0.45) +RULE_REAL(Combat, KnightACSoftcapReturn, 0.33) +RULE_REAL(Combat, LowPlateChainACSoftcapReturn, 0.23) +RULE_REAL(Combat, LowChainLeatherACSoftcapReturn, 0.17) +RULE_REAL(Combat, CasterACSoftcapReturn, 0.06) +RULE_REAL(Combat, MiscACSoftcapReturn, 0.3) +RULE_BOOL(Combat, OldACSoftcapRules, false) // use old softcaps +RULE_BOOL(Combat, UseOldDamageIntervalRules, false) // use old damage formulas for everything +RULE_REAL(Combat, WarACSoftcapReturn, 0.3448) // new AC returns +RULE_REAL(Combat, ClrRngMnkBrdACSoftcapReturn, 0.3030) +RULE_REAL(Combat, PalShdACSoftcapReturn, 0.3226) +RULE_REAL(Combat, DruNecWizEncMagACSoftcapReturn, 0.2000) +RULE_REAL(Combat, RogShmBstBerACSoftcapReturn, 0.2500) +RULE_REAL(Combat, SoftcapFactor, 1.88) +RULE_REAL(Combat, ACthac0Factor, 0.55) +RULE_REAL(Combat, ACthac20Factor, 0.55) +RULE_INT(Combat, HitCapPre20, 40) // live has it capped at 40 for whatever dumb reason... this is mainly for custom servers +RULE_INT(Combat, HitCapPre10, 20) // live has it capped at 20, see above :p +RULE_INT(Combat, MinHastedDelay, 400) // how fast we can get with haste. +RULE_REAL(Combat, AvgDefProcsPerMinute, 2.0) +RULE_REAL(Combat, DefProcPerMinAgiContrib, 0.075) //How much agility contributes to defensive proc rate +RULE_INT(Combat, SpecialAttackACBonus, 15) //Percent amount of damage per AC gained for certain special attacks (damage = AC*SpecialAttackACBonus/100). +RULE_INT(Combat, NPCFlurryChance, 20) // Chance for NPC to flurry. RULE_BOOL (Combat,TauntOverLevel, 1) //Allows you to taunt NPC's over warriors level. RULE_REAL (Combat,TauntSkillFalloff, 0.33)//For every taunt skill point that's not maxed you lose this % chance to taunt. RULE_BOOL (Combat,EXPFromDmgShield, false) //Determine if damage from a damage shield counts for EXP gain. -RULE_INT ( Combat, MonkACBonusWeight, 15) -RULE_INT ( Combat, ClientStunLevel, 55) //This is the level where client kicks and bashes can stun the target -RULE_INT ( Combat, QuiverWRHasteDiv, 3) //Weight Reduction is divided by this to get haste contribution for quivers -RULE_BOOL ( Combat, UseArcheryBonusRoll, false) //Make the 51+ archery bonus require an actual roll -RULE_INT ( Combat, ArcheryBonusChance, 50) -RULE_INT ( Combat, BerserkerFrenzyStart, 35) -RULE_INT ( Combat, BerserkerFrenzyEnd, 45) -RULE_BOOL ( Combat, OneProcPerWeapon, true) //If enabled, One proc per weapon per round -RULE_BOOL ( Combat, ProjectileDmgOnImpact, true) //If enabled, projectiles (ie arrows) will hit on impact, instead of instantly. +RULE_INT(Combat, MonkACBonusWeight, 15) +RULE_INT(Combat, ClientStunLevel, 55) //This is the level where client kicks and bashes can stun the target +RULE_INT(Combat, QuiverHasteCap, 1000) //Quiver haste cap 1000 on live for a while, currently 700 on live +RULE_BOOL(Combat, UseArcheryBonusRoll, false) //Make the 51+ archery bonus require an actual roll +RULE_INT(Combat, ArcheryBonusChance, 50) +RULE_INT(Combat, BerserkerFrenzyStart, 35) +RULE_INT(Combat, BerserkerFrenzyEnd, 45) +RULE_BOOL(Combat, OneProcPerWeapon, true) //If enabled, One proc per weapon per round +RULE_BOOL(Combat, ProjectileDmgOnImpact, true) //If enabled, projectiles (ie arrows) will hit on impact, instead of instantly. +RULE_BOOL(Combat, MeleePush, true) // enable melee push +RULE_INT(Combat, MeleePushChance, 50) // (NPCs) chance the target will be pushed. Made up, 100 actually isn't that bad +RULE_BOOL(Combat, UseLiveCombatRounds, true) // turn this false if you don't want to worry about fixing up combat rounds for NPCs +RULE_INT(Combat, NPCAssistCap, 5) // Maxiumium number of NPCs that will assist another NPC at once +RULE_INT(Combat, NPCAssistCapTimer, 6000) // Time in milliseconds a NPC will take to clear assist aggro cap space +RULE_BOOL(Combat, UseRevampHandToHand, false) // use h2h revamped dmg/delays I believe this was implemented during SoF RULE_CATEGORY_END() -RULE_CATEGORY( NPC ) -RULE_INT ( NPC, MinorNPCCorpseDecayTimeMS, 450000 ) //level<55 -RULE_INT ( NPC, MajorNPCCorpseDecayTimeMS, 1500000 ) //level>=55 -RULE_INT ( NPC, CorpseUnlockTimer, 150000 ) -RULE_INT ( NPC, EmptyNPCCorpseDecayTimeMS, 0 ) +RULE_CATEGORY(NPC) +RULE_INT(NPC, MinorNPCCorpseDecayTimeMS, 450000) //level<55 +RULE_INT(NPC, MajorNPCCorpseDecayTimeMS, 1500000) //level>=55 +RULE_INT(NPC, CorpseUnlockTimer, 150000) +RULE_INT(NPC, EmptyNPCCorpseDecayTimeMS, 0) RULE_BOOL (NPC, UseItemBonusesForNonPets, true) -RULE_INT ( NPC, SayPauseTimeInSec, 5) -RULE_INT ( NPC, OOCRegen, 0) -RULE_BOOL ( NPC, BuffFriends, false ) -RULE_BOOL ( NPC, EnableNPCQuestJournal, false) -RULE_INT ( NPC, LastFightingDelayMovingMin, 10000) -RULE_INT ( NPC, LastFightingDelayMovingMax, 20000) -RULE_BOOL ( NPC, SmartLastFightingDelayMoving, true) -RULE_BOOL ( NPC, ReturnNonQuestNoDropItems, false) // Returns NO DROP items on NPCs that don't have an EVENT_TRADE sub in their script -RULE_INT ( NPC, StartEnrageValue, 9) // % HP that an NPC will begin to enrage -RULE_BOOL ( NPC, LiveLikeEnrage, false) // If set to true then only player controlled pets will enrage -RULE_BOOL ( NPC, EnableMeritBasedFaction, false) // If set to true, faction will given in the same way as experience (solo/group/raid) +RULE_INT(NPC, SayPauseTimeInSec, 5) +RULE_INT(NPC, OOCRegen, 0) +RULE_BOOL(NPC, BuffFriends, false) +RULE_BOOL(NPC, EnableNPCQuestJournal, false) +RULE_INT(NPC, LastFightingDelayMovingMin, 10000) +RULE_INT(NPC, LastFightingDelayMovingMax, 20000) +RULE_BOOL(NPC, SmartLastFightingDelayMoving, true) +RULE_BOOL(NPC, ReturnNonQuestNoDropItems, false) // Returns NO DROP items on NPCs that don't have an EVENT_TRADE sub in their script +RULE_INT(NPC, StartEnrageValue, 9) // % HP that an NPC will begin to enrage +RULE_BOOL(NPC, LiveLikeEnrage, false) // If set to true then only player controlled pets will enrage +RULE_BOOL(NPC, EnableMeritBasedFaction, false) // If set to true, faction will given in the same way as experience (solo/group/raid) +RULE_INT(NPC, NPCToNPCAggroTimerMin, 500) +RULE_INT(NPC, NPCToNPCAggroTimerMax, 6000) +RULE_BOOL(NPC, UseClassAsLastName, true) // Uses class archetype as LastName for npcs with none +RULE_BOOL(NPC, NewLevelScaling, true) // Better level scaling, use old if new formulas would break your server RULE_CATEGORY_END() -RULE_CATEGORY ( Aggro ) -RULE_BOOL ( Aggro, SmartAggroList, true ) -RULE_INT ( Aggro, SittingAggroMod, 35 ) //35% -RULE_INT ( Aggro, MeleeRangeAggroMod, 10 ) //10% -RULE_INT ( Aggro, CurrentTargetAggroMod, 0 ) //0% -- will prefer our current target to any other; makes it harder for our npcs to switch targets. -RULE_INT ( Aggro, CriticallyWoundedAggroMod, 100 ) //100% -RULE_INT ( Aggro, SpellAggroMod, 100 ) -RULE_INT ( Aggro, SongAggroMod, 33 ) -RULE_INT ( Aggro, PetSpellAggroMod, 10 ) -RULE_REAL ( Aggro, TunnelVisionAggroMod, 0.75 ) //people not currently the top hate generate this much hate on a Tunnel Vision mob -RULE_INT ( Aggro, MaxStunProcAggro, 400 ) // Set to -1 for no limit. Maxmimum amount of aggro that a stun based proc will add. -RULE_INT ( Aggro, IntAggroThreshold, 75 ) // Int <= this will aggro regardless of level difference. +RULE_CATEGORY(Aggro) +RULE_BOOL(Aggro, SmartAggroList, true) +RULE_INT(Aggro, SittingAggroMod, 35) //35% +RULE_INT(Aggro, MeleeRangeAggroMod, 10) //10% +RULE_INT(Aggro, CurrentTargetAggroMod, 0) //0% -- will prefer our current target to any other; makes it harder for our npcs to switch targets. +RULE_INT(Aggro, CriticallyWoundedAggroMod, 100) //100% +RULE_INT(Aggro, SpellAggroMod, 100) +RULE_INT(Aggro, SongAggroMod, 33) +RULE_INT(Aggro, PetSpellAggroMod, 10) +RULE_REAL(Aggro, TunnelVisionAggroMod, 0.75) //people not currently the top hate generate this much hate on a Tunnel Vision mob +RULE_INT(Aggro, MaxScalingProcAggro, 400) // Set to -1 for no limit. Maxmimum amount of aggro that HP scaling SPA effect in a proc will add. +RULE_INT(Aggro, IntAggroThreshold, 75) // Int <= this will aggro regardless of level difference. +RULE_BOOL(Aggro, AllowTickPulling, false) // tick pulling is an exploit in an NPC's call for help fixed sometime in 2006 on live +RULE_BOOL(Aggro, UseLevelAggro, true) // Level 18+ and Undead will aggro regardless of level difference. (this will disabled Rule:IntAggroThreshold if set to true) RULE_CATEGORY_END() -RULE_CATEGORY ( TaskSystem) -RULE_BOOL ( TaskSystem, EnableTaskSystem, true) // Globally enable or disable the Task system -RULE_INT ( TaskSystem, PeriodicCheckTimer, 5) // Seconds between checks for failed tasks. Also used by the 'Touch' activity -RULE_BOOL ( TaskSystem, RecordCompletedTasks, true) -RULE_BOOL ( TaskSystem, RecordCompletedOptionalActivities, false) -RULE_BOOL ( TaskSystem, KeepOneRecordPerCompletedTask, true) -RULE_BOOL ( TaskSystem, EnableTaskProximity, true) +RULE_CATEGORY(TaskSystem) +RULE_BOOL(TaskSystem, EnableTaskSystem, true) // Globally enable or disable the Task system +RULE_INT(TaskSystem, PeriodicCheckTimer, 5) // Seconds between checks for failed tasks. Also used by the 'Touch' activity +RULE_BOOL(TaskSystem, RecordCompletedTasks, true) +RULE_BOOL(TaskSystem, RecordCompletedOptionalActivities, false) +RULE_BOOL(TaskSystem, KeepOneRecordPerCompletedTask, true) +RULE_BOOL(TaskSystem, EnableTaskProximity, true) RULE_CATEGORY_END() #ifdef BOTS -RULE_CATEGORY ( Bots ) -RULE_REAL ( Bots, BotManaRegen, 2.0 ) // Adjust mana regen for bots, 1 is fast and higher numbers slow it down 3 is about the same as players. -RULE_BOOL ( Bots, BotFinishBuffing, false ) // Allow for buffs to complete even if the bot caster is out of mana. Only affects buffing out of combat. -RULE_INT ( Bots, CreateBotCount, 150 ) // Number of bots that each account can create -RULE_INT ( Bots, SpawnBotCount, 71 ) // Number of bots a character can have spawned at one time, You + 71 bots is a 12 group raid -RULE_BOOL ( Bots, BotQuest, false ) // Optional quest method to manage bot spawn limits using the quest_globals name bot_spawn_limit, see: /bazaar/Aediles_Thrall.pl -RULE_BOOL ( Bots, BotGroupBuffing, false ) // Bots will cast single target buffs as group buffs, default is false for single. Does not make single target buffs work for MGB. -RULE_BOOL ( Bots, BotSpellQuest, false ) // Anita Thrall's (Anita_Thrall.pl) Bot Spell Scriber quests. -RULE_INT ( Bots, BotAAExpansion, 8 ) // Bots get AAs through this expansion -RULE_BOOL ( Bots, BotGroupXP, false ) // Determines whether client gets xp for bots outside their group. -RULE_BOOL ( Bots, BotBardUseOutOfCombatSongs, true) // Determines whether bard bots use additional out of combat songs. -RULE_BOOL ( Bots, BotLevelsWithOwner, false) // Auto-updates spawned bots as owner levels/de-levels (false is original behavior) +RULE_CATEGORY(Bots) +RULE_INT(Bots, AAExpansion, 8) // Bots get AAs through this expansion +RULE_BOOL(Bots, AllowCamelCaseNames, false) // Allows the use of 'MyBot' type names +RULE_INT(Bots, CommandSpellRank, 1) // Filters bot command spells by rank (1, 2 and 3 are valid filters - any other number allows all ranks) +RULE_INT(Bots, CreationLimit, 150) // Number of bots that each account can create +RULE_BOOL(Bots, FinishBuffing, false) // Allow for buffs to complete even if the bot caster is out of mana. Only affects buffing out of combat. +RULE_BOOL(Bots, GroupBuffing, false) // Bots will cast single target buffs as group buffs, default is false for single. Does not make single target buffs work for MGB. +RULE_INT(Bots, HealRotationMaxMembers, 24) // Maximum number of heal rotation members +RULE_INT(Bots, HealRotationMaxTargets, 12) // Maximum number of heal rotation targets +RULE_REAL(Bots, ManaRegen, 2.0) // Adjust mana regen for bots, 1 is fast and higher numbers slow it down 3 is about the same as players. +RULE_BOOL(Bots, PreferNoManaCommandSpells, true) // Give sorting priority to newer no-mana spells (i.e., 'Bind Affinity') +RULE_BOOL(Bots, QuestableSpawnLimit, false) // Optional quest method to manage bot spawn limits using the quest_globals name bot_spawn_limit, see: /bazaar/Aediles_Thrall.pl +RULE_BOOL(Bots, QuestableSpells, false) // Anita Thrall's (Anita_Thrall.pl) Bot Spell Scriber quests. +RULE_INT(Bots, SpawnLimit, 71) // Number of bots a character can have spawned at one time, You + 71 bots is a 12 group raid +RULE_BOOL(Bots, BotGroupXP, false) // Determines whether client gets xp for bots outside their group. +RULE_BOOL(Bots, BotBardUseOutOfCombatSongs, true) // Determines whether bard bots use additional out of combat songs (optional script) +RULE_BOOL(Bots, BotLevelsWithOwner, false) // Auto-updates spawned bots as owner levels/de-levels (false is original behavior) +RULE_BOOL(Bots, BotCharacterLevelEnabled, false) // Enables required level to spawn bots +RULE_INT(Bots, BotCharacterLevel, 0) // 0 as default (if level > this value you can spawn bots if BotCharacterLevelEnabled is true) RULE_CATEGORY_END() #endif -RULE_CATEGORY ( Chat ) -RULE_BOOL ( Chat, ServerWideOOC, true) -RULE_BOOL ( Chat, ServerWideAuction, true) -RULE_BOOL ( Chat, EnableVoiceMacros, true) -RULE_BOOL ( Chat, EnableMailKeyIPVerification, true) -RULE_BOOL ( Chat, EnableAntiSpam, true) -RULE_BOOL ( Chat, SuppressCommandErrors, false) // Do not suppress by default -RULE_INT ( Chat, MinStatusToBypassAntiSpam, 100) -RULE_INT ( Chat, MinimumMessagesPerInterval, 4) -RULE_INT ( Chat, MaximumMessagesPerInterval, 12) -RULE_INT ( Chat, MaxMessagesBeforeKick, 20) -RULE_INT ( Chat, IntervalDurationMS, 60000) -RULE_INT ( Chat, KarmaUpdateIntervalMS, 1200000) -RULE_INT ( Chat, KarmaGlobalChatLimit, 72) //amount of karma you need to be able to talk in ooc/auction/chat below the level limit -RULE_INT ( Chat, GlobalChatLevelLimit, 8) //level limit you need to of reached to talk in ooc/auction/chat if your karma is too low. +RULE_CATEGORY(Chat) +RULE_BOOL(Chat, ServerWideOOC, true) +RULE_BOOL(Chat, ServerWideAuction, true) +RULE_BOOL(Chat, EnableVoiceMacros, true) +RULE_BOOL(Chat, EnableMailKeyIPVerification, true) +RULE_BOOL(Chat, EnableAntiSpam, true) +RULE_BOOL(Chat, SuppressCommandErrors, false) // Do not suppress by default +RULE_INT(Chat, MinStatusToBypassAntiSpam, 100) +RULE_INT(Chat, MinimumMessagesPerInterval, 4) +RULE_INT(Chat, MaximumMessagesPerInterval, 12) +RULE_INT(Chat, MaxMessagesBeforeKick, 20) +RULE_INT(Chat, IntervalDurationMS, 60000) +RULE_INT(Chat, KarmaUpdateIntervalMS, 1200000) +RULE_INT(Chat, KarmaGlobalChatLimit, 72) //amount of karma you need to be able to talk in ooc/auction/chat below the level limit +RULE_INT(Chat, GlobalChatLevelLimit, 8) //level limit you need to of reached to talk in ooc/auction/chat if your karma is too low. RULE_CATEGORY_END() -RULE_CATEGORY ( Merchant ) -RULE_BOOL ( Merchant, UsePriceMod, true) // Use faction/charisma price modifiers. -RULE_REAL ( Merchant, SellCostMod, 1.05) // Modifier for NPC sell price. -RULE_REAL ( Merchant, BuyCostMod, 0.95) // Modifier for NPC buy price. -RULE_INT ( Merchant, PriceBonusPct, 4) // Determines maximum price bonus from having good faction/CHA. Value is a percent. -RULE_INT ( Merchant, PricePenaltyPct, 4) // Determines maximum price penalty from having bad faction/CHA. Value is a percent. -RULE_REAL( Merchant, ChaBonusMod, 3.45) // Determines CHA cap, from 104 CHA. 3.45 is 132 CHA at apprehensive. 0.34 is 400 CHA at apprehensive. -RULE_REAL ( Merchant, ChaPenaltyMod, 1.52) // Determines CHA bottom, up to 102 CHA. 1.52 is 37 CHA at apprehensive. 0.98 is 0 CHA at apprehensive. -RULE_BOOL ( Merchant, EnableAltCurrencySell, true) // Enables the ability to resell items to alternate currency merchants +RULE_CATEGORY(Merchant) +RULE_BOOL(Merchant, UsePriceMod, true) // Use faction/charisma price modifiers. +RULE_REAL(Merchant, SellCostMod, 1.05) // Modifier for NPC sell price. +RULE_REAL(Merchant, BuyCostMod, 0.95) // Modifier for NPC buy price. +RULE_INT(Merchant, PriceBonusPct, 4) // Determines maximum price bonus from having good faction/CHA. Value is a percent. +RULE_INT(Merchant, PricePenaltyPct, 4) // Determines maximum price penalty from having bad faction/CHA. Value is a percent. +RULE_REAL(Merchant, ChaBonusMod, 3.45) // Determines CHA cap, from 104 CHA. 3.45 is 132 CHA at apprehensive. 0.34 is 400 CHA at apprehensive. +RULE_REAL(Merchant, ChaPenaltyMod, 1.52) // Determines CHA bottom, up to 102 CHA. 1.52 is 37 CHA at apprehensive. 0.98 is 0 CHA at apprehensive. +RULE_BOOL(Merchant, EnableAltCurrencySell, true) // Enables the ability to resell items to alternate currency merchants RULE_CATEGORY_END() -RULE_CATEGORY ( Bazaar ) -RULE_BOOL ( Bazaar, AuditTrail, false) -RULE_INT ( Bazaar, MaxSearchResults, 50) -RULE_BOOL ( Bazaar, EnableWarpToTrader, true) -RULE_INT ( Bazaar, MaxBarterSearchResults, 200) // The max results returned in the /barter search +RULE_CATEGORY(Bazaar) +RULE_BOOL(Bazaar, AuditTrail, false) +RULE_INT(Bazaar, MaxSearchResults, 50) +RULE_BOOL(Bazaar, EnableWarpToTrader, true) +RULE_INT(Bazaar, MaxBarterSearchResults, 200) // The max results returned in the /barter search RULE_CATEGORY_END() -RULE_CATEGORY ( Mail ) -RULE_BOOL ( Mail, EnableMailSystem, true) // If false, client won't bring up the Mail window. -RULE_INT ( Mail, ExpireTrash, 0) // Time in seconds. 0 will delete all messages in the trash when the mailserver starts -RULE_INT ( Mail, ExpireRead, 31536000 ) // 1 Year. Set to -1 for never -RULE_INT ( Mail, ExpireUnread, 31536000 ) // 1 Year. Set to -1 for never +RULE_CATEGORY(Mail) +RULE_BOOL(Mail, EnableMailSystem, true) // If false, client won't bring up the Mail window. +RULE_INT(Mail, ExpireTrash, 0) // Time in seconds. 0 will delete all messages in the trash when the mailserver starts +RULE_INT(Mail, ExpireRead, 31536000) // 1 Year. Set to -1 for never +RULE_INT(Mail, ExpireUnread, 31536000) // 1 Year. Set to -1 for never RULE_CATEGORY_END() -RULE_CATEGORY ( Channels ) -RULE_INT ( Channels, RequiredStatusAdmin, 251) // Required status to administer chat channels -RULE_INT ( Channels, RequiredStatusListAll, 251) // Required status to list all chat channels -RULE_INT ( Channels, DeleteTimer, 1440) // Empty password protected channels will be deleted after this many minutes +RULE_CATEGORY(Channels) +RULE_INT(Channels, RequiredStatusAdmin, 251) // Required status to administer chat channels +RULE_INT(Channels, RequiredStatusListAll, 251) // Required status to list all chat channels +RULE_INT(Channels, DeleteTimer, 1440) // Empty password protected channels will be deleted after this many minutes RULE_CATEGORY_END() -RULE_CATEGORY ( EventLog ) -RULE_BOOL ( EventLog, RecordSellToMerchant, false ) // Record sales from a player to an NPC merchant in eventlog table -RULE_BOOL ( EventLog, RecordBuyFromMerchant, false ) // Record purchases by a player from an NPC merchant in eventlog table +RULE_CATEGORY(EventLog) +RULE_BOOL(EventLog, RecordSellToMerchant, false) // Record sales from a player to an NPC merchant in eventlog table +RULE_BOOL(EventLog, RecordBuyFromMerchant, false) // Record purchases by a player from an NPC merchant in eventlog table RULE_CATEGORY_END() -RULE_CATEGORY ( Adventure ) -RULE_INT ( Adventure, MinNumberForGroup, 2 ) -RULE_INT ( Adventure, MaxNumberForGroup, 6 ) -RULE_INT ( Adventure, MinNumberForRaid, 18 ) -RULE_INT ( Adventure, MaxNumberForRaid, 36 ) -RULE_INT ( Adventure, MaxLevelRange, 9 ) -RULE_INT ( Adventure, NumberKillsForBossSpawn, 45) -RULE_REAL ( Adventure, DistanceForRescueAccept, 10000.0) -RULE_REAL ( Adventure, DistanceForRescueComplete, 2500.0) -RULE_INT ( Adventure, ItemIDToEnablePorts, 41000 ) //0 to disable, otherwise using a LDoN portal will require the user to have this item. -RULE_INT ( Adventure, LDoNTrapDistanceUse, 625 ) -RULE_REAL ( Adventure, LDoNBaseTrapDifficulty, 15.0 ) -RULE_REAL ( Adventure, LDoNCriticalFailTrapThreshold, 10.0 ) -RULE_INT ( Adventure, LDoNAdventureExpireTime, 1800) //30 minutes to expire +RULE_CATEGORY(Adventure) +RULE_INT(Adventure, MinNumberForGroup, 2) +RULE_INT(Adventure, MaxNumberForGroup, 6) +RULE_INT(Adventure, MinNumberForRaid, 18) +RULE_INT(Adventure, MaxNumberForRaid, 36) +RULE_INT(Adventure, MaxLevelRange, 9) +RULE_INT(Adventure, NumberKillsForBossSpawn, 45) +RULE_REAL(Adventure, DistanceForRescueAccept, 10000.0) +RULE_REAL(Adventure, DistanceForRescueComplete, 2500.0) +RULE_INT(Adventure, ItemIDToEnablePorts, 41000) //0 to disable, otherwise using a LDoN portal will require the user to have this item. +RULE_INT(Adventure, LDoNTrapDistanceUse, 625) +RULE_REAL(Adventure, LDoNBaseTrapDifficulty, 15.0) +RULE_REAL(Adventure, LDoNCriticalFailTrapThreshold, 10.0) +RULE_INT(Adventure, LDoNAdventureExpireTime, 1800) //30 minutes to expire 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_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_CATEGORY_END() -RULE_CATEGORY( Console ) -RULE_INT ( Console, SessionTimeOut, 600000 ) // Amount of time in ms for the console session to time out +RULE_CATEGORY(Console) +RULE_INT(Console, SessionTimeOut, 600000) // Amount of time in ms for the console session to time out RULE_CATEGORY_END() -RULE_CATEGORY( QueryServ ) -RULE_BOOL( QueryServ, PlayerLogChat, false) // Logs Player Chat -RULE_BOOL( QueryServ, PlayerLogTrades, false) // Logs Player Trades -RULE_BOOL( QueryServ, PlayerLogHandins, false) // Logs Player Handins -RULE_BOOL( QueryServ, PlayerLogNPCKills, false) // Logs Player NPC Kills -RULE_BOOL( QueryServ, PlayerLogDeletes, false) // Logs Player Deletes -RULE_BOOL( QueryServ, PlayerLogMoves, false) // Logs Player Moves -RULE_BOOL( QueryServ, PlayerLogMerchantTransactions, false) // Logs Merchant Transactions -RULE_BOOL( QueryServ, PlayerLogPCCoordinates, false) // Logs Player Coordinates with certain events -RULE_BOOL( QueryServ, PlayerLogDropItem, false) // Logs Player Drop Item -RULE_BOOL( QueryServ, PlayerLogZone, false) // Logs Player Zone Events -RULE_BOOL( QueryServ, PlayerLogDeaths, false) // Logs Player Deaths -RULE_BOOL( QueryServ, PlayerLogConnectDisconnect, false) // Logs Player Connect Disconnect State -RULE_BOOL( QueryServ, PlayerLogLevels, false) // Logs Player Leveling/Deleveling -RULE_BOOL( QueryServ, PlayerLogAARate, false) // Logs Player AA Experience Rates -RULE_BOOL( QueryServ, PlayerLogQGlobalUpdate, false) // Logs Player QGlobal Updates -RULE_BOOL( QueryServ, PlayerLogTaskUpdates, false) // Logs Player Task Updates -RULE_BOOL( QueryServ, PlayerLogKeyringAddition, false) // Log PLayer Keyring additions -RULE_BOOL( QueryServ, PlayerLogAAPurchases, false) // Log Player AA Purchases -RULE_BOOL( QueryServ, PlayerLogTradeSkillEvents, false) // Log Player Tradeskill Transactions -RULE_BOOL( QueryServ, PlayerLogIssuedCommandes, false ) // Log Player Issued Commands -RULE_BOOL( QueryServ, PlayerLogMoneyTransactions, false) // Log Player Money Transaction/Splits -RULE_BOOL( QueryServ, PlayerLogAlternateCurrencyTransactions, false) // Log Ploayer Alternate Currency Transactions +RULE_CATEGORY(QueryServ) +RULE_BOOL(QueryServ, PlayerLogChat, false) // Logs Player Chat +RULE_BOOL(QueryServ, PlayerLogTrades, false) // Logs Player Trades +RULE_BOOL(QueryServ, PlayerLogHandins, false) // Logs Player Handins +RULE_BOOL(QueryServ, PlayerLogNPCKills, false) // Logs Player NPC Kills +RULE_BOOL(QueryServ, PlayerLogDeletes, false) // Logs Player Deletes +RULE_BOOL(QueryServ, PlayerLogMoves, false) // Logs Player Moves +RULE_BOOL(QueryServ, PlayerLogMerchantTransactions, false) // Logs Merchant Transactions +RULE_BOOL(QueryServ, PlayerLogPCCoordinates, false) // Logs Player Coordinates with certain events +RULE_BOOL(QueryServ, PlayerLogDropItem, false) // Logs Player Drop Item +RULE_BOOL(QueryServ, PlayerLogZone, false) // Logs Player Zone Events +RULE_BOOL(QueryServ, PlayerLogDeaths, false) // Logs Player Deaths +RULE_BOOL(QueryServ, PlayerLogConnectDisconnect, false) // Logs Player Connect Disconnect State +RULE_BOOL(QueryServ, PlayerLogLevels, false) // Logs Player Leveling/Deleveling +RULE_BOOL(QueryServ, PlayerLogAARate, false) // Logs Player AA Experience Rates +RULE_BOOL(QueryServ, PlayerLogQGlobalUpdate, false) // Logs Player QGlobal Updates +RULE_BOOL(QueryServ, PlayerLogTaskUpdates, false) // Logs Player Task Updates +RULE_BOOL(QueryServ, PlayerLogKeyringAddition, false) // Log PLayer Keyring additions +RULE_BOOL(QueryServ, PlayerLogAAPurchases, false) // Log Player AA Purchases +RULE_BOOL(QueryServ, PlayerLogTradeSkillEvents, false) // Log Player Tradeskill Transactions +RULE_BOOL(QueryServ, PlayerLogIssuedCommandes, false) // Log Player Issued Commands +RULE_BOOL(QueryServ, PlayerLogMoneyTransactions, false) // Log Player Money Transaction/Splits +RULE_BOOL(QueryServ, PlayerLogAlternateCurrencyTransactions, false) // Log Ploayer Alternate Currency Transactions RULE_CATEGORY_END() -RULE_CATEGORY( Inventory ) -RULE_BOOL ( Inventory, EnforceAugmentRestriction, true) // Forces augment slot restrictions -RULE_BOOL ( Inventory, EnforceAugmentUsability, true) // Forces augmented item usability -RULE_BOOL ( Inventory, EnforceAugmentWear, true) // Forces augment wear slot validation -RULE_BOOL ( Inventory, DeleteTransformationMold, true) //False if you want mold to last forever -RULE_BOOL ( Inventory, AllowAnyWeaponTransformation, false) //Weapons can use any weapon transformation +RULE_CATEGORY(Inventory) +RULE_BOOL(Inventory, EnforceAugmentRestriction, true) // Forces augment slot restrictions +RULE_BOOL(Inventory, EnforceAugmentUsability, true) // Forces augmented item usability +RULE_BOOL(Inventory, EnforceAugmentWear, true) // Forces augment wear slot validation +RULE_BOOL(Inventory, DeleteTransformationMold, true) //False if you want mold to last forever +RULE_BOOL(Inventory, AllowAnyWeaponTransformation, false) //Weapons can use any weapon transformation +RULE_BOOL(Inventory, TransformSummonedBags, false) //Transforms summoned bags into disenchanted ones instead of deleting RULE_CATEGORY_END() -RULE_CATEGORY( Client ) -RULE_BOOL( Client, UseLiveFactionMessage, false) // Allows players to see faction adjustments like Live +RULE_CATEGORY(Client) +RULE_BOOL(Client, UseLiveFactionMessage, false) // Allows players to see faction adjustments like Live +RULE_BOOL(Client, UseLiveBlockedMessage, false) // Allows players to see faction adjustments like Live RULE_CATEGORY_END() #undef RULE_CATEGORY diff --git a/common/say_link.cpp b/common/say_link.cpp new file mode 100644 index 000000000..3c9fe7c6e --- /dev/null +++ b/common/say_link.cpp @@ -0,0 +1,278 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "say_link.h" +#include "emu_constants.h" + +#include "string_util.h" +#include "item.h" +#include "item_base.h" +#include "../zone/zonedb.h" + + +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) + return false; + + say_link_body_struct.unknown_1 = (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); + say_link_body_struct.augment_3 = (uint32)strtol(say_link_body.substr(16, 5).c_str(), nullptr, 16); + say_link_body_struct.augment_4 = (uint32)strtol(say_link_body.substr(21, 5).c_str(), nullptr, 16); + say_link_body_struct.augment_5 = (uint32)strtol(say_link_body.substr(26, 5).c_str(), nullptr, 16); + say_link_body_struct.augment_6 = (uint32)strtol(say_link_body.substr(31, 5).c_str(), nullptr, 16); + say_link_body_struct.is_evolving = (uint8)strtol(say_link_body.substr(36, 1).c_str(), nullptr, 16); + 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); + + return true; +} + +bool EQEmu::saylink::GenerateLinkBody(std::string& say_link_body, const SayLinkBody_Struct& say_link_body_struct) +{ + say_link_body = StringFormat( + "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X", + (0x0F & say_link_body_struct.unknown_1), + (0x000FFFFF & say_link_body_struct.item_id), + (0x000FFFFF & say_link_body_struct.augment_1), + (0x000FFFFF & say_link_body_struct.augment_2), + (0x000FFFFF & say_link_body_struct.augment_3), + (0x000FFFFF & say_link_body_struct.augment_4), + (0x000FFFFF & say_link_body_struct.augment_5), + (0x000FFFFF & say_link_body_struct.augment_6), + (0x0F & say_link_body_struct.is_evolving), + (0x0000FFFF & say_link_body_struct.evolve_group), + (0xFF & say_link_body_struct.evolve_level), + (0x000FFFFF & say_link_body_struct.ornament_icon), + (0xFFFFFFFF & say_link_body_struct.hash) + ); + + if (say_link_body.length() != EQEmu::legacy::TEXT_LINK_BODY_LENGTH) + return false; + + return true; +} + +EQEmu::SayLinkEngine::SayLinkEngine() +{ + Reset(); +} + +std::string EQEmu::SayLinkEngine::GenerateLink() +{ + m_Link.clear(); + m_LinkBody.clear(); + m_LinkText.clear(); + + generate_body(); + generate_text(); + + if ((m_LinkBody.length() == EQEmu::legacy::TEXT_LINK_BODY_LENGTH) && (m_LinkText.length() > 0)) { + m_Link.push_back(0x12); + m_Link.append(m_LinkBody); + m_Link.append(m_LinkText); + m_Link.push_back(0x12); + } + + if ((m_Link.length() == 0) || (m_Link.length() > 250)) { + m_Error = true; + m_Link = ""; + Log.Out(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.Out(Logs::General, Logs::Error, ">> LinkBody: %s", m_LinkBody.c_str()); + Log.Out(Logs::General, Logs::Error, ">> LinkText: %s", m_LinkText.c_str()); + } + + return m_Link; +} + +void EQEmu::SayLinkEngine::Reset() +{ + m_LinkType = saylink::SayLinkBlank; + 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; + m_TaskUse = false; + m_Link.clear(); + m_LinkBody.clear(); + m_LinkText.clear(); + m_Error = false; +} + +void EQEmu::SayLinkEngine::generate_body() +{ + /* + Current server mask: EQClientRoF2 + + RoF2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X" (56) + RoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (55) + SoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (50) + 6.2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X" (45) + */ + + memset(&m_LinkBodyStruct, 0, sizeof(SayLinkBody_Struct)); + + const EQEmu::ItemBase* item_data = nullptr; + + switch (m_LinkType) { + case saylink::SayLinkBlank: + break; + case saylink::SayLinkItemData: + if (m_ItemData == nullptr) { break; } + m_LinkBodyStruct.item_id = m_ItemData->ID; + m_LinkBodyStruct.evolve_group = m_ItemData->LoreGroup; // this probably won't work for all items + //m_LinkBodyStruct.evolve_level = m_ItemData->EvolvingLevel; + // TODO: add hash call + break; + case saylink::SayLinkLootItem: + if (m_LootData == nullptr) { break; } + item_data = database.GetItem(m_LootData->item_id); + if (item_data == nullptr) { break; } + m_LinkBodyStruct.item_id = item_data->ID; + m_LinkBodyStruct.augment_1 = m_LootData->aug_1; + m_LinkBodyStruct.augment_2 = m_LootData->aug_2; + m_LinkBodyStruct.augment_3 = m_LootData->aug_3; + m_LinkBodyStruct.augment_4 = m_LootData->aug_4; + m_LinkBodyStruct.augment_5 = m_LootData->aug_5; + m_LinkBodyStruct.augment_6 = m_LootData->aug_6; + m_LinkBodyStruct.evolve_group = item_data->LoreGroup; // see note above + //m_LinkBodyStruct.evolve_level = item_data->EvolvingLevel; + // TODO: add hash call + break; + case saylink::SayLinkItemInst: + if (m_ItemInst == nullptr) { break; } + if (m_ItemInst->GetItem() == nullptr) { break; } + m_LinkBodyStruct.item_id = m_ItemInst->GetItem()->ID; + m_LinkBodyStruct.augment_1 = m_ItemInst->GetAugmentItemID(0); + m_LinkBodyStruct.augment_2 = m_ItemInst->GetAugmentItemID(1); + m_LinkBodyStruct.augment_3 = m_ItemInst->GetAugmentItemID(2); + m_LinkBodyStruct.augment_4 = m_ItemInst->GetAugmentItemID(3); + m_LinkBodyStruct.augment_5 = m_ItemInst->GetAugmentItemID(4); + m_LinkBodyStruct.augment_6 = m_ItemInst->GetAugmentItemID(5); + m_LinkBodyStruct.is_evolving = (m_ItemInst->IsEvolving() ? 1 : 0); + m_LinkBodyStruct.evolve_group = m_ItemInst->GetItem()->LoreGroup; // see note above + m_LinkBodyStruct.evolve_level = m_ItemInst->GetEvolveLvl(); + m_LinkBodyStruct.ornament_icon = m_ItemInst->GetOrnamentationIcon(); + // TODO: add hash call + break; + default: + break; + } + + if (m_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_TaskUse) + m_LinkBodyStruct.hash = 0x14505DC2; + + m_LinkBody = StringFormat( + "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X", + (0x0F & m_LinkBodyStruct.unknown_1), + (0x000FFFFF & m_LinkBodyStruct.item_id), + (0x000FFFFF & m_LinkBodyStruct.augment_1), + (0x000FFFFF & m_LinkBodyStruct.augment_2), + (0x000FFFFF & m_LinkBodyStruct.augment_3), + (0x000FFFFF & m_LinkBodyStruct.augment_4), + (0x000FFFFF & m_LinkBodyStruct.augment_5), + (0x000FFFFF & m_LinkBodyStruct.augment_6), + (0x0F & m_LinkBodyStruct.is_evolving), + (0x0000FFFF & m_LinkBodyStruct.evolve_group), + (0xFF & m_LinkBodyStruct.evolve_level), + (0x000FFFFF & m_LinkBodyStruct.ornament_icon), + (0xFFFFFFFF & m_LinkBodyStruct.hash) + ); +} + +void EQEmu::SayLinkEngine::generate_text() +{ + if (m_ProxyText != nullptr) { + m_LinkText = m_ProxyText; + return; + } + + const EQEmu::ItemBase* item_data = nullptr; + + switch (m_LinkType) { + case saylink::SayLinkBlank: + break; + case saylink::SayLinkItemData: + if (m_ItemData == nullptr) { break; } + m_LinkText = m_ItemData->Name; + return; + case saylink::SayLinkLootItem: + if (m_LootData == nullptr) { break; } + item_data = database.GetItem(m_LootData->item_id); + if (item_data == nullptr) { break; } + m_LinkText = item_data->Name; + return; + case saylink::SayLinkItemInst: + if (m_ItemInst == nullptr) { break; } + if (m_ItemInst->GetItem() == nullptr) { break; } + m_LinkText = m_ItemInst->GetItem()->Name; + return; + default: + break; + } + + m_LinkText = "null"; +} diff --git a/common/say_link.h b/common/say_link.h new file mode 100644 index 000000000..0bbac2e36 --- /dev/null +++ b/common/say_link.h @@ -0,0 +1,134 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_SAY_LINK_H +#define COMMON_SAY_LINK_H + +#include "types.h" + +#include + + +struct ServerLootItem_Struct; +class ItemInst; + +namespace EQEmu +{ + struct ItemBase; + struct SayLinkBody_Struct; + + namespace saylink { + enum SayLinkType { + SayLinkBlank = 0, + SayLinkItemData, + SayLinkLootItem, + SayLinkItemInst + }; + + extern bool DegenerateLinkBody(SayLinkBody_Struct& say_Link_body_struct, const std::string& say_link_body); + extern bool GenerateLinkBody(std::string& say_link_body, const SayLinkBody_Struct& say_link_body_struct); + + } /*saylink*/ + + struct SayLinkBody_Struct { + uint8 unknown_1; /* %1X */ + uint32 item_id; /* %05X */ + uint32 augment_1; /* %05X */ + uint32 augment_2; /* %05X */ + uint32 augment_3; /* %05X */ + uint32 augment_4; /* %05X */ + uint32 augment_5; /* %05X */ + uint32 augment_6; /* %05X */ + uint8 is_evolving; /* %1X */ + uint32 evolve_group; /* %05X */ + uint8 evolve_level; /* %02X */ + uint32 ornament_icon; /* %05X */ + int hash; /* %08X */ + }; + + class SayLinkEngine { + public: + SayLinkEngine(); + + void SetLinkType(saylink::SayLinkType link_type) { m_LinkType = link_type; } + void SetItemData(const EQEmu::ItemBase* item_data) { m_ItemData = item_data; } + void SetLootData(const ServerLootItem_Struct* loot_data) { m_LootData = loot_data; } + void SetItemInst(const ItemInst* 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 SetProxyText(const char* proxy_text) { m_ProxyText = proxy_text; } // overrides standard text use + void SetTaskUse() { m_TaskUse = true; } + + 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: '' + + void Reset(); + + private: + void generate_body(); + void generate_text(); + + int m_LinkType; + const ItemBase* m_ItemData; + const ServerLootItem_Struct* m_LootData; + const ItemInst* 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; + std::string m_Link; + std::string m_LinkBody; + std::string m_LinkText; + bool m_Error; + }; + +} /*EQEmu*/ + +#endif /*COMMON_SAY_LINK_H*/ diff --git a/common/servertalk.h b/common/servertalk.h index 07b414f75..06aa4830e 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -84,6 +84,7 @@ #define ServerOP_QGlobalDelete 0x0064 #define ServerOP_DepopPlayerCorpse 0x0065 #define ServerOP_RequestTellQueue 0x0066 // client asks for it's tell queues +#define ServerOP_ChangeSharedMem 0x0067 #define ServerOP_RaidAdd 0x0100 //in use #define ServerOP_RaidRemove 0x0101 //in use @@ -181,6 +182,7 @@ #define ServerOP_CZMessagePlayer 0x4008 #define ServerOP_ReloadWorld 0x4009 #define ServerOP_ReloadLogs 0x4010 +#define ServerOP_ReloadPerlExportSettings 0x4011 /* Query Server OP Codes */ #define ServerOP_QSPlayerLogTrades 0x5010 #define ServerOP_QSPlayerLogHandins 0x5011 @@ -527,7 +529,7 @@ struct ServerLSPlayerZoneChange_Struct { uint32 from; // 0 = world uint32 to; // 0 = world }; -struct ServerLSClientAuth { +struct ClientAuth_Struct { uint32 lsaccount_id; // ID# in login server's db char name[30]; // username in login server's db char key[30]; // the Key the client will present @@ -551,7 +553,9 @@ struct ServerLSPeerConnect { struct ServerConnectInfo { char address[250]; + char local_address[250]; uint16 port; + uint32 process_id; }; struct ServerGMGoto_Struct { @@ -766,6 +770,7 @@ typedef enum { struct LauncherZoneRequest { uint8 command; char short_name[33]; + uint16 port; }; struct LauncherZoneStatus { diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 6ee82167f..a28c12e2b 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1,6 +1,28 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #include #include +#if defined(_MSC_VER) && _MSC_VER >= 1800 + #include +#endif + #include "classes.h" #include "eq_packet_structs.h" #include "eqemu_exception.h" @@ -14,31 +36,19 @@ #include "rulesys.h" #include "shareddb.h" #include "string_util.h" +#include "eqemu_config.h" SharedDatabase::SharedDatabase() -: Database(), skill_caps_mmf(nullptr), items_mmf(nullptr), items_hash(nullptr), faction_mmf(nullptr), faction_hash(nullptr), - loot_table_mmf(nullptr), loot_table_hash(nullptr), loot_drop_mmf(nullptr), loot_drop_hash(nullptr), base_data_mmf(nullptr) +: Database() { } SharedDatabase::SharedDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port) -: Database(host, user, passwd, database, port), skill_caps_mmf(nullptr), items_mmf(nullptr), items_hash(nullptr), - faction_mmf(nullptr), faction_hash(nullptr), loot_table_mmf(nullptr), loot_table_hash(nullptr), loot_drop_mmf(nullptr), - loot_drop_hash(nullptr), base_data_mmf(nullptr) +: Database(host, user, passwd, database, port) { } SharedDatabase::~SharedDatabase() { - safe_delete(skill_caps_mmf); - safe_delete(items_mmf); - safe_delete(items_hash); - safe_delete(faction_mmf); - safe_delete(faction_hash); - safe_delete(loot_table_mmf); - safe_delete(loot_drop_mmf); - safe_delete(loot_table_hash); - safe_delete(loot_drop_hash); - safe_delete(base_data_mmf); } bool SharedDatabase::SetHideMe(uint32 account_id, uint8 hideme) @@ -95,8 +105,8 @@ bool SharedDatabase::SaveCursor(uint32 char_id, std::list::const_iter std::string query = StringFormat("DELETE FROM inventory WHERE charid = %i " "AND ((slotid >= 8000 AND slotid <= 8999) " "OR slotid = %i OR (slotid >= %i AND slotid <= %i) )", - char_id, MainCursor, - EmuConstants::CURSOR_BAG_BEGIN, EmuConstants::CURSOR_BAG_END); + char_id, EQEmu::legacy::SlotCursor, + EQEmu::legacy::CURSOR_BAG_BEGIN, EQEmu::legacy::CURSOR_BAG_END); auto results = QueryDatabase(query); if (!results.Success()) { std::cout << "Clearing cursor failed: " << results.ErrorMessage() << std::endl; @@ -107,7 +117,7 @@ bool SharedDatabase::SaveCursor(uint32 char_id, std::list::const_iter for(auto it = start; it != end; ++it, i++) { if (i > 8999) { break; } // shouldn't be anything in the queue that indexes this high ItemInst *inst = *it; - int16 use_slot = (i == 8000) ? MainCursor : i; + int16 use_slot = (i == 8000) ? EQEmu::legacy::SlotCursor : i; if (!SaveInventory(char_id, inst, use_slot)) { return false; } @@ -152,10 +162,10 @@ bool SharedDatabase::VerifyInventory(uint32 account_id, int16 slot_id, const Ite bool SharedDatabase::SaveInventory(uint32 char_id, const ItemInst* inst, int16 slot_id) { //never save tribute slots: - if(slot_id >= EmuConstants::TRIBUTE_BEGIN && slot_id <= EmuConstants::TRIBUTE_END) + if (slot_id >= EQEmu::legacy::TRIBUTE_BEGIN && slot_id <= EQEmu::legacy::TRIBUTE_END) return true; - if (slot_id >= EmuConstants::SHARED_BANK_BEGIN && slot_id <= EmuConstants::SHARED_BANK_BAGS_END) { + if (slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && slot_id <= EQEmu::legacy::SHARED_BANK_BAGS_END) { // Shared bank inventory if (!inst) { return DeleteSharedBankSlot(char_id, slot_id); @@ -182,11 +192,11 @@ bool SharedDatabase::SaveInventory(uint32 char_id, const ItemInst* inst, int16 s bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, int16 slot_id) { // need to check 'inst' argument for valid pointer - uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM }; - if (inst->IsType(ItemClassCommon)) { - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + uint32 augslot[EQEmu::legacy::ITEM_COMMON_SIZE] = { 0, 0, 0, 0, 0, 0 }; + if (inst->IsClassCommon()) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { ItemInst *auginst = inst->GetItem(i); - augslot[i] = (auginst && auginst->GetItem()) ? auginst->GetItem()->ID : NO_ITEM; + augslot[i] = (auginst && auginst->GetItem()) ? auginst->GetItem()->ID : 0; } } @@ -211,10 +221,10 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, i auto results = QueryDatabase(query); // Save bag contents, if slot supports bag contents - if (inst->IsType(ItemClassContainer) && Inventory::SupportsContainers(slot_id)) + if (inst->IsClassBag() && Inventory::SupportsContainers(slot_id)) // Limiting to bag slot count will get rid of 'hidden' duplicated items and 'Invalid Slot ID' // messages through attrition (and the modded code in SaveInventory) - for (uint8 idx = SUB_BEGIN; idx < inst->GetItem()->BagSlots && idx < EmuConstants::ITEM_CONTAINER_SIZE; idx++) { + for (uint8 idx = SUB_INDEX_BEGIN; idx < inst->GetItem()->BagSlots && idx < EQEmu::legacy::ITEM_CONTAINER_SIZE; idx++) { const ItemInst* baginst = inst->GetItem(idx); SaveInventory(char_id, baginst, Inventory::CalcSlotId(slot_id, idx)); } @@ -229,11 +239,11 @@ bool SharedDatabase::UpdateInventorySlot(uint32 char_id, const ItemInst* inst, i bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const ItemInst* inst, int16 slot_id) { // need to check 'inst' argument for valid pointer - uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM }; - if (inst->IsType(ItemClassCommon)) { - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + uint32 augslot[EQEmu::legacy::ITEM_COMMON_SIZE] = { 0, 0, 0, 0, 0, 0 }; + if (inst->IsClassCommon()) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { ItemInst *auginst = inst->GetItem(i); - augslot[i] = (auginst && auginst->GetItem()) ? auginst->GetItem()->ID : NO_ITEM; + augslot[i] = (auginst && auginst->GetItem()) ? auginst->GetItem()->ID : 0; } } @@ -257,10 +267,10 @@ bool SharedDatabase::UpdateSharedBankSlot(uint32 char_id, const ItemInst* inst, auto results = QueryDatabase(query); // Save bag contents, if slot supports bag contents - if (inst->IsType(ItemClassContainer) && Inventory::SupportsContainers(slot_id)) { + if (inst->IsClassBag() && Inventory::SupportsContainers(slot_id)) { // Limiting to bag slot count will get rid of 'hidden' duplicated items and 'Invalid Slot ID' // messages through attrition (and the modded code in SaveInventory) - for (uint8 idx = SUB_BEGIN; idx < inst->GetItem()->BagSlots && idx < EmuConstants::ITEM_CONTAINER_SIZE; idx++) { + for (uint8 idx = SUB_INDEX_BEGIN; idx < inst->GetItem()->BagSlots && idx < EQEmu::legacy::ITEM_CONTAINER_SIZE; idx++) { const ItemInst* baginst = inst->GetItem(idx); SaveInventory(char_id, baginst, Inventory::CalcSlotId(slot_id, idx)); } @@ -286,7 +296,7 @@ bool SharedDatabase::DeleteInventorySlot(uint32 char_id, int16 slot_id) { if (!Inventory::SupportsContainers(slot_id)) return true; - int16 base_slot_id = Inventory::CalcSlotId(slot_id, SUB_BEGIN); + int16 base_slot_id = Inventory::CalcSlotId(slot_id, SUB_INDEX_BEGIN); query = StringFormat("DELETE FROM inventory WHERE charid = %i AND slotid >= %i AND slotid < %i", char_id, base_slot_id, (base_slot_id+10)); results = QueryDatabase(query); @@ -312,7 +322,7 @@ bool SharedDatabase::DeleteSharedBankSlot(uint32 char_id, int16 slot_id) { if (!Inventory::SupportsContainers(slot_id)) return true; - int16 base_slot_id = Inventory::CalcSlotId(slot_id, SUB_BEGIN); + int16 base_slot_id = Inventory::CalcSlotId(slot_id, SUB_INDEX_BEGIN); query = StringFormat("DELETE FROM sharedbank WHERE acctid = %i " "AND slotid >= %i AND slotid < %i", account_id, base_slot_id, (base_slot_id+10)); @@ -354,7 +364,7 @@ bool SharedDatabase::SetSharedPlatinum(uint32 account_id, int32 amount_to_add) { bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, Inventory* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin_level) { - const Item_Struct* myitem; + const EQEmu::ItemBase* myitem; std::string query = StringFormat("SELECT itemid, item_charges, slot FROM starting_items " "WHERE (race = %i or race = 0) AND (class = %i or class = 0) AND " @@ -398,13 +408,13 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory *inv, bool is_charid) "sb.augslot1, sb.augslot2, sb.augslot3, " "sb.augslot4, sb.augslot5, sb.augslot6, sb.custom_data " "FROM sharedbank sb INNER JOIN character_data ch " - "ON ch.account_id=sb.acctid WHERE ch.id = %i", + "ON ch.account_id=sb.acctid WHERE ch.id = %i ORDER BY sb.slotid", id); else query = StringFormat("SELECT slotid, itemid, charges, " "augslot1, augslot2, augslot3, " "augslot4, augslot5, augslot6, custom_data " - "FROM sharedbank WHERE acctid=%i", + "FROM sharedbank WHERE acctid=%i ORDER BY slotid", id); auto results = QueryDatabase(query); if (!results.Success()) { @@ -418,7 +428,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory *inv, bool is_charid) uint32 item_id = (uint32)atoi(row[1]); int8 charges = (int8)atoi(row[2]); - uint32 aug[EmuConstants::ITEM_COMMON_SIZE]; + uint32 aug[EQEmu::legacy::ITEM_COMMON_SIZE]; aug[0] = (uint32)atoi(row[3]); aug[1] = (uint32)atoi(row[4]); aug[2] = (uint32)atoi(row[5]); @@ -426,7 +436,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory *inv, bool is_charid) aug[4] = (uint32)atoi(row[7]); aug[5] = (uint32)atoi(row[8]); - const Item_Struct *item = GetItem(item_id); + const EQEmu::ItemBase *item = GetItem(item_id); if (!item) { Log.Out(Logs::General, Logs::Error, @@ -438,14 +448,14 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory *inv, bool is_charid) int16 put_slot_id = INVALID_INDEX; ItemInst *inst = CreateBaseItem(item, charges); - if (inst && item->ItemClass == ItemClassCommon) { - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + if (inst && item->IsClassCommon()) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { if (aug[i]) inst->PutAugment(this, i, aug[i]); } } - if (row[9]) { + if (inst && row[9]) { std::string data_str(row[9]); std::string idAsString; std::string value; @@ -470,6 +480,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory *inv, bool is_charid) } } + // theoretically inst can be nullptr ... this would be very bad ... put_slot_id = inv->PutItem(slot_id, *inst); safe_delete(inst); @@ -513,7 +524,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv) uint16 charges = atoi(row[2]); uint32 color = atoul(row[3]); - uint32 aug[EmuConstants::ITEM_COMMON_SIZE]; + uint32 aug[EQEmu::legacy::ITEM_COMMON_SIZE]; aug[0] = (uint32)atoul(row[4]); aug[1] = (uint32)atoul(row[5]); @@ -528,7 +539,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv) uint32 ornament_idfile = (uint32)atoul(row[13]); uint32 ornament_hero_model = (uint32)atoul(row[14]); - const Item_Struct *item = GetItem(item_id); + const EQEmu::ItemBase *item = GetItem(item_id); if (!item) { Log.Out(Logs::General, Logs::Error, @@ -575,8 +586,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv) inst->SetOrnamentHeroModel(ornament_hero_model); if (instnodrop || - (((slot_id >= EmuConstants::EQUIPMENT_BEGIN && slot_id <= EmuConstants::EQUIPMENT_END) || - slot_id == MainPowerSource) && + (((slot_id >= EQEmu::legacy::EQUIPMENT_BEGIN && slot_id <= EQEmu::legacy::EQUIPMENT_END) || + slot_id == EQEmu::legacy::SlotPowerSource) && inst->GetItem()->Attuneable)) inst->SetAttuned(true); @@ -585,8 +596,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv) if (charges == 0x7FFF) inst->SetCharges(-1); - else if (charges == 0 && - inst->IsStackable()) // Stackable items need a minimum charge of 1 remain moveable. + else if (charges == 0 && inst->IsStackable()) // Stackable items need a minimum charge of 1 remain moveable. inst->SetCharges(1); else inst->SetCharges(charges); @@ -598,8 +608,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv) inst->SetRecastTimestamp(0); } - if (item->ItemClass == ItemClassCommon) { - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + if (item->IsClassCommon()) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { if (aug[i]) inst->PutAugment(this, i, aug[i]); } @@ -656,7 +666,7 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, Inventory *inv) int8 charges = atoi(row[2]); uint32 color = atoul(row[3]); - uint32 aug[EmuConstants::ITEM_COMMON_SIZE]; + uint32 aug[EQEmu::legacy::ITEM_COMMON_SIZE]; aug[0] = (uint32)atoi(row[4]); aug[1] = (uint32)atoi(row[5]); aug[2] = (uint32)atoi(row[6]); @@ -669,7 +679,7 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, Inventory *inv) uint32 ornament_idfile = (uint32)atoul(row[13]); uint32 ornament_hero_model = (uint32)atoul(row[14]); - const Item_Struct *item = GetItem(item_id); + const EQEmu::ItemBase *item = GetItem(item_id); int16 put_slot_id = INVALID_INDEX; if (!item) continue; @@ -716,8 +726,8 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, Inventory *inv) inst->SetCharges(charges); - if (item->ItemClass == ItemClassCommon) { - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + if (item->IsClassCommon()) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { if (aug[i]) inst->PutAugment(this, i, aug[i]); } @@ -797,28 +807,16 @@ void SharedDatabase::GetItemsCount(int32 &item_count, uint32 &max_id) item_count = atoi(row[1]); } -bool SharedDatabase::LoadItems() { - if(items_mmf) { - return true; - } +bool SharedDatabase::LoadItems(const std::string &prefix) { + items_mmf.reset(nullptr); try { + auto Config = EQEmuConfig::get(); EQEmu::IPCMutex mutex("items"); mutex.Lock(); - items_mmf = new EQEmu::MemoryMappedFile("shared/items"); - - int32 items = -1; - uint32 max_item = 0; - GetItemsCount(items, max_item); - if(items == -1) { - EQ_EXCEPT("SharedDatabase", "Database returned no result"); - } - uint32 size = static_cast(EQEmu::FixedMemoryHashSet::estimated_size(items, max_item)); - if(items_mmf->Size() != size) { - EQ_EXCEPT("SharedDatabase", "Couldn't load items because items_mmf->Size() != size"); - } - - items_hash = new EQEmu::FixedMemoryHashSet(reinterpret_cast(items_mmf->Get()), size); + std::string file_name = Config->SharedMemDir + prefix + std::string("items"); + items_mmf = std::unique_ptr(new EQEmu::MemoryMappedFile(file_name)); + items_hash = std::unique_ptr>(new EQEmu::FixedMemoryHashSet(reinterpret_cast(items_mmf->Get()), items_mmf->Size())); mutex.Unlock(); } catch(std::exception& ex) { Log.Out(Logs::General, Logs::Error, "Error Loading Items: %s", ex.what()); @@ -828,36 +826,37 @@ bool SharedDatabase::LoadItems() { return true; } -void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id) { - EQEmu::FixedMemoryHashSet hash(reinterpret_cast(data), size, items, max_item_id); +void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id) +{ + EQEmu::FixedMemoryHashSet hash(reinterpret_cast(data), size, items, max_item_id); - char ndbuffer[4]; + std::string ndbuffer; bool disableNoRent = false; - if(GetVariable("disablenorent", ndbuffer, 4)) { - if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { + if (GetVariable("disablenorent", ndbuffer)) { + if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') { disableNoRent = true; } } bool disableNoDrop = false; - if(GetVariable("disablenodrop", ndbuffer, 4)) { - if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { + if (GetVariable("disablenodrop", ndbuffer)) { + if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') { disableNoDrop = true; } } bool disableLoreGroup = false; - if(GetVariable("disablelore", ndbuffer, 4)) { - if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { + if (GetVariable("disablelore", ndbuffer)) { + if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') { disableLoreGroup = true; } } bool disableNoTransfer = false; - if(GetVariable("disablenotransfer", ndbuffer, 4)) { - if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { + if (GetVariable("disablenotransfer", ndbuffer)) { + if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') { disableNoTransfer = true; } } - Item_Struct item; + EQEmu::ItemBase item; const std::string query = "SELECT source," #define F(x) "`"#x"`," @@ -865,227 +864,229 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_ #undef F "updated FROM items ORDER BY id"; auto results = QueryDatabase(query); - if (!results.Success()) { - return; - } + if (!results.Success()) { + return; + } - for(auto row = results.begin(); row != results.end(); ++row) { - memset(&item, 0, sizeof(Item_Struct)); + for (auto row = results.begin(); row != results.end(); ++row) { + memset(&item, 0, sizeof(EQEmu::ItemBase)); - item.ItemClass = (uint8)atoi(row[ItemField::itemclass]); - strcpy(item.Name,row[ItemField::name]); - strcpy(item.Lore,row[ItemField::lore]); - strcpy(item.IDFile,row[ItemField::idfile]); + item.ItemClass = (uint8)atoi(row[ItemField::itemclass]); + strcpy(item.Name, row[ItemField::name]); + strcpy(item.Lore, row[ItemField::lore]); + strcpy(item.IDFile, row[ItemField::idfile]); - item.ID = (uint32)atoul(row[ItemField::id]); - item.Weight = (uint8)atoi(row[ItemField::weight]); - item.NoRent = disableNoRent ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::norent]); - item.NoDrop = disableNoDrop ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::nodrop]); - item.Size = (uint8)atoi(row[ItemField::size]); - item.Slots = (uint32)atoul(row[ItemField::slots]); - item.Price = (uint32)atoul(row[ItemField::price]); - item.Icon = (uint32)atoul(row[ItemField::icon]); - item.BenefitFlag = (atoul(row[ItemField::benefitflag]) != 0); - item.Tradeskills = (atoi(row[ItemField::tradeskills])==0) ? false : true; - item.CR = (int8)atoi(row[ItemField::cr]); - item.DR = (int8)atoi(row[ItemField::dr]); - item.PR = (int8)atoi(row[ItemField::pr]); - item.MR = (int8)atoi(row[ItemField::mr]); - item.FR = (int8)atoi(row[ItemField::fr]); - item.AStr = (int8)atoi(row[ItemField::astr]); - item.ASta = (int8)atoi(row[ItemField::asta]); - item.AAgi = (int8)atoi(row[ItemField::aagi]); - item.ADex = (int8)atoi(row[ItemField::adex]); - item.ACha = (int8)atoi(row[ItemField::acha]); - item.AInt = (int8)atoi(row[ItemField::aint]); - item.AWis = (int8)atoi(row[ItemField::awis]); - item.HP = (int32)atoul(row[ItemField::hp]); - item.Mana = (int32)atoul(row[ItemField::mana]); - item.AC = (int32)atoul(row[ItemField::ac]); - item.Deity = (uint32)atoul(row[ItemField::deity]); - item.SkillModValue = (int32)atoul(row[ItemField::skillmodvalue]); + item.ID = (uint32)atoul(row[ItemField::id]); + item.Weight = (int32)atoi(row[ItemField::weight]); + item.NoRent = disableNoRent ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::norent]); + item.NoDrop = disableNoDrop ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::nodrop]); + item.Size = (uint8)atoi(row[ItemField::size]); + item.Slots = (uint32)atoul(row[ItemField::slots]); + item.Price = (uint32)atoul(row[ItemField::price]); + item.Icon = (uint32)atoul(row[ItemField::icon]); + item.BenefitFlag = (atoul(row[ItemField::benefitflag]) != 0); + item.Tradeskills = (atoi(row[ItemField::tradeskills]) == 0) ? false : true; + item.CR = (int8)atoi(row[ItemField::cr]); + item.DR = (int8)atoi(row[ItemField::dr]); + item.PR = (int8)atoi(row[ItemField::pr]); + item.MR = (int8)atoi(row[ItemField::mr]); + item.FR = (int8)atoi(row[ItemField::fr]); + item.AStr = (int8)atoi(row[ItemField::astr]); + item.ASta = (int8)atoi(row[ItemField::asta]); + item.AAgi = (int8)atoi(row[ItemField::aagi]); + item.ADex = (int8)atoi(row[ItemField::adex]); + item.ACha = (int8)atoi(row[ItemField::acha]); + item.AInt = (int8)atoi(row[ItemField::aint]); + item.AWis = (int8)atoi(row[ItemField::awis]); + item.HP = (int32)atoul(row[ItemField::hp]); + item.Mana = (int32)atoul(row[ItemField::mana]); + item.AC = (int32)atoul(row[ItemField::ac]); + item.Deity = (uint32)atoul(row[ItemField::deity]); + item.SkillModValue = (int32)atoul(row[ItemField::skillmodvalue]); + item.SkillModMax = (int32)atoul(row[ItemField::skillmodmax]); + item.SkillModType = (uint32)atoul(row[ItemField::skillmodtype]); + item.BaneDmgRace = (uint32)atoul(row[ItemField::banedmgrace]); + item.BaneDmgAmt = (int8)atoi(row[ItemField::banedmgamt]); + item.BaneDmgBody = (uint32)atoul(row[ItemField::banedmgbody]); + item.Magic = (atoi(row[ItemField::magic]) == 0) ? false : true; + item.CastTime_ = (int32)atoul(row[ItemField::casttime_]); + item.ReqLevel = (uint8)atoi(row[ItemField::reqlevel]); + item.BardType = (uint32)atoul(row[ItemField::bardtype]); + item.BardValue = (int32)atoul(row[ItemField::bardvalue]); + item.Light = (int8)atoi(row[ItemField::light]); + item.Delay = (uint8)atoi(row[ItemField::delay]); + item.RecLevel = (uint8)atoi(row[ItemField::reclevel]); + item.RecSkill = (uint8)atoi(row[ItemField::recskill]); + item.ElemDmgType = (uint8)atoi(row[ItemField::elemdmgtype]); + item.ElemDmgAmt = (uint8)atoi(row[ItemField::elemdmgamt]); + item.Range = (uint8)atoi(row[ItemField::range]); + item.Damage = (uint32)atoi(row[ItemField::damage]); + item.Color = (uint32)atoul(row[ItemField::color]); + item.Classes = (uint32)atoul(row[ItemField::classes]); + item.Races = (uint32)atoul(row[ItemField::races]); - item.SkillModType = (uint32)atoul(row[ItemField::skillmodtype]); - item.BaneDmgRace = (uint32)atoul(row[ItemField::banedmgrace]); - item.BaneDmgAmt = (int8)atoi(row[ItemField::banedmgamt]); - item.BaneDmgBody = (uint32)atoul(row[ItemField::banedmgbody]); - item.Magic = (atoi(row[ItemField::magic])==0) ? false : true; - item.CastTime_ = (int32)atoul(row[ItemField::casttime_]); - item.ReqLevel = (uint8)atoi(row[ItemField::reqlevel]); - item.BardType = (uint32)atoul(row[ItemField::bardtype]); - item.BardValue = (int32)atoul(row[ItemField::bardvalue]); - item.Light = (int8)atoi(row[ItemField::light]); - item.Delay = (uint8)atoi(row[ItemField::delay]); - item.RecLevel = (uint8)atoi(row[ItemField::reclevel]); - item.RecSkill = (uint8)atoi(row[ItemField::recskill]); - item.ElemDmgType = (uint8)atoi(row[ItemField::elemdmgtype]); - item.ElemDmgAmt = (uint8)atoi(row[ItemField::elemdmgamt]); - item.Range = (uint8)atoi(row[ItemField::range]); - item.Damage = (uint32)atoi(row[ItemField::damage]); - item.Color = (uint32)atoul(row[ItemField::color]); - item.Classes = (uint32)atoul(row[ItemField::classes]); - item.Races = (uint32)atoul(row[ItemField::races]); - - item.MaxCharges = (int16)atoi(row[ItemField::maxcharges]); - item.ItemType = (uint8)atoi(row[ItemField::itemtype]); + item.MaxCharges = (int16)atoi(row[ItemField::maxcharges]); + item.ItemType = (uint8)atoi(row[ItemField::itemtype]); item.Material = (uint8)atoi(row[ItemField::material]); item.HerosForgeModel = (uint32)atoi(row[ItemField::herosforgemodel]); - item.SellRate = (float)atof(row[ItemField::sellrate]); - item.CastTime = (uint32)atoul(row[ItemField::casttime]); - item.EliteMaterial = (uint32)atoul(row[ItemField::elitematerial]); - item.ProcRate = (int32)atoi(row[ItemField::procrate]); - item.CombatEffects = (int8)atoi(row[ItemField::combateffects]); - item.Shielding = (int8)atoi(row[ItemField::shielding]); - item.StunResist = (int8)atoi(row[ItemField::stunresist]); - item.StrikeThrough = (int8)atoi(row[ItemField::strikethrough]); - item.ExtraDmgSkill = (uint32)atoul(row[ItemField::extradmgskill]); - item.ExtraDmgAmt = (uint32)atoul(row[ItemField::extradmgamt]); - item.SpellShield = (int8)atoi(row[ItemField::spellshield]); - item.Avoidance = (int8)atoi(row[ItemField::avoidance]); - item.Accuracy = (int8)atoi(row[ItemField::accuracy]); - item.CharmFileID = (uint32)atoul(row[ItemField::charmfileid]); - item.FactionMod1 = (int32)atoul(row[ItemField::factionmod1]); - item.FactionMod2 = (int32)atoul(row[ItemField::factionmod2]); - item.FactionMod3 = (int32)atoul(row[ItemField::factionmod3]); - item.FactionMod4 = (int32)atoul(row[ItemField::factionmod4]); - item.FactionAmt1 = (int32)atoul(row[ItemField::factionamt1]); - item.FactionAmt2 = (int32)atoul(row[ItemField::factionamt2]); - item.FactionAmt3 = (int32)atoul(row[ItemField::factionamt3]); - item.FactionAmt4 = (int32)atoul(row[ItemField::factionamt4]); + item.SellRate = (float)atof(row[ItemField::sellrate]); + item.CastTime = (uint32)atoul(row[ItemField::casttime]); + item.EliteMaterial = (uint32)atoul(row[ItemField::elitematerial]); + item.ProcRate = (int32)atoi(row[ItemField::procrate]); + item.CombatEffects = (int8)atoi(row[ItemField::combateffects]); + item.Shielding = (int8)atoi(row[ItemField::shielding]); + item.StunResist = (int8)atoi(row[ItemField::stunresist]); + item.StrikeThrough = (int8)atoi(row[ItemField::strikethrough]); + item.ExtraDmgSkill = (uint32)atoul(row[ItemField::extradmgskill]); + item.ExtraDmgAmt = (uint32)atoul(row[ItemField::extradmgamt]); + item.SpellShield = (int8)atoi(row[ItemField::spellshield]); + item.Avoidance = (int8)atoi(row[ItemField::avoidance]); + item.Accuracy = (int8)atoi(row[ItemField::accuracy]); + item.CharmFileID = (uint32)atoul(row[ItemField::charmfileid]); + item.FactionMod1 = (int32)atoul(row[ItemField::factionmod1]); + item.FactionMod2 = (int32)atoul(row[ItemField::factionmod2]); + item.FactionMod3 = (int32)atoul(row[ItemField::factionmod3]); + item.FactionMod4 = (int32)atoul(row[ItemField::factionmod4]); + item.FactionAmt1 = (int32)atoul(row[ItemField::factionamt1]); + item.FactionAmt2 = (int32)atoul(row[ItemField::factionamt2]); + item.FactionAmt3 = (int32)atoul(row[ItemField::factionamt3]); + item.FactionAmt4 = (int32)atoul(row[ItemField::factionamt4]); - strcpy(item.CharmFile,row[ItemField::charmfile]); + strcpy(item.CharmFile, row[ItemField::charmfile]); - item.AugType = (uint32)atoul(row[ItemField::augtype]); - item.AugSlotType[0] = (uint8)atoi(row[ItemField::augslot1type]); - item.AugSlotVisible[0] = (uint8)atoi(row[ItemField::augslot1visible]); - item.AugSlotUnk2[0] = 0; - item.AugSlotType[1] = (uint8)atoi(row[ItemField::augslot2type]); - item.AugSlotVisible[1] = (uint8)atoi(row[ItemField::augslot2visible]); - item.AugSlotUnk2[1] = 0; - item.AugSlotType[2] = (uint8)atoi(row[ItemField::augslot3type]); - item.AugSlotVisible[2] = (uint8)atoi(row[ItemField::augslot3visible]); - item.AugSlotUnk2[2] = 0; - item.AugSlotType[3] = (uint8)atoi(row[ItemField::augslot4type]); - item.AugSlotVisible[3] = (uint8)atoi(row[ItemField::augslot4visible]); - item.AugSlotUnk2[3] = 0; - item.AugSlotType[4] = (uint8)atoi(row[ItemField::augslot5type]); - item.AugSlotVisible[4] = (uint8)atoi(row[ItemField::augslot5visible]); - item.AugSlotUnk2[4] = 0; + item.AugType = (uint32)atoul(row[ItemField::augtype]); + item.AugSlotType[0] = (uint8)atoi(row[ItemField::augslot1type]); + item.AugSlotVisible[0] = (uint8)atoi(row[ItemField::augslot1visible]); + item.AugSlotUnk2[0] = 0; + item.AugSlotType[1] = (uint8)atoi(row[ItemField::augslot2type]); + item.AugSlotVisible[1] = (uint8)atoi(row[ItemField::augslot2visible]); + item.AugSlotUnk2[1] = 0; + item.AugSlotType[2] = (uint8)atoi(row[ItemField::augslot3type]); + item.AugSlotVisible[2] = (uint8)atoi(row[ItemField::augslot3visible]); + item.AugSlotUnk2[2] = 0; + item.AugSlotType[3] = (uint8)atoi(row[ItemField::augslot4type]); + item.AugSlotVisible[3] = (uint8)atoi(row[ItemField::augslot4visible]); + item.AugSlotUnk2[3] = 0; + item.AugSlotType[4] = (uint8)atoi(row[ItemField::augslot5type]); + item.AugSlotVisible[4] = (uint8)atoi(row[ItemField::augslot5visible]); + item.AugSlotUnk2[4] = 0; item.AugSlotType[5] = (uint8)atoi(row[ItemField::augslot6type]); item.AugSlotVisible[5] = (uint8)atoi(row[ItemField::augslot6visible]); item.AugSlotUnk2[5] = 0; - item.LDoNTheme = (uint32)atoul(row[ItemField::ldontheme]); - item.LDoNPrice = (uint32)atoul(row[ItemField::ldonprice]); - item.LDoNSold = (uint32)atoul(row[ItemField::ldonsold]); - item.BagType = (uint8)atoi(row[ItemField::bagtype]); - item.BagSlots = (uint8)atoi(row[ItemField::bagslots]); - item.BagSize = (uint8)atoi(row[ItemField::bagsize]); - item.BagWR = (uint8)atoi(row[ItemField::bagwr]); - item.Book = (uint8)atoi(row[ItemField::book]); - item.BookType = (uint32)atoul(row[ItemField::booktype]); + item.LDoNTheme = (uint32)atoul(row[ItemField::ldontheme]); + item.LDoNPrice = (uint32)atoul(row[ItemField::ldonprice]); + item.LDoNSold = (uint32)atoul(row[ItemField::ldonsold]); + item.BagType = (uint8)atoi(row[ItemField::bagtype]); + item.BagSlots = (uint8)std::min(atoi(row[ItemField::bagslots]), 10); // FIXME: remove when big bags supported + item.BagSize = (uint8)atoi(row[ItemField::bagsize]); + item.BagWR = (uint8)atoi(row[ItemField::bagwr]); + item.Book = (uint8)atoi(row[ItemField::book]); + item.BookType = (uint32)atoul(row[ItemField::booktype]); - strcpy(item.Filename,row[ItemField::filename]); + strcpy(item.Filename, row[ItemField::filename]); - item.BaneDmgRaceAmt = (uint32)atoul(row[ItemField::banedmgraceamt]); - item.AugRestrict = (uint32)atoul(row[ItemField::augrestrict]); - item.LoreGroup = disableLoreGroup ? (uint8)atoi("0") : atoi(row[ItemField::loregroup]); - item.LoreFlag = item.LoreGroup!=0; - item.PendingLoreFlag = (atoi(row[ItemField::pendingloreflag])==0) ? false : true; - item.ArtifactFlag = (atoi(row[ItemField::artifactflag])==0) ? false : true; - item.SummonedFlag = (atoi(row[ItemField::summonedflag])==0) ? false : true; - item.Favor = (uint32)atoul(row[ItemField::favor]); - item.FVNoDrop = (atoi(row[ItemField::fvnodrop])==0) ? false : true; - item.Endur = (uint32)atoul(row[ItemField::endur]); - item.DotShielding = (uint32)atoul(row[ItemField::dotshielding]); - item.Attack = (uint32)atoul(row[ItemField::attack]); - item.Regen = (uint32)atoul(row[ItemField::regen]); - item.ManaRegen = (uint32)atoul(row[ItemField::manaregen]); - item.EnduranceRegen = (uint32)atoul(row[ItemField::enduranceregen]); - item.Haste = (uint32)atoul(row[ItemField::haste]); - item.DamageShield = (uint32)atoul(row[ItemField::damageshield]); - item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]); - item.RecastType = (uint32)atoul(row[ItemField::recasttype]); - item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]); - item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]); - item.Attuneable = (atoi(row[ItemField::attuneable])==0) ? false : true; - item.NoPet = (atoi(row[ItemField::nopet])==0) ? false : true; - item.PointType = (uint32)atoul(row[ItemField::pointtype]); - item.PotionBelt = (atoi(row[ItemField::potionbelt])==0) ? false : true; - item.PotionBeltSlots = (atoi(row[ItemField::potionbeltslots])==0) ? false : true; - item.StackSize = (uint16)atoi(row[ItemField::stacksize]); - item.NoTransfer = disableNoTransfer ? false : (atoi(row[ItemField::notransfer])==0) ? false : true; - item.Stackable = (atoi(row[ItemField::stackable])==0) ? false : true; - item.Click.Effect = (uint32)atoul(row[ItemField::clickeffect]); - item.Click.Type = (uint8)atoul(row[ItemField::clicktype]); - item.Click.Level = (uint8)atoul(row[ItemField::clicklevel]); - item.Click.Level2 = (uint8)atoul(row[ItemField::clicklevel2]); + item.BaneDmgRaceAmt = (uint32)atoul(row[ItemField::banedmgraceamt]); + item.AugRestrict = (uint32)atoul(row[ItemField::augrestrict]); + item.LoreGroup = disableLoreGroup ? (uint8)atoi("0") : atoi(row[ItemField::loregroup]); + item.LoreFlag = item.LoreGroup != 0; + item.PendingLoreFlag = (atoi(row[ItemField::pendingloreflag]) == 0) ? false : true; + item.ArtifactFlag = (atoi(row[ItemField::artifactflag]) == 0) ? false : true; + item.SummonedFlag = (atoi(row[ItemField::summonedflag]) == 0) ? false : true; + item.Favor = (uint32)atoul(row[ItemField::favor]); + item.FVNoDrop = (atoi(row[ItemField::fvnodrop]) == 0) ? false : true; + item.Endur = (uint32)atoul(row[ItemField::endur]); + item.DotShielding = (uint32)atoul(row[ItemField::dotshielding]); + item.Attack = (uint32)atoul(row[ItemField::attack]); + item.Regen = (uint32)atoul(row[ItemField::regen]); + item.ManaRegen = (uint32)atoul(row[ItemField::manaregen]); + item.EnduranceRegen = (uint32)atoul(row[ItemField::enduranceregen]); + item.Haste = (uint32)atoul(row[ItemField::haste]); + item.DamageShield = (uint32)atoul(row[ItemField::damageshield]); + item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]); + item.RecastType = (uint32)atoul(row[ItemField::recasttype]); + item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]); + item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]); + item.Attuneable = (atoi(row[ItemField::attuneable]) == 0) ? false : true; + item.NoPet = (atoi(row[ItemField::nopet]) == 0) ? false : true; + item.PointType = (uint32)atoul(row[ItemField::pointtype]); + item.PotionBelt = (atoi(row[ItemField::potionbelt]) == 0) ? false : true; + item.PotionBeltSlots = (atoi(row[ItemField::potionbeltslots]) == 0) ? false : true; + item.StackSize = (uint16)atoi(row[ItemField::stacksize]); + item.NoTransfer = disableNoTransfer ? false : (atoi(row[ItemField::notransfer]) == 0) ? false : true; + item.Stackable = (atoi(row[ItemField::stackable]) == 0) ? false : true; + item.Click.Effect = (uint32)atoul(row[ItemField::clickeffect]); + item.Click.Type = (uint8)atoul(row[ItemField::clicktype]); + item.Click.Level = (uint8)atoul(row[ItemField::clicklevel]); + item.Click.Level2 = (uint8)atoul(row[ItemField::clicklevel2]); - strcpy(item.CharmFile,row[ItemField::charmfile]); + strcpy(item.CharmFile, row[ItemField::charmfile]); - item.Proc.Effect = (uint16)atoul(row[ItemField::proceffect]); - item.Proc.Type = (uint8)atoul(row[ItemField::proctype]); - item.Proc.Level = (uint8)atoul(row[ItemField::proclevel]); - item.Proc.Level2 = (uint8)atoul(row[ItemField::proclevel2]); - item.Worn.Effect = (uint16)atoul(row[ItemField::worneffect]); - item.Worn.Type = (uint8)atoul(row[ItemField::worntype]); - item.Worn.Level = (uint8)atoul(row[ItemField::wornlevel]); - item.Worn.Level2 = (uint8)atoul(row[ItemField::wornlevel2]); - item.Focus.Effect = (uint16)atoul(row[ItemField::focuseffect]); - item.Focus.Type = (uint8)atoul(row[ItemField::focustype]); - item.Focus.Level = (uint8)atoul(row[ItemField::focuslevel]); - item.Focus.Level2 = (uint8)atoul(row[ItemField::focuslevel2]); - item.Scroll.Effect = (uint16)atoul(row[ItemField::scrolleffect]); - item.Scroll.Type = (uint8)atoul(row[ItemField::scrolltype]); - item.Scroll.Level = (uint8)atoul(row[ItemField::scrolllevel]); - item.Scroll.Level2 = (uint8)atoul(row[ItemField::scrolllevel2]); - item.Bard.Effect = (uint16)atoul(row[ItemField::bardeffect]); - item.Bard.Type = (uint8)atoul(row[ItemField::bardtype]); - item.Bard.Level = (uint8)atoul(row[ItemField::bardlevel]); - item.Bard.Level2 = (uint8)atoul(row[ItemField::bardlevel2]); - item.QuestItemFlag = (atoi(row[ItemField::questitemflag])==0) ? false : true; - item.SVCorruption = (int32)atoi(row[ItemField::svcorruption]); - item.Purity = (uint32)atoul(row[ItemField::purity]); - item.EvolvingLevel = (uint8)atoul(row[ItemField::evolvinglevel]); - item.BackstabDmg = (uint32)atoul(row[ItemField::backstabdmg]); - item.DSMitigation = (uint32)atoul(row[ItemField::dsmitigation]); - item.HeroicStr = (int32)atoi(row[ItemField::heroic_str]); - item.HeroicInt = (int32)atoi(row[ItemField::heroic_int]); - item.HeroicWis = (int32)atoi(row[ItemField::heroic_wis]); - item.HeroicAgi = (int32)atoi(row[ItemField::heroic_agi]); - item.HeroicDex = (int32)atoi(row[ItemField::heroic_dex]); - item.HeroicSta = (int32)atoi(row[ItemField::heroic_sta]); - item.HeroicCha = (int32)atoi(row[ItemField::heroic_cha]); - item.HeroicMR = (int32)atoi(row[ItemField::heroic_mr]); - item.HeroicFR = (int32)atoi(row[ItemField::heroic_fr]); - item.HeroicCR = (int32)atoi(row[ItemField::heroic_cr]); - item.HeroicDR = (int32)atoi(row[ItemField::heroic_dr]); - item.HeroicPR = (int32)atoi(row[ItemField::heroic_pr]); - item.HeroicSVCorrup = (int32)atoi(row[ItemField::heroic_svcorrup]); - item.HealAmt = (int32)atoi(row[ItemField::healamt]); - item.SpellDmg = (int32)atoi(row[ItemField::spelldmg]); - item.LDoNSellBackRate = (uint32)atoul(row[ItemField::ldonsellbackrate]); - item.ScriptFileID = (uint32)atoul(row[ItemField::scriptfileid]); - item.ExpendableArrow = (uint16)atoul(row[ItemField::expendablearrow]); - item.Clairvoyance = (uint32)atoul(row[ItemField::clairvoyance]); + item.Proc.Effect = (int32)atoul(row[ItemField::proceffect]); + item.Proc.Type = (uint8)atoul(row[ItemField::proctype]); + item.Proc.Level = (uint8)atoul(row[ItemField::proclevel]); + item.Proc.Level2 = (uint8)atoul(row[ItemField::proclevel2]); + item.Worn.Effect = (int32)atoul(row[ItemField::worneffect]); + item.Worn.Type = (uint8)atoul(row[ItemField::worntype]); + item.Worn.Level = (uint8)atoul(row[ItemField::wornlevel]); + item.Worn.Level2 = (uint8)atoul(row[ItemField::wornlevel2]); + item.Focus.Effect = (int32)atoul(row[ItemField::focuseffect]); + item.Focus.Type = (uint8)atoul(row[ItemField::focustype]); + item.Focus.Level = (uint8)atoul(row[ItemField::focuslevel]); + item.Focus.Level2 = (uint8)atoul(row[ItemField::focuslevel2]); + item.Scroll.Effect = (int32)atoul(row[ItemField::scrolleffect]); + item.Scroll.Type = (uint8)atoul(row[ItemField::scrolltype]); + item.Scroll.Level = (uint8)atoul(row[ItemField::scrolllevel]); + item.Scroll.Level2 = (uint8)atoul(row[ItemField::scrolllevel2]); + item.Bard.Effect = (int32)atoul(row[ItemField::bardeffect]); + item.Bard.Type = (uint8)atoul(row[ItemField::bardtype]); + item.Bard.Level = (uint8)atoul(row[ItemField::bardlevel]); + item.Bard.Level2 = (uint8)atoul(row[ItemField::bardlevel2]); + item.QuestItemFlag = (atoi(row[ItemField::questitemflag]) == 0) ? false : true; + item.SVCorruption = (int32)atoi(row[ItemField::svcorruption]); + item.Purity = (uint32)atoul(row[ItemField::purity]); + item.EvolvingItem = (uint8)atoul(row[ItemField::evoitem]); + item.EvolvingID = (uint8)atoul(row[ItemField::evoid]); + item.EvolvingLevel = (uint8)atoul(row[ItemField::evolvinglevel]); + item.EvolvingMax = (uint8)atoul(row[ItemField::evomax]); + item.BackstabDmg = (uint32)atoul(row[ItemField::backstabdmg]); + item.DSMitigation = (uint32)atoul(row[ItemField::dsmitigation]); + item.HeroicStr = (int32)atoi(row[ItemField::heroic_str]); + item.HeroicInt = (int32)atoi(row[ItemField::heroic_int]); + item.HeroicWis = (int32)atoi(row[ItemField::heroic_wis]); + item.HeroicAgi = (int32)atoi(row[ItemField::heroic_agi]); + item.HeroicDex = (int32)atoi(row[ItemField::heroic_dex]); + item.HeroicSta = (int32)atoi(row[ItemField::heroic_sta]); + item.HeroicCha = (int32)atoi(row[ItemField::heroic_cha]); + item.HeroicMR = (int32)atoi(row[ItemField::heroic_mr]); + item.HeroicFR = (int32)atoi(row[ItemField::heroic_fr]); + item.HeroicCR = (int32)atoi(row[ItemField::heroic_cr]); + item.HeroicDR = (int32)atoi(row[ItemField::heroic_dr]); + item.HeroicPR = (int32)atoi(row[ItemField::heroic_pr]); + item.HeroicSVCorrup = (int32)atoi(row[ItemField::heroic_svcorrup]); + item.HealAmt = (int32)atoi(row[ItemField::healamt]); + item.SpellDmg = (int32)atoi(row[ItemField::spelldmg]); + item.LDoNSellBackRate = (uint32)atoul(row[ItemField::ldonsellbackrate]); + item.ScriptFileID = (uint32)atoul(row[ItemField::scriptfileid]); + item.ExpendableArrow = (uint16)atoul(row[ItemField::expendablearrow]); + item.Clairvoyance = (uint32)atoul(row[ItemField::clairvoyance]); - strcpy(item.ClickName,row[ItemField::clickname]); - strcpy(item.ProcName,row[ItemField::procname]); - strcpy(item.WornName,row[ItemField::wornname]); - strcpy(item.FocusName,row[ItemField::focusname]); - strcpy(item.ScrollName,row[ItemField::scrollname]); - - try { - hash.insert(item.ID, item); - } catch(std::exception &ex) { - Log.Out(Logs::General, Logs::Error, "Database::LoadItems: %s", ex.what()); - break; - } - } + strcpy(item.ClickName, row[ItemField::clickname]); + strcpy(item.ProcName, row[ItemField::procname]); + strcpy(item.WornName, row[ItemField::wornname]); + strcpy(item.FocusName, row[ItemField::focusname]); + strcpy(item.ScrollName, row[ItemField::scrollname]); + try { + hash.insert(item.ID, item); + } catch (std::exception &ex) { + Log.Out(Logs::General, Logs::Error, "Database::LoadItems: %s", ex.what()); + break; + } + } } -const Item_Struct* SharedDatabase::GetItem(uint32 id) { +const EQEmu::ItemBase* SharedDatabase::GetItem(uint32 id) { if (id == 0) { return nullptr; @@ -1104,7 +1105,7 @@ const Item_Struct* SharedDatabase::GetItem(uint32 id) { return nullptr; } -const Item_Struct* SharedDatabase::IterateItems(uint32* id) { +const EQEmu::ItemBase* SharedDatabase::IterateItems(uint32* id) { if(!items_hash || !id) { return nullptr; } @@ -1229,27 +1230,17 @@ void SharedDatabase::LoadNPCFactionLists(void *data, uint32 size, uint32 list_co } -bool SharedDatabase::LoadNPCFactionLists() { - if(faction_hash) { - return true; - } +bool SharedDatabase::LoadNPCFactionLists(const std::string &prefix) { + faction_mmf.reset(nullptr); + faction_hash.reset(nullptr); try { + auto Config = EQEmuConfig::get(); EQEmu::IPCMutex mutex("faction"); mutex.Lock(); - faction_mmf = new EQEmu::MemoryMappedFile("shared/faction"); - - uint32 list_count = 0; - uint32 max_lists = 0; - GetFactionListInfo(list_count, max_lists); - uint32 size = static_cast(EQEmu::FixedMemoryHashSet::estimated_size( - list_count, max_lists)); - - if(faction_mmf->Size() != size) { - EQ_EXCEPT("SharedDatabase", "Couldn't load npc factions because faction_mmf->Size() != size"); - } - - faction_hash = new EQEmu::FixedMemoryHashSet(reinterpret_cast(faction_mmf->Get()), size); + std::string file_name = Config->SharedMemDir + prefix + std::string("faction"); + faction_mmf = std::unique_ptr(new EQEmu::MemoryMappedFile(file_name)); + faction_hash = std::unique_ptr>(new EQEmu::FixedMemoryHashSet(reinterpret_cast(faction_mmf->Get()), faction_mmf->Size())); mutex.Unlock(); } catch(std::exception& ex) { Log.Out(Logs::General, Logs::Error, "Error Loading npc factions: %s", ex.what()); @@ -1262,7 +1253,7 @@ bool SharedDatabase::LoadNPCFactionLists() { // Create appropriate ItemInst class ItemInst* SharedDatabase::CreateItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint32 aug6, uint8 attuned) { - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; ItemInst* inst = nullptr; item = GetItem(item_id); @@ -1289,7 +1280,7 @@ ItemInst* SharedDatabase::CreateItem(uint32 item_id, int16 charges, uint32 aug1, // Create appropriate ItemInst class -ItemInst* SharedDatabase::CreateItem(const Item_Struct* item, int16 charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint32 aug6, uint8 attuned) +ItemInst* SharedDatabase::CreateItem(const EQEmu::ItemBase* item, int16 charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint32 aug6, uint8 attuned) { ItemInst* inst = nullptr; if (item) { @@ -1313,7 +1304,7 @@ ItemInst* SharedDatabase::CreateItem(const Item_Struct* item, int16 charges, uin return inst; } -ItemInst* SharedDatabase::CreateBaseItem(const Item_Struct* item, int16 charges) { +ItemInst* SharedDatabase::CreateBaseItem(const EQEmu::ItemBase* item, int16 charges) { ItemInst* inst = nullptr; if (item) { // if maxcharges is -1 that means it is an unlimited use item. @@ -1362,39 +1353,45 @@ int32 SharedDatabase::DeleteStalePlayerCorpses() { return results.RowsAffected(); } -bool SharedDatabase::GetCommandSettings(std::map &commands) { +bool SharedDatabase::GetCommandSettings(std::map>> &command_settings) +{ + command_settings.clear(); - const std::string query = "SELECT command, access FROM commands"; + std::string query = "SELECT `command`, `access`, `aliases` FROM `command_settings`"; auto results = QueryDatabase(query); - if (!results.Success()) { + if (!results.Success()) return false; + + for (auto row = results.begin(); row != results.end(); ++row) { + command_settings[row[0]].first = atoi(row[1]); + if (row[2][0] == 0) + continue; + + std::vector aliases = SplitString(row[2], '|'); + for (auto iter = aliases.begin(); iter != aliases.end(); ++iter) { + if (iter->empty()) + continue; + command_settings[row[0]].second.push_back(*iter); + } } - commands.clear(); - - for (auto row = results.begin(); row != results.end(); ++row) - commands[row[0]]=atoi(row[1]); - return true; } -bool SharedDatabase::LoadSkillCaps() { - if(skill_caps_mmf) - return true; +bool SharedDatabase::LoadSkillCaps(const std::string &prefix) { + skill_caps_mmf.reset(nullptr); uint32 class_count = PLAYER_CLASS_COUNT; - uint32 skill_count = HIGHEST_SKILL + 1; + uint32 skill_count = EQEmu::skills::HIGHEST_SKILL + 1; uint32 level_count = HARD_LEVEL_CAP + 1; uint32 size = (class_count * skill_count * level_count * sizeof(uint16)); try { + auto Config = EQEmuConfig::get(); EQEmu::IPCMutex mutex("skill_caps"); mutex.Lock(); - skill_caps_mmf = new EQEmu::MemoryMappedFile("shared/skill_caps"); - if(skill_caps_mmf->Size() != size) { - EQ_EXCEPT("SharedDatabase", "Unable to load skill caps: skill_caps_mmf->Size() != size"); - } - + std::string file_name = Config->SharedMemDir + prefix + std::string("skill_caps"); + skill_caps_mmf = std::unique_ptr(new EQEmu::MemoryMappedFile(file_name)); mutex.Unlock(); } catch(std::exception &ex) { Log.Out(Logs::General, Logs::Error, "Error loading skill caps: %s", ex.what()); @@ -1406,7 +1403,7 @@ bool SharedDatabase::LoadSkillCaps() { void SharedDatabase::LoadSkillCaps(void *data) { uint32 class_count = PLAYER_CLASS_COUNT; - uint32 skill_count = HIGHEST_SKILL + 1; + uint32 skill_count = EQEmu::skills::HIGHEST_SKILL + 1; uint32 level_count = HARD_LEVEL_CAP + 1; uint16 *skill_caps_table = reinterpret_cast(data); @@ -1431,7 +1428,7 @@ void SharedDatabase::LoadSkillCaps(void *data) { } } -uint16 SharedDatabase::GetSkillCap(uint8 Class_, SkillUseTypes Skill, uint8 Level) { +uint16 SharedDatabase::GetSkillCap(uint8 Class_, EQEmu::skills::SkillType Skill, uint8 Level) { if(!skill_caps_mmf) { return 0; } @@ -1445,7 +1442,7 @@ uint16 SharedDatabase::GetSkillCap(uint8 Class_, SkillUseTypes Skill, uint8 Leve } uint32 class_count = PLAYER_CLASS_COUNT; - uint32 skill_count = HIGHEST_SKILL + 1; + uint32 skill_count = EQEmu::skills::HIGHEST_SKILL + 1; uint32 level_count = HARD_LEVEL_CAP + 1; if(Class_ > class_count || static_cast(Skill) > skill_count || Level > level_count) { return 0; @@ -1460,7 +1457,7 @@ uint16 SharedDatabase::GetSkillCap(uint8 Class_, SkillUseTypes Skill, uint8 Leve return skill_caps_table[index]; } -uint8 SharedDatabase::GetTrainLevel(uint8 Class_, SkillUseTypes Skill, uint8 Level) { +uint8 SharedDatabase::GetTrainLevel(uint8 Class_, EQEmu::skills::SkillType Skill, uint8 Level) { if(!skill_caps_mmf) { return 0; } @@ -1474,7 +1471,7 @@ uint8 SharedDatabase::GetTrainLevel(uint8 Class_, SkillUseTypes Skill, uint8 Lev } uint32 class_count = PLAYER_CLASS_COUNT; - uint32 skill_count = HIGHEST_SKILL + 1; + uint32 skill_count = EQEmu::skills::HIGHEST_SKILL + 1; uint32 level_count = HARD_LEVEL_CAP + 1; if(Class_ > class_count || static_cast(Skill) > skill_count || Level > level_count) { return 0; @@ -1542,8 +1539,30 @@ int SharedDatabase::GetMaxSpellID() { return atoi(row[0]); } +bool SharedDatabase::LoadSpells(const std::string &prefix, int32 *records, const SPDat_Spell_Struct **sp) { + spells_mmf.reset(nullptr); + + try { + auto Config = EQEmuConfig::get(); + EQEmu::IPCMutex mutex("spells"); + mutex.Lock(); + + std::string file_name = Config->SharedMemDir + prefix + std::string("spells"); + spells_mmf = std::unique_ptr(new EQEmu::MemoryMappedFile(file_name)); + *records = *reinterpret_cast(spells_mmf->Get()); + *sp = reinterpret_cast((char*)spells_mmf->Get() + 4); + mutex.Unlock(); + } + catch(std::exception& ex) { + Log.Out(Logs::General, Logs::Error, "Error Loading Spells: %s", ex.what()); + return false; + } + return true; +} + void SharedDatabase::LoadSpells(void *data, int max_spells) { - SPDat_Spell_Struct *sp = reinterpret_cast(data); + *(uint32*)data = max_spells; + SPDat_Spell_Struct *sp = reinterpret_cast((char*)data + sizeof(uint32)); const std::string query = "SELECT * FROM spells_new ORDER BY id ASC"; auto results = QueryDatabase(query); @@ -1623,10 +1642,10 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) { int tmp_skill = atoi(row[100]);; - if(tmp_skill < 0 || tmp_skill > HIGHEST_SKILL) - sp[tempid].skill = SkillBegging; /* not much better we can do. */ // can probably be changed to client-based 'SkillNone' once activated + if (tmp_skill < 0 || tmp_skill > EQEmu::skills::HIGHEST_SKILL) + sp[tempid].skill = EQEmu::skills::SkillBegging; /* not much better we can do. */ // can probably be changed to client-based 'SkillNone' once activated else - sp[tempid].skill = (SkillUseTypes) tmp_skill; + sp[tempid].skill = (EQEmu::skills::SkillType) tmp_skill; sp[tempid].zonetype=atoi(row[101]); sp[tempid].EnvironmentType=atoi(row[102]); @@ -1645,12 +1664,13 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) { sp[tempid].uninterruptable=atoi(row[146]) != 0; sp[tempid].ResistDiff=atoi(row[147]); - sp[tempid].dot_stacking_exempt=atoi(row[148]); + sp[tempid].dot_stacking_exempt = atoi(row[148]) != 0; sp[tempid].RecourseLink = atoi(row[150]); sp[tempid].no_partial_resist = atoi(row[151]) != 0; sp[tempid].short_buff_box = atoi(row[154]); sp[tempid].descnum = atoi(row[155]); + sp[tempid].typedescnum = atoi(row[156]); sp[tempid].effectdescnum = atoi(row[157]); sp[tempid].npc_no_los = atoi(row[159]) != 0; @@ -1669,6 +1689,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) { sp[tempid].pvpresistcalc=atoi(row[178]); sp[tempid].pvpresistcap=atoi(row[179]); sp[tempid].spell_category=atoi(row[180]); + sp[tempid].cast_not_standing = atoi(row[184]) != 0; sp[tempid].can_mgb=atoi(row[185]); sp[tempid].dispel_flag = atoi(row[186]); sp[tempid].MinResist = atoi(row[189]); @@ -1679,25 +1700,29 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) { sp[tempid].directional_start = static_cast(atoi(row[194])); sp[tempid].directional_end = static_cast(atoi(row[195])); sp[tempid].sneak = atoi(row[196]) != 0; - sp[tempid].not_extendable = atoi(row[197]) != 0; + sp[tempid].not_focusable = atoi(row[197]) != 0; + sp[tempid].no_detrimental_spell_aggro = atoi(row[198]) != 0; sp[tempid].suspendable = atoi(row[200]) != 0; sp[tempid].viral_range = atoi(row[201]); + sp[tempid].songcap = atoi(row[202]); sp[tempid].no_block = atoi(row[205]); sp[tempid].spellgroup=atoi(row[207]); sp[tempid].rank = atoi(row[208]); - sp[tempid].powerful_flag=atoi(row[209]); + sp[tempid].no_resist=atoi(row[209]); sp[tempid].CastRestriction = atoi(row[211]); sp[tempid].AllowRest = atoi(row[212]) != 0; sp[tempid].InCombat = atoi(row[213]) != 0; sp[tempid].OutofCombat = atoi(row[214]) != 0; + sp[tempid].override_crit_chance = atoi(row[217]); sp[tempid].aemaxtargets = atoi(row[218]); - sp[tempid].maxtargets = atoi(row[219]); + sp[tempid].no_heal_damage_item_mod = atoi(row[219]); sp[tempid].persistdeath = atoi(row[224]) != 0; sp[tempid].min_dist = atof(row[227]); sp[tempid].min_dist_mod = atof(row[228]); sp[tempid].max_dist = atof(row[229]); sp[tempid].max_dist_mod = atof(row[230]); sp[tempid].min_range = static_cast(atoi(row[231])); + sp[tempid].no_remove = atoi(row[232]) != 0; sp[tempid].DamageShieldType = 0; } @@ -1719,25 +1744,16 @@ int SharedDatabase::GetMaxBaseDataLevel() { return atoi(row[0]); } -bool SharedDatabase::LoadBaseData() { - if(base_data_mmf) { - return true; - } +bool SharedDatabase::LoadBaseData(const std::string &prefix) { + base_data_mmf.reset(nullptr); try { + auto Config = EQEmuConfig::get(); EQEmu::IPCMutex mutex("base_data"); mutex.Lock(); - base_data_mmf = new EQEmu::MemoryMappedFile("shared/base_data"); - - int size = 16 * (GetMaxBaseDataLevel() + 1) * sizeof(BaseDataStruct); - if(size == 0) { - EQ_EXCEPT("SharedDatabase", "Base Data size is zero"); - } - - if(base_data_mmf->Size() != size) { - EQ_EXCEPT("SharedDatabase", "Couldn't load base data because base_data_mmf->Size() != size"); - } + std::string file_name = Config->SharedMemDir + prefix + std::string("base_data"); + base_data_mmf = std::unique_ptr(new EQEmu::MemoryMappedFile(file_name)); mutex.Unlock(); } catch(std::exception& ex) { Log.Out(Logs::General, Logs::Error, "Error Loading Base Data: %s", ex.what()); @@ -1793,7 +1809,6 @@ void SharedDatabase::LoadBaseData(void *data, int max_level) { bd->mana_factor = atof(row[8]); bd->endurance_factor = atof(row[9]); } - } const BaseDataStruct* SharedDatabase::GetBaseData(int lvl, int cl) { @@ -1931,6 +1946,7 @@ void SharedDatabase::LoadLootDrops(void *data, uint32 size) { "ON lootdrop.id = lootdrop_entries.lootdrop_id ORDER BY lootdrop_id"; auto results = QueryDatabase(query); if (!results.Success()) { + return; } uint32 current_id = 0; @@ -1967,21 +1983,24 @@ void SharedDatabase::LoadLootDrops(void *data, uint32 size) { } -bool SharedDatabase::LoadLoot() { - if(loot_table_mmf || loot_drop_mmf) - return true; +bool SharedDatabase::LoadLoot(const std::string &prefix) { + loot_table_mmf.reset(nullptr); + loot_drop_mmf.reset(nullptr); try { + auto Config = EQEmuConfig::get(); EQEmu::IPCMutex mutex("loot"); mutex.Lock(); - loot_table_mmf = new EQEmu::MemoryMappedFile("shared/loot_table"); - loot_table_hash = new EQEmu::FixedMemoryVariableHashSet( + std::string file_name_lt = Config->SharedMemDir + prefix + std::string("loot_table"); + loot_table_mmf = std::unique_ptr(new EQEmu::MemoryMappedFile(file_name_lt)); + loot_table_hash = std::unique_ptr>(new EQEmu::FixedMemoryVariableHashSet( reinterpret_cast(loot_table_mmf->Get()), - loot_table_mmf->Size()); - loot_drop_mmf = new EQEmu::MemoryMappedFile("shared/loot_drop"); - loot_drop_hash = new EQEmu::FixedMemoryVariableHashSet( + loot_table_mmf->Size())); + std::string file_name_ld = Config->SharedMemDir + prefix + std::string("loot_drop"); + loot_drop_mmf = std::unique_ptr(new EQEmu::MemoryMappedFile(file_name_ld)); + loot_drop_hash = std::unique_ptr>(new EQEmu::FixedMemoryVariableHashSet( reinterpret_cast(loot_drop_mmf->Get()), - loot_drop_mmf->Size()); + loot_drop_mmf->Size())); mutex.Unlock(); } catch(std::exception &ex) { Log.Out(Logs::General, Logs::Error, "Error loading loot: %s", ex.what()); @@ -2021,7 +2040,7 @@ const LootDrop_Struct* SharedDatabase::GetLootDrop(uint32 lootdrop_id) { void SharedDatabase::LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* message) { std::string query = StringFormat("SELECT `inspect_message` FROM `character_inspect_messages` WHERE `id` = %u LIMIT 1", character_id); - auto results = QueryDatabase(query); + auto results = QueryDatabase(query); auto row = results.begin(); memset(message, '\0', sizeof(InspectMessage_Struct)); for (auto row = results.begin(); row != results.end(); ++row) { @@ -2031,29 +2050,7 @@ void SharedDatabase::LoadCharacterInspectMessage(uint32 character_id, InspectMes void SharedDatabase::SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct* message) { std::string query = StringFormat("REPLACE INTO `character_inspect_messages` (id, inspect_message) VALUES (%u, '%s')", character_id, EscapeString(message->text).c_str()); - auto results = QueryDatabase(query); -} - -void SharedDatabase::GetBotInspectMessage(uint32 botid, InspectMessage_Struct* message) { - - std::string query = StringFormat("SELECT BotInspectMessage FROM bots WHERE BotID = %i", botid); auto results = QueryDatabase(query); - if (!results.Success()) { - return; - } - - if (results.RowCount() != 1) - return; - - auto row = results.begin(); - memcpy(message, row[0], sizeof(InspectMessage_Struct)); - -} - -void SharedDatabase::SetBotInspectMessage(uint32 botid, const InspectMessage_Struct* message) { - std::string msg = EscapeString(message->text); - std::string query = StringFormat("UPDATE bots SET BotInspectMessage = '%s' WHERE BotID = %i", msg.c_str(), botid); - QueryDatabase(query); } bool SharedDatabase::VerifyToken(std::string token, int& status) { diff --git a/common/shareddb.h b/common/shareddb.h index 6562b4d22..821754ec6 100644 --- a/common/shareddb.h +++ b/common/shareddb.h @@ -1,3 +1,21 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #ifndef SHAREDDB_H_ #define SHAREDDB_H_ @@ -12,6 +30,7 @@ #include #include +#include class EvolveInfo; class Inventory; @@ -20,12 +39,13 @@ struct BaseDataStruct; struct InspectMessage_Struct; struct PlayerProfile_Struct; struct SPDat_Spell_Struct; -struct Item_Struct; struct NPCFactionList; struct LootTable_Struct; struct LootDrop_Struct; + namespace EQEmu { + struct ItemBase; class MemoryMappedFile; } @@ -50,9 +70,7 @@ class SharedDatabase : public Database int32 DeleteStalePlayerCorpses(); void LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* message); void SaveCharacterInspectMessage(uint32 character_id, const InspectMessage_Struct* message); - void GetBotInspectMessage(uint32 botid, InspectMessage_Struct* message); - void SetBotInspectMessage(uint32 botid, const InspectMessage_Struct* message); - bool GetCommandSettings(std::map &commands); + bool GetCommandSettings(std::map>> &command_settings); uint32 GetTotalTimeEntitledOnAccount(uint32 AccountID); /* @@ -82,8 +100,8 @@ class SharedDatabase : public Database Item Methods */ ItemInst* CreateItem(uint32 item_id, int16 charges = 0, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, uint8 attuned = 0); - ItemInst* CreateItem(const Item_Struct* item, int16 charges = 0, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, uint8 attuned = 0); - ItemInst* CreateBaseItem(const Item_Struct* item, int16 charges = 0); + ItemInst* CreateItem(const EQEmu::ItemBase* item, int16 charges = 0, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, uint8 attuned = 0); + ItemInst* CreateBaseItem(const EQEmu::ItemBase* item, int16 charges = 0); // Web Token Verification bool VerifyToken(std::string token, int& status); @@ -95,52 +113,54 @@ class SharedDatabase : public Database //items void GetItemsCount(int32 &item_count, uint32 &max_id); void LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id); - bool LoadItems(); - const Item_Struct* IterateItems(uint32* id); - const Item_Struct* GetItem(uint32 id); + bool LoadItems(const std::string &prefix); + const EQEmu::ItemBase* IterateItems(uint32* id); + const EQEmu::ItemBase* GetItem(uint32 id); const EvolveInfo* GetEvolveInfo(uint32 loregroup); //faction lists void GetFactionListInfo(uint32 &list_count, uint32 &max_lists); const NPCFactionList* GetNPCFactionEntry(uint32 id); void LoadNPCFactionLists(void *data, uint32 size, uint32 list_count, uint32 max_lists); - bool LoadNPCFactionLists(); + bool LoadNPCFactionLists(const std::string &prefix); //loot void GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot_table, uint32 &loot_table_entries); void GetLootDropInfo(uint32 &loot_drop_count, uint32 &max_loot_drop, uint32 &loot_drop_entries); void LoadLootTables(void *data, uint32 size); void LoadLootDrops(void *data, uint32 size); - bool LoadLoot(); + bool LoadLoot(const std::string &prefix); const LootTable_Struct* GetLootTable(uint32 loottable_id); const LootDrop_Struct* GetLootDrop(uint32 lootdrop_id); void LoadSkillCaps(void *data); - bool LoadSkillCaps(); - uint16 GetSkillCap(uint8 Class_, SkillUseTypes Skill, uint8 Level); - uint8 GetTrainLevel(uint8 Class_, SkillUseTypes Skill, uint8 Level); + bool LoadSkillCaps(const std::string &prefix); + uint16 GetSkillCap(uint8 Class_, EQEmu::skills::SkillType Skill, uint8 Level); + uint8 GetTrainLevel(uint8 Class_, EQEmu::skills::SkillType Skill, uint8 Level); int GetMaxSpellID(); + bool LoadSpells(const std::string &prefix, int32 *records, const SPDat_Spell_Struct **sp); void LoadSpells(void *data, int max_spells); void LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID); int GetMaxBaseDataLevel(); - bool LoadBaseData(); + bool LoadBaseData(const std::string &prefix); void LoadBaseData(void *data, int max_level); const BaseDataStruct* GetBaseData(int lvl, int cl); protected: - EQEmu::MemoryMappedFile *skill_caps_mmf; - EQEmu::MemoryMappedFile *items_mmf; - EQEmu::FixedMemoryHashSet *items_hash; - EQEmu::MemoryMappedFile *faction_mmf; - EQEmu::FixedMemoryHashSet *faction_hash; - EQEmu::MemoryMappedFile *loot_table_mmf; - EQEmu::FixedMemoryVariableHashSet *loot_table_hash; - EQEmu::MemoryMappedFile *loot_drop_mmf; - EQEmu::FixedMemoryVariableHashSet *loot_drop_hash; - EQEmu::MemoryMappedFile *base_data_mmf; + std::unique_ptr skill_caps_mmf; + std::unique_ptr items_mmf; + std::unique_ptr> items_hash; + std::unique_ptr faction_mmf; + std::unique_ptr> faction_hash; + std::unique_ptr loot_table_mmf; + std::unique_ptr> loot_table_hash; + std::unique_ptr loot_drop_mmf; + std::unique_ptr> loot_drop_hash; + std::unique_ptr base_data_mmf; + std::unique_ptr spells_mmf; }; #endif /*SHAREDDB_H_*/ diff --git a/common/skills.cpp b/common/skills.cpp index ceb726d8c..a23d77a7b 100644 --- a/common/skills.cpp +++ b/common/skills.cpp @@ -1,5 +1,6 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -9,17 +10,19 @@ but WITHOUT ANY WARRANTY except by those people which sell it, which are required to give you total support for your newly bought product; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. + A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "types.h" #include "skills.h" -bool EQEmu::IsTradeskill(SkillUseTypes skill) +#include + + +bool EQEmu::skills::IsTradeskill(SkillType skill) { switch (skill) { case SkillFishing: @@ -40,7 +43,7 @@ bool EQEmu::IsTradeskill(SkillUseTypes skill) } } -bool EQEmu::IsSpecializedSkill(SkillUseTypes skill) +bool EQEmu::skills::IsSpecializedSkill(SkillType skill) { // this could be a simple if, but if this is more portable if any IDs change (probably won't) // or any other specialized are added (also unlikely) @@ -55,3 +58,261 @@ bool EQEmu::IsSpecializedSkill(SkillUseTypes skill) return false; } } + +float EQEmu::skills::GetSkillMeleePushForce(SkillType skill) +{ + // This is the force/magnitude of the push from an attack of this skill type + // You can find these numbers in the clients skill struct + switch (skill) { + case Skill1HBlunt: + case Skill1HSlashing: + case SkillHandtoHand: + case SkillThrowing: + return 0.1f; + case Skill2HBlunt: + case Skill2HSlashing: + case SkillEagleStrike: + case SkillKick: + case SkillTigerClaw: + case Skill2HPiercing: + return 0.2f; + case SkillArchery: + return 0.15f; + case SkillBackstab: + case SkillBash: + return 0.3f; + case SkillDragonPunch: + case SkillRoundKick: + return 0.25f; + case SkillFlyingKick: + return 0.4f; + case Skill1HPiercing: + case SkillFrenzy: + return 0.05f; + case SkillIntimidation: + return 2.5f; + default: + return 0.0f; + } +} + +bool EQEmu::skills::IsBardInstrumentSkill(SkillType skill) +{ + switch (skill) { + case SkillBrassInstruments: + case SkillSinging: + case SkillStringedInstruments: + case SkillWindInstruments: + case SkillPercussionInstruments: + return true; + default: + return false; + } +} + +bool EQEmu::skills::IsCastingSkill(SkillType skill) +{ + switch (skill) { + case SkillAbjuration: + case SkillAlteration: + case SkillConjuration: + case SkillDivination: + case SkillEvocation: + return true; + default: + return false; + } +} + +const std::map& EQEmu::skills::GetSkillTypeMap() +{ + /* VS2013 code + static const std::map skill_use_types_map = { + { Skill1HBlunt, "1H Blunt" }, + { Skill1HSlashing, "1H Slashing" }, + { Skill2HBlunt, "2H Blunt" }, + { Skill2HSlashing, "2H Slashing" }, + { SkillAbjuration, "Abjuration" }, + { SkillAlteration, "Alteration" }, + { SkillApplyPoison, "Apply Poison" }, + { SkillArchery, "Archery" }, + { SkillBackstab, "Backstab" }, + { SkillBindWound, "Bind Wound" }, + { SkillBash, "Bash" }, + { SkillBlock, "Block" }, + { SkillBrassInstruments, "Brass Instruments" }, + { SkillChanneling, "Channeling" }, + { SkillConjuration, "Conjuration" }, + { SkillDefense, "Defense" }, + { SkillDisarm, "Disarm" }, + { SkillDisarmTraps, "Disarm Traps" }, + { SkillDivination, "Divination" }, + { SkillDodge, "Dodge" }, + { SkillDoubleAttack, "Double Attack" }, + { SkillDragonPunch, "Dragon Punch" }, + { SkillDualWield, "Dual Wield" }, + { SkillEagleStrike, "Eagle Strike" }, + { SkillEvocation, "Evocation" }, + { SkillFeignDeath, "Feign Death" }, + { SkillFlyingKick, "Flying Kick" }, + { SkillForage, "Forage" }, + { SkillHandtoHand, "Hand to Hand" }, + { SkillHide, "Hide" }, + { SkillKick, "Kick" }, + { SkillMeditate, "Meditate" }, + { SkillMend, "Mend" }, + { SkillOffense, "Offense" }, + { SkillParry, "Parry" }, + { SkillPickLock, "Pick Lock" }, + { Skill1HPiercing, "1H Piercing" }, + { SkillRiposte, "Riposte" }, + { SkillRoundKick, "Round Kick" }, + { SkillSafeFall, "Safe Fall" }, + { SkillSenseHeading, "Sense Heading" }, + { SkillSinging, "Singing" }, + { SkillSneak, "Sneak" }, + { SkillSpecializeAbjure, "Specialize Abjuration" }, + { SkillSpecializeAlteration, "Specialize Alteration" }, + { SkillSpecializeConjuration, "Specialize Conjuration" }, + { SkillSpecializeDivination, "Specialize Divination" }, + { SkillSpecializeEvocation, "Specialize Evocation" }, + { SkillPickPockets, "Pick Pockets" }, + { SkillStringedInstruments, "Stringed Instruments" }, + { SkillSwimming, "Swimming" }, + { SkillThrowing, "Throwing" }, + { SkillTigerClaw, "Tiger Claw" }, + { SkillTracking, "Tracking" }, + { SkillWindInstruments, "Wind Instruments" }, + { SkillFishing, "Fishing" }, + { SkillMakePoison, "Make Poison" }, + { SkillTinkering, "Tinkering" }, + { SkillResearch, "Research" }, + { SkillAlchemy, "Alchemy" }, + { SkillBaking, "Baking" }, + { SkillTailoring, "Tailoring" }, + { SkillSenseTraps, "Sense Traps" }, + { SkillBlacksmithing, "Blacksmithing" }, + { SkillFletching, "Fletching" }, + { SkillBrewing, "Brewing" }, + { SkillAlcoholTolerance, "Alcohol Tolerance" }, + { SkillBegging, "Begging" }, + { SkillJewelryMaking, "Jewelry Making" }, + { SkillPottery, "Pottery" }, + { SkillPercussionInstruments, "Percussion Instruments" }, + { SkillIntimidation, "Intimidation" }, + { SkillBerserking, "Berserking" }, + { SkillTaunt, "Taunt" }, + { SkillFrenzy, "Frenzy" }, + { SkillRemoveTraps, "Remove Traps" }, + { SkillTripleAttack, "Triple Attack" }, + { Skill2HPiercing, "2H Piercing" } + }; + */ + + /* VS2012 code - begin */ + + static const char* skill_use_names[SkillCount] = { + "1H Blunt", + "1H Slashing", + "2H Blunt", + "2H Slashing", + "Abjuration", + "Alteration", + "Apply Poison", + "Archery", + "Backstab", + "Bind Wound", + "Bash", + "Block", + "Brass Instruments", + "Channeling", + "Conjuration", + "Defense", + "Disarm", + "Disarm Traps", + "Divination", + "Dodge", + "Double Attack", + "Dragon Punch", + "Dual Wield", + "Eagle Strike", + "Evocation", + "Feign Death", + "Flying Kick", + "Forage", + "Hand to Hand", + "Hide", + "Kick", + "Meditate", + "Mend", + "Offense", + "Parry", + "Pick Lock", + "1H Piercing", + "Riposte", + "Round Kick", + "Safe Fall", + "Sense Heading", + "Singing", + "Sneak", + "Specialize Abjuration", + "Specialize Alteration", + "Specialize Conjuration", + "Specialize Divination", + "Specialize Evocation", + "Pick Pockets", + "Stringed Instruments", + "Swimming", + "Throwing", + "Tiger Claw", + "Tracking", + "Wind Instruments", + "Fishing", + "Make Poison", + "Tinkering", + "Research", + "Alchemy", + "Baking", + "Tailoring", + "Sense Traps", + "Blacksmithing", + "Fletching", + "Brewing", + "Alcohol Tolerance", + "Begging", + "Jewelry Making", + "Pottery", + "Percussion Instruments", + "Intimidation", + "Berserking", + "Taunt", + "Frenzy", + "Remove Traps", + "Triple Attack", + "2H Piercing" + }; + + static std::map skill_type_map; + + skill_type_map.clear(); + + for (int i = Skill1HBlunt; i < SkillCount; ++i) + skill_type_map[(SkillType)i] = skill_use_names[i]; + + /* VS2012 code - end */ + + return skill_type_map; +} + +EQEmu::SkillProfile::SkillProfile() +{ + memset(&Skill, 0, (sizeof(uint32) * PACKET_SKILL_ARRAY_SIZE)); +} + +uint32 EQEmu::SkillProfile::GetSkill(int skill_id) +{ + if (skill_id < 0 || skill_id >= PACKET_SKILL_ARRAY_SIZE) + return 0; + + return Skill[skill_id]; +} diff --git a/common/skills.h b/common/skills.h index f7f66b49c..19a996729 100644 --- a/common/skills.h +++ b/common/skills.h @@ -1,5 +1,6 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemulator.org) + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -9,267 +10,299 @@ but WITHOUT ANY WARRANTY except by those people which sell it, which are required to give you total support for your newly bought product; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. + A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#ifndef SKILLS_H -#define SKILLS_H - -/* -** This is really messed up... Are we using SkillTypes as a pseudo repository? The 76th skill really throws -** things for standardization... -** -** Below is an attempt to clean this up a little... + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* -** Skill use types -** -** (ref: eqstr_us.txt [05-10-2013]) -*/ -enum SkillUseTypes +#ifndef COMMON_SKILLS_H +#define COMMON_SKILLS_H + +#include "types.h" + +#include +#include + + +namespace EQEmu { + namespace skills { + enum SkillType : int { /*13855*/ Skill1HBlunt = 0, /*13856*/ Skill1HSlashing, /*13857*/ Skill2HBlunt, /*13858*/ Skill2HSlashing, /*13859*/ SkillAbjuration, -/*13861*/ SkillAlteration, +/*13861*/ SkillAlteration, // 5 /*13862*/ SkillApplyPoison, /*13863*/ SkillArchery, /*13864*/ SkillBackstab, /*13866*/ SkillBindWound, -/*13867*/ SkillBash, +/*13867*/ SkillBash, // 10 /*13871*/ SkillBlock, /*13872*/ SkillBrassInstruments, /*13874*/ SkillChanneling, /*13875*/ SkillConjuration, -/*13876*/ SkillDefense, +/*13876*/ SkillDefense, // 15 /*13877*/ SkillDisarm, /*13878*/ SkillDisarmTraps, /*13879*/ SkillDivination, /*13880*/ SkillDodge, -/*13881*/ SkillDoubleAttack, +/*13881*/ SkillDoubleAttack, // 20 /*13882*/ SkillDragonPunch, /*13924*/ SkillTailRake = SkillDragonPunch, // Iksar Monk equivilent /*13883*/ SkillDualWield, /*13884*/ SkillEagleStrike, /*13885*/ SkillEvocation, -/*13886*/ SkillFeignDeath, +/*13886*/ SkillFeignDeath, // 25 /*13888*/ SkillFlyingKick, /*13889*/ SkillForage, /*13890*/ SkillHandtoHand, /*13891*/ SkillHide, -/*13893*/ SkillKick, +/*13893*/ SkillKick, // 30 /*13894*/ SkillMeditate, /*13895*/ SkillMend, /*13896*/ SkillOffense, /*13897*/ SkillParry, -/*13899*/ SkillPickLock, +/*13899*/ SkillPickLock, // 35 /*13900*/ Skill1HPiercing, // Changed in RoF2(05-10-2013) /*13903*/ SkillRiposte, /*13904*/ SkillRoundKick, /*13905*/ SkillSafeFall, -/*13906*/ SkillSenseHeading, +/*13906*/ SkillSenseHeading, // 40 /*13908*/ SkillSinging, /*13909*/ SkillSneak, /*13910*/ SkillSpecializeAbjure, // No idea why they truncated this one..especially when there are longer ones... /*13911*/ SkillSpecializeAlteration, -/*13912*/ SkillSpecializeConjuration, +/*13912*/ SkillSpecializeConjuration, // 45 /*13913*/ SkillSpecializeDivination, /*13914*/ SkillSpecializeEvocation, /*13915*/ SkillPickPockets, /*13916*/ SkillStringedInstruments, -/*13917*/ SkillSwimming, +/*13917*/ SkillSwimming, // 50 /*13919*/ SkillThrowing, /*13920*/ SkillTigerClaw, /*13921*/ SkillTracking, /*13923*/ SkillWindInstruments, -/*13854*/ SkillFishing, +/*13854*/ SkillFishing, // 55 /*13853*/ SkillMakePoison, /*13852*/ SkillTinkering, /*13851*/ SkillResearch, /*13850*/ SkillAlchemy, -/*13865*/ SkillBaking, +/*13865*/ SkillBaking, // 60 /*13918*/ SkillTailoring, /*13907*/ SkillSenseTraps, /*13870*/ SkillBlacksmithing, /*13887*/ SkillFletching, -/*13873*/ SkillBrewing, +/*13873*/ SkillBrewing, // 65 /*13860*/ SkillAlcoholTolerance, /*13868*/ SkillBegging, /*13892*/ SkillJewelryMaking, /*13901*/ SkillPottery, -/*13898*/ SkillPercussionInstruments, +/*13898*/ SkillPercussionInstruments, // 70 /*13922*/ SkillIntimidation, /*13869*/ SkillBerserking, /*13902*/ SkillTaunt, -/*05837*/ SkillFrenzy, // This appears to be the only listed one not grouped with the others -/*00000*/ _EmuSkillCount // move to last position of active enumeration labels +/*05837*/ SkillFrenzy, // 74 // This appears to be the only listed one not grouped with the others // SoF+ specific skills -// /*03670*/ SkillRemoveTraps, -// /*13049*/ SkillTripleAttack, +/*03670*/ SkillRemoveTraps, // 75 +/*13049*/ SkillTripleAttack, // RoF2+ specific skills -// /*00789*/ Skill2HPiercing, -// /*01216*/ SkillNone, // This needs to move down as new skills are added +/*00789*/ Skill2HPiercing, // 77 +// /*01216*/ SkillNone, // This needs to move down as new skills are added + +/*00000*/ SkillCount // move to last position of active enumeration labels // Skill Counts -// /*-----*/ _SkillCount_62 = 75, // use for Ti and earlier max skill checks -// /*-----*/ _SkillCount_SoF = 77, // use for SoF thru RoF1 max skill checks -// /*-----*/ _SkillCount_RoF2 = 78, // use for RoF2 max skill checks +// /*-----*/ SkillCount_62 = 75, // use for Ti and earlier max skill checks +// /*-----*/ SkillCount_SoF = 77, // use for SoF thru RoF1 max skill checks +// /*-----*/ SkillCount_RoF2 = 78, // use for RoF2 max skill checks // Support values -// /*-----*/ _SkillServerArraySize = _SkillCount_RoF2, // Should reflect last client '_SkillCount' +// /*-----*/ SkillServerArraySize = _SkillCount_RoF2, // Should reflect last client '_SkillCount' // Superfluous additions to SkillUseTypes..server-use only // /*-----*/ ExtSkillGenericTradeskill = 100 -/* ([EQClientVersion] [0] - Unknown, [3] - SoF, [7] - RoF2[05-10-2013]) - [Skill] [index] | [0] [1] [2] [3] [4] [5] [6] [7] - Frenzy (05837) | --- 074 074 074 074 074 074 074 - Remove Traps (03670) | --- --- --- 075 075 075 075 075 - Triple Attack (13049) | --- --- --- 076 076 076 076 076 - 2H Piercing (00789) | --- --- --- --- --- --- --- 077 -*/ + /* ([EQClientVersion] [0] - Unknown, [3] - SoF, [7] - RoF2[05-10-2013]) + [Skill] [index] | [0] [1] [2] [3] [4] [5] [6] [7] + Frenzy (05837) | --- 074 074 074 074 074 074 074 + Remove Traps (03670) | --- --- --- 075 075 075 075 075 + Triple Attack (13049) | --- --- --- 076 076 076 076 076 + 2H Piercing (00789) | --- --- --- --- --- --- --- 077 + */ -/* - [SkillCaps.txt] (SoF+) - a^b^c^d(^e) (^e is RoF+, but cursory glance appears to be all zeros) + /* + [SkillCaps.txt] (SoF+) + a^b^c^d(^e) (^e is RoF+, but cursory glance appears to be all zeros) - a - Class - b - Skill - c - Level - d - Max Value - (e - Unknown) -*/ + a - Class + b - Skill + c - Level + d - Max Value + (e - Unknown) + */ -/* - NOTE: Disregard this until it is sorted out + /* + Changed (tradeskill==75) to ExtSkillGenericTradeskill in tradeskills.cpp for both instances. If it's a pseudo-enumeration of + an AA ability, then use the 'ExtSkill' ('ExtendedSkill') prefix with a value >= 100. (current implementation) + */ + }; - I changed (tradeskill==75) to ExtSkillGenericTradeskill in tradeskills.cpp for both instances. If it's a pseudo-enumeration of - an AA ability, then use the 'ExtSkill' ('ExtendedSkill') prefix with a value >= 100. (current implementation) - - We probably need to recode ALL of the skill checks to use the new Skill2HPiercing and ensure that the animation value is - properly changed in the patch files. As far as earlier clients using this new skill, it can be done, but we just need to ensure - that skill address is not inadvertently passed to the client..and we can just send an actual message for the skill-up. Use of a - command can tell the player what that particular skill value is. - - Nothing on SkillTripleAttack just yet..haven't looked into its current implementation. - - In addition to the above re-coding, we're probably going to need to rework the database pp blob to reserve space for the current - 100-dword buffer allocation. This way, we can just add new ones without having to rework it each time. - (Wasn't done for this in particular..but, thanks Akkadius!) - - -U -*/ -}; - -// temporary until it can be sorted out... -#define HIGHEST_SKILL SkillFrenzy -// Spell Effects use this value to determine if an effect applies to all skills. + // temporary until it can be sorted out... +#define HIGHEST_SKILL Skill2HPiercing + // Spell Effects use this value to determine if an effect applies to all skills. #define ALL_SKILLS -1 -// server profile does not reflect this yet..so, prefixed with 'PACKET_' + // server profile does not reflect this yet..so, prefixed with 'PACKET_' #define PACKET_SKILL_ARRAY_SIZE 100 -// TODO: add string return for skill names + bool IsTradeskill(SkillType skill); + bool IsSpecializedSkill(SkillType skill); + float GetSkillMeleePushForce(SkillType skill); + bool IsBardInstrumentSkill(SkillType skill); + bool IsCastingSkill(SkillType skill); -/* -** Old typedef enumeration -** -*/ -/* Correct Skill Numbers as of 4-14-2002 -typedef enum { - _1H_BLUNT = 0, - _1H_SLASHING = 1, - _2H_BLUNT = 2, - _2H_SLASHING = 3, - ABJURE = 4, - ALTERATION = 5, - APPLY_POISON = 6, - ARCHERY = 7, - BACKSTAB = 8, - BIND_WOUND = 9, - BASH = 10, - BLOCKSKILL = 11, - BRASS_INSTRUMENTS = 12, - CHANNELING = 13, - CONJURATION = 14, - DEFENSE = 15, - DISARM = 16, - DISARM_TRAPS = 17, - DIVINATION = 18, - DODGE = 19, - DOUBLE_ATTACK = 20, - DRAGON_PUNCH = 21, //aka Tail Rake - DUAL_WIELD = 22, - EAGLE_STRIKE = 23, - EVOCATION = 24, - FEIGN_DEATH = 25, - FLYING_KICK = 26, - FORAGE = 27, - HAND_TO_HAND = 28, - HIDE = 29, - KICK = 30, - MEDITATE = 31, - MEND = 32, - OFFENSE = 33, - PARRY = 34, - PICK_LOCK = 35, - PIERCING = 36, - RIPOSTE = 37, - ROUND_KICK = 38, - SAFE_FALL = 39, - SENSE_HEADING = 40, - SINGING = 41, - SNEAK = 42, - SPECIALIZE_ABJURE = 43, - SPECIALIZE_ALTERATION = 44, - SPECIALIZE_CONJURATION = 45, - SPECIALIZE_DIVINATION = 46, - SPECIALIZE_EVOCATION = 47, - PICK_POCKETS = 48, - STRINGED_INSTRUMENTS = 49, - SWIMMING = 50, - THROWING = 51, - TIGER_CLAW = 52, - TRACKING = 53, - WIND_INSTRUMENTS = 54, - FISHING = 55, - MAKE_POISON = 56, - TINKERING = 57, - RESEARCH = 58, - ALCHEMY = 59, - BAKING = 60, - TAILORING = 61, - SENSE_TRAPS = 62, - BLACKSMITHING = 63, - FLETCHING = 64, - BREWING = 65, - ALCOHOL_TOLERANCE = 66, - BEGGING = 67, - JEWELRY_MAKING = 68, - POTTERY = 69, - PERCUSSION_INSTRUMENTS = 70, - INTIMIDATION = 71, - BERSERKING = 72, - TAUNT = 73, - FRENZY = 74, - GENERIC_TRADESKILL = 75 -} SkillType; + extern const std::map& GetSkillTypeMap(); -#define HIGHEST_SKILL FRENZY -*/ + } /*skills*/ -// for skill related helper functions -namespace EQEmu { - bool IsTradeskill(SkillUseTypes skill); - bool IsSpecializedSkill(SkillUseTypes skill); -} + struct SkillProfile { // prototype - not implemented + union { + struct { + uint32 _1HBlunt; + uint32 _1HSlashing; + uint32 _2HBlunt; + uint32 _2HSlashing; + uint32 Abjuration; + uint32 Alteration; + uint32 ApplyPoison; + uint32 Archery; + uint32 Backstab; + uint32 BindWound; + uint32 Bash; + uint32 Block; + uint32 BrassInstruments; + uint32 Channeling; + uint32 Conjuration; + uint32 Defense; + uint32 Disarm; + uint32 DisarmTraps; + uint32 Divination; + uint32 Dodge; + uint32 DoubleAttack; + union { + uint32 DragonPunch; + uint32 TailRake; + }; + uint32 DualWield; + uint32 EagleStrike; + uint32 Evocation; + uint32 FeignDeath; + uint32 FlyingKick; + uint32 Forage; + uint32 HandtoHand; + uint32 Hide; + uint32 Kick; + uint32 Meditate; + uint32 Mend; + uint32 Offense; + uint32 Parry; + uint32 PickLock; + uint32 _1HPiercing; + uint32 Riposte; + uint32 RoundKick; + uint32 SafeFall; + uint32 SenseHeading; + uint32 Singing; + uint32 Sneak; + uint32 SpecializeAbjure; + uint32 SpecializeAlteration; + uint32 SpecializeConjuration; + uint32 SpecializeDivination; + uint32 SpecializeEvocation; + uint32 PickPockets; + uint32 StringedInstruments; + uint32 Swimming; + uint32 Throwing; + uint32 TigerClaw; + uint32 Tracking; + uint32 WindInstruments; + uint32 Fishing; + uint32 MakePoison; + uint32 Tinkering; + uint32 Research; + uint32 Alchemy; + uint32 Baking; + uint32 Tailoring; + uint32 SenseTraps; + uint32 Blacksmithing; + uint32 Fletching; + uint32 Brewing; + uint32 AlcoholTolerance; + uint32 Begging; + uint32 JewelryMaking; + uint32 Pottery; + uint32 PercussionInstruments; + uint32 Intimidation; + uint32 Berserking; + uint32 Taunt; + uint32 Frenzy; + uint32 RemoveTraps; + uint32 TripleAttack; + uint32 _2HPiercing; + uint32 unused1; + uint32 unused2; + uint32 unused3; + uint32 unused4; + uint32 unused5; + uint32 unused6; + uint32 unused7; + uint32 unused8; + uint32 unused9; + uint32 unused10; + uint32 unused11; + uint32 unused12; + uint32 unused13; + uint32 unused14; + uint32 unused15; + uint32 unused16; + uint32 unused17; + uint32 unused18; + uint32 unused19; + uint32 unused20; + uint32 unused21; + uint32 unused22; + }; + uint32 Skill[PACKET_SKILL_ARRAY_SIZE]; + }; -#endif + SkillProfile(); + + uint32* GetSkills() { return reinterpret_cast(&Skill); } + + skills::SkillType GetLastUseableSkill() { return EQEmu::skills::Skill2HPiercing; } + + size_t GetSkillsArraySize() { return PACKET_SKILL_ARRAY_SIZE; } + uint32 GetSkill(int skill_id); + + uint32 operator[](int skill_id) { return GetSkill(skill_id); } + + // const + uint32* GetSkills() const { return const_cast(this)->GetSkills(); } + + skills::SkillType GetLastUseableSkill() const { return const_cast(this)->GetLastUseableSkill(); } + + size_t GetSkillsArraySize() const { return const_cast(this)->GetSkillsArraySize(); } + uint32 GetSkill(int skill_id) const { return const_cast(this)->GetSkill(skill_id); } + + uint32 operator[](int skill_id) const { return const_cast(this)->GetSkill(skill_id); } + }; + +} /*EQEmu*/ + +#endif /*COMMON_SKILLS_H*/ diff --git a/common/spdat.cpp b/common/spdat.cpp index e52a06e2e..f22a82000 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -72,7 +72,7 @@ -#include "../common/eqemu_logsys.h" +#include "../common/eqemu_logsys.h" #include "classes.h" #include "spdat.h" @@ -162,7 +162,7 @@ bool IsCureSpell(uint16 spell_id) bool CureEffect = false; for(int i = 0; i < EFFECT_COUNT; i++){ - if (sp.effectid[i] == SE_DiseaseCounter || sp.effectid[i] == SE_PoisonCounter + if (sp.effectid[i] == SE_DiseaseCounter || sp.effectid[i] == SE_PoisonCounter || sp.effectid[i] == SE_CurseCounter || sp.effectid[i] == SE_CorruptionCounter) CureEffect = true; } @@ -235,8 +235,11 @@ bool IsBeneficialSpell(uint16 spell_id) // If the resisttype is magic and SpellAffectIndex is Calm/memblur/dispell sight // it's not beneficial if (spells[spell_id].resisttype == RESIST_MAGIC) { - if (sai == SAI_Calm || sai == SAI_Dispell_Sight || - sai == SAI_Memory_Blur || sai == SAI_Calm_Song) + // checking these SAI cause issues with the rng defensive proc line + // So I guess instead of fixing it for real, just a quick hack :P + if (spells[spell_id].effectid[0] != SE_DefensiveProc && + (sai == SAI_Calm || sai == SAI_Dispell_Sight || sai == SAI_Memory_Blur || + sai == SAI_Calm_Song)) return false; } else { // If the resisttype is not magic and spell is Bind Sight or Cast Sight @@ -405,7 +408,7 @@ bool IsPartialCapableSpell(uint16 spell_id) { if (spells[spell_id].no_partial_resist) return false; - + if (IsPureNukeSpell(spell_id)) return true; @@ -447,7 +450,7 @@ bool IsTGBCompatibleSpell(uint16 spell_id) bool IsBardSong(uint16 spell_id) { - if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 255) + if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 255 && !spells[spell_id].IsDisciplineBuff) return true; return false; @@ -669,9 +672,7 @@ bool IsDisciplineBuff(uint16 spell_id) if (!IsValidSpell(spell_id)) return false; - if (spells[spell_id].mana == 0 && spells[spell_id].short_buff_box == 0 && - (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep) && - spells[spell_id].targettype == ST_Self) + if (spells[spell_id].IsDisciplineBuff && spells[spell_id].targettype == ST_Self) return true; return false; @@ -693,9 +694,9 @@ bool IsCombatSkill(uint16 spell_id) { if (!IsValidSpell(spell_id)) return false; - + //Check if Discipline - if ((spells[spell_id].mana == 0 && (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep))) + if ((spells[spell_id].mana == 0 && (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep))) return true; return false; @@ -704,7 +705,7 @@ bool IsCombatSkill(uint16 spell_id) bool IsResurrectionEffects(uint16 spell_id) { // spell id 756 is Resurrection Effects spell - if(IsValidSpell(spell_id) && spell_id == 756) + if(IsValidSpell(spell_id) && (spell_id == 756 || spell_id == 757)) return true; return false; @@ -1040,7 +1041,7 @@ bool IsCastonFadeDurationSpell(uint16 spell_id) bool IsPowerDistModSpell(uint16 spell_id) { - if (IsValidSpell(spell_id) && + if (IsValidSpell(spell_id) && (spells[spell_id].max_dist_mod || spells[spell_id].min_dist_mod) && spells[spell_id].max_dist > spells[spell_id].min_dist) return true; @@ -1092,6 +1093,112 @@ bool DetrimentalSpellAllowsRest(uint16 spell_id) return false; } +bool NoDetrimentalSpellAggro(uint16 spell_id) +{ + if (IsValidSpell(spell_id)) + return spells[spell_id].no_detrimental_spell_aggro; + + return false; +} + +bool IsStackableDot(uint16 spell_id) +{ + // rules according to client + if (!IsValidSpell(spell_id)) + return false; + const auto &spell = spells[spell_id]; + if (spell.dot_stacking_exempt || spell.goodEffect || !spell.buffdurationformula) + return false; + return IsEffectInSpell(spell_id, SE_CurrentHP) || IsEffectInSpell(spell_id, SE_GravityEffect); +} + +bool IsCastWhileInvis(uint16 spell_id) +{ + if (!IsValidSpell(spell_id)) + return false; + const auto &spell = spells[spell_id]; + if (spell.sneak || spell.cast_not_standing) + return true; + return false; +} + +bool IsEffectIgnoredInStacking(int spa) +{ + // this should match RoF2 + switch (spa) { + case SE_SeeInvis: + case SE_DiseaseCounter: + case SE_PoisonCounter: + case SE_Levitate: + case SE_InfraVision: + case SE_UltraVision: + case SE_CurrentHPOnce: + case SE_CurseCounter: + case SE_ImprovedDamage: + case SE_ImprovedHeal: + case SE_SpellResistReduction: + case SE_IncreaseSpellHaste: + case SE_IncreaseSpellDuration: + case SE_IncreaseRange: + case SE_SpellHateMod: + case SE_ReduceReagentCost: + case SE_ReduceManaCost: + case SE_FcStunTimeMod: + case SE_LimitMaxLevel: + case SE_LimitResist: + case SE_LimitTarget: + case SE_LimitEffect: + case SE_LimitSpellType: + case SE_LimitSpell: + case SE_LimitMinDur: + case SE_LimitInstant: + case SE_LimitMinLevel: + case SE_LimitCastTimeMin: + case SE_LimitCastTimeMax: + case SE_StackingCommand_Block: + case SE_StackingCommand_Overwrite: + case SE_PetPowerIncrease: + case SE_SkillDamageAmount: + case SE_ChannelChanceSpells: + case SE_Blank: + case SE_FcDamageAmt: + case SE_SpellDurationIncByTic: + case SE_FcSpellVulnerability: + case SE_FcDamageAmtIncoming: + case SE_FcDamagePctCrit: + case SE_FcDamageAmtCrit: + case SE_ReduceReuseTimer: + case SE_LimitCombatSkills: + case SE_BlockNextSpellFocus: + case SE_SpellTrigger: + case SE_LimitManaMin: + case SE_CorruptionCounter: + case SE_ApplyEffect: + case SE_NegateSpellEffect: + case SE_LimitSpellGroup: + case SE_LimitManaMax: + case SE_FcHealAmt: + case SE_FcHealPctIncoming: + case SE_FcHealAmtIncoming: + case SE_FcHealPctCritIncoming: + case SE_FcHealAmtCrit: + case SE_LimitClass: + case SE_LimitRace: + case SE_FcBaseEffects: + case 415: + case SE_SkillDamageAmount2: + case SE_FcLimitUse: + case SE_FcIncreaseNumHits: + case SE_LimitUseMin: + case SE_LimitUseType: + case SE_GravityEffect: + case 425: + return true; + default: + return false; + } +} + uint32 GetNimbusEffect(uint16 spell_id) { if (IsValidSpell(spell_id)) diff --git a/common/spdat.h b/common/spdat.h index b70d708f0..2734f6078 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2005 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -38,6 +38,7 @@ #define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists. #define MaxLimitInclude 16 //Number(x 0.5) of focus Limiters that have inclusive checks used when calcing focus effects #define MAX_SKILL_PROCS 4 //Number of spells to check skill procs from. (This is arbitrary) [Single spell can have multiple proc checks] +#define MAX_SYMPATHETIC_PROCS 10 // Number of sympathetic procs a client can have (This is arbitrary) const int Z_AGGRO=10; @@ -99,23 +100,23 @@ typedef enum { /* 09 */ ST_Animal = 0x09, /* 10 */ ST_Undead = 0x0a, /* 11 */ ST_Summoned = 0x0b, -/* 12 */ // NOT USED +/* 12 */ // NOT USED error is 218 (This spell only works on things that are flying.) /* 13 */ ST_Tap = 0x0d, /* 14 */ ST_Pet = 0x0e, /* 15 */ ST_Corpse = 0x0f, /* 16 */ ST_Plant = 0x10, /* 17 */ ST_Giant = 0x11, //special giant /* 18 */ ST_Dragon = 0x12, //special dragon -/* 19 */ // NOT USED +/* 19 */ // NOT USED error is 227 (This spell only works on specific coldain.) /* 20 */ ST_TargetAETap = 0x14, -/* 21 */ // NOT USED -/* 22 */ // NOT USED -/* 23 */ // NOT USED +/* 21 */ // NOT USED same switch case as ST_Undead +/* 22 */ // NOT USED same switch case as ST_Summoned +/* 23 */ // NOT USED same switch case as ST_Animal /* 24 */ ST_UndeadAE = 0x18, /* 25 */ ST_SummonedAE = 0x19, /* 26 */ // NOT USED -/* 27 */ // NOT USED -/* 28 */ // NOT USED +/* 27 */ // NOT USED error is 223 (This spell only works on insects.) +/* 28 */ // NOT USED error is 223 (This spell only works on insects.) /* 29 */ // NOT USED /* 30 */ // NOT USED /* 31 */ // NOT USED @@ -132,7 +133,7 @@ typedef enum { /* 42 */ ST_Directional = 0x2a, //ae around this target between two angles /* 43 */ ST_GroupClientAndPet = 0x2b, /* 44 */ ST_Beam = 0x2c, -/* 45 */ ST_Ring = 0x2d, +/* 45 */ ST_Ring = 0x2d, /* 46 */ ST_TargetsTarget = 0x2e, // uses the target of your target /* 47 */ ST_PetMaster = 0x2f, // uses the master as target /* 48 */ // UNKNOWN @@ -150,10 +151,10 @@ typedef enum { } DmgShieldType; //Spell Effect IDs -// full listing: https://forums.station.sony.com/eq/index.php?threads/enumerated-spa-list.206288/ +// https://forums.daybreakgames.com/eq/index.php?threads/enumerated-spa-list.206288/ // mirror: http://pastebin.com/MYeQqGwe #define SE_CurrentHP 0 // implemented - Heals and nukes, repeates every tic if in a buff -#define SE_ArmorClass 1 // implemented +#define SE_ArmorClass 1 // implemented #define SE_ATK 2 // implemented #define SE_MovementSpeed 3 // implemented - SoW, SoC, etc #define SE_STR 4 // implemented @@ -196,7 +197,7 @@ typedef enum { #define SE_Destroy 41 // implemented - Disintegrate, Banishment of Shadows #define SE_ShadowStep 42 // implemented #define SE_Berserk 43 // implemented (*not used in any known live spell) Makes client 'Berserk' giving crip blow chance. -#define SE_Lycanthropy 44 // implemented +#define SE_Lycanthropy 44 // implemented #define SE_Vampirism 45 // implemented (*not used in any known live spell) Stackable lifetap from melee. #define SE_ResistFire 46 // implemented #define SE_ResistCold 47 // implemented @@ -246,7 +247,7 @@ typedef enum { #define SE_SummonCorpse 91 // implemented #define SE_InstantHate 92 // implemented - add hate #define SE_StopRain 93 // implemented - Wake of Karana -#define SE_NegateIfCombat 94 // implemented +#define SE_NegateIfCombat 94 // implemented #define SE_Sacrifice 95 // implemented #define SE_Silence 96 // implemented #define SE_ManaPool 97 // implemented @@ -298,7 +299,7 @@ typedef enum { #define SE_LimitCastTimeMin 143 // implemented #define SE_LimitCastTimeMax 144 // implemented (*not used in any known live spell) #define SE_Teleport2 145 // implemented - Banishment of the Pantheon -//#define SE_ElectricityResist 146 // *not implemented (Lightning Rod: 23233) +//#define SE_ElectricityResist 146 // *not implemented (Lightning Rod: 23233) #define SE_PercentalHeal 147 // implemented #define SE_StackingCommand_Block 148 // implemented? #define SE_StackingCommand_Overwrite 149 // implemented? @@ -380,47 +381,47 @@ typedef enum { #define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance. #define SE_TwoHandBash 226 // *not implemented as bonus #define SE_ReduceSkillTimer 227 // implemented -//#define SE_ReduceFallDamage 228 // not implented as bonus - reduce the damage that you take from falling +#define SE_ReduceFallDamage 228 // implented - reduce the damage that you take from falling #define SE_PersistantCasting 229 // implemented -//#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability +#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability #define SE_StunBashChance 231 // implemented - increase chance to stun from bash. #define SE_DivineSave 232 // implemented (base1 == % chance on death to insta-res) (base2 == spell cast on save) #define SE_Metabolism 233 // implemented - Modifies food/drink consumption rates. -//#define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison +#define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison #define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live. //#define SE_FreePet 236 // not used #define SE_GivePetGroupTarget 237 // implemented[AA] - (Pet Affinity) #define SE_IllusionPersistence 238 // implemented - lends persistence to your illusionary disguises, causing them to last until you die or the illusion is forcibly removed. -//#define SE_FeignedCastOnChance 239 // *not implemented as bonus - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you. +#define SE_FeignedCastOnChance 239 // implemented - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you. //#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.] #define SE_ImprovedReclaimEnergy 241 // implemented - increase the amount of mana returned to you when reclaiming your pet. #define SE_IncreaseChanceMemwipe 242 // implemented - increases the chance to wipe hate with memory blurr #define SE_CharmBreakChance 243 // implemented - Total Domination #define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break. -//#define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest +#define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest #define SE_SetBreathLevel 246 // *not implemented as bonus -#define SE_RaiseSkillCap 247 // *not implemented[AA] - adds skill over the skill cap. -//#define SE_SecondaryForte 248 // not implemented as bonus(gives you a 2nd specialize skill that can go past 50 to 100) +#define SE_RaiseSkillCap 247 // implemented[AA] - adds skill over the skill cap. +#define SE_SecondaryForte 248 // not implemented as bonus(gives you a 2nd specialize skill that can go past 50 to 100) #define SE_SecondaryDmgInc 249 // implemented[AA] Allows off hand weapon to recieve a damage bonus (Sinister Strikes) #define SE_SpellProcChance 250 // implemented - Increase chance to proc from melee proc spells (ie Spirit of Panther) #define SE_ConsumeProjectile 251 // implemented[AA] - chance to not consume an arrow (ConsumeProjectile = 100) #define SE_FrontalBackstabChance 252 // implemented[AA] - chance to perform a full damage backstab from front. #define SE_FrontalBackstabMinDmg 253 // implemented[AA] - allow a frontal backstab for mininum damage. #define SE_Blank 254 // implemented -//#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield -//#define SE_ShroudofStealth 256 // not implemented as bonus - rogue improved invs -//#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold +#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield +#define SE_ShroudofStealth 256 // implemented +#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold #define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab #define SE_CombatStability 259 // implemented[AA] - damage mitigation #define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType #define SE_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live) #define SE_RaiseStatCap 262 // implemented -//#define SE_TradeSkillMastery 263 // not implemented - lets you raise more than one tradeskill above master. -//#define SE_HastenedAASkill 264 // not implemented as bonus - Use redux field in aa_actions table for this effect +#define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master. +#define SE_HastenedAASkill 264 // implemented #define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled #define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon. #define SE_PetDiscipline2 267 // *not implemented - /pet focus, /pet no cast -//#define SE_ReduceTradeskillFail 268 // *not implemented? - reduces chance to fail with given tradeskill by a percent chance +#define SE_ReduceTradeskillFail 268 // implemented - reduces chance to fail with given tradeskill by a percent chance #define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound. #define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo) #define SE_BaseMovementSpeed 271 // implemented[AA] - mods basemove speed, doesn't stack with other move mods @@ -433,19 +434,19 @@ typedef enum { #define SE_FinishingBlow 278 // implemented[AA] - chance to do massive damage under 10% HP (base1 = chance, base2 = damage) #define SE_Flurry 279 // implemented #define SE_PetFlurry 280 // implemented[AA] -//#define SE_FeignedMinion 281 // *not implemented[AA] ability allows you to instruct your pet to feign death via the '/pet feign' command. value = succeed chance +#define SE_FeignedMinion 281 // *not implemented[AA] ability allows you to instruct your pet to feign death via the '/pet feign' command. value = succeed chance #define SE_ImprovedBindWound 282 // implemented[AA] - increase bind wound amount by percent. #define SE_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk //#define SE_LoHSetHeal 284 // not used -//#define SE_NimbleEvasion 285 // *not implemented - base1 = 100 for max +#define SE_NimbleEvasion 285 // *not implemented - base1 = 100 for max #define SE_FcDamageAmt 286 // implemented - adds direct spell damage #define SE_SpellDurationIncByTic 287 // implemented -#define SE_SpecialAttackKBProc 288 // implemented[AA] - Chance to to do a knockback from special attacks [AA Dragon Punch]. +#define SE_SkillAttackProc 288 // implemented[AA] - Chance to proc spell on skill attack usage (ex. Dragon Punch) #define SE_CastOnFadeEffect 289 // implemented - Triggers only if fades after natural duration. #define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap #define SE_Purify 291 // implemented - Removes determental effects #define SE_StrikeThrough2 292 // implemented[AA] - increasing chance of bypassing an opponent's special defenses, such as dodge, block, parry, and riposte. -#define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front. +#define SE_FrontalStunResist 293 // implemented[AA] - Reduce chance to be stunned from front. -- live descriptions sounds like this isn't limited to frontal anymore #define SE_CriticalSpellChance 294 // implemented - increase chance to critical hit and critical damage modifier. //#define SE_ReduceTimerSpecial 295 // not used #define SE_FcSpellVulnerability 296 // implemented - increase in incoming spell damage @@ -477,7 +478,7 @@ typedef enum { #define SE_GateToHomeCity 322 // implemented #define SE_DefensiveProc 323 // implemented #define SE_HPToMana 324 // implemented -//#define SE_ChanceInvsBreakToAoE 325 // *not implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell. +#define SE_NoBreakAESneak 325 // implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell. #define SE_SpellSlotIncrease 326 // *not implemented as bonus - increases your spell slot availability #define SE_MysticalAttune 327 // implemented - increases amount of buffs that a player can have #define SE_DelayDeath 328 // implemented - increases how far you can fall below 0 hp before you die @@ -485,7 +486,7 @@ typedef enum { #define SE_CriticalDamageMob 330 // implemented #define SE_Salvage 331 // implemented - chance to recover items that would be destroyed in failed tradeskill combine //#define SE_SummonToCorpse 332 // *not implemented AA - Call of the Wild (Druid/Shaman Res spell with no exp) -#define SE_CastOnRuneFadeEffect 333 // implemented +#define SE_CastOnRuneFadeEffect 333 // implemented #define SE_BardAEDot 334 // implemented #define SE_BlockNextSpellFocus 335 // implemented - base1 chance to block next spell ie Puratus (8494) //#define SE_IllusionaryTarget 336 // not used @@ -514,8 +515,8 @@ typedef enum { //#define SE_PassiveSenseTrap 359 // *not implemented - Invulnerability (Brell's Blessing) #define SE_ProcOnKillShot 360 // implemented - a buff that has a base1 % to cast spell base2 when you kill a "challenging foe" base3 min level #define SE_SpellOnDeath 361 // implemented - casts spell on death of buffed -//#define SE_PotionBeltSlots 362 // *not implemented[AA] 'Quick Draw' expands the potion belt by one additional available item slot per rank. -//#define SE_BandolierSlots 363 // *not implemented[AA] 'Battle Ready' expands the bandolier by one additional save slot per rank. +#define SE_PotionBeltSlots 362 // *not implemented[AA] 'Quick Draw' expands the potion belt by one additional available item slot per rank. +#define SE_BandolierSlots 363 // *not implemented[AA] 'Battle Ready' expands the bandolier by one additional save slot per rank. #define SE_TripleAttackChance 364 // implemented #define SE_ProcOnSpellKillShot 365 // implemented - chance to trigger a spell on kill when the kill is caused by a specific spell with this effect in it (10470 Venin) #define SE_ShieldEquipDmgMod 366 // implemented[AA] Damage modifier to melee if shield equiped. (base1 = dmg mod , base2 = ?) ie Shield Specialist AA @@ -524,11 +525,11 @@ typedef enum { #define SE_CorruptionCounter 369 // implemented #define SE_ResistCorruption 370 // implemented #define SE_AttackSpeed4 371 // implemented - stackable slow effect 'Inhibit Melee' -//#define SE_ForageSkill 372 // *not implemented[AA] Will increase the skill cap for those that have the Forage skill and grant the skill and raise the cap to those that do not. +#define SE_ForageSkill 372 // *not implemented[AA] Will increase the skill cap for those that have the Forage skill and grant the skill and raise the cap to those that do not. #define SE_CastOnFadeEffectAlways 373 // implemented - Triggers if fades after natural duration OR from rune/numhits fades. #define SE_ApplyEffect 374 // implemented #define SE_DotCritDmgIncrease 375 // implemented - Increase damage of DoT critical amount -//#define SE_Fling 376 // *not implemented - used in 2 test spells (12945 | Movement Test Spell 1) +//#define SE_Fling 376 // *not implemented - used in 2 test spells (12945 | Movement Test Spell 1) #define SE_CastOnFadeEffectNPC 377 // implemented - Triggers only if fades after natural duration (On live these are usually players spells that effect an NPC). #define SE_SpellEffectResistChance 378 // implemented - Increase chance to resist specific spell effect (base1=value, base2=spell effect id) #define SE_ShadowStepDirectional 379 // implemented - handled by client @@ -543,7 +544,7 @@ typedef enum { //#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA) #define SE_FcTimerRefresh 389 // implemented - Refresh spell icons //#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited. -#define SE_MeleeVulnerability 391 // implemented [Live SPA has this as LimitManaMax however that is clearly not the effect used] +#define SE_LimitManaMax 391 // implemented #define SE_FcHealAmt 392 // implemented - Adds or removes healing from spells #define SE_FcHealPctIncoming 393 // implemented - HealRate with focus restrictions. #define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions. @@ -559,7 +560,7 @@ typedef enum { #define SE_LimitSpellSubclass 404 // *not implemented - Limits to specific types of spells (see CheckSpellCategory) [Categories NOT defined yet] #define SE_TwoHandBluntBlock 405 // implemented - chance to block attacks when using two hand blunt weapons (similiar to shield block) #define SE_CastonNumHitFade 406 // implemented - casts a spell when a buff fades due to its numhits being depleted -#define SE_CastonFocusEffect 407 // implemented - casts a spell if focus limits are met (ie triggers when a focus effects is applied) +#define SE_CastonFocusEffect 407 // implemented - casts a spell if focus limits are met (ie triggers when a focus effects is applied) #define SE_LimitHPPercent 408 // implemented - limited to a certain percent of your hp(ie heals up to 50%) #define SE_LimitManaPercent 409 // implemented - limited to a certain percent of your mana #define SE_LimitEndPercent 410 // implemented - limited to a certain percent of your end @@ -575,10 +576,10 @@ typedef enum { #define SE_FcLimitUse 420 // implemented - increases numhits count by percent (Note: not used in any known live spells) #define SE_FcIncreaseNumHits 421 // implemented[AA] - increases number of hits a buff has till fade. (focus) #define SE_LimitUseMin 422 // implemented - limit a focus to require a min amount of numhits value (used with above) -#define SE_LimitUseType 423 // implemented - limit a focus to require a certain numhits type +#define SE_LimitUseType 423 // implemented - limit a focus to require a certain numhits type #define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace //#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626) -//#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window +#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window #define SE_SkillProc 427 // implemented - chance to proc when using a skill(ie taunt) #define SE_LimitToSkill 428 // implemented - limits what skills will effect a skill proc #define SE_SkillProcSuccess 429 // implemented - chance to proc when tje skill in use successfully fires. @@ -599,9 +600,9 @@ typedef enum { #define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y //#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. #define SE_AStacker 446 // implementet - bufff stacking blocker (26219 | Qirik's Watch) -#define SE_BStacker 447 // implemented +#define SE_BStacker 447 // implemented #define SE_CStacker 448 // implemented -#define SE_DStacker 449 // implemented +#define SE_DStacker 449 // implemented #define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value #define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage #define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage @@ -612,11 +613,25 @@ typedef enum { #define SE_ResourceTap 457 // implemented Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. #define SE_FactionModPct 458 // implemented Modifies faction gains and losses by percent. #define SE_DamageModifier2 459 // implemented - Modifies melee damage by skill type +//#define SE_Ff_Override_NotFocusable 460 // +#define SE_ImprovedDamage2 461 // implemented - Increase spell damage by percent (SE_Fc_Damage_%2) +#define SE_FcDamageAmt2 462 // implemented - Increase spell damage by flat amount (SE_Fc_Damage_Amt2) +//#define SE_Shield_Target 463 // +#define SE_PC_Pet_Rampage 464 // implemented - Base1 % chance to do rampage for base2 % of damage each melee round +//#define SE_PC_Pet_AE_Rampage 465 // Would assume as above but need to confirm. +#define SE_PC_Pet_Flurry_Chance 466 // implemented - Base1 % chance to do flurry from double attack hit. +//#define SE_DS_Mitigation_Amount 467 // +//#define SE_DS_Mitigation_Percentage 468 // +//#define SE_Chance_Best_in_Spell_Grp 469 // +//#define SE_Trigger_Best_in_Spell Grp 470 // +//#define SE_Double_Melee_Round 471 // + // LAST #define DF_Permanent 50 +#define DF_Aura 51 // note this struct is historical, we don't actually need it to be // aligned to anything, but for maintaining it it is kept in the order that @@ -624,140 +639,163 @@ typedef enum { // number. note that the id field is counted as 0, this way the numbers // here match the numbers given to sep in the loading function net.cpp // -#define SPELL_LOAD_FIELD_COUNT 231 +#define SPELL_LOAD_FIELD_COUNT 236 struct SPDat_Spell_Struct { -/* 000 */ int id; // not used -/* 001 */ char name[64]; // Name of the spell -/* 002 */ char player_1[32]; // "PLAYER_1" -/* 003 */ char teleport_zone[64]; // Teleport zone, pet name summoned, or item summoned -/* 004 */ char you_cast[64]; // Message when you cast -/* 005 */ char other_casts[64]; // Message when other casts -/* 006 */ char cast_on_you[64]; // Message when spell is cast on you -/* 007 */ char cast_on_other[64]; // Message when spell is cast on someone else -/* 008 */ char spell_fades[64]; // Spell fades -/* 009 */ float range; -/* 010 */ float aoerange; -/* 011 */ float pushback; -/* 012 */ float pushup; -/* 013 */ uint32 cast_time; // Cast time -/* 014 */ uint32 recovery_time; // Recovery time -/* 015 */ uint32 recast_time; // Recast same spell time -/* 016 */ uint32 buffdurationformula; -/* 017 */ uint32 buffduration; -/* 018 */ uint32 AEDuration; // sentinel, rain of something -/* 019 */ uint16 mana; // Mana Used -/* 020 */ int base[EFFECT_COUNT]; //various purposes -/* 032 */ int base2[EFFECT_COUNT]; //various purposes -/* 044 */ int32 max[EFFECT_COUNT]; -/* 056 */ //uint16 icon; // Spell icon -/* 057 */ //uint16 memicon; // Icon on membarthing -/* 058 */ int32 components[4]; // reagents -/* 062 */ int component_counts[4]; // amount of regents used +/* 000 */ int id; // not used -- SPELLINDEX +/* 001 */ char name[64]; // Name of the spell -- SPELLNAME +/* 002 */ char player_1[32]; // "PLAYER_1" -- ACTORTAG +/* 003 */ char teleport_zone[64]; // Teleport zone, pet name summoned, or item summoned -- NPC_FILENAME +/* 004 */ char you_cast[64]; // Message when you cast -- CASTERMETXT +/* 005 */ char other_casts[64]; // Message when other casts -- CASTEROTHERTXT +/* 006 */ char cast_on_you[64]; // Message when spell is cast on you -- CASTEDMETXT +/* 007 */ char cast_on_other[64]; // Message when spell is cast on someone else -- CASTEDOTHERTXT +/* 008 */ char spell_fades[64]; // Spell fades -- SPELLGONE +/* 009 */ float range; // -- RANGE +/* 010 */ float aoerange; // -- IMPACTRANGE +/* 011 */ float pushback; // -- OUTFORCE +/* 012 */ float pushup; // -- UPFORCE +/* 013 */ uint32 cast_time; // Cast time -- CASTINGTIME +/* 014 */ uint32 recovery_time; // Recovery time -- RECOVERYDELAY +/* 015 */ uint32 recast_time; // Recast same spell time -- SPELLDELAY +/* 016 */ uint32 buffdurationformula; // -- DURATIONBASE +/* 017 */ uint32 buffduration; // -- DURATIONCAP +/* 018 */ uint32 AEDuration; // sentinel, rain of something -- IMPACTDURATION +/* 019 */ uint16 mana; // Mana Used -- MANACOST +/* 020 */ int base[EFFECT_COUNT]; //various purposes -- BASEAFFECT1 .. BASEAFFECT12 +/* 032 */ int base2[EFFECT_COUNT]; //various purposes -- BASE_EFFECT2_1 ... BASE_EFFECT2_12 +/* 044 */ int32 max[EFFECT_COUNT]; // -- AFFECT1CAP ... AFFECT12CAP +/* 056 */ //uint16 icon; // Spell icon -- IMAGENUMBER +/* 057 */ //uint16 memicon; // Icon on membarthing -- MEMIMAGENUMBER +/* 058 */ int32 components[4]; // reagents -- EXPENDREAGENT1 ... EXPENDREAGENT4 +/* 062 */ int component_counts[4]; // amount of regents used -- EXPENDQTY1 ... EXPENDQTY4 /* 066 */ int NoexpendReagent[4]; // focus items (Need but not used; Flame Lick has a Fire Beetle Eye focus.) // If it is a number between 1-4 it means components[number] is a focus and not to expend it // If it is a valid itemid it means this item is a focus as well -/* 070 */ uint16 formula[EFFECT_COUNT]; // Spell's value formula -/* 082 */ //int LightType; // probaly another effecttype flag -/* 083 */ int8 goodEffect; //0=detrimental, 1=Beneficial, 2=Beneficial, Group Only -/* 084 */ int Activated; // probably another effecttype flag -/* 085 */ int resisttype; -/* 086 */ int effectid[EFFECT_COUNT]; // Spell's effects -/* 098 */ SpellTargetType targettype; // Spell's Target -/* 099 */ int basediff; // base difficulty fizzle adjustment -/* 100 */ SkillUseTypes skill; -/* 101 */ int8 zonetype; // 01=Outdoors, 02=dungeons, ff=Any -/* 102 */ int8 EnvironmentType; -/* 103 */ int8 TimeOfDay; -/* 104 */ uint8 classes[PLAYER_CLASS_COUNT]; // Classes, and their min levels -/* 120 */ uint8 CastingAnim; -/* 121 */ //uint8 TargetAnim; -/* 122 */ //uint32 TravelType; -/* 123 */ uint16 SpellAffectIndex; -/* 124 */ int8 disallow_sit; // 124: high-end Yaulp spells (V, VI, VII, VIII [Rk 1, 2, & 3], & Gallenite's Bark of Fury -/* 125 */ int8 diety_agnostic;// 125: Words of the Skeptic + // -- NOEXPENDREAGENT1 ... NOEXPENDREAGENT4 +/* 070 */ uint16 formula[EFFECT_COUNT]; // Spell's value formula -- LEVELAFFECT1MOD ... LEVELAFFECT12MOD +/* 082 */ //int LightType; // probaly another effecttype flag -- LIGHTTYPE +/* 083 */ int8 goodEffect; //0=detrimental, 1=Beneficial, 2=Beneficial, Group Only -- BENEFICIAL +/* 084 */ int Activated; // probably another effecttype flag -- ACTIVATED +/* 085 */ int resisttype; // -- RESISTTYPE +/* 086 */ int effectid[EFFECT_COUNT]; // Spell's effects -- SPELLAFFECT1 ... SPELLAFFECT12 +/* 098 */ SpellTargetType targettype; // Spell's Target -- TYPENUMBER +/* 099 */ int basediff; // base difficulty fizzle adjustment -- BASEDIFFICULTY +/* 100 */ EQEmu::skills::SkillType skill; // -- CASTINGSKILL +/* 101 */ int8 zonetype; // 01=Outdoors, 02=dungeons, ff=Any -- ZONETYPE +/* 102 */ int8 EnvironmentType; // -- ENVIRONMENTTYPE +/* 103 */ int8 TimeOfDay; // -- TIMEOFDAY +/* 104 */ uint8 classes[PLAYER_CLASS_COUNT]; // Classes, and their min levels -- WARRIORMIN ... BERSERKERMIN +/* 120 */ uint8 CastingAnim; // -- CASTINGANIM +/* 121 */ //uint8 TargetAnim; // -- TARGETANIM +/* 122 */ //uint32 TravelType; // -- TRAVELTYPE +/* 123 */ uint16 SpellAffectIndex; // -- SPELLAFFECTINDEX +/* 124 */ int8 disallow_sit; // 124: high-end Yaulp spells (V, VI, VII, VIII [Rk 1, 2, & 3], & Gallenite's Bark of Fury -- CANCELONSIT +/* 125 */ int8 diety_agnostic;// 125: Words of the Skeptic -- DIETY_AGNOSTIC /* 126 */ int8 deities[16]; // Deity check. 201 - 216 per http://www.eqemulator.net/wiki/wikka.php?wakka=DeityList // -1: Restrict to Deity; 1: Restrict to Deity, but only used on non-Live (Test Server "Blessing of ...") spells; 0: Don't restrict -/* 142 */ // 142: between 0 & 100 - // 143: always set to 0 -/* 144 */ //int16 new_icon // Spell icon used by the client in uifiles/default/spells??.tga, both for spell gems & buff window. Looks to depreciate icon & memicon -/* 145 */ //int16 spellanim; // Doesn't look like it's the same as #doanim, so not sure what this is -/* 146 */ int8 uninterruptable; // Looks like anything != 0 is uninterruptable. Values are mostly -1, 0, & 1 (Fetid Breath = 90?) -/* 147 */ int16 ResistDiff; -/* 148 */ int8 dot_stacking_exempt; // If 1 doesn't stack with self cast by others. If -1 (not implemented) doesn't stack with same effect (???) -/* 149 */ //int deletable; -/* 150 */ uint16 RecourseLink; -/* 151 */ bool no_partial_resist; // 151: -1, 0, or 1 - // 152 & 153: all set to 0 -/* 154 */ int8 short_buff_box; // != 0, goes to short buff box. -/* 155 */ int descnum; // eqstr of description of spell -/* 156 */ //int typedescnum; // eqstr of type description -/* 157 */ int effectdescnum; // eqstr of effect description -/* 158 */ //Category Desc ID 3 -/* 159 */ bool npc_no_los; -/* 161 */ bool reflectable; -/* 162 */ int bonushate; -/* 163 */ -/* 164 */ // for most spells this appears to mimic ResistDiff -/* 165 */ bool ldon_trap; //Flag found on all LDON trap / chest related spells. -/* 166 */ int EndurCost; -/* 167 */ int8 EndurTimerIndex; -/* 168 */ bool IsDisciplineBuff; //Will goto the combat window when cast -/* 169 - 172*/ //These are zero for ALL spells -/* 173 */ int HateAdded; -/* 174 */ int EndurUpkeep; -/* 175 */ int numhitstype; // defines which type of behavior will tick down the numhit counter. -/* 176 */ int numhits; -/* 177 */ int pvpresistbase; -/* 178 */ int pvpresistcalc; -/* 179 */ int pvpresistcap; -/* 180 */ int spell_category; -/* 181 */ //unknown - likely buff duration related -/* 182 */ //unknown - likely buff duration related -/* 183 */ -/* 184 */ -/* 185 */ int8 can_mgb; // 0=no, -1 or 1 = yes -/* 186 */ int dispel_flag; -/* 187 */ //int npc_category; -/* 188 */ //int npc_usefulness; -/* 189 */ int MinResist; -/* 190 */ int MaxResist; -/* 191 */ uint8 viral_targets; -/* 192 */ uint8 viral_timer; -/* 193 */ int NimbusEffect; -/* 194 */ float directional_start; //Cone Start Angle: -/* 195 */ float directional_end; // Cone End Angle: -/* 196 */ bool sneak; // effect can only be used if sneaking (rogue 'Daggerfall' ect) -/* 197 */ bool not_extendable; -/* 198- 199 */ -/* 200 */ bool suspendable; // buff is suspended in suspended buff zones -/* 201 */ int viral_range; -/* 202 */ -/* 203 */ //int songcap; // individual song cap (how live currently does it, not implemented) -/* 204 */ -/* 205 */ bool no_block; -/* 206 */ -/* 207 */ int spellgroup; -/* 208 */ int rank; //increments AA effects with same name -/* 209 */ int powerful_flag; // Need more investigation to figure out what to call this, for now we know -1 makes charm spells not break before their duration is complete, it does alot more though -/* 210 */ // bool DurationFrozen; ??? -/* 211 */ int CastRestriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat -/* 212 */ bool AllowRest; -/* 213 */ bool InCombat; //Allow spell if target is in combat -/* 214 */ bool OutofCombat; //Allow spell if target is out of combat -/* 215 - 217 */ -/* 218 */ int aemaxtargets; //Is used for various AE effects -/* 219 */ int maxtargets; //Is used for beam and ring spells for target # limits (not implemented) -/* 220 - 223 */ -/* 224 */ bool persistdeath; // buff doesn't get stripped on death -/* 225 - 226 */ -/* 227 */ float min_dist; //spell power modified by distance from caster (Min Distance) -/* 228 */ float min_dist_mod; //spell power modified by distance from caster (Modifier at Min Distance) -/* 229 */ float max_dist; //spell power modified by distance from caster (Max Distance) -/* 230 */ float max_dist_mod; //spell power modified by distance from caster (Modifier at Max Distance) -/* 231 */ float min_range; //Min casting range -/* 232 - 236 */ + // the client actually stores deities in a single int32_t + // -- DIETY_BERTOXXULOUS ... DIETY_VEESHAN +/* 142 */ //int8 npc_no_cast; // 142: between 0 & 100 -- NPC_NO_CAST +/* 143 */ //int ai_pt_bonus; // 143: always set to 0, client doesn't save this -- AI_PT_BONUS +/* 144 */ //int16 new_icon // Spell icon used by the client in uifiles/default/spells??.tga, both for spell gems & buff window. Looks to depreciate icon & memicon -- NEW_ICON +/* 145 */ //int16 spellanim; // Doesn't look like it's the same as #doanim, so not sure what this is, particles I think -- SPELL_EFFECT_INDEX +/* 146 */ bool uninterruptable; // Looks like anything != 0 is uninterruptable. Values are mostly -1, 0, & 1 (Fetid Breath = 90?) -- NO_INTERRUPT +/* 147 */ int16 ResistDiff; // -- RESIST_MOD +/* 148 */ bool dot_stacking_exempt; // -- NOT_STACKABLE_DOT +/* 149 */ //int deletable; // -- DELETE_OK +/* 150 */ uint16 RecourseLink; // -- REFLECT_SPELLINDEX +/* 151 */ bool no_partial_resist; // 151: -1, 0, or 1 -- NO_PARTIAL_SAVE +/* 152 */ //bool small_targets_only; // -- SMALL_TARGETS_ONLY +/* 153 */ //bool uses_persistent_particles; // -- USES_PERSISTENT_PARTICLES +/* 154 */ int8 short_buff_box; // != 0, goes to short buff box. -- BARD_BUFF_BOX +/* 155 */ int descnum; // eqstr of description of spell -- DESCRIPTION_INDEX +/* 156 */ int typedescnum; // eqstr of type description -- PRIMARY_CATEGORY +/* 157 */ int effectdescnum; // eqstr of effect description -- SECONDARY_CATEGORY_1 +/* 158 */ //int secondary_category_2; //Category Desc ID 3 -- SECONDARY_CATEGORY_2 +/* 159 */ bool npc_no_los; // -- NO_NPC_LOS +/* 160 */ //bool feedbackable; // -- FEEDBACKABLE +/* 161 */ bool reflectable; // -- REFLECTABLE +/* 162 */ int bonushate; // -- HATE_MOD +/* 163 */ //int resist_per_level; // -- RESIST_PER_LEVEL +/* 164 */ //int resist_cap; // for most spells this appears to mimic ResistDiff -- RESIST_CAP +/* 165 */ bool ldon_trap; //Flag found on all LDON trap / chest related spells. -- AFFECT_INANIMATE +/* 166 */ int EndurCost; // -- STAMINA_COST +/* 167 */ int8 EndurTimerIndex; // bad name, used for all spells -- TIMER_INDEX +/* 168 */ bool IsDisciplineBuff; //Will goto the combat window when cast -- IS_SKILL +/* 169 - 172*/ //These are zero for ALL spells, also removed from live -- ATTACK_OPENING, DEFENSE_OPENING, SKILL_OPENING, NPC_ERROR_OPENING +/* 173 */ int HateAdded; // -- SPELL_HATE_GIVEN +/* 174 */ int EndurUpkeep; // -- ENDUR_UPKEEP +/* 175 */ int numhitstype; // defines which type of behavior will tick down the numhit counter. -- LIMITED_USE_TYPE +/* 176 */ int numhits; // -- LIMITED_USE_COUNT +/* 177 */ int pvpresistbase; // -- PVP_RESIST_MOD +/* 178 */ int pvpresistcalc; // -- PVP_RESIST_PER_LEVEL +/* 179 */ int pvpresistcap; // -- PVP_RESIST_CAP +/* 180 */ int spell_category; // -- GLOBAL_GROUP +/* 181 */ //int pvp_duration; // buffdurationformula for PvP -- PVP_DURATION +/* 182 */ //int pvp_duration_cap; // buffduration for PvP -- PVP_DURATION_CAP +/* 183 */ //int pcnpc_only_flag; // valid values are 0, 1 = PCs (and mercs), and 2 = NPCs (and not mercs) -- PCNPC_ONLY_FLAG +/* 184 */ bool cast_not_standing; // this is checked in the client's EQ_Spell::IsCastWhileInvisSpell, this also blocks SE_InterruptCasting from affecting this spell -- CAST_NOT_STANDING +/* 185 */ bool can_mgb; // 0=no, -1 or 1 = yes -- CAN_MGB +/* 186 */ int dispel_flag; // -- NO_DISPELL +/* 187 */ //int npc_category; // -- NPC_MEM_CATEGORY +/* 188 */ //int npc_usefulness; // -- NPC_USEFULNESS +/* 189 */ int MinResist; // -- MIN_RESIST +/* 190 */ int MaxResist; // -- MAX_RESIST +/* 191 */ uint8 viral_targets; // -- MIN_SPREAD_TIME +/* 192 */ uint8 viral_timer; // -- MAX_SPREAD_TIME +/* 193 */ int NimbusEffect; // -- DURATION_PARTICLE_EFFECT +/* 194 */ float directional_start; //Cone Start Angle: -- CONE_START_ANGLE +/* 195 */ float directional_end; // Cone End Angle: -- CONE_END_ANGLE +/* 196 */ bool sneak; // effect can only be used if sneaking (rogue 'Daggerfall' ect) -- SNEAK_ATTACK +/* 197 */ bool not_focusable; //prevents focus effects from being applied to spell -- NOT_FOCUSABLE +/* 198 */ bool no_detrimental_spell_aggro; // -- NO_DETRIMENTAL_SPELL_AGGRO +/* 199 */ //bool show_wear_off_message; // -- SHOW_WEAR_OFF_MESSAGE +/* 200 */ bool suspendable; // buff is suspended in suspended buff zones -- IS_COUNTDOWN_HELD +/* 201 */ int viral_range; // -- SPREAD_RADIUS +/* 202 */ int songcap; // individual song cap -- BASE_EFFECTS_FOCUS_CAP +/* 203 */ //bool stacks_with_self; // -- STACKS_WITH_SELF +/* 204 */ //int not_shown_to_player; // client skips this -- NOT_SHOWN_TO_PLAYER +/* 205 */ bool no_block; // -- NO_BUFF_BLOCK +/* 206 */ //int8 anim_variation; // -- ANIM_VARIATION +/* 207 */ int spellgroup; // -- SPELL_GROUP +/* 208 */ int rank; //increments AA effects with same name -- SPELL_GROUP_RANK +/* 209 */ int no_resist; //makes spells unresistable, which makes charms unbreakable as well. -- NO_RESIST +/* 210 */ // bool allow_spellscribe; // -- ALLOW_SPELLSCRIBE +/* 211 */ int CastRestriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat -- SPELL_REQ_ASSOCIATION_ID +/* 212 */ bool AllowRest; // -- BYPASS_REGEN_CHECK +/* 213 */ bool InCombat; //Allow spell if target is in combat -- CAN_CAST_IN_COMBAT +/* 214 */ bool OutofCombat; //Allow spell if target is out of combat -- CAN_CAST_OUT_OF_COMBAT +/* 215 */ //bool show_dot_message; // -- SHOW_DOT_MESSAGE +/* 216 */ //bool invalid; // -- INVALID +/* 217 */ int override_crit_chance; //Places a cap on the max chance to critical -- OVERRIDE_CRIT_CHANCE +/* 218 */ int aemaxtargets; //Is used for various AE effects -- MAX_TARGETS +/* 219 */ int no_heal_damage_item_mod; // -- NO_HEAL_DAMAGE_ITEM_MOD +/* 220 */ //int caster_requirement_id; // -- CASTER_REQUIREMENT_ID +/* 221 */ //int spell_class; // -- SPELL_CLASS +/* 222 */ //int spell_subclass; // -- SPELL_SUBCLASS +/* 223 */ //int ai_valid_targets; // -- AI_VALID_TARGETS +/* 224 */ bool persistdeath; // buff doesn't get stripped on death -- NO_STRIP_ON_DEATH +/* 225 */ //float base_effects_focus_slope; // -- BASE_EFFECTS_FOCUS_SLOPE +/* 226 */ //float base_effects_focus_offset; // -- BASE_EFFECTS_FOCUS_OFFSET +/* 227 */ float min_dist; //spell power modified by distance from caster (Min Distance) -- DISTANCE_MOD_CLOSE_DIST +/* 228 */ float min_dist_mod; //spell power modified by distance from caster (Modifier at Min Distance) -- DISTANCE_MOD_CLOSE_MULT +/* 229 */ float max_dist; //spell power modified by distance from caster (Max Distance) -- DISTANCE_MOD_FAR_DIST +/* 230 */ float max_dist_mod; //spell power modified by distance from caster (Modifier at Max Distance) -- DISTANCE_MOD_FAR_MULT +/* The client also does this + * v26 = *(float *)&v4->DistanceModFarDist - *(float *)&v4->DistanceModCloseDist; + * if ( v26 > -0.00000011920929 && v26 < 0.00000011920929 ) + * v26 = 1.0; + * v27 = (st7_0 - *(float *)&v4->DistanceModCloseMult) / v26; + * *(float *)&v4->DistanceMod = v27; + */ +/* 231 */ float min_range; //Min casting range -- MIN_RANGE +/* 232 */ bool no_remove; //prevents buff from being removed by click -- NO_REMOVE +/* 233 */ //int spell_recourse_type; // -- SPELL_RECOURSE_TYPE +/* 234 */ //bool only_during_fast_regen; // -- ONLY_DURING_FAST_REGEN +/* 235 */ //bool is_beta_only; // -- IS_BETA_ONLY +/* 236 */ //int spell_subgroup; // -- SPELL_SUBGROUP uint8 DamageShieldType; // This field does not exist in spells_us.txt }; @@ -863,6 +901,10 @@ uint32 GetPartialMeleeRuneReduction(uint32 spell_id); uint32 GetPartialMagicRuneReduction(uint32 spell_id); uint32 GetPartialMeleeRuneAmount(uint32 spell_id); uint32 GetPartialMagicRuneAmount(uint32 spell_id); +bool NoDetrimentalSpellAggro(uint16 spell_id); +bool IsStackableDot(uint16 spell_id); +bool IsCastWhileInvis(uint16 spell_id); +bool IsEffectIgnoredInStacking(int spa); int CalcPetHp(int levelb, int classb, int STA = 75); const char *GetRandPetName(); diff --git a/common/string_util.cpp b/common/string_util.cpp index e791eb7f6..902d13335 100644 --- a/common/string_util.cpp +++ b/common/string_util.cpp @@ -288,7 +288,7 @@ void RemoveApostrophes(std::string &s) char *RemoveApostrophes(const char *s) { - char *NewString = new char[strlen(s) + 1]; + auto NewString = new char[strlen(s) + 1]; strcpy(NewString, s); diff --git a/common/struct_strategy.h b/common/struct_strategy.h index f81881c26..fdb596891 100644 --- a/common/struct_strategy.h +++ b/common/struct_strategy.h @@ -4,7 +4,7 @@ class EQApplicationPacket; class EQStream; #include "emu_opcodes.h" -#include "clientversions.h" +#include "emu_versions.h" #include #include @@ -25,7 +25,7 @@ public: void Decode(EQApplicationPacket *p) const; virtual std::string Describe() const = 0; - virtual const ClientVersion GetClientVersion() const = 0; + virtual const EQEmu::versions::ClientVersion ClientVersion() const = 0; protected: //some common coders: diff --git a/common/tcp_connection.cpp b/common/tcp_connection.cpp index aa687cc01..d13cf89cc 100644 --- a/common/tcp_connection.cpp +++ b/common/tcp_connection.cpp @@ -187,7 +187,7 @@ void TCPConnection::ServerSendQueuePushEnd(const uchar* data, int32 size) { } else if (size > (sendbuf_size - sendbuf_used)) { sendbuf_size += size + 1024; - uchar* tmp = new uchar[sendbuf_size]; + auto tmp = new uchar[sendbuf_size]; memcpy(tmp, sendbuf, sendbuf_used); safe_delete_array(sendbuf); sendbuf = tmp; @@ -209,7 +209,7 @@ void TCPConnection::ServerSendQueuePushEnd(uchar** data, int32 size) { } if (size > (sendbuf_size - sendbuf_used)) { sendbuf_size += size; - uchar* tmp = new uchar[sendbuf_size]; + auto tmp = new uchar[sendbuf_size]; memcpy(tmp, sendbuf, sendbuf_used); safe_delete_array(sendbuf); sendbuf = tmp; @@ -229,7 +229,7 @@ void TCPConnection::ServerSendQueuePushFront(uchar* data, int32 size) { } else if (size > (sendbuf_size - sendbuf_used)) { sendbuf_size += size; - uchar* tmp = new uchar[sendbuf_size]; + auto tmp = new uchar[sendbuf_size]; memcpy(&tmp[size], sendbuf, sendbuf_used); safe_delete_array(sendbuf); sendbuf = tmp; @@ -608,7 +608,7 @@ bool TCPConnection::RecvData(char* errbuf) { recvbuf_echo = 0; } else if ((recvbuf_size - recvbuf_used) < 2048) { - uchar* tmpbuf = new uchar[recvbuf_size + 5120]; + auto tmpbuf = new uchar[recvbuf_size + 5120]; memcpy(tmpbuf, recvbuf, recvbuf_used); recvbuf_size += 5120; safe_delete_array(recvbuf); diff --git a/common/tcp_connection.h b/common/tcp_connection.h index ae02b9c56..c3fa5cd51 100644 --- a/common/tcp_connection.h +++ b/common/tcp_connection.h @@ -23,7 +23,9 @@ */ #ifdef _WINDOWS - #define snprintf _snprintf + #if (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER < 1900)) + #define snprintf _snprintf + #endif #define strncasecmp _strnicmp #define strcasecmp _stricmp diff --git a/common/textures.cpp b/common/textures.cpp new file mode 100644 index 000000000..7993ec384 --- /dev/null +++ b/common/textures.cpp @@ -0,0 +1,99 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "textures.h" +//#include "inventory_slot.h" + +#include // temp + + +//int EQEmu::textures::ConvertEquipmentSlotToTextureSlot(int equipment_slot) +//{ +// switch (equipment_slot) { +// case inventory::PossessionsHead: +// return textures::TextureHead; +// case inventory::PossessionsChest: +// return textures::TextureChest; +// case inventory::PossessionsArms: +// return textures::TextureArms; +// case inventory::PossessionsWrist1: +// return textures::TextureWrist; +// case inventory::PossessionsHands: +// return textures::TextureHands; +// case inventory::PossessionsLegs: +// return textures::TextureLegs; +// case inventory::PossessionsFeet: +// return textures::TextureFeet; +// case inventory::PossessionsPrimary: +// return textures::TexturePrimary; +// case inventory::PossessionsSecondary: +// return textures::TextureSecondary; +// default: +// return textures::TextureInvalid; +// } +//} + +//int EQEmu::textures::ConvertEquipmentSlotToTextureSlot(const InventorySlot &equipment_slot) +//{ +// if (equipment_slot.Type() != inventory::InvTypePossessions || equipment_slot.Bag() != inventory::InvBagInvalid || equipment_slot.Aug() != inventory::InvAugInvalid) +// return textures::TextureInvalid; +// +// return ConvertEquipmentSlotToTextureSlot(equipment_slot.Slot()); +//} + +//EQEmu::InventorySlot EQEmu::textures::ConvertTextureSlotToEquipmentSlot(int texture_slot) +//{ +// switch (texture_slot) { +// case textures::TextureHead: +// return EQEmu::InventorySlot(inventory::InvTypePossessions, inventory::PossessionsHead); +// case textures::TextureChest: +// return EQEmu::InventorySlot(inventory::InvTypePossessions, inventory::PossessionsChest); +// case textures::TextureArms: +// return EQEmu::InventorySlot(inventory::InvTypePossessions, inventory::PossessionsArms); +// case textures::TextureWrist: +// return EQEmu::InventorySlot(inventory::InvTypePossessions, inventory::PossessionsWrist1); +// case textures::TextureHands: +// return EQEmu::InventorySlot(inventory::InvTypePossessions, inventory::PossessionsHands); +// case textures::TextureLegs: +// return EQEmu::InventorySlot(inventory::InvTypePossessions, inventory::PossessionsLegs); +// case textures::TextureFeet: +// return EQEmu::InventorySlot(inventory::InvTypePossessions, inventory::PossessionsFeet); +// case textures::TexturePrimary: +// return EQEmu::InventorySlot(inventory::InvTypePossessions, inventory::PossessionsPrimary); +// case textures::TextureSecondary: +// return EQEmu::InventorySlot(inventory::InvTypePossessions, inventory::PossessionsSecondary); +// default: +// return EQEmu::InventorySlot(); +// } +//} + +EQEmu::TextureProfile::TextureProfile() +{ + memset(&Slot, 0, (sizeof(Texture_Struct) * textures::TextureCount)); +} + +EQEmu::TextureShortProfile::TextureShortProfile() +{ + memset(&Slot, 0, (sizeof(uint32) * textures::TextureCount)); +} + +EQEmu::TintProfile::TintProfile() +{ + memset(&Slot, 0, (sizeof(uint32) * textures::TextureCount)); +} diff --git a/common/textures.h b/common/textures.h new file mode 100644 index 000000000..a6333a03f --- /dev/null +++ b/common/textures.h @@ -0,0 +1,142 @@ +/* EQEMu: Everquest Server Emulator + + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMON_TEXTURES_H +#define COMMON_TEXTURES_H + +#include "types.h" + + +namespace EQEmu +{ + //class InventorySlot; + + namespace textures { + //enum : int { TextureInvalid = -1, TextureBegin }; + enum : uint8 { TextureInvalid = 255, TextureBegin = 0 }; + + //enum TextureSlot : int { + enum TextureSlot : uint8 { + TextureHead = TextureBegin, + TextureChest, + TextureArms, + TextureWrist, + TextureHands, + TextureLegs, + TextureFeet, + TexturePrimary, + TextureSecondary, + TextureCount + }; + + const int LastTexture = TextureSecondary; + const int LastTintableTexture = TextureFeet; + + //extern int ConvertEquipmentSlotToTextureSlot(int equipment_slot); + //extern int ConvertEquipmentSlotToTextureSlot(const InventorySlot &equipment_slot); + //extern InventorySlot ConvertTextureSlotToEquipmentSlot(int texture_slot); + + } /*textures*/ + + struct Texture_Struct { + uint32 Material; + uint32 Unknown1; + uint32 EliteMaterial; + uint32 HeroForgeModel; + uint32 Material2; // Same as material? + }; + + struct TextureProfile { + union { + struct { + Texture_Struct Head; + Texture_Struct Chest; + Texture_Struct Arms; + Texture_Struct Wrist; + Texture_Struct Hands; + Texture_Struct Legs; + Texture_Struct Feet; + Texture_Struct Primary; + Texture_Struct Secondary; + }; + Texture_Struct Slot[textures::TextureCount]; + }; + + TextureProfile(); + }; + + struct TextureShort_Struct { + uint32 Material; + }; + + struct TextureShortProfile { + union { + struct { + TextureShort_Struct Head; + TextureShort_Struct Chest; + TextureShort_Struct Arms; + TextureShort_Struct Wrist; + TextureShort_Struct Hands; + TextureShort_Struct Legs; + TextureShort_Struct Feet; + TextureShort_Struct Primary; + TextureShort_Struct Secondary; + }; + TextureShort_Struct Slot[textures::TextureCount]; + }; + + TextureShortProfile(); + }; + + struct Tint_Struct { + union { + struct { + uint8 Blue; + uint8 Green; + uint8 Red; + uint8 UseTint; // if there's a tint this is FF + }; + uint32 Color; + }; + + //Tint_Struct(); + }; + + struct TintProfile { + union { + struct { + Tint_Struct Head; + Tint_Struct Chest; + Tint_Struct Arms; + Tint_Struct Wrist; + Tint_Struct Hands; + Tint_Struct Legs; + Tint_Struct Feet; + Tint_Struct Primary; + Tint_Struct Secondary; + }; + Tint_Struct Slot[textures::TextureCount]; + }; + + TintProfile(); + }; + +} /*EQEmu*/ + +#endif /*COMMON_TEXTURES_H*/ diff --git a/common/timer.h b/common/timer.h index 4b2719dc6..f06f5bbe4 100644 --- a/common/timer.h +++ b/common/timer.h @@ -19,6 +19,7 @@ #define TIMER_H #include "types.h" +#include // Disgrace: for windows compile #ifdef _WINDOWS @@ -65,4 +66,28 @@ private: bool pUseAcurateTiming; }; +/* Wrapper around chrono to make adding simple time based benching easy + * ex: + * void foo() { + * ... + * BenchTimer timer; + * ... (expensive work here) + * auto dur = timer.elapsed(); + * std::cout << "foo() took " << dur << seconds" << std::endl; + * ... + * } + * */ + +struct BenchTimer +{ + typedef std::chrono::high_resolution_clock clock; + + BenchTimer() : start_time(clock::now()) {} + void reset() { start_time = clock::now(); } + // this is seconds + double elapsed() { return std::chrono::duration (clock::now() - start_time).count(); } +private: + std::chrono::time_point start_time; +}; + #endif diff --git a/common/types.h b/common/types.h index 9064b67e0..b3be97d32 100644 --- a/common/types.h +++ b/common/types.h @@ -43,7 +43,9 @@ typedef unsigned char uchar; typedef const char Const_char; //for perl XS #ifdef _WINDOWS - #define snprintf _snprintf + #if (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER < 1900)) + #define snprintf _snprintf + #endif #define strncasecmp _strnicmp #define strcasecmp _stricmp typedef void ThreadReturnType; @@ -83,4 +85,20 @@ typedef const char Const_char; //for perl XS #define DLLFUNC extern "C" #endif +// htonll and ntohll already defined on windows +#ifndef WIN32 +# if defined(__linux__) +# include +# elif defined(__FreeBSD__) || defined(__NetBSD__) +# include +# elif defined (__OpenBSD__) +# include +# define be16toh(x) betoh16(x) +# define be32toh(x) betoh32(x) +# define be64toh(x) betoh64(x) +# endif +# define htonll(x) htobe64(x) +# define ntohll(x) be64toh(x) +#endif + #endif diff --git a/common/useperl.h b/common/useperl.h index 3c0bf8f1c..e9a02d604 100644 --- a/common/useperl.h +++ b/common/useperl.h @@ -46,6 +46,16 @@ extern "C" { //the perl headers dont do this for us... #undef THIS #endif +//These need to be cleaned up on FreeBSD +#ifdef __FreeBSD__ +#ifdef do_open +#undef do_open +#endif + +#ifdef do_close +#undef do_close +#endif +#endif #endif /*EMU_PERL_H_*/ diff --git a/common/version.h b/common/version.h index 7b8cfd78c..38731b3ba 100644 --- a/common/version.h +++ b/common/version.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2013 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,13 +24,18 @@ #define CURRENT_VERSION "1.1.3" -/* - Everytime a Database SQL is added to Github, +/* + Everytime a Database SQL is added to Github, increment CURRENT_BINARY_DATABASE_VERSION number and make sure you update the manifest - Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt + Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9077 +#define CURRENT_BINARY_DATABASE_VERSION 9097 +#ifdef BOTS + #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9008 +#else + #define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0 +#endif #define COMPILE_DATE __DATE__ #define COMPILE_TIME __TIME__ #ifndef WIN32 diff --git a/common/worldconn.cpp b/common/worldconn.cpp index e85d24a75..432148f89 100644 --- a/common/worldconn.cpp +++ b/common/worldconn.cpp @@ -46,7 +46,7 @@ void WorldConnection::OnConnected() { const EQEmuConfig *Config=EQEmuConfig::get(); Log.Out(Logs::General, Logs::Netcode, "[WORLD] Connected to World: %s:%d", Config->WorldIP.c_str(), Config->WorldTCPPort); - ServerPacket* pack = new ServerPacket(ServerOP_ZAAuth, 16); + auto pack = new ServerPacket(ServerOP_ZAAuth, 16); MD5::Generate((const uchar*) m_password.c_str(), m_password.length(), pack->pBuffer); SendPacket(pack); safe_delete(pack); diff --git a/eqlaunch/eqlaunch.cpp b/eqlaunch/eqlaunch.cpp index 76c9b48d1..da37b9d3b 100644 --- a/eqlaunch/eqlaunch.cpp +++ b/eqlaunch/eqlaunch.cpp @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) { Log.Out(Logs::Detail, Logs::Launcher, "Loading server configuration failed."); return 1; } - const EQEmuConfig *Config = EQEmuConfig::get(); + auto Config = EQEmuConfig::get(); /* * Setup nice signal handlers @@ -102,8 +102,6 @@ int main(int argc, char *argv[]) { Log.Out(Logs::Detail, Logs::Launcher, "Starting main loop..."); -// zones["test"] = new ZoneLaunch(&world, "./zone", "dynamic_1"); - ProcLauncher *launch = ProcLauncher::get(); RunLoops = true; while(RunLoops) { diff --git a/eqlaunch/worldserver.cpp b/eqlaunch/worldserver.cpp index a4b27a983..37c963eb3 100644 --- a/eqlaunch/worldserver.cpp +++ b/eqlaunch/worldserver.cpp @@ -38,7 +38,7 @@ WorldServer::~WorldServer() { void WorldServer::OnConnected() { WorldConnection::OnConnected(); - ServerPacket* pack = new ServerPacket(ServerOP_LauncherConnectInfo, sizeof(LauncherConnectInfo)); + auto pack = new ServerPacket(ServerOP_LauncherConnectInfo, sizeof(LauncherConnectInfo)); LauncherConnectInfo* sci = (LauncherConnectInfo*) pack->pBuffer; strn0cpy(sci->name, m_name, sizeof(sci->name)); // sci->port = net.GetZonePort(); @@ -86,20 +86,19 @@ void WorldServer::Process() { } const LauncherZoneRequest *lzr = (const LauncherZoneRequest *) pack->pBuffer; - switch(ZoneRequestCommands(lzr->command)) { case ZR_Start: { if(m_zones.find(lzr->short_name) != m_zones.end()) { Log.Out(Logs::Detail, Logs::Launcher, "World told us to start zone %s, but it is already running.", lzr->short_name); } else { Log.Out(Logs::Detail, Logs::Launcher, "World told us to start zone %s.", lzr->short_name); - ZoneLaunch *l = new ZoneLaunch(this, m_name, lzr->short_name, m_config); + auto l = new ZoneLaunch(this, m_name, lzr->short_name, lzr->port, m_config); m_zones[lzr->short_name] = l; } break; } case ZR_Restart: { - std::map::iterator res = m_zones.find(lzr->short_name); + auto res = m_zones.find(lzr->short_name); if(res == m_zones.end()) { Log.Out(Logs::Detail, Logs::Launcher, "World told us to restart zone %s, but it is not running.", lzr->short_name); } else { @@ -109,7 +108,7 @@ void WorldServer::Process() { break; } case ZR_Stop: { - std::map::iterator res = m_zones.find(lzr->short_name); + auto res = m_zones.find(lzr->short_name); if(res == m_zones.end()) { Log.Out(Logs::Detail, Logs::Launcher, "World told us to stop zone %s, but it is not running.", lzr->short_name); } else { @@ -138,7 +137,7 @@ void WorldServer::Process() { void WorldServer::SendStatus(const char *short_name, uint32 start_count, bool running) { - ServerPacket* pack = new ServerPacket(ServerOP_LauncherZoneStatus, sizeof(LauncherZoneStatus)); + auto pack = new ServerPacket(ServerOP_LauncherZoneStatus, sizeof(LauncherZoneStatus)); LauncherZoneStatus* it =(LauncherZoneStatus*) pack->pBuffer; strn0cpy(it->short_name, short_name, 32); diff --git a/eqlaunch/zone_launch.cpp b/eqlaunch/zone_launch.cpp index 8c1e62223..7af96c59f 100644 --- a/eqlaunch/zone_launch.cpp +++ b/eqlaunch/zone_launch.cpp @@ -34,10 +34,11 @@ void ZoneLaunch::InitStartTimer() { } ZoneLaunch::ZoneLaunch(WorldServer *world, const char *launcher_name, -const char *zone_name, const EQEmuConfig *config) +const char *zone_name, uint16 port, const EQEmuConfig *config) : m_state(StateStartPending), m_world(world), m_zone(zone_name), + m_port(port), m_launcherName(launcher_name), m_config(config), m_timer(config->RestartWait), @@ -59,12 +60,16 @@ void ZoneLaunch::SendStatus() const { } void ZoneLaunch::Start() { - ProcLauncher::Spec *spec = new ProcLauncher::Spec(); + auto spec = new ProcLauncher::Spec(); spec->program = m_config->ZoneExe; -// if(m_zone.substr(0,7) == "dynamic") -// spec->args.push_back("."); -// else - spec->args.push_back(m_zone); + + if(m_port) { + std::string arg = m_zone + std::string(":") + std::to_string(m_port); + spec->args.push_back(arg); + } else { + spec->args.push_back(m_zone); + } + spec->args.push_back(m_launcherName); spec->handler = this; spec->logFile = m_config->LogPrefix + m_zone + m_config->LogSuffix; diff --git a/eqlaunch/zone_launch.h b/eqlaunch/zone_launch.h index 3dc0fd697..ac48be92c 100644 --- a/eqlaunch/zone_launch.h +++ b/eqlaunch/zone_launch.h @@ -28,7 +28,7 @@ class EQEmuConfig; class ZoneLaunch : protected ProcLauncher::EventHandler { public: ZoneLaunch(WorldServer *world, const char *launcher_name, - const char *zone_name, const EQEmuConfig *config); + const char *zone_name, uint16 port, const EQEmuConfig *config); virtual ~ZoneLaunch(); void Stop(bool graceful = true); @@ -63,6 +63,7 @@ protected: const std::string m_zone; const char *const m_launcherName; const EQEmuConfig *const m_config; + const uint16 m_port; Timer m_timer; ProcLauncher::ProcRef m_ref; diff --git a/loginserver/CMakeLists.txt b/loginserver/CMakeLists.txt index f588cbc48..82e912edc 100644 --- a/loginserver/CMakeLists.txt +++ b/loginserver/CMakeLists.txt @@ -6,7 +6,6 @@ SET(eqlogin_sources config.cpp database_mysql.cpp database_postgresql.cpp - error_log.cpp main.cpp server_manager.cpp world_server.cpp @@ -26,7 +25,6 @@ SET(eqlogin_headers database_postgresql.h encryption.h eq_crypto_api.h - error_log.h login_server.h login_structures.h options.h @@ -43,7 +41,7 @@ ADD_EXECUTABLE(loginserver ${eqlogin_sources} ${eqlogin_headers}) INSTALL(TARGETS loginserver RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) -TARGET_LINK_LIBRARIES(loginserver common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE}) +TARGET_LINK_LIBRARIES(loginserver common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY}) IF(MSVC) SET_TARGET_PROPERTIES(loginserver PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") diff --git a/loginserver/client.cpp b/loginserver/client.cpp index fe43e6675..9a6a81593 100644 --- a/loginserver/client.cpp +++ b/loginserver/client.cpp @@ -16,12 +16,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "client.h" -#include "error_log.h" #include "login_server.h" #include "login_structures.h" #include "../common/misc_functions.h" +#include "../common/eqemu_logsys.h" -extern ErrorLog *server_log; +extern EQEmuLogSys Log; extern LoginServer server; Client::Client(std::shared_ptr c, LSClientVersion v) @@ -41,7 +41,7 @@ bool Client::Process() { if(server.options.IsTraceOn()) { - server_log->Log(log_network, "Application packet received from client (size %u)", app->Size()); + Log.Out(Logs::General, Logs::Login_Server, "Application packet received from client (size %u)", app->Size()); } if(server.options.IsDumpInPacketsOn()) @@ -55,7 +55,7 @@ bool Client::Process() { if(server.options.IsTraceOn()) { - server_log->Log(log_network, "Session ready received from client."); + Log.Out(Logs::General, Logs::Login_Server, "Session ready received from client."); } Handle_SessionReady((const char*)app->pBuffer, app->Size()); break; @@ -64,13 +64,13 @@ bool Client::Process() { if(app->Size() < 20) { - server_log->Log(log_network_error, "Login received but it is too small, discarding."); + Log.Out(Logs::General, Logs::Error, "Login received but it is too small, discarding."); break; } if(server.options.IsTraceOn()) { - server_log->Log(log_network, "Login received from client."); + Log.Out(Logs::General, Logs::Login_Server, "Login received from client."); } Handle_Login((const char*)app->pBuffer, app->Size()); @@ -80,7 +80,7 @@ bool Client::Process() { if(server.options.IsTraceOn()) { - server_log->Log(log_network, "Server list request received from client."); + Log.Out(Logs::General, Logs::Login_Server, "Server list request received from client."); } SendServerListPacket(); @@ -90,7 +90,7 @@ bool Client::Process() { if(app->Size() < sizeof(PlayEverquestRequest_Struct)) { - server_log->Log(log_network_error, "Play received but it is too small, discarding."); + Log.Out(Logs::General, Logs::Error, "Play received but it is too small, discarding."); break; } @@ -101,7 +101,7 @@ bool Client::Process() { char dump[64]; app->build_header_dump(dump); - server_log->Log(log_network_error, "Recieved unhandled application packet from the client: %s.", dump); + Log.Out(Logs::General, Logs::Error, "Recieved unhandled application packet from the client: %s.", dump); } } @@ -116,20 +116,20 @@ void Client::Handle_SessionReady(const char* data, unsigned int size) { if(status != cs_not_sent_session_ready) { - server_log->Log(log_network_error, "Session ready received again after already being received."); + Log.Out(Logs::General, Logs::Error, "Session ready received again after already being received."); return; } if(size < sizeof(unsigned int)) { - server_log->Log(log_network_error, "Session ready was too small."); + Log.Out(Logs::General, Logs::Error, "Session ready was too small."); return; } unsigned int mode = *((unsigned int*)data); if(mode == (unsigned int)lm_from_world) { - server_log->Log(log_network, "Session ready indicated logged in from world(unsupported feature), disconnecting."); + Log.Out(Logs::General, Logs::Login_Server, "Session ready indicated logged in from world(unsupported feature), disconnecting."); connection->Close(); return; } @@ -175,138 +175,144 @@ void Client::Handle_SessionReady(const char* data, unsigned int size) void Client::Handle_Login(const char* data, unsigned int size) { - if(status != cs_waiting_for_login) - { - server_log->Log(log_network_error, "Login received after already having logged in."); + if(status != cs_waiting_for_login) { + Log.Out(Logs::General, Logs::Error, "Login received after already having logged in."); return; } - if((size - 12) % 8 != 0) - { - server_log->Log(log_network_error, "Login received packet of size: %u, this would cause a block corruption, discarding.", size); + if((size - 12) % 8 != 0) { + Log.Out(Logs::General, Logs::Error, "Login received packet of size: %u, this would cause a block corruption, discarding.", size); return; } status = cs_logged_in; - string e_user; - string e_hash; - char *e_buffer = nullptr; - unsigned int d_account_id = 0; - string d_pass_hash; + string entered_username; + string entered_password_hash_result; + + char *login_packet_buffer = nullptr; + + unsigned int db_account_id = 0; + string db_account_password_hash; #ifdef WIN32 - e_buffer = server.eq_crypto->DecryptUsernamePassword(data, size, server.options.GetEncryptionMode()); + login_packet_buffer = server.eq_crypto->DecryptUsernamePassword(data, size, server.options.GetEncryptionMode()); - int buffer_len = strlen(e_buffer); - e_hash.assign(e_buffer, buffer_len); - e_user.assign((e_buffer + buffer_len + 1), strlen(e_buffer + buffer_len + 1)); + int login_packet_buffer_length = strlen(login_packet_buffer); + entered_password_hash_result.assign(login_packet_buffer, login_packet_buffer_length); + entered_username.assign((login_packet_buffer + login_packet_buffer_length + 1), strlen(login_packet_buffer + login_packet_buffer_length + 1)); - if(server.options.IsTraceOn()) - { - server_log->Log(log_client, "User: %s", e_user.c_str()); - server_log->Log(log_client, "Hash: %s", e_hash.c_str()); + if(server.options.IsTraceOn()) { + Log.Out(Logs::General, Logs::Debug, "User: %s", entered_username.c_str()); + Log.Out(Logs::General, Logs::Debug, "Hash: %s", entered_password_hash_result.c_str()); } - server.eq_crypto->DeleteHeap(e_buffer); + server.eq_crypto->DeleteHeap(login_packet_buffer); #else - e_buffer = DecryptUsernamePassword(data, size, server.options.GetEncryptionMode()); + login_packet_buffer = DecryptUsernamePassword(data, size, server.options.GetEncryptionMode()); - int buffer_len = strlen(e_buffer); - e_hash.assign(e_buffer, buffer_len); - e_user.assign((e_buffer + buffer_len + 1), strlen(e_buffer + buffer_len + 1)); + int login_packet_buffer_length = strlen(login_packet_buffer); + entered_password_hash_result.assign(login_packet_buffer, login_packet_buffer_length); + entered_username.assign((login_packet_buffer + login_packet_buffer_length + 1), strlen(login_packet_buffer + login_packet_buffer_length + 1)); - if(server.options.IsTraceOn()) - { - server_log->Log(log_client, "User: %s", e_user.c_str()); - server_log->Log(log_client, "Hash: %s", e_hash.c_str()); + if(server.options.IsTraceOn()) { + Log.Out(Logs::General, Logs::Debug, "User: %s", entered_username.c_str()); + Log.Out(Logs::General, Logs::Debug, "Hash: %s", entered_password_hash_result.c_str()); } - _HeapDeleteCharBuffer(e_buffer); + _HeapDeleteCharBuffer(login_packet_buffer); #endif bool result; - if(server.db->GetLoginDataFromAccountName(e_user, d_pass_hash, d_account_id) == false) - { - server_log->Log(log_client_error, "Error logging in, user %s does not exist in the database.", e_user.c_str()); - result = false; - } - else - { - if(d_pass_hash.compare(e_hash) == 0) - { + if(server.db->GetLoginDataFromAccountName(entered_username, db_account_password_hash, db_account_id) == false) { + /* If we have auto_create_accounts enabled in the login.ini, we will process the creation of an account on our own*/ + if ( + server.config->GetVariable("options", "auto_create_accounts").compare("TRUE") == 0 && + server.db->CreateLoginData(entered_username, entered_password_hash_result, db_account_id) == true + ){ + Log.Out(Logs::General, Logs::Error, "User %s does not exist in the database, so we created it...", entered_username.c_str()); result = true; } - else - { + else{ + Log.Out(Logs::General, Logs::Error, "Error logging in, user %s does not exist in the database.", entered_username.c_str()); + result = false; + } + } + else { + if(db_account_password_hash.compare(entered_password_hash_result) == 0) { + result = true; + } + else { result = false; } } - if(result) - { - server.CM->RemoveExistingClient(d_account_id); + /* Login Accepted */ + if(result) { + + server.client_manager->RemoveExistingClient(db_account_id); + in_addr in; in.s_addr = connection->GetRemoteIP(); - server.db->UpdateLSAccountData(d_account_id, string(inet_ntoa(in))); + + server.db->UpdateLSAccountData(db_account_id, string(inet_ntoa(in))); GenerateKey(); - account_id = d_account_id; - account_name = e_user; + + account_id = db_account_id; + account_name = entered_username; EQApplicationPacket *outapp = new EQApplicationPacket(OP_LoginAccepted, 10 + 80); const LoginLoginRequest_Struct* llrs = (const LoginLoginRequest_Struct *)data; - LoginLoginAccepted_Struct* llas = (LoginLoginAccepted_Struct *)outapp->pBuffer; - llas->unknown1 = llrs->unknown1; - llas->unknown2 = llrs->unknown2; - llas->unknown3 = llrs->unknown3; - llas->unknown4 = llrs->unknown4; - llas->unknown5 = llrs->unknown5; + LoginAccepted_Struct* login_accepted = (LoginAccepted_Struct *)outapp->pBuffer; + login_accepted->unknown1 = llrs->unknown1; + login_accepted->unknown2 = llrs->unknown2; + login_accepted->unknown3 = llrs->unknown3; + login_accepted->unknown4 = llrs->unknown4; + login_accepted->unknown5 = llrs->unknown5; - Login_ReplyBlock_Struct * lrbs = new Login_ReplyBlock_Struct; - memset(lrbs, 0, sizeof(Login_ReplyBlock_Struct)); + LoginFailedAttempts_Struct * login_failed_attempts = new LoginFailedAttempts_Struct; + memset(login_failed_attempts, 0, sizeof(LoginFailedAttempts_Struct)); - lrbs->failed_attempts = 0; - lrbs->message = 0x01; - lrbs->lsid = d_account_id; - lrbs->unknown3[3] = 0x03; - lrbs->unknown4[3] = 0x02; - lrbs->unknown5[0] = 0xe7; - lrbs->unknown5[1] = 0x03; - lrbs->unknown6[0] = 0xff; - lrbs->unknown6[1] = 0xff; - lrbs->unknown6[2] = 0xff; - lrbs->unknown6[3] = 0xff; - lrbs->unknown7[0] = 0xa0; - lrbs->unknown7[1] = 0x05; - lrbs->unknown8[3] = 0x02; - lrbs->unknown9[0] = 0xff; - lrbs->unknown9[1] = 0x03; - lrbs->unknown11[0] = 0x63; - lrbs->unknown12[0] = 0x01; - memcpy(lrbs->key, key.c_str(), key.size()); + login_failed_attempts->failed_attempts = 0; + login_failed_attempts->message = 0x01; + login_failed_attempts->lsid = db_account_id; + login_failed_attempts->unknown3[3] = 0x03; + login_failed_attempts->unknown4[3] = 0x02; + login_failed_attempts->unknown5[0] = 0xe7; + login_failed_attempts->unknown5[1] = 0x03; + login_failed_attempts->unknown6[0] = 0xff; + login_failed_attempts->unknown6[1] = 0xff; + login_failed_attempts->unknown6[2] = 0xff; + login_failed_attempts->unknown6[3] = 0xff; + login_failed_attempts->unknown7[0] = 0xa0; + login_failed_attempts->unknown7[1] = 0x05; + login_failed_attempts->unknown8[3] = 0x02; + login_failed_attempts->unknown9[0] = 0xff; + login_failed_attempts->unknown9[1] = 0x03; + login_failed_attempts->unknown11[0] = 0x63; + login_failed_attempts->unknown12[0] = 0x01; + memcpy(login_failed_attempts->key, key.c_str(), key.size()); #ifdef WIN32 unsigned int e_size; - char *encrypted_buffer = server.eq_crypto->Encrypt((const char*)lrbs, 75, e_size); - memcpy(llas->encrypt, encrypted_buffer, 80); + char *encrypted_buffer = server.eq_crypto->Encrypt((const char*)login_failed_attempts, 75, e_size); + memcpy(login_accepted->encrypt, encrypted_buffer, 80); server.eq_crypto->DeleteHeap(encrypted_buffer); #else unsigned int e_size; - char *encrypted_buffer = Encrypt((const char*)lrbs, 75, e_size); - memcpy(llas->encrypt, encrypted_buffer, 80); + char *encrypted_buffer = Encrypt((const char*)login_failed_attempts, 75, e_size); + memcpy(login_accepted->encrypt, encrypted_buffer, 80); _HeapDeleteCharBuffer(encrypted_buffer); #endif - if(server.options.IsDumpOutPacketsOn()) - { + if(server.options.IsDumpOutPacketsOn()) { DumpPacket(outapp); } connection->QueuePacket(outapp); delete outapp; } - else - { + else { EQApplicationPacket *outapp = new EQApplicationPacket(OP_LoginAccepted, sizeof(LoginLoginFailed_Struct)); const LoginLoginRequest_Struct* llrs = (const LoginLoginRequest_Struct *)data; LoginLoginFailed_Struct* llas = (LoginLoginFailed_Struct *)outapp->pBuffer; @@ -317,8 +323,7 @@ void Client::Handle_Login(const char* data, unsigned int size) llas->unknown5 = llrs->unknown5; memcpy(llas->unknown6, FailedLoginResponseData, sizeof(FailedLoginResponseData)); - if(server.options.IsDumpOutPacketsOn()) - { + if(server.options.IsDumpOutPacketsOn()) { DumpPacket(outapp); } @@ -331,7 +336,7 @@ void Client::Handle_Play(const char* data) { if(status != cs_logged_in) { - server_log->Log(log_client_error, "Client sent a play request when they either were not logged in, discarding."); + Log.Out(Logs::General, Logs::Error, "Client sent a play request when they either were not logged in, discarding."); return; } @@ -341,18 +346,18 @@ void Client::Handle_Play(const char* data) if(server.options.IsTraceOn()) { - server_log->Log(log_network, "Play received from client, server number %u sequence %u.", server_id_in, sequence_in); + Log.Out(Logs::General, Logs::Login_Server, "Play received from client, server number %u sequence %u.", server_id_in, sequence_in); } this->play_server_id = (unsigned int)play->ServerNumber; play_sequence_id = sequence_in; play_server_id = server_id_in; - server.SM->SendUserToWorldRequest(server_id_in, account_id); + server.server_manager->SendUserToWorldRequest(server_id_in, account_id); } void Client::SendServerListPacket() { - EQApplicationPacket *outapp = server.SM->CreateServerListPacket(this); + EQApplicationPacket *outapp = server.server_manager->CreateServerListPacket(this); if(server.options.IsDumpOutPacketsOn()) { @@ -367,8 +372,8 @@ void Client::SendPlayResponse(EQApplicationPacket *outapp) { if(server.options.IsTraceOn()) { - server_log->Log(log_network_trace, "Sending play response for %s.", GetAccountName().c_str()); - server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size); + Log.Out(Logs::General, Logs::Netcode, "Sending play response for %s.", GetAccountName().c_str()); + // server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size); } connection->QueuePacket(outapp); status = cs_logged_in; @@ -378,7 +383,7 @@ void Client::GenerateKey() { key.clear(); int count = 0; - while(count < 10) + while (count < 10) { static const char key_selection[] = { diff --git a/loginserver/client_manager.cpp b/loginserver/client_manager.cpp index eb982f613..c600d58f5 100644 --- a/loginserver/client_manager.cpp +++ b/loginserver/client_manager.cpp @@ -16,13 +16,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "client_manager.h" -#include "error_log.h" #include "login_server.h" -extern ErrorLog *server_log; extern LoginServer server; extern bool run_server; +#include "../common/eqemu_logsys.h" +extern EQEmuLogSys Log; + ClientManager::ClientManager() { int titanium_port = atoi(server.config->GetVariable("Titanium", "port").c_str()); @@ -30,18 +31,18 @@ ClientManager::ClientManager() titanium_ops = new RegularOpcodeManager; if(!titanium_ops->LoadOpcodes(server.config->GetVariable("Titanium", "opcodes").c_str())) { - server_log->Log(log_error, "ClientManager fatal error: couldn't load opcodes for Titanium file %s.", + Log.Out(Logs::General, Logs::Error, "ClientManager fatal error: couldn't load opcodes for Titanium file %s.", server.config->GetVariable("Titanium", "opcodes").c_str()); run_server = false; } if(titanium_stream->Open()) { - server_log->Log(log_network, "ClientManager listening on Titanium stream."); + Log.Out(Logs::General, Logs::Login_Server, "ClientManager listening on Titanium stream."); } else { - server_log->Log(log_error, "ClientManager fatal error: couldn't open Titanium stream."); + Log.Out(Logs::General, Logs::Error, "ClientManager fatal error: couldn't open Titanium stream."); run_server = false; } @@ -50,18 +51,18 @@ ClientManager::ClientManager() sod_ops = new RegularOpcodeManager; if(!sod_ops->LoadOpcodes(server.config->GetVariable("SoD", "opcodes").c_str())) { - server_log->Log(log_error, "ClientManager fatal error: couldn't load opcodes for SoD file %s.", + Log.Out(Logs::General, Logs::Error, "ClientManager fatal error: couldn't load opcodes for SoD file %s.", server.config->GetVariable("SoD", "opcodes").c_str()); run_server = false; } if(sod_stream->Open()) { - server_log->Log(log_network, "ClientManager listening on SoD stream."); + Log.Out(Logs::General, Logs::Login_Server, "ClientManager listening on SoD stream."); } else { - server_log->Log(log_error, "ClientManager fatal error: couldn't open SoD stream."); + Log.Out(Logs::General, Logs::Error, "ClientManager fatal error: couldn't open SoD stream."); run_server = false; } } @@ -99,7 +100,7 @@ void ClientManager::Process() { struct in_addr in; in.s_addr = cur->GetRemoteIP(); - server_log->Log(log_network, "New Titanium client connection from %s:%d", inet_ntoa(in), ntohs(cur->GetRemotePort())); + Log.Out(Logs::General, Logs::Login_Server, "New Titanium client connection from %s:%d", inet_ntoa(in), ntohs(cur->GetRemotePort())); cur->SetOpcodeManager(&titanium_ops); Client *c = new Client(cur, cv_titanium); @@ -112,7 +113,7 @@ void ClientManager::Process() { struct in_addr in; in.s_addr = cur->GetRemoteIP(); - server_log->Log(log_network, "New SoD client connection from %s:%d", inet_ntoa(in), ntohs(cur->GetRemotePort())); + Log.Out(Logs::General, Logs::Login_Server, "New SoD client connection from %s:%d", inet_ntoa(in), ntohs(cur->GetRemotePort())); cur->SetOpcodeManager(&sod_ops); Client *c = new Client(cur, cv_sod); @@ -125,7 +126,7 @@ void ClientManager::Process() { if((*iter)->Process() == false) { - server_log->Log(log_client, "Client had a fatal error and had to be removed from the login."); + Log.Out(Logs::General, Logs::Debug, "Client had a fatal error and had to be removed from the login."); delete (*iter); iter = clients.erase(iter); } @@ -144,7 +145,7 @@ void ClientManager::ProcessDisconnect() std::shared_ptr c = (*iter)->GetConnection(); if(c->CheckClosed()) { - server_log->Log(log_network, "Client disconnected from the server, removing client."); + Log.Out(Logs::General, Logs::Login_Server, "Client disconnected from the server, removing client."); delete (*iter); iter = clients.erase(iter); } @@ -172,7 +173,7 @@ void ClientManager::RemoveExistingClient(unsigned int account_id) { if((*iter)->GetAccountID() == account_id) { - server_log->Log(log_network, "Client attempting to log in and existing client already logged in, removing existing client."); + Log.Out(Logs::General, Logs::Login_Server, "Client attempting to log in and existing client already logged in, removing existing client."); delete (*iter); iter = clients.erase(iter); } @@ -200,7 +201,7 @@ Client *ClientManager::GetClient(unsigned int account_id) if(count > 1) { - server_log->Log(log_client_error, "More than one client with a given account_id existed in the client list."); + Log.Out(Logs::General, Logs::Error, "More than one client with a given account_id existed in the client list."); } return cur; } diff --git a/loginserver/config.cpp b/loginserver/config.cpp index 96a4c8568..ee17bdbed 100644 --- a/loginserver/config.cpp +++ b/loginserver/config.cpp @@ -16,10 +16,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "../common/global_define.h" +#include "../common/eqemu_logsys.h" #include "config.h" -#include "error_log.h" -extern ErrorLog *server_log; +extern EQEmuLogSys Log; /** * Retrieves the variable we want from our title or theme * First gets the map from the title @@ -48,7 +48,7 @@ void Config::Parse(const char *file_name) { if(file_name == nullptr) { - server_log->Log(log_error, "Config::Parse(), file_name passed was null."); + Log.Out(Logs::General, Logs::Error, "Config::Parse(), file_name passed was null."); return; } @@ -71,7 +71,7 @@ void Config::Parse(const char *file_name) ++iter; if(iter == tokens.end()) { - server_log->Log(log_error, "Config::Parse(), EOF before title done parsing."); + Log.Out(Logs::General, Logs::Error, "Config::Parse(), EOF before title done parsing."); fclose(input); vars.clear(); return; @@ -104,7 +104,7 @@ void Config::Parse(const char *file_name) mode++; if((*iter).compare("=") != 0) { - server_log->Log(log_error, "Config::Parse(), invalid parse token where = should be."); + Log.Out(Logs::General, Logs::Error, "Config::Parse(), invalid parse token where = should be."); fclose(input); vars.clear(); return; @@ -133,7 +133,7 @@ void Config::Parse(const char *file_name) } else { - server_log->Log(log_error, "Config::Parse(), file was unable to be opened for parsing."); + Log.Out(Logs::General, Logs::Error, "Config::Parse(), file was unable to be opened for parsing."); } } diff --git a/loginserver/database.h b/loginserver/database.h index 7244f2e79..b7e9f9d24 100644 --- a/loginserver/database.h +++ b/loginserver/database.h @@ -44,6 +44,8 @@ public: */ virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id) { return false; } + virtual bool CreateLoginData(std::string name, std::string &password, unsigned int &id) { return false; } + /** * Retrieves the world registration from the long and short names provided. * Needed for world login procedure. diff --git a/loginserver/database_mysql.cpp b/loginserver/database_mysql.cpp index 9cf08563b..b9536de7e 100644 --- a/loginserver/database_mysql.cpp +++ b/loginserver/database_mysql.cpp @@ -20,14 +20,12 @@ #ifdef EQEMU_MYSQL_ENABLED #include "database_mysql.h" -#include "error_log.h" #include "login_server.h" +#include "../common/eqemu_logsys.h" -extern ErrorLog *server_log; +extern EQEmuLogSys Log; extern LoginServer server; -#pragma comment(lib, "mysqlclient.lib") - DatabaseMySQL::DatabaseMySQL(string user, string pass, string host, string port, string name) { this->user = user; @@ -35,35 +33,35 @@ DatabaseMySQL::DatabaseMySQL(string user, string pass, string host, string port, this->host = host; this->name = name; - db = mysql_init(nullptr); - if(db) + database = mysql_init(nullptr); + if(database) { my_bool r = 1; - mysql_options(db, MYSQL_OPT_RECONNECT, &r); - if(!mysql_real_connect(db, host.c_str(), user.c_str(), pass.c_str(), name.c_str(), atoi(port.c_str()), nullptr, 0)) + mysql_options(database, MYSQL_OPT_RECONNECT, &r); + if(!mysql_real_connect(database, host.c_str(), user.c_str(), pass.c_str(), name.c_str(), atoi(port.c_str()), nullptr, 0)) { - mysql_close(db); - server_log->Log(log_database, "Failed to connect to MySQL database. Error: %s", mysql_error(db)); + mysql_close(database); + Log.Out(Logs::General, Logs::Error, "Failed to connect to MySQL database. Error: %s", mysql_error(database)); exit(1); } } else { - server_log->Log(log_database, "Failed to create db object in MySQL database."); + Log.Out(Logs::General, Logs::Error, "Failed to create db object in MySQL database."); } } DatabaseMySQL::~DatabaseMySQL() { - if(db) + if(database) { - mysql_close(db); + mysql_close(database); } } bool DatabaseMySQL::GetLoginDataFromAccountName(string name, string &password, unsigned int &id) { - if(!db) + if (!database) { return false; } @@ -75,17 +73,17 @@ bool DatabaseMySQL::GetLoginDataFromAccountName(string name, string &password, u query << name; query << "'"; - if(mysql_query(db, query.str().c_str()) != 0) + if (mysql_query(database, query.str().c_str()) != 0) { - server_log->Log(log_database, "Mysql query failed: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); return false; } - res = mysql_use_result(db); + res = mysql_use_result(database); - if(res) + if (res) { - while((row = mysql_fetch_row(res)) != nullptr) + while ((row = mysql_fetch_row(res)) != nullptr) { id = atoi(row[0]); password = row[1]; @@ -94,14 +92,41 @@ bool DatabaseMySQL::GetLoginDataFromAccountName(string name, string &password, u } } - server_log->Log(log_database, "Mysql query returned no result: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query returned no result: %s", query.str().c_str()); + return false; +} + + +bool DatabaseMySQL::CreateLoginData(string name, string &password, unsigned int &id) +{ + if (!database) { + return false; + } + + MYSQL_RES *result; + MYSQL_ROW row; + stringstream query(stringstream::in | stringstream::out); + + query << "INSERT INTO " << server.options.GetAccountTable() << " (AccountName, AccountPassword, AccountEmail, LastLoginDate, LastIPAddress) "; + query << " VALUES('" << name << "', '" << password << "', 'local_creation', NOW(), '127.0.0.1'); "; + + if (mysql_query(database, query.str().c_str()) != 0) { + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); + return false; + } + else{ + id = mysql_insert_id(database); + return true; + } + + Log.Out(Logs::General, Logs::Error, "Mysql query returned no result: %s", query.str().c_str()); return false; } bool DatabaseMySQL::GetWorldRegistration(string long_name, string short_name, unsigned int &id, string &desc, unsigned int &list_id, - unsigned int &trusted, string &list_desc, string &account, string &password) + unsigned int &trusted, string &list_desc, string &account, string &password) { - if(!db) + if (!database) { return false; } @@ -110,26 +135,26 @@ bool DatabaseMySQL::GetWorldRegistration(string long_name, string short_name, un MYSQL_ROW row; char escaped_short_name[101]; unsigned long length; - length = mysql_real_escape_string(db, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length()); - escaped_short_name[length+1] = 0; + length = mysql_real_escape_string(database, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length()); + escaped_short_name[length + 1] = 0; stringstream query(stringstream::in | stringstream::out); - query << "SELECT WSR.ServerID, WSR.ServerTagDescription, WSR.ServerTrusted, SLT.ServerListTypeID, "; - query << "SLT.ServerListTypeDescription, WSR.ServerAdminID FROM " << server.options.GetWorldRegistrationTable(); + query << "SELECT ifnull(WSR.ServerID,999999) AS ServerID, WSR.ServerTagDescription, ifnull(WSR.ServerTrusted,0) AS ServerTrusted, ifnull(SLT.ServerListTypeID,3) AS ServerListTypeID, "; + query << "SLT.ServerListTypeDescription, ifnull(WSR.ServerAdminID,0) AS ServerAdminID FROM " << server.options.GetWorldRegistrationTable(); query << " AS WSR JOIN " << server.options.GetWorldServerTypeTable() << " AS SLT ON WSR.ServerListTypeID = SLT.ServerListTypeID"; query << " WHERE WSR.ServerShortName = '"; query << escaped_short_name; query << "'"; - if(mysql_query(db, query.str().c_str()) != 0) + if (mysql_query(database, query.str().c_str()) != 0) { - server_log->Log(log_database, "Mysql query failed: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); return false; } - res = mysql_use_result(db); - if(res) + res = mysql_use_result(database); + if (res) { - if((row = mysql_fetch_row(res)) != nullptr) + if ((row = mysql_fetch_row(res)) != nullptr) { id = atoi(row[0]); desc = row[1]; @@ -139,22 +164,22 @@ bool DatabaseMySQL::GetWorldRegistration(string long_name, string short_name, un int db_account_id = atoi(row[5]); mysql_free_result(res); - if(db_account_id > 0) + if (db_account_id > 0) { stringstream query(stringstream::in | stringstream::out); query << "SELECT AccountName, AccountPassword FROM " << server.options.GetWorldAdminRegistrationTable(); query << " WHERE ServerAdminID = " << db_account_id; - if(mysql_query(db, query.str().c_str()) != 0) + if (mysql_query(database, query.str().c_str()) != 0) { - server_log->Log(log_database, "Mysql query failed: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); return false; } - res = mysql_use_result(db); - if(res) + res = mysql_use_result(database); + if (res) { - if((row = mysql_fetch_row(res)) != nullptr) + if ((row = mysql_fetch_row(res)) != nullptr) { account = row[0]; password = row[1]; @@ -163,20 +188,20 @@ bool DatabaseMySQL::GetWorldRegistration(string long_name, string short_name, un } } - server_log->Log(log_database, "Mysql query returned no result: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query returned no result: %s", query.str().c_str()); return false; } return true; } } - server_log->Log(log_database, "Mysql query returned no result: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query returned no result: %s", query.str().c_str()); return false; } void DatabaseMySQL::UpdateLSAccountData(unsigned int id, string ip_address) { - if(!db) + if (!database) { return; } @@ -187,15 +212,15 @@ void DatabaseMySQL::UpdateLSAccountData(unsigned int id, string ip_address) query << "', LastLoginDate = now() where LoginServerID = "; query << id; - if(mysql_query(db, query.str().c_str()) != 0) + if (mysql_query(database, query.str().c_str()) != 0) { - server_log->Log(log_database, "Mysql query failed: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); } } void DatabaseMySQL::UpdateLSAccountInfo(unsigned int id, string name, string password, string email) { - if(!db) + if (!database) { return; } @@ -206,23 +231,23 @@ void DatabaseMySQL::UpdateLSAccountInfo(unsigned int id, string name, string pas query << password << "'), AccountCreateDate = now(), AccountEmail = '" << email; query << "', LastIPAddress = '0.0.0.0', LastLoginDate = now()"; - if(mysql_query(db, query.str().c_str()) != 0) + if (mysql_query(database, query.str().c_str()) != 0) { - server_log->Log(log_database, "Mysql query failed: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); } } void DatabaseMySQL::UpdateWorldRegistration(unsigned int id, string long_name, string ip_address) { - if(!db) + if (!database) { return; } char escaped_long_name[101]; unsigned long length; - length = mysql_real_escape_string(db, escaped_long_name, long_name.substr(0, 100).c_str(), long_name.substr(0, 100).length()); - escaped_long_name[length+1] = 0; + length = mysql_real_escape_string(database, escaped_long_name, long_name.substr(0, 100).c_str(), long_name.substr(0, 100).length()); + escaped_long_name[length + 1] = 0; stringstream query(stringstream::in | stringstream::out); query << "UPDATE " << server.options.GetWorldRegistrationTable() << " SET ServerLastLoginDate = now(), ServerLastIPAddr = '"; query << ip_address; @@ -231,15 +256,15 @@ void DatabaseMySQL::UpdateWorldRegistration(unsigned int id, string long_name, s query << "' WHERE ServerID = "; query << id; - if(mysql_query(db, query.str().c_str()) != 0) + if (mysql_query(database, query.str().c_str()) != 0) { - server_log->Log(log_database, "Mysql query failed: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); } } bool DatabaseMySQL::CreateWorldRegistration(string long_name, string short_name, unsigned int &id) { - if(!db) + if (!database) { return false; } @@ -249,23 +274,23 @@ bool DatabaseMySQL::CreateWorldRegistration(string long_name, string short_name, char escaped_long_name[201]; char escaped_short_name[101]; unsigned long length; - length = mysql_real_escape_string(db, escaped_long_name, long_name.substr(0, 100).c_str(), long_name.substr(0, 100).length()); - escaped_long_name[length+1] = 0; - length = mysql_real_escape_string(db, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length()); - escaped_short_name[length+1] = 0; + length = mysql_real_escape_string(database, escaped_long_name, long_name.substr(0, 100).c_str(), long_name.substr(0, 100).length()); + escaped_long_name[length + 1] = 0; + length = mysql_real_escape_string(database, escaped_short_name, short_name.substr(0, 100).c_str(), short_name.substr(0, 100).length()); + escaped_short_name[length + 1] = 0; stringstream query(stringstream::in | stringstream::out); - query << "SELECT max(ServerID) FROM " << server.options.GetWorldRegistrationTable(); + query << "SELECT ifnull(max(ServerID),0) FROM " << server.options.GetWorldRegistrationTable(); - if(mysql_query(db, query.str().c_str()) != 0) + if (mysql_query(database, query.str().c_str()) != 0) { - server_log->Log(log_database, "Mysql query failed: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); return false; } - res = mysql_use_result(db); - if(res) + res = mysql_use_result(database); + if (res) { - if((row = mysql_fetch_row(res)) != nullptr) + if ((row = mysql_fetch_row(res)) != nullptr) { id = atoi(row[0]) + 1; mysql_free_result(res); @@ -275,15 +300,15 @@ bool DatabaseMySQL::CreateWorldRegistration(string long_name, string short_name, query << ", ServerLongName = '" << escaped_long_name << "', ServerShortName = '" << escaped_short_name; query << "', ServerListTypeID = 3, ServerAdminID = 0, ServerTrusted = 0, ServerTagDescription = ''"; - if(mysql_query(db, query.str().c_str()) != 0) + if (mysql_query(database, query.str().c_str()) != 0) { - server_log->Log(log_database, "Mysql query failed: %s", query.str().c_str()); + Log.Out(Logs::General, Logs::Error, "Mysql query failed: %s", query.str().c_str()); return false; } return true; } } - server_log->Log(log_database, "World registration did not exist in the database for %s %s", long_name.c_str(), short_name.c_str()); + Log.Out(Logs::General, Logs::Error, "World registration did not exist in the database for %s %s", long_name.c_str(), short_name.c_str()); return false; } diff --git a/loginserver/database_mysql.h b/loginserver/database_mysql.h index 4249cb614..5cadff34a 100644 --- a/loginserver/database_mysql.h +++ b/loginserver/database_mysql.h @@ -35,7 +35,7 @@ public: /** * Constructor, sets our database to null. */ - DatabaseMySQL() { db = nullptr; } + DatabaseMySQL() { database = nullptr; } /** * Constructor, tries to set our database to connect to the supplied options. @@ -50,7 +50,7 @@ public: /** * @return Returns true if the database successfully connected. */ - virtual bool IsConnected() { return (db != nullptr); } + virtual bool IsConnected() { return (database != nullptr); } /** * Retrieves the login data (password hash and account id) from the account name provided @@ -59,6 +59,8 @@ public: */ virtual bool GetLoginDataFromAccountName(std::string name, std::string &password, unsigned int &id); + virtual bool CreateLoginData(std::string name, std::string &password, unsigned int &id); + /** * Retrieves the world registration from the long and short names provided. * Needed for world login procedure. @@ -88,7 +90,7 @@ public: virtual bool CreateWorldRegistration(std::string long_name, std::string short_name, unsigned int &id); protected: std::string user, pass, host, port, name; - MYSQL *db; + MYSQL *database; }; #endif diff --git a/loginserver/database_postgresql.cpp b/loginserver/database_postgresql.cpp index 3dc20d3f3..fba9aa8ec 100644 --- a/loginserver/database_postgresql.cpp +++ b/loginserver/database_postgresql.cpp @@ -23,7 +23,7 @@ #include "error_log.h" #include "login_server.h" -extern ErrorLog *server_log; + extern LoginServer server; #pragma comment(lib, "libpq.lib") @@ -34,12 +34,12 @@ DatabasePostgreSQL::DatabasePostgreSQL(string user, string pass, string host, st db = PQsetdbLogin(host.c_str(), port.c_str(), nullptr, nullptr, name.c_str(), user.c_str(), pass.c_str()); if(!db) { - server_log->Log(log_database, "Failed to connect to PostgreSQL Database."); + Log.Out(Logs::General, Logs::Error, "Failed to connect to PostgreSQL Database."); } if(PQstatus(db) != CONNECTION_OK) { - server_log->Log(log_database, "Failed to connect to PostgreSQL Database."); + Log.Out(Logs::General, Logs::Error, "Failed to connect to PostgreSQL Database."); PQfinish(db); db = nullptr; } @@ -83,7 +83,7 @@ bool DatabasePostgreSQL::GetLoginDataFromAccountName(string name, string &passwo char *error = PQresultErrorMessage(res); if(strlen(error) > 0) { - server_log->Log(log_database, "Database error in DatabasePostgreSQL::GetLoginDataFromAccountName(): %s", error); + Log.Out(Logs::General, Logs::Error, "Database error in DatabasePostgreSQL::GetLoginDataFromAccountName(): %s", error); PQclear(res); return false; } @@ -135,7 +135,7 @@ bool DatabasePostgreSQL::GetWorldRegistration(string long_name, string short_nam char *error = PQresultErrorMessage(res); if(strlen(error) > 0) { - server_log->Log(log_database, "Database error in DatabasePostgreSQL::GetWorldRegistration(): %s", error); + Log.Out(Logs::General, Logs::Error, "Database error in DatabasePostgreSQL::GetWorldRegistration(): %s", error); PQclear(res); return false; } @@ -188,7 +188,7 @@ void DatabasePostgreSQL::UpdateLSAccountData(unsigned int id, string ip_address) char *error = PQresultErrorMessage(res); if(strlen(error) > 0) { - server_log->Log(log_database, "Database error in DatabasePostgreSQL::GetLoginDataFromAccountName(): %s", error); + Log.Out(Logs::General, Logs::Error, "Database error in DatabasePostgreSQL::GetLoginDataFromAccountName(): %s", error); } PQclear(res); } @@ -225,7 +225,7 @@ void DatabasePostgreSQL::UpdateWorldRegistration(unsigned int id, string long_na char *error = PQresultErrorMessage(res); if(strlen(error) > 0) { - server_log->Log(log_database, "Database error in DatabasePostgreSQL::GetLoginDataFromAccountName(): %s", error); + Log.Out(Logs::General, Logs::Error, "Database error in DatabasePostgreSQL::GetLoginDataFromAccountName(): %s", error); } PQclear(res); } diff --git a/loginserver/encryption.cpp b/loginserver/encryption.cpp index b00f5e88b..3c9ebd49f 100644 --- a/loginserver/encryption.cpp +++ b/loginserver/encryption.cpp @@ -17,16 +17,16 @@ */ #include "../common/global_define.h" #include "encryption.h" -#include "error_log.h" #include -extern ErrorLog *server_log; +#include "../common/eqemu_logsys.h" +extern EQEmuLogSys Log; bool Encryption::LoadCrypto(std::string name) { if(!Load(name.c_str())) { - server_log->Log(log_error, "Failed to load %s from the operating system.", name.c_str()); + Log.Out(Logs::General, Logs::Error, "Failed to load %s from the operating system.", name.c_str()); return false; } else @@ -34,21 +34,21 @@ bool Encryption::LoadCrypto(std::string name) encrypt_func = (DLLFUNC_Encrypt)GetSym("Encrypt"); if(encrypt_func == NULL) { - server_log->Log(log_error, "Failed to attach Encrypt."); + Log.Out(Logs::General, Logs::Error, "Failed to attach Encrypt."); Unload(); return false; } decrypt_func = (DLLFUNC_DecryptUsernamePassword)GetSym("DecryptUsernamePassword"); if(decrypt_func == NULL) { - server_log->Log(log_error, "Failed to attach DecryptUsernamePassword."); + Log.Out(Logs::General, Logs::Error, "Failed to attach DecryptUsernamePassword."); Unload(); return false; } delete_func = (DLLFUNC_HeapDelete)GetSym("_HeapDeleteCharBuffer"); if(delete_func == NULL) { - server_log->Log(log_error, "Failed to attach _HeapDeleteCharBuffer."); + Log.Out(Logs::General, Logs::Error, "Failed to attach _HeapDeleteCharBuffer."); Unload(); return false; } diff --git a/loginserver/error_log.cpp b/loginserver/error_log.cpp deleted file mode 100644 index 03021f6c7..000000000 --- a/loginserver/error_log.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#include -#include "error_log.h" - -const char *eqLogTypes[_log_largest_type] = -{ - "Debug", - "Error", - "Database", - "Network", - "Network Trace", - "Network Error", - "World", - "World Error", - "Client", - "Client Error" -}; - -ErrorLog::ErrorLog(const char* file_name) -{ - log_mutex = new Mutex(); - error_log = fopen(file_name, "w"); -} - -ErrorLog::~ErrorLog() -{ - log_mutex->lock(); - if(error_log) - { - fclose(error_log); - } - log_mutex->unlock(); - delete log_mutex; -} - -void ErrorLog::Log(eqLogType type, const char *message, ...) -{ - if(type >= _log_largest_type) - { - return; - } - - va_list argptr; - char *buffer = new char[4096]; - va_start(argptr, message); - vsnprintf(buffer, 4096, message, argptr); - va_end(argptr); - - time_t m_clock; - struct tm *m_time; - time(&m_clock); - m_time = localtime(&m_clock); - - log_mutex->lock(); - printf("[%s] [%02d.%02d.%02d - %02d:%02d:%02d] %s\n", - eqLogTypes[type], - m_time->tm_mon+1, - m_time->tm_mday, - m_time->tm_year%100, - m_time->tm_hour, - m_time->tm_min, - m_time->tm_sec, - buffer); - - if(error_log) - { - fprintf(error_log, "[%s] [%02d.%02d.%02d - %02d:%02d:%02d] %s\n", - eqLogTypes[type], - m_time->tm_mon+1, - m_time->tm_mday, - m_time->tm_year%100, - m_time->tm_hour, - m_time->tm_min, - m_time->tm_sec, - buffer); - fflush(error_log); - } - - log_mutex->unlock(); - delete[] buffer; -} - -void ErrorLog::LogPacket(eqLogType type, const char *data, size_t size) -{ - if(type >= _log_largest_type) - { - return; - } - - log_mutex->lock(); - time_t m_clock; - struct tm *m_time; - time(&m_clock); - m_time = localtime(&m_clock); - - log_mutex->lock(); - printf("[%s] [%02d.%02d.%02d - %02d:%02d:%02d] dumping packet of size %u:\n", - eqLogTypes[type], - m_time->tm_mon+1, - m_time->tm_mday, - m_time->tm_year%100, - m_time->tm_hour, - m_time->tm_min, - m_time->tm_sec, - (unsigned int)size); - - if(error_log) - { - fprintf(error_log, "[%s] [%02d.%02d.%02d - %02d:%02d:%02d] dumping packet of size %u\n", - eqLogTypes[type], - m_time->tm_mon+1, - m_time->tm_mday, - m_time->tm_year%100, - m_time->tm_hour, - m_time->tm_min, - m_time->tm_sec, - (unsigned int)size); - } - - char ascii[17]; //16 columns + 1 null term - memset(ascii, 0, 17); - - size_t j = 0; - size_t i = 0; - for(; i < size; ++i) - { - if(i % 16 == 0) - { - if(i != 0) - { - printf(" | %s\n", ascii); - if(error_log) - { - fprintf(error_log, " | %s\n", ascii); - } - } - printf("%.4u: ", (unsigned int)i); - memset(ascii, 0, 17); - j = 0; - } - else if(i % 8 == 0) - { - printf("- "); - if(error_log) - { - fprintf(error_log, "- "); - } - } - - printf("%02X ", (unsigned int)data[i]); - if(error_log) - { - fprintf(error_log, "%02X ", (unsigned int)data[i]); - } - - if(data[i] >= 32 && data[i] < 127) - { - ascii[j++] = data[i]; - } - else - { - ascii[j++] = '.'; - } - } - - size_t k = (i - 1) % 16; - if(k < 8) - { - printf(" "); - if(error_log) - { - fprintf(error_log, " "); - } - } - - for(size_t h = k + 1; h < 16; ++h) - { - printf(" "); - if(error_log) - { - fprintf(error_log, " "); - } - } - - printf(" | %s\n", ascii); - if(error_log) - { - fprintf(error_log, " | %s\n", ascii); - fflush(error_log); - } - - log_mutex->unlock(); -} - diff --git a/loginserver/error_log.h b/loginserver/error_log.h deleted file mode 100644 index ad54e12b7..000000000 --- a/loginserver/error_log.h +++ /dev/null @@ -1,79 +0,0 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2010 EQEMu Development Team (http://eqemulator.net) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#ifndef EQEMU_ERROR_LOG_H -#define EQEMU_ERROR_LOG_H - -#include -#include -#include -#include - -#include "../common/mutex.h" - -/** - * Dictates the log type specified in ErrorLog for Log(...) - */ -enum eqLogType -{ - log_debug, - log_error, - log_database, - log_network, - log_network_trace, - log_network_error, - log_world, - log_world_error, - log_client, - log_client_error, - _log_largest_type -}; - -/** - * Basic error logging class. - * Thread safe logging class that records time and date to both a file and to console(if exists). - */ -class ErrorLog -{ -public: - /** - * Constructor: opens the log file for writing and creates our mutex for writing to the log. - */ - ErrorLog(const char* file_name); - - /** - * Closes the file and destroys the mutex. - */ - ~ErrorLog(); - - /** - * Writes to the log system a variable message. - */ - void Log(eqLogType type, const char *message, ...); - - /** - * Writes to the log system a packet. - */ - void LogPacket(eqLogType type, const char *data, size_t size); - -protected: - Mutex *log_mutex; - FILE* error_log; -}; - -#endif - diff --git a/loginserver/login_server.h b/loginserver/login_server.h index f83154b8f..1f0743a46 100644 --- a/loginserver/login_server.h +++ b/loginserver/login_server.h @@ -18,7 +18,6 @@ #ifndef EQEMU_LOGINSERVER_H #define EQEMU_LOGINSERVER_H -#include "error_log.h" #include "config.h" #include "database.h" #include "database_mysql.h" @@ -40,7 +39,7 @@ public: * but it's the most trivial way to do this. */ #ifdef WIN32 - LoginServer() : config(nullptr), db(nullptr), eq_crypto(nullptr), SM(nullptr) { } + LoginServer() : config(nullptr), db(nullptr), eq_crypto(nullptr), server_manager(nullptr) { } #else LoginServer() : config(nullptr), db(nullptr) { } #endif @@ -48,8 +47,8 @@ public: Config *config; Database *db; Options options; - ServerManager *SM; - ClientManager *CM; + ServerManager *server_manager; + ClientManager *client_manager; #ifdef WIN32 Encryption *eq_crypto; diff --git a/loginserver/login_structures.h b/loginserver/login_structures.h index 60d10a653..6e3f290e9 100644 --- a/loginserver/login_structures.h +++ b/loginserver/login_structures.h @@ -38,7 +38,7 @@ struct LoginLoginRequest_Struct { char unknown6[16]; }; -struct LoginLoginAccepted_Struct { +struct LoginAccepted_Struct { short unknown1; short unknown2; short unknown3; @@ -47,7 +47,7 @@ struct LoginLoginAccepted_Struct { char encrypt[80]; }; -struct Login_ReplyBlock_Struct +struct LoginFailedAttempts_Struct { char message; //0x01 char unknown2[7]; //0x00 diff --git a/loginserver/main.cpp b/loginserver/main.cpp index 0d51a69ff..128bdd3c7 100644 --- a/loginserver/main.cpp +++ b/loginserver/main.cpp @@ -32,7 +32,6 @@ TimeoutManager timeout_manager; LoginServer server; EQEmuLogSys Log; -ErrorLog *server_log; bool run_server = true; void CatchSignal(int sig_num) @@ -43,106 +42,63 @@ int main() { RegisterExecutablePlatform(ExePlatformLogin); set_exception_handler(); + Log.LoadLogSettingsDefaults(); - //Create our error log, is of format login_.log - time_t current_time = time(nullptr); - std::stringstream log_name(std::stringstream::in | std::stringstream::out); -#ifdef WIN32 - log_name << ".\\logs\\login_" << (unsigned int)current_time << ".log"; -#else - log_name << "./logs/login_" << (unsigned int)current_time << ".log"; -#endif - server_log = new ErrorLog(log_name.str().c_str()); - server_log->Log(log_debug, "Logging System Init."); + Log.log_settings[Logs::Error].log_to_console = Logs::General; - //Create our subsystem and parse the ini file. + Log.Out(Logs::General, Logs::Login_Server, "Logging System Init."); + + /* Parse out login.ini */ server.config = new Config(); - server_log->Log(log_debug, "Config System Init."); + Log.Out(Logs::General, Logs::Login_Server, "Config System Init."); server.config->Parse("login.ini"); - //Parse unregistered allowed option. - if(server.config->GetVariable("options", "unregistered_allowed").compare("FALSE") == 0) - { + if (server.config->GetVariable("options", "unregistered_allowed").compare("FALSE") == 0) server.options.AllowUnregistered(false); - } - //Parse trace option. - if(server.config->GetVariable("options", "trace").compare("TRUE") == 0) - { + if (server.config->GetVariable("options", "trace").compare("TRUE") == 0) server.options.Trace(true); - } - //Parse trace option. - if(server.config->GetVariable("options", "world_trace").compare("TRUE") == 0) - { + if (server.config->GetVariable("options", "world_trace").compare("TRUE") == 0) server.options.WorldTrace(true); - } - //Parse packet inc dump option. - if(server.config->GetVariable("options", "dump_packets_in").compare("TRUE") == 0) - { + if (server.config->GetVariable("options", "dump_packets_in").compare("TRUE") == 0) server.options.DumpInPackets(true); - } - //Parse packet out dump option. - if(server.config->GetVariable("options", "dump_packets_out").compare("TRUE") == 0) - { + if (server.config->GetVariable("options", "dump_packets_out").compare("TRUE") == 0) server.options.DumpOutPackets(true); - } - //Parse encryption mode option. std::string mode = server.config->GetVariable("security", "mode"); - if(mode.size() > 0) - { + if (mode.size() > 0) server.options.EncryptionMode(atoi(mode.c_str())); - } - //Parse local network option. - std::string ln = server.config->GetVariable("options", "local_network"); - if(ln.size() > 0) - { - server.options.LocalNetwork(ln); - } + std::string local_network = server.config->GetVariable("options", "local_network"); + if (local_network.size() > 0) + server.options.LocalNetwork(local_network); - //Parse reject duplicate servers option. - if(server.config->GetVariable("options", "reject_duplicate_servers").compare("TRUE") == 0) - { + if (server.config->GetVariable("options", "reject_duplicate_servers").compare("TRUE") == 0) server.options.RejectDuplicateServers(true); - } - //Parse account table option. - ln = server.config->GetVariable("schema", "account_table"); - if(ln.size() > 0) - { - server.options.AccountTable(ln); - } + local_network = server.config->GetVariable("schema", "account_table"); + if (local_network.size() > 0) + server.options.AccountTable(local_network); - //Parse world account table option. - ln = server.config->GetVariable("schema", "world_registration_table"); - if(ln.size() > 0) - { - server.options.WorldRegistrationTable(ln); - } + local_network = server.config->GetVariable("schema", "world_registration_table"); + if (local_network.size() > 0) + server.options.WorldRegistrationTable(local_network); - //Parse admin world account table option. - ln = server.config->GetVariable("schema", "world_admin_registration_table"); - if(ln.size() > 0) - { - server.options.WorldAdminRegistrationTable(ln); - } + local_network = server.config->GetVariable("schema", "world_admin_registration_table"); + if (local_network.size() > 0) + server.options.WorldAdminRegistrationTable(local_network); - //Parse world type table option. - ln = server.config->GetVariable("schema", "world_server_type_table"); - if(ln.size() > 0) - { - server.options.WorldServerTypeTable(ln); - } + local_network = server.config->GetVariable("schema", "world_server_type_table"); + if (local_network.size() > 0) + server.options.WorldServerTypeTable(local_network); - //Create our DB from options. - if(server.config->GetVariable("database", "subsystem").compare("MySQL") == 0) - { + /* Create database connection */ + if (server.config->GetVariable("database", "subsystem").compare("MySQL") == 0) { #ifdef EQEMU_MYSQL_ENABLED - server_log->Log(log_debug, "MySQL Database Init."); + Log.Out(Logs::General, Logs::Login_Server, "MySQL Database Init."); server.db = (Database*)new DatabaseMySQL( server.config->GetVariable("database", "user"), server.config->GetVariable("database", "password"), @@ -151,10 +107,9 @@ int main() server.config->GetVariable("database", "db")); #endif } - else if(server.config->GetVariable("database", "subsystem").compare("PostgreSQL") == 0) - { + else if (server.config->GetVariable("database", "subsystem").compare("PostgreSQL") == 0) { #ifdef EQEMU_POSTGRESQL_ENABLED - server_log->Log(log_debug, "PostgreSQL Database Init."); + Log.Out(Logs::General, Logs::Login_Server, "PostgreSQL Database Init."); server.db = (Database*)new DatabasePostgreSQL( server.config->GetVariable("database", "user"), server.config->GetVariable("database", "password"), @@ -164,78 +119,70 @@ int main() #endif } - //Make sure our database got created okay, otherwise cleanup and exit. - if(!server.db) - { - server_log->Log(log_error, "Database Initialization Failure."); - server_log->Log(log_debug, "Config System Shutdown."); + /* Make sure our database got created okay, otherwise cleanup and exit. */ + if (!server.db) { + Log.Out(Logs::General, Logs::Error, "Database Initialization Failure."); + Log.Out(Logs::General, Logs::Login_Server, "Config System Shutdown."); delete server.config; - server_log->Log(log_debug, "Log System Shutdown."); - delete server_log; + Log.Out(Logs::General, Logs::Login_Server, "Log System Shutdown."); return 1; } #if WIN32 //initialize our encryption. - server_log->Log(log_debug, "Encryption Initialize."); + Log.Out(Logs::General, Logs::Login_Server, "Encryption Initialize."); server.eq_crypto = new Encryption(); - if(server.eq_crypto->LoadCrypto(server.config->GetVariable("security", "plugin"))) - { - server_log->Log(log_debug, "Encryption Loaded Successfully."); + if (server.eq_crypto->LoadCrypto(server.config->GetVariable("security", "plugin"))) { + Log.Out(Logs::General, Logs::Login_Server, "Encryption Loaded Successfully."); } - else - { + else { //We can't run without encryption, cleanup and exit. - server_log->Log(log_error, "Encryption Failed to Load."); - server_log->Log(log_debug, "Database System Shutdown."); + Log.Out(Logs::General, Logs::Error, "Encryption Failed to Load."); + Log.Out(Logs::General, Logs::Login_Server, "Database System Shutdown."); delete server.db; - server_log->Log(log_debug, "Config System Shutdown."); + Log.Out(Logs::General, Logs::Login_Server, "Config System Shutdown."); delete server.config; - server_log->Log(log_debug, "Log System Shutdown."); - delete server_log; return 1; } #endif //create our server manager. - server_log->Log(log_debug, "Server Manager Initialize."); - server.SM = new ServerManager(); - if(!server.SM) - { + Log.Out(Logs::General, Logs::Login_Server, "Server Manager Initialize."); + server.server_manager = new ServerManager(); + if (!server.server_manager) { //We can't run without a server manager, cleanup and exit. - server_log->Log(log_error, "Server Manager Failed to Start."); + Log.Out(Logs::General, Logs::Error, "Server Manager Failed to Start."); + #ifdef WIN32 - server_log->Log(log_debug, "Encryption System Shutdown."); + Log.Out(Logs::General, Logs::Login_Server, "Encryption System Shutdown."); delete server.eq_crypto; #endif - server_log->Log(log_debug, "Database System Shutdown."); + + Log.Out(Logs::General, Logs::Login_Server, "Database System Shutdown."); delete server.db; - server_log->Log(log_debug, "Config System Shutdown."); + Log.Out(Logs::General, Logs::Login_Server, "Config System Shutdown."); delete server.config; - server_log->Log(log_debug, "Log System Shutdown."); - delete server_log; return 1; } //create our client manager. - server_log->Log(log_debug, "Client Manager Initialize."); - server.CM = new ClientManager(); - if(!server.CM) - { + Log.Out(Logs::General, Logs::Login_Server, "Client Manager Initialize."); + server.client_manager = new ClientManager(); + if (!server.client_manager) { //We can't run without a client manager, cleanup and exit. - server_log->Log(log_error, "Client Manager Failed to Start."); - server_log->Log(log_debug, "Server Manager Shutdown."); - delete server.SM; + Log.Out(Logs::General, Logs::Error, "Client Manager Failed to Start."); + Log.Out(Logs::General, Logs::Login_Server, "Server Manager Shutdown."); + delete server.server_manager; + #ifdef WIN32 - server_log->Log(log_debug, "Encryption System Shutdown."); + Log.Out(Logs::General, Logs::Login_Server, "Encryption System Shutdown."); delete server.eq_crypto; #endif - server_log->Log(log_debug, "Database System Shutdown."); + + Log.Out(Logs::General, Logs::Login_Server, "Database System Shutdown."); delete server.db; - server_log->Log(log_debug, "Config System Shutdown."); + Log.Out(Logs::General, Logs::Login_Server, "Config System Shutdown."); delete server.config; - server_log->Log(log_debug, "Log System Shutdown."); - delete server_log; return 1; } @@ -247,30 +194,30 @@ int main() #endif #endif - server_log->Log(log_debug, "Server Started."); - while(run_server) - { + Log.Out(Logs::General, Logs::Login_Server, "Server Started."); + while (run_server) { Timer::SetCurrentTime(); - server.CM->Process(); - server.SM->Process(); + server.client_manager->Process(); + server.server_manager->Process(); + timeout_manager.CheckTimeouts(); Sleep(100); } - server_log->Log(log_debug, "Server Shutdown."); - server_log->Log(log_debug, "Client Manager Shutdown."); - delete server.CM; - server_log->Log(log_debug, "Server Manager Shutdown."); - delete server.SM; + Log.Out(Logs::General, Logs::Login_Server, "Server Shutdown."); + Log.Out(Logs::General, Logs::Login_Server, "Client Manager Shutdown."); + delete server.client_manager; + Log.Out(Logs::General, Logs::Login_Server, "Server Manager Shutdown."); + delete server.server_manager; + #ifdef WIN32 - server_log->Log(log_debug, "Encryption System Shutdown."); + Log.Out(Logs::General, Logs::Login_Server, "Encryption System Shutdown."); delete server.eq_crypto; #endif - server_log->Log(log_debug, "Database System Shutdown."); + + Log.Out(Logs::General, Logs::Login_Server, "Database System Shutdown."); delete server.db; - server_log->Log(log_debug, "Config System Shutdown."); + Log.Out(Logs::General, Logs::Login_Server, "Config System Shutdown."); delete server.config; - server_log->Log(log_debug, "Log System Shutdown."); - delete server_log; return 0; } diff --git a/loginserver/server_manager.cpp b/loginserver/server_manager.cpp index 6a1b57d6f..87e269854 100644 --- a/loginserver/server_manager.cpp +++ b/loginserver/server_manager.cpp @@ -17,11 +17,12 @@ */ #include "server_manager.h" #include "login_server.h" -#include "error_log.h" #include "login_structures.h" #include -extern ErrorLog *server_log; +#include "../common/eqemu_logsys.h" + +extern EQEmuLogSys Log; extern LoginServer server; extern bool run_server; @@ -31,21 +32,18 @@ ServerManager::ServerManager() int listen_port = atoi(server.config->GetVariable("options", "listen_port").c_str()); tcps = new EmuTCPServer(listen_port, true); - if(tcps->Open(listen_port, error_buffer)) - { - server_log->Log(log_network, "ServerManager listening on port %u", listen_port); + if(tcps->Open(listen_port, error_buffer)) { + Log.Out(Logs::General, Logs::Login_Server, "ServerManager listening on port %u", listen_port); } - else - { - server_log->Log(log_error, "ServerManager fatal error opening port on %u: %s", listen_port, error_buffer); + else { + Log.Out(Logs::General, Logs::Error, "ServerManager fatal error opening port on %u: %s", listen_port, error_buffer); run_server = false; } } ServerManager::~ServerManager() { - if(tcps) - { + if (tcps) { tcps->Close(); delete tcps; } @@ -55,38 +53,32 @@ void ServerManager::Process() { ProcessDisconnect(); EmuTCPConnection *tcp_c = nullptr; - while(tcp_c = tcps->NewQueuePop()) - { + while (tcp_c = tcps->NewQueuePop()) { in_addr tmp; tmp.s_addr = tcp_c->GetrIP(); - server_log->Log(log_network, "New world server connection from %s:%d", inet_ntoa(tmp), tcp_c->GetrPort()); + Log.Out(Logs::General, Logs::Login_Server, "New world server connection from %s:%d", inet_ntoa(tmp), tcp_c->GetrPort()); - WorldServer *cur = GetServerByAddress(tcp_c->GetrIP()); - if(cur) - { - server_log->Log(log_network, "World server already existed for %s, removing existing connection and updating current.", inet_ntoa(tmp)); - cur->GetConnection()->Free(); - cur->SetConnection(tcp_c); - cur->Reset(); + WorldServer *server_entity = GetServerByAddress(tcp_c->GetrIP()); + if (server_entity) { + Log.Out(Logs::General, Logs::Login_Server, "World server already existed for %s, removing existing connection and updating current.", inet_ntoa(tmp)); + server_entity->GetConnection()->Free(); + server_entity->SetConnection(tcp_c); + server_entity->Reset(); } - else - { + else { WorldServer *w = new WorldServer(tcp_c); world_servers.push_back(w); } } list::iterator iter = world_servers.begin(); - while(iter != world_servers.end()) - { - if((*iter)->Process() == false) - { - server_log->Log(log_world, "World server %s had a fatal error and had to be removed from the login.", (*iter)->GetLongName().c_str()); + while (iter != world_servers.end()) { + if ((*iter)->Process() == false) { + Log.Out(Logs::General, Logs::World_Server, "World server %s had a fatal error and had to be removed from the login.", (*iter)->GetLongName().c_str()); delete (*iter); iter = world_servers.erase(iter); } - else - { + else { ++iter; } } @@ -95,20 +87,17 @@ void ServerManager::Process() void ServerManager::ProcessDisconnect() { list::iterator iter = world_servers.begin(); - while(iter != world_servers.end()) - { - EmuTCPConnection *c = (*iter)->GetConnection(); - if(!c->Connected()) - { + while (iter != world_servers.end()) { + EmuTCPConnection *connection = (*iter)->GetConnection(); + if (!connection->Connected()) { in_addr tmp; - tmp.s_addr = c->GetrIP(); - server_log->Log(log_network, "World server disconnected from the server, removing server and freeing connection."); - c->Free(); + tmp.s_addr = connection->GetrIP(); + Log.Out(Logs::General, Logs::Login_Server, "World server disconnected from the server, removing server and freeing connection."); + connection->Free(); delete (*iter); iter = world_servers.erase(iter); } - else - { + else { ++iter; } } @@ -117,10 +106,8 @@ void ServerManager::ProcessDisconnect() WorldServer* ServerManager::GetServerByAddress(unsigned int address) { list::iterator iter = world_servers.begin(); - while(iter != world_servers.end()) - { - if((*iter)->GetConnection()->GetrIP() == address) - { + while (iter != world_servers.end()) { + if ((*iter)->GetConnection()->GetrIP() == address) { return (*iter); } ++iter; @@ -138,10 +125,8 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c) string client_ip = inet_ntoa(in); list::iterator iter = world_servers.begin(); - while(iter != world_servers.end()) - { - if((*iter)->IsAuthorized() == false) - { + while (iter != world_servers.end()) { + if ((*iter)->IsAuthorized() == false) { ++iter; continue; } @@ -149,16 +134,13 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c) in.s_addr = (*iter)->GetConnection()->GetrIP(); string world_ip = inet_ntoa(in); - if(world_ip.compare(client_ip) == 0) - { + if (world_ip.compare(client_ip) == 0) { packet_size += (*iter)->GetLongName().size() + (*iter)->GetLocalIP().size() + 24; } - else if(client_ip.find(server.options.GetLocalNetwork()) != string::npos) - { + else if (client_ip.find(server.options.GetLocalNetwork()) != string::npos) { packet_size += (*iter)->GetLongName().size() + (*iter)->GetLocalIP().size() + 24; } - else - { + else { packet_size += (*iter)->GetLongName().size() + (*iter)->GetRemoteIP().size() + 24; } @@ -167,98 +149,87 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c) } EQApplicationPacket *outapp = new EQApplicationPacket(OP_ServerListResponse, packet_size); - ServerListHeader_Struct *sl = (ServerListHeader_Struct*)outapp->pBuffer; - sl->Unknown1 = 0x00000004; - sl->Unknown2 = 0x00000000; - sl->Unknown3 = 0x01650000; - /** - * Not sure what this is but it should be noted setting it to - * 0xFFFFFFFF crashes the client so: don't do that. - */ - sl->Unknown4 = 0x00000000; - sl->NumberOfServers = server_count; + ServerListHeader_Struct *server_list = (ServerListHeader_Struct*)outapp->pBuffer; + server_list->Unknown1 = 0x00000004; + server_list->Unknown2 = 0x00000000; + server_list->Unknown3 = 0x01650000; - unsigned char *data_ptr = outapp->pBuffer; - data_ptr += sizeof(ServerListHeader_Struct); + /** + * Not sure what this is but it should be noted setting it to + * 0xFFFFFFFF crashes the client so: don't do that. + */ + server_list->Unknown4 = 0x00000000; + server_list->NumberOfServers = server_count; + + unsigned char *data_pointer = outapp->pBuffer; + data_pointer += sizeof(ServerListHeader_Struct); iter = world_servers.begin(); - while(iter != world_servers.end()) - { - if((*iter)->IsAuthorized() == false) - { + while (iter != world_servers.end()) { + if ((*iter)->IsAuthorized() == false) { ++iter; continue; } in.s_addr = (*iter)->GetConnection()->GetrIP(); string world_ip = inet_ntoa(in); - if(world_ip.compare(client_ip) == 0) - { - memcpy(data_ptr, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size()); - data_ptr += ((*iter)->GetLocalIP().size() + 1); + if (world_ip.compare(client_ip) == 0) { + memcpy(data_pointer, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size()); + data_pointer += ((*iter)->GetLocalIP().size() + 1); } - else if(client_ip.find(server.options.GetLocalNetwork()) != string::npos) - { - memcpy(data_ptr, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size()); - data_ptr += ((*iter)->GetLocalIP().size() + 1); + else if (client_ip.find(server.options.GetLocalNetwork()) != string::npos) { + memcpy(data_pointer, (*iter)->GetLocalIP().c_str(), (*iter)->GetLocalIP().size()); + data_pointer += ((*iter)->GetLocalIP().size() + 1); } - else - { - memcpy(data_ptr, (*iter)->GetRemoteIP().c_str(), (*iter)->GetRemoteIP().size()); - data_ptr += ((*iter)->GetRemoteIP().size() + 1); + else { + memcpy(data_pointer, (*iter)->GetRemoteIP().c_str(), (*iter)->GetRemoteIP().size()); + data_pointer += ((*iter)->GetRemoteIP().size() + 1); } - switch((*iter)->GetServerListID()) - { - case 1: - { - *(unsigned int*)data_ptr = 0x00000030; + switch ((*iter)->GetServerListID()) { + case 1: { + *(unsigned int*)data_pointer = 0x00000030; break; } - case 2: - { - *(unsigned int*)data_ptr = 0x00000009; + case 2: { + *(unsigned int*)data_pointer = 0x00000009; break; } - default: - { - *(unsigned int*)data_ptr = 0x00000001; + default: { + *(unsigned int*)data_pointer = 0x00000001; } } - data_ptr += 4; - *(unsigned int*)data_ptr = (*iter)->GetRuntimeID(); - data_ptr += 4; + data_pointer += 4; - memcpy(data_ptr, (*iter)->GetLongName().c_str(), (*iter)->GetLongName().size()); - data_ptr += ((*iter)->GetLongName().size() + 1); + *(unsigned int*)data_pointer = (*iter)->GetRuntimeID(); + data_pointer += 4; - memcpy(data_ptr, "EN", 2); - data_ptr += 3; + memcpy(data_pointer, (*iter)->GetLongName().c_str(), (*iter)->GetLongName().size()); + data_pointer += ((*iter)->GetLongName().size() + 1); - memcpy(data_ptr, "US", 2); - data_ptr += 3; + memcpy(data_pointer, "EN", 2); + data_pointer += 3; + + memcpy(data_pointer, "US", 2); + data_pointer += 3; // 0 = Up, 1 = Down, 2 = Up, 3 = down, 4 = locked, 5 = locked(down) - if((*iter)->GetStatus() < 0) - { - if((*iter)->GetZonesBooted() == 0) - { - *(uint32*)data_ptr = 0x01; + if ((*iter)->GetStatus() < 0) { + if ((*iter)->GetZonesBooted() == 0) { + *(uint32*)data_pointer = 0x01; } - else - { - *(uint32*)data_ptr = 0x04; + else { + *(uint32*)data_pointer = 0x04; } } - else - { - *(uint32*)data_ptr = 0x02; + else { + *(uint32*)data_pointer = 0x02; } - data_ptr += 4; + data_pointer += 4; - *(uint32*)data_ptr = (*iter)->GetPlayersOnline(); - data_ptr += 4; + *(uint32*)data_pointer = (*iter)->GetPlayersOnline(); + data_pointer += 4; ++iter; } @@ -270,10 +241,8 @@ void ServerManager::SendUserToWorldRequest(unsigned int server_id, unsigned int { list::iterator iter = world_servers.begin(); bool found = false; - while(iter != world_servers.end()) - { - if((*iter)->GetRuntimeID() == server_id) - { + while (iter != world_servers.end()) { + if ((*iter)->GetRuntimeID() == server_id) { ServerPacket *outapp = new ServerPacket(ServerOP_UsertoWorldReq, sizeof(UsertoWorldRequest_Struct)); UsertoWorldRequest_Struct *utwr = (UsertoWorldRequest_Struct*)outapp->pBuffer; utwr->worldid = server_id; @@ -281,8 +250,7 @@ void ServerManager::SendUserToWorldRequest(unsigned int server_id, unsigned int (*iter)->GetConnection()->SendPacket(outapp); found = true; - if(server.options.IsDumpInPacketsOn()) - { + if (server.options.IsDumpInPacketsOn()) { DumpPacket(outapp); } delete outapp; @@ -290,25 +258,21 @@ void ServerManager::SendUserToWorldRequest(unsigned int server_id, unsigned int ++iter; } - if(!found && server.options.IsTraceOn()) - { - server_log->Log(log_client_error, "Client requested a user to world but supplied an invalid id of %u.", server_id); + if (!found && server.options.IsTraceOn()) { + Log.Out(Logs::General, Logs::Error, "Client requested a user to world but supplied an invalid id of %u.", server_id); } } bool ServerManager::ServerExists(string l_name, string s_name, WorldServer *ignore) { list::iterator iter = world_servers.begin(); - while(iter != world_servers.end()) - { - if((*iter) == ignore) - { + while (iter != world_servers.end()) { + if ((*iter) == ignore) { ++iter; continue; } - if((*iter)->GetLongName().compare(l_name) == 0 && (*iter)->GetShortName().compare(s_name) == 0) - { + if ((*iter)->GetLongName().compare(l_name) == 0 && (*iter)->GetShortName().compare(s_name) == 0) { return true; } @@ -320,18 +284,14 @@ bool ServerManager::ServerExists(string l_name, string s_name, WorldServer *igno void ServerManager::DestroyServerByName(string l_name, string s_name, WorldServer *ignore) { list::iterator iter = world_servers.begin(); - while(iter != world_servers.end()) - { - if((*iter) == ignore) - { + while (iter != world_servers.end()) { + if ((*iter) == ignore) { ++iter; } - if((*iter)->GetLongName().compare(l_name) == 0 && (*iter)->GetShortName().compare(s_name) == 0) - { + if ((*iter)->GetLongName().compare(l_name) == 0 && (*iter)->GetShortName().compare(s_name) == 0) { EmuTCPConnection *c = (*iter)->GetConnection(); - if(c->Connected()) - { + if (c->Connected()) { c->Disconnect(); } c->Free(); @@ -341,5 +301,4 @@ void ServerManager::DestroyServerByName(string l_name, string s_name, WorldServe ++iter; } -} - +} \ No newline at end of file diff --git a/loginserver/world_server.cpp b/loginserver/world_server.cpp index c91f1b702..8e912e285 100644 --- a/loginserver/world_server.cpp +++ b/loginserver/world_server.cpp @@ -16,11 +16,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "world_server.h" -#include "error_log.h" #include "login_server.h" #include "login_structures.h" +#include "config.h" -extern ErrorLog *server_log; +#include "../common/eqemu_logsys.h" + +extern EQEmuLogSys Log; extern LoginServer server; WorldServer::WorldServer(EmuTCPConnection *c) @@ -28,19 +30,18 @@ WorldServer::WorldServer(EmuTCPConnection *c) connection = c; zones_booted = 0; players_online = 0; - status = 0; + server_status = 0; runtime_id = 0; server_list_id = 0; server_type = 0; - authorized = false; - trusted = false; - logged_in = false; + is_server_authorized = false; + is_server_trusted = false; + is_server_logged_in = false; } WorldServer::~WorldServer() { - if(connection) - { + if(connection) { connection->Free(); } } @@ -49,12 +50,12 @@ void WorldServer::Reset() { zones_booted = 0; players_online = 0; - status = 0; + server_status = 0; runtime_id; server_list_id = 0; server_type = 0; - authorized = false; - logged_in = false; + is_server_authorized = false; + is_server_logged_in = false; } bool WorldServer::Process() @@ -64,7 +65,7 @@ bool WorldServer::Process() { if(server.options.IsWorldTraceOn()) { - server_log->Log(log_network_trace, "Application packet received from server: 0x%.4X, (size %u)", app->opcode, app->size); + Log.Out(Logs::General, Logs::Netcode, "Application packet received from server: 0x%.4X, (size %u)", app->opcode, app->size); } if(server.options.IsDumpInPacketsOn()) @@ -78,14 +79,14 @@ bool WorldServer::Process() { if(app->size < sizeof(ServerNewLSInfo_Struct)) { - server_log->Log(log_network_error, "Received application packet from server that had opcode ServerOP_NewLSInfo, " + Log.Out(Logs::General, Logs::Error, "Received application packet from server that had opcode ServerOP_NewLSInfo, " "but was too small. Discarded to avoid buffer overrun."); break; } if(server.options.IsWorldTraceOn()) { - server_log->Log(log_network_trace, "New Login Info Recieved."); + Log.Out(Logs::General, Logs::Netcode, "New Login Info Recieved."); } ServerNewLSInfo_Struct *info = (ServerNewLSInfo_Struct*)app->pBuffer; @@ -96,14 +97,14 @@ bool WorldServer::Process() { if(app->size < sizeof(ServerLSStatus_Struct)) { - server_log->Log(log_network_error, "Recieved application packet from server that had opcode ServerOP_LSStatus, " + Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerOP_LSStatus, " "but was too small. Discarded to avoid buffer overrun."); break; } if(server.options.IsWorldTraceOn()) { - server_log->Log(log_network_trace, "World Server Status Recieved."); + Log.Out(Logs::General, Logs::Netcode, "World Server Status Recieved."); } ServerLSStatus_Struct *ls_status = (ServerLSStatus_Struct*)app->pBuffer; @@ -127,7 +128,7 @@ bool WorldServer::Process() { if(app->size < sizeof(UsertoWorldResponse_Struct)) { - server_log->Log(log_network_error, "Recieved application packet from server that had opcode ServerOP_UsertoWorldResp, " + Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerOP_UsertoWorldResp, " "but was too small. Discarded to avoid buffer overrun."); break; } @@ -137,21 +138,22 @@ bool WorldServer::Process() //While keeping world server spam with multiple servers connected almost impossible. if(server.options.IsTraceOn()) { - server_log->Log(log_network_trace, "User-To-World Response received."); + Log.Out(Logs::General, Logs::Netcode, "User-To-World Response received."); } UsertoWorldResponse_Struct *utwr = (UsertoWorldResponse_Struct*)app->pBuffer; - server_log->Log(log_client, "Trying to find client with user id of %u.", utwr->lsaccountid); - Client *c = server.CM->GetClient(utwr->lsaccountid); + Log.Out(Logs::General, Logs::Debug, "Trying to find client with user id of %u.", utwr->lsaccountid); + Client *c = server.client_manager->GetClient(utwr->lsaccountid); if(c) { - server_log->Log(log_client, "Found client with user id of %u and account name of %s.", utwr->lsaccountid, c->GetAccountName().c_str()); + Log.Out(Logs::General, Logs::Debug, "Found client with user id of %u and account name of %s.", utwr->lsaccountid, c->GetAccountName().c_str()); EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayEverquestResponse, sizeof(PlayEverquestResponse_Struct)); PlayEverquestResponse_Struct *per = (PlayEverquestResponse_Struct*)outapp->pBuffer; per->Sequence = c->GetPlaySequence(); per->ServerNumber = c->GetPlayServerID(); - server_log->Log(log_client, "Found sequence and play of %u %u", c->GetPlaySequence(), c->GetPlayServerID()); - server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size); + Log.Out(Logs::General, Logs::Debug, "Found sequence and play of %u %u", c->GetPlaySequence(), c->GetPlayServerID()); + + Log.Out(Logs::General, Logs::Netcode, "[Size: %u] %s", outapp->size, DumpPacketToString(outapp).c_str()); if(utwr->response > 0) { @@ -180,9 +182,9 @@ bool WorldServer::Process() if(server.options.IsTraceOn()) { - server_log->Log(log_network_trace, "Sending play response with following data, allowed %u, sequence %u, server number %u, message %u", + Log.Out(Logs::General, Logs::Netcode, "Sending play response with following data, allowed %u, sequence %u, server number %u, message %u", per->Allowed, per->Sequence, per->ServerNumber, per->Message); - server_log->LogPacket(log_network_trace, (const char*)outapp->pBuffer, outapp->size); + Log.Out(Logs::General, Logs::Netcode, "[Size: %u] %s", outapp->size, DumpPacketToString(outapp).c_str()); } if(server.options.IsDumpOutPacketsOn()) @@ -195,7 +197,7 @@ bool WorldServer::Process() } else { - server_log->Log(log_client_error, "Recieved User-To-World Response for %u but could not find the client referenced!.", utwr->lsaccountid); + Log.Out(Logs::General, Logs::Error, "Recieved User-To-World Response for %u but could not find the client referenced!.", utwr->lsaccountid); } break; } @@ -203,16 +205,16 @@ bool WorldServer::Process() { if(app->size < sizeof(ServerLSAccountUpdate_Struct)) { - server_log->Log(log_network_error, "Recieved application packet from server that had opcode ServerLSAccountUpdate_Struct, " + Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had opcode ServerLSAccountUpdate_Struct, " "but was too small. Discarded to avoid buffer overrun."); break; } - server_log->Log(log_network_trace, "ServerOP_LSAccountUpdate packet received from: %s", short_name.c_str()); + Log.Out(Logs::General, Logs::Netcode, "ServerOP_LSAccountUpdate packet received from: %s", short_name.c_str()); ServerLSAccountUpdate_Struct *lsau = (ServerLSAccountUpdate_Struct*)app->pBuffer; - if(trusted) + if(is_server_trusted) { - server_log->Log(log_network_trace, "ServerOP_LSAccountUpdate update processed for: %s", lsau->useraccount); + Log.Out(Logs::General, Logs::Netcode, "ServerOP_LSAccountUpdate update processed for: %s", lsau->useraccount); string name; string password; string email; @@ -225,7 +227,7 @@ bool WorldServer::Process() } default: { - server_log->Log(log_network_error, "Recieved application packet from server that had an unknown operation code 0x%.4X.", app->opcode); + Log.Out(Logs::General, Logs::Error, "Recieved application packet from server that had an unknown operation code 0x%.4X.", app->opcode); } } @@ -237,9 +239,9 @@ bool WorldServer::Process() void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) { - if(logged_in) + if(is_server_logged_in) { - server_log->Log(log_network_error, "WorldServer::Handle_NewLSInfo called but the login server was already marked as logged in, aborting."); + Log.Out(Logs::General, Logs::Error, "WorldServer::Handle_NewLSInfo called but the login server was already marked as logged in, aborting."); return; } @@ -249,7 +251,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) } else { - server_log->Log(log_network_error, "Handle_NewLSInfo error, account name was too long."); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, account name was too long."); return; } @@ -259,7 +261,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) } else { - server_log->Log(log_network_error, "Handle_NewLSInfo error, account password was too long."); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, account password was too long."); return; } @@ -269,7 +271,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) } else { - server_log->Log(log_network_error, "Handle_NewLSInfo error, long name was too long."); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, long name was too long."); return; } @@ -279,7 +281,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) } else { - server_log->Log(log_network_error, "Handle_NewLSInfo error, short name was too long."); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, short name was too long."); return; } @@ -287,7 +289,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) { if(strlen(i->local_address) == 0) { - server_log->Log(log_network_error, "Handle_NewLSInfo error, local address was null, defaulting to localhost"); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, local address was null, defaulting to localhost"); local_ip = "127.0.0.1"; } else @@ -297,7 +299,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) } else { - server_log->Log(log_network_error, "Handle_NewLSInfo error, local address was too long."); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, local address was too long."); return; } @@ -308,7 +310,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) in_addr in; in.s_addr = GetConnection()->GetrIP(); remote_ip = inet_ntoa(in); - server_log->Log(log_network_error, "Handle_NewLSInfo error, remote address was null, defaulting to stream address %s.", remote_ip.c_str()); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, remote address was null, defaulting to stream address %s.", remote_ip.c_str()); } else { @@ -320,7 +322,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) in_addr in; in.s_addr = GetConnection()->GetrIP(); remote_ip = inet_ntoa(in); - server_log->Log(log_network_error, "Handle_NewLSInfo error, remote address was too long, defaulting to stream address %s.", remote_ip.c_str()); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, remote address was too long, defaulting to stream address %s.", remote_ip.c_str()); } if(strlen(i->serverversion) <= 64) @@ -329,7 +331,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) } else { - server_log->Log(log_network_error, "Handle_NewLSInfo error, server version was too long."); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, server version was too long."); return; } @@ -339,27 +341,27 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) } else { - server_log->Log(log_network_error, "Handle_NewLSInfo error, protocol version was too long."); + Log.Out(Logs::General, Logs::Error, "Handle_NewLSInfo error, protocol version was too long."); return; } server_type = i->servertype; - logged_in = true; + is_server_logged_in = true; if(server.options.IsRejectingDuplicateServers()) { - if(server.SM->ServerExists(long_name, short_name, this)) + if(server.server_manager->ServerExists(long_name, short_name, this)) { - server_log->Log(log_world_error, "World tried to login but there already exists a server that has that name."); + Log.Out(Logs::General, Logs::Error, "World tried to login but there already exists a server that has that name."); return; } } else { - if(server.SM->ServerExists(long_name, short_name, this)) + if(server.server_manager->ServerExists(long_name, short_name, this)) { - server_log->Log(log_world_error, "World tried to login but there already exists a server that has that name."); - server.SM->DestroyServerByName(long_name, short_name, this); + Log.Out(Logs::General, Logs::Error, "World tried to login but there already exists a server that has that name."); + server.server_manager->DestroyServerByName(long_name, short_name, this); } } @@ -378,112 +380,112 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) { if(s_acct_name.size() == 0 || s_acct_pass.size() == 0) { - server_log->Log(log_world, "Server %s(%s) successfully logged into account that had no user/password requirement.", + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) successfully logged into account that had no user/password requirement.", long_name.c_str(), short_name.c_str()); - authorized = true; + is_server_authorized = true; SetRuntimeID(s_id); server_list_id = s_list_type; desc = s_desc; } else if(s_acct_name.compare(account_name) == 0 && s_acct_pass.compare(account_password) == 0) { - server_log->Log(log_world, "Server %s(%s) successfully logged in.", + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) successfully logged in.", long_name.c_str(), short_name.c_str()); - authorized = true; + is_server_authorized = true; SetRuntimeID(s_id); server_list_id = s_list_type; desc = s_desc; - if(s_trusted) - { - server_log->Log(log_network_trace, "ServerOP_LSAccountUpdate sent to world"); - trusted = true; + if(s_trusted) { + Log.Out(Logs::General, Logs::Netcode, "ServerOP_LSAccountUpdate sent to world"); + is_server_trusted = true; ServerPacket *outapp = new ServerPacket(ServerOP_LSAccountUpdate, 0); connection->SendPacket(outapp); } } - else - { - server_log->Log(log_world, "Server %s(%s) attempted to log in but account and password did not match the entry in the database, and only" + else { + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) attempted to log in but account and password did not match the entry in the database, and only" " registered servers are allowed.", long_name.c_str(), short_name.c_str()); return; } } - else - { - server_log->Log(log_world, "Server %s(%s) attempted to log in but database couldn't find an entry and only registered servers are allowed.", + else { + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) attempted to log in but database couldn't find an entry and only registered servers are allowed.", long_name.c_str(), short_name.c_str()); return; } } - else - { - server_log->Log(log_world, "Server %s(%s) did not attempt to log in but only registered servers are allowed.", + else { + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) did not attempt to log in but only registered servers are allowed.", long_name.c_str(), short_name.c_str()); return; } } - else - { - unsigned int s_id = 0; - unsigned int s_list_type = 0; - unsigned int s_trusted = 0; - string s_desc; - string s_list_desc; - string s_acct_name; - string s_acct_pass; - if(server.db->GetWorldRegistration(long_name, short_name, s_id, s_desc, s_list_type, s_trusted, s_list_desc, s_acct_name, s_acct_pass)) + else { + unsigned int server_id = 0; + unsigned int server_list_type = 0; + unsigned int is_server_trusted = 0; + string server_description; + string server_list_description; + string server_account_name; + string server_account_password; + + + if(server.db->GetWorldRegistration( + long_name, + short_name, + server_id, + server_description, + server_list_type, + is_server_trusted, + server_list_description, + server_account_name, + server_account_password)) { - if(account_name.size() > 0 && account_password.size() > 0) - { - if(s_acct_name.compare(account_name) == 0 && s_acct_pass.compare(account_password) == 0) - { - server_log->Log(log_world, "Server %s(%s) successfully logged in.", + + if(account_name.size() > 0 && account_password.size() > 0) { + if(server_account_name.compare(account_name) == 0 && server_account_password.compare(account_password) == 0) { + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) successfully logged in.", long_name.c_str(), short_name.c_str()); - authorized = true; - SetRuntimeID(s_id); - server_list_id = s_list_type; - desc = s_desc; - if(s_trusted) - { - server_log->Log(log_network_trace, "ServerOP_LSAccountUpdate sent to world"); - trusted = true; + is_server_authorized = true; + SetRuntimeID(server_id); + server_list_id = server_list_type; + desc = server_description; + + if(is_server_trusted) { + Log.Out(Logs::General, Logs::Netcode, "ServerOP_LSAccountUpdate sent to world"); + is_server_trusted = true; ServerPacket *outapp = new ServerPacket(ServerOP_LSAccountUpdate, 0); connection->SendPacket(outapp); } } - else - { + else { // this is the first of two cases where we should deny access even if unregistered is allowed - server_log->Log(log_world, "Server %s(%s) attempted to log in but account and password did not match the entry in the database.", + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) attempted to log in but account and password did not match the entry in the database.", long_name.c_str(), short_name.c_str()); } } - else - { - if(s_acct_name.size() > 0 || s_acct_pass.size() > 0) - { + else { + if(server_account_name.size() > 0 || server_account_password.size() > 0) { // this is the second of two cases where we should deny access even if unregistered is allowed - server_log->Log(log_world, "Server %s(%s) did not attempt to log in but this server requires a password.", + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) did not attempt to log in but this server requires a password.", long_name.c_str(), short_name.c_str()); } - else - { - server_log->Log(log_world, "Server %s(%s) did not attempt to log in but unregistered servers are allowed.", + else { + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) did not attempt to log in but unregistered servers are allowed.", long_name.c_str(), short_name.c_str()); - authorized = true; - SetRuntimeID(s_id); + is_server_authorized = true; + SetRuntimeID(server_id); server_list_id = 3; } } } else { - server_log->Log(log_world, "Server %s(%s) attempted to log in but database couldn't find an entry but unregistered servers are allowed.", + Log.Out(Logs::General, Logs::World_Server, "Server %s(%s) attempted to log in but database couldn't find an entry but unregistered servers are allowed.", long_name.c_str(), short_name.c_str()); - if(server.db->CreateWorldRegistration(long_name, short_name, s_id)) - { - authorized = true; - SetRuntimeID(s_id); + if(server.db->CreateWorldRegistration(long_name, short_name, server_id)) { + is_server_authorized = true; + SetRuntimeID(server_id); server_list_id = 3; } } @@ -493,9 +495,9 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) in.s_addr = connection->GetrIP(); server.db->UpdateWorldRegistration(GetRuntimeID(), long_name, string(inet_ntoa(in))); - if(authorized) + if(is_server_authorized) { - server.CM->UpdateServerList(); + server.client_manager->UpdateServerList(); } } @@ -503,43 +505,40 @@ void WorldServer::Handle_LSStatus(ServerLSStatus_Struct *s) { players_online = s->num_players; zones_booted = s->num_zones; - status = s->status; + server_status = s->status; } void WorldServer::SendClientAuth(unsigned int ip, string account, string key, unsigned int account_id) { - ServerPacket *outapp = new ServerPacket(ServerOP_LSClientAuth, sizeof(ServerLSClientAuth)); - ServerLSClientAuth* slsca = (ServerLSClientAuth*)outapp->pBuffer; + ServerPacket *outapp = new ServerPacket(ServerOP_LSClientAuth, sizeof(ClientAuth_Struct)); + ClientAuth_Struct* client_auth = (ClientAuth_Struct*)outapp->pBuffer; - slsca->lsaccount_id = account_id; - strncpy(slsca->name, account.c_str(), account.size() > 30 ? 30 : account.size()); - strncpy(slsca->key, key.c_str(), 10); - slsca->lsadmin = 0; - slsca->worldadmin = 0; - slsca->ip = ip; + client_auth->lsaccount_id = account_id; + strncpy(client_auth->name, account.c_str(), account.size() > 30 ? 30 : account.size()); + strncpy(client_auth->key, key.c_str(), 10); + client_auth->lsadmin = 0; + client_auth->worldadmin = 0; + client_auth->ip = ip; in_addr in; - in.s_addr = ip;connection->GetrIP(); + in.s_addr = ip; connection->GetrIP(); string client_address(inet_ntoa(in)); in.s_addr = connection->GetrIP(); string world_address(inet_ntoa(in)); - if(client_address.compare(world_address) == 0) - { - slsca->local = 1; + if (client_address.compare(world_address) == 0) { + client_auth->local = 1; } - else if(client_address.find(server.options.GetLocalNetwork()) != string::npos) - { - slsca->local = 1; + else if (client_address.find(server.options.GetLocalNetwork()) != string::npos) { + client_auth->local = 1; } - else - { - slsca->local = 0; + else { + client_auth->local = 0; } connection->SendPacket(outapp); - if(server.options.IsDumpInPacketsOn()) + if (server.options.IsDumpInPacketsOn()) { DumpPacket(outapp); } diff --git a/loginserver/world_server.h b/loginserver/world_server.h index 0d8ed4251..b9a64ffe5 100644 --- a/loginserver/world_server.h +++ b/loginserver/world_server.h @@ -86,7 +86,7 @@ public: /** * Gets whether the server is authorized to show up on the server list or not. */ - bool IsAuthorized() const { return authorized; } + bool IsAuthorized() const { return is_server_authorized; } /** * Gets the local ip of the server. @@ -106,7 +106,7 @@ public: /** * Gets the status of the server. */ - int GetStatus() const { return status; } + int GetStatus() const { return server_status; } /** * Gets the number of zones online on the server. @@ -138,7 +138,7 @@ private: EmuTCPConnection *connection; unsigned int zones_booted; unsigned int players_online; - int status; + int server_status; unsigned int runtime_id; unsigned int server_list_id; unsigned int server_type; @@ -151,9 +151,9 @@ private: std::string local_ip; std::string protocol; std::string version; - bool authorized; - bool logged_in; - bool trusted; + bool is_server_authorized; + bool is_server_logged_in; + bool is_server_trusted; }; #endif diff --git a/queryserv/database.cpp b/queryserv/database.cpp index ea5bdff65..6216e112d 100644 --- a/queryserv/database.cpp +++ b/queryserv/database.cpp @@ -100,9 +100,9 @@ Database::~Database() void Database::AddSpeech(const char* from, const char* to, const char* message, uint16 minstatus, uint32 guilddbid, uint8 type) { - char *escapedFrom = new char[strlen(from) * 2 + 1]; - char *escapedTo = new char[strlen(to) * 2 + 1]; - char *escapedMessage = new char[strlen(message) * 2 + 1]; + auto escapedFrom = new char[strlen(from) * 2 + 1]; + auto escapedTo = new char[strlen(to) * 2 + 1]; + auto escapedMessage = new char[strlen(message) * 2 + 1]; DoEscapeString(escapedFrom, from, strlen(from)); DoEscapeString(escapedTo, to, strlen(to)); DoEscapeString(escapedMessage, message, strlen(message)); @@ -350,7 +350,7 @@ void Database::GeneralQueryReceive(ServerPacket *pack) { /* These are general queries passed from anywhere in zone instead of packing structures and breaking them down again and again */ - char *queryBuffer = new char[pack->ReadUInt32() + 1]; + auto queryBuffer = new char[pack->ReadUInt32() + 1]; pack->ReadString(queryBuffer); std::string query(queryBuffer); @@ -361,7 +361,7 @@ void Database::GeneralQueryReceive(ServerPacket *pack) { } safe_delete(pack); - safe_delete(queryBuffer); + safe_delete_array(queryBuffer); } void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings){ @@ -404,4 +404,4 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings){ Log.file_logs_enabled = true; } } -} \ No newline at end of file +} diff --git a/queryserv/lfguild.cpp b/queryserv/lfguild.cpp index 340321f06..ff7271832 100644 --- a/queryserv/lfguild.cpp +++ b/queryserv/lfguild.cpp @@ -168,7 +168,7 @@ void LFGuildManager::SendPlayerMatches(uint32 FromZoneID, uint32 FromInstanceID, } - ServerPacket *pack = new ServerPacket(ServerOP_QueryServGeneric, PacketSize); + auto pack = new ServerPacket(ServerOP_QueryServGeneric, PacketSize); pack->WriteUInt32(FromZoneID); pack->WriteUInt32(FromInstanceID); @@ -211,7 +211,7 @@ void LFGuildManager::SendGuildMatches(uint32 FromZoneID, uint32 FromInstanceID, } - ServerPacket *pack = new ServerPacket(ServerOP_QueryServGeneric, PacketSize); + auto pack = new ServerPacket(ServerOP_QueryServGeneric, PacketSize); pack->WriteUInt32(FromZoneID); pack->WriteUInt32(FromInstanceID); @@ -255,7 +255,7 @@ void LFGuildManager::TogglePlayer(uint32 FromZoneID, uint32 FromInstanceID, char auto results = database.QueryDatabase(query); } - ServerPacket *pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(From) + strlen(Comments) + 30); + auto pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(From) + strlen(Comments) + 30); pack->WriteUInt32(FromZoneID); pack->WriteUInt32(FromInstanceID); @@ -300,7 +300,7 @@ void LFGuildManager::ToggleGuild(uint32 FromZoneID, uint32 FromInstanceID, char } - ServerPacket *pack = new ServerPacket(ServerOP_LFGuildUpdate, strlen(GuildName) + strlen(Comments) + 30); + auto pack = new ServerPacket(ServerOP_LFGuildUpdate, strlen(GuildName) + strlen(Comments) + 30); pack->WriteString(GuildName); pack->WriteString(Comments); @@ -352,7 +352,8 @@ void LFGuildManager::SendPlayerStatus(uint32 FromZoneID, uint32 FromInstanceID, { if(!strcasecmp((*it).Name.c_str(), From)) { - ServerPacket *pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(From) + (*it).Comments.length() + 30); + auto pack = + new ServerPacket(ServerOP_QueryServGeneric, strlen(From) + (*it).Comments.length() + 30); pack->WriteUInt32(FromZoneID); pack->WriteUInt32(FromInstanceID); @@ -379,7 +380,8 @@ void LFGuildManager::SendGuildStatus(uint32 FromZoneID, uint32 FromInstanceID, c { if(!strcasecmp((*it).Name.c_str(), GuildName)) { - ServerPacket *pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(From) + (*it).Comments.length() + 42); + auto pack = + new ServerPacket(ServerOP_QueryServGeneric, strlen(From) + (*it).Comments.length() + 42); pack->WriteUInt32(FromZoneID); pack->WriteUInt32(FromInstanceID); diff --git a/shared_memory/base_data.cpp b/shared_memory/base_data.cpp index 086256cda..557d13ce5 100644 --- a/shared_memory/base_data.cpp +++ b/shared_memory/base_data.cpp @@ -23,7 +23,7 @@ #include "../common/memory_mapped_file.h" #include "../common/eqemu_exception.h" -void LoadBaseData(SharedDatabase *database) { +void LoadBaseData(SharedDatabase *database, const std::string &prefix) { EQEmu::IPCMutex mutex("base_data"); mutex.Lock(); int records = (database->GetMaxBaseDataLevel() + 1); @@ -32,11 +32,13 @@ void LoadBaseData(SharedDatabase *database) { } uint32 size = records * 16 * sizeof(BaseDataStruct); - EQEmu::MemoryMappedFile mmf("shared/base_data", size); + + auto Config = EQEmuConfig::get(); + std::string file_name = Config->SharedMemDir + prefix + std::string("base_data"); + EQEmu::MemoryMappedFile mmf(file_name, size); mmf.ZeroFile(); void *ptr = mmf.Get(); database->LoadBaseData(ptr, records); mutex.Unlock(); } - diff --git a/shared_memory/base_data.h b/shared_memory/base_data.h index c1f6c87ea..81cd8dd1b 100644 --- a/shared_memory/base_data.h +++ b/shared_memory/base_data.h @@ -19,7 +19,10 @@ #ifndef __EQEMU_SHARED_MEMORY_BASE_DATA_H #define __EQEMU_SHARED_MEMORY_BASE_DATA_H +#include +#include "../common/eqemu_config.h" + class SharedDatabase; -void LoadBaseData(SharedDatabase *database); +void LoadBaseData(SharedDatabase *database, const std::string &prefix); #endif diff --git a/shared_memory/items.cpp b/shared_memory/items.cpp index 48b81b6fc..e4c938af2 100644 --- a/shared_memory/items.cpp +++ b/shared_memory/items.cpp @@ -22,9 +22,9 @@ #include "../common/ipc_mutex.h" #include "../common/memory_mapped_file.h" #include "../common/eqemu_exception.h" -#include "../common/item_struct.h" +#include "../common/item_base.h" -void LoadItems(SharedDatabase *database) { +void LoadItems(SharedDatabase *database, const std::string &prefix) { EQEmu::IPCMutex mutex("items"); mutex.Lock(); @@ -35,8 +35,11 @@ void LoadItems(SharedDatabase *database) { EQ_EXCEPT("Shared Memory", "Unable to get any items from the database."); } - uint32 size = static_cast(EQEmu::FixedMemoryHashSet::estimated_size(items, max_item)); - EQEmu::MemoryMappedFile mmf("shared/items", size); + uint32 size = static_cast(EQEmu::FixedMemoryHashSet::estimated_size(items, max_item)); + + auto Config = EQEmuConfig::get(); + std::string file_name = Config->SharedMemDir + prefix + std::string("items"); + EQEmu::MemoryMappedFile mmf(file_name, size); mmf.ZeroFile(); void *ptr = mmf.Get(); diff --git a/shared_memory/items.h b/shared_memory/items.h index 21702eb50..47dcbaac9 100644 --- a/shared_memory/items.h +++ b/shared_memory/items.h @@ -19,7 +19,10 @@ #ifndef __EQEMU_SHARED_MEMORY_ITEMS_H #define __EQEMU_SHARED_MEMORY_ITEMS_H +#include +#include "../common/eqemu_config.h" + class SharedDatabase; -void LoadItems(SharedDatabase *database); +void LoadItems(SharedDatabase *database, const std::string &prefix); #endif diff --git a/shared_memory/loot.cpp b/shared_memory/loot.cpp index 66982c05a..742f373bf 100644 --- a/shared_memory/loot.cpp +++ b/shared_memory/loot.cpp @@ -25,7 +25,7 @@ #include "../common/fixed_memory_variable_hash_set.h" #include "../common/loottable.h" -void LoadLoot(SharedDatabase *database) { +void LoadLoot(SharedDatabase *database, const std::string &prefix) { EQEmu::IPCMutex mutex("loot"); mutex.Lock(); @@ -44,8 +44,12 @@ void LoadLoot(SharedDatabase *database) { (loot_drop_count * sizeof(LootDrop_Struct)) + //loot table headers (loot_drop_entries_count * sizeof(LootDropEntries_Struct)); //number of loot table entries - EQEmu::MemoryMappedFile mmf_loot_table("shared/loot_table", loot_table_size); - EQEmu::MemoryMappedFile mmf_loot_drop("shared/loot_drop", loot_drop_size); + auto Config = EQEmuConfig::get(); + std::string file_name_lt = Config->SharedMemDir + prefix + std::string("loot_table"); + std::string file_name_ld = Config->SharedMemDir + prefix + std::string("loot_drop"); + + EQEmu::MemoryMappedFile mmf_loot_table(file_name_lt, loot_table_size); + EQEmu::MemoryMappedFile mmf_loot_drop(file_name_ld, loot_drop_size); mmf_loot_table.ZeroFile(); mmf_loot_drop.ZeroFile(); diff --git a/shared_memory/loot.h b/shared_memory/loot.h index df97ad321..694bba7ca 100644 --- a/shared_memory/loot.h +++ b/shared_memory/loot.h @@ -19,7 +19,10 @@ #ifndef __EQEMU_SHARED_MEMORY_LOOT_H #define __EQEMU_SHARED_MEMORY_LOOT_H +#include +#include "../common/eqemu_config.h" + class SharedDatabase; -void LoadLoot(SharedDatabase *database); +void LoadLoot(SharedDatabase *database, const std::string &prefix); #endif diff --git a/shared_memory/main.cpp b/shared_memory/main.cpp index 2623ccd26..79824251f 100644 --- a/shared_memory/main.cpp +++ b/shared_memory/main.cpp @@ -26,6 +26,7 @@ #include "../common/crash.h" #include "../common/rulesys.h" #include "../common/eqemu_exception.h" +#include "../common/string_util.h" #include "items.h" #include "npc_faction.h" #include "loot.h" @@ -46,12 +47,12 @@ int main(int argc, char **argv) { return 1; } - const EQEmuConfig *config = EQEmuConfig::get(); + auto Config = EQEmuConfig::get(); SharedDatabase database; Log.Out(Logs::General, Logs::Status, "Connecting to database..."); - if(!database.Connect(config->DatabaseHost.c_str(), config->DatabaseUsername.c_str(), - config->DatabasePassword.c_str(), config->DatabaseDB.c_str(), config->DatabasePort)) { + if(!database.Connect(Config->DatabaseHost.c_str(), Config->DatabaseUsername.c_str(), + Config->DatabasePassword.c_str(), Config->DatabaseDB.c_str(), Config->DatabasePort)) { Log.Out(Logs::General, Logs::Error, "Unable to connect to the database, cannot continue without a " "database connection"); return 1; @@ -61,6 +62,19 @@ int main(int argc, char **argv) { database.LoadLogSettings(Log.log_settings); Log.StartFileLogs(); + database.LoadVariables(); + + /* If we're running shared memory and hotfix has no custom name, we probably want to start from scratch... */ + std::string db_hotfix_name; + if (database.GetVariable("hotfix_name", db_hotfix_name)) { + if (!db_hotfix_name.empty() && strcasecmp("hotfix_", db_hotfix_name.c_str()) == 0) { + Log.Out(Logs::General, Logs::Status, "Current hotfix in variables is the default %s, clearing out variable", db_hotfix_name.c_str()); + std::string query = StringFormat("UPDATE `variables` SET `value`='' WHERE (`varname`='hotfix_name')"); + database.QueryDatabase(query); + } + } + + std::string hotfix_name = ""; bool load_all = true; bool load_items = false; bool load_factions = false; @@ -69,112 +83,125 @@ int main(int argc, char **argv) { bool load_spells = false; bool load_bd = false; if(argc > 1) { - load_all = false; - for(int i = 1; i < argc; ++i) { - switch(argv[i][0]) { - case 'a': - if(strcasecmp("all", argv[i]) == 0) { - load_all = true; - } - break; - + switch(argv[i][0]) { case 'b': if(strcasecmp("base_data", argv[i]) == 0) { load_bd = true; + load_all = false; } break; - + case 'i': if(strcasecmp("items", argv[i]) == 0) { load_items = true; + load_all = false; } break; - + case 'f': if(strcasecmp("factions", argv[i]) == 0) { load_factions = true; + load_all = false; } break; - + case 'l': if(strcasecmp("loot", argv[i]) == 0) { load_loot = true; + load_all = false; } break; - + case 's': if(strcasecmp("skill_caps", argv[i]) == 0) { load_skill_caps = true; + load_all = false; } else if(strcasecmp("spells", argv[i]) == 0) { load_spells = true; + load_all = false; } break; + case '-': { + auto split = SplitString(argv[i], '='); + if(split.size() >= 2) { + auto command = split[0]; + auto argument = split[1]; + if(strcasecmp("-hotfix", command.c_str()) == 0) { + hotfix_name = argument; + load_all = true; + } + } + break; + } } } } + if(hotfix_name.length() > 0) { + Log.Out(Logs::General, Logs::Status, "Writing data for hotfix '%s'", hotfix_name.c_str()); + } + if(load_all || load_items) { Log.Out(Logs::General, Logs::Status, "Loading items..."); try { - LoadItems(&database); + LoadItems(&database, hotfix_name); } catch(std::exception &ex) { Log.Out(Logs::General, Logs::Error, "%s", ex.what()); return 1; } } - + if(load_all || load_factions) { Log.Out(Logs::General, Logs::Status, "Loading factions..."); try { - LoadFactions(&database); + LoadFactions(&database, hotfix_name); } catch(std::exception &ex) { Log.Out(Logs::General, Logs::Error, "%s", ex.what()); return 1; } } - + if(load_all || load_loot) { Log.Out(Logs::General, Logs::Status, "Loading loot..."); try { - LoadLoot(&database); + LoadLoot(&database, hotfix_name); } catch(std::exception &ex) { Log.Out(Logs::General, Logs::Error, "%s", ex.what()); return 1; } } - + if(load_all || load_skill_caps) { Log.Out(Logs::General, Logs::Status, "Loading skill caps..."); try { - LoadSkillCaps(&database); + LoadSkillCaps(&database, hotfix_name); } catch(std::exception &ex) { Log.Out(Logs::General, Logs::Error, "%s", ex.what()); return 1; } } - + if(load_all || load_spells) { Log.Out(Logs::General, Logs::Status, "Loading spells..."); try { - LoadSpells(&database); + LoadSpells(&database, hotfix_name); } catch(std::exception &ex) { Log.Out(Logs::General, Logs::Error, "%s", ex.what()); return 1; } } - + if(load_all || load_bd) { Log.Out(Logs::General, Logs::Status, "Loading base data..."); try { - LoadBaseData(&database); + LoadBaseData(&database, hotfix_name); } catch(std::exception &ex) { Log.Out(Logs::General, Logs::Error, "%s", ex.what()); return 1; } } - + Log.CloseFileLogs(); - return 0; } diff --git a/shared_memory/npc_faction.cpp b/shared_memory/npc_faction.cpp index ebaeb3457..2c6ab0098 100644 --- a/shared_memory/npc_faction.cpp +++ b/shared_memory/npc_faction.cpp @@ -24,7 +24,7 @@ #include "../common/eqemu_exception.h" #include "../common/faction.h" -void LoadFactions(SharedDatabase *database) { +void LoadFactions(SharedDatabase *database, const std::string &prefix) { EQEmu::IPCMutex mutex("faction"); mutex.Lock(); @@ -33,7 +33,10 @@ void LoadFactions(SharedDatabase *database) { database->GetFactionListInfo(lists, max_list); uint32 size = static_cast(EQEmu::FixedMemoryHashSet::estimated_size(lists, max_list)); - EQEmu::MemoryMappedFile mmf("shared/faction", size); + + auto Config = EQEmuConfig::get(); + std::string file_name = Config->SharedMemDir + prefix + std::string("faction"); + EQEmu::MemoryMappedFile mmf(file_name, size); mmf.ZeroFile(); void *ptr = mmf.Get(); diff --git a/shared_memory/npc_faction.h b/shared_memory/npc_faction.h index 52038dd9b..0b8a047f0 100644 --- a/shared_memory/npc_faction.h +++ b/shared_memory/npc_faction.h @@ -19,7 +19,10 @@ #ifndef __EQEMU_SHARED_MEMORY_NPC_FACTION_H #define __EQEMU_SHARED_MEMORY_NPC_FACTION_H +#include +#include "../common/eqemu_config.h" + class SharedDatabase; -void LoadFactions(SharedDatabase *database); +void LoadFactions(SharedDatabase *database, const std::string &prefix); #endif diff --git a/shared_memory/skill_caps.cpp b/shared_memory/skill_caps.cpp index 94205ce72..758ce6955 100644 --- a/shared_memory/skill_caps.cpp +++ b/shared_memory/skill_caps.cpp @@ -25,15 +25,18 @@ #include "../common/classes.h" #include "../common/features.h" -void LoadSkillCaps(SharedDatabase *database) { +void LoadSkillCaps(SharedDatabase *database, const std::string &prefix) { EQEmu::IPCMutex mutex("skill_caps"); mutex.Lock(); uint32 class_count = PLAYER_CLASS_COUNT; - uint32 skill_count = HIGHEST_SKILL + 1; + uint32 skill_count = EQEmu::skills::HIGHEST_SKILL + 1; uint32 level_count = HARD_LEVEL_CAP + 1; uint32 size = (class_count * skill_count * level_count * sizeof(uint16)); - EQEmu::MemoryMappedFile mmf("shared/skill_caps", size); + + auto Config = EQEmuConfig::get(); + std::string file_name = Config->SharedMemDir + prefix + std::string("skill_caps"); + EQEmu::MemoryMappedFile mmf(file_name, size); mmf.ZeroFile(); void *ptr = mmf.Get(); diff --git a/shared_memory/skill_caps.h b/shared_memory/skill_caps.h index e01dab4f4..da2cebc51 100644 --- a/shared_memory/skill_caps.h +++ b/shared_memory/skill_caps.h @@ -19,8 +19,11 @@ #ifndef __EQEMU_SHARED_MEMORY_SKILL_CAPS_H #define __EQEMU_SHARED_MEMORY_SKILL_CAPS_H +#include +#include "../common/eqemu_config.h" + class SharedDatabase; -void LoadSkillCaps(SharedDatabase *database); +void LoadSkillCaps(SharedDatabase *database, const std::string &prefix); #endif diff --git a/shared_memory/spells.cpp b/shared_memory/spells.cpp index 444f3b466..c653e26f5 100644 --- a/shared_memory/spells.cpp +++ b/shared_memory/spells.cpp @@ -24,7 +24,7 @@ #include "../common/eqemu_exception.h" #include "../common/spdat.h" -void LoadSpells(SharedDatabase *database) { +void LoadSpells(SharedDatabase *database, const std::string &prefix) { EQEmu::IPCMutex mutex("spells"); mutex.Lock(); int records = database->GetMaxSpellID() + 1; @@ -32,8 +32,11 @@ void LoadSpells(SharedDatabase *database) { EQ_EXCEPT("Shared Memory", "Unable to get any spells from the database."); } - uint32 size = records * sizeof(SPDat_Spell_Struct); - EQEmu::MemoryMappedFile mmf("shared/spells", size); + uint32 size = records * sizeof(SPDat_Spell_Struct) + sizeof(uint32); + + auto Config = EQEmuConfig::get(); + std::string file_name = Config->SharedMemDir + prefix + std::string("spells"); + EQEmu::MemoryMappedFile mmf(file_name, size); mmf.ZeroFile(); void *ptr = mmf.Get(); diff --git a/shared_memory/spells.h b/shared_memory/spells.h index 590ee0536..bdda1eac4 100644 --- a/shared_memory/spells.h +++ b/shared_memory/spells.h @@ -19,7 +19,10 @@ #ifndef __EQEMU_SHARED_MEMORY_SPELLS_H #define __EQEMU_SHARED_MEMORY_SPELLS_H +#include +#include "../common/eqemu_config.h" + class SharedDatabase; -void LoadSpells(SharedDatabase *database); +void LoadSpells(SharedDatabase *database, const std::string &prefix); #endif diff --git a/tests/fixed_memory_test.h b/tests/fixed_memory_test.h index fcff0c9e8..06b529f3c 100644 --- a/tests/fixed_memory_test.h +++ b/tests/fixed_memory_test.h @@ -27,7 +27,7 @@ class FixedMemoryHashTest : public Test::Suite { typedef void(FixedMemoryHashTest::*TestFunction)(void); public: FixedMemoryHashTest() { - size_ = EQEmu::FixedMemoryHashSet::estimated_size(72000, 190000); + size_ = EQEmu::FixedMemoryHashSet::estimated_size(72000, 190000); data_ = new uint8[size_]; memset(data_, 0, size_); TEST_ADD(FixedMemoryHashTest::InitTest); @@ -49,7 +49,7 @@ public: private: void InitTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_, 72000, 190000); + EQEmu::FixedMemoryHashSet hash(data_, size_, 72000, 190000); TEST_ASSERT(!hash.exists(1001)); TEST_ASSERT(hash.size() == 0); TEST_ASSERT(hash.max_size() == 72000); @@ -57,7 +57,7 @@ public: } void LoadTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::FixedMemoryHashSet hash(data_, size_); TEST_ASSERT(!hash.exists(1001)); TEST_ASSERT(hash.size() == 0); TEST_ASSERT(hash.max_size() == 72000); @@ -65,8 +65,8 @@ public: } void InsertTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); - Item_Struct item; + EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::ItemBase item; memset(&item, 0, sizeof(item)); strcpy(item.Name, "Iron Sword"); item.ID = 1001; @@ -79,20 +79,20 @@ public: } void RetrieveTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::FixedMemoryHashSet hash(data_, size_); TEST_ASSERT(hash.exists(1001)); TEST_ASSERT(hash.size() == 1); TEST_ASSERT(hash.max_size() == 72000); TEST_ASSERT(!hash.empty()); - Item_Struct item = hash[1001]; + EQEmu::ItemBase item = hash[1001]; TEST_ASSERT(strcmp(item.Name, "Iron Sword") == 0); TEST_ASSERT(item.ID == 1001); } void OverwriteTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); - Item_Struct item; + EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::ItemBase item; memset(&item, 0, sizeof(item)); strcpy(item.Name, "Steel Sword"); item.ID = 1001; @@ -105,20 +105,20 @@ public: } void OverwriteRetrieveTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::FixedMemoryHashSet hash(data_, size_); TEST_ASSERT(hash.exists(1001)); TEST_ASSERT(hash.size() == 1); TEST_ASSERT((hash.max_size() == 72000)); TEST_ASSERT(!hash.empty()); - Item_Struct item = hash[1001]; + EQEmu::ItemBase item = hash[1001]; TEST_ASSERT(strcmp(item.Name, "Steel Sword") == 0); TEST_ASSERT(item.ID == 1001); } void InsertAgainTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); - Item_Struct item; + EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::ItemBase item; memset(&item, 0, sizeof(item)); strcpy(item.Name, "Iron Sword"); item.ID = 1000; @@ -132,14 +132,14 @@ public: } void RetrieveAgainTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::FixedMemoryHashSet hash(data_, size_); TEST_ASSERT(hash.exists(1000)); TEST_ASSERT(hash.exists(1001)); TEST_ASSERT(hash.size() == 2); TEST_ASSERT(hash.max_size() == 72000); TEST_ASSERT(!hash.empty()); - Item_Struct item = hash[1000]; + EQEmu::ItemBase item = hash[1000]; TEST_ASSERT(strcmp(item.Name, "Iron Sword") == 0); TEST_ASSERT(item.ID == 1000); @@ -149,8 +149,8 @@ public: } void InsertBeginTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); - Item_Struct item; + EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::ItemBase item; memset(&item, 0, sizeof(item)); strcpy(item.Name, "Bronze Sword"); item.ID = 0; @@ -165,7 +165,7 @@ public: } void RetrieveBeginTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::FixedMemoryHashSet hash(data_, size_); TEST_ASSERT(hash.exists(1000)); TEST_ASSERT(hash.exists(1001)); TEST_ASSERT(hash.exists(0)); @@ -173,7 +173,7 @@ public: TEST_ASSERT(hash.max_size() == 72000); TEST_ASSERT(!hash.empty()); - Item_Struct item = hash[1000]; + EQEmu::ItemBase item = hash[1000]; TEST_ASSERT(strcmp(item.Name, "Iron Sword") == 0); TEST_ASSERT(item.ID == 1000); @@ -187,8 +187,8 @@ public: } void InsertEndTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); - Item_Struct item; + EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::ItemBase item; memset(&item, 0, sizeof(item)); strcpy(item.Name, "Jade Sword"); item.ID = 190000; @@ -204,7 +204,7 @@ public: } void RetrieveEndTest() { - EQEmu::FixedMemoryHashSet hash(data_, size_); + EQEmu::FixedMemoryHashSet hash(data_, size_); TEST_ASSERT(hash.exists(1000)); TEST_ASSERT(hash.exists(1001)); TEST_ASSERT(hash.exists(0)); @@ -213,7 +213,7 @@ public: TEST_ASSERT(hash.max_size() == 72000); TEST_ASSERT(!hash.empty()); - Item_Struct item = hash[1000]; + EQEmu::ItemBase item = hash[1000]; TEST_ASSERT(strcmp(item.Name, "Iron Sword") == 0); TEST_ASSERT(item.ID == 1000); diff --git a/tests/ipc_mutex_test.h b/tests/ipc_mutex_test.h index 69c70ca93..d465f869c 100644 --- a/tests/ipc_mutex_test.h +++ b/tests/ipc_mutex_test.h @@ -21,6 +21,9 @@ #include "cppunit/cpptest.h" #include "../common/ipc_mutex.h" +#include "../common/eqemu_config.h" + +extern const EQEmuConfig *Config; class IPCMutexTest : public Test::Suite { typedef void(IPCMutexTest::*TestFunction)(void); diff --git a/tests/main.cpp b/tests/main.cpp index d64dfead4..9d72da520 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -29,8 +29,13 @@ #include "string_util_test.h" #include "data_verification_test.h" #include "skills_util_test.h" +#include "../common/eqemu_config.h" + +const EQEmuConfig *Config; int main() { + auto ConfigLoadResult = EQEmuConfig::LoadConfig(); + Config = EQEmuConfig::get(); try { std::ofstream outfile("test_output.txt"); std::unique_ptr output(new Test::TextOutput(Test::TextOutput::Verbose, outfile)); diff --git a/tests/skills_util_test.h b/tests/skills_util_test.h index 96507256e..478de4206 100644 --- a/tests/skills_util_test.h +++ b/tests/skills_util_test.h @@ -35,13 +35,13 @@ public: private: void IsTradeskill() { - TEST_ASSERT(EQEmu::IsTradeskill(SkillPottery)); - TEST_ASSERT(!EQEmu::IsTradeskill(SkillParry)); + TEST_ASSERT(EQEmu::skills::IsTradeskill(EQEmu::skills::SkillPottery)); + TEST_ASSERT(!EQEmu::skills::IsTradeskill(EQEmu::skills::SkillParry)); } void IsSpecializedSkill() { - TEST_ASSERT(EQEmu::IsSpecializedSkill(SkillSpecializeConjuration)); - TEST_ASSERT(!EQEmu::IsSpecializedSkill(SkillConjuration)) + TEST_ASSERT(EQEmu::skills::IsSpecializedSkill(EQEmu::skills::SkillSpecializeConjuration)); + TEST_ASSERT(!EQEmu::skills::IsSpecializedSkill(EQEmu::skills::SkillConjuration)) } }; diff --git a/ucs/chatchannel.cpp b/ucs/chatchannel.cpp index 890d3d908..9ab9db216 100644 --- a/ucs/chatchannel.cpp +++ b/ucs/chatchannel.cpp @@ -23,6 +23,7 @@ #include "clientlist.h" #include "database.h" #include +#include extern Database database; extern uint32 ChatMessagesSent; @@ -307,17 +308,15 @@ bool ChatChannel::RemoveClient(Client *c) { return true; } -void ChatChannel::SendOPList(Client *c) { - - if(!c) return; +void ChatChannel::SendOPList(Client *c) +{ + if (!c) + return; c->GeneralChannelMessage("Channel " + Name + " op-list: (Owner=" + Owner + ")"); - std::list::iterator Iterator; - - for(Iterator = Moderators.begin(); Iterator != Moderators.end(); ++Iterator) - c->GeneralChannelMessage((*Iterator)); - + for (auto &&m : Moderators) + c->GeneralChannelMessage(m); } void ChatChannel::SendChannelMembers(Client *c) { @@ -566,10 +565,9 @@ void ChatChannelList::Process() { } } -void ChatChannel::AddInvitee(std::string Invitee) { - - if(!IsInvitee(Invitee)) { - +void ChatChannel::AddInvitee(const std::string &Invitee) +{ + if (!IsInvitee(Invitee)) { Invitees.push_back(Invitee); Log.Out(Logs::Detail, Logs::UCS_Server, "Added %s as invitee to channel %s", Invitee.c_str(), Name.c_str()); @@ -577,40 +575,24 @@ void ChatChannel::AddInvitee(std::string Invitee) { } -void ChatChannel::RemoveInvitee(std::string Invitee) { +void ChatChannel::RemoveInvitee(std::string Invitee) +{ + auto it = std::find(std::begin(Invitees), std::end(Invitees), Invitee); - std::list::iterator Iterator; - - for(Iterator = Invitees.begin(); Iterator != Invitees.end(); ++Iterator) { - - if((*Iterator) == Invitee) { - - Invitees.erase(Iterator); - - Log.Out(Logs::Detail, Logs::UCS_Server, "Removed %s as invitee to channel %s", Invitee.c_str(), Name.c_str()); - - return; - } + if(it != std::end(Invitees)) { + Invitees.erase(it); + Log.Out(Logs::Detail, Logs::UCS_Server, "Removed %s as invitee to channel %s", Invitee.c_str(), Name.c_str()); } } -bool ChatChannel::IsInvitee(std::string Invitee) { - - std::list::iterator Iterator; - - for(Iterator = Invitees.begin(); Iterator != Invitees.end(); ++Iterator) { - - if((*Iterator) == Invitee) - return true; - } - - return false; +bool ChatChannel::IsInvitee(std::string Invitee) +{ + return std::find(std::begin(Invitees), std::end(Invitees), Invitee) != std::end(Invitees); } -void ChatChannel::AddModerator(std::string Moderator) { - - if(!IsModerator(Moderator)) { - +void ChatChannel::AddModerator(const std::string &Moderator) +{ + if (!IsModerator(Moderator)) { Moderators.push_back(Moderator); Log.Out(Logs::Detail, Logs::UCS_Server, "Added %s as moderator to channel %s", Moderator.c_str(), Name.c_str()); @@ -618,75 +600,44 @@ void ChatChannel::AddModerator(std::string Moderator) { } -void ChatChannel::RemoveModerator(std::string Moderator) { +void ChatChannel::RemoveModerator(const std::string &Moderator) +{ + auto it = std::find(std::begin(Moderators), std::end(Moderators), Moderator); - std::list::iterator Iterator; - - for(Iterator = Moderators.begin(); Iterator != Moderators.end(); ++Iterator) { - - if((*Iterator) == Moderator) { - - Moderators.erase(Iterator); - - Log.Out(Logs::Detail, Logs::UCS_Server, "Removed %s as moderator to channel %s", Moderator.c_str(), Name.c_str()); - - return; - } + if (it != std::end(Moderators)) { + Moderators.erase(it); + Log.Out(Logs::Detail, Logs::UCS_Server, "Removed %s as moderator to channel %s", Moderator.c_str(), Name.c_str()); } } -bool ChatChannel::IsModerator(std::string Moderator) { - - std::list::iterator Iterator; - - for(Iterator = Moderators.begin(); Iterator != Moderators.end(); ++Iterator) { - - if((*Iterator) == Moderator) - return true; - } - - return false; +bool ChatChannel::IsModerator(std::string Moderator) +{ + return std::find(std::begin(Moderators), std::end(Moderators), Moderator) != std::end(Moderators); } -void ChatChannel::AddVoice(std::string inVoiced) { - - if(!HasVoice(inVoiced)) { - +void ChatChannel::AddVoice(const std::string &inVoiced) +{ + if (!HasVoice(inVoiced)) { Voiced.push_back(inVoiced); Log.Out(Logs::Detail, Logs::UCS_Server, "Added %s as voiced to channel %s", inVoiced.c_str(), Name.c_str()); } - } -void ChatChannel::RemoveVoice(std::string inVoiced) { +void ChatChannel::RemoveVoice(const std::string &inVoiced) +{ + auto it = std::find(std::begin(Voiced), std::end(Voiced), inVoiced); - std::list::iterator Iterator; + if (it != std::end(Voiced)) { + Voiced.erase(it); - for(Iterator = Voiced.begin(); Iterator != Voiced.end(); ++Iterator) { - - if((*Iterator) == inVoiced) { - - Voiced.erase(Iterator); - - Log.Out(Logs::Detail, Logs::UCS_Server, "Removed %s as voiced to channel %s", inVoiced.c_str(), Name.c_str()); - - return; - } + Log.Out(Logs::Detail, Logs::UCS_Server, "Removed %s as voiced to channel %s", inVoiced.c_str(), Name.c_str()); } } -bool ChatChannel::HasVoice(std::string inVoiced) { - - std::list::iterator Iterator; - - for(Iterator = Voiced.begin(); Iterator != Voiced.end(); ++Iterator) { - - if((*Iterator) == inVoiced) - return true; - } - - return false; +bool ChatChannel::HasVoice(std::string inVoiced) +{ + return std::find(std::begin(Voiced), std::end(Voiced), inVoiced) != std::end(Voiced); } std::string CapitaliseName(std::string inString) { diff --git a/ucs/chatchannel.h b/ucs/chatchannel.h index 39fb24c8b..718ab8e4c 100644 --- a/ucs/chatchannel.h +++ b/ucs/chatchannel.h @@ -5,7 +5,7 @@ #include "../common/linked_list.h" #include "../common/timer.h" #include -#include +#include class Client; @@ -21,9 +21,9 @@ public: bool IsClientInChannel(Client *c); int MemberCount(int Status); - std::string GetName() { return Name; } + const std::string &GetName() { return Name; } void SendMessageToChannel(std::string Message, Client* Sender); - bool CheckPassword(std::string inPassword) { return ((Password.length() == 0) || (Password == inPassword)); } + bool CheckPassword(std::string inPassword) { return Password.empty() || Password == inPassword; } void SetPassword(std::string inPassword); bool IsOwner(std::string Name) { return (Owner == Name); } void SetOwner(std::string inOwner); @@ -31,14 +31,14 @@ public: int GetMinStatus() { return MinimumStatus; } bool ReadyToDelete() { return DeleteTimer.Check(); } void SendOPList(Client *c); - void AddInvitee(std::string Invitee); + void AddInvitee(const std::string &Invitee); void RemoveInvitee(std::string Invitee); bool IsInvitee(std::string Invitee); - void AddModerator(std::string Moderator); - void RemoveModerator(std::string Modeerator); + void AddModerator(const std::string &Moderator); + void RemoveModerator(const std::string &Moderator); bool IsModerator(std::string Moderator); - void AddVoice(std::string Voiced); - void RemoveVoice(std::string Voiced); + void AddVoice(const std::string &Voiced); + void RemoveVoice(const std::string &Voiced); bool HasVoice(std::string Voiced); inline bool IsModerated() { return Moderated; } void SetModerated(bool inModerated); @@ -60,9 +60,9 @@ private: LinkedList ClientsInChannel; - std::list Moderators; - std::list Invitees; - std::list Voiced; + std::vector Moderators; + std::vector Invitees; + std::vector Voiced; }; diff --git a/ucs/clientlist.cpp b/ucs/clientlist.cpp index bd79822ab..f49e02986 100644 --- a/ucs/clientlist.cpp +++ b/ucs/clientlist.cpp @@ -38,7 +38,7 @@ extern Database database; extern std::string WorldShortName; extern std::string GetMailPrefix(); extern ChatChannelList *ChannelList; -extern Clientlist *CL; +extern Clientlist *g_Clientlist; extern uint32 ChatMessagesSent; extern uint32 MailMessagesSent; @@ -572,46 +572,36 @@ void Clientlist::CheckForStaleConnections(Client *c) { } } -void Clientlist::Process() { - +void Clientlist::Process() +{ std::shared_ptr eqs; - while((eqs = chatsf->Pop())) { - + while ((eqs = chatsf->Pop())) { struct in_addr in; - in.s_addr = eqs->GetRemoteIP(); - Log.Out(Logs::Detail, Logs::UCS_Server, "New Client UDP connection from %s:%d", inet_ntoa(in), ntohs(eqs->GetRemotePort())); + Log.Out(Logs::Detail, Logs::UCS_Server, "New Client UDP connection from %s:%d", inet_ntoa(in), + ntohs(eqs->GetRemotePort())); eqs->SetOpcodeManager(&ChatOpMgr); auto c = new Client(eqs); - ClientChatConnections.push_back(c); } - std::list::iterator Iterator; - - for(Iterator = ClientChatConnections.begin(); Iterator != ClientChatConnections.end(); ++Iterator) { - - (*Iterator)->AccountUpdate(); - if((*Iterator)->ClientStream->CheckClosed()) { - + auto it = ClientChatConnections.begin(); + while (it != ClientChatConnections.end()) { + (*it)->AccountUpdate(); + if ((*it)->ClientStream->CheckClosed()) { struct in_addr in; - - in.s_addr = (*Iterator)->ClientStream->GetRemoteIP(); + in.s_addr = (*it)->ClientStream->GetRemoteIP(); Log.Out(Logs::Detail, Logs::UCS_Server, "Client connection from %s:%d closed.", inet_ntoa(in), - ntohs((*Iterator)->ClientStream->GetRemotePort())); + ntohs((*it)->ClientStream->GetRemotePort())); - safe_delete((*Iterator)); - - Iterator = ClientChatConnections.erase(Iterator); - - if(Iterator == ClientChatConnections.end()) - break; + safe_delete((*it)); + it = ClientChatConnections.erase(it); continue; } @@ -619,114 +609,95 @@ void Clientlist::Process() { bool KeyValid = true; - while( KeyValid && !(*Iterator)->GetForceDisconnect() && - (app = (EQApplicationPacket *)(*Iterator)->ClientStream->PopPacket())) { - - + while (KeyValid && !(*it)->GetForceDisconnect() && (app = (*it)->ClientStream->PopPacket())) { EmuOpcode opcode = app->GetOpcode(); - switch(opcode) { + switch (opcode) { + case OP_MailLogin: { + char *PacketBuffer = (char *)app->pBuffer; + char MailBox[64]; + char Key[64]; + char ConnectionTypeIndicator; - case OP_MailLogin: { + VARSTRUCT_DECODE_STRING(MailBox, PacketBuffer); - char *PacketBuffer = (char *)app->pBuffer; + if (strlen(PacketBuffer) != 9) { + Log.Out(Logs::Detail, Logs::UCS_Server, + "Mail key is the wrong size. Version of world incompatible with UCS."); + KeyValid = false; + break; + } + ConnectionTypeIndicator = VARSTRUCT_DECODE_TYPE(char, PacketBuffer); - char MailBox[64]; + (*it)->SetConnectionType(ConnectionTypeIndicator); - char Key[64]; + VARSTRUCT_DECODE_STRING(Key, PacketBuffer); - char ConnectionTypeIndicator; + std::string MailBoxString = MailBox, CharacterName; - VARSTRUCT_DECODE_STRING(MailBox, PacketBuffer); + // Strip off the SOE.EQ.. + // + std::string::size_type LastPeriod = MailBoxString.find_last_of("."); - if(strlen(PacketBuffer) != 9) - { - Log.Out(Logs::Detail, Logs::UCS_Server, "Mail key is the wrong size. Version of world incompatible with UCS."); - KeyValid = false; - break; - } - ConnectionTypeIndicator = VARSTRUCT_DECODE_TYPE(char, PacketBuffer); + if (LastPeriod == std::string::npos) + CharacterName = MailBoxString; + else + CharacterName = MailBoxString.substr(LastPeriod + 1); - (*Iterator)->SetConnectionType(ConnectionTypeIndicator); - - VARSTRUCT_DECODE_STRING(Key, PacketBuffer); - - std::string MailBoxString = MailBox, CharacterName; - - // Strip off the SOE.EQ.. - // - std::string::size_type LastPeriod = MailBoxString.find_last_of("."); - - if(LastPeriod == std::string::npos) - CharacterName = MailBoxString; - else - CharacterName = MailBoxString.substr(LastPeriod + 1); - - Log.Out(Logs::Detail, Logs::UCS_Server, "Received login for user %s with key %s", MailBox, Key); - - if(!database.VerifyMailKey(CharacterName, (*Iterator)->ClientStream->GetRemoteIP(), Key)) { - - Log.Out(Logs::Detail, Logs::UCS_Server, "Chat Key for %s does not match, closing connection.", MailBox); - - KeyValid = false; - - break; - } - - (*Iterator)->SetAccountID(database.FindAccount(CharacterName.c_str(), (*Iterator))); - - database.GetAccountStatus((*Iterator)); - - if((*Iterator)->GetConnectionType() == ConnectionTypeCombined) - (*Iterator)->SendFriends(); - - (*Iterator)->SendMailBoxes(); - - CheckForStaleConnections((*Iterator)); + Log.Out(Logs::Detail, Logs::UCS_Server, "Received login for user %s with key %s", + MailBox, Key); + if (!database.VerifyMailKey(CharacterName, (*it)->ClientStream->GetRemoteIP(), Key)) { + Log.Out(Logs::Detail, Logs::UCS_Server, + "Chat Key for %s does not match, closing connection.", MailBox); + KeyValid = false; break; } - case OP_Mail: { + (*it)->SetAccountID(database.FindAccount(CharacterName.c_str(), (*it))); - std::string CommandString = (const char*)app->pBuffer; + database.GetAccountStatus((*it)); - ProcessOPMailCommand((*Iterator), CommandString); + if ((*it)->GetConnectionType() == ConnectionTypeCombined) + (*it)->SendFriends(); - break; - } + (*it)->SendMailBoxes(); - default: { + CheckForStaleConnections((*it)); + break; + } - Log.Out(Logs::Detail, Logs::UCS_Server, "Unhandled chat opcode %8X", opcode); - break; - } + case OP_Mail: { + std::string CommandString = (const char *)app->pBuffer; + ProcessOPMailCommand((*it), CommandString); + break; + } + + default: { + Log.Out(Logs::Detail, Logs::UCS_Server, "Unhandled chat opcode %8X", opcode); + break; + } } safe_delete(app); - } - if(!KeyValid || (*Iterator)->GetForceDisconnect()) { - + if (!KeyValid || (*it)->GetForceDisconnect()) { struct in_addr in; + in.s_addr = (*it)->ClientStream->GetRemoteIP(); - in.s_addr = (*Iterator)->ClientStream->GetRemoteIP(); + Log.Out(Logs::Detail, Logs::UCS_Server, + "Force disconnecting client: %s:%d, KeyValid=%i, GetForceDisconnect()=%i", + inet_ntoa(in), ntohs((*it)->ClientStream->GetRemotePort()), KeyValid, + (*it)->GetForceDisconnect()); - Log.Out(Logs::Detail, Logs::UCS_Server, "Force disconnecting client: %s:%d, KeyValid=%i, GetForceDisconnect()=%i", - inet_ntoa(in), ntohs((*Iterator)->ClientStream->GetRemotePort()), - KeyValid, (*Iterator)->GetForceDisconnect()); + (*it)->ClientStream->Close(); - (*Iterator)->ClientStream->Close(); + safe_delete((*it)); - safe_delete((*Iterator)); - - Iterator = ClientChatConnections.erase(Iterator); - - if(Iterator == ClientChatConnections.end()) - break; + it = ClientChatConnections.erase(it); + continue; } - + ++it; } - } void Clientlist::ProcessOPMailCommand(Client *c, std::string CommandString) @@ -1777,7 +1748,7 @@ void Client::ChannelInvite(std::string CommandString) { Log.Out(Logs::Detail, Logs::UCS_Server, "[%s] invites [%s] to channel [%s]", GetName().c_str(), Invitee.c_str(), ChannelName.c_str()); - Client *RequiredClient = CL->FindCharacter(Invitee); + Client *RequiredClient = g_Clientlist->FindCharacter(Invitee); if(!RequiredClient) { @@ -1905,7 +1876,7 @@ void Client::ChannelGrantModerator(std::string CommandString) { Log.Out(Logs::Detail, Logs::UCS_Server, "[%s] gives [%s] moderator rights to channel [%s]", GetName().c_str(), Moderator.c_str(), ChannelName.c_str()); - Client *RequiredClient = CL->FindCharacter(Moderator); + Client *RequiredClient = g_Clientlist->FindCharacter(Moderator); if(!RequiredClient && (database.FindCharacter(Moderator.c_str()) < 0)) { @@ -1986,7 +1957,7 @@ void Client::ChannelGrantVoice(std::string CommandString) { Log.Out(Logs::Detail, Logs::UCS_Server, "[%s] gives [%s] voice to channel [%s]", GetName().c_str(), Voicee.c_str(), ChannelName.c_str()); - Client *RequiredClient = CL->FindCharacter(Voicee); + Client *RequiredClient = g_Clientlist->FindCharacter(Voicee); if(!RequiredClient && (database.FindCharacter(Voicee.c_str()) < 0)) { @@ -2014,7 +1985,7 @@ void Client::ChannelGrantVoice(std::string CommandString) { return; } - if(RequiredChannel->IsOwner(RequiredClient->GetName()) || RequiredChannel->IsModerator(RequiredClient->GetName())) { + if(RequiredClient && (RequiredChannel->IsOwner(RequiredClient->GetName()) || RequiredChannel->IsModerator(RequiredClient->GetName()))) { GeneralChannelMessage("The channel owner and moderators automatically have voice."); return; @@ -2074,7 +2045,7 @@ void Client::ChannelKick(std::string CommandString) { Log.Out(Logs::Detail, Logs::UCS_Server, "[%s] kicks [%s] from channel [%s]", GetName().c_str(), Kickee.c_str(), ChannelName.c_str()); - Client *RequiredClient = CL->FindCharacter(Kickee); + Client *RequiredClient = g_Clientlist->FindCharacter(Kickee); if(!RequiredClient) { @@ -2281,23 +2252,22 @@ void Client::SendNotification(int MailBoxNumber, std::string Subject, std::strin safe_delete(outapp); } -void Client::ChangeMailBox(int NewMailBox) { - +void Client::ChangeMailBox(int NewMailBox) +{ Log.Out(Logs::Detail, Logs::UCS_Server, "%s Change to mailbox %i", MailBoxName().c_str(), NewMailBox); SetMailBox(NewMailBox); + auto id = std::to_string(NewMailBox); Log.Out(Logs::Detail, Logs::UCS_Server, "New mailbox is %s", MailBoxName().c_str()); - auto outapp = new EQApplicationPacket(OP_MailboxChange, 2); + auto outapp = new EQApplicationPacket(OP_MailboxChange, id.length() + 1); char *buf = (char *)outapp->pBuffer; - VARSTRUCT_ENCODE_INTSTRING(buf, NewMailBox); - + VARSTRUCT_ENCODE_STRING(buf, id.c_str()); QueuePacket(outapp); - safe_delete(outapp); } @@ -2356,7 +2326,7 @@ void Client::SendFriends() { std::string Client::MailBoxName() { - if((Characters.size() == 0) || (CurrentMailBox > (Characters.size() - 1))) + if((Characters.empty()) || (CurrentMailBox > (Characters.size() - 1))) { Log.Out(Logs::Detail, Logs::UCS_Server, "MailBoxName() called with CurrentMailBox set to %i and Characters.size() is %i", CurrentMailBox, Characters.size()); @@ -2373,7 +2343,7 @@ std::string Client::MailBoxName() { int Client::GetCharID() { - if(Characters.size() == 0) + if(Characters.empty()) return 0; return Characters[0].CharID; diff --git a/ucs/database.cpp b/ucs/database.cpp index 8cd1b73f5..dbd0af504 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -48,7 +48,7 @@ #include "../common/string_util.h" #include "chatchannel.h" -extern Clientlist *CL; +extern Clientlist *g_Clientlist; extern std::string GetMailPrefix(); extern ChatChannelList *ChannelList; extern uint32 MailMessagesSent; @@ -200,19 +200,21 @@ bool Database::VerifyMailKey(std::string characterName, int IPAddress, std::stri return !strcmp(row[0], combinedKey); } -int Database::FindCharacter(const char *characterName) { - +int Database::FindCharacter(const char *characterName) +{ char *safeCharName = RemoveApostrophes(characterName); - std::string query = StringFormat("SELECT `id` FROM `character_data` WHERE `name`='%s' LIMIT 1", safeCharName); - auto results = QueryDatabase(query); + std::string query = StringFormat("SELECT `id` FROM `character_data` WHERE `name`='%s' LIMIT 1", safeCharName); + auto results = QueryDatabase(query); if (!results.Success()) { - safe_delete(safeCharName); + safe_delete_array(safeCharName); return -1; } - safe_delete(safeCharName); + + safe_delete_array(safeCharName); if (results.RowCount() != 1) { - Log.Out(Logs::Detail, Logs::UCS_Server, "Bad result from FindCharacter query for character %s", characterName); + Log.Out(Logs::Detail, Logs::UCS_Server, "Bad result from FindCharacter query for character %s", + characterName); return -1; } @@ -461,7 +463,7 @@ bool Database::SendMail(std::string recipient, std::string from, std::string sub Log.Out(Logs::Detail, Logs::UCS_Server, "MessageID %i generated, from %s, to %s", results.LastInsertedID(), from.c_str(), recipient.c_str()); - Client *client = CL->IsCharacterOnline(characterName); + Client *client = g_Clientlist->IsCharacterOnline(characterName); if(client) { std::string FQN = GetMailPrefix() + from; @@ -618,4 +620,4 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings){ Log.file_logs_enabled = true; } } -} \ No newline at end of file +} diff --git a/ucs/ucs.cpp b/ucs/ucs.cpp index b6beeb268..877ff0d0c 100644 --- a/ucs/ucs.cpp +++ b/ucs/ucs.cpp @@ -34,7 +34,7 @@ #include ChatChannelList *ChannelList; -Clientlist *CL; +Clientlist *g_Clientlist; EQEmuLogSys Log; TimeoutManager timeout_manager; Database database; @@ -124,7 +124,7 @@ int main() { exit(1); } - CL = new Clientlist(Config->ChatPort); + g_Clientlist = new Clientlist(Config->ChatPort); ChannelList = new ChatChannelList(); @@ -147,7 +147,7 @@ int main() { Timer::SetCurrentTime(); - CL->Process(); + g_Clientlist->Process(); if(ChannelListProcessTimer.Check()) ChannelList->Process(); @@ -165,7 +165,7 @@ int main() { ChannelList->RemoveAllChannels(); - CL->CloseAllConnections(); + g_Clientlist->CloseAllConnections(); Log.CloseFileLogs(); diff --git a/ucs/worldserver.cpp b/ucs/worldserver.cpp index 395d72e59..4e11c39b7 100644 --- a/ucs/worldserver.cpp +++ b/ucs/worldserver.cpp @@ -34,7 +34,7 @@ #include "../common/md5.h" extern WorldServer worldserver; -extern Clientlist *CL; +extern Clientlist *g_Clientlist; extern const ucsconfig *Config; extern Database database; @@ -90,7 +90,7 @@ void WorldServer::Process() Log.Out(Logs::Detail, Logs::UCS_Server, "Player: %s, Sent Message: %s", From, Message.c_str()); - Client *c = CL->FindCharacter(From); + Client *c = g_Clientlist->FindCharacter(From); safe_delete_array(From); @@ -109,7 +109,7 @@ void WorldServer::Process() } else if(Message[0] == '[') { - CL->ProcessOPMailCommand(c, Message.substr(1, std::string::npos)); + g_Clientlist->ProcessOPMailCommand(c, Message.substr(1, std::string::npos)); } break; diff --git a/utils/defaults/eqemu_config.xml.full b/utils/defaults/eqemu_config.xml.full index ed1cc6002..3195352c5 100644 --- a/utils/defaults/eqemu_config.xml.full +++ b/utils/defaults/eqemu_config.xml.full @@ -68,7 +68,7 @@ - + @@ -80,11 +80,16 @@ + - - - + + + + + + + diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index d144b040e..aefcd8dbc 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -131,6 +131,7 @@ OP_GuildPromote=0x2945 OP_GuildPublicNote=0x3c2c OP_GuildManageBanker=0x389c # Was 0x096d OP_GuildBank=0x2ab0 # Was 0x10c3 +OP_GuildBankItemList=0x1cbf OP_SetGuildRank=0x3599 OP_GuildUpdateURLAndChannel=0x7851 OP_GuildStatus=0x25a5 @@ -171,6 +172,7 @@ OP_BeginCast=0x17ff OP_ColoredText=0x41cb OP_ConsentResponse=0x183d OP_MemorizeSpell=0x2fac +OP_LinkedReuse=0x3ac0 OP_SwapSpell=0x4736 OP_CastSpell=0x1cb5 OP_Consider=0x4d8d @@ -194,6 +196,7 @@ OP_Consent=0x400e OP_ConsentDeny=0x34c1 OP_AutoFire=0x314e OP_PetCommands=0x0093 +OP_PetHoTT=0x0df4 OP_DeleteSpell=0x305c OP_Surname=0x1a87 OP_ClearSurname=0x17b6 @@ -234,6 +237,8 @@ OP_TargetHoTT=0x3af5 OP_XTargetResponse=0x7f64 OP_XTargetRequest=0x6753 OP_XTargetAutoAddHaters=0x5f51 +OP_XTargetOpen=0x7423 +OP_XTargetOpenResponse=0x27e8 OP_TargetBuffs=0x1c71 OP_BuffCreate=0x71f5 OP_BuffRemoveRequest=0x7efd @@ -269,8 +274,8 @@ OP_RequestDuel=0x1ea9 OP_MobRename=0x5040 OP_AugmentItem=0x1627 # Was 0x37cb OP_WeaponEquip1=0x35c3 -OP_WeaponEquip2=0x012f # Was 0x6022 -OP_WeaponUnequip2=0x1076 # Was 0x0110 +OP_PlayerStateAdd=0x012f # Was 0x6022 +OP_PlayerStateRemove=0x1076 # Was 0x0110 OP_ApplyPoison=0x1499 OP_Save=0x2e6f OP_TestBuff=0x046e # Was 0x3772 @@ -352,6 +357,8 @@ OP_Weblink=0x7cce #OP_OpenInventory=0x0000 # Likely does not exist in RoF -U OP_OpenContainer=0x654f OP_Marquee=0x288a +OP_Fling=0x6b8e +OP_CancelSneakHide=0x265f OP_DzQuit=0x5fc8 OP_DzListTimers=0x67b9 diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 0cc0c69d0..19ef8d842 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -130,6 +130,7 @@ OP_GuildPromote=0x6a98 OP_GuildPublicNote=0x5053 OP_GuildManageBanker=0x3f35 OP_GuildBank=0x5134 +OP_GuildBankItemList=0x7850 OP_SetGuildRank=0x0b9c OP_GuildUpdateURLAndChannel=0x2958 OP_GuildStatus=0x7326 @@ -170,6 +171,7 @@ OP_BeginCast=0x318f OP_ColoredText=0x43af OP_ConsentResponse=0x384a OP_MemorizeSpell=0x217c +OP_LinkedReuse=0x1619 OP_SwapSpell=0x0efa OP_CastSpell=0x1287 OP_Consider=0x742b @@ -193,6 +195,7 @@ OP_Consent=0x1fd1 OP_ConsentDeny=0x7a45 OP_AutoFire=0x241e OP_PetCommands=0x0159 +OP_PetHoTT=0x794a OP_DeleteSpell=0x3358 OP_Surname=0x0423 OP_ClearSurname=0x3fb0 @@ -234,6 +237,8 @@ OP_TargetBuffs=0x4f4b OP_XTargetResponse=0x4d59 OP_XTargetRequest=0x3763 OP_XTargetAutoAddHaters=0x672f +OP_XTargetOpen=0x61df +OP_XTargetOpenResponse=0x3ef8 OP_BuffCreate=0x3377 OP_BuffRemoveRequest=0x64f2 OP_DeleteSpawn=0x7280 @@ -268,8 +273,8 @@ OP_RequestDuel=0x3af1 OP_MobRename=0x2c57 OP_AugmentItem=0x661b OP_WeaponEquip1=0x34a7 -OP_WeaponEquip2=0x559a -OP_WeaponUnequip2=0x2d25 +OP_PlayerStateAdd=0x559a +OP_PlayerStateRemove=0x2d25 OP_ApplyPoison=0x31e6 OP_Save=0x4a39 OP_TestBuff=0x7cb8 @@ -294,8 +299,8 @@ OP_MarkNPC=0x1fb5 OP_MarkRaidNPC=0x5a58 #unimplemented OP_ClearNPCMarks=0x2003 OP_ClearRaidNPCMarks=0x20d3 #unimplemented -OP_DelegateAbility=0x4c9d -OP_SetGroupTarget=0x026 +OP_DelegateAbility=0x76b8 +OP_SetGroupTarget=0x2814 OP_Charm=0x5d92 OP_Stun=0x36a4 OP_SendFindableNPCs=0x4613 @@ -352,6 +357,9 @@ OP_OpenContainer=0x0000 OP_Marquee=0x502e OP_ItemRecastDelay=0x15a9 #OP_OpenInventory=0x0000 # Likely does not exist in RoF -U +OP_ResetAA=0x1669 +OP_Fling=0x6f80 +OP_CancelSneakHide=0x0927 # Expeditions OP_DzAddPlayer=0x4701 @@ -535,6 +543,9 @@ OP_FeignDeath=0x52fa OP_Mend=0x0ecf OP_Bind_Wound=0x0386 OP_LDoNOpen=0x3d5c +#OP_LDoNDisarmTraps= #Same as OP_DisarmTraps in RoF +OP_LDoNPickLock=0x9be3 +OP_LDoNInspect=0x0438 # Task packets OP_TaskDescription=0x3714 diff --git a/utils/patches/patch_SoD.conf b/utils/patches/patch_SoD.conf index a5dee668c..08e072d33 100644 --- a/utils/patches/patch_SoD.conf +++ b/utils/patches/patch_SoD.conf @@ -171,6 +171,7 @@ OP_BeginCast=0x0d5a # C OP_ColoredText=0x569a # C OP_ConsentResponse=0x6e47 # C OP_MemorizeSpell=0x8543 # C +OP_LinkedReuse=0x6ef9 OP_SwapSpell=0x3fd2 # C OP_CastSpell=0x3582 # C OP_Consider=0x6024 # C @@ -266,8 +267,8 @@ OP_RequestDuel=0x79e0 # C OP_MobRename=0x0a1d # C OP_AugmentItem=0x0370 # C OP_WeaponEquip1=0x719e # C -OP_WeaponEquip2=0x7b6e # C -OP_WeaponUnequip2=0x19a8 # C +OP_PlayerStateAdd=0x7b6e # C +OP_PlayerStateRemove=0x19a8 # C OP_ApplyPoison=0x405b # C OP_Save=0x5c85 # C OP_TestBuff=0x5fc7 # C @@ -351,6 +352,8 @@ OP_InspectMessageUpdate=0x53a3 # C OP_OpenInventory=0x1003 OP_OpenContainer=0x3278 OP_Marquee=0x7dc9 +OP_Fling=0x2b88 +OP_CancelSneakHide=0x7705 # Expedition OP_DzQuit=0x054e diff --git a/utils/patches/patch_SoF.conf b/utils/patches/patch_SoF.conf index 80aee8bdc..d758daea9 100644 --- a/utils/patches/patch_SoF.conf +++ b/utils/patches/patch_SoF.conf @@ -169,6 +169,7 @@ OP_BeginCast=0x5A50 #SEQ 12/04/08 OP_ColoredText=0x3BC7 #SEQ 12/04/08 OP_ConsentResponse=0x4D30 #SEQ 12/04/08 OP_MemorizeSpell=0x6A93 #SEQ 12/04/08 +OP_LinkedReuse=0x2c26 OP_SwapSpell=0x1418 #SEQ 12/04/08 OP_CastSpell=0x7F5D #SEQ 12/04/08 OP_Consider=0x32E1 #SEQ 12/04/08 @@ -262,8 +263,8 @@ OP_RequestDuel=0x3A2B #Xinu 02/22/09 OP_MobRename=0x6be5 #Trevius 01/16/09 OP_AugmentItem=0x172A #Trevius 03/14/09 OP_WeaponEquip1=0x7260 #Trevius 02/27/09 -OP_WeaponEquip2=0x5C2F #Trevius 02/27/09 -OP_WeaponUnequip2=0x6213 #Trevius 02/27/09 +OP_PlayerStateAdd=0x5C2F #Trevius 02/27/09 +OP_PlayerStateRemove=0x6213 #Trevius 02/27/09 OP_ApplyPoison=0x4543 #WildcardX 03/6/09 OP_Save=0x72F2 #Trevius 03/15/09 OP_TestBuff=0x07BF #/testbuff @@ -334,6 +335,7 @@ OP_OpenInventory=0x66c8 OP_OpenContainer=0x10e3 OP_Marquee=0x2f75 OP_Untargetable=0x3e36 +OP_CancelSneakHide=0x5335 #expedition OP_DzQuit=0x20d6 diff --git a/utils/patches/patch_Titanium.conf b/utils/patches/patch_Titanium.conf index 2660738de..23f07109f 100644 --- a/utils/patches/patch_Titanium.conf +++ b/utils/patches/patch_Titanium.conf @@ -170,6 +170,7 @@ OP_Save=0x736b # ShowEQ 10/27/05 OP_Camp=0x78c1 # ShowEQ 10/27/05 OP_EndLootRequest=0x2316 # ShowEQ 10/27/05 OP_MemorizeSpell=0x308e # ShowEQ 10/27/05 +OP_LinkedReuse=0x6a00 OP_SwapSpell=0x2126 # ShowEQ 10/27/05 OP_CastSpell=0x304b # ShowEQ 10/27/05 OP_DeleteSpell=0x4f37 @@ -286,6 +287,7 @@ OP_RemoveNimbusEffect=0x0000 OP_CrystalReclaim=0x7cfe OP_CrystalCreate=0x62c3 OP_Marquee=0x1d4d +OP_CancelSneakHide=0x48C2 OP_DzQuit=0x486d OP_DzListTimers=0x39aa @@ -534,8 +536,8 @@ OP_PVPLeaderBoardDetailsRequest=0x06a2 OP_PVPLeaderBoardDetailsReply=0x246a OP_PickLockSuccess=0x40E7 OP_WeaponEquip1=0x6c5e -OP_WeaponEquip2=0x63da -OP_WeaponUnequip2=0x381d +OP_PlayerStateAdd=0x63da +OP_PlayerStateRemove=0x381d OP_VoiceMacroIn=0x2866 # Client to Server OP_VoiceMacroOut=0x2ec6 # Server to Client OP_CameraEffect=0x0937 # Correct diff --git a/utils/patches/patch_UF.conf b/utils/patches/patch_UF.conf index 09c6a8252..f41b62740 100644 --- a/utils/patches/patch_UF.conf +++ b/utils/patches/patch_UF.conf @@ -173,6 +173,7 @@ OP_BeginCast=0x0d5a # C OP_ColoredText=0x71bf # C OP_ConsentResponse=0x0e87 # C OP_MemorizeSpell=0x3887 # C +OP_LinkedReuse=0x1b26 OP_SwapSpell=0x5805 # C OP_CastSpell=0x50c2 # C OP_Consider=0x3c2d # C @@ -197,6 +198,7 @@ OP_Consent=0x6bb9 # C OP_ConsentDeny=0x4cd1 # C OP_AutoFire=0x5db5 # C OP_PetCommands=0x7706 # C +OP_PetHoTT=0x2528 OP_DeleteSpell=0x0698 # C OP_Surname=0x44ae # C OP_ClearSurname=0x6705 # C @@ -238,6 +240,8 @@ OP_TargetHoTT=0x790c # C OP_XTargetResponse=0x6eb5 # OP_XTargetRequest=0x4750 # OP_XTargetAutoAddHaters=0x1a28 # +OP_XTargetOpen=0x11ae +OP_XTargetOpenResponse=0x45d3 OP_TargetBuffs=0x3f24 # C OP_BuffCreate=0x2121 # V OP_BuffRemoveRequest=0x4065 @@ -272,8 +276,8 @@ OP_RequestDuel=0x6cfe # C OP_MobRename=0x0507 # C OP_AugmentItem=0x7c87 # C OP_WeaponEquip1=0x4572 # C -OP_WeaponEquip2=0x399b # C -OP_WeaponUnequip2=0x416b # C +OP_PlayerStateAdd=0x399b # C +OP_PlayerStateRemove=0x416b # C OP_ApplyPoison=0x5cd3 # C OP_Save=0x6618 # C OP_TestBuff=0x3415 # C @@ -358,6 +362,8 @@ OP_InspectMessageUpdate=0x7fa1 # C #OP_OpenInventory=0x0000 # Likely does not exist in UF -U OP_OpenContainer=0x041a OP_Marquee=0x3675 +OP_Fling=0x51b1 +OP_CancelSneakHide=0x7686 OP_DzQuit=0x1539 OP_DzListTimers=0x21e9 @@ -532,6 +538,9 @@ OP_InstillDoubt=0x221a # C OP_FeignDeath=0x002b # C OP_Mend=0x10a6 # C OP_LDoNOpen=0x032b # C +OP_LDoNDisarmTraps=0x1a84 +OP_LDoNPickLock=0x0370 +OP_LDoNInspect=0x0aaa # Task packets OP_TaskActivityComplete=0x5832 # C diff --git a/utils/scripts/bot_command_spell_scripts/_blank_spells.sql b/utils/scripts/bot_command_spell_scripts/_blank_spells.sql new file mode 100644 index 000000000..2250c7fa4 --- /dev/null +++ b/utils/scripts/bot_command_spell_scripts/_blank_spells.sql @@ -0,0 +1,135 @@ +SELECT +-- base + CASE + WHEN `targettype` = '1' AND `CastRestriction` = '0' THEN 'TargetOptional' + WHEN `targettype` = '3' AND `CastRestriction` = '0' THEN 'GroupV1' + WHEN `targettype` = '4' AND `CastRestriction` = '0' THEN 'AECaster' + WHEN `targettype` = '5' AND `CastRestriction` = '0' THEN 'Single' + WHEN `targettype` = '5' AND `CastRestriction` = '150' THEN 'Animal' + WHEN `targettype` = '6' AND `CastRestriction` = '0' THEN 'Self' + WHEN `targettype` = '8' AND `CastRestriction` = '0' THEN 'AETarget' + WHEN `targettype` = '9' AND `CastRestriction` = '0' THEN 'Animal' + WHEN `targettype` = '10' AND `CastRestriction` = '0' THEN 'Undead' + WHEN `targettype` = '11' AND `CastRestriction` = '0' THEN 'Summoned' + WHEN `targettype` = '13' AND `CastRestriction` = '0' THEN 'Tap' + WHEN `targettype` = '14' AND `CastRestriction` = '0' THEN 'Pet' + WHEN `targettype` = '15' AND `CastRestriction` = '0' THEN 'Corpse' + WHEN `targettype` = '16' AND `CastRestriction` = '0' THEN 'Plant' + WHEN `targettype` = '17' AND `CastRestriction` = '0' THEN 'Giant' + WHEN `targettype` = '18' AND `CastRestriction` = '0' THEN 'Dragon' + WHEN `targettype` = '34' AND `CastRestriction` = '0' THEN 'LDoNChest_Cursed' + WHEN `targettype` = '38' AND `CastRestriction` = '0' THEN 'SummonedPet' + WHEN `targettype` = '39' AND `CastRestriction` = '0' THEN 'GroupNoPets' -- V1 or V2? + WHEN `targettype` = '40' AND `CastRestriction` = '0' THEN 'AEBard' + WHEN `targettype` = '41' AND `CastRestriction` = '0' THEN 'GroupV2' + WHEN `targettype` = '42' AND `CastRestriction` = '0' THEN 'Directional' + WHEN `targettype` = '43' AND `CastRestriction` = '0' THEN 'GroupClientAndPet' + WHEN `targettype` = '44' AND `CastRestriction` = '0' THEN 'Beam' + WHEN `targettype` = '45' AND `CastRestriction` = '0' THEN 'Ring' + WHEN `targettype` = '46' AND `CastRestriction` = '0' THEN 'TargetsTarget' + ELSE CONCAT(`targettype`, ', ', `CastRestriction`) -- 'UNDEFINED' + END target_type, + CASE + WHEN `zonetype` NOT IN ('-1', '0') THEN `zonetype` + ELSE '0' + END zone_type, + caster_class, + spell_level, + `id` spell_id, + CONCAT('"', `name`, '"') spell_name +-- base + +FROM ( + SELECT 'WARRIOR' caster_class, `classes1` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes1` NOT IN ('254', '255') +UNION ALL + SELECT 'CLERIC' caster_class, `classes2` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes2` NOT IN ('254', '255') +UNION ALL + SELECT 'PALADIN' caster_class, `classes3` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes3` NOT IN ('254', '255') +UNION ALL + SELECT 'RANGER' caster_class, `classes4` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes4` NOT IN ('254', '255') +UNION ALL + SELECT 'SHADOWKNIGHT' caster_class, `classes5` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes5` NOT IN ('254', '255') +UNION ALL + SELECT 'DRUID' caster_class, `classes6` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes6` NOT IN ('254', '255') +UNION ALL + SELECT 'MONK' caster_class, `classes7` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes7` NOT IN ('254', '255') +UNION ALL + SELECT 'BARD' caster_class, `classes8` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes8` NOT IN ('254', '255') +UNION ALL + SELECT 'ROGUE' caster_class, `classes9` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes9` NOT IN ('254', '255') +UNION ALL + SELECT 'SHAMAN' caster_class, `classes10` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes10` NOT IN ('254', '255') +UNION ALL + SELECT 'NECROMANCER' caster_class, `classes11` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes11` NOT IN ('254', '255') +UNION ALL + SELECT 'WIZARD' caster_class, `classes12` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes12` NOT IN ('254', '255') +UNION ALL + SELECT 'MAGICIAN' caster_class, `classes13` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes13` NOT IN ('254', '255') +UNION ALL + SELECT 'ENCHANTER' caster_class, `classes14` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes14` NOT IN ('254', '255') +UNION ALL + SELECT 'BEASTLORD' caster_class, `classes15` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes15` NOT IN ('254', '255') +UNION ALL + SELECT 'BERSERKER' caster_class, `classes16` spell_level, + `spells_new`.* + FROM `spells_new` + WHERE `classes16` NOT IN ('254', '255') +) spells + +-- WHERE `name` NOT LIKE '%II' +-- --- +-- WHERE `name` NOT LIKE '%Rk. II%' +-- AND `name` NOT LIKE '%Rk.II%' +-- AND `name` NOT LIKE '%Rk. III%' +-- AND `name` NOT LIKE '%Rk.III%' +ORDER BY FIELD(target_type, 'Animal', 'Undead', 'Summoned', 'Pet', 'Plant', 'TargetsTarget', 'Single', 'Self', 'GroupV1', 'GroupV2', 'GroupNoPets', 'AECaster', 'AETarget', 'Corpse'), + zone_type, + FIELD(caster_class, 'WARRIOR', 'CLERIC', 'PALADIN', 'RANGER', 'SHADOWKNIGHT', 'DRUID', 'MONK', 'BARD', 'ROGUE', 'SHAMAN', 'NECROMANCER', 'WIZARD', 'MAGICIAN', 'ENCHANTER', 'BEASTLORD', 'BERSERKER'), + spell_level, + spell_id, + spell_name diff --git a/utils/scripts/convert_maps_to_mmfs.pl b/utils/scripts/convert_maps_to_mmfs.pl new file mode 100644 index 000000000..4c68c7e18 --- /dev/null +++ b/utils/scripts/convert_maps_to_mmfs.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +########################################################### +#::: Automatic (Map-to-MMF) Conversion Script +#::: Author: Uleat +#::: Purpose: To convert existing zone maps to memory-mapped files +########################################################### + +use Config; + +print("\n"); +print("Zone Map-to-MMF Batch convertor\n"); +print("===============================\n"); +print("\n"); + +if($Config{osname}=~/freebsd|linux/i){ $OS = "Linux"; } +if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; } +print("Operating System is: $Config{osname}\n"); +print("\n"); + +opendir(D, "maps") || die "Can't find directory maps: $!\n"; +my @mapfiles = grep { /\.map$/ && !/_lit/ } readdir(D); +closedir(D); + +foreach my $mapfile (@mapfiles) { + my $result = "Unknown action..\n"; + print("processing map: '$mapfile'\n"); + if($OS eq "Windows"){ $result = `zone convert_map $mapfile`; } + if($OS eq "Linux"){ $result = `./zone convert_map $mapfile`; } + print("-- $result"); +} + +print("\n"); +print("Batch processing complete\n") diff --git a/utils/scripts/db_dumper.pl b/utils/scripts/db_dumper.pl index 71e552ad3..5b4bb229d 100644 --- a/utils/scripts/db_dumper.pl +++ b/utils/scripts/db_dumper.pl @@ -15,7 +15,7 @@ $localdrive = "C:"; #::: Where Windows and all Install Programs are... $linesep = "---------------------------------------"; use POSIX qw(strftime); -my $date = strftime "%m-%d-%Y", localtime; +my $date = strftime "%m_%d_%Y", localtime; print "\nTodays Date: " . $date . "\n"; use Config; @@ -32,6 +32,7 @@ if(!$ARGV[0]){ 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 ' Example: perl DB_Dumper.pl Loc="E:\Backups"' . "\n\n"; print "######################################################\n"; exit; @@ -59,6 +60,9 @@ print "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 "Compression SET\n"; $Compress = 1; @@ -105,19 +109,25 @@ else { if($t_tables ne ""){ $tables_f_l = substr($t_tables_l, 0, 20) . '...'; - $target_file = '' . $tables_f_l . ' ' . $date . ''; + $target_file = '' . $tables_f_l . '_' . $date . ''; print "Performing table based backup...\n"; #::: Backup Database... print "Backing up Database " . $db . "... \n\n"; - $cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' ' . $t_tables . ' > "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql"'; + 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 . ' > "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql"'; printcmd($cmd); system($cmd); } else{ #::: Entire DB Backup - $target_file = '' . $db . ' ' . $date . ''; + $target_file = '' . $db . '_' . $date . ''; #::: Backup Database... print "Backing up Database " . $db . "... \n\n"; - $cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' > "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql"'; + if($no_lock == 1){ + $added_parameters .= " --skip-lock-tables "; + } + $cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' ' . $added_parameters . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' > "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql"'; printcmd($cmd); system($cmd); } diff --git a/utils/scripts/eqemu_update.pl b/utils/scripts/eqemu_update.pl index 04c5367b3..6d1e32c3a 100644 --- a/utils/scripts/eqemu_update.pl +++ b/utils/scripts/eqemu_update.pl @@ -9,19 +9,28 @@ $menu_displayed = 0; use Config; +use File::Copy qw(copy); +use POSIX qw(strftime); +use File::Path; +use File::Find; +use URI::Escape; +use Time::HiRes qw(usleep); + +$time_stamp = strftime('%m-%d-%Y', gmtime()); + $console_output .= " Operating System is: $Config{osname}\n"; -if($Config{osname}=~/linux/i){ $OS = "Linux"; } +if($Config{osname}=~/freebsd|linux/i){ $OS = "Linux"; } if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; } #::: If current version is less than what world is reporting, then download a new one... -$current_version = 2; +$current_version = 14; if($ARGV[0] eq "V"){ if($ARGV[1] > $current_version){ print "eqemu_update.pl Automatic Database Upgrade Needs updating...\n"; print " Current version: " . $current_version . "\n"; print " New version: " . $ARGV[1] . "\n"; - GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl", "eqemu_update.pl"); + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl", "eqemu_update.pl"); exit; } else{ @@ -30,14 +39,19 @@ if($ARGV[0] eq "V"){ exit; } +#::: Sets database run stage check +$db_run_stage = 0; + $perl_version = $^V; $perl_version =~s/v//g; print "Perl Version is " . $perl_version . "\n"; if($perl_version > 5.12){ no warnings 'uninitialized'; } no warnings; +($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(); + my $confile = "eqemu_config.xml"; #default -open(F, "<$confile") or die "Unable to open config: $confile\n"; +open(F, "<$confile"); my $indb = 0; while() { s/\r//g; @@ -87,9 +101,91 @@ if($OS eq "Linux"){ } #::: Path not found, error and exit -if($path eq ""){ +if($path eq ""){ print "MySQL path not found, please add the path for automatic database upgrading to continue... \n\n"; - print "Exiting...\n"; + print "script_exiting...\n"; + exit; +} + +if($ARGV[0] eq "install_peq_db"){ + + $db_name = "peq"; + if($ARGV[1]){ + $db_name = $ARGV[1]; + } + + $db = $db_name; + + #::: Database Routines + print "MariaDB :: Creating Database '" . $db_name . "'\n"; + print `"$path" --host $host --user $user --password="$pass" -N -B -e "DROP DATABASE IF EXISTS $db_name;"`; + print `"$path" --host $host --user $user --password="$pass" -N -B -e "CREATE DATABASE $db_name"`; + if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); } + if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); } + $bin_db_ver = trim($db_version[1]); + check_db_version_table(); + $local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1")); + fetch_peq_db_full(); + print "\nFetching Latest Database Updates...\n"; + main_db_management(); + print "\nApplying Latest Database Updates...\n"; + main_db_management(); + + print get_mysql_result("UPDATE `launcher` SET `dynamics` = 30 WHERE `name` = 'zone'"); +} + +if($ARGV[0] eq "remove_duplicate_rules"){ + remove_duplicate_rule_values(); + exit; +} + +if($ARGV[0] eq "installer"){ + print "Running EQEmu Server installer routines...\n"; + mkdir('logs'); + mkdir('updates_staged'); + mkdir('shared'); + fetch_latest_windows_binaries(); + map_files_fetch_bulk(); + opcodes_fetch(); + plugins_fetch(); + quest_files_fetch(); + lua_modules_fetch(); + + #::: Binary dll's + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/lua51.dll", "lua51.dll", 1); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/zlib1.dll", "zlib1.dll", 1); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/libmysql.dll", "libmysql.dll", 1); + + #::: Server scripts + fetch_utility_scripts(); + + #::: Database Routines + print "MariaDB :: Creating Database 'peq'\n"; + print `"$path" --host $host --user $user --password="$pass" -N -B -e "DROP DATABASE IF EXISTS peq;"`; + print `"$path" --host $host --user $user --password="$pass" -N -B -e "CREATE DATABASE peq"`; + if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); } + if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); } + $bin_db_ver = trim($db_version[1]); + check_db_version_table(); + $local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1")); + fetch_peq_db_full(); + print "\nFetching Latest Database Updates...\n"; + main_db_management(); + print "\nApplying Latest Database Updates...\n"; + main_db_management(); + + print get_mysql_result("UPDATE `launcher` SET `dynamics` = 30 WHERE `name` = 'zone'"); + + if($OS eq "Windows"){ + check_windows_firewall_rules(); + do_windows_login_server_setup(); + } + exit; +} + +if($ARGV[0] eq "db_dump_compress"){ database_dump_compress(); exit; } +if($ARGV[0] eq "login_server_setup"){ + do_windows_login_server_setup(); exit; } @@ -97,25 +193,29 @@ if($path eq ""){ mkdir('db_update'); #::: Check if db_version table exists... -if(trim(GetMySQLResult("SHOW COLUMNS FROM db_version LIKE 'Revision'")) ne ""){ - print GetMySQLResult("DROP TABLE db_version"); +if(trim(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'Revision'")) ne "" && $db){ + print get_mysql_result("DROP TABLE db_version"); print "Old db_version table present, dropping...\n\n"; } -if(GetMySQLResult("SHOW TABLES LIKE 'db_version'") eq ""){ - print GetMySQLResult(" - CREATE TABLE db_version ( - version int(11) DEFAULT '0' - ) ENGINE=InnoDB DEFAULT CHARSET=latin1; - INSERT INTO db_version (version) VALUES ('1000');"); - print "Table 'db_version' does not exists.... Creating...\n\n"; +sub check_db_version_table{ + if(get_mysql_result("SHOW TABLES LIKE 'db_version'") eq "" && $db){ + print get_mysql_result(" + CREATE TABLE db_version ( + version int(11) DEFAULT '0' + ) ENGINE=InnoDB DEFAULT CHARSET=latin1; + INSERT INTO db_version (version) VALUES ('1000');"); + print "Table 'db_version' does not exists.... Creating...\n\n"; + } } +check_db_version_table(); + if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); } if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); } $bin_db_ver = trim($db_version[1]); -$local_db_ver = trim(GetMySQLResult("SELECT version FROM db_version LIMIT 1")); +$local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1")); #::: If ran from Linux startup script, supress output if($bin_db_ver == $local_db_ver && $ARGV[0] eq "ran_from_start"){ @@ -123,44 +223,82 @@ if($bin_db_ver == $local_db_ver && $ARGV[0] eq "ran_from_start"){ exit; } else{ - print $console_output; + print $console_output if $db; } +if($db){ + print " Binary Revision / Local: (" . $bin_db_ver . " / " . $local_db_ver . ")\n"; + + #::: Bots + #::: Make sure we're running a bots binary to begin with + if(trim($db_version[2]) > 0){ + $bots_local_db_version = get_bots_db_version(); + if($bots_local_db_version > 0){ + print " (Bots) Binary Revision / Local: (" . trim($db_version[2]) . " / " . $bots_local_db_version . ")\n"; + } + } -print " Binary Database Version: (" . $bin_db_ver . ")\n"; -print " Local Database Version: (" . $local_db_ver . ")\n\n"; + #::: If World ran this script, and our version is up to date, continue... + if($bin_db_ver <= $local_db_ver && $ARGV[0] eq "ran_from_world"){ + print " Database up to Date: Continuing World Bootup...\n"; + print "============================================================\n"; + exit; + } -#::: If World ran this script, and our version is up to date, continue... -if($bin_db_ver <= $local_db_ver && $ARGV[0] eq "ran_from_world"){ - print " Database up to Date: Continuing World Bootup...\n"; - print "============================================================\n"; - exit; } -print "Retrieving latest database manifest...\n"; -GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt"); -# GetRemoteFile("https://dl.dropboxusercontent.com/u/50023467/dl/db_update_manifest.txt", "db_update/db_update_manifest.txt"); - if($local_db_ver < $bin_db_ver && $ARGV[0] eq "ran_from_world"){ print "You have missing database updates, type 1 or 2 to backup your database before running them as recommended...\n\n"; #::: Display Menu - ShowMenuPrompt(); + show_menu_prompt(); } else{ #::: Most likely ran standalone print "\n"; - ShowMenuPrompt(); + show_menu_prompt(); } +sub do_update_self{ + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl", "eqemu_update.pl"); + die "Rerun eqemu_update.pl"; +} -sub ShowMenuPrompt { +sub fetch_utility_scripts { + if($OS eq "Windows"){ + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_database_backup.bat", "t_database_backup.bat"); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_start_server.bat", "t_start_server.bat"); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_start_server_with_login_server.bat", "t_start_server_with_login_server.bat"); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_stop_server.bat", "t_stop_server.bat"); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_server_crash_report.pl", "t_server_crash_report.pl"); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/win_server_launcher.pl", "win_server_launcher.pl"); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_start_server_with_login_server.bat", "t_start_server_with_login_server.bat"); + } + else { + print "No scripts found for OS: " . $OS . "...\n"; + } +} + +sub show_menu_prompt { my %dispatch = ( 1 => \&database_dump, 2 => \&database_dump_compress, - 3 => \&Run_Database_Check, - 4 => \&AA_Fetch, - 5 => \&OpCodes_Fetch, - 0 => \&Exit, + 3 => \&main_db_management, + 4 => \&bots_db_management, + 5 => \&opcodes_fetch, + 6 => \&map_files_fetch, + 7 => \&plugins_fetch, + 8 => \&quest_files_fetch, + 9 => \&lua_modules_fetch, + 10 => \&aa_fetch, + 11 => \&fetch_latest_windows_binaries, + 12 => \&fetch_server_dlls, + 13 => \&do_windows_login_server_setup, + 14 => \&remove_duplicate_rule_values, + 15 => \&fetch_utility_scripts, + 18 => \&fetch_latest_windows_binaries_bots, + 19 => \&do_bots_db_schema_drop, + 20 => \&do_update_self, + 0 => \&script_exit, ); while (1) { @@ -170,7 +308,7 @@ sub ShowMenuPrompt { $menu_show++; next; } - print MenuOptions(), '> '; + print menu_options(), '> '; $menu_displayed++; if($menu_displayed > 50){ print "Safety: Menu looping too many times, exiting...\n"; @@ -197,36 +335,63 @@ sub ShowMenuPrompt { } } -sub MenuOptions { +sub menu_options { if(@total_updates){ - $option[3] = "Run pending REQUIRED updates... (" . scalar (@total_updates) . ")"; + if($bots_db_management == 1){ + $option[3] = "Check and stage pending REQUIRED Database updates"; + $bots_management = "Run pending REQUIRED updates... (" . scalar (@total_updates) . ")"; + } + else{ + $option[3] = "Run pending REQUIRED updates... (" . scalar (@total_updates) . ")"; + if(get_mysql_result("SHOW TABLES LIKE 'bots'") eq ""){ + $bots_management = "Install bots database pre-requisites (Requires bots server binaries)"; + } + else{ + $bots_management = "Check for Bot pending REQUIRED database updates... (Must have bots enabled)"; + } + } } else{ - $option[3] = "Check for pending REQUIRED Database updates - Stages updates for automatic upgrade..."; + $option[3] = "Check and stage pending REQUIRED Database updates"; + $bots_management = "Check for Bot REQUIRED database updates... (Must have bots enabled)"; } return <new; - $ua->timeout(10); - $ua->env_proxy; - my $response = $ua->get($URL); - - if ($response->is_success){ - open (FILE, '> ' . $Dest_File . ''); - print FILE $response->decoded_content; - close (FILE); - print " URL: " . $URL . "\n"; - print " Saved: " . $Dest_File . " \n"; - } - else { - print "Error, no connection to the internet...\n\n"; - die $response->status_line; + #::: Build file path of the destination file so that we may check for the folder's existence and make it if necessary + if($Dest_File=~/\//i){ + my @dir_path = split('/', $Dest_File); + $build_path = ""; + $di = 0; + while($dir_path[$di]){ + $build_path .= $dir_path[$di] . "/"; + #::: If path does not exist, create the directory... + if (!-d $build_path) { + mkdir($build_path); + } + if(!$dir_path[$di + 2] && $dir_path[$di + 1]){ + # print $actual_path . "\n"; + $actual_path = $build_path; + last; + } + $di++; } } - if($OS eq "Linux"){ + + if($OS eq "Windows"){ + #::: For non-text type requests... + if($content_type == 1){ + $break = 0; + while($break == 0) { + use LWP::Simple qw(getstore); + if(!getstore($URL, $Dest_File)){ + # print "Error, no connection or failed request...\n\n"; + } + # sleep(1); + #::: Make sure the file exists before continuing... + if(-e $Dest_File) { + $break = 1; + print " [URL] :: " . $URL . "\n"; + print " [Saved] :: " . $Dest_File . "\n"; + } else { $break = 0; } + usleep(500); + } + } + else{ + $break = 0; + while($break == 0) { + require LWP::UserAgent; + my $ua = LWP::UserAgent->new; + $ua->timeout(10); + $ua->env_proxy; + my $response = $ua->get($URL); + if ($response->is_success){ + open (FILE, '> ' . $Dest_File . ''); + print FILE $response->decoded_content; + close (FILE); + } + else { + # print "Error, no connection or failed request...\n\n"; + } + if(-e $Dest_File) { + $break = 1; + print " [URL] :: " . $URL . "\n"; + print " [Saved] :: " . $Dest_File . "\n"; + } else { $break = 0; } + usleep(500); + } + } + } + if($OS eq "Linux"){ #::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt $wget = `wget --no-check-certificate --quiet -O $Dest_File $URL`; - print " URL: " . $URL . "\n"; - print " Saved: " . $Dest_File . " \n"; + print " o URL: (" . $URL . ")\n"; + print " o Saved: (" . $Dest_File . ") \n"; if($wget=~/unable to resolve/i){ - print "Error, no connection to the internet...\n\n"; - die; + print "Error, no connection or failed request...\n\n"; + #die; } } } @@ -308,16 +526,21 @@ sub trim { } #::: Fetch Latest PEQ AA's -sub AA_Fetch{ +sub aa_fetch{ + if(!$db){ + print "No database present, check your eqemu_config.xml for proper MySQL/MariaDB configuration...\n"; + return; + } + print "Pulling down PEQ AA Tables...\n"; - GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/peq_aa_tables.sql", "db_update/peq_aa_tables.sql"); + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/peq_aa_tables_post_rework.sql", "db_update/peq_aa_tables_post_rework.sql"); print "\n\nInstalling AA Tables...\n"; - print GetMySQLResultFromFile("db_update/peq_aa_tables.sql"); + print get_mysql_result_from_file("db_update/peq_aa_tables_post_rework.sql"); print "\nDone...\n\n"; } #::: Fetch Latest Opcodes -sub OpCodes_Fetch{ +sub opcodes_fetch{ print "Pulling down latest opcodes...\n"; %opcodes = ( 1 => ["opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/opcodes.conf"], @@ -340,41 +563,865 @@ sub OpCodes_Fetch{ } print "\nDownloading (" . $opcodes{$loop}[0] . ") File: '" . $file_name . "'...\n\n"; - GetRemoteFile($opcodes{$loop}[1], $file_name); - $loop++; + get_remote_file($opcodes{$loop}[1], $file_name); + $loop++; } print "\nDone...\n\n"; } +sub remove_duplicate_rule_values{ + $ruleset_id = trim(get_mysql_result("SELECT `ruleset_id` FROM `rule_sets` WHERE `name` = 'default'")); + print "Default Ruleset ID: " . $ruleset_id . "\n"; + + $total_removed = 0; + #::: Store Default values... + $mysql_result = get_mysql_result("SELECT * FROM `rule_values` WHERE `ruleset_id` = " . $ruleset_id); + my @lines = split("\n", $mysql_result); + foreach my $val (@lines){ + my @values = split("\t", $val); + $rule_set_values{$values[1]}[0] = $values[2]; + } + #::: Compare default values against other rulesets to check for duplicates... + $mysql_result = get_mysql_result("SELECT * FROM `rule_values` WHERE `ruleset_id` != " . $ruleset_id); + my @lines = split("\n", $mysql_result); + foreach my $val (@lines){ + my @values = split("\t", $val); + if($values[2] == $rule_set_values{$values[1]}[0]){ + print "DUPLICATE : " . $values[1] . " (Ruleset (" . $values[0] . ")) matches default value of : " . $values[2] . ", removing...\n"; + get_mysql_result("DELETE FROM `rule_values` WHERE `ruleset_id` = " . $values[0] . " AND `rule_name` = '" . $values[1] . "'"); + $total_removed++; + } + } + + print "Total duplicate rules removed... " . $total_removed . "\n"; +} + +sub copy_file{ + $l_source_file = $_[0]; + $l_dest_file = $_[1]; + if($l_dest_file=~/\//i){ + my @dir_path = split('/', $l_dest_file); + $build_path = ""; + $di = 0; + while($dir_path[$di]){ + $build_path .= $dir_path[$di] . "/"; + #::: If path does not exist, create the directory... + if (!-d $build_path) { + mkdir($build_path); + } + if(!$dir_path[$di + 2] && $dir_path[$di + 1]){ + # print $actual_path . "\n"; + $actual_path = $build_path; + last; + } + $di++; + } + } + copy $l_source_file, $l_dest_file; +} + +sub fetch_latest_windows_binaries{ + print "\n --- Fetching Latest Windows Binaries... --- \n"; + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/master_windows_build.zip", "updates_staged/master_windows_build.zip", 1); + print "\n --- Fetched Latest Windows Binaries... --- \n"; + print "\n --- Extracting... --- \n"; + unzip('updates_staged/master_windows_build.zip', 'updates_staged/binaries/'); + my @files; + my $start_dir = "updates_staged/binaries"; + find( + sub { push @files, $File::Find::name unless -d; }, + $start_dir + ); + for my $file (@files) { + $dest_file = $file; + $dest_file =~s/updates_staged\/binaries\///g; + print "Installing :: " . $dest_file . "\n"; + copy_file($file, $dest_file); + } + print "\n --- Done... --- \n"; + + rmtree('updates_staged'); +} + +sub fetch_latest_windows_binaries_bots{ + print "\n --- Fetching Latest Windows Binaries with Bots... --- \n"; + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/master_windows_build_bots.zip", "updates_staged/master_windows_build_bots.zip", 1); + print "\n --- Fetched Latest Windows Binaries with Bots... --- \n"; + print "\n --- Extracting... --- \n"; + unzip('updates_staged/master_windows_build_bots.zip', 'updates_staged/binaries/'); + my @files; + my $start_dir = "updates_staged/binaries"; + find( + sub { push @files, $File::Find::name unless -d; }, + $start_dir + ); + for my $file (@files) { + $dest_file = $file; + $dest_file =~s/updates_staged\/binaries\///g; + print "Installing :: " . $dest_file . "\n"; + copy_file($file, $dest_file); + } + print "\n --- Done... --- \n"; + + rmtree('updates_staged'); +} + +sub do_windows_login_server_setup{ + print "\n --- Fetching Loginserver... --- \n"; + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/login_server.zip", "updates_staged/login_server.zip", 1); + print "\n --- Extracting... --- \n"; + unzip('updates_staged/login_server.zip', 'updates_staged/login_server/'); + my @files; + my $start_dir = "updates_staged/login_server"; + find( + sub { push @files, $File::Find::name unless -d; }, + $start_dir + ); + for my $file (@files) { + $dest_file = $file; + $dest_file =~s/updates_staged\/login_server\///g; + print "Installing :: " . $dest_file . "\n"; + copy_file($file, $dest_file); + } + print "\n Done... \n"; + + print "Pulling down Loginserver database tables...\n"; + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/login_server_tables.sql", "db_update/login_server_tables.sql"); + print "\n\nInstalling Loginserver tables...\n"; + print get_mysql_result_from_file("db_update/login_server_tables.sql"); + print "\nDone...\n\n"; + + add_login_server_firewall_rules(); + + rmtree('updates_staged'); + rmtree('db_update'); + + print "\nPress any key to continue...\n"; + + <>; #Read from STDIN + +} + +sub add_login_server_firewall_rules{ + #::: Check Loginserver Firewall install for Windows + if($OS eq "Windows"){ + $output = `netsh advfirewall firewall show rule name=all`; + @output_buffer = split("\n", $output); + $has_loginserver_rules_titanium = 0; + $has_loginserver_rules_sod = 0; + foreach my $val (@output_buffer){ + if($val=~/Rule Name/i){ + $val=~s/Rule Name://g; + if($val=~/EQEmu Loginserver/i && $val=~/Titanium/i){ + $has_loginserver_rules_titanium = 1; + print "Found existing rule :: " . trim($val) . "\n"; + } + if($val=~/EQEmu Loginserver/i && $val=~/SOD/i){ + $has_loginserver_rules_sod = 1; + print "Found existing rule :: " . trim($val) . "\n"; + } + } + } + + if($has_loginserver_rules_titanium == 0){ + print "Attempting to add EQEmu Loginserver Firewall Rules (Titanium) (TCP) port 5998 \n"; + print `netsh advfirewall firewall add rule name="EQEmu Loginserver (Titanium) (5998) TCP" dir=in action=allow protocol=TCP localport=5998`; + print "Attempting to add EQEmu Loginserver Firewall Rules (Titanium) (UDP) port 5998 \n"; + print `netsh advfirewall firewall add rule name="EQEmu Loginserver (Titanium) (5998) UDP" dir=in action=allow protocol=UDP localport=5998`; + } + if($has_loginserver_rules_sod == 0){ + print "Attempting to add EQEmu Loginserver Firewall Rules (SOD+) (TCP) port 5999 \n"; + print `netsh advfirewall firewall add rule name="EQEmu Loginserver (SOD+) (5999) TCP" dir=in action=allow protocol=TCP localport=5999`; + print "Attempting to add EQEmu Loginserver Firewall Rules (SOD+) (UDP) port 5999 \n"; + print `netsh advfirewall firewall add rule name="EQEmu Loginserver (SOD+) (5999) UDP" dir=in action=allow protocol=UDP localport=5999`; + } + + print "If firewall rules don't add you must run this script (eqemu_update.pl) as administrator\n"; + print "\n"; + print "#::: Instructions \n"; + print "In order to connect your server to the loginserver you must point your eqemu_config.xml to your local server similar to the following:\n"; + print " + + login.eqemulator.net + 5998 + + + + + 127.0.0.1 + 5998 + + + + "; + print "\nWhen done, make sure your EverQuest client points to your loginserver's IP (In this case it would be 127.0.0.1) in the eqhosts.txt file\n"; + } +} + +sub check_windows_firewall_rules{ + $output = `netsh advfirewall firewall show rule name=all`; + @output_buffer = split("\n", $output); + $has_world_rules = 0; + $has_zone_rules = 0; + foreach my $val (@output_buffer){ + if($val=~/Rule Name/i){ + $val=~s/Rule Name://g; + if($val=~/EQEmu World/i){ + $has_world_rules = 1; + print "Found existing rule :: " . trim($val) . "\n"; + } + if($val=~/EQEmu Zone/i){ + $has_zone_rules = 1; + print "Found existing rule :: " . trim($val) . "\n"; + } + } + } + + if($has_world_rules == 0){ + print "Attempting to add EQEmu World Firewall Rules (TCP) port 9000 \n"; + print `netsh advfirewall firewall add rule name="EQEmu World (9000) TCP" dir=in action=allow protocol=TCP localport=9000`; + print "Attempting to add EQEmu World Firewall Rules (UDP) port 9000 \n"; + print `netsh advfirewall firewall add rule name="EQEmu World (9000) UDP" dir=in action=allow protocol=UDP localport=9000`; + } + if($has_zone_rules == 0){ + print "Attempting to add EQEmu Zones (7000-7500) TCP \n"; + print `netsh advfirewall firewall add rule name="EQEmu Zones (7000-7500) TCP" dir=in action=allow protocol=TCP localport=7000-7500`; + print "Attempting to add EQEmu Zones (7000-7500) UDP \n"; + print `netsh advfirewall firewall add rule name="EQEmu Zones (7000-7500) UDP" dir=in action=allow protocol=UDP localport=7000-7500`; + } +} + +sub fetch_server_dlls{ + print "Fetching lua51.dll, zlib1.dll, libmysql.dll...\n"; + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/lua51.dll", "lua51.dll", 1); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/zlib1.dll", "zlib1.dll", 1); + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/libmysql.dll", "libmysql.dll", 1); +} + +sub fetch_peq_db_full{ + print "Downloading latest PEQ Database... Please wait...\n"; + get_remote_file("http://edit.peqtgc.com/weekly/peq_beta.zip", "updates_staged/peq_beta.zip", 1); + print "Downloaded latest PEQ Database... Extracting...\n"; + unzip('updates_staged/peq_beta.zip', 'updates_staged/peq_db/'); + my $start_dir = "updates_staged\\peq_db"; + find( + sub { push @files, $File::Find::name unless -d; }, + $start_dir + ); + for my $file (@files) { + $dest_file = $file; + $dest_file =~s/updates_staged\\peq_db\///g; + if($file=~/peqbeta|player_tables/i){ + print "MariaDB :: Installing :: " . $dest_file . "\n"; + get_mysql_result_from_file($file); + } + if($file=~/eqtime/i){ + print "Installing eqtime.cfg\n"; + copy_file($file, "eqtime.cfg"); + } + } +} + +sub map_files_fetch_bulk{ + print "\n --- Fetching Latest Maps... (This could take a few minutes...) --- \n"; + get_remote_file("http://github.com/Akkadius/EQEmuMaps/archive/master.zip", "maps/maps.zip", 1); + unzip('maps/maps.zip', 'maps/'); + my @files; + my $start_dir = "maps\\EQEmuMaps-master\\maps"; + find( + sub { push @files, $File::Find::name unless -d; }, + $start_dir + ); + for my $file (@files) { + $dest_file = $file; + $dest_file =~s/maps\\EQEmuMaps-master\\maps\///g; + print "Installing :: " . $dest_file . "\n"; + copy_file($file, "maps/" . $new_file); + } + print "\n --- Fetched Latest Maps... --- \n"; + + rmtree('maps/EQEmuMaps-master'); + unlink('maps/maps.zip'); +} + +sub map_files_fetch{ + print "\n --- Fetching Latest Maps --- \n"; + + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuMaps/master/!eqemu_maps_manifest.txt", "updates_staged/eqemu_maps_manifest.txt"); + + #::: Get Data from manifest + open (FILE, "updates_staged/eqemu_maps_manifest.txt"); + $i = 0; + while (){ + chomp; + $o = $_; + @manifest_map_data = split(',', $o); + if($manifest_map_data[0] ne ""){ + $maps_manifest[$i] = [$manifest_map_data[0], $manifest_map_data[1]]; + $i++; + } + } + + #::: Download + $fc = 0; + for($m = 0; $m <= $i; $m++){ + my $file_existing = $maps_manifest[$m][0]; + my $file_existing_size = (stat $file_existing)[7]; + if($file_existing_size != $maps_manifest[$m][1]){ + print "Updating: '" . $maps_manifest[$m][0] . "'\n"; + get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuMaps/master/" . $maps_manifest[$m][0], $maps_manifest[$m][0], 1); + $fc++; + } + } + + if($fc == 0){ + print "\nNo Map Updates found... \n\n"; + } +} + +sub quest_files_fetch{ + if (!-e "updates_staged/Quests-Plugins-master/quests/") { + print "\n --- Fetching Latest Quests --- \n"; + get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1); + print "\nFetched latest quests...\n"; + mkdir('updates_staged'); + unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/'); + } + + $fc = 0; + use File::Find; + use File::Compare; + + my @files; + my $start_dir = "updates_staged/Quests-Plugins-master/quests/"; + find( + sub { push @files, $File::Find::name unless -d; }, + $start_dir + ); + for my $file (@files) { + if($file=~/\.pl|\.lua|\.ext/i){ + $staged_file = $file; + $dest_file = $file; + $dest_file =~s/updates_staged\/Quests-Plugins-master\///g; + + if (!-e $dest_file) { + copy_file($staged_file, $dest_file); + print "Installing :: '" . $dest_file . "'\n"; + $fc++; + } + else{ + $diff = do_file_diff($dest_file, $staged_file); + if($diff ne ""){ + $backup_dest = "updates_backups/" . $time_stamp . "/" . $dest_file; + + print $diff . "\n"; + print "\nFile Different :: '" . $dest_file . "'\n"; + print "\nDo you wish to update this Quest? '" . $dest_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n"; + my $input = ; + if($input=~/N/i){} + else{ + #::: Make a backup + copy_file($dest_file, $backup_dest); + #::: Copy staged to running + copy($staged_file, $dest_file); + print "Installing :: '" . $dest_file . "'\n\n"; + } + $fc++; + } + } + } + } + + rmtree('updates_staged'); + + if($fc == 0){ + print "\nNo Quest Updates found... \n\n"; + } +} + +sub lua_modules_fetch{ + if (!-e "updates_staged/Quests-Plugins-master/quests/lua_modules/") { + print "\n --- Fetching Latest LUA Modules --- \n"; + get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1); + print "\nFetched latest LUA Modules...\n"; + unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/'); + } + + $fc = 0; + use File::Find; + use File::Compare; + + my @files; + my $start_dir = "updates_staged/Quests-Plugins-master/quests/lua_modules/"; + find( + sub { push @files, $File::Find::name unless -d; }, + $start_dir + ); + for my $file (@files) { + if($file=~/\.pl|\.lua|\.ext/i){ + $staged_file = $file; + $dest_file = $file; + $dest_file =~s/updates_staged\/Quests-Plugins-master\/quests\///g; + + if (!-e $dest_file) { + copy_file($staged_file, $dest_file); + print "Installing :: '" . $dest_file . "'\n"; + $fc++; + } + else{ + $diff = do_file_diff($dest_file, $staged_file); + if($diff ne ""){ + $backup_dest = "updates_backups/" . $time_stamp . "/" . $dest_file; + print $diff . "\n"; + print "\nFile Different :: '" . $dest_file . "'\n"; + print "\nDo you wish to update this LUA Module? '" . $dest_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n"; + my $input = ; + if($input=~/N/i){} + else{ + #::: Make a backup + copy_file($dest_file, $backup_dest); + #::: Copy staged to running + copy($staged_file, $dest_file); + print "Installing :: '" . $dest_file . "'\n\n"; + } + $fc++; + } + } + } + } + + if($fc == 0){ + print "\nNo LUA Modules Updates found... \n\n"; + } +} + +sub plugins_fetch{ + if (!-e "updates_staged/Quests-Plugins-master/plugins/") { + print "\n --- Fetching Latest Plugins --- \n"; + get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1); + print "\nFetched latest plugins...\n"; + unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/'); + } + + $fc = 0; + use File::Find; + use File::Compare; + + my @files; + my $start_dir = "updates_staged/Quests-Plugins-master/plugins/"; + find( + sub { push @files, $File::Find::name unless -d; }, + $start_dir + ); + for my $file (@files) { + if($file=~/\.pl|\.lua|\.ext/i){ + $staged_file = $file; + $dest_file = $file; + $dest_file =~s/updates_staged\/Quests-Plugins-master\///g; + + if (!-e $dest_file) { + copy_file($staged_file, $dest_file); + print "Installing :: '" . $dest_file . "'\n"; + $fc++; + } + else{ + $diff = do_file_diff($dest_file, $staged_file); + if($diff ne ""){ + $backup_dest = "updates_backups/" . $time_stamp . "/" . $dest_file; + print $diff . "\n"; + print "\nFile Different :: '" . $dest_file . "'\n"; + print "\nDo you wish to update this Plugin? '" . $dest_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n"; + my $input = ; + if($input=~/N/i){} + else{ + #::: Make a backup + copy_file($dest_file, $backup_dest); + #::: Copy staged to running + copy($staged_file, $dest_file); + print "Installing :: '" . $dest_file . "'\n\n"; + } + $fc++; + } + } + } + } + + if($fc == 0){ + print "\nNo Plugin Updates found... \n\n"; + } +} + +sub do_file_diff{ + $file_1 = $_[0]; + $file_2 = $_[1]; + if($OS eq "Windows"){ + eval "use Text::Diff"; + $diff = diff($file_1, $file_2, { STYLE => "Unified" }); + return $diff; + } + if($OS eq "Linux"){ + # print 'diff -u "$file_1" "$file_2"' . "\n"; + return `diff -u "$file_1" "$file_2"`; + } +} + +sub unzip{ + $archive_to_unzip = $_[0]; + $dest_folder = $_[1]; + + if($OS eq "Windows"){ + eval "use Archive::Zip qw( :ERROR_CODES :CONSTANTS )"; + my $zip = Archive::Zip->new(); + unless ( $zip->read($archive_to_unzip) == AZ_OK ) { + die 'read error'; + } + print "Extracting...\n"; + $zip->extractTree('', $dest_folder); + } + if($OS eq "Linux"){ + print `unzip -o "$archive_to_unzip" -d "$dest_folder"`; + } +} + +sub are_file_sizes_different{ + $file_1 = $_[0]; + $file_2 = $_[1]; + my $file_1 = (stat $file_1)[7]; + my $file_2 = (stat $file_2)[7]; + # print $file_1 . " :: " . $file_2 . "\n"; + if($file_1 != $file_2){ + return 1; + } + return; +} + +sub do_bots_db_schema_drop{ + #"drop_bots.sql" is run before reverting database back to 'normal' + print "Fetching drop_bots.sql...\n"; + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/bots/drop_bots.sql", "db_update/drop_bots.sql"); + print get_mysql_result_from_file("db_update/drop_bots.sql"); + + print "Restoring normality...\n"; + print get_mysql_result("DELETE FROM `rule_values` WHERE `rule_name` LIKE 'Bots:%';"); + + if(get_mysql_result("SHOW TABLES LIKE 'commands'") ne "" && $db){ + print get_mysql_result("DELETE FROM `commands` WHERE `command` LIKE 'bot';"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'command_settings'") ne "" && $db){ + print get_mysql_result("DELETE FROM `command_settings` WHERE `command` LIKE 'bot';"); + } + + if(get_mysql_result("SHOW KEYS FROM `group_id` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){ + print get_mysql_result("ALTER TABLE `group_id` DROP PRIMARY KEY;"); + } + print get_mysql_result("ALTER TABLE `group_id` ADD PRIMARY KEY (`groupid`, `charid`, `ismerc`);"); + + if(get_mysql_result("SHOW KEYS FROM `guild_members` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){ + print get_mysql_result("ALTER TABLE `guild_members` DROP PRIMARY KEY;"); + } + print get_mysql_result("ALTER TABLE `guild_members` ADD PRIMARY KEY (`char_id`);"); + + print get_mysql_result("UPDATE `spawn2` SET `enabled` = 0 WHERE `id` IN (59297,59298);"); + + if(get_mysql_result("SHOW COLUMNS FROM `db_version` LIKE 'bots_version'") ne "" && $db){ + print get_mysql_result("UPDATE `db_version` SET `bots_version` = 0;"); + } +} + +sub modify_db_for_bots{ + #Called after the db bots schema (2015_09_30_bots.sql) has been loaded + print "Modifying database for bots...\n"; + print get_mysql_result("UPDATE `spawn2` SET `enabled` = 1 WHERE `id` IN (59297,59298);"); + + if(get_mysql_result("SHOW KEYS FROM `guild_members` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){ + print get_mysql_result("ALTER TABLE `guild_members` DROP PRIMARY KEY;"); + } + + if(get_mysql_result("SHOW KEYS FROM `group_id` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){ + print get_mysql_result("ALTER TABLE `group_id` DROP PRIMARY KEY;"); + } + print get_mysql_result("ALTER TABLE `group_id` ADD PRIMARY KEY USING BTREE(`groupid`, `charid`, `name`, `ismerc`);"); + + if(get_mysql_result("SHOW TABLES LIKE 'command_settings'") ne "" && get_mysql_result("SELECT `command` FROM `command_settings` WHERE `command` LIKE 'bot'") eq "" && $db){ + print get_mysql_result("INSERT INTO `command_settings` VALUES ('bot', '0', '');"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'commands'") ne "" && get_mysql_result("SELECT `command` FROM `commands` WHERE `command` LIKE 'bot'") eq "" && $db){ + print get_mysql_result("INSERT INTO `commands` VALUES ('bot', '0');"); + } + + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotAAExpansion'") ne "" && $db){ + print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:AAExpansion' WHERE `rule_name` LIKE 'Bots:BotAAExpansion';"); + } + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:AAExpansion'") eq "" && $db){ + print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:AAExpansion', '8', 'The expansion through which bots will obtain AAs');"); + } + + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CreateBotCount'") ne "" && $db){ + print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:CreationLimit' WHERE `rule_name` LIKE 'Bots:CreateBotCount';"); + } + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CreationLimit'") eq "" && $db){ + print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:CreationLimit', '150', 'Number of bots that each account can create');"); + } + + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotFinishBuffing'") ne "" && $db){ + print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:FinishBuffing' WHERE `rule_name` LIKE 'Bots:BotFinishBuffing';"); + } + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:FinishBuffing'") eq "" && $db){ + print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:FinishBuffing', 'false', 'Allow for buffs to complete even if the bot caster is out of mana. Only affects buffing out of combat.');"); + } + + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotGroupBuffing'") ne "" && $db){ + print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:GroupBuffing' WHERE `rule_name` LIKE 'Bots:BotGroupBuffing';"); + } + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:GroupBuffing'") eq "" && $db){ + print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:GroupBuffing', 'false', 'Bots will cast single target buffs as group buffs, default is false for single. Does not make single target buffs work for MGB.');"); + } + + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotManaRegen'") ne "" && $db){ + print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:ManaRegen' WHERE `rule_name` LIKE 'Bots:BotManaRegen';"); + } + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:ManaRegen'") eq "" && $db){ + print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:ManaRegen', '3.0', 'Adjust mana regen for bots, 1 is fast and higher numbers slow it down 3 is about the same as players.');"); + } + + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotQuest'") ne "" && $db){ + print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:QuestableSpawnLimit' WHERE `rule_name` LIKE 'Bots:BotQuest';"); + } + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:QuestableSpawnLimit'") eq "" && $db){ + print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:QuestableSpawnLimit', 'false', 'Optional quest method to manage bot spawn limits using the quest_globals name bot_spawn_limit, see: /bazaar/Aediles_Thrall.pl');"); + } + + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotSpellQuest'") ne "" && $db){ + print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:QuestableSpells' WHERE `rule_name` LIKE 'Bots:BotSpellQuest';"); + } + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:QuestableSpells'") eq "" && $db){ + print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:QuestableSpells', 'false', 'Anita Thrall\\\'s (Anita_Thrall.pl) Bot Spell Scriber quests.');"); + } + + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:SpawnBotCount'") ne "" && $db){ + print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:SpawnLimit' WHERE `rule_name` LIKE 'Bots:SpawnBotCount';"); + } + if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:SpawnLimit'") eq "" && $db){ + print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:SpawnLimit', '71', 'Number of bots a character can have spawned at one time, You + 71 bots is a 12 group raid');"); + } + + convert_existing_bot_data(); +} + +sub convert_existing_bot_data{ + if(get_mysql_result("SHOW TABLES LIKE 'bots'") ne "" && $db){ + print "Converting existing bot data...\n"; + print get_mysql_result("INSERT INTO `bot_data` (`bot_id`, `owner_id`, `spells_id`, `name`, `last_name`, `zone_id`, `gender`, `race`, `class`, `level`, `creation_day`, `last_spawn`, `time_spawned`, `size`, `face`, `hair_color`, `hair_style`, `beard`, `beard_color`, `eye_color_1`, `eye_color_2`, `drakkin_heritage`, `drakkin_tattoo`, `drakkin_details`, `ac`, `atk`, `hp`, `mana`, `str`, `sta`, `cha`, `dex`, `int`, `agi`, `wis`, `fire`, `cold`, `magic`, `poison`, `disease`, `corruption`) SELECT `BotID`, `BotOwnerCharacterID`, `BotSpellsID`, `Name`, `LastName`, `LastZoneId`, `Gender`, `Race`, `Class`, `BotLevel`, UNIX_TIMESTAMP(`BotCreateDate`), UNIX_TIMESTAMP(`LastSpawnDate`), `TotalPlayTime`, `Size`, `Face`, `LuclinHairColor`, `LuclinHairStyle`, `LuclinBeard`, `LuclinBeardColor`, `LuclinEyeColor`, `LuclinEyeColor2`, `DrakkinHeritage`, `DrakkinTattoo`, `DrakkinDetails`, `AC`, `ATK`, `HP`, `Mana`, `STR`, `STA`, `CHA`, `DEX`, `_INT`, `AGI`, `WIS`, `FR`, `CR`, `MR`, `PR`, `DR`, `Corrup` FROM `bots`;"); + + print get_mysql_result("INSERT INTO `bot_inspect_messages` (`bot_id`, `inspect_message`) SELECT `BotID`, `BotInspectMessage` FROM `bots`;"); + + print get_mysql_result("RENAME TABLE `bots` TO `bots_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'botstances'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_stances` (`bot_id`, `stance_id`) SELECT bs.`BotID`, bs.`StanceID` FROM `botstances` bs INNER JOIN `bot_data` bd ON bs.`BotID` = bd.`bot_id`;"); + + print get_mysql_result("RENAME TABLE `botstances` TO `botstances_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'bottimers'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) SELECT bt.`BotID`, bt.`TimerID`, bt.`Value` FROM `bottimers` bt INNER JOIN `bot_data` bd ON bt.`BotID` = bd.`bot_id`;"); + + print get_mysql_result("RENAME TABLE `bottimers` TO `bottimers_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'botbuffs'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_buffs` (`buffs_index`, `bot_id`, `spell_id`, `caster_level`, `duration_formula`, `tics_remaining`, `poison_counters`, `disease_counters`, `curse_counters`, `corruption_counters`, `numhits`, `melee_rune`, `magic_rune`, `persistent`) SELECT bb.`BotBuffId`, bb.`BotId`, bb.`SpellId`, bb.`CasterLevel`, bb.`DurationFormula`, bb.`TicsRemaining`, bb.`PoisonCounters`, bb.`DiseaseCounters`, bb.`CurseCounters`, bb.`CorruptionCounters`, bb.`HitCount`, bb.`MeleeRune`, bb.`MagicRune`, bb.`Persistent` FROM `botbuffs` bb INNER JOIN `bot_data` bd ON bb.`BotId` = bd.`bot_id`;"); + + if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'dot_rune'") ne "" && $db){ + print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`dot_rune` = bbo.`dot_rune` WHERE bb.`bot_id` = bbo.`BotID`;"); + } + + if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'caston_x'") ne "" && $db){ + print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`caston_x` = bbo.`caston_x` WHERE bb.`bot_id` = bbo.`BotID`;"); + } + + if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'caston_y'") ne "" && $db){ + print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`caston_y` = bbo.`caston_y` WHERE bb.`bot_id` = bbo.`BotID`;"); + } + + if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'caston_z'") ne "" && $db){ + print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`caston_z` = bbo.`caston_z` WHERE bb.`bot_id` = bbo.`BotID`;"); + } + + if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'ExtraDIChance'") ne "" && $db){ + print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`extra_di_chance` = bbo.`ExtraDIChance` WHERE bb.`bot_id` = bbo.`BotID`;"); + } + + print get_mysql_result("RENAME TABLE `botbuffs` TO `botbuffs_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'botinventory'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_inventories` (`inventories_index`, `bot_id`, `slot_id`, `item_id`, `inst_charges`, `inst_color`, `inst_no_drop`, `augment_1`, `augment_2`, `augment_3`, `augment_4`, `augment_5`) SELECT bi.`BotInventoryID`, bi.`BotID`, bi.`SlotID`, bi.`ItemID`, bi.`charges`, bi.`color`, bi.`instnodrop`, bi.`augslot1`, bi.`augslot2`, bi.`augslot3`, bi.`augslot4`, bi.`augslot5` FROM `botinventory` bi INNER JOIN `bot_data` bd ON bi.`BotID` = bd.`bot_id`;"); + + if(get_mysql_result("SHOW COLUMNS FROM `botinventory` LIKE 'augslot6'") ne "" && $db){ + print get_mysql_result("UPDATE `bot_inventories` bi INNER JOIN `botinventory` bio ON bi.`inventories_index` = bio.`BotInventoryID` SET bi.`augment_6` = bio.`augslot6` WHERE bi.`bot_id` = bio.`BotID`;"); + } + + print get_mysql_result("RENAME TABLE `botinventory` TO `botinventory_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'botpets'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_pets` (`pets_index`, `pet_id`, `bot_id`, `name`, `mana`, `hp`) SELECT bp.`BotPetsId`, bp.`PetId`, bp.`BotId`, bp.`Name`, bp.`Mana`, bp.`HitPoints` FROM `botpets` bp INNER JOIN `bot_data` bd ON bp.`BotId` = bd.`bot_id`;"); + + print get_mysql_result("RENAME TABLE `botpets` TO `botpets_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'botpetbuffs'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_pet_buffs` (`pet_buffs_index`, `pets_index`, `spell_id`, `caster_level`, `duration`) SELECT bpb.`BotPetBuffId`, bpb.`BotPetsId`, bpb.`SpellId`, bpb.`CasterLevel`, bpb.`Duration` FROM `botpetbuffs` bpb INNER JOIN `bot_pets` bp ON bpb.`BotPetsId` = bp.`pets_index`;"); + + print get_mysql_result("RENAME TABLE `botpetbuffs` TO `botpetbuffs_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'botpetinventory'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_pet_inventories` (`pet_inventories_index`, `pets_index`, `item_id`) SELECT bpi.`BotPetInventoryId`, bpi.`BotPetsId`, bpi.`ItemId` FROM `botpetinventory` bpi INNER JOIN `bot_pets` bp ON bpi.`BotPetsId` = bp.`pets_index`;"); + + print get_mysql_result("RENAME TABLE `botpetinventory` TO `botpetinventory_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'botgroup'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_groups` (`groups_index`, `group_leader_id`, `group_name`) SELECT bg.`BotGroupId`, bg.`BotGroupLeaderBotId`, bg.`BotGroupName` FROM `botgroup` bg INNER JOIN `bot_data` bd ON bg.`BotGroupLeaderBotId` = bd.`bot_id`;"); + + print get_mysql_result("RENAME TABLE `botgroup` TO `botgroup_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'botgroupmembers'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_group_members` (`group_members_index`, `groups_index`, `bot_id`) SELECT bgm.`BotGroupMemberId`, bgm.`BotGroupId`, bgm.`BotId` FROM `botgroupmembers` bgm INNER JOIN `bot_groups` bg ON bgm.`BotGroupId` = bg.`groups_index` INNER JOIN `bot_data` bd ON bgm.`BotId` = bd.`bot_id`;"); + + print get_mysql_result("RENAME TABLE `botgroupmembers` TO `botgroupmembers_old`;"); + } + + if(get_mysql_result("SHOW TABLES LIKE 'botguildmembers'") ne "" && $db){ + print get_mysql_result("INSERT INTO `bot_guild_members` (`bot_id`, `guild_id`, `rank`, `tribute_enable`, `total_tribute`, `last_tribute`, `banker`, `public_note`, `alt`) SELECT bgm.`char_id`, bgm.`guild_id`, bgm.`rank`, bgm.`tribute_enable`, bgm.`total_tribute`, bgm.`last_tribute`, bgm.`banker`, bgm.`public_note`, bgm.`alt` FROM `botguildmembers` bgm INNER JOIN `guilds` g ON bgm.`guild_id` = g.`id` INNER JOIN `bot_data` bd ON bgm.`char_id` = bd.`bot_id`;"); + + print get_mysql_result("RENAME TABLE `botguildmembers` TO `botguildmembers_old`;"); + } +} + +sub get_bots_db_version{ + #::: Check if bots_version column exists... + if(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'bots_version'") eq "" && $db){ + print get_mysql_result("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version;"); + print "\nColumn 'bots_version' does not exists.... Adding to 'db_version' table...\n\n"; + } + $bots_local_db_version = trim(get_mysql_result("SELECT bots_version FROM db_version LIMIT 1")); + return $bots_local_db_version; +} + +sub bots_db_management{ + #::: Main Binary Database version + $bin_db_ver = trim($db_version[2]); + + #::: If we have stale data from main db run + if($db_run_stage > 0 && $bots_db_management == 0){ + clear_database_runs(); + } + + if($bin_db_ver == 0){ + print "Your server binaries (world/zone) are not compiled for bots...\n"; + return; + } + + #::: Set on flag for running bot updates... + $bots_db_management = 1; + + $bots_local_db_version = get_bots_db_version(); + + run_database_check(); +} + +sub main_db_management{ + #::: If we have stale data from bots db run + if($db_run_stage > 0 && $bots_db_management == 1){ + clear_database_runs(); + } + + #::: Main Binary Database version + $bin_db_ver = trim($db_version[1]); + + $bots_db_management = 0; + run_database_check(); +} + +sub clear_database_runs{ + # print "DEBUG :: clear_database_runs\n\n"; + #::: Clear manifest data... + %m_d = (); + #::: Clear updates... + @total_updates = (); + #::: Clear stage + $db_run_stage = 0; +} + #::: Responsible for Database Upgrade Routines -sub Run_Database_Check{ +sub run_database_check{ + + if(!$db){ + print "No database present, check your eqemu_config.xml for proper MySQL/MariaDB configuration...\n"; + return; + } + + if(!@total_updates){ + #::: Pull down bots database manifest + if($bots_db_management == 1){ + print "Retrieving latest bots database manifest...\n"; + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/bots/bots_db_update_manifest.txt", "db_update/db_update_manifest.txt"); + } + #::: Pull down mainstream database manifest + else{ + print "Retrieving latest database manifest...\n"; + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt"); + } + } + #::: Run 2 - Running pending updates... - if(defined(@total_updates)){ + if(@total_updates){ @total_updates = sort @total_updates; foreach my $val (@total_updates){ $file_name = trim($m_d{$val}[1]); print "Running Update: " . $val . " - " . $file_name . "\n"; - print GetMySQLResultFromFile("db_update/$file_name"); - print GetMySQLResult("UPDATE db_version SET version = $val WHERE version < $val"); - } - } - + print get_mysql_result_from_file("db_update/$file_name"); + print get_mysql_result("UPDATE db_version SET version = $val WHERE version < $val"); + + if($bots_db_management == 1 && $val == 9000){ + modify_db_for_bots(); + } + } + $db_run_stage = 2; + } #::: Run 1 - Initial checking of needed updates... - print "Reading manifest...\n\n"; - use Data::Dumper; - open (FILE, "db_update/db_update_manifest.txt"); - while () { - chomp; - $o = $_; - if($o=~/#/i){ next; } - @manifest = split('\|', $o); - $m_d{$manifest[0]} = [@manifest]; + else{ + print "Reading manifest...\n\n"; + use Data::Dumper; + open (FILE, "db_update/db_update_manifest.txt"); + while () { + chomp; + $o = $_; + if($o=~/#/i){ next; } + @manifest = split('\|', $o); + $m_d{$manifest[0]} = [@manifest]; + } + #::: Setting Manifest stage... + $db_run_stage = 1; } @total_updates = (); + #::: This is where we set checkpoints for where a database might be so we don't check so far back in the manifest... + $revision_check = 1000; + if(get_mysql_result("SHOW TABLES LIKE 'character_data'") ne ""){ + $revision_check = 9000; + } + #::: Iterate through Manifest backwards from binary version down to local version... - for($i = $bin_db_ver; $i > 1000; $i--){ + for($i = $bin_db_ver; $i > $revision_check; $i--){ if(!defined($m_d{$i}[0])){ next; } $file_name = trim($m_d{$i}[1]); @@ -384,9 +1431,9 @@ sub Run_Database_Check{ #::: Match type update if($match_type eq "contains"){ - if(trim(GetMySQLResult($query_check))=~/$match_text/i){ + if(trim(get_mysql_result($query_check))=~/$match_text/i){ print "Missing DB Update " . $i . " '" . $file_name . "' \n"; - FetchMissingUpdate($i, $file_name); + fetch_missing_db_update($i, $file_name); push(@total_updates, $i); } else{ @@ -396,22 +1443,22 @@ sub Run_Database_Check{ print_break(); } if($match_type eq "missing"){ - if(GetMySQLResult($query_check)=~/$match_text/i){ + if(get_mysql_result($query_check)=~/$match_text/i){ print "DB up to date with: " . $i . " - '" . $file_name . "' \n"; next; } else{ print "Missing DB Update " . $i . " '" . $file_name . "' \n"; - FetchMissingUpdate($i, $file_name); + fetch_missing_db_update($i, $file_name); push(@total_updates, $i); } print_match_debug(); print_break(); } if($match_type eq "empty"){ - if(GetMySQLResult($query_check) eq ""){ + if(get_mysql_result($query_check) eq ""){ print "Missing DB Update " . $i . " '" . $file_name . "' \n"; - FetchMissingUpdate($i, $file_name); + fetch_missing_db_update($i, $file_name); push(@total_updates, $i); } else{ @@ -421,9 +1468,9 @@ sub Run_Database_Check{ print_break(); } if($match_type eq "not_empty"){ - if(GetMySQLResult($query_check) ne ""){ + if(get_mysql_result($query_check) ne ""){ print "Missing DB Update " . $i . " '" . $file_name . "' \n"; - FetchMissingUpdate($i, $file_name); + fetch_missing_db_update($i, $file_name); push(@total_updates, $i); } else{ @@ -433,23 +1480,36 @@ sub Run_Database_Check{ print_break(); } } - print "\n"; + print "\n"; - if(scalar (@total_updates) == 0){ + if(scalar (@total_updates) == 0 && $db_run_stage == 2){ print "No updates need to be run...\n"; - print "Setting Database to Binary Version (" . $bin_db_ver . ") if not already...\n\n"; - GetMySQLResult("UPDATE db_version SET version = $bin_db_ver"); + if($bots_db_management == 1){ + print "Setting Database to Bots Binary Version (" . $bin_db_ver . ") if not already...\n\n"; + get_mysql_result("UPDATE db_version SET bots_version = $bin_db_ver"); + } + else{ + print "Setting Database to Binary Version (" . $bin_db_ver . ") if not already...\n\n"; + get_mysql_result("UPDATE db_version SET version = $bin_db_ver"); + } + + clear_database_runs(); } } -sub FetchMissingUpdate{ +sub fetch_missing_db_update{ $db_update = $_[0]; $update_file = $_[1]; - if($db_update >= 9000){ - GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/required/" . $update_file, "db_update/" . $update_file . ""); + if($db_update >= 9000){ + if($bots_db_management == 1){ + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/bots/required/" . $update_file, "db_update/" . $update_file . ""); + } + else{ + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/required/" . $update_file, "db_update/" . $update_file . ""); + } } elsif($db_update >= 5000 && $db_update <= 9000){ - GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/svn/" . $update_file, "db_update/" . $update_file . ""); + get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/svn/" . $update_file, "db_update/" . $update_file . ""); } } @@ -458,7 +1518,7 @@ sub print_match_debug{ print " Match Type: '" . $match_type . "'\n"; print " Match Text: '" . $match_text . "'\n"; print " Query Check: '" . $query_check . "'\n"; - print " Result: '" . trim(GetMySQLResult($query_check)) . "'\n"; + print " Result: '" . trim(get_mysql_result($query_check)) . "'\n"; } sub print_break{ if(!$debug){ return; } diff --git a/utils/scripts/import_13th_floor.pl b/utils/scripts/import_13th_floor.pl new file mode 100644 index 000000000..6a66892f9 --- /dev/null +++ b/utils/scripts/import_13th_floor.pl @@ -0,0 +1,255 @@ +#! /usr/bin/perl + +######################################################################## +#::: 13th floor import script +#::: Current Source: http://items.sodeq.org/download.php +#::: Authors: (Natedog, Akkadius) +######################################################################## + +use DBI; +use DBD::mysql; + +my $database_name = ""; +my $total_items = 0; +my $read_items_file = "items.txt"; #default +my $dbh = LoadMysql(); + +read_items_file_from_13th_floor_text(); +update_items_table(); + +sub LoadMysql{ + #::: Config Variables + my $confile = "eqemu_config.xml"; + open(F, "<$confile") or die "Unable to open config: $confile\n"; + my $indb = 0; + while() { + s/\r//g; + if(//i) { $indb = 1; } + next unless($indb == 1); + if(/<\/database>/i) { $indb = 0; last; } + if(/(.*)<\/host>/i) { $host = $1; } + elsif(/(.*)<\/username>/i) { $user = $1; } + elsif(/(.*)<\/password>/i) { $pass = $1; } + elsif(/(.*)<\/db>/i) { $db = $1; } + } + $database_name = $db; + #::: DATA SOURCE NAME + $dsn = "dbi:mysql:$db:localhost:3306"; + #::: PERL DBI CONNECT + $connect = DBI->connect($dsn, $user, $pass); + return $connect; +} + +sub read_items_file_from_13th_floor_text { + + #::: Read from file and place into array + open(F, "<" . $read_items_file) or die "Unable to open itemfile: " . $read_items_file . "\n"; + my @item_file_lines = ; + close(F); + + #::: Chomp this array... + my @newitem_file_lines; + chomp($item_file_lines[0]); + @fields = split("(?prepare("SHOW TABLES LIKE 'items_floor'"); + $sth->execute(); + my $has_items_floor = $sth->fetchrow_array(); + + #::: If we have items_floor + if ($has_items_floor eq '') { + $dbh->do("CREATE TABLE `items_floor` (`" . join("` VARCHAR(64) NOT NULL DEFAULT '', `", @fields). "` VARCHAR(64) NOT NULL DEFAULT '', UNIQUE INDEX `ID` (`id`)) COLLATE='latin1_swedish_ci' ENGINE=MyISAM"); + $dbh->do("ALTER TABLE `items_floor` CHANGE `id` `id` INT(11) NOT NULL DEFAULT '0'"); + printf "Database items_floor created\n"; + } + + #::: Create REPLACE INTO header and define worker variables... + $master_insert = "REPLACE INTO `items_floor` (" . join(",", @fields) . ") VALUES "; + $query_insert_ph = ""; #::: Used for building placeholder values in query Ex: (?, ?, ?) + @field_values = (); #::: Used for stuffing mysql field values + $query_count = 0; #::: Used for chunking query updates + $print_cycle = 0; #::: Counter for console updates + $start_time = time(); #::: Start time for import + $total_items_file = scalar(grep $_, @item_file_lines) - 1; #::: Total items in text file + + #::: Iterate through each item in items.txt + for (1 .. $#item_file_lines) { + @f = split("(? 500){ + $query_insert_ph = substr($query_insert_ph, 0, -2); + $dbh->prepare($master_insert . " " . $query_insert_ph)->execute(@field_values); + $query_count = 0; + $query_insert_ph = ""; + @field_values = (); + } + + #::: Print updates to console + if($print_cycle > 25){ + print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r"; + $print_cycle = 0; + } + + #::: Counters + $total_items++; + $query_count++; + $print_cycle++; + } + + #::: One last processing print + print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r"; + + printf "\n" . $total_items . " items added to database... Took " . (time() - $start_time) . " second(s)... \n"; + + print "Flipping slots 21 and 22..."; + $rows_affected = $dbh->prepare(" + UPDATE `items_floor` + SET `slots` = (`slots` ^ 6291456) + WHERE (`slots` & 6291456) + IN (2097152, 4194304)")->execute(); + print " Rows affected (" . $rows_affected . ")\n"; +} + +sub update_items_table { + + #::: Keep Items table sane + $query_handle = $dbh->prepare(" + ALTER TABLE `items` + MODIFY COLUMN `UNK132` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL; + "); + $query_handle->execute(); + + my @matching_table; + my @missing_items_table; + my @missing_items_floor_table; + + #::: Get columns from `items` + my $sth = $dbh->prepare("SHOW COLUMNS FROM `items`;"); + $sth->execute(); + my @items_table; + while (my @row = $sth->fetchrow_array()) { + push(@items_table, $row[0]); + } + + #::: Get columns from `items_floor` + $sth2 = $dbh->prepare("SHOW COLUMNS FROM `items_floor`"); + $sth2->execute(); + my @items_floor_table; + while (my @row = $sth2->fetchrow_array()) { + push(@items_floor_table, $row[0]); + } + + #::: Go through the original items table columns and line them up with what columns match on 13th floor + #::: This is so we can use the matching columns to update and insert item data into `items` table + foreach $value (@items_table) { + if ( grep( /^$value$/i, @items_floor_table ) ) { + push(@matching_table, $value); + } else { + #::: What values are we missing from EMU items table.. + push(@missing_items_table, $value); + } + } + + #::: What values are we missing from.. 13thFloor + foreach $value (@items_floor_table) { + if ( grep( /^$value$/i, @items_table ) ) { + #DO NOTHING... + } else { + push(@missing_items_floor_table, $value); + } + } + + #::: Go through the matched columns and build our query strings... + + my $items_field_list = ""; #::: Build the field list for the INSERT (field1, field2) + my $items_floor_field_list = ""; #::: What fields we will select from items_floor table to insert into items (matched columns) + my $update_fields = ""; #::: To update an existing item entry if it exists... + + foreach $match (@matching_table) { + $match = lc($match); + $update_fields .= "`" . $match . "` = fi.`" . $match . "`, "; + $items_field_list .= "`" . $match . "`, "; + $items_floor_field_list .= "fi.`" . $match . "`, "; + } + #::: Trim ', ' off the ends + $update_fields = substr($update_fields, 0, -2); + $items_field_list = substr($items_field_list, 0, -2); + $items_floor_field_list = substr($items_floor_field_list, 0, -2); + + #::: Mixed up fields... + $items_floor_field_list =~ s/booktype/booklang/g; #our booktype is mixed with theirs... + $update_fields =~ s/`booktype` = fi.`booktype`/`booktype` = fi.`booklang`/g; + + #::: FIELDS THAT DO NOT MATCH GO HERE + my @items_add = ( + "casttime_", "endur", "range", "attuneable", "evolvinglevel", "herosforgemodel", "scrolltype", + "scriptfileid", "powersourcecapacity", "augslot1unk2", "augslot2unk2", "augslot3unk2", "augslot4unk2", + "augslot5unk2", "augslot6unk2", "recskill", "book" + ); + my @items_floor_add = ( + "foodduration", "endurance", "therange", "attunable", "evolvl", "heroforge1", "scrolleffecttype", + "rightclickscriptid", "powersourcecap", "augslot1unk", "augslot2unk", "augslot3unk", "augslot4unk", + "augslot5unk", "augslot6unk", "reqskill", "booktype" + ); + + #::: Match the mis-matched fields... + my $spot = 0; + foreach $value (@items_add) { + $items_field_list .= ", `" . $value . "`"; + $update_fields .= ", `" . $value . "` = fi.`" . $items_floor_add[$spot] . "`"; + $spot++; + @missing_items_table = grep {$_ ne $value} @missing_items_table; + } + foreach $value (@items_floor_add) { + $items_floor_field_list .= ", fi.`" . $value . "`"; + @missing_items_floor_table = grep {$_ ne $value} @missing_items_floor_table; + } + + my $update_query = " + INSERT INTO items (" . $items_field_list . ") + SELECT " . $items_floor_field_list . " + FROM items_floor fi + ON DUPLICATE KEY UPDATE " . $update_fields; + + #::: Print missing fields to file + my $write_file = "missing_item_fields.txt"; + + open(F, ">$write_file") or die "Unable to open questfile: $write_file\n"; + print F "$update_query \n\n"; + print F "EQEMU items Table missing fields\n"; + foreach $value (@missing_items_table) { + print F "$value\n"; + } + print F "\n\n13thFloor items Table missing fields\n"; + foreach $value (@missing_items_floor_table) { + print F "$value\n"; + } + close(F); + + #::: Number of rows affected by query + $rows = $dbh->do($update_query); + + #::: Update stackables + $dbh->do("UPDATE items i SET i.stackable = 1 WHERE i.stacksize > 1"); + + print "Added all new items to Items table (" . $rows . ")!\n"; + +} + +sub trim($) { + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} \ No newline at end of file diff --git a/utils/scripts/load_13thfloor_items.pl b/utils/scripts/load_13thfloor_items.pl deleted file mode 100644 index 03fbfe5fb..000000000 --- a/utils/scripts/load_13thfloor_items.pl +++ /dev/null @@ -1,77 +0,0 @@ -#! /usr/bin/perl - -use DBI; -use Getopt::Std; - -getopts('d:h'); -$conf = "eqemu_config.xml"; -if($opt_h) { - die "Usage: load_13thfloor_items.pl [-d path/to/eqemu_config.xml]\n"; -} -if($opt_d) { - $conf = $opt_d; -} - -$db = "eq"; -$user = "eq"; -$pass = "eq"; -$host = "localhost"; -open(F, "<$conf") or die "Unable to open config $conf\n"; -$indb = 0; -while() { - s/\r//g; - if(//i) { - $indb = 1; - } - next unless($indb == 1); - if(/<\/database>/i) { - $indb = 0; - last; - } - if(/(.*)<\/host>/i) { - $host = $1; - } elsif(/(.*)<\/username>/i) { - $user = $1; - } elsif(/(.*)<\/password>/i) { - $pass = $1; - } elsif(/(.*)<\/db>/i) { - $db = $1; - } -} -if(!$db || !$user || !$pass || !$host) { - die "Invalid db.ini, missing one of: host, user, password, database\n"; -} - -$source="DBI:mysql:database=$db;host=$host"; - -my $dbh = DBI->connect($source, $user, $pass) || die "Could not create db handle\n"; - -$_=; -chomp(); -s/'/\\'/g; -@fields=split("(? "itemuse" -); - -$insert="replace into items (".join(",",@fields).",source,updated) values ('"; -$insert=~s/UNK130/potionbeltslots/; -$insert=~s/UNK133/stackable/; - -#select(STDOUT); $|=1; -while() { - chomp(); - s/'/\\'/g; - @f=split("(?do($statement); - printf("Processing: %d %s \r",$f[4],$f[1]); - ++$count; -} -printf("Processed: %d items(s) \n",$count); - diff --git a/utils/scripts/opcode_handlers.py b/utils/scripts/opcode_handlers.py index ce0e955a3..fb3923209 100644 --- a/utils/scripts/opcode_handlers.py +++ b/utils/scripts/opcode_handlers.py @@ -23,7 +23,7 @@ VERBOSE = False # messaging: {False - minimal, True - robust} base_path = os.getcwd()[:-14] # '/utils/scripts' base_path = base_path.replace('\\', '/') -client_list = ['6.2', 'Titanium', 'SoF', 'SoD', 'Underfoot', 'RoF', 'RoF2'] +client_list = ['6.2', 'Titanium', 'SoF', 'SoD', 'UF', 'RoF', 'RoF2'] server_list = ['Login', 'World', 'Zone', 'UCS'] client_opcodes = {} # x[key='Client'][key='OP_CodeName'](value='0x####') @@ -248,7 +248,7 @@ def loadclientopcodes(): for client in client_list: try: - short_name = '/patch_{0}.conf'.format(client).lower() + short_name = '/patch_{0}.conf'.format(client) file_name = '{0}/utils/patches{1}'.format( base_path, @@ -745,6 +745,7 @@ def discoverserverhandlers(): locations['Zone'].append('/zone/aa.cpp') locations['Zone'].append('/zone/attack.cpp') locations['Zone'].append('/zone/bot.cpp') + locations['Zone'].append('/zone/bot_command.cpp') locations['Zone'].append('/zone/client.cpp') locations['Zone'].append('/zone/client_packet.cpp') locations['Zone'].append('/zone/client_process.cpp') diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 2ad0b647c..283500c3b 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -1,261 +1,261 @@ -5001|1_task_system.sql +5001|1_task_system.sql|SHOW TABLES LIKE 'tasks'|empty| # 5002|2_optional_maxclients.sql # 5003|14_optional_merchantlist.sql -5004|35_task_stepped.sql -5005|42_task_min_maxlevel.sql -5006|55_zone_shutdowndeleay.sql +5004|35_task_stepped.sql|SHOW COLUMNS FROM `tasks` LIKE 'stepped'|not_empty| +5005|42_task_min_maxlevel.sql|SHOW COLUMNS FROM `tasks` LIKE 'minlevel'|empty| +5006|55_zone_shutdowndeleay.sql|SHOW COLUMNS FROM `zone` LIKE 'shutdowndelay'|empty| # 5007|68_optional_character_maxexplevel.sql # 5008|103_optional_chat_rules.sql -5009|104_traps.sql +5009|104_traps.sql|SHOW COLUMNS FROM `traps` LIKE 'respawn_time'|empty| # 5010|106_optional_proc_rules.sql -5011|120_damageshieldtypes.sql -5012|125_aggrozone.sql +5011|120_damageshieldtypes.sql|SHOW TABLES LIKE 'damageshieldtypes'|empty| +# 5012|125_aggrozone.sql # 5013|127_optional_spell_rules.sql # 5014|129_optional_shared_plat_rule.sql # 5015|131_optional_combat_rules.sql -5016|133_task_repeatable.sql -5017|142_deathpeace_and_lifetap_aas.sql +5016|133_task_repeatable.sql|SHOW COLUMNS FROM `tasks` LIKE 'repeatable'|empty| +5017|142_deathpeace_and_lifetap_aas.sql|SELECT * FROM db_version WHERE version > 5016|empty| # 5018|158_optional_death_exp_loss.sql -5019|176_melody.sql -5020|189_character_.sql -5021|196_trader.sql -5022|210_undyeme.sql -5023|222_buyer.sql -5024|226_account_limiting.sql -5025|230_spells_table.sql -5026|235_horses_table.sql -5027|243_spawn_timers.sql -5028|247_mail.sql -5029|249_chatchannels.sql -5030|250_bot_spell_update.sql +# 5019|176_melody.sql +5020|189_character_.sql|SELECT * FROM db_version WHERE version >= 5020|empty| +5021|196_trader.sql|SHOW TABLES LIKE 'trader'|empty| +# 5022|210_undyeme.sql +5023|222_buyer.sql|SHOW TABLES LIKE 'buyer'|empty| +# 5024|226_account_limiting.sql +5025|230_spells_table.sql|SHOW TABLES LIKE 'spells_new'|empty| +5026|235_horses_table.sql|SHOW TABLES LIKE 'horses'|empty| +5027|243_spawn_timers.sql|SHOW TABLES LIKE 'respawn_times'|empty| +5028|247_mail.sql|SHOW TABLES LIKE 'mail'|empty| +5029|249_chatchannels.sql|SHOW TABLES LIKE 'chatchannels'|empty| +# 5030|250_bot_spell_update.sql # 5031|250_optional_bot_spell_update.sql # 5032|285_optional_bot_spell_update.sql -5033|292_augslots.sql -5034|294_merchant_logging.sql -5035|304_faction_list.sql -5036|326_aas.sql -5037|328_bot_management.sql +# 5033|292_augslots.sql|SELECT * FROM db_version WHERE version >= 5033|empty| +5034|294_merchant_logging.sql|SHOW COLUMNS FROM `eventlog` LIKE 'event_nid'|empty| +5035|304_faction_list.sql|SELECT * FROM db_version WHERE version >= 5035|empty| +5036|326_aas.sql|SELECT * FROM db_version WHERE version > 5035|empty| +# 5037|328_bot_management.sql # 5038|328_optional_bot_management.sql -5039|340_gm_ips.sql -5040|356_combat.sql -5041|360_peqzone.sql -5042|364_ranged_dist_rule.sql -5043|386_bot_save_raid.sql +5039|340_gm_ips.sql|SHOW TABLES LIKE 'gm_ips'|empty| +# 5040|356_combat.sql +# 5041|360_peqzone.sql +# 5042|364_ranged_dist_rule.sql +# 5043|386_bot_save_raid.sql # 5044|434_optional_rest_state_rules.sql -5045|447_sof_startzone_rule.sql -5046|463_altadv_vars.sql -5047|475_aa_actions.sql -5048|500_spawn2_optimization.sql -5049|503_bugs.sql -5050|518_drakkin_npc_type_features.sql -5051|524_rule_values_notes.sql -5052|527_npc_armor_tint.sql -5053|553_saylink_table.sql -5054|564_nokeyring.sql -5055|600_group_leadership.sql -5056|612_instance_changes.sql -5057|615_adventure_assassination.sql -5058|619_Adventure_Recruiter_Flavor.sql -5059|621_LDoNTraps.sql -5060|633_ucs.sql -5061|634_TrapTemplateDefaultValue.sql -5062|643_BotsTable.sql -5063|646_archery_penalty_rule.sql -5064|665_heroic_resists.sql -5065|667_titles.sql -5066|687_aa_table_changes.sql -5067|699_peqzone_rule.sql -5068|702_aashieldblock_tint_table.sql -5069|703_peqzone_rule.sql -5070|704_rules.sql -5071|710_tint_set_naming.sql -5072|721_pathing_rules.sql -5073|730_smart_delay_moving.sql -5074|731_rule_assist_notarget_self.sql -5075|732_sacrifice_rules.sql -5076|745_slow_mitigation.sql -5077|754_archery_base_damage_rule.sql -5078|755_sof_altadv_vars_updates.sql -5079|773_monk_rules.sql +# 5045|447_sof_startzone_rule.sql +# 5046|463_altadv_vars.sql +# 5047|475_aa_actions.sql +5048|500_spawn2_optimization.sql|SELECT * FROM db_version WHERE version >= 5048|empty| +5049|503_bugs.sql|SHOW TABLES LIKE 'bugs'|empty| +5050|518_drakkin_npc_type_features.sql|SHOW TABLES LIKE 'bugs'|empty| +5051|524_rule_values_notes.sql|SELECT * FROM db_version WHERE version >= 5051|empty| +5052|527_npc_armor_tint.sql|SELECT * FROM db_version WHERE version >= 5052|empty| +5053|553_saylink_table.sql|SHOW TABLES LIKE 'saylink'|empty| +5054|564_nokeyring.sql|SHOW COLUMNS FROM `doors` LIKE 'nokeyring'|empty| +5055|600_group_leadership.sql|SELECT * FROM db_version WHERE version >= 5055|empty| +5056|612_instance_changes.sql|SELECT * FROM db_version WHERE version >= 5056|empty| +5057|615_adventure_assassination.sql|SELECT * FROM db_version WHERE version >= 5057|empty| +5058|619_Adventure_Recruiter_Flavor.sql|SELECT * FROM db_version WHERE version >= 5058|empty| +5059|621_LDoNTraps.sql|SHOW TABLES LIKE 'ldon_trap_templates'|empty| +5060|633_ucs.sql|SHOW TABLES LIKE 'friends'|empty| +5061|634_TrapTemplateDefaultValue.sql|SHOW COLUMNS FROM `npc_types` LIKE 'trap_template'|empty| +# 5062|643_BotsTable.sql +# 5063|646_archery_penalty_rule.sql +5064|665_heroic_resists.sql|SELECT * FROM db_version WHERE version >= 5064|empty| +5065|667_titles.sql|SHOW TABLES LIKE 'titles'|empty| +5066|687_aa_table_changes.sql|SELECT * FROM db_version WHERE version >= 5066|empty| +# 5067|699_peqzone_rule.sql +5068|702_aashieldblock_tint_table.sql|SHOW TABLES LIKE 'npc_types_tint'|empty| +# 5069|703_peqzone_rule.sql +# 5070|704_rules.sql +5071|710_tint_set_naming.sql|SELECT * FROM db_version WHERE version >= 5071|empty| +5072|721_pathing_rules.sql|SELECT * FROM db_version WHERE version >= 5072|empty| +# 5073|730_smart_delay_moving.sql +# 5074|731_rule_assist_notarget_self.sql +# 5075|732_sacrifice_rules.sql +5076|745_slow_mitigation.sql|SELECT * FROM db_version WHERE version >= 5076|empty| +# 5077|754_archery_base_damage_rule.sql +5078|755_sof_altadv_vars_updates.sql|SELECT * FROM db_version WHERE version >= 5078|empty| +# 5079|773_monk_rules.sql # 5080|853_optional_rule_aaexp.sql # 5081|858_optional_rule_ip_limit_by_status.sql # 5082|892_optional_bots_table_mod.sql # 5083|893_optional_bots_table_mod.sql -5084|898_npc_maxlevel_scalerate.sql +5084|898_npc_maxlevel_scalerate.sql|SHOW COLUMNS FROM `npc_types` LIKE 'maxlevel'|empty| # 5085|902_optional_rule_snareflee.sql -5086|923_spawn2_enabled.sql -5087|962_hot_zone.sql -5088|964_reports.sql -5089|971_veteran_rewards.sql -5090|977_raid_npc_private_corpses.sql -5091|979_unique_spawn_by_name.sql -5092|980_account_ip.sql -5093|1022_botadventuring.sql -5094|1027_botactives.sql -5095|1030_botzoningsupport.sql -5096|1036_botbuffs.sql -5097|1038_botpetstatepersists.sql -5098|1038_grouptablesuniquecolumndefinitions.sql -5099|1039_botguilds.sql -5100|1040_DeprecatedBotRaidsSystems.sql -5101|1057_titles.sql -5102|1077_botgroups.sql -5103|1136_spell_globals.sql +5086|923_spawn2_enabled.sql|SHOW COLUMNS FROM `spawn2` LIKE 'enabled'|empty| +5087|962_hot_zone.sql|SHOW COLUMNS FROM `zone` LIKE 'hotzone'|empty| +5088|964_reports.sql|SHOW TABLES LIKE 'reports'|empty| +5089|971_veteran_rewards.sql|SHOW TABLES LIKE 'veteran_reward_templates'|empty| +5090|977_raid_npc_private_corpses.sql|SELECT * FROM db_version WHERE version >= 5090|empty| +5091|979_unique_spawn_by_name.sql|SHOW COLUMNS FROM `npc_types` LIKE 'unique_spawn_by_name'|empty| +5092|980_account_ip.sql|SHOW TABLES LIKE 'account_ip'|empty| +# 5093|1022_botadventuring.sql +# 5094|1027_botactives.sql +# 5095|1030_botzoningsupport.sql +# 5096|1036_botbuffs.sql +# 5097|1038_botpetstatepersists.sql +5098|1038_grouptablesuniquecolumndefinitions.sql|SELECT * FROM db_version WHERE version >= 5098|empty| +# 5099|1039_botguilds.sql +# 5100|1040_DeprecatedBotRaidsSystems.sql +5101|1057_titles.sql|SHOW TABLES LIKE 'player_titlesets'|empty| +# 5102|1077_botgroups.sql +5103|1136_spell_globals.sql|SHOW TABLES LIKE 'spell_globals'|empty| # 5104|1144_optional_rule_return_nodrop.sql -5105|1195_account_suspendeduntil.sql -5106|1259_npc_skill_types.sql -5107|1280_bot_augs.sql +5105|1195_account_suspendeduntil.sql|SELECT * FROM db_version WHERE version >= 5105|empty| +5106|1259_npc_skill_types.sql|SHOW COLUMNS FROM `npc_types` LIKE 'prim_melee_type'|empty| +# 5107|1280_bot_augs.sql # 5108|1290_optional_exp_loss_rule.sql -5109|1293_guild_bank.sql -5110|1379_loginserver_trusted_server.sql -5111|1392_recipe_learning.sql +5109|1293_guild_bank.sql|SHOW TABLES LIKE 'guild_bank'|empty| +# 5110|1379_loginserver_trusted_server.sql +5111|1392_recipe_learning.sql|SELECT * FROM db_version WHERE version >= 5111|empty| # 5112|1394_optional_rule_sod_hp_mana_end.sql -5113|1404_faction_list.sql +5113|1404_faction_list.sql|SELECT * FROM db_version WHERE version >= 5113|empty| # 5114|1410_optional_sod_aas_ht_and_loh.sql -5115|1436_login_server_table_fix.sql -5116|1446_allowrest_optional.sql -5117|1446_allowrest_required.sql -5118|1450_cvs.sql -5119|1451_guilds.sql -5120|1498_instance_adventure.sql -5121|1510_global_instances.sql -5122|1511_map_path_loading.sql -5123|1513_zone_points.sql -5124|1519_zone_primary_key_id.sql -5125|1542_items_table_cleanup.sql -5126|1548_nimbuseffect_required.sql -5127|1562_instanced_spawnconditions.sql -5128|1586_waypoints_optional.sql -5129|1610_tradeskill_required.sql -5130|1618_zone.sql +# 5115|1436_login_server_table_fix.sql +# 5116|1446_allowrest_optional.sql +5117|1446_allowrest_required.sql|SELECT * FROM db_version WHERE version >= 5117|empty| +# 5118|1450_cvs.sql +5119|1451_guilds.sql|SELECT * FROM db_version WHERE version >= 5119|empty| +5120|1498_instance_adventure.sql|SELECT * FROM db_version WHERE version >= 5120|empty| +5121|1510_global_instances.sql|SELECT * FROM db_version WHERE version >= 5121|empty| +5122|1511_map_path_loading.sql|SHOW COLUMNS FROM `zone` LIKE 'map_file_name'|empty| +5123|1513_zone_points.sql|SELECT * FROM db_version WHERE version >= 5123|empty| +5124|1519_zone_primary_key_id.sql|SELECT * FROM db_version WHERE version >= 5124|empty| +5125|1542_items_table_cleanup.sql|SELECT * FROM db_version WHERE version >= 5125|empty| +5126|1548_nimbuseffect_required.sql|SELECT * FROM db_version WHERE version >= 5126|empty| +5127|1562_instanced_spawnconditions.sql|SHOW TABLES LIKE 'spawn_condition_values'|empty| +# 5128|1586_waypoints_optional.sql +5129|1610_tradeskill_required.sql|SELECT * FROM db_version WHERE version >= 5129|empty| +5130|1618_zone.sql|SELECT * FROM db_version WHERE version >= 5130|empty| # 5131|1625_optional_rule_class_race_exp_bonus.sql # 5132|1672_optional_rules_respawn_window.sql # 5133|1679_optional_rules_blocked_buffs.sql -5134|1696_modify_zone_and_object_tables.sql -5135|1711_account_restricted_aa.sql +5134|1696_modify_zone_and_object_tables.sql|SELECT * FROM db_version WHERE version >= 5134|empty| +5135|1711_account_restricted_aa.sql|SHOW COLUMNS FROM `account` LIKE 'time_creation'|empty| # 5136|1717_optional_rule_bash_stun_chance.sql # 5137|1718_optional_rules_mod3s.sql # 5138|1719_optional_triggerOnCastAAs.sql # 5139|1720_optional_sql_AAs.sql -5140|1720_required_sql_AA_effects_update.sql +# 5140|1720_required_sql_AA_effects_update.sql # 5141|1721_optional_sql_drakkin_breath_update.sql -5142|1721_required_sql_altadv_vars_update.sql +# 5142|1721_required_sql_altadv_vars_update.sql # 5143|1723_optional_sql_new_stats_window_rule.sql -5144|1723_required_sql_corruption.sql +5144|1723_required_sql_corruption.sql|SELECT * FROM db_version WHERE version >= 5144|empty| # 5145|1736_optional_sql_feral_swipe.sql -5146|1737_required_sql_rule_and_aa_update.sql +# 5146|1737_required_sql_rule_and_aa_update.sql # 5147|1746_optional_sql_bot_manaregen.sql # 5148|1747_optional_HoT_zone_and_zonepoints.sql # 5149|1750_optional_sql_reflect_rule.sql # 5150|1753_optional_haste_cap_rule.sql -5151|1753_required_sql_healing_adept_aa.sql -5152|1754_required_sql_healing_adept_aa_fix.sql -5153|1755_required_sql_fear_resist_aas.sql +# 5151|1753_required_sql_healing_adept_aa.sql +# 5152|1754_required_sql_healing_adept_aa_fix.sql +# 5153|1755_required_sql_fear_resist_aas.sql # 5154|1784_optional_corpsedrag_rules.sql -5155|1786_required_update_to_aas.sql -5156|1790_required_aa_required_level_cost.sql -5157|1793_resist_adjust.sql +# 5155|1786_required_update_to_aas.sql +# 5156|1790_required_aa_required_level_cost.sql +5157|1793_resist_adjust.sql|SHOW COLUMNS FROM `npc_spells_entries` LIKE 'resist_adjust'|empty| # 5158|1799_optional_rest_regen_endurance_rule.sql -5159|1802_required_doppelganger.sql -5160|1803_required_tasks_xpreward_signed.sql -5161|1804_required_ae_melee_updates.sql +5159|1802_required_doppelganger.sql|SELECT * FROM db_version WHERE version >= 5159|empty| +5160|1803_required_tasks_xpreward_signed.sql|SELECT * FROM db_version WHERE version >= 5160|empty| +5161|1804_required_ae_melee_updates.sql|SELECT * FROM db_version WHERE version >= 5161|empty| # 5162|1809_optional_rules.sql -5163|1813_required_doppelganger_npcid_change.sql +5163|1813_required_doppelganger_npcid_change.sql|SELECT * FROM db_version WHERE version >= 5163|empty| # 5164|1817_optional_npc_archery_bonus_rule.sql # 5165|1823_optional_delay_death.sql -5166|1847_required_doors_dest_zone_size_32.sql +5166|1847_required_doors_dest_zone_size_32.sql|SELECT * FROM db_version WHERE version >= 5166|empty| # 5167|1859_optional_item_casts_use_focus_rule.sql # 5168|1884_optional_bot_spells_update.sql # 5169|1885_optional_rules_fv_pvp_expansions.sql # 5170|1889_optional_skill_cap_rule.sql -5171|1908_required_npc_types_definitions.sql +5171|1908_required_npc_types_definitions.sql|SHOW COLUMNS FROM `npc_types` LIKE 'attack_count'|empty| # 5172|1926_optional_stat_cap.sql -5173|1944_spawn2.sql -5174|1946_doors.sql +5173|1944_spawn2.sql|SHOW COLUMNS FROM `spawn2` LIKE 'animation'|empty| +5174|1946_doors.sql|SELECT * FROM db_version WHERE version >= 5166|empty| # 5175|1960_optional_console_timeout_rule.sql # 5176|1962_optional_guild_creation_window_rules.sql # 5177|1963_optional_rule_live_like_focuses.sql # 5178|1968_optional_enrage_rules.sql # 5179|1972_optional_extradmg_item_cap.sql -5180|1974_required_bot_spells_update.sql -5181|1977_underwater.sql +# 5180|1974_required_bot_spells_update.sql +5181|1977_underwater.sql|SHOW COLUMNS FROM `npc_types` LIKE 'underwater'|empty| # 5182|1998_optional_intoxication_and_looting_rules.sql -5183|2004_charges_alt_currency.sql +5183|2004_charges_alt_currency.sql|SHOW TABLES LIKE 'alternate_currency'|empty| # 5184|2015_optional_specialization_training_rule.sql # 5185|2016_optional_rule_bot_aa_expansion.sql # 5186|2023_optional_mysqlcli.sql # 5187|2024_optional_update_crystals.sql -5188|2024_required_update.sql -5189|2057_required_discovered_items.sql +5188|2024_required_update.sql|SHOW TABLES LIKE 'char_create_combinations'|empty| +5189|2057_required_discovered_items.sql|SHOW TABLES LIKE 'discovered_items'|empty| # 5190|2058_optional_rule_discovered_items.sql -5191|2062_required_version_changes.sql -5192|2069_required_pets.sql -5193|2079_player_speech.sql -5194|2087_required_bots_hp_and_mana_and_spell_updates.sql -5195|2098_required_zonepoint_version_changes.sql -5196|2099_required_discovered_items_account_status.sql -5197|2104_required_group_roles.sql -5198|2107_required_bot_stances.sql -5199|2129_required_lfguild.sql -5200|2133_required_faction_loot_despawn.sql -5201|2136_extended_targets.sql -5202|2142_emotes.sql +5191|2062_required_version_changes.sql|SELECT * FROM db_version WHERE version >= 5191|empty| +5192|2069_required_pets.sql|SHOW TABLES LIKE 'pets_equipmentset'|empty| +# 5193|2079_player_speech.sql +# 5194|2087_required_bots_hp_and_mana_and_spell_updates.sql +5195|2098_required_zonepoint_version_changes.sql|SELECT * FROM db_version WHERE version >= 5195|empty| +5196|2099_required_discovered_items_account_status.sql|SELECT * FROM db_version WHERE version >= 5196|empty| +5197|2104_required_group_roles.sql|SELECT * FROM db_version WHERE version >= 5197|empty| +# 5198|2107_required_bot_stances.sql +5199|2129_required_lfguild.sql|SHOW TABLES LIKE 'lfguild'|empty| +5200|2133_required_faction_loot_despawn.sql|SELECT * FROM db_version WHERE version >= 5200|empty| +5201|2136_extended_targets.sql|SELECT * FROM db_version WHERE version >= 5201|empty| +5202|2142_emotes.sql|SELECT * FROM db_version WHERE version >= 5202|empty| # 5203|2154_optional_rule_spell_procs_resists_falloff.sql # 5204|2156_optional_charm_break_rule.sql # 5205|2159_optional_defensiveproc_rules.sql -5206|2164_require_bots_bottimers.sql +# 5206|2164_require_bots_bottimers.sql # 5207|2171_optional_SpecialAttackACBonus_rule.sql # 5208|2176_optional_aa_expansion_SOF_fix.sql # 5209|2176_optional_FrenzyBonus_rule.sql -5210|2176_required_aa_updates.sql -5211|2178_required_aa_updates.sql +5210|2176_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5210|empty| +5211|2178_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5211|empty| # 5212|2183_optional_bot_xp_rule.sql # 5213|2185_optional_NPCFlurryChacne_rule # 5214|2185_optional_NPCFlurryChacne_rule.sql # 5215|2185_optional_NPCFlurryChance_rule.sql -5216|2185_required_aa_updates -5217|2185_required_aa_updates.sql +5216|2185_required_aa_updates|SELECT * FROM db_version WHERE version >= 5216|empty| +5217|2185_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5217|empty| # 5218|2188_optional_miscspelleffect_rules # 5219|2188_optional_miscspelleffect_rules.sql -5220|2188_required_aa_updates -5221|2188_required_aa_updates.sql +# 5220|2188_required_aa_updates +5221|2188_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5221|empty| # 5222|2189_optional_taunt_rules # 5223|2189_optional_taunt_rules.sql -5224|2195_required_sharedplatupdates.sql +5224|2195_required_sharedplatupdates.sql|SELECT * FROM db_version WHERE version >= 5224|empty| # 5225|2208_optional_aa_stacking_rule.sql # 5226|2208_optional_EnableSoulAbrasionAA.sql -5227|2208_required_aa_updates.sql +5227|2208_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5227|empty| # 5228|2209_optional_additive_bonus_rule.sql -5229|2213_loot_changes.sql -5230|2214_faction_list_mod.sql -5231|2215_required_aa_updates.sql +5229|2213_loot_changes.sql|SELECT * FROM db_version WHERE version >= 5229|empty| +5230|2214_faction_list_mod.sql|SHOW TABLES LIKE 'faction_list_mod'|empty| +5231|2215_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5231|empty| # 5232|2243_optional_char_max_level_rule.sql -5233|2260_probability.sql -5234|2262_required_pet_discipline_update.sql -5235|2264_required_aa_updates.sql -5236|2268_QueryServ.sql -5237|2268_required_updates.sql +# 5233|2260_probability.sql +5234|2262_required_pet_discipline_update.sql|SELECT * FROM db_version WHERE version >= 5234|empty| +5235|2264_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5235|empty| +# 5236|2268_QueryServ.sql +5237|2268_required_updates.sql|SELECT * FROM db_version WHERE version >= 5237|empty| # 5238|2274_optional_rule_iplimitdisconnectall.sql # 5239|2278_optional_rule_targetableswarmpet.sql # 5240|2280_optional_rule_targetableswarmpet-rename.sql -5241|2283_required_npc_changes.sql -5242|2299_required_inspectmessage_fields.sql +5241|2283_required_npc_changes.sql|SHOW COLUMNS FROM `npc_types` LIKE 'spellscale'|empty| +5242|2299_required_inspectmessage_fields.sql|SELECT * FROM db_version WHERE version >= 5242|empty| # 5243|2300_optional_loot_changes.sql -5244|2304_QueryServ.sql -5245|2340_required_maxbuffslotspet.sql -5246|2361_QueryServ.sql -5247|2361_required_qs_rule_values.sql -5248|2370_required_aa_updates.sql -5249|2376_required_aa_updates.sql -# 5250|2380_optional_merc_data.sql -# 5251|2380_optional_merc_merchant_npctypes_update.sql -# 5252|2380_optional_merc_rules.sql -5253|2383_required_group_ismerc.sql +# 5244|2304_QueryServ.sql +# 5245|2340_required_maxbuffslotspet.sql +# 5246|2361_QueryServ.sql +# 5247|2361_required_qs_rule_values.sql +5248|2370_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5248|empty| +5249|2376_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5249|empty| +5250|2380_optional_merc_data.sql|SELECT * FROM db_version WHERE version >= 5250|empty| +5251|2380_optional_merc_merchant_npctypes_update.sql|SELECT * FROM db_version WHERE version >= 5251|empty| +5252|2380_optional_merc_rules.sql|SELECT * FROM db_version WHERE version >= 5252|empty| +5253|2383_required_group_ismerc.sql|SELECT * FROM db_version WHERE version >= 5253|empty| # 5254|2428_optional_levelbasedexpmods.sql # 5255|2448_optional_stun_proc_aggro_rule.sql -5256|2471_required_aa_updates.sql -5257|2482_required_start_zones.sql -5258|2504_required_aa_updates.sql +5256|2471_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5256|empty| +5257|2482_required_start_zones.sql|SELECT * FROM db_version WHERE version >= 5257|empty| +5258|2504_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5258|empty| 8000|mercs.sql|SHOW TABLES LIKE 'merc_stats'|empty| 9000|2013_02_18_Merc_Rules_and_Tables.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Mercs:ResurrectRadius%'|empty| 9001|2013_02_25_Impr_HT_LT.sql|SHOW TABLES LIKE 'merc_inventory'|empty| @@ -331,9 +331,29 @@ 9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty| 9076|2015_02_04_average_coin.sql|SHOW COLUMNS FROM `loottable` WHERE Field = 'avgcoin'|contains|smallint 9077|2015_02_12_zone_gravity.sql|SHOW COLUMNS FROM `zone` LIKE 'gravity'|empty| +9078|2015_05_20_BuffInstrumentMod.sql|SHOW COLUMNS FROM `character_buffs` LIKE 'instrument_mod'|empty| +9079|2015_05_23_BuffDurations.sql|SHOW COLUMNS FROM `character_buffs` LIKE 'ticsremaining'|contains|unsigned| +9080|2015_05_23_PetBuffInstrumentMod.sql|SHOW COLUMNS FROM `character_pet_buffs` LIKE 'instrument_mod'|empty| +9081|2015_05_23_dbstr_us.sql|SHOW TABLES LIKE 'db_str'|empty| +9082|2015_05_25_npc_types_texture_fields.sql|SHOW COLUMNS FROM `npc_types` LIKE 'armtexture'|empty| +9083|2015_06_07_aa_update.sql|SHOW COLUMNS FROM `character_alternate_abilities` LIKE 'charges'|empty| +9084|2015_06_30_runspeed_adjustments.sql|SELECT `runspeed` FROM `npc_types` WHERE `runspeed` > 3|not_empty| +9085|2015_07_01_Marquee_Rule.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Character:MarqueeHPUpdates%'|empty| +9086|2015_07_02_aa_rework.sql|SHOW TABLES LIKE 'aa_ranks'|empty| +9087|2015_09_25_inventory_snapshots.sql|SHOW TABLES LIKE 'inventory_snapshots'|empty| +9088|2015_11_01_perl_event_export_settings.sql|SHOW TABLES LIKE 'perl_event_export_settings'|empty| +9089|2015_11_02_ai_idle_no_spell_recast_default_changes.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Spells:AI_IdleNoSpellMinRecast%' AND `rule_value` = '500'|not_empty| +9090|2015_12_01_spell_scribe_restriction_rule.sql|SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Character:RestrictSpellScribing'|empty| +9091|2015_12_07_command_settings.sql|SHOW TABLES LIKE 'command_settings'|empty| +9092|2015_12_17_eqtime.sql|SHOW TABLES LIKE 'eqtime'|empty| +9093|2015_12_21_items_updates_evoitem.sql|SHOW COLUMNS FROM `items` LIKE 'evoitem'|empty| +9094|2015_12_29_quest_zone_events.sql|SELECT * FROM perl_event_export_settings WHERE event_description = 'EVENT_SPAWN_ZONE'|empty| +9095|2016_01_08_command_find_aliases.sql|SELECT * FROM `command_settings` WHERE `command` LIKE 'findaliases'|empty| +9096|2016_03_05_secondary_recall.sql|SHOW COLUMNS FROM `character_bind` LIKE 'slot'|empty| +9097|2016_07_03_npc_class_as_last_name.sql|SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'NPC:UseClassAsLastName'|empty| # Upgrade conditions: -# This won't be needed after this system is implemented, but it is used database that are not +# This won't be needed after this system is implemented, but it is used database that are not # yet using the versioning system to figure out where the database is schema wise to determine # which updates are necessary to run # diff --git a/utils/sql/git/bots/README b/utils/sql/git/bots/README index 3f3c94cb1..844709fb9 100644 --- a/utils/sql/git/bots/README +++ b/utils/sql/git/bots/README @@ -1,3 +1,6 @@ -Use this new load_bots.sql to source bot information into your database. +Use the eqemu_update.pl script to source/update bot information into your database. -This file now contains all of the script information so that it may be run from inside of HeidiSQL. \ No newline at end of file + +Developers: Please prefix 'bots_' to sql file description (after the date) in order to prevent issues naming conflicts. + +Example: 1970_01_01_bots_file_description.sql diff --git a/utils/sql/git/bots/bots_db_update_manifest.txt b/utils/sql/git/bots/bots_db_update_manifest.txt new file mode 100644 index 000000000..3122545a0 --- /dev/null +++ b/utils/sql/git/bots/bots_db_update_manifest.txt @@ -0,0 +1,28 @@ +9000|2015_09_30_bots.sql|SHOW TABLES LIKE 'bot_data'|empty| +9001|2016_03_24_bots_command_settings.sql|SHOW TABLES LIKE 'bot_command_settings'|empty| +9002|2016_03_24_bots_command_rules.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CommandSpellRank'|empty| +9003|2016_04_05_bots_pet_spell_id_field.sql|SHOW COLUMNS FROM `bot_pets` LIKE 'pet_id'|not_empty| +9004|2016_04_07_bots_heal_override_target.sql|SELECT `bot_command` FROM `bot_command_settings` WHERE `bot_command` LIKE 'healrotationclearhot'|empty| +9005|2016_04_08_bots_heal_rotations.sql|SHOW TABLES LIKE 'bot_heal_rotations'|empty| +9006|2016_04_12_bots_inventory_window.sql|SELECT `bot_command` FROM `bot_command_settings` WHERE `bot_command` LIKE 'inventorywindow'|empty| +9007|2016_06_23_bots_camel_case_name_rule.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE 'Bots:AllowCamelCaseNames'|empty| +9008|2016_06_28_bots_inventory_charges_update.sql|SELECT * FROM `information_schema`.`COLUMNS` isc WHERE isc.`TABLE_SCHEMA` = DATABASE() AND isc.`TABLE_NAME` = 'bot_inventories' AND isc.`COLUMN_NAME` = 'inst_charges' AND isc.`DATA_TYPE` = 'tinyint'|not_empty| + +# Upgrade conditions: +# This won't be needed after this system is implemented, but it is used database that are not +# yet using the versioning system to figure out where the database is schema wise to determine +# which updates are necessary to run +# +# Example: Version|Filename.sql|Query_to_Check_Condition_For_Needed_Update|match type|text to match +# 0 = Database Version +# 1 = Filename.sql +# 2 = Query_to_Check_Condition_For_Needed_Update +# 3 = Match Type - If condition from match type to Value 4 is true, update will flag for needing to be ran +# contains = If query results contains text from 4th value +# match = If query results matches text from 4th value +# missing = If query result is missing text from 4th value +# empty = If the query results in no results +# not_empty = If the query is not empty +# 4 = Text to match +# +# diff --git a/utils/sql/git/bots/required/2014_03_22_BotGuildMember_ScriptFailureFix.sql b/utils/sql/git/bots/deprecated/2014_03_22_BotGuildMember_ScriptFailureFix.sql similarity index 100% rename from utils/sql/git/bots/required/2014_03_22_BotGuildMember_ScriptFailureFix.sql rename to utils/sql/git/bots/deprecated/2014_03_22_BotGuildMember_ScriptFailureFix.sql diff --git a/utils/sql/git/bots/deprecated/drop_bots (pre-update script).sql b/utils/sql/git/bots/deprecated/drop_bots (pre-update script).sql new file mode 100644 index 000000000..24dcccb02 --- /dev/null +++ b/utils/sql/git/bots/deprecated/drop_bots (pre-update script).sql @@ -0,0 +1,85 @@ +-- 'drop_bots (pre-update script)' sql script file +-- current as of 11/30/2015 +-- +-- Note: This file will remove bot schema loaded by 'load_bots' sql scripts. +-- There may still be remnants of bot activity in tables `guild_members` and +-- `group_id`. If these entries are causing issues, you may need to manually +-- remove them. + + +SELECT "dropping views..."; +DROP VIEW IF EXISTS `vwGuildMembers`; +DROP VIEW IF EXISTS `vwGroups`; +DROP VIEW IF EXISTS `vwBotGroups`; +DROP VIEW IF EXISTS `vwBotCharacterMobs`; + + +SELECT "dropping functions..."; +DROP FUNCTION IF EXISTS `GetMobTypeByName`; +DROP FUNCTION IF EXISTS `GetMobTypeByID`; +DROP FUNCTION IF EXISTS `GetMobType`; + + +SELECT "dropping tables..."; +DROP TABLE IF EXISTS `botguildmembers`; +DROP TABLE IF EXISTS `botgroupmembers`; +DROP TABLE IF EXISTS `botgroup`; +DROP TABLE IF EXISTS `botgroups`; -- this table is not a part of 'load_bots.sql' +DROP TABLE IF EXISTS `botpetinventory`; +DROP TABLE IF EXISTS `botpetbuffs`; +DROP TABLE IF EXISTS `botpets`; +DROP TABLE IF EXISTS `botinventory`; +DROP TABLE IF EXISTS `botbuffs`; +DROP TABLE IF EXISTS `bottimers`; +DROP TABLE IF EXISTS `botstances`; +DROP TABLE IF EXISTS `bots`; + +DROP PROCEDURE IF EXISTS `DropBotsSchema`; + + +DELIMITER $$ + +CREATE PROCEDURE `DropBotsSchema` () +BEGIN + SELECT "deleting rules..."; + DELETE FROM `rule_values` WHERE `rule_name` LIKE 'Bots%'; + + + SELECT "deleting command..."; + DELETE FROM `commands` WHERE `command` LIKE 'bot'; + + + SELECT "restoring keys..."; + IF (EXISTS(SELECT `CONSTRAINT_NAME` FROM `information_schema`.`KEY_COLUMN_USAGE` WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'group_id' AND `CONSTRAINT_NAME` = 'PRIMARY')) THEN + ALTER TABLE `group_id` DROP PRIMARY KEY; + END IF; + ALTER TABLE `group_id` ADD PRIMARY KEY (`groupid`, `charid`, `ismerc`); + + IF (EXISTS(SELECT `CONSTRAINT_NAME` FROM `information_schema`.`KEY_COLUMN_USAGE` WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'guild_members' AND `CONSTRAINT_NAME` = 'PRIMARY')) THEN + ALTER TABLE `guild_members` DROP PRIMARY KEY; + END IF; + ALTER TABLE `guild_members` ADD PRIMARY KEY (`char_id`); + + + SELECT "de-activating spawns..."; + UPDATE `spawn2` SET `enabled` = 0 WHERE `id` IN (59297,59298); + + + SELECT "clearing database version..."; + IF (EXISTS(SELECT `COLUMN_NAME` FROM `information_schema`.`COLUMNS` WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'db_version' AND `COLUMN_NAME` = 'bots_version')) THEN + UPDATE `db_version` + SET `bots_version` = 0; + END IF; + +END$$ + +DELIMITER ; + + +CALL `DropBotsSchema`(); + +SELECT "dropping procedure..."; +DROP PROCEDURE IF EXISTS `DropBotsSchema`; + + +-- End of File diff --git a/utils/sql/git/bots/load_bots.sql b/utils/sql/git/bots/deprecated/load_bots.sql similarity index 100% rename from utils/sql/git/bots/load_bots.sql rename to utils/sql/git/bots/deprecated/load_bots.sql diff --git a/utils/sql/git/bots/drop_bots.sql b/utils/sql/git/bots/drop_bots.sql index df8ca4fa8..1e31003bd 100644 --- a/utils/sql/git/bots/drop_bots.sql +++ b/utils/sql/git/bots/drop_bots.sql @@ -1,35 +1,35 @@ -- 'drop_bots' sql script file --- current as of 10/15/2014 +-- current as of 12/11/2015 -- --- Note: This file will revert all changes made by either 'load_bots' sql file. +-- Note: This file will remove bot schema loaded by 'load_bots' sql scripts. -- There may still be remnants of bot activity in tables `guild_members` and -- `group_id`. If these entries are causing issues, you may need to manually -- remove them. -- --- If this script fails due to a 'SQL Error (1068): Multiple primary key defined' --- error, run this query: ALTER TABLE `guild_members` DROP PRIMARY KEY; --- and it should remove the key so this script will process in its entirety. +-- Use eqemu_update.pl to administer this script -ALTER TABLE `guild_members` ADD PRIMARY KEY (`char_id`); -ALTER TABLE `group_id` DROP PRIMARY KEY, ADD PRIMARY KEY (`groupid`, `charid`, `ismerc`); +DROP VIEW IF EXISTS `vwguildmembers`; +DROP VIEW IF EXISTS `vwgroups`; +DROP VIEW IF EXISTS `vwbotgroups`; +DROP VIEW IF EXISTS `vwbotcharactermobs`; -UPDATE `spawn2` SET `enabled` = 0 WHERE `id` IN (59297,59298); - -DELETE FROM `commands` WHERE `command` = 'bot'; -DELETE FROM `rule_values` WHERE `rule_name` LIKE 'Bots%'; - -DROP VIEW IF EXISTS `vwBotCharacterMobs`; -DROP VIEW IF EXISTS `vwBotGroups`; -DROP VIEW IF EXISTS `vwGroups`; DROP VIEW IF EXISTS `vwGuildMembers`; +DROP VIEW IF EXISTS `vwGroups`; +DROP VIEW IF EXISTS `vwBotGroups`; +DROP VIEW IF EXISTS `vwBotCharacterMobs`; +DROP VIEW IF EXISTS `vw_guild_members`; +DROP VIEW IF EXISTS `vw_groups`; +DROP VIEW IF EXISTS `vw_bot_groups`; +DROP VIEW IF EXISTS `vw_bot_character_mobs`; + +DROP FUNCTION IF EXISTS `GetMobTypeByName`; +DROP FUNCTION IF EXISTS `GetMobTypeByID`; DROP FUNCTION IF EXISTS `GetMobType`; DROP TABLE IF EXISTS `botguildmembers`; DROP TABLE IF EXISTS `botgroupmembers`; --- this table is not a part of 'load_bots.sql' -DROP TABLE IF EXISTS `botgroups`; DROP TABLE IF EXISTS `botgroup`; DROP TABLE IF EXISTS `botpetinventory`; DROP TABLE IF EXISTS `botpetbuffs`; @@ -39,3 +39,36 @@ DROP TABLE IF EXISTS `botbuffs`; DROP TABLE IF EXISTS `bottimers`; DROP TABLE IF EXISTS `botstances`; DROP TABLE IF EXISTS `bots`; + +DROP TABLE IF EXISTS `botgroups`; -- this table is not a part of 'load_bots.sql' + +DROP TABLE IF EXISTS `botguildmembers_old`; +DROP TABLE IF EXISTS `botgroupmembers_old`; +DROP TABLE IF EXISTS `botgroup_old`; +DROP TABLE IF EXISTS `botpetinventory_old`; +DROP TABLE IF EXISTS `botpetbuffs_old`; +DROP TABLE IF EXISTS `botpets_old`; +DROP TABLE IF EXISTS `botinventory_old`; +DROP TABLE IF EXISTS `botbuffs_old`; +DROP TABLE IF EXISTS `bottimers_old`; +DROP TABLE IF EXISTS `botstances_old`; +DROP TABLE IF EXISTS `bots_old`; + +DROP TABLE IF EXISTS `bot_guild_members`; +DROP TABLE IF EXISTS `bot_group_members`; +DROP TABLE IF EXISTS `bot_groups`; +DROP TABLE IF EXISTS `bot_pet_inventories`; +DROP TABLE IF EXISTS `bot_pet_buffs`; +DROP TABLE IF EXISTS `bot_pets`; +DROP TABLE IF EXISTS `bot_inventories`; +DROP TABLE IF EXISTS `bot_buffs`; +DROP TABLE IF EXISTS `bot_timers`; +DROP TABLE IF EXISTS `bot_stances`; +DROP TABLE IF EXISTS `bot_inspect_messages`; +DROP TABLE IF EXISTS `bot_data`; + +DROP PROCEDURE IF EXISTS `LoadBotsSchema`; +DROP PROCEDURE IF EXISTS `DropBotsSchema`; + + +-- End of File diff --git a/utils/sql/git/bots/required/2015_09_30_bots.sql b/utils/sql/git/bots/required/2015_09_30_bots.sql new file mode 100644 index 000000000..838e85c16 --- /dev/null +++ b/utils/sql/git/bots/required/2015_09_30_bots.sql @@ -0,0 +1,346 @@ +-- '2015_09_30_bots' sql script file +-- current as of 12/11/2015 +-- +-- Use eqemu_update.pl to administer this script + + +-- Clean-up +DROP VIEW IF EXISTS `vwbotcharactermobs`; +DROP VIEW IF EXISTS `vwbotgroups`; +DROP VIEW IF EXISTS `vwgroups`; +DROP VIEW IF EXISTS `vwguildmembers`; + +DROP VIEW IF EXISTS `vwBotCharacterMobs`; +DROP VIEW IF EXISTS `vwBotGroups`; +DROP VIEW IF EXISTS `vwGroups`; +DROP VIEW IF EXISTS `vwGuildMembers`; + +DROP VIEW IF EXISTS `vw_bot_character_mobs`; +DROP VIEW IF EXISTS `vw_bot_groups`; +DROP VIEW IF EXISTS `vw_groups`; +DROP VIEW IF EXISTS `vw_guild_members`; + +DROP FUNCTION IF EXISTS `GetMobType`; +DROP FUNCTION IF EXISTS `GetMobTypeByName`; +DROP FUNCTION IF EXISTS `GetMobTypeByID`; + +DROP PROCEDURE IF EXISTS `LoadBotsSchema`; + + +-- Tables +CREATE TABLE `bot_data` ( + `bot_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, + `owner_id` INT(11) UNSIGNED NOT NULL, + `spells_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `name` VARCHAR(64) NOT NULL DEFAULT '', + `last_name` VARCHAR(64) NOT NULL DEFAULT '', + `title` VARCHAR(32) NOT NULL DEFAULT '', -- Unused + `suffix` VARCHAR(32) NOT NULL DEFAULT '', -- Unused + `zone_id` SMALLINT(6) NOT NULL DEFAULT '0', + `gender` TINYINT(2) NOT NULL DEFAULT '0', + `race` SMALLINT(5) NOT NULL DEFAULT '0', + `class` TINYINT(2) NOT NULL DEFAULT '0', + `level` TINYINT(2) UNSIGNED NOT NULL DEFAULT '0', + `deity` INT(11) UNSIGNED NOT NULL DEFAULT '0', -- Unused + `creation_day` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `last_spawn` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `time_spawned` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `size` FLOAT NOT NULL DEFAULT '0', + `face` INT(10) NOT NULL DEFAULT '1', + `hair_color` INT(10) NOT NULL DEFAULT '1', + `hair_style` INT(10) NOT NULL DEFAULT '1', + `beard` INT(10) NOT NULL DEFAULT '0', + `beard_color` INT(10) NOT NULL DEFAULT '1', + `eye_color_1` INT(10) NOT NULL DEFAULT '1', + `eye_color_2` INT(10) NOT NULL DEFAULT '1', + `drakkin_heritage` INT(10) NOT NULL DEFAULT '0', + `drakkin_tattoo` INT(10) NOT NULL DEFAULT '0', + `drakkin_details` INT(10) NOT NULL DEFAULT '0', + `ac` SMALLINT(5) NOT NULL DEFAULT '0', + `atk` MEDIUMINT(9) NOT NULL DEFAULT '0', + `hp` INTEGER NOT NULL DEFAULT '0', + `mana` INTEGER NOT NULL DEFAULT '0', + `str` MEDIUMINT(8) NOT NULL DEFAULT '75', + `sta` MEDIUMINT(8) NOT NULL DEFAULT '75', + `cha` MEDIUMINT(8) NOT NULL DEFAULT '75', + `dex` MEDIUMINT(8) NOT NULL DEFAULT '75', + `int` MEDIUMINT(8) NOT NULL DEFAULT '75', + `agi` MEDIUMINT(8) NOT NULL DEFAULT '75', + `wis` MEDIUMINT(8) NOT NULL DEFAULT '75', + `fire` SMALLINT(5) NOT NULL DEFAULT '0', + `cold` SMALLINT(5) NOT NULL DEFAULT '0', + `magic` SMALLINT(5) NOT NULL DEFAULT '0', + `poison` SMALLINT(5) NOT NULL DEFAULT '0', + `disease` SMALLINT(5) NOT NULL DEFAULT '0', + `corruption` SMALLINT(5) NOT NULL DEFAULT '0', + `show_helm` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `follow_distance` INT(11) UNSIGNED NOT NULL DEFAULT '200', + PRIMARY KEY (`bot_id`) +) ENGINE=InnoDB; + +CREATE TABLE `bot_inspect_messages` ( + `bot_id` INT(11) UNSIGNED NOT NULL, + `inspect_message` VARCHAR(256) NOT NULL DEFAULT '', + PRIMARY KEY (`bot_id`), + INDEX `bot_id` (`bot_id`) +) ENGINE=InnoDB; + +CREATE TABLE `bot_stances` ( + `bot_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `stance_id` TINYINT UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`bot_id`), + CONSTRAINT `FK_bot_stances_1` FOREIGN KEY (`bot_id`) REFERENCES `bot_data` (`bot_id`) +); + +CREATE TABLE `bot_timers` ( + `bot_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `timer_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `timer_value` INT(11) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`bot_id`), + CONSTRAINT `FK_bot_timers_1` FOREIGN KEY (`bot_id`) REFERENCES `bot_data` (`bot_id`) +); + +CREATE TABLE `bot_buffs` ( + `buffs_index` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, + `bot_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `spell_id` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `caster_level` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + `duration_formula` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `tics_remaining` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `poison_counters` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `disease_counters` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `curse_counters` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `corruption_counters` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `numhits` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `melee_rune` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `magic_rune` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `dot_rune` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `persistent` TINYINT(1) NOT NULL DEFAULT '0', + `caston_x` INT(10) NOT NULL DEFAULT '0', + `caston_y` INT(10) NOT NULL DEFAULT '0', + `caston_z` INT(10) NOT NULL DEFAULT '0', + `extra_di_chance` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `instrument_mod` INT(10) NOT NULL DEFAULT '10', -- Unused + PRIMARY KEY (`buffs_index`), + KEY `FK_bot_buffs_1` (`bot_id`), + CONSTRAINT `FK_bot_buffs_1` FOREIGN KEY (`bot_id`) REFERENCES `bot_data` (`bot_id`) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1; + +CREATE TABLE `bot_inventories` ( + `inventories_index` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `bot_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `slot_id` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `item_id` INT(11) UNSIGNED NULL DEFAULT '0', + `inst_charges` TINYINT(3) UNSIGNED DEFAULT 0, + `inst_color` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `inst_no_drop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', + `inst_custom_data` TEXT NULL, + `ornament_icon` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornament_id_file` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', + `augment_1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augment_2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augment_3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augment_4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augment_5` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augment_6` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`inventories_index`), + KEY `FK_bot_inventories_1` (`bot_id`), + CONSTRAINT `FK_bot_inventories_1` FOREIGN KEY (`bot_id`) REFERENCES `bot_data` (`bot_id`) +) ENGINE=InnoDB; + +CREATE TABLE `bot_pets` ( + `pets_index` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `pet_id` INTEGER UNSIGNED NOT NULL DEFAULT '0', + `bot_id` INTEGER UNSIGNED NOT NULL DEFAULT '0', + `name` VARCHAR(64) NULL, + `mana` INTEGER NOT NULL DEFAULT '0', + `hp` INTEGER NOT NULL DEFAULT '0', + PRIMARY KEY (`pets_index`), + KEY `FK_bot_pets_1` (`bot_id`), + CONSTRAINT `FK_bot_pets_1` FOREIGN KEY (`bot_id`) REFERENCES `bot_data` (`bot_id`), + CONSTRAINT `U_bot_pets_1` UNIQUE (`bot_id`) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1; + +CREATE TABLE `bot_pet_buffs` ( + `pet_buffs_index` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `pets_index` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `spell_id` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `caster_level` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `duration` INT(11) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`pet_buffs_index`), + KEY `FK_bot_pet_buffs_1` (`pets_index`), + CONSTRAINT `FK_bot_pet_buffs_1` FOREIGN KEY (`pets_index`) REFERENCES `bot_pets` (`pets_index`) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1; + +CREATE TABLE `bot_pet_inventories` ( + `pet_inventories_index` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `pets_index` INTEGER UNSIGNED NOT NULL DEFAULT '0', + `item_id` INTEGER UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`pet_inventories_index`), + KEY `FK_bot_pet_inventories_1` (`pets_index`), + CONSTRAINT `FK_bot_pet_inventories_1` FOREIGN KEY (`pets_index`) REFERENCES `bot_pets` (`pets_index`) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1; + +CREATE TABLE `bot_groups` ( + `groups_index` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `group_leader_id` INTEGER UNSIGNED NOT NULL DEFAULT '0', + `group_name` VARCHAR(64) NOT NULL, + PRIMARY KEY (`groups_index`), + KEY `FK_bot_groups_1` (`group_leader_id`), + CONSTRAINT `FK_bot_groups_1` FOREIGN KEY (`group_leader_id`) REFERENCES `bot_data` (`bot_id`) +) ENGINE=InnoDB; + +CREATE TABLE `bot_group_members` ( + `group_members_index` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + `groups_index` INTEGER UNSIGNED NOT NULL DEFAULT '0', + `bot_id` INTEGER UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`group_members_index`), + KEY `FK_bot_group_members_1` (`groups_index`), + CONSTRAINT `FK_bot_group_members_1` FOREIGN KEY (`groups_index`) REFERENCES `bot_groups` (`groups_index`), + KEY `FK_bot_group_members_2` (`bot_id`), + CONSTRAINT `FK_bot_group_members_2` FOREIGN KEY (`bot_id`) REFERENCES `bot_data` (`bot_id`) +) ENGINE=InnoDB; + +CREATE TABLE `bot_guild_members` ( + `bot_id` INT(11) NOT NULL DEFAULT '0', + `guild_id` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT '0', + `rank` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + `tribute_enable` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + `total_tribute` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `last_tribute` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `banker` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + `public_note` TEXT NULL, + `alt` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`bot_id`) +) ENGINE=InnoDB; + + +-- Functions +DELIMITER $$ + +-- (no code references - see `vw_groups` below) +CREATE FUNCTION `GetMobType` (mob_name VARCHAR(64)) RETURNS CHAR(1) +BEGIN + DECLARE Result CHAR(1); + + SET Result = NULL; + + IF ((SELECT COUNT(*) FROM `character_data` WHERE `name` = mob_name) > 0) THEN + SET Result = 'C'; + ELSEIF ((SELECT COUNT(*) FROM `bot_data` WHERE `name` = mob_name) > 0) THEN + SET Result = 'B'; + END IF; + + RETURN Result; +END$$ + +-- (one code reference in /common/database.cpp) +CREATE FUNCTION `GetMobTypeById` (mob_id INTEGER UNSIGNED) RETURNS CHAR(1) +BEGIN + DECLARE Result CHAR(1); + + SET Result = NULL; + + IF ((select `id` from `character_data` where `id` = mob_id) > 0) THEN + SET Result = 'C'; + ELSEIF ((select `bot_id` from `bot_data` where `bot_id` = mob_id) > 0) THEN + SET Result = 'B'; + END IF; + + RETURN Result; +END$$ + +-- (for reference only) +-- CREATE FUNCTION `GetMobTypeByName` (mob_name VARCHAR(64)) RETURNS CHAR(1) +-- BEGIN +-- DECLARE Result CHAR(1); +-- +-- SET Result = NULL; +-- +-- IF (select `id` from `character_data` where `name` = mob_name) > 0 THEN +-- SET Result = 'C'; +-- ELSEIF (select `bot_id` from `bot_data` where `name` = mob_name) > 0 THEN +-- SET Result = 'B'; +-- END IF; +-- +-- RETURN Result; +-- END $$ + +DELIMITER ; + + +-- Views +CREATE VIEW `vw_bot_character_mobs` AS +SELECT +_utf8'C' AS mob_type, +c.`id`, +c.`name`, +c.`class`, +c.`level`, +c.`last_login`, +c.`zone_id` +FROM `character_data` AS c +UNION ALL +SELECT _utf8'B' AS mob_type, +b.`bot_id` AS id, +b.`name`, +b.`class`, +b.`level`, +b.`last_spawn` AS last_login, +b.`zone_id` +FROM `bot_data` AS b; + +CREATE VIEW `vw_bot_groups` AS +SELECT +g.`groups_index`, +g.`group_name`, +g.`group_leader_id`, +b.`name` AS group_leader_name, +b.`owner_id`, +c.`name` AS owner_name +FROM `bot_groups` AS g +JOIN `bot_data` AS b ON g.`group_leader_id` = b.`bot_id` +JOIN `character_data` AS c ON b.`owner_id` = c.`id` +ORDER BY b.`owner_id`, g.`group_name`; + +CREATE VIEW `vw_groups` AS +SELECT +g.`groupid` AS group_id, +GetMobType(g.`name`) AS mob_type, +g.`name` AS name, +g.`charid` AS mob_id, +IFNULL(c.`level`, b.`level`) AS level +FROM `group_id` AS g +LEFT JOIN `character_data` AS c ON g.`name` = c.`name` +LEFT JOIN `bot_data` AS b ON g.`name` = b.`name`; + +CREATE VIEW `vw_guild_members` AS +SELECT +'C' AS mob_type, +cm.`char_id`, +cm.`guild_id`, +cm.`rank`, +cm.`tribute_enable`, +cm.`total_tribute`, +cm.`last_tribute`, +cm.`banker`, +cm.`public_note`, +cm.`alt` +FROM `guild_members` AS cm +UNION ALL +SELECT +'B' AS mob_type, +bm.`bot_id` AS char_id, +bm.`guild_id`, +bm.`rank`, +bm.`tribute_enable`, +bm.`total_tribute`, +bm.`last_tribute`, +bm.`banker`, +bm.`public_note`, +bm.`alt` +FROM `bot_guild_members` AS bm; + + +-- End of File diff --git a/utils/sql/git/bots/required/2016_03_24_bots_command_rules.sql b/utils/sql/git/bots/required/2016_03_24_bots_command_rules.sql new file mode 100644 index 000000000..be3009944 --- /dev/null +++ b/utils/sql/git/bots/required/2016_03_24_bots_command_rules.sql @@ -0,0 +1,5 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES +(1, 'Bots:CommandSpellRank', '1', 'Filters bot command spells by rank (1, 2 and 3 are valid filters - any other number allows all ranks)'), +(1, 'Bots:HealRotationMaxMembers', '24', 'Maximum number of heal rotation members'), +(1, 'Bots:HealRotationMaxTargets', '12', 'Maximum number of heal rotation targets'), +(1, 'Bots:PreferNoManaCommandSpells', 'true', 'Give sorting priority to newer no-mana spells (i.e., \'Bind Affinity\')'); diff --git a/utils/sql/git/bots/required/2016_03_24_bots_command_settings.sql b/utils/sql/git/bots/required/2016_03_24_bots_command_settings.sql new file mode 100644 index 000000000..7b37e466f --- /dev/null +++ b/utils/sql/git/bots/required/2016_03_24_bots_command_settings.sql @@ -0,0 +1,102 @@ +CREATE TABLE `bot_command_settings` ( + `bot_command` varchar(128) NOT NULL DEFAULT '', + `access` int(11) NOT NULL DEFAULT '0', + `aliases` varchar(256) NOT NULL DEFAULT '', + PRIMARY KEY (`bot_command`), + UNIQUE KEY `UK_bot_command_settings_1` (`bot_command`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `bot_command_settings` VALUES +('actionable', 0, ''), +('aggressive', 0, 'agg'), +('attack', 0, 'atk'), +('bindaffinity', 0, 'bind'), +('bot', 0, 'b'), +('botappearance', 0, 'app|appearance'), +('botbeardcolor', 0, 'bc|beardcolor'), +('botbeardstyle', 0, 'bs|beardstyle'), +('botcamp', 0, 'camp'), +('botclone', 200, 'clone'), +('botcreate', 0, 'create'), +('botdelete', 0, 'delete'), +('botdetails', 0, 'details'), +('botdyearmor', 0, 'dyearmor'), +('boteyes', 0, 'eyes'), +('botface', 0, 'face'), +('botfollowdistance', 0, 'followd'), +('botgroup', 0, 'bg'), +('botgroupaddmember', 0, 'bgadd'), +('botgroupcreate', 0, 'bgcreate'), +('botgroupdelete', 0, 'bgdelete'), +('botgrouplist', 0, 'bglist'), +('botgroupload', 0, 'bgload'), +('botgroupremovemember', 0, 'bgremove'), +('bothaircolor', 0, 'hc|haircolor'), +('bothairstyle', 0, 'hs|hairstyle'), +('botheritage', 0, 'her|heritage'), +('botinspectmessage', 0, 'inspect'), +('botlist', 0, 'list'), +('botoutofcombat', 0, 'ooc|outofcombat'), +('botreport', 0, 'report|health|mana'), +('botspawn', 0, 'spawn'), +('botstance', 0, 'stance'), +('botsummon', 0, 'summon'), +('bottattoo', 0, 'tattoo'), +('bottogglearcher', 0, 'archer|togglearcher'), +('bottogglehelm', 0, 'helm|togglehelm'), +('botupdate', 0, 'update'), +('botwoad', 0, 'woad'), +('charm', 0, ''), +('circle', 0, 'cir'), +('cure', 0, ''), +('defensive', 0, 'def'), +('depart', 0, 'dep'), +('escape', 0, 'evac|succor'), +('findaliases', 0, 'alias'), +('follow', 0, ''), +('guard', 0, ''), +('healrotation', 0, 'hr'), +('healrotationadaptivetargeting', 0, 'hradapt'), +('healrotationaddmember', 0, 'hraddm'), +('healrotationaddtarget', 0, 'hraddt'), +('healrotationadjustcritical', 0, 'hrcrit'), +('healrotationadjustsafe', 0, 'hrsafe'), +('healrotationcastingoverride', 0, 'hroverride'), +('healrotationchangeinterval', 0, 'hrinterval'), +('healrotationcleartargets', 0, 'hrclear'), +('healrotationcreate', 0, 'hrcreate'), +('healrotationfastheals', 0, 'hrfastheals'), +('healrotationlist', 0, 'hrlist'), +('healrotationremovemember', 0, 'hrremm'), +('healrotationremovetarget', 0, 'hrremt'), +('healrotationresetlimits', 0, 'hrreset'), +('healrotationstart', 0, 'hrstart'), +('healrotationstop', 0, 'hrstop'), +('help', 0, '?'), +('hold', 0, ''), +('identify', 0, 'lore'), +('inventory', 0, 'inv'), +('inventorygive', 0, 'invgive'), +('inventorylist', 0, 'invlist'), +('inventoryremove', 0, 'invremove'), +('invisibility', 0, 'invis'), +('levitation', 0, 'lev'), +('lull', 0, 'calm|pacify'), +('mesmerize', 0, 'mez'), +('movementspeed', 0, 'sow'), +('pet', 0, 'p'), +('petremove', 0, 'prem'), +('petsettype', 0, 'pset'), +('picklock', 0, 'pl'), +('portal', 0, 'port'), +('pull', 0, ''), +('release', 0, ''), +('resistance', 0, 'resist'), +('resurrect', 0, 'revive'), +('rune', 0, ''), +('sendhome', 0, 'gate'), +('size', 0, ''), +('summoncorpse', 0, 'scorpse'), +('taunt', 0, ''), +('track', 0, ''), +('waterbreathing', 0, 'wb|eb'); diff --git a/utils/sql/git/bots/required/2016_04_05_bots_pet_spell_id_field.sql b/utils/sql/git/bots/required/2016_04_05_bots_pet_spell_id_field.sql new file mode 100644 index 000000000..d2d930160 --- /dev/null +++ b/utils/sql/git/bots/required/2016_04_05_bots_pet_spell_id_field.sql @@ -0,0 +1 @@ +ALTER TABLE `bot_pets` CHANGE COLUMN `pet_id` `spell_id` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `pets_index`; diff --git a/utils/sql/git/bots/required/2016_04_07_bots_heal_override_target.sql b/utils/sql/git/bots/required/2016_04_07_bots_heal_override_target.sql new file mode 100644 index 000000000..02cc4083e --- /dev/null +++ b/utils/sql/git/bots/required/2016_04_07_bots_heal_override_target.sql @@ -0,0 +1,3 @@ +INSERT INTO `bot_command_settings` VALUES +('healrotationclearhot', 0, 'hrclearhot'), +('healrotationsethot', 0, 'hrsethot'); diff --git a/utils/sql/git/bots/required/2016_04_08_bots_heal_rotations.sql b/utils/sql/git/bots/required/2016_04_08_bots_heal_rotations.sql new file mode 100644 index 000000000..71e0f5af4 --- /dev/null +++ b/utils/sql/git/bots/required/2016_04_08_bots_heal_rotations.sql @@ -0,0 +1,41 @@ +CREATE TABLE `bot_heal_rotations` ( + `heal_rotation_index` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, + `bot_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `interval` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `fast_heals` INT(3) UNSIGNED NOT NULL DEFAULT '0', + `adaptive_targeting` INT(3) UNSIGNED NOT NULL DEFAULT '0', + `casting_override` INT(3) UNSIGNED NOT NULL DEFAULT '0', + `safe_hp_base` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + `safe_hp_cloth` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + `safe_hp_leather` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + `safe_hp_chain` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + `safe_hp_plate` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + `critical_hp_base` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + `critical_hp_cloth` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + `critical_hp_leather` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + `critical_hp_chain` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + `critical_hp_plate` FLOAT(11) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`heal_rotation_index`), + CONSTRAINT `FK_bot_heal_rotations` FOREIGN KEY (`bot_id`) REFERENCES `bot_data` (`bot_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +CREATE TABLE `bot_heal_rotation_members` ( + `member_index` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, + `heal_rotation_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `bot_id` INT(11) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`member_index`), + CONSTRAINT `FK_bot_heal_rotation_members_1` FOREIGN KEY (`heal_rotation_index`) REFERENCES `bot_heal_rotations` (`heal_rotation_index`), + CONSTRAINT `FK_bot_heal_rotation_members_2` FOREIGN KEY (`bot_id`) REFERENCES `bot_data` (`bot_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +CREATE TABLE `bot_heal_rotation_targets` ( + `target_index` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, + `heal_rotation_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `target_name` varchar(64) NOT NULL DEFAULT '', + PRIMARY KEY (`target_index`), + CONSTRAINT `FK_bot_heal_rotation_targets` FOREIGN KEY (`heal_rotation_index`) REFERENCES `bot_heal_rotations` (`heal_rotation_index`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `bot_command_settings` VALUES +('healrotationdelete', 0, 'hrdelete'), +('healrotationsave', 0, 'hrsave'); diff --git a/utils/sql/git/bots/required/2016_04_12_bots_inventory_window.sql b/utils/sql/git/bots/required/2016_04_12_bots_inventory_window.sql new file mode 100644 index 000000000..b0269559d --- /dev/null +++ b/utils/sql/git/bots/required/2016_04_12_bots_inventory_window.sql @@ -0,0 +1,2 @@ +INSERT INTO `bot_command_settings` VALUES +('inventorywindow', 0, 'invwindow'); diff --git a/utils/sql/git/bots/required/2016_06_23_bots_camel_case_name_rule.sql b/utils/sql/git/bots/required/2016_06_23_bots_camel_case_name_rule.sql new file mode 100644 index 000000000..6a758f28a --- /dev/null +++ b/utils/sql/git/bots/required/2016_06_23_bots_camel_case_name_rule.sql @@ -0,0 +1,2 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES +(1, 'Bots:AllowCamelCaseNames', 'false', 'Allows the use of \'MyBot\' type names'); diff --git a/utils/sql/git/bots/required/2016_06_28_bots_inventory_charges_update.sql b/utils/sql/git/bots/required/2016_06_28_bots_inventory_charges_update.sql new file mode 100644 index 000000000..1315c3e9e --- /dev/null +++ b/utils/sql/git/bots/required/2016_06_28_bots_inventory_charges_update.sql @@ -0,0 +1 @@ +ALTER TABLE `bot_inventories` MODIFY COLUMN `inst_charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0'; diff --git a/utils/sql/git/optional/2014_03_17_EnforceAugmentRules.sql b/utils/sql/git/optional/2014_03_17_EnforceAugmentRules.sql index e89d4a437..25ec3734d 100644 --- a/utils/sql/git/optional/2014_03_17_EnforceAugmentRules.sql +++ b/utils/sql/git/optional/2014_03_17_EnforceAugmentRules.sql @@ -1,3 +1,3 @@ INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentRestriction', 'false', 'Forces augment slot restrictions.'); INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentUsability', 'false', 'Forces augmented item usability.'); -INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentWear', 'false', 'Forces augment wear slot validation.'); \ No newline at end of file +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:EnforceAugmentWear', 'false', 'Forces augment wear slot validation.'); diff --git a/utils/sql/git/optional/2015_2_5_UseAdditiveFocusFromWornSlot.sql b/utils/sql/git/optional/2015_02_05_UseAdditiveFocusFromWornSlot.sql similarity index 100% rename from utils/sql/git/optional/2015_2_5_UseAdditiveFocusFromWornSlot.sql rename to utils/sql/git/optional/2015_02_05_UseAdditiveFocusFromWornSlot.sql diff --git a/utils/sql/git/optional/2015_2_6_AdditiveBonusWornType.sql b/utils/sql/git/optional/2015_02_06_AdditiveBonusWornType.sql similarity index 100% rename from utils/sql/git/optional/2015_2_6_AdditiveBonusWornType.sql rename to utils/sql/git/optional/2015_02_06_AdditiveBonusWornType.sql diff --git a/utils/sql/git/optional/2015_04_30_MeleePush.sql b/utils/sql/git/optional/2015_04_30_MeleePush.sql new file mode 100644 index 000000000..e640d4237 --- /dev/null +++ b/utils/sql/git/optional/2015_04_30_MeleePush.sql @@ -0,0 +1,2 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:MeleePush', 'true', 'Turns on Melee Push.'); +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:MeleePushChance', '50', 'Chance that an NPC can be pushed from melee.'); diff --git a/utils/sql/git/optional/2015_05_18_FishingLineLength.sql b/utils/sql/git/optional/2015_05_18_FishingLineLength.sql new file mode 100644 index 000000000..f57c4d02e --- /dev/null +++ b/utils/sql/git/optional/2015_05_18_FishingLineLength.sql @@ -0,0 +1 @@ +UPDATE rule_values SET rule_value=100 WHERE rule_name='Watermap:FishingLineLength'; diff --git a/utils/sql/git/optional/2015_06_07_SpellsTargetBuffsRule.sql b/utils/sql/git/optional/2015_06_07_SpellsTargetBuffsRule.sql new file mode 100644 index 000000000..1dcc9d922 --- /dev/null +++ b/utils/sql/git/optional/2015_06_07_SpellsTargetBuffsRule.sql @@ -0,0 +1 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:AlwaysSendTargetBuffs', 'false', 'Allows the server to send the targets buffs ignoring the LAA.'); diff --git a/utils/sql/git/optional/2015_06_07_TransformSummonedBagsRule.sql b/utils/sql/git/optional/2015_06_07_TransformSummonedBagsRule.sql new file mode 100644 index 000000000..d0af46a24 --- /dev/null +++ b/utils/sql/git/optional/2015_06_07_TransformSummonedBagsRule.sql @@ -0,0 +1 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Inventory:TransformSummonedBags', 'true', 'Transforms summoned bags into disenchanted ones instead of deleting.'); diff --git a/utils/sql/git/optional/2015_06_28_RescaleRunspeeds_RunOnceOnly.sql b/utils/sql/git/optional/2015_06_28_RescaleRunspeeds_RunOnceOnly.sql new file mode 100644 index 000000000..2810d3291 --- /dev/null +++ b/utils/sql/git/optional/2015_06_28_RescaleRunspeeds_RunOnceOnly.sql @@ -0,0 +1,7 @@ +/* This rescales the old peq runspeeds which were about 80 percent too high to new values */ +/* This section should only ever be run once */ +UPDATE npc_types SET npc_types.runspeed = 1.050 WHERE (npc_types.runspeed > 0 and npc_types.runspeed < 1.2); +UPDATE npc_types SET npc_types.runspeed = 1.325 WHERE (npc_types.runspeed > 1.19 and npc_types.runspeed < 1.75 and race != 73 and race != 72); +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.runspeed > 1.69 and npc_types.runspeed < 2.2); +UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE (npc_types.runspeed > 2.19 and npc_types.runspeed < 3); +UPDATE npc_types SET npc_types.runspeed = (npc_types.runspeed * 0.8) WHERE (npc_types.runspeed > 2.99 and npc_types.runspeed < 20); \ No newline at end of file diff --git a/utils/sql/git/optional/2015_06_28_SetMobSpecificRunSpeeds_AfterAnyRescaling.sql b/utils/sql/git/optional/2015_06_28_SetMobSpecificRunSpeeds_AfterAnyRescaling.sql new file mode 100644 index 000000000..064c39ce4 --- /dev/null +++ b/utils/sql/git/optional/2015_06_28_SetMobSpecificRunSpeeds_AfterAnyRescaling.sql @@ -0,0 +1,61 @@ +/* some specific by name */ +UPDATE npc_types SET npc_types.runspeed = 3.175 WHERE npc_types.name = 'a_shadowed_man'; +UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.name = 'aviak_egret'; +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.name = 'froglok_hunter'; +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.name = 'froglok_forager'; +/* rhinos */ +UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.race = 135; +/* centaurs */ +UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.race = 16; +/* griffins */ +UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.race = 47; +/* wolves - use size, to not change cubs*/ +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.race = 42 and npc_types.size > 5); +/* sarnaks */ +UPDATE npc_types SET npc_types.runspeed = 1.325 WHERE npc_types.race = 131; +/* sabertooth tigers - use size, to not change cubs*/ +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.race = 119 and npc_types.size > 6); +/* lions */ +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.race = 50 and npc_types.size > 7); +/* panthers/pumas */ +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.race = 76; +/* beetles */ +UPDATE npc_types SET npc_types.runspeed = 1.05 WHERE npc_types.race = 22; +/*leeches*/ +UPDATE npc_types SET npc_types.runspeed = 1.05 WHERE npc_types.race = 104; +/*a_brontotherium*/ +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.race = 169; +/* raptors */ +UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.race = 163; +/* vicious plants */ +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE npc_types.race = 162; +/* western wastes, drakes, cragwyrms and wyvern */ +UPDATE npc_types +JOIN spawnentry ON npc_types.id = spawnentry.npcID +JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID +SET npc_types.runspeed = 1.575 +WHERE ((npc_types.race = 89 OR npc_types.race = 157 OR npc_types.race = 158) AND spawn2.zone = 'westwastes'); +/* velium hounds/wolves */ +UPDATE npc_types +JOIN spawnentry ON npc_types.id = spawnentry.npcID +JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID +SET npc_types.runspeed = 1.850 +WHERE (npc_types.race = 42 AND spawn2.zone = 'westwastes'); +/* Overthere Specials, goons, etc. */ +UPDATE npc_types +JOIN spawnentry ON npc_types.id = spawnentry.npcID +JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID +SET npc_types.runspeed = 1.850 +WHERE ((npc_types.race = 77 or npc_types.race = 147) AND spawn2.zone = 'overthere'); +UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.name = 'Captain_Rottgrime'; +UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE npc_types.name = 'an_undead_marine'; +/* Pet Speeds. */ +UPDATE npc_types +JOIN pets ON npc_types.id = pets.npcID +SET npc_types.runspeed = 1.575; +/* raptors in tim are slower than other raptors in kunark */ +UPDATE npc_types +JOIN spawnentry ON npc_types.id = spawnentry.npcID +JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID +SET npc_types.runspeed = 1.325 +WHERE ( npc_types.race = 163 AND spawn2.zone = 'timorous' ); diff --git a/utils/sql/git/optional/2015_07_05_LiveCombatRounds.sql b/utils/sql/git/optional/2015_07_05_LiveCombatRounds.sql new file mode 100644 index 000000000..2a5377656 --- /dev/null +++ b/utils/sql/git/optional/2015_07_05_LiveCombatRounds.sql @@ -0,0 +1 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:UseLiveCombatRounds', 'true', 'If true use live NPC combat rules, false will use old rules.'); diff --git a/utils/sql/git/optional/2015_07_06_TripleAttack.sql b/utils/sql/git/optional/2015_07_06_TripleAttack.sql new file mode 100644 index 000000000..e5061e108 --- /dev/null +++ b/utils/sql/git/optional/2015_07_06_TripleAttack.sql @@ -0,0 +1,27 @@ +DELIMITER $$ +DROP PROCEDURE IF EXISTS GrantTripleAttack$$ +CREATE PROCEDURE GrantTripleAttack() + BEGIN + DECLARE finished INT; + DECLARE char_id INT; + DECLARE skill_max INT; + DECLARE cur CURSOR FOR SELECT character_data.id, skill_caps.cap FROM `character_data` LEFT JOIN `skill_caps` ON character_data.`level` = skill_caps.`level` AND character_data.class = skill_caps.class AND skill_caps.skillID = 76; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1; + + OPEN cur; + + SET finished = 0; + REPEAT + FETCH cur INTO char_id, skill_max; + + IF skill_max IS NOT NULL AND skill_max > 0 THEN + REPLACE INTO `character_skills` (`id`, `skill_id`, `value`) VALUES(char_id, 76, skill_max); + END IF; + UNTIL finished END REPEAT; + + CLOSE cur; + END$$ +DELIMITER ; + +CALL GrantTripleAttack(); +DROP PROCEDURE GrantTripleAttack; diff --git a/utils/sql/git/optional/2015_07_22_CommonTongue.sql b/utils/sql/git/optional/2015_07_22_CommonTongue.sql new file mode 100644 index 000000000..7fe6d3c4f --- /dev/null +++ b/utils/sql/git/optional/2015_07_22_CommonTongue.sql @@ -0,0 +1,4 @@ +INSERT INTO `rule_values` VALUES +('1', 'Character:IksarCommonTongue', '95', ''), +('1', 'Character:OgreCommonTongue', '95', ''), +('1', 'Character:TrollCommonTongue', '95', ''); \ No newline at end of file diff --git a/utils/sql/git/optional/2015_10_15_spells_new_update.sql b/utils/sql/git/optional/2015_10_15_spells_new_update.sql new file mode 100644 index 000000000..23dc2abb1 --- /dev/null +++ b/utils/sql/git/optional/2015_10_15_spells_new_update.sql @@ -0,0 +1,7 @@ +ALTER TABLE `spells_new` CHANGE `field209` `no_resist` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field232` `no_remove` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `maxtargets` `no_hd_item_mod` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `not_extendable` `not_focusable` INT(11) NOT NULL DEFAULT '0'; +ALTER TABLE `spells_new` CHANGE `field217` `override_crit` INT(11) NOT NULL DEFAULT '0'; + + diff --git a/utils/sql/git/optional/2015_12_26_oow_aa_missing.sql b/utils/sql/git/optional/2015_12_26_oow_aa_missing.sql new file mode 100644 index 000000000..50e3aade3 --- /dev/null +++ b/utils/sql/git/optional/2015_12_26_oow_aa_missing.sql @@ -0,0 +1,3 @@ +INSERT INTO `aa_ranks` (`id`, `upper_hotkey_sid`, `lower_hotkey_sid`, `title_sid`, `desc_sid`, `cost`, `level_req`, `spell`, `spell_type`, `recast_time`, `expansion`, `prev_id`, `next_id`) VALUES (1015, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1014, 1016); + +INSERT INTO `aa_rank_effects` (`rank_id`, `slot`, `effect_id`, `base1`, `base2`) VALUES (1015, 1, 262, 40, 7), (1015, 2, 262, 40, 8), (1015, 3, 262, 40, 9), (1015, 4, 262, 40, 10), (1015, 5, 262, 40, 11); diff --git a/utils/sql/git/required/2014_12_31_npc_types_default_values_update.sql b/utils/sql/git/required/2014_12_31_npc_types_default_values_update.sql index b75544981..d06f3f74c 100644 --- a/utils/sql/git/required/2014_12_31_npc_types_default_values_update.sql +++ b/utils/sql/git/required/2014_12_31_npc_types_default_values_update.sql @@ -1,3 +1,6 @@ +UPDATE `npc_types` SET `bodytype` = 0 WHERE `bodytype` IS NULL; ALTER TABLE `npc_types` MODIFY `bodytype` INT(11) NOT NULL DEFAULT '1'; +UPDATE `npc_types` SET `d_melee_texture1` = 0 WHERE `d_melee_texture1` IS NULL; ALTER TABLE `npc_types` MODIFY `d_melee_texture1` INT(11) NOT NULL DEFAULT '0'; +UPDATE `npc_types` SET `d_melee_texture2` = 0 WHERE `d_melee_texture2` IS NULL; ALTER TABLE `npc_types` MODIFY `d_melee_texture2` INT(11) NOT NULL DEFAULT '0'; diff --git a/utils/sql/git/required/2015_05_20_BuffInstrumentMod.sql b/utils/sql/git/required/2015_05_20_BuffInstrumentMod.sql new file mode 100644 index 000000000..140fe5b66 --- /dev/null +++ b/utils/sql/git/required/2015_05_20_BuffInstrumentMod.sql @@ -0,0 +1 @@ +ALTER TABLE `character_buffs` ADD COLUMN `instrument_mod` int(10) DEFAULT 10 NOT NULL; diff --git a/utils/sql/git/required/2015_05_23_BuffDurations.sql b/utils/sql/git/required/2015_05_23_BuffDurations.sql new file mode 100644 index 000000000..5f03039a6 --- /dev/null +++ b/utils/sql/git/required/2015_05_23_BuffDurations.sql @@ -0,0 +1,2 @@ +ALTER TABLE `character_buffs` CHANGE COLUMN `ticsremaining` `ticsremaining` INT(11) SIGNED NOT NULL; +ALTER TABLE `merc_buffs` CHANGE COLUMN `TicsRemaining` `TicsRemaining` INT(11) SIGNED NOT NULL DEFAULT 0; diff --git a/utils/sql/git/required/2015_05_23_PetBuffInstrumentMod.sql b/utils/sql/git/required/2015_05_23_PetBuffInstrumentMod.sql new file mode 100644 index 000000000..40cc453dc --- /dev/null +++ b/utils/sql/git/required/2015_05_23_PetBuffInstrumentMod.sql @@ -0,0 +1 @@ +ALTER TABLE `character_pet_buffs` ADD COLUMN `instrument_mod` tinyint UNSIGNED DEFAULT 10 NOT NULL; diff --git a/utils/sql/git/required/2015_05_23_dbstr_us.sql b/utils/sql/git/required/2015_05_23_dbstr_us.sql new file mode 100644 index 000000000..1eba0afa6 --- /dev/null +++ b/utils/sql/git/required/2015_05_23_dbstr_us.sql @@ -0,0 +1,6 @@ +CREATE TABLE `db_str` ( + `id` INT(10) NOT NULL, + `type` INT(10) NOT NULL, + `value` TEXT NOT NULL, + PRIMARY KEY (`id`, `type`) +); diff --git a/utils/sql/git/required/2015_05_25_npc_types_texture_fields.sql b/utils/sql/git/required/2015_05_25_npc_types_texture_fields.sql new file mode 100644 index 000000000..acd8d26b6 --- /dev/null +++ b/utils/sql/git/required/2015_05_25_npc_types_texture_fields.sql @@ -0,0 +1,6 @@ +ALTER TABLE npc_types +ADD COLUMN `armtexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `raid_target`, +ADD COLUMN `bracertexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `armtexture`, +ADD COLUMN `handtexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `bracertexture`, +ADD COLUMN `legtexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `handtexture`, +ADD COLUMN `feettexture` tinyint(2) NOT NULL DEFAULT '0' AFTER `legtexture`; \ No newline at end of file diff --git a/utils/sql/git/required/2015_06_07_aa_update.sql b/utils/sql/git/required/2015_06_07_aa_update.sql new file mode 100644 index 000000000..a888a75ea --- /dev/null +++ b/utils/sql/git/required/2015_06_07_aa_update.sql @@ -0,0 +1 @@ +ALTER TABLE character_alternate_abilities ADD COLUMN charges SMALLINT(11) UNSIGNED NOT NULL DEFAULT 0; diff --git a/utils/sql/git/required/2015_06_30_runspeed_adjustments.sql b/utils/sql/git/required/2015_06_30_runspeed_adjustments.sql new file mode 100644 index 000000000..f3feaec1a --- /dev/null +++ b/utils/sql/git/required/2015_06_30_runspeed_adjustments.sql @@ -0,0 +1,7 @@ +/* This rescales the old peq runspeeds which were about 80 percent too high to new values */ +/* This section should only ever be run once */ +UPDATE npc_types SET npc_types.runspeed = 1.050 WHERE (npc_types.runspeed > 0 and npc_types.runspeed < 1.2); +UPDATE npc_types SET npc_types.runspeed = 1.325 WHERE (npc_types.runspeed > 1.19 and npc_types.runspeed < 1.75 and race != 73 and race != 72); +UPDATE npc_types SET npc_types.runspeed = 1.575 WHERE (npc_types.runspeed > 1.69 and npc_types.runspeed < 2.2); +UPDATE npc_types SET npc_types.runspeed = 1.850 WHERE (npc_types.runspeed > 2.19 and npc_types.runspeed < 3); +UPDATE npc_types SET npc_types.runspeed = 3 WHERE npc_types.runspeed > 3; \ No newline at end of file diff --git a/utils/sql/git/required/2015_07_01_Marquee_Rule.sql b/utils/sql/git/required/2015_07_01_Marquee_Rule.sql new file mode 100644 index 000000000..039a34412 --- /dev/null +++ b/utils/sql/git/required/2015_07_01_Marquee_Rule.sql @@ -0,0 +1 @@ +INSERT INTO `rule_values` (`rule_name`, `rule_value`, `notes`) VALUES ('Character:MarqueeHPUpdates', 'false', 'Will show Health % in center of screen < 100%'); \ No newline at end of file diff --git a/utils/sql/git/required/2015_07_02_aa_rework.sql b/utils/sql/git/required/2015_07_02_aa_rework.sql new file mode 100644 index 000000000..77dde6b86 --- /dev/null +++ b/utils/sql/git/required/2015_07_02_aa_rework.sql @@ -0,0 +1,20679 @@ +DROP TABLE IF EXISTS `aa_ability`; +CREATE TABLE IF NOT EXISTS `aa_ability` ( + `id` int(10) unsigned NOT NULL, + `name` text NOT NULL, + `category` int(10) NOT NULL DEFAULT '-1', + `classes` int(10) NOT NULL DEFAULT '65535', + `races` int(10) NOT NULL DEFAULT '65535', + `drakkin_heritage` int(10) NOT NULL DEFAULT '127', + `deities` int(10) NOT NULL DEFAULT '131071', + `status` int(10) NOT NULL DEFAULT '0', + `type` int(10) NOT NULL DEFAULT '0', + `charges` int(11) NOT NULL DEFAULT '0', + `grant_only` tinyint(4) NOT NULL DEFAULT '0', + `first_rank_id` int(10) NOT NULL DEFAULT '-1', + `enabled` tinyint(3) unsigned NOT NULL DEFAULT '1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `aa_ability` (`id`, `name`, `category`, `classes`, `races`, `drakkin_heritage`, `deities`, `status`, `type`, `charges`, `grant_only`, `first_rank_id`, `enabled`) VALUES + (0, 'Unknown AA -1', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 49999, 1), + (1, 'Innate Strength', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 2, 1), + (2, 'Innate Stamina', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 7, 1), + (3, 'Innate Agility', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 12, 1), + (4, 'Innate Dexterity', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 17, 1), + (5, 'Innate Intelligence', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 22, 1), + (6, 'Innate Wisdom', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 27, 1), + (7, 'Innate Charisma', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 32, 1), + (8, 'Innate Fire Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 37, 1), + (9, 'Innate Cold Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 42, 1), + (10, 'Innate Magic Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 47, 1), + (11, 'Innate Poison Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 52, 1), + (12, 'Innate Disease Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 57, 1), + (13, 'Innate Run Speed', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 62, 1), + (15, 'Innate Metabolism', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 68, 1), + (16, 'Innate Lung Capacity', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 71, 1), + (17, 'First Aid', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 74, 1), + (18, 'Healing Adept', -1, 16942, 65535, 127, 131071, 0, 2, 0, 0, 77, 1), + (19, 'Healing Gift', -1, 16942, 65535, 127, 131071, 0, 2, 0, 0, 80, 1), + (20, 'Spell Casting Mastery', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 83, 1), + (21, 'Spell Casting Reinforcement', -1, 25150, 65535, 127, 131071, 0, 2, 0, 0, 86, 1), + (23, 'Spell Casting Fury', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 92, 1), + (25, 'Spell Casting Subtlety', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 98, 1), + (26, 'Spell Casting Expertise', -1, 15504, 65535, 127, 131071, 0, 2, 0, 0, 101, 1), + (27, 'Spell Casting Deftness', -1, 7184, 65535, 127, 131071, 0, 2, 0, 0, 104, 1), + (28, 'Natural Durability', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 107, 1), + (29, 'Natural Healing', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 110, 1), + (30, 'Combat Fury', -1, 16596, 65535, 127, 131071, 0, 2, 0, 0, 113, 1), + (31, 'Fear Resistance', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 116, 1), + (32, 'Finishing Blow', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 119, 1), + (33, 'Combat Stability', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 122, 1), + (34, 'Combat Agility', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 125, 1), + (35, 'Mass Group Buff', -1, 30254, 65535, 127, 131071, 0, 3, 0, 0, 128, 1), + (36, 'Divine Resurrection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 129, 1), + (37, 'Innate Invis to Undead', -1, 1026, 65535, 127, 131071, 0, 3, 0, 0, 130, 1), + (38, 'Celestial Regeneration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 131, 1), + (39, 'Bestow Divine Aura', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 132, 1), + (41, 'Purify Soul', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 136, 1), + (42, 'Quick Evacuation', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 137, 1), + (43, 'Exodus', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 140, 1), + (44, 'Quick Damage', -1, 6176, 65535, 127, 131071, 0, 3, 0, 0, 141, 1), + (45, 'Enhanced Root', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 144, 1), + (46, 'Dire Charm', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 145, 1), + (47, 'Cannibalization', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 146, 1), + (48, 'Quick Buff', -1, 25134, 65535, 127, 131071, 0, 2, 0, 0, 147, 1), + (49, 'Alchemy Mastery', 6, 512, 65535, 127, 131071, 0, 1, 0, 0, 150, 1), + (50, 'Rabid Bear', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 153, 1), + (52, 'Improved Familiar', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 155, 1), + (53, 'Nexus Gate', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 156, 1), + (55, 'Permanent Illusion', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 158, 1), + (56, 'Jewel Craft Mastery', 6, 8192, 65535, 127, 131071, 0, 1, 0, 0, 159, 1), + (57, 'Gather Mana', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 162, 1), + (58, 'Mend Companion', -1, 21504, 65535, 127, 131071, 0, 3, 0, 0, 163, 1), + (60, 'Frenzied Burnout', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 167, 1), + (61, 'Elemental Form: Fire', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 168, 1), + (62, 'Elemental Form: Water', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 171, 1), + (63, 'Elemental Form: Earth', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 174, 1), + (64, 'Elemental Form: Air', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 177, 1), + (67, 'Elemental Pact', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 182, 1), + (68, 'Life Burn', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 183, 1), + (69, 'Dead Mesmerization', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 184, 1), + (70, 'Fear Storm', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 185, 1), + (71, 'Flesh to Bone', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 186, 1), + (72, 'Call to Corpse', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 187, 1), + (73, 'Divine Stun', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 188, 1), + (75, 'Slay Undead', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 190, 1), + (76, 'Act of Valor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 193, 1), + (77, 'Holy Steed', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 194, 1), + (78, 'Fearless', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 195, 1), + (79, '2 Hand Bash', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 196, 1), + (80, 'Innate Camouflage', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 197, 1), + (81, 'Ambidexterity', -1, 16841, 65535, 127, 131071, 0, 3, 0, 0, 198, 1), + (82, 'Archery Mastery', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 199, 1), + (84, 'Endless Quiver', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 205, 1), + (85, 'Unholy Steed', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 206, 1), + (87, 'Leech Touch', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 208, 1), + (89, 'Soul Abrasion', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 210, 1), + (90, 'Instrument Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 213, 1), + (94, 'Jam Fest', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 225, 1), + (97, 'Critical Mend', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 230, 1), + (98, 'Purify Body', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 233, 1), + (100, 'Rapid Feign', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 237, 1), + (101, 'Return Kick', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 240, 1), + (102, 'Escape', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 243, 1), + (103, 'Poison Mastery', 6, 256, 65535, 127, 131071, 0, 1, 0, 0, 244, 1), + (104, 'Double Riposte', -1, 49501, 65535, 127, 131071, 0, 2, 0, 0, 247, 1), + (107, 'Purge Poison', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 254, 1), + (108, 'Flurry', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 255, 1), + (109, 'Rampage', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 258, 1), + (110, 'Area Taunt', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 259, 1), + (111, 'War Cry', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 260, 1), + (112, 'Bandage Wound', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 263, 1), + (114, 'Spell Casting Fury Mastery', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 267, 1), + (116, 'Dragon Punch', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 273, 1), + (117, 'Strong Root', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 274, 1), + (118, 'Singing Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 275, 1), + (119, 'Body and Mind Rejuvenation', -1, 16540, 65535, 127, 131071, 0, 3, 0, 0, 278, 1), + (120, 'Physical Enhancement', -1, 49629, 65535, 127, 131071, 0, 3, 0, 0, 279, 1), + (121, 'Adv. Trap Negotiation', -1, 384, 65535, 127, 131071, 0, 3, 0, 0, 280, 1), + (122, 'Acrobatics', -1, 448, 65535, 127, 131071, 0, 3, 0, 0, 283, 1), + (123, 'Scribble Notes', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 286, 1), + (124, 'Chaotic Stab', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 287, 1), + (125, 'Pet Discipline', -1, 22032, 65535, 127, 131071, 0, 3, 0, 0, 288, 1), + (126, 'Hobble of Spirits', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 289, 1), + (127, 'Frenzy of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 290, 1), + (128, 'Paragon of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 291, 1), + (129, 'Chains of Purity', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10348, 1), + (130, 'Resplendent Glory', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 8300, 1), + (131, 'Rage of Rallos Zek', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 8303, 1), + (132, 'Enhanced Area Taunt', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 8312, 1), + (133, 'Decapitation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 14200, 1), + (134, 'Hastened Berserking Disciplines', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 14203, 1), + (135, 'Quiet Miracle', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14206, 1), + (136, 'Repel the Wicked', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14207, 1), + (137, 'Beacon of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14208, 1), + (138, 'Blessed Chains', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14209, 1), + (139, 'Hastened Focused Celestial Regeneration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14213, 1), + (140, 'Quickened Spirit Calling', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14225, 1), + (141, 'New Tanaan Crafting Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 412, 1), + (142, 'Planar Power', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 418, 1), + (143, 'Planar Durability', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 423, 1), + (144, 'Innate Enlightenment', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 426, 1), + (146, 'Unknown AA 8001', 9, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8000, 0), + (147, 'Spiritual Rebuke', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14231, 1), + (148, 'Pathosis', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14232, 1), + (149, 'Preincarnation', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 14233, 1), + (150, 'Mastery of the Past', -1, 15504, 65535, 127, 131071, 0, 2, 0, 0, 446, 1), + (151, 'Spiritual Blessing', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14234, 1), + (152, 'Communion of the Cheetah', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14237, 1), + (153, 'Radiant Cure', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 459, 1), + (154, 'Hastened Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 462, 1), + (156, 'Hastened Purification of the Soul', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 468, 1), + (157, 'Hastened Gathering', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 471, 1), + (158, 'Hastened Rabidity', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 474, 1), + (159, 'Hastened Exodus', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 477, 1), + (160, 'Hastened Root', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 480, 1), + (161, 'Hastened Mending', -1, 21504, 65535, 127, 131071, 0, 3, 0, 0, 483, 1), + (163, 'Hastened Instigation', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 489, 1), + (164, 'Hastened Rampage', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 492, 1), + (165, 'Hastened Purification of the Body', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 495, 1), + (166, 'Hasty Exit', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 498, 1), + (167, 'Hastened Purification', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 501, 1), + (168, 'Hastened Nature\'s Fury', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14241, 1), + (169, 'Divine Arbitration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 507, 1), + (170, 'Wrath of the Wild', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 510, 1), + (171, 'Virulent Paralysis', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 513, 1), + (172, 'Harvest of Druzzil', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 516, 1), + (173, 'Eldritch Rune', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 517, 1), + (174, 'Servant of Ro', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 520, 1), + (175, 'Wake the Dead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 523, 1), + (176, 'Suspended Minion', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 526, 1), + (177, 'Spirit Call', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 528, 1), + (178, 'Wrath of the Forest Walker', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14244, 1), + (179, 'Gift of Sylvan Spirits', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14249, 1), + (180, 'Hand of Piety', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 534, 1), + (181, 'Mithaniel\'s Binding', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 537, 1), + (182, 'Summon Personal Tribute Master', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5006, 1), + (183, 'Extended Vinelash Cascade', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14254, 1), + (184, 'Guardian of the Forest', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 545, 1), + (185, 'Spirit of the Wood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 548, 1), + (186, 'Bestial Frenzy', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 551, 1), + (187, 'Harmonious Attack', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 556, 1), + (188, 'Knight\'s Advantage', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 561, 1), + (189, 'Ferocity', -1, 33097, 65535, 127, 131071, 0, 2, 0, 0, 564, 1), + (190, 'Viscid Roots', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 567, 1), + (193, 'Feigned Minion', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 574, 1), + (194, 'Unfailing Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 577, 1), + (195, 'Animation Empathy', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 580, 1), + (196, 'Rush to Judgment', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 583, 1), + (197, 'Living Shield', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 586, 1), + (198, 'Consumption of the Soul', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 589, 1), + (199, 'Boastful Bellow', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 592, 1), + (200, 'Fervent Blessing', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 593, 1), + (201, 'Touch of the Wicked', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 596, 1), + (202, 'Punishing Blade', -1, 32841, 65535, 127, 131071, 0, 2, 0, 0, 599, 1), + (203, 'Speed of the Knight', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 602, 1), + (204, 'Shroud of Stealth', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 605, 1), + (205, 'Nimble Evasion', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 606, 1), + (206, 'Technique of Master Wu', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 611, 1), + (207, 'Host of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 616, 1), + (208, 'Call of Xuzl', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 619, 1), + (209, 'Hastened Stealth', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 622, 1), + (210, 'Ingenuity', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 625, 1), + (211, 'Fleet of Foot', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 628, 1), + (212, 'Fading Memories', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 630, 1), + (213, 'Tactical Mastery', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 631, 1), + (214, 'Theft of Life', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 634, 1), + (215, 'Fury of Magic', -1, 13858, 65535, 127, 131071, 0, 2, 0, 0, 637, 1), + (216, 'Extended Spirit of the Bear', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14259, 1), + (217, 'Project Illusion', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 643, 1), + (218, 'Headshot', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 644, 1), + (219, 'Entrap', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 645, 1), + (220, 'Sonic Displacement', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 13528, 1), + (221, 'Total Domination', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 649, 1), + (222, 'Stalwart Endurance', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 652, 1), + (223, 'Quick Summoning', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 655, 1), + (224, 'Mental Clarity', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 658, 1), + (225, 'Innate Regeneration', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 661, 1), + (227, 'Extended Notes', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 665, 1), + (228, 'Hastened Warder\'s Gift', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13463, 1), + (229, 'Improved Reclaim Energy', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 671, 1), + (230, 'Hastened Possum', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13449, 1), + (231, 'Shauri\'s Sonorious Clouding', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 13527, 1), + (232, 'Veil of the Underbrush', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14262, 1), + (233, 'Packrat', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 678, 1), + (234, 'Heightened Endurance ', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 683, 1), + (235, 'Weapon Affinity', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 686, 1), + (236, 'Secondary Forte', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 691, 1), + (237, 'Persistent Casting', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 692, 1), + (238, 'Tune of Pursuance', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 695, 1), + (239, 'Hastened Companion\'s Sacrifice', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13474, 1), + (240, 'Cheetah\'s Pounce', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13483, 1), + (241, 'Bloodlust', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13484, 1), + (242, 'Primal Fury', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13485, 1), + (244, 'Lure of the Siren\'s Song', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 13529, 1), + (245, 'Bestial Alignment', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 718, 1), + (246, 'Hidden Communion of the Cheetah', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14265, 1), + (247, 'Feral Swipe', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 723, 1), + (248, 'Warder\'s Fury', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 724, 1), + (249, 'Warder\'s Alacrity', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 729, 1), + (250, 'Pet Affinity', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 734, 1), + (251, 'Mastery of the Past', -1, 16942, 65535, 127, 131071, 0, 2, 0, 0, 735, 1), + (252, 'Spell Casting Subtlety', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 738, 1), + (254, 'Divine Avatar', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 746, 1), + (255, 'Exquisite Benediction', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 749, 1), + (256, 'Hastened Curing', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 754, 1), + (257, 'Nature\'s Boon', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 757, 1), + (258, 'Advanced Tracking', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 762, 1), + (259, 'Critical Affliction', -1, 18104, 65535, 127, 131071, 0, 2, 0, 0, 767, 1), + (260, 'Glacial Arrow', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13549, 1), + (261, 'Doppelganger', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 773, 1), + (262, 'Enhanced Forgetfulness', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 776, 1), + (263, 'Mesmerization Mastery', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 781, 1), + (264, 'Quick Mass Group Buff', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 782, 1), + (265, 'Shared Health', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 785, 1), + (266, 'Elemental Fury', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 790, 1), + (267, 'Elemental Alacrity ', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 795, 1), + (268, 'Elemental Agility', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 800, 1), + (269, 'Elemental Durability', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 803, 1), + (270, 'Sinister Strikes', -1, 16841, 65535, 127, 131071, 0, 3, 0, 0, 806, 1), + (271, 'Strikethrough', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 807, 1), + (272, 'Stonewall', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 810, 1), + (273, 'Rapid Strikes ', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 815, 1), + (274, 'Kick Mastery', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 820, 1), + (275, 'Heightened Awareness', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 823, 1), + (276, 'Destructive Force ', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 828, 1), + (278, 'Death\'s Fury ', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 834, 1), + (279, 'Quickening of Death ', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 839, 1), + (280, 'Group Perfected Invisibility to Undead', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 14281, 1), + (281, 'Triple Backstab', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 846, 1), + (282, 'Hastened Piety', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 849, 1), + (283, 'Immobilizing Bash', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 852, 1), + (284, 'Vicious Smash', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 855, 1), + (285, 'Radiant Cure', -1, 4, 65535, 127, 131071, 0, 2, 0, 0, 860, 1), + (286, 'Purification ', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 863, 1), + (287, 'Precision of the Pathfinder', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 864, 1), + (288, 'Coat of Thistles', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 867, 1), + (289, 'Flaming Arrows', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 872, 1), + (290, 'Frost Arrows', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 875, 1), + (291, 'Perfected Invisibility to Undead', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 14282, 1), + (292, 'Trap Circumvention ', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 881, 1), + (293, 'Quickened Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14283, 1), + (294, 'Virulent Venom ', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 888, 1), + (295, 'Extended Dreary Deeds', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14286, 1), + (296, 'Intense Hatred', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 895, 1), + (297, 'Quickened Frenzied Burnout', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 14289, 1), + (299, 'Sturdiness', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 907, 1), + (300, 'Warlord\'s Tenacity ', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 912, 1), + (301, 'Strengthened Strike', -1, 9, 65535, 127, 131071, 0, 3, 0, 0, 915, 1), + (302, 'Extended Shielding', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 918, 1), + (303, 'Ro\'s Flaming Familiar ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 921, 1), + (304, 'E\'ci\'s Icy Familiar ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 922, 1), + (305, 'Druzzil\'s Mystical Familiar ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 923, 1), + (306, 'Unknown AA 15819', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15819, 1), + (307, 'Ward of Destruction ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 926, 1), + (308, 'Frenzied Devastation', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 931, 1), + (309, 'Combat Fury', -1, 32769, 65535, 127, 131071, 0, 2, 0, 0, 934, 1), + (310, 'Combat Fury', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 937, 1), + (311, 'Combat Fury', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 940, 1), + (312, 'Quickened Host of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 14292, 1), + (313, 'Hastened Companion\'s Relocation', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 14295, 1), + (314, 'Veteran\'s Wrath', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1047, 1), + (315, 'Planar Durability', -1, 32788, 65535, 127, 131071, 0, 3, 0, 0, 952, 1), + (316, 'Innate Enlightenment', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 955, 1), + (317, 'Dire Charm', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 960, 1), + (318, 'Dire Charm', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 961, 1), + (319, 'Touch of the Divine', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 962, 1), + (320, 'Swarm of Decay', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 967, 1), + (321, 'Call of the Ancients', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 970, 1), + (322, 'Innate See Invis', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1388, 1), + (323, 'Virulent Talon', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 14307, 1), + (324, 'Blacksmithing Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 979, 1), + (325, 'Baking Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 982, 1), + (326, 'Brewing Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 985, 1), + (327, 'Fletching Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 988, 1), + (328, 'Pottery Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 991, 1), + (329, 'Tailoring Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 994, 1), + (330, 'Salvage', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 997, 1), + (331, 'Origin', 9, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1000, 1), + (333, 'Discordant Defiance', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1006, 1), + (334, 'Mystical Attuning', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1021, 1), + (335, 'Delay Death', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1026, 1), + (336, 'Earthen Brawn', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8263, 1), + (337, 'Unknown AA 15798', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15798, 1), + (338, 'Veteran\'s Wrath', -1, 16596, 65535, 127, 131071, 0, 2, 0, 0, 1041, 1), + (339, 'Veteran\'s Wrath', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1044, 1), + (340, 'Unknown AA 15833', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15833, 1), + (341, 'Veteran\'s Wrath', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 1050, 1), + (342, 'Staff Block', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 14301, 1), + (343, 'Hastened Pestilent Paralysis', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14308, 1), + (344, 'Hastened Mercurial Torment', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14311, 1), + (345, 'Unknown AA 15768', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15768, 1), + (346, 'Unknown AA 15771', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 15771, 1), + (347, 'Mnemonic Retention', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 1071, 1), + (348, 'Expansive Mind', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 1072, 1), + (350, 'Death\'s Malaise', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14321, 1), + (351, 'Dying Grasp', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14322, 1), + (352, 'Arcane Tongues', 6, 15360, 65535, 127, 131071, 0, 2, 0, 0, 1089, 1), + (353, 'Master of Disguise', -1, 384, 65535, 127, 131071, 0, 3, 0, 0, 1092, 1), + (354, 'Slippery Attacks', -1, 16841, 65535, 127, 131071, 0, 2, 0, 0, 1093, 1), + (355, 'Unknown AA 15836', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15836, 1), + (357, 'Unknown AA 16176', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16176, 1), + (358, 'Fury of Magic', -1, 16540, 65535, 127, 131071, 0, 2, 0, 0, 1107, 1), + (359, 'Dance of Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1110, 1), + (360, 'Bloodthirsty Blade', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13616, 1), + (361, 'Shield of Notes', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1116, 1), + (362, 'Roar of Thunder', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 1119, 1), + (363, 'Unknown AA 16179', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16179, 1), + (364, 'Persistent Minion', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 1122, 1), + (365, 'A Hole In Space', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 14323, 1), + (366, 'Advanced Pet Discipline', -1, 22032, 65535, 127, 131071, 0, 3, 0, 0, 1129, 1), + (367, 'Throwing Mastery', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1131, 1), + (368, 'Blur of Axes', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1134, 1), + (369, 'Hastened War Cry', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1137, 1), + (370, 'Dead Aim', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1140, 1), + (371, 'Frenzied Defense', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1166, 1), + (372, 'Tireless Sprint', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1146, 1), + (373, 'Desperation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1149, 1), + (374, 'Untamed Rage', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1150, 1), + (375, 'Echoing Cries', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1155, 1), + (376, 'Distant Strike', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14372, 1), + (377, 'Earthen Stability', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8268, 1), + (378, 'Earthen Alacrity', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8273, 1), + (379, 'Earthen Artistry', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8278, 1), + (380, 'Earthen Sagacity', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8283, 1), + (381, 'Earthen Brilliance', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8288, 1), + (382, 'Earthen Allure', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8293, 1), + (383, 'Extended Spirit of the Wood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12646, 1), + (384, 'Spirit of the Bear', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12651, 1), + (385, 'Twinheal', -1, 16942, 65535, 127, 131071, 0, 2, 0, 0, 12652, 1), + (386, 'Nature\'s Fury', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12661, 1), + (387, 'Blood Pact', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1178, 1), + (388, 'Shielding Resistance', -1, 16841, 65535, 127, 131071, 0, 2, 0, 0, 1181, 1), + (389, 'Healing Boon', -1, 518, 65535, 127, 131071, 0, 2, 0, 0, 1186, 1), + (390, 'Elemental Union', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 13695, 1), + (391, 'Celestial Hammer', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1192, 1), + (392, 'Divine Retribution', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1195, 1), + (393, 'Nature\'s Blessing', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12655, 1), + (394, 'Extended Convergence of Spirit', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12645, 1), + (395, 'Hastened Storm Strike', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12664, 1), + (396, 'Sanctuary', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1209, 1), + (397, 'Destructive Fury', -1, 2048, 65535, 127, 131071, 0, 2, 0, 0, 1210, 1), + (398, 'Destructive Fury', -1, 13858, 65535, 127, 131071, 0, 2, 0, 0, 1213, 1), + (399, 'Unknown AA 16180', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16180, 1), + (400, 'Hastened Improved Twincast', -1, 14370, 65535, 127, 131071, 0, 3, 0, 0, 14331, 1), + (401, 'Extended Heel of Kanji', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 12688, 1), + (402, 'Extended Scaledfist', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 12691, 1), + (403, 'Paralytic Spores', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 14264, 1), + (404, 'Call of the Wild', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 1228, 1), + (405, 'Secondary Recall', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 1229, 1), + (406, 'Nature\'s Bounty', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 1230, 1), + (407, 'Extended Speed Focus', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7884, 1), + (408, 'Extended Crystalpalm', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7885, 1), + (409, 'Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1233, 1), + (410, 'Fists of Steel', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 12706, 1), + (411, 'Extended Deftdance', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12709, 1), + (412, 'Color Shock', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1239, 1), + (413, 'Mind Over Matter', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1242, 1), + (414, 'Soothing Words', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1245, 1), + (415, 'Hastened Deftdance', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12710, 1), + (416, 'Hastened Lyre Leap', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12713, 1), + (417, 'Hastened Quick Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12716, 1), + (418, 'Replenish Companion', -1, 21504, 65535, 127, 131071, 0, 3, 0, 0, 1126, 1), + (419, 'Extended Quick Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12719, 1), + (420, 'Imitate Death', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1255, 1), + (424, 'Extended Fierce Eye', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12720, 1), + (425, 'Hastened Fierce Eye', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12721, 1), + (426, 'Unknown AA 15904', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 15904, 1), + (427, 'Resounding Dirge', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12737, 1), + (428, 'Death Peace', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 1272, 1), + (429, 'Unknown AA 15908', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15908, 1), + (430, 'Mercurial Torment', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12766, 1), + (431, 'Pestilent Paralysis', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12770, 1), + (432, 'Hastened Divine Companion Aura', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 12773, 1), + (433, 'Embalmer\'s Carapace', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12778, 1), + (434, 'Steadfast Will', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 1284, 1), + (435, 'Shield Block', -1, 21, 65535, 127, 131071, 0, 2, 0, 0, 1287, 1), + (436, 'Hastened Encroaching Darkness', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12779, 1), + (437, 'Tracking Mastery', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1296, 1), + (438, 'Expanding Darkness', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12782, 1), + (439, 'Precision', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1304, 1), + (440, 'Nerves of Steel', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1307, 1), + (441, 'Aegis of Kildrukaun', -1, 5120, 65535, 127, 131071, 0, 3, 0, 0, 12785, 1), + (442, 'Touch of the Cursed', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 1313, 1), + (443, 'Bestial Bloodrage', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12804, 1), + (444, 'Companion\'s Sacrifice', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12807, 1), + (445, 'Shield Block', -1, 16384, 65535, 127, 131071, 0, 2, 0, 0, 12813, 1), + (446, 'Spiritual Channeling', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 1323, 1), + (447, 'Ancestral Aid', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 1327, 1), + (448, 'Extended Feralgia', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12816, 1), + (450, 'Hastened Protective Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12819, 1), + (451, 'Mind Crash', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1334, 1), + (452, 'Prolonged Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1337, 1), + (453, 'Summon Permutation Peddler', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 9032, 1), + (454, 'Hastened Empathic Fury', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12822, 1), + (455, 'Convergence of Spirits', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13556, 1), + (456, 'Teleport Bind', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1343, 1), + (457, 'Quickened Paragon of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12831, 1), + (458, 'Warder\'s Gift', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12837, 1), + (459, 'Gelid Rending', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12846, 1), + (460, 'Quickened Nature\'s Salve', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12849, 1), + (462, 'Auspice of the Hunter', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1345, 1), + (463, 'Divine Guardian', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 13385, 1), + (464, 'Divine Peace', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 13388, 1), + (465, 'Savage Spirit', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1348, 1), + (466, 'Trials of Mata Muram', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1011, 1), + (467, 'Press the Attack', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 1351, 1), + (468, 'Crippling Strike', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1352, 1), + (469, 'Stunning Kick', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1355, 1), + (470, 'Eye Gouge', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1358, 1), + (471, 'Gift of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1361, 1), + (472, 'Tenacity of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1362, 1), + (473, 'Embrace of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1363, 1), + (474, 'Power of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1364, 1), + (475, 'Fervor of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1365, 1), + (476, 'Gift of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1366, 1), + (477, 'Valor of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1367, 1), + (478, 'Embrace of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1368, 1), + (479, 'Power of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1369, 1), + (480, 'Sanctity of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1370, 1), + (481, 'Lesson of the Devoted', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1371, 1), + (482, 'Infusion of the Faithful', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1372, 1), + (483, 'Chaotic Jester', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1373, 1), + (484, 'Expedient Recovery', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1374, 1), + (485, 'Steadfast Servant', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1375, 1), + (486, 'Staunch Recovery', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1376, 1), + (487, 'Intensity of the Resolute', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1377, 1), + (488, 'Curse of Blood', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1378, 1), + (489, 'Yaulp', -1, 6, 65535, 127, 131071, 0, 3, 0, 0, 13389, 1), + (490, 'Abscond', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12864, 1), + (491, 'Atol\'s Unresistable Shackles', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12865, 1), + (492, 'Dimensional Shield', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 12866, 1), + (493, 'Improved Sustained Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12867, 1), + (494, 'Silent Casting', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 1409, 1), + (495, 'Gift of Mana', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 1435, 1), + (496, 'Field Dressing', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 1611, 1), + (497, 'Bandage Wounds', -1, 32766, 65535, 127, 131071, 0, 1, 0, 0, 1420, 1), + (498, 'Enhanced Aggression', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 1592, 1), + (499, 'Cascading Rage', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1425, 1), + (500, 'Silent Casting', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 1404, 1), + (501, 'E\'ci\'s Icy Blessing', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12886, 1), + (503, 'Hastened Thunder', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 1471, 1), + (504, 'Conservation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1453, 1), + (505, 'Cry of Battle', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1458, 1), + (506, 'Ward of Purity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1459, 1), + (507, 'Ro\'s Fiery Blessing', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12887, 1), + (508, 'Druzzil\'s Mystical Blessing', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12888, 1), + (509, 'Kerafyrm\'s Favor', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12889, 1), + (510, 'Kerafyrm\'s Prismatic Familiar', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12892, 1), + (511, 'Throne of Heroes', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 4665, 1), + (512, 'Translocational Anchor', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1630, 1), + (513, 'Hastened Phantasmal Opponent', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12894, 1), + (514, 'Pyromancy', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1478, 1), + (515, 'Improved Twincast', -1, 14370, 65535, 127, 131071, 0, 3, 0, 0, 12893, 1), + (516, 'Abundant Healing', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 1486, 1), + (517, 'Hastened First Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12902, 1), + (518, 'Shared Camouflage', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 1494, 1), + (519, 'Convergence of Spirits', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 1495, 1), + (520, 'Nature\'s Guardian', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 1498, 1), + (521, 'Edict of Command', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1501, 1), + (522, 'Extended Burnout', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1504, 1), + (523, 'Hastened Second Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12907, 1), + (524, 'Blood Magic', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 1510, 1), + (525, 'Graverobbing', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 1511, 1), + (526, 'Affliction Mastery', -1, 1568, 65535, 127, 131071, 0, 3, 0, 0, 1514, 1), + (527, 'Hastened Third Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12912, 1), + (528, 'Ancestral Guard', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 1520, 1), + (529, 'Cloak of Light', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 1523, 1), + (530, 'Profound Visage', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12920, 1), + (531, 'Cloak of Shadows', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 1527, 1), + (532, 'Willful Death', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 1528, 1), + (533, 'Unknown AA 16016', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16016, 1), + (534, 'Calculated Insanity', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12931, 1), + (535, 'Crippling Aurora', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12937, 1), + (536, 'Appraisal', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1542, 1), + (537, 'Precise Strikes', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1543, 1), + (538, 'Hastened Death', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1546, 1), + (539, 'Unflinching Resolve', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1549, 1), + (540, 'Weightless Steps', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1552, 1), + (541, 'Hastened Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1555, 1), + (542, 'Unknown AA 16071', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 16071, 1), + (543, 'Diminutive Companion', -1, 20480, 65535, 127, 131071, 0, 3, 0, 0, 12941, 1), + (544, 'Song of Stone', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1569, 1), + (545, 'Deep Sleep', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1572, 1), + (546, 'Companion\'s Gift', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1577, 1), + (547, 'Unknown AA 16081', -1, 15360, 65535, 127, 131071, 0, 3, 0, 0, 16081, 1), + (548, 'Hastened Defiance', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 1583, 1), + (549, 'Dauntless Perseverance', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 1591, 1), + (550, 'Steadfast Resolve', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 14275, 1), + (551, 'Hastened Mind Crash', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1414, 1), + (552, 'Call of Challenge', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 1597, 1), + (553, 'Cacophony', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1598, 1), + (554, 'Hastened Nightmare Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14341, 1), + (555, 'Anatomy', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1604, 1), + (556, 'Scintillating Beam', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14346, 1), + (557, 'Trick Shot', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1608, 1), + (558, 'Turn Undead', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1383, 1), + (559, 'Turn Summoned', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1462, 1), + (560, 'Selo\'s Enduring Cadence', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1627, 1), + (561, 'Hastened Harvest of Druzzil', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12881, 1), + (562, 'Lightning Strikes', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1616, 1), + (563, 'Concentration', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 1588, 1), + (565, 'Mana Burn', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1638, 1), + (567, 'Unknown AA 16146', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16146, 1), + (568, 'Thief\'s Intuition', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1641, 1), + (569, 'Thief\'s Intuition', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1642, 1), + (570, 'Valiant Steed', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 1645, 1), + (571, 'Abyssal Steed', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 1646, 1), + (572, 'Holy Warhorse', -1, 4, 65535, 127, 131071, 0, 3, 0, 1, 1643, 1), + (573, 'Unholy Warhorse', -1, 16, 65535, 127, 131071, 0, 3, 0, 1, 1644, 1), + (574, 'Harmonic Dissonance', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1647, 1), + (575, 'Tinkering Mastery', 6, 15639, 65535, 127, 131071, 0, 1, 0, 1, 4672, 1), + (576, 'Jewel Craft Mastery ', 6, 57343, 65535, 127, 131071, 0, 1, 0, 0, 4675, 1), + (577, 'Concussive Intuition', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12885, 1), + (578, 'Glyph Spray', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12939, 1), + (579, 'Combat Medic ', -1, 32766, 65535, 127, 131071, 0, 1, 0, 0, 4688, 1), + (580, 'Hastened Outrider\'s Accuracy', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13565, 1), + (581, 'Quick Draw', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 4698, 1), + (582, 'Battle Ready', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 4699, 1), + (583, 'Hastened Outrider\'s Evasion', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13568, 1), + (584, 'Grasp of Sylvan Spirits', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13571, 1), + (585, 'Glyph of Dragon Scales', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 4702, 1), + (586, 'Glyph of Indeterminable Reward', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 13788, 1), + (587, 'Glyph of Arcane Secrets', 7, 32318, 65535, 127, 131071, 0, 4, 1, 0, 4704, 1), + (588, 'Glyph of Draconic Potential', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 4705, 1), + (589, 'Glyph of Destruction', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 4706, 1), + (590, 'Breath of Atathus', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5150, 1), + (591, 'Breath of Draton\'ra', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5165, 1), + (592, 'Breath of Osh\'vir', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5180, 1), + (593, 'Breath of Venesh', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5195, 1), + (594, 'Breath of Mysaphar', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5210, 1), + (595, 'Breath of Keikolin', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5225, 1), + (596, 'Small Modulation Shard', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 12963, 1), + (597, 'Medium Modulation Shard', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 12964, 1), + (598, 'Large Modulation Shard', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 12965, 1), + (599, 'Hastened Malosinete', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 12968, 1), + (600, 'Blessing of the Devoted', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 9033, 1), + (601, 'Grappling Strike', -1, 65, 65535, 127, 131071, 0, 3, 0, 0, 4836, 1), + (602, 'Mental Contortion', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12938, 1), + (603, 'Shield of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 12971, 1), + (604, 'Extended Malosinete', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 12977, 1), + (605, 'Shield Specialist', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 4844, 1), + (606, 'Mark of the Mage Hunter', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 4849, 1), + (609, 'Uncanny Resilience', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 4854, 1), + (610, 'Blinding Fury', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 4857, 1), + (611, 'Battle Leap', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 4860, 1), + (612, 'Soul Seeker', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 4861, 1), + (613, 'Lingering Death', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13096, 1), + (614, 'Spirit Guardian', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 5369, 1), + (615, 'Surreality', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4887, 1), + (616, 'Mana Draw', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4890, 1), + (617, 'Doppelganger\'s Beckon', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 5127, 1), + (618, 'Armor of Ancestral Spirits', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 12989, 1), + (619, 'Group Pact of the Wolf', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 12992, 1), + (620, 'Hastened Inconspicuous Totem', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13001, 1), + (621, 'Fire Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 4903, 1), + (622, 'Vapor Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 4906, 1), + (623, 'Ice Core ', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 4909, 1), + (624, 'Stone Core ', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 4912, 1), + (625, 'Volatile Mana Blaze', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 4915, 1), + (626, 'Purified Spirits', -1, 546, 65535, 127, 131071, 0, 3, 0, 0, 13004, 1), + (627, 'Group Spirit Walk', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13008, 1), + (628, 'Greater Blood Tithe', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 4924, 1), + (629, 'Gathering Dusk', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 4927, 1), + (630, 'Group Silent Presence', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13009, 1), + (631, 'Double Attack', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 5366, 1), + (632, 'Sanguine Mind Crystal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4934, 1), + (633, 'Azure Mind Crystal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4935, 1), + (634, 'Hastened Cannibalization', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13010, 1), + (635, 'Hastened Spirit Channeling', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13013, 1), + (636, 'Arcane Whisper', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 4938, 1), + (637, 'Vengeful Spirits', -1, 9776, 65535, 127, 131071, 0, 3, 0, 0, 13017, 1), + (638, 'Crippling Apparition', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13020, 1), + (639, 'Dimensional Instability', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 4943, 1), + (640, 'Cryomancy', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 4944, 1), + (641, 'Hastened Self Preservation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13055, 1), + (642, 'Binding Axe', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13065, 1), + (643, 'Agony of Absolution', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13066, 1), + (644, 'Hastened Absolution', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13067, 1), + (645, 'Hastened Calculated Insanity', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 13753, 1), + (646, 'Hastened Mental Contortion', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 13758, 1), + (647, 'Hastened Crippling Aurora', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 13764, 1), + (649, 'Hastened Leech Touch', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14046, 1), + (650, 'Bony Grasp of Death', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14051, 1), + (651, 'Thought Leech', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14052, 1), + (652, 'Hastened Leechcurse Discipline', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14056, 1), + (653, 'Hastened Unholy Aura Discipline', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14059, 1), + (654, 'Hastened Harmshield', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 14062, 1), + (655, 'Hastened Projection of Doom', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14065, 1), + (656, 'Hastened Projection of Piety', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14068, 1), + (657, 'Shield of Brilliance', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14071, 1), + (658, 'Hastened Sanctification Discipline', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14076, 1), + (659, 'Speed of the Savior', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14080, 1), + (660, 'Divine Call', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14081, 1), + (661, 'Hunter\'s Fury', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 5248, 1), + (662, 'Union of Spirits', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 5251, 1), + (663, 'Quickened Stuns', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14100, 1), + (664, 'Extended Outrider\'s Attack', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 14115, 1), + (665, 'Death\'s Wrath', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 5264, 1), + (666, 'Taste of Blood', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 5015, 1), + (667, 'Summoner\'s Beckon', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 5269, 1), + (668, 'Hymn of the Last Stand', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 5017, 1), + (669, 'Bladed Song', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 5020, 1), + (670, 'Twisted Shank', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 5021, 1), + (671, 'Dirty Fighting', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 5022, 1), + (672, 'Ligament Slice', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 5025, 1), + (673, 'Tumble', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 5028, 1), + (674, 'Unknown AA 16149', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16149, 1), + (675, 'Shrink', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14224, 1), + (676, 'Convergence', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14358, 1), + (677, 'Gift of Deathly Resolve', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14359, 1), + (678, 'Unknown AA 16082', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 16082, 1), + (679, 'Unknown AA 16083', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 16083, 1), + (680, 'Unknown AA 16084', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16084, 1), + (681, 'Unknown AA 16087', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16087, 1), + (682, 'Unknown AA 16096', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16096, 1), + (683, 'Unknown AA 16097', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16097, 1), + (684, 'Unknown AA 16104', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16104, 1), + (685, 'Unknown AA 16105', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16105, 1), + (686, 'Unknown AA 16106', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16106, 1), + (687, 'Unknown AA 16107', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16107, 1), + (688, 'Unknown AA 16108', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16108, 1), + (689, 'Combat Medic ', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 5136, 1), + (690, 'Unknown AA 16109', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16109, 1), + (691, 'Unknown AA 16113', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16113, 1), + (692, 'Unknown AA 16114', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16114, 1), + (693, 'Unknown AA 16117', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16117, 1), + (694, 'Unknown AA 16120', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16120, 1), + (695, 'Unknown AA 16152', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16152, 1), + (696, 'Unknown AA 16156', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16156, 1), + (697, 'Mortal Coil', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 5085, 1), + (698, 'Hastened Purified Spirits', -1, 546, 65535, 127, 131071, 0, 3, 0, 0, 13416, 1), + (699, 'Swarm of Fireflies', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 13419, 1), + (700, 'Unknown AA 16159', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16159, 1), + (701, 'Armor of the Inquisitor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 5095, 1), + (702, 'Hand of Disruption', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 5098, 1), + (703, 'Quickened Death Bloom', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14318, 1), + (704, 'Hero\'s Barracks', 9, 65535, 65535, 127, 131071, 0, 4, 0, 1, 14367, 1), + (705, 'Spirit of the White Wolf', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 5105, 1), + (706, 'Unknown AA 16160', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16160, 1), + (707, 'Pact of the Wolf', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 5109, 1), + (708, 'Enchant Alaran Metal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 13271, 1), + (709, 'Mass Enchant Alaran Metal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 13272, 1), + (710, 'Funeral Pyre', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14360, 1), + (711, 'Unknown AA 16162', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16162, 1), + (712, 'Hastened Sanctuary', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 5118, 1), + (713, 'Etherium Blades', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14129, 1), + (714, 'Hastened Assassination Disciplines', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14135, 1), + (715, 'Cunning Disguise: Shissar', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14139, 1), + (716, 'Scout\'s Mastery of Piercing', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14141, 1), + (717, 'Extended Envenomed Blades', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14144, 1), + (718, 'Heel of Brithrax', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14151, 1), + (719, 'Extended Zan Fi\'s Whistle', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14163, 1), + (720, 'Hastened Marr\'s Salvation', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14088, 1), + (721, 'Hastened Armor of the Inquisitor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14091, 1), + (722, 'Hastened Drape of Shadows', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 14304, 1), + (723, 'Unknown AA 16185', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16185, 1), + (724, 'Hastened Eldritch Rune', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14364, 1), + (725, 'Unknown AA 16124', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 16124, 1), + (726, 'Unknown AA 16128', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 16128, 1), + (727, 'Unknown AA 16131', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 16131, 1), + (728, 'Unknown AA 16137', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 16137, 1), + (729, 'Unknown AA 16140', -1, 6, 65535, 127, 131071, 0, 3, 0, 0, 16140, 1), + (730, 'Unknown AA 16186', -1, 9, 65535, 127, 131071, 0, 3, 0, 0, 16186, 1), + (731, 'Unknown AA 16188', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16188, 1), + (732, 'Unknown AA 16195', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16195, 1), + (733, 'Killing Spree', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 4739, 1), + (734, 'Hold the Line', -1, 32833, 65535, 127, 131071, 0, 3, 0, 0, 4742, 1), + (735, 'Battle Frenzy', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 13134, 1), + (737, 'Quickened Silent Casting', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 13143, 1), + (738, 'Quickened Silent Casting', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 13146, 1), + (739, 'Balefire Burst', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13164, 1), + (740, 'Blood Tithe', -1, 1568, 65535, 127, 131071, 0, 3, 0, 0, 4761, 1), + (741, 'Leap of Faith', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13202, 1), + (742, 'Unknown AA 16196', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16196, 1), + (743, 'Hastened Explosion of Hatred', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13166, 1), + (744, 'Howl of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13169, 1), + (745, 'Hastened Tune In Your Head', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 13204, 1), + (746, 'Unknown AA 16197', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16197, 1), + (747, 'Unknown AA 16200', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16200, 1), + (748, 'Nightmare Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4894, 1), + (749, 'Explosion of Spite', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13165, 1), + (751, 'Scent of Terris', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13225, 1), + (752, 'Bloodfury', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13224, 1), + (753, 'Dreary Deeds', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 13252, 1), + (754, 'Enchant Feymetal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 13260, 1), + (755, 'Mass Enchant Feymetal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 13261, 1), + (756, 'Enlightened Focus of Arcanum', -1, 15904, 65535, 127, 131071, 0, 3, 0, 0, 13646, 1), + (757, 'Shifting Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 5276, 1), + (758, 'Extended Silent Casting', -1, 15360, 65535, 127, 131071, 0, 3, 0, 0, 13667, 1), + (759, 'Fury of Kerafyrm', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 13670, 1), + (760, 'Unknown AA 16203', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 16203, 1), + (761, 'Unknown AA 16208', -1, 552, 65535, 127, 131071, 0, 3, 0, 0, 16208, 1), + (762, 'Shield Block', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 5283, 1), + (763, 'Mirrored Pestilence', -1, 1552, 65535, 127, 131071, 0, 3, 0, 0, 13684, 1), + (764, 'Embrace The Decay', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13687, 1), + (765, 'Quickened Scent of Terris', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13689, 1), + (766, 'Frenzy of the Dead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13693, 1), + (767, 'Unknown AA 16211', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 16211, 1), + (768, 'Unknown AA 16215', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 16215, 1), + (769, 'Marr\'s Salvation', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13100, 1), + (770, 'Blessing of the Faithful', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13101, 1), + (771, 'Unbridled Strike of Fear', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13108, 1), + (772, 'Noteworthy Disguise: Drake', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14192, 1), + (773, 'Death\'s Effigy', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13133, 1), + (774, 'Empowered Focus of Arcanum', -1, 15904, 65535, 127, 131071, 0, 3, 0, 0, 14690, 1), + (775, 'Unknown AA 16342', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16342, 1), + (776, 'Arcane Overkill', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 5295, 1), + (777, 'Funeral Dirge', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 5298, 1), + (778, 'Protection of the Spirit Wolf', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 5007, 1), + (779, 'Hastened Juggernaut Surge', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13873, 1), + (780, 'Hastened Resilience', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13878, 1), + (781, 'Hastened Blood Pact', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13881, 1), + (782, 'Unknown AA 16317', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 16317, 1), + (783, 'Energetic Attunement', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1056, 1), + (784, 'Heart of Flames', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1251, 1), + (785, 'Heart of Vapor', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1252, 1), + (786, 'Heart of Ice', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1253, 1), + (787, 'Heart of Stone', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1254, 1), + (789, 'Stealthy Getaway', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1477, 1), + (790, 'Seized Opportunity', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 878, 1), + (791, 'Veil of Mindshadow', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4931, 1), + (792, 'Army of the Dead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 1274, 1), + (793, 'Mana Blast', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1639, 1), + (794, 'Mana Blaze', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1640, 1), + (795, 'Innate Corruption Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1662, 1), + (796, 'Hastened Five Point Palm', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 13889, 1), + (797, 'Moving Mountains', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 13130, 1), + (798, 'Veturika\'s Perseverance', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14229, 1), + (799, 'Unknown AA 16644', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16644, 1), + (800, 'Vehement Rage', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 6607, 1), + (801, 'Knee Strike', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6610, 1), + (802, 'Hastened Fortitude Discipline', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6611, 1), + (803, 'Hastened Furious Discipline', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6614, 1), + (804, 'Warlord\'s Bravery', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6617, 1), + (805, 'Hastened Speed Focus', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14148, 1), + (806, 'Hastened Zan Fi\'s Whistle', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14160, 1), + (807, 'Pressure Points', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14157, 1), + (808, 'Hastened Thunder', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14166, 1), + (809, 'Allegretto of Battle', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14181, 1), + (810, 'Vivace of Conflict', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14186, 1), + (811, 'Unknown AA 16218', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 16218, 1), + (812, 'Unknown AA 16221', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 16221, 1), + (813, 'Unknown AA 16222', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 16222, 1), + (814, 'Unknown AA 16225', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 16225, 1), + (815, 'Unknown AA 16230', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 16230, 1), + (816, 'Unknown AA 16235', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 16235, 1), + (817, 'Unknown AA 16238', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 16238, 1), + (818, 'Unknown AA 16257', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 16257, 1), + (819, 'Unknown AA 16666', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16666, 1), + (820, 'Death\'s Revenge', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6630, 1), + (821, 'Harmshield', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 6635, 1), + (822, 'Explosion of Hatred', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6640, 1), + (823, 'Cascading Theft of Defense', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6641, 1), + (824, 'Hate Step', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6644, 1), + (825, 'Vicious Bite of Chaos', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6645, 1), + (826, 'Encroaching Darkness', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 6646, 1), + (827, 'Unknown AA 16745', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16745, 1), + (828, 'Unknown AA 16260', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 16260, 1), + (829, 'Unknown AA 16263', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 16263, 1), + (830, 'Unknown AA 16272', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 16272, 1), + (831, 'Unknown AA 16276', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 16276, 1), + (832, 'Unknown AA 16287', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 16287, 1), + (833, 'Unknown AA 17252', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17252, 1), + (834, 'Unknown AA 16296', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 16296, 1), + (835, 'Unknown AA 16300', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 16300, 1), + (836, 'Unknown AA 16310', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 16310, 1), + (837, 'Unknown AA 16330', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 16330, 1), + (838, 'Unknown AA 16163', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16163, 1), + (839, 'Unknown AA 16360', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 16360, 1), + (840, 'Unknown AA 16363', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16363, 1), + (841, 'Sleight of Hand', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6663, 1), + (842, 'Enduring Vision', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6666, 1), + (843, 'Expertise of Blades', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6668, 1), + (844, 'Cunning Disguise: Human', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6671, 1), + (845, 'Cunning Disguise: Half-Elf', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6672, 1), + (846, 'Cunning Disguise: Barbarian', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6673, 1), + (847, 'Cunning Disguise: Erudite', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6674, 1), + (848, 'Cunning Disguise: Troll', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6675, 1), + (849, 'Cunning Disguise: Goblin', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6676, 1), + (850, 'Unknown AA 16366', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16366, 1), + (851, 'Unknown AA 16369', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16369, 1), + (852, 'Unknown AA 16370', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 16370, 1), + (853, 'Unknown AA 16371', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 16371, 1), + (854, 'Unknown AA 17256', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17256, 1), + (856, 'Tigir\'s Insect Swarm', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6691, 1), + (857, 'Dampen Resistance', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6692, 1), + (858, 'Hastened Dampen Resistance', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6697, 1), + (859, 'Spirit Walk', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6702, 1), + (860, 'Hastened Virulent Paralysis', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6703, 1), + (861, 'Languid Bite', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6706, 1), + (862, 'Quickened Blood of Nadox', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6709, 1), + (863, 'Hastened Spirit Call', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6712, 1), + (864, 'Hastened Thousand Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14169, 1), + (865, 'Unknown AA 17257', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17257, 1), + (866, 'Extended Dance of Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14179, 1), + (867, 'Extended Thousand Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14180, 1), + (868, 'Unknown AA 16380', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 16380, 1), + (869, 'Unknown AA 16386', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 16386, 1), + (870, 'Harmonious Arrow', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6750, 1), + (871, 'Hastened Weapon Shield', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6751, 1), + (872, 'Outrider\'s Attack', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6754, 1), + (873, 'Group Guardian of the Forest', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6755, 1), + (874, 'Pack Hunt', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6758, 1), + (875, 'Keen Blade', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6761, 1), + (876, 'Outrider\'s Evasion', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6764, 1), + (877, 'Ranged Finesse', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6765, 1), + (878, 'Bow Mastery', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1196, 1), + (879, 'Unknown AA 17258', -1, 1040, 65535, 127, 131071, 0, 2, 0, 0, 17258, 1), + (880, 'Unknown AA 16392', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 16392, 1), + (881, 'Unknown AA 16395', -1, 10248, 65535, 127, 131071, 0, 3, 0, 0, 16395, 1), + (882, 'Unknown AA 16396', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 16396, 1), + (883, 'Unknown AA 16536', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 16536, 1), + (884, 'Unknown AA 17209', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 17209, 1), + (885, 'Unknown AA 17212', -1, 1, 65535, 127, 131071, 0, 2, 0, 0, 17212, 1), + (886, 'Unknown AA 17218', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 17218, 1), + (888, 'Unknown AA 17555', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17555, 1), + (889, 'Unknown AA 17229', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17229, 1), + (890, 'Unknown AA 17235', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17235, 1), + (891, 'Healing Light', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6791, 1), + (892, 'Halt the Dead', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6794, 1), + (894, 'Unknown AA 17242', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17242, 1), + (895, 'Unknown AA 17245', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17245, 1), + (896, 'Unknown AA 17249', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17249, 1), + (897, 'Unknown AA 17199', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 17199, 1), + (898, 'Unknown AA 17267', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17267, 1), + (899, 'Unknown AA 17273', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 17273, 1), + (900, 'Rise of Bones', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6815, 1), + (901, 'Whisperwind', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6818, 1), + (902, 'Hastened Blood Magic', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6819, 1), + (903, 'Overpower Undead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6822, 1), + (904, 'Hastened Swarm of Decay', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6823, 1), + (905, 'Gift of the Grave', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6828, 1), + (906, 'Hastened Gut Punch', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10522, 1), + (907, 'Hastened First Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10527, 1), + (908, 'Hastened Second Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10532, 1), + (909, 'Hastened Third Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10537, 1), + (910, 'Unknown AA 17280', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 17280, 1), + (911, 'Warlord\'s Resurgence', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10545, 1), + (912, 'Warlord\'s Fury', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10546, 1), + (914, 'Improved Shield Specialist', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10548, 1), + (915, 'Unknown AA 17281', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 17281, 1), + (917, 'Hastened Grappling Strike', -1, 65, 65535, 127, 131071, 0, 3, 0, 0, 10588, 1), + (918, 'Furious Refrain', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10627, 1), + (919, 'Unknown AA 17554', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17554, 1), + (920, 'Valorous Rage', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10711, 1), + (921, 'Hastened Group Guardian of the Forest', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10714, 1), + (922, 'Hastened Outrider\'s Attack', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10719, 1), + (923, 'Hastened Protection of the Spirit Wolf', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10722, 1), + (924, 'Hastened Imbued Ferocity', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10727, 1), + (925, 'Hastened Harmonious Arrow', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10730, 1), + (926, 'Hastened Entrap', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10733, 1), + (927, 'Poison Arrows', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10736, 1), + (928, 'Merciless Blade', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14026, 1), + (929, 'Combatant\'s Pact', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14029, 1), + (930, 'Warlord\'s Resolve', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14032, 1), + (931, 'Hastened Hate\'s Attraction', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 12582, 1), + (932, 'Unknown AA 17289', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 17289, 1), + (933, 'Improved Death Peace', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 12635, 1), + (934, 'Unknown AA 17307', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 17307, 1), + (935, 'Blessing of Ro', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10789, 1), + (936, 'Extended Wild Growth', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 10792, 1), + (937, 'Unknown AA 17317', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17317, 1), + (938, 'Eyes Wide Open', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 12636, 1), + (939, 'Communion of the Cheetah', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12638, 1), + (940, 'Hastened Song of Stone', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6870, 1), + (941, 'Flurry', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6873, 1), + (942, 'Destructive Cascade', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6876, 1), + (943, 'Total Domination', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6879, 1), + (944, 'Enhanced Forgetfulness', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6882, 1), + (945, 'Infusion of Thunder', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10346, 1), + (946, 'Hastened Warlord\'s Bravery', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14037, 1), + (947, 'Hastened Warlord\'s Tenacity', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14040, 1), + (948, 'Unknown AA 17328', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17328, 1), + (949, 'Unknown AA 17329', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17329, 1), + (950, 'Unknown AA 17336', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17336, 1), + (951, 'Unknown AA 17339', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 17339, 1), + (952, 'Unknown AA 17342', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17342, 1), + (953, 'Unknown AA 17344', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17344, 1), + (954, 'Unknown AA 17347', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17347, 1), + (955, 'Unknown AA 17357', -1, 514, 65535, 127, 131071, 0, 2, 0, 0, 17357, 1), + (956, 'Unknown AA 17361', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 17361, 1), + (957, 'Unknown AA 17364', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17364, 1), + (958, 'Unknown AA 17370', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17370, 1), + (959, 'Unknown AA 17372', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17372, 1), + (960, 'Stomping Leap', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 6930, 1), + (961, 'Juggernaut Surge', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6931, 1), + (962, 'Distraction Attack', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6932, 1), + (963, 'Hastened Savage Spirit', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6935, 1), + (964, 'Dying Blow', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6938, 1), + (965, 'Hastened Projection of Fury', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10519, 1), + (966, 'Unknown AA 17373', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 17373, 1), + (967, 'Blade Guardian', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13444, 1), + (968, 'Unknown AA 17375', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 17375, 1), + (969, 'Unknown AA 17378', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 17378, 1), + (970, 'Unknown AA 17378', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 17379, 1), + (971, 'Unknown AA 17378', -1, 16384, 65535, 127, 131071, 0, 2, 0, 0, 17380, 1), + (972, 'Unknown AA 17384', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 17384, 1), + (974, 'Unknown AA 17409', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 17409, 1), + (975, 'Unknown AA 17414', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 17414, 1), + (976, 'Unknown AA 17418', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17418, 1), + (977, 'Unknown AA 17558', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17558, 1), + (978, 'Unknown AA 17428', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17428, 1), + (979, 'Unknown AA 17436', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17436, 1), + (980, 'Natural Invisibility', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6970, 1), + (981, 'Attack of the Warders', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6971, 1), + (982, 'Hastened Feral Attacks', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6974, 1), + (983, 'Hastened Focused Paragon', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6977, 1), + (984, 'Hastened Paragon', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6980, 1), + (985, 'Group Bestial Alignment', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6983, 1), + (986, 'Bite of the Asp', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6984, 1), + (987, 'Raven\'s Claw', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6985, 1), + (988, 'Gorilla Smash', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6986, 1), + (989, 'Stonefoot', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10340, 1), + (990, 'Hastened Stunning Kick', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10343, 1), + (991, 'Quickened Turn Undead', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10470, 1), + (992, 'Tranquil Blessings', -1, 30254, 65535, 127, 131071, 0, 3, 0, 0, 3676, 1), + (993, 'Righteous Zeal', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6082, 1), + (994, 'Hastened Divine Retribution', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6088, 1), + (995, 'Intrinsic Efficiency', -1, 15386, 65535, 127, 131071, 0, 2, 0, 0, 6112, 1), + (996, 'Powerful Elixirs', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6113, 1), + (997, 'Celestial Rapidity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6534, 1), + (998, 'Hastened Celestial Regeneration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 2400, 1), + (999, 'Improved Burst of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7765, 1), + (1000, 'Unknown AA 17439', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17439, 1), + (1001, 'Unknown AA 17445', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17445, 1), + (1002, 'Unknown AA 17448', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17448, 1), + (1003, 'Unknown AA 10478', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10478, 1), + (1004, 'Unknown AA 17492', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 17492, 1), + (1005, 'Unknown AA 17495', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 17495, 1), + (1006, 'Unknown AA 17515', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 17515, 1), + (1007, 'Unknown AA 17517', -1, 5120, 65535, 127, 131071, 0, 3, 0, 0, 17517, 1), + (1008, 'Unknown AA 17522', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 17522, 1), + (1009, 'Unknown AA 17533', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 17533, 1), + (1011, 'Neshika\'s Blink', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7869, 1), + (1012, 'Five Point Palm', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7875, 1), + (1013, 'War Cry of the Braxi', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13872, 1), + (1014, 'Unknown AA 17538', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 17538, 1), + (1015, 'Unknown AA 17547', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 17547, 1), + (1016, 'Unknown AA 17549', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 17549, 1), + (1017, 'Unknown AA 17238', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17238, 1), + (1018, 'Unknown AA 17553', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 17553, 1), + (1019, 'Unknown AA 17248', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17248, 1), + (1020, 'Hastened Companion\'s Blessing', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 12478, 1), + (1021, 'Unknown AA 17215', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 17215, 1), + (1022, 'Destructive Fury', -1, 16540, 65535, 127, 131071, 0, 2, 0, 0, 6636, 1), + (1023, 'Restoration of Life', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14010, 1), + (1024, 'Hastened Leap of Faith', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14085, 1), + (1025, 'Hastened Beacon of the Righteous', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14011, 1), + (1026, 'Unknown AA 17561', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17561, 1), + (1027, 'Unknown AA 17564', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17564, 1), + (1028, 'Unknown AA 17567', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17567, 1), + (1029, 'Unknown AA 17570', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17570, 1), + (1030, 'Unknown AA 17573', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17573, 1), + (1031, 'Unknown AA 17576', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17576, 1), + (1032, 'Unknown AA 17579', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17579, 1), + (1033, 'Unknown AA 17582', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17582, 1), + (1034, 'Unknown AA 17585', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17585, 1), + (1035, 'Unknown AA 17588', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17588, 1), + (1036, 'Unknown AA 17591', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17591, 1), + (1037, 'Unknown AA 17594', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17594, 1), + (1038, 'Unknown AA 17597', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17597, 1), + (1039, 'Unknown AA 17600', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17600, 1), + (1040, 'Theft of Essence', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 7900, 1), + (1041, 'Malosinete', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 7903, 1), + (1042, 'Unknown AA 17603', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17603, 1), + (1043, 'Unknown AA 17606', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17606, 1), + (1044, 'Unknown AA 17609', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17609, 1), + (1045, 'Unknown AA 17612', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17612, 1), + (1046, 'Unknown AA 17615', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17615, 1), + (1047, 'Unknown AA 17618', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17618, 1), + (1048, 'Unknown AA 17621', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17621, 1), + (1049, 'Unknown AA 17624', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17624, 1), + (1050, 'Unknown AA 17627', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17627, 1), + (1051, 'Unknown AA 17630', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17630, 1), + (1052, 'Unknown AA 17633', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17633, 1), + (1053, 'Unknown AA 10481', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 10481, 1), + (1054, 'Unknown AA 17639', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 17639, 1), + (1060, 'Hastened Turn Undead', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7940, 1), + (1061, 'Cascading Divine Aura', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7943, 1), + (1062, 'Group Purify Soul', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7944, 1), + (1063, 'Hastened Renewal', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7945, 1), + (1064, 'Sanctified Blessing', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7948, 1), + (1065, 'Focused Celestial Regeneration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7951, 1), + (1090, 'Mastery of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7980, 1), + (1091, 'Hastened Nature\'s Guardian', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7983, 1), + (1092, 'Spirit of the Black Wolf', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7986, 1), + (1093, 'Hastened Lycan Soul', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7989, 1), + (1113, 'Hastened Mass Group Buff', -1, 30254, 65535, 127, 131071, 0, 3, 0, 0, 5010, 1), + (1115, 'Mystical Shield', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 5045, 1), + (1120, 'Self Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8030, 1), + (1121, 'Hastened Veil of Mindshadow', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8031, 1), + (1122, 'Phantasmal Opponent', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8034, 1), + (1123, 'Hastened Edict of Command', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8035, 1), + (1124, 'Fog of Memories', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8038, 1), + (1125, 'Bite of Tashani', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8039, 1), + (1150, 'Fury of Druzzil', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8060, 1), + (1151, 'Fury of Eci', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8063, 1), + (1152, 'Fury of Ro', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8066, 1), + (1153, 'Fortified Entanglement', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8069, 1), + (1154, 'Force of Will', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8072, 1), + (1155, 'Atol\'s Shackles', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8075, 1), + (1156, 'Hastened Manaburn', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8076, 1), + (1157, 'Hastened Call of Xuzl', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8082, 1), + (1158, 'Divine Steed', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 1667, 1), + (1159, 'Hastened Leap', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 11014, 1), + (1169, 'Unknown AA 16336', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16336, 1), + (1170, 'Unknown AA 16339', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16339, 1), + (1171, 'Hastened Counterattack Discipline', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15502, 1), + (1173, 'Hastened Onslaught', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15509, 1), + (1174, 'Mrylokar\'s Rigor', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15512, 1), + (1175, 'Absorbing Agent', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15515, 1), + (1176, 'Improved Requiem of Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15516, 1), + (1177, 'Quickened Requiem of Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15517, 1), + (1178, 'Silent Displacement', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15521, 1), + (1200, 'Companion\'s Alacrity', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 8190, 1), + (1201, 'Improved Intimidation', -1, 41408, 65535, 127, 131071, 0, 2, 0, 1, 8193, 1), + (1202, 'Perfected Levitation', -1, 31272, 65535, 127, 131071, 0, 2, 0, 0, 8194, 1), + (1203, 'Hastened Fortify Companion', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 8195, 1), + (1204, 'Empowered Ingenuity', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 8198, 1), + (1205, 'Companion\'s Fury', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 8201, 1), + (1206, 'Quickened Radiant Cure', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 8204, 1), + (1207, 'Quickened Radiant Cure', -1, 4, 65535, 127, 131071, 0, 2, 0, 0, 8207, 1), + (1208, 'Mental Stamina', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 8210, 1), + (1209, 'Hardy Endurance', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 8215, 1), + (1210, 'Group Perfected Invisibility', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 8220, 1), + (1211, 'Focus of Arcanum', -1, 15904, 65535, 127, 131071, 0, 3, 0, 0, 8221, 1), + (1212, 'Group Perfected Invisibility to Undead', -1, 1046, 65535, 127, 131071, 0, 2, 0, 0, 8222, 1), + (1214, 'Cascade of Life', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 8224, 1), + (1215, 'Summon Companion', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 8227, 1), + (1216, 'Mental Fortitude', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8228, 1), + (1217, 'Gate', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 8231, 1), + (1218, 'Extended Ingenuity', -1, 128, 65535, 127, 131071, 0, 2, 0, 0, 8040, 1), + (1219, 'Armor of Wisdom', -1, 1, 65535, 127, 131071, 0, 2, 0, 0, 8235, 1), + (1220, 'Armor of Wisdom', -1, 20, 65535, 127, 131071, 0, 2, 0, 0, 8240, 1), + (1221, 'Armor of Wisdom', -1, 202, 65535, 127, 131071, 0, 2, 0, 0, 8245, 1), + (1222, 'Armor of Wisdom', -1, 49920, 65535, 127, 131071, 0, 2, 0, 0, 8250, 1), + (1223, 'Armor of Wisdom', -1, 15392, 65535, 127, 131071, 0, 2, 0, 0, 8255, 1), + (1232, 'Way of the Katori', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15429, 1), + (1233, 'Harmony of Battle', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15432, 1), + (1234, 'Hastened Ironfist', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15438, 1), + (1235, 'Two-Finger Wasp Touch', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15447, 1), + (1236, 'Thunderfoot', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15444, 1), + (1237, 'Extended Bloodlust', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15414, 1), + (1239, 'Consumption of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15423, 1), + (1240, 'Frenzied Swipes', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15424, 1), + (1242, 'Hastened Synergy', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15450, 1), + (1243, 'Hastened Crane Stance', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15453, 1), + (1244, 'Hastened Eye Gouge', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15456, 1), + (1245, 'Troubadour\'s Slashing Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15540, 1), + (1246, 'Troubadour\'s Blunt Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15543, 1), + (1247, 'Troubadour\'s Piercing Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15546, 1), + (1248, 'Hastened Lure of the Siren\'s Song', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15549, 1), + (1249, 'Frenzied Axe of Rallos', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15555, 1), + (1250, 'Juggernaut\'s Mastery of Throwing', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15564, 1), + (1251, 'Furious Rampage', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15567, 1), + (1252, 'Battle Stomp', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15569, 1), + (1253, 'Communion of Blood', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15570, 1), + (1254, 'Hastened Dying Grasp', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15571, 1), + (1255, 'Rest the Dead', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 15574, 1), + (1256, 'Extended Encroaching Darkness', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 15579, 1), + (1257, 'Hand of Death', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15582, 1), + (1258, 'Quickened Levant', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15591, 1), + (1259, 'Cascade of Decay', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15594, 1), + (1261, 'Hastened Fury of the Gods', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15598, 1), + (1262, 'Lower Element', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15601, 1), + (1263, 'Destructive Adept', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15602, 1), + (1264, 'Arcane Fusion', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15609, 1), + (1265, 'Arcane Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15611, 1), + (1266, 'Force of Flame', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15612, 1), + (1267, 'Force of Ice', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15615, 1), + (1269, 'Sha\'s Reprisal', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15425, 1), + (1270, 'Crippling Spirit', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 15377, 1), + (1271, 'Quick Damage', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15622, 1), + (1272, 'Assassin\'s Wrath', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15625, 1), + (1273, 'Hastened Swiftblade', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15634, 1), + (1274, 'Improved Explosion of Spite', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15639, 1), + (1275, 'Improved Explosion of Hatred', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15640, 1), + (1277, 'Soul Touch', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15642, 1), + (1278, 'Soul Flay', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15643, 1), + (1279, 'Ragged Bite of Agony', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15646, 1), + (1281, 'Everburn', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15648, 1), + (1282, 'Marr\'s Gift', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15619, 1), + (1300, 'Fundament of Intellect', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 9100, 1), + (1301, 'Fundament of Intellect', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9109, 1), + (1302, 'Fundament of Intellect', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 9118, 1), + (1303, 'Fundament of Intellect', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 9127, 1), + (1304, 'Fundament of Wisdom', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 9136, 1), + (1305, 'Fundament of Wisdom', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 9145, 1), + (1306, 'Fundament of Wisdom', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 9154, 1), + (1307, 'Fundament of Power', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 9163, 1), + (1308, 'Fundament of Power', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9172, 1), + (1309, 'Fundament of Power', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 9181, 1), + (1310, 'Fundament of Power', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 9190, 1), + (1311, 'Fundament of Power', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 9199, 1), + (1312, 'Fundament of Combat', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 9208, 1), + (1313, 'Fundament of Combat', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9217, 1), + (1314, 'Fundament of Combat', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 9226, 1), + (1315, 'Fundament of Combat', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 9235, 1), + (1350, 'Fundament: First Spire of Arcanum', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 9300, 1), + (1351, 'Fundament: Second Spire of Arcanum', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 9303, 1), + (1352, 'Fundament: Third Spire of Arcanum', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 9306, 1), + (1360, 'Fundament: First Spire of the Sensei', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9309, 1), + (1361, 'Fundament: Second Spire of the Sensei', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9312, 1), + (1362, 'Fundament: Third Spire of the Sensei', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9315, 1), + (1370, 'Fundament: First Spire of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 9318, 1), + (1371, 'Fundament: Second Spire of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 9321, 1), + (1372, 'Fundament: Third Spire of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 9324, 1), + (1380, 'Fundament: First Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 9327, 1), + (1381, 'Fundament: Second Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 9330, 1), + (1382, 'Fundament: Third Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 9333, 1), + (1390, 'Fundament: First Spire of Necromancy', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9336, 1), + (1391, 'Fundament: Second Spire of Necromancy', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9339, 1), + (1392, 'Fundament: Third Spire of Necromancy', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9342, 1), + (1400, 'Fundament: First Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 9345, 1), + (1401, 'Fundament: Second Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 9348, 1), + (1402, 'Fundament: Third Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 9351, 1), + (1403, 'Sturdy Companion', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 9503, 1), + (1404, 'Extended Swarm', -1, 32306, 65535, 127, 131071, 0, 3, 0, 0, 9506, 1), + (1405, 'Twincast', -1, 15906, 65535, 127, 131071, 0, 3, 0, 0, 9509, 1), + (1406, 'Staff Block', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9512, 1), + (1410, 'Fundament: First Spire of the Rake', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 9354, 1), + (1411, 'Fundament: Second Spire of the Rake', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 9357, 1), + (1412, 'Fundament: Third Spire of the Rake', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 9360, 1), + (1420, 'Fundament: First Spire of the Minstrels', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 9363, 1), + (1421, 'Fundament: Second Spire of the Minstrels', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 9366, 1), + (1422, 'Fundament: Third Spire of the Minstrels', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 9369, 1), + (1430, 'Fundament: First Spire of the Savage Lord', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 9372, 1), + (1431, 'Fundament: Second Spire of the Savage Lord', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 9375, 1), + (1432, 'Fundament: Third Spire of the Savage Lord', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 9378, 1), + (1433, 'Extended Ingenuity', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 8232, 1), + (1440, 'Fundament: First Spire of Holiness', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 9381, 1), + (1441, 'Fundament: Second Spire of Holiness', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 9384, 1), + (1442, 'Fundament: Third Spire of Holiness', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 9387, 1), + (1450, 'Fundament: First Spire of the Reavers', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9390, 1), + (1451, 'Fundament: Second Spire of the Reavers', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9393, 1), + (1452, 'Fundament: Third Spire of the Reavers', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9396, 1), + (1460, 'Fundament: First Spire of the Pathfinders', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 9399, 1), + (1461, 'Fundament: Second Spire of the Pathfinders', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 9402, 1), + (1462, 'Fundament: Third Spire of the Pathfinders', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 9405, 1), + (1470, 'Fundament: First Spire of Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 9408, 1), + (1471, 'Fundament: Second Spire of Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 9411, 1), + (1472, 'Fundament: Third Spire of Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 9414, 1), + (1480, 'Fundament: First Spire of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 9417, 1), + (1481, 'Fundament: Second Spire of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 9420, 1), + (1482, 'Fundament: Third Spire of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 9423, 1), + (1490, 'Fundament: First Spire of Ancestors', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 9426, 1), + (1491, 'Fundament: Second Spire of Ancestors', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 9429, 1), + (1492, 'Fundament: Third Spire of Ancestors', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 9432, 1), + (1500, 'Fundament: First Spire of Savagery', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 9435, 1), + (1501, 'Fundament: Second Spire of Savagery', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 9438, 1), + (1502, 'Fundament: Third Spire of Savagery', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 9441, 1), + (1503, 'Hallowed Steed', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13673, 1), + (1504, 'Wicked Steed', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13674, 1), + (1505, 'Unknown AA 16103', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16103, 1), + (1580, 'Divine Companion Aura', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 5809, 1), + (1662, 'Spell Casting Mastery', -1, 16412, 65535, 127, 131071, 0, 2, 0, 0, 1216, 1), + (1663, 'Gift of Mana', -1, 16412, 65535, 127, 131071, 0, 2, 0, 0, 1219, 1), + (1664, 'Twinproc', -1, 50175, 65535, 127, 131071, 0, 3, 0, 0, 12416, 1), + (1665, 'Tactical Mastery', -1, 16596, 65535, 127, 131071, 0, 3, 0, 0, 12419, 1), + (1666, 'Group Perfected Levitation', -1, 31272, 65535, 127, 131071, 0, 2, 0, 0, 12422, 1), + (1667, 'Quickened Encroaching Darkness', -1, 1040, 65535, 127, 131071, 0, 2, 0, 0, 6026, 1), + (1668, 'Acute Focus of Arcanum', -1, 15904, 65535, 127, 131071, 0, 3, 0, 0, 8260, 1), + (1669, 'Flurry', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 5806, 1), + (1680, 'Hastened Flash of Anger', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13905, 1), + (1681, 'Hastened Bazu Roar', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13908, 1), + (1682, 'Hastened Scowl', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13911, 1), + (1683, 'Hastened Mark of the Mage Hunter', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13917, 1), + (1684, 'Knowledge of Alaran Culture', 2, 65535, 65535, 127, 131071, 0, 4, 0, 0, 14017, 1), + (1685, 'Knowledge of Alaran Culture - Advanced', 2, 65535, 65535, 127, 131071, 0, 4, 0, 0, 14018, 1), + (1686, 'Brace For Impact', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14019, 1), + (1687, 'Summon Tome of the Hero\'s Journey', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 14371, 1), + (1800, 'Enchant Planar Alloy', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 14373, 1), + (1801, 'Mass Enchant Planar Alloy', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 14374, 1), + (2000, 'Armor of Experience', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 4700, 1), + (2001, 'Sneering Grin', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15096, 1), + (2002, 'Warlord\'s Grasp', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15099, 1), + (2003, 'Hastened Press the Attack', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15100, 1), + (2004, 'Hastened Rage of Rallos Zek', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15105, 1), + (2005, 'Hastened Unbroken Attention', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15108, 1), + (2006, 'Extended Resplendant Glory', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15113, 1), + (2007, 'Wars Sheol\'s Heroic Blade', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15119, 1), + (2008, 'Hastened Vehement Rage', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15120, 1), + (2009, 'Hastened Barbed Tongue', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15123, 1), + (2010, 'Hastened Shield Topple', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15126, 1), + (2011, 'Imperator\'s Command', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15129, 1), + (2012, 'Imperator\'s Charge', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15130, 1), + (2013, 'Imperator\'s Precision', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15131, 1), + (2014, 'Hastened Divine Call', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15132, 1), + (2015, 'Extended Divine Call', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15135, 1), + (2016, 'Heroic Leap', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15136, 1), + (2018, 'Helix of the Undying', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 15146, 1), + (2019, 'Group Armor of the Inquisitor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15147, 1), + (2020, 'Quickened Demand For Honor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15150, 1), + (2021, 'Extended Sanctification', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15153, 1), + (2022, 'Extended Speed of the Savior', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15154, 1), + (2023, 'Extended Preservation of Marr', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15155, 1), + (2024, 'Extended Shield of Brilliance', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15158, 1), + (2025, 'Extended Blessing of the Faithful', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15159, 1), + (2026, 'Hastened Speed of the Savior', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15162, 1), + (2028, 'Hastened Shield of Brilliance', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15168, 1), + (2031, 'Purity of Death', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15177, 1), + (2032, 'Quickened Scourge Skin', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15179, 1), + (2034, 'Gift of the Quick Spear', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15193, 1), + (2035, 'Extended Provocation for Power', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15194, 1), + (2036, 'Quickened Auspice of the Hunter', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15253, 1), + (2037, 'Chameleon\'s Gift', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15304, 1), + (2040, 'Hastened Enraging Kicks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15283, 1), + (2041, 'Close Combat Mastery', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15288, 1), + (2042, 'Quickened Cover Tracks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15295, 1), + (2045, 'Shield of Reverence', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15338, 1), + (2046, 'Extended Healing Frenzy', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15342, 1), + (2047, 'Call of the Herald', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15343, 1), + (2048, 'Covenant of Spirit', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 15356, 1), + (2049, 'Talisman of Celerity', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 15357, 1), + (2050, 'Extended Spiritual Blessing', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 15358, 1), + (2051, 'Rejuvenation of Spirit', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 15362, 1), + (2053, 'Hastened Turgur\'s Swarm', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 15371, 1), + (2054, 'Shielding of Spirits', -1, 16930, 65535, 127, 131071, 0, 2, 0, 0, 15374, 1), + (2055, 'Hastened Lunar Healing', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 15383, 1), + (2056, 'Quickened Blessing of Ro', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 15389, 1), + (2057, 'Hastened Wall of Wind', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 15403, 1), + (2059, 'Quickened Focused Paragon of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15406, 1), + (2060, 'Elemental Ward', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15200, 1), + (2061, 'Cloak of Shadows', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15203, 1), + (2062, 'Hastened Elemental Union', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15204, 1), + (2063, 'Hastened Virulent Talon', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15207, 1), + (2064, 'Wind of Malosinete', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 15210, 1), + (2065, 'Mana Reserve', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15213, 1), + (2066, 'Second Wind Ward', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15214, 1), + (2076, 'Steel Vengeance', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15217, 1), + (2077, 'Extended Vapor Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15220, 1), + (2078, 'Extended Stone Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15223, 1), + (2079, 'Extended Fire Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15226, 1), + (2080, 'Extended Ice Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15229, 1), + (2081, 'Flames of Power', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15232, 1), + (2200, 'Rune of Banishment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15475, 1), + (2201, 'Hastened Glyph Spray', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15478, 1), + (2202, 'Illusions of Grandeur', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15481, 1), + (2203, 'Illusory Ally', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15482, 1), + (2204, 'Gracious Gift of Mana', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15485, 1), + (2205, 'Chromatic Haze', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15486, 1), + (2206, 'Blanket of Forgetfulness', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15489, 1), + (2207, 'Ethereal Manipulation', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15490, 1), + (2208, 'Quick Mezz', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15493, 1), + (2209, 'Reactive Rune', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15496, 1), + (2234, 'Cover Tracks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10368, 1), + (2235, 'Imbued Ferocity', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10387, 1), + (2709, 'Perfected Dead Man Floating', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13692, 1), + (2899, 'Levant', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 10700, 1), + (3000, 'Auroria Mastery', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 6987, 1), + (3202, 'Pet Discipline', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 7733, 1), + (3203, 'Enchant Palladium Trio', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7736, 1), + (3204, 'Mass Enchant Palladium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7737, 1), + (3205, 'Greater Mass Enchant Palladium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7738, 1), + (3206, 'Enchant Dwerium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7732, 1), + (3207, 'Mass Enchant Dwerium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7734, 1), + (3208, 'Enchant Palladium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7735, 1), + (3209, 'Enchant Temporite', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7739, 1), + (3210, 'Mass Enchant Temporite', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7740, 1), + (3211, 'Nature\'s Reprieve', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10388, 1), + (3212, 'Hastened Divine Intervention', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10358, 1), + (3213, 'Projection of Fury', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10351, 1), + (3214, 'Improved Atone', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10364, 1), + (3215, 'Projection of Doom', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10352, 1), + (3216, 'Projection of Piety', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10353, 1), + (3217, 'Hastened Jolting Kicks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 12500, 1), + (3218, 'Enchant Cosgrite', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7741, 1), + (3219, 'Mass Enchant Cosgrite', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7742, 1), + (3500, 'Blessing of Light', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10355, 1), + (3506, 'Fierce Eye', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 5717, 1), + (3511, 'Punch Mastery', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 6020, 1), + (3512, 'Companion\'s Durability', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 6051, 1), + (3513, 'Rake\'s Deadly Aim', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6322, 1), + (3514, 'Rogue\'s Fury', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6325, 1), + (3515, 'Envenomed Blades', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6328, 1), + (3516, 'Companion of Necessity', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 6333, 1), + (3517, 'Rake\'s Powerful Aim', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6334, 1), + (3518, 'Hastened Cacophony', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6337, 1), + (3519, 'Hastened Funeral Dirge', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6340, 1), + (3520, 'Master\'s Hastened Combination', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 6343, 1), + (3521, 'Hastened Silent Casting', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 6346, 1), + (3522, 'Hastened Silent Casting', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 6349, 1), + (3525, 'Precise Blow', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 5776, 1), + (3550, 'Beguiler\'s Banishment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 5849, 1), + (3551, 'Beguiler\'s Directed Banishment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 5870, 1), + (3600, 'Rapid Defiance', 1, 1, 65535, 127, 131071, 0, 3, 0, 1, 6136, 1), + (3646, 'Blast of Anger', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6135, 1), + (3676, 'Gift of Life', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10354, 1), + (3701, 'Dirge of the Sleepwalker', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6200, 1), + (3702, 'Quick Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6201, 1), + (3703, 'Steady Hands ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6202, 1), + (3704, 'Selo\'s Sonata', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6205, 1), + (3705, 'Companion\'s Blessing ', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 6206, 1), + (3706, 'Hastened Bestial Alignment ', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6209, 1), + (3707, 'Fortify Companion ', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 6212, 1), + (3708, 'Burst of Power ', -1, 20, 65535, 127, 131071, 0, 2, 0, 0, 6215, 1), + (3709, 'Pact of the Wurine', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6218, 1), + (3710, 'Reckless Abandon ', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6219, 1), + (3711, 'Gift of Resurrection', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6222, 1), + (3713, 'Hastened Call of the Wild ', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 6228, 1), + (3714, 'Protection of Direwood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 6232, 1), + (3716, 'Clinging Root ', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 6236, 1), + (3718, 'Critical Affliction', -1, 8194, 65535, 127, 131071, 0, 2, 0, 0, 6240, 1), + (3720, 'Mana Overburn ', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 6249, 1), + (3724, 'Knight\'s Return Strike ', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 6266, 1), + (3725, 'Hunter\'s Return Kick ', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6269, 1), + (3726, 'Hastened Ligament Slice ', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6272, 1), + (3727, 'Knave\'s Return Strike', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6275, 1), + (3728, 'Storm Strike', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 6278, 1), + (3729, 'Turgur\'s Swarm', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6281, 1), + (3730, 'Silent Presence', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6282, 1), + (3731, 'Infused by Rage ', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6283, 1), + (3732, 'Gut Punch', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6286, 1), + (3733, 'Warlord\'s Return Kick', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6287, 1), + (3734, 'Arcomancy ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 6290, 1), + (3800, 'Blessing of Resurrection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6299, 1), + (3801, 'General Sturdiness', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 6119, 1), + (3802, 'Shield Block', -1, 392, 65535, 127, 131071, 0, 2, 0, 0, 6124, 1), + (3803, 'Hastened Trueshot', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6355, 1), + (3804, 'Outrider\'s Accuracy', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6370, 1), + (3805, 'Hastened Mend', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 4801, 1), + (3812, 'Perfected Invisibility', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 7069, 1), + (3813, 'Spell Casting Reinforcement', -1, 7168, 65535, 127, 131071, 0, 2, 0, 0, 6257, 1), + (3815, 'Destructive Cascade', -1, 9776, 65535, 127, 131071, 0, 3, 0, 0, 6375, 1), + (3816, 'Companion\'s Relocation', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 6379, 1), + (3817, 'Focused Paragon of Spirits', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6380, 1), + (3818, 'Companion\'s Agility', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 6383, 1), + (3819, 'Maestro\'s Concentration', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6386, 1), + (3820, 'Blessing of Life', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6395, 1), + (3821, 'Quickened Harvest of Druzzil', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 6503, 1), + (3822, 'Chattering Bones', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6508, 1), + (3823, 'Warlord\'s Deadly Aim', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6511, 1), + (3824, 'Quickened Call of the Wild', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 6514, 1), + (3826, 'Force of Disruption', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 5984, 1), + (3830, 'Hastened Divine Avatar', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7100, 1), + (3831, 'Hastened Purification', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 7103, 1), + (3832, 'Beastlords Feral Kick', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 7106, 1), + (3833, 'Burst of Power ', -1, 32841, 65535, 127, 131071, 0, 2, 0, 0, 6409, 1), + (3834, 'Burst of Power ', -1, 256, 65535, 127, 131071, 0, 2, 0, 0, 6419, 1), + (3835, 'Shield Block', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 6428, 1), + (3836, 'Holy Root', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6436, 1), + (3837, 'Burst of Power ', -1, 16512, 65535, 127, 131071, 0, 2, 0, 0, 6060, 1), + (3838, 'Quickened Suspend Minion', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 6445, 1), + (3839, 'Quickened Summon Axes', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6452, 1), + (3840, 'Recourse of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6601, 1), + (3841, 'Call Hither', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 6455, 1), + (3842, 'Fortified Survival', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 6458, 1), + (3843, 'Fortified Intervention', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6461, 1), + (3865, 'Planar Durability', -1, 72, 65535, 127, 131071, 0, 3, 0, 0, 6422, 1), + (3890, 'Hastened Force of Will', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 7822, 1), + (3891, 'Hastened Burnout', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 7832, 1), + (3892, 'Hastened Rumbling Servant', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 7828, 1), + (3893, 'Extended Rumbling Servant', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 7827, 1), + (3899, 'Furious Leap', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 6499, 1), + (4001, 'Undaunted Fury', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 7407, 1), + (4002, 'Frenzied Volley', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 7818, 1), + (4200, 'Hastened Forceful Rejuvenation', -1, 32318, 65535, 127, 131071, 0, 2, 0, 0, 12475, 1), + (4666, 'Shield Specialist', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 4666, 1), + (5000, 'Glyph of Courage', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7000, 1), + (5002, 'Glyph of Stored Life', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7002, 1), + (5003, 'Glyph of Frantic Infusion', 7, 30224, 65535, 127, 131071, 0, 4, 1, 0, 7003, 1), + (5004, 'Glyph of Angry Thoughts', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7004, 1), + (5005, 'Foraging', 8, 65535, 65535, 127, 131071, 0, 1, 0, 0, 7062, 1), + (6000, 'Harm Touch', 9, 16, 65535, 127, 131071, 0, 3, 0, 0, 7800, 1), + (6001, 'Lay on Hands', 9, 4, 65535, 127, 131071, 0, 3, 0, 0, 7850, 1), + (6002, 'Hunter\'s Attack Power', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6546, 1), + (6106, 'Sustained Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 6106, 1), + (6302, 'Hastened Reckless Abandon', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6302, 1), + (6362, 'Hastened Recklessness', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6362, 1), + (6478, 'Hastened Blessing of Resurrection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6478, 1), + (6481, 'Hastened Divine Resurrection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6481, 1), + (6488, 'Flurry of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6488, 1), + (6489, 'Hastened Holyforge', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6489, 1), + (6492, 'Inquisitor\'s Judgement', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6492, 1), + (6988, 'Extended Group Bestial Alignment', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6988, 1), + (7000, 'Voice of Thule', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6639, 1), + (7001, 'Zan Fi\'s Whistle', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7872, 1), + (7002, 'Summon Remains', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9500, 1), + (7003, 'Forceful Rejuvenation', -1, 32318, 65535, 127, 131071, 0, 2, 0, 0, 9502, 1), + (7007, 'Summon Remains', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9501, 1), + (7009, 'Teleport Bind', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 1419, 1), + (7016, 'Glyph of the Master', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7016, 1), + (7017, 'Glyph of Lost Secrets', 7, 32318, 65535, 127, 131071, 0, 4, 1, 0, 7017, 1), + (7018, 'Glyph of Genari Might', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7018, 1), + (7019, 'Glyph of the Cataclysm', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7019, 1), + (7025, 'Group Shrink', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 7669, 1), + (7033, 'Lasting Bravery', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 7033, 1), + (7036, 'Hastened Blast of Anger', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 7036, 1), + (7050, 'Call of the Hero', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1017, 1), + (7060, 'Precision of Axes', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 4809, 1), + (7070, 'Hastened Distraction Attack', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6941, 1), + (7105, 'Deathly Pact', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 976, 1), + (7106, 'Planar Durability', -1, 16768, 65535, 127, 131071, 0, 3, 0, 0, 6467, 1), + (7107, 'Hastened Getaway', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 7005, 1), + (7108, 'Divine Aura', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 977, 1), + (7109, 'Hastened Wrath of the Wild', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7664, 1), + (7689, 'Burst of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7689, 1), + (7690, 'Spirit Mastery', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7690, 1), + (7695, 'Quickened Blood of Avoling', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 7695, 1), + (7698, 'Dead Man Floating', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 7698, 1), + (7699, 'Dread Incarnate', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 7699, 1), + (7700, 'Flurry', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 7700, 1), + (7703, 'Death Bloom', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 7703, 1), + (7712, 'Disruptive Persecution', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 7712, 1), + (7715, 'Hastened Whisperwind', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 7715, 1), + (7743, 'Hastened Guardian of the Forest', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7743, 1), + (7746, 'Hastened Flusterbolt', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7746, 1), + (7747, 'Volatile Arrow', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7747, 1), + (7748, 'Pathfinder\'s Grace', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7748, 1), + (7751, 'Hastened Cover Tracks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7751, 1), + (7754, 'Steed of Souls', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7754, 1), + (7755, 'Scourge Skin', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7755, 1), + (7756, 'Death\'s Effigy', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7756, 1), + (7757, 'Hastened Visage of Death', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7757, 1), + (7760, 'Hastened Hate Step', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7760, 1), + (7801, 'Songwriting', 6, 128, 65535, 127, 131071, 0, 3, 0, 0, 9001, 1), + (7809, 'Hybrid Research', 6, 16412, 65535, 127, 131071, 0, 2, 0, 0, 9011, 1), + (7819, 'Written Prayer', 6, 546, 65535, 127, 131071, 0, 2, 0, 0, 9021, 1), + (7925, 'Sionachie\'s Crescendo', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1018, 1), + (8081, 'Summon Resupply Agent', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 9000, 1), + (8130, 'Summon Clockwork Banker', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 9031, 1), + (8200, 'Hastened Dirge of the Sleepwalker', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10329, 1), + (8201, 'Vainglorious Shout ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10330, 1), + (8202, 'Lyre Leap ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10331, 1), + (8203, 'Domination Mastery ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10332, 1), + (8204, 'Lyrical Prankster', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10333, 1), + (8205, 'Selo\'s Kick ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10336, 1), + (8261, 'A Tune Stuck In Your Head', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10339, 1), + (8262, 'The Show Must Go On', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 7010, 1), + (8300, 'Spell Casting Subtlety', -1, 16384, 65535, 127, 131071, 0, 2, 0, 0, 10370, 1), + (8301, 'Improved Natural Invisibility', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 10373, 1), + (8302, 'Protection of the Warder', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 10374, 1), + (8303, 'Nature\'s Salve', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 10377, 1), + (8304, 'Focus of Animus', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 10380, 1), + (8314, 'Fluid March', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 8314, 1), + (8317, 'Hastened Selo\'s Kick', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 8317, 1), + (8319, 'Hastened Bellow', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 8319, 1), + (8322, 'Belltone Mind', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 8322, 1), + (8325, 'Subtle Blows', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 8325, 1), + (8331, 'Enhanced Thief\'s Eyes', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 8331, 1), + (8332, 'Extended Languid Bite', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 8332, 1), + (8335, 'Quickened Malosinete', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 8335, 1), + (8341, 'Drape of Shadows', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 8341, 1), + (8342, 'Host in the Shell', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 8342, 1), + (8347, 'Hastened Mana Draw', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8347, 1), + (8350, 'Hastened Mezmerization', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8350, 1), + (8400, 'Self Preservation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 10400, 1), + (8401, 'Hastened Frenzy', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 10401, 1), + (8402, 'Extended Havoc', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 10404, 1), + (8500, 'Healing Frenzy', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10450, 1), + (8501, 'Overpowering Strikes', -1, 6, 65535, 127, 131071, 0, 3, 0, 0, 10453, 1), + (8502, 'Quickened Blessing of Ressurection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10456, 1), + (8503, 'Hastened Atonement', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10459, 1), + (8504, 'Improved Sanctuary', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10462, 1), + (8505, 'Blessing of Sanctuary', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10463, 1), + (8506, 'Hastened Celestial Hammer', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10464, 1), + (8600, 'Spirit of Eagle', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 10500, 1), + (8601, 'Flight of Eagles', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10501, 1), + (8602, 'Egress', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10502, 1), + (8603, 'Spirits of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10503, 1), + (8604, 'Wall of Wind', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10506, 1), + (8605, 'Hastened Spirit of the Wood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10511, 1), + (8606, 'Hastened Convergence of Spirits', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10514, 1), + (8700, 'Beam of Slumber', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10550, 1), + (8701, 'Phantasmic Reflex', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10551, 1), + (8702, 'Friendly Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10557, 1), + (8703, 'Hastened Self Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10558, 1), + (8704, 'Forceful Banishment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10561, 1), + (8708, 'Hastened Cascading Rage', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6908, 1), + (8800, 'Force of Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 10600, 1), + (8801, 'Aspect of Zomm', -1, 6144, 65535, 127, 131071, 0, 3, 0, 0, 10603, 1), + (8802, 'Extended Shared Health', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 10610, 1), + (8900, 'Agile Feet', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10650, 1), + (8901, 'Hastened Defensive Poses', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10653, 1), + (8902, 'Extended Impenetrable Discipline', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10656, 1), + (8903, 'Hastened Destructive Force', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10657, 1), + (9001, 'Reluctant Benevolence', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 10701, 1), + (9100, 'Bestow Divine Aura', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10752, 1), + (9101, 'Blessing of Purification', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10753, 1), + (9102, 'Sense the Dead', -1, 1030, 65535, 127, 131071, 0, 3, 0, 0, 10754, 1), + (9200, 'Hastened Auspice of the Hunter', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10800, 1), + (9201, 'Clenched Jaw', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10803, 1), + (9202, 'Scout\'s Mastery of Fire', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10806, 1), + (9203, 'Scout\'s Mastery of Ice', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10809, 1), + (9205, 'Scout\'s Mastery of Slashing', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10815, 1), + (9206, 'Scout\'s Mastery of Piercing', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10818, 1), + (9207, 'Scout\'s Mastery of Blunt Weapons', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10821, 1), + (9300, 'Massive Strike', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 10850, 1), + (9301, 'Strikethrough', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 10853, 1), + (9400, 'Hate\'s Attraction', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10900, 1), + (9401, 'Feigned Minion', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10903, 1), + (9402, 'Hastened Summon Remains', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10909, 1), + (9403, 'Visage of Death', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10912, 1), + (9404, 'Cascading Theft of Life', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10915, 1), + (9500, 'Extended Sloth', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10950, 1), + (9501, 'Hastened Ancestral Aid', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10951, 1), + (9502, 'Hastened Union of Spirits', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10954, 1), + (9503, 'Group Shrink', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10957, 1), + (9504, 'Inconspicuous Totem', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10958, 1), + (9505, 'Extended Pestilence', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10959, 1), + (9600, 'Hastened Taunt', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 11000, 1), + (9601, 'Extended Shield Reflect', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 11003, 1), + (9602, 'Extended Commanding Voice', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 11004, 1), + (9700, 'Hastened Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11050, 1), + (9701, 'Netherstep', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11055, 1), + (9702, 'Beam of Displacement', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11056, 1), + (9703, 'Translocate', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11057, 1), + (9704, 'Teleport', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11058, 1), + (10367, 'Ageless Enmity', -1, 1, 65535, 127, 131071, 0, 2, 0, 0, 10367, 1), + (10389, 'Extended Trickery', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 10389, 1), + (10392, 'Ageless Enmity', -1, 20, 65535, 127, 131071, 0, 2, 0, 0, 10392, 1), + (10393, 'Shackles of Tunare', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10393, 1), + (10394, 'Beacon of the Righteous', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10394, 1), + (10395, 'Bobbing Corpse', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10395, 1), + (10396, 'Group Spirit of the White Wolf', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10396, 1), + (10397, 'Group Spirit of the Black Wolf', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10397, 1), + (10405, 'Hastened Deflection Discipline', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 10405, 1), + (10410, 'Rogue Triple Attack Skillup Test', -1, 256, 65535, 127, 131071, 0, 3, 0, 1, 10410, 1), + (10413, 'Hastened Host of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 10413, 1), + (10424, 'Hand of Ro', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10424, 1), + (10425, 'Fixation of Ro', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10425, 1), + (10426, 'Peaceful Spirit of the Wood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10426, 1), + (10427, 'Peaceful Convergence of Spirits', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10427, 1), + (10434, 'Quickened Army of the Dead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 10434, 1), + (11073, 'Playing Possum', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11073, 1), + (11074, 'Cat-like Reflexes', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11074, 1), + (11077, 'Hastened Bite of the Asp', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11077, 1), + (11078, 'Hastened Gorilla Smash', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11078, 1), + (11079, 'Hastened Raven\'s Claw', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11079, 1), + (11080, 'Chameleon Strike', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11080, 1), + (11085, 'Two Hands, No Mercy!', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 11085, 1), + (11088, 'Hastened Cry of Battle', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 11088, 1), + (12600, 'Hastened Frenzied Stabbing', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12600, 1), + (12603, 'Extended Frenzied Stabbing Discipline', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12603, 1), + (12606, 'Speed of the Scoundrel', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12606, 1), + (12607, 'Hastened Pinpoint', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12607, 1), + (12615, 'Hastened Twisted Chance Discipline', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12615, 1), + (15073, 'Banestrike', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 15073, 1), + (15074, 'Hastened Banestrike', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 15074, 1), + (30050, 'Unknown AA 30050', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 30050, 1), + (30100, 'Unknown AA 30100', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 30100, 1), + (30150, 'Unknown AA 30150', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 30150, 1), + (30175, 'Unknown AA 30175', 2, 65335, 65535, 127, 131071, 0, 4, 0, 1, 30175, 1), + (30180, 'Unknown AA 30180', 2, 128, 65535, 127, 131071, 0, 4, 0, 1, 30180, 1), + (30185, 'Unknown AA 30185', 2, 64, 65535, 127, 131071, 0, 4, 0, 1, 30185, 1), + (30190, 'Unknown AA 30190', 2, 8, 65535, 127, 131071, 0, 4, 0, 1, 30190, 1), + (30195, 'Unknown AA 30195', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 30195, 1); + +DROP TABLE IF EXISTS `aa_ranks`; +CREATE TABLE IF NOT EXISTS `aa_ranks` ( + `id` int(10) unsigned NOT NULL, + `upper_hotkey_sid` int(10) NOT NULL DEFAULT '-1', + `lower_hotkey_sid` int(10) NOT NULL DEFAULT '-1', + `title_sid` int(10) NOT NULL DEFAULT '-1', + `desc_sid` int(10) NOT NULL DEFAULT '-1', + `cost` int(10) NOT NULL DEFAULT '1', + `level_req` int(10) NOT NULL DEFAULT '51', + `spell` int(10) NOT NULL DEFAULT '-1', + `spell_type` int(10) NOT NULL DEFAULT '0', + `recast_time` int(10) NOT NULL DEFAULT '0', + `expansion` int(10) NOT NULL DEFAULT '0', + `prev_id` int(10) NOT NULL DEFAULT '-1', + `next_id` int(10) NOT NULL DEFAULT '-1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `aa_ranks` (`id`, `upper_hotkey_sid`, `lower_hotkey_sid`, `title_sid`, `desc_sid`, `cost`, `level_req`, `spell`, `spell_type`, `recast_time`, `expansion`, `prev_id`, `next_id`) VALUES + (2, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, -1, 3), + (3, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, 2, 4), + (4, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, 3, 5), + (5, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, 4, 6), + (6, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, 5, 292), + (7, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, -1, 8), + (8, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, 7, 9), + (9, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, 8, 10), + (10, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, 9, 11), + (11, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, 10, 302), + (12, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, -1, 13), + (13, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, 12, 14), + (14, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, 13, 15), + (15, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, 14, 16), + (16, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, 15, 312), + (17, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, -1, 18), + (18, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, 17, 19), + (19, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, 18, 20), + (20, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, 19, 21), + (21, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, 20, 322), + (22, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, -1, 23), + (23, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, 22, 24), + (24, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, 23, 25), + (25, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, 24, 26), + (26, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, 25, 332), + (27, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, -1, 28), + (28, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, 27, 29), + (29, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, 28, 30), + (30, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, 29, 31), + (31, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, 30, 342), + (32, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, -1, 33), + (33, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, 32, 34), + (34, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, 33, 35), + (35, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, 34, 36), + (36, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, 35, 352), + (37, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, -1, 38), + (38, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, 37, 39), + (39, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, 38, 40), + (40, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, 39, 41), + (41, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, 40, 362), + (42, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, -1, 43), + (43, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, 42, 44), + (44, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, 43, 45), + (45, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, 44, 46), + (46, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, 45, 372), + (47, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, -1, 48), + (48, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, 47, 49), + (49, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, 48, 50), + (50, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, 49, 51), + (51, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, 50, 382), + (52, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, -1, 53), + (53, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, 52, 54), + (54, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, 53, 55), + (55, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, 54, 56), + (56, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, 55, 392), + (57, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, -1, 58), + (58, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, 57, 59), + (59, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, 58, 60), + (60, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, 59, 61), + (61, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, 60, 402), + (62, -1, -1, 62, 62, 1, 51, -1, 0, 0, 3, -1, 63), + (63, -1, -1, 62, 62, 1, 51, -1, 0, 0, 3, 62, 64), + (64, -1, -1, 62, 62, 1, 51, -1, 0, 0, 3, 63, 672), + (68, -1, -1, 68, 68, 1, 51, -1, 0, 0, 3, -1, 69), + (69, -1, -1, 68, 68, 1, 51, -1, 0, 0, 3, 68, 70), + (70, -1, -1, 68, 68, 1, 51, -1, 0, 0, 3, 69, -1), + (71, -1, -1, 71, 71, 1, 51, -1, 0, 0, 3, -1, 72), + (72, -1, -1, 71, 71, 1, 51, -1, 0, 0, 3, 71, 73), + (73, -1, -1, 71, 71, 1, 51, -1, 0, 0, 3, 72, 676), + (74, -1, -1, 74, 74, 1, 51, -1, 0, 0, 3, -1, 75), + (75, -1, -1, 74, 74, 1, 51, -1, 0, 0, 3, 74, 76), + (76, -1, -1, 74, 74, 1, 51, -1, 0, 0, 3, 75, -1), + (77, -1, -1, 77, 77, 2, 55, -1, 0, 0, 3, -1, 78), + (78, -1, -1, 77, 77, 4, 55, -1, 0, 0, 3, 77, 79), + (79, -1, -1, 77, 77, 6, 55, -1, 0, 0, 3, 78, 434), + (80, -1, -1, 80, 80, 2, 55, -1, 0, 0, 3, -1, 81), + (81, -1, -1, 80, 80, 4, 55, -1, 0, 0, 3, 80, 82), + (82, -1, -1, 80, 80, 6, 55, -1, 0, 0, 3, 81, 437), + (83, -1, -1, 83, 83, 2, 55, -1, 0, 0, 3, -1, 84), + (84, -1, -1, 83, 83, 4, 55, -1, 0, 0, 3, 83, 85), + (85, -1, -1, 83, 83, 6, 55, -1, 0, 0, 3, 84, 13099), + (86, -1, -1, 86, 86, 2, 55, -1, 0, 0, 3, -1, 87), + (87, -1, -1, 86, 86, 4, 55, -1, 0, 0, 3, 86, 88), + (88, -1, -1, 86, 86, 6, 55, -1, 0, 0, 3, 87, 266), + (92, -1, -1, 92, 92, 2, 55, -1, 0, 0, 3, -1, 93), + (93, -1, -1, 92, 92, 4, 55, -1, 0, 0, 3, 92, 94), + (94, -1, -1, 92, 92, 6, 55, -1, 0, 0, 3, 93, -1), + (98, -1, -1, 98, 98, 2, 55, -1, 0, 0, 3, -1, 99), + (99, -1, -1, 98, 98, 4, 55, -1, 0, 0, 3, 98, 100), + (100, -1, -1, 98, 98, 6, 55, -1, 0, 0, 3, 99, 4767), + (101, -1, -1, 101, 101, 2, 55, -1, 0, 0, 3, -1, 102), + (102, -1, -1, 101, 101, 4, 55, -1, 0, 0, 3, 101, 103), + (103, -1, -1, 101, 101, 6, 55, -1, 0, 0, 3, 102, -1), + (104, -1, -1, 104, 104, 2, 55, -1, 0, 0, 3, -1, 105), + (105, -1, -1, 104, 104, 4, 55, -1, 0, 0, 3, 104, 106), + (106, -1, -1, 104, 104, 6, 55, -1, 0, 0, 3, 105, -1), + (107, -1, -1, 107, 107, 2, 55, -1, 0, 0, 3, -1, 108), + (108, -1, -1, 107, 107, 4, 55, -1, 0, 0, 3, 107, 109), + (109, -1, -1, 107, 107, 6, 55, -1, 0, 0, 3, 108, 7541), + (110, -1, -1, 110, 110, 2, 55, -1, 0, 0, 3, -1, 111), + (111, -1, -1, 110, 110, 4, 55, -1, 0, 0, 3, 110, 112), + (112, -1, -1, 110, 110, 6, 55, -1, 0, 0, 3, 111, -1), + (113, -1, -1, 113, 113, 2, 55, -1, 0, 0, 3, -1, 114), + (114, -1, -1, 113, 113, 4, 55, -1, 0, 0, 3, 113, 115), + (115, -1, -1, 113, 113, 6, 55, -1, 0, 0, 3, 114, 443), + (116, -1, -1, 116, 116, 2, 55, -1, 0, 0, 3, -1, 117), + (117, -1, -1, 116, 116, 4, 55, -1, 0, 0, 3, 116, 118), + (118, -1, -1, 116, 116, 6, 55, -1, 0, 0, 3, 117, -1), + (119, -1, -1, 119, 119, 2, 55, -1, 0, 0, 3, -1, 120), + (120, -1, -1, 119, 119, 4, 55, -1, 0, 0, 3, 119, 121), + (121, -1, -1, 119, 119, 6, 55, -1, 0, 0, 3, 120, 440), + (122, -1, -1, 122, 122, 2, 55, -1, 0, 0, 3, -1, 123), + (123, -1, -1, 122, 122, 4, 55, -1, 0, 0, 3, 122, 124), + (124, -1, -1, 122, 122, 6, 55, -1, 0, 0, 3, 123, 454), + (125, -1, -1, 125, 125, 2, 55, -1, 0, 0, 3, -1, 126), + (126, -1, -1, 125, 125, 4, 55, -1, 0, 0, 3, 125, 127), + (127, -1, -1, 125, 125, 6, 55, -1, 0, 0, 3, 126, 449), + (128, 128, 128, 128, 128, 9, 59, 5228, 1, 4320, 3, -1, -1), + (129, 129, 129, 129, 129, 5, 59, 2738, 2, 64800, 3, -1, -1), + (130, 130, 130, 130, 130, 3, 59, 2739, 3, 7, 3, -1, -1), + (131, 131, 131, 131, 131, 5, 59, 2740, 4, 900, 3, -1, 531), + (132, 132, 132, 132, 132, 6, 59, 2741, 5, 600, 3, -1, -1), + (136, 136, -1, 136, 136, 5, 59, 2742, 7, 1800, 3, -1, 15341), + (137, -1, -1, 137, 137, 3, 59, -1, 0, 0, 3, -1, 138), + (138, -1, -1, 137, 137, 6, 59, -1, 0, 0, 3, 137, 139), + (139, -1, -1, 137, 137, 9, 59, -1, 0, 0, 3, 138, -1), + (140, 140, -1, 140, 140, 6, 59, 2771, 3, 4320, 3, -1, -1), + (141, -1, -1, 141, 12863, 3, 59, -1, 0, 0, 3, -1, 142), + (142, -1, -1, 141, 12863, 6, 59, -1, 0, 0, 3, 141, 143), + (143, -1, -1, 141, 12863, 9, 59, -1, 0, 0, 3, 142, 12863), + (144, -1, -1, 144, 144, 5, 59, -1, 0, 0, 3, -1, -1), + (145, 145, 145, 145, 145, 9, 59, 2761, 2, 4320, 3, -1, -1), + (146, 146, 146, 146, 146, 5, 59, 2749, 2, 180, 3, -1, 5069), + (147, -1, -1, 147, 147, 3, 59, -1, 0, 0, 3, -1, 148), + (148, -1, -1, 147, 147, 6, 59, -1, 0, 0, 3, 147, 149), + (149, -1, -1, 147, 147, 9, 59, -1, 0, 0, 3, 148, -1), + (150, -1, -1, 150, 150, 3, 59, -1, 0, 0, 3, -1, 151), + (151, -1, -1, 150, 150, 6, 59, -1, 0, 0, 3, 150, 152), + (152, -1, -1, 150, 150, 9, 59, -1, 0, 0, 3, 151, -1), + (153, 153, 153, 153, 153, 5, 59, 2750, 3, 2160, 3, -1, 1519), + (155, 155, 155, 155, 155, 9, 59, 2758, 8, 60, 3, -1, 533), + (156, 156, 156, 156, 156, 6, 59, 2734, 2, 4320, 3, -1, -1), + (158, -1, -1, 158, 158, 3, 59, -1, 0, 0, 3, -1, -1), + (159, -1, -1, 159, 159, 2, 59, -1, 0, 0, 3, -1, 160), + (160, -1, -1, 159, 159, 4, 59, -1, 0, 0, 3, 159, 161), + (161, -1, -1, 159, 159, 6, 59, -1, 0, 0, 3, 160, -1), + (162, 162, 162, 162, 162, 5, 59, 2753, 3, 8640, 3, -1, -1), + (163, 163, 163, 163, 163, 5, 59, 2752, 2, 2160, 3, -1, -1), + (167, 167, 167, 167, 167, 6, 59, 2754, 14, 900, 3, -1, 5879), + (168, 168, 168, 168, 168, 3, 59, 2795, 4, 10, 3, -1, 169), + (169, 168, 168, 168, 168, 6, 59, 2796, 4, 10, 3, 168, 170), + (170, 168, 168, 168, 168, 9, 59, 2797, 4, 10, 3, 169, 15241), + (171, 171, 171, 171, 171, 3, 59, 2798, 4, 10, 3, -1, 172), + (172, 171, 171, 171, 171, 6, 59, 2799, 4, 10, 3, 171, 173), + (173, 171, 171, 171, 171, 9, 59, 2800, 4, 10, 3, 172, 15244), + (174, 174, 174, 174, 174, 3, 59, 2792, 4, 10, 3, -1, 175), + (175, 174, 174, 174, 174, 6, 59, 2793, 4, 10, 3, 174, 176), + (176, 174, 174, 174, 174, 9, 59, 2794, 4, 10, 3, 175, 15247), + (177, 177, 177, 177, 177, 3, 59, 2789, 4, 10, 3, -1, 178), + (178, 177, 177, 177, 177, 6, 59, 2790, 4, 10, 3, 177, 179), + (179, 177, 177, 177, 177, 9, 59, 2791, 4, 10, 3, 178, 15250), + (182, -1, -1, 182, 182, 5, 59, -1, 0, 0, 3, -1, -1), + (183, 183, 183, 183, 183, 9, 59, 2755, 4, 8640, 3, -1, -1), + (184, 184, 184, 184, 184, 3, 59, 2756, 5, 4320, 3, -1, 5953), + (185, 185, 185, 185, 185, 5, 59, 2757, 6, 4320, 3, -1, -1), + (186, 186, 186, 186, 186, 3, 59, 2772, 7, 7, 3, -1, -1), + (187, 187, 187, 187, 187, 6, 59, 2764, 8, 4320, 3, -1, -1), + (188, 188, 188, 188, 188, 9, 59, 2190, 2, 30, 3, -1, 1277), + (190, -1, -1, 190, 190, 3, 59, -1, 0, 0, 3, -1, 191), + (191, -1, -1, 190, 190, 6, 59, -1, 0, 0, 3, 190, 192), + (192, -1, -1, 190, 190, 9, 59, -1, 0, 0, 3, 191, 1524), + (193, 193, 193, 193, 193, 3, 59, 2775, 3, 4320, 3, -1, -1), + (194, 194, 194, 194, 194, 5, 59, 2874, 0, 1, 3, -1, -1), + (195, -1, -1, 195, 195, 6, 59, -1, 0, 0, 3, -1, -1), + (196, -1, -1, 196, 196, 6, 59, -1, 0, 0, 3, -1, -1), + (197, 197, 197, 197, 197, 5, 59, 2765, 2, 7, 3, -1, -1), + (198, -1, -1, 198, 198, 9, 59, -1, 0, 0, 3, -1, -1), + (199, -1, -1, 199, 199, 3, 59, -1, 0, 0, 3, -1, 200), + (200, -1, -1, 199, 199, 6, 59, -1, 0, 0, 3, 199, 201), + (201, -1, -1, 199, 199, 9, 59, -1, 0, 0, 3, 200, 12507), + (205, -1, -1, 205, 205, 9, 59, -1, 0, 0, 3, -1, -1), + (206, 206, 206, 206, 206, 5, 59, 2875, 0, 1, 3, -1, -1), + (208, 208, 208, 208, 208, 6, 59, 2766, 2, 4320, 3, -1, -1), + (210, -1, -1, 210, 210, 3, 59, -1, 0, 0, 3, -1, 211), + (211, -1, -1, 210, 210, 6, 59, -1, 0, 0, 3, 210, 212), + (212, -1, -1, 210, 210, 9, 59, -1, 0, 0, 3, 211, 1316), + (213, -1, -1, 213, 213, 3, 59, -1, 0, 0, 3, -1, 214), + (214, -1, -1, 213, 213, 6, 59, -1, 0, 0, 3, 213, 215), + (215, -1, -1, 213, 213, 9, 59, -1, 0, 0, 3, 214, 700), + (225, -1, -1, 225, 225, 3, 59, -1, 0, 0, 3, -1, 226), + (226, -1, -1, 225, 225, 6, 59, -1, 0, 0, 3, 225, 227), + (227, -1, -1, 225, 225, 9, 59, -1, 0, 0, 3, 226, -1), + (230, -1, -1, 230, 230, 3, 59, -1, 0, 0, 3, -1, 231), + (231, -1, -1, 230, 230, 6, 59, -1, 0, 0, 3, 230, 232), + (232, -1, -1, 230, 230, 9, 59, -1, 0, 0, 3, 231, 539), + (233, 233, 233, 233, 233, 9, 59, 5248, 1, 1800, 3, -1, -1), + (237, -1, -1, 237, 237, 3, 59, -1, 0, 0, 3, -1, 238), + (238, -1, -1, 237, 237, 6, 59, -1, 0, 0, 3, 237, 239), + (239, -1, -1, 237, 237, 9, 59, -1, 0, 0, 3, 238, -1), + (240, -1, -1, 240, 240, 3, 59, -1, 0, 0, 3, -1, 241), + (241, -1, -1, 240, 240, 6, 59, -1, 0, 0, 3, 240, 242), + (242, -1, -1, 240, 240, 9, 59, -1, 0, 0, 3, 241, -1), + (243, 243, -1, 243, 243, 9, 59, 5244, 1, 1440, 3, -1, -1), + (244, -1, -1, 244, 244, 3, 59, -1, 0, 0, 3, -1, 245), + (245, -1, -1, 244, 244, 6, 59, -1, 0, 0, 3, 244, 246), + (246, -1, -1, 244, 244, 9, 59, -1, 0, 0, 3, 245, 8328), + (247, -1, -1, 247, 247, 3, 59, -1, 0, 0, 3, -1, 248), + (248, -1, -1, 247, 247, 6, 59, -1, 0, 0, 3, 247, 249), + (249, -1, -1, 247, 247, 9, 59, -1, 0, 0, 3, 248, 504), + (254, 254, 254, 254, 254, 5, 59, 5232, 12, 4320, 3, -1, -1), + (255, -1, -1, 255, 255, 3, 59, -1, 0, 0, 3, -1, 256), + (256, -1, -1, 255, 255, 6, 59, -1, 0, 0, 3, 255, 257), + (257, -1, -1, 255, 255, 9, 59, -1, 0, 0, 3, 256, 542), + (258, 258, -1, 258, 258, 5, 59, 5233, 1, 600, 3, -1, 10578), + (259, 259, 259, 259, 259, 5, 59, 5234, 2, 900, 3, -1, -1), + (260, 260, -1, 260, 260, 3, 59, 5229, 3, 2160, 3, -1, 261), + (261, 260, -1, 260, 260, 6, 59, 5230, 3, 2160, 3, 260, 262), + (262, 260, -1, 260, 260, 9, 59, 5231, 3, 2160, 3, 261, 8309), + (263, -1, -1, 263, 263, 3, 59, -1, 0, 0, 3, -1, 264), + (264, -1, -1, 263, 263, 6, 59, -1, 0, 0, 3, 263, 265), + (265, -1, -1, 263, 263, 9, 59, -1, 0, 0, 3, 264, -1), + (266, -1, -1, 86, 86, 8, 59, -1, 0, 0, 3, 88, 10467), + (267, -1, -1, 267, 267, 3, 59, -1, 0, 0, 3, -1, 268), + (268, -1, -1, 267, 267, 6, 59, -1, 0, 0, 3, 267, 269), + (269, -1, -1, 267, 267, 9, 59, -1, 0, 0, 3, 268, 640), + (273, -1, -1, 273, 273, 5, 59, 2767, 0, 0, 3, -1, -1), + (274, 274, 274, 274, 274, 5, 59, 2748, 4, 4320, 3, -1, -1), + (275, -1, -1, 275, 275, 3, 59, -1, 0, 0, 3, -1, 276), + (276, -1, -1, 275, 275, 6, 59, -1, 0, 0, 3, 275, 277), + (277, -1, -1, 275, 275, 9, 59, -1, 0, 0, 3, 276, 701), + (278, -1, -1, 278, 278, 5, 59, -1, 0, 0, 3, -1, -1), + (279, -1, -1, 279, 279, 5, 59, -1, 0, 0, 3, -1, 18972), + (280, -1, -1, 280, 280, 3, 59, -1, 0, 0, 3, -1, 281), + (281, -1, -1, 280, 280, 6, 59, -1, 0, 0, 3, 280, 282), + (282, -1, -1, 280, 280, 9, 59, -1, 0, 0, 3, 281, -1), + (283, -1, -1, 283, 283, 3, 59, -1, 0, 0, 3, -1, 284), + (284, -1, -1, 283, 283, 6, 59, -1, 0, 0, 3, 283, 285), + (285, -1, -1, 283, 283, 9, 59, -1, 0, 0, 3, 284, -1), + (286, -1, -1, 286, 286, 3, 59, -1, 0, 0, 3, -1, -1), + (287, -1, -1, 287, 287, 6, 59, -1, 0, 0, 3, -1, -1), + (288, -1, -1, 288, 288, 6, 59, -1, 0, 0, 3, -1, -1), + (289, 289, 289, 289, 289, 5, 59, 3290, 3, 300, 3, -1, 1607), + (290, 290, 290, 290, 290, 4, 59, 3289, 4, 720, 3, -1, 13173), + (291, 291, 291, 291, 291, 6, 59, 3291, 5, 900, 3, -1, 1123), + (292, -1, -1, 2, 2, 1, 61, -1, 0, 0, 4, 6, 293), + (293, -1, -1, 2, 2, 1, 61, -1, 0, 0, 4, 292, 294), + (294, -1, -1, 2, 2, 1, 62, -1, 0, 0, 4, 293, 295), + (295, -1, -1, 2, 2, 1, 62, -1, 0, 0, 4, 294, 296), + (296, -1, -1, 2, 2, 1, 63, -1, 0, 0, 4, 295, 297), + (297, -1, -1, 2, 2, 1, 63, -1, 0, 0, 4, 296, 298), + (298, -1, -1, 2, 2, 1, 64, -1, 0, 0, 4, 297, 299), + (299, -1, -1, 2, 2, 1, 64, -1, 0, 0, 4, 298, 300), + (300, -1, -1, 2, 2, 1, 65, -1, 0, 0, 4, 299, 301), + (301, -1, -1, 2, 2, 1, 65, -1, 0, 0, 4, 300, -1), + (302, -1, -1, 7, 7, 1, 61, -1, 0, 0, 4, 11, 303), + (303, -1, -1, 7, 7, 1, 61, -1, 0, 0, 4, 302, 304), + (304, -1, -1, 7, 7, 1, 62, -1, 0, 0, 4, 303, 305), + (305, -1, -1, 7, 7, 1, 62, -1, 0, 0, 4, 304, 306), + (306, -1, -1, 7, 7, 1, 63, -1, 0, 0, 4, 305, 307), + (307, -1, -1, 7, 7, 1, 63, -1, 0, 0, 4, 306, 308), + (308, -1, -1, 7, 7, 1, 64, -1, 0, 0, 4, 307, 309), + (309, -1, -1, 7, 7, 1, 64, -1, 0, 0, 4, 308, 310), + (310, -1, -1, 7, 7, 1, 65, -1, 0, 0, 4, 309, 311), + (311, -1, -1, 7, 7, 1, 65, -1, 0, 0, 4, 310, -1), + (312, -1, -1, 12, 12, 1, 61, -1, 0, 0, 4, 16, 313), + (313, -1, -1, 12, 12, 1, 61, -1, 0, 0, 4, 312, 314), + (314, -1, -1, 12, 12, 1, 62, -1, 0, 0, 4, 313, 315), + (315, -1, -1, 12, 12, 1, 62, -1, 0, 0, 4, 314, 316), + (316, -1, -1, 12, 12, 1, 63, -1, 0, 0, 4, 315, 317), + (317, -1, -1, 12, 12, 1, 63, -1, 0, 0, 4, 316, 318), + (318, -1, -1, 12, 12, 1, 64, -1, 0, 0, 4, 317, 319), + (319, -1, -1, 12, 12, 1, 64, -1, 0, 0, 4, 318, 320), + (320, -1, -1, 12, 12, 1, 65, -1, 0, 0, 4, 319, 321), + (321, -1, -1, 12, 12, 1, 65, -1, 0, 0, 4, 320, -1), + (322, -1, -1, 17, 17, 1, 61, -1, 0, 0, 4, 21, 323), + (323, -1, -1, 17, 17, 1, 61, -1, 0, 0, 4, 322, 324), + (324, -1, -1, 17, 17, 1, 62, -1, 0, 0, 4, 323, 325), + (325, -1, -1, 17, 17, 1, 62, -1, 0, 0, 4, 324, 326), + (326, -1, -1, 17, 17, 1, 63, -1, 0, 0, 4, 325, 327), + (327, -1, -1, 17, 17, 1, 63, -1, 0, 0, 4, 326, 328), + (328, -1, -1, 17, 17, 1, 64, -1, 0, 0, 4, 327, 329), + (329, -1, -1, 17, 17, 1, 64, -1, 0, 0, 4, 328, 330), + (330, -1, -1, 17, 17, 1, 65, -1, 0, 0, 4, 329, 331), + (331, -1, -1, 17, 17, 1, 65, -1, 0, 0, 4, 330, -1), + (332, -1, -1, 22, 22, 1, 61, -1, 0, 0, 4, 26, 333), + (333, -1, -1, 22, 22, 1, 61, -1, 0, 0, 4, 332, 334), + (334, -1, -1, 22, 22, 1, 62, -1, 0, 0, 4, 333, 335), + (335, -1, -1, 22, 22, 1, 62, -1, 0, 0, 4, 334, 336), + (336, -1, -1, 22, 22, 1, 63, -1, 0, 0, 4, 335, 337), + (337, -1, -1, 22, 22, 1, 63, -1, 0, 0, 4, 336, 338), + (338, -1, -1, 22, 22, 1, 64, -1, 0, 0, 4, 337, 339), + (339, -1, -1, 22, 22, 1, 64, -1, 0, 0, 4, 338, 340), + (340, -1, -1, 22, 22, 1, 65, -1, 0, 0, 4, 339, 341), + (341, -1, -1, 22, 22, 1, 65, -1, 0, 0, 4, 340, -1), + (342, -1, -1, 27, 27, 1, 61, -1, 0, 0, 4, 31, 343), + (343, -1, -1, 27, 27, 1, 61, -1, 0, 0, 4, 342, 344), + (344, -1, -1, 27, 27, 1, 62, -1, 0, 0, 4, 343, 345), + (345, -1, -1, 27, 27, 1, 62, -1, 0, 0, 4, 344, 346), + (346, -1, -1, 27, 27, 1, 63, -1, 0, 0, 4, 345, 347), + (347, -1, -1, 27, 27, 1, 63, -1, 0, 0, 4, 346, 348), + (348, -1, -1, 27, 27, 1, 64, -1, 0, 0, 4, 347, 349), + (349, -1, -1, 27, 27, 1, 64, -1, 0, 0, 4, 348, 350), + (350, -1, -1, 27, 27, 1, 65, -1, 0, 0, 4, 349, 351), + (351, -1, -1, 27, 27, 1, 65, -1, 0, 0, 4, 350, -1), + (352, -1, -1, 32, 32, 1, 61, -1, 0, 0, 4, 36, 353), + (353, -1, -1, 32, 32, 1, 61, -1, 0, 0, 4, 352, 354), + (354, -1, -1, 32, 32, 1, 62, -1, 0, 0, 4, 353, 355), + (355, -1, -1, 32, 32, 1, 62, -1, 0, 0, 4, 354, 356), + (356, -1, -1, 32, 32, 1, 63, -1, 0, 0, 4, 355, 357), + (357, -1, -1, 32, 32, 1, 63, -1, 0, 0, 4, 356, 358), + (358, -1, -1, 32, 32, 1, 64, -1, 0, 0, 4, 357, 359), + (359, -1, -1, 32, 32, 1, 64, -1, 0, 0, 4, 358, 360), + (360, -1, -1, 32, 32, 1, 65, -1, 0, 0, 4, 359, 361), + (361, -1, -1, 32, 32, 1, 65, -1, 0, 0, 4, 360, -1), + (362, -1, -1, 37, 37, 1, 61, -1, 0, 0, 4, 41, 363), + (363, -1, -1, 37, 37, 1, 61, -1, 0, 0, 4, 362, 364), + (364, -1, -1, 37, 37, 1, 62, -1, 0, 0, 4, 363, 365), + (365, -1, -1, 37, 37, 1, 62, -1, 0, 0, 4, 364, 366), + (366, -1, -1, 37, 37, 1, 63, -1, 0, 0, 4, 365, 367), + (367, -1, -1, 37, 37, 1, 63, -1, 0, 0, 4, 366, 368), + (368, -1, -1, 37, 37, 1, 64, -1, 0, 0, 4, 367, 369), + (369, -1, -1, 37, 37, 1, 64, -1, 0, 0, 4, 368, 370), + (370, -1, -1, 37, 37, 1, 65, -1, 0, 0, 4, 369, 371), + (371, -1, -1, 37, 37, 1, 65, -1, 0, 0, 4, 370, -1), + (372, -1, -1, 42, 42, 1, 61, -1, 0, 0, 4, 46, 373), + (373, -1, -1, 42, 42, 1, 61, -1, 0, 0, 4, 372, 374), + (374, -1, -1, 42, 42, 1, 62, -1, 0, 0, 4, 373, 375), + (375, -1, -1, 42, 42, 1, 62, -1, 0, 0, 4, 374, 376), + (376, -1, -1, 42, 42, 1, 63, -1, 0, 0, 4, 375, 377), + (377, -1, -1, 42, 42, 1, 63, -1, 0, 0, 4, 376, 378), + (378, -1, -1, 42, 42, 1, 64, -1, 0, 0, 4, 377, 379), + (379, -1, -1, 42, 42, 1, 64, -1, 0, 0, 4, 378, 380), + (380, -1, -1, 42, 42, 1, 65, -1, 0, 0, 4, 379, 381), + (381, -1, -1, 42, 42, 1, 65, -1, 0, 0, 4, 380, -1), + (382, -1, -1, 47, 47, 1, 61, -1, 0, 0, 4, 51, 383), + (383, -1, -1, 47, 47, 1, 61, -1, 0, 0, 4, 382, 384), + (384, -1, -1, 47, 47, 1, 62, -1, 0, 0, 4, 383, 385), + (385, -1, -1, 47, 47, 1, 62, -1, 0, 0, 4, 384, 386), + (386, -1, -1, 47, 47, 1, 63, -1, 0, 0, 4, 385, 387), + (387, -1, -1, 47, 47, 1, 63, -1, 0, 0, 4, 386, 388), + (388, -1, -1, 47, 47, 1, 64, -1, 0, 0, 4, 387, 389), + (389, -1, -1, 47, 47, 1, 64, -1, 0, 0, 4, 388, 390), + (390, -1, -1, 47, 47, 1, 65, -1, 0, 0, 4, 389, 391), + (391, -1, -1, 47, 47, 1, 65, -1, 0, 0, 4, 390, -1), + (392, -1, -1, 52, 52, 1, 61, -1, 0, 0, 4, 56, 393), + (393, -1, -1, 52, 52, 1, 61, -1, 0, 0, 4, 392, 394), + (394, -1, -1, 52, 52, 1, 62, -1, 0, 0, 4, 393, 395), + (395, -1, -1, 52, 52, 1, 62, -1, 0, 0, 4, 394, 396), + (396, -1, -1, 52, 52, 1, 63, -1, 0, 0, 4, 395, 397), + (397, -1, -1, 52, 52, 1, 63, -1, 0, 0, 4, 396, 398), + (398, -1, -1, 52, 52, 1, 64, -1, 0, 0, 4, 397, 399), + (399, -1, -1, 52, 52, 1, 64, -1, 0, 0, 4, 398, 400), + (400, -1, -1, 52, 52, 1, 65, -1, 0, 0, 4, 399, 401), + (401, -1, -1, 52, 52, 1, 65, -1, 0, 0, 4, 400, -1), + (402, -1, -1, 57, 57, 1, 61, -1, 0, 0, 4, 61, 403), + (403, -1, -1, 57, 57, 1, 61, -1, 0, 0, 4, 402, 404), + (404, -1, -1, 57, 57, 1, 62, -1, 0, 0, 4, 403, 405), + (405, -1, -1, 57, 57, 1, 62, -1, 0, 0, 4, 404, 406), + (406, -1, -1, 57, 57, 1, 63, -1, 0, 0, 4, 405, 407), + (407, -1, -1, 57, 57, 1, 63, -1, 0, 0, 4, 406, 408), + (408, -1, -1, 57, 57, 1, 64, -1, 0, 0, 4, 407, 409), + (409, -1, -1, 57, 57, 1, 64, -1, 0, 0, 4, 408, 410), + (410, -1, -1, 57, 57, 1, 65, -1, 0, 0, 4, 409, 411), + (411, -1, -1, 57, 57, 1, 65, -1, 0, 0, 4, 410, -1), + (412, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, -1, 413), + (413, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 412, 414), + (414, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 413, 415), + (415, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 414, 416), + (416, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 415, 417), + (417, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 416, -1), + (418, -1, -1, 418, 418, 2, 61, -1, 0, 0, 4, -1, 419), + (419, -1, -1, 418, 418, 2, 62, -1, 0, 0, 4, 418, 420), + (420, -1, -1, 418, 418, 2, 63, -1, 0, 0, 4, 419, 421), + (421, -1, -1, 418, 418, 2, 64, -1, 0, 0, 4, 420, 422), + (422, -1, -1, 418, 418, 2, 65, -1, 0, 0, 4, 421, 1001), + (423, -1, -1, 423, 423, 3, 61, -1, 0, 0, 4, -1, 424), + (424, -1, -1, 423, 423, 3, 63, -1, 0, 0, 4, 423, 425), + (425, -1, -1, 423, 423, 3, 65, -1, 0, 0, 4, 424, -1), + (426, -1, -1, 426, 426, 3, 61, -1, 0, 0, 4, -1, 427), + (427, -1, -1, 426, 426, 3, 62, -1, 0, 0, 4, 426, 428), + (428, -1, -1, 426, 426, 3, 63, -1, 0, 0, 4, 427, 429), + (429, -1, -1, 426, 426, 3, 64, -1, 0, 0, 4, 428, 430), + (430, -1, -1, 426, 426, 3, 65, -1, 0, 0, 4, 429, -1), + (434, -1, -1, 77, 77, 2, 62, -1, 0, 0, 4, 79, 435), + (435, -1, -1, 77, 77, 4, 63, -1, 0, 0, 4, 434, 436), + (436, -1, -1, 77, 77, 6, 64, -1, 0, 0, 4, 435, 1083), + (437, -1, -1, 80, 80, 2, 62, -1, 0, 0, 4, 82, 438), + (438, -1, -1, 80, 80, 3, 63, -1, 0, 0, 4, 437, 439), + (439, -1, -1, 80, 80, 4, 64, -1, 0, 0, 4, 438, 1086), + (440, -1, -1, 119, 119, 2, 62, -1, 0, 0, 4, 121, 441), + (441, -1, -1, 119, 119, 2, 63, -1, 0, 0, 4, 440, 442), + (442, -1, -1, 119, 119, 2, 64, -1, 0, 0, 4, 441, 1053), + (443, -1, -1, 113, 113, 3, 62, -1, 0, 0, 4, 115, 444), + (444, -1, -1, 113, 113, 3, 63, -1, 0, 0, 4, 443, 445), + (445, -1, -1, 113, 113, 3, 64, -1, 0, 0, 4, 444, -1), + (446, -1, -1, 446, 735, 3, 62, -1, 0, 0, 4, -1, 447), + (447, -1, -1, 446, 735, 3, 63, -1, 0, 0, 4, 446, 448), + (448, -1, -1, 446, 735, 3, 64, -1, 0, 0, 4, 447, 7050), + (449, -1, -1, 125, 125, 3, 61, -1, 0, 0, 4, 127, 450), + (450, -1, -1, 125, 125, 3, 62, -1, 0, 0, 4, 449, 451), + (451, -1, -1, 125, 125, 3, 63, -1, 0, 0, 4, 450, 452), + (452, -1, -1, 125, 125, 3, 64, -1, 0, 0, 4, 451, 453), + (453, -1, -1, 125, 125, 3, 65, -1, 0, 0, 4, 452, 1061), + (454, -1, -1, 122, 122, 3, 61, -1, 0, 0, 4, 124, 455), + (455, -1, -1, 122, 122, 3, 62, -1, 0, 0, 4, 454, 456), + (456, -1, -1, 122, 122, 3, 63, -1, 0, 0, 4, 455, 457), + (457, -1, -1, 122, 122, 3, 64, -1, 0, 0, 4, 456, 458), + (458, -1, -1, 122, 122, 3, 65, -1, 0, 0, 4, 457, 1066), + (459, 459, 459, 459, 459, 2, 61, 3297, 8, 180, 4, -1, 460), + (460, 459, 459, 459, 459, 4, 63, 3298, 8, 180, 4, 459, 461), + (461, 459, 459, 459, 459, 6, 65, 3299, 8, 180, 4, 460, 1189), + (462, -1, -1, 462, 462, 2, 63, -1, 0, 0, 4, -1, 463), + (463, -1, -1, 462, 462, 2, 64, -1, 0, 0, 4, 462, 464), + (464, -1, -1, 462, 462, 2, 65, -1, 0, 0, 4, 463, 7994), + (468, -1, -1, 468, 468, 2, 63, -1, 0, 0, 4, -1, 469), + (469, -1, -1, 468, 468, 2, 64, -1, 0, 0, 4, 468, 470), + (470, -1, -1, 468, 468, 2, 65, -1, 0, 0, 4, 469, 6439), + (471, -1, -1, 471, 471, 2, 63, -1, 0, 0, 4, -1, 472), + (472, -1, -1, 471, 471, 2, 64, -1, 0, 0, 4, 471, 473), + (473, -1, -1, 471, 471, 2, 65, -1, 0, 0, 4, 472, 12899), + (474, -1, -1, 474, 474, 2, 63, -1, 0, 0, 4, -1, 475), + (475, -1, -1, 474, 474, 2, 64, -1, 0, 0, 4, 474, 476), + (476, -1, -1, 474, 474, 2, 65, -1, 0, 0, 4, 475, 15359), + (477, -1, -1, 477, 477, 2, 63, -1, 0, 0, 4, -1, 478), + (478, -1, -1, 477, 477, 2, 64, -1, 0, 0, 4, 477, 479), + (479, -1, -1, 477, 477, 2, 65, -1, 0, 0, 4, 478, 6233), + (480, -1, -1, 480, 480, 2, 63, -1, 0, 0, 4, -1, 481), + (481, -1, -1, 480, 480, 2, 64, -1, 0, 0, 4, 480, 482), + (482, -1, -1, 480, 480, 2, 65, -1, 0, 0, 4, 481, 4921), + (483, -1, -1, 483, 483, 2, 63, -1, 0, 0, 4, -1, 484), + (484, -1, -1, 483, 483, 2, 64, -1, 0, 0, 4, 483, 485), + (485, -1, -1, 483, 483, 2, 65, -1, 0, 0, 4, 484, -1), + (489, -1, -1, 489, 489, 3, 63, -1, 0, 0, 4, -1, 490), + (490, -1, -1, 489, 489, 3, 64, -1, 0, 0, 4, 489, 491), + (491, -1, -1, 489, 489, 3, 65, -1, 0, 0, 4, 490, 7116), + (492, -1, -1, 492, 492, 2, 63, -1, 0, 0, 4, -1, 493), + (493, -1, -1, 492, 492, 2, 64, -1, 0, 0, 4, 492, 494), + (494, -1, -1, 492, 492, 2, 65, -1, 0, 0, 4, 493, 7128), + (495, -1, -1, 495, 495, 2, 63, -1, 0, 0, 4, -1, 496), + (496, -1, -1, 495, 495, 2, 64, -1, 0, 0, 4, 495, 497), + (497, -1, -1, 495, 495, 2, 65, -1, 0, 0, 4, 496, 6260), + (498, -1, -1, 498, 498, 2, 63, -1, 0, 0, 4, -1, 499), + (499, -1, -1, 498, 498, 2, 64, -1, 0, 0, 4, 498, 500), + (500, -1, -1, 498, 498, 2, 65, -1, 0, 0, 4, 499, 886), + (501, -1, -1, 501, 501, 2, 63, -1, 0, 0, 4, -1, 502), + (502, -1, -1, 501, 501, 2, 64, -1, 0, 0, 4, 501, 503), + (503, -1, -1, 501, 501, 2, 65, -1, 0, 0, 4, 502, 6319), + (504, -1, -1, 247, 247, 3, 62, -1, 0, 0, 4, 249, 505), + (505, -1, -1, 247, 247, 3, 63, -1, 0, 0, 4, 504, 506), + (506, -1, -1, 247, 247, 3, 64, -1, 0, 0, 4, 505, -1), + (507, 507, 507, 507, 507, 3, 61, 3252, 9, 180, 4, -1, 508), + (508, 507, 507, 507, 507, 3, 63, 3253, 9, 180, 4, 507, 509), + (509, 507, 507, 507, 507, 3, 65, 3254, 9, 180, 4, 508, -1), + (510, 510, 510, 510, 510, 3, 61, 3255, 37, 240, 4, -1, 511), + (511, 510, 510, 510, 510, 3, 63, 3256, 37, 240, 4, 510, 512), + (512, 510, 510, 510, 510, 3, 65, 3257, 37, 240, 4, 511, 7425), + (513, 513, 513, 513, 513, 3, 61, 3274, 4, 120, 4, -1, 514), + (514, 513, 513, 513, 513, 3, 63, 3275, 4, 120, 4, 513, 515), + (515, 513, 513, 513, 513, 3, 65, 3276, 4, 120, 4, 514, 6095), + (516, 516, 516, 516, 516, 2, 62, 3338, 5, 480, 4, -1, 6398), + (517, 517, 517, 517, 517, 3, 61, 3258, 12, 600, 4, -1, 518), + (518, 517, 517, 517, 517, 3, 63, 3259, 12, 600, 4, 517, 519), + (519, 517, 517, 517, 517, 3, 65, 3260, 12, 600, 4, 518, 1440), + (520, 520, 520, 520, 520, 3, 61, 3265, 6, 540, 4, -1, 521), + (521, 520, 520, 520, 520, 3, 63, 3266, 6, 540, 4, 520, 522), + (522, 520, 520, 520, 520, 3, 65, 3267, 6, 540, 4, 521, 1507), + (523, 523, 523, 523, 523, 5, 61, 3268, 9, 540, 4, -1, 524), + (524, 523, 523, 523, 523, 4, 63, 3269, 9, 540, 4, 523, 525), + (525, 523, 523, 523, 523, 3, 65, 3270, 9, 540, 4, 524, -1), + (526, 526, 526, 526, 526, 5, 62, 3248, 0, 1, 4, -1, 527), + (527, 526, 526, 526, 526, 3, 64, 3249, 0, 1, 4, 526, -1), + (528, 528, 528, 528, 528, 4, 61, 3283, 5, 720, 4, -1, 529), + (529, 528, 528, 528, 528, 3, 63, 3284, 5, 720, 4, 528, 530), + (530, 528, 528, 528, 528, 2, 65, 3285, 5, 720, 4, 529, 900), + (531, 131, 131, 131, 131, 3, 63, 3250, 4, 900, 4, 131, 532), + (532, 131, 131, 131, 131, 6, 64, 3251, 4, 900, 4, 531, 1203), + (533, 155, 155, 155, 155, 6, 64, 3264, 8, 60, 4, 155, 1344), + (534, 534, 534, 534, 534, 3, 61, 3261, 4, 2160, 4, -1, 535), + (535, 534, 534, 534, 534, 3, 63, 3262, 4, 2160, 4, 534, 536), + (536, 534, 534, 534, 534, 3, 65, 3263, 4, 2160, 4, 535, 715), + (537, -1, -1, 537, 537, 3, 63, -1, 0, 0, 4, -1, 538), + (538, -1, -1, 537, 537, 3, 64, -1, 0, 0, 4, 537, -1), + (539, -1, -1, 230, 230, 2, 63, -1, 0, 0, 4, 232, 540), + (540, -1, -1, 230, 230, 4, 64, -1, 0, 0, 4, 539, 541), + (541, -1, -1, 230, 230, 6, 65, -1, 0, 0, 4, 540, 12677), + (542, -1, -1, 255, 255, 2, 63, -1, 0, 0, 4, 257, 543), + (543, -1, -1, 255, 255, 4, 64, -1, 0, 0, 4, 542, 544), + (544, -1, -1, 255, 255, 6, 65, -1, 0, 0, 4, 543, 1163), + (545, 545, 545, 545, 545, 3, 61, 3271, 3, 900, 4, -1, 546), + (546, 545, 545, 545, 545, 3, 63, 3272, 3, 900, 4, 545, 547), + (547, 545, 545, 545, 545, 3, 65, 3273, 3, 900, 4, 546, 1293), + (548, 548, 548, 548, 548, 4, 61, 3277, 5, 900, 4, -1, 549), + (549, 548, 548, 548, 548, 3, 63, 3278, 5, 900, 4, 548, 550), + (550, 548, 548, 548, 548, 2, 65, 3279, 5, 900, 4, 549, 1225), + (551, -1, -1, 551, 551, 2, 61, -1, 0, 0, 4, -1, 552), + (552, -1, -1, 551, 551, 2, 62, -1, 0, 0, 4, 551, 553), + (553, -1, -1, 551, 551, 2, 63, -1, 0, 0, 4, 552, 554), + (554, -1, -1, 551, 551, 2, 64, -1, 0, 0, 4, 553, 555), + (555, -1, -1, 551, 551, 2, 65, -1, 0, 0, 4, 554, 1633), + (556, -1, -1, 556, 556, 2, 61, -1, 0, 0, 4, -1, 557), + (557, -1, -1, 556, 556, 2, 62, -1, 0, 0, 4, 556, 558), + (558, -1, -1, 556, 556, 2, 63, -1, 0, 0, 4, 557, 559), + (559, -1, -1, 556, 556, 2, 64, -1, 0, 0, 4, 558, 560), + (560, -1, -1, 556, 556, 2, 65, -1, 0, 0, 4, 559, 1563), + (561, -1, -1, 561, 561, 2, 61, -1, 0, 0, 4, -1, 562), + (562, -1, -1, 561, 561, 4, 63, -1, 0, 0, 4, 561, 563), + (563, -1, -1, 561, 561, 6, 65, -1, 0, 0, 4, 562, 1624), + (564, -1, -1, 564, 564, 3, 61, -1, 0, 0, 4, -1, 565), + (565, -1, -1, 564, 564, 3, 63, -1, 0, 0, 4, 564, 566), + (566, -1, -1, 564, 564, 3, 65, -1, 0, 0, 4, 565, 1621), + (567, -1, -1, 567, 567, 5, 63, -1, 0, 0, 4, -1, 5061), + (574, -1, -1, 574, 574, 3, 61, -1, 0, 0, 4, -1, 575), + (575, -1, -1, 574, 574, 3, 63, -1, 0, 0, 4, 574, 576), + (576, -1, -1, 574, 574, 3, 65, -1, 0, 0, 4, 575, 7718), + (577, -1, -1, 577, 577, 2, 61, -1, 0, 0, 4, -1, 578), + (578, -1, -1, 577, 577, 4, 63, -1, 0, 0, 4, 577, 579), + (579, -1, -1, 577, 577, 6, 65, -1, 0, 0, 4, 578, -1), + (580, -1, -1, 580, 580, 4, 61, -1, 0, 0, 4, -1, 581), + (581, -1, -1, 580, 580, 3, 63, -1, 0, 0, 4, 580, 582), + (582, -1, -1, 580, 580, 2, 65, -1, 0, 0, 4, 581, -1), + (583, -1, -1, 583, 583, 2, 63, -1, 0, 0, 4, -1, 584), + (584, -1, -1, 583, 583, 2, 64, -1, 0, 0, 4, 583, 585), + (585, -1, -1, 583, 583, 2, 65, -1, 0, 0, 4, 584, -1), + (586, -1, -1, 586, 586, 2, 61, -1, 0, 0, 4, -1, 587), + (587, -1, -1, 586, 586, 4, 63, -1, 0, 0, 4, 586, 588), + (588, -1, -1, 586, 586, 6, 65, -1, 0, 0, 4, 587, 6130), + (589, -1, -1, 589, 589, 3, 61, -1, 0, 0, 4, -1, 590), + (590, -1, -1, 589, 589, 3, 63, -1, 0, 0, 4, 589, 591), + (591, -1, -1, 589, 589, 3, 65, -1, 0, 0, 4, 590, 893), + (592, 592, 592, 592, 592, 6, 63, 3282, 2, 18, 4, -1, 702), + (593, -1, -1, 593, 593, 3, 61, -1, 0, 0, 4, -1, 594), + (594, -1, -1, 593, 593, 3, 63, -1, 0, 0, 4, 593, 595), + (595, -1, -1, 593, 593, 3, 65, -1, 0, 0, 4, 594, 5972), + (596, -1, -1, 596, 596, 2, 61, -1, 0, 0, 4, -1, 597), + (597, -1, -1, 596, 596, 4, 63, -1, 0, 0, 4, 596, 598), + (598, -1, -1, 596, 596, 6, 65, -1, 0, 0, 4, 597, 5973), + (599, -1, -1, 599, 599, 2, 61, -1, 0, 0, 4, -1, 600), + (600, -1, -1, 599, 599, 4, 63, -1, 0, 0, 4, 599, 601), + (601, -1, -1, 599, 599, 6, 65, -1, 0, 0, 4, 600, 1536), + (602, -1, -1, 602, 602, 3, 61, -1, 0, 0, 4, -1, 603), + (603, -1, -1, 602, 602, 3, 63, -1, 0, 0, 4, 602, 604), + (604, -1, -1, 602, 602, 3, 65, -1, 0, 0, 4, 603, 1533), + (605, -1, -1, 605, 605, 6, 63, -1, 0, 0, 4, -1, -1), + (606, -1, -1, 606, 606, 1, 61, -1, 0, 0, 4, -1, 607), + (607, -1, -1, 606, 606, 1, 62, -1, 0, 0, 4, 606, 608), + (608, -1, -1, 606, 606, 1, 63, -1, 0, 0, 4, 607, 609), + (609, -1, -1, 606, 606, 1, 64, -1, 0, 0, 4, 608, 610), + (610, -1, -1, 606, 606, 1, 65, -1, 0, 0, 4, 609, -1), + (611, -1, -1, 611, 611, 2, 61, -1, 0, 0, 4, -1, 612), + (612, -1, -1, 611, 611, 2, 62, -1, 0, 0, 4, 611, 613), + (613, -1, -1, 611, 611, 2, 63, -1, 0, 0, 4, 612, 614), + (614, -1, -1, 611, 611, 2, 64, -1, 0, 0, 4, 613, 615), + (615, -1, -1, 611, 611, 2, 65, -1, 0, 0, 4, 614, 7175), + (616, 616, 616, 616, 616, 5, 63, 3286, 7, 900, 4, -1, 617), + (617, 616, 616, 616, 616, 4, 64, 3287, 7, 900, 4, 616, 618), + (618, 616, 616, 616, 616, 3, 65, 3288, 7, 900, 4, 617, 1248), + (619, 619, 619, 619, 619, 3, 61, 3292, 6, 900, 4, -1, 620), + (620, 619, 619, 619, 619, 2, 63, 3293, 6, 900, 4, 619, 621), + (621, 619, 619, 619, 619, 1, 65, 3294, 6, 900, 4, 620, 721), + (622, -1, -1, 622, 622, 3, 61, -1, 0, 0, 4, -1, 623), + (623, -1, -1, 622, 622, 3, 62, -1, 0, 0, 4, 622, 624), + (624, -1, -1, 622, 622, 3, 63, -1, 0, 0, 4, 623, 8329), + (625, -1, -1, 625, 625, 1, 61, -1, 0, 0, 4, -1, 626), + (626, -1, -1, 625, 625, 2, 63, -1, 0, 0, 4, 625, 627), + (627, -1, -1, 625, 625, 3, 65, -1, 0, 0, 4, 626, 4733), + (628, -1, -1, 628, 628, 2, 62, -1, 0, 0, 4, -1, 629), + (629, -1, -1, 628, 628, 4, 64, -1, 0, 0, 4, 628, -1), + (630, 630, 630, 630, 630, 6, 63, 5243, 7, 1, 4, -1, -1), + (631, -1, -1, 631, 631, 2, 61, -1, 0, 0, 4, -1, 632), + (632, -1, -1, 631, 631, 3, 63, -1, 0, 0, 4, 631, 633), + (633, -1, -1, 631, 631, 4, 65, -1, 0, 0, 4, 632, 1172), + (634, -1, -1, 634, 634, 1, 61, -1, 0, 0, 4, -1, 635), + (635, -1, -1, 634, 634, 2, 63, -1, 0, 0, 4, 634, 636), + (636, -1, -1, 634, 634, 3, 65, -1, 0, 0, 4, 635, 844), + (637, -1, -1, 637, 637, 3, 61, -1, 0, 0, 4, -1, 638), + (638, -1, -1, 637, 637, 6, 63, -1, 0, 0, 4, 637, 639), + (639, -1, -1, 637, 637, 9, 65, -1, 0, 0, 4, 638, 770), + (640, -1, -1, 267, 267, 2, 61, -1, 0, 0, 4, 269, 641), + (641, -1, -1, 267, 267, 4, 63, -1, 0, 0, 4, 640, 642), + (642, -1, -1, 267, 267, 6, 65, -1, 0, 0, 4, 641, 924), + (643, 643, 643, 643, 643, 4, 62, 5227, 0, 1, 4, -1, -1), + (644, -1, -1, 644, 644, 4, 60, -1, 0, 0, 4, -1, 1601), + (645, 645, -1, 645, 645, 4, 64, 3614, 4, 5, 4, -1, 5999), + (649, -1, -1, 649, 649, 2, 61, -1, 0, 0, 4, -1, 650), + (650, -1, -1, 649, 649, 4, 63, -1, 0, 0, 4, 649, 651), + (651, -1, -1, 649, 649, 6, 65, -1, 0, 0, 4, 650, 5860), + (652, -1, -1, 652, 652, 2, 61, -1, 0, 0, 4, -1, 653), + (653, -1, -1, 652, 652, 4, 63, -1, 0, 0, 4, 652, 654), + (654, -1, -1, 652, 652, 6, 65, -1, 0, 0, 4, 653, -1), + (655, -1, -1, 655, 655, 3, 59, -1, 0, 0, 3, -1, 656), + (656, -1, -1, 655, 655, 6, 59, -1, 0, 0, 3, 655, 657), + (657, -1, -1, 655, 655, 9, 59, -1, 0, 0, 3, 656, -1), + (658, -1, -1, 658, 658, 2, 55, -1, 0, 0, 3, -1, 659), + (659, -1, -1, 658, 658, 4, 55, -1, 0, 0, 3, 658, 660), + (660, -1, -1, 658, 658, 6, 55, -1, 0, 0, 3, 659, 5306), + (661, -1, -1, 65, 661, 1, 51, -1, 0, 0, 3, -1, 662), + (662, -1, -1, 65, 661, 1, 51, -1, 0, 0, 3, 661, 663), + (663, -1, -1, 65, 661, 1, 51, -1, 0, 0, 3, 662, 674), + (665, -1, -1, 270, 665, 3, 59, -1, 0, 0, 3, -1, 666), + (666, -1, -1, 270, 665, 6, 59, -1, 0, 0, 3, 665, 667), + (667, -1, -1, 270, 665, 9, 59, -1, 0, 0, 3, 666, 668), + (668, -1, -1, 270, 665, 2, 63, -1, 0, 0, 4, 667, 669), + (669, -1, -1, 270, 665, 2, 64, -1, 0, 0, 4, 668, 670), + (670, -1, -1, 270, 665, 2, 65, -1, 0, 0, 4, 669, 7612), + (671, -1, -1, 671, 671, 3, 59, -1, 0, 0, 3, -1, -1), + (672, -1, -1, 62, 62, 5, 61, -1, 0, 0, 7, 64, 673), + (673, -1, -1, 62, 62, 5, 61, -1, 0, 0, 7, 672, -1), + (674, -1, -1, 65, 661, 3, 61, -1, 0, 0, 7, 663, 675), + (675, -1, -1, 65, 661, 3, 61, -1, 0, 0, 7, 674, 1031), + (676, -1, -1, 71, 71, 2, 61, -1, 0, 0, 7, 73, 677), + (677, -1, -1, 71, 71, 3, 61, -1, 0, 0, 7, 676, 978), + (678, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, -1, 679), + (679, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, 678, 680), + (680, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, 679, 681), + (681, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, 680, 682), + (682, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, 681, 6518), + (683, -1, -1, 683, 683, 3, 61, -1, 0, 0, 7, -1, 684), + (684, -1, -1, 683, 683, 6, 61, -1, 0, 0, 7, 683, 685), + (685, -1, -1, 683, 683, 9, 61, -1, 0, 0, 7, 684, 1036), + (686, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, -1, 687), + (687, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, 686, 688), + (688, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, 687, 689), + (689, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, 688, 690), + (690, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, 689, 7640), + (691, -1, -1, 691, 691, 9, 55, -1, 0, 0, 7, -1, -1), + (692, -1, -1, 692, 692, 3, 55, -1, 0, 0, 7, -1, 693), + (693, -1, -1, 692, 692, 6, 55, -1, 0, 0, 7, 692, 694), + (694, -1, -1, 692, 692, 9, 55, -1, 0, 0, 7, 693, 7647), + (695, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, -1, 696), + (696, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, 695, 697), + (697, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, 696, 698), + (698, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, 697, 699), + (699, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, 698, 15529), + (700, -1, -1, 213, 213, 9, 61, -1, 0, 0, 7, 215, -1), + (701, -1, -1, 275, 275, 9, 61, -1, 0, 0, 7, 277, -1), + (702, 592, 592, 592, 592, 3, 65, 4842, 2, 18, 7, 592, 703), + (703, 592, 592, 592, 592, 3, 65, 4843, 2, 18, 7, 702, 704), + (704, 592, 592, 592, 592, 3, 65, 4844, 2, 18, 7, 703, 705), + (705, 592, 592, 592, 592, 3, 65, 4845, 2, 18, 7, 704, 706), + (706, 592, 592, 592, 592, 3, 65, 4846, 2, 18, 7, 705, 1102), + (715, 534, 534, 534, 534, 3, 65, 5112, 4, 2160, 7, 536, 716), + (716, 534, 534, 534, 534, 6, 65, 5113, 4, 2160, 7, 715, 717), + (717, 534, 534, 534, 534, 9, 65, 5114, 4, 2160, 7, 716, 1278), + (718, 718, 718, 718, 718, 3, 65, 4521, 7, 4320, 7, -1, 719), + (719, 718, 718, 718, 718, 6, 65, 4522, 7, 4320, 7, 718, 720), + (720, 718, 718, 718, 718, 9, 65, 4523, 7, 4320, 7, 719, 1019), + (721, 619, 619, 619, 619, 5, 65, 5110, 6, 900, 7, 621, 722), + (722, 619, 619, 619, 619, 5, 65, 5111, 6, 900, 7, 721, 6296), + (723, 723, 723, 723, 723, 9, 65, 4788, 6, 30, 7, -1, 4963), + (724, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, -1, 725), + (725, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, 724, 726), + (726, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, 725, 727), + (727, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, 726, 728), + (728, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, 727, 5254), + (729, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, -1, 730), + (730, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, 729, 731), + (731, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, 730, 732), + (732, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, 731, 733), + (733, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, 732, 1467), + (734, -1, -1, 734, 734, 12, 65, -1, 0, 0, 7, -1, -1), + (735, -1, -1, 735, 735, 3, 62, -1, 0, 0, 7, -1, 736), + (736, -1, -1, 735, 735, 3, 62, -1, 0, 0, 7, 735, 737), + (737, -1, -1, 735, 735, 3, 62, -1, 0, 0, 7, 736, 7056), + (738, -1, -1, 98, 738, 3, 55, -1, 0, 0, 7, -1, 739), + (739, -1, -1, 98, 738, 6, 55, -1, 0, 0, 7, 738, 740), + (740, -1, -1, 98, 738, 9, 55, -1, 0, 0, 7, 739, 5317), + (746, 746, 746, 746, 746, 3, 65, 4549, 10, 2160, 7, -1, 747), + (747, 746, 746, 746, 746, 6, 65, 4550, 10, 2160, 7, 746, 748), + (748, 746, 746, 746, 746, 9, 65, 4551, 10, 2160, 7, 747, 1491), + (749, 749, 749, 749, 749, 5, 65, 4790, 11, 1800, 7, -1, 750), + (750, 749, 749, 749, 749, 5, 65, 4791, 11, 1800, 7, 749, 751), + (751, 749, 749, 749, 749, 5, 65, 4792, 11, 1800, 7, 750, 752), + (752, 749, 749, 749, 749, 5, 65, 4793, 11, 1800, 7, 751, 753), + (753, 749, 749, 749, 749, 5, 65, 4794, 11, 1800, 7, 752, 1206), + (754, -1, -1, 754, 754, 3, 65, -1, 0, 0, 7, -1, 755), + (755, -1, -1, 754, 754, 6, 65, -1, 0, 0, 7, 754, 756), + (756, -1, -1, 754, 754, 9, 65, -1, 0, 0, 7, 755, 7659), + (757, 757, -1, 757, 757, 5, 65, 4796, 6, 1800, 7, -1, 758), + (758, 757, -1, 757, 757, 5, 65, 4797, 6, 1800, 7, 757, 759), + (759, 757, -1, 757, 757, 5, 65, 4798, 6, 1800, 7, 758, 760), + (760, 757, -1, 757, 757, 5, 65, 4799, 6, 1800, 7, 759, 761), + (761, 757, -1, 757, 757, 5, 65, 4800, 6, 1800, 7, 760, 1222), + (762, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, -1, 763), + (763, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, 762, 764), + (764, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, 763, 765), + (765, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, 764, 766), + (766, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, 765, -1), + (767, -1, -1, 767, 767, 3, 65, -1, 0, 0, 7, -1, 768), + (768, -1, -1, 767, 767, 6, 65, -1, 0, 0, 7, 767, 769), + (769, -1, -1, 767, 767, 9, 65, -1, 0, 0, 7, 768, 1099), + (770, -1, -1, 637, 637, 3, 65, -1, 0, 0, 7, 639, 771), + (771, -1, -1, 637, 637, 6, 65, -1, 0, 0, 7, 770, 772), + (772, -1, -1, 637, 637, 9, 65, -1, 0, 0, 7, 771, 4749), + (773, 773, -1, 773, 773, 3, 65, 4552, 5, 1800, 7, -1, 774), + (774, 773, -1, 773, 773, 6, 65, 4553, 5, 1800, 7, 773, 775), + (775, 773, -1, 773, 773, 9, 65, 4554, 5, 1800, 7, 774, 5854), + (776, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, -1, 777), + (777, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, 776, 778), + (778, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, 777, 779), + (779, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, 778, 780), + (780, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, 779, -1), + (781, -1, -1, 781, 781, 12, 65, -1, 0, 0, 7, -1, 5850), + (782, -1, -1, 782, 782, 3, 65, -1, 0, 0, 7, -1, 783), + (783, -1, -1, 782, 782, 6, 65, -1, 0, 0, 7, 782, 784), + (784, -1, -1, 782, 782, 9, 65, -1, 0, 0, 7, 783, -1), + (785, 785, 785, 785, 785, 5, 65, 5235, 8, 900, 7, -1, 786), + (786, 785, 785, 785, 785, 5, 65, 5236, 8, 900, 7, 785, 787), + (787, 785, 785, 785, 785, 5, 65, 5237, 8, 900, 7, 786, 788), + (788, 785, 785, 785, 785, 5, 65, 5238, 8, 900, 7, 787, 789), + (789, 785, 785, 785, 785, 5, 65, 5239, 8, 900, 7, 788, 15235), + (790, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, -1, 791), + (791, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, 790, 792), + (792, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, 791, 793), + (793, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, 792, 794), + (794, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, 793, 5259), + (795, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, -1, 796), + (796, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, 795, 797), + (797, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, 796, 798), + (798, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, 797, 799), + (799, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, 798, 1430), + (800, -1, -1, 800, 800, 3, 65, -1, 0, 0, 7, -1, 801), + (801, -1, -1, 800, 800, 6, 65, -1, 0, 0, 7, 800, 802), + (802, -1, -1, 800, 800, 9, 65, -1, 0, 0, 7, 801, -1), + (803, -1, -1, 803, 803, 3, 65, -1, 0, 0, 7, -1, 804), + (804, -1, -1, 803, 803, 6, 65, -1, 0, 0, 7, 803, 805), + (805, -1, -1, 803, 803, 9, 65, -1, 0, 0, 7, 804, -1), + (806, -1, -1, 806, 806, 12, 65, -1, 0, 0, 7, -1, -1), + (807, -1, -1, 807, 807, 3, 65, -1, 0, 0, 7, -1, 808), + (808, -1, -1, 807, 807, 6, 65, -1, 0, 0, 7, 807, 809), + (809, -1, -1, 807, 807, 9, 65, -1, 0, 0, 7, 808, 1268), + (810, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, -1, 811), + (811, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, 810, 812), + (812, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, 811, 813), + (813, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, 812, 814), + (814, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, 813, 4824), + (815, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, -1, 816), + (816, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, 815, 817), + (817, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, 816, 818), + (818, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, 817, 819), + (819, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, 818, 5141), + (820, -1, -1, 820, 820, 3, 65, -1, 0, 0, 7, -1, 821), + (821, -1, -1, 820, 820, 6, 65, -1, 0, 0, 7, 820, 822), + (822, -1, -1, 820, 820, 9, 65, -1, 0, 0, 7, 821, 1265), + (823, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, -1, 824), + (824, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, 823, 825), + (825, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, 824, 826), + (826, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, 825, 827), + (827, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, 826, -1), + (828, 828, 828, 828, 828, 3, 65, 5240, 2, 3600, 7, -1, 829), + (829, 828, 828, 828, 828, 6, 65, 5241, 2, 3600, 7, 828, 830), + (830, 828, 828, 828, 828, 9, 65, 5242, 2, 3600, 7, 829, 16250), + (834, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, -1, 835), + (835, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, 834, 836), + (836, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, 835, 837), + (837, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, 836, 838), + (838, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, 837, -1), + (839, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, -1, 840), + (840, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, 839, 841), + (841, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, 840, 842), + (842, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, 841, 843), + (843, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, 842, 5325), + (844, -1, -1, 634, 634, 5, 65, -1, 0, 0, 7, 636, 845), + (845, -1, -1, 634, 634, 5, 65, -1, 0, 0, 7, 844, 1319), + (846, -1, -1, 846, 846, 3, 65, -1, 0, 0, 7, -1, 847), + (847, -1, -1, 846, 846, 6, 65, -1, 0, 0, 7, 846, 848), + (848, -1, -1, 846, 846, 9, 65, -1, 0, 0, 7, 847, 1301), + (849, -1, -1, 849, 849, 3, 65, -1, 0, 0, 7, -1, 850), + (850, -1, -1, 849, 849, 6, 65, -1, 0, 0, 7, 849, 851), + (851, -1, -1, 849, 849, 9, 65, -1, 0, 0, 7, 850, 10621), + (852, -1, -1, 852, 852, 5, 65, -1, 0, 0, 7, -1, 853), + (853, -1, -1, 852, 852, 5, 65, -1, 0, 0, 7, 852, 854), + (854, -1, -1, 852, 852, 5, 65, -1, 0, 0, 7, 853, 5500), + (855, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, -1, 856), + (856, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, 855, 857), + (857, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, 856, 858), + (858, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, 857, 859), + (859, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, 858, 7673), + (860, 860, 860, 860, 860, 3, 65, 3297, 5, 180, 7, -1, 861), + (861, 860, 860, 860, 860, 6, 65, 3298, 5, 180, 7, 860, 862), + (862, 860, 860, 860, 860, 9, 65, 3299, 5, 180, 7, 861, 5130), + (863, 863, -1, 863, 863, 12, 65, 5248, 6, 4320, 7, -1, -1), + (864, -1, -1, 864, 864, 3, 65, -1, 0, 0, 7, -1, 865), + (865, -1, -1, 864, 864, 6, 65, -1, 0, 0, 7, 864, 866), + (866, -1, -1, 864, 864, 9, 65, -1, 0, 0, 7, 865, 1290), + (867, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, -1, 868), + (868, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, 867, 869), + (869, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, 868, 870), + (870, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, 869, 871), + (871, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, 870, 7362), + (872, 872, 872, 872, 872, 3, 65, 4802, 5, 180, 7, -1, 873), + (873, 872, 872, 872, 872, 6, 65, 4803, 5, 180, 7, 872, 874), + (874, 872, 872, 872, 872, 9, 65, 4804, 5, 180, 7, 873, 7367), + (875, 875, 875, 875, 875, 3, 65, 4805, 5, 180, 7, -1, 876), + (876, 875, 875, 875, 875, 6, 65, 4806, 5, 180, 7, 875, 877), + (877, 875, 875, 875, 875, 9, 65, 4807, 5, 180, 7, 876, 7370), + (878, -1, -1, 878, 878, 3, 65, -1, 0, 0, 7, -1, 879), + (879, -1, -1, 878, 878, 6, 65, -1, 0, 0, 7, 878, 880), + (880, -1, -1, 878, 878, 9, 65, -1, 0, 0, 7, 879, 1539), + (881, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, -1, 882), + (882, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, 881, 883), + (883, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, 882, 884), + (884, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, 883, 885), + (885, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, 884, -1), + (886, -1, -1, 498, 498, 5, 65, -1, 0, 0, 7, 500, 887), + (887, -1, -1, 498, 498, 5, 65, -1, 0, 0, 7, 886, 975), + (888, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, -1, 889), + (889, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, 888, 890), + (890, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, 889, 891), + (891, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, 890, 892), + (892, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, 891, 16267), + (893, -1, -1, 589, 589, 5, 65, -1, 0, 0, 7, 591, 894), + (894, -1, -1, 589, 589, 5, 65, -1, 0, 0, 7, 893, 5270), + (895, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, -1, 896), + (896, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, 895, 897), + (897, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, 896, 898), + (898, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, 897, 899), + (899, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, 898, 6075), + (900, 528, 528, 528, 528, 5, 65, 4826, 5, 720, 7, 530, 901), + (901, 528, 528, 528, 528, 5, 65, 4827, 5, 720, 7, 900, 6103), + (907, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, -1, 908), + (908, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, 907, 909), + (909, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, 908, 910), + (910, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, 909, 911), + (911, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, 910, 5243), + (912, 912, 912, 912, 912, 3, 65, 4925, 4, 3600, 7, -1, 913), + (913, 912, 912, 912, 912, 6, 65, 4926, 4, 3600, 7, 912, 914), + (914, 912, 912, 912, 912, 9, 65, 4927, 4, 3600, 7, 913, 1330), + (915, -1, -1, 915, 915, 3, 65, -1, 0, 0, 7, -1, 916), + (916, -1, -1, 915, 915, 6, 65, -1, 0, 0, 7, 915, 917), + (917, -1, -1, 915, 915, 9, 65, -1, 0, 0, 7, 916, -1), + (918, -1, -1, 918, 918, 3, 65, -1, 0, 0, 7, -1, 919), + (919, -1, -1, 918, 918, 6, 65, -1, 0, 0, 7, 918, 920), + (920, -1, -1, 918, 918, 9, 65, -1, 0, 0, 7, 919, -1), + (921, 921, 921, 921, 921, 12, 65, 4833, 8, 60, 7, -1, 1340), + (922, 922, 922, 922, 922, 12, 65, 4834, 8, 60, 7, -1, 1341), + (923, 923, 923, 923, 923, 12, 65, 4835, 8, 60, 7, -1, 1342), + (924, -1, -1, 267, 267, 5, 65, -1, 0, 0, 7, 642, 925), + (925, -1, -1, 267, 267, 5, 65, -1, 0, 0, 7, 924, 5133), + (926, 926, 926, 926, 926, 3, 65, 4836, 12, 1800, 7, -1, 927), + (927, 926, 926, 926, 926, 3, 65, 4837, 12, 1800, 7, 926, 928), + (928, 926, 926, 926, 926, 3, 65, 4838, 12, 1800, 7, 927, 929), + (929, 926, 926, 926, 926, 3, 65, 4839, 12, 1800, 7, 928, 930), + (930, 926, 926, 926, 926, 3, 65, 4840, 12, 1800, 7, 929, 14991), + (931, 931, 931, 931, 931, 3, 65, 5245, 13, 4320, 7, -1, 932), + (932, 931, 931, 931, 931, 6, 65, 5246, 13, 4320, 7, 931, 933), + (933, 931, 931, 931, 931, 9, 65, 5247, 13, 4320, 7, 932, -1), + (934, -1, -1, 113, 934, 2, 55, -1, 0, 0, 3, -1, 935), + (935, -1, -1, 113, 934, 4, 55, -1, 0, 0, 3, 934, 936), + (936, -1, -1, 113, 934, 6, 55, -1, 0, 0, 3, 935, 943), + (937, -1, -1, 113, 937, 2, 55, -1, 0, 0, 3, -1, 938), + (938, -1, -1, 113, 937, 4, 55, -1, 0, 0, 3, 937, 939), + (939, -1, -1, 113, 937, 6, 55, -1, 0, 0, 3, 938, 946), + (940, -1, -1, 113, 940, 2, 55, -1, 0, 0, 3, -1, 941), + (941, -1, -1, 113, 940, 4, 55, -1, 0, 0, 3, 940, 942), + (942, -1, -1, 113, 940, 6, 55, -1, 0, 0, 3, 941, 949), + (943, -1, -1, 113, 934, 3, 62, -1, 0, 0, 4, 936, 944), + (944, -1, -1, 113, 934, 3, 63, -1, 0, 0, 4, 943, 945), + (945, -1, -1, 113, 934, 3, 64, -1, 0, 0, 4, 944, -1), + (946, -1, -1, 113, 937, 3, 62, -1, 0, 0, 4, 939, 947), + (947, -1, -1, 113, 937, 3, 63, -1, 0, 0, 4, 946, 948), + (948, -1, -1, 113, 937, 3, 64, -1, 0, 0, 4, 947, -1), + (949, -1, -1, 113, 940, 3, 62, -1, 0, 0, 4, 942, 950), + (950, -1, -1, 113, 940, 3, 63, -1, 0, 0, 4, 949, 951), + (951, -1, -1, 113, 940, 3, 64, -1, 0, 0, 4, 950, -1), + (952, -1, -1, 952, 952, 3, 61, -1, 0, 0, 4, -1, 953), + (953, -1, -1, 952, 952, 3, 63, -1, 0, 0, 4, 952, 954), + (954, -1, -1, 952, 952, 3, 65, -1, 0, 0, 4, 953, -1), + (955, -1, -1, 955, 955, 3, 61, -1, 0, 0, 4, -1, 956), + (956, -1, -1, 955, 955, 3, 62, -1, 0, 0, 4, 955, 957), + (957, -1, -1, 955, 955, 3, 63, -1, 0, 0, 4, 956, 958), + (958, -1, -1, 955, 955, 3, 64, -1, 0, 0, 4, 957, 959), + (959, -1, -1, 955, 955, 3, 65, -1, 0, 0, 4, 958, -1), + (960, 960, 960, 960, 960, 9, 59, 2760, 7, 4320, 3, -1, -1), + (961, 961, 961, 961, 961, 9, 59, 2759, 11, 4320, 3, -1, -1), + (962, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, -1, 963), + (963, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, 962, 964), + (964, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, 963, 965), + (965, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, 964, 966), + (966, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, 965, 6223), + (967, 967, 967, 967, 967, 3, 65, 4564, 10, 1800, 7, -1, 968), + (968, 967, 967, 967, 967, 6, 65, 4565, 10, 1800, 7, 967, 969), + (969, 967, 967, 967, 967, 9, 65, 4566, 10, 1800, 7, 968, 6464), + (970, 970, 970, 970, 970, 5, 65, 4828, 6, 1800, 7, -1, 971), + (971, 970, 970, 970, 970, 5, 65, 4829, 6, 1800, 7, 970, 972), + (972, 970, 970, 970, 970, 5, 65, 4830, 6, 1800, 7, 971, 973), + (973, 970, 970, 970, 970, 5, 65, 4831, 6, 1800, 7, 972, 974), + (974, 970, 970, 970, 970, 5, 65, 4832, 6, 1800, 7, 973, 1324), + (975, -1, -1, 498, 498, 5, 65, -1, 0, 0, 15, 887, 13262), + (976, -1, -1, 976, 976, 5, 59, -1, 0, 0, 15, -1, -1), + (977, 977, 977, 977, 977, 6, 64, 13835, 72, 600, 15, -1, -1), + (978, -1, -1, 71, 71, 5, 68, -1, 0, 0, 8, 677, -1), + (979, -1, -1, 979, 979, 3, 59, -1, 0, 0, 8, -1, 980), + (980, -1, -1, 979, 979, 6, 59, -1, 0, 0, 8, 979, 981), + (981, -1, -1, 979, 979, 9, 59, -1, 0, 0, 8, 980, -1), + (982, -1, -1, 982, 982, 3, 59, -1, 0, 0, 8, -1, 983), + (983, -1, -1, 982, 982, 6, 59, -1, 0, 0, 8, 982, 984), + (984, -1, -1, 982, 982, 9, 59, -1, 0, 0, 8, 983, -1), + (985, -1, -1, 985, 985, 3, 59, -1, 0, 0, 8, -1, 986), + (986, -1, -1, 985, 985, 6, 59, -1, 0, 0, 8, 985, 987), + (987, -1, -1, 985, 985, 9, 59, -1, 0, 0, 8, 986, -1), + (988, -1, -1, 988, 988, 3, 59, -1, 0, 0, 8, -1, 989), + (989, -1, -1, 988, 988, 6, 59, -1, 0, 0, 8, 988, 990), + (990, -1, -1, 988, 988, 9, 59, -1, 0, 0, 8, 989, -1), + (991, -1, -1, 991, 991, 3, 59, -1, 0, 0, 8, -1, 992), + (992, -1, -1, 991, 991, 6, 59, -1, 0, 0, 8, 991, 993), + (993, -1, -1, 991, 991, 9, 59, -1, 0, 0, 8, 992, -1), + (994, -1, -1, 994, 994, 3, 59, -1, 0, 0, 8, -1, 995), + (995, -1, -1, 994, 994, 6, 59, -1, 0, 0, 8, 994, 996), + (996, -1, -1, 994, 994, 9, 59, -1, 0, 0, 8, 995, -1), + (997, -1, -1, 997, 997, 5, 60, -1, 0, 0, 8, -1, 998), + (998, -1, -1, 997, 997, 5, 65, -1, 0, 0, 8, 997, 999), + (999, -1, -1, 997, 997, 5, 70, -1, 0, 0, 8, 998, 1113), + (1000, 1000, -1, 1000, 1000, 0, 5, 5824, 20, 1080, 0, -1, -1), + (1001, -1, -1, 418, 418, 5, 66, -1, 0, 0, 8, 422, 1002), + (1002, -1, -1, 418, 418, 5, 67, -1, 0, 0, 8, 1001, 1003), + (1003, -1, -1, 418, 418, 5, 68, -1, 0, 0, 8, 1002, 1004), + (1004, -1, -1, 418, 418, 5, 69, -1, 0, 0, 8, 1003, 1005), + (1005, -1, -1, 418, 418, 5, 70, -1, 0, 0, 8, 1004, 4678), + (1006, -1, -1, 1006, 1006, 5, 66, -1, 0, 0, 8, -1, 1007), + (1007, -1, -1, 1006, 1006, 5, 67, -1, 0, 0, 8, 1006, 1008), + (1008, -1, -1, 1006, 1006, 5, 68, -1, 0, 0, 8, 1007, 1009), + (1009, -1, -1, 1006, 1006, 5, 69, -1, 0, 0, 8, 1008, 1010), + (1010, -1, -1, 1006, 1006, 5, 70, -1, 0, 0, 8, 1009, 7516), + (1011, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, -1, 1012), + (1012, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1011, 1013), + (1013, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1012, 1014), + (1014, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1013, 1015), + (1016, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1015, -1), + (1017, 1017, 1017, 1017, 1017, 6, 59, 16531, 75, 15, 15, -1, 13726), + (1018, 1018, 1018, 1018, 1018, 2, 63, 16455, 69, 1, 15, -1, -1), + (1019, 718, 718, 718, 718, 12, 65, 21746, 7, 4320, 16, 720, 13454), + (1021, -1, -1, 1021, 1021, 5, 51, -1, 0, 0, 8, -1, 1022), + (1022, -1, -1, 1021, 1021, 5, 55, -1, 0, 0, 8, 1021, 1023), + (1023, -1, -1, 1021, 1021, 5, 60, -1, 0, 0, 8, 1022, 1024), + (1024, -1, -1, 1021, 1021, 5, 65, -1, 0, 0, 8, 1023, 1025), + (1025, -1, -1, 1021, 1021, 5, 70, -1, 0, 0, 8, 1024, 6521), + (1026, -1, -1, 1026, 1026, 3, 66, -1, 0, 0, 8, -1, 1027), + (1027, -1, -1, 1026, 1026, 3, 67, -1, 0, 0, 8, 1026, 1028), + (1028, -1, -1, 1026, 1026, 3, 68, -1, 0, 0, 8, 1027, 1029), + (1029, -1, -1, 1026, 1026, 3, 69, -1, 0, 0, 8, 1028, 1030), + (1030, -1, -1, 1026, 1026, 3, 70, -1, 0, 0, 8, 1029, 1389), + (1031, -1, -1, 65, 661, 3, 66, -1, 0, 0, 8, 675, 1032), + (1032, -1, -1, 65, 661, 3, 67, -1, 0, 0, 8, 1031, 1033), + (1033, -1, -1, 65, 661, 3, 68, -1, 0, 0, 8, 1032, 1034), + (1034, -1, -1, 65, 661, 3, 69, -1, 0, 0, 8, 1033, 1035), + (1035, -1, -1, 65, 661, 3, 70, -1, 0, 0, 8, 1034, 4693), + (1036, -1, -1, 683, 683, 5, 66, -1, 0, 0, 8, 685, 1037), + (1037, -1, -1, 683, 683, 5, 68, -1, 0, 0, 8, 1036, 1038), + (1038, -1, -1, 683, 683, 5, 70, -1, 0, 0, 8, 1037, 5301), + (1041, -1, -1, 1041, 1041, 3, 67, -1, 0, 0, 8, -1, 1042), + (1042, -1, -1, 1041, 1041, 6, 68, -1, 0, 0, 8, 1041, 1043), + (1043, -1, -1, 1041, 1041, 9, 69, -1, 0, 0, 8, 1042, 4707), + (1044, -1, -1, 1044, 1044, 3, 67, -1, 0, 0, 8, -1, 1045), + (1045, -1, -1, 1044, 1044, 6, 68, -1, 0, 0, 8, 1044, 1046), + (1046, -1, -1, 1044, 1044, 9, 69, -1, 0, 0, 8, 1045, 4710), + (1047, -1, -1, 1047, 1047, 3, 67, -1, 0, 0, 8, -1, 1048), + (1048, -1, -1, 1047, 1047, 6, 68, -1, 0, 0, 8, 1047, 1049), + (1049, -1, -1, 1047, 1047, 9, 69, -1, 0, 0, 8, 1048, 4713), + (1050, -1, -1, 1050, 1050, 3, 67, -1, 0, 0, 8, -1, 1051), + (1051, -1, -1, 1050, 1050, 6, 68, -1, 0, 0, 8, 1050, 1052), + (1052, -1, -1, 1050, 1050, 9, 69, -1, 0, 0, 8, 1051, 4716), + (1053, -1, -1, 119, 119, 3, 66, -1, 0, 0, 8, 442, 1054), + (1054, -1, -1, 119, 119, 3, 68, -1, 0, 0, 8, 1053, 1055), + (1055, -1, -1, 119, 119, 3, 70, -1, 0, 0, 8, 1054, 4722), + (1056, -1, -1, 1056, 1056, 5, 71, -1, 0, 0, 12, -1, 1057), + (1057, -1, -1, 1056, 1056, 5, 72, -1, 0, 0, 12, 1056, 1058), + (1058, -1, -1, 1056, 1056, 5, 73, -1, 0, 0, 12, 1057, 1059), + (1059, -1, -1, 1056, 1056, 5, 74, -1, 0, 0, 12, 1058, 1060), + (1060, -1, -1, 1056, 1056, 5, 75, -1, 0, 0, 12, 1059, 6431), + (1061, -1, -1, 125, 125, 5, 66, -1, 0, 0, 8, 453, 1062), + (1062, -1, -1, 125, 125, 5, 67, -1, 0, 0, 8, 1061, 1063), + (1063, -1, -1, 125, 125, 5, 68, -1, 0, 0, 8, 1062, 1064), + (1064, -1, -1, 125, 125, 5, 69, -1, 0, 0, 8, 1063, 1065), + (1065, -1, -1, 125, 125, 5, 70, -1, 0, 0, 8, 1064, 1394), + (1066, -1, -1, 122, 122, 5, 66, -1, 0, 0, 8, 458, 1067), + (1067, -1, -1, 122, 122, 5, 67, -1, 0, 0, 8, 1066, 1068), + (1068, -1, -1, 122, 122, 5, 68, -1, 0, 0, 8, 1067, 1069), + (1069, -1, -1, 122, 122, 5, 69, -1, 0, 0, 8, 1068, 1070), + (1070, -1, -1, 122, 122, 5, 70, -1, 0, 0, 8, 1069, 1399), + (1071, -1, -1, 1071, 1071, 3, 55, -1, 0, 0, 8, -1, 4764), + (1072, -1, -1, 1072, 1072, 5, 66, -1, 0, 0, 8, -1, 1073), + (1073, -1, -1, 1072, 1072, 5, 67, -1, 0, 0, 8, 1072, 1074), + (1074, -1, -1, 1072, 1072, 5, 68, -1, 0, 0, 8, 1073, 1075), + (1075, -1, -1, 1072, 1072, 5, 69, -1, 0, 0, 8, 1074, 1076), + (1076, -1, -1, 1072, 1072, 5, 70, -1, 0, 0, 8, 1075, 4744), + (1083, -1, -1, 77, 77, 3, 66, -1, 0, 0, 8, 436, 1084), + (1084, -1, -1, 77, 77, 6, 68, -1, 0, 0, 8, 1083, 1085), + (1085, -1, -1, 77, 77, 9, 70, -1, 0, 0, 8, 1084, 12449), + (1086, -1, -1, 80, 80, 3, 66, -1, 0, 0, 8, 439, 1087), + (1087, -1, -1, 80, 80, 6, 68, -1, 0, 0, 8, 1086, 1088), + (1088, -1, -1, 80, 80, 9, 70, -1, 0, 0, 8, 1087, 4779), + (1089, -1, -1, 1089, 1089, 3, 59, -1, 0, 0, 8, -1, 1090), + (1090, -1, -1, 1089, 1089, 6, 59, -1, 0, 0, 8, 1089, 1091), + (1091, -1, -1, 1089, 1089, 9, 59, -1, 0, 0, 8, 1090, -1), + (1092, -1, -1, 1092, 1092, 7, 67, -1, 0, 0, 8, -1, -1), + (1093, -1, -1, 1093, 1093, 3, 66, -1, 0, 0, 8, -1, 1094), + (1094, -1, -1, 1093, 1093, 3, 67, -1, 0, 0, 8, 1093, 1095), + (1095, -1, -1, 1093, 1093, 3, 68, -1, 0, 0, 8, 1094, 1096), + (1096, -1, -1, 1093, 1093, 3, 69, -1, 0, 0, 8, 1095, 1097), + (1097, -1, -1, 1093, 1093, 3, 70, -1, 0, 0, 8, 1096, -1), + (1099, -1, -1, 767, 767, 3, 67, -1, 0, 0, 8, 769, 1100), + (1100, -1, -1, 767, 767, 6, 68, -1, 0, 0, 8, 1099, 1101), + (1101, -1, -1, 767, 767, 9, 69, -1, 0, 0, 8, 1100, 12423), + (1102, 592, 592, 592, 592, 3, 66, 5825, 2, 18, 8, 706, 1103), + (1103, 592, 592, 592, 592, 3, 67, 5826, 2, 18, 8, 1102, 1104), + (1104, 592, 592, 592, 592, 3, 68, 5827, 2, 18, 8, 1103, 1105), + (1105, 592, 592, 592, 592, 3, 69, 5828, 2, 18, 8, 1104, 1106), + (1106, 592, 592, 592, 592, 3, 70, 5829, 2, 18, 8, 1105, 4975), + (1107, -1, -1, 1107, 1107, 3, 66, -1, 0, 0, 8, -1, 1108), + (1108, -1, -1, 1107, 1107, 6, 68, -1, 0, 0, 8, 1107, 1109), + (1109, -1, -1, 1107, 1107, 9, 70, -1, 0, 0, 8, 1108, 5286), + (1110, 1110, 1110, 1110, 1110, 3, 68, 5830, 3, 2160, 8, -1, 1111), + (1111, 1110, 1110, 1110, 1110, 6, 69, 5831, 3, 2160, 8, 1110, 1112), + (1112, 1110, 1110, 1110, 1110, 9, 70, 5832, 3, 2160, 8, 1111, 6400), + (1113, -1, -1, 997, 997, 5, 75, -1, 0, 0, 16, 999, 1114), + (1114, -1, -1, 997, 997, 5, 80, -1, 0, 0, 16, 1113, 1115), + (1115, -1, -1, 997, 997, 5, 85, -1, 0, 0, 16, 1114, -1), + (1116, 1116, 1116, 1116, 1116, 3, 68, 5837, 4, 2160, 8, -1, 1117), + (1117, 1116, 1116, 1116, 1116, 6, 69, 5838, 4, 2160, 8, 1116, 1118), + (1118, 1116, 1116, 1116, 1116, 9, 70, 5839, 4, 2160, 8, 1117, 4980), + (1119, 1119, 1119, 1119, 1119, 3, 68, 5841, 8, 900, 8, -1, 1120), + (1120, 1119, 1119, 1119, 1119, 6, 69, 5842, 8, 900, 8, 1119, 1121), + (1121, 1119, 1119, 1119, 1119, 9, 70, 5843, 8, 900, 8, 1120, 4964), + (1122, -1, -1, 1122, 1122, 7, 67, -1, 0, 0, 8, -1, -1), + (1123, 291, 291, 291, 291, 5, 66, 5854, 5, 900, 8, 291, 1124), + (1124, 291, 291, 291, 291, 5, 68, 5855, 5, 900, 8, 1123, 1125), + (1125, 291, 291, 291, 291, 5, 70, 5856, 5, 900, 8, 1124, 4969), + (1126, 1126, 1126, 1126, 1126, 3, 67, 5845, 2, 2160, 8, -1, 1127), + (1127, 1126, 1126, 1126, 1126, 6, 68, 5846, 2, 2160, 8, 1126, 1128), + (1128, 1126, 1126, 1126, 1126, 9, 69, 5847, 2, 2160, 8, 1127, 5513), + (1129, -1, -1, 1129, 1129, 5, 67, -1, 0, 0, 8, -1, 1130), + (1130, -1, -1, 1129, 1129, 3, 69, -1, 0, 0, 8, 1129, -1), + (1131, -1, -1, 1131, 1131, 3, 59, -1, 0, 0, 3, -1, 1132), + (1132, -1, -1, 1131, 1131, 6, 59, -1, 0, 0, 3, 1131, 1133), + (1133, -1, -1, 1131, 1131, 9, 59, -1, 0, 0, 3, 1132, 11082), + (1134, -1, -1, 1134, 1134, 3, 61, -1, 0, 0, 4, -1, 1135), + (1135, -1, -1, 1134, 1134, 4, 63, -1, 0, 0, 4, 1134, 1136), + (1136, -1, -1, 1134, 1134, 5, 65, -1, 0, 0, 4, 1135, 1158), + (1137, -1, -1, 1137, 1137, 3, 59, -1, 0, 0, 3, -1, 1138), + (1138, -1, -1, 1137, 1137, 6, 59, -1, 0, 0, 3, 1137, 1139), + (1139, -1, -1, 1137, 1137, 9, 59, -1, 0, 0, 3, 1138, -1), + (1140, -1, -1, 1140, 1140, 3, 61, -1, 0, 0, 4, -1, 1141), + (1141, -1, -1, 1140, 1140, 3, 63, -1, 0, 0, 4, 1140, 1142), + (1142, -1, -1, 1140, 1140, 3, 65, -1, 0, 0, 4, 1141, -1), + (1146, 1146, 1146, 1146, 1146, 3, 59, 6040, 3, 1500, 3, -1, 1147), + (1147, 1146, 1146, 1146, 1146, 6, 59, 6041, 3, 1200, 3, 1146, 1148), + (1148, 1146, 1146, 1146, 1146, 9, 59, 6042, 3, 900, 3, 1147, -1), + (1149, 1149, -1, 1149, 1149, 12, 65, 5853, 5, 1320, 7, -1, -1), + (1150, 1150, 1150, 1150, 1150, 3, 65, 5848, 2, 2160, 7, -1, 1151), + (1151, 1150, 1150, 1150, 1150, 6, 65, 5849, 2, 2160, 7, 1150, 1152), + (1152, 1150, 1150, 1150, 1150, 9, 65, 5850, 2, 2160, 7, 1151, -1), + (1155, -1, -1, 1155, 1155, 3, 65, -1, 0, 0, 7, -1, 1156), + (1156, -1, -1, 1155, 1155, 6, 65, -1, 0, 0, 7, 1155, 1157), + (1157, -1, -1, 1155, 1155, 9, 65, -1, 0, 0, 7, 1156, -1), + (1158, -1, -1, 1134, 1134, 4, 66, -1, 0, 0, 8, 1136, 1159), + (1159, -1, -1, 1134, 1134, 4, 67, -1, 0, 0, 8, 1158, 1160), + (1160, -1, -1, 1134, 1134, 4, 68, -1, 0, 0, 8, 1159, 1161), + (1161, -1, -1, 1134, 1134, 4, 69, -1, 0, 0, 8, 1160, 1162), + (1162, -1, -1, 1134, 1134, 4, 70, -1, 0, 0, 8, 1161, 4790), + (1163, -1, -1, 255, 255, 5, 67, -1, 0, 0, 8, 544, 1164), + (1164, -1, -1, 255, 255, 5, 68, -1, 0, 0, 8, 1163, 1165), + (1165, -1, -1, 255, 255, 5, 69, -1, 0, 0, 8, 1164, 4795), + (1166, -1, -1, 1143, 1143, 3, 65, -1, 0, 0, 15, -1, 1167), + (1167, -1, -1, 1143, 1143, 6, 65, -1, 0, 0, 15, 1166, 1168), + (1168, -1, -1, 1143, 1143, 9, 65, -1, 0, 0, 15, 1167, 6911), + (1172, -1, -1, 631, 631, 5, 67, -1, 0, 0, 8, 633, 1173), + (1173, -1, -1, 631, 631, 5, 68, -1, 0, 0, 8, 1172, 1174), + (1174, -1, -1, 631, 631, 5, 69, -1, 0, 0, 8, 1173, 4798), + (1178, 1178, 1178, 1178, 1178, 3, 68, 5857, 4, 900, 8, -1, 1179), + (1179, 1178, 1178, 1178, 1178, 6, 69, 5858, 4, 900, 8, 1178, 1180), + (1180, 1178, 1178, 1178, 1178, 9, 70, 5859, 4, 900, 8, 1179, 5779), + (1181, -1, -1, 1181, 1181, 3, 66, -1, 0, 0, 8, -1, 1182), + (1182, -1, -1, 1181, 1181, 3, 67, -1, 0, 0, 8, 1181, 1183), + (1183, -1, -1, 1181, 1181, 3, 68, -1, 0, 0, 8, 1182, 1184), + (1184, -1, -1, 1181, 1181, 3, 69, -1, 0, 0, 8, 1183, 1185), + (1185, -1, -1, 1181, 1181, 3, 70, -1, 0, 0, 8, 1184, -1), + (1186, -1, -1, 1186, 1186, 3, 66, -1, 0, 0, 8, -1, 1187), + (1187, -1, -1, 1186, 1186, 6, 68, -1, 0, 0, 8, 1186, 1188), + (1188, -1, -1, 1186, 1186, 9, 70, -1, 0, 0, 8, 1187, 4776), + (1189, 459, 459, 459, 459, 3, 66, 5860, 8, 180, 8, 461, 1190), + (1190, 459, 459, 459, 459, 6, 68, 5861, 8, 180, 8, 1189, 1191), + (1191, 459, 459, 459, 459, 9, 70, 5862, 8, 180, 8, 1190, 5062), + (1192, 1192, 1192, 1192, 1192, 5, 67, 5863, 12, 1320, 8, -1, 1193), + (1193, 1192, 1192, 1192, 1192, 5, 68, 5864, 12, 1320, 8, 1192, 1194), + (1194, 1192, 1192, 1192, 1192, 5, 69, 5865, 12, 1320, 8, 1193, 5076), + (1195, 1195, 1195, 1195, 1195, 12, 70, 5866, 13, 2160, 8, -1, 5079), + (1196, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, -1, 1197), + (1197, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, 1196, 1198), + (1198, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, 1197, 1199), + (1199, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, 1198, 1200), + (1200, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, 1199, 10743), + (1203, 131, 131, 131, 131, 5, 67, 5869, 4, 900, 8, 532, 1204), + (1204, 131, 131, 131, 131, 5, 68, 5870, 4, 900, 8, 1203, 1205), + (1205, 131, 131, 131, 131, 5, 69, 5988, 4, 900, 8, 1204, 5070), + (1206, 749, 749, 749, 749, 5, 66, 5871, 11, 1800, 8, 753, 1207), + (1207, 749, 749, 749, 749, 5, 68, 5872, 11, 1800, 8, 1206, 1208), + (1208, 749, 749, 749, 749, 5, 70, 5873, 11, 1800, 8, 1207, 17298), + (1209, 1209, -1, 1209, 1209, 12, 70, 5912, 14, 4320, 8, -1, -1), + (1210, -1, -1, 1210, 1210, 3, 66, -1, 0, 0, 8, -1, 1211), + (1211, -1, -1, 1210, 1210, 6, 68, -1, 0, 0, 8, 1210, 1212), + (1212, -1, -1, 1210, 1210, 9, 70, -1, 0, 0, 8, 1211, 1483), + (1213, -1, -1, 1210, 1213, 3, 66, -1, 0, 0, 8, -1, 1214), + (1214, -1, -1, 1210, 1213, 6, 68, -1, 0, 0, 8, 1213, 1215), + (1215, -1, -1, 1210, 1213, 9, 70, -1, 0, 0, 8, 1214, 4755), + (1216, -1, -1, 83, 83, 3, 81, -1, 0, 0, 16, -1, 1217), + (1217, -1, -1, 83, 83, 6, 81, -1, 0, 0, 16, 1216, 1218), + (1218, -1, -1, 83, 83, 9, 81, -1, 0, 0, 16, 1217, 15422), + (1219, -1, -1, 1435, 1435, 10, 71, -1, 0, 0, 16, -1, 1220), + (1220, -1, -1, 1435, 1435, 11, 71, -1, 0, 0, 16, 1219, 1221), + (1221, -1, -1, 1435, 1435, 12, 71, -1, 0, 0, 16, 1220, 1648), + (1222, 757, -1, 757, 1222, 5, 66, 5877, 6, 1800, 8, 761, 1223), + (1223, 757, -1, 757, 1222, 5, 68, 5878, 6, 1800, 8, 1222, 1224), + (1224, 757, -1, 757, 1222, 5, 70, 5879, 6, 1800, 8, 1223, 5051), + (1225, 548, 548, 548, 548, 5, 67, 5881, 5, 900, 8, 550, 1226), + (1226, 548, 548, 548, 548, 5, 68, 5882, 5, 900, 8, 1225, 1227), + (1227, 548, 548, 548, 548, 5, 69, 5883, 5, 900, 8, 1226, 5054), + (1228, 1228, 1228, 1228, 1228, 9, 70, 5880, 9, 600, 8, -1, -1), + (1229, 1229, 1229, 1229, 1229, 7, 66, 6094, 10, 600, 8, -1, -1), + (1230, -1, -1, 1230, 1230, 1, 51, -1, 0, 0, 8, -1, 1231), + (1231, -1, -1, 1230, 1230, 2, 53, -1, 0, 0, 8, 1230, 1232), + (1232, -1, -1, 1230, 1230, 3, 55, -1, 0, 0, 8, 1231, 5000), + (1233, 1233, -1, 1233, 1233, 3, 68, 5887, 7, 2160, 8, -1, 1234), + (1234, 1233, -1, 1233, 1233, 6, 69, 5888, 7, 2160, 8, 1233, 1235), + (1235, 1233, -1, 1233, 1233, 9, 70, 5889, 7, 2160, 8, 1234, -1), + (1239, 1239, 1239, 1239, 1239, 12, 70, 5903, 6, 600, 8, -1, 5868), + (1242, 1242, 1242, 1242, 1242, 3, 67, 5906, 9, 1320, 8, -1, 1243), + (1243, 1242, 1242, 1242, 1242, 6, 68, 5907, 9, 1320, 8, 1242, 1244), + (1244, 1242, 1242, 1242, 1242, 9, 69, 5908, 9, 1320, 8, 1243, 5857), + (1245, 1245, 1245, 1245, 1245, 3, 66, 5909, 8, 2160, 8, -1, 1246), + (1246, 1245, 1245, 1245, 1245, 6, 68, 5910, 8, 2160, 8, 1245, 1247), + (1247, 1245, 1245, 1245, 1245, 9, 70, 5911, 8, 2160, 8, 1246, 15459), + (1248, 616, 616, 616, 616, 3, 68, 6226, 7, 900, 8, 618, 1249), + (1249, 616, 616, 616, 616, 6, 69, 6227, 7, 900, 8, 1248, 1250), + (1250, 616, 616, 616, 616, 9, 70, 6228, 7, 900, 8, 1249, 6254), + (1251, 1251, 1251, 1251, 1251, 9, 70, 5915, 9, 1320, 8, -1, -1), + (1252, 1252, 1252, 1252, 1252, 9, 68, 5913, 9, 1320, 8, -1, -1), + (1253, 1253, 1253, 1253, 1253, 9, 67, 5916, 16, 1320, 8, -1, -1), + (1254, 1254, 1254, 1254, 1254, 9, 69, 5914, 16, 1320, 8, -1, -1), + (1255, 1255, 1255, 1255, 1255, 9, 70, 5918, 4, 1080, 8, -1, -1), + (1265, -1, -1, 820, 820, 5, 66, -1, 0, 0, 8, 822, 1266), + (1266, -1, -1, 820, 820, 5, 68, -1, 0, 0, 8, 1265, 1267), + (1267, -1, -1, 820, 820, 5, 70, -1, 0, 0, 8, 1266, 4813), + (1268, -1, -1, 807, 807, 5, 66, -1, 0, 0, 8, 809, 1269), + (1269, -1, -1, 807, 807, 5, 68, -1, 0, 0, 8, 1268, 1270), + (1270, -1, -1, 807, 807, 5, 70, -1, 0, 0, 8, 1269, 5922), + (1272, 209, 209, 209, 1272, 5, 66, 5919, 12, 5, 8, -1, 6378), + (1274, 1274, 1274, 1274, 1274, 3, 68, 5921, 9, 540, 8, -1, 1275), + (1275, 1274, 1274, 1274, 1274, 6, 69, 5922, 9, 540, 8, 1274, 1276), + (1276, 1274, 1274, 1274, 1274, 9, 70, 5923, 9, 540, 8, 1275, 4864), + (1277, 188, 188, 188, 188, 9, 68, 5924, 2, 30, 8, 188, 5044), + (1278, 534, 534, 534, 534, 5, 67, 5927, 4, 2160, 8, 717, 1279), + (1279, 534, 534, 534, 534, 5, 68, 5928, 4, 2160, 8, 1278, 1280), + (1280, 534, 534, 534, 534, 5, 69, 5929, 4, 2160, 8, 1279, 5041), + (1284, -1, -1, 1284, 1284, 3, 66, -1, 0, 0, 8, -1, 1285), + (1285, -1, -1, 1284, 1284, 6, 68, -1, 0, 0, 8, 1284, 1286), + (1286, -1, -1, 1284, 1284, 9, 70, -1, 0, 0, 8, 1285, 5035), + (1287, -1, -1, 1287, 1287, 3, 67, -1, 0, 0, 8, -1, 1288), + (1288, -1, -1, 1287, 1287, 6, 68, -1, 0, 0, 8, 1287, 1289), + (1289, -1, -1, 1287, 1287, 9, 69, -1, 0, 0, 8, 1288, 5516), + (1290, -1, -1, 864, 864, 3, 66, -1, 0, 0, 8, 866, 1291), + (1291, -1, -1, 864, 864, 6, 68, -1, 0, 0, 8, 1290, 1292), + (1292, -1, -1, 864, 864, 9, 70, -1, 0, 0, 8, 1291, 4983), + (1293, 545, 545, 545, 545, 3, 68, 6079, 3, 900, 8, 547, 1294), + (1294, 545, 545, 545, 545, 6, 69, 6080, 3, 900, 8, 1293, 1295), + (1295, 545, 545, 545, 545, 9, 70, 6081, 3, 900, 8, 1294, 4997), + (1296, -1, -1, 1296, 1296, 3, 66, -1, 0, 0, 8, -1, 1297), + (1297, -1, -1, 1296, 1296, 3, 67, -1, 0, 0, 8, 1296, 1298), + (1298, -1, -1, 1296, 1296, 3, 68, -1, 0, 0, 8, 1297, 1299), + (1299, -1, -1, 1296, 1296, 3, 69, -1, 0, 0, 8, 1298, 1300), + (1300, -1, -1, 1296, 1296, 3, 70, -1, 0, 0, 8, 1299, -1), + (1301, -1, -1, 846, 846, 3, 66, -1, 0, 0, 8, 848, 1302), + (1302, -1, -1, 846, 846, 6, 68, -1, 0, 0, 8, 1301, 1303), + (1303, -1, -1, 846, 846, 9, 70, -1, 0, 0, 8, 1302, 4948), + (1304, -1, -1, 1304, 1304, 3, 66, -1, 0, 0, 8, -1, 1305), + (1305, -1, -1, 1304, 1304, 6, 68, -1, 0, 0, 8, 1304, 1306), + (1306, -1, -1, 1304, 1304, 9, 70, -1, 0, 0, 8, 1305, 6029), + (1307, -1, -1, 1307, 1307, 5, 66, -1, 0, 0, 8, -1, 1308), + (1308, -1, -1, 1307, 1307, 5, 67, -1, 0, 0, 8, 1307, 1309), + (1309, -1, -1, 1307, 1307, 5, 68, -1, 0, 0, 8, 1308, 1310), + (1310, -1, -1, 1307, 1307, 5, 69, -1, 0, 0, 8, 1309, 1311), + (1311, -1, -1, 1307, 1307, 5, 70, -1, 0, 0, 8, 1310, 6660), + (1313, -1, -1, 1313, 1313, 3, 68, -1, 0, 0, 8, -1, 1314), + (1314, -1, -1, 1313, 1313, 6, 69, -1, 0, 0, 8, 1313, 1315), + (1315, -1, -1, 1313, 1313, 9, 70, -1, 0, 0, 8, 1314, 5029), + (1316, -1, -1, 210, 210, 5, 67, -1, 0, 0, 8, 212, 1317), + (1317, -1, -1, 210, 210, 5, 68, -1, 0, 0, 8, 1316, 1318), + (1318, -1, -1, 210, 210, 5, 69, -1, 0, 0, 8, 1317, 6072), + (1319, -1, -1, 634, 634, 5, 67, -1, 0, 0, 8, 845, 1320), + (1320, -1, -1, 634, 634, 5, 68, -1, 0, 0, 8, 1319, 1321), + (1321, -1, -1, 634, 634, 5, 69, -1, 0, 0, 8, 1320, 5032), + (1323, 1323, 1323, 1323, 1323, 12, 70, 5932, 7, 2160, 8, -1, -1), + (1324, 970, 970, 970, 970, 5, 66, 6030, 6, 1800, 8, 974, 1325), + (1325, 970, 970, 970, 970, 5, 68, 6031, 6, 1800, 8, 1324, 1326), + (1326, 970, 970, 970, 970, 5, 70, 6032, 6, 1800, 8, 1325, 17311), + (1327, 1327, 1327, 1327, 1327, 5, 67, 5933, 10, 900, 8, -1, 1328), + (1328, 1327, 1327, 1327, 1327, 5, 68, 5934, 10, 900, 8, 1327, 1329), + (1329, 1327, 1327, 1327, 1327, 5, 69, 5935, 10, 900, 8, 1328, 5314), + (1330, 912, 912, 912, 912, 3, 66, 5936, 4, 3600, 8, 914, 1331), + (1331, 912, 912, 912, 912, 6, 68, 5937, 4, 3600, 8, 1330, 1332), + (1332, 912, 912, 912, 912, 9, 70, 5938, 4, 3600, 8, 1331, 7119), + (1334, 1334, 1334, 1334, 1334, 3, 66, 5943, 11, 4320, 8, -1, 1335), + (1335, 1334, 1334, 1334, 1334, 6, 68, 5944, 11, 4320, 8, 1334, 1336), + (1336, 1334, 1334, 1334, 1334, 9, 70, 5945, 11, 4320, 8, 1335, 6152), + (1337, 1337, 1337, 1337, 1337, 5, 67, 5946, 13, 4320, 8, -1, 1338), + (1338, 1337, 1337, 1337, 1337, 5, 68, 5947, 13, 4320, 8, 1337, 1339), + (1339, 1337, 1337, 1337, 1337, 5, 69, 5948, 13, 4320, 8, 1338, 6158), + (1340, 921, 921, 921, 921, 12, 69, 5950, 8, 60, 8, 921, 5280), + (1341, 922, 922, 922, 922, 12, 68, 5951, 8, 60, 8, 922, 5281), + (1342, 923, 923, 923, 923, 12, 67, 5952, 8, 60, 8, 923, 5282), + (1343, 1343, 1343, 1343, 1343, 9, 69, 5953, 9, 300, 8, -1, -1), + (1344, 155, 155, 155, 155, 12, 70, 5949, 8, 60, 8, 533, 5279), + (1345, 1345, 1345, 1345, 1345, 5, 67, 6132, 6, 900, 8, -1, 1346), + (1346, 1345, 1345, 1345, 1345, 5, 68, 6133, 6, 900, 8, 1345, 1347), + (1347, 1345, 1345, 1345, 1345, 5, 69, 6134, 6, 900, 8, 1346, 5003), + (1348, 1348, 1348, 1348, 1348, 3, 68, 6090, 0, 3600, 8, -1, 1349), + (1349, 1348, 1348, 1348, 1348, 6, 69, 6091, 0, 3600, 8, 1348, 1350), + (1350, 1348, 1348, 1348, 1348, 9, 70, 6092, 0, 3600, 8, 1349, 5770), + (1351, 1351, 1351, 1351, 1351, 5, 67, 5939, 5, 30, 8, -1, 6133), + (1352, 1352, 1352, 1352, 1352, 3, 67, 6067, 3, 60, 8, -1, 1353), + (1353, 1352, 1352, 1352, 1352, 6, 68, 6068, 3, 60, 8, 1352, 1354), + (1354, 1352, 1352, 1352, 1352, 9, 69, 6069, 3, 60, 8, 1353, 6313), + (1355, 1355, 1355, 1355, 1355, 3, 68, 6070, 3, 60, 8, -1, 1356), + (1356, 1355, 1355, 1355, 1355, 6, 69, 6071, 3, 60, 8, 1355, 1357), + (1357, 1355, 1355, 1355, 1355, 9, 70, 6072, 3, 60, 8, 1356, 5240), + (1358, 1358, 1358, 1358, 1358, 3, 66, 6073, 3, 60, 8, -1, 1359), + (1359, 1358, 1358, 1358, 1358, 6, 67, 6074, 3, 60, 8, 1358, 1360), + (1360, 1358, 1358, 1358, 1358, 9, 68, 6075, 3, 60, 8, 1359, 6307), + (1361, -1, -1, 1361, 1361, 0, 65, -1, 0, 0, 3, -1, -1), + (1362, -1, -1, 1362, 1362, 0, 65, -1, 0, 0, 3, -1, -1), + (1363, -1, -1, 1363, 1363, 0, 68, -1, 0, 0, 3, -1, -1), + (1364, -1, -1, 1364, 1364, 0, 68, -1, 0, 0, 3, -1, -1), + (1365, -1, -1, 1365, 1365, 0, 68, -1, 0, 0, 3, -1, -1), + (1366, -1, -1, 1366, 1366, 0, 65, -1, 0, 0, 3, -1, -1), + (1367, -1, -1, 1367, 1367, 0, 65, -1, 0, 0, 3, -1, -1), + (1368, -1, -1, 1368, 1368, 0, 68, -1, 0, 0, 3, -1, -1), + (1369, -1, -1, 1369, 1369, 0, 68, -1, 0, 0, 3, -1, -1), + (1370, -1, -1, 1370, 1370, 0, 68, -1, 0, 0, 3, -1, -1), + (1371, 1371, 1371, 1371, 1371, 0, 1, 6880, 23, 72000, 0, -1, -1), + (1372, 1372, 1372, 1372, 1372, 0, 1, 6881, 24, 72000, 0, -1, -1), + (1373, 1373, 1373, 1373, 1373, 0, 1, 6882, 25, 72000, 0, -1, -1), + (1374, 1374, 1374, 1374, 1374, 0, 1, 6883, 26, 590400, 0, -1, -1), + (1375, 1375, 1375, 1375, 1375, 0, 1, 6884, 27, 72000, 0, -1, -1), + (1376, 1376, 1376, 1376, 1376, 0, 1, 6885, 28, 244800, 0, -1, -1), + (1377, 1377, 1377, 1377, 1377, 0, 1, 6886, 29, 14400, 0, -1, -1), + (1378, -1, -1, 1378, 1378, 0, 1, -1, 0, 0, 10, -1, 1379), + (1379, -1, -1, 1379, 1379, 0, 1, -1, 0, 0, 10, 1378, 1380), + (1380, -1, -1, 1380, 1380, 0, 1, -1, 0, 0, 10, 1379, 1381), + (1382, -1, -1, 1382, 1382, 0, 1, -1, 0, 0, 10, 1381, -1), + (1383, 1383, 1383, 1383, 1383, 3, 59, 8048, 6, 300, 3, -1, 1384), + (1384, 1383, 1383, 1383, 1383, 6, 59, 8049, 6, 300, 3, 1383, 1385), + (1385, 1383, 1383, 1383, 1383, 9, 59, 8050, 6, 300, 3, 1384, 1386), + (1386, 1383, 1383, 1383, 1383, 9, 65, 8052, 6, 300, 4, 1385, 1387), + (1387, 1383, 1383, 1383, 1383, 9, 70, 8053, 6, 300, 10, 1386, 5084), + (1388, -1, -1, 1388, 1388, 9, 70, -1, 0, 0, 10, -1, -1), + (1389, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1030, 1390), + (1390, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1389, 1391), + (1391, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1390, 1392), + (1392, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1391, 1393), + (1393, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1392, 4683), + (1394, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1065, 1395), + (1395, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1394, 1396), + (1396, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1395, 1397), + (1397, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1396, 1398), + (1398, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1397, 5519), + (1399, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1070, 1400), + (1400, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1399, 1401), + (1401, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1400, 1402), + (1402, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1401, 1403), + (1403, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1402, 5524), + (1404, 1404, 1404, 1404, 1404, 5, 66, 8054, 15, 2160, 10, -1, 1405), + (1405, 1404, 1404, 1404, 1404, 5, 67, 8055, 15, 2160, 10, 1404, 1406), + (1406, 1404, 1404, 1404, 1404, 5, 68, 8056, 15, 2160, 10, 1405, 1407), + (1407, 1404, 1404, 1404, 1404, 5, 69, 8057, 15, 2160, 10, 1406, 1408), + (1408, 1404, 1404, 1404, 1404, 5, 70, 8058, 15, 2160, 10, 1407, 12880), + (1409, 1409, 1409, 1409, 1409, 5, 66, 8054, 15, 2160, 10, -1, 1410), + (1410, 1409, 1409, 1409, 1409, 5, 67, 8055, 15, 2160, 10, 1409, 1411), + (1411, 1409, 1409, 1409, 1409, 5, 68, 8056, 15, 2160, 10, 1410, 1412), + (1412, 1409, 1409, 1409, 1409, 5, 69, 8057, 15, 2160, 10, 1411, 1413), + (1413, 1409, 1409, 1409, 1409, 5, 70, 8058, 15, 2160, 10, 1412, -1), + (1414, -1, -1, 1414, 1414, 5, 66, -1, 0, 0, 10, -1, 1415), + (1415, -1, -1, 1414, 1414, 5, 67, -1, 0, 0, 10, 1414, 1416), + (1416, -1, -1, 1414, 1414, 5, 68, -1, 0, 0, 10, 1415, 1417), + (1417, -1, -1, 1414, 1414, 5, 69, -1, 0, 0, 10, 1416, 1418), + (1418, -1, -1, 1414, 1414, 5, 70, -1, 0, 0, 10, 1417, 12874), + (1419, 1419, 1419, 1419, 1419, 9, 74, 16441, 52, 300, 15, -1, -1), + (1420, -1, -1, 1420, 1420, 3, 66, -1, 0, 0, 10, -1, 1421), + (1421, -1, -1, 1420, 1420, 3, 67, -1, 0, 0, 10, 1420, 1422), + (1422, -1, -1, 1420, 1420, 3, 68, -1, 0, 0, 10, 1421, 1423), + (1423, -1, -1, 1420, 1420, 3, 69, -1, 0, 0, 10, 1422, 1424), + (1424, -1, -1, 1420, 1420, 3, 70, -1, 0, 0, 10, 1423, -1), + (1425, 1425, 1425, 1425, 1425, 5, 70, 8060, 2, 2160, 10, -1, 1426), + (1426, 1425, 1425, 1425, 1425, 5, 70, 8061, 2, 2160, 10, 1425, 1427), + (1427, 1425, 1425, 1425, 1425, 5, 70, 8063, 2, 2160, 10, 1426, 1428), + (1428, 1425, 1425, 1425, 1425, 5, 70, 8066, 2, 2160, 10, 1427, 1429), + (1429, 1425, 1425, 1425, 1425, 5, 70, 8070, 2, 2160, 10, 1428, 5759), + (1430, -1, -1, 795, 795, 3, 70, -1, 0, 0, 10, 799, 1431), + (1431, -1, -1, 795, 795, 6, 70, -1, 0, 0, 10, 1430, 1432), + (1432, -1, -1, 795, 795, 9, 70, -1, 0, 0, 10, 1431, 4897), + (1435, -1, -1, 1435, 1435, 3, 66, -1, 0, 0, 10, -1, 1436), + (1436, -1, -1, 1435, 1435, 6, 68, -1, 0, 0, 10, 1435, 1437), + (1437, -1, -1, 1435, 1435, 9, 70, -1, 0, 0, 10, 1436, 4773), + (1440, 517, 517, 517, 517, 5, 66, 8109, 12, 600, 10, 519, 1441), + (1441, 517, 517, 517, 517, 5, 67, 8110, 12, 600, 10, 1440, 1442), + (1442, 517, 517, 517, 517, 5, 68, 8111, 12, 600, 10, 1441, 1443), + (1443, 517, 517, 517, 517, 5, 69, 8112, 12, 600, 10, 1442, 1444), + (1444, 517, 517, 517, 517, 5, 70, 8113, 12, 600, 10, 1443, 7296), + (1453, -1, -1, 1453, 1453, 5, 66, -1, 0, 0, 10, -1, 1454), + (1454, -1, -1, 1453, 1453, 5, 67, -1, 0, 0, 10, 1453, 1455), + (1455, -1, -1, 1453, 1453, 5, 68, -1, 0, 0, 10, 1454, 1456), + (1456, -1, -1, 1453, 1453, 5, 69, -1, 0, 0, 10, 1455, 1457), + (1457, -1, -1, 1453, 1453, 5, 70, -1, 0, 0, 10, 1456, -1), + (1458, 1458, 1458, 1458, 1458, 12, 70, 8124, 6, 4320, 10, -1, -1), + (1459, 1459, 1459, 1459, 1459, 7, 70, 8125, 11, 1800, 10, -1, 1460), + (1460, 1459, 1459, 1459, 1459, 7, 70, 8126, 11, 1800, 10, 1459, 1461), + (1461, 1459, 1459, 1459, 1459, 7, 70, 8127, 11, 1800, 10, 1460, 5080), + (1462, 1462, 1462, 1462, 1462, 3, 59, 8133, 5, 300, 3, -1, 1463), + (1463, 1462, 1462, 1462, 1462, 6, 59, 8134, 5, 300, 3, 1462, 1464), + (1464, 1462, 1462, 1462, 1462, 9, 59, 8135, 5, 300, 3, 1463, 1465), + (1465, 1462, 1462, 1462, 1462, 9, 65, 8137, 5, 300, 4, 1464, 1466), + (1466, 1462, 1462, 1462, 1462, 9, 70, 8138, 5, 300, 10, 1465, 4900), + (1467, -1, -1, 729, 729, 3, 70, -1, 0, 0, 10, 733, 1468), + (1468, -1, -1, 729, 729, 6, 70, -1, 0, 0, 10, 1467, 1469), + (1469, -1, -1, 729, 729, 9, 70, -1, 0, 0, 10, 1468, 4960), + (1471, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, -1, 1472), + (1472, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, 1471, 1473), + (1473, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, 1472, 1474), + (1474, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, 1473, 1475), + (1475, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, 1474, 6442), + (1477, 1477, 1477, 1477, 1477, 9, 70, 8149, 3, 4320, 10, -1, -1), + (1478, 1478, -1, 1478, 1478, 3, 66, 8406, 0, 1, 10, -1, 1479), + (1479, 1478, -1, 1478, 1478, 6, 68, 8407, 0, 1, 10, 1478, 1480), + (1480, 1478, -1, 1478, 1478, 9, 70, 8408, 0, 1, 10, 1479, 6161), + (1483, -1, -1, 1210, 1210, 7, 70, -1, 0, 0, 10, 1212, 1484), + (1484, -1, -1, 1210, 1210, 7, 70, -1, 0, 0, 10, 1483, 1485), + (1485, -1, -1, 1210, 1210, 7, 70, -1, 0, 0, 10, 1484, 4752), + (1486, -1, -1, 1486, 1486, 5, 66, -1, 0, 0, 10, -1, 1487), + (1487, -1, -1, 1486, 1486, 5, 67, -1, 0, 0, 10, 1486, 1488), + (1488, -1, -1, 1486, 1486, 5, 68, -1, 0, 0, 10, 1487, 1489), + (1489, -1, -1, 1486, 1486, 5, 69, -1, 0, 0, 10, 1488, 1490), + (1490, -1, -1, 1486, 1486, 5, 70, -1, 0, 0, 10, 1489, 5529), + (1491, 746, 746, 746, 746, 3, 70, 8156, 10, 2160, 10, 748, 1492), + (1492, 746, 746, 746, 746, 6, 70, 8157, 10, 2160, 10, 1491, 1493), + (1493, 746, 746, 746, 746, 9, 70, 8158, 10, 2160, 10, 1492, 5800), + (1494, 1494, 1494, 1494, 1494, 12, 70, 8170, 2, 7, 10, -1, -1), + (1495, 1495, 1495, 1495, 1495, 3, 70, 8190, 30, 900, 10, -1, 1496), + (1496, 1495, 1495, 1495, 1495, 6, 70, 8191, 30, 900, 10, 1495, 1497), + (1497, 1495, 1495, 1495, 1495, 9, 70, 8192, 30, 900, 10, 1496, 5311), + (1498, 1498, 1498, 1498, 1498, 3, 70, 8193, 12, 1320, 10, -1, 1499), + (1499, 1498, 1498, 1498, 1498, 6, 70, 8194, 12, 1320, 10, 1498, 1500), + (1500, 1498, 1498, 1498, 1498, 9, 70, 8195, 12, 1320, 10, 1499, 5058), + (1501, 1501, 1501, 1501, 1501, 3, 70, 8196, 10, 4320, 10, -1, 1502), + (1502, 1501, 1501, 1501, 1501, 6, 70, 8197, 10, 4320, 10, 1501, 1503), + (1503, 1501, 1501, 1501, 1501, 9, 70, 8198, 10, 4320, 10, 1502, 1558), + (1504, -1, -1, 1504, 1504, 5, 70, -1, 0, 0, 10, -1, 1505), + (1505, -1, -1, 1504, 1504, 5, 70, -1, 0, 0, 10, 1504, 1506), + (1506, -1, -1, 1504, 1504, 5, 70, -1, 0, 0, 10, 1505, 5880), + (1507, 520, 520, 520, 520, 3, 70, 8201, 6, 540, 10, 522, 1508), + (1508, 520, 520, 520, 520, 6, 70, 8202, 6, 540, 10, 1507, 1509), + (1509, 520, 520, 520, 520, 9, 70, 8203, 6, 540, 10, 1508, 5883), + (1510, 1510, -1, 1510, 1510, 12, 70, 8205, 13, 2160, 10, -1, 7202), + (1511, -1, -1, 1511, 1511, 5, 70, -1, 0, 0, 10, -1, 1512), + (1512, -1, -1, 1511, 1511, 5, 70, -1, 0, 0, 10, 1511, 1513), + (1513, -1, -1, 1511, 1511, 5, 70, -1, 0, 0, 10, 1512, 5950), + (1514, -1, -1, 1514, 1514, 7, 70, -1, 0, 0, 10, -1, 1515), + (1515, -1, -1, 1514, 1514, 7, 70, -1, 0, 0, 10, 1514, 1516), + (1516, -1, -1, 1514, 1514, 7, 70, -1, 0, 0, 10, 1515, 13404), + (1519, 153, 153, 153, 153, 9, 70, 8216, 3, 2160, 10, 153, 5068), + (1520, 1520, 1520, 1520, 1520, 3, 70, 8218, 11, 900, 10, -1, 1521), + (1521, 1520, 1520, 1520, 1520, 6, 70, 8219, 11, 900, 10, 1520, 1522), + (1522, 1520, 1520, 1520, 1520, 9, 70, 8220, 11, 900, 10, 1521, 6449), + (1523, 1523, 1523, 1523, 1523, 12, 70, 8221, 7, 7, 10, -1, -1), + (1524, -1, -1, 190, 190, 7, 70, -1, 0, 0, 10, 192, 1526), + (1525, -1, -1, 190, 190, 7, 70, -1, 0, 0, 10, 1526, 5038), + (1526, -1, -1, 190, 190, 7, 70, -1, 0, 0, 10, 1524, 1525), + (1527, 1527, 1527, 1527, 1527, 12, 70, 8223, 3, 7, 10, -1, -1), + (1528, -1, -1, 1528, 4819, 5, 66, -1, 0, 0, 10, -1, 1529), + (1529, -1, -1, 1528, 4819, 5, 67, -1, 0, 0, 10, 1528, 1530), + (1530, -1, -1, 1528, 4819, 5, 68, -1, 0, 0, 10, 1529, 1531), + (1531, -1, -1, 1528, 4819, 5, 69, -1, 0, 0, 10, 1530, 1532), + (1532, -1, -1, 1528, 4819, 5, 70, -1, 0, 0, 10, 1531, 4819), + (1533, -1, -1, 602, 602, 3, 70, -1, 0, 0, 10, 604, 1534), + (1534, -1, -1, 602, 602, 6, 70, -1, 0, 0, 10, 1533, 1535), + (1535, -1, -1, 602, 602, 9, 70, -1, 0, 0, 10, 1534, 4758), + (1536, -1, -1, 599, 599, 3, 70, -1, 0, 0, 10, 601, 1537), + (1537, -1, -1, 599, 599, 6, 70, -1, 0, 0, 10, 1536, 1538), + (1538, -1, -1, 599, 599, 9, 70, -1, 0, 0, 10, 1537, 5534), + (1539, -1, -1, 878, 878, 7, 70, -1, 0, 0, 10, 880, 1540), + (1540, -1, -1, 878, 878, 7, 70, -1, 0, 0, 10, 1539, 1541), + (1541, -1, -1, 878, 878, 7, 70, -1, 0, 0, 10, 1540, 4957), + (1542, 1542, -1, 1542, 1542, 3, 60, 8240, 0, 1, 10, -1, -1), + (1543, -1, -1, 1543, 1543, 5, 70, -1, 0, 0, 10, -1, 1544), + (1544, -1, -1, 1543, 1543, 5, 70, -1, 0, 0, 10, 1543, 1545), + (1545, -1, -1, 1543, 1543, 5, 70, -1, 0, 0, 10, 1544, 4951), + (1546, -1, -1, 1546, 1546, 5, 70, -1, 0, 0, 10, -1, 1547), + (1547, -1, -1, 1546, 1546, 5, 70, -1, 0, 0, 10, 1546, 1548), + (1548, -1, -1, 1546, 1546, 5, 70, -1, 0, 0, 10, 1547, 4829), + (1549, -1, -1, 1549, 1549, 3, 66, -1, 0, 0, 10, -1, 1550), + (1550, -1, -1, 1549, 1549, 6, 68, -1, 0, 0, 10, 1549, 1551), + (1551, -1, -1, 1549, 1549, 9, 70, -1, 0, 0, 10, 1550, -1), + (1552, -1, -1, 1552, 1552, 3, 66, -1, 0, 0, 10, -1, 1553), + (1553, -1, -1, 1552, 1552, 6, 68, -1, 0, 0, 10, 1552, 1554), + (1554, -1, -1, 1552, 1552, 9, 70, -1, 0, 0, 10, 1553, -1), + (1555, -1, -1, 1555, 1555, 5, 70, -1, 0, 0, 10, -1, 1556), + (1556, -1, -1, 1555, 1555, 5, 70, -1, 0, 0, 10, 1555, 1557), + (1557, -1, -1, 1555, 1555, 5, 70, -1, 0, 0, 10, 1556, 12727), + (1558, 1501, 1501, 1501, 1501, 6, 75, 16444, 10, 4320, 15, 1503, 1559), + (1559, 1501, 1501, 1501, 1501, 6, 80, 16445, 10, 4320, 15, 1558, 1560), + (1560, 1501, 1501, 1501, 1501, 6, 85, 16446, 10, 4320, 15, 1559, 13244), + (1563, -1, -1, 556, 556, 5, 66, -1, 0, 0, 10, 560, 1564), + (1564, -1, -1, 556, 556, 5, 67, -1, 0, 0, 10, 1563, 1565), + (1565, -1, -1, 556, 556, 5, 68, -1, 0, 0, 10, 1564, 1566), + (1566, -1, -1, 556, 556, 5, 69, -1, 0, 0, 10, 1565, 1567), + (1567, -1, -1, 556, 556, 5, 70, -1, 0, 0, 10, 1566, 17004), + (1569, 1569, 1569, 1569, 1569, 3, 70, 8256, 5, 1800, 10, -1, 1570), + (1570, 1569, 1569, 1569, 1569, 6, 70, 8257, 5, 1800, 10, 1569, 1571), + (1571, 1569, 1569, 1569, 1569, 9, 70, 8258, 5, 1800, 10, 1570, 5713), + (1572, -1, -1, 1572, 1572, 5, 66, -1, 0, 0, 10, -1, 1573), + (1573, -1, -1, 1572, 1572, 5, 67, -1, 0, 0, 10, 1572, 1574), + (1574, -1, -1, 1572, 1572, 5, 68, -1, 0, 0, 10, 1573, 1575), + (1575, -1, -1, 1572, 1572, 5, 69, -1, 0, 0, 10, 1574, 1576), + (1576, -1, -1, 1572, 1572, 5, 70, -1, 0, 0, 10, 1575, 10554), + (1577, -1, -1, 1577, 1577, 3, 66, -1, 0, 0, 10, -1, 1578), + (1578, -1, -1, 1577, 1577, 6, 68, -1, 0, 0, 10, 1577, 1579), + (1579, -1, -1, 1577, 1577, 9, 70, -1, 0, 0, 10, 1578, 5886), + (1583, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, -1, 1584), + (1584, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, 1583, 1585), + (1585, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, 1584, 1586), + (1586, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, 1585, 1587), + (1587, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, 1586, -1), + (1588, -1, -1, 1587, 1587, 3, 66, -1, 0, 0, 10, -1, 1589), + (1589, -1, -1, 1587, 1587, 6, 68, -1, 0, 0, 10, 1588, 1590), + (1590, -1, -1, 1587, 1587, 9, 70, -1, 0, 0, 10, 1589, -1), + (1591, -1, -1, 1586, 1586, 12, 70, -1, 0, 0, 10, -1, -1), + (1592, -1, -1, 1592, 1592, 5, 66, -1, 0, 0, 10, -1, 1593), + (1593, -1, -1, 1592, 1592, 5, 67, -1, 0, 0, 10, 1592, 1594), + (1594, -1, -1, 1592, 1592, 5, 68, -1, 0, 0, 10, 1593, 1595), + (1595, -1, -1, 1592, 1592, 5, 69, -1, 0, 0, 10, 1594, 1596), + (1596, -1, -1, 1592, 1592, 5, 70, -1, 0, 0, 10, 1595, 4725), + (1597, 1597, 1597, 1597, 1597, 9, 70, 8271, 6, 10, 10, -1, 6606), + (1598, 1598, -1, 1598, 1598, 3, 70, 8272, 6, 900, 10, -1, 1599), + (1599, 1598, -1, 1598, 1598, 6, 70, 8273, 6, 900, 10, 1598, 1600), + (1600, 1598, -1, 1598, 1598, 9, 70, 8274, 6, 900, 10, 1599, 4972), + (1601, -1, -1, 644, 644, 5, 61, -1, 0, 0, 10, 644, 1602), + (1602, -1, -1, 644, 644, 5, 63, -1, 0, 0, 10, 1601, 1603), + (1603, -1, -1, 644, 644, 5, 65, -1, 0, 0, 10, 1602, 4986), + (1604, -1, -1, 1604, 1604, 5, 60, -1, 0, 0, 10, -1, 1605), + (1605, -1, -1, 1604, 1604, 5, 61, -1, 0, 0, 10, 1604, 1606), + (1606, -1, -1, 1604, 1604, 5, 62, -1, 0, 0, 10, 1605, 5290), + (1607, 289, 289, 289, 289, 9, 70, 8278, 3, 300, 10, 289, 5742), + (1608, -1, -1, 1608, 1608, 3, 66, -1, 0, 0, 10, -1, 1609), + (1609, -1, -1, 1608, 1608, 6, 68, -1, 0, 0, 10, 1608, 1610), + (1610, -1, -1, 1608, 1608, 9, 70, -1, 0, 0, 10, 1609, 4989), + (1611, -1, -1, 1417, 1417, 3, 66, -1, 0, 0, 10, -1, 1612), + (1612, -1, -1, 1417, 1417, 3, 67, -1, 0, 0, 10, 1611, 1613), + (1613, -1, -1, 1417, 1417, 3, 68, -1, 0, 0, 10, 1612, 1614), + (1614, -1, -1, 1417, 1417, 3, 69, -1, 0, 0, 10, 1613, 1615), + (1615, -1, -1, 1417, 1417, 3, 70, -1, 0, 0, 10, 1614, -1), + (1616, -1, -1, 1616, 1616, 5, 66, -1, 0, 0, 10, -1, 1617), + (1617, -1, -1, 1616, 1616, 5, 67, -1, 0, 0, 10, 1616, 1618), + (1618, -1, -1, 1616, 1616, 5, 68, -1, 0, 0, 10, 1617, 1619), + (1619, -1, -1, 1616, 1616, 5, 69, -1, 0, 0, 10, 1618, 1620), + (1620, -1, -1, 1616, 1616, 5, 70, -1, 0, 0, 10, 1619, 4992), + (1621, -1, -1, 564, 564, 7, 70, -1, 0, 0, 10, 566, 1622), + (1622, -1, -1, 564, 564, 7, 70, -1, 0, 0, 10, 1621, 1623), + (1623, -1, -1, 564, 564, 7, 70, -1, 0, 0, 10, 1622, -1), + (1624, -1, -1, 561, 561, 7, 70, -1, 0, 0, 10, 563, 1625), + (1625, -1, -1, 561, 561, 7, 70, -1, 0, 0, 10, 1624, 1626), + (1626, -1, -1, 561, 561, 7, 70, -1, 0, 0, 10, 1625, -1), + (1627, -1, -1, 1627, 1627, 3, 66, -1, 0, 0, 10, -1, 1628), + (1628, -1, -1, 1627, 1627, 6, 68, -1, 0, 0, 10, 1627, 1629), + (1629, -1, -1, 1627, 1627, 9, 70, -1, 0, 0, 10, 1628, -1), + (1630, 1474, 1474, 1474, 1474, 3, 70, 8146, 14, 300, 10, -1, 1631), + (1631, 1474, 1474, 1474, 1474, 6, 70, 8147, 14, 300, 10, 1630, 1632), + (1632, 1474, 1474, 1474, 1474, 9, 70, 8148, 14, 300, 10, 1631, -1), + (1633, -1, -1, 551, 551, 5, 66, -1, 0, 0, 10, 555, 1634), + (1634, -1, -1, 551, 551, 5, 67, -1, 0, 0, 10, 1633, 1635), + (1635, -1, -1, 551, 551, 5, 68, -1, 0, 0, 10, 1634, 1636), + (1636, -1, -1, 551, 551, 5, 69, -1, 0, 0, 10, 1635, 1637), + (1637, -1, -1, 551, 551, 5, 70, -1, 0, 0, 10, 1636, 6905), + (1638, 1638, 1638, 1638, 1638, 5, 59, 8450, 7, 4320, 3, -1, -1), + (1639, 1639, 1639, 1639, 1639, 9, 65, 8451, 7, 4320, 4, -1, -1), + (1640, 1640, 1640, 1640, 1640, 12, 70, 8452, 7, 4320, 10, -1, -1), + (1641, -1, -1, 1641, 1641, 15, 70, -1, 0, 0, 3, -1, -1), + (1642, -1, -1, 1642, 1642, 15, 70, -1, 0, 0, 3, -1, -1), + (1643, 1643, 1643, 1643, 1643, 0, 59, 8975, 0, 1, 11, -1, -1), + (1644, 1644, 1644, 1644, 1644, 0, 59, 8900, 0, 1, 11, -1, -1), + (1645, 1645, 1645, 1645, 1645, 9, 70, 8977, 0, 1, 3, -1, -1), + (1646, 1646, 1646, 1646, 1646, 9, 70, 8978, 0, 1, 3, -1, -1), + (1647, 1647, 1647, 1647, 1647, 0, 68, 8771, 21, 900, 3, -1, -1), + (1648, -1, -1, 1435, 4773, 9, 71, -1, 0, 0, 16, 1221, 1649), + (1649, -1, -1, 1435, 4773, 9, 76, -1, 0, 0, 16, 1648, 1650), + (1650, -1, -1, 1435, 4773, 9, 81, -1, 0, 0, 16, 1649, 13091), + (1651, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 8214, 1652), + (1652, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 1651, 1653), + (1653, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 1652, 1654), + (1654, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 1653, 1655), + (1655, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 1654, 13149), + (1656, -1, -1, 8204, 8204, 4, 85, -1, 0, 0, 16, 8206, 1657), + (1657, -1, -1, 8204, 8204, 4, 85, -1, 0, 0, 16, 1656, -1), + (1659, -1, -1, 8207, 8207, 4, 85, -1, 0, 0, 16, 8209, 1660), + (1660, -1, -1, 8207, 8207, 4, 85, -1, 0, 0, 16, 1659, -1), + (1662, -1, -1, 1662, 1662, 3, 65, -1, 0, 0, 17, -1, 1663), + (1663, -1, -1, 1662, 1662, 3, 66, -1, 0, 0, 17, 1662, 1664), + (1664, -1, -1, 1662, 1662, 3, 67, -1, 0, 0, 17, 1663, 1665), + (1665, -1, -1, 1662, 1662, 3, 68, -1, 0, 0, 17, 1664, 1666), + (1666, -1, -1, 1662, 1662, 3, 69, -1, 0, 0, 17, 1665, -1), + (1667, 1667, 1667, 1667, 1667, 9, 85, 23602, 0, 1, 16, -1, -1), + (2400, -1, -1, 2400, 2400, 9, 81, 0, 0, 0, 17, -1, 2401), + (2401, -1, -1, 2400, 2400, 12, 83, 0, 0, 0, 17, 2400, 2402), + (2402, -1, -1, 2400, 2400, 15, 85, 0, 0, 0, 17, 2401, 15344), + (3676, 3676, 3676, 3676, 3676, 9, 85, 23606, 67, 30, 16, -1, -1), + (4665, 4665, 4665, 4665, 4665, 0, 1, 9177, 19, 4320, 0, -1, -1), + (4666, -1, -1, 4844, 4844, 5, 81, -1, 0, 0, 16, -1, 4667), + (4667, -1, -1, 4844, 4844, 5, 82, -1, 0, 0, 16, 4666, 4668), + (4668, -1, -1, 4844, 4844, 5, 83, -1, 0, 0, 16, 4667, 4669), + (4669, -1, -1, 4844, 4844, 5, 84, -1, 0, 0, 16, 4668, 4670), + (4670, -1, -1, 4844, 4844, 5, 85, -1, 0, 0, 16, 4669, -1), + (4672, -1, -1, 4672, 4672, 3, 59, -1, 0, 0, 8, -1, 4673), + (4673, -1, -1, 4672, 4672, 6, 59, -1, 0, 0, 8, 4672, 4674), + (4674, -1, -1, 4672, 4672, 9, 59, -1, 0, 0, 8, 4673, -1), + (4675, -1, -1, 4675, 4675, 3, 59, -1, 0, 0, 3, -1, 4676), + (4676, -1, -1, 4675, 4675, 6, 59, -1, 0, 0, 3, 4675, 4677), + (4677, -1, -1, 4675, 4675, 9, 59, -1, 0, 0, 3, 4676, -1), + (4678, -1, -1, 418, 418, 5, 71, -1, 0, 0, 12, 1005, 4679), + (4679, -1, -1, 418, 418, 5, 72, -1, 0, 0, 12, 4678, 4680), + (4680, -1, -1, 418, 418, 5, 73, -1, 0, 0, 12, 4679, 4681), + (4681, -1, -1, 418, 418, 5, 74, -1, 0, 0, 12, 4680, 4682), + (4682, -1, -1, 418, 418, 5, 75, -1, 0, 0, 12, 4681, 7547), + (4683, -1, -1, 1026, 1026, 5, 71, -1, 0, 0, 12, 1393, 4684), + (4684, -1, -1, 1026, 1026, 5, 72, -1, 0, 0, 12, 4683, 4685), + (4685, -1, -1, 1026, 1026, 5, 73, -1, 0, 0, 12, 4684, 4686), + (4686, -1, -1, 1026, 1026, 5, 74, -1, 0, 0, 12, 4685, 4687), + (4687, -1, -1, 1026, 1026, 5, 75, -1, 0, 0, 12, 4686, 6523), + (4688, -1, -1, 4688, 4688, 3, 71, -1, 0, 0, 12, -1, 4689), + (4689, -1, -1, 4688, 4688, 3, 72, -1, 0, 0, 12, 4688, 4690), + (4690, -1, -1, 4688, 4688, 3, 73, -1, 0, 0, 12, 4689, 4691), + (4691, -1, -1, 4688, 4688, 3, 74, -1, 0, 0, 12, 4690, 4692), + (4692, -1, -1, 4688, 4688, 3, 75, -1, 0, 0, 12, 4691, -1), + (4693, -1, -1, 65, 661, 3, 71, -1, 0, 0, 12, 1035, 4694), + (4694, -1, -1, 65, 661, 3, 72, -1, 0, 0, 12, 4693, 4695), + (4695, -1, -1, 65, 661, 3, 73, -1, 0, 0, 12, 4694, 4696), + (4696, -1, -1, 65, 661, 3, 74, -1, 0, 0, 12, 4695, 4697), + (4697, -1, -1, 65, 661, 3, 75, -1, 0, 0, 12, 4696, 6390), + (4698, -1, -1, 4698, 4698, 5, 51, -1, 0, 0, 12, -1, 6545), + (4699, -1, -1, 4699, 4699, 5, 51, -1, 0, 0, 12, -1, 6540), + (4700, 1037, 1037, 1037, 1037, 0, 1, 7619, 33, 72000, 0, -1, -1), + (4702, 4702, 4702, 4702, 4702, 3, 71, 9475, 31, 600, 12, -1, -1), + (4704, 4704, 4704, 4704, 4704, 4, 71, 9477, 31, 600, 12, -1, -1), + (4705, 4705, 4705, 4705, 4705, 3, 71, 9478, 31, 600, 12, -1, -1), + (4706, 4706, 4706, 4706, 4706, 3, 71, 9479, 31, 600, 12, -1, -1), + (4707, -1, -1, 1041, 1041, 6, 71, -1, 0, 0, 12, 1043, 4708), + (4708, -1, -1, 1041, 1041, 6, 73, -1, 0, 0, 12, 4707, 4709), + (4709, -1, -1, 1041, 1041, 6, 75, -1, 0, 0, 12, 4708, 5542), + (4710, -1, -1, 1044, 1044, 6, 71, -1, 0, 0, 12, 1046, 4711), + (4711, -1, -1, 1044, 1044, 6, 73, -1, 0, 0, 12, 4710, 4712), + (4712, -1, -1, 1044, 1044, 6, 75, -1, 0, 0, 12, 4711, 5545), + (4713, -1, -1, 1047, 1047, 6, 71, -1, 0, 0, 12, 1049, 4714), + (4714, -1, -1, 1047, 1047, 6, 73, -1, 0, 0, 12, 4713, 4715), + (4715, -1, -1, 1047, 1047, 6, 75, -1, 0, 0, 12, 4714, 5548), + (4716, -1, -1, 1050, 1050, 6, 71, -1, 0, 0, 12, 1052, 4717), + (4717, -1, -1, 1050, 1050, 6, 73, -1, 0, 0, 12, 4716, 4718), + (4718, -1, -1, 1050, 1050, 6, 75, -1, 0, 0, 12, 4717, 5551), + (4722, -1, -1, 119, 119, 3, 71, -1, 0, 0, 12, 1055, 4723), + (4723, -1, -1, 119, 119, 3, 73, -1, 0, 0, 12, 4722, 4724), + (4724, -1, -1, 119, 119, 3, 75, -1, 0, 0, 12, 4723, 5554), + (4725, -1, -1, 1592, 1592, 5, 71, -1, 0, 0, 12, 1596, 4726), + (4726, -1, -1, 1592, 1592, 5, 72, -1, 0, 0, 12, 4725, 4727), + (4727, -1, -1, 1592, 1592, 5, 73, -1, 0, 0, 12, 4726, 4728), + (4728, -1, -1, 1592, 1592, 5, 74, -1, 0, 0, 12, 4727, 4729), + (4729, -1, -1, 1592, 1592, 5, 75, -1, 0, 0, 12, 4728, 5557), + (4733, -1, -1, 625, 625, 3, 71, -1, 0, 0, 12, 627, 4734), + (4734, -1, -1, 625, 625, 3, 73, -1, 0, 0, 12, 4733, 4735), + (4735, -1, -1, 625, 625, 3, 75, -1, 0, 0, 12, 4734, 7641), + (4739, -1, -1, 4739, 4739, 3, 71, -1, 0, 0, 12, -1, 4740), + (4740, -1, -1, 4739, 4739, 6, 73, -1, 0, 0, 12, 4739, 4741), + (4741, -1, -1, 4739, 4739, 9, 75, -1, 0, 0, 12, 4740, 5562), + (4742, 4742, 4742, 4742, 4742, 9, 71, 11024, 12, 600, 12, -1, 5565), + (4744, -1, -1, 1072, 1072, 5, 71, -1, 0, 0, 12, 1076, 4745), + (4745, -1, -1, 1072, 1072, 5, 72, -1, 0, 0, 12, 4744, 4746), + (4746, -1, -1, 1072, 1072, 5, 73, -1, 0, 0, 12, 4745, 4747), + (4747, -1, -1, 1072, 1072, 5, 74, -1, 0, 0, 12, 4746, 4748), + (4748, -1, -1, 1072, 1072, 5, 75, -1, 0, 0, 12, 4747, 5566), + (4749, -1, -1, 637, 637, 6, 71, -1, 0, 0, 12, 772, 4750), + (4750, -1, -1, 637, 637, 6, 73, -1, 0, 0, 12, 4749, 4751), + (4751, -1, -1, 637, 637, 6, 75, -1, 0, 0, 12, 4750, 5571), + (4752, -1, -1, 1210, 1210, 7, 71, -1, 0, 0, 12, 1485, 4753), + (4753, -1, -1, 1210, 1210, 7, 73, -1, 0, 0, 12, 4752, 4754), + (4754, -1, -1, 1210, 1210, 7, 75, -1, 0, 0, 12, 4753, 5574), + (4755, -1, -1, 1210, 1213, 6, 71, -1, 0, 0, 12, 1215, 4756), + (4756, -1, -1, 1210, 1213, 6, 73, -1, 0, 0, 12, 4755, 4757), + (4757, -1, -1, 1210, 1213, 6, 75, -1, 0, 0, 12, 4756, 5577), + (4758, -1, -1, 602, 602, 6, 71, -1, 0, 0, 12, 1535, 4759), + (4759, -1, -1, 602, 602, 6, 73, -1, 0, 0, 12, 4758, 4760), + (4760, -1, -1, 602, 602, 6, 75, -1, 0, 0, 12, 4759, 5580), + (4761, -1, -1, 4761, 4761, 7, 71, -1, 0, 0, 12, -1, 4762), + (4762, -1, -1, 4761, 4761, 7, 73, -1, 0, 0, 12, 4761, 4763), + (4763, -1, -1, 4761, 4761, 7, 75, -1, 0, 0, 12, 4762, 6500), + (4764, -1, -1, 1071, 1071, 6, 75, -1, 0, 0, 14, 1071, 7553), + (4767, -1, -1, 98, 98, 4, 71, -1, 0, 0, 12, 100, 4768), + (4768, -1, -1, 98, 98, 4, 73, -1, 0, 0, 12, 4767, 4769), + (4769, -1, -1, 98, 98, 4, 75, -1, 0, 0, 12, 4768, 5586), + (4773, -1, -1, 1435, 4773, 9, 71, -1, 0, 0, 12, 1437, 6517), + (4776, -1, -1, 1186, 1186, 6, 71, -1, 0, 0, 12, 1188, 4777), + (4777, -1, -1, 1186, 1186, 6, 73, -1, 0, 0, 12, 4776, 4778), + (4778, -1, -1, 1186, 1186, 6, 75, -1, 0, 0, 12, 4777, 5589), + (4779, -1, -1, 80, 80, 6, 71, -1, 0, 0, 12, 1088, 4780), + (4780, -1, -1, 80, 80, 6, 73, -1, 0, 0, 12, 4779, 4781), + (4781, -1, -1, 80, 80, 6, 75, -1, 0, 0, 12, 4780, 5592), + (4790, -1, -1, 1134, 1134, 5, 71, -1, 0, 0, 12, 1162, 4791), + (4791, -1, -1, 1134, 1134, 5, 72, -1, 0, 0, 12, 4790, 4792), + (4792, -1, -1, 1134, 1134, 5, 73, -1, 0, 0, 12, 4791, 4793), + (4793, -1, -1, 1134, 1134, 5, 74, -1, 0, 0, 12, 4792, 4794), + (4794, -1, -1, 1134, 1134, 5, 75, -1, 0, 0, 12, 4793, 4804), + (4795, -1, -1, 255, 255, 5, 71, -1, 0, 0, 12, 1165, 4796), + (4796, -1, -1, 255, 255, 5, 73, -1, 0, 0, 12, 4795, 4797), + (4797, -1, -1, 255, 255, 5, 75, -1, 0, 0, 12, 4796, 5595), + (4798, -1, -1, 631, 631, 5, 71, -1, 0, 0, 12, 1174, 4799), + (4799, -1, -1, 631, 631, 5, 73, -1, 0, 0, 12, 4798, 4800), + (4800, -1, -1, 631, 631, 5, 75, -1, 0, 0, 12, 4799, -1), + (4801, -1, -1, 4801, 4801, 6, 74, -1, 0, 0, 14, -1, 4802), + (4802, -1, -1, 4801, 4801, 6, 76, -1, 0, 0, 14, 4801, 4803), + (4803, -1, -1, 4801, 4801, 6, 78, -1, 0, 0, 14, 4802, 7160), + (4804, -1, -1, 1134, 1134, 5, 76, -1, 0, 0, 15, 4794, 4805), + (4805, -1, -1, 1134, 1134, 5, 77, -1, 0, 0, 15, 4804, 4806), + (4806, -1, -1, 1134, 1134, 5, 78, -1, 0, 0, 15, 4805, 4807), + (4807, -1, -1, 1134, 1134, 5, 79, -1, 0, 0, 15, 4806, 4808), + (4808, -1, -1, 1134, 1134, 5, 80, -1, 0, 0, 15, 4807, 10311), + (4809, -1, -1, 4809, 4809, 5, 81, -1, 0, 0, 15, -1, 4810), + (4810, -1, -1, 4809, 4809, 5, 83, -1, 0, 0, 15, 4809, 4811), + (4811, -1, -1, 4809, 4809, 5, 85, -1, 0, 0, 15, 4810, 10316), + (4813, -1, -1, 820, 820, 5, 71, -1, 0, 0, 12, 1267, 4814), + (4814, -1, -1, 820, 820, 5, 73, -1, 0, 0, 12, 4813, 4815), + (4815, -1, -1, 820, 820, 5, 75, -1, 0, 0, 12, 4814, 5917), + (4819, -1, -1, 1528, 4819, 5, 71, -1, 0, 0, 12, 1532, 4820), + (4820, -1, -1, 1528, 4819, 5, 72, -1, 0, 0, 12, 4819, 4821), + (4821, -1, -1, 1528, 4819, 5, 73, -1, 0, 0, 12, 4820, 4822), + (4822, -1, -1, 1528, 4819, 5, 74, -1, 0, 0, 12, 4821, 4823), + (4823, -1, -1, 1528, 4819, 5, 75, -1, 0, 0, 12, 4822, 15188), + (4824, -1, -1, 810, 810, 5, 71, -1, 0, 0, 12, 814, 4825), + (4825, -1, -1, 810, 810, 5, 72, -1, 0, 0, 12, 4824, 4826), + (4826, -1, -1, 810, 810, 5, 73, -1, 0, 0, 12, 4825, 4827), + (4827, -1, -1, 810, 810, 5, 74, -1, 0, 0, 12, 4826, 4828), + (4828, -1, -1, 810, 810, 5, 75, -1, 0, 0, 12, 4827, 15426), + (4829, -1, -1, 1546, 1546, 5, 71, -1, 0, 0, 12, 1548, 4830), + (4830, -1, -1, 1546, 1546, 5, 72, -1, 0, 0, 12, 4829, 4831), + (4831, -1, -1, 1546, 1546, 5, 73, -1, 0, 0, 12, 4830, 6441), + (4836, 4836, 4836, 4836, 4836, 5, 71, 11033, 5, 30, 12, -1, -1), + (4844, -1, -1, 4844, 4844, 5, 71, -1, 0, 0, 12, -1, 4845), + (4845, -1, -1, 4844, 4844, 5, 72, -1, 0, 0, 12, 4844, 4846), + (4846, -1, -1, 4844, 4844, 5, 73, -1, 0, 0, 12, 4845, 4847), + (4847, -1, -1, 4844, 4844, 5, 74, -1, 0, 0, 12, 4846, 4848), + (4848, -1, -1, 4844, 4844, 5, 75, -1, 0, 0, 12, 4847, 7122), + (4849, 4849, 4849, 4849, 4849, 9, 71, 11041, 7, 1800, 12, -1, 6134), + (4854, 4854, 4854, 4854, 4854, 3, 71, 11046, 8, 600, 12, -1, 4855), + (4855, 4854, 4854, 4854, 4854, 6, 73, 11047, 8, 600, 12, 4854, 4856), + (4856, 4854, 4854, 4854, 4854, 9, 75, 11048, 8, 600, 12, 4855, 5764), + (4857, 4857, 4857, 4857, 4857, 3, 71, 11049, 7, 600, 12, -1, 4858), + (4858, 4857, 4857, 4857, 4857, 6, 73, 11050, 7, 600, 12, 4857, 4859), + (4859, 4857, 4857, 4857, 4857, 9, 75, 11051, 7, 600, 12, 4858, 5767), + (4860, 4860, 4860, 4860, 4860, 9, 75, 11052, 13, 60, 12, -1, 5606), + (4861, -1, -1, 4861, 4861, 6, 71, -1, 0, 0, 12, -1, 4862), + (4862, -1, -1, 4861, 4861, 6, 73, -1, 0, 0, 12, 4861, 4863), + (4863, -1, -1, 4861, 4861, 6, 75, -1, 0, 0, 12, 4862, 5954), + (4864, 1274, 1274, 1274, 1274, 6, 73, 11053, 9, 540, 12, 1276, 4865), + (4865, 1274, 1274, 1274, 1274, 6, 74, 11054, 9, 540, 12, 4864, 4866), + (4866, 1274, 1274, 1274, 1274, 6, 75, 11055, 9, 540, 12, 4865, 5947), + (4887, -1, -1, 4887, 4887, 6, 71, -1, 0, 0, 12, -1, 4888), + (4888, -1, -1, 4887, 4887, 6, 73, -1, 0, 0, 12, 4887, 4889), + (4889, -1, -1, 4887, 4887, 6, 75, -1, 0, 0, 12, 4888, -1), + (4890, 4890, -1, 4890, 4890, 9, 75, 11056, 3, 8640, 12, -1, 5869), + (4894, 4894, 4894, 4894, 4894, 6, 73, 11057, 7, 2160, 12, -1, 4895), + (4895, 4894, 4894, 4894, 4894, 6, 74, 11058, 7, 2160, 12, 4894, 4896), + (4896, 4894, 4894, 4894, 4894, 6, 75, 11059, 7, 2160, 12, 4895, 6352), + (4897, -1, -1, 795, 795, 6, 71, -1, 0, 0, 12, 1432, 4898), + (4898, -1, -1, 795, 795, 6, 73, -1, 0, 0, 12, 4897, 4899), + (4899, -1, -1, 795, 795, 6, 75, -1, 0, 0, 12, 4898, 5889), + (4900, 1462, 1462, 1462, 1462, 6, 71, 11061, 5, 300, 12, 1466, 4901), + (4901, 1462, 1462, 1462, 1462, 6, 73, 11062, 5, 300, 12, 4900, 4902), + (4902, 1462, 1462, 1462, 1462, 6, 75, 11063, 5, 300, 12, 4901, 14739), + (4903, 4903, 4903, 4903, 4903, 9, 71, 11064, 9, 1320, 12, -1, 5892), + (4906, 4906, 4906, 4906, 4906, 9, 71, 11065, 9, 1320, 12, -1, 5893), + (4909, 4909, 4909, 4909, 4909, 9, 71, 11066, 16, 1320, 12, -1, 5894), + (4912, 4912, 4912, 4912, 4912, 9, 71, 11067, 16, 1320, 12, -1, 5895), + (4915, 4915, 4915, 4915, 4915, 9, 71, 11068, 7, 4320, 12, -1, 4916), + (4916, 4915, 4915, 4915, 4915, 9, 73, 11069, 7, 4320, 12, 4915, 4917), + (4917, 4915, 4915, 4915, 4915, 9, 75, 11070, 7, 4320, 12, 4916, 5607), + (4921, -1, -1, 480, 480, 2, 71, -1, 0, 0, 12, 482, 4922), + (4922, -1, -1, 480, 480, 2, 73, -1, 0, 0, 12, 4921, 4923), + (4923, -1, -1, 480, 480, 2, 75, -1, 0, 0, 12, 4922, -1), + (4924, -1, -1, 4924, 4924, 5, 75, -1, 0, 0, 12, -1, 4925), + (4925, -1, -1, 4924, 4924, 5, 75, -1, 0, 0, 12, 4924, 4926), + (4926, -1, -1, 4924, 4924, 5, 75, -1, 0, 0, 12, 4925, 5944), + (4927, 4927, 4927, 4927, 4927, 9, 71, 11076, 14, 600, 12, -1, 7209), + (4931, 4931, 4931, 4931, 4931, 6, 71, 11083, 4, 600, 12, -1, 4932), + (4932, 4931, 4931, 4931, 4931, 6, 73, 11084, 4, 600, 12, 4931, 4933), + (4933, 4931, 4931, 4931, 4931, 6, 75, 11085, 4, 600, 12, 4932, 6054), + (4934, 4934, 4934, 4934, 4934, 7, 71, 11086, 13, 300, 12, -1, 7295), + (4935, 4935, 4935, 4935, 4935, 7, 71, 11087, 14, 300, 12, -1, 7294), + (4938, 4938, 4938, 4938, 4938, 9, 75, 11092, 35, 1800, 12, -1, 5610), + (4943, 4943, 4943, 4943, 4943, 7, 75, 11098, 17, 1800, 12, -1, -1), + (4944, 4944, -1, 4944, 4944, 3, 71, 11103, 0, 1, 12, -1, 4945), + (4945, 4944, -1, 4944, 4944, 6, 73, 11104, 0, 1, 12, 4944, 4946), + (4946, 4944, -1, 4944, 4944, 9, 75, 11105, 0, 1, 12, 4945, 6155), + (4948, -1, -1, 846, 846, 3, 71, -1, 0, 0, 12, 1303, 4949), + (4949, -1, -1, 846, 846, 6, 73, -1, 0, 0, 12, 4948, 4950), + (4950, -1, -1, 846, 846, 9, 75, -1, 0, 0, 12, 4949, 6035), + (4951, -1, -1, 1543, 1543, 5, 71, -1, 0, 0, 12, 1545, 4952), + (4952, -1, -1, 1543, 1543, 5, 73, -1, 0, 0, 12, 4951, 4953), + (4953, -1, -1, 1543, 1543, 5, 75, -1, 0, 0, 12, 4952, 6042), + (4957, -1, -1, 878, 878, 7, 71, -1, 0, 0, 12, 1541, 4958), + (4958, -1, -1, 878, 878, 7, 73, -1, 0, 0, 12, 4957, 4959), + (4959, -1, -1, 878, 878, 7, 75, -1, 0, 0, 12, 4958, 6331), + (4960, -1, -1, 729, 729, 6, 71, -1, 0, 0, 12, 1469, 4961), + (4961, -1, -1, 729, 729, 6, 73, -1, 0, 0, 12, 4960, 4962), + (4962, -1, -1, 729, 729, 6, 75, -1, 0, 0, 12, 4961, 5738), + (4963, 723, 723, 723, 723, 9, 71, 11205, 6, 30, 12, 723, 5737), + (4964, 1119, 1119, 1119, 1119, 6, 73, 11206, 8, 900, 12, 1121, 4965), + (4965, 1119, 1119, 1119, 1119, 6, 74, 11207, 8, 900, 12, 4964, 4966), + (4966, 1119, 1119, 1119, 1119, 6, 75, 11208, 8, 900, 12, 4965, 5734), + (4969, 291, 291, 291, 291, 5, 71, 11212, 5, 900, 12, 1125, 4970), + (4970, 291, 291, 291, 291, 5, 73, 11213, 5, 900, 12, 4969, 4971), + (4971, 291, 291, 291, 291, 5, 75, 11214, 5, 900, 12, 4970, 5743), + (4972, 1598, -1, 1598, 1598, 6, 71, 11215, 6, 900, 12, 1600, 4973), + (4973, 1598, -1, 1598, 1598, 6, 73, 11216, 6, 900, 12, 4972, 4974), + (4974, 1598, -1, 1598, 1598, 6, 75, 11217, 6, 900, 12, 4973, 5710), + (4975, 592, 592, 592, 592, 3, 71, 11218, 2, 18, 12, 1106, 4976), + (4976, 592, 592, 592, 592, 3, 72, 11219, 2, 18, 12, 4975, 4977), + (4977, 592, 592, 592, 592, 3, 73, 11220, 2, 18, 12, 4976, 4978), + (4978, 592, 592, 592, 592, 3, 74, 11221, 2, 18, 12, 4977, 4979), + (4979, 592, 592, 592, 592, 3, 75, 11222, 2, 18, 12, 4978, 5702), + (4980, 1116, 1116, 1116, 1116, 6, 73, 11223, 4, 2160, 12, 1118, 4981), + (4981, 1116, 1116, 1116, 1116, 6, 74, 11224, 4, 2160, 12, 4980, 4982), + (4982, 1116, 1116, 1116, 1116, 6, 75, 11225, 4, 2160, 12, 4981, 5699), + (4983, -1, -1, 864, 864, 6, 71, -1, 0, 0, 12, 1292, 4984), + (4984, -1, -1, 864, 864, 6, 73, -1, 0, 0, 12, 4983, 4985), + (4985, -1, -1, 864, 864, 6, 75, -1, 0, 0, 12, 4984, 6011), + (4986, -1, -1, 644, 644, 5, 67, -1, 0, 0, 12, 1603, 4987), + (4987, -1, -1, 644, 644, 5, 69, -1, 0, 0, 12, 4986, 4988), + (4988, -1, -1, 644, 644, 5, 71, -1, 0, 0, 12, 4987, 6017), + (4989, -1, -1, 1608, 1608, 6, 71, -1, 0, 0, 12, 1610, 4990), + (4990, -1, -1, 1608, 1608, 6, 73, -1, 0, 0, 12, 4989, 4991), + (4991, -1, -1, 1608, 1608, 6, 75, -1, 0, 0, 12, 4990, 7378), + (4992, -1, -1, 1616, 1616, 5, 71, -1, 0, 0, 12, 1620, 4993), + (4993, -1, -1, 1616, 1616, 5, 72, -1, 0, 0, 12, 4992, 4994), + (4994, -1, -1, 1616, 1616, 5, 73, -1, 0, 0, 12, 4993, 4995), + (4995, -1, -1, 1616, 1616, 5, 74, -1, 0, 0, 12, 4994, 4996), + (4996, -1, -1, 1616, 1616, 5, 75, -1, 0, 0, 12, 4995, 6003), + (4997, 545, 545, 545, 545, 6, 73, 11226, 3, 900, 12, 1295, 4998), + (4998, 545, 545, 545, 545, 6, 74, 11227, 3, 900, 12, 4997, 4999), + (4999, 545, 545, 545, 545, 6, 75, 11228, 3, 900, 12, 4998, 6000), + (5000, -1, -1, 1230, 1230, 2, 71, -1, 0, 0, 12, 1232, 5001), + (5001, -1, -1, 1230, 1230, 2, 73, -1, 0, 0, 12, 5000, 5002), + (5002, -1, -1, 1230, 1230, 2, 75, -1, 0, 0, 12, 5001, -1), + (5003, 1345, 1345, 1345, 1345, 5, 73, 11229, 6, 900, 12, 1347, 5004), + (5004, 1345, 1345, 1345, 1345, 5, 74, 11230, 6, 900, 12, 5003, 5005), + (5005, 1345, 1345, 1345, 1345, 5, 75, 11231, 6, 900, 12, 5004, 6008), + (5006, 5006, 5006, 5006, 5006, 0, 0, 27673, 96, 72000, 0, -1, -1), + (5007, 5007, 5007, 5007, 5007, 3, 71, 11233, 8, 2160, 12, -1, 5008), + (5008, 5007, 5007, 5007, 5007, 6, 73, 11234, 8, 2160, 12, 5007, 5009), + (5009, 5007, 5007, 5007, 5007, 9, 75, 11235, 8, 2160, 12, 5008, 6425), + (5010, -1, -1, 1007, 1007, 8, 81, -1, 0, 0, 16, -1, 5011), + (5011, -1, -1, 1007, 1007, 10, 83, -1, 0, 0, 16, 5010, 5012), + (5012, -1, -1, 1007, 1007, 12, 85, -1, 0, 0, 16, 5011, 15317), + (5013, -1, -1, 1284, 1284, 6, 83, -1, 0, 0, 16, 5037, 5014), + (5014, -1, -1, 1284, 1284, 6, 85, -1, 0, 0, 16, 5013, -1), + (5015, 5015, 5015, 5015, 5015, 5, 75, 11241, 9, 900, 12, -1, 5741), + (5017, 5017, 5017, 5017, 5017, 3, 71, 11243, 8, 600, 12, -1, 5018), + (5018, 5017, 5017, 5017, 5017, 6, 73, 11244, 8, 600, 12, 5017, 5019), + (5019, 5017, 5017, 5017, 5017, 9, 75, 11245, 8, 600, 12, 5018, 7454), + (5020, 5020, 5020, 5020, 5020, 9, 75, 11246, 9, 300, 12, -1, 5716), + (5021, 5021, 5021, 5021, 5021, 9, 71, 11341, 7, 60, 12, -1, 10868), + (5022, 5022, 5022, 5022, 5022, 3, 71, 11247, 5, 600, 12, -1, 5023), + (5023, 5022, 5022, 5022, 5022, 6, 73, 23986, 5, 600, 12, 5022, 5024), + (5024, 5022, 5022, 5022, 5022, 9, 75, 23987, 5, 600, 12, 5023, 6038), + (5025, 5025, 5025, 5025, 5025, 3, 71, 11251, 6, 180, 12, -1, 5026), + (5026, 5025, 5025, 5025, 5025, 6, 73, 11252, 6, 180, 12, 5025, 5027), + (5027, 5025, 5025, 5025, 5025, 9, 75, 11253, 6, 180, 12, 5026, -1), + (5028, 5028, -1, 5028, 5028, 9, 75, 11254, 4, 900, 12, -1, 6041), + (5029, -1, -1, 1313, 1313, 6, 71, -1, 0, 0, 8, 1315, 5030), + (5030, -1, -1, 1313, 1313, 6, 73, -1, 0, 0, 8, 5029, 5031), + (5031, -1, -1, 1313, 1313, 6, 75, -1, 0, 0, 8, 5030, 6066), + (5032, -1, -1, 634, 634, 5, 72, -1, 0, 0, 12, 1321, 5033), + (5033, -1, -1, 634, 634, 5, 73, -1, 0, 0, 12, 5032, 5034), + (5034, -1, -1, 634, 634, 5, 74, -1, 0, 0, 12, 5033, 5611), + (5035, -1, -1, 1284, 1284, 6, 71, -1, 0, 0, 12, 1286, 5036), + (5036, -1, -1, 1284, 1284, 6, 73, -1, 0, 0, 12, 5035, 5037), + (5037, -1, -1, 1284, 1284, 6, 75, -1, 0, 0, 12, 5036, 5013), + (5038, -1, -1, 190, 190, 7, 71, -1, 0, 0, 12, 1525, 5039), + (5039, -1, -1, 190, 190, 7, 73, -1, 0, 0, 12, 5038, 5040), + (5040, -1, -1, 190, 190, 7, 75, -1, 0, 0, 12, 5039, 15141), + (5041, 534, 534, 534, 534, 5, 72, 11255, 4, 2160, 12, 1280, 5042), + (5042, 534, 534, 534, 534, 5, 73, 11256, 4, 2160, 12, 5041, 5043), + (5043, 534, 534, 534, 534, 5, 74, 11257, 4, 2160, 12, 5042, 5969), + (5044, 188, 188, 188, 188, 9, 73, 11258, 2, 30, 12, 1277, 7339), + (5045, -1, -1, 1057, 1057, 9, 85, -1, 0, 0, 16, -1, -1), + (5051, 757, -1, 757, 757, 5, 71, 11262, 6, 1800, 12, 1224, 5052), + (5052, 757, -1, 757, 757, 5, 73, 11263, 6, 1800, 12, 5051, 5053), + (5053, 757, -1, 757, 757, 5, 75, 11264, 6, 1800, 12, 5052, 5822), + (5054, 548, 548, 548, 548, 5, 72, 11265, 5, 900, 12, 1227, 5055), + (5055, 548, 548, 548, 548, 5, 73, 11266, 5, 900, 12, 5054, 5056), + (5056, 548, 548, 548, 548, 5, 74, 11267, 5, 900, 12, 5055, 5829), + (5058, 1498, 1498, 1498, 1498, 6, 71, 11269, 12, 1320, 12, 1500, 5059), + (5059, 1498, 1498, 1498, 1498, 6, 73, 11270, 12, 1320, 12, 5058, 5060), + (5060, 1498, 1498, 1498, 1498, 6, 75, 11271, 12, 1320, 12, 5059, 5819), + (5061, -1, -1, 567, 567, 5, 72, -1, 0, 0, 12, 567, 5825), + (5062, 459, 459, 459, 459, 6, 71, 11272, 8, 180, 12, 1191, 5063), + (5063, 459, 459, 459, 459, 6, 73, 11273, 8, 180, 12, 5062, 5064), + (5064, 459, 459, 459, 459, 6, 75, 11274, 8, 180, 12, 5063, -1), + (5068, 153, 153, 153, 153, 9, 75, 11279, 3, 2160, 12, 1519, 6101), + (5069, 146, 146, 146, 146, 5, 72, 11281, 2, 180, 12, 146, 6102), + (5070, 131, 131, 131, 131, 5, 72, 11282, 4, 900, 12, 1205, 5071), + (5071, 131, 131, 131, 131, 5, 73, 11283, 4, 900, 12, 5070, 5072), + (5072, 131, 131, 131, 131, 5, 74, 11284, 4, 900, 12, 5071, 5791), + (5076, 1192, 1192, 1192, 1192, 5, 72, 11288, 12, 1320, 12, 1194, 5077), + (5077, 1192, 1192, 1192, 1192, 5, 73, 11289, 12, 1320, 12, 5076, 5078), + (5078, 1192, 1192, 1192, 1192, 5, 74, 11290, 12, 1320, 12, 5077, 5794), + (5079, 1195, 1195, 1195, 1195, 9, 75, 11291, 13, 2160, 12, 1195, 5790), + (5080, 1459, 1459, 1459, 1459, 5, 71, 11293, 11, 1800, 12, 1461, 5081), + (5081, 1459, 1459, 1459, 1459, 5, 73, 11294, 11, 1800, 12, 5080, 5082), + (5082, 1459, 1459, 1459, 1459, 5, 75, 11295, 11, 1800, 12, 5081, 5803), + (5084, 1383, 1383, 1383, 1383, 12, 75, 11296, 6, 300, 12, 1387, 5789), + (5085, -1, -1, 5085, 5085, 3, 71, -1, 0, 0, 12, -1, 5086), + (5086, -1, -1, 5085, 5085, 6, 73, -1, 0, 0, 12, 5085, 5087), + (5087, -1, -1, 5085, 5085, 9, 75, -1, 0, 0, 12, 5086, 6406), + (5095, 5095, 5095, 5095, 5095, 3, 71, 11307, 10, 900, 12, -1, 5096), + (5096, 5095, 5095, 5095, 5095, 6, 73, 11308, 10, 900, 12, 5095, 5097), + (5097, 5095, 5095, 5095, 5095, 9, 75, 11309, 10, 900, 12, 5096, 5975), + (5098, 5098, 5098, 5098, 5098, 9, 75, 11310, 2, 30, 12, -1, -1), + (5105, 5105, 5105, 5105, 5105, 9, 75, 11317, 11, 600, 12, -1, 5832), + (5109, 5109, 5109, 5109, 5109, 9, 75, 11321, 0, 1, 12, -1, 6448), + (5118, -1, -1, 5083, 5083, 3, 71, -1, 0, 0, 12, -1, 5119), + (5119, -1, -1, 5083, 5083, 3, 73, -1, 0, 0, 12, 5118, 5120), + (5120, -1, -1, 5083, 5083, 3, 75, -1, 0, 0, 12, 5119, 5797), + (5127, -1, -1, 5127, 5127, 3, 71, -1, 0, 0, 12, -1, 5128), + (5128, -1, -1, 5127, 5127, 3, 73, -1, 0, 0, 12, 5127, 5129), + (5129, -1, -1, 5127, 5127, 3, 75, -1, 0, 0, 12, 5128, -1), + (5130, 860, 860, 860, 860, 6, 71, 5860, 5, 180, 12, 862, 5131), + (5131, 860, 860, 860, 860, 6, 73, 5861, 5, 180, 12, 5130, 5132), + (5132, 860, 860, 860, 860, 6, 75, 5862, 5, 180, 12, 5131, -1), + (5133, -1, -1, 267, 267, 6, 71, -1, 0, 0, 12, 925, 5134), + (5134, -1, -1, 267, 267, 6, 73, -1, 0, 0, 12, 5133, 5135), + (5135, -1, -1, 267, 267, 6, 75, -1, 0, 0, 12, 5134, 5617), + (5136, -1, -1, 4688, 4688, 3, 71, -1, 0, 0, 12, -1, 5137), + (5137, -1, -1, 4688, 4688, 3, 72, -1, 0, 0, 12, 5136, 5138), + (5138, -1, -1, 4688, 4688, 3, 73, -1, 0, 0, 12, 5137, 5139), + (5139, -1, -1, 4688, 4688, 3, 74, -1, 0, 0, 12, 5138, 5140), + (5140, -1, -1, 4688, 4688, 3, 75, -1, 0, 0, 12, 5139, -1), + (5141, -1, -1, 815, 815, 5, 71, -1, 0, 0, 12, 819, 5142), + (5142, -1, -1, 815, 815, 5, 72, -1, 0, 0, 12, 5141, 5143), + (5143, -1, -1, 815, 815, 5, 73, -1, 0, 0, 12, 5142, 5144), + (5144, -1, -1, 815, 815, 5, 74, -1, 0, 0, 12, 5143, 5145), + (5145, -1, -1, 815, 815, 5, 75, -1, 0, 0, 12, 5144, 5909), + (5150, 5150, 5150, 5150, 5150, 0, 1, 11112, 22, 300, 3, -1, 5151), + (5165, 5165, 5165, 5165, 5165, 0, 1, 11127, 22, 300, 3, -1, 5166), + (5180, 5180, 5180, 5180, 5180, 0, 1, 11142, 22, 300, 3, -1, 5181), + (5195, 5195, 5195, 5195, 5195, 0, 1, 11157, 22, 300, 3, -1, 5196), + (5210, 5210, 5210, 5210, 5210, 0, 1, 11172, 22, 300, 3, -1, 5211), + (5225, 5225, 5225, 5225, 5225, 0, 1, 11187, 22, 300, 3, -1, 5226), + (5240, 1355, 1355, 1355, 1355, 6, 71, 11611, 3, 60, 12, 1357, 5241), + (5241, 1355, 1355, 1355, 1355, 6, 73, 11612, 3, 60, 12, 5240, 5242), + (5242, 1355, 1355, 1355, 1355, 6, 75, 11613, 3, 60, 12, 5241, 5914), + (5243, -1, -1, 907, 907, 7, 71, -1, 0, 0, 12, 911, 5244), + (5244, -1, -1, 907, 907, 7, 72, -1, 0, 0, 12, 5243, 5245), + (5245, -1, -1, 907, 907, 7, 73, -1, 0, 0, 12, 5244, 5246), + (5246, -1, -1, 907, 907, 7, 74, -1, 0, 0, 12, 5245, 5247), + (5247, -1, -1, 907, 907, 7, 75, -1, 0, 0, 12, 5246, -1), + (5248, -1, -1, 5248, 5248, 3, 71, -1, 0, 0, 12, -1, 5249), + (5249, -1, -1, 5248, 5248, 6, 73, -1, 0, 0, 12, 5248, 5250), + (5250, -1, -1, 5248, 5248, 9, 75, -1, 0, 0, 12, 5249, 6014), + (5251, 5251, 5251, 5251, 5251, 5, 71, 11615, 13, 900, 12, -1, 5252), + (5252, 5251, 5251, 5251, 5251, 5, 73, 11616, 13, 900, 12, 5251, 5253), + (5253, 5251, 5251, 5251, 5251, 5, 75, 11617, 13, 900, 12, 5252, 6092), + (5254, -1, -1, 724, 724, 3, 71, -1, 0, 0, 12, 728, 5255), + (5255, -1, -1, 724, 724, 3, 72, -1, 0, 0, 12, 5254, 5256), + (5256, -1, -1, 724, 724, 3, 73, -1, 0, 0, 12, 5255, 5257), + (5257, -1, -1, 724, 724, 3, 74, -1, 0, 0, 12, 5256, 5258), + (5258, -1, -1, 724, 724, 3, 75, -1, 0, 0, 12, 5257, 5729), + (5259, -1, -1, 790, 790, 3, 71, -1, 0, 0, 12, 794, 5260), + (5260, -1, -1, 790, 790, 3, 72, -1, 0, 0, 12, 5259, 5261), + (5261, -1, -1, 790, 790, 3, 73, -1, 0, 0, 12, 5260, 5262), + (5262, -1, -1, 790, 790, 3, 74, -1, 0, 0, 12, 5261, 5263), + (5263, -1, -1, 790, 790, 3, 75, -1, 0, 0, 12, 5262, 5320), + (5264, -1, -1, 5264, 5264, 3, 71, -1, 0, 0, 12, -1, 5265), + (5265, -1, -1, 5264, 5264, 3, 72, -1, 0, 0, 12, 5264, 5266), + (5266, -1, -1, 5264, 5264, 3, 73, -1, 0, 0, 12, 5265, 5267), + (5267, -1, -1, 5264, 5264, 3, 74, -1, 0, 0, 12, 5266, 5268), + (5268, -1, -1, 5264, 5264, 3, 75, -1, 0, 0, 12, 5267, 5939), + (5269, -1, -1, 5269, 5269, 3, 71, -1, 0, 0, 12, -1, -1), + (5270, -1, -1, 589, 589, 7, 71, -1, 0, 0, 12, 894, 5271), + (5271, -1, -1, 589, 589, 7, 73, -1, 0, 0, 12, 5270, 5272), + (5272, -1, -1, 589, 589, 7, 75, -1, 0, 0, 12, 5271, 6063), + (5276, -1, -1, 5276, 5276, 3, 71, -1, 0, 0, 12, -1, 5277), + (5277, -1, -1, 5276, 5276, 6, 73, -1, 0, 0, 12, 5276, 5278), + (5278, -1, -1, 5276, 5276, 9, 75, -1, 0, 0, 12, 5277, 15238), + (5279, 155, 155, 155, 155, 12, 75, 11624, 8, 60, 12, 1344, 5289), + (5280, 921, 921, 921, 921, 9, 74, 11625, 8, 60, 12, 1340, 6149), + (5281, 922, 922, 922, 922, 9, 73, 11626, 8, 60, 12, 1341, 6150), + (5282, 923, 923, 923, 923, 9, 72, 11627, 8, 60, 12, 1342, 6151), + (5283, -1, -1, 5263, 5263, 3, 71, -1, 0, 0, 12, -1, 5284), + (5284, -1, -1, 5263, 5263, 6, 73, -1, 0, 0, 12, 5283, 5285), + (5285, -1, -1, 5263, 5263, 9, 75, -1, 0, 0, 12, 5284, 5620), + (5286, -1, -1, 1107, 1107, 6, 71, -1, 0, 0, 12, 1109, 5287), + (5287, -1, -1, 1107, 1107, 6, 73, -1, 0, 0, 12, 5286, 5288), + (5288, -1, -1, 1107, 1107, 6, 75, -1, 0, 0, 12, 5287, 6403), + (5289, 155, 155, 155, 155, 12, 77, 13227, 8, 60, 14, 5279, 7238), + (5290, -1, -1, 1604, 1604, 5, 63, -1, 0, 0, 12, 1606, 5291), + (5291, -1, -1, 1604, 1604, 5, 64, -1, 0, 0, 12, 5290, 5292), + (5292, -1, -1, 1604, 1604, 5, 65, -1, 0, 0, 12, 5291, 5293), + (5293, -1, -1, 1604, 1604, 5, 66, -1, 0, 0, 12, 5292, 5294), + (5294, -1, -1, 1604, 1604, 5, 67, -1, 0, 0, 12, 5293, 6032), + (5295, -1, -1, 5295, 5295, 3, 71, -1, 0, 0, 12, -1, 5296), + (5296, -1, -1, 5295, 5295, 6, 73, -1, 0, 0, 12, 5295, 5297), + (5297, -1, -1, 5295, 5295, 9, 75, -1, 0, 0, 12, 5296, 6531), + (5298, 5298, 5298, 5298, 5298, 3, 71, 11630, 32, 1800, 12, -1, 5299), + (5299, 5298, 5298, 5298, 5298, 6, 73, 11631, 32, 1800, 12, 5298, 5300), + (5300, 5298, 5298, 5298, 5298, 9, 75, 11632, 32, 1800, 12, 5299, 5707), + (5301, -1, -1, 683, 683, 5, 71, -1, 0, 0, 12, 1038, 5302), + (5302, -1, -1, 683, 683, 5, 72, -1, 0, 0, 12, 5301, 5303), + (5303, -1, -1, 683, 683, 5, 73, -1, 0, 0, 12, 5302, 5304), + (5304, -1, -1, 683, 683, 5, 74, -1, 0, 0, 12, 5303, 5305), + (5305, -1, -1, 683, 683, 5, 75, -1, 0, 0, 12, 5304, 6080), + (5306, -1, -1, 658, 658, 5, 71, -1, 0, 0, 12, 660, 5307), + (5307, -1, -1, 658, 658, 5, 72, -1, 0, 0, 12, 5306, 5308), + (5308, -1, -1, 658, 658, 5, 73, -1, 0, 0, 12, 5307, 5309), + (5309, -1, -1, 658, 658, 5, 74, -1, 0, 0, 12, 5308, 5310), + (5310, -1, -1, 658, 658, 5, 75, -1, 0, 0, 12, 5309, 5623), + (5311, 1495, 1495, 1495, 1495, 5, 71, 11639, 30, 900, 12, 1497, 5312), + (5312, 1495, 1495, 1495, 1495, 5, 73, 11640, 30, 900, 12, 5311, 5313), + (5313, 1495, 1495, 1495, 1495, 5, 75, 11641, 30, 900, 12, 5312, 5826), + (5314, 1327, 1327, 1327, 1327, 5, 71, 11642, 10, 900, 12, 1329, 5315), + (5315, 1327, 1327, 1327, 1327, 5, 73, 11643, 10, 900, 12, 5314, 5316), + (5316, 1327, 1327, 1327, 1327, 5, 75, 11644, 10, 900, 12, 5315, 6098), + (5317, -1, -1, 98, 738, 4, 71, -1, 0, 0, 12, 740, 5318), + (5318, -1, -1, 98, 738, 4, 73, -1, 0, 0, 12, 5317, 5319), + (5319, -1, -1, 98, 738, 4, 75, -1, 0, 0, 12, 5318, 5628), + (5320, -1, -1, 790, 790, 6, 76, -1, 0, 0, 14, 5263, 5321), + (5321, -1, -1, 790, 790, 6, 77, -1, 0, 0, 14, 5320, 5322), + (5322, -1, -1, 790, 790, 6, 78, -1, 0, 0, 14, 5321, 5323), + (5323, -1, -1, 790, 790, 6, 79, -1, 0, 0, 14, 5322, 5324), + (5324, -1, -1, 790, 790, 6, 80, -1, 0, 0, 14, 5323, 7270), + (5325, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 843, 5326), + (5326, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 5325, 5327), + (5327, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 5326, 5328), + (5328, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 5327, 5329), + (5329, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 5328, 7210), + (5330, 1327, 1327, 1327, 1327, 12, 91, 30870, 10, 900, 18, 10189, 5331), + (5333, 1520, 1520, 1520, 1520, 9, 91, 30873, 11, 900, 18, 12999, 5334), + (5336, 12989, 12989, 12989, 12989, 11, 91, 30876, 73, 1800, 18, 12991, 5337), + (5339, -1, -1, 6383, 6383, 11, 91, -1, 0, 0, 18, 12803, 5340), + (5342, 6692, 6692, 6692, 6692, 9, 91, 30879, 42, 600, 18, 6696, 5343), + (5347, -1, -1, 6375, 6375, 12, 91, -1, 0, 0, 18, 10086, 5348), + (5348, -1, -1, 6375, 6375, 15, 93, -1, 0, 0, 18, 5347, 5349), + (5350, 12992, 12992, 12992, 12992, 12, 91, 30884, 0, 1, 18, 12994, 5351), + (5353, 6706, 6706, 6706, 6706, 9, 91, 30887, 44, 600, 18, 10181, 5354), + (5356, 5109, 5109, 5109, 5109, 12, 92, 30890, 0, 1, 18, 13016, 17323), + (5357, 528, 528, 528, 528, 12, 91, 30891, 5, 720, 18, 13163, 5358), + (5360, -1, -1, 9503, 9503, 11, 91, -1, 0, 0, 18, 12794, 5361), + (5363, 5251, 5251, 5251, 5251, 15, 91, 30894, 13, 900, 18, 10199, 5364), + (5366, -1, -1, 5002, 5002, 12, 91, -1, 34, 0, 18, -1, 5367), + (5369, 5001, 5001, 5001, 5001, 12, 91, 30900, 32, 600, 18, -1, 5370), + (5500, -1, -1, 852, 852, 9, 78, -1, 0, 0, 14, 854, 5501), + (5501, -1, -1, 852, 852, 10, 79, -1, 0, 0, 14, 5500, 5502), + (5502, -1, -1, 852, 852, 12, 80, -1, 0, 0, 14, 5501, 7678), + (5513, 1126, 1126, 1126, 1126, 8, 77, 12668, 2, 2160, 14, 1128, 5514), + (5514, 1126, 1126, 1126, 1126, 9, 78, 12669, 2, 2160, 14, 5513, 5515), + (5515, 1126, 1126, 1126, 1126, 10, 79, 12670, 2, 2160, 14, 5514, 13253), + (5516, -1, -1, 1287, 1287, 8, 77, -1, 0, 0, 14, 1289, 5517), + (5517, -1, -1, 1287, 1287, 9, 78, -1, 0, 0, 14, 5516, 5518), + (5518, -1, -1, 1287, 1287, 10, 79, -1, 0, 0, 14, 5517, 12469), + (5519, -1, -1, 125, 125, 6, 76, -1, 0, 0, 14, 1398, 5520), + (5520, -1, -1, 125, 125, 7, 77, -1, 0, 0, 14, 5519, 5521), + (5521, -1, -1, 125, 125, 8, 78, -1, 0, 0, 14, 5520, 5522), + (5522, -1, -1, 125, 125, 9, 79, -1, 0, 0, 14, 5521, 5523), + (5523, -1, -1, 125, 125, 10, 80, -1, 0, 0, 14, 5522, 7501), + (5524, -1, -1, 122, 122, 6, 76, -1, 0, 0, 14, 1403, 5525), + (5525, -1, -1, 122, 122, 7, 77, -1, 0, 0, 14, 5524, 5526), + (5526, -1, -1, 122, 122, 8, 78, -1, 0, 0, 14, 5525, 5527), + (5527, -1, -1, 122, 122, 9, 79, -1, 0, 0, 14, 5526, 5528), + (5528, -1, -1, 122, 122, 10, 80, -1, 0, 0, 14, 5527, 7506), + (5529, -1, -1, 1486, 1486, 7, 76, -1, 0, 0, 14, 1490, 5530), + (5530, -1, -1, 1486, 1486, 8, 77, -1, 0, 0, 14, 5529, 5531), + (5531, -1, -1, 1486, 1486, 9, 78, -1, 0, 0, 14, 5530, 5532), + (5532, -1, -1, 1486, 1486, 10, 79, -1, 0, 0, 14, 5531, 5533), + (5533, -1, -1, 1486, 1486, 12, 80, -1, 0, 0, 14, 5532, 7554), + (5534, -1, -1, 599, 599, 9, 78, -1, 0, 0, 14, 1538, 5535), + (5535, -1, -1, 599, 599, 10, 79, -1, 0, 0, 14, 5534, 5536), + (5536, -1, -1, 599, 599, 12, 80, -1, 0, 0, 14, 5535, 7559), + (5542, -1, -1, 1041, 1041, 7, 76, -1, 0, 0, 14, 4709, 5543), + (5543, -1, -1, 1041, 1041, 9, 78, -1, 0, 0, 14, 5542, 5544), + (5544, -1, -1, 1041, 1041, 12, 80, -1, 0, 0, 14, 5543, 7562), + (5545, -1, -1, 1044, 1044, 7, 76, -1, 0, 0, 14, 4712, 5546), + (5546, -1, -1, 1044, 1044, 9, 78, -1, 0, 0, 14, 5545, 5547), + (5547, -1, -1, 1044, 1044, 12, 80, -1, 0, 0, 14, 5546, 7650), + (5548, -1, -1, 1047, 1047, 7, 76, -1, 0, 0, 14, 4715, 5549), + (5549, -1, -1, 1047, 1047, 9, 78, -1, 0, 0, 14, 5548, 5550), + (5550, -1, -1, 1047, 1047, 12, 80, -1, 0, 0, 14, 5549, 7653), + (5551, -1, -1, 1050, 1050, 7, 76, -1, 0, 0, 14, 4718, 5552), + (5552, -1, -1, 1050, 1050, 9, 78, -1, 0, 0, 14, 5551, 5553), + (5553, -1, -1, 1050, 1050, 12, 80, -1, 0, 0, 14, 5552, 7656), + (5554, -1, -1, 119, 119, 7, 76, -1, 0, 0, 14, 4724, 5555), + (5555, -1, -1, 119, 119, 9, 78, -1, 0, 0, 14, 5554, 5556), + (5556, -1, -1, 119, 119, 12, 80, -1, 0, 0, 14, 5555, 7565), + (5557, -1, -1, 1592, 1592, 7, 76, -1, 0, 0, 14, 4729, 5558), + (5558, -1, -1, 1592, 1592, 8, 77, -1, 0, 0, 14, 5557, 5559), + (5559, -1, -1, 1592, 1592, 9, 78, -1, 0, 0, 14, 5558, 5560), + (5560, -1, -1, 1592, 1592, 10, 79, -1, 0, 0, 14, 5559, 5561), + (5561, -1, -1, 1592, 1592, 12, 80, -1, 0, 0, 14, 5560, 7568), + (5562, -1, -1, 4739, 4739, 7, 76, -1, 0, 0, 14, 4741, 5563), + (5563, -1, -1, 4739, 4739, 9, 78, -1, 0, 0, 14, 5562, 5564), + (5564, -1, -1, 4739, 4739, 12, 80, -1, 0, 0, 14, 5563, 7573), + (5565, 4742, 4742, 4742, 4742, 7, 76, 12671, 12, 600, 14, 4742, -1), + (5566, -1, -1, 1072, 1072, 7, 76, -1, 0, 0, 14, 4748, 5567), + (5567, -1, -1, 1072, 1072, 8, 77, -1, 0, 0, 14, 5566, 5568), + (5568, -1, -1, 1072, 1072, 9, 78, -1, 0, 0, 14, 5567, 5569), + (5569, -1, -1, 1072, 1072, 10, 79, -1, 0, 0, 14, 5568, 5570), + (5570, -1, -1, 1072, 1072, 12, 80, -1, 0, 0, 14, 5569, 7576), + (5571, -1, -1, 637, 637, 7, 76, -1, 0, 0, 14, 4751, 5572), + (5572, -1, -1, 637, 637, 9, 78, -1, 0, 0, 14, 5571, 5573), + (5573, -1, -1, 637, 637, 12, 80, -1, 0, 0, 14, 5572, 12435), + (5574, -1, -1, 1210, 1210, 7, 76, -1, 0, 0, 14, 4754, 5575), + (5575, -1, -1, 1210, 1210, 9, 78, -1, 0, 0, 14, 5574, 5576), + (5576, -1, -1, 1210, 1210, 12, 80, -1, 0, 0, 14, 5575, 7232), + (5577, -1, -1, 1210, 1213, 7, 76, -1, 0, 0, 14, 4757, 5578), + (5578, -1, -1, 1210, 1213, 9, 78, -1, 0, 0, 14, 5577, 5579), + (5579, -1, -1, 1210, 1213, 12, 80, -1, 0, 0, 14, 5578, 7581), + (5580, -1, -1, 602, 602, 7, 76, -1, 0, 0, 14, 4760, 5581), + (5581, -1, -1, 602, 602, 9, 78, -1, 0, 0, 14, 5580, 5582), + (5582, -1, -1, 602, 602, 12, 80, -1, 0, 0, 14, 5581, 10685), + (5586, -1, -1, 98, 98, 7, 76, -1, 0, 0, 14, 4769, 5587), + (5587, -1, -1, 98, 98, 9, 78, -1, 0, 0, 14, 5586, 5588), + (5588, -1, -1, 98, 98, 12, 80, -1, 0, 0, 14, 5587, 7584), + (5589, -1, -1, 1186, 1186, 7, 76, -1, 0, 0, 14, 4778, 5590), + (5590, -1, -1, 1186, 1186, 9, 78, -1, 0, 0, 14, 5589, 5591), + (5591, -1, -1, 1186, 1186, 12, 80, -1, 0, 0, 14, 5590, 7587), + (5592, -1, -1, 80, 80, 7, 76, -1, 0, 0, 14, 4781, 5593), + (5593, -1, -1, 80, 80, 9, 78, -1, 0, 0, 14, 5592, 5594), + (5594, -1, -1, 80, 80, 12, 80, -1, 0, 0, 14, 5593, 7590), + (5595, -1, -1, 255, 255, 7, 76, -1, 0, 0, 14, 4797, 5596), + (5596, -1, -1, 255, 255, 9, 78, -1, 0, 0, 14, 5595, 5597), + (5597, -1, -1, 255, 255, 12, 80, -1, 0, 0, 14, 5596, 7631), + (5606, 4860, 4860, 4860, 4860, 12, 80, 11688, 13, 60, 14, 4860, 7127), + (5607, 4915, 4915, 4915, 4915, 7, 76, 12673, 7, 4320, 14, 4917, 5608), + (5608, 4915, 4915, 4915, 4915, 9, 78, 12674, 7, 4320, 14, 5607, 5609), + (5609, 4915, 4915, 4915, 4915, 12, 80, 12675, 7, 4320, 14, 5608, 7246), + (5610, 4938, 4938, 4938, 4938, 12, 80, 12676, 35, 1800, 14, 4938, 5614), + (5611, -1, -1, 634, 634, 7, 76, -1, 0, 0, 14, 5034, 5612), + (5612, -1, -1, 634, 634, 9, 78, -1, 0, 0, 14, 5611, 5613), + (5613, -1, -1, 634, 634, 12, 80, -1, 0, 0, 14, 5612, 7713), + (5614, 4938, 4938, 4938, 4938, 9, 85, 16852, 35, 1800, 16, 5610, 12875), + (5617, -1, -1, 267, 267, 7, 76, -1, 0, 0, 14, 5135, 5618), + (5618, -1, -1, 267, 267, 9, 78, -1, 0, 0, 14, 5617, 5619), + (5619, -1, -1, 267, 267, 12, 80, -1, 0, 0, 14, 5618, 12860), + (5620, -1, -1, 5263, 5263, 7, 76, -1, 0, 0, 14, 5285, 5621), + (5621, -1, -1, 5263, 5263, 9, 78, -1, 0, 0, 14, 5620, 5622), + (5622, -1, -1, 5263, 5263, 12, 80, -1, 0, 0, 14, 5621, 12466), + (5623, -1, -1, 658, 658, 5, 76, -1, 0, 0, 14, 5310, 5624), + (5624, -1, -1, 658, 658, 5, 77, -1, 0, 0, 14, 5623, 5625), + (5625, -1, -1, 658, 658, 5, 78, -1, 0, 0, 14, 5624, 5626), + (5626, -1, -1, 658, 658, 5, 79, -1, 0, 0, 14, 5625, 5627), + (5627, -1, -1, 658, 658, 5, 80, -1, 0, 0, 14, 5626, 7593), + (5628, -1, -1, 98, 738, 7, 76, -1, 0, 0, 14, 5319, 5629), + (5629, -1, -1, 98, 738, 9, 78, -1, 0, 0, 14, 5628, 5630), + (5630, -1, -1, 98, 738, 12, 80, -1, 0, 0, 14, 5629, 7598), + (5699, 1116, 1116, 1116, 1116, 7, 76, 12500, 4, 2160, 14, 4982, 5700), + (5700, 1116, 1116, 1116, 1116, 9, 78, 12501, 4, 2160, 14, 5699, 5701), + (5701, 1116, 1116, 1116, 1116, 12, 80, 12502, 4, 2160, 14, 5700, 7430), + (5702, 592, 592, 592, 592, 4, 76, 12503, 2, 18, 14, 4979, 5703), + (5703, 592, 592, 592, 592, 4, 77, 12504, 2, 18, 14, 5702, 5704), + (5704, 592, 592, 592, 592, 4, 78, 12505, 2, 18, 14, 5703, 5705), + (5705, 592, 592, 592, 592, 4, 79, 12506, 2, 18, 14, 5704, 5706), + (5706, 592, 592, 592, 592, 4, 80, 12507, 2, 18, 14, 5705, 7433), + (5707, 5298, 5298, 5298, 5298, 9, 78, 12508, 32, 1800, 14, 5300, 5708), + (5708, 5298, 5298, 5298, 5298, 10, 79, 12509, 32, 1800, 14, 5707, 5709), + (5709, 5298, 5298, 5298, 5298, 12, 80, 12510, 32, 1800, 14, 5708, 7438), + (5710, 1598, -1, 1598, 1598, 7, 76, 12511, 6, 900, 14, 4974, 5711), + (5711, 1598, -1, 1598, 1598, 9, 78, 12512, 6, 900, 14, 5710, 5712), + (5712, 1598, -1, 1598, 1598, 12, 80, 12513, 6, 900, 14, 5711, 7441), + (5713, 1569, 1569, 1569, 1569, 7, 76, 12514, 5, 1800, 14, 1571, 5714), + (5714, 1569, 1569, 1569, 1569, 9, 78, 12515, 5, 1800, 14, 5713, 5715), + (5715, 1569, 1569, 1569, 1569, 12, 80, 12516, 5, 1800, 14, 5714, 7457), + (5716, 5020, 5020, 5020, 5020, 9, 77, 12517, 9, 300, 14, 5020, 7444), + (5717, 5717, 5717, 5717, 5717, 10, 76, 12519, 17, 600, 14, -1, -1), + (5729, -1, -1, 724, 724, 7, 76, -1, 0, 0, 14, 5258, 5730), + (5730, -1, -1, 724, 724, 8, 77, -1, 0, 0, 14, 5729, 5731), + (5731, -1, -1, 724, 724, 9, 78, -1, 0, 0, 14, 5730, 5732), + (5732, -1, -1, 724, 724, 10, 79, -1, 0, 0, 14, 5731, 5733), + (5733, -1, -1, 724, 724, 12, 80, -1, 0, 0, 14, 5732, 7489), + (5734, 1119, 1119, 1119, 1119, 7, 78, 12520, 8, 900, 14, 4966, 5735), + (5735, 1119, 1119, 1119, 1119, 8, 79, 12521, 8, 900, 14, 5734, 5736), + (5736, 1119, 1119, 1119, 1119, 9, 80, 12522, 8, 900, 14, 5735, 7479), + (5737, 723, 723, 723, 723, 7, 76, 12523, 6, 30, 14, 4963, 7482), + (5738, -1, -1, 729, 729, 7, 76, -1, 0, 0, 14, 4962, 5739), + (5739, -1, -1, 729, 729, 8, 77, -1, 0, 0, 14, 5738, 5740), + (5740, -1, -1, 729, 729, 9, 78, -1, 0, 0, 14, 5739, 7494), + (5741, 5015, 5015, 5015, 5015, 12, 80, 12524, 9, 900, 14, 5015, 7483), + (5742, 289, 289, 289, 289, 12, 80, 12525, 3, 300, 14, 1607, 7484), + (5743, 291, 291, 291, 291, 9, 78, 12526, 5, 900, 14, 4971, 5744), + (5744, 291, 291, 291, 291, 10, 79, 12527, 5, 900, 14, 5743, 5745), + (5745, 291, 291, 291, 291, 12, 80, 12528, 5, 900, 14, 5744, 7485), + (5759, 1425, 1425, 1425, 1425, 7, 78, 13565, 2, 2160, 14, 1429, 5760), + (5760, 1425, 1425, 1425, 1425, 8, 78, 13570, 2, 2160, 14, 5759, 5761), + (5761, 1425, 1425, 1425, 1425, 9, 79, 13575, 2, 2160, 14, 5760, 5762), + (5762, 1425, 1425, 1425, 1425, 10, 79, 13580, 2, 2160, 14, 5761, 5763), + (5763, 1425, 1425, 1425, 1425, 11, 80, 13585, 2, 2160, 14, 5762, -1), + (5764, 4854, 4854, 4854, 4854, 7, 76, 12534, 8, 600, 14, 4856, 5765), + (5765, 4854, 4854, 4854, 4854, 9, 78, 12535, 8, 600, 14, 5764, 5766), + (5766, 4854, 4854, 4854, 4854, 12, 80, 12536, 8, 600, 14, 5765, 7178), + (5767, 4857, 4857, 4857, 4857, 7, 76, 12537, 7, 600, 14, 4859, 5768), + (5768, 4857, 4857, 4857, 4857, 9, 78, 12538, 7, 600, 14, 5767, 5769), + (5769, 4857, 4857, 4857, 4857, 12, 80, 12539, 7, 600, 14, 5768, 17030), + (5770, 1348, 1348, 1348, 1348, 9, 78, 12540, 0, 3600, 14, 1350, 5771), + (5771, 1348, 1348, 1348, 1348, 10, 79, 12541, 0, 3600, 14, 5770, 5772), + (5772, 1348, 1348, 1348, 1348, 12, 80, 12542, 0, 3600, 14, 5771, 7184), + (5776, -1, -1, 5776, 5776, 7, 76, -1, 0, 0, 14, -1, 5777), + (5777, -1, -1, 5776, 5776, 9, 78, -1, 0, 0, 14, 5776, 5778), + (5778, -1, -1, 5776, 5776, 12, 80, -1, 0, 0, 14, 5777, 7196), + (5779, 1178, 1178, 1178, 1178, 7, 76, 12546, 4, 900, 14, 1180, 5780), + (5780, 1178, 1178, 1178, 1178, 8, 77, 12547, 4, 900, 14, 5779, 5781), + (5781, 1178, 1178, 1178, 1178, 9, 78, 12548, 4, 900, 14, 5780, 7187), + (5789, 1383, 1383, 1383, 1383, 12, 80, 12549, 6, 300, 14, 5084, 7299), + (5790, 1195, 1195, 1195, 1195, 9, 80, 12550, 13, 2160, 14, 5079, 7300), + (5791, 131, 131, 131, 131, 8, 77, 12551, 4, 900, 14, 5072, 5792), + (5792, 131, 131, 131, 131, 9, 78, 12552, 4, 900, 14, 5791, 5793), + (5793, 131, 131, 131, 131, 10, 79, 12553, 4, 900, 14, 5792, 7301), + (5794, 1192, 1192, 1192, 1192, 8, 77, 12554, 12, 1320, 14, 5078, 5795), + (5795, 1192, 1192, 1192, 1192, 9, 78, 12555, 12, 1320, 14, 5794, 5796), + (5796, 1192, 1192, 1192, 1192, 10, 79, 12556, 12, 1320, 14, 5795, 7304), + (5797, -1, -1, 5083, 5083, 7, 76, -1, 0, 0, 14, 5120, 5798), + (5798, -1, -1, 5083, 5083, 9, 78, -1, 0, 0, 14, 5797, 5799), + (5799, -1, -1, 5083, 5083, 12, 80, -1, 0, 0, 14, 5798, -1), + (5800, 746, 746, 746, 746, 9, 78, 12557, 10, 2160, 14, 1493, 5801), + (5801, 746, 746, 746, 746, 10, 79, 12558, 10, 2160, 14, 5800, 5802), + (5802, 746, 746, 746, 746, 12, 80, 12559, 10, 2160, 14, 5801, 7307), + (5803, 1459, 1459, 1459, 1459, 7, 76, 12560, 11, 1800, 14, 5082, 5804), + (5804, 1459, 1459, 1459, 1459, 9, 78, 12561, 11, 1800, 14, 5803, 5805), + (5805, 1459, 1459, 1459, 1459, 12, 80, 12562, 11, 1800, 14, 5804, 7310), + (5806, -1, -1, 255, 255, 7, 59, -1, 0, 0, 16, -1, 5807), + (5807, -1, -1, 255, 255, 9, 59, -1, 0, 0, 16, 5806, 5808), + (5808, -1, -1, 255, 255, 12, 59, -1, 0, 0, 16, 5807, 10623), + (5809, 5833, 5833, 5833, 5833, 9, 85, 20184, 72, 900, 16, -1, -1), + (5819, 1498, 1498, 1498, 1498, 7, 76, 12563, 12, 1320, 14, 5060, 5820), + (5820, 1498, 1498, 1498, 1498, 9, 78, 12564, 12, 1320, 14, 5819, 5821), + (5821, 1498, 1498, 1498, 1498, 12, 80, 12565, 12, 1320, 14, 5820, 7408), + (5822, 757, -1, 757, 757, 7, 76, 12566, 6, 1800, 14, 5053, 5823), + (5823, 757, -1, 757, 757, 9, 78, 12567, 6, 1800, 14, 5822, 5824), + (5824, 757, -1, 757, 757, 12, 80, 12568, 6, 1800, 14, 5823, 7411), + (5825, -1, -1, 567, 567, 7, 76, -1, 0, 0, 14, 5061, -1), + (5826, 1495, 1495, 1495, 1495, 7, 76, 12569, 30, 900, 14, 5313, 5827), + (5827, 1495, 1495, 1495, 1495, 9, 78, 12570, 30, 900, 14, 5826, 5828), + (5828, 1495, 1495, 1495, 1495, 12, 80, 12571, 30, 900, 14, 5827, 7414), + (5829, 548, 548, 548, 548, 8, 77, 12572, 5, 900, 14, 5056, 5830), + (5830, 548, 548, 548, 548, 9, 78, 12573, 5, 900, 14, 5829, 5831), + (5831, 548, 548, 548, 548, 10, 79, 12574, 5, 900, 14, 5830, 7417), + (5832, 5105, 5105, 5105, 5105, 12, 80, 12575, 11, 600, 14, 5105, 7420), + (5849, 54009, 54009, 54009, 54009, 7, 73, 12576, 22, 12, 14, -1, 12923), + (5850, -1, -1, 781, 781, 8, 77, -1, 0, 0, 14, 781, 7284), + (5854, 773, -1, 773, 773, 7, 76, 12580, 5, 1800, 14, 775, 5855), + (5855, 773, -1, 773, 773, 9, 78, 12581, 5, 1800, 14, 5854, 5856), + (5856, 773, -1, 773, 773, 12, 80, 12582, 5, 1800, 14, 5855, 7276), + (5857, 1242, 1242, 1242, 1242, 7, 76, 12577, 9, 1320, 14, 1244, 5858), + (5858, 1242, 1242, 1242, 1242, 9, 78, 12578, 9, 1320, 14, 5857, 5859), + (5859, 1242, 1242, 1242, 1242, 12, 80, 12579, 9, 1320, 14, 5858, 7285), + (5860, -1, -1, 649, 649, 7, 76, -1, 0, 0, 14, 651, 5861), + (5861, -1, -1, 649, 649, 9, 78, -1, 0, 0, 14, 5860, 5862), + (5862, -1, -1, 649, 649, 12, 80, -1, 0, 0, 14, 5861, -1), + (5868, 1239, 1239, 1239, 1239, 12, 80, 13224, 6, 600, 14, 1239, 7275), + (5869, 4890, -1, 4890, 4890, 9, 77, 12587, 3, 8640, 14, 4890, 5871), + (5870, 54010, 54010, 54010, 54010, 7, 73, 12828, 22, 6, 14, -1, -1), + (5871, 4890, -1, 4890, 4890, 9, 79, 16440, 3, 8640, 15, 5869, 5872), + (5872, 4890, -1, 4890, 4890, 9, 81, 21745, 3, 8640, 16, 5871, 14280), + (5879, 167, 167, 167, 167, 10, 79, 12588, 14, 900, 14, 167, 7249), + (5880, -1, -1, 1504, 1504, 5, 76, -1, 0, 0, 14, 1506, 5881), + (5881, -1, -1, 1504, 1504, 5, 78, -1, 0, 0, 14, 5880, 5882), + (5882, -1, -1, 1504, 1504, 5, 80, -1, 0, 0, 14, 5881, 7260), + (5883, 520, 520, 520, 520, 12, 76, 12589, 6, 540, 14, 1509, 5884), + (5884, 520, 520, 520, 520, 12, 78, 12590, 6, 540, 14, 5883, 5885), + (5885, 520, 520, 520, 520, 12, 80, 12591, 6, 540, 14, 5884, 7250), + (5886, -1, -1, 1577, 1577, 7, 76, -1, 0, 0, 14, 1579, 5887), + (5887, -1, -1, 1577, 1577, 9, 78, -1, 0, 0, 14, 5886, 5888), + (5888, -1, -1, 1577, 1577, 12, 80, -1, 0, 0, 14, 5887, 7263), + (5889, -1, -1, 795, 795, 7, 76, -1, 0, 0, 14, 4899, 5890), + (5890, -1, -1, 795, 795, 9, 78, -1, 0, 0, 14, 5889, 5891), + (5891, -1, -1, 795, 795, 12, 80, -1, 0, 0, 14, 5890, 7267), + (5892, 4903, 4903, 4903, 4903, 9, 76, 12592, 9, 1320, 14, 4903, 7253), + (5893, 4906, 4906, 4906, 4906, 9, 76, 12593, 9, 1320, 14, 4906, 7254), + (5894, 4909, 4909, 4909, 4909, 9, 76, 12594, 16, 1320, 14, 4909, 7255), + (5895, 4912, 4912, 4912, 4912, 9, 76, 12595, 16, 1320, 14, 4912, 7256), + (5909, -1, -1, 815, 815, 7, 76, -1, 0, 0, 14, 5145, 5910), + (5910, -1, -1, 815, 815, 8, 77, -1, 0, 0, 14, 5909, 5911), + (5911, -1, -1, 815, 815, 9, 78, -1, 0, 0, 14, 5910, 5912), + (5912, -1, -1, 815, 815, 10, 79, -1, 0, 0, 14, 5911, 5913), + (5913, -1, -1, 815, 815, 12, 80, -1, 0, 0, 14, 5912, 7634), + (5914, 1355, 1355, 1355, 1355, 6, 76, 12596, 3, 60, 14, 5242, 5915), + (5915, 1355, 1355, 1355, 1355, 6, 78, 12597, 3, 60, 14, 5914, 5916), + (5916, 1355, 1355, 1355, 1355, 6, 80, 12598, 3, 60, 14, 5915, 7172), + (5917, -1, -1, 820, 820, 5, 76, -1, 0, 0, 14, 4815, 5918), + (5918, -1, -1, 820, 820, 5, 78, -1, 0, 0, 14, 5917, 5919), + (5919, -1, -1, 820, 820, 5, 80, -1, 0, 0, 14, 5918, 7163), + (5922, -1, -1, 807, 807, 5, 76, -1, 0, 0, 14, 1270, 5923), + (5923, -1, -1, 807, 807, 5, 78, -1, 0, 0, 14, 5922, 5924), + (5924, -1, -1, 807, 807, 5, 80, -1, 0, 0, 14, 5923, 7628), + (5939, -1, -1, 5264, 5264, 7, 76, -1, 0, 0, 14, 5268, 5940), + (5940, -1, -1, 5264, 5264, 8, 77, -1, 0, 0, 14, 5939, 5941), + (5941, -1, -1, 5264, 5264, 9, 78, -1, 0, 0, 14, 5940, 5942), + (5942, -1, -1, 5264, 5264, 10, 79, -1, 0, 0, 14, 5941, 5943), + (5943, -1, -1, 5264, 5264, 12, 80, -1, 0, 0, 14, 5942, 7204), + (5944, -1, -1, 4924, 4924, 9, 78, -1, 0, 0, 14, 4926, 5945), + (5945, -1, -1, 4924, 4924, 10, 79, -1, 0, 0, 14, 5944, 5946), + (5946, -1, -1, 4924, 4924, 12, 80, -1, 0, 0, 14, 5945, -1), + (5947, 1274, 1274, 1274, 1274, 9, 78, 12599, 9, 540, 14, 4866, 5948), + (5948, 1274, 1274, 1274, 1274, 10, 79, 12600, 9, 540, 14, 5947, 5949), + (5949, 1274, 1274, 1274, 1274, 12, 80, 12601, 9, 540, 14, 5948, 7199), + (5950, -1, -1, 1511, 1511, 12, 80, -1, 0, 0, 14, 1513, 5951), + (5951, -1, -1, 1511, 1511, 12, 80, -1, 0, 0, 14, 5950, 5952), + (5952, -1, -1, 1511, 1511, 12, 80, -1, 0, 0, 14, 5951, -1), + (5953, 184, 184, 184, 184, 10, 79, 12602, 5, 4320, 14, 184, 7203), + (5954, -1, -1, 4861, 4861, 7, 76, -1, 0, 0, 14, 4863, 5955), + (5955, -1, -1, 4861, 4861, 9, 78, -1, 0, 0, 14, 5954, 5956), + (5956, -1, -1, 4861, 4861, 12, 80, -1, 0, 0, 14, 5955, 7215), + (5969, 534, 534, 534, 534, 7, 76, 12603, 4, 2160, 14, 5043, 5970), + (5970, 534, 534, 534, 534, 9, 78, 12604, 4, 2160, 14, 5969, 5971), + (5971, 534, 534, 534, 534, 12, 80, 12605, 4, 2160, 14, 5970, 7329), + (5972, -1, -1, 593, 593, 7, 76, -1, 0, 0, 14, 595, -1), + (5973, -1, -1, 596, 596, 7, 76, -1, 0, 0, 14, 598, -1), + (5975, 5095, 5095, 5095, 5095, 7, 76, 12606, 10, 900, 14, 5097, 5976), + (5976, 5095, 5095, 5095, 5095, 9, 78, 12607, 10, 900, 14, 5975, 5977), + (5977, 5095, 5095, 5095, 5095, 12, 80, 12608, 10, 900, 14, 5976, 7332), + (5984, 5984, 5984, 5984, 5984, 12, 80, 12609, 2, 30, 14, -1, 7335), + (5999, 645, -1, 645, 645, 10, 79, 12610, 4, 5, 14, 645, 10739), + (6000, 545, 545, 545, 545, 7, 76, 12611, 3, 900, 14, 4999, 6001), + (6001, 545, 545, 545, 545, 9, 78, 12612, 3, 900, 14, 6000, 6002), + (6002, 545, 545, 545, 545, 12, 80, 12613, 3, 900, 14, 6001, 7344), + (6003, -1, -1, 1616, 1616, 7, 76, -1, 0, 0, 14, 4996, 6004), + (6004, -1, -1, 1616, 1616, 8, 77, -1, 0, 0, 14, 6003, 6005), + (6005, -1, -1, 1616, 1616, 9, 78, -1, 0, 0, 14, 6004, 6006), + (6006, -1, -1, 1616, 1616, 10, 79, -1, 0, 0, 14, 6005, 6007), + (6007, -1, -1, 1616, 1616, 12, 80, -1, 0, 0, 14, 6006, 7637), + (6008, 1345, 1345, 1345, 1345, 8, 77, 12614, 6, 900, 14, 5005, 6009), + (6009, 1345, 1345, 1345, 1345, 9, 78, 12615, 6, 900, 14, 6008, 6010), + (6010, 1345, 1345, 1345, 1345, 10, 79, 12616, 6, 900, 14, 6009, 7347), + (6011, -1, -1, 864, 864, 12, 80, -1, 0, 0, 14, 4985, 6012), + (6012, -1, -1, 864, 864, 12, 80, -1, 0, 0, 14, 6011, 6013), + (6013, -1, -1, 864, 864, 12, 80, -1, 0, 0, 14, 6012, 7353), + (6014, -1, -1, 5248, 5248, 7, 76, -1, 0, 0, 14, 5250, 6015), + (6015, -1, -1, 5248, 5248, 9, 78, -1, 0, 0, 14, 6014, 6016), + (6016, -1, -1, 5248, 5248, 12, 80, -1, 0, 0, 14, 6015, 7356), + (6017, -1, -1, 644, 644, 7, 73, -1, 0, 0, 14, 4988, 6018), + (6018, -1, -1, 644, 644, 9, 75, -1, 0, 0, 14, 6017, 6019), + (6019, -1, -1, 644, 644, 12, 77, -1, 0, 0, 14, 6018, 7359), + (6020, -1, -1, 6020, 6020, 2, 65, -1, 0, 0, 14, -1, 6021), + (6021, -1, -1, 6020, 6020, 2, 65, -1, 0, 0, 14, 6020, 6022), + (6022, -1, -1, 6020, 6020, 2, 65, -1, 0, 0, 14, 6021, 6045), + (6023, -1, -1, 119, 119, 12, 85, -1, 0, 0, 16, 7567, 6024), + (6024, -1, -1, 119, 119, 12, 85, -1, 0, 0, 16, 6023, 6025), + (6025, -1, -1, 119, 119, 12, 85, -1, 0, 0, 16, 6024, 12548), + (6026, -1, -1, 1004, 1004, 7, 81, -1, 0, 0, 16, -1, 6027), + (6027, -1, -1, 1004, 1004, 9, 81, -1, 0, 0, 16, 6026, 6028), + (6028, -1, -1, 1004, 1004, 12, 81, -1, 0, 0, 16, 6027, -1), + (6029, -1, -1, 1304, 1304, 7, 76, -1, 0, 0, 14, 1306, 6030), + (6030, -1, -1, 1304, 1304, 9, 78, -1, 0, 0, 14, 6029, 6031), + (6031, -1, -1, 1304, 1304, 12, 80, -1, 0, 0, 14, 6030, 7148), + (6032, -1, -1, 1604, 1604, 7, 69, -1, 0, 0, 14, 5294, 6033), + (6033, -1, -1, 1604, 1604, 9, 71, -1, 0, 0, 14, 6032, 6034), + (6034, -1, -1, 1604, 1604, 12, 73, -1, 0, 0, 14, 6033, 7131), + (6035, -1, -1, 846, 846, 7, 76, -1, 0, 0, 14, 4950, 6036), + (6036, -1, -1, 846, 846, 9, 78, -1, 0, 0, 14, 6035, 6037), + (6037, -1, -1, 846, 846, 12, 80, -1, 0, 0, 14, 6036, 7151), + (6038, 5022, 5022, 5022, 5022, 7, 76, 23988, 5, 600, 14, 5024, 6039), + (6039, 5022, 5022, 5022, 5022, 9, 78, 23989, 5, 600, 14, 6038, 6040), + (6040, 5022, 5022, 5022, 5022, 12, 80, 23990, 5, 600, 14, 6039, 15628), + (6041, 5028, -1, 5028, 5028, 9, 78, 12621, 4, 900, 14, 5028, -1), + (6042, -1, -1, 1543, 1543, 7, 76, -1, 0, 0, 14, 4953, 6043), + (6043, -1, -1, 1543, 1543, 9, 78, -1, 0, 0, 14, 6042, 6044), + (6044, -1, -1, 1543, 1543, 12, 80, -1, 0, 0, 14, 6043, 7134), + (6045, -1, -1, 6020, 6020, 2, 66, -1, 0, 0, 14, 6022, 6046), + (6046, -1, -1, 6020, 6020, 2, 68, -1, 0, 0, 14, 6045, 6047), + (6047, -1, -1, 6020, 6020, 2, 70, -1, 0, 0, 14, 6046, 6048), + (6048, -1, -1, 6020, 6020, 2, 71, -1, 0, 0, 14, 6047, 6049), + (6049, -1, -1, 6020, 6020, 2, 73, -1, 0, 0, 14, 6048, 6050), + (6050, -1, -1, 6020, 6020, 2, 75, -1, 0, 0, 14, 6049, 6057), + (6051, -1, -1, 6051, 6051, 3, 76, -1, 0, 0, 14, -1, 6052), + (6052, -1, -1, 6051, 6051, 3, 78, -1, 0, 0, 14, 6051, 6053), + (6053, -1, -1, 6051, 6051, 3, 80, -1, 0, 0, 14, 6052, 7601), + (6054, 4931, 4931, 4931, 4931, 7, 76, 12756, 4, 600, 14, 4933, 6055), + (6055, 4931, 4931, 4931, 4931, 7, 78, 12757, 4, 600, 14, 6054, 6056), + (6056, 4931, 4931, 4931, 4931, 7, 80, 12758, 4, 600, 14, 6055, 7291), + (6057, -1, -1, 6020, 6020, 2, 76, -1, 0, 0, 14, 6050, 6058), + (6058, -1, -1, 6020, 6020, 2, 78, -1, 0, 0, 14, 6057, 6059), + (6059, -1, -1, 6020, 6020, 2, 80, -1, 0, 0, 14, 6058, 7169), + (6060, -1, -1, 6540, 6540, 8, 76, -1, 0, 0, 14, -1, 6061), + (6061, -1, -1, 6540, 6540, 8, 76, -1, 0, 0, 14, 6060, 6470), + (6063, -1, -1, 589, 589, 7, 76, -1, 0, 0, 14, 5272, 6064), + (6064, -1, -1, 589, 589, 9, 78, -1, 0, 0, 14, 6063, 6065), + (6065, -1, -1, 589, 589, 12, 80, -1, 0, 0, 14, 6064, 7390), + (6066, -1, -1, 1313, 1313, 7, 76, -1, 0, 0, 14, 5031, 6067), + (6067, -1, -1, 1313, 1313, 7, 76, -1, 0, 0, 14, 6066, 6068), + (6068, -1, -1, 1313, 1313, 8, 77, -1, 0, 0, 14, 6067, 6069), + (6069, -1, -1, 1313, 1313, 9, 78, -1, 0, 0, 14, 6068, 6070), + (6070, -1, -1, 1313, 1313, 10, 79, -1, 0, 0, 14, 6069, 6071), + (6071, -1, -1, 1313, 1313, 12, 80, -1, 0, 0, 14, 6070, 7393), + (6072, -1, -1, 210, 210, 8, 77, -1, 0, 0, 14, 1318, 6073), + (6073, -1, -1, 210, 210, 9, 78, -1, 0, 0, 14, 6072, 6074), + (6074, -1, -1, 210, 210, 10, 79, -1, 0, 0, 14, 6073, 7399), + (6075, -1, -1, 895, 895, 7, 76, -1, 0, 0, 14, 899, 6076), + (6076, -1, -1, 895, 895, 8, 77, -1, 0, 0, 14, 6075, 6077), + (6077, -1, -1, 895, 895, 9, 78, -1, 0, 0, 14, 6076, 6078), + (6078, -1, -1, 895, 895, 10, 79, -1, 0, 0, 14, 6077, 6079), + (6079, -1, -1, 895, 895, 12, 80, -1, 0, 0, 14, 6078, 7402), + (6080, -1, -1, 683, 683, 5, 75, -1, 0, 0, 14, 5305, 6081), + (6081, -1, -1, 683, 683, 5, 75, -1, 0, 0, 14, 6080, 7604), + (6082, -1, -1, 6084, 6084, 5, 85, 0, 0, 0, 17, -1, 6083), + (6083, -1, -1, 6084, 6084, 5, 87, 0, 0, 0, 17, 6082, 6084), + (6084, -1, -1, 6084, 6084, 5, 89, 0, 0, 0, 17, 6083, 13366), + (6085, -1, -1, 6761, 6761, 10, 81, -1, 0, 0, 16, 6763, 6086), + (6086, -1, -1, 6761, 6761, 11, 83, -1, 0, 0, 16, 6085, 6087), + (6087, -1, -1, 6761, 6761, 12, 85, -1, 0, 0, 16, 6086, 10763), + (6088, -1, -1, 6088, 6088, 9, 85, 0, 0, 0, 17, -1, 6089), + (6089, -1, -1, 6088, 6088, 12, 87, 0, 0, 0, 17, 6088, 6090), + (6090, -1, -1, 6088, 6088, 15, 89, 0, 0, 0, 17, 6089, -1), + (6092, 5251, 5251, 5251, 5251, 7, 76, 12635, 13, 900, 14, 5253, 6093), + (6093, 5251, 5251, 5251, 5251, 9, 78, 12636, 13, 900, 14, 6092, 6094), + (6094, 5251, 5251, 5251, 5251, 12, 80, 12637, 13, 900, 14, 6093, 7472), + (6095, 513, 513, 513, 513, 7, 76, 12638, 4, 120, 14, 515, 6096), + (6096, 513, 513, 513, 513, 9, 78, 12639, 4, 120, 14, 6095, 6097), + (6097, 513, 513, 513, 513, 12, 80, 12640, 4, 120, 14, 6096, 7475), + (6098, 1327, 1327, 1327, 1327, 7, 76, 12641, 10, 900, 14, 5316, 6099), + (6099, 1327, 1327, 1327, 1327, 9, 78, 12642, 10, 900, 14, 6098, 6100), + (6100, 1327, 1327, 1327, 1327, 12, 80, 12643, 10, 900, 14, 6099, 7460), + (6101, 153, 153, 153, 153, 12, 80, 12644, 3, 2160, 14, 5068, 7468), + (6102, 146, 146, 146, 146, 8, 77, 12645, 2, 180, 14, 5069, 7466), + (6103, 528, 528, 528, 528, 7, 76, 12646, 5, 720, 14, 901, 6104), + (6104, 528, 528, 528, 528, 9, 78, 12647, 5, 720, 14, 6103, 6105), + (6105, 528, 528, 528, 528, 12, 80, 12648, 5, 720, 14, 6104, 7469), + (6106, 6106, 6106, 6106, 6106, 4, 67, 21965, 13, 4320, 16, -1, 6107), + (6107, 6106, 6106, 6106, 6106, 5, 68, 21966, 13, 4320, 16, 6106, 6108), + (6108, 6106, 6106, 6106, 6106, 6, 69, 21967, 13, 4320, 16, 6107, 6109), + (6109, 6106, 6106, 6106, 6106, 7, 77, 21968, 13, 4320, 16, 6108, 6110), + (6110, 6106, 6106, 6106, 6106, 8, 78, 21969, 13, 4320, 16, 6109, 6111), + (6111, 6106, 6106, 6106, 6106, 9, 79, 21970, 13, 4320, 16, 6110, -1), + (6112, -1, -1, 6112, 6112, 5, 85, -1, 0, 0, 17, -1, 12966), + (6113, -1, -1, 6113, 6113, 9, 85, 0, 0, 0, 17, -1, 6114), + (6114, -1, -1, 6113, 6113, 12, 87, 0, 0, 0, 17, 6113, 6115), + (6115, -1, -1, 6113, 6113, 15, 89, 0, 0, 0, 17, 6114, -1), + (6119, -1, -1, 6119, 6119, 6, 76, -1, 0, 0, 14, -1, 6120), + (6120, -1, -1, 6119, 6119, 6, 77, -1, 0, 0, 14, 6119, 6121), + (6121, -1, -1, 6119, 6119, 6, 78, -1, 0, 0, 14, 6120, 6122), + (6122, -1, -1, 6119, 6119, 6, 79, -1, 0, 0, 14, 6121, 6123), + (6123, -1, -1, 6119, 6119, 6, 80, -1, 0, 0, 14, 6122, 7526), + (6124, -1, -1, 5263, 5263, 3, 71, -1, 0, 0, 12, -1, 6125), + (6125, -1, -1, 5263, 5263, 6, 73, -1, 0, 0, 12, 6124, 6126), + (6126, -1, -1, 5263, 5263, 9, 75, -1, 0, 0, 12, 6125, 6127), + (6127, -1, -1, 5263, 5263, 10, 76, -1, 0, 0, 14, 6126, 6128), + (6128, -1, -1, 5263, 5263, 11, 78, -1, 0, 0, 14, 6127, 6129), + (6129, -1, -1, 5263, 5263, 12, 80, -1, 0, 0, 14, 6128, 12463), + (6130, -1, -1, 586, 586, 7, 76, -1, 0, 0, 14, 588, 6131), + (6131, -1, -1, 586, 586, 7, 76, -1, 0, 0, 14, 6130, 6132), + (6132, -1, -1, 586, 586, 7, 76, -1, 0, 0, 14, 6131, -1), + (6133, 1351, 1351, 1351, 1351, 8, 77, 12649, 5, 30, 14, 1351, 7109), + (6134, 4849, 4849, 4849, 4849, 7, 76, 12650, 7, 1800, 14, 4849, 7110), + (6135, 54006, 54006, 54006, 54006, 7, 76, 12651, 18, 180, 14, -1, 7111), + (6136, -1, -1, 6136, 6136, 7, 76, -1, 0, 0, 10, -1, 6137), + (6149, 921, 921, 921, 921, 9, 79, 12652, 8, 60, 14, 5280, 7245), + (6150, 922, 922, 922, 922, 9, 78, 12653, 8, 60, 14, 5281, 7236), + (6151, 923, 923, 923, 923, 9, 77, 12654, 8, 60, 14, 5282, 7235), + (6152, 1334, 1334, 1334, 1334, 9, 78, 12655, 11, 4320, 14, 1336, 6153), + (6153, 1334, 1334, 1334, 1334, 10, 79, 12656, 11, 4320, 14, 6152, 6154), + (6154, 1334, 1334, 1334, 1334, 12, 80, 12657, 11, 4320, 14, 6153, 7239), + (6155, 4944, -1, 4944, 4944, 7, 76, 12658, 0, 1, 14, 4946, 6156), + (6156, 4944, -1, 4944, 4944, 9, 78, 12659, 0, 1, 14, 6155, 6157), + (6157, 4944, -1, 4944, 4944, 12, 80, 12660, 0, 1, 14, 6156, 7229), + (6158, 1337, 1337, 1337, 1337, 8, 77, 12661, 13, 4320, 14, 1339, 6159), + (6159, 1337, 1337, 1337, 1337, 9, 78, 12662, 13, 4320, 14, 6158, 6160), + (6160, 1337, 1337, 1337, 1337, 10, 79, 12663, 13, 4320, 14, 6159, 14338), + (6161, 1478, -1, 1478, 1478, 9, 78, 12664, 0, 1, 14, 1480, 6162), + (6162, 1478, -1, 1478, 1478, 10, 79, 12665, 0, 1, 14, 6161, 6163), + (6163, 1478, -1, 1478, 1478, 12, 80, 12666, 0, 1, 14, 6162, 7242), + (6200, 6533, 6533, 6533, 6533, 10, 79, 12768, 15, 600, 14, -1, 7428), + (6201, 6534, 6534, 6534, 6534, 9, 78, 12769, 16, 900, 14, -1, 7429), + (6202, -1, -1, 6535, 6535, 5, 70, -1, 0, 0, 14, -1, 6203), + (6203, -1, -1, 6535, 6535, 5, 70, -1, 0, 0, 14, 6202, 6204), + (6204, -1, -1, 6535, 6535, 5, 70, -1, 0, 0, 14, 6203, -1), + (6205, 6536, 6536, 6536, 6536, 7, 76, 12712, 39, 5, 14, -1, -1), + (6206, 6537, 6537, 6537, 6537, 7, 76, 12770, 30, 900, 14, -1, 6207), + (6207, 6537, 6537, 6537, 6537, 8, 77, 12771, 30, 900, 14, 6206, 6208), + (6208, 6537, 6537, 6537, 6537, 9, 78, 12772, 30, 900, 14, 6207, 7606), + (6209, -1, -1, 6538, 6538, 7, 76, -1, 0, 0, 14, -1, 6210), + (6210, -1, -1, 6538, 6538, 9, 78, -1, 0, 0, 14, 6209, 6211), + (6211, -1, -1, 6538, 6538, 12, 80, -1, 0, 0, 14, 6210, 7478), + (6212, 6539, 6539, 6539, 6539, 6, 71, 12776, 18, 1800, 14, -1, 6213), + (6213, 6539, 6539, 6539, 6539, 6, 74, 12777, 18, 1800, 14, 6212, 6214), + (6214, 6539, 6539, 6539, 6539, 6, 77, 12778, 18, 1800, 14, 6213, 7609), + (6215, -1, -1, 6540, 6540, 8, 71, -1, 0, 0, 14, -1, 6216), + (6216, -1, -1, 6540, 6540, 8, 72, -1, 0, 0, 14, 6215, 6217), + (6217, -1, -1, 6540, 6540, 8, 73, -1, 0, 0, 14, 6216, 6300), + (6218, 6218, 6218, 6218, 6218, 7, 76, 12782, 0, 1, 14, -1, 7488), + (6219, 6542, 6542, 6542, 6542, 7, 76, 12783, 18, 1800, 14, -1, 6220), + (6220, 6542, 6542, 6542, 6542, 9, 78, 12784, 18, 1800, 14, 6219, 6221), + (6221, 6542, 6542, 6542, 6542, 12, 80, 12785, 18, 1800, 14, 6220, -1), + (6222, 6543, 6543, 6543, 6543, 9, 72, 13143, 18, 25, 14, -1, -1), + (6223, -1, -1, 962, 962, 5, 76, -1, 0, 0, 14, 966, 6224), + (6224, -1, -1, 962, 962, 5, 77, -1, 0, 0, 14, 6223, 6225), + (6225, -1, -1, 962, 962, 5, 78, -1, 0, 0, 14, 6224, 6226), + (6226, -1, -1, 962, 962, 5, 79, -1, 0, 0, 14, 6225, 6227), + (6227, -1, -1, 962, 962, 5, 80, -1, 0, 0, 14, 6226, 10361), + (6228, -1, -1, 6545, 6545, 2, 70, -1, 0, 0, 14, -1, 6229), + (6229, -1, -1, 6545, 6545, 2, 70, -1, 0, 0, 14, 6228, 6230), + (6230, -1, -1, 6545, 6545, 2, 70, -1, 0, 0, 14, 6229, 6231), + (6231, -1, -1, 6545, 6545, 2, 70, -1, 0, 0, 14, 6230, -1), + (6232, 6232, 6232, 6232, 6232, 12, 80, 14413, 18, 900, 14, -1, 7421), + (6233, -1, -1, 477, 477, 2, 70, -1, 0, 0, 14, 479, 6234), + (6234, -1, -1, 477, 477, 2, 71, -1, 0, 0, 14, 6233, 6235), + (6235, -1, -1, 477, 477, 2, 72, -1, 0, 0, 14, 6234, 16094), + (6236, -1, -1, 6548, 6548, 6, 73, -1, 0, 0, 14, -1, 6237), + (6237, -1, -1, 6548, 6548, 6, 75, -1, 0, 0, 14, 6236, 6238), + (6238, -1, -1, 6548, 6548, 8, 77, -1, 0, 0, 14, 6237, 12929), + (6240, -1, -1, 767, 767, 3, 65, -1, 0, 0, 14, -1, 6241), + (6241, -1, -1, 767, 767, 6, 65, -1, 0, 0, 14, 6240, 6242), + (6242, -1, -1, 767, 767, 9, 65, -1, 0, 0, 14, 6241, 6243), + (6243, -1, -1, 767, 767, 3, 67, -1, 0, 0, 14, 6242, 6244), + (6244, -1, -1, 767, 767, 6, 68, -1, 0, 0, 14, 6243, 6245), + (6245, -1, -1, 767, 767, 9, 69, -1, 0, 0, 14, 6244, 12426), + (6249, 6552, 6552, 6552, 6552, 5, 70, -1, 0, 0, 14, -1, 6250), + (6250, 6552, 6552, 6552, 6552, 6, 72, -1, 0, 0, 14, 6249, 6251), + (6251, 6552, 6552, 6552, 6552, 6, 74, -1, 0, 0, 14, 6250, 6252), + (6252, 6552, 6552, 6552, 6552, 7, 76, -1, 0, 0, 14, 6251, 6253), + (6253, 6552, 6552, 6552, 6552, 9, 78, -1, 0, 0, 14, 6252, 7279), + (6254, 616, 616, 616, 616, 6, 73, 12765, 7, 900, 14, 1250, 6255), + (6255, 616, 616, 616, 616, 7, 76, 12766, 7, 900, 14, 6254, 6256), + (6256, 616, 616, 616, 616, 10, 79, 12767, 7, 900, 14, 6255, 7257), + (6257, -1, -1, 86, 86, 2, 55, -1, 0, 0, 14, -1, 6258), + (6258, -1, -1, 86, 86, 4, 55, -1, 0, 0, 14, 6257, 6259), + (6259, -1, -1, 86, 86, 6, 55, -1, 0, 0, 14, 6258, 8223), + (6260, -1, -1, 495, 495, 6, 73, -1, 0, 0, 14, 497, 6261), + (6261, -1, -1, 495, 495, 7, 76, -1, 0, 0, 14, 6260, 6262), + (6262, -1, -1, 495, 495, 10, 79, -1, 0, 0, 14, 6261, 10666), + (6266, -1, -1, 6557, 6557, 6, 73, -1, 0, 0, 14, -1, 6267), + (6267, -1, -1, 6557, 6557, 7, 76, -1, 0, 0, 14, 6266, 6268), + (6268, -1, -1, 6557, 6557, 10, 79, -1, 0, 0, 14, 6267, -1), + (6269, -1, -1, 6558, 6558, 6, 73, -1, 0, 0, 14, -1, 6270), + (6270, -1, -1, 6558, 6558, 7, 76, -1, 0, 0, 14, 6269, 6271), + (6271, -1, -1, 6558, 6558, 10, 79, -1, 0, 0, 14, 6270, -1), + (6272, -1, -1, 6559, 6559, 6, 73, -1, 0, 0, 14, -1, 6273), + (6273, -1, -1, 6559, 6559, 7, 75, -1, 0, 0, 14, 6272, 6274), + (6274, -1, -1, 6559, 6559, 10, 77, -1, 0, 0, 14, 6273, 7137), + (6275, -1, -1, 6560, 6560, 6, 73, -1, 0, 0, 14, -1, 6276), + (6276, -1, -1, 6560, 6560, 7, 76, -1, 0, 0, 14, 6275, 6277), + (6277, -1, -1, 6560, 6560, 10, 79, -1, 0, 0, 14, 6276, 16266), + (6278, 6561, 6561, 6561, 6561, 7, 76, 12795, 32, 30, 14, -1, 6279), + (6279, 6561, 6561, 6561, 6561, 7, 76, 12796, 32, 30, 14, 6278, 6280), + (6280, 6561, 6561, 6561, 6561, 7, 76, 12797, 32, 30, 14, 6279, 7422), + (6281, 6563, 6563, 6563, 6563, 9, 78, 13144, 36, 8, 14, -1, 12995), + (6282, 6562, 6562, 6562, 6562, 6, 72, 12798, 39, 1, 14, -1, -1), + (6283, -1, -1, 6564, 6564, 6, 73, -1, 0, 0, 14, -1, 6284), + (6284, -1, -1, 6564, 6564, 7, 76, -1, 0, 0, 14, 6283, 6285), + (6285, -1, -1, 6564, 6564, 10, 79, -1, 0, 0, 14, 6284, 7112), + (6286, 6565, 6565, 6565, 6565, 7, 76, 12802, 17, 45, 14, -1, 7115), + (6287, -1, -1, 6566, 6566, 6, 73, -1, 0, 0, 14, -1, 6288), + (6288, -1, -1, 6566, 6566, 7, 76, -1, 0, 0, 14, 6287, 6289), + (6289, -1, -1, 6566, 6566, 10, 79, -1, 0, 0, 14, 6288, -1), + (6290, 6290, 6290, 6290, 6290, 6, 71, 12803, 0, 1, 14, -1, 6291), + (6291, 6290, 6290, 6290, 6290, 6, 73, 12804, 0, 1, 14, 6290, 6292), + (6292, 6290, 6290, 6290, 6290, 6, 75, 12805, 0, 1, 14, 6291, 6293), + (6293, 6290, 6290, 6290, 6290, 7, 76, 12806, 0, 1, 14, 6292, 6294), + (6294, 6290, 6290, 6290, 6290, 9, 78, 12807, 0, 1, 14, 6293, 6295), + (6295, 6290, 6290, 6290, 6290, 12, 80, 12808, 0, 1, 14, 6294, 7223), + (6296, 619, 619, 619, 619, 6, 73, 12759, 6, 900, 14, 722, 6297), + (6297, 619, 619, 619, 619, 6, 73, 12760, 6, 900, 14, 6296, 6298), + (6298, 619, 619, 619, 619, 6, 73, 12761, 6, 900, 14, 6297, 7226), + (6299, 6299, 6299, 6299, 6299, 9, 65, 12786, 18, 12, 14, -1, -1), + (6300, -1, -1, 6540, 6540, 8, 74, -1, 0, 0, 14, 6217, 6301), + (6301, -1, -1, 6540, 6540, 8, 75, -1, 0, 0, 14, 6300, 6472), + (6302, -1, -1, 6302, 6302, 5, 81, 0, 0, 0, 16, -1, 6303), + (6303, -1, -1, 6302, 6302, 5, 83, 0, 0, 0, 16, 6302, 6304), + (6304, -1, -1, 6302, 6302, 5, 85, 0, 0, 0, 16, 6303, 11011), + (6307, 1358, 1358, 1358, 1358, 6, 71, 13168, 3, 60, 14, 1360, 6308), + (6308, 1358, 1358, 1358, 1358, 6, 73, 13169, 3, 60, 14, 6307, 6309), + (6309, 1358, 1358, 1358, 1358, 6, 75, 13170, 3, 60, 14, 6308, 6310), + (6310, 1358, 1358, 1358, 1358, 6, 76, 13171, 3, 60, 14, 6309, 6311), + (6311, 1358, 1358, 1358, 1358, 6, 78, 13172, 3, 60, 14, 6310, 6312), + (6312, 1358, 1358, 1358, 1358, 6, 80, 13173, 3, 60, 14, 6311, 7157), + (6313, 1352, 1352, 1352, 1352, 6, 71, 13174, 3, 60, 14, 1354, 6314), + (6314, 1352, 1352, 1352, 1352, 6, 73, 13175, 3, 60, 14, 6313, 6315), + (6315, 1352, 1352, 1352, 1352, 6, 75, 13177, 3, 60, 14, 6314, 6316), + (6316, 1352, 1352, 1352, 1352, 6, 76, 13178, 3, 60, 14, 6315, 6317), + (6317, 1352, 1352, 1352, 1352, 6, 78, 13179, 3, 60, 14, 6316, 6318), + (6318, 1352, 1352, 1352, 1352, 6, 80, 13180, 3, 60, 14, 6317, 7154), + (6319, -1, -1, 501, 501, 6, 73, -1, 0, 0, 14, 503, 6320), + (6320, -1, -1, 501, 501, 6, 75, -1, 0, 0, 14, 6319, 6321), + (6321, -1, -1, 501, 501, 6, 77, -1, 0, 0, 14, 6320, 6528), + (6322, -1, -1, 6322, 6322, 6, 73, -1, 0, 0, 14, -1, 6323), + (6323, -1, -1, 6322, 6322, 6, 75, -1, 0, 0, 14, 6322, 6324), + (6324, -1, -1, 6322, 6322, 6, 77, -1, 0, 0, 14, 6323, -1), + (6325, 6325, 6325, 6325, 6325, 7, 73, 13213, 18, 600, 14, -1, 6326), + (6326, 6325, 6325, 6325, 6325, 7, 75, 13214, 18, 600, 14, 6325, 6327), + (6327, 6325, 6325, 6325, 6325, 7, 77, 13215, 18, 600, 14, 6326, 6361), + (6328, 6328, 6328, 6328, 6328, 7, 74, 13204, 10, 600, 14, -1, 6329), + (6329, 6328, 6328, 6328, 6328, 7, 76, 13205, 10, 600, 14, 6328, 6330), + (6330, 6328, 6328, 6328, 6328, 7, 78, 13212, 10, 600, 14, 6329, 7143), + (6331, -1, -1, 878, 878, 7, 76, -1, 0, 0, 14, 4959, 6332), + (6332, -1, -1, 878, 878, 7, 78, -1, 0, 0, 14, 6331, 7146), + (6333, 6333, 6333, 6333, 6333, 9, 59, 13167, 3, 600, 14, -1, 7266), + (6334, -1, -1, 6334, 6334, 6, 73, -1, 0, 0, 14, -1, 6335), + (6335, -1, -1, 6334, 6334, 6, 75, -1, 0, 0, 14, 6334, 6336), + (6336, -1, -1, 6334, 6334, 6, 77, -1, 0, 0, 14, 6335, -1), + (6337, -1, -1, 6337, 6337, 6, 74, -1, 0, 0, 14, -1, 6338), + (6338, -1, -1, 6337, 6337, 6, 76, -1, 0, 0, 14, 6337, 6339), + (6339, -1, -1, 6337, 6337, 6, 78, -1, 0, 0, 14, 6338, 7448), + (6340, -1, -1, 6340, 6340, 6, 74, -1, 0, 0, 14, -1, 6341), + (6341, -1, -1, 6340, 6340, 6, 76, -1, 0, 0, 14, 6340, 6342), + (6342, -1, -1, 6340, 6340, 6, 78, -1, 0, 0, 14, 6341, 7451), + (6343, -1, -1, 6343, 6343, 6, 74, -1, 0, 0, 14, -1, 6344), + (6344, -1, -1, 6343, 6343, 6, 76, -1, 0, 0, 14, 6343, 6345), + (6345, -1, -1, 6343, 6343, 6, 78, -1, 0, 0, 14, 6344, 7166), + (6346, -1, -1, 6346, 6346, 6, 74, -1, 0, 0, 14, -1, 6347), + (6347, -1, -1, 6346, 6346, 6, 76, -1, 0, 0, 14, 6346, 6348), + (6348, -1, -1, 6346, 6346, 6, 78, -1, 0, 0, 14, 6347, 7615), + (6349, -1, -1, 6349, 6349, 6, 74, -1, 0, 0, 14, -1, 6350), + (6350, -1, -1, 6349, 6349, 6, 76, -1, 0, 0, 14, 6349, 6351), + (6351, -1, -1, 6349, 6349, 6, 78, -1, 0, 0, 14, 6350, 7618), + (6352, 4894, 4894, 4894, 4894, 6, 76, 13181, 7, 2160, 14, 4896, 6353), + (6353, 4894, 4894, 4894, 4894, 6, 77, 13182, 7, 2160, 14, 6352, 6354), + (6354, 4894, 4894, 4894, 4894, 6, 78, 13183, 7, 2160, 14, 6353, 7288), + (6355, -1, -1, 6355, 6355, 6, 73, -1, 0, 0, 14, -1, 6356), + (6356, -1, -1, 6355, 6355, 6, 74, -1, 0, 0, 14, 6355, 6357), + (6357, -1, -1, 6355, 6355, 6, 75, -1, 0, 0, 14, 6356, 6358), + (6358, -1, -1, 6355, 6355, 6, 76, -1, 0, 0, 14, 6357, 6359), + (6359, -1, -1, 6355, 6355, 6, 77, -1, 0, 0, 14, 6358, 6360), + (6360, -1, -1, 6355, 6355, 6, 80, -1, 0, 0, 16, 6359, 14101), + (6361, 6325, 6325, 6325, 6325, 7, 81, 16861, 18, 600, 16, 6327, 12633), + (6362, -1, -1, 6362, 6362, 5, 77, 0, 0, 0, 16, -1, 6363), + (6363, -1, -1, 6362, 6362, 5, 79, 0, 0, 0, 16, 6362, 6364), + (6364, -1, -1, 6362, 6362, 5, 81, 0, 0, 0, 16, 6363, 6365), + (6365, -1, -1, 6362, 6362, 5, 83, 0, 0, 0, 16, 6364, 6366), + (6366, -1, -1, 6362, 6362, 5, 85, 0, 0, 0, 16, 6365, 16327), + (6370, 6370, 6370, 6370, 6370, 6, 76, 13188, 7, 600, 14, -1, 6371), + (6371, 6370, 6370, 6370, 6370, 6, 77, 13189, 7, 600, 14, 6370, 6372), + (6372, 6370, 6370, 6370, 6370, 6, 78, 13190, 7, 600, 14, 6371, 7350), + (6375, -1, -1, 6375, 6375, 6, 76, -1, 0, 0, 14, -1, 6376), + (6376, -1, -1, 6375, 6375, 6, 77, -1, 0, 0, 14, 6375, 6377), + (6377, -1, -1, 6375, 6375, 6, 78, -1, 0, 0, 14, 6376, 7644), + (6378, 209, 209, 209, 1272, 6, 76, 13501, 12, 5, 14, 1272, -1), + (6379, 6379, 6379, 6379, 6379, 6, 60, 13500, 37, 5, 14, -1, -1), + (6380, 6380, 6380, 6380, 6380, 6, 78, 13209, 39, 120, 14, -1, 6381), + (6381, 6380, 6380, 6380, 6380, 6, 79, 13210, 39, 120, 14, 6380, 6382), + (6382, 6380, 6380, 6380, 6380, 6, 80, 13211, 39, 120, 14, 6381, 7497), + (6383, -1, -1, 6383, 6383, 3, 70, -1, 0, 0, 14, -1, 6384), + (6384, -1, -1, 6383, 6383, 6, 70, -1, 0, 0, 14, 6383, 6385), + (6385, -1, -1, 6383, 6383, 9, 70, -1, 0, 0, 14, 6384, 10607), + (6386, -1, -1, 6386, 6386, 7, 72, -1, 0, 0, 14, -1, 6387), + (6387, -1, -1, 6386, 6386, 7, 74, -1, 0, 0, 14, 6386, 6388), + (6388, -1, -1, 6386, 6386, 7, 76, -1, 0, 0, 14, 6387, 6389), + (6389, -1, -1, 6386, 6386, 7, 78, -1, 0, 0, 14, 6388, 13521), + (6390, -1, -1, 65, 661, 3, 76, -1, 0, 0, 14, 4697, 6391), + (6391, -1, -1, 65, 661, 3, 77, -1, 0, 0, 14, 6390, 6392), + (6392, -1, -1, 65, 661, 3, 78, -1, 0, 0, 14, 6391, 6393), + (6393, -1, -1, 65, 661, 3, 79, -1, 0, 0, 14, 6392, 6394), + (6394, -1, -1, 65, 661, 3, 80, -1, 0, 0, 14, 6393, 7534), + (6395, -1, -1, 6395, 6395, 7, 76, -1, 0, 0, 14, -1, 6396), + (6396, -1, -1, 6395, 6395, 7, 77, -1, 0, 0, 14, 6395, 6397), + (6397, -1, -1, 6395, 6395, 7, 78, -1, 0, 0, 14, 6396, 7336), + (6398, 516, 516, 516, 516, 6, 72, 13198, 5, 480, 14, 516, 7237), + (6400, 1110, 1110, 1110, 1110, 6, 73, 13192, 3, 2160, 14, 1112, 6401), + (6401, 1110, 1110, 1110, 1110, 6, 75, 13193, 3, 2160, 14, 6400, 6402), + (6402, 1110, 1110, 1110, 1110, 6, 76, 13194, 3, 2160, 14, 6401, 7445), + (6403, -1, -1, 1107, 1107, 7, 76, -1, 0, 0, 14, 5288, 6404), + (6404, -1, -1, 1107, 1107, 9, 78, -1, 0, 0, 14, 6403, 6405), + (6405, -1, -1, 1107, 1107, 12, 80, -1, 0, 0, 14, 6404, 12432), + (6406, -1, -1, 5085, 5085, 6, 76, -1, 0, 0, 14, 5087, 6407), + (6407, -1, -1, 5085, 5085, 6, 78, -1, 0, 0, 14, 6406, 6408), + (6408, -1, -1, 5085, 5085, 6, 80, -1, 0, 0, 14, 6407, 7384), + (6409, -1, -1, 6540, 6540, 8, 71, -1, 0, 0, 14, -1, 6410), + (6410, -1, -1, 6540, 6540, 8, 72, -1, 0, 0, 14, 6409, 6411), + (6411, -1, -1, 6540, 6540, 8, 73, -1, 0, 0, 14, 6410, 6412), + (6412, -1, -1, 6540, 6540, 8, 74, -1, 0, 0, 14, 6411, 6413), + (6413, -1, -1, 6540, 6540, 8, 75, -1, 0, 0, 14, 6412, 6414), + (6414, -1, -1, 6540, 6540, 8, 76, -1, 0, 0, 14, 6413, 6415), + (6415, -1, -1, 6540, 6540, 8, 77, -1, 0, 0, 14, 6414, 6416), + (6416, -1, -1, 6540, 6540, 8, 78, -1, 0, 0, 14, 6415, 6417), + (6417, -1, -1, 6540, 6540, 8, 79, -1, 0, 0, 14, 6416, 6418), + (6418, -1, -1, 6540, 6540, 8, 80, -1, 0, 0, 14, 6417, 6474), + (6419, -1, -1, 6540, 6540, 8, 71, -1, 0, 0, 14, -1, 6420), + (6420, -1, -1, 6540, 6540, 8, 72, -1, 0, 0, 14, 6419, 6421), + (6421, -1, -1, 6540, 6540, 8, 73, -1, 0, 0, 14, 6420, 6476), + (6422, -1, -1, 6422, 6422, 3, 61, -1, 0, 0, 14, -1, 6423), + (6423, -1, -1, 6422, 6422, 3, 63, -1, 0, 0, 14, 6422, 6424), + (6424, -1, -1, 6422, 6422, 3, 65, -1, 0, 0, 14, 6423, -1), + (6425, 5007, 5007, 5007, 5007, 9, 76, 13509, 8, 2160, 14, 5009, 6426), + (6426, 5007, 5007, 5007, 5007, 9, 78, 13510, 8, 2160, 14, 6425, 6427), + (6427, 5007, 5007, 5007, 5007, 9, 80, 13511, 8, 2160, 14, 6426, 7341), + (6428, -1, -1, 1287, 1287, 3, 67, -1, 0, 0, 14, -1, 6429), + (6429, -1, -1, 1287, 1287, 6, 68, -1, 0, 0, 14, 6428, 6430), + (6430, -1, -1, 1287, 1287, 9, 69, -1, 0, 0, 14, 6429, 12472), + (6431, -1, -1, 1056, 1056, 5, 76, -1, 0, 0, 14, 1060, 6432), + (6432, -1, -1, 1056, 1056, 5, 77, -1, 0, 0, 14, 6431, 6433), + (6433, -1, -1, 1056, 1056, 5, 78, -1, 0, 0, 14, 6432, 6434), + (6434, -1, -1, 1056, 1056, 5, 79, -1, 0, 0, 14, 6433, 6435), + (6435, -1, -1, 1056, 1056, 5, 80, -1, 0, 0, 14, 6434, 7521), + (6436, -1, -1, 6436, 6436, 6, 73, -1, 0, 0, 14, -1, 6437), + (6437, -1, -1, 6436, 6436, 6, 75, -1, 0, 0, 14, 6436, 6438), + (6438, -1, -1, 6436, 6436, 8, 77, -1, 0, 0, 14, 6437, 7313), + (6439, -1, -1, 468, 468, 2, 67, -1, 0, 0, 14, 470, 6440), + (6440, -1, -1, 468, 468, 2, 69, -1, 0, 0, 14, 6439, 7316), + (6441, -1, -1, 1546, 1546, 5, 76, -1, 0, 0, 14, 4831, 12673), + (6442, -1, -1, 1471, 1471, 6, 76, -1, 0, 0, 14, 1475, 6443), + (6443, -1, -1, 1471, 1471, 6, 77, -1, 0, 0, 14, 6442, -1), + (6445, -1, -1, 6445, 6445, 2, 62, -1, 0, 0, 14, -1, 6446), + (6446, -1, -1, 6445, 6445, 2, 64, -1, 0, 0, 14, 6445, 6447), + (6447, -1, -1, 6445, 6445, 2, 66, -1, 0, 0, 14, 6446, -1), + (6448, 5109, 5109, 5109, 5109, 9, 77, 13515, 0, 1, 14, 5109, 7467), + (6449, 1520, 1520, 1520, 1520, 9, 70, 13516, 11, 900, 14, 1522, 6450), + (6450, 1520, 1520, 1520, 1520, 9, 70, 13517, 11, 900, 14, 6449, 6451), + (6451, 1520, 1520, 1520, 1520, 9, 70, 13518, 11, 900, 14, 6450, 7463), + (6452, -1, -1, 6452, 6452, 2, 71, -1, 0, 0, 14, -1, 6453), + (6453, -1, -1, 6452, 6452, 2, 72, -1, 0, 0, 14, 6452, 6454), + (6454, -1, -1, 6452, 6452, 2, 73, -1, 0, 0, 14, 6453, -1), + (6455, 6455, 6455, 6455, 6455, 2, 72, 14750, 36, 30, 14, -1, 6456), + (6456, 6455, 6455, 6455, 6455, 2, 74, 14751, 36, 30, 14, 6455, 6457), + (6457, 6455, 6455, 6455, 6455, 2, 76, 14752, 36, 30, 14, 6456, -1), + (6458, -1, -1, 6458, 6458, 3, 78, -1, 0, 0, 14, -1, 6459), + (6459, -1, -1, 6458, 6458, 3, 78, -1, 0, 0, 14, 6458, 6460), + (6460, -1, -1, 6458, 6458, 3, 78, -1, 0, 0, 14, 6459, -1), + (6461, -1, -1, 6461, 6461, 3, 78, -1, 0, 0, 14, -1, 6462), + (6462, -1, -1, 6461, 6461, 3, 78, -1, 0, 0, 14, 6461, 6463), + (6463, -1, -1, 6461, 6461, 3, 78, -1, 0, 0, 14, 6462, -1), + (6464, 967, 967, 967, 967, 6, 76, 13897, 10, 1800, 14, 969, 6465), + (6465, 967, 967, 967, 967, 6, 77, 13898, 10, 1800, 14, 6464, 6466), + (6466, 967, 967, 967, 967, 6, 78, 13899, 10, 1800, 14, 6465, 7217), + (6467, -1, -1, 6467, 6467, 3, 61, -1, 0, 0, 15, -1, 6468), + (6468, -1, -1, 6467, 6467, 3, 63, -1, 0, 0, 15, 6467, 6469), + (6469, -1, -1, 6467, 6467, 3, 65, -1, 0, 0, 15, 6468, -1), + (6470, -1, -1, 6540, 6540, 8, 76, -1, 0, 0, 15, 6061, 6471), + (6471, -1, -1, 6540, 6540, 8, 81, -1, 0, 0, 15, 6470, 12487), + (6472, -1, -1, 6540, 6540, 8, 81, -1, 0, 0, 15, 6301, 6473), + (6473, -1, -1, 6540, 6540, 8, 83, -1, 0, 0, 15, 6472, 12481), + (6474, -1, -1, 6540, 6540, 8, 81, -1, 0, 0, 15, 6418, 6475), + (6475, -1, -1, 6540, 6540, 8, 83, -1, 0, 0, 15, 6474, 12483), + (6476, -1, -1, 6540, 6540, 8, 81, -1, 0, 0, 15, 6421, 6477), + (6477, -1, -1, 6540, 6540, 8, 83, -1, 0, 0, 15, 6476, 12485), + (6478, 0, 0, 6478, 6478, 3, 81, -1, 0, 0, 16, -1, 6479), + (6479, 0, 0, 6478, 6478, 5, 83, -1, 0, 0, 16, 6478, 6480), + (6480, 0, 0, 6478, 6478, 7, 85, -1, 0, 0, 16, 6479, -1), + (6481, 0, 0, 6481, 6481, 5, 85, -1, 0, 0, 16, -1, 6482), + (6482, 0, 0, 6481, 6481, 7, 85, -1, 0, 0, 16, 6481, 6483), + (6483, 0, 0, 6481, 6481, 9, 85, -1, 0, 0, 16, 6482, 15314), + (6484, -1, -1, 7940, 7940, 5, 85, -1, 0, 0, 16, 10032, 6485), + (6485, -1, -1, 7940, 7940, 7, 85, -1, 0, 0, 16, 6484, 6486), + (6486, -1, -1, 7940, 7940, 9, 85, -1, 0, 0, 16, 6485, 15320), + (6487, 1383, 1383, 1383, 1383, 12, 85, 21812, 6, 300, 16, 10014, 14221), + (6488, 6488, 6488, 6488, 6488, 12, 85, 21806, 32, 900, 16, -1, 13383), + (6489, -1, -1, 6489, 6489, 5, 81, -1, 0, 0, 16, -1, 6490), + (6490, -1, -1, 6489, 6489, 7, 83, -1, 0, 0, 16, 6489, 6491), + (6491, -1, -1, 6489, 6489, 9, 85, -1, 0, 0, 16, 6490, 17239), + (6492, 6492, 6492, 6492, 6492, 7, 75, 21692, 52, 720, 16, -1, 6493), + (6493, 6492, 6492, 6492, 6492, 7, 77, 21693, 52, 720, 16, 6492, 6494), + (6494, 6492, 6492, 6492, 6492, 7, 79, 21694, 52, 720, 16, 6493, 6495), + (6495, 6492, 6492, 6492, 6492, 7, 81, 21695, 52, 720, 16, 6494, 6496), + (6496, 6492, 6492, 6492, 6492, 7, 83, 21696, 52, 720, 16, 6495, 6497), + (6497, 6492, 6492, 6492, 6492, 7, 85, 21697, 52, 720, 16, 6496, 10679), + (6499, 6499, 6499, 6499, 6499, 3, 75, 13512, 13, 60, 14, -1, -1), + (6500, -1, -1, 4761, 4761, 7, 76, -1, 0, 0, 14, 4763, 6501), + (6501, -1, -1, 4761, 4761, 7, 78, -1, 0, 0, 14, 6500, 6502), + (6502, -1, -1, 4761, 4761, 7, 80, -1, 0, 0, 14, 6501, -1), + (6503, -1, -1, 6503, 6503, 6, 72, -1, 0, 0, 14, -1, 6504), + (6504, -1, -1, 6503, 6503, 6, 72, -1, 0, 0, 14, 6503, 6505), + (6505, -1, -1, 6503, 6503, 6, 72, -1, 0, 0, 14, 6504, 6506), + (6506, -1, -1, 6503, 6503, 6, 72, -1, 0, 0, 14, 6505, -1), + (6508, 6508, 6508, 6508, 6508, 7, 74, 13195, 38, 600, 14, -1, 6509), + (6509, 6508, 6508, 6508, 6508, 7, 76, 13196, 38, 600, 14, 6508, 6510), + (6510, 6508, 6508, 6508, 6508, 7, 78, 13197, 38, 600, 14, 6509, 7387), + (6511, -1, -1, 6511, 6511, 6, 73, -1, 0, 0, 14, -1, 6512), + (6512, -1, -1, 6511, 6511, 6, 75, -1, 0, 0, 14, 6511, 6513), + (6513, -1, -1, 6511, 6511, 6, 77, -1, 0, 0, 14, 6512, -1), + (6514, -1, -1, 6514, 6514, 2, 72, -1, 0, 0, 14, -1, 6515), + (6515, -1, -1, 6514, 6514, 2, 72, -1, 0, 0, 14, 6514, 6516), + (6516, -1, -1, 6514, 6514, 2, 72, -1, 0, 0, 14, 6515, -1), + (6517, -1, -1, 1435, 4773, 9, 76, -1, 0, 0, 14, 4773, 7621), + (6518, -1, -1, 678, 678, 3, 65, -1, 0, 0, 14, 682, 6519), + (6519, -1, -1, 678, 678, 3, 65, -1, 0, 0, 14, 6518, 6520), + (6520, -1, -1, 678, 678, 3, 65, -1, 0, 0, 14, 6519, 7544), + (6521, -1, -1, 1021, 1021, 5, 75, -1, 0, 0, 14, 1025, 6522), + (6522, -1, -1, 1021, 1021, 5, 80, -1, 0, 0, 14, 6521, 7539), + (6523, -1, -1, 1026, 1026, 5, 76, -1, 0, 0, 14, 4687, 6524), + (6524, -1, -1, 1026, 1026, 5, 77, -1, 0, 0, 14, 6523, 6525), + (6525, -1, -1, 1026, 1026, 5, 78, -1, 0, 0, 14, 6524, 6526), + (6526, -1, -1, 1026, 1026, 5, 79, -1, 0, 0, 14, 6525, 6527), + (6527, -1, -1, 1026, 1026, 5, 80, -1, 0, 0, 14, 6526, 7511), + (6528, -1, -1, 501, 501, 5, 96, -1, 0, 0, 19, 6321, 6529), + (6531, -1, -1, 5295, 5295, 6, 76, -1, 0, 0, 14, 5297, 6532), + (6532, -1, -1, 5295, 5295, 6, 78, -1, 0, 0, 14, 6531, 6533), + (6533, -1, -1, 5295, 5295, 6, 80, -1, 0, 0, 14, 6532, 7220), + (6534, 8000, 8000, 8000, 8000, 12, 90, 23607, 73, 600, 17, -1, 14216), + (6540, -1, -1, 4699, 4699, 5, 56, -1, 0, 0, 14, 4699, 7500), + (6545, -1, -1, 4698, 4698, 5, 56, -1, 0, 0, 14, 4698, -1), + (6546, -1, -1, 6546, 6546, 0, 55, -1, 0, 0, 3, -1, 6547), + (6547, -1, -1, 6546, 6546, 0, 56, -1, 0, 0, 3, 6546, 6548), + (6548, -1, -1, 6546, 6546, 0, 57, -1, 0, 0, 3, 6547, 6549), + (6549, -1, -1, 6546, 6546, 0, 58, -1, 0, 0, 3, 6548, 6550), + (6550, -1, -1, 6546, 6546, 0, 59, -1, 0, 0, 3, 6549, 6551), + (6551, -1, -1, 6546, 6546, 0, 60, -1, 0, 0, 3, 6550, 6552), + (6552, -1, -1, 6546, 6546, 0, 61, -1, 0, 0, 3, 6551, 6553), + (6553, -1, -1, 6546, 6546, 0, 62, -1, 0, 0, 3, 6552, 6554), + (6554, -1, -1, 6546, 6546, 0, 63, -1, 0, 0, 3, 6553, 6555), + (6555, -1, -1, 6546, 6546, 0, 64, -1, 0, 0, 3, 6554, 6556), + (6556, -1, -1, 6546, 6546, 0, 65, -1, 0, 0, 3, 6555, 6557), + (6557, -1, -1, 6546, 6546, 0, 66, -1, 0, 0, 3, 6556, 6558), + (6558, -1, -1, 6546, 6546, 0, 67, -1, 0, 0, 3, 6557, 6559), + (6559, -1, -1, 6546, 6546, 0, 68, -1, 0, 0, 3, 6558, 6560), + (6560, -1, -1, 6546, 6546, 0, 69, -1, 0, 0, 3, 6559, 6561), + (6561, -1, -1, 6546, 6546, 0, 70, -1, 0, 0, 3, 6560, 6562), + (6562, -1, -1, 6546, 6546, 0, 71, -1, 0, 0, 3, 6561, 6563), + (6563, -1, -1, 6546, 6546, 0, 72, -1, 0, 0, 3, 6562, 6564), + (6564, -1, -1, 6546, 6546, 0, 73, -1, 0, 0, 3, 6563, 6565), + (6565, -1, -1, 6546, 6546, 0, 74, -1, 0, 0, 3, 6564, 6566), + (6566, -1, -1, 6546, 6546, 0, 75, -1, 0, 0, 3, 6565, 6567), + (6567, -1, -1, 6546, 6546, 0, 76, -1, 0, 0, 3, 6566, 6568), + (6568, -1, -1, 6546, 6546, 0, 77, -1, 0, 0, 3, 6567, 6569), + (6569, -1, -1, 6546, 6546, 0, 78, -1, 0, 0, 3, 6568, 6570), + (6570, -1, -1, 6546, 6546, 0, 79, -1, 0, 0, 3, 6569, 6571), + (6571, -1, -1, 6546, 6546, 0, 80, -1, 0, 0, 3, 6570, 7373), + (6601, -1, -1, 6601, 6601, 6, 72, -1, 0, 0, 14, -1, 6602), + (6602, -1, -1, 6601, 6601, 6, 73, -1, 0, 0, 14, 6601, 6603), + (6603, -1, -1, 6601, 6601, 6, 74, -1, 0, 0, 14, 6602, 6604), + (6604, -1, -1, 6601, 6601, 6, 75, -1, 0, 0, 14, 6603, 6605), + (6605, -1, -1, 6601, 6601, 6, 76, -1, 0, 0, 14, 6604, 7318), + (6606, 1597, 1597, 1597, 1597, 9, 75, 16095, 6, 10, 15, 1597, 10571), + (6607, 6607, 6607, 6607, 6607, 9, 75, 16092, 61, 600, 15, -1, 6608), + (6608, 6607, 6607, 6607, 6607, 9, 80, 16093, 61, 600, 15, 6607, 6609), + (6609, 6607, 6607, 6607, 6607, 9, 85, 16094, 61, 600, 15, 6608, 16324), + (6610, 6610, 6610, 6610, 6610, 2, 55, 16096, 41, 30, 15, -1, 10003), + (6611, -1, -1, 6611, 6611, 2, 60, -1, 0, 0, 15, -1, 6612), + (6612, -1, -1, 6611, 6611, 4, 63, -1, 0, 0, 15, 6611, 6613), + (6613, -1, -1, 6611, 6611, 6, 66, -1, 0, 0, 15, 6612, 6618), + (6614, -1, -1, 6614, 6614, 2, 60, -1, 0, 0, 15, -1, 6615), + (6615, -1, -1, 6614, 6614, 4, 63, -1, 0, 0, 15, 6614, 6616), + (6616, -1, -1, 6614, 6614, 6, 66, -1, 0, 0, 15, 6615, 10004), + (6617, 6617, 6617, 6617, 6617, 6, 83, 16097, 42, 3600, 15, -1, 10572), + (6618, -1, -1, 6611, 6611, 6, 69, -1, 0, 0, 15, 6613, 6619), + (6619, -1, -1, 6611, 6611, 6, 72, -1, 0, 0, 15, 6618, 10574), + (6630, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, -1, 6631), + (6631, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, 6630, 6632), + (6632, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, 6631, 6633), + (6633, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, 6632, 6634), + (6634, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, 6633, 10070), + (6635, 6635, 6635, 6635, 6635, 7, 70, 16098, 41, 600, 15, -1, -1), + (6636, -1, -1, 6636, 6636, 3, 70, -1, 0, 0, 15, -1, 6637), + (6637, -1, -1, 6636, 6636, 6, 70, -1, 0, 0, 15, 6636, 6638), + (6638, -1, -1, 6636, 6636, 9, 70, -1, 0, 0, 15, 6637, 10041), + (6639, 6639, 6639, 6639, 6639, 7, 70, 16099, 42, 300, 15, -1, 15173), + (6640, 6640, 6640, 6640, 6640, 7, 81, 16100, 43, 60, 15, -1, 12585), + (6641, -1, -1, 6641, 6641, 7, 81, -1, 0, 0, 15, -1, 6642), + (6642, -1, -1, 6641, 6641, 8, 83, -1, 0, 0, 15, 6641, 6643), + (6643, -1, -1, 6641, 6641, 9, 85, -1, 0, 0, 15, 6642, 10075), + (6644, 6644, 6644, 6644, 6644, 2, 70, 16104, 44, 20, 15, -1, 12586), + (6645, 6645, 6645, 6645, 6645, 6, 80, 16105, 45, 60, 15, -1, 13107), + (6646, 6646, 6646, 6646, 6646, 6, 70, 16106, 46, 6, 15, -1, -1), + (6660, -1, -1, 1307, 1307, 5, 73, -1, 0, 0, 15, 1311, 6661), + (6661, -1, -1, 1307, 1307, 5, 74, -1, 0, 0, 15, 6660, 6662), + (6662, -1, -1, 1307, 1307, 5, 75, -1, 0, 0, 15, 6661, 13210), + (6663, 6663, 6663, 6663, 6663, 7, 73, 16107, 59, 600, 15, -1, 6664), + (6664, 6663, 6663, 6663, 6663, 7, 75, 16108, 59, 600, 15, 6663, 6665), + (6665, 6663, 6663, 6663, 6663, 7, 77, 16109, 59, 600, 15, 6664, 10162), + (6666, -1, -1, 6666, 6666, 8, 81, -1, 0, 0, 15, -1, 6667), + (6667, -1, -1, 6666, 6666, 8, 83, -1, 0, 0, 15, 6666, -1), + (6668, -1, -1, 6668, 6668, 3, 76, -1, 0, 0, 15, -1, 6669), + (6669, -1, -1, 6668, 6668, 3, 77, -1, 0, 0, 15, 6668, 6670), + (6670, -1, -1, 6668, 6668, 3, 78, -1, 0, 0, 15, 6669, -1), + (6671, 6671, 6671, 6671, 6671, 4, 65, 16148, 60, 60, 15, -1, -1), + (6672, 6672, 6672, 6672, 6672, 4, 67, 16149, 60, 60, 15, -1, -1), + (6673, 6673, 6673, 6673, 6673, 4, 69, 16150, 60, 60, 15, -1, -1), + (6674, 6674, 6674, 6674, 6674, 4, 71, 16151, 60, 60, 15, -1, -1), + (6675, 6675, 6675, 6675, 6675, 4, 73, 16152, 60, 60, 15, -1, -1), + (6676, 6676, 6676, 6676, 6676, 4, 75, 16153, 60, 60, 15, -1, -1), + (6691, 6691, 6691, 6691, 6691, 9, 81, 16114, 41, 30, 15, -1, -1), + (6692, 6692, 6692, 6692, 6692, 7, 65, 16115, 42, 600, 15, -1, 6693), + (6693, 6692, 6692, 6692, 6692, 7, 70, 16116, 42, 600, 15, 6692, 6694), + (6694, 6692, 6692, 6692, 6692, 7, 75, 16117, 42, 600, 15, 6693, 6695), + (6695, 6692, 6692, 6692, 6692, 7, 80, 16118, 42, 600, 15, 6694, 6696), + (6696, 6692, 6692, 6692, 6692, 7, 85, 16119, 42, 600, 15, 6695, 5342), + (6697, -1, -1, 6697, 6697, 7, 65, -1, 0, 0, 15, -1, 6698), + (6698, -1, -1, 6697, 6697, 7, 70, -1, 0, 0, 15, 6697, 6699), + (6699, -1, -1, 6697, 6697, 7, 75, -1, 0, 0, 15, 6698, 6700), + (6700, -1, -1, 6697, 6697, 7, 80, -1, 0, 0, 15, 6699, 6701), + (6701, -1, -1, 6697, 6697, 7, 85, -1, 0, 0, 15, 6700, -1), + (6702, 6702, 6702, 6702, 6702, 9, 75, 16120, 43, 120, 15, -1, -1), + (6703, -1, -1, 6703, 6703, 3, 65, -1, 0, 0, 15, -1, 6704), + (6704, -1, -1, 6703, 6703, 3, 65, -1, 0, 0, 15, 6703, 6705), + (6705, -1, -1, 6703, 6703, 3, 65, -1, 0, 0, 15, 6704, 10176), + (6706, 6706, 6706, 6706, 6706, 7, 75, 16121, 44, 600, 15, -1, 6707), + (6707, 6706, 6706, 6706, 6706, 7, 80, 16122, 44, 600, 15, 6706, 6708), + (6708, 6706, 6706, 6706, 6706, 7, 85, 16123, 44, 600, 15, 6707, 10179), + (6709, -1, -1, 6709, 6709, 3, 60, -1, 0, 0, 15, -1, 6710), + (6710, -1, -1, 6709, 6709, 3, 61, -1, 0, 0, 15, 6709, 6711), + (6711, -1, -1, 6709, 6709, 3, 62, -1, 0, 0, 15, 6710, -1), + (6712, -1, -1, 6712, 6712, 7, 65, -1, 0, 0, 15, -1, 6713), + (6713, -1, -1, 6712, 6712, 7, 70, -1, 0, 0, 15, 6712, 6714), + (6714, -1, -1, 6712, 6712, 7, 75, -1, 0, 0, 15, 6713, 6715), + (6715, -1, -1, 6712, 6712, 7, 80, -1, 0, 0, 15, 6714, 6716), + (6716, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 15, 6715, 10182), + (6750, 6750, 6750, 6750, 6750, 9, 85, 16127, 60, 120, 15, -1, 13899), + (6751, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, -1, 6752), + (6752, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, 6751, 6753), + (6753, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, 6752, 6768), + (6754, 6754, 6754, 6754, 6754, 7, 70, 16130, 41, 1200, 15, -1, 10053), + (6755, 6755, 6755, 6755, 6755, 7, 81, 16131, 42, 900, 15, -1, 6756), + (6756, 6755, 6755, 6755, 6755, 9, 83, 16132, 42, 900, 15, 6755, 6757), + (6757, 6755, 6755, 6755, 6755, 12, 85, 16133, 42, 900, 15, 6756, 13542), + (6758, 6758, 6758, 6758, 6758, 3, 81, 16134, 43, 900, 15, -1, 6759), + (6759, 6758, 6758, 6758, 6758, 6, 83, 16135, 43, 900, 15, 6758, 6760), + (6760, 6758, 6758, 6758, 6758, 9, 85, 16136, 43, 900, 15, 6759, 10054), + (6761, -1, -1, 6761, 6761, 3, 65, -1, 0, 0, 15, -1, 6762), + (6762, -1, -1, 6761, 6761, 6, 65, -1, 0, 0, 15, 6761, 6763), + (6763, -1, -1, 6761, 6761, 9, 65, -1, 0, 0, 15, 6762, 6085), + (6764, 6764, 6764, 6764, 6764, 7, 75, 16137, 52, 600, 15, -1, 10057), + (6765, -1, -1, 6765, 6765, 3, 70, -1, 0, 0, 15, -1, 6766), + (6766, -1, -1, 6765, 6765, 6, 75, -1, 0, 0, 15, 6765, 6767), + (6767, -1, -1, 6765, 6765, 9, 80, -1, 0, 0, 15, 6766, 10058), + (6768, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, 6753, 6769), + (6769, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, 6768, 10769), + (6791, -1, -1, 6791, 6791, 6, 75, -1, 0, 0, 15, -1, 6792), + (6792, -1, -1, 6791, 6791, 6, 80, -1, 0, 0, 15, 6791, 6793), + (6793, -1, -1, 6791, 6791, 6, 85, -1, 0, 0, 15, 6792, 10044), + (6794, 6794, 6794, 6794, 6794, 6, 75, 16142, 41, 60, 15, -1, -1), + (6815, 6815, 6815, 6815, 6815, 8, 75, 16144, 60, 600, 15, -1, 6816), + (6816, 6815, 6815, 6815, 6815, 8, 80, 16145, 60, 600, 15, 6815, 6817), + (6817, 6815, 6815, 6815, 6815, 8, 85, 16146, 60, 600, 15, 6816, 10200), + (6818, 6818, 6818, 6818, 6818, 6, 70, 16147, 44, 20, 15, -1, -1), + (6819, -1, -1, 6819, 6819, 6, 72, -1, 0, 0, 15, -1, 6820), + (6820, -1, -1, 6819, 6819, 6, 74, -1, 0, 0, 15, 6819, 6821), + (6821, -1, -1, 6819, 6819, 6, 76, -1, 0, 0, 15, 6820, 10203), + (6822, 6822, 6822, 6822, 6822, 12, 80, 16154, 42, 120, 15, -1, 13683), + (6823, -1, -1, 6823, 6823, 4, 65, -1, 0, 0, 15, -1, 6824), + (6824, -1, -1, 6823, 6823, 4, 67, -1, 0, 0, 15, 6823, 6825), + (6825, -1, -1, 6823, 6823, 4, 69, -1, 0, 0, 15, 6824, 6826), + (6826, -1, -1, 6823, 6823, 4, 71, -1, 0, 0, 15, 6825, 6827), + (6827, -1, -1, 6823, 6823, 4, 73, -1, 0, 0, 15, 6826, 10206), + (6828, 6828, 6828, 6828, 6828, 12, 80, 16155, 43, 60, 15, -1, 10208), + (6870, -1, -1, 6870, 6870, 6, 75, -1, 0, 0, 15, -1, 6871), + (6871, -1, -1, 6870, 6870, 6, 75, -1, 0, 0, 15, 6870, 6872), + (6872, -1, -1, 6870, 6870, 6, 75, -1, 0, 0, 15, 6871, 10130), + (6873, -1, -1, 255, 255, 3, 76, -1, 0, 0, 15, -1, 6874), + (6874, -1, -1, 255, 255, 6, 76, -1, 0, 0, 15, 6873, 6875), + (6875, -1, -1, 255, 255, 9, 76, -1, 0, 0, 15, 6874, 10133), + (6876, -1, -1, 6375, 6375, 6, 76, -1, 0, 0, 15, -1, 6877), + (6877, -1, -1, 6375, 6375, 6, 77, -1, 0, 0, 15, 6876, 6878), + (6878, -1, -1, 6375, 6375, 6, 78, -1, 0, 0, 15, 6877, 10136), + (6879, -1, -1, 649, 649, 2, 66, -1, 0, 0, 15, -1, 6880), + (6880, -1, -1, 649, 649, 4, 68, -1, 0, 0, 15, 6879, 6881), + (6881, -1, -1, 649, 649, 6, 70, -1, 0, 0, 15, 6880, -1), + (6882, -1, -1, 776, 776, 3, 70, -1, 0, 0, 15, -1, 6883), + (6883, -1, -1, 776, 776, 3, 70, -1, 0, 0, 15, 6882, 6884), + (6884, -1, -1, 776, 776, 3, 70, -1, 0, 0, 15, 6883, -1), + (6900, -1, -1, 6935, 6935, 6, 81, -1, 0, 0, 16, 6937, 6901), + (6901, -1, -1, 6935, 6935, 6, 82, -1, 0, 0, 16, 6900, 6902), + (6902, -1, -1, 6935, 6935, 6, 83, -1, 0, 0, 16, 6901, 6903), + (6903, -1, -1, 6935, 6935, 6, 84, -1, 0, 0, 16, 6902, 6904), + (6904, -1, -1, 6935, 6935, 6, 85, -1, 0, 0, 16, 6903, 14196), + (6905, -1, -1, 551, 551, 5, 81, -1, 0, 0, 16, 1637, 6906), + (6906, -1, -1, 551, 551, 5, 83, -1, 0, 0, 16, 6905, 6907), + (6907, -1, -1, 551, 551, 5, 85, -1, 0, 0, 16, 6906, 12843), + (6908, -1, -1, 6908, 6908, 6, 81, -1, 0, 0, 16, -1, 6909), + (6909, -1, -1, 6908, 6908, 6, 83, -1, 0, 0, 16, 6908, 6910), + (6910, -1, -1, 6908, 6908, 6, 85, -1, 0, 0, 16, 6909, 14199), + (6911, -1, -1, 1143, 1143, 5, 65, -1, 0, 0, 16, 1168, 6912), + (6912, -1, -1, 1143, 1143, 7, 65, -1, 0, 0, 16, 6911, 6913), + (6913, -1, -1, 1143, 1143, 9, 65, -1, 0, 0, 16, 6912, -1), + (6930, 6930, 6930, 6930, 6930, 12, 80, 16156, 13, 60, 15, -1, -1), + (6931, 6931, 6931, 6931, 6931, 12, 85, 16157, 41, 600, 15, -1, 10319), + (6932, 6932, 6932, 6932, 6932, 7, 81, 16158, 42, 1200, 15, -1, 6933), + (6933, 6932, 6932, 6932, 6932, 7, 83, 16159, 42, 1200, 15, 6932, 6934), + (6934, 6932, 6932, 6932, 6932, 7, 85, 16160, 42, 1200, 15, 6933, 10320), + (6935, -1, -1, 6935, 6935, 6, 75, -1, 0, 0, 15, -1, 6936), + (6936, -1, -1, 6935, 6935, 6, 77, -1, 0, 0, 15, 6935, 6937), + (6937, -1, -1, 6935, 6935, 6, 79, -1, 0, 0, 15, 6936, 6900), + (6938, -1, -1, 6938, 6938, 7, 81, -1, 0, 0, 15, -1, 6939), + (6939, -1, -1, 6938, 6938, 7, 83, -1, 0, 0, 15, 6938, 6940), + (6940, -1, -1, 6938, 6938, 7, 85, -1, 0, 0, 15, 6939, -1), + (6941, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, -1, 6942), + (6942, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, 6941, 6943), + (6943, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, 6942, 6944), + (6944, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, 6943, 6945), + (6945, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, 6944, -1), + (6970, 6970, 6970, 6970, 6970, 6, 70, 16167, 61, 6, 15, -1, -1), + (6971, 6971, 6971, 6971, 6971, 7, 78, 16168, 41, 600, 15, -1, 6972), + (6972, 6971, 6971, 6971, 6971, 7, 80, 16169, 41, 600, 15, 6971, 6973), + (6973, 6971, 6971, 6971, 6971, 7, 82, 16170, 41, 600, 15, 6972, 10288), + (6974, -1, -1, 6974, 6974, 5, 81, -1, 0, 0, 15, -1, 6975), + (6975, -1, -1, 6974, 6974, 5, 83, -1, 0, 0, 15, 6974, 6976), + (6976, -1, -1, 6974, 6974, 5, 85, -1, 0, 0, 15, 6975, 10291), + (6977, -1, -1, 6977, 6977, 5, 81, -1, 0, 0, 15, -1, 6978), + (6978, -1, -1, 6977, 6977, 5, 83, -1, 0, 0, 15, 6977, 6979), + (6979, -1, -1, 6977, 6977, 5, 85, -1, 0, 0, 15, 6978, 12840), + (6980, -1, -1, 6980, 6980, 5, 81, -1, 0, 0, 15, -1, 6981), + (6981, -1, -1, 6980, 6980, 5, 83, -1, 0, 0, 15, 6980, 6982), + (6982, -1, -1, 6980, 6980, 5, 85, -1, 0, 0, 15, 6981, 12834), + (6983, 6983, 6983, 6983, 6983, 7, 83, 16439, 66, 720, 15, -1, 16246), + (6984, 6984, 6984, 6984, 6984, 6, 73, 16172, 60, 60, 15, -1, 10294), + (6985, 6985, 6985, 6985, 6985, 6, 73, 16173, 60, 60, 15, -1, 10295), + (6986, 6986, 6986, 6986, 6986, 6, 73, 16174, 60, 60, 15, -1, 10296), + (6987, -1, -1, 6987, 6987, 12, 81, -1, 0, 0, 15, -1, -1), + (6988, -1, -1, 6988, 6988, 5, 83, 0, 0, 0, 16, -1, 6989), + (6989, -1, -1, 6988, 6988, 5, 84, 0, 0, 0, 16, 6988, 6990), + (6990, -1, -1, 6988, 6988, 5, 83, 0, 0, 0, 16, 6989, 14278), + (7000, 7000, 7000, 7000, 7000, 4, 65, 12748, 31, 600, 3, -1, -1), + (7002, 7002, 7002, 7002, 7002, 4, 65, 12750, 31, 600, 3, -1, -1), + (7003, 7003, 7003, 7003, 7003, 4, 65, 12751, 31, 600, 3, -1, -1), + (7004, 7004, 7004, 7004, 7004, 4, 65, 12752, 31, 300, 3, -1, -1), + (7005, -1, -1, 7005, 7005, 2, 73, -1, 0, 0, 15, -1, 7006), + (7006, -1, -1, 7005, 7005, 2, 74, -1, 0, 0, 15, 7005, 7007), + (7007, -1, -1, 7005, 7005, 2, 75, -1, 0, 0, 15, 7006, 15632), + (7008, -1, -1, 1604, 1604, 9, 81, -1, 0, 0, 16, 7133, 7009), + (7009, -1, -1, 1604, 1604, 12, 83, -1, 0, 0, 16, 7008, 12612), + (7010, -1, -1, 7010, 7010, 6, 81, -1, 0, 0, 16, -1, 7011), + (7011, -1, -1, 7010, 7010, 6, 83, -1, 0, 0, 16, 7010, 7012), + (7012, -1, -1, 7010, 7010, 6, 85, -1, 0, 0, 16, 7011, 7013), + (7013, -1, -1, 7010, 7010, 6, 85, -1, 0, 0, 16, 7012, 7014), + (7014, -1, -1, 7010, 7010, 6, 85, -1, 0, 0, 16, 7013, 7015), + (7015, -1, -1, 7010, 7010, 6, 85, -1, 0, 0, 16, 7014, 13533), + (7016, 7016, 7016, 7016, 7016, 5, 85, 21658, 31, 600, 3, -1, -1), + (7017, 7017, 7017, 7017, 7017, 5, 85, 21659, 31, 600, 3, -1, -1), + (7018, 7018, 7018, 7018, 7018, 5, 85, 21660, 31, 600, 3, -1, -1), + (7019, 7019, 7019, 7019, 7019, 5, 85, 21661, 31, 600, 3, -1, -1), + (7020, 7020, 7020, 7020, 7020, 0, 85, 21658, 31, 600, 3, -1, -1), + (7021, 7021, 7021, 7021, 7021, 0, 85, 21659, 31, 600, 3, -1, -1), + (7022, 7022, 7022, 7022, 7022, 0, 85, 21660, 31, 600, 3, -1, -1), + (7023, 7023, 7023, 7023, 7023, 0, 85, 21661, 31, 600, 3, -1, -1), + (7024, 7024, 7024, 7024, 7024, 0, 0, 9475, 31, 600, 12, -1, -1), + (7025, 7025, 7025, 7025, 7025, 0, 0, 9477, 31, 600, 12, -1, -1), + (7026, 7026, 7026, 7026, 7026, 0, 0, 9478, 31, 600, 12, -1, -1), + (7027, 7027, 7027, 7027, 7027, 0, 0, 9479, 31, 600, 12, -1, -1), + (7028, 7028, 7028, 7028, 7028, 0, 0, 12748, 31, 600, 3, -1, -1), + (7030, 7030, 7030, 7030, 7030, 0, 0, 12750, 31, 600, 3, -1, -1), + (7031, 7031, 7031, 7031, 7031, 0, 0, 12751, 31, 600, 3, -1, -1), + (7032, 7032, 7032, 7032, 7032, 0, 0, 12752, 31, 300, 3, -1, -1), + (7033, -1, -1, 7033, 7033, 6, 85, 0, 0, 0, 16, -1, 7034), + (7034, -1, -1, 7033, 7033, 9, 85, 0, 0, 0, 16, 7033, 7035), + (7035, -1, -1, 7033, 7033, 12, 85, 0, 0, 0, 16, 7034, 15746), + (7036, -1, -1, 7036, 7036, 7, 81, -1, 0, 0, 16, -1, 7037), + (7037, -1, -1, 7036, 7036, 9, 81, -1, 0, 0, 16, 7036, 7038), + (7038, -1, -1, 7036, 7036, 12, 81, -1, 0, 0, 16, 7037, 10579), + (7050, -1, -1, 446, 735, 5, 67, -1, 0, 0, 8, 448, 7051), + (7051, -1, -1, 446, 735, 5, 68, -1, 0, 0, 8, 7050, 7052), + (7052, -1, -1, 446, 735, 5, 69, -1, 0, 0, 8, 7051, 7053), + (7053, -1, -1, 446, 735, 7, 72, -1, 0, 0, 12, 7052, 7054), + (7054, -1, -1, 446, 735, 7, 73, -1, 0, 0, 12, 7053, 7055), + (7055, -1, -1, 446, 735, 7, 74, -1, 0, 0, 12, 7054, 7063), + (7056, -1, -1, 735, 735, 5, 67, -1, 0, 0, 8, 737, 7057), + (7057, -1, -1, 735, 735, 5, 68, -1, 0, 0, 8, 7056, 7058), + (7058, -1, -1, 735, 735, 5, 69, -1, 0, 0, 8, 7057, 7059), + (7059, -1, -1, 735, 735, 7, 72, -1, 0, 0, 12, 7058, 7060), + (7060, -1, -1, 735, 735, 7, 73, -1, 0, 0, 12, 7059, 7061), + (7061, -1, -1, 735, 735, 7, 74, -1, 0, 0, 12, 7060, 7066), + (7062, -1, -1, 7062, 7062, 3, 51, -1, 0, 0, 0, -1, -1), + (7063, -1, -1, 446, 735, 8, 76, -1, 0, 0, 14, 7055, 7064), + (7064, -1, -1, 446, 735, 8, 77, -1, 0, 0, 14, 7063, 7065), + (7065, -1, -1, 446, 735, 8, 78, -1, 0, 0, 14, 7064, 7622), + (7066, -1, -1, 735, 735, 8, 76, -1, 0, 0, 14, 7061, 7067), + (7067, -1, -1, 735, 735, 8, 77, -1, 0, 0, 14, 7066, 7068), + (7068, -1, -1, 735, 735, 8, 78, -1, 0, 0, 14, 7067, 7625), + (7069, 7069, 7069, 7069, 7069, 3, 71, 13219, 39, 7, 14, -1, -1), + (7100, -1, -1, 7100, 7100, 6, 76, -1, 0, 0, 14, -1, 7101), + (7101, -1, -1, 7100, 7100, 6, 77, -1, 0, 0, 14, 7100, 7102), + (7102, -1, -1, 7100, 7100, 6, 78, -1, 0, 0, 14, 7101, 7323), + (7103, -1, -1, 7103, 7103, 2, 65, -1, 0, 0, 14, -1, 7104), + (7104, -1, -1, 7103, 7103, 2, 65, -1, 0, 0, 14, 7103, 7105), + (7105, -1, -1, 7103, 7103, 2, 65, -1, 0, 0, 14, 7104, 7326), + (7106, -1, -1, 7106, 7106, 6, 73, -1, 0, 0, 14, -1, 7107), + (7107, -1, -1, 7106, 7106, 7, 76, -1, 0, 0, 14, 7106, 7108), + (7108, -1, -1, 7106, 7106, 10, 79, -1, 0, 0, 14, 7107, -1), + (7109, 1351, 1351, 1351, 1351, 8, 82, 13499, 5, 30, 15, 6133, 13109), + (7110, 4849, 4849, 4849, 4849, 7, 81, 13593, 7, 1800, 15, 6134, 13914), + (7111, 54006, 54006, 54006, 54006, 7, 81, 13594, 18, 180, 15, 6135, 10006), + (7112, -1, -1, 6564, 6564, 6, 78, -1, 0, 0, 15, 6285, 7113), + (7113, -1, -1, 6564, 6564, 7, 81, -1, 0, 0, 15, 7112, 7114), + (7114, -1, -1, 6564, 6564, 10, 84, -1, 0, 0, 15, 7113, 10007), + (7115, 6565, 6565, 6565, 6565, 7, 81, 13595, 17, 45, 15, 6286, 10010), + (7116, -1, -1, 489, 489, 3, 68, -1, 0, 0, 15, 491, 7117), + (7117, -1, -1, 489, 489, 3, 69, -1, 0, 0, 15, 7116, 7118), + (7118, -1, -1, 489, 489, 3, 70, -1, 0, 0, 15, 7117, -1), + (7119, 912, 912, 912, 912, 3, 71, 13496, 4, 3600, 15, 1332, 7120), + (7120, 912, 912, 912, 912, 6, 73, 13497, 4, 3600, 15, 7119, 7121), + (7121, 912, 912, 912, 912, 9, 75, 13498, 4, 3600, 15, 7120, 10011), + (7122, -1, -1, 4844, 4844, 5, 76, -1, 0, 0, 15, 4848, 7123), + (7123, -1, -1, 4844, 4844, 5, 77, -1, 0, 0, 15, 7122, 7124), + (7124, -1, -1, 4844, 4844, 5, 78, -1, 0, 0, 15, 7123, 7125), + (7125, -1, -1, 4844, 4844, 5, 79, -1, 0, 0, 15, 7124, 7126), + (7126, -1, -1, 4844, 4844, 5, 80, -1, 0, 0, 15, 7125, 7686), + (7127, 4860, 4860, 4860, 4860, 12, 85, 13599, 13, 60, 15, 5606, -1), + (7128, -1, -1, 492, 492, 2, 68, -1, 0, 0, 15, 494, 7129), + (7129, -1, -1, 492, 492, 2, 69, -1, 0, 0, 15, 7128, 7130), + (7130, -1, -1, 492, 492, 2, 70, -1, 0, 0, 15, 7129, 10576), + (7131, -1, -1, 1604, 1604, 7, 75, -1, 0, 0, 15, 6034, 7132), + (7132, -1, -1, 1604, 1604, 9, 77, -1, 0, 0, 15, 7131, 7133), + (7133, -1, -1, 1604, 1604, 12, 79, -1, 0, 0, 15, 7132, 7008), + (7134, -1, -1, 1543, 1543, 7, 81, -1, 0, 0, 15, 6044, 7135), + (7135, -1, -1, 1543, 1543, 9, 83, -1, 0, 0, 15, 7134, 7136), + (7136, -1, -1, 1543, 1543, 12, 85, -1, 0, 0, 15, 7135, 10165), + (7137, -1, -1, 6559, 6559, 6, 79, -1, 0, 0, 15, 6274, 7138), + (7138, -1, -1, 6559, 6559, 7, 81, -1, 0, 0, 15, 7137, 7139), + (7139, -1, -1, 6559, 6559, 10, 83, -1, 0, 0, 15, 7138, -1), + (7143, 6328, 6328, 6328, 6328, 7, 79, 13601, 10, 600, 15, 6330, 7144), + (7144, 6328, 6328, 6328, 6328, 7, 81, 13602, 10, 600, 15, 7143, 7145), + (7145, 6328, 6328, 6328, 6328, 7, 83, 13603, 10, 600, 15, 7144, 10168), + (7146, -1, -1, 878, 878, 7, 81, -1, 0, 0, 15, 6332, 7147), + (7147, -1, -1, 878, 878, 7, 83, -1, 0, 0, 15, 7146, 10171), + (7148, -1, -1, 1304, 1304, 7, 81, -1, 0, 0, 15, 6031, 7149), + (7149, -1, -1, 1304, 1304, 9, 83, -1, 0, 0, 15, 7148, 7150), + (7150, -1, -1, 1304, 1304, 12, 85, -1, 0, 0, 15, 7149, 10865), + (7151, -1, -1, 846, 846, 7, 81, -1, 0, 0, 15, 6037, 7152), + (7152, -1, -1, 846, 846, 9, 83, -1, 0, 0, 15, 7151, 7153), + (7153, -1, -1, 846, 846, 12, 85, -1, 0, 0, 15, 7152, 10173), + (7154, 1352, 1352, 1352, 1352, 6, 81, 13613, 3, 60, 15, 6318, 7155), + (7155, 1352, 1352, 1352, 1352, 6, 83, 13614, 3, 60, 15, 7154, 7156), + (7156, 1352, 1352, 1352, 1352, 6, 85, 13615, 3, 60, 15, 7155, 10113), + (7157, 1358, 1358, 1358, 1358, 6, 81, 13610, 3, 60, 15, 6312, 7158), + (7158, 1358, 1358, 1358, 1358, 6, 83, 13611, 3, 60, 15, 7157, 7159), + (7159, 1358, 1358, 1358, 1358, 6, 85, 13612, 3, 60, 15, 7158, 10116), + (7160, -1, -1, 4801, 4801, 6, 79, -1, 0, 0, 15, 4803, 7161), + (7161, -1, -1, 4801, 4801, 6, 81, -1, 0, 0, 15, 7160, 7162), + (7162, -1, -1, 4801, 4801, 6, 83, -1, 0, 0, 15, 7161, 10122), + (7163, -1, -1, 820, 820, 5, 81, -1, 0, 0, 15, 5919, 7164), + (7164, -1, -1, 820, 820, 5, 83, -1, 0, 0, 15, 7163, 7165), + (7165, -1, -1, 820, 820, 5, 85, -1, 0, 0, 15, 7164, 10660), + (7166, -1, -1, 6343, 6343, 6, 79, -1, 0, 0, 15, 6345, 7167), + (7167, -1, -1, 6343, 6343, 6, 81, -1, 0, 0, 15, 7166, 7168), + (7168, -1, -1, 6343, 6343, 6, 83, -1, 0, 0, 15, 7167, -1), + (7169, -1, -1, 6020, 6020, 2, 81, -1, 0, 0, 15, 6059, 7170), + (7170, -1, -1, 6020, 6020, 2, 83, -1, 0, 0, 15, 7169, 7171), + (7171, -1, -1, 6020, 6020, 2, 85, -1, 0, 0, 15, 7170, 10663), + (7172, 1355, 1355, 1355, 1355, 6, 81, 13607, 3, 60, 15, 5916, 7173), + (7173, 1355, 1355, 1355, 1355, 6, 83, 13608, 3, 60, 15, 7172, 7174), + (7174, 1355, 1355, 1355, 1355, 6, 85, 13609, 3, 60, 15, 7173, 10119), + (7175, -1, -1, 611, 611, 2, 68, -1, 0, 0, 15, 615, 7176), + (7176, -1, -1, 611, 611, 2, 69, -1, 0, 0, 15, 7175, 7177), + (7177, -1, -1, 611, 611, 2, 70, -1, 0, 0, 15, 7176, 10124), + (7178, 4854, 4854, 4854, 4854, 7, 81, 13616, 8, 600, 15, 5766, 7179), + (7179, 4854, 4854, 4854, 4854, 9, 83, 13617, 8, 600, 15, 7178, 7180), + (7180, 4854, 4854, 4854, 4854, 12, 85, 13618, 8, 600, 15, 7179, 10323), + (7184, 1348, 1348, 1348, 1348, 12, 91, 13622, 0, 3600, 18, 5772, 7185), + (7187, 1178, 1178, 1178, 1178, 7, 81, 13625, 4, 900, 15, 5781, 7188), + (7188, 1178, 1178, 1178, 1178, 8, 82, 13626, 4, 900, 15, 7187, 7189), + (7189, 1178, 1178, 1178, 1178, 9, 83, 13627, 4, 900, 15, 7188, 10326), + (7196, -1, -1, 5776, 5776, 7, 81, -1, 0, 0, 16, 5778, 7197), + (7197, -1, -1, 5776, 5776, 9, 83, -1, 0, 0, 16, 7196, 7198), + (7198, -1, -1, 5776, 5776, 12, 85, -1, 0, 0, 16, 7197, 13043), + (7199, 1274, 1274, 1274, 1274, 9, 83, 13657, 9, 540, 15, 5949, 7200), + (7200, 1274, 1274, 1274, 1274, 10, 84, 13658, 9, 540, 15, 7199, 7201), + (7201, 1274, 1274, 1274, 1274, 12, 85, 13659, 9, 540, 15, 7200, 10209), + (7202, 1510, -1, 1510, 1510, 12, 75, 13664, 13, 2160, 15, 1510, 10212), + (7203, 184, 184, 184, 184, 10, 84, 13660, 5, 4320, 15, 5953, -1), + (7204, -1, -1, 5264, 5264, 7, 81, -1, 0, 0, 15, 5943, 7205), + (7205, -1, -1, 5264, 5264, 8, 82, -1, 0, 0, 15, 7204, 7206), + (7206, -1, -1, 5264, 5264, 9, 83, -1, 0, 0, 15, 7205, 7207), + (7207, -1, -1, 5264, 5264, 10, 84, -1, 0, 0, 15, 7206, 7208), + (7208, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 15, 7207, 10213), + (7209, 4927, 4927, 4927, 4927, 9, 76, 13656, 14, 600, 15, 4927, 10218), + (7210, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 5329, 7211), + (7211, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 7210, 7212), + (7212, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 7211, 7213), + (7213, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 7212, 7214), + (7214, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 7213, 10219), + (7215, -1, -1, 4861, 4861, 9, 83, -1, 0, 0, 15, 5956, 7216), + (7216, -1, -1, 4861, 4861, 12, 85, -1, 0, 0, 15, 7215, 7682), + (7217, 967, 967, 967, 967, 6, 81, 13661, 10, 1800, 15, 6466, 7218), + (7218, 967, 967, 967, 967, 6, 82, 13662, 10, 1800, 15, 7217, 7219), + (7219, 967, 967, 967, 967, 6, 83, 13663, 10, 1800, 15, 7218, 10224), + (7220, -1, -1, 5295, 5295, 6, 81, -1, 0, 0, 15, 6533, 7221), + (7221, -1, -1, 5295, 5295, 6, 83, -1, 0, 0, 15, 7220, 7222), + (7222, -1, -1, 5295, 5295, 6, 85, -1, 0, 0, 15, 7221, 10227), + (7223, 6290, 6290, 6290, 6290, 7, 81, 13689, 0, 1, 15, 6295, 7224), + (7224, 6290, 6290, 6290, 6290, 9, 83, 13690, 0, 1, 15, 7223, 7225), + (7225, 6290, 6290, 6290, 6290, 12, 85, 13691, 0, 1, 15, 7224, 11064), + (7226, 619, 619, 619, 619, 6, 78, 13686, 6, 900, 15, 6298, 7227), + (7227, 619, 619, 619, 619, 6, 78, 13687, 6, 900, 15, 7226, 7228), + (7228, 619, 619, 619, 619, 6, 78, 13688, 6, 900, 15, 7227, 10230), + (7229, 4944, -1, 4944, 4944, 7, 81, 13677, 0, 1, 15, 6157, 7230), + (7230, 4944, -1, 4944, 4944, 9, 83, 13678, 0, 1, 15, 7229, 7231), + (7231, 4944, -1, 4944, 4944, 12, 85, 13679, 0, 1, 15, 7230, 11067), + (7232, -1, -1, 1210, 1210, 7, 81, -1, 0, 0, 15, 5576, 7233), + (7233, -1, -1, 1210, 1210, 9, 83, -1, 0, 0, 15, 7232, 7234), + (7234, -1, -1, 1210, 1210, 12, 85, -1, 0, 0, 15, 7233, 12523), + (7235, 923, 923, 923, 923, 9, 82, 13673, 8, 60, 15, 6151, -1), + (7236, 922, 922, 922, 922, 9, 83, 13672, 8, 60, 15, 6150, -1), + (7237, 516, 516, 516, 516, 6, 77, 13692, 5, 480, 15, 6398, 10233), + (7238, 155, 155, 155, 155, 12, 82, 13693, 8, 60, 15, 5289, 14324), + (7239, 1334, 1334, 1334, 1334, 9, 83, 13674, 11, 4320, 15, 6154, 7240), + (7240, 1334, 1334, 1334, 1334, 10, 84, 13675, 11, 4320, 15, 7239, 7241), + (7241, 1334, 1334, 1334, 1334, 12, 85, 13676, 11, 4320, 15, 7240, 10234), + (7242, 1478, -1, 1478, 1478, 9, 83, 13680, 0, 1, 15, 6163, 7243), + (7243, 1478, -1, 1478, 1478, 10, 84, 13681, 0, 1, 15, 7242, 7244), + (7244, 1478, -1, 1478, 1478, 12, 85, 13682, 0, 1, 15, 7243, 11070), + (7245, 921, 921, 921, 921, 9, 84, 13671, 8, 60, 15, 6149, -1), + (7246, 4915, 4915, 4915, 4915, 7, 81, 13683, 7, 4320, 15, 5609, 7247), + (7247, 4915, 4915, 4915, 4915, 9, 83, 13684, 7, 4320, 15, 7246, 7248), + (7248, 4915, 4915, 4915, 4915, 12, 85, 13685, 7, 4320, 15, 7247, -1), + (7249, 167, 167, 167, 167, 10, 84, 13703, 14, 900, 15, 5879, 8343), + (7250, 520, 520, 520, 520, 12, 81, 13704, 6, 540, 15, 5885, 7251), + (7251, 520, 520, 520, 520, 12, 83, 13705, 6, 540, 15, 7250, 7252), + (7252, 520, 520, 520, 520, 12, 85, 13706, 6, 540, 15, 7251, 10252), + (7253, 4903, 4903, 4903, 4903, 9, 81, 13707, 9, 1320, 15, 5892, 10255), + (7254, 4906, 4906, 4906, 4906, 9, 81, 13708, 9, 1320, 15, 5893, 10256), + (7255, 4909, 4909, 4909, 4909, 9, 81, 13709, 16, 1320, 15, 5894, 10257), + (7256, 4912, 4912, 4912, 4912, 9, 81, 13710, 16, 1320, 15, 5895, 10258), + (7257, 616, 616, 616, 616, 6, 78, 13711, 7, 900, 15, 6256, 7258), + (7258, 616, 616, 616, 616, 7, 81, 13712, 7, 900, 15, 7257, 7259), + (7259, 616, 616, 616, 616, 10, 84, 13713, 7, 900, 15, 7258, 10259), + (7260, -1, -1, 1504, 1504, 5, 81, -1, 0, 0, 15, 5882, 7261), + (7261, -1, -1, 1504, 1504, 5, 83, -1, 0, 0, 15, 7260, 7262), + (7262, -1, -1, 1504, 1504, 5, 85, -1, 0, 0, 15, 7261, -1), + (7263, -1, -1, 1577, 1577, 7, 81, -1, 0, 0, 15, 5888, 7264), + (7264, -1, -1, 1577, 1577, 9, 83, -1, 0, 0, 15, 7263, 7265), + (7265, -1, -1, 1577, 1577, 12, 85, -1, 0, 0, 15, 7264, 10262), + (7266, 6333, 6333, 6333, 6333, 6, 64, 13714, 3, 600, 15, 6333, 13920), + (7267, -1, -1, 795, 795, 7, 81, -1, 0, 0, 15, 5891, 7268), + (7268, -1, -1, 795, 795, 9, 83, -1, 0, 0, 15, 7267, 7269), + (7269, -1, -1, 795, 795, 12, 85, -1, 0, 0, 15, 7268, 10265), + (7270, -1, -1, 790, 790, 6, 81, -1, 0, 0, 15, 5324, 7271), + (7271, -1, -1, 790, 790, 6, 82, -1, 0, 0, 15, 7270, 7272), + (7272, -1, -1, 790, 790, 6, 83, -1, 0, 0, 15, 7271, 7273), + (7273, -1, -1, 790, 790, 6, 84, -1, 0, 0, 15, 7272, 7274), + (7274, -1, -1, 790, 790, 6, 85, -1, 0, 0, 15, 7273, 12950), + (7275, 1239, 1239, 1239, 1239, 12, 85, 13735, 6, 600, 15, 5868, 13251), + (7276, 773, -1, 773, 773, 7, 81, 13726, 5, 1800, 15, 5856, 7277), + (7277, 773, -1, 773, 773, 9, 83, 13727, 5, 1800, 15, 7276, 7278), + (7278, 773, -1, 773, 773, 12, 85, 13728, 5, 1800, 15, 7277, 10564), + (7279, 6552, 6552, 6552, 6552, 5, 75, -1, 0, 0, 15, 6253, 7280), + (7280, 6552, 6552, 6552, 6552, 6, 77, -1, 0, 0, 15, 7279, 7281), + (7281, 6552, 6552, 6552, 6552, 6, 79, -1, 0, 0, 15, 7280, 7282), + (7282, 6552, 6552, 6552, 6552, 7, 81, -1, 0, 0, 15, 7281, 7283), + (7283, 6552, 6552, 6552, 6552, 9, 83, -1, 0, 0, 15, 7282, -1), + (7284, -1, -1, 781, 781, 8, 82, -1, 0, 0, 15, 5850, 13763), + (7285, 1242, 1242, 1242, 1242, 7, 81, 13723, 9, 1320, 15, 5859, 7286), + (7286, 1242, 1242, 1242, 1242, 9, 83, 13724, 9, 1320, 15, 7285, 7287), + (7287, 1242, 1242, 1242, 1242, 12, 85, 13725, 9, 1320, 15, 7286, 10271), + (7288, 4894, 4894, 4894, 4894, 6, 81, 13732, 7, 2160, 15, 6354, 7289), + (7289, 4894, 4894, 4894, 4894, 6, 82, 13733, 7, 2160, 15, 7288, 7290), + (7290, 4894, 4894, 4894, 4894, 6, 83, 13734, 7, 2160, 15, 7289, 13247), + (7291, 4931, 4931, 4931, 4931, 7, 81, 13729, 4, 600, 15, 6056, 7292), + (7292, 4931, 4931, 4931, 4931, 7, 83, 13730, 4, 600, 15, 7291, 7293), + (7293, 4931, 4931, 4931, 4931, 7, 85, 13731, 4, 600, 15, 7292, 10274), + (7294, 4935, 4935, 4935, 4935, 7, 76, 13722, 14, 300, 15, 4935, 10277), + (7295, 4934, 4934, 4934, 4934, 7, 76, 13721, 13, 300, 15, 4934, 10278), + (7296, 517, 517, 517, 517, 5, 73, 13718, 12, 600, 15, 1444, 7297), + (7297, 517, 517, 517, 517, 5, 74, 13719, 12, 600, 15, 7296, 7298), + (7298, 517, 517, 517, 517, 5, 75, 13720, 12, 600, 15, 7297, 10279), + (7299, 1383, 1383, 1383, 1383, 12, 85, 16000, 6, 300, 15, 5789, 10014), + (7300, 1195, 1195, 1195, 1195, 9, 85, 16001, 13, 2160, 15, 5790, 10015), + (7301, 131, 131, 131, 131, 8, 82, 16002, 4, 900, 15, 5793, 7302), + (7302, 131, 131, 131, 131, 9, 83, 16003, 4, 900, 15, 7301, 7303), + (7303, 131, 131, 131, 131, 10, 84, 16004, 4, 900, 15, 7302, 10016), + (7304, 1192, 1192, 1192, 1192, 8, 82, 16005, 12, 1320, 15, 5796, 7305), + (7305, 1192, 1192, 1192, 1192, 9, 83, 16006, 12, 1320, 15, 7304, 7306), + (7306, 1192, 1192, 1192, 1192, 10, 84, 16007, 12, 1320, 15, 7305, 10019), + (7307, 746, 746, 746, 746, 9, 83, 16008, 10, 2160, 15, 5802, 7308), + (7308, 746, 746, 746, 746, 10, 84, 16009, 10, 2160, 15, 7307, 7309), + (7309, 746, 746, 746, 746, 12, 85, 16010, 10, 2160, 15, 7308, 10022), + (7310, 1459, 1459, 1459, 1459, 7, 81, 16011, 11, 1800, 15, 5805, 7311), + (7311, 1459, 1459, 1459, 1459, 9, 83, 16012, 11, 1800, 15, 7310, 7312), + (7312, 1459, 1459, 1459, 1459, 12, 85, 16013, 11, 1800, 15, 7311, -1), + (7313, -1, -1, 6436, 6436, 6, 78, -1, 0, 0, 15, 6438, 7314), + (7314, -1, -1, 6436, 6436, 6, 80, -1, 0, 0, 15, 7313, 7315), + (7315, -1, -1, 6436, 6436, 8, 82, -1, 0, 0, 15, 7314, -1), + (7316, -1, -1, 468, 468, 2, 72, -1, 0, 0, 15, 6440, 7317), + (7317, -1, -1, 468, 468, 2, 74, -1, 0, 0, 15, 7316, 17288), + (7318, -1, -1, 6601, 6601, 6, 77, -1, 0, 0, 15, 6605, 7319), + (7319, -1, -1, 6601, 6601, 6, 78, -1, 0, 0, 15, 7318, 7320), + (7320, -1, -1, 6601, 6601, 6, 79, -1, 0, 0, 15, 7319, 7321), + (7321, -1, -1, 6601, 6601, 6, 80, -1, 0, 0, 15, 7320, 7322), + (7322, -1, -1, 6601, 6601, 6, 81, -1, 0, 0, 15, 7321, 10025), + (7323, -1, -1, 7100, 7100, 6, 81, -1, 0, 0, 15, 7102, 7324), + (7324, -1, -1, 7100, 7100, 6, 82, -1, 0, 0, 15, 7323, 7325), + (7325, -1, -1, 7100, 7100, 6, 83, -1, 0, 0, 15, 7324, 8427), + (7326, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 15, 7105, 7327), + (7327, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 15, 7326, 7328), + (7328, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 15, 7327, 10750), + (7329, 534, 534, 534, 534, 7, 81, 16021, 4, 2160, 15, 5971, 7330), + (7330, 534, 534, 534, 534, 9, 83, 16022, 4, 2160, 15, 7329, 7331), + (7331, 534, 534, 534, 534, 12, 85, 16023, 4, 2160, 15, 7330, 10047), + (7332, 5095, 5095, 5095, 5095, 7, 81, 16024, 10, 900, 15, 5977, 7333), + (7333, 5095, 5095, 5095, 5095, 9, 83, 16025, 10, 900, 15, 7332, 7334), + (7334, 5095, 5095, 5095, 5095, 12, 85, 16026, 10, 900, 15, 7333, 10640), + (7335, 5984, 5984, 5984, 5984, 12, 85, 16027, 2, 30, 15, 5984, 7710), + (7336, -1, -1, 6395, 6395, 7, 81, -1, 0, 0, 15, 6397, 7337), + (7337, -1, -1, 6395, 6395, 7, 82, -1, 0, 0, 15, 7336, 7338), + (7338, -1, -1, 6395, 6395, 7, 83, -1, 0, 0, 15, 7337, 10050), + (7339, 188, 188, 188, 188, 9, 78, 16020, 2, 30, 14, 5044, 7662), + (7340, 7850, 7850, 7850, 7850, 8, 81, 16028, 39, 4320, 0, 7865, 10618), + (7341, 5007, 5007, 5007, 5007, 9, 81, 16047, 8, 2160, 15, 6427, 7342), + (7342, 5007, 5007, 5007, 5007, 9, 83, 16048, 8, 2160, 15, 7341, 7343), + (7343, 5007, 5007, 5007, 5007, 9, 85, 16049, 8, 2160, 15, 7342, 10061), + (7344, 545, 545, 545, 545, 7, 81, 16038, 3, 900, 15, 6002, 7345), + (7345, 545, 545, 545, 545, 9, 83, 16039, 3, 900, 15, 7344, 7346), + (7346, 545, 545, 545, 545, 12, 85, 16040, 3, 900, 15, 7345, 10758), + (7347, 1345, 1345, 1345, 1345, 8, 82, 16041, 6, 900, 15, 6010, 7348), + (7348, 1345, 1345, 1345, 1345, 9, 83, 16042, 6, 900, 15, 7347, 7349), + (7349, 1345, 1345, 1345, 1345, 10, 84, 16043, 6, 900, 15, 7348, 10740), + (7350, 6370, 6370, 6370, 6370, 6, 81, 16044, 7, 600, 15, 6372, 7351), + (7351, 6370, 6370, 6370, 6370, 6, 82, 16045, 7, 600, 15, 7350, 7352), + (7352, 6370, 6370, 6370, 6370, 6, 83, 16046, 7, 600, 15, 7351, 14112), + (7353, -1, -1, 864, 864, 6, 85, -1, 0, 0, 15, 6013, 7354), + (7354, -1, -1, 864, 864, 6, 85, -1, 0, 0, 15, 7353, 7355), + (7355, -1, -1, 864, 864, 6, 85, -1, 0, 0, 15, 7354, -1), + (7356, -1, -1, 5248, 5248, 7, 81, -1, 0, 0, 15, 6016, 7357), + (7357, -1, -1, 5248, 5248, 9, 83, -1, 0, 0, 15, 7356, 7358), + (7358, -1, -1, 5248, 5248, 12, 85, -1, 0, 0, 15, 7357, 16170), + (7359, -1, -1, 644, 644, 7, 79, -1, 0, 0, 15, 6019, 7360), + (7360, -1, -1, 644, 644, 9, 81, -1, 0, 0, 15, 7359, 7361), + (7361, -1, -1, 644, 644, 12, 83, -1, 0, 0, 15, 7360, 13092), + (7362, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 871, 7363), + (7363, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 7362, 7364), + (7364, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 7363, 7365), + (7365, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 7364, 7366), + (7366, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 7365, 10748), + (7367, 872, 872, 872, 872, 3, 70, 16032, 5, 180, 15, 874, 7368), + (7368, 872, 872, 872, 872, 6, 70, 16033, 5, 180, 15, 7367, 7369), + (7369, 872, 872, 872, 872, 9, 70, 16034, 5, 180, 15, 7368, 10772), + (7370, 875, 875, 875, 875, 3, 70, 16035, 5, 180, 15, 877, 7371), + (7371, 875, 875, 875, 875, 6, 73, 16036, 5, 180, 15, 7370, 7372), + (7372, 875, 875, 875, 875, 9, 75, 16037, 5, 180, 15, 7371, 10775), + (7373, -1, -1, 6546, 6546, 0, 81, -1, 0, 0, 15, 6571, 7374), + (7374, -1, -1, 6546, 6546, 0, 82, -1, 0, 0, 15, 7373, 7375), + (7375, -1, -1, 6546, 6546, 0, 83, -1, 0, 0, 15, 7374, 7376), + (7376, -1, -1, 6546, 6546, 0, 84, -1, 0, 0, 15, 7375, 7377), + (7377, -1, -1, 6546, 6546, 0, 85, -1, 0, 0, 15, 7376, 13122), + (7378, -1, -1, 1608, 1608, 3, 71, -1, 0, 0, 15, 4991, 7379), + (7379, -1, -1, 1608, 1608, 6, 73, -1, 0, 0, 15, 7378, 7380), + (7380, -1, -1, 1608, 1608, 9, 75, -1, 0, 0, 15, 7379, 7381), + (7381, -1, -1, 1608, 1608, 6, 76, -1, 0, 0, 15, 7380, 7382), + (7382, -1, -1, 1608, 1608, 6, 78, -1, 0, 0, 15, 7381, 7383), + (7383, -1, -1, 1608, 1608, 6, 80, -1, 0, 0, 15, 7382, 10064), + (7384, -1, -1, 5085, 5085, 6, 81, -1, 0, 0, 15, 6408, 7385), + (7385, -1, -1, 5085, 5085, 6, 83, -1, 0, 0, 15, 7384, 7386), + (7386, -1, -1, 5085, 5085, 6, 85, -1, 0, 0, 15, 7385, 10383), + (7387, 6508, 6508, 6508, 6508, 7, 79, 16059, 38, 600, 15, 6510, 7388), + (7388, 6508, 6508, 6508, 6508, 7, 81, 16060, 38, 600, 15, 7387, 7389), + (7389, 6508, 6508, 6508, 6508, 7, 83, 16061, 38, 600, 15, 7388, 10078), + (7390, -1, -1, 589, 589, 7, 81, -1, 0, 0, 15, 6065, 7391), + (7391, -1, -1, 589, 589, 7, 83, -1, 0, 0, 15, 7390, 7392), + (7392, -1, -1, 589, 589, 7, 85, -1, 0, 0, 15, 7391, 7707), + (7393, -1, -1, 1313, 1313, 7, 81, -1, 0, 0, 15, 6071, 7394), + (7394, -1, -1, 1313, 1313, 7, 81, -1, 0, 0, 15, 7393, 7395), + (7395, -1, -1, 1313, 1313, 8, 82, -1, 0, 0, 15, 7394, 7396), + (7396, -1, -1, 1313, 1313, 9, 83, -1, 0, 0, 15, 7395, 7397), + (7397, -1, -1, 1313, 1313, 10, 84, -1, 0, 0, 15, 7396, 7398), + (7398, -1, -1, 1313, 1313, 12, 85, -1, 0, 0, 15, 7397, 10081), + (7399, -1, -1, 210, 210, 8, 82, -1, 0, 0, 15, 6074, 7400), + (7400, -1, -1, 210, 210, 9, 83, -1, 0, 0, 15, 7399, 7401), + (7401, -1, -1, 210, 210, 10, 84, -1, 0, 0, 15, 7400, 15172), + (7402, -1, -1, 895, 895, 7, 81, -1, 0, 0, 15, 6079, 7403), + (7403, -1, -1, 895, 895, 8, 82, -1, 0, 0, 15, 7402, 7404), + (7404, -1, -1, 895, 895, 9, 83, -1, 0, 0, 15, 7403, 7405), + (7405, -1, -1, 895, 895, 10, 84, -1, 0, 0, 15, 7404, 7406), + (7406, -1, -1, 895, 895, 12, 85, -1, 0, 0, 15, 7405, 10906), + (7407, -1, -1, 7407, 7407, 12, 85, 0, 0, 0, 16, -1, -1), + (7408, 1498, 1498, 1498, 1498, 7, 81, 16075, 12, 1320, 15, 5821, 7409), + (7409, 1498, 1498, 1498, 1498, 9, 83, 16076, 12, 1320, 15, 7408, 7410), + (7410, 1498, 1498, 1498, 1498, 12, 85, 16077, 12, 1320, 15, 7409, 10090), + (7411, 757, -1, 757, 757, 7, 81, 16078, 6, 1800, 15, 5824, 7412), + (7412, 757, -1, 757, 757, 9, 83, 16079, 6, 1800, 15, 7411, 7413), + (7413, 757, -1, 757, 757, 12, 85, 16080, 6, 1800, 15, 7412, 12658), + (7414, 1495, 1495, 1495, 1495, 7, 81, 16081, 30, 900, 15, 5828, 7415), + (7415, 1495, 1495, 1495, 1495, 9, 83, 16082, 30, 900, 15, 7414, 7416), + (7416, 1495, 1495, 1495, 1495, 12, 85, 16083, 30, 900, 15, 7415, 10093), + (7417, 548, 548, 548, 548, 8, 82, 16084, 5, 900, 15, 5831, 7418), + (7418, 548, 548, 548, 548, 9, 83, 16085, 5, 900, 15, 7417, 7419), + (7419, 548, 548, 548, 548, 10, 84, 16086, 5, 900, 15, 7418, 10096), + (7420, 5105, 5105, 5105, 5105, 12, 85, 16087, 11, 600, 15, 5832, 10509), + (7421, 6232, 6232, 6232, 6232, 12, 85, 16091, 18, 900, 15, 6232, -1), + (7422, 6561, 6561, 6561, 6561, 7, 81, 16088, 32, 30, 15, 6280, 7423), + (7423, 6561, 6561, 6561, 6561, 7, 81, 16089, 32, 30, 15, 7422, 7424), + (7424, 6561, 6561, 6561, 6561, 7, 81, 16090, 32, 30, 15, 7423, 10099), + (7425, 510, 510, 510, 510, 3, 66, 16072, 37, 240, 15, 512, 7426), + (7426, 510, 510, 510, 510, 3, 68, 16073, 37, 240, 15, 7425, 7427), + (7427, 510, 510, 510, 510, 3, 70, 16074, 37, 240, 15, 7426, 10102), + (7428, 6533, 6533, 6533, 6533, 10, 84, 13785, 15, 600, 15, 6200, 10139), + (7429, 6534, 6534, 6534, 6534, 9, 83, 13777, 16, 900, 15, 6201, 13524), + (7430, 1116, 1116, 1116, 1116, 7, 81, 13762, 4, 2160, 15, 5701, 7431), + (7431, 1116, 1116, 1116, 1116, 9, 83, 13763, 4, 2160, 15, 7430, 7432), + (7432, 1116, 1116, 1116, 1116, 12, 85, 13764, 4, 2160, 15, 7431, 10140), + (7433, 592, 592, 592, 592, 5, 81, 13765, 2, 18, 15, 5706, 7434), + (7434, 592, 592, 592, 592, 5, 82, 13766, 2, 18, 15, 7433, 7435), + (7435, 592, 592, 592, 592, 5, 83, 13767, 2, 18, 15, 7434, 7436), + (7436, 592, 592, 592, 592, 5, 84, 13768, 2, 18, 15, 7435, 7437), + (7437, 592, 592, 592, 592, 5, 85, 13769, 2, 18, 15, 7436, 12749), + (7438, 5298, 5298, 5298, 5298, 9, 83, 13770, 32, 1800, 15, 5709, 7439), + (7439, 5298, 5298, 5298, 5298, 10, 84, 13771, 32, 1800, 15, 7438, 7440), + (7440, 5298, 5298, 5298, 5298, 12, 85, 13772, 32, 1800, 15, 7439, 10143), + (7441, 1598, -1, 1598, 1598, 7, 81, 13773, 6, 900, 15, 5712, 7442), + (7442, 1598, -1, 1598, 1598, 9, 83, 13774, 6, 900, 15, 7441, 7443), + (7443, 1598, -1, 1598, 1598, 12, 85, 13775, 6, 900, 15, 7442, 10146), + (7444, 5020, 5020, 5020, 5020, 9, 82, 13776, 9, 300, 15, 5716, 10149), + (7445, 1110, 1110, 1110, 1110, 6, 78, 13778, 3, 2160, 15, 6402, 7446), + (7446, 1110, 1110, 1110, 1110, 6, 80, 13779, 3, 2160, 15, 7445, 7447), + (7447, 1110, 1110, 1110, 1110, 6, 81, 13780, 3, 2160, 15, 7446, 10150), + (7448, -1, -1, 6337, 6337, 6, 79, -1, 0, 0, 15, 6339, 7449), + (7449, -1, -1, 6337, 6337, 6, 81, -1, 0, 0, 15, 7448, 7450), + (7450, -1, -1, 6337, 6337, 6, 83, -1, 0, 0, 15, 7449, 10153), + (7451, -1, -1, 6340, 6340, 6, 79, -1, 0, 0, 15, 6342, 7452), + (7452, -1, -1, 6340, 6340, 6, 81, -1, 0, 0, 15, 7451, 7453), + (7453, -1, -1, 6340, 6340, 6, 83, -1, 0, 0, 15, 7452, 16306), + (7454, 5017, 5017, 5017, 5017, 3, 76, 13759, 8, 600, 15, 5019, 7455), + (7455, 5017, 5017, 5017, 5017, 6, 78, 13760, 8, 600, 15, 7454, 7456), + (7456, 5017, 5017, 5017, 5017, 9, 80, 13761, 8, 600, 15, 7455, 10156), + (7457, 1569, 1569, 1569, 1569, 7, 82, 13756, 5, 1800, 15, 5715, 7458), + (7458, 1569, 1569, 1569, 1569, 7, 83, 13757, 5, 1800, 15, 7457, 7459), + (7459, 1569, 1569, 1569, 1569, 7, 85, 13758, 5, 1800, 15, 7458, 10159), + (7460, 1327, 1327, 1327, 1327, 7, 81, 13792, 10, 900, 15, 6100, 7461), + (7461, 1327, 1327, 1327, 1327, 9, 83, 13793, 10, 900, 15, 7460, 7462), + (7462, 1327, 1327, 1327, 1327, 12, 85, 13794, 10, 900, 15, 7461, 10187), + (7463, 1520, 1520, 1520, 1520, 9, 75, 13801, 11, 900, 15, 6451, 7464), + (7464, 1520, 1520, 1520, 1520, 9, 75, 13802, 11, 900, 15, 7463, 7465), + (7465, 1520, 1520, 1520, 1520, 9, 75, 13803, 11, 900, 15, 7464, 10190), + (7466, 146, 146, 146, 146, 8, 82, 13796, 2, 180, 15, 6102, 7691), + (7467, 5109, 5109, 5109, 5109, 9, 82, 13800, 0, 1, 15, 6448, 13016), + (7468, 153, 153, 153, 153, 12, 85, 13795, 3, 2160, 15, 6101, 10193), + (7469, 528, 528, 528, 528, 7, 81, 13797, 5, 720, 15, 6105, 7470), + (7470, 528, 528, 528, 528, 9, 83, 13798, 5, 720, 15, 7469, 7471), + (7471, 528, 528, 528, 528, 12, 85, 13799, 5, 720, 15, 7470, 10194), + (7472, 5251, 5251, 5251, 5251, 7, 81, 13786, 13, 900, 15, 6094, 7473), + (7473, 5251, 5251, 5251, 5251, 9, 83, 13787, 13, 900, 15, 7472, 7474), + (7474, 5251, 5251, 5251, 5251, 12, 85, 13788, 13, 900, 15, 7473, 10197), + (7475, 513, 513, 513, 513, 7, 81, 13789, 4, 120, 15, 6097, 7476), + (7476, 513, 513, 513, 513, 9, 83, 13790, 4, 120, 15, 7475, 7477), + (7477, 513, 513, 513, 513, 12, 85, 13791, 4, 120, 15, 7476, -1), + (7478, -1, -1, 6538, 6538, 12, 85, -1, 0, 0, 15, 6211, 15421), + (7479, 1119, 1119, 1119, 1119, 7, 83, 13805, 8, 900, 15, 5736, 7480), + (7480, 1119, 1119, 1119, 1119, 8, 84, 13806, 8, 900, 15, 7479, 7481), + (7481, 1119, 1119, 1119, 1119, 9, 85, 13807, 8, 900, 15, 7480, 10297), + (7482, 723, 723, 723, 723, 7, 81, 13808, 6, 30, 15, 5737, 10300), + (7483, 5015, 5015, 5015, 5015, 12, 85, 13809, 9, 900, 15, 5741, 10301), + (7484, 289, 289, 289, 289, 12, 85, 13810, 3, 300, 15, 5742, -1), + (7485, 291, 291, 291, 291, 9, 83, 13811, 5, 900, 15, 5745, 7486), + (7486, 291, 291, 291, 291, 10, 84, 13812, 5, 900, 15, 7485, 7487), + (7487, 291, 291, 291, 291, 12, 85, 13813, 5, 900, 15, 7486, 10302), + (7488, 6218, 6218, 6218, 6218, 7, 81, 13814, 0, 1, 15, 6218, 14272), + (7489, -1, -1, 724, 724, 7, 81, -1, 0, 0, 15, 5733, 7490), + (7490, -1, -1, 724, 724, 8, 82, -1, 0, 0, 15, 7489, 7491), + (7491, -1, -1, 724, 724, 9, 83, -1, 0, 0, 15, 7490, 7492), + (7492, -1, -1, 724, 724, 10, 84, -1, 0, 0, 15, 7491, 7493), + (7493, -1, -1, 724, 724, 12, 85, -1, 0, 0, 15, 7492, 16890), + (7494, -1, -1, 729, 729, 7, 81, -1, 0, 0, 15, 5740, 7495), + (7495, -1, -1, 729, 729, 8, 82, -1, 0, 0, 15, 7494, 7496), + (7496, -1, -1, 729, 729, 9, 83, -1, 0, 0, 15, 7495, 10305), + (7497, 6380, 6380, 6380, 6380, 6, 83, 13815, 39, 120, 15, 6382, 7498), + (7498, 6380, 6380, 6380, 6380, 6, 84, 13816, 39, 120, 15, 7497, 7499), + (7499, 6380, 6380, 6380, 6380, 6, 85, 13817, 39, 120, 15, 7498, 10308), + (7500, -1, -1, 4699, 4699, 5, 61, -1, 0, 0, 15, 6540, 10788), + (7501, -1, -1, 125, 125, 6, 81, -1, 0, 0, 15, 5523, 7502), + (7502, -1, -1, 125, 125, 7, 82, -1, 0, 0, 15, 7501, 7503), + (7503, -1, -1, 125, 125, 8, 83, -1, 0, 0, 15, 7502, 7504), + (7504, -1, -1, 125, 125, 9, 84, -1, 0, 0, 15, 7503, 7505), + (7505, -1, -1, 125, 125, 10, 85, -1, 0, 0, 15, 7504, 12396), + (7506, -1, -1, 122, 122, 6, 81, -1, 0, 0, 15, 5528, 7507), + (7507, -1, -1, 122, 122, 7, 82, -1, 0, 0, 15, 7506, 7508), + (7508, -1, -1, 122, 122, 8, 83, -1, 0, 0, 15, 7507, 7509), + (7509, -1, -1, 122, 122, 9, 84, -1, 0, 0, 15, 7508, 7510), + (7510, -1, -1, 122, 122, 10, 85, -1, 0, 0, 15, 7509, 12401), + (7511, -1, -1, 1026, 1026, 5, 81, -1, 0, 0, 15, 6527, 7512), + (7512, -1, -1, 1026, 1026, 5, 82, -1, 0, 0, 15, 7511, 7513), + (7513, -1, -1, 1026, 1026, 5, 83, -1, 0, 0, 15, 7512, 7514), + (7514, -1, -1, 1026, 1026, 5, 84, -1, 0, 0, 15, 7513, 7515), + (7515, -1, -1, 1026, 1026, 5, 85, -1, 0, 0, 15, 7514, 7886), + (7516, -1, -1, 1006, 1006, 5, 71, -1, 0, 0, 15, 1010, 7517), + (7517, -1, -1, 1006, 1006, 5, 72, -1, 0, 0, 15, 7516, 7518), + (7518, -1, -1, 1006, 1006, 5, 73, -1, 0, 0, 15, 7517, 7519), + (7519, -1, -1, 1006, 1006, 5, 74, -1, 0, 0, 15, 7518, 7520), + (7520, -1, -1, 1006, 1006, 5, 75, -1, 0, 0, 15, 7519, 7837), + (7521, -1, -1, 1056, 1056, 5, 81, -1, 0, 0, 15, 6435, 7522), + (7522, -1, -1, 1056, 1056, 5, 82, -1, 0, 0, 15, 7521, 7523), + (7523, -1, -1, 1056, 1056, 5, 83, -1, 0, 0, 15, 7522, 7524), + (7524, -1, -1, 1056, 1056, 5, 84, -1, 0, 0, 15, 7523, 7525), + (7525, -1, -1, 1056, 1056, 5, 85, -1, 0, 0, 15, 7524, 16414), + (7526, -1, -1, 6119, 6119, 6, 81, -1, 0, 0, 15, 6123, 7527), + (7527, -1, -1, 6119, 6119, 6, 82, -1, 0, 0, 15, 7526, 7528), + (7528, -1, -1, 6119, 6119, 6, 83, -1, 0, 0, 15, 7527, 7529), + (7529, -1, -1, 6119, 6119, 6, 84, -1, 0, 0, 15, 7528, 7530), + (7530, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 15, 7529, 12406), + (7534, -1, -1, 65, 661, 3, 81, -1, 0, 0, 15, 6394, 7535), + (7535, -1, -1, 65, 661, 3, 82, -1, 0, 0, 15, 7534, 7536), + (7536, -1, -1, 65, 661, 3, 83, -1, 0, 0, 15, 7535, 7537), + (7537, -1, -1, 65, 661, 3, 84, -1, 0, 0, 15, 7536, 7538), + (7538, -1, -1, 65, 661, 3, 85, -1, 0, 0, 15, 7537, 7904), + (7539, -1, -1, 1021, 1021, 5, 80, -1, 0, 0, 16, 6522, 7540), + (7540, -1, -1, 1021, 1021, 5, 85, -1, 0, 0, 16, 7539, 7683), + (7541, -1, -1, 107, 107, 2, 60, -1, 0, 0, 15, 109, 7542), + (7542, -1, -1, 107, 107, 4, 60, -1, 0, 0, 15, 7541, 7543), + (7543, -1, -1, 107, 107, 6, 60, -1, 0, 0, 15, 7542, -1), + (7544, -1, -1, 678, 678, 3, 70, -1, 0, 0, 15, 6520, 7545), + (7545, -1, -1, 678, 678, 3, 70, -1, 0, 0, 15, 7544, 7546), + (7546, -1, -1, 678, 678, 3, 70, -1, 0, 0, 15, 7545, -1), + (7547, -1, -1, 418, 418, 5, 76, -1, 0, 0, 15, 4682, 7548), + (7548, -1, -1, 418, 418, 5, 77, -1, 0, 0, 15, 7547, 7549), + (7549, -1, -1, 418, 418, 5, 78, -1, 0, 0, 15, 7548, 7550), + (7550, -1, -1, 418, 418, 5, 79, -1, 0, 0, 15, 7549, 7551), + (7551, -1, -1, 418, 418, 5, 80, -1, 0, 0, 15, 7550, -1), + (7553, -1, -1, 1071, 1071, 6, 80, -1, 0, 0, 16, 4764, 7681), + (7554, -1, -1, 1486, 1486, 7, 81, -1, 0, 0, 15, 5533, 7555), + (7555, -1, -1, 1486, 1486, 8, 82, -1, 0, 0, 15, 7554, 7556), + (7556, -1, -1, 1486, 1486, 9, 83, -1, 0, 0, 15, 7555, 7557), + (7557, -1, -1, 1486, 1486, 10, 84, -1, 0, 0, 15, 7556, 7558), + (7558, -1, -1, 1486, 1486, 12, 85, -1, 0, 0, 15, 7557, 7722), + (7559, -1, -1, 599, 599, 9, 83, -1, 0, 0, 15, 5536, 7560), + (7560, -1, -1, 599, 599, 10, 84, -1, 0, 0, 15, 7559, 7561), + (7561, -1, -1, 599, 599, 12, 85, -1, 0, 0, 15, 7560, 13026), + (7562, -1, -1, 1041, 1041, 7, 81, -1, 0, 0, 15, 5544, 7563), + (7563, -1, -1, 1041, 1041, 9, 83, -1, 0, 0, 15, 7562, 7564), + (7564, -1, -1, 1041, 1041, 12, 85, -1, 0, 0, 15, 7563, 12697), + (7565, -1, -1, 119, 119, 7, 81, -1, 0, 0, 15, 5556, 7566), + (7566, -1, -1, 119, 119, 9, 83, -1, 0, 0, 15, 7565, 7567), + (7567, -1, -1, 119, 119, 12, 85, -1, 0, 0, 15, 7566, 6023), + (7568, -1, -1, 1592, 1592, 7, 81, -1, 0, 0, 15, 5561, 7569), + (7569, -1, -1, 1592, 1592, 8, 82, -1, 0, 0, 15, 7568, 7570), + (7570, -1, -1, 1592, 1592, 9, 83, -1, 0, 0, 15, 7569, 7571), + (7571, -1, -1, 1592, 1592, 10, 84, -1, 0, 0, 15, 7570, 7572), + (7572, -1, -1, 1592, 1592, 12, 85, -1, 0, 0, 15, 7571, 12439), + (7573, -1, -1, 4739, 4739, 7, 81, -1, 0, 0, 15, 5564, 7574), + (7574, -1, -1, 4739, 4739, 9, 83, -1, 0, 0, 15, 7573, 7575), + (7575, -1, -1, 4739, 4739, 12, 85, -1, 0, 0, 15, 7574, -1), + (7576, -1, -1, 1072, 1072, 7, 81, -1, 0, 0, 15, 5570, 7577), + (7577, -1, -1, 1072, 1072, 8, 82, -1, 0, 0, 15, 7576, 7578), + (7578, -1, -1, 1072, 1072, 9, 83, -1, 0, 0, 15, 7577, 7579), + (7579, -1, -1, 1072, 1072, 10, 84, -1, 0, 0, 15, 7578, 7580), + (7580, -1, -1, 1072, 1072, 12, 85, -1, 0, 0, 15, 7579, 12444), + (7581, -1, -1, 1210, 1213, 7, 81, -1, 0, 0, 15, 5579, 7582), + (7582, -1, -1, 1210, 1213, 9, 83, -1, 0, 0, 15, 7581, 7583), + (7583, -1, -1, 1210, 1213, 12, 85, -1, 0, 0, 15, 7582, 8344), + (7584, -1, -1, 98, 98, 7, 81, -1, 0, 0, 15, 5588, 7585), + (7585, -1, -1, 98, 98, 9, 83, -1, 0, 0, 15, 7584, 7586), + (7586, -1, -1, 98, 98, 12, 85, -1, 0, 0, 15, 7585, 11061), + (7587, -1, -1, 1186, 1186, 7, 81, -1, 0, 0, 15, 5591, 7588), + (7588, -1, -1, 1186, 1186, 9, 83, -1, 0, 0, 15, 7587, 7589), + (7589, -1, -1, 1186, 1186, 12, 85, -1, 0, 0, 15, 7588, 7692), + (7590, -1, -1, 80, 80, 7, 81, -1, 0, 0, 15, 5594, 7591), + (7591, -1, -1, 80, 80, 9, 83, -1, 0, 0, 15, 7590, 7592), + (7592, -1, -1, 80, 80, 12, 85, -1, 0, 0, 15, 7591, 12452), + (7593, -1, -1, 658, 658, 5, 81, -1, 0, 0, 15, 5627, 7594), + (7594, -1, -1, 658, 658, 5, 82, -1, 0, 0, 15, 7593, 7595), + (7595, -1, -1, 658, 658, 5, 83, -1, 0, 0, 15, 7594, 7596), + (7596, -1, -1, 658, 658, 5, 84, -1, 0, 0, 15, 7595, 7597), + (7597, -1, -1, 658, 658, 5, 85, -1, 0, 0, 15, 7596, 12455), + (7598, -1, -1, 98, 738, 7, 81, -1, 0, 0, 15, 5630, 7599), + (7599, -1, -1, 98, 738, 9, 83, -1, 0, 0, 15, 7598, 7600), + (7600, -1, -1, 98, 738, 12, 85, -1, 0, 0, 15, 7599, 13924), + (7601, -1, -1, 6051, 6051, 3, 81, -1, 0, 0, 15, 6053, 7602), + (7602, -1, -1, 6051, 6051, 3, 83, -1, 0, 0, 15, 7601, 7603), + (7603, -1, -1, 6051, 6051, 3, 85, -1, 0, 0, 15, 7602, 10604), + (7604, -1, -1, 683, 683, 5, 80, -1, 0, 0, 15, 6081, 7605), + (7605, -1, -1, 683, 683, 5, 80, -1, 0, 0, 15, 7604, 12694), + (7606, 6537, 6537, 6537, 6537, 7, 81, 13821, 30, 900, 15, 6208, 7607), + (7607, 6537, 6537, 6537, 6537, 8, 82, 13822, 30, 900, 15, 7606, 7608), + (7608, 6537, 6537, 6537, 6537, 9, 83, 13823, 30, 900, 15, 7607, 12460), + (7609, 6539, 6539, 6539, 6539, 6, 76, 13824, 18, 1800, 15, 6214, 7610), + (7610, 6539, 6539, 6539, 6539, 6, 79, 13825, 18, 1800, 15, 7609, 7611), + (7611, 6539, 6539, 6539, 6539, 6, 82, 13826, 18, 1800, 15, 7610, 12942), + (7612, -1, -1, 270, 665, 2, 66, -1, 0, 0, 15, 670, 7613), + (7613, -1, -1, 270, 665, 2, 67, -1, 0, 0, 15, 7612, 7614), + (7614, -1, -1, 270, 665, 2, 68, -1, 0, 0, 15, 7613, -1), + (7615, -1, -1, 6346, 6346, 6, 79, -1, 0, 0, 15, 6348, 7616), + (7616, -1, -1, 6346, 6346, 6, 81, -1, 0, 0, 15, 7615, 7617), + (7617, -1, -1, 6346, 6346, 6, 83, -1, 0, 0, 15, 7616, 15397), + (7618, -1, -1, 6349, 6349, 6, 79, -1, 0, 0, 15, 6351, 7619), + (7619, -1, -1, 6349, 6349, 6, 81, -1, 0, 0, 15, 7618, 7620), + (7620, -1, -1, 6349, 6349, 6, 83, -1, 0, 0, 15, 7619, 11053), + (7621, -1, -1, 1435, 4773, 9, 81, -1, 0, 0, 15, 6517, 13090), + (7622, -1, -1, 446, 735, 8, 81, -1, 0, 0, 15, 7065, 7623), + (7623, -1, -1, 446, 735, 8, 82, -1, 0, 0, 15, 7622, 7624), + (7624, -1, -1, 446, 735, 8, 83, -1, 0, 0, 15, 7623, 10473), + (7625, -1, -1, 735, 735, 8, 81, -1, 0, 0, 15, 7068, 7626), + (7626, -1, -1, 735, 735, 8, 82, -1, 0, 0, 15, 7625, 7627), + (7627, -1, -1, 735, 735, 8, 83, -1, 0, 0, 15, 7626, 10632), + (7628, -1, -1, 807, 807, 5, 81, -1, 0, 0, 15, 5924, 7629), + (7629, -1, -1, 807, 807, 5, 83, -1, 0, 0, 15, 7628, 7630), + (7630, -1, -1, 807, 807, 5, 85, -1, 0, 0, 15, 7629, 12685), + (7631, -1, -1, 255, 255, 7, 81, -1, 0, 0, 15, 5597, 7632), + (7632, -1, -1, 255, 255, 9, 83, -1, 0, 0, 15, 7631, 7633), + (7633, -1, -1, 255, 255, 12, 85, -1, 0, 0, 15, 7632, 17441), + (7634, -1, -1, 815, 815, 9, 83, -1, 0, 0, 15, 5913, 7635), + (7635, -1, -1, 815, 815, 10, 84, -1, 0, 0, 15, 7634, 7636), + (7636, -1, -1, 815, 815, 12, 85, -1, 0, 0, 15, 7635, 15441), + (7637, -1, -1, 1616, 1616, 5, 83, -1, 0, 0, 15, 6007, 7638), + (7638, -1, -1, 1616, 1616, 5, 84, -1, 0, 0, 15, 7637, 7639), + (7639, -1, -1, 1616, 1616, 5, 85, -1, 0, 0, 15, 7638, -1), + (7640, -1, -1, 686, 686, 5, 60, -1, 0, 0, 15, 690, 12438), + (7641, -1, -1, 625, 625, 3, 76, -1, 0, 0, 15, 4735, 7642), + (7642, -1, -1, 625, 625, 3, 78, -1, 0, 0, 15, 7641, 7643), + (7643, -1, -1, 625, 625, 3, 80, -1, 0, 0, 15, 7642, -1), + (7644, -1, -1, 6375, 6375, 6, 81, -1, 0, 0, 15, 6377, 7645), + (7645, -1, -1, 6375, 6375, 6, 82, -1, 0, 0, 15, 7644, 7646), + (7646, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 15, 7645, 7663), + (7647, -1, -1, 692, 692, 6, 60, -1, 0, 0, 15, 694, 7648), + (7648, -1, -1, 692, 692, 6, 60, -1, 0, 0, 15, 7647, 7649), + (7649, -1, -1, 692, 692, 6, 60, -1, 0, 0, 15, 7648, 7670), + (7650, -1, -1, 1044, 1044, 7, 81, -1, 0, 0, 15, 5547, 7651), + (7651, -1, -1, 1044, 1044, 9, 83, -1, 0, 0, 15, 7650, 7652), + (7652, -1, -1, 1044, 1044, 12, 85, -1, 0, 0, 15, 7651, 13074), + (7653, -1, -1, 1047, 1047, 7, 81, -1, 0, 0, 15, 5550, 7654), + (7654, -1, -1, 1047, 1047, 9, 83, -1, 0, 0, 15, 7653, 7655), + (7655, -1, -1, 1047, 1047, 12, 85, -1, 0, 0, 15, 7654, 13077), + (7656, -1, -1, 1050, 1050, 7, 81, -1, 0, 0, 15, 5553, 7657), + (7657, -1, -1, 1050, 1050, 9, 83, -1, 0, 0, 15, 7656, 7658), + (7658, -1, -1, 1050, 1050, 12, 85, -1, 0, 0, 15, 7657, 13023), + (7659, -1, -1, 754, 754, 3, 70, -1, 0, 0, 15, 756, 7660), + (7660, -1, -1, 754, 754, 6, 70, -1, 0, 0, 15, 7659, 7661), + (7661, -1, -1, 754, 754, 9, 70, -1, 0, 0, 15, 7660, -1), + (7662, 188, 188, 188, 188, 9, 83, 16431, 2, 30, 15, 7339, 10647), + (7663, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 15, 7646, 10084), + (7664, -1, -1, 7664, 7664, 2, 73, -1, 0, 0, 15, -1, 7665), + (7665, -1, -1, 7664, 7664, 2, 74, -1, 0, 0, 15, 7664, 7666), + (7666, -1, -1, 7664, 7664, 2, 75, -1, 0, 0, 15, 7665, 7667), + (7667, -1, -1, 7664, 7664, 2, 76, -1, 0, 0, 15, 7666, 7668), + (7668, -1, -1, 7664, 7664, 2, 77, -1, 0, 0, 15, 7667, 10105), + (7669, 7669, 7669, 7669, 7669, 3, 81, 13838, 35, 5, 15, -1, -1), + (7670, -1, -1, 692, 692, 7, 75, -1, 0, 0, 16, 7649, 7671), + (7671, -1, -1, 692, 692, 9, 80, -1, 0, 0, 16, 7670, 7672), + (7672, -1, -1, 692, 692, 12, 85, -1, 0, 0, 16, 7671, 12767), + (7673, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 859, 7674), + (7674, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 7673, 7675), + (7675, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 7674, 7676), + (7676, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 7675, 7677), + (7677, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 7676, 10688), + (7678, -1, -1, 852, 852, 9, 81, -1, 0, 0, 16, 5502, 7679), + (7679, -1, -1, 852, 852, 10, 83, -1, 0, 0, 16, 7678, 7680), + (7680, -1, -1, 852, 852, 12, 85, -1, 0, 0, 16, 7679, 12576), + (7681, -1, -1, 1071, 1071, 6, 80, -1, 0, 0, 16, 7553, -1), + (7682, -1, -1, 4861, 4861, 12, 85, -1, 0, 0, 16, 7216, 12757), + (7683, -1, -1, 1021, 1021, 5, 85, -1, 0, 0, 16, 7540, 7684), + (7684, -1, -1, 1021, 1021, 5, 85, -1, 0, 0, 16, 7683, 7685), + (7685, -1, -1, 1021, 1021, 5, 85, -1, 0, 0, 16, 7684, 13894), + (7686, -1, -1, 4844, 4844, 5, 81, -1, 0, 0, 16, 7126, 7687), + (7687, -1, -1, 4844, 4844, 5, 83, -1, 0, 0, 16, 7686, 7688), + (7688, -1, -1, 4844, 4844, 5, 85, -1, 0, 0, 16, 7687, -1), + (7689, 7689, 7689, 7689, 7689, 12, 85, 21820, 94, 180, 16, -1, -1), + (7690, -1, -1, 7690, 7690, 12, 85, -1, 0, 0, 16, -1, -1), + (7691, 146, 146, 146, 146, 8, 85, 16862, 2, 180, 16, 7466, 13256), + (7692, -1, -1, 1186, 1186, 12, 85, -1, 0, 0, 16, 7589, 7693), + (7693, -1, -1, 1186, 1186, 12, 85, -1, 0, 0, 16, 7692, 7694), + (7694, -1, -1, 1186, 1186, 12, 85, -1, 0, 0, 16, 7693, 12564), + (7695, -1, -1, 7695, 7695, 6, 85, -1, 0, 0, 16, -1, 7696), + (7696, -1, -1, 7695, 7695, 6, 85, -1, 0, 0, 16, 7695, 7697), + (7697, -1, -1, 7695, 7695, 6, 85, -1, 0, 0, 16, 7696, -1), + (7698, 7698, 7698, 7698, 7698, 6, 85, 21763, 17, 6, 16, -1, -1), + (7699, -1, -1, 7699, 7699, 12, 85, 0, 0, 0, 16, -1, -1), + (7700, -1, -1, 255, 255, 7, 81, -1, 0, 0, 16, -1, 7701), + (7701, -1, -1, 255, 255, 9, 83, -1, 0, 0, 16, 7700, 7702), + (7702, -1, -1, 255, 255, 12, 85, -1, 0, 0, 16, 7701, 12610), + (7703, 7703, 7703, 7703, 7703, 12, 85, 21754, 16, 600, 16, -1, -1), + (7704, -1, -1, 8195, 8195, 5, 81, -1, 0, 0, 16, 8197, 7705), + (7705, -1, -1, 8195, 8195, 5, 83, -1, 0, 0, 16, 7704, 7706), + (7706, -1, -1, 8195, 8195, 5, 85, -1, 0, 0, 16, 7705, -1), + (7707, -1, -1, 589, 589, 7, 85, -1, 0, 0, 16, 7392, 7708), + (7708, -1, -1, 589, 589, 7, 85, -1, 0, 0, 16, 7707, 7709), + (7709, -1, -1, 589, 589, 7, 85, -1, 0, 0, 16, 7708, 13104), + (7710, 5984, 5984, 5984, 5984, 12, 85, 21679, 2, 30, 16, 7335, 7711), + (7711, 5984, 5984, 5984, 5984, 12, 85, 21680, 2, 30, 16, 7710, 10626), + (7712, 7712, 7712, 7712, 7712, 12, 85, 21682, 2, 30, 16, -1, 10646), + (7713, -1, -1, 634, 634, 12, 81, -1, 0, 0, 16, 5613, 7714), + (7714, -1, -1, 634, 634, 12, 83, -1, 0, 0, 16, 7713, 10778), + (7715, -1, -1, 7715, 7715, 5, 77, 0, 0, 0, 16, -1, 7716), + (7716, -1, -1, 7715, 7715, 5, 79, 0, 0, 0, 16, 7715, 7717), + (7717, -1, -1, 7715, 7715, 5, 81, 0, 0, 0, 16, 7716, 14314), + (7718, -1, -1, 574, 574, 3, 81, -1, 0, 0, 16, 576, -1), + (7722, -1, -1, 1486, 1486, 7, 86, -1, 0, 0, 17, 7558, 7723), + (7723, -1, -1, 1486, 1486, 8, 87, -1, 0, 0, 17, 7722, 7724), + (7724, -1, -1, 1486, 1486, 9, 88, -1, 0, 0, 17, 7723, 7725), + (7725, -1, -1, 1486, 1486, 10, 89, -1, 0, 0, 17, 7724, 7726), + (7726, -1, -1, 1486, 1486, 12, 90, -1, 0, 0, 17, 7725, 7842), + (7732, 7732, 7732, 7732, 7732, 0, 60, 7732, 34, 3600, 14, -1, -1), + (7733, -1, -1, 288, 288, 6, 65, -1, 0, 0, 14, -1, -1), + (7734, 7734, 7734, 7734, 7734, 0, 61, 7734, 34, 28800, 14, -1, -1), + (7735, 7735, 7735, 7735, 7735, 0, 51, 7731, 32, 3600, 9, -1, -1), + (7736, 7736, 7736, 7736, 7736, 0, 52, 7865, 32, 10800, 9, -1, -1), + (7737, 7737, 7737, 7737, 7737, 0, 53, 7733, 32, 10800, 9, -1, -1), + (7738, 7738, 7738, 7738, 7738, 0, 54, 7990, 32, 21600, 9, -1, -1), + (7739, 7739, 7739, 7739, 7739, 0, 65, 13064, 36, 3600, 0, -1, -1), + (7740, 7740, 7740, 7740, 7740, 0, 66, 13065, 36, 28800, 0, -1, -1), + (7741, 7741, 7741, 7741, 7741, 0, 70, 21854, 50, 3600, 0, -1, -1), + (7742, 7742, 7742, 7742, 7742, 0, 71, 21855, 50, 28800, 0, -1, -1), + (7743, -1, -1, 7743, 7743, 5, 61, -1, 0, 0, 16, -1, 7744), + (7744, -1, -1, 7743, 7743, 7, 61, -1, 0, 0, 16, 7743, 7745), + (7745, -1, -1, 7743, 7743, 9, 61, -1, 0, 0, 16, 7744, 10717), + (7746, -1, -1, 7746, 7746, 5, 85, -1, 0, 0, 16, -1, 7763), + (7747, 7747, 7747, 7747, 7747, 9, 85, 21790, 32, 180, 16, -1, -1), + (7748, -1, -1, 7748, 7748, 3, 81, -1, 0, 0, 16, -1, 7749), + (7749, -1, -1, 7748, 7748, 6, 83, -1, 0, 0, 16, 7748, 7750), + (7750, -1, -1, 7748, 7748, 9, 85, -1, 0, 0, 16, 7749, -1), + (7751, -1, -1, 7751, 7751, 5, 85, -1, 0, 0, 16, -1, 7752), + (7752, -1, -1, 7751, 7751, 5, 85, -1, 0, 0, 16, 7751, 7753), + (7753, -1, -1, 7751, 7751, 5, 85, -1, 0, 0, 16, 7752, 14132), + (7754, 7754, 7754, 7754, 7754, 9, 85, 21803, 0, 1, 16, -1, -1), + (7755, 7755, 7755, 7755, 7755, 9, 81, 21804, 53, 900, 16, -1, 15782), + (7756, 7756, 7756, 7756, 7756, 12, 85, 21805, 54, 120, 16, -1, -1), + (7757, -1, -1, 7757, 7757, 5, 85, -1, 0, 0, 16, -1, 7758), + (7758, -1, -1, 7757, 7757, 7, 85, -1, 0, 0, 16, 7757, 7759), + (7759, -1, -1, 7757, 7757, 9, 85, -1, 0, 0, 16, 7758, 12587), + (7760, -1, -1, 7760, 7760, 5, 85, -1, 0, 0, 16, -1, 7761), + (7761, -1, -1, 7760, 7760, 7, 85, -1, 0, 0, 16, 7760, 7762), + (7762, -1, -1, 7760, 7760, 9, 85, -1, 0, 0, 16, 7761, -1), + (7763, -1, -1, 7746, 7746, 5, 85, -1, 0, 0, 16, 7746, 7764), + (7764, -1, -1, 7746, 7746, 5, 85, -1, 0, 0, 16, 7763, -1), + (7765, -1, -1, 7765, 7765, 5, 86, 0, 0, 0, 17, -1, 7766), + (7766, -1, -1, 7765, 7765, 7, 87, 0, 0, 0, 17, 7765, 7767), + (7767, -1, -1, 7765, 7765, 9, 88, 0, 0, 0, 17, 7766, 7768), + (7768, -1, -1, 7765, 7765, 12, 89, 0, 0, 0, 17, 7767, 7769), + (7770, 131, 131, 131, 131, 9, 86, 27655, 4, 900, 17, 10018, 7771), + (7771, 131, 131, 131, 131, 12, 88, 27656, 4, 900, 17, 7770, 7772), + (7772, 131, 131, 131, 131, 15, 90, 27657, 4, 900, 17, 7771, 13374), + (7773, 7951, 7951, 7951, 7951, 9, 86, 27658, 61, 900, 17, 10040, 7774), + (7774, 7951, 7951, 7951, 7951, 9, 88, 27659, 61, 900, 17, 7773, 7775), + (7775, 7951, 7951, 7951, 7951, 9, 90, 27660, 61, 900, 17, 7774, 13377), + (7800, 7800, 7800, 7800, 7800, 0, 1, 13531, 39, 4320, 0, -1, 7801), + (7801, 7800, 7800, 7800, 7800, 0, 6, 13532, 39, 4320, 0, 7800, 7802), + (7802, 7800, 7800, 7800, 7800, 0, 11, 13533, 39, 4320, 0, 7801, 7803), + (7803, 7800, 7800, 7800, 7800, 0, 16, 13534, 39, 4320, 0, 7802, 7804), + (7804, 7800, 7800, 7800, 7800, 0, 21, 13535, 39, 4320, 0, 7803, 7805), + (7805, 7800, 7800, 7800, 7800, 0, 26, 13536, 39, 4320, 0, 7804, 7806), + (7806, 7800, 7800, 7800, 7800, 0, 31, 13537, 39, 4320, 0, 7805, 7807), + (7807, 7800, 7800, 7800, 7800, 0, 36, 13538, 39, 4320, 0, 7806, 7808), + (7808, 7800, 7800, 7800, 7800, 0, 41, 13539, 39, 4320, 0, 7807, 7809), + (7809, 7800, 7800, 7800, 7800, 0, 46, 13540, 39, 4320, 0, 7808, 7810), + (7810, 7800, 7800, 7800, 7800, 3, 51, 13541, 39, 4320, 0, 7809, 7811), + (7811, 7800, 7800, 7800, 7800, 4, 56, 13542, 39, 4320, 0, 7810, 7812), + (7812, 7800, 7800, 7800, 7800, 5, 61, 13543, 39, 4320, 0, 7811, 7813), + (7813, 7800, 7800, 7800, 7800, 6, 66, 13544, 39, 4320, 0, 7812, 7814), + (7814, 7800, 7800, 7800, 7800, 7, 71, 13545, 39, 4320, 0, 7813, 7815), + (7815, 7800, 7800, 7800, 7800, 8, 76, 13562, 39, 4320, 0, 7814, 7816), + (7816, 7800, 7800, 7800, 7800, 8, 81, 16062, 39, 4320, 0, 7815, 7817), + (7817, 7800, 7800, 7800, 7800, 9, 83, 16855, 39, 4320, 0, 7816, 10786), + (7818, -1, -1, 7818, 7818, 12, 85, 21750, 0, 0, 16, -1, 13029), + (7819, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 9514, 7820), + (7820, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7819, 7821), + (7821, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7820, 7881), + (7822, -1, -1, 7822, 7822, 5, 77, 0, 0, 0, 16, -1, 7823), + (7823, -1, -1, 7822, 7822, 5, 79, 0, 0, 0, 16, 7822, 7824), + (7824, -1, -1, 7822, 7822, 5, 81, 0, 0, 0, 16, 7823, 7825), + (7825, -1, -1, 7822, 7822, 5, 83, 0, 0, 0, 16, 7824, 7826), + (7826, -1, -1, 7822, 7822, 5, 85, 0, 0, 0, 16, 7825, 14328), + (7827, -1, -1, 7827, 7827, 5, 81, 0, 0, 0, 16, -1, -1), + (7828, -1, -1, 7828, 7828, 5, 79, 0, 0, 0, 16, -1, 7829), + (7829, -1, -1, 7828, 7828, 5, 81, 0, 0, 0, 16, 7828, 7830), + (7830, -1, -1, 7828, 7828, 5, 83, 0, 0, 0, 16, 7829, -1), + (7832, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, -1, 7833), + (7833, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, 7832, 7834), + (7834, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, 7833, 7835), + (7835, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, 7834, 7836), + (7836, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, 7835, -1), + (7837, -1, -1, 1006, 1006, 5, 76, -1, 0, 0, 17, 7520, 7838), + (7838, -1, -1, 1006, 1006, 5, 77, -1, 0, 0, 17, 7837, 7839), + (7839, -1, -1, 1006, 1006, 5, 78, -1, 0, 0, 17, 7838, 7840), + (7840, -1, -1, 1006, 1006, 5, 79, -1, 0, 0, 17, 7839, 7841), + (7841, -1, -1, 1006, 1006, 5, 80, -1, 0, 0, 17, 7840, 8470), + (7842, -1, -1, 1486, 1486, 12, 91, -1, 0, 0, 18, 7726, 7843), + (7843, -1, -1, 1486, 1486, 12, 92, -1, 0, 0, 18, 7842, 7844), + (7844, -1, -1, 1486, 1486, 12, 93, -1, 0, 0, 18, 7843, 7845), + (7850, 7850, 7850, 7850, 7850, 0, 1, 13546, 39, 4320, 0, -1, 7851), + (7851, 7850, 7850, 7850, 7850, 0, 6, 13547, 39, 4320, 0, 7850, 7852), + (7852, 7850, 7850, 7850, 7850, 0, 11, 13548, 39, 4320, 0, 7851, 7853), + (7853, 7850, 7850, 7850, 7850, 0, 16, 13549, 39, 4320, 0, 7852, 7854), + (7854, 7850, 7850, 7850, 7850, 0, 21, 13550, 39, 4320, 0, 7853, 7855), + (7855, 7850, 7850, 7850, 7850, 0, 26, 13551, 39, 4320, 0, 7854, 7856), + (7856, 7850, 7850, 7850, 7850, 0, 31, 13552, 39, 4320, 0, 7855, 7857), + (7857, 7850, 7850, 7850, 7850, 0, 36, 13553, 39, 4320, 0, 7856, 7858), + (7858, 7850, 7850, 7850, 7850, 0, 41, 13554, 39, 4320, 0, 7857, 7859), + (7859, 7850, 7850, 7850, 7850, 0, 46, 13555, 39, 4320, 0, 7858, 7860), + (7860, 7850, 7850, 7850, 7850, 3, 51, 13556, 39, 4320, 0, 7859, 7861), + (7861, 7850, 7850, 7850, 7850, 4, 56, 13557, 39, 4320, 0, 7860, 7862), + (7862, 7850, 7850, 7850, 7850, 5, 61, 13558, 39, 4320, 0, 7861, 7863), + (7863, 7850, 7850, 7850, 7850, 6, 66, 13559, 39, 4320, 0, 7862, 7864), + (7864, 7850, 7850, 7850, 7850, 7, 71, 13560, 39, 4320, 0, 7863, 7865), + (7865, 7850, 7850, 7850, 7850, 8, 76, 13561, 39, 4320, 0, 7864, 7340), + (7869, 7869, 7869, 7869, 7869, 6, 73, 16175, 60, 30, 15, -1, 7870), + (7870, 7869, 7869, 7869, 7869, 6, 77, 16176, 60, 30, 15, 7869, 7871), + (7871, 7869, 7869, 7869, 7869, 6, 81, 16177, 60, 30, 15, 7870, -1), + (7872, 7872, 7872, 7872, 7872, 6, 76, 16178, 41, 600, 15, -1, 7873), + (7873, 7872, 7872, 7872, 7872, 6, 81, 16179, 41, 600, 15, 7872, 7874), + (7874, 7872, 7872, 7872, 7872, 6, 85, 16180, 41, 600, 15, 7873, 10127), + (7875, 7875, 7875, 7875, 7875, 6, 76, 16181, 42, 600, 15, -1, 7876), + (7876, 7875, 7875, 7875, 7875, 6, 81, 16182, 42, 600, 15, 7875, 7877), + (7877, 7875, 7875, 7875, 7875, 6, 85, 16183, 42, 600, 15, 7876, 7878), + (7878, 7875, 7875, 7875, 7875, 6, 85, 16859, 42, 600, 16, 7877, 7879), + (7879, 7875, 7875, 7875, 7875, 6, 85, 21823, 42, 600, 16, 7878, 7880), + (7880, 7875, 7875, 7875, 7875, 6, 85, 21824, 42, 600, 16, 7879, 13816), + (7881, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7821, 7882), + (7882, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7881, 7883), + (7883, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7882, 13187), + (7884, -1, -1, 7884, 7884, 9, 85, -1, 0, 0, 16, -1, 12689), + (7885, -1, -1, 7885, 7885, 9, 85, -1, 0, 0, 16, -1, 12690), + (7886, -1, -1, 1026, 1026, 5, 85, -1, 0, 0, 17, 7515, 7887), + (7887, -1, -1, 1026, 1026, 5, 86, -1, 0, 0, 17, 7886, 7888), + (7888, -1, -1, 1026, 1026, 5, 87, -1, 0, 0, 17, 7887, 7889), + (7889, -1, -1, 1026, 1026, 5, 88, -1, 0, 0, 17, 7888, 7890), + (7890, -1, -1, 1026, 1026, 5, 89, -1, 0, 0, 17, 7889, 8430), + (7900, -1, -1, 7900, 7900, 4, 60, -1, 0, 0, 15, -1, 7901), + (7901, -1, -1, 7900, 7900, 4, 65, -1, 0, 0, 15, 7900, 7902), + (7902, -1, -1, 7900, 7900, 4, 70, -1, 0, 0, 15, 7901, 10268), + (7903, 7903, 7903, 7903, 7903, 6, 75, 16188, 60, 30, 15, -1, 12976), + (7904, -1, -1, 65, 661, 3, 85, -1, 0, 0, 17, 7538, 7905), + (7905, -1, -1, 65, 661, 3, 86, -1, 0, 0, 17, 7904, 7906), + (7906, -1, -1, 65, 661, 3, 87, -1, 0, 0, 17, 7905, 7907), + (7907, -1, -1, 65, 661, 3, 88, -1, 0, 0, 17, 7906, 7908), + (7908, -1, -1, 65, 661, 3, 89, -1, 0, 0, 17, 7907, 8435), + (7940, -1, -1, 7940, 7940, 6, 60, -1, 0, 0, 15, -1, 7941), + (7941, -1, -1, 7940, 7940, 6, 65, -1, 0, 0, 15, 7940, 7942), + (7942, -1, -1, 7940, 7940, 6, 70, -1, 0, 0, 15, 7941, 10030), + (7943, 7943, 7943, 7943, 7943, 6, 79, 16192, 60, 8640, 15, -1, 7993), + (7944, 7944, 7944, 7944, 7944, 7, 79, 16193, 34, 1800, 15, -1, -1), + (7945, -1, -1, 7945, 7945, 6, 81, -1, 0, 0, 15, -1, 7946), + (7946, -1, -1, 7945, 7945, 6, 82, -1, 0, 0, 15, 7945, 7947), + (7947, -1, -1, 7945, 7945, 6, 83, -1, 0, 0, 15, 7946, 10033), + (7948, -1, -1, 7948, 7948, 6, 75, -1, 0, 0, 15, -1, 7949), + (7949, -1, -1, 7948, 7948, 6, 80, -1, 0, 0, 15, 7948, 7950), + (7950, -1, -1, 7948, 7948, 6, 85, -1, 0, 0, 15, 7949, 10035), + (7951, 7951, 7951, 7951, 7951, 6, 82, 16200, 61, 900, 15, -1, 7952), + (7952, 7951, 7951, 7951, 7951, 6, 83, 16201, 61, 900, 15, 7951, 7953), + (7953, 7951, 7951, 7951, 7951, 6, 84, 16202, 61, 900, 15, 7952, 10038), + (7980, -1, -1, 7980, 7980, 6, 70, -1, 0, 0, 15, -1, 7981), + (7981, -1, -1, 7980, 7980, 6, 73, -1, 0, 0, 15, 7980, 7982), + (7982, -1, -1, 7980, 7980, 6, 76, -1, 0, 0, 15, 7981, -1), + (7983, -1, -1, 7983, 7983, 6, 70, -1, 0, 0, 15, -1, 7984), + (7984, -1, -1, 7983, 7983, 6, 73, -1, 0, 0, 15, 7983, 7985), + (7985, -1, -1, 7983, 7983, 6, 76, -1, 0, 0, 15, 7984, 10110), + (7986, 7986, 7986, 7986, 7986, 9, 75, 16203, 11, 600, 15, -1, 7987), + (7987, 7986, 7986, 7986, 7986, 12, 80, 16204, 11, 600, 15, 7986, 7988), + (7988, 7986, 7986, 7986, 7986, 12, 85, 16205, 11, 600, 15, 7987, 10510), + (7989, -1, -1, 7989, 7989, 6, 75, -1, 0, 0, 15, -1, 7990), + (7990, -1, -1, 7989, 7989, 6, 80, -1, 0, 0, 15, 7989, 7991), + (7991, -1, -1, 7989, 7989, 6, 85, -1, 0, 0, 15, 7990, 7992), + (7992, -1, -1, 7989, 7989, 6, 85, -1, 0, 0, 15, 7991, 13415), + (7993, 7943, 7943, 7943, 7943, 6, 85, 23601, 60, 8640, 17, 7943, -1), + (7994, -1, -1, 462, 462, 2, 81, -1, 0, 0, 17, 464, 7995), + (7995, -1, -1, 462, 462, 2, 85, -1, 0, 0, 17, 7994, -1), + (8000, -1, -1, 8001, 8001, 0, 50, -1, 0, 0, 8, -1, -1), + (8030, 8030, 8030, 8030, 8030, 6, 70, 16206, 60, 900, 15, -1, -1), + (8031, -1, -1, 8031, 8031, 6, 75, -1, 0, 0, 15, -1, 8032), + (8032, -1, -1, 8031, 8031, 6, 77, -1, 0, 0, 15, 8031, 8033), + (8033, -1, -1, 8031, 8031, 6, 79, -1, 0, 0, 15, 8032, 10282), + (8034, 8034, 8034, 8034, 8034, 6, 81, 16207, 59, 600, 15, -1, -1), + (8035, -1, -1, 8035, 8035, 6, 73, -1, 0, 0, 15, -1, 8036), + (8036, -1, -1, 8035, 8035, 6, 75, -1, 0, 0, 15, 8035, 8037), + (8037, -1, -1, 8035, 8035, 6, 77, -1, 0, 0, 15, 8036, 10285), + (8038, 8038, 8038, 8038, 8038, 6, 81, 16210, 56, 12, 15, -1, 17541), + (8039, 8039, 8039, 8039, 8039, 6, 83, 16211, 58, 7, 15, -1, 15462), + (8040, -1, -1, 8040, 8040, 4, 65, -1, 0, 0, 15, -1, 8041), + (8041, -1, -1, 8040, 8040, 4, 70, -1, 0, 0, 15, 8040, 8042), + (8042, -1, -1, 8040, 8040, 4, 75, -1, 0, 0, 15, 8041, 8043), + (8043, -1, -1, 8040, 8040, 4, 78, -1, 0, 0, 15, 8042, 8313), + (8059, -1, -1, 8232, 8232, 4, 78, -1, 0, 0, 15, 8234, 8261), + (8060, 8060, 8060, 8060, 8060, 7, 75, 16238, 41, 1800, 15, -1, 8061), + (8061, 8060, 8060, 8060, 8060, 7, 78, 16239, 41, 1800, 15, 8060, 8062), + (8062, 8060, 8060, 8060, 8060, 7, 81, 16240, 41, 1800, 15, 8061, 10237), + (8063, 8063, 8063, 8063, 8063, 7, 75, 16241, 41, 1800, 15, -1, 8064), + (8064, 8063, 8063, 8063, 8063, 7, 78, 16242, 41, 1800, 15, 8063, 8065), + (8065, 8063, 8063, 8063, 8063, 7, 81, 16243, 41, 1800, 15, 8064, 10240), + (8066, 8066, 8066, 8066, 8066, 7, 75, 16244, 41, 1800, 15, -1, 8067), + (8067, 8066, 8066, 8066, 8066, 7, 78, 16245, 41, 1800, 15, 8066, 8068), + (8068, 8066, 8066, 8066, 8066, 7, 81, 16246, 41, 1800, 15, 8067, 10243), + (8069, -1, -1, 8069, 8069, 5, 71, -1, 0, 0, 15, -1, 8070), + (8070, -1, -1, 8069, 8069, 5, 72, -1, 0, 0, 15, 8069, 8071), + (8071, -1, -1, 8069, 8069, 5, 73, -1, 0, 0, 15, 8070, 15606), + (8072, 8072, 8072, 8072, 8072, 7, 75, 16221, 37, 20, 15, -1, 8073), + (8073, 8072, 8072, 8072, 8072, 7, 75, 16222, 37, 20, 15, 8072, 8074), + (8074, 8072, 8072, 8072, 8072, 7, 75, 16223, 37, 20, 15, 8073, 10246), + (8075, 8075, 8075, 8075, 8075, 7, 81, 16224, 42, 6, 15, -1, -1), + (8076, -1, -1, 8076, 8076, 5, 77, -1, 0, 0, 15, -1, 8077), + (8077, -1, -1, 8076, 8076, 5, 78, -1, 0, 0, 15, 8076, 8078), + (8078, -1, -1, 8076, 8076, 5, 79, -1, 0, 0, 15, 8077, 8079), + (8079, -1, -1, 8076, 8076, 5, 80, -1, 0, 0, 15, 8078, 8080), + (8080, -1, -1, 8076, 8076, 5, 81, -1, 0, 0, 15, 8079, 8081), + (8081, -1, -1, 8076, 8076, 5, 82, -1, 0, 0, 15, 8080, -1), + (8082, -1, -1, 8082, 8082, 3, 65, -1, 0, 0, 15, -1, 8083), + (8083, -1, -1, 8082, 8082, 3, 67, -1, 0, 0, 15, 8082, 8084), + (8084, -1, -1, 8082, 8082, 3, 69, -1, 0, 0, 15, 8083, 10249), + (8190, -1, -1, 8190, 8190, 7, 75, -1, 0, 0, 15, -1, 8191), + (8191, -1, -1, 8190, 8190, 7, 75, -1, 0, 0, 15, 8190, 8192), + (8192, -1, -1, 8190, 8190, 7, 75, -1, 0, 0, 15, 8191, -1), + (8193, -1, -1, 8193, 8193, 7, 75, -1, 0, 0, 15, -1, -1), + (8194, 8194, 8194, 8194, 8194, 7, 75, 16226, 47, 12, 15, -1, -1), + (8195, -1, -1, 8195, 8195, 4, 75, -1, 0, 0, 15, -1, 8196), + (8196, -1, -1, 8195, 8195, 4, 75, -1, 0, 0, 15, 8195, 8197), + (8197, -1, -1, 8195, 8195, 4, 75, -1, 0, 0, 15, 8196, 7704), + (8198, -1, -1, 8198, 8198, 4, 65, -1, 0, 0, 15, -1, 8199), + (8199, -1, -1, 8198, 8198, 4, 65, -1, 0, 0, 15, 8198, 8200), + (8200, -1, -1, 8198, 8198, 4, 65, -1, 0, 0, 15, 8199, -1), + (8201, -1, -1, 8201, 8201, 7, 81, -1, 0, 0, 15, -1, 8202), + (8202, -1, -1, 8201, 8201, 7, 81, -1, 0, 0, 15, 8201, 8203), + (8203, -1, -1, 8201, 8201, 7, 81, -1, 0, 0, 15, 8202, 16475), + (8204, -1, -1, 8204, 8204, 4, 75, -1, 0, 0, 15, -1, 8205), + (8205, -1, -1, 8204, 8204, 4, 75, -1, 0, 0, 15, 8204, 8206), + (8206, -1, -1, 8204, 8204, 4, 75, -1, 0, 0, 15, 8205, 1656), + (8207, -1, -1, 8207, 8207, 4, 75, -1, 0, 0, 15, -1, 8208), + (8208, -1, -1, 8207, 8207, 4, 75, -1, 0, 0, 15, 8207, 8209), + (8209, -1, -1, 8207, 8207, 4, 75, -1, 0, 0, 15, 8208, 1659), + (8210, -1, -1, 8210, 8210, 5, 65, -1, 0, 0, 15, -1, 8211), + (8211, -1, -1, 8210, 8210, 5, 70, -1, 0, 0, 15, 8210, 8212), + (8212, -1, -1, 8210, 8210, 5, 75, -1, 0, 0, 15, 8211, 8213), + (8213, -1, -1, 8210, 8210, 5, 80, -1, 0, 0, 15, 8212, 8214), + (8214, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 15, 8213, 1651), + (8215, -1, -1, 8215, 8215, 5, 65, -1, 0, 0, 15, -1, 8216), + (8216, -1, -1, 8215, 8215, 5, 70, -1, 0, 0, 15, 8215, 8217), + (8217, -1, -1, 8215, 8215, 5, 75, -1, 0, 0, 15, 8216, 8218), + (8218, -1, -1, 8215, 8215, 5, 80, -1, 0, 0, 15, 8217, 8219), + (8219, -1, -1, 8215, 8215, 5, 85, -1, 0, 0, 15, 8218, 12559), + (8220, 8220, 8220, 8220, 8220, 5, 76, 16227, 39, 15, 15, -1, -1), + (8221, 8221, 8221, 8221, 8221, 9, 81, 16228, 45, 600, 15, -1, -1), + (8222, 8222, 8222, 8222, 8222, 7, 75, 16229, 70, 10, 15, -1, -1), + (8223, -1, -1, 86, 86, 8, 59, -1, 0, 0, 15, 6259, 8262), + (8224, -1, -1, 8224, 8224, 5, 75, -1, 0, 0, 15, -1, 8225), + (8225, -1, -1, 8224, 8224, 5, 80, -1, 0, 0, 15, 8224, 8226), + (8226, -1, -1, 8224, 8224, 5, 85, -1, 0, 0, 15, 8225, 8421), + (8227, 8227, 8227, 8227, 8227, 3, 55, 16233, 71, 10, 15, -1, 12810), + (8228, -1, -1, 8228, 8228, 5, 75, -1, 0, 0, 15, -1, 8229), + (8229, -1, -1, 8228, 8228, 5, 80, -1, 0, 0, 15, 8228, 8230), + (8230, -1, -1, 8228, 8228, 5, 85, -1, 0, 0, 15, 8229, -1), + (8231, 8231, -1, 8231, 8231, 3, 55, 16234, 38, 60, 15, -1, -1), + (8232, -1, -1, 8232, 8232, 4, 65, -1, 0, 0, 15, -1, 8233), + (8233, -1, -1, 8232, 8232, 4, 70, -1, 0, 0, 15, 8232, 8234), + (8234, -1, -1, 8232, 8232, 4, 75, -1, 0, 0, 15, 8233, 8059), + (8235, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, -1, 8236), + (8236, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, 8235, 8237), + (8237, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, 8236, 8238), + (8238, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, 8237, 8239), + (8239, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, 8238, 8304), + (8240, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, -1, 8241), + (8241, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, 8240, 8242), + (8242, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, 8241, 8243), + (8243, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, 8242, 8244), + (8244, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, 8243, 10781), + (8245, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, -1, 8246), + (8246, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, 8245, 8247), + (8247, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, 8246, 8248), + (8248, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, 8247, 8249), + (8249, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, 8248, 8422), + (8250, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, -1, 8251), + (8251, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, 8250, 8252), + (8252, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, 8251, 8253), + (8253, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, 8252, 8254), + (8254, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, 8253, 13046), + (8255, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, -1, 8256), + (8256, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, 8255, 8257), + (8257, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, 8256, 8258), + (8258, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, 8257, 8259), + (8259, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, 8258, 12411), + (8260, 8005, 8005, 8005, 8005, 9, 85, 20185, 45, 600, 16, -1, -1), + (8261, -1, -1, 8232, 8232, 4, 80, -1, 0, 0, 16, 8059, 15772), + (8262, -1, -1, 86, 86, 8, 65, -1, 0, 0, 16, 8223, -1), + (8263, -1, -1, 8263, 8263, 5, 81, -1, 0, 0, 16, -1, 8264), + (8264, -1, -1, 8263, 8263, 5, 82, -1, 0, 0, 16, 8263, 8265), + (8265, -1, -1, 8263, 8263, 5, 83, -1, 0, 0, 16, 8264, 8266), + (8266, -1, -1, 8263, 8263, 5, 84, -1, 0, 0, 16, 8265, 8267), + (8267, -1, -1, 8263, 8263, 5, 85, -1, 0, 0, 16, 8266, 8351), + (8268, -1, -1, 8268, 8268, 5, 81, -1, 0, 0, 16, -1, 8269), + (8269, -1, -1, 8268, 8268, 5, 82, -1, 0, 0, 16, 8268, 8270), + (8270, -1, -1, 8268, 8268, 5, 83, -1, 0, 0, 16, 8269, 8271), + (8271, -1, -1, 8268, 8268, 5, 84, -1, 0, 0, 16, 8270, 8272), + (8272, -1, -1, 8268, 8268, 5, 85, -1, 0, 0, 16, 8271, 8361), + (8273, -1, -1, 8273, 8273, 5, 81, -1, 0, 0, 16, -1, 8274), + (8274, -1, -1, 8273, 8273, 5, 82, -1, 0, 0, 16, 8273, 8275), + (8275, -1, -1, 8273, 8273, 5, 83, -1, 0, 0, 16, 8274, 8276), + (8276, -1, -1, 8273, 8273, 5, 84, -1, 0, 0, 16, 8275, 8277), + (8277, -1, -1, 8273, 8273, 5, 85, -1, 0, 0, 16, 8276, 8371), + (8278, -1, -1, 8278, 8278, 5, 81, -1, 0, 0, 16, -1, 8279), + (8279, -1, -1, 8278, 8278, 5, 82, -1, 0, 0, 16, 8278, 8280), + (8280, -1, -1, 8278, 8278, 5, 83, -1, 0, 0, 16, 8279, 8281), + (8281, -1, -1, 8278, 8278, 5, 84, -1, 0, 0, 16, 8280, 8282), + (8282, -1, -1, 8278, 8278, 5, 85, -1, 0, 0, 16, 8281, 8381), + (8283, -1, -1, 8283, 8283, 5, 81, -1, 0, 0, 16, -1, 8284), + (8284, -1, -1, 8283, 8283, 5, 82, -1, 0, 0, 16, 8283, 8285), + (8285, -1, -1, 8283, 8283, 5, 83, -1, 0, 0, 16, 8284, 8286), + (8286, -1, -1, 8283, 8283, 5, 84, -1, 0, 0, 16, 8285, 8287), + (8287, -1, -1, 8283, 8283, 5, 85, -1, 0, 0, 16, 8286, 8391), + (8288, -1, -1, 8288, 8288, 5, 81, -1, 0, 0, 16, -1, 8289), + (8289, -1, -1, 8288, 8288, 5, 82, -1, 0, 0, 16, 8288, 8290), + (8290, -1, -1, 8288, 8288, 5, 83, -1, 0, 0, 16, 8289, 8291), + (8291, -1, -1, 8288, 8288, 5, 84, -1, 0, 0, 16, 8290, 8292), + (8292, -1, -1, 8288, 8288, 5, 85, -1, 0, 0, 16, 8291, 8401), + (8293, -1, -1, 8293, 8293, 5, 81, -1, 0, 0, 16, -1, 8294), + (8294, -1, -1, 8293, 8293, 5, 82, -1, 0, 0, 16, 8293, 8295), + (8295, -1, -1, 8293, 8293, 5, 83, -1, 0, 0, 16, 8294, 8296), + (8296, -1, -1, 8293, 8293, 5, 84, -1, 0, 0, 16, 8295, 8297), + (8297, -1, -1, 8293, 8293, 5, 85, -1, 0, 0, 16, 8296, 8411), + (8300, 8300, 8300, 8300, 8300, 5, 81, 21778, 8, 900, 16, -1, 8301), + (8301, 8300, 8300, 8300, 8300, 7, 83, 21779, 8, 900, 16, 8300, 8302), + (8302, 8300, 8300, 8300, 8300, 9, 85, 21780, 8, 900, 16, 8301, 15111), + (8303, 8303, 8303, 8303, 8303, 12, 85, 21773, 9, 1800, 16, -1, -1), + (8304, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8239, 8305), + (8305, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8304, 8306), + (8306, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8305, 8307), + (8307, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8306, 8308), + (8308, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8307, 13353), + (8309, 260, -1, 260, 260, 5, 81, 21687, 3, 2160, 16, 262, 8310), + (8310, 260, -1, 260, 260, 7, 83, 21688, 3, 2160, 16, 8309, 8311), + (8311, 260, -1, 260, 260, 9, 85, 21689, 3, 2160, 16, 8310, -1), + (8312, 8312, 8312, 8312, 8312, 12, 85, 21690, 2, 900, 16, -1, -1), + (8313, -1, -1, 8040, 8040, 4, 80, -1, 0, 0, 16, 8043, 15773), + (8314, -1, -1, 8314, 8314, 7, 85, -1, 0, 0, 16, -1, 8315), + (8315, -1, -1, 8314, 8314, 9, 85, -1, 0, 0, 16, 8314, 8316), + (8316, -1, -1, 8314, 8314, 12, 85, -1, 0, 0, 16, 8315, 13508), + (8317, -1, -1, 8317, 8317, 5, 85, -1, 0, 0, 16, -1, 8318), + (8318, -1, -1, 8317, 8317, 5, 85, -1, 0, 0, 16, 8317, -1), + (8319, -1, -1, 8319, 8319, 5, 85, -1, 0, 0, 16, -1, 8320), + (8320, -1, -1, 8319, 8319, 5, 85, -1, 0, 0, 16, 8319, 8321), + (8321, -1, -1, 8319, 8319, 5, 85, -1, 0, 0, 16, 8320, -1), + (8322, -1, -1, 8322, 8322, 5, 81, 0, 0, 0, 16, -1, 8323), + (8323, -1, -1, 8322, 8322, 7, 83, 0, 0, 0, 16, 8322, 8324), + (8324, -1, -1, 8322, 8322, 9, 85, 0, 0, 0, 16, 8323, 13199), + (8325, -1, -1, 8325, 8325, 7, 81, 0, 0, 0, 16, -1, 8326), + (8326, -1, -1, 8325, 8325, 9, 81, 0, 0, 0, 16, 8325, 8327), + (8327, -1, -1, 8325, 8325, 11, 81, 0, 0, 0, 16, 8326, 13219), + (8328, -1, -1, 244, 244, 12, 59, -1, 0, 0, 3, 246, -1), + (8329, -1, -1, 622, 622, 3, 71, -1, 0, 0, 16, 624, -1), + (8331, -1, -1, 8331, 8331, 9, 85, 0, 0, 0, 16, -1, -1), + (8332, -1, -1, 8332, 8332, 7, 85, 0, 0, 0, 16, -1, 8333), + (8333, -1, -1, 8332, 8332, 7, 85, 0, 0, 0, 16, 8332, 8334), + (8334, -1, -1, 8332, 8332, 7, 85, 0, 0, 0, 16, 8333, -1), + (8335, -1, -1, 8335, 8335, 5, 81, 0, 0, 0, 16, -1, 8336), + (8336, -1, -1, 8335, 8335, 5, 82, 0, 0, 0, 16, 8335, 8337), + (8337, -1, -1, 8335, 8335, 5, 83, 0, 0, 0, 16, 8336, 8338), + (8338, -1, -1, 8335, 8335, 5, 84, 0, 0, 0, 16, 8337, 8339), + (8339, -1, -1, 8335, 8335, 5, 85, 0, 0, 0, 16, 8338, -1), + (8341, 8341, 8341, 8341, 8341, 12, 85, 21829, 53, 450, 16, -1, -1), + (8342, 8342, 8342, 8342, 8342, 12, 85, 21843, 54, 240, 16, -1, 14729), + (8343, 167, 167, 167, 167, 10, 85, 21837, 14, 900, 16, 7249, 12955), + (8344, -1, -1, 1210, 1213, 12, 85, -1, 0, 0, 16, 7583, 8345), + (8345, -1, -1, 1210, 1213, 12, 85, -1, 0, 0, 16, 8344, 8346), + (8346, -1, -1, 1210, 1213, 12, 85, -1, 0, 0, 16, 8345, 12526), + (8347, -1, -1, 8347, 8347, 7, 81, 0, 0, 0, 16, -1, 8348), + (8348, -1, -1, 8347, 8347, 9, 83, 0, 0, 0, 16, 8347, 8349), + (8349, -1, -1, 8347, 8347, 11, 85, 0, 0, 0, 16, 8348, -1), + (8350, -1, -1, 8350, 8350, 12, 85, 0, 0, 0, 16, -1, -1), + (8351, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8267, 8352), + (8352, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8351, 8353), + (8353, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8352, 8354), + (8354, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8353, 8355), + (8355, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8354, 8356), + (8356, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8355, 8357), + (8357, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8356, 8358), + (8358, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8357, 8359), + (8359, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8358, 8360), + (8360, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8359, 13933), + (8361, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8272, 8362), + (8362, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8361, 8363), + (8363, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8362, 8364), + (8364, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8363, 8365), + (8365, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8364, 8366), + (8366, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8365, 8367), + (8367, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8366, 8368), + (8368, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8367, 8369), + (8369, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8368, 8370), + (8370, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8369, 13943), + (8371, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8277, 8372), + (8372, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8371, 8373), + (8373, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8372, 8374), + (8374, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8373, 8375), + (8375, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8374, 8376), + (8376, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8375, 8377), + (8377, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8376, 8378), + (8378, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8377, 8379), + (8379, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8378, 8380), + (8380, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8379, 13953), + (8381, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8282, 8382), + (8382, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8381, 8383), + (8383, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8382, 8384), + (8384, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8383, 8385), + (8385, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8384, 8386), + (8386, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8385, 8387), + (8387, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8386, 8388), + (8388, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8387, 8389), + (8389, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8388, 8390), + (8390, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8389, 13963), + (8391, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8287, 8392), + (8392, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8391, 8393), + (8393, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8392, 8394), + (8394, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8393, 8395), + (8395, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8394, 8396), + (8396, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8395, 8397), + (8397, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8396, 8398), + (8398, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8397, 8399), + (8399, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8398, 8400), + (8400, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8399, 13973), + (8401, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8292, 8402), + (8402, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8401, 8403), + (8403, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8402, 8404), + (8404, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8403, 8405), + (8405, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8404, 8406), + (8406, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8405, 8407), + (8407, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8406, 8408), + (8408, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8407, 8409), + (8409, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8408, 8410), + (8410, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8409, 13983), + (8411, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8297, 8412), + (8412, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8411, 8413), + (8413, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8412, 8414), + (8414, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8413, 8415), + (8415, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8414, 8416), + (8416, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8415, 8417), + (8417, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8416, 8418), + (8418, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8417, 8419), + (8419, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8418, 8420), + (8420, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8419, 13993), + (8421, -1, -1, 8224, 8224, 5, 90, -1, 0, 0, 17, 8226, -1), + (8422, -1, -1, 8245, 8245, 6, 86, -1, 0, 0, 17, 8249, 8423), + (8423, -1, -1, 8245, 8245, 6, 87, -1, 0, 0, 17, 8422, 8424), + (8424, -1, -1, 8245, 8245, 6, 88, -1, 0, 0, 17, 8423, 8425), + (8425, -1, -1, 8245, 8245, 6, 89, -1, 0, 0, 17, 8424, 8426), + (8426, -1, -1, 8245, 8245, 6, 90, -1, 0, 0, 17, 8425, 13338), + (8427, -1, -1, 7100, 7100, 6, 85, -1, 0, 0, 17, 7325, 8428), + (8428, -1, -1, 7100, 7100, 6, 87, -1, 0, 0, 17, 8427, 8429), + (8429, -1, -1, 7100, 7100, 6, 89, -1, 0, 0, 17, 8428, -1), + (8430, -1, -1, 1026, 1026, 10, 91, -1, 0, 0, 18, 7890, 8431), + (8435, -1, -1, 65, 661, 8, 91, -1, 0, 0, 18, 7908, 8436), + (8440, -1, -1, 122, 122, 13, 91, -1, 0, 0, 18, 13089, 8441), + (8445, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 12637, 8446), + (8446, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 8445, 8447), + (8447, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 8446, 16419), + (8448, -1, -1, 6119, 6119, 8, 91, -1, 0, 0, 18, 12496, 8449), + (8463, -1, -1, 125, 125, 10, 91, -1, 0, 0, 18, 13084, 8464), + (8464, -1, -1, 125, 125, 11, 91, -1, 0, 0, 18, 8463, 8465), + (8470, -1, -1, 1006, 1006, 10, 91, -1, 0, 0, 18, 7841, 8471), + (9000, 9000, 9000, 9000, 9000, 0, 1, 16995, 49, 72000, 0, -1, -1), + (9001, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, -1, 9002), + (9002, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9001, 9003), + (9003, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9002, 9004), + (9004, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9003, 9005), + (9005, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9004, 9006), + (9006, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9005, 9007), + (9007, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9006, 9008), + (9008, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9007, 9009), + (9009, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9008, 9010), + (9010, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9009, -1), + (9011, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, -1, 9012), + (9012, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9011, 9013), + (9013, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9012, 9014), + (9014, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9013, 9015), + (9015, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9014, 9016), + (9016, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9015, 9017), + (9017, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9016, 9018), + (9018, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9017, 9019), + (9019, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9018, 9020), + (9020, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9019, -1), + (9021, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, -1, 9022), + (9022, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9021, 9023), + (9023, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9022, 9024), + (9024, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9023, 9025), + (9025, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9024, 9026), + (9026, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9025, 9027), + (9027, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9026, 9028), + (9028, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9027, 9029), + (9029, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9028, 9030), + (9030, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9029, -1), + (9031, 9031, 9031, 9031, 9031, 0, 1, 16601, 65, 72000, 0, -1, -1), + (9032, 9032, 9032, 9032, 9032, 0, 0, 21815, 51, 72000, 0, -1, -1), + (9033, -1, -1, 9033, 9033, 0, 1, -1, 0, 0, 0, -1, -1), + (9100, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, -1, 9101), + (9101, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9100, 9102), + (9102, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9101, 9103), + (9103, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9102, 9104), + (9104, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9103, 9105), + (9105, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9104, 9106), + (9106, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9105, 9107), + (9107, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9106, 9108), + (9108, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9107, -1), + (9109, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, -1, 9110), + (9110, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9109, 9111), + (9111, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9110, 9112), + (9112, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9111, 9113), + (9113, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9112, 9114), + (9114, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9113, 9115), + (9115, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9114, 9116), + (9116, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9115, 9117), + (9117, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9116, -1), + (9118, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, -1, 9119), + (9119, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9118, 9120), + (9120, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9119, 9121), + (9121, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9120, 9122), + (9122, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9121, 9123), + (9123, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9122, 9124), + (9124, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9123, 9125), + (9125, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9124, 9126), + (9126, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9125, -1), + (9127, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, -1, 9128), + (9128, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9127, 9129), + (9129, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9128, 9130), + (9130, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9129, 9131), + (9131, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9130, 9132), + (9132, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9131, 9133), + (9133, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9132, 9134), + (9134, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9133, 9135), + (9135, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9134, -1), + (9136, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, -1, 9137), + (9137, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9136, 9138), + (9138, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9137, 9139), + (9139, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9138, 9140), + (9140, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9139, 9141), + (9141, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9140, 9142), + (9142, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9141, 9143), + (9143, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9142, 9144), + (9144, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9143, -1), + (9145, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, -1, 9146), + (9146, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9145, 9147), + (9147, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9146, 9148), + (9148, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9147, 9149), + (9149, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9148, 9150), + (9150, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9149, 9151), + (9151, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9150, 9152), + (9152, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9151, 9153), + (9153, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9152, -1), + (9154, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, -1, 9155), + (9155, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9154, 9156), + (9156, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9155, 9157), + (9157, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9156, 9158), + (9158, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9157, 9159), + (9159, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9158, 9160), + (9160, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9159, 9161), + (9161, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9160, 9162), + (9162, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9161, -1), + (9163, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, -1, 9164), + (9164, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9163, 9165), + (9165, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9164, 9166), + (9166, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9165, 9167), + (9167, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9166, 9168), + (9168, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9167, 9169), + (9169, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9168, 9170), + (9170, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9169, 9171), + (9171, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9170, -1), + (9172, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, -1, 9173), + (9173, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9172, 9174), + (9174, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9173, 9175), + (9175, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9174, 9176), + (9176, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9175, 9177), + (9177, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9176, 9178), + (9178, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9177, 9179), + (9179, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9178, 9180), + (9180, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9179, -1), + (9181, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, -1, 9182), + (9182, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9181, 9183), + (9183, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9182, 9184), + (9184, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9183, 9185), + (9185, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9184, 9186), + (9186, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9185, 9187), + (9187, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9186, 9188), + (9188, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9187, 9189), + (9189, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9188, -1), + (9190, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, -1, 9191), + (9191, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9190, 9192), + (9192, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9191, 9193), + (9193, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9192, 9194), + (9194, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9193, 9195), + (9195, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9194, 9196), + (9196, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9195, 9197), + (9197, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9196, 9198), + (9198, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9197, -1), + (9199, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, -1, 9200), + (9200, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9199, 9201), + (9201, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9200, 9202), + (9202, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9201, 9203), + (9203, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9202, 9204), + (9204, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9203, 9205), + (9205, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9204, 9206), + (9206, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9205, 9207), + (9207, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9206, -1), + (9208, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, -1, 9209), + (9209, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9208, 9210), + (9210, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9209, 9211), + (9211, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9210, 9212), + (9212, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9211, 9213), + (9213, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9212, 9214), + (9214, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9213, 9215), + (9215, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9214, 9216), + (9216, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9215, -1), + (9217, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, -1, 9218), + (9218, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9217, 9219), + (9219, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9218, 9220), + (9220, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9219, 9221), + (9221, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9220, 9222), + (9222, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9221, 9223), + (9223, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9222, 9224), + (9224, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9223, 9225), + (9225, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9224, -1), + (9226, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, -1, 9227), + (9227, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9226, 9228), + (9228, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9227, 9229), + (9229, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9228, 9230), + (9230, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9229, 9231), + (9231, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9230, 9232), + (9232, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9231, 9233), + (9233, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9232, 9234), + (9234, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9233, -1), + (9235, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, -1, 9236), + (9236, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9235, 9237), + (9237, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9236, 9238), + (9238, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9237, 9239), + (9239, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9238, 9240), + (9240, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9239, 9241), + (9241, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9240, 9242), + (9242, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9241, 9243), + (9243, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9242, -1), + (9300, 9300, 9300, 9300, 9300, 5, 85, 16212, 40, 600, 15, -1, 9301), + (9301, 9300, 9300, 9300, 9300, 5, 85, 16213, 40, 600, 15, 9300, 9302), + (9302, 9300, 9300, 9300, 9300, 5, 85, 16214, 40, 600, 15, 9301, -1), + (9303, 9303, 9303, 9303, 9303, 5, 85, 16215, 40, 600, 15, -1, 9304), + (9304, 9303, 9303, 9303, 9303, 5, 85, 16216, 40, 600, 15, 9303, 9305), + (9305, 9303, 9303, 9303, 9303, 5, 85, 16217, 40, 600, 15, 9304, -1), + (9306, 9306, 9306, 9306, 9306, 5, 85, 16218, 40, 600, 15, -1, 9307), + (9307, 9306, 9306, 9306, 9306, 5, 85, 16219, 40, 600, 15, 9306, 9308), + (9308, 9306, 9306, 9306, 9306, 5, 85, 16220, 40, 600, 15, 9307, -1), + (9309, 9309, 9309, 9309, 9309, 5, 85, 16249, 40, 600, 15, -1, 9310), + (9310, 9309, 9309, 9309, 9309, 5, 85, 16250, 40, 600, 15, 9309, 9311), + (9311, 9309, 9309, 9309, 9309, 5, 85, 16251, 40, 600, 15, 9310, -1), + (9312, 9312, 9312, 9312, 9312, 5, 85, 16252, 40, 600, 15, -1, 9313), + (9313, 9312, 9312, 9312, 9312, 5, 85, 16253, 40, 600, 15, 9312, 9314), + (9314, 9312, 9312, 9312, 9312, 5, 85, 16254, 40, 600, 15, 9313, -1), + (9315, 9315, 9315, 9315, 9315, 5, 85, 16255, 40, 600, 15, -1, 9316), + (9316, 9315, 9315, 9315, 9315, 5, 85, 16256, 40, 600, 15, 9315, 9317), + (9317, 9315, 9315, 9315, 9315, 5, 85, 16257, 40, 600, 15, 9316, -1), + (9318, 9318, 9318, 9318, 9318, 5, 85, 16261, 40, 600, 15, -1, 9319), + (9319, 9318, 9318, 9318, 9318, 5, 85, 16262, 40, 600, 15, 9318, 9320), + (9320, 9318, 9318, 9318, 9318, 5, 85, 16263, 40, 600, 15, 9319, -1), + (9321, 9321, 9321, 9321, 9321, 5, 85, 16264, 40, 600, 15, -1, 9322), + (9322, 9321, 9321, 9321, 9321, 5, 85, 16265, 40, 600, 15, 9321, 9323), + (9323, 9321, 9321, 9321, 9321, 5, 85, 16266, 40, 600, 15, 9322, -1), + (9324, 9324, 9324, 9324, 9324, 5, 85, 16267, 40, 600, 15, -1, 9325), + (9325, 9324, 9324, 9324, 9324, 5, 85, 16268, 40, 600, 15, 9324, 9326), + (9326, 9324, 9324, 9324, 9324, 5, 85, 16269, 40, 600, 15, 9325, -1), + (9327, 9327, 9327, 9327, 9327, 5, 85, 16270, 40, 600, 15, -1, 9328), + (9328, 9327, 9327, 9327, 9327, 5, 85, 16271, 40, 600, 15, 9327, 9329), + (9329, 9327, 9327, 9327, 9327, 5, 85, 16272, 40, 600, 15, 9328, -1), + (9330, 9330, 9330, 9330, 9330, 5, 85, 16273, 40, 600, 15, -1, 9331), + (9331, 9330, 9330, 9330, 9330, 5, 85, 16274, 40, 600, 15, 9330, 9332), + (9332, 9330, 9330, 9330, 9330, 5, 85, 16275, 40, 600, 15, 9331, -1), + (9333, 9333, 9333, 9333, 9333, 5, 85, 16276, 40, 600, 15, -1, 9334), + (9334, 9333, 9333, 9333, 9333, 5, 85, 16277, 40, 600, 15, 9333, 9335), + (9335, 9333, 9333, 9333, 9333, 5, 85, 16278, 40, 600, 15, 9334, -1), + (9336, 9336, 9336, 9336, 9336, 5, 85, 16284, 40, 600, 15, -1, 9337), + (9337, 9336, 9336, 9336, 9336, 5, 85, 16285, 40, 600, 15, 9336, 9338), + (9338, 9336, 9336, 9336, 9336, 5, 85, 16286, 40, 600, 15, 9337, -1), + (9339, 9339, 9339, 9339, 9339, 5, 85, 16287, 40, 600, 15, -1, 9340), + (9340, 9339, 9339, 9339, 9339, 5, 85, 16288, 40, 600, 15, 9339, 9341), + (9341, 9339, 9339, 9339, 9339, 5, 85, 16289, 40, 600, 15, 9340, -1), + (9342, 9342, 9342, 9342, 9342, 5, 85, 16290, 40, 600, 15, -1, 9343), + (9343, 9342, 9342, 9342, 9342, 5, 85, 16291, 40, 600, 15, 9342, 9344), + (9344, 9342, 9342, 9342, 9342, 5, 85, 16292, 40, 600, 15, 9343, -1), + (9345, 9345, 9345, 9345, 9345, 5, 85, 16293, 40, 600, 15, -1, 9346), + (9346, 9345, 9345, 9345, 9345, 5, 85, 16294, 40, 600, 15, 9345, 9347), + (9347, 9345, 9345, 9345, 9345, 5, 85, 16295, 40, 600, 15, 9346, -1), + (9348, 9348, 9348, 9348, 9348, 5, 85, 16296, 40, 600, 15, -1, 9349), + (9349, 9348, 9348, 9348, 9348, 5, 85, 16297, 40, 600, 15, 9348, 9350), + (9350, 9348, 9348, 9348, 9348, 5, 85, 16298, 40, 600, 15, 9349, -1), + (9351, 9351, 9351, 9351, 9351, 5, 85, 16299, 40, 600, 15, -1, 9352), + (9352, 9351, 9351, 9351, 9351, 5, 85, 16300, 40, 600, 15, 9351, 9353), + (9353, 9351, 9351, 9351, 9351, 5, 85, 16301, 40, 600, 15, 9352, -1), + (9354, 9354, 9354, 9354, 9354, 5, 85, 16305, 40, 600, 15, -1, 9355), + (9355, 9354, 9354, 9354, 9354, 5, 85, 16306, 40, 600, 15, 9354, 9356), + (9356, 9354, 9354, 9354, 9354, 5, 85, 16307, 40, 600, 15, 9355, 12626), + (9357, 9357, 9357, 9357, 9357, 5, 85, 16308, 40, 600, 15, -1, 9358), + (9358, 9357, 9357, 9357, 9357, 5, 85, 16309, 40, 600, 15, 9357, 9359), + (9359, 9357, 9357, 9357, 9357, 5, 85, 16310, 40, 600, 15, 9358, 12629), + (9360, 9360, 9360, 9360, 9360, 5, 85, 16311, 40, 600, 15, -1, 9361), + (9361, 9360, 9360, 9360, 9360, 5, 85, 16312, 40, 600, 15, 9360, 9362), + (9362, 9360, 9360, 9360, 9360, 5, 85, 16313, 40, 600, 15, 9361, 12632), + (9363, 9363, 9363, 9363, 9363, 5, 85, 16317, 40, 600, 15, -1, 9364), + (9364, 9363, 9363, 9363, 9363, 5, 85, 16318, 40, 600, 15, 9363, 9365), + (9365, 9363, 9363, 9363, 9363, 5, 85, 16319, 40, 600, 15, 9364, -1), + (9366, 9366, 9366, 9366, 9366, 5, 85, 16320, 40, 600, 15, -1, 9367), + (9367, 9366, 9366, 9366, 9366, 5, 85, 16321, 40, 600, 15, 9366, 9368), + (9368, 9366, 9366, 9366, 9366, 5, 85, 16322, 40, 600, 15, 9367, -1), + (9369, 9369, 9369, 9369, 9369, 5, 85, 16323, 40, 600, 15, -1, 9370), + (9370, 9369, 9369, 9369, 9369, 5, 85, 16324, 40, 600, 15, 9369, 9371), + (9371, 9369, 9369, 9369, 9369, 5, 85, 16325, 40, 600, 15, 9370, -1), + (9372, 9372, 9372, 9372, 9372, 5, 85, 16326, 40, 600, 15, -1, 9373), + (9373, 9372, 9372, 9372, 9372, 5, 85, 16327, 40, 600, 15, 9372, 9374), + (9374, 9372, 9372, 9372, 9372, 5, 85, 16328, 40, 600, 15, 9373, -1), + (9375, 9375, 9375, 9375, 9375, 5, 85, 16329, 40, 600, 15, -1, 9376), + (9376, 9375, 9375, 9375, 9375, 5, 85, 16330, 40, 600, 15, 9375, 9377), + (9377, 9375, 9375, 9375, 9375, 5, 85, 16331, 40, 600, 15, 9376, -1), + (9378, 9378, 9378, 9378, 9378, 5, 85, 16332, 40, 600, 15, -1, 9379), + (9379, 9378, 9378, 9378, 9378, 5, 85, 16333, 40, 600, 15, 9378, 9380), + (9380, 9378, 9378, 9378, 9378, 5, 85, 16334, 40, 600, 15, 9379, -1), + (9381, 9381, 9381, 9381, 9381, 5, 85, 16335, 40, 600, 15, -1, 9382), + (9382, 9381, 9381, 9381, 9381, 5, 85, 16336, 40, 600, 15, 9381, 9383), + (9383, 9381, 9381, 9381, 9381, 5, 85, 16337, 40, 600, 15, 9382, -1), + (9384, 9384, 9384, 9384, 9384, 5, 85, 16338, 40, 600, 15, -1, 9385), + (9385, 9384, 9384, 9384, 9384, 5, 85, 16339, 40, 600, 15, 9384, 9386), + (9386, 9384, 9384, 9384, 9384, 5, 85, 16340, 40, 600, 15, 9385, -1), + (9387, 9387, 9387, 9387, 9387, 5, 85, 16341, 40, 600, 15, -1, 9388), + (9388, 9387, 9387, 9387, 9387, 5, 85, 16342, 40, 600, 15, 9387, 9389), + (9389, 9387, 9387, 9387, 9387, 5, 85, 16343, 40, 600, 15, 9388, -1), + (9390, 9390, 9390, 9390, 9390, 5, 85, 16344, 40, 600, 15, -1, 9391), + (9391, 9390, 9390, 9390, 9390, 5, 85, 16345, 40, 600, 15, 9390, 9392), + (9392, 9390, 9390, 9390, 9390, 5, 85, 16346, 40, 600, 15, 9391, -1), + (9393, 9393, 9393, 9393, 9393, 5, 85, 16347, 40, 600, 15, -1, 9394), + (9394, 9393, 9393, 9393, 9393, 5, 85, 16348, 40, 600, 15, 9393, 9395), + (9395, 9393, 9393, 9393, 9393, 5, 85, 16349, 40, 600, 15, 9394, -1), + (9396, 9396, 9396, 9396, 9396, 5, 85, 16350, 40, 600, 15, -1, 9397), + (9397, 9396, 9396, 9396, 9396, 5, 85, 16351, 40, 600, 15, 9396, 9398), + (9398, 9396, 9396, 9396, 9396, 5, 85, 16352, 40, 600, 15, 9397, -1), + (9399, 9399, 9399, 9399, 9399, 5, 85, 16359, 40, 600, 15, -1, 9400), + (9400, 9399, 9399, 9399, 9399, 5, 85, 16360, 40, 600, 15, 9399, 9401), + (9401, 9399, 9399, 9399, 9399, 5, 85, 16361, 40, 600, 15, 9400, -1), + (9402, 9402, 9402, 9402, 9402, 5, 85, 16362, 40, 600, 15, -1, 9403), + (9403, 9402, 9402, 9402, 9402, 5, 85, 16363, 40, 600, 15, 9402, 9404), + (9404, 9402, 9402, 9402, 9402, 5, 85, 16364, 40, 600, 15, 9403, -1), + (9405, 9405, 9405, 9405, 9405, 5, 85, 16365, 40, 600, 15, -1, 9406), + (9406, 9405, 9405, 9405, 9405, 5, 85, 16366, 40, 600, 15, 9405, 9407), + (9407, 9405, 9405, 9405, 9405, 5, 85, 16367, 40, 600, 15, 9406, -1), + (9408, 9408, 9408, 9408, 9408, 5, 85, 16368, 40, 600, 15, -1, 9409), + (9409, 9408, 9408, 9408, 9408, 5, 85, 16369, 40, 600, 15, 9408, 9410), + (9410, 9408, 9408, 9408, 9408, 5, 85, 16370, 40, 600, 15, 9409, -1), + (9411, 9411, 9411, 9411, 9411, 5, 85, 16371, 40, 600, 15, -1, 9412), + (9412, 9411, 9411, 9411, 9411, 5, 85, 16372, 40, 600, 15, 9411, 9413), + (9413, 9411, 9411, 9411, 9411, 5, 85, 16373, 40, 600, 15, 9412, -1), + (9414, 9414, 9414, 9414, 9414, 5, 85, 16374, 40, 600, 15, -1, 9415), + (9415, 9414, 9414, 9414, 9414, 5, 85, 16375, 40, 600, 15, 9414, 9416), + (9416, 9414, 9414, 9414, 9414, 5, 85, 16376, 40, 600, 15, 9415, -1), + (9417, 9417, 9417, 9417, 9417, 5, 85, 16377, 40, 600, 15, -1, 9418), + (9418, 9417, 9417, 9417, 9417, 5, 85, 16378, 40, 600, 15, 9417, 9419), + (9419, 9417, 9417, 9417, 9417, 5, 85, 16379, 40, 600, 15, 9418, -1), + (9420, 9420, 9420, 9420, 9420, 5, 85, 16380, 40, 600, 15, -1, 9421), + (9421, 9420, 9420, 9420, 9420, 5, 85, 16381, 40, 600, 15, 9420, 9422), + (9422, 9420, 9420, 9420, 9420, 5, 85, 16382, 40, 600, 15, 9421, -1), + (9423, 9423, 9423, 9423, 9423, 5, 85, 16386, 40, 600, 15, -1, 9424), + (9424, 9423, 9423, 9423, 9423, 5, 85, 16387, 40, 600, 15, 9423, 9425), + (9425, 9423, 9423, 9423, 9423, 5, 85, 16388, 40, 600, 15, 9424, -1), + (9426, 9426, 9426, 9426, 9426, 5, 85, 16389, 40, 600, 15, -1, 9427), + (9427, 9426, 9426, 9426, 9426, 5, 85, 16390, 40, 600, 15, 9426, 9428), + (9428, 9426, 9426, 9426, 9426, 5, 85, 16391, 40, 600, 15, 9427, -1), + (9429, 9429, 9429, 9429, 9429, 5, 85, 16392, 40, 600, 15, -1, 9430), + (9430, 9429, 9429, 9429, 9429, 5, 85, 16393, 40, 600, 15, 9429, 9431), + (9431, 9429, 9429, 9429, 9429, 5, 85, 16394, 40, 600, 15, 9430, -1), + (9432, 9432, 9432, 9432, 9432, 5, 85, 16395, 40, 600, 15, -1, 9433), + (9433, 9432, 9432, 9432, 9432, 5, 85, 16396, 40, 600, 15, 9432, 9434), + (9434, 9432, 9432, 9432, 9432, 5, 85, 16397, 40, 600, 15, 9433, -1), + (9435, 9435, 9435, 9435, 9435, 5, 85, 16398, 40, 600, 15, -1, 9436), + (9436, 9435, 9435, 9435, 9435, 5, 85, 16399, 40, 600, 15, 9435, 9437), + (9437, 9435, 9435, 9435, 9435, 5, 85, 16400, 40, 600, 15, 9436, -1), + (9438, 9438, 9438, 9438, 9438, 5, 85, 16401, 40, 600, 15, -1, 9439), + (9439, 9438, 9438, 9438, 9438, 5, 85, 16402, 40, 600, 15, 9438, 9440), + (9440, 9438, 9438, 9438, 9438, 5, 85, 16403, 40, 600, 15, 9439, -1), + (9441, 9441, 9441, 9441, 9441, 5, 85, 16404, 40, 600, 15, -1, 9442), + (9442, 9441, 9441, 9441, 9441, 5, 85, 16405, 40, 600, 15, 9441, 9443), + (9443, 9441, 9441, 9441, 9441, 5, 85, 16406, 40, 600, 15, 9442, -1), + (9500, 9500, 9500, 9500, 9500, 3, 76, 16247, 47, 60, 15, -1, -1), + (9501, 9501, 9501, 9501, 9501, 9, 85, 16247, 47, 600, 15, -1, -1), + (9502, 9502, 9502, 9502, 9502, 7, 81, 16248, 48, 3600, 15, -1, -1), + (9503, -1, -1, 9503, 9503, 7, 83, -1, 0, 0, 15, -1, 9504), + (9504, -1, -1, 9503, 9503, 7, 84, -1, 0, 0, 15, 9503, 9505), + (9505, -1, -1, 9503, 9503, 7, 85, -1, 0, 0, 15, 9504, 10087), + (9506, -1, -1, 9506, 9506, 7, 81, -1, 0, 0, 15, -1, 9507), + (9507, -1, -1, 9506, 9506, 7, 83, -1, 0, 0, 15, 9506, 9508), + (9508, -1, -1, 9506, 9506, 7, 85, -1, 0, 0, 15, 9507, 13630), + (9509, -1, -1, 9509, 9509, 7, 81, -1, 0, 0, 15, -1, 9510), + (9510, -1, -1, 9509, 9509, 7, 82, -1, 0, 0, 15, 9509, 9511), + (9511, -1, -1, 9509, 9509, 7, 83, -1, 0, 0, 15, 9510, 9515), + (9512, -1, -1, 9512, 9512, 7, 81, -1, 0, 0, 15, -1, 9513), + (9513, -1, -1, 9512, 9512, 7, 82, -1, 0, 0, 15, 9512, 9514), + (9514, -1, -1, 9512, 9512, 7, 83, -1, 0, 0, 15, 9513, 7819), + (9515, -1, -1, 9509, 9509, 7, 86, -1, 0, 0, 17, 9511, 16361), + (10003, 6610, 6610, 6610, 6610, 5, 60, 16494, 41, 30, 16, 6610, 10573), + (10004, -1, -1, 6614, 6614, 6, 70, -1, 0, 0, 16, 6616, 10005), + (10005, -1, -1, 6614, 6614, 9, 70, -1, 0, 0, 16, 10004, 10575), + (10006, 54006, 54006, 54006, 54006, 7, 85, 16495, 18, 180, 16, 7111, 13425), + (10007, -1, -1, 6564, 6564, 10, 85, -1, 0, 0, 16, 7114, 10008), + (10008, -1, -1, 6564, 6564, 10, 85, -1, 0, 0, 16, 10007, 10009), + (10009, -1, -1, 6564, 6564, 10, 85, -1, 0, 0, 16, 10008, 10568), + (10010, 6565, 6565, 6565, 6565, 7, 85, 16496, 17, 45, 16, 7115, 10517), + (10011, 912, 912, 912, 912, 9, 80, 16497, 4, 3600, 16, 7121, 10012), + (10012, 912, 912, 912, 912, 9, 80, 16498, 4, 3600, 16, 10011, 10013), + (10013, 912, 912, 912, 912, 9, 80, 16499, 4, 3600, 16, 10012, 10585), + (10014, 1383, 1383, 1383, 1383, 12, 85, 21766, 6, 300, 16, 7299, 6487), + (10015, 1195, 1195, 1195, 1195, 9, 85, 16504, 13, 2160, 16, 7300, 13259), + (10016, 131, 131, 131, 131, 10, 85, 16505, 4, 900, 16, 7303, 10017), + (10017, 131, 131, 131, 131, 10, 85, 16506, 4, 900, 16, 10016, 10018), + (10018, 131, 131, 131, 131, 10, 85, 16507, 4, 900, 16, 10017, 7770), + (10019, 1192, 1192, 1192, 1192, 10, 85, 20177, 12, 1320, 16, 7306, 10020), + (10020, 1192, 1192, 1192, 1192, 10, 85, 21652, 12, 1320, 16, 10019, 10021), + (10021, 1192, 1192, 1192, 1192, 10, 85, 21704, 12, 1320, 16, 10020, 13363), + (10022, 746, 746, 746, 746, 12, 85, 16511, 10, 2160, 16, 7309, 10023), + (10023, 746, 746, 746, 746, 12, 85, 16512, 10, 2160, 16, 10022, 10024), + (10024, 746, 746, 746, 746, 12, 85, 16513, 10, 2160, 16, 10023, 15321), + (10025, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 7322, 10026), + (10026, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 10025, 10027), + (10027, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 10026, 10028), + (10028, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 10027, 10029), + (10029, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 10028, 10437), + (10030, -1, -1, 7940, 7940, 5, 75, -1, 0, 0, 16, 7942, 10031), + (10031, -1, -1, 7940, 7940, 7, 75, -1, 0, 0, 16, 10030, 10032), + (10032, -1, -1, 7940, 7940, 9, 75, -1, 0, 0, 16, 10031, 6484), + (10033, -1, -1, 7945, 7945, 6, 85, -1, 0, 0, 16, 7947, 10034), + (10034, -1, -1, 7945, 7945, 6, 85, -1, 0, 0, 16, 10033, 10347), + (10035, -1, -1, 7948, 7948, 6, 85, -1, 0, 0, 16, 7950, 10036), + (10036, -1, -1, 7948, 7948, 6, 85, -1, 0, 0, 16, 10035, 10037), + (10037, -1, -1, 7948, 7948, 6, 85, -1, 0, 0, 16, 10036, 15328), + (10038, 7951, 7951, 7951, 7951, 6, 85, 16514, 61, 900, 16, 7953, 10039), + (10039, 7951, 7951, 7951, 7951, 6, 85, 16515, 61, 900, 16, 10038, 10040), + (10040, 7951, 7951, 7951, 7951, 6, 85, 16516, 61, 900, 16, 10039, 7773), + (10041, -1, -1, 6636, 6636, 9, 75, -1, 0, 0, 16, 6638, 10042), + (10042, -1, -1, 6636, 6636, 10, 75, -1, 0, 0, 16, 10041, 10043), + (10043, -1, -1, 6636, 6636, 11, 75, -1, 0, 0, 16, 10042, 12529), + (10044, -1, -1, 6791, 6791, 6, 85, -1, 0, 0, 16, 6793, 10045), + (10045, -1, -1, 6791, 6791, 6, 85, -1, 0, 0, 16, 10044, 10046), + (10046, -1, -1, 6791, 6791, 6, 85, -1, 0, 0, 16, 10045, 10676), + (10047, 534, 534, 534, 534, 12, 85, 16561, 4, 2160, 16, 7331, 10048), + (10048, 534, 534, 534, 534, 12, 85, 16562, 4, 2160, 16, 10047, 10049), + (10049, 534, 534, 534, 534, 12, 85, 16563, 4, 2160, 16, 10048, 10708), + (10050, -1, -1, 6395, 6395, 7, 85, -1, 0, 0, 16, 7338, 10051), + (10051, -1, -1, 6395, 6395, 7, 85, -1, 0, 0, 16, 10050, 10052), + (10052, -1, -1, 6395, 6395, 7, 85, -1, 0, 0, 16, 10051, 10705), + (10053, 6754, 6754, 6754, 6754, 9, 75, 16570, 41, 1200, 16, 6754, 14111), + (10054, 6758, 6758, 6758, 6758, 10, 85, 16571, 43, 900, 16, 6760, 10055), + (10055, 6758, 6758, 6758, 6758, 11, 85, 16572, 43, 900, 16, 10054, 10056), + (10056, 6758, 6758, 6758, 6758, 12, 85, 16573, 43, 900, 16, 10055, 13546), + (10057, 6764, 6764, 6764, 6764, 9, 80, 16574, 52, 600, 16, 6764, 16716), + (10058, -1, -1, 6765, 6765, 9, 85, -1, 0, 0, 16, 6767, 10059), + (10059, -1, -1, 6765, 6765, 9, 85, -1, 0, 0, 16, 10058, 10060), + (10060, -1, -1, 6765, 6765, 9, 85, -1, 0, 0, 16, 10059, 10766), + (10061, 5007, 5007, 5007, 5007, 9, 85, 16575, 8, 2160, 16, 7343, 10062), + (10062, 5007, 5007, 5007, 5007, 9, 85, 16576, 8, 2160, 16, 10061, 10063), + (10063, 5007, 5007, 5007, 5007, 9, 85, 16577, 8, 2160, 16, 10062, 13119), + (10064, -1, -1, 1608, 1608, 6, 85, -1, 0, 0, 16, 7383, 10065), + (10065, -1, -1, 1608, 1608, 7, 85, -1, 0, 0, 16, 10064, 10066), + (10066, -1, -1, 1608, 1608, 8, 85, -1, 0, 0, 16, 10065, 10067), + (10067, -1, -1, 1608, 1608, 9, 85, -1, 0, 0, 16, 10066, 10068), + (10068, -1, -1, 1608, 1608, 10, 85, -1, 0, 0, 16, 10067, 10069), + (10069, -1, -1, 1608, 1608, 11, 85, -1, 0, 0, 16, 10068, 16730), + (10070, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 6634, 10071), + (10071, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 10070, 10072), + (10072, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 10071, 10073), + (10073, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 10072, 10074), + (10074, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 10073, 13621), + (10075, -1, -1, 6641, 6641, 9, 85, -1, 0, 0, 16, 6643, 10076), + (10076, -1, -1, 6641, 6641, 9, 85, -1, 0, 0, 16, 10075, 10077), + (10077, -1, -1, 6641, 6641, 9, 85, -1, 0, 0, 16, 10076, 16192), + (10078, 6508, 6508, 6508, 6508, 7, 85, 16578, 38, 600, 16, 7389, 10079), + (10079, 6508, 6508, 6508, 6508, 7, 85, 16579, 38, 600, 16, 10078, 10080), + (10080, 6508, 6508, 6508, 6508, 7, 85, 16580, 38, 600, 16, 10079, 15775), + (10081, -1, -1, 1313, 1313, 12, 85, -1, 0, 0, 16, 7398, 10082), + (10082, -1, -1, 1313, 1313, 12, 85, -1, 0, 0, 16, 10081, 10083), + (10083, -1, -1, 1313, 1313, 12, 85, -1, 0, 0, 16, 10082, 12579), + (10084, -1, -1, 6375, 6375, 6, 85, -1, 0, 0, 16, 7663, 10085), + (10085, -1, -1, 6375, 6375, 6, 85, -1, 0, 0, 16, 10084, 10086), + (10086, -1, -1, 6375, 6375, 6, 85, -1, 0, 0, 16, 10085, 5347), + (10087, -1, -1, 9503, 9503, 7, 85, -1, 0, 0, 16, 9505, 10088), + (10088, -1, -1, 9503, 9503, 7, 85, -1, 0, 0, 16, 10087, 10089), + (10089, -1, -1, 9503, 9503, 7, 85, -1, 0, 0, 16, 10088, 12792), + (10090, 1498, 1498, 1498, 1498, 12, 85, 16590, 12, 1320, 16, 7410, 10091), + (10091, 1498, 1498, 1498, 1498, 12, 85, 16591, 12, 1320, 16, 10090, 10092), + (10092, 1498, 1498, 1498, 1498, 12, 85, 16602, 12, 1320, 16, 10091, 13401), + (10093, 1495, 1495, 1495, 1495, 9, 86, 16603, 30, 900, 17, 7416, 10094), + (10096, 548, 548, 548, 548, 10, 85, 16606, 5, 900, 16, 7419, 10097), + (10097, 548, 548, 548, 548, 10, 85, 16607, 5, 900, 16, 10096, 10098), + (10098, 548, 548, 548, 548, 10, 85, 16608, 5, 900, 16, 10097, 13158), + (10099, 6561, 6561, 6561, 6561, 7, 85, 16609, 32, 30, 16, 7424, 10100), + (10100, 6561, 6561, 6561, 6561, 7, 85, 16610, 32, 30, 16, 10099, 10101), + (10101, 6561, 6561, 6561, 6561, 7, 85, 16611, 32, 30, 16, 10100, 10418), + (10102, 510, 510, 510, 510, 3, 75, 16587, 37, 240, 16, 7427, 10103), + (10103, 510, 510, 510, 510, 3, 75, 16588, 37, 240, 16, 10102, 10104), + (10104, 510, 510, 510, 510, 3, 75, 16589, 37, 240, 16, 10103, 10824), + (10105, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 7668, 10106), + (10106, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 10105, 10107), + (10107, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 10106, 10108), + (10108, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 10107, 10109), + (10109, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 10108, 17350), + (10110, -1, -1, 7983, 7983, 6, 81, -1, 0, 0, 16, 7985, 10111), + (10111, -1, -1, 7983, 7983, 6, 81, -1, 0, 0, 16, 10110, 10112), + (10112, -1, -1, 7983, 7983, 6, 81, -1, 0, 0, 16, 10111, -1), + (10113, 1352, 1352, 1352, 1352, 6, 85, 16618, 3, 60, 16, 7156, 10114), + (10114, 1352, 1352, 1352, 1352, 6, 85, 16619, 3, 60, 16, 10113, 10115), + (10115, 1352, 1352, 1352, 1352, 6, 85, 16620, 3, 60, 16, 10114, 13807), + (10116, 1358, 1358, 1358, 1358, 6, 85, 16615, 3, 60, 16, 7159, 10117), + (10117, 1358, 1358, 1358, 1358, 6, 85, 16616, 3, 60, 16, 10116, 10118), + (10118, 1358, 1358, 1358, 1358, 6, 85, 16617, 3, 60, 16, 10117, 13810), + (10119, 1355, 1355, 1355, 1355, 6, 85, 16612, 3, 60, 16, 7174, 10120), + (10120, 1355, 1355, 1355, 1355, 6, 85, 16613, 3, 60, 16, 10119, 10121), + (10121, 1355, 1355, 1355, 1355, 6, 85, 16614, 3, 60, 16, 10120, 12700), + (10122, -1, -1, 4801, 4801, 6, 85, -1, 0, 0, 16, 7162, 10123), + (10123, -1, -1, 4801, 4801, 6, 85, -1, 0, 0, 16, 10122, 12674), + (10124, -1, -1, 611, 611, 2, 75, -1, 0, 0, 16, 7177, 10125), + (10125, -1, -1, 611, 611, 2, 75, -1, 0, 0, 16, 10124, 10126), + (10126, -1, -1, 611, 611, 2, 75, -1, 0, 0, 16, 10125, 12703), + (10127, 7872, 7872, 7872, 7872, 6, 85, 16621, 41, 600, 16, 7874, 10128), + (10128, 7872, 7872, 7872, 7872, 6, 85, 16622, 41, 600, 16, 10127, 10129), + (10129, 7872, 7872, 7872, 7872, 6, 85, 16623, 41, 600, 16, 10128, 12682), + (10130, -1, -1, 6870, 6870, 6, 80, -1, 0, 0, 16, 6872, 10131), + (10131, -1, -1, 6870, 6870, 6, 80, -1, 0, 0, 16, 10130, 10132), + (10132, -1, -1, 6870, 6870, 6, 80, -1, 0, 0, 16, 10131, -1), + (10133, -1, -1, 255, 255, 9, 80, -1, 0, 0, 16, 6875, 10134), + (10134, -1, -1, 255, 255, 9, 80, -1, 0, 0, 16, 10133, 10135), + (10135, -1, -1, 255, 255, 9, 80, -1, 0, 0, 16, 10134, 13196), + (10136, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 16, 6878, 10137), + (10137, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 16, 10136, 10138), + (10138, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 16, 10137, 12734), + (10139, 6533, 6533, 6533, 6533, 10, 85, 16631, 15, 600, 16, 7428, 12740), + (10140, 1116, 1116, 1116, 1116, 12, 85, 16647, 4, 2160, 16, 7432, 10141), + (10141, 1116, 1116, 1116, 1116, 12, 85, 16648, 4, 2160, 16, 10140, 10142), + (10142, 1116, 1116, 1116, 1116, 12, 85, 16649, 4, 2160, 16, 10141, 12743), + (10143, 5298, 5298, 5298, 5298, 12, 85, 16632, 32, 1800, 16, 7440, 10144), + (10144, 5298, 5298, 5298, 5298, 12, 85, 16633, 32, 1800, 16, 10143, 10145), + (10145, 5298, 5298, 5298, 5298, 12, 85, 16634, 32, 1800, 16, 10144, 12746), + (10146, 1598, -1, 1598, 1598, 12, 85, 16638, 6, 900, 16, 7443, 10147), + (10147, 1598, -1, 1598, 1598, 12, 85, 16639, 6, 900, 16, 10146, 10148), + (10148, 1598, -1, 1598, 1598, 12, 85, 16640, 6, 900, 16, 10147, 13193), + (10149, 5020, 5020, 5020, 5020, 9, 85, 16630, 9, 300, 16, 7444, 13490), + (10150, 1110, 1110, 1110, 1110, 6, 85, 16641, 3, 2160, 16, 7447, 10151), + (10151, 1110, 1110, 1110, 1110, 6, 85, 16642, 3, 2160, 16, 10150, 10152), + (10152, 1110, 1110, 1110, 1110, 6, 85, 16643, 3, 2160, 16, 10151, 13190), + (10153, -1, -1, 6337, 6337, 6, 85, -1, 0, 0, 16, 7450, 10154), + (10154, -1, -1, 6337, 6337, 6, 85, -1, 0, 0, 16, 10153, 10155), + (10155, -1, -1, 6337, 6337, 6, 85, -1, 0, 0, 16, 10154, 16297), + (10156, 5017, 5017, 5017, 5017, 9, 85, 16627, 8, 600, 16, 7456, 10157), + (10157, 5017, 5017, 5017, 5017, 9, 85, 16628, 8, 600, 16, 10156, 10158), + (10158, 5017, 5017, 5017, 5017, 9, 85, 16629, 8, 600, 16, 10157, 14189), + (10159, 1569, 1569, 1569, 1569, 7, 85, 16624, 5, 1800, 16, 7459, 10160), + (10160, 1569, 1569, 1569, 1569, 7, 85, 16625, 5, 1800, 16, 10159, 10161), + (10161, 1569, 1569, 1569, 1569, 7, 85, 16626, 5, 1800, 16, 10160, 17276), + (10162, 6663, 6663, 6663, 6663, 7, 82, 16653, 59, 600, 16, 6665, 10163), + (10163, 6663, 6663, 6663, 6663, 7, 82, 16654, 59, 600, 16, 10162, 10164), + (10164, 6663, 6663, 6663, 6663, 7, 82, 16655, 59, 600, 16, 10163, -1), + (10165, -1, -1, 1543, 1543, 12, 85, -1, 0, 0, 16, 7136, 10166), + (10166, -1, -1, 1543, 1543, 12, 85, -1, 0, 0, 16, 10165, 10167), + (10167, -1, -1, 1543, 1543, 12, 85, -1, 0, 0, 16, 10166, 13213), + (10168, 6328, 6328, 6328, 6328, 7, 85, 16650, 10, 600, 16, 7145, 10169), + (10169, 6328, 6328, 6328, 6328, 7, 85, 16651, 10, 600, 16, 10168, 10170), + (10170, 6328, 6328, 6328, 6328, 7, 85, 16652, 10, 600, 16, 10169, 13770), + (10171, -1, -1, 878, 878, 7, 85, -1, 0, 0, 16, 7147, 10172), + (10172, -1, -1, 878, 878, 7, 85, -1, 0, 0, 16, 10171, -1), + (10173, -1, -1, 846, 846, 12, 85, -1, 0, 0, 16, 7153, 10174), + (10174, -1, -1, 846, 846, 12, 85, -1, 0, 0, 16, 10173, 10175), + (10175, -1, -1, 846, 846, 12, 85, -1, 0, 0, 16, 10174, 13795), + (10176, -1, -1, 6703, 6703, 3, 70, -1, 0, 0, 16, 6705, 10177), + (10177, -1, -1, 6703, 6703, 3, 70, -1, 0, 0, 16, 10176, 10178), + (10178, -1, -1, 6703, 6703, 3, 70, -1, 0, 0, 16, 10177, 13005), + (10179, 6706, 6706, 6706, 6706, 7, 85, 16675, 44, 600, 16, 6708, 10180), + (10180, 6706, 6706, 6706, 6706, 7, 85, 16676, 44, 600, 16, 10179, 10181), + (10181, 6706, 6706, 6706, 6706, 7, 85, 16677, 44, 600, 16, 10180, 5353), + (10182, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 6716, 10183), + (10183, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 10182, 10184), + (10184, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 10183, 10185), + (10185, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 10184, 10186), + (10186, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 10185, -1), + (10187, 1327, 1327, 1327, 1327, 12, 85, 16665, 10, 900, 16, 7462, 10188), + (10188, 1327, 1327, 1327, 1327, 12, 85, 16666, 10, 900, 16, 10187, 10189), + (10189, 1327, 1327, 1327, 1327, 12, 85, 16667, 10, 900, 16, 10188, 5330), + (10190, 1520, 1520, 1520, 1520, 9, 80, 16672, 11, 900, 16, 7465, 10191), + (10191, 1520, 1520, 1520, 1520, 9, 80, 16673, 11, 900, 16, 10190, 10192), + (10192, 1520, 1520, 1520, 1520, 9, 80, 16674, 11, 900, 16, 10191, 12997), + (10193, 153, 153, 153, 153, 12, 85, 16668, 3, 2160, 16, 7468, 11081), + (10194, 528, 528, 528, 528, 12, 85, 16669, 5, 720, 16, 7471, 10195), + (10195, 528, 528, 528, 528, 12, 85, 16670, 5, 720, 16, 10194, 10196), + (10196, 528, 528, 528, 528, 12, 85, 16671, 5, 720, 16, 10195, 13161), + (10197, 5251, 5251, 5251, 5251, 12, 85, 16662, 13, 900, 16, 7474, 10198), + (10198, 5251, 5251, 5251, 5251, 12, 85, 16663, 13, 900, 16, 10197, 10199), + (10199, 5251, 5251, 5251, 5251, 12, 85, 16664, 13, 900, 16, 10198, 5363), + (10200, 6815, 6815, 6815, 6815, 8, 85, 16691, 60, 600, 16, 6817, 10201), + (10201, 6815, 6815, 6815, 6815, 8, 85, 16692, 60, 600, 16, 10200, 10202), + (10202, 6815, 6815, 6815, 6815, 8, 85, 16693, 60, 600, 16, 10201, 12786), + (10203, -1, -1, 6819, 6819, 6, 77, -1, 0, 0, 16, 6821, 10204), + (10204, -1, -1, 6819, 6819, 6, 77, -1, 0, 0, 16, 10203, 10205), + (10205, -1, -1, 6819, 6819, 6, 77, -1, 0, 0, 16, 10204, -1), + (10206, -1, -1, 6823, 6823, 4, 75, -1, 0, 0, 16, 6827, 10207), + (10207, -1, -1, 6823, 6823, 4, 77, -1, 0, 0, 16, 10206, -1), + (10208, 6828, 6828, 6828, 6828, 12, 85, 16686, 43, 60, 16, 6828, 17534), + (10209, 1274, 1274, 1274, 1274, 12, 85, 16683, 9, 540, 16, 7201, 10210), + (10210, 1274, 1274, 1274, 1274, 12, 85, 16684, 9, 540, 16, 10209, 10211), + (10211, 1274, 1274, 1274, 1274, 12, 85, 16685, 9, 540, 16, 10210, 12760), + (10212, 1510, -1, 1510, 1510, 12, 80, 16690, 13, 2160, 16, 7202, -1), + (10213, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 7208, 10214), + (10214, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 10213, 10215), + (10215, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 10214, 10216), + (10216, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 10215, 10217), + (10217, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 10216, 12798), + (10218, 4927, 4927, 4927, 4927, 9, 85, 16682, 14, 600, 16, 7209, -1), + (10219, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 7214, 10220), + (10220, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 10219, 10221), + (10221, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 10220, 10222), + (10222, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 10221, 10223), + (10223, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 10222, -1), + (10224, 967, 967, 967, 967, 6, 85, 16687, 10, 1800, 16, 7219, 10225), + (10225, 967, 967, 967, 967, 6, 85, 16688, 10, 1800, 16, 10224, 10226), + (10226, 967, 967, 967, 967, 6, 85, 16689, 10, 1800, 16, 10225, 12789), + (10227, -1, -1, 5295, 5295, 6, 85, -1, 0, 0, 16, 7222, 10228), + (10228, -1, -1, 5295, 5295, 6, 85, -1, 0, 0, 16, 10227, 10229), + (10229, -1, -1, 5295, 5295, 6, 85, -1, 0, 0, 16, 10228, 13226), + (10230, 619, 619, 619, 619, 6, 83, 16704, 6, 900, 16, 7228, 10231), + (10231, 619, 619, 619, 619, 6, 83, 16705, 6, 900, 16, 10230, 10232), + (10232, 619, 619, 619, 619, 6, 83, 16706, 6, 900, 16, 10231, -1), + (10233, 516, 516, 516, 516, 6, 82, 16707, 5, 480, 16, 7237, 12879), + (10234, 1334, 1334, 1334, 1334, 12, 85, 16701, 11, 4320, 16, 7241, 10235), + (10235, 1334, 1334, 1334, 1334, 12, 85, 16702, 11, 4320, 16, 10234, 10236), + (10236, 1334, 1334, 1334, 1334, 12, 85, 16703, 11, 4320, 16, 10235, 12868), + (10237, 8060, 8060, 8060, 8060, 7, 85, 16711, 41, 1800, 16, 8062, 10238), + (10238, 8060, 8060, 8060, 8060, 7, 85, 16712, 41, 1800, 16, 10237, 10239), + (10239, 8060, 8060, 8060, 8060, 7, 85, 16713, 41, 1800, 16, 10238, 13650), + (10240, 8063, 8063, 8063, 8063, 7, 85, 16714, 41, 1800, 16, 8065, 10241), + (10241, 8063, 8063, 8063, 8063, 7, 85, 16715, 41, 1800, 16, 10240, 10242), + (10242, 8063, 8063, 8063, 8063, 7, 85, 16716, 41, 1800, 16, 10241, 13653), + (10243, 8066, 8066, 8066, 8066, 7, 85, 16717, 41, 1800, 16, 8068, 10244), + (10244, 8066, 8066, 8066, 8066, 7, 85, 16718, 41, 1800, 16, 10243, 10245), + (10245, 8066, 8066, 8066, 8066, 7, 85, 16719, 41, 1800, 16, 10244, 13656), + (10246, 8072, 8072, 8072, 8072, 7, 80, 16708, 37, 20, 16, 8074, 10247), + (10247, 8072, 8072, 8072, 8072, 7, 80, 16709, 37, 20, 16, 10246, 10248), + (10248, 8072, 8072, 8072, 8072, 7, 80, 16710, 37, 20, 16, 10247, 12857), + (10249, -1, -1, 8082, 8082, 3, 74, -1, 0, 0, 16, 8084, 10250), + (10250, -1, -1, 8082, 8082, 3, 74, -1, 0, 0, 16, 10249, 10251), + (10251, -1, -1, 8082, 8082, 3, 74, -1, 0, 0, 16, 10250, -1), + (10252, 520, 520, 520, 520, 12, 85, 16723, 6, 540, 16, 7252, 10253), + (10253, 520, 520, 520, 520, 12, 85, 16724, 6, 540, 16, 10252, 10254), + (10254, 520, 520, 520, 520, 12, 85, 16725, 6, 540, 16, 10253, 12985), + (10255, 4903, 4903, 4903, 4903, 9, 81, 16726, 9, 1320, 16, 7253, 12956), + (10256, 4906, 4906, 4906, 4906, 9, 81, 16727, 9, 1320, 16, 7254, 12959), + (10257, 4909, 4909, 4909, 4909, 9, 81, 16728, 16, 1320, 16, 7255, 12957), + (10258, 4912, 4912, 4912, 4912, 9, 81, 16729, 16, 1320, 16, 7256, 12958), + (10259, 616, 616, 616, 616, 10, 85, 16733, 7, 900, 16, 7259, 10260), + (10260, 616, 616, 616, 616, 10, 85, 16734, 7, 900, 16, 10259, 10261), + (10261, 616, 616, 616, 616, 10, 85, 16735, 7, 900, 16, 10260, 14730), + (10262, -1, -1, 1577, 1577, 12, 85, -1, 0, 0, 16, 7265, 10263), + (10263, -1, -1, 1577, 1577, 12, 85, -1, 0, 0, 16, 10262, 10264), + (10264, -1, -1, 1577, 1577, 12, 85, -1, 0, 0, 16, 10263, 13707), + (10265, -1, -1, 795, 795, 12, 85, -1, 0, 0, 16, 7269, 10266), + (10266, -1, -1, 795, 795, 12, 85, -1, 0, 0, 16, 10265, 10267), + (10267, -1, -1, 795, 795, 12, 85, -1, 0, 0, 16, 10266, 12945), + (10268, -1, -1, 7900, 7900, 4, 70, -1, 0, 0, 16, 7902, 10269), + (10269, -1, -1, 7900, 7900, 4, 70, -1, 0, 0, 16, 10268, 10270), + (10270, -1, -1, 7900, 7900, 4, 70, -1, 0, 0, 16, 10269, -1), + (10271, 1242, 1242, 1242, 1242, 12, 85, 16744, 9, 1320, 16, 7287, 10272), + (10272, 1242, 1242, 1242, 1242, 12, 85, 16745, 9, 1320, 16, 10271, 10273), + (10273, 1242, 1242, 1242, 1242, 12, 85, 16746, 9, 1320, 16, 10272, 12934), + (10274, 4931, 4931, 4931, 4931, 7, 85, 16747, 4, 600, 16, 7293, 10275), + (10275, 4931, 4931, 4931, 4931, 7, 85, 16748, 4, 600, 16, 10274, 10276), + (10276, 4931, 4931, 4931, 4931, 7, 85, 16749, 4, 600, 16, 10275, 10428), + (10277, 4935, 4935, 4935, 4935, 7, 81, 16743, 14, 300, 16, 7294, 17540), + (10278, 4934, 4934, 4934, 4934, 7, 81, 16742, 13, 300, 16, 7295, 17539), + (10279, 517, 517, 517, 517, 5, 80, 16739, 12, 600, 16, 7298, 10280), + (10280, 517, 517, 517, 517, 5, 80, 16740, 12, 600, 16, 10279, 10281), + (10281, 517, 517, 517, 517, 5, 80, 16741, 12, 600, 16, 10280, 12917), + (10282, -1, -1, 8031, 8031, 6, 84, -1, 0, 0, 16, 8033, 10283), + (10283, -1, -1, 8031, 8031, 6, 84, -1, 0, 0, 16, 10282, 10284), + (10284, -1, -1, 8031, 8031, 6, 84, -1, 0, 0, 16, 10283, 10431), + (10285, -1, -1, 8035, 8035, 6, 82, -1, 0, 0, 16, 8037, 10286), + (10286, -1, -1, 8035, 8035, 6, 82, -1, 0, 0, 16, 10285, 10287), + (10287, -1, -1, 8035, 8035, 6, 82, -1, 0, 0, 16, 10286, 15472), + (10288, 6971, 6971, 6971, 6971, 7, 85, 16761, 41, 600, 16, 6973, 10289), + (10289, 6971, 6971, 6971, 6971, 7, 85, 16762, 41, 600, 16, 10288, 10290), + (10290, 6971, 6971, 6971, 6971, 7, 85, 16763, 41, 600, 16, 10289, 14274), + (10291, -1, -1, 6974, 6974, 5, 85, -1, 0, 0, 16, 6976, 10292), + (10292, -1, -1, 6974, 6974, 5, 85, -1, 0, 0, 16, 10291, 10293), + (10293, -1, -1, 6974, 6974, 5, 85, -1, 0, 0, 16, 10292, -1), + (10294, 6984, 6984, 6984, 6984, 6, 78, 16765, 60, 60, 16, 6984, 13177), + (10295, 6985, 6985, 6985, 6985, 6, 78, 16766, 60, 60, 16, 6985, 13179), + (10296, 6986, 6986, 6986, 6986, 6, 78, 16767, 60, 60, 16, 6986, 13178), + (10297, 1119, 1119, 1119, 1119, 9, 85, 16750, 8, 900, 16, 7481, 10298), + (10298, 1119, 1119, 1119, 1119, 9, 85, 16751, 8, 900, 16, 10297, 10299), + (10299, 1119, 1119, 1119, 1119, 9, 85, 16752, 8, 900, 16, 10298, 16883), + (10300, 723, 723, 723, 723, 7, 85, 16753, 6, 30, 16, 7482, 14273), + (10301, 5015, 5015, 5015, 5015, 12, 85, 16754, 9, 900, 16, 7483, 17382), + (10302, 291, 291, 291, 291, 12, 85, 16755, 5, 900, 16, 7487, 10303), + (10303, 291, 291, 291, 291, 12, 85, 16756, 5, 900, 16, 10302, 10304), + (10304, 291, 291, 291, 291, 12, 85, 16757, 5, 900, 16, 10303, 12828), + (10305, -1, -1, 729, 729, 9, 85, -1, 0, 0, 16, 7496, 10306), + (10306, -1, -1, 729, 729, 9, 85, -1, 0, 0, 16, 10305, 10307), + (10307, -1, -1, 729, 729, 9, 85, -1, 0, 0, 16, 10306, 16887), + (10308, 6380, 6380, 6380, 6380, 6, 85, 16758, 39, 120, 16, 7499, 10309), + (10309, 6380, 6380, 6380, 6380, 6, 85, 16759, 39, 120, 16, 10308, 10310), + (10310, 6380, 6380, 6380, 6380, 6, 85, 16760, 39, 120, 16, 10309, 13170), + (10311, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 4808, 10312), + (10312, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 10311, 10313), + (10313, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 10312, 10314), + (10314, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 10313, 10315), + (10315, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 10314, 13035), + (10316, -1, -1, 4809, 4809, 5, 85, -1, 0, 0, 16, 4811, 10317), + (10317, -1, -1, 4809, 4809, 5, 85, -1, 0, 0, 16, 10316, 10318), + (10318, -1, -1, 4809, 4809, 5, 85, -1, 0, 0, 16, 10317, 13040), + (10319, 6931, 6931, 6931, 6931, 12, 85, 16774, 41, 600, 16, 6931, 13058), + (10320, 6932, 6932, 6932, 6932, 7, 85, 16775, 42, 1200, 16, 6934, 10321), + (10321, 6932, 6932, 6932, 6932, 7, 85, 16776, 42, 1200, 16, 10320, 10322), + (10322, 6932, 6932, 6932, 6932, 7, 85, 16777, 42, 1200, 16, 10321, 13062), + (10323, 4854, 4854, 4854, 4854, 12, 85, 16768, 8, 600, 16, 7180, 10324), + (10324, 4854, 4854, 4854, 4854, 12, 85, 16769, 8, 600, 16, 10323, 10325), + (10325, 4854, 4854, 4854, 4854, 12, 85, 16770, 8, 600, 16, 10324, 13059), + (10326, 1178, 1178, 1178, 1178, 9, 85, 16771, 4, 900, 16, 7189, 10327), + (10327, 1178, 1178, 1178, 1178, 9, 85, 16772, 4, 900, 16, 10326, 10328), + (10328, 1178, 1178, 1178, 1178, 9, 85, 16773, 4, 900, 16, 10327, 13845), + (10329, -1, -1, 10329, 10329, 5, 85, 0, 0, 0, 16, -1, 10398), + (10330, 10330, 10330, 10330, 10330, 7, 85, 16785, 35, 30, 16, -1, 13203), + (10331, 10331, 10331, 10331, 10331, 6, 85, 16787, 44, 20, 16, -1, -1), + (10332, -1, -1, 10332, 10332, 3, 85, -1, 0, 0, 16, -1, 12733), + (10333, 10333, 10333, 10333, 10333, 5, 85, 16788, 55, 120, 16, -1, 10334), + (10334, 10333, 10333, 10333, 10333, 7, 85, 16789, 55, 120, 16, 10333, 10335), + (10335, 10333, 10333, 10333, 10333, 9, 85, 16790, 55, 120, 16, 10334, 12724), + (10336, 10336, 10336, 10336, 10336, 5, 85, 16791, 58, 8, 16, -1, 10337), + (10337, 10336, 10336, 10336, 10336, 7, 85, 16792, 58, 8, 16, 10336, 10338), + (10338, 10336, 10336, 10336, 10336, 9, 85, 16793, 58, 8, 16, 10337, 12730), + (10339, 10339, 10339, 10339, 10339, 12, 85, 16786, 48, 1800, 16, -1, -1), + (10340, -1, -1, 10340, 10340, 3, 80, -1, 0, 0, 16, -1, 10341), + (10341, -1, -1, 10340, 10340, 6, 83, -1, 0, 0, 16, 10340, 10342), + (10342, -1, -1, 10340, 10340, 9, 85, -1, 0, 0, 16, 10341, 13184), + (10343, -1, -1, 10343, 10343, 5, 85, 0, 0, 0, 16, -1, 10344), + (10344, -1, -1, 10343, 10343, 7, 85, 0, 0, 0, 16, 10343, 10345), + (10345, -1, -1, 10343, 10343, 9, 85, 0, 0, 0, 16, 10344, 13841), + (10346, 10346, 10346, 10346, 10346, 9, 85, 21783, 46, 600, 16, -1, 13183), + (10347, -1, -1, 7945, 7945, 6, 85, -1, 0, 0, 16, 10034, 17310), + (10348, 0, 0, 10348, 10348, 5, 80, -1, 0, 0, 16, -1, 10349), + (10349, 0, 0, 10348, 10348, 7, 83, -1, 0, 0, 16, 10348, 10350), + (10350, 0, 0, 10348, 10348, 9, 85, -1, 0, 0, 16, 10349, 13578), + (10351, 10351, 10351, 10351, 10351, 12, 85, 21785, 34, 600, 16, -1, 10682), + (10352, 10352, 10352, 10352, 10352, 12, 85, 21786, 34, 600, 16, -1, 10683), + (10353, 10353, 10353, 10353, 10353, 12, 85, 21787, 34, 600, 16, -1, 10684), + (10354, 10354, 10354, 10354, 10354, 8, 85, 21653, 39, 4320, 16, -1, 14016), + (10355, -1, -1, 10355, 10355, 6, 83, -1, 0, 0, 16, -1, 10356), + (10356, -1, -1, 10355, 10355, 8, 84, -1, 0, 0, 16, 10355, 10357), + (10357, -1, -1, 10355, 10355, 10, 85, -1, 0, 0, 16, 10356, 10643), + (10358, -1, -1, 10358, 10358, 7, 80, -1, 0, 0, 16, -1, 10359), + (10359, -1, -1, 10358, 10358, 9, 83, -1, 0, 0, 16, 10358, 10360), + (10360, -1, -1, 10358, 10358, 12, 85, -1, 0, 0, 16, 10359, 14210), + (10361, -1, -1, 962, 962, 5, 83, -1, 0, 0, 16, 6227, 10362), + (10362, -1, -1, 962, 962, 5, 84, -1, 0, 0, 16, 10361, 10363), + (10363, -1, -1, 962, 962, 5, 85, -1, 0, 0, 16, 10362, 14218), + (10364, -1, -1, 10364, 10364, 5, 85, -1, 0, 0, 16, -1, 10365), + (10365, -1, -1, 10364, 10364, 7, 85, -1, 0, 0, 16, 10364, 10366), + (10366, -1, -1, 10364, 10364, 9, 85, -1, 0, 0, 16, 10365, 10442), + (10367, 10367, 10367, 10367, 10367, 12, 85, 21751, 30, 360, 16, -1, 10630), + (10368, 10368, 10368, 10368, 10368, 6, 85, 21654, 46, 900, 16, -1, 10369), + (10369, 10368, 10368, 10368, 10368, 9, 85, 21655, 46, 900, 16, 10368, 10386), + (10370, -1, -1, 10370, 10370, 3, 60, -1, 0, 0, 16, -1, 10371), + (10371, -1, -1, 10370, 10370, 3, 60, -1, 0, 0, 16, 10370, 10372), + (10372, -1, -1, 10370, 10370, 3, 60, -1, 0, 0, 16, 10371, 13927), + (10373, 10373, 10373, 10373, 10373, 6, 75, 16806, 62, 6, 16, -1, -1), + (10374, 10374, 10374, 10374, 10374, 6, 85, 16800, 63, 900, 16, -1, 10375), + (10375, 10374, 10374, 10374, 10374, 6, 85, 16801, 63, 900, 16, 10374, 10376), + (10376, 10374, 10374, 10374, 10374, 6, 85, 16802, 63, 900, 16, 10375, 13174), + (10377, 10377, 10377, 10377, 10377, 6, 85, 16794, 64, 60, 16, -1, 10378), + (10378, 10377, 10377, 10377, 10377, 6, 85, 16795, 64, 60, 16, 10377, 10379), + (10379, 10377, 10377, 10377, 10377, 6, 85, 16796, 64, 60, 16, 10378, 13180), + (10380, -1, -1, 10380, 10380, 6, 85, -1, 0, 0, 16, -1, 10381), + (10381, -1, -1, 10380, 10380, 6, 85, -1, 0, 0, 16, 10380, 10382), + (10382, -1, -1, 10380, 10380, 6, 85, -1, 0, 0, 16, 10381, 13477), + (10383, -1, -1, 5085, 5085, 6, 85, -1, 0, 0, 16, 7386, 10384), + (10384, -1, -1, 5085, 5085, 6, 85, -1, 0, 0, 16, 10383, 10385), + (10385, -1, -1, 5085, 5085, 6, 85, -1, 0, 0, 16, 10384, -1), + (10386, 10368, 10368, 10368, 10368, 12, 85, 21656, 46, 900, 16, 10369, -1), + (10387, 10387, 10387, 10387, 10387, 9, 85, 21835, 45, 1200, 16, -1, -1), + (10388, -1, -1, 10388, 10388, 12, 85, -1, 0, 0, 16, -1, 13545), + (10389, -1, -1, 10389, 10389, 9, 83, 0, 0, 0, 16, -1, 10390), + (10390, -1, -1, 10389, 10389, 11, 84, 0, 0, 0, 16, 10389, 10391), + (10391, -1, -1, 10389, 10389, 12, 85, 0, 0, 0, 16, 10390, -1), + (10392, 10392, 10392, 10392, 10392, 12, 85, 21751, 11, 480, 16, -1, 10631), + (10393, 10393, 10393, 10393, 10393, 9, 81, 3246, 42, 2, 16, -1, -1), + (10394, 10394, 10394, 10394, 10394, 12, 85, 21821, 30, 600, 16, -1, 10704), + (10395, 10395, 10395, 10395, 10395, 3, 80, 21748, 62, 5, 16, -1, 12590), + (10396, 10396, 10396, 10396, 10396, 12, 85, 16857, 14, 600, 16, -1, 10790), + (10397, 10397, 10397, 10397, 10397, 12, 85, 16858, 14, 600, 16, -1, 10791), + (10398, -1, -1, 10329, 10329, 7, 85, 0, 0, 0, 16, 10329, 10399), + (10399, -1, -1, 10329, 10329, 9, 85, 0, 0, 0, 16, 10398, -1), + (10400, 10400, 10400, 10400, 10400, 6, 85, 16807, 62, 900, 16, -1, 15558), + (10401, -1, -1, 10401, 10401, 6, 85, -1, 0, 0, 16, -1, 10402), + (10402, -1, -1, 10401, 10401, 6, 85, -1, 0, 0, 16, 10401, 10403), + (10403, -1, -1, 10401, 10401, 6, 85, -1, 0, 0, 16, 10402, 13052), + (10404, -1, -1, 10404, 10404, 6, 85, -1, 0, 0, 16, -1, 13051), + (10405, -1, -1, 10405, 10405, 7, 81, 0, 0, 0, 16, -1, 10406), + (10406, -1, -1, 10405, 10405, 7, 82, 0, 0, 0, 16, 10405, 10407), + (10407, -1, -1, 10405, 10405, 7, 83, 0, 0, 0, 16, 10406, 10408), + (10408, -1, -1, 10405, 10405, 7, 84, 0, 0, 0, 16, 10407, 10409), + (10409, -1, -1, 10405, 10405, 7, 85, 0, 0, 0, 16, 10408, 10671), + (10410, -1, -1, 10410, 10410, 8, 85, -1, 0, 0, 16, -1, 10411), + (10413, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, -1, 10414), + (10414, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, 10413, 10415), + (10415, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, 10414, 10416), + (10416, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, 10415, 10417), + (10417, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, 10416, -1), + (10418, 6561, 6561, 6561, 6561, 7, 85, 21808, 32, 30, 16, 10101, 10419), + (10419, 6561, 6561, 6561, 6561, 7, 85, 21810, 32, 30, 16, 10418, 10420), + (10420, 6561, 6561, 6561, 6561, 7, 85, 21811, 32, 30, 16, 10419, 14256), + (10421, 10506, 10506, 10506, 10506, 9, 85, 23521, 66, 120, 16, 10508, -1), + (10424, 10424, 10424, 10424, 10424, 7, 81, 21813, 41, 6, 16, -1, -1), + (10425, 10425, 10425, 10425, 10425, 7, 81, 21814, 39, 6, 16, -1, -1), + (10426, 10426, 10426, 10426, 10426, 10, 85, 21816, 5, 900, 16, -1, -1), + (10427, 10427, 10427, 10427, 10427, 12, 85, 21818, 30, 900, 16, -1, -1), + (10428, 4931, 4931, 4931, 4931, 7, 85, 21838, 4, 600, 16, 10276, 10429), + (10429, 4931, 4931, 4931, 4931, 7, 85, 21839, 4, 600, 16, 10428, 10430), + (10430, 4931, 4931, 4931, 4931, 7, 85, 21844, 4, 600, 16, 10429, 13241), + (10431, -1, -1, 8031, 8031, 6, 85, -1, 0, 0, 16, 10284, 10432), + (10432, -1, -1, 8031, 8031, 6, 85, -1, 0, 0, 16, 10431, 10433), + (10433, -1, -1, 8031, 8031, 6, 85, -1, 0, 0, 16, 10432, -1), + (10434, -1, -1, 10434, 10434, 7, 85, 0, 0, 0, 16, -1, 10435), + (10435, -1, -1, 10434, 10434, 9, 85, 0, 0, 0, 16, 10434, 10436), + (10436, -1, -1, 10434, 10434, 12, 85, 0, 0, 0, 16, 10435, -1), + (10437, -1, -1, 6601, 6601, 6, 86, -1, 0, 0, 17, 10029, 10438), + (10438, -1, -1, 6601, 6601, 6, 87, -1, 0, 0, 17, 10437, 10439), + (10439, -1, -1, 6601, 6601, 6, 88, -1, 0, 0, 17, 10438, 10440), + (10440, -1, -1, 6601, 6601, 6, 89, -1, 0, 0, 17, 10439, 10441), + (10442, -1, -1, 10364, 10364, 9, 86, -1, 0, 0, 17, 10366, 10443), + (10443, -1, -1, 10364, 10364, 9, 88, -1, 0, 0, 17, 10442, -1), + (10450, 10450, 10450, 10450, 10450, 7, 85, 16808, 63, 900, 16, -1, 10451), + (10451, 10450, 10450, 10450, 10450, 7, 85, 16809, 63, 900, 16, 10450, 10452), + (10452, 10450, 10450, 10450, 10450, 7, 85, 16810, 63, 900, 16, 10451, 10468), + (10453, -1, -1, 10453, 10453, 5, 85, -1, 0, 0, 16, -1, 10454), + (10454, -1, -1, 10453, 10453, 7, 85, -1, 0, 0, 16, 10453, 10455), + (10455, -1, -1, 10453, 10453, 9, 85, -1, 0, 0, 16, 10454, 13607), + (10456, -1, -1, 10456, 10456, 5, 85, -1, 0, 0, 16, -1, 10457), + (10457, -1, -1, 10456, 10456, 7, 85, -1, 0, 0, 16, 10456, 10458), + (10458, -1, -1, 10456, 10456, 9, 85, -1, 0, 0, 16, 10457, -1), + (10459, -1, -1, 10459, 10459, 5, 65, -1, 0, 0, 16, -1, 10460), + (10460, -1, -1, 10459, 10459, 7, 65, -1, 0, 0, 16, 10459, 10461), + (10461, -1, -1, 10459, 10459, 9, 65, -1, 0, 0, 16, 10460, -1), + (10462, 10462, 10462, 10462, 10462, 12, 85, 16811, 14, 4320, 16, -1, -1), + (10463, 10463, 10463, 10463, 10463, 12, 85, 16812, 16, 4320, 16, -1, -1), + (10464, -1, -1, 10464, 10464, 5, 80, -1, 0, 0, 16, -1, 10465), + (10465, -1, -1, 10464, 10464, 7, 80, -1, 0, 0, 16, 10464, 10466), + (10466, -1, -1, 10464, 10464, 9, 80, -1, 0, 0, 16, 10465, 13140), + (10467, -1, -1, 86, 86, 8, 85, -1, 0, 0, 17, 266, -1), + (10468, 10450, 10450, 10450, 10450, 7, 85, 23603, 63, 900, 17, 10452, 10469), + (10469, 10450, 10450, 10450, 10450, 7, 85, 23604, 63, 900, 17, 10468, 10670), + (10470, -1, -1, 10470, 10470, 9, 86, -1, 0, 0, 17, -1, 10471), + (10471, -1, -1, 10470, 10470, 12, 88, -1, 0, 0, 17, 10470, 10472), + (10472, -1, -1, 10470, 10470, 15, 90, -1, 0, 0, 17, 10471, 15828), + (10473, -1, -1, 446, 735, 10, 86, -1, 0, 0, 17, 7624, 10474), + (10474, -1, -1, 446, 735, 10, 87, -1, 0, 0, 17, 10473, 10475), + (10475, -1, -1, 446, 735, 10, 88, -1, 0, 0, 17, 10474, 10476), + (10476, -1, -1, 446, 735, 10, 89, -1, 0, 0, 17, 10475, 10477), + (10477, -1, -1, 446, 735, 10, 90, -1, 0, 0, 17, 10476, 13308), + (10478, -1, -1, 10478, 10478, 15, 101, -1, 0, 0, 21, -1, 10479), + (10481, 10481, 10481, 10481, 10481, 21, 105, 46249, 90, 600, 21, -1, -1), + (10500, 10500, 10500, 10500, 10500, 7, 85, 16813, 62, 12, 16, -1, -1), + (10501, 10501, 10501, 10501, 10501, 7, 85, 16814, 63, 1, 16, -1, -1), + (10502, 10502, -1, 10502, 10502, 7, 85, 1566, 64, 120, 16, -1, 12647), + (10503, 10503, 10503, 10503, 10503, 9, 85, 16816, 13, 600, 16, -1, 10504), + (10504, 10503, 10503, 10503, 10503, 9, 85, 16817, 13, 600, 16, 10503, 10505), + (10505, 10503, 10503, 10503, 10503, 9, 85, 16818, 13, 600, 16, 10504, 12648), + (10506, 10506, 10506, 10506, 10506, 9, 85, 16819, 66, 120, 16, -1, 10507), + (10507, 10506, 10506, 10506, 10506, 9, 85, 16820, 66, 120, 16, 10506, 10508), + (10508, 10506, 10506, 10506, 10506, 9, 85, 16821, 66, 120, 16, 10507, 10421), + (10509, 5105, 5105, 5105, 5105, 12, 85, 16822, 11, 600, 16, 7420, 13154), + (10510, 7986, 7986, 7986, 7986, 12, 85, 16823, 11, 600, 16, 7988, 13155), + (10511, -1, -1, 10511, 10511, 6, 85, -1, 0, 0, 16, -1, 10512), + (10512, -1, -1, 10511, 10511, 6, 85, -1, 0, 0, 16, 10511, 10513), + (10513, -1, -1, 10511, 10511, 6, 85, -1, 0, 0, 16, 10512, 12642), + (10514, -1, -1, 10514, 10514, 6, 85, -1, 0, 0, 16, -1, 10516), + (10515, -1, -1, 10514, 10514, 6, 85, -1, 0, 0, 16, 10516, 12639), + (10516, -1, -1, 10514, 10514, 6, 85, -1, 0, 0, 16, 10514, 10515), + (10517, 6565, 6565, 6565, 6565, 9, 88, 23608, 17, 45, 17, 10010, 10518), + (10519, -1, -1, 10519, 10519, 9, 86, 0, 0, 0, 17, -1, 10520), + (10522, -1, -1, 10522, 10522, 7, 86, 0, 0, 0, 17, -1, 10523), + (10527, -1, -1, 10527, 10527, 5, 86, 0, 0, 0, 17, -1, 10528), + (10532, -1, -1, 10532, 10532, 5, 86, 0, 0, 0, 17, -1, 10533), + (10537, -1, -1, 10537, 10537, 5, 86, 0, 0, 0, 17, -1, 10538), + (10545, 10545, 10545, 10545, 10545, 12, 85, 23531, 73, 600, 17, -1, -1), + (10546, 10546, 10546, 10546, 10546, 12, 85, 23528, 74, 600, 17, -1, -1), + (10548, -1, -1, 10548, 10548, 9, 86, -1, 0, 0, 17, -1, 10549), + (10550, 10550, 10550, 10550, 10550, 7, 85, 16824, 61, 120, 16, -1, 13250), + (10551, -1, -1, 10551, 10551, 6, 85, -1, 0, 0, 16, -1, 10552), + (10552, -1, -1, 10551, 10551, 6, 85, -1, 0, 0, 16, 10551, 10553), + (10553, -1, -1, 10551, 10551, 6, 85, -1, 0, 0, 16, 10552, 14764), + (10554, -1, -1, 1572, 1572, 5, 80, -1, 0, 0, 16, 1576, 10555), + (10555, -1, -1, 1572, 1572, 5, 80, -1, 0, 0, 16, 10554, 10556), + (10556, -1, -1, 1572, 1572, 5, 80, -1, 0, 0, 16, 10555, 16062), + (10557, 12395, 12395, 12395, 12395, 9, 75, 16828, 11, 900, 16, -1, -1), + (10558, -1, -1, 10558, 10558, 6, 80, -1, 0, 0, 16, -1, 10559), + (10559, -1, -1, 10558, 10558, 6, 83, -1, 0, 0, 16, 10558, 10560), + (10560, -1, -1, 10558, 10558, 6, 85, -1, 0, 0, 16, 10559, 15469), + (10561, -1, -1, 10561, 10561, 6, 85, -1, 0, 0, 16, -1, 10562), + (10562, -1, -1, 10561, 10561, 6, 85, -1, 0, 0, 16, 10561, 10563), + (10563, -1, -1, 10561, 10561, 6, 85, -1, 0, 0, 16, 10562, 15466), + (10564, 773, -1, 773, 773, 12, 85, 16829, 5, 1800, 16, 7278, 10565), + (10565, 773, -1, 773, 773, 12, 85, 16830, 5, 1800, 16, 10564, 10566), + (10566, 773, -1, 773, 773, 12, 85, 16831, 5, 1800, 16, 10565, 13734), + (10568, -1, -1, 6564, 6564, 10, 86, -1, 0, 0, 17, 10009, 10569), + (10571, 1597, 1597, 1597, 1597, 9, 85, 23611, 6, 10, 17, 6606, -1), + (10572, 6617, 6617, 6617, 6617, 12, 86, 23612, 42, 3600, 17, 6617, 14036), + (10573, 6610, 6610, 6610, 6610, 9, 86, 23613, 41, 30, 17, 10003, 13422), + (10574, -1, -1, 6611, 6611, 6, 85, -1, 0, 0, 17, 6619, 16121), + (10575, -1, -1, 6614, 6614, 9, 85, -1, 0, 0, 17, 10005, -1), + (10576, -1, -1, 492, 492, 2, 87, -1, 0, 0, 17, 7130, -1), + (10578, 258, -1, 258, 258, 9, 86, 27520, 1, 600, 17, 258, 16003), + (10579, -1, -1, 7036, 10579, 9, 85, 0, 0, 0, 17, 7038, 10580), + (10580, -1, -1, 7036, 10579, 12, 87, 0, 0, 0, 17, 10579, 10581), + (10585, 912, 912, 912, 912, 9, 86, 23617, 4, 3600, 17, 10013, 10586), + (10588, -1, -1, 10588, 10588, 5, 86, 0, 0, 0, 17, -1, 10589), + (10589, -1, -1, 10588, 10588, 5, 87, 0, 0, 0, 17, 10588, 10590), + (10590, -1, -1, 10588, 10588, 5, 88, 0, 0, 0, 17, 10589, 10591), + (10591, -1, -1, 10588, 10588, 5, 89, 0, 0, 0, 17, 10590, 10592), + (10592, -1, -1, 10588, 10588, 5, 90, 0, 0, 0, 17, 10591, 17206), + (10600, 10600, 10600, 10600, 10600, 7, 85, 16832, 73, 20, 16, -1, 10601), + (10601, 10600, 10600, 10600, 10600, 7, 85, 16833, 73, 20, 16, 10600, 10602), + (10602, 10600, 10600, 10600, 10600, 7, 85, 16834, 73, 20, 16, 10601, 12982), + (10603, 10601, 10601, 10601, 10601, 3, 85, 16835, 62, 6, 16, -1, -1), + (10604, -1, -1, 6051, 6051, 3, 85, -1, 0, 0, 16, 7603, 10605), + (10605, -1, -1, 6051, 6051, 3, 85, -1, 0, 0, 16, 10604, 10606), + (10606, -1, -1, 6051, 6051, 3, 85, -1, 0, 0, 16, 10605, 12795), + (10607, -1, -1, 6383, 6383, 9, 80, -1, 0, 0, 16, 6385, 10608), + (10608, -1, -1, 6383, 6383, 9, 80, -1, 0, 0, 16, 10607, 10609), + (10609, -1, -1, 6383, 6383, 9, 80, -1, 0, 0, 16, 10608, 12801), + (10610, -1, -1, 10610, 10610, 3, 70, -1, 0, 0, 16, -1, 10611), + (10611, -1, -1, 10610, 10610, 3, 70, -1, 0, 0, 16, 10610, 10612), + (10612, -1, -1, 10610, 10610, 3, 70, -1, 0, 0, 16, 10611, -1), + (10618, 7850, 7850, 7850, 7850, 9, 86, 23532, 39, 4320, 17, 7340, 10619), + (10619, 7850, 7850, 7850, 7850, 12, 88, 23533, 39, 4320, 17, 10618, 10620), + (10620, 7850, 7850, 7850, 7850, 15, 90, 23534, 39, 4320, 17, 10619, 13604), + (10621, -1, -1, 849, 849, 9, 85, -1, 0, 0, 17, 851, 10622), + (10622, -1, -1, 849, 849, 9, 87, -1, 0, 0, 17, 10621, 16604), + (10623, -1, -1, 255, 255, 9, 85, -1, 0, 0, 17, 5808, 10624), + (10624, -1, -1, 255, 255, 12, 87, -1, 0, 0, 17, 10623, 10625), + (10625, -1, -1, 255, 255, 15, 89, -1, 0, 0, 17, 10624, 13589), + (10626, 5984, 5984, 5984, 5984, 12, 90, 23535, 2, 30, 17, 7711, 13592), + (10627, -1, -1, 10627, 10627, 3, 59, 0, 0, 0, 3, -1, 10628), + (10628, -1, -1, 10627, 10627, 3, 59, 0, 0, 0, 3, 10627, 10629), + (10629, -1, -1, 10627, 10627, 3, 59, 0, 0, 0, 3, 10628, -1), + (10630, 10367, 10367, 10367, 10367, 12, 90, 27642, 30, 360, 17, 10367, 13434), + (10631, 10392, 10392, 10392, 10392, 12, 90, 27642, 11, 480, 17, 10392, -1), + (10632, -1, -1, 735, 735, 10, 86, -1, 0, 0, 17, 7627, 10633), + (10633, -1, -1, 735, 735, 10, 87, -1, 0, 0, 17, 10632, 10634), + (10634, -1, -1, 735, 735, 10, 88, -1, 0, 0, 17, 10633, 10635), + (10635, -1, -1, 735, 735, 10, 89, -1, 0, 0, 17, 10634, 10636), + (10636, -1, -1, 735, 735, 10, 90, -1, 0, 0, 17, 10635, 13884), + (10637, -1, -1, 1287, 1287, 9, 86, -1, 0, 0, 17, 12471, 10638), + (10638, -1, -1, 1287, 1287, 12, 88, -1, 0, 0, 17, 10637, 10639), + (10639, -1, -1, 1287, 1287, 15, 90, -1, 0, 0, 17, 10638, 13323), + (10640, 5095, 5095, 5095, 5095, 9, 85, 23620, 10, 900, 17, 7334, 10641), + (10641, 5095, 5095, 5095, 5095, 12, 87, 23621, 10, 900, 17, 10640, 10642), + (10642, 5095, 5095, 5095, 5095, 15, 89, 23622, 10, 900, 17, 10641, 13575), + (10643, -1, -1, 10355, 10355, 10, 86, -1, 0, 0, 17, 10357, 10644), + (10644, -1, -1, 10355, 10355, 10, 88, -1, 0, 0, 17, 10643, 10645), + (10645, -1, -1, 10355, 10355, 10, 90, -1, 0, 0, 17, 10644, 14094), + (10646, 7712, 7712, 7712, 7712, 15, 90, 23536, 2, 30, 17, 7712, 13585), + (10647, 188, 188, 188, 188, 9, 88, 23537, 2, 30, 17, 7662, 13586), + (10650, -1, -1, 10650, 10650, 7, 85, -1, 0, 0, 16, -1, 10651), + (10651, -1, -1, 10650, 10650, 9, 85, -1, 0, 0, 16, 10650, 10652), + (10652, -1, -1, 10650, 10650, 12, 85, -1, 0, 0, 16, 10651, 13804), + (10653, -1, -1, 10653, 10653, 7, 85, -1, 0, 0, 16, -1, 10654), + (10654, -1, -1, 10653, 10653, 7, 85, -1, 0, 0, 16, 10653, 10655), + (10655, -1, -1, 10653, 10653, 7, 85, -1, 0, 0, 16, 10654, 17406), + (10656, -1, -1, 10656, 10656, 7, 85, -1, 0, 0, 16, -1, 12678), + (10657, -1, -1, 10657, 10657, 7, 85, -1, 0, 0, 16, -1, 10658), + (10658, -1, -1, 10657, 10657, 7, 85, -1, 0, 0, 16, 10657, 10659), + (10659, -1, -1, 10657, 10657, 7, 85, -1, 0, 0, 16, 10658, 12679), + (10660, -1, -1, 820, 820, 5, 85, -1, 0, 0, 16, 7165, 10661), + (10661, -1, -1, 820, 820, 5, 85, -1, 0, 0, 16, 10660, 10662), + (10662, -1, -1, 820, 820, 5, 85, -1, 0, 0, 16, 10661, 12667), + (10663, -1, -1, 6020, 6020, 2, 85, -1, 0, 0, 16, 7171, 10664), + (10664, -1, -1, 6020, 6020, 2, 85, -1, 0, 0, 16, 10663, 10665), + (10665, -1, -1, 6020, 6020, 2, 85, -1, 0, 0, 16, 10664, 12670), + (10666, -1, -1, 495, 495, 6, 85, -1, 0, 0, 16, 6262, 10667), + (10667, -1, -1, 495, 495, 5, 85, -1, 0, 0, 16, 10666, 10668), + (10668, -1, -1, 495, 495, 7, 85, -1, 0, 0, 16, 10667, 17391), + (10670, 10450, 10450, 10450, 10450, 7, 85, 23605, 63, 900, 17, 10469, 15839), + (10671, -1, -1, 10405, 10405, 9, 86, 0, 0, 0, 17, 10409, 10672), + (10672, -1, -1, 10405, 10405, 9, 87, 0, 0, 0, 17, 10671, 10673), + (10673, -1, -1, 10405, 10405, 9, 88, 0, 0, 0, 17, 10672, 10674), + (10674, -1, -1, 10405, 10405, 9, 89, 0, 0, 0, 17, 10673, 10675), + (10675, -1, -1, 10405, 10405, 9, 90, 0, 0, 0, 17, 10674, -1), + (10676, -1, -1, 6791, 6791, 6, 86, -1, 0, 0, 17, 10046, 10677), + (10677, -1, -1, 6791, 6791, 6, 88, -1, 0, 0, 17, 10676, 10678), + (10678, -1, -1, 6791, 6791, 6, 90, -1, 0, 0, 17, 10677, 13598), + (10679, 6492, 6492, 6492, 6492, 9, 85, 23626, 52, 720, 17, 6497, 10680), + (10680, 6492, 6492, 6492, 6492, 9, 87, 23627, 52, 720, 17, 10679, 10681), + (10681, 6492, 6492, 6492, 6492, 9, 89, 23628, 52, 720, 17, 10680, 14003), + (10682, 10351, 10351, 10351, 10351, 15, 90, 23538, 34, 600, 17, 10351, -1), + (10683, 10352, 10352, 10352, 10352, 15, 90, 23539, 34, 600, 17, 10352, -1), + (10684, 10353, 10353, 10353, 10353, 15, 90, 23540, 34, 600, 17, 10353, -1), + (10685, -1, -1, 602, 602, 9, 86, -1, 0, 0, 17, 5582, 10686), + (10686, -1, -1, 602, 602, 12, 88, -1, 0, 0, 17, 10685, 10687), + (10687, -1, -1, 602, 602, 15, 90, -1, 0, 0, 17, 10686, 13610), + (10688, -1, -1, 855, 855, 7, 86, -1, 0, 0, 17, 7677, 10689), + (10689, -1, -1, 855, 855, 7, 87, -1, 0, 0, 17, 10688, 10690), + (10690, -1, -1, 855, 855, 7, 88, -1, 0, 0, 17, 10689, 10691), + (10691, -1, -1, 855, 855, 7, 89, -1, 0, 0, 17, 10690, 10692), + (10692, -1, -1, 855, 855, 7, 90, -1, 0, 0, 17, 10691, 13613), + (10700, 10700, 10700, 10700, 10700, 7, 85, 16839, 61, 10, 16, -1, -1), + (10701, 10701, 10701, 10701, 10701, 7, 85, 21662, 32, 360, 16, -1, 10702), + (10702, 10701, 10701, 10701, 10701, 9, 85, 21663, 32, 360, 16, 10701, 10703), + (10703, 10701, 10701, 10701, 10701, 12, 85, 21664, 32, 360, 16, 10702, 12754), + (10704, 10394, 10394, 10394, 10394, 12, 85, 23541, 30, 300, 17, 10394, 13584), + (10705, -1, -1, 6395, 6395, 9, 86, -1, 0, 0, 17, 10052, 10706), + (10706, -1, -1, 6395, 6395, 9, 88, -1, 0, 0, 17, 10705, 10707), + (10707, -1, -1, 6395, 6395, 9, 90, -1, 0, 0, 17, 10706, 14097), + (10708, 534, 534, 534, 534, 12, 86, 23545, 4, 2160, 17, 10049, 10709), + (10709, 534, 534, 534, 534, 12, 88, 23546, 4, 2160, 17, 10708, 10710), + (10710, 534, 534, 534, 534, 12, 90, 23547, 4, 2160, 17, 10709, 13595), + (10711, 10711, 10711, 10711, 10711, 9, 86, 23548, 75, 1200, 17, -1, 10712), + (10712, 10711, 10711, 10711, 10711, 12, 88, 23549, 75, 1200, 17, 10711, 10713), + (10713, 10711, 10711, 10711, 10711, 15, 90, 23550, 75, 1200, 17, 10712, 14006), + (10714, -1, -1, 10714, 10714, 9, 86, 0, 0, 0, 17, -1, 10715), + (10715, -1, -1, 10714, 10714, 12, 88, 0, 0, 0, 17, 10714, 10716), + (10717, -1, -1, 7743, 7743, 9, 61, -1, 0, 0, 17, 7745, 10718), + (10718, -1, -1, 7743, 7743, 9, 61, -1, 0, 0, 17, 10717, 15258), + (10719, -1, -1, 10719, 10719, 9, 75, 0, 0, 0, 17, -1, 10720), + (10720, -1, -1, 10719, 10719, 12, 75, 0, 0, 0, 17, 10719, 10721), + (10721, -1, -1, 10719, 10719, 15, 75, 0, 0, 0, 17, 10720, 13562), + (10722, -1, -1, 10722, 10722, 5, 81, 0, 0, 0, 17, -1, 10723), + (10723, -1, -1, 10722, 10722, 5, 82, 0, 0, 0, 17, 10722, 10724), + (10724, -1, -1, 10722, 10722, 7, 83, 0, 0, 0, 17, 10723, 10725), + (10725, -1, -1, 10722, 10722, 9, 84, 0, 0, 0, 17, 10724, 10726), + (10726, -1, -1, 10722, 10722, 12, 85, 0, 0, 0, 17, 10725, 15280), + (10727, -1, -1, 10727, 10727, 7, 86, 0, 0, 0, 17, -1, 10728), + (10728, -1, -1, 10727, 10727, 9, 88, 0, 0, 0, 17, 10727, 10729), + (10730, -1, -1, 10730, 10730, 7, 86, 0, 0, 0, 17, -1, 10731), + (10731, -1, -1, 10730, 10730, 9, 88, 0, 0, 0, 17, 10730, 10732), + (10733, -1, -1, 10733, 10733, 7, 81, 0, 0, 0, 17, -1, 10734), + (10734, -1, -1, 10733, 10733, 9, 83, 0, 0, 0, 17, 10733, 10735), + (10735, -1, -1, 10733, 10733, 12, 85, 0, 0, 0, 17, 10734, -1), + (10736, 10736, 10736, 10736, 10736, 7, 86, 23632, 5, 180, 17, -1, 10737), + (10737, 10736, 10736, 10736, 10736, 9, 88, 23633, 5, 180, 17, 10736, 10738), + (10739, 645, -1, 645, 645, 12, 86, 23551, 4, 5, 17, 5999, 13410), + (10740, 1345, 1345, 1345, 1345, 9, 86, 23552, 6, 900, 17, 7349, 10741), + (10741, 1345, 1345, 1345, 1345, 12, 88, 23553, 6, 900, 17, 10740, 10742), + (10743, -1, -1, 1196, 1196, 5, 86, -1, 0, 0, 17, 1200, 10744), + (10744, -1, -1, 1196, 1196, 5, 87, -1, 0, 0, 17, 10743, 10745), + (10745, -1, -1, 1196, 1196, 5, 88, -1, 0, 0, 17, 10744, 10746), + (10748, -1, -1, 867, 867, 7, 86, -1, 0, 0, 17, 7366, 10749), + (10749, -1, -1, 867, 867, 7, 87, -1, 0, 0, 17, 10748, 10755), + (10750, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 16, 7328, 10751), + (10751, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 16, 10750, -1), + (10752, 10752, 10752, 10752, 10752, 6, 85, 16843, 72, 600, 16, -1, -1), + (10753, 10753, 10753, 10753, 10753, 12, 80, 16844, 6, 4320, 16, -1, -1), + (10754, 10754, 10754, 10754, 10754, 2, 70, 16845, 62, 5, 16, -1, -1), + (10755, -1, -1, 867, 867, 7, 88, -1, 0, 0, 17, 10749, 10756), + (10758, 545, 545, 545, 545, 12, 86, 23638, 3, 900, 17, 7346, 10759), + (10759, 545, 545, 545, 545, 12, 87, 23639, 3, 900, 17, 10758, 10760), + (10760, 545, 545, 545, 545, 12, 88, 23640, 3, 900, 17, 10759, 10761), + (10763, -1, -1, 6761, 6761, 12, 86, -1, 0, 0, 17, 6087, 10764), + (10764, -1, -1, 6761, 6761, 12, 88, -1, 0, 0, 17, 10763, 10765), + (10766, -1, -1, 6765, 6765, 9, 85, -1, 0, 0, 17, 10060, 10767), + (10767, -1, -1, 6765, 6765, 9, 87, -1, 0, 0, 17, 10766, 10768), + (10768, -1, -1, 6765, 6765, 9, 89, -1, 0, 0, 17, 10767, 13553), + (10769, -1, -1, 6751, 6751, 9, 86, -1, 0, 0, 17, 6769, 10770), + (10770, -1, -1, 6751, 6751, 9, 88, -1, 0, 0, 17, 10769, 10771), + (10772, 872, 872, 872, 872, 9, 85, 23555, 5, 180, 17, 7369, 10773), + (10773, 872, 872, 872, 872, 9, 87, 23556, 5, 180, 17, 10772, 10774), + (10774, 872, 872, 872, 872, 9, 89, 23557, 5, 180, 17, 10773, -1), + (10775, 875, 875, 875, 875, 9, 85, 23561, 5, 180, 17, 7372, 10776), + (10776, 875, 875, 875, 875, 9, 87, 23562, 5, 180, 17, 10775, 10777), + (10777, 875, 875, 875, 875, 9, 89, 23563, 5, 180, 17, 10776, 13536), + (10778, -1, -1, 634, 634, 12, 85, -1, 0, 0, 17, 7714, 10779), + (10779, -1, -1, 634, 634, 12, 87, -1, 0, 0, 17, 10778, 10780), + (10780, -1, -1, 634, 634, 12, 89, -1, 0, 0, 17, 10779, 15585), + (10781, -1, -1, 8240, 8240, 9, 85, -1, 0, 0, 17, 8244, 10782), + (10782, -1, -1, 8240, 8240, 9, 86, -1, 0, 0, 17, 10781, 10783), + (10783, -1, -1, 8240, 8240, 9, 87, -1, 0, 0, 17, 10782, 10784), + (10784, -1, -1, 8240, 8240, 9, 88, -1, 0, 0, 17, 10783, 10785), + (10785, -1, -1, 8240, 8240, 9, 89, -1, 0, 0, 17, 10784, 13343), + (10786, 7800, 7800, 7800, 7800, 12, 85, 23567, 39, 4320, 17, 7817, 10787), + (10787, 7800, 7800, 7800, 7800, 12, 87, 23568, 39, 4320, 17, 10786, 13619), + (10788, -1, -1, 4699, 4699, 7, 65, -1, 0, 0, 17, 7500, -1), + (10789, 10789, 10789, 10789, 10789, 15, 90, 23575, 41, 6, 17, -1, 14261), + (10790, 10396, 10396, 10396, 10396, 15, 90, 23576, 14, 600, 17, 10396, 14024), + (10791, 10397, 10397, 10397, 10397, 15, 90, 23577, 14, 600, 17, 10397, 14025), + (10792, -1, -1, 10792, 10792, 5, 86, 0, 0, 0, 17, -1, 10793), + (10793, -1, -1, 10792, 10792, 7, 87, 0, 0, 0, 17, 10792, 10794), + (10794, -1, -1, 10792, 10792, 9, 88, 0, 0, 0, 17, 10793, 10795), + (10795, -1, -1, 10792, 10792, 11, 89, 0, 0, 0, 17, 10794, 10796), + (10796, -1, -1, 10792, 10792, 13, 90, 0, 0, 0, 17, 10795, 17365), + (10800, -1, -1, 10800, 10800, 6, 70, -1, 0, 0, 16, -1, 10801), + (10801, -1, -1, 10800, 10800, 9, 70, -1, 0, 0, 16, 10800, 10802), + (10802, -1, -1, 10800, 10800, 12, 70, -1, 0, 0, 16, 10801, 17476), + (10803, -1, -1, 10803, 10803, 6, 76, -1, 0, 0, 16, -1, 10804), + (10804, -1, -1, 10803, 10803, 6, 78, -1, 0, 0, 16, 10803, 10805), + (10805, -1, -1, 10803, 10803, 6, 80, -1, 0, 0, 16, 10804, -1), + (10806, 10806, 10806, 10806, 10806, 10, 80, 16846, 71, 540, 16, -1, 10807), + (10807, 10806, 10806, 10806, 10806, 11, 80, 16847, 71, 540, 16, 10806, 10808), + (10808, 10806, 10806, 10806, 10806, 12, 80, 16848, 71, 540, 16, 10807, 15298), + (10809, 10809, 10809, 10809, 10809, 10, 80, 16849, 71, 540, 16, -1, 10810), + (10810, 10809, 10809, 10809, 10809, 11, 80, 16850, 71, 540, 16, 10809, 10811), + (10811, 10809, 10809, 10809, 10809, 12, 80, 16851, 71, 540, 16, 10810, 15301), + (10815, 10815, 10815, 10815, 10815, 6, 80, -1, 0, 0, 16, -1, 10816), + (10816, 10815, 10815, 10815, 10815, 9, 80, -1, 0, 0, 16, 10815, 10817), + (10817, 10815, 10815, 10815, 10815, 12, 80, -1, 0, 0, 16, 10816, 13110), + (10818, 10818, 10818, 10818, 10818, 6, 80, -1, 0, 0, 16, -1, 10819), + (10819, 10818, 10818, 10818, 10818, 9, 80, -1, 0, 0, 16, 10818, 10820), + (10820, 10818, 10818, 10818, 10818, 12, 80, -1, 0, 0, 16, 10819, 13113), + (10821, 10821, 10821, 10821, 10821, 6, 80, -1, 0, 0, 16, -1, 10822), + (10822, 10821, 10821, 10821, 10821, 9, 80, -1, 0, 0, 16, 10821, 10823), + (10823, 10821, 10821, 10821, 10821, 12, 80, -1, 0, 0, 16, 10822, 13116), + (10824, 510, 510, 510, 510, 6, 86, 23578, 37, 240, 17, 10104, 10825), + (10850, -1, -1, 10850, 10850, 6, 85, 16864, 0, 0, 16, -1, 10851), + (10851, -1, -1, 10850, 10850, 6, 85, 16865, 0, 0, 16, 10850, 10852), + (10852, -1, -1, 10850, 10850, 6, 85, 16866, 0, 0, 16, 10851, 13207), + (10853, -1, -1, 10853, 10853, 3, 65, -1, 0, 0, 16, -1, 10854), + (10854, -1, -1, 10853, 10853, 6, 65, -1, 0, 0, 16, 10853, 10855), + (10855, -1, -1, 10853, 10853, 9, 65, -1, 0, 0, 16, 10854, 10856), + (10856, -1, -1, 10853, 10853, 5, 66, -1, 0, 0, 16, 10855, 10857), + (10857, -1, -1, 10853, 10853, 5, 68, -1, 0, 0, 16, 10856, 10858), + (10858, -1, -1, 10853, 10853, 5, 70, -1, 0, 0, 16, 10857, 10859), + (10859, -1, -1, 10853, 10853, 5, 76, -1, 0, 0, 16, 10858, 10860), + (10860, -1, -1, 10853, 10853, 5, 78, -1, 0, 0, 16, 10859, 10861), + (10861, -1, -1, 10853, 10853, 5, 80, -1, 0, 0, 16, 10860, 10862), + (10862, -1, -1, 10853, 10853, 5, 81, -1, 0, 0, 16, 10861, 10863), + (10863, -1, -1, 10853, 10853, 5, 83, -1, 0, 0, 16, 10862, 10864), + (10864, -1, -1, 10853, 10853, 5, 85, -1, 0, 0, 16, 10863, 15954), + (10865, -1, -1, 1304, 1304, 12, 85, -1, 0, 0, 16, 7150, 10866), + (10866, -1, -1, 1304, 1304, 12, 85, -1, 0, 0, 16, 10865, 10867), + (10867, -1, -1, 1304, 1304, 12, 85, -1, 0, 0, 16, 10866, 13218), + (10868, 5021, 5021, 5021, 5021, 9, 76, 16867, 7, 60, 16, 5021, 10869), + (10869, 5021, 5021, 5021, 5021, 9, 81, 16868, 7, 60, 16, 10868, 10870), + (10870, 5021, 5021, 5021, 5021, 9, 85, 16869, 7, 60, 16, 10869, 12618), + (10900, 10900, 10900, 10900, 10900, 9, 85, 16870, 55, 120, 16, -1, 10901), + (10901, 10900, 10900, 10900, 10900, 9, 85, 16871, 55, 120, 16, 10900, 10902), + (10902, 10900, 10900, 10900, 10900, 9, 85, 16872, 55, 120, 16, 10901, 13624), + (10903, -1, -1, 10903, 10903, 6, 81, -1, 0, 0, 16, -1, 10904), + (10904, -1, -1, 10903, 10903, 6, 83, -1, 0, 0, 16, 10903, 10905), + (10905, -1, -1, 10903, 10903, 6, 85, -1, 0, 0, 16, 10904, -1), + (10906, -1, -1, 895, 895, 12, 85, -1, 0, 0, 16, 7406, 10907), + (10907, -1, -1, 895, 895, 12, 85, -1, 0, 0, 16, 10906, 10908), + (10908, -1, -1, 895, 895, 12, 85, -1, 0, 0, 16, 10907, 13627), + (10909, -1, -1, 10909, 10909, 6, 85, -1, 0, 0, 16, -1, 10910), + (10910, -1, -1, 10909, 10909, 6, 85, -1, 0, 0, 16, 10909, 10911), + (10911, -1, -1, 10909, 10909, 6, 85, -1, 0, 0, 16, 10910, -1), + (10912, 10912, 10912, 10912, 10912, 6, 85, 16873, 69, 1800, 16, -1, 10913), + (10913, 10912, 10912, 10912, 10912, 6, 85, 16874, 69, 1800, 16, 10912, 10914), + (10914, 10912, 10912, 10912, 10912, 6, 85, 16875, 69, 1800, 16, 10913, 14053), + (10915, -1, -1, 10915, 10915, 9, 85, -1, 0, 0, 16, -1, 10916), + (10916, -1, -1, 10915, 10915, 9, 85, -1, 0, 0, 16, 10915, 10917), + (10917, -1, -1, 10915, 10915, 9, 85, -1, 0, 0, 16, 10916, 16189), + (10950, -1, -1, 10950, 10950, 6, 85, -1, 0, 0, 16, -1, -1), + (10951, -1, -1, 10951, 10951, 12, 85, -1, 0, 0, 16, -1, 10952), + (10952, -1, -1, 10951, 10951, 12, 85, -1, 0, 0, 16, 10951, 10953), + (10953, -1, -1, 10951, 10951, 12, 85, -1, 0, 0, 16, 10952, 15363), + (10954, -1, -1, 10954, 10954, 12, 85, -1, 0, 0, 16, -1, 10955), + (10955, -1, -1, 10954, 10954, 12, 85, -1, 0, 0, 16, 10954, 10956), + (10956, -1, -1, 10954, 10954, 12, 85, -1, 0, 0, 16, 10955, -1), + (10957, 10957, 10957, 10957, 10957, 6, 85, 16879, 61, 5, 16, -1, -1), + (10958, 10958, 10958, 10958, 10958, 12, 85, 16880, 62, 900, 16, -1, 13000), + (10959, 10959, 10959, 10959, 10959, 12, 85, 16881, 63, 600, 16, -1, 10961), + (10961, 10959, 10959, 10959, 10959, 12, 85, 21717, 63, 600, 16, 10959, 10962), + (10962, 10959, 10959, 10959, 10959, 12, 85, 21718, 63, 600, 16, 10961, 12988), + (11000, -1, -1, 11000, 11000, 6, 85, -1, 0, 0, 16, -1, 11001), + (11001, -1, -1, 11000, 11000, 9, 85, -1, 0, 0, 16, 11000, 11002), + (11002, -1, -1, 11000, 11000, 12, 85, -1, 0, 0, 16, 11001, -1), + (11003, -1, -1, 11003, 11003, 6, 85, -1, 0, 0, 16, -1, -1), + (11004, -1, -1, 11004, 11004, 6, 85, -1, 0, 0, 16, -1, 11005), + (11005, -1, -1, 11004, 11004, 6, 85, -1, 0, 0, 16, 11004, 11006), + (11006, -1, -1, 11004, 11004, 6, 85, -1, 0, 0, 16, 11005, -1), + (11011, -1, -1, 6302, 6302, 5, 85, 0, 0, 0, 16, 6304, 11012), + (11012, -1, -1, 6302, 6302, 5, 85, 0, 0, 0, 16, 11011, 11013), + (11013, -1, -1, 6302, 6302, 5, 85, 0, 0, 0, 16, 11012, 15552), + (11014, -1, -1, 11007, 11007, 5, 80, -1, 0, 0, 16, -1, 11015), + (11015, -1, -1, 11007, 11007, 7, 82, -1, 0, 0, 16, 11014, 11016), + (11016, -1, -1, 11007, 11007, 9, 85, -1, 0, 0, 16, 11015, 11020), + (11020, -1, -1, 11007, 11007, 12, 86, -1, 0, 0, 17, 11016, -1), + (11050, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, -1, 11051), + (11051, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, 11050, 11052), + (11052, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, 11051, 11059), + (11053, -1, -1, 6349, 6349, 6, 83, -1, 0, 0, 16, 7620, 11054), + (11054, -1, -1, 6349, 6349, 6, 83, -1, 0, 0, 16, 11053, -1), + (11055, 11055, 11055, 11055, 11055, 3, 85, 16884, 63, 20, 16, -1, -1), + (11056, 11056, 11056, 11056, 11056, 6, 85, 16885, 64, 180, 16, -1, -1), + (11057, 11057, 11057, 11057, 11057, 2, 85, 1422, 65, 10, 16, -1, -1), + (11058, 11058, 11058, 11058, 11058, 2, 85, 3243, 66, 10, 16, -1, -1), + (11059, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, 11052, 11060), + (11060, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, 11059, 12871), + (11061, -1, -1, 98, 98, 12, 85, -1, 0, 0, 16, 7586, 11062), + (11062, -1, -1, 98, 98, 12, 85, -1, 0, 0, 16, 11061, 11063), + (11063, -1, -1, 98, 98, 12, 85, -1, 0, 0, 16, 11062, 13921), + (11064, 6290, 6290, 6290, 6290, 7, 85, 23500, 0, 1, 16, 7225, 11065), + (11065, 6290, 6290, 6290, 6290, 9, 85, 23501, 0, 1, 16, 11064, 11066), + (11066, 6290, 6290, 6290, 6290, 12, 85, 23502, 0, 1, 16, 11065, 13229), + (11067, 4944, -1, 4944, 4944, 7, 85, 23506, 0, 1, 16, 7231, 11068), + (11068, 4944, -1, 4944, 4944, 9, 85, 23507, 0, 1, 16, 11067, 11069), + (11069, 4944, -1, 4944, 4944, 12, 85, 23508, 0, 1, 16, 11068, 13232), + (11070, 1478, -1, 1478, 1478, 9, 85, 23512, 0, 1, 16, 7244, 11071), + (11071, 1478, -1, 1478, 1478, 10, 85, 23513, 0, 1, 16, 11070, 11072), + (11072, 1478, -1, 1478, 1478, 12, 85, 23514, 0, 1, 16, 11071, 13235), + (11073, 11073, 11073, 11073, 11073, 12, 85, 23518, 53, 30, 16, -1, 13447), + (11074, -1, -1, 11074, 11074, 5, 81, 0, 0, 0, 16, -1, 11075), + (11075, -1, -1, 11074, 11074, 7, 83, 0, 0, 0, 16, 11074, 11076), + (11076, -1, -1, 11074, 11074, 9, 85, 0, 0, 0, 16, 11075, -1), + (11077, -1, -1, 11077, 11077, 5, 81, 0, 0, 0, 16, -1, 15895), + (11078, -1, -1, 11078, 11078, 5, 81, 0, 0, 0, 16, -1, 15891), + (11079, -1, -1, 11079, 11079, 5, 81, 0, 0, 0, 16, -1, 15893), + (11080, 11080, 11080, 11080, 11080, 7, 85, 23519, 10, 20, 16, -1, 13472), + (11081, 153, 153, 153, 153, 12, 85, 23599, 3, 2160, 16, 10193, 12996), + (11082, -1, -1, 1131, 1131, 6, 81, -1, 0, 0, 16, 1133, 11083), + (11083, -1, -1, 1131, 1131, 9, 83, -1, 0, 0, 16, 11082, 11084), + (11084, -1, -1, 1131, 1131, 12, 85, -1, 0, 0, 16, 11083, 13032), + (11085, -1, -1, 11085, 11085, 7, 85, 0, 0, 0, 16, -1, 11086), + (11086, -1, -1, 11085, 11085, 9, 85, 0, 0, 0, 16, 11085, 11087), + (11087, -1, -1, 11085, 11085, 12, 85, 0, 0, 0, 16, 11086, 13021), + (11088, -1, -1, 11088, 11088, 6, 75, 0, 0, 0, 16, -1, 11089), + (11089, -1, -1, 11088, 11088, 6, 75, 0, 0, 0, 16, 11088, 11090), + (11090, -1, -1, 11088, 11088, 6, 75, 0, 0, 0, 16, 11089, 11091), + (11091, -1, -1, 11088, 11088, 6, 75, 0, 0, 0, 16, 11090, -1), + (12396, -1, -1, 125, 125, 8, 85, -1, 0, 0, 16, 7505, 12397), + (12397, -1, -1, 125, 125, 9, 85, -1, 0, 0, 16, 12396, 12398), + (12398, -1, -1, 125, 125, 10, 85, -1, 0, 0, 16, 12397, 12399), + (12399, -1, -1, 125, 125, 11, 85, -1, 0, 0, 16, 12398, 12400), + (12400, -1, -1, 125, 125, 12, 85, -1, 0, 0, 16, 12399, 13080), + (12401, -1, -1, 122, 122, 8, 85, -1, 0, 0, 16, 7510, 12402), + (12402, -1, -1, 122, 122, 9, 85, -1, 0, 0, 16, 12401, 12403), + (12403, -1, -1, 122, 122, 10, 85, -1, 0, 0, 16, 12402, 12404), + (12404, -1, -1, 122, 122, 11, 85, -1, 0, 0, 16, 12403, 12405), + (12405, -1, -1, 122, 122, 12, 85, -1, 0, 0, 16, 12404, 13085), + (12406, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 7530, 12407), + (12407, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 12406, 12408), + (12408, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 12407, 12409), + (12409, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 12408, 12410), + (12410, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 12409, 12492), + (12411, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 8259, 12412), + (12412, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 12411, 12413), + (12413, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 12412, 12414), + (12414, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 12413, 12415), + (12415, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 12414, 13358), + (12416, -1, -1, 12416, 12416, 7, 83, -1, 0, 0, 16, -1, 12417), + (12417, -1, -1, 12416, 12416, 9, 84, -1, 0, 0, 16, 12416, 12418), + (12418, -1, -1, 12416, 12416, 12, 85, -1, 0, 0, 16, 12417, 13413), + (12419, -1, -1, 12419, 12419, 5, 83, -1, 0, 0, 16, -1, 12420), + (12420, -1, -1, 12419, 12419, 5, 84, -1, 0, 0, 16, 12419, 12421), + (12421, -1, -1, 12419, 12419, 5, 85, -1, 0, 0, 16, 12420, 12575), + (12422, 12422, 12422, 12422, 12422, 12, 85, 13994, 47, 12, 16, -1, -1), + (12423, -1, -1, 767, 767, 9, 81, -1, 0, 0, 16, 1101, 12424), + (12424, -1, -1, 767, 767, 10, 83, -1, 0, 0, 16, 12423, 12425), + (12425, -1, -1, 767, 767, 12, 85, -1, 0, 0, 16, 12424, -1), + (12426, -1, -1, 767, 767, 3, 81, -1, 0, 0, 16, 6245, 12427), + (12427, -1, -1, 767, 767, 6, 83, -1, 0, 0, 16, 12426, 12428), + (12428, -1, -1, 767, 767, 9, 85, -1, 0, 0, 16, 12427, -1), + (12432, -1, -1, 1107, 1107, 10, 81, -1, 0, 0, 16, 6405, 12433), + (12433, -1, -1, 1107, 1107, 11, 83, -1, 0, 0, 16, 12432, 12434), + (12434, -1, -1, 1107, 1107, 12, 85, -1, 0, 0, 16, 12433, 12556), + (12435, -1, -1, 637, 637, 8, 81, -1, 0, 0, 16, 5573, 12436), + (12436, -1, -1, 637, 637, 10, 83, -1, 0, 0, 16, 12435, 12437), + (12437, -1, -1, 637, 637, 12, 85, -1, 0, 0, 16, 12436, 12553), + (12438, -1, -1, 686, 686, 5, 85, -1, 0, 0, 16, 7640, -1), + (12439, -1, -1, 1592, 1592, 9, 85, -1, 0, 0, 16, 7572, 12440), + (12440, -1, -1, 1592, 1592, 10, 85, -1, 0, 0, 16, 12439, 12441), + (12441, -1, -1, 1592, 1592, 11, 85, -1, 0, 0, 16, 12440, 12442), + (12442, -1, -1, 1592, 1592, 12, 85, -1, 0, 0, 16, 12441, 12443), + (12443, -1, -1, 1592, 1592, 12, 85, -1, 0, 0, 16, 12442, 12532), + (12444, -1, -1, 1072, 1072, 8, 85, -1, 0, 0, 16, 7580, 12445), + (12445, -1, -1, 1072, 1072, 9, 85, -1, 0, 0, 16, 12444, 12446), + (12446, -1, -1, 1072, 1072, 10, 85, -1, 0, 0, 16, 12445, 12447), + (12447, -1, -1, 1072, 1072, 11, 85, -1, 0, 0, 16, 12446, 12448), + (12448, -1, -1, 1072, 1072, 12, 85, -1, 0, 0, 16, 12447, 12537), + (12449, -1, -1, 77, 77, 10, 81, -1, 0, 0, 16, 1085, 12450), + (12450, -1, -1, 77, 77, 11, 83, -1, 0, 0, 16, 12449, 12451), + (12451, -1, -1, 77, 77, 12, 85, -1, 0, 0, 16, 12450, 12497), + (12452, -1, -1, 80, 80, 12, 85, -1, 0, 0, 16, 7592, 12453), + (12453, -1, -1, 80, 80, 12, 85, -1, 0, 0, 16, 12452, 12454), + (12454, -1, -1, 80, 80, 12, 85, -1, 0, 0, 16, 12453, 12567), + (12455, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 7597, 12456), + (12456, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 12455, 12457), + (12457, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 12456, 12458), + (12458, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 12457, 12459), + (12459, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 12458, 12570), + (12460, 6537, 6537, 6537, 6537, 7, 83, 20172, 30, 900, 16, 7608, 12461), + (12461, 6537, 6537, 6537, 6537, 8, 83, 20173, 30, 900, 16, 12460, 12462), + (12462, 6537, 6537, 6537, 6537, 9, 83, 20174, 30, 900, 16, 12461, 12520), + (12463, -1, -1, 5263, 5263, 7, 81, -1, 0, 0, 16, 6129, 12464), + (12464, -1, -1, 5263, 5263, 8, 81, -1, 0, 0, 16, 12463, 12465), + (12465, -1, -1, 5263, 5263, 9, 81, -1, 0, 0, 16, 12464, 16173), + (12466, -1, -1, 5263, 5263, 7, 81, -1, 0, 0, 16, 5622, 12467), + (12467, -1, -1, 5263, 5263, 9, 81, -1, 0, 0, 16, 12466, 12468), + (12468, -1, -1, 5263, 5263, 12, 81, -1, 0, 0, 16, 12467, 15714), + (12469, -1, -1, 1287, 1287, 7, 81, -1, 0, 0, 16, 5518, 12470), + (12470, -1, -1, 1287, 1287, 9, 81, -1, 0, 0, 16, 12469, 12471), + (12471, -1, -1, 1287, 1287, 12, 81, -1, 0, 0, 16, 12470, 10637), + (12472, -1, -1, 1287, 1287, 8, 81, -1, 0, 0, 16, 6430, 12473), + (12473, -1, -1, 1287, 1287, 9, 81, -1, 0, 0, 16, 12472, 12474), + (12474, -1, -1, 1287, 1287, 10, 81, -1, 0, 0, 16, 12473, 13238), + (12475, -1, -1, 12430, 12430, 5, 85, 0, 0, 0, 16, -1, 12476), + (12476, -1, -1, 12430, 12430, 7, 85, 0, 0, 0, 16, 12475, 12477), + (12477, -1, -1, 12430, 12430, 9, 85, 0, 0, 0, 16, 12476, 12876), + (12478, -1, -1, 12478, 12478, 5, 85, 0, 0, 0, 16, -1, 12479), + (12479, -1, -1, 12478, 12478, 7, 85, 0, 0, 0, 16, 12478, 12480), + (12480, -1, -1, 12478, 12478, 9, 85, 0, 0, 0, 16, 12479, -1), + (12481, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 6473, 12482), + (12482, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 12481, 12508), + (12483, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 6475, 12484), + (12484, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 12483, 12511), + (12485, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 6477, 12486), + (12486, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 12485, 12514), + (12487, -1, -1, 6540, 6540, 8, 83, -1, 0, 0, 16, 6471, 12488), + (12488, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 12487, 12517), + (12492, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 17, 12410, 12493), + (12493, -1, -1, 6119, 6119, 6, 86, -1, 0, 0, 17, 12492, 12494), + (12494, -1, -1, 6119, 6119, 6, 87, -1, 0, 0, 17, 12493, 12495), + (12495, -1, -1, 6119, 6119, 6, 88, -1, 0, 0, 17, 12494, 12496), + (12496, -1, -1, 6119, 6119, 6, 89, -1, 0, 0, 17, 12495, 8448), + (12497, -1, -1, 77, 77, 12, 86, -1, 0, 0, 17, 12451, 12498), + (12498, -1, -1, 77, 77, 12, 88, -1, 0, 0, 17, 12497, 12499), + (12499, -1, -1, 77, 77, 12, 90, -1, 0, 0, 17, 12498, 13296), + (12500, -1, -1, 12500, 12500, 5, 81, -1, 0, 0, 16, -1, 12501), + (12501, -1, -1, 12500, 12500, 7, 81, -1, 0, 0, 16, 12500, 12502), + (12502, -1, -1, 12500, 12500, 9, 81, -1, 0, 0, 16, 12501, 12505), + (12505, -1, -1, 12500, 12500, 11, 83, -1, 0, 0, 16, 12502, 12506), + (12506, -1, -1, 12500, 12500, 12, 85, -1, 0, 0, 16, 12505, -1), + (12507, -1, -1, 199, 199, 12, 81, -1, 0, 0, 16, 201, -1), + (12508, -1, -1, 6540, 6540, 8, 86, -1, 0, 0, 17, 12482, 12509), + (12509, -1, -1, 6540, 6540, 8, 88, -1, 0, 0, 17, 12508, 12510), + (12510, -1, -1, 6540, 6540, 8, 90, -1, 0, 0, 17, 12509, 16440), + (12511, -1, -1, 6540, 6540, 8, 86, -1, 0, 0, 17, 12484, 12512), + (12512, -1, -1, 6540, 6540, 8, 88, -1, 0, 0, 17, 12511, 12513), + (12513, -1, -1, 6540, 6540, 8, 90, -1, 0, 0, 17, 12512, 12591), + (12514, -1, -1, 6540, 6540, 8, 86, -1, 0, 0, 17, 12486, 12515), + (12515, -1, -1, 6540, 6540, 8, 88, -1, 0, 0, 17, 12514, 12516), + (12516, -1, -1, 6540, 6540, 8, 90, -1, 0, 0, 17, 12515, 12594), + (12517, -1, -1, 6540, 6540, 8, 86, -1, 0, 0, 17, 12488, 12518), + (12518, -1, -1, 6540, 6540, 8, 88, -1, 0, 0, 17, 12517, 12519), + (12519, -1, -1, 6540, 6540, 8, 90, -1, 0, 0, 17, 12518, 12597), + (12520, 6537, 6537, 6537, 6537, 7, 86, 23974, 30, 900, 17, 12462, 12521), + (12521, 6537, 6537, 6537, 6537, 8, 88, 23975, 30, 900, 17, 12520, 12522), + (12522, 6537, 6537, 6537, 6537, 9, 90, 23976, 30, 900, 17, 12521, 13275), + (12523, -1, -1, 1210, 1210, 7, 86, -1, 0, 0, 17, 7234, 12524), + (12526, -1, -1, 1210, 1213, 12, 86, -1, 0, 0, 17, 8346, 12527), + (12527, -1, -1, 1210, 1213, 12, 88, -1, 0, 0, 17, 12526, 12528), + (12528, -1, -1, 1210, 1213, 12, 90, -1, 0, 0, 17, 12527, 14349), + (12529, -1, -1, 6636, 6636, 9, 86, -1, 0, 0, 17, 10043, 12530), + (12530, -1, -1, 6636, 6636, 10, 88, -1, 0, 0, 17, 12529, 12531), + (12531, -1, -1, 6636, 6636, 11, 90, -1, 0, 0, 17, 12530, 16164), + (12532, -1, -1, 1592, 1592, 9, 86, -1, 0, 0, 17, 12443, 12533), + (12533, -1, -1, 1592, 1592, 10, 87, -1, 0, 0, 17, 12532, 12534), + (12534, -1, -1, 1592, 1592, 11, 88, -1, 0, 0, 17, 12533, 12535), + (12535, -1, -1, 1592, 1592, 12, 89, -1, 0, 0, 17, 12534, 12536), + (12536, -1, -1, 1592, 1592, 12, 90, -1, 0, 0, 17, 12535, 13930), + (12537, -1, -1, 1072, 1072, 8, 86, -1, 0, 0, 17, 12448, 12538), + (12538, -1, -1, 1072, 1072, 9, 87, -1, 0, 0, 17, 12537, 12539), + (12539, -1, -1, 1072, 1072, 10, 88, -1, 0, 0, 17, 12538, 12540), + (12540, -1, -1, 1072, 1072, 11, 89, -1, 0, 0, 17, 12539, 12541), + (12541, -1, -1, 1072, 1072, 12, 90, -1, 0, 0, 17, 12540, 13281), + (12548, -1, -1, 119, 119, 12, 86, -1, 0, 0, 17, 6025, 12549), + (12549, -1, -1, 119, 119, 12, 87, -1, 0, 0, 17, 12548, 12550), + (12550, -1, -1, 119, 119, 12, 88, -1, 0, 0, 17, 12549, 12551), + (12551, -1, -1, 119, 119, 12, 89, -1, 0, 0, 17, 12550, 12552), + (12552, -1, -1, 119, 119, 12, 90, -1, 0, 0, 17, 12551, 13286), + (12553, -1, -1, 637, 637, 8, 86, -1, 0, 0, 17, 12437, 12554), + (12554, -1, -1, 637, 637, 10, 88, -1, 0, 0, 17, 12553, 12555), + (12555, -1, -1, 637, 637, 12, 90, -1, 0, 0, 17, 12554, 14361), + (12556, -1, -1, 1107, 1107, 10, 86, -1, 0, 0, 17, 12434, 12557), + (12557, -1, -1, 1107, 1107, 11, 88, -1, 0, 0, 17, 12556, 12558), + (12558, -1, -1, 1107, 1107, 12, 90, -1, 0, 0, 17, 12557, 16489), + (12559, -1, -1, 8215, 8215, 5, 86, -1, 0, 0, 17, 8219, 12560), + (12560, -1, -1, 8215, 8215, 5, 87, -1, 0, 0, 17, 12559, 12561), + (12561, -1, -1, 8215, 8215, 5, 88, -1, 0, 0, 17, 12560, 12562), + (12562, -1, -1, 8215, 8215, 5, 89, -1, 0, 0, 17, 12561, 12563), + (12563, -1, -1, 8215, 8215, 5, 90, -1, 0, 0, 17, 12562, 15694), + (12564, -1, -1, 1186, 1186, 12, 86, -1, 0, 0, 17, 7694, 12565), + (12565, -1, -1, 1186, 1186, 12, 88, -1, 0, 0, 17, 12564, 12566), + (12566, -1, -1, 1186, 1186, 12, 90, -1, 0, 0, 17, 12565, 13299), + (12567, -1, -1, 80, 80, 12, 86, -1, 0, 0, 17, 12454, 12568), + (12568, -1, -1, 80, 80, 12, 88, -1, 0, 0, 17, 12567, 12569), + (12569, -1, -1, 80, 80, 12, 90, -1, 0, 0, 17, 12568, 13302), + (12570, -1, -1, 658, 658, 5, 86, -1, 0, 0, 17, 12459, 12571), + (12571, -1, -1, 658, 658, 5, 87, -1, 0, 0, 17, 12570, 12572), + (12572, -1, -1, 658, 658, 5, 88, -1, 0, 0, 17, 12571, 12573), + (12573, -1, -1, 658, 658, 5, 89, -1, 0, 0, 17, 12572, 12574), + (12574, -1, -1, 658, 658, 5, 90, -1, 0, 0, 17, 12573, 13313), + (12575, -1, -1, 12419, 12419, 9, 90, -1, 0, 0, 17, 12421, 13520), + (12576, -1, -1, 852, 852, 12, 86, -1, 0, 0, 17, 7680, 12577), + (12577, -1, -1, 852, 852, 12, 88, -1, 0, 0, 17, 12576, 12578), + (12578, -1, -1, 852, 852, 12, 90, -1, 0, 0, 17, 12577, 13601), + (12579, -1, -1, 1313, 1313, 12, 86, -1, 0, 0, 17, 10083, 12580), + (12580, -1, -1, 1313, 1313, 12, 88, -1, 0, 0, 17, 12579, 12581), + (12581, -1, -1, 1313, 1313, 12, 90, -1, 0, 0, 17, 12580, 14043), + (12582, -1, -1, 12582, 12582, 7, 85, 0, 0, 0, 17, -1, 12583), + (12583, -1, -1, 12582, 12582, 9, 87, 0, 0, 0, 17, 12582, 12584), + (12584, -1, -1, 12582, 12582, 12, 89, 0, 0, 0, 17, 12583, 15174), + (12585, 6640, 6640, 6640, 6640, 9, 86, 23572, 43, 60, 17, 6640, -1), + (12586, 6644, 6644, 6644, 6644, 2, 86, 23573, 44, 20, 17, 6644, -1), + (12587, -1, -1, 7757, 7757, 9, 86, -1, 0, 0, 17, 7759, 12588), + (12588, -1, -1, 7757, 7757, 9, 88, -1, 0, 0, 17, 12587, 12589), + (12589, -1, -1, 7757, 7757, 9, 90, -1, 0, 0, 17, 12588, 15182), + (12590, 10395, 10395, 10395, 10395, 5, 85, 23574, 62, 5, 17, 10395, -1), + (12591, -1, -1, 6540, 6540, 15, 91, -1, 0, 0, 18, 12513, 12592), + (12594, -1, -1, 6540, 6540, 11, 91, -1, 0, 0, 18, 12516, 12595), + (12597, -1, -1, 6540, 6540, 9, 91, -1, 0, 0, 18, 12519, 12598), + (12598, -1, -1, 6540, 6540, 11, 93, -1, 0, 0, 18, 12597, 12599), + (12600, -1, -1, 12600, 12600, 7, 85, 0, 0, 0, 17, -1, 13072), + (12603, -1, -1, 12603, 12603, 10, 70, 0, 0, 0, 17, -1, -1), + (12606, -1, -1, 12606, 12606, 6, 85, 0, 0, 0, 17, -1, -1), + (12607, -1, -1, 12607, 12607, 6, 74, 0, 0, 0, 17, -1, 14140), + (12610, -1, -1, 255, 255, 9, 87, -1, 0, 0, 17, 7702, 13773), + (12612, -1, -1, 1604, 1604, 10, 85, -1, 0, 0, 17, 7009, 12613), + (12613, -1, -1, 1604, 1604, 12, 87, -1, 0, 0, 17, 12612, 13095), + (12615, -1, -1, 12615, 12615, 10, 85, 0, 0, 0, 17, -1, 12616), + (12616, -1, -1, 12615, 12615, 12, 87, 0, 0, 0, 17, 12615, 12617), + (12617, -1, -1, 12615, 12615, 14, 89, 0, 0, 0, 17, 12616, 14138), + (12618, 5021, 5021, 5021, 5021, 9, 86, 24009, 7, 60, 17, 10870, 12619), + (12619, 5021, 5021, 5021, 5021, 9, 87, 24010, 7, 60, 17, 12618, 12620), + (12620, 5021, 5021, 5021, 5021, 9, 88, 24011, 7, 60, 17, 12619, 12621), + (12621, 5021, 5021, 5021, 5021, 9, 89, 24012, 7, 60, 17, 12620, 13785), + (12626, 9354, 9354, 9354, 9354, 5, 86, 23996, 40, 600, 17, 9356, -1), + (12629, 9357, 9357, 9357, 9357, 5, 86, 24002, 40, 600, 17, 9359, -1), + (12632, 9360, 9360, 9360, 9360, 5, 86, 24005, 40, 600, 17, 9362, -1), + (12633, 6325, 6325, 6325, 6325, 7, 85, 24008, 18, 600, 17, 6361, 13792), + (12635, 12635, 12635, 12635, 12635, 12, 90, 23643, 12, 5, 17, -1, -1), + (12636, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, -1, 12637), + (12637, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 12636, 8445), + (12638, 12638, 12638, 12638, 12638, 9, 85, 23581, 68, 10, 17, -1, -1), + (12639, -1, -1, 10514, 10514, 6, 86, -1, 0, 0, 17, 10515, 12640), + (12642, -1, -1, 10511, 10511, 6, 86, -1, 0, 0, 17, 10513, 12643), + (12645, -1, -1, 12645, 12645, 9, 90, 0, 0, 0, 17, -1, 15386), + (12646, -1, -1, 12646, 12646, 9, 90, 0, 0, 0, 17, -1, 15388), + (12647, 10502, -1, 10502, 10502, 7, 90, 16815, 64, 120, 17, 10502, -1), + (12648, 10503, 10503, 10503, 10503, 9, 86, 23582, 13, 600, 17, 10505, 12649), + (12651, 12651, 12651, 12651, 12651, 15, 90, 23585, 69, 600, 17, -1, 17352), + (12652, -1, -1, 12652, 12652, 9, 86, 0, 0, 0, 17, -1, 12653), + (12653, -1, -1, 12652, 12652, 12, 88, 0, 0, 0, 17, 12652, 12654), + (12654, -1, -1, 12652, 12652, 15, 90, 0, 0, 0, 17, 12653, 13411), + (12655, 12655, 12655, 12655, 12655, 9, 86, 23586, 70, 1800, 17, -1, 12656), + (12658, 757, -1, 757, 757, 12, 86, 23589, 6, 1800, 17, 7413, 12659), + (12661, 12661, 12661, 12661, 12661, 9, 86, 23592, 73, 2700, 17, -1, 12662), + (12664, -1, -1, 12664, 12664, 7, 86, 0, 0, 0, 17, -1, 12665), + (12667, -1, -1, 820, 820, 5, 86, -1, 0, 0, 17, 10662, 12668), + (12668, -1, -1, 820, 820, 5, 88, -1, 0, 0, 17, 12667, 12669), + (12669, -1, -1, 820, 820, 5, 90, -1, 0, 0, 17, 12668, 13820), + (12670, -1, -1, 6020, 6020, 2, 86, -1, 0, 0, 17, 10665, 12671), + (12671, -1, -1, 6020, 6020, 2, 87, -1, 0, 0, 17, 12670, 12672), + (12672, -1, -1, 6020, 6020, 2, 88, -1, 0, 0, 17, 12671, 12692), + (12673, -1, -1, 1546, 1546, 5, 80, -1, 0, 0, 17, 6441, -1), + (12674, -1, -1, 4801, 4801, 6, 86, -1, 0, 0, 17, 10123, 12675), + (12675, -1, -1, 4801, 4801, 6, 88, -1, 0, 0, 17, 12674, 12676), + (12676, -1, -1, 4801, 4801, 6, 90, -1, 0, 0, 17, 12675, -1), + (12677, -1, -1, 230, 230, 6, 90, -1, 0, 0, 17, 541, 16249), + (12678, -1, -1, 10656, 10656, 12, 90, 0, 0, 0, 17, 10656, -1), + (12679, -1, -1, 10657, 10657, 7, 86, 0, 0, 0, 17, 10659, 12680), + (12680, -1, -1, 10657, 10657, 9, 88, 0, 0, 0, 17, 12679, 12681), + (12681, -1, -1, 10657, 10657, 12, 90, 0, 0, 0, 17, 12680, 14154), + (12682, 7872, 7872, 7872, 7872, 6, 86, 23595, 41, 600, 17, 10129, 12683), + (12683, 7872, 7872, 7872, 7872, 6, 88, 23596, 41, 600, 17, 12682, 12684), + (12684, 7872, 7872, 7872, 7872, 6, 90, 23597, 41, 600, 17, 12683, 13838), + (12685, -1, -1, 807, 807, 5, 86, -1, 0, 0, 17, 7630, 12686), + (12686, -1, -1, 807, 807, 5, 88, -1, 0, 0, 17, 12685, 12687), + (12687, -1, -1, 807, 807, 5, 90, -1, 0, 0, 17, 12686, -1), + (12688, -1, -1, 12688, 12688, 12, 90, 0, 0, 0, 17, -1, -1), + (12689, -1, -1, 7884, 7884, 12, 87, -1, 0, 0, 17, 7884, -1), + (12690, -1, -1, 7885, 7885, 12, 86, -1, 0, 0, 17, 7885, -1), + (12691, -1, -1, 12691, 12691, 12, 88, 0, 0, 0, 17, -1, -1), + (12692, -1, -1, 6020, 6020, 2, 89, -1, 0, 0, 17, 12672, 12693), + (12693, -1, -1, 6020, 6020, 2, 90, -1, 0, 0, 17, 12692, 13823), + (12694, -1, -1, 683, 683, 5, 86, -1, 0, 0, 17, 7605, 12695), + (12695, -1, -1, 683, 683, 5, 88, -1, 0, 0, 17, 12694, 12696), + (12696, -1, -1, 683, 683, 5, 90, -1, 0, 0, 17, 12695, 13305), + (12697, -1, -1, 1041, 1041, 12, 86, -1, 0, 0, 17, 7564, 12698), + (12698, -1, -1, 1041, 1041, 12, 88, -1, 0, 0, 17, 12697, 12699), + (12699, -1, -1, 1041, 1041, 12, 90, -1, 0, 0, 17, 12698, 13332), + (12700, 1355, 1355, 1355, 1355, 9, 86, 23644, 3, 60, 17, 10121, 12701), + (12701, 1355, 1355, 1355, 1355, 9, 88, 23645, 3, 60, 17, 12700, 12702), + (12702, 1355, 1355, 1355, 1355, 9, 90, 23646, 3, 60, 17, 12701, 13832), + (12703, -1, -1, 611, 611, 4, 86, -1, 0, 0, 17, 10126, 12704), + (12704, -1, -1, 611, 611, 4, 88, -1, 0, 0, 17, 12703, 12705), + (12705, -1, -1, 611, 611, 4, 90, -1, 0, 0, 17, 12704, 13835), + (12706, -1, -1, 12706, 12706, 7, 86, 0, 0, 0, 17, -1, 12707), + (12707, -1, -1, 12706, 12706, 9, 88, 0, 0, 0, 17, 12706, 12708), + (12708, -1, -1, 12706, 12706, 12, 90, 0, 0, 0, 17, 12707, 13813), + (12709, -1, -1, 12709, 12709, 9, 86, -1, 0, 0, 17, -1, -1), + (12710, -1, -1, 12710, 12710, 9, 86, 0, 0, 0, 17, -1, 12711), + (12711, -1, -1, 12710, 12710, 12, 88, 0, 0, 0, 17, 12710, 12712), + (12712, -1, -1, 12710, 12710, 15, 90, 0, 0, 0, 17, 12711, 14173), + (12713, -1, -1, 12713, 12713, 7, 86, 0, 0, 0, 17, -1, 12714), + (12714, -1, -1, 12713, 12713, 7, 88, 0, 0, 0, 17, 12713, 12715), + (12715, -1, -1, 12713, 12713, 7, 90, 0, 0, 0, 17, 12714, -1), + (12716, -1, -1, 12716, 12716, 7, 86, 0, 0, 0, 17, -1, 12717), + (12717, -1, -1, 12716, 12716, 7, 88, 0, 0, 0, 17, 12716, 12718), + (12718, -1, -1, 12716, 12716, 7, 90, 0, 0, 0, 17, 12717, 15526), + (12719, -1, -1, 12719, 12719, 9, 90, 0, 0, 0, 17, -1, -1), + (12720, -1, -1, 12720, 12720, 9, 86, 0, 0, 0, 17, -1, -1), + (12721, -1, -1, 12721, 12721, 7, 86, 0, 0, 0, 17, -1, 12722), + (12722, -1, -1, 12721, 12721, 9, 88, 0, 0, 0, 17, 12721, 12723), + (12723, -1, -1, 12721, 12721, 12, 90, 0, 0, 0, 17, 12722, 16303), + (12724, 10333, 10333, 10333, 10333, 9, 86, 23647, 55, 120, 17, 10335, 12725), + (12725, 10333, 10333, 10333, 10333, 9, 86, 23648, 55, 120, 17, 12724, 12726), + (12726, 10333, 10333, 10333, 10333, 9, 86, 23649, 55, 120, 17, 12725, 15988), + (12727, -1, -1, 1555, 1555, 7, 86, 0, 0, 0, 17, 1557, 12728), + (12728, -1, -1, 1555, 1555, 7, 88, 0, 0, 0, 17, 12727, 12729), + (12729, -1, -1, 1555, 1555, 7, 90, 0, 0, 0, 17, 12728, -1), + (12730, 10336, 10336, 10336, 10336, 9, 86, 23650, 58, 8, 17, 10338, 12731), + (12731, 10336, 10336, 10336, 10336, 12, 88, 23651, 58, 8, 17, 12730, 12732), + (12732, 10336, 10336, 10336, 10336, 15, 90, 23652, 58, 8, 17, 12731, 13517), + (12733, -1, -1, 10332, 10332, 7, 90, -1, 0, 0, 17, 10332, -1), + (12734, -1, -1, 6375, 6375, 9, 86, -1, 0, 0, 17, 10138, 12735), + (12735, -1, -1, 6375, 6375, 9, 88, -1, 0, 0, 17, 12734, 12736), + (12736, -1, -1, 6375, 6375, 9, 90, -1, 0, 0, 17, 12735, 13502), + (12737, -1, -1, 12737, 12737, 9, 86, 0, 0, 0, 17, -1, 12738), + (12738, -1, -1, 12737, 12737, 9, 88, 0, 0, 0, 17, 12737, 12739), + (12739, -1, -1, 12737, 12737, 9, 90, 0, 0, 0, 17, 12738, 15961), + (12740, 6533, 6533, 6533, 6533, 10, 86, 23653, 15, 600, 17, 10139, 12741), + (12741, 6533, 6533, 6533, 6533, 10, 88, 23654, 15, 600, 17, 12740, 12742), + (12742, 6533, 6533, 6533, 6533, 10, 90, 23655, 15, 600, 17, 12741, 13505), + (12743, 1116, 1116, 1116, 1116, 12, 86, 23656, 4, 2160, 17, 10142, 12744), + (12744, 1116, 1116, 1116, 1116, 12, 88, 23657, 4, 2160, 17, 12743, 12745), + (12745, 1116, 1116, 1116, 1116, 12, 90, 23658, 4, 2160, 17, 12744, 13530), + (12746, 5298, 5298, 5298, 5298, 12, 86, 23659, 32, 1800, 17, 10145, 12747), + (12747, 5298, 5298, 5298, 5298, 12, 88, 23660, 32, 1800, 17, 12746, 12748), + (12748, 5298, 5298, 5298, 5298, 12, 90, 23661, 32, 1800, 17, 12747, 13514), + (12749, 592, 592, 592, 592, 5, 86, 23665, 2, 18, 17, 7437, 12750), + (12750, 592, 592, 592, 592, 5, 88, 23666, 2, 18, 17, 12749, 12751), + (12751, 592, 592, 592, 592, 5, 90, 23667, 2, 18, 17, 12750, 13499), + (12754, 10701, 10701, 10701, 10701, 12, 86, 23668, 32, 360, 17, 10703, 12755), + (12755, 10701, 10701, 10701, 10701, 12, 88, 23669, 32, 360, 17, 12754, 12756), + (12756, 10701, 10701, 10701, 10701, 12, 90, 23670, 32, 360, 17, 12755, 15588), + (12757, -1, -1, 4861, 4861, 12, 86, -1, 0, 0, 17, 7682, 12758), + (12758, -1, -1, 4861, 4861, 12, 88, -1, 0, 0, 17, 12757, 12759), + (12759, -1, -1, 4861, 4861, 12, 90, -1, 0, 0, 17, 12758, -1), + (12760, 1274, 1274, 1274, 1274, 12, 86, 23674, 9, 540, 17, 10211, 12761), + (12761, 1274, 1274, 1274, 1274, 12, 88, 23675, 9, 540, 17, 12760, 12762), + (12762, 1274, 1274, 1274, 1274, 12, 90, 23676, 9, 540, 17, 12761, 14352), + (12766, 12766, 12766, 12766, 12766, 15, 90, 23677, 69, 3600, 17, -1, 13682), + (12767, -1, -1, 692, 692, 12, 86, -1, 0, 0, 17, 7672, 12768), + (12768, -1, -1, 692, 692, 12, 88, -1, 0, 0, 17, 12767, 12769), + (12769, -1, -1, 692, 692, 12, 90, -1, 0, 0, 17, 12768, 17295), + (12770, 12770, 12770, 12770, 12770, 9, 85, 23678, 52, 120, 17, -1, 12771), + (12771, 12770, 12770, 12770, 12770, 12, 87, 23679, 52, 120, 17, 12770, 12772), + (12772, 12770, 12770, 12770, 12770, 15, 89, 23680, 52, 120, 17, 12771, -1), + (12773, -1, -1, 12773, 12773, 7, 86, 0, 0, 0, 17, -1, 12774), + (12774, -1, -1, 12773, 12773, 7, 87, 0, 0, 0, 17, 12773, 12775), + (12775, -1, -1, 12773, 12773, 7, 88, 0, 0, 0, 17, 12774, 12776), + (12776, -1, -1, 12773, 12773, 7, 89, 0, 0, 0, 17, 12775, 12777), + (12777, -1, -1, 12773, 12773, 7, 90, 0, 0, 0, 17, 12776, -1), + (12778, 12778, 12778, 12778, 12778, 12, 90, 23681, 74, 1200, 17, -1, 13678), + (12779, -1, -1, 12779, 12779, 7, 85, 0, 0, 0, 17, -1, 12780), + (12780, -1, -1, 12779, 12779, 9, 87, 0, 0, 0, 17, 12779, 12781), + (12781, -1, -1, 12779, 12779, 12, 89, 0, 0, 0, 17, 12780, -1), + (12782, -1, -1, 12782, 12782, 7, 86, 0, 0, 0, 17, -1, 12783), + (12783, -1, -1, 12782, 12782, 9, 88, 0, 0, 0, 17, 12782, 12784), + (12784, -1, -1, 12782, 12782, 12, 90, 0, 0, 0, 17, 12783, -1), + (12785, 12785, 12785, 12785, 12785, 12, 90, 23683, 80, 30, 17, -1, 17131), + (12786, 6815, 6815, 6815, 6815, 8, 86, 23684, 60, 600, 17, 10202, 12787), + (12787, 6815, 6815, 6815, 6815, 8, 88, 23685, 60, 600, 17, 12786, 12788), + (12788, 6815, 6815, 6815, 6815, 8, 90, 23686, 60, 600, 17, 12787, 14355), + (12789, 967, 967, 967, 967, 7, 85, 23687, 10, 1800, 17, 10226, 12790), + (12790, 967, 967, 967, 967, 7, 87, 23688, 10, 1800, 17, 12789, 12791), + (12791, 967, 967, 967, 967, 7, 89, 23689, 10, 1800, 17, 12790, 17535), + (12792, -1, -1, 9503, 9503, 7, 86, -1, 0, 0, 17, 10089, 12793), + (12793, -1, -1, 9503, 9503, 7, 88, -1, 0, 0, 17, 12792, 12794), + (12794, -1, -1, 9503, 9503, 7, 90, -1, 0, 0, 17, 12793, 5360), + (12795, -1, -1, 6051, 6051, 5, 85, -1, 0, 0, 17, 10606, 12796), + (12796, -1, -1, 6051, 6051, 5, 87, -1, 0, 0, 17, 12795, 12797), + (12797, -1, -1, 6051, 6051, 5, 89, -1, 0, 0, 17, 12796, 13278), + (12798, -1, -1, 5264, 5264, 12, 86, -1, 0, 0, 17, 10217, 12799), + (12799, -1, -1, 5264, 5264, 12, 88, -1, 0, 0, 17, 12798, 12800), + (12800, -1, -1, 5264, 5264, 12, 90, -1, 0, 0, 17, 12799, 13675), + (12801, -1, -1, 6383, 6383, 9, 85, -1, 0, 0, 17, 10609, 12802), + (12802, -1, -1, 6383, 6383, 9, 87, -1, 0, 0, 17, 12801, 12803), + (12803, -1, -1, 6383, 6383, 9, 89, -1, 0, 0, 17, 12802, 5339), + (12804, 12804, 12804, 12804, 12804, 7, 86, 23693, 75, 900, 17, -1, 12805), + (12807, 12807, 12807, 12807, 12807, 7, 86, 23699, 73, 1200, 17, -1, 12808), + (12810, 8227, 8227, 8227, 12810, 5, 85, 27402, 71, 10, 17, 8227, 12811), + (12811, 8227, 8227, 8227, 12810, 7, 87, 27403, 71, 10, 17, 12810, 12812), + (12812, 8227, 8227, 8227, 12810, 9, 89, 27404, 71, 10, 17, 12811, -1), + (12813, -1, -1, 1287, 1287, 5, 75, -1, 0, 0, 17, -1, 12814), + (12814, -1, -1, 1287, 1287, 5, 77, -1, 0, 0, 17, 12813, 12815), + (12815, -1, -1, 1287, 1287, 5, 79, -1, 0, 0, 17, 12814, 14279), + (12816, -1, -1, 12816, 12816, 7, 86, 0, 0, 0, 17, -1, 12817), + (12819, -1, -1, 12819, 12819, 9, 85, 0, 0, 0, 17, -1, 12820), + (12820, -1, -1, 12819, 12819, 12, 87, 0, 0, 0, 17, 12819, 12821), + (12822, -1, -1, 12822, 12822, 9, 86, 0, 0, 0, 17, -1, 12823), + (12828, 291, 291, 291, 12828, 12, 86, 27409, 5, 900, 17, 10304, 12829), + (12831, -1, -1, 12831, 12831, 7, 86, 0, 0, 0, 17, -1, 12832), + (12834, -1, -1, 6980, 6980, 5, 85, -1, 0, 0, 17, 6982, 12835), + (12835, -1, -1, 6980, 6980, 5, 87, -1, 0, 0, 17, 12834, 12836), + (12837, 12837, 12837, 12837, 12837, 7, 86, 27412, 74, 420, 17, -1, 12838), + (12840, -1, -1, 6977, 6977, 5, 85, -1, 0, 0, 17, 6979, 12841), + (12841, -1, -1, 6977, 6977, 5, 87, -1, 0, 0, 17, 12840, 12842), + (12843, -1, -1, 551, 551, 5, 86, -1, 0, 0, 17, 6907, 12844), + (12846, -1, -1, 12846, 12846, 7, 86, 6499, 0, 0, 17, -1, 12847), + (12849, -1, -1, 12849, 12849, 7, 86, 0, 0, 0, 17, -1, 12850), + (12857, 8072, 8072, 8072, 8072, 7, 86, 27419, 37, 20, 17, 10248, 12858), + (12860, -1, -1, 267, 267, 12, 86, -1, 0, 0, 17, 5619, 12861), + (12863, -1, -1, 141, 12863, 12, 59, -1, 0, 0, 17, 143, 15396), + (12864, 12864, -1, 12864, 12864, 5, 59, 27422, 73, 10, 17, -1, 17486), + (12865, 12865, 12865, 12865, 12865, 12, 90, 27423, 42, 6, 17, -1, -1), + (12866, 12866, 12866, 12866, 12866, 12, 86, 27424, 74, 1800, 17, -1, 15605), + (12867, 12867, 12867, 12867, 12867, 12, 86, 27426, 13, 4320, 17, -1, -1), + (12868, 1334, 1334, 1334, 1334, 12, 86, 27427, 11, 4320, 17, 10236, 12869), + (12871, -1, -1, 11050, 11050, 9, 85, -1, 0, 0, 17, 11060, 12872), + (12872, -1, -1, 11050, 11050, 12, 87, -1, 0, 0, 17, 12871, 12873), + (12874, -1, -1, 1414, 1414, 5, 86, -1, 0, 0, 17, 1418, 17490), + (12875, 4938, 4938, 4938, 4938, 12, 90, 27430, 35, 1800, 17, 5614, 13727), + (12876, -1, -1, 12430, 12430, 7, 86, 0, 0, 0, 17, 12477, 12877), + (12877, -1, -1, 12430, 12430, 9, 88, 0, 0, 0, 17, 12876, 12878), + (12878, -1, -1, 12430, 12430, 12, 90, 0, 0, 0, 17, 12877, 15270), + (12879, 516, 516, 516, 516, 6, 86, 27431, 5, 480, 17, 10233, 13659), + (12880, 1404, 1404, 1404, 1404, 7, 85, 27432, 15, 2160, 17, 1408, -1), + (12881, -1, -1, 12881, 12881, 9, 86, 0, 0, 0, 17, -1, 12882), + (12885, 12885, 12885, 12885, 12885, 12, 86, 27435, 75, 90, 17, -1, 17491), + (12886, -1, -1, 12886, 12886, 2, 85, -1, 0, 0, 17, -1, -1), + (12887, -1, -1, 12887, 12887, 2, 87, -1, 0, 0, 17, -1, -1), + (12888, -1, -1, 12888, 12888, 2, 89, -1, 0, 0, 17, -1, -1), + (12889, -1, -1, 12889, 12889, 2, 85, -1, 0, 0, 17, -1, 12890), + (12890, -1, -1, 12889, 12889, 2, 87, -1, 0, 0, 17, 12889, 12891), + (12892, 12892, 12892, 12892, 12892, 3, 90, 27434, 8, 60, 17, -1, 13666), + (12893, 12893, 12893, 12893, 12893, 12, 90, 27436, 76, 1800, 17, -1, 13663), + (12894, -1, -1, 12894, 12894, 5, 86, 0, 0, 0, 17, -1, 12895), + (12899, -1, -1, 471, 471, 2, 85, -1, 0, 0, 17, 473, 12900), + (12900, -1, -1, 471, 471, 2, 87, -1, 0, 0, 17, 12899, 12901), + (12902, -1, -1, 12902, 12902, 5, 85, 0, 0, 0, 17, -1, 12903), + (12903, -1, -1, 12902, 12902, 5, 86, 0, 0, 0, 17, 12902, 12904), + (12907, -1, -1, 12907, 12907, 5, 85, 0, 0, 0, 17, -1, 12908), + (12908, -1, -1, 12907, 12907, 5, 86, 0, 0, 0, 17, 12907, 12909), + (12912, -1, -1, 12912, 12912, 5, 85, 0, 0, 0, 17, -1, 12913), + (12913, -1, -1, 12912, 12912, 5, 86, 0, 0, 0, 17, 12912, 12914), + (12917, 517, 517, 517, 517, 5, 85, 27437, 12, 600, 17, 10281, 12918), + (12918, 517, 517, 517, 517, 5, 87, 27438, 12, 600, 17, 12917, 12919), + (12920, -1, -1, 12920, 12920, 5, 86, 0, 0, 0, 17, -1, 12921), + (12923, 54009, 54009, 54009, 12923, 3, 85, 27440, 22, 12, 17, 5849, 12924), + (12924, 54009, 54009, 54009, 12923, 3, 87, 27441, 22, 12, 17, 12923, 12925), + (12929, -1, -1, 6548, 6548, 8, 85, -1, 0, 0, 17, 6238, 12930), + (12930, -1, -1, 6548, 6548, 8, 90, -1, 0, 0, 17, 12929, 15463), + (12931, 12931, 12931, 12931, 12931, 7, 86, 27443, 73, 3600, 17, -1, 12932), + (12934, 1242, 1242, 1242, 1242, 12, 86, 27446, 9, 1320, 17, 10273, 12935), + (12937, 12937, 12937, 12937, 12937, 12, 86, 27449, 16, 420, 17, -1, 13733), + (12938, 12938, 12938, 12938, 12938, 15, 88, 27450, 75, 2700, 17, -1, 13743), + (12939, 12939, 12939, 12939, 12939, 12, 90, 27451, 77, 1800, 17, -1, 14756), + (12941, 12941, 12941, 12941, 12941, 5, 85, 27453, 77, 1, 17, -1, -1), + (12942, 6539, 6539, 6539, 6539, 6, 86, 27454, 18, 1800, 17, 7611, 12943), + (12943, 6539, 6539, 6539, 6539, 6, 88, 27455, 18, 1800, 17, 12942, 12944), + (12944, 6539, 6539, 6539, 6539, 6, 90, 27456, 18, 1800, 17, 12943, 13291), + (12945, -1, -1, 795, 795, 12, 85, -1, 0, 0, 17, 10267, 12946), + (12946, -1, -1, 795, 795, 12, 86, -1, 0, 0, 17, 12945, 12947), + (12947, -1, -1, 795, 795, 12, 87, -1, 0, 0, 17, 12946, 12948), + (12948, -1, -1, 795, 795, 12, 88, -1, 0, 0, 17, 12947, 12949), + (12949, -1, -1, 795, 795, 12, 89, -1, 0, 0, 17, 12948, 13710), + (12950, -1, -1, 790, 790, 6, 86, -1, 0, 0, 17, 7274, 12951), + (12951, -1, -1, 790, 790, 6, 87, -1, 0, 0, 17, 12950, 12952), + (12952, -1, -1, 790, 790, 6, 88, -1, 0, 0, 17, 12951, 12953), + (12953, -1, -1, 790, 790, 6, 89, -1, 0, 0, 17, 12952, 12954), + (12954, -1, -1, 790, 790, 6, 90, -1, 0, 0, 17, 12953, 13713), + (12955, 167, 167, 167, 167, 10, 86, 27457, 14, 900, 17, 8343, 13718), + (12956, 4903, 4903, 4903, 4903, 9, 85, 27460, 9, 1320, 17, 10255, 13698), + (12957, 4909, 4909, 4909, 4909, 9, 85, 27461, 16, 1320, 17, 10257, 14733), + (12958, 4912, 4912, 4912, 4912, 9, 85, 27459, 16, 1320, 17, 10258, 13704), + (12959, 4906, 4906, 4906, 4906, 9, 85, 27458, 9, 1320, 17, 10256, 13701), + (12963, 12963, 12963, 12963, 12963, 7, 86, 27465, 81, 5, 17, -1, -1), + (12964, 12964, 12964, 12964, 12964, 7, 88, 27466, 81, 5, 17, -1, -1), + (12965, 12965, 12965, 12965, 12965, 7, 90, 27467, 81, 5, 17, -1, -1), + (12966, -1, -1, 6112, 6112, 5, 87, -1, 0, 0, 17, 6112, 12967), + (12967, -1, -1, 6112, 6112, 5, 89, -1, 0, 0, 17, 12966, 16402), + (12968, -1, -1, 12968, 12968, 7, 85, 0, 0, 0, 17, -1, 12969), + (12969, -1, -1, 12968, 12968, 7, 87, 0, 0, 0, 17, 12968, 12970), + (12970, -1, -1, 12968, 12968, 7, 89, 0, 0, 0, 17, 12969, 14238), + (12971, 12971, 12971, 12971, 12971, 5, 86, 27471, 79, 2160, 17, -1, 12972), + (12972, 12971, 12971, 12971, 12971, 7, 87, 27472, 79, 2160, 17, 12971, 12973), + (12973, 12971, 12971, 12971, 12971, 9, 88, 27473, 79, 2160, 17, 12972, 12974), + (12974, 12971, 12971, 12971, 12971, 12, 89, 27474, 79, 2160, 17, 12973, 12975), + (12975, 12971, 12971, 12971, 12971, 15, 90, 27475, 79, 2160, 17, 12974, -1), + (12976, 7903, 7903, 7903, 7903, 6, 85, 27476, 60, 30, 17, 7903, 14734), + (12977, -1, -1, 12977, 12977, 5, 85, 0, 0, 0, 17, -1, 12978), + (12978, -1, -1, 12977, 12977, 5, 86, 0, 0, 0, 17, 12977, 12979), + (12979, -1, -1, 12977, 12977, 5, 87, 0, 0, 0, 17, 12978, 12980), + (12980, -1, -1, 12977, 12977, 5, 88, 0, 0, 0, 17, 12979, 12981), + (12981, -1, -1, 12977, 12977, 5, 89, 0, 0, 0, 17, 12980, 17334), + (12982, 10600, 10600, 10600, 10600, 7, 86, 27477, 73, 20, 17, 10602, 12983), + (12983, 10600, 10600, 10600, 10600, 7, 88, 27478, 73, 20, 17, 12982, 12984), + (12984, 10600, 10600, 10600, 10600, 7, 90, 27479, 73, 20, 17, 12983, 13720), + (12985, 520, 520, 520, 520, 12, 86, 27480, 6, 540, 17, 10254, 12986), + (12986, 520, 520, 520, 520, 12, 88, 27481, 6, 540, 17, 12985, 12987), + (12987, 520, 520, 520, 520, 12, 90, 27482, 6, 540, 17, 12986, -1), + (12988, -1, -1, 10959, 12988, 12, 90, -1, 0, 0, 17, 10962, -1), + (12989, 12989, 12989, 12989, 12989, 7, 86, 27486, 73, 1800, 17, -1, 12990), + (12990, 12989, 12989, 12989, 12989, 9, 88, 27487, 73, 1800, 17, 12989, 12991), + (12991, 12989, 12989, 12989, 12989, 12, 90, 27488, 73, 1800, 17, 12990, 5336), + (12992, 12992, 12992, 12992, 12992, 9, 86, 27489, 0, 1, 17, -1, 12993), + (12993, 12992, 12992, 12992, 12992, 12, 88, 27490, 0, 1, 17, 12992, 12994), + (12994, 12992, 12992, 12992, 12992, 15, 90, 27491, 0, 1, 17, 12993, 5350), + (12995, 6563, 6563, 6563, 6563, 12, 86, 27492, 36, 8, 17, 6281, -1), + (12996, 153, 153, 153, 153, 12, 90, 27493, 3, 2160, 17, 11081, 17333), + (12997, 1520, 1520, 1520, 1520, 9, 85, 27494, 11, 900, 17, 10192, 12998), + (12998, 1520, 1520, 1520, 1520, 9, 87, 27495, 11, 900, 17, 12997, 12999), + (12999, 1520, 1520, 1520, 1520, 9, 89, 27496, 11, 900, 17, 12998, 5333), + (13000, 10958, 10958, 10958, 10958, 15, 90, 27497, 62, 900, 17, 10958, 16214), + (13001, -1, -1, 13001, 13001, 7, 86, -1, 0, 0, 17, -1, 13002), + (13002, -1, -1, 13001, 13001, 7, 88, -1, 0, 0, 17, 13001, 13003), + (13003, -1, -1, 13001, 13001, 7, 90, -1, 0, 0, 17, 13002, 15348), + (13004, 13004, 13004, 13004, 13004, 9, 86, 27499, 78, 300, 17, -1, 15855), + (13005, -1, -1, 6703, 6703, 3, 86, -1, 0, 0, 17, 10178, 13006), + (13006, -1, -1, 6703, 6703, 3, 88, -1, 0, 0, 17, 13005, 13007), + (13007, -1, -1, 6703, 6703, 3, 90, -1, 0, 0, 17, 13006, -1), + (13008, 13008, 13008, 13008, 13008, 9, 90, 27500, 86, 300, 17, -1, -1), + (13009, 13009, 13009, 13009, 13009, 6, 86, 27501, 39, 1, 17, -1, -1), + (13010, -1, -1, 13010, 13010, 6, 85, 0, 0, 0, 17, -1, 13011), + (13011, -1, -1, 13010, 13010, 6, 87, 0, 0, 0, 17, 13010, 13012), + (13012, -1, -1, 13010, 13010, 6, 89, 0, 0, 0, 17, 13011, 14223), + (13013, -1, -1, 13013, 13013, 6, 86, 0, 0, 0, 17, -1, 13014), + (13014, -1, -1, 13013, 13013, 6, 88, 0, 0, 0, 17, 13013, 13015), + (13015, -1, -1, 13013, 13013, 6, 90, 0, 0, 0, 17, 13014, -1), + (13016, 5109, 5109, 5109, 5109, 9, 86, 27502, 0, 1, 17, 7467, 5356), + (13017, -1, -1, 13017, 13017, 9, 86, -1, 0, 0, 17, -1, 13018), + (13018, -1, -1, 13017, 13017, 12, 88, -1, 0, 0, 17, 13017, 13019), + (13019, -1, -1, 13017, 13017, 15, 90, -1, 0, 0, 17, 13018, 13396), + (13020, 13020, 13020, 13020, 13020, 12, 86, 27503, 76, 420, 17, -1, -1), + (13021, -1, -1, 11085, 11085, 12, 86, 0, 0, 0, 17, 11087, 13022), + (13023, -1, -1, 1050, 1050, 12, 86, -1, 0, 0, 17, 7658, 13024), + (13026, -1, -1, 599, 599, 12, 86, -1, 0, 0, 17, 7561, 13027), + (13027, -1, -1, 599, 599, 12, 88, -1, 0, 0, 17, 13026, 13028), + (13028, -1, -1, 599, 599, 12, 90, -1, 0, 0, 17, 13027, 13438), + (13029, -1, -1, 7818, 7818, 9, 86, 31681, 0, 0, 17, 7818, 13030), + (13032, -1, -1, 1131, 1131, 9, 85, -1, 0, 0, 17, 11084, 13033), + (13033, -1, -1, 1131, 1131, 12, 87, -1, 0, 0, 17, 13032, 13034), + (13035, -1, -1, 1134, 1134, 3, 86, -1, 0, 0, 17, 10315, 13036), + (13040, -1, -1, 4809, 4809, 5, 86, -1, 0, 0, 17, 10318, 13041), + (13043, -1, -1, 5776, 5776, 9, 86, -1, 0, 0, 17, 7198, 13044), + (13046, -1, -1, 8250, 8250, 6, 85, -1, 0, 0, 17, 8254, 13047), + (13047, -1, -1, 8250, 8250, 6, 86, -1, 0, 0, 17, 13046, 13048), + (13048, -1, -1, 8250, 8250, 6, 87, -1, 0, 0, 17, 13047, 13049), + (13049, -1, -1, 8250, 8250, 6, 88, -1, 0, 0, 17, 13048, 13050), + (13050, -1, -1, 8250, 8250, 6, 89, -1, 0, 0, 17, 13049, 13348), + (13051, -1, -1, 10404, 10404, 6, 90, -1, 0, 0, 17, 10404, -1), + (13052, -1, -1, 10401, 10401, 6, 86, -1, 0, 0, 17, 10403, 13053), + (13055, -1, -1, 13055, 13055, 6, 86, 0, 0, 0, 17, -1, 13056), + (13058, 6931, 6931, 6931, 6931, 12, 90, 27504, 41, 600, 17, 10319, 13857), + (13059, 4854, 4854, 4854, 4854, 9, 86, 27505, 8, 600, 17, 10325, 13060), + (13062, 6932, 6932, 6932, 6932, 7, 86, 27508, 42, 1200, 17, 10322, 13063), + (13065, 13065, 13065, 13065, 13065, 12, 86, 27514, 70, 90, 17, -1, -1), + (13066, 13066, 13066, 13066, 13066, 9, 85, 27516, 71, 1800, 17, -1, -1), + (13067, -1, -1, 13067, 13067, 6, 86, 0, 0, 0, 17, -1, 13068), + (13072, -1, -1, 12600, 12600, 7, 87, 0, 0, 0, 17, 12600, 13073), + (13073, -1, -1, 12600, 12600, 7, 89, 0, 0, 0, 17, 13072, 13222), + (13074, -1, -1, 1044, 1044, 9, 86, -1, 0, 0, 17, 7652, 13075), + (13075, -1, -1, 1044, 1044, 12, 88, -1, 0, 0, 17, 13074, 13076), + (13076, -1, -1, 1044, 1044, 15, 90, -1, 0, 0, 17, 13075, 13326), + (13077, -1, -1, 1047, 1047, 9, 86, -1, 0, 0, 17, 7655, 13078), + (13078, -1, -1, 1047, 1047, 12, 88, -1, 0, 0, 17, 13077, 13079), + (13080, -1, -1, 125, 125, 9, 86, -1, 0, 0, 17, 12400, 13081), + (13081, -1, -1, 125, 125, 10, 87, -1, 0, 0, 17, 13080, 13082), + (13082, -1, -1, 125, 125, 11, 88, -1, 0, 0, 17, 13081, 13083), + (13083, -1, -1, 125, 125, 12, 89, -1, 0, 0, 17, 13082, 13084), + (13084, -1, -1, 125, 125, 13, 90, -1, 0, 0, 17, 13083, 8463), + (13085, -1, -1, 122, 122, 9, 86, -1, 0, 0, 17, 12405, 13086), + (13086, -1, -1, 122, 122, 10, 87, -1, 0, 0, 17, 13085, 13087), + (13087, -1, -1, 122, 122, 11, 88, -1, 0, 0, 17, 13086, 13088), + (13088, -1, -1, 122, 122, 12, 89, -1, 0, 0, 17, 13087, 13089), + (13089, -1, -1, 122, 122, 13, 90, -1, 0, 0, 17, 13088, 8440), + (13090, -1, -1, 1435, 4773, 9, 86, -1, 0, 0, 17, 7621, 13295), + (13091, -1, -1, 1435, 4773, 9, 86, -1, 0, 0, 17, 1650, 13294), + (13092, -1, -1, 644, 644, 9, 85, -1, 0, 0, 17, 7361, 13093), + (13093, -1, -1, 644, 644, 12, 87, -1, 0, 0, 17, 13092, 13094), + (13094, -1, -1, 644, 644, 15, 89, -1, 0, 0, 17, 13093, 13265), + (13095, -1, -1, 1604, 1604, 15, 89, -1, 0, 0, 17, 12613, 13767), + (13096, -1, -1, 13096, 13096, 12, 86, -1, 0, 0, 17, -1, 13097), + (13097, -1, -1, 13096, 13096, 12, 88, -1, 0, 0, 17, 13096, 13098), + (13098, -1, -1, 13096, 13096, 12, 90, -1, 0, 0, 17, 13097, 13127), + (13099, -1, -1, 83, 83, 9, 55, -1, 0, 0, 17, 85, -1), + (13100, 13100, 13100, 13100, 13100, 9, 86, 27534, 86, 300, 17, -1, 15140), + (13101, -1, -1, 13101, 13101, 7, 86, 0, 0, 0, 17, -1, 13102), + (13102, -1, -1, 13101, 13101, 9, 88, 0, 0, 0, 17, 13101, 13103), + (13103, -1, -1, 13101, 13101, 12, 90, 0, 0, 0, 17, 13102, 14082), + (13104, -1, -1, 589, 589, 9, 86, -1, 0, 0, 17, 7709, 13105), + (13105, -1, -1, 589, 589, 9, 88, -1, 0, 0, 17, 13104, 13106), + (13106, -1, -1, 589, 589, 9, 90, -1, 0, 0, 17, 13105, 15778), + (13107, 6645, 6645, 6645, 6645, 9, 90, 27541, 45, 60, 17, 6645, 13633), + (13108, 13108, 13108, 13108, 13108, 5, 90, 27542, 89, 30, 17, -1, -1), + (13109, 1351, 1351, 1351, 1351, 8, 90, 27543, 5, 30, 17, 7109, -1), + (13110, 10815, 10815, 10815, 10815, 9, 86, -1, 0, 0, 17, 10817, 13111), + (13111, 10815, 10815, 10815, 10815, 11, 88, -1, 0, 0, 17, 13110, 13112), + (13113, 10818, 10818, 10818, 10818, 9, 86, -1, 0, 0, 17, 10820, 13114), + (13114, 10818, 10818, 10818, 10818, 11, 88, -1, 0, 0, 17, 13113, 13115), + (13116, 10821, 10821, 10821, 10821, 9, 86, -1, 0, 0, 17, 10823, 13117), + (13117, 10821, 10821, 10821, 10821, 11, 88, -1, 0, 0, 17, 13116, 13118), + (13119, 5007, 5007, 5007, 5007, 9, 86, 27544, 8, 2160, 17, 10063, 13120), + (13120, 5007, 5007, 5007, 5007, 9, 88, 27545, 8, 2160, 17, 13119, 13121), + (13122, -1, -1, 6546, 6546, 0, 86, -1, 0, 0, 17, 7377, 13123), + (13123, -1, -1, 6546, 6546, 0, 87, -1, 0, 0, 17, 13122, 13124), + (13124, -1, -1, 6546, 6546, 0, 88, -1, 0, 0, 17, 13123, 13125), + (13127, -1, -1, 13096, 13096, 12, 91, -1, 0, 0, 18, 13098, 13128), + (13130, 13130, 13130, 13130, 13130, 15, 95, 32440, 48, 30, 18, -1, -1), + (13133, 7756, 7756, 7756, 7756, 12, 85, 21805, 85, 120, 17, -1, -1), + (13134, 13134, 13134, 13134, 13134, 7, 86, 27547, 74, 900, 17, -1, 13135), + (13135, 13134, 13134, 13134, 13134, 7, 88, 27548, 74, 900, 17, 13134, 13136), + (13136, 13134, 13134, 13134, 13134, 7, 90, 27549, 74, 900, 17, 13135, 13380), + (13140, -1, -1, 10464, 10464, 7, 86, -1, 0, 0, 17, 10466, 13141), + (13141, -1, -1, 10464, 10464, 9, 88, -1, 0, 0, 17, 13140, 13142), + (13142, -1, -1, 10464, 10464, 11, 90, -1, 0, 0, 17, 13141, -1), + (13143, -1, -1, 13143, 13143, 5, 86, 0, 0, 0, 17, -1, 13144), + (13144, -1, -1, 13143, 13143, 5, 88, 0, 0, 0, 17, 13143, 13145), + (13145, -1, -1, 13143, 13143, 5, 90, 0, 0, 0, 17, 13144, -1), + (13146, -1, -1, 13146, 13146, 5, 86, 0, 0, 0, 17, -1, 13147), + (13147, -1, -1, 13146, 13146, 5, 88, 0, 0, 0, 17, 13146, 13148), + (13148, -1, -1, 13146, 13146, 5, 90, 0, 0, 0, 17, 13147, -1), + (13149, -1, -1, 8210, 8210, 5, 86, -1, 0, 0, 17, 1655, 13150), + (13150, -1, -1, 8210, 8210, 5, 87, -1, 0, 0, 17, 13149, 13151), + (13151, -1, -1, 8210, 8210, 5, 88, -1, 0, 0, 17, 13150, 13152), + (13152, -1, -1, 8210, 8210, 5, 89, -1, 0, 0, 17, 13151, 13153), + (13153, -1, -1, 8210, 8210, 5, 90, -1, 0, 0, 17, 13152, 13318), + (13154, 5105, 5105, 5105, 5105, 12, 90, 27550, 11, 600, 17, 10509, 14023), + (13155, 7986, 7986, 7986, 7986, 12, 90, 27551, 11, 600, 17, 10510, 14022), + (13158, 548, 548, 548, 548, 10, 86, 27552, 5, 900, 17, 10098, 13159), + (13161, 528, 528, 528, 528, 12, 86, 27555, 5, 720, 17, 10196, 13162), + (13162, 528, 528, 528, 528, 12, 88, 27556, 5, 720, 17, 13161, 13163), + (13163, 528, 528, 528, 528, 12, 90, 27557, 5, 720, 17, 13162, 5357), + (13164, 13164, 13164, 13164, 13164, 9, 86, 27540, 99, 180, 17, -1, -1), + (13165, 13165, 13165, 13165, 13165, 9, 86, 27559, 56, 60, 17, -1, -1), + (13166, -1, -1, 13166, 13166, 7, 86, 0, 0, 0, 17, -1, 13167), + (13167, -1, -1, 13166, 13166, 7, 88, 0, 0, 0, 17, 13166, 13168), + (13168, -1, -1, 13166, 13166, 7, 90, 0, 0, 0, 17, 13167, -1), + (13169, 13169, 13169, 13169, 13169, 9, 90, 27560, 99, 180, 17, -1, 17221), + (13170, 6380, 6380, 6380, 6380, 6, 86, 27561, 39, 120, 17, 10310, 13171), + (13173, 290, 290, 290, 290, 8, 86, 27564, 4, 720, 17, 290, 13448), + (13174, 10374, 10374, 10374, 10374, 6, 85, 27565, 63, 900, 17, 10376, 13175), + (13175, 10374, 10374, 10374, 10374, 8, 87, 27566, 63, 900, 17, 13174, 13176), + (13177, 6984, 6984, 6984, 6984, 6, 83, 27568, 60, 60, 17, 10294, 13466), + (13178, 6986, 6986, 6986, 6986, 6, 83, 27570, 60, 60, 17, 10296, 13468), + (13179, 6985, 6985, 6985, 6985, 6, 83, 27569, 60, 60, 17, 10295, 13467), + (13180, 10377, 10377, 10377, 10377, 6, 86, 16796, 64, 60, 17, 10379, 13181), + (13183, 10346, 10346, 10346, 10346, 9, 90, 27574, 46, 600, 17, 10346, 13819), + (13184, -1, -1, 10340, 10340, 9, 86, -1, 0, 0, 17, 10342, 13185), + (13185, -1, -1, 10340, 10340, 9, 88, -1, 0, 0, 17, 13184, 13186), + (13186, -1, -1, 10340, 10340, 9, 90, -1, 0, 0, 17, 13185, 13829), + (13187, -1, -1, 9512, 9512, 7, 86, -1, 0, 0, 17, 7883, 13188), + (13188, -1, -1, 9512, 9512, 7, 88, -1, 0, 0, 17, 13187, 13189), + (13189, -1, -1, 9512, 9512, 7, 90, -1, 0, 0, 17, 13188, 13826), + (13190, 1110, 1110, 1110, 1110, 6, 86, 27576, 3, 2160, 17, 10152, 13191), + (13191, 1110, 1110, 1110, 1110, 6, 88, 27577, 3, 2160, 17, 13190, 13192), + (13192, 1110, 1110, 1110, 1110, 6, 90, 27578, 3, 2160, 17, 13191, 13496), + (13193, 1598, -1, 1598, 1598, 9, 86, 27582, 6, 900, 17, 10148, 13194), + (13194, 1598, -1, 1598, 1598, 11, 88, 27583, 6, 900, 17, 13193, 13195), + (13195, 1598, -1, 1598, 1598, 13, 90, 27584, 6, 900, 17, 13194, 13493), + (13196, -1, -1, 255, 255, 9, 86, -1, 0, 0, 17, 10135, 13197), + (13197, -1, -1, 255, 255, 9, 88, -1, 0, 0, 17, 13196, 13198), + (13198, -1, -1, 255, 255, 9, 90, -1, 0, 0, 17, 13197, 13511), + (13199, -1, -1, 8322, 8322, 9, 86, 0, 0, 0, 17, 8324, 13200), + (13200, -1, -1, 8322, 8322, 9, 88, 0, 0, 0, 17, 13199, 13201), + (13201, -1, -1, 8322, 8322, 9, 90, 0, 0, 0, 17, 13200, -1), + (13202, 13202, 13202, 13202, 13202, 2, 81, 27585, 98, 20, 17, -1, 14009), + (13203, 10330, 10330, 10330, 10330, 7, 90, 27586, 35, 30, 17, 10330, 13492), + (13204, -1, -1, 13204, 13204, 7, 86, -1, 0, 0, 17, -1, 13205), + (13205, -1, -1, 13204, 13204, 7, 88, -1, 0, 0, 17, 13204, 13206), + (13206, -1, -1, 13204, 13204, 7, 90, -1, 0, 0, 17, 13205, 14176), + (13207, -1, -1, 10850, 10850, 9, 86, 27587, 0, 0, 17, 10852, 13208), + (13208, -1, -1, 10850, 10850, 9, 88, 27588, 0, 0, 17, 13207, 13209), + (13209, -1, -1, 10850, 10850, 9, 90, 27589, 0, 0, 17, 13208, 13779), + (13210, -1, -1, 1307, 1307, 5, 81, -1, 0, 0, 17, 6662, 13211), + (13211, -1, -1, 1307, 1307, 5, 83, -1, 0, 0, 17, 13210, 13212), + (13212, -1, -1, 1307, 1307, 5, 85, -1, 0, 0, 17, 13211, -1), + (13213, -1, -1, 1543, 1543, 7, 86, -1, 0, 0, 17, 10167, 13214), + (13214, -1, -1, 1543, 1543, 7, 87, -1, 0, 0, 17, 13213, 13215), + (13215, -1, -1, 1543, 1543, 7, 88, -1, 0, 0, 17, 13214, 13216), + (13216, -1, -1, 1543, 1543, 7, 89, -1, 0, 0, 17, 13215, 13217), + (13217, -1, -1, 1543, 1543, 7, 90, -1, 0, 0, 17, 13216, 13782), + (13218, -1, -1, 1304, 1304, 12, 90, -1, 0, 0, 17, 10867, 13789), + (13219, -1, -1, 8325, 8325, 7, 85, 0, 0, 0, 17, 8327, 13220), + (13220, -1, -1, 8325, 8325, 9, 87, 0, 0, 0, 17, 13219, 13221), + (13221, -1, -1, 8325, 8325, 11, 89, 0, 0, 0, 17, 13220, 13798), + (13222, -1, -1, 12600, 12600, 7, 89, 0, 0, 0, 17, 13073, 13223), + (13223, -1, -1, 12600, 12600, 7, 89, 0, 0, 0, 17, 13222, -1), + (13224, 13224, -1, 13224, 13224, 3, 86, 27590, 98, 1, 17, -1, 15559), + (13225, 13225, 13225, 13225, 13225, 6, 86, 27592, 0, 4, 17, -1, 13688), + (13226, -1, -1, 5295, 5295, 6, 86, -1, 0, 0, 17, 10229, 13227), + (13229, 6290, 6290, 6290, 6290, 9, 86, 27596, 0, 1, 17, 11066, 13230), + (13232, 4944, -1, 4944, 4944, 9, 86, 27602, 0, 1, 17, 11069, 13233), + (13235, 1478, -1, 1478, 1478, 9, 86, 27608, 0, 1, 17, 11072, 13236), + (13238, -1, -1, 1287, 1287, 9, 86, -1, 0, 0, 17, 12474, 13239), + (13239, -1, -1, 1287, 1287, 10, 88, -1, 0, 0, 17, 13238, 13240), + (13240, -1, -1, 1287, 1287, 11, 90, -1, 0, 0, 17, 13239, 15719), + (13241, 4931, 4931, 4931, 4931, 7, 86, 27614, 4, 600, 17, 10430, 13242), + (13244, 1501, 1501, 1501, 1501, 6, 86, 27617, 10, 4320, 17, 1560, 13245), + (13247, 4894, 4894, 4894, 4894, 6, 86, 27620, 7, 2160, 17, 7290, 13248), + (13250, 10550, 10550, 10550, 10550, 7, 90, 27626, 61, 120, 17, 10550, 13728), + (13251, 1239, 1239, 1239, 1239, 9, 90, 27627, 6, 600, 17, 7275, 13732), + (13252, 13252, 13252, 13252, 13252, 9, 86, 27629, 95, 4, 17, -1, 16065), + (13253, 1126, 1126, 1126, 1126, 7, 85, 27630, 2, 2160, 17, 5515, 13254), + (13254, 1126, 1126, 1126, 1126, 7, 87, 27631, 2, 2160, 17, 13253, 13255), + (13255, 1126, 1126, 1126, 1126, 7, 89, 27632, 2, 2160, 17, 13254, 13723), + (13256, 146, 146, 146, 146, 8, 86, 27633, 2, 180, 17, 7691, 13257), + (13257, 146, 146, 146, 146, 8, 88, 27634, 2, 180, 17, 13256, 13258), + (13258, 146, 146, 146, 146, 8, 90, 27635, 2, 180, 17, 13257, 14222), + (13259, 1195, 1195, 1195, 1195, 9, 90, 27661, 13, 2160, 17, 10015, 15334), + (13260, 13260, 13260, 13260, 13260, 0, 80, 27664, 98, 3600, 17, -1, -1), + (13261, 13261, 13261, 13261, 13261, 0, 81, 27665, 98, 28800, 17, -1, -1), + (13262, -1, -1, 498, 498, 5, 70, -1, 0, 0, 16, 975, 13263), + (13263, -1, -1, 498, 498, 5, 75, -1, 0, 0, 16, 13262, 13264), + (13264, -1, -1, 498, 498, 5, 80, -1, 0, 0, 16, 13263, -1), + (13271, 13271, 13271, 13271, 13271, 0, 80, 27691, 97, 3600, 18, -1, -1), + (13272, 13272, 13272, 13272, 13272, 0, 81, 27692, 97, 28800, 18, -1, -1), + (13275, 6537, 6537, 6537, 6537, 10, 91, 30638, 30, 900, 18, 12522, 13276), + (13278, -1, -1, 6051, 6051, 10, 91, -1, 0, 0, 18, 12797, 13279), + (13281, -1, -1, 1072, 1072, 12, 91, -1, 0, 0, 18, 12541, 13282), + (13286, -1, -1, 119, 119, 12, 91, -1, 0, 0, 18, 12552, 13287), + (13291, 6539, 6539, 6539, 6539, 9, 91, 30641, 18, 1800, 18, 12944, 13292), + (13294, -1, -1, 1435, 4773, 12, 91, -1, 0, 0, 18, 13091, 14490), + (13295, -1, -1, 1435, 4773, 12, 91, -1, 0, 0, 18, 13090, 14491), + (13296, -1, -1, 77, 77, 12, 91, -1, 0, 0, 18, 12499, 13297), + (13297, -1, -1, 77, 77, 12, 93, -1, 0, 0, 18, 13296, 13298), + (13299, -1, -1, 1186, 1186, 12, 91, -1, 0, 0, 18, 12566, 13300), + (13302, -1, -1, 80, 80, 12, 91, -1, 0, 0, 18, 12569, 13303), + (13305, -1, -1, 683, 683, 10, 91, -1, 0, 0, 18, 12696, 13306), + (13308, -1, -1, 446, 735, 10, 91, -1, 0, 0, 18, 10477, 13309), + (13313, -1, -1, 658, 658, 8, 91, -1, 0, 0, 18, 12574, 13314), + (13318, -1, -1, 8210, 8210, 10, 91, -1, 0, 0, 18, 13153, 13319), + (13323, -1, -1, 1287, 1287, 12, 91, -1, 0, 0, 18, 10639, 13324), + (13326, -1, -1, 1044, 1044, 10, 91, -1, 0, 0, 18, 13076, 13327), + (13332, -1, -1, 1041, 1041, 11, 91, -1, 0, 0, 18, 12699, 13333), + (13338, -1, -1, 8245, 8245, 11, 91, -1, 0, 0, 18, 8426, 13339), + (13343, -1, -1, 8240, 8240, 11, 91, -1, 0, 0, 18, 10785, 13344), + (13348, -1, -1, 8250, 8250, 11, 91, -1, 0, 0, 18, 13050, 13349), + (13353, -1, -1, 8235, 8235, 11, 91, -1, 0, 0, 18, 8308, 13354), + (13358, -1, -1, 8255, 8255, 11, 91, -1, 0, 0, 18, 12415, 13359), + (13363, 1192, 1192, 1192, 1192, 9, 91, 30645, 12, 1320, 18, 10021, 13364), + (13383, 6488, 6488, 6488, 6488, 15, 91, 30657, 32, 900, 18, 6488, 13384), + (13385, 13385, 13385, 13385, 13385, 12, 91, 30659, 75, 600, 18, -1, 13386), + (13388, 13388, 13388, 13388, 13388, 12, 91, 30665, 79, 180, 18, -1, -1), + (13389, 13389, -1, 13389, 13389, 5, 91, 30666, 77, 12, 18, -1, 15832), + (13396, -1, -1, 13017, 13017, 15, 91, -1, 0, 0, 18, 13019, 13397), + (13401, 1498, 1498, 1498, 1498, 15, 91, 30679, 12, 1320, 18, 10092, 13402), + (13404, -1, -1, 1514, 1514, 11, 91, -1, 0, 0, 18, 1516, 13405), + (13410, 645, -1, 645, 645, 15, 95, 30682, 4, 5, 18, 10739, -1), + (13411, -1, -1, 12652, 12652, 15, 92, 0, 0, 0, 18, 12654, 13412), + (13413, -1, -1, 12416, 12416, 15, 91, -1, 0, 0, 18, 12418, 13414), + (13415, -1, -1, 7989, 7989, 9, 95, -1, 0, 0, 18, 7992, -1), + (13416, -1, -1, 13416, 13416, 9, 91, 0, 0, 0, 18, -1, 13417), + (13419, 13419, 13419, 13419, 13419, 12, 91, 30683, 99, 600, 18, -1, 13420), + (13425, 54006, 54006, 54006, 54006, 9, 91, 30692, 18, 180, 18, 10006, 13426), + (13438, -1, -1, 599, 599, 13, 91, -1, 0, 0, 18, 13028, 13439), + (13444, 13444, 13444, 13444, 13444, 9, 91, 30699, 75, 600, 18, -1, 13445), + (13447, 11073, 11073, 11073, 11073, 12, 95, 30705, 53, 30, 18, 11073, 15412), + (13449, -1, -1, 13449, 13449, 5, 91, -1, 0, 0, 18, -1, 13450), + (13454, 718, 718, 718, 718, 12, 91, 30711, 7, 4320, 18, 1019, 14855), + (13463, -1, -1, 13463, 13463, 7, 91, -1, 0, 0, 18, -1, 13464), + (13466, 6984, 6984, 6984, 6984, 9, 91, 30721, 60, 60, 18, 13177, 13469), + (13467, 6985, 6985, 6985, 6985, 9, 91, 30723, 60, 60, 18, 13179, 13470), + (13468, 6986, 6986, 6986, 6986, 12, 92, 30725, 60, 60, 18, 13178, 13471), + (13472, 11080, 11080, 11080, 11080, 11, 91, 30727, 10, 20, 18, 11080, 13473), + (13474, -1, -1, 13474, 13474, 9, 91, -1, 0, 0, 18, -1, 13475), + (13477, -1, -1, 10380, 10380, 11, 91, -1, 0, 0, 18, 10382, 13478), + (13483, 13483, 13483, 13483, 13483, 5, 91, 30735, 68, 20, 18, -1, -1), + (13484, 13484, -1, 13484, 13484, 12, 95, 30736, 76, 720, 18, -1, 15879), + (13485, -1, -1, 13485, 13485, 7, 91, -1, 0, 0, 18, -1, 13486), + (13490, 5020, 5020, 5020, 5020, 9, 91, 30742, 9, 300, 18, 10149, 13491), + (13492, 10330, 10330, 10330, 10330, 12, 95, 30744, 35, 30, 18, 13203, 14797), + (13493, 1598, -1, 1598, 1598, 11, 91, 30745, 6, 900, 18, 13195, 13494), + (13496, 1110, 1110, 1110, 1110, 9, 91, 30748, 3, 2160, 18, 13192, 13497), + (13499, 592, 592, 592, 592, 9, 91, 30754, 2, 18, 18, 12751, 13500), + (13502, -1, -1, 6375, 6375, 9, 91, -1, 0, 0, 18, 12736, 13503), + (13505, 6533, 6533, 6533, 6533, 11, 91, 30757, 15, 600, 18, 12742, 13506), + (13508, -1, -1, 8314, 8314, 9, 91, -1, 0, 0, 18, 8316, 13509), + (13511, -1, -1, 255, 255, 9, 91, -1, 0, 0, 18, 13198, 13512), + (13514, 5298, 5298, 5298, 5298, 12, 91, 30760, 32, 1800, 18, 12748, 13515), + (13517, 10336, 10336, 10336, 10336, 11, 91, 30766, 58, 8, 18, 12732, 13518), + (13520, -1, -1, 12419, 12419, 15, 95, -1, 0, 0, 18, 12575, 16886), + (13521, -1, -1, 6386, 6386, 9, 91, -1, 0, 0, 18, 6389, 13522), + (13524, 6534, 6534, 6534, 6534, 11, 91, 30769, 16, 900, 18, 7429, 13525), + (13527, 13527, 13527, 13527, 13527, 9, 91, 30772, 18, 9, 18, -1, 15964), + (13528, 13528, 13528, 13528, 13528, 10, 91, 30773, 42, 60, 18, -1, -1), + (13529, 13529, 13529, 13529, 13529, 15, 95, 30774, 41, 120, 18, -1, -1), + (13530, 1116, 1116, 1116, 1116, 12, 91, 30775, 4, 2160, 18, 12745, 13531), + (13533, -1, -1, 7010, 7010, 9, 91, -1, 0, 0, 18, 7015, 13534), + (13542, 6755, 6755, 6755, 6755, 12, 91, 30784, 42, 900, 18, 6757, 13543), + (13545, -1, -1, 10388, 10388, 12, 95, -1, 0, 0, 18, 10388, 15293), + (13546, 6758, 6758, 6758, 6758, 11, 91, 32360, 43, 900, 18, 10056, 13547), + (13549, 13549, 13549, 13549, 13549, 15, 95, 30788, 64, 180, 18, -1, -1), + (13556, 13556, 13556, 13556, 13556, 9, 91, 30792, 44, 600, 18, -1, 13557), + (13562, -1, -1, 10719, 10719, 15, 91, 0, 0, 0, 18, 10721, 13563), + (13565, -1, -1, 13565, 13565, 11, 91, 0, 0, 0, 18, -1, 13566), + (13568, -1, -1, 13568, 13568, 11, 91, 0, 0, 0, 18, -1, 13569), + (13571, 13571, 13571, 13571, 13571, 12, 91, 30795, 50, 60, 18, -1, -1), + (13575, 5095, 5095, 5095, 5095, 11, 91, 30796, 10, 900, 18, 10642, 13576), + (13578, 0, 0, 10348, 10348, 9, 91, -1, 0, 0, 18, 10350, 13579), + (13584, 10394, 10394, 10394, 10394, 15, 91, 30799, 30, 300, 18, 10704, 14981), + (13585, 7712, 7712, 7712, 7712, 15, 95, 30800, 2, 30, 18, 10646, 15095), + (13586, 188, 188, 188, 188, 12, 91, 30801, 2, 30, 18, 10647, 13587), + (13589, -1, -1, 255, 255, 13, 91, -1, 0, 0, 18, 10625, 13590), + (13590, -1, -1, 255, 255, 15, 93, -1, 0, 0, 18, 13589, 13591), + (13592, 5984, 5984, 5984, 5984, 12, 91, 30803, 2, 30, 18, 10626, 13593), + (13595, 534, 534, 534, 534, 12, 91, 30806, 4, 2160, 18, 10710, 13596), + (13598, -1, -1, 6791, 6791, 11, 91, -1, 0, 0, 18, 10678, 13599), + (13601, -1, -1, 852, 852, 11, 91, -1, 0, 0, 18, 12578, 13602), + (13604, 7850, 7850, 7850, 7850, 15, 91, 30812, 39, 4320, 18, 10620, 13605), + (13607, -1, -1, 10453, 10453, 11, 91, -1, 0, 0, 18, 10455, 13608), + (13610, -1, -1, 602, 602, 12, 91, -1, 0, 0, 18, 10687, 13611), + (13613, -1, -1, 855, 855, 11, 91, -1, 0, 0, 18, 10692, 13614), + (13616, -1, -1, 13616, 13616, 7, 91, -1, 0, 0, 18, -1, 13617), + (13617, -1, -1, 13616, 13616, 9, 93, -1, 0, 0, 18, 13616, 13618), + (13618, -1, -1, 13616, 13616, 12, 95, -1, 0, 0, 18, 13617, 14786), + (13619, 7800, 7800, 7800, 7800, 15, 91, 30815, 39, 4320, 18, 10787, 13620), + (13621, -1, -1, 6630, 6630, 9, 91, -1, 0, 0, 18, 10074, 13622), + (13624, 10900, 10900, 10900, 10900, 9, 91, 30817, 55, 120, 18, 10902, 13625), + (13627, -1, -1, 895, 895, 9, 91, -1, 0, 0, 18, 10908, 13628), + (13628, -1, -1, 895, 895, 12, 93, -1, 0, 0, 18, 13627, 13629), + (13630, -1, -1, 9506, 9506, 11, 91, -1, 0, 0, 18, 9508, 13631), + (13633, 6645, 6645, 6645, 6645, 15, 95, 30820, 45, 60, 18, 13107, 15178), + (13646, 13646, 13646, 13646, 13646, 15, 91, 30837, 45, 600, 18, -1, -1), + (13650, 8060, 8060, 8060, 8060, 9, 91, 31524, 41, 1800, 18, 10239, 13651), + (13653, 8063, 8063, 8063, 8063, 9, 91, 31527, 41, 1800, 18, 10242, 13654), + (13656, 8066, 8066, 8066, 8066, 11, 91, 31530, 41, 1800, 18, 10245, 13657), + (13663, 12893, 12893, 12893, 12893, 15, 91, 31534, 76, 1800, 18, 12893, 13664), + (13667, -1, -1, 13667, 13667, 11, 91, -1, 0, 0, 18, -1, 13668), + (13670, 13670, 13670, 13670, 13670, 12, 91, 31538, 43, 1800, 18, -1, 13671), + (13673, 13673, 13673, 13673, 13673, 18, 95, 32050, 0, 1, 18, -1, -1), + (13674, 13674, 13674, 13674, 13674, 18, 95, 32058, 0, 1, 18, -1, -1), + (13675, -1, -1, 5264, 5264, 12, 91, -1, 0, 0, 18, 12800, 13676), + (13678, 13678, 13678, 13678, 13678, 15, 95, 31543, 74, 1200, 18, 12778, -1), + (13682, 12766, 12766, 12766, 12766, 18, 95, 31545, 69, 3600, 18, 12766, -1), + (13683, 6822, 6822, 6822, 6822, 15, 91, 31546, 42, 120, 18, 6822, 14780), + (13684, -1, -1, 13684, 13684, 9, 91, -1, 0, 0, 18, -1, 13685), + (13685, -1, -1, 13684, 13684, 12, 93, -1, 0, 0, 18, 13684, 13686), + (13686, -1, -1, 13684, 13684, 15, 95, -1, 0, 0, 18, 13685, 16653), + (13687, 13687, 13687, 13687, 13687, 15, 91, 31547, 75, 300, 18, -1, 17521), + (13688, 13225, 13225, 13225, 13225, 12, 91, 31548, 0, 4, 18, 13225, 15620), + (13689, -1, -1, 13689, 13689, 9, 91, -1, 0, 0, 18, -1, 13690), + (13692, 12208, 12208, 12208, 12208, 6, 91, 31549, 17, 12, 18, -1, -1), + (13693, 13693, 13693, 13693, 13693, 18, 95, 31550, 76, 500, 18, -1, 17531), + (13695, 13695, 13695, 13695, 13695, 12, 91, 31577, 91, 1320, 18, -1, 13696), + (13698, 4903, 4903, 4903, 4903, 12, 91, 31580, 9, 1320, 18, 12956, 13699), + (13701, 4906, 4906, 4906, 4906, 12, 91, 31583, 9, 1320, 18, 12959, 13702), + (13704, 4912, 4912, 4912, 4912, 12, 91, 31586, 16, 1320, 18, 12958, 13705), + (13707, -1, -1, 1577, 1577, 12, 91, -1, 0, 0, 18, 10264, 13708), + (13710, -1, -1, 795, 795, 9, 91, -1, 0, 0, 18, 12949, 13711), + (13713, -1, -1, 790, 790, 6, 91, -1, 0, 0, 18, 12954, 13714), + (13718, 167, 167, 167, 167, 12, 91, 31589, 14, 900, 18, 12955, 13719), + (13720, 10600, 10600, 10600, 10600, 11, 91, 31591, 73, 20, 18, 12984, 13721), + (13723, 1126, 1126, 1126, 1126, 11, 91, 31594, 2, 2160, 18, 13255, 13724), + (13726, 1017, 1017, 1017, 1017, 12, 91, 31597, 75, 15, 18, 1017, -1), + (13727, 4938, 4938, 4938, 4938, 12, 95, 31598, 35, 1800, 18, 12875, 16031), + (13734, 773, -1, 773, 773, 9, 91, 31606, 5, 1800, 18, 10566, 13735), + (13753, -1, -1, 13753, 13753, 5, 91, -1, 0, 0, 18, -1, 13754), + (13758, -1, -1, 13758, 13758, 5, 91, -1, 0, 0, 18, -1, 13759), + (13763, -1, -1, 781, 781, 12, 95, -1, 0, 0, 18, 7284, -1), + (13764, -1, -1, 13764, 13764, 9, 91, -1, 0, 0, 18, -1, 13765), + (13767, -1, -1, 1604, 1604, 12, 91, -1, 0, 0, 18, 13095, 13768), + (13770, 6328, 6328, 6328, 6328, 9, 91, 31628, 10, 600, 18, 10170, 13771), + (13771, 6328, 6328, 6328, 6328, 12, 93, 31629, 10, 600, 18, 13770, 13772), + (13773, -1, -1, 255, 255, 11, 91, -1, 0, 0, 18, 12610, 13774), + (13774, -1, -1, 255, 255, 13, 92, -1, 0, 0, 18, 13773, 13775), + (13775, -1, -1, 255, 255, 15, 93, -1, 0, 0, 18, 13774, 14126), + (13779, -1, -1, 10850, 10850, 12, 91, 31637, 0, 0, 18, 13209, 13780), + (13782, -1, -1, 1543, 1543, 9, 91, -1, 0, 0, 18, 13217, 13783), + (13785, 5021, 5021, 5021, 5021, 11, 91, 31640, 7, 60, 18, 12621, 13786), + (13788, 13788, 13788, 13788, 13788, 25, 51, 31643, 31, 2, 3, -1, -1), + (13789, -1, -1, 1304, 1304, 11, 91, -1, 0, 0, 18, 13218, 13790), + (13790, -1, -1, 1304, 1304, 13, 93, -1, 0, 0, 18, 13789, 13791), + (13792, 13792, 13792, 13792, 13792, 9, 91, 31644, 18, 600, 18, 12633, 13793), + (13795, -1, -1, 846, 846, 12, 91, -1, 0, 0, 18, 10175, 13796), + (13798, -1, -1, 8325, 8325, 9, 91, -1, 0, 0, 18, 13221, 13799), + (13804, -1, -1, 10650, 10650, 9, 91, -1, 0, 0, 18, 10652, 13805), + (13807, 1352, 1352, 1352, 1352, 9, 91, 31647, 3, 60, 18, 10115, 13808), + (13810, 1358, 1358, 1358, 1358, 9, 91, 31650, 3, 60, 18, 10118, 13811), + (13813, -1, -1, 12706, 12706, 12, 91, 0, 0, 0, 18, 12708, 13814), + (13816, 7875, 7875, 7875, 7875, 9, 91, 31653, 42, 600, 18, 7880, 13817), + (13819, 10346, 10346, 10346, 10346, 12, 95, 31659, 46, 600, 18, 13183, 16924), + (13820, -1, -1, 820, 820, 9, 91, -1, 0, 0, 18, 12669, 13821), + (13823, -1, -1, 6020, 6020, 9, 91, -1, 0, 0, 18, 12693, 13824), + (13826, -1, -1, 9512, 9512, 9, 91, -1, 0, 0, 18, 13189, 13827), + (13829, -1, -1, 10340, 10340, 12, 91, -1, 0, 0, 18, 13186, 13830), + (13832, 1355, 1355, 1355, 1355, 11, 91, 31661, 3, 60, 18, 12702, 13833), + (13835, -1, -1, 611, 611, 9, 91, -1, 0, 0, 18, 12705, 13836), + (13838, 7872, 7872, 7872, 7872, 9, 91, 31664, 41, 600, 18, 12684, 13839), + (13841, -1, -1, 10343, 10343, 9, 91, 0, 0, 0, 18, 10345, 13842), + (13845, 1178, 1178, 1178, 1178, 9, 91, 31669, 4, 900, 18, 10328, 13846), + (13872, 13872, 13872, 13872, 13872, 15, 95, 31694, 63, 60, 18, -1, 16002), + (13873, -1, -1, 13873, 13873, 7, 91, 0, 0, 0, 18, -1, 13874), + (13878, -1, -1, 13878, 13878, 9, 91, 0, 0, 0, 18, -1, 13879), + (13881, -1, -1, 13881, 13881, 9, 91, 0, 0, 0, 18, -1, 13882), + (13884, -1, -1, 735, 735, 10, 91, -1, 0, 0, 18, 10636, 13885), + (13889, -1, -1, 13889, 13889, 5, 91, 0, 0, 0, 18, -1, 13890), + (13894, -1, -1, 1021, 1021, 6, 91, -1, 0, 0, 18, 7685, 13895), + (13899, 6750, 6750, 6750, 6750, 15, 95, 32100, 60, 120, 18, 6750, 15294), + (13905, -1, -1, 13905, 13905, 10, 91, -1, 0, 0, 18, -1, 13906), + (13908, -1, -1, 13908, 13908, 10, 91, -1, 0, 0, 18, -1, 13909), + (13911, -1, -1, 13911, 13911, 12, 91, -1, 0, 0, 18, -1, 13912), + (13914, 4849, 4849, 4849, 4849, 12, 91, 32103, 7, 1800, 18, 7110, 13915), + (13917, -1, -1, 13917, 13917, 9, 91, -1, 0, 0, 18, -1, 13918), + (13920, 6333, 6333, 6333, 6333, 15, 91, 32140, 3, 600, 18, 7266, 16032), + (13921, -1, -1, 98, 98, 12, 91, -1, 0, 0, 18, 11063, 13922), + (13924, -1, -1, 98, 738, 12, 91, -1, 0, 0, 18, 7600, 13925), + (13927, -1, -1, 10370, 10370, 10, 91, -1, 0, 0, 18, 10372, 13928), + (13930, -1, -1, 1592, 1592, 12, 91, -1, 0, 0, 18, 12536, 13931), + (13933, -1, -1, 8263, 8263, 5, 91, -1, 0, 0, 18, 8360, 13934), + (13943, -1, -1, 8268, 8268, 5, 91, -1, 0, 0, 18, 8370, 13944), + (13953, -1, -1, 8273, 8273, 5, 91, -1, 0, 0, 18, 8380, 13954), + (13963, -1, -1, 8278, 8278, 5, 91, -1, 0, 0, 18, 8390, 13964), + (13973, -1, -1, 8283, 8283, 5, 91, -1, 0, 0, 18, 8400, 13974), + (13983, -1, -1, 8288, 8288, 5, 91, -1, 0, 0, 18, 8410, 13984), + (13993, -1, -1, 8293, 8293, 5, 91, -1, 0, 0, 18, 8420, 13994), + (14003, 6492, 6492, 6492, 6492, 12, 91, 32151, 52, 720, 18, 10681, 14004), + (14006, 10711, 10711, 10711, 10711, 15, 91, 32157, 75, 1200, 18, 10713, 14007), + (14009, 13202, 13202, 13202, 13202, 6, 91, 32160, 98, 20, 18, 13202, -1), + (14010, 14010, 14010, 14010, 14010, 15, 95, 32161, 97, 20, 18, -1, -1), + (14011, -1, -1, 14011, 14011, 5, 91, -1, 0, 0, 18, -1, 14012), + (14016, 10354, 10354, 10354, 10354, 15, 95, 32162, 39, 4320, 18, 10354, 14647), + (14017, -1, -1, 14017, 14017, 0, 90, -1, 0, 0, 18, -1, -1), + (14018, -1, -1, 14018, 14018, 0, 91, -1, 0, 0, 18, -1, -1), + (14019, 14019, 14019, 14019, 14019, 12, 91, 32177, 14, 900, 18, -1, 14020), + (14026, -1, -1, 14026, 14026, 12, 91, -1, 0, 0, 18, -1, 14027), + (14029, -1, -1, 14029, 14029, 12, 91, -1, 0, 0, 18, -1, 14030), + (14032, -1, -1, 14032, 14032, 15, 95, -1, 0, 0, 18, -1, -1), + (14037, -1, -1, 14037, 14037, 9, 91, 0, 0, 0, 18, -1, 14038), + (14040, -1, -1, 14040, 14040, 9, 91, 0, 0, 0, 18, -1, 14041), + (14043, -1, -1, 1313, 1313, 12, 91, -1, 0, 0, 18, 12581, 14044), + (14046, -1, -1, 14046, 14046, 5, 91, -1, 0, 0, 18, -1, 14047), + (14051, 14051, 14051, 14051, 14051, 12, 95, 32300, 62, 8, 18, -1, 15774), + (14052, 14052, 14052, 14052, 14052, 21, 95, 32301, 13, 1440, 18, -1, 14793), + (14053, 10912, 10912, 10912, 10912, 9, 91, 32303, 69, 1800, 18, 10914, 14054), + (14054, 10912, 10912, 10912, 10912, 12, 93, 32304, 69, 1800, 18, 14053, 14055), + (14055, 10912, 10912, 10912, 10912, 15, 95, 32305, 69, 1800, 18, 14054, -1), + (14056, -1, -1, 14056, 14056, 9, 91, -1, 0, 0, 18, -1, 14057), + (14059, -1, -1, 14059, 14059, 9, 91, -1, 0, 0, 18, -1, 14060), + (14062, -1, -1, 14062, 14062, 9, 91, -1, 0, 0, 18, -1, 14063), + (14065, -1, -1, 14065, 14065, 9, 91, 0, 0, 0, 18, -1, 14066), + (14068, -1, -1, 14068, 14068, 9, 91, 0, 0, 0, 18, -1, 14069), + (14071, 14071, 14071, 14071, 14071, 9, 91, 32307, 12, 600, 18, -1, 14072), + (14076, -1, -1, 14076, 14076, 9, 91, -1, 0, 0, 18, -1, 14077), + (14080, 14080, 14080, 14080, 14080, 9, 95, 32312, 13, 900, 18, -1, -1), + (14081, 14081, 14081, 14081, 14081, 9, 95, 32313, 14, 120, 18, -1, 17240), + (14082, -1, -1, 13101, 13101, 9, 91, 0, 0, 0, 18, 13103, 14083), + (14085, -1, -1, 14085, 14085, 9, 91, -1, 0, 0, 18, -1, 14086), + (14088, -1, -1, 14088, 14088, 9, 91, -1, 0, 0, 18, -1, 14089), + (14091, -1, -1, 14091, 14091, 9, 91, -1, 0, 0, 18, -1, 14092), + (14094, -1, -1, 10355, 10355, 9, 91, -1, 0, 0, 18, 10645, 14095), + (14097, -1, -1, 6395, 6395, 12, 91, -1, 0, 0, 18, 10707, 14098), + (14100, -1, -1, 14100, 14100, 15, 95, -1, 0, 0, 18, -1, -1), + (14101, -1, -1, 6355, 6355, 9, 91, -1, 0, 0, 18, 6360, 14263), + (14111, 6754, 6754, 6754, 6754, 12, 95, 32326, 41, 1200, 18, 10053, 14839), + (14112, 6370, 6370, 6370, 6370, 9, 91, 32329, 7, 600, 18, 7352, 14113), + (14115, -1, -1, 14115, 14115, 12, 91, -1, 0, 0, 18, -1, 14116), + (14129, -1, -1, 14129, 14129, 12, 91, -1, 0, 0, 18, -1, 14130), + (14130, -1, -1, 14129, 14129, 15, 93, -1, 0, 0, 18, 14129, 14131), + (14132, -1, -1, 7751, 7751, 7, 91, -1, 0, 0, 18, 7753, 14133), + (14135, -1, -1, 14135, 14135, 12, 91, -1, 0, 0, 18, -1, 14136), + (14138, -1, -1, 12615, 12615, 18, 95, -1, 0, 0, 18, 12617, 15499), + (14139, 14139, 14139, 14139, 14139, 15, 95, 32328, 60, 60, 18, -1, -1), + (14140, -1, -1, 12607, 12607, 15, 95, 0, 0, 0, 18, 12607, 15631), + (14141, -1, -1, 14141, 14141, 9, 91, -1, 0, 0, 18, -1, 14142), + (14144, -1, -1, 14144, 14144, 7, 91, -1, 0, 0, 18, -1, 14145), + (14148, -1, -1, 14148, 14148, 9, 91, 0, 0, 0, 18, -1, 14149), + (14151, -1, -1, 14151, 14151, 9, 91, 0, 0, 0, 18, -1, 14152), + (14154, -1, -1, 10657, 10657, 12, 91, 0, 0, 0, 18, 12681, 14155), + (14157, -1, -1, 14157, 14157, 9, 91, 0, 0, 0, 18, -1, 14158), + (14160, -1, -1, 14160, 14160, 9, 91, 0, 0, 0, 18, -1, 14161), + (14163, -1, -1, 14163, 14163, 9, 91, 0, 0, 0, 18, -1, 14164), + (14166, -1, -1, 14166, 14166, 9, 91, 0, 0, 0, 18, -1, 14167), + (14169, -1, -1, 14169, 14169, 7, 91, -1, 0, 0, 18, -1, 14170), + (14173, -1, -1, 12710, 12710, 9, 91, -1, 0, 0, 18, 12712, 14174), + (14176, -1, -1, 13204, 13204, 9, 91, -1, 0, 0, 18, 13206, 14177), + (14179, -1, -1, 14179, 14179, 9, 95, -1, 0, 0, 18, -1, -1), + (14180, -1, -1, 14180, 14180, 9, 95, -1, 0, 0, 18, -1, -1), + (14181, -1, -1, 14181, 14181, 9, 91, -1, 0, 0, 18, -1, 14182), + (14186, -1, -1, 14186, 14186, 9, 91, -1, 0, 0, 18, -1, 14187), + (14189, 5017, 5017, 5017, 5017, 9, 91, 32332, 8, 600, 18, 10158, 14190), + (14192, 14192, 14192, 14192, 14192, 15, 95, 32335, 36, 12, 18, -1, 15525), + (14196, -1, -1, 6935, 6935, 9, 91, -1, 0, 0, 18, 6904, 14197), + (14199, -1, -1, 6908, 6908, 12, 95, -1, 0, 0, 18, 6910, 15560), + (14200, -1, -1, 14200, 14200, 9, 91, 32336, 0, 0, 18, -1, 14201), + (14203, -1, -1, 14203, 14203, 12, 91, -1, 0, 0, 18, -1, 14204), + (14206, 14206, 14206, 14206, 14206, 12, 95, 32339, 41, 600, 18, -1, 15324), + (14207, 14207, 14207, 14207, 14207, 12, 95, 32340, 39, 180, 18, -1, -1), + (14208, 14208, 14208, 14208, 14208, 12, 95, 32341, 17, 180, 18, -1, 14568), + (14209, 14209, 14209, 14209, 14209, 12, 95, 32342, 22, 3, 18, -1, -1), + (14210, -1, -1, 10358, 10358, 12, 91, -1, 0, 0, 18, 10360, 14211), + (14213, -1, -1, 14213, 14213, 11, 91, -1, 0, 0, 18, -1, 14214), + (14218, -1, -1, 962, 962, 9, 91, -1, 0, 0, 18, 10363, 14219), + (14221, 1383, 1383, 1383, 1383, 18, 95, 32345, 6, 300, 18, 6487, 14581), + (14222, 146, 146, 146, 146, 15, 95, 32346, 2, 180, 18, 13258, 14977), + (14223, -1, -1, 13010, 13010, 12, 95, 0, 0, 0, 18, 13012, 16205), + (14224, 14224, -1, 14224, 14224, 9, 91, 345, 61, 5, 18, -1, 15860), + (14225, -1, -1, 14225, 14225, 9, 91, -1, 0, 0, 18, -1, 14226), + (14229, 14229, 14229, 14229, 14229, 12, 100, 37168, 42, 600, 19, -1, -1), + (14231, 14231, 14231, 14231, 14231, 12, 95, 32347, 91, 6, 18, -1, 16207), + (14232, 14232, -1, 14232, 14232, 12, 95, 32348, 92, 6, 18, -1, 14674), + (14233, 14233, 14233, 14233, 14233, 15, 95, 32349, 93, 30, 18, -1, 15621), + (14234, 14234, 14234, 14234, 14234, 9, 91, 32350, 94, 1800, 18, -1, 14235), + (14237, 12638, 12638, 12638, 12638, 9, 91, 23581, 68, 10, 18, -1, -1), + (14238, -1, -1, 12968, 12968, 9, 91, 0, 0, 0, 18, 12970, 14239), + (14241, -1, -1, 14241, 14241, 9, 91, -1, 0, 0, 18, -1, 14242), + (14244, -1, -1, 14244, 14244, 9, 91, -1, 0, 0, 18, -1, 14245), + (14249, -1, -1, 14249, 14249, 9, 91, -1, 0, 0, 18, -1, 14250), + (14254, -1, -1, 14254, 14254, 11, 91, -1, 0, 0, 18, -1, 14255), + (14256, 6561, 6561, 6561, 6561, 9, 91, 32353, 32, 30, 18, 10420, 14257), + (14259, -1, -1, 14259, 14259, 11, 91, -1, 0, 0, 18, -1, 14260), + (14262, 14262, 14262, 14262, 14262, 15, 95, 32357, 95, 180, 18, -1, -1), + (14264, 14264, 14264, 14264, 14264, 12, 95, 32358, 97, 120, 18, -1, 14600), + (14265, 14265, 14265, 14265, 14265, 15, 95, 32359, 68, 30, 18, -1, -1), + (14272, 6218, 6218, 6218, 14272, 12, 95, 32369, 0, 1, 18, 7488, 17381), + (14273, 723, 723, 723, 723, 12, 95, 32370, 6, 30, 18, 10300, 14869), + (14274, 6971, 6971, 6971, 6971, 9, 91, 32371, 41, 600, 18, 10290, 17383), + (14275, -1, -1, 14275, 14275, 7, 91, -1, 0, 0, 18, -1, 14276), + (14278, -1, -1, 14278, 14278, 12, 95, 0, 0, 0, 18, 6990, 16248), + (14279, -1, -1, 1287, 1287, 11, 95, -1, 0, 0, 18, 12815, 16529), + (14280, 4890, -1, 4890, 4890, 12, 95, 32373, 3, 8640, 18, 5872, 14776), + (14281, 14281, 14281, 14281, 14281, 12, 95, 32375, 39, 15, 18, -1, -1), + (14282, 14282, 14282, 14282, 14282, 9, 91, 32374, 39, 7, 18, -1, -1), + (14283, -1, -1, 14283, 14283, 7, 91, -1, 0, 0, 18, -1, 14284), + (14286, -1, -1, 14286, 14286, 9, 91, -1, 0, 0, 18, -1, 14287), + (14289, -1, -1, 14289, 14289, 9, 91, -1, 0, 0, 18, -1, 14290), + (14292, -1, -1, 14292, 14292, 9, 91, -1, 0, 0, 18, -1, 14293), + (14295, -1, -1, 14295, 14295, 9, 95, -1, 0, 0, 18, -1, 14296), + (14301, -1, -1, 14301, 14301, 9, 91, -1, 0, 0, 18, -1, 14302), + (14304, -1, -1, 14304, 14304, 9, 91, -1, 0, 0, 18, -1, 14305), + (14307, 14307, 14307, 14307, 14307, 12, 95, 32376, 92, 1200, 18, -1, 14743), + (14308, -1, -1, 14308, 14308, 9, 91, -1, 0, 0, 18, -1, 14309), + (14311, -1, -1, 14311, 14311, 9, 91, -1, 0, 0, 18, -1, 14312), + (14314, -1, -1, 7715, 7715, 7, 91, -1, 0, 0, 18, 7717, 14315), + (14318, -1, -1, 14318, 14318, 9, 91, -1, 0, 0, 18, -1, 14319), + (14321, 14321, 14321, 14321, 14321, 12, 95, 32378, 92, 8, 18, -1, 14781), + (14322, 14322, 14322, 14322, 14322, 12, 95, 32379, 94, 2160, 18, -1, 14782), + (14323, 14323, 14323, 14323, 14323, 12, 95, 32380, 92, 150, 18, -1, -1), + (14324, 155, 155, 155, 155, 15, 95, 32381, 8, 60, 18, 7238, 15610), + (14328, -1, -1, 7822, 7822, 7, 91, -1, 0, 0, 18, 7826, 14329), + (14331, -1, -1, 14331, 14331, 9, 91, -1, 0, 0, 18, -1, 14332), + (14338, 1337, 1337, 1337, 1337, 12, 91, 32382, 13, 4320, 18, 6160, 14339), + (14341, -1, -1, 14341, 14341, 5, 91, -1, 0, 0, 18, -1, 14342), + (14346, 14346, 14346, 14346, 14346, 9, 91, 32385, 94, 12, 18, -1, 14347), + (14349, -1, -1, 1210, 1213, 12, 91, -1, 0, 0, 18, 12528, 14350), + (14352, 1274, 1274, 1274, 1274, 12, 91, 32391, 9, 540, 18, 12762, 14353), + (14355, 6815, 6815, 6815, 6815, 9, 91, 32394, 60, 600, 18, 12788, 14356), + (14358, 14358, -1, 14358, 14358, 15, 95, 32397, 98, 300, 18, -1, -1), + (14359, 14359, 14359, 14359, 14359, 15, 95, 32399, 93, 1200, 18, -1, -1), + (14360, 14360, 14360, 14360, 14360, 15, 95, 32400, 95, 1800, 18, -1, 16334), + (14361, -1, -1, 637, 637, 12, 91, -1, 0, 0, 18, 12555, 14362), + (14364, -1, -1, 14364, 14364, 9, 91, -1, 0, 0, 18, -1, 14365), + (14367, -1, -1, 14367, 14367, 0, 1, -1, 0, 0, 0, -1, 14368), + (14371, 14371, 14371, 14371, 14371, 0, 1, 32910, 0, 10, 0, -1, -1), + (14372, 13844, 13844, 13844, 13844, 6, 95, 31667, 47, 6, 18, -1, -1), + (14373, 14373, 14373, 14373, 14373, 0, 85, 33106, 87, 3600, 19, -1, -1), + (14374, 14374, 14374, 14374, 14374, 0, 86, 33107, 88, 28800, 19, -1, -1), + (14690, 14690, 14690, 14690, 14690, 15, 96, 37014, 45, 600, 19, -1, 17479), + (14729, 8342, 8342, 8342, 8342, 15, 100, 33909, 54, 240, 19, 8342, 17501), + (14730, 616, 616, 616, 616, 12, 96, 33910, 7, 900, 19, 10261, 14731), + (14733, 4909, 4909, 4909, 4909, 18, 100, 33913, 16, 1320, 19, 12957, 17147), + (14734, 7903, 7903, 7903, 7903, 12, 100, 33914, 60, 30, 19, 12976, 15853), + (14739, 1462, 1462, 1462, 1462, 18, 99, 33919, 5, 300, 19, 4902, 16054), + (14764, -1, -1, 10551, 10551, 12, 96, -1, 0, 0, 19, 10553, 14765), + (14991, 926, 926, 926, 926, 5, 85, 11071, 12, 1800, 17, 930, 14992), + (14992, 926, 926, 926, 926, 5, 86, 11072, 12, 1800, 17, 14991, 14993), + (15073, 15073, -1, 15073, 15073, 0, 1, 37668, 90, 60, 19, -1, -1), + (15074, -1, -1, 15074, 15074, 0, 1, -1, 0, 0, 19, -1, 15075), + (15096, 15096, 15096, 15096, 15096, 5, 96, 38151, 35, 30, 19, -1, 15097), + (15099, 15099, 15099, 15099, 15099, 12, 100, 37187, 15, 45, 19, -1, 16566), + (15100, -1, -1, 15100, 15100, 5, 96, -1, 0, 0, 19, -1, 15101), + (15105, -1, -1, 15105, 15105, 11, 96, -1, 0, 0, 19, -1, 15106), + (15108, -1, -1, 15108, 15108, 9, 98, -1, 0, 0, 19, -1, 15109), + (15111, 8300, 8300, 8300, 8300, 11, 97, 37189, 8, 900, 19, 8302, 15112), + (15113, -1, -1, 15113, 15113, 11, 96, -1, 0, 0, 19, -1, 15114), + (15119, 15119, 15119, 15119, 15119, 12, 100, 37194, 16, 1200, 19, -1, 15749), + (15120, -1, -1, 15120, 15120, 9, 96, -1, 0, 0, 19, -1, 15121), + (15123, -1, -1, 15123, 15123, 9, 96, -1, 0, 0, 19, -1, 15124), + (15126, -1, -1, 15126, 15126, 9, 96, -1, 0, 0, 19, -1, 15127), + (15129, 15129, 15129, 15129, 15129, 12, 100, 37196, 32, 180, 19, -1, 15736), + (15130, 15130, 15130, 15130, 15130, 12, 100, 37197, 32, 180, 19, -1, 15737), + (15131, 15131, 15131, 15131, 15131, 12, 100, 37198, 32, 180, 19, -1, 15738), + (15132, -1, -1, 15132, 15132, 9, 96, -1, 0, 0, 19, -1, 15133), + (15135, -1, -1, 15135, 15135, 9, 100, -1, 0, 0, 19, -1, -1), + (15136, 15136, 15136, 15136, 15136, 9, 96, 38001, 5, 120, 19, -1, 17241), + (15140, 13100, 13100, 13100, 13100, 11, 100, 38002, 86, 300, 19, 13100, -1), + (15141, -1, -1, 190, 190, 9, 96, -1, 0, 0, 19, 5040, 15142), + (15146, 15146, 15146, 15146, 15146, 13, 100, 38006, 95, 9, 19, -1, 15758), + (15147, 15147, 15147, 15147, 15147, 11, 96, 38007, 8, 1200, 19, -1, 15148), + (15150, -1, -1, 15150, 15150, 7, 96, -1, 0, 0, 19, -1, 15151), + (15153, -1, -1, 15153, 15153, 11, 100, -1, 0, 0, 19, -1, -1), + (15154, -1, -1, 15154, 15154, 9, 96, -1, 0, 0, 19, -1, -1), + (15155, -1, -1, 15155, 15155, 5, 96, -1, 0, 0, 19, -1, 15156), + (15158, -1, -1, 15158, 15158, 13, 100, -1, 0, 0, 19, -1, -1), + (15159, -1, -1, 15159, 15159, 7, 96, -1, 0, 0, 19, -1, 15160), + (15162, -1, -1, 15162, 15162, 7, 96, -1, 0, 0, 19, -1, 15163), + (15168, -1, -1, 15168, 15168, 9, 96, -1, 0, 0, 19, -1, 15169), + (15172, -1, -1, 210, 210, 12, 100, -1, 0, 0, 19, 7401, 16658), + (15173, 6639, 6639, 6639, 6639, 9, 100, 38012, 42, 300, 19, 6639, 15788), + (15174, -1, -1, 12582, 12582, 9, 96, -1, 0, 0, 19, 12584, 15175), + (15177, 15177, 15177, 15177, 15177, 9, 100, 38013, 94, 180, 19, -1, -1), + (15179, -1, -1, 15179, 15179, 7, 96, -1, 0, 0, 19, -1, 15180), + (15182, -1, -1, 7757, 7757, 5, 96, -1, 0, 0, 19, 12589, 15183), + (15188, -1, -1, 1528, 4819, 5, 96, -1, 0, 0, 19, 4823, 15189), + (15193, 15193, 15193, 15193, 15193, 15, 100, 38016, 92, 600, 19, -1, -1), + (15194, -1, -1, 15194, 15194, 9, 100, -1, 0, 0, 19, -1, -1), + (15200, 15200, 15200, 15200, 15200, 9, 96, 38304, 32, 1080, 19, -1, 15201), + (15203, 15203, 15203, 15203, 15203, 15, 100, 38307, 34, 480, 19, -1, -1), + (15204, -1, -1, 15204, 15204, 9, 96, -1, 0, 0, 19, -1, 15205), + (15207, -1, -1, 15207, 15207, 9, 96, -1, 0, 0, 19, -1, 15208), + (15210, 15210, 15210, 15210, 15210, 9, 96, 38308, 12, 120, 19, -1, 15211), + (15213, 15213, 15213, 15213, 15213, 15, 100, 38312, 42, 1080, 19, -1, 17509), + (15214, 15214, 15214, 15214, 15214, 9, 96, 38313, 43, 1800, 19, -1, 15215), + (15217, -1, -1, 15217, 15217, 11, 96, -1, 0, 0, 19, -1, 15218), + (15220, -1, -1, 15220, 15220, 9, 100, -1, 0, 0, 19, -1, 15221), + (15223, -1, -1, 15223, 15223, 9, 100, -1, 0, 0, 19, -1, 15224), + (15226, -1, -1, 15226, 15226, 9, 100, -1, 0, 0, 19, -1, 15227), + (15229, -1, -1, 15229, 15229, 9, 100, -1, 0, 0, 19, -1, 15230), + (15232, -1, -1, 15232, 15232, 9, 96, -1, 0, 0, 19, -1, 15233), + (15235, 785, 785, 785, 785, 9, 96, 38325, 8, 900, 19, 789, 15236), + (15238, -1, -1, 5276, 5276, 11, 96, -1, 0, 0, 19, 5278, 15239), + (15241, 168, 168, 168, 168, 11, 96, 38329, 4, 10, 19, 170, 15242), + (15244, 171, 171, 171, 171, 11, 96, 38333, 4, 10, 19, 173, 15245), + (15247, 174, 174, 174, 174, 11, 96, 38336, 4, 10, 19, 176, 15248), + (15250, 177, 177, 177, 177, 11, 96, 38340, 4, 10, 19, 179, 15251), + (15253, -1, -1, 15253, 15253, 4, 96, -1, 0, 0, 19, -1, 15254), + (15258, -1, -1, 7743, 7743, 11, 100, -1, 0, 0, 19, 10718, -1), + (15270, -1, -1, 12430, 12430, 15, 100, -1, 0, 0, 19, 12878, -1), + (15280, -1, -1, 10722, 10722, 9, 96, -1, 0, 0, 19, 10726, 15281), + (15283, -1, -1, 15283, 15283, 5, 96, -1, 0, 0, 19, -1, 15284), + (15288, -1, -1, 15288, 15288, 7, 96, -1, 0, 0, 19, -1, 15289), + (15295, -1, -1, 15295, 15295, 7, 96, -1, 0, 0, 19, -1, 15296), + (15298, 10806, 10806, 10806, 10806, 9, 96, 38025, 71, 540, 19, 10808, 15299), + (15301, 10809, 10809, 10809, 10809, 9, 96, 38028, 71, 540, 19, 10811, 15302), + (15304, 15304, 15304, 15304, 15304, 12, 100, 38031, 91, 360, 19, -1, -1), + (15314, 0, 0, 6481, 6481, 11, 96, -1, 0, 0, 19, 6483, 15315), + (15317, -1, -1, 15317, 15317, 9, 96, -1, 0, 0, 19, 5012, 15318), + (15320, -1, -1, 7940, 7940, 11, 100, -1, 0, 0, 19, 6486, -1), + (15321, 746, 746, 746, 746, 9, 96, 38033, 10, 2160, 19, 10024, 15322), + (15328, -1, -1, 7948, 7948, 9, 96, -1, 0, 0, 19, 10037, 15329), + (15338, 15338, 15338, 15338, 15338, 9, 96, 38054, 30, 600, 19, -1, 15339), + (15341, 136, -1, 136, 136, 7, 100, 38057, 7, 1800, 19, 136, -1), + (15342, -1, -1, 15341, 15341, 7, 100, -1, 0, 0, 19, -1, -1), + (15343, 15343, 15343, 15343, 15343, 12, 100, 38058, 21, 300, 19, -1, -1), + (15344, -1, -1, 2400, 2400, 12, 97, -1, 0, 0, 19, 2402, 15345), + (15348, -1, -1, 13001, 13001, 7, 96, -1, 0, 0, 19, 13003, 15349), + (15356, -1, -1, 15356, 15356, 15, 100, -1, 0, 0, 19, -1, 15851), + (15357, 15357, 15357, 15357, 15357, 9, 96, 38062, 95, 2, 19, -1, -1), + (15358, -1, -1, 15358, 15358, 12, 100, -1, 0, 0, 19, -1, -1), + (15359, -1, -1, 474, 474, 5, 96, -1, 0, 0, 19, 476, 15360), + (15362, 15362, 15362, 15362, 15362, 15, 100, 38063, 89, 20, 19, -1, -1), + (15363, -1, -1, 10951, 10951, 12, 97, -1, 0, 0, 19, 10953, 15364), + (15371, -1, -1, 15371, 15371, 7, 96, -1, 0, 0, 19, -1, 15372), + (15374, -1, -1, 15374, 15374, 9, 96, -1, 0, 0, 19, -1, 15375), + (15377, 15377, 15377, 15377, 15377, 15, 100, 38070, 75, 420, 19, -1, 15852), + (15383, -1, -1, 15383, 15383, 9, 96, -1, 0, 0, 19, -1, 15384), + (15389, -1, -1, 15389, 15389, 9, 96, -1, 0, 0, 19, -1, 15390), + (15396, -1, -1, 141, 12863, 12, 100, -1, 0, 0, 19, 12863, -1), + (15397, -1, -1, 6346, 6346, 9, 96, -1, 0, 0, 19, 7617, 15398), + (15403, -1, -1, 15403, 15403, 7, 96, -1, 0, 0, 19, -1, 15404), + (15406, -1, -1, 15406, 15406, 7, 96, -1, 0, 0, 19, -1, 15407), + (15414, -1, -1, 15414, 15414, 9, 100, -1, 0, 0, 19, -1, -1), + (15421, -1, -1, 6538, 6538, 12, 100, -1, 0, 0, 19, 7478, -1), + (15422, -1, -1, 83, 83, 12, 100, -1, 0, 0, 19, 1218, -1), + (15423, 15423, 15423, 15423, 15423, 15, 100, 38078, 52, 180, 19, -1, 15884), + (15424, 15424, 15424, 15424, 15424, 12, 100, 38079, 78, 1200, 19, -1, -1), + (15425, 15425, 15425, 15425, 15425, 15, 100, 38077, 79, 6, 19, -1, 15903), + (15426, -1, -1, 810, 810, 5, 96, -1, 0, 0, 19, 4828, 15427), + (15429, -1, -1, 15429, 15429, 7, 96, -1, 0, 0, 19, -1, 15430), + (15432, -1, -1, 15432, 15432, 7, 96, -1, 0, 0, 19, -1, 15433), + (15438, -1, -1, 15438, 15438, 9, 96, -1, 0, 0, 19, -1, 15439), + (15441, -1, -1, 815, 815, 10, 96, -1, 0, 0, 19, 7636, 15442), + (15444, -1, -1, 15444, 15444, 9, 96, 38080, 0, 0, 19, -1, 15445), + (15447, 15447, 15447, 15447, 15447, 9, 96, 38083, 78, 180, 19, -1, 15448), + (15450, -1, -1, 15450, 15450, 9, 96, -1, 0, 0, 19, -1, 15451), + (15453, -1, -1, 15453, 15453, 9, 96, -1, 0, 0, 19, -1, 15454), + (15456, -1, -1, 15456, 15456, 9, 96, -1, 0, 0, 19, -1, 15457), + (15459, 1245, 1245, 1245, 1245, 9, 96, 38404, 8, 2160, 19, 1247, 15460), + (15462, 8039, 8039, 8039, 38407, 15, 100, 38407, 58, 7, 19, 8039, 17167), + (15466, -1, -1, 10561, 10561, 9, 96, -1, 0, 0, 19, 10563, 15467), + (15469, -1, -1, 10558, 10558, 9, 96, -1, 0, 0, 19, 10560, 15470), + (15472, -1, -1, 8035, 8035, 9, 96, -1, 0, 0, 19, 10287, 15473), + (15475, 15475, 15475, 15475, 15475, 11, 96, 38408, 41, 600, 20, -1, 15476), + (15478, -1, -1, 15478, 15478, 9, 96, -1, 0, 0, 19, -1, 15479), + (15481, 15481, 15481, 15481, 15481, 18, 100, 38603, 53, 1080, 19, -1, -1), + (15482, 15482, 15482, 15482, 15482, 11, 96, 38414, 42, 1800, 19, -1, 15483), + (15485, -1, -1, 15485, 15485, 18, 100, -1, 0, 0, 19, -1, -1), + (15486, 15486, 15486, 15486, 15486, 12, 96, 38418, 43, 600, 19, -1, 15487), + (15489, 15489, 15489, 15489, 15489, 18, 100, 38421, 52, 10, 19, -1, -1), + (15490, 15490, 15490, 15490, 15490, 11, 96, 38422, 44, 10, 19, -1, 15491), + (15493, -1, -1, 15493, 15493, 9, 96, -1, 0, 0, 19, -1, 15494), + (15496, 15496, 15496, 15496, 15496, 11, 96, 38425, 46, 1800, 19, -1, 15497), + (15502, -1, -1, 15502, 15502, 9, 96, -1, 0, 0, 19, -1, 15503), + (15509, -1, -1, 15509, 15509, 9, 96, -1, 0, 0, 19, -1, 15510), + (15512, -1, -1, 15512, 15512, 9, 96, 38086, 0, 0, 19, -1, 15513), + (15515, 15515, 15515, 15515, 15515, 12, 100, 38089, 11, 90, 19, -1, 17417), + (15516, -1, -1, 15516, 15516, 9, 100, -1, 0, 0, 19, -1, 15960), + (15517, -1, -1, 15517, 15517, 7, 96, -1, 0, 0, 19, -1, 15518), + (15521, 15521, 15521, 15521, 15521, 12, 96, 38090, 42, 60, 19, -1, -1), + (15526, -1, -1, 12716, 12716, 7, 96, -1, 0, 0, 19, 12718, 15527), + (15529, -1, -1, 695, 695, 4, 96, -1, 0, 0, 19, 699, 15530), + (15540, -1, -1, 15540, 15540, 7, 96, -1, 0, 0, 19, -1, 15541), + (15543, -1, -1, 15543, 15543, 7, 96, -1, 0, 0, 19, -1, 15544), + (15546, -1, -1, 15546, 15546, 7, 96, -1, 0, 0, 19, -1, 15547), + (15549, -1, -1, 15549, 15549, 7, 96, -1, 0, 0, 19, -1, 15550), + (15552, -1, -1, 6302, 6302, 5, 96, -1, 0, 0, 19, 11013, 15553), + (15555, -1, -1, 15555, 15555, 11, 96, -1, 0, 0, 19, -1, 15556), + (15558, 10400, 10400, 10400, 10400, 9, 100, 38104, 62, 900, 19, 10400, -1), + (15564, -1, -1, 15564, 15564, 9, 96, -1, 0, 0, 19, -1, 15565), + (15567, 15567, 15567, 15567, 15567, 12, 96, 38106, 11, 1200, 19, -1, 15568), + (15569, 15569, 15569, 15569, 15569, 12, 96, 38108, 13, 60, 19, -1, 15991), + (15570, 15570, 15570, 15570, 15570, 15, 100, 38109, 64, 600, 19, -1, 15992), + (15571, -1, -1, 15571, 15571, 7, 96, -1, 0, 0, 19, -1, 15572), + (15574, 15574, 15574, 15574, 15574, 9, 80, 38110, 73, 4, 15, -1, 15575), + (15575, 15574, 15574, 15574, 15574, 9, 85, 38111, 73, 4, 16, 15574, 15576), + (15576, 15574, 15574, 15574, 15574, 9, 90, 38112, 73, 4, 17, 15575, 15577), + (15577, 15574, 15574, 15574, 15574, 9, 95, 38113, 73, 4, 18, 15576, 15578), + (15579, -1, -1, 15579, 15579, 7, 96, -1, 0, 0, 19, -1, 15580), + (15582, 15582, 15582, 15582, 15582, 9, 96, 38115, 34, 600, 19, -1, 15583), + (15585, -1, -1, 634, 634, 11, 96, -1, 0, 0, 19, 10780, 15586), + (15588, 10701, 10701, 10701, 10701, 12, 96, 38121, 32, 360, 19, 12756, 15589), + (15591, -1, -1, 15591, 15591, 5, 96, -1, 0, 0, 19, -1, 15592), + (15594, 15594, 15594, 15594, 15594, 9, 96, 38197, 39, 30, 19, -1, 15595), + (15598, -1, -1, 15598, 15598, 12, 96, -1, 0, 0, 19, -1, 15599), + (15601, 15601, 15601, 15601, 15601, 12, 96, 38131, 34, 6, 19, -1, 16077), + (15602, -1, -1, 15602, 15602, 9, 96, -1, 0, 0, 19, -1, 15603), + (15605, 12866, 12866, 12866, 12866, 15, 96, 38132, 74, 1800, 19, 12866, -1), + (15606, -1, -1, 8069, 8069, 5, 96, -1, 0, 0, 19, 8071, 15607), + (15609, -1, -1, 15609, 15609, 15, 100, -1, 0, 0, 19, -1, -1), + (15611, 15611, 15611, 15611, 15611, 18, 100, 38136, 32, 900, 19, -1, 16078), + (15612, 15612, 15612, 15612, 15612, 12, 96, 38137, 36, 20, 19, -1, 15613), + (15615, 15615, 15615, 15615, 15615, 12, 96, 38140, 44, 20, 19, -1, 15616), + (15619, 15619, 15619, 15619, 15619, 15, 100, 37188, 32, 600, 19, -1, -1), + (15622, -1, -1, 15622, 15622, 7, 96, -1, 0, 0, 19, -1, 15623), + (15625, -1, -1, 15625, 15625, 9, 96, -1, 0, 0, 19, -1, 15626), + (15628, 5022, 5022, 5022, 5022, 9, 96, 38176, 5, 600, 19, 6040, 15629), + (15632, -1, -1, 7005, 7005, 5, 96, -1, 0, 0, 19, 7007, 15633), + (15634, -1, -1, 15634, 15634, 3, 80, -1, 0, 0, 19, -1, 15635), + (15635, -1, -1, 15634, 15634, 5, 85, -1, 0, 0, 19, 15634, 15636), + (15639, 15639, 15639, 15639, 15639, 12, 96, 38183, 56, 60, 19, -1, -1), + (15640, 15640, 15640, 15640, 15640, 12, 100, 38184, 43, 60, 19, -1, -1), + (15642, 15642, 15642, 15642, 15642, 18, 100, 38187, 13, 1440, 19, -1, -1), + (15643, 15643, 15643, 15643, 15643, 9, 96, 38188, 75, 600, 19, -1, 15644), + (15646, 15646, 15646, 15646, 15646, 15, 100, 38194, 74, 60, 19, -1, 17255), + (15648, -1, -1, 15648, 15648, 9, 96, -1, 0, 0, 19, -1, 15649), + (15694, -1, -1, 8215, 8215, 5, 96, -1, 0, 0, 20, 12563, 15695), + (15714, -1, -1, 5263, 5263, 12, 96, -1, 0, 0, 20, 12468, 15715), + (15719, -1, -1, 1287, 1287, 11, 96, -1, 0, 0, 20, 13240, 15720), + (15746, -1, -1, 7033, 7033, 12, 96, 0, 0, 0, 20, 7035, 15747), + (15768, -1, -1, 15768, 15768, 7, 96, -1, 0, 0, 20, -1, 15769), + (15771, 15771, -1, 15771, 15771, 1, 55, 38274, 0, 3, 20, -1, -1), + (15772, -1, -1, 8232, 8232, 8, 100, -1, 0, 0, 20, 8261, -1), + (15773, -1, -1, 8040, 8040, 8, 100, -1, 0, 0, 20, 8313, -1), + (15775, 6508, 6508, 6508, 6508, 9, 96, 38276, 38, 600, 20, 10080, 15776), + (15778, -1, -1, 589, 589, 12, 96, -1, 0, 0, 20, 13106, 15779), + (15782, 7755, 7755, 7755, 7755, 12, 96, 38280, 53, 900, 20, 7755, 16187), + (15798, 15798, 15798, 15798, 15798, 9, 100, 38297, 34, 18, 20, -1, 15799), + (15819, 15819, 15819, 15819, 15819, 18, 100, 40807, 18, 900, 20, -1, -1), + (15833, -1, -1, 15833, 15833, 9, 96, 0, 0, 0, 20, -1, 15834), + (15836, -1, -1, 15836, 15836, 9, 100, 0, 0, 0, 20, -1, 15837), + (15839, 10450, 10450, 10450, 10450, 7, 96, 40817, 63, 900, 20, 10670, 15840), + (15855, 13004, 13004, 13004, 13004, 9, 96, 40832, 78, 300, 20, 13004, -1), + (15891, -1, -1, 11078, 11078, 9, 96, 0, 0, 0, 20, 11078, 15892), + (15893, -1, -1, 11079, 11079, 9, 96, 0, 0, 0, 20, 11079, 15894), + (15895, -1, -1, 11077, 11077, 9, 96, 0, 0, 0, 20, 11077, 15896), + (15904, 15904, 15904, 15904, 15904, 7, 66, 40874, 54, 600, 20, -1, -1), + (15908, -1, -1, 15908, 15908, 3, 80, -1, 0, 0, 20, -1, 15909), + (15909, -1, -1, 15908, 15908, 5, 85, -1, 0, 0, 20, 15908, 15910), + (15910, -1, -1, 15908, 15908, 7, 90, -1, 0, 0, 20, 15909, 15911), + (15954, -1, -1, 10853, 10853, 5, 90, -1, 0, 0, 20, 10864, 15955), + (15961, -1, -1, 12737, 12737, 9, 96, 0, 0, 0, 20, 12739, 15962), + (15988, 10333, 10333, 10333, 10333, 9, 96, 40894, 55, 120, 20, 12726, 15989), + (16016, 16016, 16016, 16016, 16016, 12, 100, 40919, 17, 12, 20, -1, -1), + (16062, -1, -1, 1572, 1572, 5, 96, -1, 0, 0, 20, 10556, 16063), + (16071, 16071, 16071, 16071, 16071, 15, 100, 40953, 46, 1800, 20, -1, 16072), + (16081, 16081, 16081, 16081, 16081, 15, 100, 40969, 55, 6, 20, -1, -1), + (16082, 16082, 16082, 16082, 16082, 3, 100, 40970, 53, 6, 20, -1, -1), + (16083, 16083, 16083, 16083, 16083, 3, 55, 40971, 46, 6, 20, -1, -1), + (16084, -1, -1, 16084, 16084, 9, 100, 0, 0, 0, 20, -1, 16085), + (16087, -1, -1, 16087, 16087, 5, 100, 0, 0, 6, 20, -1, 16088), + (16094, -1, -1, 477, 477, 2, 100, -1, 0, 0, 20, 6235, 16095), + (16096, 16096, 16096, 16096, 16096, 12, 100, 40972, 36, 6, 20, -1, -1), + (16097, 16097, 16097, 16097, 16097, 12, 100, 40973, 38, 600, 20, -1, 16098), + (16103, 16103, 16103, 16103, 16103, 0, 85, 41071, 35, 180, 16, -1, -1), + (16104, -1, -1, 16104, 16104, 5, 85, 0, 0, 0, 20, -1, -1), + (16105, 16105, 16105, 16105, 16105, 0, 85, 41086, 76, 30, 20, -1, -1), + (16106, 16106, 16106, 16106, 16106, 0, 85, 41087, 76, 30, 20, -1, -1), + (16107, 16107, 16107, 16107, 16107, 0, 85, 41088, 76, 30, 20, -1, -1), + (16108, 16108, 16108, 16108, 16108, 12, 100, 41090, 77, 120, 20, -1, -1), + (16109, -1, -1, 16109, 16109, 11, 96, -1, 0, 0, 20, -1, 16110), + (16113, 16113, 16113, 16113, 16113, 15, 100, 41096, 78, 60, 20, -1, -1), + (16114, -1, -1, 16114, 16114, 5, 96, -1, 0, 0, 20, -1, 16115), + (16117, -1, -1, 16117, 16117, 11, 96, -1, 0, 0, 20, -1, 16118), + (16120, -1, -1, 16120, 16120, 9, 105, -1, 0, 0, 21, -1, -1), + (16121, -1, -1, 6611, 6611, 6, 100, -1, 0, 0, 20, 10574, 16122), + (16124, -1, -1, 16124, 16124, 5, 96, -1, 0, 0, 20, -1, 16125), + (16128, -1, -1, 16128, 16128, 6, 96, -1, 0, 0, 20, -1, 16129), + (16131, -1, -1, 16131, 16131, 5, 96, -1, 0, 0, 20, -1, 16132), + (16137, -1, -1, 16137, 16137, 9, 100, -1, 0, 0, 20, -1, 16138), + (16140, -1, -1, 16140, 16140, 9, 100, -1, 0, 0, 20, -1, -1), + (16146, -1, -1, 16146, 16146, 11, 100, -1, 0, 0, 20, -1, 16147), + (16149, -1, -1, 16149, 16149, 9, 100, -1, 0, 0, 20, -1, 16150), + (16152, -1, -1, 16152, 16152, 11, 100, -1, 0, 0, 20, -1, 16153), + (16156, -1, -1, 16156, 16156, 12, 100, -1, 0, 0, 20, -1, 16157), + (16159, -1, -1, 16159, 16159, 15, 100, -1, 0, 0, 20, -1, -1), + (16160, 16160, 16160, 16160, 16160, 18, 100, 41110, 81, 900, 20, -1, -1), + (16162, 16162, 16162, 16162, 16162, 12, 100, 41112, 80, 180, 20, -1, -1), + (16163, 16163, 16163, 16163, 16163, 18, 100, 41113, 63, 180, 20, -1, 16695), + (16164, -1, -1, 6636, 6636, 9, 96, -1, 0, 0, 20, 12531, 16165), + (16170, -1, -1, 5248, 5248, 12, 96, -1, 0, 0, 20, 7358, 16171), + (16173, -1, -1, 5263, 5263, 9, 101, -1, 0, 0, 21, 12465, 16174), + (16176, -1, -1, 16176, 16176, 7, 100, -1, 0, 0, 20, -1, 16177), + (16179, -1, -1, 16179, 16179, 18, 100, 41122, 0, 0, 20, -1, -1), + (16180, -1, -1, 16180, 16180, 7, 96, -1, 0, 0, 20, -1, 16181), + (16185, 16185, 16185, 16185, 16185, 18, 100, 41124, 68, 600, 20, -1, 16729), + (16186, -1, -1, 16186, 16186, 12, 100, 41125, 0, 0, 20, -1, -1), + (16188, 16188, 16188, 16188, 16188, 12, 100, 41126, 58, 180, 20, -1, -1), + (16189, -1, -1, 10915, 10915, 9, 96, -1, 0, 0, 20, 10917, 16190), + (16192, -1, -1, 6641, 6641, 9, 96, -1, 0, 0, 20, 10077, 16193), + (16195, 16195, 16195, 16195, 16195, 15, 100, 41133, 59, 60, 20, -1, -1), + (16196, 16196, 16196, 16196, 16196, 15, 100, 41134, 60, 900, 20, -1, 16665), + (16197, 16197, 16197, 16197, 16197, 12, 96, 41136, 61, 900, 20, -1, 16198), + (16200, 16200, 16200, 16200, 16200, 9, 96, 41139, 63, 900, 20, -1, 16201), + (16203, 16203, 16203, 16203, 16203, 12, 96, 41143, 98, 120, 20, -1, 16204), + (16208, -1, -1, 16208, 16208, 5, 96, -1, 0, 0, 20, -1, 16209), + (16211, -1, -1, 16211, 16211, 7, 100, -1, 0, 0, 20, -1, 16212), + (16214, 10958, 10958, 10958, 16214, 18, 100, 41148, 62, 900, 20, 13000, -1), + (16215, 16215, 16215, 16215, 16215, 9, 96, 41150, 92, 300, 20, -1, 16216), + (16218, -1, -1, 16218, 16218, 7, 96, -1, 0, 0, 20, -1, 16219), + (16221, -1, -1, 16221, 16221, 9, 100, -1, 0, 0, 20, -1, 16223), + (16222, 16222, -1, 16222, 16222, 9, 100, 41153, 88, 30, 20, -1, -1), + (16225, -1, -1, 16225, 16225, 5, 96, -1, 0, 0, 20, -1, 16226), + (16230, -1, -1, 16230, 16230, 5, 96, -1, 0, 0, 20, -1, 16231), + (16235, -1, -1, 16235, 16235, 7, 96, -1, 0, 0, 20, -1, 16236), + (16238, -1, -1, 16238, 16238, 7, 96, -1, 0, 0, 20, -1, 16239), + (16246, 6983, 6983, 6983, 6983, 9, 96, 41157, 66, 720, 20, 6983, 16247), + (16249, -1, -1, 230, 230, 9, 100, -1, 0, 0, 20, 12677, -1), + (16250, 828, 828, 828, 828, 9, 96, 41159, 2, 3600, 20, 830, -1), + (16257, -1, -1, 16257, 16257, 11, 100, 0, 0, 0, 20, -1, 16258), + (16260, -1, -1, 16260, 16260, 11, 100, -1, 0, 0, 20, -1, 16261), + (16263, 16263, 16263, 16263, 16263, 11, 96, 41161, 95, 600, 20, -1, 16264), + (16266, -1, -1, 6560, 6560, 9, 96, -1, 0, 0, 20, 6277, -1), + (16267, -1, -1, 888, 888, 3, 96, -1, 0, 0, 20, 892, 16268), + (16272, -1, -1, 16272, 16272, 9, 96, -1, 0, 0, 20, -1, 16273), + (16276, -1, -1, 16276, 16276, 5, 96, -1, 0, 0, 20, -1, 16277), + (16287, -1, -1, 16287, 16287, 7, 96, -1, 0, 0, 20, -1, 16288), + (16296, 16296, 16296, 16296, 16296, 13, 100, 41168, 60, 30, 20, -1, -1), + (16297, -1, -1, 6337, 6337, 6, 96, -1, 0, 0, 20, 10155, 16298), + (16300, -1, -1, 16300, 16300, 9, 100, -1, 0, 0, 20, -1, 16301), + (16303, -1, -1, 12721, 12721, 9, 96, 0, 0, 0, 20, 12723, 16304), + (16306, -1, -1, 6340, 6340, 6, 96, -1, 0, 0, 20, 7453, -1), + (16310, 16310, 16310, 16310, 16310, 12, 100, 41169, 97, 600, 20, -1, -1), + (16317, -1, -1, 16317, 16317, 5, 100, -1, 0, 0, 20, -1, 16318), + (16324, 6607, 6607, 6607, 16324, 9, 96, 16491, 61, 600, 20, 6609, 16325), + (16327, -1, -1, 6362, 6362, 7, 96, 0, 0, 0, 20, 6366, 16328), + (16330, -1, -1, 16330, 16330, 9, 96, -1, 0, 0, 20, -1, 16331), + (16336, -1, -1, 16336, 16336, 7, 96, -1, 0, 0, 20, -1, 16337), + (16339, -1, -1, 16339, 16339, 7, 96, -1, 0, 0, 20, -1, 16340), + (16342, -1, -1, 16342, 16342, 7, 96, -1, 0, 0, 20, -1, 16343), + (16360, 16360, 16360, 16360, 16360, 9, 100, 41188, 91, 6, 20, -1, -1), + (16361, -1, -1, 9509, 9509, 7, 96, -1, 0, 0, 20, 9515, -1), + (16363, 16363, 16363, 16363, 16363, 12, 96, 41193, 89, 1800, 20, -1, 16364), + (16366, -1, -1, 16366, 16366, 12, 96, -1, 0, 0, 20, -1, 16367), + (16369, 16369, 16369, 16369, 16369, 15, 100, 41196, 98, 12, 20, -1, -1), + (16370, 16370, -1, 16370, 16370, 5, 100, 41197, 98, 12, 20, -1, -1), + (16371, -1, -1, 16371, 16371, 3, 96, -1, 0, 0, 20, -1, 16372), + (16380, -1, -1, 16380, 16380, 5, 96, -1, 0, 0, 20, -1, 16381), + (16386, -1, -1, 16386, 16386, 7, 96, -1, 0, 0, 20, -1, 16387), + (16392, -1, -1, 16392, 16392, 5, 96, -1, 0, 0, 20, -1, 16393), + (16395, 16395, 16395, 16395, 16395, 7, 100, 41305, 93, 10, 20, -1, -1), + (16396, -1, -1, 16396, 16396, 7, 96, -1, 0, 0, 20, -1, 16397), + (16402, -1, -1, 6112, 6112, 5, 96, -1, 0, 0, 20, 12967, 16403), + (16414, -1, -1, 1056, 1056, 5, 101, -1, 0, 0, 21, 7525, 16415), + (16419, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 8447, 16420), + (16420, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 16419, 16421), + (16421, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 16420, -1), + (16440, -1, -1, 6540, 6540, 10, 101, -1, 0, 0, 21, 12510, 16441), + (16475, -1, -1, 8201, 8201, 9, 101, -1, 0, 0, 21, 8203, 16476), + (16489, -1, -1, 1107, 1107, 9, 101, -1, 0, 0, 21, 12558, 16490), + (16536, -1, -1, 16536, 16536, 5, 101, -1, 0, 0, 21, -1, 16537), + (16604, -1, -1, 849, 849, 11, 105, -1, 0, 0, 21, 10622, -1), + (16644, -1, -1, 16644, 16644, 11, 101, -1, 0, 0, 21, -1, 16645), + (16666, -1, -1, 16666, 16666, 9, 101, -1, 0, 0, 21, -1, 16667), + (16716, 6764, 6764, 6764, 6764, 12, 105, 41308, 52, 600, 21, 10057, -1), + (16730, -1, -1, 1608, 1608, 13, 101, -1, 0, 0, 21, 10069, 16731), + (16745, -1, -1, 16745, 16745, 9, 101, -1, 0, 0, 21, -1, 16746), + (16883, 1119, 1119, 1119, 1119, 12, 101, 41594, 8, 900, 21, 10299, 16884), + (16887, -1, -1, 729, 729, 11, 101, -1, 0, 0, 21, 10307, 16888), + (16890, -1, -1, 724, 724, 15, 101, -1, 0, 0, 21, 7493, 16891), + (17004, -1, -1, 556, 556, 7, 101, -1, 0, 0, 21, 1567, 17005), + (17030, 4857, 4857, 4857, 4857, 15, 101, 41660, 7, 600, 21, 5769, 17031), + (17131, 12785, 12785, 12785, 12785, 15, 105, 41736, 80, 30, 21, 12785, -1), + (17199, 17199, 17199, 17199, 17199, 100, 51, 41819, 31, 2, 21, -1, -1), + (17206, -1, -1, 10588, 10588, 7, 101, 0, 0, 0, 21, 10592, 17207), + (17209, -1, -1, 17209, 17209, 9, 101, -1, 0, 0, 21, -1, 17210), + (17212, -1, -1, 17212, 17212, 12, 101, -1, 0, 0, 21, -1, 17213), + (17215, -1, -1, 17215, 17215, 12, 101, -1, 0, 0, 21, -1, 17216), + (17218, -1, -1, 17218, 17218, 9, 101, -1, 0, 0, 21, -1, 17219), + (17229, -1, -1, 17229, 17229, 9, 101, -1, 0, 0, 21, -1, 17230), + (17235, -1, -1, 17235, 17235, 15, 101, -1, 0, 0, 21, -1, 17236), + (17238, 17238, 17238, 17238, 17238, 24, 105, 41808, 10, 900, 21, -1, -1), + (17239, -1, -1, 6489, 6489, 12, 101, -1, 0, 0, 21, 6491, -1), + (17242, -1, -1, 17242, 17242, 12, 101, -1, 0, 0, 21, -1, 17243), + (17245, -1, -1, 17245, 17245, 12, 101, -1, 0, 0, 21, -1, 17246), + (17248, 17248, 17248, 17248, 17248, 24, 105, 41811, 93, 1080, 21, -1, -1), + (17249, -1, -1, 17249, 17249, 12, 101, -1, 0, 0, 21, -1, 17250), + (17252, -1, -1, 17252, 17252, 9, 101, -1, 0, 0, 21, -1, 17253), + (17256, 17256, 17256, 17256, 17256, 21, 105, 41815, 93, 360, 21, -1, -1), + (17257, 17257, 17257, 17257, 17257, 21, 105, 41816, 98, 300, 21, -1, -1), + (17258, -1, -1, 17258, 17258, 15, 101, 0, 0, 0, 21, -1, 17259), + (17267, -1, -1, 17267, 17267, 9, 101, -1, 0, 0, 21, -1, 17268), + (17273, 17273, 17273, 17273, 17273, 15, 101, 41830, 98, 720, 21, -1, -1), + (17276, 1569, 1569, 1569, 1569, 9, 101, 41831, 5, 1800, 21, 10161, 17277), + (17280, 17280, 17280, 17280, 17280, 21, 105, 41834, 97, 720, 21, -1, -1), + (17281, -1, -1, 17281, 17281, 15, 105, -1, 0, 0, 21, -1, -1), + (17288, -1, -1, 17288, 17288, 9, 105, -1, 0, 0, 21, 7317, -1), + (17289, -1, -1, 17289, 17289, 7, 101, -1, 0, 0, 21, -1, 17290), + (17295, -1, -1, 692, 692, 12, 101, -1, 0, 0, 21, 12769, 17296), + (17298, 749, 749, 749, 749, 15, 105, 41837, 11, 1800, 21, 1208, -1), + (17307, -1, -1, 17307, 17307, 9, 101, -1, 0, 0, 21, -1, 17308), + (17310, -1, -1, 7945, 7945, 9, 105, -1, 0, 0, 21, 10347, -1), + (17311, 970, 970, 970, 970, 9, 101, 41845, 6, 1800, 21, 1326, 17312), + (17317, -1, -1, 17317, 17317, 9, 101, -1, 0, 0, 21, -1, 17318), + (17328, 17328, 17328, 17328, 17328, 21, 105, 41854, 87, 600, 21, -1, -1), + (17329, 17329, 17329, 17329, 17329, 12, 101, 41855, 88, 20, 21, -1, -1), + (17333, 153, 153, 153, 153, 18, 105, 41856, 3, 2160, 21, 12996, -1), + (17334, -1, -1, 12977, 12977, 12, 102, 0, 0, 0, 21, 12981, 17335), + (17336, -1, -1, 17336, 17336, 9, 101, -1, 0, 0, 21, -1, 17337), + (17339, -1, -1, 17339, 17339, 9, 101, -1, 0, 0, 21, -1, 17340), + (17342, 17342, 17342, 17342, 17342, 15, 105, 41857, 85, 60, 21, -1, -1), + (17344, 17344, 17344, 17344, 17344, 15, 101, 41858, 94, 780, 21, -1, 17345), + (17347, 17347, 17347, 17347, 17347, 12, 101, 41861, 32, 30, 21, -1, 17348), + (17350, -1, -1, 7664, 7664, 5, 102, -1, 0, 0, 21, 10109, 17351), + (17357, -1, -1, 17357, 17357, 9, 96, -1, 0, 0, 19, -1, 17358), + (17361, -1, -1, 17361, 17361, 5, 100, -1, 0, 0, 21, -1, 17362), + (17364, 17364, 17364, 17364, 17364, 15, 105, 46160, 87, 120, 21, -1, -1), + (17365, -1, -1, 10792, 10792, 15, 101, 0, 0, 0, 21, 10796, 17366), + (17370, -1, -1, 17370, 17370, 15, 102, 0, 0, 0, 21, -1, 17371), + (17372, 17372, 17372, 17372, 17372, 18, 104, 46161, 85, 300, 21, -1, -1), + (17373, 17373, -1, 17373, 17373, 15, 105, 46162, 98, 900, 21, -1, -1), + (17375, -1, -1, 17375, 17375, 12, 101, -1, 0, 0, 21, -1, 17376), + (17378, 17378, 17378, 17378, 17378, 10, 101, 46164, 97, 3, 21, -1, -1), + (17379, 17378, 17378, 17378, 17378, 10, 101, 46165, 86, 3, 21, -1, -1), + (17380, 17378, 17378, 17378, 17378, 10, 101, 46166, 97, 3, 21, -1, -1), + (17382, 5015, 5015, 5015, 5015, 15, 103, 46168, 9, 900, 21, 10301, -1), + (17384, 17384, 17384, 17384, 17384, 18, 101, 46171, 10, 20, 21, -1, -1), + (17391, -1, -1, 495, 495, 12, 105, -1, 0, 0, 21, 10668, -1), + (17406, -1, -1, 10653, 10653, 12, 103, -1, 0, 0, 21, 10655, -1), + (17409, -1, -1, 17409, 17409, 15, 105, -1, 0, 0, 21, -1, -1), + (17414, -1, -1, 17414, 17414, 9, 101, -1, 0, 0, 21, -1, 17415), + (17418, -1, -1, 17418, 17418, 7, 101, -1, 0, 0, 21, -1, 17419), + (17428, 17428, 17428, 17428, 17428, 15, 101, 46178, 0, 0, 21, -1, 17429), + (17436, -1, -1, 17436, 17436, 7, 101, -1, 0, 0, 21, -1, 17437), + (17439, -1, -1, 17439, 17439, 9, 102, -1, 0, 0, 21, -1, 17440), + (17441, -1, -1, 255, 255, 15, 102, -1, 0, 0, 21, 7633, -1), + (17445, -1, -1, 17445, 17445, 15, 101, 0, 0, 0, 21, -1, 17446), + (17448, -1, -1, 17448, 17448, 15, 102, 0, 0, 0, 21, -1, 17449), + (17476, -1, -1, 10800, 10800, 15, 101, -1, 0, 0, 21, 10802, 17477), + (17486, 12864, -1, 12864, 12864, 12, 105, 46195, 73, 10, 21, 12864, -1), + (17492, -1, -1, 17492, 17492, 9, 101, -1, 0, 0, 21, -1, 17493), + (17495, -1, -1, 17495, 17495, 9, 101, -1, 0, 0, 21, -1, 17496), + (17515, -1, -1, 17515, 17515, 7, 102, -1, 0, 0, 21, -1, 17516), + (17517, -1, -1, 17517, 17517, 9, 101, -1, 0, 0, 21, -1, 17518), + (17522, -1, -1, 17522, 17522, 9, 101, -1, 0, 0, 21, -1, 17523), + (17533, -1, -1, 17533, 17533, 15, 105, -1, 0, 0, 21, -1, -1), + (17534, 6828, 6828, 6828, 6828, 15, 105, 46207, 43, 60, 21, 10208, -1), + (17535, 967, 967, 967, 967, 9, 101, 46208, 10, 1800, 21, 12791, 17536), + (17538, 17538, 17538, 17538, 17538, 21, 105, 46212, 91, 1800, 21, -1, -1), + (17539, 4934, 4934, 4934, 4934, 12, 105, 46214, 13, 300, 21, 10278, -1), + (17540, 4935, 4935, 4935, 4935, 12, 105, 46215, 14, 300, 21, 10277, -1), + (17541, 8038, 8038, 8038, 8038, 12, 105, 46217, 56, 12, 21, 8038, -1), + (17547, -1, -1, 17547, 17547, 12, 102, -1, 0, 0, 21, -1, 17548), + (17549, -1, -1, 17549, 17549, 9, 101, -1, 0, 0, 21, -1, 17550), + (17553, -1, -1, 17553, 17553, 18, 105, -1, 0, 0, 21, -1, -1), + (17554, -1, -1, 17554, 17554, 15, 105, -1, 0, 0, 21, -1, -1), + (17555, -1, -1, 17555, 17555, 5, 101, -1, 0, 0, 21, -1, 17556), + (17558, -1, -1, 17558, 17558, 5, 101, -1, 0, 0, 21, -1, 17559), + (17561, -1, -1, 17561, 17561, 5, 101, -1, 0, 0, 21, -1, 17562), + (17564, -1, -1, 17564, 17564, 5, 101, -1, 0, 0, 21, -1, 17565), + (17567, -1, -1, 17567, 17567, 5, 101, -1, 0, 0, 21, -1, 17568), + (17570, -1, -1, 17570, 17570, 5, 101, -1, 0, 0, 21, -1, 17571), + (17573, -1, -1, 17573, 17573, 5, 101, -1, 0, 0, 21, -1, 17574), + (17576, -1, -1, 17576, 17576, 5, 101, -1, 0, 0, 21, -1, 17577), + (17579, -1, -1, 17579, 17579, 5, 101, -1, 0, 0, 21, -1, 17580), + (17582, -1, -1, 17582, 17582, 5, 101, -1, 0, 0, 21, -1, 17583), + (17585, -1, -1, 17585, 17585, 5, 101, -1, 0, 0, 21, -1, 17586), + (17588, -1, -1, 17588, 17588, 5, 101, -1, 0, 0, 21, -1, 17589), + (17591, -1, -1, 17591, 17591, 5, 101, -1, 0, 0, 21, -1, 17592), + (17594, -1, -1, 17594, 17594, 5, 101, -1, 0, 0, 21, -1, 17595), + (17597, -1, -1, 17597, 17597, 5, 101, -1, 0, 0, 21, -1, 17598), + (17600, -1, -1, 17600, 17600, 5, 101, -1, 0, 0, 21, -1, 17601), + (17603, -1, -1, 17603, 17603, 5, 101, -1, 0, 0, 21, -1, 17604), + (17606, -1, -1, 17606, 17606, 5, 101, -1, 0, 0, 21, -1, 17607), + (17609, -1, -1, 17609, 17609, 5, 101, -1, 0, 0, 21, -1, 17610), + (17612, -1, -1, 17612, 17612, 5, 101, -1, 0, 0, 21, -1, 17613), + (17615, -1, -1, 17615, 17615, 5, 101, -1, 0, 0, 21, -1, 17616), + (17618, -1, -1, 17618, 17618, 5, 101, -1, 0, 0, 21, -1, 17619), + (17621, -1, -1, 17621, 17621, 5, 101, -1, 0, 0, 21, -1, 17622), + (17624, -1, -1, 17624, 17624, 5, 101, -1, 0, 0, 21, -1, 17625), + (17627, -1, -1, 17627, 17627, 5, 101, -1, 0, 0, 21, -1, 17628), + (17630, -1, -1, 17630, 17630, 5, 101, -1, 0, 0, 21, -1, 17631), + (17633, -1, -1, 17633, 17633, 5, 101, -1, 0, 0, 21, -1, 17634), + (17639, -1, -1, 17639, 17639, 9, 91, 0, 0, 0, 18, -1, 17640), + (18972, -1, -1, 279, 279, 15, 105, -1, 0, 0, 21, 279, -1), + (30050, -1, -1, 30050, 30050, 0, 1, -1, 0, 0, 0, -1, 30051), + (30100, -1, -1, 30100, 30100, 0, 1, -1, 0, 0, 0, -1, 30101), + (30150, -1, -1, 30150, 30150, 0, 1, -1, 0, 0, 0, -1, 30151), + (30175, -1, -1, 30175, 30175, 0, 1, -1, 0, 0, 0, -1, 30176), + (30180, -1, -1, 30180, 30180, 0, 1, -1, 0, 0, 0, -1, 30181), + (30185, -1, -1, 30185, 30185, 0, 1, -1, 0, 0, 0, -1, 30186), + (30190, -1, -1, 30190, 30190, 0, 1, -1, 0, 0, 0, -1, 30191), + (30195, -1, -1, 30195, 30195, 0, 1, -1, 0, 0, 0, -1, 30196), + (49999, -1, -1, -1, -1, 0, 71, 0, 0, 0, 0, -1, 1); + +-- Dumping structure for table eqdb.aa_rank_effects +DROP TABLE IF EXISTS `aa_rank_effects`; +CREATE TABLE IF NOT EXISTS `aa_rank_effects` ( + `rank_id` int(10) unsigned NOT NULL, + `slot` int(10) unsigned NOT NULL DEFAULT '1', + `effect_id` int(10) NOT NULL DEFAULT '0', + `base1` int(10) NOT NULL DEFAULT '0', + `base2` int(10) NOT NULL DEFAULT '0', + PRIMARY KEY (`rank_id`,`slot`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `aa_rank_effects` (`rank_id`, `slot`, `effect_id`, `base1`, `base2`) VALUES + (2, 1, 4, 2, 0), + (3, 1, 4, 4, 0), + (4, 1, 4, 6, 0), + (5, 1, 4, 8, 0), + (6, 1, 4, 10, 0), + (7, 1, 7, 2, 0), + (8, 1, 7, 4, 0), + (9, 1, 7, 6, 0), + (10, 1, 7, 8, 0), + (11, 1, 7, 10, 0), + (12, 1, 6, 2, 0), + (13, 1, 6, 4, 0), + (14, 1, 6, 6, 0), + (15, 1, 6, 8, 0), + (16, 1, 6, 10, 0), + (17, 1, 5, 2, 0), + (18, 1, 5, 4, 0), + (19, 1, 5, 6, 0), + (20, 1, 5, 8, 0), + (21, 1, 5, 10, 0), + (22, 1, 8, 2, 0), + (23, 1, 8, 4, 0), + (24, 1, 8, 6, 0), + (25, 1, 8, 8, 0), + (26, 1, 8, 10, 0), + (27, 1, 9, 2, 0), + (28, 1, 9, 4, 0), + (29, 1, 9, 6, 0), + (30, 1, 9, 8, 0), + (31, 1, 9, 10, 0), + (32, 1, 10, 2, 0), + (33, 1, 10, 4, 0), + (34, 1, 10, 6, 0), + (35, 1, 10, 8, 0), + (36, 1, 10, 10, 0), + (37, 1, 46, 2, 0), + (38, 1, 46, 4, 0), + (39, 1, 46, 6, 0), + (40, 1, 46, 8, 0), + (41, 1, 46, 10, 0), + (42, 1, 47, 2, 0), + (43, 1, 47, 4, 0), + (44, 1, 47, 6, 0), + (45, 1, 47, 8, 0), + (46, 1, 47, 10, 0), + (47, 1, 50, 2, 0), + (48, 1, 50, 4, 0), + (49, 1, 50, 6, 0), + (50, 1, 50, 8, 0), + (51, 1, 50, 10, 0), + (52, 1, 48, 2, 0), + (53, 1, 48, 4, 0), + (54, 1, 48, 6, 0), + (55, 1, 48, 8, 0), + (56, 1, 48, 10, 0), + (57, 1, 49, 2, 0), + (58, 1, 49, 4, 0), + (59, 1, 49, 6, 0), + (60, 1, 49, 8, 0), + (61, 1, 49, 10, 0), + (62, 1, 271, 8, 0), + (63, 1, 271, 14, 0), + (64, 1, 271, 21, 0), + (68, 1, 233, 110, 0), + (69, 1, 233, 125, 0), + (70, 1, 233, 150, 0), + (71, 1, 246, 110, 0), + (72, 1, 246, 125, 0), + (73, 1, 246, 150, 0), + (74, 1, 269, 10, 0), + (75, 1, 269, 20, 0), + (76, 1, 269, 30, 0), + (77, 1, 125, 2, 2), + (77, 2, 137, 0, 0), + (77, 3, 141, 1, 0), + (77, 4, 139, -6233, 0), + (77, 5, 139, -6265, 0), + (77, 6, 125, 2, 2), + (77, 7, 137, 147, 0), + (77, 8, 141, 1, 0), + (78, 1, 125, 5, 5), + (78, 2, 137, 0, 0), + (78, 3, 141, 1, 0), + (78, 4, 139, -6233, 0), + (78, 5, 139, -6265, 0), + (78, 6, 125, 5, 5), + (78, 7, 137, 147, 0), + (78, 8, 141, 1, 0), + (79, 1, 125, 10, 10), + (79, 2, 137, 0, 0), + (79, 3, 141, 1, 0), + (79, 4, 139, -6233, 0), + (79, 5, 139, -6265, 0), + (79, 6, 125, 10, 10), + (79, 7, 137, 147, 0), + (79, 8, 141, 1, 0), + (80, 1, 274, 3, 0), + (81, 1, 274, 6, 0), + (82, 1, 274, 10, 0), + (83, 1, 132, 2, 2), + (84, 1, 132, 5, 5), + (85, 1, 132, 10, 10), + (86, 1, 128, 5, 5), + (86, 2, 138, 1, 0), + (86, 3, 140, 1, 0), + (86, 4, 139, -2741, 0), + (86, 5, 139, -16843, 0), + (86, 6, 385, -16192, 0), + (86, 7, 385, -10547, 0), + (86, 8, 385, -13543, 0), + (87, 1, 128, 15, 15), + (87, 2, 138, 1, 0), + (87, 3, 140, 1, 0), + (87, 4, 139, -2741, 0), + (87, 5, 139, -16843, 0), + (87, 6, 385, -16192, 0), + (87, 7, 385, -10547, 0), + (87, 8, 385, -13543, 0), + (88, 1, 128, 30, 30), + (88, 2, 138, 1, 0), + (88, 3, 140, 1, 0), + (88, 4, 139, -2741, 0), + (88, 5, 139, -16843, 0), + (88, 6, 385, -16192, 0), + (88, 7, 385, -10547, 0), + (88, 8, 385, -13543, 0), + (92, 1, 294, 2, 100), + (93, 1, 294, 4, 100), + (94, 1, 294, 7, 100), + (98, 1, 114, -5, 0), + (99, 1, 114, -10, 0), + (100, 1, 114, -20, 0), + (101, 1, 265, 20, 0), + (102, 1, 265, 40, 0), + (103, 1, 265, 52, 0), + (104, 1, 127, 10, 10), + (104, 2, 138, 1, 0), + (104, 3, 140, 1, 0), + (104, 4, 143, 3000, 0), + (105, 1, 127, 25, 25), + (105, 2, 138, 1, 0), + (105, 3, 140, 1, 0), + (105, 4, 143, 3000, 0), + (106, 1, 127, 50, 50), + (106, 2, 138, 1, 0), + (106, 3, 140, 1, 0), + (106, 4, 143, 3000, 0), + (107, 1, 214, 200, 0), + (108, 1, 214, 500, 0), + (109, 1, 214, 1000, 0), + (110, 1, 0, 1, 0), + (111, 1, 0, 2, 0), + (112, 1, 0, 3, 0), + (113, 1, 169, 15, -1), + (114, 1, 169, 40, -1), + (115, 1, 169, 75, -1), + (116, 1, 181, 5, 0), + (117, 1, 181, 10, 0), + (118, 1, 181, 25, 0), + (119, 1, 278, 500, 16000), + (119, 2, 440, 50, 100), + (120, 1, 278, 510, 17102), + (120, 2, 440, 52, 100), + (121, 1, 278, 520, 19635), + (121, 2, 440, 54, 100), + (122, 1, 259, 2, 0), + (123, 1, 259, 5, 0), + (124, 1, 259, 10, 0), + (125, 1, 172, 2, 0), + (126, 1, 172, 5, 0), + (127, 1, 172, 10, 0), + (137, 1, 127, 10, 10), + (137, 2, 137, 88, 0), + (138, 1, 127, 25, 25), + (138, 2, 137, 88, 0), + (139, 1, 127, 50, 50), + (139, 2, 137, 88, 0), + (141, 1, 127, 2, 2), + (141, 2, 137, 0, 0), + (141, 3, 138, 0, 0), + (141, 4, 141, 1, 0), + (141, 5, 143, 3000, 0), + (141, 6, 127, 2, 2), + (141, 7, 385, 16555, 0), + (141, 8, 385, 16655, 0), + (142, 1, 127, 5, 5), + (142, 2, 137, 0, 0), + (142, 3, 138, 0, 0), + (142, 4, 141, 1, 0), + (142, 5, 143, 3000, 0), + (142, 6, 127, 5, 5), + (142, 7, 385, 16555, 0), + (142, 8, 385, 16655, 0), + (143, 1, 127, 10, 10), + (143, 2, 137, 0, 0), + (143, 3, 138, 0, 0), + (143, 4, 141, 1, 0), + (143, 5, 143, 3000, 0), + (143, 6, 127, 10, 10), + (143, 7, 385, 16555, 0), + (143, 8, 385, 16655, 0), + (144, 1, 244, 50, 0), + (147, 1, 127, 10, 10), + (147, 2, 138, 1, 0), + (147, 3, 140, 1, 0), + (147, 4, 143, 3000, 0), + (148, 1, 127, 25, 25), + (148, 2, 138, 1, 0), + (148, 3, 140, 1, 0), + (148, 4, 143, 3000, 0), + (149, 1, 127, 50, 50), + (149, 2, 138, 1, 0), + (149, 3, 140, 1, 0), + (149, 4, 143, 3000, 0), + (150, 1, 268, 10, 59), + (151, 1, 268, 25, 59), + (152, 1, 268, 50, 59), + (158, 1, 238, 1, 0), + (159, 1, 268, 10, 68), + (160, 1, 268, 25, 68), + (161, 1, 268, 50, 68), + (182, 1, 131, 100, 0), + (182, 2, 137, 33, 0), + (190, 1, 219, 225, 680), + (191, 1, 219, 235, 1190), + (192, 1, 219, 240, 1700), + (195, 1, 181, 100, 0), + (196, 1, 226, 1, 0), + (198, 1, 276, 32, 0), + (199, 1, 301, 30, 0), + (200, 1, 301, 60, 0), + (201, 1, 301, 100, 0), + (205, 1, 251, 100, 0), + (210, 1, 302, 50, 50), + (210, 2, 385, 99, 0), + (211, 1, 302, 100, 100), + (211, 2, 385, 99, 0), + (212, 1, 302, 200, 200), + (212, 2, 385, 99, 0), + (213, 1, 260, 2, 23), + (213, 2, 260, 2, 24), + (213, 3, 260, 2, 25), + (213, 4, 260, 2, 26), + (214, 1, 260, 4, 23), + (214, 2, 260, 4, 24), + (214, 3, 260, 4, 25), + (214, 4, 260, 4, 26), + (215, 1, 260, 6, 23), + (215, 2, 260, 6, 24), + (215, 3, 260, 6, 25), + (215, 4, 260, 6, 26), + (225, 1, 272, 1, 0), + (226, 1, 272, 3, 0), + (227, 1, 272, 5, 0), + (230, 1, 275, 10, 0), + (231, 1, 275, 20, 0), + (232, 1, 275, 30, 0), + (237, 1, 227, 1, 25), + (238, 1, 227, 3, 25), + (239, 1, 227, 5, 25), + (240, 1, 224, 20, 26), + (240, 2, 173, 1, 0), + (241, 1, 224, 35, 26), + (241, 2, 173, 2, 0), + (242, 1, 224, 50, 26), + (242, 2, 173, 3, 0), + (244, 1, 268, 10, 56), + (244, 2, 234, 7500, 0), + (245, 1, 268, 25, 56), + (245, 2, 234, 5000, 0), + (246, 1, 268, 50, 56), + (246, 2, 234, 2500, 0), + (247, 1, 224, 15, 0), + (248, 1, 224, 30, 0), + (249, 1, 224, 50, 0), + (255, 1, 279, 7, 0), + (256, 1, 279, 11, 0), + (257, 1, 279, 15, 0), + (263, 1, 282, 10, 0), + (264, 1, 282, 25, 0), + (265, 1, 282, 50, 0), + (266, 1, 128, 50, 50), + (266, 2, 138, 1, 0), + (266, 3, 140, 1, 0), + (266, 4, 139, -2741, 0), + (266, 5, 139, -16843, 0), + (266, 6, 385, -16192, 0), + (266, 7, 385, -10547, 0), + (266, 8, 385, -13543, 0), + (267, 1, 294, 2, 100), + (268, 1, 294, 4, 100), + (269, 1, 294, 6, 100), + (273, 1, 288, 1000, 21), + (275, 1, 260, 2, 50), + (276, 1, 260, 4, 50), + (277, 1, 260, 6, 50), + (278, 1, 0, 1, 0), + (278, 2, 15, 1, 0), + (279, 1, 214, 200, 0), + (279, 2, 259, 2, 0), + (279, 3, 172, 2, 0), + (280, 1, 227, 1, 62), + (280, 2, 227, 1, 17), + (281, 1, 227, 3, 62), + (281, 2, 227, 3, 17), + (282, 1, 227, 5, 62), + (282, 2, 227, 5, 17), + (283, 1, 228, 10, 0), + (284, 1, 228, 20, 0), + (285, 1, 228, 30, 0), + (286, 1, 10, 0, 0), + (287, 1, 253, 1, 0), + (288, 1, 257, 1, 0), + (288, 2, 267, 1, 31), + (288, 3, 267, 1, 32), + (288, 4, 267, 1, 33), + (288, 5, 267, 1, 15), + (288, 6, 267, 1, 16), + (288, 7, 267, 1, 17), + (288, 8, 267, 1, 18), + (288, 9, 267, 1, 19), + (288, 10, 267, 1, 20), + (292, 1, 4, 12, 0), + (293, 1, 4, 14, 0), + (294, 1, 4, 16, 0), + (295, 1, 4, 18, 0), + (296, 1, 4, 20, 0), + (297, 1, 4, 22, 0), + (298, 1, 4, 24, 0), + (299, 1, 4, 26, 0), + (300, 1, 4, 28, 0), + (301, 1, 4, 30, 0), + (302, 1, 7, 12, 0), + (303, 1, 7, 14, 0), + (304, 1, 7, 16, 0), + (305, 1, 7, 18, 0), + (306, 1, 7, 20, 0), + (307, 1, 7, 22, 0), + (308, 1, 7, 24, 0), + (309, 1, 7, 26, 0), + (310, 1, 7, 28, 0), + (311, 1, 7, 30, 0), + (312, 1, 6, 12, 0), + (313, 1, 6, 14, 0), + (314, 1, 6, 16, 0), + (315, 1, 6, 18, 0), + (316, 1, 6, 20, 0), + (317, 1, 6, 22, 0), + (318, 1, 6, 24, 0), + (319, 1, 6, 26, 0), + (320, 1, 6, 28, 0), + (321, 1, 6, 30, 0), + (322, 1, 5, 12, 0), + (323, 1, 5, 14, 0), + (324, 1, 5, 16, 0), + (325, 1, 5, 18, 0), + (326, 1, 5, 20, 0), + (327, 1, 5, 22, 0), + (328, 1, 5, 24, 0), + (329, 1, 5, 26, 0), + (330, 1, 5, 28, 0), + (331, 1, 5, 30, 0), + (332, 1, 8, 12, 0), + (333, 1, 8, 14, 0), + (334, 1, 8, 16, 0), + (335, 1, 8, 18, 0), + (336, 1, 8, 20, 0), + (337, 1, 8, 22, 0), + (338, 1, 8, 24, 0), + (339, 1, 8, 26, 0), + (340, 1, 8, 28, 0), + (341, 1, 8, 30, 0), + (342, 1, 9, 12, 0), + (343, 1, 9, 14, 0), + (344, 1, 9, 16, 0), + (345, 1, 9, 18, 0), + (346, 1, 9, 20, 0), + (347, 1, 9, 22, 0), + (348, 1, 9, 24, 0), + (349, 1, 9, 26, 0), + (350, 1, 9, 28, 0), + (351, 1, 9, 30, 0), + (352, 1, 10, 12, 0), + (353, 1, 10, 14, 0), + (354, 1, 10, 16, 0), + (355, 1, 10, 18, 0), + (356, 1, 10, 20, 0), + (357, 1, 10, 22, 0), + (358, 1, 10, 24, 0), + (359, 1, 10, 26, 0), + (360, 1, 10, 28, 0), + (361, 1, 10, 30, 0), + (362, 1, 46, 12, 0), + (363, 1, 46, 14, 0), + (364, 1, 46, 16, 0), + (365, 1, 46, 18, 0), + (366, 1, 46, 20, 0), + (367, 1, 46, 22, 0), + (368, 1, 46, 24, 0), + (369, 1, 46, 26, 0), + (370, 1, 46, 28, 0), + (371, 1, 46, 30, 0), + (372, 1, 47, 12, 0), + (373, 1, 47, 14, 0), + (374, 1, 47, 16, 0), + (375, 1, 47, 18, 0), + (376, 1, 47, 20, 0), + (377, 1, 47, 22, 0), + (378, 1, 47, 24, 0), + (379, 1, 47, 26, 0), + (380, 1, 47, 28, 0), + (381, 1, 47, 30, 0), + (382, 1, 50, 12, 0), + (383, 1, 50, 14, 0), + (384, 1, 50, 16, 0), + (385, 1, 50, 18, 0), + (386, 1, 50, 20, 0), + (387, 1, 50, 22, 0), + (388, 1, 50, 24, 0), + (389, 1, 50, 26, 0), + (390, 1, 50, 28, 0), + (391, 1, 50, 30, 0), + (392, 1, 48, 12, 0), + (393, 1, 48, 14, 0), + (394, 1, 48, 16, 0), + (395, 1, 48, 18, 0), + (396, 1, 48, 20, 0), + (397, 1, 48, 22, 0), + (398, 1, 48, 24, 0), + (399, 1, 48, 26, 0), + (400, 1, 48, 28, 0), + (401, 1, 48, 30, 0), + (402, 1, 49, 12, 0), + (403, 1, 49, 14, 0), + (404, 1, 49, 16, 0), + (405, 1, 49, 18, 0), + (406, 1, 49, 20, 0), + (407, 1, 49, 22, 0), + (408, 1, 49, 24, 0), + (409, 1, 49, 26, 0), + (410, 1, 49, 28, 0), + (411, 1, 49, 30, 0), + (412, 1, 263, 1, 0), + (413, 1, 263, 2, 0), + (414, 1, 263, 3, 0), + (415, 1, 263, 4, 0), + (416, 1, 263, 5, 0), + (417, 1, 263, 6, 0), + (418, 1, 262, 5, 0), + (418, 2, 262, 5, 1), + (418, 3, 262, 5, 2), + (418, 4, 262, 5, 3), + (418, 5, 262, 5, 4), + (418, 6, 262, 5, 5), + (418, 7, 262, 5, 6), + (419, 1, 262, 10, 0), + (419, 2, 262, 10, 1), + (419, 3, 262, 10, 2), + (419, 4, 262, 10, 3), + (419, 5, 262, 10, 4), + (419, 6, 262, 10, 5), + (419, 7, 262, 10, 6), + (420, 1, 262, 15, 0), + (420, 2, 262, 15, 1), + (420, 3, 262, 15, 2), + (420, 4, 262, 15, 3), + (420, 5, 262, 15, 4), + (420, 6, 262, 15, 5), + (420, 7, 262, 15, 6), + (421, 1, 262, 20, 0), + (421, 2, 262, 20, 1), + (421, 3, 262, 20, 2), + (421, 4, 262, 20, 3), + (421, 5, 262, 20, 4), + (421, 6, 262, 20, 5), + (421, 7, 262, 20, 6), + (422, 1, 262, 25, 0), + (422, 2, 262, 25, 1), + (422, 3, 262, 25, 2), + (422, 4, 262, 25, 3), + (422, 5, 262, 25, 4), + (422, 6, 262, 25, 5), + (422, 7, 262, 25, 6), + (423, 1, 214, 150, 0), + (424, 1, 214, 300, 0), + (425, 1, 214, 450, 0), + (426, 1, 262, 10, 5), + (426, 2, 262, 10, 4), + (427, 1, 262, 20, 5), + (427, 2, 262, 20, 4), + (428, 1, 262, 30, 5), + (428, 2, 262, 30, 4), + (429, 1, 262, 40, 5), + (429, 2, 262, 40, 4), + (430, 1, 262, 50, 5), + (430, 2, 262, 50, 4), + (434, 1, 125, 13, 13), + (434, 2, 137, 0, 0), + (434, 3, 141, 1, 0), + (434, 4, 139, -6233, 0), + (434, 5, 139, -6265, 0), + (434, 6, 125, 13, 13), + (434, 7, 137, 147, 0), + (434, 8, 141, 1, 0), + (435, 1, 125, 16, 16), + (435, 2, 137, 0, 0), + (435, 3, 141, 1, 0), + (435, 4, 139, -6233, 0), + (435, 5, 139, -6265, 0), + (435, 6, 125, 16, 16), + (435, 7, 137, 147, 0), + (435, 8, 141, 1, 0), + (436, 1, 125, 19, 19), + (436, 2, 137, 0, 0), + (436, 3, 141, 1, 0), + (436, 4, 139, -6233, 0), + (436, 5, 139, -6265, 0), + (436, 6, 125, 19, 19), + (436, 7, 137, 147, 0), + (436, 8, 141, 1, 0), + (437, 1, 274, 12, 0), + (438, 1, 274, 14, 0), + (439, 1, 274, 16, 0), + (440, 1, 278, 530, 21210), + (440, 2, 440, 56, 100), + (441, 1, 278, 540, 23160), + (441, 2, 440, 58, 100), + (442, 1, 278, 550, 25230), + (442, 2, 440, 60, 100), + (443, 1, 169, 100, -1), + (444, 1, 169, 125, -1), + (445, 1, 169, 150, -1), + (446, 1, 265, 54, 0), + (447, 1, 265, 56, 0), + (448, 1, 265, 58, 0), + (449, 1, 172, 13, 0), + (450, 1, 172, 16, 0), + (451, 1, 172, 19, 0), + (452, 1, 172, 22, 0), + (453, 1, 172, 25, 0), + (454, 1, 259, 13, 0), + (455, 1, 259, 16, 0), + (456, 1, 259, 19, 0), + (457, 1, 259, 22, 0), + (458, 1, 259, 25, 0), + (462, 1, 264, 60, 39), + (462, 2, 264, 864, 1061), + (463, 1, 264, 120, 39), + (463, 2, 264, 1728, 1061), + (464, 1, 264, 180, 39), + (464, 2, 264, 2592, 1061), + (468, 1, 264, 180, 41), + (469, 1, 264, 360, 41), + (470, 1, 264, 540, 41), + (471, 1, 264, 864, 57), + (471, 2, 264, 864, 616), + (472, 1, 264, 1728, 57), + (472, 2, 264, 1728, 616), + (473, 1, 264, 2592, 57), + (473, 2, 264, 2592, 616), + (474, 1, 264, 240, 50), + (475, 1, 264, 480, 50), + (476, 1, 264, 720, 50), + (477, 1, 264, 432, 43), + (478, 1, 264, 864, 43), + (479, 1, 264, 1296, 43), + (480, 1, 264, 432, 117), + (481, 1, 264, 864, 117), + (482, 1, 264, 1296, 117), + (483, 1, 264, 540, 58), + (483, 2, 264, 540, 418), + (484, 1, 264, 1080, 58), + (484, 2, 264, 1080, 418), + (485, 1, 264, 1620, 58), + (485, 2, 264, 1620, 418), + (489, 1, 264, 90, 110), + (490, 1, 264, 180, 110), + (491, 1, 264, 270, 110), + (492, 1, 264, 60, 109), + (493, 1, 264, 120, 109), + (494, 1, 264, 180, 109), + (495, 1, 264, 180, 98), + (496, 1, 264, 360, 98), + (497, 1, 264, 540, 98), + (498, 1, 264, 144, 102), + (499, 1, 264, 288, 102), + (500, 1, 264, 432, 102), + (501, 1, 264, 432, 107), + (502, 1, 264, 864, 107), + (503, 1, 264, 1296, 107), + (504, 1, 224, 110, 0), + (505, 1, 224, 120, 0), + (506, 1, 224, 130, 0), + (537, 1, 282, 60, 0), + (538, 1, 282, 75, 0), + (539, 1, 275, 68, 0), + (540, 1, 275, 76, 0), + (541, 1, 275, 84, 0), + (542, 1, 279, 17, 0), + (543, 1, 279, 19, 0), + (544, 1, 279, 21, 0), + (551, 1, 225, 3, 0), + (552, 1, 225, 6, 0), + (553, 1, 225, 9, 0), + (554, 1, 225, 12, 0), + (555, 1, 225, 15, 0), + (556, 1, 225, 3, 0), + (557, 1, 225, 6, 0), + (558, 1, 225, 9, 0), + (559, 1, 225, 12, 0), + (560, 1, 225, 15, 0), + (561, 1, 177, 3, -1), + (562, 1, 177, 6, -1), + (563, 1, 177, 9, -1), + (564, 1, 177, 3, -1), + (565, 1, 177, 6, -1), + (566, 1, 177, 9, -1), + (567, 1, 244, -12, 0), + (574, 1, 281, 25, 0), + (575, 1, 281, 50, 0), + (576, 1, 281, 75, 0), + (577, 1, 277, 20, 0), + (578, 1, 277, 40, 0), + (579, 1, 277, 60, 0), + (580, 1, 267, 1, 4), + (580, 2, 267, 1, 5), + (580, 3, 267, 1, 29), + (581, 1, 267, 1, 2), + (581, 2, 267, 1, 3), + (581, 3, 267, 1, 4), + (581, 4, 267, 1, 5), + (581, 5, 267, 1, 29), + (582, 1, 267, 1, 0), + (582, 2, 267, 1, 1), + (582, 3, 267, 1, 2), + (582, 4, 267, 1, 3), + (582, 5, 267, 1, 4), + (582, 6, 267, 1, 4), + (582, 7, 267, 1, 5), + (582, 8, 267, 1, 6), + (582, 9, 267, 1, 7), + (582, 10, 267, 1, 8), + (582, 11, 267, 1, 9), + (582, 12, 267, 1, 10), + (582, 13, 267, 1, 11), + (582, 14, 267, 1, 12), + (582, 15, 267, 1, 13), + (582, 16, 267, 1, 14), + (582, 17, 267, 1, 28), + (582, 18, 267, 1, 29), + (582, 19, 267, 1, 30), + (583, 1, 264, 7, 73), + (583, 2, 264, 7, 702), + (583, 3, 264, 7, 3826), + (583, 4, 264, 7, 7712), + (584, 1, 264, 14, 73), + (584, 2, 264, 14, 702), + (584, 3, 264, 14, 3826), + (584, 4, 264, 14, 7712), + (585, 1, 264, 21, 73), + (585, 2, 264, 21, 702), + (585, 3, 264, 21, 3826), + (585, 4, 264, 21, 7712), + (586, 1, 255, 12, 0), + (587, 1, 255, 24, 0), + (588, 1, 255, 36, 0), + (589, 1, 303, 500, 500), + (589, 2, 139, 2766, 0), + (590, 1, 303, 1000, 1000), + (590, 2, 139, 2766, 0), + (591, 1, 303, 1500, 1500), + (591, 2, 139, 2766, 0), + (593, 1, 264, 720, 6001), + (593, 2, 264, 720, 3676), + (594, 1, 264, 1440, 6001), + (594, 2, 264, 1440, 3676), + (595, 1, 264, 2160, 6001), + (595, 2, 264, 2160, 3676), + (596, 1, 264, 720, 6000), + (596, 2, 264, 720, 87), + (597, 1, 264, 1440, 6000), + (597, 2, 264, 1440, 87), + (598, 1, 264, 2160, 6000), + (598, 2, 264, 2160, 87), + (599, 1, 266, 2, 0), + (600, 1, 266, 5, 0), + (601, 1, 266, 8, 0), + (602, 1, 266, 2, 0), + (603, 1, 266, 5, 0), + (604, 1, 266, 8, 0), + (605, 1, 256, 1, 0), + (606, 1, 285, 20, 0), + (607, 1, 285, 40, 0), + (608, 1, 285, 60, 0), + (609, 1, 285, 80, 0), + (610, 1, 285, 100, 0), + (611, 1, 283, 20, 0), + (612, 1, 283, 40, 0), + (613, 1, 283, 60, 0), + (614, 1, 283, 80, 0), + (615, 1, 283, 100, 0), + (622, 1, 227, 1, 29), + (622, 2, 227, 1, 42), + (623, 1, 227, 2, 29), + (623, 2, 227, 2, 42), + (624, 1, 227, 3, 29), + (624, 2, 227, 3, 42), + (625, 1, 294, 3, 100), + (626, 1, 294, 6, 100), + (627, 1, 294, 9, 100), + (628, 1, 290, 5, 0), + (629, 1, 290, 10, 0), + (631, 1, 292, 15, 0), + (632, 1, 292, 30, 0), + (633, 1, 292, 45, 0), + (634, 1, 274, 3, 0), + (635, 1, 274, 6, 0), + (636, 1, 274, 10, 0), + (637, 1, 294, 2, 100), + (638, 1, 294, 4, 100), + (639, 1, 294, 6, 100), + (640, 1, 294, 7, 100), + (641, 1, 294, 8, 100), + (642, 1, 294, 9, 100), + (644, 1, 217, 0, 32000), + (644, 2, 346, 59, 0), + (649, 1, 243, 15, 0), + (650, 1, 243, 25, 0), + (651, 1, 243, 35, 0), + (652, 1, 293, 25, 0), + (653, 1, 293, 50, 0), + (654, 1, 293, 75, 0), + (655, 1, 127, 10, 10), + (655, 2, 137, 32, 0), + (655, 3, 127, 10, 10), + (655, 4, 137, 33, 0), + (655, 5, 127, 10, 10), + (655, 6, 137, 82, 0), + (655, 7, 127, 2, 2), + (655, 8, 137, 152, 0), + (655, 9, 143, 3000, 0), + (656, 1, 127, 25, 25), + (656, 2, 137, 32, 0), + (656, 3, 127, 25, 25), + (656, 4, 137, 33, 0), + (656, 5, 127, 25, 25), + (656, 6, 137, 82, 0), + (656, 7, 127, 5, 5), + (656, 8, 137, 152, 0), + (656, 9, 143, 3000, 0), + (657, 1, 127, 50, 50), + (657, 2, 137, 32, 0), + (657, 3, 127, 50, 50), + (657, 4, 137, 33, 0), + (657, 5, 127, 50, 50), + (657, 6, 137, 82, 0), + (657, 7, 127, 10, 10), + (657, 8, 137, 152, 0), + (657, 9, 143, 3000, 0), + (658, 1, 15, 1, 0), + (659, 1, 15, 2, 0), + (660, 1, 15, 3, 0), + (661, 1, 0, 1, 0), + (662, 1, 0, 2, 0), + (663, 1, 0, 3, 0), + (665, 1, 270, 10, 0), + (666, 1, 270, 15, 0), + (667, 1, 270, 25, 0), + (668, 1, 270, 55, 0), + (669, 1, 270, 60, 0), + (670, 1, 270, 65, 0), + (671, 1, 241, 95, 0), + (672, 1, 271, 28, 0), + (673, 1, 271, 35, 0), + (674, 1, 0, 4, 0), + (675, 1, 0, 5, 0), + (676, 1, 246, 325, 0), + (677, 1, 246, 350, 0), + (678, 1, 221, 3, 0), + (679, 1, 221, 6, 0), + (680, 1, 221, 9, 0), + (681, 1, 221, 12, 0), + (682, 1, 221, 15, 0), + (683, 1, 189, 1, 0), + (684, 1, 189, 2, 0), + (685, 1, 189, 3, 0), + (686, 1, 200, 10, 0), + (687, 1, 200, 20, 0), + (688, 1, 200, 30, 0), + (689, 1, 200, 40, 0), + (690, 1, 200, 50, 0), + (691, 1, 248, 100, 0), + (692, 1, 229, 5, 0), + (693, 1, 229, 10, 0), + (694, 1, 229, 15, 0), + (695, 1, 247, 10, 53), + (696, 1, 247, 20, 53), + (697, 1, 247, 30, 53), + (698, 1, 247, 40, 53), + (699, 1, 247, 50, 53), + (700, 1, 260, 8, 23), + (700, 2, 260, 8, 24), + (700, 3, 260, 8, 25), + (700, 4, 260, 8, 26), + (701, 1, 260, 8, 50), + (724, 1, 218, 1, 0), + (725, 1, 218, 2, 0), + (726, 1, 218, 3, 0), + (727, 1, 218, 4, 0), + (728, 1, 218, 5, 0), + (729, 1, 280, 4, 0), + (730, 1, 280, 8, 0), + (731, 1, 280, 12, 0), + (732, 1, 280, 16, 0), + (733, 1, 280, 20, 0), + (734, 1, 237, 1, 0), + (735, 1, 265, 54, 0), + (736, 1, 265, 56, 0), + (737, 1, 265, 58, 0), + (738, 1, 114, -5, 0), + (739, 1, 114, -10, 0), + (740, 1, 114, -20, 0), + (754, 1, 264, 18, 153), + (755, 1, 264, 36, 153), + (756, 1, 264, 54, 153), + (762, 1, 247, 10, 53), + (763, 1, 247, 20, 53), + (764, 1, 247, 30, 53), + (765, 1, 247, 40, 53), + (766, 1, 247, 50, 53), + (767, 1, 273, 3, 0), + (768, 1, 273, 6, 0), + (769, 1, 273, 9, 0), + (770, 1, 294, 7, 100), + (771, 1, 294, 8, 100), + (772, 1, 294, 9, 100), + (776, 1, 242, 10, 0), + (777, 1, 242, 20, 0), + (778, 1, 242, 30, 0), + (779, 1, 242, 40, 0), + (780, 1, 242, 50, 0), + (781, 1, 287, 1, 1), + (781, 2, 137, 31, 0), + (781, 3, 136, 5, 0), + (782, 1, 264, 432, 35), + (783, 1, 264, 864, 35), + (784, 1, 264, 1296, 35), + (790, 1, 218, 1, 0), + (791, 1, 218, 2, 0), + (792, 1, 218, 3, 0), + (793, 1, 218, 4, 0), + (794, 1, 218, 5, 0), + (795, 1, 280, 4, 0), + (796, 1, 280, 8, 0), + (797, 1, 280, 12, 0), + (798, 1, 280, 16, 0), + (799, 1, 280, 20, 0), + (800, 1, 215, 2, 0), + (801, 1, 215, 5, 0), + (802, 1, 215, 10, 0), + (803, 1, 213, 2, 0), + (804, 1, 213, 5, 0), + (805, 1, 213, 10, 0), + (806, 1, 249, 1, 0), + (807, 1, 292, 5, 0), + (808, 1, 292, 10, 0), + (809, 1, 292, 15, 0), + (810, 1, 239, 10, 0), + (811, 1, 239, 20, 0), + (812, 1, 239, 30, 0), + (813, 1, 239, 40, 0), + (814, 1, 239, 50, 0), + (815, 1, 279, 7, 0), + (816, 1, 279, 11, 0), + (817, 1, 279, 15, 0), + (818, 1, 279, 17, 0), + (819, 1, 279, 19, 0), + (820, 1, 220, 10, 26), + (820, 2, 220, 10, 30), + (820, 3, 220, 10, 38), + (821, 1, 220, 20, 26), + (821, 2, 220, 20, 30), + (821, 3, 220, 20, 38), + (822, 1, 220, 30, 26), + (822, 2, 220, 30, 30), + (822, 3, 220, 30, 38), + (823, 1, 222, 20, 0), + (824, 1, 222, 40, 0), + (825, 1, 222, 60, 0), + (826, 1, 222, 80, 0), + (827, 1, 222, 100, 0), + (834, 1, 218, 1, 0), + (835, 1, 218, 2, 0), + (836, 1, 218, 3, 0), + (837, 1, 218, 4, 0), + (838, 1, 218, 5, 0), + (839, 1, 280, 4, 0), + (840, 1, 280, 8, 0), + (841, 1, 280, 12, 0), + (842, 1, 280, 16, 0), + (843, 1, 280, 20, 0), + (844, 1, 274, 12, 0), + (845, 1, 274, 14, 0), + (846, 1, 258, 5, 0), + (847, 1, 258, 10, 0), + (848, 1, 258, 15, 0), + (849, 1, 264, 240, 180), + (850, 1, 264, 480, 180), + (851, 1, 264, 720, 180), + (852, 1, 231, 1, 0), + (853, 1, 231, 2, 0), + (854, 1, 231, 3, 0), + (855, 1, 220, 5, 10), + (856, 1, 220, 10, 10), + (857, 1, 220, 15, 10), + (858, 1, 220, 20, 10), + (859, 1, 220, 25, 10), + (864, 1, 216, 10, 0), + (864, 2, 216, 10, 1), + (864, 3, 216, 10, 2), + (864, 4, 216, 10, 3), + (864, 5, 216, 10, 10), + (864, 6, 216, 10, 28), + (864, 7, 216, 10, 30), + (864, 8, 216, 10, 36), + (864, 9, 216, 10, 77), + (865, 1, 216, 20, 0), + (865, 2, 216, 20, 1), + (865, 3, 216, 20, 2), + (865, 4, 216, 20, 3), + (865, 5, 216, 20, 10), + (865, 6, 216, 20, 28), + (865, 7, 216, 20, 30), + (865, 8, 216, 20, 36), + (865, 9, 216, 20, 77), + (866, 1, 216, 30, 0), + (866, 2, 216, 30, 1), + (866, 3, 216, 30, 2), + (866, 4, 216, 30, 3), + (866, 5, 216, 30, 10), + (866, 6, 216, 30, 28), + (866, 7, 216, 30, 30), + (866, 8, 216, 30, 36), + (866, 9, 216, 30, 77), + (867, 1, 59, -3, 0), + (868, 1, 59, -6, 0), + (869, 1, 59, -9, 0), + (870, 1, 59, -12, 0), + (871, 1, 59, -15, 0), + (878, 1, 252, 10, 0), + (879, 1, 252, 20, 0), + (880, 1, 252, 30, 0), + (881, 1, 245, 10, 0), + (882, 1, 245, 20, 0), + (883, 1, 245, 30, 0), + (884, 1, 245, 40, 0), + (885, 1, 245, 50, 0), + (886, 1, 264, 576, 102), + (887, 1, 264, 720, 102), + (888, 1, 250, 10, 0), + (889, 1, 250, 20, 0), + (890, 1, 250, 30, 0), + (891, 1, 250, 40, 0), + (892, 1, 250, 50, 0), + (893, 1, 303, 2000, 2000), + (893, 2, 139, 2766, 0), + (894, 1, 303, 2500, 2500), + (894, 2, 139, 2766, 0), + (895, 1, 59, -3, 0), + (896, 1, 59, -6, 0), + (897, 1, 59, -9, 0), + (898, 1, 59, -12, 0), + (899, 1, 59, -15, 0), + (907, 1, 69, 100, 0), + (908, 1, 69, 200, 0), + (909, 1, 69, 300, 0), + (910, 1, 69, 400, 0), + (911, 1, 69, 500, 0), + (915, 1, 220, 5, 10), + (915, 2, 220, 5, 30), + (916, 1, 220, 10, 10), + (916, 2, 220, 10, 30), + (917, 1, 220, 15, 10), + (917, 2, 220, 15, 30), + (918, 1, 230, 2, 0), + (919, 1, 230, 4, 0), + (920, 1, 230, 6, 0), + (924, 1, 294, 10, 100), + (925, 1, 294, 11, 100), + (934, 1, 169, 15, -1), + (935, 1, 169, 30, -1), + (936, 1, 169, 60, -1), + (937, 1, 169, 15, 0), + (937, 2, 169, 15, 1), + (937, 3, 169, 15, 2), + (937, 4, 169, 15, 3), + (937, 5, 169, 15, 7), + (937, 6, 169, 15, 8), + (937, 7, 169, 15, 10), + (937, 8, 169, 15, 28), + (937, 9, 169, 15, 30), + (937, 10, 169, 15, 36), + (937, 11, 169, 15, 51), + (938, 1, 169, 40, 0), + (938, 2, 169, 40, 1), + (938, 3, 169, 40, 2), + (938, 4, 169, 40, 3), + (938, 5, 169, 40, 7), + (938, 6, 169, 40, 8), + (938, 7, 169, 40, 10), + (938, 8, 169, 40, 28), + (938, 9, 169, 40, 30), + (938, 10, 169, 40, 36), + (938, 11, 169, 30, 51), + (939, 1, 169, 75, 0), + (939, 2, 169, 75, 1), + (939, 3, 169, 75, 2), + (939, 4, 169, 75, 3), + (939, 5, 169, 75, 7), + (939, 6, 169, 75, 8), + (939, 7, 169, 75, 10), + (939, 8, 169, 75, 28), + (939, 9, 169, 75, 30), + (939, 10, 169, 75, 36), + (939, 11, 169, 60, 51), + (940, 1, 169, 15, 0), + (940, 2, 169, 15, 1), + (940, 3, 169, 15, 2), + (940, 4, 169, 15, 3), + (940, 5, 169, 15, 7), + (940, 6, 169, 15, 8), + (940, 7, 169, 15, 10), + (940, 8, 169, 15, 28), + (940, 9, 169, 15, 30), + (940, 10, 169, 15, 36), + (940, 11, 169, 15, 51), + (940, 12, 169, 15, 77), + (941, 1, 169, 40, 0), + (941, 2, 169, 40, 1), + (941, 3, 169, 40, 2), + (941, 4, 169, 40, 3), + (941, 5, 169, 30, 7), + (941, 6, 169, 40, 8), + (941, 7, 169, 40, 10), + (941, 8, 169, 40, 28), + (941, 9, 169, 40, 30), + (941, 10, 169, 40, 36), + (941, 11, 169, 40, 51), + (941, 12, 169, 40, 77), + (942, 1, 169, 75, 0), + (942, 2, 169, 75, 1), + (942, 3, 169, 75, 2), + (942, 4, 169, 75, 3), + (942, 5, 169, 60, 7), + (942, 6, 169, 75, 8), + (942, 7, 169, 75, 10), + (942, 8, 169, 75, 28), + (942, 9, 169, 75, 30), + (942, 10, 169, 75, 36), + (942, 11, 169, 75, 51), + (942, 12, 169, 75, 77), + (943, 1, 169, 146, -1), + (944, 1, 169, 172, -1), + (945, 1, 169, 198, -1), + (946, 1, 169, 175, 0), + (946, 2, 169, 175, 1), + (946, 3, 169, 175, 2), + (946, 4, 169, 175, 3), + (946, 5, 169, 175, 7), + (946, 6, 169, 175, 8), + (946, 7, 169, 175, 10), + (946, 8, 169, 175, 28), + (946, 9, 169, 175, 30), + (946, 10, 169, 175, 36), + (946, 11, 169, 146, 51), + (947, 1, 169, 200, 0), + (947, 2, 169, 200, 1), + (947, 3, 169, 200, 2), + (947, 4, 169, 200, 3), + (947, 5, 169, 200, 7), + (947, 6, 169, 200, 8), + (947, 7, 169, 200, 10), + (947, 8, 169, 200, 28), + (947, 9, 169, 200, 30), + (947, 10, 169, 200, 36), + (947, 11, 169, 172, 51), + (948, 1, 169, 225, 0), + (948, 2, 169, 225, 1), + (948, 3, 169, 225, 2), + (948, 4, 169, 225, 3), + (948, 5, 169, 225, 7), + (948, 6, 169, 225, 8), + (948, 7, 169, 225, 10), + (948, 8, 169, 225, 28), + (948, 9, 169, 225, 30), + (948, 10, 169, 225, 36), + (948, 11, 169, 198, 51), + (949, 1, 169, 175, 0), + (949, 2, 169, 175, 1), + (949, 3, 169, 175, 2), + (949, 4, 169, 175, 3), + (949, 5, 169, 161, 7), + (949, 6, 169, 175, 8), + (949, 7, 169, 175, 10), + (949, 8, 169, 175, 28), + (949, 9, 169, 175, 30), + (949, 10, 169, 175, 36), + (949, 11, 169, 175, 51), + (949, 12, 169, 175, 77), + (950, 1, 169, 200, 0), + (950, 2, 169, 200, 1), + (950, 3, 169, 200, 2), + (950, 4, 169, 200, 3), + (950, 5, 169, 187, 7), + (950, 6, 169, 200, 8), + (950, 7, 169, 200, 10), + (950, 8, 169, 200, 28), + (950, 9, 169, 200, 30), + (950, 10, 169, 200, 36), + (950, 11, 169, 200, 51), + (950, 12, 169, 200, 77), + (951, 1, 169, 225, 0), + (951, 2, 169, 225, 1), + (951, 3, 169, 225, 2), + (951, 4, 169, 225, 3), + (951, 5, 169, 213, 7), + (951, 6, 169, 225, 8), + (951, 7, 169, 225, 10), + (951, 8, 169, 225, 28), + (951, 9, 169, 225, 30), + (951, 10, 169, 225, 36), + (951, 11, 169, 225, 51), + (951, 12, 169, 225, 77), + (952, 1, 214, 125, 0), + (953, 1, 214, 250, 0), + (954, 1, 214, 375, 0), + (955, 1, 262, 10, 4), + (955, 2, 262, 10, 5), + (956, 1, 262, 20, 4), + (956, 2, 262, 20, 5), + (957, 1, 262, 30, 4), + (957, 2, 262, 30, 5), + (958, 1, 262, 40, 4), + (958, 2, 262, 40, 5), + (959, 1, 262, 50, 4), + (959, 2, 262, 50, 5), + (962, 1, 232, 2, 4544), + (963, 1, 232, 4, 4544), + (964, 1, 232, 6, 4544), + (965, 1, 232, 8, 4544), + (966, 1, 232, 10, 4544), + (975, 1, 264, 864, 102), + (976, 1, 131, 100, 0), + (976, 2, 137, 33, 0), + (978, 1, 14, 1, 0), + (978, 2, 246, 350, 0), + (979, 1, 268, 10, 63), + (980, 1, 268, 25, 63), + (981, 1, 268, 50, 63), + (982, 1, 268, 10, 60), + (983, 1, 268, 25, 60), + (984, 1, 268, 50, 60), + (985, 1, 268, 10, 65), + (986, 1, 268, 25, 65), + (987, 1, 268, 50, 65), + (988, 1, 268, 10, 64), + (989, 1, 268, 25, 64), + (990, 1, 268, 50, 64), + (991, 1, 268, 10, 69), + (992, 1, 268, 25, 69), + (993, 1, 268, 50, 69), + (994, 1, 268, 10, 61), + (995, 1, 268, 25, 61), + (996, 1, 268, 50, 61), + (997, 1, 331, 5, 0), + (998, 1, 331, 15, 0), + (999, 1, 331, 25, 0), + (1001, 1, 262, 30, 0), + (1001, 2, 262, 30, 1), + (1001, 3, 262, 30, 2), + (1001, 4, 262, 30, 3), + (1001, 5, 262, 30, 4), + (1001, 6, 262, 30, 5), + (1001, 7, 262, 30, 6), + (1002, 1, 262, 35, 0), + (1002, 2, 262, 35, 1), + (1002, 3, 262, 35, 2), + (1002, 4, 262, 35, 3), + (1002, 5, 262, 35, 4), + (1002, 6, 262, 35, 5), + (1002, 7, 262, 35, 6), + (1003, 1, 262, 40, 0), + (1003, 2, 262, 40, 1), + (1003, 3, 262, 40, 2), + (1003, 4, 262, 40, 3), + (1003, 5, 262, 40, 4), + (1003, 6, 262, 40, 5), + (1003, 7, 262, 40, 6), + (1004, 1, 262, 45, 0), + (1004, 2, 262, 45, 1), + (1004, 3, 262, 45, 2), + (1004, 4, 262, 45, 3), + (1004, 5, 262, 45, 4), + (1004, 6, 262, 45, 5), + (1004, 7, 262, 45, 6), + (1005, 1, 262, 50, 0), + (1005, 2, 262, 50, 1), + (1005, 3, 262, 50, 2), + (1005, 4, 262, 50, 3), + (1005, 5, 262, 50, 4), + (1005, 6, 262, 50, 5), + (1005, 7, 262, 50, 6), + (1006, 1, 262, 5, 7), + (1006, 2, 262, 5, 8), + (1006, 3, 262, 5, 9), + (1006, 4, 262, 5, 10), + (1006, 5, 262, 5, 11), + (1007, 1, 262, 10, 7), + (1007, 2, 262, 10, 8), + (1007, 3, 262, 10, 9), + (1007, 4, 262, 10, 10), + (1007, 5, 262, 10, 11), + (1008, 1, 262, 15, 7), + (1008, 2, 262, 15, 8), + (1008, 3, 262, 15, 9), + (1008, 4, 262, 15, 10), + (1008, 5, 262, 15, 11), + (1009, 1, 262, 20, 7), + (1009, 2, 262, 20, 8), + (1009, 3, 262, 20, 9), + (1009, 4, 262, 20, 10), + (1009, 5, 262, 20, 11), + (1010, 1, 262, 25, 7), + (1010, 2, 262, 25, 8), + (1010, 3, 262, 25, 9), + (1010, 4, 262, 25, 10), + (1010, 5, 262, 25, 11), + (1011, 1, 262, 8, 7), + (1011, 2, 262, 8, 8), + (1011, 3, 262, 8, 9), + (1011, 4, 262, 8, 10), + (1011, 5, 262, 8, 11), + (1012, 1, 262, 16, 7), + (1012, 2, 262, 16, 8), + (1012, 3, 262, 16, 9), + (1012, 4, 262, 16, 10), + (1012, 5, 262, 16, 11), + (1013, 1, 262, 24, 7), + (1013, 2, 262, 24, 8), + (1013, 3, 262, 24, 9), + (1013, 4, 262, 24, 10), + (1013, 5, 262, 24, 11), + (1014, 1, 262, 32, 7), + (1014, 2, 262, 32, 8), + (1014, 3, 262, 32, 9), + (1014, 4, 262, 32, 10), + (1014, 5, 262, 32, 11), + (1016, 1, 262, 50, 7), + (1016, 2, 262, 50, 8), + (1016, 3, 262, 50, 9), + (1016, 4, 262, 50, 10), + (1016, 5, 262, 50, 11), + (1021, 1, 327, 1, 0), + (1022, 1, 327, 2, 0), + (1023, 1, 327, 3, 0), + (1024, 1, 327, 4, 0), + (1025, 1, 327, 5, 0), + (1026, 1, 328, 50, 0), + (1027, 1, 328, 100, 0), + (1028, 1, 328, 150, 0), + (1029, 1, 328, 200, 0), + (1030, 1, 328, 250, 0), + (1031, 1, 0, 6, 0), + (1032, 1, 0, 7, 0), + (1033, 1, 0, 8, 0), + (1034, 1, 0, 9, 0), + (1035, 1, 0, 10, 0), + (1036, 1, 189, 4, 0), + (1037, 1, 189, 5, 0), + (1038, 1, 189, 6, 0), + (1041, 1, 330, 25, 0), + (1041, 2, 330, 25, 1), + (1041, 3, 330, 25, 2), + (1041, 4, 330, 25, 3), + (1041, 5, 330, 25, 28), + (1041, 6, 330, 25, 36), + (1041, 7, 330, 25, 77), + (1042, 1, 330, 50, 0), + (1042, 2, 330, 50, 1), + (1042, 3, 330, 50, 2), + (1042, 4, 330, 50, 3), + (1042, 5, 330, 50, 28), + (1042, 6, 330, 50, 36), + (1042, 7, 330, 50, 77), + (1043, 1, 330, 75, 0), + (1043, 2, 330, 75, 1), + (1043, 3, 330, 75, 2), + (1043, 4, 330, 75, 3), + (1043, 5, 330, 75, 28), + (1043, 6, 330, 75, 36), + (1043, 7, 330, 75, 77), + (1044, 1, 330, 25, 0), + (1044, 2, 330, 25, 1), + (1044, 3, 330, 25, 2), + (1044, 4, 330, 25, 3), + (1044, 5, 330, 25, 28), + (1044, 6, 330, 25, 36), + (1045, 1, 330, 50, 0), + (1045, 2, 330, 50, 1), + (1045, 3, 330, 50, 2), + (1045, 4, 330, 50, 3), + (1045, 5, 330, 50, 28), + (1045, 6, 330, 50, 36), + (1046, 1, 330, 75, 0), + (1046, 2, 330, 75, 1), + (1046, 3, 330, 75, 2), + (1046, 4, 330, 75, 3), + (1046, 5, 330, 75, 28), + (1046, 6, 330, 75, 36), + (1047, 1, 330, 25, 0), + (1047, 2, 330, 25, 1), + (1047, 3, 330, 25, 2), + (1047, 4, 330, 25, 3), + (1047, 5, 330, 25, 28), + (1047, 6, 330, 25, 36), + (1047, 7, 330, 25, 77), + (1048, 1, 330, 50, 0), + (1048, 2, 330, 50, 1), + (1048, 3, 330, 50, 2), + (1048, 4, 330, 50, 3), + (1048, 5, 330, 50, 28), + (1048, 6, 330, 50, 36), + (1048, 7, 330, 50, 77), + (1049, 1, 330, 75, 0), + (1049, 2, 330, 75, 1), + (1049, 3, 330, 75, 2), + (1049, 4, 330, 75, 3), + (1049, 5, 330, 75, 28), + (1049, 6, 330, 75, 36), + (1049, 7, 330, 75, 77), + (1050, 1, 330, 15, 0), + (1050, 2, 330, 15, 1), + (1050, 3, 330, 15, 2), + (1050, 4, 330, 15, 3), + (1050, 5, 330, 15, 28), + (1050, 6, 330, 15, 36), + (1050, 7, 330, 15, 77), + (1051, 1, 330, 30, 0), + (1051, 2, 330, 30, 1), + (1051, 3, 330, 30, 2), + (1051, 4, 330, 30, 3), + (1051, 5, 330, 30, 28), + (1051, 6, 330, 30, 36), + (1051, 7, 330, 30, 77), + (1052, 1, 330, 50, 0), + (1052, 2, 330, 50, 1), + (1052, 3, 330, 50, 2), + (1052, 4, 330, 50, 3), + (1052, 5, 330, 50, 28), + (1052, 6, 330, 50, 36), + (1052, 7, 330, 50, 77), + (1053, 1, 278, 560, 27200), + (1053, 2, 440, 61, 100), + (1054, 1, 278, 580, 30135), + (1054, 2, 440, 63, 100), + (1055, 1, 278, 600, 32780), + (1055, 2, 440, 65, 100), + (1056, 1, 317, 1, 0), + (1057, 1, 317, 2, 0), + (1058, 1, 317, 3, 0), + (1059, 1, 317, 4, 0), + (1060, 1, 317, 5, 0), + (1061, 1, 172, 26, 0), + (1062, 1, 172, 27, 0), + (1063, 1, 172, 28, 0), + (1064, 1, 172, 30, 0), + (1065, 1, 172, 32, 0), + (1066, 1, 259, 27, 0), + (1067, 1, 259, 29, 0), + (1068, 1, 259, 31, 0), + (1069, 1, 259, 33, 0), + (1070, 1, 259, 35, 0), + (1071, 1, 326, 1, 0), + (1072, 1, 318, 1, 0), + (1073, 1, 318, 2, 0), + (1074, 1, 318, 3, 0), + (1075, 1, 318, 4, 0), + (1076, 1, 318, 5, 0), + (1083, 1, 125, 22, 22), + (1083, 2, 137, 0, 0), + (1083, 3, 141, 1, 0), + (1083, 4, 139, -6233, 0), + (1083, 5, 139, -6265, 0), + (1083, 6, 125, 22, 22), + (1083, 7, 137, 147, 0), + (1083, 8, 141, 1, 0), + (1084, 1, 125, 25, 25), + (1084, 2, 137, 0, 0), + (1084, 3, 141, 1, 0), + (1084, 4, 139, -6233, 0), + (1084, 5, 139, -6265, 0), + (1084, 6, 125, 25, 25), + (1084, 7, 137, 147, 0), + (1084, 8, 141, 1, 0), + (1085, 1, 125, 28, 28), + (1085, 2, 137, 0, 0), + (1085, 3, 141, 1, 0), + (1085, 4, 139, -6233, 0), + (1085, 5, 139, -6265, 0), + (1085, 6, 125, 28, 28), + (1085, 7, 137, 147, 0), + (1085, 8, 141, 1, 0), + (1086, 1, 274, 18, 0), + (1087, 1, 274, 20, 0), + (1088, 1, 274, 22, 0), + (1089, 1, 268, 10, 58), + (1090, 1, 268, 25, 58), + (1091, 1, 268, 50, 58), + (1092, 1, 238, 1, 0), + (1093, 1, 304, -20, 0), + (1094, 1, 304, -40, 0), + (1095, 1, 304, -60, 0), + (1096, 1, 304, -80, 0), + (1097, 1, 304, -100, 0), + (1099, 1, 273, 12, 0), + (1100, 1, 273, 15, 0), + (1101, 1, 273, 18, 0), + (1107, 1, 294, 2, 100), + (1108, 1, 294, 4, 100), + (1109, 1, 294, 6, 100), + (1113, 1, 331, 30, 0), + (1114, 1, 331, 35, 0), + (1115, 1, 331, 40, 0), + (1122, 1, 308, 1, 0), + (1129, 1, 267, 1, 24), + (1129, 2, 267, 1, 25), + (1129, 3, 267, 1, 26), + (1130, 1, 267, 1, 18), + (1130, 2, 267, 1, 19), + (1130, 3, 267, 1, 20), + (1130, 4, 267, 1, 21), + (1130, 5, 267, 1, 22), + (1130, 6, 267, 1, 23), + (1130, 7, 267, 1, 24), + (1130, 8, 267, 1, 25), + (1130, 9, 267, 1, 26), + (1131, 1, 185, 10, 51), + (1132, 1, 185, 20, 51), + (1133, 1, 185, 30, 51), + (1134, 1, 220, 32, 74), + (1135, 1, 220, 64, 74), + (1136, 1, 220, 96, 74), + (1137, 1, 310, 180000, 0), + (1137, 2, 139, 5027, 0), + (1137, 3, 310, 180000, 0), + (1137, 4, 139, 5028, 0), + (1137, 5, 310, 180000, 0), + (1137, 6, 139, 5029, 0), + (1137, 7, 310, 180000, 0), + (1137, 8, 139, 5030, 0), + (1137, 9, 310, 180000, 0), + (1137, 10, 139, 5031, 0), + (1137, 11, 310, 180000, 0), + (1137, 12, 139, 5032, 0), + (1137, 13, 310, 180000, 0), + (1137, 14, 139, 8476, 0), + (1138, 1, 310, 360000, 0), + (1138, 2, 139, 5027, 0), + (1138, 3, 310, 360000, 0), + (1138, 4, 139, 5028, 0), + (1138, 5, 310, 360000, 0), + (1138, 6, 139, 5029, 0), + (1138, 7, 310, 360000, 0), + (1138, 8, 139, 5030, 0), + (1138, 9, 310, 360000, 0), + (1138, 10, 139, 5031, 0), + (1138, 11, 310, 360000, 0), + (1138, 12, 139, 5032, 0), + (1138, 13, 310, 360000, 0), + (1138, 14, 139, 8476, 0), + (1139, 1, 310, 540000, 0), + (1139, 2, 139, 5027, 0), + (1139, 3, 310, 540000, 0), + (1139, 4, 139, 5028, 0), + (1139, 5, 310, 540000, 0), + (1139, 6, 139, 5029, 0), + (1139, 7, 310, 540000, 0), + (1139, 8, 139, 5030, 0), + (1139, 9, 310, 540000, 0), + (1139, 10, 139, 5031, 0), + (1139, 11, 310, 540000, 0), + (1139, 12, 139, 5032, 0), + (1139, 13, 310, 540000, 0), + (1139, 14, 139, 8476, 0), + (1140, 1, 216, 10, 51), + (1141, 1, 216, 20, 51), + (1142, 1, 216, 30, 51), + (1155, 1, 128, 25, 0), + (1155, 2, 139, 5027, 0), + (1155, 3, 128, 25, 0), + (1155, 4, 139, 5028, 0), + (1155, 5, 128, 25, 0), + (1155, 6, 139, 5029, 0), + (1155, 7, 128, 25, 0), + (1155, 8, 139, 5030, 0), + (1155, 9, 128, 25, 0), + (1155, 10, 139, 5031, 0), + (1155, 11, 128, 25, 0), + (1155, 12, 139, 5032, 0), + (1155, 13, 128, 25, 0), + (1155, 14, 139, 8476, 0), + (1156, 1, 128, 50, 0), + (1156, 2, 139, 5027, 0), + (1156, 3, 128, 50, 0), + (1156, 4, 139, 5028, 0), + (1156, 5, 128, 50, 0), + (1156, 6, 139, 5029, 0), + (1156, 7, 128, 50, 0), + (1156, 8, 139, 5030, 0), + (1156, 9, 128, 50, 0), + (1156, 10, 139, 5031, 0), + (1156, 11, 128, 50, 0), + (1156, 12, 139, 5032, 0), + (1156, 13, 128, 50, 0), + (1156, 14, 139, 8476, 0), + (1157, 1, 128, 100, 0), + (1157, 2, 139, 5027, 0), + (1157, 3, 128, 100, 0), + (1157, 4, 139, 5028, 0), + (1157, 5, 128, 100, 0), + (1157, 6, 139, 5029, 0), + (1157, 7, 128, 100, 0), + (1157, 8, 139, 5030, 0), + (1157, 9, 128, 100, 0), + (1157, 10, 139, 5031, 0), + (1157, 11, 128, 100, 0), + (1157, 12, 139, 5032, 0), + (1157, 13, 128, 100, 0), + (1157, 14, 139, 8476, 0), + (1158, 1, 220, 128, 74), + (1159, 1, 220, 160, 74), + (1160, 1, 220, 192, 74), + (1161, 1, 220, 224, 74), + (1162, 1, 220, 256, 74), + (1163, 1, 279, 23, 0), + (1164, 1, 279, 25, 0), + (1165, 1, 279, 27, 0), + (1166, 1, 224, 20, 74), + (1166, 2, 173, 1, 0), + (1167, 1, 224, 35, 74), + (1167, 2, 173, 1, 0), + (1168, 1, 224, 50, 74), + (1168, 2, 173, 2, 0), + (1172, 1, 292, 50, 0), + (1173, 1, 292, 55, 0), + (1174, 1, 292, 60, 0), + (1181, 1, 305, -20, 0), + (1182, 1, 305, -40, 0), + (1183, 1, 305, -60, 0), + (1184, 1, 305, -80, 0), + (1185, 1, 305, -100, 0), + (1186, 1, 319, 3, 0), + (1187, 1, 319, 6, 0), + (1188, 1, 319, 10, 0), + (1196, 1, 220, 20, 7), + (1197, 1, 220, 40, 7), + (1198, 1, 220, 60, 7), + (1199, 1, 220, 80, 7), + (1200, 1, 220, 100, 7), + (1210, 1, 294, 0, 107), + (1211, 1, 294, 0, 115), + (1212, 1, 294, 0, 125), + (1213, 1, 294, 0, 107), + (1214, 1, 294, 0, 115), + (1215, 1, 294, 0, 125), + (1216, 1, 132, 2, 2), + (1217, 1, 132, 5, 5), + (1218, 1, 132, 10, 10), + (1219, 1, 339, 3, 8105), + (1219, 2, 142, 65, 0), + (1219, 3, 311, 0, 0), + (1219, 4, 134, 70, 0), + (1219, 5, 348, 10, 0), + (1219, 6, 137, 0, 0), + (1219, 7, 339, 3, 8105), + (1219, 8, 142, 65, 0), + (1219, 9, 311, 0, 0), + (1219, 10, 134, 70, 0), + (1219, 11, 348, 10, 0), + (1219, 12, 137, 100, 0), + (1219, 13, 339, 3, 8105), + (1219, 14, 142, 65, 0), + (1219, 15, 311, 0, 0), + (1219, 16, 134, 70, 0), + (1219, 17, 348, 10, 0), + (1219, 18, 137, 79, 0), + (1219, 19, 339, 3, 8105), + (1219, 20, 142, 65, 0), + (1219, 21, 311, 0, 0), + (1219, 22, 134, 70, 0), + (1219, 23, 348, 10, 0), + (1219, 24, 137, 147, 0), + (1220, 1, 339, 6, 8105), + (1220, 2, 142, 65, 0), + (1220, 3, 311, 0, 0), + (1220, 4, 134, 70, 0), + (1220, 5, 348, 10, 0), + (1220, 6, 137, 0, 0), + (1220, 7, 339, 6, 8105), + (1220, 8, 142, 65, 0), + (1220, 9, 311, 0, 0), + (1220, 10, 134, 70, 0), + (1220, 11, 348, 10, 0), + (1220, 12, 137, 100, 0), + (1220, 13, 339, 6, 8105), + (1220, 14, 142, 65, 0), + (1220, 15, 311, 0, 0), + (1220, 16, 134, 70, 0), + (1220, 17, 348, 10, 0), + (1220, 18, 137, 79, 0), + (1220, 19, 339, 6, 8105), + (1220, 20, 142, 65, 0), + (1220, 21, 311, 0, 0), + (1220, 22, 134, 70, 0), + (1220, 23, 348, 10, 0), + (1220, 24, 137, 147, 0), + (1221, 1, 339, 10, 8105), + (1221, 2, 142, 65, 0), + (1221, 3, 311, 0, 0), + (1221, 4, 134, 70, 0), + (1221, 5, 348, 10, 0), + (1221, 6, 137, 0, 0), + (1221, 7, 339, 10, 8105), + (1221, 8, 142, 65, 0), + (1221, 9, 311, 0, 0), + (1221, 10, 134, 70, 0), + (1221, 11, 348, 10, 0), + (1221, 12, 137, 100, 0), + (1221, 13, 339, 10, 8105), + (1221, 14, 142, 65, 0), + (1221, 15, 311, 0, 0), + (1221, 16, 134, 70, 0), + (1221, 17, 348, 10, 0), + (1221, 18, 137, 79, 0), + (1221, 19, 339, 10, 8105), + (1221, 20, 142, 65, 0), + (1221, 21, 311, 0, 0), + (1221, 22, 134, 70, 0), + (1221, 23, 348, 10, 0), + (1221, 24, 137, 147, 0), + (1230, 1, 313, 25, 0), + (1231, 1, 313, 50, 0), + (1232, 1, 313, 75, 0), + (1265, 1, 220, 40, 26), + (1265, 2, 220, 40, 30), + (1265, 3, 220, 40, 38), + (1266, 1, 220, 50, 26), + (1266, 2, 220, 50, 30), + (1266, 3, 220, 50, 38), + (1267, 1, 220, 60, 26), + (1267, 2, 220, 60, 30), + (1267, 3, 220, 60, 38), + (1268, 1, 292, 20, 0), + (1269, 1, 292, 25, 0), + (1270, 1, 292, 30, 0), + (1284, 1, 293, 15, 0), + (1285, 1, 293, 30, 0), + (1286, 1, 293, 50, 0), + (1287, 1, 320, 1, 0), + (1288, 1, 320, 3, 0), + (1289, 1, 320, 5, 0), + (1290, 1, 216, 40, 0), + (1290, 2, 216, 40, 1), + (1290, 3, 216, 40, 2), + (1290, 4, 216, 40, 3), + (1290, 5, 216, 40, 10), + (1290, 6, 216, 40, 28), + (1290, 7, 216, 40, 30), + (1290, 8, 216, 40, 36), + (1290, 9, 216, 40, 77), + (1291, 1, 216, 50, 0), + (1291, 2, 216, 50, 1), + (1291, 3, 216, 50, 2), + (1291, 4, 216, 50, 3), + (1291, 5, 216, 50, 10), + (1291, 6, 216, 50, 28), + (1291, 7, 216, 50, 30), + (1291, 8, 216, 50, 36), + (1291, 9, 216, 50, 77), + (1292, 1, 216, 60, 0), + (1292, 2, 216, 60, 1), + (1292, 3, 216, 60, 2), + (1292, 4, 216, 60, 3), + (1292, 5, 216, 60, 10), + (1292, 6, 216, 60, 28), + (1292, 7, 216, 60, 30), + (1292, 8, 216, 60, 36), + (1292, 9, 216, 60, 77), + (1296, 1, 247, 20, 53), + (1297, 1, 247, 40, 53), + (1298, 1, 247, 60, 53), + (1299, 1, 247, 80, 53), + (1300, 1, 247, 100, 53), + (1301, 1, 258, 20, 0), + (1302, 1, 258, 25, 0), + (1303, 1, 258, 30, 0), + (1304, 1, 216, 50, 8), + (1305, 1, 216, 100, 8), + (1306, 1, 216, 150, 8), + (1307, 1, 325, 10, 0), + (1308, 1, 325, 20, 0), + (1309, 1, 325, 30, 0), + (1310, 1, 325, 40, 0), + (1311, 1, 325, 50, 0), + (1313, 1, 85, 6037, 0), + (1314, 1, 85, 6038, 0), + (1315, 1, 85, 6039, 0), + (1316, 1, 302, 216, 216), + (1316, 2, 385, 99, 0), + (1317, 1, 302, 233, 233), + (1317, 2, 385, 99, 0), + (1318, 1, 302, 250, 250), + (1318, 2, 385, 99, 0), + (1319, 1, 274, 16, 0), + (1320, 1, 274, 18, 0), + (1321, 1, 274, 20, 0), + (1361, 1, 159, 10, 0), + (1361, 2, 262, 10, 0), + (1361, 3, 262, 10, 1), + (1361, 4, 262, 10, 2), + (1361, 5, 262, 10, 3), + (1361, 6, 262, 10, 4), + (1361, 7, 262, 10, 5), + (1361, 8, 262, 10, 6), + (1362, 1, 214, 300, 0), + (1362, 2, 97, 200, 0), + (1362, 3, 190, 200, 0), + (1363, 1, 327, 1, 0), + (1364, 1, 273, 1, 0), + (1364, 2, 274, 1, 0), + (1364, 3, 294, 1, 100), + (1364, 4, 169, 40, 0), + (1364, 5, 169, 40, 1), + (1364, 6, 169, 40, 2), + (1364, 7, 169, 40, 3), + (1364, 8, 169, 40, 8), + (1364, 9, 169, 40, 10), + (1364, 10, 169, 40, 26), + (1364, 11, 169, 40, 28), + (1364, 12, 169, 40, 30), + (1364, 13, 169, 40, 36), + (1364, 14, 169, 40, 74), + (1365, 1, 180, 2, 0), + (1366, 1, 159, 10, 0), + (1366, 2, 262, 10, 0), + (1366, 3, 262, 10, 1), + (1366, 4, 262, 10, 2), + (1366, 5, 262, 10, 3), + (1366, 6, 262, 10, 4), + (1366, 7, 262, 10, 5), + (1366, 8, 262, 10, 6), + (1367, 1, 214, 300, 0), + (1367, 2, 97, 200, 0), + (1367, 3, 190, 200, 0), + (1368, 1, 327, 1, 0), + (1369, 1, 273, 1, 0), + (1369, 2, 274, 1, 0), + (1369, 3, 294, 1, 100), + (1369, 4, 169, 40, 0), + (1369, 5, 169, 40, 1), + (1369, 6, 169, 40, 2), + (1369, 7, 169, 40, 3), + (1369, 8, 169, 40, 8), + (1369, 9, 169, 40, 10), + (1369, 10, 169, 40, 26), + (1369, 11, 169, 40, 28), + (1369, 12, 169, 40, 30), + (1369, 13, 169, 40, 36), + (1369, 14, 169, 40, 74), + (1370, 1, 180, 2, 0), + (1378, 1, 10, 0, 0), + (1379, 1, 10, 0, 0), + (1380, 1, 10, 0, 0), + (1382, 1, 10, 0, 0), + (1388, 2, 13, 1, 0), + (1389, 1, 328, 300, 0), + (1390, 1, 328, 350, 0), + (1391, 1, 328, 400, 0), + (1392, 1, 328, 450, 0), + (1393, 1, 328, 500, 0), + (1394, 1, 172, 33, 0), + (1395, 1, 172, 34, 0), + (1396, 1, 172, 35, 0), + (1397, 1, 172, 37, 0), + (1398, 1, 172, 39, 0), + (1399, 1, 259, 37, 0), + (1400, 1, 259, 39, 0), + (1401, 1, 259, 41, 0), + (1402, 1, 259, 43, 0), + (1403, 1, 259, 45, 0), + (1414, 1, 264, 432, 451), + (1415, 1, 264, 864, 451), + (1416, 1, 264, 1296, 451), + (1417, 1, 264, 1728, 451), + (1418, 1, 264, 2160, 451), + (1420, 1, 282, 20, 0), + (1421, 1, 282, 40, 0), + (1422, 1, 282, 60, 0), + (1423, 1, 282, 80, 0), + (1424, 1, 282, 100, 0), + (1430, 1, 280, 27, 0), + (1431, 1, 280, 34, 0), + (1432, 1, 280, 41, 0), + (1435, 1, 339, 3, 8105), + (1435, 2, 142, 65, 0), + (1435, 3, 311, 0, 0), + (1435, 4, 134, 70, 0), + (1435, 5, 348, 10, 0), + (1435, 6, 137, 0, 0), + (1435, 7, 339, 3, 8105), + (1435, 8, 142, 65, 0), + (1435, 9, 311, 0, 0), + (1435, 10, 134, 70, 0), + (1435, 11, 348, 10, 0), + (1435, 12, 137, 100, 0), + (1435, 13, 339, 3, 8105), + (1435, 14, 142, 65, 0), + (1435, 15, 311, 0, 0), + (1435, 16, 134, 70, 0), + (1435, 17, 348, 10, 0), + (1435, 18, 137, 79, 0), + (1435, 19, 339, 3, 8105), + (1435, 20, 142, 65, 0), + (1435, 21, 311, 0, 0), + (1435, 22, 134, 70, 0), + (1435, 23, 348, 10, 0), + (1435, 24, 137, 147, 0), + (1436, 1, 339, 6, 8105), + (1436, 2, 142, 65, 0), + (1436, 3, 311, 0, 0), + (1436, 4, 134, 70, 0), + (1436, 5, 348, 10, 0), + (1436, 6, 137, 0, 0), + (1436, 7, 339, 6, 8105), + (1436, 8, 142, 65, 0), + (1436, 9, 311, 0, 0), + (1436, 10, 134, 70, 0), + (1436, 11, 348, 10, 0), + (1436, 12, 137, 100, 0), + (1436, 13, 339, 6, 8105), + (1436, 14, 142, 65, 0), + (1436, 15, 311, 0, 0), + (1436, 16, 134, 70, 0), + (1436, 17, 348, 10, 0), + (1436, 18, 137, 79, 0), + (1436, 19, 339, 6, 8105), + (1436, 20, 142, 65, 0), + (1436, 21, 311, 0, 0), + (1436, 22, 134, 70, 0), + (1436, 23, 348, 10, 0), + (1436, 24, 137, 147, 0), + (1437, 1, 339, 10, 8105), + (1437, 2, 142, 65, 0), + (1437, 3, 311, 0, 0), + (1437, 4, 134, 70, 0), + (1437, 5, 348, 10, 0), + (1437, 6, 137, 0, 0), + (1437, 7, 339, 10, 8105), + (1437, 8, 142, 65, 0), + (1437, 9, 311, 0, 0), + (1437, 10, 134, 70, 0), + (1437, 11, 348, 10, 0), + (1437, 12, 137, 100, 0), + (1437, 13, 339, 10, 8105), + (1437, 14, 142, 65, 0), + (1437, 15, 311, 0, 0), + (1437, 16, 134, 70, 0), + (1437, 17, 348, 10, 0), + (1437, 18, 137, 79, 0), + (1437, 19, 339, 10, 8105), + (1437, 20, 142, 65, 0), + (1437, 21, 311, 0, 0), + (1437, 22, 134, 70, 0), + (1437, 23, 348, 10, 0), + (1437, 24, 137, 147, 0), + (1453, 1, 131, 10, 10), + (1453, 2, 137, 32, 0), + (1453, 3, 311, 1, 0), + (1454, 1, 131, 20, 20), + (1454, 2, 137, 32, 0), + (1454, 3, 311, 1, 0), + (1455, 1, 131, 30, 30), + (1455, 2, 137, 32, 0), + (1455, 3, 311, 1, 0), + (1456, 1, 131, 40, 40), + (1456, 2, 137, 32, 0), + (1456, 3, 311, 1, 0), + (1457, 1, 131, 50, 50), + (1457, 2, 137, 32, 0), + (1457, 3, 311, 1, 0), + (1467, 1, 280, 27, 0), + (1468, 1, 280, 34, 0), + (1469, 1, 280, 41, 0), + (1471, 1, 264, 90, 362), + (1472, 1, 264, 180, 362), + (1473, 1, 264, 270, 362), + (1474, 1, 264, 360, 362), + (1475, 1, 264, 450, 362), + (1483, 1, 294, 0, 133), + (1484, 1, 294, 0, 141), + (1485, 1, 294, 0, 150), + (1486, 1, 339, 1, 8165), + (1486, 2, 138, 1, 0), + (1486, 3, 141, 1, 0), + (1486, 4, 142, 60, 0), + (1486, 5, 137, 0, 0), + (1486, 6, 311, 0, 0), + (1486, 7, 134, 75, 0), + (1486, 8, 139, -265, 0), + (1486, 9, 139, -754, 0), + (1486, 10, 139, -1332, 0), + (1486, 11, 139, -1572, 0), + (1486, 12, 139, -2749, 0), + (1486, 13, 139, -4979, 0), + (1486, 14, 139, -5418, 0), + (1486, 15, 139, -5403, 0), + (1486, 16, 348, 10, 0), + (1487, 1, 339, 3, 8166), + (1487, 2, 138, 1, 0), + (1487, 3, 141, 1, 0), + (1487, 4, 142, 60, 0), + (1487, 5, 137, 0, 0), + (1487, 6, 311, 0, 0), + (1487, 7, 134, 75, 0), + (1487, 8, 139, -265, 0), + (1487, 9, 139, -754, 0), + (1487, 10, 139, -1332, 0), + (1487, 11, 139, -1572, 0), + (1487, 12, 139, -2749, 0), + (1487, 13, 139, -4979, 0), + (1487, 14, 139, -5418, 0), + (1487, 15, 139, -5403, 0), + (1487, 16, 348, 10, 0), + (1488, 1, 339, 5, 8167), + (1488, 2, 138, 1, 0), + (1488, 3, 141, 1, 0), + (1488, 4, 142, 60, 0), + (1488, 5, 137, 0, 0), + (1488, 6, 311, 0, 0), + (1488, 7, 134, 75, 0), + (1488, 8, 139, -265, 0), + (1488, 9, 139, -754, 0), + (1488, 10, 139, -1332, 0), + (1488, 11, 139, -1572, 0), + (1488, 12, 139, -2749, 0), + (1488, 13, 139, -4979, 0), + (1488, 14, 139, -5418, 0), + (1488, 15, 139, -5403, 0), + (1488, 16, 348, 10, 0), + (1489, 1, 339, 7, 8168), + (1489, 2, 138, 1, 0), + (1489, 3, 141, 1, 0), + (1489, 4, 142, 60, 0), + (1489, 5, 137, 0, 0), + (1489, 6, 311, 0, 0), + (1489, 7, 134, 75, 0), + (1489, 8, 139, -265, 0), + (1489, 9, 139, -754, 0), + (1489, 10, 139, -1332, 0), + (1489, 11, 139, -1572, 0), + (1489, 12, 139, -2749, 0), + (1489, 13, 139, -4979, 0), + (1489, 14, 139, -5418, 0), + (1489, 15, 139, -5403, 0), + (1489, 16, 348, 10, 0), + (1490, 1, 339, 9, 8169), + (1490, 2, 138, 1, 0), + (1490, 3, 141, 1, 0), + (1490, 4, 142, 60, 0), + (1490, 5, 137, 0, 0), + (1490, 6, 311, 0, 0), + (1490, 7, 134, 75, 0), + (1490, 8, 139, -265, 0), + (1490, 9, 139, -754, 0), + (1490, 10, 139, -1332, 0), + (1490, 11, 139, -1572, 0), + (1490, 12, 139, -2749, 0), + (1490, 13, 139, -4979, 0), + (1490, 14, 139, -5418, 0), + (1490, 15, 139, -5403, 0), + (1490, 16, 348, 10, 0), + (1504, 1, 287, 2, 0), + (1504, 2, 385, 2754, 1), + (1505, 1, 287, 4, 0), + (1505, 2, 385, 2754, 1), + (1506, 1, 287, 6, 0), + (1506, 2, 385, 2754, 1), + (1511, 1, 264, 60, 175), + (1511, 2, 264, 60, 792), + (1512, 1, 264, 120, 175), + (1512, 2, 264, 120, 792), + (1513, 1, 264, 180, 175), + (1513, 2, 264, 180, 792), + (1514, 1, 273, 2, 0), + (1515, 1, 273, 4, 0), + (1516, 1, 273, 6, 0), + (1524, 1, 219, 260, 1800), + (1525, 1, 219, 300, 2000), + (1526, 1, 219, 280, 1900), + (1528, 1, 239, 30, 0), + (1529, 1, 239, 35, 0), + (1530, 1, 239, 40, 0), + (1531, 1, 239, 45, 0), + (1532, 1, 239, 50, 0), + (1533, 1, 266, 11, 0), + (1534, 1, 266, 14, 0), + (1535, 1, 266, 17, 0), + (1536, 1, 266, 11, 0), + (1537, 1, 266, 14, 0), + (1538, 1, 266, 17, 0), + (1539, 1, 252, 37, 0), + (1540, 1, 252, 44, 0), + (1541, 1, 252, 50, 0), + (1543, 1, 220, 10, 8), + (1544, 1, 220, 20, 8), + (1545, 1, 220, 30, 8), + (1546, 1, 264, 120, 420), + (1547, 1, 264, 240, 420), + (1548, 1, 264, 360, 420), + (1549, 1, 293, 25, 0), + (1550, 1, 293, 50, 0), + (1551, 1, 293, 75, 0), + (1552, 1, 271, 5, 0), + (1553, 1, 271, 10, 0), + (1554, 1, 271, 15, 0), + (1555, 1, 264, 240, 359), + (1556, 1, 264, 480, 359), + (1557, 1, 264, 720, 359), + (1563, 1, 225, 18, 0), + (1564, 1, 225, 21, 0), + (1565, 1, 225, 24, 0), + (1566, 1, 225, 27, 0), + (1567, 1, 225, 30, 0), + (1572, 1, 339, 2, 8261), + (1572, 2, 138, 0, 0), + (1572, 3, 137, 31, 0), + (1572, 4, 311, 0, 0), + (1573, 1, 339, 4, 8262), + (1573, 2, 138, 0, 0), + (1573, 3, 137, 31, 0), + (1573, 4, 311, 0, 0), + (1574, 1, 339, 6, 8263), + (1574, 2, 138, 0, 0), + (1574, 3, 137, 31, 0), + (1574, 4, 311, 0, 0), + (1575, 1, 339, 8, 8264), + (1575, 2, 138, 0, 0), + (1575, 3, 137, 31, 0), + (1575, 4, 311, 0, 0), + (1576, 1, 339, 10, 8265), + (1576, 2, 138, 0, 0), + (1576, 3, 137, 31, 0), + (1576, 4, 311, 0, 0), + (1577, 1, 274, 3, 0), + (1578, 1, 274, 6, 0), + (1579, 1, 274, 10, 0), + (1583, 1, 264, 360, 300), + (1584, 1, 264, 720, 300), + (1585, 1, 264, 1080, 300), + (1586, 1, 264, 1440, 300), + (1587, 1, 264, 1800, 300), + (1588, 1, 344, 50, 0), + (1589, 1, 344, 100, 0), + (1590, 1, 344, 150, 0), + (1591, 1, 293, 25, 0), + (1592, 1, 341, 10, 0), + (1593, 1, 341, 20, 0), + (1594, 1, 341, 30, 0), + (1595, 1, 341, 40, 0), + (1596, 1, 341, 50, 0), + (1601, 1, 217, 0, 35200), + (1601, 2, 346, 60, 0), + (1602, 1, 217, 0, 42440), + (1602, 2, 346, 62, 0), + (1603, 1, 217, 0, 46480), + (1603, 2, 346, 64, 0), + (1604, 1, 439, 0, 32000), + (1604, 2, 345, 59, 0), + (1605, 1, 439, 0, 35200), + (1605, 2, 345, 60, 0), + (1606, 1, 439, 0, 42440), + (1606, 2, 345, 61, 0), + (1608, 1, 347, 2, 0), + (1609, 1, 347, 4, 0), + (1610, 1, 347, 6, 0), + (1611, 1, 282, 20, 0), + (1612, 1, 282, 40, 0), + (1613, 1, 282, 60, 0), + (1614, 1, 282, 80, 0), + (1615, 1, 282, 100, 0), + (1616, 1, 279, 7, 0), + (1617, 1, 279, 11, 0), + (1618, 1, 279, 15, 0), + (1619, 1, 279, 17, 0), + (1620, 1, 279, 19, 0), + (1621, 1, 177, 20, -1), + (1622, 1, 177, 22, -1), + (1623, 1, 177, 24, -1), + (1624, 1, 177, 20, -1), + (1625, 1, 177, 22, -1), + (1626, 1, 177, 24, -1), + (1627, 1, 271, 5, 0), + (1628, 1, 271, 10, 0), + (1629, 1, 271, 15, 0), + (1633, 1, 225, 18, 0), + (1634, 1, 225, 21, 0), + (1635, 1, 225, 24, 0), + (1636, 1, 225, 27, 0), + (1637, 1, 225, 30, 0), + (1641, 1, 359, 100, 0), + (1642, 1, 359, 60, 0), + (1648, 1, 339, 10, 8105), + (1648, 2, 142, 65, 0), + (1648, 3, 311, 0, 0), + (1648, 4, 134, 70, 0), + (1648, 5, 348, 10, 0), + (1648, 6, 137, 0, 0), + (1648, 7, 339, 10, 8105), + (1648, 8, 142, 65, 0), + (1648, 9, 311, 0, 0), + (1648, 10, 134, 70, 0), + (1648, 11, 348, 10, 0), + (1648, 12, 137, 100, 0), + (1648, 13, 339, 10, 8105), + (1648, 14, 142, 65, 0), + (1648, 15, 311, 0, 0), + (1648, 16, 134, 70, 0), + (1648, 17, 348, 10, 0), + (1648, 18, 137, 79, 0), + (1648, 19, 339, 10, 8105), + (1648, 20, 142, 65, 0), + (1648, 21, 311, 0, 0), + (1648, 22, 134, 70, 0), + (1648, 23, 348, 10, 0), + (1648, 24, 137, 147, 0), + (1648, 25, 339, 10, 11404), + (1648, 26, 142, 71, 0), + (1648, 27, 311, 0, 0), + (1648, 28, 134, 75, 0), + (1648, 29, 348, 10, 0), + (1648, 30, 137, 0, 0), + (1648, 31, 339, 10, 11404), + (1648, 32, 142, 71, 0), + (1648, 33, 311, 0, 0), + (1648, 34, 134, 75, 0), + (1648, 35, 348, 10, 0), + (1648, 36, 137, 100, 0), + (1648, 37, 339, 10, 11404), + (1648, 38, 142, 71, 0), + (1648, 39, 311, 0, 0), + (1648, 40, 134, 75, 0), + (1648, 41, 348, 10, 0), + (1648, 42, 137, 79, 0), + (1648, 43, 339, 10, 11404), + (1648, 44, 142, 71, 0), + (1648, 45, 311, 0, 0), + (1648, 46, 134, 75, 0), + (1648, 47, 348, 10, 0), + (1648, 48, 137, 147, 0), + (1649, 1, 339, 10, 8105), + (1649, 2, 142, 65, 0), + (1649, 3, 311, 0, 0), + (1649, 4, 134, 70, 0), + (1649, 5, 348, 10, 0), + (1649, 6, 137, 0, 0), + (1649, 7, 339, 10, 8105), + (1649, 8, 142, 65, 0), + (1649, 9, 311, 0, 0), + (1649, 10, 134, 70, 0), + (1649, 11, 348, 10, 0), + (1649, 12, 137, 100, 0), + (1649, 13, 339, 10, 8105), + (1649, 14, 142, 65, 0), + (1649, 15, 311, 0, 0), + (1649, 16, 134, 70, 0), + (1649, 17, 348, 10, 0), + (1649, 18, 137, 79, 0), + (1649, 19, 339, 10, 8105), + (1649, 20, 142, 65, 0), + (1649, 21, 311, 0, 0), + (1649, 22, 134, 70, 0), + (1649, 23, 348, 10, 0), + (1649, 24, 137, 147, 0), + (1649, 25, 339, 10, 11404), + (1649, 26, 142, 71, 0), + (1649, 27, 311, 0, 0), + (1649, 28, 134, 75, 0), + (1649, 29, 348, 10, 0), + (1649, 30, 137, 0, 0), + (1649, 31, 339, 10, 11404), + (1649, 32, 142, 71, 0), + (1649, 33, 311, 0, 0), + (1649, 34, 134, 75, 0), + (1649, 35, 348, 10, 0), + (1649, 36, 137, 100, 0), + (1649, 37, 339, 10, 11404), + (1649, 38, 142, 71, 0), + (1649, 39, 311, 0, 0), + (1649, 40, 134, 75, 0), + (1649, 41, 348, 10, 0), + (1649, 42, 137, 79, 0), + (1649, 43, 339, 10, 11404), + (1649, 44, 142, 71, 0), + (1649, 45, 311, 0, 0), + (1649, 46, 134, 75, 0), + (1649, 47, 348, 10, 0), + (1649, 48, 137, 147, 0), + (1649, 49, 339, 10, 13199), + (1649, 50, 142, 76, 0), + (1649, 51, 311, 0, 0), + (1649, 52, 134, 80, 0), + (1649, 53, 348, 10, 0), + (1649, 54, 137, 0, 0), + (1649, 55, 339, 10, 13199), + (1649, 56, 142, 76, 0), + (1649, 57, 311, 0, 0), + (1649, 58, 134, 80, 0), + (1649, 59, 348, 10, 0), + (1649, 60, 137, 100, 0), + (1649, 61, 339, 10, 13199), + (1649, 62, 142, 76, 0), + (1649, 63, 311, 0, 0), + (1649, 64, 134, 80, 0), + (1649, 65, 348, 10, 0), + (1649, 66, 137, 79, 0), + (1649, 67, 339, 10, 13199), + (1649, 68, 142, 76, 0), + (1649, 69, 311, 0, 0), + (1649, 70, 134, 80, 0), + (1649, 71, 348, 10, 0), + (1649, 72, 137, 147, 0), + (1650, 1, 339, 10, 8105), + (1650, 2, 142, 65, 0), + (1650, 3, 311, 0, 0), + (1650, 4, 134, 70, 0), + (1650, 5, 348, 10, 0), + (1650, 6, 137, 0, 0), + (1650, 7, 339, 10, 8105), + (1650, 8, 142, 65, 0), + (1650, 9, 311, 0, 0), + (1650, 10, 134, 70, 0), + (1650, 11, 348, 10, 0), + (1650, 12, 137, 100, 0), + (1650, 13, 339, 10, 8105), + (1650, 14, 142, 65, 0), + (1650, 15, 311, 0, 0), + (1650, 16, 134, 70, 0), + (1650, 17, 348, 10, 0), + (1650, 18, 137, 79, 0), + (1650, 19, 339, 10, 8105), + (1650, 20, 142, 65, 0), + (1650, 21, 311, 0, 0), + (1650, 22, 134, 70, 0), + (1650, 23, 348, 10, 0), + (1650, 24, 137, 147, 0), + (1650, 25, 339, 10, 11404), + (1650, 26, 142, 71, 0), + (1650, 27, 311, 0, 0), + (1650, 28, 134, 75, 0), + (1650, 29, 348, 10, 0), + (1650, 30, 137, 0, 0), + (1650, 31, 339, 10, 11404), + (1650, 32, 142, 71, 0), + (1650, 33, 311, 0, 0), + (1650, 34, 134, 75, 0), + (1650, 35, 348, 10, 0), + (1650, 36, 137, 100, 0), + (1650, 37, 339, 10, 11404), + (1650, 38, 142, 71, 0), + (1650, 39, 311, 0, 0), + (1650, 40, 134, 75, 0), + (1650, 41, 348, 10, 0), + (1650, 42, 137, 79, 0), + (1650, 43, 339, 10, 11404), + (1650, 44, 142, 71, 0), + (1650, 45, 311, 0, 0), + (1650, 46, 134, 75, 0), + (1650, 47, 348, 10, 0), + (1650, 48, 137, 147, 0), + (1650, 49, 339, 10, 13199), + (1650, 50, 142, 76, 0), + (1650, 51, 311, 0, 0), + (1650, 52, 134, 80, 0), + (1650, 53, 348, 10, 0), + (1650, 54, 137, 0, 0), + (1650, 55, 339, 10, 13199), + (1650, 56, 142, 76, 0), + (1650, 57, 311, 0, 0), + (1650, 58, 134, 80, 0), + (1650, 59, 348, 10, 0), + (1650, 60, 137, 100, 0), + (1650, 61, 339, 10, 13199), + (1650, 62, 142, 76, 0), + (1650, 63, 311, 0, 0), + (1650, 64, 134, 80, 0), + (1650, 65, 348, 10, 0), + (1650, 66, 137, 79, 0), + (1650, 67, 339, 10, 13199), + (1650, 68, 142, 76, 0), + (1650, 69, 311, 0, 0), + (1650, 70, 134, 80, 0), + (1650, 71, 348, 10, 0), + (1650, 72, 137, 147, 0), + (1650, 73, 339, 10, 13830), + (1650, 74, 142, 81, 0), + (1650, 75, 311, 0, 0), + (1650, 76, 134, 85, 0), + (1650, 77, 348, 10, 0), + (1650, 78, 137, 0, 0), + (1650, 79, 339, 10, 13830), + (1650, 80, 142, 81, 0), + (1650, 81, 311, 0, 0), + (1650, 82, 134, 85, 0), + (1650, 83, 348, 10, 0), + (1650, 84, 137, 100, 0), + (1650, 85, 339, 10, 13830), + (1650, 86, 142, 81, 0), + (1650, 87, 311, 0, 0), + (1650, 88, 134, 85, 0), + (1650, 89, 348, 10, 0), + (1650, 90, 137, 79, 0), + (1650, 91, 339, 10, 13830), + (1650, 92, 142, 81, 0), + (1650, 93, 311, 0, 0), + (1650, 94, 134, 85, 0), + (1650, 95, 348, 10, 0), + (1650, 96, 137, 147, 0), + (1651, 1, 97, 300, 0), + (1652, 1, 97, 350, 0), + (1653, 1, 97, 400, 0), + (1654, 1, 97, 450, 0), + (1655, 1, 97, 500, 0), + (1656, 1, 127, 40, 0), + (1656, 2, 137, 154, 0), + (1656, 3, 403, 2, 0), + (1656, 4, 404, 10, 0), + (1657, 1, 127, 50, 0), + (1657, 2, 137, 154, 0), + (1657, 3, 403, 2, 0), + (1657, 4, 404, 10, 0), + (1659, 1, 127, 40, 0), + (1659, 2, 137, 154, 0), + (1659, 3, 403, 2, 0), + (1659, 4, 404, 10, 0), + (1660, 1, 127, 50, 0), + (1660, 2, 137, 154, 0), + (1660, 3, 403, 2, 0), + (1660, 4, 404, 10, 0), + (1662, 1, 370, 2, 0), + (1663, 1, 370, 4, 0), + (1664, 1, 370, 6, 0), + (1665, 1, 370, 8, 0), + (1666, 1, 370, 10, 0), + (2400, 1, 264, 90, 38), + (2401, 1, 264, 180, 38), + (2402, 1, 264, 270, 38), + (4666, 0, 366, 10, 50), + (4666, 1, 349, 5, 0), + (4667, 0, 366, 30, 50), + (4667, 1, 349, 10, 0), + (4668, 0, 366, 60, 50), + (4668, 1, 349, 15, 0), + (4669, 0, 366, 10, 500), + (4669, 1, 349, 20, 0), + (4670, 0, 366, 30, 500), + (4670, 1, 349, 25, 0), + (4672, 1, 268, 10, 57), + (4673, 1, 268, 25, 57), + (4674, 1, 268, 50, 57), + (4675, 1, 268, 10, 68), + (4676, 1, 268, 25, 68), + (4677, 1, 268, 50, 68), + (4678, 1, 262, 55, 0), + (4678, 2, 262, 55, 1), + (4678, 3, 262, 55, 2), + (4678, 4, 262, 55, 3), + (4678, 5, 262, 55, 4), + (4678, 6, 262, 55, 5), + (4678, 7, 262, 55, 6), + (4679, 1, 262, 60, 0), + (4679, 2, 262, 60, 1), + (4679, 3, 262, 60, 2), + (4679, 4, 262, 60, 3), + (4679, 5, 262, 60, 4), + (4679, 6, 262, 60, 5), + (4679, 7, 262, 60, 6), + (4680, 1, 262, 65, 0), + (4680, 2, 262, 65, 1), + (4680, 3, 262, 65, 2), + (4680, 4, 262, 65, 3), + (4680, 5, 262, 65, 4), + (4680, 6, 262, 65, 5), + (4680, 7, 262, 65, 6), + (4681, 1, 262, 70, 0), + (4681, 2, 262, 70, 1), + (4681, 3, 262, 70, 2), + (4681, 4, 262, 70, 3), + (4681, 5, 262, 70, 4), + (4681, 6, 262, 70, 5), + (4681, 7, 262, 70, 6), + (4682, 1, 262, 75, 0), + (4682, 2, 262, 75, 1), + (4682, 3, 262, 75, 2), + (4682, 4, 262, 75, 3), + (4682, 5, 262, 75, 4), + (4682, 6, 262, 75, 5), + (4682, 7, 262, 75, 6), + (4683, 1, 328, 550, 0), + (4684, 1, 328, 600, 0), + (4685, 1, 328, 650, 0), + (4686, 1, 328, 700, 0), + (4687, 1, 328, 750, 0), + (4688, 1, 282, 20, 0), + (4689, 1, 282, 40, 0), + (4690, 1, 282, 60, 0), + (4691, 1, 282, 80, 0), + (4692, 1, 282, 100, 0), + (4693, 1, 0, 11, 0), + (4694, 1, 0, 12, 0), + (4695, 1, 0, 13, 0), + (4696, 1, 0, 14, 0), + (4697, 1, 0, 15, 0), + (4698, 1, 362, 1, 0), + (4699, 1, 363, 1, 0), + (4707, 1, 330, 85, 0), + (4707, 2, 330, 85, 1), + (4707, 3, 330, 85, 2), + (4707, 4, 330, 85, 3), + (4707, 5, 330, 85, 28), + (4707, 6, 330, 85, 36), + (4707, 7, 330, 85, 77), + (4708, 1, 330, 95, 0), + (4708, 2, 330, 95, 1), + (4708, 3, 330, 95, 2), + (4708, 4, 330, 95, 3), + (4708, 5, 330, 95, 28), + (4708, 6, 330, 95, 36), + (4708, 7, 330, 95, 77), + (4709, 1, 330, 105, 0), + (4709, 2, 330, 105, 1), + (4709, 3, 330, 105, 2), + (4709, 4, 330, 105, 3), + (4709, 5, 330, 105, 28), + (4709, 6, 330, 105, 36), + (4709, 7, 330, 105, 77), + (4710, 1, 330, 85, 0), + (4710, 2, 330, 85, 1), + (4710, 3, 330, 85, 2), + (4710, 4, 330, 85, 3), + (4710, 5, 330, 85, 28), + (4710, 6, 330, 85, 36), + (4711, 1, 330, 95, 0), + (4711, 2, 330, 95, 1), + (4711, 3, 330, 95, 2), + (4711, 4, 330, 95, 3), + (4711, 5, 330, 95, 28), + (4711, 6, 330, 95, 36), + (4712, 1, 330, 105, 0), + (4712, 2, 330, 105, 1), + (4712, 3, 330, 105, 2), + (4712, 4, 330, 105, 3), + (4712, 5, 330, 105, 28), + (4712, 6, 330, 105, 36), + (4713, 1, 330, 85, 0), + (4713, 2, 330, 85, 1), + (4713, 3, 330, 85, 2), + (4713, 4, 330, 85, 3), + (4713, 5, 330, 85, 28), + (4713, 6, 330, 85, 36), + (4713, 7, 330, 85, 77), + (4714, 1, 330, 95, 0), + (4714, 2, 330, 95, 1), + (4714, 3, 330, 95, 2), + (4714, 4, 330, 95, 3), + (4714, 5, 330, 95, 28), + (4714, 6, 330, 95, 36), + (4714, 7, 330, 95, 77), + (4715, 1, 330, 105, 0), + (4715, 2, 330, 105, 1), + (4715, 3, 330, 105, 2), + (4715, 4, 330, 105, 3), + (4715, 5, 330, 105, 28), + (4715, 6, 330, 105, 36), + (4715, 7, 330, 105, 77), + (4716, 1, 330, 60, 0), + (4716, 2, 330, 60, 1), + (4716, 3, 330, 60, 2), + (4716, 4, 330, 60, 3), + (4716, 5, 330, 60, 28), + (4716, 6, 330, 60, 36), + (4716, 7, 330, 60, 77), + (4717, 1, 330, 70, 0), + (4717, 2, 330, 70, 1), + (4717, 3, 330, 70, 2), + (4717, 4, 330, 70, 3), + (4717, 5, 330, 70, 28), + (4717, 6, 330, 70, 36), + (4717, 7, 330, 70, 77), + (4718, 1, 330, 80, 0), + (4718, 2, 330, 80, 1), + (4718, 3, 330, 80, 2), + (4718, 4, 330, 80, 3), + (4718, 5, 330, 80, 28), + (4718, 6, 330, 80, 36), + (4718, 7, 330, 80, 77), + (4722, 1, 278, 620, 35216), + (4722, 2, 440, 66, 100), + (4723, 1, 278, 650, 38310), + (4723, 2, 440, 68, 100), + (4724, 1, 278, 670, 41300), + (4724, 2, 440, 70, 100), + (4725, 1, 341, 60, 0), + (4726, 1, 341, 70, 0), + (4727, 1, 341, 80, 0), + (4728, 1, 341, 90, 0), + (4729, 1, 341, 100, 0), + (4733, 1, 294, 11, 100), + (4734, 1, 294, 13, 100), + (4735, 1, 294, 15, 100), + (4739, 1, 360, 10, 11023), + (4740, 1, 360, 20, 11023), + (4741, 1, 360, 30, 11023), + (4744, 1, 318, 6, 0), + (4745, 1, 318, 7, 0), + (4746, 1, 318, 8, 0), + (4747, 1, 318, 9, 0), + (4748, 1, 318, 10, 0), + (4749, 1, 294, 11, 100), + (4750, 1, 294, 13, 100), + (4751, 1, 294, 15, 100), + (4752, 1, 294, 0, 155), + (4753, 1, 294, 0, 160), + (4754, 1, 294, 0, 165), + (4755, 1, 294, 0, 130), + (4756, 1, 294, 0, 135), + (4757, 1, 294, 0, 140), + (4758, 1, 266, 27, 0), + (4759, 1, 266, 28, 0), + (4760, 1, 266, 29, 0), + (4761, 1, 273, 2, 0), + (4762, 1, 273, 3, 0), + (4763, 1, 273, 4, 0), + (4764, 1, 326, 2, 0), + (4767, 1, 114, -43, 0), + (4768, 1, 114, -46, 0), + (4769, 1, 114, -50, 0), + (4773, 1, 339, 10, 8105), + (4773, 2, 142, 65, 0), + (4773, 3, 311, 0, 0), + (4773, 4, 134, 70, 0), + (4773, 5, 348, 10, 0), + (4773, 6, 137, 0, 0), + (4773, 7, 339, 10, 8105), + (4773, 8, 142, 65, 0), + (4773, 9, 311, 0, 0), + (4773, 10, 134, 70, 0), + (4773, 11, 348, 10, 0), + (4773, 12, 137, 100, 0), + (4773, 13, 339, 10, 8105), + (4773, 14, 142, 65, 0), + (4773, 15, 311, 0, 0), + (4773, 16, 134, 70, 0), + (4773, 17, 348, 10, 0), + (4773, 18, 137, 79, 0), + (4773, 19, 339, 10, 8105), + (4773, 20, 142, 65, 0), + (4773, 21, 311, 0, 0), + (4773, 22, 134, 70, 0), + (4773, 23, 348, 10, 0), + (4773, 24, 137, 147, 0), + (4773, 25, 339, 10, 11404), + (4773, 26, 142, 71, 0), + (4773, 27, 311, 0, 0), + (4773, 28, 134, 75, 0), + (4773, 29, 348, 10, 0), + (4773, 30, 137, 0, 0), + (4773, 31, 339, 10, 11404), + (4773, 32, 142, 71, 0), + (4773, 33, 311, 0, 0), + (4773, 34, 134, 75, 0), + (4773, 35, 348, 10, 0), + (4773, 36, 137, 100, 0), + (4773, 37, 339, 10, 11404), + (4773, 38, 142, 71, 0), + (4773, 39, 311, 0, 0), + (4773, 40, 134, 75, 0), + (4773, 41, 348, 10, 0), + (4773, 42, 137, 79, 0), + (4773, 43, 339, 10, 11404), + (4773, 44, 142, 71, 0), + (4773, 45, 311, 0, 0), + (4773, 46, 134, 75, 0), + (4773, 47, 348, 10, 0), + (4773, 48, 137, 147, 0), + (4776, 1, 319, 12, 0), + (4777, 1, 319, 14, 0), + (4778, 1, 319, 16, 0), + (4779, 1, 274, 24, 0), + (4780, 1, 274, 26, 0), + (4781, 1, 274, 28, 0), + (4790, 1, 220, 288, 74), + (4791, 1, 220, 320, 74), + (4792, 1, 220, 352, 74), + (4793, 1, 220, 384, 74), + (4794, 1, 220, 416, 74), + (4795, 1, 279, 28, 0), + (4796, 1, 279, 29, 0), + (4797, 1, 279, 30, 0), + (4798, 1, 292, 65, 0), + (4799, 1, 292, 70, 0), + (4800, 1, 292, 75, 0), + (4801, 1, 227, 30, 32), + (4802, 1, 227, 60, 32), + (4803, 1, 227, 90, 32), + (4804, 1, 220, 448, 74), + (4805, 1, 220, 480, 74), + (4806, 1, 220, 512, 74), + (4807, 1, 220, 544, 74), + (4808, 1, 220, 576, 74), + (4809, 1, 216, 40, 74), + (4810, 1, 216, 80, 74), + (4811, 1, 216, 120, 74), + (4813, 1, 220, 70, 26), + (4813, 2, 220, 70, 30), + (4813, 3, 220, 70, 38), + (4814, 1, 220, 80, 26), + (4814, 2, 220, 80, 30), + (4814, 3, 220, 80, 38), + (4815, 1, 220, 90, 26), + (4815, 2, 220, 90, 30), + (4815, 3, 220, 90, 38), + (4819, 1, 239, 52, 0), + (4820, 1, 239, 54, 0), + (4821, 1, 239, 56, 0), + (4822, 1, 239, 58, 0), + (4823, 1, 239, 60, 0), + (4824, 1, 239, 52, 0), + (4825, 1, 239, 54, 0), + (4826, 1, 239, 56, 0), + (4827, 1, 239, 58, 0), + (4828, 1, 239, 60, 0), + (4829, 1, 264, 480, 420), + (4830, 1, 264, 600, 420), + (4831, 1, 264, 720, 420), + (4844, 1, 349, 5, 0), + (4845, 1, 349, 10, 0), + (4846, 1, 349, 15, 0), + (4847, 1, 349, 20, 0), + (4848, 1, 349, 25, 0), + (4861, 1, 264, 600, 68), + (4862, 1, 264, 1200, 68), + (4863, 1, 264, 1800, 68), + (4887, 1, 264, 120, 413), + (4888, 1, 264, 240, 413), + (4889, 1, 264, 360, 413), + (4897, 1, 280, 44, 0), + (4898, 1, 280, 47, 0), + (4899, 1, 280, 50, 0), + (4921, 1, 264, 1896, 117), + (4921, 2, 244, 75, 0), + (4922, 1, 264, 2496, 117), + (4922, 2, 244, 60, 0), + (4923, 1, 264, 3096, 117), + (4923, 2, 244, 45, 0), + (4924, 1, 273, 1, 0), + (4925, 1, 273, 2, 0), + (4926, 1, 273, 3, 0), + (4948, 1, 258, 35, 0), + (4949, 1, 258, 40, 0), + (4950, 1, 258, 45, 0), + (4951, 1, 220, 40, 8), + (4952, 1, 220, 50, 8), + (4953, 1, 220, 60, 8), + (4957, 1, 252, 55, 0), + (4958, 1, 252, 60, 0), + (4959, 1, 252, 65, 0), + (4960, 1, 280, 46, 0), + (4961, 1, 280, 51, 0), + (4962, 1, 280, 56, 0), + (4983, 1, 216, 65, 0), + (4983, 2, 216, 65, 1), + (4983, 3, 216, 65, 2), + (4983, 4, 216, 65, 3), + (4983, 5, 216, 65, 10), + (4983, 6, 216, 65, 28), + (4983, 7, 216, 65, 30), + (4983, 8, 216, 65, 36), + (4983, 9, 216, 65, 77), + (4984, 1, 216, 70, 0), + (4984, 2, 216, 70, 1), + (4984, 3, 216, 70, 2), + (4984, 4, 216, 70, 3), + (4984, 5, 216, 70, 10), + (4984, 6, 216, 70, 28), + (4984, 7, 216, 70, 30), + (4984, 8, 216, 70, 36), + (4984, 9, 216, 70, 77), + (4985, 1, 216, 75, 0), + (4985, 2, 216, 75, 1), + (4985, 3, 216, 75, 2), + (4985, 4, 216, 75, 3), + (4985, 5, 216, 75, 10), + (4985, 6, 216, 75, 28), + (4985, 7, 216, 75, 30), + (4985, 8, 216, 75, 36), + (4985, 9, 216, 75, 77), + (4986, 1, 217, 0, 52960), + (4986, 2, 346, 66, 40), + (4987, 1, 217, 0, 55400), + (4987, 2, 346, 68, 40), + (4988, 1, 217, 0, 60280), + (4988, 2, 346, 70, 40), + (4989, 1, 347, 8, 0), + (4990, 1, 347, 10, 0), + (4991, 1, 347, 12, 0), + (4992, 1, 279, 21, 0), + (4993, 1, 279, 23, 0), + (4994, 1, 279, 25, 0), + (4995, 1, 279, 27, 0), + (4996, 1, 279, 28, 0), + (5000, 1, 313, 80, 0), + (5001, 1, 313, 90, 0), + (5002, 1, 313, 100, 0), + (5010, 1, 264, 432, 35), + (5011, 1, 264, 864, 35), + (5012, 1, 264, 1296, 35), + (5013, 1, 293, 90, 0), + (5014, 1, 293, 100, 0), + (5029, 1, 85, 11621, 0), + (5030, 1, 85, 11622, 0), + (5031, 1, 85, 11623, 0), + (5032, 1, 274, 22, 0), + (5033, 1, 274, 24, 0), + (5034, 1, 274, 26, 0), + (5035, 1, 293, 60, 0), + (5036, 1, 293, 70, 0), + (5037, 1, 293, 80, 0), + (5038, 1, 219, 330, 2100), + (5039, 1, 219, 360, 2200), + (5040, 1, 219, 390, 2300), + (5045, 1, 180, 5, 0), + (5061, 1, 244, -25, 0), + (5085, 1, 360, 25, 11297), + (5086, 1, 360, 25, 11298), + (5087, 1, 360, 25, 11299), + (5118, 1, 264, 720, 396), + (5118, 2, 264, 720, 8504), + (5118, 3, 264, 720, 8505), + (5119, 1, 264, 1440, 396), + (5119, 2, 264, 1440, 8504), + (5119, 3, 264, 1440, 8505), + (5120, 1, 264, 2160, 396), + (5120, 2, 264, 2160, 8504), + (5120, 3, 264, 2160, 8505), + (5127, 1, 264, 300, 261), + (5128, 1, 264, 600, 261), + (5129, 1, 264, 900, 261), + (5133, 1, 294, 13, 100), + (5134, 1, 294, 15, 100), + (5135, 1, 294, 17, 100), + (5136, 1, 282, 20, 0), + (5137, 1, 282, 40, 0), + (5138, 1, 282, 60, 0), + (5139, 1, 282, 80, 0), + (5140, 1, 282, 100, 0), + (5141, 1, 279, 21, 0), + (5142, 1, 279, 23, 0), + (5143, 1, 279, 25, 0), + (5144, 1, 279, 27, 0), + (5145, 1, 279, 28, 0), + (5243, 1, 69, 600, 0), + (5244, 1, 69, 700, 0), + (5245, 1, 69, 800, 0), + (5246, 1, 69, 900, 0), + (5247, 1, 69, 1000, 0), + (5248, 1, 360, 10, 11232), + (5249, 1, 360, 20, 11232), + (5250, 1, 360, 30, 11232), + (5254, 1, 218, 6, 0), + (5255, 1, 218, 7, 0), + (5256, 1, 218, 8, 0), + (5257, 1, 218, 9, 0), + (5258, 1, 218, 10, 0), + (5259, 1, 218, 6, 0), + (5260, 1, 218, 7, 0), + (5261, 1, 218, 8, 0), + (5262, 1, 218, 9, 0), + (5263, 1, 218, 10, 0), + (5264, 1, 218, 1, 0), + (5265, 1, 218, 2, 0), + (5266, 1, 218, 3, 0), + (5267, 1, 218, 4, 0), + (5268, 1, 218, 5, 0), + (5269, 1, 131, 50, 50), + (5269, 2, 137, 82, 0), + (5270, 1, 303, 3000, 3000), + (5270, 2, 139, 2766, 0), + (5271, 1, 303, 3500, 3500), + (5271, 2, 139, 2766, 0), + (5272, 1, 303, 4000, 4000), + (5272, 2, 139, 2766, 0), + (5276, 1, 264, 60, 621), + (5276, 2, 264, 60, 622), + (5276, 3, 264, 60, 623), + (5276, 4, 264, 60, 784), + (5276, 5, 264, 60, 785), + (5276, 6, 264, 60, 786), + (5276, 7, 264, 60, 787), + (5276, 8, 264, 60, 624), + (5277, 1, 264, 120, 621), + (5277, 2, 264, 120, 622), + (5277, 3, 264, 120, 623), + (5277, 4, 264, 120, 784), + (5277, 5, 264, 120, 785), + (5277, 6, 264, 120, 786), + (5277, 7, 264, 120, 787), + (5277, 8, 264, 120, 624), + (5278, 1, 264, 180, 621), + (5278, 2, 264, 180, 622), + (5278, 3, 264, 180, 623), + (5278, 4, 264, 180, 784), + (5278, 5, 264, 180, 785), + (5278, 6, 264, 180, 786), + (5278, 7, 264, 180, 787), + (5278, 8, 264, 180, 624), + (5283, 1, 320, 1, 0), + (5284, 1, 320, 3, 0), + (5285, 1, 320, 5, 0), + (5286, 1, 294, 7, 100), + (5287, 1, 294, 8, 100), + (5288, 1, 294, 9, 100), + (5290, 1, 439, 0, 46480), + (5290, 2, 345, 62, 0), + (5291, 1, 439, 0, 52960), + (5291, 2, 345, 63, 0), + (5292, 1, 439, 0, 55400), + (5292, 2, 345, 64, 0), + (5293, 1, 439, 0, 60280), + (5293, 2, 345, 65, 0), + (5294, 1, 439, 0, 65440), + (5294, 2, 345, 66, 50), + (5295, 1, 360, 10, 11629), + (5296, 1, 360, 20, 11629), + (5297, 1, 360, 30, 11629), + (5301, 1, 189, 7, 0), + (5302, 1, 189, 8, 0), + (5303, 1, 189, 9, 0), + (5304, 1, 189, 10, 0), + (5305, 1, 189, 11, 0), + (5306, 1, 15, 4, 0), + (5307, 1, 15, 5, 0), + (5308, 1, 15, 6, 0), + (5309, 1, 15, 7, 0), + (5310, 1, 15, 8, 0), + (5317, 1, 114, -43, 0), + (5318, 1, 114, -46, 0), + (5319, 1, 114, -50, 0), + (5320, 1, 218, 11, 0), + (5321, 1, 218, 12, 0), + (5322, 1, 218, 13, 0), + (5323, 1, 218, 14, 0), + (5324, 1, 218, 15, 0), + (5325, 1, 280, 27, 0), + (5326, 1, 280, 34, 0), + (5327, 1, 280, 41, 0), + (5328, 1, 280, 44, 0), + (5329, 1, 280, 47, 0), + (5339, 1, 215, 24, 0), + (5347, 1, 375, 225, 0), + (5348, 1, 375, 230, 0), + (5360, 1, 397, 1300, 0), + (5366, 1, 247, 75, 20), + (5500, 1, 231, 5, 0), + (5501, 1, 231, 7, 0), + (5502, 1, 231, 9, 0), + (5516, 1, 320, 6, 0), + (5517, 1, 320, 7, 0), + (5518, 1, 320, 8, 0), + (5519, 1, 172, 40, 0), + (5520, 1, 172, 41, 0), + (5521, 1, 172, 42, 0), + (5522, 1, 172, 43, 0), + (5523, 1, 172, 44, 0), + (5524, 1, 259, 46, 0), + (5525, 1, 259, 47, 0), + (5526, 1, 259, 48, 0), + (5527, 1, 259, 49, 0), + (5528, 1, 259, 50, 0), + (5529, 1, 339, 11, 12680), + (5529, 2, 138, 1, 0), + (5529, 3, 141, 1, 0), + (5529, 4, 142, 60, 0), + (5529, 5, 137, 0, 0), + (5529, 6, 311, 0, 0), + (5529, 7, 134, 80, 0), + (5529, 8, 139, -265, 0), + (5529, 9, 139, -754, 0), + (5529, 10, 139, -1332, 0), + (5529, 11, 139, -1572, 0), + (5529, 12, 139, -2749, 0), + (5529, 13, 139, -4979, 0), + (5529, 14, 139, -5418, 0), + (5529, 15, 139, -5403, 0), + (5529, 16, 348, 10, 0), + (5530, 1, 339, 13, 12681), + (5530, 2, 138, 1, 0), + (5530, 3, 141, 1, 0), + (5530, 4, 142, 60, 0), + (5530, 5, 137, 0, 0), + (5530, 6, 311, 0, 0), + (5530, 7, 134, 80, 0), + (5530, 8, 139, -265, 0), + (5530, 9, 139, -754, 0), + (5530, 10, 139, -1332, 0), + (5530, 11, 139, -1572, 0), + (5530, 12, 139, -2749, 0), + (5530, 13, 139, -4979, 0), + (5530, 14, 139, -5418, 0), + (5530, 15, 139, -5403, 0), + (5530, 16, 348, 10, 0), + (5531, 1, 339, 15, 12682), + (5531, 2, 138, 1, 0), + (5531, 3, 141, 1, 0), + (5531, 4, 142, 60, 0), + (5531, 5, 137, 0, 0), + (5531, 6, 311, 0, 0), + (5531, 7, 134, 80, 0), + (5531, 8, 139, -265, 0), + (5531, 9, 139, -754, 0), + (5531, 10, 139, -1332, 0), + (5531, 11, 139, -1572, 0), + (5531, 12, 139, -2749, 0), + (5531, 13, 139, -4979, 0), + (5531, 14, 139, -5418, 0), + (5531, 15, 139, -5403, 0), + (5531, 16, 348, 10, 0), + (5532, 1, 339, 17, 12683), + (5532, 2, 138, 1, 0), + (5532, 3, 141, 1, 0), + (5532, 4, 142, 60, 0), + (5532, 5, 137, 0, 0), + (5532, 6, 311, 0, 0), + (5532, 7, 134, 80, 0), + (5532, 8, 139, -265, 0), + (5532, 9, 139, -754, 0), + (5532, 10, 139, -1332, 0), + (5532, 11, 139, -1572, 0), + (5532, 12, 139, -2749, 0), + (5532, 13, 139, -4979, 0), + (5532, 14, 139, -5418, 0), + (5532, 15, 139, -5403, 0), + (5532, 16, 348, 10, 0), + (5533, 1, 339, 19, 12684), + (5533, 2, 138, 1, 0), + (5533, 3, 141, 1, 0), + (5533, 4, 142, 60, 0), + (5533, 5, 137, 0, 0), + (5533, 6, 311, 0, 0), + (5533, 7, 134, 80, 0), + (5533, 8, 139, -265, 0), + (5533, 9, 139, -754, 0), + (5533, 10, 139, -1332, 0), + (5533, 11, 139, -1572, 0), + (5533, 12, 139, -2749, 0), + (5533, 13, 139, -4979, 0), + (5533, 14, 139, -5418, 0), + (5533, 15, 139, -5403, 0), + (5533, 16, 348, 10, 0), + (5534, 1, 266, 18, 0), + (5535, 1, 266, 20, 0), + (5536, 1, 266, 22, 0), + (5542, 1, 330, 110, 0), + (5542, 2, 330, 110, 1), + (5542, 3, 330, 110, 2), + (5542, 4, 330, 110, 3), + (5542, 5, 330, 110, 28), + (5542, 6, 330, 110, 36), + (5542, 7, 330, 110, 77), + (5543, 1, 330, 115, 0), + (5543, 2, 330, 115, 1), + (5543, 3, 330, 115, 2), + (5543, 4, 330, 115, 3), + (5543, 5, 330, 115, 28), + (5543, 6, 330, 115, 36), + (5543, 7, 330, 115, 77), + (5544, 1, 330, 120, 0), + (5544, 2, 330, 120, 1), + (5544, 3, 330, 120, 2), + (5544, 4, 330, 120, 3), + (5544, 5, 330, 120, 28), + (5544, 6, 330, 120, 36), + (5544, 7, 330, 120, 77), + (5545, 1, 330, 110, 0), + (5545, 2, 330, 110, 1), + (5545, 3, 330, 110, 2), + (5545, 4, 330, 110, 3), + (5545, 5, 330, 110, 28), + (5545, 6, 330, 110, 36), + (5546, 1, 330, 115, 0), + (5546, 2, 330, 115, 1), + (5546, 3, 330, 115, 2), + (5546, 4, 330, 115, 3), + (5546, 5, 330, 115, 28), + (5546, 6, 330, 115, 36), + (5547, 1, 330, 120, 0), + (5547, 2, 330, 120, 1), + (5547, 3, 330, 120, 2), + (5547, 4, 330, 120, 3), + (5547, 5, 330, 120, 28), + (5547, 6, 330, 120, 36), + (5548, 1, 330, 110, 0), + (5548, 2, 330, 110, 1), + (5548, 3, 330, 110, 2), + (5548, 4, 330, 110, 3), + (5548, 5, 330, 110, 28), + (5548, 6, 330, 110, 36), + (5548, 7, 330, 110, 77), + (5549, 1, 330, 115, 0), + (5549, 2, 330, 115, 1), + (5549, 3, 330, 115, 2), + (5549, 4, 330, 115, 3), + (5549, 5, 330, 115, 28), + (5549, 6, 330, 115, 36), + (5549, 7, 330, 115, 77), + (5550, 1, 330, 120, 0), + (5550, 2, 330, 120, 1), + (5550, 3, 330, 120, 2), + (5550, 4, 330, 120, 3), + (5550, 5, 330, 120, 28), + (5550, 6, 330, 120, 36), + (5550, 7, 330, 120, 77), + (5551, 1, 330, 85, 0), + (5551, 2, 330, 85, 1), + (5551, 3, 330, 85, 2), + (5551, 4, 330, 85, 3), + (5551, 5, 330, 85, 28), + (5551, 6, 330, 85, 36), + (5551, 7, 330, 85, 77), + (5552, 1, 330, 90, 0), + (5552, 2, 330, 90, 1), + (5552, 3, 330, 90, 2), + (5552, 4, 330, 90, 3), + (5552, 5, 330, 90, 28), + (5552, 6, 330, 90, 36), + (5552, 7, 330, 90, 77), + (5553, 1, 330, 95, 0), + (5553, 2, 330, 95, 1), + (5553, 3, 330, 95, 2), + (5553, 4, 330, 95, 3), + (5553, 5, 330, 95, 28), + (5553, 6, 330, 95, 36), + (5553, 7, 330, 95, 77), + (5554, 1, 278, 700, 44340), + (5554, 2, 440, 71, 100), + (5555, 1, 278, 720, 47230), + (5555, 2, 440, 73, 100), + (5556, 1, 278, 750, 51057), + (5556, 2, 440, 75, 100), + (5557, 1, 341, 110, 0), + (5558, 1, 341, 120, 0), + (5559, 1, 341, 130, 0), + (5560, 1, 341, 140, 0), + (5561, 1, 341, 150, 0), + (5562, 1, 360, 40, 11023), + (5563, 1, 360, 50, 11023), + (5564, 1, 360, 60, 11023), + (5566, 1, 318, 11, 0), + (5567, 1, 318, 12, 0), + (5568, 1, 318, 13, 0), + (5569, 1, 318, 14, 0), + (5570, 1, 318, 15, 0), + (5571, 1, 294, 16, 100), + (5572, 1, 294, 17, 100), + (5573, 1, 294, 18, 100), + (5574, 1, 294, 0, 170), + (5575, 1, 294, 0, 175), + (5576, 1, 294, 0, 180), + (5577, 1, 294, 0, 145), + (5578, 1, 294, 0, 150), + (5579, 1, 294, 0, 155), + (5580, 1, 266, 30, 0), + (5581, 1, 266, 31, 0), + (5582, 1, 266, 32, 0), + (5586, 1, 114, -53, 0), + (5587, 1, 114, -56, 0), + (5588, 1, 114, -59, 0), + (5589, 1, 319, 17, 0), + (5590, 1, 319, 19, 0), + (5591, 1, 319, 21, 0), + (5592, 1, 274, 30, 0), + (5593, 1, 274, 32, 0), + (5594, 1, 274, 34, 0), + (5595, 1, 279, 31, 0), + (5596, 1, 279, 32, 0), + (5597, 1, 279, 33, 0), + (5611, 1, 274, 28, 0), + (5612, 1, 274, 30, 0), + (5613, 1, 274, 32, 0), + (5617, 1, 294, 18, 100), + (5618, 1, 294, 19, 100), + (5619, 1, 294, 20, 100), + (5620, 1, 320, 6, 0), + (5621, 1, 320, 7, 0), + (5622, 1, 320, 8, 0), + (5623, 1, 15, 9, 0), + (5624, 1, 15, 10, 0), + (5625, 1, 15, 11, 0), + (5626, 1, 15, 12, 0), + (5627, 1, 15, 13, 0), + (5628, 1, 114, -53, 0), + (5629, 1, 114, -56, 0), + (5630, 1, 114, -59, 0), + (5729, 1, 218, 11, 0), + (5730, 1, 218, 12, 0), + (5731, 1, 218, 13, 0), + (5732, 1, 218, 14, 0), + (5733, 1, 218, 15, 0), + (5738, 1, 280, 62, 0), + (5739, 1, 280, 63, 0), + (5740, 1, 280, 64, 0), + (5776, 1, 169, 5, -1), + (5777, 1, 169, 10, -1), + (5778, 1, 169, 15, -1), + (5797, 1, 264, 2520, 396), + (5797, 2, 264, 2520, 8504), + (5797, 3, 264, 2520, 8505), + (5798, 1, 264, 2880, 396), + (5798, 2, 264, 2880, 8504), + (5798, 3, 264, 2880, 8505), + (5799, 1, 264, 3240, 396), + (5799, 2, 264, 3240, 8504), + (5799, 3, 264, 3240, 8505), + (5806, 1, 279, 7, 0), + (5807, 1, 279, 11, 0), + (5808, 1, 279, 15, 0), + (5825, 1, 244, -40, 0), + (5850, 1, 287, 2, 1), + (5850, 2, 137, 31, 0), + (5850, 3, 136, 5, 0), + (5860, 1, 243, 40, 0), + (5861, 1, 243, 45, 0), + (5862, 1, 243, 50, 0), + (5880, 1, 287, 8, 0), + (5880, 2, 385, 2754, 1), + (5881, 1, 287, 10, 0), + (5881, 2, 385, 2754, 1), + (5882, 1, 287, 12, 0), + (5882, 2, 385, 2754, 1), + (5883, 2, 139, 2754, 1), + (5886, 1, 274, 12, 0), + (5887, 1, 274, 14, 0), + (5888, 1, 274, 16, 0), + (5889, 1, 280, 51, 0), + (5890, 1, 280, 52, 0), + (5891, 1, 280, 53, 0), + (5909, 1, 279, 29, 0), + (5910, 1, 279, 30, 0), + (5911, 1, 279, 31, 0), + (5912, 1, 279, 32, 0), + (5913, 1, 279, 33, 0), + (5917, 1, 220, 100, 26), + (5917, 2, 220, 100, 30), + (5917, 3, 220, 100, 38), + (5918, 1, 220, 110, 26), + (5918, 2, 220, 110, 30), + (5918, 3, 220, 110, 38), + (5919, 1, 220, 120, 26), + (5919, 2, 220, 120, 30), + (5919, 3, 220, 120, 38), + (5922, 1, 292, 35, 0), + (5923, 1, 292, 40, 0), + (5924, 1, 292, 45, 0), + (5939, 1, 218, 6, 0), + (5940, 1, 218, 7, 0), + (5941, 1, 218, 8, 0), + (5942, 1, 218, 9, 0), + (5943, 1, 218, 10, 0), + (5944, 1, 273, 4, 0), + (5945, 1, 273, 5, 0), + (5946, 1, 273, 6, 0), + (5950, 1, 264, 240, 175), + (5950, 2, 264, 240, 792), + (5951, 1, 264, 300, 175), + (5951, 2, 264, 300, 792), + (5952, 1, 264, 360, 175), + (5952, 2, 264, 360, 792), + (5954, 1, 264, 2400, 68), + (5955, 1, 264, 3000, 68), + (5956, 1, 264, 3600, 68), + (5972, 1, 264, 2880, 6001), + (5972, 2, 264, 2880, 3676), + (5973, 1, 264, 2880, 6000), + (5973, 2, 264, 2880, 87), + (6003, 1, 279, 29, 0), + (6004, 1, 279, 30, 0), + (6005, 1, 279, 31, 0), + (6006, 1, 279, 32, 0), + (6007, 1, 279, 33, 0), + (6011, 1, 216, 95, 0), + (6011, 2, 216, 95, 1), + (6011, 3, 216, 95, 2), + (6011, 4, 216, 95, 3), + (6011, 5, 216, 95, 10), + (6011, 6, 216, 95, 28), + (6011, 7, 216, 95, 30), + (6011, 8, 216, 95, 36), + (6011, 9, 216, 95, 77), + (6012, 1, 216, 100, 0), + (6012, 2, 216, 100, 1), + (6012, 3, 216, 100, 2), + (6012, 4, 216, 100, 3), + (6012, 5, 216, 100, 10), + (6012, 6, 216, 100, 28), + (6012, 7, 216, 100, 30), + (6012, 8, 216, 100, 36), + (6012, 9, 216, 100, 77), + (6013, 1, 216, 105, 0), + (6013, 2, 216, 105, 1), + (6013, 3, 216, 105, 2), + (6013, 4, 216, 105, 3), + (6013, 5, 216, 105, 10), + (6013, 6, 216, 105, 28), + (6013, 7, 216, 105, 30), + (6013, 8, 216, 105, 36), + (6013, 9, 216, 105, 77), + (6014, 1, 360, 40, 12617), + (6015, 1, 360, 50, 12617), + (6016, 1, 360, 60, 12617), + (6017, 1, 217, 0, 65440), + (6017, 2, 346, 72, 28), + (6018, 1, 217, 0, 70880), + (6018, 2, 346, 74, 28), + (6019, 1, 217, 0, 76600), + (6019, 2, 346, 76, 28), + (6020, 1, 220, 15, 21), + (6020, 2, 220, 15, 23), + (6020, 3, 220, 30, 52), + (6020, 4, 220, 15, 28), + (6021, 1, 220, 25, 21), + (6021, 2, 220, 25, 23), + (6021, 3, 220, 50, 52), + (6021, 4, 220, 25, 28), + (6022, 1, 220, 35, 21), + (6022, 2, 220, 35, 23), + (6022, 3, 220, 70, 52), + (6022, 4, 220, 35, 28), + (6023, 1, 278, 900, 66950), + (6023, 2, 440, 82, 100), + (6024, 1, 278, 900, 70230), + (6024, 2, 440, 84, 100), + (6025, 1, 278, 900, 74935), + (6025, 2, 440, 86, 100), + (6026, 1, 127, 10, 0), + (6026, 2, 139, 16106, 0), + (6027, 1, 127, 25, 0), + (6027, 2, 139, 16106, 0), + (6028, 1, 127, 50, 0), + (6028, 2, 139, 16106, 0), + (6029, 1, 216, 200, 8), + (6030, 1, 216, 250, 8), + (6031, 1, 216, 300, 8), + (6032, 1, 439, 0, 70880), + (6032, 2, 345, 68, 50), + (6033, 1, 439, 0, 76600), + (6033, 2, 345, 70, 50), + (6034, 1, 439, 0, 82600), + (6034, 2, 345, 72, 35), + (6035, 1, 258, 48, 0), + (6036, 1, 258, 51, 0), + (6037, 1, 258, 54, 0), + (6042, 1, 220, 70, 8), + (6043, 1, 220, 80, 8), + (6044, 1, 220, 100, 8), + (6045, 1, 220, 45, 21), + (6045, 2, 220, 45, 23), + (6045, 3, 220, 90, 52), + (6045, 4, 220, 45, 28), + (6046, 1, 220, 55, 21), + (6046, 2, 220, 55, 23), + (6046, 3, 220, 110, 52), + (6046, 4, 220, 55, 28), + (6047, 1, 220, 65, 21), + (6047, 2, 220, 65, 23), + (6047, 3, 220, 130, 52), + (6047, 4, 220, 65, 28), + (6048, 1, 220, 75, 21), + (6048, 2, 220, 75, 23), + (6048, 3, 220, 150, 52), + (6048, 4, 220, 75, 28), + (6049, 1, 220, 85, 21), + (6049, 2, 220, 85, 23), + (6049, 3, 220, 170, 52), + (6049, 4, 220, 85, 28), + (6050, 1, 220, 95, 21), + (6050, 2, 220, 95, 23), + (6050, 3, 220, 190, 52), + (6050, 4, 220, 95, 28), + (6051, 1, 213, 1, 0), + (6052, 1, 213, 3, 0), + (6053, 1, 213, 5, 0), + (6057, 1, 220, 105, 21), + (6057, 2, 220, 105, 23), + (6057, 3, 220, 210, 52), + (6057, 4, 220, 105, 28), + (6058, 1, 220, 115, 21), + (6058, 2, 220, 115, 23), + (6058, 3, 220, 230, 52), + (6058, 4, 220, 115, 28), + (6059, 1, 220, 125, 21), + (6059, 2, 220, 125, 23), + (6059, 3, 220, 250, 52), + (6059, 4, 220, 125, 28), + (6060, 1, 247, 5, 76), + (6061, 1, 247, 10, 76), + (6063, 1, 303, 4500, 4500), + (6063, 2, 139, 2766, 0), + (6064, 1, 303, 5000, 5000), + (6064, 2, 139, 2766, 0), + (6065, 1, 303, 5500, 5500), + (6065, 2, 139, 2766, 0), + (6066, 1, 85, 12629, 0), + (6067, 1, 85, 12630, 0), + (6068, 1, 85, 12631, 0), + (6069, 1, 85, 12632, 0), + (6070, 1, 85, 12633, 0), + (6071, 1, 85, 12634, 0), + (6072, 1, 302, 266, 266), + (6072, 2, 385, 99, 0), + (6073, 1, 302, 290, 290), + (6073, 2, 385, 99, 0), + (6074, 1, 302, 310, 310), + (6074, 2, 385, 99, 0), + (6075, 1, 59, -18, 0), + (6076, 1, 59, -21, 0), + (6077, 1, 59, -24, 0), + (6078, 1, 59, -27, 0), + (6079, 1, 59, -30, 0), + (6080, 1, 189, 12, 0), + (6081, 1, 189, 13, 0), + (6082, 1, 247, 50, 20), + (6083, 1, 247, 75, 20), + (6084, 1, 247, 100, 20), + (6085, 1, 292, 20, 0), + (6086, 1, 292, 30, 0), + (6087, 1, 292, 40, 0), + (6088, 1, 264, 180, 392), + (6089, 1, 264, 360, 392), + (6090, 1, 264, 540, 392), + (6112, 1, 131, 10, 10), + (6112, 2, 348, 10, 0), + (6112, 3, 137, -32, 0), + (6113, 1, 287, 2, 0), + (6113, 2, 137, 100, 0), + (6113, 3, 385, -4232, 0), + (6113, 4, 385, -4332, 0), + (6113, 5, 139, -2741, 0), + (6113, 6, 385, -16192, 0), + (6113, 7, 139, -16843, 0), + (6114, 1, 287, 3, 0), + (6114, 2, 137, 100, 0), + (6114, 3, 385, -4232, 0), + (6114, 4, 385, -4332, 0), + (6114, 5, 139, -2741, 0), + (6114, 6, 385, -16192, 0), + (6114, 7, 139, -16843, 0), + (6115, 1, 287, 4, 0), + (6115, 2, 137, 100, 0), + (6115, 3, 385, -4232, 0), + (6115, 4, 385, -4332, 0), + (6115, 5, 139, -2741, 0), + (6115, 6, 385, -16192, 0), + (6115, 7, 139, -16843, 0), + (6119, 1, 69, 100, 0), + (6120, 1, 69, 200, 0), + (6121, 1, 69, 300, 0), + (6122, 1, 69, 400, 0), + (6123, 1, 69, 500, 0), + (6124, 1, 320, 1, 0), + (6125, 1, 320, 3, 0), + (6126, 1, 320, 5, 0), + (6127, 1, 320, 6, 0), + (6128, 1, 320, 7, 0), + (6129, 1, 320, 8, 0), + (6130, 1, 255, 48, 0), + (6131, 1, 255, 60, 0), + (6132, 1, 255, 72, 0), + (6136, 1, 264, 360, 300), + (6202, 1, 247, 10, 35), + (6203, 1, 247, 20, 35), + (6204, 1, 247, 60, 35), + (6209, 1, 264, 720, 245), + (6210, 1, 264, 1440, 245), + (6211, 1, 264, 2160, 245), + (6215, 1, 247, 5, 76), + (6216, 1, 247, 10, 76), + (6217, 1, 247, 15, 76), + (6223, 1, 232, 11, 4544), + (6224, 1, 232, 12, 4544), + (6225, 1, 232, 13, 4544), + (6226, 1, 232, 14, 4544), + (6227, 1, 232, 15, 4544), + (6228, 1, 264, 120, 404), + (6229, 1, 264, 240, 404), + (6230, 1, 264, 360, 404), + (6231, 1, 264, 480, 404), + (6233, 1, 264, 1728, 43), + (6234, 1, 264, 2160, 43), + (6235, 1, 264, 2592, 43), + (6236, 1, 287, 1, 0), + (6236, 2, 137, 3, 0), + (6236, 3, 137, 99, 0), + (6236, 4, 138, 0, 0), + (6236, 5, 244, 50, 0), + (6237, 1, 287, 2, 0), + (6237, 2, 137, 3, 0), + (6237, 3, 137, 99, 0), + (6237, 4, 138, 0, 0), + (6237, 5, 244, 38, 0), + (6238, 1, 287, 3, 0), + (6238, 2, 137, 3, 0), + (6238, 3, 137, 99, 0), + (6238, 4, 138, 0, 0), + (6238, 5, 244, 25, 0), + (6240, 1, 273, 3, 0), + (6241, 1, 273, 6, 0), + (6242, 1, 273, 9, 0), + (6243, 1, 273, 12, 0), + (6244, 1, 273, 15, 0), + (6245, 1, 273, 18, 0), + (6249, 1, 310, 1000, 0), + (6249, 2, 139, 11903, 0), + (6249, 3, 310, 1000, 0), + (6249, 4, 139, 11904, 0), + (6249, 5, 310, 1000, 0), + (6249, 6, 139, 11905, 0), + (6249, 7, 310, 1000, 0), + (6249, 8, 139, 1362, 0), + (6249, 9, 310, 1000, 0), + (6249, 10, 139, 8032, 0), + (6249, 11, 310, 1000, 0), + (6249, 12, 385, 6131, 0), + (6249, 13, 385, 6231, 0), + (6249, 14, 385, 6331, 0), + (6249, 15, 385, 6431, 0), + (6249, 16, 385, 6531, 0), + (6249, 17, 385, 6631, 0), + (6250, 1, 310, 2000, 0), + (6250, 2, 139, 11903, 0), + (6250, 3, 310, 2000, 0), + (6250, 4, 139, 11904, 0), + (6250, 5, 310, 2000, 0), + (6250, 6, 139, 11905, 0), + (6250, 7, 310, 2000, 0), + (6250, 8, 139, 1362, 0), + (6250, 9, 310, 2000, 0), + (6250, 10, 139, 8032, 0), + (6250, 11, 310, 2000, 0), + (6250, 12, 385, 6131, 0), + (6250, 13, 385, 6231, 0), + (6250, 14, 385, 6331, 0), + (6250, 15, 385, 6431, 0), + (6250, 16, 385, 6531, 0), + (6250, 17, 385, 6631, 0), + (6251, 1, 310, 3000, 0), + (6251, 2, 139, 11903, 0), + (6251, 3, 310, 3000, 0), + (6251, 4, 139, 11904, 0), + (6251, 5, 310, 3000, 0), + (6251, 6, 139, 11905, 0), + (6251, 7, 310, 3000, 0), + (6251, 8, 139, 1362, 0), + (6251, 9, 310, 3000, 0), + (6251, 10, 139, 8032, 0), + (6251, 11, 310, 3000, 0), + (6251, 12, 385, 6131, 0), + (6251, 13, 385, 6231, 0), + (6251, 14, 385, 6331, 0), + (6251, 15, 385, 6431, 0), + (6251, 16, 385, 6531, 0), + (6251, 17, 385, 6631, 0), + (6252, 1, 310, 4000, 0), + (6252, 2, 139, 11903, 0), + (6252, 3, 310, 4000, 0), + (6252, 4, 139, 11904, 0), + (6252, 5, 310, 4000, 0), + (6252, 6, 139, 11905, 0), + (6252, 7, 310, 4000, 0), + (6252, 8, 139, 1362, 0), + (6252, 9, 310, 4000, 0), + (6252, 10, 139, 8032, 0), + (6252, 11, 310, 4000, 0), + (6252, 12, 385, 6131, 0), + (6252, 13, 385, 6231, 0), + (6252, 14, 385, 6331, 0), + (6252, 15, 385, 6431, 0), + (6252, 16, 385, 6531, 0), + (6252, 17, 385, 6631, 0), + (6253, 1, 310, 5000, 0), + (6253, 2, 139, 11903, 0), + (6253, 3, 310, 5000, 0), + (6253, 4, 139, 11904, 0), + (6253, 5, 310, 5000, 0), + (6253, 6, 139, 11905, 0), + (6253, 7, 310, 5000, 0), + (6253, 8, 139, 1362, 0), + (6253, 9, 310, 5000, 0), + (6253, 10, 139, 8032, 0), + (6253, 11, 310, 5000, 0), + (6253, 12, 385, 6131, 0), + (6253, 13, 385, 6231, 0), + (6253, 14, 385, 6331, 0), + (6253, 15, 385, 6431, 0), + (6253, 16, 385, 6531, 0), + (6253, 17, 385, 6631, 0), + (6257, 1, 128, 5, 5), + (6257, 2, 138, 1, 0), + (6257, 3, 140, 1, 0), + (6257, 4, 139, -2741, 0), + (6257, 5, 139, -16843, 0), + (6257, 6, 385, -16192, 0), + (6258, 1, 128, 15, 15), + (6258, 2, 138, 1, 0), + (6258, 3, 140, 1, 0), + (6258, 4, 139, -2741, 0), + (6258, 5, 139, -16843, 0), + (6258, 6, 385, -16192, 0), + (6259, 1, 128, 30, 30), + (6259, 2, 138, 1, 0), + (6259, 3, 140, 1, 0), + (6259, 4, 139, -2741, 0), + (6259, 5, 139, -16843, 0), + (6259, 6, 385, -16192, 0), + (6260, 1, 264, 720, 98), + (6261, 1, 264, 900, 98), + (6262, 1, 264, 1080, 98), + (6266, 1, 224, 20, 10), + (6266, 2, 173, 1, 0), + (6267, 1, 224, 35, 10), + (6267, 2, 173, 2, 0), + (6268, 1, 224, 50, 10), + (6268, 2, 173, 3, 0), + (6269, 1, 224, 20, 30), + (6269, 2, 173, 1, 0), + (6270, 1, 224, 35, 30), + (6270, 2, 173, 2, 0), + (6271, 1, 224, 50, 30), + (6271, 2, 173, 3, 0), + (6272, 1, 264, 15, 672), + (6273, 1, 264, 30, 672), + (6274, 1, 264, 45, 672), + (6275, 1, 224, 20, 8), + (6275, 2, 173, 1, 0), + (6276, 1, 224, 35, 8), + (6276, 2, 173, 2, 0), + (6277, 1, 224, 50, 8), + (6277, 2, 173, 3, 0), + (6283, 1, 85, 13200, 0), + (6284, 1, 85, 13200, 25), + (6285, 1, 85, 13200, 50), + (6287, 1, 224, 20, 30), + (6287, 2, 173, 1, 0), + (6288, 1, 224, 35, 30), + (6288, 2, 173, 3, 0), + (6289, 1, 224, 50, 30), + (6289, 2, 173, 3, 0), + (6300, 1, 247, 20, 76), + (6301, 1, 247, 25, 76), + (6302, 1, 264, 120, 3710), + (6303, 1, 264, 240, 3710), + (6304, 1, 264, 360, 3710), + (6319, 1, 264, 1728, 107), + (6320, 1, 264, 2160, 107), + (6321, 1, 264, 2592, 107), + (6322, 1, 216, 5, 51), + (6323, 1, 216, 15, 51), + (6324, 1, 216, 25, 51), + (6331, 1, 252, 70, 0), + (6332, 1, 252, 75, 0), + (6334, 1, 185, 5, 51), + (6335, 1, 185, 10, 51), + (6336, 1, 185, 15, 51), + (6337, 1, 264, 60, 553), + (6338, 1, 264, 120, 553), + (6339, 1, 264, 180, 553), + (6340, 1, 264, 180, 777), + (6341, 1, 264, 360, 777), + (6342, 1, 264, 540, 777), + (6343, 1, 264, 5, 468), + (6343, 2, 264, 5, 469), + (6343, 3, 264, 5, 470), + (6344, 1, 264, 10, 468), + (6344, 2, 264, 10, 469), + (6344, 3, 264, 10, 470), + (6345, 1, 264, 15, 468), + (6345, 2, 264, 15, 469), + (6345, 3, 264, 15, 470), + (6346, 1, 264, 180, 494), + (6347, 1, 264, 360, 494), + (6348, 1, 264, 540, 494), + (6349, 1, 264, 180, 500), + (6350, 1, 264, 360, 500), + (6351, 1, 264, 540, 500), + (6355, 1, 310, 360000, 0), + (6355, 2, 139, 4506, 0), + (6355, 3, 310, 360000, 0), + (6355, 4, 385, 11122, 0), + (6355, 5, 385, 11222, 0), + (6355, 6, 385, 11322, 0), + (6355, 7, 385, 11522, 0), + (6356, 1, 310, 720000, 0), + (6356, 2, 139, 4506, 0), + (6356, 3, 310, 720000, 0), + (6356, 4, 385, 11122, 0), + (6356, 5, 385, 11222, 0), + (6356, 6, 385, 11322, 0), + (6356, 7, 385, 11522, 0), + (6357, 1, 310, 1080000, 0), + (6357, 2, 139, 4506, 0), + (6357, 3, 310, 1080000, 0), + (6357, 4, 385, 11122, 0), + (6357, 5, 385, 11222, 0), + (6357, 6, 385, 11322, 0), + (6357, 7, 385, 11522, 0), + (6358, 1, 310, 1440000, 0), + (6358, 2, 139, 4506, 0), + (6358, 3, 310, 1440000, 0), + (6358, 4, 385, 11122, 0), + (6358, 5, 385, 11222, 0), + (6358, 6, 385, 11322, 0), + (6358, 7, 385, 11522, 0), + (6359, 1, 310, 1800000, 0), + (6359, 2, 139, 4506, 0), + (6359, 3, 310, 1800000, 0), + (6359, 4, 385, 11122, 0), + (6359, 5, 385, 11222, 0), + (6359, 6, 385, 11322, 0), + (6359, 7, 385, 11522, 0), + (6360, 1, 310, 2160000, 0), + (6360, 2, 139, 4506, 0), + (6360, 3, 310, 2160000, 0), + (6360, 4, 385, 11122, 0), + (6360, 5, 385, 11222, 0), + (6360, 6, 385, 11322, 0), + (6360, 7, 385, 11522, 0), + (6361, 1, 213, 3, 0), + (6362, 1, 310, 120000, 0), + (6362, 2, 139, 5040, 0), + (6363, 1, 310, 240000, 0), + (6363, 2, 139, 5040, 0), + (6364, 1, 310, 360000, 0), + (6364, 2, 139, 5040, 0), + (6365, 1, 310, 480000, 0), + (6365, 2, 139, 5040, 0), + (6366, 1, 310, 600000, 0), + (6366, 2, 139, 5040, 0), + (6375, 1, 375, 107, 0), + (6376, 1, 375, 115, 0), + (6377, 1, 375, 125, 0), + (6383, 1, 215, 5, 0), + (6384, 1, 215, 7, 0), + (6385, 1, 215, 10, 0), + (6386, 1, 293, 5, 0), + (6387, 1, 293, 10, 0), + (6388, 1, 293, 15, 0), + (6389, 1, 293, 20, 0), + (6390, 1, 0, 16, 0), + (6391, 1, 0, 17, 0), + (6392, 1, 0, 18, 0), + (6393, 1, 0, 19, 0), + (6394, 1, 0, 20, 0), + (6395, 1, 85, 13502, 0), + (6396, 1, 85, 13503, 0), + (6397, 1, 85, 13504, 0), + (6403, 1, 294, 11, 100), + (6404, 1, 294, 13, 100), + (6405, 1, 294, 15, 100), + (6406, 1, 360, 25, 13201), + (6407, 1, 360, 25, 13202), + (6408, 1, 360, 25, 13203), + (6409, 1, 247, 5, 76), + (6410, 1, 247, 10, 76), + (6411, 1, 247, 15, 76), + (6412, 1, 247, 20, 76), + (6413, 1, 247, 25, 76), + (6414, 1, 247, 30, 76), + (6415, 1, 247, 35, 76), + (6416, 1, 247, 40, 76), + (6417, 1, 247, 45, 76), + (6418, 1, 247, 50, 76), + (6419, 1, 247, 5, 76), + (6420, 1, 247, 10, 76), + (6421, 1, 247, 15, 76), + (6422, 1, 214, 100, 0), + (6423, 1, 214, 200, 0), + (6424, 1, 214, 300, 0), + (6428, 1, 320, 1, 0), + (6429, 1, 320, 3, 0), + (6430, 1, 320, 5, 0), + (6431, 1, 317, 6, 0), + (6432, 1, 317, 7, 0), + (6433, 1, 317, 8, 0), + (6434, 1, 317, 9, 0), + (6435, 1, 317, 10, 0), + (6436, 1, 244, 70, 0), + (6437, 1, 244, 60, 0), + (6438, 1, 244, 50, 0), + (6439, 1, 264, 720, 41), + (6440, 1, 264, 900, 41), + (6441, 1, 264, 840, 420), + (6442, 1, 264, 540, 362), + (6443, 1, 264, 630, 362), + (6445, 1, 127, 15, 0), + (6445, 2, 139, 3248, 0), + (6445, 3, 127, 15, 0), + (6445, 4, 139, 3249, 0), + (6446, 1, 127, 30, 0), + (6446, 2, 139, 3248, 0), + (6446, 3, 127, 30, 0), + (6446, 4, 139, 3249, 0), + (6447, 1, 127, 50, 0), + (6447, 2, 139, 3248, 0), + (6447, 3, 127, 50, 0), + (6447, 4, 139, 3249, 0), + (6452, 1, 310, 1000, 0), + (6452, 2, 403, 7, 0), + (6452, 3, 404, 35, 0), + (6452, 4, 144, 2000, 0), + (6452, 5, 310, 5000, 0), + (6452, 6, 403, 7, 0), + (6452, 7, 404, 35, 0), + (6452, 8, 144, 10000, 0), + (6453, 1, 310, 2000, 0), + (6453, 2, 403, 7, 0), + (6453, 3, 404, 35, 0), + (6453, 4, 144, 2000, 0), + (6453, 5, 310, 10000, 0), + (6453, 6, 403, 7, 0), + (6453, 7, 404, 35, 0), + (6453, 8, 144, 10000, 0), + (6454, 1, 310, 3000, 0), + (6454, 2, 403, 7, 0), + (6454, 3, 404, 35, 0), + (6454, 4, 144, 2000, 0), + (6454, 5, 310, 15000, 0), + (6454, 6, 403, 7, 0), + (6454, 7, 404, 35, 0), + (6454, 8, 144, 10000, 0), + (6458, 1, 310, 30000, 0), + (6458, 2, 385, 5137, 0), + (6458, 3, 385, 5237, 0), + (6458, 4, 385, 5337, 0), + (6458, 5, 385, 5437, 0), + (6458, 6, 385, 5537, 0), + (6458, 7, 385, 5637, 0), + (6458, 8, 127, 15, 15), + (6458, 9, 385, 5137, 0), + (6458, 10, 385, 5237, 0), + (6458, 11, 385, 5337, 0), + (6458, 12, 385, 5437, 0), + (6458, 13, 385, 5537, 0), + (6458, 14, 385, 5637, 0), + (6459, 1, 310, 60000, 0), + (6459, 2, 385, 5137, 0), + (6459, 3, 385, 5237, 0), + (6459, 4, 385, 5337, 0), + (6459, 5, 385, 5437, 0), + (6459, 6, 385, 5537, 0), + (6459, 7, 385, 5637, 0), + (6459, 8, 127, 30, 30), + (6459, 9, 385, 5137, 0), + (6459, 10, 385, 5237, 0), + (6459, 11, 385, 5337, 0), + (6459, 12, 385, 5437, 0), + (6459, 13, 385, 5537, 0), + (6459, 14, 385, 5637, 0), + (6460, 1, 310, 90000, 0), + (6460, 2, 385, 5137, 0), + (6460, 3, 385, 5237, 0), + (6460, 4, 385, 5337, 0), + (6460, 5, 385, 5437, 0), + (6460, 6, 385, 5537, 0), + (6460, 7, 385, 5637, 0), + (6460, 8, 127, 50, 50), + (6460, 9, 385, 5137, 0), + (6460, 10, 385, 5237, 0), + (6460, 11, 385, 5337, 0), + (6460, 12, 385, 5437, 0), + (6460, 13, 385, 5537, 0), + (6460, 14, 385, 5637, 0), + (6461, 1, 127, 15, 0), + (6461, 2, 385, 14130, 0), + (6461, 3, 385, 14230, 0), + (6461, 4, 385, 14330, 0), + (6461, 5, 385, 14430, 0), + (6461, 6, 385, 14530, 0), + (6461, 7, 385, 14630, 0), + (6461, 8, 310, 30000, 0), + (6461, 9, 385, 14130, 0), + (6461, 10, 385, 14230, 0), + (6461, 11, 385, 14330, 0), + (6461, 12, 385, 14430, 0), + (6461, 13, 385, 14530, 0), + (6461, 14, 385, 14630, 0), + (6462, 1, 127, 30, 0), + (6462, 2, 385, 14130, 0), + (6462, 3, 385, 14230, 0), + (6462, 4, 385, 14330, 0), + (6462, 5, 385, 14430, 0), + (6462, 6, 385, 14530, 0), + (6462, 7, 385, 14630, 0), + (6462, 8, 310, 60000, 0), + (6462, 9, 385, 14130, 0), + (6462, 10, 385, 14230, 0), + (6462, 11, 385, 14330, 0), + (6462, 12, 385, 14430, 0), + (6462, 13, 385, 14530, 0), + (6462, 14, 385, 14630, 0), + (6463, 1, 127, 50, 0), + (6463, 2, 385, 14130, 0), + (6463, 3, 385, 14230, 0), + (6463, 4, 385, 14330, 0), + (6463, 5, 385, 14430, 0), + (6463, 6, 385, 14530, 0), + (6463, 7, 385, 14630, 0), + (6463, 8, 310, 90000, 0), + (6463, 9, 385, 14130, 0), + (6463, 10, 385, 14230, 0), + (6463, 11, 385, 14330, 0), + (6463, 12, 385, 14430, 0), + (6463, 13, 385, 14530, 0), + (6463, 14, 385, 14630, 0), + (6467, 1, 214, 100, 0), + (6468, 1, 214, 200, 0), + (6469, 1, 214, 300, 0), + (6470, 1, 247, 15, 76), + (6471, 1, 247, 20, 76), + (6472, 1, 247, 30, 76), + (6473, 1, 247, 35, 76), + (6474, 1, 247, 55, 76), + (6475, 1, 247, 60, 76), + (6476, 1, 247, 20, 76), + (6477, 1, 247, 25, 76), + (6478, 1, 264, 1, 3800), + (6479, 1, 264, 2, 3800), + (6480, 1, 264, 3, 3800), + (6481, 1, 264, 6480, 36), + (6482, 1, 264, 12960, 36), + (6483, 1, 264, 19440, 36), + (6484, 1, 264, 105, 558), + (6485, 1, 264, 120, 558), + (6486, 1, 264, 135, 558), + (6489, 1, 310, 600000, 0), + (6489, 2, 139, 4500, 0), + (6489, 3, 411, 8, 0), + (6490, 1, 310, 1200000, 0), + (6490, 2, 139, 4500, 0), + (6490, 3, 411, 8, 0), + (6491, 1, 310, 1800000, 0), + (6491, 2, 139, 4500, 0), + (6491, 3, 411, 8, 0), + (6500, 1, 273, 5, 0), + (6501, 1, 273, 6, 0), + (6502, 1, 273, 7, 0), + (6503, 1, 127, 12, 0), + (6503, 2, 385, 3338, 0), + (6504, 1, 127, 24, 0), + (6504, 2, 385, 3338, 0), + (6505, 1, 127, 36, 0), + (6505, 2, 385, 3338, 0), + (6506, 1, 127, 50, 0), + (6506, 2, 385, 3338, 0), + (6511, 1, 216, 5, 7), + (6512, 1, 216, 15, 7), + (6513, 1, 216, 25, 7), + (6514, 1, 127, 15, 0), + (6514, 2, 139, 5880, 0), + (6515, 1, 127, 30, 0), + (6515, 2, 139, 5880, 0), + (6516, 1, 127, 50, 0), + (6516, 2, 139, 5880, 0), + (6517, 1, 339, 10, 8105), + (6517, 2, 142, 65, 0), + (6517, 3, 311, 0, 0), + (6517, 4, 134, 70, 0), + (6517, 5, 348, 10, 0), + (6517, 6, 137, 0, 0), + (6517, 7, 339, 10, 8105), + (6517, 8, 142, 65, 0), + (6517, 9, 311, 0, 0), + (6517, 10, 134, 70, 0), + (6517, 11, 348, 10, 0), + (6517, 12, 137, 100, 0), + (6517, 13, 339, 10, 8105), + (6517, 14, 142, 65, 0), + (6517, 15, 311, 0, 0), + (6517, 16, 134, 70, 0), + (6517, 17, 348, 10, 0), + (6517, 18, 137, 79, 0), + (6517, 19, 339, 10, 8105), + (6517, 20, 142, 65, 0), + (6517, 21, 311, 0, 0), + (6517, 22, 134, 70, 0), + (6517, 23, 348, 10, 0), + (6517, 24, 137, 147, 0), + (6517, 25, 339, 10, 11404), + (6517, 26, 142, 71, 0), + (6517, 27, 311, 0, 0), + (6517, 28, 134, 75, 0), + (6517, 29, 348, 10, 0), + (6517, 30, 137, 0, 0), + (6517, 31, 339, 10, 11404), + (6517, 32, 142, 71, 0), + (6517, 33, 311, 0, 0), + (6517, 34, 134, 75, 0), + (6517, 35, 348, 10, 0), + (6517, 36, 137, 100, 0), + (6517, 37, 339, 10, 11404), + (6517, 38, 142, 71, 0), + (6517, 39, 311, 0, 0), + (6517, 40, 134, 75, 0), + (6517, 41, 348, 10, 0), + (6517, 42, 137, 79, 0), + (6517, 43, 339, 10, 11404), + (6517, 44, 142, 71, 0), + (6517, 45, 311, 0, 0), + (6517, 46, 134, 75, 0), + (6517, 47, 348, 10, 0), + (6517, 48, 137, 147, 0), + (6517, 49, 339, 10, 13199), + (6517, 50, 142, 76, 0), + (6517, 51, 311, 0, 0), + (6517, 52, 134, 80, 0), + (6517, 53, 348, 10, 0), + (6517, 54, 137, 0, 0), + (6517, 55, 339, 10, 13199), + (6517, 56, 142, 76, 0), + (6517, 57, 311, 0, 0), + (6517, 58, 134, 80, 0), + (6517, 59, 348, 10, 0), + (6517, 60, 137, 100, 0), + (6517, 61, 339, 10, 13199), + (6517, 62, 142, 76, 0), + (6517, 63, 311, 0, 0), + (6517, 64, 134, 80, 0), + (6517, 65, 348, 10, 0), + (6517, 66, 137, 79, 0), + (6517, 67, 339, 10, 13199), + (6517, 68, 142, 76, 0), + (6517, 69, 311, 0, 0), + (6517, 70, 134, 80, 0), + (6517, 71, 348, 10, 0), + (6517, 72, 137, 147, 0), + (6518, 1, 221, 18, 0), + (6519, 1, 221, 21, 0), + (6520, 1, 221, 24, 0), + (6521, 1, 327, 6, 0), + (6522, 1, 327, 7, 0), + (6523, 1, 328, 800, 0), + (6524, 1, 328, 850, 0), + (6525, 1, 328, 900, 0), + (6526, 1, 328, 950, 0), + (6527, 1, 328, 1000, 0), + (6528, 1, 264, 3024, 107), + (6531, 1, 360, 40, 11629), + (6532, 1, 360, 50, 11629), + (6533, 1, 360, 60, 11629), + (6540, 1, 363, 2, 0), + (6545, 1, 362, 2, 0), + (6546, 1, 2, 4, 0), + (6547, 1, 2, 8, 0), + (6548, 1, 2, 12, 0), + (6549, 1, 2, 16, 0), + (6550, 1, 2, 20, 0), + (6551, 1, 2, 24, 0), + (6552, 1, 2, 28, 0), + (6553, 1, 2, 32, 0), + (6554, 1, 2, 36, 0), + (6555, 1, 2, 40, 0), + (6556, 1, 2, 44, 0), + (6557, 1, 2, 48, 0), + (6558, 1, 2, 52, 0), + (6559, 1, 2, 56, 0), + (6560, 1, 2, 60, 0), + (6561, 1, 2, 64, 0), + (6562, 1, 2, 68, 0), + (6563, 1, 2, 72, 0), + (6564, 1, 2, 76, 0), + (6565, 1, 2, 80, 0), + (6566, 1, 2, 84, 0), + (6567, 1, 2, 88, 0), + (6568, 1, 2, 92, 0), + (6569, 1, 2, 96, 0), + (6570, 1, 2, 100, 0), + (6571, 1, 2, 104, 0), + (6601, 1, 339, 5, 13519), + (6601, 2, 137, 21, 0), + (6602, 1, 339, 10, 13519), + (6602, 2, 137, 21, 0), + (6603, 1, 339, 15, 13519), + (6603, 2, 137, 21, 0), + (6604, 1, 339, 20, 13519), + (6604, 2, 137, 21, 0), + (6605, 1, 339, 25, 13519), + (6605, 2, 137, 21, 0), + (6611, 1, 310, 120000, 0), + (6611, 2, 139, 4670, 0), + (6612, 1, 310, 240000, 0), + (6612, 2, 139, 4670, 0), + (6613, 1, 310, 360000, 0), + (6613, 2, 139, 4670, 0), + (6614, 1, 310, 120000, 0), + (6614, 2, 139, 4674, 0), + (6615, 1, 310, 240000, 0), + (6615, 2, 139, 4674, 0), + (6616, 1, 310, 360000, 0), + (6616, 2, 139, 4674, 0), + (6618, 1, 310, 480000, 0), + (6618, 2, 139, 4670, 0), + (6619, 1, 310, 600000, 0), + (6619, 2, 139, 4670, 0), + (6630, 1, 218, 1, 0), + (6631, 1, 218, 2, 0), + (6632, 1, 218, 3, 0), + (6633, 1, 218, 4, 0), + (6634, 1, 218, 5, 0), + (6636, 1, 294, 0, 107), + (6637, 1, 294, 0, 115), + (6638, 1, 294, 0, 125), + (6641, 1, 339, 10, 16101), + (6641, 2, 138, 0, 0), + (6641, 3, 142, 70, 0), + (6641, 4, 403, 4, 0), + (6641, 5, 348, 1, 0), + (6641, 6, 404, 2, 0), + (6641, 7, 141, 1, 0), + (6642, 1, 339, 10, 16102), + (6642, 2, 138, 0, 0), + (6642, 3, 142, 70, 0), + (6642, 4, 403, 4, 0), + (6642, 5, 348, 1, 0), + (6642, 6, 404, 2, 0), + (6642, 7, 141, 1, 0), + (6643, 1, 339, 10, 16103), + (6643, 2, 138, 0, 0), + (6643, 3, 142, 70, 0), + (6643, 4, 403, 4, 0), + (6643, 5, 348, 1, 0), + (6643, 6, 404, 2, 0), + (6643, 7, 141, 1, 0), + (6660, 1, 325, 55, 0), + (6661, 1, 325, 60, 0), + (6662, 1, 325, 65, 0), + (6666, 1, 287, 2, 0), + (6666, 2, 139, 8001, 0), + (6666, 3, 385, 12529, 0), + (6667, 1, 287, 4, 0), + (6667, 2, 139, 8001, 0), + (6667, 3, 385, 12529, 0), + (6668, 1, 287, 2, 0), + (6668, 2, 139, 11251, 0), + (6668, 3, 139, 11252, 0), + (6668, 4, 139, 11253, 0), + (6669, 1, 287, 4, 0), + (6669, 2, 139, 11251, 0), + (6669, 3, 139, 11252, 0), + (6669, 4, 139, 11253, 0), + (6670, 1, 287, 6, 0), + (6670, 2, 139, 11251, 0), + (6670, 3, 139, 11252, 0), + (6670, 4, 139, 11253, 0), + (6697, 1, 264, 30, 857), + (6698, 1, 264, 60, 857), + (6699, 1, 264, 90, 857), + (6700, 1, 264, 120, 857), + (6701, 1, 264, 150, 857), + (6703, 1, 264, 10, 171), + (6704, 1, 264, 20, 171), + (6705, 1, 264, 30, 171), + (6709, 1, 127, 5, 0), + (6709, 2, 139, 3842, 0), + (6710, 1, 127, 10, 0), + (6710, 2, 139, 3842, 0), + (6711, 1, 127, 15, 0), + (6711, 2, 139, 3842, 0), + (6712, 1, 264, 30, 177), + (6713, 1, 264, 60, 177), + (6714, 1, 264, 90, 177), + (6715, 1, 264, 120, 177), + (6716, 1, 264, 150, 177), + (6751, 1, 310, 240000, 0), + (6751, 2, 139, 4519, 0), + (6752, 1, 310, 480000, 0), + (6752, 2, 139, 4519, 0), + (6753, 1, 310, 720000, 0), + (6753, 2, 139, 4519, 0), + (6761, 1, 292, 5, 0), + (6762, 1, 292, 10, 0), + (6763, 1, 292, 15, 0), + (6765, 1, 330, 15, 7), + (6766, 1, 330, 30, 7), + (6767, 1, 330, 50, 7), + (6768, 1, 310, 960000, 0), + (6768, 2, 139, 4519, 0), + (6769, 1, 310, 1200000, 0), + (6769, 2, 139, 4519, 0), + (6791, 1, 339, 20, 16139), + (6791, 2, 137, 21, 0), + (6791, 3, 385, -18000, 0), + (6791, 4, 339, 20, 16139), + (6791, 5, 137, 343, 0), + (6791, 6, 385, -18000, 0), + (6792, 1, 339, 20, 16140), + (6792, 2, 137, 21, 0), + (6792, 3, 385, -18000, 0), + (6792, 4, 339, 20, 16140), + (6792, 5, 137, 343, 0), + (6792, 6, 385, -18000, 0), + (6793, 1, 339, 20, 16141), + (6793, 2, 137, 21, 0), + (6793, 3, 385, -18000, 0), + (6793, 4, 339, 20, 16141), + (6793, 5, 137, 343, 0), + (6793, 6, 385, -18000, 0), + (6819, 1, 264, 180, 524), + (6820, 1, 264, 360, 524), + (6821, 1, 264, 540, 524), + (6823, 1, 264, 180, 320), + (6824, 1, 264, 360, 320), + (6825, 1, 264, 540, 320), + (6826, 1, 264, 720, 320), + (6827, 1, 264, 900, 320), + (6870, 1, 264, 180, 544), + (6871, 1, 264, 360, 544), + (6872, 1, 264, 540, 544), + (6873, 1, 279, 7, 0), + (6874, 1, 279, 11, 0), + (6875, 1, 279, 15, 0), + (6876, 1, 375, 107, 0), + (6877, 1, 375, 115, 0), + (6878, 1, 375, 125, 0), + (6879, 1, 243, 15, 0), + (6880, 1, 243, 25, 0), + (6881, 1, 243, 35, 0), + (6882, 1, 242, 5, 0), + (6883, 1, 242, 10, 0), + (6884, 1, 242, 15, 0), + (6900, 1, 264, 840, 465), + (6901, 1, 264, 1140, 465), + (6902, 1, 264, 1440, 465), + (6903, 1, 264, 1740, 465), + (6904, 1, 264, 2040, 465), + (6905, 1, 225, 33, 0), + (6906, 1, 225, 36, 0), + (6907, 1, 225, 39, 0), + (6908, 1, 264, 180, 499), + (6909, 1, 264, 360, 499), + (6910, 1, 264, 540, 499), + (6911, 1, 224, 60, 74), + (6911, 2, 173, 2, 0), + (6912, 1, 224, 70, 74), + (6912, 2, 173, 3, 0), + (6913, 1, 224, 80, 74), + (6913, 2, 173, 3, 0), + (6935, 1, 264, 180, 465), + (6936, 1, 264, 360, 465), + (6937, 1, 264, 540, 465), + (6938, 1, 361, 65, 16164), + (6939, 1, 361, 75, 16165), + (6940, 1, 361, 85, 16166), + (6941, 1, 264, 120, 962), + (6942, 1, 264, 240, 962), + (6943, 1, 264, 360, 962), + (6944, 1, 264, 480, 962), + (6945, 1, 264, 600, 962), + (6974, 1, 264, 3, 247), + (6974, 2, 264, 2, 986), + (6974, 3, 264, 2, 987), + (6974, 4, 264, 2, 988), + (6975, 1, 264, 6, 247), + (6975, 2, 264, 4, 986), + (6975, 3, 264, 4, 987), + (6975, 4, 264, 4, 988), + (6976, 1, 264, 12, 247), + (6976, 2, 264, 6, 986), + (6976, 3, 264, 6, 987), + (6976, 4, 264, 6, 988), + (6977, 1, 264, 6, 3817), + (6978, 1, 264, 12, 3817), + (6979, 1, 264, 18, 3817), + (6980, 1, 264, 45, 128), + (6981, 1, 264, 90, 128), + (6982, 1, 264, 135, 128), + (6987, 1, 353, 1, 0), + (6988, 1, 287, 1, 0), + (6988, 2, 385, 16439, 0), + (6988, 3, 411, 32768, 0), + (6989, 1, 287, 2, 0), + (6989, 2, 385, 16439, 0), + (6989, 3, 411, 32768, 0), + (6990, 1, 287, 3, 0), + (6990, 2, 385, 16439, 0), + (6990, 3, 411, 32768, 0), + (7005, 1, 264, 432, 789), + (7006, 1, 264, 864, 789), + (7007, 1, 264, 1296, 789), + (7008, 1, 439, 0, 109400), + (7008, 2, 345, 80, 35), + (7009, 1, 439, 0, 116800), + (7009, 2, 345, 82, 35), + (7010, 1, 378, 25, 96), + (7011, 1, 378, 30, 96), + (7012, 1, 378, 35, 96), + (7013, 1, 378, 40, 96), + (7014, 1, 378, 45, 96), + (7015, 1, 378, 50, 96), + (7033, 1, 421, 5, 0), + (7033, 2, 139, 16097, 0), + (7033, 3, 139, 23612, 0), + (7033, 4, 139, 32196, 0), + (7033, 5, 139, 32565, 0), + (7033, 6, 423, 6, 0), + (7033, 7, 422, 5, 0), + (7033, 8, 411, 2, 0), + (7034, 1, 421, 10, 0), + (7034, 2, 139, 16097, 0), + (7034, 3, 139, 23612, 0), + (7034, 4, 139, 32196, 0), + (7034, 5, 139, 32565, 0), + (7034, 6, 423, 6, 0), + (7034, 7, 422, 5, 0), + (7034, 8, 411, 2, 0), + (7035, 1, 421, 15, 0), + (7035, 2, 139, 16097, 0), + (7035, 3, 139, 23612, 0), + (7035, 4, 139, 32196, 0), + (7035, 5, 139, 32565, 0), + (7035, 6, 423, 6, 0), + (7035, 7, 422, 5, 0), + (7035, 8, 411, 2, 0), + (7036, 1, 264, 10, 3646), + (7037, 1, 264, 20, 3646), + (7038, 1, 264, 30, 3646), + (7050, 1, 265, 62, 0), + (7051, 1, 265, 64, 0), + (7052, 1, 265, 66, 0), + (7053, 1, 265, 67, 0), + (7054, 1, 265, 69, 0), + (7055, 1, 265, 71, 0), + (7056, 1, 265, 62, 0), + (7057, 1, 265, 64, 0), + (7058, 1, 265, 66, 0), + (7059, 1, 265, 67, 0), + (7060, 1, 265, 69, 0), + (7061, 1, 265, 71, 0), + (7062, 1, 372, 50, 0), + (7063, 1, 265, 72, 0), + (7064, 1, 265, 74, 0), + (7065, 1, 265, 76, 0), + (7066, 1, 265, 72, 0), + (7067, 1, 265, 74, 0), + (7068, 1, 265, 76, 0), + (7100, 1, 264, 180, 254), + (7101, 1, 264, 360, 254), + (7102, 1, 264, 540, 254), + (7103, 1, 264, 432, 286), + (7103, 2, 264, 432, 10753), + (7103, 3, 264, 432, 9101), + (7104, 1, 264, 864, 286), + (7104, 2, 264, 864, 10753), + (7104, 3, 264, 864, 9101), + (7105, 1, 264, 1296, 286), + (7105, 2, 264, 1296, 10753), + (7105, 3, 264, 1296, 9101), + (7106, 1, 224, 20, 30), + (7106, 2, 173, 1, 0), + (7107, 1, 224, 35, 30), + (7107, 2, 173, 2, 0), + (7108, 1, 224, 50, 30), + (7108, 2, 173, 3, 0), + (7112, 1, 85, 13596, 50), + (7113, 1, 85, 13597, 50), + (7114, 1, 85, 13598, 50), + (7116, 1, 264, 360, 110), + (7117, 1, 264, 450, 110), + (7118, 1, 264, 540, 110), + (7122, 1, 349, 30, 0), + (7123, 1, 349, 35, 0), + (7124, 1, 349, 40, 0), + (7125, 1, 349, 45, 0), + (7126, 1, 349, 50, 0), + (7128, 1, 264, 240, 109), + (7129, 1, 264, 300, 109), + (7130, 1, 264, 360, 109), + (7131, 1, 439, 0, 88880), + (7131, 2, 345, 74, 28), + (7132, 1, 439, 0, 95440), + (7132, 2, 345, 76, 28), + (7133, 1, 439, 0, 102280), + (7133, 2, 345, 78, 28), + (7134, 1, 220, 120, 8), + (7135, 1, 220, 140, 8), + (7136, 1, 220, 165, 8), + (7137, 1, 264, 60, 672), + (7138, 1, 264, 75, 672), + (7139, 1, 264, 90, 672), + (7146, 1, 252, 80, 0), + (7147, 1, 252, 85, 0), + (7148, 1, 216, 350, 8), + (7149, 1, 216, 400, 8), + (7150, 1, 216, 450, 8), + (7151, 1, 258, 59, 0), + (7152, 1, 258, 64, 0), + (7153, 1, 258, 69, 0), + (7160, 1, 227, 120, 32), + (7161, 1, 227, 150, 32), + (7162, 1, 227, 180, 32), + (7163, 1, 220, 130, 26), + (7163, 2, 220, 130, 30), + (7163, 3, 220, 130, 38), + (7164, 1, 220, 140, 26), + (7164, 2, 220, 140, 30), + (7164, 3, 220, 140, 38), + (7165, 1, 220, 150, 26), + (7165, 2, 220, 150, 30), + (7165, 3, 220, 150, 38), + (7166, 1, 264, 20, 468), + (7166, 2, 264, 20, 469), + (7166, 3, 264, 20, 470), + (7167, 1, 264, 25, 468), + (7167, 2, 264, 25, 469), + (7167, 3, 264, 25, 470), + (7168, 1, 264, 30, 468), + (7168, 2, 264, 30, 469), + (7168, 3, 264, 30, 470), + (7169, 1, 220, 135, 21), + (7169, 2, 220, 135, 23), + (7169, 3, 220, 270, 52), + (7169, 4, 220, 135, 28), + (7170, 1, 220, 145, 21), + (7170, 2, 220, 145, 23), + (7170, 3, 220, 290, 52), + (7170, 4, 220, 145, 28), + (7171, 1, 220, 155, 21), + (7171, 2, 220, 155, 23), + (7171, 3, 220, 310, 52), + (7171, 4, 220, 155, 28), + (7175, 1, 283, 120, 0), + (7176, 1, 283, 140, 0), + (7177, 1, 283, 160, 0), + (7196, 1, 169, 20, -1), + (7197, 1, 169, 25, -1), + (7198, 1, 169, 30, -1), + (7204, 1, 218, 11, 0), + (7205, 1, 218, 12, 0), + (7206, 1, 218, 13, 0), + (7207, 1, 218, 14, 0), + (7208, 1, 218, 15, 0), + (7210, 1, 280, 50, 0), + (7211, 1, 280, 53, 0), + (7212, 1, 280, 56, 0), + (7213, 1, 280, 59, 0), + (7214, 1, 280, 62, 0), + (7215, 1, 264, 4200, 68), + (7216, 1, 264, 4800, 68), + (7220, 1, 360, 60, 12701), + (7221, 1, 360, 60, 12702), + (7222, 1, 360, 60, 12703), + (7232, 1, 294, 0, 185), + (7233, 1, 294, 0, 190), + (7234, 1, 294, 0, 195), + (7260, 1, 287, 14, 0), + (7260, 2, 385, 2754, 1), + (7261, 1, 287, 16, 0), + (7261, 2, 385, 2754, 1), + (7262, 1, 287, 18, 0), + (7262, 2, 385, 2754, 1), + (7263, 1, 274, 18, 0), + (7264, 1, 274, 20, 0), + (7265, 1, 274, 22, 0), + (7267, 1, 280, 54, 0), + (7268, 1, 280, 55, 0), + (7269, 1, 280, 56, 0), + (7270, 1, 218, 16, 0), + (7271, 1, 218, 17, 0), + (7272, 1, 218, 18, 0), + (7273, 1, 218, 19, 0), + (7274, 1, 218, 20, 0), + (7279, 1, 310, 6000, 0), + (7279, 2, 139, 11903, 0), + (7279, 3, 310, 6000, 0), + (7279, 4, 139, 11904, 0), + (7279, 5, 310, 6000, 0), + (7279, 6, 139, 11905, 0), + (7279, 7, 310, 6000, 0), + (7279, 8, 139, 1362, 0), + (7279, 9, 310, 6000, 0), + (7279, 10, 139, 8032, 0), + (7279, 11, 310, 6000, 0), + (7279, 12, 385, 6131, 0), + (7279, 13, 385, 6231, 0), + (7279, 14, 385, 6331, 0), + (7279, 15, 385, 6431, 0), + (7279, 16, 385, 6531, 0), + (7279, 17, 385, 6631, 0), + (7280, 1, 310, 7000, 0), + (7280, 2, 139, 11903, 0), + (7280, 3, 310, 7000, 0), + (7280, 4, 139, 11904, 0), + (7280, 5, 310, 7000, 0), + (7280, 6, 139, 11905, 0), + (7280, 7, 310, 7000, 0), + (7280, 8, 139, 1362, 0), + (7280, 9, 310, 7000, 0), + (7280, 10, 139, 8032, 0), + (7280, 11, 310, 7000, 0), + (7280, 12, 385, 6131, 0), + (7280, 13, 385, 6231, 0), + (7280, 14, 385, 6331, 0), + (7280, 15, 385, 6431, 0), + (7280, 16, 385, 6531, 0), + (7280, 17, 385, 6631, 0), + (7281, 1, 310, 8000, 0), + (7281, 2, 139, 11903, 0), + (7281, 3, 310, 8000, 0), + (7281, 4, 139, 11904, 0), + (7281, 5, 310, 8000, 0), + (7281, 6, 139, 11905, 0), + (7281, 7, 310, 8000, 0), + (7281, 8, 139, 1362, 0), + (7281, 9, 310, 8000, 0), + (7281, 10, 139, 8032, 0), + (7281, 11, 310, 8000, 0), + (7281, 12, 385, 6131, 0), + (7281, 13, 385, 6231, 0), + (7281, 14, 385, 6331, 0), + (7281, 15, 385, 6431, 0), + (7281, 16, 385, 6531, 0), + (7281, 17, 385, 6631, 0), + (7282, 1, 310, 9000, 0), + (7282, 2, 139, 11903, 0), + (7282, 3, 310, 9000, 0), + (7282, 4, 139, 11904, 0), + (7282, 5, 310, 9000, 0), + (7282, 6, 139, 11905, 0), + (7282, 7, 310, 9000, 0), + (7282, 8, 139, 1362, 0), + (7282, 9, 310, 9000, 0), + (7282, 10, 139, 8032, 0), + (7282, 11, 310, 9000, 0), + (7282, 12, 385, 6131, 0), + (7282, 13, 385, 6231, 0), + (7282, 14, 385, 6331, 0), + (7282, 15, 385, 6431, 0), + (7282, 16, 385, 6531, 0), + (7282, 17, 385, 6631, 0), + (7283, 1, 310, 10000, 0), + (7283, 2, 139, 11903, 0), + (7283, 3, 310, 10000, 0), + (7283, 4, 139, 11904, 0), + (7283, 5, 310, 10000, 0), + (7283, 6, 139, 11905, 0), + (7283, 7, 310, 10000, 0), + (7283, 8, 139, 1362, 0), + (7283, 9, 310, 10000, 0), + (7283, 10, 139, 8032, 0), + (7283, 11, 310, 10000, 0), + (7283, 12, 385, 6131, 0), + (7283, 13, 385, 6231, 0), + (7283, 14, 385, 6331, 0), + (7283, 15, 385, 6431, 0), + (7283, 16, 385, 6531, 0), + (7283, 17, 385, 6631, 0), + (7284, 1, 287, 3, 0), + (7284, 2, 137, 31, 0), + (7284, 3, 136, 5, 0), + (7313, 1, 244, 40, 0), + (7314, 1, 244, 30, 0), + (7315, 1, 244, 20, 0), + (7316, 1, 264, 1080, 41), + (7317, 1, 264, 1260, 41), + (7318, 1, 339, 25, 16015), + (7318, 2, 137, 21, 0), + (7319, 1, 339, 25, 16016), + (7319, 2, 137, 21, 0), + (7320, 1, 339, 25, 16017), + (7320, 2, 137, 21, 0), + (7321, 1, 339, 25, 16018), + (7321, 2, 137, 21, 0), + (7322, 1, 339, 25, 16019), + (7322, 2, 137, 21, 0), + (7323, 1, 264, 720, 254), + (7324, 1, 264, 900, 254), + (7325, 1, 264, 1080, 254), + (7326, 1, 264, 1728, 286), + (7326, 2, 264, 1728, 10753), + (7326, 3, 264, 1728, 9101), + (7327, 1, 264, 2160, 286), + (7327, 2, 264, 2160, 10753), + (7327, 3, 264, 2160, 9101), + (7328, 1, 264, 2592, 286), + (7328, 2, 264, 2592, 10753), + (7328, 3, 264, 2592, 9101), + (7336, 1, 85, 16029, 0), + (7337, 1, 85, 16030, 0), + (7338, 1, 85, 16031, 0), + (7353, 1, 216, 115, 0), + (7353, 2, 216, 115, 1), + (7353, 3, 216, 115, 2), + (7353, 4, 216, 115, 3), + (7353, 5, 216, 115, 10), + (7353, 6, 216, 115, 28), + (7353, 7, 216, 115, 30), + (7353, 8, 216, 115, 36), + (7353, 9, 216, 115, 77), + (7354, 1, 216, 120, 0), + (7354, 2, 216, 120, 1), + (7354, 3, 216, 120, 2), + (7354, 4, 216, 120, 3), + (7354, 5, 216, 120, 10), + (7354, 6, 216, 120, 28), + (7354, 7, 216, 120, 30), + (7354, 8, 216, 120, 36), + (7354, 9, 216, 120, 77), + (7355, 1, 216, 125, 0), + (7355, 2, 216, 125, 1), + (7355, 3, 216, 125, 2), + (7355, 4, 216, 125, 3), + (7355, 5, 216, 125, 10), + (7355, 6, 216, 125, 28), + (7355, 7, 216, 125, 30), + (7355, 8, 216, 125, 36), + (7355, 9, 216, 125, 77), + (7356, 1, 360, 60, 16056), + (7357, 1, 360, 60, 16057), + (7358, 1, 360, 60, 16058), + (7359, 1, 217, 0, 82600), + (7359, 2, 346, 78, 22), + (7360, 1, 217, 0, 88880), + (7360, 2, 346, 80, 22), + (7361, 1, 217, 0, 95440), + (7361, 2, 346, 82, 22), + (7362, 1, 59, -18, 0), + (7363, 1, 59, -21, 0), + (7364, 1, 59, -24, 0), + (7365, 1, 59, -27, 0), + (7366, 1, 59, -30, 0), + (7373, 1, 2, 108, 0), + (7374, 1, 2, 112, 0), + (7375, 1, 2, 116, 0), + (7376, 1, 2, 120, 0), + (7377, 1, 2, 124, 0), + (7378, 1, 347, 14, 0), + (7379, 1, 347, 16, 0), + (7380, 1, 347, 18, 0), + (7381, 1, 347, 20, 0), + (7382, 1, 347, 22, 0), + (7383, 1, 347, 24, 0), + (7384, 1, 360, 25, 16063), + (7385, 1, 360, 25, 16064), + (7386, 1, 360, 25, 16065), + (7390, 1, 303, 6000, 6000), + (7390, 2, 139, 2766, 0), + (7391, 1, 303, 6500, 6500), + (7391, 2, 139, 2766, 0), + (7392, 1, 303, 7500, 8500), + (7392, 2, 139, 2766, 0), + (7393, 1, 85, 16066, 0), + (7394, 1, 85, 16067, 0), + (7395, 1, 85, 16068, 0), + (7396, 1, 85, 16069, 0), + (7397, 1, 85, 16070, 0), + (7398, 1, 85, 16071, 0), + (7399, 1, 302, 350, 350), + (7399, 2, 385, 99, 0), + (7400, 1, 302, 370, 370), + (7400, 2, 385, 99, 0), + (7401, 1, 302, 400, 400), + (7401, 2, 385, 99, 0), + (7402, 1, 59, -33, 0), + (7403, 1, 59, -36, 0), + (7404, 1, 59, -39, 0), + (7405, 1, 59, -42, 0), + (7406, 1, 59, -45, 0), + (7407, 1, 181, 100, -1), + (7448, 1, 264, 240, 553), + (7449, 1, 264, 300, 553), + (7450, 1, 264, 360, 553), + (7451, 1, 264, 720, 777), + (7452, 1, 264, 900, 777), + (7453, 1, 264, 1080, 777), + (7478, 1, 264, 2880, 245), + (7489, 1, 218, 16, 0), + (7490, 1, 218, 17, 0), + (7491, 1, 218, 18, 0), + (7492, 1, 218, 19, 0), + (7493, 1, 218, 20, 0), + (7494, 1, 280, 65, 0), + (7495, 1, 280, 66, 0), + (7496, 1, 280, 67, 0), + (7500, 1, 363, 3, 0), + (7501, 1, 172, 45, 0), + (7502, 1, 172, 46, 0), + (7503, 1, 172, 47, 0), + (7504, 1, 172, 48, 0), + (7505, 1, 172, 49, 0), + (7506, 1, 259, 51, 0), + (7507, 1, 259, 52, 0), + (7508, 1, 259, 53, 0), + (7509, 1, 259, 54, 0), + (7510, 1, 259, 55, 0), + (7511, 1, 328, 1050, 0), + (7512, 1, 328, 1100, 0), + (7513, 1, 328, 1150, 0), + (7514, 1, 328, 1200, 0), + (7515, 1, 328, 1250, 0), + (7516, 1, 262, 30, 7), + (7516, 2, 262, 30, 8), + (7516, 3, 262, 30, 9), + (7516, 4, 262, 30, 10), + (7516, 5, 262, 30, 11), + (7517, 1, 262, 35, 7), + (7517, 2, 262, 35, 8), + (7517, 3, 262, 35, 9), + (7517, 4, 262, 35, 10), + (7517, 5, 262, 35, 11), + (7518, 1, 262, 40, 7), + (7518, 2, 262, 40, 8), + (7518, 3, 262, 40, 9), + (7518, 4, 262, 40, 10), + (7518, 5, 262, 40, 11), + (7519, 1, 262, 45, 7), + (7519, 2, 262, 45, 8), + (7519, 3, 262, 45, 9), + (7519, 4, 262, 45, 10), + (7519, 5, 262, 45, 11), + (7520, 1, 262, 50, 7), + (7520, 2, 262, 50, 8), + (7520, 3, 262, 50, 9), + (7520, 4, 262, 50, 10), + (7520, 5, 262, 50, 11), + (7521, 1, 317, 11, 0), + (7522, 1, 317, 12, 0), + (7523, 1, 317, 13, 0), + (7524, 1, 317, 14, 0), + (7525, 1, 317, 15, 0), + (7526, 1, 69, 600, 0), + (7527, 1, 69, 700, 0), + (7528, 1, 69, 800, 0), + (7529, 1, 69, 900, 0), + (7530, 1, 69, 1000, 0), + (7534, 1, 0, 21, 0), + (7535, 1, 0, 22, 0), + (7536, 1, 0, 23, 0), + (7537, 1, 0, 24, 0), + (7538, 1, 0, 25, 0), + (7539, 1, 327, 8, 0), + (7540, 1, 327, 9, 0), + (7541, 1, 214, 1100, 0), + (7542, 1, 214, 1200, 0), + (7543, 1, 214, 1300, 0), + (7544, 1, 221, 27, 0), + (7545, 1, 221, 30, 0), + (7546, 1, 221, 33, 0), + (7547, 1, 262, 80, 0), + (7547, 2, 262, 80, 1), + (7547, 3, 262, 80, 2), + (7547, 4, 262, 80, 3), + (7547, 5, 262, 80, 4), + (7547, 6, 262, 80, 5), + (7547, 7, 262, 80, 6), + (7548, 1, 262, 85, 0), + (7548, 2, 262, 85, 1), + (7548, 3, 262, 85, 2), + (7548, 4, 262, 85, 3), + (7548, 5, 262, 85, 4), + (7548, 6, 262, 85, 5), + (7548, 7, 262, 85, 6), + (7549, 1, 262, 90, 0), + (7549, 2, 262, 90, 1), + (7549, 3, 262, 90, 2), + (7549, 4, 262, 90, 3), + (7549, 5, 262, 90, 4), + (7549, 6, 262, 90, 5), + (7549, 7, 262, 90, 6), + (7550, 1, 262, 95, 0), + (7550, 2, 262, 95, 1), + (7550, 3, 262, 95, 2), + (7550, 4, 262, 95, 3), + (7550, 5, 262, 95, 4), + (7550, 6, 262, 95, 5), + (7550, 7, 262, 95, 6), + (7551, 1, 262, 100, 0), + (7551, 2, 262, 100, 1), + (7551, 3, 262, 100, 2), + (7551, 4, 262, 100, 3), + (7551, 5, 262, 100, 4), + (7551, 6, 262, 100, 5), + (7551, 7, 262, 100, 6), + (7553, 1, 326, 3, 0), + (7554, 1, 339, 20, 16194), + (7554, 2, 138, 1, 0), + (7554, 3, 141, 1, 0), + (7554, 4, 142, 65, 0), + (7554, 5, 137, 0, 0), + (7554, 6, 311, 0, 0), + (7554, 7, 134, 85, 0), + (7554, 8, 139, -265, 0), + (7554, 9, 139, -754, 0), + (7554, 10, 139, -1332, 0), + (7554, 11, 139, -1572, 0), + (7554, 12, 139, -2749, 0), + (7554, 13, 139, -4979, 0), + (7554, 14, 139, -5418, 0), + (7554, 15, 139, -5403, 0), + (7554, 16, 348, 10, 0), + (7555, 1, 339, 21, 16195), + (7555, 2, 138, 1, 0), + (7555, 3, 141, 1, 0), + (7555, 4, 142, 65, 0), + (7555, 5, 137, 0, 0), + (7555, 6, 311, 0, 0), + (7555, 7, 134, 85, 0), + (7555, 8, 139, -265, 0), + (7555, 9, 139, -754, 0), + (7555, 10, 139, -1332, 0), + (7555, 11, 139, -1572, 0), + (7555, 12, 139, -2749, 0), + (7555, 13, 139, -4979, 0), + (7555, 14, 139, -5418, 0), + (7555, 15, 139, -5403, 0), + (7555, 16, 348, 10, 0), + (7556, 1, 339, 22, 16196), + (7556, 2, 138, 1, 0), + (7556, 3, 141, 1, 0), + (7556, 4, 142, 65, 0), + (7556, 5, 137, 0, 0), + (7556, 6, 311, 0, 0), + (7556, 7, 134, 85, 0), + (7556, 8, 139, -265, 0), + (7556, 9, 139, -754, 0), + (7556, 10, 139, -1332, 0), + (7556, 11, 139, -1572, 0), + (7556, 12, 139, -2749, 0), + (7556, 13, 139, -4979, 0), + (7556, 14, 139, -5418, 0), + (7556, 15, 139, -5403, 0), + (7556, 16, 348, 10, 0), + (7557, 1, 339, 23, 16417), + (7557, 2, 138, 1, 0), + (7557, 3, 141, 1, 0), + (7557, 4, 142, 65, 0), + (7557, 5, 137, 0, 0), + (7557, 6, 311, 0, 0), + (7557, 7, 134, 85, 0), + (7557, 8, 139, -265, 0), + (7557, 9, 139, -754, 0), + (7557, 10, 139, -1332, 0), + (7557, 11, 139, -1572, 0), + (7557, 12, 139, -2749, 0), + (7557, 13, 139, -4979, 0), + (7557, 14, 139, -5418, 0), + (7557, 15, 139, -5403, 0), + (7557, 16, 348, 10, 0), + (7558, 1, 339, 24, 16418), + (7558, 2, 138, 1, 0), + (7558, 3, 141, 1, 0), + (7558, 4, 142, 65, 0), + (7558, 5, 137, 0, 0), + (7558, 6, 311, 0, 0), + (7558, 7, 134, 85, 0), + (7558, 8, 139, -265, 0), + (7558, 9, 139, -754, 0), + (7558, 10, 139, -1332, 0), + (7558, 11, 139, -1572, 0), + (7558, 12, 139, -2749, 0), + (7558, 13, 139, -4979, 0), + (7558, 14, 139, -5418, 0), + (7558, 15, 139, -5403, 0), + (7558, 16, 348, 10, 0), + (7559, 1, 266, 23, 0), + (7560, 1, 266, 24, 0), + (7561, 1, 266, 25, 0), + (7562, 1, 330, 125, 0), + (7562, 2, 330, 125, 1), + (7562, 3, 330, 125, 2), + (7562, 4, 330, 125, 3), + (7562, 5, 330, 125, 28), + (7562, 6, 330, 125, 36), + (7562, 7, 330, 125, 77), + (7563, 1, 330, 130, 0), + (7563, 2, 330, 130, 1), + (7563, 3, 330, 130, 2), + (7563, 4, 330, 130, 3), + (7563, 5, 330, 130, 28), + (7563, 6, 330, 130, 36), + (7563, 7, 330, 130, 77), + (7564, 1, 330, 135, 0), + (7564, 2, 330, 135, 1), + (7564, 3, 330, 135, 2), + (7564, 4, 330, 135, 3), + (7564, 5, 330, 135, 28), + (7564, 6, 330, 135, 36), + (7564, 7, 330, 135, 77), + (7565, 1, 278, 800, 54510), + (7565, 2, 440, 76, 100), + (7566, 1, 278, 850, 58400), + (7566, 2, 440, 78, 100), + (7567, 1, 278, 900, 62680), + (7567, 2, 440, 80, 100), + (7568, 1, 341, 160, 0), + (7569, 1, 341, 170, 0), + (7570, 1, 341, 180, 0), + (7571, 1, 341, 190, 0), + (7572, 1, 341, 200, 0), + (7573, 1, 360, 70, 11023), + (7574, 1, 360, 80, 11023), + (7575, 1, 360, 90, 11023), + (7576, 1, 318, 16, 0), + (7577, 1, 318, 17, 0), + (7578, 1, 318, 18, 0), + (7579, 1, 318, 19, 0), + (7580, 1, 318, 20, 0), + (7581, 1, 294, 0, 160), + (7582, 1, 294, 0, 165), + (7583, 1, 294, 0, 170), + (7584, 1, 114, -60, 0), + (7585, 1, 114, -61, 0), + (7586, 1, 114, -62, 0), + (7587, 1, 319, 22, 0), + (7588, 1, 319, 23, 0), + (7589, 1, 319, 24, 0), + (7590, 1, 274, 35, 0), + (7591, 1, 274, 36, 0), + (7592, 1, 274, 37, 0), + (7593, 1, 15, 14, 0), + (7594, 1, 15, 15, 0), + (7595, 1, 15, 16, 0), + (7596, 1, 15, 17, 0), + (7597, 1, 15, 18, 0), + (7598, 1, 114, -60, 0), + (7599, 1, 114, -61, 0), + (7600, 1, 114, -62, 0), + (7601, 1, 213, 7, 0), + (7602, 1, 213, 9, 0), + (7603, 1, 213, 11, 0), + (7604, 1, 189, 14, 0), + (7605, 1, 189, 15, 0), + (7612, 1, 270, 70, 0), + (7613, 1, 270, 75, 0), + (7614, 1, 270, 80, 0), + (7615, 1, 264, 720, 494), + (7616, 1, 264, 900, 494), + (7617, 1, 264, 1080, 494), + (7618, 1, 264, 720, 500), + (7619, 1, 264, 900, 500), + (7620, 1, 264, 1080, 500), + (7621, 1, 339, 10, 8105), + (7621, 2, 142, 65, 0), + (7621, 3, 311, 0, 0), + (7621, 4, 134, 70, 0), + (7621, 5, 348, 10, 0), + (7621, 6, 137, 0, 0), + (7621, 7, 339, 10, 8105), + (7621, 8, 142, 65, 0), + (7621, 9, 311, 0, 0), + (7621, 10, 134, 70, 0), + (7621, 11, 348, 10, 0), + (7621, 12, 137, 100, 0), + (7621, 13, 339, 10, 8105), + (7621, 14, 142, 65, 0), + (7621, 15, 311, 0, 0), + (7621, 16, 134, 70, 0), + (7621, 17, 348, 10, 0), + (7621, 18, 137, 79, 0), + (7621, 19, 339, 10, 8105), + (7621, 20, 142, 65, 0), + (7621, 21, 311, 0, 0), + (7621, 22, 134, 70, 0), + (7621, 23, 348, 10, 0), + (7621, 24, 137, 147, 0), + (7621, 25, 339, 10, 11404), + (7621, 26, 142, 71, 0), + (7621, 27, 311, 0, 0), + (7621, 28, 134, 75, 0), + (7621, 29, 348, 10, 0), + (7621, 30, 137, 0, 0), + (7621, 31, 339, 10, 11404), + (7621, 32, 142, 71, 0), + (7621, 33, 311, 0, 0), + (7621, 34, 134, 75, 0), + (7621, 35, 348, 10, 0), + (7621, 36, 137, 100, 0), + (7621, 37, 339, 10, 11404), + (7621, 38, 142, 71, 0), + (7621, 39, 311, 0, 0), + (7621, 40, 134, 75, 0), + (7621, 41, 348, 10, 0), + (7621, 42, 137, 79, 0), + (7621, 43, 339, 10, 11404), + (7621, 44, 142, 71, 0), + (7621, 45, 311, 0, 0), + (7621, 46, 134, 75, 0), + (7621, 47, 348, 10, 0), + (7621, 48, 137, 147, 0), + (7621, 49, 339, 10, 13199), + (7621, 50, 142, 76, 0), + (7621, 51, 311, 0, 0), + (7621, 52, 134, 80, 0), + (7621, 53, 348, 10, 0), + (7621, 54, 137, 0, 0), + (7621, 55, 339, 10, 13199), + (7621, 56, 142, 76, 0), + (7621, 57, 311, 0, 0), + (7621, 58, 134, 80, 0), + (7621, 59, 348, 10, 0), + (7621, 60, 137, 100, 0), + (7621, 61, 339, 10, 13199), + (7621, 62, 142, 76, 0), + (7621, 63, 311, 0, 0), + (7621, 64, 134, 80, 0), + (7621, 65, 348, 10, 0), + (7621, 66, 137, 79, 0), + (7621, 67, 339, 10, 13199), + (7621, 68, 142, 76, 0), + (7621, 69, 311, 0, 0), + (7621, 70, 134, 80, 0), + (7621, 71, 348, 10, 0), + (7621, 72, 137, 147, 0), + (7621, 73, 339, 10, 13830), + (7621, 74, 142, 81, 0), + (7621, 75, 311, 0, 0), + (7621, 76, 134, 85, 0), + (7621, 77, 348, 10, 0), + (7621, 78, 137, 0, 0), + (7621, 79, 339, 10, 13830), + (7621, 80, 142, 81, 0), + (7621, 81, 311, 0, 0), + (7621, 82, 134, 85, 0), + (7621, 83, 348, 10, 0), + (7621, 84, 137, 100, 0), + (7621, 85, 339, 10, 13830), + (7621, 86, 142, 81, 0), + (7621, 87, 311, 0, 0), + (7621, 88, 134, 85, 0), + (7621, 89, 348, 10, 0), + (7621, 90, 137, 79, 0), + (7621, 91, 339, 10, 13830), + (7621, 92, 142, 81, 0), + (7621, 93, 311, 0, 0), + (7621, 94, 134, 85, 0), + (7621, 95, 348, 10, 0), + (7621, 96, 137, 147, 0), + (7622, 1, 265, 79, 0), + (7623, 1, 265, 80, 0), + (7624, 1, 265, 81, 0), + (7625, 1, 265, 79, 0), + (7626, 1, 265, 80, 0), + (7627, 1, 265, 81, 0), + (7628, 1, 292, 46, 0), + (7629, 1, 292, 47, 0), + (7630, 1, 292, 48, 0), + (7631, 1, 279, 34, 0), + (7632, 1, 279, 35, 0), + (7633, 1, 279, 36, 0), + (7634, 1, 279, 34, 0), + (7635, 1, 279, 35, 0), + (7636, 1, 279, 36, 0), + (7637, 1, 279, 34, 0), + (7638, 1, 279, 35, 0), + (7639, 1, 279, 36, 0), + (7640, 1, 200, 60, 0), + (7641, 1, 294, 17, 100), + (7642, 1, 294, 19, 100), + (7643, 1, 294, 21, 100), + (7644, 1, 375, 130, 0), + (7645, 1, 375, 135, 0), + (7646, 1, 375, 140, 0), + (7647, 1, 229, 20, 0), + (7648, 1, 229, 25, 0), + (7649, 1, 229, 30, 0), + (7650, 1, 330, 125, 0), + (7650, 2, 330, 125, 1), + (7650, 3, 330, 125, 2), + (7650, 4, 330, 125, 3), + (7650, 5, 330, 125, 28), + (7650, 6, 330, 125, 36), + (7651, 1, 330, 130, 0), + (7651, 2, 330, 130, 1), + (7651, 3, 330, 130, 2), + (7651, 4, 330, 130, 3), + (7651, 5, 330, 130, 28), + (7651, 6, 330, 130, 36), + (7652, 1, 330, 135, 0), + (7652, 2, 330, 135, 1), + (7652, 3, 330, 135, 2), + (7652, 4, 330, 135, 3), + (7652, 5, 330, 135, 28), + (7652, 6, 330, 135, 36), + (7653, 1, 330, 125, 0), + (7653, 2, 330, 125, 1), + (7653, 3, 330, 125, 2), + (7653, 4, 330, 125, 3), + (7653, 5, 330, 125, 28), + (7653, 6, 330, 125, 36), + (7653, 7, 330, 125, 77), + (7654, 1, 330, 130, 0), + (7654, 2, 330, 130, 1), + (7654, 3, 330, 130, 2), + (7654, 4, 330, 130, 3), + (7654, 5, 330, 130, 28), + (7654, 6, 330, 130, 36), + (7654, 7, 330, 130, 77), + (7655, 1, 330, 135, 0), + (7655, 2, 330, 135, 1), + (7655, 3, 330, 135, 2), + (7655, 4, 330, 135, 3), + (7655, 5, 330, 135, 28), + (7655, 6, 330, 135, 36), + (7655, 7, 330, 135, 77), + (7656, 1, 330, 100, 0), + (7656, 2, 330, 100, 1), + (7656, 3, 330, 100, 2), + (7656, 4, 330, 100, 3), + (7656, 5, 330, 100, 28), + (7656, 6, 330, 100, 36), + (7656, 7, 330, 100, 77), + (7657, 1, 330, 105, 0), + (7657, 2, 330, 105, 1), + (7657, 3, 330, 105, 2), + (7657, 4, 330, 105, 3), + (7657, 5, 330, 105, 28), + (7657, 6, 330, 105, 36), + (7657, 7, 330, 105, 77), + (7658, 1, 330, 110, 0), + (7658, 2, 330, 110, 1), + (7658, 3, 330, 110, 2), + (7658, 4, 330, 110, 3), + (7658, 5, 330, 110, 28), + (7658, 6, 330, 110, 36), + (7658, 7, 330, 110, 77), + (7659, 1, 264, 72, 153), + (7660, 1, 264, 90, 153), + (7661, 1, 264, 108, 153), + (7663, 1, 375, 150, 0), + (7664, 1, 264, 10, 170), + (7665, 1, 264, 20, 170), + (7666, 1, 264, 30, 170), + (7667, 1, 264, 40, 170), + (7668, 1, 264, 50, 170), + (7670, 1, 229, 35, 0), + (7671, 1, 229, 40, 0), + (7672, 1, 229, 45, 0), + (7673, 1, 220, 50, 10), + (7674, 1, 220, 65, 10), + (7675, 1, 220, 80, 10), + (7676, 1, 220, 95, 10), + (7677, 1, 220, 110, 10), + (7678, 1, 231, 11, 0), + (7679, 1, 231, 13, 0), + (7680, 1, 231, 15, 0), + (7681, 1, 326, 4, 0), + (7682, 1, 264, 5400, 68), + (7683, 1, 327, 10, 0), + (7684, 1, 327, 11, 0), + (7685, 1, 327, 12, 0), + (7686, 1, 349, 55, 0), + (7687, 1, 349, 60, 0), + (7688, 1, 349, 65, 0), + (7690, 1, 353, 1, 0), + (7692, 1, 319, 25, 0), + (7693, 1, 319, 26, 0), + (7694, 1, 319, 27, 0), + (7695, 1, 127, 5, 0), + (7695, 2, 385, 14232, 0), + (7696, 1, 127, 10, 0), + (7696, 2, 385, 14232, 0), + (7697, 1, 127, 15, 0), + (7697, 2, 385, 14232, 0), + (7699, 1, 181, 100, 0), + (7700, 1, 279, 7, 0), + (7701, 1, 279, 11, 0), + (7702, 1, 279, 15, 0), + (7704, 1, 264, 540, 3707), + (7705, 1, 264, 720, 3707), + (7706, 1, 264, 900, 3707), + (7707, 1, 303, 8500, 9500), + (7707, 2, 139, 2766, 0), + (7708, 1, 303, 9500, 11000), + (7708, 2, 139, 2766, 0), + (7709, 1, 303, 11000, 14000), + (7709, 2, 139, 2766, 0), + (7713, 1, 274, 34, 0), + (7714, 1, 274, 36, 0), + (7715, 1, 264, 2, 901), + (7716, 1, 264, 4, 901), + (7717, 1, 264, 6, 901), + (7718, 1, 281, 90, 0), + (7722, 1, 339, 25, 23492), + (7722, 2, 138, 1, 0), + (7722, 3, 141, 1, 0), + (7722, 4, 142, 70, 0), + (7722, 5, 137, 0, 0), + (7722, 6, 311, 0, 0), + (7722, 7, 134, 90, 0), + (7722, 8, 139, -265, 0), + (7722, 9, 139, -754, 0), + (7722, 10, 139, -1332, 0), + (7722, 11, 139, -1572, 0), + (7722, 12, 139, -2749, 0), + (7722, 13, 139, -4979, 0), + (7722, 14, 139, -5418, 0), + (7722, 15, 139, -5403, 0), + (7722, 16, 348, 10, 0), + (7723, 1, 339, 26, 23493), + (7723, 2, 138, 1, 0), + (7723, 3, 141, 1, 0), + (7723, 4, 142, 70, 0), + (7723, 5, 137, 0, 0), + (7723, 6, 311, 0, 0), + (7723, 7, 134, 90, 0), + (7723, 8, 139, -265, 0), + (7723, 9, 139, -754, 0), + (7723, 10, 139, -1332, 0), + (7723, 11, 139, -1572, 0), + (7723, 12, 139, -2749, 0), + (7723, 13, 139, -4979, 0), + (7723, 14, 139, -5418, 0), + (7723, 15, 139, -5403, 0), + (7723, 16, 348, 10, 0), + (7724, 1, 339, 27, 23494), + (7724, 2, 138, 1, 0), + (7724, 3, 141, 1, 0), + (7724, 4, 142, 70, 0), + (7724, 5, 137, 0, 0), + (7724, 6, 311, 0, 0), + (7724, 7, 134, 90, 0), + (7724, 8, 139, -265, 0), + (7724, 9, 139, -754, 0), + (7724, 10, 139, -1332, 0), + (7724, 11, 139, -1572, 0), + (7724, 12, 139, -2749, 0), + (7724, 13, 139, -4979, 0), + (7724, 14, 139, -5418, 0), + (7724, 15, 139, -5403, 0), + (7724, 16, 348, 10, 0), + (7725, 1, 339, 28, 23495), + (7725, 2, 138, 1, 0), + (7725, 3, 141, 1, 0), + (7725, 4, 142, 70, 0), + (7725, 5, 137, 0, 0), + (7725, 6, 311, 0, 0), + (7725, 7, 134, 90, 0), + (7725, 8, 139, -265, 0), + (7725, 9, 139, -754, 0), + (7725, 10, 139, -1332, 0), + (7725, 11, 139, -1572, 0), + (7725, 12, 139, -2749, 0), + (7725, 13, 139, -4979, 0), + (7725, 14, 139, -5418, 0), + (7725, 15, 139, -5403, 0), + (7725, 16, 348, 10, 0), + (7726, 1, 339, 29, 23496), + (7726, 2, 138, 1, 0), + (7726, 3, 141, 1, 0), + (7726, 4, 142, 70, 0), + (7726, 5, 137, 0, 0), + (7726, 6, 311, 0, 0), + (7726, 7, 134, 90, 0), + (7726, 8, 139, -265, 0), + (7726, 9, 139, -754, 0), + (7726, 10, 139, -1332, 0), + (7726, 11, 139, -1572, 0), + (7726, 12, 139, -2749, 0), + (7726, 13, 139, -4979, 0), + (7726, 14, 139, -5418, 0), + (7726, 15, 139, -5403, 0), + (7726, 16, 348, 10, 0), + (7733, 1, 257, 1, 0), + (7733, 2, 267, 1, 31), + (7733, 3, 267, 1, 32), + (7733, 4, 267, 1, 33), + (7733, 5, 267, 1, 15), + (7733, 6, 267, 1, 16), + (7733, 7, 267, 1, 17), + (7733, 8, 267, 1, 18), + (7733, 9, 267, 1, 19), + (7733, 10, 267, 1, 20), + (7743, 1, 264, 90, 184), + (7744, 1, 264, 180, 184), + (7745, 1, 264, 270, 184), + (7746, 1, 310, 2000, 0), + (7746, 2, 385, 11233, 0), + (7746, 3, 385, 11333, 0), + (7746, 4, 411, 16, 0), + (7748, 1, 271, 5, 0), + (7749, 1, 271, 10, 0), + (7750, 1, 271, 15, 0), + (7751, 1, 264, 60, 2234), + (7752, 1, 264, 120, 2234), + (7753, 1, 264, 180, 2234), + (7757, 1, 264, 120, 9403), + (7758, 1, 264, 240, 9403), + (7759, 1, 264, 360, 9403), + (7760, 1, 264, 2, 824), + (7761, 1, 264, 4, 824), + (7762, 1, 264, 6, 824), + (7763, 1, 310, 4000, 0), + (7763, 2, 385, 11233, 0), + (7763, 3, 385, 11333, 0), + (7763, 4, 411, 16, 0), + (7764, 1, 310, 6000, 0), + (7764, 2, 385, 11233, 0), + (7764, 3, 385, 11333, 0), + (7764, 4, 411, 16, 0), + (7765, 1, 392, 1000, 0), + (7765, 2, 139, 21820, 0), + (7765, 3, 411, 4, 0), + (7766, 1, 392, 2000, 0), + (7766, 2, 139, 21820, 0), + (7766, 3, 411, 4, 0), + (7767, 1, 392, 3000, 0), + (7767, 2, 139, 21820, 0), + (7767, 3, 411, 4, 0), + (7768, 1, 392, 4000, 0), + (7768, 2, 139, 21820, 0), + (7768, 3, 411, 4, 0), + (7818, 1, 288, 200, 51), + (7818, 2, 288, 50, 51), + (7819, 1, 405, 7, 0), + (7820, 1, 405, 9, 0), + (7821, 1, 405, 11, 0), + (7822, 1, 264, 1, 1154), + (7823, 1, 264, 2, 1154), + (7824, 1, 264, 3, 1154), + (7825, 1, 264, 4, 1154), + (7826, 1, 264, 5, 1154), + (7827, 1, 398, 9000, 0), + (7827, 2, 385, 7225, 0), + (7827, 3, 385, 7325, 0), + (7827, 4, 385, 7425, 0), + (7828, 1, 310, 2000, 0), + (7828, 2, 385, 7225, 0), + (7828, 3, 385, 7325, 0), + (7828, 4, 385, 7425, 0), + (7828, 5, 385, 7525, 0), + (7828, 6, 385, 7625, 0), + (7829, 1, 310, 4000, 0), + (7829, 2, 385, 7225, 0), + (7829, 3, 385, 7325, 0), + (7829, 4, 385, 7425, 0), + (7829, 5, 385, 7525, 0), + (7829, 6, 385, 7625, 0), + (7830, 1, 310, 6000, 0), + (7830, 2, 385, 7225, 0), + (7830, 3, 385, 7325, 0), + (7830, 4, 385, 7425, 0), + (7830, 5, 385, 7525, 0), + (7830, 6, 385, 7625, 0), + (7832, 1, 264, 60, 60), + (7833, 2, 264, 120, 60), + (7834, 3, 264, 180, 60), + (7835, 4, 264, 240, 60), + (7836, 5, 264, 300, 60), + (7837, 1, 262, 55, 7), + (7837, 2, 262, 55, 8), + (7837, 3, 262, 55, 9), + (7837, 4, 262, 55, 10), + (7837, 5, 262, 55, 11), + (7838, 1, 262, 60, 7), + (7838, 2, 262, 60, 8), + (7838, 3, 262, 60, 9), + (7838, 4, 262, 60, 10), + (7838, 5, 262, 60, 11), + (7839, 1, 262, 65, 7), + (7839, 2, 262, 65, 8), + (7839, 3, 262, 65, 9), + (7839, 4, 262, 65, 10), + (7839, 5, 262, 65, 11), + (7840, 1, 262, 70, 7), + (7840, 2, 262, 70, 8), + (7840, 3, 262, 70, 9), + (7840, 4, 262, 70, 10), + (7840, 5, 262, 70, 11), + (7841, 1, 262, 75, 7), + (7841, 2, 262, 75, 8), + (7841, 3, 262, 75, 9), + (7841, 4, 262, 75, 10), + (7841, 5, 262, 75, 11), + (7842, 1, 339, 30, 27695), + (7842, 2, 138, 1, 0), + (7842, 3, 141, 1, 0), + (7842, 4, 142, 70, 0), + (7842, 5, 137, 0, 0), + (7842, 6, 311, 0, 0), + (7842, 7, 134, 100, 0), + (7842, 8, 139, -265, 0), + (7842, 9, 139, -754, 0), + (7842, 10, 139, -1332, 0), + (7842, 11, 139, -1572, 0), + (7842, 12, 139, -2749, 0), + (7842, 13, 139, -4979, 0), + (7842, 14, 139, -5418, 0), + (7842, 15, 139, -5403, 0), + (7842, 16, 348, 10, 0), + (7843, 1, 339, 31, 27696), + (7843, 2, 138, 1, 0), + (7843, 3, 141, 1, 0), + (7843, 4, 142, 70, 0), + (7843, 5, 137, 0, 0), + (7843, 6, 311, 0, 0), + (7843, 7, 134, 100, 0), + (7843, 8, 139, -265, 0), + (7843, 9, 139, -754, 0), + (7843, 10, 139, -1332, 0), + (7843, 11, 139, -1572, 0), + (7843, 12, 139, -2749, 0), + (7843, 13, 139, -4979, 0), + (7843, 14, 139, -5418, 0), + (7843, 15, 139, -5403, 0), + (7843, 16, 348, 10, 0), + (7844, 1, 339, 32, 27697), + (7844, 2, 138, 1, 0), + (7844, 3, 141, 1, 0), + (7844, 4, 142, 70, 0), + (7844, 5, 137, 0, 0), + (7844, 6, 311, 0, 0), + (7844, 7, 134, 100, 0), + (7844, 8, 139, -265, 0), + (7844, 9, 139, -754, 0), + (7844, 10, 139, -1332, 0), + (7844, 11, 139, -1572, 0), + (7844, 12, 139, -2749, 0), + (7844, 13, 139, -4979, 0), + (7844, 14, 139, -5418, 0), + (7844, 15, 139, -5403, 0), + (7844, 16, 348, 10, 0), + (7881, 1, 405, 13, 0), + (7882, 1, 405, 15, 0), + (7883, 1, 405, 17, 0), + (7884, 1, 287, 1, 0), + (7884, 2, 139, 4691, 0), + (7884, 3, 411, 128, 0), + (7885, 1, 287, 1, 0), + (7885, 2, 385, 8111, 0), + (7885, 3, 385, 15008, 0), + (7885, 4, 385, 8411, 0), + (7885, 5, 385, 8511, 0), + (7885, 6, 411, 128, 0), + (7886, 1, 328, 1300, 0), + (7887, 1, 328, 1350, 0), + (7888, 1, 328, 1400, 0), + (7889, 1, 328, 1450, 0), + (7890, 1, 328, 1500, 0), + (7900, 1, 339, 45, 16189), + (7900, 2, 136, 11, 0), + (7900, 3, 383, 45, 16189), + (7900, 4, 385, 11012, 0), + (7900, 5, 383, 45, 16189), + (7900, 6, 385, 5130, 0), + (7900, 7, 383, 45, 16189), + (7900, 8, 385, 5230, 0), + (7900, 9, 383, 45, 16189), + (7900, 10, 136, 22, 0), + (7900, 11, 383, 45, 16189), + (7900, 12, 385, 5330, 0), + (7900, 13, 385, 5430, 0), + (7900, 14, 385, 5530, 0), + (7901, 1, 339, 45, 16190), + (7901, 2, 136, 11, 0), + (7901, 3, 383, 45, 16190), + (7901, 4, 385, 11012, 0), + (7901, 5, 383, 45, 16190), + (7901, 6, 385, 5130, 0), + (7901, 7, 383, 45, 16190), + (7901, 8, 385, 5230, 0), + (7901, 9, 383, 45, 16190), + (7901, 10, 136, 22, 0), + (7901, 11, 383, 45, 16190), + (7901, 12, 385, 5330, 0), + (7901, 13, 385, 5430, 0), + (7901, 14, 385, 5530, 0), + (7902, 1, 339, 45, 16191), + (7902, 2, 136, 11, 0), + (7902, 3, 383, 45, 16191), + (7902, 4, 385, 11012, 0), + (7902, 5, 383, 45, 16191), + (7902, 6, 385, 5130, 0), + (7902, 7, 383, 45, 16191), + (7902, 8, 385, 5230, 0), + (7902, 9, 383, 45, 16191), + (7902, 10, 136, 22, 0), + (7902, 11, 383, 45, 16191), + (7902, 12, 385, 5330, 0), + (7902, 13, 385, 5430, 0), + (7902, 14, 385, 5530, 0), + (7904, 1, 0, 26, 0), + (7905, 1, 0, 27, 0), + (7906, 1, 0, 28, 0), + (7907, 1, 0, 29, 0), + (7908, 1, 0, 30, 0), + (7940, 1, 264, 15, 558), + (7941, 1, 264, 30, 558), + (7942, 1, 264, 45, 558), + (7945, 1, 310, 2000, 0), + (7945, 2, 139, 8007, 0), + (7945, 3, 310, 2000, 0), + (7945, 4, 385, 4140, 0), + (7945, 5, 385, 4240, 0), + (7945, 6, 385, 4340, 0), + (7945, 7, 385, 4440, 0), + (7945, 8, 385, 4540, 0), + (7945, 9, 385, 4640, 0), + (7946, 1, 310, 4000, 0), + (7946, 2, 139, 8007, 0), + (7946, 3, 310, 4000, 0), + (7946, 4, 385, 4140, 0), + (7946, 5, 385, 4240, 0), + (7946, 6, 385, 4340, 0), + (7946, 7, 385, 4440, 0), + (7946, 8, 385, 4540, 0), + (7946, 9, 385, 4640, 0), + (7947, 1, 310, 6000, 0), + (7947, 2, 139, 8007, 0), + (7947, 3, 310, 6000, 0), + (7947, 4, 385, 4140, 0), + (7947, 5, 385, 4240, 0), + (7947, 6, 385, 4340, 0), + (7947, 7, 385, 4440, 0), + (7947, 8, 385, 4540, 0), + (7947, 9, 385, 4640, 0), + (7948, 1, 339, 25, 16197), + (7948, 2, 138, 1, 0), + (7948, 3, 142, 60, 0), + (7948, 4, 137, 35, 0), + (7948, 5, 134, 75, 0), + (7948, 6, 339, 25, 16197), + (7948, 7, 138, 1, 0), + (7948, 8, 142, 60, 0), + (7948, 9, 137, 36, 0), + (7948, 10, 134, 75, 0), + (7948, 11, 339, 25, 16197), + (7948, 12, 138, 1, 0), + (7948, 13, 142, 60, 0), + (7948, 14, 137, 369, 0), + (7948, 15, 134, 75, 0), + (7948, 16, 339, 25, 16197), + (7948, 17, 138, 1, 0), + (7948, 18, 142, 60, 0), + (7948, 19, 137, 116, 0), + (7948, 20, 134, 75, 0), + (7949, 1, 339, 25, 16198), + (7949, 2, 138, 1, 0), + (7949, 3, 142, 60, 0), + (7949, 4, 137, 35, 0), + (7949, 5, 134, 80, 0), + (7949, 6, 339, 25, 16198), + (7949, 7, 138, 1, 0), + (7949, 8, 142, 60, 0), + (7949, 9, 137, 36, 0), + (7949, 10, 134, 80, 0), + (7949, 11, 339, 25, 16198), + (7949, 12, 138, 1, 0), + (7949, 13, 142, 60, 0), + (7949, 14, 137, 369, 0), + (7949, 15, 134, 80, 0), + (7949, 16, 339, 25, 16198), + (7949, 17, 138, 1, 0), + (7949, 18, 142, 60, 0), + (7949, 19, 137, 116, 0), + (7949, 20, 134, 80, 0), + (7950, 1, 339, 25, 16199), + (7950, 2, 138, 1, 0), + (7950, 3, 142, 60, 0), + (7950, 4, 137, 35, 0), + (7950, 5, 134, 85, 0), + (7950, 6, 339, 25, 16199), + (7950, 7, 138, 1, 0), + (7950, 8, 142, 60, 0), + (7950, 9, 137, 36, 0), + (7950, 10, 134, 85, 0), + (7950, 11, 339, 25, 16199), + (7950, 12, 138, 1, 0), + (7950, 13, 142, 60, 0), + (7950, 14, 137, 369, 0), + (7950, 15, 134, 85, 0), + (7950, 16, 339, 25, 16199), + (7950, 17, 138, 1, 0), + (7950, 18, 142, 60, 0), + (7950, 19, 137, 116, 0), + (7950, 20, 134, 85, 0), + (7980, 1, 243, 15, 0), + (7981, 1, 243, 25, 0), + (7982, 1, 243, 35, 0), + (7983, 1, 264, 120, 520), + (7984, 1, 264, 240, 520), + (7985, 1, 264, 360, 520), + (7989, 1, 264, 30, 705), + (7989, 2, 264, 30, 1092), + (7989, 3, 264, 30, 10396), + (7989, 4, 264, 30, 10397), + (7990, 1, 264, 60, 705), + (7990, 2, 264, 60, 1092), + (7990, 3, 264, 60, 10396), + (7990, 4, 264, 60, 10397), + (7991, 1, 264, 90, 705), + (7991, 2, 264, 90, 1092), + (7991, 3, 264, 90, 10396), + (7991, 4, 264, 90, 10397), + (7992, 1, 264, 120, 705), + (7992, 2, 264, 120, 1092), + (7992, 3, 264, 120, 10396), + (7992, 4, 264, 120, 10397), + (7994, 1, 264, 240, 39), + (7994, 2, 264, 3456, 1061), + (7995, 1, 264, 300, 39), + (7995, 2, 264, 4320, 1061), + (8000, 1, 69, 200, 0), + (8000, 2, 2, 75, 0), + (8000, 3, 97, 200, 0), + (8000, 4, 317, 8, 0), + (8031, 1, 264, 30, 791), + (8032, 1, 264, 60, 791), + (8033, 1, 264, 90, 791), + (8035, 1, 264, 180, 521), + (8036, 1, 264, 360, 521), + (8037, 1, 264, 540, 521), + (8040, 1, 128, 5, 5), + (8040, 2, 138, 1, 0), + (8040, 3, 140, 1, 0), + (8040, 4, 311, 0, 0), + (8040, 5, 411, 256, 0), + (8040, 6, 137, -40, 0), + (8040, 7, 391, 1, 0), + (8041, 1, 128, 15, 15), + (8041, 2, 138, 1, 0), + (8041, 3, 140, 1, 0), + (8041, 4, 311, 0, 0), + (8041, 5, 411, 256, 0), + (8041, 6, 137, -40, 0), + (8041, 7, 391, 1, 0), + (8042, 1, 128, 30, 30), + (8042, 2, 138, 1, 0), + (8042, 3, 140, 1, 0), + (8042, 4, 311, 0, 0), + (8042, 5, 411, 256, 0), + (8042, 6, 137, -40, 0), + (8042, 7, 391, 1, 0), + (8043, 1, 128, 50, 50), + (8043, 2, 138, 1, 0), + (8043, 3, 140, 1, 0), + (8043, 4, 311, 0, 0), + (8043, 5, 411, 256, 0), + (8043, 6, 137, -40, 0), + (8043, 7, 391, 1, 0), + (8059, 1, 128, 50, 50), + (8059, 2, 138, 1, 0), + (8059, 3, 140, 1, 0), + (8059, 4, 311, 0, 0), + (8059, 5, 411, 66434, 0), + (8059, 6, 137, -40, 0), + (8069, 1, 244, -10, 0), + (8070, 1, 244, -15, 0), + (8071, 1, 244, -20, 0), + (8076, 1, 264, 360, 565), + (8076, 2, 264, 360, 793), + (8076, 3, 264, 360, 794), + (8077, 1, 264, 720, 565), + (8077, 2, 264, 720, 793), + (8077, 3, 264, 720, 794), + (8078, 1, 264, 1080, 565), + (8078, 2, 264, 1080, 793), + (8078, 3, 264, 1080, 794), + (8079, 1, 264, 1440, 565), + (8079, 2, 264, 1440, 793), + (8079, 3, 264, 1440, 794), + (8080, 1, 264, 1800, 565), + (8080, 2, 264, 1800, 793), + (8080, 3, 264, 1800, 794), + (8081, 1, 264, 2160, 565), + (8081, 2, 264, 2160, 793), + (8081, 3, 264, 2160, 794), + (8082, 1, 264, 60, 208), + (8083, 1, 264, 120, 208), + (8084, 1, 264, 180, 208), + (8190, 1, 280, 2, 0), + (8191, 1, 280, 4, 0), + (8192, 1, 280, 6, 0), + (8193, 1, 339, 100, 16225), + (8193, 2, 139, 6838, 0), + (8195, 1, 264, 120, 3707), + (8196, 1, 264, 240, 3707), + (8197, 1, 264, 360, 3707), + (8198, 1, 294, 0, 110), + (8199, 1, 294, 0, 120), + (8200, 1, 294, 0, 130), + (8201, 1, 218, 1, 0), + (8202, 1, 218, 2, 0), + (8203, 1, 218, 3, 0), + (8204, 1, 127, 10, 0), + (8204, 2, 137, 154, 0), + (8204, 3, 403, 2, 0), + (8204, 4, 404, 10, 0), + (8205, 1, 127, 20, 0), + (8205, 2, 137, 154, 0), + (8205, 3, 403, 2, 0), + (8205, 4, 404, 10, 0), + (8206, 1, 127, 30, 0), + (8206, 2, 137, 154, 0), + (8206, 3, 403, 2, 0), + (8206, 4, 404, 10, 0), + (8207, 1, 127, 10, 0), + (8207, 2, 137, 154, 0), + (8207, 3, 403, 2, 0), + (8207, 4, 404, 10, 0), + (8208, 1, 127, 20, 0), + (8208, 2, 137, 154, 0), + (8208, 3, 403, 2, 0), + (8208, 4, 404, 10, 0), + (8209, 1, 127, 30, 0), + (8209, 2, 137, 154, 0), + (8209, 3, 403, 2, 0), + (8209, 4, 404, 10, 0), + (8210, 1, 97, 50, 0), + (8211, 1, 97, 100, 0), + (8212, 1, 97, 150, 0), + (8213, 1, 97, 200, 0), + (8214, 1, 97, 250, 0), + (8215, 1, 190, 50, 0), + (8216, 1, 190, 100, 0), + (8217, 1, 190, 150, 0), + (8218, 1, 190, 200, 0), + (8219, 1, 190, 250, 0), + (8223, 1, 128, 50, 50), + (8223, 2, 138, 1, 0), + (8223, 3, 140, 1, 0), + (8223, 4, 139, -2741, 0), + (8223, 5, 139, -16843, 0), + (8223, 6, 385, -16192, 0), + (8224, 1, 339, 10, 16230), + (8224, 2, 138, 1, 0), + (8224, 3, 141, 1, 0), + (8224, 4, 142, 60, 0), + (8224, 5, 137, 0, 0), + (8224, 6, 311, 0, 0), + (8224, 7, 134, 80, 0), + (8224, 8, 139, -265, 0), + (8224, 9, 139, -754, 0), + (8224, 10, 139, -1332, 0), + (8224, 11, 139, -1572, 0), + (8224, 12, 139, -2749, 0), + (8224, 13, 139, -4979, 0), + (8224, 14, 139, -5418, 0), + (8224, 15, 139, -5403, 0), + (8225, 1, 339, 10, 16231), + (8225, 2, 138, 1, 0), + (8225, 3, 141, 1, 0), + (8225, 4, 142, 65, 0), + (8225, 5, 137, 0, 0), + (8225, 6, 311, 0, 0), + (8225, 7, 134, 85, 0), + (8225, 8, 139, -265, 0), + (8225, 9, 139, -754, 0), + (8225, 10, 139, -1332, 0), + (8225, 11, 139, -1572, 0), + (8225, 12, 139, -2749, 0), + (8225, 13, 139, -4979, 0), + (8225, 14, 139, -5418, 0), + (8225, 15, 139, -5403, 0), + (8226, 1, 339, 10, 16232), + (8226, 2, 138, 1, 0), + (8226, 3, 141, 1, 0), + (8226, 4, 142, 70, 0), + (8226, 5, 137, 0, 0), + (8226, 6, 311, 0, 0), + (8226, 7, 134, 90, 0), + (8226, 8, 139, -265, 0), + (8226, 9, 139, -754, 0), + (8226, 10, 139, -1332, 0), + (8226, 11, 139, -1572, 0), + (8226, 12, 139, -2749, 0), + (8226, 13, 139, -4979, 0), + (8226, 14, 139, -5418, 0), + (8226, 15, 139, -5403, 0), + (8228, 1, 378, 5, 22), + (8229, 1, 378, 10, 22), + (8230, 1, 378, 15, 22), + (8232, 1, 128, 5, 5), + (8232, 2, 138, 1, 0), + (8232, 3, 140, 1, 0), + (8232, 4, 311, 0, 0), + (8232, 5, 411, 66434, 0), + (8232, 6, 137, -40, 0), + (8233, 1, 128, 15, 15), + (8233, 2, 138, 1, 0), + (8233, 3, 140, 1, 0), + (8233, 4, 311, 0, 0), + (8233, 5, 411, 66434, 0), + (8233, 6, 137, -40, 0), + (8234, 1, 128, 30, 30), + (8234, 2, 138, 1, 0), + (8234, 3, 140, 1, 0), + (8234, 4, 311, 0, 0), + (8234, 5, 411, 66434, 0), + (8234, 6, 137, -40, 0), + (8235, 1, 1, 29, 0), + (8236, 1, 1, 58, 0), + (8237, 1, 1, 87, 0), + (8238, 1, 1, 116, 0), + (8239, 1, 1, 145, 0), + (8240, 1, 1, 31, 0), + (8241, 1, 1, 62, 0), + (8242, 1, 1, 93, 0), + (8243, 1, 1, 124, 0), + (8244, 1, 1, 155, 0), + (8245, 1, 1, 33, 0), + (8246, 1, 1, 66, 0), + (8247, 1, 1, 99, 0), + (8248, 1, 1, 132, 0), + (8249, 1, 1, 165, 0), + (8250, 1, 1, 40, 0), + (8251, 1, 1, 80, 0), + (8252, 1, 1, 120, 0), + (8253, 1, 1, 160, 0), + (8254, 1, 1, 200, 0), + (8255, 1, 1, 50, 0), + (8256, 1, 1, 100, 0), + (8257, 1, 1, 150, 0), + (8258, 1, 1, 200, 0), + (8259, 1, 1, 250, 0), + (8261, 1, 128, 65, 65), + (8261, 2, 138, 1, 0), + (8261, 3, 140, 1, 0), + (8261, 4, 311, 0, 0), + (8261, 5, 411, 66434, 0), + (8261, 6, 137, -40, 0), + (8262, 1, 128, 70, 70), + (8262, 2, 138, 1, 0), + (8262, 3, 140, 1, 0), + (8262, 4, 139, -2741, 0), + (8262, 5, 139, -16843, 0), + (8262, 6, 385, -16192, 0), + (8263, 1, 262, 5, 0), + (8264, 1, 262, 10, 0), + (8265, 1, 262, 15, 0), + (8266, 1, 262, 20, 0), + (8267, 1, 262, 25, 0), + (8268, 1, 262, 5, 1), + (8269, 1, 262, 10, 1), + (8270, 1, 262, 15, 1), + (8271, 1, 262, 20, 1), + (8272, 1, 262, 25, 1), + (8273, 1, 262, 5, 2), + (8274, 1, 262, 10, 2), + (8275, 1, 262, 15, 2), + (8276, 1, 262, 20, 2), + (8277, 1, 262, 25, 2), + (8278, 1, 262, 5, 3), + (8279, 1, 262, 10, 3), + (8280, 1, 262, 15, 3), + (8281, 1, 262, 20, 3), + (8282, 1, 262, 25, 3), + (8283, 1, 262, 5, 4), + (8284, 1, 262, 10, 4), + (8285, 1, 262, 15, 4), + (8286, 1, 262, 20, 4), + (8287, 1, 262, 25, 4), + (8288, 1, 262, 5, 5), + (8289, 1, 262, 10, 5), + (8290, 1, 262, 15, 5), + (8291, 1, 262, 20, 5), + (8292, 1, 262, 25, 5), + (8293, 1, 262, 5, 6), + (8294, 1, 262, 10, 6), + (8295, 1, 262, 15, 6), + (8296, 1, 262, 20, 6), + (8297, 1, 262, 25, 6), + (8304, 1, 1, 174, 0), + (8305, 1, 1, 203, 0), + (8306, 1, 1, 232, 0), + (8307, 1, 1, 261, 0), + (8308, 1, 1, 290, 0), + (8313, 1, 128, 65, 65), + (8313, 2, 138, 1, 0), + (8313, 3, 140, 1, 0), + (8313, 4, 311, 0, 0), + (8313, 5, 411, 256, 0), + (8313, 6, 137, -40, 0), + (8313, 7, 391, 1, 0), + (8314, 1, 378, 2, 3), + (8315, 1, 378, 3, 3), + (8316, 1, 378, 4, 3), + (8317, 1, 264, 1, 8205), + (8318, 1, 264, 2, 8205), + (8319, 1, 264, 2, 199), + (8320, 1, 264, 4, 199), + (8321, 1, 264, 6, 199), + (8322, 1, 378, 15, 31), + (8323, 1, 378, 20, 31), + (8324, 1, 378, 25, 31), + (8325, 1, 114, -3, 0), + (8326, 1, 114, -6, 0), + (8327, 1, 114, -9, 0), + (8328, 1, 268, 75, 56), + (8328, 2, 234, 1000, 0), + (8329, 1, 227, 4, 29), + (8329, 2, 227, 4, 42), + (8331, 1, 413, 10, 0), + (8331, 2, 139, 8001, 0), + (8331, 3, 385, 12529, 0), + (8331, 4, 411, 512, 0), + (8332, 1, 287, 1, 0), + (8332, 2, 385, 116121, 0), + (8333, 1, 287, 2, 0), + (8333, 2, 385, 116121, 0), + (8334, 1, 287, 3, 0), + (8334, 2, 385, 116121, 0), + (8335, 1, 127, 10, 0), + (8335, 2, 385, 16188, 0), + (8336, 1, 127, 20, 0), + (8336, 2, 385, 16188, 0), + (8337, 1, 127, 30, 0), + (8337, 2, 385, 16188, 0), + (8338, 1, 127, 40, 0), + (8338, 2, 385, 16188, 0), + (8339, 1, 127, 50, 0), + (8339, 2, 385, 16188, 0), + (8344, 1, 294, 0, 175), + (8345, 1, 294, 0, 180), + (8346, 1, 294, 0, 185), + (8347, 1, 264, 600, 616), + (8348, 1, 264, 1200, 616), + (8349, 1, 264, 1800, 616), + (8350, 1, 310, 1200, 0), + (8350, 2, 385, 6212, 0), + (8350, 3, 310, 600, 0), + (8350, 4, 385, 6215, 0), + (8350, 5, 310, 150, 0), + (8350, 6, 385, 6218, 0), + (8350, 7, 310, 9000, 0), + (8350, 8, 385, 6232, 0), + (8350, 9, 310, 600, 0), + (8350, 10, 385, 6243, 0), + (8350, 11, 310, 150, 0), + (8350, 12, 385, 6245, 0), + (8350, 13, 310, 1200, 0), + (8350, 14, 385, 6412, 0), + (8350, 15, 310, 600, 0), + (8350, 16, 385, 6415, 0), + (8350, 17, 310, 150, 0), + (8350, 18, 385, 6418, 0), + (8350, 19, 310, 9000, 0), + (8350, 20, 385, 6432, 0), + (8350, 21, 310, 600, 0), + (8350, 22, 385, 6443, 0), + (8350, 23, 310, 150, 0), + (8350, 24, 385, 6445, 0), + (8351, 1, 262, 30, 0), + (8352, 1, 262, 35, 0), + (8353, 1, 262, 40, 0), + (8354, 1, 262, 45, 0), + (8355, 1, 262, 50, 0), + (8356, 1, 262, 55, 0), + (8357, 1, 262, 60, 0), + (8358, 1, 262, 65, 0), + (8359, 1, 262, 70, 0), + (8360, 1, 262, 75, 0), + (8361, 1, 262, 30, 1), + (8362, 1, 262, 35, 1), + (8363, 1, 262, 40, 1), + (8364, 1, 262, 45, 1), + (8365, 1, 262, 50, 1), + (8366, 1, 262, 55, 1), + (8367, 1, 262, 60, 1), + (8368, 1, 262, 65, 1), + (8369, 1, 262, 70, 1), + (8370, 1, 262, 75, 1), + (8371, 1, 262, 30, 2), + (8372, 1, 262, 35, 2), + (8373, 1, 262, 40, 2), + (8374, 1, 262, 45, 2), + (8375, 1, 262, 50, 2), + (8376, 1, 262, 55, 2), + (8377, 1, 262, 60, 2), + (8378, 1, 262, 65, 2), + (8379, 1, 262, 70, 2), + (8380, 1, 262, 75, 2), + (8381, 1, 262, 30, 3), + (8382, 1, 262, 35, 3), + (8383, 1, 262, 40, 3), + (8384, 1, 262, 45, 3), + (8385, 1, 262, 50, 3), + (8386, 1, 262, 55, 3), + (8387, 1, 262, 60, 3), + (8388, 1, 262, 65, 3), + (8389, 1, 262, 70, 3), + (8390, 1, 262, 75, 3), + (8391, 1, 262, 30, 4), + (8392, 1, 262, 35, 4), + (8393, 1, 262, 40, 4), + (8394, 1, 262, 45, 4), + (8395, 1, 262, 50, 4), + (8396, 1, 262, 55, 4), + (8397, 1, 262, 60, 4), + (8398, 1, 262, 65, 4), + (8399, 1, 262, 70, 4), + (8400, 1, 262, 75, 4), + (8401, 1, 262, 30, 5), + (8402, 1, 262, 35, 5), + (8403, 1, 262, 40, 5), + (8404, 1, 262, 45, 5), + (8405, 1, 262, 50, 5), + (8406, 1, 262, 55, 5), + (8407, 1, 262, 60, 5), + (8408, 1, 262, 65, 5), + (8409, 1, 262, 70, 5), + (8410, 1, 262, 75, 5), + (8411, 1, 262, 30, 6), + (8412, 1, 262, 35, 6), + (8413, 1, 262, 40, 6), + (8414, 1, 262, 45, 6), + (8415, 1, 262, 50, 6), + (8416, 1, 262, 55, 6), + (8417, 1, 262, 60, 6), + (8418, 1, 262, 65, 6), + (8419, 1, 262, 70, 6), + (8420, 1, 262, 75, 6), + (8421, 1, 339, 10, 27535), + (8421, 2, 138, 1, 0), + (8421, 3, 141, 1, 0), + (8421, 4, 142, 75, 0), + (8421, 5, 137, 0, 0), + (8421, 6, 311, 0, 0), + (8421, 7, 134, 95, 0), + (8421, 8, 139, -265, 0), + (8421, 9, 139, -754, 0), + (8421, 10, 139, -1332, 0), + (8421, 11, 139, -1572, 0), + (8421, 12, 139, -2749, 0), + (8421, 13, 139, -4979, 0), + (8421, 14, 139, -5418, 0), + (8421, 15, 139, -5403, 0), + (8422, 1, 1, 198, 0), + (8423, 1, 1, 231, 0), + (8424, 1, 1, 264, 0), + (8425, 1, 1, 297, 0), + (8426, 1, 1, 330, 0), + (8427, 1, 264, 1260, 254), + (8428, 1, 264, 1440, 254), + (8429, 1, 264, 1620, 254), + (8430, 1, 328, 1600, 0), + (8435, 1, 0, 35, 0), + (8440, 1, 259, 66, 0), + (8445, 1, 426, 3, 0), + (8446, 1, 426, 4, 0), + (8447, 1, 426, 5, 0), + (8448, 1, 69, 2200, 0), + (8463, 1, 172, 60, 0), + (8464, 1, 172, 61, 0), + (8470, 1, 262, 80, 7), + (8470, 2, 262, 80, 8), + (8470, 3, 262, 80, 9), + (8470, 4, 262, 80, 10), + (8470, 5, 262, 80, 11), + (9001, 1, 247, 10, 58), + (9002, 1, 247, 20, 58), + (9003, 1, 247, 30, 58), + (9004, 1, 247, 40, 58), + (9005, 1, 247, 50, 58), + (9006, 1, 247, 60, 58), + (9007, 1, 247, 70, 58), + (9008, 1, 247, 80, 58), + (9009, 1, 247, 90, 58), + (9010, 1, 247, 100, 58), + (9011, 1, 247, 10, 58), + (9012, 1, 247, 20, 58), + (9013, 1, 247, 30, 58), + (9014, 1, 247, 40, 58), + (9015, 1, 247, 50, 58), + (9016, 1, 247, 60, 58), + (9017, 1, 247, 70, 58), + (9018, 1, 247, 80, 58), + (9019, 1, 247, 90, 58), + (9020, 1, 247, 100, 58), + (9021, 1, 247, 10, 58), + (9022, 1, 247, 20, 58), + (9023, 1, 247, 30, 58), + (9024, 1, 247, 40, 58), + (9025, 1, 247, 50, 58), + (9026, 1, 247, 60, 58), + (9027, 1, 247, 70, 58), + (9028, 1, 247, 80, 58), + (9029, 1, 247, 90, 58), + (9030, 1, 247, 100, 58), + (9033, 1, 264, 18000, 481), + (9033, 2, 264, 18000, 482), + (9033, 3, 264, 18000, 483), + (9033, 4, 264, 147600, 484), + (9033, 5, 264, 18000, 485), + (9033, 6, 264, 61200, 486), + (9033, 7, 264, 3600, 487), + (9033, 8, 264, 1080, 511), + (9033, 9, 264, 18000, 182), + (9033, 10, 264, 18000, 8081), + (9033, 11, 264, 18000, 8130), + (9033, 12, 264, 18000, 453), + (9033, 13, 264, 18000, 2000), + (9100, 1, 97, 10, 0), + (9100, 2, 262, 1, 5), + (9101, 1, 97, 20, 0), + (9101, 2, 262, 2, 5), + (9102, 1, 97, 30, 0), + (9102, 2, 262, 3, 5), + (9103, 1, 97, 40, 0), + (9103, 2, 262, 4, 5), + (9104, 1, 97, 50, 0), + (9104, 2, 262, 5, 5), + (9105, 1, 97, 60, 0), + (9105, 2, 262, 6, 5), + (9106, 1, 97, 70, 0), + (9106, 2, 262, 7, 5), + (9107, 1, 97, 80, 0), + (9107, 2, 262, 8, 5), + (9108, 1, 97, 90, 0), + (9108, 2, 262, 9, 5), + (9109, 1, 69, 10, 0), + (9109, 2, 262, 1, 1), + (9110, 1, 69, 20, 0), + (9110, 2, 262, 2, 1), + (9111, 1, 69, 30, 0), + (9111, 2, 262, 3, 1), + (9112, 1, 69, 40, 0), + (9112, 2, 262, 4, 1), + (9113, 1, 69, 50, 0), + (9113, 2, 262, 5, 1), + (9114, 1, 69, 60, 0), + (9114, 2, 262, 6, 1), + (9115, 1, 69, 70, 0), + (9115, 2, 262, 7, 1), + (9116, 1, 69, 80, 0), + (9116, 2, 262, 8, 1), + (9117, 1, 69, 90, 0), + (9117, 2, 262, 9, 1), + (9118, 1, 97, 10, 0), + (9118, 2, 262, 1, 5), + (9119, 1, 97, 20, 0), + (9119, 2, 262, 2, 5), + (9120, 1, 97, 30, 0), + (9120, 2, 262, 3, 5), + (9121, 1, 97, 40, 0), + (9121, 2, 262, 4, 5), + (9122, 1, 97, 50, 0), + (9122, 2, 262, 5, 5), + (9123, 1, 97, 60, 0), + (9123, 2, 262, 6, 5), + (9124, 1, 97, 70, 0), + (9124, 2, 262, 7, 5), + (9125, 1, 97, 80, 0), + (9125, 2, 262, 8, 5), + (9126, 1, 97, 90, 0), + (9126, 2, 262, 9, 5), + (9127, 1, 69, 10, 0), + (9127, 2, 262, 1, 5), + (9128, 1, 69, 20, 0), + (9128, 2, 262, 2, 5), + (9129, 1, 69, 30, 0), + (9129, 2, 262, 3, 5), + (9130, 1, 69, 40, 0), + (9130, 2, 262, 4, 5), + (9131, 1, 69, 50, 0), + (9131, 2, 262, 5, 5), + (9132, 1, 69, 60, 0), + (9132, 2, 262, 6, 5), + (9133, 1, 69, 70, 0), + (9133, 2, 262, 7, 5), + (9134, 1, 69, 80, 0), + (9134, 2, 262, 8, 5), + (9135, 1, 69, 90, 0), + (9135, 2, 262, 9, 5), + (9136, 1, 97, 10, 0), + (9136, 2, 262, 1, 4), + (9137, 1, 97, 20, 0), + (9137, 2, 262, 2, 4), + (9138, 1, 97, 30, 0), + (9138, 2, 262, 3, 4), + (9139, 1, 97, 40, 0), + (9139, 2, 262, 4, 4), + (9140, 1, 97, 50, 0), + (9140, 2, 262, 5, 4), + (9141, 1, 97, 60, 0), + (9141, 2, 262, 6, 4), + (9142, 1, 97, 70, 0), + (9142, 2, 262, 7, 4), + (9143, 1, 97, 80, 0), + (9143, 2, 262, 8, 4), + (9144, 1, 97, 90, 0), + (9144, 2, 262, 9, 4), + (9145, 1, 97, 10, 0), + (9145, 2, 262, 1, 4), + (9146, 1, 97, 20, 0), + (9146, 2, 262, 2, 4), + (9147, 1, 97, 30, 0), + (9147, 2, 262, 3, 4), + (9148, 1, 97, 40, 0), + (9148, 2, 262, 4, 4), + (9149, 1, 97, 50, 0), + (9149, 2, 262, 5, 4), + (9150, 1, 97, 60, 0), + (9150, 2, 262, 6, 4), + (9151, 1, 97, 70, 0), + (9151, 2, 262, 7, 4), + (9152, 1, 97, 80, 0), + (9152, 2, 262, 8, 4), + (9153, 1, 97, 90, 0), + (9153, 2, 262, 9, 4), + (9154, 1, 69, 10, 0), + (9154, 2, 262, 1, 1), + (9155, 1, 69, 20, 0), + (9155, 2, 262, 2, 1), + (9156, 1, 69, 30, 0), + (9156, 2, 262, 3, 1), + (9157, 1, 69, 40, 0), + (9157, 2, 262, 4, 1), + (9158, 1, 69, 50, 0), + (9158, 2, 262, 5, 1), + (9159, 1, 69, 60, 0), + (9159, 2, 262, 6, 1), + (9160, 1, 69, 70, 0), + (9160, 2, 262, 7, 1), + (9161, 1, 69, 80, 0), + (9161, 2, 262, 8, 1), + (9162, 1, 69, 90, 0), + (9162, 2, 262, 9, 1), + (9163, 1, 69, 10, 0), + (9163, 2, 262, 1, 3), + (9164, 1, 69, 20, 0), + (9164, 2, 262, 2, 3), + (9165, 1, 69, 30, 0), + (9165, 2, 262, 3, 3), + (9166, 1, 69, 40, 0), + (9166, 2, 262, 4, 3), + (9167, 1, 69, 50, 0), + (9167, 2, 262, 5, 3), + (9168, 1, 69, 60, 0), + (9168, 2, 262, 6, 3), + (9169, 1, 69, 70, 0), + (9169, 2, 262, 7, 3), + (9170, 1, 69, 80, 0), + (9170, 2, 262, 8, 3), + (9171, 1, 69, 90, 0), + (9171, 2, 262, 9, 3), + (9172, 1, 69, 10, 0), + (9172, 2, 262, 1, 0), + (9173, 1, 69, 20, 0), + (9173, 2, 262, 2, 0), + (9174, 1, 69, 30, 0), + (9174, 2, 262, 3, 0), + (9175, 1, 69, 40, 0), + (9175, 2, 262, 4, 0), + (9176, 1, 69, 50, 0), + (9176, 2, 262, 5, 0), + (9177, 1, 69, 60, 0), + (9177, 2, 262, 6, 0), + (9178, 1, 69, 70, 0), + (9178, 2, 262, 7, 0), + (9179, 1, 69, 80, 0), + (9179, 2, 262, 8, 0), + (9180, 1, 69, 90, 0), + (9180, 2, 262, 9, 0), + (9181, 1, 69, 10, 0), + (9181, 2, 262, 1, 0), + (9182, 1, 69, 20, 0), + (9182, 2, 262, 2, 0), + (9183, 1, 69, 30, 0), + (9183, 2, 262, 3, 0), + (9184, 1, 69, 40, 0), + (9184, 2, 262, 4, 0), + (9185, 1, 69, 50, 0), + (9185, 2, 262, 5, 0), + (9186, 1, 69, 60, 0), + (9186, 2, 262, 6, 0), + (9187, 1, 69, 70, 0), + (9187, 2, 262, 7, 0), + (9188, 1, 69, 80, 0), + (9188, 2, 262, 8, 0), + (9189, 1, 69, 90, 0), + (9189, 2, 262, 9, 0), + (9190, 1, 69, 10, 0), + (9190, 2, 262, 1, 0), + (9191, 1, 69, 20, 0), + (9191, 2, 262, 2, 0), + (9192, 1, 69, 30, 0), + (9192, 2, 262, 3, 0), + (9193, 1, 69, 40, 0), + (9193, 2, 262, 4, 0), + (9194, 1, 69, 50, 0), + (9194, 2, 262, 5, 0), + (9195, 1, 69, 60, 0), + (9195, 2, 262, 6, 0), + (9196, 1, 69, 70, 0), + (9196, 2, 262, 7, 0), + (9197, 1, 69, 80, 0), + (9197, 2, 262, 8, 0), + (9198, 1, 69, 90, 0), + (9198, 2, 262, 9, 0), + (9199, 1, 97, 10, 0), + (9199, 2, 262, 1, 0), + (9200, 1, 97, 20, 0), + (9200, 2, 262, 2, 0), + (9201, 1, 97, 30, 0), + (9201, 2, 262, 3, 0), + (9202, 1, 97, 40, 0), + (9202, 2, 262, 4, 0), + (9203, 1, 97, 50, 0), + (9203, 2, 262, 5, 0), + (9204, 1, 97, 60, 0), + (9204, 2, 262, 6, 0), + (9205, 1, 97, 70, 0), + (9205, 2, 262, 7, 0), + (9206, 1, 97, 80, 0), + (9206, 2, 262, 8, 0), + (9207, 1, 97, 90, 0), + (9207, 2, 262, 9, 0), + (9208, 1, 69, 10, 0), + (9208, 2, 262, 1, 0), + (9209, 1, 69, 20, 0), + (9209, 2, 262, 2, 0), + (9210, 1, 69, 30, 0), + (9210, 2, 262, 3, 0), + (9211, 1, 69, 40, 0), + (9211, 2, 262, 4, 0), + (9212, 1, 69, 50, 0), + (9212, 2, 262, 5, 0), + (9213, 1, 69, 60, 0), + (9213, 2, 262, 6, 0), + (9214, 1, 69, 70, 0), + (9214, 2, 262, 7, 0), + (9215, 1, 69, 80, 0), + (9215, 2, 262, 8, 0), + (9216, 1, 69, 90, 0), + (9216, 2, 262, 9, 0), + (9217, 1, 190, 10, 0), + (9217, 2, 262, 1, 0), + (9218, 1, 190, 20, 0), + (9218, 2, 262, 2, 0), + (9219, 1, 190, 30, 0), + (9219, 2, 262, 3, 0), + (9220, 1, 190, 40, 0), + (9220, 2, 262, 4, 0), + (9221, 1, 190, 50, 0), + (9221, 2, 262, 5, 0), + (9222, 1, 190, 60, 0), + (9222, 2, 262, 6, 0), + (9223, 1, 190, 70, 0), + (9223, 2, 262, 7, 0), + (9224, 1, 190, 80, 0), + (9224, 2, 262, 8, 0), + (9225, 1, 190, 90, 0), + (9225, 2, 262, 9, 0), + (9226, 1, 69, 10, 0), + (9226, 2, 262, 1, 0), + (9227, 1, 69, 20, 0), + (9227, 2, 262, 2, 0), + (9228, 1, 69, 30, 0), + (9228, 2, 262, 3, 0), + (9229, 1, 69, 40, 0), + (9229, 2, 262, 4, 0), + (9230, 1, 69, 50, 0), + (9230, 2, 262, 5, 0), + (9231, 1, 69, 60, 0), + (9231, 2, 262, 6, 0), + (9232, 1, 69, 70, 0), + (9232, 2, 262, 7, 0), + (9233, 1, 69, 80, 0), + (9233, 2, 262, 8, 0), + (9234, 1, 69, 90, 0), + (9234, 2, 262, 9, 0), + (9235, 1, 190, 10, 0), + (9235, 2, 262, 1, 0), + (9236, 1, 190, 20, 0), + (9236, 2, 262, 2, 0), + (9237, 1, 190, 30, 0), + (9237, 2, 262, 3, 0), + (9238, 1, 190, 40, 0), + (9238, 2, 262, 4, 0), + (9239, 1, 190, 50, 0), + (9239, 2, 262, 5, 0), + (9240, 1, 190, 60, 0), + (9240, 2, 262, 6, 0), + (9241, 1, 190, 70, 0), + (9241, 2, 262, 7, 0), + (9242, 1, 190, 80, 0), + (9242, 2, 262, 8, 0), + (9243, 1, 190, 90, 0), + (9243, 2, 262, 9, 0), + (9503, 1, 397, 100, 0), + (9504, 1, 397, 200, 0), + (9505, 1, 397, 300, 0), + (9506, 1, 398, 1000, 0), + (9506, 2, 137, 152, 0), + (9507, 1, 398, 2000, 0), + (9507, 2, 137, 152, 0), + (9508, 1, 398, 3000, 0), + (9508, 2, 137, 152, 0), + (9509, 1, 399, 1, 0), + (9509, 2, 141, 1, 0), + (9509, 3, 138, 0, 0), + (9509, 4, 134, 254, 0), + (9509, 5, 348, 10, 0), + (9509, 6, 137, 0, 0), + (9509, 7, 311, 0, 0), + (9509, 8, 137, -152, 0), + (9509, 9, 137, -39, 0), + (9510, 1, 399, 2, 0), + (9510, 2, 141, 1, 0), + (9510, 3, 138, 0, 0), + (9510, 4, 134, 254, 0), + (9510, 5, 348, 10, 0), + (9510, 6, 137, 0, 0), + (9510, 7, 311, 0, 0), + (9510, 8, 137, -152, 0), + (9510, 9, 137, -39, 0), + (9511, 1, 399, 3, 0), + (9511, 2, 141, 1, 0), + (9511, 3, 138, 0, 0), + (9511, 4, 134, 254, 0), + (9511, 5, 348, 10, 0), + (9511, 6, 137, 0, 0), + (9511, 7, 311, 0, 0), + (9511, 8, 137, -152, 0), + (9511, 9, 137, -39, 0), + (9512, 1, 405, 1, 0), + (9513, 1, 405, 3, 0), + (9514, 1, 405, 5, 0), + (9515, 1, 399, 4, 0), + (9515, 2, 141, 1, 0), + (9515, 3, 138, 0, 0), + (9515, 4, 134, 254, 0), + (9515, 5, 348, 10, 0), + (9515, 6, 137, 0, 0), + (9515, 7, 311, 0, 0), + (9515, 8, 137, -152, 0), + (9515, 9, 137, -39, 0), + (10004, 1, 310, 480000, 0), + (10004, 2, 139, 4674, 0), + (10005, 1, 310, 600000, 0), + (10005, 2, 139, 4674, 0), + (10007, 1, 85, 16500, 50), + (10008, 1, 85, 16501, 50), + (10009, 1, 85, 16502, 50), + (10025, 1, 339, 25, 16517), + (10025, 2, 137, 21, 0), + (10026, 1, 339, 25, 16518), + (10026, 2, 137, 21, 0), + (10027, 1, 339, 25, 16519), + (10027, 2, 137, 21, 0), + (10028, 1, 339, 25, 16520), + (10028, 2, 137, 21, 0), + (10029, 1, 339, 25, 16555), + (10029, 2, 137, 21, 0), + (10030, 1, 264, 60, 558), + (10031, 1, 264, 75, 558), + (10032, 1, 264, 90, 558), + (10033, 1, 310, 8000, 0), + (10033, 2, 139, 8007, 0), + (10033, 3, 310, 8000, 0), + (10033, 4, 385, 4140, 0), + (10033, 5, 385, 4240, 0), + (10033, 6, 385, 4340, 0), + (10033, 7, 385, 4440, 0), + (10033, 8, 385, 4540, 0), + (10033, 9, 385, 4640, 0), + (10034, 1, 310, 10000, 0), + (10034, 2, 139, 8007, 0), + (10034, 3, 310, 10000, 0), + (10034, 4, 385, 4140, 0), + (10034, 5, 385, 4240, 0), + (10034, 6, 385, 4340, 0), + (10034, 7, 385, 4440, 0), + (10034, 8, 385, 4540, 0), + (10034, 9, 385, 4640, 0), + (10035, 1, 339, 25, 16556), + (10035, 2, 138, 1, 0), + (10035, 3, 142, 60, 0), + (10035, 4, 137, 35, 0), + (10035, 5, 134, 85, 0), + (10035, 6, 339, 25, 16556), + (10035, 7, 138, 1, 0), + (10035, 8, 142, 60, 0), + (10035, 9, 137, 36, 0), + (10035, 10, 134, 85, 0), + (10035, 11, 339, 25, 16556), + (10035, 12, 138, 1, 0), + (10035, 13, 142, 60, 0), + (10035, 14, 137, 369, 0), + (10035, 15, 134, 85, 0), + (10035, 16, 339, 25, 16556), + (10035, 17, 138, 1, 0), + (10035, 18, 142, 60, 0), + (10035, 19, 137, 116, 0), + (10035, 20, 134, 85, 0), + (10036, 1, 339, 25, 16557), + (10036, 2, 138, 1, 0), + (10036, 3, 142, 60, 0), + (10036, 4, 137, 35, 0), + (10036, 5, 134, 85, 0), + (10036, 6, 339, 25, 16557), + (10036, 7, 138, 1, 0), + (10036, 8, 142, 60, 0), + (10036, 9, 137, 36, 0), + (10036, 10, 134, 85, 0), + (10036, 11, 339, 25, 16557), + (10036, 12, 138, 1, 0), + (10036, 13, 142, 60, 0), + (10036, 14, 137, 369, 0), + (10036, 15, 134, 85, 0), + (10036, 16, 339, 25, 16557), + (10036, 17, 138, 1, 0), + (10036, 18, 142, 60, 0), + (10036, 19, 137, 116, 0), + (10036, 20, 134, 85, 0), + (10037, 1, 339, 25, 16558), + (10037, 2, 138, 1, 0), + (10037, 3, 142, 60, 0), + (10037, 4, 137, 35, 0), + (10037, 5, 134, 85, 0), + (10037, 6, 339, 25, 16558), + (10037, 7, 138, 1, 0), + (10037, 8, 142, 60, 0), + (10037, 9, 137, 36, 0), + (10037, 10, 134, 85, 0), + (10037, 11, 339, 25, 16558), + (10037, 12, 138, 1, 0), + (10037, 13, 142, 60, 0), + (10037, 14, 137, 369, 0), + (10037, 15, 134, 85, 0), + (10037, 16, 339, 25, 16558), + (10037, 17, 138, 1, 0), + (10037, 18, 142, 60, 0), + (10037, 19, 137, 116, 0), + (10037, 20, 134, 85, 0), + (10041, 1, 294, 0, 135), + (10042, 1, 294, 0, 145), + (10043, 1, 294, 0, 155), + (10044, 1, 339, 20, 16564), + (10044, 2, 137, 21, 0), + (10044, 3, 385, -18000, 0), + (10044, 4, 339, 20, 16564), + (10044, 5, 137, 343, 0), + (10044, 6, 385, -18000, 0), + (10045, 1, 339, 20, 16565), + (10045, 2, 137, 21, 0), + (10045, 3, 385, -18000, 0), + (10045, 4, 339, 20, 16565), + (10045, 5, 137, 343, 0), + (10045, 6, 385, -18000, 0), + (10046, 1, 339, 20, 16566), + (10046, 2, 137, 21, 0), + (10046, 3, 385, -18000, 0), + (10046, 4, 339, 20, 16566), + (10046, 5, 137, 343, 0), + (10046, 6, 385, -18000, 0), + (10050, 1, 85, 16567, 0), + (10051, 1, 85, 16568, 0), + (10052, 1, 85, 16569, 0), + (10058, 1, 330, 55, 7), + (10059, 1, 330, 60, 7), + (10060, 1, 330, 65, 7), + (10064, 1, 347, 25, 0), + (10065, 1, 347, 26, 0), + (10066, 1, 347, 27, 0), + (10067, 1, 347, 28, 0), + (10068, 1, 347, 29, 0), + (10069, 1, 347, 30, 0), + (10070, 1, 218, 6, 0), + (10071, 1, 218, 7, 0), + (10072, 1, 218, 8, 0), + (10073, 1, 218, 9, 0), + (10074, 1, 218, 10, 0), + (10075, 1, 339, 10, 16581), + (10075, 2, 138, 0, 0), + (10075, 3, 142, 70, 0), + (10075, 4, 403, 4, 0), + (10075, 5, 348, 1, 0), + (10075, 6, 404, 2, 0), + (10075, 7, 141, 1, 0), + (10076, 1, 339, 10, 16582), + (10076, 2, 138, 0, 0), + (10076, 3, 142, 70, 0), + (10076, 4, 403, 4, 0), + (10076, 5, 348, 1, 0), + (10076, 6, 404, 2, 0), + (10076, 7, 141, 1, 0), + (10077, 1, 339, 10, 16583), + (10077, 2, 138, 0, 0), + (10077, 3, 142, 70, 0), + (10077, 4, 403, 4, 0), + (10077, 5, 348, 1, 0), + (10077, 6, 404, 2, 0), + (10077, 7, 141, 1, 0), + (10081, 1, 85, 16584, 0), + (10082, 1, 85, 16585, 0), + (10083, 1, 85, 16586, 0), + (10084, 1, 375, 175, 0), + (10085, 1, 375, 200, 0), + (10086, 1, 375, 215, 0), + (10087, 1, 397, 400, 0), + (10088, 1, 397, 600, 0), + (10089, 1, 397, 800, 0), + (10105, 1, 264, 60, 170), + (10106, 1, 264, 70, 170), + (10107, 1, 264, 80, 170), + (10108, 1, 264, 90, 170), + (10109, 1, 264, 100, 170), + (10110, 1, 264, 480, 520), + (10111, 1, 264, 600, 520), + (10112, 1, 264, 720, 520), + (10122, 1, 227, 210, 32), + (10123, 1, 227, 240, 32), + (10124, 1, 283, 180, 0), + (10125, 1, 283, 200, 0), + (10126, 1, 283, 220, 0), + (10130, 1, 264, 720, 544), + (10131, 1, 264, 900, 544), + (10132, 1, 264, 1080, 544), + (10133, 1, 279, 19, 0), + (10134, 1, 279, 23, 0), + (10135, 1, 279, 27, 0), + (10136, 1, 375, 130, 0), + (10137, 1, 375, 135, 0), + (10138, 1, 375, 140, 0), + (10153, 1, 264, 420, 553), + (10154, 1, 264, 480, 553), + (10155, 1, 264, 540, 553), + (10165, 1, 220, 195, 8), + (10166, 1, 220, 225, 8), + (10167, 1, 220, 255, 8), + (10171, 1, 252, 90, 0), + (10172, 1, 252, 95, 0), + (10173, 1, 258, 70, 0), + (10174, 1, 258, 71, 0), + (10175, 1, 258, 72, 0), + (10176, 1, 264, 40, 171), + (10177, 1, 264, 50, 171), + (10178, 1, 264, 60, 171), + (10182, 1, 264, 180, 177), + (10183, 1, 264, 210, 177), + (10184, 1, 264, 240, 177), + (10185, 1, 264, 270, 177), + (10186, 1, 264, 300, 177), + (10203, 1, 264, 720, 524), + (10204, 1, 264, 900, 524), + (10205, 1, 264, 1080, 524), + (10206, 1, 264, 1080, 320), + (10207, 1, 264, 1260, 320), + (10213, 1, 218, 16, 0), + (10214, 1, 218, 17, 0), + (10215, 1, 218, 18, 0), + (10216, 1, 218, 19, 0), + (10217, 1, 218, 20, 0), + (10219, 1, 280, 63, 0), + (10220, 1, 280, 64, 0), + (10221, 1, 280, 65, 0), + (10222, 1, 280, 66, 0), + (10223, 1, 280, 67, 0), + (10227, 1, 360, 60, 16720), + (10228, 1, 360, 60, 16721), + (10229, 1, 360, 60, 16722), + (10249, 1, 264, 240, 208), + (10250, 1, 264, 300, 208), + (10251, 1, 264, 360, 208), + (10262, 1, 274, 23, 0), + (10263, 1, 274, 24, 0), + (10264, 1, 274, 25, 0), + (10265, 1, 280, 57, 0), + (10266, 1, 280, 58, 0), + (10267, 1, 280, 59, 0), + (10268, 1, 339, 45, 16736), + (10268, 2, 136, 11, 0), + (10268, 3, 383, 45, 16736), + (10268, 4, 385, 11012, 0), + (10268, 5, 383, 45, 16736), + (10268, 6, 385, 5130, 0), + (10268, 7, 383, 45, 16736), + (10268, 8, 385, 5230, 0), + (10268, 9, 383, 45, 16736), + (10268, 10, 136, 22, 0), + (10268, 11, 383, 45, 16736), + (10268, 12, 385, 5330, 0), + (10268, 13, 385, 5430, 0), + (10268, 14, 385, 5530, 0), + (10269, 1, 339, 45, 16737), + (10269, 2, 136, 11, 0), + (10269, 3, 383, 45, 16737), + (10269, 4, 385, 11012, 0), + (10269, 5, 383, 45, 16737), + (10269, 6, 385, 5130, 0), + (10269, 7, 383, 45, 16737), + (10269, 8, 385, 5230, 0), + (10269, 9, 383, 45, 16737), + (10269, 10, 136, 22, 0), + (10269, 11, 383, 45, 16737), + (10269, 12, 385, 5330, 0), + (10269, 13, 385, 5430, 0), + (10269, 14, 385, 5530, 0), + (10270, 1, 339, 45, 16738), + (10270, 2, 136, 11, 0), + (10270, 3, 383, 45, 16738), + (10270, 4, 385, 11012, 0), + (10270, 5, 383, 45, 16738), + (10270, 6, 385, 5130, 0), + (10270, 7, 383, 45, 16738), + (10270, 8, 385, 5230, 0), + (10270, 9, 383, 45, 16738), + (10270, 10, 136, 22, 0), + (10270, 11, 383, 45, 16738), + (10270, 12, 385, 5330, 0), + (10270, 13, 385, 5430, 0), + (10270, 14, 385, 5530, 0), + (10282, 1, 264, 120, 791), + (10283, 1, 264, 150, 791), + (10284, 1, 264, 180, 791), + (10285, 1, 264, 720, 521), + (10286, 1, 264, 900, 521), + (10287, 1, 264, 1080, 521), + (10291, 1, 264, 15, 247), + (10291, 2, 264, 8, 986), + (10291, 3, 264, 8, 987), + (10291, 4, 264, 8, 988), + (10292, 1, 264, 18, 247), + (10292, 2, 264, 10, 986), + (10292, 3, 264, 10, 987), + (10292, 4, 264, 10, 988), + (10293, 1, 264, 21, 247), + (10293, 2, 264, 12, 986), + (10293, 3, 264, 12, 987), + (10293, 4, 264, 12, 988), + (10305, 1, 280, 68, 0), + (10306, 1, 280, 69, 0), + (10307, 1, 280, 70, 0), + (10311, 1, 220, 608, 74), + (10312, 1, 220, 640, 74), + (10313, 1, 220, 672, 74), + (10314, 1, 220, 704, 74), + (10315, 1, 220, 736, 74), + (10316, 1, 216, 160, 74), + (10317, 1, 216, 200, 74), + (10318, 1, 216, 240, 74), + (10329, 1, 264, 60, 3701), + (10332, 1, 287, 1, 0), + (10332, 2, 137, 22, 0), + (10332, 3, 411, 256, 0), + (10340, 1, 220, 100, 26), + (10341, 1, 220, 160, 26), + (10342, 1, 220, 235, 26), + (10343, 1, 264, 5, 469), + (10344, 1, 264, 10, 469), + (10345, 1, 264, 15, 469), + (10347, 1, 310, 12000, 0), + (10347, 2, 139, 8007, 0), + (10347, 3, 310, 12000, 0), + (10347, 4, 385, 4140, 0), + (10347, 5, 385, 4240, 0), + (10347, 6, 385, 4340, 0), + (10347, 7, 385, 4440, 0), + (10347, 8, 385, 4540, 0), + (10347, 9, 385, 4640, 0), + (10348, 1, 244, 60, 0), + (10349, 1, 244, 50, 0), + (10350, 1, 244, 40, 0), + (10355, 1, 124, 50, 50), + (10355, 2, 385, 19, 0), + (10355, 3, 144, 0, 0), + (10355, 4, 403, 3, 0), + (10355, 5, 404, 48, 0), + (10355, 6, 385, -21768, 0), + (10356, 1, 124, 100, 100), + (10356, 2, 385, 19, 0), + (10356, 3, 144, 0, 0), + (10356, 4, 403, 3, 0), + (10356, 5, 404, 48, 0), + (10356, 6, 385, -21768, 0), + (10357, 1, 124, 150, 150), + (10357, 2, 385, 19, 0), + (10357, 3, 144, 0, 0), + (10357, 4, 403, 3, 0), + (10357, 5, 404, 48, 0), + (10357, 6, 385, -21768, 0), + (10358, 1, 310, 10000, 0), + (10358, 2, 139, 1546, 0), + (10358, 3, 310, 10000, 0), + (10358, 4, 385, 4357, 0), + (10358, 5, 385, 4457, 0), + (10358, 6, 385, 4557, 0), + (10358, 7, 385, 4657, 0), + (10358, 8, 411, 4, 0), + (10359, 1, 310, 20000, 0), + (10359, 2, 139, 1546, 0), + (10359, 3, 310, 20000, 0), + (10359, 4, 385, 4357, 0), + (10359, 5, 385, 4457, 0), + (10359, 6, 385, 4557, 0), + (10359, 7, 385, 4657, 0), + (10359, 8, 411, 4, 0), + (10360, 1, 310, 30000, 0), + (10360, 2, 139, 1546, 0), + (10360, 3, 310, 30000, 0), + (10360, 4, 385, 4357, 0), + (10360, 5, 385, 4457, 0), + (10360, 6, 385, 4557, 0), + (10360, 7, 385, 4657, 0), + (10360, 8, 411, 4, 0), + (10361, 1, 232, 17, 4544), + (10362, 1, 232, 19, 4544), + (10363, 1, 232, 21, 4544), + (10364, 1, 413, -5, 0), + (10364, 2, 139, 480, 0), + (10364, 3, 385, 4352, 0), + (10364, 4, 385, 4452, 0), + (10365, 1, 413, -10, 0), + (10365, 2, 139, 480, 0), + (10365, 3, 385, 4352, 0), + (10365, 4, 385, 4452, 0), + (10366, 1, 413, -15, 0), + (10366, 2, 139, 480, 0), + (10366, 3, 385, 4352, 0), + (10366, 4, 385, 4452, 0), + (10370, 1, 114, -5, 0), + (10371, 1, 114, -10, 0), + (10372, 1, 114, -20, 0), + (10380, 1, 126, 5, 0), + (10380, 2, 134, 85, 0), + (10380, 3, 135, 4, 0), + (10380, 4, 135, 5, 0), + (10381, 1, 126, 10, 0), + (10381, 2, 134, 85, 0), + (10381, 3, 135, 4, 0), + (10381, 4, 135, 5, 0), + (10382, 1, 126, 15, 0), + (10382, 2, 134, 85, 0), + (10382, 3, 135, 4, 0), + (10382, 4, 135, 5, 0), + (10383, 1, 360, 25, 21770), + (10384, 1, 360, 25, 21771), + (10385, 1, 360, 25, 21772), + (10388, 1, 323, 21850, 0), + (10389, 1, 287, 5, 0), + (10389, 2, 385, 16107, 0), + (10389, 3, 411, 512, 0), + (10390, 1, 287, 10, 0), + (10390, 2, 385, 16107, 0), + (10390, 3, 411, 512, 0), + (10391, 1, 287, 15, 0), + (10391, 2, 385, 16107, 0), + (10391, 3, 411, 512, 0), + (10398, 1, 264, 120, 3701), + (10399, 1, 264, 180, 3701), + (10401, 1, 310, 30000, 0), + (10401, 2, 385, 3107, 0), + (10401, 3, 385, 3207, 0), + (10401, 4, 385, 3307, 0), + (10401, 5, 385, 3407, 0), + (10401, 6, 385, 3507, 0), + (10401, 7, 385, 3607, 0), + (10402, 1, 310, 60000, 0), + (10402, 2, 385, 3107, 0), + (10402, 3, 385, 3207, 0), + (10402, 4, 385, 3307, 0), + (10402, 5, 385, 3407, 0), + (10402, 6, 385, 3507, 0), + (10402, 7, 385, 3607, 0), + (10403, 1, 310, 90000, 0), + (10403, 2, 385, 3107, 0), + (10403, 3, 385, 3207, 0), + (10403, 4, 385, 3307, 0), + (10403, 5, 385, 3407, 0), + (10403, 6, 385, 3507, 0), + (10403, 7, 385, 3607, 0), + (10404, 1, 287, 1, 0), + (10404, 2, 139, 8003, 0), + (10405, 1, 310, 120000, 0), + (10405, 2, 139, 4590, 0), + (10406, 1, 310, 240000, 0), + (10406, 2, 139, 4590, 0), + (10407, 1, 310, 360000, 0), + (10407, 2, 139, 4590, 0), + (10408, 1, 310, 480000, 0), + (10408, 2, 139, 4590, 0), + (10409, 1, 310, 600000, 0), + (10409, 2, 139, 4590, 0), + (10410, 1, 247, 130, 76), + (10413, 1, 264, 60, 207), + (10414, 2, 264, 120, 207), + (10415, 3, 264, 180, 207), + (10416, 4, 264, 240, 207), + (10417, 5, 264, 300, 207), + (10431, 1, 264, 210, 791), + (10432, 1, 264, 240, 791), + (10433, 1, 264, 270, 791), + (10434, 1, 127, 16, 0), + (10434, 2, 385, 5921, 0), + (10435, 1, 127, 33, 0), + (10435, 2, 385, 5921, 0), + (10436, 1, 127, 50, 0), + (10436, 2, 385, 5921, 0), + (10437, 1, 339, 25, 23523), + (10437, 2, 137, 21, 0), + (10438, 1, 339, 25, 23524), + (10438, 2, 137, 21, 0), + (10439, 1, 339, 25, 23525), + (10439, 2, 137, 21, 0), + (10440, 1, 339, 25, 23526), + (10440, 2, 137, 21, 0), + (10442, 1, 413, -20, 0), + (10442, 2, 139, 480, 0), + (10442, 3, 385, 4352, 0), + (10442, 4, 385, 4452, 0), + (10443, 1, 413, -25, 0), + (10443, 2, 139, 480, 0), + (10443, 3, 385, 4352, 0), + (10443, 4, 385, 4452, 0), + (10453, 1, 126, 1, 1), + (10453, 2, 137, 21, 0), + (10453, 3, 231, 1, 0), + (10454, 1, 126, 2, 2), + (10454, 2, 137, 21, 0), + (10454, 3, 231, 2, 0), + (10455, 1, 126, 3, 3), + (10455, 2, 137, 21, 0), + (10455, 3, 231, 3, 0), + (10456, 1, 127, 15, 15), + (10456, 2, 139, 12786, 0), + (10457, 1, 127, 30, 30), + (10457, 2, 139, 12786, 0), + (10458, 1, 127, 50, 50), + (10458, 2, 139, 12786, 0), + (10459, 1, 310, 3000, 0), + (10459, 2, 139, 480, 0), + (10459, 3, 310, 3000, 0), + (10459, 4, 385, 4352, 0), + (10459, 5, 385, 4452, 0), + (10459, 6, 385, 4552, 0), + (10460, 1, 310, 6000, 0), + (10460, 2, 139, 480, 0), + (10460, 3, 310, 6000, 0), + (10460, 4, 385, 4352, 0), + (10460, 5, 385, 4452, 0), + (10460, 6, 385, 4552, 0), + (10461, 1, 310, 10000, 0), + (10461, 2, 139, 480, 0), + (10461, 3, 310, 10000, 0), + (10461, 4, 385, 4352, 0), + (10461, 5, 385, 4452, 0), + (10461, 6, 385, 4552, 0), + (10464, 1, 264, 120, 391), + (10465, 1, 264, 240, 391), + (10466, 1, 264, 360, 391), + (10467, 1, 128, 70, 70), + (10467, 2, 138, 1, 0), + (10467, 3, 140, 1, 0), + (10467, 4, 139, -2741, 0), + (10467, 5, 139, -16843, 0), + (10467, 6, 385, -16192, 0), + (10467, 7, 385, -10547, 0), + (10467, 8, 385, -13543, 0), + (10470, 1, 127, 10, 0), + (10470, 2, 385, 8048, 0), + (10471, 1, 127, 20, 0), + (10471, 2, 385, 8048, 0), + (10472, 1, 127, 30, 0), + (10472, 2, 385, 8048, 0), + (10473, 1, 265, 82, 0), + (10474, 1, 265, 83, 0), + (10475, 1, 265, 84, 0), + (10476, 1, 265, 85, 0), + (10477, 1, 265, 86, 0), + (10478, 1, 360, 3, 46246), + (10511, 1, 264, 60, 185), + (10511, 2, 264, 60, 10426), + (10512, 1, 264, 120, 185), + (10512, 2, 264, 120, 10426), + (10513, 1, 264, 180, 185), + (10513, 2, 264, 180, 10426), + (10514, 1, 264, 60, 519), + (10514, 2, 264, 60, 10427), + (10515, 1, 264, 180, 519), + (10515, 2, 264, 180, 10427), + (10516, 1, 264, 120, 519), + (10516, 2, 264, 120, 10427), + (10519, 1, 264, 60, 3213), + (10522, 1, 264, 2, 3732), + (10527, 1, 264, 30, 1400), + (10532, 1, 264, 30, 1401), + (10537, 1, 264, 30, 1402), + (10548, 1, 349, 10, 0), + (10548, 2, 200, 10, 0), + (10548, 3, 419, 27672, 20), + (10551, 1, 339, 10, 16825), + (10551, 2, 137, 31, 0), + (10552, 1, 339, 10, 16826), + (10552, 2, 137, 31, 0), + (10553, 1, 339, 10, 16827), + (10553, 2, 137, 31, 0), + (10554, 1, 339, 12, 8265), + (10554, 2, 138, 0, 0), + (10554, 3, 137, 31, 0), + (10554, 4, 311, 0, 0), + (10555, 1, 339, 14, 8265), + (10555, 2, 138, 0, 0), + (10555, 3, 137, 31, 0), + (10555, 4, 311, 0, 0), + (10556, 1, 339, 16, 8265), + (10556, 2, 138, 0, 0), + (10556, 3, 137, 31, 0), + (10556, 4, 311, 0, 0), + (10558, 1, 264, 60, 1120), + (10559, 1, 264, 120, 1120), + (10560, 1, 264, 180, 1120), + (10561, 1, 126, 5, 5), + (10561, 2, 139, 12576, 0), + (10561, 3, 126, 5, 5), + (10561, 4, 139, 12828, 0), + (10562, 1, 126, 10, 10), + (10562, 2, 139, 12576, 0), + (10562, 3, 126, 10, 10), + (10562, 4, 139, 12828, 0), + (10563, 1, 126, 15, 15), + (10563, 2, 139, 12576, 0), + (10563, 3, 126, 15, 15), + (10563, 4, 139, 12828, 0), + (10568, 1, 85, 23614, 50), + (10574, 1, 310, 720000, 0), + (10574, 2, 139, 4670, 0), + (10575, 1, 310, 720000, 0), + (10575, 2, 139, 4674, 0), + (10576, 1, 264, 420, 109), + (10579, 1, 264, 40, 3646), + (10580, 1, 264, 50, 3646), + (10588, 1, 264, 2, 601), + (10589, 1, 264, 4, 601), + (10590, 1, 264, 6, 601), + (10591, 1, 264, 8, 601), + (10592, 1, 264, 10, 601), + (10604, 1, 213, 13, 0), + (10605, 1, 213, 15, 0), + (10606, 1, 213, 17, 0), + (10607, 1, 215, 12, 0), + (10608, 1, 215, 14, 0), + (10609, 1, 215, 16, 0), + (10610, 1, 129, 25, 25), + (10610, 2, 385, 100265, 0), + (10611, 1, 129, 25, 25), + (10611, 2, 385, 100265, 0), + (10612, 1, 129, 25, 25), + (10612, 2, 385, 100265, 0), + (10621, 1, 264, 960, 180), + (10622, 1, 264, 1200, 180), + (10623, 1, 279, 19, 0), + (10624, 1, 279, 24, 0), + (10625, 1, 279, 30, 0), + (10627, 1, 224, 20, 74), + (10627, 2, 173, 1, 0), + (10628, 1, 224, 35, 74), + (10628, 2, 173, 2, 0), + (10629, 1, 224, 50, 74), + (10629, 2, 173, 3, 0), + (10632, 1, 265, 82, 0), + (10633, 1, 265, 83, 0), + (10634, 1, 265, 84, 0), + (10635, 1, 265, 85, 0), + (10636, 1, 265, 86, 0), + (10637, 1, 320, 12, 0), + (10638, 1, 320, 13, 0), + (10639, 1, 320, 14, 0), + (10641, 2, 385, 11064, 0), + (10643, 1, 124, 200, 200), + (10643, 2, 385, 19, 0), + (10643, 3, 144, 0, 0), + (10643, 4, 403, 3, 0), + (10643, 5, 404, 48, 0), + (10643, 6, 385, -21768, 0), + (10644, 1, 124, 250, 250), + (10644, 2, 385, 19, 0), + (10644, 3, 144, 0, 0), + (10644, 4, 403, 3, 0), + (10644, 5, 404, 48, 0), + (10644, 6, 385, -21768, 0), + (10645, 1, 124, 300, 300), + (10645, 2, 385, 19, 0), + (10645, 3, 144, 0, 0), + (10645, 4, 403, 3, 0), + (10645, 5, 404, 48, 0), + (10645, 6, 385, -21768, 0), + (10650, 1, 378, 1, 3), + (10651, 1, 378, 2, 3), + (10652, 1, 378, 3, 3), + (10653, 1, 310, 120000, 0), + (10653, 2, 139, 4502, 0), + (10653, 3, 139, 4509, 0), + (10654, 1, 310, 240000, 0), + (10654, 2, 139, 4502, 0), + (10654, 3, 139, 4509, 0), + (10655, 1, 310, 360000, 0), + (10655, 2, 139, 4502, 0), + (10655, 3, 139, 4509, 0), + (10656, 1, 287, 1, 0), + (10656, 2, 385, 15002, 0), + (10656, 3, 385, 15003, 0), + (10656, 4, 411, 128, 0), + (10657, 1, 264, 300, 276), + (10658, 1, 264, 600, 276), + (10659, 1, 264, 900, 276), + (10660, 1, 220, 175, 26), + (10660, 2, 220, 175, 30), + (10660, 3, 220, 175, 38), + (10661, 1, 220, 200, 26), + (10661, 2, 220, 200, 30), + (10661, 3, 220, 200, 38), + (10662, 1, 220, 225, 26), + (10662, 2, 220, 225, 30), + (10662, 3, 220, 225, 38), + (10663, 1, 220, 165, 21), + (10663, 2, 220, 165, 23), + (10663, 3, 220, 330, 52), + (10663, 4, 220, 165, 28), + (10664, 1, 220, 175, 21), + (10664, 2, 220, 175, 23), + (10664, 3, 220, 350, 52), + (10664, 4, 220, 175, 28), + (10665, 1, 220, 185, 21), + (10665, 2, 220, 185, 23), + (10665, 3, 220, 370, 52), + (10665, 4, 220, 185, 28), + (10666, 1, 264, 1200, 98), + (10667, 1, 264, 1320, 98), + (10668, 1, 264, 1440, 98), + (10671, 1, 310, 720000, 0), + (10671, 2, 139, 4590, 0), + (10672, 1, 310, 840000, 0), + (10672, 2, 139, 4590, 0), + (10673, 1, 310, 960000, 0), + (10673, 2, 139, 4590, 0), + (10674, 1, 310, 1080000, 0), + (10674, 2, 139, 4590, 0), + (10675, 1, 310, 1200000, 0), + (10675, 2, 139, 4590, 0), + (10676, 1, 339, 20, 23623), + (10676, 2, 137, 21, 0), + (10676, 3, 385, -18000, 0), + (10676, 4, 339, 20, 23623), + (10676, 5, 137, 343, 0), + (10676, 6, 385, -18000, 0), + (10677, 1, 339, 20, 23624), + (10677, 2, 137, 21, 0), + (10677, 3, 385, -18000, 0), + (10677, 4, 339, 20, 23624), + (10677, 5, 137, 343, 0), + (10677, 6, 385, -18000, 0), + (10678, 1, 339, 20, 23625), + (10678, 2, 137, 21, 0), + (10678, 3, 385, -18000, 0), + (10678, 4, 339, 20, 23625), + (10678, 5, 137, 343, 0), + (10678, 6, 385, -18000, 0), + (10685, 1, 266, 34, 0), + (10686, 1, 266, 39, 0), + (10687, 1, 266, 45, 0), + (10688, 1, 220, 125, 10), + (10689, 1, 220, 145, 10), + (10690, 1, 220, 165, 10), + (10691, 1, 220, 190, 10), + (10692, 1, 220, 220, 10), + (10705, 1, 85, 23542, 0), + (10706, 1, 85, 23543, 0), + (10707, 1, 85, 23544, 0), + (10714, 1, 264, 90, 873), + (10715, 1, 264, 180, 873), + (10717, 1, 264, 360, 184), + (10718, 1, 264, 450, 184), + (10719, 1, 264, 120, 872), + (10720, 1, 264, 240, 872), + (10721, 1, 264, 360, 872), + (10722, 1, 264, 120, 778), + (10723, 1, 264, 240, 778), + (10724, 1, 264, 360, 778), + (10725, 1, 264, 480, 778), + (10726, 1, 264, 600, 778), + (10727, 1, 264, 120, 2235), + (10728, 1, 264, 240, 2235), + (10730, 1, 264, 10, 870), + (10731, 1, 264, 20, 870), + (10733, 1, 264, 1, 219), + (10734, 1, 264, 2, 219), + (10735, 1, 264, 3, 219), + (10743, 1, 220, 135, 7), + (10744, 1, 220, 170, 7), + (10745, 1, 220, 205, 7), + (10748, 1, 59, -35, 0), + (10749, 1, 59, -42, 0), + (10750, 1, 264, 3024, 286), + (10750, 2, 264, 3024, 10753), + (10750, 3, 264, 3024, 9101), + (10751, 1, 264, 3456, 286), + (10751, 2, 264, 3456, 10753), + (10751, 3, 264, 3456, 9101), + (10755, 1, 59, -50, 0), + (10763, 1, 292, 50, 0), + (10764, 1, 292, 60, 0), + (10766, 1, 330, 70, 7), + (10767, 1, 330, 75, 7), + (10768, 1, 330, 80, 7), + (10769, 1, 310, 1440000, 0), + (10769, 2, 139, 4519, 0), + (10770, 1, 310, 1680000, 0), + (10770, 2, 139, 4519, 0), + (10778, 1, 274, 38, 0), + (10779, 1, 274, 40, 0), + (10780, 1, 274, 42, 0), + (10781, 1, 1, 186, 0), + (10782, 1, 1, 217, 0), + (10783, 1, 1, 248, 0), + (10784, 1, 1, 279, 0), + (10785, 1, 1, 310, 0), + (10788, 1, 363, 4, 0), + (10792, 1, 287, 1, 0), + (10792, 2, 385, 5240, 0), + (10792, 3, 385, 5340, 0), + (10792, 4, 385, 5440, 0), + (10792, 5, 385, 5540, 0), + (10792, 6, 385, 5640, 0), + (10793, 1, 287, 2, 0), + (10793, 2, 385, 5240, 0), + (10793, 3, 385, 5340, 0), + (10793, 4, 385, 5440, 0), + (10793, 5, 385, 5540, 0), + (10793, 6, 385, 5640, 0), + (10794, 1, 287, 3, 0), + (10794, 2, 385, 5240, 0), + (10794, 3, 385, 5340, 0), + (10794, 4, 385, 5440, 0), + (10794, 5, 385, 5540, 0), + (10794, 6, 385, 5640, 0), + (10795, 1, 287, 4, 0), + (10795, 2, 385, 5240, 0), + (10795, 3, 385, 5340, 0), + (10795, 4, 385, 5440, 0), + (10795, 5, 385, 5540, 0), + (10795, 6, 385, 5640, 0), + (10796, 1, 287, 5, 0), + (10796, 2, 385, 5240, 0), + (10796, 3, 385, 5340, 0), + (10796, 4, 385, 5440, 0), + (10796, 5, 385, 5540, 0), + (10796, 6, 385, 5640, 0), + (10800, 1, 264, 60, 462), + (10801, 1, 264, 120, 462), + (10802, 1, 264, 180, 462), + (10803, 1, 293, 25, 0), + (10804, 1, 293, 50, 0), + (10805, 1, 293, 75, 0), + (10815, 1, 185, 2, 1), + (10815, 2, 185, 2, 3), + (10816, 1, 185, 4, 1), + (10816, 2, 185, 4, 3), + (10817, 1, 185, 6, 1), + (10817, 2, 185, 6, 3), + (10818, 1, 185, 1, 36), + (10819, 1, 185, 3, 36), + (10820, 1, 185, 5, 36), + (10821, 1, 185, 2, 0), + (10821, 2, 185, 2, 2), + (10822, 1, 185, 4, 0), + (10822, 2, 185, 4, 2), + (10823, 1, 185, 6, 0), + (10823, 2, 185, 6, 2), + (10850, 1, 288, 100, 8), + (10851, 1, 288, 100, 8), + (10852, 1, 288, 100, 8), + (10853, 1, 292, 5, 0), + (10854, 1, 292, 10, 0), + (10855, 1, 292, 15, 0), + (10856, 1, 292, 20, 0), + (10857, 1, 292, 25, 0), + (10858, 1, 292, 30, 0), + (10859, 1, 292, 35, 0), + (10860, 1, 292, 40, 0), + (10861, 1, 292, 45, 0), + (10862, 1, 292, 46, 0), + (10863, 1, 292, 47, 0), + (10864, 1, 292, 48, 0), + (10865, 1, 216, 500, 8), + (10866, 1, 216, 550, 8), + (10867, 1, 216, 650, 8), + (10903, 1, 281, 25, 0), + (10904, 1, 281, 50, 0), + (10905, 1, 281, 75, 0), + (10906, 1, 59, -48, 0), + (10907, 1, 59, -51, 0), + (10908, 1, 59, -54, 0), + (10909, 1, 264, 60, 7007), + (10910, 1, 264, 120, 7007), + (10911, 1, 264, 180, 7007), + (10915, 1, 339, 10, 16876), + (10915, 2, 138, 0, 0), + (10915, 3, 142, 70, 0), + (10915, 4, 411, 32, 0), + (10915, 5, 348, 1, 0), + (10915, 6, 141, 1, 0), + (10916, 1, 339, 10, 16877), + (10916, 2, 138, 0, 0), + (10916, 3, 142, 70, 0), + (10916, 4, 411, 32, 0), + (10916, 5, 348, 1, 0), + (10916, 6, 141, 1, 0), + (10917, 1, 339, 10, 16878), + (10917, 2, 138, 0, 0), + (10917, 3, 142, 70, 0), + (10917, 4, 411, 32, 0), + (10917, 5, 348, 1, 0), + (10917, 6, 141, 1, 0), + (10950, 1, 287, 1, 0), + (10950, 2, 403, 4, 0), + (10950, 3, 404, 38, 0), + (10950, 4, 348, 1, 0), + (10950, 5, 137, 11, 0), + (10950, 6, 140, 2, 0), + (10951, 1, 264, 60, 447), + (10952, 1, 264, 120, 447), + (10953, 1, 264, 180, 447), + (10954, 1, 264, 60, 662), + (10955, 1, 264, 120, 662), + (10956, 1, 264, 180, 662), + (11000, 1, 227, 1, 73), + (11001, 1, 227, 2, 73), + (11002, 1, 227, 3, 73), + (11003, 1, 287, 1, 0), + (11003, 2, 137, 158, 0), + (11003, 3, 411, 2, 0), + (11004, 1, 287, 1, 0), + (11004, 2, 139, 8000, 0), + (11005, 1, 287, 2, 0), + (11005, 2, 139, 8000, 0), + (11006, 1, 287, 3, 0), + (11006, 2, 139, 8000, 0), + (11011, 1, 264, 480, 3710), + (11012, 1, 264, 600, 3710), + (11013, 1, 264, 720, 3710), + (11014, 1, 264, 10, 3899), + (11014, 2, 264, 10, 611), + (11014, 3, 264, 10, 960), + (11014, 4, 264, 10, 1252), + (11015, 1, 264, 20, 3899), + (11015, 2, 264, 20, 611), + (11015, 3, 264, 20, 960), + (11015, 4, 264, 20, 1252), + (11016, 1, 264, 30, 3899), + (11016, 2, 264, 30, 611), + (11016, 3, 264, 30, 960), + (11016, 4, 264, 30, 1252), + (11020, 1, 264, 40, 3899), + (11020, 2, 264, 40, 611), + (11020, 3, 264, 40, 960), + (11020, 4, 264, 40, 1252), + (11050, 1, 264, 360, 452), + (11050, 2, 264, 360, 6106), + (11050, 3, 264, 360, 493), + (11051, 1, 264, 720, 452), + (11051, 2, 264, 720, 6106), + (11051, 3, 264, 720, 493), + (11052, 1, 264, 1080, 452), + (11052, 2, 264, 1080, 6106), + (11052, 3, 264, 1080, 493), + (11053, 1, 264, 1260, 500), + (11054, 1, 264, 1440, 500), + (11059, 1, 264, 1440, 452), + (11059, 2, 264, 1440, 6106), + (11059, 3, 264, 1440, 493), + (11060, 1, 264, 1800, 452), + (11060, 2, 264, 1800, 6106), + (11060, 3, 264, 1800, 493), + (11061, 1, 114, -63, 0), + (11062, 1, 114, -64, 0), + (11063, 1, 114, -65, 0), + (11074, 1, 247, 100, 39), + (11075, 1, 247, 150, 39), + (11076, 1, 247, 200, 39), + (11077, 1, 264, 10, 986), + (11078, 1, 264, 10, 988), + (11079, 1, 264, 10, 987), + (11082, 1, 185, 40, 51), + (11083, 1, 185, 50, 51), + (11084, 1, 185, 60, 51), + (11085, 1, 247, 20, 2), + (11085, 2, 247, 20, 3), + (11085, 3, 247, 20, 77), + (11085, 4, 220, 25, 77), + (11085, 5, 220, 25, 2), + (11085, 6, 220, 25, 3), + (11086, 1, 247, 40, 2), + (11086, 2, 247, 40, 3), + (11086, 3, 247, 40, 77), + (11086, 4, 220, 35, 77), + (11086, 5, 220, 35, 2), + (11086, 6, 220, 35, 3), + (11087, 1, 247, 60, 2), + (11087, 2, 247, 60, 3), + (11087, 3, 247, 60, 77), + (11087, 4, 220, 50, 77), + (11087, 5, 220, 50, 2), + (11087, 6, 220, 50, 3), + (11088, 1, 264, 180, 505), + (11089, 1, 264, 360, 505), + (11090, 1, 264, 540, 505), + (11091, 1, 264, 720, 505), + (12396, 1, 172, 50, 0), + (12397, 1, 172, 51, 0), + (12398, 1, 172, 52, 0), + (12399, 1, 172, 53, 0), + (12400, 1, 172, 54, 0), + (12401, 1, 259, 56, 0), + (12402, 1, 259, 57, 0), + (12403, 1, 259, 58, 0), + (12404, 1, 259, 59, 0), + (12405, 1, 259, 60, 0), + (12406, 1, 69, 1100, 0), + (12407, 1, 69, 1200, 0), + (12408, 1, 69, 1300, 0), + (12409, 1, 69, 1400, 0), + (12410, 1, 69, 1500, 0), + (12411, 1, 1, 300, 0), + (12412, 1, 1, 350, 0), + (12413, 1, 1, 400, 0), + (12414, 1, 1, 450, 0), + (12415, 1, 1, 500, 0), + (12416, 1, 399, 3, 0), + (12416, 2, 141, 1, 0), + (12416, 3, 138, 0, 0), + (12416, 4, 142, 255, 0), + (12416, 5, 391, 0, 0), + (12416, 6, 311, 0, 0), + (12416, 7, 137, -152, 0), + (12416, 8, 411, 100350, 0), + (12416, 9, 137, -39, 0), + (12417, 1, 399, 6, 0), + (12417, 2, 141, 1, 0), + (12417, 3, 138, 0, 0), + (12417, 4, 142, 255, 0), + (12417, 5, 391, 0, 0), + (12417, 6, 311, 0, 0), + (12417, 7, 137, -152, 0), + (12417, 8, 411, 100350, 0), + (12417, 9, 137, -39, 0), + (12418, 1, 399, 9, 0), + (12418, 2, 141, 1, 0), + (12418, 3, 138, 0, 0), + (12418, 4, 142, 255, 0), + (12418, 5, 391, 0, 0), + (12418, 6, 311, 0, 0), + (12418, 7, 137, -152, 0), + (12418, 8, 411, 100350, 0), + (12418, 9, 137, -39, 0), + (12419, 1, 292, 15, 0), + (12420, 1, 292, 30, 0), + (12421, 1, 292, 45, 0), + (12423, 1, 273, 21, 0), + (12424, 1, 273, 24, 0), + (12425, 1, 273, 27, 0), + (12426, 1, 273, 21, 0), + (12427, 1, 273, 24, 0), + (12428, 1, 273, 27, 0), + (12432, 1, 294, 17, 100), + (12433, 1, 294, 19, 100), + (12434, 1, 294, 21, 100), + (12435, 1, 294, 23, 100), + (12436, 1, 294, 25, 100), + (12437, 1, 294, 27, 100), + (12438, 1, 200, 70, 0), + (12439, 1, 341, 210, 0), + (12440, 1, 341, 220, 0), + (12441, 1, 341, 230, 0), + (12442, 1, 341, 240, 0), + (12443, 1, 341, 250, 0), + (12444, 1, 318, 21, 0), + (12445, 1, 318, 22, 0), + (12446, 1, 318, 23, 0), + (12447, 1, 318, 24, 0), + (12448, 1, 318, 25, 0), + (12449, 1, 125, 31, 31), + (12449, 2, 137, 0, 0), + (12449, 3, 141, 1, 0), + (12449, 4, 139, -6233, 0), + (12449, 5, 139, -6265, 0), + (12449, 6, 125, 31, 31), + (12449, 7, 137, 147, 0), + (12449, 8, 141, 1, 0), + (12450, 1, 125, 34, 34), + (12450, 2, 137, 0, 0), + (12450, 3, 141, 1, 0), + (12450, 4, 139, -6233, 0), + (12450, 5, 139, -6265, 0), + (12450, 6, 125, 34, 34), + (12450, 7, 137, 147, 0), + (12450, 8, 141, 1, 0), + (12451, 1, 125, 37, 37), + (12451, 2, 137, 0, 0), + (12451, 3, 141, 1, 0), + (12451, 4, 139, -6233, 0), + (12451, 5, 139, -6265, 0), + (12451, 6, 125, 37, 37), + (12451, 7, 137, 147, 0), + (12451, 8, 141, 1, 0), + (12452, 1, 274, 38, 0), + (12453, 1, 274, 39, 0), + (12454, 1, 274, 40, 0), + (12455, 1, 15, 19, 0), + (12456, 1, 15, 20, 0), + (12457, 1, 15, 21, 0), + (12458, 1, 15, 22, 0), + (12459, 1, 15, 23, 0), + (12463, 1, 320, 9, 0), + (12464, 1, 320, 10, 0), + (12465, 1, 320, 11, 0), + (12466, 1, 320, 9, 0), + (12467, 1, 320, 10, 0), + (12468, 1, 320, 11, 0), + (12469, 1, 320, 9, 0), + (12470, 1, 320, 10, 0), + (12471, 1, 320, 11, 0), + (12472, 1, 320, 6, 0), + (12473, 1, 320, 7, 0), + (12474, 1, 320, 8, 0), + (12475, 1, 264, 180, 7003), + (12476, 1, 264, 360, 7003), + (12477, 1, 264, 540, 7003), + (12478, 1, 264, 60, 3705), + (12479, 1, 264, 120, 3705), + (12480, 1, 264, 180, 3705), + (12481, 1, 247, 40, 76), + (12482, 1, 247, 45, 76), + (12483, 1, 247, 65, 76), + (12484, 1, 247, 70, 76), + (12485, 1, 247, 30, 76), + (12486, 1, 247, 35, 76), + (12487, 1, 247, 25, 76), + (12488, 1, 247, 30, 76), + (12492, 1, 69, 1600, 0), + (12493, 1, 69, 1700, 0), + (12494, 1, 69, 1800, 0), + (12495, 1, 69, 1900, 0), + (12496, 1, 69, 2000, 0), + (12497, 1, 125, 40, 40), + (12497, 2, 137, 0, 0), + (12497, 3, 141, 1, 0), + (12497, 4, 139, -6233, 0), + (12497, 5, 139, -6265, 0), + (12497, 6, 125, 40, 40), + (12497, 7, 137, 147, 0), + (12497, 8, 141, 1, 0), + (12498, 1, 125, 43, 43), + (12498, 2, 137, 0, 0), + (12498, 3, 141, 1, 0), + (12498, 4, 139, -6233, 0), + (12498, 5, 139, -6265, 0), + (12498, 6, 125, 43, 43), + (12498, 7, 137, 147, 0), + (12498, 8, 141, 1, 0), + (12499, 1, 125, 46, 46), + (12499, 2, 137, 0, 0), + (12499, 3, 141, 1, 0), + (12499, 4, 139, -6233, 0), + (12499, 5, 139, -6265, 0), + (12499, 6, 125, 46, 46), + (12499, 7, 137, 147, 0), + (12499, 8, 141, 1, 0), + (12500, 1, 310, 1000, 0), + (12500, 2, 385, 4004, 0), + (12500, 3, 385, 11202, 0), + (12500, 4, 385, 11302, 0), + (12500, 5, 385, 11402, 0), + (12500, 6, 385, 11502, 0), + (12500, 7, 385, 11602, 0), + (12501, 1, 310, 2000, 0), + (12501, 2, 385, 4004, 0), + (12501, 3, 385, 11202, 0), + (12501, 4, 385, 11302, 0), + (12501, 5, 385, 11402, 0), + (12501, 6, 385, 11502, 0), + (12501, 7, 385, 11602, 0), + (12502, 1, 310, 3000, 0), + (12502, 2, 385, 4004, 0), + (12502, 3, 385, 11202, 0), + (12502, 4, 385, 11302, 0), + (12502, 5, 385, 11402, 0), + (12502, 6, 385, 11502, 0), + (12502, 7, 385, 11602, 0), + (12505, 1, 310, 4000, 0), + (12505, 2, 385, 4004, 0), + (12505, 3, 385, 11202, 0), + (12505, 4, 385, 11302, 0), + (12505, 5, 385, 11402, 0), + (12505, 6, 385, 11502, 0), + (12505, 7, 385, 11602, 0), + (12506, 1, 310, 5000, 0), + (12506, 2, 385, 4004, 0), + (12506, 3, 385, 11202, 0), + (12506, 4, 385, 11302, 0), + (12506, 5, 385, 11402, 0), + (12506, 6, 385, 11502, 0), + (12506, 7, 385, 11602, 0), + (12507, 1, 301, 120, 0), + (12508, 1, 247, 50, 76), + (12509, 1, 247, 55, 76), + (12510, 1, 247, 60, 76), + (12511, 1, 247, 75, 76), + (12512, 1, 247, 80, 76), + (12513, 1, 247, 85, 76), + (12514, 1, 247, 40, 76), + (12515, 1, 247, 45, 76), + (12516, 1, 247, 50, 76), + (12517, 1, 247, 35, 76), + (12518, 1, 247, 40, 76), + (12519, 1, 247, 45, 76), + (12523, 1, 294, 0, 200), + (12526, 1, 294, 0, 190), + (12527, 1, 294, 0, 195), + (12528, 1, 294, 0, 200), + (12529, 1, 294, 0, 165), + (12530, 1, 294, 0, 175), + (12531, 1, 294, 0, 185), + (12532, 1, 341, 260, 0), + (12533, 1, 341, 270, 0), + (12534, 1, 341, 280, 0), + (12535, 1, 341, 290, 0), + (12536, 1, 341, 300, 0), + (12537, 1, 318, 26, 0), + (12538, 1, 318, 27, 0), + (12539, 1, 318, 28, 0), + (12540, 1, 318, 29, 0), + (12541, 1, 318, 30, 0), + (12548, 1, 278, 900, 79230), + (12548, 2, 440, 87, 100), + (12549, 1, 278, 900, 86260), + (12549, 2, 440, 88, 100), + (12550, 1, 278, 900, 88260), + (12550, 2, 440, 89, 100), + (12551, 1, 278, 900, 91510), + (12551, 2, 440, 90, 100), + (12552, 1, 278, 900, 96305), + (12552, 2, 440, 91, 100), + (12553, 1, 294, 29, 102), + (12554, 1, 294, 31, 104), + (12555, 1, 294, 33, 106), + (12556, 1, 294, 23, 100), + (12557, 1, 294, 25, 100), + (12558, 1, 294, 27, 100), + (12559, 1, 190, 300, 0), + (12560, 1, 190, 350, 0), + (12561, 1, 190, 400, 0), + (12562, 1, 190, 450, 0), + (12563, 1, 190, 500, 0), + (12564, 1, 319, 28, 0), + (12565, 1, 319, 29, 0), + (12566, 1, 319, 30, 0), + (12567, 1, 274, 41, 0), + (12568, 1, 274, 42, 0), + (12569, 1, 274, 43, 0), + (12570, 1, 15, 24, 0), + (12571, 1, 15, 25, 0), + (12572, 1, 15, 26, 0), + (12573, 1, 15, 27, 0), + (12574, 1, 15, 28, 0), + (12575, 1, 292, 60, 0), + (12576, 1, 231, 17, 0), + (12577, 1, 231, 19, 0), + (12578, 1, 231, 21, 0), + (12579, 1, 85, 23569, 0), + (12580, 1, 85, 23570, 0), + (12581, 1, 85, 23571, 0), + (12582, 1, 264, 10, 9400), + (12583, 1, 264, 20, 9400), + (12584, 1, 264, 30, 9400), + (12587, 1, 264, 480, 9403), + (12588, 1, 264, 600, 9403), + (12589, 1, 264, 720, 9403), + (12591, 1, 247, 90, 76), + (12594, 1, 247, 55, 76), + (12597, 1, 247, 50, 76), + (12598, 1, 247, 55, 76), + (12600, 1, 310, 60000, 0), + (12600, 2, 139, 6197, 0), + (12600, 3, 411, 512, 0), + (12603, 1, 287, 1, 0), + (12603, 2, 139, 6197, 0), + (12603, 3, 411, 512, 0), + (12606, 1, 271, 5, 0), + (12607, 1, 310, 12000, 0), + (12607, 2, 385, 13007, 0), + (12607, 3, 385, 12105, 0), + (12607, 4, 385, 12205, 0), + (12607, 5, 310, 36000, 0), + (12607, 6, 385, 12305, 0), + (12607, 7, 385, 12405, 0), + (12607, 8, 385, 12505, 0), + (12607, 9, 411, 512, 0), + (12610, 1, 279, 19, 0), + (12612, 1, 439, 0, 124480), + (12612, 2, 345, 84, 25), + (12613, 1, 439, 0, 132440), + (12613, 2, 345, 86, 25), + (12615, 1, 310, 120000, 0), + (12615, 2, 139, 4695, 0), + (12615, 3, 411, 512, 0), + (12616, 1, 310, 240000, 0), + (12616, 2, 139, 4695, 0), + (12616, 3, 411, 512, 0), + (12617, 1, 310, 360000, 0), + (12617, 2, 139, 4695, 0), + (12617, 3, 411, 512, 0), + (12636, 1, 426, 1, 0), + (12637, 1, 426, 2, 0), + (12639, 1, 264, 240, 519), + (12639, 2, 264, 240, 10427), + (12642, 1, 264, 240, 185), + (12642, 2, 264, 240, 10426), + (12645, 1, 287, 1, 0), + (12645, 2, 385, 8190, 0), + (12645, 3, 287, 1, 0), + (12645, 4, 385, 21818, 0), + (12645, 5, 411, 64, 0), + (12646, 1, 287, 1, 0), + (12646, 2, 385, 3277, 0), + (12646, 3, 287, 1, 0), + (12646, 4, 385, 21816, 0), + (12652, 1, 399, 1, 0), + (12652, 2, 138, 1, 0), + (12652, 3, 137, 0, 0), + (12652, 4, 348, 10, 0), + (12652, 5, 311, 0, 0), + (12652, 6, 141, 1, 0), + (12652, 7, 134, 254, 0), + (12652, 8, 137, -39, 0), + (12653, 1, 399, 2, 0), + (12653, 2, 138, 1, 0), + (12653, 3, 137, 0, 0), + (12653, 4, 348, 10, 0), + (12653, 5, 311, 0, 0), + (12653, 6, 141, 1, 0), + (12653, 7, 134, 254, 0), + (12653, 8, 137, -39, 0), + (12654, 1, 399, 3, 0), + (12654, 2, 138, 1, 0), + (12654, 3, 137, 0, 0), + (12654, 4, 348, 10, 0), + (12654, 5, 311, 0, 0), + (12654, 6, 141, 1, 0), + (12654, 7, 134, 254, 0), + (12654, 8, 137, -39, 0), + (12664, 1, 264, 2, 3728), + (12667, 1, 220, 250, 26), + (12667, 2, 220, 250, 30), + (12667, 3, 220, 250, 38), + (12668, 1, 220, 275, 26), + (12668, 2, 220, 275, 30), + (12668, 3, 220, 275, 38), + (12669, 1, 220, 300, 26), + (12669, 2, 220, 300, 30), + (12669, 3, 220, 300, 38), + (12670, 1, 220, 200, 21), + (12670, 2, 220, 200, 23), + (12670, 3, 220, 400, 52), + (12670, 4, 220, 200, 28), + (12671, 1, 220, 215, 21), + (12671, 2, 220, 215, 23), + (12671, 3, 220, 450, 52), + (12671, 4, 220, 215, 28), + (12672, 1, 220, 235, 21), + (12672, 2, 220, 235, 23), + (12672, 3, 220, 510, 52), + (12672, 4, 220, 235, 28), + (12673, 1, 264, 960, 420), + (12674, 1, 227, 270, 32), + (12675, 1, 227, 300, 32), + (12676, 1, 227, 330, 32), + (12677, 1, 275, 92, 0), + (12678, 1, 287, 2, 0), + (12678, 2, 385, 15002, 0), + (12678, 3, 385, 15003, 0), + (12678, 4, 411, 128, 0), + (12679, 1, 264, 1200, 276), + (12680, 1, 264, 1500, 276), + (12681, 1, 264, 1800, 276), + (12685, 1, 292, 49, 0), + (12686, 1, 292, 50, 0), + (12687, 1, 292, 51, 0), + (12688, 1, 287, 1, 0), + (12688, 2, 385, 8473, 0), + (12688, 3, 385, 8318, 0), + (12688, 4, 385, 8418, 0), + (12688, 5, 385, 8518, 0), + (12688, 6, 411, 128, 0), + (12689, 1, 287, 2, 0), + (12689, 2, 139, 4691, 0), + (12689, 3, 411, 128, 0), + (12690, 1, 287, 2, 0), + (12690, 2, 385, 8111, 0), + (12690, 3, 385, 15008, 0), + (12690, 4, 385, 8411, 0), + (12690, 5, 385, 8511, 0), + (12690, 6, 411, 128, 0), + (12691, 1, 287, 1, 0), + (12691, 2, 385, 15007, 0), + (12691, 3, 411, 128, 0), + (12691, 4, 385, 8316, 0), + (12692, 1, 220, 255, 21), + (12692, 2, 220, 255, 23), + (12692, 3, 220, 570, 52), + (12692, 4, 220, 255, 28), + (12693, 1, 220, 275, 21), + (12693, 2, 220, 275, 23), + (12693, 3, 220, 630, 52), + (12693, 4, 220, 275, 28), + (12694, 1, 189, 16, 0), + (12695, 1, 189, 17, 0), + (12696, 1, 189, 18, 0), + (12697, 1, 330, 140, 0), + (12697, 2, 330, 140, 1), + (12697, 3, 330, 140, 2), + (12697, 4, 330, 140, 3), + (12697, 5, 330, 140, 28), + (12697, 6, 330, 140, 36), + (12697, 7, 330, 140, 77), + (12698, 1, 330, 145, 0), + (12698, 2, 330, 145, 1), + (12698, 3, 330, 145, 2), + (12698, 4, 330, 145, 3), + (12698, 5, 330, 145, 28), + (12698, 6, 330, 145, 36), + (12698, 7, 330, 145, 77), + (12699, 1, 330, 150, 0), + (12699, 2, 330, 150, 1), + (12699, 3, 330, 150, 2), + (12699, 4, 330, 150, 3), + (12699, 5, 330, 150, 28), + (12699, 6, 330, 150, 36), + (12699, 7, 330, 150, 77), + (12703, 1, 283, 240, 0), + (12704, 1, 283, 260, 0), + (12705, 1, 283, 280, 0), + (12706, 1, 220, 60, 28), + (12706, 2, 220, 60, 0), + (12706, 3, 427, 23598, 3), + (12706, 4, 428, 28, 0), + (12706, 5, 428, 0, 0), + (12707, 1, 220, 85, 28), + (12707, 2, 220, 85, 0), + (12707, 3, 427, 23598, 5), + (12707, 4, 428, 28, 0), + (12707, 5, 428, 0, 0), + (12708, 1, 220, 115, 28), + (12708, 2, 220, 115, 0), + (12708, 3, 427, 23598, 7), + (12708, 4, 428, 28, 0), + (12708, 5, 428, 0, 0), + (12709, 1, 287, 1, 0), + (12709, 2, 139, 4516, 0), + (12709, 3, 411, 256, 0), + (12710, 1, 310, 360000, 0), + (12710, 2, 139, 4516, 0), + (12710, 3, 411, 256, 0), + (12711, 1, 310, 720000, 0), + (12711, 2, 139, 4516, 0), + (12711, 3, 411, 256, 0), + (12712, 1, 310, 1080000, 0), + (12712, 2, 139, 4516, 0), + (12712, 3, 411, 256, 0), + (12713, 1, 264, 2, 8202), + (12714, 1, 264, 4, 8202), + (12715, 1, 264, 6, 8202), + (12716, 1, 264, 30, 3702), + (12717, 1, 264, 60, 3702), + (12718, 1, 264, 90, 3702), + (12719, 1, 128, 10, 0), + (12719, 2, 385, 12769, 0), + (12719, 3, 411, 256, 0), + (12720, 1, 287, 1, 0), + (12720, 2, 139, 12519, 0), + (12720, 3, 411, 256, 0), + (12721, 1, 264, 60, 3506), + (12722, 1, 264, 120, 3506), + (12723, 1, 264, 180, 3506), + (12727, 1, 264, 960, 359), + (12728, 1, 264, 1200, 359), + (12729, 1, 264, 1440, 359), + (12733, 1, 287, 2, 0), + (12733, 2, 137, 22, 0), + (12733, 3, 411, 256, 0), + (12734, 1, 375, 145, 0), + (12735, 1, 375, 150, 0), + (12736, 1, 375, 155, 0), + (12737, 1, 129, 5, 0), + (12737, 2, 385, 12768, 0), + (12737, 3, 411, 256, 0), + (12738, 1, 129, 10, 0), + (12738, 2, 385, 12768, 0), + (12738, 3, 411, 256, 0), + (12739, 1, 129, 15, 0), + (12739, 2, 385, 12768, 0), + (12739, 3, 411, 256, 0), + (12757, 1, 264, 6000, 68), + (12758, 1, 264, 6600, 68), + (12759, 1, 264, 7200, 68), + (12767, 1, 229, 50, 0), + (12768, 1, 229, 55, 0), + (12769, 1, 229, 60, 0), + (12773, 1, 264, 60, 1580), + (12774, 1, 264, 120, 1580), + (12775, 1, 264, 180, 1580), + (12776, 1, 264, 240, 1580), + (12777, 1, 264, 300, 1580), + (12779, 1, 264, 0, 826), + (12780, 1, 264, 1, 826), + (12781, 1, 264, 1, 826), + (12782, 1, 129, 10, 0), + (12782, 2, 385, 16106, 0), + (12783, 1, 129, 20, 0), + (12783, 2, 385, 16106, 0), + (12784, 1, 129, 30, 0), + (12784, 2, 385, 16106, 0), + (12792, 1, 397, 1000, 0), + (12793, 1, 397, 1200, 0), + (12794, 1, 397, 1250, 0), + (12795, 1, 213, 19, 0), + (12796, 1, 213, 21, 0), + (12797, 1, 213, 23, 0), + (12798, 1, 218, 21, 0), + (12799, 1, 218, 22, 0), + (12800, 1, 218, 23, 0), + (12801, 1, 215, 18, 0), + (12802, 1, 215, 20, 0), + (12803, 1, 215, 22, 0), + (12813, 1, 320, 2, 0), + (12814, 1, 320, 4, 0), + (12815, 1, 320, 6, 0), + (12816, 1, 128, 1, 0), + (12816, 2, 385, 2223, 0), + (12816, 3, 385, 2323, 0), + (12816, 4, 385, 2240, 0), + (12816, 5, 385, 2340, 0), + (12816, 6, 385, 2440, 0), + (12816, 7, 385, 2540, 0), + (12816, 8, 398, 6000, 0), + (12816, 9, 385, 11872, 0), + (12816, 10, 385, 14154, 0), + (12816, 11, 385, 18166, 0), + (12816, 12, 385, 27225, 0), + (12816, 13, 385, 2419, 0), + (12816, 14, 385, 2427, 0), + (12816, 15, 385, 30374, 0), + (12816, 16, 385, 2527, 0), + (12816, 17, 385, 36431, 0), + (12819, 1, 310, 23400, 0), + (12819, 2, 139, 4671, 0), + (12819, 3, 411, 32768, 0), + (12820, 1, 310, 46800, 0), + (12820, 2, 139, 4671, 0), + (12820, 3, 411, 32768, 0), + (12822, 1, 310, 153000, 0), + (12822, 2, 139, 8233, 0), + (12822, 3, 310, 120000, 0), + (12822, 4, 385, 2439, 0), + (12822, 5, 385, 2539, 0), + (12822, 6, 411, 32768, 0), + (12831, 1, 127, 17, 0), + (12831, 2, 385, 3291, 0), + (12831, 3, 385, 3817, 0), + (12831, 4, 411, 32768, 0), + (12834, 1, 264, 180, 128), + (12835, 1, 264, 225, 128), + (12840, 1, 264, 24, 3817), + (12841, 1, 264, 30, 3817), + (12843, 1, 225, 42, 0), + (12846, 1, 288, 20, 28), + (12846, 2, 288, 20, 0), + (12849, 1, 127, 14, 0), + (12849, 2, 385, 16794, 0), + (12849, 3, 411, 32768, 0), + (12860, 1, 294, 21, 102), + (12863, 1, 127, 15, 15), + (12863, 2, 137, 0, 0), + (12863, 3, 138, 0, 0), + (12863, 4, 141, 1, 0), + (12863, 5, 143, 3000, 0), + (12863, 6, 127, 15, 15), + (12863, 7, 385, 16555, 0), + (12863, 8, 385, 16655, 0), + (12871, 1, 264, 2160, 452), + (12871, 2, 264, 2160, 6106), + (12871, 3, 264, 2160, 493), + (12872, 1, 264, 2520, 452), + (12872, 2, 264, 2520, 6106), + (12872, 3, 264, 2520, 493), + (12874, 1, 264, 2572, 451), + (12876, 1, 264, 900, 7003), + (12877, 1, 264, 1260, 7003), + (12878, 1, 264, 1620, 7003), + (12881, 1, 264, 45, 172), + (12886, 1, 10, 0, 0), + (12887, 1, 10, 0, 0), + (12888, 1, 10, 0, 0), + (12889, 1, 10, 0, 0), + (12890, 1, 10, 0, 0), + (12894, 1, 264, 30, 1122), + (12899, 1, 264, 3456, 57), + (12899, 2, 264, 3456, 616), + (12900, 1, 264, 4320, 57), + (12900, 2, 264, 4320, 616), + (12902, 1, 264, 30, 1380), + (12903, 1, 264, 60, 1380), + (12907, 1, 264, 30, 1381), + (12908, 1, 264, 60, 1381), + (12912, 1, 264, 30, 1382), + (12913, 1, 264, 60, 1382), + (12920, 1, 130, 10, 10), + (12920, 2, 139, 2569, 0), + (12920, 3, 130, -10, -10), + (12920, 4, 139, 2568, 0), + (12929, 1, 287, 4, 0), + (12929, 2, 137, 3, 0), + (12929, 3, 137, 99, 0), + (12929, 4, 138, 0, 0), + (12929, 5, 244, 20, 0), + (12930, 1, 287, 5, 0), + (12930, 2, 137, 3, 0), + (12930, 3, 137, 99, 0), + (12930, 4, 138, 0, 0), + (12930, 5, 244, 15, 0), + (12945, 1, 280, 60, 0), + (12946, 1, 280, 61, 0), + (12947, 1, 280, 62, 0), + (12948, 1, 280, 63, 0), + (12949, 1, 280, 64, 0), + (12950, 1, 218, 21, 0), + (12951, 1, 218, 22, 0), + (12952, 1, 218, 23, 0), + (12953, 1, 218, 24, 0), + (12954, 1, 218, 25, 0), + (12966, 1, 131, 25, 25), + (12966, 2, 348, 10, 0), + (12966, 3, 137, -32, 0), + (12967, 1, 131, 50, 50), + (12967, 2, 348, 10, 0), + (12967, 3, 137, -32, 0), + (12968, 1, 264, 3, 1041), + (12969, 1, 264, 6, 1041), + (12970, 1, 264, 9, 1041), + (12977, 1, 287, 2, 0), + (12977, 2, 385, 16188, 0), + (12978, 1, 287, 4, 0), + (12978, 2, 385, 16188, 0), + (12979, 1, 287, 6, 0), + (12979, 2, 385, 16188, 0), + (12980, 1, 287, 8, 0), + (12980, 2, 385, 16188, 0), + (12981, 1, 287, 10, 0), + (12981, 2, 385, 16188, 0), + (12988, 1, 287, 3, 0), + (12988, 2, 140, 3, 0), + (12988, 3, 348, 1, 0), + (12988, 4, 138, 0, 0), + (12988, 5, 137, 0, 0), + (13001, 1, 264, 60, 9504), + (13002, 1, 264, 120, 9504), + (13003, 1, 264, 180, 9504), + (13005, 1, 264, 70, 171), + (13006, 1, 264, 80, 171), + (13007, 1, 264, 90, 171), + (13010, 1, 264, 10, 47), + (13011, 1, 264, 20, 47), + (13012, 1, 264, 30, 47), + (13013, 1, 264, 120, 446), + (13014, 1, 264, 240, 446), + (13015, 1, 264, 360, 446), + (13017, 1, 375, 15, 0), + (13018, 1, 375, 25, 0), + (13019, 1, 375, 35, 0), + (13021, 1, 247, 80, 2), + (13021, 2, 247, 80, 3), + (13021, 3, 247, 80, 77), + (13021, 4, 220, 75, 77), + (13021, 5, 220, 75, 2), + (13021, 6, 220, 75, 3), + (13023, 1, 330, 115, 0), + (13023, 2, 330, 115, 1), + (13023, 3, 330, 115, 2), + (13023, 4, 330, 115, 3), + (13023, 5, 330, 115, 28), + (13023, 6, 330, 115, 36), + (13023, 7, 330, 115, 77), + (13026, 1, 266, 26, 0), + (13027, 1, 266, 27, 0), + (13028, 1, 266, 28, 0), + (13029, 1, 288, 250, 51), + (13029, 2, 288, 60, 51), + (13032, 1, 185, 70, 51), + (13033, 1, 185, 80, 51), + (13035, 1, 220, 768, 74), + (13040, 1, 216, 280, 74), + (13043, 1, 169, 35, -1), + (13046, 1, 1, 240, 0), + (13047, 1, 1, 280, 0), + (13048, 1, 1, 320, 0), + (13049, 1, 1, 360, 0), + (13050, 1, 1, 400, 0), + (13051, 1, 287, 2, 0), + (13051, 2, 139, 8003, 0), + (13052, 1, 310, 120000, 0), + (13052, 2, 385, 3107, 0), + (13052, 3, 385, 3207, 0), + (13052, 4, 385, 3307, 0), + (13052, 5, 385, 3407, 0), + (13052, 6, 385, 3507, 0), + (13052, 7, 385, 3607, 0), + (13055, 1, 264, 60, 8400), + (13067, 1, 264, 120, 643), + (13072, 1, 310, 120000, 0), + (13072, 2, 139, 6197, 0), + (13072, 3, 411, 512, 0), + (13073, 1, 310, 180000, 0), + (13073, 2, 139, 6197, 0), + (13073, 3, 411, 512, 0), + (13074, 1, 330, 140, 0), + (13074, 2, 330, 140, 1), + (13074, 3, 330, 140, 2), + (13074, 4, 330, 140, 3), + (13074, 5, 330, 140, 28), + (13074, 6, 330, 140, 36), + (13075, 1, 330, 145, 0), + (13075, 2, 330, 145, 1), + (13075, 3, 330, 145, 2), + (13075, 4, 330, 145, 3), + (13075, 5, 330, 145, 28), + (13075, 6, 330, 145, 36), + (13076, 1, 330, 150, 0), + (13076, 2, 330, 150, 1), + (13076, 3, 330, 150, 2), + (13076, 4, 330, 150, 3), + (13076, 5, 330, 150, 28), + (13076, 6, 330, 150, 36), + (13077, 1, 330, 140, 0), + (13077, 2, 330, 140, 1), + (13077, 3, 330, 140, 2), + (13077, 4, 330, 140, 3), + (13077, 5, 330, 140, 28), + (13077, 6, 330, 140, 36), + (13077, 7, 330, 140, 77), + (13078, 1, 330, 145, 0), + (13078, 2, 330, 145, 1), + (13078, 3, 330, 145, 2), + (13078, 4, 330, 145, 3), + (13078, 5, 330, 145, 28), + (13078, 6, 330, 145, 36), + (13078, 7, 330, 145, 77), + (13080, 1, 172, 55, 0), + (13081, 1, 172, 56, 0), + (13082, 1, 172, 57, 0), + (13083, 1, 172, 58, 0), + (13084, 1, 172, 59, 0), + (13085, 1, 259, 61, 0), + (13086, 1, 259, 62, 0), + (13087, 1, 259, 63, 0), + (13088, 1, 259, 64, 0), + (13089, 1, 259, 65, 0), + (13090, 1, 339, 10, 8105), + (13090, 2, 142, 65, 0), + (13090, 3, 311, 0, 0), + (13090, 4, 134, 70, 0), + (13090, 5, 348, 10, 0), + (13090, 6, 137, 0, 0), + (13090, 7, 339, 10, 8105), + (13090, 8, 142, 65, 0), + (13090, 9, 311, 0, 0), + (13090, 10, 134, 70, 0), + (13090, 11, 348, 10, 0), + (13090, 12, 137, 100, 0), + (13090, 13, 339, 10, 8105), + (13090, 14, 142, 65, 0), + (13090, 15, 311, 0, 0), + (13090, 16, 134, 70, 0), + (13090, 17, 348, 10, 0), + (13090, 18, 137, 79, 0), + (13090, 19, 339, 10, 8105), + (13090, 20, 142, 65, 0), + (13090, 21, 311, 0, 0), + (13090, 22, 134, 70, 0), + (13090, 23, 348, 10, 0), + (13090, 24, 137, 147, 0), + (13090, 25, 339, 10, 11404), + (13090, 26, 142, 71, 0), + (13090, 27, 311, 0, 0), + (13090, 28, 134, 75, 0), + (13090, 29, 348, 10, 0), + (13090, 30, 137, 0, 0), + (13090, 31, 339, 10, 11404), + (13090, 32, 142, 71, 0), + (13090, 33, 311, 0, 0), + (13090, 34, 134, 75, 0), + (13090, 35, 348, 10, 0), + (13090, 36, 137, 100, 0), + (13090, 37, 339, 10, 11404), + (13090, 38, 142, 71, 0), + (13090, 39, 311, 0, 0), + (13090, 40, 134, 75, 0), + (13090, 41, 348, 10, 0), + (13090, 42, 137, 79, 0), + (13090, 43, 339, 10, 11404), + (13090, 44, 142, 71, 0), + (13090, 45, 311, 0, 0), + (13090, 46, 134, 75, 0), + (13090, 47, 348, 10, 0), + (13090, 48, 137, 147, 0), + (13090, 49, 339, 10, 13199), + (13090, 50, 142, 76, 0), + (13090, 51, 311, 0, 0), + (13090, 52, 134, 80, 0), + (13090, 53, 348, 10, 0), + (13090, 54, 137, 0, 0), + (13090, 55, 339, 10, 13199), + (13090, 56, 142, 76, 0), + (13090, 57, 311, 0, 0), + (13090, 58, 134, 80, 0), + (13090, 59, 348, 10, 0), + (13090, 60, 137, 100, 0), + (13090, 61, 339, 10, 13199), + (13090, 62, 142, 76, 0), + (13090, 63, 311, 0, 0), + (13090, 64, 134, 80, 0), + (13090, 65, 348, 10, 0), + (13090, 66, 137, 79, 0), + (13090, 67, 339, 10, 13199), + (13090, 68, 142, 76, 0), + (13090, 69, 311, 0, 0), + (13090, 70, 134, 80, 0), + (13090, 71, 348, 10, 0), + (13090, 72, 137, 147, 0), + (13090, 73, 339, 10, 13830), + (13090, 74, 142, 81, 0), + (13090, 75, 311, 0, 0), + (13090, 76, 134, 85, 0), + (13090, 77, 348, 10, 0), + (13090, 78, 137, 0, 0), + (13090, 79, 339, 10, 13830), + (13090, 80, 142, 81, 0), + (13090, 81, 311, 0, 0), + (13090, 82, 134, 85, 0), + (13090, 83, 348, 10, 0), + (13090, 84, 137, 100, 0), + (13090, 85, 339, 10, 13830), + (13090, 86, 142, 81, 0), + (13090, 87, 311, 0, 0), + (13090, 88, 134, 85, 0), + (13090, 89, 348, 10, 0), + (13090, 90, 137, 79, 0), + (13090, 91, 339, 10, 13830), + (13090, 92, 142, 81, 0), + (13090, 93, 311, 0, 0), + (13090, 94, 134, 85, 0), + (13090, 95, 348, 10, 0), + (13090, 96, 137, 147, 0), + (13090, 97, 339, 10, 27527), + (13090, 98, 142, 86, 0), + (13090, 99, 311, 0, 0), + (13090, 100, 134, 90, 0), + (13090, 101, 348, 10, 0), + (13090, 102, 137, 0, 0), + (13090, 103, 339, 10, 27527), + (13090, 104, 142, 86, 0), + (13090, 105, 311, 0, 0), + (13090, 106, 134, 90, 0), + (13090, 107, 348, 10, 0), + (13090, 108, 137, 100, 0), + (13090, 109, 339, 10, 27527), + (13090, 110, 142, 86, 0), + (13090, 111, 311, 0, 0), + (13090, 112, 134, 90, 0), + (13090, 113, 348, 10, 0), + (13090, 114, 137, 79, 0), + (13090, 115, 339, 10, 27527), + (13090, 116, 142, 86, 0), + (13090, 117, 311, 0, 0), + (13090, 118, 134, 90, 0), + (13090, 119, 348, 10, 0), + (13090, 120, 137, 147, 0), + (13091, 1, 339, 10, 8105), + (13091, 2, 142, 65, 0), + (13091, 3, 311, 0, 0), + (13091, 4, 134, 70, 0), + (13091, 5, 348, 10, 0), + (13091, 6, 137, 0, 0), + (13091, 7, 339, 10, 8105), + (13091, 8, 142, 65, 0), + (13091, 9, 311, 0, 0), + (13091, 10, 134, 70, 0), + (13091, 11, 348, 10, 0), + (13091, 12, 137, 100, 0), + (13091, 13, 339, 10, 8105), + (13091, 14, 142, 65, 0), + (13091, 15, 311, 0, 0), + (13091, 16, 134, 70, 0), + (13091, 17, 348, 10, 0), + (13091, 18, 137, 79, 0), + (13091, 19, 339, 10, 8105), + (13091, 20, 142, 65, 0), + (13091, 21, 311, 0, 0), + (13091, 22, 134, 70, 0), + (13091, 23, 348, 10, 0), + (13091, 24, 137, 147, 0), + (13091, 25, 339, 10, 11404), + (13091, 26, 142, 71, 0), + (13091, 27, 311, 0, 0), + (13091, 28, 134, 75, 0), + (13091, 29, 348, 10, 0), + (13091, 30, 137, 0, 0), + (13091, 31, 339, 10, 11404), + (13091, 32, 142, 71, 0), + (13091, 33, 311, 0, 0), + (13091, 34, 134, 75, 0), + (13091, 35, 348, 10, 0), + (13091, 36, 137, 100, 0), + (13091, 37, 339, 10, 11404), + (13091, 38, 142, 71, 0), + (13091, 39, 311, 0, 0), + (13091, 40, 134, 75, 0), + (13091, 41, 348, 10, 0), + (13091, 42, 137, 79, 0), + (13091, 43, 339, 10, 11404), + (13091, 44, 142, 71, 0), + (13091, 45, 311, 0, 0), + (13091, 46, 134, 75, 0), + (13091, 47, 348, 10, 0), + (13091, 48, 137, 147, 0), + (13091, 49, 339, 10, 13199), + (13091, 50, 142, 76, 0), + (13091, 51, 311, 0, 0), + (13091, 52, 134, 80, 0), + (13091, 53, 348, 10, 0), + (13091, 54, 137, 0, 0), + (13091, 55, 339, 10, 13199), + (13091, 56, 142, 76, 0), + (13091, 57, 311, 0, 0), + (13091, 58, 134, 80, 0), + (13091, 59, 348, 10, 0), + (13091, 60, 137, 100, 0), + (13091, 61, 339, 10, 13199), + (13091, 62, 142, 76, 0), + (13091, 63, 311, 0, 0), + (13091, 64, 134, 80, 0), + (13091, 65, 348, 10, 0), + (13091, 66, 137, 79, 0), + (13091, 67, 339, 10, 13199), + (13091, 68, 142, 76, 0), + (13091, 69, 311, 0, 0), + (13091, 70, 134, 80, 0), + (13091, 71, 348, 10, 0), + (13091, 72, 137, 147, 0), + (13091, 73, 339, 10, 13830), + (13091, 74, 142, 81, 0), + (13091, 75, 311, 0, 0), + (13091, 76, 134, 85, 0), + (13091, 77, 348, 10, 0), + (13091, 78, 137, 0, 0), + (13091, 79, 339, 10, 13830), + (13091, 80, 142, 81, 0), + (13091, 81, 311, 0, 0), + (13091, 82, 134, 85, 0), + (13091, 83, 348, 10, 0), + (13091, 84, 137, 100, 0), + (13091, 85, 339, 10, 13830), + (13091, 86, 142, 81, 0), + (13091, 87, 311, 0, 0), + (13091, 88, 134, 85, 0), + (13091, 89, 348, 10, 0), + (13091, 90, 137, 79, 0), + (13091, 91, 339, 10, 13830), + (13091, 92, 142, 81, 0), + (13091, 93, 311, 0, 0), + (13091, 94, 134, 85, 0), + (13091, 95, 348, 10, 0), + (13091, 96, 137, 147, 0), + (13091, 97, 339, 10, 27527), + (13091, 98, 142, 86, 0), + (13091, 99, 311, 0, 0), + (13091, 100, 134, 90, 0), + (13091, 101, 348, 10, 0), + (13091, 102, 137, 0, 0), + (13091, 103, 339, 10, 27527), + (13091, 104, 142, 86, 0), + (13091, 105, 311, 0, 0), + (13091, 106, 134, 90, 0), + (13091, 107, 348, 10, 0), + (13091, 108, 137, 100, 0), + (13091, 109, 339, 10, 27527), + (13091, 110, 142, 86, 0), + (13091, 111, 311, 0, 0), + (13091, 112, 134, 90, 0), + (13091, 113, 348, 10, 0), + (13091, 114, 137, 79, 0), + (13091, 115, 339, 10, 27527), + (13091, 116, 142, 86, 0), + (13091, 117, 311, 0, 0), + (13091, 118, 134, 90, 0), + (13091, 119, 348, 10, 0), + (13091, 120, 137, 147, 0), + (13092, 1, 217, 0, 102280), + (13092, 2, 346, 84, 18), + (13093, 1, 217, 0, 109400), + (13093, 2, 346, 86, 18), + (13094, 1, 217, 0, 116800), + (13094, 2, 346, 88, 18), + (13095, 1, 439, 0, 140680), + (13095, 2, 345, 88, 25), + (13096, 1, 287, 1, 0), + (13096, 2, 140, 3, 0), + (13096, 3, 348, 1, 0), + (13096, 4, 138, 0, 0), + (13096, 5, 137, 0, 0), + (13097, 1, 287, 2, 0), + (13097, 2, 140, 3, 0), + (13097, 3, 348, 1, 0), + (13097, 4, 138, 0, 0), + (13097, 5, 137, 0, 0), + (13098, 1, 287, 3, 0), + (13098, 2, 140, 3, 0), + (13098, 3, 348, 1, 0), + (13098, 4, 138, 0, 0), + (13098, 5, 137, 0, 0), + (13099, 1, 132, 15, 15), + (13101, 1, 360, 25, 27537), + (13102, 1, 360, 25, 27538), + (13103, 1, 360, 25, 27539), + (13104, 1, 303, 14000, 18000), + (13104, 2, 139, 2766, 0), + (13105, 1, 303, 18000, 22500), + (13105, 2, 139, 2766, 0), + (13106, 1, 303, 22500, 27500), + (13106, 2, 139, 2766, 0), + (13110, 1, 185, 8, 1), + (13110, 2, 185, 8, 3), + (13111, 1, 185, 10, 1), + (13111, 2, 185, 10, 3), + (13113, 1, 185, 7, 36), + (13114, 1, 185, 9, 36), + (13116, 1, 185, 8, 0), + (13116, 2, 185, 8, 2), + (13117, 1, 185, 10, 0), + (13117, 2, 185, 10, 2), + (13122, 1, 2, 128, 0), + (13123, 1, 2, 132, 0), + (13124, 1, 2, 136, 0), + (13127, 1, 287, 4, 0), + (13127, 2, 140, 3, 0), + (13127, 3, 348, 1, 0), + (13127, 4, 138, 0, 0), + (13127, 5, 137, 0, 0), + (13130, 1, 264, 1440, 7003), + (13140, 1, 264, 480, 391), + (13141, 1, 264, 600, 391), + (13142, 1, 264, 720, 391), + (13143, 1, 127, 17, 0), + (13143, 2, 385, 8054, 0), + (13144, 1, 127, 34, 0), + (13144, 2, 385, 8054, 0), + (13145, 1, 127, 50, 0), + (13145, 2, 385, 8054, 0), + (13146, 1, 127, 17, 0), + (13146, 2, 385, 8054, 0), + (13147, 1, 127, 34, 0), + (13147, 2, 385, 8054, 0), + (13148, 1, 127, 50, 0), + (13148, 2, 385, 8054, 0), + (13149, 1, 97, 550, 0), + (13150, 1, 97, 600, 0), + (13151, 1, 97, 650, 0), + (13152, 1, 97, 700, 0), + (13153, 1, 97, 750, 0), + (13166, 1, 264, 5, 749), + (13166, 2, 264, 5, 822), + (13166, 3, 264, 5, 1274), + (13166, 4, 264, 5, 1275), + (13167, 1, 264, 10, 749), + (13167, 2, 264, 10, 822), + (13167, 3, 264, 10, 1274), + (13167, 4, 264, 10, 1275), + (13168, 1, 264, 15, 749), + (13168, 2, 264, 15, 822), + (13168, 3, 264, 15, 1274), + (13168, 4, 264, 15, 1275), + (13184, 1, 220, 315, 26), + (13185, 1, 220, 400, 26), + (13186, 1, 220, 500, 26), + (13187, 1, 405, 19, 0), + (13188, 1, 405, 21, 0), + (13189, 1, 405, 23, 0), + (13196, 1, 279, 31, 0), + (13197, 1, 279, 35, 0), + (13198, 1, 279, 39, 0), + (13199, 1, 378, 30, 31), + (13200, 1, 378, 35, 31), + (13201, 1, 378, 40, 31), + (13204, 1, 264, 180, 8261), + (13205, 1, 264, 360, 8261), + (13206, 1, 264, 540, 8261), + (13207, 1, 288, 100, 8), + (13208, 1, 288, 100, 8), + (13209, 1, 288, 100, 8), + (13210, 1, 325, 70, 0), + (13211, 1, 325, 75, 0), + (13212, 1, 325, 80, 0), + (13213, 1, 220, 285, 8), + (13214, 1, 220, 315, 8), + (13215, 1, 220, 350, 8), + (13216, 1, 220, 390, 8), + (13217, 1, 220, 440, 8), + (13218, 1, 216, 750, 8), + (13219, 1, 114, -12, 0), + (13220, 1, 114, -15, 0), + (13221, 1, 114, -18, 0), + (13222, 1, 310, 240000, 0), + (13222, 2, 139, 6197, 0), + (13222, 3, 411, 512, 0), + (13223, 1, 310, 300000, 0), + (13223, 2, 139, 6197, 0), + (13223, 3, 411, 512, 0), + (13226, 1, 360, 60, 27593), + (13238, 1, 320, 9, 0), + (13239, 1, 320, 10, 0), + (13240, 1, 320, 11, 0), + (13262, 1, 264, 1008, 102), + (13263, 1, 264, 1152, 102), + (13264, 1, 264, 1290, 102), + (13278, 1, 213, 25, 0), + (13281, 1, 318, 31, 0), + (13286, 1, 278, 900, 102200), + (13286, 2, 440, 92, 100), + (13294, 1, 339, 10, 8105), + (13294, 2, 142, 65, 0), + (13294, 3, 311, 0, 0), + (13294, 4, 134, 70, 0), + (13294, 5, 348, 10, 0), + (13294, 6, 137, 0, 0), + (13294, 7, 339, 10, 8105), + (13294, 8, 142, 65, 0), + (13294, 9, 311, 0, 0), + (13294, 10, 134, 70, 0), + (13294, 11, 348, 10, 0), + (13294, 12, 137, 100, 0), + (13294, 13, 339, 10, 8105), + (13294, 14, 142, 65, 0), + (13294, 15, 311, 0, 0), + (13294, 16, 134, 70, 0), + (13294, 17, 348, 10, 0), + (13294, 18, 137, 79, 0), + (13294, 19, 339, 10, 8105), + (13294, 20, 142, 65, 0), + (13294, 21, 311, 0, 0), + (13294, 22, 134, 70, 0), + (13294, 23, 348, 10, 0), + (13294, 24, 137, 147, 0), + (13294, 25, 339, 10, 11404), + (13294, 26, 142, 71, 0), + (13294, 27, 311, 0, 0), + (13294, 28, 134, 75, 0), + (13294, 29, 348, 10, 0), + (13294, 30, 137, 0, 0), + (13294, 31, 339, 10, 11404), + (13294, 32, 142, 71, 0), + (13294, 33, 311, 0, 0), + (13294, 34, 134, 75, 0), + (13294, 35, 348, 10, 0), + (13294, 36, 137, 100, 0), + (13294, 37, 339, 10, 11404), + (13294, 38, 142, 71, 0), + (13294, 39, 311, 0, 0), + (13294, 40, 134, 75, 0), + (13294, 41, 348, 10, 0), + (13294, 42, 137, 79, 0), + (13294, 43, 339, 10, 11404), + (13294, 44, 142, 71, 0), + (13294, 45, 311, 0, 0), + (13294, 46, 134, 75, 0), + (13294, 47, 348, 10, 0), + (13294, 48, 137, 147, 0), + (13294, 49, 339, 10, 13199), + (13294, 50, 142, 76, 0), + (13294, 51, 311, 0, 0), + (13294, 52, 134, 80, 0), + (13294, 53, 348, 10, 0), + (13294, 54, 137, 0, 0), + (13294, 55, 339, 10, 13199), + (13294, 56, 142, 76, 0), + (13294, 57, 311, 0, 0), + (13294, 58, 134, 80, 0), + (13294, 59, 348, 10, 0), + (13294, 60, 137, 100, 0), + (13294, 61, 339, 10, 13199), + (13294, 62, 142, 76, 0), + (13294, 63, 311, 0, 0), + (13294, 64, 134, 80, 0), + (13294, 65, 348, 10, 0), + (13294, 66, 137, 79, 0), + (13294, 67, 339, 10, 13199), + (13294, 68, 142, 76, 0), + (13294, 69, 311, 0, 0), + (13294, 70, 134, 80, 0), + (13294, 71, 348, 10, 0), + (13294, 72, 137, 147, 0), + (13294, 73, 339, 10, 13830), + (13294, 74, 142, 81, 0), + (13294, 75, 311, 0, 0), + (13294, 76, 134, 85, 0), + (13294, 77, 348, 10, 0), + (13294, 78, 137, 0, 0), + (13294, 79, 339, 10, 13830), + (13294, 80, 142, 81, 0), + (13294, 81, 311, 0, 0), + (13294, 82, 134, 85, 0), + (13294, 83, 348, 10, 0), + (13294, 84, 137, 100, 0), + (13294, 85, 339, 10, 13830), + (13294, 86, 142, 81, 0), + (13294, 87, 311, 0, 0), + (13294, 88, 134, 85, 0), + (13294, 89, 348, 10, 0), + (13294, 90, 137, 79, 0), + (13294, 91, 339, 10, 13830), + (13294, 92, 142, 81, 0), + (13294, 93, 311, 0, 0), + (13294, 94, 134, 85, 0), + (13294, 95, 348, 10, 0), + (13294, 96, 137, 147, 0), + (13294, 97, 339, 10, 27527), + (13294, 98, 142, 86, 0), + (13294, 99, 311, 0, 0), + (13294, 100, 134, 90, 0), + (13294, 101, 348, 10, 0), + (13294, 102, 137, 0, 0), + (13294, 103, 339, 10, 27527), + (13294, 104, 142, 86, 0), + (13294, 105, 311, 0, 0), + (13294, 106, 134, 90, 0), + (13294, 107, 348, 10, 0), + (13294, 108, 137, 100, 0), + (13294, 109, 339, 10, 27527), + (13294, 110, 142, 86, 0), + (13294, 111, 311, 0, 0), + (13294, 112, 134, 90, 0), + (13294, 113, 348, 10, 0), + (13294, 114, 137, 79, 0), + (13294, 115, 339, 10, 27527), + (13294, 116, 142, 86, 0), + (13294, 117, 311, 0, 0), + (13294, 118, 134, 90, 0), + (13294, 119, 348, 10, 0), + (13294, 120, 137, 147, 0), + (13294, 121, 339, 10, 30644), + (13294, 122, 142, 91, 0), + (13294, 123, 311, 0, 0), + (13294, 124, 134, 95, 0), + (13294, 125, 348, 10, 0), + (13294, 126, 137, 0, 0), + (13294, 127, 339, 10, 30644), + (13294, 128, 142, 91, 0), + (13294, 129, 311, 0, 0), + (13294, 130, 134, 95, 0), + (13294, 131, 348, 10, 0), + (13294, 132, 137, 100, 0), + (13294, 133, 339, 10, 30644), + (13294, 134, 142, 91, 0), + (13294, 135, 311, 0, 0), + (13294, 136, 134, 95, 0), + (13294, 137, 348, 10, 0), + (13294, 138, 137, 79, 0), + (13294, 139, 339, 10, 30644), + (13294, 140, 142, 91, 0), + (13294, 141, 311, 0, 0), + (13294, 142, 134, 95, 0), + (13294, 143, 348, 10, 0), + (13294, 144, 137, 147, 0), + (13295, 1, 339, 10, 8105), + (13295, 2, 142, 65, 0), + (13295, 3, 311, 0, 0), + (13295, 4, 134, 70, 0), + (13295, 5, 348, 10, 0), + (13295, 6, 137, 0, 0), + (13295, 7, 339, 10, 8105), + (13295, 8, 142, 65, 0), + (13295, 9, 311, 0, 0), + (13295, 10, 134, 70, 0), + (13295, 11, 348, 10, 0), + (13295, 12, 137, 100, 0), + (13295, 13, 339, 10, 8105), + (13295, 14, 142, 65, 0), + (13295, 15, 311, 0, 0), + (13295, 16, 134, 70, 0), + (13295, 17, 348, 10, 0), + (13295, 18, 137, 79, 0), + (13295, 19, 339, 10, 8105), + (13295, 20, 142, 65, 0), + (13295, 21, 311, 0, 0), + (13295, 22, 134, 70, 0), + (13295, 23, 348, 10, 0), + (13295, 24, 137, 147, 0), + (13295, 25, 339, 10, 11404), + (13295, 26, 142, 71, 0), + (13295, 27, 311, 0, 0), + (13295, 28, 134, 75, 0), + (13295, 29, 348, 10, 0), + (13295, 30, 137, 0, 0), + (13295, 31, 339, 10, 11404), + (13295, 32, 142, 71, 0), + (13295, 33, 311, 0, 0), + (13295, 34, 134, 75, 0), + (13295, 35, 348, 10, 0), + (13295, 36, 137, 100, 0), + (13295, 37, 339, 10, 11404), + (13295, 38, 142, 71, 0), + (13295, 39, 311, 0, 0), + (13295, 40, 134, 75, 0), + (13295, 41, 348, 10, 0), + (13295, 42, 137, 79, 0), + (13295, 43, 339, 10, 11404), + (13295, 44, 142, 71, 0), + (13295, 45, 311, 0, 0), + (13295, 46, 134, 75, 0), + (13295, 47, 348, 10, 0), + (13295, 48, 137, 147, 0), + (13295, 49, 339, 10, 13199), + (13295, 50, 142, 76, 0), + (13295, 51, 311, 0, 0), + (13295, 52, 134, 80, 0), + (13295, 53, 348, 10, 0), + (13295, 54, 137, 0, 0), + (13295, 55, 339, 10, 13199), + (13295, 56, 142, 76, 0), + (13295, 57, 311, 0, 0), + (13295, 58, 134, 80, 0), + (13295, 59, 348, 10, 0), + (13295, 60, 137, 100, 0), + (13295, 61, 339, 10, 13199), + (13295, 62, 142, 76, 0), + (13295, 63, 311, 0, 0), + (13295, 64, 134, 80, 0), + (13295, 65, 348, 10, 0), + (13295, 66, 137, 79, 0), + (13295, 67, 339, 10, 13199), + (13295, 68, 142, 76, 0), + (13295, 69, 311, 0, 0), + (13295, 70, 134, 80, 0), + (13295, 71, 348, 10, 0), + (13295, 72, 137, 147, 0), + (13295, 73, 339, 10, 13830), + (13295, 74, 142, 81, 0), + (13295, 75, 311, 0, 0), + (13295, 76, 134, 85, 0), + (13295, 77, 348, 10, 0), + (13295, 78, 137, 0, 0), + (13295, 79, 339, 10, 13830), + (13295, 80, 142, 81, 0), + (13295, 81, 311, 0, 0), + (13295, 82, 134, 85, 0), + (13295, 83, 348, 10, 0), + (13295, 84, 137, 100, 0), + (13295, 85, 339, 10, 13830), + (13295, 86, 142, 81, 0), + (13295, 87, 311, 0, 0), + (13295, 88, 134, 85, 0), + (13295, 89, 348, 10, 0), + (13295, 90, 137, 79, 0), + (13295, 91, 339, 10, 13830), + (13295, 92, 142, 81, 0), + (13295, 93, 311, 0, 0), + (13295, 94, 134, 85, 0), + (13295, 95, 348, 10, 0), + (13295, 96, 137, 147, 0), + (13295, 97, 339, 10, 27527), + (13295, 98, 142, 86, 0), + (13295, 99, 311, 0, 0), + (13295, 100, 134, 90, 0), + (13295, 101, 348, 10, 0), + (13295, 102, 137, 0, 0), + (13295, 103, 339, 10, 27527), + (13295, 104, 142, 86, 0), + (13295, 105, 311, 0, 0), + (13295, 106, 134, 90, 0), + (13295, 107, 348, 10, 0), + (13295, 108, 137, 100, 0), + (13295, 109, 339, 10, 27527), + (13295, 110, 142, 86, 0), + (13295, 111, 311, 0, 0), + (13295, 112, 134, 90, 0), + (13295, 113, 348, 10, 0), + (13295, 114, 137, 79, 0), + (13295, 115, 339, 10, 27527), + (13295, 116, 142, 86, 0), + (13295, 117, 311, 0, 0), + (13295, 118, 134, 90, 0), + (13295, 119, 348, 10, 0), + (13295, 120, 137, 147, 0), + (13295, 121, 339, 10, 30644), + (13295, 122, 142, 91, 0), + (13295, 123, 311, 0, 0), + (13295, 124, 134, 95, 0), + (13295, 125, 348, 10, 0), + (13295, 126, 137, 0, 0), + (13295, 127, 339, 10, 30644), + (13295, 128, 142, 91, 0), + (13295, 129, 311, 0, 0), + (13295, 130, 134, 95, 0), + (13295, 131, 348, 10, 0), + (13295, 132, 137, 100, 0), + (13295, 133, 339, 10, 30644), + (13295, 134, 142, 91, 0), + (13295, 135, 311, 0, 0), + (13295, 136, 134, 95, 0), + (13295, 137, 348, 10, 0), + (13295, 138, 137, 79, 0), + (13295, 139, 339, 10, 30644), + (13295, 140, 142, 91, 0), + (13295, 141, 311, 0, 0), + (13295, 142, 134, 95, 0), + (13295, 143, 348, 10, 0), + (13295, 144, 137, 147, 0), + (13296, 1, 125, 49, 49), + (13296, 2, 137, 0, 0), + (13296, 3, 141, 1, 0), + (13296, 4, 139, -6233, 0), + (13296, 5, 139, -6265, 0), + (13296, 6, 125, 49, 49), + (13296, 7, 137, 147, 0), + (13296, 8, 141, 1, 0), + (13297, 1, 125, 52, 52), + (13297, 2, 137, 0, 0), + (13297, 3, 141, 1, 0), + (13297, 4, 139, -6233, 0), + (13297, 5, 139, -6265, 0), + (13297, 6, 125, 52, 52), + (13297, 7, 137, 147, 0), + (13297, 8, 141, 1, 0), + (13299, 1, 319, 31, 0), + (13302, 1, 274, 44, 0), + (13305, 1, 189, 19, 0), + (13308, 1, 265, 87, 0), + (13313, 1, 15, 29, 0), + (13318, 1, 97, 850, 0), + (13323, 1, 320, 15, 0), + (13326, 1, 330, 155, 0), + (13326, 2, 330, 155, 1), + (13326, 3, 330, 155, 2), + (13326, 4, 330, 155, 3), + (13326, 5, 330, 155, 28), + (13326, 6, 330, 155, 36), + (13332, 1, 330, 155, 0), + (13332, 2, 330, 155, 1), + (13332, 3, 330, 155, 2), + (13332, 4, 330, 155, 3), + (13332, 5, 330, 155, 28), + (13332, 6, 330, 155, 36), + (13332, 7, 330, 155, 77), + (13338, 1, 1, 370, 0), + (13343, 1, 1, 340, 0), + (13348, 1, 1, 440, 0), + (13353, 1, 1, 330, 0), + (13358, 1, 1, 540, 0), + (13396, 1, 375, 40, 0), + (13404, 1, 273, 8, 0), + (13411, 1, 399, 4, 0), + (13411, 2, 138, 1, 0), + (13411, 3, 137, 0, 0), + (13411, 4, 348, 10, 0), + (13411, 5, 311, 0, 0), + (13411, 6, 141, 1, 0), + (13411, 7, 134, 254, 0), + (13411, 8, 137, -39, 0), + (13413, 1, 399, 12, 0), + (13413, 2, 141, 1, 0), + (13413, 3, 138, 0, 0), + (13413, 4, 142, 255, 0), + (13413, 5, 391, 0, 0), + (13413, 6, 311, 0, 0), + (13413, 7, 137, -152, 0), + (13413, 8, 411, 100350, 0), + (13413, 9, 137, -39, 0), + (13415, 1, 264, 150, 705), + (13415, 2, 264, 150, 1092), + (13415, 3, 264, 150, 10396), + (13415, 4, 264, 150, 10397), + (13416, 1, 264, 20, 626), + (13438, 1, 266, 29, 0), + (13449, 1, 264, 2, 11073), + (13463, 1, 264, 90, 458), + (13474, 1, 264, 120, 444), + (13477, 1, 126, 20, 0), + (13477, 2, 134, 95, 0), + (13477, 3, 135, 4, 0), + (13477, 4, 135, 5, 0), + (13485, 1, 279, 3, 0), + (13502, 1, 375, 160, 0), + (13508, 1, 378, 5, 3), + (13511, 1, 279, 43, 0), + (13520, 1, 292, 70, 0), + (13521, 1, 293, 25, 0), + (13533, 1, 378, 55, 96), + (13545, 1, 323, 30787, 0), + (13562, 1, 264, 480, 872), + (13565, 1, 264, 60, 3804), + (13568, 1, 264, 60, 876), + (13578, 1, 244, 30, 0), + (13589, 1, 279, 34, 0), + (13590, 1, 279, 38, 0), + (13598, 1, 339, 20, 30809), + (13598, 2, 137, 21, 0), + (13598, 3, 385, -18000, 0), + (13598, 4, 339, 20, 30809), + (13598, 5, 137, 343, 0), + (13598, 6, 385, -18000, 0), + (13601, 1, 231, 22, 0), + (13607, 1, 126, 4, 4), + (13607, 2, 137, 21, 0), + (13607, 3, 231, 4, 4), + (13610, 1, 266, 47, 0), + (13613, 1, 220, 260, 10), + (13616, 1, 220, 150, 2), + (13616, 2, 220, 150, 3), + (13616, 3, 220, 150, 77), + (13617, 1, 220, 375, 2), + (13617, 2, 220, 375, 3), + (13617, 3, 220, 375, 77), + (13618, 1, 220, 500, 2), + (13618, 2, 220, 500, 3), + (13618, 3, 220, 500, 77), + (13621, 1, 218, 11, 0), + (13627, 1, 59, -59, 0), + (13628, 1, 59, -64, 0), + (13630, 1, 398, 10000, 0), + (13630, 2, 137, 152, 0), + (13667, 1, 287, 1, 0), + (13667, 2, 385, 8054, 0), + (13675, 1, 218, 24, 0), + (13684, 1, 399, 2, 0), + (13684, 2, 140, 2, 0), + (13684, 3, 348, 10, 0), + (13684, 4, 138, 0, 0), + (13684, 5, 137, -152, 0), + (13684, 6, 137, -39, 0), + (13685, 1, 399, 3, 0), + (13685, 2, 140, 2, 0), + (13685, 3, 348, 10, 0), + (13685, 4, 138, 0, 0), + (13685, 5, 137, -152, 0), + (13685, 6, 137, -39, 0), + (13686, 1, 399, 4, 0), + (13686, 2, 140, 2, 0), + (13686, 3, 348, 10, 0), + (13686, 4, 138, 0, 0), + (13686, 5, 137, -152, 0), + (13686, 6, 137, -39, 0), + (13689, 1, 127, 10, 0), + (13689, 2, 139, 27592, 0), + (13689, 3, 139, 31548, 0), + (13707, 1, 274, 26, 0), + (13710, 1, 280, 65, 0), + (13713, 1, 218, 26, 0), + (13753, 1, 264, 360, 534), + (13758, 1, 264, 360, 602), + (13763, 1, 287, 4, 0), + (13763, 2, 137, 31, 0), + (13763, 3, 136, 5, 0), + (13764, 1, 264, 60, 535), + (13767, 1, 439, 0, 153514), + (13767, 2, 345, 90, 22), + (13773, 1, 279, 21, 0), + (13774, 1, 279, 23, 0), + (13775, 1, 279, 25, 0), + (13779, 1, 288, 100, 8), + (13782, 1, 220, 490, 8), + (13789, 1, 216, 850, 8), + (13790, 1, 216, 950, 8), + (13795, 1, 258, 73, 0), + (13798, 1, 114, -21, 0), + (13804, 1, 378, 4, 3), + (13813, 1, 220, 150, 28), + (13813, 2, 220, 150, 0), + (13813, 3, 427, 23598, 9), + (13813, 4, 428, 28, 0), + (13813, 5, 428, 0, 0), + (13820, 1, 220, 325, 26), + (13820, 2, 220, 325, 30), + (13820, 3, 220, 325, 38), + (13823, 1, 220, 295, 21), + (13823, 2, 220, 295, 23), + (13823, 3, 220, 670, 52), + (13823, 4, 220, 295, 28), + (13826, 1, 405, 25, 0), + (13829, 1, 220, 550, 26), + (13835, 1, 283, 300, 0), + (13841, 1, 264, 17, 469), + (13873, 1, 264, 30, 961), + (13878, 1, 264, 60, 609), + (13881, 1, 264, 60, 387), + (13884, 1, 265, 87, 0), + (13889, 1, 264, 60, 1012), + (13894, 1, 327, 13, 0), + (13905, 1, 310, 24000, 0), + (13905, 2, 385, 15319, 0), + (13908, 1, 310, 3000, 0), + (13908, 2, 385, 15307, 0), + (13908, 3, 385, 15407, 0), + (13908, 4, 385, 15507, 0), + (13908, 5, 385, 15607, 0), + (13911, 1, 310, 3000, 0), + (13911, 2, 385, 16005, 0), + (13911, 3, 310, 3000, 0), + (13911, 4, 385, 15405, 0), + (13911, 5, 385, 15505, 0), + (13911, 6, 385, 15605, 0), + (13911, 7, 411, 2, 0), + (13917, 1, 264, 120, 606), + (13921, 1, 114, -66, 0), + (13924, 1, 114, -64, 0), + (13927, 1, 114, -25, 0), + (13930, 1, 341, 310, 0), + (13933, 1, 262, 80, 0), + (13943, 1, 262, 80, 1), + (13953, 1, 262, 80, 2), + (13963, 1, 262, 80, 3), + (13973, 1, 262, 80, 4), + (13983, 1, 262, 80, 5), + (13993, 1, 262, 80, 6), + (14011, 1, 264, 30, 10394), + (14017, 1, 69, 10, 0), + (14018, 1, 69, 10, 0), + (14026, 1, 185, 3, 2), + (14026, 2, 185, 3, 3), + (14026, 3, 185, 3, 77), + (14026, 4, 220, 50, 2), + (14026, 5, 220, 50, 3), + (14026, 6, 220, 50, 77), + (14029, 1, 395, 5, 5), + (14029, 2, 385, 9758, 0), + (14029, 3, 385, 9858, 0), + (14029, 4, 385, 9958, 0), + (14032, 1, 181, 100, 0), + (14037, 1, 264, 180, 804), + (14040, 1, 264, 180, 300), + (14043, 1, 85, 32197, 0), + (14046, 1, 264, 90, 87), + (14056, 1, 310, 360000, 0), + (14056, 2, 139, 4504, 0), + (14059, 1, 310, -180000, 0), + (14059, 2, 139, 4520, 0), + (14062, 1, 264, 60, 821), + (14065, 1, 264, 60, 3215), + (14068, 1, 264, 60, 3216), + (14076, 1, 310, 480000, 0), + (14076, 2, 139, 4518, 0), + (14082, 1, 360, 26, 32314), + (14085, 1, 264, 2, 741), + (14088, 1, 264, 30, 769), + (14091, 1, 264, 120, 701), + (14094, 1, 124, 325, 350), + (14094, 2, 385, 19, 0), + (14094, 3, 144, 0, 0), + (14094, 4, 403, 3, 0), + (14094, 5, 404, 48, 0), + (14094, 6, 385, -21768, 0), + (14097, 1, 85, 32317, 5), + (14100, 1, 127, 50, 0), + (14100, 2, 137, 21, 0), + (14100, 3, 143, 1, 0), + (14100, 4, 134, 253, 0), + (14100, 5, 348, 1, 0), + (14101, 1, 310, 2520000, 0), + (14101, 2, 139, 4506, 0), + (14101, 3, 310, 2520000, 0), + (14101, 4, 385, 11122, 0), + (14101, 5, 385, 11222, 0), + (14101, 6, 385, 11322, 0), + (14101, 7, 385, 11522, 0), + (14115, 1, 287, 1, 0), + (14115, 2, 385, 16130, 0), + (14129, 1, 220, 60, 36), + (14129, 2, 427, 32327, 3), + (14129, 3, 428, 36, 0), + (14130, 1, 220, 90, 36), + (14130, 2, 427, 32327, 5), + (14130, 3, 428, 36, 0), + (14132, 1, 264, 240, 2234), + (14135, 1, 310, 132000, 0), + (14135, 2, 385, 13005, 0), + (14135, 3, 385, 12423, 0), + (14135, 4, 385, 12504, 0), + (14135, 5, 310, 132000, 0), + (14135, 6, 139, 4676, 0), + (14135, 7, 411, 512, 0), + (14138, 1, 310, 480000, 0), + (14138, 2, 139, 4695, 0), + (14138, 3, 411, 512, 0), + (14140, 1, 310, 24000, 0), + (14140, 2, 385, 13007, 0), + (14140, 3, 385, 12105, 0), + (14140, 4, 385, 12205, 0), + (14140, 5, 310, 72000, 0), + (14140, 6, 385, 12305, 0), + (14140, 7, 385, 12405, 0), + (14140, 8, 385, 12505, 0), + (14140, 9, 411, 512, 0), + (14141, 1, 185, 2, 36), + (14144, 1, 287, 1, 0), + (14144, 2, 385, 13204, 0), + (14144, 3, 411, 512, 0), + (14148, 1, 310, 90000, 0), + (14148, 2, 139, 4691, 0), + (14151, 1, 185, 2, 26), + (14151, 2, 220, 100, 26), + (14154, 1, 264, 2100, 276), + (14157, 1, 216, 150, 26), + (14160, 1, 264, 60, 7001), + (14163, 1, 287, 1, 0), + (14163, 2, 385, 16178, 0), + (14163, 3, 411, 128, 0), + (14166, 1, 264, 60, 945), + (14169, 1, 310, 202500, 0), + (14169, 2, 139, 8030, 0), + (14169, 3, 411, 256, 0), + (14173, 1, 310, 1440000, 0), + (14173, 2, 139, 4516, 0), + (14173, 3, 411, 256, 0), + (14176, 1, 264, 660, 8261), + (14179, 1, 287, 1, 0), + (14179, 2, 385, 5830, 0), + (14179, 3, 411, 256, 0), + (14180, 1, 287, 1, 0), + (14180, 2, 139, 8030, 0), + (14180, 3, 411, 256, 0), + (14181, 1, 247, 25, 20), + (14186, 1, 247, 25, 76), + (14196, 1, 264, 2340, 465), + (14199, 1, 264, 720, 499), + (14200, 1, 288, 15, 2), + (14200, 2, 288, 15, 3), + (14200, 3, 288, 15, 51), + (14200, 4, 288, 15, 77), + (14203, 1, 310, 150000, 0), + (14203, 2, 385, 3419, 0), + (14203, 3, 385, 14005, 0), + (14203, 4, 385, 3519, 0), + (14203, 5, 411, 65536, 0), + (14210, 1, 310, 40000, 0), + (14210, 2, 139, 1546, 0), + (14210, 3, 310, 40000, 0), + (14210, 4, 385, 4357, 0), + (14210, 5, 385, 4457, 0), + (14210, 6, 385, 4557, 0), + (14210, 7, 385, 4657, 0), + (14210, 8, 411, 4, 0), + (14213, 1, 264, 120, 1065), + (14218, 1, 232, 23, 4544), + (14223, 1, 264, 40, 47), + (14225, 1, 127, 16, 0), + (14225, 2, 385, 3283, 0), + (14225, 3, 411, 1024, 0), + (14238, 1, 264, 12, 1041), + (14241, 1, 264, 180, 386), + (14244, 1, 286, 100, 0), + (14244, 2, 138, 0, 0), + (14244, 3, 143, 1, 0), + (14244, 4, 348, 1, 0), + (14244, 5, 411, 64, 0), + (14249, 1, 392, 200, 0), + (14249, 2, 138, 1, 0), + (14249, 3, 348, 1, 0), + (14254, 1, 287, 1, 0), + (14254, 2, 385, 2025, 0), + (14254, 3, 385, 5121, 0), + (14254, 4, 385, 5221, 0), + (14254, 5, 385, 5562, 0), + (14259, 1, 287, 1, 0), + (14259, 2, 139, 23585, 0), + (14275, 1, 239, 20, 0), + (14278, 1, 287, 4, 0), + (14278, 2, 385, 16439, 0), + (14278, 3, 411, 32768, 0), + (14279, 1, 320, 8, 0), + (14283, 1, 127, 17, 0), + (14283, 2, 385, 3151, 0), + (14283, 3, 385, 5887, 0), + (14286, 1, 287, 1, 0), + (14286, 2, 385, 4877, 0), + (14289, 1, 127, 10, 0), + (14289, 2, 385, 2754, 0), + (14292, 1, 127, 10, 0), + (14292, 2, 385, 3286, 0), + (14295, 1, 264, 1, 3816), + (14301, 1, 405, 5, 0), + (14304, 1, 264, 45, 8341), + (14308, 1, 264, 20, 431), + (14311, 1, 264, 360, 430), + (14314, 1, 264, 8, 901), + (14318, 1, 127, 10, 0), + (14318, 2, 139, 21754, 0), + (14328, 1, 264, 6, 1154), + (14331, 1, 264, 120, 515), + (14341, 1, 264, 360, 748), + (14349, 1, 294, 0, 205), + (14361, 1, 294, 35, 109), + (14364, 1, 264, 90, 173), + (14367, 1, 445, 1, 0), + (14764, 1, 339, 10, 33950), + (14764, 2, 137, 31, 0), + (15074, 1, 264, 5, 15073), + (15100, 1, 264, 2, 467), + (15105, 1, 264, 120, 131), + (15108, 1, 310, 60000, 0), + (15108, 2, 385, 15521, 0), + (15108, 3, 411, 2, 0), + (15111, 1, 287, 1, 0), + (15111, 2, 385, 21778, 0), + (15113, 1, 287, 3, 0), + (15113, 2, 385, 21778, 0), + (15113, 3, 411, 2, 0), + (15120, 1, 264, 60, 800), + (15123, 1, 310, 120000, 0), + (15123, 2, 385, 15422, 0), + (15123, 3, 411, 2, 0), + (15126, 1, 310, 1000, 0), + (15126, 2, 385, 15212, 0), + (15126, 3, 411, 2, 0), + (15132, 1, 264, 10, 660), + (15135, 1, 287, 1, 0), + (15135, 2, 139, 32313, 0), + (15141, 1, 219, 420, 2400), + (15150, 1, 127, 10, 0), + (15150, 2, 385, 10505, 0), + (15150, 3, 385, 10105, 0), + (15150, 4, 385, 10205, 0), + (15150, 5, 385, 10305, 0), + (15150, 6, 385, 10405, 0), + (15150, 7, 385, 10605, 0), + (15153, 1, 287, 1, 0), + (15153, 2, 139, 4518, 0), + (15154, 1, 287, 1, 0), + (15154, 2, 139, 32312, 0), + (15155, 1, 287, 1, 0), + (15155, 2, 385, 10320, 0), + (15155, 3, 385, 10420, 0), + (15155, 4, 385, 10520, 0), + (15158, 1, 287, 1, 0), + (15158, 2, 385, 32307, 0), + (15159, 1, 287, 1, 0), + (15159, 2, 385, 27537, 0), + (15162, 1, 264, 120, 659), + (15168, 1, 264, 60, 657), + (15172, 1, 302, 430, 430), + (15172, 2, 385, 99, 0), + (15174, 1, 264, 40, 9400), + (15179, 1, 127, 10, 0), + (15179, 2, 139, 21804, 0), + (15179, 3, 139, 38280, 0), + (15182, 1, 264, 840, 9403), + (15188, 1, 239, 62, 0), + (15194, 1, 287, 1, 0), + (15194, 2, 385, 13407, 0), + (15194, 3, 385, 13507, 0), + (15204, 1, 264, 60, 390), + (15207, 1, 264, 60, 323), + (15217, 1, 339, 10, 38319), + (15217, 2, 385, 11006, 0), + (15217, 3, 385, 7108, 0), + (15217, 4, 385, 7208, 0), + (15217, 5, 385, 7308, 0), + (15217, 6, 385, 7408, 0), + (15217, 7, 385, 7508, 0), + (15217, 8, 385, 7608, 0), + (15220, 1, 287, 1, 0), + (15220, 2, 385, 11065, 0), + (15223, 1, 287, 1, 0), + (15223, 2, 385, 11067, 0), + (15226, 1, 287, 1, 0), + (15226, 2, 385, 11064, 0), + (15229, 1, 287, 1, 0), + (15229, 2, 385, 11066, 0), + (15232, 1, 339, 100, 38322), + (15232, 2, 385, 7518, 0), + (15238, 1, 264, 240, 621), + (15238, 2, 264, 240, 622), + (15238, 3, 264, 240, 623), + (15238, 4, 264, 240, 784), + (15238, 5, 264, 240, 785), + (15238, 6, 264, 240, 786), + (15238, 7, 264, 240, 787), + (15238, 8, 264, 240, 624), + (15253, 1, 127, 10, 0), + (15253, 2, 385, 32322, 0), + (15258, 1, 264, 540, 184), + (15270, 1, 264, 1980, 7003), + (15280, 1, 264, 720, 778), + (15283, 1, 310, 1000, 0), + (15283, 2, 385, 11402, 0), + (15283, 3, 385, 11502, 0), + (15283, 4, 385, 11441, 0), + (15283, 5, 385, 11541, 0), + (15283, 6, 385, 11641, 0), + (15288, 1, 220, 50, 0), + (15288, 2, 220, 50, 1), + (15288, 3, 220, 100, 2), + (15288, 4, 220, 100, 3), + (15288, 5, 220, 50, 36), + (15288, 6, 220, 100, 77), + (15295, 1, 127, 10, 0), + (15295, 2, 385, 21654, 0), + (15314, 1, 264, 25920, 36), + (15317, 1, 264, 1728, 35), + (15320, 1, 264, 150, 558), + (15328, 1, 339, 25, 38037), + (15328, 2, 138, 1, 0), + (15328, 3, 142, 65, 0), + (15328, 4, 137, 35, 0), + (15328, 5, 134, 90, 0), + (15328, 6, 339, 25, 38037), + (15328, 7, 138, 1, 0), + (15328, 8, 142, 65, 0), + (15328, 9, 137, 36, 0), + (15328, 10, 134, 90, 0), + (15328, 11, 339, 25, 38037), + (15328, 12, 138, 1, 0), + (15328, 13, 142, 65, 0), + (15328, 14, 137, 369, 0), + (15328, 15, 134, 90, 0), + (15328, 16, 339, 25, 38037), + (15328, 17, 138, 1, 0), + (15328, 18, 142, 65, 0), + (15328, 19, 137, 116, 0), + (15328, 20, 134, 90, 0), + (15342, 1, 287, 1, 0), + (15342, 2, 385, 23605, 0), + (15344, 1, 264, 360, 38), + (15348, 1, 264, 240, 9504), + (15356, 1, 232, 20, 4544), + (15358, 1, 287, 1, 0), + (15358, 2, 385, 32350, 0), + (15359, 1, 264, 960, 50), + (15363, 1, 264, 240, 447), + (15371, 1, 264, 1, 3729), + (15374, 1, 195, 20, 0), + (15383, 1, 310, 1000, 0), + (15383, 2, 385, 5132, 0), + (15383, 3, 385, 5232, 0), + (15383, 4, 385, 5332, 0), + (15383, 5, 385, 5432, 0), + (15383, 6, 385, 5532, 0), + (15383, 7, 385, 5032, 0), + (15383, 8, 385, 5632, 0), + (15389, 1, 127, 16, 0), + (15389, 2, 385, 23575, 0), + (15396, 1, 127, 20, 20), + (15396, 2, 137, 0, 0), + (15396, 3, 138, 0, 0), + (15396, 4, 141, 1, 0), + (15396, 5, 143, 3000, 0), + (15396, 6, 127, 20, 20), + (15396, 7, 385, 16555, 0), + (15396, 8, 385, 16655, 0), + (15397, 1, 264, 1260, 494), + (15403, 1, 264, 10, 8604), + (15406, 1, 127, 10, 10), + (15406, 2, 385, 37097, 0), + (15414, 1, 287, 1, 0), + (15414, 2, 139, 30736, 0), + (15421, 1, 264, 3600, 245), + (15422, 1, 132, 15, 15), + (15426, 1, 239, 62, 0), + (15429, 1, 220, 135, 2), + (15432, 1, 184, 5, -1), + (15438, 1, 310, 180000, 0), + (15438, 2, 385, 8316, 0), + (15438, 3, 411, 128, 0), + (15441, 1, 279, 38, 0), + (15444, 1, 288, 60, 26), + (15450, 1, 310, 3000, 0), + (15450, 2, 385, 8202, 0), + (15450, 3, 385, 8302, 0), + (15450, 4, 385, 8402, 0), + (15450, 5, 385, 8502, 0), + (15450, 6, 385, 8602, 0), + (15450, 7, 411, 128, 0), + (15453, 1, 310, 60000, 0), + (15453, 2, 385, 8421, 0), + (15453, 3, 411, 128, 0), + (15456, 1, 264, 5, 470), + (15466, 1, 126, 20, 20), + (15466, 2, 139, 12576, 0), + (15466, 3, 126, 20, 20), + (15466, 4, 139, 12828, 0), + (15469, 1, 264, 240, 1120), + (15472, 1, 264, 1260, 521), + (15478, 1, 264, 120, 578), + (15485, 1, 339, 10, 38417), + (15485, 2, 142, 96, 0), + (15485, 3, 311, 0, 0), + (15485, 4, 134, 105, 0), + (15485, 5, 348, 10, 0), + (15485, 6, 137, 0, 0), + (15485, 7, 339, 10, 38417), + (15485, 8, 142, 96, 0), + (15485, 9, 311, 0, 0), + (15485, 10, 134, 105, 0), + (15485, 11, 348, 10, 0), + (15485, 12, 137, 100, 0), + (15485, 13, 339, 10, 38417), + (15485, 14, 142, 96, 0), + (15485, 15, 311, 0, 0), + (15485, 16, 134, 105, 0), + (15485, 17, 348, 10, 0), + (15485, 18, 137, 79, 0), + (15485, 19, 339, 10, 38417), + (15485, 20, 142, 96, 0), + (15485, 21, 311, 0, 0), + (15485, 22, 134, 105, 0), + (15485, 23, 348, 10, 0), + (15485, 24, 137, 147, 0), + (15493, 1, 127, 10, 0), + (15493, 2, 137, 31, 0), + (15502, 1, 310, 240000, 0), + (15502, 2, 139, 4673, 0), + (15502, 3, 411, 512, 0), + (15509, 1, 310, 3000, 0), + (15509, 2, 385, 12315, 0), + (15509, 3, 385, 12415, 0), + (15509, 4, 385, 12515, 0), + (15509, 5, 385, 12615, 0), + (15509, 10, 411, 512, 0), + (15512, 1, 288, 50, 8), + (15516, 1, 126, 20, 0), + (15516, 2, 139, 3066, 0), + (15516, 3, 411, 256, 0), + (15517, 1, 127, 16, 0), + (15517, 2, 139, 3066, 0), + (15517, 3, 411, 256, 0), + (15526, 1, 264, 120, 3702), + (15529, 1, 247, 60, 53), + (15540, 1, 185, 5, 1), + (15543, 1, 185, 5, 0), + (15546, 1, 185, 5, 36), + (15549, 1, 264, 15, 244), + (15552, 1, 264, 840, 3710), + (15555, 1, 339, 5, 38103), + (15555, 2, 385, 3208, 0), + (15555, 3, 385, 3308, 0), + (15555, 4, 385, 3408, 0), + (15555, 5, 385, 3508, 0), + (15564, 1, 220, 68, 51), + (15571, 1, 264, 180, 351), + (15579, 1, 287, 2, 0), + (15579, 2, 139, 16106, 0), + (15585, 1, 274, 44, 0), + (15591, 1, 127, 10, 0), + (15591, 2, 139, 16839, 0), + (15598, 1, 264, 180, 759), + (15598, 2, 264, 180, 1150), + (15598, 3, 264, 180, 1151), + (15598, 4, 264, 180, 1152), + (15602, 1, 124, 1, 0), + (15602, 2, 138, 0, 0), + (15602, 3, 141, 1, 0), + (15602, 4, 348, 10, 0), + (15606, 1, 244, -25, 0), + (15609, 1, 383, 10, 38134), + (15609, 2, 141, 1, 0), + (15609, 3, 348, 10, 0), + (15609, 4, 142, 85, 0), + (15609, 5, 143, 3000, 0), + (15622, 1, 127, 5, 5), + (15622, 2, 137, 0, 0), + (15622, 3, 138, 0, 0), + (15622, 4, 141, 1, 0), + (15625, 1, 330, 10, 8), + (15632, 1, 264, 1728, 789), + (15634, 1, 310, 1500, 0), + (15634, 2, 385, 12110, 0), + (15634, 3, 385, 12210, 0), + (15634, 4, 385, 12310, 0), + (15634, 5, 385, 12410, 0), + (15634, 6, 385, 12510, 0), + (15635, 1, 310, 3000, 0), + (15635, 2, 385, 12110, 0), + (15635, 3, 385, 12210, 0), + (15635, 4, 385, 12310, 0), + (15635, 5, 385, 12410, 0), + (15635, 6, 385, 12510, 0), + (15648, 1, 185, 3, 74), + (15694, 1, 190, 550, 0), + (15714, 1, 320, 12, 0), + (15719, 1, 320, 12, 0), + (15746, 1, 421, 20, 0), + (15746, 2, 139, 16097, 0), + (15746, 3, 139, 23612, 0), + (15746, 4, 139, 32196, 0), + (15746, 5, 139, 32565, 0), + (15746, 6, 423, 6, 0), + (15746, 7, 422, 5, 0), + (15746, 8, 411, 2, 0), + (15768, 1, 125, 1, 2), + (15768, 2, 136, 46, 0), + (15772, 1, 128, 80, 80), + (15772, 2, 138, 1, 0), + (15772, 3, 140, 1, 0), + (15772, 4, 311, 0, 0), + (15772, 5, 411, 66434, 0), + (15772, 6, 137, -40, 0), + (15773, 1, 128, 80, 80), + (15773, 2, 138, 1, 0), + (15773, 3, 140, 1, 0), + (15773, 4, 311, 0, 0), + (15773, 5, 411, 256, 0), + (15773, 6, 137, -40, 0), + (15773, 7, 391, 1, 0), + (15778, 1, 303, 27500, 32500), + (15778, 2, 139, 2766, 0), + (15833, 1, 264, 60, 2045), + (15836, 1, 264, 60, 463), + (15891, 1, 264, 20, 988), + (15893, 1, 264, 20, 987), + (15895, 1, 264, 20, 986), + (15908, 1, 220, 125, 0), + (15908, 2, 220, 200, 2), + (15909, 1, 220, 155, 0), + (15909, 2, 220, 290, 2), + (15910, 1, 220, 185, 0), + (15910, 2, 220, 385, 2), + (15954, 1, 292, 49, 0), + (15961, 1, 129, 20, 0), + (15961, 2, 385, 12768, 0), + (15961, 3, 411, 256, 0), + (16062, 1, 339, 20, 40941), + (16062, 2, 138, 0, 0), + (16062, 3, 137, 31, 0), + (16062, 4, 311, 0, 0), + (16084, 1, 158, 1, 0), + (16087, 1, 264, 432, 53), + (16094, 1, 264, 3024, 43), + (16104, 1, 10, 0, 0), + (16109, 1, 69, 3000, 0), + (16114, 1, 114, 2, 0), + (16117, 1, 171, 2, 0), + (16120, 1, 226, 1, 0), + (16121, 1, 310, 840000, 0), + (16121, 2, 139, 4670, 0), + (16124, 1, 264, 2, 3711), + (16128, 1, 127, 8, 0), + (16128, 2, 139, 13143, 0), + (16131, 1, 130, 10, 0), + (16131, 2, 385, 18000, 0), + (16137, 1, 287, 1, 0), + (16137, 2, 385, 21821, 0), + (16140, 1, 287, 1, 0), + (16140, 2, 385, 30666, 0), + (16146, 1, 339, 2, 41107), + (16146, 2, 142, 95, 0), + (16146, 3, 138, 1, 0), + (16146, 4, 137, 0, 0), + (16146, 5, 348, 10, 0), + (16146, 6, 141, 1, 0), + (16149, 1, 129, 20, 0), + (16149, 2, 385, 4357, 0), + (16149, 3, 385, 4457, 0), + (16149, 4, 385, 4557, 0), + (16149, 5, 411, 4, 0), + (16152, 1, 339, 3, 41108), + (16152, 2, 142, 90, 0), + (16152, 3, 138, 0, 0), + (16152, 4, 137, 0, 0), + (16152, 5, 348, 10, 0), + (16152, 6, 141, 1, 0), + (16156, 1, 392, 1000, 0), + (16156, 2, 385, 32341, 0), + (16159, 1, 287, 1, 0), + (16159, 2, 385, 32307, 0), + (16164, 1, 294, 0, 195), + (16170, 1, 360, 70, 41119), + (16173, 1, 320, 12, 0), + (16176, 1, 264, 2, 337), + (16179, 1, 288, 8, 7), + (16180, 1, 264, 5, 584), + (16186, 1, 288, 100, 30), + (16189, 1, 339, 12, 41127), + (16189, 2, 138, 0, 0), + (16189, 3, 142, 70, 0), + (16189, 4, 411, 32, 0), + (16189, 5, 348, 1, 0), + (16189, 6, 141, 1, 0), + (16192, 1, 339, 12, 41130), + (16192, 2, 138, 0, 0), + (16192, 3, 142, 70, 0), + (16192, 4, 403, 4, 0), + (16192, 5, 348, 1, 0), + (16192, 6, 404, 2, 0), + (16192, 7, 141, 1, 0), + (16208, 1, 247, 5, 27), + (16211, 1, 287, 1, 0), + (16211, 2, 139, 23581, 0), + (16211, 3, 139, 32359, 0), + (16218, 1, 264, 10, 403), + (16221, 1, 287, 1, 0), + (16221, 2, 385, 23586, 0), + (16225, 1, 264, 1, 219), + (16230, 1, 310, 1000, 0), + (16230, 2, 385, 2431, 0), + (16230, 3, 385, 2531, 0), + (16230, 4, 385, 2545, 0), + (16230, 5, 385, 2631, 0), + (16235, 1, 126, 35, 0), + (16235, 2, 134, 100, 0), + (16235, 3, 135, 3, 0), + (16238, 1, 287, 2, 0), + (16238, 2, 385, 23693, 0), + (16238, 3, 460, 1, 0), + (16249, 1, 275, 100, 0), + (16257, 1, 429, 37114, 2), + (16257, 2, 428, 52, 0), + (16260, 1, 427, 41160, 3), + (16260, 2, 428, 23, 0), + (16266, 1, 224, 50, 8), + (16266, 2, 173, 4, 0), + (16267, 1, 250, 52, 0), + (16272, 1, 175, 2, 0), + (16276, 1, 247, 10, 36), + (16287, 1, 264, 20, 669), + (16297, 1, 264, 600, 553), + (16300, 1, 264, 60, 668), + (16303, 1, 264, 240, 3506), + (16306, 1, 264, 1260, 777), + (16317, 1, 220, 100, -1), + (16327, 1, 310, 720000, 0), + (16327, 2, 139, 5040, 0), + (16330, 1, 330, 105, 74), + (16336, 1, 264, 30, 1257), + (16339, 1, 264, 10, 773), + (16342, 1, 127, 10, 0), + (16342, 2, 385, 38115, 0), + (16361, 1, 399, 5, 0), + (16361, 2, 141, 1, 0), + (16361, 3, 138, 0, 0), + (16361, 4, 134, 254, 0), + (16361, 5, 348, 10, 0), + (16361, 6, 137, 0, 0), + (16361, 7, 311, 0, 0), + (16361, 8, 137, -152, 0), + (16361, 9, 137, -39, 0), + (16366, 1, 286, 200, 0), + (16366, 2, 138, 0, 0), + (16366, 3, 143, 1, 0), + (16366, 4, 348, 10, 0), + (16371, 1, 129, 20, 0), + (16371, 2, 385, 2754, 0), + (16380, 1, 264, 30, 2061), + (16386, 1, 264, 10, 2064), + (16392, 1, 264, 90, 2202), + (16396, 1, 127, 5, 5), + (16396, 2, 137, 0, 0), + (16396, 3, 138, 0, 0), + (16396, 4, 141, 1, 0), + (16402, 1, 131, 60, 60), + (16402, 2, 348, 10, 0), + (16402, 3, 137, -32, 0), + (16414, 1, 317, 16, 0), + (16419, 1, 426, 6, 0), + (16420, 1, 426, 7, 0), + (16421, 1, 426, 8, 0), + (16440, 1, 247, 65, 76), + (16475, 1, 218, 4, 0), + (16489, 1, 294, 29, 102), + (16536, 1, 405, 3, 0), + (16604, 1, 264, 1440, 180), + (16644, 1, 264, 60, 747), + (16666, 1, 264, 60, 742), + (16730, 1, 347, 31, 0), + (16745, 1, 264, 60, 706), + (16887, 1, 280, 75, 0), + (16890, 1, 218, 21, 0), + (17004, 1, 225, 35, 0), + (17206, 1, 264, 12, 601), + (17209, 1, 264, 180, 111), + (17212, 1, 264, 60, 10367), + (17215, 1, 378, 2, 22), + (17215, 2, 378, 2, 31), + (17215, 3, 378, 2, 3), + (17215, 4, 378, 2, 20), + (17218, 1, 127, 10, 0), + (17218, 2, 139, 27560, 0), + (17229, 1, 220, 900, 3), + (17229, 2, 220, 900, 2), + (17229, 3, 220, 900, 77), + (17235, 1, 127, 15, 0), + (17235, 2, 385, 12609, 0), + (17239, 1, 310, 2400000, 0), + (17239, 2, 139, 4500, 0), + (17239, 3, 411, 8, 0), + (17242, 1, 378, 1, 22), + (17242, 2, 378, 1, 31), + (17242, 3, 378, 1, 3), + (17242, 4, 378, 1, 20), + (17245, 1, 378, 1, 22), + (17245, 2, 378, 1, 31), + (17245, 3, 378, 1, 3), + (17245, 4, 378, 1, 20), + (17249, 1, 264, 120, 651), + (17252, 1, 310, 3000, 0), + (17252, 2, 385, 13438, 0), + (17252, 3, 385, 13538, 0), + (17252, 4, 385, 13638, 0), + (17258, 1, 399, 2, 0), + (17258, 2, 137, 457, 0), + (17258, 3, 399, 2, 0), + (17258, 4, 134, 253, 0), + (17258, 5, 142, 100, 0), + (17258, 6, 138, 0, 0), + (17258, 7, 136, 13, 0), + (17258, 8, 136, 20, 0), + (17258, 9, 137, -39, 0), + (17267, 1, 127, 10, 0), + (17267, 2, 385, 13507, 0), + (17267, 3, 385, 13107, 0), + (17267, 4, 385, 13207, 0), + (17267, 5, 385, 13307, 0), + (17267, 6, 385, 13407, 0), + (17267, 7, 385, 13607, 0), + (17281, 1, 287, 1, 0), + (17281, 2, 385, 16646, 0), + (17288, 1, 264, 1440, 41), + (17289, 1, 264, 180, 1062), + (17295, 1, 229, 62, 0), + (17307, 1, 127, 8, 0), + (17307, 2, 139, 38058, 0), + (17310, 1, 310, 14000, 0), + (17310, 2, 139, 8007, 0), + (17310, 3, 310, 14000, 0), + (17310, 4, 385, 4140, 0), + (17310, 5, 385, 4240, 0), + (17310, 6, 385, 4340, 0), + (17310, 7, 385, 4440, 0), + (17310, 8, 385, 4540, 0), + (17310, 9, 385, 4640, 0), + (17317, 1, 264, 60, 1270), + (17334, 1, 287, 12, 0), + (17334, 2, 385, 16188, 0), + (17336, 1, 287, 1, 0), + (17336, 2, 385, 32348, 0), + (17339, 1, 264, 12, 760), + (17350, 1, 264, 110, 170), + (17357, 1, 287, 1, 0), + (17357, 2, 137, 100, 0), + (17357, 3, 138, 1, 0), + (17361, 1, 264, 60, 405), + (17361, 2, 264, 60, 426), + (17365, 1, 287, 6, 0), + (17365, 2, 385, 5240, 0), + (17365, 3, 385, 5340, 0), + (17365, 4, 385, 5440, 0), + (17365, 5, 385, 5540, 0), + (17365, 6, 385, 5640, 0), + (17370, 1, 287, 1, 0), + (17370, 2, 138, 0, 0), + (17370, 3, 137, 0, 0), + (17370, 4, 137, 100, 0), + (17370, 5, 140, 1, 0), + (17370, 6, 348, 10, 0), + (17375, 1, 127, 10, 0), + (17375, 2, 385, 38078, 0), + (17391, 1, 264, 1560, 98), + (17406, 1, 310, 480000, 0), + (17406, 2, 139, 4502, 0), + (17406, 3, 139, 4509, 0), + (17409, 1, 214, 205, 0), + (17409, 2, 259, 4, 0), + (17409, 3, 172, 4, 0), + (17414, 1, 264, 120, 673), + (17418, 1, 247, 10, 74), + (17428, 1, 288, 5, 51), + (17436, 1, 264, 60, 372), + (17439, 1, 287, 1, 0), + (17439, 2, 385, 6040, 0), + (17441, 1, 279, 37, 0), + (17445, 1, 310, 60000, 0), + (17445, 2, 385, 3312, 0), + (17448, 1, 287, 1, 0), + (17448, 2, 385, 14005, 0), + (17448, 3, 385, 3519, 0), + (17476, 1, 264, 240, 462), + (17492, 1, 264, 120, 840), + (17495, 1, 264, 20, 9702), + (17515, 1, 127, 25, 0), + (17515, 2, 385, 7125, 0), + (17517, 1, 127, 17, 0), + (17517, 2, 385, 23683, 0), + (17517, 3, 460, 1, 0), + (17522, 1, 264, 30, 764), + (17533, 1, 287, 1, 0), + (17533, 2, 139, 32399, 0), + (17533, 3, 460, 1, 0), + (17547, 1, 287, 1, 0), + (17547, 2, 137, 0, 0), + (17547, 3, 137, 100, 0), + (17547, 4, 140, 2, 0), + (17547, 5, 138, 0, 0), + (17547, 6, 348, 10, 0), + (17549, 1, 264, 10, 8700), + (17553, 1, 339, 8, 41768), + (17553, 2, 138, 0, 0), + (17553, 3, 141, 1, 0), + (17553, 4, 134, 253, 0), + (17553, 5, 142, 85, 0), + (17553, 6, 143, 1, 0), + (17553, 7, 311, 0, 0), + (17553, 8, 348, 1, 0), + (17553, 9, 137, 0, 0), + (17554, 1, 227, 2, 74), + (17555, 1, 286, 126, 2), + (17555, 2, 385, 9606, 0), + (17555, 3, 303, 252, 0), + (17555, 4, 385, 9606, 0), + (17558, 1, 413, 2, 2), + (17558, 2, 385, 9603, 0), + (17558, 3, 411, 2048, 0), + (17561, 1, 413, 2, 2), + (17561, 2, 385, 9609, 0), + (17561, 3, 411, 2048, 0), + (17564, 1, 413, 2, 2), + (17564, 2, 385, 9619, 0), + (17564, 3, 411, 2048, 0), + (17567, 1, 413, 2, 2), + (17567, 2, 385, 9613, 0), + (17567, 3, 411, 2048, 0), + (17570, 1, 413, 2, 2), + (17570, 2, 385, 9604, 0), + (17570, 3, 411, 2048, 0), + (17573, 1, 413, 2, 2), + (17573, 2, 385, 9651, 0), + (17573, 3, 411, 2048, 0), + (17576, 1, 413, 2, 2), + (17576, 2, 385, 16652, 0), + (17576, 3, 411, 4096, 0), + (17579, 1, 413, 2, 2), + (17579, 2, 385, 16629, 0), + (17579, 3, 411, 4096, 0), + (17582, 1, 413, 2, 2), + (17582, 2, 385, 16650, 0), + (17582, 3, 411, 4096, 0), + (17585, 1, 413, 2, 2), + (17585, 2, 385, 16608, 0), + (17585, 3, 411, 4096, 0), + (17588, 1, 413, 2, 2), + (17588, 2, 385, 16615, 0), + (17588, 3, 411, 4096, 0), + (17591, 1, 413, 2, 2), + (17591, 2, 385, 16618, 0), + (17591, 3, 411, 4096, 0), + (17594, 1, 413, 2, 2), + (17594, 2, 385, 16625, 0), + (17594, 3, 411, 4096, 0), + (17597, 1, 286, 345, 0), + (17597, 2, 385, 7604, 0), + (17600, 1, 413, 2, 2), + (17600, 2, 385, 7608, 0), + (17600, 3, 411, 8192, 0), + (17603, 1, 413, 2, 2), + (17603, 2, 385, 7612, 0), + (17603, 3, 411, 8192, 0), + (17606, 1, 392, 419, 0), + (17606, 2, 385, 7613, 0), + (17606, 3, 396, 838, 0), + (17606, 4, 385, 7613, 0), + (17609, 1, 413, 2, 2), + (17609, 2, 385, 7636, 0), + (17609, 3, 411, 8192, 0), + (17612, 1, 413, 2, 2), + (17612, 2, 385, 7618, 0), + (17612, 3, 411, 8192, 0), + (17615, 1, 286, 539, 0), + (17615, 2, 385, 7638, 0), + (17618, 1, 413, 2, 2), + (17618, 2, 385, 6664, 0), + (17618, 3, 411, 16384, 0), + (17621, 1, 413, 2, 2), + (17621, 2, 385, 6648, 0), + (17621, 3, 411, 16384, 0), + (17624, 1, 413, 2, 2), + (17624, 2, 385, 6649, 0), + (17624, 3, 411, 16384, 0), + (17627, 1, 413, 2, 2), + (17627, 2, 385, 6611, 0), + (17627, 3, 411, 16384, 0), + (17630, 1, 413, 2, 2), + (17630, 2, 385, 6652, 0), + (17630, 3, 411, 16384, 0), + (17633, 1, 413, 2, 2), + (17633, 2, 385, 6655, 0), + (17633, 3, 411, 16384, 0), + (17639, 1, 323, 37182, 100), + (18972, 1, 214, 210, 0), + (18972, 2, 259, 5, 0), + (18972, 3, 172, 5, 0), + (30050, 1, 69, 25, 0), + (30050, 2, 97, 25, 0), + (30050, 3, 190, 25, 0), + (30050, 4, 328, 25, 0), + (30100, 1, 1, 10, 0), + (30100, 2, 2, 10, 0), + (30100, 3, 341, 10, 0), + (30150, 1, 262, 5, 0), + (30150, 2, 262, 5, 1), + (30150, 3, 262, 5, 2), + (30150, 4, 262, 5, 3), + (30150, 5, 262, 5, 4), + (30150, 6, 262, 5, 5), + (30150, 7, 262, 5, 6), + (30150, 8, 159, 5, 0), + (30150, 9, 0, 2, 0), + (30150, 10, 15, 2, 0), + (30150, 11, 189, 2, 0), + (30150, 12, 317, 2, 0), + (30150, 13, 318, 2, 0), + (30175, 1, 271, 1, 0), + (30180, 1, 264, 1, 8202), + (30185, 1, 264, 1, 1011), + (30195, 1, 432, 1, 0), + (49999, 1, 10, 0, 0); + +DROP TABLE IF EXISTS `aa_rank_prereqs`; +CREATE TABLE IF NOT EXISTS `aa_rank_prereqs` ( + `rank_id` int(10) unsigned NOT NULL, + `aa_id` int(10) NOT NULL, + `points` int(10) NOT NULL, + PRIMARY KEY (`rank_id`,`aa_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `aa_rank_prereqs` (`rank_id`, `aa_id`, `points`) VALUES + (129, 19, 3), + (131, 19, 3), + (136, 19, 3), + (141, 23, 3), + (142, 23, 3), + (143, 23, 3), + (146, 224, 3), + (162, 224, 3), + (190, 30, 3), + (191, 30, 3), + (192, 30, 3), + (195, 31, 3), + (230, 17, 3), + (231, 17, 3), + (232, 17, 3), + (255, 309, 3), + (256, 309, 3), + (257, 309, 3), + (260, 31, 3), + (261, 31, 3), + (262, 31, 3), + (263, 17, 3), + (264, 17, 3), + (265, 17, 3), + (267, 23, 3), + (268, 23, 3), + (269, 23, 3), + (446, 26, 3), + (447, 26, 3), + (448, 26, 3), + (462, 39, 1), + (463, 39, 1), + (464, 39, 1), + (468, 41, 1), + (469, 41, 1), + (470, 41, 1), + (471, 57, 1), + (472, 57, 1), + (473, 57, 1), + (474, 50, 1), + (475, 50, 1), + (476, 50, 1), + (477, 43, 1), + (478, 43, 1), + (479, 43, 1), + (480, 117, 1), + (481, 117, 1), + (482, 117, 1), + (483, 58, 1), + (484, 58, 1), + (485, 58, 1), + (489, 110, 1), + (490, 110, 1), + (491, 110, 1), + (492, 109, 1), + (493, 109, 1), + (494, 109, 1), + (495, 98, 1), + (496, 98, 1), + (497, 98, 1), + (498, 102, 1), + (499, 102, 1), + (500, 102, 1), + (501, 107, 1), + (502, 107, 1), + (503, 107, 1), + (531, 19, 3), + (532, 19, 3), + (534, 6001, 11), + (535, 6001, 11), + (536, 6001, 11), + (537, 112, 3), + (538, 112, 3), + (539, 17, 3), + (540, 17, 3), + (541, 17, 3), + (542, 309, 3), + (543, 309, 3), + (544, 309, 3), + (567, 45, 1), + (574, 125, 1), + (575, 125, 1), + (576, 125, 1), + (583, 73, 1), + (584, 73, 1), + (585, 73, 1), + (586, 120, 1), + (587, 120, 1), + (588, 120, 1), + (589, 87, 1), + (590, 87, 1), + (591, 87, 1), + (592, 30, 1), + (593, 6001, 11), + (594, 6001, 11), + (595, 6001, 11), + (596, 6000, 11), + (597, 6000, 11), + (598, 6000, 11), + (637, 23, 3), + (638, 23, 3), + (639, 23, 3), + (640, 23, 3), + (641, 23, 3), + (642, 23, 3), + (643, 55, 1), + (644, 82, 1), + (702, 30, 1), + (703, 30, 1), + (704, 30, 1), + (705, 30, 1), + (706, 30, 1), + (715, 6001, 11), + (716, 6001, 11), + (717, 6001, 11), + (754, 153, 3), + (755, 153, 3), + (756, 153, 3), + (770, 23, 3), + (771, 23, 3), + (772, 23, 3), + (773, 217, 1), + (774, 217, 1), + (775, 217, 1), + (782, 35, 1), + (783, 35, 1), + (784, 35, 1), + (806, 81, 1), + (849, 180, 3), + (850, 180, 3), + (851, 180, 3), + (886, 102, 1), + (887, 102, 1), + (893, 87, 1), + (894, 87, 1), + (924, 23, 3), + (925, 23, 3), + (931, 23, 1), + (932, 23, 1), + (933, 23, 1), + (975, 102, 1), + (1018, 227, 3), + (1041, 30, 6), + (1042, 30, 6), + (1043, 30, 6), + (1044, 310, 6), + (1045, 310, 6), + (1046, 310, 6), + (1047, 311, 3), + (1048, 311, 3), + (1049, 311, 3), + (1050, 309, 6), + (1051, 309, 6), + (1052, 309, 6), + (1102, 30, 1), + (1103, 30, 1), + (1104, 30, 1), + (1105, 30, 1), + (1106, 30, 1), + (1107, 23, 3), + (1108, 23, 3), + (1109, 23, 3), + (1110, 187, 5), + (1111, 187, 5), + (1112, 187, 5), + (1122, 176, 2), + (1126, 58, 1), + (1127, 58, 1), + (1128, 58, 1), + (1129, 125, 1), + (1130, 125, 1), + (1150, 189, 3), + (1151, 189, 3), + (1152, 189, 3), + (1163, 309, 3), + (1164, 309, 3), + (1165, 309, 3), + (1203, 19, 3), + (1204, 19, 3), + (1205, 19, 3), + (1210, 114, 6), + (1211, 114, 6), + (1212, 114, 6), + (1213, 215, 6), + (1214, 215, 6), + (1215, 215, 6), + (1242, 173, 3), + (1243, 173, 3), + (1244, 173, 3), + (1251, 61, 1), + (1252, 64, 1), + (1253, 62, 1), + (1254, 63, 1), + (1274, 175, 3), + (1275, 175, 3), + (1276, 175, 3), + (1278, 6001, 11), + (1279, 6001, 11), + (1280, 6001, 11), + (1323, 47, 1), + (1337, 308, 3), + (1338, 308, 3), + (1339, 308, 3), + (1414, 451, 1), + (1415, 451, 1), + (1416, 451, 1), + (1417, 451, 1), + (1418, 451, 1), + (1420, 17, 3), + (1421, 17, 3), + (1422, 17, 3), + (1423, 17, 3), + (1424, 17, 3), + (1425, 374, 3), + (1426, 374, 3), + (1427, 374, 3), + (1428, 374, 3), + (1429, 374, 3), + (1435, 20, 3), + (1436, 20, 3), + (1437, 20, 3), + (1458, 375, 3), + (1459, 255, 5), + (1460, 255, 5), + (1461, 255, 5), + (1471, 362, 1), + (1472, 362, 1), + (1473, 362, 1), + (1474, 362, 1), + (1475, 362, 1), + (1483, 114, 6), + (1484, 114, 6), + (1485, 114, 6), + (1486, 19, 7), + (1487, 19, 7), + (1488, 19, 7), + (1489, 19, 7), + (1490, 19, 7), + (1494, 80, 1), + (1495, 185, 6), + (1496, 185, 6), + (1497, 185, 6), + (1501, 46, 1), + (1502, 46, 1), + (1503, 46, 1), + (1504, 60, 1), + (1505, 60, 1), + (1506, 60, 1), + (1511, 175, 3), + (1512, 175, 3), + (1513, 175, 3), + (1514, 259, 6), + (1515, 259, 6), + (1516, 259, 6), + (1524, 30, 3), + (1525, 30, 3), + (1526, 30, 3), + (1543, 439, 3), + (1544, 439, 3), + (1545, 439, 3), + (1546, 420, 1), + (1547, 420, 1), + (1548, 420, 1), + (1552, 13, 5), + (1553, 13, 5), + (1554, 13, 5), + (1555, 359, 3), + (1556, 359, 3), + (1557, 359, 3), + (1558, 46, 1), + (1559, 46, 1), + (1560, 46, 1), + (1572, 263, 1), + (1573, 263, 1), + (1574, 263, 1), + (1575, 263, 1), + (1576, 263, 1), + (1577, 58, 1), + (1578, 58, 1), + (1579, 58, 1), + (1583, 300, 6), + (1584, 300, 6), + (1585, 300, 6), + (1586, 300, 6), + (1587, 300, 6), + (1591, 222, 3), + (1601, 82, 1), + (1602, 82, 1), + (1603, 82, 1), + (1608, 82, 3), + (1609, 82, 3), + (1610, 82, 3), + (1611, 181, 2), + (1612, 181, 2), + (1613, 181, 2), + (1614, 181, 2), + (1615, 181, 2), + (1627, 13, 5), + (1628, 13, 5), + (1629, 13, 5), + (1638, 224, 3), + (1639, 565, 1), + (1640, 793, 1), + (1641, 121, 3), + (1642, 121, 3), + (1643, 77, 1), + (1644, 85, 1), + (1645, 77, 1), + (1646, 85, 1), + (1656, 153, 1), + (1657, 153, 1), + (1659, 285, 1), + (1660, 285, 1), + (1667, 570, 1), + (2400, 38, 1), + (2401, 38, 1), + (2402, 38, 1), + (3676, 35, 1), + (4666, 435, 3), + (4667, 435, 3), + (4668, 435, 3), + (4669, 435, 3), + (4670, 435, 3), + (4688, 497, 5), + (4689, 497, 5), + (4690, 497, 5), + (4691, 497, 5), + (4692, 497, 5), + (4707, 30, 6), + (4708, 30, 6), + (4709, 30, 6), + (4710, 310, 6), + (4711, 310, 6), + (4712, 310, 6), + (4713, 311, 3), + (4714, 311, 3), + (4715, 311, 3), + (4716, 309, 6), + (4717, 309, 6), + (4718, 309, 6), + (4749, 23, 3), + (4750, 23, 3), + (4751, 23, 3), + (4752, 114, 6), + (4753, 114, 6), + (4754, 114, 6), + (4755, 215, 6), + (4756, 215, 6), + (4757, 215, 6), + (4761, 526, 3), + (4762, 526, 3), + (4763, 526, 3), + (4773, 20, 3), + (4795, 309, 3), + (4796, 309, 3), + (4797, 309, 3), + (4829, 420, 1), + (4830, 420, 1), + (4831, 420, 1), + (4844, 435, 3), + (4845, 435, 3), + (4846, 435, 3), + (4847, 435, 3), + (4848, 435, 3), + (4861, 68, 1), + (4862, 68, 1), + (4863, 68, 1), + (4864, 175, 3), + (4865, 175, 3), + (4866, 175, 3), + (4887, 413, 3), + (4888, 413, 3), + (4889, 413, 3), + (4890, 57, 1), + (4894, 409, 3), + (4895, 409, 3), + (4896, 409, 3), + (4903, 784, 1), + (4906, 785, 1), + (4909, 786, 1), + (4912, 787, 1), + (4915, 794, 1), + (4916, 794, 1), + (4917, 794, 1), + (4921, 117, 1), + (4922, 117, 1), + (4923, 117, 1), + (4924, 740, 3), + (4925, 740, 3), + (4926, 740, 3), + (4931, 173, 8), + (4932, 173, 8), + (4933, 173, 8), + (4951, 439, 3), + (4952, 439, 3), + (4953, 439, 3), + (4975, 30, 1), + (4976, 30, 1), + (4977, 30, 1), + (4978, 30, 1), + (4979, 30, 1), + (4986, 82, 1), + (4987, 82, 1), + (4988, 82, 1), + (4989, 82, 3), + (4990, 82, 3), + (4991, 82, 3), + (5010, 35, 1), + (5011, 35, 1), + (5012, 35, 1), + (5038, 30, 3), + (5039, 30, 3), + (5040, 30, 3), + (5041, 6001, 11), + (5042, 6001, 11), + (5043, 6001, 11), + (5061, 45, 1), + (5069, 224, 3), + (5070, 19, 3), + (5071, 19, 3), + (5072, 19, 3), + (5080, 255, 5), + (5081, 255, 5), + (5082, 255, 5), + (5098, 73, 2), + (5118, 396, 1), + (5119, 396, 1), + (5120, 396, 1), + (5127, 261, 3), + (5128, 261, 3), + (5129, 261, 3), + (5133, 23, 3), + (5134, 23, 3), + (5135, 23, 3), + (5136, 496, 5), + (5137, 496, 5), + (5138, 496, 5), + (5139, 496, 5), + (5140, 496, 5), + (5251, 447, 3), + (5252, 447, 3), + (5253, 447, 3), + (5264, 278, 5), + (5265, 278, 5), + (5266, 278, 5), + (5267, 278, 5), + (5268, 278, 5), + (5270, 87, 1), + (5271, 87, 1), + (5272, 87, 1), + (5286, 23, 3), + (5287, 23, 3), + (5288, 23, 3), + (5311, 185, 6), + (5312, 185, 6), + (5313, 185, 6), + (5330, 1685, 1), + (5333, 1685, 1), + (5336, 1685, 1), + (5339, 1685, 1), + (5342, 1685, 1), + (5347, 1685, 1), + (5348, 1685, 1), + (5350, 707, 4), + (5350, 1685, 1), + (5353, 1685, 1), + (5356, 1685, 1), + (5357, 1685, 1), + (5360, 1685, 1), + (5363, 447, 3), + (5363, 1685, 1), + (5366, 1685, 1), + (5369, 1685, 1), + (5513, 58, 1), + (5514, 58, 1), + (5515, 58, 1), + (5529, 19, 7), + (5530, 19, 7), + (5531, 19, 7), + (5532, 19, 7), + (5533, 19, 7), + (5542, 30, 6), + (5543, 30, 6), + (5544, 30, 6), + (5545, 310, 6), + (5546, 310, 6), + (5547, 310, 6), + (5548, 311, 3), + (5549, 311, 3), + (5550, 311, 3), + (5551, 309, 6), + (5552, 309, 6), + (5553, 309, 6), + (5571, 23, 3), + (5572, 23, 3), + (5573, 23, 3), + (5574, 114, 6), + (5575, 114, 6), + (5576, 114, 6), + (5577, 215, 6), + (5578, 215, 6), + (5579, 215, 6), + (5595, 309, 3), + (5596, 309, 3), + (5597, 309, 3), + (5607, 794, 1), + (5608, 794, 1), + (5609, 794, 1), + (5617, 23, 3), + (5618, 23, 3), + (5619, 23, 3), + (5702, 30, 1), + (5703, 30, 1), + (5704, 30, 1), + (5705, 30, 1), + (5706, 30, 1), + (5759, 374, 3), + (5760, 374, 3), + (5761, 374, 3), + (5762, 374, 3), + (5763, 374, 3), + (5791, 19, 3), + (5792, 19, 3), + (5793, 19, 3), + (5797, 396, 1), + (5798, 396, 1), + (5799, 396, 1), + (5803, 255, 5), + (5804, 255, 5), + (5805, 255, 5), + (5806, 30, 3), + (5807, 30, 3), + (5808, 30, 3), + (5825, 45, 1), + (5826, 185, 6), + (5827, 185, 6), + (5828, 185, 6), + (5854, 217, 1), + (5855, 217, 1), + (5856, 217, 1), + (5857, 173, 3), + (5858, 173, 3), + (5859, 173, 3), + (5869, 57, 1), + (5871, 57, 1), + (5872, 57, 1), + (5880, 60, 1), + (5881, 60, 1), + (5882, 60, 1), + (5886, 58, 1), + (5887, 58, 1), + (5888, 58, 1), + (5892, 784, 1), + (5893, 785, 1), + (5894, 786, 1), + (5895, 787, 1), + (5939, 278, 5), + (5940, 278, 5), + (5941, 278, 5), + (5942, 278, 5), + (5943, 278, 5), + (5944, 740, 3), + (5945, 740, 3), + (5946, 740, 3), + (5947, 175, 3), + (5948, 175, 3), + (5949, 175, 3), + (5950, 175, 3), + (5951, 175, 3), + (5952, 175, 3), + (5954, 68, 1), + (5955, 68, 1), + (5956, 68, 1), + (5969, 6001, 11), + (5970, 6001, 11), + (5971, 6001, 11), + (5972, 6001, 11), + (5973, 6000, 11), + (5984, 702, 1), + (6017, 82, 1), + (6018, 82, 1), + (6019, 82, 1), + (6026, 826, 1), + (6027, 826, 1), + (6028, 826, 1), + (6042, 439, 3), + (6043, 439, 3), + (6044, 439, 3), + (6054, 173, 8), + (6055, 173, 8), + (6056, 173, 8), + (6063, 87, 1), + (6064, 87, 1), + (6065, 87, 1), + (6088, 392, 1), + (6089, 392, 1), + (6090, 392, 1), + (6092, 447, 3), + (6093, 447, 3), + (6094, 447, 3), + (6102, 224, 3), + (6106, 308, 3), + (6107, 308, 3), + (6108, 308, 3), + (6109, 308, 3), + (6110, 308, 3), + (6111, 308, 3), + (6130, 120, 1), + (6131, 120, 1), + (6132, 120, 1), + (6136, 300, 6), + (6158, 308, 3), + (6159, 308, 3), + (6160, 308, 3), + (6209, 245, 3), + (6210, 245, 3), + (6211, 245, 3), + (6228, 404, 1), + (6229, 404, 1), + (6230, 404, 1), + (6231, 404, 1), + (6233, 43, 1), + (6234, 43, 1), + (6235, 43, 1), + (6260, 98, 1), + (6261, 98, 1), + (6262, 98, 1), + (6272, 672, 1), + (6273, 672, 1), + (6274, 672, 1), + (6275, 790, 1), + (6276, 790, 1), + (6277, 790, 1), + (6302, 3710, 1), + (6303, 3710, 1), + (6304, 3710, 1), + (6319, 107, 1), + (6320, 107, 1), + (6321, 107, 1), + (6333, 125, 1), + (6337, 553, 1), + (6338, 553, 1), + (6339, 553, 1), + (6340, 777, 1), + (6341, 777, 1), + (6342, 777, 1), + (6346, 494, 3), + (6347, 494, 3), + (6348, 494, 3), + (6349, 500, 3), + (6350, 500, 3), + (6351, 500, 3), + (6352, 409, 3), + (6353, 409, 3), + (6354, 409, 3), + (6380, 128, 3), + (6381, 128, 3), + (6382, 128, 3), + (6400, 187, 5), + (6401, 187, 5), + (6402, 187, 5), + (6403, 23, 3), + (6404, 23, 3), + (6405, 23, 3), + (6439, 41, 1), + (6440, 41, 1), + (6441, 420, 1), + (6442, 362, 1), + (6443, 362, 1), + (6445, 176, 1), + (6446, 176, 1), + (6447, 176, 1), + (6478, 3800, 1), + (6479, 3800, 1), + (6480, 3800, 1), + (6481, 36, 1), + (6482, 36, 1), + (6483, 36, 1), + (6484, 558, 1), + (6485, 558, 1), + (6486, 558, 1), + (6499, 611, 1), + (6500, 526, 3), + (6501, 526, 3), + (6502, 526, 3), + (6503, 172, 1), + (6504, 172, 1), + (6505, 172, 1), + (6506, 172, 1), + (6514, 404, 1), + (6515, 404, 1), + (6516, 404, 1), + (6517, 20, 1), + (6528, 107, 1), + (6630, 278, 5), + (6631, 278, 5), + (6632, 278, 5), + (6633, 278, 5), + (6634, 278, 5), + (6636, 358, 3), + (6637, 358, 3), + (6638, 358, 3), + (6668, 672, 3), + (6669, 672, 3), + (6670, 672, 3), + (6697, 857, 1), + (6698, 857, 1), + (6699, 857, 1), + (6700, 857, 1), + (6701, 857, 1), + (6703, 171, 1), + (6704, 171, 1), + (6705, 171, 1), + (6712, 177, 1), + (6713, 177, 1), + (6714, 177, 1), + (6715, 177, 1), + (6716, 177, 1), + (6755, 184, 3), + (6756, 184, 3), + (6757, 184, 3), + (6819, 524, 1), + (6820, 524, 1), + (6821, 524, 1), + (6823, 320, 1), + (6824, 320, 1), + (6825, 320, 1), + (6826, 320, 1), + (6827, 320, 1), + (6870, 544, 1), + (6871, 544, 1), + (6872, 544, 1), + (6873, 3837, 3), + (6874, 3837, 3), + (6875, 3837, 3), + (6876, 259, 3), + (6877, 259, 3), + (6878, 259, 3), + (6900, 465, 3), + (6901, 465, 3), + (6902, 465, 3), + (6903, 465, 3), + (6904, 465, 3), + (6908, 499, 1), + (6909, 499, 1), + (6910, 499, 1), + (6930, 611, 1), + (6935, 465, 3), + (6936, 465, 3), + (6937, 465, 3), + (6941, 962, 1), + (6942, 962, 1), + (6943, 962, 1), + (6944, 962, 1), + (6945, 962, 1), + (6977, 3817, 1), + (6978, 3817, 1), + (6979, 3817, 1), + (6980, 128, 1), + (6981, 128, 1), + (6982, 128, 1), + (6983, 245, 3), + (6988, 985, 1), + (6989, 985, 1), + (6990, 985, 1), + (7005, 789, 1), + (7006, 789, 1), + (7007, 789, 1), + (7033, 804, 1), + (7034, 804, 1), + (7035, 804, 1), + (7036, 3646, 1), + (7037, 3646, 1), + (7038, 3646, 1), + (7050, 26, 3), + (7051, 26, 3), + (7052, 26, 3), + (7053, 26, 3), + (7054, 26, 3), + (7055, 26, 3), + (7063, 26, 3), + (7064, 26, 3), + (7065, 26, 3), + (7100, 254, 3), + (7101, 254, 3), + (7102, 254, 3), + (7103, 286, 1), + (7104, 286, 1), + (7105, 286, 1), + (7116, 110, 1), + (7117, 110, 1), + (7118, 110, 1), + (7122, 435, 3), + (7123, 435, 3), + (7124, 435, 3), + (7125, 435, 3), + (7126, 435, 3), + (7128, 109, 1), + (7129, 109, 1), + (7130, 109, 1), + (7134, 439, 3), + (7135, 439, 3), + (7136, 439, 3), + (7137, 672, 1), + (7138, 672, 1), + (7139, 672, 1), + (7184, 1685, 1), + (7199, 175, 3), + (7200, 175, 3), + (7201, 175, 3), + (7204, 278, 5), + (7205, 278, 5), + (7206, 278, 5), + (7207, 278, 5), + (7208, 278, 5), + (7215, 68, 1), + (7216, 68, 1), + (7232, 114, 6), + (7233, 114, 6), + (7234, 114, 6), + (7246, 794, 1), + (7247, 794, 1), + (7248, 794, 1), + (7253, 784, 1), + (7254, 785, 1), + (7255, 786, 1), + (7256, 787, 1), + (7260, 60, 1), + (7261, 60, 1), + (7262, 60, 1), + (7263, 58, 1), + (7264, 58, 1), + (7265, 58, 1), + (7266, 125, 1), + (7276, 217, 1), + (7277, 217, 1), + (7278, 217, 1), + (7285, 173, 3), + (7286, 173, 3), + (7287, 173, 3), + (7288, 409, 3), + (7289, 409, 3), + (7290, 409, 3), + (7291, 173, 8), + (7292, 173, 8), + (7293, 173, 8), + (7301, 19, 3), + (7302, 19, 3), + (7303, 19, 3), + (7310, 255, 5), + (7311, 255, 5), + (7312, 255, 5), + (7316, 41, 1), + (7317, 41, 1), + (7323, 254, 3), + (7324, 254, 3), + (7325, 254, 3), + (7326, 286, 1), + (7327, 286, 1), + (7328, 286, 1), + (7329, 6001, 11), + (7330, 6001, 11), + (7331, 6001, 11), + (7335, 702, 1), + (7359, 82, 1), + (7360, 82, 1), + (7361, 82, 1), + (7378, 82, 3), + (7379, 82, 3), + (7380, 82, 3), + (7381, 82, 3), + (7382, 82, 3), + (7383, 82, 3), + (7390, 87, 1), + (7391, 87, 1), + (7392, 87, 1), + (7407, 31, 3), + (7414, 185, 6), + (7415, 185, 6), + (7416, 185, 6), + (7433, 30, 1), + (7434, 30, 1), + (7435, 30, 1), + (7436, 30, 1), + (7437, 30, 1), + (7445, 187, 5), + (7446, 187, 5), + (7447, 187, 5), + (7448, 553, 1), + (7449, 553, 1), + (7450, 553, 1), + (7451, 777, 1), + (7452, 777, 1), + (7453, 777, 1), + (7466, 224, 3), + (7472, 447, 3), + (7473, 447, 3), + (7474, 447, 3), + (7478, 245, 3), + (7497, 128, 3), + (7498, 128, 3), + (7499, 128, 3), + (7554, 19, 7), + (7555, 19, 7), + (7556, 19, 7), + (7557, 19, 7), + (7558, 19, 7), + (7562, 30, 6), + (7563, 30, 6), + (7564, 30, 6), + (7581, 215, 6), + (7582, 215, 6), + (7583, 215, 6), + (7615, 494, 3), + (7616, 494, 3), + (7617, 494, 3), + (7618, 500, 3), + (7619, 500, 3), + (7620, 500, 3), + (7621, 20, 1), + (7622, 26, 3), + (7623, 26, 3), + (7624, 26, 3), + (7631, 309, 3), + (7632, 309, 3), + (7633, 309, 3), + (7650, 310, 6), + (7651, 310, 6), + (7652, 310, 6), + (7653, 311, 3), + (7654, 311, 3), + (7655, 311, 3), + (7656, 309, 6), + (7657, 309, 6), + (7658, 309, 6), + (7659, 153, 3), + (7660, 153, 3), + (7661, 153, 3), + (7664, 170, 3), + (7665, 170, 3), + (7666, 170, 3), + (7667, 170, 3), + (7668, 170, 3), + (7682, 68, 1), + (7686, 435, 3), + (7687, 435, 3), + (7688, 435, 3), + (7691, 224, 3), + (7695, 862, 3), + (7696, 862, 3), + (7697, 862, 3), + (7700, 310, 3), + (7701, 310, 3), + (7702, 310, 3), + (7704, 3707, 1), + (7705, 3707, 1), + (7706, 3707, 1), + (7707, 87, 1), + (7708, 87, 1), + (7709, 87, 1), + (7710, 702, 1), + (7711, 702, 1), + (7712, 3826, 1), + (7715, 901, 1), + (7716, 901, 1), + (7717, 901, 1), + (7718, 125, 1), + (7722, 19, 7), + (7723, 19, 7), + (7724, 19, 7), + (7725, 19, 7), + (7726, 19, 7), + (7733, 195, 3), + (7743, 184, 1), + (7744, 184, 1), + (7745, 184, 1), + (7748, 13, 5), + (7749, 13, 5), + (7750, 13, 5), + (7751, 2234, 1), + (7752, 2234, 1), + (7753, 2234, 1), + (7754, 85, 1), + (7757, 9403, 1), + (7758, 9403, 1), + (7759, 9403, 1), + (7760, 824, 1), + (7761, 824, 1), + (7762, 824, 1), + (7765, 7689, 1), + (7766, 7689, 1), + (7767, 7689, 1), + (7768, 7689, 1), + (7770, 19, 3), + (7771, 19, 3), + (7772, 19, 3), + (7773, 19, 3), + (7774, 19, 3), + (7775, 19, 3), + (7822, 1154, 1), + (7823, 1154, 1), + (7824, 1154, 1), + (7825, 1154, 1), + (7826, 1154, 1), + (7827, 1404, 3), + (7832, 60, 1), + (7833, 60, 1), + (7834, 60, 1), + (7835, 60, 1), + (7836, 60, 1), + (7842, 19, 7), + (7843, 19, 7), + (7844, 19, 7), + (7940, 558, 1), + (7941, 558, 1), + (7942, 558, 1), + (7943, 39, 1), + (7944, 41, 1), + (7951, 19, 3), + (7952, 19, 3), + (7953, 19, 3), + (7983, 520, 1), + (7984, 520, 1), + (7985, 520, 1), + (7986, 705, 1), + (7987, 705, 1), + (7988, 705, 1), + (7989, 1092, 1), + (7990, 1092, 1), + (7991, 1092, 1), + (7992, 1092, 1), + (7993, 39, 1), + (7994, 39, 1), + (7995, 39, 1), + (8031, 791, 1), + (8032, 791, 1), + (8033, 791, 1), + (8035, 521, 1), + (8036, 521, 1), + (8037, 521, 1), + (8069, 160, 4), + (8070, 160, 4), + (8071, 160, 4), + (8076, 565, 1), + (8077, 565, 1), + (8078, 565, 1), + (8079, 565, 1), + (8080, 565, 1), + (8081, 565, 1), + (8082, 208, 1), + (8083, 208, 1), + (8084, 208, 1), + (8195, 3707, 1), + (8196, 3707, 1), + (8197, 3707, 1), + (8198, 210, 1), + (8199, 210, 1), + (8200, 210, 1), + (8204, 153, 1), + (8205, 153, 1), + (8206, 153, 1), + (8207, 285, 1), + (8208, 285, 1), + (8209, 285, 1), + (8220, 3812, 1), + (8224, 516, 3), + (8225, 516, 3), + (8226, 516, 3), + (8260, 1211, 1), + (8263, 142, 20), + (8264, 142, 20), + (8265, 142, 20), + (8266, 142, 20), + (8267, 142, 20), + (8268, 142, 20), + (8269, 142, 20), + (8270, 142, 20), + (8271, 142, 20), + (8272, 142, 20), + (8273, 142, 20), + (8274, 142, 20), + (8275, 142, 20), + (8276, 142, 20), + (8277, 142, 20), + (8278, 142, 20), + (8279, 142, 20), + (8280, 142, 20), + (8281, 142, 20), + (8282, 142, 20), + (8283, 142, 20), + (8284, 142, 20), + (8285, 142, 20), + (8286, 142, 20), + (8287, 142, 20), + (8288, 142, 20), + (8289, 142, 20), + (8290, 142, 20), + (8291, 142, 20), + (8292, 142, 20), + (8293, 142, 20), + (8294, 142, 20), + (8295, 142, 20), + (8296, 142, 20), + (8297, 142, 20), + (8303, 309, 6), + (8309, 31, 3), + (8310, 31, 3), + (8311, 31, 3), + (8312, 110, 1), + (8317, 8205, 1), + (8318, 8205, 1), + (8319, 199, 1), + (8320, 199, 1), + (8321, 199, 1), + (8332, 861, 1), + (8333, 861, 1), + (8334, 861, 1), + (8335, 1041, 1), + (8336, 1041, 1), + (8337, 1041, 1), + (8338, 1041, 1), + (8339, 1041, 1), + (8344, 215, 6), + (8345, 215, 6), + (8346, 215, 6), + (8347, 616, 1), + (8348, 616, 1), + (8349, 616, 1), + (8351, 142, 20), + (8352, 142, 20), + (8353, 142, 20), + (8354, 142, 20), + (8355, 142, 20), + (8356, 142, 20), + (8357, 142, 20), + (8358, 142, 20), + (8359, 142, 20), + (8360, 142, 20), + (8361, 142, 20), + (8362, 142, 20), + (8363, 142, 20), + (8364, 142, 20), + (8365, 142, 20), + (8366, 142, 20), + (8367, 142, 20), + (8368, 142, 20), + (8369, 142, 20), + (8370, 142, 20), + (8371, 142, 20), + (8372, 142, 20), + (8373, 142, 20), + (8374, 142, 20), + (8375, 142, 20), + (8376, 142, 20), + (8377, 142, 20), + (8378, 142, 20), + (8379, 142, 20), + (8380, 142, 20), + (8381, 142, 20), + (8382, 142, 20), + (8383, 142, 20), + (8384, 142, 20), + (8385, 142, 20), + (8386, 142, 20), + (8387, 142, 20), + (8388, 142, 20), + (8389, 142, 20), + (8390, 142, 20), + (8391, 142, 20), + (8392, 142, 20), + (8393, 142, 20), + (8394, 142, 20), + (8395, 142, 20), + (8396, 142, 20), + (8397, 142, 20), + (8398, 142, 20), + (8399, 142, 20), + (8400, 142, 20), + (8401, 142, 20), + (8402, 142, 20), + (8403, 142, 20), + (8404, 142, 20), + (8405, 142, 20), + (8406, 142, 20), + (8407, 142, 20), + (8408, 142, 20), + (8409, 142, 20), + (8410, 142, 20), + (8411, 142, 20), + (8412, 142, 20), + (8413, 142, 20), + (8414, 142, 20), + (8415, 142, 20), + (8416, 142, 20), + (8417, 142, 20), + (8418, 142, 20), + (8419, 142, 20), + (8420, 142, 20), + (8421, 516, 3), + (8427, 254, 3), + (8428, 254, 3), + (8429, 254, 3), + (9103, 1350, 3), + (9104, 1350, 3), + (9105, 1350, 3), + (9106, 1351, 3), + (9107, 1351, 3), + (9108, 1351, 3), + (9112, 1390, 3), + (9113, 1390, 3), + (9114, 1390, 3), + (9115, 1391, 3), + (9116, 1391, 3), + (9117, 1391, 3), + (9121, 1370, 3), + (9122, 1370, 3), + (9123, 1370, 3), + (9124, 1371, 3), + (9125, 1371, 3), + (9126, 1371, 3), + (9130, 1380, 3), + (9131, 1380, 3), + (9132, 1380, 3), + (9133, 1381, 3), + (9134, 1381, 3), + (9135, 1381, 3), + (9139, 1470, 3), + (9140, 1470, 3), + (9141, 1470, 3), + (9142, 1471, 3), + (9143, 1471, 3), + (9144, 1471, 3), + (9148, 1480, 3), + (9149, 1480, 3), + (9150, 1480, 3), + (9151, 1481, 3), + (9152, 1481, 3), + (9153, 1481, 3), + (9157, 1490, 3), + (9158, 1490, 3), + (9159, 1490, 3), + (9160, 1491, 3), + (9161, 1491, 3), + (9162, 1491, 3), + (9166, 1460, 3), + (9167, 1460, 3), + (9168, 1460, 3), + (9169, 1461, 3), + (9170, 1461, 3), + (9171, 1461, 3), + (9175, 1450, 3), + (9176, 1450, 3), + (9177, 1450, 3), + (9178, 1451, 3), + (9179, 1451, 3), + (9180, 1451, 3), + (9184, 1440, 3), + (9185, 1440, 3), + (9186, 1440, 3), + (9187, 1441, 3), + (9188, 1441, 3), + (9189, 1441, 3), + (9193, 1420, 3), + (9194, 1420, 3), + (9195, 1420, 3), + (9196, 1421, 3), + (9197, 1421, 3), + (9198, 1421, 3), + (9202, 1430, 3), + (9203, 1430, 3), + (9204, 1430, 3), + (9205, 1431, 3), + (9206, 1431, 3), + (9207, 1431, 3), + (9211, 1400, 3), + (9212, 1400, 3), + (9213, 1400, 3), + (9214, 1401, 3), + (9215, 1401, 3), + (9216, 1401, 3), + (9220, 1360, 3), + (9221, 1360, 3), + (9222, 1360, 3), + (9223, 1361, 3), + (9224, 1361, 3), + (9225, 1361, 3), + (9229, 1500, 3), + (9230, 1500, 3), + (9231, 1500, 3), + (9232, 1501, 3), + (9233, 1501, 3), + (9234, 1501, 3), + (9238, 1410, 3), + (9239, 1410, 3), + (9240, 1410, 3), + (9241, 1411, 3), + (9242, 1411, 3), + (9243, 1411, 3), + (9300, 1300, 3), + (9301, 1300, 3), + (9302, 1300, 3), + (9303, 1300, 6), + (9304, 1300, 6), + (9305, 1300, 6), + (9306, 1300, 9), + (9307, 1300, 9), + (9308, 1300, 9), + (9309, 1313, 3), + (9310, 1313, 3), + (9311, 1313, 3), + (9312, 1313, 6), + (9313, 1313, 6), + (9314, 1313, 6), + (9315, 1313, 9), + (9316, 1313, 9), + (9317, 1313, 9), + (9318, 1302, 3), + (9319, 1302, 3), + (9320, 1302, 3), + (9321, 1302, 6), + (9322, 1302, 6), + (9323, 1302, 6), + (9324, 1302, 9), + (9325, 1302, 9), + (9326, 1302, 9), + (9327, 1303, 3), + (9328, 1303, 3), + (9329, 1303, 3), + (9330, 1303, 6), + (9331, 1303, 6), + (9332, 1303, 6), + (9333, 1303, 9), + (9334, 1303, 9), + (9335, 1303, 9), + (9336, 1301, 3), + (9337, 1301, 3), + (9338, 1301, 3), + (9339, 1301, 6), + (9340, 1301, 6), + (9341, 1301, 6), + (9342, 1301, 9), + (9343, 1301, 9), + (9344, 1301, 9), + (9345, 1312, 3), + (9346, 1312, 3), + (9347, 1312, 3), + (9348, 1312, 6), + (9349, 1312, 6), + (9350, 1312, 6), + (9351, 1312, 9), + (9352, 1312, 9), + (9353, 1312, 9), + (9354, 1315, 3), + (9355, 1315, 3), + (9356, 1315, 3), + (9357, 1315, 6), + (9358, 1315, 6), + (9359, 1315, 6), + (9360, 1315, 9), + (9361, 1315, 9), + (9362, 1315, 9), + (9363, 1310, 3), + (9364, 1310, 3), + (9365, 1310, 3), + (9366, 1310, 6), + (9367, 1310, 6), + (9368, 1310, 6), + (9369, 1310, 9), + (9370, 1310, 9), + (9371, 1310, 9), + (9372, 1311, 3), + (9373, 1311, 3), + (9374, 1311, 3), + (9375, 1311, 6), + (9376, 1311, 6), + (9377, 1311, 6), + (9378, 1311, 9), + (9379, 1311, 9), + (9380, 1311, 9), + (9381, 1309, 3), + (9382, 1309, 3), + (9383, 1309, 3), + (9384, 1309, 6), + (9385, 1309, 6), + (9386, 1309, 6), + (9387, 1309, 9), + (9388, 1309, 9), + (9389, 1309, 9), + (9390, 1308, 3), + (9391, 1308, 3), + (9392, 1308, 3), + (9393, 1308, 6), + (9394, 1308, 6), + (9395, 1308, 6), + (9396, 1308, 9), + (9397, 1308, 9), + (9398, 1308, 9), + (9399, 1307, 3), + (9400, 1307, 3), + (9401, 1307, 3), + (9402, 1307, 6), + (9403, 1307, 6), + (9404, 1307, 6), + (9405, 1307, 9), + (9406, 1307, 9), + (9407, 1307, 9), + (9408, 1304, 3), + (9409, 1304, 3), + (9410, 1304, 3), + (9411, 1304, 6), + (9412, 1304, 6), + (9413, 1304, 6), + (9414, 1304, 9), + (9415, 1304, 9), + (9416, 1304, 9), + (9417, 1305, 3), + (9418, 1305, 3), + (9419, 1305, 3), + (9420, 1305, 6), + (9421, 1305, 6), + (9422, 1305, 6), + (9423, 1305, 9), + (9424, 1305, 9), + (9425, 1305, 9), + (9426, 1306, 3), + (9427, 1306, 3), + (9428, 1306, 3), + (9429, 1306, 6), + (9430, 1306, 6), + (9431, 1306, 6), + (9432, 1306, 9), + (9433, 1306, 9), + (9434, 1306, 9), + (9435, 1314, 3), + (9436, 1314, 3), + (9437, 1314, 3), + (9438, 1314, 6), + (9439, 1314, 6), + (9440, 1314, 6), + (9441, 1314, 9), + (9442, 1314, 9), + (9443, 1314, 9), + (9500, 72, 1), + (10016, 19, 3), + (10017, 19, 3), + (10018, 19, 3), + (10030, 558, 1), + (10031, 558, 1), + (10032, 558, 1), + (10038, 19, 3), + (10039, 19, 3), + (10040, 19, 3), + (10041, 358, 3), + (10042, 358, 3), + (10043, 358, 3), + (10047, 6001, 11), + (10048, 6001, 11), + (10049, 6001, 11), + (10064, 82, 3), + (10065, 82, 3), + (10066, 82, 3), + (10067, 82, 3), + (10068, 82, 3), + (10069, 82, 3), + (10070, 278, 5), + (10071, 278, 5), + (10072, 278, 5), + (10073, 278, 5), + (10074, 278, 5), + (10093, 185, 6), + (10105, 170, 3), + (10106, 170, 3), + (10107, 170, 3), + (10108, 170, 3), + (10109, 170, 3), + (10110, 520, 1), + (10111, 520, 1), + (10112, 520, 1), + (10130, 544, 1), + (10131, 544, 1), + (10132, 544, 1), + (10133, 3837, 3), + (10134, 3837, 3), + (10135, 3837, 3), + (10136, 259, 3), + (10137, 259, 3), + (10138, 259, 3), + (10150, 187, 5), + (10151, 187, 5), + (10152, 187, 5), + (10153, 553, 1), + (10154, 553, 1), + (10155, 553, 1), + (10165, 439, 3), + (10166, 439, 3), + (10167, 439, 3), + (10176, 171, 1), + (10177, 171, 1), + (10178, 171, 1), + (10182, 177, 1), + (10183, 177, 1), + (10184, 177, 1), + (10185, 177, 1), + (10186, 177, 1), + (10197, 447, 3), + (10198, 447, 3), + (10199, 447, 3), + (10203, 524, 1), + (10204, 524, 1), + (10205, 524, 1), + (10206, 320, 1), + (10207, 320, 1), + (10209, 175, 3), + (10210, 175, 3), + (10211, 175, 3), + (10213, 278, 5), + (10214, 278, 5), + (10215, 278, 5), + (10216, 278, 5), + (10217, 278, 5), + (10249, 208, 1), + (10250, 208, 1), + (10251, 208, 1), + (10255, 784, 1), + (10256, 785, 1), + (10257, 786, 1), + (10258, 787, 1), + (10262, 58, 1), + (10263, 58, 1), + (10264, 58, 1), + (10271, 173, 3), + (10272, 173, 3), + (10273, 173, 3), + (10274, 173, 8), + (10275, 173, 8), + (10276, 173, 8), + (10282, 791, 1), + (10283, 791, 1), + (10284, 791, 1), + (10285, 521, 1), + (10286, 521, 1), + (10287, 521, 1), + (10308, 128, 3), + (10309, 128, 3), + (10310, 128, 3), + (10329, 3701, 1), + (10330, 199, 3), + (10332, 943, 3), + (10336, 941, 1), + (10337, 941, 1), + (10338, 941, 1), + (10354, 6001, 17), + (10389, 841, 1), + (10390, 841, 1), + (10391, 841, 1), + (10396, 705, 4), + (10397, 1092, 4), + (10398, 3701, 1), + (10399, 3701, 1), + (10413, 207, 1), + (10414, 207, 1), + (10415, 207, 1), + (10416, 207, 1), + (10417, 207, 1), + (10426, 185, 18), + (10427, 519, 15), + (10428, 173, 8), + (10429, 173, 8), + (10430, 173, 8), + (10431, 791, 1), + (10432, 791, 1), + (10433, 791, 1), + (10434, 792, 1), + (10435, 792, 1), + (10436, 792, 1), + (10450, 19, 9), + (10451, 19, 9), + (10452, 19, 9), + (10456, 3800, 1), + (10457, 3800, 1), + (10458, 3800, 1), + (10462, 396, 1), + (10463, 396, 1), + (10464, 391, 9), + (10465, 391, 9), + (10466, 391, 9), + (10468, 19, 9), + (10469, 19, 9), + (10470, 558, 1), + (10471, 558, 1), + (10472, 558, 1), + (10473, 26, 3), + (10474, 26, 3), + (10475, 26, 3), + (10476, 26, 3), + (10477, 26, 3), + (10510, 705, 1), + (10511, 185, 3), + (10512, 185, 3), + (10513, 185, 3), + (10514, 519, 3), + (10515, 519, 3), + (10516, 519, 3), + (10519, 3213, 1), + (10522, 3732, 1), + (10527, 1400, 1), + (10532, 1401, 1), + (10537, 1402, 1), + (10548, 605, 13), + (10554, 263, 1), + (10555, 263, 1), + (10556, 263, 1), + (10557, 1120, 1), + (10558, 1120, 1), + (10559, 1120, 1), + (10560, 1120, 1), + (10561, 3551, 1), + (10562, 3551, 1), + (10563, 3551, 1), + (10564, 217, 1), + (10565, 217, 1), + (10566, 217, 1), + (10576, 109, 1), + (10579, 3646, 1), + (10580, 3646, 1), + (10588, 601, 1), + (10589, 601, 1), + (10590, 601, 1), + (10591, 601, 1), + (10592, 601, 1), + (10610, 265, 5), + (10611, 265, 5), + (10612, 265, 5), + (10621, 180, 3), + (10622, 180, 3), + (10623, 30, 3), + (10624, 30, 3), + (10625, 30, 3), + (10626, 702, 1), + (10646, 3826, 1), + (10657, 276, 3), + (10658, 276, 3), + (10659, 276, 3), + (10666, 98, 1), + (10667, 98, 1), + (10668, 98, 1), + (10670, 19, 9), + (10708, 6001, 11), + (10709, 6001, 11), + (10710, 6001, 11), + (10711, 30, 6), + (10712, 30, 6), + (10713, 30, 6), + (10714, 873, 1), + (10715, 873, 1), + (10717, 184, 1), + (10718, 184, 1), + (10719, 872, 1), + (10720, 872, 1), + (10721, 872, 1), + (10722, 778, 1), + (10723, 778, 1), + (10724, 778, 1), + (10725, 778, 1), + (10726, 778, 1), + (10727, 2235, 1), + (10728, 2235, 1), + (10730, 870, 1), + (10731, 870, 1), + (10733, 219, 1), + (10734, 219, 1), + (10735, 219, 1), + (10750, 286, 1), + (10751, 286, 1), + (10752, 7108, 1), + (10753, 286, 1), + (10789, 10424, 1), + (10790, 705, 4), + (10791, 1092, 4), + (10800, 462, 3), + (10801, 462, 3), + (10802, 462, 3), + (10903, 125, 1), + (10904, 125, 1), + (10905, 125, 1), + (10909, 7007, 1), + (10910, 7007, 1), + (10911, 7007, 1), + (10915, 823, 3), + (10916, 823, 3), + (10917, 823, 3), + (10951, 447, 3), + (10952, 447, 3), + (10953, 447, 3), + (10954, 662, 3), + (10955, 662, 3), + (10956, 662, 3), + (11011, 3710, 1), + (11012, 3710, 1), + (11013, 3710, 1), + (11014, 3899, 1), + (11015, 3899, 1), + (11016, 3899, 1), + (11020, 3899, 1), + (11050, 452, 3), + (11051, 452, 3), + (11052, 452, 3), + (11053, 500, 3), + (11054, 500, 3), + (11059, 452, 3), + (11060, 452, 3), + (11077, 986, 1), + (11078, 988, 1), + (11079, 987, 1), + (11088, 505, 1), + (11089, 505, 1), + (11090, 505, 1), + (11091, 505, 1), + (12422, 1202, 1), + (12432, 23, 3), + (12433, 23, 3), + (12434, 23, 3), + (12435, 23, 3), + (12436, 23, 3), + (12437, 23, 3), + (12475, 7003, 1), + (12476, 7003, 1), + (12477, 7003, 1), + (12478, 3705, 9), + (12479, 3705, 9), + (12480, 3705, 9), + (12523, 114, 6), + (12526, 215, 6), + (12527, 215, 6), + (12528, 215, 6), + (12529, 358, 3), + (12530, 358, 3), + (12531, 358, 3), + (12553, 23, 3), + (12554, 23, 3), + (12555, 23, 3), + (12556, 23, 3), + (12557, 23, 3), + (12558, 23, 3), + (12582, 9400, 1), + (12583, 9400, 1), + (12584, 9400, 1), + (12587, 9403, 1), + (12588, 9403, 1), + (12589, 9403, 1), + (12600, 3514, 1), + (12606, 13, 5), + (12610, 310, 3), + (12626, 1410, 3), + (12629, 1411, 3), + (12632, 1412, 3), + (12635, 428, 2), + (12639, 519, 3), + (12642, 185, 3), + (12645, 519, 1), + (12646, 185, 1), + (12664, 3728, 1), + (12673, 420, 1), + (12677, 17, 3), + (12679, 276, 3), + (12680, 276, 3), + (12681, 276, 3), + (12697, 30, 6), + (12698, 30, 6), + (12699, 30, 6), + (12713, 8202, 1), + (12714, 8202, 1), + (12715, 8202, 1), + (12716, 3702, 1), + (12717, 3702, 1), + (12718, 3702, 1), + (12719, 3702, 1), + (12720, 3506, 1), + (12721, 3506, 1), + (12722, 3506, 1), + (12723, 3506, 1), + (12727, 359, 3), + (12728, 359, 3), + (12729, 359, 3), + (12730, 941, 1), + (12731, 941, 1), + (12732, 941, 1), + (12733, 943, 3), + (12734, 259, 3), + (12735, 259, 3), + (12736, 259, 3), + (12737, 3701, 1), + (12738, 3701, 1), + (12739, 3701, 1), + (12749, 30, 1), + (12750, 30, 1), + (12751, 30, 1), + (12757, 68, 1), + (12758, 68, 1), + (12759, 68, 1), + (12760, 175, 3), + (12761, 175, 3), + (12762, 175, 3), + (12773, 1580, 1), + (12774, 1580, 1), + (12775, 1580, 1), + (12776, 1580, 1), + (12777, 1580, 1), + (12779, 826, 1), + (12780, 826, 1), + (12781, 826, 1), + (12782, 826, 1), + (12783, 826, 1), + (12784, 826, 1), + (12798, 278, 5), + (12799, 278, 5), + (12800, 278, 5), + (12831, 128, 1), + (12834, 128, 1), + (12835, 128, 1), + (12840, 3817, 1), + (12841, 3817, 1), + (12849, 8303, 1), + (12860, 23, 3), + (12863, 23, 3), + (12865, 1155, 1), + (12866, 639, 1), + (12867, 6106, 6), + (12871, 452, 3), + (12872, 452, 3), + (12874, 451, 1), + (12876, 7003, 1), + (12877, 7003, 1), + (12878, 7003, 1), + (12881, 172, 1), + (12886, 304, 5), + (12887, 303, 5), + (12888, 305, 5), + (12889, 501, 1), + (12890, 507, 1), + (12892, 509, 3), + (12894, 1122, 1), + (12899, 57, 1), + (12900, 57, 1), + (12902, 1380, 1), + (12903, 1380, 1), + (12907, 1381, 1), + (12908, 1381, 1), + (12912, 1382, 1), + (12913, 1382, 1), + (12934, 173, 3), + (12956, 784, 1), + (12957, 786, 1), + (12958, 787, 1), + (12959, 785, 1), + (12964, 596, 1), + (12965, 597, 1), + (12968, 1041, 1), + (12969, 1041, 1), + (12970, 1041, 1), + (12977, 1041, 1), + (12978, 1041, 1), + (12979, 1041, 1), + (12980, 1041, 1), + (12981, 1041, 1), + (12992, 707, 4), + (12993, 707, 4), + (12994, 707, 4), + (13001, 9504, 1), + (13002, 9504, 1), + (13003, 9504, 1), + (13004, 153, 9), + (13005, 171, 1), + (13006, 171, 1), + (13007, 171, 1), + (13008, 859, 1), + (13009, 3730, 1), + (13010, 47, 1), + (13011, 47, 1), + (13012, 47, 1), + (13013, 446, 1), + (13014, 446, 1), + (13015, 446, 1), + (13017, 3815, 10), + (13018, 3815, 10), + (13019, 3815, 10), + (13023, 309, 6), + (13055, 8400, 1), + (13067, 643, 1), + (13072, 3514, 1), + (13073, 3514, 1), + (13074, 310, 6), + (13075, 310, 6), + (13076, 310, 6), + (13077, 311, 3), + (13078, 311, 3), + (13090, 20, 1), + (13092, 82, 1), + (13093, 82, 1), + (13094, 82, 1), + (13104, 87, 1), + (13105, 87, 1), + (13106, 87, 1), + (13130, 1685, 1), + (13140, 391, 9), + (13141, 391, 9), + (13142, 391, 9), + (13143, 500, 1), + (13144, 500, 1), + (13145, 500, 1), + (13146, 494, 1), + (13147, 494, 1), + (13148, 494, 1), + (13155, 705, 1), + (13166, 822, 1), + (13167, 822, 1), + (13168, 822, 1), + (13170, 128, 3), + (13190, 187, 5), + (13191, 187, 5), + (13192, 187, 5), + (13196, 3837, 3), + (13197, 3837, 3), + (13198, 3837, 3), + (13203, 199, 3), + (13204, 8261, 1), + (13205, 8261, 1), + (13206, 8261, 1), + (13213, 439, 3), + (13214, 439, 3), + (13215, 439, 3), + (13216, 439, 3), + (13217, 439, 3), + (13222, 3514, 1), + (13223, 3514, 1), + (13241, 173, 8), + (13244, 46, 1), + (13247, 409, 3), + (13253, 58, 1), + (13254, 58, 1), + (13255, 58, 1), + (13256, 224, 3), + (13257, 224, 3), + (13258, 224, 3), + (13262, 102, 1), + (13263, 102, 1), + (13264, 102, 1), + (13271, 1685, 1), + (13272, 1685, 1), + (13295, 20, 1), + (13308, 26, 3), + (13326, 310, 6), + (13326, 1685, 1), + (13332, 30, 6), + (13363, 1685, 1), + (13383, 1685, 1), + (13385, 1685, 1), + (13388, 1685, 1), + (13389, 1685, 1), + (13396, 1685, 1), + (13396, 3815, 10), + (13401, 1685, 1), + (13404, 259, 6), + (13404, 1685, 1), + (13410, 1685, 1), + (13413, 1685, 1), + (13415, 1092, 1), + (13415, 1685, 1), + (13416, 626, 1), + (13416, 1685, 1), + (13419, 1685, 1), + (13425, 1685, 1), + (13444, 1685, 1), + (13447, 1685, 1), + (13449, 1685, 1), + (13449, 11073, 1), + (13454, 1685, 1), + (13463, 458, 1), + (13463, 1685, 1), + (13466, 1685, 1), + (13467, 1685, 1), + (13468, 1685, 1), + (13472, 1685, 1), + (13474, 444, 1), + (13474, 1685, 1), + (13477, 1685, 1), + (13483, 1685, 1), + (13484, 1685, 1), + (13485, 1685, 1), + (13490, 1685, 1), + (13492, 199, 3), + (13492, 1685, 1), + (13493, 1685, 1), + (13496, 187, 5), + (13496, 1685, 1), + (13499, 30, 1), + (13499, 1685, 1), + (13502, 259, 3), + (13502, 1685, 1), + (13505, 1685, 1), + (13508, 1685, 1), + (13511, 1685, 1), + (13511, 3837, 3), + (13514, 1685, 1), + (13517, 941, 1), + (13517, 1685, 1), + (13520, 1685, 1), + (13521, 1685, 1), + (13524, 1685, 1), + (13527, 1685, 1), + (13528, 1685, 1), + (13529, 1685, 1), + (13530, 1685, 1), + (13533, 1685, 1), + (13542, 184, 3), + (13542, 1685, 1), + (13545, 1685, 1), + (13546, 1685, 1), + (13549, 1685, 1), + (13556, 1685, 1), + (13562, 872, 1), + (13562, 1685, 1), + (13565, 1685, 1), + (13565, 3804, 1), + (13568, 876, 1), + (13568, 1685, 1), + (13571, 1685, 1), + (13575, 1685, 1), + (13578, 1685, 1), + (13584, 1685, 1), + (13585, 1685, 1), + (13585, 3826, 1), + (13586, 1685, 1), + (13589, 30, 3), + (13589, 1685, 1), + (13590, 30, 3), + (13590, 1685, 1), + (13592, 702, 1), + (13592, 1685, 1), + (13595, 1685, 1), + (13595, 6001, 11), + (13598, 1685, 1), + (13601, 1685, 1), + (13604, 1685, 1), + (13607, 1685, 1), + (13610, 1685, 1), + (13613, 1685, 1), + (13616, 1685, 1), + (13617, 1685, 1), + (13618, 1685, 1), + (13619, 1685, 1), + (13621, 278, 5), + (13621, 1685, 1), + (13624, 1685, 1), + (13627, 1685, 1), + (13628, 1685, 1), + (13630, 1685, 1), + (13633, 1685, 1), + (13646, 1668, 1), + (13646, 1685, 1), + (13650, 1685, 1), + (13653, 1685, 1), + (13656, 1685, 1), + (13663, 1685, 1), + (13667, 500, 1), + (13667, 1685, 1), + (13670, 1685, 1), + (13673, 1158, 1), + (13674, 7754, 1), + (13675, 278, 5), + (13675, 1685, 1), + (13678, 1685, 1), + (13682, 1685, 1), + (13683, 1685, 1), + (13684, 1685, 1), + (13685, 1685, 1), + (13686, 1685, 1), + (13687, 1685, 1), + (13688, 1685, 1), + (13689, 751, 1), + (13689, 1685, 1), + (13692, 1685, 1), + (13693, 1685, 1), + (13695, 1685, 1), + (13698, 784, 1), + (13698, 1685, 1), + (13701, 785, 1), + (13701, 1685, 1), + (13704, 787, 1), + (13704, 1685, 1), + (13707, 58, 1), + (13707, 1685, 1), + (13710, 1685, 1), + (13713, 1685, 1), + (13718, 1685, 1), + (13720, 1685, 1), + (13723, 58, 1), + (13723, 1685, 1), + (13726, 1685, 1), + (13727, 25, 3), + (13727, 1685, 1), + (13734, 217, 1), + (13734, 1685, 1), + (13753, 534, 1), + (13753, 1685, 1), + (13758, 602, 1), + (13758, 1685, 1), + (13763, 1685, 1), + (13764, 535, 1), + (13764, 1685, 1), + (13767, 1685, 1), + (13770, 1685, 1), + (13771, 1685, 1), + (13773, 310, 3), + (13773, 1685, 1), + (13774, 310, 3), + (13774, 1685, 1), + (13775, 310, 3), + (13775, 1685, 1), + (13779, 1685, 1), + (13782, 439, 3), + (13782, 1685, 1), + (13785, 1685, 1), + (13789, 1685, 1), + (13790, 1685, 1), + (13792, 1685, 1), + (13795, 1685, 1), + (13798, 1685, 1), + (13804, 1685, 1), + (13807, 1685, 1), + (13810, 1685, 1), + (13813, 1685, 1), + (13816, 1685, 1), + (13819, 1685, 1), + (13820, 1685, 1), + (13823, 1685, 1), + (13826, 1685, 1), + (13829, 1685, 1), + (13832, 1685, 1), + (13835, 1685, 1), + (13838, 1685, 1), + (13841, 1685, 1), + (13845, 1685, 1), + (13872, 1685, 1), + (13873, 961, 1), + (13873, 1685, 1), + (13878, 609, 1), + (13878, 1685, 1), + (13881, 387, 1), + (13881, 1685, 1), + (13889, 1012, 1), + (13889, 1685, 1), + (13899, 1685, 1), + (13905, 1685, 1), + (13908, 1685, 1), + (13911, 1685, 1), + (13914, 1685, 1), + (13917, 606, 1), + (13917, 1685, 1), + (13920, 125, 1), + (13920, 1685, 1), + (13933, 142, 20), + (13943, 142, 20), + (13953, 142, 20), + (13963, 142, 20), + (13973, 142, 20), + (13983, 142, 20), + (13993, 142, 20), + (14003, 1685, 1), + (14006, 30, 6), + (14006, 1685, 1), + (14009, 1685, 1), + (14010, 1685, 1), + (14011, 1685, 1), + (14011, 10394, 1), + (14016, 1685, 1), + (14016, 6001, 17), + (14018, 1684, 1), + (14019, 1685, 1), + (14026, 1685, 1), + (14029, 1685, 1), + (14032, 1685, 1), + (14037, 804, 1), + (14037, 1685, 1), + (14040, 300, 1), + (14040, 1685, 1), + (14043, 1685, 1), + (14046, 87, 1), + (14046, 1685, 1), + (14051, 1685, 1), + (14052, 1685, 1), + (14053, 1685, 1), + (14054, 1685, 1), + (14055, 1685, 1), + (14056, 1685, 1), + (14059, 1685, 1), + (14062, 821, 1), + (14062, 1685, 1), + (14065, 1685, 1), + (14065, 3215, 1), + (14068, 1685, 1), + (14068, 3216, 1), + (14071, 1685, 1), + (14076, 1685, 1), + (14080, 1685, 1), + (14081, 1685, 1), + (14082, 1685, 1), + (14085, 741, 1), + (14085, 1685, 1), + (14088, 769, 1), + (14088, 1685, 1), + (14091, 701, 1), + (14091, 1685, 1), + (14094, 1685, 1), + (14097, 1685, 1), + (14100, 1685, 1), + (14101, 1685, 1), + (14111, 1685, 1), + (14112, 1685, 1), + (14115, 872, 1), + (14115, 1685, 1), + (14129, 1685, 1), + (14130, 1685, 1), + (14132, 1685, 1), + (14132, 2234, 1), + (14135, 1685, 1), + (14138, 1685, 1), + (14139, 1685, 1), + (14140, 1685, 1), + (14141, 1685, 1), + (14144, 1685, 1), + (14144, 3515, 1), + (14148, 1685, 1), + (14151, 1685, 1), + (14154, 276, 3), + (14154, 1685, 1), + (14157, 1685, 1), + (14160, 1685, 1), + (14160, 7001, 1), + (14163, 1685, 1), + (14163, 7001, 1), + (14166, 945, 1), + (14166, 1685, 1), + (14169, 1685, 1), + (14173, 1685, 1), + (14176, 1685, 1), + (14176, 8261, 1), + (14179, 359, 1), + (14179, 1685, 1), + (14180, 1685, 1), + (14181, 1685, 1), + (14181, 3837, 12), + (14186, 809, 5), + (14186, 1685, 1), + (14189, 1685, 1), + (14192, 1685, 1), + (14196, 465, 3), + (14196, 1685, 1), + (14199, 499, 1), + (14199, 1685, 1), + (14200, 1685, 1), + (14203, 1685, 1), + (14206, 1685, 1), + (14207, 1685, 1), + (14208, 1685, 1), + (14208, 7689, 1), + (14209, 1685, 1), + (14210, 1685, 1), + (14213, 1065, 1), + (14213, 1685, 1), + (14218, 1685, 1), + (14221, 1685, 1), + (14222, 224, 3), + (14222, 1685, 1), + (14223, 47, 1), + (14223, 1685, 1), + (14224, 1685, 1), + (14225, 177, 1), + (14225, 1685, 1), + (14229, 135, 1), + (14231, 1685, 1), + (14232, 1685, 1), + (14233, 1685, 1), + (14234, 1685, 1), + (14237, 1685, 1), + (14238, 1041, 1), + (14238, 1685, 1), + (14241, 386, 1), + (14241, 1685, 1), + (14244, 1685, 1), + (14249, 1685, 1), + (14254, 386, 1), + (14254, 1685, 1), + (14256, 1685, 1), + (14259, 384, 1), + (14259, 1685, 1), + (14265, 939, 1), + (14265, 1685, 1), + (14272, 1685, 1), + (14273, 1685, 1), + (14274, 1685, 1), + (14275, 1685, 1), + (14278, 985, 1), + (14278, 1685, 1), + (14280, 57, 1), + (14280, 1685, 1), + (14281, 291, 1), + (14281, 1685, 1), + (14282, 1685, 1), + (14282, 3812, 1), + (14283, 1685, 1), + (14286, 753, 1), + (14286, 1685, 1), + (14289, 1685, 1), + (14292, 207, 1), + (14292, 1685, 1), + (14295, 1685, 1), + (14295, 3816, 1), + (14304, 1685, 1), + (14304, 8341, 1), + (14307, 1685, 1), + (14308, 431, 1), + (14308, 1685, 1), + (14311, 430, 1), + (14311, 1685, 1), + (14314, 901, 1), + (14314, 1685, 1), + (14318, 1685, 1), + (14318, 7703, 1), + (14321, 1685, 1), + (14322, 1685, 1), + (14323, 1685, 1), + (14324, 1685, 1), + (14328, 1154, 1), + (14328, 1685, 1), + (14331, 515, 1), + (14331, 1685, 1), + (14338, 308, 3), + (14338, 1685, 1), + (14341, 748, 1), + (14341, 1685, 1), + (14346, 1685, 1), + (14349, 215, 6), + (14352, 175, 3), + (14352, 1685, 1), + (14355, 1685, 1), + (14358, 1685, 1), + (14359, 1685, 1), + (14360, 1685, 1), + (14361, 23, 3), + (14364, 173, 1), + (14364, 1685, 1), + (14372, 1685, 1), + (14690, 756, 1), + (14733, 786, 1), + (15100, 467, 1), + (15105, 131, 1), + (15113, 130, 1), + (15120, 800, 1), + (15132, 660, 1), + (15135, 660, 1), + (15141, 30, 3), + (15147, 701, 13), + (15154, 659, 1), + (15158, 657, 1), + (15159, 770, 1), + (15162, 659, 1), + (15168, 657, 1), + (15174, 9400, 1), + (15179, 7755, 1), + (15182, 9403, 1), + (15204, 390, 1), + (15207, 323, 1), + (15210, 1041, 1), + (15220, 622, 1), + (15223, 624, 1), + (15226, 621, 1), + (15229, 623, 1), + (15253, 462, 1), + (15258, 184, 1), + (15270, 7003, 1), + (15280, 778, 1), + (15295, 2234, 1), + (15314, 36, 1), + (15317, 35, 1), + (15320, 558, 1), + (15341, 19, 3), + (15342, 8500, 1), + (15344, 38, 1), + (15348, 9504, 1), + (15356, 149, 1), + (15358, 151, 1), + (15359, 50, 1), + (15363, 447, 3), + (15371, 3729, 1), + (15377, 638, 1), + (15389, 935, 1), + (15396, 23, 3), + (15397, 494, 3), + (15403, 8604, 1), + (15406, 3817, 1), + (15414, 241, 1), + (15421, 245, 3), + (15424, 247, 1), + (15424, 982, 6), + (15466, 3551, 1), + (15469, 1120, 1), + (15472, 521, 1), + (15478, 578, 1), + (15481, 398, 24), + (15482, 261, 1), + (15485, 495, 9), + (15486, 534, 3), + (15526, 3702, 1), + (15549, 244, 1), + (15552, 3710, 1), + (15571, 351, 1), + (15579, 826, 1), + (15591, 2899, 1), + (15598, 759, 1), + (15598, 1150, 1), + (15598, 1151, 1), + (15598, 1152, 1), + (15605, 639, 1), + (15606, 160, 4), + (15622, 23, 3), + (15632, 789, 1), + (15639, 749, 1), + (15640, 822, 2), + (15746, 804, 1), + (15778, 87, 1), + (15833, 2045, 1), + (15836, 463, 1), + (15839, 19, 9), + (15855, 153, 9), + (15891, 988, 1), + (15893, 987, 1), + (15895, 986, 1), + (15961, 3701, 1), + (16062, 263, 1), + (16071, 2209, 3), + (16087, 53, 1), + (16094, 43, 1), + (16103, 7703, 1), + (16105, 684, 1), + (16106, 684, 1), + (16107, 684, 1), + (16117, 309, 6), + (16124, 3711, 1), + (16128, 3711, 1), + (16131, 73, 1), + (16137, 10394, 1), + (16140, 489, 1), + (16156, 137, 1), + (16159, 2045, 1), + (16163, 260, 1), + (16163, 7747, 1), + (16164, 358, 3), + (16176, 337, 1), + (16180, 584, 1), + (16185, 9202, 1), + (16185, 9203, 1), + (16189, 823, 3), + (16203, 403, 1), + (16211, 152, 1), + (16218, 403, 1), + (16221, 393, 1), + (16225, 219, 1), + (16238, 443, 1), + (16246, 245, 3), + (16249, 17, 3), + (16257, 470, 20), + (16266, 790, 1), + (16287, 669, 1), + (16297, 553, 1), + (16300, 668, 1), + (16303, 3506, 1), + (16306, 777, 1), + (16336, 1257, 1), + (16339, 773, 1), + (16342, 1257, 1), + (16371, 60, 1), + (16380, 2061, 1), + (16386, 2064, 1), + (16392, 2202, 1), + (16489, 23, 3), + (16604, 180, 3), + (16644, 747, 1), + (16666, 742, 1), + (16730, 82, 3), + (16745, 706, 1), + (17206, 601, 1), + (17209, 111, 1), + (17212, 10367, 1), + (17218, 744, 1), + (17235, 3826, 1), + (17280, 8205, 1), + (17281, 359, 1), + (17288, 41, 1), + (17289, 1062, 1), + (17307, 2047, 1), + (17317, 1270, 1), + (17334, 1041, 1), + (17336, 148, 1), + (17339, 760, 1), + (17342, 148, 1), + (17350, 170, 3), + (17361, 405, 1), + (17361, 426, 1), + (17364, 935, 4), + (17375, 1239, 1), + (17391, 98, 1), + (17409, 120, 1), + (17414, 673, 1), + (17436, 372, 1), + (17439, 372, 1), + (17441, 309, 3), + (17476, 462, 3), + (17492, 840, 1), + (17495, 9702, 1), + (17515, 3841, 1), + (17517, 441, 1), + (17522, 764, 1), + (17533, 677, 1), + (17549, 8700, 1); + +RENAME TABLE `character_alternate_abilities` TO `character_alternate_abilities_old`; +DROP TABLE IF EXISTS `character_alternate_abilities`; +CREATE TABLE IF NOT EXISTS `character_alternate_abilities` ( + `id` int(11) unsigned NOT NULL DEFAULT '0', + `aa_id` smallint(11) unsigned NOT NULL DEFAULT '0', + `aa_value` smallint(11) unsigned NOT NULL DEFAULT '0', + `charges` smallint(11) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`,`aa_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +ALTER TABLE `character_data` ADD COLUMN `aa_points_spent_old` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `aa_points_spent`; +ALTER TABLE `character_data` ADD COLUMN `aa_points_old` INT(11) UNSIGNED NOT NULL DEFAULT '0' AFTER `aa_points`; + +UPDATE `character_data` SET `aa_points_spent_old` = `aa_points_spent`, `aa_points_old` = `aa_points`; + + -- sanity checks since if someone never logged in after the db conversion there is junk data + -- I don't have a good way of addressing this so I keep the old data in aa_points_spent_old and aa_points_old and character_alternate_abilities_old + -- for anyone who wants to personally polish up their player data +UPDATE `character_data` SET `aa_points_spent` = 2700 WHERE `aa_points_spent` > 2700; +UPDATE `character_data` SET `aa_points` = 5000 WHERE `aa_points` > 5000; + + -- another sanity check, give people a few levels below 51 to keep their points +UPDATE `character_data` SET `aa_points_spent` = 0 WHERE `level` < 48; +UPDATE `character_data` SET `aa_points` = 0 WHERE `level` < 48; + + -- aa refund here +UPDATE `character_data` SET `aa_points` = `aa_points_spent` + `aa_points`; +UPDATE `character_data` SET `aa_points_spent` = 0; diff --git a/utils/sql/git/required/2015_09_25_inventory_snapshots.sql b/utils/sql/git/required/2015_09_25_inventory_snapshots.sql new file mode 100644 index 000000000..12b167e8b --- /dev/null +++ b/utils/sql/git/required/2015_09_25_inventory_snapshots.sql @@ -0,0 +1,46 @@ +CREATE TABLE `inventory_snapshots` ( + `time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `charid` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `itemid` INT(11) UNSIGNED NULL DEFAULT '0', + `charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0', + `color` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0', + `augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0', + `instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', + `custom_data` TEXT NULL, + `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`time_index`, `charid`, `slotid`) +) +COLLATE='latin1_swedish_ci' +ENGINE=InnoDB; + +ALTER TABLE `character_data` ADD COLUMN `e_last_invsnapshot` INT(11) UNSIGNED NOT NULL DEFAULT '0'; + +INSERT INTO `rule_values` VALUES +(1, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'), +(2, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'), +(4, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'), +(5, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'), +(10, 'Character:ActiveInvSnapshots', 'false', 'Takes a periodic snapshot of inventory contents from online players'), +(1, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'), +(2, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'), +(4, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'), +(5, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'), +(10, 'Character:InvSnapshotMinIntervalM', '180', 'Minimum time (in minutes) between inventory snapshots'), +(1, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'), +(2, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'), +(4, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'), +(5, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'), +(10, 'Character:InvSnapshotMinRetryM', '30', 'Time (in minutes) to re-attempt an inventory snapshot after a failure'), +(1, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries'), +(2, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries'), +(4, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries'), +(5, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries'), +(10, 'Character:InvSnapshotHistoryD', '30', 'Time (in days) to keep snapshot entries'); diff --git a/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql b/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql new file mode 100644 index 000000000..14efd90a5 --- /dev/null +++ b/utils/sql/git/required/2015_11_01_perl_event_export_settings.sql @@ -0,0 +1,95 @@ +CREATE TABLE `perl_event_export_settings` ( + `event_id` int(11) NOT NULL, + `event_description` varchar(150) DEFAULT NULL, + `export_qglobals` smallint(11) DEFAULT '0', + `export_mob` smallint(11) DEFAULT '0', + `export_zone` smallint(11) DEFAULT '0', + `export_item` smallint(11) DEFAULT '0', + `export_event` smallint(11) DEFAULT '0', + PRIMARY KEY (`event_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- ---------------------------- +-- Records of perl_event_export_settings +-- ---------------------------- +INSERT INTO `perl_event_export_settings` VALUES ('0', 'EVENT_SAY', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('1', 'EVENT_ITEM', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('2', 'EVENT_DEATH', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('3', 'EVENT_SPAWN', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('4', 'EVENT_ATTACK', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('5', 'EVENT_COMBAT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('6', 'EVENT_AGGRO', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('7', 'EVENT_SLAY', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('8', 'EVENT_NPC_SLAY', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('9', 'EVENT_WAYPOINT_ARRIVE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('10', 'EVENT_WAYPOINT_DEPART', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('11', 'EVENT_TIMER', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('12', 'EVENT_SIGNAL', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('13', 'EVENT_HP', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('14', 'EVENT_ENTER', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('15', 'EVENT_EXIT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('16', 'EVENT_ENTERZONE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('17', 'EVENT_CLICKDOOR', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('18', 'EVENT_LOOT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('19', 'EVENT_ZONE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('20', 'EVENT_LEVEL_UP', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('21', 'EVENT_KILLED_MERIT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('22', 'EVENT_CAST_ON', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('23', 'EVENT_TASKACCEPTED', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('24', 'EVENT_TASK_STAGE_COMPLETE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('25', 'EVENT_TASK_UPDATE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('26', 'EVENT_TASK_COMPLETE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('27', 'EVENT_TASK_FAIL', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('28', 'EVENT_AGGRO_SAY', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('29', 'EVENT_PLAYER_PICKUP', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('30', 'EVENT_POPUPRESPONSE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('31', 'EVENT_ENVIRONMENTAL_DAMAGE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('32', 'EVENT_PROXIMITY_SAY', '1', '1', '1', '1', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('33', 'EVENT_CAST', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('34', 'EVENT_CAST_BEGIN', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('35', 'EVENT_SCALE_CALC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('36', 'EVENT_ITEM_ENTER_ZONE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('37', 'EVENT_TARGET_CHANGE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('38', 'EVENT_HATE_LIST', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('39', 'EVENT_SPELL_EFFECT_CLIENT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('40', 'EVENT_SPELL_EFFECT_NPC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('41', 'EVENT_SPELL_EFFECT_BUFF_TIC_CLIENT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('42', 'EVENT_SPELL_EFFECT_BUFF_TIC_NPC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('43', 'EVENT_SPELL_FADE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('44', 'EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('45', 'EVENT_COMBINE_SUCCESS', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('46', 'EVENT_COMBINE_FAILURE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('47', 'EVENT_ITEM_CLICK', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('48', 'EVENT_ITEM_CLICK_CAST', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('49', 'EVENT_GROUP_CHANGE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('50', 'EVENT_FORAGE_SUCCESS', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('51', 'EVENT_FORAGE_FAILURE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('52', 'EVENT_FISH_START', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('53', 'EVENT_FISH_SUCCESS', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('54', 'EVENT_FISH_FAILURE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('55', 'EVENT_CLICK_OBJECT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('56', 'EVENT_DISCOVER_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('57', 'EVENT_DISCONNECT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('58', 'EVENT_CONNECT', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('59', 'EVENT_ITEM_TICK', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('60', 'EVENT_DUEL_WIN', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('61', 'EVENT_DUEL_LOSE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('62', 'EVENT_ENCOUNTER_LOAD', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('63', 'EVENT_ENCOUNTER_UNLOAD', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('64', 'EVENT_SAY', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('65', 'EVENT_DROP_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('66', 'EVENT_DESTROY_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('67', 'EVENT_FEIGN_DEATH', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('68', 'EVENT_WEAPON_PROC', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('69', 'EVENT_EQUIP_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('70', 'EVENT_UNEQUIP_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('71', 'EVENT_AUGMENT_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('72', 'EVENT_UNAUGMENT_ITEM', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('73', 'EVENT_AUGMENT_INSERT', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('74', 'EVENT_AUGMENT_REMOVE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('75', 'EVENT_ENTER_AREA', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('76', 'EVENT_LEAVE_AREA', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('77', 'EVENT_RESPAWN', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('78', 'EVENT_DEATH_COMPLETE', '1', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('79', 'EVENT_UNHANDLED_OPCODE', '0', '1', '1', '0', '1'); +INSERT INTO `perl_event_export_settings` VALUES ('80', 'EVENT_TICK', '0', '1', '1', '0', '1'); diff --git a/utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql b/utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql new file mode 100644 index 000000000..fe09523c7 --- /dev/null +++ b/utils/sql/git/required/2015_11_02_ai_idle_no_spell_recast_default_changes.sql @@ -0,0 +1,2 @@ +UPDATE `rule_values` SET `rule_value` = '6000' WHERE `rule_value` = '500' AND `rule_name` = 'Spells:AI_IdleNoSpellMinRecast'; +UPDATE `rule_values` SET `rule_value` = '60000' WHERE `rule_value` = '2000' AND `rule_name` = 'Spells:AI_IdleNoSpellMaxRecast'; \ No newline at end of file diff --git a/utils/sql/git/required/2015_12_01_spell_scribe_restriction_rule.sql b/utils/sql/git/required/2015_12_01_spell_scribe_restriction_rule.sql new file mode 100644 index 000000000..277e66882 --- /dev/null +++ b/utils/sql/git/required/2015_12_01_spell_scribe_restriction_rule.sql @@ -0,0 +1,7 @@ +INSERT INTO `rule_values` VALUES ('0', 'Character:RestrictSpellScribing', 'false', 'Restricts spell scribing to allowable races/classes of spell scroll, if true'); +INSERT INTO `rule_values` VALUES ('1', 'Character:RestrictSpellScribing', 'false', 'Restricts spell scribing to allowable races/classes of spell scroll, if true'); +INSERT INTO `rule_values` VALUES ('2', 'Character:RestrictSpellScribing', 'false', 'Restricts spell scribing to allowable races/classes of spell scroll, if true'); +INSERT INTO `rule_values` VALUES ('3', 'Character:RestrictSpellScribing', 'false', 'Restricts spell scribing to allowable races/classes of spell scroll, if true'); +INSERT INTO `rule_values` VALUES ('4', 'Character:RestrictSpellScribing', 'false', 'Restricts spell scribing to allowable races/classes of spell scroll, if true'); +INSERT INTO `rule_values` VALUES ('5', 'Character:RestrictSpellScribing', 'false', 'Restricts spell scribing to allowable races/classes of spell scroll, if true'); +INSERT INTO `rule_values` VALUES ('10', 'Character:RestrictSpellScribing', 'false', 'Restricts spell scribing to allowable races/classes of spell scroll, if true'); diff --git a/utils/sql/git/required/2015_12_07_command_settings.sql b/utils/sql/git/required/2015_12_07_command_settings.sql new file mode 100644 index 000000000..470525d4c --- /dev/null +++ b/utils/sql/git/required/2015_12_07_command_settings.sql @@ -0,0 +1,11 @@ +RENAME TABLE `commands` to `commands_old`; + +CREATE TABLE `command_settings` ( + `command` varchar(128) NOT NULL DEFAULT '', + `access` int(11) NOT NULL DEFAULT '0', + `aliases` varchar(256) NOT NULL DEFAULT '', + PRIMARY KEY (`command`), + UNIQUE KEY `UK_command_settings_1` (`command`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `command_settings` VALUES ('acceptrules', '90', ''),('advnpcspawn', '150', 'advnpc'),('aggro', '80', ''),('aggrozone', '200', ''),('ai', '100', ''),('appearance', '150', ''),('apply_shared_memory', '250', ''),('attack', '150', ''),('augmentitem', '250', 'aug'),('ban', '200', ''),('beard', '80', ''),('beardcolor', '80', ''),('bestz', '80', ''),('bind', '80', ''),('camerashake', '80', ''),('castspell', '90', 'cast'),('chat', '200', ''),('checklos', '50', 'los'),('clearinvsnapshots', '200', ''),('connectworldserver', '200', 'connectworld'),('corpse', '90', ''),('crashtest', '201', ''),('cvs', '80', ''),('damage', '150', ''),('date', '150', ''),('dbspawn2', '100', ''),('delacct', '200', ''),('deletegraveyard', '200', ''),('delpetition', '80', ''),('depop', '100', ''),('depopzone', '100', ''),('details', '80', ''),('disablerecipe', '80', ''),('disarmtrap', '80', ''),('distance', '80', ''),('doanim', '50', ''),('emote', '150', ''),('emotesearch', '80', ''),('emoteview', '80', ''),('enablerecipe', '80', ''),('equipitem', '50', ''),('face', '80', ''),('findnpctype', '90', 'fn'),('findspell', '90', 'fs|spfind'),('findzone', '1', 'fz'),('fixmob', '150', ''),('flag', '201', ''),('flagedit', '150', ''),('flags', '80', ''),('flymode', '80', ''),('fov', '80', ''),('freeze', '100', ''),('gassign', '150', ''),('gender', '90', ''),('getplayerburiedcorpsecount', '100', ''),('getvariable', '200', ''),('ginfo', '20', ''),('giveitem', '150', 'gi'),('givemoney', '150', ''),('globalview', '80', ''),('gm', '80', ''),('gmspeed', '80', ''),('goto', '80', ''),('grid', '150', ''),('guild', '80', 'guilds'),('guildapprove', '0', ''),('guildcreate', '0', ''),('guildlist', '0', ''),('hair', '80', ''),('haircolor', '80', ''),('haste', '100', ''),('hatelist', '80', ''),('heal', '100', ''),('helm', '80', ''),('help', '0', ''),('heritage', '80', ''),('heromodel', '200', 'hm'),('hideme', '80', 'gmhideme'),('hotfix', '250', ''),('hp', '90', ''),('incstat', '200', ''),('instance', '80', ''),('interrogateinv', '0', ''),('interrupt', '50', ''),('invsnapshot', '80', ''),('invul', '80', 'invulnerable'),('ipban', '201', ''),('iplookup', '200', ''),('iteminfo', '10', ''),('itemsearch', '90', 'fi|finditem|search'),('kick', '80', ''),('kill', '80', ''),('lastname', '80', ''),('level', '150', ''),('listnpcs', '90', ''),('listpetition', '80', ''),('load_shared_memory', '250', ''),('loc', '0', ''),('lock', '200', ''),('logs', '250', ''),('logtest', '250', ''),('makepet', '150', ''),('mana', '100', ''),('maxskills', '90', ''),('memspell', '100', ''),('merchant_close_shop', '100', 'close_shop'),('merchant_open_shop', '100', 'open_shop'),('modifynpcstat', '150', ''),('motd', '200', ''),('movechar', '80', ''),('myskills', '0', ''),('mysqltest', '250', ''),('mysql', '255', ''),('mystats', '50', ''),('name', '100', ''),('netstats', '200', ''),('npccast', '90', ''),('npcedit', '150', ''),('npcemote', '80', ''),('npcloot', '150', ''),('npcsay', '80', ''),('npcshout', '90', ''),('npcspawn', '100', ''),('npcspecialattk', '150', 'npcspecialatk|npcspecialattack'),('npcstats', '90', ''),('npctype_cache', '250', ''),('npctypespawn', '90', 'dbspawn'),('nukebuffs', '100', ''),('nukeitem', '150', ''),('object', '100', ''),('oocmute', '200', ''),('opcode', '250', ''),('path', '200', ''),('peekinv', '80', ''),('peqzone', '2', ''),('permaclass', '150', ''),('permagender', '150', ''),('permarace', '150', ''),('petitioninfo', '20', ''),('pf', '0', ''),('picklock', '0', ''),('pvp', '80', ''),('qglobal', '150', ''),('questerrors', '0', ''),('race', '90', ''),('raidloot', '0', ''),('randomfeatures', '90', ''),('refreshgroup', '0', ''),('reloadaa', '200', ''),('reloadallrules', '80', ''),('reloademote', '80', ''),('reloadlevelmods', '255', ''),('reloadperlexportsettings', '255', ''),('reloadqst', '80', 'reloadquest|rq'),('reloadrulesworld', '80', ''),('reloadstatic', '150', ''),('reloadtitles', '150', ''),('reloadworld', '255', ''),('reloadzps', '150', 'reloadzonepoints'),('repop', '90', ''),('repopclose', '100', ''),('resetaa', '100', ''),('resetaa_timer', '200', ''),('revoke', '80', ''),('rules', '200', ''),('save', '80', ''),('scribespell', '90', ''),('scribespells', '100', ''),('sendzonespawns', '200', ''),('sensetrap', '0', ''),('serverinfo', '201', ''),('serverrules', '90', ''),('setaapts', '100', 'setaapoints'),('setaaxp', '100', 'setaaexp'),('setadventurepoints', '200', ''),('setanim', '200', ''),('setcrystals', '100', ''),('setfaction', '170', ''),('setgraveyard', '200', ''),('setlanguage', '50', ''),('setlsinfo', '0', ''),('setpass', '150', ''),('setpvppoints', '100', ''),('setskill', '90', ''),('setskillall', '100', 'setallskill|setallskills'),('setstartzone', '80', ''),('setstat', '255', ''),('setxp', '100', 'setexp'),('showbonusstats', '50', ''),('showbuffs', '80', ''),('shownumhits', '0', ''),('showskills', '50', ''),('showspellslist', '100', ''),('showstats', '80', ''),('shutdown', '200', ''),('size', '90', ''),('spawn', '150', ''),('spawnfix', '80', ''),('spawnstatus', '150', ''),('spellinfo', '10', ''),('spoff', '0', ''),('spon', '0', ''),('stun', '100', ''),('summon', '80', ''),('summonburiedplayercorpse', '100', ''),('summonitem', '150', 'si'),('suspend', '100', ''),('task', '150', ''),('tattoo', '80', ''),('tempname', '100', ''),('texture', '150', ''),('time', '90', ''),('timers', '200', ''),('timezone', '90', ''),('title', '100', ''),('titlesuffix', '50', ''),('traindisc', '100', ''),('tune', '100', ''),('undyeme', '0', ''),('unfreeze', '100', ''),('unlock', '150', ''),('unscribespell', '90', ''),('unscribespells', '100', ''),('untraindisc', '180', ''),('untraindiscs', '180', ''),('uptime', '10', ''),('version', '0', ''),('viewnpctype', '100', ''),('viewpetition', '80', ''),('wc', '200', ''),('weather', '90', ''),('worldshutdown', '200', ''),('wp', '150', ''),('wpadd', '150', ''),('wpinfo', '150', ''),('xtargets', '250', ''),('zclip', '150', ''),('zcolor', '150', ''),('zheader', '150', ''),('zone', '80', ''),('zonebootup', '100', ''),('zoneinstance', '80', ''),('zonelock', '200', ''),('zoneshutdown', '200', ''),('zonespawn', '250', ''),('zonestatus', '150', ''),('zopp', '250', ''),('zsafecoords', '150', ''),('zsave', '200', ''), ('zsky', '150', ''),('zstats', '80', ''),('zunderworld', '80', ''),('zuwcoords', '80', ''); diff --git a/utils/sql/git/required/2015_12_17_eqtime.sql b/utils/sql/git/required/2015_12_17_eqtime.sql new file mode 100644 index 000000000..c264edf27 --- /dev/null +++ b/utils/sql/git/required/2015_12_17_eqtime.sql @@ -0,0 +1,11 @@ +DROP TABLE IF EXISTS `eqtime`; +CREATE TABLE `eqtime` ( + `minute` tinyint(4) not null default 0, + `hour` tinyint(4) not null default 0, + `day` tinyint(4) not null default 0, + `month` tinyint(4) not null default 0, + `year` int(4) not null default 0, + `realtime` int(11) not null default 0 +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +INSERT INTO eqtime values (0,1,28,12,3766,1444035661); \ No newline at end of file diff --git a/utils/sql/git/required/2015_12_21_items_updates_evoitem.sql b/utils/sql/git/required/2015_12_21_items_updates_evoitem.sql new file mode 100644 index 000000000..195df8a87 --- /dev/null +++ b/utils/sql/git/required/2015_12_21_items_updates_evoitem.sql @@ -0,0 +1,8 @@ +ALTER TABLE `items` + ADD COLUMN `evoitem` INT(11) NOT NULL DEFAULT '0' AFTER `purity`, + ADD COLUMN `evoid` INT(11) NOT NULL DEFAULT '0' AFTER `evoitem`, + ADD COLUMN `evomax` INT(11) NOT NULL DEFAULT '0' AFTER `evolvinglevel`, + CHANGE `UNK038` `skillmodmax` INT(11) NOT NULL DEFAULT '0', + CHANGE `UNK222` `heirloom` INT(11) NOT NULL DEFAULT '0', + CHANGE `UNK235` `placeable` INT(11) NOT NULL DEFAULT '0', + CHANGE `UNK242` `epicitem` INT(11) NOT NULL DEFAULT '0'; \ No newline at end of file diff --git a/utils/sql/git/required/2015_12_29_quest_zone_events.sql b/utils/sql/git/required/2015_12_29_quest_zone_events.sql new file mode 100644 index 000000000..783cb477e --- /dev/null +++ b/utils/sql/git/required/2015_12_29_quest_zone_events.sql @@ -0,0 +1,4 @@ +INSERT INTO `perl_event_export_settings` (`event_id`, `event_description`, `export_qglobals`, `export_mob`, `export_zone`, `export_item`, `export_event`) VALUES (81, 'EVENT_SPAWN_ZONE', 0, 0, 0, 0, 1); +INSERT INTO `perl_event_export_settings` (`event_id`, `event_description`, `export_qglobals`, `export_mob`, `export_zone`, `export_item`, `export_event`) VALUES (82, 'EVENT_DEATH_ZONE', 0, 0, 0, 0, 1); +ALTER TABLE `rule_values` +MODIFY COLUMN `notes` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `rule_value`; \ No newline at end of file diff --git a/utils/sql/git/required/2016_01_08_command_find_aliases.sql b/utils/sql/git/required/2016_01_08_command_find_aliases.sql new file mode 100644 index 000000000..ad798dd6a --- /dev/null +++ b/utils/sql/git/required/2016_01_08_command_find_aliases.sql @@ -0,0 +1 @@ +INSERT INTO `command_settings` VALUES ('findaliases', 0, 'fa'); diff --git a/utils/sql/git/required/2016_03_05_secondary_recall.sql b/utils/sql/git/required/2016_03_05_secondary_recall.sql new file mode 100644 index 000000000..7b0f02754 --- /dev/null +++ b/utils/sql/git/required/2016_03_05_secondary_recall.sql @@ -0,0 +1,6 @@ +ALTER TABLE `character_bind` ADD `slot` int(4) AFTER `id`; +UPDATE `character_bind` SET `slot`='0' WHERE `is_home`=0; +UPDATE `character_bind` SET `slot`='4' WHERE `is_home`=1; +ALTER TABLE `character_bind` DROP PRIMARY KEY, ADD PRIMARY KEY(`id`, `slot`); +ALTER TABLE `character_bind` DROP COLUMN `is_home`; + diff --git a/utils/sql/git/required/2016_07_03_npc_class_as_last_name.sql b/utils/sql/git/required/2016_07_03_npc_class_as_last_name.sql new file mode 100644 index 000000000..75f4b5296 --- /dev/null +++ b/utils/sql/git/required/2016_07_03_npc_class_as_last_name.sql @@ -0,0 +1,2 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES +(1, 'NPC:UseClassAsLastName', 'true', 'Uses class archetype as LastName for npcs with none'); diff --git a/utils/sql/peq_aa_tables_post_rework.sql b/utils/sql/peq_aa_tables_post_rework.sql new file mode 100644 index 000000000..9d3b05eaf --- /dev/null +++ b/utils/sql/peq_aa_tables_post_rework.sql @@ -0,0 +1,20656 @@ +DROP TABLE IF EXISTS `aa_ability`; +CREATE TABLE IF NOT EXISTS `aa_ability` ( + `id` int(10) unsigned NOT NULL, + `name` text NOT NULL, + `category` int(10) NOT NULL DEFAULT '-1', + `classes` int(10) NOT NULL DEFAULT '65535', + `races` int(10) NOT NULL DEFAULT '65535', + `drakkin_heritage` int(10) NOT NULL DEFAULT '127', + `deities` int(10) NOT NULL DEFAULT '131071', + `status` int(10) NOT NULL DEFAULT '0', + `type` int(10) NOT NULL DEFAULT '0', + `charges` int(11) NOT NULL DEFAULT '0', + `grant_only` tinyint(4) NOT NULL DEFAULT '0', + `first_rank_id` int(10) NOT NULL DEFAULT '-1', + `enabled` tinyint(3) unsigned NOT NULL DEFAULT '1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `aa_ability` (`id`, `name`, `category`, `classes`, `races`, `drakkin_heritage`, `deities`, `status`, `type`, `charges`, `grant_only`, `first_rank_id`, `enabled`) VALUES + (0, 'Unknown AA -1', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 49999, 1), + (1, 'Innate Strength', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 2, 1), + (2, 'Innate Stamina', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 7, 1), + (3, 'Innate Agility', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 12, 1), + (4, 'Innate Dexterity', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 17, 1), + (5, 'Innate Intelligence', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 22, 1), + (6, 'Innate Wisdom', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 27, 1), + (7, 'Innate Charisma', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 32, 1), + (8, 'Innate Fire Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 37, 1), + (9, 'Innate Cold Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 42, 1), + (10, 'Innate Magic Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 47, 1), + (11, 'Innate Poison Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 52, 1), + (12, 'Innate Disease Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 57, 1), + (13, 'Innate Run Speed', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 62, 1), + (15, 'Innate Metabolism', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 68, 1), + (16, 'Innate Lung Capacity', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 71, 1), + (17, 'First Aid', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 74, 1), + (18, 'Healing Adept', -1, 16942, 65535, 127, 131071, 0, 2, 0, 0, 77, 1), + (19, 'Healing Gift', -1, 16942, 65535, 127, 131071, 0, 2, 0, 0, 80, 1), + (20, 'Spell Casting Mastery', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 83, 1), + (21, 'Spell Casting Reinforcement', -1, 25150, 65535, 127, 131071, 0, 2, 0, 0, 86, 1), + (23, 'Spell Casting Fury', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 92, 1), + (25, 'Spell Casting Subtlety', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 98, 1), + (26, 'Spell Casting Expertise', -1, 15504, 65535, 127, 131071, 0, 2, 0, 0, 101, 1), + (27, 'Spell Casting Deftness', -1, 7184, 65535, 127, 131071, 0, 2, 0, 0, 104, 1), + (28, 'Natural Durability', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 107, 1), + (29, 'Natural Healing', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 110, 1), + (30, 'Combat Fury', -1, 16596, 65535, 127, 131071, 0, 2, 0, 0, 113, 1), + (31, 'Fear Resistance', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 116, 1), + (32, 'Finishing Blow', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 119, 1), + (33, 'Combat Stability', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 122, 1), + (34, 'Combat Agility', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 125, 1), + (35, 'Mass Group Buff', -1, 30254, 65535, 127, 131071, 0, 3, 0, 0, 128, 1), + (36, 'Divine Resurrection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 129, 1), + (37, 'Innate Invis to Undead', -1, 1026, 65535, 127, 131071, 0, 3, 0, 0, 130, 1), + (38, 'Celestial Regeneration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 131, 1), + (39, 'Bestow Divine Aura', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 132, 1), + (41, 'Purify Soul', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 136, 1), + (42, 'Quick Evacuation', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 137, 1), + (43, 'Exodus', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 140, 1), + (44, 'Quick Damage', -1, 6176, 65535, 127, 131071, 0, 3, 0, 0, 141, 1), + (45, 'Enhanced Root', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 144, 1), + (46, 'Dire Charm', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 145, 1), + (47, 'Cannibalization', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 146, 1), + (48, 'Quick Buff', -1, 25134, 65535, 127, 131071, 0, 2, 0, 0, 147, 1), + (49, 'Alchemy Mastery', 6, 512, 65535, 127, 131071, 0, 1, 0, 0, 150, 1), + (50, 'Rabid Bear', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 153, 1), + (52, 'Improved Familiar', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 155, 1), + (53, 'Nexus Gate', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 156, 1), + (55, 'Permanent Illusion', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 158, 1), + (56, 'Jewel Craft Mastery', 6, 8192, 65535, 127, 131071, 0, 1, 0, 0, 159, 1), + (57, 'Gather Mana', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 162, 1), + (58, 'Mend Companion', -1, 21504, 65535, 127, 131071, 0, 3, 0, 0, 163, 1), + (60, 'Frenzied Burnout', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 167, 1), + (61, 'Elemental Form: Fire', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 168, 1), + (62, 'Elemental Form: Water', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 171, 1), + (63, 'Elemental Form: Earth', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 174, 1), + (64, 'Elemental Form: Air', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 177, 1), + (67, 'Elemental Pact', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 182, 1), + (68, 'Life Burn', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 183, 1), + (69, 'Dead Mesmerization', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 184, 1), + (70, 'Fear Storm', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 185, 1), + (71, 'Flesh to Bone', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 186, 1), + (72, 'Call to Corpse', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 187, 1), + (73, 'Divine Stun', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 188, 1), + (75, 'Slay Undead', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 190, 1), + (76, 'Act of Valor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 193, 1), + (77, 'Holy Steed', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 194, 1), + (78, 'Fearless', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 195, 1), + (79, '2 Hand Bash', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 196, 1), + (80, 'Innate Camouflage', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 197, 1), + (81, 'Ambidexterity', -1, 16841, 65535, 127, 131071, 0, 3, 0, 0, 198, 1), + (82, 'Archery Mastery', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 199, 1), + (84, 'Endless Quiver', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 205, 1), + (85, 'Unholy Steed', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 206, 1), + (87, 'Leech Touch', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 208, 1), + (89, 'Soul Abrasion', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 210, 1), + (90, 'Instrument Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 213, 1), + (94, 'Jam Fest', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 225, 1), + (97, 'Critical Mend', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 230, 1), + (98, 'Purify Body', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 233, 1), + (100, 'Rapid Feign', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 237, 1), + (101, 'Return Kick', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 240, 1), + (102, 'Escape', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 243, 1), + (103, 'Poison Mastery', 6, 256, 65535, 127, 131071, 0, 1, 0, 0, 244, 1), + (104, 'Double Riposte', -1, 49501, 65535, 127, 131071, 0, 2, 0, 0, 247, 1), + (107, 'Purge Poison', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 254, 1), + (108, 'Flurry', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 255, 1), + (109, 'Rampage', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 258, 1), + (110, 'Area Taunt', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 259, 1), + (111, 'War Cry', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 260, 1), + (112, 'Bandage Wound', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 263, 1), + (114, 'Spell Casting Fury Mastery', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 267, 1), + (116, 'Dragon Punch', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 273, 1), + (117, 'Strong Root', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 274, 1), + (118, 'Singing Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 275, 1), + (119, 'Body and Mind Rejuvenation', -1, 16540, 65535, 127, 131071, 0, 3, 0, 0, 278, 1), + (120, 'Physical Enhancement', -1, 49629, 65535, 127, 131071, 0, 3, 0, 0, 279, 1), + (121, 'Adv. Trap Negotiation', -1, 384, 65535, 127, 131071, 0, 3, 0, 0, 280, 1), + (122, 'Acrobatics', -1, 448, 65535, 127, 131071, 0, 3, 0, 0, 283, 1), + (123, 'Scribble Notes', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 286, 1), + (124, 'Chaotic Stab', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 287, 1), + (125, 'Pet Discipline', -1, 22032, 65535, 127, 131071, 0, 3, 0, 0, 288, 1), + (126, 'Hobble of Spirits', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 289, 1), + (127, 'Frenzy of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 290, 1), + (128, 'Paragon of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 291, 1), + (129, 'Chains of Purity', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10348, 1), + (130, 'Resplendent Glory', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 8300, 1), + (131, 'Rage of Rallos Zek', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 8303, 1), + (132, 'Enhanced Area Taunt', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 8312, 1), + (133, 'Decapitation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 14200, 1), + (134, 'Hastened Berserking Disciplines', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 14203, 1), + (135, 'Quiet Miracle', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14206, 1), + (136, 'Repel the Wicked', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14207, 1), + (137, 'Beacon of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14208, 1), + (138, 'Blessed Chains', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14209, 1), + (139, 'Hastened Focused Celestial Regeneration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14213, 1), + (140, 'Quickened Spirit Calling', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14225, 1), + (141, 'New Tanaan Crafting Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 412, 1), + (142, 'Planar Power', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 418, 1), + (143, 'Planar Durability', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 423, 1), + (144, 'Innate Enlightenment', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 426, 1), + (146, 'Unknown AA 8001', 9, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8000, 0), + (147, 'Spiritual Rebuke', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14231, 1), + (148, 'Pathosis', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14232, 1), + (149, 'Preincarnation', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 14233, 1), + (150, 'Mastery of the Past', -1, 15504, 65535, 127, 131071, 0, 2, 0, 0, 446, 1), + (151, 'Spiritual Blessing', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14234, 1), + (152, 'Communion of the Cheetah', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14237, 1), + (153, 'Radiant Cure', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 459, 1), + (154, 'Hastened Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 462, 1), + (156, 'Hastened Purification of the Soul', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 468, 1), + (157, 'Hastened Gathering', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 471, 1), + (158, 'Hastened Rabidity', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 474, 1), + (159, 'Hastened Exodus', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 477, 1), + (160, 'Hastened Root', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 480, 1), + (161, 'Hastened Mending', -1, 21504, 65535, 127, 131071, 0, 3, 0, 0, 483, 1), + (163, 'Hastened Instigation', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 489, 1), + (164, 'Hastened Rampage', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 492, 1), + (165, 'Hastened Purification of the Body', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 495, 1), + (166, 'Hasty Exit', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 498, 1), + (167, 'Hastened Purification', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 501, 1), + (168, 'Hastened Nature\'s Fury', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14241, 1), + (169, 'Divine Arbitration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 507, 1), + (170, 'Wrath of the Wild', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 510, 1), + (171, 'Virulent Paralysis', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 513, 1), + (172, 'Harvest of Druzzil', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 516, 1), + (173, 'Eldritch Rune', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 517, 1), + (174, 'Servant of Ro', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 520, 1), + (175, 'Wake the Dead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 523, 1), + (176, 'Suspended Minion', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 526, 1), + (177, 'Spirit Call', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 528, 1), + (178, 'Wrath of the Forest Walker', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14244, 1), + (179, 'Gift of Sylvan Spirits', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14249, 1), + (180, 'Hand of Piety', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 534, 1), + (181, 'Mithaniel\'s Binding', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 537, 1), + (182, 'Summon Personal Tribute Master', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5006, 1), + (183, 'Extended Vinelash Cascade', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14254, 1), + (184, 'Guardian of the Forest', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 545, 1), + (185, 'Spirit of the Wood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 548, 1), + (186, 'Bestial Frenzy', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 551, 1), + (187, 'Harmonious Attack', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 556, 1), + (188, 'Knight\'s Advantage', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 561, 1), + (189, 'Ferocity', -1, 33097, 65535, 127, 131071, 0, 2, 0, 0, 564, 1), + (190, 'Viscid Roots', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 567, 1), + (193, 'Feigned Minion', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 574, 1), + (194, 'Unfailing Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 577, 1), + (195, 'Animation Empathy', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 580, 1), + (196, 'Rush to Judgment', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 583, 1), + (197, 'Living Shield', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 586, 1), + (198, 'Consumption of the Soul', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 589, 1), + (199, 'Boastful Bellow', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 592, 1), + (200, 'Fervent Blessing', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 593, 1), + (201, 'Touch of the Wicked', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 596, 1), + (202, 'Punishing Blade', -1, 32841, 65535, 127, 131071, 0, 2, 0, 0, 599, 1), + (203, 'Speed of the Knight', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 602, 1), + (204, 'Shroud of Stealth', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 605, 1), + (205, 'Nimble Evasion', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 606, 1), + (206, 'Technique of Master Wu', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 611, 1), + (207, 'Host of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 616, 1), + (208, 'Call of Xuzl', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 619, 1), + (209, 'Hastened Stealth', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 622, 1), + (210, 'Ingenuity', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 625, 1), + (211, 'Fleet of Foot', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 628, 1), + (212, 'Fading Memories', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 630, 1), + (213, 'Tactical Mastery', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 631, 1), + (214, 'Theft of Life', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 634, 1), + (215, 'Fury of Magic', -1, 13858, 65535, 127, 131071, 0, 2, 0, 0, 637, 1), + (216, 'Extended Spirit of the Bear', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14259, 1), + (217, 'Project Illusion', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 643, 1), + (218, 'Headshot', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 644, 1), + (219, 'Entrap', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 645, 1), + (220, 'Sonic Displacement', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 13528, 1), + (221, 'Total Domination', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 649, 1), + (222, 'Stalwart Endurance', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 652, 1), + (223, 'Quick Summoning', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 655, 1), + (224, 'Mental Clarity', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 658, 1), + (225, 'Innate Regeneration', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 661, 1), + (227, 'Extended Notes', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 665, 1), + (228, 'Hastened Warder\'s Gift', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13463, 1), + (229, 'Improved Reclaim Energy', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 671, 1), + (230, 'Hastened Possum', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13449, 1), + (231, 'Shauri\'s Sonorious Clouding', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 13527, 1), + (232, 'Veil of the Underbrush', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14262, 1), + (233, 'Packrat', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 678, 1), + (234, 'Heightened Endurance ', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 683, 1), + (235, 'Weapon Affinity', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 686, 1), + (236, 'Secondary Forte', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 691, 1), + (237, 'Persistent Casting', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 692, 1), + (238, 'Tune of Pursuance', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 695, 1), + (239, 'Hastened Companion\'s Sacrifice', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13474, 1), + (240, 'Cheetah\'s Pounce', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13483, 1), + (241, 'Bloodlust', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13484, 1), + (242, 'Primal Fury', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 13485, 1), + (244, 'Lure of the Siren\'s Song', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 13529, 1), + (245, 'Bestial Alignment', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 718, 1), + (246, 'Hidden Communion of the Cheetah', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 14265, 1), + (247, 'Feral Swipe', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 723, 1), + (248, 'Warder\'s Fury', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 724, 1), + (249, 'Warder\'s Alacrity', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 729, 1), + (250, 'Pet Affinity', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 734, 1), + (251, 'Mastery of the Past', -1, 16942, 65535, 127, 131071, 0, 2, 0, 0, 735, 1), + (252, 'Spell Casting Subtlety', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 738, 1), + (254, 'Divine Avatar', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 746, 1), + (255, 'Exquisite Benediction', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 749, 1), + (256, 'Hastened Curing', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 754, 1), + (257, 'Nature\'s Boon', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 757, 1), + (258, 'Advanced Tracking', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 762, 1), + (259, 'Critical Affliction', -1, 18104, 65535, 127, 131071, 0, 2, 0, 0, 767, 1), + (260, 'Glacial Arrow', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13549, 1), + (261, 'Doppelganger', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 773, 1), + (262, 'Enhanced Forgetfulness', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 776, 1), + (263, 'Mesmerization Mastery', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 781, 1), + (264, 'Quick Mass Group Buff', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 782, 1), + (265, 'Shared Health', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 785, 1), + (266, 'Elemental Fury', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 790, 1), + (267, 'Elemental Alacrity ', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 795, 1), + (268, 'Elemental Agility', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 800, 1), + (269, 'Elemental Durability', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 803, 1), + (270, 'Sinister Strikes', -1, 16841, 65535, 127, 131071, 0, 3, 0, 0, 806, 1), + (271, 'Strikethrough', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 807, 1), + (272, 'Stonewall', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 810, 1), + (273, 'Rapid Strikes ', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 815, 1), + (274, 'Kick Mastery', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 820, 1), + (275, 'Heightened Awareness', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 823, 1), + (276, 'Destructive Force ', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 828, 1), + (278, 'Death\'s Fury ', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 834, 1), + (279, 'Quickening of Death ', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 839, 1), + (280, 'Group Perfected Invisibility to Undead', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 14281, 1), + (281, 'Triple Backstab', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 846, 1), + (282, 'Hastened Piety', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 849, 1), + (283, 'Immobilizing Bash', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 852, 1), + (284, 'Vicious Smash', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 855, 1), + (285, 'Radiant Cure', -1, 4, 65535, 127, 131071, 0, 2, 0, 0, 860, 1), + (286, 'Purification ', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 863, 1), + (287, 'Precision of the Pathfinder', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 864, 1), + (288, 'Coat of Thistles', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 867, 1), + (289, 'Flaming Arrows', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 872, 1), + (290, 'Frost Arrows', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 875, 1), + (291, 'Perfected Invisibility to Undead', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 14282, 1), + (292, 'Trap Circumvention ', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 881, 1), + (293, 'Quickened Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14283, 1), + (294, 'Virulent Venom ', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 888, 1), + (295, 'Extended Dreary Deeds', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14286, 1), + (296, 'Intense Hatred', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 895, 1), + (297, 'Quickened Frenzied Burnout', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 14289, 1), + (299, 'Sturdiness', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 907, 1), + (300, 'Warlord\'s Tenacity ', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 912, 1), + (301, 'Strengthened Strike', -1, 9, 65535, 127, 131071, 0, 3, 0, 0, 915, 1), + (302, 'Extended Shielding', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 918, 1), + (303, 'Ro\'s Flaming Familiar ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 921, 1), + (304, 'E\'ci\'s Icy Familiar ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 922, 1), + (305, 'Druzzil\'s Mystical Familiar ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 923, 1), + (306, 'Unknown AA 15819', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15819, 1), + (307, 'Ward of Destruction ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 926, 1), + (308, 'Frenzied Devastation', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 931, 1), + (309, 'Combat Fury', -1, 32769, 65535, 127, 131071, 0, 2, 0, 0, 934, 1), + (310, 'Combat Fury', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 937, 1), + (311, 'Combat Fury', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 940, 1), + (312, 'Quickened Host of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 14292, 1), + (313, 'Hastened Companion\'s Relocation', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 14295, 1), + (314, 'Veteran\'s Wrath', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1047, 1), + (315, 'Planar Durability', -1, 32788, 65535, 127, 131071, 0, 3, 0, 0, 952, 1), + (316, 'Innate Enlightenment', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 955, 1), + (317, 'Dire Charm', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 960, 1), + (318, 'Dire Charm', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 961, 1), + (319, 'Touch of the Divine', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 962, 1), + (320, 'Swarm of Decay', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 967, 1), + (321, 'Call of the Ancients', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 970, 1), + (322, 'Innate See Invis', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1388, 1), + (323, 'Virulent Talon', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 14307, 1), + (324, 'Blacksmithing Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 979, 1), + (325, 'Baking Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 982, 1), + (326, 'Brewing Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 985, 1), + (327, 'Fletching Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 988, 1), + (328, 'Pottery Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 991, 1), + (329, 'Tailoring Mastery', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 994, 1), + (330, 'Salvage', 6, 65535, 65535, 127, 131071, 0, 1, 0, 0, 997, 1), + (331, 'Origin', 9, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1000, 1), + (333, 'Discordant Defiance', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1006, 1), + (334, 'Mystical Attuning', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1021, 1), + (335, 'Delay Death', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1026, 1), + (336, 'Earthen Brawn', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8263, 1), + (337, 'Unknown AA 15798', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15798, 1), + (338, 'Veteran\'s Wrath', -1, 16596, 65535, 127, 131071, 0, 2, 0, 0, 1041, 1), + (339, 'Veteran\'s Wrath', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1044, 1), + (340, 'Unknown AA 15833', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15833, 1), + (341, 'Veteran\'s Wrath', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 1050, 1), + (342, 'Staff Block', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 14301, 1), + (343, 'Hastened Pestilent Paralysis', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14308, 1), + (344, 'Hastened Mercurial Torment', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14311, 1), + (345, 'Unknown AA 15768', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15768, 1), + (346, 'Unknown AA 15771', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 15771, 1), + (347, 'Mnemonic Retention', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 1071, 1), + (348, 'Expansive Mind', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 1072, 1), + (350, 'Death\'s Malaise', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14321, 1), + (351, 'Dying Grasp', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14322, 1), + (352, 'Arcane Tongues', 6, 15360, 65535, 127, 131071, 0, 2, 0, 0, 1089, 1), + (353, 'Master of Disguise', -1, 384, 65535, 127, 131071, 0, 3, 0, 0, 1092, 1), + (354, 'Slippery Attacks', -1, 16841, 65535, 127, 131071, 0, 2, 0, 0, 1093, 1), + (355, 'Unknown AA 15836', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15836, 1), + (357, 'Unknown AA 16176', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16176, 1), + (358, 'Fury of Magic', -1, 16540, 65535, 127, 131071, 0, 2, 0, 0, 1107, 1), + (359, 'Dance of Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1110, 1), + (360, 'Bloodthirsty Blade', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13616, 1), + (361, 'Shield of Notes', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1116, 1), + (362, 'Roar of Thunder', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 1119, 1), + (363, 'Unknown AA 16179', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16179, 1), + (364, 'Persistent Minion', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 1122, 1), + (365, 'A Hole In Space', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 14323, 1), + (366, 'Advanced Pet Discipline', -1, 22032, 65535, 127, 131071, 0, 3, 0, 0, 1129, 1), + (367, 'Throwing Mastery', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1131, 1), + (368, 'Blur of Axes', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1134, 1), + (369, 'Hastened War Cry', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1137, 1), + (370, 'Dead Aim', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1140, 1), + (371, 'Frenzied Defense', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1166, 1), + (372, 'Tireless Sprint', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1146, 1), + (373, 'Desperation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1149, 1), + (374, 'Untamed Rage', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1150, 1), + (375, 'Echoing Cries', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1155, 1), + (376, 'Distant Strike', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14372, 1), + (377, 'Earthen Stability', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8268, 1), + (378, 'Earthen Alacrity', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8273, 1), + (379, 'Earthen Artistry', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8278, 1), + (380, 'Earthen Sagacity', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8283, 1), + (381, 'Earthen Brilliance', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8288, 1), + (382, 'Earthen Allure', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8293, 1), + (383, 'Extended Spirit of the Wood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12646, 1), + (384, 'Spirit of the Bear', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12651, 1), + (385, 'Twinheal', -1, 16942, 65535, 127, 131071, 0, 2, 0, 0, 12652, 1), + (386, 'Nature\'s Fury', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12661, 1), + (387, 'Blood Pact', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1178, 1), + (388, 'Shielding Resistance', -1, 16841, 65535, 127, 131071, 0, 2, 0, 0, 1181, 1), + (389, 'Healing Boon', -1, 518, 65535, 127, 131071, 0, 2, 0, 0, 1186, 1), + (390, 'Elemental Union', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 13695, 1), + (391, 'Celestial Hammer', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1192, 1), + (392, 'Divine Retribution', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1195, 1), + (393, 'Nature\'s Blessing', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12655, 1), + (394, 'Extended Convergence of Spirit', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12645, 1), + (395, 'Hastened Storm Strike', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12664, 1), + (396, 'Sanctuary', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1209, 1), + (397, 'Destructive Fury', -1, 2048, 65535, 127, 131071, 0, 2, 0, 0, 1210, 1), + (398, 'Destructive Fury', -1, 13858, 65535, 127, 131071, 0, 2, 0, 0, 1213, 1), + (399, 'Unknown AA 16180', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16180, 1), + (400, 'Hastened Improved Twincast', -1, 14370, 65535, 127, 131071, 0, 3, 0, 0, 14331, 1), + (401, 'Extended Heel of Kanji', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 12688, 1), + (402, 'Extended Scaledfist', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 12691, 1), + (403, 'Paralytic Spores', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 14264, 1), + (404, 'Call of the Wild', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 1228, 1), + (405, 'Secondary Recall', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 1229, 1), + (406, 'Nature\'s Bounty', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 1230, 1), + (407, 'Extended Speed Focus', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7884, 1), + (408, 'Extended Crystalpalm', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7885, 1), + (409, 'Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1233, 1), + (410, 'Fists of Steel', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 12706, 1), + (411, 'Extended Deftdance', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12709, 1), + (412, 'Color Shock', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1239, 1), + (413, 'Mind Over Matter', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1242, 1), + (414, 'Soothing Words', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1245, 1), + (415, 'Hastened Deftdance', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12710, 1), + (416, 'Hastened Lyre Leap', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12713, 1), + (417, 'Hastened Quick Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12716, 1), + (418, 'Replenish Companion', -1, 21504, 65535, 127, 131071, 0, 3, 0, 0, 1126, 1), + (419, 'Extended Quick Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12719, 1), + (420, 'Imitate Death', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1255, 1), + (424, 'Extended Fierce Eye', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12720, 1), + (425, 'Hastened Fierce Eye', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12721, 1), + (426, 'Unknown AA 15904', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 15904, 1), + (427, 'Resounding Dirge', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 12737, 1), + (428, 'Death Peace', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 1272, 1), + (429, 'Unknown AA 15908', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15908, 1), + (430, 'Mercurial Torment', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12766, 1), + (431, 'Pestilent Paralysis', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12770, 1), + (432, 'Hastened Divine Companion Aura', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 12773, 1), + (433, 'Embalmer\'s Carapace', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12778, 1), + (434, 'Steadfast Will', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 1284, 1), + (435, 'Shield Block', -1, 21, 65535, 127, 131071, 0, 2, 0, 0, 1287, 1), + (436, 'Hastened Encroaching Darkness', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12779, 1), + (437, 'Tracking Mastery', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1296, 1), + (438, 'Expanding Darkness', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 12782, 1), + (439, 'Precision', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1304, 1), + (440, 'Nerves of Steel', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1307, 1), + (441, 'Aegis of Kildrukaun', -1, 5120, 65535, 127, 131071, 0, 3, 0, 0, 12785, 1), + (442, 'Touch of the Cursed', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 1313, 1), + (443, 'Bestial Bloodrage', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12804, 1), + (444, 'Companion\'s Sacrifice', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12807, 1), + (445, 'Shield Block', -1, 16384, 65535, 127, 131071, 0, 2, 0, 0, 12813, 1), + (446, 'Spiritual Channeling', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 1323, 1), + (447, 'Ancestral Aid', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 1327, 1), + (448, 'Extended Feralgia', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12816, 1), + (450, 'Hastened Protective Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12819, 1), + (451, 'Mind Crash', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1334, 1), + (452, 'Prolonged Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1337, 1), + (453, 'Summon Permutation Peddler', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 9032, 1), + (454, 'Hastened Empathic Fury', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12822, 1), + (455, 'Convergence of Spirits', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13556, 1), + (456, 'Teleport Bind', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1343, 1), + (457, 'Quickened Paragon of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12831, 1), + (458, 'Warder\'s Gift', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12837, 1), + (459, 'Gelid Rending', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12846, 1), + (460, 'Quickened Nature\'s Salve', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 12849, 1), + (462, 'Auspice of the Hunter', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1345, 1), + (463, 'Divine Guardian', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 13385, 1), + (464, 'Divine Peace', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 13388, 1), + (465, 'Savage Spirit', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1348, 1), + (466, 'Trials of Mata Muram', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1011, 1), + (467, 'Press the Attack', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 1351, 1), + (468, 'Crippling Strike', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1352, 1), + (469, 'Stunning Kick', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1355, 1), + (470, 'Eye Gouge', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1358, 1), + (471, 'Gift of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1361, 1), + (472, 'Tenacity of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1362, 1), + (473, 'Embrace of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1363, 1), + (474, 'Power of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1364, 1), + (475, 'Fervor of the Dark Reign', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1365, 1), + (476, 'Gift of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1366, 1), + (477, 'Valor of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1367, 1), + (478, 'Embrace of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1368, 1), + (479, 'Power of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1369, 1), + (480, 'Sanctity of the Keepers', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1370, 1), + (481, 'Lesson of the Devoted', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1371, 1), + (482, 'Infusion of the Faithful', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1372, 1), + (483, 'Chaotic Jester', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1373, 1), + (484, 'Expedient Recovery', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1374, 1), + (485, 'Steadfast Servant', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1375, 1), + (486, 'Staunch Recovery', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1376, 1), + (487, 'Intensity of the Resolute', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1377, 1), + (488, 'Curse of Blood', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1378, 1), + (489, 'Yaulp', -1, 6, 65535, 127, 131071, 0, 3, 0, 0, 13389, 1), + (490, 'Abscond', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12864, 1), + (491, 'Atol\'s Unresistable Shackles', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12865, 1), + (492, 'Dimensional Shield', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 12866, 1), + (493, 'Improved Sustained Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12867, 1), + (494, 'Silent Casting', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 1409, 1), + (495, 'Gift of Mana', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 1435, 1), + (496, 'Field Dressing', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 1611, 1), + (497, 'Bandage Wounds', -1, 32766, 65535, 127, 131071, 0, 1, 0, 0, 1420, 1), + (498, 'Enhanced Aggression', -1, 49629, 65535, 127, 131071, 0, 2, 0, 0, 1592, 1), + (499, 'Cascading Rage', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1425, 1), + (500, 'Silent Casting', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 1404, 1), + (501, 'E\'ci\'s Icy Blessing', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12886, 1), + (503, 'Hastened Thunder', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 1471, 1), + (504, 'Conservation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1453, 1), + (505, 'Cry of Battle', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 1458, 1), + (506, 'Ward of Purity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1459, 1), + (507, 'Ro\'s Fiery Blessing', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12887, 1), + (508, 'Druzzil\'s Mystical Blessing', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12888, 1), + (509, 'Kerafyrm\'s Favor', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12889, 1), + (510, 'Kerafyrm\'s Prismatic Familiar', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12892, 1), + (511, 'Throne of Heroes', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 4665, 1), + (512, 'Translocational Anchor', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1630, 1), + (513, 'Hastened Phantasmal Opponent', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12894, 1), + (514, 'Pyromancy', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1478, 1), + (515, 'Improved Twincast', -1, 14370, 65535, 127, 131071, 0, 3, 0, 0, 12893, 1), + (516, 'Abundant Healing', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 1486, 1), + (517, 'Hastened First Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12902, 1), + (518, 'Shared Camouflage', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 1494, 1), + (519, 'Convergence of Spirits', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 1495, 1), + (520, 'Nature\'s Guardian', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 1498, 1), + (521, 'Edict of Command', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1501, 1), + (522, 'Extended Burnout', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1504, 1), + (523, 'Hastened Second Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12907, 1), + (524, 'Blood Magic', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 1510, 1), + (525, 'Graverobbing', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 1511, 1), + (526, 'Affliction Mastery', -1, 1568, 65535, 127, 131071, 0, 3, 0, 0, 1514, 1), + (527, 'Hastened Third Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12912, 1), + (528, 'Ancestral Guard', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 1520, 1), + (529, 'Cloak of Light', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 1523, 1), + (530, 'Profound Visage', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12920, 1), + (531, 'Cloak of Shadows', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 1527, 1), + (532, 'Willful Death', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 1528, 1), + (533, 'Unknown AA 16016', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16016, 1), + (534, 'Calculated Insanity', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12931, 1), + (535, 'Crippling Aurora', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12937, 1), + (536, 'Appraisal', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1542, 1), + (537, 'Precise Strikes', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1543, 1), + (538, 'Hastened Death', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1546, 1), + (539, 'Unflinching Resolve', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1549, 1), + (540, 'Weightless Steps', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 1552, 1), + (541, 'Hastened Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1555, 1), + (542, 'Unknown AA 16071', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 16071, 1), + (543, 'Diminutive Companion', -1, 20480, 65535, 127, 131071, 0, 3, 0, 0, 12941, 1), + (544, 'Song of Stone', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1569, 1), + (545, 'Deep Sleep', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 1572, 1), + (546, 'Companion\'s Gift', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1577, 1), + (547, 'Unknown AA 16081', -1, 15360, 65535, 127, 131071, 0, 3, 0, 0, 16081, 1), + (548, 'Hastened Defiance', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 1583, 1), + (549, 'Dauntless Perseverance', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 1591, 1), + (550, 'Steadfast Resolve', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 14275, 1), + (551, 'Hastened Mind Crash', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1414, 1), + (552, 'Call of Challenge', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 1597, 1), + (553, 'Cacophony', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1598, 1), + (554, 'Hastened Nightmare Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14341, 1), + (555, 'Anatomy', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1604, 1), + (556, 'Scintillating Beam', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14346, 1), + (557, 'Trick Shot', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1608, 1), + (558, 'Turn Undead', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 1383, 1), + (559, 'Turn Summoned', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1462, 1), + (560, 'Selo\'s Enduring Cadence', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1627, 1), + (561, 'Hastened Harvest of Druzzil', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12881, 1), + (562, 'Lightning Strikes', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1616, 1), + (563, 'Concentration', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 1588, 1), + (565, 'Mana Burn', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1638, 1), + (567, 'Unknown AA 16146', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16146, 1), + (568, 'Thief\'s Intuition', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1641, 1), + (569, 'Thief\'s Intuition', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1642, 1), + (570, 'Valiant Steed', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 1645, 1), + (571, 'Abyssal Steed', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 1646, 1), + (572, 'Holy Warhorse', -1, 4, 65535, 127, 131071, 0, 3, 0, 1, 1643, 1), + (573, 'Unholy Warhorse', -1, 16, 65535, 127, 131071, 0, 3, 0, 1, 1644, 1), + (574, 'Harmonic Dissonance', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 1647, 1), + (575, 'Tinkering Mastery', 6, 15639, 65535, 127, 131071, 0, 1, 0, 1, 4672, 1), + (576, 'Jewel Craft Mastery ', 6, 57343, 65535, 127, 131071, 0, 1, 0, 0, 4675, 1), + (577, 'Concussive Intuition', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 12885, 1), + (578, 'Glyph Spray', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12939, 1), + (579, 'Combat Medic ', -1, 32766, 65535, 127, 131071, 0, 1, 0, 0, 4688, 1), + (580, 'Hastened Outrider\'s Accuracy', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13565, 1), + (581, 'Quick Draw', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 4698, 1), + (582, 'Battle Ready', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 4699, 1), + (583, 'Hastened Outrider\'s Evasion', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13568, 1), + (584, 'Grasp of Sylvan Spirits', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 13571, 1), + (585, 'Glyph of Dragon Scales', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 4702, 1), + (586, 'Glyph of Indeterminable Reward', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 13788, 1), + (587, 'Glyph of Arcane Secrets', 7, 32318, 65535, 127, 131071, 0, 4, 1, 0, 4704, 1), + (588, 'Glyph of Draconic Potential', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 4705, 1), + (589, 'Glyph of Destruction', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 4706, 1), + (590, 'Breath of Atathus', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5150, 1), + (591, 'Breath of Draton\'ra', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5165, 1), + (592, 'Breath of Osh\'vir', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5180, 1), + (593, 'Breath of Venesh', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5195, 1), + (594, 'Breath of Mysaphar', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5210, 1), + (595, 'Breath of Keikolin', 8, 65535, 65535, 127, 131071, 0, 4, 0, 1, 5225, 1), + (596, 'Small Modulation Shard', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 12963, 1), + (597, 'Medium Modulation Shard', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 12964, 1), + (598, 'Large Modulation Shard', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 12965, 1), + (599, 'Hastened Malosinete', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 12968, 1), + (600, 'Blessing of the Devoted', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 9033, 1), + (601, 'Grappling Strike', -1, 65, 65535, 127, 131071, 0, 3, 0, 0, 4836, 1), + (602, 'Mental Contortion', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 12938, 1), + (603, 'Shield of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 12971, 1), + (604, 'Extended Malosinete', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 12977, 1), + (605, 'Shield Specialist', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 4844, 1), + (606, 'Mark of the Mage Hunter', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 4849, 1), + (609, 'Uncanny Resilience', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 4854, 1), + (610, 'Blinding Fury', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 4857, 1), + (611, 'Battle Leap', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 4860, 1), + (612, 'Soul Seeker', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 4861, 1), + (613, 'Lingering Death', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13096, 1), + (614, 'Spirit Guardian', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 5369, 1), + (615, 'Surreality', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4887, 1), + (616, 'Mana Draw', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4890, 1), + (617, 'Doppelganger\'s Beckon', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 5127, 1), + (618, 'Armor of Ancestral Spirits', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 12989, 1), + (619, 'Group Pact of the Wolf', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 12992, 1), + (620, 'Hastened Inconspicuous Totem', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13001, 1), + (621, 'Fire Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 4903, 1), + (622, 'Vapor Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 4906, 1), + (623, 'Ice Core ', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 4909, 1), + (624, 'Stone Core ', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 4912, 1), + (625, 'Volatile Mana Blaze', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 4915, 1), + (626, 'Purified Spirits', -1, 546, 65535, 127, 131071, 0, 3, 0, 0, 13004, 1), + (627, 'Group Spirit Walk', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13008, 1), + (628, 'Greater Blood Tithe', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 4924, 1), + (629, 'Gathering Dusk', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 4927, 1), + (630, 'Group Silent Presence', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13009, 1), + (631, 'Double Attack', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 5366, 1), + (632, 'Sanguine Mind Crystal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4934, 1), + (633, 'Azure Mind Crystal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4935, 1), + (634, 'Hastened Cannibalization', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13010, 1), + (635, 'Hastened Spirit Channeling', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13013, 1), + (636, 'Arcane Whisper', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 4938, 1), + (637, 'Vengeful Spirits', -1, 9776, 65535, 127, 131071, 0, 3, 0, 0, 13017, 1), + (638, 'Crippling Apparition', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 13020, 1), + (639, 'Dimensional Instability', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 4943, 1), + (640, 'Cryomancy', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 4944, 1), + (641, 'Hastened Self Preservation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13055, 1), + (642, 'Binding Axe', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13065, 1), + (643, 'Agony of Absolution', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13066, 1), + (644, 'Hastened Absolution', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13067, 1), + (645, 'Hastened Calculated Insanity', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 13753, 1), + (646, 'Hastened Mental Contortion', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 13758, 1), + (647, 'Hastened Crippling Aurora', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 13764, 1), + (649, 'Hastened Leech Touch', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14046, 1), + (650, 'Bony Grasp of Death', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14051, 1), + (651, 'Thought Leech', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14052, 1), + (652, 'Hastened Leechcurse Discipline', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14056, 1), + (653, 'Hastened Unholy Aura Discipline', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14059, 1), + (654, 'Hastened Harmshield', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 14062, 1), + (655, 'Hastened Projection of Doom', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 14065, 1), + (656, 'Hastened Projection of Piety', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14068, 1), + (657, 'Shield of Brilliance', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14071, 1), + (658, 'Hastened Sanctification Discipline', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14076, 1), + (659, 'Speed of the Savior', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14080, 1), + (660, 'Divine Call', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14081, 1), + (661, 'Hunter\'s Fury', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 5248, 1), + (662, 'Union of Spirits', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 5251, 1), + (663, 'Quickened Stuns', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14100, 1), + (664, 'Extended Outrider\'s Attack', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 14115, 1), + (665, 'Death\'s Wrath', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 5264, 1), + (666, 'Taste of Blood', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 5015, 1), + (667, 'Summoner\'s Beckon', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 5269, 1), + (668, 'Hymn of the Last Stand', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 5017, 1), + (669, 'Bladed Song', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 5020, 1), + (670, 'Twisted Shank', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 5021, 1), + (671, 'Dirty Fighting', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 5022, 1), + (672, 'Ligament Slice', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 5025, 1), + (673, 'Tumble', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 5028, 1), + (674, 'Unknown AA 16149', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16149, 1), + (675, 'Shrink', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 14224, 1), + (676, 'Convergence', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14358, 1), + (677, 'Gift of Deathly Resolve', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14359, 1), + (678, 'Unknown AA 16082', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 16082, 1), + (679, 'Unknown AA 16083', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 16083, 1), + (680, 'Unknown AA 16084', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16084, 1), + (681, 'Unknown AA 16087', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16087, 1), + (682, 'Unknown AA 16096', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16096, 1), + (683, 'Unknown AA 16097', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16097, 1), + (684, 'Unknown AA 16104', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16104, 1), + (685, 'Unknown AA 16105', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16105, 1), + (686, 'Unknown AA 16106', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16106, 1), + (687, 'Unknown AA 16107', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16107, 1), + (688, 'Unknown AA 16108', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16108, 1), + (689, 'Combat Medic ', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 5136, 1), + (690, 'Unknown AA 16109', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16109, 1), + (691, 'Unknown AA 16113', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16113, 1), + (692, 'Unknown AA 16114', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16114, 1), + (693, 'Unknown AA 16117', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16117, 1), + (694, 'Unknown AA 16120', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 16120, 1), + (695, 'Unknown AA 16152', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16152, 1), + (696, 'Unknown AA 16156', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16156, 1), + (697, 'Mortal Coil', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 5085, 1), + (698, 'Hastened Purified Spirits', -1, 546, 65535, 127, 131071, 0, 3, 0, 0, 13416, 1), + (699, 'Swarm of Fireflies', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 13419, 1), + (700, 'Unknown AA 16159', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16159, 1), + (701, 'Armor of the Inquisitor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 5095, 1), + (702, 'Hand of Disruption', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 5098, 1), + (703, 'Quickened Death Bloom', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14318, 1), + (704, 'Hero\'s Barracks', 9, 65535, 65535, 127, 131071, 0, 4, 0, 1, 14367, 1), + (705, 'Spirit of the White Wolf', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 5105, 1), + (706, 'Unknown AA 16160', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16160, 1), + (707, 'Pact of the Wolf', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 5109, 1), + (708, 'Enchant Alaran Metal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 13271, 1), + (709, 'Mass Enchant Alaran Metal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 13272, 1), + (710, 'Funeral Pyre', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 14360, 1), + (711, 'Unknown AA 16162', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16162, 1), + (712, 'Hastened Sanctuary', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 5118, 1), + (713, 'Etherium Blades', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14129, 1), + (714, 'Hastened Assassination Disciplines', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14135, 1), + (715, 'Cunning Disguise: Shissar', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14139, 1), + (716, 'Scout\'s Mastery of Piercing', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14141, 1), + (717, 'Extended Envenomed Blades', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 14144, 1), + (718, 'Heel of Brithrax', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14151, 1), + (719, 'Extended Zan Fi\'s Whistle', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14163, 1), + (720, 'Hastened Marr\'s Salvation', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14088, 1), + (721, 'Hastened Armor of the Inquisitor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14091, 1), + (722, 'Hastened Drape of Shadows', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 14304, 1), + (723, 'Unknown AA 16185', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16185, 1), + (724, 'Hastened Eldritch Rune', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 14364, 1), + (725, 'Unknown AA 16124', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 16124, 1), + (726, 'Unknown AA 16128', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 16128, 1), + (727, 'Unknown AA 16131', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 16131, 1), + (728, 'Unknown AA 16137', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 16137, 1), + (729, 'Unknown AA 16140', -1, 6, 65535, 127, 131071, 0, 3, 0, 0, 16140, 1), + (730, 'Unknown AA 16186', -1, 9, 65535, 127, 131071, 0, 3, 0, 0, 16186, 1), + (731, 'Unknown AA 16188', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16188, 1), + (732, 'Unknown AA 16195', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16195, 1), + (733, 'Killing Spree', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 4739, 1), + (734, 'Hold the Line', -1, 32833, 65535, 127, 131071, 0, 3, 0, 0, 4742, 1), + (735, 'Battle Frenzy', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 13134, 1), + (737, 'Quickened Silent Casting', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 13143, 1), + (738, 'Quickened Silent Casting', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 13146, 1), + (739, 'Balefire Burst', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13164, 1), + (740, 'Blood Tithe', -1, 1568, 65535, 127, 131071, 0, 3, 0, 0, 4761, 1), + (741, 'Leap of Faith', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13202, 1), + (742, 'Unknown AA 16196', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16196, 1), + (743, 'Hastened Explosion of Hatred', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13166, 1), + (744, 'Howl of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13169, 1), + (745, 'Hastened Tune In Your Head', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 13204, 1), + (746, 'Unknown AA 16197', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16197, 1), + (747, 'Unknown AA 16200', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16200, 1), + (748, 'Nightmare Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4894, 1), + (749, 'Explosion of Spite', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13165, 1), + (751, 'Scent of Terris', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13225, 1), + (752, 'Bloodfury', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13224, 1), + (753, 'Dreary Deeds', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 13252, 1), + (754, 'Enchant Feymetal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 13260, 1), + (755, 'Mass Enchant Feymetal', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 13261, 1), + (756, 'Enlightened Focus of Arcanum', -1, 15904, 65535, 127, 131071, 0, 3, 0, 0, 13646, 1), + (757, 'Shifting Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 5276, 1), + (758, 'Extended Silent Casting', -1, 15360, 65535, 127, 131071, 0, 3, 0, 0, 13667, 1), + (759, 'Fury of Kerafyrm', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 13670, 1), + (760, 'Unknown AA 16203', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 16203, 1), + (761, 'Unknown AA 16208', -1, 552, 65535, 127, 131071, 0, 3, 0, 0, 16208, 1), + (762, 'Shield Block', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 5283, 1), + (763, 'Mirrored Pestilence', -1, 1552, 65535, 127, 131071, 0, 3, 0, 0, 13684, 1), + (764, 'Embrace The Decay', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13687, 1), + (765, 'Quickened Scent of Terris', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13689, 1), + (766, 'Frenzy of the Dead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13693, 1), + (767, 'Unknown AA 16211', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 16211, 1), + (768, 'Unknown AA 16215', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 16215, 1), + (769, 'Marr\'s Salvation', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13100, 1), + (770, 'Blessing of the Faithful', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13101, 1), + (771, 'Unbridled Strike of Fear', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13108, 1), + (772, 'Noteworthy Disguise: Drake', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14192, 1), + (773, 'Death\'s Effigy', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13133, 1), + (774, 'Empowered Focus of Arcanum', -1, 15904, 65535, 127, 131071, 0, 3, 0, 0, 14690, 1), + (775, 'Unknown AA 16342', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16342, 1), + (776, 'Arcane Overkill', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 5295, 1), + (777, 'Funeral Dirge', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 5298, 1), + (778, 'Protection of the Spirit Wolf', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 5007, 1), + (779, 'Hastened Juggernaut Surge', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13873, 1), + (780, 'Hastened Resilience', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13878, 1), + (781, 'Hastened Blood Pact', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13881, 1), + (782, 'Unknown AA 16317', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 16317, 1), + (783, 'Energetic Attunement', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1056, 1), + (784, 'Heart of Flames', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1251, 1), + (785, 'Heart of Vapor', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1252, 1), + (786, 'Heart of Ice', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1253, 1), + (787, 'Heart of Stone', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1254, 1), + (789, 'Stealthy Getaway', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 1477, 1), + (790, 'Seized Opportunity', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 878, 1), + (791, 'Veil of Mindshadow', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 4931, 1), + (792, 'Army of the Dead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 1274, 1), + (793, 'Mana Blast', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1639, 1), + (794, 'Mana Blaze', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 1640, 1), + (795, 'Innate Corruption Protection', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 1662, 1), + (796, 'Hastened Five Point Palm', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 13889, 1), + (797, 'Moving Mountains', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 13130, 1), + (798, 'Veturika\'s Perseverance', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 14229, 1), + (799, 'Unknown AA 16644', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16644, 1), + (800, 'Vehement Rage', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 6607, 1), + (801, 'Knee Strike', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6610, 1), + (802, 'Hastened Fortitude Discipline', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6611, 1), + (803, 'Hastened Furious Discipline', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6614, 1), + (804, 'Warlord\'s Bravery', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6617, 1), + (805, 'Hastened Speed Focus', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14148, 1), + (806, 'Hastened Zan Fi\'s Whistle', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14160, 1), + (807, 'Pressure Points', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14157, 1), + (808, 'Hastened Thunder', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 14166, 1), + (809, 'Allegretto of Battle', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14181, 1), + (810, 'Vivace of Conflict', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14186, 1), + (811, 'Unknown AA 16218', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 16218, 1), + (812, 'Unknown AA 16221', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 16221, 1), + (813, 'Unknown AA 16222', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 16222, 1), + (814, 'Unknown AA 16225', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 16225, 1), + (815, 'Unknown AA 16230', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 16230, 1), + (816, 'Unknown AA 16235', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 16235, 1), + (817, 'Unknown AA 16238', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 16238, 1), + (818, 'Unknown AA 16257', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 16257, 1), + (819, 'Unknown AA 16666', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 16666, 1), + (820, 'Death\'s Revenge', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6630, 1), + (821, 'Harmshield', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 6635, 1), + (822, 'Explosion of Hatred', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6640, 1), + (823, 'Cascading Theft of Defense', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6641, 1), + (824, 'Hate Step', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6644, 1), + (825, 'Vicious Bite of Chaos', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6645, 1), + (826, 'Encroaching Darkness', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 6646, 1), + (827, 'Unknown AA 16745', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 16745, 1), + (828, 'Unknown AA 16260', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 16260, 1), + (829, 'Unknown AA 16263', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 16263, 1), + (830, 'Unknown AA 16272', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 16272, 1), + (831, 'Unknown AA 16276', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 16276, 1), + (832, 'Unknown AA 16287', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 16287, 1), + (833, 'Unknown AA 17252', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17252, 1), + (834, 'Unknown AA 16296', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 16296, 1), + (835, 'Unknown AA 16300', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 16300, 1), + (836, 'Unknown AA 16310', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 16310, 1), + (837, 'Unknown AA 16330', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 16330, 1), + (838, 'Unknown AA 16163', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 16163, 1), + (839, 'Unknown AA 16360', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 16360, 1), + (840, 'Unknown AA 16363', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16363, 1), + (841, 'Sleight of Hand', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6663, 1), + (842, 'Enduring Vision', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6666, 1), + (843, 'Expertise of Blades', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6668, 1), + (844, 'Cunning Disguise: Human', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6671, 1), + (845, 'Cunning Disguise: Half-Elf', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6672, 1), + (846, 'Cunning Disguise: Barbarian', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6673, 1), + (847, 'Cunning Disguise: Erudite', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6674, 1), + (848, 'Cunning Disguise: Troll', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6675, 1), + (849, 'Cunning Disguise: Goblin', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6676, 1), + (850, 'Unknown AA 16366', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16366, 1), + (851, 'Unknown AA 16369', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 16369, 1), + (852, 'Unknown AA 16370', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 16370, 1), + (853, 'Unknown AA 16371', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 16371, 1), + (854, 'Unknown AA 17256', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17256, 1), + (856, 'Tigir\'s Insect Swarm', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6691, 1), + (857, 'Dampen Resistance', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6692, 1), + (858, 'Hastened Dampen Resistance', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6697, 1), + (859, 'Spirit Walk', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6702, 1), + (860, 'Hastened Virulent Paralysis', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6703, 1), + (861, 'Languid Bite', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6706, 1), + (862, 'Quickened Blood of Nadox', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6709, 1), + (863, 'Hastened Spirit Call', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6712, 1), + (864, 'Hastened Thousand Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14169, 1), + (865, 'Unknown AA 17257', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17257, 1), + (866, 'Extended Dance of Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14179, 1), + (867, 'Extended Thousand Blades', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 14180, 1), + (868, 'Unknown AA 16380', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 16380, 1), + (869, 'Unknown AA 16386', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 16386, 1), + (870, 'Harmonious Arrow', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6750, 1), + (871, 'Hastened Weapon Shield', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6751, 1), + (872, 'Outrider\'s Attack', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6754, 1), + (873, 'Group Guardian of the Forest', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6755, 1), + (874, 'Pack Hunt', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6758, 1), + (875, 'Keen Blade', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6761, 1), + (876, 'Outrider\'s Evasion', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6764, 1), + (877, 'Ranged Finesse', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6765, 1), + (878, 'Bow Mastery', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 1196, 1), + (879, 'Unknown AA 17258', -1, 1040, 65535, 127, 131071, 0, 2, 0, 0, 17258, 1), + (880, 'Unknown AA 16392', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 16392, 1), + (881, 'Unknown AA 16395', -1, 10248, 65535, 127, 131071, 0, 3, 0, 0, 16395, 1), + (882, 'Unknown AA 16396', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 16396, 1), + (883, 'Unknown AA 16536', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 16536, 1), + (884, 'Unknown AA 17209', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 17209, 1), + (885, 'Unknown AA 17212', -1, 1, 65535, 127, 131071, 0, 2, 0, 0, 17212, 1), + (886, 'Unknown AA 17218', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 17218, 1), + (888, 'Unknown AA 17555', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17555, 1), + (889, 'Unknown AA 17229', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17229, 1), + (890, 'Unknown AA 17235', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17235, 1), + (891, 'Healing Light', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6791, 1), + (892, 'Halt the Dead', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6794, 1), + (894, 'Unknown AA 17242', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17242, 1), + (895, 'Unknown AA 17245', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17245, 1), + (896, 'Unknown AA 17249', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17249, 1), + (897, 'Unknown AA 17199', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 17199, 1), + (898, 'Unknown AA 17267', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 17267, 1), + (899, 'Unknown AA 17273', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 17273, 1), + (900, 'Rise of Bones', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6815, 1), + (901, 'Whisperwind', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6818, 1), + (902, 'Hastened Blood Magic', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6819, 1), + (903, 'Overpower Undead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6822, 1), + (904, 'Hastened Swarm of Decay', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6823, 1), + (905, 'Gift of the Grave', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 6828, 1), + (906, 'Hastened Gut Punch', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10522, 1), + (907, 'Hastened First Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10527, 1), + (908, 'Hastened Second Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10532, 1), + (909, 'Hastened Third Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10537, 1), + (910, 'Unknown AA 17280', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 17280, 1), + (911, 'Warlord\'s Resurgence', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10545, 1), + (912, 'Warlord\'s Fury', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10546, 1), + (914, 'Improved Shield Specialist', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10548, 1), + (915, 'Unknown AA 17281', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 17281, 1), + (917, 'Hastened Grappling Strike', -1, 65, 65535, 127, 131071, 0, 3, 0, 0, 10588, 1), + (918, 'Furious Refrain', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10627, 1), + (919, 'Unknown AA 17554', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17554, 1), + (920, 'Valorous Rage', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10711, 1), + (921, 'Hastened Group Guardian of the Forest', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10714, 1), + (922, 'Hastened Outrider\'s Attack', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10719, 1), + (923, 'Hastened Protection of the Spirit Wolf', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10722, 1), + (924, 'Hastened Imbued Ferocity', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10727, 1), + (925, 'Hastened Harmonious Arrow', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10730, 1), + (926, 'Hastened Entrap', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10733, 1), + (927, 'Poison Arrows', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10736, 1), + (928, 'Merciless Blade', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14026, 1), + (929, 'Combatant\'s Pact', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14029, 1), + (930, 'Warlord\'s Resolve', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14032, 1), + (931, 'Hastened Hate\'s Attraction', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 12582, 1), + (932, 'Unknown AA 17289', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 17289, 1), + (933, 'Improved Death Peace', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 12635, 1), + (934, 'Unknown AA 17307', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 17307, 1), + (935, 'Blessing of Ro', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10789, 1), + (936, 'Extended Wild Growth', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 10792, 1), + (937, 'Unknown AA 17317', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17317, 1), + (938, 'Eyes Wide Open', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 12636, 1), + (939, 'Communion of the Cheetah', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 12638, 1), + (940, 'Hastened Song of Stone', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6870, 1), + (941, 'Flurry', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6873, 1), + (942, 'Destructive Cascade', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6876, 1), + (943, 'Total Domination', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6879, 1), + (944, 'Enhanced Forgetfulness', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6882, 1), + (945, 'Infusion of Thunder', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10346, 1), + (946, 'Hastened Warlord\'s Bravery', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14037, 1), + (947, 'Hastened Warlord\'s Tenacity', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14040, 1), + (948, 'Unknown AA 17328', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17328, 1), + (949, 'Unknown AA 17329', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17329, 1), + (950, 'Unknown AA 17336', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17336, 1), + (951, 'Unknown AA 17339', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 17339, 1), + (952, 'Unknown AA 17342', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 17342, 1), + (953, 'Unknown AA 17344', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17344, 1), + (954, 'Unknown AA 17347', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17347, 1), + (955, 'Unknown AA 17357', -1, 514, 65535, 127, 131071, 0, 2, 0, 0, 17357, 1), + (956, 'Unknown AA 17361', -1, 2080, 65535, 127, 131071, 0, 3, 0, 0, 17361, 1), + (957, 'Unknown AA 17364', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17364, 1), + (958, 'Unknown AA 17370', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17370, 1), + (959, 'Unknown AA 17372', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 17372, 1), + (960, 'Stomping Leap', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 6930, 1), + (961, 'Juggernaut Surge', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6931, 1), + (962, 'Distraction Attack', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6932, 1), + (963, 'Hastened Savage Spirit', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6935, 1), + (964, 'Dying Blow', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6938, 1), + (965, 'Hastened Projection of Fury', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10519, 1), + (966, 'Unknown AA 17373', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 17373, 1), + (967, 'Blade Guardian', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13444, 1), + (968, 'Unknown AA 17375', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 17375, 1), + (969, 'Unknown AA 17378', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 17378, 1), + (970, 'Unknown AA 17378', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 17379, 1), + (971, 'Unknown AA 17378', -1, 16384, 65535, 127, 131071, 0, 2, 0, 0, 17380, 1), + (972, 'Unknown AA 17384', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 17384, 1), + (974, 'Unknown AA 17409', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 17409, 1), + (975, 'Unknown AA 17414', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 17414, 1), + (976, 'Unknown AA 17418', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17418, 1), + (977, 'Unknown AA 17558', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17558, 1), + (978, 'Unknown AA 17428', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17428, 1), + (979, 'Unknown AA 17436', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17436, 1), + (980, 'Natural Invisibility', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6970, 1), + (981, 'Attack of the Warders', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6971, 1), + (982, 'Hastened Feral Attacks', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6974, 1), + (983, 'Hastened Focused Paragon', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6977, 1), + (984, 'Hastened Paragon', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6980, 1), + (985, 'Group Bestial Alignment', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6983, 1), + (986, 'Bite of the Asp', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6984, 1), + (987, 'Raven\'s Claw', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6985, 1), + (988, 'Gorilla Smash', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6986, 1), + (989, 'Stonefoot', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10340, 1), + (990, 'Hastened Stunning Kick', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10343, 1), + (991, 'Quickened Turn Undead', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10470, 1), + (992, 'Tranquil Blessings', -1, 30254, 65535, 127, 131071, 0, 3, 0, 0, 3676, 1), + (993, 'Righteous Zeal', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6082, 1), + (994, 'Hastened Divine Retribution', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6088, 1), + (995, 'Intrinsic Efficiency', -1, 15386, 65535, 127, 131071, 0, 2, 0, 0, 6112, 1), + (996, 'Powerful Elixirs', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6113, 1), + (997, 'Celestial Rapidity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6534, 1), + (998, 'Hastened Celestial Regeneration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 2400, 1), + (999, 'Improved Burst of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7765, 1), + (1000, 'Unknown AA 17439', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17439, 1), + (1001, 'Unknown AA 17445', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17445, 1), + (1002, 'Unknown AA 17448', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 17448, 1), + (1003, 'Unknown AA 10478', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10478, 1), + (1004, 'Unknown AA 17492', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 17492, 1), + (1005, 'Unknown AA 17495', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 17495, 1), + (1006, 'Unknown AA 17515', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 17515, 1), + (1007, 'Unknown AA 17517', -1, 5120, 65535, 127, 131071, 0, 3, 0, 0, 17517, 1), + (1008, 'Unknown AA 17522', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 17522, 1), + (1009, 'Unknown AA 17533', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 17533, 1), + (1011, 'Neshika\'s Blink', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7869, 1), + (1012, 'Five Point Palm', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7875, 1), + (1013, 'War Cry of the Braxi', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 13872, 1), + (1014, 'Unknown AA 17538', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 17538, 1), + (1015, 'Unknown AA 17547', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 17547, 1), + (1016, 'Unknown AA 17549', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 17549, 1), + (1017, 'Unknown AA 17238', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17238, 1), + (1018, 'Unknown AA 17553', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 17553, 1), + (1019, 'Unknown AA 17248', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 17248, 1), + (1020, 'Hastened Companion\'s Blessing', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 12478, 1), + (1021, 'Unknown AA 17215', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 17215, 1), + (1022, 'Destructive Fury', -1, 16540, 65535, 127, 131071, 0, 2, 0, 0, 6636, 1), + (1023, 'Restoration of Life', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14010, 1), + (1024, 'Hastened Leap of Faith', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14085, 1), + (1025, 'Hastened Beacon of the Righteous', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 14011, 1), + (1026, 'Unknown AA 17561', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17561, 1), + (1027, 'Unknown AA 17564', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17564, 1), + (1028, 'Unknown AA 17567', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17567, 1), + (1029, 'Unknown AA 17570', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17570, 1), + (1030, 'Unknown AA 17573', -1, 1024, 65535, 127, 131071, 0, 5, 0, 0, 17573, 1), + (1031, 'Unknown AA 17576', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17576, 1), + (1032, 'Unknown AA 17579', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17579, 1), + (1033, 'Unknown AA 17582', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17582, 1), + (1034, 'Unknown AA 17585', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17585, 1), + (1035, 'Unknown AA 17588', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17588, 1), + (1036, 'Unknown AA 17591', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17591, 1), + (1037, 'Unknown AA 17594', -1, 2048, 65535, 127, 131071, 0, 5, 0, 0, 17594, 1), + (1038, 'Unknown AA 17597', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17597, 1), + (1039, 'Unknown AA 17600', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17600, 1), + (1040, 'Theft of Essence', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 7900, 1), + (1041, 'Malosinete', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 7903, 1), + (1042, 'Unknown AA 17603', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17603, 1), + (1043, 'Unknown AA 17606', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17606, 1), + (1044, 'Unknown AA 17609', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17609, 1), + (1045, 'Unknown AA 17612', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17612, 1), + (1046, 'Unknown AA 17615', -1, 4096, 65535, 127, 131071, 0, 5, 0, 0, 17615, 1), + (1047, 'Unknown AA 17618', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17618, 1), + (1048, 'Unknown AA 17621', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17621, 1), + (1049, 'Unknown AA 17624', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17624, 1), + (1050, 'Unknown AA 17627', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17627, 1), + (1051, 'Unknown AA 17630', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17630, 1), + (1052, 'Unknown AA 17633', -1, 8192, 65535, 127, 131071, 0, 5, 0, 0, 17633, 1), + (1053, 'Unknown AA 10481', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 10481, 1), + (1054, 'Unknown AA 17639', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 17639, 1), + (1060, 'Hastened Turn Undead', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7940, 1), + (1061, 'Cascading Divine Aura', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7943, 1), + (1062, 'Group Purify Soul', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7944, 1), + (1063, 'Hastened Renewal', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7945, 1), + (1064, 'Sanctified Blessing', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7948, 1), + (1065, 'Focused Celestial Regeneration', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7951, 1), + (1090, 'Mastery of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7980, 1), + (1091, 'Hastened Nature\'s Guardian', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7983, 1), + (1092, 'Spirit of the Black Wolf', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7986, 1), + (1093, 'Hastened Lycan Soul', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7989, 1), + (1113, 'Hastened Mass Group Buff', -1, 30254, 65535, 127, 131071, 0, 3, 0, 0, 5010, 1), + (1115, 'Mystical Shield', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 5045, 1), + (1120, 'Self Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8030, 1), + (1121, 'Hastened Veil of Mindshadow', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8031, 1), + (1122, 'Phantasmal Opponent', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8034, 1), + (1123, 'Hastened Edict of Command', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8035, 1), + (1124, 'Fog of Memories', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8038, 1), + (1125, 'Bite of Tashani', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8039, 1), + (1150, 'Fury of Druzzil', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8060, 1), + (1151, 'Fury of Eci', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8063, 1), + (1152, 'Fury of Ro', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8066, 1), + (1153, 'Fortified Entanglement', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8069, 1), + (1154, 'Force of Will', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8072, 1), + (1155, 'Atol\'s Shackles', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8075, 1), + (1156, 'Hastened Manaburn', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8076, 1), + (1157, 'Hastened Call of Xuzl', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 8082, 1), + (1158, 'Divine Steed', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 1667, 1), + (1159, 'Hastened Leap', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 11014, 1), + (1169, 'Unknown AA 16336', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16336, 1), + (1170, 'Unknown AA 16339', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16339, 1), + (1171, 'Hastened Counterattack Discipline', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15502, 1), + (1173, 'Hastened Onslaught', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15509, 1), + (1174, 'Mrylokar\'s Rigor', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15512, 1), + (1175, 'Absorbing Agent', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15515, 1), + (1176, 'Improved Requiem of Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15516, 1), + (1177, 'Quickened Requiem of Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15517, 1), + (1178, 'Silent Displacement', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15521, 1), + (1200, 'Companion\'s Alacrity', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 8190, 1), + (1201, 'Improved Intimidation', -1, 41408, 65535, 127, 131071, 0, 2, 0, 1, 8193, 1), + (1202, 'Perfected Levitation', -1, 31272, 65535, 127, 131071, 0, 2, 0, 0, 8194, 1), + (1203, 'Hastened Fortify Companion', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 8195, 1), + (1204, 'Empowered Ingenuity', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 8198, 1), + (1205, 'Companion\'s Fury', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 8201, 1), + (1206, 'Quickened Radiant Cure', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 8204, 1), + (1207, 'Quickened Radiant Cure', -1, 4, 65535, 127, 131071, 0, 2, 0, 0, 8207, 1), + (1208, 'Mental Stamina', -1, 32446, 65535, 127, 131071, 0, 2, 0, 0, 8210, 1), + (1209, 'Hardy Endurance', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 8215, 1), + (1210, 'Group Perfected Invisibility', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 8220, 1), + (1211, 'Focus of Arcanum', -1, 15904, 65535, 127, 131071, 0, 3, 0, 0, 8221, 1), + (1212, 'Group Perfected Invisibility to Undead', -1, 1046, 65535, 127, 131071, 0, 2, 0, 0, 8222, 1), + (1214, 'Cascade of Life', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 8224, 1), + (1215, 'Summon Companion', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 8227, 1), + (1216, 'Mental Fortitude', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 8228, 1), + (1217, 'Gate', -1, 15906, 65535, 127, 131071, 0, 2, 0, 0, 8231, 1), + (1218, 'Extended Ingenuity', -1, 128, 65535, 127, 131071, 0, 2, 0, 0, 8040, 1), + (1219, 'Armor of Wisdom', -1, 1, 65535, 127, 131071, 0, 2, 0, 0, 8235, 1), + (1220, 'Armor of Wisdom', -1, 20, 65535, 127, 131071, 0, 2, 0, 0, 8240, 1), + (1221, 'Armor of Wisdom', -1, 202, 65535, 127, 131071, 0, 2, 0, 0, 8245, 1), + (1222, 'Armor of Wisdom', -1, 49920, 65535, 127, 131071, 0, 2, 0, 0, 8250, 1), + (1223, 'Armor of Wisdom', -1, 15392, 65535, 127, 131071, 0, 2, 0, 0, 8255, 1), + (1232, 'Way of the Katori', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15429, 1), + (1233, 'Harmony of Battle', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15432, 1), + (1234, 'Hastened Ironfist', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15438, 1), + (1235, 'Two-Finger Wasp Touch', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15447, 1), + (1236, 'Thunderfoot', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15444, 1), + (1237, 'Extended Bloodlust', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15414, 1), + (1239, 'Consumption of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15423, 1), + (1240, 'Frenzied Swipes', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15424, 1), + (1242, 'Hastened Synergy', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15450, 1), + (1243, 'Hastened Crane Stance', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15453, 1), + (1244, 'Hastened Eye Gouge', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 15456, 1), + (1245, 'Troubadour\'s Slashing Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15540, 1), + (1246, 'Troubadour\'s Blunt Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15543, 1), + (1247, 'Troubadour\'s Piercing Mastery', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15546, 1), + (1248, 'Hastened Lure of the Siren\'s Song', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 15549, 1), + (1249, 'Frenzied Axe of Rallos', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15555, 1), + (1250, 'Juggernaut\'s Mastery of Throwing', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15564, 1), + (1251, 'Furious Rampage', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15567, 1), + (1252, 'Battle Stomp', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15569, 1), + (1253, 'Communion of Blood', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15570, 1), + (1254, 'Hastened Dying Grasp', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15571, 1), + (1255, 'Rest the Dead', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 15574, 1), + (1256, 'Extended Encroaching Darkness', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 15579, 1), + (1257, 'Hand of Death', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15582, 1), + (1258, 'Quickened Levant', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15591, 1), + (1259, 'Cascade of Decay', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15594, 1), + (1261, 'Hastened Fury of the Gods', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15598, 1), + (1262, 'Lower Element', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15601, 1), + (1263, 'Destructive Adept', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15602, 1), + (1264, 'Arcane Fusion', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15609, 1), + (1265, 'Arcane Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15611, 1), + (1266, 'Force of Flame', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15612, 1), + (1267, 'Force of Ice', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 15615, 1), + (1269, 'Sha\'s Reprisal', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15425, 1), + (1270, 'Crippling Spirit', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 15377, 1), + (1271, 'Quick Damage', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 15622, 1), + (1272, 'Assassin\'s Wrath', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15625, 1), + (1273, 'Hastened Swiftblade', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 15634, 1), + (1274, 'Improved Explosion of Spite', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15639, 1), + (1275, 'Improved Explosion of Hatred', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15640, 1), + (1277, 'Soul Touch', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15642, 1), + (1278, 'Soul Flay', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15643, 1), + (1279, 'Ragged Bite of Agony', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15646, 1), + (1281, 'Everburn', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 15648, 1), + (1282, 'Marr\'s Gift', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15619, 1), + (1300, 'Fundament of Intellect', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 9100, 1), + (1301, 'Fundament of Intellect', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9109, 1), + (1302, 'Fundament of Intellect', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 9118, 1), + (1303, 'Fundament of Intellect', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 9127, 1), + (1304, 'Fundament of Wisdom', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 9136, 1), + (1305, 'Fundament of Wisdom', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 9145, 1), + (1306, 'Fundament of Wisdom', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 9154, 1), + (1307, 'Fundament of Power', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 9163, 1), + (1308, 'Fundament of Power', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9172, 1), + (1309, 'Fundament of Power', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 9181, 1), + (1310, 'Fundament of Power', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 9190, 1), + (1311, 'Fundament of Power', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 9199, 1), + (1312, 'Fundament of Combat', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 9208, 1), + (1313, 'Fundament of Combat', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9217, 1), + (1314, 'Fundament of Combat', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 9226, 1), + (1315, 'Fundament of Combat', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 9235, 1), + (1350, 'Fundament: First Spire of Arcanum', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 9300, 1), + (1351, 'Fundament: Second Spire of Arcanum', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 9303, 1), + (1352, 'Fundament: Third Spire of Arcanum', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 9306, 1), + (1360, 'Fundament: First Spire of the Sensei', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9309, 1), + (1361, 'Fundament: Second Spire of the Sensei', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9312, 1), + (1362, 'Fundament: Third Spire of the Sensei', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9315, 1), + (1370, 'Fundament: First Spire of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 9318, 1), + (1371, 'Fundament: Second Spire of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 9321, 1), + (1372, 'Fundament: Third Spire of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 9324, 1), + (1380, 'Fundament: First Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 9327, 1), + (1381, 'Fundament: Second Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 9330, 1), + (1382, 'Fundament: Third Spire of Enchantment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 9333, 1), + (1390, 'Fundament: First Spire of Necromancy', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9336, 1), + (1391, 'Fundament: Second Spire of Necromancy', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9339, 1), + (1392, 'Fundament: Third Spire of Necromancy', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9342, 1), + (1400, 'Fundament: First Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 9345, 1), + (1401, 'Fundament: Second Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 9348, 1), + (1402, 'Fundament: Third Spire of the Warlord', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 9351, 1), + (1403, 'Sturdy Companion', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 9503, 1), + (1404, 'Extended Swarm', -1, 32306, 65535, 127, 131071, 0, 3, 0, 0, 9506, 1), + (1405, 'Twincast', -1, 15906, 65535, 127, 131071, 0, 3, 0, 0, 9509, 1), + (1406, 'Staff Block', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 9512, 1), + (1410, 'Fundament: First Spire of the Rake', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 9354, 1), + (1411, 'Fundament: Second Spire of the Rake', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 9357, 1), + (1412, 'Fundament: Third Spire of the Rake', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 9360, 1), + (1420, 'Fundament: First Spire of the Minstrels', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 9363, 1), + (1421, 'Fundament: Second Spire of the Minstrels', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 9366, 1), + (1422, 'Fundament: Third Spire of the Minstrels', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 9369, 1), + (1430, 'Fundament: First Spire of the Savage Lord', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 9372, 1), + (1431, 'Fundament: Second Spire of the Savage Lord', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 9375, 1), + (1432, 'Fundament: Third Spire of the Savage Lord', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 9378, 1), + (1433, 'Extended Ingenuity', -1, 33089, 65535, 127, 131071, 0, 2, 0, 0, 8232, 1), + (1440, 'Fundament: First Spire of Holiness', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 9381, 1), + (1441, 'Fundament: Second Spire of Holiness', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 9384, 1), + (1442, 'Fundament: Third Spire of Holiness', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 9387, 1), + (1450, 'Fundament: First Spire of the Reavers', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9390, 1), + (1451, 'Fundament: Second Spire of the Reavers', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9393, 1), + (1452, 'Fundament: Third Spire of the Reavers', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9396, 1), + (1460, 'Fundament: First Spire of the Pathfinders', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 9399, 1), + (1461, 'Fundament: Second Spire of the Pathfinders', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 9402, 1), + (1462, 'Fundament: Third Spire of the Pathfinders', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 9405, 1), + (1470, 'Fundament: First Spire of Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 9408, 1), + (1471, 'Fundament: Second Spire of Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 9411, 1), + (1472, 'Fundament: Third Spire of Divinity', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 9414, 1), + (1480, 'Fundament: First Spire of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 9417, 1), + (1481, 'Fundament: Second Spire of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 9420, 1), + (1482, 'Fundament: Third Spire of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 9423, 1), + (1490, 'Fundament: First Spire of Ancestors', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 9426, 1), + (1491, 'Fundament: Second Spire of Ancestors', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 9429, 1), + (1492, 'Fundament: Third Spire of Ancestors', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 9432, 1), + (1500, 'Fundament: First Spire of Savagery', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 9435, 1), + (1501, 'Fundament: Second Spire of Savagery', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 9438, 1), + (1502, 'Fundament: Third Spire of Savagery', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 9441, 1), + (1503, 'Hallowed Steed', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 13673, 1), + (1504, 'Wicked Steed', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 13674, 1), + (1505, 'Unknown AA 16103', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 16103, 1), + (1580, 'Divine Companion Aura', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 5809, 1), + (1662, 'Spell Casting Mastery', -1, 16412, 65535, 127, 131071, 0, 2, 0, 0, 1216, 1), + (1663, 'Gift of Mana', -1, 16412, 65535, 127, 131071, 0, 2, 0, 0, 1219, 1), + (1664, 'Twinproc', -1, 50175, 65535, 127, 131071, 0, 3, 0, 0, 12416, 1), + (1665, 'Tactical Mastery', -1, 16596, 65535, 127, 131071, 0, 3, 0, 0, 12419, 1), + (1666, 'Group Perfected Levitation', -1, 31272, 65535, 127, 131071, 0, 2, 0, 0, 12422, 1), + (1667, 'Quickened Encroaching Darkness', -1, 1040, 65535, 127, 131071, 0, 2, 0, 0, 6026, 1), + (1668, 'Acute Focus of Arcanum', -1, 15904, 65535, 127, 131071, 0, 3, 0, 0, 8260, 1), + (1669, 'Flurry', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 5806, 1), + (1680, 'Hastened Flash of Anger', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13905, 1), + (1681, 'Hastened Bazu Roar', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13908, 1), + (1682, 'Hastened Scowl', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13911, 1), + (1683, 'Hastened Mark of the Mage Hunter', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 13917, 1), + (1684, 'Knowledge of Alaran Culture', 2, 65535, 65535, 127, 131071, 0, 4, 0, 0, 14017, 1), + (1685, 'Knowledge of Alaran Culture - Advanced', 2, 65535, 65535, 127, 131071, 0, 4, 0, 0, 14018, 1), + (1686, 'Brace For Impact', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 14019, 1), + (1687, 'Summon Tome of the Hero\'s Journey', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 14371, 1), + (1800, 'Enchant Planar Alloy', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 14373, 1), + (1801, 'Mass Enchant Planar Alloy', -1, 8192, 65535, 127, 131071, 0, 3, 0, 1, 14374, 1), + (2000, 'Armor of Experience', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 4700, 1), + (2001, 'Sneering Grin', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15096, 1), + (2002, 'Warlord\'s Grasp', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15099, 1), + (2003, 'Hastened Press the Attack', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15100, 1), + (2004, 'Hastened Rage of Rallos Zek', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15105, 1), + (2005, 'Hastened Unbroken Attention', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15108, 1), + (2006, 'Extended Resplendant Glory', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15113, 1), + (2007, 'Wars Sheol\'s Heroic Blade', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15119, 1), + (2008, 'Hastened Vehement Rage', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15120, 1), + (2009, 'Hastened Barbed Tongue', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15123, 1), + (2010, 'Hastened Shield Topple', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15126, 1), + (2011, 'Imperator\'s Command', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15129, 1), + (2012, 'Imperator\'s Charge', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15130, 1), + (2013, 'Imperator\'s Precision', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 15131, 1), + (2014, 'Hastened Divine Call', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15132, 1), + (2015, 'Extended Divine Call', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15135, 1), + (2016, 'Heroic Leap', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15136, 1), + (2018, 'Helix of the Undying', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 15146, 1), + (2019, 'Group Armor of the Inquisitor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15147, 1), + (2020, 'Quickened Demand For Honor', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15150, 1), + (2021, 'Extended Sanctification', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15153, 1), + (2022, 'Extended Speed of the Savior', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15154, 1), + (2023, 'Extended Preservation of Marr', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15155, 1), + (2024, 'Extended Shield of Brilliance', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15158, 1), + (2025, 'Extended Blessing of the Faithful', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15159, 1), + (2026, 'Hastened Speed of the Savior', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15162, 1), + (2028, 'Hastened Shield of Brilliance', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 15168, 1), + (2031, 'Purity of Death', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15177, 1), + (2032, 'Quickened Scourge Skin', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15179, 1), + (2034, 'Gift of the Quick Spear', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15193, 1), + (2035, 'Extended Provocation for Power', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 15194, 1), + (2036, 'Quickened Auspice of the Hunter', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15253, 1), + (2037, 'Chameleon\'s Gift', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15304, 1), + (2040, 'Hastened Enraging Kicks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15283, 1), + (2041, 'Close Combat Mastery', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15288, 1), + (2042, 'Quickened Cover Tracks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 15295, 1), + (2045, 'Shield of Reverence', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15338, 1), + (2046, 'Extended Healing Frenzy', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15342, 1), + (2047, 'Call of the Herald', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 15343, 1), + (2048, 'Covenant of Spirit', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 15356, 1), + (2049, 'Talisman of Celerity', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 15357, 1), + (2050, 'Extended Spiritual Blessing', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 15358, 1), + (2051, 'Rejuvenation of Spirit', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 15362, 1), + (2053, 'Hastened Turgur\'s Swarm', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 15371, 1), + (2054, 'Shielding of Spirits', -1, 16930, 65535, 127, 131071, 0, 2, 0, 0, 15374, 1), + (2055, 'Hastened Lunar Healing', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 15383, 1), + (2056, 'Quickened Blessing of Ro', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 15389, 1), + (2057, 'Hastened Wall of Wind', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 15403, 1), + (2059, 'Quickened Focused Paragon of Spirit', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 15406, 1), + (2060, 'Elemental Ward', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15200, 1), + (2061, 'Cloak of Shadows', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15203, 1), + (2062, 'Hastened Elemental Union', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15204, 1), + (2063, 'Hastened Virulent Talon', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15207, 1), + (2064, 'Wind of Malosinete', -1, 4608, 65535, 127, 131071, 0, 3, 0, 0, 15210, 1), + (2065, 'Mana Reserve', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15213, 1), + (2066, 'Second Wind Ward', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15214, 1), + (2076, 'Steel Vengeance', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15217, 1), + (2077, 'Extended Vapor Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15220, 1), + (2078, 'Extended Stone Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15223, 1), + (2079, 'Extended Fire Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15226, 1), + (2080, 'Extended Ice Core', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15229, 1), + (2081, 'Flames of Power', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 15232, 1), + (2200, 'Rune of Banishment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15475, 1), + (2201, 'Hastened Glyph Spray', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15478, 1), + (2202, 'Illusions of Grandeur', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15481, 1), + (2203, 'Illusory Ally', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15482, 1), + (2204, 'Gracious Gift of Mana', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15485, 1), + (2205, 'Chromatic Haze', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15486, 1), + (2206, 'Blanket of Forgetfulness', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15489, 1), + (2207, 'Ethereal Manipulation', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15490, 1), + (2208, 'Quick Mezz', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15493, 1), + (2209, 'Reactive Rune', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 15496, 1), + (2234, 'Cover Tracks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10368, 1), + (2235, 'Imbued Ferocity', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10387, 1), + (2709, 'Perfected Dead Man Floating', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 13692, 1), + (2899, 'Levant', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 10700, 1), + (3000, 'Auroria Mastery', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 6987, 1), + (3202, 'Pet Discipline', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 7733, 1), + (3203, 'Enchant Palladium Trio', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7736, 1), + (3204, 'Mass Enchant Palladium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7737, 1), + (3205, 'Greater Mass Enchant Palladium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7738, 1), + (3206, 'Enchant Dwerium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7732, 1), + (3207, 'Mass Enchant Dwerium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7734, 1), + (3208, 'Enchant Palladium', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7735, 1), + (3209, 'Enchant Temporite', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7739, 1), + (3210, 'Mass Enchant Temporite', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7740, 1), + (3211, 'Nature\'s Reprieve', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10388, 1), + (3212, 'Hastened Divine Intervention', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10358, 1), + (3213, 'Projection of Fury', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 10351, 1), + (3214, 'Improved Atone', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10364, 1), + (3215, 'Projection of Doom', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10352, 1), + (3216, 'Projection of Piety', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10353, 1), + (3217, 'Hastened Jolting Kicks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 12500, 1), + (3218, 'Enchant Cosgrite', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7741, 1), + (3219, 'Mass Enchant Cosgrite', 6, 8192, 65535, 127, 131071, 0, 3, 0, 1, 7742, 1), + (3500, 'Blessing of Light', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10355, 1), + (3506, 'Fierce Eye', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 5717, 1), + (3511, 'Punch Mastery', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 6020, 1), + (3512, 'Companion\'s Durability', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 6051, 1), + (3513, 'Rake\'s Deadly Aim', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6322, 1), + (3514, 'Rogue\'s Fury', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6325, 1), + (3515, 'Envenomed Blades', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6328, 1), + (3516, 'Companion of Necessity', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 6333, 1), + (3517, 'Rake\'s Powerful Aim', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6334, 1), + (3518, 'Hastened Cacophony', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6337, 1), + (3519, 'Hastened Funeral Dirge', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6340, 1), + (3520, 'Master\'s Hastened Combination', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 6343, 1), + (3521, 'Hastened Silent Casting', -1, 546, 65535, 127, 131071, 0, 2, 0, 0, 6346, 1), + (3522, 'Hastened Silent Casting', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 6349, 1), + (3525, 'Precise Blow', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 5776, 1), + (3550, 'Beguiler\'s Banishment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 5849, 1), + (3551, 'Beguiler\'s Directed Banishment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 5870, 1), + (3600, 'Rapid Defiance', 1, 1, 65535, 127, 131071, 0, 3, 0, 1, 6136, 1), + (3646, 'Blast of Anger', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6135, 1), + (3676, 'Gift of Life', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10354, 1), + (3701, 'Dirge of the Sleepwalker', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6200, 1), + (3702, 'Quick Time', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6201, 1), + (3703, 'Steady Hands ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6202, 1), + (3704, 'Selo\'s Sonata', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6205, 1), + (3705, 'Companion\'s Blessing ', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 6206, 1), + (3706, 'Hastened Bestial Alignment ', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6209, 1), + (3707, 'Fortify Companion ', -1, 30224, 65535, 127, 131071, 0, 2, 0, 0, 6212, 1), + (3708, 'Burst of Power ', -1, 20, 65535, 127, 131071, 0, 2, 0, 0, 6215, 1), + (3709, 'Pact of the Wurine', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6218, 1), + (3710, 'Reckless Abandon ', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6219, 1), + (3711, 'Gift of Resurrection', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6222, 1), + (3713, 'Hastened Call of the Wild ', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 6228, 1), + (3714, 'Protection of Direwood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 6232, 1), + (3716, 'Clinging Root ', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 6236, 1), + (3718, 'Critical Affliction', -1, 8194, 65535, 127, 131071, 0, 2, 0, 0, 6240, 1), + (3720, 'Mana Overburn ', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 6249, 1), + (3724, 'Knight\'s Return Strike ', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 6266, 1), + (3725, 'Hunter\'s Return Kick ', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6269, 1), + (3726, 'Hastened Ligament Slice ', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6272, 1), + (3727, 'Knave\'s Return Strike', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 6275, 1), + (3728, 'Storm Strike', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 6278, 1), + (3729, 'Turgur\'s Swarm', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6281, 1), + (3730, 'Silent Presence', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6282, 1), + (3731, 'Infused by Rage ', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6283, 1), + (3732, 'Gut Punch', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6286, 1), + (3733, 'Warlord\'s Return Kick', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6287, 1), + (3734, 'Arcomancy ', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 6290, 1), + (3800, 'Blessing of Resurrection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6299, 1), + (3801, 'General Sturdiness', -1, 65535, 65535, 127, 131071, 0, 1, 0, 0, 6119, 1), + (3802, 'Shield Block', -1, 392, 65535, 127, 131071, 0, 2, 0, 0, 6124, 1), + (3803, 'Hastened Trueshot', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6355, 1), + (3804, 'Outrider\'s Accuracy', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6370, 1), + (3805, 'Hastened Mend', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 4801, 1), + (3812, 'Perfected Invisibility', -1, 14336, 65535, 127, 131071, 0, 3, 0, 0, 7069, 1), + (3813, 'Spell Casting Reinforcement', -1, 7168, 65535, 127, 131071, 0, 2, 0, 0, 6257, 1), + (3815, 'Destructive Cascade', -1, 9776, 65535, 127, 131071, 0, 3, 0, 0, 6375, 1), + (3816, 'Companion\'s Relocation', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 6379, 1), + (3817, 'Focused Paragon of Spirits', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6380, 1), + (3818, 'Companion\'s Agility', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 6383, 1), + (3819, 'Maestro\'s Concentration', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 6386, 1), + (3820, 'Blessing of Life', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6395, 1), + (3821, 'Quickened Harvest of Druzzil', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 6503, 1), + (3822, 'Chattering Bones', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6508, 1), + (3823, 'Warlord\'s Deadly Aim', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 6511, 1), + (3824, 'Quickened Call of the Wild', -1, 544, 65535, 127, 131071, 0, 3, 0, 0, 6514, 1), + (3826, 'Force of Disruption', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 5984, 1), + (3830, 'Hastened Divine Avatar', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7100, 1), + (3831, 'Hastened Purification', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 7103, 1), + (3832, 'Beastlords Feral Kick', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 7106, 1), + (3833, 'Burst of Power ', -1, 32841, 65535, 127, 131071, 0, 2, 0, 0, 6409, 1), + (3834, 'Burst of Power ', -1, 256, 65535, 127, 131071, 0, 2, 0, 0, 6419, 1), + (3835, 'Shield Block', -1, 15360, 65535, 127, 131071, 0, 2, 0, 0, 6428, 1), + (3836, 'Holy Root', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6436, 1), + (3837, 'Burst of Power ', -1, 16512, 65535, 127, 131071, 0, 2, 0, 0, 6060, 1), + (3838, 'Quickened Suspend Minion', -1, 30224, 65535, 127, 131071, 0, 3, 0, 0, 6445, 1), + (3839, 'Quickened Summon Axes', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6452, 1), + (3840, 'Recourse of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6601, 1), + (3841, 'Call Hither', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 6455, 1), + (3842, 'Fortified Survival', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 6458, 1), + (3843, 'Fortified Intervention', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 6461, 1), + (3865, 'Planar Durability', -1, 72, 65535, 127, 131071, 0, 3, 0, 0, 6422, 1), + (3890, 'Hastened Force of Will', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 7822, 1), + (3891, 'Hastened Burnout', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 7832, 1), + (3892, 'Hastened Rumbling Servant', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 7828, 1), + (3893, 'Extended Rumbling Servant', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 7827, 1), + (3899, 'Furious Leap', -1, 32769, 65535, 127, 131071, 0, 3, 0, 0, 6499, 1), + (4001, 'Undaunted Fury', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 7407, 1), + (4002, 'Frenzied Volley', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 7818, 1), + (4200, 'Hastened Forceful Rejuvenation', -1, 32318, 65535, 127, 131071, 0, 2, 0, 0, 12475, 1), + (4666, 'Shield Specialist', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 4666, 1), + (5000, 'Glyph of Courage', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7000, 1), + (5002, 'Glyph of Stored Life', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7002, 1), + (5003, 'Glyph of Frantic Infusion', 7, 30224, 65535, 127, 131071, 0, 4, 1, 0, 7003, 1), + (5004, 'Glyph of Angry Thoughts', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7004, 1), + (5005, 'Foraging', 8, 65535, 65535, 127, 131071, 0, 1, 0, 0, 7062, 1), + (6000, 'Harm Touch', 9, 16, 65535, 127, 131071, 0, 3, 0, 0, 7800, 1), + (6001, 'Lay on Hands', 9, 4, 65535, 127, 131071, 0, 3, 0, 0, 7850, 1), + (6002, 'Hunter\'s Attack Power', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 6546, 1), + (6106, 'Sustained Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 6106, 1), + (6302, 'Hastened Reckless Abandon', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6302, 1), + (6362, 'Hastened Recklessness', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6362, 1), + (6478, 'Hastened Blessing of Resurrection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6478, 1), + (6481, 'Hastened Divine Resurrection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6481, 1), + (6488, 'Flurry of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 6488, 1), + (6489, 'Hastened Holyforge', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6489, 1), + (6492, 'Inquisitor\'s Judgement', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 6492, 1), + (6988, 'Extended Group Bestial Alignment', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 6988, 1), + (7000, 'Voice of Thule', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 6639, 1), + (7001, 'Zan Fi\'s Whistle', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 7872, 1), + (7002, 'Summon Remains', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 9500, 1), + (7003, 'Forceful Rejuvenation', -1, 32318, 65535, 127, 131071, 0, 2, 0, 0, 9502, 1), + (7007, 'Summon Remains', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 9501, 1), + (7009, 'Teleport Bind', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 1419, 1), + (7016, 'Glyph of the Master', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7016, 1), + (7017, 'Glyph of Lost Secrets', 7, 32318, 65535, 127, 131071, 0, 4, 1, 0, 7017, 1), + (7018, 'Glyph of Genari Might', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7018, 1), + (7019, 'Glyph of the Cataclysm', 7, 65535, 65535, 127, 131071, 0, 4, 1, 0, 7019, 1), + (7025, 'Group Shrink', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 7669, 1), + (7033, 'Lasting Bravery', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 7033, 1), + (7036, 'Hastened Blast of Anger', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 7036, 1), + (7050, 'Call of the Hero', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 1017, 1), + (7060, 'Precision of Axes', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 4809, 1), + (7070, 'Hastened Distraction Attack', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6941, 1), + (7105, 'Deathly Pact', -1, 1040, 65535, 127, 131071, 0, 3, 0, 0, 976, 1), + (7106, 'Planar Durability', -1, 16768, 65535, 127, 131071, 0, 3, 0, 0, 6467, 1), + (7107, 'Hastened Getaway', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 7005, 1), + (7108, 'Divine Aura', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 977, 1), + (7109, 'Hastened Wrath of the Wild', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 7664, 1), + (7689, 'Burst of Life', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7689, 1), + (7690, 'Spirit Mastery', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 7690, 1), + (7695, 'Quickened Blood of Avoling', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 7695, 1), + (7698, 'Dead Man Floating', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 7698, 1), + (7699, 'Dread Incarnate', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 7699, 1), + (7700, 'Flurry', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 7700, 1), + (7703, 'Death Bloom', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 7703, 1), + (7712, 'Disruptive Persecution', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 7712, 1), + (7715, 'Hastened Whisperwind', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 7715, 1), + (7743, 'Hastened Guardian of the Forest', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7743, 1), + (7746, 'Hastened Flusterbolt', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7746, 1), + (7747, 'Volatile Arrow', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7747, 1), + (7748, 'Pathfinder\'s Grace', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7748, 1), + (7751, 'Hastened Cover Tracks', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 7751, 1), + (7754, 'Steed of Souls', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7754, 1), + (7755, 'Scourge Skin', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7755, 1), + (7756, 'Death\'s Effigy', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7756, 1), + (7757, 'Hastened Visage of Death', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7757, 1), + (7760, 'Hastened Hate Step', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 7760, 1), + (7801, 'Songwriting', 6, 128, 65535, 127, 131071, 0, 3, 0, 0, 9001, 1), + (7809, 'Hybrid Research', 6, 16412, 65535, 127, 131071, 0, 2, 0, 0, 9011, 1), + (7819, 'Written Prayer', 6, 546, 65535, 127, 131071, 0, 2, 0, 0, 9021, 1), + (7925, 'Sionachie\'s Crescendo', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 1018, 1), + (8081, 'Summon Resupply Agent', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 9000, 1), + (8130, 'Summon Clockwork Banker', 5, 65535, 65535, 127, 131071, 0, 4, 0, 1, 9031, 1), + (8200, 'Hastened Dirge of the Sleepwalker', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10329, 1), + (8201, 'Vainglorious Shout ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10330, 1), + (8202, 'Lyre Leap ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10331, 1), + (8203, 'Domination Mastery ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10332, 1), + (8204, 'Lyrical Prankster', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10333, 1), + (8205, 'Selo\'s Kick ', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10336, 1), + (8261, 'A Tune Stuck In Your Head', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 10339, 1), + (8262, 'The Show Must Go On', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 7010, 1), + (8300, 'Spell Casting Subtlety', -1, 16384, 65535, 127, 131071, 0, 2, 0, 0, 10370, 1), + (8301, 'Improved Natural Invisibility', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 10373, 1), + (8302, 'Protection of the Warder', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 10374, 1), + (8303, 'Nature\'s Salve', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 10377, 1), + (8304, 'Focus of Animus', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 10380, 1), + (8314, 'Fluid March', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 8314, 1), + (8317, 'Hastened Selo\'s Kick', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 8317, 1), + (8319, 'Hastened Bellow', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 8319, 1), + (8322, 'Belltone Mind', -1, 128, 65535, 127, 131071, 0, 3, 0, 0, 8322, 1), + (8325, 'Subtle Blows', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 8325, 1), + (8331, 'Enhanced Thief\'s Eyes', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 8331, 1), + (8332, 'Extended Languid Bite', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 8332, 1), + (8335, 'Quickened Malosinete', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 8335, 1), + (8341, 'Drape of Shadows', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 8341, 1), + (8342, 'Host in the Shell', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 8342, 1), + (8347, 'Hastened Mana Draw', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8347, 1), + (8350, 'Hastened Mezmerization', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 8350, 1), + (8400, 'Self Preservation', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 10400, 1), + (8401, 'Hastened Frenzy', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 10401, 1), + (8402, 'Extended Havoc', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 10404, 1), + (8500, 'Healing Frenzy', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10450, 1), + (8501, 'Overpowering Strikes', -1, 6, 65535, 127, 131071, 0, 3, 0, 0, 10453, 1), + (8502, 'Quickened Blessing of Ressurection', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10456, 1), + (8503, 'Hastened Atonement', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10459, 1), + (8504, 'Improved Sanctuary', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10462, 1), + (8505, 'Blessing of Sanctuary', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10463, 1), + (8506, 'Hastened Celestial Hammer', -1, 2, 65535, 127, 131071, 0, 3, 0, 0, 10464, 1), + (8600, 'Spirit of Eagle', -1, 40, 65535, 127, 131071, 0, 3, 0, 0, 10500, 1), + (8601, 'Flight of Eagles', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10501, 1), + (8602, 'Egress', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10502, 1), + (8603, 'Spirits of Nature', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10503, 1), + (8604, 'Wall of Wind', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10506, 1), + (8605, 'Hastened Spirit of the Wood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10511, 1), + (8606, 'Hastened Convergence of Spirits', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10514, 1), + (8700, 'Beam of Slumber', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10550, 1), + (8701, 'Phantasmic Reflex', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10551, 1), + (8702, 'Friendly Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10557, 1), + (8703, 'Hastened Self Stasis', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10558, 1), + (8704, 'Forceful Banishment', -1, 8192, 65535, 127, 131071, 0, 3, 0, 0, 10561, 1), + (8708, 'Hastened Cascading Rage', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 6908, 1), + (8800, 'Force of Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 10600, 1), + (8801, 'Aspect of Zomm', -1, 6144, 65535, 127, 131071, 0, 3, 0, 0, 10603, 1), + (8802, 'Extended Shared Health', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 10610, 1), + (8900, 'Agile Feet', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10650, 1), + (8901, 'Hastened Defensive Poses', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10653, 1), + (8902, 'Extended Impenetrable Discipline', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10656, 1), + (8903, 'Hastened Destructive Force', -1, 64, 65535, 127, 131071, 0, 3, 0, 0, 10657, 1), + (9001, 'Reluctant Benevolence', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 10701, 1), + (9100, 'Bestow Divine Aura', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10752, 1), + (9101, 'Blessing of Purification', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10753, 1), + (9102, 'Sense the Dead', -1, 1030, 65535, 127, 131071, 0, 3, 0, 0, 10754, 1), + (9200, 'Hastened Auspice of the Hunter', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10800, 1), + (9201, 'Clenched Jaw', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10803, 1), + (9202, 'Scout\'s Mastery of Fire', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10806, 1), + (9203, 'Scout\'s Mastery of Ice', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10809, 1), + (9205, 'Scout\'s Mastery of Slashing', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10815, 1), + (9206, 'Scout\'s Mastery of Piercing', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10818, 1), + (9207, 'Scout\'s Mastery of Blunt Weapons', -1, 8, 65535, 127, 131071, 0, 3, 0, 0, 10821, 1), + (9300, 'Massive Strike', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 10850, 1), + (9301, 'Strikethrough', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 10853, 1), + (9400, 'Hate\'s Attraction', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10900, 1), + (9401, 'Feigned Minion', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10903, 1), + (9402, 'Hastened Summon Remains', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10909, 1), + (9403, 'Visage of Death', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10912, 1), + (9404, 'Cascading Theft of Life', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10915, 1), + (9500, 'Extended Sloth', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10950, 1), + (9501, 'Hastened Ancestral Aid', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10951, 1), + (9502, 'Hastened Union of Spirits', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10954, 1), + (9503, 'Group Shrink', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10957, 1), + (9504, 'Inconspicuous Totem', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10958, 1), + (9505, 'Extended Pestilence', -1, 512, 65535, 127, 131071, 0, 3, 0, 0, 10959, 1), + (9600, 'Hastened Taunt', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 11000, 1), + (9601, 'Extended Shield Reflect', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 11003, 1), + (9602, 'Extended Commanding Voice', -1, 1, 65535, 127, 131071, 0, 3, 0, 0, 11004, 1), + (9700, 'Hastened Destruction', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11050, 1), + (9701, 'Netherstep', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11055, 1), + (9702, 'Beam of Displacement', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11056, 1), + (9703, 'Translocate', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11057, 1), + (9704, 'Teleport', -1, 2048, 65535, 127, 131071, 0, 3, 0, 0, 11058, 1), + (10367, 'Ageless Enmity', -1, 1, 65535, 127, 131071, 0, 2, 0, 0, 10367, 1), + (10389, 'Extended Trickery', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 10389, 1), + (10392, 'Ageless Enmity', -1, 20, 65535, 127, 131071, 0, 2, 0, 0, 10392, 1), + (10393, 'Shackles of Tunare', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10393, 1), + (10394, 'Beacon of the Righteous', -1, 4, 65535, 127, 131071, 0, 3, 0, 0, 10394, 1), + (10395, 'Bobbing Corpse', -1, 16, 65535, 127, 131071, 0, 3, 0, 0, 10395, 1), + (10396, 'Group Spirit of the White Wolf', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10396, 1), + (10397, 'Group Spirit of the Black Wolf', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10397, 1), + (10405, 'Hastened Deflection Discipline', -1, 20, 65535, 127, 131071, 0, 3, 0, 0, 10405, 1), + (10410, 'Rogue Triple Attack Skillup Test', -1, 256, 65535, 127, 131071, 0, 3, 0, 1, 10410, 1), + (10413, 'Hastened Host of the Elements', -1, 4096, 65535, 127, 131071, 0, 3, 0, 0, 10413, 1), + (10424, 'Hand of Ro', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10424, 1), + (10425, 'Fixation of Ro', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10425, 1), + (10426, 'Peaceful Spirit of the Wood', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10426, 1), + (10427, 'Peaceful Convergence of Spirits', -1, 32, 65535, 127, 131071, 0, 3, 0, 0, 10427, 1), + (10434, 'Quickened Army of the Dead', -1, 1024, 65535, 127, 131071, 0, 3, 0, 0, 10434, 1), + (11073, 'Playing Possum', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11073, 1), + (11074, 'Cat-like Reflexes', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11074, 1), + (11077, 'Hastened Bite of the Asp', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11077, 1), + (11078, 'Hastened Gorilla Smash', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11078, 1), + (11079, 'Hastened Raven\'s Claw', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11079, 1), + (11080, 'Chameleon Strike', -1, 16384, 65535, 127, 131071, 0, 3, 0, 0, 11080, 1), + (11085, 'Two Hands, No Mercy!', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 11085, 1), + (11088, 'Hastened Cry of Battle', -1, 32768, 65535, 127, 131071, 0, 3, 0, 0, 11088, 1), + (12600, 'Hastened Frenzied Stabbing', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12600, 1), + (12603, 'Extended Frenzied Stabbing Discipline', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12603, 1), + (12606, 'Speed of the Scoundrel', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12606, 1), + (12607, 'Hastened Pinpoint', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12607, 1), + (12615, 'Hastened Twisted Chance Discipline', -1, 256, 65535, 127, 131071, 0, 3, 0, 0, 12615, 1), + (15073, 'Banestrike', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 15073, 1), + (15074, 'Hastened Banestrike', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 15074, 1), + (30050, 'Unknown AA 30050', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 30050, 1), + (30100, 'Unknown AA 30100', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 30100, 1), + (30150, 'Unknown AA 30150', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 30150, 1), + (30175, 'Unknown AA 30175', 2, 65335, 65535, 127, 131071, 0, 4, 0, 1, 30175, 1), + (30180, 'Unknown AA 30180', 2, 128, 65535, 127, 131071, 0, 4, 0, 1, 30180, 1), + (30185, 'Unknown AA 30185', 2, 64, 65535, 127, 131071, 0, 4, 0, 1, 30185, 1), + (30190, 'Unknown AA 30190', 2, 8, 65535, 127, 131071, 0, 4, 0, 1, 30190, 1), + (30195, 'Unknown AA 30195', 2, 65535, 65535, 127, 131071, 0, 4, 0, 1, 30195, 1); + +DROP TABLE IF EXISTS `aa_ranks`; +CREATE TABLE IF NOT EXISTS `aa_ranks` ( + `id` int(10) unsigned NOT NULL, + `upper_hotkey_sid` int(10) NOT NULL DEFAULT '-1', + `lower_hotkey_sid` int(10) NOT NULL DEFAULT '-1', + `title_sid` int(10) NOT NULL DEFAULT '-1', + `desc_sid` int(10) NOT NULL DEFAULT '-1', + `cost` int(10) NOT NULL DEFAULT '1', + `level_req` int(10) NOT NULL DEFAULT '51', + `spell` int(10) NOT NULL DEFAULT '-1', + `spell_type` int(10) NOT NULL DEFAULT '0', + `recast_time` int(10) NOT NULL DEFAULT '0', + `expansion` int(10) NOT NULL DEFAULT '0', + `prev_id` int(10) NOT NULL DEFAULT '-1', + `next_id` int(10) NOT NULL DEFAULT '-1', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `aa_ranks` (`id`, `upper_hotkey_sid`, `lower_hotkey_sid`, `title_sid`, `desc_sid`, `cost`, `level_req`, `spell`, `spell_type`, `recast_time`, `expansion`, `prev_id`, `next_id`) VALUES + (2, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, -1, 3), + (3, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, 2, 4), + (4, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, 3, 5), + (5, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, 4, 6), + (6, -1, -1, 2, 2, 1, 51, -1, 0, 0, 3, 5, 292), + (7, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, -1, 8), + (8, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, 7, 9), + (9, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, 8, 10), + (10, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, 9, 11), + (11, -1, -1, 7, 7, 1, 51, -1, 0, 0, 3, 10, 302), + (12, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, -1, 13), + (13, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, 12, 14), + (14, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, 13, 15), + (15, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, 14, 16), + (16, -1, -1, 12, 12, 1, 51, -1, 0, 0, 3, 15, 312), + (17, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, -1, 18), + (18, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, 17, 19), + (19, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, 18, 20), + (20, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, 19, 21), + (21, -1, -1, 17, 17, 1, 51, -1, 0, 0, 3, 20, 322), + (22, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, -1, 23), + (23, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, 22, 24), + (24, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, 23, 25), + (25, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, 24, 26), + (26, -1, -1, 22, 22, 1, 51, -1, 0, 0, 3, 25, 332), + (27, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, -1, 28), + (28, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, 27, 29), + (29, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, 28, 30), + (30, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, 29, 31), + (31, -1, -1, 27, 27, 1, 51, -1, 0, 0, 3, 30, 342), + (32, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, -1, 33), + (33, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, 32, 34), + (34, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, 33, 35), + (35, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, 34, 36), + (36, -1, -1, 32, 32, 1, 51, -1, 0, 0, 3, 35, 352), + (37, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, -1, 38), + (38, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, 37, 39), + (39, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, 38, 40), + (40, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, 39, 41), + (41, -1, -1, 37, 37, 1, 51, -1, 0, 0, 3, 40, 362), + (42, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, -1, 43), + (43, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, 42, 44), + (44, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, 43, 45), + (45, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, 44, 46), + (46, -1, -1, 42, 42, 1, 51, -1, 0, 0, 3, 45, 372), + (47, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, -1, 48), + (48, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, 47, 49), + (49, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, 48, 50), + (50, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, 49, 51), + (51, -1, -1, 47, 47, 1, 51, -1, 0, 0, 3, 50, 382), + (52, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, -1, 53), + (53, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, 52, 54), + (54, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, 53, 55), + (55, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, 54, 56), + (56, -1, -1, 52, 52, 1, 51, -1, 0, 0, 3, 55, 392), + (57, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, -1, 58), + (58, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, 57, 59), + (59, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, 58, 60), + (60, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, 59, 61), + (61, -1, -1, 57, 57, 1, 51, -1, 0, 0, 3, 60, 402), + (62, -1, -1, 62, 62, 1, 51, -1, 0, 0, 3, -1, 63), + (63, -1, -1, 62, 62, 1, 51, -1, 0, 0, 3, 62, 64), + (64, -1, -1, 62, 62, 1, 51, -1, 0, 0, 3, 63, 672), + (68, -1, -1, 68, 68, 1, 51, -1, 0, 0, 3, -1, 69), + (69, -1, -1, 68, 68, 1, 51, -1, 0, 0, 3, 68, 70), + (70, -1, -1, 68, 68, 1, 51, -1, 0, 0, 3, 69, -1), + (71, -1, -1, 71, 71, 1, 51, -1, 0, 0, 3, -1, 72), + (72, -1, -1, 71, 71, 1, 51, -1, 0, 0, 3, 71, 73), + (73, -1, -1, 71, 71, 1, 51, -1, 0, 0, 3, 72, 676), + (74, -1, -1, 74, 74, 1, 51, -1, 0, 0, 3, -1, 75), + (75, -1, -1, 74, 74, 1, 51, -1, 0, 0, 3, 74, 76), + (76, -1, -1, 74, 74, 1, 51, -1, 0, 0, 3, 75, -1), + (77, -1, -1, 77, 77, 2, 55, -1, 0, 0, 3, -1, 78), + (78, -1, -1, 77, 77, 4, 55, -1, 0, 0, 3, 77, 79), + (79, -1, -1, 77, 77, 6, 55, -1, 0, 0, 3, 78, 434), + (80, -1, -1, 80, 80, 2, 55, -1, 0, 0, 3, -1, 81), + (81, -1, -1, 80, 80, 4, 55, -1, 0, 0, 3, 80, 82), + (82, -1, -1, 80, 80, 6, 55, -1, 0, 0, 3, 81, 437), + (83, -1, -1, 83, 83, 2, 55, -1, 0, 0, 3, -1, 84), + (84, -1, -1, 83, 83, 4, 55, -1, 0, 0, 3, 83, 85), + (85, -1, -1, 83, 83, 6, 55, -1, 0, 0, 3, 84, 13099), + (86, -1, -1, 86, 86, 2, 55, -1, 0, 0, 3, -1, 87), + (87, -1, -1, 86, 86, 4, 55, -1, 0, 0, 3, 86, 88), + (88, -1, -1, 86, 86, 6, 55, -1, 0, 0, 3, 87, 266), + (92, -1, -1, 92, 92, 2, 55, -1, 0, 0, 3, -1, 93), + (93, -1, -1, 92, 92, 4, 55, -1, 0, 0, 3, 92, 94), + (94, -1, -1, 92, 92, 6, 55, -1, 0, 0, 3, 93, -1), + (98, -1, -1, 98, 98, 2, 55, -1, 0, 0, 3, -1, 99), + (99, -1, -1, 98, 98, 4, 55, -1, 0, 0, 3, 98, 100), + (100, -1, -1, 98, 98, 6, 55, -1, 0, 0, 3, 99, 4767), + (101, -1, -1, 101, 101, 2, 55, -1, 0, 0, 3, -1, 102), + (102, -1, -1, 101, 101, 4, 55, -1, 0, 0, 3, 101, 103), + (103, -1, -1, 101, 101, 6, 55, -1, 0, 0, 3, 102, -1), + (104, -1, -1, 104, 104, 2, 55, -1, 0, 0, 3, -1, 105), + (105, -1, -1, 104, 104, 4, 55, -1, 0, 0, 3, 104, 106), + (106, -1, -1, 104, 104, 6, 55, -1, 0, 0, 3, 105, -1), + (107, -1, -1, 107, 107, 2, 55, -1, 0, 0, 3, -1, 108), + (108, -1, -1, 107, 107, 4, 55, -1, 0, 0, 3, 107, 109), + (109, -1, -1, 107, 107, 6, 55, -1, 0, 0, 3, 108, 7541), + (110, -1, -1, 110, 110, 2, 55, -1, 0, 0, 3, -1, 111), + (111, -1, -1, 110, 110, 4, 55, -1, 0, 0, 3, 110, 112), + (112, -1, -1, 110, 110, 6, 55, -1, 0, 0, 3, 111, -1), + (113, -1, -1, 113, 113, 2, 55, -1, 0, 0, 3, -1, 114), + (114, -1, -1, 113, 113, 4, 55, -1, 0, 0, 3, 113, 115), + (115, -1, -1, 113, 113, 6, 55, -1, 0, 0, 3, 114, 443), + (116, -1, -1, 116, 116, 2, 55, -1, 0, 0, 3, -1, 117), + (117, -1, -1, 116, 116, 4, 55, -1, 0, 0, 3, 116, 118), + (118, -1, -1, 116, 116, 6, 55, -1, 0, 0, 3, 117, -1), + (119, -1, -1, 119, 119, 2, 55, -1, 0, 0, 3, -1, 120), + (120, -1, -1, 119, 119, 4, 55, -1, 0, 0, 3, 119, 121), + (121, -1, -1, 119, 119, 6, 55, -1, 0, 0, 3, 120, 440), + (122, -1, -1, 122, 122, 2, 55, -1, 0, 0, 3, -1, 123), + (123, -1, -1, 122, 122, 4, 55, -1, 0, 0, 3, 122, 124), + (124, -1, -1, 122, 122, 6, 55, -1, 0, 0, 3, 123, 454), + (125, -1, -1, 125, 125, 2, 55, -1, 0, 0, 3, -1, 126), + (126, -1, -1, 125, 125, 4, 55, -1, 0, 0, 3, 125, 127), + (127, -1, -1, 125, 125, 6, 55, -1, 0, 0, 3, 126, 449), + (128, 128, 128, 128, 128, 9, 59, 5228, 1, 4320, 3, -1, -1), + (129, 129, 129, 129, 129, 5, 59, 2738, 2, 64800, 3, -1, -1), + (130, 130, 130, 130, 130, 3, 59, 2739, 3, 7, 3, -1, -1), + (131, 131, 131, 131, 131, 5, 59, 2740, 4, 900, 3, -1, 531), + (132, 132, 132, 132, 132, 6, 59, 2741, 5, 600, 3, -1, -1), + (136, 136, -1, 136, 136, 5, 59, 2742, 7, 1800, 3, -1, 15341), + (137, -1, -1, 137, 137, 3, 59, -1, 0, 0, 3, -1, 138), + (138, -1, -1, 137, 137, 6, 59, -1, 0, 0, 3, 137, 139), + (139, -1, -1, 137, 137, 9, 59, -1, 0, 0, 3, 138, -1), + (140, 140, -1, 140, 140, 6, 59, 2771, 3, 4320, 3, -1, -1), + (141, -1, -1, 141, 12863, 3, 59, -1, 0, 0, 3, -1, 142), + (142, -1, -1, 141, 12863, 6, 59, -1, 0, 0, 3, 141, 143), + (143, -1, -1, 141, 12863, 9, 59, -1, 0, 0, 3, 142, 12863), + (144, -1, -1, 144, 144, 5, 59, -1, 0, 0, 3, -1, -1), + (145, 145, 145, 145, 145, 9, 59, 2761, 2, 4320, 3, -1, -1), + (146, 146, 146, 146, 146, 5, 59, 2749, 2, 180, 3, -1, 5069), + (147, -1, -1, 147, 147, 3, 59, -1, 0, 0, 3, -1, 148), + (148, -1, -1, 147, 147, 6, 59, -1, 0, 0, 3, 147, 149), + (149, -1, -1, 147, 147, 9, 59, -1, 0, 0, 3, 148, -1), + (150, -1, -1, 150, 150, 3, 59, -1, 0, 0, 3, -1, 151), + (151, -1, -1, 150, 150, 6, 59, -1, 0, 0, 3, 150, 152), + (152, -1, -1, 150, 150, 9, 59, -1, 0, 0, 3, 151, -1), + (153, 153, 153, 153, 153, 5, 59, 2750, 3, 2160, 3, -1, 1519), + (155, 155, 155, 155, 155, 9, 59, 2758, 8, 60, 3, -1, 533), + (156, 156, 156, 156, 156, 6, 59, 2734, 2, 4320, 3, -1, -1), + (158, -1, -1, 158, 158, 3, 59, -1, 0, 0, 3, -1, -1), + (159, -1, -1, 159, 159, 2, 59, -1, 0, 0, 3, -1, 160), + (160, -1, -1, 159, 159, 4, 59, -1, 0, 0, 3, 159, 161), + (161, -1, -1, 159, 159, 6, 59, -1, 0, 0, 3, 160, -1), + (162, 162, 162, 162, 162, 5, 59, 2753, 3, 8640, 3, -1, -1), + (163, 163, 163, 163, 163, 5, 59, 2752, 2, 2160, 3, -1, -1), + (167, 167, 167, 167, 167, 6, 59, 2754, 14, 900, 3, -1, 5879), + (168, 168, 168, 168, 168, 3, 59, 2795, 4, 10, 3, -1, 169), + (169, 168, 168, 168, 168, 6, 59, 2796, 4, 10, 3, 168, 170), + (170, 168, 168, 168, 168, 9, 59, 2797, 4, 10, 3, 169, 15241), + (171, 171, 171, 171, 171, 3, 59, 2798, 4, 10, 3, -1, 172), + (172, 171, 171, 171, 171, 6, 59, 2799, 4, 10, 3, 171, 173), + (173, 171, 171, 171, 171, 9, 59, 2800, 4, 10, 3, 172, 15244), + (174, 174, 174, 174, 174, 3, 59, 2792, 4, 10, 3, -1, 175), + (175, 174, 174, 174, 174, 6, 59, 2793, 4, 10, 3, 174, 176), + (176, 174, 174, 174, 174, 9, 59, 2794, 4, 10, 3, 175, 15247), + (177, 177, 177, 177, 177, 3, 59, 2789, 4, 10, 3, -1, 178), + (178, 177, 177, 177, 177, 6, 59, 2790, 4, 10, 3, 177, 179), + (179, 177, 177, 177, 177, 9, 59, 2791, 4, 10, 3, 178, 15250), + (182, -1, -1, 182, 182, 5, 59, -1, 0, 0, 3, -1, -1), + (183, 183, 183, 183, 183, 9, 59, 2755, 4, 8640, 3, -1, -1), + (184, 184, 184, 184, 184, 3, 59, 2756, 5, 4320, 3, -1, 5953), + (185, 185, 185, 185, 185, 5, 59, 2757, 6, 4320, 3, -1, -1), + (186, 186, 186, 186, 186, 3, 59, 2772, 7, 7, 3, -1, -1), + (187, 187, 187, 187, 187, 6, 59, 2764, 8, 4320, 3, -1, -1), + (188, 188, 188, 188, 188, 9, 59, 2190, 2, 30, 3, -1, 1277), + (190, -1, -1, 190, 190, 3, 59, -1, 0, 0, 3, -1, 191), + (191, -1, -1, 190, 190, 6, 59, -1, 0, 0, 3, 190, 192), + (192, -1, -1, 190, 190, 9, 59, -1, 0, 0, 3, 191, 1524), + (193, 193, 193, 193, 193, 3, 59, 2775, 3, 4320, 3, -1, -1), + (194, 194, 194, 194, 194, 5, 59, 2874, 0, 1, 3, -1, -1), + (195, -1, -1, 195, 195, 6, 59, -1, 0, 0, 3, -1, -1), + (196, -1, -1, 196, 196, 6, 59, -1, 0, 0, 3, -1, -1), + (197, 197, 197, 197, 197, 5, 59, 2765, 2, 7, 3, -1, -1), + (198, -1, -1, 198, 198, 9, 59, -1, 0, 0, 3, -1, -1), + (199, -1, -1, 199, 199, 3, 59, -1, 0, 0, 3, -1, 200), + (200, -1, -1, 199, 199, 6, 59, -1, 0, 0, 3, 199, 201), + (201, -1, -1, 199, 199, 9, 59, -1, 0, 0, 3, 200, 12507), + (205, -1, -1, 205, 205, 9, 59, -1, 0, 0, 3, -1, -1), + (206, 206, 206, 206, 206, 5, 59, 2875, 0, 1, 3, -1, -1), + (208, 208, 208, 208, 208, 6, 59, 2766, 2, 4320, 3, -1, -1), + (210, -1, -1, 210, 210, 3, 59, -1, 0, 0, 3, -1, 211), + (211, -1, -1, 210, 210, 6, 59, -1, 0, 0, 3, 210, 212), + (212, -1, -1, 210, 210, 9, 59, -1, 0, 0, 3, 211, 1316), + (213, -1, -1, 213, 213, 3, 59, -1, 0, 0, 3, -1, 214), + (214, -1, -1, 213, 213, 6, 59, -1, 0, 0, 3, 213, 215), + (215, -1, -1, 213, 213, 9, 59, -1, 0, 0, 3, 214, 700), + (225, -1, -1, 225, 225, 3, 59, -1, 0, 0, 3, -1, 226), + (226, -1, -1, 225, 225, 6, 59, -1, 0, 0, 3, 225, 227), + (227, -1, -1, 225, 225, 9, 59, -1, 0, 0, 3, 226, -1), + (230, -1, -1, 230, 230, 3, 59, -1, 0, 0, 3, -1, 231), + (231, -1, -1, 230, 230, 6, 59, -1, 0, 0, 3, 230, 232), + (232, -1, -1, 230, 230, 9, 59, -1, 0, 0, 3, 231, 539), + (233, 233, 233, 233, 233, 9, 59, 5248, 1, 1800, 3, -1, -1), + (237, -1, -1, 237, 237, 3, 59, -1, 0, 0, 3, -1, 238), + (238, -1, -1, 237, 237, 6, 59, -1, 0, 0, 3, 237, 239), + (239, -1, -1, 237, 237, 9, 59, -1, 0, 0, 3, 238, -1), + (240, -1, -1, 240, 240, 3, 59, -1, 0, 0, 3, -1, 241), + (241, -1, -1, 240, 240, 6, 59, -1, 0, 0, 3, 240, 242), + (242, -1, -1, 240, 240, 9, 59, -1, 0, 0, 3, 241, -1), + (243, 243, -1, 243, 243, 9, 59, 5244, 1, 1440, 3, -1, -1), + (244, -1, -1, 244, 244, 3, 59, -1, 0, 0, 3, -1, 245), + (245, -1, -1, 244, 244, 6, 59, -1, 0, 0, 3, 244, 246), + (246, -1, -1, 244, 244, 9, 59, -1, 0, 0, 3, 245, 8328), + (247, -1, -1, 247, 247, 3, 59, -1, 0, 0, 3, -1, 248), + (248, -1, -1, 247, 247, 6, 59, -1, 0, 0, 3, 247, 249), + (249, -1, -1, 247, 247, 9, 59, -1, 0, 0, 3, 248, 504), + (254, 254, 254, 254, 254, 5, 59, 5232, 12, 4320, 3, -1, -1), + (255, -1, -1, 255, 255, 3, 59, -1, 0, 0, 3, -1, 256), + (256, -1, -1, 255, 255, 6, 59, -1, 0, 0, 3, 255, 257), + (257, -1, -1, 255, 255, 9, 59, -1, 0, 0, 3, 256, 542), + (258, 258, -1, 258, 258, 5, 59, 5233, 1, 600, 3, -1, 10578), + (259, 259, 259, 259, 259, 5, 59, 5234, 2, 900, 3, -1, -1), + (260, 260, -1, 260, 260, 3, 59, 5229, 3, 2160, 3, -1, 261), + (261, 260, -1, 260, 260, 6, 59, 5230, 3, 2160, 3, 260, 262), + (262, 260, -1, 260, 260, 9, 59, 5231, 3, 2160, 3, 261, 8309), + (263, -1, -1, 263, 263, 3, 59, -1, 0, 0, 3, -1, 264), + (264, -1, -1, 263, 263, 6, 59, -1, 0, 0, 3, 263, 265), + (265, -1, -1, 263, 263, 9, 59, -1, 0, 0, 3, 264, -1), + (266, -1, -1, 86, 86, 8, 59, -1, 0, 0, 3, 88, 10467), + (267, -1, -1, 267, 267, 3, 59, -1, 0, 0, 3, -1, 268), + (268, -1, -1, 267, 267, 6, 59, -1, 0, 0, 3, 267, 269), + (269, -1, -1, 267, 267, 9, 59, -1, 0, 0, 3, 268, 640), + (273, -1, -1, 273, 273, 5, 59, 2767, 0, 0, 3, -1, -1), + (274, 274, 274, 274, 274, 5, 59, 2748, 4, 4320, 3, -1, -1), + (275, -1, -1, 275, 275, 3, 59, -1, 0, 0, 3, -1, 276), + (276, -1, -1, 275, 275, 6, 59, -1, 0, 0, 3, 275, 277), + (277, -1, -1, 275, 275, 9, 59, -1, 0, 0, 3, 276, 701), + (278, -1, -1, 278, 278, 5, 59, -1, 0, 0, 3, -1, -1), + (279, -1, -1, 279, 279, 5, 59, -1, 0, 0, 3, -1, 18972), + (280, -1, -1, 280, 280, 3, 59, -1, 0, 0, 3, -1, 281), + (281, -1, -1, 280, 280, 6, 59, -1, 0, 0, 3, 280, 282), + (282, -1, -1, 280, 280, 9, 59, -1, 0, 0, 3, 281, -1), + (283, -1, -1, 283, 283, 3, 59, -1, 0, 0, 3, -1, 284), + (284, -1, -1, 283, 283, 6, 59, -1, 0, 0, 3, 283, 285), + (285, -1, -1, 283, 283, 9, 59, -1, 0, 0, 3, 284, -1), + (286, -1, -1, 286, 286, 3, 59, -1, 0, 0, 3, -1, -1), + (287, -1, -1, 287, 287, 6, 59, -1, 0, 0, 3, -1, -1), + (288, -1, -1, 288, 288, 6, 59, -1, 0, 0, 3, -1, -1), + (289, 289, 289, 289, 289, 5, 59, 3290, 3, 300, 3, -1, 1607), + (290, 290, 290, 290, 290, 4, 59, 3289, 4, 720, 3, -1, 13173), + (291, 291, 291, 291, 291, 6, 59, 3291, 5, 900, 3, -1, 1123), + (292, -1, -1, 2, 2, 1, 61, -1, 0, 0, 4, 6, 293), + (293, -1, -1, 2, 2, 1, 61, -1, 0, 0, 4, 292, 294), + (294, -1, -1, 2, 2, 1, 62, -1, 0, 0, 4, 293, 295), + (295, -1, -1, 2, 2, 1, 62, -1, 0, 0, 4, 294, 296), + (296, -1, -1, 2, 2, 1, 63, -1, 0, 0, 4, 295, 297), + (297, -1, -1, 2, 2, 1, 63, -1, 0, 0, 4, 296, 298), + (298, -1, -1, 2, 2, 1, 64, -1, 0, 0, 4, 297, 299), + (299, -1, -1, 2, 2, 1, 64, -1, 0, 0, 4, 298, 300), + (300, -1, -1, 2, 2, 1, 65, -1, 0, 0, 4, 299, 301), + (301, -1, -1, 2, 2, 1, 65, -1, 0, 0, 4, 300, -1), + (302, -1, -1, 7, 7, 1, 61, -1, 0, 0, 4, 11, 303), + (303, -1, -1, 7, 7, 1, 61, -1, 0, 0, 4, 302, 304), + (304, -1, -1, 7, 7, 1, 62, -1, 0, 0, 4, 303, 305), + (305, -1, -1, 7, 7, 1, 62, -1, 0, 0, 4, 304, 306), + (306, -1, -1, 7, 7, 1, 63, -1, 0, 0, 4, 305, 307), + (307, -1, -1, 7, 7, 1, 63, -1, 0, 0, 4, 306, 308), + (308, -1, -1, 7, 7, 1, 64, -1, 0, 0, 4, 307, 309), + (309, -1, -1, 7, 7, 1, 64, -1, 0, 0, 4, 308, 310), + (310, -1, -1, 7, 7, 1, 65, -1, 0, 0, 4, 309, 311), + (311, -1, -1, 7, 7, 1, 65, -1, 0, 0, 4, 310, -1), + (312, -1, -1, 12, 12, 1, 61, -1, 0, 0, 4, 16, 313), + (313, -1, -1, 12, 12, 1, 61, -1, 0, 0, 4, 312, 314), + (314, -1, -1, 12, 12, 1, 62, -1, 0, 0, 4, 313, 315), + (315, -1, -1, 12, 12, 1, 62, -1, 0, 0, 4, 314, 316), + (316, -1, -1, 12, 12, 1, 63, -1, 0, 0, 4, 315, 317), + (317, -1, -1, 12, 12, 1, 63, -1, 0, 0, 4, 316, 318), + (318, -1, -1, 12, 12, 1, 64, -1, 0, 0, 4, 317, 319), + (319, -1, -1, 12, 12, 1, 64, -1, 0, 0, 4, 318, 320), + (320, -1, -1, 12, 12, 1, 65, -1, 0, 0, 4, 319, 321), + (321, -1, -1, 12, 12, 1, 65, -1, 0, 0, 4, 320, -1), + (322, -1, -1, 17, 17, 1, 61, -1, 0, 0, 4, 21, 323), + (323, -1, -1, 17, 17, 1, 61, -1, 0, 0, 4, 322, 324), + (324, -1, -1, 17, 17, 1, 62, -1, 0, 0, 4, 323, 325), + (325, -1, -1, 17, 17, 1, 62, -1, 0, 0, 4, 324, 326), + (326, -1, -1, 17, 17, 1, 63, -1, 0, 0, 4, 325, 327), + (327, -1, -1, 17, 17, 1, 63, -1, 0, 0, 4, 326, 328), + (328, -1, -1, 17, 17, 1, 64, -1, 0, 0, 4, 327, 329), + (329, -1, -1, 17, 17, 1, 64, -1, 0, 0, 4, 328, 330), + (330, -1, -1, 17, 17, 1, 65, -1, 0, 0, 4, 329, 331), + (331, -1, -1, 17, 17, 1, 65, -1, 0, 0, 4, 330, -1), + (332, -1, -1, 22, 22, 1, 61, -1, 0, 0, 4, 26, 333), + (333, -1, -1, 22, 22, 1, 61, -1, 0, 0, 4, 332, 334), + (334, -1, -1, 22, 22, 1, 62, -1, 0, 0, 4, 333, 335), + (335, -1, -1, 22, 22, 1, 62, -1, 0, 0, 4, 334, 336), + (336, -1, -1, 22, 22, 1, 63, -1, 0, 0, 4, 335, 337), + (337, -1, -1, 22, 22, 1, 63, -1, 0, 0, 4, 336, 338), + (338, -1, -1, 22, 22, 1, 64, -1, 0, 0, 4, 337, 339), + (339, -1, -1, 22, 22, 1, 64, -1, 0, 0, 4, 338, 340), + (340, -1, -1, 22, 22, 1, 65, -1, 0, 0, 4, 339, 341), + (341, -1, -1, 22, 22, 1, 65, -1, 0, 0, 4, 340, -1), + (342, -1, -1, 27, 27, 1, 61, -1, 0, 0, 4, 31, 343), + (343, -1, -1, 27, 27, 1, 61, -1, 0, 0, 4, 342, 344), + (344, -1, -1, 27, 27, 1, 62, -1, 0, 0, 4, 343, 345), + (345, -1, -1, 27, 27, 1, 62, -1, 0, 0, 4, 344, 346), + (346, -1, -1, 27, 27, 1, 63, -1, 0, 0, 4, 345, 347), + (347, -1, -1, 27, 27, 1, 63, -1, 0, 0, 4, 346, 348), + (348, -1, -1, 27, 27, 1, 64, -1, 0, 0, 4, 347, 349), + (349, -1, -1, 27, 27, 1, 64, -1, 0, 0, 4, 348, 350), + (350, -1, -1, 27, 27, 1, 65, -1, 0, 0, 4, 349, 351), + (351, -1, -1, 27, 27, 1, 65, -1, 0, 0, 4, 350, -1), + (352, -1, -1, 32, 32, 1, 61, -1, 0, 0, 4, 36, 353), + (353, -1, -1, 32, 32, 1, 61, -1, 0, 0, 4, 352, 354), + (354, -1, -1, 32, 32, 1, 62, -1, 0, 0, 4, 353, 355), + (355, -1, -1, 32, 32, 1, 62, -1, 0, 0, 4, 354, 356), + (356, -1, -1, 32, 32, 1, 63, -1, 0, 0, 4, 355, 357), + (357, -1, -1, 32, 32, 1, 63, -1, 0, 0, 4, 356, 358), + (358, -1, -1, 32, 32, 1, 64, -1, 0, 0, 4, 357, 359), + (359, -1, -1, 32, 32, 1, 64, -1, 0, 0, 4, 358, 360), + (360, -1, -1, 32, 32, 1, 65, -1, 0, 0, 4, 359, 361), + (361, -1, -1, 32, 32, 1, 65, -1, 0, 0, 4, 360, -1), + (362, -1, -1, 37, 37, 1, 61, -1, 0, 0, 4, 41, 363), + (363, -1, -1, 37, 37, 1, 61, -1, 0, 0, 4, 362, 364), + (364, -1, -1, 37, 37, 1, 62, -1, 0, 0, 4, 363, 365), + (365, -1, -1, 37, 37, 1, 62, -1, 0, 0, 4, 364, 366), + (366, -1, -1, 37, 37, 1, 63, -1, 0, 0, 4, 365, 367), + (367, -1, -1, 37, 37, 1, 63, -1, 0, 0, 4, 366, 368), + (368, -1, -1, 37, 37, 1, 64, -1, 0, 0, 4, 367, 369), + (369, -1, -1, 37, 37, 1, 64, -1, 0, 0, 4, 368, 370), + (370, -1, -1, 37, 37, 1, 65, -1, 0, 0, 4, 369, 371), + (371, -1, -1, 37, 37, 1, 65, -1, 0, 0, 4, 370, -1), + (372, -1, -1, 42, 42, 1, 61, -1, 0, 0, 4, 46, 373), + (373, -1, -1, 42, 42, 1, 61, -1, 0, 0, 4, 372, 374), + (374, -1, -1, 42, 42, 1, 62, -1, 0, 0, 4, 373, 375), + (375, -1, -1, 42, 42, 1, 62, -1, 0, 0, 4, 374, 376), + (376, -1, -1, 42, 42, 1, 63, -1, 0, 0, 4, 375, 377), + (377, -1, -1, 42, 42, 1, 63, -1, 0, 0, 4, 376, 378), + (378, -1, -1, 42, 42, 1, 64, -1, 0, 0, 4, 377, 379), + (379, -1, -1, 42, 42, 1, 64, -1, 0, 0, 4, 378, 380), + (380, -1, -1, 42, 42, 1, 65, -1, 0, 0, 4, 379, 381), + (381, -1, -1, 42, 42, 1, 65, -1, 0, 0, 4, 380, -1), + (382, -1, -1, 47, 47, 1, 61, -1, 0, 0, 4, 51, 383), + (383, -1, -1, 47, 47, 1, 61, -1, 0, 0, 4, 382, 384), + (384, -1, -1, 47, 47, 1, 62, -1, 0, 0, 4, 383, 385), + (385, -1, -1, 47, 47, 1, 62, -1, 0, 0, 4, 384, 386), + (386, -1, -1, 47, 47, 1, 63, -1, 0, 0, 4, 385, 387), + (387, -1, -1, 47, 47, 1, 63, -1, 0, 0, 4, 386, 388), + (388, -1, -1, 47, 47, 1, 64, -1, 0, 0, 4, 387, 389), + (389, -1, -1, 47, 47, 1, 64, -1, 0, 0, 4, 388, 390), + (390, -1, -1, 47, 47, 1, 65, -1, 0, 0, 4, 389, 391), + (391, -1, -1, 47, 47, 1, 65, -1, 0, 0, 4, 390, -1), + (392, -1, -1, 52, 52, 1, 61, -1, 0, 0, 4, 56, 393), + (393, -1, -1, 52, 52, 1, 61, -1, 0, 0, 4, 392, 394), + (394, -1, -1, 52, 52, 1, 62, -1, 0, 0, 4, 393, 395), + (395, -1, -1, 52, 52, 1, 62, -1, 0, 0, 4, 394, 396), + (396, -1, -1, 52, 52, 1, 63, -1, 0, 0, 4, 395, 397), + (397, -1, -1, 52, 52, 1, 63, -1, 0, 0, 4, 396, 398), + (398, -1, -1, 52, 52, 1, 64, -1, 0, 0, 4, 397, 399), + (399, -1, -1, 52, 52, 1, 64, -1, 0, 0, 4, 398, 400), + (400, -1, -1, 52, 52, 1, 65, -1, 0, 0, 4, 399, 401), + (401, -1, -1, 52, 52, 1, 65, -1, 0, 0, 4, 400, -1), + (402, -1, -1, 57, 57, 1, 61, -1, 0, 0, 4, 61, 403), + (403, -1, -1, 57, 57, 1, 61, -1, 0, 0, 4, 402, 404), + (404, -1, -1, 57, 57, 1, 62, -1, 0, 0, 4, 403, 405), + (405, -1, -1, 57, 57, 1, 62, -1, 0, 0, 4, 404, 406), + (406, -1, -1, 57, 57, 1, 63, -1, 0, 0, 4, 405, 407), + (407, -1, -1, 57, 57, 1, 63, -1, 0, 0, 4, 406, 408), + (408, -1, -1, 57, 57, 1, 64, -1, 0, 0, 4, 407, 409), + (409, -1, -1, 57, 57, 1, 64, -1, 0, 0, 4, 408, 410), + (410, -1, -1, 57, 57, 1, 65, -1, 0, 0, 4, 409, 411), + (411, -1, -1, 57, 57, 1, 65, -1, 0, 0, 4, 410, -1), + (412, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, -1, 413), + (413, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 412, 414), + (414, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 413, 415), + (415, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 414, 416), + (416, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 415, 417), + (417, -1, -1, 412, 412, 3, 51, -1, 0, 0, 3, 416, -1), + (418, -1, -1, 418, 418, 2, 61, -1, 0, 0, 4, -1, 419), + (419, -1, -1, 418, 418, 2, 62, -1, 0, 0, 4, 418, 420), + (420, -1, -1, 418, 418, 2, 63, -1, 0, 0, 4, 419, 421), + (421, -1, -1, 418, 418, 2, 64, -1, 0, 0, 4, 420, 422), + (422, -1, -1, 418, 418, 2, 65, -1, 0, 0, 4, 421, 1001), + (423, -1, -1, 423, 423, 3, 61, -1, 0, 0, 4, -1, 424), + (424, -1, -1, 423, 423, 3, 63, -1, 0, 0, 4, 423, 425), + (425, -1, -1, 423, 423, 3, 65, -1, 0, 0, 4, 424, -1), + (426, -1, -1, 426, 426, 3, 61, -1, 0, 0, 4, -1, 427), + (427, -1, -1, 426, 426, 3, 62, -1, 0, 0, 4, 426, 428), + (428, -1, -1, 426, 426, 3, 63, -1, 0, 0, 4, 427, 429), + (429, -1, -1, 426, 426, 3, 64, -1, 0, 0, 4, 428, 430), + (430, -1, -1, 426, 426, 3, 65, -1, 0, 0, 4, 429, -1), + (434, -1, -1, 77, 77, 2, 62, -1, 0, 0, 4, 79, 435), + (435, -1, -1, 77, 77, 4, 63, -1, 0, 0, 4, 434, 436), + (436, -1, -1, 77, 77, 6, 64, -1, 0, 0, 4, 435, 1083), + (437, -1, -1, 80, 80, 2, 62, -1, 0, 0, 4, 82, 438), + (438, -1, -1, 80, 80, 3, 63, -1, 0, 0, 4, 437, 439), + (439, -1, -1, 80, 80, 4, 64, -1, 0, 0, 4, 438, 1086), + (440, -1, -1, 119, 119, 2, 62, -1, 0, 0, 4, 121, 441), + (441, -1, -1, 119, 119, 2, 63, -1, 0, 0, 4, 440, 442), + (442, -1, -1, 119, 119, 2, 64, -1, 0, 0, 4, 441, 1053), + (443, -1, -1, 113, 113, 3, 62, -1, 0, 0, 4, 115, 444), + (444, -1, -1, 113, 113, 3, 63, -1, 0, 0, 4, 443, 445), + (445, -1, -1, 113, 113, 3, 64, -1, 0, 0, 4, 444, -1), + (446, -1, -1, 446, 735, 3, 62, -1, 0, 0, 4, -1, 447), + (447, -1, -1, 446, 735, 3, 63, -1, 0, 0, 4, 446, 448), + (448, -1, -1, 446, 735, 3, 64, -1, 0, 0, 4, 447, 7050), + (449, -1, -1, 125, 125, 3, 61, -1, 0, 0, 4, 127, 450), + (450, -1, -1, 125, 125, 3, 62, -1, 0, 0, 4, 449, 451), + (451, -1, -1, 125, 125, 3, 63, -1, 0, 0, 4, 450, 452), + (452, -1, -1, 125, 125, 3, 64, -1, 0, 0, 4, 451, 453), + (453, -1, -1, 125, 125, 3, 65, -1, 0, 0, 4, 452, 1061), + (454, -1, -1, 122, 122, 3, 61, -1, 0, 0, 4, 124, 455), + (455, -1, -1, 122, 122, 3, 62, -1, 0, 0, 4, 454, 456), + (456, -1, -1, 122, 122, 3, 63, -1, 0, 0, 4, 455, 457), + (457, -1, -1, 122, 122, 3, 64, -1, 0, 0, 4, 456, 458), + (458, -1, -1, 122, 122, 3, 65, -1, 0, 0, 4, 457, 1066), + (459, 459, 459, 459, 459, 2, 61, 3297, 8, 180, 4, -1, 460), + (460, 459, 459, 459, 459, 4, 63, 3298, 8, 180, 4, 459, 461), + (461, 459, 459, 459, 459, 6, 65, 3299, 8, 180, 4, 460, 1189), + (462, -1, -1, 462, 462, 2, 63, -1, 0, 0, 4, -1, 463), + (463, -1, -1, 462, 462, 2, 64, -1, 0, 0, 4, 462, 464), + (464, -1, -1, 462, 462, 2, 65, -1, 0, 0, 4, 463, 7994), + (468, -1, -1, 468, 468, 2, 63, -1, 0, 0, 4, -1, 469), + (469, -1, -1, 468, 468, 2, 64, -1, 0, 0, 4, 468, 470), + (470, -1, -1, 468, 468, 2, 65, -1, 0, 0, 4, 469, 6439), + (471, -1, -1, 471, 471, 2, 63, -1, 0, 0, 4, -1, 472), + (472, -1, -1, 471, 471, 2, 64, -1, 0, 0, 4, 471, 473), + (473, -1, -1, 471, 471, 2, 65, -1, 0, 0, 4, 472, 12899), + (474, -1, -1, 474, 474, 2, 63, -1, 0, 0, 4, -1, 475), + (475, -1, -1, 474, 474, 2, 64, -1, 0, 0, 4, 474, 476), + (476, -1, -1, 474, 474, 2, 65, -1, 0, 0, 4, 475, 15359), + (477, -1, -1, 477, 477, 2, 63, -1, 0, 0, 4, -1, 478), + (478, -1, -1, 477, 477, 2, 64, -1, 0, 0, 4, 477, 479), + (479, -1, -1, 477, 477, 2, 65, -1, 0, 0, 4, 478, 6233), + (480, -1, -1, 480, 480, 2, 63, -1, 0, 0, 4, -1, 481), + (481, -1, -1, 480, 480, 2, 64, -1, 0, 0, 4, 480, 482), + (482, -1, -1, 480, 480, 2, 65, -1, 0, 0, 4, 481, 4921), + (483, -1, -1, 483, 483, 2, 63, -1, 0, 0, 4, -1, 484), + (484, -1, -1, 483, 483, 2, 64, -1, 0, 0, 4, 483, 485), + (485, -1, -1, 483, 483, 2, 65, -1, 0, 0, 4, 484, -1), + (489, -1, -1, 489, 489, 3, 63, -1, 0, 0, 4, -1, 490), + (490, -1, -1, 489, 489, 3, 64, -1, 0, 0, 4, 489, 491), + (491, -1, -1, 489, 489, 3, 65, -1, 0, 0, 4, 490, 7116), + (492, -1, -1, 492, 492, 2, 63, -1, 0, 0, 4, -1, 493), + (493, -1, -1, 492, 492, 2, 64, -1, 0, 0, 4, 492, 494), + (494, -1, -1, 492, 492, 2, 65, -1, 0, 0, 4, 493, 7128), + (495, -1, -1, 495, 495, 2, 63, -1, 0, 0, 4, -1, 496), + (496, -1, -1, 495, 495, 2, 64, -1, 0, 0, 4, 495, 497), + (497, -1, -1, 495, 495, 2, 65, -1, 0, 0, 4, 496, 6260), + (498, -1, -1, 498, 498, 2, 63, -1, 0, 0, 4, -1, 499), + (499, -1, -1, 498, 498, 2, 64, -1, 0, 0, 4, 498, 500), + (500, -1, -1, 498, 498, 2, 65, -1, 0, 0, 4, 499, 886), + (501, -1, -1, 501, 501, 2, 63, -1, 0, 0, 4, -1, 502), + (502, -1, -1, 501, 501, 2, 64, -1, 0, 0, 4, 501, 503), + (503, -1, -1, 501, 501, 2, 65, -1, 0, 0, 4, 502, 6319), + (504, -1, -1, 247, 247, 3, 62, -1, 0, 0, 4, 249, 505), + (505, -1, -1, 247, 247, 3, 63, -1, 0, 0, 4, 504, 506), + (506, -1, -1, 247, 247, 3, 64, -1, 0, 0, 4, 505, -1), + (507, 507, 507, 507, 507, 3, 61, 3252, 9, 180, 4, -1, 508), + (508, 507, 507, 507, 507, 3, 63, 3253, 9, 180, 4, 507, 509), + (509, 507, 507, 507, 507, 3, 65, 3254, 9, 180, 4, 508, -1), + (510, 510, 510, 510, 510, 3, 61, 3255, 37, 240, 4, -1, 511), + (511, 510, 510, 510, 510, 3, 63, 3256, 37, 240, 4, 510, 512), + (512, 510, 510, 510, 510, 3, 65, 3257, 37, 240, 4, 511, 7425), + (513, 513, 513, 513, 513, 3, 61, 3274, 4, 120, 4, -1, 514), + (514, 513, 513, 513, 513, 3, 63, 3275, 4, 120, 4, 513, 515), + (515, 513, 513, 513, 513, 3, 65, 3276, 4, 120, 4, 514, 6095), + (516, 516, 516, 516, 516, 2, 62, 3338, 5, 480, 4, -1, 6398), + (517, 517, 517, 517, 517, 3, 61, 3258, 12, 600, 4, -1, 518), + (518, 517, 517, 517, 517, 3, 63, 3259, 12, 600, 4, 517, 519), + (519, 517, 517, 517, 517, 3, 65, 3260, 12, 600, 4, 518, 1440), + (520, 520, 520, 520, 520, 3, 61, 3265, 6, 540, 4, -1, 521), + (521, 520, 520, 520, 520, 3, 63, 3266, 6, 540, 4, 520, 522), + (522, 520, 520, 520, 520, 3, 65, 3267, 6, 540, 4, 521, 1507), + (523, 523, 523, 523, 523, 5, 61, 3268, 9, 540, 4, -1, 524), + (524, 523, 523, 523, 523, 4, 63, 3269, 9, 540, 4, 523, 525), + (525, 523, 523, 523, 523, 3, 65, 3270, 9, 540, 4, 524, -1), + (526, 526, 526, 526, 526, 5, 62, 3248, 0, 1, 4, -1, 527), + (527, 526, 526, 526, 526, 3, 64, 3249, 0, 1, 4, 526, -1), + (528, 528, 528, 528, 528, 4, 61, 3283, 5, 720, 4, -1, 529), + (529, 528, 528, 528, 528, 3, 63, 3284, 5, 720, 4, 528, 530), + (530, 528, 528, 528, 528, 2, 65, 3285, 5, 720, 4, 529, 900), + (531, 131, 131, 131, 131, 3, 63, 3250, 4, 900, 4, 131, 532), + (532, 131, 131, 131, 131, 6, 64, 3251, 4, 900, 4, 531, 1203), + (533, 155, 155, 155, 155, 6, 64, 3264, 8, 60, 4, 155, 1344), + (534, 534, 534, 534, 534, 3, 61, 3261, 4, 2160, 4, -1, 535), + (535, 534, 534, 534, 534, 3, 63, 3262, 4, 2160, 4, 534, 536), + (536, 534, 534, 534, 534, 3, 65, 3263, 4, 2160, 4, 535, 715), + (537, -1, -1, 537, 537, 3, 63, -1, 0, 0, 4, -1, 538), + (538, -1, -1, 537, 537, 3, 64, -1, 0, 0, 4, 537, -1), + (539, -1, -1, 230, 230, 2, 63, -1, 0, 0, 4, 232, 540), + (540, -1, -1, 230, 230, 4, 64, -1, 0, 0, 4, 539, 541), + (541, -1, -1, 230, 230, 6, 65, -1, 0, 0, 4, 540, 12677), + (542, -1, -1, 255, 255, 2, 63, -1, 0, 0, 4, 257, 543), + (543, -1, -1, 255, 255, 4, 64, -1, 0, 0, 4, 542, 544), + (544, -1, -1, 255, 255, 6, 65, -1, 0, 0, 4, 543, 1163), + (545, 545, 545, 545, 545, 3, 61, 3271, 3, 900, 4, -1, 546), + (546, 545, 545, 545, 545, 3, 63, 3272, 3, 900, 4, 545, 547), + (547, 545, 545, 545, 545, 3, 65, 3273, 3, 900, 4, 546, 1293), + (548, 548, 548, 548, 548, 4, 61, 3277, 5, 900, 4, -1, 549), + (549, 548, 548, 548, 548, 3, 63, 3278, 5, 900, 4, 548, 550), + (550, 548, 548, 548, 548, 2, 65, 3279, 5, 900, 4, 549, 1225), + (551, -1, -1, 551, 551, 2, 61, -1, 0, 0, 4, -1, 552), + (552, -1, -1, 551, 551, 2, 62, -1, 0, 0, 4, 551, 553), + (553, -1, -1, 551, 551, 2, 63, -1, 0, 0, 4, 552, 554), + (554, -1, -1, 551, 551, 2, 64, -1, 0, 0, 4, 553, 555), + (555, -1, -1, 551, 551, 2, 65, -1, 0, 0, 4, 554, 1633), + (556, -1, -1, 556, 556, 2, 61, -1, 0, 0, 4, -1, 557), + (557, -1, -1, 556, 556, 2, 62, -1, 0, 0, 4, 556, 558), + (558, -1, -1, 556, 556, 2, 63, -1, 0, 0, 4, 557, 559), + (559, -1, -1, 556, 556, 2, 64, -1, 0, 0, 4, 558, 560), + (560, -1, -1, 556, 556, 2, 65, -1, 0, 0, 4, 559, 1563), + (561, -1, -1, 561, 561, 2, 61, -1, 0, 0, 4, -1, 562), + (562, -1, -1, 561, 561, 4, 63, -1, 0, 0, 4, 561, 563), + (563, -1, -1, 561, 561, 6, 65, -1, 0, 0, 4, 562, 1624), + (564, -1, -1, 564, 564, 3, 61, -1, 0, 0, 4, -1, 565), + (565, -1, -1, 564, 564, 3, 63, -1, 0, 0, 4, 564, 566), + (566, -1, -1, 564, 564, 3, 65, -1, 0, 0, 4, 565, 1621), + (567, -1, -1, 567, 567, 5, 63, -1, 0, 0, 4, -1, 5061), + (574, -1, -1, 574, 574, 3, 61, -1, 0, 0, 4, -1, 575), + (575, -1, -1, 574, 574, 3, 63, -1, 0, 0, 4, 574, 576), + (576, -1, -1, 574, 574, 3, 65, -1, 0, 0, 4, 575, 7718), + (577, -1, -1, 577, 577, 2, 61, -1, 0, 0, 4, -1, 578), + (578, -1, -1, 577, 577, 4, 63, -1, 0, 0, 4, 577, 579), + (579, -1, -1, 577, 577, 6, 65, -1, 0, 0, 4, 578, -1), + (580, -1, -1, 580, 580, 4, 61, -1, 0, 0, 4, -1, 581), + (581, -1, -1, 580, 580, 3, 63, -1, 0, 0, 4, 580, 582), + (582, -1, -1, 580, 580, 2, 65, -1, 0, 0, 4, 581, -1), + (583, -1, -1, 583, 583, 2, 63, -1, 0, 0, 4, -1, 584), + (584, -1, -1, 583, 583, 2, 64, -1, 0, 0, 4, 583, 585), + (585, -1, -1, 583, 583, 2, 65, -1, 0, 0, 4, 584, -1), + (586, -1, -1, 586, 586, 2, 61, -1, 0, 0, 4, -1, 587), + (587, -1, -1, 586, 586, 4, 63, -1, 0, 0, 4, 586, 588), + (588, -1, -1, 586, 586, 6, 65, -1, 0, 0, 4, 587, 6130), + (589, -1, -1, 589, 589, 3, 61, -1, 0, 0, 4, -1, 590), + (590, -1, -1, 589, 589, 3, 63, -1, 0, 0, 4, 589, 591), + (591, -1, -1, 589, 589, 3, 65, -1, 0, 0, 4, 590, 893), + (592, 592, 592, 592, 592, 6, 63, 3282, 2, 18, 4, -1, 702), + (593, -1, -1, 593, 593, 3, 61, -1, 0, 0, 4, -1, 594), + (594, -1, -1, 593, 593, 3, 63, -1, 0, 0, 4, 593, 595), + (595, -1, -1, 593, 593, 3, 65, -1, 0, 0, 4, 594, 5972), + (596, -1, -1, 596, 596, 2, 61, -1, 0, 0, 4, -1, 597), + (597, -1, -1, 596, 596, 4, 63, -1, 0, 0, 4, 596, 598), + (598, -1, -1, 596, 596, 6, 65, -1, 0, 0, 4, 597, 5973), + (599, -1, -1, 599, 599, 2, 61, -1, 0, 0, 4, -1, 600), + (600, -1, -1, 599, 599, 4, 63, -1, 0, 0, 4, 599, 601), + (601, -1, -1, 599, 599, 6, 65, -1, 0, 0, 4, 600, 1536), + (602, -1, -1, 602, 602, 3, 61, -1, 0, 0, 4, -1, 603), + (603, -1, -1, 602, 602, 3, 63, -1, 0, 0, 4, 602, 604), + (604, -1, -1, 602, 602, 3, 65, -1, 0, 0, 4, 603, 1533), + (605, -1, -1, 605, 605, 6, 63, -1, 0, 0, 4, -1, -1), + (606, -1, -1, 606, 606, 1, 61, -1, 0, 0, 4, -1, 607), + (607, -1, -1, 606, 606, 1, 62, -1, 0, 0, 4, 606, 608), + (608, -1, -1, 606, 606, 1, 63, -1, 0, 0, 4, 607, 609), + (609, -1, -1, 606, 606, 1, 64, -1, 0, 0, 4, 608, 610), + (610, -1, -1, 606, 606, 1, 65, -1, 0, 0, 4, 609, -1), + (611, -1, -1, 611, 611, 2, 61, -1, 0, 0, 4, -1, 612), + (612, -1, -1, 611, 611, 2, 62, -1, 0, 0, 4, 611, 613), + (613, -1, -1, 611, 611, 2, 63, -1, 0, 0, 4, 612, 614), + (614, -1, -1, 611, 611, 2, 64, -1, 0, 0, 4, 613, 615), + (615, -1, -1, 611, 611, 2, 65, -1, 0, 0, 4, 614, 7175), + (616, 616, 616, 616, 616, 5, 63, 3286, 7, 900, 4, -1, 617), + (617, 616, 616, 616, 616, 4, 64, 3287, 7, 900, 4, 616, 618), + (618, 616, 616, 616, 616, 3, 65, 3288, 7, 900, 4, 617, 1248), + (619, 619, 619, 619, 619, 3, 61, 3292, 6, 900, 4, -1, 620), + (620, 619, 619, 619, 619, 2, 63, 3293, 6, 900, 4, 619, 621), + (621, 619, 619, 619, 619, 1, 65, 3294, 6, 900, 4, 620, 721), + (622, -1, -1, 622, 622, 3, 61, -1, 0, 0, 4, -1, 623), + (623, -1, -1, 622, 622, 3, 62, -1, 0, 0, 4, 622, 624), + (624, -1, -1, 622, 622, 3, 63, -1, 0, 0, 4, 623, 8329), + (625, -1, -1, 625, 625, 1, 61, -1, 0, 0, 4, -1, 626), + (626, -1, -1, 625, 625, 2, 63, -1, 0, 0, 4, 625, 627), + (627, -1, -1, 625, 625, 3, 65, -1, 0, 0, 4, 626, 4733), + (628, -1, -1, 628, 628, 2, 62, -1, 0, 0, 4, -1, 629), + (629, -1, -1, 628, 628, 4, 64, -1, 0, 0, 4, 628, -1), + (630, 630, 630, 630, 630, 6, 63, 5243, 7, 1, 4, -1, -1), + (631, -1, -1, 631, 631, 2, 61, -1, 0, 0, 4, -1, 632), + (632, -1, -1, 631, 631, 3, 63, -1, 0, 0, 4, 631, 633), + (633, -1, -1, 631, 631, 4, 65, -1, 0, 0, 4, 632, 1172), + (634, -1, -1, 634, 634, 1, 61, -1, 0, 0, 4, -1, 635), + (635, -1, -1, 634, 634, 2, 63, -1, 0, 0, 4, 634, 636), + (636, -1, -1, 634, 634, 3, 65, -1, 0, 0, 4, 635, 844), + (637, -1, -1, 637, 637, 3, 61, -1, 0, 0, 4, -1, 638), + (638, -1, -1, 637, 637, 6, 63, -1, 0, 0, 4, 637, 639), + (639, -1, -1, 637, 637, 9, 65, -1, 0, 0, 4, 638, 770), + (640, -1, -1, 267, 267, 2, 61, -1, 0, 0, 4, 269, 641), + (641, -1, -1, 267, 267, 4, 63, -1, 0, 0, 4, 640, 642), + (642, -1, -1, 267, 267, 6, 65, -1, 0, 0, 4, 641, 924), + (643, 643, 643, 643, 643, 4, 62, 5227, 0, 1, 4, -1, -1), + (644, -1, -1, 644, 644, 4, 60, -1, 0, 0, 4, -1, 1601), + (645, 645, -1, 645, 645, 4, 64, 3614, 4, 5, 4, -1, 5999), + (649, -1, -1, 649, 649, 2, 61, -1, 0, 0, 4, -1, 650), + (650, -1, -1, 649, 649, 4, 63, -1, 0, 0, 4, 649, 651), + (651, -1, -1, 649, 649, 6, 65, -1, 0, 0, 4, 650, 5860), + (652, -1, -1, 652, 652, 2, 61, -1, 0, 0, 4, -1, 653), + (653, -1, -1, 652, 652, 4, 63, -1, 0, 0, 4, 652, 654), + (654, -1, -1, 652, 652, 6, 65, -1, 0, 0, 4, 653, -1), + (655, -1, -1, 655, 655, 3, 59, -1, 0, 0, 3, -1, 656), + (656, -1, -1, 655, 655, 6, 59, -1, 0, 0, 3, 655, 657), + (657, -1, -1, 655, 655, 9, 59, -1, 0, 0, 3, 656, -1), + (658, -1, -1, 658, 658, 2, 55, -1, 0, 0, 3, -1, 659), + (659, -1, -1, 658, 658, 4, 55, -1, 0, 0, 3, 658, 660), + (660, -1, -1, 658, 658, 6, 55, -1, 0, 0, 3, 659, 5306), + (661, -1, -1, 65, 661, 1, 51, -1, 0, 0, 3, -1, 662), + (662, -1, -1, 65, 661, 1, 51, -1, 0, 0, 3, 661, 663), + (663, -1, -1, 65, 661, 1, 51, -1, 0, 0, 3, 662, 674), + (665, -1, -1, 270, 665, 3, 59, -1, 0, 0, 3, -1, 666), + (666, -1, -1, 270, 665, 6, 59, -1, 0, 0, 3, 665, 667), + (667, -1, -1, 270, 665, 9, 59, -1, 0, 0, 3, 666, 668), + (668, -1, -1, 270, 665, 2, 63, -1, 0, 0, 4, 667, 669), + (669, -1, -1, 270, 665, 2, 64, -1, 0, 0, 4, 668, 670), + (670, -1, -1, 270, 665, 2, 65, -1, 0, 0, 4, 669, 7612), + (671, -1, -1, 671, 671, 3, 59, -1, 0, 0, 3, -1, -1), + (672, -1, -1, 62, 62, 5, 61, -1, 0, 0, 7, 64, 673), + (673, -1, -1, 62, 62, 5, 61, -1, 0, 0, 7, 672, -1), + (674, -1, -1, 65, 661, 3, 61, -1, 0, 0, 7, 663, 675), + (675, -1, -1, 65, 661, 3, 61, -1, 0, 0, 7, 674, 1031), + (676, -1, -1, 71, 71, 2, 61, -1, 0, 0, 7, 73, 677), + (677, -1, -1, 71, 71, 3, 61, -1, 0, 0, 7, 676, 978), + (678, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, -1, 679), + (679, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, 678, 680), + (680, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, 679, 681), + (681, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, 680, 682), + (682, -1, -1, 678, 678, 3, 61, -1, 0, 0, 7, 681, 6518), + (683, -1, -1, 683, 683, 3, 61, -1, 0, 0, 7, -1, 684), + (684, -1, -1, 683, 683, 6, 61, -1, 0, 0, 7, 683, 685), + (685, -1, -1, 683, 683, 9, 61, -1, 0, 0, 7, 684, 1036), + (686, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, -1, 687), + (687, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, 686, 688), + (688, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, 687, 689), + (689, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, 688, 690), + (690, -1, -1, 686, 686, 5, 55, -1, 0, 0, 7, 689, 7640), + (691, -1, -1, 691, 691, 9, 55, -1, 0, 0, 7, -1, -1), + (692, -1, -1, 692, 692, 3, 55, -1, 0, 0, 7, -1, 693), + (693, -1, -1, 692, 692, 6, 55, -1, 0, 0, 7, 692, 694), + (694, -1, -1, 692, 692, 9, 55, -1, 0, 0, 7, 693, 7647), + (695, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, -1, 696), + (696, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, 695, 697), + (697, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, 696, 698), + (698, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, 697, 699), + (699, -1, -1, 695, 695, 4, 65, -1, 0, 0, 7, 698, 15529), + (700, -1, -1, 213, 213, 9, 61, -1, 0, 0, 7, 215, -1), + (701, -1, -1, 275, 275, 9, 61, -1, 0, 0, 7, 277, -1), + (702, 592, 592, 592, 592, 3, 65, 4842, 2, 18, 7, 592, 703), + (703, 592, 592, 592, 592, 3, 65, 4843, 2, 18, 7, 702, 704), + (704, 592, 592, 592, 592, 3, 65, 4844, 2, 18, 7, 703, 705), + (705, 592, 592, 592, 592, 3, 65, 4845, 2, 18, 7, 704, 706), + (706, 592, 592, 592, 592, 3, 65, 4846, 2, 18, 7, 705, 1102), + (715, 534, 534, 534, 534, 3, 65, 5112, 4, 2160, 7, 536, 716), + (716, 534, 534, 534, 534, 6, 65, 5113, 4, 2160, 7, 715, 717), + (717, 534, 534, 534, 534, 9, 65, 5114, 4, 2160, 7, 716, 1278), + (718, 718, 718, 718, 718, 3, 65, 4521, 7, 4320, 7, -1, 719), + (719, 718, 718, 718, 718, 6, 65, 4522, 7, 4320, 7, 718, 720), + (720, 718, 718, 718, 718, 9, 65, 4523, 7, 4320, 7, 719, 1019), + (721, 619, 619, 619, 619, 5, 65, 5110, 6, 900, 7, 621, 722), + (722, 619, 619, 619, 619, 5, 65, 5111, 6, 900, 7, 721, 6296), + (723, 723, 723, 723, 723, 9, 65, 4788, 6, 30, 7, -1, 4963), + (724, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, -1, 725), + (725, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, 724, 726), + (726, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, 725, 727), + (727, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, 726, 728), + (728, -1, -1, 724, 724, 3, 65, -1, 0, 0, 7, 727, 5254), + (729, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, -1, 730), + (730, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, 729, 731), + (731, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, 730, 732), + (732, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, 731, 733), + (733, -1, -1, 729, 729, 5, 65, -1, 0, 0, 7, 732, 1467), + (734, -1, -1, 734, 734, 12, 65, -1, 0, 0, 7, -1, -1), + (735, -1, -1, 735, 735, 3, 62, -1, 0, 0, 7, -1, 736), + (736, -1, -1, 735, 735, 3, 62, -1, 0, 0, 7, 735, 737), + (737, -1, -1, 735, 735, 3, 62, -1, 0, 0, 7, 736, 7056), + (738, -1, -1, 98, 738, 3, 55, -1, 0, 0, 7, -1, 739), + (739, -1, -1, 98, 738, 6, 55, -1, 0, 0, 7, 738, 740), + (740, -1, -1, 98, 738, 9, 55, -1, 0, 0, 7, 739, 5317), + (746, 746, 746, 746, 746, 3, 65, 4549, 10, 2160, 7, -1, 747), + (747, 746, 746, 746, 746, 6, 65, 4550, 10, 2160, 7, 746, 748), + (748, 746, 746, 746, 746, 9, 65, 4551, 10, 2160, 7, 747, 1491), + (749, 749, 749, 749, 749, 5, 65, 4790, 11, 1800, 7, -1, 750), + (750, 749, 749, 749, 749, 5, 65, 4791, 11, 1800, 7, 749, 751), + (751, 749, 749, 749, 749, 5, 65, 4792, 11, 1800, 7, 750, 752), + (752, 749, 749, 749, 749, 5, 65, 4793, 11, 1800, 7, 751, 753), + (753, 749, 749, 749, 749, 5, 65, 4794, 11, 1800, 7, 752, 1206), + (754, -1, -1, 754, 754, 3, 65, -1, 0, 0, 7, -1, 755), + (755, -1, -1, 754, 754, 6, 65, -1, 0, 0, 7, 754, 756), + (756, -1, -1, 754, 754, 9, 65, -1, 0, 0, 7, 755, 7659), + (757, 757, -1, 757, 757, 5, 65, 4796, 6, 1800, 7, -1, 758), + (758, 757, -1, 757, 757, 5, 65, 4797, 6, 1800, 7, 757, 759), + (759, 757, -1, 757, 757, 5, 65, 4798, 6, 1800, 7, 758, 760), + (760, 757, -1, 757, 757, 5, 65, 4799, 6, 1800, 7, 759, 761), + (761, 757, -1, 757, 757, 5, 65, 4800, 6, 1800, 7, 760, 1222), + (762, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, -1, 763), + (763, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, 762, 764), + (764, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, 763, 765), + (765, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, 764, 766), + (766, -1, -1, 762, 762, 4, 65, -1, 0, 0, 7, 765, -1), + (767, -1, -1, 767, 767, 3, 65, -1, 0, 0, 7, -1, 768), + (768, -1, -1, 767, 767, 6, 65, -1, 0, 0, 7, 767, 769), + (769, -1, -1, 767, 767, 9, 65, -1, 0, 0, 7, 768, 1099), + (770, -1, -1, 637, 637, 3, 65, -1, 0, 0, 7, 639, 771), + (771, -1, -1, 637, 637, 6, 65, -1, 0, 0, 7, 770, 772), + (772, -1, -1, 637, 637, 9, 65, -1, 0, 0, 7, 771, 4749), + (773, 773, -1, 773, 773, 3, 65, 4552, 5, 1800, 7, -1, 774), + (774, 773, -1, 773, 773, 6, 65, 4553, 5, 1800, 7, 773, 775), + (775, 773, -1, 773, 773, 9, 65, 4554, 5, 1800, 7, 774, 5854), + (776, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, -1, 777), + (777, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, 776, 778), + (778, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, 777, 779), + (779, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, 778, 780), + (780, -1, -1, 776, 776, 3, 65, -1, 0, 0, 7, 779, -1), + (781, -1, -1, 781, 781, 12, 65, -1, 0, 0, 7, -1, 5850), + (782, -1, -1, 782, 782, 3, 65, -1, 0, 0, 7, -1, 783), + (783, -1, -1, 782, 782, 6, 65, -1, 0, 0, 7, 782, 784), + (784, -1, -1, 782, 782, 9, 65, -1, 0, 0, 7, 783, -1), + (785, 785, 785, 785, 785, 5, 65, 5235, 8, 900, 7, -1, 786), + (786, 785, 785, 785, 785, 5, 65, 5236, 8, 900, 7, 785, 787), + (787, 785, 785, 785, 785, 5, 65, 5237, 8, 900, 7, 786, 788), + (788, 785, 785, 785, 785, 5, 65, 5238, 8, 900, 7, 787, 789), + (789, 785, 785, 785, 785, 5, 65, 5239, 8, 900, 7, 788, 15235), + (790, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, -1, 791), + (791, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, 790, 792), + (792, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, 791, 793), + (793, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, 792, 794), + (794, -1, -1, 790, 790, 3, 65, -1, 0, 0, 7, 793, 5259), + (795, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, -1, 796), + (796, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, 795, 797), + (797, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, 796, 798), + (798, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, 797, 799), + (799, -1, -1, 795, 795, 5, 65, -1, 0, 0, 7, 798, 1430), + (800, -1, -1, 800, 800, 3, 65, -1, 0, 0, 7, -1, 801), + (801, -1, -1, 800, 800, 6, 65, -1, 0, 0, 7, 800, 802), + (802, -1, -1, 800, 800, 9, 65, -1, 0, 0, 7, 801, -1), + (803, -1, -1, 803, 803, 3, 65, -1, 0, 0, 7, -1, 804), + (804, -1, -1, 803, 803, 6, 65, -1, 0, 0, 7, 803, 805), + (805, -1, -1, 803, 803, 9, 65, -1, 0, 0, 7, 804, -1), + (806, -1, -1, 806, 806, 12, 65, -1, 0, 0, 7, -1, -1), + (807, -1, -1, 807, 807, 3, 65, -1, 0, 0, 7, -1, 808), + (808, -1, -1, 807, 807, 6, 65, -1, 0, 0, 7, 807, 809), + (809, -1, -1, 807, 807, 9, 65, -1, 0, 0, 7, 808, 1268), + (810, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, -1, 811), + (811, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, 810, 812), + (812, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, 811, 813), + (813, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, 812, 814), + (814, -1, -1, 810, 810, 5, 65, -1, 0, 0, 7, 813, 4824), + (815, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, -1, 816), + (816, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, 815, 817), + (817, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, 816, 818), + (818, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, 817, 819), + (819, -1, -1, 815, 815, 4, 65, -1, 0, 0, 7, 818, 5141), + (820, -1, -1, 820, 820, 3, 65, -1, 0, 0, 7, -1, 821), + (821, -1, -1, 820, 820, 6, 65, -1, 0, 0, 7, 820, 822), + (822, -1, -1, 820, 820, 9, 65, -1, 0, 0, 7, 821, 1265), + (823, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, -1, 824), + (824, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, 823, 825), + (825, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, 824, 826), + (826, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, 825, 827), + (827, -1, -1, 823, 823, 5, 65, -1, 0, 0, 7, 826, -1), + (828, 828, 828, 828, 828, 3, 65, 5240, 2, 3600, 7, -1, 829), + (829, 828, 828, 828, 828, 6, 65, 5241, 2, 3600, 7, 828, 830), + (830, 828, 828, 828, 828, 9, 65, 5242, 2, 3600, 7, 829, 16250), + (834, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, -1, 835), + (835, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, 834, 836), + (836, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, 835, 837), + (837, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, 836, 838), + (838, -1, -1, 834, 834, 3, 65, -1, 0, 0, 7, 837, -1), + (839, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, -1, 840), + (840, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, 839, 841), + (841, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, 840, 842), + (842, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, 841, 843), + (843, -1, -1, 839, 839, 5, 65, -1, 0, 0, 7, 842, 5325), + (844, -1, -1, 634, 634, 5, 65, -1, 0, 0, 7, 636, 845), + (845, -1, -1, 634, 634, 5, 65, -1, 0, 0, 7, 844, 1319), + (846, -1, -1, 846, 846, 3, 65, -1, 0, 0, 7, -1, 847), + (847, -1, -1, 846, 846, 6, 65, -1, 0, 0, 7, 846, 848), + (848, -1, -1, 846, 846, 9, 65, -1, 0, 0, 7, 847, 1301), + (849, -1, -1, 849, 849, 3, 65, -1, 0, 0, 7, -1, 850), + (850, -1, -1, 849, 849, 6, 65, -1, 0, 0, 7, 849, 851), + (851, -1, -1, 849, 849, 9, 65, -1, 0, 0, 7, 850, 10621), + (852, -1, -1, 852, 852, 5, 65, -1, 0, 0, 7, -1, 853), + (853, -1, -1, 852, 852, 5, 65, -1, 0, 0, 7, 852, 854), + (854, -1, -1, 852, 852, 5, 65, -1, 0, 0, 7, 853, 5500), + (855, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, -1, 856), + (856, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, 855, 857), + (857, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, 856, 858), + (858, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, 857, 859), + (859, -1, -1, 855, 855, 5, 65, -1, 0, 0, 7, 858, 7673), + (860, 860, 860, 860, 860, 3, 65, 3297, 5, 180, 7, -1, 861), + (861, 860, 860, 860, 860, 6, 65, 3298, 5, 180, 7, 860, 862), + (862, 860, 860, 860, 860, 9, 65, 3299, 5, 180, 7, 861, 5130), + (863, 863, -1, 863, 863, 12, 65, 5248, 6, 4320, 7, -1, -1), + (864, -1, -1, 864, 864, 3, 65, -1, 0, 0, 7, -1, 865), + (865, -1, -1, 864, 864, 6, 65, -1, 0, 0, 7, 864, 866), + (866, -1, -1, 864, 864, 9, 65, -1, 0, 0, 7, 865, 1290), + (867, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, -1, 868), + (868, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, 867, 869), + (869, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, 868, 870), + (870, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, 869, 871), + (871, -1, -1, 867, 867, 5, 65, -1, 0, 0, 7, 870, 7362), + (872, 872, 872, 872, 872, 3, 65, 4802, 5, 180, 7, -1, 873), + (873, 872, 872, 872, 872, 6, 65, 4803, 5, 180, 7, 872, 874), + (874, 872, 872, 872, 872, 9, 65, 4804, 5, 180, 7, 873, 7367), + (875, 875, 875, 875, 875, 3, 65, 4805, 5, 180, 7, -1, 876), + (876, 875, 875, 875, 875, 6, 65, 4806, 5, 180, 7, 875, 877), + (877, 875, 875, 875, 875, 9, 65, 4807, 5, 180, 7, 876, 7370), + (878, -1, -1, 878, 878, 3, 65, -1, 0, 0, 7, -1, 879), + (879, -1, -1, 878, 878, 6, 65, -1, 0, 0, 7, 878, 880), + (880, -1, -1, 878, 878, 9, 65, -1, 0, 0, 7, 879, 1539), + (881, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, -1, 882), + (882, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, 881, 883), + (883, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, 882, 884), + (884, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, 883, 885), + (885, -1, -1, 881, 881, 3, 65, -1, 0, 0, 7, 884, -1), + (886, -1, -1, 498, 498, 5, 65, -1, 0, 0, 7, 500, 887), + (887, -1, -1, 498, 498, 5, 65, -1, 0, 0, 7, 886, 975), + (888, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, -1, 889), + (889, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, 888, 890), + (890, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, 889, 891), + (891, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, 890, 892), + (892, -1, -1, 888, 888, 3, 65, -1, 0, 0, 7, 891, 16267), + (893, -1, -1, 589, 589, 5, 65, -1, 0, 0, 7, 591, 894), + (894, -1, -1, 589, 589, 5, 65, -1, 0, 0, 7, 893, 5270), + (895, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, -1, 896), + (896, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, 895, 897), + (897, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, 896, 898), + (898, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, 897, 899), + (899, -1, -1, 895, 895, 5, 65, -1, 0, 0, 7, 898, 6075), + (900, 528, 528, 528, 528, 5, 65, 4826, 5, 720, 7, 530, 901), + (901, 528, 528, 528, 528, 5, 65, 4827, 5, 720, 7, 900, 6103), + (907, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, -1, 908), + (908, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, 907, 909), + (909, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, 908, 910), + (910, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, 909, 911), + (911, -1, -1, 907, 907, 5, 65, -1, 0, 0, 7, 910, 5243), + (912, 912, 912, 912, 912, 3, 65, 4925, 4, 3600, 7, -1, 913), + (913, 912, 912, 912, 912, 6, 65, 4926, 4, 3600, 7, 912, 914), + (914, 912, 912, 912, 912, 9, 65, 4927, 4, 3600, 7, 913, 1330), + (915, -1, -1, 915, 915, 3, 65, -1, 0, 0, 7, -1, 916), + (916, -1, -1, 915, 915, 6, 65, -1, 0, 0, 7, 915, 917), + (917, -1, -1, 915, 915, 9, 65, -1, 0, 0, 7, 916, -1), + (918, -1, -1, 918, 918, 3, 65, -1, 0, 0, 7, -1, 919), + (919, -1, -1, 918, 918, 6, 65, -1, 0, 0, 7, 918, 920), + (920, -1, -1, 918, 918, 9, 65, -1, 0, 0, 7, 919, -1), + (921, 921, 921, 921, 921, 12, 65, 4833, 8, 60, 7, -1, 1340), + (922, 922, 922, 922, 922, 12, 65, 4834, 8, 60, 7, -1, 1341), + (923, 923, 923, 923, 923, 12, 65, 4835, 8, 60, 7, -1, 1342), + (924, -1, -1, 267, 267, 5, 65, -1, 0, 0, 7, 642, 925), + (925, -1, -1, 267, 267, 5, 65, -1, 0, 0, 7, 924, 5133), + (926, 926, 926, 926, 926, 3, 65, 4836, 12, 1800, 7, -1, 927), + (927, 926, 926, 926, 926, 3, 65, 4837, 12, 1800, 7, 926, 928), + (928, 926, 926, 926, 926, 3, 65, 4838, 12, 1800, 7, 927, 929), + (929, 926, 926, 926, 926, 3, 65, 4839, 12, 1800, 7, 928, 930), + (930, 926, 926, 926, 926, 3, 65, 4840, 12, 1800, 7, 929, 14991), + (931, 931, 931, 931, 931, 3, 65, 5245, 13, 4320, 7, -1, 932), + (932, 931, 931, 931, 931, 6, 65, 5246, 13, 4320, 7, 931, 933), + (933, 931, 931, 931, 931, 9, 65, 5247, 13, 4320, 7, 932, -1), + (934, -1, -1, 113, 934, 2, 55, -1, 0, 0, 3, -1, 935), + (935, -1, -1, 113, 934, 4, 55, -1, 0, 0, 3, 934, 936), + (936, -1, -1, 113, 934, 6, 55, -1, 0, 0, 3, 935, 943), + (937, -1, -1, 113, 937, 2, 55, -1, 0, 0, 3, -1, 938), + (938, -1, -1, 113, 937, 4, 55, -1, 0, 0, 3, 937, 939), + (939, -1, -1, 113, 937, 6, 55, -1, 0, 0, 3, 938, 946), + (940, -1, -1, 113, 940, 2, 55, -1, 0, 0, 3, -1, 941), + (941, -1, -1, 113, 940, 4, 55, -1, 0, 0, 3, 940, 942), + (942, -1, -1, 113, 940, 6, 55, -1, 0, 0, 3, 941, 949), + (943, -1, -1, 113, 934, 3, 62, -1, 0, 0, 4, 936, 944), + (944, -1, -1, 113, 934, 3, 63, -1, 0, 0, 4, 943, 945), + (945, -1, -1, 113, 934, 3, 64, -1, 0, 0, 4, 944, -1), + (946, -1, -1, 113, 937, 3, 62, -1, 0, 0, 4, 939, 947), + (947, -1, -1, 113, 937, 3, 63, -1, 0, 0, 4, 946, 948), + (948, -1, -1, 113, 937, 3, 64, -1, 0, 0, 4, 947, -1), + (949, -1, -1, 113, 940, 3, 62, -1, 0, 0, 4, 942, 950), + (950, -1, -1, 113, 940, 3, 63, -1, 0, 0, 4, 949, 951), + (951, -1, -1, 113, 940, 3, 64, -1, 0, 0, 4, 950, -1), + (952, -1, -1, 952, 952, 3, 61, -1, 0, 0, 4, -1, 953), + (953, -1, -1, 952, 952, 3, 63, -1, 0, 0, 4, 952, 954), + (954, -1, -1, 952, 952, 3, 65, -1, 0, 0, 4, 953, -1), + (955, -1, -1, 955, 955, 3, 61, -1, 0, 0, 4, -1, 956), + (956, -1, -1, 955, 955, 3, 62, -1, 0, 0, 4, 955, 957), + (957, -1, -1, 955, 955, 3, 63, -1, 0, 0, 4, 956, 958), + (958, -1, -1, 955, 955, 3, 64, -1, 0, 0, 4, 957, 959), + (959, -1, -1, 955, 955, 3, 65, -1, 0, 0, 4, 958, -1), + (960, 960, 960, 960, 960, 9, 59, 2760, 7, 4320, 3, -1, -1), + (961, 961, 961, 961, 961, 9, 59, 2759, 11, 4320, 3, -1, -1), + (962, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, -1, 963), + (963, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, 962, 964), + (964, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, 963, 965), + (965, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, 964, 966), + (966, -1, -1, 962, 962, 5, 65, -1, 0, 0, 7, 965, 6223), + (967, 967, 967, 967, 967, 3, 65, 4564, 10, 1800, 7, -1, 968), + (968, 967, 967, 967, 967, 6, 65, 4565, 10, 1800, 7, 967, 969), + (969, 967, 967, 967, 967, 9, 65, 4566, 10, 1800, 7, 968, 6464), + (970, 970, 970, 970, 970, 5, 65, 4828, 6, 1800, 7, -1, 971), + (971, 970, 970, 970, 970, 5, 65, 4829, 6, 1800, 7, 970, 972), + (972, 970, 970, 970, 970, 5, 65, 4830, 6, 1800, 7, 971, 973), + (973, 970, 970, 970, 970, 5, 65, 4831, 6, 1800, 7, 972, 974), + (974, 970, 970, 970, 970, 5, 65, 4832, 6, 1800, 7, 973, 1324), + (975, -1, -1, 498, 498, 5, 65, -1, 0, 0, 15, 887, 13262), + (976, -1, -1, 976, 976, 5, 59, -1, 0, 0, 15, -1, -1), + (977, 977, 977, 977, 977, 6, 64, 13835, 72, 600, 15, -1, -1), + (978, -1, -1, 71, 71, 5, 68, -1, 0, 0, 8, 677, -1), + (979, -1, -1, 979, 979, 3, 59, -1, 0, 0, 8, -1, 980), + (980, -1, -1, 979, 979, 6, 59, -1, 0, 0, 8, 979, 981), + (981, -1, -1, 979, 979, 9, 59, -1, 0, 0, 8, 980, -1), + (982, -1, -1, 982, 982, 3, 59, -1, 0, 0, 8, -1, 983), + (983, -1, -1, 982, 982, 6, 59, -1, 0, 0, 8, 982, 984), + (984, -1, -1, 982, 982, 9, 59, -1, 0, 0, 8, 983, -1), + (985, -1, -1, 985, 985, 3, 59, -1, 0, 0, 8, -1, 986), + (986, -1, -1, 985, 985, 6, 59, -1, 0, 0, 8, 985, 987), + (987, -1, -1, 985, 985, 9, 59, -1, 0, 0, 8, 986, -1), + (988, -1, -1, 988, 988, 3, 59, -1, 0, 0, 8, -1, 989), + (989, -1, -1, 988, 988, 6, 59, -1, 0, 0, 8, 988, 990), + (990, -1, -1, 988, 988, 9, 59, -1, 0, 0, 8, 989, -1), + (991, -1, -1, 991, 991, 3, 59, -1, 0, 0, 8, -1, 992), + (992, -1, -1, 991, 991, 6, 59, -1, 0, 0, 8, 991, 993), + (993, -1, -1, 991, 991, 9, 59, -1, 0, 0, 8, 992, -1), + (994, -1, -1, 994, 994, 3, 59, -1, 0, 0, 8, -1, 995), + (995, -1, -1, 994, 994, 6, 59, -1, 0, 0, 8, 994, 996), + (996, -1, -1, 994, 994, 9, 59, -1, 0, 0, 8, 995, -1), + (997, -1, -1, 997, 997, 5, 60, -1, 0, 0, 8, -1, 998), + (998, -1, -1, 997, 997, 5, 65, -1, 0, 0, 8, 997, 999), + (999, -1, -1, 997, 997, 5, 70, -1, 0, 0, 8, 998, 1113), + (1000, 1000, -1, 1000, 1000, 0, 5, 5824, 20, 1080, 0, -1, -1), + (1001, -1, -1, 418, 418, 5, 66, -1, 0, 0, 8, 422, 1002), + (1002, -1, -1, 418, 418, 5, 67, -1, 0, 0, 8, 1001, 1003), + (1003, -1, -1, 418, 418, 5, 68, -1, 0, 0, 8, 1002, 1004), + (1004, -1, -1, 418, 418, 5, 69, -1, 0, 0, 8, 1003, 1005), + (1005, -1, -1, 418, 418, 5, 70, -1, 0, 0, 8, 1004, 4678), + (1006, -1, -1, 1006, 1006, 5, 66, -1, 0, 0, 8, -1, 1007), + (1007, -1, -1, 1006, 1006, 5, 67, -1, 0, 0, 8, 1006, 1008), + (1008, -1, -1, 1006, 1006, 5, 68, -1, 0, 0, 8, 1007, 1009), + (1009, -1, -1, 1006, 1006, 5, 69, -1, 0, 0, 8, 1008, 1010), + (1010, -1, -1, 1006, 1006, 5, 70, -1, 0, 0, 8, 1009, 7516), + (1011, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, -1, 1012), + (1012, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1011, 1013), + (1013, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1012, 1014), + (1014, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1013, 1015), + (1015, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1014, 1016), + (1016, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1015, -1), + (1017, 1017, 1017, 1017, 1017, 6, 59, 16531, 75, 15, 15, -1, 13726), + (1018, 1018, 1018, 1018, 1018, 2, 63, 16455, 69, 1, 15, -1, -1), + (1019, 718, 718, 718, 718, 12, 65, 21746, 7, 4320, 16, 720, 13454), + (1021, -1, -1, 1021, 1021, 5, 51, -1, 0, 0, 8, -1, 1022), + (1022, -1, -1, 1021, 1021, 5, 55, -1, 0, 0, 8, 1021, 1023), + (1023, -1, -1, 1021, 1021, 5, 60, -1, 0, 0, 8, 1022, 1024), + (1024, -1, -1, 1021, 1021, 5, 65, -1, 0, 0, 8, 1023, 1025), + (1025, -1, -1, 1021, 1021, 5, 70, -1, 0, 0, 8, 1024, 6521), + (1026, -1, -1, 1026, 1026, 3, 66, -1, 0, 0, 8, -1, 1027), + (1027, -1, -1, 1026, 1026, 3, 67, -1, 0, 0, 8, 1026, 1028), + (1028, -1, -1, 1026, 1026, 3, 68, -1, 0, 0, 8, 1027, 1029), + (1029, -1, -1, 1026, 1026, 3, 69, -1, 0, 0, 8, 1028, 1030), + (1030, -1, -1, 1026, 1026, 3, 70, -1, 0, 0, 8, 1029, 1389), + (1031, -1, -1, 65, 661, 3, 66, -1, 0, 0, 8, 675, 1032), + (1032, -1, -1, 65, 661, 3, 67, -1, 0, 0, 8, 1031, 1033), + (1033, -1, -1, 65, 661, 3, 68, -1, 0, 0, 8, 1032, 1034), + (1034, -1, -1, 65, 661, 3, 69, -1, 0, 0, 8, 1033, 1035), + (1035, -1, -1, 65, 661, 3, 70, -1, 0, 0, 8, 1034, 4693), + (1036, -1, -1, 683, 683, 5, 66, -1, 0, 0, 8, 685, 1037), + (1037, -1, -1, 683, 683, 5, 68, -1, 0, 0, 8, 1036, 1038), + (1038, -1, -1, 683, 683, 5, 70, -1, 0, 0, 8, 1037, 5301), + (1041, -1, -1, 1041, 1041, 3, 67, -1, 0, 0, 8, -1, 1042), + (1042, -1, -1, 1041, 1041, 6, 68, -1, 0, 0, 8, 1041, 1043), + (1043, -1, -1, 1041, 1041, 9, 69, -1, 0, 0, 8, 1042, 4707), + (1044, -1, -1, 1044, 1044, 3, 67, -1, 0, 0, 8, -1, 1045), + (1045, -1, -1, 1044, 1044, 6, 68, -1, 0, 0, 8, 1044, 1046), + (1046, -1, -1, 1044, 1044, 9, 69, -1, 0, 0, 8, 1045, 4710), + (1047, -1, -1, 1047, 1047, 3, 67, -1, 0, 0, 8, -1, 1048), + (1048, -1, -1, 1047, 1047, 6, 68, -1, 0, 0, 8, 1047, 1049), + (1049, -1, -1, 1047, 1047, 9, 69, -1, 0, 0, 8, 1048, 4713), + (1050, -1, -1, 1050, 1050, 3, 67, -1, 0, 0, 8, -1, 1051), + (1051, -1, -1, 1050, 1050, 6, 68, -1, 0, 0, 8, 1050, 1052), + (1052, -1, -1, 1050, 1050, 9, 69, -1, 0, 0, 8, 1051, 4716), + (1053, -1, -1, 119, 119, 3, 66, -1, 0, 0, 8, 442, 1054), + (1054, -1, -1, 119, 119, 3, 68, -1, 0, 0, 8, 1053, 1055), + (1055, -1, -1, 119, 119, 3, 70, -1, 0, 0, 8, 1054, 4722), + (1056, -1, -1, 1056, 1056, 5, 71, -1, 0, 0, 12, -1, 1057), + (1057, -1, -1, 1056, 1056, 5, 72, -1, 0, 0, 12, 1056, 1058), + (1058, -1, -1, 1056, 1056, 5, 73, -1, 0, 0, 12, 1057, 1059), + (1059, -1, -1, 1056, 1056, 5, 74, -1, 0, 0, 12, 1058, 1060), + (1060, -1, -1, 1056, 1056, 5, 75, -1, 0, 0, 12, 1059, 6431), + (1061, -1, -1, 125, 125, 5, 66, -1, 0, 0, 8, 453, 1062), + (1062, -1, -1, 125, 125, 5, 67, -1, 0, 0, 8, 1061, 1063), + (1063, -1, -1, 125, 125, 5, 68, -1, 0, 0, 8, 1062, 1064), + (1064, -1, -1, 125, 125, 5, 69, -1, 0, 0, 8, 1063, 1065), + (1065, -1, -1, 125, 125, 5, 70, -1, 0, 0, 8, 1064, 1394), + (1066, -1, -1, 122, 122, 5, 66, -1, 0, 0, 8, 458, 1067), + (1067, -1, -1, 122, 122, 5, 67, -1, 0, 0, 8, 1066, 1068), + (1068, -1, -1, 122, 122, 5, 68, -1, 0, 0, 8, 1067, 1069), + (1069, -1, -1, 122, 122, 5, 69, -1, 0, 0, 8, 1068, 1070), + (1070, -1, -1, 122, 122, 5, 70, -1, 0, 0, 8, 1069, 1399), + (1071, -1, -1, 1071, 1071, 3, 55, -1, 0, 0, 8, -1, 4764), + (1072, -1, -1, 1072, 1072, 5, 66, -1, 0, 0, 8, -1, 1073), + (1073, -1, -1, 1072, 1072, 5, 67, -1, 0, 0, 8, 1072, 1074), + (1074, -1, -1, 1072, 1072, 5, 68, -1, 0, 0, 8, 1073, 1075), + (1075, -1, -1, 1072, 1072, 5, 69, -1, 0, 0, 8, 1074, 1076), + (1076, -1, -1, 1072, 1072, 5, 70, -1, 0, 0, 8, 1075, 4744), + (1083, -1, -1, 77, 77, 3, 66, -1, 0, 0, 8, 436, 1084), + (1084, -1, -1, 77, 77, 6, 68, -1, 0, 0, 8, 1083, 1085), + (1085, -1, -1, 77, 77, 9, 70, -1, 0, 0, 8, 1084, 12449), + (1086, -1, -1, 80, 80, 3, 66, -1, 0, 0, 8, 439, 1087), + (1087, -1, -1, 80, 80, 6, 68, -1, 0, 0, 8, 1086, 1088), + (1088, -1, -1, 80, 80, 9, 70, -1, 0, 0, 8, 1087, 4779), + (1089, -1, -1, 1089, 1089, 3, 59, -1, 0, 0, 8, -1, 1090), + (1090, -1, -1, 1089, 1089, 6, 59, -1, 0, 0, 8, 1089, 1091), + (1091, -1, -1, 1089, 1089, 9, 59, -1, 0, 0, 8, 1090, -1), + (1092, -1, -1, 1092, 1092, 7, 67, -1, 0, 0, 8, -1, -1), + (1093, -1, -1, 1093, 1093, 3, 66, -1, 0, 0, 8, -1, 1094), + (1094, -1, -1, 1093, 1093, 3, 67, -1, 0, 0, 8, 1093, 1095), + (1095, -1, -1, 1093, 1093, 3, 68, -1, 0, 0, 8, 1094, 1096), + (1096, -1, -1, 1093, 1093, 3, 69, -1, 0, 0, 8, 1095, 1097), + (1097, -1, -1, 1093, 1093, 3, 70, -1, 0, 0, 8, 1096, -1), + (1099, -1, -1, 767, 767, 3, 67, -1, 0, 0, 8, 769, 1100), + (1100, -1, -1, 767, 767, 6, 68, -1, 0, 0, 8, 1099, 1101), + (1101, -1, -1, 767, 767, 9, 69, -1, 0, 0, 8, 1100, 12423), + (1102, 592, 592, 592, 592, 3, 66, 5825, 2, 18, 8, 706, 1103), + (1103, 592, 592, 592, 592, 3, 67, 5826, 2, 18, 8, 1102, 1104), + (1104, 592, 592, 592, 592, 3, 68, 5827, 2, 18, 8, 1103, 1105), + (1105, 592, 592, 592, 592, 3, 69, 5828, 2, 18, 8, 1104, 1106), + (1106, 592, 592, 592, 592, 3, 70, 5829, 2, 18, 8, 1105, 4975), + (1107, -1, -1, 1107, 1107, 3, 66, -1, 0, 0, 8, -1, 1108), + (1108, -1, -1, 1107, 1107, 6, 68, -1, 0, 0, 8, 1107, 1109), + (1109, -1, -1, 1107, 1107, 9, 70, -1, 0, 0, 8, 1108, 5286), + (1110, 1110, 1110, 1110, 1110, 3, 68, 5830, 3, 2160, 8, -1, 1111), + (1111, 1110, 1110, 1110, 1110, 6, 69, 5831, 3, 2160, 8, 1110, 1112), + (1112, 1110, 1110, 1110, 1110, 9, 70, 5832, 3, 2160, 8, 1111, 6400), + (1113, -1, -1, 997, 997, 5, 75, -1, 0, 0, 16, 999, 1114), + (1114, -1, -1, 997, 997, 5, 80, -1, 0, 0, 16, 1113, 1115), + (1115, -1, -1, 997, 997, 5, 85, -1, 0, 0, 16, 1114, -1), + (1116, 1116, 1116, 1116, 1116, 3, 68, 5837, 4, 2160, 8, -1, 1117), + (1117, 1116, 1116, 1116, 1116, 6, 69, 5838, 4, 2160, 8, 1116, 1118), + (1118, 1116, 1116, 1116, 1116, 9, 70, 5839, 4, 2160, 8, 1117, 4980), + (1119, 1119, 1119, 1119, 1119, 3, 68, 5841, 8, 900, 8, -1, 1120), + (1120, 1119, 1119, 1119, 1119, 6, 69, 5842, 8, 900, 8, 1119, 1121), + (1121, 1119, 1119, 1119, 1119, 9, 70, 5843, 8, 900, 8, 1120, 4964), + (1122, -1, -1, 1122, 1122, 7, 67, -1, 0, 0, 8, -1, -1), + (1123, 291, 291, 291, 291, 5, 66, 5854, 5, 900, 8, 291, 1124), + (1124, 291, 291, 291, 291, 5, 68, 5855, 5, 900, 8, 1123, 1125), + (1125, 291, 291, 291, 291, 5, 70, 5856, 5, 900, 8, 1124, 4969), + (1126, 1126, 1126, 1126, 1126, 3, 67, 5845, 2, 2160, 8, -1, 1127), + (1127, 1126, 1126, 1126, 1126, 6, 68, 5846, 2, 2160, 8, 1126, 1128), + (1128, 1126, 1126, 1126, 1126, 9, 69, 5847, 2, 2160, 8, 1127, 5513), + (1129, -1, -1, 1129, 1129, 5, 67, -1, 0, 0, 8, -1, 1130), + (1130, -1, -1, 1129, 1129, 3, 69, -1, 0, 0, 8, 1129, -1), + (1131, -1, -1, 1131, 1131, 3, 59, -1, 0, 0, 3, -1, 1132), + (1132, -1, -1, 1131, 1131, 6, 59, -1, 0, 0, 3, 1131, 1133), + (1133, -1, -1, 1131, 1131, 9, 59, -1, 0, 0, 3, 1132, 11082), + (1134, -1, -1, 1134, 1134, 3, 61, -1, 0, 0, 4, -1, 1135), + (1135, -1, -1, 1134, 1134, 4, 63, -1, 0, 0, 4, 1134, 1136), + (1136, -1, -1, 1134, 1134, 5, 65, -1, 0, 0, 4, 1135, 1158), + (1137, -1, -1, 1137, 1137, 3, 59, -1, 0, 0, 3, -1, 1138), + (1138, -1, -1, 1137, 1137, 6, 59, -1, 0, 0, 3, 1137, 1139), + (1139, -1, -1, 1137, 1137, 9, 59, -1, 0, 0, 3, 1138, -1), + (1140, -1, -1, 1140, 1140, 3, 61, -1, 0, 0, 4, -1, 1141), + (1141, -1, -1, 1140, 1140, 3, 63, -1, 0, 0, 4, 1140, 1142), + (1142, -1, -1, 1140, 1140, 3, 65, -1, 0, 0, 4, 1141, -1), + (1146, 1146, 1146, 1146, 1146, 3, 59, 6040, 3, 1500, 3, -1, 1147), + (1147, 1146, 1146, 1146, 1146, 6, 59, 6041, 3, 1200, 3, 1146, 1148), + (1148, 1146, 1146, 1146, 1146, 9, 59, 6042, 3, 900, 3, 1147, -1), + (1149, 1149, -1, 1149, 1149, 12, 65, 5853, 5, 1320, 7, -1, -1), + (1150, 1150, 1150, 1150, 1150, 3, 65, 5848, 2, 2160, 7, -1, 1151), + (1151, 1150, 1150, 1150, 1150, 6, 65, 5849, 2, 2160, 7, 1150, 1152), + (1152, 1150, 1150, 1150, 1150, 9, 65, 5850, 2, 2160, 7, 1151, -1), + (1155, -1, -1, 1155, 1155, 3, 65, -1, 0, 0, 7, -1, 1156), + (1156, -1, -1, 1155, 1155, 6, 65, -1, 0, 0, 7, 1155, 1157), + (1157, -1, -1, 1155, 1155, 9, 65, -1, 0, 0, 7, 1156, -1), + (1158, -1, -1, 1134, 1134, 4, 66, -1, 0, 0, 8, 1136, 1159), + (1159, -1, -1, 1134, 1134, 4, 67, -1, 0, 0, 8, 1158, 1160), + (1160, -1, -1, 1134, 1134, 4, 68, -1, 0, 0, 8, 1159, 1161), + (1161, -1, -1, 1134, 1134, 4, 69, -1, 0, 0, 8, 1160, 1162), + (1162, -1, -1, 1134, 1134, 4, 70, -1, 0, 0, 8, 1161, 4790), + (1163, -1, -1, 255, 255, 5, 67, -1, 0, 0, 8, 544, 1164), + (1164, -1, -1, 255, 255, 5, 68, -1, 0, 0, 8, 1163, 1165), + (1165, -1, -1, 255, 255, 5, 69, -1, 0, 0, 8, 1164, 4795), + (1166, -1, -1, 1143, 1143, 3, 65, -1, 0, 0, 15, -1, 1167), + (1167, -1, -1, 1143, 1143, 6, 65, -1, 0, 0, 15, 1166, 1168), + (1168, -1, -1, 1143, 1143, 9, 65, -1, 0, 0, 15, 1167, 6911), + (1172, -1, -1, 631, 631, 5, 67, -1, 0, 0, 8, 633, 1173), + (1173, -1, -1, 631, 631, 5, 68, -1, 0, 0, 8, 1172, 1174), + (1174, -1, -1, 631, 631, 5, 69, -1, 0, 0, 8, 1173, 4798), + (1178, 1178, 1178, 1178, 1178, 3, 68, 5857, 4, 900, 8, -1, 1179), + (1179, 1178, 1178, 1178, 1178, 6, 69, 5858, 4, 900, 8, 1178, 1180), + (1180, 1178, 1178, 1178, 1178, 9, 70, 5859, 4, 900, 8, 1179, 5779), + (1181, -1, -1, 1181, 1181, 3, 66, -1, 0, 0, 8, -1, 1182), + (1182, -1, -1, 1181, 1181, 3, 67, -1, 0, 0, 8, 1181, 1183), + (1183, -1, -1, 1181, 1181, 3, 68, -1, 0, 0, 8, 1182, 1184), + (1184, -1, -1, 1181, 1181, 3, 69, -1, 0, 0, 8, 1183, 1185), + (1185, -1, -1, 1181, 1181, 3, 70, -1, 0, 0, 8, 1184, -1), + (1186, -1, -1, 1186, 1186, 3, 66, -1, 0, 0, 8, -1, 1187), + (1187, -1, -1, 1186, 1186, 6, 68, -1, 0, 0, 8, 1186, 1188), + (1188, -1, -1, 1186, 1186, 9, 70, -1, 0, 0, 8, 1187, 4776), + (1189, 459, 459, 459, 459, 3, 66, 5860, 8, 180, 8, 461, 1190), + (1190, 459, 459, 459, 459, 6, 68, 5861, 8, 180, 8, 1189, 1191), + (1191, 459, 459, 459, 459, 9, 70, 5862, 8, 180, 8, 1190, 5062), + (1192, 1192, 1192, 1192, 1192, 5, 67, 5863, 12, 1320, 8, -1, 1193), + (1193, 1192, 1192, 1192, 1192, 5, 68, 5864, 12, 1320, 8, 1192, 1194), + (1194, 1192, 1192, 1192, 1192, 5, 69, 5865, 12, 1320, 8, 1193, 5076), + (1195, 1195, 1195, 1195, 1195, 12, 70, 5866, 13, 2160, 8, -1, 5079), + (1196, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, -1, 1197), + (1197, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, 1196, 1198), + (1198, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, 1197, 1199), + (1199, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, 1198, 1200), + (1200, -1, -1, 1196, 1196, 2, 81, -1, 0, 0, 15, 1199, 10743), + (1203, 131, 131, 131, 131, 5, 67, 5869, 4, 900, 8, 532, 1204), + (1204, 131, 131, 131, 131, 5, 68, 5870, 4, 900, 8, 1203, 1205), + (1205, 131, 131, 131, 131, 5, 69, 5988, 4, 900, 8, 1204, 5070), + (1206, 749, 749, 749, 749, 5, 66, 5871, 11, 1800, 8, 753, 1207), + (1207, 749, 749, 749, 749, 5, 68, 5872, 11, 1800, 8, 1206, 1208), + (1208, 749, 749, 749, 749, 5, 70, 5873, 11, 1800, 8, 1207, 17298), + (1209, 1209, -1, 1209, 1209, 12, 70, 5912, 14, 4320, 8, -1, -1), + (1210, -1, -1, 1210, 1210, 3, 66, -1, 0, 0, 8, -1, 1211), + (1211, -1, -1, 1210, 1210, 6, 68, -1, 0, 0, 8, 1210, 1212), + (1212, -1, -1, 1210, 1210, 9, 70, -1, 0, 0, 8, 1211, 1483), + (1213, -1, -1, 1210, 1213, 3, 66, -1, 0, 0, 8, -1, 1214), + (1214, -1, -1, 1210, 1213, 6, 68, -1, 0, 0, 8, 1213, 1215), + (1215, -1, -1, 1210, 1213, 9, 70, -1, 0, 0, 8, 1214, 4755), + (1216, -1, -1, 83, 83, 3, 81, -1, 0, 0, 16, -1, 1217), + (1217, -1, -1, 83, 83, 6, 81, -1, 0, 0, 16, 1216, 1218), + (1218, -1, -1, 83, 83, 9, 81, -1, 0, 0, 16, 1217, 15422), + (1219, -1, -1, 1435, 1435, 10, 71, -1, 0, 0, 16, -1, 1220), + (1220, -1, -1, 1435, 1435, 11, 71, -1, 0, 0, 16, 1219, 1221), + (1221, -1, -1, 1435, 1435, 12, 71, -1, 0, 0, 16, 1220, 1648), + (1222, 757, -1, 757, 1222, 5, 66, 5877, 6, 1800, 8, 761, 1223), + (1223, 757, -1, 757, 1222, 5, 68, 5878, 6, 1800, 8, 1222, 1224), + (1224, 757, -1, 757, 1222, 5, 70, 5879, 6, 1800, 8, 1223, 5051), + (1225, 548, 548, 548, 548, 5, 67, 5881, 5, 900, 8, 550, 1226), + (1226, 548, 548, 548, 548, 5, 68, 5882, 5, 900, 8, 1225, 1227), + (1227, 548, 548, 548, 548, 5, 69, 5883, 5, 900, 8, 1226, 5054), + (1228, 1228, 1228, 1228, 1228, 9, 70, 5880, 9, 600, 8, -1, -1), + (1229, 1229, 1229, 1229, 1229, 7, 66, 6094, 10, 600, 8, -1, -1), + (1230, -1, -1, 1230, 1230, 1, 51, -1, 0, 0, 8, -1, 1231), + (1231, -1, -1, 1230, 1230, 2, 53, -1, 0, 0, 8, 1230, 1232), + (1232, -1, -1, 1230, 1230, 3, 55, -1, 0, 0, 8, 1231, 5000), + (1233, 1233, -1, 1233, 1233, 3, 68, 5887, 7, 2160, 8, -1, 1234), + (1234, 1233, -1, 1233, 1233, 6, 69, 5888, 7, 2160, 8, 1233, 1235), + (1235, 1233, -1, 1233, 1233, 9, 70, 5889, 7, 2160, 8, 1234, -1), + (1239, 1239, 1239, 1239, 1239, 12, 70, 5903, 6, 600, 8, -1, 5868), + (1242, 1242, 1242, 1242, 1242, 3, 67, 5906, 9, 1320, 8, -1, 1243), + (1243, 1242, 1242, 1242, 1242, 6, 68, 5907, 9, 1320, 8, 1242, 1244), + (1244, 1242, 1242, 1242, 1242, 9, 69, 5908, 9, 1320, 8, 1243, 5857), + (1245, 1245, 1245, 1245, 1245, 3, 66, 5909, 8, 2160, 8, -1, 1246), + (1246, 1245, 1245, 1245, 1245, 6, 68, 5910, 8, 2160, 8, 1245, 1247), + (1247, 1245, 1245, 1245, 1245, 9, 70, 5911, 8, 2160, 8, 1246, 15459), + (1248, 616, 616, 616, 616, 3, 68, 6226, 7, 900, 8, 618, 1249), + (1249, 616, 616, 616, 616, 6, 69, 6227, 7, 900, 8, 1248, 1250), + (1250, 616, 616, 616, 616, 9, 70, 6228, 7, 900, 8, 1249, 6254), + (1251, 1251, 1251, 1251, 1251, 9, 70, 5915, 9, 1320, 8, -1, -1), + (1252, 1252, 1252, 1252, 1252, 9, 68, 5913, 9, 1320, 8, -1, -1), + (1253, 1253, 1253, 1253, 1253, 9, 67, 5916, 16, 1320, 8, -1, -1), + (1254, 1254, 1254, 1254, 1254, 9, 69, 5914, 16, 1320, 8, -1, -1), + (1255, 1255, 1255, 1255, 1255, 9, 70, 5918, 4, 1080, 8, -1, -1), + (1265, -1, -1, 820, 820, 5, 66, -1, 0, 0, 8, 822, 1266), + (1266, -1, -1, 820, 820, 5, 68, -1, 0, 0, 8, 1265, 1267), + (1267, -1, -1, 820, 820, 5, 70, -1, 0, 0, 8, 1266, 4813), + (1268, -1, -1, 807, 807, 5, 66, -1, 0, 0, 8, 809, 1269), + (1269, -1, -1, 807, 807, 5, 68, -1, 0, 0, 8, 1268, 1270), + (1270, -1, -1, 807, 807, 5, 70, -1, 0, 0, 8, 1269, 5922), + (1272, 209, 209, 209, 1272, 5, 66, 5919, 12, 5, 8, -1, 6378), + (1274, 1274, 1274, 1274, 1274, 3, 68, 5921, 9, 540, 8, -1, 1275), + (1275, 1274, 1274, 1274, 1274, 6, 69, 5922, 9, 540, 8, 1274, 1276), + (1276, 1274, 1274, 1274, 1274, 9, 70, 5923, 9, 540, 8, 1275, 4864), + (1277, 188, 188, 188, 188, 9, 68, 5924, 2, 30, 8, 188, 5044), + (1278, 534, 534, 534, 534, 5, 67, 5927, 4, 2160, 8, 717, 1279), + (1279, 534, 534, 534, 534, 5, 68, 5928, 4, 2160, 8, 1278, 1280), + (1280, 534, 534, 534, 534, 5, 69, 5929, 4, 2160, 8, 1279, 5041), + (1284, -1, -1, 1284, 1284, 3, 66, -1, 0, 0, 8, -1, 1285), + (1285, -1, -1, 1284, 1284, 6, 68, -1, 0, 0, 8, 1284, 1286), + (1286, -1, -1, 1284, 1284, 9, 70, -1, 0, 0, 8, 1285, 5035), + (1287, -1, -1, 1287, 1287, 3, 67, -1, 0, 0, 8, -1, 1288), + (1288, -1, -1, 1287, 1287, 6, 68, -1, 0, 0, 8, 1287, 1289), + (1289, -1, -1, 1287, 1287, 9, 69, -1, 0, 0, 8, 1288, 5516), + (1290, -1, -1, 864, 864, 3, 66, -1, 0, 0, 8, 866, 1291), + (1291, -1, -1, 864, 864, 6, 68, -1, 0, 0, 8, 1290, 1292), + (1292, -1, -1, 864, 864, 9, 70, -1, 0, 0, 8, 1291, 4983), + (1293, 545, 545, 545, 545, 3, 68, 6079, 3, 900, 8, 547, 1294), + (1294, 545, 545, 545, 545, 6, 69, 6080, 3, 900, 8, 1293, 1295), + (1295, 545, 545, 545, 545, 9, 70, 6081, 3, 900, 8, 1294, 4997), + (1296, -1, -1, 1296, 1296, 3, 66, -1, 0, 0, 8, -1, 1297), + (1297, -1, -1, 1296, 1296, 3, 67, -1, 0, 0, 8, 1296, 1298), + (1298, -1, -1, 1296, 1296, 3, 68, -1, 0, 0, 8, 1297, 1299), + (1299, -1, -1, 1296, 1296, 3, 69, -1, 0, 0, 8, 1298, 1300), + (1300, -1, -1, 1296, 1296, 3, 70, -1, 0, 0, 8, 1299, -1), + (1301, -1, -1, 846, 846, 3, 66, -1, 0, 0, 8, 848, 1302), + (1302, -1, -1, 846, 846, 6, 68, -1, 0, 0, 8, 1301, 1303), + (1303, -1, -1, 846, 846, 9, 70, -1, 0, 0, 8, 1302, 4948), + (1304, -1, -1, 1304, 1304, 3, 66, -1, 0, 0, 8, -1, 1305), + (1305, -1, -1, 1304, 1304, 6, 68, -1, 0, 0, 8, 1304, 1306), + (1306, -1, -1, 1304, 1304, 9, 70, -1, 0, 0, 8, 1305, 6029), + (1307, -1, -1, 1307, 1307, 5, 66, -1, 0, 0, 8, -1, 1308), + (1308, -1, -1, 1307, 1307, 5, 67, -1, 0, 0, 8, 1307, 1309), + (1309, -1, -1, 1307, 1307, 5, 68, -1, 0, 0, 8, 1308, 1310), + (1310, -1, -1, 1307, 1307, 5, 69, -1, 0, 0, 8, 1309, 1311), + (1311, -1, -1, 1307, 1307, 5, 70, -1, 0, 0, 8, 1310, 6660), + (1313, -1, -1, 1313, 1313, 3, 68, -1, 0, 0, 8, -1, 1314), + (1314, -1, -1, 1313, 1313, 6, 69, -1, 0, 0, 8, 1313, 1315), + (1315, -1, -1, 1313, 1313, 9, 70, -1, 0, 0, 8, 1314, 5029), + (1316, -1, -1, 210, 210, 5, 67, -1, 0, 0, 8, 212, 1317), + (1317, -1, -1, 210, 210, 5, 68, -1, 0, 0, 8, 1316, 1318), + (1318, -1, -1, 210, 210, 5, 69, -1, 0, 0, 8, 1317, 6072), + (1319, -1, -1, 634, 634, 5, 67, -1, 0, 0, 8, 845, 1320), + (1320, -1, -1, 634, 634, 5, 68, -1, 0, 0, 8, 1319, 1321), + (1321, -1, -1, 634, 634, 5, 69, -1, 0, 0, 8, 1320, 5032), + (1323, 1323, 1323, 1323, 1323, 12, 70, 5932, 7, 2160, 8, -1, -1), + (1324, 970, 970, 970, 970, 5, 66, 6030, 6, 1800, 8, 974, 1325), + (1325, 970, 970, 970, 970, 5, 68, 6031, 6, 1800, 8, 1324, 1326), + (1326, 970, 970, 970, 970, 5, 70, 6032, 6, 1800, 8, 1325, 17311), + (1327, 1327, 1327, 1327, 1327, 5, 67, 5933, 10, 900, 8, -1, 1328), + (1328, 1327, 1327, 1327, 1327, 5, 68, 5934, 10, 900, 8, 1327, 1329), + (1329, 1327, 1327, 1327, 1327, 5, 69, 5935, 10, 900, 8, 1328, 5314), + (1330, 912, 912, 912, 912, 3, 66, 5936, 4, 3600, 8, 914, 1331), + (1331, 912, 912, 912, 912, 6, 68, 5937, 4, 3600, 8, 1330, 1332), + (1332, 912, 912, 912, 912, 9, 70, 5938, 4, 3600, 8, 1331, 7119), + (1334, 1334, 1334, 1334, 1334, 3, 66, 5943, 11, 4320, 8, -1, 1335), + (1335, 1334, 1334, 1334, 1334, 6, 68, 5944, 11, 4320, 8, 1334, 1336), + (1336, 1334, 1334, 1334, 1334, 9, 70, 5945, 11, 4320, 8, 1335, 6152), + (1337, 1337, 1337, 1337, 1337, 5, 67, 5946, 13, 4320, 8, -1, 1338), + (1338, 1337, 1337, 1337, 1337, 5, 68, 5947, 13, 4320, 8, 1337, 1339), + (1339, 1337, 1337, 1337, 1337, 5, 69, 5948, 13, 4320, 8, 1338, 6158), + (1340, 921, 921, 921, 921, 12, 69, 5950, 8, 60, 8, 921, 5280), + (1341, 922, 922, 922, 922, 12, 68, 5951, 8, 60, 8, 922, 5281), + (1342, 923, 923, 923, 923, 12, 67, 5952, 8, 60, 8, 923, 5282), + (1343, 1343, 1343, 1343, 1343, 9, 69, 5953, 9, 300, 8, -1, -1), + (1344, 155, 155, 155, 155, 12, 70, 5949, 8, 60, 8, 533, 5279), + (1345, 1345, 1345, 1345, 1345, 5, 67, 6132, 6, 900, 8, -1, 1346), + (1346, 1345, 1345, 1345, 1345, 5, 68, 6133, 6, 900, 8, 1345, 1347), + (1347, 1345, 1345, 1345, 1345, 5, 69, 6134, 6, 900, 8, 1346, 5003), + (1348, 1348, 1348, 1348, 1348, 3, 68, 6090, 0, 3600, 8, -1, 1349), + (1349, 1348, 1348, 1348, 1348, 6, 69, 6091, 0, 3600, 8, 1348, 1350), + (1350, 1348, 1348, 1348, 1348, 9, 70, 6092, 0, 3600, 8, 1349, 5770), + (1351, 1351, 1351, 1351, 1351, 5, 67, 5939, 5, 30, 8, -1, 6133), + (1352, 1352, 1352, 1352, 1352, 3, 67, 6067, 3, 60, 8, -1, 1353), + (1353, 1352, 1352, 1352, 1352, 6, 68, 6068, 3, 60, 8, 1352, 1354), + (1354, 1352, 1352, 1352, 1352, 9, 69, 6069, 3, 60, 8, 1353, 6313), + (1355, 1355, 1355, 1355, 1355, 3, 68, 6070, 3, 60, 8, -1, 1356), + (1356, 1355, 1355, 1355, 1355, 6, 69, 6071, 3, 60, 8, 1355, 1357), + (1357, 1355, 1355, 1355, 1355, 9, 70, 6072, 3, 60, 8, 1356, 5240), + (1358, 1358, 1358, 1358, 1358, 3, 66, 6073, 3, 60, 8, -1, 1359), + (1359, 1358, 1358, 1358, 1358, 6, 67, 6074, 3, 60, 8, 1358, 1360), + (1360, 1358, 1358, 1358, 1358, 9, 68, 6075, 3, 60, 8, 1359, 6307), + (1361, -1, -1, 1361, 1361, 0, 65, -1, 0, 0, 3, -1, -1), + (1362, -1, -1, 1362, 1362, 0, 65, -1, 0, 0, 3, -1, -1), + (1363, -1, -1, 1363, 1363, 0, 68, -1, 0, 0, 3, -1, -1), + (1364, -1, -1, 1364, 1364, 0, 68, -1, 0, 0, 3, -1, -1), + (1365, -1, -1, 1365, 1365, 0, 68, -1, 0, 0, 3, -1, -1), + (1366, -1, -1, 1366, 1366, 0, 65, -1, 0, 0, 3, -1, -1), + (1367, -1, -1, 1367, 1367, 0, 65, -1, 0, 0, 3, -1, -1), + (1368, -1, -1, 1368, 1368, 0, 68, -1, 0, 0, 3, -1, -1), + (1369, -1, -1, 1369, 1369, 0, 68, -1, 0, 0, 3, -1, -1), + (1370, -1, -1, 1370, 1370, 0, 68, -1, 0, 0, 3, -1, -1), + (1371, 1371, 1371, 1371, 1371, 0, 1, 6880, 23, 72000, 0, -1, -1), + (1372, 1372, 1372, 1372, 1372, 0, 1, 6881, 24, 72000, 0, -1, -1), + (1373, 1373, 1373, 1373, 1373, 0, 1, 6882, 25, 72000, 0, -1, -1), + (1374, 1374, 1374, 1374, 1374, 0, 1, 6883, 26, 590400, 0, -1, -1), + (1375, 1375, 1375, 1375, 1375, 0, 1, 6884, 27, 72000, 0, -1, -1), + (1376, 1376, 1376, 1376, 1376, 0, 1, 6885, 28, 244800, 0, -1, -1), + (1377, 1377, 1377, 1377, 1377, 0, 1, 6886, 29, 14400, 0, -1, -1), + (1378, -1, -1, 1378, 1378, 0, 1, -1, 0, 0, 10, -1, 1379), + (1379, -1, -1, 1379, 1379, 0, 1, -1, 0, 0, 10, 1378, 1380), + (1380, -1, -1, 1380, 1380, 0, 1, -1, 0, 0, 10, 1379, 1381), + (1382, -1, -1, 1382, 1382, 0, 1, -1, 0, 0, 10, 1381, -1), + (1383, 1383, 1383, 1383, 1383, 3, 59, 8048, 6, 300, 3, -1, 1384), + (1384, 1383, 1383, 1383, 1383, 6, 59, 8049, 6, 300, 3, 1383, 1385), + (1385, 1383, 1383, 1383, 1383, 9, 59, 8050, 6, 300, 3, 1384, 1386), + (1386, 1383, 1383, 1383, 1383, 9, 65, 8052, 6, 300, 4, 1385, 1387), + (1387, 1383, 1383, 1383, 1383, 9, 70, 8053, 6, 300, 10, 1386, 5084), + (1388, -1, -1, 1388, 1388, 9, 70, -1, 0, 0, 10, -1, -1), + (1389, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1030, 1390), + (1390, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1389, 1391), + (1391, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1390, 1392), + (1392, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1391, 1393), + (1393, -1, -1, 1026, 1026, 5, 70, -1, 0, 0, 10, 1392, 4683), + (1394, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1065, 1395), + (1395, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1394, 1396), + (1396, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1395, 1397), + (1397, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1396, 1398), + (1398, -1, -1, 125, 125, 5, 70, -1, 0, 0, 10, 1397, 5519), + (1399, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1070, 1400), + (1400, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1399, 1401), + (1401, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1400, 1402), + (1402, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1401, 1403), + (1403, -1, -1, 122, 122, 5, 70, -1, 0, 0, 10, 1402, 5524), + (1404, 1404, 1404, 1404, 1404, 5, 66, 8054, 15, 2160, 10, -1, 1405), + (1405, 1404, 1404, 1404, 1404, 5, 67, 8055, 15, 2160, 10, 1404, 1406), + (1406, 1404, 1404, 1404, 1404, 5, 68, 8056, 15, 2160, 10, 1405, 1407), + (1407, 1404, 1404, 1404, 1404, 5, 69, 8057, 15, 2160, 10, 1406, 1408), + (1408, 1404, 1404, 1404, 1404, 5, 70, 8058, 15, 2160, 10, 1407, 12880), + (1409, 1409, 1409, 1409, 1409, 5, 66, 8054, 15, 2160, 10, -1, 1410), + (1410, 1409, 1409, 1409, 1409, 5, 67, 8055, 15, 2160, 10, 1409, 1411), + (1411, 1409, 1409, 1409, 1409, 5, 68, 8056, 15, 2160, 10, 1410, 1412), + (1412, 1409, 1409, 1409, 1409, 5, 69, 8057, 15, 2160, 10, 1411, 1413), + (1413, 1409, 1409, 1409, 1409, 5, 70, 8058, 15, 2160, 10, 1412, -1), + (1414, -1, -1, 1414, 1414, 5, 66, -1, 0, 0, 10, -1, 1415), + (1415, -1, -1, 1414, 1414, 5, 67, -1, 0, 0, 10, 1414, 1416), + (1416, -1, -1, 1414, 1414, 5, 68, -1, 0, 0, 10, 1415, 1417), + (1417, -1, -1, 1414, 1414, 5, 69, -1, 0, 0, 10, 1416, 1418), + (1418, -1, -1, 1414, 1414, 5, 70, -1, 0, 0, 10, 1417, 12874), + (1419, 1419, 1419, 1419, 1419, 9, 74, 16441, 52, 300, 15, -1, -1), + (1420, -1, -1, 1420, 1420, 3, 66, -1, 0, 0, 10, -1, 1421), + (1421, -1, -1, 1420, 1420, 3, 67, -1, 0, 0, 10, 1420, 1422), + (1422, -1, -1, 1420, 1420, 3, 68, -1, 0, 0, 10, 1421, 1423), + (1423, -1, -1, 1420, 1420, 3, 69, -1, 0, 0, 10, 1422, 1424), + (1424, -1, -1, 1420, 1420, 3, 70, -1, 0, 0, 10, 1423, -1), + (1425, 1425, 1425, 1425, 1425, 5, 70, 8060, 2, 2160, 10, -1, 1426), + (1426, 1425, 1425, 1425, 1425, 5, 70, 8061, 2, 2160, 10, 1425, 1427), + (1427, 1425, 1425, 1425, 1425, 5, 70, 8063, 2, 2160, 10, 1426, 1428), + (1428, 1425, 1425, 1425, 1425, 5, 70, 8066, 2, 2160, 10, 1427, 1429), + (1429, 1425, 1425, 1425, 1425, 5, 70, 8070, 2, 2160, 10, 1428, 5759), + (1430, -1, -1, 795, 795, 3, 70, -1, 0, 0, 10, 799, 1431), + (1431, -1, -1, 795, 795, 6, 70, -1, 0, 0, 10, 1430, 1432), + (1432, -1, -1, 795, 795, 9, 70, -1, 0, 0, 10, 1431, 4897), + (1435, -1, -1, 1435, 1435, 3, 66, -1, 0, 0, 10, -1, 1436), + (1436, -1, -1, 1435, 1435, 6, 68, -1, 0, 0, 10, 1435, 1437), + (1437, -1, -1, 1435, 1435, 9, 70, -1, 0, 0, 10, 1436, 4773), + (1440, 517, 517, 517, 517, 5, 66, 8109, 12, 600, 10, 519, 1441), + (1441, 517, 517, 517, 517, 5, 67, 8110, 12, 600, 10, 1440, 1442), + (1442, 517, 517, 517, 517, 5, 68, 8111, 12, 600, 10, 1441, 1443), + (1443, 517, 517, 517, 517, 5, 69, 8112, 12, 600, 10, 1442, 1444), + (1444, 517, 517, 517, 517, 5, 70, 8113, 12, 600, 10, 1443, 7296), + (1453, -1, -1, 1453, 1453, 5, 66, -1, 0, 0, 10, -1, 1454), + (1454, -1, -1, 1453, 1453, 5, 67, -1, 0, 0, 10, 1453, 1455), + (1455, -1, -1, 1453, 1453, 5, 68, -1, 0, 0, 10, 1454, 1456), + (1456, -1, -1, 1453, 1453, 5, 69, -1, 0, 0, 10, 1455, 1457), + (1457, -1, -1, 1453, 1453, 5, 70, -1, 0, 0, 10, 1456, -1), + (1458, 1458, 1458, 1458, 1458, 12, 70, 8124, 6, 4320, 10, -1, -1), + (1459, 1459, 1459, 1459, 1459, 7, 70, 8125, 11, 1800, 10, -1, 1460), + (1460, 1459, 1459, 1459, 1459, 7, 70, 8126, 11, 1800, 10, 1459, 1461), + (1461, 1459, 1459, 1459, 1459, 7, 70, 8127, 11, 1800, 10, 1460, 5080), + (1462, 1462, 1462, 1462, 1462, 3, 59, 8133, 5, 300, 3, -1, 1463), + (1463, 1462, 1462, 1462, 1462, 6, 59, 8134, 5, 300, 3, 1462, 1464), + (1464, 1462, 1462, 1462, 1462, 9, 59, 8135, 5, 300, 3, 1463, 1465), + (1465, 1462, 1462, 1462, 1462, 9, 65, 8137, 5, 300, 4, 1464, 1466), + (1466, 1462, 1462, 1462, 1462, 9, 70, 8138, 5, 300, 10, 1465, 4900), + (1467, -1, -1, 729, 729, 3, 70, -1, 0, 0, 10, 733, 1468), + (1468, -1, -1, 729, 729, 6, 70, -1, 0, 0, 10, 1467, 1469), + (1469, -1, -1, 729, 729, 9, 70, -1, 0, 0, 10, 1468, 4960), + (1471, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, -1, 1472), + (1472, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, 1471, 1473), + (1473, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, 1472, 1474), + (1474, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, 1473, 1475), + (1475, -1, -1, 1471, 1471, 5, 70, -1, 0, 0, 10, 1474, 6442), + (1477, 1477, 1477, 1477, 1477, 9, 70, 8149, 3, 4320, 10, -1, -1), + (1478, 1478, -1, 1478, 1478, 3, 66, 8406, 0, 1, 10, -1, 1479), + (1479, 1478, -1, 1478, 1478, 6, 68, 8407, 0, 1, 10, 1478, 1480), + (1480, 1478, -1, 1478, 1478, 9, 70, 8408, 0, 1, 10, 1479, 6161), + (1483, -1, -1, 1210, 1210, 7, 70, -1, 0, 0, 10, 1212, 1484), + (1484, -1, -1, 1210, 1210, 7, 70, -1, 0, 0, 10, 1483, 1485), + (1485, -1, -1, 1210, 1210, 7, 70, -1, 0, 0, 10, 1484, 4752), + (1486, -1, -1, 1486, 1486, 5, 66, -1, 0, 0, 10, -1, 1487), + (1487, -1, -1, 1486, 1486, 5, 67, -1, 0, 0, 10, 1486, 1488), + (1488, -1, -1, 1486, 1486, 5, 68, -1, 0, 0, 10, 1487, 1489), + (1489, -1, -1, 1486, 1486, 5, 69, -1, 0, 0, 10, 1488, 1490), + (1490, -1, -1, 1486, 1486, 5, 70, -1, 0, 0, 10, 1489, 5529), + (1491, 746, 746, 746, 746, 3, 70, 8156, 10, 2160, 10, 748, 1492), + (1492, 746, 746, 746, 746, 6, 70, 8157, 10, 2160, 10, 1491, 1493), + (1493, 746, 746, 746, 746, 9, 70, 8158, 10, 2160, 10, 1492, 5800), + (1494, 1494, 1494, 1494, 1494, 12, 70, 8170, 2, 7, 10, -1, -1), + (1495, 1495, 1495, 1495, 1495, 3, 70, 8190, 30, 900, 10, -1, 1496), + (1496, 1495, 1495, 1495, 1495, 6, 70, 8191, 30, 900, 10, 1495, 1497), + (1497, 1495, 1495, 1495, 1495, 9, 70, 8192, 30, 900, 10, 1496, 5311), + (1498, 1498, 1498, 1498, 1498, 3, 70, 8193, 12, 1320, 10, -1, 1499), + (1499, 1498, 1498, 1498, 1498, 6, 70, 8194, 12, 1320, 10, 1498, 1500), + (1500, 1498, 1498, 1498, 1498, 9, 70, 8195, 12, 1320, 10, 1499, 5058), + (1501, 1501, 1501, 1501, 1501, 3, 70, 8196, 10, 4320, 10, -1, 1502), + (1502, 1501, 1501, 1501, 1501, 6, 70, 8197, 10, 4320, 10, 1501, 1503), + (1503, 1501, 1501, 1501, 1501, 9, 70, 8198, 10, 4320, 10, 1502, 1558), + (1504, -1, -1, 1504, 1504, 5, 70, -1, 0, 0, 10, -1, 1505), + (1505, -1, -1, 1504, 1504, 5, 70, -1, 0, 0, 10, 1504, 1506), + (1506, -1, -1, 1504, 1504, 5, 70, -1, 0, 0, 10, 1505, 5880), + (1507, 520, 520, 520, 520, 3, 70, 8201, 6, 540, 10, 522, 1508), + (1508, 520, 520, 520, 520, 6, 70, 8202, 6, 540, 10, 1507, 1509), + (1509, 520, 520, 520, 520, 9, 70, 8203, 6, 540, 10, 1508, 5883), + (1510, 1510, -1, 1510, 1510, 12, 70, 8205, 13, 2160, 10, -1, 7202), + (1511, -1, -1, 1511, 1511, 5, 70, -1, 0, 0, 10, -1, 1512), + (1512, -1, -1, 1511, 1511, 5, 70, -1, 0, 0, 10, 1511, 1513), + (1513, -1, -1, 1511, 1511, 5, 70, -1, 0, 0, 10, 1512, 5950), + (1514, -1, -1, 1514, 1514, 7, 70, -1, 0, 0, 10, -1, 1515), + (1515, -1, -1, 1514, 1514, 7, 70, -1, 0, 0, 10, 1514, 1516), + (1516, -1, -1, 1514, 1514, 7, 70, -1, 0, 0, 10, 1515, 13404), + (1519, 153, 153, 153, 153, 9, 70, 8216, 3, 2160, 10, 153, 5068), + (1520, 1520, 1520, 1520, 1520, 3, 70, 8218, 11, 900, 10, -1, 1521), + (1521, 1520, 1520, 1520, 1520, 6, 70, 8219, 11, 900, 10, 1520, 1522), + (1522, 1520, 1520, 1520, 1520, 9, 70, 8220, 11, 900, 10, 1521, 6449), + (1523, 1523, 1523, 1523, 1523, 12, 70, 8221, 7, 7, 10, -1, -1), + (1524, -1, -1, 190, 190, 7, 70, -1, 0, 0, 10, 192, 1526), + (1525, -1, -1, 190, 190, 7, 70, -1, 0, 0, 10, 1526, 5038), + (1526, -1, -1, 190, 190, 7, 70, -1, 0, 0, 10, 1524, 1525), + (1527, 1527, 1527, 1527, 1527, 12, 70, 8223, 3, 7, 10, -1, -1), + (1528, -1, -1, 1528, 4819, 5, 66, -1, 0, 0, 10, -1, 1529), + (1529, -1, -1, 1528, 4819, 5, 67, -1, 0, 0, 10, 1528, 1530), + (1530, -1, -1, 1528, 4819, 5, 68, -1, 0, 0, 10, 1529, 1531), + (1531, -1, -1, 1528, 4819, 5, 69, -1, 0, 0, 10, 1530, 1532), + (1532, -1, -1, 1528, 4819, 5, 70, -1, 0, 0, 10, 1531, 4819), + (1533, -1, -1, 602, 602, 3, 70, -1, 0, 0, 10, 604, 1534), + (1534, -1, -1, 602, 602, 6, 70, -1, 0, 0, 10, 1533, 1535), + (1535, -1, -1, 602, 602, 9, 70, -1, 0, 0, 10, 1534, 4758), + (1536, -1, -1, 599, 599, 3, 70, -1, 0, 0, 10, 601, 1537), + (1537, -1, -1, 599, 599, 6, 70, -1, 0, 0, 10, 1536, 1538), + (1538, -1, -1, 599, 599, 9, 70, -1, 0, 0, 10, 1537, 5534), + (1539, -1, -1, 878, 878, 7, 70, -1, 0, 0, 10, 880, 1540), + (1540, -1, -1, 878, 878, 7, 70, -1, 0, 0, 10, 1539, 1541), + (1541, -1, -1, 878, 878, 7, 70, -1, 0, 0, 10, 1540, 4957), + (1542, 1542, -1, 1542, 1542, 3, 60, 8240, 0, 1, 10, -1, -1), + (1543, -1, -1, 1543, 1543, 5, 70, -1, 0, 0, 10, -1, 1544), + (1544, -1, -1, 1543, 1543, 5, 70, -1, 0, 0, 10, 1543, 1545), + (1545, -1, -1, 1543, 1543, 5, 70, -1, 0, 0, 10, 1544, 4951), + (1546, -1, -1, 1546, 1546, 5, 70, -1, 0, 0, 10, -1, 1547), + (1547, -1, -1, 1546, 1546, 5, 70, -1, 0, 0, 10, 1546, 1548), + (1548, -1, -1, 1546, 1546, 5, 70, -1, 0, 0, 10, 1547, 4829), + (1549, -1, -1, 1549, 1549, 3, 66, -1, 0, 0, 10, -1, 1550), + (1550, -1, -1, 1549, 1549, 6, 68, -1, 0, 0, 10, 1549, 1551), + (1551, -1, -1, 1549, 1549, 9, 70, -1, 0, 0, 10, 1550, -1), + (1552, -1, -1, 1552, 1552, 3, 66, -1, 0, 0, 10, -1, 1553), + (1553, -1, -1, 1552, 1552, 6, 68, -1, 0, 0, 10, 1552, 1554), + (1554, -1, -1, 1552, 1552, 9, 70, -1, 0, 0, 10, 1553, -1), + (1555, -1, -1, 1555, 1555, 5, 70, -1, 0, 0, 10, -1, 1556), + (1556, -1, -1, 1555, 1555, 5, 70, -1, 0, 0, 10, 1555, 1557), + (1557, -1, -1, 1555, 1555, 5, 70, -1, 0, 0, 10, 1556, 12727), + (1558, 1501, 1501, 1501, 1501, 6, 75, 16444, 10, 4320, 15, 1503, 1559), + (1559, 1501, 1501, 1501, 1501, 6, 80, 16445, 10, 4320, 15, 1558, 1560), + (1560, 1501, 1501, 1501, 1501, 6, 85, 16446, 10, 4320, 15, 1559, 13244), + (1563, -1, -1, 556, 556, 5, 66, -1, 0, 0, 10, 560, 1564), + (1564, -1, -1, 556, 556, 5, 67, -1, 0, 0, 10, 1563, 1565), + (1565, -1, -1, 556, 556, 5, 68, -1, 0, 0, 10, 1564, 1566), + (1566, -1, -1, 556, 556, 5, 69, -1, 0, 0, 10, 1565, 1567), + (1567, -1, -1, 556, 556, 5, 70, -1, 0, 0, 10, 1566, 17004), + (1569, 1569, 1569, 1569, 1569, 3, 70, 8256, 5, 1800, 10, -1, 1570), + (1570, 1569, 1569, 1569, 1569, 6, 70, 8257, 5, 1800, 10, 1569, 1571), + (1571, 1569, 1569, 1569, 1569, 9, 70, 8258, 5, 1800, 10, 1570, 5713), + (1572, -1, -1, 1572, 1572, 5, 66, -1, 0, 0, 10, -1, 1573), + (1573, -1, -1, 1572, 1572, 5, 67, -1, 0, 0, 10, 1572, 1574), + (1574, -1, -1, 1572, 1572, 5, 68, -1, 0, 0, 10, 1573, 1575), + (1575, -1, -1, 1572, 1572, 5, 69, -1, 0, 0, 10, 1574, 1576), + (1576, -1, -1, 1572, 1572, 5, 70, -1, 0, 0, 10, 1575, 10554), + (1577, -1, -1, 1577, 1577, 3, 66, -1, 0, 0, 10, -1, 1578), + (1578, -1, -1, 1577, 1577, 6, 68, -1, 0, 0, 10, 1577, 1579), + (1579, -1, -1, 1577, 1577, 9, 70, -1, 0, 0, 10, 1578, 5886), + (1583, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, -1, 1584), + (1584, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, 1583, 1585), + (1585, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, 1584, 1586), + (1586, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, 1585, 1587), + (1587, -1, -1, 1583, 1583, 5, 70, -1, 0, 0, 10, 1586, -1), + (1588, -1, -1, 1587, 1587, 3, 66, -1, 0, 0, 10, -1, 1589), + (1589, -1, -1, 1587, 1587, 6, 68, -1, 0, 0, 10, 1588, 1590), + (1590, -1, -1, 1587, 1587, 9, 70, -1, 0, 0, 10, 1589, -1), + (1591, -1, -1, 1586, 1586, 12, 70, -1, 0, 0, 10, -1, -1), + (1592, -1, -1, 1592, 1592, 5, 66, -1, 0, 0, 10, -1, 1593), + (1593, -1, -1, 1592, 1592, 5, 67, -1, 0, 0, 10, 1592, 1594), + (1594, -1, -1, 1592, 1592, 5, 68, -1, 0, 0, 10, 1593, 1595), + (1595, -1, -1, 1592, 1592, 5, 69, -1, 0, 0, 10, 1594, 1596), + (1596, -1, -1, 1592, 1592, 5, 70, -1, 0, 0, 10, 1595, 4725), + (1597, 1597, 1597, 1597, 1597, 9, 70, 8271, 6, 10, 10, -1, 6606), + (1598, 1598, -1, 1598, 1598, 3, 70, 8272, 6, 900, 10, -1, 1599), + (1599, 1598, -1, 1598, 1598, 6, 70, 8273, 6, 900, 10, 1598, 1600), + (1600, 1598, -1, 1598, 1598, 9, 70, 8274, 6, 900, 10, 1599, 4972), + (1601, -1, -1, 644, 644, 5, 61, -1, 0, 0, 10, 644, 1602), + (1602, -1, -1, 644, 644, 5, 63, -1, 0, 0, 10, 1601, 1603), + (1603, -1, -1, 644, 644, 5, 65, -1, 0, 0, 10, 1602, 4986), + (1604, -1, -1, 1604, 1604, 5, 60, -1, 0, 0, 10, -1, 1605), + (1605, -1, -1, 1604, 1604, 5, 61, -1, 0, 0, 10, 1604, 1606), + (1606, -1, -1, 1604, 1604, 5, 62, -1, 0, 0, 10, 1605, 5290), + (1607, 289, 289, 289, 289, 9, 70, 8278, 3, 300, 10, 289, 5742), + (1608, -1, -1, 1608, 1608, 3, 66, -1, 0, 0, 10, -1, 1609), + (1609, -1, -1, 1608, 1608, 6, 68, -1, 0, 0, 10, 1608, 1610), + (1610, -1, -1, 1608, 1608, 9, 70, -1, 0, 0, 10, 1609, 4989), + (1611, -1, -1, 1417, 1417, 3, 66, -1, 0, 0, 10, -1, 1612), + (1612, -1, -1, 1417, 1417, 3, 67, -1, 0, 0, 10, 1611, 1613), + (1613, -1, -1, 1417, 1417, 3, 68, -1, 0, 0, 10, 1612, 1614), + (1614, -1, -1, 1417, 1417, 3, 69, -1, 0, 0, 10, 1613, 1615), + (1615, -1, -1, 1417, 1417, 3, 70, -1, 0, 0, 10, 1614, -1), + (1616, -1, -1, 1616, 1616, 5, 66, -1, 0, 0, 10, -1, 1617), + (1617, -1, -1, 1616, 1616, 5, 67, -1, 0, 0, 10, 1616, 1618), + (1618, -1, -1, 1616, 1616, 5, 68, -1, 0, 0, 10, 1617, 1619), + (1619, -1, -1, 1616, 1616, 5, 69, -1, 0, 0, 10, 1618, 1620), + (1620, -1, -1, 1616, 1616, 5, 70, -1, 0, 0, 10, 1619, 4992), + (1621, -1, -1, 564, 564, 7, 70, -1, 0, 0, 10, 566, 1622), + (1622, -1, -1, 564, 564, 7, 70, -1, 0, 0, 10, 1621, 1623), + (1623, -1, -1, 564, 564, 7, 70, -1, 0, 0, 10, 1622, -1), + (1624, -1, -1, 561, 561, 7, 70, -1, 0, 0, 10, 563, 1625), + (1625, -1, -1, 561, 561, 7, 70, -1, 0, 0, 10, 1624, 1626), + (1626, -1, -1, 561, 561, 7, 70, -1, 0, 0, 10, 1625, -1), + (1627, -1, -1, 1627, 1627, 3, 66, -1, 0, 0, 10, -1, 1628), + (1628, -1, -1, 1627, 1627, 6, 68, -1, 0, 0, 10, 1627, 1629), + (1629, -1, -1, 1627, 1627, 9, 70, -1, 0, 0, 10, 1628, -1), + (1630, 1474, 1474, 1474, 1474, 3, 70, 8146, 14, 300, 10, -1, 1631), + (1631, 1474, 1474, 1474, 1474, 6, 70, 8147, 14, 300, 10, 1630, 1632), + (1632, 1474, 1474, 1474, 1474, 9, 70, 8148, 14, 300, 10, 1631, -1), + (1633, -1, -1, 551, 551, 5, 66, -1, 0, 0, 10, 555, 1634), + (1634, -1, -1, 551, 551, 5, 67, -1, 0, 0, 10, 1633, 1635), + (1635, -1, -1, 551, 551, 5, 68, -1, 0, 0, 10, 1634, 1636), + (1636, -1, -1, 551, 551, 5, 69, -1, 0, 0, 10, 1635, 1637), + (1637, -1, -1, 551, 551, 5, 70, -1, 0, 0, 10, 1636, 6905), + (1638, 1638, 1638, 1638, 1638, 5, 59, 8450, 7, 4320, 3, -1, -1), + (1639, 1639, 1639, 1639, 1639, 9, 65, 8451, 7, 4320, 4, -1, -1), + (1640, 1640, 1640, 1640, 1640, 12, 70, 8452, 7, 4320, 10, -1, -1), + (1641, -1, -1, 1641, 1641, 15, 70, -1, 0, 0, 3, -1, -1), + (1642, -1, -1, 1642, 1642, 15, 70, -1, 0, 0, 3, -1, -1), + (1643, 1643, 1643, 1643, 1643, 0, 59, 8975, 0, 1, 11, -1, -1), + (1644, 1644, 1644, 1644, 1644, 0, 59, 8900, 0, 1, 11, -1, -1), + (1645, 1645, 1645, 1645, 1645, 9, 70, 8977, 0, 1, 3, -1, -1), + (1646, 1646, 1646, 1646, 1646, 9, 70, 8978, 0, 1, 3, -1, -1), + (1647, 1647, 1647, 1647, 1647, 0, 68, 8771, 21, 900, 3, -1, -1), + (1648, -1, -1, 1435, 4773, 9, 71, -1, 0, 0, 16, 1221, 1649), + (1649, -1, -1, 1435, 4773, 9, 76, -1, 0, 0, 16, 1648, 1650), + (1650, -1, -1, 1435, 4773, 9, 81, -1, 0, 0, 16, 1649, 13091), + (1651, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 8214, 1652), + (1652, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 1651, 1653), + (1653, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 1652, 1654), + (1654, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 1653, 1655), + (1655, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 16, 1654, 13149), + (1656, -1, -1, 8204, 8204, 4, 85, -1, 0, 0, 16, 8206, 1657), + (1657, -1, -1, 8204, 8204, 4, 85, -1, 0, 0, 16, 1656, -1), + (1659, -1, -1, 8207, 8207, 4, 85, -1, 0, 0, 16, 8209, 1660), + (1660, -1, -1, 8207, 8207, 4, 85, -1, 0, 0, 16, 1659, -1), + (1662, -1, -1, 1662, 1662, 3, 65, -1, 0, 0, 17, -1, 1663), + (1663, -1, -1, 1662, 1662, 3, 66, -1, 0, 0, 17, 1662, 1664), + (1664, -1, -1, 1662, 1662, 3, 67, -1, 0, 0, 17, 1663, 1665), + (1665, -1, -1, 1662, 1662, 3, 68, -1, 0, 0, 17, 1664, 1666), + (1666, -1, -1, 1662, 1662, 3, 69, -1, 0, 0, 17, 1665, -1), + (1667, 1667, 1667, 1667, 1667, 9, 85, 23602, 0, 1, 16, -1, -1), + (2400, -1, -1, 2400, 2400, 9, 81, 0, 0, 0, 17, -1, 2401), + (2401, -1, -1, 2400, 2400, 12, 83, 0, 0, 0, 17, 2400, 2402), + (2402, -1, -1, 2400, 2400, 15, 85, 0, 0, 0, 17, 2401, 15344), + (3676, 3676, 3676, 3676, 3676, 9, 85, 23606, 67, 30, 16, -1, -1), + (4665, 4665, 4665, 4665, 4665, 0, 1, 9177, 19, 4320, 0, -1, -1), + (4666, -1, -1, 4844, 4844, 5, 81, -1, 0, 0, 16, -1, 4667), + (4667, -1, -1, 4844, 4844, 5, 82, -1, 0, 0, 16, 4666, 4668), + (4668, -1, -1, 4844, 4844, 5, 83, -1, 0, 0, 16, 4667, 4669), + (4669, -1, -1, 4844, 4844, 5, 84, -1, 0, 0, 16, 4668, 4670), + (4670, -1, -1, 4844, 4844, 5, 85, -1, 0, 0, 16, 4669, -1), + (4672, -1, -1, 4672, 4672, 3, 59, -1, 0, 0, 8, -1, 4673), + (4673, -1, -1, 4672, 4672, 6, 59, -1, 0, 0, 8, 4672, 4674), + (4674, -1, -1, 4672, 4672, 9, 59, -1, 0, 0, 8, 4673, -1), + (4675, -1, -1, 4675, 4675, 3, 59, -1, 0, 0, 3, -1, 4676), + (4676, -1, -1, 4675, 4675, 6, 59, -1, 0, 0, 3, 4675, 4677), + (4677, -1, -1, 4675, 4675, 9, 59, -1, 0, 0, 3, 4676, -1), + (4678, -1, -1, 418, 418, 5, 71, -1, 0, 0, 12, 1005, 4679), + (4679, -1, -1, 418, 418, 5, 72, -1, 0, 0, 12, 4678, 4680), + (4680, -1, -1, 418, 418, 5, 73, -1, 0, 0, 12, 4679, 4681), + (4681, -1, -1, 418, 418, 5, 74, -1, 0, 0, 12, 4680, 4682), + (4682, -1, -1, 418, 418, 5, 75, -1, 0, 0, 12, 4681, 7547), + (4683, -1, -1, 1026, 1026, 5, 71, -1, 0, 0, 12, 1393, 4684), + (4684, -1, -1, 1026, 1026, 5, 72, -1, 0, 0, 12, 4683, 4685), + (4685, -1, -1, 1026, 1026, 5, 73, -1, 0, 0, 12, 4684, 4686), + (4686, -1, -1, 1026, 1026, 5, 74, -1, 0, 0, 12, 4685, 4687), + (4687, -1, -1, 1026, 1026, 5, 75, -1, 0, 0, 12, 4686, 6523), + (4688, -1, -1, 4688, 4688, 3, 71, -1, 0, 0, 12, -1, 4689), + (4689, -1, -1, 4688, 4688, 3, 72, -1, 0, 0, 12, 4688, 4690), + (4690, -1, -1, 4688, 4688, 3, 73, -1, 0, 0, 12, 4689, 4691), + (4691, -1, -1, 4688, 4688, 3, 74, -1, 0, 0, 12, 4690, 4692), + (4692, -1, -1, 4688, 4688, 3, 75, -1, 0, 0, 12, 4691, -1), + (4693, -1, -1, 65, 661, 3, 71, -1, 0, 0, 12, 1035, 4694), + (4694, -1, -1, 65, 661, 3, 72, -1, 0, 0, 12, 4693, 4695), + (4695, -1, -1, 65, 661, 3, 73, -1, 0, 0, 12, 4694, 4696), + (4696, -1, -1, 65, 661, 3, 74, -1, 0, 0, 12, 4695, 4697), + (4697, -1, -1, 65, 661, 3, 75, -1, 0, 0, 12, 4696, 6390), + (4698, -1, -1, 4698, 4698, 5, 51, -1, 0, 0, 12, -1, 6545), + (4699, -1, -1, 4699, 4699, 5, 51, -1, 0, 0, 12, -1, 6540), + (4700, 1037, 1037, 1037, 1037, 0, 1, 7619, 33, 72000, 0, -1, -1), + (4702, 4702, 4702, 4702, 4702, 3, 71, 9475, 31, 600, 12, -1, -1), + (4704, 4704, 4704, 4704, 4704, 4, 71, 9477, 31, 600, 12, -1, -1), + (4705, 4705, 4705, 4705, 4705, 3, 71, 9478, 31, 600, 12, -1, -1), + (4706, 4706, 4706, 4706, 4706, 3, 71, 9479, 31, 600, 12, -1, -1), + (4707, -1, -1, 1041, 1041, 6, 71, -1, 0, 0, 12, 1043, 4708), + (4708, -1, -1, 1041, 1041, 6, 73, -1, 0, 0, 12, 4707, 4709), + (4709, -1, -1, 1041, 1041, 6, 75, -1, 0, 0, 12, 4708, 5542), + (4710, -1, -1, 1044, 1044, 6, 71, -1, 0, 0, 12, 1046, 4711), + (4711, -1, -1, 1044, 1044, 6, 73, -1, 0, 0, 12, 4710, 4712), + (4712, -1, -1, 1044, 1044, 6, 75, -1, 0, 0, 12, 4711, 5545), + (4713, -1, -1, 1047, 1047, 6, 71, -1, 0, 0, 12, 1049, 4714), + (4714, -1, -1, 1047, 1047, 6, 73, -1, 0, 0, 12, 4713, 4715), + (4715, -1, -1, 1047, 1047, 6, 75, -1, 0, 0, 12, 4714, 5548), + (4716, -1, -1, 1050, 1050, 6, 71, -1, 0, 0, 12, 1052, 4717), + (4717, -1, -1, 1050, 1050, 6, 73, -1, 0, 0, 12, 4716, 4718), + (4718, -1, -1, 1050, 1050, 6, 75, -1, 0, 0, 12, 4717, 5551), + (4722, -1, -1, 119, 119, 3, 71, -1, 0, 0, 12, 1055, 4723), + (4723, -1, -1, 119, 119, 3, 73, -1, 0, 0, 12, 4722, 4724), + (4724, -1, -1, 119, 119, 3, 75, -1, 0, 0, 12, 4723, 5554), + (4725, -1, -1, 1592, 1592, 5, 71, -1, 0, 0, 12, 1596, 4726), + (4726, -1, -1, 1592, 1592, 5, 72, -1, 0, 0, 12, 4725, 4727), + (4727, -1, -1, 1592, 1592, 5, 73, -1, 0, 0, 12, 4726, 4728), + (4728, -1, -1, 1592, 1592, 5, 74, -1, 0, 0, 12, 4727, 4729), + (4729, -1, -1, 1592, 1592, 5, 75, -1, 0, 0, 12, 4728, 5557), + (4733, -1, -1, 625, 625, 3, 71, -1, 0, 0, 12, 627, 4734), + (4734, -1, -1, 625, 625, 3, 73, -1, 0, 0, 12, 4733, 4735), + (4735, -1, -1, 625, 625, 3, 75, -1, 0, 0, 12, 4734, 7641), + (4739, -1, -1, 4739, 4739, 3, 71, -1, 0, 0, 12, -1, 4740), + (4740, -1, -1, 4739, 4739, 6, 73, -1, 0, 0, 12, 4739, 4741), + (4741, -1, -1, 4739, 4739, 9, 75, -1, 0, 0, 12, 4740, 5562), + (4742, 4742, 4742, 4742, 4742, 9, 71, 11024, 12, 600, 12, -1, 5565), + (4744, -1, -1, 1072, 1072, 5, 71, -1, 0, 0, 12, 1076, 4745), + (4745, -1, -1, 1072, 1072, 5, 72, -1, 0, 0, 12, 4744, 4746), + (4746, -1, -1, 1072, 1072, 5, 73, -1, 0, 0, 12, 4745, 4747), + (4747, -1, -1, 1072, 1072, 5, 74, -1, 0, 0, 12, 4746, 4748), + (4748, -1, -1, 1072, 1072, 5, 75, -1, 0, 0, 12, 4747, 5566), + (4749, -1, -1, 637, 637, 6, 71, -1, 0, 0, 12, 772, 4750), + (4750, -1, -1, 637, 637, 6, 73, -1, 0, 0, 12, 4749, 4751), + (4751, -1, -1, 637, 637, 6, 75, -1, 0, 0, 12, 4750, 5571), + (4752, -1, -1, 1210, 1210, 7, 71, -1, 0, 0, 12, 1485, 4753), + (4753, -1, -1, 1210, 1210, 7, 73, -1, 0, 0, 12, 4752, 4754), + (4754, -1, -1, 1210, 1210, 7, 75, -1, 0, 0, 12, 4753, 5574), + (4755, -1, -1, 1210, 1213, 6, 71, -1, 0, 0, 12, 1215, 4756), + (4756, -1, -1, 1210, 1213, 6, 73, -1, 0, 0, 12, 4755, 4757), + (4757, -1, -1, 1210, 1213, 6, 75, -1, 0, 0, 12, 4756, 5577), + (4758, -1, -1, 602, 602, 6, 71, -1, 0, 0, 12, 1535, 4759), + (4759, -1, -1, 602, 602, 6, 73, -1, 0, 0, 12, 4758, 4760), + (4760, -1, -1, 602, 602, 6, 75, -1, 0, 0, 12, 4759, 5580), + (4761, -1, -1, 4761, 4761, 7, 71, -1, 0, 0, 12, -1, 4762), + (4762, -1, -1, 4761, 4761, 7, 73, -1, 0, 0, 12, 4761, 4763), + (4763, -1, -1, 4761, 4761, 7, 75, -1, 0, 0, 12, 4762, 6500), + (4764, -1, -1, 1071, 1071, 6, 75, -1, 0, 0, 14, 1071, 7553), + (4767, -1, -1, 98, 98, 4, 71, -1, 0, 0, 12, 100, 4768), + (4768, -1, -1, 98, 98, 4, 73, -1, 0, 0, 12, 4767, 4769), + (4769, -1, -1, 98, 98, 4, 75, -1, 0, 0, 12, 4768, 5586), + (4773, -1, -1, 1435, 4773, 9, 71, -1, 0, 0, 12, 1437, 6517), + (4776, -1, -1, 1186, 1186, 6, 71, -1, 0, 0, 12, 1188, 4777), + (4777, -1, -1, 1186, 1186, 6, 73, -1, 0, 0, 12, 4776, 4778), + (4778, -1, -1, 1186, 1186, 6, 75, -1, 0, 0, 12, 4777, 5589), + (4779, -1, -1, 80, 80, 6, 71, -1, 0, 0, 12, 1088, 4780), + (4780, -1, -1, 80, 80, 6, 73, -1, 0, 0, 12, 4779, 4781), + (4781, -1, -1, 80, 80, 6, 75, -1, 0, 0, 12, 4780, 5592), + (4790, -1, -1, 1134, 1134, 5, 71, -1, 0, 0, 12, 1162, 4791), + (4791, -1, -1, 1134, 1134, 5, 72, -1, 0, 0, 12, 4790, 4792), + (4792, -1, -1, 1134, 1134, 5, 73, -1, 0, 0, 12, 4791, 4793), + (4793, -1, -1, 1134, 1134, 5, 74, -1, 0, 0, 12, 4792, 4794), + (4794, -1, -1, 1134, 1134, 5, 75, -1, 0, 0, 12, 4793, 4804), + (4795, -1, -1, 255, 255, 5, 71, -1, 0, 0, 12, 1165, 4796), + (4796, -1, -1, 255, 255, 5, 73, -1, 0, 0, 12, 4795, 4797), + (4797, -1, -1, 255, 255, 5, 75, -1, 0, 0, 12, 4796, 5595), + (4798, -1, -1, 631, 631, 5, 71, -1, 0, 0, 12, 1174, 4799), + (4799, -1, -1, 631, 631, 5, 73, -1, 0, 0, 12, 4798, 4800), + (4800, -1, -1, 631, 631, 5, 75, -1, 0, 0, 12, 4799, -1), + (4801, -1, -1, 4801, 4801, 6, 74, -1, 0, 0, 14, -1, 4802), + (4802, -1, -1, 4801, 4801, 6, 76, -1, 0, 0, 14, 4801, 4803), + (4803, -1, -1, 4801, 4801, 6, 78, -1, 0, 0, 14, 4802, 7160), + (4804, -1, -1, 1134, 1134, 5, 76, -1, 0, 0, 15, 4794, 4805), + (4805, -1, -1, 1134, 1134, 5, 77, -1, 0, 0, 15, 4804, 4806), + (4806, -1, -1, 1134, 1134, 5, 78, -1, 0, 0, 15, 4805, 4807), + (4807, -1, -1, 1134, 1134, 5, 79, -1, 0, 0, 15, 4806, 4808), + (4808, -1, -1, 1134, 1134, 5, 80, -1, 0, 0, 15, 4807, 10311), + (4809, -1, -1, 4809, 4809, 5, 81, -1, 0, 0, 15, -1, 4810), + (4810, -1, -1, 4809, 4809, 5, 83, -1, 0, 0, 15, 4809, 4811), + (4811, -1, -1, 4809, 4809, 5, 85, -1, 0, 0, 15, 4810, 10316), + (4813, -1, -1, 820, 820, 5, 71, -1, 0, 0, 12, 1267, 4814), + (4814, -1, -1, 820, 820, 5, 73, -1, 0, 0, 12, 4813, 4815), + (4815, -1, -1, 820, 820, 5, 75, -1, 0, 0, 12, 4814, 5917), + (4819, -1, -1, 1528, 4819, 5, 71, -1, 0, 0, 12, 1532, 4820), + (4820, -1, -1, 1528, 4819, 5, 72, -1, 0, 0, 12, 4819, 4821), + (4821, -1, -1, 1528, 4819, 5, 73, -1, 0, 0, 12, 4820, 4822), + (4822, -1, -1, 1528, 4819, 5, 74, -1, 0, 0, 12, 4821, 4823), + (4823, -1, -1, 1528, 4819, 5, 75, -1, 0, 0, 12, 4822, 15188), + (4824, -1, -1, 810, 810, 5, 71, -1, 0, 0, 12, 814, 4825), + (4825, -1, -1, 810, 810, 5, 72, -1, 0, 0, 12, 4824, 4826), + (4826, -1, -1, 810, 810, 5, 73, -1, 0, 0, 12, 4825, 4827), + (4827, -1, -1, 810, 810, 5, 74, -1, 0, 0, 12, 4826, 4828), + (4828, -1, -1, 810, 810, 5, 75, -1, 0, 0, 12, 4827, 15426), + (4829, -1, -1, 1546, 1546, 5, 71, -1, 0, 0, 12, 1548, 4830), + (4830, -1, -1, 1546, 1546, 5, 72, -1, 0, 0, 12, 4829, 4831), + (4831, -1, -1, 1546, 1546, 5, 73, -1, 0, 0, 12, 4830, 6441), + (4836, 4836, 4836, 4836, 4836, 5, 71, 11033, 5, 30, 12, -1, -1), + (4844, -1, -1, 4844, 4844, 5, 71, -1, 0, 0, 12, -1, 4845), + (4845, -1, -1, 4844, 4844, 5, 72, -1, 0, 0, 12, 4844, 4846), + (4846, -1, -1, 4844, 4844, 5, 73, -1, 0, 0, 12, 4845, 4847), + (4847, -1, -1, 4844, 4844, 5, 74, -1, 0, 0, 12, 4846, 4848), + (4848, -1, -1, 4844, 4844, 5, 75, -1, 0, 0, 12, 4847, 7122), + (4849, 4849, 4849, 4849, 4849, 9, 71, 11041, 7, 1800, 12, -1, 6134), + (4854, 4854, 4854, 4854, 4854, 3, 71, 11046, 8, 600, 12, -1, 4855), + (4855, 4854, 4854, 4854, 4854, 6, 73, 11047, 8, 600, 12, 4854, 4856), + (4856, 4854, 4854, 4854, 4854, 9, 75, 11048, 8, 600, 12, 4855, 5764), + (4857, 4857, 4857, 4857, 4857, 3, 71, 11049, 7, 600, 12, -1, 4858), + (4858, 4857, 4857, 4857, 4857, 6, 73, 11050, 7, 600, 12, 4857, 4859), + (4859, 4857, 4857, 4857, 4857, 9, 75, 11051, 7, 600, 12, 4858, 5767), + (4860, 4860, 4860, 4860, 4860, 9, 75, 11052, 13, 60, 12, -1, 5606), + (4861, -1, -1, 4861, 4861, 6, 71, -1, 0, 0, 12, -1, 4862), + (4862, -1, -1, 4861, 4861, 6, 73, -1, 0, 0, 12, 4861, 4863), + (4863, -1, -1, 4861, 4861, 6, 75, -1, 0, 0, 12, 4862, 5954), + (4864, 1274, 1274, 1274, 1274, 6, 73, 11053, 9, 540, 12, 1276, 4865), + (4865, 1274, 1274, 1274, 1274, 6, 74, 11054, 9, 540, 12, 4864, 4866), + (4866, 1274, 1274, 1274, 1274, 6, 75, 11055, 9, 540, 12, 4865, 5947), + (4887, -1, -1, 4887, 4887, 6, 71, -1, 0, 0, 12, -1, 4888), + (4888, -1, -1, 4887, 4887, 6, 73, -1, 0, 0, 12, 4887, 4889), + (4889, -1, -1, 4887, 4887, 6, 75, -1, 0, 0, 12, 4888, -1), + (4890, 4890, -1, 4890, 4890, 9, 75, 11056, 3, 8640, 12, -1, 5869), + (4894, 4894, 4894, 4894, 4894, 6, 73, 11057, 7, 2160, 12, -1, 4895), + (4895, 4894, 4894, 4894, 4894, 6, 74, 11058, 7, 2160, 12, 4894, 4896), + (4896, 4894, 4894, 4894, 4894, 6, 75, 11059, 7, 2160, 12, 4895, 6352), + (4897, -1, -1, 795, 795, 6, 71, -1, 0, 0, 12, 1432, 4898), + (4898, -1, -1, 795, 795, 6, 73, -1, 0, 0, 12, 4897, 4899), + (4899, -1, -1, 795, 795, 6, 75, -1, 0, 0, 12, 4898, 5889), + (4900, 1462, 1462, 1462, 1462, 6, 71, 11061, 5, 300, 12, 1466, 4901), + (4901, 1462, 1462, 1462, 1462, 6, 73, 11062, 5, 300, 12, 4900, 4902), + (4902, 1462, 1462, 1462, 1462, 6, 75, 11063, 5, 300, 12, 4901, 14739), + (4903, 4903, 4903, 4903, 4903, 9, 71, 11064, 9, 1320, 12, -1, 5892), + (4906, 4906, 4906, 4906, 4906, 9, 71, 11065, 9, 1320, 12, -1, 5893), + (4909, 4909, 4909, 4909, 4909, 9, 71, 11066, 16, 1320, 12, -1, 5894), + (4912, 4912, 4912, 4912, 4912, 9, 71, 11067, 16, 1320, 12, -1, 5895), + (4915, 4915, 4915, 4915, 4915, 9, 71, 11068, 7, 4320, 12, -1, 4916), + (4916, 4915, 4915, 4915, 4915, 9, 73, 11069, 7, 4320, 12, 4915, 4917), + (4917, 4915, 4915, 4915, 4915, 9, 75, 11070, 7, 4320, 12, 4916, 5607), + (4921, -1, -1, 480, 480, 2, 71, -1, 0, 0, 12, 482, 4922), + (4922, -1, -1, 480, 480, 2, 73, -1, 0, 0, 12, 4921, 4923), + (4923, -1, -1, 480, 480, 2, 75, -1, 0, 0, 12, 4922, -1), + (4924, -1, -1, 4924, 4924, 5, 75, -1, 0, 0, 12, -1, 4925), + (4925, -1, -1, 4924, 4924, 5, 75, -1, 0, 0, 12, 4924, 4926), + (4926, -1, -1, 4924, 4924, 5, 75, -1, 0, 0, 12, 4925, 5944), + (4927, 4927, 4927, 4927, 4927, 9, 71, 11076, 14, 600, 12, -1, 7209), + (4931, 4931, 4931, 4931, 4931, 6, 71, 11083, 4, 600, 12, -1, 4932), + (4932, 4931, 4931, 4931, 4931, 6, 73, 11084, 4, 600, 12, 4931, 4933), + (4933, 4931, 4931, 4931, 4931, 6, 75, 11085, 4, 600, 12, 4932, 6054), + (4934, 4934, 4934, 4934, 4934, 7, 71, 11086, 13, 300, 12, -1, 7295), + (4935, 4935, 4935, 4935, 4935, 7, 71, 11087, 14, 300, 12, -1, 7294), + (4938, 4938, 4938, 4938, 4938, 9, 75, 11092, 35, 1800, 12, -1, 5610), + (4943, 4943, 4943, 4943, 4943, 7, 75, 11098, 17, 1800, 12, -1, -1), + (4944, 4944, -1, 4944, 4944, 3, 71, 11103, 0, 1, 12, -1, 4945), + (4945, 4944, -1, 4944, 4944, 6, 73, 11104, 0, 1, 12, 4944, 4946), + (4946, 4944, -1, 4944, 4944, 9, 75, 11105, 0, 1, 12, 4945, 6155), + (4948, -1, -1, 846, 846, 3, 71, -1, 0, 0, 12, 1303, 4949), + (4949, -1, -1, 846, 846, 6, 73, -1, 0, 0, 12, 4948, 4950), + (4950, -1, -1, 846, 846, 9, 75, -1, 0, 0, 12, 4949, 6035), + (4951, -1, -1, 1543, 1543, 5, 71, -1, 0, 0, 12, 1545, 4952), + (4952, -1, -1, 1543, 1543, 5, 73, -1, 0, 0, 12, 4951, 4953), + (4953, -1, -1, 1543, 1543, 5, 75, -1, 0, 0, 12, 4952, 6042), + (4957, -1, -1, 878, 878, 7, 71, -1, 0, 0, 12, 1541, 4958), + (4958, -1, -1, 878, 878, 7, 73, -1, 0, 0, 12, 4957, 4959), + (4959, -1, -1, 878, 878, 7, 75, -1, 0, 0, 12, 4958, 6331), + (4960, -1, -1, 729, 729, 6, 71, -1, 0, 0, 12, 1469, 4961), + (4961, -1, -1, 729, 729, 6, 73, -1, 0, 0, 12, 4960, 4962), + (4962, -1, -1, 729, 729, 6, 75, -1, 0, 0, 12, 4961, 5738), + (4963, 723, 723, 723, 723, 9, 71, 11205, 6, 30, 12, 723, 5737), + (4964, 1119, 1119, 1119, 1119, 6, 73, 11206, 8, 900, 12, 1121, 4965), + (4965, 1119, 1119, 1119, 1119, 6, 74, 11207, 8, 900, 12, 4964, 4966), + (4966, 1119, 1119, 1119, 1119, 6, 75, 11208, 8, 900, 12, 4965, 5734), + (4969, 291, 291, 291, 291, 5, 71, 11212, 5, 900, 12, 1125, 4970), + (4970, 291, 291, 291, 291, 5, 73, 11213, 5, 900, 12, 4969, 4971), + (4971, 291, 291, 291, 291, 5, 75, 11214, 5, 900, 12, 4970, 5743), + (4972, 1598, -1, 1598, 1598, 6, 71, 11215, 6, 900, 12, 1600, 4973), + (4973, 1598, -1, 1598, 1598, 6, 73, 11216, 6, 900, 12, 4972, 4974), + (4974, 1598, -1, 1598, 1598, 6, 75, 11217, 6, 900, 12, 4973, 5710), + (4975, 592, 592, 592, 592, 3, 71, 11218, 2, 18, 12, 1106, 4976), + (4976, 592, 592, 592, 592, 3, 72, 11219, 2, 18, 12, 4975, 4977), + (4977, 592, 592, 592, 592, 3, 73, 11220, 2, 18, 12, 4976, 4978), + (4978, 592, 592, 592, 592, 3, 74, 11221, 2, 18, 12, 4977, 4979), + (4979, 592, 592, 592, 592, 3, 75, 11222, 2, 18, 12, 4978, 5702), + (4980, 1116, 1116, 1116, 1116, 6, 73, 11223, 4, 2160, 12, 1118, 4981), + (4981, 1116, 1116, 1116, 1116, 6, 74, 11224, 4, 2160, 12, 4980, 4982), + (4982, 1116, 1116, 1116, 1116, 6, 75, 11225, 4, 2160, 12, 4981, 5699), + (4983, -1, -1, 864, 864, 6, 71, -1, 0, 0, 12, 1292, 4984), + (4984, -1, -1, 864, 864, 6, 73, -1, 0, 0, 12, 4983, 4985), + (4985, -1, -1, 864, 864, 6, 75, -1, 0, 0, 12, 4984, 6011), + (4986, -1, -1, 644, 644, 5, 67, -1, 0, 0, 12, 1603, 4987), + (4987, -1, -1, 644, 644, 5, 69, -1, 0, 0, 12, 4986, 4988), + (4988, -1, -1, 644, 644, 5, 71, -1, 0, 0, 12, 4987, 6017), + (4989, -1, -1, 1608, 1608, 6, 71, -1, 0, 0, 12, 1610, 4990), + (4990, -1, -1, 1608, 1608, 6, 73, -1, 0, 0, 12, 4989, 4991), + (4991, -1, -1, 1608, 1608, 6, 75, -1, 0, 0, 12, 4990, 7378), + (4992, -1, -1, 1616, 1616, 5, 71, -1, 0, 0, 12, 1620, 4993), + (4993, -1, -1, 1616, 1616, 5, 72, -1, 0, 0, 12, 4992, 4994), + (4994, -1, -1, 1616, 1616, 5, 73, -1, 0, 0, 12, 4993, 4995), + (4995, -1, -1, 1616, 1616, 5, 74, -1, 0, 0, 12, 4994, 4996), + (4996, -1, -1, 1616, 1616, 5, 75, -1, 0, 0, 12, 4995, 6003), + (4997, 545, 545, 545, 545, 6, 73, 11226, 3, 900, 12, 1295, 4998), + (4998, 545, 545, 545, 545, 6, 74, 11227, 3, 900, 12, 4997, 4999), + (4999, 545, 545, 545, 545, 6, 75, 11228, 3, 900, 12, 4998, 6000), + (5000, -1, -1, 1230, 1230, 2, 71, -1, 0, 0, 12, 1232, 5001), + (5001, -1, -1, 1230, 1230, 2, 73, -1, 0, 0, 12, 5000, 5002), + (5002, -1, -1, 1230, 1230, 2, 75, -1, 0, 0, 12, 5001, -1), + (5003, 1345, 1345, 1345, 1345, 5, 73, 11229, 6, 900, 12, 1347, 5004), + (5004, 1345, 1345, 1345, 1345, 5, 74, 11230, 6, 900, 12, 5003, 5005), + (5005, 1345, 1345, 1345, 1345, 5, 75, 11231, 6, 900, 12, 5004, 6008), + (5006, 5006, 5006, 5006, 5006, 0, 0, 27673, 96, 72000, 0, -1, -1), + (5007, 5007, 5007, 5007, 5007, 3, 71, 11233, 8, 2160, 12, -1, 5008), + (5008, 5007, 5007, 5007, 5007, 6, 73, 11234, 8, 2160, 12, 5007, 5009), + (5009, 5007, 5007, 5007, 5007, 9, 75, 11235, 8, 2160, 12, 5008, 6425), + (5010, -1, -1, 1007, 1007, 8, 81, -1, 0, 0, 16, -1, 5011), + (5011, -1, -1, 1007, 1007, 10, 83, -1, 0, 0, 16, 5010, 5012), + (5012, -1, -1, 1007, 1007, 12, 85, -1, 0, 0, 16, 5011, 15317), + (5013, -1, -1, 1284, 1284, 6, 83, -1, 0, 0, 16, 5037, 5014), + (5014, -1, -1, 1284, 1284, 6, 85, -1, 0, 0, 16, 5013, -1), + (5015, 5015, 5015, 5015, 5015, 5, 75, 11241, 9, 900, 12, -1, 5741), + (5017, 5017, 5017, 5017, 5017, 3, 71, 11243, 8, 600, 12, -1, 5018), + (5018, 5017, 5017, 5017, 5017, 6, 73, 11244, 8, 600, 12, 5017, 5019), + (5019, 5017, 5017, 5017, 5017, 9, 75, 11245, 8, 600, 12, 5018, 7454), + (5020, 5020, 5020, 5020, 5020, 9, 75, 11246, 9, 300, 12, -1, 5716), + (5021, 5021, 5021, 5021, 5021, 9, 71, 11341, 7, 60, 12, -1, 10868), + (5022, 5022, 5022, 5022, 5022, 3, 71, 11247, 5, 600, 12, -1, 5023), + (5023, 5022, 5022, 5022, 5022, 6, 73, 23986, 5, 600, 12, 5022, 5024), + (5024, 5022, 5022, 5022, 5022, 9, 75, 23987, 5, 600, 12, 5023, 6038), + (5025, 5025, 5025, 5025, 5025, 3, 71, 11251, 6, 180, 12, -1, 5026), + (5026, 5025, 5025, 5025, 5025, 6, 73, 11252, 6, 180, 12, 5025, 5027), + (5027, 5025, 5025, 5025, 5025, 9, 75, 11253, 6, 180, 12, 5026, -1), + (5028, 5028, -1, 5028, 5028, 9, 75, 11254, 4, 900, 12, -1, 6041), + (5029, -1, -1, 1313, 1313, 6, 71, -1, 0, 0, 8, 1315, 5030), + (5030, -1, -1, 1313, 1313, 6, 73, -1, 0, 0, 8, 5029, 5031), + (5031, -1, -1, 1313, 1313, 6, 75, -1, 0, 0, 8, 5030, 6066), + (5032, -1, -1, 634, 634, 5, 72, -1, 0, 0, 12, 1321, 5033), + (5033, -1, -1, 634, 634, 5, 73, -1, 0, 0, 12, 5032, 5034), + (5034, -1, -1, 634, 634, 5, 74, -1, 0, 0, 12, 5033, 5611), + (5035, -1, -1, 1284, 1284, 6, 71, -1, 0, 0, 12, 1286, 5036), + (5036, -1, -1, 1284, 1284, 6, 73, -1, 0, 0, 12, 5035, 5037), + (5037, -1, -1, 1284, 1284, 6, 75, -1, 0, 0, 12, 5036, 5013), + (5038, -1, -1, 190, 190, 7, 71, -1, 0, 0, 12, 1525, 5039), + (5039, -1, -1, 190, 190, 7, 73, -1, 0, 0, 12, 5038, 5040), + (5040, -1, -1, 190, 190, 7, 75, -1, 0, 0, 12, 5039, 15141), + (5041, 534, 534, 534, 534, 5, 72, 11255, 4, 2160, 12, 1280, 5042), + (5042, 534, 534, 534, 534, 5, 73, 11256, 4, 2160, 12, 5041, 5043), + (5043, 534, 534, 534, 534, 5, 74, 11257, 4, 2160, 12, 5042, 5969), + (5044, 188, 188, 188, 188, 9, 73, 11258, 2, 30, 12, 1277, 7339), + (5045, -1, -1, 1057, 1057, 9, 85, -1, 0, 0, 16, -1, -1), + (5051, 757, -1, 757, 757, 5, 71, 11262, 6, 1800, 12, 1224, 5052), + (5052, 757, -1, 757, 757, 5, 73, 11263, 6, 1800, 12, 5051, 5053), + (5053, 757, -1, 757, 757, 5, 75, 11264, 6, 1800, 12, 5052, 5822), + (5054, 548, 548, 548, 548, 5, 72, 11265, 5, 900, 12, 1227, 5055), + (5055, 548, 548, 548, 548, 5, 73, 11266, 5, 900, 12, 5054, 5056), + (5056, 548, 548, 548, 548, 5, 74, 11267, 5, 900, 12, 5055, 5829), + (5058, 1498, 1498, 1498, 1498, 6, 71, 11269, 12, 1320, 12, 1500, 5059), + (5059, 1498, 1498, 1498, 1498, 6, 73, 11270, 12, 1320, 12, 5058, 5060), + (5060, 1498, 1498, 1498, 1498, 6, 75, 11271, 12, 1320, 12, 5059, 5819), + (5061, -1, -1, 567, 567, 5, 72, -1, 0, 0, 12, 567, 5825), + (5062, 459, 459, 459, 459, 6, 71, 11272, 8, 180, 12, 1191, 5063), + (5063, 459, 459, 459, 459, 6, 73, 11273, 8, 180, 12, 5062, 5064), + (5064, 459, 459, 459, 459, 6, 75, 11274, 8, 180, 12, 5063, -1), + (5068, 153, 153, 153, 153, 9, 75, 11279, 3, 2160, 12, 1519, 6101), + (5069, 146, 146, 146, 146, 5, 72, 11281, 2, 180, 12, 146, 6102), + (5070, 131, 131, 131, 131, 5, 72, 11282, 4, 900, 12, 1205, 5071), + (5071, 131, 131, 131, 131, 5, 73, 11283, 4, 900, 12, 5070, 5072), + (5072, 131, 131, 131, 131, 5, 74, 11284, 4, 900, 12, 5071, 5791), + (5076, 1192, 1192, 1192, 1192, 5, 72, 11288, 12, 1320, 12, 1194, 5077), + (5077, 1192, 1192, 1192, 1192, 5, 73, 11289, 12, 1320, 12, 5076, 5078), + (5078, 1192, 1192, 1192, 1192, 5, 74, 11290, 12, 1320, 12, 5077, 5794), + (5079, 1195, 1195, 1195, 1195, 9, 75, 11291, 13, 2160, 12, 1195, 5790), + (5080, 1459, 1459, 1459, 1459, 5, 71, 11293, 11, 1800, 12, 1461, 5081), + (5081, 1459, 1459, 1459, 1459, 5, 73, 11294, 11, 1800, 12, 5080, 5082), + (5082, 1459, 1459, 1459, 1459, 5, 75, 11295, 11, 1800, 12, 5081, 5803), + (5084, 1383, 1383, 1383, 1383, 12, 75, 11296, 6, 300, 12, 1387, 5789), + (5085, -1, -1, 5085, 5085, 3, 71, -1, 0, 0, 12, -1, 5086), + (5086, -1, -1, 5085, 5085, 6, 73, -1, 0, 0, 12, 5085, 5087), + (5087, -1, -1, 5085, 5085, 9, 75, -1, 0, 0, 12, 5086, 6406), + (5095, 5095, 5095, 5095, 5095, 3, 71, 11307, 10, 900, 12, -1, 5096), + (5096, 5095, 5095, 5095, 5095, 6, 73, 11308, 10, 900, 12, 5095, 5097), + (5097, 5095, 5095, 5095, 5095, 9, 75, 11309, 10, 900, 12, 5096, 5975), + (5098, 5098, 5098, 5098, 5098, 9, 75, 11310, 2, 30, 12, -1, -1), + (5105, 5105, 5105, 5105, 5105, 9, 75, 11317, 11, 600, 12, -1, 5832), + (5109, 5109, 5109, 5109, 5109, 9, 75, 11321, 0, 1, 12, -1, 6448), + (5118, -1, -1, 5083, 5083, 3, 71, -1, 0, 0, 12, -1, 5119), + (5119, -1, -1, 5083, 5083, 3, 73, -1, 0, 0, 12, 5118, 5120), + (5120, -1, -1, 5083, 5083, 3, 75, -1, 0, 0, 12, 5119, 5797), + (5127, -1, -1, 5127, 5127, 3, 71, -1, 0, 0, 12, -1, 5128), + (5128, -1, -1, 5127, 5127, 3, 73, -1, 0, 0, 12, 5127, 5129), + (5129, -1, -1, 5127, 5127, 3, 75, -1, 0, 0, 12, 5128, -1), + (5130, 860, 860, 860, 860, 6, 71, 5860, 5, 180, 12, 862, 5131), + (5131, 860, 860, 860, 860, 6, 73, 5861, 5, 180, 12, 5130, 5132), + (5132, 860, 860, 860, 860, 6, 75, 5862, 5, 180, 12, 5131, -1), + (5133, -1, -1, 267, 267, 6, 71, -1, 0, 0, 12, 925, 5134), + (5134, -1, -1, 267, 267, 6, 73, -1, 0, 0, 12, 5133, 5135), + (5135, -1, -1, 267, 267, 6, 75, -1, 0, 0, 12, 5134, 5617), + (5136, -1, -1, 4688, 4688, 3, 71, -1, 0, 0, 12, -1, 5137), + (5137, -1, -1, 4688, 4688, 3, 72, -1, 0, 0, 12, 5136, 5138), + (5138, -1, -1, 4688, 4688, 3, 73, -1, 0, 0, 12, 5137, 5139), + (5139, -1, -1, 4688, 4688, 3, 74, -1, 0, 0, 12, 5138, 5140), + (5140, -1, -1, 4688, 4688, 3, 75, -1, 0, 0, 12, 5139, -1), + (5141, -1, -1, 815, 815, 5, 71, -1, 0, 0, 12, 819, 5142), + (5142, -1, -1, 815, 815, 5, 72, -1, 0, 0, 12, 5141, 5143), + (5143, -1, -1, 815, 815, 5, 73, -1, 0, 0, 12, 5142, 5144), + (5144, -1, -1, 815, 815, 5, 74, -1, 0, 0, 12, 5143, 5145), + (5145, -1, -1, 815, 815, 5, 75, -1, 0, 0, 12, 5144, 5909), + (5150, 5150, 5150, 5150, 5150, 0, 1, 11112, 22, 300, 3, -1, 5151), + (5165, 5165, 5165, 5165, 5165, 0, 1, 11127, 22, 300, 3, -1, 5166), + (5180, 5180, 5180, 5180, 5180, 0, 1, 11142, 22, 300, 3, -1, 5181), + (5195, 5195, 5195, 5195, 5195, 0, 1, 11157, 22, 300, 3, -1, 5196), + (5210, 5210, 5210, 5210, 5210, 0, 1, 11172, 22, 300, 3, -1, 5211), + (5225, 5225, 5225, 5225, 5225, 0, 1, 11187, 22, 300, 3, -1, 5226), + (5240, 1355, 1355, 1355, 1355, 6, 71, 11611, 3, 60, 12, 1357, 5241), + (5241, 1355, 1355, 1355, 1355, 6, 73, 11612, 3, 60, 12, 5240, 5242), + (5242, 1355, 1355, 1355, 1355, 6, 75, 11613, 3, 60, 12, 5241, 5914), + (5243, -1, -1, 907, 907, 7, 71, -1, 0, 0, 12, 911, 5244), + (5244, -1, -1, 907, 907, 7, 72, -1, 0, 0, 12, 5243, 5245), + (5245, -1, -1, 907, 907, 7, 73, -1, 0, 0, 12, 5244, 5246), + (5246, -1, -1, 907, 907, 7, 74, -1, 0, 0, 12, 5245, 5247), + (5247, -1, -1, 907, 907, 7, 75, -1, 0, 0, 12, 5246, -1), + (5248, -1, -1, 5248, 5248, 3, 71, -1, 0, 0, 12, -1, 5249), + (5249, -1, -1, 5248, 5248, 6, 73, -1, 0, 0, 12, 5248, 5250), + (5250, -1, -1, 5248, 5248, 9, 75, -1, 0, 0, 12, 5249, 6014), + (5251, 5251, 5251, 5251, 5251, 5, 71, 11615, 13, 900, 12, -1, 5252), + (5252, 5251, 5251, 5251, 5251, 5, 73, 11616, 13, 900, 12, 5251, 5253), + (5253, 5251, 5251, 5251, 5251, 5, 75, 11617, 13, 900, 12, 5252, 6092), + (5254, -1, -1, 724, 724, 3, 71, -1, 0, 0, 12, 728, 5255), + (5255, -1, -1, 724, 724, 3, 72, -1, 0, 0, 12, 5254, 5256), + (5256, -1, -1, 724, 724, 3, 73, -1, 0, 0, 12, 5255, 5257), + (5257, -1, -1, 724, 724, 3, 74, -1, 0, 0, 12, 5256, 5258), + (5258, -1, -1, 724, 724, 3, 75, -1, 0, 0, 12, 5257, 5729), + (5259, -1, -1, 790, 790, 3, 71, -1, 0, 0, 12, 794, 5260), + (5260, -1, -1, 790, 790, 3, 72, -1, 0, 0, 12, 5259, 5261), + (5261, -1, -1, 790, 790, 3, 73, -1, 0, 0, 12, 5260, 5262), + (5262, -1, -1, 790, 790, 3, 74, -1, 0, 0, 12, 5261, 5263), + (5263, -1, -1, 790, 790, 3, 75, -1, 0, 0, 12, 5262, 5320), + (5264, -1, -1, 5264, 5264, 3, 71, -1, 0, 0, 12, -1, 5265), + (5265, -1, -1, 5264, 5264, 3, 72, -1, 0, 0, 12, 5264, 5266), + (5266, -1, -1, 5264, 5264, 3, 73, -1, 0, 0, 12, 5265, 5267), + (5267, -1, -1, 5264, 5264, 3, 74, -1, 0, 0, 12, 5266, 5268), + (5268, -1, -1, 5264, 5264, 3, 75, -1, 0, 0, 12, 5267, 5939), + (5269, -1, -1, 5269, 5269, 3, 71, -1, 0, 0, 12, -1, -1), + (5270, -1, -1, 589, 589, 7, 71, -1, 0, 0, 12, 894, 5271), + (5271, -1, -1, 589, 589, 7, 73, -1, 0, 0, 12, 5270, 5272), + (5272, -1, -1, 589, 589, 7, 75, -1, 0, 0, 12, 5271, 6063), + (5276, -1, -1, 5276, 5276, 3, 71, -1, 0, 0, 12, -1, 5277), + (5277, -1, -1, 5276, 5276, 6, 73, -1, 0, 0, 12, 5276, 5278), + (5278, -1, -1, 5276, 5276, 9, 75, -1, 0, 0, 12, 5277, 15238), + (5279, 155, 155, 155, 155, 12, 75, 11624, 8, 60, 12, 1344, 5289), + (5280, 921, 921, 921, 921, 9, 74, 11625, 8, 60, 12, 1340, 6149), + (5281, 922, 922, 922, 922, 9, 73, 11626, 8, 60, 12, 1341, 6150), + (5282, 923, 923, 923, 923, 9, 72, 11627, 8, 60, 12, 1342, 6151), + (5283, -1, -1, 5263, 5263, 3, 71, -1, 0, 0, 12, -1, 5284), + (5284, -1, -1, 5263, 5263, 6, 73, -1, 0, 0, 12, 5283, 5285), + (5285, -1, -1, 5263, 5263, 9, 75, -1, 0, 0, 12, 5284, 5620), + (5286, -1, -1, 1107, 1107, 6, 71, -1, 0, 0, 12, 1109, 5287), + (5287, -1, -1, 1107, 1107, 6, 73, -1, 0, 0, 12, 5286, 5288), + (5288, -1, -1, 1107, 1107, 6, 75, -1, 0, 0, 12, 5287, 6403), + (5289, 155, 155, 155, 155, 12, 77, 13227, 8, 60, 14, 5279, 7238), + (5290, -1, -1, 1604, 1604, 5, 63, -1, 0, 0, 12, 1606, 5291), + (5291, -1, -1, 1604, 1604, 5, 64, -1, 0, 0, 12, 5290, 5292), + (5292, -1, -1, 1604, 1604, 5, 65, -1, 0, 0, 12, 5291, 5293), + (5293, -1, -1, 1604, 1604, 5, 66, -1, 0, 0, 12, 5292, 5294), + (5294, -1, -1, 1604, 1604, 5, 67, -1, 0, 0, 12, 5293, 6032), + (5295, -1, -1, 5295, 5295, 3, 71, -1, 0, 0, 12, -1, 5296), + (5296, -1, -1, 5295, 5295, 6, 73, -1, 0, 0, 12, 5295, 5297), + (5297, -1, -1, 5295, 5295, 9, 75, -1, 0, 0, 12, 5296, 6531), + (5298, 5298, 5298, 5298, 5298, 3, 71, 11630, 32, 1800, 12, -1, 5299), + (5299, 5298, 5298, 5298, 5298, 6, 73, 11631, 32, 1800, 12, 5298, 5300), + (5300, 5298, 5298, 5298, 5298, 9, 75, 11632, 32, 1800, 12, 5299, 5707), + (5301, -1, -1, 683, 683, 5, 71, -1, 0, 0, 12, 1038, 5302), + (5302, -1, -1, 683, 683, 5, 72, -1, 0, 0, 12, 5301, 5303), + (5303, -1, -1, 683, 683, 5, 73, -1, 0, 0, 12, 5302, 5304), + (5304, -1, -1, 683, 683, 5, 74, -1, 0, 0, 12, 5303, 5305), + (5305, -1, -1, 683, 683, 5, 75, -1, 0, 0, 12, 5304, 6080), + (5306, -1, -1, 658, 658, 5, 71, -1, 0, 0, 12, 660, 5307), + (5307, -1, -1, 658, 658, 5, 72, -1, 0, 0, 12, 5306, 5308), + (5308, -1, -1, 658, 658, 5, 73, -1, 0, 0, 12, 5307, 5309), + (5309, -1, -1, 658, 658, 5, 74, -1, 0, 0, 12, 5308, 5310), + (5310, -1, -1, 658, 658, 5, 75, -1, 0, 0, 12, 5309, 5623), + (5311, 1495, 1495, 1495, 1495, 5, 71, 11639, 30, 900, 12, 1497, 5312), + (5312, 1495, 1495, 1495, 1495, 5, 73, 11640, 30, 900, 12, 5311, 5313), + (5313, 1495, 1495, 1495, 1495, 5, 75, 11641, 30, 900, 12, 5312, 5826), + (5314, 1327, 1327, 1327, 1327, 5, 71, 11642, 10, 900, 12, 1329, 5315), + (5315, 1327, 1327, 1327, 1327, 5, 73, 11643, 10, 900, 12, 5314, 5316), + (5316, 1327, 1327, 1327, 1327, 5, 75, 11644, 10, 900, 12, 5315, 6098), + (5317, -1, -1, 98, 738, 4, 71, -1, 0, 0, 12, 740, 5318), + (5318, -1, -1, 98, 738, 4, 73, -1, 0, 0, 12, 5317, 5319), + (5319, -1, -1, 98, 738, 4, 75, -1, 0, 0, 12, 5318, 5628), + (5320, -1, -1, 790, 790, 6, 76, -1, 0, 0, 14, 5263, 5321), + (5321, -1, -1, 790, 790, 6, 77, -1, 0, 0, 14, 5320, 5322), + (5322, -1, -1, 790, 790, 6, 78, -1, 0, 0, 14, 5321, 5323), + (5323, -1, -1, 790, 790, 6, 79, -1, 0, 0, 14, 5322, 5324), + (5324, -1, -1, 790, 790, 6, 80, -1, 0, 0, 14, 5323, 7270), + (5325, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 843, 5326), + (5326, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 5325, 5327), + (5327, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 5326, 5328), + (5328, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 5327, 5329), + (5329, -1, -1, 839, 839, 6, 70, -1, 0, 0, 14, 5328, 7210), + (5330, 1327, 1327, 1327, 1327, 12, 91, 30870, 10, 900, 18, 10189, 5331), + (5333, 1520, 1520, 1520, 1520, 9, 91, 30873, 11, 900, 18, 12999, 5334), + (5336, 12989, 12989, 12989, 12989, 11, 91, 30876, 73, 1800, 18, 12991, 5337), + (5339, -1, -1, 6383, 6383, 11, 91, -1, 0, 0, 18, 12803, 5340), + (5342, 6692, 6692, 6692, 6692, 9, 91, 30879, 42, 600, 18, 6696, 5343), + (5347, -1, -1, 6375, 6375, 12, 91, -1, 0, 0, 18, 10086, 5348), + (5348, -1, -1, 6375, 6375, 15, 93, -1, 0, 0, 18, 5347, 5349), + (5350, 12992, 12992, 12992, 12992, 12, 91, 30884, 0, 1, 18, 12994, 5351), + (5353, 6706, 6706, 6706, 6706, 9, 91, 30887, 44, 600, 18, 10181, 5354), + (5356, 5109, 5109, 5109, 5109, 12, 92, 30890, 0, 1, 18, 13016, 17323), + (5357, 528, 528, 528, 528, 12, 91, 30891, 5, 720, 18, 13163, 5358), + (5360, -1, -1, 9503, 9503, 11, 91, -1, 0, 0, 18, 12794, 5361), + (5363, 5251, 5251, 5251, 5251, 15, 91, 30894, 13, 900, 18, 10199, 5364), + (5366, -1, -1, 5002, 5002, 12, 91, -1, 34, 0, 18, -1, 5367), + (5369, 5001, 5001, 5001, 5001, 12, 91, 30900, 32, 600, 18, -1, 5370), + (5500, -1, -1, 852, 852, 9, 78, -1, 0, 0, 14, 854, 5501), + (5501, -1, -1, 852, 852, 10, 79, -1, 0, 0, 14, 5500, 5502), + (5502, -1, -1, 852, 852, 12, 80, -1, 0, 0, 14, 5501, 7678), + (5513, 1126, 1126, 1126, 1126, 8, 77, 12668, 2, 2160, 14, 1128, 5514), + (5514, 1126, 1126, 1126, 1126, 9, 78, 12669, 2, 2160, 14, 5513, 5515), + (5515, 1126, 1126, 1126, 1126, 10, 79, 12670, 2, 2160, 14, 5514, 13253), + (5516, -1, -1, 1287, 1287, 8, 77, -1, 0, 0, 14, 1289, 5517), + (5517, -1, -1, 1287, 1287, 9, 78, -1, 0, 0, 14, 5516, 5518), + (5518, -1, -1, 1287, 1287, 10, 79, -1, 0, 0, 14, 5517, 12469), + (5519, -1, -1, 125, 125, 6, 76, -1, 0, 0, 14, 1398, 5520), + (5520, -1, -1, 125, 125, 7, 77, -1, 0, 0, 14, 5519, 5521), + (5521, -1, -1, 125, 125, 8, 78, -1, 0, 0, 14, 5520, 5522), + (5522, -1, -1, 125, 125, 9, 79, -1, 0, 0, 14, 5521, 5523), + (5523, -1, -1, 125, 125, 10, 80, -1, 0, 0, 14, 5522, 7501), + (5524, -1, -1, 122, 122, 6, 76, -1, 0, 0, 14, 1403, 5525), + (5525, -1, -1, 122, 122, 7, 77, -1, 0, 0, 14, 5524, 5526), + (5526, -1, -1, 122, 122, 8, 78, -1, 0, 0, 14, 5525, 5527), + (5527, -1, -1, 122, 122, 9, 79, -1, 0, 0, 14, 5526, 5528), + (5528, -1, -1, 122, 122, 10, 80, -1, 0, 0, 14, 5527, 7506), + (5529, -1, -1, 1486, 1486, 7, 76, -1, 0, 0, 14, 1490, 5530), + (5530, -1, -1, 1486, 1486, 8, 77, -1, 0, 0, 14, 5529, 5531), + (5531, -1, -1, 1486, 1486, 9, 78, -1, 0, 0, 14, 5530, 5532), + (5532, -1, -1, 1486, 1486, 10, 79, -1, 0, 0, 14, 5531, 5533), + (5533, -1, -1, 1486, 1486, 12, 80, -1, 0, 0, 14, 5532, 7554), + (5534, -1, -1, 599, 599, 9, 78, -1, 0, 0, 14, 1538, 5535), + (5535, -1, -1, 599, 599, 10, 79, -1, 0, 0, 14, 5534, 5536), + (5536, -1, -1, 599, 599, 12, 80, -1, 0, 0, 14, 5535, 7559), + (5542, -1, -1, 1041, 1041, 7, 76, -1, 0, 0, 14, 4709, 5543), + (5543, -1, -1, 1041, 1041, 9, 78, -1, 0, 0, 14, 5542, 5544), + (5544, -1, -1, 1041, 1041, 12, 80, -1, 0, 0, 14, 5543, 7562), + (5545, -1, -1, 1044, 1044, 7, 76, -1, 0, 0, 14, 4712, 5546), + (5546, -1, -1, 1044, 1044, 9, 78, -1, 0, 0, 14, 5545, 5547), + (5547, -1, -1, 1044, 1044, 12, 80, -1, 0, 0, 14, 5546, 7650), + (5548, -1, -1, 1047, 1047, 7, 76, -1, 0, 0, 14, 4715, 5549), + (5549, -1, -1, 1047, 1047, 9, 78, -1, 0, 0, 14, 5548, 5550), + (5550, -1, -1, 1047, 1047, 12, 80, -1, 0, 0, 14, 5549, 7653), + (5551, -1, -1, 1050, 1050, 7, 76, -1, 0, 0, 14, 4718, 5552), + (5552, -1, -1, 1050, 1050, 9, 78, -1, 0, 0, 14, 5551, 5553), + (5553, -1, -1, 1050, 1050, 12, 80, -1, 0, 0, 14, 5552, 7656), + (5554, -1, -1, 119, 119, 7, 76, -1, 0, 0, 14, 4724, 5555), + (5555, -1, -1, 119, 119, 9, 78, -1, 0, 0, 14, 5554, 5556), + (5556, -1, -1, 119, 119, 12, 80, -1, 0, 0, 14, 5555, 7565), + (5557, -1, -1, 1592, 1592, 7, 76, -1, 0, 0, 14, 4729, 5558), + (5558, -1, -1, 1592, 1592, 8, 77, -1, 0, 0, 14, 5557, 5559), + (5559, -1, -1, 1592, 1592, 9, 78, -1, 0, 0, 14, 5558, 5560), + (5560, -1, -1, 1592, 1592, 10, 79, -1, 0, 0, 14, 5559, 5561), + (5561, -1, -1, 1592, 1592, 12, 80, -1, 0, 0, 14, 5560, 7568), + (5562, -1, -1, 4739, 4739, 7, 76, -1, 0, 0, 14, 4741, 5563), + (5563, -1, -1, 4739, 4739, 9, 78, -1, 0, 0, 14, 5562, 5564), + (5564, -1, -1, 4739, 4739, 12, 80, -1, 0, 0, 14, 5563, 7573), + (5565, 4742, 4742, 4742, 4742, 7, 76, 12671, 12, 600, 14, 4742, -1), + (5566, -1, -1, 1072, 1072, 7, 76, -1, 0, 0, 14, 4748, 5567), + (5567, -1, -1, 1072, 1072, 8, 77, -1, 0, 0, 14, 5566, 5568), + (5568, -1, -1, 1072, 1072, 9, 78, -1, 0, 0, 14, 5567, 5569), + (5569, -1, -1, 1072, 1072, 10, 79, -1, 0, 0, 14, 5568, 5570), + (5570, -1, -1, 1072, 1072, 12, 80, -1, 0, 0, 14, 5569, 7576), + (5571, -1, -1, 637, 637, 7, 76, -1, 0, 0, 14, 4751, 5572), + (5572, -1, -1, 637, 637, 9, 78, -1, 0, 0, 14, 5571, 5573), + (5573, -1, -1, 637, 637, 12, 80, -1, 0, 0, 14, 5572, 12435), + (5574, -1, -1, 1210, 1210, 7, 76, -1, 0, 0, 14, 4754, 5575), + (5575, -1, -1, 1210, 1210, 9, 78, -1, 0, 0, 14, 5574, 5576), + (5576, -1, -1, 1210, 1210, 12, 80, -1, 0, 0, 14, 5575, 7232), + (5577, -1, -1, 1210, 1213, 7, 76, -1, 0, 0, 14, 4757, 5578), + (5578, -1, -1, 1210, 1213, 9, 78, -1, 0, 0, 14, 5577, 5579), + (5579, -1, -1, 1210, 1213, 12, 80, -1, 0, 0, 14, 5578, 7581), + (5580, -1, -1, 602, 602, 7, 76, -1, 0, 0, 14, 4760, 5581), + (5581, -1, -1, 602, 602, 9, 78, -1, 0, 0, 14, 5580, 5582), + (5582, -1, -1, 602, 602, 12, 80, -1, 0, 0, 14, 5581, 10685), + (5586, -1, -1, 98, 98, 7, 76, -1, 0, 0, 14, 4769, 5587), + (5587, -1, -1, 98, 98, 9, 78, -1, 0, 0, 14, 5586, 5588), + (5588, -1, -1, 98, 98, 12, 80, -1, 0, 0, 14, 5587, 7584), + (5589, -1, -1, 1186, 1186, 7, 76, -1, 0, 0, 14, 4778, 5590), + (5590, -1, -1, 1186, 1186, 9, 78, -1, 0, 0, 14, 5589, 5591), + (5591, -1, -1, 1186, 1186, 12, 80, -1, 0, 0, 14, 5590, 7587), + (5592, -1, -1, 80, 80, 7, 76, -1, 0, 0, 14, 4781, 5593), + (5593, -1, -1, 80, 80, 9, 78, -1, 0, 0, 14, 5592, 5594), + (5594, -1, -1, 80, 80, 12, 80, -1, 0, 0, 14, 5593, 7590), + (5595, -1, -1, 255, 255, 7, 76, -1, 0, 0, 14, 4797, 5596), + (5596, -1, -1, 255, 255, 9, 78, -1, 0, 0, 14, 5595, 5597), + (5597, -1, -1, 255, 255, 12, 80, -1, 0, 0, 14, 5596, 7631), + (5606, 4860, 4860, 4860, 4860, 12, 80, 11688, 13, 60, 14, 4860, 7127), + (5607, 4915, 4915, 4915, 4915, 7, 76, 12673, 7, 4320, 14, 4917, 5608), + (5608, 4915, 4915, 4915, 4915, 9, 78, 12674, 7, 4320, 14, 5607, 5609), + (5609, 4915, 4915, 4915, 4915, 12, 80, 12675, 7, 4320, 14, 5608, 7246), + (5610, 4938, 4938, 4938, 4938, 12, 80, 12676, 35, 1800, 14, 4938, 5614), + (5611, -1, -1, 634, 634, 7, 76, -1, 0, 0, 14, 5034, 5612), + (5612, -1, -1, 634, 634, 9, 78, -1, 0, 0, 14, 5611, 5613), + (5613, -1, -1, 634, 634, 12, 80, -1, 0, 0, 14, 5612, 7713), + (5614, 4938, 4938, 4938, 4938, 9, 85, 16852, 35, 1800, 16, 5610, 12875), + (5617, -1, -1, 267, 267, 7, 76, -1, 0, 0, 14, 5135, 5618), + (5618, -1, -1, 267, 267, 9, 78, -1, 0, 0, 14, 5617, 5619), + (5619, -1, -1, 267, 267, 12, 80, -1, 0, 0, 14, 5618, 12860), + (5620, -1, -1, 5263, 5263, 7, 76, -1, 0, 0, 14, 5285, 5621), + (5621, -1, -1, 5263, 5263, 9, 78, -1, 0, 0, 14, 5620, 5622), + (5622, -1, -1, 5263, 5263, 12, 80, -1, 0, 0, 14, 5621, 12466), + (5623, -1, -1, 658, 658, 5, 76, -1, 0, 0, 14, 5310, 5624), + (5624, -1, -1, 658, 658, 5, 77, -1, 0, 0, 14, 5623, 5625), + (5625, -1, -1, 658, 658, 5, 78, -1, 0, 0, 14, 5624, 5626), + (5626, -1, -1, 658, 658, 5, 79, -1, 0, 0, 14, 5625, 5627), + (5627, -1, -1, 658, 658, 5, 80, -1, 0, 0, 14, 5626, 7593), + (5628, -1, -1, 98, 738, 7, 76, -1, 0, 0, 14, 5319, 5629), + (5629, -1, -1, 98, 738, 9, 78, -1, 0, 0, 14, 5628, 5630), + (5630, -1, -1, 98, 738, 12, 80, -1, 0, 0, 14, 5629, 7598), + (5699, 1116, 1116, 1116, 1116, 7, 76, 12500, 4, 2160, 14, 4982, 5700), + (5700, 1116, 1116, 1116, 1116, 9, 78, 12501, 4, 2160, 14, 5699, 5701), + (5701, 1116, 1116, 1116, 1116, 12, 80, 12502, 4, 2160, 14, 5700, 7430), + (5702, 592, 592, 592, 592, 4, 76, 12503, 2, 18, 14, 4979, 5703), + (5703, 592, 592, 592, 592, 4, 77, 12504, 2, 18, 14, 5702, 5704), + (5704, 592, 592, 592, 592, 4, 78, 12505, 2, 18, 14, 5703, 5705), + (5705, 592, 592, 592, 592, 4, 79, 12506, 2, 18, 14, 5704, 5706), + (5706, 592, 592, 592, 592, 4, 80, 12507, 2, 18, 14, 5705, 7433), + (5707, 5298, 5298, 5298, 5298, 9, 78, 12508, 32, 1800, 14, 5300, 5708), + (5708, 5298, 5298, 5298, 5298, 10, 79, 12509, 32, 1800, 14, 5707, 5709), + (5709, 5298, 5298, 5298, 5298, 12, 80, 12510, 32, 1800, 14, 5708, 7438), + (5710, 1598, -1, 1598, 1598, 7, 76, 12511, 6, 900, 14, 4974, 5711), + (5711, 1598, -1, 1598, 1598, 9, 78, 12512, 6, 900, 14, 5710, 5712), + (5712, 1598, -1, 1598, 1598, 12, 80, 12513, 6, 900, 14, 5711, 7441), + (5713, 1569, 1569, 1569, 1569, 7, 76, 12514, 5, 1800, 14, 1571, 5714), + (5714, 1569, 1569, 1569, 1569, 9, 78, 12515, 5, 1800, 14, 5713, 5715), + (5715, 1569, 1569, 1569, 1569, 12, 80, 12516, 5, 1800, 14, 5714, 7457), + (5716, 5020, 5020, 5020, 5020, 9, 77, 12517, 9, 300, 14, 5020, 7444), + (5717, 5717, 5717, 5717, 5717, 10, 76, 12519, 17, 600, 14, -1, -1), + (5729, -1, -1, 724, 724, 7, 76, -1, 0, 0, 14, 5258, 5730), + (5730, -1, -1, 724, 724, 8, 77, -1, 0, 0, 14, 5729, 5731), + (5731, -1, -1, 724, 724, 9, 78, -1, 0, 0, 14, 5730, 5732), + (5732, -1, -1, 724, 724, 10, 79, -1, 0, 0, 14, 5731, 5733), + (5733, -1, -1, 724, 724, 12, 80, -1, 0, 0, 14, 5732, 7489), + (5734, 1119, 1119, 1119, 1119, 7, 78, 12520, 8, 900, 14, 4966, 5735), + (5735, 1119, 1119, 1119, 1119, 8, 79, 12521, 8, 900, 14, 5734, 5736), + (5736, 1119, 1119, 1119, 1119, 9, 80, 12522, 8, 900, 14, 5735, 7479), + (5737, 723, 723, 723, 723, 7, 76, 12523, 6, 30, 14, 4963, 7482), + (5738, -1, -1, 729, 729, 7, 76, -1, 0, 0, 14, 4962, 5739), + (5739, -1, -1, 729, 729, 8, 77, -1, 0, 0, 14, 5738, 5740), + (5740, -1, -1, 729, 729, 9, 78, -1, 0, 0, 14, 5739, 7494), + (5741, 5015, 5015, 5015, 5015, 12, 80, 12524, 9, 900, 14, 5015, 7483), + (5742, 289, 289, 289, 289, 12, 80, 12525, 3, 300, 14, 1607, 7484), + (5743, 291, 291, 291, 291, 9, 78, 12526, 5, 900, 14, 4971, 5744), + (5744, 291, 291, 291, 291, 10, 79, 12527, 5, 900, 14, 5743, 5745), + (5745, 291, 291, 291, 291, 12, 80, 12528, 5, 900, 14, 5744, 7485), + (5759, 1425, 1425, 1425, 1425, 7, 78, 13565, 2, 2160, 14, 1429, 5760), + (5760, 1425, 1425, 1425, 1425, 8, 78, 13570, 2, 2160, 14, 5759, 5761), + (5761, 1425, 1425, 1425, 1425, 9, 79, 13575, 2, 2160, 14, 5760, 5762), + (5762, 1425, 1425, 1425, 1425, 10, 79, 13580, 2, 2160, 14, 5761, 5763), + (5763, 1425, 1425, 1425, 1425, 11, 80, 13585, 2, 2160, 14, 5762, -1), + (5764, 4854, 4854, 4854, 4854, 7, 76, 12534, 8, 600, 14, 4856, 5765), + (5765, 4854, 4854, 4854, 4854, 9, 78, 12535, 8, 600, 14, 5764, 5766), + (5766, 4854, 4854, 4854, 4854, 12, 80, 12536, 8, 600, 14, 5765, 7178), + (5767, 4857, 4857, 4857, 4857, 7, 76, 12537, 7, 600, 14, 4859, 5768), + (5768, 4857, 4857, 4857, 4857, 9, 78, 12538, 7, 600, 14, 5767, 5769), + (5769, 4857, 4857, 4857, 4857, 12, 80, 12539, 7, 600, 14, 5768, 17030), + (5770, 1348, 1348, 1348, 1348, 9, 78, 12540, 0, 3600, 14, 1350, 5771), + (5771, 1348, 1348, 1348, 1348, 10, 79, 12541, 0, 3600, 14, 5770, 5772), + (5772, 1348, 1348, 1348, 1348, 12, 80, 12542, 0, 3600, 14, 5771, 7184), + (5776, -1, -1, 5776, 5776, 7, 76, -1, 0, 0, 14, -1, 5777), + (5777, -1, -1, 5776, 5776, 9, 78, -1, 0, 0, 14, 5776, 5778), + (5778, -1, -1, 5776, 5776, 12, 80, -1, 0, 0, 14, 5777, 7196), + (5779, 1178, 1178, 1178, 1178, 7, 76, 12546, 4, 900, 14, 1180, 5780), + (5780, 1178, 1178, 1178, 1178, 8, 77, 12547, 4, 900, 14, 5779, 5781), + (5781, 1178, 1178, 1178, 1178, 9, 78, 12548, 4, 900, 14, 5780, 7187), + (5789, 1383, 1383, 1383, 1383, 12, 80, 12549, 6, 300, 14, 5084, 7299), + (5790, 1195, 1195, 1195, 1195, 9, 80, 12550, 13, 2160, 14, 5079, 7300), + (5791, 131, 131, 131, 131, 8, 77, 12551, 4, 900, 14, 5072, 5792), + (5792, 131, 131, 131, 131, 9, 78, 12552, 4, 900, 14, 5791, 5793), + (5793, 131, 131, 131, 131, 10, 79, 12553, 4, 900, 14, 5792, 7301), + (5794, 1192, 1192, 1192, 1192, 8, 77, 12554, 12, 1320, 14, 5078, 5795), + (5795, 1192, 1192, 1192, 1192, 9, 78, 12555, 12, 1320, 14, 5794, 5796), + (5796, 1192, 1192, 1192, 1192, 10, 79, 12556, 12, 1320, 14, 5795, 7304), + (5797, -1, -1, 5083, 5083, 7, 76, -1, 0, 0, 14, 5120, 5798), + (5798, -1, -1, 5083, 5083, 9, 78, -1, 0, 0, 14, 5797, 5799), + (5799, -1, -1, 5083, 5083, 12, 80, -1, 0, 0, 14, 5798, -1), + (5800, 746, 746, 746, 746, 9, 78, 12557, 10, 2160, 14, 1493, 5801), + (5801, 746, 746, 746, 746, 10, 79, 12558, 10, 2160, 14, 5800, 5802), + (5802, 746, 746, 746, 746, 12, 80, 12559, 10, 2160, 14, 5801, 7307), + (5803, 1459, 1459, 1459, 1459, 7, 76, 12560, 11, 1800, 14, 5082, 5804), + (5804, 1459, 1459, 1459, 1459, 9, 78, 12561, 11, 1800, 14, 5803, 5805), + (5805, 1459, 1459, 1459, 1459, 12, 80, 12562, 11, 1800, 14, 5804, 7310), + (5806, -1, -1, 255, 255, 7, 59, -1, 0, 0, 16, -1, 5807), + (5807, -1, -1, 255, 255, 9, 59, -1, 0, 0, 16, 5806, 5808), + (5808, -1, -1, 255, 255, 12, 59, -1, 0, 0, 16, 5807, 10623), + (5809, 5833, 5833, 5833, 5833, 9, 85, 20184, 72, 900, 16, -1, -1), + (5819, 1498, 1498, 1498, 1498, 7, 76, 12563, 12, 1320, 14, 5060, 5820), + (5820, 1498, 1498, 1498, 1498, 9, 78, 12564, 12, 1320, 14, 5819, 5821), + (5821, 1498, 1498, 1498, 1498, 12, 80, 12565, 12, 1320, 14, 5820, 7408), + (5822, 757, -1, 757, 757, 7, 76, 12566, 6, 1800, 14, 5053, 5823), + (5823, 757, -1, 757, 757, 9, 78, 12567, 6, 1800, 14, 5822, 5824), + (5824, 757, -1, 757, 757, 12, 80, 12568, 6, 1800, 14, 5823, 7411), + (5825, -1, -1, 567, 567, 7, 76, -1, 0, 0, 14, 5061, -1), + (5826, 1495, 1495, 1495, 1495, 7, 76, 12569, 30, 900, 14, 5313, 5827), + (5827, 1495, 1495, 1495, 1495, 9, 78, 12570, 30, 900, 14, 5826, 5828), + (5828, 1495, 1495, 1495, 1495, 12, 80, 12571, 30, 900, 14, 5827, 7414), + (5829, 548, 548, 548, 548, 8, 77, 12572, 5, 900, 14, 5056, 5830), + (5830, 548, 548, 548, 548, 9, 78, 12573, 5, 900, 14, 5829, 5831), + (5831, 548, 548, 548, 548, 10, 79, 12574, 5, 900, 14, 5830, 7417), + (5832, 5105, 5105, 5105, 5105, 12, 80, 12575, 11, 600, 14, 5105, 7420), + (5849, 54009, 54009, 54009, 54009, 7, 73, 12576, 22, 12, 14, -1, 12923), + (5850, -1, -1, 781, 781, 8, 77, -1, 0, 0, 14, 781, 7284), + (5854, 773, -1, 773, 773, 7, 76, 12580, 5, 1800, 14, 775, 5855), + (5855, 773, -1, 773, 773, 9, 78, 12581, 5, 1800, 14, 5854, 5856), + (5856, 773, -1, 773, 773, 12, 80, 12582, 5, 1800, 14, 5855, 7276), + (5857, 1242, 1242, 1242, 1242, 7, 76, 12577, 9, 1320, 14, 1244, 5858), + (5858, 1242, 1242, 1242, 1242, 9, 78, 12578, 9, 1320, 14, 5857, 5859), + (5859, 1242, 1242, 1242, 1242, 12, 80, 12579, 9, 1320, 14, 5858, 7285), + (5860, -1, -1, 649, 649, 7, 76, -1, 0, 0, 14, 651, 5861), + (5861, -1, -1, 649, 649, 9, 78, -1, 0, 0, 14, 5860, 5862), + (5862, -1, -1, 649, 649, 12, 80, -1, 0, 0, 14, 5861, -1), + (5868, 1239, 1239, 1239, 1239, 12, 80, 13224, 6, 600, 14, 1239, 7275), + (5869, 4890, -1, 4890, 4890, 9, 77, 12587, 3, 8640, 14, 4890, 5871), + (5870, 54010, 54010, 54010, 54010, 7, 73, 12828, 22, 6, 14, -1, -1), + (5871, 4890, -1, 4890, 4890, 9, 79, 16440, 3, 8640, 15, 5869, 5872), + (5872, 4890, -1, 4890, 4890, 9, 81, 21745, 3, 8640, 16, 5871, 14280), + (5879, 167, 167, 167, 167, 10, 79, 12588, 14, 900, 14, 167, 7249), + (5880, -1, -1, 1504, 1504, 5, 76, -1, 0, 0, 14, 1506, 5881), + (5881, -1, -1, 1504, 1504, 5, 78, -1, 0, 0, 14, 5880, 5882), + (5882, -1, -1, 1504, 1504, 5, 80, -1, 0, 0, 14, 5881, 7260), + (5883, 520, 520, 520, 520, 12, 76, 12589, 6, 540, 14, 1509, 5884), + (5884, 520, 520, 520, 520, 12, 78, 12590, 6, 540, 14, 5883, 5885), + (5885, 520, 520, 520, 520, 12, 80, 12591, 6, 540, 14, 5884, 7250), + (5886, -1, -1, 1577, 1577, 7, 76, -1, 0, 0, 14, 1579, 5887), + (5887, -1, -1, 1577, 1577, 9, 78, -1, 0, 0, 14, 5886, 5888), + (5888, -1, -1, 1577, 1577, 12, 80, -1, 0, 0, 14, 5887, 7263), + (5889, -1, -1, 795, 795, 7, 76, -1, 0, 0, 14, 4899, 5890), + (5890, -1, -1, 795, 795, 9, 78, -1, 0, 0, 14, 5889, 5891), + (5891, -1, -1, 795, 795, 12, 80, -1, 0, 0, 14, 5890, 7267), + (5892, 4903, 4903, 4903, 4903, 9, 76, 12592, 9, 1320, 14, 4903, 7253), + (5893, 4906, 4906, 4906, 4906, 9, 76, 12593, 9, 1320, 14, 4906, 7254), + (5894, 4909, 4909, 4909, 4909, 9, 76, 12594, 16, 1320, 14, 4909, 7255), + (5895, 4912, 4912, 4912, 4912, 9, 76, 12595, 16, 1320, 14, 4912, 7256), + (5909, -1, -1, 815, 815, 7, 76, -1, 0, 0, 14, 5145, 5910), + (5910, -1, -1, 815, 815, 8, 77, -1, 0, 0, 14, 5909, 5911), + (5911, -1, -1, 815, 815, 9, 78, -1, 0, 0, 14, 5910, 5912), + (5912, -1, -1, 815, 815, 10, 79, -1, 0, 0, 14, 5911, 5913), + (5913, -1, -1, 815, 815, 12, 80, -1, 0, 0, 14, 5912, 7634), + (5914, 1355, 1355, 1355, 1355, 6, 76, 12596, 3, 60, 14, 5242, 5915), + (5915, 1355, 1355, 1355, 1355, 6, 78, 12597, 3, 60, 14, 5914, 5916), + (5916, 1355, 1355, 1355, 1355, 6, 80, 12598, 3, 60, 14, 5915, 7172), + (5917, -1, -1, 820, 820, 5, 76, -1, 0, 0, 14, 4815, 5918), + (5918, -1, -1, 820, 820, 5, 78, -1, 0, 0, 14, 5917, 5919), + (5919, -1, -1, 820, 820, 5, 80, -1, 0, 0, 14, 5918, 7163), + (5922, -1, -1, 807, 807, 5, 76, -1, 0, 0, 14, 1270, 5923), + (5923, -1, -1, 807, 807, 5, 78, -1, 0, 0, 14, 5922, 5924), + (5924, -1, -1, 807, 807, 5, 80, -1, 0, 0, 14, 5923, 7628), + (5939, -1, -1, 5264, 5264, 7, 76, -1, 0, 0, 14, 5268, 5940), + (5940, -1, -1, 5264, 5264, 8, 77, -1, 0, 0, 14, 5939, 5941), + (5941, -1, -1, 5264, 5264, 9, 78, -1, 0, 0, 14, 5940, 5942), + (5942, -1, -1, 5264, 5264, 10, 79, -1, 0, 0, 14, 5941, 5943), + (5943, -1, -1, 5264, 5264, 12, 80, -1, 0, 0, 14, 5942, 7204), + (5944, -1, -1, 4924, 4924, 9, 78, -1, 0, 0, 14, 4926, 5945), + (5945, -1, -1, 4924, 4924, 10, 79, -1, 0, 0, 14, 5944, 5946), + (5946, -1, -1, 4924, 4924, 12, 80, -1, 0, 0, 14, 5945, -1), + (5947, 1274, 1274, 1274, 1274, 9, 78, 12599, 9, 540, 14, 4866, 5948), + (5948, 1274, 1274, 1274, 1274, 10, 79, 12600, 9, 540, 14, 5947, 5949), + (5949, 1274, 1274, 1274, 1274, 12, 80, 12601, 9, 540, 14, 5948, 7199), + (5950, -1, -1, 1511, 1511, 12, 80, -1, 0, 0, 14, 1513, 5951), + (5951, -1, -1, 1511, 1511, 12, 80, -1, 0, 0, 14, 5950, 5952), + (5952, -1, -1, 1511, 1511, 12, 80, -1, 0, 0, 14, 5951, -1), + (5953, 184, 184, 184, 184, 10, 79, 12602, 5, 4320, 14, 184, 7203), + (5954, -1, -1, 4861, 4861, 7, 76, -1, 0, 0, 14, 4863, 5955), + (5955, -1, -1, 4861, 4861, 9, 78, -1, 0, 0, 14, 5954, 5956), + (5956, -1, -1, 4861, 4861, 12, 80, -1, 0, 0, 14, 5955, 7215), + (5969, 534, 534, 534, 534, 7, 76, 12603, 4, 2160, 14, 5043, 5970), + (5970, 534, 534, 534, 534, 9, 78, 12604, 4, 2160, 14, 5969, 5971), + (5971, 534, 534, 534, 534, 12, 80, 12605, 4, 2160, 14, 5970, 7329), + (5972, -1, -1, 593, 593, 7, 76, -1, 0, 0, 14, 595, -1), + (5973, -1, -1, 596, 596, 7, 76, -1, 0, 0, 14, 598, -1), + (5975, 5095, 5095, 5095, 5095, 7, 76, 12606, 10, 900, 14, 5097, 5976), + (5976, 5095, 5095, 5095, 5095, 9, 78, 12607, 10, 900, 14, 5975, 5977), + (5977, 5095, 5095, 5095, 5095, 12, 80, 12608, 10, 900, 14, 5976, 7332), + (5984, 5984, 5984, 5984, 5984, 12, 80, 12609, 2, 30, 14, -1, 7335), + (5999, 645, -1, 645, 645, 10, 79, 12610, 4, 5, 14, 645, 10739), + (6000, 545, 545, 545, 545, 7, 76, 12611, 3, 900, 14, 4999, 6001), + (6001, 545, 545, 545, 545, 9, 78, 12612, 3, 900, 14, 6000, 6002), + (6002, 545, 545, 545, 545, 12, 80, 12613, 3, 900, 14, 6001, 7344), + (6003, -1, -1, 1616, 1616, 7, 76, -1, 0, 0, 14, 4996, 6004), + (6004, -1, -1, 1616, 1616, 8, 77, -1, 0, 0, 14, 6003, 6005), + (6005, -1, -1, 1616, 1616, 9, 78, -1, 0, 0, 14, 6004, 6006), + (6006, -1, -1, 1616, 1616, 10, 79, -1, 0, 0, 14, 6005, 6007), + (6007, -1, -1, 1616, 1616, 12, 80, -1, 0, 0, 14, 6006, 7637), + (6008, 1345, 1345, 1345, 1345, 8, 77, 12614, 6, 900, 14, 5005, 6009), + (6009, 1345, 1345, 1345, 1345, 9, 78, 12615, 6, 900, 14, 6008, 6010), + (6010, 1345, 1345, 1345, 1345, 10, 79, 12616, 6, 900, 14, 6009, 7347), + (6011, -1, -1, 864, 864, 12, 80, -1, 0, 0, 14, 4985, 6012), + (6012, -1, -1, 864, 864, 12, 80, -1, 0, 0, 14, 6011, 6013), + (6013, -1, -1, 864, 864, 12, 80, -1, 0, 0, 14, 6012, 7353), + (6014, -1, -1, 5248, 5248, 7, 76, -1, 0, 0, 14, 5250, 6015), + (6015, -1, -1, 5248, 5248, 9, 78, -1, 0, 0, 14, 6014, 6016), + (6016, -1, -1, 5248, 5248, 12, 80, -1, 0, 0, 14, 6015, 7356), + (6017, -1, -1, 644, 644, 7, 73, -1, 0, 0, 14, 4988, 6018), + (6018, -1, -1, 644, 644, 9, 75, -1, 0, 0, 14, 6017, 6019), + (6019, -1, -1, 644, 644, 12, 77, -1, 0, 0, 14, 6018, 7359), + (6020, -1, -1, 6020, 6020, 2, 65, -1, 0, 0, 14, -1, 6021), + (6021, -1, -1, 6020, 6020, 2, 65, -1, 0, 0, 14, 6020, 6022), + (6022, -1, -1, 6020, 6020, 2, 65, -1, 0, 0, 14, 6021, 6045), + (6023, -1, -1, 119, 119, 12, 85, -1, 0, 0, 16, 7567, 6024), + (6024, -1, -1, 119, 119, 12, 85, -1, 0, 0, 16, 6023, 6025), + (6025, -1, -1, 119, 119, 12, 85, -1, 0, 0, 16, 6024, 12548), + (6026, -1, -1, 1004, 1004, 7, 81, -1, 0, 0, 16, -1, 6027), + (6027, -1, -1, 1004, 1004, 9, 81, -1, 0, 0, 16, 6026, 6028), + (6028, -1, -1, 1004, 1004, 12, 81, -1, 0, 0, 16, 6027, -1), + (6029, -1, -1, 1304, 1304, 7, 76, -1, 0, 0, 14, 1306, 6030), + (6030, -1, -1, 1304, 1304, 9, 78, -1, 0, 0, 14, 6029, 6031), + (6031, -1, -1, 1304, 1304, 12, 80, -1, 0, 0, 14, 6030, 7148), + (6032, -1, -1, 1604, 1604, 7, 69, -1, 0, 0, 14, 5294, 6033), + (6033, -1, -1, 1604, 1604, 9, 71, -1, 0, 0, 14, 6032, 6034), + (6034, -1, -1, 1604, 1604, 12, 73, -1, 0, 0, 14, 6033, 7131), + (6035, -1, -1, 846, 846, 7, 76, -1, 0, 0, 14, 4950, 6036), + (6036, -1, -1, 846, 846, 9, 78, -1, 0, 0, 14, 6035, 6037), + (6037, -1, -1, 846, 846, 12, 80, -1, 0, 0, 14, 6036, 7151), + (6038, 5022, 5022, 5022, 5022, 7, 76, 23988, 5, 600, 14, 5024, 6039), + (6039, 5022, 5022, 5022, 5022, 9, 78, 23989, 5, 600, 14, 6038, 6040), + (6040, 5022, 5022, 5022, 5022, 12, 80, 23990, 5, 600, 14, 6039, 15628), + (6041, 5028, -1, 5028, 5028, 9, 78, 12621, 4, 900, 14, 5028, -1), + (6042, -1, -1, 1543, 1543, 7, 76, -1, 0, 0, 14, 4953, 6043), + (6043, -1, -1, 1543, 1543, 9, 78, -1, 0, 0, 14, 6042, 6044), + (6044, -1, -1, 1543, 1543, 12, 80, -1, 0, 0, 14, 6043, 7134), + (6045, -1, -1, 6020, 6020, 2, 66, -1, 0, 0, 14, 6022, 6046), + (6046, -1, -1, 6020, 6020, 2, 68, -1, 0, 0, 14, 6045, 6047), + (6047, -1, -1, 6020, 6020, 2, 70, -1, 0, 0, 14, 6046, 6048), + (6048, -1, -1, 6020, 6020, 2, 71, -1, 0, 0, 14, 6047, 6049), + (6049, -1, -1, 6020, 6020, 2, 73, -1, 0, 0, 14, 6048, 6050), + (6050, -1, -1, 6020, 6020, 2, 75, -1, 0, 0, 14, 6049, 6057), + (6051, -1, -1, 6051, 6051, 3, 76, -1, 0, 0, 14, -1, 6052), + (6052, -1, -1, 6051, 6051, 3, 78, -1, 0, 0, 14, 6051, 6053), + (6053, -1, -1, 6051, 6051, 3, 80, -1, 0, 0, 14, 6052, 7601), + (6054, 4931, 4931, 4931, 4931, 7, 76, 12756, 4, 600, 14, 4933, 6055), + (6055, 4931, 4931, 4931, 4931, 7, 78, 12757, 4, 600, 14, 6054, 6056), + (6056, 4931, 4931, 4931, 4931, 7, 80, 12758, 4, 600, 14, 6055, 7291), + (6057, -1, -1, 6020, 6020, 2, 76, -1, 0, 0, 14, 6050, 6058), + (6058, -1, -1, 6020, 6020, 2, 78, -1, 0, 0, 14, 6057, 6059), + (6059, -1, -1, 6020, 6020, 2, 80, -1, 0, 0, 14, 6058, 7169), + (6060, -1, -1, 6540, 6540, 8, 76, -1, 0, 0, 14, -1, 6061), + (6061, -1, -1, 6540, 6540, 8, 76, -1, 0, 0, 14, 6060, 6470), + (6063, -1, -1, 589, 589, 7, 76, -1, 0, 0, 14, 5272, 6064), + (6064, -1, -1, 589, 589, 9, 78, -1, 0, 0, 14, 6063, 6065), + (6065, -1, -1, 589, 589, 12, 80, -1, 0, 0, 14, 6064, 7390), + (6066, -1, -1, 1313, 1313, 7, 76, -1, 0, 0, 14, 5031, 6067), + (6067, -1, -1, 1313, 1313, 7, 76, -1, 0, 0, 14, 6066, 6068), + (6068, -1, -1, 1313, 1313, 8, 77, -1, 0, 0, 14, 6067, 6069), + (6069, -1, -1, 1313, 1313, 9, 78, -1, 0, 0, 14, 6068, 6070), + (6070, -1, -1, 1313, 1313, 10, 79, -1, 0, 0, 14, 6069, 6071), + (6071, -1, -1, 1313, 1313, 12, 80, -1, 0, 0, 14, 6070, 7393), + (6072, -1, -1, 210, 210, 8, 77, -1, 0, 0, 14, 1318, 6073), + (6073, -1, -1, 210, 210, 9, 78, -1, 0, 0, 14, 6072, 6074), + (6074, -1, -1, 210, 210, 10, 79, -1, 0, 0, 14, 6073, 7399), + (6075, -1, -1, 895, 895, 7, 76, -1, 0, 0, 14, 899, 6076), + (6076, -1, -1, 895, 895, 8, 77, -1, 0, 0, 14, 6075, 6077), + (6077, -1, -1, 895, 895, 9, 78, -1, 0, 0, 14, 6076, 6078), + (6078, -1, -1, 895, 895, 10, 79, -1, 0, 0, 14, 6077, 6079), + (6079, -1, -1, 895, 895, 12, 80, -1, 0, 0, 14, 6078, 7402), + (6080, -1, -1, 683, 683, 5, 75, -1, 0, 0, 14, 5305, 6081), + (6081, -1, -1, 683, 683, 5, 75, -1, 0, 0, 14, 6080, 7604), + (6082, -1, -1, 6084, 6084, 5, 85, 0, 0, 0, 17, -1, 6083), + (6083, -1, -1, 6084, 6084, 5, 87, 0, 0, 0, 17, 6082, 6084), + (6084, -1, -1, 6084, 6084, 5, 89, 0, 0, 0, 17, 6083, 13366), + (6085, -1, -1, 6761, 6761, 10, 81, -1, 0, 0, 16, 6763, 6086), + (6086, -1, -1, 6761, 6761, 11, 83, -1, 0, 0, 16, 6085, 6087), + (6087, -1, -1, 6761, 6761, 12, 85, -1, 0, 0, 16, 6086, 10763), + (6088, -1, -1, 6088, 6088, 9, 85, 0, 0, 0, 17, -1, 6089), + (6089, -1, -1, 6088, 6088, 12, 87, 0, 0, 0, 17, 6088, 6090), + (6090, -1, -1, 6088, 6088, 15, 89, 0, 0, 0, 17, 6089, -1), + (6092, 5251, 5251, 5251, 5251, 7, 76, 12635, 13, 900, 14, 5253, 6093), + (6093, 5251, 5251, 5251, 5251, 9, 78, 12636, 13, 900, 14, 6092, 6094), + (6094, 5251, 5251, 5251, 5251, 12, 80, 12637, 13, 900, 14, 6093, 7472), + (6095, 513, 513, 513, 513, 7, 76, 12638, 4, 120, 14, 515, 6096), + (6096, 513, 513, 513, 513, 9, 78, 12639, 4, 120, 14, 6095, 6097), + (6097, 513, 513, 513, 513, 12, 80, 12640, 4, 120, 14, 6096, 7475), + (6098, 1327, 1327, 1327, 1327, 7, 76, 12641, 10, 900, 14, 5316, 6099), + (6099, 1327, 1327, 1327, 1327, 9, 78, 12642, 10, 900, 14, 6098, 6100), + (6100, 1327, 1327, 1327, 1327, 12, 80, 12643, 10, 900, 14, 6099, 7460), + (6101, 153, 153, 153, 153, 12, 80, 12644, 3, 2160, 14, 5068, 7468), + (6102, 146, 146, 146, 146, 8, 77, 12645, 2, 180, 14, 5069, 7466), + (6103, 528, 528, 528, 528, 7, 76, 12646, 5, 720, 14, 901, 6104), + (6104, 528, 528, 528, 528, 9, 78, 12647, 5, 720, 14, 6103, 6105), + (6105, 528, 528, 528, 528, 12, 80, 12648, 5, 720, 14, 6104, 7469), + (6106, 6106, 6106, 6106, 6106, 4, 67, 21965, 13, 4320, 16, -1, 6107), + (6107, 6106, 6106, 6106, 6106, 5, 68, 21966, 13, 4320, 16, 6106, 6108), + (6108, 6106, 6106, 6106, 6106, 6, 69, 21967, 13, 4320, 16, 6107, 6109), + (6109, 6106, 6106, 6106, 6106, 7, 77, 21968, 13, 4320, 16, 6108, 6110), + (6110, 6106, 6106, 6106, 6106, 8, 78, 21969, 13, 4320, 16, 6109, 6111), + (6111, 6106, 6106, 6106, 6106, 9, 79, 21970, 13, 4320, 16, 6110, -1), + (6112, -1, -1, 6112, 6112, 5, 85, -1, 0, 0, 17, -1, 12966), + (6113, -1, -1, 6113, 6113, 9, 85, 0, 0, 0, 17, -1, 6114), + (6114, -1, -1, 6113, 6113, 12, 87, 0, 0, 0, 17, 6113, 6115), + (6115, -1, -1, 6113, 6113, 15, 89, 0, 0, 0, 17, 6114, -1), + (6119, -1, -1, 6119, 6119, 6, 76, -1, 0, 0, 14, -1, 6120), + (6120, -1, -1, 6119, 6119, 6, 77, -1, 0, 0, 14, 6119, 6121), + (6121, -1, -1, 6119, 6119, 6, 78, -1, 0, 0, 14, 6120, 6122), + (6122, -1, -1, 6119, 6119, 6, 79, -1, 0, 0, 14, 6121, 6123), + (6123, -1, -1, 6119, 6119, 6, 80, -1, 0, 0, 14, 6122, 7526), + (6124, -1, -1, 5263, 5263, 3, 71, -1, 0, 0, 12, -1, 6125), + (6125, -1, -1, 5263, 5263, 6, 73, -1, 0, 0, 12, 6124, 6126), + (6126, -1, -1, 5263, 5263, 9, 75, -1, 0, 0, 12, 6125, 6127), + (6127, -1, -1, 5263, 5263, 10, 76, -1, 0, 0, 14, 6126, 6128), + (6128, -1, -1, 5263, 5263, 11, 78, -1, 0, 0, 14, 6127, 6129), + (6129, -1, -1, 5263, 5263, 12, 80, -1, 0, 0, 14, 6128, 12463), + (6130, -1, -1, 586, 586, 7, 76, -1, 0, 0, 14, 588, 6131), + (6131, -1, -1, 586, 586, 7, 76, -1, 0, 0, 14, 6130, 6132), + (6132, -1, -1, 586, 586, 7, 76, -1, 0, 0, 14, 6131, -1), + (6133, 1351, 1351, 1351, 1351, 8, 77, 12649, 5, 30, 14, 1351, 7109), + (6134, 4849, 4849, 4849, 4849, 7, 76, 12650, 7, 1800, 14, 4849, 7110), + (6135, 54006, 54006, 54006, 54006, 7, 76, 12651, 18, 180, 14, -1, 7111), + (6136, -1, -1, 6136, 6136, 7, 76, -1, 0, 0, 10, -1, 6137), + (6149, 921, 921, 921, 921, 9, 79, 12652, 8, 60, 14, 5280, 7245), + (6150, 922, 922, 922, 922, 9, 78, 12653, 8, 60, 14, 5281, 7236), + (6151, 923, 923, 923, 923, 9, 77, 12654, 8, 60, 14, 5282, 7235), + (6152, 1334, 1334, 1334, 1334, 9, 78, 12655, 11, 4320, 14, 1336, 6153), + (6153, 1334, 1334, 1334, 1334, 10, 79, 12656, 11, 4320, 14, 6152, 6154), + (6154, 1334, 1334, 1334, 1334, 12, 80, 12657, 11, 4320, 14, 6153, 7239), + (6155, 4944, -1, 4944, 4944, 7, 76, 12658, 0, 1, 14, 4946, 6156), + (6156, 4944, -1, 4944, 4944, 9, 78, 12659, 0, 1, 14, 6155, 6157), + (6157, 4944, -1, 4944, 4944, 12, 80, 12660, 0, 1, 14, 6156, 7229), + (6158, 1337, 1337, 1337, 1337, 8, 77, 12661, 13, 4320, 14, 1339, 6159), + (6159, 1337, 1337, 1337, 1337, 9, 78, 12662, 13, 4320, 14, 6158, 6160), + (6160, 1337, 1337, 1337, 1337, 10, 79, 12663, 13, 4320, 14, 6159, 14338), + (6161, 1478, -1, 1478, 1478, 9, 78, 12664, 0, 1, 14, 1480, 6162), + (6162, 1478, -1, 1478, 1478, 10, 79, 12665, 0, 1, 14, 6161, 6163), + (6163, 1478, -1, 1478, 1478, 12, 80, 12666, 0, 1, 14, 6162, 7242), + (6200, 6533, 6533, 6533, 6533, 10, 79, 12768, 15, 600, 14, -1, 7428), + (6201, 6534, 6534, 6534, 6534, 9, 78, 12769, 16, 900, 14, -1, 7429), + (6202, -1, -1, 6535, 6535, 5, 70, -1, 0, 0, 14, -1, 6203), + (6203, -1, -1, 6535, 6535, 5, 70, -1, 0, 0, 14, 6202, 6204), + (6204, -1, -1, 6535, 6535, 5, 70, -1, 0, 0, 14, 6203, -1), + (6205, 6536, 6536, 6536, 6536, 7, 76, 12712, 39, 5, 14, -1, -1), + (6206, 6537, 6537, 6537, 6537, 7, 76, 12770, 30, 900, 14, -1, 6207), + (6207, 6537, 6537, 6537, 6537, 8, 77, 12771, 30, 900, 14, 6206, 6208), + (6208, 6537, 6537, 6537, 6537, 9, 78, 12772, 30, 900, 14, 6207, 7606), + (6209, -1, -1, 6538, 6538, 7, 76, -1, 0, 0, 14, -1, 6210), + (6210, -1, -1, 6538, 6538, 9, 78, -1, 0, 0, 14, 6209, 6211), + (6211, -1, -1, 6538, 6538, 12, 80, -1, 0, 0, 14, 6210, 7478), + (6212, 6539, 6539, 6539, 6539, 6, 71, 12776, 18, 1800, 14, -1, 6213), + (6213, 6539, 6539, 6539, 6539, 6, 74, 12777, 18, 1800, 14, 6212, 6214), + (6214, 6539, 6539, 6539, 6539, 6, 77, 12778, 18, 1800, 14, 6213, 7609), + (6215, -1, -1, 6540, 6540, 8, 71, -1, 0, 0, 14, -1, 6216), + (6216, -1, -1, 6540, 6540, 8, 72, -1, 0, 0, 14, 6215, 6217), + (6217, -1, -1, 6540, 6540, 8, 73, -1, 0, 0, 14, 6216, 6300), + (6218, 6218, 6218, 6218, 6218, 7, 76, 12782, 0, 1, 14, -1, 7488), + (6219, 6542, 6542, 6542, 6542, 7, 76, 12783, 18, 1800, 14, -1, 6220), + (6220, 6542, 6542, 6542, 6542, 9, 78, 12784, 18, 1800, 14, 6219, 6221), + (6221, 6542, 6542, 6542, 6542, 12, 80, 12785, 18, 1800, 14, 6220, -1), + (6222, 6543, 6543, 6543, 6543, 9, 72, 13143, 18, 25, 14, -1, -1), + (6223, -1, -1, 962, 962, 5, 76, -1, 0, 0, 14, 966, 6224), + (6224, -1, -1, 962, 962, 5, 77, -1, 0, 0, 14, 6223, 6225), + (6225, -1, -1, 962, 962, 5, 78, -1, 0, 0, 14, 6224, 6226), + (6226, -1, -1, 962, 962, 5, 79, -1, 0, 0, 14, 6225, 6227), + (6227, -1, -1, 962, 962, 5, 80, -1, 0, 0, 14, 6226, 10361), + (6228, -1, -1, 6545, 6545, 2, 70, -1, 0, 0, 14, -1, 6229), + (6229, -1, -1, 6545, 6545, 2, 70, -1, 0, 0, 14, 6228, 6230), + (6230, -1, -1, 6545, 6545, 2, 70, -1, 0, 0, 14, 6229, 6231), + (6231, -1, -1, 6545, 6545, 2, 70, -1, 0, 0, 14, 6230, -1), + (6232, 6232, 6232, 6232, 6232, 12, 80, 14413, 18, 900, 14, -1, 7421), + (6233, -1, -1, 477, 477, 2, 70, -1, 0, 0, 14, 479, 6234), + (6234, -1, -1, 477, 477, 2, 71, -1, 0, 0, 14, 6233, 6235), + (6235, -1, -1, 477, 477, 2, 72, -1, 0, 0, 14, 6234, 16094), + (6236, -1, -1, 6548, 6548, 6, 73, -1, 0, 0, 14, -1, 6237), + (6237, -1, -1, 6548, 6548, 6, 75, -1, 0, 0, 14, 6236, 6238), + (6238, -1, -1, 6548, 6548, 8, 77, -1, 0, 0, 14, 6237, 12929), + (6240, -1, -1, 767, 767, 3, 65, -1, 0, 0, 14, -1, 6241), + (6241, -1, -1, 767, 767, 6, 65, -1, 0, 0, 14, 6240, 6242), + (6242, -1, -1, 767, 767, 9, 65, -1, 0, 0, 14, 6241, 6243), + (6243, -1, -1, 767, 767, 3, 67, -1, 0, 0, 14, 6242, 6244), + (6244, -1, -1, 767, 767, 6, 68, -1, 0, 0, 14, 6243, 6245), + (6245, -1, -1, 767, 767, 9, 69, -1, 0, 0, 14, 6244, 12426), + (6249, 6552, 6552, 6552, 6552, 5, 70, -1, 0, 0, 14, -1, 6250), + (6250, 6552, 6552, 6552, 6552, 6, 72, -1, 0, 0, 14, 6249, 6251), + (6251, 6552, 6552, 6552, 6552, 6, 74, -1, 0, 0, 14, 6250, 6252), + (6252, 6552, 6552, 6552, 6552, 7, 76, -1, 0, 0, 14, 6251, 6253), + (6253, 6552, 6552, 6552, 6552, 9, 78, -1, 0, 0, 14, 6252, 7279), + (6254, 616, 616, 616, 616, 6, 73, 12765, 7, 900, 14, 1250, 6255), + (6255, 616, 616, 616, 616, 7, 76, 12766, 7, 900, 14, 6254, 6256), + (6256, 616, 616, 616, 616, 10, 79, 12767, 7, 900, 14, 6255, 7257), + (6257, -1, -1, 86, 86, 2, 55, -1, 0, 0, 14, -1, 6258), + (6258, -1, -1, 86, 86, 4, 55, -1, 0, 0, 14, 6257, 6259), + (6259, -1, -1, 86, 86, 6, 55, -1, 0, 0, 14, 6258, 8223), + (6260, -1, -1, 495, 495, 6, 73, -1, 0, 0, 14, 497, 6261), + (6261, -1, -1, 495, 495, 7, 76, -1, 0, 0, 14, 6260, 6262), + (6262, -1, -1, 495, 495, 10, 79, -1, 0, 0, 14, 6261, 10666), + (6266, -1, -1, 6557, 6557, 6, 73, -1, 0, 0, 14, -1, 6267), + (6267, -1, -1, 6557, 6557, 7, 76, -1, 0, 0, 14, 6266, 6268), + (6268, -1, -1, 6557, 6557, 10, 79, -1, 0, 0, 14, 6267, -1), + (6269, -1, -1, 6558, 6558, 6, 73, -1, 0, 0, 14, -1, 6270), + (6270, -1, -1, 6558, 6558, 7, 76, -1, 0, 0, 14, 6269, 6271), + (6271, -1, -1, 6558, 6558, 10, 79, -1, 0, 0, 14, 6270, -1), + (6272, -1, -1, 6559, 6559, 6, 73, -1, 0, 0, 14, -1, 6273), + (6273, -1, -1, 6559, 6559, 7, 75, -1, 0, 0, 14, 6272, 6274), + (6274, -1, -1, 6559, 6559, 10, 77, -1, 0, 0, 14, 6273, 7137), + (6275, -1, -1, 6560, 6560, 6, 73, -1, 0, 0, 14, -1, 6276), + (6276, -1, -1, 6560, 6560, 7, 76, -1, 0, 0, 14, 6275, 6277), + (6277, -1, -1, 6560, 6560, 10, 79, -1, 0, 0, 14, 6276, 16266), + (6278, 6561, 6561, 6561, 6561, 7, 76, 12795, 32, 30, 14, -1, 6279), + (6279, 6561, 6561, 6561, 6561, 7, 76, 12796, 32, 30, 14, 6278, 6280), + (6280, 6561, 6561, 6561, 6561, 7, 76, 12797, 32, 30, 14, 6279, 7422), + (6281, 6563, 6563, 6563, 6563, 9, 78, 13144, 36, 8, 14, -1, 12995), + (6282, 6562, 6562, 6562, 6562, 6, 72, 12798, 39, 1, 14, -1, -1), + (6283, -1, -1, 6564, 6564, 6, 73, -1, 0, 0, 14, -1, 6284), + (6284, -1, -1, 6564, 6564, 7, 76, -1, 0, 0, 14, 6283, 6285), + (6285, -1, -1, 6564, 6564, 10, 79, -1, 0, 0, 14, 6284, 7112), + (6286, 6565, 6565, 6565, 6565, 7, 76, 12802, 17, 45, 14, -1, 7115), + (6287, -1, -1, 6566, 6566, 6, 73, -1, 0, 0, 14, -1, 6288), + (6288, -1, -1, 6566, 6566, 7, 76, -1, 0, 0, 14, 6287, 6289), + (6289, -1, -1, 6566, 6566, 10, 79, -1, 0, 0, 14, 6288, -1), + (6290, 6290, 6290, 6290, 6290, 6, 71, 12803, 0, 1, 14, -1, 6291), + (6291, 6290, 6290, 6290, 6290, 6, 73, 12804, 0, 1, 14, 6290, 6292), + (6292, 6290, 6290, 6290, 6290, 6, 75, 12805, 0, 1, 14, 6291, 6293), + (6293, 6290, 6290, 6290, 6290, 7, 76, 12806, 0, 1, 14, 6292, 6294), + (6294, 6290, 6290, 6290, 6290, 9, 78, 12807, 0, 1, 14, 6293, 6295), + (6295, 6290, 6290, 6290, 6290, 12, 80, 12808, 0, 1, 14, 6294, 7223), + (6296, 619, 619, 619, 619, 6, 73, 12759, 6, 900, 14, 722, 6297), + (6297, 619, 619, 619, 619, 6, 73, 12760, 6, 900, 14, 6296, 6298), + (6298, 619, 619, 619, 619, 6, 73, 12761, 6, 900, 14, 6297, 7226), + (6299, 6299, 6299, 6299, 6299, 9, 65, 12786, 18, 12, 14, -1, -1), + (6300, -1, -1, 6540, 6540, 8, 74, -1, 0, 0, 14, 6217, 6301), + (6301, -1, -1, 6540, 6540, 8, 75, -1, 0, 0, 14, 6300, 6472), + (6302, -1, -1, 6302, 6302, 5, 81, 0, 0, 0, 16, -1, 6303), + (6303, -1, -1, 6302, 6302, 5, 83, 0, 0, 0, 16, 6302, 6304), + (6304, -1, -1, 6302, 6302, 5, 85, 0, 0, 0, 16, 6303, 11011), + (6307, 1358, 1358, 1358, 1358, 6, 71, 13168, 3, 60, 14, 1360, 6308), + (6308, 1358, 1358, 1358, 1358, 6, 73, 13169, 3, 60, 14, 6307, 6309), + (6309, 1358, 1358, 1358, 1358, 6, 75, 13170, 3, 60, 14, 6308, 6310), + (6310, 1358, 1358, 1358, 1358, 6, 76, 13171, 3, 60, 14, 6309, 6311), + (6311, 1358, 1358, 1358, 1358, 6, 78, 13172, 3, 60, 14, 6310, 6312), + (6312, 1358, 1358, 1358, 1358, 6, 80, 13173, 3, 60, 14, 6311, 7157), + (6313, 1352, 1352, 1352, 1352, 6, 71, 13174, 3, 60, 14, 1354, 6314), + (6314, 1352, 1352, 1352, 1352, 6, 73, 13175, 3, 60, 14, 6313, 6315), + (6315, 1352, 1352, 1352, 1352, 6, 75, 13177, 3, 60, 14, 6314, 6316), + (6316, 1352, 1352, 1352, 1352, 6, 76, 13178, 3, 60, 14, 6315, 6317), + (6317, 1352, 1352, 1352, 1352, 6, 78, 13179, 3, 60, 14, 6316, 6318), + (6318, 1352, 1352, 1352, 1352, 6, 80, 13180, 3, 60, 14, 6317, 7154), + (6319, -1, -1, 501, 501, 6, 73, -1, 0, 0, 14, 503, 6320), + (6320, -1, -1, 501, 501, 6, 75, -1, 0, 0, 14, 6319, 6321), + (6321, -1, -1, 501, 501, 6, 77, -1, 0, 0, 14, 6320, 6528), + (6322, -1, -1, 6322, 6322, 6, 73, -1, 0, 0, 14, -1, 6323), + (6323, -1, -1, 6322, 6322, 6, 75, -1, 0, 0, 14, 6322, 6324), + (6324, -1, -1, 6322, 6322, 6, 77, -1, 0, 0, 14, 6323, -1), + (6325, 6325, 6325, 6325, 6325, 7, 73, 13213, 18, 600, 14, -1, 6326), + (6326, 6325, 6325, 6325, 6325, 7, 75, 13214, 18, 600, 14, 6325, 6327), + (6327, 6325, 6325, 6325, 6325, 7, 77, 13215, 18, 600, 14, 6326, 6361), + (6328, 6328, 6328, 6328, 6328, 7, 74, 13204, 10, 600, 14, -1, 6329), + (6329, 6328, 6328, 6328, 6328, 7, 76, 13205, 10, 600, 14, 6328, 6330), + (6330, 6328, 6328, 6328, 6328, 7, 78, 13212, 10, 600, 14, 6329, 7143), + (6331, -1, -1, 878, 878, 7, 76, -1, 0, 0, 14, 4959, 6332), + (6332, -1, -1, 878, 878, 7, 78, -1, 0, 0, 14, 6331, 7146), + (6333, 6333, 6333, 6333, 6333, 9, 59, 13167, 3, 600, 14, -1, 7266), + (6334, -1, -1, 6334, 6334, 6, 73, -1, 0, 0, 14, -1, 6335), + (6335, -1, -1, 6334, 6334, 6, 75, -1, 0, 0, 14, 6334, 6336), + (6336, -1, -1, 6334, 6334, 6, 77, -1, 0, 0, 14, 6335, -1), + (6337, -1, -1, 6337, 6337, 6, 74, -1, 0, 0, 14, -1, 6338), + (6338, -1, -1, 6337, 6337, 6, 76, -1, 0, 0, 14, 6337, 6339), + (6339, -1, -1, 6337, 6337, 6, 78, -1, 0, 0, 14, 6338, 7448), + (6340, -1, -1, 6340, 6340, 6, 74, -1, 0, 0, 14, -1, 6341), + (6341, -1, -1, 6340, 6340, 6, 76, -1, 0, 0, 14, 6340, 6342), + (6342, -1, -1, 6340, 6340, 6, 78, -1, 0, 0, 14, 6341, 7451), + (6343, -1, -1, 6343, 6343, 6, 74, -1, 0, 0, 14, -1, 6344), + (6344, -1, -1, 6343, 6343, 6, 76, -1, 0, 0, 14, 6343, 6345), + (6345, -1, -1, 6343, 6343, 6, 78, -1, 0, 0, 14, 6344, 7166), + (6346, -1, -1, 6346, 6346, 6, 74, -1, 0, 0, 14, -1, 6347), + (6347, -1, -1, 6346, 6346, 6, 76, -1, 0, 0, 14, 6346, 6348), + (6348, -1, -1, 6346, 6346, 6, 78, -1, 0, 0, 14, 6347, 7615), + (6349, -1, -1, 6349, 6349, 6, 74, -1, 0, 0, 14, -1, 6350), + (6350, -1, -1, 6349, 6349, 6, 76, -1, 0, 0, 14, 6349, 6351), + (6351, -1, -1, 6349, 6349, 6, 78, -1, 0, 0, 14, 6350, 7618), + (6352, 4894, 4894, 4894, 4894, 6, 76, 13181, 7, 2160, 14, 4896, 6353), + (6353, 4894, 4894, 4894, 4894, 6, 77, 13182, 7, 2160, 14, 6352, 6354), + (6354, 4894, 4894, 4894, 4894, 6, 78, 13183, 7, 2160, 14, 6353, 7288), + (6355, -1, -1, 6355, 6355, 6, 73, -1, 0, 0, 14, -1, 6356), + (6356, -1, -1, 6355, 6355, 6, 74, -1, 0, 0, 14, 6355, 6357), + (6357, -1, -1, 6355, 6355, 6, 75, -1, 0, 0, 14, 6356, 6358), + (6358, -1, -1, 6355, 6355, 6, 76, -1, 0, 0, 14, 6357, 6359), + (6359, -1, -1, 6355, 6355, 6, 77, -1, 0, 0, 14, 6358, 6360), + (6360, -1, -1, 6355, 6355, 6, 80, -1, 0, 0, 16, 6359, 14101), + (6361, 6325, 6325, 6325, 6325, 7, 81, 16861, 18, 600, 16, 6327, 12633), + (6362, -1, -1, 6362, 6362, 5, 77, 0, 0, 0, 16, -1, 6363), + (6363, -1, -1, 6362, 6362, 5, 79, 0, 0, 0, 16, 6362, 6364), + (6364, -1, -1, 6362, 6362, 5, 81, 0, 0, 0, 16, 6363, 6365), + (6365, -1, -1, 6362, 6362, 5, 83, 0, 0, 0, 16, 6364, 6366), + (6366, -1, -1, 6362, 6362, 5, 85, 0, 0, 0, 16, 6365, 16327), + (6370, 6370, 6370, 6370, 6370, 6, 76, 13188, 7, 600, 14, -1, 6371), + (6371, 6370, 6370, 6370, 6370, 6, 77, 13189, 7, 600, 14, 6370, 6372), + (6372, 6370, 6370, 6370, 6370, 6, 78, 13190, 7, 600, 14, 6371, 7350), + (6375, -1, -1, 6375, 6375, 6, 76, -1, 0, 0, 14, -1, 6376), + (6376, -1, -1, 6375, 6375, 6, 77, -1, 0, 0, 14, 6375, 6377), + (6377, -1, -1, 6375, 6375, 6, 78, -1, 0, 0, 14, 6376, 7644), + (6378, 209, 209, 209, 1272, 6, 76, 13501, 12, 5, 14, 1272, -1), + (6379, 6379, 6379, 6379, 6379, 6, 60, 13500, 37, 5, 14, -1, -1), + (6380, 6380, 6380, 6380, 6380, 6, 78, 13209, 39, 120, 14, -1, 6381), + (6381, 6380, 6380, 6380, 6380, 6, 79, 13210, 39, 120, 14, 6380, 6382), + (6382, 6380, 6380, 6380, 6380, 6, 80, 13211, 39, 120, 14, 6381, 7497), + (6383, -1, -1, 6383, 6383, 3, 70, -1, 0, 0, 14, -1, 6384), + (6384, -1, -1, 6383, 6383, 6, 70, -1, 0, 0, 14, 6383, 6385), + (6385, -1, -1, 6383, 6383, 9, 70, -1, 0, 0, 14, 6384, 10607), + (6386, -1, -1, 6386, 6386, 7, 72, -1, 0, 0, 14, -1, 6387), + (6387, -1, -1, 6386, 6386, 7, 74, -1, 0, 0, 14, 6386, 6388), + (6388, -1, -1, 6386, 6386, 7, 76, -1, 0, 0, 14, 6387, 6389), + (6389, -1, -1, 6386, 6386, 7, 78, -1, 0, 0, 14, 6388, 13521), + (6390, -1, -1, 65, 661, 3, 76, -1, 0, 0, 14, 4697, 6391), + (6391, -1, -1, 65, 661, 3, 77, -1, 0, 0, 14, 6390, 6392), + (6392, -1, -1, 65, 661, 3, 78, -1, 0, 0, 14, 6391, 6393), + (6393, -1, -1, 65, 661, 3, 79, -1, 0, 0, 14, 6392, 6394), + (6394, -1, -1, 65, 661, 3, 80, -1, 0, 0, 14, 6393, 7534), + (6395, -1, -1, 6395, 6395, 7, 76, -1, 0, 0, 14, -1, 6396), + (6396, -1, -1, 6395, 6395, 7, 77, -1, 0, 0, 14, 6395, 6397), + (6397, -1, -1, 6395, 6395, 7, 78, -1, 0, 0, 14, 6396, 7336), + (6398, 516, 516, 516, 516, 6, 72, 13198, 5, 480, 14, 516, 7237), + (6400, 1110, 1110, 1110, 1110, 6, 73, 13192, 3, 2160, 14, 1112, 6401), + (6401, 1110, 1110, 1110, 1110, 6, 75, 13193, 3, 2160, 14, 6400, 6402), + (6402, 1110, 1110, 1110, 1110, 6, 76, 13194, 3, 2160, 14, 6401, 7445), + (6403, -1, -1, 1107, 1107, 7, 76, -1, 0, 0, 14, 5288, 6404), + (6404, -1, -1, 1107, 1107, 9, 78, -1, 0, 0, 14, 6403, 6405), + (6405, -1, -1, 1107, 1107, 12, 80, -1, 0, 0, 14, 6404, 12432), + (6406, -1, -1, 5085, 5085, 6, 76, -1, 0, 0, 14, 5087, 6407), + (6407, -1, -1, 5085, 5085, 6, 78, -1, 0, 0, 14, 6406, 6408), + (6408, -1, -1, 5085, 5085, 6, 80, -1, 0, 0, 14, 6407, 7384), + (6409, -1, -1, 6540, 6540, 8, 71, -1, 0, 0, 14, -1, 6410), + (6410, -1, -1, 6540, 6540, 8, 72, -1, 0, 0, 14, 6409, 6411), + (6411, -1, -1, 6540, 6540, 8, 73, -1, 0, 0, 14, 6410, 6412), + (6412, -1, -1, 6540, 6540, 8, 74, -1, 0, 0, 14, 6411, 6413), + (6413, -1, -1, 6540, 6540, 8, 75, -1, 0, 0, 14, 6412, 6414), + (6414, -1, -1, 6540, 6540, 8, 76, -1, 0, 0, 14, 6413, 6415), + (6415, -1, -1, 6540, 6540, 8, 77, -1, 0, 0, 14, 6414, 6416), + (6416, -1, -1, 6540, 6540, 8, 78, -1, 0, 0, 14, 6415, 6417), + (6417, -1, -1, 6540, 6540, 8, 79, -1, 0, 0, 14, 6416, 6418), + (6418, -1, -1, 6540, 6540, 8, 80, -1, 0, 0, 14, 6417, 6474), + (6419, -1, -1, 6540, 6540, 8, 71, -1, 0, 0, 14, -1, 6420), + (6420, -1, -1, 6540, 6540, 8, 72, -1, 0, 0, 14, 6419, 6421), + (6421, -1, -1, 6540, 6540, 8, 73, -1, 0, 0, 14, 6420, 6476), + (6422, -1, -1, 6422, 6422, 3, 61, -1, 0, 0, 14, -1, 6423), + (6423, -1, -1, 6422, 6422, 3, 63, -1, 0, 0, 14, 6422, 6424), + (6424, -1, -1, 6422, 6422, 3, 65, -1, 0, 0, 14, 6423, -1), + (6425, 5007, 5007, 5007, 5007, 9, 76, 13509, 8, 2160, 14, 5009, 6426), + (6426, 5007, 5007, 5007, 5007, 9, 78, 13510, 8, 2160, 14, 6425, 6427), + (6427, 5007, 5007, 5007, 5007, 9, 80, 13511, 8, 2160, 14, 6426, 7341), + (6428, -1, -1, 1287, 1287, 3, 67, -1, 0, 0, 14, -1, 6429), + (6429, -1, -1, 1287, 1287, 6, 68, -1, 0, 0, 14, 6428, 6430), + (6430, -1, -1, 1287, 1287, 9, 69, -1, 0, 0, 14, 6429, 12472), + (6431, -1, -1, 1056, 1056, 5, 76, -1, 0, 0, 14, 1060, 6432), + (6432, -1, -1, 1056, 1056, 5, 77, -1, 0, 0, 14, 6431, 6433), + (6433, -1, -1, 1056, 1056, 5, 78, -1, 0, 0, 14, 6432, 6434), + (6434, -1, -1, 1056, 1056, 5, 79, -1, 0, 0, 14, 6433, 6435), + (6435, -1, -1, 1056, 1056, 5, 80, -1, 0, 0, 14, 6434, 7521), + (6436, -1, -1, 6436, 6436, 6, 73, -1, 0, 0, 14, -1, 6437), + (6437, -1, -1, 6436, 6436, 6, 75, -1, 0, 0, 14, 6436, 6438), + (6438, -1, -1, 6436, 6436, 8, 77, -1, 0, 0, 14, 6437, 7313), + (6439, -1, -1, 468, 468, 2, 67, -1, 0, 0, 14, 470, 6440), + (6440, -1, -1, 468, 468, 2, 69, -1, 0, 0, 14, 6439, 7316), + (6441, -1, -1, 1546, 1546, 5, 76, -1, 0, 0, 14, 4831, 12673), + (6442, -1, -1, 1471, 1471, 6, 76, -1, 0, 0, 14, 1475, 6443), + (6443, -1, -1, 1471, 1471, 6, 77, -1, 0, 0, 14, 6442, -1), + (6445, -1, -1, 6445, 6445, 2, 62, -1, 0, 0, 14, -1, 6446), + (6446, -1, -1, 6445, 6445, 2, 64, -1, 0, 0, 14, 6445, 6447), + (6447, -1, -1, 6445, 6445, 2, 66, -1, 0, 0, 14, 6446, -1), + (6448, 5109, 5109, 5109, 5109, 9, 77, 13515, 0, 1, 14, 5109, 7467), + (6449, 1520, 1520, 1520, 1520, 9, 70, 13516, 11, 900, 14, 1522, 6450), + (6450, 1520, 1520, 1520, 1520, 9, 70, 13517, 11, 900, 14, 6449, 6451), + (6451, 1520, 1520, 1520, 1520, 9, 70, 13518, 11, 900, 14, 6450, 7463), + (6452, -1, -1, 6452, 6452, 2, 71, -1, 0, 0, 14, -1, 6453), + (6453, -1, -1, 6452, 6452, 2, 72, -1, 0, 0, 14, 6452, 6454), + (6454, -1, -1, 6452, 6452, 2, 73, -1, 0, 0, 14, 6453, -1), + (6455, 6455, 6455, 6455, 6455, 2, 72, 14750, 36, 30, 14, -1, 6456), + (6456, 6455, 6455, 6455, 6455, 2, 74, 14751, 36, 30, 14, 6455, 6457), + (6457, 6455, 6455, 6455, 6455, 2, 76, 14752, 36, 30, 14, 6456, -1), + (6458, -1, -1, 6458, 6458, 3, 78, -1, 0, 0, 14, -1, 6459), + (6459, -1, -1, 6458, 6458, 3, 78, -1, 0, 0, 14, 6458, 6460), + (6460, -1, -1, 6458, 6458, 3, 78, -1, 0, 0, 14, 6459, -1), + (6461, -1, -1, 6461, 6461, 3, 78, -1, 0, 0, 14, -1, 6462), + (6462, -1, -1, 6461, 6461, 3, 78, -1, 0, 0, 14, 6461, 6463), + (6463, -1, -1, 6461, 6461, 3, 78, -1, 0, 0, 14, 6462, -1), + (6464, 967, 967, 967, 967, 6, 76, 13897, 10, 1800, 14, 969, 6465), + (6465, 967, 967, 967, 967, 6, 77, 13898, 10, 1800, 14, 6464, 6466), + (6466, 967, 967, 967, 967, 6, 78, 13899, 10, 1800, 14, 6465, 7217), + (6467, -1, -1, 6467, 6467, 3, 61, -1, 0, 0, 15, -1, 6468), + (6468, -1, -1, 6467, 6467, 3, 63, -1, 0, 0, 15, 6467, 6469), + (6469, -1, -1, 6467, 6467, 3, 65, -1, 0, 0, 15, 6468, -1), + (6470, -1, -1, 6540, 6540, 8, 76, -1, 0, 0, 15, 6061, 6471), + (6471, -1, -1, 6540, 6540, 8, 81, -1, 0, 0, 15, 6470, 12487), + (6472, -1, -1, 6540, 6540, 8, 81, -1, 0, 0, 15, 6301, 6473), + (6473, -1, -1, 6540, 6540, 8, 83, -1, 0, 0, 15, 6472, 12481), + (6474, -1, -1, 6540, 6540, 8, 81, -1, 0, 0, 15, 6418, 6475), + (6475, -1, -1, 6540, 6540, 8, 83, -1, 0, 0, 15, 6474, 12483), + (6476, -1, -1, 6540, 6540, 8, 81, -1, 0, 0, 15, 6421, 6477), + (6477, -1, -1, 6540, 6540, 8, 83, -1, 0, 0, 15, 6476, 12485), + (6478, 0, 0, 6478, 6478, 3, 81, -1, 0, 0, 16, -1, 6479), + (6479, 0, 0, 6478, 6478, 5, 83, -1, 0, 0, 16, 6478, 6480), + (6480, 0, 0, 6478, 6478, 7, 85, -1, 0, 0, 16, 6479, -1), + (6481, 0, 0, 6481, 6481, 5, 85, -1, 0, 0, 16, -1, 6482), + (6482, 0, 0, 6481, 6481, 7, 85, -1, 0, 0, 16, 6481, 6483), + (6483, 0, 0, 6481, 6481, 9, 85, -1, 0, 0, 16, 6482, 15314), + (6484, -1, -1, 7940, 7940, 5, 85, -1, 0, 0, 16, 10032, 6485), + (6485, -1, -1, 7940, 7940, 7, 85, -1, 0, 0, 16, 6484, 6486), + (6486, -1, -1, 7940, 7940, 9, 85, -1, 0, 0, 16, 6485, 15320), + (6487, 1383, 1383, 1383, 1383, 12, 85, 21812, 6, 300, 16, 10014, 14221), + (6488, 6488, 6488, 6488, 6488, 12, 85, 21806, 32, 900, 16, -1, 13383), + (6489, -1, -1, 6489, 6489, 5, 81, -1, 0, 0, 16, -1, 6490), + (6490, -1, -1, 6489, 6489, 7, 83, -1, 0, 0, 16, 6489, 6491), + (6491, -1, -1, 6489, 6489, 9, 85, -1, 0, 0, 16, 6490, 17239), + (6492, 6492, 6492, 6492, 6492, 7, 75, 21692, 52, 720, 16, -1, 6493), + (6493, 6492, 6492, 6492, 6492, 7, 77, 21693, 52, 720, 16, 6492, 6494), + (6494, 6492, 6492, 6492, 6492, 7, 79, 21694, 52, 720, 16, 6493, 6495), + (6495, 6492, 6492, 6492, 6492, 7, 81, 21695, 52, 720, 16, 6494, 6496), + (6496, 6492, 6492, 6492, 6492, 7, 83, 21696, 52, 720, 16, 6495, 6497), + (6497, 6492, 6492, 6492, 6492, 7, 85, 21697, 52, 720, 16, 6496, 10679), + (6499, 6499, 6499, 6499, 6499, 3, 75, 13512, 13, 60, 14, -1, -1), + (6500, -1, -1, 4761, 4761, 7, 76, -1, 0, 0, 14, 4763, 6501), + (6501, -1, -1, 4761, 4761, 7, 78, -1, 0, 0, 14, 6500, 6502), + (6502, -1, -1, 4761, 4761, 7, 80, -1, 0, 0, 14, 6501, -1), + (6503, -1, -1, 6503, 6503, 6, 72, -1, 0, 0, 14, -1, 6504), + (6504, -1, -1, 6503, 6503, 6, 72, -1, 0, 0, 14, 6503, 6505), + (6505, -1, -1, 6503, 6503, 6, 72, -1, 0, 0, 14, 6504, 6506), + (6506, -1, -1, 6503, 6503, 6, 72, -1, 0, 0, 14, 6505, -1), + (6508, 6508, 6508, 6508, 6508, 7, 74, 13195, 38, 600, 14, -1, 6509), + (6509, 6508, 6508, 6508, 6508, 7, 76, 13196, 38, 600, 14, 6508, 6510), + (6510, 6508, 6508, 6508, 6508, 7, 78, 13197, 38, 600, 14, 6509, 7387), + (6511, -1, -1, 6511, 6511, 6, 73, -1, 0, 0, 14, -1, 6512), + (6512, -1, -1, 6511, 6511, 6, 75, -1, 0, 0, 14, 6511, 6513), + (6513, -1, -1, 6511, 6511, 6, 77, -1, 0, 0, 14, 6512, -1), + (6514, -1, -1, 6514, 6514, 2, 72, -1, 0, 0, 14, -1, 6515), + (6515, -1, -1, 6514, 6514, 2, 72, -1, 0, 0, 14, 6514, 6516), + (6516, -1, -1, 6514, 6514, 2, 72, -1, 0, 0, 14, 6515, -1), + (6517, -1, -1, 1435, 4773, 9, 76, -1, 0, 0, 14, 4773, 7621), + (6518, -1, -1, 678, 678, 3, 65, -1, 0, 0, 14, 682, 6519), + (6519, -1, -1, 678, 678, 3, 65, -1, 0, 0, 14, 6518, 6520), + (6520, -1, -1, 678, 678, 3, 65, -1, 0, 0, 14, 6519, 7544), + (6521, -1, -1, 1021, 1021, 5, 75, -1, 0, 0, 14, 1025, 6522), + (6522, -1, -1, 1021, 1021, 5, 80, -1, 0, 0, 14, 6521, 7539), + (6523, -1, -1, 1026, 1026, 5, 76, -1, 0, 0, 14, 4687, 6524), + (6524, -1, -1, 1026, 1026, 5, 77, -1, 0, 0, 14, 6523, 6525), + (6525, -1, -1, 1026, 1026, 5, 78, -1, 0, 0, 14, 6524, 6526), + (6526, -1, -1, 1026, 1026, 5, 79, -1, 0, 0, 14, 6525, 6527), + (6527, -1, -1, 1026, 1026, 5, 80, -1, 0, 0, 14, 6526, 7511), + (6528, -1, -1, 501, 501, 5, 96, -1, 0, 0, 19, 6321, 6529), + (6531, -1, -1, 5295, 5295, 6, 76, -1, 0, 0, 14, 5297, 6532), + (6532, -1, -1, 5295, 5295, 6, 78, -1, 0, 0, 14, 6531, 6533), + (6533, -1, -1, 5295, 5295, 6, 80, -1, 0, 0, 14, 6532, 7220), + (6534, 8000, 8000, 8000, 8000, 12, 90, 23607, 73, 600, 17, -1, 14216), + (6540, -1, -1, 4699, 4699, 5, 56, -1, 0, 0, 14, 4699, 7500), + (6545, -1, -1, 4698, 4698, 5, 56, -1, 0, 0, 14, 4698, -1), + (6546, -1, -1, 6546, 6546, 0, 55, -1, 0, 0, 3, -1, 6547), + (6547, -1, -1, 6546, 6546, 0, 56, -1, 0, 0, 3, 6546, 6548), + (6548, -1, -1, 6546, 6546, 0, 57, -1, 0, 0, 3, 6547, 6549), + (6549, -1, -1, 6546, 6546, 0, 58, -1, 0, 0, 3, 6548, 6550), + (6550, -1, -1, 6546, 6546, 0, 59, -1, 0, 0, 3, 6549, 6551), + (6551, -1, -1, 6546, 6546, 0, 60, -1, 0, 0, 3, 6550, 6552), + (6552, -1, -1, 6546, 6546, 0, 61, -1, 0, 0, 3, 6551, 6553), + (6553, -1, -1, 6546, 6546, 0, 62, -1, 0, 0, 3, 6552, 6554), + (6554, -1, -1, 6546, 6546, 0, 63, -1, 0, 0, 3, 6553, 6555), + (6555, -1, -1, 6546, 6546, 0, 64, -1, 0, 0, 3, 6554, 6556), + (6556, -1, -1, 6546, 6546, 0, 65, -1, 0, 0, 3, 6555, 6557), + (6557, -1, -1, 6546, 6546, 0, 66, -1, 0, 0, 3, 6556, 6558), + (6558, -1, -1, 6546, 6546, 0, 67, -1, 0, 0, 3, 6557, 6559), + (6559, -1, -1, 6546, 6546, 0, 68, -1, 0, 0, 3, 6558, 6560), + (6560, -1, -1, 6546, 6546, 0, 69, -1, 0, 0, 3, 6559, 6561), + (6561, -1, -1, 6546, 6546, 0, 70, -1, 0, 0, 3, 6560, 6562), + (6562, -1, -1, 6546, 6546, 0, 71, -1, 0, 0, 3, 6561, 6563), + (6563, -1, -1, 6546, 6546, 0, 72, -1, 0, 0, 3, 6562, 6564), + (6564, -1, -1, 6546, 6546, 0, 73, -1, 0, 0, 3, 6563, 6565), + (6565, -1, -1, 6546, 6546, 0, 74, -1, 0, 0, 3, 6564, 6566), + (6566, -1, -1, 6546, 6546, 0, 75, -1, 0, 0, 3, 6565, 6567), + (6567, -1, -1, 6546, 6546, 0, 76, -1, 0, 0, 3, 6566, 6568), + (6568, -1, -1, 6546, 6546, 0, 77, -1, 0, 0, 3, 6567, 6569), + (6569, -1, -1, 6546, 6546, 0, 78, -1, 0, 0, 3, 6568, 6570), + (6570, -1, -1, 6546, 6546, 0, 79, -1, 0, 0, 3, 6569, 6571), + (6571, -1, -1, 6546, 6546, 0, 80, -1, 0, 0, 3, 6570, 7373), + (6601, -1, -1, 6601, 6601, 6, 72, -1, 0, 0, 14, -1, 6602), + (6602, -1, -1, 6601, 6601, 6, 73, -1, 0, 0, 14, 6601, 6603), + (6603, -1, -1, 6601, 6601, 6, 74, -1, 0, 0, 14, 6602, 6604), + (6604, -1, -1, 6601, 6601, 6, 75, -1, 0, 0, 14, 6603, 6605), + (6605, -1, -1, 6601, 6601, 6, 76, -1, 0, 0, 14, 6604, 7318), + (6606, 1597, 1597, 1597, 1597, 9, 75, 16095, 6, 10, 15, 1597, 10571), + (6607, 6607, 6607, 6607, 6607, 9, 75, 16092, 61, 600, 15, -1, 6608), + (6608, 6607, 6607, 6607, 6607, 9, 80, 16093, 61, 600, 15, 6607, 6609), + (6609, 6607, 6607, 6607, 6607, 9, 85, 16094, 61, 600, 15, 6608, 16324), + (6610, 6610, 6610, 6610, 6610, 2, 55, 16096, 41, 30, 15, -1, 10003), + (6611, -1, -1, 6611, 6611, 2, 60, -1, 0, 0, 15, -1, 6612), + (6612, -1, -1, 6611, 6611, 4, 63, -1, 0, 0, 15, 6611, 6613), + (6613, -1, -1, 6611, 6611, 6, 66, -1, 0, 0, 15, 6612, 6618), + (6614, -1, -1, 6614, 6614, 2, 60, -1, 0, 0, 15, -1, 6615), + (6615, -1, -1, 6614, 6614, 4, 63, -1, 0, 0, 15, 6614, 6616), + (6616, -1, -1, 6614, 6614, 6, 66, -1, 0, 0, 15, 6615, 10004), + (6617, 6617, 6617, 6617, 6617, 6, 83, 16097, 42, 3600, 15, -1, 10572), + (6618, -1, -1, 6611, 6611, 6, 69, -1, 0, 0, 15, 6613, 6619), + (6619, -1, -1, 6611, 6611, 6, 72, -1, 0, 0, 15, 6618, 10574), + (6630, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, -1, 6631), + (6631, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, 6630, 6632), + (6632, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, 6631, 6633), + (6633, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, 6632, 6634), + (6634, -1, -1, 6630, 6630, 6, 70, -1, 0, 0, 15, 6633, 10070), + (6635, 6635, 6635, 6635, 6635, 7, 70, 16098, 41, 600, 15, -1, -1), + (6636, -1, -1, 6636, 6636, 3, 70, -1, 0, 0, 15, -1, 6637), + (6637, -1, -1, 6636, 6636, 6, 70, -1, 0, 0, 15, 6636, 6638), + (6638, -1, -1, 6636, 6636, 9, 70, -1, 0, 0, 15, 6637, 10041), + (6639, 6639, 6639, 6639, 6639, 7, 70, 16099, 42, 300, 15, -1, 15173), + (6640, 6640, 6640, 6640, 6640, 7, 81, 16100, 43, 60, 15, -1, 12585), + (6641, -1, -1, 6641, 6641, 7, 81, -1, 0, 0, 15, -1, 6642), + (6642, -1, -1, 6641, 6641, 8, 83, -1, 0, 0, 15, 6641, 6643), + (6643, -1, -1, 6641, 6641, 9, 85, -1, 0, 0, 15, 6642, 10075), + (6644, 6644, 6644, 6644, 6644, 2, 70, 16104, 44, 20, 15, -1, 12586), + (6645, 6645, 6645, 6645, 6645, 6, 80, 16105, 45, 60, 15, -1, 13107), + (6646, 6646, 6646, 6646, 6646, 6, 70, 16106, 46, 6, 15, -1, -1), + (6660, -1, -1, 1307, 1307, 5, 73, -1, 0, 0, 15, 1311, 6661), + (6661, -1, -1, 1307, 1307, 5, 74, -1, 0, 0, 15, 6660, 6662), + (6662, -1, -1, 1307, 1307, 5, 75, -1, 0, 0, 15, 6661, 13210), + (6663, 6663, 6663, 6663, 6663, 7, 73, 16107, 59, 600, 15, -1, 6664), + (6664, 6663, 6663, 6663, 6663, 7, 75, 16108, 59, 600, 15, 6663, 6665), + (6665, 6663, 6663, 6663, 6663, 7, 77, 16109, 59, 600, 15, 6664, 10162), + (6666, -1, -1, 6666, 6666, 8, 81, -1, 0, 0, 15, -1, 6667), + (6667, -1, -1, 6666, 6666, 8, 83, -1, 0, 0, 15, 6666, -1), + (6668, -1, -1, 6668, 6668, 3, 76, -1, 0, 0, 15, -1, 6669), + (6669, -1, -1, 6668, 6668, 3, 77, -1, 0, 0, 15, 6668, 6670), + (6670, -1, -1, 6668, 6668, 3, 78, -1, 0, 0, 15, 6669, -1), + (6671, 6671, 6671, 6671, 6671, 4, 65, 16148, 60, 60, 15, -1, -1), + (6672, 6672, 6672, 6672, 6672, 4, 67, 16149, 60, 60, 15, -1, -1), + (6673, 6673, 6673, 6673, 6673, 4, 69, 16150, 60, 60, 15, -1, -1), + (6674, 6674, 6674, 6674, 6674, 4, 71, 16151, 60, 60, 15, -1, -1), + (6675, 6675, 6675, 6675, 6675, 4, 73, 16152, 60, 60, 15, -1, -1), + (6676, 6676, 6676, 6676, 6676, 4, 75, 16153, 60, 60, 15, -1, -1), + (6691, 6691, 6691, 6691, 6691, 9, 81, 16114, 41, 30, 15, -1, -1), + (6692, 6692, 6692, 6692, 6692, 7, 65, 16115, 42, 600, 15, -1, 6693), + (6693, 6692, 6692, 6692, 6692, 7, 70, 16116, 42, 600, 15, 6692, 6694), + (6694, 6692, 6692, 6692, 6692, 7, 75, 16117, 42, 600, 15, 6693, 6695), + (6695, 6692, 6692, 6692, 6692, 7, 80, 16118, 42, 600, 15, 6694, 6696), + (6696, 6692, 6692, 6692, 6692, 7, 85, 16119, 42, 600, 15, 6695, 5342), + (6697, -1, -1, 6697, 6697, 7, 65, -1, 0, 0, 15, -1, 6698), + (6698, -1, -1, 6697, 6697, 7, 70, -1, 0, 0, 15, 6697, 6699), + (6699, -1, -1, 6697, 6697, 7, 75, -1, 0, 0, 15, 6698, 6700), + (6700, -1, -1, 6697, 6697, 7, 80, -1, 0, 0, 15, 6699, 6701), + (6701, -1, -1, 6697, 6697, 7, 85, -1, 0, 0, 15, 6700, -1), + (6702, 6702, 6702, 6702, 6702, 9, 75, 16120, 43, 120, 15, -1, -1), + (6703, -1, -1, 6703, 6703, 3, 65, -1, 0, 0, 15, -1, 6704), + (6704, -1, -1, 6703, 6703, 3, 65, -1, 0, 0, 15, 6703, 6705), + (6705, -1, -1, 6703, 6703, 3, 65, -1, 0, 0, 15, 6704, 10176), + (6706, 6706, 6706, 6706, 6706, 7, 75, 16121, 44, 600, 15, -1, 6707), + (6707, 6706, 6706, 6706, 6706, 7, 80, 16122, 44, 600, 15, 6706, 6708), + (6708, 6706, 6706, 6706, 6706, 7, 85, 16123, 44, 600, 15, 6707, 10179), + (6709, -1, -1, 6709, 6709, 3, 60, -1, 0, 0, 15, -1, 6710), + (6710, -1, -1, 6709, 6709, 3, 61, -1, 0, 0, 15, 6709, 6711), + (6711, -1, -1, 6709, 6709, 3, 62, -1, 0, 0, 15, 6710, -1), + (6712, -1, -1, 6712, 6712, 7, 65, -1, 0, 0, 15, -1, 6713), + (6713, -1, -1, 6712, 6712, 7, 70, -1, 0, 0, 15, 6712, 6714), + (6714, -1, -1, 6712, 6712, 7, 75, -1, 0, 0, 15, 6713, 6715), + (6715, -1, -1, 6712, 6712, 7, 80, -1, 0, 0, 15, 6714, 6716), + (6716, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 15, 6715, 10182), + (6750, 6750, 6750, 6750, 6750, 9, 85, 16127, 60, 120, 15, -1, 13899), + (6751, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, -1, 6752), + (6752, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, 6751, 6753), + (6753, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, 6752, 6768), + (6754, 6754, 6754, 6754, 6754, 7, 70, 16130, 41, 1200, 15, -1, 10053), + (6755, 6755, 6755, 6755, 6755, 7, 81, 16131, 42, 900, 15, -1, 6756), + (6756, 6755, 6755, 6755, 6755, 9, 83, 16132, 42, 900, 15, 6755, 6757), + (6757, 6755, 6755, 6755, 6755, 12, 85, 16133, 42, 900, 15, 6756, 13542), + (6758, 6758, 6758, 6758, 6758, 3, 81, 16134, 43, 900, 15, -1, 6759), + (6759, 6758, 6758, 6758, 6758, 6, 83, 16135, 43, 900, 15, 6758, 6760), + (6760, 6758, 6758, 6758, 6758, 9, 85, 16136, 43, 900, 15, 6759, 10054), + (6761, -1, -1, 6761, 6761, 3, 65, -1, 0, 0, 15, -1, 6762), + (6762, -1, -1, 6761, 6761, 6, 65, -1, 0, 0, 15, 6761, 6763), + (6763, -1, -1, 6761, 6761, 9, 65, -1, 0, 0, 15, 6762, 6085), + (6764, 6764, 6764, 6764, 6764, 7, 75, 16137, 52, 600, 15, -1, 10057), + (6765, -1, -1, 6765, 6765, 3, 70, -1, 0, 0, 15, -1, 6766), + (6766, -1, -1, 6765, 6765, 6, 75, -1, 0, 0, 15, 6765, 6767), + (6767, -1, -1, 6765, 6765, 9, 80, -1, 0, 0, 15, 6766, 10058), + (6768, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, 6753, 6769), + (6769, -1, -1, 6751, 6751, 6, 75, -1, 0, 0, 15, 6768, 10769), + (6791, -1, -1, 6791, 6791, 6, 75, -1, 0, 0, 15, -1, 6792), + (6792, -1, -1, 6791, 6791, 6, 80, -1, 0, 0, 15, 6791, 6793), + (6793, -1, -1, 6791, 6791, 6, 85, -1, 0, 0, 15, 6792, 10044), + (6794, 6794, 6794, 6794, 6794, 6, 75, 16142, 41, 60, 15, -1, -1), + (6815, 6815, 6815, 6815, 6815, 8, 75, 16144, 60, 600, 15, -1, 6816), + (6816, 6815, 6815, 6815, 6815, 8, 80, 16145, 60, 600, 15, 6815, 6817), + (6817, 6815, 6815, 6815, 6815, 8, 85, 16146, 60, 600, 15, 6816, 10200), + (6818, 6818, 6818, 6818, 6818, 6, 70, 16147, 44, 20, 15, -1, -1), + (6819, -1, -1, 6819, 6819, 6, 72, -1, 0, 0, 15, -1, 6820), + (6820, -1, -1, 6819, 6819, 6, 74, -1, 0, 0, 15, 6819, 6821), + (6821, -1, -1, 6819, 6819, 6, 76, -1, 0, 0, 15, 6820, 10203), + (6822, 6822, 6822, 6822, 6822, 12, 80, 16154, 42, 120, 15, -1, 13683), + (6823, -1, -1, 6823, 6823, 4, 65, -1, 0, 0, 15, -1, 6824), + (6824, -1, -1, 6823, 6823, 4, 67, -1, 0, 0, 15, 6823, 6825), + (6825, -1, -1, 6823, 6823, 4, 69, -1, 0, 0, 15, 6824, 6826), + (6826, -1, -1, 6823, 6823, 4, 71, -1, 0, 0, 15, 6825, 6827), + (6827, -1, -1, 6823, 6823, 4, 73, -1, 0, 0, 15, 6826, 10206), + (6828, 6828, 6828, 6828, 6828, 12, 80, 16155, 43, 60, 15, -1, 10208), + (6870, -1, -1, 6870, 6870, 6, 75, -1, 0, 0, 15, -1, 6871), + (6871, -1, -1, 6870, 6870, 6, 75, -1, 0, 0, 15, 6870, 6872), + (6872, -1, -1, 6870, 6870, 6, 75, -1, 0, 0, 15, 6871, 10130), + (6873, -1, -1, 255, 255, 3, 76, -1, 0, 0, 15, -1, 6874), + (6874, -1, -1, 255, 255, 6, 76, -1, 0, 0, 15, 6873, 6875), + (6875, -1, -1, 255, 255, 9, 76, -1, 0, 0, 15, 6874, 10133), + (6876, -1, -1, 6375, 6375, 6, 76, -1, 0, 0, 15, -1, 6877), + (6877, -1, -1, 6375, 6375, 6, 77, -1, 0, 0, 15, 6876, 6878), + (6878, -1, -1, 6375, 6375, 6, 78, -1, 0, 0, 15, 6877, 10136), + (6879, -1, -1, 649, 649, 2, 66, -1, 0, 0, 15, -1, 6880), + (6880, -1, -1, 649, 649, 4, 68, -1, 0, 0, 15, 6879, 6881), + (6881, -1, -1, 649, 649, 6, 70, -1, 0, 0, 15, 6880, -1), + (6882, -1, -1, 776, 776, 3, 70, -1, 0, 0, 15, -1, 6883), + (6883, -1, -1, 776, 776, 3, 70, -1, 0, 0, 15, 6882, 6884), + (6884, -1, -1, 776, 776, 3, 70, -1, 0, 0, 15, 6883, -1), + (6900, -1, -1, 6935, 6935, 6, 81, -1, 0, 0, 16, 6937, 6901), + (6901, -1, -1, 6935, 6935, 6, 82, -1, 0, 0, 16, 6900, 6902), + (6902, -1, -1, 6935, 6935, 6, 83, -1, 0, 0, 16, 6901, 6903), + (6903, -1, -1, 6935, 6935, 6, 84, -1, 0, 0, 16, 6902, 6904), + (6904, -1, -1, 6935, 6935, 6, 85, -1, 0, 0, 16, 6903, 14196), + (6905, -1, -1, 551, 551, 5, 81, -1, 0, 0, 16, 1637, 6906), + (6906, -1, -1, 551, 551, 5, 83, -1, 0, 0, 16, 6905, 6907), + (6907, -1, -1, 551, 551, 5, 85, -1, 0, 0, 16, 6906, 12843), + (6908, -1, -1, 6908, 6908, 6, 81, -1, 0, 0, 16, -1, 6909), + (6909, -1, -1, 6908, 6908, 6, 83, -1, 0, 0, 16, 6908, 6910), + (6910, -1, -1, 6908, 6908, 6, 85, -1, 0, 0, 16, 6909, 14199), + (6911, -1, -1, 1143, 1143, 5, 65, -1, 0, 0, 16, 1168, 6912), + (6912, -1, -1, 1143, 1143, 7, 65, -1, 0, 0, 16, 6911, 6913), + (6913, -1, -1, 1143, 1143, 9, 65, -1, 0, 0, 16, 6912, -1), + (6930, 6930, 6930, 6930, 6930, 12, 80, 16156, 13, 60, 15, -1, -1), + (6931, 6931, 6931, 6931, 6931, 12, 85, 16157, 41, 600, 15, -1, 10319), + (6932, 6932, 6932, 6932, 6932, 7, 81, 16158, 42, 1200, 15, -1, 6933), + (6933, 6932, 6932, 6932, 6932, 7, 83, 16159, 42, 1200, 15, 6932, 6934), + (6934, 6932, 6932, 6932, 6932, 7, 85, 16160, 42, 1200, 15, 6933, 10320), + (6935, -1, -1, 6935, 6935, 6, 75, -1, 0, 0, 15, -1, 6936), + (6936, -1, -1, 6935, 6935, 6, 77, -1, 0, 0, 15, 6935, 6937), + (6937, -1, -1, 6935, 6935, 6, 79, -1, 0, 0, 15, 6936, 6900), + (6938, -1, -1, 6938, 6938, 7, 81, -1, 0, 0, 15, -1, 6939), + (6939, -1, -1, 6938, 6938, 7, 83, -1, 0, 0, 15, 6938, 6940), + (6940, -1, -1, 6938, 6938, 7, 85, -1, 0, 0, 15, 6939, -1), + (6941, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, -1, 6942), + (6942, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, 6941, 6943), + (6943, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, 6942, 6944), + (6944, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, 6943, 6945), + (6945, -1, -1, 6941, 6941, 6, 81, -1, 0, 0, 15, 6944, -1), + (6970, 6970, 6970, 6970, 6970, 6, 70, 16167, 61, 6, 15, -1, -1), + (6971, 6971, 6971, 6971, 6971, 7, 78, 16168, 41, 600, 15, -1, 6972), + (6972, 6971, 6971, 6971, 6971, 7, 80, 16169, 41, 600, 15, 6971, 6973), + (6973, 6971, 6971, 6971, 6971, 7, 82, 16170, 41, 600, 15, 6972, 10288), + (6974, -1, -1, 6974, 6974, 5, 81, -1, 0, 0, 15, -1, 6975), + (6975, -1, -1, 6974, 6974, 5, 83, -1, 0, 0, 15, 6974, 6976), + (6976, -1, -1, 6974, 6974, 5, 85, -1, 0, 0, 15, 6975, 10291), + (6977, -1, -1, 6977, 6977, 5, 81, -1, 0, 0, 15, -1, 6978), + (6978, -1, -1, 6977, 6977, 5, 83, -1, 0, 0, 15, 6977, 6979), + (6979, -1, -1, 6977, 6977, 5, 85, -1, 0, 0, 15, 6978, 12840), + (6980, -1, -1, 6980, 6980, 5, 81, -1, 0, 0, 15, -1, 6981), + (6981, -1, -1, 6980, 6980, 5, 83, -1, 0, 0, 15, 6980, 6982), + (6982, -1, -1, 6980, 6980, 5, 85, -1, 0, 0, 15, 6981, 12834), + (6983, 6983, 6983, 6983, 6983, 7, 83, 16439, 66, 720, 15, -1, 16246), + (6984, 6984, 6984, 6984, 6984, 6, 73, 16172, 60, 60, 15, -1, 10294), + (6985, 6985, 6985, 6985, 6985, 6, 73, 16173, 60, 60, 15, -1, 10295), + (6986, 6986, 6986, 6986, 6986, 6, 73, 16174, 60, 60, 15, -1, 10296), + (6987, -1, -1, 6987, 6987, 12, 81, -1, 0, 0, 15, -1, -1), + (6988, -1, -1, 6988, 6988, 5, 83, 0, 0, 0, 16, -1, 6989), + (6989, -1, -1, 6988, 6988, 5, 84, 0, 0, 0, 16, 6988, 6990), + (6990, -1, -1, 6988, 6988, 5, 83, 0, 0, 0, 16, 6989, 14278), + (7000, 7000, 7000, 7000, 7000, 4, 65, 12748, 31, 600, 3, -1, -1), + (7002, 7002, 7002, 7002, 7002, 4, 65, 12750, 31, 600, 3, -1, -1), + (7003, 7003, 7003, 7003, 7003, 4, 65, 12751, 31, 600, 3, -1, -1), + (7004, 7004, 7004, 7004, 7004, 4, 65, 12752, 31, 300, 3, -1, -1), + (7005, -1, -1, 7005, 7005, 2, 73, -1, 0, 0, 15, -1, 7006), + (7006, -1, -1, 7005, 7005, 2, 74, -1, 0, 0, 15, 7005, 7007), + (7007, -1, -1, 7005, 7005, 2, 75, -1, 0, 0, 15, 7006, 15632), + (7008, -1, -1, 1604, 1604, 9, 81, -1, 0, 0, 16, 7133, 7009), + (7009, -1, -1, 1604, 1604, 12, 83, -1, 0, 0, 16, 7008, 12612), + (7010, -1, -1, 7010, 7010, 6, 81, -1, 0, 0, 16, -1, 7011), + (7011, -1, -1, 7010, 7010, 6, 83, -1, 0, 0, 16, 7010, 7012), + (7012, -1, -1, 7010, 7010, 6, 85, -1, 0, 0, 16, 7011, 7013), + (7013, -1, -1, 7010, 7010, 6, 85, -1, 0, 0, 16, 7012, 7014), + (7014, -1, -1, 7010, 7010, 6, 85, -1, 0, 0, 16, 7013, 7015), + (7015, -1, -1, 7010, 7010, 6, 85, -1, 0, 0, 16, 7014, 13533), + (7016, 7016, 7016, 7016, 7016, 5, 85, 21658, 31, 600, 3, -1, -1), + (7017, 7017, 7017, 7017, 7017, 5, 85, 21659, 31, 600, 3, -1, -1), + (7018, 7018, 7018, 7018, 7018, 5, 85, 21660, 31, 600, 3, -1, -1), + (7019, 7019, 7019, 7019, 7019, 5, 85, 21661, 31, 600, 3, -1, -1), + (7020, 7020, 7020, 7020, 7020, 0, 85, 21658, 31, 600, 3, -1, -1), + (7021, 7021, 7021, 7021, 7021, 0, 85, 21659, 31, 600, 3, -1, -1), + (7022, 7022, 7022, 7022, 7022, 0, 85, 21660, 31, 600, 3, -1, -1), + (7023, 7023, 7023, 7023, 7023, 0, 85, 21661, 31, 600, 3, -1, -1), + (7024, 7024, 7024, 7024, 7024, 0, 0, 9475, 31, 600, 12, -1, -1), + (7025, 7025, 7025, 7025, 7025, 0, 0, 9477, 31, 600, 12, -1, -1), + (7026, 7026, 7026, 7026, 7026, 0, 0, 9478, 31, 600, 12, -1, -1), + (7027, 7027, 7027, 7027, 7027, 0, 0, 9479, 31, 600, 12, -1, -1), + (7028, 7028, 7028, 7028, 7028, 0, 0, 12748, 31, 600, 3, -1, -1), + (7030, 7030, 7030, 7030, 7030, 0, 0, 12750, 31, 600, 3, -1, -1), + (7031, 7031, 7031, 7031, 7031, 0, 0, 12751, 31, 600, 3, -1, -1), + (7032, 7032, 7032, 7032, 7032, 0, 0, 12752, 31, 300, 3, -1, -1), + (7033, -1, -1, 7033, 7033, 6, 85, 0, 0, 0, 16, -1, 7034), + (7034, -1, -1, 7033, 7033, 9, 85, 0, 0, 0, 16, 7033, 7035), + (7035, -1, -1, 7033, 7033, 12, 85, 0, 0, 0, 16, 7034, 15746), + (7036, -1, -1, 7036, 7036, 7, 81, -1, 0, 0, 16, -1, 7037), + (7037, -1, -1, 7036, 7036, 9, 81, -1, 0, 0, 16, 7036, 7038), + (7038, -1, -1, 7036, 7036, 12, 81, -1, 0, 0, 16, 7037, 10579), + (7050, -1, -1, 446, 735, 5, 67, -1, 0, 0, 8, 448, 7051), + (7051, -1, -1, 446, 735, 5, 68, -1, 0, 0, 8, 7050, 7052), + (7052, -1, -1, 446, 735, 5, 69, -1, 0, 0, 8, 7051, 7053), + (7053, -1, -1, 446, 735, 7, 72, -1, 0, 0, 12, 7052, 7054), + (7054, -1, -1, 446, 735, 7, 73, -1, 0, 0, 12, 7053, 7055), + (7055, -1, -1, 446, 735, 7, 74, -1, 0, 0, 12, 7054, 7063), + (7056, -1, -1, 735, 735, 5, 67, -1, 0, 0, 8, 737, 7057), + (7057, -1, -1, 735, 735, 5, 68, -1, 0, 0, 8, 7056, 7058), + (7058, -1, -1, 735, 735, 5, 69, -1, 0, 0, 8, 7057, 7059), + (7059, -1, -1, 735, 735, 7, 72, -1, 0, 0, 12, 7058, 7060), + (7060, -1, -1, 735, 735, 7, 73, -1, 0, 0, 12, 7059, 7061), + (7061, -1, -1, 735, 735, 7, 74, -1, 0, 0, 12, 7060, 7066), + (7062, -1, -1, 7062, 7062, 3, 51, -1, 0, 0, 0, -1, -1), + (7063, -1, -1, 446, 735, 8, 76, -1, 0, 0, 14, 7055, 7064), + (7064, -1, -1, 446, 735, 8, 77, -1, 0, 0, 14, 7063, 7065), + (7065, -1, -1, 446, 735, 8, 78, -1, 0, 0, 14, 7064, 7622), + (7066, -1, -1, 735, 735, 8, 76, -1, 0, 0, 14, 7061, 7067), + (7067, -1, -1, 735, 735, 8, 77, -1, 0, 0, 14, 7066, 7068), + (7068, -1, -1, 735, 735, 8, 78, -1, 0, 0, 14, 7067, 7625), + (7069, 7069, 7069, 7069, 7069, 3, 71, 13219, 39, 7, 14, -1, -1), + (7100, -1, -1, 7100, 7100, 6, 76, -1, 0, 0, 14, -1, 7101), + (7101, -1, -1, 7100, 7100, 6, 77, -1, 0, 0, 14, 7100, 7102), + (7102, -1, -1, 7100, 7100, 6, 78, -1, 0, 0, 14, 7101, 7323), + (7103, -1, -1, 7103, 7103, 2, 65, -1, 0, 0, 14, -1, 7104), + (7104, -1, -1, 7103, 7103, 2, 65, -1, 0, 0, 14, 7103, 7105), + (7105, -1, -1, 7103, 7103, 2, 65, -1, 0, 0, 14, 7104, 7326), + (7106, -1, -1, 7106, 7106, 6, 73, -1, 0, 0, 14, -1, 7107), + (7107, -1, -1, 7106, 7106, 7, 76, -1, 0, 0, 14, 7106, 7108), + (7108, -1, -1, 7106, 7106, 10, 79, -1, 0, 0, 14, 7107, -1), + (7109, 1351, 1351, 1351, 1351, 8, 82, 13499, 5, 30, 15, 6133, 13109), + (7110, 4849, 4849, 4849, 4849, 7, 81, 13593, 7, 1800, 15, 6134, 13914), + (7111, 54006, 54006, 54006, 54006, 7, 81, 13594, 18, 180, 15, 6135, 10006), + (7112, -1, -1, 6564, 6564, 6, 78, -1, 0, 0, 15, 6285, 7113), + (7113, -1, -1, 6564, 6564, 7, 81, -1, 0, 0, 15, 7112, 7114), + (7114, -1, -1, 6564, 6564, 10, 84, -1, 0, 0, 15, 7113, 10007), + (7115, 6565, 6565, 6565, 6565, 7, 81, 13595, 17, 45, 15, 6286, 10010), + (7116, -1, -1, 489, 489, 3, 68, -1, 0, 0, 15, 491, 7117), + (7117, -1, -1, 489, 489, 3, 69, -1, 0, 0, 15, 7116, 7118), + (7118, -1, -1, 489, 489, 3, 70, -1, 0, 0, 15, 7117, -1), + (7119, 912, 912, 912, 912, 3, 71, 13496, 4, 3600, 15, 1332, 7120), + (7120, 912, 912, 912, 912, 6, 73, 13497, 4, 3600, 15, 7119, 7121), + (7121, 912, 912, 912, 912, 9, 75, 13498, 4, 3600, 15, 7120, 10011), + (7122, -1, -1, 4844, 4844, 5, 76, -1, 0, 0, 15, 4848, 7123), + (7123, -1, -1, 4844, 4844, 5, 77, -1, 0, 0, 15, 7122, 7124), + (7124, -1, -1, 4844, 4844, 5, 78, -1, 0, 0, 15, 7123, 7125), + (7125, -1, -1, 4844, 4844, 5, 79, -1, 0, 0, 15, 7124, 7126), + (7126, -1, -1, 4844, 4844, 5, 80, -1, 0, 0, 15, 7125, 7686), + (7127, 4860, 4860, 4860, 4860, 12, 85, 13599, 13, 60, 15, 5606, -1), + (7128, -1, -1, 492, 492, 2, 68, -1, 0, 0, 15, 494, 7129), + (7129, -1, -1, 492, 492, 2, 69, -1, 0, 0, 15, 7128, 7130), + (7130, -1, -1, 492, 492, 2, 70, -1, 0, 0, 15, 7129, 10576), + (7131, -1, -1, 1604, 1604, 7, 75, -1, 0, 0, 15, 6034, 7132), + (7132, -1, -1, 1604, 1604, 9, 77, -1, 0, 0, 15, 7131, 7133), + (7133, -1, -1, 1604, 1604, 12, 79, -1, 0, 0, 15, 7132, 7008), + (7134, -1, -1, 1543, 1543, 7, 81, -1, 0, 0, 15, 6044, 7135), + (7135, -1, -1, 1543, 1543, 9, 83, -1, 0, 0, 15, 7134, 7136), + (7136, -1, -1, 1543, 1543, 12, 85, -1, 0, 0, 15, 7135, 10165), + (7137, -1, -1, 6559, 6559, 6, 79, -1, 0, 0, 15, 6274, 7138), + (7138, -1, -1, 6559, 6559, 7, 81, -1, 0, 0, 15, 7137, 7139), + (7139, -1, -1, 6559, 6559, 10, 83, -1, 0, 0, 15, 7138, -1), + (7143, 6328, 6328, 6328, 6328, 7, 79, 13601, 10, 600, 15, 6330, 7144), + (7144, 6328, 6328, 6328, 6328, 7, 81, 13602, 10, 600, 15, 7143, 7145), + (7145, 6328, 6328, 6328, 6328, 7, 83, 13603, 10, 600, 15, 7144, 10168), + (7146, -1, -1, 878, 878, 7, 81, -1, 0, 0, 15, 6332, 7147), + (7147, -1, -1, 878, 878, 7, 83, -1, 0, 0, 15, 7146, 10171), + (7148, -1, -1, 1304, 1304, 7, 81, -1, 0, 0, 15, 6031, 7149), + (7149, -1, -1, 1304, 1304, 9, 83, -1, 0, 0, 15, 7148, 7150), + (7150, -1, -1, 1304, 1304, 12, 85, -1, 0, 0, 15, 7149, 10865), + (7151, -1, -1, 846, 846, 7, 81, -1, 0, 0, 15, 6037, 7152), + (7152, -1, -1, 846, 846, 9, 83, -1, 0, 0, 15, 7151, 7153), + (7153, -1, -1, 846, 846, 12, 85, -1, 0, 0, 15, 7152, 10173), + (7154, 1352, 1352, 1352, 1352, 6, 81, 13613, 3, 60, 15, 6318, 7155), + (7155, 1352, 1352, 1352, 1352, 6, 83, 13614, 3, 60, 15, 7154, 7156), + (7156, 1352, 1352, 1352, 1352, 6, 85, 13615, 3, 60, 15, 7155, 10113), + (7157, 1358, 1358, 1358, 1358, 6, 81, 13610, 3, 60, 15, 6312, 7158), + (7158, 1358, 1358, 1358, 1358, 6, 83, 13611, 3, 60, 15, 7157, 7159), + (7159, 1358, 1358, 1358, 1358, 6, 85, 13612, 3, 60, 15, 7158, 10116), + (7160, -1, -1, 4801, 4801, 6, 79, -1, 0, 0, 15, 4803, 7161), + (7161, -1, -1, 4801, 4801, 6, 81, -1, 0, 0, 15, 7160, 7162), + (7162, -1, -1, 4801, 4801, 6, 83, -1, 0, 0, 15, 7161, 10122), + (7163, -1, -1, 820, 820, 5, 81, -1, 0, 0, 15, 5919, 7164), + (7164, -1, -1, 820, 820, 5, 83, -1, 0, 0, 15, 7163, 7165), + (7165, -1, -1, 820, 820, 5, 85, -1, 0, 0, 15, 7164, 10660), + (7166, -1, -1, 6343, 6343, 6, 79, -1, 0, 0, 15, 6345, 7167), + (7167, -1, -1, 6343, 6343, 6, 81, -1, 0, 0, 15, 7166, 7168), + (7168, -1, -1, 6343, 6343, 6, 83, -1, 0, 0, 15, 7167, -1), + (7169, -1, -1, 6020, 6020, 2, 81, -1, 0, 0, 15, 6059, 7170), + (7170, -1, -1, 6020, 6020, 2, 83, -1, 0, 0, 15, 7169, 7171), + (7171, -1, -1, 6020, 6020, 2, 85, -1, 0, 0, 15, 7170, 10663), + (7172, 1355, 1355, 1355, 1355, 6, 81, 13607, 3, 60, 15, 5916, 7173), + (7173, 1355, 1355, 1355, 1355, 6, 83, 13608, 3, 60, 15, 7172, 7174), + (7174, 1355, 1355, 1355, 1355, 6, 85, 13609, 3, 60, 15, 7173, 10119), + (7175, -1, -1, 611, 611, 2, 68, -1, 0, 0, 15, 615, 7176), + (7176, -1, -1, 611, 611, 2, 69, -1, 0, 0, 15, 7175, 7177), + (7177, -1, -1, 611, 611, 2, 70, -1, 0, 0, 15, 7176, 10124), + (7178, 4854, 4854, 4854, 4854, 7, 81, 13616, 8, 600, 15, 5766, 7179), + (7179, 4854, 4854, 4854, 4854, 9, 83, 13617, 8, 600, 15, 7178, 7180), + (7180, 4854, 4854, 4854, 4854, 12, 85, 13618, 8, 600, 15, 7179, 10323), + (7184, 1348, 1348, 1348, 1348, 12, 91, 13622, 0, 3600, 18, 5772, 7185), + (7187, 1178, 1178, 1178, 1178, 7, 81, 13625, 4, 900, 15, 5781, 7188), + (7188, 1178, 1178, 1178, 1178, 8, 82, 13626, 4, 900, 15, 7187, 7189), + (7189, 1178, 1178, 1178, 1178, 9, 83, 13627, 4, 900, 15, 7188, 10326), + (7196, -1, -1, 5776, 5776, 7, 81, -1, 0, 0, 16, 5778, 7197), + (7197, -1, -1, 5776, 5776, 9, 83, -1, 0, 0, 16, 7196, 7198), + (7198, -1, -1, 5776, 5776, 12, 85, -1, 0, 0, 16, 7197, 13043), + (7199, 1274, 1274, 1274, 1274, 9, 83, 13657, 9, 540, 15, 5949, 7200), + (7200, 1274, 1274, 1274, 1274, 10, 84, 13658, 9, 540, 15, 7199, 7201), + (7201, 1274, 1274, 1274, 1274, 12, 85, 13659, 9, 540, 15, 7200, 10209), + (7202, 1510, -1, 1510, 1510, 12, 75, 13664, 13, 2160, 15, 1510, 10212), + (7203, 184, 184, 184, 184, 10, 84, 13660, 5, 4320, 15, 5953, -1), + (7204, -1, -1, 5264, 5264, 7, 81, -1, 0, 0, 15, 5943, 7205), + (7205, -1, -1, 5264, 5264, 8, 82, -1, 0, 0, 15, 7204, 7206), + (7206, -1, -1, 5264, 5264, 9, 83, -1, 0, 0, 15, 7205, 7207), + (7207, -1, -1, 5264, 5264, 10, 84, -1, 0, 0, 15, 7206, 7208), + (7208, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 15, 7207, 10213), + (7209, 4927, 4927, 4927, 4927, 9, 76, 13656, 14, 600, 15, 4927, 10218), + (7210, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 5329, 7211), + (7211, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 7210, 7212), + (7212, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 7211, 7213), + (7213, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 7212, 7214), + (7214, -1, -1, 839, 839, 6, 75, -1, 0, 0, 15, 7213, 10219), + (7215, -1, -1, 4861, 4861, 9, 83, -1, 0, 0, 15, 5956, 7216), + (7216, -1, -1, 4861, 4861, 12, 85, -1, 0, 0, 15, 7215, 7682), + (7217, 967, 967, 967, 967, 6, 81, 13661, 10, 1800, 15, 6466, 7218), + (7218, 967, 967, 967, 967, 6, 82, 13662, 10, 1800, 15, 7217, 7219), + (7219, 967, 967, 967, 967, 6, 83, 13663, 10, 1800, 15, 7218, 10224), + (7220, -1, -1, 5295, 5295, 6, 81, -1, 0, 0, 15, 6533, 7221), + (7221, -1, -1, 5295, 5295, 6, 83, -1, 0, 0, 15, 7220, 7222), + (7222, -1, -1, 5295, 5295, 6, 85, -1, 0, 0, 15, 7221, 10227), + (7223, 6290, 6290, 6290, 6290, 7, 81, 13689, 0, 1, 15, 6295, 7224), + (7224, 6290, 6290, 6290, 6290, 9, 83, 13690, 0, 1, 15, 7223, 7225), + (7225, 6290, 6290, 6290, 6290, 12, 85, 13691, 0, 1, 15, 7224, 11064), + (7226, 619, 619, 619, 619, 6, 78, 13686, 6, 900, 15, 6298, 7227), + (7227, 619, 619, 619, 619, 6, 78, 13687, 6, 900, 15, 7226, 7228), + (7228, 619, 619, 619, 619, 6, 78, 13688, 6, 900, 15, 7227, 10230), + (7229, 4944, -1, 4944, 4944, 7, 81, 13677, 0, 1, 15, 6157, 7230), + (7230, 4944, -1, 4944, 4944, 9, 83, 13678, 0, 1, 15, 7229, 7231), + (7231, 4944, -1, 4944, 4944, 12, 85, 13679, 0, 1, 15, 7230, 11067), + (7232, -1, -1, 1210, 1210, 7, 81, -1, 0, 0, 15, 5576, 7233), + (7233, -1, -1, 1210, 1210, 9, 83, -1, 0, 0, 15, 7232, 7234), + (7234, -1, -1, 1210, 1210, 12, 85, -1, 0, 0, 15, 7233, 12523), + (7235, 923, 923, 923, 923, 9, 82, 13673, 8, 60, 15, 6151, -1), + (7236, 922, 922, 922, 922, 9, 83, 13672, 8, 60, 15, 6150, -1), + (7237, 516, 516, 516, 516, 6, 77, 13692, 5, 480, 15, 6398, 10233), + (7238, 155, 155, 155, 155, 12, 82, 13693, 8, 60, 15, 5289, 14324), + (7239, 1334, 1334, 1334, 1334, 9, 83, 13674, 11, 4320, 15, 6154, 7240), + (7240, 1334, 1334, 1334, 1334, 10, 84, 13675, 11, 4320, 15, 7239, 7241), + (7241, 1334, 1334, 1334, 1334, 12, 85, 13676, 11, 4320, 15, 7240, 10234), + (7242, 1478, -1, 1478, 1478, 9, 83, 13680, 0, 1, 15, 6163, 7243), + (7243, 1478, -1, 1478, 1478, 10, 84, 13681, 0, 1, 15, 7242, 7244), + (7244, 1478, -1, 1478, 1478, 12, 85, 13682, 0, 1, 15, 7243, 11070), + (7245, 921, 921, 921, 921, 9, 84, 13671, 8, 60, 15, 6149, -1), + (7246, 4915, 4915, 4915, 4915, 7, 81, 13683, 7, 4320, 15, 5609, 7247), + (7247, 4915, 4915, 4915, 4915, 9, 83, 13684, 7, 4320, 15, 7246, 7248), + (7248, 4915, 4915, 4915, 4915, 12, 85, 13685, 7, 4320, 15, 7247, -1), + (7249, 167, 167, 167, 167, 10, 84, 13703, 14, 900, 15, 5879, 8343), + (7250, 520, 520, 520, 520, 12, 81, 13704, 6, 540, 15, 5885, 7251), + (7251, 520, 520, 520, 520, 12, 83, 13705, 6, 540, 15, 7250, 7252), + (7252, 520, 520, 520, 520, 12, 85, 13706, 6, 540, 15, 7251, 10252), + (7253, 4903, 4903, 4903, 4903, 9, 81, 13707, 9, 1320, 15, 5892, 10255), + (7254, 4906, 4906, 4906, 4906, 9, 81, 13708, 9, 1320, 15, 5893, 10256), + (7255, 4909, 4909, 4909, 4909, 9, 81, 13709, 16, 1320, 15, 5894, 10257), + (7256, 4912, 4912, 4912, 4912, 9, 81, 13710, 16, 1320, 15, 5895, 10258), + (7257, 616, 616, 616, 616, 6, 78, 13711, 7, 900, 15, 6256, 7258), + (7258, 616, 616, 616, 616, 7, 81, 13712, 7, 900, 15, 7257, 7259), + (7259, 616, 616, 616, 616, 10, 84, 13713, 7, 900, 15, 7258, 10259), + (7260, -1, -1, 1504, 1504, 5, 81, -1, 0, 0, 15, 5882, 7261), + (7261, -1, -1, 1504, 1504, 5, 83, -1, 0, 0, 15, 7260, 7262), + (7262, -1, -1, 1504, 1504, 5, 85, -1, 0, 0, 15, 7261, -1), + (7263, -1, -1, 1577, 1577, 7, 81, -1, 0, 0, 15, 5888, 7264), + (7264, -1, -1, 1577, 1577, 9, 83, -1, 0, 0, 15, 7263, 7265), + (7265, -1, -1, 1577, 1577, 12, 85, -1, 0, 0, 15, 7264, 10262), + (7266, 6333, 6333, 6333, 6333, 6, 64, 13714, 3, 600, 15, 6333, 13920), + (7267, -1, -1, 795, 795, 7, 81, -1, 0, 0, 15, 5891, 7268), + (7268, -1, -1, 795, 795, 9, 83, -1, 0, 0, 15, 7267, 7269), + (7269, -1, -1, 795, 795, 12, 85, -1, 0, 0, 15, 7268, 10265), + (7270, -1, -1, 790, 790, 6, 81, -1, 0, 0, 15, 5324, 7271), + (7271, -1, -1, 790, 790, 6, 82, -1, 0, 0, 15, 7270, 7272), + (7272, -1, -1, 790, 790, 6, 83, -1, 0, 0, 15, 7271, 7273), + (7273, -1, -1, 790, 790, 6, 84, -1, 0, 0, 15, 7272, 7274), + (7274, -1, -1, 790, 790, 6, 85, -1, 0, 0, 15, 7273, 12950), + (7275, 1239, 1239, 1239, 1239, 12, 85, 13735, 6, 600, 15, 5868, 13251), + (7276, 773, -1, 773, 773, 7, 81, 13726, 5, 1800, 15, 5856, 7277), + (7277, 773, -1, 773, 773, 9, 83, 13727, 5, 1800, 15, 7276, 7278), + (7278, 773, -1, 773, 773, 12, 85, 13728, 5, 1800, 15, 7277, 10564), + (7279, 6552, 6552, 6552, 6552, 5, 75, -1, 0, 0, 15, 6253, 7280), + (7280, 6552, 6552, 6552, 6552, 6, 77, -1, 0, 0, 15, 7279, 7281), + (7281, 6552, 6552, 6552, 6552, 6, 79, -1, 0, 0, 15, 7280, 7282), + (7282, 6552, 6552, 6552, 6552, 7, 81, -1, 0, 0, 15, 7281, 7283), + (7283, 6552, 6552, 6552, 6552, 9, 83, -1, 0, 0, 15, 7282, -1), + (7284, -1, -1, 781, 781, 8, 82, -1, 0, 0, 15, 5850, 13763), + (7285, 1242, 1242, 1242, 1242, 7, 81, 13723, 9, 1320, 15, 5859, 7286), + (7286, 1242, 1242, 1242, 1242, 9, 83, 13724, 9, 1320, 15, 7285, 7287), + (7287, 1242, 1242, 1242, 1242, 12, 85, 13725, 9, 1320, 15, 7286, 10271), + (7288, 4894, 4894, 4894, 4894, 6, 81, 13732, 7, 2160, 15, 6354, 7289), + (7289, 4894, 4894, 4894, 4894, 6, 82, 13733, 7, 2160, 15, 7288, 7290), + (7290, 4894, 4894, 4894, 4894, 6, 83, 13734, 7, 2160, 15, 7289, 13247), + (7291, 4931, 4931, 4931, 4931, 7, 81, 13729, 4, 600, 15, 6056, 7292), + (7292, 4931, 4931, 4931, 4931, 7, 83, 13730, 4, 600, 15, 7291, 7293), + (7293, 4931, 4931, 4931, 4931, 7, 85, 13731, 4, 600, 15, 7292, 10274), + (7294, 4935, 4935, 4935, 4935, 7, 76, 13722, 14, 300, 15, 4935, 10277), + (7295, 4934, 4934, 4934, 4934, 7, 76, 13721, 13, 300, 15, 4934, 10278), + (7296, 517, 517, 517, 517, 5, 73, 13718, 12, 600, 15, 1444, 7297), + (7297, 517, 517, 517, 517, 5, 74, 13719, 12, 600, 15, 7296, 7298), + (7298, 517, 517, 517, 517, 5, 75, 13720, 12, 600, 15, 7297, 10279), + (7299, 1383, 1383, 1383, 1383, 12, 85, 16000, 6, 300, 15, 5789, 10014), + (7300, 1195, 1195, 1195, 1195, 9, 85, 16001, 13, 2160, 15, 5790, 10015), + (7301, 131, 131, 131, 131, 8, 82, 16002, 4, 900, 15, 5793, 7302), + (7302, 131, 131, 131, 131, 9, 83, 16003, 4, 900, 15, 7301, 7303), + (7303, 131, 131, 131, 131, 10, 84, 16004, 4, 900, 15, 7302, 10016), + (7304, 1192, 1192, 1192, 1192, 8, 82, 16005, 12, 1320, 15, 5796, 7305), + (7305, 1192, 1192, 1192, 1192, 9, 83, 16006, 12, 1320, 15, 7304, 7306), + (7306, 1192, 1192, 1192, 1192, 10, 84, 16007, 12, 1320, 15, 7305, 10019), + (7307, 746, 746, 746, 746, 9, 83, 16008, 10, 2160, 15, 5802, 7308), + (7308, 746, 746, 746, 746, 10, 84, 16009, 10, 2160, 15, 7307, 7309), + (7309, 746, 746, 746, 746, 12, 85, 16010, 10, 2160, 15, 7308, 10022), + (7310, 1459, 1459, 1459, 1459, 7, 81, 16011, 11, 1800, 15, 5805, 7311), + (7311, 1459, 1459, 1459, 1459, 9, 83, 16012, 11, 1800, 15, 7310, 7312), + (7312, 1459, 1459, 1459, 1459, 12, 85, 16013, 11, 1800, 15, 7311, -1), + (7313, -1, -1, 6436, 6436, 6, 78, -1, 0, 0, 15, 6438, 7314), + (7314, -1, -1, 6436, 6436, 6, 80, -1, 0, 0, 15, 7313, 7315), + (7315, -1, -1, 6436, 6436, 8, 82, -1, 0, 0, 15, 7314, -1), + (7316, -1, -1, 468, 468, 2, 72, -1, 0, 0, 15, 6440, 7317), + (7317, -1, -1, 468, 468, 2, 74, -1, 0, 0, 15, 7316, 17288), + (7318, -1, -1, 6601, 6601, 6, 77, -1, 0, 0, 15, 6605, 7319), + (7319, -1, -1, 6601, 6601, 6, 78, -1, 0, 0, 15, 7318, 7320), + (7320, -1, -1, 6601, 6601, 6, 79, -1, 0, 0, 15, 7319, 7321), + (7321, -1, -1, 6601, 6601, 6, 80, -1, 0, 0, 15, 7320, 7322), + (7322, -1, -1, 6601, 6601, 6, 81, -1, 0, 0, 15, 7321, 10025), + (7323, -1, -1, 7100, 7100, 6, 81, -1, 0, 0, 15, 7102, 7324), + (7324, -1, -1, 7100, 7100, 6, 82, -1, 0, 0, 15, 7323, 7325), + (7325, -1, -1, 7100, 7100, 6, 83, -1, 0, 0, 15, 7324, 8427), + (7326, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 15, 7105, 7327), + (7327, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 15, 7326, 7328), + (7328, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 15, 7327, 10750), + (7329, 534, 534, 534, 534, 7, 81, 16021, 4, 2160, 15, 5971, 7330), + (7330, 534, 534, 534, 534, 9, 83, 16022, 4, 2160, 15, 7329, 7331), + (7331, 534, 534, 534, 534, 12, 85, 16023, 4, 2160, 15, 7330, 10047), + (7332, 5095, 5095, 5095, 5095, 7, 81, 16024, 10, 900, 15, 5977, 7333), + (7333, 5095, 5095, 5095, 5095, 9, 83, 16025, 10, 900, 15, 7332, 7334), + (7334, 5095, 5095, 5095, 5095, 12, 85, 16026, 10, 900, 15, 7333, 10640), + (7335, 5984, 5984, 5984, 5984, 12, 85, 16027, 2, 30, 15, 5984, 7710), + (7336, -1, -1, 6395, 6395, 7, 81, -1, 0, 0, 15, 6397, 7337), + (7337, -1, -1, 6395, 6395, 7, 82, -1, 0, 0, 15, 7336, 7338), + (7338, -1, -1, 6395, 6395, 7, 83, -1, 0, 0, 15, 7337, 10050), + (7339, 188, 188, 188, 188, 9, 78, 16020, 2, 30, 14, 5044, 7662), + (7340, 7850, 7850, 7850, 7850, 8, 81, 16028, 39, 4320, 0, 7865, 10618), + (7341, 5007, 5007, 5007, 5007, 9, 81, 16047, 8, 2160, 15, 6427, 7342), + (7342, 5007, 5007, 5007, 5007, 9, 83, 16048, 8, 2160, 15, 7341, 7343), + (7343, 5007, 5007, 5007, 5007, 9, 85, 16049, 8, 2160, 15, 7342, 10061), + (7344, 545, 545, 545, 545, 7, 81, 16038, 3, 900, 15, 6002, 7345), + (7345, 545, 545, 545, 545, 9, 83, 16039, 3, 900, 15, 7344, 7346), + (7346, 545, 545, 545, 545, 12, 85, 16040, 3, 900, 15, 7345, 10758), + (7347, 1345, 1345, 1345, 1345, 8, 82, 16041, 6, 900, 15, 6010, 7348), + (7348, 1345, 1345, 1345, 1345, 9, 83, 16042, 6, 900, 15, 7347, 7349), + (7349, 1345, 1345, 1345, 1345, 10, 84, 16043, 6, 900, 15, 7348, 10740), + (7350, 6370, 6370, 6370, 6370, 6, 81, 16044, 7, 600, 15, 6372, 7351), + (7351, 6370, 6370, 6370, 6370, 6, 82, 16045, 7, 600, 15, 7350, 7352), + (7352, 6370, 6370, 6370, 6370, 6, 83, 16046, 7, 600, 15, 7351, 14112), + (7353, -1, -1, 864, 864, 6, 85, -1, 0, 0, 15, 6013, 7354), + (7354, -1, -1, 864, 864, 6, 85, -1, 0, 0, 15, 7353, 7355), + (7355, -1, -1, 864, 864, 6, 85, -1, 0, 0, 15, 7354, -1), + (7356, -1, -1, 5248, 5248, 7, 81, -1, 0, 0, 15, 6016, 7357), + (7357, -1, -1, 5248, 5248, 9, 83, -1, 0, 0, 15, 7356, 7358), + (7358, -1, -1, 5248, 5248, 12, 85, -1, 0, 0, 15, 7357, 16170), + (7359, -1, -1, 644, 644, 7, 79, -1, 0, 0, 15, 6019, 7360), + (7360, -1, -1, 644, 644, 9, 81, -1, 0, 0, 15, 7359, 7361), + (7361, -1, -1, 644, 644, 12, 83, -1, 0, 0, 15, 7360, 13092), + (7362, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 871, 7363), + (7363, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 7362, 7364), + (7364, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 7363, 7365), + (7365, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 7364, 7366), + (7366, -1, -1, 867, 867, 5, 70, -1, 0, 0, 15, 7365, 10748), + (7367, 872, 872, 872, 872, 3, 70, 16032, 5, 180, 15, 874, 7368), + (7368, 872, 872, 872, 872, 6, 70, 16033, 5, 180, 15, 7367, 7369), + (7369, 872, 872, 872, 872, 9, 70, 16034, 5, 180, 15, 7368, 10772), + (7370, 875, 875, 875, 875, 3, 70, 16035, 5, 180, 15, 877, 7371), + (7371, 875, 875, 875, 875, 6, 73, 16036, 5, 180, 15, 7370, 7372), + (7372, 875, 875, 875, 875, 9, 75, 16037, 5, 180, 15, 7371, 10775), + (7373, -1, -1, 6546, 6546, 0, 81, -1, 0, 0, 15, 6571, 7374), + (7374, -1, -1, 6546, 6546, 0, 82, -1, 0, 0, 15, 7373, 7375), + (7375, -1, -1, 6546, 6546, 0, 83, -1, 0, 0, 15, 7374, 7376), + (7376, -1, -1, 6546, 6546, 0, 84, -1, 0, 0, 15, 7375, 7377), + (7377, -1, -1, 6546, 6546, 0, 85, -1, 0, 0, 15, 7376, 13122), + (7378, -1, -1, 1608, 1608, 3, 71, -1, 0, 0, 15, 4991, 7379), + (7379, -1, -1, 1608, 1608, 6, 73, -1, 0, 0, 15, 7378, 7380), + (7380, -1, -1, 1608, 1608, 9, 75, -1, 0, 0, 15, 7379, 7381), + (7381, -1, -1, 1608, 1608, 6, 76, -1, 0, 0, 15, 7380, 7382), + (7382, -1, -1, 1608, 1608, 6, 78, -1, 0, 0, 15, 7381, 7383), + (7383, -1, -1, 1608, 1608, 6, 80, -1, 0, 0, 15, 7382, 10064), + (7384, -1, -1, 5085, 5085, 6, 81, -1, 0, 0, 15, 6408, 7385), + (7385, -1, -1, 5085, 5085, 6, 83, -1, 0, 0, 15, 7384, 7386), + (7386, -1, -1, 5085, 5085, 6, 85, -1, 0, 0, 15, 7385, 10383), + (7387, 6508, 6508, 6508, 6508, 7, 79, 16059, 38, 600, 15, 6510, 7388), + (7388, 6508, 6508, 6508, 6508, 7, 81, 16060, 38, 600, 15, 7387, 7389), + (7389, 6508, 6508, 6508, 6508, 7, 83, 16061, 38, 600, 15, 7388, 10078), + (7390, -1, -1, 589, 589, 7, 81, -1, 0, 0, 15, 6065, 7391), + (7391, -1, -1, 589, 589, 7, 83, -1, 0, 0, 15, 7390, 7392), + (7392, -1, -1, 589, 589, 7, 85, -1, 0, 0, 15, 7391, 7707), + (7393, -1, -1, 1313, 1313, 7, 81, -1, 0, 0, 15, 6071, 7394), + (7394, -1, -1, 1313, 1313, 7, 81, -1, 0, 0, 15, 7393, 7395), + (7395, -1, -1, 1313, 1313, 8, 82, -1, 0, 0, 15, 7394, 7396), + (7396, -1, -1, 1313, 1313, 9, 83, -1, 0, 0, 15, 7395, 7397), + (7397, -1, -1, 1313, 1313, 10, 84, -1, 0, 0, 15, 7396, 7398), + (7398, -1, -1, 1313, 1313, 12, 85, -1, 0, 0, 15, 7397, 10081), + (7399, -1, -1, 210, 210, 8, 82, -1, 0, 0, 15, 6074, 7400), + (7400, -1, -1, 210, 210, 9, 83, -1, 0, 0, 15, 7399, 7401), + (7401, -1, -1, 210, 210, 10, 84, -1, 0, 0, 15, 7400, 15172), + (7402, -1, -1, 895, 895, 7, 81, -1, 0, 0, 15, 6079, 7403), + (7403, -1, -1, 895, 895, 8, 82, -1, 0, 0, 15, 7402, 7404), + (7404, -1, -1, 895, 895, 9, 83, -1, 0, 0, 15, 7403, 7405), + (7405, -1, -1, 895, 895, 10, 84, -1, 0, 0, 15, 7404, 7406), + (7406, -1, -1, 895, 895, 12, 85, -1, 0, 0, 15, 7405, 10906), + (7407, -1, -1, 7407, 7407, 12, 85, 0, 0, 0, 16, -1, -1), + (7408, 1498, 1498, 1498, 1498, 7, 81, 16075, 12, 1320, 15, 5821, 7409), + (7409, 1498, 1498, 1498, 1498, 9, 83, 16076, 12, 1320, 15, 7408, 7410), + (7410, 1498, 1498, 1498, 1498, 12, 85, 16077, 12, 1320, 15, 7409, 10090), + (7411, 757, -1, 757, 757, 7, 81, 16078, 6, 1800, 15, 5824, 7412), + (7412, 757, -1, 757, 757, 9, 83, 16079, 6, 1800, 15, 7411, 7413), + (7413, 757, -1, 757, 757, 12, 85, 16080, 6, 1800, 15, 7412, 12658), + (7414, 1495, 1495, 1495, 1495, 7, 81, 16081, 30, 900, 15, 5828, 7415), + (7415, 1495, 1495, 1495, 1495, 9, 83, 16082, 30, 900, 15, 7414, 7416), + (7416, 1495, 1495, 1495, 1495, 12, 85, 16083, 30, 900, 15, 7415, 10093), + (7417, 548, 548, 548, 548, 8, 82, 16084, 5, 900, 15, 5831, 7418), + (7418, 548, 548, 548, 548, 9, 83, 16085, 5, 900, 15, 7417, 7419), + (7419, 548, 548, 548, 548, 10, 84, 16086, 5, 900, 15, 7418, 10096), + (7420, 5105, 5105, 5105, 5105, 12, 85, 16087, 11, 600, 15, 5832, 10509), + (7421, 6232, 6232, 6232, 6232, 12, 85, 16091, 18, 900, 15, 6232, -1), + (7422, 6561, 6561, 6561, 6561, 7, 81, 16088, 32, 30, 15, 6280, 7423), + (7423, 6561, 6561, 6561, 6561, 7, 81, 16089, 32, 30, 15, 7422, 7424), + (7424, 6561, 6561, 6561, 6561, 7, 81, 16090, 32, 30, 15, 7423, 10099), + (7425, 510, 510, 510, 510, 3, 66, 16072, 37, 240, 15, 512, 7426), + (7426, 510, 510, 510, 510, 3, 68, 16073, 37, 240, 15, 7425, 7427), + (7427, 510, 510, 510, 510, 3, 70, 16074, 37, 240, 15, 7426, 10102), + (7428, 6533, 6533, 6533, 6533, 10, 84, 13785, 15, 600, 15, 6200, 10139), + (7429, 6534, 6534, 6534, 6534, 9, 83, 13777, 16, 900, 15, 6201, 13524), + (7430, 1116, 1116, 1116, 1116, 7, 81, 13762, 4, 2160, 15, 5701, 7431), + (7431, 1116, 1116, 1116, 1116, 9, 83, 13763, 4, 2160, 15, 7430, 7432), + (7432, 1116, 1116, 1116, 1116, 12, 85, 13764, 4, 2160, 15, 7431, 10140), + (7433, 592, 592, 592, 592, 5, 81, 13765, 2, 18, 15, 5706, 7434), + (7434, 592, 592, 592, 592, 5, 82, 13766, 2, 18, 15, 7433, 7435), + (7435, 592, 592, 592, 592, 5, 83, 13767, 2, 18, 15, 7434, 7436), + (7436, 592, 592, 592, 592, 5, 84, 13768, 2, 18, 15, 7435, 7437), + (7437, 592, 592, 592, 592, 5, 85, 13769, 2, 18, 15, 7436, 12749), + (7438, 5298, 5298, 5298, 5298, 9, 83, 13770, 32, 1800, 15, 5709, 7439), + (7439, 5298, 5298, 5298, 5298, 10, 84, 13771, 32, 1800, 15, 7438, 7440), + (7440, 5298, 5298, 5298, 5298, 12, 85, 13772, 32, 1800, 15, 7439, 10143), + (7441, 1598, -1, 1598, 1598, 7, 81, 13773, 6, 900, 15, 5712, 7442), + (7442, 1598, -1, 1598, 1598, 9, 83, 13774, 6, 900, 15, 7441, 7443), + (7443, 1598, -1, 1598, 1598, 12, 85, 13775, 6, 900, 15, 7442, 10146), + (7444, 5020, 5020, 5020, 5020, 9, 82, 13776, 9, 300, 15, 5716, 10149), + (7445, 1110, 1110, 1110, 1110, 6, 78, 13778, 3, 2160, 15, 6402, 7446), + (7446, 1110, 1110, 1110, 1110, 6, 80, 13779, 3, 2160, 15, 7445, 7447), + (7447, 1110, 1110, 1110, 1110, 6, 81, 13780, 3, 2160, 15, 7446, 10150), + (7448, -1, -1, 6337, 6337, 6, 79, -1, 0, 0, 15, 6339, 7449), + (7449, -1, -1, 6337, 6337, 6, 81, -1, 0, 0, 15, 7448, 7450), + (7450, -1, -1, 6337, 6337, 6, 83, -1, 0, 0, 15, 7449, 10153), + (7451, -1, -1, 6340, 6340, 6, 79, -1, 0, 0, 15, 6342, 7452), + (7452, -1, -1, 6340, 6340, 6, 81, -1, 0, 0, 15, 7451, 7453), + (7453, -1, -1, 6340, 6340, 6, 83, -1, 0, 0, 15, 7452, 16306), + (7454, 5017, 5017, 5017, 5017, 3, 76, 13759, 8, 600, 15, 5019, 7455), + (7455, 5017, 5017, 5017, 5017, 6, 78, 13760, 8, 600, 15, 7454, 7456), + (7456, 5017, 5017, 5017, 5017, 9, 80, 13761, 8, 600, 15, 7455, 10156), + (7457, 1569, 1569, 1569, 1569, 7, 82, 13756, 5, 1800, 15, 5715, 7458), + (7458, 1569, 1569, 1569, 1569, 7, 83, 13757, 5, 1800, 15, 7457, 7459), + (7459, 1569, 1569, 1569, 1569, 7, 85, 13758, 5, 1800, 15, 7458, 10159), + (7460, 1327, 1327, 1327, 1327, 7, 81, 13792, 10, 900, 15, 6100, 7461), + (7461, 1327, 1327, 1327, 1327, 9, 83, 13793, 10, 900, 15, 7460, 7462), + (7462, 1327, 1327, 1327, 1327, 12, 85, 13794, 10, 900, 15, 7461, 10187), + (7463, 1520, 1520, 1520, 1520, 9, 75, 13801, 11, 900, 15, 6451, 7464), + (7464, 1520, 1520, 1520, 1520, 9, 75, 13802, 11, 900, 15, 7463, 7465), + (7465, 1520, 1520, 1520, 1520, 9, 75, 13803, 11, 900, 15, 7464, 10190), + (7466, 146, 146, 146, 146, 8, 82, 13796, 2, 180, 15, 6102, 7691), + (7467, 5109, 5109, 5109, 5109, 9, 82, 13800, 0, 1, 15, 6448, 13016), + (7468, 153, 153, 153, 153, 12, 85, 13795, 3, 2160, 15, 6101, 10193), + (7469, 528, 528, 528, 528, 7, 81, 13797, 5, 720, 15, 6105, 7470), + (7470, 528, 528, 528, 528, 9, 83, 13798, 5, 720, 15, 7469, 7471), + (7471, 528, 528, 528, 528, 12, 85, 13799, 5, 720, 15, 7470, 10194), + (7472, 5251, 5251, 5251, 5251, 7, 81, 13786, 13, 900, 15, 6094, 7473), + (7473, 5251, 5251, 5251, 5251, 9, 83, 13787, 13, 900, 15, 7472, 7474), + (7474, 5251, 5251, 5251, 5251, 12, 85, 13788, 13, 900, 15, 7473, 10197), + (7475, 513, 513, 513, 513, 7, 81, 13789, 4, 120, 15, 6097, 7476), + (7476, 513, 513, 513, 513, 9, 83, 13790, 4, 120, 15, 7475, 7477), + (7477, 513, 513, 513, 513, 12, 85, 13791, 4, 120, 15, 7476, -1), + (7478, -1, -1, 6538, 6538, 12, 85, -1, 0, 0, 15, 6211, 15421), + (7479, 1119, 1119, 1119, 1119, 7, 83, 13805, 8, 900, 15, 5736, 7480), + (7480, 1119, 1119, 1119, 1119, 8, 84, 13806, 8, 900, 15, 7479, 7481), + (7481, 1119, 1119, 1119, 1119, 9, 85, 13807, 8, 900, 15, 7480, 10297), + (7482, 723, 723, 723, 723, 7, 81, 13808, 6, 30, 15, 5737, 10300), + (7483, 5015, 5015, 5015, 5015, 12, 85, 13809, 9, 900, 15, 5741, 10301), + (7484, 289, 289, 289, 289, 12, 85, 13810, 3, 300, 15, 5742, -1), + (7485, 291, 291, 291, 291, 9, 83, 13811, 5, 900, 15, 5745, 7486), + (7486, 291, 291, 291, 291, 10, 84, 13812, 5, 900, 15, 7485, 7487), + (7487, 291, 291, 291, 291, 12, 85, 13813, 5, 900, 15, 7486, 10302), + (7488, 6218, 6218, 6218, 6218, 7, 81, 13814, 0, 1, 15, 6218, 14272), + (7489, -1, -1, 724, 724, 7, 81, -1, 0, 0, 15, 5733, 7490), + (7490, -1, -1, 724, 724, 8, 82, -1, 0, 0, 15, 7489, 7491), + (7491, -1, -1, 724, 724, 9, 83, -1, 0, 0, 15, 7490, 7492), + (7492, -1, -1, 724, 724, 10, 84, -1, 0, 0, 15, 7491, 7493), + (7493, -1, -1, 724, 724, 12, 85, -1, 0, 0, 15, 7492, 16890), + (7494, -1, -1, 729, 729, 7, 81, -1, 0, 0, 15, 5740, 7495), + (7495, -1, -1, 729, 729, 8, 82, -1, 0, 0, 15, 7494, 7496), + (7496, -1, -1, 729, 729, 9, 83, -1, 0, 0, 15, 7495, 10305), + (7497, 6380, 6380, 6380, 6380, 6, 83, 13815, 39, 120, 15, 6382, 7498), + (7498, 6380, 6380, 6380, 6380, 6, 84, 13816, 39, 120, 15, 7497, 7499), + (7499, 6380, 6380, 6380, 6380, 6, 85, 13817, 39, 120, 15, 7498, 10308), + (7500, -1, -1, 4699, 4699, 5, 61, -1, 0, 0, 15, 6540, 10788), + (7501, -1, -1, 125, 125, 6, 81, -1, 0, 0, 15, 5523, 7502), + (7502, -1, -1, 125, 125, 7, 82, -1, 0, 0, 15, 7501, 7503), + (7503, -1, -1, 125, 125, 8, 83, -1, 0, 0, 15, 7502, 7504), + (7504, -1, -1, 125, 125, 9, 84, -1, 0, 0, 15, 7503, 7505), + (7505, -1, -1, 125, 125, 10, 85, -1, 0, 0, 15, 7504, 12396), + (7506, -1, -1, 122, 122, 6, 81, -1, 0, 0, 15, 5528, 7507), + (7507, -1, -1, 122, 122, 7, 82, -1, 0, 0, 15, 7506, 7508), + (7508, -1, -1, 122, 122, 8, 83, -1, 0, 0, 15, 7507, 7509), + (7509, -1, -1, 122, 122, 9, 84, -1, 0, 0, 15, 7508, 7510), + (7510, -1, -1, 122, 122, 10, 85, -1, 0, 0, 15, 7509, 12401), + (7511, -1, -1, 1026, 1026, 5, 81, -1, 0, 0, 15, 6527, 7512), + (7512, -1, -1, 1026, 1026, 5, 82, -1, 0, 0, 15, 7511, 7513), + (7513, -1, -1, 1026, 1026, 5, 83, -1, 0, 0, 15, 7512, 7514), + (7514, -1, -1, 1026, 1026, 5, 84, -1, 0, 0, 15, 7513, 7515), + (7515, -1, -1, 1026, 1026, 5, 85, -1, 0, 0, 15, 7514, 7886), + (7516, -1, -1, 1006, 1006, 5, 71, -1, 0, 0, 15, 1010, 7517), + (7517, -1, -1, 1006, 1006, 5, 72, -1, 0, 0, 15, 7516, 7518), + (7518, -1, -1, 1006, 1006, 5, 73, -1, 0, 0, 15, 7517, 7519), + (7519, -1, -1, 1006, 1006, 5, 74, -1, 0, 0, 15, 7518, 7520), + (7520, -1, -1, 1006, 1006, 5, 75, -1, 0, 0, 15, 7519, 7837), + (7521, -1, -1, 1056, 1056, 5, 81, -1, 0, 0, 15, 6435, 7522), + (7522, -1, -1, 1056, 1056, 5, 82, -1, 0, 0, 15, 7521, 7523), + (7523, -1, -1, 1056, 1056, 5, 83, -1, 0, 0, 15, 7522, 7524), + (7524, -1, -1, 1056, 1056, 5, 84, -1, 0, 0, 15, 7523, 7525), + (7525, -1, -1, 1056, 1056, 5, 85, -1, 0, 0, 15, 7524, 16414), + (7526, -1, -1, 6119, 6119, 6, 81, -1, 0, 0, 15, 6123, 7527), + (7527, -1, -1, 6119, 6119, 6, 82, -1, 0, 0, 15, 7526, 7528), + (7528, -1, -1, 6119, 6119, 6, 83, -1, 0, 0, 15, 7527, 7529), + (7529, -1, -1, 6119, 6119, 6, 84, -1, 0, 0, 15, 7528, 7530), + (7530, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 15, 7529, 12406), + (7534, -1, -1, 65, 661, 3, 81, -1, 0, 0, 15, 6394, 7535), + (7535, -1, -1, 65, 661, 3, 82, -1, 0, 0, 15, 7534, 7536), + (7536, -1, -1, 65, 661, 3, 83, -1, 0, 0, 15, 7535, 7537), + (7537, -1, -1, 65, 661, 3, 84, -1, 0, 0, 15, 7536, 7538), + (7538, -1, -1, 65, 661, 3, 85, -1, 0, 0, 15, 7537, 7904), + (7539, -1, -1, 1021, 1021, 5, 80, -1, 0, 0, 16, 6522, 7540), + (7540, -1, -1, 1021, 1021, 5, 85, -1, 0, 0, 16, 7539, 7683), + (7541, -1, -1, 107, 107, 2, 60, -1, 0, 0, 15, 109, 7542), + (7542, -1, -1, 107, 107, 4, 60, -1, 0, 0, 15, 7541, 7543), + (7543, -1, -1, 107, 107, 6, 60, -1, 0, 0, 15, 7542, -1), + (7544, -1, -1, 678, 678, 3, 70, -1, 0, 0, 15, 6520, 7545), + (7545, -1, -1, 678, 678, 3, 70, -1, 0, 0, 15, 7544, 7546), + (7546, -1, -1, 678, 678, 3, 70, -1, 0, 0, 15, 7545, -1), + (7547, -1, -1, 418, 418, 5, 76, -1, 0, 0, 15, 4682, 7548), + (7548, -1, -1, 418, 418, 5, 77, -1, 0, 0, 15, 7547, 7549), + (7549, -1, -1, 418, 418, 5, 78, -1, 0, 0, 15, 7548, 7550), + (7550, -1, -1, 418, 418, 5, 79, -1, 0, 0, 15, 7549, 7551), + (7551, -1, -1, 418, 418, 5, 80, -1, 0, 0, 15, 7550, -1), + (7553, -1, -1, 1071, 1071, 6, 80, -1, 0, 0, 16, 4764, 7681), + (7554, -1, -1, 1486, 1486, 7, 81, -1, 0, 0, 15, 5533, 7555), + (7555, -1, -1, 1486, 1486, 8, 82, -1, 0, 0, 15, 7554, 7556), + (7556, -1, -1, 1486, 1486, 9, 83, -1, 0, 0, 15, 7555, 7557), + (7557, -1, -1, 1486, 1486, 10, 84, -1, 0, 0, 15, 7556, 7558), + (7558, -1, -1, 1486, 1486, 12, 85, -1, 0, 0, 15, 7557, 7722), + (7559, -1, -1, 599, 599, 9, 83, -1, 0, 0, 15, 5536, 7560), + (7560, -1, -1, 599, 599, 10, 84, -1, 0, 0, 15, 7559, 7561), + (7561, -1, -1, 599, 599, 12, 85, -1, 0, 0, 15, 7560, 13026), + (7562, -1, -1, 1041, 1041, 7, 81, -1, 0, 0, 15, 5544, 7563), + (7563, -1, -1, 1041, 1041, 9, 83, -1, 0, 0, 15, 7562, 7564), + (7564, -1, -1, 1041, 1041, 12, 85, -1, 0, 0, 15, 7563, 12697), + (7565, -1, -1, 119, 119, 7, 81, -1, 0, 0, 15, 5556, 7566), + (7566, -1, -1, 119, 119, 9, 83, -1, 0, 0, 15, 7565, 7567), + (7567, -1, -1, 119, 119, 12, 85, -1, 0, 0, 15, 7566, 6023), + (7568, -1, -1, 1592, 1592, 7, 81, -1, 0, 0, 15, 5561, 7569), + (7569, -1, -1, 1592, 1592, 8, 82, -1, 0, 0, 15, 7568, 7570), + (7570, -1, -1, 1592, 1592, 9, 83, -1, 0, 0, 15, 7569, 7571), + (7571, -1, -1, 1592, 1592, 10, 84, -1, 0, 0, 15, 7570, 7572), + (7572, -1, -1, 1592, 1592, 12, 85, -1, 0, 0, 15, 7571, 12439), + (7573, -1, -1, 4739, 4739, 7, 81, -1, 0, 0, 15, 5564, 7574), + (7574, -1, -1, 4739, 4739, 9, 83, -1, 0, 0, 15, 7573, 7575), + (7575, -1, -1, 4739, 4739, 12, 85, -1, 0, 0, 15, 7574, -1), + (7576, -1, -1, 1072, 1072, 7, 81, -1, 0, 0, 15, 5570, 7577), + (7577, -1, -1, 1072, 1072, 8, 82, -1, 0, 0, 15, 7576, 7578), + (7578, -1, -1, 1072, 1072, 9, 83, -1, 0, 0, 15, 7577, 7579), + (7579, -1, -1, 1072, 1072, 10, 84, -1, 0, 0, 15, 7578, 7580), + (7580, -1, -1, 1072, 1072, 12, 85, -1, 0, 0, 15, 7579, 12444), + (7581, -1, -1, 1210, 1213, 7, 81, -1, 0, 0, 15, 5579, 7582), + (7582, -1, -1, 1210, 1213, 9, 83, -1, 0, 0, 15, 7581, 7583), + (7583, -1, -1, 1210, 1213, 12, 85, -1, 0, 0, 15, 7582, 8344), + (7584, -1, -1, 98, 98, 7, 81, -1, 0, 0, 15, 5588, 7585), + (7585, -1, -1, 98, 98, 9, 83, -1, 0, 0, 15, 7584, 7586), + (7586, -1, -1, 98, 98, 12, 85, -1, 0, 0, 15, 7585, 11061), + (7587, -1, -1, 1186, 1186, 7, 81, -1, 0, 0, 15, 5591, 7588), + (7588, -1, -1, 1186, 1186, 9, 83, -1, 0, 0, 15, 7587, 7589), + (7589, -1, -1, 1186, 1186, 12, 85, -1, 0, 0, 15, 7588, 7692), + (7590, -1, -1, 80, 80, 7, 81, -1, 0, 0, 15, 5594, 7591), + (7591, -1, -1, 80, 80, 9, 83, -1, 0, 0, 15, 7590, 7592), + (7592, -1, -1, 80, 80, 12, 85, -1, 0, 0, 15, 7591, 12452), + (7593, -1, -1, 658, 658, 5, 81, -1, 0, 0, 15, 5627, 7594), + (7594, -1, -1, 658, 658, 5, 82, -1, 0, 0, 15, 7593, 7595), + (7595, -1, -1, 658, 658, 5, 83, -1, 0, 0, 15, 7594, 7596), + (7596, -1, -1, 658, 658, 5, 84, -1, 0, 0, 15, 7595, 7597), + (7597, -1, -1, 658, 658, 5, 85, -1, 0, 0, 15, 7596, 12455), + (7598, -1, -1, 98, 738, 7, 81, -1, 0, 0, 15, 5630, 7599), + (7599, -1, -1, 98, 738, 9, 83, -1, 0, 0, 15, 7598, 7600), + (7600, -1, -1, 98, 738, 12, 85, -1, 0, 0, 15, 7599, 13924), + (7601, -1, -1, 6051, 6051, 3, 81, -1, 0, 0, 15, 6053, 7602), + (7602, -1, -1, 6051, 6051, 3, 83, -1, 0, 0, 15, 7601, 7603), + (7603, -1, -1, 6051, 6051, 3, 85, -1, 0, 0, 15, 7602, 10604), + (7604, -1, -1, 683, 683, 5, 80, -1, 0, 0, 15, 6081, 7605), + (7605, -1, -1, 683, 683, 5, 80, -1, 0, 0, 15, 7604, 12694), + (7606, 6537, 6537, 6537, 6537, 7, 81, 13821, 30, 900, 15, 6208, 7607), + (7607, 6537, 6537, 6537, 6537, 8, 82, 13822, 30, 900, 15, 7606, 7608), + (7608, 6537, 6537, 6537, 6537, 9, 83, 13823, 30, 900, 15, 7607, 12460), + (7609, 6539, 6539, 6539, 6539, 6, 76, 13824, 18, 1800, 15, 6214, 7610), + (7610, 6539, 6539, 6539, 6539, 6, 79, 13825, 18, 1800, 15, 7609, 7611), + (7611, 6539, 6539, 6539, 6539, 6, 82, 13826, 18, 1800, 15, 7610, 12942), + (7612, -1, -1, 270, 665, 2, 66, -1, 0, 0, 15, 670, 7613), + (7613, -1, -1, 270, 665, 2, 67, -1, 0, 0, 15, 7612, 7614), + (7614, -1, -1, 270, 665, 2, 68, -1, 0, 0, 15, 7613, -1), + (7615, -1, -1, 6346, 6346, 6, 79, -1, 0, 0, 15, 6348, 7616), + (7616, -1, -1, 6346, 6346, 6, 81, -1, 0, 0, 15, 7615, 7617), + (7617, -1, -1, 6346, 6346, 6, 83, -1, 0, 0, 15, 7616, 15397), + (7618, -1, -1, 6349, 6349, 6, 79, -1, 0, 0, 15, 6351, 7619), + (7619, -1, -1, 6349, 6349, 6, 81, -1, 0, 0, 15, 7618, 7620), + (7620, -1, -1, 6349, 6349, 6, 83, -1, 0, 0, 15, 7619, 11053), + (7621, -1, -1, 1435, 4773, 9, 81, -1, 0, 0, 15, 6517, 13090), + (7622, -1, -1, 446, 735, 8, 81, -1, 0, 0, 15, 7065, 7623), + (7623, -1, -1, 446, 735, 8, 82, -1, 0, 0, 15, 7622, 7624), + (7624, -1, -1, 446, 735, 8, 83, -1, 0, 0, 15, 7623, 10473), + (7625, -1, -1, 735, 735, 8, 81, -1, 0, 0, 15, 7068, 7626), + (7626, -1, -1, 735, 735, 8, 82, -1, 0, 0, 15, 7625, 7627), + (7627, -1, -1, 735, 735, 8, 83, -1, 0, 0, 15, 7626, 10632), + (7628, -1, -1, 807, 807, 5, 81, -1, 0, 0, 15, 5924, 7629), + (7629, -1, -1, 807, 807, 5, 83, -1, 0, 0, 15, 7628, 7630), + (7630, -1, -1, 807, 807, 5, 85, -1, 0, 0, 15, 7629, 12685), + (7631, -1, -1, 255, 255, 7, 81, -1, 0, 0, 15, 5597, 7632), + (7632, -1, -1, 255, 255, 9, 83, -1, 0, 0, 15, 7631, 7633), + (7633, -1, -1, 255, 255, 12, 85, -1, 0, 0, 15, 7632, 17441), + (7634, -1, -1, 815, 815, 9, 83, -1, 0, 0, 15, 5913, 7635), + (7635, -1, -1, 815, 815, 10, 84, -1, 0, 0, 15, 7634, 7636), + (7636, -1, -1, 815, 815, 12, 85, -1, 0, 0, 15, 7635, 15441), + (7637, -1, -1, 1616, 1616, 5, 83, -1, 0, 0, 15, 6007, 7638), + (7638, -1, -1, 1616, 1616, 5, 84, -1, 0, 0, 15, 7637, 7639), + (7639, -1, -1, 1616, 1616, 5, 85, -1, 0, 0, 15, 7638, -1), + (7640, -1, -1, 686, 686, 5, 60, -1, 0, 0, 15, 690, 12438), + (7641, -1, -1, 625, 625, 3, 76, -1, 0, 0, 15, 4735, 7642), + (7642, -1, -1, 625, 625, 3, 78, -1, 0, 0, 15, 7641, 7643), + (7643, -1, -1, 625, 625, 3, 80, -1, 0, 0, 15, 7642, -1), + (7644, -1, -1, 6375, 6375, 6, 81, -1, 0, 0, 15, 6377, 7645), + (7645, -1, -1, 6375, 6375, 6, 82, -1, 0, 0, 15, 7644, 7646), + (7646, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 15, 7645, 7663), + (7647, -1, -1, 692, 692, 6, 60, -1, 0, 0, 15, 694, 7648), + (7648, -1, -1, 692, 692, 6, 60, -1, 0, 0, 15, 7647, 7649), + (7649, -1, -1, 692, 692, 6, 60, -1, 0, 0, 15, 7648, 7670), + (7650, -1, -1, 1044, 1044, 7, 81, -1, 0, 0, 15, 5547, 7651), + (7651, -1, -1, 1044, 1044, 9, 83, -1, 0, 0, 15, 7650, 7652), + (7652, -1, -1, 1044, 1044, 12, 85, -1, 0, 0, 15, 7651, 13074), + (7653, -1, -1, 1047, 1047, 7, 81, -1, 0, 0, 15, 5550, 7654), + (7654, -1, -1, 1047, 1047, 9, 83, -1, 0, 0, 15, 7653, 7655), + (7655, -1, -1, 1047, 1047, 12, 85, -1, 0, 0, 15, 7654, 13077), + (7656, -1, -1, 1050, 1050, 7, 81, -1, 0, 0, 15, 5553, 7657), + (7657, -1, -1, 1050, 1050, 9, 83, -1, 0, 0, 15, 7656, 7658), + (7658, -1, -1, 1050, 1050, 12, 85, -1, 0, 0, 15, 7657, 13023), + (7659, -1, -1, 754, 754, 3, 70, -1, 0, 0, 15, 756, 7660), + (7660, -1, -1, 754, 754, 6, 70, -1, 0, 0, 15, 7659, 7661), + (7661, -1, -1, 754, 754, 9, 70, -1, 0, 0, 15, 7660, -1), + (7662, 188, 188, 188, 188, 9, 83, 16431, 2, 30, 15, 7339, 10647), + (7663, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 15, 7646, 10084), + (7664, -1, -1, 7664, 7664, 2, 73, -1, 0, 0, 15, -1, 7665), + (7665, -1, -1, 7664, 7664, 2, 74, -1, 0, 0, 15, 7664, 7666), + (7666, -1, -1, 7664, 7664, 2, 75, -1, 0, 0, 15, 7665, 7667), + (7667, -1, -1, 7664, 7664, 2, 76, -1, 0, 0, 15, 7666, 7668), + (7668, -1, -1, 7664, 7664, 2, 77, -1, 0, 0, 15, 7667, 10105), + (7669, 7669, 7669, 7669, 7669, 3, 81, 13838, 35, 5, 15, -1, -1), + (7670, -1, -1, 692, 692, 7, 75, -1, 0, 0, 16, 7649, 7671), + (7671, -1, -1, 692, 692, 9, 80, -1, 0, 0, 16, 7670, 7672), + (7672, -1, -1, 692, 692, 12, 85, -1, 0, 0, 16, 7671, 12767), + (7673, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 859, 7674), + (7674, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 7673, 7675), + (7675, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 7674, 7676), + (7676, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 7675, 7677), + (7677, -1, -1, 855, 855, 5, 75, -1, 0, 0, 16, 7676, 10688), + (7678, -1, -1, 852, 852, 9, 81, -1, 0, 0, 16, 5502, 7679), + (7679, -1, -1, 852, 852, 10, 83, -1, 0, 0, 16, 7678, 7680), + (7680, -1, -1, 852, 852, 12, 85, -1, 0, 0, 16, 7679, 12576), + (7681, -1, -1, 1071, 1071, 6, 80, -1, 0, 0, 16, 7553, -1), + (7682, -1, -1, 4861, 4861, 12, 85, -1, 0, 0, 16, 7216, 12757), + (7683, -1, -1, 1021, 1021, 5, 85, -1, 0, 0, 16, 7540, 7684), + (7684, -1, -1, 1021, 1021, 5, 85, -1, 0, 0, 16, 7683, 7685), + (7685, -1, -1, 1021, 1021, 5, 85, -1, 0, 0, 16, 7684, 13894), + (7686, -1, -1, 4844, 4844, 5, 81, -1, 0, 0, 16, 7126, 7687), + (7687, -1, -1, 4844, 4844, 5, 83, -1, 0, 0, 16, 7686, 7688), + (7688, -1, -1, 4844, 4844, 5, 85, -1, 0, 0, 16, 7687, -1), + (7689, 7689, 7689, 7689, 7689, 12, 85, 21820, 94, 180, 16, -1, -1), + (7690, -1, -1, 7690, 7690, 12, 85, -1, 0, 0, 16, -1, -1), + (7691, 146, 146, 146, 146, 8, 85, 16862, 2, 180, 16, 7466, 13256), + (7692, -1, -1, 1186, 1186, 12, 85, -1, 0, 0, 16, 7589, 7693), + (7693, -1, -1, 1186, 1186, 12, 85, -1, 0, 0, 16, 7692, 7694), + (7694, -1, -1, 1186, 1186, 12, 85, -1, 0, 0, 16, 7693, 12564), + (7695, -1, -1, 7695, 7695, 6, 85, -1, 0, 0, 16, -1, 7696), + (7696, -1, -1, 7695, 7695, 6, 85, -1, 0, 0, 16, 7695, 7697), + (7697, -1, -1, 7695, 7695, 6, 85, -1, 0, 0, 16, 7696, -1), + (7698, 7698, 7698, 7698, 7698, 6, 85, 21763, 17, 6, 16, -1, -1), + (7699, -1, -1, 7699, 7699, 12, 85, 0, 0, 0, 16, -1, -1), + (7700, -1, -1, 255, 255, 7, 81, -1, 0, 0, 16, -1, 7701), + (7701, -1, -1, 255, 255, 9, 83, -1, 0, 0, 16, 7700, 7702), + (7702, -1, -1, 255, 255, 12, 85, -1, 0, 0, 16, 7701, 12610), + (7703, 7703, 7703, 7703, 7703, 12, 85, 21754, 16, 600, 16, -1, -1), + (7704, -1, -1, 8195, 8195, 5, 81, -1, 0, 0, 16, 8197, 7705), + (7705, -1, -1, 8195, 8195, 5, 83, -1, 0, 0, 16, 7704, 7706), + (7706, -1, -1, 8195, 8195, 5, 85, -1, 0, 0, 16, 7705, -1), + (7707, -1, -1, 589, 589, 7, 85, -1, 0, 0, 16, 7392, 7708), + (7708, -1, -1, 589, 589, 7, 85, -1, 0, 0, 16, 7707, 7709), + (7709, -1, -1, 589, 589, 7, 85, -1, 0, 0, 16, 7708, 13104), + (7710, 5984, 5984, 5984, 5984, 12, 85, 21679, 2, 30, 16, 7335, 7711), + (7711, 5984, 5984, 5984, 5984, 12, 85, 21680, 2, 30, 16, 7710, 10626), + (7712, 7712, 7712, 7712, 7712, 12, 85, 21682, 2, 30, 16, -1, 10646), + (7713, -1, -1, 634, 634, 12, 81, -1, 0, 0, 16, 5613, 7714), + (7714, -1, -1, 634, 634, 12, 83, -1, 0, 0, 16, 7713, 10778), + (7715, -1, -1, 7715, 7715, 5, 77, 0, 0, 0, 16, -1, 7716), + (7716, -1, -1, 7715, 7715, 5, 79, 0, 0, 0, 16, 7715, 7717), + (7717, -1, -1, 7715, 7715, 5, 81, 0, 0, 0, 16, 7716, 14314), + (7718, -1, -1, 574, 574, 3, 81, -1, 0, 0, 16, 576, -1), + (7722, -1, -1, 1486, 1486, 7, 86, -1, 0, 0, 17, 7558, 7723), + (7723, -1, -1, 1486, 1486, 8, 87, -1, 0, 0, 17, 7722, 7724), + (7724, -1, -1, 1486, 1486, 9, 88, -1, 0, 0, 17, 7723, 7725), + (7725, -1, -1, 1486, 1486, 10, 89, -1, 0, 0, 17, 7724, 7726), + (7726, -1, -1, 1486, 1486, 12, 90, -1, 0, 0, 17, 7725, 7842), + (7732, 7732, 7732, 7732, 7732, 0, 60, 7732, 34, 3600, 14, -1, -1), + (7733, -1, -1, 288, 288, 6, 65, -1, 0, 0, 14, -1, -1), + (7734, 7734, 7734, 7734, 7734, 0, 61, 7734, 34, 28800, 14, -1, -1), + (7735, 7735, 7735, 7735, 7735, 0, 51, 7731, 32, 3600, 9, -1, -1), + (7736, 7736, 7736, 7736, 7736, 0, 52, 7865, 32, 10800, 9, -1, -1), + (7737, 7737, 7737, 7737, 7737, 0, 53, 7733, 32, 10800, 9, -1, -1), + (7738, 7738, 7738, 7738, 7738, 0, 54, 7990, 32, 21600, 9, -1, -1), + (7739, 7739, 7739, 7739, 7739, 0, 65, 13064, 36, 3600, 0, -1, -1), + (7740, 7740, 7740, 7740, 7740, 0, 66, 13065, 36, 28800, 0, -1, -1), + (7741, 7741, 7741, 7741, 7741, 0, 70, 21854, 50, 3600, 0, -1, -1), + (7742, 7742, 7742, 7742, 7742, 0, 71, 21855, 50, 28800, 0, -1, -1), + (7743, -1, -1, 7743, 7743, 5, 61, -1, 0, 0, 16, -1, 7744), + (7744, -1, -1, 7743, 7743, 7, 61, -1, 0, 0, 16, 7743, 7745), + (7745, -1, -1, 7743, 7743, 9, 61, -1, 0, 0, 16, 7744, 10717), + (7746, -1, -1, 7746, 7746, 5, 85, -1, 0, 0, 16, -1, 7763), + (7747, 7747, 7747, 7747, 7747, 9, 85, 21790, 32, 180, 16, -1, -1), + (7748, -1, -1, 7748, 7748, 3, 81, -1, 0, 0, 16, -1, 7749), + (7749, -1, -1, 7748, 7748, 6, 83, -1, 0, 0, 16, 7748, 7750), + (7750, -1, -1, 7748, 7748, 9, 85, -1, 0, 0, 16, 7749, -1), + (7751, -1, -1, 7751, 7751, 5, 85, -1, 0, 0, 16, -1, 7752), + (7752, -1, -1, 7751, 7751, 5, 85, -1, 0, 0, 16, 7751, 7753), + (7753, -1, -1, 7751, 7751, 5, 85, -1, 0, 0, 16, 7752, 14132), + (7754, 7754, 7754, 7754, 7754, 9, 85, 21803, 0, 1, 16, -1, -1), + (7755, 7755, 7755, 7755, 7755, 9, 81, 21804, 53, 900, 16, -1, 15782), + (7756, 7756, 7756, 7756, 7756, 12, 85, 21805, 54, 120, 16, -1, -1), + (7757, -1, -1, 7757, 7757, 5, 85, -1, 0, 0, 16, -1, 7758), + (7758, -1, -1, 7757, 7757, 7, 85, -1, 0, 0, 16, 7757, 7759), + (7759, -1, -1, 7757, 7757, 9, 85, -1, 0, 0, 16, 7758, 12587), + (7760, -1, -1, 7760, 7760, 5, 85, -1, 0, 0, 16, -1, 7761), + (7761, -1, -1, 7760, 7760, 7, 85, -1, 0, 0, 16, 7760, 7762), + (7762, -1, -1, 7760, 7760, 9, 85, -1, 0, 0, 16, 7761, -1), + (7763, -1, -1, 7746, 7746, 5, 85, -1, 0, 0, 16, 7746, 7764), + (7764, -1, -1, 7746, 7746, 5, 85, -1, 0, 0, 16, 7763, -1), + (7765, -1, -1, 7765, 7765, 5, 86, 0, 0, 0, 17, -1, 7766), + (7766, -1, -1, 7765, 7765, 7, 87, 0, 0, 0, 17, 7765, 7767), + (7767, -1, -1, 7765, 7765, 9, 88, 0, 0, 0, 17, 7766, 7768), + (7768, -1, -1, 7765, 7765, 12, 89, 0, 0, 0, 17, 7767, 7769), + (7770, 131, 131, 131, 131, 9, 86, 27655, 4, 900, 17, 10018, 7771), + (7771, 131, 131, 131, 131, 12, 88, 27656, 4, 900, 17, 7770, 7772), + (7772, 131, 131, 131, 131, 15, 90, 27657, 4, 900, 17, 7771, 13374), + (7773, 7951, 7951, 7951, 7951, 9, 86, 27658, 61, 900, 17, 10040, 7774), + (7774, 7951, 7951, 7951, 7951, 9, 88, 27659, 61, 900, 17, 7773, 7775), + (7775, 7951, 7951, 7951, 7951, 9, 90, 27660, 61, 900, 17, 7774, 13377), + (7800, 7800, 7800, 7800, 7800, 0, 1, 13531, 39, 4320, 0, -1, 7801), + (7801, 7800, 7800, 7800, 7800, 0, 6, 13532, 39, 4320, 0, 7800, 7802), + (7802, 7800, 7800, 7800, 7800, 0, 11, 13533, 39, 4320, 0, 7801, 7803), + (7803, 7800, 7800, 7800, 7800, 0, 16, 13534, 39, 4320, 0, 7802, 7804), + (7804, 7800, 7800, 7800, 7800, 0, 21, 13535, 39, 4320, 0, 7803, 7805), + (7805, 7800, 7800, 7800, 7800, 0, 26, 13536, 39, 4320, 0, 7804, 7806), + (7806, 7800, 7800, 7800, 7800, 0, 31, 13537, 39, 4320, 0, 7805, 7807), + (7807, 7800, 7800, 7800, 7800, 0, 36, 13538, 39, 4320, 0, 7806, 7808), + (7808, 7800, 7800, 7800, 7800, 0, 41, 13539, 39, 4320, 0, 7807, 7809), + (7809, 7800, 7800, 7800, 7800, 0, 46, 13540, 39, 4320, 0, 7808, 7810), + (7810, 7800, 7800, 7800, 7800, 3, 51, 13541, 39, 4320, 0, 7809, 7811), + (7811, 7800, 7800, 7800, 7800, 4, 56, 13542, 39, 4320, 0, 7810, 7812), + (7812, 7800, 7800, 7800, 7800, 5, 61, 13543, 39, 4320, 0, 7811, 7813), + (7813, 7800, 7800, 7800, 7800, 6, 66, 13544, 39, 4320, 0, 7812, 7814), + (7814, 7800, 7800, 7800, 7800, 7, 71, 13545, 39, 4320, 0, 7813, 7815), + (7815, 7800, 7800, 7800, 7800, 8, 76, 13562, 39, 4320, 0, 7814, 7816), + (7816, 7800, 7800, 7800, 7800, 8, 81, 16062, 39, 4320, 0, 7815, 7817), + (7817, 7800, 7800, 7800, 7800, 9, 83, 16855, 39, 4320, 0, 7816, 10786), + (7818, -1, -1, 7818, 7818, 12, 85, 21750, 0, 0, 16, -1, 13029), + (7819, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 9514, 7820), + (7820, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7819, 7821), + (7821, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7820, 7881), + (7822, -1, -1, 7822, 7822, 5, 77, 0, 0, 0, 16, -1, 7823), + (7823, -1, -1, 7822, 7822, 5, 79, 0, 0, 0, 16, 7822, 7824), + (7824, -1, -1, 7822, 7822, 5, 81, 0, 0, 0, 16, 7823, 7825), + (7825, -1, -1, 7822, 7822, 5, 83, 0, 0, 0, 16, 7824, 7826), + (7826, -1, -1, 7822, 7822, 5, 85, 0, 0, 0, 16, 7825, 14328), + (7827, -1, -1, 7827, 7827, 5, 81, 0, 0, 0, 16, -1, -1), + (7828, -1, -1, 7828, 7828, 5, 79, 0, 0, 0, 16, -1, 7829), + (7829, -1, -1, 7828, 7828, 5, 81, 0, 0, 0, 16, 7828, 7830), + (7830, -1, -1, 7828, 7828, 5, 83, 0, 0, 0, 16, 7829, -1), + (7832, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, -1, 7833), + (7833, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, 7832, 7834), + (7834, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, 7833, 7835), + (7835, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, 7834, 7836), + (7836, -1, -1, 7832, 7832, 5, 85, 0, 0, 0, 16, 7835, -1), + (7837, -1, -1, 1006, 1006, 5, 76, -1, 0, 0, 17, 7520, 7838), + (7838, -1, -1, 1006, 1006, 5, 77, -1, 0, 0, 17, 7837, 7839), + (7839, -1, -1, 1006, 1006, 5, 78, -1, 0, 0, 17, 7838, 7840), + (7840, -1, -1, 1006, 1006, 5, 79, -1, 0, 0, 17, 7839, 7841), + (7841, -1, -1, 1006, 1006, 5, 80, -1, 0, 0, 17, 7840, 8470), + (7842, -1, -1, 1486, 1486, 12, 91, -1, 0, 0, 18, 7726, 7843), + (7843, -1, -1, 1486, 1486, 12, 92, -1, 0, 0, 18, 7842, 7844), + (7844, -1, -1, 1486, 1486, 12, 93, -1, 0, 0, 18, 7843, 7845), + (7850, 7850, 7850, 7850, 7850, 0, 1, 13546, 39, 4320, 0, -1, 7851), + (7851, 7850, 7850, 7850, 7850, 0, 6, 13547, 39, 4320, 0, 7850, 7852), + (7852, 7850, 7850, 7850, 7850, 0, 11, 13548, 39, 4320, 0, 7851, 7853), + (7853, 7850, 7850, 7850, 7850, 0, 16, 13549, 39, 4320, 0, 7852, 7854), + (7854, 7850, 7850, 7850, 7850, 0, 21, 13550, 39, 4320, 0, 7853, 7855), + (7855, 7850, 7850, 7850, 7850, 0, 26, 13551, 39, 4320, 0, 7854, 7856), + (7856, 7850, 7850, 7850, 7850, 0, 31, 13552, 39, 4320, 0, 7855, 7857), + (7857, 7850, 7850, 7850, 7850, 0, 36, 13553, 39, 4320, 0, 7856, 7858), + (7858, 7850, 7850, 7850, 7850, 0, 41, 13554, 39, 4320, 0, 7857, 7859), + (7859, 7850, 7850, 7850, 7850, 0, 46, 13555, 39, 4320, 0, 7858, 7860), + (7860, 7850, 7850, 7850, 7850, 3, 51, 13556, 39, 4320, 0, 7859, 7861), + (7861, 7850, 7850, 7850, 7850, 4, 56, 13557, 39, 4320, 0, 7860, 7862), + (7862, 7850, 7850, 7850, 7850, 5, 61, 13558, 39, 4320, 0, 7861, 7863), + (7863, 7850, 7850, 7850, 7850, 6, 66, 13559, 39, 4320, 0, 7862, 7864), + (7864, 7850, 7850, 7850, 7850, 7, 71, 13560, 39, 4320, 0, 7863, 7865), + (7865, 7850, 7850, 7850, 7850, 8, 76, 13561, 39, 4320, 0, 7864, 7340), + (7869, 7869, 7869, 7869, 7869, 6, 73, 16175, 60, 30, 15, -1, 7870), + (7870, 7869, 7869, 7869, 7869, 6, 77, 16176, 60, 30, 15, 7869, 7871), + (7871, 7869, 7869, 7869, 7869, 6, 81, 16177, 60, 30, 15, 7870, -1), + (7872, 7872, 7872, 7872, 7872, 6, 76, 16178, 41, 600, 15, -1, 7873), + (7873, 7872, 7872, 7872, 7872, 6, 81, 16179, 41, 600, 15, 7872, 7874), + (7874, 7872, 7872, 7872, 7872, 6, 85, 16180, 41, 600, 15, 7873, 10127), + (7875, 7875, 7875, 7875, 7875, 6, 76, 16181, 42, 600, 15, -1, 7876), + (7876, 7875, 7875, 7875, 7875, 6, 81, 16182, 42, 600, 15, 7875, 7877), + (7877, 7875, 7875, 7875, 7875, 6, 85, 16183, 42, 600, 15, 7876, 7878), + (7878, 7875, 7875, 7875, 7875, 6, 85, 16859, 42, 600, 16, 7877, 7879), + (7879, 7875, 7875, 7875, 7875, 6, 85, 21823, 42, 600, 16, 7878, 7880), + (7880, 7875, 7875, 7875, 7875, 6, 85, 21824, 42, 600, 16, 7879, 13816), + (7881, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7821, 7882), + (7882, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7881, 7883), + (7883, -1, -1, 9512, 9512, 7, 85, -1, 0, 0, 16, 7882, 13187), + (7884, -1, -1, 7884, 7884, 9, 85, -1, 0, 0, 16, -1, 12689), + (7885, -1, -1, 7885, 7885, 9, 85, -1, 0, 0, 16, -1, 12690), + (7886, -1, -1, 1026, 1026, 5, 85, -1, 0, 0, 17, 7515, 7887), + (7887, -1, -1, 1026, 1026, 5, 86, -1, 0, 0, 17, 7886, 7888), + (7888, -1, -1, 1026, 1026, 5, 87, -1, 0, 0, 17, 7887, 7889), + (7889, -1, -1, 1026, 1026, 5, 88, -1, 0, 0, 17, 7888, 7890), + (7890, -1, -1, 1026, 1026, 5, 89, -1, 0, 0, 17, 7889, 8430), + (7900, -1, -1, 7900, 7900, 4, 60, -1, 0, 0, 15, -1, 7901), + (7901, -1, -1, 7900, 7900, 4, 65, -1, 0, 0, 15, 7900, 7902), + (7902, -1, -1, 7900, 7900, 4, 70, -1, 0, 0, 15, 7901, 10268), + (7903, 7903, 7903, 7903, 7903, 6, 75, 16188, 60, 30, 15, -1, 12976), + (7904, -1, -1, 65, 661, 3, 85, -1, 0, 0, 17, 7538, 7905), + (7905, -1, -1, 65, 661, 3, 86, -1, 0, 0, 17, 7904, 7906), + (7906, -1, -1, 65, 661, 3, 87, -1, 0, 0, 17, 7905, 7907), + (7907, -1, -1, 65, 661, 3, 88, -1, 0, 0, 17, 7906, 7908), + (7908, -1, -1, 65, 661, 3, 89, -1, 0, 0, 17, 7907, 8435), + (7940, -1, -1, 7940, 7940, 6, 60, -1, 0, 0, 15, -1, 7941), + (7941, -1, -1, 7940, 7940, 6, 65, -1, 0, 0, 15, 7940, 7942), + (7942, -1, -1, 7940, 7940, 6, 70, -1, 0, 0, 15, 7941, 10030), + (7943, 7943, 7943, 7943, 7943, 6, 79, 16192, 60, 8640, 15, -1, 7993), + (7944, 7944, 7944, 7944, 7944, 7, 79, 16193, 34, 1800, 15, -1, -1), + (7945, -1, -1, 7945, 7945, 6, 81, -1, 0, 0, 15, -1, 7946), + (7946, -1, -1, 7945, 7945, 6, 82, -1, 0, 0, 15, 7945, 7947), + (7947, -1, -1, 7945, 7945, 6, 83, -1, 0, 0, 15, 7946, 10033), + (7948, -1, -1, 7948, 7948, 6, 75, -1, 0, 0, 15, -1, 7949), + (7949, -1, -1, 7948, 7948, 6, 80, -1, 0, 0, 15, 7948, 7950), + (7950, -1, -1, 7948, 7948, 6, 85, -1, 0, 0, 15, 7949, 10035), + (7951, 7951, 7951, 7951, 7951, 6, 82, 16200, 61, 900, 15, -1, 7952), + (7952, 7951, 7951, 7951, 7951, 6, 83, 16201, 61, 900, 15, 7951, 7953), + (7953, 7951, 7951, 7951, 7951, 6, 84, 16202, 61, 900, 15, 7952, 10038), + (7980, -1, -1, 7980, 7980, 6, 70, -1, 0, 0, 15, -1, 7981), + (7981, -1, -1, 7980, 7980, 6, 73, -1, 0, 0, 15, 7980, 7982), + (7982, -1, -1, 7980, 7980, 6, 76, -1, 0, 0, 15, 7981, -1), + (7983, -1, -1, 7983, 7983, 6, 70, -1, 0, 0, 15, -1, 7984), + (7984, -1, -1, 7983, 7983, 6, 73, -1, 0, 0, 15, 7983, 7985), + (7985, -1, -1, 7983, 7983, 6, 76, -1, 0, 0, 15, 7984, 10110), + (7986, 7986, 7986, 7986, 7986, 9, 75, 16203, 11, 600, 15, -1, 7987), + (7987, 7986, 7986, 7986, 7986, 12, 80, 16204, 11, 600, 15, 7986, 7988), + (7988, 7986, 7986, 7986, 7986, 12, 85, 16205, 11, 600, 15, 7987, 10510), + (7989, -1, -1, 7989, 7989, 6, 75, -1, 0, 0, 15, -1, 7990), + (7990, -1, -1, 7989, 7989, 6, 80, -1, 0, 0, 15, 7989, 7991), + (7991, -1, -1, 7989, 7989, 6, 85, -1, 0, 0, 15, 7990, 7992), + (7992, -1, -1, 7989, 7989, 6, 85, -1, 0, 0, 15, 7991, 13415), + (7993, 7943, 7943, 7943, 7943, 6, 85, 23601, 60, 8640, 17, 7943, -1), + (7994, -1, -1, 462, 462, 2, 81, -1, 0, 0, 17, 464, 7995), + (7995, -1, -1, 462, 462, 2, 85, -1, 0, 0, 17, 7994, -1), + (8000, -1, -1, 8001, 8001, 0, 50, -1, 0, 0, 8, -1, -1), + (8030, 8030, 8030, 8030, 8030, 6, 70, 16206, 60, 900, 15, -1, -1), + (8031, -1, -1, 8031, 8031, 6, 75, -1, 0, 0, 15, -1, 8032), + (8032, -1, -1, 8031, 8031, 6, 77, -1, 0, 0, 15, 8031, 8033), + (8033, -1, -1, 8031, 8031, 6, 79, -1, 0, 0, 15, 8032, 10282), + (8034, 8034, 8034, 8034, 8034, 6, 81, 16207, 59, 600, 15, -1, -1), + (8035, -1, -1, 8035, 8035, 6, 73, -1, 0, 0, 15, -1, 8036), + (8036, -1, -1, 8035, 8035, 6, 75, -1, 0, 0, 15, 8035, 8037), + (8037, -1, -1, 8035, 8035, 6, 77, -1, 0, 0, 15, 8036, 10285), + (8038, 8038, 8038, 8038, 8038, 6, 81, 16210, 56, 12, 15, -1, 17541), + (8039, 8039, 8039, 8039, 8039, 6, 83, 16211, 58, 7, 15, -1, 15462), + (8040, -1, -1, 8040, 8040, 4, 65, -1, 0, 0, 15, -1, 8041), + (8041, -1, -1, 8040, 8040, 4, 70, -1, 0, 0, 15, 8040, 8042), + (8042, -1, -1, 8040, 8040, 4, 75, -1, 0, 0, 15, 8041, 8043), + (8043, -1, -1, 8040, 8040, 4, 78, -1, 0, 0, 15, 8042, 8313), + (8059, -1, -1, 8232, 8232, 4, 78, -1, 0, 0, 15, 8234, 8261), + (8060, 8060, 8060, 8060, 8060, 7, 75, 16238, 41, 1800, 15, -1, 8061), + (8061, 8060, 8060, 8060, 8060, 7, 78, 16239, 41, 1800, 15, 8060, 8062), + (8062, 8060, 8060, 8060, 8060, 7, 81, 16240, 41, 1800, 15, 8061, 10237), + (8063, 8063, 8063, 8063, 8063, 7, 75, 16241, 41, 1800, 15, -1, 8064), + (8064, 8063, 8063, 8063, 8063, 7, 78, 16242, 41, 1800, 15, 8063, 8065), + (8065, 8063, 8063, 8063, 8063, 7, 81, 16243, 41, 1800, 15, 8064, 10240), + (8066, 8066, 8066, 8066, 8066, 7, 75, 16244, 41, 1800, 15, -1, 8067), + (8067, 8066, 8066, 8066, 8066, 7, 78, 16245, 41, 1800, 15, 8066, 8068), + (8068, 8066, 8066, 8066, 8066, 7, 81, 16246, 41, 1800, 15, 8067, 10243), + (8069, -1, -1, 8069, 8069, 5, 71, -1, 0, 0, 15, -1, 8070), + (8070, -1, -1, 8069, 8069, 5, 72, -1, 0, 0, 15, 8069, 8071), + (8071, -1, -1, 8069, 8069, 5, 73, -1, 0, 0, 15, 8070, 15606), + (8072, 8072, 8072, 8072, 8072, 7, 75, 16221, 37, 20, 15, -1, 8073), + (8073, 8072, 8072, 8072, 8072, 7, 75, 16222, 37, 20, 15, 8072, 8074), + (8074, 8072, 8072, 8072, 8072, 7, 75, 16223, 37, 20, 15, 8073, 10246), + (8075, 8075, 8075, 8075, 8075, 7, 81, 16224, 42, 6, 15, -1, -1), + (8076, -1, -1, 8076, 8076, 5, 77, -1, 0, 0, 15, -1, 8077), + (8077, -1, -1, 8076, 8076, 5, 78, -1, 0, 0, 15, 8076, 8078), + (8078, -1, -1, 8076, 8076, 5, 79, -1, 0, 0, 15, 8077, 8079), + (8079, -1, -1, 8076, 8076, 5, 80, -1, 0, 0, 15, 8078, 8080), + (8080, -1, -1, 8076, 8076, 5, 81, -1, 0, 0, 15, 8079, 8081), + (8081, -1, -1, 8076, 8076, 5, 82, -1, 0, 0, 15, 8080, -1), + (8082, -1, -1, 8082, 8082, 3, 65, -1, 0, 0, 15, -1, 8083), + (8083, -1, -1, 8082, 8082, 3, 67, -1, 0, 0, 15, 8082, 8084), + (8084, -1, -1, 8082, 8082, 3, 69, -1, 0, 0, 15, 8083, 10249), + (8190, -1, -1, 8190, 8190, 7, 75, -1, 0, 0, 15, -1, 8191), + (8191, -1, -1, 8190, 8190, 7, 75, -1, 0, 0, 15, 8190, 8192), + (8192, -1, -1, 8190, 8190, 7, 75, -1, 0, 0, 15, 8191, -1), + (8193, -1, -1, 8193, 8193, 7, 75, -1, 0, 0, 15, -1, -1), + (8194, 8194, 8194, 8194, 8194, 7, 75, 16226, 47, 12, 15, -1, -1), + (8195, -1, -1, 8195, 8195, 4, 75, -1, 0, 0, 15, -1, 8196), + (8196, -1, -1, 8195, 8195, 4, 75, -1, 0, 0, 15, 8195, 8197), + (8197, -1, -1, 8195, 8195, 4, 75, -1, 0, 0, 15, 8196, 7704), + (8198, -1, -1, 8198, 8198, 4, 65, -1, 0, 0, 15, -1, 8199), + (8199, -1, -1, 8198, 8198, 4, 65, -1, 0, 0, 15, 8198, 8200), + (8200, -1, -1, 8198, 8198, 4, 65, -1, 0, 0, 15, 8199, -1), + (8201, -1, -1, 8201, 8201, 7, 81, -1, 0, 0, 15, -1, 8202), + (8202, -1, -1, 8201, 8201, 7, 81, -1, 0, 0, 15, 8201, 8203), + (8203, -1, -1, 8201, 8201, 7, 81, -1, 0, 0, 15, 8202, 16475), + (8204, -1, -1, 8204, 8204, 4, 75, -1, 0, 0, 15, -1, 8205), + (8205, -1, -1, 8204, 8204, 4, 75, -1, 0, 0, 15, 8204, 8206), + (8206, -1, -1, 8204, 8204, 4, 75, -1, 0, 0, 15, 8205, 1656), + (8207, -1, -1, 8207, 8207, 4, 75, -1, 0, 0, 15, -1, 8208), + (8208, -1, -1, 8207, 8207, 4, 75, -1, 0, 0, 15, 8207, 8209), + (8209, -1, -1, 8207, 8207, 4, 75, -1, 0, 0, 15, 8208, 1659), + (8210, -1, -1, 8210, 8210, 5, 65, -1, 0, 0, 15, -1, 8211), + (8211, -1, -1, 8210, 8210, 5, 70, -1, 0, 0, 15, 8210, 8212), + (8212, -1, -1, 8210, 8210, 5, 75, -1, 0, 0, 15, 8211, 8213), + (8213, -1, -1, 8210, 8210, 5, 80, -1, 0, 0, 15, 8212, 8214), + (8214, -1, -1, 8210, 8210, 5, 85, -1, 0, 0, 15, 8213, 1651), + (8215, -1, -1, 8215, 8215, 5, 65, -1, 0, 0, 15, -1, 8216), + (8216, -1, -1, 8215, 8215, 5, 70, -1, 0, 0, 15, 8215, 8217), + (8217, -1, -1, 8215, 8215, 5, 75, -1, 0, 0, 15, 8216, 8218), + (8218, -1, -1, 8215, 8215, 5, 80, -1, 0, 0, 15, 8217, 8219), + (8219, -1, -1, 8215, 8215, 5, 85, -1, 0, 0, 15, 8218, 12559), + (8220, 8220, 8220, 8220, 8220, 5, 76, 16227, 39, 15, 15, -1, -1), + (8221, 8221, 8221, 8221, 8221, 9, 81, 16228, 45, 600, 15, -1, -1), + (8222, 8222, 8222, 8222, 8222, 7, 75, 16229, 70, 10, 15, -1, -1), + (8223, -1, -1, 86, 86, 8, 59, -1, 0, 0, 15, 6259, 8262), + (8224, -1, -1, 8224, 8224, 5, 75, -1, 0, 0, 15, -1, 8225), + (8225, -1, -1, 8224, 8224, 5, 80, -1, 0, 0, 15, 8224, 8226), + (8226, -1, -1, 8224, 8224, 5, 85, -1, 0, 0, 15, 8225, 8421), + (8227, 8227, 8227, 8227, 8227, 3, 55, 16233, 71, 10, 15, -1, 12810), + (8228, -1, -1, 8228, 8228, 5, 75, -1, 0, 0, 15, -1, 8229), + (8229, -1, -1, 8228, 8228, 5, 80, -1, 0, 0, 15, 8228, 8230), + (8230, -1, -1, 8228, 8228, 5, 85, -1, 0, 0, 15, 8229, -1), + (8231, 8231, -1, 8231, 8231, 3, 55, 16234, 38, 60, 15, -1, -1), + (8232, -1, -1, 8232, 8232, 4, 65, -1, 0, 0, 15, -1, 8233), + (8233, -1, -1, 8232, 8232, 4, 70, -1, 0, 0, 15, 8232, 8234), + (8234, -1, -1, 8232, 8232, 4, 75, -1, 0, 0, 15, 8233, 8059), + (8235, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, -1, 8236), + (8236, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, 8235, 8237), + (8237, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, 8236, 8238), + (8238, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, 8237, 8239), + (8239, -1, -1, 8235, 8235, 6, 81, -1, 0, 0, 15, 8238, 8304), + (8240, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, -1, 8241), + (8241, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, 8240, 8242), + (8242, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, 8241, 8243), + (8243, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, 8242, 8244), + (8244, -1, -1, 8240, 8240, 6, 81, -1, 0, 0, 15, 8243, 10781), + (8245, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, -1, 8246), + (8246, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, 8245, 8247), + (8247, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, 8246, 8248), + (8248, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, 8247, 8249), + (8249, -1, -1, 8245, 8245, 6, 81, -1, 0, 0, 15, 8248, 8422), + (8250, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, -1, 8251), + (8251, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, 8250, 8252), + (8252, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, 8251, 8253), + (8253, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, 8252, 8254), + (8254, -1, -1, 8250, 8250, 6, 81, -1, 0, 0, 15, 8253, 13046), + (8255, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, -1, 8256), + (8256, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, 8255, 8257), + (8257, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, 8256, 8258), + (8258, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, 8257, 8259), + (8259, -1, -1, 8255, 8255, 6, 81, -1, 0, 0, 15, 8258, 12411), + (8260, 8005, 8005, 8005, 8005, 9, 85, 20185, 45, 600, 16, -1, -1), + (8261, -1, -1, 8232, 8232, 4, 80, -1, 0, 0, 16, 8059, 15772), + (8262, -1, -1, 86, 86, 8, 65, -1, 0, 0, 16, 8223, -1), + (8263, -1, -1, 8263, 8263, 5, 81, -1, 0, 0, 16, -1, 8264), + (8264, -1, -1, 8263, 8263, 5, 82, -1, 0, 0, 16, 8263, 8265), + (8265, -1, -1, 8263, 8263, 5, 83, -1, 0, 0, 16, 8264, 8266), + (8266, -1, -1, 8263, 8263, 5, 84, -1, 0, 0, 16, 8265, 8267), + (8267, -1, -1, 8263, 8263, 5, 85, -1, 0, 0, 16, 8266, 8351), + (8268, -1, -1, 8268, 8268, 5, 81, -1, 0, 0, 16, -1, 8269), + (8269, -1, -1, 8268, 8268, 5, 82, -1, 0, 0, 16, 8268, 8270), + (8270, -1, -1, 8268, 8268, 5, 83, -1, 0, 0, 16, 8269, 8271), + (8271, -1, -1, 8268, 8268, 5, 84, -1, 0, 0, 16, 8270, 8272), + (8272, -1, -1, 8268, 8268, 5, 85, -1, 0, 0, 16, 8271, 8361), + (8273, -1, -1, 8273, 8273, 5, 81, -1, 0, 0, 16, -1, 8274), + (8274, -1, -1, 8273, 8273, 5, 82, -1, 0, 0, 16, 8273, 8275), + (8275, -1, -1, 8273, 8273, 5, 83, -1, 0, 0, 16, 8274, 8276), + (8276, -1, -1, 8273, 8273, 5, 84, -1, 0, 0, 16, 8275, 8277), + (8277, -1, -1, 8273, 8273, 5, 85, -1, 0, 0, 16, 8276, 8371), + (8278, -1, -1, 8278, 8278, 5, 81, -1, 0, 0, 16, -1, 8279), + (8279, -1, -1, 8278, 8278, 5, 82, -1, 0, 0, 16, 8278, 8280), + (8280, -1, -1, 8278, 8278, 5, 83, -1, 0, 0, 16, 8279, 8281), + (8281, -1, -1, 8278, 8278, 5, 84, -1, 0, 0, 16, 8280, 8282), + (8282, -1, -1, 8278, 8278, 5, 85, -1, 0, 0, 16, 8281, 8381), + (8283, -1, -1, 8283, 8283, 5, 81, -1, 0, 0, 16, -1, 8284), + (8284, -1, -1, 8283, 8283, 5, 82, -1, 0, 0, 16, 8283, 8285), + (8285, -1, -1, 8283, 8283, 5, 83, -1, 0, 0, 16, 8284, 8286), + (8286, -1, -1, 8283, 8283, 5, 84, -1, 0, 0, 16, 8285, 8287), + (8287, -1, -1, 8283, 8283, 5, 85, -1, 0, 0, 16, 8286, 8391), + (8288, -1, -1, 8288, 8288, 5, 81, -1, 0, 0, 16, -1, 8289), + (8289, -1, -1, 8288, 8288, 5, 82, -1, 0, 0, 16, 8288, 8290), + (8290, -1, -1, 8288, 8288, 5, 83, -1, 0, 0, 16, 8289, 8291), + (8291, -1, -1, 8288, 8288, 5, 84, -1, 0, 0, 16, 8290, 8292), + (8292, -1, -1, 8288, 8288, 5, 85, -1, 0, 0, 16, 8291, 8401), + (8293, -1, -1, 8293, 8293, 5, 81, -1, 0, 0, 16, -1, 8294), + (8294, -1, -1, 8293, 8293, 5, 82, -1, 0, 0, 16, 8293, 8295), + (8295, -1, -1, 8293, 8293, 5, 83, -1, 0, 0, 16, 8294, 8296), + (8296, -1, -1, 8293, 8293, 5, 84, -1, 0, 0, 16, 8295, 8297), + (8297, -1, -1, 8293, 8293, 5, 85, -1, 0, 0, 16, 8296, 8411), + (8300, 8300, 8300, 8300, 8300, 5, 81, 21778, 8, 900, 16, -1, 8301), + (8301, 8300, 8300, 8300, 8300, 7, 83, 21779, 8, 900, 16, 8300, 8302), + (8302, 8300, 8300, 8300, 8300, 9, 85, 21780, 8, 900, 16, 8301, 15111), + (8303, 8303, 8303, 8303, 8303, 12, 85, 21773, 9, 1800, 16, -1, -1), + (8304, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8239, 8305), + (8305, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8304, 8306), + (8306, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8305, 8307), + (8307, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8306, 8308), + (8308, -1, -1, 8235, 8235, 6, 85, -1, 0, 0, 16, 8307, 13353), + (8309, 260, -1, 260, 260, 5, 81, 21687, 3, 2160, 16, 262, 8310), + (8310, 260, -1, 260, 260, 7, 83, 21688, 3, 2160, 16, 8309, 8311), + (8311, 260, -1, 260, 260, 9, 85, 21689, 3, 2160, 16, 8310, -1), + (8312, 8312, 8312, 8312, 8312, 12, 85, 21690, 2, 900, 16, -1, -1), + (8313, -1, -1, 8040, 8040, 4, 80, -1, 0, 0, 16, 8043, 15773), + (8314, -1, -1, 8314, 8314, 7, 85, -1, 0, 0, 16, -1, 8315), + (8315, -1, -1, 8314, 8314, 9, 85, -1, 0, 0, 16, 8314, 8316), + (8316, -1, -1, 8314, 8314, 12, 85, -1, 0, 0, 16, 8315, 13508), + (8317, -1, -1, 8317, 8317, 5, 85, -1, 0, 0, 16, -1, 8318), + (8318, -1, -1, 8317, 8317, 5, 85, -1, 0, 0, 16, 8317, -1), + (8319, -1, -1, 8319, 8319, 5, 85, -1, 0, 0, 16, -1, 8320), + (8320, -1, -1, 8319, 8319, 5, 85, -1, 0, 0, 16, 8319, 8321), + (8321, -1, -1, 8319, 8319, 5, 85, -1, 0, 0, 16, 8320, -1), + (8322, -1, -1, 8322, 8322, 5, 81, 0, 0, 0, 16, -1, 8323), + (8323, -1, -1, 8322, 8322, 7, 83, 0, 0, 0, 16, 8322, 8324), + (8324, -1, -1, 8322, 8322, 9, 85, 0, 0, 0, 16, 8323, 13199), + (8325, -1, -1, 8325, 8325, 7, 81, 0, 0, 0, 16, -1, 8326), + (8326, -1, -1, 8325, 8325, 9, 81, 0, 0, 0, 16, 8325, 8327), + (8327, -1, -1, 8325, 8325, 11, 81, 0, 0, 0, 16, 8326, 13219), + (8328, -1, -1, 244, 244, 12, 59, -1, 0, 0, 3, 246, -1), + (8329, -1, -1, 622, 622, 3, 71, -1, 0, 0, 16, 624, -1), + (8331, -1, -1, 8331, 8331, 9, 85, 0, 0, 0, 16, -1, -1), + (8332, -1, -1, 8332, 8332, 7, 85, 0, 0, 0, 16, -1, 8333), + (8333, -1, -1, 8332, 8332, 7, 85, 0, 0, 0, 16, 8332, 8334), + (8334, -1, -1, 8332, 8332, 7, 85, 0, 0, 0, 16, 8333, -1), + (8335, -1, -1, 8335, 8335, 5, 81, 0, 0, 0, 16, -1, 8336), + (8336, -1, -1, 8335, 8335, 5, 82, 0, 0, 0, 16, 8335, 8337), + (8337, -1, -1, 8335, 8335, 5, 83, 0, 0, 0, 16, 8336, 8338), + (8338, -1, -1, 8335, 8335, 5, 84, 0, 0, 0, 16, 8337, 8339), + (8339, -1, -1, 8335, 8335, 5, 85, 0, 0, 0, 16, 8338, -1), + (8341, 8341, 8341, 8341, 8341, 12, 85, 21829, 53, 450, 16, -1, -1), + (8342, 8342, 8342, 8342, 8342, 12, 85, 21843, 54, 240, 16, -1, 14729), + (8343, 167, 167, 167, 167, 10, 85, 21837, 14, 900, 16, 7249, 12955), + (8344, -1, -1, 1210, 1213, 12, 85, -1, 0, 0, 16, 7583, 8345), + (8345, -1, -1, 1210, 1213, 12, 85, -1, 0, 0, 16, 8344, 8346), + (8346, -1, -1, 1210, 1213, 12, 85, -1, 0, 0, 16, 8345, 12526), + (8347, -1, -1, 8347, 8347, 7, 81, 0, 0, 0, 16, -1, 8348), + (8348, -1, -1, 8347, 8347, 9, 83, 0, 0, 0, 16, 8347, 8349), + (8349, -1, -1, 8347, 8347, 11, 85, 0, 0, 0, 16, 8348, -1), + (8350, -1, -1, 8350, 8350, 12, 85, 0, 0, 0, 16, -1, -1), + (8351, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8267, 8352), + (8352, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8351, 8353), + (8353, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8352, 8354), + (8354, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8353, 8355), + (8355, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8354, 8356), + (8356, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8355, 8357), + (8357, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8356, 8358), + (8358, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8357, 8359), + (8359, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8358, 8360), + (8360, -1, -1, 8263, 8263, 3, 85, -1, 0, 0, 17, 8359, 13933), + (8361, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8272, 8362), + (8362, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8361, 8363), + (8363, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8362, 8364), + (8364, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8363, 8365), + (8365, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8364, 8366), + (8366, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8365, 8367), + (8367, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8366, 8368), + (8368, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8367, 8369), + (8369, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8368, 8370), + (8370, -1, -1, 8268, 8268, 3, 85, -1, 0, 0, 17, 8369, 13943), + (8371, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8277, 8372), + (8372, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8371, 8373), + (8373, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8372, 8374), + (8374, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8373, 8375), + (8375, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8374, 8376), + (8376, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8375, 8377), + (8377, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8376, 8378), + (8378, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8377, 8379), + (8379, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8378, 8380), + (8380, -1, -1, 8273, 8273, 3, 85, -1, 0, 0, 17, 8379, 13953), + (8381, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8282, 8382), + (8382, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8381, 8383), + (8383, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8382, 8384), + (8384, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8383, 8385), + (8385, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8384, 8386), + (8386, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8385, 8387), + (8387, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8386, 8388), + (8388, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8387, 8389), + (8389, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8388, 8390), + (8390, -1, -1, 8278, 8278, 3, 85, -1, 0, 0, 17, 8389, 13963), + (8391, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8287, 8392), + (8392, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8391, 8393), + (8393, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8392, 8394), + (8394, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8393, 8395), + (8395, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8394, 8396), + (8396, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8395, 8397), + (8397, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8396, 8398), + (8398, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8397, 8399), + (8399, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8398, 8400), + (8400, -1, -1, 8283, 8283, 3, 85, -1, 0, 0, 17, 8399, 13973), + (8401, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8292, 8402), + (8402, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8401, 8403), + (8403, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8402, 8404), + (8404, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8403, 8405), + (8405, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8404, 8406), + (8406, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8405, 8407), + (8407, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8406, 8408), + (8408, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8407, 8409), + (8409, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8408, 8410), + (8410, -1, -1, 8288, 8288, 3, 85, -1, 0, 0, 17, 8409, 13983), + (8411, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8297, 8412), + (8412, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8411, 8413), + (8413, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8412, 8414), + (8414, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8413, 8415), + (8415, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8414, 8416), + (8416, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8415, 8417), + (8417, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8416, 8418), + (8418, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8417, 8419), + (8419, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8418, 8420), + (8420, -1, -1, 8293, 8293, 3, 85, -1, 0, 0, 17, 8419, 13993), + (8421, -1, -1, 8224, 8224, 5, 90, -1, 0, 0, 17, 8226, -1), + (8422, -1, -1, 8245, 8245, 6, 86, -1, 0, 0, 17, 8249, 8423), + (8423, -1, -1, 8245, 8245, 6, 87, -1, 0, 0, 17, 8422, 8424), + (8424, -1, -1, 8245, 8245, 6, 88, -1, 0, 0, 17, 8423, 8425), + (8425, -1, -1, 8245, 8245, 6, 89, -1, 0, 0, 17, 8424, 8426), + (8426, -1, -1, 8245, 8245, 6, 90, -1, 0, 0, 17, 8425, 13338), + (8427, -1, -1, 7100, 7100, 6, 85, -1, 0, 0, 17, 7325, 8428), + (8428, -1, -1, 7100, 7100, 6, 87, -1, 0, 0, 17, 8427, 8429), + (8429, -1, -1, 7100, 7100, 6, 89, -1, 0, 0, 17, 8428, -1), + (8430, -1, -1, 1026, 1026, 10, 91, -1, 0, 0, 18, 7890, 8431), + (8435, -1, -1, 65, 661, 8, 91, -1, 0, 0, 18, 7908, 8436), + (8440, -1, -1, 122, 122, 13, 91, -1, 0, 0, 18, 13089, 8441), + (8445, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 12637, 8446), + (8446, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 8445, 8447), + (8447, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 8446, 16419), + (8448, -1, -1, 6119, 6119, 8, 91, -1, 0, 0, 18, 12496, 8449), + (8463, -1, -1, 125, 125, 10, 91, -1, 0, 0, 18, 13084, 8464), + (8464, -1, -1, 125, 125, 11, 91, -1, 0, 0, 18, 8463, 8465), + (8470, -1, -1, 1006, 1006, 10, 91, -1, 0, 0, 18, 7841, 8471), + (9000, 9000, 9000, 9000, 9000, 0, 1, 16995, 49, 72000, 0, -1, -1), + (9001, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, -1, 9002), + (9002, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9001, 9003), + (9003, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9002, 9004), + (9004, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9003, 9005), + (9005, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9004, 9006), + (9006, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9005, 9007), + (9007, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9006, 9008), + (9008, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9007, 9009), + (9009, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9008, 9010), + (9010, -1, -1, 9101, 9101, 2, 51, -1, 0, 0, 15, 9009, -1), + (9011, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, -1, 9012), + (9012, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9011, 9013), + (9013, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9012, 9014), + (9014, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9013, 9015), + (9015, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9014, 9016), + (9016, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9015, 9017), + (9017, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9016, 9018), + (9018, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9017, 9019), + (9019, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9018, 9020), + (9020, -1, -1, 9111, 9111, 4, 51, -1, 0, 0, 15, 9019, -1), + (9021, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, -1, 9022), + (9022, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9021, 9023), + (9023, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9022, 9024), + (9024, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9023, 9025), + (9025, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9024, 9026), + (9026, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9025, 9027), + (9027, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9026, 9028), + (9028, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9027, 9029), + (9029, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9028, 9030), + (9030, -1, -1, 9121, 9121, 3, 51, -1, 0, 0, 15, 9029, -1), + (9031, 9031, 9031, 9031, 9031, 0, 1, 16601, 65, 72000, 0, -1, -1), + (9032, 9032, 9032, 9032, 9032, 0, 0, 21815, 51, 72000, 0, -1, -1), + (9033, -1, -1, 9033, 9033, 0, 1, -1, 0, 0, 0, -1, -1), + (9100, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, -1, 9101), + (9101, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9100, 9102), + (9102, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9101, 9103), + (9103, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9102, 9104), + (9104, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9103, 9105), + (9105, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9104, 9106), + (9106, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9105, 9107), + (9107, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9106, 9108), + (9108, -1, -1, 9100, 9100, 1, 85, -1, 0, 0, 15, 9107, -1), + (9109, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, -1, 9110), + (9110, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9109, 9111), + (9111, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9110, 9112), + (9112, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9111, 9113), + (9113, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9112, 9114), + (9114, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9113, 9115), + (9115, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9114, 9116), + (9116, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9115, 9117), + (9117, -1, -1, 9109, 9109, 1, 85, -1, 0, 0, 15, 9116, -1), + (9118, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, -1, 9119), + (9119, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9118, 9120), + (9120, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9119, 9121), + (9121, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9120, 9122), + (9122, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9121, 9123), + (9123, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9122, 9124), + (9124, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9123, 9125), + (9125, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9124, 9126), + (9126, -1, -1, 9118, 9118, 1, 85, -1, 0, 0, 15, 9125, -1), + (9127, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, -1, 9128), + (9128, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9127, 9129), + (9129, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9128, 9130), + (9130, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9129, 9131), + (9131, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9130, 9132), + (9132, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9131, 9133), + (9133, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9132, 9134), + (9134, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9133, 9135), + (9135, -1, -1, 9127, 9127, 1, 85, -1, 0, 0, 15, 9134, -1), + (9136, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, -1, 9137), + (9137, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9136, 9138), + (9138, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9137, 9139), + (9139, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9138, 9140), + (9140, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9139, 9141), + (9141, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9140, 9142), + (9142, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9141, 9143), + (9143, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9142, 9144), + (9144, -1, -1, 9136, 9136, 1, 85, -1, 0, 0, 15, 9143, -1), + (9145, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, -1, 9146), + (9146, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9145, 9147), + (9147, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9146, 9148), + (9148, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9147, 9149), + (9149, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9148, 9150), + (9150, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9149, 9151), + (9151, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9150, 9152), + (9152, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9151, 9153), + (9153, -1, -1, 9145, 9145, 1, 85, -1, 0, 0, 15, 9152, -1), + (9154, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, -1, 9155), + (9155, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9154, 9156), + (9156, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9155, 9157), + (9157, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9156, 9158), + (9158, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9157, 9159), + (9159, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9158, 9160), + (9160, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9159, 9161), + (9161, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9160, 9162), + (9162, -1, -1, 9154, 9154, 1, 85, -1, 0, 0, 15, 9161, -1), + (9163, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, -1, 9164), + (9164, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9163, 9165), + (9165, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9164, 9166), + (9166, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9165, 9167), + (9167, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9166, 9168), + (9168, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9167, 9169), + (9169, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9168, 9170), + (9170, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9169, 9171), + (9171, -1, -1, 9163, 9163, 1, 85, -1, 0, 0, 15, 9170, -1), + (9172, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, -1, 9173), + (9173, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9172, 9174), + (9174, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9173, 9175), + (9175, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9174, 9176), + (9176, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9175, 9177), + (9177, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9176, 9178), + (9178, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9177, 9179), + (9179, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9178, 9180), + (9180, -1, -1, 9172, 9172, 1, 85, -1, 0, 0, 15, 9179, -1), + (9181, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, -1, 9182), + (9182, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9181, 9183), + (9183, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9182, 9184), + (9184, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9183, 9185), + (9185, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9184, 9186), + (9186, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9185, 9187), + (9187, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9186, 9188), + (9188, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9187, 9189), + (9189, -1, -1, 9181, 9181, 1, 85, -1, 0, 0, 15, 9188, -1), + (9190, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, -1, 9191), + (9191, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9190, 9192), + (9192, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9191, 9193), + (9193, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9192, 9194), + (9194, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9193, 9195), + (9195, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9194, 9196), + (9196, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9195, 9197), + (9197, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9196, 9198), + (9198, -1, -1, 9190, 9190, 1, 85, -1, 0, 0, 15, 9197, -1), + (9199, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, -1, 9200), + (9200, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9199, 9201), + (9201, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9200, 9202), + (9202, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9201, 9203), + (9203, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9202, 9204), + (9204, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9203, 9205), + (9205, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9204, 9206), + (9206, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9205, 9207), + (9207, -1, -1, 9199, 9199, 1, 85, -1, 0, 0, 15, 9206, -1), + (9208, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, -1, 9209), + (9209, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9208, 9210), + (9210, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9209, 9211), + (9211, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9210, 9212), + (9212, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9211, 9213), + (9213, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9212, 9214), + (9214, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9213, 9215), + (9215, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9214, 9216), + (9216, -1, -1, 9208, 9208, 1, 85, -1, 0, 0, 15, 9215, -1), + (9217, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, -1, 9218), + (9218, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9217, 9219), + (9219, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9218, 9220), + (9220, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9219, 9221), + (9221, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9220, 9222), + (9222, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9221, 9223), + (9223, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9222, 9224), + (9224, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9223, 9225), + (9225, -1, -1, 9217, 9217, 1, 85, -1, 0, 0, 15, 9224, -1), + (9226, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, -1, 9227), + (9227, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9226, 9228), + (9228, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9227, 9229), + (9229, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9228, 9230), + (9230, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9229, 9231), + (9231, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9230, 9232), + (9232, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9231, 9233), + (9233, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9232, 9234), + (9234, -1, -1, 9226, 9226, 1, 85, -1, 0, 0, 15, 9233, -1), + (9235, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, -1, 9236), + (9236, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9235, 9237), + (9237, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9236, 9238), + (9238, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9237, 9239), + (9239, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9238, 9240), + (9240, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9239, 9241), + (9241, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9240, 9242), + (9242, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9241, 9243), + (9243, -1, -1, 9235, 9235, 1, 85, -1, 0, 0, 15, 9242, -1), + (9300, 9300, 9300, 9300, 9300, 5, 85, 16212, 40, 600, 15, -1, 9301), + (9301, 9300, 9300, 9300, 9300, 5, 85, 16213, 40, 600, 15, 9300, 9302), + (9302, 9300, 9300, 9300, 9300, 5, 85, 16214, 40, 600, 15, 9301, -1), + (9303, 9303, 9303, 9303, 9303, 5, 85, 16215, 40, 600, 15, -1, 9304), + (9304, 9303, 9303, 9303, 9303, 5, 85, 16216, 40, 600, 15, 9303, 9305), + (9305, 9303, 9303, 9303, 9303, 5, 85, 16217, 40, 600, 15, 9304, -1), + (9306, 9306, 9306, 9306, 9306, 5, 85, 16218, 40, 600, 15, -1, 9307), + (9307, 9306, 9306, 9306, 9306, 5, 85, 16219, 40, 600, 15, 9306, 9308), + (9308, 9306, 9306, 9306, 9306, 5, 85, 16220, 40, 600, 15, 9307, -1), + (9309, 9309, 9309, 9309, 9309, 5, 85, 16249, 40, 600, 15, -1, 9310), + (9310, 9309, 9309, 9309, 9309, 5, 85, 16250, 40, 600, 15, 9309, 9311), + (9311, 9309, 9309, 9309, 9309, 5, 85, 16251, 40, 600, 15, 9310, -1), + (9312, 9312, 9312, 9312, 9312, 5, 85, 16252, 40, 600, 15, -1, 9313), + (9313, 9312, 9312, 9312, 9312, 5, 85, 16253, 40, 600, 15, 9312, 9314), + (9314, 9312, 9312, 9312, 9312, 5, 85, 16254, 40, 600, 15, 9313, -1), + (9315, 9315, 9315, 9315, 9315, 5, 85, 16255, 40, 600, 15, -1, 9316), + (9316, 9315, 9315, 9315, 9315, 5, 85, 16256, 40, 600, 15, 9315, 9317), + (9317, 9315, 9315, 9315, 9315, 5, 85, 16257, 40, 600, 15, 9316, -1), + (9318, 9318, 9318, 9318, 9318, 5, 85, 16261, 40, 600, 15, -1, 9319), + (9319, 9318, 9318, 9318, 9318, 5, 85, 16262, 40, 600, 15, 9318, 9320), + (9320, 9318, 9318, 9318, 9318, 5, 85, 16263, 40, 600, 15, 9319, -1), + (9321, 9321, 9321, 9321, 9321, 5, 85, 16264, 40, 600, 15, -1, 9322), + (9322, 9321, 9321, 9321, 9321, 5, 85, 16265, 40, 600, 15, 9321, 9323), + (9323, 9321, 9321, 9321, 9321, 5, 85, 16266, 40, 600, 15, 9322, -1), + (9324, 9324, 9324, 9324, 9324, 5, 85, 16267, 40, 600, 15, -1, 9325), + (9325, 9324, 9324, 9324, 9324, 5, 85, 16268, 40, 600, 15, 9324, 9326), + (9326, 9324, 9324, 9324, 9324, 5, 85, 16269, 40, 600, 15, 9325, -1), + (9327, 9327, 9327, 9327, 9327, 5, 85, 16270, 40, 600, 15, -1, 9328), + (9328, 9327, 9327, 9327, 9327, 5, 85, 16271, 40, 600, 15, 9327, 9329), + (9329, 9327, 9327, 9327, 9327, 5, 85, 16272, 40, 600, 15, 9328, -1), + (9330, 9330, 9330, 9330, 9330, 5, 85, 16273, 40, 600, 15, -1, 9331), + (9331, 9330, 9330, 9330, 9330, 5, 85, 16274, 40, 600, 15, 9330, 9332), + (9332, 9330, 9330, 9330, 9330, 5, 85, 16275, 40, 600, 15, 9331, -1), + (9333, 9333, 9333, 9333, 9333, 5, 85, 16276, 40, 600, 15, -1, 9334), + (9334, 9333, 9333, 9333, 9333, 5, 85, 16277, 40, 600, 15, 9333, 9335), + (9335, 9333, 9333, 9333, 9333, 5, 85, 16278, 40, 600, 15, 9334, -1), + (9336, 9336, 9336, 9336, 9336, 5, 85, 16284, 40, 600, 15, -1, 9337), + (9337, 9336, 9336, 9336, 9336, 5, 85, 16285, 40, 600, 15, 9336, 9338), + (9338, 9336, 9336, 9336, 9336, 5, 85, 16286, 40, 600, 15, 9337, -1), + (9339, 9339, 9339, 9339, 9339, 5, 85, 16287, 40, 600, 15, -1, 9340), + (9340, 9339, 9339, 9339, 9339, 5, 85, 16288, 40, 600, 15, 9339, 9341), + (9341, 9339, 9339, 9339, 9339, 5, 85, 16289, 40, 600, 15, 9340, -1), + (9342, 9342, 9342, 9342, 9342, 5, 85, 16290, 40, 600, 15, -1, 9343), + (9343, 9342, 9342, 9342, 9342, 5, 85, 16291, 40, 600, 15, 9342, 9344), + (9344, 9342, 9342, 9342, 9342, 5, 85, 16292, 40, 600, 15, 9343, -1), + (9345, 9345, 9345, 9345, 9345, 5, 85, 16293, 40, 600, 15, -1, 9346), + (9346, 9345, 9345, 9345, 9345, 5, 85, 16294, 40, 600, 15, 9345, 9347), + (9347, 9345, 9345, 9345, 9345, 5, 85, 16295, 40, 600, 15, 9346, -1), + (9348, 9348, 9348, 9348, 9348, 5, 85, 16296, 40, 600, 15, -1, 9349), + (9349, 9348, 9348, 9348, 9348, 5, 85, 16297, 40, 600, 15, 9348, 9350), + (9350, 9348, 9348, 9348, 9348, 5, 85, 16298, 40, 600, 15, 9349, -1), + (9351, 9351, 9351, 9351, 9351, 5, 85, 16299, 40, 600, 15, -1, 9352), + (9352, 9351, 9351, 9351, 9351, 5, 85, 16300, 40, 600, 15, 9351, 9353), + (9353, 9351, 9351, 9351, 9351, 5, 85, 16301, 40, 600, 15, 9352, -1), + (9354, 9354, 9354, 9354, 9354, 5, 85, 16305, 40, 600, 15, -1, 9355), + (9355, 9354, 9354, 9354, 9354, 5, 85, 16306, 40, 600, 15, 9354, 9356), + (9356, 9354, 9354, 9354, 9354, 5, 85, 16307, 40, 600, 15, 9355, 12626), + (9357, 9357, 9357, 9357, 9357, 5, 85, 16308, 40, 600, 15, -1, 9358), + (9358, 9357, 9357, 9357, 9357, 5, 85, 16309, 40, 600, 15, 9357, 9359), + (9359, 9357, 9357, 9357, 9357, 5, 85, 16310, 40, 600, 15, 9358, 12629), + (9360, 9360, 9360, 9360, 9360, 5, 85, 16311, 40, 600, 15, -1, 9361), + (9361, 9360, 9360, 9360, 9360, 5, 85, 16312, 40, 600, 15, 9360, 9362), + (9362, 9360, 9360, 9360, 9360, 5, 85, 16313, 40, 600, 15, 9361, 12632), + (9363, 9363, 9363, 9363, 9363, 5, 85, 16317, 40, 600, 15, -1, 9364), + (9364, 9363, 9363, 9363, 9363, 5, 85, 16318, 40, 600, 15, 9363, 9365), + (9365, 9363, 9363, 9363, 9363, 5, 85, 16319, 40, 600, 15, 9364, -1), + (9366, 9366, 9366, 9366, 9366, 5, 85, 16320, 40, 600, 15, -1, 9367), + (9367, 9366, 9366, 9366, 9366, 5, 85, 16321, 40, 600, 15, 9366, 9368), + (9368, 9366, 9366, 9366, 9366, 5, 85, 16322, 40, 600, 15, 9367, -1), + (9369, 9369, 9369, 9369, 9369, 5, 85, 16323, 40, 600, 15, -1, 9370), + (9370, 9369, 9369, 9369, 9369, 5, 85, 16324, 40, 600, 15, 9369, 9371), + (9371, 9369, 9369, 9369, 9369, 5, 85, 16325, 40, 600, 15, 9370, -1), + (9372, 9372, 9372, 9372, 9372, 5, 85, 16326, 40, 600, 15, -1, 9373), + (9373, 9372, 9372, 9372, 9372, 5, 85, 16327, 40, 600, 15, 9372, 9374), + (9374, 9372, 9372, 9372, 9372, 5, 85, 16328, 40, 600, 15, 9373, -1), + (9375, 9375, 9375, 9375, 9375, 5, 85, 16329, 40, 600, 15, -1, 9376), + (9376, 9375, 9375, 9375, 9375, 5, 85, 16330, 40, 600, 15, 9375, 9377), + (9377, 9375, 9375, 9375, 9375, 5, 85, 16331, 40, 600, 15, 9376, -1), + (9378, 9378, 9378, 9378, 9378, 5, 85, 16332, 40, 600, 15, -1, 9379), + (9379, 9378, 9378, 9378, 9378, 5, 85, 16333, 40, 600, 15, 9378, 9380), + (9380, 9378, 9378, 9378, 9378, 5, 85, 16334, 40, 600, 15, 9379, -1), + (9381, 9381, 9381, 9381, 9381, 5, 85, 16335, 40, 600, 15, -1, 9382), + (9382, 9381, 9381, 9381, 9381, 5, 85, 16336, 40, 600, 15, 9381, 9383), + (9383, 9381, 9381, 9381, 9381, 5, 85, 16337, 40, 600, 15, 9382, -1), + (9384, 9384, 9384, 9384, 9384, 5, 85, 16338, 40, 600, 15, -1, 9385), + (9385, 9384, 9384, 9384, 9384, 5, 85, 16339, 40, 600, 15, 9384, 9386), + (9386, 9384, 9384, 9384, 9384, 5, 85, 16340, 40, 600, 15, 9385, -1), + (9387, 9387, 9387, 9387, 9387, 5, 85, 16341, 40, 600, 15, -1, 9388), + (9388, 9387, 9387, 9387, 9387, 5, 85, 16342, 40, 600, 15, 9387, 9389), + (9389, 9387, 9387, 9387, 9387, 5, 85, 16343, 40, 600, 15, 9388, -1), + (9390, 9390, 9390, 9390, 9390, 5, 85, 16344, 40, 600, 15, -1, 9391), + (9391, 9390, 9390, 9390, 9390, 5, 85, 16345, 40, 600, 15, 9390, 9392), + (9392, 9390, 9390, 9390, 9390, 5, 85, 16346, 40, 600, 15, 9391, -1), + (9393, 9393, 9393, 9393, 9393, 5, 85, 16347, 40, 600, 15, -1, 9394), + (9394, 9393, 9393, 9393, 9393, 5, 85, 16348, 40, 600, 15, 9393, 9395), + (9395, 9393, 9393, 9393, 9393, 5, 85, 16349, 40, 600, 15, 9394, -1), + (9396, 9396, 9396, 9396, 9396, 5, 85, 16350, 40, 600, 15, -1, 9397), + (9397, 9396, 9396, 9396, 9396, 5, 85, 16351, 40, 600, 15, 9396, 9398), + (9398, 9396, 9396, 9396, 9396, 5, 85, 16352, 40, 600, 15, 9397, -1), + (9399, 9399, 9399, 9399, 9399, 5, 85, 16359, 40, 600, 15, -1, 9400), + (9400, 9399, 9399, 9399, 9399, 5, 85, 16360, 40, 600, 15, 9399, 9401), + (9401, 9399, 9399, 9399, 9399, 5, 85, 16361, 40, 600, 15, 9400, -1), + (9402, 9402, 9402, 9402, 9402, 5, 85, 16362, 40, 600, 15, -1, 9403), + (9403, 9402, 9402, 9402, 9402, 5, 85, 16363, 40, 600, 15, 9402, 9404), + (9404, 9402, 9402, 9402, 9402, 5, 85, 16364, 40, 600, 15, 9403, -1), + (9405, 9405, 9405, 9405, 9405, 5, 85, 16365, 40, 600, 15, -1, 9406), + (9406, 9405, 9405, 9405, 9405, 5, 85, 16366, 40, 600, 15, 9405, 9407), + (9407, 9405, 9405, 9405, 9405, 5, 85, 16367, 40, 600, 15, 9406, -1), + (9408, 9408, 9408, 9408, 9408, 5, 85, 16368, 40, 600, 15, -1, 9409), + (9409, 9408, 9408, 9408, 9408, 5, 85, 16369, 40, 600, 15, 9408, 9410), + (9410, 9408, 9408, 9408, 9408, 5, 85, 16370, 40, 600, 15, 9409, -1), + (9411, 9411, 9411, 9411, 9411, 5, 85, 16371, 40, 600, 15, -1, 9412), + (9412, 9411, 9411, 9411, 9411, 5, 85, 16372, 40, 600, 15, 9411, 9413), + (9413, 9411, 9411, 9411, 9411, 5, 85, 16373, 40, 600, 15, 9412, -1), + (9414, 9414, 9414, 9414, 9414, 5, 85, 16374, 40, 600, 15, -1, 9415), + (9415, 9414, 9414, 9414, 9414, 5, 85, 16375, 40, 600, 15, 9414, 9416), + (9416, 9414, 9414, 9414, 9414, 5, 85, 16376, 40, 600, 15, 9415, -1), + (9417, 9417, 9417, 9417, 9417, 5, 85, 16377, 40, 600, 15, -1, 9418), + (9418, 9417, 9417, 9417, 9417, 5, 85, 16378, 40, 600, 15, 9417, 9419), + (9419, 9417, 9417, 9417, 9417, 5, 85, 16379, 40, 600, 15, 9418, -1), + (9420, 9420, 9420, 9420, 9420, 5, 85, 16380, 40, 600, 15, -1, 9421), + (9421, 9420, 9420, 9420, 9420, 5, 85, 16381, 40, 600, 15, 9420, 9422), + (9422, 9420, 9420, 9420, 9420, 5, 85, 16382, 40, 600, 15, 9421, -1), + (9423, 9423, 9423, 9423, 9423, 5, 85, 16386, 40, 600, 15, -1, 9424), + (9424, 9423, 9423, 9423, 9423, 5, 85, 16387, 40, 600, 15, 9423, 9425), + (9425, 9423, 9423, 9423, 9423, 5, 85, 16388, 40, 600, 15, 9424, -1), + (9426, 9426, 9426, 9426, 9426, 5, 85, 16389, 40, 600, 15, -1, 9427), + (9427, 9426, 9426, 9426, 9426, 5, 85, 16390, 40, 600, 15, 9426, 9428), + (9428, 9426, 9426, 9426, 9426, 5, 85, 16391, 40, 600, 15, 9427, -1), + (9429, 9429, 9429, 9429, 9429, 5, 85, 16392, 40, 600, 15, -1, 9430), + (9430, 9429, 9429, 9429, 9429, 5, 85, 16393, 40, 600, 15, 9429, 9431), + (9431, 9429, 9429, 9429, 9429, 5, 85, 16394, 40, 600, 15, 9430, -1), + (9432, 9432, 9432, 9432, 9432, 5, 85, 16395, 40, 600, 15, -1, 9433), + (9433, 9432, 9432, 9432, 9432, 5, 85, 16396, 40, 600, 15, 9432, 9434), + (9434, 9432, 9432, 9432, 9432, 5, 85, 16397, 40, 600, 15, 9433, -1), + (9435, 9435, 9435, 9435, 9435, 5, 85, 16398, 40, 600, 15, -1, 9436), + (9436, 9435, 9435, 9435, 9435, 5, 85, 16399, 40, 600, 15, 9435, 9437), + (9437, 9435, 9435, 9435, 9435, 5, 85, 16400, 40, 600, 15, 9436, -1), + (9438, 9438, 9438, 9438, 9438, 5, 85, 16401, 40, 600, 15, -1, 9439), + (9439, 9438, 9438, 9438, 9438, 5, 85, 16402, 40, 600, 15, 9438, 9440), + (9440, 9438, 9438, 9438, 9438, 5, 85, 16403, 40, 600, 15, 9439, -1), + (9441, 9441, 9441, 9441, 9441, 5, 85, 16404, 40, 600, 15, -1, 9442), + (9442, 9441, 9441, 9441, 9441, 5, 85, 16405, 40, 600, 15, 9441, 9443), + (9443, 9441, 9441, 9441, 9441, 5, 85, 16406, 40, 600, 15, 9442, -1), + (9500, 9500, 9500, 9500, 9500, 3, 76, 16247, 47, 60, 15, -1, -1), + (9501, 9501, 9501, 9501, 9501, 9, 85, 16247, 47, 600, 15, -1, -1), + (9502, 9502, 9502, 9502, 9502, 7, 81, 16248, 48, 3600, 15, -1, -1), + (9503, -1, -1, 9503, 9503, 7, 83, -1, 0, 0, 15, -1, 9504), + (9504, -1, -1, 9503, 9503, 7, 84, -1, 0, 0, 15, 9503, 9505), + (9505, -1, -1, 9503, 9503, 7, 85, -1, 0, 0, 15, 9504, 10087), + (9506, -1, -1, 9506, 9506, 7, 81, -1, 0, 0, 15, -1, 9507), + (9507, -1, -1, 9506, 9506, 7, 83, -1, 0, 0, 15, 9506, 9508), + (9508, -1, -1, 9506, 9506, 7, 85, -1, 0, 0, 15, 9507, 13630), + (9509, -1, -1, 9509, 9509, 7, 81, -1, 0, 0, 15, -1, 9510), + (9510, -1, -1, 9509, 9509, 7, 82, -1, 0, 0, 15, 9509, 9511), + (9511, -1, -1, 9509, 9509, 7, 83, -1, 0, 0, 15, 9510, 9515), + (9512, -1, -1, 9512, 9512, 7, 81, -1, 0, 0, 15, -1, 9513), + (9513, -1, -1, 9512, 9512, 7, 82, -1, 0, 0, 15, 9512, 9514), + (9514, -1, -1, 9512, 9512, 7, 83, -1, 0, 0, 15, 9513, 7819), + (9515, -1, -1, 9509, 9509, 7, 86, -1, 0, 0, 17, 9511, 16361), + (10003, 6610, 6610, 6610, 6610, 5, 60, 16494, 41, 30, 16, 6610, 10573), + (10004, -1, -1, 6614, 6614, 6, 70, -1, 0, 0, 16, 6616, 10005), + (10005, -1, -1, 6614, 6614, 9, 70, -1, 0, 0, 16, 10004, 10575), + (10006, 54006, 54006, 54006, 54006, 7, 85, 16495, 18, 180, 16, 7111, 13425), + (10007, -1, -1, 6564, 6564, 10, 85, -1, 0, 0, 16, 7114, 10008), + (10008, -1, -1, 6564, 6564, 10, 85, -1, 0, 0, 16, 10007, 10009), + (10009, -1, -1, 6564, 6564, 10, 85, -1, 0, 0, 16, 10008, 10568), + (10010, 6565, 6565, 6565, 6565, 7, 85, 16496, 17, 45, 16, 7115, 10517), + (10011, 912, 912, 912, 912, 9, 80, 16497, 4, 3600, 16, 7121, 10012), + (10012, 912, 912, 912, 912, 9, 80, 16498, 4, 3600, 16, 10011, 10013), + (10013, 912, 912, 912, 912, 9, 80, 16499, 4, 3600, 16, 10012, 10585), + (10014, 1383, 1383, 1383, 1383, 12, 85, 21766, 6, 300, 16, 7299, 6487), + (10015, 1195, 1195, 1195, 1195, 9, 85, 16504, 13, 2160, 16, 7300, 13259), + (10016, 131, 131, 131, 131, 10, 85, 16505, 4, 900, 16, 7303, 10017), + (10017, 131, 131, 131, 131, 10, 85, 16506, 4, 900, 16, 10016, 10018), + (10018, 131, 131, 131, 131, 10, 85, 16507, 4, 900, 16, 10017, 7770), + (10019, 1192, 1192, 1192, 1192, 10, 85, 20177, 12, 1320, 16, 7306, 10020), + (10020, 1192, 1192, 1192, 1192, 10, 85, 21652, 12, 1320, 16, 10019, 10021), + (10021, 1192, 1192, 1192, 1192, 10, 85, 21704, 12, 1320, 16, 10020, 13363), + (10022, 746, 746, 746, 746, 12, 85, 16511, 10, 2160, 16, 7309, 10023), + (10023, 746, 746, 746, 746, 12, 85, 16512, 10, 2160, 16, 10022, 10024), + (10024, 746, 746, 746, 746, 12, 85, 16513, 10, 2160, 16, 10023, 15321), + (10025, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 7322, 10026), + (10026, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 10025, 10027), + (10027, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 10026, 10028), + (10028, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 10027, 10029), + (10029, -1, -1, 6601, 6601, 6, 85, -1, 0, 0, 16, 10028, 10437), + (10030, -1, -1, 7940, 7940, 5, 75, -1, 0, 0, 16, 7942, 10031), + (10031, -1, -1, 7940, 7940, 7, 75, -1, 0, 0, 16, 10030, 10032), + (10032, -1, -1, 7940, 7940, 9, 75, -1, 0, 0, 16, 10031, 6484), + (10033, -1, -1, 7945, 7945, 6, 85, -1, 0, 0, 16, 7947, 10034), + (10034, -1, -1, 7945, 7945, 6, 85, -1, 0, 0, 16, 10033, 10347), + (10035, -1, -1, 7948, 7948, 6, 85, -1, 0, 0, 16, 7950, 10036), + (10036, -1, -1, 7948, 7948, 6, 85, -1, 0, 0, 16, 10035, 10037), + (10037, -1, -1, 7948, 7948, 6, 85, -1, 0, 0, 16, 10036, 15328), + (10038, 7951, 7951, 7951, 7951, 6, 85, 16514, 61, 900, 16, 7953, 10039), + (10039, 7951, 7951, 7951, 7951, 6, 85, 16515, 61, 900, 16, 10038, 10040), + (10040, 7951, 7951, 7951, 7951, 6, 85, 16516, 61, 900, 16, 10039, 7773), + (10041, -1, -1, 6636, 6636, 9, 75, -1, 0, 0, 16, 6638, 10042), + (10042, -1, -1, 6636, 6636, 10, 75, -1, 0, 0, 16, 10041, 10043), + (10043, -1, -1, 6636, 6636, 11, 75, -1, 0, 0, 16, 10042, 12529), + (10044, -1, -1, 6791, 6791, 6, 85, -1, 0, 0, 16, 6793, 10045), + (10045, -1, -1, 6791, 6791, 6, 85, -1, 0, 0, 16, 10044, 10046), + (10046, -1, -1, 6791, 6791, 6, 85, -1, 0, 0, 16, 10045, 10676), + (10047, 534, 534, 534, 534, 12, 85, 16561, 4, 2160, 16, 7331, 10048), + (10048, 534, 534, 534, 534, 12, 85, 16562, 4, 2160, 16, 10047, 10049), + (10049, 534, 534, 534, 534, 12, 85, 16563, 4, 2160, 16, 10048, 10708), + (10050, -1, -1, 6395, 6395, 7, 85, -1, 0, 0, 16, 7338, 10051), + (10051, -1, -1, 6395, 6395, 7, 85, -1, 0, 0, 16, 10050, 10052), + (10052, -1, -1, 6395, 6395, 7, 85, -1, 0, 0, 16, 10051, 10705), + (10053, 6754, 6754, 6754, 6754, 9, 75, 16570, 41, 1200, 16, 6754, 14111), + (10054, 6758, 6758, 6758, 6758, 10, 85, 16571, 43, 900, 16, 6760, 10055), + (10055, 6758, 6758, 6758, 6758, 11, 85, 16572, 43, 900, 16, 10054, 10056), + (10056, 6758, 6758, 6758, 6758, 12, 85, 16573, 43, 900, 16, 10055, 13546), + (10057, 6764, 6764, 6764, 6764, 9, 80, 16574, 52, 600, 16, 6764, 16716), + (10058, -1, -1, 6765, 6765, 9, 85, -1, 0, 0, 16, 6767, 10059), + (10059, -1, -1, 6765, 6765, 9, 85, -1, 0, 0, 16, 10058, 10060), + (10060, -1, -1, 6765, 6765, 9, 85, -1, 0, 0, 16, 10059, 10766), + (10061, 5007, 5007, 5007, 5007, 9, 85, 16575, 8, 2160, 16, 7343, 10062), + (10062, 5007, 5007, 5007, 5007, 9, 85, 16576, 8, 2160, 16, 10061, 10063), + (10063, 5007, 5007, 5007, 5007, 9, 85, 16577, 8, 2160, 16, 10062, 13119), + (10064, -1, -1, 1608, 1608, 6, 85, -1, 0, 0, 16, 7383, 10065), + (10065, -1, -1, 1608, 1608, 7, 85, -1, 0, 0, 16, 10064, 10066), + (10066, -1, -1, 1608, 1608, 8, 85, -1, 0, 0, 16, 10065, 10067), + (10067, -1, -1, 1608, 1608, 9, 85, -1, 0, 0, 16, 10066, 10068), + (10068, -1, -1, 1608, 1608, 10, 85, -1, 0, 0, 16, 10067, 10069), + (10069, -1, -1, 1608, 1608, 11, 85, -1, 0, 0, 16, 10068, 16730), + (10070, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 6634, 10071), + (10071, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 10070, 10072), + (10072, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 10071, 10073), + (10073, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 10072, 10074), + (10074, -1, -1, 6630, 6630, 6, 75, -1, 0, 0, 16, 10073, 13621), + (10075, -1, -1, 6641, 6641, 9, 85, -1, 0, 0, 16, 6643, 10076), + (10076, -1, -1, 6641, 6641, 9, 85, -1, 0, 0, 16, 10075, 10077), + (10077, -1, -1, 6641, 6641, 9, 85, -1, 0, 0, 16, 10076, 16192), + (10078, 6508, 6508, 6508, 6508, 7, 85, 16578, 38, 600, 16, 7389, 10079), + (10079, 6508, 6508, 6508, 6508, 7, 85, 16579, 38, 600, 16, 10078, 10080), + (10080, 6508, 6508, 6508, 6508, 7, 85, 16580, 38, 600, 16, 10079, 15775), + (10081, -1, -1, 1313, 1313, 12, 85, -1, 0, 0, 16, 7398, 10082), + (10082, -1, -1, 1313, 1313, 12, 85, -1, 0, 0, 16, 10081, 10083), + (10083, -1, -1, 1313, 1313, 12, 85, -1, 0, 0, 16, 10082, 12579), + (10084, -1, -1, 6375, 6375, 6, 85, -1, 0, 0, 16, 7663, 10085), + (10085, -1, -1, 6375, 6375, 6, 85, -1, 0, 0, 16, 10084, 10086), + (10086, -1, -1, 6375, 6375, 6, 85, -1, 0, 0, 16, 10085, 5347), + (10087, -1, -1, 9503, 9503, 7, 85, -1, 0, 0, 16, 9505, 10088), + (10088, -1, -1, 9503, 9503, 7, 85, -1, 0, 0, 16, 10087, 10089), + (10089, -1, -1, 9503, 9503, 7, 85, -1, 0, 0, 16, 10088, 12792), + (10090, 1498, 1498, 1498, 1498, 12, 85, 16590, 12, 1320, 16, 7410, 10091), + (10091, 1498, 1498, 1498, 1498, 12, 85, 16591, 12, 1320, 16, 10090, 10092), + (10092, 1498, 1498, 1498, 1498, 12, 85, 16602, 12, 1320, 16, 10091, 13401), + (10093, 1495, 1495, 1495, 1495, 9, 86, 16603, 30, 900, 17, 7416, 10094), + (10096, 548, 548, 548, 548, 10, 85, 16606, 5, 900, 16, 7419, 10097), + (10097, 548, 548, 548, 548, 10, 85, 16607, 5, 900, 16, 10096, 10098), + (10098, 548, 548, 548, 548, 10, 85, 16608, 5, 900, 16, 10097, 13158), + (10099, 6561, 6561, 6561, 6561, 7, 85, 16609, 32, 30, 16, 7424, 10100), + (10100, 6561, 6561, 6561, 6561, 7, 85, 16610, 32, 30, 16, 10099, 10101), + (10101, 6561, 6561, 6561, 6561, 7, 85, 16611, 32, 30, 16, 10100, 10418), + (10102, 510, 510, 510, 510, 3, 75, 16587, 37, 240, 16, 7427, 10103), + (10103, 510, 510, 510, 510, 3, 75, 16588, 37, 240, 16, 10102, 10104), + (10104, 510, 510, 510, 510, 3, 75, 16589, 37, 240, 16, 10103, 10824), + (10105, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 7668, 10106), + (10106, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 10105, 10107), + (10107, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 10106, 10108), + (10108, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 10107, 10109), + (10109, -1, -1, 7664, 7664, 2, 82, -1, 0, 0, 16, 10108, 17350), + (10110, -1, -1, 7983, 7983, 6, 81, -1, 0, 0, 16, 7985, 10111), + (10111, -1, -1, 7983, 7983, 6, 81, -1, 0, 0, 16, 10110, 10112), + (10112, -1, -1, 7983, 7983, 6, 81, -1, 0, 0, 16, 10111, -1), + (10113, 1352, 1352, 1352, 1352, 6, 85, 16618, 3, 60, 16, 7156, 10114), + (10114, 1352, 1352, 1352, 1352, 6, 85, 16619, 3, 60, 16, 10113, 10115), + (10115, 1352, 1352, 1352, 1352, 6, 85, 16620, 3, 60, 16, 10114, 13807), + (10116, 1358, 1358, 1358, 1358, 6, 85, 16615, 3, 60, 16, 7159, 10117), + (10117, 1358, 1358, 1358, 1358, 6, 85, 16616, 3, 60, 16, 10116, 10118), + (10118, 1358, 1358, 1358, 1358, 6, 85, 16617, 3, 60, 16, 10117, 13810), + (10119, 1355, 1355, 1355, 1355, 6, 85, 16612, 3, 60, 16, 7174, 10120), + (10120, 1355, 1355, 1355, 1355, 6, 85, 16613, 3, 60, 16, 10119, 10121), + (10121, 1355, 1355, 1355, 1355, 6, 85, 16614, 3, 60, 16, 10120, 12700), + (10122, -1, -1, 4801, 4801, 6, 85, -1, 0, 0, 16, 7162, 10123), + (10123, -1, -1, 4801, 4801, 6, 85, -1, 0, 0, 16, 10122, 12674), + (10124, -1, -1, 611, 611, 2, 75, -1, 0, 0, 16, 7177, 10125), + (10125, -1, -1, 611, 611, 2, 75, -1, 0, 0, 16, 10124, 10126), + (10126, -1, -1, 611, 611, 2, 75, -1, 0, 0, 16, 10125, 12703), + (10127, 7872, 7872, 7872, 7872, 6, 85, 16621, 41, 600, 16, 7874, 10128), + (10128, 7872, 7872, 7872, 7872, 6, 85, 16622, 41, 600, 16, 10127, 10129), + (10129, 7872, 7872, 7872, 7872, 6, 85, 16623, 41, 600, 16, 10128, 12682), + (10130, -1, -1, 6870, 6870, 6, 80, -1, 0, 0, 16, 6872, 10131), + (10131, -1, -1, 6870, 6870, 6, 80, -1, 0, 0, 16, 10130, 10132), + (10132, -1, -1, 6870, 6870, 6, 80, -1, 0, 0, 16, 10131, -1), + (10133, -1, -1, 255, 255, 9, 80, -1, 0, 0, 16, 6875, 10134), + (10134, -1, -1, 255, 255, 9, 80, -1, 0, 0, 16, 10133, 10135), + (10135, -1, -1, 255, 255, 9, 80, -1, 0, 0, 16, 10134, 13196), + (10136, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 16, 6878, 10137), + (10137, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 16, 10136, 10138), + (10138, -1, -1, 6375, 6375, 6, 83, -1, 0, 0, 16, 10137, 12734), + (10139, 6533, 6533, 6533, 6533, 10, 85, 16631, 15, 600, 16, 7428, 12740), + (10140, 1116, 1116, 1116, 1116, 12, 85, 16647, 4, 2160, 16, 7432, 10141), + (10141, 1116, 1116, 1116, 1116, 12, 85, 16648, 4, 2160, 16, 10140, 10142), + (10142, 1116, 1116, 1116, 1116, 12, 85, 16649, 4, 2160, 16, 10141, 12743), + (10143, 5298, 5298, 5298, 5298, 12, 85, 16632, 32, 1800, 16, 7440, 10144), + (10144, 5298, 5298, 5298, 5298, 12, 85, 16633, 32, 1800, 16, 10143, 10145), + (10145, 5298, 5298, 5298, 5298, 12, 85, 16634, 32, 1800, 16, 10144, 12746), + (10146, 1598, -1, 1598, 1598, 12, 85, 16638, 6, 900, 16, 7443, 10147), + (10147, 1598, -1, 1598, 1598, 12, 85, 16639, 6, 900, 16, 10146, 10148), + (10148, 1598, -1, 1598, 1598, 12, 85, 16640, 6, 900, 16, 10147, 13193), + (10149, 5020, 5020, 5020, 5020, 9, 85, 16630, 9, 300, 16, 7444, 13490), + (10150, 1110, 1110, 1110, 1110, 6, 85, 16641, 3, 2160, 16, 7447, 10151), + (10151, 1110, 1110, 1110, 1110, 6, 85, 16642, 3, 2160, 16, 10150, 10152), + (10152, 1110, 1110, 1110, 1110, 6, 85, 16643, 3, 2160, 16, 10151, 13190), + (10153, -1, -1, 6337, 6337, 6, 85, -1, 0, 0, 16, 7450, 10154), + (10154, -1, -1, 6337, 6337, 6, 85, -1, 0, 0, 16, 10153, 10155), + (10155, -1, -1, 6337, 6337, 6, 85, -1, 0, 0, 16, 10154, 16297), + (10156, 5017, 5017, 5017, 5017, 9, 85, 16627, 8, 600, 16, 7456, 10157), + (10157, 5017, 5017, 5017, 5017, 9, 85, 16628, 8, 600, 16, 10156, 10158), + (10158, 5017, 5017, 5017, 5017, 9, 85, 16629, 8, 600, 16, 10157, 14189), + (10159, 1569, 1569, 1569, 1569, 7, 85, 16624, 5, 1800, 16, 7459, 10160), + (10160, 1569, 1569, 1569, 1569, 7, 85, 16625, 5, 1800, 16, 10159, 10161), + (10161, 1569, 1569, 1569, 1569, 7, 85, 16626, 5, 1800, 16, 10160, 17276), + (10162, 6663, 6663, 6663, 6663, 7, 82, 16653, 59, 600, 16, 6665, 10163), + (10163, 6663, 6663, 6663, 6663, 7, 82, 16654, 59, 600, 16, 10162, 10164), + (10164, 6663, 6663, 6663, 6663, 7, 82, 16655, 59, 600, 16, 10163, -1), + (10165, -1, -1, 1543, 1543, 12, 85, -1, 0, 0, 16, 7136, 10166), + (10166, -1, -1, 1543, 1543, 12, 85, -1, 0, 0, 16, 10165, 10167), + (10167, -1, -1, 1543, 1543, 12, 85, -1, 0, 0, 16, 10166, 13213), + (10168, 6328, 6328, 6328, 6328, 7, 85, 16650, 10, 600, 16, 7145, 10169), + (10169, 6328, 6328, 6328, 6328, 7, 85, 16651, 10, 600, 16, 10168, 10170), + (10170, 6328, 6328, 6328, 6328, 7, 85, 16652, 10, 600, 16, 10169, 13770), + (10171, -1, -1, 878, 878, 7, 85, -1, 0, 0, 16, 7147, 10172), + (10172, -1, -1, 878, 878, 7, 85, -1, 0, 0, 16, 10171, -1), + (10173, -1, -1, 846, 846, 12, 85, -1, 0, 0, 16, 7153, 10174), + (10174, -1, -1, 846, 846, 12, 85, -1, 0, 0, 16, 10173, 10175), + (10175, -1, -1, 846, 846, 12, 85, -1, 0, 0, 16, 10174, 13795), + (10176, -1, -1, 6703, 6703, 3, 70, -1, 0, 0, 16, 6705, 10177), + (10177, -1, -1, 6703, 6703, 3, 70, -1, 0, 0, 16, 10176, 10178), + (10178, -1, -1, 6703, 6703, 3, 70, -1, 0, 0, 16, 10177, 13005), + (10179, 6706, 6706, 6706, 6706, 7, 85, 16675, 44, 600, 16, 6708, 10180), + (10180, 6706, 6706, 6706, 6706, 7, 85, 16676, 44, 600, 16, 10179, 10181), + (10181, 6706, 6706, 6706, 6706, 7, 85, 16677, 44, 600, 16, 10180, 5353), + (10182, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 6716, 10183), + (10183, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 10182, 10184), + (10184, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 10183, 10185), + (10185, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 10184, 10186), + (10186, -1, -1, 6712, 6712, 7, 85, -1, 0, 0, 16, 10185, -1), + (10187, 1327, 1327, 1327, 1327, 12, 85, 16665, 10, 900, 16, 7462, 10188), + (10188, 1327, 1327, 1327, 1327, 12, 85, 16666, 10, 900, 16, 10187, 10189), + (10189, 1327, 1327, 1327, 1327, 12, 85, 16667, 10, 900, 16, 10188, 5330), + (10190, 1520, 1520, 1520, 1520, 9, 80, 16672, 11, 900, 16, 7465, 10191), + (10191, 1520, 1520, 1520, 1520, 9, 80, 16673, 11, 900, 16, 10190, 10192), + (10192, 1520, 1520, 1520, 1520, 9, 80, 16674, 11, 900, 16, 10191, 12997), + (10193, 153, 153, 153, 153, 12, 85, 16668, 3, 2160, 16, 7468, 11081), + (10194, 528, 528, 528, 528, 12, 85, 16669, 5, 720, 16, 7471, 10195), + (10195, 528, 528, 528, 528, 12, 85, 16670, 5, 720, 16, 10194, 10196), + (10196, 528, 528, 528, 528, 12, 85, 16671, 5, 720, 16, 10195, 13161), + (10197, 5251, 5251, 5251, 5251, 12, 85, 16662, 13, 900, 16, 7474, 10198), + (10198, 5251, 5251, 5251, 5251, 12, 85, 16663, 13, 900, 16, 10197, 10199), + (10199, 5251, 5251, 5251, 5251, 12, 85, 16664, 13, 900, 16, 10198, 5363), + (10200, 6815, 6815, 6815, 6815, 8, 85, 16691, 60, 600, 16, 6817, 10201), + (10201, 6815, 6815, 6815, 6815, 8, 85, 16692, 60, 600, 16, 10200, 10202), + (10202, 6815, 6815, 6815, 6815, 8, 85, 16693, 60, 600, 16, 10201, 12786), + (10203, -1, -1, 6819, 6819, 6, 77, -1, 0, 0, 16, 6821, 10204), + (10204, -1, -1, 6819, 6819, 6, 77, -1, 0, 0, 16, 10203, 10205), + (10205, -1, -1, 6819, 6819, 6, 77, -1, 0, 0, 16, 10204, -1), + (10206, -1, -1, 6823, 6823, 4, 75, -1, 0, 0, 16, 6827, 10207), + (10207, -1, -1, 6823, 6823, 4, 77, -1, 0, 0, 16, 10206, -1), + (10208, 6828, 6828, 6828, 6828, 12, 85, 16686, 43, 60, 16, 6828, 17534), + (10209, 1274, 1274, 1274, 1274, 12, 85, 16683, 9, 540, 16, 7201, 10210), + (10210, 1274, 1274, 1274, 1274, 12, 85, 16684, 9, 540, 16, 10209, 10211), + (10211, 1274, 1274, 1274, 1274, 12, 85, 16685, 9, 540, 16, 10210, 12760), + (10212, 1510, -1, 1510, 1510, 12, 80, 16690, 13, 2160, 16, 7202, -1), + (10213, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 7208, 10214), + (10214, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 10213, 10215), + (10215, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 10214, 10216), + (10216, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 10215, 10217), + (10217, -1, -1, 5264, 5264, 12, 85, -1, 0, 0, 16, 10216, 12798), + (10218, 4927, 4927, 4927, 4927, 9, 85, 16682, 14, 600, 16, 7209, -1), + (10219, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 7214, 10220), + (10220, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 10219, 10221), + (10221, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 10220, 10222), + (10222, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 10221, 10223), + (10223, -1, -1, 839, 839, 6, 80, -1, 0, 0, 16, 10222, -1), + (10224, 967, 967, 967, 967, 6, 85, 16687, 10, 1800, 16, 7219, 10225), + (10225, 967, 967, 967, 967, 6, 85, 16688, 10, 1800, 16, 10224, 10226), + (10226, 967, 967, 967, 967, 6, 85, 16689, 10, 1800, 16, 10225, 12789), + (10227, -1, -1, 5295, 5295, 6, 85, -1, 0, 0, 16, 7222, 10228), + (10228, -1, -1, 5295, 5295, 6, 85, -1, 0, 0, 16, 10227, 10229), + (10229, -1, -1, 5295, 5295, 6, 85, -1, 0, 0, 16, 10228, 13226), + (10230, 619, 619, 619, 619, 6, 83, 16704, 6, 900, 16, 7228, 10231), + (10231, 619, 619, 619, 619, 6, 83, 16705, 6, 900, 16, 10230, 10232), + (10232, 619, 619, 619, 619, 6, 83, 16706, 6, 900, 16, 10231, -1), + (10233, 516, 516, 516, 516, 6, 82, 16707, 5, 480, 16, 7237, 12879), + (10234, 1334, 1334, 1334, 1334, 12, 85, 16701, 11, 4320, 16, 7241, 10235), + (10235, 1334, 1334, 1334, 1334, 12, 85, 16702, 11, 4320, 16, 10234, 10236), + (10236, 1334, 1334, 1334, 1334, 12, 85, 16703, 11, 4320, 16, 10235, 12868), + (10237, 8060, 8060, 8060, 8060, 7, 85, 16711, 41, 1800, 16, 8062, 10238), + (10238, 8060, 8060, 8060, 8060, 7, 85, 16712, 41, 1800, 16, 10237, 10239), + (10239, 8060, 8060, 8060, 8060, 7, 85, 16713, 41, 1800, 16, 10238, 13650), + (10240, 8063, 8063, 8063, 8063, 7, 85, 16714, 41, 1800, 16, 8065, 10241), + (10241, 8063, 8063, 8063, 8063, 7, 85, 16715, 41, 1800, 16, 10240, 10242), + (10242, 8063, 8063, 8063, 8063, 7, 85, 16716, 41, 1800, 16, 10241, 13653), + (10243, 8066, 8066, 8066, 8066, 7, 85, 16717, 41, 1800, 16, 8068, 10244), + (10244, 8066, 8066, 8066, 8066, 7, 85, 16718, 41, 1800, 16, 10243, 10245), + (10245, 8066, 8066, 8066, 8066, 7, 85, 16719, 41, 1800, 16, 10244, 13656), + (10246, 8072, 8072, 8072, 8072, 7, 80, 16708, 37, 20, 16, 8074, 10247), + (10247, 8072, 8072, 8072, 8072, 7, 80, 16709, 37, 20, 16, 10246, 10248), + (10248, 8072, 8072, 8072, 8072, 7, 80, 16710, 37, 20, 16, 10247, 12857), + (10249, -1, -1, 8082, 8082, 3, 74, -1, 0, 0, 16, 8084, 10250), + (10250, -1, -1, 8082, 8082, 3, 74, -1, 0, 0, 16, 10249, 10251), + (10251, -1, -1, 8082, 8082, 3, 74, -1, 0, 0, 16, 10250, -1), + (10252, 520, 520, 520, 520, 12, 85, 16723, 6, 540, 16, 7252, 10253), + (10253, 520, 520, 520, 520, 12, 85, 16724, 6, 540, 16, 10252, 10254), + (10254, 520, 520, 520, 520, 12, 85, 16725, 6, 540, 16, 10253, 12985), + (10255, 4903, 4903, 4903, 4903, 9, 81, 16726, 9, 1320, 16, 7253, 12956), + (10256, 4906, 4906, 4906, 4906, 9, 81, 16727, 9, 1320, 16, 7254, 12959), + (10257, 4909, 4909, 4909, 4909, 9, 81, 16728, 16, 1320, 16, 7255, 12957), + (10258, 4912, 4912, 4912, 4912, 9, 81, 16729, 16, 1320, 16, 7256, 12958), + (10259, 616, 616, 616, 616, 10, 85, 16733, 7, 900, 16, 7259, 10260), + (10260, 616, 616, 616, 616, 10, 85, 16734, 7, 900, 16, 10259, 10261), + (10261, 616, 616, 616, 616, 10, 85, 16735, 7, 900, 16, 10260, 14730), + (10262, -1, -1, 1577, 1577, 12, 85, -1, 0, 0, 16, 7265, 10263), + (10263, -1, -1, 1577, 1577, 12, 85, -1, 0, 0, 16, 10262, 10264), + (10264, -1, -1, 1577, 1577, 12, 85, -1, 0, 0, 16, 10263, 13707), + (10265, -1, -1, 795, 795, 12, 85, -1, 0, 0, 16, 7269, 10266), + (10266, -1, -1, 795, 795, 12, 85, -1, 0, 0, 16, 10265, 10267), + (10267, -1, -1, 795, 795, 12, 85, -1, 0, 0, 16, 10266, 12945), + (10268, -1, -1, 7900, 7900, 4, 70, -1, 0, 0, 16, 7902, 10269), + (10269, -1, -1, 7900, 7900, 4, 70, -1, 0, 0, 16, 10268, 10270), + (10270, -1, -1, 7900, 7900, 4, 70, -1, 0, 0, 16, 10269, -1), + (10271, 1242, 1242, 1242, 1242, 12, 85, 16744, 9, 1320, 16, 7287, 10272), + (10272, 1242, 1242, 1242, 1242, 12, 85, 16745, 9, 1320, 16, 10271, 10273), + (10273, 1242, 1242, 1242, 1242, 12, 85, 16746, 9, 1320, 16, 10272, 12934), + (10274, 4931, 4931, 4931, 4931, 7, 85, 16747, 4, 600, 16, 7293, 10275), + (10275, 4931, 4931, 4931, 4931, 7, 85, 16748, 4, 600, 16, 10274, 10276), + (10276, 4931, 4931, 4931, 4931, 7, 85, 16749, 4, 600, 16, 10275, 10428), + (10277, 4935, 4935, 4935, 4935, 7, 81, 16743, 14, 300, 16, 7294, 17540), + (10278, 4934, 4934, 4934, 4934, 7, 81, 16742, 13, 300, 16, 7295, 17539), + (10279, 517, 517, 517, 517, 5, 80, 16739, 12, 600, 16, 7298, 10280), + (10280, 517, 517, 517, 517, 5, 80, 16740, 12, 600, 16, 10279, 10281), + (10281, 517, 517, 517, 517, 5, 80, 16741, 12, 600, 16, 10280, 12917), + (10282, -1, -1, 8031, 8031, 6, 84, -1, 0, 0, 16, 8033, 10283), + (10283, -1, -1, 8031, 8031, 6, 84, -1, 0, 0, 16, 10282, 10284), + (10284, -1, -1, 8031, 8031, 6, 84, -1, 0, 0, 16, 10283, 10431), + (10285, -1, -1, 8035, 8035, 6, 82, -1, 0, 0, 16, 8037, 10286), + (10286, -1, -1, 8035, 8035, 6, 82, -1, 0, 0, 16, 10285, 10287), + (10287, -1, -1, 8035, 8035, 6, 82, -1, 0, 0, 16, 10286, 15472), + (10288, 6971, 6971, 6971, 6971, 7, 85, 16761, 41, 600, 16, 6973, 10289), + (10289, 6971, 6971, 6971, 6971, 7, 85, 16762, 41, 600, 16, 10288, 10290), + (10290, 6971, 6971, 6971, 6971, 7, 85, 16763, 41, 600, 16, 10289, 14274), + (10291, -1, -1, 6974, 6974, 5, 85, -1, 0, 0, 16, 6976, 10292), + (10292, -1, -1, 6974, 6974, 5, 85, -1, 0, 0, 16, 10291, 10293), + (10293, -1, -1, 6974, 6974, 5, 85, -1, 0, 0, 16, 10292, -1), + (10294, 6984, 6984, 6984, 6984, 6, 78, 16765, 60, 60, 16, 6984, 13177), + (10295, 6985, 6985, 6985, 6985, 6, 78, 16766, 60, 60, 16, 6985, 13179), + (10296, 6986, 6986, 6986, 6986, 6, 78, 16767, 60, 60, 16, 6986, 13178), + (10297, 1119, 1119, 1119, 1119, 9, 85, 16750, 8, 900, 16, 7481, 10298), + (10298, 1119, 1119, 1119, 1119, 9, 85, 16751, 8, 900, 16, 10297, 10299), + (10299, 1119, 1119, 1119, 1119, 9, 85, 16752, 8, 900, 16, 10298, 16883), + (10300, 723, 723, 723, 723, 7, 85, 16753, 6, 30, 16, 7482, 14273), + (10301, 5015, 5015, 5015, 5015, 12, 85, 16754, 9, 900, 16, 7483, 17382), + (10302, 291, 291, 291, 291, 12, 85, 16755, 5, 900, 16, 7487, 10303), + (10303, 291, 291, 291, 291, 12, 85, 16756, 5, 900, 16, 10302, 10304), + (10304, 291, 291, 291, 291, 12, 85, 16757, 5, 900, 16, 10303, 12828), + (10305, -1, -1, 729, 729, 9, 85, -1, 0, 0, 16, 7496, 10306), + (10306, -1, -1, 729, 729, 9, 85, -1, 0, 0, 16, 10305, 10307), + (10307, -1, -1, 729, 729, 9, 85, -1, 0, 0, 16, 10306, 16887), + (10308, 6380, 6380, 6380, 6380, 6, 85, 16758, 39, 120, 16, 7499, 10309), + (10309, 6380, 6380, 6380, 6380, 6, 85, 16759, 39, 120, 16, 10308, 10310), + (10310, 6380, 6380, 6380, 6380, 6, 85, 16760, 39, 120, 16, 10309, 13170), + (10311, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 4808, 10312), + (10312, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 10311, 10313), + (10313, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 10312, 10314), + (10314, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 10313, 10315), + (10315, -1, -1, 1134, 1134, 3, 85, -1, 0, 0, 16, 10314, 13035), + (10316, -1, -1, 4809, 4809, 5, 85, -1, 0, 0, 16, 4811, 10317), + (10317, -1, -1, 4809, 4809, 5, 85, -1, 0, 0, 16, 10316, 10318), + (10318, -1, -1, 4809, 4809, 5, 85, -1, 0, 0, 16, 10317, 13040), + (10319, 6931, 6931, 6931, 6931, 12, 85, 16774, 41, 600, 16, 6931, 13058), + (10320, 6932, 6932, 6932, 6932, 7, 85, 16775, 42, 1200, 16, 6934, 10321), + (10321, 6932, 6932, 6932, 6932, 7, 85, 16776, 42, 1200, 16, 10320, 10322), + (10322, 6932, 6932, 6932, 6932, 7, 85, 16777, 42, 1200, 16, 10321, 13062), + (10323, 4854, 4854, 4854, 4854, 12, 85, 16768, 8, 600, 16, 7180, 10324), + (10324, 4854, 4854, 4854, 4854, 12, 85, 16769, 8, 600, 16, 10323, 10325), + (10325, 4854, 4854, 4854, 4854, 12, 85, 16770, 8, 600, 16, 10324, 13059), + (10326, 1178, 1178, 1178, 1178, 9, 85, 16771, 4, 900, 16, 7189, 10327), + (10327, 1178, 1178, 1178, 1178, 9, 85, 16772, 4, 900, 16, 10326, 10328), + (10328, 1178, 1178, 1178, 1178, 9, 85, 16773, 4, 900, 16, 10327, 13845), + (10329, -1, -1, 10329, 10329, 5, 85, 0, 0, 0, 16, -1, 10398), + (10330, 10330, 10330, 10330, 10330, 7, 85, 16785, 35, 30, 16, -1, 13203), + (10331, 10331, 10331, 10331, 10331, 6, 85, 16787, 44, 20, 16, -1, -1), + (10332, -1, -1, 10332, 10332, 3, 85, -1, 0, 0, 16, -1, 12733), + (10333, 10333, 10333, 10333, 10333, 5, 85, 16788, 55, 120, 16, -1, 10334), + (10334, 10333, 10333, 10333, 10333, 7, 85, 16789, 55, 120, 16, 10333, 10335), + (10335, 10333, 10333, 10333, 10333, 9, 85, 16790, 55, 120, 16, 10334, 12724), + (10336, 10336, 10336, 10336, 10336, 5, 85, 16791, 58, 8, 16, -1, 10337), + (10337, 10336, 10336, 10336, 10336, 7, 85, 16792, 58, 8, 16, 10336, 10338), + (10338, 10336, 10336, 10336, 10336, 9, 85, 16793, 58, 8, 16, 10337, 12730), + (10339, 10339, 10339, 10339, 10339, 12, 85, 16786, 48, 1800, 16, -1, -1), + (10340, -1, -1, 10340, 10340, 3, 80, -1, 0, 0, 16, -1, 10341), + (10341, -1, -1, 10340, 10340, 6, 83, -1, 0, 0, 16, 10340, 10342), + (10342, -1, -1, 10340, 10340, 9, 85, -1, 0, 0, 16, 10341, 13184), + (10343, -1, -1, 10343, 10343, 5, 85, 0, 0, 0, 16, -1, 10344), + (10344, -1, -1, 10343, 10343, 7, 85, 0, 0, 0, 16, 10343, 10345), + (10345, -1, -1, 10343, 10343, 9, 85, 0, 0, 0, 16, 10344, 13841), + (10346, 10346, 10346, 10346, 10346, 9, 85, 21783, 46, 600, 16, -1, 13183), + (10347, -1, -1, 7945, 7945, 6, 85, -1, 0, 0, 16, 10034, 17310), + (10348, 0, 0, 10348, 10348, 5, 80, -1, 0, 0, 16, -1, 10349), + (10349, 0, 0, 10348, 10348, 7, 83, -1, 0, 0, 16, 10348, 10350), + (10350, 0, 0, 10348, 10348, 9, 85, -1, 0, 0, 16, 10349, 13578), + (10351, 10351, 10351, 10351, 10351, 12, 85, 21785, 34, 600, 16, -1, 10682), + (10352, 10352, 10352, 10352, 10352, 12, 85, 21786, 34, 600, 16, -1, 10683), + (10353, 10353, 10353, 10353, 10353, 12, 85, 21787, 34, 600, 16, -1, 10684), + (10354, 10354, 10354, 10354, 10354, 8, 85, 21653, 39, 4320, 16, -1, 14016), + (10355, -1, -1, 10355, 10355, 6, 83, -1, 0, 0, 16, -1, 10356), + (10356, -1, -1, 10355, 10355, 8, 84, -1, 0, 0, 16, 10355, 10357), + (10357, -1, -1, 10355, 10355, 10, 85, -1, 0, 0, 16, 10356, 10643), + (10358, -1, -1, 10358, 10358, 7, 80, -1, 0, 0, 16, -1, 10359), + (10359, -1, -1, 10358, 10358, 9, 83, -1, 0, 0, 16, 10358, 10360), + (10360, -1, -1, 10358, 10358, 12, 85, -1, 0, 0, 16, 10359, 14210), + (10361, -1, -1, 962, 962, 5, 83, -1, 0, 0, 16, 6227, 10362), + (10362, -1, -1, 962, 962, 5, 84, -1, 0, 0, 16, 10361, 10363), + (10363, -1, -1, 962, 962, 5, 85, -1, 0, 0, 16, 10362, 14218), + (10364, -1, -1, 10364, 10364, 5, 85, -1, 0, 0, 16, -1, 10365), + (10365, -1, -1, 10364, 10364, 7, 85, -1, 0, 0, 16, 10364, 10366), + (10366, -1, -1, 10364, 10364, 9, 85, -1, 0, 0, 16, 10365, 10442), + (10367, 10367, 10367, 10367, 10367, 12, 85, 21751, 30, 360, 16, -1, 10630), + (10368, 10368, 10368, 10368, 10368, 6, 85, 21654, 46, 900, 16, -1, 10369), + (10369, 10368, 10368, 10368, 10368, 9, 85, 21655, 46, 900, 16, 10368, 10386), + (10370, -1, -1, 10370, 10370, 3, 60, -1, 0, 0, 16, -1, 10371), + (10371, -1, -1, 10370, 10370, 3, 60, -1, 0, 0, 16, 10370, 10372), + (10372, -1, -1, 10370, 10370, 3, 60, -1, 0, 0, 16, 10371, 13927), + (10373, 10373, 10373, 10373, 10373, 6, 75, 16806, 62, 6, 16, -1, -1), + (10374, 10374, 10374, 10374, 10374, 6, 85, 16800, 63, 900, 16, -1, 10375), + (10375, 10374, 10374, 10374, 10374, 6, 85, 16801, 63, 900, 16, 10374, 10376), + (10376, 10374, 10374, 10374, 10374, 6, 85, 16802, 63, 900, 16, 10375, 13174), + (10377, 10377, 10377, 10377, 10377, 6, 85, 16794, 64, 60, 16, -1, 10378), + (10378, 10377, 10377, 10377, 10377, 6, 85, 16795, 64, 60, 16, 10377, 10379), + (10379, 10377, 10377, 10377, 10377, 6, 85, 16796, 64, 60, 16, 10378, 13180), + (10380, -1, -1, 10380, 10380, 6, 85, -1, 0, 0, 16, -1, 10381), + (10381, -1, -1, 10380, 10380, 6, 85, -1, 0, 0, 16, 10380, 10382), + (10382, -1, -1, 10380, 10380, 6, 85, -1, 0, 0, 16, 10381, 13477), + (10383, -1, -1, 5085, 5085, 6, 85, -1, 0, 0, 16, 7386, 10384), + (10384, -1, -1, 5085, 5085, 6, 85, -1, 0, 0, 16, 10383, 10385), + (10385, -1, -1, 5085, 5085, 6, 85, -1, 0, 0, 16, 10384, -1), + (10386, 10368, 10368, 10368, 10368, 12, 85, 21656, 46, 900, 16, 10369, -1), + (10387, 10387, 10387, 10387, 10387, 9, 85, 21835, 45, 1200, 16, -1, -1), + (10388, -1, -1, 10388, 10388, 12, 85, -1, 0, 0, 16, -1, 13545), + (10389, -1, -1, 10389, 10389, 9, 83, 0, 0, 0, 16, -1, 10390), + (10390, -1, -1, 10389, 10389, 11, 84, 0, 0, 0, 16, 10389, 10391), + (10391, -1, -1, 10389, 10389, 12, 85, 0, 0, 0, 16, 10390, -1), + (10392, 10392, 10392, 10392, 10392, 12, 85, 21751, 11, 480, 16, -1, 10631), + (10393, 10393, 10393, 10393, 10393, 9, 81, 3246, 42, 2, 16, -1, -1), + (10394, 10394, 10394, 10394, 10394, 12, 85, 21821, 30, 600, 16, -1, 10704), + (10395, 10395, 10395, 10395, 10395, 3, 80, 21748, 62, 5, 16, -1, 12590), + (10396, 10396, 10396, 10396, 10396, 12, 85, 16857, 14, 600, 16, -1, 10790), + (10397, 10397, 10397, 10397, 10397, 12, 85, 16858, 14, 600, 16, -1, 10791), + (10398, -1, -1, 10329, 10329, 7, 85, 0, 0, 0, 16, 10329, 10399), + (10399, -1, -1, 10329, 10329, 9, 85, 0, 0, 0, 16, 10398, -1), + (10400, 10400, 10400, 10400, 10400, 6, 85, 16807, 62, 900, 16, -1, 15558), + (10401, -1, -1, 10401, 10401, 6, 85, -1, 0, 0, 16, -1, 10402), + (10402, -1, -1, 10401, 10401, 6, 85, -1, 0, 0, 16, 10401, 10403), + (10403, -1, -1, 10401, 10401, 6, 85, -1, 0, 0, 16, 10402, 13052), + (10404, -1, -1, 10404, 10404, 6, 85, -1, 0, 0, 16, -1, 13051), + (10405, -1, -1, 10405, 10405, 7, 81, 0, 0, 0, 16, -1, 10406), + (10406, -1, -1, 10405, 10405, 7, 82, 0, 0, 0, 16, 10405, 10407), + (10407, -1, -1, 10405, 10405, 7, 83, 0, 0, 0, 16, 10406, 10408), + (10408, -1, -1, 10405, 10405, 7, 84, 0, 0, 0, 16, 10407, 10409), + (10409, -1, -1, 10405, 10405, 7, 85, 0, 0, 0, 16, 10408, 10671), + (10410, -1, -1, 10410, 10410, 8, 85, -1, 0, 0, 16, -1, 10411), + (10413, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, -1, 10414), + (10414, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, 10413, 10415), + (10415, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, 10414, 10416), + (10416, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, 10415, 10417), + (10417, -1, -1, 10413, 10413, 5, 81, 0, 0, 0, 16, 10416, -1), + (10418, 6561, 6561, 6561, 6561, 7, 85, 21808, 32, 30, 16, 10101, 10419), + (10419, 6561, 6561, 6561, 6561, 7, 85, 21810, 32, 30, 16, 10418, 10420), + (10420, 6561, 6561, 6561, 6561, 7, 85, 21811, 32, 30, 16, 10419, 14256), + (10421, 10506, 10506, 10506, 10506, 9, 85, 23521, 66, 120, 16, 10508, -1), + (10424, 10424, 10424, 10424, 10424, 7, 81, 21813, 41, 6, 16, -1, -1), + (10425, 10425, 10425, 10425, 10425, 7, 81, 21814, 39, 6, 16, -1, -1), + (10426, 10426, 10426, 10426, 10426, 10, 85, 21816, 5, 900, 16, -1, -1), + (10427, 10427, 10427, 10427, 10427, 12, 85, 21818, 30, 900, 16, -1, -1), + (10428, 4931, 4931, 4931, 4931, 7, 85, 21838, 4, 600, 16, 10276, 10429), + (10429, 4931, 4931, 4931, 4931, 7, 85, 21839, 4, 600, 16, 10428, 10430), + (10430, 4931, 4931, 4931, 4931, 7, 85, 21844, 4, 600, 16, 10429, 13241), + (10431, -1, -1, 8031, 8031, 6, 85, -1, 0, 0, 16, 10284, 10432), + (10432, -1, -1, 8031, 8031, 6, 85, -1, 0, 0, 16, 10431, 10433), + (10433, -1, -1, 8031, 8031, 6, 85, -1, 0, 0, 16, 10432, -1), + (10434, -1, -1, 10434, 10434, 7, 85, 0, 0, 0, 16, -1, 10435), + (10435, -1, -1, 10434, 10434, 9, 85, 0, 0, 0, 16, 10434, 10436), + (10436, -1, -1, 10434, 10434, 12, 85, 0, 0, 0, 16, 10435, -1), + (10437, -1, -1, 6601, 6601, 6, 86, -1, 0, 0, 17, 10029, 10438), + (10438, -1, -1, 6601, 6601, 6, 87, -1, 0, 0, 17, 10437, 10439), + (10439, -1, -1, 6601, 6601, 6, 88, -1, 0, 0, 17, 10438, 10440), + (10440, -1, -1, 6601, 6601, 6, 89, -1, 0, 0, 17, 10439, 10441), + (10442, -1, -1, 10364, 10364, 9, 86, -1, 0, 0, 17, 10366, 10443), + (10443, -1, -1, 10364, 10364, 9, 88, -1, 0, 0, 17, 10442, -1), + (10450, 10450, 10450, 10450, 10450, 7, 85, 16808, 63, 900, 16, -1, 10451), + (10451, 10450, 10450, 10450, 10450, 7, 85, 16809, 63, 900, 16, 10450, 10452), + (10452, 10450, 10450, 10450, 10450, 7, 85, 16810, 63, 900, 16, 10451, 10468), + (10453, -1, -1, 10453, 10453, 5, 85, -1, 0, 0, 16, -1, 10454), + (10454, -1, -1, 10453, 10453, 7, 85, -1, 0, 0, 16, 10453, 10455), + (10455, -1, -1, 10453, 10453, 9, 85, -1, 0, 0, 16, 10454, 13607), + (10456, -1, -1, 10456, 10456, 5, 85, -1, 0, 0, 16, -1, 10457), + (10457, -1, -1, 10456, 10456, 7, 85, -1, 0, 0, 16, 10456, 10458), + (10458, -1, -1, 10456, 10456, 9, 85, -1, 0, 0, 16, 10457, -1), + (10459, -1, -1, 10459, 10459, 5, 65, -1, 0, 0, 16, -1, 10460), + (10460, -1, -1, 10459, 10459, 7, 65, -1, 0, 0, 16, 10459, 10461), + (10461, -1, -1, 10459, 10459, 9, 65, -1, 0, 0, 16, 10460, -1), + (10462, 10462, 10462, 10462, 10462, 12, 85, 16811, 14, 4320, 16, -1, -1), + (10463, 10463, 10463, 10463, 10463, 12, 85, 16812, 16, 4320, 16, -1, -1), + (10464, -1, -1, 10464, 10464, 5, 80, -1, 0, 0, 16, -1, 10465), + (10465, -1, -1, 10464, 10464, 7, 80, -1, 0, 0, 16, 10464, 10466), + (10466, -1, -1, 10464, 10464, 9, 80, -1, 0, 0, 16, 10465, 13140), + (10467, -1, -1, 86, 86, 8, 85, -1, 0, 0, 17, 266, -1), + (10468, 10450, 10450, 10450, 10450, 7, 85, 23603, 63, 900, 17, 10452, 10469), + (10469, 10450, 10450, 10450, 10450, 7, 85, 23604, 63, 900, 17, 10468, 10670), + (10470, -1, -1, 10470, 10470, 9, 86, -1, 0, 0, 17, -1, 10471), + (10471, -1, -1, 10470, 10470, 12, 88, -1, 0, 0, 17, 10470, 10472), + (10472, -1, -1, 10470, 10470, 15, 90, -1, 0, 0, 17, 10471, 15828), + (10473, -1, -1, 446, 735, 10, 86, -1, 0, 0, 17, 7624, 10474), + (10474, -1, -1, 446, 735, 10, 87, -1, 0, 0, 17, 10473, 10475), + (10475, -1, -1, 446, 735, 10, 88, -1, 0, 0, 17, 10474, 10476), + (10476, -1, -1, 446, 735, 10, 89, -1, 0, 0, 17, 10475, 10477), + (10477, -1, -1, 446, 735, 10, 90, -1, 0, 0, 17, 10476, 13308), + (10478, -1, -1, 10478, 10478, 15, 101, -1, 0, 0, 21, -1, 10479), + (10481, 10481, 10481, 10481, 10481, 21, 105, 46249, 90, 600, 21, -1, -1), + (10500, 10500, 10500, 10500, 10500, 7, 85, 16813, 62, 12, 16, -1, -1), + (10501, 10501, 10501, 10501, 10501, 7, 85, 16814, 63, 1, 16, -1, -1), + (10502, 10502, -1, 10502, 10502, 7, 85, 1566, 64, 120, 16, -1, 12647), + (10503, 10503, 10503, 10503, 10503, 9, 85, 16816, 13, 600, 16, -1, 10504), + (10504, 10503, 10503, 10503, 10503, 9, 85, 16817, 13, 600, 16, 10503, 10505), + (10505, 10503, 10503, 10503, 10503, 9, 85, 16818, 13, 600, 16, 10504, 12648), + (10506, 10506, 10506, 10506, 10506, 9, 85, 16819, 66, 120, 16, -1, 10507), + (10507, 10506, 10506, 10506, 10506, 9, 85, 16820, 66, 120, 16, 10506, 10508), + (10508, 10506, 10506, 10506, 10506, 9, 85, 16821, 66, 120, 16, 10507, 10421), + (10509, 5105, 5105, 5105, 5105, 12, 85, 16822, 11, 600, 16, 7420, 13154), + (10510, 7986, 7986, 7986, 7986, 12, 85, 16823, 11, 600, 16, 7988, 13155), + (10511, -1, -1, 10511, 10511, 6, 85, -1, 0, 0, 16, -1, 10512), + (10512, -1, -1, 10511, 10511, 6, 85, -1, 0, 0, 16, 10511, 10513), + (10513, -1, -1, 10511, 10511, 6, 85, -1, 0, 0, 16, 10512, 12642), + (10514, -1, -1, 10514, 10514, 6, 85, -1, 0, 0, 16, -1, 10516), + (10515, -1, -1, 10514, 10514, 6, 85, -1, 0, 0, 16, 10516, 12639), + (10516, -1, -1, 10514, 10514, 6, 85, -1, 0, 0, 16, 10514, 10515), + (10517, 6565, 6565, 6565, 6565, 9, 88, 23608, 17, 45, 17, 10010, 10518), + (10519, -1, -1, 10519, 10519, 9, 86, 0, 0, 0, 17, -1, 10520), + (10522, -1, -1, 10522, 10522, 7, 86, 0, 0, 0, 17, -1, 10523), + (10527, -1, -1, 10527, 10527, 5, 86, 0, 0, 0, 17, -1, 10528), + (10532, -1, -1, 10532, 10532, 5, 86, 0, 0, 0, 17, -1, 10533), + (10537, -1, -1, 10537, 10537, 5, 86, 0, 0, 0, 17, -1, 10538), + (10545, 10545, 10545, 10545, 10545, 12, 85, 23531, 73, 600, 17, -1, -1), + (10546, 10546, 10546, 10546, 10546, 12, 85, 23528, 74, 600, 17, -1, -1), + (10548, -1, -1, 10548, 10548, 9, 86, -1, 0, 0, 17, -1, 10549), + (10550, 10550, 10550, 10550, 10550, 7, 85, 16824, 61, 120, 16, -1, 13250), + (10551, -1, -1, 10551, 10551, 6, 85, -1, 0, 0, 16, -1, 10552), + (10552, -1, -1, 10551, 10551, 6, 85, -1, 0, 0, 16, 10551, 10553), + (10553, -1, -1, 10551, 10551, 6, 85, -1, 0, 0, 16, 10552, 14764), + (10554, -1, -1, 1572, 1572, 5, 80, -1, 0, 0, 16, 1576, 10555), + (10555, -1, -1, 1572, 1572, 5, 80, -1, 0, 0, 16, 10554, 10556), + (10556, -1, -1, 1572, 1572, 5, 80, -1, 0, 0, 16, 10555, 16062), + (10557, 12395, 12395, 12395, 12395, 9, 75, 16828, 11, 900, 16, -1, -1), + (10558, -1, -1, 10558, 10558, 6, 80, -1, 0, 0, 16, -1, 10559), + (10559, -1, -1, 10558, 10558, 6, 83, -1, 0, 0, 16, 10558, 10560), + (10560, -1, -1, 10558, 10558, 6, 85, -1, 0, 0, 16, 10559, 15469), + (10561, -1, -1, 10561, 10561, 6, 85, -1, 0, 0, 16, -1, 10562), + (10562, -1, -1, 10561, 10561, 6, 85, -1, 0, 0, 16, 10561, 10563), + (10563, -1, -1, 10561, 10561, 6, 85, -1, 0, 0, 16, 10562, 15466), + (10564, 773, -1, 773, 773, 12, 85, 16829, 5, 1800, 16, 7278, 10565), + (10565, 773, -1, 773, 773, 12, 85, 16830, 5, 1800, 16, 10564, 10566), + (10566, 773, -1, 773, 773, 12, 85, 16831, 5, 1800, 16, 10565, 13734), + (10568, -1, -1, 6564, 6564, 10, 86, -1, 0, 0, 17, 10009, 10569), + (10571, 1597, 1597, 1597, 1597, 9, 85, 23611, 6, 10, 17, 6606, -1), + (10572, 6617, 6617, 6617, 6617, 12, 86, 23612, 42, 3600, 17, 6617, 14036), + (10573, 6610, 6610, 6610, 6610, 9, 86, 23613, 41, 30, 17, 10003, 13422), + (10574, -1, -1, 6611, 6611, 6, 85, -1, 0, 0, 17, 6619, 16121), + (10575, -1, -1, 6614, 6614, 9, 85, -1, 0, 0, 17, 10005, -1), + (10576, -1, -1, 492, 492, 2, 87, -1, 0, 0, 17, 7130, -1), + (10578, 258, -1, 258, 258, 9, 86, 27520, 1, 600, 17, 258, 16003), + (10579, -1, -1, 7036, 10579, 9, 85, 0, 0, 0, 17, 7038, 10580), + (10580, -1, -1, 7036, 10579, 12, 87, 0, 0, 0, 17, 10579, 10581), + (10585, 912, 912, 912, 912, 9, 86, 23617, 4, 3600, 17, 10013, 10586), + (10588, -1, -1, 10588, 10588, 5, 86, 0, 0, 0, 17, -1, 10589), + (10589, -1, -1, 10588, 10588, 5, 87, 0, 0, 0, 17, 10588, 10590), + (10590, -1, -1, 10588, 10588, 5, 88, 0, 0, 0, 17, 10589, 10591), + (10591, -1, -1, 10588, 10588, 5, 89, 0, 0, 0, 17, 10590, 10592), + (10592, -1, -1, 10588, 10588, 5, 90, 0, 0, 0, 17, 10591, 17206), + (10600, 10600, 10600, 10600, 10600, 7, 85, 16832, 73, 20, 16, -1, 10601), + (10601, 10600, 10600, 10600, 10600, 7, 85, 16833, 73, 20, 16, 10600, 10602), + (10602, 10600, 10600, 10600, 10600, 7, 85, 16834, 73, 20, 16, 10601, 12982), + (10603, 10601, 10601, 10601, 10601, 3, 85, 16835, 62, 6, 16, -1, -1), + (10604, -1, -1, 6051, 6051, 3, 85, -1, 0, 0, 16, 7603, 10605), + (10605, -1, -1, 6051, 6051, 3, 85, -1, 0, 0, 16, 10604, 10606), + (10606, -1, -1, 6051, 6051, 3, 85, -1, 0, 0, 16, 10605, 12795), + (10607, -1, -1, 6383, 6383, 9, 80, -1, 0, 0, 16, 6385, 10608), + (10608, -1, -1, 6383, 6383, 9, 80, -1, 0, 0, 16, 10607, 10609), + (10609, -1, -1, 6383, 6383, 9, 80, -1, 0, 0, 16, 10608, 12801), + (10610, -1, -1, 10610, 10610, 3, 70, -1, 0, 0, 16, -1, 10611), + (10611, -1, -1, 10610, 10610, 3, 70, -1, 0, 0, 16, 10610, 10612), + (10612, -1, -1, 10610, 10610, 3, 70, -1, 0, 0, 16, 10611, -1), + (10618, 7850, 7850, 7850, 7850, 9, 86, 23532, 39, 4320, 17, 7340, 10619), + (10619, 7850, 7850, 7850, 7850, 12, 88, 23533, 39, 4320, 17, 10618, 10620), + (10620, 7850, 7850, 7850, 7850, 15, 90, 23534, 39, 4320, 17, 10619, 13604), + (10621, -1, -1, 849, 849, 9, 85, -1, 0, 0, 17, 851, 10622), + (10622, -1, -1, 849, 849, 9, 87, -1, 0, 0, 17, 10621, 16604), + (10623, -1, -1, 255, 255, 9, 85, -1, 0, 0, 17, 5808, 10624), + (10624, -1, -1, 255, 255, 12, 87, -1, 0, 0, 17, 10623, 10625), + (10625, -1, -1, 255, 255, 15, 89, -1, 0, 0, 17, 10624, 13589), + (10626, 5984, 5984, 5984, 5984, 12, 90, 23535, 2, 30, 17, 7711, 13592), + (10627, -1, -1, 10627, 10627, 3, 59, 0, 0, 0, 3, -1, 10628), + (10628, -1, -1, 10627, 10627, 3, 59, 0, 0, 0, 3, 10627, 10629), + (10629, -1, -1, 10627, 10627, 3, 59, 0, 0, 0, 3, 10628, -1), + (10630, 10367, 10367, 10367, 10367, 12, 90, 27642, 30, 360, 17, 10367, 13434), + (10631, 10392, 10392, 10392, 10392, 12, 90, 27642, 11, 480, 17, 10392, -1), + (10632, -1, -1, 735, 735, 10, 86, -1, 0, 0, 17, 7627, 10633), + (10633, -1, -1, 735, 735, 10, 87, -1, 0, 0, 17, 10632, 10634), + (10634, -1, -1, 735, 735, 10, 88, -1, 0, 0, 17, 10633, 10635), + (10635, -1, -1, 735, 735, 10, 89, -1, 0, 0, 17, 10634, 10636), + (10636, -1, -1, 735, 735, 10, 90, -1, 0, 0, 17, 10635, 13884), + (10637, -1, -1, 1287, 1287, 9, 86, -1, 0, 0, 17, 12471, 10638), + (10638, -1, -1, 1287, 1287, 12, 88, -1, 0, 0, 17, 10637, 10639), + (10639, -1, -1, 1287, 1287, 15, 90, -1, 0, 0, 17, 10638, 13323), + (10640, 5095, 5095, 5095, 5095, 9, 85, 23620, 10, 900, 17, 7334, 10641), + (10641, 5095, 5095, 5095, 5095, 12, 87, 23621, 10, 900, 17, 10640, 10642), + (10642, 5095, 5095, 5095, 5095, 15, 89, 23622, 10, 900, 17, 10641, 13575), + (10643, -1, -1, 10355, 10355, 10, 86, -1, 0, 0, 17, 10357, 10644), + (10644, -1, -1, 10355, 10355, 10, 88, -1, 0, 0, 17, 10643, 10645), + (10645, -1, -1, 10355, 10355, 10, 90, -1, 0, 0, 17, 10644, 14094), + (10646, 7712, 7712, 7712, 7712, 15, 90, 23536, 2, 30, 17, 7712, 13585), + (10647, 188, 188, 188, 188, 9, 88, 23537, 2, 30, 17, 7662, 13586), + (10650, -1, -1, 10650, 10650, 7, 85, -1, 0, 0, 16, -1, 10651), + (10651, -1, -1, 10650, 10650, 9, 85, -1, 0, 0, 16, 10650, 10652), + (10652, -1, -1, 10650, 10650, 12, 85, -1, 0, 0, 16, 10651, 13804), + (10653, -1, -1, 10653, 10653, 7, 85, -1, 0, 0, 16, -1, 10654), + (10654, -1, -1, 10653, 10653, 7, 85, -1, 0, 0, 16, 10653, 10655), + (10655, -1, -1, 10653, 10653, 7, 85, -1, 0, 0, 16, 10654, 17406), + (10656, -1, -1, 10656, 10656, 7, 85, -1, 0, 0, 16, -1, 12678), + (10657, -1, -1, 10657, 10657, 7, 85, -1, 0, 0, 16, -1, 10658), + (10658, -1, -1, 10657, 10657, 7, 85, -1, 0, 0, 16, 10657, 10659), + (10659, -1, -1, 10657, 10657, 7, 85, -1, 0, 0, 16, 10658, 12679), + (10660, -1, -1, 820, 820, 5, 85, -1, 0, 0, 16, 7165, 10661), + (10661, -1, -1, 820, 820, 5, 85, -1, 0, 0, 16, 10660, 10662), + (10662, -1, -1, 820, 820, 5, 85, -1, 0, 0, 16, 10661, 12667), + (10663, -1, -1, 6020, 6020, 2, 85, -1, 0, 0, 16, 7171, 10664), + (10664, -1, -1, 6020, 6020, 2, 85, -1, 0, 0, 16, 10663, 10665), + (10665, -1, -1, 6020, 6020, 2, 85, -1, 0, 0, 16, 10664, 12670), + (10666, -1, -1, 495, 495, 6, 85, -1, 0, 0, 16, 6262, 10667), + (10667, -1, -1, 495, 495, 5, 85, -1, 0, 0, 16, 10666, 10668), + (10668, -1, -1, 495, 495, 7, 85, -1, 0, 0, 16, 10667, 17391), + (10670, 10450, 10450, 10450, 10450, 7, 85, 23605, 63, 900, 17, 10469, 15839), + (10671, -1, -1, 10405, 10405, 9, 86, 0, 0, 0, 17, 10409, 10672), + (10672, -1, -1, 10405, 10405, 9, 87, 0, 0, 0, 17, 10671, 10673), + (10673, -1, -1, 10405, 10405, 9, 88, 0, 0, 0, 17, 10672, 10674), + (10674, -1, -1, 10405, 10405, 9, 89, 0, 0, 0, 17, 10673, 10675), + (10675, -1, -1, 10405, 10405, 9, 90, 0, 0, 0, 17, 10674, -1), + (10676, -1, -1, 6791, 6791, 6, 86, -1, 0, 0, 17, 10046, 10677), + (10677, -1, -1, 6791, 6791, 6, 88, -1, 0, 0, 17, 10676, 10678), + (10678, -1, -1, 6791, 6791, 6, 90, -1, 0, 0, 17, 10677, 13598), + (10679, 6492, 6492, 6492, 6492, 9, 85, 23626, 52, 720, 17, 6497, 10680), + (10680, 6492, 6492, 6492, 6492, 9, 87, 23627, 52, 720, 17, 10679, 10681), + (10681, 6492, 6492, 6492, 6492, 9, 89, 23628, 52, 720, 17, 10680, 14003), + (10682, 10351, 10351, 10351, 10351, 15, 90, 23538, 34, 600, 17, 10351, -1), + (10683, 10352, 10352, 10352, 10352, 15, 90, 23539, 34, 600, 17, 10352, -1), + (10684, 10353, 10353, 10353, 10353, 15, 90, 23540, 34, 600, 17, 10353, -1), + (10685, -1, -1, 602, 602, 9, 86, -1, 0, 0, 17, 5582, 10686), + (10686, -1, -1, 602, 602, 12, 88, -1, 0, 0, 17, 10685, 10687), + (10687, -1, -1, 602, 602, 15, 90, -1, 0, 0, 17, 10686, 13610), + (10688, -1, -1, 855, 855, 7, 86, -1, 0, 0, 17, 7677, 10689), + (10689, -1, -1, 855, 855, 7, 87, -1, 0, 0, 17, 10688, 10690), + (10690, -1, -1, 855, 855, 7, 88, -1, 0, 0, 17, 10689, 10691), + (10691, -1, -1, 855, 855, 7, 89, -1, 0, 0, 17, 10690, 10692), + (10692, -1, -1, 855, 855, 7, 90, -1, 0, 0, 17, 10691, 13613), + (10700, 10700, 10700, 10700, 10700, 7, 85, 16839, 61, 10, 16, -1, -1), + (10701, 10701, 10701, 10701, 10701, 7, 85, 21662, 32, 360, 16, -1, 10702), + (10702, 10701, 10701, 10701, 10701, 9, 85, 21663, 32, 360, 16, 10701, 10703), + (10703, 10701, 10701, 10701, 10701, 12, 85, 21664, 32, 360, 16, 10702, 12754), + (10704, 10394, 10394, 10394, 10394, 12, 85, 23541, 30, 300, 17, 10394, 13584), + (10705, -1, -1, 6395, 6395, 9, 86, -1, 0, 0, 17, 10052, 10706), + (10706, -1, -1, 6395, 6395, 9, 88, -1, 0, 0, 17, 10705, 10707), + (10707, -1, -1, 6395, 6395, 9, 90, -1, 0, 0, 17, 10706, 14097), + (10708, 534, 534, 534, 534, 12, 86, 23545, 4, 2160, 17, 10049, 10709), + (10709, 534, 534, 534, 534, 12, 88, 23546, 4, 2160, 17, 10708, 10710), + (10710, 534, 534, 534, 534, 12, 90, 23547, 4, 2160, 17, 10709, 13595), + (10711, 10711, 10711, 10711, 10711, 9, 86, 23548, 75, 1200, 17, -1, 10712), + (10712, 10711, 10711, 10711, 10711, 12, 88, 23549, 75, 1200, 17, 10711, 10713), + (10713, 10711, 10711, 10711, 10711, 15, 90, 23550, 75, 1200, 17, 10712, 14006), + (10714, -1, -1, 10714, 10714, 9, 86, 0, 0, 0, 17, -1, 10715), + (10715, -1, -1, 10714, 10714, 12, 88, 0, 0, 0, 17, 10714, 10716), + (10717, -1, -1, 7743, 7743, 9, 61, -1, 0, 0, 17, 7745, 10718), + (10718, -1, -1, 7743, 7743, 9, 61, -1, 0, 0, 17, 10717, 15258), + (10719, -1, -1, 10719, 10719, 9, 75, 0, 0, 0, 17, -1, 10720), + (10720, -1, -1, 10719, 10719, 12, 75, 0, 0, 0, 17, 10719, 10721), + (10721, -1, -1, 10719, 10719, 15, 75, 0, 0, 0, 17, 10720, 13562), + (10722, -1, -1, 10722, 10722, 5, 81, 0, 0, 0, 17, -1, 10723), + (10723, -1, -1, 10722, 10722, 5, 82, 0, 0, 0, 17, 10722, 10724), + (10724, -1, -1, 10722, 10722, 7, 83, 0, 0, 0, 17, 10723, 10725), + (10725, -1, -1, 10722, 10722, 9, 84, 0, 0, 0, 17, 10724, 10726), + (10726, -1, -1, 10722, 10722, 12, 85, 0, 0, 0, 17, 10725, 15280), + (10727, -1, -1, 10727, 10727, 7, 86, 0, 0, 0, 17, -1, 10728), + (10728, -1, -1, 10727, 10727, 9, 88, 0, 0, 0, 17, 10727, 10729), + (10730, -1, -1, 10730, 10730, 7, 86, 0, 0, 0, 17, -1, 10731), + (10731, -1, -1, 10730, 10730, 9, 88, 0, 0, 0, 17, 10730, 10732), + (10733, -1, -1, 10733, 10733, 7, 81, 0, 0, 0, 17, -1, 10734), + (10734, -1, -1, 10733, 10733, 9, 83, 0, 0, 0, 17, 10733, 10735), + (10735, -1, -1, 10733, 10733, 12, 85, 0, 0, 0, 17, 10734, -1), + (10736, 10736, 10736, 10736, 10736, 7, 86, 23632, 5, 180, 17, -1, 10737), + (10737, 10736, 10736, 10736, 10736, 9, 88, 23633, 5, 180, 17, 10736, 10738), + (10739, 645, -1, 645, 645, 12, 86, 23551, 4, 5, 17, 5999, 13410), + (10740, 1345, 1345, 1345, 1345, 9, 86, 23552, 6, 900, 17, 7349, 10741), + (10741, 1345, 1345, 1345, 1345, 12, 88, 23553, 6, 900, 17, 10740, 10742), + (10743, -1, -1, 1196, 1196, 5, 86, -1, 0, 0, 17, 1200, 10744), + (10744, -1, -1, 1196, 1196, 5, 87, -1, 0, 0, 17, 10743, 10745), + (10745, -1, -1, 1196, 1196, 5, 88, -1, 0, 0, 17, 10744, 10746), + (10748, -1, -1, 867, 867, 7, 86, -1, 0, 0, 17, 7366, 10749), + (10749, -1, -1, 867, 867, 7, 87, -1, 0, 0, 17, 10748, 10755), + (10750, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 16, 7328, 10751), + (10751, -1, -1, 7103, 7103, 2, 70, -1, 0, 0, 16, 10750, -1), + (10752, 10752, 10752, 10752, 10752, 6, 85, 16843, 72, 600, 16, -1, -1), + (10753, 10753, 10753, 10753, 10753, 12, 80, 16844, 6, 4320, 16, -1, -1), + (10754, 10754, 10754, 10754, 10754, 2, 70, 16845, 62, 5, 16, -1, -1), + (10755, -1, -1, 867, 867, 7, 88, -1, 0, 0, 17, 10749, 10756), + (10758, 545, 545, 545, 545, 12, 86, 23638, 3, 900, 17, 7346, 10759), + (10759, 545, 545, 545, 545, 12, 87, 23639, 3, 900, 17, 10758, 10760), + (10760, 545, 545, 545, 545, 12, 88, 23640, 3, 900, 17, 10759, 10761), + (10763, -1, -1, 6761, 6761, 12, 86, -1, 0, 0, 17, 6087, 10764), + (10764, -1, -1, 6761, 6761, 12, 88, -1, 0, 0, 17, 10763, 10765), + (10766, -1, -1, 6765, 6765, 9, 85, -1, 0, 0, 17, 10060, 10767), + (10767, -1, -1, 6765, 6765, 9, 87, -1, 0, 0, 17, 10766, 10768), + (10768, -1, -1, 6765, 6765, 9, 89, -1, 0, 0, 17, 10767, 13553), + (10769, -1, -1, 6751, 6751, 9, 86, -1, 0, 0, 17, 6769, 10770), + (10770, -1, -1, 6751, 6751, 9, 88, -1, 0, 0, 17, 10769, 10771), + (10772, 872, 872, 872, 872, 9, 85, 23555, 5, 180, 17, 7369, 10773), + (10773, 872, 872, 872, 872, 9, 87, 23556, 5, 180, 17, 10772, 10774), + (10774, 872, 872, 872, 872, 9, 89, 23557, 5, 180, 17, 10773, -1), + (10775, 875, 875, 875, 875, 9, 85, 23561, 5, 180, 17, 7372, 10776), + (10776, 875, 875, 875, 875, 9, 87, 23562, 5, 180, 17, 10775, 10777), + (10777, 875, 875, 875, 875, 9, 89, 23563, 5, 180, 17, 10776, 13536), + (10778, -1, -1, 634, 634, 12, 85, -1, 0, 0, 17, 7714, 10779), + (10779, -1, -1, 634, 634, 12, 87, -1, 0, 0, 17, 10778, 10780), + (10780, -1, -1, 634, 634, 12, 89, -1, 0, 0, 17, 10779, 15585), + (10781, -1, -1, 8240, 8240, 9, 85, -1, 0, 0, 17, 8244, 10782), + (10782, -1, -1, 8240, 8240, 9, 86, -1, 0, 0, 17, 10781, 10783), + (10783, -1, -1, 8240, 8240, 9, 87, -1, 0, 0, 17, 10782, 10784), + (10784, -1, -1, 8240, 8240, 9, 88, -1, 0, 0, 17, 10783, 10785), + (10785, -1, -1, 8240, 8240, 9, 89, -1, 0, 0, 17, 10784, 13343), + (10786, 7800, 7800, 7800, 7800, 12, 85, 23567, 39, 4320, 17, 7817, 10787), + (10787, 7800, 7800, 7800, 7800, 12, 87, 23568, 39, 4320, 17, 10786, 13619), + (10788, -1, -1, 4699, 4699, 7, 65, -1, 0, 0, 17, 7500, -1), + (10789, 10789, 10789, 10789, 10789, 15, 90, 23575, 41, 6, 17, -1, 14261), + (10790, 10396, 10396, 10396, 10396, 15, 90, 23576, 14, 600, 17, 10396, 14024), + (10791, 10397, 10397, 10397, 10397, 15, 90, 23577, 14, 600, 17, 10397, 14025), + (10792, -1, -1, 10792, 10792, 5, 86, 0, 0, 0, 17, -1, 10793), + (10793, -1, -1, 10792, 10792, 7, 87, 0, 0, 0, 17, 10792, 10794), + (10794, -1, -1, 10792, 10792, 9, 88, 0, 0, 0, 17, 10793, 10795), + (10795, -1, -1, 10792, 10792, 11, 89, 0, 0, 0, 17, 10794, 10796), + (10796, -1, -1, 10792, 10792, 13, 90, 0, 0, 0, 17, 10795, 17365), + (10800, -1, -1, 10800, 10800, 6, 70, -1, 0, 0, 16, -1, 10801), + (10801, -1, -1, 10800, 10800, 9, 70, -1, 0, 0, 16, 10800, 10802), + (10802, -1, -1, 10800, 10800, 12, 70, -1, 0, 0, 16, 10801, 17476), + (10803, -1, -1, 10803, 10803, 6, 76, -1, 0, 0, 16, -1, 10804), + (10804, -1, -1, 10803, 10803, 6, 78, -1, 0, 0, 16, 10803, 10805), + (10805, -1, -1, 10803, 10803, 6, 80, -1, 0, 0, 16, 10804, -1), + (10806, 10806, 10806, 10806, 10806, 10, 80, 16846, 71, 540, 16, -1, 10807), + (10807, 10806, 10806, 10806, 10806, 11, 80, 16847, 71, 540, 16, 10806, 10808), + (10808, 10806, 10806, 10806, 10806, 12, 80, 16848, 71, 540, 16, 10807, 15298), + (10809, 10809, 10809, 10809, 10809, 10, 80, 16849, 71, 540, 16, -1, 10810), + (10810, 10809, 10809, 10809, 10809, 11, 80, 16850, 71, 540, 16, 10809, 10811), + (10811, 10809, 10809, 10809, 10809, 12, 80, 16851, 71, 540, 16, 10810, 15301), + (10815, 10815, 10815, 10815, 10815, 6, 80, -1, 0, 0, 16, -1, 10816), + (10816, 10815, 10815, 10815, 10815, 9, 80, -1, 0, 0, 16, 10815, 10817), + (10817, 10815, 10815, 10815, 10815, 12, 80, -1, 0, 0, 16, 10816, 13110), + (10818, 10818, 10818, 10818, 10818, 6, 80, -1, 0, 0, 16, -1, 10819), + (10819, 10818, 10818, 10818, 10818, 9, 80, -1, 0, 0, 16, 10818, 10820), + (10820, 10818, 10818, 10818, 10818, 12, 80, -1, 0, 0, 16, 10819, 13113), + (10821, 10821, 10821, 10821, 10821, 6, 80, -1, 0, 0, 16, -1, 10822), + (10822, 10821, 10821, 10821, 10821, 9, 80, -1, 0, 0, 16, 10821, 10823), + (10823, 10821, 10821, 10821, 10821, 12, 80, -1, 0, 0, 16, 10822, 13116), + (10824, 510, 510, 510, 510, 6, 86, 23578, 37, 240, 17, 10104, 10825), + (10850, -1, -1, 10850, 10850, 6, 85, 16864, 0, 0, 16, -1, 10851), + (10851, -1, -1, 10850, 10850, 6, 85, 16865, 0, 0, 16, 10850, 10852), + (10852, -1, -1, 10850, 10850, 6, 85, 16866, 0, 0, 16, 10851, 13207), + (10853, -1, -1, 10853, 10853, 3, 65, -1, 0, 0, 16, -1, 10854), + (10854, -1, -1, 10853, 10853, 6, 65, -1, 0, 0, 16, 10853, 10855), + (10855, -1, -1, 10853, 10853, 9, 65, -1, 0, 0, 16, 10854, 10856), + (10856, -1, -1, 10853, 10853, 5, 66, -1, 0, 0, 16, 10855, 10857), + (10857, -1, -1, 10853, 10853, 5, 68, -1, 0, 0, 16, 10856, 10858), + (10858, -1, -1, 10853, 10853, 5, 70, -1, 0, 0, 16, 10857, 10859), + (10859, -1, -1, 10853, 10853, 5, 76, -1, 0, 0, 16, 10858, 10860), + (10860, -1, -1, 10853, 10853, 5, 78, -1, 0, 0, 16, 10859, 10861), + (10861, -1, -1, 10853, 10853, 5, 80, -1, 0, 0, 16, 10860, 10862), + (10862, -1, -1, 10853, 10853, 5, 81, -1, 0, 0, 16, 10861, 10863), + (10863, -1, -1, 10853, 10853, 5, 83, -1, 0, 0, 16, 10862, 10864), + (10864, -1, -1, 10853, 10853, 5, 85, -1, 0, 0, 16, 10863, 15954), + (10865, -1, -1, 1304, 1304, 12, 85, -1, 0, 0, 16, 7150, 10866), + (10866, -1, -1, 1304, 1304, 12, 85, -1, 0, 0, 16, 10865, 10867), + (10867, -1, -1, 1304, 1304, 12, 85, -1, 0, 0, 16, 10866, 13218), + (10868, 5021, 5021, 5021, 5021, 9, 76, 16867, 7, 60, 16, 5021, 10869), + (10869, 5021, 5021, 5021, 5021, 9, 81, 16868, 7, 60, 16, 10868, 10870), + (10870, 5021, 5021, 5021, 5021, 9, 85, 16869, 7, 60, 16, 10869, 12618), + (10900, 10900, 10900, 10900, 10900, 9, 85, 16870, 55, 120, 16, -1, 10901), + (10901, 10900, 10900, 10900, 10900, 9, 85, 16871, 55, 120, 16, 10900, 10902), + (10902, 10900, 10900, 10900, 10900, 9, 85, 16872, 55, 120, 16, 10901, 13624), + (10903, -1, -1, 10903, 10903, 6, 81, -1, 0, 0, 16, -1, 10904), + (10904, -1, -1, 10903, 10903, 6, 83, -1, 0, 0, 16, 10903, 10905), + (10905, -1, -1, 10903, 10903, 6, 85, -1, 0, 0, 16, 10904, -1), + (10906, -1, -1, 895, 895, 12, 85, -1, 0, 0, 16, 7406, 10907), + (10907, -1, -1, 895, 895, 12, 85, -1, 0, 0, 16, 10906, 10908), + (10908, -1, -1, 895, 895, 12, 85, -1, 0, 0, 16, 10907, 13627), + (10909, -1, -1, 10909, 10909, 6, 85, -1, 0, 0, 16, -1, 10910), + (10910, -1, -1, 10909, 10909, 6, 85, -1, 0, 0, 16, 10909, 10911), + (10911, -1, -1, 10909, 10909, 6, 85, -1, 0, 0, 16, 10910, -1), + (10912, 10912, 10912, 10912, 10912, 6, 85, 16873, 69, 1800, 16, -1, 10913), + (10913, 10912, 10912, 10912, 10912, 6, 85, 16874, 69, 1800, 16, 10912, 10914), + (10914, 10912, 10912, 10912, 10912, 6, 85, 16875, 69, 1800, 16, 10913, 14053), + (10915, -1, -1, 10915, 10915, 9, 85, -1, 0, 0, 16, -1, 10916), + (10916, -1, -1, 10915, 10915, 9, 85, -1, 0, 0, 16, 10915, 10917), + (10917, -1, -1, 10915, 10915, 9, 85, -1, 0, 0, 16, 10916, 16189), + (10950, -1, -1, 10950, 10950, 6, 85, -1, 0, 0, 16, -1, -1), + (10951, -1, -1, 10951, 10951, 12, 85, -1, 0, 0, 16, -1, 10952), + (10952, -1, -1, 10951, 10951, 12, 85, -1, 0, 0, 16, 10951, 10953), + (10953, -1, -1, 10951, 10951, 12, 85, -1, 0, 0, 16, 10952, 15363), + (10954, -1, -1, 10954, 10954, 12, 85, -1, 0, 0, 16, -1, 10955), + (10955, -1, -1, 10954, 10954, 12, 85, -1, 0, 0, 16, 10954, 10956), + (10956, -1, -1, 10954, 10954, 12, 85, -1, 0, 0, 16, 10955, -1), + (10957, 10957, 10957, 10957, 10957, 6, 85, 16879, 61, 5, 16, -1, -1), + (10958, 10958, 10958, 10958, 10958, 12, 85, 16880, 62, 900, 16, -1, 13000), + (10959, 10959, 10959, 10959, 10959, 12, 85, 16881, 63, 600, 16, -1, 10961), + (10961, 10959, 10959, 10959, 10959, 12, 85, 21717, 63, 600, 16, 10959, 10962), + (10962, 10959, 10959, 10959, 10959, 12, 85, 21718, 63, 600, 16, 10961, 12988), + (11000, -1, -1, 11000, 11000, 6, 85, -1, 0, 0, 16, -1, 11001), + (11001, -1, -1, 11000, 11000, 9, 85, -1, 0, 0, 16, 11000, 11002), + (11002, -1, -1, 11000, 11000, 12, 85, -1, 0, 0, 16, 11001, -1), + (11003, -1, -1, 11003, 11003, 6, 85, -1, 0, 0, 16, -1, -1), + (11004, -1, -1, 11004, 11004, 6, 85, -1, 0, 0, 16, -1, 11005), + (11005, -1, -1, 11004, 11004, 6, 85, -1, 0, 0, 16, 11004, 11006), + (11006, -1, -1, 11004, 11004, 6, 85, -1, 0, 0, 16, 11005, -1), + (11011, -1, -1, 6302, 6302, 5, 85, 0, 0, 0, 16, 6304, 11012), + (11012, -1, -1, 6302, 6302, 5, 85, 0, 0, 0, 16, 11011, 11013), + (11013, -1, -1, 6302, 6302, 5, 85, 0, 0, 0, 16, 11012, 15552), + (11014, -1, -1, 11007, 11007, 5, 80, -1, 0, 0, 16, -1, 11015), + (11015, -1, -1, 11007, 11007, 7, 82, -1, 0, 0, 16, 11014, 11016), + (11016, -1, -1, 11007, 11007, 9, 85, -1, 0, 0, 16, 11015, 11020), + (11020, -1, -1, 11007, 11007, 12, 86, -1, 0, 0, 17, 11016, -1), + (11050, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, -1, 11051), + (11051, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, 11050, 11052), + (11052, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, 11051, 11059), + (11053, -1, -1, 6349, 6349, 6, 83, -1, 0, 0, 16, 7620, 11054), + (11054, -1, -1, 6349, 6349, 6, 83, -1, 0, 0, 16, 11053, -1), + (11055, 11055, 11055, 11055, 11055, 3, 85, 16884, 63, 20, 16, -1, -1), + (11056, 11056, 11056, 11056, 11056, 6, 85, 16885, 64, 180, 16, -1, -1), + (11057, 11057, 11057, 11057, 11057, 2, 85, 1422, 65, 10, 16, -1, -1), + (11058, 11058, 11058, 11058, 11058, 2, 85, 3243, 66, 10, 16, -1, -1), + (11059, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, 11052, 11060), + (11060, -1, -1, 11050, 11050, 6, 85, -1, 0, 0, 16, 11059, 12871), + (11061, -1, -1, 98, 98, 12, 85, -1, 0, 0, 16, 7586, 11062), + (11062, -1, -1, 98, 98, 12, 85, -1, 0, 0, 16, 11061, 11063), + (11063, -1, -1, 98, 98, 12, 85, -1, 0, 0, 16, 11062, 13921), + (11064, 6290, 6290, 6290, 6290, 7, 85, 23500, 0, 1, 16, 7225, 11065), + (11065, 6290, 6290, 6290, 6290, 9, 85, 23501, 0, 1, 16, 11064, 11066), + (11066, 6290, 6290, 6290, 6290, 12, 85, 23502, 0, 1, 16, 11065, 13229), + (11067, 4944, -1, 4944, 4944, 7, 85, 23506, 0, 1, 16, 7231, 11068), + (11068, 4944, -1, 4944, 4944, 9, 85, 23507, 0, 1, 16, 11067, 11069), + (11069, 4944, -1, 4944, 4944, 12, 85, 23508, 0, 1, 16, 11068, 13232), + (11070, 1478, -1, 1478, 1478, 9, 85, 23512, 0, 1, 16, 7244, 11071), + (11071, 1478, -1, 1478, 1478, 10, 85, 23513, 0, 1, 16, 11070, 11072), + (11072, 1478, -1, 1478, 1478, 12, 85, 23514, 0, 1, 16, 11071, 13235), + (11073, 11073, 11073, 11073, 11073, 12, 85, 23518, 53, 30, 16, -1, 13447), + (11074, -1, -1, 11074, 11074, 5, 81, 0, 0, 0, 16, -1, 11075), + (11075, -1, -1, 11074, 11074, 7, 83, 0, 0, 0, 16, 11074, 11076), + (11076, -1, -1, 11074, 11074, 9, 85, 0, 0, 0, 16, 11075, -1), + (11077, -1, -1, 11077, 11077, 5, 81, 0, 0, 0, 16, -1, 15895), + (11078, -1, -1, 11078, 11078, 5, 81, 0, 0, 0, 16, -1, 15891), + (11079, -1, -1, 11079, 11079, 5, 81, 0, 0, 0, 16, -1, 15893), + (11080, 11080, 11080, 11080, 11080, 7, 85, 23519, 10, 20, 16, -1, 13472), + (11081, 153, 153, 153, 153, 12, 85, 23599, 3, 2160, 16, 10193, 12996), + (11082, -1, -1, 1131, 1131, 6, 81, -1, 0, 0, 16, 1133, 11083), + (11083, -1, -1, 1131, 1131, 9, 83, -1, 0, 0, 16, 11082, 11084), + (11084, -1, -1, 1131, 1131, 12, 85, -1, 0, 0, 16, 11083, 13032), + (11085, -1, -1, 11085, 11085, 7, 85, 0, 0, 0, 16, -1, 11086), + (11086, -1, -1, 11085, 11085, 9, 85, 0, 0, 0, 16, 11085, 11087), + (11087, -1, -1, 11085, 11085, 12, 85, 0, 0, 0, 16, 11086, 13021), + (11088, -1, -1, 11088, 11088, 6, 75, 0, 0, 0, 16, -1, 11089), + (11089, -1, -1, 11088, 11088, 6, 75, 0, 0, 0, 16, 11088, 11090), + (11090, -1, -1, 11088, 11088, 6, 75, 0, 0, 0, 16, 11089, 11091), + (11091, -1, -1, 11088, 11088, 6, 75, 0, 0, 0, 16, 11090, -1), + (12396, -1, -1, 125, 125, 8, 85, -1, 0, 0, 16, 7505, 12397), + (12397, -1, -1, 125, 125, 9, 85, -1, 0, 0, 16, 12396, 12398), + (12398, -1, -1, 125, 125, 10, 85, -1, 0, 0, 16, 12397, 12399), + (12399, -1, -1, 125, 125, 11, 85, -1, 0, 0, 16, 12398, 12400), + (12400, -1, -1, 125, 125, 12, 85, -1, 0, 0, 16, 12399, 13080), + (12401, -1, -1, 122, 122, 8, 85, -1, 0, 0, 16, 7510, 12402), + (12402, -1, -1, 122, 122, 9, 85, -1, 0, 0, 16, 12401, 12403), + (12403, -1, -1, 122, 122, 10, 85, -1, 0, 0, 16, 12402, 12404), + (12404, -1, -1, 122, 122, 11, 85, -1, 0, 0, 16, 12403, 12405), + (12405, -1, -1, 122, 122, 12, 85, -1, 0, 0, 16, 12404, 13085), + (12406, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 7530, 12407), + (12407, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 12406, 12408), + (12408, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 12407, 12409), + (12409, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 12408, 12410), + (12410, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 16, 12409, 12492), + (12411, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 8259, 12412), + (12412, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 12411, 12413), + (12413, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 12412, 12414), + (12414, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 12413, 12415), + (12415, -1, -1, 8255, 8255, 6, 85, -1, 0, 0, 16, 12414, 13358), + (12416, -1, -1, 12416, 12416, 7, 83, -1, 0, 0, 16, -1, 12417), + (12417, -1, -1, 12416, 12416, 9, 84, -1, 0, 0, 16, 12416, 12418), + (12418, -1, -1, 12416, 12416, 12, 85, -1, 0, 0, 16, 12417, 13413), + (12419, -1, -1, 12419, 12419, 5, 83, -1, 0, 0, 16, -1, 12420), + (12420, -1, -1, 12419, 12419, 5, 84, -1, 0, 0, 16, 12419, 12421), + (12421, -1, -1, 12419, 12419, 5, 85, -1, 0, 0, 16, 12420, 12575), + (12422, 12422, 12422, 12422, 12422, 12, 85, 13994, 47, 12, 16, -1, -1), + (12423, -1, -1, 767, 767, 9, 81, -1, 0, 0, 16, 1101, 12424), + (12424, -1, -1, 767, 767, 10, 83, -1, 0, 0, 16, 12423, 12425), + (12425, -1, -1, 767, 767, 12, 85, -1, 0, 0, 16, 12424, -1), + (12426, -1, -1, 767, 767, 3, 81, -1, 0, 0, 16, 6245, 12427), + (12427, -1, -1, 767, 767, 6, 83, -1, 0, 0, 16, 12426, 12428), + (12428, -1, -1, 767, 767, 9, 85, -1, 0, 0, 16, 12427, -1), + (12432, -1, -1, 1107, 1107, 10, 81, -1, 0, 0, 16, 6405, 12433), + (12433, -1, -1, 1107, 1107, 11, 83, -1, 0, 0, 16, 12432, 12434), + (12434, -1, -1, 1107, 1107, 12, 85, -1, 0, 0, 16, 12433, 12556), + (12435, -1, -1, 637, 637, 8, 81, -1, 0, 0, 16, 5573, 12436), + (12436, -1, -1, 637, 637, 10, 83, -1, 0, 0, 16, 12435, 12437), + (12437, -1, -1, 637, 637, 12, 85, -1, 0, 0, 16, 12436, 12553), + (12438, -1, -1, 686, 686, 5, 85, -1, 0, 0, 16, 7640, -1), + (12439, -1, -1, 1592, 1592, 9, 85, -1, 0, 0, 16, 7572, 12440), + (12440, -1, -1, 1592, 1592, 10, 85, -1, 0, 0, 16, 12439, 12441), + (12441, -1, -1, 1592, 1592, 11, 85, -1, 0, 0, 16, 12440, 12442), + (12442, -1, -1, 1592, 1592, 12, 85, -1, 0, 0, 16, 12441, 12443), + (12443, -1, -1, 1592, 1592, 12, 85, -1, 0, 0, 16, 12442, 12532), + (12444, -1, -1, 1072, 1072, 8, 85, -1, 0, 0, 16, 7580, 12445), + (12445, -1, -1, 1072, 1072, 9, 85, -1, 0, 0, 16, 12444, 12446), + (12446, -1, -1, 1072, 1072, 10, 85, -1, 0, 0, 16, 12445, 12447), + (12447, -1, -1, 1072, 1072, 11, 85, -1, 0, 0, 16, 12446, 12448), + (12448, -1, -1, 1072, 1072, 12, 85, -1, 0, 0, 16, 12447, 12537), + (12449, -1, -1, 77, 77, 10, 81, -1, 0, 0, 16, 1085, 12450), + (12450, -1, -1, 77, 77, 11, 83, -1, 0, 0, 16, 12449, 12451), + (12451, -1, -1, 77, 77, 12, 85, -1, 0, 0, 16, 12450, 12497), + (12452, -1, -1, 80, 80, 12, 85, -1, 0, 0, 16, 7592, 12453), + (12453, -1, -1, 80, 80, 12, 85, -1, 0, 0, 16, 12452, 12454), + (12454, -1, -1, 80, 80, 12, 85, -1, 0, 0, 16, 12453, 12567), + (12455, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 7597, 12456), + (12456, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 12455, 12457), + (12457, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 12456, 12458), + (12458, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 12457, 12459), + (12459, -1, -1, 658, 658, 5, 85, -1, 0, 0, 16, 12458, 12570), + (12460, 6537, 6537, 6537, 6537, 7, 83, 20172, 30, 900, 16, 7608, 12461), + (12461, 6537, 6537, 6537, 6537, 8, 83, 20173, 30, 900, 16, 12460, 12462), + (12462, 6537, 6537, 6537, 6537, 9, 83, 20174, 30, 900, 16, 12461, 12520), + (12463, -1, -1, 5263, 5263, 7, 81, -1, 0, 0, 16, 6129, 12464), + (12464, -1, -1, 5263, 5263, 8, 81, -1, 0, 0, 16, 12463, 12465), + (12465, -1, -1, 5263, 5263, 9, 81, -1, 0, 0, 16, 12464, 16173), + (12466, -1, -1, 5263, 5263, 7, 81, -1, 0, 0, 16, 5622, 12467), + (12467, -1, -1, 5263, 5263, 9, 81, -1, 0, 0, 16, 12466, 12468), + (12468, -1, -1, 5263, 5263, 12, 81, -1, 0, 0, 16, 12467, 15714), + (12469, -1, -1, 1287, 1287, 7, 81, -1, 0, 0, 16, 5518, 12470), + (12470, -1, -1, 1287, 1287, 9, 81, -1, 0, 0, 16, 12469, 12471), + (12471, -1, -1, 1287, 1287, 12, 81, -1, 0, 0, 16, 12470, 10637), + (12472, -1, -1, 1287, 1287, 8, 81, -1, 0, 0, 16, 6430, 12473), + (12473, -1, -1, 1287, 1287, 9, 81, -1, 0, 0, 16, 12472, 12474), + (12474, -1, -1, 1287, 1287, 10, 81, -1, 0, 0, 16, 12473, 13238), + (12475, -1, -1, 12430, 12430, 5, 85, 0, 0, 0, 16, -1, 12476), + (12476, -1, -1, 12430, 12430, 7, 85, 0, 0, 0, 16, 12475, 12477), + (12477, -1, -1, 12430, 12430, 9, 85, 0, 0, 0, 16, 12476, 12876), + (12478, -1, -1, 12478, 12478, 5, 85, 0, 0, 0, 16, -1, 12479), + (12479, -1, -1, 12478, 12478, 7, 85, 0, 0, 0, 16, 12478, 12480), + (12480, -1, -1, 12478, 12478, 9, 85, 0, 0, 0, 16, 12479, -1), + (12481, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 6473, 12482), + (12482, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 12481, 12508), + (12483, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 6475, 12484), + (12484, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 12483, 12511), + (12485, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 6477, 12486), + (12486, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 12485, 12514), + (12487, -1, -1, 6540, 6540, 8, 83, -1, 0, 0, 16, 6471, 12488), + (12488, -1, -1, 6540, 6540, 8, 85, -1, 0, 0, 16, 12487, 12517), + (12492, -1, -1, 6119, 6119, 6, 85, -1, 0, 0, 17, 12410, 12493), + (12493, -1, -1, 6119, 6119, 6, 86, -1, 0, 0, 17, 12492, 12494), + (12494, -1, -1, 6119, 6119, 6, 87, -1, 0, 0, 17, 12493, 12495), + (12495, -1, -1, 6119, 6119, 6, 88, -1, 0, 0, 17, 12494, 12496), + (12496, -1, -1, 6119, 6119, 6, 89, -1, 0, 0, 17, 12495, 8448), + (12497, -1, -1, 77, 77, 12, 86, -1, 0, 0, 17, 12451, 12498), + (12498, -1, -1, 77, 77, 12, 88, -1, 0, 0, 17, 12497, 12499), + (12499, -1, -1, 77, 77, 12, 90, -1, 0, 0, 17, 12498, 13296), + (12500, -1, -1, 12500, 12500, 5, 81, -1, 0, 0, 16, -1, 12501), + (12501, -1, -1, 12500, 12500, 7, 81, -1, 0, 0, 16, 12500, 12502), + (12502, -1, -1, 12500, 12500, 9, 81, -1, 0, 0, 16, 12501, 12505), + (12505, -1, -1, 12500, 12500, 11, 83, -1, 0, 0, 16, 12502, 12506), + (12506, -1, -1, 12500, 12500, 12, 85, -1, 0, 0, 16, 12505, -1), + (12507, -1, -1, 199, 199, 12, 81, -1, 0, 0, 16, 201, -1), + (12508, -1, -1, 6540, 6540, 8, 86, -1, 0, 0, 17, 12482, 12509), + (12509, -1, -1, 6540, 6540, 8, 88, -1, 0, 0, 17, 12508, 12510), + (12510, -1, -1, 6540, 6540, 8, 90, -1, 0, 0, 17, 12509, 16440), + (12511, -1, -1, 6540, 6540, 8, 86, -1, 0, 0, 17, 12484, 12512), + (12512, -1, -1, 6540, 6540, 8, 88, -1, 0, 0, 17, 12511, 12513), + (12513, -1, -1, 6540, 6540, 8, 90, -1, 0, 0, 17, 12512, 12591), + (12514, -1, -1, 6540, 6540, 8, 86, -1, 0, 0, 17, 12486, 12515), + (12515, -1, -1, 6540, 6540, 8, 88, -1, 0, 0, 17, 12514, 12516), + (12516, -1, -1, 6540, 6540, 8, 90, -1, 0, 0, 17, 12515, 12594), + (12517, -1, -1, 6540, 6540, 8, 86, -1, 0, 0, 17, 12488, 12518), + (12518, -1, -1, 6540, 6540, 8, 88, -1, 0, 0, 17, 12517, 12519), + (12519, -1, -1, 6540, 6540, 8, 90, -1, 0, 0, 17, 12518, 12597), + (12520, 6537, 6537, 6537, 6537, 7, 86, 23974, 30, 900, 17, 12462, 12521), + (12521, 6537, 6537, 6537, 6537, 8, 88, 23975, 30, 900, 17, 12520, 12522), + (12522, 6537, 6537, 6537, 6537, 9, 90, 23976, 30, 900, 17, 12521, 13275), + (12523, -1, -1, 1210, 1210, 7, 86, -1, 0, 0, 17, 7234, 12524), + (12526, -1, -1, 1210, 1213, 12, 86, -1, 0, 0, 17, 8346, 12527), + (12527, -1, -1, 1210, 1213, 12, 88, -1, 0, 0, 17, 12526, 12528), + (12528, -1, -1, 1210, 1213, 12, 90, -1, 0, 0, 17, 12527, 14349), + (12529, -1, -1, 6636, 6636, 9, 86, -1, 0, 0, 17, 10043, 12530), + (12530, -1, -1, 6636, 6636, 10, 88, -1, 0, 0, 17, 12529, 12531), + (12531, -1, -1, 6636, 6636, 11, 90, -1, 0, 0, 17, 12530, 16164), + (12532, -1, -1, 1592, 1592, 9, 86, -1, 0, 0, 17, 12443, 12533), + (12533, -1, -1, 1592, 1592, 10, 87, -1, 0, 0, 17, 12532, 12534), + (12534, -1, -1, 1592, 1592, 11, 88, -1, 0, 0, 17, 12533, 12535), + (12535, -1, -1, 1592, 1592, 12, 89, -1, 0, 0, 17, 12534, 12536), + (12536, -1, -1, 1592, 1592, 12, 90, -1, 0, 0, 17, 12535, 13930), + (12537, -1, -1, 1072, 1072, 8, 86, -1, 0, 0, 17, 12448, 12538), + (12538, -1, -1, 1072, 1072, 9, 87, -1, 0, 0, 17, 12537, 12539), + (12539, -1, -1, 1072, 1072, 10, 88, -1, 0, 0, 17, 12538, 12540), + (12540, -1, -1, 1072, 1072, 11, 89, -1, 0, 0, 17, 12539, 12541), + (12541, -1, -1, 1072, 1072, 12, 90, -1, 0, 0, 17, 12540, 13281), + (12548, -1, -1, 119, 119, 12, 86, -1, 0, 0, 17, 6025, 12549), + (12549, -1, -1, 119, 119, 12, 87, -1, 0, 0, 17, 12548, 12550), + (12550, -1, -1, 119, 119, 12, 88, -1, 0, 0, 17, 12549, 12551), + (12551, -1, -1, 119, 119, 12, 89, -1, 0, 0, 17, 12550, 12552), + (12552, -1, -1, 119, 119, 12, 90, -1, 0, 0, 17, 12551, 13286), + (12553, -1, -1, 637, 637, 8, 86, -1, 0, 0, 17, 12437, 12554), + (12554, -1, -1, 637, 637, 10, 88, -1, 0, 0, 17, 12553, 12555), + (12555, -1, -1, 637, 637, 12, 90, -1, 0, 0, 17, 12554, 14361), + (12556, -1, -1, 1107, 1107, 10, 86, -1, 0, 0, 17, 12434, 12557), + (12557, -1, -1, 1107, 1107, 11, 88, -1, 0, 0, 17, 12556, 12558), + (12558, -1, -1, 1107, 1107, 12, 90, -1, 0, 0, 17, 12557, 16489), + (12559, -1, -1, 8215, 8215, 5, 86, -1, 0, 0, 17, 8219, 12560), + (12560, -1, -1, 8215, 8215, 5, 87, -1, 0, 0, 17, 12559, 12561), + (12561, -1, -1, 8215, 8215, 5, 88, -1, 0, 0, 17, 12560, 12562), + (12562, -1, -1, 8215, 8215, 5, 89, -1, 0, 0, 17, 12561, 12563), + (12563, -1, -1, 8215, 8215, 5, 90, -1, 0, 0, 17, 12562, 15694), + (12564, -1, -1, 1186, 1186, 12, 86, -1, 0, 0, 17, 7694, 12565), + (12565, -1, -1, 1186, 1186, 12, 88, -1, 0, 0, 17, 12564, 12566), + (12566, -1, -1, 1186, 1186, 12, 90, -1, 0, 0, 17, 12565, 13299), + (12567, -1, -1, 80, 80, 12, 86, -1, 0, 0, 17, 12454, 12568), + (12568, -1, -1, 80, 80, 12, 88, -1, 0, 0, 17, 12567, 12569), + (12569, -1, -1, 80, 80, 12, 90, -1, 0, 0, 17, 12568, 13302), + (12570, -1, -1, 658, 658, 5, 86, -1, 0, 0, 17, 12459, 12571), + (12571, -1, -1, 658, 658, 5, 87, -1, 0, 0, 17, 12570, 12572), + (12572, -1, -1, 658, 658, 5, 88, -1, 0, 0, 17, 12571, 12573), + (12573, -1, -1, 658, 658, 5, 89, -1, 0, 0, 17, 12572, 12574), + (12574, -1, -1, 658, 658, 5, 90, -1, 0, 0, 17, 12573, 13313), + (12575, -1, -1, 12419, 12419, 9, 90, -1, 0, 0, 17, 12421, 13520), + (12576, -1, -1, 852, 852, 12, 86, -1, 0, 0, 17, 7680, 12577), + (12577, -1, -1, 852, 852, 12, 88, -1, 0, 0, 17, 12576, 12578), + (12578, -1, -1, 852, 852, 12, 90, -1, 0, 0, 17, 12577, 13601), + (12579, -1, -1, 1313, 1313, 12, 86, -1, 0, 0, 17, 10083, 12580), + (12580, -1, -1, 1313, 1313, 12, 88, -1, 0, 0, 17, 12579, 12581), + (12581, -1, -1, 1313, 1313, 12, 90, -1, 0, 0, 17, 12580, 14043), + (12582, -1, -1, 12582, 12582, 7, 85, 0, 0, 0, 17, -1, 12583), + (12583, -1, -1, 12582, 12582, 9, 87, 0, 0, 0, 17, 12582, 12584), + (12584, -1, -1, 12582, 12582, 12, 89, 0, 0, 0, 17, 12583, 15174), + (12585, 6640, 6640, 6640, 6640, 9, 86, 23572, 43, 60, 17, 6640, -1), + (12586, 6644, 6644, 6644, 6644, 2, 86, 23573, 44, 20, 17, 6644, -1), + (12587, -1, -1, 7757, 7757, 9, 86, -1, 0, 0, 17, 7759, 12588), + (12588, -1, -1, 7757, 7757, 9, 88, -1, 0, 0, 17, 12587, 12589), + (12589, -1, -1, 7757, 7757, 9, 90, -1, 0, 0, 17, 12588, 15182), + (12590, 10395, 10395, 10395, 10395, 5, 85, 23574, 62, 5, 17, 10395, -1), + (12591, -1, -1, 6540, 6540, 15, 91, -1, 0, 0, 18, 12513, 12592), + (12594, -1, -1, 6540, 6540, 11, 91, -1, 0, 0, 18, 12516, 12595), + (12597, -1, -1, 6540, 6540, 9, 91, -1, 0, 0, 18, 12519, 12598), + (12598, -1, -1, 6540, 6540, 11, 93, -1, 0, 0, 18, 12597, 12599), + (12600, -1, -1, 12600, 12600, 7, 85, 0, 0, 0, 17, -1, 13072), + (12603, -1, -1, 12603, 12603, 10, 70, 0, 0, 0, 17, -1, -1), + (12606, -1, -1, 12606, 12606, 6, 85, 0, 0, 0, 17, -1, -1), + (12607, -1, -1, 12607, 12607, 6, 74, 0, 0, 0, 17, -1, 14140), + (12610, -1, -1, 255, 255, 9, 87, -1, 0, 0, 17, 7702, 13773), + (12612, -1, -1, 1604, 1604, 10, 85, -1, 0, 0, 17, 7009, 12613), + (12613, -1, -1, 1604, 1604, 12, 87, -1, 0, 0, 17, 12612, 13095), + (12615, -1, -1, 12615, 12615, 10, 85, 0, 0, 0, 17, -1, 12616), + (12616, -1, -1, 12615, 12615, 12, 87, 0, 0, 0, 17, 12615, 12617), + (12617, -1, -1, 12615, 12615, 14, 89, 0, 0, 0, 17, 12616, 14138), + (12618, 5021, 5021, 5021, 5021, 9, 86, 24009, 7, 60, 17, 10870, 12619), + (12619, 5021, 5021, 5021, 5021, 9, 87, 24010, 7, 60, 17, 12618, 12620), + (12620, 5021, 5021, 5021, 5021, 9, 88, 24011, 7, 60, 17, 12619, 12621), + (12621, 5021, 5021, 5021, 5021, 9, 89, 24012, 7, 60, 17, 12620, 13785), + (12626, 9354, 9354, 9354, 9354, 5, 86, 23996, 40, 600, 17, 9356, -1), + (12629, 9357, 9357, 9357, 9357, 5, 86, 24002, 40, 600, 17, 9359, -1), + (12632, 9360, 9360, 9360, 9360, 5, 86, 24005, 40, 600, 17, 9362, -1), + (12633, 6325, 6325, 6325, 6325, 7, 85, 24008, 18, 600, 17, 6361, 13792), + (12635, 12635, 12635, 12635, 12635, 12, 90, 23643, 12, 5, 17, -1, -1), + (12636, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, -1, 12637), + (12637, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 12636, 8445), + (12638, 12638, 12638, 12638, 12638, 9, 85, 23581, 68, 10, 17, -1, -1), + (12639, -1, -1, 10514, 10514, 6, 86, -1, 0, 0, 17, 10515, 12640), + (12642, -1, -1, 10511, 10511, 6, 86, -1, 0, 0, 17, 10513, 12643), + (12645, -1, -1, 12645, 12645, 9, 90, 0, 0, 0, 17, -1, 15386), + (12646, -1, -1, 12646, 12646, 9, 90, 0, 0, 0, 17, -1, 15388), + (12647, 10502, -1, 10502, 10502, 7, 90, 16815, 64, 120, 17, 10502, -1), + (12648, 10503, 10503, 10503, 10503, 9, 86, 23582, 13, 600, 17, 10505, 12649), + (12651, 12651, 12651, 12651, 12651, 15, 90, 23585, 69, 600, 17, -1, 17352), + (12652, -1, -1, 12652, 12652, 9, 86, 0, 0, 0, 17, -1, 12653), + (12653, -1, -1, 12652, 12652, 12, 88, 0, 0, 0, 17, 12652, 12654), + (12654, -1, -1, 12652, 12652, 15, 90, 0, 0, 0, 17, 12653, 13411), + (12655, 12655, 12655, 12655, 12655, 9, 86, 23586, 70, 1800, 17, -1, 12656), + (12658, 757, -1, 757, 757, 12, 86, 23589, 6, 1800, 17, 7413, 12659), + (12661, 12661, 12661, 12661, 12661, 9, 86, 23592, 73, 2700, 17, -1, 12662), + (12664, -1, -1, 12664, 12664, 7, 86, 0, 0, 0, 17, -1, 12665), + (12667, -1, -1, 820, 820, 5, 86, -1, 0, 0, 17, 10662, 12668), + (12668, -1, -1, 820, 820, 5, 88, -1, 0, 0, 17, 12667, 12669), + (12669, -1, -1, 820, 820, 5, 90, -1, 0, 0, 17, 12668, 13820), + (12670, -1, -1, 6020, 6020, 2, 86, -1, 0, 0, 17, 10665, 12671), + (12671, -1, -1, 6020, 6020, 2, 87, -1, 0, 0, 17, 12670, 12672), + (12672, -1, -1, 6020, 6020, 2, 88, -1, 0, 0, 17, 12671, 12692), + (12673, -1, -1, 1546, 1546, 5, 80, -1, 0, 0, 17, 6441, -1), + (12674, -1, -1, 4801, 4801, 6, 86, -1, 0, 0, 17, 10123, 12675), + (12675, -1, -1, 4801, 4801, 6, 88, -1, 0, 0, 17, 12674, 12676), + (12676, -1, -1, 4801, 4801, 6, 90, -1, 0, 0, 17, 12675, -1), + (12677, -1, -1, 230, 230, 6, 90, -1, 0, 0, 17, 541, 16249), + (12678, -1, -1, 10656, 10656, 12, 90, 0, 0, 0, 17, 10656, -1), + (12679, -1, -1, 10657, 10657, 7, 86, 0, 0, 0, 17, 10659, 12680), + (12680, -1, -1, 10657, 10657, 9, 88, 0, 0, 0, 17, 12679, 12681), + (12681, -1, -1, 10657, 10657, 12, 90, 0, 0, 0, 17, 12680, 14154), + (12682, 7872, 7872, 7872, 7872, 6, 86, 23595, 41, 600, 17, 10129, 12683), + (12683, 7872, 7872, 7872, 7872, 6, 88, 23596, 41, 600, 17, 12682, 12684), + (12684, 7872, 7872, 7872, 7872, 6, 90, 23597, 41, 600, 17, 12683, 13838), + (12685, -1, -1, 807, 807, 5, 86, -1, 0, 0, 17, 7630, 12686), + (12686, -1, -1, 807, 807, 5, 88, -1, 0, 0, 17, 12685, 12687), + (12687, -1, -1, 807, 807, 5, 90, -1, 0, 0, 17, 12686, -1), + (12688, -1, -1, 12688, 12688, 12, 90, 0, 0, 0, 17, -1, -1), + (12689, -1, -1, 7884, 7884, 12, 87, -1, 0, 0, 17, 7884, -1), + (12690, -1, -1, 7885, 7885, 12, 86, -1, 0, 0, 17, 7885, -1), + (12691, -1, -1, 12691, 12691, 12, 88, 0, 0, 0, 17, -1, -1), + (12692, -1, -1, 6020, 6020, 2, 89, -1, 0, 0, 17, 12672, 12693), + (12693, -1, -1, 6020, 6020, 2, 90, -1, 0, 0, 17, 12692, 13823), + (12694, -1, -1, 683, 683, 5, 86, -1, 0, 0, 17, 7605, 12695), + (12695, -1, -1, 683, 683, 5, 88, -1, 0, 0, 17, 12694, 12696), + (12696, -1, -1, 683, 683, 5, 90, -1, 0, 0, 17, 12695, 13305), + (12697, -1, -1, 1041, 1041, 12, 86, -1, 0, 0, 17, 7564, 12698), + (12698, -1, -1, 1041, 1041, 12, 88, -1, 0, 0, 17, 12697, 12699), + (12699, -1, -1, 1041, 1041, 12, 90, -1, 0, 0, 17, 12698, 13332), + (12700, 1355, 1355, 1355, 1355, 9, 86, 23644, 3, 60, 17, 10121, 12701), + (12701, 1355, 1355, 1355, 1355, 9, 88, 23645, 3, 60, 17, 12700, 12702), + (12702, 1355, 1355, 1355, 1355, 9, 90, 23646, 3, 60, 17, 12701, 13832), + (12703, -1, -1, 611, 611, 4, 86, -1, 0, 0, 17, 10126, 12704), + (12704, -1, -1, 611, 611, 4, 88, -1, 0, 0, 17, 12703, 12705), + (12705, -1, -1, 611, 611, 4, 90, -1, 0, 0, 17, 12704, 13835), + (12706, -1, -1, 12706, 12706, 7, 86, 0, 0, 0, 17, -1, 12707), + (12707, -1, -1, 12706, 12706, 9, 88, 0, 0, 0, 17, 12706, 12708), + (12708, -1, -1, 12706, 12706, 12, 90, 0, 0, 0, 17, 12707, 13813), + (12709, -1, -1, 12709, 12709, 9, 86, -1, 0, 0, 17, -1, -1), + (12710, -1, -1, 12710, 12710, 9, 86, 0, 0, 0, 17, -1, 12711), + (12711, -1, -1, 12710, 12710, 12, 88, 0, 0, 0, 17, 12710, 12712), + (12712, -1, -1, 12710, 12710, 15, 90, 0, 0, 0, 17, 12711, 14173), + (12713, -1, -1, 12713, 12713, 7, 86, 0, 0, 0, 17, -1, 12714), + (12714, -1, -1, 12713, 12713, 7, 88, 0, 0, 0, 17, 12713, 12715), + (12715, -1, -1, 12713, 12713, 7, 90, 0, 0, 0, 17, 12714, -1), + (12716, -1, -1, 12716, 12716, 7, 86, 0, 0, 0, 17, -1, 12717), + (12717, -1, -1, 12716, 12716, 7, 88, 0, 0, 0, 17, 12716, 12718), + (12718, -1, -1, 12716, 12716, 7, 90, 0, 0, 0, 17, 12717, 15526), + (12719, -1, -1, 12719, 12719, 9, 90, 0, 0, 0, 17, -1, -1), + (12720, -1, -1, 12720, 12720, 9, 86, 0, 0, 0, 17, -1, -1), + (12721, -1, -1, 12721, 12721, 7, 86, 0, 0, 0, 17, -1, 12722), + (12722, -1, -1, 12721, 12721, 9, 88, 0, 0, 0, 17, 12721, 12723), + (12723, -1, -1, 12721, 12721, 12, 90, 0, 0, 0, 17, 12722, 16303), + (12724, 10333, 10333, 10333, 10333, 9, 86, 23647, 55, 120, 17, 10335, 12725), + (12725, 10333, 10333, 10333, 10333, 9, 86, 23648, 55, 120, 17, 12724, 12726), + (12726, 10333, 10333, 10333, 10333, 9, 86, 23649, 55, 120, 17, 12725, 15988), + (12727, -1, -1, 1555, 1555, 7, 86, 0, 0, 0, 17, 1557, 12728), + (12728, -1, -1, 1555, 1555, 7, 88, 0, 0, 0, 17, 12727, 12729), + (12729, -1, -1, 1555, 1555, 7, 90, 0, 0, 0, 17, 12728, -1), + (12730, 10336, 10336, 10336, 10336, 9, 86, 23650, 58, 8, 17, 10338, 12731), + (12731, 10336, 10336, 10336, 10336, 12, 88, 23651, 58, 8, 17, 12730, 12732), + (12732, 10336, 10336, 10336, 10336, 15, 90, 23652, 58, 8, 17, 12731, 13517), + (12733, -1, -1, 10332, 10332, 7, 90, -1, 0, 0, 17, 10332, -1), + (12734, -1, -1, 6375, 6375, 9, 86, -1, 0, 0, 17, 10138, 12735), + (12735, -1, -1, 6375, 6375, 9, 88, -1, 0, 0, 17, 12734, 12736), + (12736, -1, -1, 6375, 6375, 9, 90, -1, 0, 0, 17, 12735, 13502), + (12737, -1, -1, 12737, 12737, 9, 86, 0, 0, 0, 17, -1, 12738), + (12738, -1, -1, 12737, 12737, 9, 88, 0, 0, 0, 17, 12737, 12739), + (12739, -1, -1, 12737, 12737, 9, 90, 0, 0, 0, 17, 12738, 15961), + (12740, 6533, 6533, 6533, 6533, 10, 86, 23653, 15, 600, 17, 10139, 12741), + (12741, 6533, 6533, 6533, 6533, 10, 88, 23654, 15, 600, 17, 12740, 12742), + (12742, 6533, 6533, 6533, 6533, 10, 90, 23655, 15, 600, 17, 12741, 13505), + (12743, 1116, 1116, 1116, 1116, 12, 86, 23656, 4, 2160, 17, 10142, 12744), + (12744, 1116, 1116, 1116, 1116, 12, 88, 23657, 4, 2160, 17, 12743, 12745), + (12745, 1116, 1116, 1116, 1116, 12, 90, 23658, 4, 2160, 17, 12744, 13530), + (12746, 5298, 5298, 5298, 5298, 12, 86, 23659, 32, 1800, 17, 10145, 12747), + (12747, 5298, 5298, 5298, 5298, 12, 88, 23660, 32, 1800, 17, 12746, 12748), + (12748, 5298, 5298, 5298, 5298, 12, 90, 23661, 32, 1800, 17, 12747, 13514), + (12749, 592, 592, 592, 592, 5, 86, 23665, 2, 18, 17, 7437, 12750), + (12750, 592, 592, 592, 592, 5, 88, 23666, 2, 18, 17, 12749, 12751), + (12751, 592, 592, 592, 592, 5, 90, 23667, 2, 18, 17, 12750, 13499), + (12754, 10701, 10701, 10701, 10701, 12, 86, 23668, 32, 360, 17, 10703, 12755), + (12755, 10701, 10701, 10701, 10701, 12, 88, 23669, 32, 360, 17, 12754, 12756), + (12756, 10701, 10701, 10701, 10701, 12, 90, 23670, 32, 360, 17, 12755, 15588), + (12757, -1, -1, 4861, 4861, 12, 86, -1, 0, 0, 17, 7682, 12758), + (12758, -1, -1, 4861, 4861, 12, 88, -1, 0, 0, 17, 12757, 12759), + (12759, -1, -1, 4861, 4861, 12, 90, -1, 0, 0, 17, 12758, -1), + (12760, 1274, 1274, 1274, 1274, 12, 86, 23674, 9, 540, 17, 10211, 12761), + (12761, 1274, 1274, 1274, 1274, 12, 88, 23675, 9, 540, 17, 12760, 12762), + (12762, 1274, 1274, 1274, 1274, 12, 90, 23676, 9, 540, 17, 12761, 14352), + (12766, 12766, 12766, 12766, 12766, 15, 90, 23677, 69, 3600, 17, -1, 13682), + (12767, -1, -1, 692, 692, 12, 86, -1, 0, 0, 17, 7672, 12768), + (12768, -1, -1, 692, 692, 12, 88, -1, 0, 0, 17, 12767, 12769), + (12769, -1, -1, 692, 692, 12, 90, -1, 0, 0, 17, 12768, 17295), + (12770, 12770, 12770, 12770, 12770, 9, 85, 23678, 52, 120, 17, -1, 12771), + (12771, 12770, 12770, 12770, 12770, 12, 87, 23679, 52, 120, 17, 12770, 12772), + (12772, 12770, 12770, 12770, 12770, 15, 89, 23680, 52, 120, 17, 12771, -1), + (12773, -1, -1, 12773, 12773, 7, 86, 0, 0, 0, 17, -1, 12774), + (12774, -1, -1, 12773, 12773, 7, 87, 0, 0, 0, 17, 12773, 12775), + (12775, -1, -1, 12773, 12773, 7, 88, 0, 0, 0, 17, 12774, 12776), + (12776, -1, -1, 12773, 12773, 7, 89, 0, 0, 0, 17, 12775, 12777), + (12777, -1, -1, 12773, 12773, 7, 90, 0, 0, 0, 17, 12776, -1), + (12778, 12778, 12778, 12778, 12778, 12, 90, 23681, 74, 1200, 17, -1, 13678), + (12779, -1, -1, 12779, 12779, 7, 85, 0, 0, 0, 17, -1, 12780), + (12780, -1, -1, 12779, 12779, 9, 87, 0, 0, 0, 17, 12779, 12781), + (12781, -1, -1, 12779, 12779, 12, 89, 0, 0, 0, 17, 12780, -1), + (12782, -1, -1, 12782, 12782, 7, 86, 0, 0, 0, 17, -1, 12783), + (12783, -1, -1, 12782, 12782, 9, 88, 0, 0, 0, 17, 12782, 12784), + (12784, -1, -1, 12782, 12782, 12, 90, 0, 0, 0, 17, 12783, -1), + (12785, 12785, 12785, 12785, 12785, 12, 90, 23683, 80, 30, 17, -1, 17131), + (12786, 6815, 6815, 6815, 6815, 8, 86, 23684, 60, 600, 17, 10202, 12787), + (12787, 6815, 6815, 6815, 6815, 8, 88, 23685, 60, 600, 17, 12786, 12788), + (12788, 6815, 6815, 6815, 6815, 8, 90, 23686, 60, 600, 17, 12787, 14355), + (12789, 967, 967, 967, 967, 7, 85, 23687, 10, 1800, 17, 10226, 12790), + (12790, 967, 967, 967, 967, 7, 87, 23688, 10, 1800, 17, 12789, 12791), + (12791, 967, 967, 967, 967, 7, 89, 23689, 10, 1800, 17, 12790, 17535), + (12792, -1, -1, 9503, 9503, 7, 86, -1, 0, 0, 17, 10089, 12793), + (12793, -1, -1, 9503, 9503, 7, 88, -1, 0, 0, 17, 12792, 12794), + (12794, -1, -1, 9503, 9503, 7, 90, -1, 0, 0, 17, 12793, 5360), + (12795, -1, -1, 6051, 6051, 5, 85, -1, 0, 0, 17, 10606, 12796), + (12796, -1, -1, 6051, 6051, 5, 87, -1, 0, 0, 17, 12795, 12797), + (12797, -1, -1, 6051, 6051, 5, 89, -1, 0, 0, 17, 12796, 13278), + (12798, -1, -1, 5264, 5264, 12, 86, -1, 0, 0, 17, 10217, 12799), + (12799, -1, -1, 5264, 5264, 12, 88, -1, 0, 0, 17, 12798, 12800), + (12800, -1, -1, 5264, 5264, 12, 90, -1, 0, 0, 17, 12799, 13675), + (12801, -1, -1, 6383, 6383, 9, 85, -1, 0, 0, 17, 10609, 12802), + (12802, -1, -1, 6383, 6383, 9, 87, -1, 0, 0, 17, 12801, 12803), + (12803, -1, -1, 6383, 6383, 9, 89, -1, 0, 0, 17, 12802, 5339), + (12804, 12804, 12804, 12804, 12804, 7, 86, 23693, 75, 900, 17, -1, 12805), + (12807, 12807, 12807, 12807, 12807, 7, 86, 23699, 73, 1200, 17, -1, 12808), + (12810, 8227, 8227, 8227, 12810, 5, 85, 27402, 71, 10, 17, 8227, 12811), + (12811, 8227, 8227, 8227, 12810, 7, 87, 27403, 71, 10, 17, 12810, 12812), + (12812, 8227, 8227, 8227, 12810, 9, 89, 27404, 71, 10, 17, 12811, -1), + (12813, -1, -1, 1287, 1287, 5, 75, -1, 0, 0, 17, -1, 12814), + (12814, -1, -1, 1287, 1287, 5, 77, -1, 0, 0, 17, 12813, 12815), + (12815, -1, -1, 1287, 1287, 5, 79, -1, 0, 0, 17, 12814, 14279), + (12816, -1, -1, 12816, 12816, 7, 86, 0, 0, 0, 17, -1, 12817), + (12819, -1, -1, 12819, 12819, 9, 85, 0, 0, 0, 17, -1, 12820), + (12820, -1, -1, 12819, 12819, 12, 87, 0, 0, 0, 17, 12819, 12821), + (12822, -1, -1, 12822, 12822, 9, 86, 0, 0, 0, 17, -1, 12823), + (12828, 291, 291, 291, 12828, 12, 86, 27409, 5, 900, 17, 10304, 12829), + (12831, -1, -1, 12831, 12831, 7, 86, 0, 0, 0, 17, -1, 12832), + (12834, -1, -1, 6980, 6980, 5, 85, -1, 0, 0, 17, 6982, 12835), + (12835, -1, -1, 6980, 6980, 5, 87, -1, 0, 0, 17, 12834, 12836), + (12837, 12837, 12837, 12837, 12837, 7, 86, 27412, 74, 420, 17, -1, 12838), + (12840, -1, -1, 6977, 6977, 5, 85, -1, 0, 0, 17, 6979, 12841), + (12841, -1, -1, 6977, 6977, 5, 87, -1, 0, 0, 17, 12840, 12842), + (12843, -1, -1, 551, 551, 5, 86, -1, 0, 0, 17, 6907, 12844), + (12846, -1, -1, 12846, 12846, 7, 86, 6499, 0, 0, 17, -1, 12847), + (12849, -1, -1, 12849, 12849, 7, 86, 0, 0, 0, 17, -1, 12850), + (12857, 8072, 8072, 8072, 8072, 7, 86, 27419, 37, 20, 17, 10248, 12858), + (12860, -1, -1, 267, 267, 12, 86, -1, 0, 0, 17, 5619, 12861), + (12863, -1, -1, 141, 12863, 12, 59, -1, 0, 0, 17, 143, 15396), + (12864, 12864, -1, 12864, 12864, 5, 59, 27422, 73, 10, 17, -1, 17486), + (12865, 12865, 12865, 12865, 12865, 12, 90, 27423, 42, 6, 17, -1, -1), + (12866, 12866, 12866, 12866, 12866, 12, 86, 27424, 74, 1800, 17, -1, 15605), + (12867, 12867, 12867, 12867, 12867, 12, 86, 27426, 13, 4320, 17, -1, -1), + (12868, 1334, 1334, 1334, 1334, 12, 86, 27427, 11, 4320, 17, 10236, 12869), + (12871, -1, -1, 11050, 11050, 9, 85, -1, 0, 0, 17, 11060, 12872), + (12872, -1, -1, 11050, 11050, 12, 87, -1, 0, 0, 17, 12871, 12873), + (12874, -1, -1, 1414, 1414, 5, 86, -1, 0, 0, 17, 1418, 17490), + (12875, 4938, 4938, 4938, 4938, 12, 90, 27430, 35, 1800, 17, 5614, 13727), + (12876, -1, -1, 12430, 12430, 7, 86, 0, 0, 0, 17, 12477, 12877), + (12877, -1, -1, 12430, 12430, 9, 88, 0, 0, 0, 17, 12876, 12878), + (12878, -1, -1, 12430, 12430, 12, 90, 0, 0, 0, 17, 12877, 15270), + (12879, 516, 516, 516, 516, 6, 86, 27431, 5, 480, 17, 10233, 13659), + (12880, 1404, 1404, 1404, 1404, 7, 85, 27432, 15, 2160, 17, 1408, -1), + (12881, -1, -1, 12881, 12881, 9, 86, 0, 0, 0, 17, -1, 12882), + (12885, 12885, 12885, 12885, 12885, 12, 86, 27435, 75, 90, 17, -1, 17491), + (12886, -1, -1, 12886, 12886, 2, 85, -1, 0, 0, 17, -1, -1), + (12887, -1, -1, 12887, 12887, 2, 87, -1, 0, 0, 17, -1, -1), + (12888, -1, -1, 12888, 12888, 2, 89, -1, 0, 0, 17, -1, -1), + (12889, -1, -1, 12889, 12889, 2, 85, -1, 0, 0, 17, -1, 12890), + (12890, -1, -1, 12889, 12889, 2, 87, -1, 0, 0, 17, 12889, 12891), + (12892, 12892, 12892, 12892, 12892, 3, 90, 27434, 8, 60, 17, -1, 13666), + (12893, 12893, 12893, 12893, 12893, 12, 90, 27436, 76, 1800, 17, -1, 13663), + (12894, -1, -1, 12894, 12894, 5, 86, 0, 0, 0, 17, -1, 12895), + (12899, -1, -1, 471, 471, 2, 85, -1, 0, 0, 17, 473, 12900), + (12900, -1, -1, 471, 471, 2, 87, -1, 0, 0, 17, 12899, 12901), + (12902, -1, -1, 12902, 12902, 5, 85, 0, 0, 0, 17, -1, 12903), + (12903, -1, -1, 12902, 12902, 5, 86, 0, 0, 0, 17, 12902, 12904), + (12907, -1, -1, 12907, 12907, 5, 85, 0, 0, 0, 17, -1, 12908), + (12908, -1, -1, 12907, 12907, 5, 86, 0, 0, 0, 17, 12907, 12909), + (12912, -1, -1, 12912, 12912, 5, 85, 0, 0, 0, 17, -1, 12913), + (12913, -1, -1, 12912, 12912, 5, 86, 0, 0, 0, 17, 12912, 12914), + (12917, 517, 517, 517, 517, 5, 85, 27437, 12, 600, 17, 10281, 12918), + (12918, 517, 517, 517, 517, 5, 87, 27438, 12, 600, 17, 12917, 12919), + (12920, -1, -1, 12920, 12920, 5, 86, 0, 0, 0, 17, -1, 12921), + (12923, 54009, 54009, 54009, 12923, 3, 85, 27440, 22, 12, 17, 5849, 12924), + (12924, 54009, 54009, 54009, 12923, 3, 87, 27441, 22, 12, 17, 12923, 12925), + (12929, -1, -1, 6548, 6548, 8, 85, -1, 0, 0, 17, 6238, 12930), + (12930, -1, -1, 6548, 6548, 8, 90, -1, 0, 0, 17, 12929, 15463), + (12931, 12931, 12931, 12931, 12931, 7, 86, 27443, 73, 3600, 17, -1, 12932), + (12934, 1242, 1242, 1242, 1242, 12, 86, 27446, 9, 1320, 17, 10273, 12935), + (12937, 12937, 12937, 12937, 12937, 12, 86, 27449, 16, 420, 17, -1, 13733), + (12938, 12938, 12938, 12938, 12938, 15, 88, 27450, 75, 2700, 17, -1, 13743), + (12939, 12939, 12939, 12939, 12939, 12, 90, 27451, 77, 1800, 17, -1, 14756), + (12941, 12941, 12941, 12941, 12941, 5, 85, 27453, 77, 1, 17, -1, -1), + (12942, 6539, 6539, 6539, 6539, 6, 86, 27454, 18, 1800, 17, 7611, 12943), + (12943, 6539, 6539, 6539, 6539, 6, 88, 27455, 18, 1800, 17, 12942, 12944), + (12944, 6539, 6539, 6539, 6539, 6, 90, 27456, 18, 1800, 17, 12943, 13291), + (12945, -1, -1, 795, 795, 12, 85, -1, 0, 0, 17, 10267, 12946), + (12946, -1, -1, 795, 795, 12, 86, -1, 0, 0, 17, 12945, 12947), + (12947, -1, -1, 795, 795, 12, 87, -1, 0, 0, 17, 12946, 12948), + (12948, -1, -1, 795, 795, 12, 88, -1, 0, 0, 17, 12947, 12949), + (12949, -1, -1, 795, 795, 12, 89, -1, 0, 0, 17, 12948, 13710), + (12950, -1, -1, 790, 790, 6, 86, -1, 0, 0, 17, 7274, 12951), + (12951, -1, -1, 790, 790, 6, 87, -1, 0, 0, 17, 12950, 12952), + (12952, -1, -1, 790, 790, 6, 88, -1, 0, 0, 17, 12951, 12953), + (12953, -1, -1, 790, 790, 6, 89, -1, 0, 0, 17, 12952, 12954), + (12954, -1, -1, 790, 790, 6, 90, -1, 0, 0, 17, 12953, 13713), + (12955, 167, 167, 167, 167, 10, 86, 27457, 14, 900, 17, 8343, 13718), + (12956, 4903, 4903, 4903, 4903, 9, 85, 27460, 9, 1320, 17, 10255, 13698), + (12957, 4909, 4909, 4909, 4909, 9, 85, 27461, 16, 1320, 17, 10257, 14733), + (12958, 4912, 4912, 4912, 4912, 9, 85, 27459, 16, 1320, 17, 10258, 13704), + (12959, 4906, 4906, 4906, 4906, 9, 85, 27458, 9, 1320, 17, 10256, 13701), + (12963, 12963, 12963, 12963, 12963, 7, 86, 27465, 81, 5, 17, -1, -1), + (12964, 12964, 12964, 12964, 12964, 7, 88, 27466, 81, 5, 17, -1, -1), + (12965, 12965, 12965, 12965, 12965, 7, 90, 27467, 81, 5, 17, -1, -1), + (12966, -1, -1, 6112, 6112, 5, 87, -1, 0, 0, 17, 6112, 12967), + (12967, -1, -1, 6112, 6112, 5, 89, -1, 0, 0, 17, 12966, 16402), + (12968, -1, -1, 12968, 12968, 7, 85, 0, 0, 0, 17, -1, 12969), + (12969, -1, -1, 12968, 12968, 7, 87, 0, 0, 0, 17, 12968, 12970), + (12970, -1, -1, 12968, 12968, 7, 89, 0, 0, 0, 17, 12969, 14238), + (12971, 12971, 12971, 12971, 12971, 5, 86, 27471, 79, 2160, 17, -1, 12972), + (12972, 12971, 12971, 12971, 12971, 7, 87, 27472, 79, 2160, 17, 12971, 12973), + (12973, 12971, 12971, 12971, 12971, 9, 88, 27473, 79, 2160, 17, 12972, 12974), + (12974, 12971, 12971, 12971, 12971, 12, 89, 27474, 79, 2160, 17, 12973, 12975), + (12975, 12971, 12971, 12971, 12971, 15, 90, 27475, 79, 2160, 17, 12974, -1), + (12976, 7903, 7903, 7903, 7903, 6, 85, 27476, 60, 30, 17, 7903, 14734), + (12977, -1, -1, 12977, 12977, 5, 85, 0, 0, 0, 17, -1, 12978), + (12978, -1, -1, 12977, 12977, 5, 86, 0, 0, 0, 17, 12977, 12979), + (12979, -1, -1, 12977, 12977, 5, 87, 0, 0, 0, 17, 12978, 12980), + (12980, -1, -1, 12977, 12977, 5, 88, 0, 0, 0, 17, 12979, 12981), + (12981, -1, -1, 12977, 12977, 5, 89, 0, 0, 0, 17, 12980, 17334), + (12982, 10600, 10600, 10600, 10600, 7, 86, 27477, 73, 20, 17, 10602, 12983), + (12983, 10600, 10600, 10600, 10600, 7, 88, 27478, 73, 20, 17, 12982, 12984), + (12984, 10600, 10600, 10600, 10600, 7, 90, 27479, 73, 20, 17, 12983, 13720), + (12985, 520, 520, 520, 520, 12, 86, 27480, 6, 540, 17, 10254, 12986), + (12986, 520, 520, 520, 520, 12, 88, 27481, 6, 540, 17, 12985, 12987), + (12987, 520, 520, 520, 520, 12, 90, 27482, 6, 540, 17, 12986, -1), + (12988, -1, -1, 10959, 12988, 12, 90, -1, 0, 0, 17, 10962, -1), + (12989, 12989, 12989, 12989, 12989, 7, 86, 27486, 73, 1800, 17, -1, 12990), + (12990, 12989, 12989, 12989, 12989, 9, 88, 27487, 73, 1800, 17, 12989, 12991), + (12991, 12989, 12989, 12989, 12989, 12, 90, 27488, 73, 1800, 17, 12990, 5336), + (12992, 12992, 12992, 12992, 12992, 9, 86, 27489, 0, 1, 17, -1, 12993), + (12993, 12992, 12992, 12992, 12992, 12, 88, 27490, 0, 1, 17, 12992, 12994), + (12994, 12992, 12992, 12992, 12992, 15, 90, 27491, 0, 1, 17, 12993, 5350), + (12995, 6563, 6563, 6563, 6563, 12, 86, 27492, 36, 8, 17, 6281, -1), + (12996, 153, 153, 153, 153, 12, 90, 27493, 3, 2160, 17, 11081, 17333), + (12997, 1520, 1520, 1520, 1520, 9, 85, 27494, 11, 900, 17, 10192, 12998), + (12998, 1520, 1520, 1520, 1520, 9, 87, 27495, 11, 900, 17, 12997, 12999), + (12999, 1520, 1520, 1520, 1520, 9, 89, 27496, 11, 900, 17, 12998, 5333), + (13000, 10958, 10958, 10958, 10958, 15, 90, 27497, 62, 900, 17, 10958, 16214), + (13001, -1, -1, 13001, 13001, 7, 86, -1, 0, 0, 17, -1, 13002), + (13002, -1, -1, 13001, 13001, 7, 88, -1, 0, 0, 17, 13001, 13003), + (13003, -1, -1, 13001, 13001, 7, 90, -1, 0, 0, 17, 13002, 15348), + (13004, 13004, 13004, 13004, 13004, 9, 86, 27499, 78, 300, 17, -1, 15855), + (13005, -1, -1, 6703, 6703, 3, 86, -1, 0, 0, 17, 10178, 13006), + (13006, -1, -1, 6703, 6703, 3, 88, -1, 0, 0, 17, 13005, 13007), + (13007, -1, -1, 6703, 6703, 3, 90, -1, 0, 0, 17, 13006, -1), + (13008, 13008, 13008, 13008, 13008, 9, 90, 27500, 86, 300, 17, -1, -1), + (13009, 13009, 13009, 13009, 13009, 6, 86, 27501, 39, 1, 17, -1, -1), + (13010, -1, -1, 13010, 13010, 6, 85, 0, 0, 0, 17, -1, 13011), + (13011, -1, -1, 13010, 13010, 6, 87, 0, 0, 0, 17, 13010, 13012), + (13012, -1, -1, 13010, 13010, 6, 89, 0, 0, 0, 17, 13011, 14223), + (13013, -1, -1, 13013, 13013, 6, 86, 0, 0, 0, 17, -1, 13014), + (13014, -1, -1, 13013, 13013, 6, 88, 0, 0, 0, 17, 13013, 13015), + (13015, -1, -1, 13013, 13013, 6, 90, 0, 0, 0, 17, 13014, -1), + (13016, 5109, 5109, 5109, 5109, 9, 86, 27502, 0, 1, 17, 7467, 5356), + (13017, -1, -1, 13017, 13017, 9, 86, -1, 0, 0, 17, -1, 13018), + (13018, -1, -1, 13017, 13017, 12, 88, -1, 0, 0, 17, 13017, 13019), + (13019, -1, -1, 13017, 13017, 15, 90, -1, 0, 0, 17, 13018, 13396), + (13020, 13020, 13020, 13020, 13020, 12, 86, 27503, 76, 420, 17, -1, -1), + (13021, -1, -1, 11085, 11085, 12, 86, 0, 0, 0, 17, 11087, 13022), + (13023, -1, -1, 1050, 1050, 12, 86, -1, 0, 0, 17, 7658, 13024), + (13026, -1, -1, 599, 599, 12, 86, -1, 0, 0, 17, 7561, 13027), + (13027, -1, -1, 599, 599, 12, 88, -1, 0, 0, 17, 13026, 13028), + (13028, -1, -1, 599, 599, 12, 90, -1, 0, 0, 17, 13027, 13438), + (13029, -1, -1, 7818, 7818, 9, 86, 31681, 0, 0, 17, 7818, 13030), + (13032, -1, -1, 1131, 1131, 9, 85, -1, 0, 0, 17, 11084, 13033), + (13033, -1, -1, 1131, 1131, 12, 87, -1, 0, 0, 17, 13032, 13034), + (13035, -1, -1, 1134, 1134, 3, 86, -1, 0, 0, 17, 10315, 13036), + (13040, -1, -1, 4809, 4809, 5, 86, -1, 0, 0, 17, 10318, 13041), + (13043, -1, -1, 5776, 5776, 9, 86, -1, 0, 0, 17, 7198, 13044), + (13046, -1, -1, 8250, 8250, 6, 85, -1, 0, 0, 17, 8254, 13047), + (13047, -1, -1, 8250, 8250, 6, 86, -1, 0, 0, 17, 13046, 13048), + (13048, -1, -1, 8250, 8250, 6, 87, -1, 0, 0, 17, 13047, 13049), + (13049, -1, -1, 8250, 8250, 6, 88, -1, 0, 0, 17, 13048, 13050), + (13050, -1, -1, 8250, 8250, 6, 89, -1, 0, 0, 17, 13049, 13348), + (13051, -1, -1, 10404, 10404, 6, 90, -1, 0, 0, 17, 10404, -1), + (13052, -1, -1, 10401, 10401, 6, 86, -1, 0, 0, 17, 10403, 13053), + (13055, -1, -1, 13055, 13055, 6, 86, 0, 0, 0, 17, -1, 13056), + (13058, 6931, 6931, 6931, 6931, 12, 90, 27504, 41, 600, 17, 10319, 13857), + (13059, 4854, 4854, 4854, 4854, 9, 86, 27505, 8, 600, 17, 10325, 13060), + (13062, 6932, 6932, 6932, 6932, 7, 86, 27508, 42, 1200, 17, 10322, 13063), + (13065, 13065, 13065, 13065, 13065, 12, 86, 27514, 70, 90, 17, -1, -1), + (13066, 13066, 13066, 13066, 13066, 9, 85, 27516, 71, 1800, 17, -1, -1), + (13067, -1, -1, 13067, 13067, 6, 86, 0, 0, 0, 17, -1, 13068), + (13072, -1, -1, 12600, 12600, 7, 87, 0, 0, 0, 17, 12600, 13073), + (13073, -1, -1, 12600, 12600, 7, 89, 0, 0, 0, 17, 13072, 13222), + (13074, -1, -1, 1044, 1044, 9, 86, -1, 0, 0, 17, 7652, 13075), + (13075, -1, -1, 1044, 1044, 12, 88, -1, 0, 0, 17, 13074, 13076), + (13076, -1, -1, 1044, 1044, 15, 90, -1, 0, 0, 17, 13075, 13326), + (13077, -1, -1, 1047, 1047, 9, 86, -1, 0, 0, 17, 7655, 13078), + (13078, -1, -1, 1047, 1047, 12, 88, -1, 0, 0, 17, 13077, 13079), + (13080, -1, -1, 125, 125, 9, 86, -1, 0, 0, 17, 12400, 13081), + (13081, -1, -1, 125, 125, 10, 87, -1, 0, 0, 17, 13080, 13082), + (13082, -1, -1, 125, 125, 11, 88, -1, 0, 0, 17, 13081, 13083), + (13083, -1, -1, 125, 125, 12, 89, -1, 0, 0, 17, 13082, 13084), + (13084, -1, -1, 125, 125, 13, 90, -1, 0, 0, 17, 13083, 8463), + (13085, -1, -1, 122, 122, 9, 86, -1, 0, 0, 17, 12405, 13086), + (13086, -1, -1, 122, 122, 10, 87, -1, 0, 0, 17, 13085, 13087), + (13087, -1, -1, 122, 122, 11, 88, -1, 0, 0, 17, 13086, 13088), + (13088, -1, -1, 122, 122, 12, 89, -1, 0, 0, 17, 13087, 13089), + (13089, -1, -1, 122, 122, 13, 90, -1, 0, 0, 17, 13088, 8440), + (13090, -1, -1, 1435, 4773, 9, 86, -1, 0, 0, 17, 7621, 13295), + (13091, -1, -1, 1435, 4773, 9, 86, -1, 0, 0, 17, 1650, 13294), + (13092, -1, -1, 644, 644, 9, 85, -1, 0, 0, 17, 7361, 13093), + (13093, -1, -1, 644, 644, 12, 87, -1, 0, 0, 17, 13092, 13094), + (13094, -1, -1, 644, 644, 15, 89, -1, 0, 0, 17, 13093, 13265), + (13095, -1, -1, 1604, 1604, 15, 89, -1, 0, 0, 17, 12613, 13767), + (13096, -1, -1, 13096, 13096, 12, 86, -1, 0, 0, 17, -1, 13097), + (13097, -1, -1, 13096, 13096, 12, 88, -1, 0, 0, 17, 13096, 13098), + (13098, -1, -1, 13096, 13096, 12, 90, -1, 0, 0, 17, 13097, 13127), + (13099, -1, -1, 83, 83, 9, 55, -1, 0, 0, 17, 85, -1), + (13100, 13100, 13100, 13100, 13100, 9, 86, 27534, 86, 300, 17, -1, 15140), + (13101, -1, -1, 13101, 13101, 7, 86, 0, 0, 0, 17, -1, 13102), + (13102, -1, -1, 13101, 13101, 9, 88, 0, 0, 0, 17, 13101, 13103), + (13103, -1, -1, 13101, 13101, 12, 90, 0, 0, 0, 17, 13102, 14082), + (13104, -1, -1, 589, 589, 9, 86, -1, 0, 0, 17, 7709, 13105), + (13105, -1, -1, 589, 589, 9, 88, -1, 0, 0, 17, 13104, 13106), + (13106, -1, -1, 589, 589, 9, 90, -1, 0, 0, 17, 13105, 15778), + (13107, 6645, 6645, 6645, 6645, 9, 90, 27541, 45, 60, 17, 6645, 13633), + (13108, 13108, 13108, 13108, 13108, 5, 90, 27542, 89, 30, 17, -1, -1), + (13109, 1351, 1351, 1351, 1351, 8, 90, 27543, 5, 30, 17, 7109, -1), + (13110, 10815, 10815, 10815, 10815, 9, 86, -1, 0, 0, 17, 10817, 13111), + (13111, 10815, 10815, 10815, 10815, 11, 88, -1, 0, 0, 17, 13110, 13112), + (13113, 10818, 10818, 10818, 10818, 9, 86, -1, 0, 0, 17, 10820, 13114), + (13114, 10818, 10818, 10818, 10818, 11, 88, -1, 0, 0, 17, 13113, 13115), + (13116, 10821, 10821, 10821, 10821, 9, 86, -1, 0, 0, 17, 10823, 13117), + (13117, 10821, 10821, 10821, 10821, 11, 88, -1, 0, 0, 17, 13116, 13118), + (13119, 5007, 5007, 5007, 5007, 9, 86, 27544, 8, 2160, 17, 10063, 13120), + (13120, 5007, 5007, 5007, 5007, 9, 88, 27545, 8, 2160, 17, 13119, 13121), + (13122, -1, -1, 6546, 6546, 0, 86, -1, 0, 0, 17, 7377, 13123), + (13123, -1, -1, 6546, 6546, 0, 87, -1, 0, 0, 17, 13122, 13124), + (13124, -1, -1, 6546, 6546, 0, 88, -1, 0, 0, 17, 13123, 13125), + (13127, -1, -1, 13096, 13096, 12, 91, -1, 0, 0, 18, 13098, 13128), + (13130, 13130, 13130, 13130, 13130, 15, 95, 32440, 48, 30, 18, -1, -1), + (13133, 7756, 7756, 7756, 7756, 12, 85, 21805, 85, 120, 17, -1, -1), + (13134, 13134, 13134, 13134, 13134, 7, 86, 27547, 74, 900, 17, -1, 13135), + (13135, 13134, 13134, 13134, 13134, 7, 88, 27548, 74, 900, 17, 13134, 13136), + (13136, 13134, 13134, 13134, 13134, 7, 90, 27549, 74, 900, 17, 13135, 13380), + (13140, -1, -1, 10464, 10464, 7, 86, -1, 0, 0, 17, 10466, 13141), + (13141, -1, -1, 10464, 10464, 9, 88, -1, 0, 0, 17, 13140, 13142), + (13142, -1, -1, 10464, 10464, 11, 90, -1, 0, 0, 17, 13141, -1), + (13143, -1, -1, 13143, 13143, 5, 86, 0, 0, 0, 17, -1, 13144), + (13144, -1, -1, 13143, 13143, 5, 88, 0, 0, 0, 17, 13143, 13145), + (13145, -1, -1, 13143, 13143, 5, 90, 0, 0, 0, 17, 13144, -1), + (13146, -1, -1, 13146, 13146, 5, 86, 0, 0, 0, 17, -1, 13147), + (13147, -1, -1, 13146, 13146, 5, 88, 0, 0, 0, 17, 13146, 13148), + (13148, -1, -1, 13146, 13146, 5, 90, 0, 0, 0, 17, 13147, -1), + (13149, -1, -1, 8210, 8210, 5, 86, -1, 0, 0, 17, 1655, 13150), + (13150, -1, -1, 8210, 8210, 5, 87, -1, 0, 0, 17, 13149, 13151), + (13151, -1, -1, 8210, 8210, 5, 88, -1, 0, 0, 17, 13150, 13152), + (13152, -1, -1, 8210, 8210, 5, 89, -1, 0, 0, 17, 13151, 13153), + (13153, -1, -1, 8210, 8210, 5, 90, -1, 0, 0, 17, 13152, 13318), + (13154, 5105, 5105, 5105, 5105, 12, 90, 27550, 11, 600, 17, 10509, 14023), + (13155, 7986, 7986, 7986, 7986, 12, 90, 27551, 11, 600, 17, 10510, 14022), + (13158, 548, 548, 548, 548, 10, 86, 27552, 5, 900, 17, 10098, 13159), + (13161, 528, 528, 528, 528, 12, 86, 27555, 5, 720, 17, 10196, 13162), + (13162, 528, 528, 528, 528, 12, 88, 27556, 5, 720, 17, 13161, 13163), + (13163, 528, 528, 528, 528, 12, 90, 27557, 5, 720, 17, 13162, 5357), + (13164, 13164, 13164, 13164, 13164, 9, 86, 27540, 99, 180, 17, -1, -1), + (13165, 13165, 13165, 13165, 13165, 9, 86, 27559, 56, 60, 17, -1, -1), + (13166, -1, -1, 13166, 13166, 7, 86, 0, 0, 0, 17, -1, 13167), + (13167, -1, -1, 13166, 13166, 7, 88, 0, 0, 0, 17, 13166, 13168), + (13168, -1, -1, 13166, 13166, 7, 90, 0, 0, 0, 17, 13167, -1), + (13169, 13169, 13169, 13169, 13169, 9, 90, 27560, 99, 180, 17, -1, 17221), + (13170, 6380, 6380, 6380, 6380, 6, 86, 27561, 39, 120, 17, 10310, 13171), + (13173, 290, 290, 290, 290, 8, 86, 27564, 4, 720, 17, 290, 13448), + (13174, 10374, 10374, 10374, 10374, 6, 85, 27565, 63, 900, 17, 10376, 13175), + (13175, 10374, 10374, 10374, 10374, 8, 87, 27566, 63, 900, 17, 13174, 13176), + (13177, 6984, 6984, 6984, 6984, 6, 83, 27568, 60, 60, 17, 10294, 13466), + (13178, 6986, 6986, 6986, 6986, 6, 83, 27570, 60, 60, 17, 10296, 13468), + (13179, 6985, 6985, 6985, 6985, 6, 83, 27569, 60, 60, 17, 10295, 13467), + (13180, 10377, 10377, 10377, 10377, 6, 86, 16796, 64, 60, 17, 10379, 13181), + (13183, 10346, 10346, 10346, 10346, 9, 90, 27574, 46, 600, 17, 10346, 13819), + (13184, -1, -1, 10340, 10340, 9, 86, -1, 0, 0, 17, 10342, 13185), + (13185, -1, -1, 10340, 10340, 9, 88, -1, 0, 0, 17, 13184, 13186), + (13186, -1, -1, 10340, 10340, 9, 90, -1, 0, 0, 17, 13185, 13829), + (13187, -1, -1, 9512, 9512, 7, 86, -1, 0, 0, 17, 7883, 13188), + (13188, -1, -1, 9512, 9512, 7, 88, -1, 0, 0, 17, 13187, 13189), + (13189, -1, -1, 9512, 9512, 7, 90, -1, 0, 0, 17, 13188, 13826), + (13190, 1110, 1110, 1110, 1110, 6, 86, 27576, 3, 2160, 17, 10152, 13191), + (13191, 1110, 1110, 1110, 1110, 6, 88, 27577, 3, 2160, 17, 13190, 13192), + (13192, 1110, 1110, 1110, 1110, 6, 90, 27578, 3, 2160, 17, 13191, 13496), + (13193, 1598, -1, 1598, 1598, 9, 86, 27582, 6, 900, 17, 10148, 13194), + (13194, 1598, -1, 1598, 1598, 11, 88, 27583, 6, 900, 17, 13193, 13195), + (13195, 1598, -1, 1598, 1598, 13, 90, 27584, 6, 900, 17, 13194, 13493), + (13196, -1, -1, 255, 255, 9, 86, -1, 0, 0, 17, 10135, 13197), + (13197, -1, -1, 255, 255, 9, 88, -1, 0, 0, 17, 13196, 13198), + (13198, -1, -1, 255, 255, 9, 90, -1, 0, 0, 17, 13197, 13511), + (13199, -1, -1, 8322, 8322, 9, 86, 0, 0, 0, 17, 8324, 13200), + (13200, -1, -1, 8322, 8322, 9, 88, 0, 0, 0, 17, 13199, 13201), + (13201, -1, -1, 8322, 8322, 9, 90, 0, 0, 0, 17, 13200, -1), + (13202, 13202, 13202, 13202, 13202, 2, 81, 27585, 98, 20, 17, -1, 14009), + (13203, 10330, 10330, 10330, 10330, 7, 90, 27586, 35, 30, 17, 10330, 13492), + (13204, -1, -1, 13204, 13204, 7, 86, -1, 0, 0, 17, -1, 13205), + (13205, -1, -1, 13204, 13204, 7, 88, -1, 0, 0, 17, 13204, 13206), + (13206, -1, -1, 13204, 13204, 7, 90, -1, 0, 0, 17, 13205, 14176), + (13207, -1, -1, 10850, 10850, 9, 86, 27587, 0, 0, 17, 10852, 13208), + (13208, -1, -1, 10850, 10850, 9, 88, 27588, 0, 0, 17, 13207, 13209), + (13209, -1, -1, 10850, 10850, 9, 90, 27589, 0, 0, 17, 13208, 13779), + (13210, -1, -1, 1307, 1307, 5, 81, -1, 0, 0, 17, 6662, 13211), + (13211, -1, -1, 1307, 1307, 5, 83, -1, 0, 0, 17, 13210, 13212), + (13212, -1, -1, 1307, 1307, 5, 85, -1, 0, 0, 17, 13211, -1), + (13213, -1, -1, 1543, 1543, 7, 86, -1, 0, 0, 17, 10167, 13214), + (13214, -1, -1, 1543, 1543, 7, 87, -1, 0, 0, 17, 13213, 13215), + (13215, -1, -1, 1543, 1543, 7, 88, -1, 0, 0, 17, 13214, 13216), + (13216, -1, -1, 1543, 1543, 7, 89, -1, 0, 0, 17, 13215, 13217), + (13217, -1, -1, 1543, 1543, 7, 90, -1, 0, 0, 17, 13216, 13782), + (13218, -1, -1, 1304, 1304, 12, 90, -1, 0, 0, 17, 10867, 13789), + (13219, -1, -1, 8325, 8325, 7, 85, 0, 0, 0, 17, 8327, 13220), + (13220, -1, -1, 8325, 8325, 9, 87, 0, 0, 0, 17, 13219, 13221), + (13221, -1, -1, 8325, 8325, 11, 89, 0, 0, 0, 17, 13220, 13798), + (13222, -1, -1, 12600, 12600, 7, 89, 0, 0, 0, 17, 13073, 13223), + (13223, -1, -1, 12600, 12600, 7, 89, 0, 0, 0, 17, 13222, -1), + (13224, 13224, -1, 13224, 13224, 3, 86, 27590, 98, 1, 17, -1, 15559), + (13225, 13225, 13225, 13225, 13225, 6, 86, 27592, 0, 4, 17, -1, 13688), + (13226, -1, -1, 5295, 5295, 6, 86, -1, 0, 0, 17, 10229, 13227), + (13229, 6290, 6290, 6290, 6290, 9, 86, 27596, 0, 1, 17, 11066, 13230), + (13232, 4944, -1, 4944, 4944, 9, 86, 27602, 0, 1, 17, 11069, 13233), + (13235, 1478, -1, 1478, 1478, 9, 86, 27608, 0, 1, 17, 11072, 13236), + (13238, -1, -1, 1287, 1287, 9, 86, -1, 0, 0, 17, 12474, 13239), + (13239, -1, -1, 1287, 1287, 10, 88, -1, 0, 0, 17, 13238, 13240), + (13240, -1, -1, 1287, 1287, 11, 90, -1, 0, 0, 17, 13239, 15719), + (13241, 4931, 4931, 4931, 4931, 7, 86, 27614, 4, 600, 17, 10430, 13242), + (13244, 1501, 1501, 1501, 1501, 6, 86, 27617, 10, 4320, 17, 1560, 13245), + (13247, 4894, 4894, 4894, 4894, 6, 86, 27620, 7, 2160, 17, 7290, 13248), + (13250, 10550, 10550, 10550, 10550, 7, 90, 27626, 61, 120, 17, 10550, 13728), + (13251, 1239, 1239, 1239, 1239, 9, 90, 27627, 6, 600, 17, 7275, 13732), + (13252, 13252, 13252, 13252, 13252, 9, 86, 27629, 95, 4, 17, -1, 16065), + (13253, 1126, 1126, 1126, 1126, 7, 85, 27630, 2, 2160, 17, 5515, 13254), + (13254, 1126, 1126, 1126, 1126, 7, 87, 27631, 2, 2160, 17, 13253, 13255), + (13255, 1126, 1126, 1126, 1126, 7, 89, 27632, 2, 2160, 17, 13254, 13723), + (13256, 146, 146, 146, 146, 8, 86, 27633, 2, 180, 17, 7691, 13257), + (13257, 146, 146, 146, 146, 8, 88, 27634, 2, 180, 17, 13256, 13258), + (13258, 146, 146, 146, 146, 8, 90, 27635, 2, 180, 17, 13257, 14222), + (13259, 1195, 1195, 1195, 1195, 9, 90, 27661, 13, 2160, 17, 10015, 15334), + (13260, 13260, 13260, 13260, 13260, 0, 80, 27664, 98, 3600, 17, -1, -1), + (13261, 13261, 13261, 13261, 13261, 0, 81, 27665, 98, 28800, 17, -1, -1), + (13262, -1, -1, 498, 498, 5, 70, -1, 0, 0, 16, 975, 13263), + (13263, -1, -1, 498, 498, 5, 75, -1, 0, 0, 16, 13262, 13264), + (13264, -1, -1, 498, 498, 5, 80, -1, 0, 0, 16, 13263, -1), + (13271, 13271, 13271, 13271, 13271, 0, 80, 27691, 97, 3600, 18, -1, -1), + (13272, 13272, 13272, 13272, 13272, 0, 81, 27692, 97, 28800, 18, -1, -1), + (13275, 6537, 6537, 6537, 6537, 10, 91, 30638, 30, 900, 18, 12522, 13276), + (13278, -1, -1, 6051, 6051, 10, 91, -1, 0, 0, 18, 12797, 13279), + (13281, -1, -1, 1072, 1072, 12, 91, -1, 0, 0, 18, 12541, 13282), + (13286, -1, -1, 119, 119, 12, 91, -1, 0, 0, 18, 12552, 13287), + (13291, 6539, 6539, 6539, 6539, 9, 91, 30641, 18, 1800, 18, 12944, 13292), + (13294, -1, -1, 1435, 4773, 12, 91, -1, 0, 0, 18, 13091, 14490), + (13295, -1, -1, 1435, 4773, 12, 91, -1, 0, 0, 18, 13090, 14491), + (13296, -1, -1, 77, 77, 12, 91, -1, 0, 0, 18, 12499, 13297), + (13297, -1, -1, 77, 77, 12, 93, -1, 0, 0, 18, 13296, 13298), + (13299, -1, -1, 1186, 1186, 12, 91, -1, 0, 0, 18, 12566, 13300), + (13302, -1, -1, 80, 80, 12, 91, -1, 0, 0, 18, 12569, 13303), + (13305, -1, -1, 683, 683, 10, 91, -1, 0, 0, 18, 12696, 13306), + (13308, -1, -1, 446, 735, 10, 91, -1, 0, 0, 18, 10477, 13309), + (13313, -1, -1, 658, 658, 8, 91, -1, 0, 0, 18, 12574, 13314), + (13318, -1, -1, 8210, 8210, 10, 91, -1, 0, 0, 18, 13153, 13319), + (13323, -1, -1, 1287, 1287, 12, 91, -1, 0, 0, 18, 10639, 13324), + (13326, -1, -1, 1044, 1044, 10, 91, -1, 0, 0, 18, 13076, 13327), + (13332, -1, -1, 1041, 1041, 11, 91, -1, 0, 0, 18, 12699, 13333), + (13338, -1, -1, 8245, 8245, 11, 91, -1, 0, 0, 18, 8426, 13339), + (13343, -1, -1, 8240, 8240, 11, 91, -1, 0, 0, 18, 10785, 13344), + (13348, -1, -1, 8250, 8250, 11, 91, -1, 0, 0, 18, 13050, 13349), + (13353, -1, -1, 8235, 8235, 11, 91, -1, 0, 0, 18, 8308, 13354), + (13358, -1, -1, 8255, 8255, 11, 91, -1, 0, 0, 18, 12415, 13359), + (13363, 1192, 1192, 1192, 1192, 9, 91, 30645, 12, 1320, 18, 10021, 13364), + (13383, 6488, 6488, 6488, 6488, 15, 91, 30657, 32, 900, 18, 6488, 13384), + (13385, 13385, 13385, 13385, 13385, 12, 91, 30659, 75, 600, 18, -1, 13386), + (13388, 13388, 13388, 13388, 13388, 12, 91, 30665, 79, 180, 18, -1, -1), + (13389, 13389, -1, 13389, 13389, 5, 91, 30666, 77, 12, 18, -1, 15832), + (13396, -1, -1, 13017, 13017, 15, 91, -1, 0, 0, 18, 13019, 13397), + (13401, 1498, 1498, 1498, 1498, 15, 91, 30679, 12, 1320, 18, 10092, 13402), + (13404, -1, -1, 1514, 1514, 11, 91, -1, 0, 0, 18, 1516, 13405), + (13410, 645, -1, 645, 645, 15, 95, 30682, 4, 5, 18, 10739, -1), + (13411, -1, -1, 12652, 12652, 15, 92, 0, 0, 0, 18, 12654, 13412), + (13413, -1, -1, 12416, 12416, 15, 91, -1, 0, 0, 18, 12418, 13414), + (13415, -1, -1, 7989, 7989, 9, 95, -1, 0, 0, 18, 7992, -1), + (13416, -1, -1, 13416, 13416, 9, 91, 0, 0, 0, 18, -1, 13417), + (13419, 13419, 13419, 13419, 13419, 12, 91, 30683, 99, 600, 18, -1, 13420), + (13425, 54006, 54006, 54006, 54006, 9, 91, 30692, 18, 180, 18, 10006, 13426), + (13438, -1, -1, 599, 599, 13, 91, -1, 0, 0, 18, 13028, 13439), + (13444, 13444, 13444, 13444, 13444, 9, 91, 30699, 75, 600, 18, -1, 13445), + (13447, 11073, 11073, 11073, 11073, 12, 95, 30705, 53, 30, 18, 11073, 15412), + (13449, -1, -1, 13449, 13449, 5, 91, -1, 0, 0, 18, -1, 13450), + (13454, 718, 718, 718, 718, 12, 91, 30711, 7, 4320, 18, 1019, 14855), + (13463, -1, -1, 13463, 13463, 7, 91, -1, 0, 0, 18, -1, 13464), + (13466, 6984, 6984, 6984, 6984, 9, 91, 30721, 60, 60, 18, 13177, 13469), + (13467, 6985, 6985, 6985, 6985, 9, 91, 30723, 60, 60, 18, 13179, 13470), + (13468, 6986, 6986, 6986, 6986, 12, 92, 30725, 60, 60, 18, 13178, 13471), + (13472, 11080, 11080, 11080, 11080, 11, 91, 30727, 10, 20, 18, 11080, 13473), + (13474, -1, -1, 13474, 13474, 9, 91, -1, 0, 0, 18, -1, 13475), + (13477, -1, -1, 10380, 10380, 11, 91, -1, 0, 0, 18, 10382, 13478), + (13483, 13483, 13483, 13483, 13483, 5, 91, 30735, 68, 20, 18, -1, -1), + (13484, 13484, -1, 13484, 13484, 12, 95, 30736, 76, 720, 18, -1, 15879), + (13485, -1, -1, 13485, 13485, 7, 91, -1, 0, 0, 18, -1, 13486), + (13490, 5020, 5020, 5020, 5020, 9, 91, 30742, 9, 300, 18, 10149, 13491), + (13492, 10330, 10330, 10330, 10330, 12, 95, 30744, 35, 30, 18, 13203, 14797), + (13493, 1598, -1, 1598, 1598, 11, 91, 30745, 6, 900, 18, 13195, 13494), + (13496, 1110, 1110, 1110, 1110, 9, 91, 30748, 3, 2160, 18, 13192, 13497), + (13499, 592, 592, 592, 592, 9, 91, 30754, 2, 18, 18, 12751, 13500), + (13502, -1, -1, 6375, 6375, 9, 91, -1, 0, 0, 18, 12736, 13503), + (13505, 6533, 6533, 6533, 6533, 11, 91, 30757, 15, 600, 18, 12742, 13506), + (13508, -1, -1, 8314, 8314, 9, 91, -1, 0, 0, 18, 8316, 13509), + (13511, -1, -1, 255, 255, 9, 91, -1, 0, 0, 18, 13198, 13512), + (13514, 5298, 5298, 5298, 5298, 12, 91, 30760, 32, 1800, 18, 12748, 13515), + (13517, 10336, 10336, 10336, 10336, 11, 91, 30766, 58, 8, 18, 12732, 13518), + (13520, -1, -1, 12419, 12419, 15, 95, -1, 0, 0, 18, 12575, 16886), + (13521, -1, -1, 6386, 6386, 9, 91, -1, 0, 0, 18, 6389, 13522), + (13524, 6534, 6534, 6534, 6534, 11, 91, 30769, 16, 900, 18, 7429, 13525), + (13527, 13527, 13527, 13527, 13527, 9, 91, 30772, 18, 9, 18, -1, 15964), + (13528, 13528, 13528, 13528, 13528, 10, 91, 30773, 42, 60, 18, -1, -1), + (13529, 13529, 13529, 13529, 13529, 15, 95, 30774, 41, 120, 18, -1, -1), + (13530, 1116, 1116, 1116, 1116, 12, 91, 30775, 4, 2160, 18, 12745, 13531), + (13533, -1, -1, 7010, 7010, 9, 91, -1, 0, 0, 18, 7015, 13534), + (13542, 6755, 6755, 6755, 6755, 12, 91, 30784, 42, 900, 18, 6757, 13543), + (13545, -1, -1, 10388, 10388, 12, 95, -1, 0, 0, 18, 10388, 15293), + (13546, 6758, 6758, 6758, 6758, 11, 91, 32360, 43, 900, 18, 10056, 13547), + (13549, 13549, 13549, 13549, 13549, 15, 95, 30788, 64, 180, 18, -1, -1), + (13556, 13556, 13556, 13556, 13556, 9, 91, 30792, 44, 600, 18, -1, 13557), + (13562, -1, -1, 10719, 10719, 15, 91, 0, 0, 0, 18, 10721, 13563), + (13565, -1, -1, 13565, 13565, 11, 91, 0, 0, 0, 18, -1, 13566), + (13568, -1, -1, 13568, 13568, 11, 91, 0, 0, 0, 18, -1, 13569), + (13571, 13571, 13571, 13571, 13571, 12, 91, 30795, 50, 60, 18, -1, -1), + (13575, 5095, 5095, 5095, 5095, 11, 91, 30796, 10, 900, 18, 10642, 13576), + (13578, 0, 0, 10348, 10348, 9, 91, -1, 0, 0, 18, 10350, 13579), + (13584, 10394, 10394, 10394, 10394, 15, 91, 30799, 30, 300, 18, 10704, 14981), + (13585, 7712, 7712, 7712, 7712, 15, 95, 30800, 2, 30, 18, 10646, 15095), + (13586, 188, 188, 188, 188, 12, 91, 30801, 2, 30, 18, 10647, 13587), + (13589, -1, -1, 255, 255, 13, 91, -1, 0, 0, 18, 10625, 13590), + (13590, -1, -1, 255, 255, 15, 93, -1, 0, 0, 18, 13589, 13591), + (13592, 5984, 5984, 5984, 5984, 12, 91, 30803, 2, 30, 18, 10626, 13593), + (13595, 534, 534, 534, 534, 12, 91, 30806, 4, 2160, 18, 10710, 13596), + (13598, -1, -1, 6791, 6791, 11, 91, -1, 0, 0, 18, 10678, 13599), + (13601, -1, -1, 852, 852, 11, 91, -1, 0, 0, 18, 12578, 13602), + (13604, 7850, 7850, 7850, 7850, 15, 91, 30812, 39, 4320, 18, 10620, 13605), + (13607, -1, -1, 10453, 10453, 11, 91, -1, 0, 0, 18, 10455, 13608), + (13610, -1, -1, 602, 602, 12, 91, -1, 0, 0, 18, 10687, 13611), + (13613, -1, -1, 855, 855, 11, 91, -1, 0, 0, 18, 10692, 13614), + (13616, -1, -1, 13616, 13616, 7, 91, -1, 0, 0, 18, -1, 13617), + (13617, -1, -1, 13616, 13616, 9, 93, -1, 0, 0, 18, 13616, 13618), + (13618, -1, -1, 13616, 13616, 12, 95, -1, 0, 0, 18, 13617, 14786), + (13619, 7800, 7800, 7800, 7800, 15, 91, 30815, 39, 4320, 18, 10787, 13620), + (13621, -1, -1, 6630, 6630, 9, 91, -1, 0, 0, 18, 10074, 13622), + (13624, 10900, 10900, 10900, 10900, 9, 91, 30817, 55, 120, 18, 10902, 13625), + (13627, -1, -1, 895, 895, 9, 91, -1, 0, 0, 18, 10908, 13628), + (13628, -1, -1, 895, 895, 12, 93, -1, 0, 0, 18, 13627, 13629), + (13630, -1, -1, 9506, 9506, 11, 91, -1, 0, 0, 18, 9508, 13631), + (13633, 6645, 6645, 6645, 6645, 15, 95, 30820, 45, 60, 18, 13107, 15178), + (13646, 13646, 13646, 13646, 13646, 15, 91, 30837, 45, 600, 18, -1, -1), + (13650, 8060, 8060, 8060, 8060, 9, 91, 31524, 41, 1800, 18, 10239, 13651), + (13653, 8063, 8063, 8063, 8063, 9, 91, 31527, 41, 1800, 18, 10242, 13654), + (13656, 8066, 8066, 8066, 8066, 11, 91, 31530, 41, 1800, 18, 10245, 13657), + (13663, 12893, 12893, 12893, 12893, 15, 91, 31534, 76, 1800, 18, 12893, 13664), + (13667, -1, -1, 13667, 13667, 11, 91, -1, 0, 0, 18, -1, 13668), + (13670, 13670, 13670, 13670, 13670, 12, 91, 31538, 43, 1800, 18, -1, 13671), + (13673, 13673, 13673, 13673, 13673, 18, 95, 32050, 0, 1, 18, -1, -1), + (13674, 13674, 13674, 13674, 13674, 18, 95, 32058, 0, 1, 18, -1, -1), + (13675, -1, -1, 5264, 5264, 12, 91, -1, 0, 0, 18, 12800, 13676), + (13678, 13678, 13678, 13678, 13678, 15, 95, 31543, 74, 1200, 18, 12778, -1), + (13682, 12766, 12766, 12766, 12766, 18, 95, 31545, 69, 3600, 18, 12766, -1), + (13683, 6822, 6822, 6822, 6822, 15, 91, 31546, 42, 120, 18, 6822, 14780), + (13684, -1, -1, 13684, 13684, 9, 91, -1, 0, 0, 18, -1, 13685), + (13685, -1, -1, 13684, 13684, 12, 93, -1, 0, 0, 18, 13684, 13686), + (13686, -1, -1, 13684, 13684, 15, 95, -1, 0, 0, 18, 13685, 16653), + (13687, 13687, 13687, 13687, 13687, 15, 91, 31547, 75, 300, 18, -1, 17521), + (13688, 13225, 13225, 13225, 13225, 12, 91, 31548, 0, 4, 18, 13225, 15620), + (13689, -1, -1, 13689, 13689, 9, 91, -1, 0, 0, 18, -1, 13690), + (13692, 12208, 12208, 12208, 12208, 6, 91, 31549, 17, 12, 18, -1, -1), + (13693, 13693, 13693, 13693, 13693, 18, 95, 31550, 76, 500, 18, -1, 17531), + (13695, 13695, 13695, 13695, 13695, 12, 91, 31577, 91, 1320, 18, -1, 13696), + (13698, 4903, 4903, 4903, 4903, 12, 91, 31580, 9, 1320, 18, 12956, 13699), + (13701, 4906, 4906, 4906, 4906, 12, 91, 31583, 9, 1320, 18, 12959, 13702), + (13704, 4912, 4912, 4912, 4912, 12, 91, 31586, 16, 1320, 18, 12958, 13705), + (13707, -1, -1, 1577, 1577, 12, 91, -1, 0, 0, 18, 10264, 13708), + (13710, -1, -1, 795, 795, 9, 91, -1, 0, 0, 18, 12949, 13711), + (13713, -1, -1, 790, 790, 6, 91, -1, 0, 0, 18, 12954, 13714), + (13718, 167, 167, 167, 167, 12, 91, 31589, 14, 900, 18, 12955, 13719), + (13720, 10600, 10600, 10600, 10600, 11, 91, 31591, 73, 20, 18, 12984, 13721), + (13723, 1126, 1126, 1126, 1126, 11, 91, 31594, 2, 2160, 18, 13255, 13724), + (13726, 1017, 1017, 1017, 1017, 12, 91, 31597, 75, 15, 18, 1017, -1), + (13727, 4938, 4938, 4938, 4938, 12, 95, 31598, 35, 1800, 18, 12875, 16031), + (13734, 773, -1, 773, 773, 9, 91, 31606, 5, 1800, 18, 10566, 13735), + (13753, -1, -1, 13753, 13753, 5, 91, -1, 0, 0, 18, -1, 13754), + (13758, -1, -1, 13758, 13758, 5, 91, -1, 0, 0, 18, -1, 13759), + (13763, -1, -1, 781, 781, 12, 95, -1, 0, 0, 18, 7284, -1), + (13764, -1, -1, 13764, 13764, 9, 91, -1, 0, 0, 18, -1, 13765), + (13767, -1, -1, 1604, 1604, 12, 91, -1, 0, 0, 18, 13095, 13768), + (13770, 6328, 6328, 6328, 6328, 9, 91, 31628, 10, 600, 18, 10170, 13771), + (13771, 6328, 6328, 6328, 6328, 12, 93, 31629, 10, 600, 18, 13770, 13772), + (13773, -1, -1, 255, 255, 11, 91, -1, 0, 0, 18, 12610, 13774), + (13774, -1, -1, 255, 255, 13, 92, -1, 0, 0, 18, 13773, 13775), + (13775, -1, -1, 255, 255, 15, 93, -1, 0, 0, 18, 13774, 14126), + (13779, -1, -1, 10850, 10850, 12, 91, 31637, 0, 0, 18, 13209, 13780), + (13782, -1, -1, 1543, 1543, 9, 91, -1, 0, 0, 18, 13217, 13783), + (13785, 5021, 5021, 5021, 5021, 11, 91, 31640, 7, 60, 18, 12621, 13786), + (13788, 13788, 13788, 13788, 13788, 25, 51, 31643, 31, 2, 3, -1, -1), + (13789, -1, -1, 1304, 1304, 11, 91, -1, 0, 0, 18, 13218, 13790), + (13790, -1, -1, 1304, 1304, 13, 93, -1, 0, 0, 18, 13789, 13791), + (13792, 13792, 13792, 13792, 13792, 9, 91, 31644, 18, 600, 18, 12633, 13793), + (13795, -1, -1, 846, 846, 12, 91, -1, 0, 0, 18, 10175, 13796), + (13798, -1, -1, 8325, 8325, 9, 91, -1, 0, 0, 18, 13221, 13799), + (13804, -1, -1, 10650, 10650, 9, 91, -1, 0, 0, 18, 10652, 13805), + (13807, 1352, 1352, 1352, 1352, 9, 91, 31647, 3, 60, 18, 10115, 13808), + (13810, 1358, 1358, 1358, 1358, 9, 91, 31650, 3, 60, 18, 10118, 13811), + (13813, -1, -1, 12706, 12706, 12, 91, 0, 0, 0, 18, 12708, 13814), + (13816, 7875, 7875, 7875, 7875, 9, 91, 31653, 42, 600, 18, 7880, 13817), + (13819, 10346, 10346, 10346, 10346, 12, 95, 31659, 46, 600, 18, 13183, 16924), + (13820, -1, -1, 820, 820, 9, 91, -1, 0, 0, 18, 12669, 13821), + (13823, -1, -1, 6020, 6020, 9, 91, -1, 0, 0, 18, 12693, 13824), + (13826, -1, -1, 9512, 9512, 9, 91, -1, 0, 0, 18, 13189, 13827), + (13829, -1, -1, 10340, 10340, 12, 91, -1, 0, 0, 18, 13186, 13830), + (13832, 1355, 1355, 1355, 1355, 11, 91, 31661, 3, 60, 18, 12702, 13833), + (13835, -1, -1, 611, 611, 9, 91, -1, 0, 0, 18, 12705, 13836), + (13838, 7872, 7872, 7872, 7872, 9, 91, 31664, 41, 600, 18, 12684, 13839), + (13841, -1, -1, 10343, 10343, 9, 91, 0, 0, 0, 18, 10345, 13842), + (13845, 1178, 1178, 1178, 1178, 9, 91, 31669, 4, 900, 18, 10328, 13846), + (13872, 13872, 13872, 13872, 13872, 15, 95, 31694, 63, 60, 18, -1, 16002), + (13873, -1, -1, 13873, 13873, 7, 91, 0, 0, 0, 18, -1, 13874), + (13878, -1, -1, 13878, 13878, 9, 91, 0, 0, 0, 18, -1, 13879), + (13881, -1, -1, 13881, 13881, 9, 91, 0, 0, 0, 18, -1, 13882), + (13884, -1, -1, 735, 735, 10, 91, -1, 0, 0, 18, 10636, 13885), + (13889, -1, -1, 13889, 13889, 5, 91, 0, 0, 0, 18, -1, 13890), + (13894, -1, -1, 1021, 1021, 6, 91, -1, 0, 0, 18, 7685, 13895), + (13899, 6750, 6750, 6750, 6750, 15, 95, 32100, 60, 120, 18, 6750, 15294), + (13905, -1, -1, 13905, 13905, 10, 91, -1, 0, 0, 18, -1, 13906), + (13908, -1, -1, 13908, 13908, 10, 91, -1, 0, 0, 18, -1, 13909), + (13911, -1, -1, 13911, 13911, 12, 91, -1, 0, 0, 18, -1, 13912), + (13914, 4849, 4849, 4849, 4849, 12, 91, 32103, 7, 1800, 18, 7110, 13915), + (13917, -1, -1, 13917, 13917, 9, 91, -1, 0, 0, 18, -1, 13918), + (13920, 6333, 6333, 6333, 6333, 15, 91, 32140, 3, 600, 18, 7266, 16032), + (13921, -1, -1, 98, 98, 12, 91, -1, 0, 0, 18, 11063, 13922), + (13924, -1, -1, 98, 738, 12, 91, -1, 0, 0, 18, 7600, 13925), + (13927, -1, -1, 10370, 10370, 10, 91, -1, 0, 0, 18, 10372, 13928), + (13930, -1, -1, 1592, 1592, 12, 91, -1, 0, 0, 18, 12536, 13931), + (13933, -1, -1, 8263, 8263, 5, 91, -1, 0, 0, 18, 8360, 13934), + (13943, -1, -1, 8268, 8268, 5, 91, -1, 0, 0, 18, 8370, 13944), + (13953, -1, -1, 8273, 8273, 5, 91, -1, 0, 0, 18, 8380, 13954), + (13963, -1, -1, 8278, 8278, 5, 91, -1, 0, 0, 18, 8390, 13964), + (13973, -1, -1, 8283, 8283, 5, 91, -1, 0, 0, 18, 8400, 13974), + (13983, -1, -1, 8288, 8288, 5, 91, -1, 0, 0, 18, 8410, 13984), + (13993, -1, -1, 8293, 8293, 5, 91, -1, 0, 0, 18, 8420, 13994), + (14003, 6492, 6492, 6492, 6492, 12, 91, 32151, 52, 720, 18, 10681, 14004), + (14006, 10711, 10711, 10711, 10711, 15, 91, 32157, 75, 1200, 18, 10713, 14007), + (14009, 13202, 13202, 13202, 13202, 6, 91, 32160, 98, 20, 18, 13202, -1), + (14010, 14010, 14010, 14010, 14010, 15, 95, 32161, 97, 20, 18, -1, -1), + (14011, -1, -1, 14011, 14011, 5, 91, -1, 0, 0, 18, -1, 14012), + (14016, 10354, 10354, 10354, 10354, 15, 95, 32162, 39, 4320, 18, 10354, 14647), + (14017, -1, -1, 14017, 14017, 0, 90, -1, 0, 0, 18, -1, -1), + (14018, -1, -1, 14018, 14018, 0, 91, -1, 0, 0, 18, -1, -1), + (14019, 14019, 14019, 14019, 14019, 12, 91, 32177, 14, 900, 18, -1, 14020), + (14026, -1, -1, 14026, 14026, 12, 91, -1, 0, 0, 18, -1, 14027), + (14029, -1, -1, 14029, 14029, 12, 91, -1, 0, 0, 18, -1, 14030), + (14032, -1, -1, 14032, 14032, 15, 95, -1, 0, 0, 18, -1, -1), + (14037, -1, -1, 14037, 14037, 9, 91, 0, 0, 0, 18, -1, 14038), + (14040, -1, -1, 14040, 14040, 9, 91, 0, 0, 0, 18, -1, 14041), + (14043, -1, -1, 1313, 1313, 12, 91, -1, 0, 0, 18, 12581, 14044), + (14046, -1, -1, 14046, 14046, 5, 91, -1, 0, 0, 18, -1, 14047), + (14051, 14051, 14051, 14051, 14051, 12, 95, 32300, 62, 8, 18, -1, 15774), + (14052, 14052, 14052, 14052, 14052, 21, 95, 32301, 13, 1440, 18, -1, 14793), + (14053, 10912, 10912, 10912, 10912, 9, 91, 32303, 69, 1800, 18, 10914, 14054), + (14054, 10912, 10912, 10912, 10912, 12, 93, 32304, 69, 1800, 18, 14053, 14055), + (14055, 10912, 10912, 10912, 10912, 15, 95, 32305, 69, 1800, 18, 14054, -1), + (14056, -1, -1, 14056, 14056, 9, 91, -1, 0, 0, 18, -1, 14057), + (14059, -1, -1, 14059, 14059, 9, 91, -1, 0, 0, 18, -1, 14060), + (14062, -1, -1, 14062, 14062, 9, 91, -1, 0, 0, 18, -1, 14063), + (14065, -1, -1, 14065, 14065, 9, 91, 0, 0, 0, 18, -1, 14066), + (14068, -1, -1, 14068, 14068, 9, 91, 0, 0, 0, 18, -1, 14069), + (14071, 14071, 14071, 14071, 14071, 9, 91, 32307, 12, 600, 18, -1, 14072), + (14076, -1, -1, 14076, 14076, 9, 91, -1, 0, 0, 18, -1, 14077), + (14080, 14080, 14080, 14080, 14080, 9, 95, 32312, 13, 900, 18, -1, -1), + (14081, 14081, 14081, 14081, 14081, 9, 95, 32313, 14, 120, 18, -1, 17240), + (14082, -1, -1, 13101, 13101, 9, 91, 0, 0, 0, 18, 13103, 14083), + (14085, -1, -1, 14085, 14085, 9, 91, -1, 0, 0, 18, -1, 14086), + (14088, -1, -1, 14088, 14088, 9, 91, -1, 0, 0, 18, -1, 14089), + (14091, -1, -1, 14091, 14091, 9, 91, -1, 0, 0, 18, -1, 14092), + (14094, -1, -1, 10355, 10355, 9, 91, -1, 0, 0, 18, 10645, 14095), + (14097, -1, -1, 6395, 6395, 12, 91, -1, 0, 0, 18, 10707, 14098), + (14100, -1, -1, 14100, 14100, 15, 95, -1, 0, 0, 18, -1, -1), + (14101, -1, -1, 6355, 6355, 9, 91, -1, 0, 0, 18, 6360, 14263), + (14111, 6754, 6754, 6754, 6754, 12, 95, 32326, 41, 1200, 18, 10053, 14839), + (14112, 6370, 6370, 6370, 6370, 9, 91, 32329, 7, 600, 18, 7352, 14113), + (14115, -1, -1, 14115, 14115, 12, 91, -1, 0, 0, 18, -1, 14116), + (14129, -1, -1, 14129, 14129, 12, 91, -1, 0, 0, 18, -1, 14130), + (14130, -1, -1, 14129, 14129, 15, 93, -1, 0, 0, 18, 14129, 14131), + (14132, -1, -1, 7751, 7751, 7, 91, -1, 0, 0, 18, 7753, 14133), + (14135, -1, -1, 14135, 14135, 12, 91, -1, 0, 0, 18, -1, 14136), + (14138, -1, -1, 12615, 12615, 18, 95, -1, 0, 0, 18, 12617, 15499), + (14139, 14139, 14139, 14139, 14139, 15, 95, 32328, 60, 60, 18, -1, -1), + (14140, -1, -1, 12607, 12607, 15, 95, 0, 0, 0, 18, 12607, 15631), + (14141, -1, -1, 14141, 14141, 9, 91, -1, 0, 0, 18, -1, 14142), + (14144, -1, -1, 14144, 14144, 7, 91, -1, 0, 0, 18, -1, 14145), + (14148, -1, -1, 14148, 14148, 9, 91, 0, 0, 0, 18, -1, 14149), + (14151, -1, -1, 14151, 14151, 9, 91, 0, 0, 0, 18, -1, 14152), + (14154, -1, -1, 10657, 10657, 12, 91, 0, 0, 0, 18, 12681, 14155), + (14157, -1, -1, 14157, 14157, 9, 91, 0, 0, 0, 18, -1, 14158), + (14160, -1, -1, 14160, 14160, 9, 91, 0, 0, 0, 18, -1, 14161), + (14163, -1, -1, 14163, 14163, 9, 91, 0, 0, 0, 18, -1, 14164), + (14166, -1, -1, 14166, 14166, 9, 91, 0, 0, 0, 18, -1, 14167), + (14169, -1, -1, 14169, 14169, 7, 91, -1, 0, 0, 18, -1, 14170), + (14173, -1, -1, 12710, 12710, 9, 91, -1, 0, 0, 18, 12712, 14174), + (14176, -1, -1, 13204, 13204, 9, 91, -1, 0, 0, 18, 13206, 14177), + (14179, -1, -1, 14179, 14179, 9, 95, -1, 0, 0, 18, -1, -1), + (14180, -1, -1, 14180, 14180, 9, 95, -1, 0, 0, 18, -1, -1), + (14181, -1, -1, 14181, 14181, 9, 91, -1, 0, 0, 18, -1, 14182), + (14186, -1, -1, 14186, 14186, 9, 91, -1, 0, 0, 18, -1, 14187), + (14189, 5017, 5017, 5017, 5017, 9, 91, 32332, 8, 600, 18, 10158, 14190), + (14192, 14192, 14192, 14192, 14192, 15, 95, 32335, 36, 12, 18, -1, 15525), + (14196, -1, -1, 6935, 6935, 9, 91, -1, 0, 0, 18, 6904, 14197), + (14199, -1, -1, 6908, 6908, 12, 95, -1, 0, 0, 18, 6910, 15560), + (14200, -1, -1, 14200, 14200, 9, 91, 32336, 0, 0, 18, -1, 14201), + (14203, -1, -1, 14203, 14203, 12, 91, -1, 0, 0, 18, -1, 14204), + (14206, 14206, 14206, 14206, 14206, 12, 95, 32339, 41, 600, 18, -1, 15324), + (14207, 14207, 14207, 14207, 14207, 12, 95, 32340, 39, 180, 18, -1, -1), + (14208, 14208, 14208, 14208, 14208, 12, 95, 32341, 17, 180, 18, -1, 14568), + (14209, 14209, 14209, 14209, 14209, 12, 95, 32342, 22, 3, 18, -1, -1), + (14210, -1, -1, 10358, 10358, 12, 91, -1, 0, 0, 18, 10360, 14211), + (14213, -1, -1, 14213, 14213, 11, 91, -1, 0, 0, 18, -1, 14214), + (14218, -1, -1, 962, 962, 9, 91, -1, 0, 0, 18, 10363, 14219), + (14221, 1383, 1383, 1383, 1383, 18, 95, 32345, 6, 300, 18, 6487, 14581), + (14222, 146, 146, 146, 146, 15, 95, 32346, 2, 180, 18, 13258, 14977), + (14223, -1, -1, 13010, 13010, 12, 95, 0, 0, 0, 18, 13012, 16205), + (14224, 14224, -1, 14224, 14224, 9, 91, 345, 61, 5, 18, -1, 15860), + (14225, -1, -1, 14225, 14225, 9, 91, -1, 0, 0, 18, -1, 14226), + (14229, 14229, 14229, 14229, 14229, 12, 100, 37168, 42, 600, 19, -1, -1), + (14231, 14231, 14231, 14231, 14231, 12, 95, 32347, 91, 6, 18, -1, 16207), + (14232, 14232, -1, 14232, 14232, 12, 95, 32348, 92, 6, 18, -1, 14674), + (14233, 14233, 14233, 14233, 14233, 15, 95, 32349, 93, 30, 18, -1, 15621), + (14234, 14234, 14234, 14234, 14234, 9, 91, 32350, 94, 1800, 18, -1, 14235), + (14237, 12638, 12638, 12638, 12638, 9, 91, 23581, 68, 10, 18, -1, -1), + (14238, -1, -1, 12968, 12968, 9, 91, 0, 0, 0, 18, 12970, 14239), + (14241, -1, -1, 14241, 14241, 9, 91, -1, 0, 0, 18, -1, 14242), + (14244, -1, -1, 14244, 14244, 9, 91, -1, 0, 0, 18, -1, 14245), + (14249, -1, -1, 14249, 14249, 9, 91, -1, 0, 0, 18, -1, 14250), + (14254, -1, -1, 14254, 14254, 11, 91, -1, 0, 0, 18, -1, 14255), + (14256, 6561, 6561, 6561, 6561, 9, 91, 32353, 32, 30, 18, 10420, 14257), + (14259, -1, -1, 14259, 14259, 11, 91, -1, 0, 0, 18, -1, 14260), + (14262, 14262, 14262, 14262, 14262, 15, 95, 32357, 95, 180, 18, -1, -1), + (14264, 14264, 14264, 14264, 14264, 12, 95, 32358, 97, 120, 18, -1, 14600), + (14265, 14265, 14265, 14265, 14265, 15, 95, 32359, 68, 30, 18, -1, -1), + (14272, 6218, 6218, 6218, 14272, 12, 95, 32369, 0, 1, 18, 7488, 17381), + (14273, 723, 723, 723, 723, 12, 95, 32370, 6, 30, 18, 10300, 14869), + (14274, 6971, 6971, 6971, 6971, 9, 91, 32371, 41, 600, 18, 10290, 17383), + (14275, -1, -1, 14275, 14275, 7, 91, -1, 0, 0, 18, -1, 14276), + (14278, -1, -1, 14278, 14278, 12, 95, 0, 0, 0, 18, 6990, 16248), + (14279, -1, -1, 1287, 1287, 11, 95, -1, 0, 0, 18, 12815, 16529), + (14280, 4890, -1, 4890, 4890, 12, 95, 32373, 3, 8640, 18, 5872, 14776), + (14281, 14281, 14281, 14281, 14281, 12, 95, 32375, 39, 15, 18, -1, -1), + (14282, 14282, 14282, 14282, 14282, 9, 91, 32374, 39, 7, 18, -1, -1), + (14283, -1, -1, 14283, 14283, 7, 91, -1, 0, 0, 18, -1, 14284), + (14286, -1, -1, 14286, 14286, 9, 91, -1, 0, 0, 18, -1, 14287), + (14289, -1, -1, 14289, 14289, 9, 91, -1, 0, 0, 18, -1, 14290), + (14292, -1, -1, 14292, 14292, 9, 91, -1, 0, 0, 18, -1, 14293), + (14295, -1, -1, 14295, 14295, 9, 95, -1, 0, 0, 18, -1, 14296), + (14301, -1, -1, 14301, 14301, 9, 91, -1, 0, 0, 18, -1, 14302), + (14304, -1, -1, 14304, 14304, 9, 91, -1, 0, 0, 18, -1, 14305), + (14307, 14307, 14307, 14307, 14307, 12, 95, 32376, 92, 1200, 18, -1, 14743), + (14308, -1, -1, 14308, 14308, 9, 91, -1, 0, 0, 18, -1, 14309), + (14311, -1, -1, 14311, 14311, 9, 91, -1, 0, 0, 18, -1, 14312), + (14314, -1, -1, 7715, 7715, 7, 91, -1, 0, 0, 18, 7717, 14315), + (14318, -1, -1, 14318, 14318, 9, 91, -1, 0, 0, 18, -1, 14319), + (14321, 14321, 14321, 14321, 14321, 12, 95, 32378, 92, 8, 18, -1, 14781), + (14322, 14322, 14322, 14322, 14322, 12, 95, 32379, 94, 2160, 18, -1, 14782), + (14323, 14323, 14323, 14323, 14323, 12, 95, 32380, 92, 150, 18, -1, -1), + (14324, 155, 155, 155, 155, 15, 95, 32381, 8, 60, 18, 7238, 15610), + (14328, -1, -1, 7822, 7822, 7, 91, -1, 0, 0, 18, 7826, 14329), + (14331, -1, -1, 14331, 14331, 9, 91, -1, 0, 0, 18, -1, 14332), + (14338, 1337, 1337, 1337, 1337, 12, 91, 32382, 13, 4320, 18, 6160, 14339), + (14341, -1, -1, 14341, 14341, 5, 91, -1, 0, 0, 18, -1, 14342), + (14346, 14346, 14346, 14346, 14346, 9, 91, 32385, 94, 12, 18, -1, 14347), + (14349, -1, -1, 1210, 1213, 12, 91, -1, 0, 0, 18, 12528, 14350), + (14352, 1274, 1274, 1274, 1274, 12, 91, 32391, 9, 540, 18, 12762, 14353), + (14355, 6815, 6815, 6815, 6815, 9, 91, 32394, 60, 600, 18, 12788, 14356), + (14358, 14358, -1, 14358, 14358, 15, 95, 32397, 98, 300, 18, -1, -1), + (14359, 14359, 14359, 14359, 14359, 15, 95, 32399, 93, 1200, 18, -1, -1), + (14360, 14360, 14360, 14360, 14360, 15, 95, 32400, 95, 1800, 18, -1, 16334), + (14361, -1, -1, 637, 637, 12, 91, -1, 0, 0, 18, 12555, 14362), + (14364, -1, -1, 14364, 14364, 9, 91, -1, 0, 0, 18, -1, 14365), + (14367, -1, -1, 14367, 14367, 0, 1, -1, 0, 0, 0, -1, 14368), + (14371, 14371, 14371, 14371, 14371, 0, 1, 32910, 0, 10, 0, -1, -1), + (14372, 13844, 13844, 13844, 13844, 6, 95, 31667, 47, 6, 18, -1, -1), + (14373, 14373, 14373, 14373, 14373, 0, 85, 33106, 87, 3600, 19, -1, -1), + (14374, 14374, 14374, 14374, 14374, 0, 86, 33107, 88, 28800, 19, -1, -1), + (14690, 14690, 14690, 14690, 14690, 15, 96, 37014, 45, 600, 19, -1, 17479), + (14729, 8342, 8342, 8342, 8342, 15, 100, 33909, 54, 240, 19, 8342, 17501), + (14730, 616, 616, 616, 616, 12, 96, 33910, 7, 900, 19, 10261, 14731), + (14733, 4909, 4909, 4909, 4909, 18, 100, 33913, 16, 1320, 19, 12957, 17147), + (14734, 7903, 7903, 7903, 7903, 12, 100, 33914, 60, 30, 19, 12976, 15853), + (14739, 1462, 1462, 1462, 1462, 18, 99, 33919, 5, 300, 19, 4902, 16054), + (14764, -1, -1, 10551, 10551, 12, 96, -1, 0, 0, 19, 10553, 14765), + (14991, 926, 926, 926, 926, 5, 85, 11071, 12, 1800, 17, 930, 14992), + (14992, 926, 926, 926, 926, 5, 86, 11072, 12, 1800, 17, 14991, 14993), + (15073, 15073, -1, 15073, 15073, 0, 1, 37668, 90, 60, 19, -1, -1), + (15074, -1, -1, 15074, 15074, 0, 1, -1, 0, 0, 19, -1, 15075), + (15096, 15096, 15096, 15096, 15096, 5, 96, 38151, 35, 30, 19, -1, 15097), + (15099, 15099, 15099, 15099, 15099, 12, 100, 37187, 15, 45, 19, -1, 16566), + (15100, -1, -1, 15100, 15100, 5, 96, -1, 0, 0, 19, -1, 15101), + (15105, -1, -1, 15105, 15105, 11, 96, -1, 0, 0, 19, -1, 15106), + (15108, -1, -1, 15108, 15108, 9, 98, -1, 0, 0, 19, -1, 15109), + (15111, 8300, 8300, 8300, 8300, 11, 97, 37189, 8, 900, 19, 8302, 15112), + (15113, -1, -1, 15113, 15113, 11, 96, -1, 0, 0, 19, -1, 15114), + (15119, 15119, 15119, 15119, 15119, 12, 100, 37194, 16, 1200, 19, -1, 15749), + (15120, -1, -1, 15120, 15120, 9, 96, -1, 0, 0, 19, -1, 15121), + (15123, -1, -1, 15123, 15123, 9, 96, -1, 0, 0, 19, -1, 15124), + (15126, -1, -1, 15126, 15126, 9, 96, -1, 0, 0, 19, -1, 15127), + (15129, 15129, 15129, 15129, 15129, 12, 100, 37196, 32, 180, 19, -1, 15736), + (15130, 15130, 15130, 15130, 15130, 12, 100, 37197, 32, 180, 19, -1, 15737), + (15131, 15131, 15131, 15131, 15131, 12, 100, 37198, 32, 180, 19, -1, 15738), + (15132, -1, -1, 15132, 15132, 9, 96, -1, 0, 0, 19, -1, 15133), + (15135, -1, -1, 15135, 15135, 9, 100, -1, 0, 0, 19, -1, -1), + (15136, 15136, 15136, 15136, 15136, 9, 96, 38001, 5, 120, 19, -1, 17241), + (15140, 13100, 13100, 13100, 13100, 11, 100, 38002, 86, 300, 19, 13100, -1), + (15141, -1, -1, 190, 190, 9, 96, -1, 0, 0, 19, 5040, 15142), + (15146, 15146, 15146, 15146, 15146, 13, 100, 38006, 95, 9, 19, -1, 15758), + (15147, 15147, 15147, 15147, 15147, 11, 96, 38007, 8, 1200, 19, -1, 15148), + (15150, -1, -1, 15150, 15150, 7, 96, -1, 0, 0, 19, -1, 15151), + (15153, -1, -1, 15153, 15153, 11, 100, -1, 0, 0, 19, -1, -1), + (15154, -1, -1, 15154, 15154, 9, 96, -1, 0, 0, 19, -1, -1), + (15155, -1, -1, 15155, 15155, 5, 96, -1, 0, 0, 19, -1, 15156), + (15158, -1, -1, 15158, 15158, 13, 100, -1, 0, 0, 19, -1, -1), + (15159, -1, -1, 15159, 15159, 7, 96, -1, 0, 0, 19, -1, 15160), + (15162, -1, -1, 15162, 15162, 7, 96, -1, 0, 0, 19, -1, 15163), + (15168, -1, -1, 15168, 15168, 9, 96, -1, 0, 0, 19, -1, 15169), + (15172, -1, -1, 210, 210, 12, 100, -1, 0, 0, 19, 7401, 16658), + (15173, 6639, 6639, 6639, 6639, 9, 100, 38012, 42, 300, 19, 6639, 15788), + (15174, -1, -1, 12582, 12582, 9, 96, -1, 0, 0, 19, 12584, 15175), + (15177, 15177, 15177, 15177, 15177, 9, 100, 38013, 94, 180, 19, -1, -1), + (15179, -1, -1, 15179, 15179, 7, 96, -1, 0, 0, 19, -1, 15180), + (15182, -1, -1, 7757, 7757, 5, 96, -1, 0, 0, 19, 12589, 15183), + (15188, -1, -1, 1528, 4819, 5, 96, -1, 0, 0, 19, 4823, 15189), + (15193, 15193, 15193, 15193, 15193, 15, 100, 38016, 92, 600, 19, -1, -1), + (15194, -1, -1, 15194, 15194, 9, 100, -1, 0, 0, 19, -1, -1), + (15200, 15200, 15200, 15200, 15200, 9, 96, 38304, 32, 1080, 19, -1, 15201), + (15203, 15203, 15203, 15203, 15203, 15, 100, 38307, 34, 480, 19, -1, -1), + (15204, -1, -1, 15204, 15204, 9, 96, -1, 0, 0, 19, -1, 15205), + (15207, -1, -1, 15207, 15207, 9, 96, -1, 0, 0, 19, -1, 15208), + (15210, 15210, 15210, 15210, 15210, 9, 96, 38308, 12, 120, 19, -1, 15211), + (15213, 15213, 15213, 15213, 15213, 15, 100, 38312, 42, 1080, 19, -1, 17509), + (15214, 15214, 15214, 15214, 15214, 9, 96, 38313, 43, 1800, 19, -1, 15215), + (15217, -1, -1, 15217, 15217, 11, 96, -1, 0, 0, 19, -1, 15218), + (15220, -1, -1, 15220, 15220, 9, 100, -1, 0, 0, 19, -1, 15221), + (15223, -1, -1, 15223, 15223, 9, 100, -1, 0, 0, 19, -1, 15224), + (15226, -1, -1, 15226, 15226, 9, 100, -1, 0, 0, 19, -1, 15227), + (15229, -1, -1, 15229, 15229, 9, 100, -1, 0, 0, 19, -1, 15230), + (15232, -1, -1, 15232, 15232, 9, 96, -1, 0, 0, 19, -1, 15233), + (15235, 785, 785, 785, 785, 9, 96, 38325, 8, 900, 19, 789, 15236), + (15238, -1, -1, 5276, 5276, 11, 96, -1, 0, 0, 19, 5278, 15239), + (15241, 168, 168, 168, 168, 11, 96, 38329, 4, 10, 19, 170, 15242), + (15244, 171, 171, 171, 171, 11, 96, 38333, 4, 10, 19, 173, 15245), + (15247, 174, 174, 174, 174, 11, 96, 38336, 4, 10, 19, 176, 15248), + (15250, 177, 177, 177, 177, 11, 96, 38340, 4, 10, 19, 179, 15251), + (15253, -1, -1, 15253, 15253, 4, 96, -1, 0, 0, 19, -1, 15254), + (15258, -1, -1, 7743, 7743, 11, 100, -1, 0, 0, 19, 10718, -1), + (15270, -1, -1, 12430, 12430, 15, 100, -1, 0, 0, 19, 12878, -1), + (15280, -1, -1, 10722, 10722, 9, 96, -1, 0, 0, 19, 10726, 15281), + (15283, -1, -1, 15283, 15283, 5, 96, -1, 0, 0, 19, -1, 15284), + (15288, -1, -1, 15288, 15288, 7, 96, -1, 0, 0, 19, -1, 15289), + (15295, -1, -1, 15295, 15295, 7, 96, -1, 0, 0, 19, -1, 15296), + (15298, 10806, 10806, 10806, 10806, 9, 96, 38025, 71, 540, 19, 10808, 15299), + (15301, 10809, 10809, 10809, 10809, 9, 96, 38028, 71, 540, 19, 10811, 15302), + (15304, 15304, 15304, 15304, 15304, 12, 100, 38031, 91, 360, 19, -1, -1), + (15314, 0, 0, 6481, 6481, 11, 96, -1, 0, 0, 19, 6483, 15315), + (15317, -1, -1, 15317, 15317, 9, 96, -1, 0, 0, 19, 5012, 15318), + (15320, -1, -1, 7940, 7940, 11, 100, -1, 0, 0, 19, 6486, -1), + (15321, 746, 746, 746, 746, 9, 96, 38033, 10, 2160, 19, 10024, 15322), + (15328, -1, -1, 7948, 7948, 9, 96, -1, 0, 0, 19, 10037, 15329), + (15338, 15338, 15338, 15338, 15338, 9, 96, 38054, 30, 600, 19, -1, 15339), + (15341, 136, -1, 136, 136, 7, 100, 38057, 7, 1800, 19, 136, -1), + (15342, -1, -1, 15341, 15341, 7, 100, -1, 0, 0, 19, -1, -1), + (15343, 15343, 15343, 15343, 15343, 12, 100, 38058, 21, 300, 19, -1, -1), + (15344, -1, -1, 2400, 2400, 12, 97, -1, 0, 0, 19, 2402, 15345), + (15348, -1, -1, 13001, 13001, 7, 96, -1, 0, 0, 19, 13003, 15349), + (15356, -1, -1, 15356, 15356, 15, 100, -1, 0, 0, 19, -1, 15851), + (15357, 15357, 15357, 15357, 15357, 9, 96, 38062, 95, 2, 19, -1, -1), + (15358, -1, -1, 15358, 15358, 12, 100, -1, 0, 0, 19, -1, -1), + (15359, -1, -1, 474, 474, 5, 96, -1, 0, 0, 19, 476, 15360), + (15362, 15362, 15362, 15362, 15362, 15, 100, 38063, 89, 20, 19, -1, -1), + (15363, -1, -1, 10951, 10951, 12, 97, -1, 0, 0, 19, 10953, 15364), + (15371, -1, -1, 15371, 15371, 7, 96, -1, 0, 0, 19, -1, 15372), + (15374, -1, -1, 15374, 15374, 9, 96, -1, 0, 0, 19, -1, 15375), + (15377, 15377, 15377, 15377, 15377, 15, 100, 38070, 75, 420, 19, -1, 15852), + (15383, -1, -1, 15383, 15383, 9, 96, -1, 0, 0, 19, -1, 15384), + (15389, -1, -1, 15389, 15389, 9, 96, -1, 0, 0, 19, -1, 15390), + (15396, -1, -1, 141, 12863, 12, 100, -1, 0, 0, 19, 12863, -1), + (15397, -1, -1, 6346, 6346, 9, 96, -1, 0, 0, 19, 7617, 15398), + (15403, -1, -1, 15403, 15403, 7, 96, -1, 0, 0, 19, -1, 15404), + (15406, -1, -1, 15406, 15406, 7, 96, -1, 0, 0, 19, -1, 15407), + (15414, -1, -1, 15414, 15414, 9, 100, -1, 0, 0, 19, -1, -1), + (15421, -1, -1, 6538, 6538, 12, 100, -1, 0, 0, 19, 7478, -1), + (15422, -1, -1, 83, 83, 12, 100, -1, 0, 0, 19, 1218, -1), + (15423, 15423, 15423, 15423, 15423, 15, 100, 38078, 52, 180, 19, -1, 15884), + (15424, 15424, 15424, 15424, 15424, 12, 100, 38079, 78, 1200, 19, -1, -1), + (15425, 15425, 15425, 15425, 15425, 15, 100, 38077, 79, 6, 19, -1, 15903), + (15426, -1, -1, 810, 810, 5, 96, -1, 0, 0, 19, 4828, 15427), + (15429, -1, -1, 15429, 15429, 7, 96, -1, 0, 0, 19, -1, 15430), + (15432, -1, -1, 15432, 15432, 7, 96, -1, 0, 0, 19, -1, 15433), + (15438, -1, -1, 15438, 15438, 9, 96, -1, 0, 0, 19, -1, 15439), + (15441, -1, -1, 815, 815, 10, 96, -1, 0, 0, 19, 7636, 15442), + (15444, -1, -1, 15444, 15444, 9, 96, 38080, 0, 0, 19, -1, 15445), + (15447, 15447, 15447, 15447, 15447, 9, 96, 38083, 78, 180, 19, -1, 15448), + (15450, -1, -1, 15450, 15450, 9, 96, -1, 0, 0, 19, -1, 15451), + (15453, -1, -1, 15453, 15453, 9, 96, -1, 0, 0, 19, -1, 15454), + (15456, -1, -1, 15456, 15456, 9, 96, -1, 0, 0, 19, -1, 15457), + (15459, 1245, 1245, 1245, 1245, 9, 96, 38404, 8, 2160, 19, 1247, 15460), + (15462, 8039, 8039, 8039, 38407, 15, 100, 38407, 58, 7, 19, 8039, 17167), + (15466, -1, -1, 10561, 10561, 9, 96, -1, 0, 0, 19, 10563, 15467), + (15469, -1, -1, 10558, 10558, 9, 96, -1, 0, 0, 19, 10560, 15470), + (15472, -1, -1, 8035, 8035, 9, 96, -1, 0, 0, 19, 10287, 15473), + (15475, 15475, 15475, 15475, 15475, 11, 96, 38408, 41, 600, 20, -1, 15476), + (15478, -1, -1, 15478, 15478, 9, 96, -1, 0, 0, 19, -1, 15479), + (15481, 15481, 15481, 15481, 15481, 18, 100, 38603, 53, 1080, 19, -1, -1), + (15482, 15482, 15482, 15482, 15482, 11, 96, 38414, 42, 1800, 19, -1, 15483), + (15485, -1, -1, 15485, 15485, 18, 100, -1, 0, 0, 19, -1, -1), + (15486, 15486, 15486, 15486, 15486, 12, 96, 38418, 43, 600, 19, -1, 15487), + (15489, 15489, 15489, 15489, 15489, 18, 100, 38421, 52, 10, 19, -1, -1), + (15490, 15490, 15490, 15490, 15490, 11, 96, 38422, 44, 10, 19, -1, 15491), + (15493, -1, -1, 15493, 15493, 9, 96, -1, 0, 0, 19, -1, 15494), + (15496, 15496, 15496, 15496, 15496, 11, 96, 38425, 46, 1800, 19, -1, 15497), + (15502, -1, -1, 15502, 15502, 9, 96, -1, 0, 0, 19, -1, 15503), + (15509, -1, -1, 15509, 15509, 9, 96, -1, 0, 0, 19, -1, 15510), + (15512, -1, -1, 15512, 15512, 9, 96, 38086, 0, 0, 19, -1, 15513), + (15515, 15515, 15515, 15515, 15515, 12, 100, 38089, 11, 90, 19, -1, 17417), + (15516, -1, -1, 15516, 15516, 9, 100, -1, 0, 0, 19, -1, 15960), + (15517, -1, -1, 15517, 15517, 7, 96, -1, 0, 0, 19, -1, 15518), + (15521, 15521, 15521, 15521, 15521, 12, 96, 38090, 42, 60, 19, -1, -1), + (15526, -1, -1, 12716, 12716, 7, 96, -1, 0, 0, 19, 12718, 15527), + (15529, -1, -1, 695, 695, 4, 96, -1, 0, 0, 19, 699, 15530), + (15540, -1, -1, 15540, 15540, 7, 96, -1, 0, 0, 19, -1, 15541), + (15543, -1, -1, 15543, 15543, 7, 96, -1, 0, 0, 19, -1, 15544), + (15546, -1, -1, 15546, 15546, 7, 96, -1, 0, 0, 19, -1, 15547), + (15549, -1, -1, 15549, 15549, 7, 96, -1, 0, 0, 19, -1, 15550), + (15552, -1, -1, 6302, 6302, 5, 96, -1, 0, 0, 19, 11013, 15553), + (15555, -1, -1, 15555, 15555, 11, 96, -1, 0, 0, 19, -1, 15556), + (15558, 10400, 10400, 10400, 10400, 9, 100, 38104, 62, 900, 19, 10400, -1), + (15564, -1, -1, 15564, 15564, 9, 96, -1, 0, 0, 19, -1, 15565), + (15567, 15567, 15567, 15567, 15567, 12, 96, 38106, 11, 1200, 19, -1, 15568), + (15569, 15569, 15569, 15569, 15569, 12, 96, 38108, 13, 60, 19, -1, 15991), + (15570, 15570, 15570, 15570, 15570, 15, 100, 38109, 64, 600, 19, -1, 15992), + (15571, -1, -1, 15571, 15571, 7, 96, -1, 0, 0, 19, -1, 15572), + (15574, 15574, 15574, 15574, 15574, 9, 80, 38110, 73, 4, 15, -1, 15575), + (15575, 15574, 15574, 15574, 15574, 9, 85, 38111, 73, 4, 16, 15574, 15576), + (15576, 15574, 15574, 15574, 15574, 9, 90, 38112, 73, 4, 17, 15575, 15577), + (15577, 15574, 15574, 15574, 15574, 9, 95, 38113, 73, 4, 18, 15576, 15578), + (15579, -1, -1, 15579, 15579, 7, 96, -1, 0, 0, 19, -1, 15580), + (15582, 15582, 15582, 15582, 15582, 9, 96, 38115, 34, 600, 19, -1, 15583), + (15585, -1, -1, 634, 634, 11, 96, -1, 0, 0, 19, 10780, 15586), + (15588, 10701, 10701, 10701, 10701, 12, 96, 38121, 32, 360, 19, 12756, 15589), + (15591, -1, -1, 15591, 15591, 5, 96, -1, 0, 0, 19, -1, 15592), + (15594, 15594, 15594, 15594, 15594, 9, 96, 38197, 39, 30, 19, -1, 15595), + (15598, -1, -1, 15598, 15598, 12, 96, -1, 0, 0, 19, -1, 15599), + (15601, 15601, 15601, 15601, 15601, 12, 96, 38131, 34, 6, 19, -1, 16077), + (15602, -1, -1, 15602, 15602, 9, 96, -1, 0, 0, 19, -1, 15603), + (15605, 12866, 12866, 12866, 12866, 15, 96, 38132, 74, 1800, 19, 12866, -1), + (15606, -1, -1, 8069, 8069, 5, 96, -1, 0, 0, 19, 8071, 15607), + (15609, -1, -1, 15609, 15609, 15, 100, -1, 0, 0, 19, -1, -1), + (15611, 15611, 15611, 15611, 15611, 18, 100, 38136, 32, 900, 19, -1, 16078), + (15612, 15612, 15612, 15612, 15612, 12, 96, 38137, 36, 20, 19, -1, 15613), + (15615, 15615, 15615, 15615, 15615, 12, 96, 38140, 44, 20, 19, -1, 15616), + (15619, 15619, 15619, 15619, 15619, 15, 100, 37188, 32, 600, 19, -1, -1), + (15622, -1, -1, 15622, 15622, 7, 96, -1, 0, 0, 19, -1, 15623), + (15625, -1, -1, 15625, 15625, 9, 96, -1, 0, 0, 19, -1, 15626), + (15628, 5022, 5022, 5022, 5022, 9, 96, 38176, 5, 600, 19, 6040, 15629), + (15632, -1, -1, 7005, 7005, 5, 96, -1, 0, 0, 19, 7007, 15633), + (15634, -1, -1, 15634, 15634, 3, 80, -1, 0, 0, 19, -1, 15635), + (15635, -1, -1, 15634, 15634, 5, 85, -1, 0, 0, 19, 15634, 15636), + (15639, 15639, 15639, 15639, 15639, 12, 96, 38183, 56, 60, 19, -1, -1), + (15640, 15640, 15640, 15640, 15640, 12, 100, 38184, 43, 60, 19, -1, -1), + (15642, 15642, 15642, 15642, 15642, 18, 100, 38187, 13, 1440, 19, -1, -1), + (15643, 15643, 15643, 15643, 15643, 9, 96, 38188, 75, 600, 19, -1, 15644), + (15646, 15646, 15646, 15646, 15646, 15, 100, 38194, 74, 60, 19, -1, 17255), + (15648, -1, -1, 15648, 15648, 9, 96, -1, 0, 0, 19, -1, 15649), + (15694, -1, -1, 8215, 8215, 5, 96, -1, 0, 0, 20, 12563, 15695), + (15714, -1, -1, 5263, 5263, 12, 96, -1, 0, 0, 20, 12468, 15715), + (15719, -1, -1, 1287, 1287, 11, 96, -1, 0, 0, 20, 13240, 15720), + (15746, -1, -1, 7033, 7033, 12, 96, 0, 0, 0, 20, 7035, 15747), + (15768, -1, -1, 15768, 15768, 7, 96, -1, 0, 0, 20, -1, 15769), + (15771, 15771, -1, 15771, 15771, 1, 55, 38274, 0, 3, 20, -1, -1), + (15772, -1, -1, 8232, 8232, 8, 100, -1, 0, 0, 20, 8261, -1), + (15773, -1, -1, 8040, 8040, 8, 100, -1, 0, 0, 20, 8313, -1), + (15775, 6508, 6508, 6508, 6508, 9, 96, 38276, 38, 600, 20, 10080, 15776), + (15778, -1, -1, 589, 589, 12, 96, -1, 0, 0, 20, 13106, 15779), + (15782, 7755, 7755, 7755, 7755, 12, 96, 38280, 53, 900, 20, 7755, 16187), + (15798, 15798, 15798, 15798, 15798, 9, 100, 38297, 34, 18, 20, -1, 15799), + (15819, 15819, 15819, 15819, 15819, 18, 100, 40807, 18, 900, 20, -1, -1), + (15833, -1, -1, 15833, 15833, 9, 96, 0, 0, 0, 20, -1, 15834), + (15836, -1, -1, 15836, 15836, 9, 100, 0, 0, 0, 20, -1, 15837), + (15839, 10450, 10450, 10450, 10450, 7, 96, 40817, 63, 900, 20, 10670, 15840), + (15855, 13004, 13004, 13004, 13004, 9, 96, 40832, 78, 300, 20, 13004, -1), + (15891, -1, -1, 11078, 11078, 9, 96, 0, 0, 0, 20, 11078, 15892), + (15893, -1, -1, 11079, 11079, 9, 96, 0, 0, 0, 20, 11079, 15894), + (15895, -1, -1, 11077, 11077, 9, 96, 0, 0, 0, 20, 11077, 15896), + (15904, 15904, 15904, 15904, 15904, 7, 66, 40874, 54, 600, 20, -1, -1), + (15908, -1, -1, 15908, 15908, 3, 80, -1, 0, 0, 20, -1, 15909), + (15909, -1, -1, 15908, 15908, 5, 85, -1, 0, 0, 20, 15908, 15910), + (15910, -1, -1, 15908, 15908, 7, 90, -1, 0, 0, 20, 15909, 15911), + (15954, -1, -1, 10853, 10853, 5, 90, -1, 0, 0, 20, 10864, 15955), + (15961, -1, -1, 12737, 12737, 9, 96, 0, 0, 0, 20, 12739, 15962), + (15988, 10333, 10333, 10333, 10333, 9, 96, 40894, 55, 120, 20, 12726, 15989), + (16016, 16016, 16016, 16016, 16016, 12, 100, 40919, 17, 12, 20, -1, -1), + (16062, -1, -1, 1572, 1572, 5, 96, -1, 0, 0, 20, 10556, 16063), + (16071, 16071, 16071, 16071, 16071, 15, 100, 40953, 46, 1800, 20, -1, 16072), + (16081, 16081, 16081, 16081, 16081, 15, 100, 40969, 55, 6, 20, -1, -1), + (16082, 16082, 16082, 16082, 16082, 3, 100, 40970, 53, 6, 20, -1, -1), + (16083, 16083, 16083, 16083, 16083, 3, 55, 40971, 46, 6, 20, -1, -1), + (16084, -1, -1, 16084, 16084, 9, 100, 0, 0, 0, 20, -1, 16085), + (16087, -1, -1, 16087, 16087, 5, 100, 0, 0, 6, 20, -1, 16088), + (16094, -1, -1, 477, 477, 2, 100, -1, 0, 0, 20, 6235, 16095), + (16096, 16096, 16096, 16096, 16096, 12, 100, 40972, 36, 6, 20, -1, -1), + (16097, 16097, 16097, 16097, 16097, 12, 100, 40973, 38, 600, 20, -1, 16098), + (16103, 16103, 16103, 16103, 16103, 0, 85, 41071, 35, 180, 16, -1, -1), + (16104, -1, -1, 16104, 16104, 5, 85, 0, 0, 0, 20, -1, -1), + (16105, 16105, 16105, 16105, 16105, 0, 85, 41086, 76, 30, 20, -1, -1), + (16106, 16106, 16106, 16106, 16106, 0, 85, 41087, 76, 30, 20, -1, -1), + (16107, 16107, 16107, 16107, 16107, 0, 85, 41088, 76, 30, 20, -1, -1), + (16108, 16108, 16108, 16108, 16108, 12, 100, 41090, 77, 120, 20, -1, -1), + (16109, -1, -1, 16109, 16109, 11, 96, -1, 0, 0, 20, -1, 16110), + (16113, 16113, 16113, 16113, 16113, 15, 100, 41096, 78, 60, 20, -1, -1), + (16114, -1, -1, 16114, 16114, 5, 96, -1, 0, 0, 20, -1, 16115), + (16117, -1, -1, 16117, 16117, 11, 96, -1, 0, 0, 20, -1, 16118), + (16120, -1, -1, 16120, 16120, 9, 105, -1, 0, 0, 21, -1, -1), + (16121, -1, -1, 6611, 6611, 6, 100, -1, 0, 0, 20, 10574, 16122), + (16124, -1, -1, 16124, 16124, 5, 96, -1, 0, 0, 20, -1, 16125), + (16128, -1, -1, 16128, 16128, 6, 96, -1, 0, 0, 20, -1, 16129), + (16131, -1, -1, 16131, 16131, 5, 96, -1, 0, 0, 20, -1, 16132), + (16137, -1, -1, 16137, 16137, 9, 100, -1, 0, 0, 20, -1, 16138), + (16140, -1, -1, 16140, 16140, 9, 100, -1, 0, 0, 20, -1, -1), + (16146, -1, -1, 16146, 16146, 11, 100, -1, 0, 0, 20, -1, 16147), + (16149, -1, -1, 16149, 16149, 9, 100, -1, 0, 0, 20, -1, 16150), + (16152, -1, -1, 16152, 16152, 11, 100, -1, 0, 0, 20, -1, 16153), + (16156, -1, -1, 16156, 16156, 12, 100, -1, 0, 0, 20, -1, 16157), + (16159, -1, -1, 16159, 16159, 15, 100, -1, 0, 0, 20, -1, -1), + (16160, 16160, 16160, 16160, 16160, 18, 100, 41110, 81, 900, 20, -1, -1), + (16162, 16162, 16162, 16162, 16162, 12, 100, 41112, 80, 180, 20, -1, -1), + (16163, 16163, 16163, 16163, 16163, 18, 100, 41113, 63, 180, 20, -1, 16695), + (16164, -1, -1, 6636, 6636, 9, 96, -1, 0, 0, 20, 12531, 16165), + (16170, -1, -1, 5248, 5248, 12, 96, -1, 0, 0, 20, 7358, 16171), + (16173, -1, -1, 5263, 5263, 9, 101, -1, 0, 0, 21, 12465, 16174), + (16176, -1, -1, 16176, 16176, 7, 100, -1, 0, 0, 20, -1, 16177), + (16179, -1, -1, 16179, 16179, 18, 100, 41122, 0, 0, 20, -1, -1), + (16180, -1, -1, 16180, 16180, 7, 96, -1, 0, 0, 20, -1, 16181), + (16185, 16185, 16185, 16185, 16185, 18, 100, 41124, 68, 600, 20, -1, 16729), + (16186, -1, -1, 16186, 16186, 12, 100, 41125, 0, 0, 20, -1, -1), + (16188, 16188, 16188, 16188, 16188, 12, 100, 41126, 58, 180, 20, -1, -1), + (16189, -1, -1, 10915, 10915, 9, 96, -1, 0, 0, 20, 10917, 16190), + (16192, -1, -1, 6641, 6641, 9, 96, -1, 0, 0, 20, 10077, 16193), + (16195, 16195, 16195, 16195, 16195, 15, 100, 41133, 59, 60, 20, -1, -1), + (16196, 16196, 16196, 16196, 16196, 15, 100, 41134, 60, 900, 20, -1, 16665), + (16197, 16197, 16197, 16197, 16197, 12, 96, 41136, 61, 900, 20, -1, 16198), + (16200, 16200, 16200, 16200, 16200, 9, 96, 41139, 63, 900, 20, -1, 16201), + (16203, 16203, 16203, 16203, 16203, 12, 96, 41143, 98, 120, 20, -1, 16204), + (16208, -1, -1, 16208, 16208, 5, 96, -1, 0, 0, 20, -1, 16209), + (16211, -1, -1, 16211, 16211, 7, 100, -1, 0, 0, 20, -1, 16212), + (16214, 10958, 10958, 10958, 16214, 18, 100, 41148, 62, 900, 20, 13000, -1), + (16215, 16215, 16215, 16215, 16215, 9, 96, 41150, 92, 300, 20, -1, 16216), + (16218, -1, -1, 16218, 16218, 7, 96, -1, 0, 0, 20, -1, 16219), + (16221, -1, -1, 16221, 16221, 9, 100, -1, 0, 0, 20, -1, 16223), + (16222, 16222, -1, 16222, 16222, 9, 100, 41153, 88, 30, 20, -1, -1), + (16225, -1, -1, 16225, 16225, 5, 96, -1, 0, 0, 20, -1, 16226), + (16230, -1, -1, 16230, 16230, 5, 96, -1, 0, 0, 20, -1, 16231), + (16235, -1, -1, 16235, 16235, 7, 96, -1, 0, 0, 20, -1, 16236), + (16238, -1, -1, 16238, 16238, 7, 96, -1, 0, 0, 20, -1, 16239), + (16246, 6983, 6983, 6983, 6983, 9, 96, 41157, 66, 720, 20, 6983, 16247), + (16249, -1, -1, 230, 230, 9, 100, -1, 0, 0, 20, 12677, -1), + (16250, 828, 828, 828, 828, 9, 96, 41159, 2, 3600, 20, 830, -1), + (16257, -1, -1, 16257, 16257, 11, 100, 0, 0, 0, 20, -1, 16258), + (16260, -1, -1, 16260, 16260, 11, 100, -1, 0, 0, 20, -1, 16261), + (16263, 16263, 16263, 16263, 16263, 11, 96, 41161, 95, 600, 20, -1, 16264), + (16266, -1, -1, 6560, 6560, 9, 96, -1, 0, 0, 20, 6277, -1), + (16267, -1, -1, 888, 888, 3, 96, -1, 0, 0, 20, 892, 16268), + (16272, -1, -1, 16272, 16272, 9, 96, -1, 0, 0, 20, -1, 16273), + (16276, -1, -1, 16276, 16276, 5, 96, -1, 0, 0, 20, -1, 16277), + (16287, -1, -1, 16287, 16287, 7, 96, -1, 0, 0, 20, -1, 16288), + (16296, 16296, 16296, 16296, 16296, 13, 100, 41168, 60, 30, 20, -1, -1), + (16297, -1, -1, 6337, 6337, 6, 96, -1, 0, 0, 20, 10155, 16298), + (16300, -1, -1, 16300, 16300, 9, 100, -1, 0, 0, 20, -1, 16301), + (16303, -1, -1, 12721, 12721, 9, 96, 0, 0, 0, 20, 12723, 16304), + (16306, -1, -1, 6340, 6340, 6, 96, -1, 0, 0, 20, 7453, -1), + (16310, 16310, 16310, 16310, 16310, 12, 100, 41169, 97, 600, 20, -1, -1), + (16317, -1, -1, 16317, 16317, 5, 100, -1, 0, 0, 20, -1, 16318), + (16324, 6607, 6607, 6607, 16324, 9, 96, 16491, 61, 600, 20, 6609, 16325), + (16327, -1, -1, 6362, 6362, 7, 96, 0, 0, 0, 20, 6366, 16328), + (16330, -1, -1, 16330, 16330, 9, 96, -1, 0, 0, 20, -1, 16331), + (16336, -1, -1, 16336, 16336, 7, 96, -1, 0, 0, 20, -1, 16337), + (16339, -1, -1, 16339, 16339, 7, 96, -1, 0, 0, 20, -1, 16340), + (16342, -1, -1, 16342, 16342, 7, 96, -1, 0, 0, 20, -1, 16343), + (16360, 16360, 16360, 16360, 16360, 9, 100, 41188, 91, 6, 20, -1, -1), + (16361, -1, -1, 9509, 9509, 7, 96, -1, 0, 0, 20, 9515, -1), + (16363, 16363, 16363, 16363, 16363, 12, 96, 41193, 89, 1800, 20, -1, 16364), + (16366, -1, -1, 16366, 16366, 12, 96, -1, 0, 0, 20, -1, 16367), + (16369, 16369, 16369, 16369, 16369, 15, 100, 41196, 98, 12, 20, -1, -1), + (16370, 16370, -1, 16370, 16370, 5, 100, 41197, 98, 12, 20, -1, -1), + (16371, -1, -1, 16371, 16371, 3, 96, -1, 0, 0, 20, -1, 16372), + (16380, -1, -1, 16380, 16380, 5, 96, -1, 0, 0, 20, -1, 16381), + (16386, -1, -1, 16386, 16386, 7, 96, -1, 0, 0, 20, -1, 16387), + (16392, -1, -1, 16392, 16392, 5, 96, -1, 0, 0, 20, -1, 16393), + (16395, 16395, 16395, 16395, 16395, 7, 100, 41305, 93, 10, 20, -1, -1), + (16396, -1, -1, 16396, 16396, 7, 96, -1, 0, 0, 20, -1, 16397), + (16402, -1, -1, 6112, 6112, 5, 96, -1, 0, 0, 20, 12967, 16403), + (16414, -1, -1, 1056, 1056, 5, 101, -1, 0, 0, 21, 7525, 16415), + (16419, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 8447, 16420), + (16420, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 16419, 16421), + (16421, -1, -1, 12636, 12636, 0, 1, -1, 0, 0, 16, 16420, -1), + (16440, -1, -1, 6540, 6540, 10, 101, -1, 0, 0, 21, 12510, 16441), + (16475, -1, -1, 8201, 8201, 9, 101, -1, 0, 0, 21, 8203, 16476), + (16489, -1, -1, 1107, 1107, 9, 101, -1, 0, 0, 21, 12558, 16490), + (16536, -1, -1, 16536, 16536, 5, 101, -1, 0, 0, 21, -1, 16537), + (16604, -1, -1, 849, 849, 11, 105, -1, 0, 0, 21, 10622, -1), + (16644, -1, -1, 16644, 16644, 11, 101, -1, 0, 0, 21, -1, 16645), + (16666, -1, -1, 16666, 16666, 9, 101, -1, 0, 0, 21, -1, 16667), + (16716, 6764, 6764, 6764, 6764, 12, 105, 41308, 52, 600, 21, 10057, -1), + (16730, -1, -1, 1608, 1608, 13, 101, -1, 0, 0, 21, 10069, 16731), + (16745, -1, -1, 16745, 16745, 9, 101, -1, 0, 0, 21, -1, 16746), + (16883, 1119, 1119, 1119, 1119, 12, 101, 41594, 8, 900, 21, 10299, 16884), + (16887, -1, -1, 729, 729, 11, 101, -1, 0, 0, 21, 10307, 16888), + (16890, -1, -1, 724, 724, 15, 101, -1, 0, 0, 21, 7493, 16891), + (17004, -1, -1, 556, 556, 7, 101, -1, 0, 0, 21, 1567, 17005), + (17030, 4857, 4857, 4857, 4857, 15, 101, 41660, 7, 600, 21, 5769, 17031), + (17131, 12785, 12785, 12785, 12785, 15, 105, 41736, 80, 30, 21, 12785, -1), + (17199, 17199, 17199, 17199, 17199, 100, 51, 41819, 31, 2, 21, -1, -1), + (17206, -1, -1, 10588, 10588, 7, 101, 0, 0, 0, 21, 10592, 17207), + (17209, -1, -1, 17209, 17209, 9, 101, -1, 0, 0, 21, -1, 17210), + (17212, -1, -1, 17212, 17212, 12, 101, -1, 0, 0, 21, -1, 17213), + (17215, -1, -1, 17215, 17215, 12, 101, -1, 0, 0, 21, -1, 17216), + (17218, -1, -1, 17218, 17218, 9, 101, -1, 0, 0, 21, -1, 17219), + (17229, -1, -1, 17229, 17229, 9, 101, -1, 0, 0, 21, -1, 17230), + (17235, -1, -1, 17235, 17235, 15, 101, -1, 0, 0, 21, -1, 17236), + (17238, 17238, 17238, 17238, 17238, 24, 105, 41808, 10, 900, 21, -1, -1), + (17239, -1, -1, 6489, 6489, 12, 101, -1, 0, 0, 21, 6491, -1), + (17242, -1, -1, 17242, 17242, 12, 101, -1, 0, 0, 21, -1, 17243), + (17245, -1, -1, 17245, 17245, 12, 101, -1, 0, 0, 21, -1, 17246), + (17248, 17248, 17248, 17248, 17248, 24, 105, 41811, 93, 1080, 21, -1, -1), + (17249, -1, -1, 17249, 17249, 12, 101, -1, 0, 0, 21, -1, 17250), + (17252, -1, -1, 17252, 17252, 9, 101, -1, 0, 0, 21, -1, 17253), + (17256, 17256, 17256, 17256, 17256, 21, 105, 41815, 93, 360, 21, -1, -1), + (17257, 17257, 17257, 17257, 17257, 21, 105, 41816, 98, 300, 21, -1, -1), + (17258, -1, -1, 17258, 17258, 15, 101, 0, 0, 0, 21, -1, 17259), + (17267, -1, -1, 17267, 17267, 9, 101, -1, 0, 0, 21, -1, 17268), + (17273, 17273, 17273, 17273, 17273, 15, 101, 41830, 98, 720, 21, -1, -1), + (17276, 1569, 1569, 1569, 1569, 9, 101, 41831, 5, 1800, 21, 10161, 17277), + (17280, 17280, 17280, 17280, 17280, 21, 105, 41834, 97, 720, 21, -1, -1), + (17281, -1, -1, 17281, 17281, 15, 105, -1, 0, 0, 21, -1, -1), + (17288, -1, -1, 17288, 17288, 9, 105, -1, 0, 0, 21, 7317, -1), + (17289, -1, -1, 17289, 17289, 7, 101, -1, 0, 0, 21, -1, 17290), + (17295, -1, -1, 692, 692, 12, 101, -1, 0, 0, 21, 12769, 17296), + (17298, 749, 749, 749, 749, 15, 105, 41837, 11, 1800, 21, 1208, -1), + (17307, -1, -1, 17307, 17307, 9, 101, -1, 0, 0, 21, -1, 17308), + (17310, -1, -1, 7945, 7945, 9, 105, -1, 0, 0, 21, 10347, -1), + (17311, 970, 970, 970, 970, 9, 101, 41845, 6, 1800, 21, 1326, 17312), + (17317, -1, -1, 17317, 17317, 9, 101, -1, 0, 0, 21, -1, 17318), + (17328, 17328, 17328, 17328, 17328, 21, 105, 41854, 87, 600, 21, -1, -1), + (17329, 17329, 17329, 17329, 17329, 12, 101, 41855, 88, 20, 21, -1, -1), + (17333, 153, 153, 153, 153, 18, 105, 41856, 3, 2160, 21, 12996, -1), + (17334, -1, -1, 12977, 12977, 12, 102, 0, 0, 0, 21, 12981, 17335), + (17336, -1, -1, 17336, 17336, 9, 101, -1, 0, 0, 21, -1, 17337), + (17339, -1, -1, 17339, 17339, 9, 101, -1, 0, 0, 21, -1, 17340), + (17342, 17342, 17342, 17342, 17342, 15, 105, 41857, 85, 60, 21, -1, -1), + (17344, 17344, 17344, 17344, 17344, 15, 101, 41858, 94, 780, 21, -1, 17345), + (17347, 17347, 17347, 17347, 17347, 12, 101, 41861, 32, 30, 21, -1, 17348), + (17350, -1, -1, 7664, 7664, 5, 102, -1, 0, 0, 21, 10109, 17351), + (17357, -1, -1, 17357, 17357, 9, 96, -1, 0, 0, 19, -1, 17358), + (17361, -1, -1, 17361, 17361, 5, 100, -1, 0, 0, 21, -1, 17362), + (17364, 17364, 17364, 17364, 17364, 15, 105, 46160, 87, 120, 21, -1, -1), + (17365, -1, -1, 10792, 10792, 15, 101, 0, 0, 0, 21, 10796, 17366), + (17370, -1, -1, 17370, 17370, 15, 102, 0, 0, 0, 21, -1, 17371), + (17372, 17372, 17372, 17372, 17372, 18, 104, 46161, 85, 300, 21, -1, -1), + (17373, 17373, -1, 17373, 17373, 15, 105, 46162, 98, 900, 21, -1, -1), + (17375, -1, -1, 17375, 17375, 12, 101, -1, 0, 0, 21, -1, 17376), + (17378, 17378, 17378, 17378, 17378, 10, 101, 46164, 97, 3, 21, -1, -1), + (17379, 17378, 17378, 17378, 17378, 10, 101, 46165, 86, 3, 21, -1, -1), + (17380, 17378, 17378, 17378, 17378, 10, 101, 46166, 97, 3, 21, -1, -1), + (17382, 5015, 5015, 5015, 5015, 15, 103, 46168, 9, 900, 21, 10301, -1), + (17384, 17384, 17384, 17384, 17384, 18, 101, 46171, 10, 20, 21, -1, -1), + (17391, -1, -1, 495, 495, 12, 105, -1, 0, 0, 21, 10668, -1), + (17406, -1, -1, 10653, 10653, 12, 103, -1, 0, 0, 21, 10655, -1), + (17409, -1, -1, 17409, 17409, 15, 105, -1, 0, 0, 21, -1, -1), + (17414, -1, -1, 17414, 17414, 9, 101, -1, 0, 0, 21, -1, 17415), + (17418, -1, -1, 17418, 17418, 7, 101, -1, 0, 0, 21, -1, 17419), + (17428, 17428, 17428, 17428, 17428, 15, 101, 46178, 0, 0, 21, -1, 17429), + (17436, -1, -1, 17436, 17436, 7, 101, -1, 0, 0, 21, -1, 17437), + (17439, -1, -1, 17439, 17439, 9, 102, -1, 0, 0, 21, -1, 17440), + (17441, -1, -1, 255, 255, 15, 102, -1, 0, 0, 21, 7633, -1), + (17445, -1, -1, 17445, 17445, 15, 101, 0, 0, 0, 21, -1, 17446), + (17448, -1, -1, 17448, 17448, 15, 102, 0, 0, 0, 21, -1, 17449), + (17476, -1, -1, 10800, 10800, 15, 101, -1, 0, 0, 21, 10802, 17477), + (17486, 12864, -1, 12864, 12864, 12, 105, 46195, 73, 10, 21, 12864, -1), + (17492, -1, -1, 17492, 17492, 9, 101, -1, 0, 0, 21, -1, 17493), + (17495, -1, -1, 17495, 17495, 9, 101, -1, 0, 0, 21, -1, 17496), + (17515, -1, -1, 17515, 17515, 7, 102, -1, 0, 0, 21, -1, 17516), + (17517, -1, -1, 17517, 17517, 9, 101, -1, 0, 0, 21, -1, 17518), + (17522, -1, -1, 17522, 17522, 9, 101, -1, 0, 0, 21, -1, 17523), + (17533, -1, -1, 17533, 17533, 15, 105, -1, 0, 0, 21, -1, -1), + (17534, 6828, 6828, 6828, 6828, 15, 105, 46207, 43, 60, 21, 10208, -1), + (17535, 967, 967, 967, 967, 9, 101, 46208, 10, 1800, 21, 12791, 17536), + (17538, 17538, 17538, 17538, 17538, 21, 105, 46212, 91, 1800, 21, -1, -1), + (17539, 4934, 4934, 4934, 4934, 12, 105, 46214, 13, 300, 21, 10278, -1), + (17540, 4935, 4935, 4935, 4935, 12, 105, 46215, 14, 300, 21, 10277, -1), + (17541, 8038, 8038, 8038, 8038, 12, 105, 46217, 56, 12, 21, 8038, -1), + (17547, -1, -1, 17547, 17547, 12, 102, -1, 0, 0, 21, -1, 17548), + (17549, -1, -1, 17549, 17549, 9, 101, -1, 0, 0, 21, -1, 17550), + (17553, -1, -1, 17553, 17553, 18, 105, -1, 0, 0, 21, -1, -1), + (17554, -1, -1, 17554, 17554, 15, 105, -1, 0, 0, 21, -1, -1), + (17555, -1, -1, 17555, 17555, 5, 101, -1, 0, 0, 21, -1, 17556), + (17558, -1, -1, 17558, 17558, 5, 101, -1, 0, 0, 21, -1, 17559), + (17561, -1, -1, 17561, 17561, 5, 101, -1, 0, 0, 21, -1, 17562), + (17564, -1, -1, 17564, 17564, 5, 101, -1, 0, 0, 21, -1, 17565), + (17567, -1, -1, 17567, 17567, 5, 101, -1, 0, 0, 21, -1, 17568), + (17570, -1, -1, 17570, 17570, 5, 101, -1, 0, 0, 21, -1, 17571), + (17573, -1, -1, 17573, 17573, 5, 101, -1, 0, 0, 21, -1, 17574), + (17576, -1, -1, 17576, 17576, 5, 101, -1, 0, 0, 21, -1, 17577), + (17579, -1, -1, 17579, 17579, 5, 101, -1, 0, 0, 21, -1, 17580), + (17582, -1, -1, 17582, 17582, 5, 101, -1, 0, 0, 21, -1, 17583), + (17585, -1, -1, 17585, 17585, 5, 101, -1, 0, 0, 21, -1, 17586), + (17588, -1, -1, 17588, 17588, 5, 101, -1, 0, 0, 21, -1, 17589), + (17591, -1, -1, 17591, 17591, 5, 101, -1, 0, 0, 21, -1, 17592), + (17594, -1, -1, 17594, 17594, 5, 101, -1, 0, 0, 21, -1, 17595), + (17597, -1, -1, 17597, 17597, 5, 101, -1, 0, 0, 21, -1, 17598), + (17600, -1, -1, 17600, 17600, 5, 101, -1, 0, 0, 21, -1, 17601), + (17603, -1, -1, 17603, 17603, 5, 101, -1, 0, 0, 21, -1, 17604), + (17606, -1, -1, 17606, 17606, 5, 101, -1, 0, 0, 21, -1, 17607), + (17609, -1, -1, 17609, 17609, 5, 101, -1, 0, 0, 21, -1, 17610), + (17612, -1, -1, 17612, 17612, 5, 101, -1, 0, 0, 21, -1, 17613), + (17615, -1, -1, 17615, 17615, 5, 101, -1, 0, 0, 21, -1, 17616), + (17618, -1, -1, 17618, 17618, 5, 101, -1, 0, 0, 21, -1, 17619), + (17621, -1, -1, 17621, 17621, 5, 101, -1, 0, 0, 21, -1, 17622), + (17624, -1, -1, 17624, 17624, 5, 101, -1, 0, 0, 21, -1, 17625), + (17627, -1, -1, 17627, 17627, 5, 101, -1, 0, 0, 21, -1, 17628), + (17630, -1, -1, 17630, 17630, 5, 101, -1, 0, 0, 21, -1, 17631), + (17633, -1, -1, 17633, 17633, 5, 101, -1, 0, 0, 21, -1, 17634), + (17639, -1, -1, 17639, 17639, 9, 91, 0, 0, 0, 18, -1, 17640), + (18972, -1, -1, 279, 279, 15, 105, -1, 0, 0, 21, 279, -1), + (30050, -1, -1, 30050, 30050, 0, 1, -1, 0, 0, 0, -1, 30051), + (30100, -1, -1, 30100, 30100, 0, 1, -1, 0, 0, 0, -1, 30101), + (30150, -1, -1, 30150, 30150, 0, 1, -1, 0, 0, 0, -1, 30151), + (30175, -1, -1, 30175, 30175, 0, 1, -1, 0, 0, 0, -1, 30176), + (30180, -1, -1, 30180, 30180, 0, 1, -1, 0, 0, 0, -1, 30181), + (30185, -1, -1, 30185, 30185, 0, 1, -1, 0, 0, 0, -1, 30186), + (30190, -1, -1, 30190, 30190, 0, 1, -1, 0, 0, 0, -1, 30191), + (30195, -1, -1, 30195, 30195, 0, 1, -1, 0, 0, 0, -1, 30196), + (49999, -1, -1, -1, -1, 0, 71, 0, 0, 0, 0, -1, 1); + +-- Dumping structure for table eqdb.aa_rank_effects +DROP TABLE IF EXISTS `aa_rank_effects`; +CREATE TABLE IF NOT EXISTS `aa_rank_effects` ( + `rank_id` int(10) unsigned NOT NULL, + `slot` int(10) unsigned NOT NULL DEFAULT '1', + `effect_id` int(10) NOT NULL DEFAULT '0', + `base1` int(10) NOT NULL DEFAULT '0', + `base2` int(10) NOT NULL DEFAULT '0', + PRIMARY KEY (`rank_id`,`slot`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `aa_rank_effects` (`rank_id`, `slot`, `effect_id`, `base1`, `base2`) VALUES + (2, 1, 4, 2, 0), + (3, 1, 4, 4, 0), + (4, 1, 4, 6, 0), + (5, 1, 4, 8, 0), + (6, 1, 4, 10, 0), + (7, 1, 7, 2, 0), + (8, 1, 7, 4, 0), + (9, 1, 7, 6, 0), + (10, 1, 7, 8, 0), + (11, 1, 7, 10, 0), + (12, 1, 6, 2, 0), + (13, 1, 6, 4, 0), + (14, 1, 6, 6, 0), + (15, 1, 6, 8, 0), + (16, 1, 6, 10, 0), + (17, 1, 5, 2, 0), + (18, 1, 5, 4, 0), + (19, 1, 5, 6, 0), + (20, 1, 5, 8, 0), + (21, 1, 5, 10, 0), + (22, 1, 8, 2, 0), + (23, 1, 8, 4, 0), + (24, 1, 8, 6, 0), + (25, 1, 8, 8, 0), + (26, 1, 8, 10, 0), + (27, 1, 9, 2, 0), + (28, 1, 9, 4, 0), + (29, 1, 9, 6, 0), + (30, 1, 9, 8, 0), + (31, 1, 9, 10, 0), + (32, 1, 10, 2, 0), + (33, 1, 10, 4, 0), + (34, 1, 10, 6, 0), + (35, 1, 10, 8, 0), + (36, 1, 10, 10, 0), + (37, 1, 46, 2, 0), + (38, 1, 46, 4, 0), + (39, 1, 46, 6, 0), + (40, 1, 46, 8, 0), + (41, 1, 46, 10, 0), + (42, 1, 47, 2, 0), + (43, 1, 47, 4, 0), + (44, 1, 47, 6, 0), + (45, 1, 47, 8, 0), + (46, 1, 47, 10, 0), + (47, 1, 50, 2, 0), + (48, 1, 50, 4, 0), + (49, 1, 50, 6, 0), + (50, 1, 50, 8, 0), + (51, 1, 50, 10, 0), + (52, 1, 48, 2, 0), + (53, 1, 48, 4, 0), + (54, 1, 48, 6, 0), + (55, 1, 48, 8, 0), + (56, 1, 48, 10, 0), + (57, 1, 49, 2, 0), + (58, 1, 49, 4, 0), + (59, 1, 49, 6, 0), + (60, 1, 49, 8, 0), + (61, 1, 49, 10, 0), + (62, 1, 271, 8, 0), + (63, 1, 271, 14, 0), + (64, 1, 271, 21, 0), + (68, 1, 233, 110, 0), + (69, 1, 233, 125, 0), + (70, 1, 233, 150, 0), + (71, 1, 246, 110, 0), + (72, 1, 246, 125, 0), + (73, 1, 246, 150, 0), + (74, 1, 269, 10, 0), + (75, 1, 269, 20, 0), + (76, 1, 269, 30, 0), + (77, 1, 125, 2, 2), + (77, 2, 137, 0, 0), + (77, 3, 141, 1, 0), + (77, 4, 139, -6233, 0), + (77, 5, 139, -6265, 0), + (77, 6, 125, 2, 2), + (77, 7, 137, 147, 0), + (77, 8, 141, 1, 0), + (78, 1, 125, 5, 5), + (78, 2, 137, 0, 0), + (78, 3, 141, 1, 0), + (78, 4, 139, -6233, 0), + (78, 5, 139, -6265, 0), + (78, 6, 125, 5, 5), + (78, 7, 137, 147, 0), + (78, 8, 141, 1, 0), + (79, 1, 125, 10, 10), + (79, 2, 137, 0, 0), + (79, 3, 141, 1, 0), + (79, 4, 139, -6233, 0), + (79, 5, 139, -6265, 0), + (79, 6, 125, 10, 10), + (79, 7, 137, 147, 0), + (79, 8, 141, 1, 0), + (80, 1, 274, 3, 0), + (81, 1, 274, 6, 0), + (82, 1, 274, 10, 0), + (83, 1, 132, 2, 2), + (84, 1, 132, 5, 5), + (85, 1, 132, 10, 10), + (86, 1, 128, 5, 5), + (86, 2, 138, 1, 0), + (86, 3, 140, 1, 0), + (86, 4, 139, -2741, 0), + (86, 5, 139, -16843, 0), + (86, 6, 385, -16192, 0), + (86, 7, 385, -10547, 0), + (86, 8, 385, -13543, 0), + (87, 1, 128, 15, 15), + (87, 2, 138, 1, 0), + (87, 3, 140, 1, 0), + (87, 4, 139, -2741, 0), + (87, 5, 139, -16843, 0), + (87, 6, 385, -16192, 0), + (87, 7, 385, -10547, 0), + (87, 8, 385, -13543, 0), + (88, 1, 128, 30, 30), + (88, 2, 138, 1, 0), + (88, 3, 140, 1, 0), + (88, 4, 139, -2741, 0), + (88, 5, 139, -16843, 0), + (88, 6, 385, -16192, 0), + (88, 7, 385, -10547, 0), + (88, 8, 385, -13543, 0), + (92, 1, 294, 2, 100), + (93, 1, 294, 4, 100), + (94, 1, 294, 7, 100), + (98, 1, 114, -5, 0), + (99, 1, 114, -10, 0), + (100, 1, 114, -20, 0), + (101, 1, 265, 20, 0), + (102, 1, 265, 40, 0), + (103, 1, 265, 52, 0), + (104, 1, 127, 10, 10), + (104, 2, 138, 1, 0), + (104, 3, 140, 1, 0), + (104, 4, 143, 3000, 0), + (105, 1, 127, 25, 25), + (105, 2, 138, 1, 0), + (105, 3, 140, 1, 0), + (105, 4, 143, 3000, 0), + (106, 1, 127, 50, 50), + (106, 2, 138, 1, 0), + (106, 3, 140, 1, 0), + (106, 4, 143, 3000, 0), + (107, 1, 214, 200, 0), + (108, 1, 214, 500, 0), + (109, 1, 214, 1000, 0), + (110, 1, 0, 1, 0), + (111, 1, 0, 2, 0), + (112, 1, 0, 3, 0), + (113, 1, 169, 15, -1), + (114, 1, 169, 40, -1), + (115, 1, 169, 75, -1), + (116, 1, 181, 5, 0), + (117, 1, 181, 10, 0), + (118, 1, 181, 25, 0), + (119, 1, 278, 500, 16000), + (119, 2, 440, 50, 100), + (120, 1, 278, 510, 17102), + (120, 2, 440, 52, 100), + (121, 1, 278, 520, 19635), + (121, 2, 440, 54, 100), + (122, 1, 259, 2, 0), + (123, 1, 259, 5, 0), + (124, 1, 259, 10, 0), + (125, 1, 172, 2, 0), + (126, 1, 172, 5, 0), + (127, 1, 172, 10, 0), + (137, 1, 127, 10, 10), + (137, 2, 137, 88, 0), + (138, 1, 127, 25, 25), + (138, 2, 137, 88, 0), + (139, 1, 127, 50, 50), + (139, 2, 137, 88, 0), + (141, 1, 127, 2, 2), + (141, 2, 137, 0, 0), + (141, 3, 138, 0, 0), + (141, 4, 141, 1, 0), + (141, 5, 143, 3000, 0), + (141, 6, 127, 2, 2), + (141, 7, 385, 16555, 0), + (141, 8, 385, 16655, 0), + (142, 1, 127, 5, 5), + (142, 2, 137, 0, 0), + (142, 3, 138, 0, 0), + (142, 4, 141, 1, 0), + (142, 5, 143, 3000, 0), + (142, 6, 127, 5, 5), + (142, 7, 385, 16555, 0), + (142, 8, 385, 16655, 0), + (143, 1, 127, 10, 10), + (143, 2, 137, 0, 0), + (143, 3, 138, 0, 0), + (143, 4, 141, 1, 0), + (143, 5, 143, 3000, 0), + (143, 6, 127, 10, 10), + (143, 7, 385, 16555, 0), + (143, 8, 385, 16655, 0), + (144, 1, 244, 50, 0), + (147, 1, 127, 10, 10), + (147, 2, 138, 1, 0), + (147, 3, 140, 1, 0), + (147, 4, 143, 3000, 0), + (148, 1, 127, 25, 25), + (148, 2, 138, 1, 0), + (148, 3, 140, 1, 0), + (148, 4, 143, 3000, 0), + (149, 1, 127, 50, 50), + (149, 2, 138, 1, 0), + (149, 3, 140, 1, 0), + (149, 4, 143, 3000, 0), + (150, 1, 268, 10, 59), + (151, 1, 268, 25, 59), + (152, 1, 268, 50, 59), + (158, 1, 238, 1, 0), + (159, 1, 268, 10, 68), + (160, 1, 268, 25, 68), + (161, 1, 268, 50, 68), + (182, 1, 131, 100, 0), + (182, 2, 137, 33, 0), + (190, 1, 219, 225, 680), + (191, 1, 219, 235, 1190), + (192, 1, 219, 240, 1700), + (195, 1, 181, 100, 0), + (196, 1, 226, 1, 0), + (198, 1, 276, 32, 0), + (199, 1, 301, 30, 0), + (200, 1, 301, 60, 0), + (201, 1, 301, 100, 0), + (205, 1, 251, 100, 0), + (210, 1, 302, 50, 50), + (210, 2, 385, 99, 0), + (211, 1, 302, 100, 100), + (211, 2, 385, 99, 0), + (212, 1, 302, 200, 200), + (212, 2, 385, 99, 0), + (213, 1, 260, 2, 23), + (213, 2, 260, 2, 24), + (213, 3, 260, 2, 25), + (213, 4, 260, 2, 26), + (214, 1, 260, 4, 23), + (214, 2, 260, 4, 24), + (214, 3, 260, 4, 25), + (214, 4, 260, 4, 26), + (215, 1, 260, 6, 23), + (215, 2, 260, 6, 24), + (215, 3, 260, 6, 25), + (215, 4, 260, 6, 26), + (225, 1, 272, 1, 0), + (226, 1, 272, 3, 0), + (227, 1, 272, 5, 0), + (230, 1, 275, 10, 0), + (231, 1, 275, 20, 0), + (232, 1, 275, 30, 0), + (237, 1, 227, 1, 25), + (238, 1, 227, 3, 25), + (239, 1, 227, 5, 25), + (240, 1, 224, 20, 26), + (240, 2, 173, 1, 0), + (241, 1, 224, 35, 26), + (241, 2, 173, 2, 0), + (242, 1, 224, 50, 26), + (242, 2, 173, 3, 0), + (244, 1, 268, 10, 56), + (244, 2, 234, 7500, 0), + (245, 1, 268, 25, 56), + (245, 2, 234, 5000, 0), + (246, 1, 268, 50, 56), + (246, 2, 234, 2500, 0), + (247, 1, 224, 15, 0), + (248, 1, 224, 30, 0), + (249, 1, 224, 50, 0), + (255, 1, 279, 7, 0), + (256, 1, 279, 11, 0), + (257, 1, 279, 15, 0), + (263, 1, 282, 10, 0), + (264, 1, 282, 25, 0), + (265, 1, 282, 50, 0), + (266, 1, 128, 50, 50), + (266, 2, 138, 1, 0), + (266, 3, 140, 1, 0), + (266, 4, 139, -2741, 0), + (266, 5, 139, -16843, 0), + (266, 6, 385, -16192, 0), + (266, 7, 385, -10547, 0), + (266, 8, 385, -13543, 0), + (267, 1, 294, 2, 100), + (268, 1, 294, 4, 100), + (269, 1, 294, 6, 100), + (273, 1, 288, 1000, 21), + (275, 1, 260, 2, 50), + (276, 1, 260, 4, 50), + (277, 1, 260, 6, 50), + (278, 1, 0, 1, 0), + (278, 2, 15, 1, 0), + (279, 1, 214, 200, 0), + (279, 2, 259, 2, 0), + (279, 3, 172, 2, 0), + (280, 1, 227, 1, 62), + (280, 2, 227, 1, 17), + (281, 1, 227, 3, 62), + (281, 2, 227, 3, 17), + (282, 1, 227, 5, 62), + (282, 2, 227, 5, 17), + (283, 1, 228, 10, 0), + (284, 1, 228, 20, 0), + (285, 1, 228, 30, 0), + (286, 1, 10, 0, 0), + (287, 1, 253, 1, 0), + (288, 1, 257, 1, 0), + (288, 2, 267, 1, 31), + (288, 3, 267, 1, 32), + (288, 4, 267, 1, 33), + (288, 5, 267, 1, 15), + (288, 6, 267, 1, 16), + (288, 7, 267, 1, 17), + (288, 8, 267, 1, 18), + (288, 9, 267, 1, 19), + (288, 10, 267, 1, 20), + (292, 1, 4, 12, 0), + (293, 1, 4, 14, 0), + (294, 1, 4, 16, 0), + (295, 1, 4, 18, 0), + (296, 1, 4, 20, 0), + (297, 1, 4, 22, 0), + (298, 1, 4, 24, 0), + (299, 1, 4, 26, 0), + (300, 1, 4, 28, 0), + (301, 1, 4, 30, 0), + (302, 1, 7, 12, 0), + (303, 1, 7, 14, 0), + (304, 1, 7, 16, 0), + (305, 1, 7, 18, 0), + (306, 1, 7, 20, 0), + (307, 1, 7, 22, 0), + (308, 1, 7, 24, 0), + (309, 1, 7, 26, 0), + (310, 1, 7, 28, 0), + (311, 1, 7, 30, 0), + (312, 1, 6, 12, 0), + (313, 1, 6, 14, 0), + (314, 1, 6, 16, 0), + (315, 1, 6, 18, 0), + (316, 1, 6, 20, 0), + (317, 1, 6, 22, 0), + (318, 1, 6, 24, 0), + (319, 1, 6, 26, 0), + (320, 1, 6, 28, 0), + (321, 1, 6, 30, 0), + (322, 1, 5, 12, 0), + (323, 1, 5, 14, 0), + (324, 1, 5, 16, 0), + (325, 1, 5, 18, 0), + (326, 1, 5, 20, 0), + (327, 1, 5, 22, 0), + (328, 1, 5, 24, 0), + (329, 1, 5, 26, 0), + (330, 1, 5, 28, 0), + (331, 1, 5, 30, 0), + (332, 1, 8, 12, 0), + (333, 1, 8, 14, 0), + (334, 1, 8, 16, 0), + (335, 1, 8, 18, 0), + (336, 1, 8, 20, 0), + (337, 1, 8, 22, 0), + (338, 1, 8, 24, 0), + (339, 1, 8, 26, 0), + (340, 1, 8, 28, 0), + (341, 1, 8, 30, 0), + (342, 1, 9, 12, 0), + (343, 1, 9, 14, 0), + (344, 1, 9, 16, 0), + (345, 1, 9, 18, 0), + (346, 1, 9, 20, 0), + (347, 1, 9, 22, 0), + (348, 1, 9, 24, 0), + (349, 1, 9, 26, 0), + (350, 1, 9, 28, 0), + (351, 1, 9, 30, 0), + (352, 1, 10, 12, 0), + (353, 1, 10, 14, 0), + (354, 1, 10, 16, 0), + (355, 1, 10, 18, 0), + (356, 1, 10, 20, 0), + (357, 1, 10, 22, 0), + (358, 1, 10, 24, 0), + (359, 1, 10, 26, 0), + (360, 1, 10, 28, 0), + (361, 1, 10, 30, 0), + (362, 1, 46, 12, 0), + (363, 1, 46, 14, 0), + (364, 1, 46, 16, 0), + (365, 1, 46, 18, 0), + (366, 1, 46, 20, 0), + (367, 1, 46, 22, 0), + (368, 1, 46, 24, 0), + (369, 1, 46, 26, 0), + (370, 1, 46, 28, 0), + (371, 1, 46, 30, 0), + (372, 1, 47, 12, 0), + (373, 1, 47, 14, 0), + (374, 1, 47, 16, 0), + (375, 1, 47, 18, 0), + (376, 1, 47, 20, 0), + (377, 1, 47, 22, 0), + (378, 1, 47, 24, 0), + (379, 1, 47, 26, 0), + (380, 1, 47, 28, 0), + (381, 1, 47, 30, 0), + (382, 1, 50, 12, 0), + (383, 1, 50, 14, 0), + (384, 1, 50, 16, 0), + (385, 1, 50, 18, 0), + (386, 1, 50, 20, 0), + (387, 1, 50, 22, 0), + (388, 1, 50, 24, 0), + (389, 1, 50, 26, 0), + (390, 1, 50, 28, 0), + (391, 1, 50, 30, 0), + (392, 1, 48, 12, 0), + (393, 1, 48, 14, 0), + (394, 1, 48, 16, 0), + (395, 1, 48, 18, 0), + (396, 1, 48, 20, 0), + (397, 1, 48, 22, 0), + (398, 1, 48, 24, 0), + (399, 1, 48, 26, 0), + (400, 1, 48, 28, 0), + (401, 1, 48, 30, 0), + (402, 1, 49, 12, 0), + (403, 1, 49, 14, 0), + (404, 1, 49, 16, 0), + (405, 1, 49, 18, 0), + (406, 1, 49, 20, 0), + (407, 1, 49, 22, 0), + (408, 1, 49, 24, 0), + (409, 1, 49, 26, 0), + (410, 1, 49, 28, 0), + (411, 1, 49, 30, 0), + (412, 1, 263, 1, 0), + (413, 1, 263, 2, 0), + (414, 1, 263, 3, 0), + (415, 1, 263, 4, 0), + (416, 1, 263, 5, 0), + (417, 1, 263, 6, 0), + (418, 1, 262, 5, 0), + (418, 2, 262, 5, 1), + (418, 3, 262, 5, 2), + (418, 4, 262, 5, 3), + (418, 5, 262, 5, 4), + (418, 6, 262, 5, 5), + (418, 7, 262, 5, 6), + (419, 1, 262, 10, 0), + (419, 2, 262, 10, 1), + (419, 3, 262, 10, 2), + (419, 4, 262, 10, 3), + (419, 5, 262, 10, 4), + (419, 6, 262, 10, 5), + (419, 7, 262, 10, 6), + (420, 1, 262, 15, 0), + (420, 2, 262, 15, 1), + (420, 3, 262, 15, 2), + (420, 4, 262, 15, 3), + (420, 5, 262, 15, 4), + (420, 6, 262, 15, 5), + (420, 7, 262, 15, 6), + (421, 1, 262, 20, 0), + (421, 2, 262, 20, 1), + (421, 3, 262, 20, 2), + (421, 4, 262, 20, 3), + (421, 5, 262, 20, 4), + (421, 6, 262, 20, 5), + (421, 7, 262, 20, 6), + (422, 1, 262, 25, 0), + (422, 2, 262, 25, 1), + (422, 3, 262, 25, 2), + (422, 4, 262, 25, 3), + (422, 5, 262, 25, 4), + (422, 6, 262, 25, 5), + (422, 7, 262, 25, 6), + (423, 1, 214, 150, 0), + (424, 1, 214, 300, 0), + (425, 1, 214, 450, 0), + (426, 1, 262, 10, 5), + (426, 2, 262, 10, 4), + (427, 1, 262, 20, 5), + (427, 2, 262, 20, 4), + (428, 1, 262, 30, 5), + (428, 2, 262, 30, 4), + (429, 1, 262, 40, 5), + (429, 2, 262, 40, 4), + (430, 1, 262, 50, 5), + (430, 2, 262, 50, 4), + (434, 1, 125, 13, 13), + (434, 2, 137, 0, 0), + (434, 3, 141, 1, 0), + (434, 4, 139, -6233, 0), + (434, 5, 139, -6265, 0), + (434, 6, 125, 13, 13), + (434, 7, 137, 147, 0), + (434, 8, 141, 1, 0), + (435, 1, 125, 16, 16), + (435, 2, 137, 0, 0), + (435, 3, 141, 1, 0), + (435, 4, 139, -6233, 0), + (435, 5, 139, -6265, 0), + (435, 6, 125, 16, 16), + (435, 7, 137, 147, 0), + (435, 8, 141, 1, 0), + (436, 1, 125, 19, 19), + (436, 2, 137, 0, 0), + (436, 3, 141, 1, 0), + (436, 4, 139, -6233, 0), + (436, 5, 139, -6265, 0), + (436, 6, 125, 19, 19), + (436, 7, 137, 147, 0), + (436, 8, 141, 1, 0), + (437, 1, 274, 12, 0), + (438, 1, 274, 14, 0), + (439, 1, 274, 16, 0), + (440, 1, 278, 530, 21210), + (440, 2, 440, 56, 100), + (441, 1, 278, 540, 23160), + (441, 2, 440, 58, 100), + (442, 1, 278, 550, 25230), + (442, 2, 440, 60, 100), + (443, 1, 169, 100, -1), + (444, 1, 169, 125, -1), + (445, 1, 169, 150, -1), + (446, 1, 265, 54, 0), + (447, 1, 265, 56, 0), + (448, 1, 265, 58, 0), + (449, 1, 172, 13, 0), + (450, 1, 172, 16, 0), + (451, 1, 172, 19, 0), + (452, 1, 172, 22, 0), + (453, 1, 172, 25, 0), + (454, 1, 259, 13, 0), + (455, 1, 259, 16, 0), + (456, 1, 259, 19, 0), + (457, 1, 259, 22, 0), + (458, 1, 259, 25, 0), + (462, 1, 264, 60, 39), + (462, 2, 264, 864, 1061), + (463, 1, 264, 120, 39), + (463, 2, 264, 1728, 1061), + (464, 1, 264, 180, 39), + (464, 2, 264, 2592, 1061), + (468, 1, 264, 180, 41), + (469, 1, 264, 360, 41), + (470, 1, 264, 540, 41), + (471, 1, 264, 864, 57), + (471, 2, 264, 864, 616), + (472, 1, 264, 1728, 57), + (472, 2, 264, 1728, 616), + (473, 1, 264, 2592, 57), + (473, 2, 264, 2592, 616), + (474, 1, 264, 240, 50), + (475, 1, 264, 480, 50), + (476, 1, 264, 720, 50), + (477, 1, 264, 432, 43), + (478, 1, 264, 864, 43), + (479, 1, 264, 1296, 43), + (480, 1, 264, 432, 117), + (481, 1, 264, 864, 117), + (482, 1, 264, 1296, 117), + (483, 1, 264, 540, 58), + (483, 2, 264, 540, 418), + (484, 1, 264, 1080, 58), + (484, 2, 264, 1080, 418), + (485, 1, 264, 1620, 58), + (485, 2, 264, 1620, 418), + (489, 1, 264, 90, 110), + (490, 1, 264, 180, 110), + (491, 1, 264, 270, 110), + (492, 1, 264, 60, 109), + (493, 1, 264, 120, 109), + (494, 1, 264, 180, 109), + (495, 1, 264, 180, 98), + (496, 1, 264, 360, 98), + (497, 1, 264, 540, 98), + (498, 1, 264, 144, 102), + (499, 1, 264, 288, 102), + (500, 1, 264, 432, 102), + (501, 1, 264, 432, 107), + (502, 1, 264, 864, 107), + (503, 1, 264, 1296, 107), + (504, 1, 224, 110, 0), + (505, 1, 224, 120, 0), + (506, 1, 224, 130, 0), + (537, 1, 282, 60, 0), + (538, 1, 282, 75, 0), + (539, 1, 275, 68, 0), + (540, 1, 275, 76, 0), + (541, 1, 275, 84, 0), + (542, 1, 279, 17, 0), + (543, 1, 279, 19, 0), + (544, 1, 279, 21, 0), + (551, 1, 225, 3, 0), + (552, 1, 225, 6, 0), + (553, 1, 225, 9, 0), + (554, 1, 225, 12, 0), + (555, 1, 225, 15, 0), + (556, 1, 225, 3, 0), + (557, 1, 225, 6, 0), + (558, 1, 225, 9, 0), + (559, 1, 225, 12, 0), + (560, 1, 225, 15, 0), + (561, 1, 177, 3, -1), + (562, 1, 177, 6, -1), + (563, 1, 177, 9, -1), + (564, 1, 177, 3, -1), + (565, 1, 177, 6, -1), + (566, 1, 177, 9, -1), + (567, 1, 244, -12, 0), + (574, 1, 281, 25, 0), + (575, 1, 281, 50, 0), + (576, 1, 281, 75, 0), + (577, 1, 277, 20, 0), + (578, 1, 277, 40, 0), + (579, 1, 277, 60, 0), + (580, 1, 267, 1, 4), + (580, 2, 267, 1, 5), + (580, 3, 267, 1, 29), + (581, 1, 267, 1, 2), + (581, 2, 267, 1, 3), + (581, 3, 267, 1, 4), + (581, 4, 267, 1, 5), + (581, 5, 267, 1, 29), + (582, 1, 267, 1, 0), + (582, 2, 267, 1, 1), + (582, 3, 267, 1, 2), + (582, 4, 267, 1, 3), + (582, 5, 267, 1, 4), + (582, 6, 267, 1, 4), + (582, 7, 267, 1, 5), + (582, 8, 267, 1, 6), + (582, 9, 267, 1, 7), + (582, 10, 267, 1, 8), + (582, 11, 267, 1, 9), + (582, 12, 267, 1, 10), + (582, 13, 267, 1, 11), + (582, 14, 267, 1, 12), + (582, 15, 267, 1, 13), + (582, 16, 267, 1, 14), + (582, 17, 267, 1, 28), + (582, 18, 267, 1, 29), + (582, 19, 267, 1, 30), + (583, 1, 264, 7, 73), + (583, 2, 264, 7, 702), + (583, 3, 264, 7, 3826), + (583, 4, 264, 7, 7712), + (584, 1, 264, 14, 73), + (584, 2, 264, 14, 702), + (584, 3, 264, 14, 3826), + (584, 4, 264, 14, 7712), + (585, 1, 264, 21, 73), + (585, 2, 264, 21, 702), + (585, 3, 264, 21, 3826), + (585, 4, 264, 21, 7712), + (586, 1, 255, 12, 0), + (587, 1, 255, 24, 0), + (588, 1, 255, 36, 0), + (589, 1, 303, 500, 500), + (589, 2, 139, 2766, 0), + (590, 1, 303, 1000, 1000), + (590, 2, 139, 2766, 0), + (591, 1, 303, 1500, 1500), + (591, 2, 139, 2766, 0), + (593, 1, 264, 720, 6001), + (593, 2, 264, 720, 3676), + (594, 1, 264, 1440, 6001), + (594, 2, 264, 1440, 3676), + (595, 1, 264, 2160, 6001), + (595, 2, 264, 2160, 3676), + (596, 1, 264, 720, 6000), + (596, 2, 264, 720, 87), + (597, 1, 264, 1440, 6000), + (597, 2, 264, 1440, 87), + (598, 1, 264, 2160, 6000), + (598, 2, 264, 2160, 87), + (599, 1, 266, 2, 0), + (600, 1, 266, 5, 0), + (601, 1, 266, 8, 0), + (602, 1, 266, 2, 0), + (603, 1, 266, 5, 0), + (604, 1, 266, 8, 0), + (605, 1, 256, 1, 0), + (606, 1, 285, 20, 0), + (607, 1, 285, 40, 0), + (608, 1, 285, 60, 0), + (609, 1, 285, 80, 0), + (610, 1, 285, 100, 0), + (611, 1, 283, 20, 0), + (612, 1, 283, 40, 0), + (613, 1, 283, 60, 0), + (614, 1, 283, 80, 0), + (615, 1, 283, 100, 0), + (622, 1, 227, 1, 29), + (622, 2, 227, 1, 42), + (623, 1, 227, 2, 29), + (623, 2, 227, 2, 42), + (624, 1, 227, 3, 29), + (624, 2, 227, 3, 42), + (625, 1, 294, 3, 100), + (626, 1, 294, 6, 100), + (627, 1, 294, 9, 100), + (628, 1, 290, 5, 0), + (629, 1, 290, 10, 0), + (631, 1, 292, 15, 0), + (632, 1, 292, 30, 0), + (633, 1, 292, 45, 0), + (634, 1, 274, 3, 0), + (635, 1, 274, 6, 0), + (636, 1, 274, 10, 0), + (637, 1, 294, 2, 100), + (638, 1, 294, 4, 100), + (639, 1, 294, 6, 100), + (640, 1, 294, 7, 100), + (641, 1, 294, 8, 100), + (642, 1, 294, 9, 100), + (644, 1, 217, 0, 32000), + (644, 2, 346, 59, 0), + (649, 1, 243, 15, 0), + (650, 1, 243, 25, 0), + (651, 1, 243, 35, 0), + (652, 1, 293, 25, 0), + (653, 1, 293, 50, 0), + (654, 1, 293, 75, 0), + (655, 1, 127, 10, 10), + (655, 2, 137, 32, 0), + (655, 3, 127, 10, 10), + (655, 4, 137, 33, 0), + (655, 5, 127, 10, 10), + (655, 6, 137, 82, 0), + (655, 7, 127, 2, 2), + (655, 8, 137, 152, 0), + (655, 9, 143, 3000, 0), + (656, 1, 127, 25, 25), + (656, 2, 137, 32, 0), + (656, 3, 127, 25, 25), + (656, 4, 137, 33, 0), + (656, 5, 127, 25, 25), + (656, 6, 137, 82, 0), + (656, 7, 127, 5, 5), + (656, 8, 137, 152, 0), + (656, 9, 143, 3000, 0), + (657, 1, 127, 50, 50), + (657, 2, 137, 32, 0), + (657, 3, 127, 50, 50), + (657, 4, 137, 33, 0), + (657, 5, 127, 50, 50), + (657, 6, 137, 82, 0), + (657, 7, 127, 10, 10), + (657, 8, 137, 152, 0), + (657, 9, 143, 3000, 0), + (658, 1, 15, 1, 0), + (659, 1, 15, 2, 0), + (660, 1, 15, 3, 0), + (661, 1, 0, 1, 0), + (662, 1, 0, 2, 0), + (663, 1, 0, 3, 0), + (665, 1, 270, 10, 0), + (666, 1, 270, 15, 0), + (667, 1, 270, 25, 0), + (668, 1, 270, 55, 0), + (669, 1, 270, 60, 0), + (670, 1, 270, 65, 0), + (671, 1, 241, 95, 0), + (672, 1, 271, 28, 0), + (673, 1, 271, 35, 0), + (674, 1, 0, 4, 0), + (675, 1, 0, 5, 0), + (676, 1, 246, 325, 0), + (677, 1, 246, 350, 0), + (678, 1, 221, 3, 0), + (679, 1, 221, 6, 0), + (680, 1, 221, 9, 0), + (681, 1, 221, 12, 0), + (682, 1, 221, 15, 0), + (683, 1, 189, 1, 0), + (684, 1, 189, 2, 0), + (685, 1, 189, 3, 0), + (686, 1, 200, 10, 0), + (687, 1, 200, 20, 0), + (688, 1, 200, 30, 0), + (689, 1, 200, 40, 0), + (690, 1, 200, 50, 0), + (691, 1, 248, 100, 0), + (692, 1, 229, 5, 0), + (693, 1, 229, 10, 0), + (694, 1, 229, 15, 0), + (695, 1, 247, 10, 53), + (696, 1, 247, 20, 53), + (697, 1, 247, 30, 53), + (698, 1, 247, 40, 53), + (699, 1, 247, 50, 53), + (700, 1, 260, 8, 23), + (700, 2, 260, 8, 24), + (700, 3, 260, 8, 25), + (700, 4, 260, 8, 26), + (701, 1, 260, 8, 50), + (724, 1, 218, 1, 0), + (725, 1, 218, 2, 0), + (726, 1, 218, 3, 0), + (727, 1, 218, 4, 0), + (728, 1, 218, 5, 0), + (729, 1, 280, 4, 0), + (730, 1, 280, 8, 0), + (731, 1, 280, 12, 0), + (732, 1, 280, 16, 0), + (733, 1, 280, 20, 0), + (734, 1, 237, 1, 0), + (735, 1, 265, 54, 0), + (736, 1, 265, 56, 0), + (737, 1, 265, 58, 0), + (738, 1, 114, -5, 0), + (739, 1, 114, -10, 0), + (740, 1, 114, -20, 0), + (754, 1, 264, 18, 153), + (755, 1, 264, 36, 153), + (756, 1, 264, 54, 153), + (762, 1, 247, 10, 53), + (763, 1, 247, 20, 53), + (764, 1, 247, 30, 53), + (765, 1, 247, 40, 53), + (766, 1, 247, 50, 53), + (767, 1, 273, 3, 0), + (768, 1, 273, 6, 0), + (769, 1, 273, 9, 0), + (770, 1, 294, 7, 100), + (771, 1, 294, 8, 100), + (772, 1, 294, 9, 100), + (776, 1, 242, 10, 0), + (777, 1, 242, 20, 0), + (778, 1, 242, 30, 0), + (779, 1, 242, 40, 0), + (780, 1, 242, 50, 0), + (781, 1, 287, 1, 1), + (781, 2, 137, 31, 0), + (781, 3, 136, 5, 0), + (782, 1, 264, 432, 35), + (783, 1, 264, 864, 35), + (784, 1, 264, 1296, 35), + (790, 1, 218, 1, 0), + (791, 1, 218, 2, 0), + (792, 1, 218, 3, 0), + (793, 1, 218, 4, 0), + (794, 1, 218, 5, 0), + (795, 1, 280, 4, 0), + (796, 1, 280, 8, 0), + (797, 1, 280, 12, 0), + (798, 1, 280, 16, 0), + (799, 1, 280, 20, 0), + (800, 1, 215, 2, 0), + (801, 1, 215, 5, 0), + (802, 1, 215, 10, 0), + (803, 1, 213, 2, 0), + (804, 1, 213, 5, 0), + (805, 1, 213, 10, 0), + (806, 1, 249, 1, 0), + (807, 1, 292, 5, 0), + (808, 1, 292, 10, 0), + (809, 1, 292, 15, 0), + (810, 1, 239, 10, 0), + (811, 1, 239, 20, 0), + (812, 1, 239, 30, 0), + (813, 1, 239, 40, 0), + (814, 1, 239, 50, 0), + (815, 1, 279, 7, 0), + (816, 1, 279, 11, 0), + (817, 1, 279, 15, 0), + (818, 1, 279, 17, 0), + (819, 1, 279, 19, 0), + (820, 1, 220, 10, 26), + (820, 2, 220, 10, 30), + (820, 3, 220, 10, 38), + (821, 1, 220, 20, 26), + (821, 2, 220, 20, 30), + (821, 3, 220, 20, 38), + (822, 1, 220, 30, 26), + (822, 2, 220, 30, 30), + (822, 3, 220, 30, 38), + (823, 1, 222, 20, 0), + (824, 1, 222, 40, 0), + (825, 1, 222, 60, 0), + (826, 1, 222, 80, 0), + (827, 1, 222, 100, 0), + (834, 1, 218, 1, 0), + (835, 1, 218, 2, 0), + (836, 1, 218, 3, 0), + (837, 1, 218, 4, 0), + (838, 1, 218, 5, 0), + (839, 1, 280, 4, 0), + (840, 1, 280, 8, 0), + (841, 1, 280, 12, 0), + (842, 1, 280, 16, 0), + (843, 1, 280, 20, 0), + (844, 1, 274, 12, 0), + (845, 1, 274, 14, 0), + (846, 1, 258, 5, 0), + (847, 1, 258, 10, 0), + (848, 1, 258, 15, 0), + (849, 1, 264, 240, 180), + (850, 1, 264, 480, 180), + (851, 1, 264, 720, 180), + (852, 1, 231, 1, 0), + (853, 1, 231, 2, 0), + (854, 1, 231, 3, 0), + (855, 1, 220, 5, 10), + (856, 1, 220, 10, 10), + (857, 1, 220, 15, 10), + (858, 1, 220, 20, 10), + (859, 1, 220, 25, 10), + (864, 1, 216, 10, 0), + (864, 2, 216, 10, 1), + (864, 3, 216, 10, 2), + (864, 4, 216, 10, 3), + (864, 5, 216, 10, 10), + (864, 6, 216, 10, 28), + (864, 7, 216, 10, 30), + (864, 8, 216, 10, 36), + (864, 9, 216, 10, 77), + (865, 1, 216, 20, 0), + (865, 2, 216, 20, 1), + (865, 3, 216, 20, 2), + (865, 4, 216, 20, 3), + (865, 5, 216, 20, 10), + (865, 6, 216, 20, 28), + (865, 7, 216, 20, 30), + (865, 8, 216, 20, 36), + (865, 9, 216, 20, 77), + (866, 1, 216, 30, 0), + (866, 2, 216, 30, 1), + (866, 3, 216, 30, 2), + (866, 4, 216, 30, 3), + (866, 5, 216, 30, 10), + (866, 6, 216, 30, 28), + (866, 7, 216, 30, 30), + (866, 8, 216, 30, 36), + (866, 9, 216, 30, 77), + (867, 1, 59, -3, 0), + (868, 1, 59, -6, 0), + (869, 1, 59, -9, 0), + (870, 1, 59, -12, 0), + (871, 1, 59, -15, 0), + (878, 1, 252, 10, 0), + (879, 1, 252, 20, 0), + (880, 1, 252, 30, 0), + (881, 1, 245, 10, 0), + (882, 1, 245, 20, 0), + (883, 1, 245, 30, 0), + (884, 1, 245, 40, 0), + (885, 1, 245, 50, 0), + (886, 1, 264, 576, 102), + (887, 1, 264, 720, 102), + (888, 1, 250, 10, 0), + (889, 1, 250, 20, 0), + (890, 1, 250, 30, 0), + (891, 1, 250, 40, 0), + (892, 1, 250, 50, 0), + (893, 1, 303, 2000, 2000), + (893, 2, 139, 2766, 0), + (894, 1, 303, 2500, 2500), + (894, 2, 139, 2766, 0), + (895, 1, 59, -3, 0), + (896, 1, 59, -6, 0), + (897, 1, 59, -9, 0), + (898, 1, 59, -12, 0), + (899, 1, 59, -15, 0), + (907, 1, 69, 100, 0), + (908, 1, 69, 200, 0), + (909, 1, 69, 300, 0), + (910, 1, 69, 400, 0), + (911, 1, 69, 500, 0), + (915, 1, 220, 5, 10), + (915, 2, 220, 5, 30), + (916, 1, 220, 10, 10), + (916, 2, 220, 10, 30), + (917, 1, 220, 15, 10), + (917, 2, 220, 15, 30), + (918, 1, 230, 2, 0), + (919, 1, 230, 4, 0), + (920, 1, 230, 6, 0), + (924, 1, 294, 10, 100), + (925, 1, 294, 11, 100), + (934, 1, 169, 15, -1), + (935, 1, 169, 30, -1), + (936, 1, 169, 60, -1), + (937, 1, 169, 15, 0), + (937, 2, 169, 15, 1), + (937, 3, 169, 15, 2), + (937, 4, 169, 15, 3), + (937, 5, 169, 15, 7), + (937, 6, 169, 15, 8), + (937, 7, 169, 15, 10), + (937, 8, 169, 15, 28), + (937, 9, 169, 15, 30), + (937, 10, 169, 15, 36), + (937, 11, 169, 15, 51), + (938, 1, 169, 40, 0), + (938, 2, 169, 40, 1), + (938, 3, 169, 40, 2), + (938, 4, 169, 40, 3), + (938, 5, 169, 40, 7), + (938, 6, 169, 40, 8), + (938, 7, 169, 40, 10), + (938, 8, 169, 40, 28), + (938, 9, 169, 40, 30), + (938, 10, 169, 40, 36), + (938, 11, 169, 30, 51), + (939, 1, 169, 75, 0), + (939, 2, 169, 75, 1), + (939, 3, 169, 75, 2), + (939, 4, 169, 75, 3), + (939, 5, 169, 75, 7), + (939, 6, 169, 75, 8), + (939, 7, 169, 75, 10), + (939, 8, 169, 75, 28), + (939, 9, 169, 75, 30), + (939, 10, 169, 75, 36), + (939, 11, 169, 60, 51), + (940, 1, 169, 15, 0), + (940, 2, 169, 15, 1), + (940, 3, 169, 15, 2), + (940, 4, 169, 15, 3), + (940, 5, 169, 15, 7), + (940, 6, 169, 15, 8), + (940, 7, 169, 15, 10), + (940, 8, 169, 15, 28), + (940, 9, 169, 15, 30), + (940, 10, 169, 15, 36), + (940, 11, 169, 15, 51), + (940, 12, 169, 15, 77), + (941, 1, 169, 40, 0), + (941, 2, 169, 40, 1), + (941, 3, 169, 40, 2), + (941, 4, 169, 40, 3), + (941, 5, 169, 30, 7), + (941, 6, 169, 40, 8), + (941, 7, 169, 40, 10), + (941, 8, 169, 40, 28), + (941, 9, 169, 40, 30), + (941, 10, 169, 40, 36), + (941, 11, 169, 40, 51), + (941, 12, 169, 40, 77), + (942, 1, 169, 75, 0), + (942, 2, 169, 75, 1), + (942, 3, 169, 75, 2), + (942, 4, 169, 75, 3), + (942, 5, 169, 60, 7), + (942, 6, 169, 75, 8), + (942, 7, 169, 75, 10), + (942, 8, 169, 75, 28), + (942, 9, 169, 75, 30), + (942, 10, 169, 75, 36), + (942, 11, 169, 75, 51), + (942, 12, 169, 75, 77), + (943, 1, 169, 146, -1), + (944, 1, 169, 172, -1), + (945, 1, 169, 198, -1), + (946, 1, 169, 175, 0), + (946, 2, 169, 175, 1), + (946, 3, 169, 175, 2), + (946, 4, 169, 175, 3), + (946, 5, 169, 175, 7), + (946, 6, 169, 175, 8), + (946, 7, 169, 175, 10), + (946, 8, 169, 175, 28), + (946, 9, 169, 175, 30), + (946, 10, 169, 175, 36), + (946, 11, 169, 146, 51), + (947, 1, 169, 200, 0), + (947, 2, 169, 200, 1), + (947, 3, 169, 200, 2), + (947, 4, 169, 200, 3), + (947, 5, 169, 200, 7), + (947, 6, 169, 200, 8), + (947, 7, 169, 200, 10), + (947, 8, 169, 200, 28), + (947, 9, 169, 200, 30), + (947, 10, 169, 200, 36), + (947, 11, 169, 172, 51), + (948, 1, 169, 225, 0), + (948, 2, 169, 225, 1), + (948, 3, 169, 225, 2), + (948, 4, 169, 225, 3), + (948, 5, 169, 225, 7), + (948, 6, 169, 225, 8), + (948, 7, 169, 225, 10), + (948, 8, 169, 225, 28), + (948, 9, 169, 225, 30), + (948, 10, 169, 225, 36), + (948, 11, 169, 198, 51), + (949, 1, 169, 175, 0), + (949, 2, 169, 175, 1), + (949, 3, 169, 175, 2), + (949, 4, 169, 175, 3), + (949, 5, 169, 161, 7), + (949, 6, 169, 175, 8), + (949, 7, 169, 175, 10), + (949, 8, 169, 175, 28), + (949, 9, 169, 175, 30), + (949, 10, 169, 175, 36), + (949, 11, 169, 175, 51), + (949, 12, 169, 175, 77), + (950, 1, 169, 200, 0), + (950, 2, 169, 200, 1), + (950, 3, 169, 200, 2), + (950, 4, 169, 200, 3), + (950, 5, 169, 187, 7), + (950, 6, 169, 200, 8), + (950, 7, 169, 200, 10), + (950, 8, 169, 200, 28), + (950, 9, 169, 200, 30), + (950, 10, 169, 200, 36), + (950, 11, 169, 200, 51), + (950, 12, 169, 200, 77), + (951, 1, 169, 225, 0), + (951, 2, 169, 225, 1), + (951, 3, 169, 225, 2), + (951, 4, 169, 225, 3), + (951, 5, 169, 213, 7), + (951, 6, 169, 225, 8), + (951, 7, 169, 225, 10), + (951, 8, 169, 225, 28), + (951, 9, 169, 225, 30), + (951, 10, 169, 225, 36), + (951, 11, 169, 225, 51), + (951, 12, 169, 225, 77), + (952, 1, 214, 125, 0), + (953, 1, 214, 250, 0), + (954, 1, 214, 375, 0), + (955, 1, 262, 10, 4), + (955, 2, 262, 10, 5), + (956, 1, 262, 20, 4), + (956, 2, 262, 20, 5), + (957, 1, 262, 30, 4), + (957, 2, 262, 30, 5), + (958, 1, 262, 40, 4), + (958, 2, 262, 40, 5), + (959, 1, 262, 50, 4), + (959, 2, 262, 50, 5), + (962, 1, 232, 2, 4544), + (963, 1, 232, 4, 4544), + (964, 1, 232, 6, 4544), + (965, 1, 232, 8, 4544), + (966, 1, 232, 10, 4544), + (975, 1, 264, 864, 102), + (976, 1, 131, 100, 0), + (976, 2, 137, 33, 0), + (978, 1, 14, 1, 0), + (978, 2, 246, 350, 0), + (979, 1, 268, 10, 63), + (980, 1, 268, 25, 63), + (981, 1, 268, 50, 63), + (982, 1, 268, 10, 60), + (983, 1, 268, 25, 60), + (984, 1, 268, 50, 60), + (985, 1, 268, 10, 65), + (986, 1, 268, 25, 65), + (987, 1, 268, 50, 65), + (988, 1, 268, 10, 64), + (989, 1, 268, 25, 64), + (990, 1, 268, 50, 64), + (991, 1, 268, 10, 69), + (992, 1, 268, 25, 69), + (993, 1, 268, 50, 69), + (994, 1, 268, 10, 61), + (995, 1, 268, 25, 61), + (996, 1, 268, 50, 61), + (997, 1, 331, 5, 0), + (998, 1, 331, 15, 0), + (999, 1, 331, 25, 0), + (1001, 1, 262, 30, 0), + (1001, 2, 262, 30, 1), + (1001, 3, 262, 30, 2), + (1001, 4, 262, 30, 3), + (1001, 5, 262, 30, 4), + (1001, 6, 262, 30, 5), + (1001, 7, 262, 30, 6), + (1002, 1, 262, 35, 0), + (1002, 2, 262, 35, 1), + (1002, 3, 262, 35, 2), + (1002, 4, 262, 35, 3), + (1002, 5, 262, 35, 4), + (1002, 6, 262, 35, 5), + (1002, 7, 262, 35, 6), + (1003, 1, 262, 40, 0), + (1003, 2, 262, 40, 1), + (1003, 3, 262, 40, 2), + (1003, 4, 262, 40, 3), + (1003, 5, 262, 40, 4), + (1003, 6, 262, 40, 5), + (1003, 7, 262, 40, 6), + (1004, 1, 262, 45, 0), + (1004, 2, 262, 45, 1), + (1004, 3, 262, 45, 2), + (1004, 4, 262, 45, 3), + (1004, 5, 262, 45, 4), + (1004, 6, 262, 45, 5), + (1004, 7, 262, 45, 6), + (1005, 1, 262, 50, 0), + (1005, 2, 262, 50, 1), + (1005, 3, 262, 50, 2), + (1005, 4, 262, 50, 3), + (1005, 5, 262, 50, 4), + (1005, 6, 262, 50, 5), + (1005, 7, 262, 50, 6), + (1006, 1, 262, 5, 7), + (1006, 2, 262, 5, 8), + (1006, 3, 262, 5, 9), + (1006, 4, 262, 5, 10), + (1006, 5, 262, 5, 11), + (1007, 1, 262, 10, 7), + (1007, 2, 262, 10, 8), + (1007, 3, 262, 10, 9), + (1007, 4, 262, 10, 10), + (1007, 5, 262, 10, 11), + (1008, 1, 262, 15, 7), + (1008, 2, 262, 15, 8), + (1008, 3, 262, 15, 9), + (1008, 4, 262, 15, 10), + (1008, 5, 262, 15, 11), + (1009, 1, 262, 20, 7), + (1009, 2, 262, 20, 8), + (1009, 3, 262, 20, 9), + (1009, 4, 262, 20, 10), + (1009, 5, 262, 20, 11), + (1010, 1, 262, 25, 7), + (1010, 2, 262, 25, 8), + (1010, 3, 262, 25, 9), + (1010, 4, 262, 25, 10), + (1010, 5, 262, 25, 11), + (1011, 1, 262, 8, 7), + (1011, 2, 262, 8, 8), + (1011, 3, 262, 8, 9), + (1011, 4, 262, 8, 10), + (1011, 5, 262, 8, 11), + (1012, 1, 262, 16, 7), + (1012, 2, 262, 16, 8), + (1012, 3, 262, 16, 9), + (1012, 4, 262, 16, 10), + (1012, 5, 262, 16, 11), + (1013, 1, 262, 24, 7), + (1013, 2, 262, 24, 8), + (1013, 3, 262, 24, 9), + (1013, 4, 262, 24, 10), + (1013, 5, 262, 24, 11), + (1014, 1, 262, 32, 7), + (1014, 2, 262, 32, 8), + (1014, 3, 262, 32, 9), + (1014, 4, 262, 32, 10), + (1014, 5, 262, 32, 11), + (1015, 1, 262, 40, 7), + (1015, 2, 262, 40, 8), + (1015, 3, 262, 40, 9), + (1015, 4, 262, 40, 10), + (1015, 5, 262, 40, 11), + (1016, 1, 262, 50, 7), + (1016, 2, 262, 50, 8), + (1016, 3, 262, 50, 9), + (1016, 4, 262, 50, 10), + (1016, 5, 262, 50, 11), + (1021, 1, 327, 1, 0), + (1022, 1, 327, 2, 0), + (1023, 1, 327, 3, 0), + (1024, 1, 327, 4, 0), + (1025, 1, 327, 5, 0), + (1026, 1, 328, 50, 0), + (1027, 1, 328, 100, 0), + (1028, 1, 328, 150, 0), + (1029, 1, 328, 200, 0), + (1030, 1, 328, 250, 0), + (1031, 1, 0, 6, 0), + (1032, 1, 0, 7, 0), + (1033, 1, 0, 8, 0), + (1034, 1, 0, 9, 0), + (1035, 1, 0, 10, 0), + (1036, 1, 189, 4, 0), + (1037, 1, 189, 5, 0), + (1038, 1, 189, 6, 0), + (1041, 1, 330, 25, 0), + (1041, 2, 330, 25, 1), + (1041, 3, 330, 25, 2), + (1041, 4, 330, 25, 3), + (1041, 5, 330, 25, 28), + (1041, 6, 330, 25, 36), + (1041, 7, 330, 25, 77), + (1042, 1, 330, 50, 0), + (1042, 2, 330, 50, 1), + (1042, 3, 330, 50, 2), + (1042, 4, 330, 50, 3), + (1042, 5, 330, 50, 28), + (1042, 6, 330, 50, 36), + (1042, 7, 330, 50, 77), + (1043, 1, 330, 75, 0), + (1043, 2, 330, 75, 1), + (1043, 3, 330, 75, 2), + (1043, 4, 330, 75, 3), + (1043, 5, 330, 75, 28), + (1043, 6, 330, 75, 36), + (1043, 7, 330, 75, 77), + (1044, 1, 330, 25, 0), + (1044, 2, 330, 25, 1), + (1044, 3, 330, 25, 2), + (1044, 4, 330, 25, 3), + (1044, 5, 330, 25, 28), + (1044, 6, 330, 25, 36), + (1045, 1, 330, 50, 0), + (1045, 2, 330, 50, 1), + (1045, 3, 330, 50, 2), + (1045, 4, 330, 50, 3), + (1045, 5, 330, 50, 28), + (1045, 6, 330, 50, 36), + (1046, 1, 330, 75, 0), + (1046, 2, 330, 75, 1), + (1046, 3, 330, 75, 2), + (1046, 4, 330, 75, 3), + (1046, 5, 330, 75, 28), + (1046, 6, 330, 75, 36), + (1047, 1, 330, 25, 0), + (1047, 2, 330, 25, 1), + (1047, 3, 330, 25, 2), + (1047, 4, 330, 25, 3), + (1047, 5, 330, 25, 28), + (1047, 6, 330, 25, 36), + (1047, 7, 330, 25, 77), + (1048, 1, 330, 50, 0), + (1048, 2, 330, 50, 1), + (1048, 3, 330, 50, 2), + (1048, 4, 330, 50, 3), + (1048, 5, 330, 50, 28), + (1048, 6, 330, 50, 36), + (1048, 7, 330, 50, 77), + (1049, 1, 330, 75, 0), + (1049, 2, 330, 75, 1), + (1049, 3, 330, 75, 2), + (1049, 4, 330, 75, 3), + (1049, 5, 330, 75, 28), + (1049, 6, 330, 75, 36), + (1049, 7, 330, 75, 77), + (1050, 1, 330, 15, 0), + (1050, 2, 330, 15, 1), + (1050, 3, 330, 15, 2), + (1050, 4, 330, 15, 3), + (1050, 5, 330, 15, 28), + (1050, 6, 330, 15, 36), + (1050, 7, 330, 15, 77), + (1051, 1, 330, 30, 0), + (1051, 2, 330, 30, 1), + (1051, 3, 330, 30, 2), + (1051, 4, 330, 30, 3), + (1051, 5, 330, 30, 28), + (1051, 6, 330, 30, 36), + (1051, 7, 330, 30, 77), + (1052, 1, 330, 50, 0), + (1052, 2, 330, 50, 1), + (1052, 3, 330, 50, 2), + (1052, 4, 330, 50, 3), + (1052, 5, 330, 50, 28), + (1052, 6, 330, 50, 36), + (1052, 7, 330, 50, 77), + (1053, 1, 278, 560, 27200), + (1053, 2, 440, 61, 100), + (1054, 1, 278, 580, 30135), + (1054, 2, 440, 63, 100), + (1055, 1, 278, 600, 32780), + (1055, 2, 440, 65, 100), + (1056, 1, 317, 1, 0), + (1057, 1, 317, 2, 0), + (1058, 1, 317, 3, 0), + (1059, 1, 317, 4, 0), + (1060, 1, 317, 5, 0), + (1061, 1, 172, 26, 0), + (1062, 1, 172, 27, 0), + (1063, 1, 172, 28, 0), + (1064, 1, 172, 30, 0), + (1065, 1, 172, 32, 0), + (1066, 1, 259, 27, 0), + (1067, 1, 259, 29, 0), + (1068, 1, 259, 31, 0), + (1069, 1, 259, 33, 0), + (1070, 1, 259, 35, 0), + (1071, 1, 326, 1, 0), + (1072, 1, 318, 1, 0), + (1073, 1, 318, 2, 0), + (1074, 1, 318, 3, 0), + (1075, 1, 318, 4, 0), + (1076, 1, 318, 5, 0), + (1083, 1, 125, 22, 22), + (1083, 2, 137, 0, 0), + (1083, 3, 141, 1, 0), + (1083, 4, 139, -6233, 0), + (1083, 5, 139, -6265, 0), + (1083, 6, 125, 22, 22), + (1083, 7, 137, 147, 0), + (1083, 8, 141, 1, 0), + (1084, 1, 125, 25, 25), + (1084, 2, 137, 0, 0), + (1084, 3, 141, 1, 0), + (1084, 4, 139, -6233, 0), + (1084, 5, 139, -6265, 0), + (1084, 6, 125, 25, 25), + (1084, 7, 137, 147, 0), + (1084, 8, 141, 1, 0), + (1085, 1, 125, 28, 28), + (1085, 2, 137, 0, 0), + (1085, 3, 141, 1, 0), + (1085, 4, 139, -6233, 0), + (1085, 5, 139, -6265, 0), + (1085, 6, 125, 28, 28), + (1085, 7, 137, 147, 0), + (1085, 8, 141, 1, 0), + (1086, 1, 274, 18, 0), + (1087, 1, 274, 20, 0), + (1088, 1, 274, 22, 0), + (1089, 1, 268, 10, 58), + (1090, 1, 268, 25, 58), + (1091, 1, 268, 50, 58), + (1092, 1, 238, 1, 0), + (1093, 1, 304, -20, 0), + (1094, 1, 304, -40, 0), + (1095, 1, 304, -60, 0), + (1096, 1, 304, -80, 0), + (1097, 1, 304, -100, 0), + (1099, 1, 273, 12, 0), + (1100, 1, 273, 15, 0), + (1101, 1, 273, 18, 0), + (1107, 1, 294, 2, 100), + (1108, 1, 294, 4, 100), + (1109, 1, 294, 6, 100), + (1113, 1, 331, 30, 0), + (1114, 1, 331, 35, 0), + (1115, 1, 331, 40, 0), + (1122, 1, 308, 1, 0), + (1129, 1, 267, 1, 24), + (1129, 2, 267, 1, 25), + (1129, 3, 267, 1, 26), + (1130, 1, 267, 1, 18), + (1130, 2, 267, 1, 19), + (1130, 3, 267, 1, 20), + (1130, 4, 267, 1, 21), + (1130, 5, 267, 1, 22), + (1130, 6, 267, 1, 23), + (1130, 7, 267, 1, 24), + (1130, 8, 267, 1, 25), + (1130, 9, 267, 1, 26), + (1131, 1, 185, 10, 51), + (1132, 1, 185, 20, 51), + (1133, 1, 185, 30, 51), + (1134, 1, 220, 32, 74), + (1135, 1, 220, 64, 74), + (1136, 1, 220, 96, 74), + (1137, 1, 310, 180000, 0), + (1137, 2, 139, 5027, 0), + (1137, 3, 310, 180000, 0), + (1137, 4, 139, 5028, 0), + (1137, 5, 310, 180000, 0), + (1137, 6, 139, 5029, 0), + (1137, 7, 310, 180000, 0), + (1137, 8, 139, 5030, 0), + (1137, 9, 310, 180000, 0), + (1137, 10, 139, 5031, 0), + (1137, 11, 310, 180000, 0), + (1137, 12, 139, 5032, 0), + (1137, 13, 310, 180000, 0), + (1137, 14, 139, 8476, 0), + (1138, 1, 310, 360000, 0), + (1138, 2, 139, 5027, 0), + (1138, 3, 310, 360000, 0), + (1138, 4, 139, 5028, 0), + (1138, 5, 310, 360000, 0), + (1138, 6, 139, 5029, 0), + (1138, 7, 310, 360000, 0), + (1138, 8, 139, 5030, 0), + (1138, 9, 310, 360000, 0), + (1138, 10, 139, 5031, 0), + (1138, 11, 310, 360000, 0), + (1138, 12, 139, 5032, 0), + (1138, 13, 310, 360000, 0), + (1138, 14, 139, 8476, 0), + (1139, 1, 310, 540000, 0), + (1139, 2, 139, 5027, 0), + (1139, 3, 310, 540000, 0), + (1139, 4, 139, 5028, 0), + (1139, 5, 310, 540000, 0), + (1139, 6, 139, 5029, 0), + (1139, 7, 310, 540000, 0), + (1139, 8, 139, 5030, 0), + (1139, 9, 310, 540000, 0), + (1139, 10, 139, 5031, 0), + (1139, 11, 310, 540000, 0), + (1139, 12, 139, 5032, 0), + (1139, 13, 310, 540000, 0), + (1139, 14, 139, 8476, 0), + (1140, 1, 216, 10, 51), + (1141, 1, 216, 20, 51), + (1142, 1, 216, 30, 51), + (1155, 1, 128, 25, 0), + (1155, 2, 139, 5027, 0), + (1155, 3, 128, 25, 0), + (1155, 4, 139, 5028, 0), + (1155, 5, 128, 25, 0), + (1155, 6, 139, 5029, 0), + (1155, 7, 128, 25, 0), + (1155, 8, 139, 5030, 0), + (1155, 9, 128, 25, 0), + (1155, 10, 139, 5031, 0), + (1155, 11, 128, 25, 0), + (1155, 12, 139, 5032, 0), + (1155, 13, 128, 25, 0), + (1155, 14, 139, 8476, 0), + (1156, 1, 128, 50, 0), + (1156, 2, 139, 5027, 0), + (1156, 3, 128, 50, 0), + (1156, 4, 139, 5028, 0), + (1156, 5, 128, 50, 0), + (1156, 6, 139, 5029, 0), + (1156, 7, 128, 50, 0), + (1156, 8, 139, 5030, 0), + (1156, 9, 128, 50, 0), + (1156, 10, 139, 5031, 0), + (1156, 11, 128, 50, 0), + (1156, 12, 139, 5032, 0), + (1156, 13, 128, 50, 0), + (1156, 14, 139, 8476, 0), + (1157, 1, 128, 100, 0), + (1157, 2, 139, 5027, 0), + (1157, 3, 128, 100, 0), + (1157, 4, 139, 5028, 0), + (1157, 5, 128, 100, 0), + (1157, 6, 139, 5029, 0), + (1157, 7, 128, 100, 0), + (1157, 8, 139, 5030, 0), + (1157, 9, 128, 100, 0), + (1157, 10, 139, 5031, 0), + (1157, 11, 128, 100, 0), + (1157, 12, 139, 5032, 0), + (1157, 13, 128, 100, 0), + (1157, 14, 139, 8476, 0), + (1158, 1, 220, 128, 74), + (1159, 1, 220, 160, 74), + (1160, 1, 220, 192, 74), + (1161, 1, 220, 224, 74), + (1162, 1, 220, 256, 74), + (1163, 1, 279, 23, 0), + (1164, 1, 279, 25, 0), + (1165, 1, 279, 27, 0), + (1166, 1, 224, 20, 74), + (1166, 2, 173, 1, 0), + (1167, 1, 224, 35, 74), + (1167, 2, 173, 1, 0), + (1168, 1, 224, 50, 74), + (1168, 2, 173, 2, 0), + (1172, 1, 292, 50, 0), + (1173, 1, 292, 55, 0), + (1174, 1, 292, 60, 0), + (1181, 1, 305, -20, 0), + (1182, 1, 305, -40, 0), + (1183, 1, 305, -60, 0), + (1184, 1, 305, -80, 0), + (1185, 1, 305, -100, 0), + (1186, 1, 319, 3, 0), + (1187, 1, 319, 6, 0), + (1188, 1, 319, 10, 0), + (1196, 1, 220, 20, 7), + (1197, 1, 220, 40, 7), + (1198, 1, 220, 60, 7), + (1199, 1, 220, 80, 7), + (1200, 1, 220, 100, 7), + (1210, 1, 294, 0, 107), + (1211, 1, 294, 0, 115), + (1212, 1, 294, 0, 125), + (1213, 1, 294, 0, 107), + (1214, 1, 294, 0, 115), + (1215, 1, 294, 0, 125), + (1216, 1, 132, 2, 2), + (1217, 1, 132, 5, 5), + (1218, 1, 132, 10, 10), + (1219, 1, 339, 3, 8105), + (1219, 2, 142, 65, 0), + (1219, 3, 311, 0, 0), + (1219, 4, 134, 70, 0), + (1219, 5, 348, 10, 0), + (1219, 6, 137, 0, 0), + (1219, 7, 339, 3, 8105), + (1219, 8, 142, 65, 0), + (1219, 9, 311, 0, 0), + (1219, 10, 134, 70, 0), + (1219, 11, 348, 10, 0), + (1219, 12, 137, 100, 0), + (1219, 13, 339, 3, 8105), + (1219, 14, 142, 65, 0), + (1219, 15, 311, 0, 0), + (1219, 16, 134, 70, 0), + (1219, 17, 348, 10, 0), + (1219, 18, 137, 79, 0), + (1219, 19, 339, 3, 8105), + (1219, 20, 142, 65, 0), + (1219, 21, 311, 0, 0), + (1219, 22, 134, 70, 0), + (1219, 23, 348, 10, 0), + (1219, 24, 137, 147, 0), + (1220, 1, 339, 6, 8105), + (1220, 2, 142, 65, 0), + (1220, 3, 311, 0, 0), + (1220, 4, 134, 70, 0), + (1220, 5, 348, 10, 0), + (1220, 6, 137, 0, 0), + (1220, 7, 339, 6, 8105), + (1220, 8, 142, 65, 0), + (1220, 9, 311, 0, 0), + (1220, 10, 134, 70, 0), + (1220, 11, 348, 10, 0), + (1220, 12, 137, 100, 0), + (1220, 13, 339, 6, 8105), + (1220, 14, 142, 65, 0), + (1220, 15, 311, 0, 0), + (1220, 16, 134, 70, 0), + (1220, 17, 348, 10, 0), + (1220, 18, 137, 79, 0), + (1220, 19, 339, 6, 8105), + (1220, 20, 142, 65, 0), + (1220, 21, 311, 0, 0), + (1220, 22, 134, 70, 0), + (1220, 23, 348, 10, 0), + (1220, 24, 137, 147, 0), + (1221, 1, 339, 10, 8105), + (1221, 2, 142, 65, 0), + (1221, 3, 311, 0, 0), + (1221, 4, 134, 70, 0), + (1221, 5, 348, 10, 0), + (1221, 6, 137, 0, 0), + (1221, 7, 339, 10, 8105), + (1221, 8, 142, 65, 0), + (1221, 9, 311, 0, 0), + (1221, 10, 134, 70, 0), + (1221, 11, 348, 10, 0), + (1221, 12, 137, 100, 0), + (1221, 13, 339, 10, 8105), + (1221, 14, 142, 65, 0), + (1221, 15, 311, 0, 0), + (1221, 16, 134, 70, 0), + (1221, 17, 348, 10, 0), + (1221, 18, 137, 79, 0), + (1221, 19, 339, 10, 8105), + (1221, 20, 142, 65, 0), + (1221, 21, 311, 0, 0), + (1221, 22, 134, 70, 0), + (1221, 23, 348, 10, 0), + (1221, 24, 137, 147, 0), + (1230, 1, 313, 25, 0), + (1231, 1, 313, 50, 0), + (1232, 1, 313, 75, 0), + (1265, 1, 220, 40, 26), + (1265, 2, 220, 40, 30), + (1265, 3, 220, 40, 38), + (1266, 1, 220, 50, 26), + (1266, 2, 220, 50, 30), + (1266, 3, 220, 50, 38), + (1267, 1, 220, 60, 26), + (1267, 2, 220, 60, 30), + (1267, 3, 220, 60, 38), + (1268, 1, 292, 20, 0), + (1269, 1, 292, 25, 0), + (1270, 1, 292, 30, 0), + (1284, 1, 293, 15, 0), + (1285, 1, 293, 30, 0), + (1286, 1, 293, 50, 0), + (1287, 1, 320, 1, 0), + (1288, 1, 320, 3, 0), + (1289, 1, 320, 5, 0), + (1290, 1, 216, 40, 0), + (1290, 2, 216, 40, 1), + (1290, 3, 216, 40, 2), + (1290, 4, 216, 40, 3), + (1290, 5, 216, 40, 10), + (1290, 6, 216, 40, 28), + (1290, 7, 216, 40, 30), + (1290, 8, 216, 40, 36), + (1290, 9, 216, 40, 77), + (1291, 1, 216, 50, 0), + (1291, 2, 216, 50, 1), + (1291, 3, 216, 50, 2), + (1291, 4, 216, 50, 3), + (1291, 5, 216, 50, 10), + (1291, 6, 216, 50, 28), + (1291, 7, 216, 50, 30), + (1291, 8, 216, 50, 36), + (1291, 9, 216, 50, 77), + (1292, 1, 216, 60, 0), + (1292, 2, 216, 60, 1), + (1292, 3, 216, 60, 2), + (1292, 4, 216, 60, 3), + (1292, 5, 216, 60, 10), + (1292, 6, 216, 60, 28), + (1292, 7, 216, 60, 30), + (1292, 8, 216, 60, 36), + (1292, 9, 216, 60, 77), + (1296, 1, 247, 20, 53), + (1297, 1, 247, 40, 53), + (1298, 1, 247, 60, 53), + (1299, 1, 247, 80, 53), + (1300, 1, 247, 100, 53), + (1301, 1, 258, 20, 0), + (1302, 1, 258, 25, 0), + (1303, 1, 258, 30, 0), + (1304, 1, 216, 50, 8), + (1305, 1, 216, 100, 8), + (1306, 1, 216, 150, 8), + (1307, 1, 325, 10, 0), + (1308, 1, 325, 20, 0), + (1309, 1, 325, 30, 0), + (1310, 1, 325, 40, 0), + (1311, 1, 325, 50, 0), + (1313, 1, 85, 6037, 0), + (1314, 1, 85, 6038, 0), + (1315, 1, 85, 6039, 0), + (1316, 1, 302, 216, 216), + (1316, 2, 385, 99, 0), + (1317, 1, 302, 233, 233), + (1317, 2, 385, 99, 0), + (1318, 1, 302, 250, 250), + (1318, 2, 385, 99, 0), + (1319, 1, 274, 16, 0), + (1320, 1, 274, 18, 0), + (1321, 1, 274, 20, 0), + (1361, 1, 159, 10, 0), + (1361, 2, 262, 10, 0), + (1361, 3, 262, 10, 1), + (1361, 4, 262, 10, 2), + (1361, 5, 262, 10, 3), + (1361, 6, 262, 10, 4), + (1361, 7, 262, 10, 5), + (1361, 8, 262, 10, 6), + (1362, 1, 214, 300, 0), + (1362, 2, 97, 200, 0), + (1362, 3, 190, 200, 0), + (1363, 1, 327, 1, 0), + (1364, 1, 273, 1, 0), + (1364, 2, 274, 1, 0), + (1364, 3, 294, 1, 100), + (1364, 4, 169, 40, 0), + (1364, 5, 169, 40, 1), + (1364, 6, 169, 40, 2), + (1364, 7, 169, 40, 3), + (1364, 8, 169, 40, 8), + (1364, 9, 169, 40, 10), + (1364, 10, 169, 40, 26), + (1364, 11, 169, 40, 28), + (1364, 12, 169, 40, 30), + (1364, 13, 169, 40, 36), + (1364, 14, 169, 40, 74), + (1365, 1, 180, 2, 0), + (1366, 1, 159, 10, 0), + (1366, 2, 262, 10, 0), + (1366, 3, 262, 10, 1), + (1366, 4, 262, 10, 2), + (1366, 5, 262, 10, 3), + (1366, 6, 262, 10, 4), + (1366, 7, 262, 10, 5), + (1366, 8, 262, 10, 6), + (1367, 1, 214, 300, 0), + (1367, 2, 97, 200, 0), + (1367, 3, 190, 200, 0), + (1368, 1, 327, 1, 0), + (1369, 1, 273, 1, 0), + (1369, 2, 274, 1, 0), + (1369, 3, 294, 1, 100), + (1369, 4, 169, 40, 0), + (1369, 5, 169, 40, 1), + (1369, 6, 169, 40, 2), + (1369, 7, 169, 40, 3), + (1369, 8, 169, 40, 8), + (1369, 9, 169, 40, 10), + (1369, 10, 169, 40, 26), + (1369, 11, 169, 40, 28), + (1369, 12, 169, 40, 30), + (1369, 13, 169, 40, 36), + (1369, 14, 169, 40, 74), + (1370, 1, 180, 2, 0), + (1378, 1, 10, 0, 0), + (1379, 1, 10, 0, 0), + (1380, 1, 10, 0, 0), + (1382, 1, 10, 0, 0), + (1388, 2, 13, 1, 0), + (1389, 1, 328, 300, 0), + (1390, 1, 328, 350, 0), + (1391, 1, 328, 400, 0), + (1392, 1, 328, 450, 0), + (1393, 1, 328, 500, 0), + (1394, 1, 172, 33, 0), + (1395, 1, 172, 34, 0), + (1396, 1, 172, 35, 0), + (1397, 1, 172, 37, 0), + (1398, 1, 172, 39, 0), + (1399, 1, 259, 37, 0), + (1400, 1, 259, 39, 0), + (1401, 1, 259, 41, 0), + (1402, 1, 259, 43, 0), + (1403, 1, 259, 45, 0), + (1414, 1, 264, 432, 451), + (1415, 1, 264, 864, 451), + (1416, 1, 264, 1296, 451), + (1417, 1, 264, 1728, 451), + (1418, 1, 264, 2160, 451), + (1420, 1, 282, 20, 0), + (1421, 1, 282, 40, 0), + (1422, 1, 282, 60, 0), + (1423, 1, 282, 80, 0), + (1424, 1, 282, 100, 0), + (1430, 1, 280, 27, 0), + (1431, 1, 280, 34, 0), + (1432, 1, 280, 41, 0), + (1435, 1, 339, 3, 8105), + (1435, 2, 142, 65, 0), + (1435, 3, 311, 0, 0), + (1435, 4, 134, 70, 0), + (1435, 5, 348, 10, 0), + (1435, 6, 137, 0, 0), + (1435, 7, 339, 3, 8105), + (1435, 8, 142, 65, 0), + (1435, 9, 311, 0, 0), + (1435, 10, 134, 70, 0), + (1435, 11, 348, 10, 0), + (1435, 12, 137, 100, 0), + (1435, 13, 339, 3, 8105), + (1435, 14, 142, 65, 0), + (1435, 15, 311, 0, 0), + (1435, 16, 134, 70, 0), + (1435, 17, 348, 10, 0), + (1435, 18, 137, 79, 0), + (1435, 19, 339, 3, 8105), + (1435, 20, 142, 65, 0), + (1435, 21, 311, 0, 0), + (1435, 22, 134, 70, 0), + (1435, 23, 348, 10, 0), + (1435, 24, 137, 147, 0), + (1436, 1, 339, 6, 8105), + (1436, 2, 142, 65, 0), + (1436, 3, 311, 0, 0), + (1436, 4, 134, 70, 0), + (1436, 5, 348, 10, 0), + (1436, 6, 137, 0, 0), + (1436, 7, 339, 6, 8105), + (1436, 8, 142, 65, 0), + (1436, 9, 311, 0, 0), + (1436, 10, 134, 70, 0), + (1436, 11, 348, 10, 0), + (1436, 12, 137, 100, 0), + (1436, 13, 339, 6, 8105), + (1436, 14, 142, 65, 0), + (1436, 15, 311, 0, 0), + (1436, 16, 134, 70, 0), + (1436, 17, 348, 10, 0), + (1436, 18, 137, 79, 0), + (1436, 19, 339, 6, 8105), + (1436, 20, 142, 65, 0), + (1436, 21, 311, 0, 0), + (1436, 22, 134, 70, 0), + (1436, 23, 348, 10, 0), + (1436, 24, 137, 147, 0), + (1437, 1, 339, 10, 8105), + (1437, 2, 142, 65, 0), + (1437, 3, 311, 0, 0), + (1437, 4, 134, 70, 0), + (1437, 5, 348, 10, 0), + (1437, 6, 137, 0, 0), + (1437, 7, 339, 10, 8105), + (1437, 8, 142, 65, 0), + (1437, 9, 311, 0, 0), + (1437, 10, 134, 70, 0), + (1437, 11, 348, 10, 0), + (1437, 12, 137, 100, 0), + (1437, 13, 339, 10, 8105), + (1437, 14, 142, 65, 0), + (1437, 15, 311, 0, 0), + (1437, 16, 134, 70, 0), + (1437, 17, 348, 10, 0), + (1437, 18, 137, 79, 0), + (1437, 19, 339, 10, 8105), + (1437, 20, 142, 65, 0), + (1437, 21, 311, 0, 0), + (1437, 22, 134, 70, 0), + (1437, 23, 348, 10, 0), + (1437, 24, 137, 147, 0), + (1453, 1, 131, 10, 10), + (1453, 2, 137, 32, 0), + (1453, 3, 311, 1, 0), + (1454, 1, 131, 20, 20), + (1454, 2, 137, 32, 0), + (1454, 3, 311, 1, 0), + (1455, 1, 131, 30, 30), + (1455, 2, 137, 32, 0), + (1455, 3, 311, 1, 0), + (1456, 1, 131, 40, 40), + (1456, 2, 137, 32, 0), + (1456, 3, 311, 1, 0), + (1457, 1, 131, 50, 50), + (1457, 2, 137, 32, 0), + (1457, 3, 311, 1, 0), + (1467, 1, 280, 27, 0), + (1468, 1, 280, 34, 0), + (1469, 1, 280, 41, 0), + (1471, 1, 264, 90, 362), + (1472, 1, 264, 180, 362), + (1473, 1, 264, 270, 362), + (1474, 1, 264, 360, 362), + (1475, 1, 264, 450, 362), + (1483, 1, 294, 0, 133), + (1484, 1, 294, 0, 141), + (1485, 1, 294, 0, 150), + (1486, 1, 339, 1, 8165), + (1486, 2, 138, 1, 0), + (1486, 3, 141, 1, 0), + (1486, 4, 142, 60, 0), + (1486, 5, 137, 0, 0), + (1486, 6, 311, 0, 0), + (1486, 7, 134, 75, 0), + (1486, 8, 139, -265, 0), + (1486, 9, 139, -754, 0), + (1486, 10, 139, -1332, 0), + (1486, 11, 139, -1572, 0), + (1486, 12, 139, -2749, 0), + (1486, 13, 139, -4979, 0), + (1486, 14, 139, -5418, 0), + (1486, 15, 139, -5403, 0), + (1486, 16, 348, 10, 0), + (1487, 1, 339, 3, 8166), + (1487, 2, 138, 1, 0), + (1487, 3, 141, 1, 0), + (1487, 4, 142, 60, 0), + (1487, 5, 137, 0, 0), + (1487, 6, 311, 0, 0), + (1487, 7, 134, 75, 0), + (1487, 8, 139, -265, 0), + (1487, 9, 139, -754, 0), + (1487, 10, 139, -1332, 0), + (1487, 11, 139, -1572, 0), + (1487, 12, 139, -2749, 0), + (1487, 13, 139, -4979, 0), + (1487, 14, 139, -5418, 0), + (1487, 15, 139, -5403, 0), + (1487, 16, 348, 10, 0), + (1488, 1, 339, 5, 8167), + (1488, 2, 138, 1, 0), + (1488, 3, 141, 1, 0), + (1488, 4, 142, 60, 0), + (1488, 5, 137, 0, 0), + (1488, 6, 311, 0, 0), + (1488, 7, 134, 75, 0), + (1488, 8, 139, -265, 0), + (1488, 9, 139, -754, 0), + (1488, 10, 139, -1332, 0), + (1488, 11, 139, -1572, 0), + (1488, 12, 139, -2749, 0), + (1488, 13, 139, -4979, 0), + (1488, 14, 139, -5418, 0), + (1488, 15, 139, -5403, 0), + (1488, 16, 348, 10, 0), + (1489, 1, 339, 7, 8168), + (1489, 2, 138, 1, 0), + (1489, 3, 141, 1, 0), + (1489, 4, 142, 60, 0), + (1489, 5, 137, 0, 0), + (1489, 6, 311, 0, 0), + (1489, 7, 134, 75, 0), + (1489, 8, 139, -265, 0), + (1489, 9, 139, -754, 0), + (1489, 10, 139, -1332, 0), + (1489, 11, 139, -1572, 0), + (1489, 12, 139, -2749, 0), + (1489, 13, 139, -4979, 0), + (1489, 14, 139, -5418, 0), + (1489, 15, 139, -5403, 0), + (1489, 16, 348, 10, 0), + (1490, 1, 339, 9, 8169), + (1490, 2, 138, 1, 0), + (1490, 3, 141, 1, 0), + (1490, 4, 142, 60, 0), + (1490, 5, 137, 0, 0), + (1490, 6, 311, 0, 0), + (1490, 7, 134, 75, 0), + (1490, 8, 139, -265, 0), + (1490, 9, 139, -754, 0), + (1490, 10, 139, -1332, 0), + (1490, 11, 139, -1572, 0), + (1490, 12, 139, -2749, 0), + (1490, 13, 139, -4979, 0), + (1490, 14, 139, -5418, 0), + (1490, 15, 139, -5403, 0), + (1490, 16, 348, 10, 0), + (1504, 1, 287, 2, 0), + (1504, 2, 385, 2754, 1), + (1505, 1, 287, 4, 0), + (1505, 2, 385, 2754, 1), + (1506, 1, 287, 6, 0), + (1506, 2, 385, 2754, 1), + (1511, 1, 264, 60, 175), + (1511, 2, 264, 60, 792), + (1512, 1, 264, 120, 175), + (1512, 2, 264, 120, 792), + (1513, 1, 264, 180, 175), + (1513, 2, 264, 180, 792), + (1514, 1, 273, 2, 0), + (1515, 1, 273, 4, 0), + (1516, 1, 273, 6, 0), + (1524, 1, 219, 260, 1800), + (1525, 1, 219, 300, 2000), + (1526, 1, 219, 280, 1900), + (1528, 1, 239, 30, 0), + (1529, 1, 239, 35, 0), + (1530, 1, 239, 40, 0), + (1531, 1, 239, 45, 0), + (1532, 1, 239, 50, 0), + (1533, 1, 266, 11, 0), + (1534, 1, 266, 14, 0), + (1535, 1, 266, 17, 0), + (1536, 1, 266, 11, 0), + (1537, 1, 266, 14, 0), + (1538, 1, 266, 17, 0), + (1539, 1, 252, 37, 0), + (1540, 1, 252, 44, 0), + (1541, 1, 252, 50, 0), + (1543, 1, 220, 10, 8), + (1544, 1, 220, 20, 8), + (1545, 1, 220, 30, 8), + (1546, 1, 264, 120, 420), + (1547, 1, 264, 240, 420), + (1548, 1, 264, 360, 420), + (1549, 1, 293, 25, 0), + (1550, 1, 293, 50, 0), + (1551, 1, 293, 75, 0), + (1552, 1, 271, 5, 0), + (1553, 1, 271, 10, 0), + (1554, 1, 271, 15, 0), + (1555, 1, 264, 240, 359), + (1556, 1, 264, 480, 359), + (1557, 1, 264, 720, 359), + (1563, 1, 225, 18, 0), + (1564, 1, 225, 21, 0), + (1565, 1, 225, 24, 0), + (1566, 1, 225, 27, 0), + (1567, 1, 225, 30, 0), + (1572, 1, 339, 2, 8261), + (1572, 2, 138, 0, 0), + (1572, 3, 137, 31, 0), + (1572, 4, 311, 0, 0), + (1573, 1, 339, 4, 8262), + (1573, 2, 138, 0, 0), + (1573, 3, 137, 31, 0), + (1573, 4, 311, 0, 0), + (1574, 1, 339, 6, 8263), + (1574, 2, 138, 0, 0), + (1574, 3, 137, 31, 0), + (1574, 4, 311, 0, 0), + (1575, 1, 339, 8, 8264), + (1575, 2, 138, 0, 0), + (1575, 3, 137, 31, 0), + (1575, 4, 311, 0, 0), + (1576, 1, 339, 10, 8265), + (1576, 2, 138, 0, 0), + (1576, 3, 137, 31, 0), + (1576, 4, 311, 0, 0), + (1577, 1, 274, 3, 0), + (1578, 1, 274, 6, 0), + (1579, 1, 274, 10, 0), + (1583, 1, 264, 360, 300), + (1584, 1, 264, 720, 300), + (1585, 1, 264, 1080, 300), + (1586, 1, 264, 1440, 300), + (1587, 1, 264, 1800, 300), + (1588, 1, 344, 50, 0), + (1589, 1, 344, 100, 0), + (1590, 1, 344, 150, 0), + (1591, 1, 293, 25, 0), + (1592, 1, 341, 10, 0), + (1593, 1, 341, 20, 0), + (1594, 1, 341, 30, 0), + (1595, 1, 341, 40, 0), + (1596, 1, 341, 50, 0), + (1601, 1, 217, 0, 35200), + (1601, 2, 346, 60, 0), + (1602, 1, 217, 0, 42440), + (1602, 2, 346, 62, 0), + (1603, 1, 217, 0, 46480), + (1603, 2, 346, 64, 0), + (1604, 1, 439, 0, 32000), + (1604, 2, 345, 59, 0), + (1605, 1, 439, 0, 35200), + (1605, 2, 345, 60, 0), + (1606, 1, 439, 0, 42440), + (1606, 2, 345, 61, 0), + (1608, 1, 347, 2, 0), + (1609, 1, 347, 4, 0), + (1610, 1, 347, 6, 0), + (1611, 1, 282, 20, 0), + (1612, 1, 282, 40, 0), + (1613, 1, 282, 60, 0), + (1614, 1, 282, 80, 0), + (1615, 1, 282, 100, 0), + (1616, 1, 279, 7, 0), + (1617, 1, 279, 11, 0), + (1618, 1, 279, 15, 0), + (1619, 1, 279, 17, 0), + (1620, 1, 279, 19, 0), + (1621, 1, 177, 20, -1), + (1622, 1, 177, 22, -1), + (1623, 1, 177, 24, -1), + (1624, 1, 177, 20, -1), + (1625, 1, 177, 22, -1), + (1626, 1, 177, 24, -1), + (1627, 1, 271, 5, 0), + (1628, 1, 271, 10, 0), + (1629, 1, 271, 15, 0), + (1633, 1, 225, 18, 0), + (1634, 1, 225, 21, 0), + (1635, 1, 225, 24, 0), + (1636, 1, 225, 27, 0), + (1637, 1, 225, 30, 0), + (1641, 1, 359, 100, 0), + (1642, 1, 359, 60, 0), + (1648, 1, 339, 10, 8105), + (1648, 2, 142, 65, 0), + (1648, 3, 311, 0, 0), + (1648, 4, 134, 70, 0), + (1648, 5, 348, 10, 0), + (1648, 6, 137, 0, 0), + (1648, 7, 339, 10, 8105), + (1648, 8, 142, 65, 0), + (1648, 9, 311, 0, 0), + (1648, 10, 134, 70, 0), + (1648, 11, 348, 10, 0), + (1648, 12, 137, 100, 0), + (1648, 13, 339, 10, 8105), + (1648, 14, 142, 65, 0), + (1648, 15, 311, 0, 0), + (1648, 16, 134, 70, 0), + (1648, 17, 348, 10, 0), + (1648, 18, 137, 79, 0), + (1648, 19, 339, 10, 8105), + (1648, 20, 142, 65, 0), + (1648, 21, 311, 0, 0), + (1648, 22, 134, 70, 0), + (1648, 23, 348, 10, 0), + (1648, 24, 137, 147, 0), + (1648, 25, 339, 10, 11404), + (1648, 26, 142, 71, 0), + (1648, 27, 311, 0, 0), + (1648, 28, 134, 75, 0), + (1648, 29, 348, 10, 0), + (1648, 30, 137, 0, 0), + (1648, 31, 339, 10, 11404), + (1648, 32, 142, 71, 0), + (1648, 33, 311, 0, 0), + (1648, 34, 134, 75, 0), + (1648, 35, 348, 10, 0), + (1648, 36, 137, 100, 0), + (1648, 37, 339, 10, 11404), + (1648, 38, 142, 71, 0), + (1648, 39, 311, 0, 0), + (1648, 40, 134, 75, 0), + (1648, 41, 348, 10, 0), + (1648, 42, 137, 79, 0), + (1648, 43, 339, 10, 11404), + (1648, 44, 142, 71, 0), + (1648, 45, 311, 0, 0), + (1648, 46, 134, 75, 0), + (1648, 47, 348, 10, 0), + (1648, 48, 137, 147, 0), + (1649, 1, 339, 10, 8105), + (1649, 2, 142, 65, 0), + (1649, 3, 311, 0, 0), + (1649, 4, 134, 70, 0), + (1649, 5, 348, 10, 0), + (1649, 6, 137, 0, 0), + (1649, 7, 339, 10, 8105), + (1649, 8, 142, 65, 0), + (1649, 9, 311, 0, 0), + (1649, 10, 134, 70, 0), + (1649, 11, 348, 10, 0), + (1649, 12, 137, 100, 0), + (1649, 13, 339, 10, 8105), + (1649, 14, 142, 65, 0), + (1649, 15, 311, 0, 0), + (1649, 16, 134, 70, 0), + (1649, 17, 348, 10, 0), + (1649, 18, 137, 79, 0), + (1649, 19, 339, 10, 8105), + (1649, 20, 142, 65, 0), + (1649, 21, 311, 0, 0), + (1649, 22, 134, 70, 0), + (1649, 23, 348, 10, 0), + (1649, 24, 137, 147, 0), + (1649, 25, 339, 10, 11404), + (1649, 26, 142, 71, 0), + (1649, 27, 311, 0, 0), + (1649, 28, 134, 75, 0), + (1649, 29, 348, 10, 0), + (1649, 30, 137, 0, 0), + (1649, 31, 339, 10, 11404), + (1649, 32, 142, 71, 0), + (1649, 33, 311, 0, 0), + (1649, 34, 134, 75, 0), + (1649, 35, 348, 10, 0), + (1649, 36, 137, 100, 0), + (1649, 37, 339, 10, 11404), + (1649, 38, 142, 71, 0), + (1649, 39, 311, 0, 0), + (1649, 40, 134, 75, 0), + (1649, 41, 348, 10, 0), + (1649, 42, 137, 79, 0), + (1649, 43, 339, 10, 11404), + (1649, 44, 142, 71, 0), + (1649, 45, 311, 0, 0), + (1649, 46, 134, 75, 0), + (1649, 47, 348, 10, 0), + (1649, 48, 137, 147, 0), + (1649, 49, 339, 10, 13199), + (1649, 50, 142, 76, 0), + (1649, 51, 311, 0, 0), + (1649, 52, 134, 80, 0), + (1649, 53, 348, 10, 0), + (1649, 54, 137, 0, 0), + (1649, 55, 339, 10, 13199), + (1649, 56, 142, 76, 0), + (1649, 57, 311, 0, 0), + (1649, 58, 134, 80, 0), + (1649, 59, 348, 10, 0), + (1649, 60, 137, 100, 0), + (1649, 61, 339, 10, 13199), + (1649, 62, 142, 76, 0), + (1649, 63, 311, 0, 0), + (1649, 64, 134, 80, 0), + (1649, 65, 348, 10, 0), + (1649, 66, 137, 79, 0), + (1649, 67, 339, 10, 13199), + (1649, 68, 142, 76, 0), + (1649, 69, 311, 0, 0), + (1649, 70, 134, 80, 0), + (1649, 71, 348, 10, 0), + (1649, 72, 137, 147, 0), + (1650, 1, 339, 10, 8105), + (1650, 2, 142, 65, 0), + (1650, 3, 311, 0, 0), + (1650, 4, 134, 70, 0), + (1650, 5, 348, 10, 0), + (1650, 6, 137, 0, 0), + (1650, 7, 339, 10, 8105), + (1650, 8, 142, 65, 0), + (1650, 9, 311, 0, 0), + (1650, 10, 134, 70, 0), + (1650, 11, 348, 10, 0), + (1650, 12, 137, 100, 0), + (1650, 13, 339, 10, 8105), + (1650, 14, 142, 65, 0), + (1650, 15, 311, 0, 0), + (1650, 16, 134, 70, 0), + (1650, 17, 348, 10, 0), + (1650, 18, 137, 79, 0), + (1650, 19, 339, 10, 8105), + (1650, 20, 142, 65, 0), + (1650, 21, 311, 0, 0), + (1650, 22, 134, 70, 0), + (1650, 23, 348, 10, 0), + (1650, 24, 137, 147, 0), + (1650, 25, 339, 10, 11404), + (1650, 26, 142, 71, 0), + (1650, 27, 311, 0, 0), + (1650, 28, 134, 75, 0), + (1650, 29, 348, 10, 0), + (1650, 30, 137, 0, 0), + (1650, 31, 339, 10, 11404), + (1650, 32, 142, 71, 0), + (1650, 33, 311, 0, 0), + (1650, 34, 134, 75, 0), + (1650, 35, 348, 10, 0), + (1650, 36, 137, 100, 0), + (1650, 37, 339, 10, 11404), + (1650, 38, 142, 71, 0), + (1650, 39, 311, 0, 0), + (1650, 40, 134, 75, 0), + (1650, 41, 348, 10, 0), + (1650, 42, 137, 79, 0), + (1650, 43, 339, 10, 11404), + (1650, 44, 142, 71, 0), + (1650, 45, 311, 0, 0), + (1650, 46, 134, 75, 0), + (1650, 47, 348, 10, 0), + (1650, 48, 137, 147, 0), + (1650, 49, 339, 10, 13199), + (1650, 50, 142, 76, 0), + (1650, 51, 311, 0, 0), + (1650, 52, 134, 80, 0), + (1650, 53, 348, 10, 0), + (1650, 54, 137, 0, 0), + (1650, 55, 339, 10, 13199), + (1650, 56, 142, 76, 0), + (1650, 57, 311, 0, 0), + (1650, 58, 134, 80, 0), + (1650, 59, 348, 10, 0), + (1650, 60, 137, 100, 0), + (1650, 61, 339, 10, 13199), + (1650, 62, 142, 76, 0), + (1650, 63, 311, 0, 0), + (1650, 64, 134, 80, 0), + (1650, 65, 348, 10, 0), + (1650, 66, 137, 79, 0), + (1650, 67, 339, 10, 13199), + (1650, 68, 142, 76, 0), + (1650, 69, 311, 0, 0), + (1650, 70, 134, 80, 0), + (1650, 71, 348, 10, 0), + (1650, 72, 137, 147, 0), + (1650, 73, 339, 10, 13830), + (1650, 74, 142, 81, 0), + (1650, 75, 311, 0, 0), + (1650, 76, 134, 85, 0), + (1650, 77, 348, 10, 0), + (1650, 78, 137, 0, 0), + (1650, 79, 339, 10, 13830), + (1650, 80, 142, 81, 0), + (1650, 81, 311, 0, 0), + (1650, 82, 134, 85, 0), + (1650, 83, 348, 10, 0), + (1650, 84, 137, 100, 0), + (1650, 85, 339, 10, 13830), + (1650, 86, 142, 81, 0), + (1650, 87, 311, 0, 0), + (1650, 88, 134, 85, 0), + (1650, 89, 348, 10, 0), + (1650, 90, 137, 79, 0), + (1650, 91, 339, 10, 13830), + (1650, 92, 142, 81, 0), + (1650, 93, 311, 0, 0), + (1650, 94, 134, 85, 0), + (1650, 95, 348, 10, 0), + (1650, 96, 137, 147, 0), + (1651, 1, 97, 300, 0), + (1652, 1, 97, 350, 0), + (1653, 1, 97, 400, 0), + (1654, 1, 97, 450, 0), + (1655, 1, 97, 500, 0), + (1656, 1, 127, 40, 0), + (1656, 2, 137, 154, 0), + (1656, 3, 403, 2, 0), + (1656, 4, 404, 10, 0), + (1657, 1, 127, 50, 0), + (1657, 2, 137, 154, 0), + (1657, 3, 403, 2, 0), + (1657, 4, 404, 10, 0), + (1659, 1, 127, 40, 0), + (1659, 2, 137, 154, 0), + (1659, 3, 403, 2, 0), + (1659, 4, 404, 10, 0), + (1660, 1, 127, 50, 0), + (1660, 2, 137, 154, 0), + (1660, 3, 403, 2, 0), + (1660, 4, 404, 10, 0), + (1662, 1, 370, 2, 0), + (1663, 1, 370, 4, 0), + (1664, 1, 370, 6, 0), + (1665, 1, 370, 8, 0), + (1666, 1, 370, 10, 0), + (2400, 1, 264, 90, 38), + (2401, 1, 264, 180, 38), + (2402, 1, 264, 270, 38), + (4666, 0, 366, 10, 50), + (4666, 1, 349, 5, 0), + (4667, 0, 366, 30, 50), + (4667, 1, 349, 10, 0), + (4668, 0, 366, 60, 50), + (4668, 1, 349, 15, 0), + (4669, 0, 366, 10, 500), + (4669, 1, 349, 20, 0), + (4670, 0, 366, 30, 500), + (4670, 1, 349, 25, 0), + (4672, 1, 268, 10, 57), + (4673, 1, 268, 25, 57), + (4674, 1, 268, 50, 57), + (4675, 1, 268, 10, 68), + (4676, 1, 268, 25, 68), + (4677, 1, 268, 50, 68), + (4678, 1, 262, 55, 0), + (4678, 2, 262, 55, 1), + (4678, 3, 262, 55, 2), + (4678, 4, 262, 55, 3), + (4678, 5, 262, 55, 4), + (4678, 6, 262, 55, 5), + (4678, 7, 262, 55, 6), + (4679, 1, 262, 60, 0), + (4679, 2, 262, 60, 1), + (4679, 3, 262, 60, 2), + (4679, 4, 262, 60, 3), + (4679, 5, 262, 60, 4), + (4679, 6, 262, 60, 5), + (4679, 7, 262, 60, 6), + (4680, 1, 262, 65, 0), + (4680, 2, 262, 65, 1), + (4680, 3, 262, 65, 2), + (4680, 4, 262, 65, 3), + (4680, 5, 262, 65, 4), + (4680, 6, 262, 65, 5), + (4680, 7, 262, 65, 6), + (4681, 1, 262, 70, 0), + (4681, 2, 262, 70, 1), + (4681, 3, 262, 70, 2), + (4681, 4, 262, 70, 3), + (4681, 5, 262, 70, 4), + (4681, 6, 262, 70, 5), + (4681, 7, 262, 70, 6), + (4682, 1, 262, 75, 0), + (4682, 2, 262, 75, 1), + (4682, 3, 262, 75, 2), + (4682, 4, 262, 75, 3), + (4682, 5, 262, 75, 4), + (4682, 6, 262, 75, 5), + (4682, 7, 262, 75, 6), + (4683, 1, 328, 550, 0), + (4684, 1, 328, 600, 0), + (4685, 1, 328, 650, 0), + (4686, 1, 328, 700, 0), + (4687, 1, 328, 750, 0), + (4688, 1, 282, 20, 0), + (4689, 1, 282, 40, 0), + (4690, 1, 282, 60, 0), + (4691, 1, 282, 80, 0), + (4692, 1, 282, 100, 0), + (4693, 1, 0, 11, 0), + (4694, 1, 0, 12, 0), + (4695, 1, 0, 13, 0), + (4696, 1, 0, 14, 0), + (4697, 1, 0, 15, 0), + (4698, 1, 362, 1, 0), + (4699, 1, 363, 1, 0), + (4707, 1, 330, 85, 0), + (4707, 2, 330, 85, 1), + (4707, 3, 330, 85, 2), + (4707, 4, 330, 85, 3), + (4707, 5, 330, 85, 28), + (4707, 6, 330, 85, 36), + (4707, 7, 330, 85, 77), + (4708, 1, 330, 95, 0), + (4708, 2, 330, 95, 1), + (4708, 3, 330, 95, 2), + (4708, 4, 330, 95, 3), + (4708, 5, 330, 95, 28), + (4708, 6, 330, 95, 36), + (4708, 7, 330, 95, 77), + (4709, 1, 330, 105, 0), + (4709, 2, 330, 105, 1), + (4709, 3, 330, 105, 2), + (4709, 4, 330, 105, 3), + (4709, 5, 330, 105, 28), + (4709, 6, 330, 105, 36), + (4709, 7, 330, 105, 77), + (4710, 1, 330, 85, 0), + (4710, 2, 330, 85, 1), + (4710, 3, 330, 85, 2), + (4710, 4, 330, 85, 3), + (4710, 5, 330, 85, 28), + (4710, 6, 330, 85, 36), + (4711, 1, 330, 95, 0), + (4711, 2, 330, 95, 1), + (4711, 3, 330, 95, 2), + (4711, 4, 330, 95, 3), + (4711, 5, 330, 95, 28), + (4711, 6, 330, 95, 36), + (4712, 1, 330, 105, 0), + (4712, 2, 330, 105, 1), + (4712, 3, 330, 105, 2), + (4712, 4, 330, 105, 3), + (4712, 5, 330, 105, 28), + (4712, 6, 330, 105, 36), + (4713, 1, 330, 85, 0), + (4713, 2, 330, 85, 1), + (4713, 3, 330, 85, 2), + (4713, 4, 330, 85, 3), + (4713, 5, 330, 85, 28), + (4713, 6, 330, 85, 36), + (4713, 7, 330, 85, 77), + (4714, 1, 330, 95, 0), + (4714, 2, 330, 95, 1), + (4714, 3, 330, 95, 2), + (4714, 4, 330, 95, 3), + (4714, 5, 330, 95, 28), + (4714, 6, 330, 95, 36), + (4714, 7, 330, 95, 77), + (4715, 1, 330, 105, 0), + (4715, 2, 330, 105, 1), + (4715, 3, 330, 105, 2), + (4715, 4, 330, 105, 3), + (4715, 5, 330, 105, 28), + (4715, 6, 330, 105, 36), + (4715, 7, 330, 105, 77), + (4716, 1, 330, 60, 0), + (4716, 2, 330, 60, 1), + (4716, 3, 330, 60, 2), + (4716, 4, 330, 60, 3), + (4716, 5, 330, 60, 28), + (4716, 6, 330, 60, 36), + (4716, 7, 330, 60, 77), + (4717, 1, 330, 70, 0), + (4717, 2, 330, 70, 1), + (4717, 3, 330, 70, 2), + (4717, 4, 330, 70, 3), + (4717, 5, 330, 70, 28), + (4717, 6, 330, 70, 36), + (4717, 7, 330, 70, 77), + (4718, 1, 330, 80, 0), + (4718, 2, 330, 80, 1), + (4718, 3, 330, 80, 2), + (4718, 4, 330, 80, 3), + (4718, 5, 330, 80, 28), + (4718, 6, 330, 80, 36), + (4718, 7, 330, 80, 77), + (4722, 1, 278, 620, 35216), + (4722, 2, 440, 66, 100), + (4723, 1, 278, 650, 38310), + (4723, 2, 440, 68, 100), + (4724, 1, 278, 670, 41300), + (4724, 2, 440, 70, 100), + (4725, 1, 341, 60, 0), + (4726, 1, 341, 70, 0), + (4727, 1, 341, 80, 0), + (4728, 1, 341, 90, 0), + (4729, 1, 341, 100, 0), + (4733, 1, 294, 11, 100), + (4734, 1, 294, 13, 100), + (4735, 1, 294, 15, 100), + (4739, 1, 360, 10, 11023), + (4740, 1, 360, 20, 11023), + (4741, 1, 360, 30, 11023), + (4744, 1, 318, 6, 0), + (4745, 1, 318, 7, 0), + (4746, 1, 318, 8, 0), + (4747, 1, 318, 9, 0), + (4748, 1, 318, 10, 0), + (4749, 1, 294, 11, 100), + (4750, 1, 294, 13, 100), + (4751, 1, 294, 15, 100), + (4752, 1, 294, 0, 155), + (4753, 1, 294, 0, 160), + (4754, 1, 294, 0, 165), + (4755, 1, 294, 0, 130), + (4756, 1, 294, 0, 135), + (4757, 1, 294, 0, 140), + (4758, 1, 266, 27, 0), + (4759, 1, 266, 28, 0), + (4760, 1, 266, 29, 0), + (4761, 1, 273, 2, 0), + (4762, 1, 273, 3, 0), + (4763, 1, 273, 4, 0), + (4764, 1, 326, 2, 0), + (4767, 1, 114, -43, 0), + (4768, 1, 114, -46, 0), + (4769, 1, 114, -50, 0), + (4773, 1, 339, 10, 8105), + (4773, 2, 142, 65, 0), + (4773, 3, 311, 0, 0), + (4773, 4, 134, 70, 0), + (4773, 5, 348, 10, 0), + (4773, 6, 137, 0, 0), + (4773, 7, 339, 10, 8105), + (4773, 8, 142, 65, 0), + (4773, 9, 311, 0, 0), + (4773, 10, 134, 70, 0), + (4773, 11, 348, 10, 0), + (4773, 12, 137, 100, 0), + (4773, 13, 339, 10, 8105), + (4773, 14, 142, 65, 0), + (4773, 15, 311, 0, 0), + (4773, 16, 134, 70, 0), + (4773, 17, 348, 10, 0), + (4773, 18, 137, 79, 0), + (4773, 19, 339, 10, 8105), + (4773, 20, 142, 65, 0), + (4773, 21, 311, 0, 0), + (4773, 22, 134, 70, 0), + (4773, 23, 348, 10, 0), + (4773, 24, 137, 147, 0), + (4773, 25, 339, 10, 11404), + (4773, 26, 142, 71, 0), + (4773, 27, 311, 0, 0), + (4773, 28, 134, 75, 0), + (4773, 29, 348, 10, 0), + (4773, 30, 137, 0, 0), + (4773, 31, 339, 10, 11404), + (4773, 32, 142, 71, 0), + (4773, 33, 311, 0, 0), + (4773, 34, 134, 75, 0), + (4773, 35, 348, 10, 0), + (4773, 36, 137, 100, 0), + (4773, 37, 339, 10, 11404), + (4773, 38, 142, 71, 0), + (4773, 39, 311, 0, 0), + (4773, 40, 134, 75, 0), + (4773, 41, 348, 10, 0), + (4773, 42, 137, 79, 0), + (4773, 43, 339, 10, 11404), + (4773, 44, 142, 71, 0), + (4773, 45, 311, 0, 0), + (4773, 46, 134, 75, 0), + (4773, 47, 348, 10, 0), + (4773, 48, 137, 147, 0), + (4776, 1, 319, 12, 0), + (4777, 1, 319, 14, 0), + (4778, 1, 319, 16, 0), + (4779, 1, 274, 24, 0), + (4780, 1, 274, 26, 0), + (4781, 1, 274, 28, 0), + (4790, 1, 220, 288, 74), + (4791, 1, 220, 320, 74), + (4792, 1, 220, 352, 74), + (4793, 1, 220, 384, 74), + (4794, 1, 220, 416, 74), + (4795, 1, 279, 28, 0), + (4796, 1, 279, 29, 0), + (4797, 1, 279, 30, 0), + (4798, 1, 292, 65, 0), + (4799, 1, 292, 70, 0), + (4800, 1, 292, 75, 0), + (4801, 1, 227, 30, 32), + (4802, 1, 227, 60, 32), + (4803, 1, 227, 90, 32), + (4804, 1, 220, 448, 74), + (4805, 1, 220, 480, 74), + (4806, 1, 220, 512, 74), + (4807, 1, 220, 544, 74), + (4808, 1, 220, 576, 74), + (4809, 1, 216, 40, 74), + (4810, 1, 216, 80, 74), + (4811, 1, 216, 120, 74), + (4813, 1, 220, 70, 26), + (4813, 2, 220, 70, 30), + (4813, 3, 220, 70, 38), + (4814, 1, 220, 80, 26), + (4814, 2, 220, 80, 30), + (4814, 3, 220, 80, 38), + (4815, 1, 220, 90, 26), + (4815, 2, 220, 90, 30), + (4815, 3, 220, 90, 38), + (4819, 1, 239, 52, 0), + (4820, 1, 239, 54, 0), + (4821, 1, 239, 56, 0), + (4822, 1, 239, 58, 0), + (4823, 1, 239, 60, 0), + (4824, 1, 239, 52, 0), + (4825, 1, 239, 54, 0), + (4826, 1, 239, 56, 0), + (4827, 1, 239, 58, 0), + (4828, 1, 239, 60, 0), + (4829, 1, 264, 480, 420), + (4830, 1, 264, 600, 420), + (4831, 1, 264, 720, 420), + (4844, 1, 349, 5, 0), + (4845, 1, 349, 10, 0), + (4846, 1, 349, 15, 0), + (4847, 1, 349, 20, 0), + (4848, 1, 349, 25, 0), + (4861, 1, 264, 600, 68), + (4862, 1, 264, 1200, 68), + (4863, 1, 264, 1800, 68), + (4887, 1, 264, 120, 413), + (4888, 1, 264, 240, 413), + (4889, 1, 264, 360, 413), + (4897, 1, 280, 44, 0), + (4898, 1, 280, 47, 0), + (4899, 1, 280, 50, 0), + (4921, 1, 264, 1896, 117), + (4921, 2, 244, 75, 0), + (4922, 1, 264, 2496, 117), + (4922, 2, 244, 60, 0), + (4923, 1, 264, 3096, 117), + (4923, 2, 244, 45, 0), + (4924, 1, 273, 1, 0), + (4925, 1, 273, 2, 0), + (4926, 1, 273, 3, 0), + (4948, 1, 258, 35, 0), + (4949, 1, 258, 40, 0), + (4950, 1, 258, 45, 0), + (4951, 1, 220, 40, 8), + (4952, 1, 220, 50, 8), + (4953, 1, 220, 60, 8), + (4957, 1, 252, 55, 0), + (4958, 1, 252, 60, 0), + (4959, 1, 252, 65, 0), + (4960, 1, 280, 46, 0), + (4961, 1, 280, 51, 0), + (4962, 1, 280, 56, 0), + (4983, 1, 216, 65, 0), + (4983, 2, 216, 65, 1), + (4983, 3, 216, 65, 2), + (4983, 4, 216, 65, 3), + (4983, 5, 216, 65, 10), + (4983, 6, 216, 65, 28), + (4983, 7, 216, 65, 30), + (4983, 8, 216, 65, 36), + (4983, 9, 216, 65, 77), + (4984, 1, 216, 70, 0), + (4984, 2, 216, 70, 1), + (4984, 3, 216, 70, 2), + (4984, 4, 216, 70, 3), + (4984, 5, 216, 70, 10), + (4984, 6, 216, 70, 28), + (4984, 7, 216, 70, 30), + (4984, 8, 216, 70, 36), + (4984, 9, 216, 70, 77), + (4985, 1, 216, 75, 0), + (4985, 2, 216, 75, 1), + (4985, 3, 216, 75, 2), + (4985, 4, 216, 75, 3), + (4985, 5, 216, 75, 10), + (4985, 6, 216, 75, 28), + (4985, 7, 216, 75, 30), + (4985, 8, 216, 75, 36), + (4985, 9, 216, 75, 77), + (4986, 1, 217, 0, 52960), + (4986, 2, 346, 66, 40), + (4987, 1, 217, 0, 55400), + (4987, 2, 346, 68, 40), + (4988, 1, 217, 0, 60280), + (4988, 2, 346, 70, 40), + (4989, 1, 347, 8, 0), + (4990, 1, 347, 10, 0), + (4991, 1, 347, 12, 0), + (4992, 1, 279, 21, 0), + (4993, 1, 279, 23, 0), + (4994, 1, 279, 25, 0), + (4995, 1, 279, 27, 0), + (4996, 1, 279, 28, 0), + (5000, 1, 313, 80, 0), + (5001, 1, 313, 90, 0), + (5002, 1, 313, 100, 0), + (5010, 1, 264, 432, 35), + (5011, 1, 264, 864, 35), + (5012, 1, 264, 1296, 35), + (5013, 1, 293, 90, 0), + (5014, 1, 293, 100, 0), + (5029, 1, 85, 11621, 0), + (5030, 1, 85, 11622, 0), + (5031, 1, 85, 11623, 0), + (5032, 1, 274, 22, 0), + (5033, 1, 274, 24, 0), + (5034, 1, 274, 26, 0), + (5035, 1, 293, 60, 0), + (5036, 1, 293, 70, 0), + (5037, 1, 293, 80, 0), + (5038, 1, 219, 330, 2100), + (5039, 1, 219, 360, 2200), + (5040, 1, 219, 390, 2300), + (5045, 1, 180, 5, 0), + (5061, 1, 244, -25, 0), + (5085, 1, 360, 25, 11297), + (5086, 1, 360, 25, 11298), + (5087, 1, 360, 25, 11299), + (5118, 1, 264, 720, 396), + (5118, 2, 264, 720, 8504), + (5118, 3, 264, 720, 8505), + (5119, 1, 264, 1440, 396), + (5119, 2, 264, 1440, 8504), + (5119, 3, 264, 1440, 8505), + (5120, 1, 264, 2160, 396), + (5120, 2, 264, 2160, 8504), + (5120, 3, 264, 2160, 8505), + (5127, 1, 264, 300, 261), + (5128, 1, 264, 600, 261), + (5129, 1, 264, 900, 261), + (5133, 1, 294, 13, 100), + (5134, 1, 294, 15, 100), + (5135, 1, 294, 17, 100), + (5136, 1, 282, 20, 0), + (5137, 1, 282, 40, 0), + (5138, 1, 282, 60, 0), + (5139, 1, 282, 80, 0), + (5140, 1, 282, 100, 0), + (5141, 1, 279, 21, 0), + (5142, 1, 279, 23, 0), + (5143, 1, 279, 25, 0), + (5144, 1, 279, 27, 0), + (5145, 1, 279, 28, 0), + (5243, 1, 69, 600, 0), + (5244, 1, 69, 700, 0), + (5245, 1, 69, 800, 0), + (5246, 1, 69, 900, 0), + (5247, 1, 69, 1000, 0), + (5248, 1, 360, 10, 11232), + (5249, 1, 360, 20, 11232), + (5250, 1, 360, 30, 11232), + (5254, 1, 218, 6, 0), + (5255, 1, 218, 7, 0), + (5256, 1, 218, 8, 0), + (5257, 1, 218, 9, 0), + (5258, 1, 218, 10, 0), + (5259, 1, 218, 6, 0), + (5260, 1, 218, 7, 0), + (5261, 1, 218, 8, 0), + (5262, 1, 218, 9, 0), + (5263, 1, 218, 10, 0), + (5264, 1, 218, 1, 0), + (5265, 1, 218, 2, 0), + (5266, 1, 218, 3, 0), + (5267, 1, 218, 4, 0), + (5268, 1, 218, 5, 0), + (5269, 1, 131, 50, 50), + (5269, 2, 137, 82, 0), + (5270, 1, 303, 3000, 3000), + (5270, 2, 139, 2766, 0), + (5271, 1, 303, 3500, 3500), + (5271, 2, 139, 2766, 0), + (5272, 1, 303, 4000, 4000), + (5272, 2, 139, 2766, 0), + (5276, 1, 264, 60, 621), + (5276, 2, 264, 60, 622), + (5276, 3, 264, 60, 623), + (5276, 4, 264, 60, 784), + (5276, 5, 264, 60, 785), + (5276, 6, 264, 60, 786), + (5276, 7, 264, 60, 787), + (5276, 8, 264, 60, 624), + (5277, 1, 264, 120, 621), + (5277, 2, 264, 120, 622), + (5277, 3, 264, 120, 623), + (5277, 4, 264, 120, 784), + (5277, 5, 264, 120, 785), + (5277, 6, 264, 120, 786), + (5277, 7, 264, 120, 787), + (5277, 8, 264, 120, 624), + (5278, 1, 264, 180, 621), + (5278, 2, 264, 180, 622), + (5278, 3, 264, 180, 623), + (5278, 4, 264, 180, 784), + (5278, 5, 264, 180, 785), + (5278, 6, 264, 180, 786), + (5278, 7, 264, 180, 787), + (5278, 8, 264, 180, 624), + (5283, 1, 320, 1, 0), + (5284, 1, 320, 3, 0), + (5285, 1, 320, 5, 0), + (5286, 1, 294, 7, 100), + (5287, 1, 294, 8, 100), + (5288, 1, 294, 9, 100), + (5290, 1, 439, 0, 46480), + (5290, 2, 345, 62, 0), + (5291, 1, 439, 0, 52960), + (5291, 2, 345, 63, 0), + (5292, 1, 439, 0, 55400), + (5292, 2, 345, 64, 0), + (5293, 1, 439, 0, 60280), + (5293, 2, 345, 65, 0), + (5294, 1, 439, 0, 65440), + (5294, 2, 345, 66, 50), + (5295, 1, 360, 10, 11629), + (5296, 1, 360, 20, 11629), + (5297, 1, 360, 30, 11629), + (5301, 1, 189, 7, 0), + (5302, 1, 189, 8, 0), + (5303, 1, 189, 9, 0), + (5304, 1, 189, 10, 0), + (5305, 1, 189, 11, 0), + (5306, 1, 15, 4, 0), + (5307, 1, 15, 5, 0), + (5308, 1, 15, 6, 0), + (5309, 1, 15, 7, 0), + (5310, 1, 15, 8, 0), + (5317, 1, 114, -43, 0), + (5318, 1, 114, -46, 0), + (5319, 1, 114, -50, 0), + (5320, 1, 218, 11, 0), + (5321, 1, 218, 12, 0), + (5322, 1, 218, 13, 0), + (5323, 1, 218, 14, 0), + (5324, 1, 218, 15, 0), + (5325, 1, 280, 27, 0), + (5326, 1, 280, 34, 0), + (5327, 1, 280, 41, 0), + (5328, 1, 280, 44, 0), + (5329, 1, 280, 47, 0), + (5339, 1, 215, 24, 0), + (5347, 1, 375, 225, 0), + (5348, 1, 375, 230, 0), + (5360, 1, 397, 1300, 0), + (5366, 1, 247, 75, 20), + (5500, 1, 231, 5, 0), + (5501, 1, 231, 7, 0), + (5502, 1, 231, 9, 0), + (5516, 1, 320, 6, 0), + (5517, 1, 320, 7, 0), + (5518, 1, 320, 8, 0), + (5519, 1, 172, 40, 0), + (5520, 1, 172, 41, 0), + (5521, 1, 172, 42, 0), + (5522, 1, 172, 43, 0), + (5523, 1, 172, 44, 0), + (5524, 1, 259, 46, 0), + (5525, 1, 259, 47, 0), + (5526, 1, 259, 48, 0), + (5527, 1, 259, 49, 0), + (5528, 1, 259, 50, 0), + (5529, 1, 339, 11, 12680), + (5529, 2, 138, 1, 0), + (5529, 3, 141, 1, 0), + (5529, 4, 142, 60, 0), + (5529, 5, 137, 0, 0), + (5529, 6, 311, 0, 0), + (5529, 7, 134, 80, 0), + (5529, 8, 139, -265, 0), + (5529, 9, 139, -754, 0), + (5529, 10, 139, -1332, 0), + (5529, 11, 139, -1572, 0), + (5529, 12, 139, -2749, 0), + (5529, 13, 139, -4979, 0), + (5529, 14, 139, -5418, 0), + (5529, 15, 139, -5403, 0), + (5529, 16, 348, 10, 0), + (5530, 1, 339, 13, 12681), + (5530, 2, 138, 1, 0), + (5530, 3, 141, 1, 0), + (5530, 4, 142, 60, 0), + (5530, 5, 137, 0, 0), + (5530, 6, 311, 0, 0), + (5530, 7, 134, 80, 0), + (5530, 8, 139, -265, 0), + (5530, 9, 139, -754, 0), + (5530, 10, 139, -1332, 0), + (5530, 11, 139, -1572, 0), + (5530, 12, 139, -2749, 0), + (5530, 13, 139, -4979, 0), + (5530, 14, 139, -5418, 0), + (5530, 15, 139, -5403, 0), + (5530, 16, 348, 10, 0), + (5531, 1, 339, 15, 12682), + (5531, 2, 138, 1, 0), + (5531, 3, 141, 1, 0), + (5531, 4, 142, 60, 0), + (5531, 5, 137, 0, 0), + (5531, 6, 311, 0, 0), + (5531, 7, 134, 80, 0), + (5531, 8, 139, -265, 0), + (5531, 9, 139, -754, 0), + (5531, 10, 139, -1332, 0), + (5531, 11, 139, -1572, 0), + (5531, 12, 139, -2749, 0), + (5531, 13, 139, -4979, 0), + (5531, 14, 139, -5418, 0), + (5531, 15, 139, -5403, 0), + (5531, 16, 348, 10, 0), + (5532, 1, 339, 17, 12683), + (5532, 2, 138, 1, 0), + (5532, 3, 141, 1, 0), + (5532, 4, 142, 60, 0), + (5532, 5, 137, 0, 0), + (5532, 6, 311, 0, 0), + (5532, 7, 134, 80, 0), + (5532, 8, 139, -265, 0), + (5532, 9, 139, -754, 0), + (5532, 10, 139, -1332, 0), + (5532, 11, 139, -1572, 0), + (5532, 12, 139, -2749, 0), + (5532, 13, 139, -4979, 0), + (5532, 14, 139, -5418, 0), + (5532, 15, 139, -5403, 0), + (5532, 16, 348, 10, 0), + (5533, 1, 339, 19, 12684), + (5533, 2, 138, 1, 0), + (5533, 3, 141, 1, 0), + (5533, 4, 142, 60, 0), + (5533, 5, 137, 0, 0), + (5533, 6, 311, 0, 0), + (5533, 7, 134, 80, 0), + (5533, 8, 139, -265, 0), + (5533, 9, 139, -754, 0), + (5533, 10, 139, -1332, 0), + (5533, 11, 139, -1572, 0), + (5533, 12, 139, -2749, 0), + (5533, 13, 139, -4979, 0), + (5533, 14, 139, -5418, 0), + (5533, 15, 139, -5403, 0), + (5533, 16, 348, 10, 0), + (5534, 1, 266, 18, 0), + (5535, 1, 266, 20, 0), + (5536, 1, 266, 22, 0), + (5542, 1, 330, 110, 0), + (5542, 2, 330, 110, 1), + (5542, 3, 330, 110, 2), + (5542, 4, 330, 110, 3), + (5542, 5, 330, 110, 28), + (5542, 6, 330, 110, 36), + (5542, 7, 330, 110, 77), + (5543, 1, 330, 115, 0), + (5543, 2, 330, 115, 1), + (5543, 3, 330, 115, 2), + (5543, 4, 330, 115, 3), + (5543, 5, 330, 115, 28), + (5543, 6, 330, 115, 36), + (5543, 7, 330, 115, 77), + (5544, 1, 330, 120, 0), + (5544, 2, 330, 120, 1), + (5544, 3, 330, 120, 2), + (5544, 4, 330, 120, 3), + (5544, 5, 330, 120, 28), + (5544, 6, 330, 120, 36), + (5544, 7, 330, 120, 77), + (5545, 1, 330, 110, 0), + (5545, 2, 330, 110, 1), + (5545, 3, 330, 110, 2), + (5545, 4, 330, 110, 3), + (5545, 5, 330, 110, 28), + (5545, 6, 330, 110, 36), + (5546, 1, 330, 115, 0), + (5546, 2, 330, 115, 1), + (5546, 3, 330, 115, 2), + (5546, 4, 330, 115, 3), + (5546, 5, 330, 115, 28), + (5546, 6, 330, 115, 36), + (5547, 1, 330, 120, 0), + (5547, 2, 330, 120, 1), + (5547, 3, 330, 120, 2), + (5547, 4, 330, 120, 3), + (5547, 5, 330, 120, 28), + (5547, 6, 330, 120, 36), + (5548, 1, 330, 110, 0), + (5548, 2, 330, 110, 1), + (5548, 3, 330, 110, 2), + (5548, 4, 330, 110, 3), + (5548, 5, 330, 110, 28), + (5548, 6, 330, 110, 36), + (5548, 7, 330, 110, 77), + (5549, 1, 330, 115, 0), + (5549, 2, 330, 115, 1), + (5549, 3, 330, 115, 2), + (5549, 4, 330, 115, 3), + (5549, 5, 330, 115, 28), + (5549, 6, 330, 115, 36), + (5549, 7, 330, 115, 77), + (5550, 1, 330, 120, 0), + (5550, 2, 330, 120, 1), + (5550, 3, 330, 120, 2), + (5550, 4, 330, 120, 3), + (5550, 5, 330, 120, 28), + (5550, 6, 330, 120, 36), + (5550, 7, 330, 120, 77), + (5551, 1, 330, 85, 0), + (5551, 2, 330, 85, 1), + (5551, 3, 330, 85, 2), + (5551, 4, 330, 85, 3), + (5551, 5, 330, 85, 28), + (5551, 6, 330, 85, 36), + (5551, 7, 330, 85, 77), + (5552, 1, 330, 90, 0), + (5552, 2, 330, 90, 1), + (5552, 3, 330, 90, 2), + (5552, 4, 330, 90, 3), + (5552, 5, 330, 90, 28), + (5552, 6, 330, 90, 36), + (5552, 7, 330, 90, 77), + (5553, 1, 330, 95, 0), + (5553, 2, 330, 95, 1), + (5553, 3, 330, 95, 2), + (5553, 4, 330, 95, 3), + (5553, 5, 330, 95, 28), + (5553, 6, 330, 95, 36), + (5553, 7, 330, 95, 77), + (5554, 1, 278, 700, 44340), + (5554, 2, 440, 71, 100), + (5555, 1, 278, 720, 47230), + (5555, 2, 440, 73, 100), + (5556, 1, 278, 750, 51057), + (5556, 2, 440, 75, 100), + (5557, 1, 341, 110, 0), + (5558, 1, 341, 120, 0), + (5559, 1, 341, 130, 0), + (5560, 1, 341, 140, 0), + (5561, 1, 341, 150, 0), + (5562, 1, 360, 40, 11023), + (5563, 1, 360, 50, 11023), + (5564, 1, 360, 60, 11023), + (5566, 1, 318, 11, 0), + (5567, 1, 318, 12, 0), + (5568, 1, 318, 13, 0), + (5569, 1, 318, 14, 0), + (5570, 1, 318, 15, 0), + (5571, 1, 294, 16, 100), + (5572, 1, 294, 17, 100), + (5573, 1, 294, 18, 100), + (5574, 1, 294, 0, 170), + (5575, 1, 294, 0, 175), + (5576, 1, 294, 0, 180), + (5577, 1, 294, 0, 145), + (5578, 1, 294, 0, 150), + (5579, 1, 294, 0, 155), + (5580, 1, 266, 30, 0), + (5581, 1, 266, 31, 0), + (5582, 1, 266, 32, 0), + (5586, 1, 114, -53, 0), + (5587, 1, 114, -56, 0), + (5588, 1, 114, -59, 0), + (5589, 1, 319, 17, 0), + (5590, 1, 319, 19, 0), + (5591, 1, 319, 21, 0), + (5592, 1, 274, 30, 0), + (5593, 1, 274, 32, 0), + (5594, 1, 274, 34, 0), + (5595, 1, 279, 31, 0), + (5596, 1, 279, 32, 0), + (5597, 1, 279, 33, 0), + (5611, 1, 274, 28, 0), + (5612, 1, 274, 30, 0), + (5613, 1, 274, 32, 0), + (5617, 1, 294, 18, 100), + (5618, 1, 294, 19, 100), + (5619, 1, 294, 20, 100), + (5620, 1, 320, 6, 0), + (5621, 1, 320, 7, 0), + (5622, 1, 320, 8, 0), + (5623, 1, 15, 9, 0), + (5624, 1, 15, 10, 0), + (5625, 1, 15, 11, 0), + (5626, 1, 15, 12, 0), + (5627, 1, 15, 13, 0), + (5628, 1, 114, -53, 0), + (5629, 1, 114, -56, 0), + (5630, 1, 114, -59, 0), + (5729, 1, 218, 11, 0), + (5730, 1, 218, 12, 0), + (5731, 1, 218, 13, 0), + (5732, 1, 218, 14, 0), + (5733, 1, 218, 15, 0), + (5738, 1, 280, 62, 0), + (5739, 1, 280, 63, 0), + (5740, 1, 280, 64, 0), + (5776, 1, 169, 5, -1), + (5777, 1, 169, 10, -1), + (5778, 1, 169, 15, -1), + (5797, 1, 264, 2520, 396), + (5797, 2, 264, 2520, 8504), + (5797, 3, 264, 2520, 8505), + (5798, 1, 264, 2880, 396), + (5798, 2, 264, 2880, 8504), + (5798, 3, 264, 2880, 8505), + (5799, 1, 264, 3240, 396), + (5799, 2, 264, 3240, 8504), + (5799, 3, 264, 3240, 8505), + (5806, 1, 279, 7, 0), + (5807, 1, 279, 11, 0), + (5808, 1, 279, 15, 0), + (5825, 1, 244, -40, 0), + (5850, 1, 287, 2, 1), + (5850, 2, 137, 31, 0), + (5850, 3, 136, 5, 0), + (5860, 1, 243, 40, 0), + (5861, 1, 243, 45, 0), + (5862, 1, 243, 50, 0), + (5880, 1, 287, 8, 0), + (5880, 2, 385, 2754, 1), + (5881, 1, 287, 10, 0), + (5881, 2, 385, 2754, 1), + (5882, 1, 287, 12, 0), + (5882, 2, 385, 2754, 1), + (5883, 2, 139, 2754, 1), + (5886, 1, 274, 12, 0), + (5887, 1, 274, 14, 0), + (5888, 1, 274, 16, 0), + (5889, 1, 280, 51, 0), + (5890, 1, 280, 52, 0), + (5891, 1, 280, 53, 0), + (5909, 1, 279, 29, 0), + (5910, 1, 279, 30, 0), + (5911, 1, 279, 31, 0), + (5912, 1, 279, 32, 0), + (5913, 1, 279, 33, 0), + (5917, 1, 220, 100, 26), + (5917, 2, 220, 100, 30), + (5917, 3, 220, 100, 38), + (5918, 1, 220, 110, 26), + (5918, 2, 220, 110, 30), + (5918, 3, 220, 110, 38), + (5919, 1, 220, 120, 26), + (5919, 2, 220, 120, 30), + (5919, 3, 220, 120, 38), + (5922, 1, 292, 35, 0), + (5923, 1, 292, 40, 0), + (5924, 1, 292, 45, 0), + (5939, 1, 218, 6, 0), + (5940, 1, 218, 7, 0), + (5941, 1, 218, 8, 0), + (5942, 1, 218, 9, 0), + (5943, 1, 218, 10, 0), + (5944, 1, 273, 4, 0), + (5945, 1, 273, 5, 0), + (5946, 1, 273, 6, 0), + (5950, 1, 264, 240, 175), + (5950, 2, 264, 240, 792), + (5951, 1, 264, 300, 175), + (5951, 2, 264, 300, 792), + (5952, 1, 264, 360, 175), + (5952, 2, 264, 360, 792), + (5954, 1, 264, 2400, 68), + (5955, 1, 264, 3000, 68), + (5956, 1, 264, 3600, 68), + (5972, 1, 264, 2880, 6001), + (5972, 2, 264, 2880, 3676), + (5973, 1, 264, 2880, 6000), + (5973, 2, 264, 2880, 87), + (6003, 1, 279, 29, 0), + (6004, 1, 279, 30, 0), + (6005, 1, 279, 31, 0), + (6006, 1, 279, 32, 0), + (6007, 1, 279, 33, 0), + (6011, 1, 216, 95, 0), + (6011, 2, 216, 95, 1), + (6011, 3, 216, 95, 2), + (6011, 4, 216, 95, 3), + (6011, 5, 216, 95, 10), + (6011, 6, 216, 95, 28), + (6011, 7, 216, 95, 30), + (6011, 8, 216, 95, 36), + (6011, 9, 216, 95, 77), + (6012, 1, 216, 100, 0), + (6012, 2, 216, 100, 1), + (6012, 3, 216, 100, 2), + (6012, 4, 216, 100, 3), + (6012, 5, 216, 100, 10), + (6012, 6, 216, 100, 28), + (6012, 7, 216, 100, 30), + (6012, 8, 216, 100, 36), + (6012, 9, 216, 100, 77), + (6013, 1, 216, 105, 0), + (6013, 2, 216, 105, 1), + (6013, 3, 216, 105, 2), + (6013, 4, 216, 105, 3), + (6013, 5, 216, 105, 10), + (6013, 6, 216, 105, 28), + (6013, 7, 216, 105, 30), + (6013, 8, 216, 105, 36), + (6013, 9, 216, 105, 77), + (6014, 1, 360, 40, 12617), + (6015, 1, 360, 50, 12617), + (6016, 1, 360, 60, 12617), + (6017, 1, 217, 0, 65440), + (6017, 2, 346, 72, 28), + (6018, 1, 217, 0, 70880), + (6018, 2, 346, 74, 28), + (6019, 1, 217, 0, 76600), + (6019, 2, 346, 76, 28), + (6020, 1, 220, 15, 21), + (6020, 2, 220, 15, 23), + (6020, 3, 220, 30, 52), + (6020, 4, 220, 15, 28), + (6021, 1, 220, 25, 21), + (6021, 2, 220, 25, 23), + (6021, 3, 220, 50, 52), + (6021, 4, 220, 25, 28), + (6022, 1, 220, 35, 21), + (6022, 2, 220, 35, 23), + (6022, 3, 220, 70, 52), + (6022, 4, 220, 35, 28), + (6023, 1, 278, 900, 66950), + (6023, 2, 440, 82, 100), + (6024, 1, 278, 900, 70230), + (6024, 2, 440, 84, 100), + (6025, 1, 278, 900, 74935), + (6025, 2, 440, 86, 100), + (6026, 1, 127, 10, 0), + (6026, 2, 139, 16106, 0), + (6027, 1, 127, 25, 0), + (6027, 2, 139, 16106, 0), + (6028, 1, 127, 50, 0), + (6028, 2, 139, 16106, 0), + (6029, 1, 216, 200, 8), + (6030, 1, 216, 250, 8), + (6031, 1, 216, 300, 8), + (6032, 1, 439, 0, 70880), + (6032, 2, 345, 68, 50), + (6033, 1, 439, 0, 76600), + (6033, 2, 345, 70, 50), + (6034, 1, 439, 0, 82600), + (6034, 2, 345, 72, 35), + (6035, 1, 258, 48, 0), + (6036, 1, 258, 51, 0), + (6037, 1, 258, 54, 0), + (6042, 1, 220, 70, 8), + (6043, 1, 220, 80, 8), + (6044, 1, 220, 100, 8), + (6045, 1, 220, 45, 21), + (6045, 2, 220, 45, 23), + (6045, 3, 220, 90, 52), + (6045, 4, 220, 45, 28), + (6046, 1, 220, 55, 21), + (6046, 2, 220, 55, 23), + (6046, 3, 220, 110, 52), + (6046, 4, 220, 55, 28), + (6047, 1, 220, 65, 21), + (6047, 2, 220, 65, 23), + (6047, 3, 220, 130, 52), + (6047, 4, 220, 65, 28), + (6048, 1, 220, 75, 21), + (6048, 2, 220, 75, 23), + (6048, 3, 220, 150, 52), + (6048, 4, 220, 75, 28), + (6049, 1, 220, 85, 21), + (6049, 2, 220, 85, 23), + (6049, 3, 220, 170, 52), + (6049, 4, 220, 85, 28), + (6050, 1, 220, 95, 21), + (6050, 2, 220, 95, 23), + (6050, 3, 220, 190, 52), + (6050, 4, 220, 95, 28), + (6051, 1, 213, 1, 0), + (6052, 1, 213, 3, 0), + (6053, 1, 213, 5, 0), + (6057, 1, 220, 105, 21), + (6057, 2, 220, 105, 23), + (6057, 3, 220, 210, 52), + (6057, 4, 220, 105, 28), + (6058, 1, 220, 115, 21), + (6058, 2, 220, 115, 23), + (6058, 3, 220, 230, 52), + (6058, 4, 220, 115, 28), + (6059, 1, 220, 125, 21), + (6059, 2, 220, 125, 23), + (6059, 3, 220, 250, 52), + (6059, 4, 220, 125, 28), + (6060, 1, 247, 5, 76), + (6061, 1, 247, 10, 76), + (6063, 1, 303, 4500, 4500), + (6063, 2, 139, 2766, 0), + (6064, 1, 303, 5000, 5000), + (6064, 2, 139, 2766, 0), + (6065, 1, 303, 5500, 5500), + (6065, 2, 139, 2766, 0), + (6066, 1, 85, 12629, 0), + (6067, 1, 85, 12630, 0), + (6068, 1, 85, 12631, 0), + (6069, 1, 85, 12632, 0), + (6070, 1, 85, 12633, 0), + (6071, 1, 85, 12634, 0), + (6072, 1, 302, 266, 266), + (6072, 2, 385, 99, 0), + (6073, 1, 302, 290, 290), + (6073, 2, 385, 99, 0), + (6074, 1, 302, 310, 310), + (6074, 2, 385, 99, 0), + (6075, 1, 59, -18, 0), + (6076, 1, 59, -21, 0), + (6077, 1, 59, -24, 0), + (6078, 1, 59, -27, 0), + (6079, 1, 59, -30, 0), + (6080, 1, 189, 12, 0), + (6081, 1, 189, 13, 0), + (6082, 1, 247, 50, 20), + (6083, 1, 247, 75, 20), + (6084, 1, 247, 100, 20), + (6085, 1, 292, 20, 0), + (6086, 1, 292, 30, 0), + (6087, 1, 292, 40, 0), + (6088, 1, 264, 180, 392), + (6089, 1, 264, 360, 392), + (6090, 1, 264, 540, 392), + (6112, 1, 131, 10, 10), + (6112, 2, 348, 10, 0), + (6112, 3, 137, -32, 0), + (6113, 1, 287, 2, 0), + (6113, 2, 137, 100, 0), + (6113, 3, 385, -4232, 0), + (6113, 4, 385, -4332, 0), + (6113, 5, 139, -2741, 0), + (6113, 6, 385, -16192, 0), + (6113, 7, 139, -16843, 0), + (6114, 1, 287, 3, 0), + (6114, 2, 137, 100, 0), + (6114, 3, 385, -4232, 0), + (6114, 4, 385, -4332, 0), + (6114, 5, 139, -2741, 0), + (6114, 6, 385, -16192, 0), + (6114, 7, 139, -16843, 0), + (6115, 1, 287, 4, 0), + (6115, 2, 137, 100, 0), + (6115, 3, 385, -4232, 0), + (6115, 4, 385, -4332, 0), + (6115, 5, 139, -2741, 0), + (6115, 6, 385, -16192, 0), + (6115, 7, 139, -16843, 0), + (6119, 1, 69, 100, 0), + (6120, 1, 69, 200, 0), + (6121, 1, 69, 300, 0), + (6122, 1, 69, 400, 0), + (6123, 1, 69, 500, 0), + (6124, 1, 320, 1, 0), + (6125, 1, 320, 3, 0), + (6126, 1, 320, 5, 0), + (6127, 1, 320, 6, 0), + (6128, 1, 320, 7, 0), + (6129, 1, 320, 8, 0), + (6130, 1, 255, 48, 0), + (6131, 1, 255, 60, 0), + (6132, 1, 255, 72, 0), + (6136, 1, 264, 360, 300), + (6202, 1, 247, 10, 35), + (6203, 1, 247, 20, 35), + (6204, 1, 247, 60, 35), + (6209, 1, 264, 720, 245), + (6210, 1, 264, 1440, 245), + (6211, 1, 264, 2160, 245), + (6215, 1, 247, 5, 76), + (6216, 1, 247, 10, 76), + (6217, 1, 247, 15, 76), + (6223, 1, 232, 11, 4544), + (6224, 1, 232, 12, 4544), + (6225, 1, 232, 13, 4544), + (6226, 1, 232, 14, 4544), + (6227, 1, 232, 15, 4544), + (6228, 1, 264, 120, 404), + (6229, 1, 264, 240, 404), + (6230, 1, 264, 360, 404), + (6231, 1, 264, 480, 404), + (6233, 1, 264, 1728, 43), + (6234, 1, 264, 2160, 43), + (6235, 1, 264, 2592, 43), + (6236, 1, 287, 1, 0), + (6236, 2, 137, 3, 0), + (6236, 3, 137, 99, 0), + (6236, 4, 138, 0, 0), + (6236, 5, 244, 50, 0), + (6237, 1, 287, 2, 0), + (6237, 2, 137, 3, 0), + (6237, 3, 137, 99, 0), + (6237, 4, 138, 0, 0), + (6237, 5, 244, 38, 0), + (6238, 1, 287, 3, 0), + (6238, 2, 137, 3, 0), + (6238, 3, 137, 99, 0), + (6238, 4, 138, 0, 0), + (6238, 5, 244, 25, 0), + (6240, 1, 273, 3, 0), + (6241, 1, 273, 6, 0), + (6242, 1, 273, 9, 0), + (6243, 1, 273, 12, 0), + (6244, 1, 273, 15, 0), + (6245, 1, 273, 18, 0), + (6249, 1, 310, 1000, 0), + (6249, 2, 139, 11903, 0), + (6249, 3, 310, 1000, 0), + (6249, 4, 139, 11904, 0), + (6249, 5, 310, 1000, 0), + (6249, 6, 139, 11905, 0), + (6249, 7, 310, 1000, 0), + (6249, 8, 139, 1362, 0), + (6249, 9, 310, 1000, 0), + (6249, 10, 139, 8032, 0), + (6249, 11, 310, 1000, 0), + (6249, 12, 385, 6131, 0), + (6249, 13, 385, 6231, 0), + (6249, 14, 385, 6331, 0), + (6249, 15, 385, 6431, 0), + (6249, 16, 385, 6531, 0), + (6249, 17, 385, 6631, 0), + (6250, 1, 310, 2000, 0), + (6250, 2, 139, 11903, 0), + (6250, 3, 310, 2000, 0), + (6250, 4, 139, 11904, 0), + (6250, 5, 310, 2000, 0), + (6250, 6, 139, 11905, 0), + (6250, 7, 310, 2000, 0), + (6250, 8, 139, 1362, 0), + (6250, 9, 310, 2000, 0), + (6250, 10, 139, 8032, 0), + (6250, 11, 310, 2000, 0), + (6250, 12, 385, 6131, 0), + (6250, 13, 385, 6231, 0), + (6250, 14, 385, 6331, 0), + (6250, 15, 385, 6431, 0), + (6250, 16, 385, 6531, 0), + (6250, 17, 385, 6631, 0), + (6251, 1, 310, 3000, 0), + (6251, 2, 139, 11903, 0), + (6251, 3, 310, 3000, 0), + (6251, 4, 139, 11904, 0), + (6251, 5, 310, 3000, 0), + (6251, 6, 139, 11905, 0), + (6251, 7, 310, 3000, 0), + (6251, 8, 139, 1362, 0), + (6251, 9, 310, 3000, 0), + (6251, 10, 139, 8032, 0), + (6251, 11, 310, 3000, 0), + (6251, 12, 385, 6131, 0), + (6251, 13, 385, 6231, 0), + (6251, 14, 385, 6331, 0), + (6251, 15, 385, 6431, 0), + (6251, 16, 385, 6531, 0), + (6251, 17, 385, 6631, 0), + (6252, 1, 310, 4000, 0), + (6252, 2, 139, 11903, 0), + (6252, 3, 310, 4000, 0), + (6252, 4, 139, 11904, 0), + (6252, 5, 310, 4000, 0), + (6252, 6, 139, 11905, 0), + (6252, 7, 310, 4000, 0), + (6252, 8, 139, 1362, 0), + (6252, 9, 310, 4000, 0), + (6252, 10, 139, 8032, 0), + (6252, 11, 310, 4000, 0), + (6252, 12, 385, 6131, 0), + (6252, 13, 385, 6231, 0), + (6252, 14, 385, 6331, 0), + (6252, 15, 385, 6431, 0), + (6252, 16, 385, 6531, 0), + (6252, 17, 385, 6631, 0), + (6253, 1, 310, 5000, 0), + (6253, 2, 139, 11903, 0), + (6253, 3, 310, 5000, 0), + (6253, 4, 139, 11904, 0), + (6253, 5, 310, 5000, 0), + (6253, 6, 139, 11905, 0), + (6253, 7, 310, 5000, 0), + (6253, 8, 139, 1362, 0), + (6253, 9, 310, 5000, 0), + (6253, 10, 139, 8032, 0), + (6253, 11, 310, 5000, 0), + (6253, 12, 385, 6131, 0), + (6253, 13, 385, 6231, 0), + (6253, 14, 385, 6331, 0), + (6253, 15, 385, 6431, 0), + (6253, 16, 385, 6531, 0), + (6253, 17, 385, 6631, 0), + (6257, 1, 128, 5, 5), + (6257, 2, 138, 1, 0), + (6257, 3, 140, 1, 0), + (6257, 4, 139, -2741, 0), + (6257, 5, 139, -16843, 0), + (6257, 6, 385, -16192, 0), + (6258, 1, 128, 15, 15), + (6258, 2, 138, 1, 0), + (6258, 3, 140, 1, 0), + (6258, 4, 139, -2741, 0), + (6258, 5, 139, -16843, 0), + (6258, 6, 385, -16192, 0), + (6259, 1, 128, 30, 30), + (6259, 2, 138, 1, 0), + (6259, 3, 140, 1, 0), + (6259, 4, 139, -2741, 0), + (6259, 5, 139, -16843, 0), + (6259, 6, 385, -16192, 0), + (6260, 1, 264, 720, 98), + (6261, 1, 264, 900, 98), + (6262, 1, 264, 1080, 98), + (6266, 1, 224, 20, 10), + (6266, 2, 173, 1, 0), + (6267, 1, 224, 35, 10), + (6267, 2, 173, 2, 0), + (6268, 1, 224, 50, 10), + (6268, 2, 173, 3, 0), + (6269, 1, 224, 20, 30), + (6269, 2, 173, 1, 0), + (6270, 1, 224, 35, 30), + (6270, 2, 173, 2, 0), + (6271, 1, 224, 50, 30), + (6271, 2, 173, 3, 0), + (6272, 1, 264, 15, 672), + (6273, 1, 264, 30, 672), + (6274, 1, 264, 45, 672), + (6275, 1, 224, 20, 8), + (6275, 2, 173, 1, 0), + (6276, 1, 224, 35, 8), + (6276, 2, 173, 2, 0), + (6277, 1, 224, 50, 8), + (6277, 2, 173, 3, 0), + (6283, 1, 85, 13200, 0), + (6284, 1, 85, 13200, 25), + (6285, 1, 85, 13200, 50), + (6287, 1, 224, 20, 30), + (6287, 2, 173, 1, 0), + (6288, 1, 224, 35, 30), + (6288, 2, 173, 3, 0), + (6289, 1, 224, 50, 30), + (6289, 2, 173, 3, 0), + (6300, 1, 247, 20, 76), + (6301, 1, 247, 25, 76), + (6302, 1, 264, 120, 3710), + (6303, 1, 264, 240, 3710), + (6304, 1, 264, 360, 3710), + (6319, 1, 264, 1728, 107), + (6320, 1, 264, 2160, 107), + (6321, 1, 264, 2592, 107), + (6322, 1, 216, 5, 51), + (6323, 1, 216, 15, 51), + (6324, 1, 216, 25, 51), + (6331, 1, 252, 70, 0), + (6332, 1, 252, 75, 0), + (6334, 1, 185, 5, 51), + (6335, 1, 185, 10, 51), + (6336, 1, 185, 15, 51), + (6337, 1, 264, 60, 553), + (6338, 1, 264, 120, 553), + (6339, 1, 264, 180, 553), + (6340, 1, 264, 180, 777), + (6341, 1, 264, 360, 777), + (6342, 1, 264, 540, 777), + (6343, 1, 264, 5, 468), + (6343, 2, 264, 5, 469), + (6343, 3, 264, 5, 470), + (6344, 1, 264, 10, 468), + (6344, 2, 264, 10, 469), + (6344, 3, 264, 10, 470), + (6345, 1, 264, 15, 468), + (6345, 2, 264, 15, 469), + (6345, 3, 264, 15, 470), + (6346, 1, 264, 180, 494), + (6347, 1, 264, 360, 494), + (6348, 1, 264, 540, 494), + (6349, 1, 264, 180, 500), + (6350, 1, 264, 360, 500), + (6351, 1, 264, 540, 500), + (6355, 1, 310, 360000, 0), + (6355, 2, 139, 4506, 0), + (6355, 3, 310, 360000, 0), + (6355, 4, 385, 11122, 0), + (6355, 5, 385, 11222, 0), + (6355, 6, 385, 11322, 0), + (6355, 7, 385, 11522, 0), + (6356, 1, 310, 720000, 0), + (6356, 2, 139, 4506, 0), + (6356, 3, 310, 720000, 0), + (6356, 4, 385, 11122, 0), + (6356, 5, 385, 11222, 0), + (6356, 6, 385, 11322, 0), + (6356, 7, 385, 11522, 0), + (6357, 1, 310, 1080000, 0), + (6357, 2, 139, 4506, 0), + (6357, 3, 310, 1080000, 0), + (6357, 4, 385, 11122, 0), + (6357, 5, 385, 11222, 0), + (6357, 6, 385, 11322, 0), + (6357, 7, 385, 11522, 0), + (6358, 1, 310, 1440000, 0), + (6358, 2, 139, 4506, 0), + (6358, 3, 310, 1440000, 0), + (6358, 4, 385, 11122, 0), + (6358, 5, 385, 11222, 0), + (6358, 6, 385, 11322, 0), + (6358, 7, 385, 11522, 0), + (6359, 1, 310, 1800000, 0), + (6359, 2, 139, 4506, 0), + (6359, 3, 310, 1800000, 0), + (6359, 4, 385, 11122, 0), + (6359, 5, 385, 11222, 0), + (6359, 6, 385, 11322, 0), + (6359, 7, 385, 11522, 0), + (6360, 1, 310, 2160000, 0), + (6360, 2, 139, 4506, 0), + (6360, 3, 310, 2160000, 0), + (6360, 4, 385, 11122, 0), + (6360, 5, 385, 11222, 0), + (6360, 6, 385, 11322, 0), + (6360, 7, 385, 11522, 0), + (6361, 1, 213, 3, 0), + (6362, 1, 310, 120000, 0), + (6362, 2, 139, 5040, 0), + (6363, 1, 310, 240000, 0), + (6363, 2, 139, 5040, 0), + (6364, 1, 310, 360000, 0), + (6364, 2, 139, 5040, 0), + (6365, 1, 310, 480000, 0), + (6365, 2, 139, 5040, 0), + (6366, 1, 310, 600000, 0), + (6366, 2, 139, 5040, 0), + (6375, 1, 375, 107, 0), + (6376, 1, 375, 115, 0), + (6377, 1, 375, 125, 0), + (6383, 1, 215, 5, 0), + (6384, 1, 215, 7, 0), + (6385, 1, 215, 10, 0), + (6386, 1, 293, 5, 0), + (6387, 1, 293, 10, 0), + (6388, 1, 293, 15, 0), + (6389, 1, 293, 20, 0), + (6390, 1, 0, 16, 0), + (6391, 1, 0, 17, 0), + (6392, 1, 0, 18, 0), + (6393, 1, 0, 19, 0), + (6394, 1, 0, 20, 0), + (6395, 1, 85, 13502, 0), + (6396, 1, 85, 13503, 0), + (6397, 1, 85, 13504, 0), + (6403, 1, 294, 11, 100), + (6404, 1, 294, 13, 100), + (6405, 1, 294, 15, 100), + (6406, 1, 360, 25, 13201), + (6407, 1, 360, 25, 13202), + (6408, 1, 360, 25, 13203), + (6409, 1, 247, 5, 76), + (6410, 1, 247, 10, 76), + (6411, 1, 247, 15, 76), + (6412, 1, 247, 20, 76), + (6413, 1, 247, 25, 76), + (6414, 1, 247, 30, 76), + (6415, 1, 247, 35, 76), + (6416, 1, 247, 40, 76), + (6417, 1, 247, 45, 76), + (6418, 1, 247, 50, 76), + (6419, 1, 247, 5, 76), + (6420, 1, 247, 10, 76), + (6421, 1, 247, 15, 76), + (6422, 1, 214, 100, 0), + (6423, 1, 214, 200, 0), + (6424, 1, 214, 300, 0), + (6428, 1, 320, 1, 0), + (6429, 1, 320, 3, 0), + (6430, 1, 320, 5, 0), + (6431, 1, 317, 6, 0), + (6432, 1, 317, 7, 0), + (6433, 1, 317, 8, 0), + (6434, 1, 317, 9, 0), + (6435, 1, 317, 10, 0), + (6436, 1, 244, 70, 0), + (6437, 1, 244, 60, 0), + (6438, 1, 244, 50, 0), + (6439, 1, 264, 720, 41), + (6440, 1, 264, 900, 41), + (6441, 1, 264, 840, 420), + (6442, 1, 264, 540, 362), + (6443, 1, 264, 630, 362), + (6445, 1, 127, 15, 0), + (6445, 2, 139, 3248, 0), + (6445, 3, 127, 15, 0), + (6445, 4, 139, 3249, 0), + (6446, 1, 127, 30, 0), + (6446, 2, 139, 3248, 0), + (6446, 3, 127, 30, 0), + (6446, 4, 139, 3249, 0), + (6447, 1, 127, 50, 0), + (6447, 2, 139, 3248, 0), + (6447, 3, 127, 50, 0), + (6447, 4, 139, 3249, 0), + (6452, 1, 310, 1000, 0), + (6452, 2, 403, 7, 0), + (6452, 3, 404, 35, 0), + (6452, 4, 144, 2000, 0), + (6452, 5, 310, 5000, 0), + (6452, 6, 403, 7, 0), + (6452, 7, 404, 35, 0), + (6452, 8, 144, 10000, 0), + (6453, 1, 310, 2000, 0), + (6453, 2, 403, 7, 0), + (6453, 3, 404, 35, 0), + (6453, 4, 144, 2000, 0), + (6453, 5, 310, 10000, 0), + (6453, 6, 403, 7, 0), + (6453, 7, 404, 35, 0), + (6453, 8, 144, 10000, 0), + (6454, 1, 310, 3000, 0), + (6454, 2, 403, 7, 0), + (6454, 3, 404, 35, 0), + (6454, 4, 144, 2000, 0), + (6454, 5, 310, 15000, 0), + (6454, 6, 403, 7, 0), + (6454, 7, 404, 35, 0), + (6454, 8, 144, 10000, 0), + (6458, 1, 310, 30000, 0), + (6458, 2, 385, 5137, 0), + (6458, 3, 385, 5237, 0), + (6458, 4, 385, 5337, 0), + (6458, 5, 385, 5437, 0), + (6458, 6, 385, 5537, 0), + (6458, 7, 385, 5637, 0), + (6458, 8, 127, 15, 15), + (6458, 9, 385, 5137, 0), + (6458, 10, 385, 5237, 0), + (6458, 11, 385, 5337, 0), + (6458, 12, 385, 5437, 0), + (6458, 13, 385, 5537, 0), + (6458, 14, 385, 5637, 0), + (6459, 1, 310, 60000, 0), + (6459, 2, 385, 5137, 0), + (6459, 3, 385, 5237, 0), + (6459, 4, 385, 5337, 0), + (6459, 5, 385, 5437, 0), + (6459, 6, 385, 5537, 0), + (6459, 7, 385, 5637, 0), + (6459, 8, 127, 30, 30), + (6459, 9, 385, 5137, 0), + (6459, 10, 385, 5237, 0), + (6459, 11, 385, 5337, 0), + (6459, 12, 385, 5437, 0), + (6459, 13, 385, 5537, 0), + (6459, 14, 385, 5637, 0), + (6460, 1, 310, 90000, 0), + (6460, 2, 385, 5137, 0), + (6460, 3, 385, 5237, 0), + (6460, 4, 385, 5337, 0), + (6460, 5, 385, 5437, 0), + (6460, 6, 385, 5537, 0), + (6460, 7, 385, 5637, 0), + (6460, 8, 127, 50, 50), + (6460, 9, 385, 5137, 0), + (6460, 10, 385, 5237, 0), + (6460, 11, 385, 5337, 0), + (6460, 12, 385, 5437, 0), + (6460, 13, 385, 5537, 0), + (6460, 14, 385, 5637, 0), + (6461, 1, 127, 15, 0), + (6461, 2, 385, 14130, 0), + (6461, 3, 385, 14230, 0), + (6461, 4, 385, 14330, 0), + (6461, 5, 385, 14430, 0), + (6461, 6, 385, 14530, 0), + (6461, 7, 385, 14630, 0), + (6461, 8, 310, 30000, 0), + (6461, 9, 385, 14130, 0), + (6461, 10, 385, 14230, 0), + (6461, 11, 385, 14330, 0), + (6461, 12, 385, 14430, 0), + (6461, 13, 385, 14530, 0), + (6461, 14, 385, 14630, 0), + (6462, 1, 127, 30, 0), + (6462, 2, 385, 14130, 0), + (6462, 3, 385, 14230, 0), + (6462, 4, 385, 14330, 0), + (6462, 5, 385, 14430, 0), + (6462, 6, 385, 14530, 0), + (6462, 7, 385, 14630, 0), + (6462, 8, 310, 60000, 0), + (6462, 9, 385, 14130, 0), + (6462, 10, 385, 14230, 0), + (6462, 11, 385, 14330, 0), + (6462, 12, 385, 14430, 0), + (6462, 13, 385, 14530, 0), + (6462, 14, 385, 14630, 0), + (6463, 1, 127, 50, 0), + (6463, 2, 385, 14130, 0), + (6463, 3, 385, 14230, 0), + (6463, 4, 385, 14330, 0), + (6463, 5, 385, 14430, 0), + (6463, 6, 385, 14530, 0), + (6463, 7, 385, 14630, 0), + (6463, 8, 310, 90000, 0), + (6463, 9, 385, 14130, 0), + (6463, 10, 385, 14230, 0), + (6463, 11, 385, 14330, 0), + (6463, 12, 385, 14430, 0), + (6463, 13, 385, 14530, 0), + (6463, 14, 385, 14630, 0), + (6467, 1, 214, 100, 0), + (6468, 1, 214, 200, 0), + (6469, 1, 214, 300, 0), + (6470, 1, 247, 15, 76), + (6471, 1, 247, 20, 76), + (6472, 1, 247, 30, 76), + (6473, 1, 247, 35, 76), + (6474, 1, 247, 55, 76), + (6475, 1, 247, 60, 76), + (6476, 1, 247, 20, 76), + (6477, 1, 247, 25, 76), + (6478, 1, 264, 1, 3800), + (6479, 1, 264, 2, 3800), + (6480, 1, 264, 3, 3800), + (6481, 1, 264, 6480, 36), + (6482, 1, 264, 12960, 36), + (6483, 1, 264, 19440, 36), + (6484, 1, 264, 105, 558), + (6485, 1, 264, 120, 558), + (6486, 1, 264, 135, 558), + (6489, 1, 310, 600000, 0), + (6489, 2, 139, 4500, 0), + (6489, 3, 411, 8, 0), + (6490, 1, 310, 1200000, 0), + (6490, 2, 139, 4500, 0), + (6490, 3, 411, 8, 0), + (6491, 1, 310, 1800000, 0), + (6491, 2, 139, 4500, 0), + (6491, 3, 411, 8, 0), + (6500, 1, 273, 5, 0), + (6501, 1, 273, 6, 0), + (6502, 1, 273, 7, 0), + (6503, 1, 127, 12, 0), + (6503, 2, 385, 3338, 0), + (6504, 1, 127, 24, 0), + (6504, 2, 385, 3338, 0), + (6505, 1, 127, 36, 0), + (6505, 2, 385, 3338, 0), + (6506, 1, 127, 50, 0), + (6506, 2, 385, 3338, 0), + (6511, 1, 216, 5, 7), + (6512, 1, 216, 15, 7), + (6513, 1, 216, 25, 7), + (6514, 1, 127, 15, 0), + (6514, 2, 139, 5880, 0), + (6515, 1, 127, 30, 0), + (6515, 2, 139, 5880, 0), + (6516, 1, 127, 50, 0), + (6516, 2, 139, 5880, 0), + (6517, 1, 339, 10, 8105), + (6517, 2, 142, 65, 0), + (6517, 3, 311, 0, 0), + (6517, 4, 134, 70, 0), + (6517, 5, 348, 10, 0), + (6517, 6, 137, 0, 0), + (6517, 7, 339, 10, 8105), + (6517, 8, 142, 65, 0), + (6517, 9, 311, 0, 0), + (6517, 10, 134, 70, 0), + (6517, 11, 348, 10, 0), + (6517, 12, 137, 100, 0), + (6517, 13, 339, 10, 8105), + (6517, 14, 142, 65, 0), + (6517, 15, 311, 0, 0), + (6517, 16, 134, 70, 0), + (6517, 17, 348, 10, 0), + (6517, 18, 137, 79, 0), + (6517, 19, 339, 10, 8105), + (6517, 20, 142, 65, 0), + (6517, 21, 311, 0, 0), + (6517, 22, 134, 70, 0), + (6517, 23, 348, 10, 0), + (6517, 24, 137, 147, 0), + (6517, 25, 339, 10, 11404), + (6517, 26, 142, 71, 0), + (6517, 27, 311, 0, 0), + (6517, 28, 134, 75, 0), + (6517, 29, 348, 10, 0), + (6517, 30, 137, 0, 0), + (6517, 31, 339, 10, 11404), + (6517, 32, 142, 71, 0), + (6517, 33, 311, 0, 0), + (6517, 34, 134, 75, 0), + (6517, 35, 348, 10, 0), + (6517, 36, 137, 100, 0), + (6517, 37, 339, 10, 11404), + (6517, 38, 142, 71, 0), + (6517, 39, 311, 0, 0), + (6517, 40, 134, 75, 0), + (6517, 41, 348, 10, 0), + (6517, 42, 137, 79, 0), + (6517, 43, 339, 10, 11404), + (6517, 44, 142, 71, 0), + (6517, 45, 311, 0, 0), + (6517, 46, 134, 75, 0), + (6517, 47, 348, 10, 0), + (6517, 48, 137, 147, 0), + (6517, 49, 339, 10, 13199), + (6517, 50, 142, 76, 0), + (6517, 51, 311, 0, 0), + (6517, 52, 134, 80, 0), + (6517, 53, 348, 10, 0), + (6517, 54, 137, 0, 0), + (6517, 55, 339, 10, 13199), + (6517, 56, 142, 76, 0), + (6517, 57, 311, 0, 0), + (6517, 58, 134, 80, 0), + (6517, 59, 348, 10, 0), + (6517, 60, 137, 100, 0), + (6517, 61, 339, 10, 13199), + (6517, 62, 142, 76, 0), + (6517, 63, 311, 0, 0), + (6517, 64, 134, 80, 0), + (6517, 65, 348, 10, 0), + (6517, 66, 137, 79, 0), + (6517, 67, 339, 10, 13199), + (6517, 68, 142, 76, 0), + (6517, 69, 311, 0, 0), + (6517, 70, 134, 80, 0), + (6517, 71, 348, 10, 0), + (6517, 72, 137, 147, 0), + (6518, 1, 221, 18, 0), + (6519, 1, 221, 21, 0), + (6520, 1, 221, 24, 0), + (6521, 1, 327, 6, 0), + (6522, 1, 327, 7, 0), + (6523, 1, 328, 800, 0), + (6524, 1, 328, 850, 0), + (6525, 1, 328, 900, 0), + (6526, 1, 328, 950, 0), + (6527, 1, 328, 1000, 0), + (6528, 1, 264, 3024, 107), + (6531, 1, 360, 40, 11629), + (6532, 1, 360, 50, 11629), + (6533, 1, 360, 60, 11629), + (6540, 1, 363, 2, 0), + (6545, 1, 362, 2, 0), + (6546, 1, 2, 4, 0), + (6547, 1, 2, 8, 0), + (6548, 1, 2, 12, 0), + (6549, 1, 2, 16, 0), + (6550, 1, 2, 20, 0), + (6551, 1, 2, 24, 0), + (6552, 1, 2, 28, 0), + (6553, 1, 2, 32, 0), + (6554, 1, 2, 36, 0), + (6555, 1, 2, 40, 0), + (6556, 1, 2, 44, 0), + (6557, 1, 2, 48, 0), + (6558, 1, 2, 52, 0), + (6559, 1, 2, 56, 0), + (6560, 1, 2, 60, 0), + (6561, 1, 2, 64, 0), + (6562, 1, 2, 68, 0), + (6563, 1, 2, 72, 0), + (6564, 1, 2, 76, 0), + (6565, 1, 2, 80, 0), + (6566, 1, 2, 84, 0), + (6567, 1, 2, 88, 0), + (6568, 1, 2, 92, 0), + (6569, 1, 2, 96, 0), + (6570, 1, 2, 100, 0), + (6571, 1, 2, 104, 0), + (6601, 1, 339, 5, 13519), + (6601, 2, 137, 21, 0), + (6602, 1, 339, 10, 13519), + (6602, 2, 137, 21, 0), + (6603, 1, 339, 15, 13519), + (6603, 2, 137, 21, 0), + (6604, 1, 339, 20, 13519), + (6604, 2, 137, 21, 0), + (6605, 1, 339, 25, 13519), + (6605, 2, 137, 21, 0), + (6611, 1, 310, 120000, 0), + (6611, 2, 139, 4670, 0), + (6612, 1, 310, 240000, 0), + (6612, 2, 139, 4670, 0), + (6613, 1, 310, 360000, 0), + (6613, 2, 139, 4670, 0), + (6614, 1, 310, 120000, 0), + (6614, 2, 139, 4674, 0), + (6615, 1, 310, 240000, 0), + (6615, 2, 139, 4674, 0), + (6616, 1, 310, 360000, 0), + (6616, 2, 139, 4674, 0), + (6618, 1, 310, 480000, 0), + (6618, 2, 139, 4670, 0), + (6619, 1, 310, 600000, 0), + (6619, 2, 139, 4670, 0), + (6630, 1, 218, 1, 0), + (6631, 1, 218, 2, 0), + (6632, 1, 218, 3, 0), + (6633, 1, 218, 4, 0), + (6634, 1, 218, 5, 0), + (6636, 1, 294, 0, 107), + (6637, 1, 294, 0, 115), + (6638, 1, 294, 0, 125), + (6641, 1, 339, 10, 16101), + (6641, 2, 138, 0, 0), + (6641, 3, 142, 70, 0), + (6641, 4, 403, 4, 0), + (6641, 5, 348, 1, 0), + (6641, 6, 404, 2, 0), + (6641, 7, 141, 1, 0), + (6642, 1, 339, 10, 16102), + (6642, 2, 138, 0, 0), + (6642, 3, 142, 70, 0), + (6642, 4, 403, 4, 0), + (6642, 5, 348, 1, 0), + (6642, 6, 404, 2, 0), + (6642, 7, 141, 1, 0), + (6643, 1, 339, 10, 16103), + (6643, 2, 138, 0, 0), + (6643, 3, 142, 70, 0), + (6643, 4, 403, 4, 0), + (6643, 5, 348, 1, 0), + (6643, 6, 404, 2, 0), + (6643, 7, 141, 1, 0), + (6660, 1, 325, 55, 0), + (6661, 1, 325, 60, 0), + (6662, 1, 325, 65, 0), + (6666, 1, 287, 2, 0), + (6666, 2, 139, 8001, 0), + (6666, 3, 385, 12529, 0), + (6667, 1, 287, 4, 0), + (6667, 2, 139, 8001, 0), + (6667, 3, 385, 12529, 0), + (6668, 1, 287, 2, 0), + (6668, 2, 139, 11251, 0), + (6668, 3, 139, 11252, 0), + (6668, 4, 139, 11253, 0), + (6669, 1, 287, 4, 0), + (6669, 2, 139, 11251, 0), + (6669, 3, 139, 11252, 0), + (6669, 4, 139, 11253, 0), + (6670, 1, 287, 6, 0), + (6670, 2, 139, 11251, 0), + (6670, 3, 139, 11252, 0), + (6670, 4, 139, 11253, 0), + (6697, 1, 264, 30, 857), + (6698, 1, 264, 60, 857), + (6699, 1, 264, 90, 857), + (6700, 1, 264, 120, 857), + (6701, 1, 264, 150, 857), + (6703, 1, 264, 10, 171), + (6704, 1, 264, 20, 171), + (6705, 1, 264, 30, 171), + (6709, 1, 127, 5, 0), + (6709, 2, 139, 3842, 0), + (6710, 1, 127, 10, 0), + (6710, 2, 139, 3842, 0), + (6711, 1, 127, 15, 0), + (6711, 2, 139, 3842, 0), + (6712, 1, 264, 30, 177), + (6713, 1, 264, 60, 177), + (6714, 1, 264, 90, 177), + (6715, 1, 264, 120, 177), + (6716, 1, 264, 150, 177), + (6751, 1, 310, 240000, 0), + (6751, 2, 139, 4519, 0), + (6752, 1, 310, 480000, 0), + (6752, 2, 139, 4519, 0), + (6753, 1, 310, 720000, 0), + (6753, 2, 139, 4519, 0), + (6761, 1, 292, 5, 0), + (6762, 1, 292, 10, 0), + (6763, 1, 292, 15, 0), + (6765, 1, 330, 15, 7), + (6766, 1, 330, 30, 7), + (6767, 1, 330, 50, 7), + (6768, 1, 310, 960000, 0), + (6768, 2, 139, 4519, 0), + (6769, 1, 310, 1200000, 0), + (6769, 2, 139, 4519, 0), + (6791, 1, 339, 20, 16139), + (6791, 2, 137, 21, 0), + (6791, 3, 385, -18000, 0), + (6791, 4, 339, 20, 16139), + (6791, 5, 137, 343, 0), + (6791, 6, 385, -18000, 0), + (6792, 1, 339, 20, 16140), + (6792, 2, 137, 21, 0), + (6792, 3, 385, -18000, 0), + (6792, 4, 339, 20, 16140), + (6792, 5, 137, 343, 0), + (6792, 6, 385, -18000, 0), + (6793, 1, 339, 20, 16141), + (6793, 2, 137, 21, 0), + (6793, 3, 385, -18000, 0), + (6793, 4, 339, 20, 16141), + (6793, 5, 137, 343, 0), + (6793, 6, 385, -18000, 0), + (6819, 1, 264, 180, 524), + (6820, 1, 264, 360, 524), + (6821, 1, 264, 540, 524), + (6823, 1, 264, 180, 320), + (6824, 1, 264, 360, 320), + (6825, 1, 264, 540, 320), + (6826, 1, 264, 720, 320), + (6827, 1, 264, 900, 320), + (6870, 1, 264, 180, 544), + (6871, 1, 264, 360, 544), + (6872, 1, 264, 540, 544), + (6873, 1, 279, 7, 0), + (6874, 1, 279, 11, 0), + (6875, 1, 279, 15, 0), + (6876, 1, 375, 107, 0), + (6877, 1, 375, 115, 0), + (6878, 1, 375, 125, 0), + (6879, 1, 243, 15, 0), + (6880, 1, 243, 25, 0), + (6881, 1, 243, 35, 0), + (6882, 1, 242, 5, 0), + (6883, 1, 242, 10, 0), + (6884, 1, 242, 15, 0), + (6900, 1, 264, 840, 465), + (6901, 1, 264, 1140, 465), + (6902, 1, 264, 1440, 465), + (6903, 1, 264, 1740, 465), + (6904, 1, 264, 2040, 465), + (6905, 1, 225, 33, 0), + (6906, 1, 225, 36, 0), + (6907, 1, 225, 39, 0), + (6908, 1, 264, 180, 499), + (6909, 1, 264, 360, 499), + (6910, 1, 264, 540, 499), + (6911, 1, 224, 60, 74), + (6911, 2, 173, 2, 0), + (6912, 1, 224, 70, 74), + (6912, 2, 173, 3, 0), + (6913, 1, 224, 80, 74), + (6913, 2, 173, 3, 0), + (6935, 1, 264, 180, 465), + (6936, 1, 264, 360, 465), + (6937, 1, 264, 540, 465), + (6938, 1, 361, 65, 16164), + (6939, 1, 361, 75, 16165), + (6940, 1, 361, 85, 16166), + (6941, 1, 264, 120, 962), + (6942, 1, 264, 240, 962), + (6943, 1, 264, 360, 962), + (6944, 1, 264, 480, 962), + (6945, 1, 264, 600, 962), + (6974, 1, 264, 3, 247), + (6974, 2, 264, 2, 986), + (6974, 3, 264, 2, 987), + (6974, 4, 264, 2, 988), + (6975, 1, 264, 6, 247), + (6975, 2, 264, 4, 986), + (6975, 3, 264, 4, 987), + (6975, 4, 264, 4, 988), + (6976, 1, 264, 12, 247), + (6976, 2, 264, 6, 986), + (6976, 3, 264, 6, 987), + (6976, 4, 264, 6, 988), + (6977, 1, 264, 6, 3817), + (6978, 1, 264, 12, 3817), + (6979, 1, 264, 18, 3817), + (6980, 1, 264, 45, 128), + (6981, 1, 264, 90, 128), + (6982, 1, 264, 135, 128), + (6987, 1, 353, 1, 0), + (6988, 1, 287, 1, 0), + (6988, 2, 385, 16439, 0), + (6988, 3, 411, 32768, 0), + (6989, 1, 287, 2, 0), + (6989, 2, 385, 16439, 0), + (6989, 3, 411, 32768, 0), + (6990, 1, 287, 3, 0), + (6990, 2, 385, 16439, 0), + (6990, 3, 411, 32768, 0), + (7005, 1, 264, 432, 789), + (7006, 1, 264, 864, 789), + (7007, 1, 264, 1296, 789), + (7008, 1, 439, 0, 109400), + (7008, 2, 345, 80, 35), + (7009, 1, 439, 0, 116800), + (7009, 2, 345, 82, 35), + (7010, 1, 378, 25, 96), + (7011, 1, 378, 30, 96), + (7012, 1, 378, 35, 96), + (7013, 1, 378, 40, 96), + (7014, 1, 378, 45, 96), + (7015, 1, 378, 50, 96), + (7033, 1, 421, 5, 0), + (7033, 2, 139, 16097, 0), + (7033, 3, 139, 23612, 0), + (7033, 4, 139, 32196, 0), + (7033, 5, 139, 32565, 0), + (7033, 6, 423, 6, 0), + (7033, 7, 422, 5, 0), + (7033, 8, 411, 2, 0), + (7034, 1, 421, 10, 0), + (7034, 2, 139, 16097, 0), + (7034, 3, 139, 23612, 0), + (7034, 4, 139, 32196, 0), + (7034, 5, 139, 32565, 0), + (7034, 6, 423, 6, 0), + (7034, 7, 422, 5, 0), + (7034, 8, 411, 2, 0), + (7035, 1, 421, 15, 0), + (7035, 2, 139, 16097, 0), + (7035, 3, 139, 23612, 0), + (7035, 4, 139, 32196, 0), + (7035, 5, 139, 32565, 0), + (7035, 6, 423, 6, 0), + (7035, 7, 422, 5, 0), + (7035, 8, 411, 2, 0), + (7036, 1, 264, 10, 3646), + (7037, 1, 264, 20, 3646), + (7038, 1, 264, 30, 3646), + (7050, 1, 265, 62, 0), + (7051, 1, 265, 64, 0), + (7052, 1, 265, 66, 0), + (7053, 1, 265, 67, 0), + (7054, 1, 265, 69, 0), + (7055, 1, 265, 71, 0), + (7056, 1, 265, 62, 0), + (7057, 1, 265, 64, 0), + (7058, 1, 265, 66, 0), + (7059, 1, 265, 67, 0), + (7060, 1, 265, 69, 0), + (7061, 1, 265, 71, 0), + (7062, 1, 372, 50, 0), + (7063, 1, 265, 72, 0), + (7064, 1, 265, 74, 0), + (7065, 1, 265, 76, 0), + (7066, 1, 265, 72, 0), + (7067, 1, 265, 74, 0), + (7068, 1, 265, 76, 0), + (7100, 1, 264, 180, 254), + (7101, 1, 264, 360, 254), + (7102, 1, 264, 540, 254), + (7103, 1, 264, 432, 286), + (7103, 2, 264, 432, 10753), + (7103, 3, 264, 432, 9101), + (7104, 1, 264, 864, 286), + (7104, 2, 264, 864, 10753), + (7104, 3, 264, 864, 9101), + (7105, 1, 264, 1296, 286), + (7105, 2, 264, 1296, 10753), + (7105, 3, 264, 1296, 9101), + (7106, 1, 224, 20, 30), + (7106, 2, 173, 1, 0), + (7107, 1, 224, 35, 30), + (7107, 2, 173, 2, 0), + (7108, 1, 224, 50, 30), + (7108, 2, 173, 3, 0), + (7112, 1, 85, 13596, 50), + (7113, 1, 85, 13597, 50), + (7114, 1, 85, 13598, 50), + (7116, 1, 264, 360, 110), + (7117, 1, 264, 450, 110), + (7118, 1, 264, 540, 110), + (7122, 1, 349, 30, 0), + (7123, 1, 349, 35, 0), + (7124, 1, 349, 40, 0), + (7125, 1, 349, 45, 0), + (7126, 1, 349, 50, 0), + (7128, 1, 264, 240, 109), + (7129, 1, 264, 300, 109), + (7130, 1, 264, 360, 109), + (7131, 1, 439, 0, 88880), + (7131, 2, 345, 74, 28), + (7132, 1, 439, 0, 95440), + (7132, 2, 345, 76, 28), + (7133, 1, 439, 0, 102280), + (7133, 2, 345, 78, 28), + (7134, 1, 220, 120, 8), + (7135, 1, 220, 140, 8), + (7136, 1, 220, 165, 8), + (7137, 1, 264, 60, 672), + (7138, 1, 264, 75, 672), + (7139, 1, 264, 90, 672), + (7146, 1, 252, 80, 0), + (7147, 1, 252, 85, 0), + (7148, 1, 216, 350, 8), + (7149, 1, 216, 400, 8), + (7150, 1, 216, 450, 8), + (7151, 1, 258, 59, 0), + (7152, 1, 258, 64, 0), + (7153, 1, 258, 69, 0), + (7160, 1, 227, 120, 32), + (7161, 1, 227, 150, 32), + (7162, 1, 227, 180, 32), + (7163, 1, 220, 130, 26), + (7163, 2, 220, 130, 30), + (7163, 3, 220, 130, 38), + (7164, 1, 220, 140, 26), + (7164, 2, 220, 140, 30), + (7164, 3, 220, 140, 38), + (7165, 1, 220, 150, 26), + (7165, 2, 220, 150, 30), + (7165, 3, 220, 150, 38), + (7166, 1, 264, 20, 468), + (7166, 2, 264, 20, 469), + (7166, 3, 264, 20, 470), + (7167, 1, 264, 25, 468), + (7167, 2, 264, 25, 469), + (7167, 3, 264, 25, 470), + (7168, 1, 264, 30, 468), + (7168, 2, 264, 30, 469), + (7168, 3, 264, 30, 470), + (7169, 1, 220, 135, 21), + (7169, 2, 220, 135, 23), + (7169, 3, 220, 270, 52), + (7169, 4, 220, 135, 28), + (7170, 1, 220, 145, 21), + (7170, 2, 220, 145, 23), + (7170, 3, 220, 290, 52), + (7170, 4, 220, 145, 28), + (7171, 1, 220, 155, 21), + (7171, 2, 220, 155, 23), + (7171, 3, 220, 310, 52), + (7171, 4, 220, 155, 28), + (7175, 1, 283, 120, 0), + (7176, 1, 283, 140, 0), + (7177, 1, 283, 160, 0), + (7196, 1, 169, 20, -1), + (7197, 1, 169, 25, -1), + (7198, 1, 169, 30, -1), + (7204, 1, 218, 11, 0), + (7205, 1, 218, 12, 0), + (7206, 1, 218, 13, 0), + (7207, 1, 218, 14, 0), + (7208, 1, 218, 15, 0), + (7210, 1, 280, 50, 0), + (7211, 1, 280, 53, 0), + (7212, 1, 280, 56, 0), + (7213, 1, 280, 59, 0), + (7214, 1, 280, 62, 0), + (7215, 1, 264, 4200, 68), + (7216, 1, 264, 4800, 68), + (7220, 1, 360, 60, 12701), + (7221, 1, 360, 60, 12702), + (7222, 1, 360, 60, 12703), + (7232, 1, 294, 0, 185), + (7233, 1, 294, 0, 190), + (7234, 1, 294, 0, 195), + (7260, 1, 287, 14, 0), + (7260, 2, 385, 2754, 1), + (7261, 1, 287, 16, 0), + (7261, 2, 385, 2754, 1), + (7262, 1, 287, 18, 0), + (7262, 2, 385, 2754, 1), + (7263, 1, 274, 18, 0), + (7264, 1, 274, 20, 0), + (7265, 1, 274, 22, 0), + (7267, 1, 280, 54, 0), + (7268, 1, 280, 55, 0), + (7269, 1, 280, 56, 0), + (7270, 1, 218, 16, 0), + (7271, 1, 218, 17, 0), + (7272, 1, 218, 18, 0), + (7273, 1, 218, 19, 0), + (7274, 1, 218, 20, 0), + (7279, 1, 310, 6000, 0), + (7279, 2, 139, 11903, 0), + (7279, 3, 310, 6000, 0), + (7279, 4, 139, 11904, 0), + (7279, 5, 310, 6000, 0), + (7279, 6, 139, 11905, 0), + (7279, 7, 310, 6000, 0), + (7279, 8, 139, 1362, 0), + (7279, 9, 310, 6000, 0), + (7279, 10, 139, 8032, 0), + (7279, 11, 310, 6000, 0), + (7279, 12, 385, 6131, 0), + (7279, 13, 385, 6231, 0), + (7279, 14, 385, 6331, 0), + (7279, 15, 385, 6431, 0), + (7279, 16, 385, 6531, 0), + (7279, 17, 385, 6631, 0), + (7280, 1, 310, 7000, 0), + (7280, 2, 139, 11903, 0), + (7280, 3, 310, 7000, 0), + (7280, 4, 139, 11904, 0), + (7280, 5, 310, 7000, 0), + (7280, 6, 139, 11905, 0), + (7280, 7, 310, 7000, 0), + (7280, 8, 139, 1362, 0), + (7280, 9, 310, 7000, 0), + (7280, 10, 139, 8032, 0), + (7280, 11, 310, 7000, 0), + (7280, 12, 385, 6131, 0), + (7280, 13, 385, 6231, 0), + (7280, 14, 385, 6331, 0), + (7280, 15, 385, 6431, 0), + (7280, 16, 385, 6531, 0), + (7280, 17, 385, 6631, 0), + (7281, 1, 310, 8000, 0), + (7281, 2, 139, 11903, 0), + (7281, 3, 310, 8000, 0), + (7281, 4, 139, 11904, 0), + (7281, 5, 310, 8000, 0), + (7281, 6, 139, 11905, 0), + (7281, 7, 310, 8000, 0), + (7281, 8, 139, 1362, 0), + (7281, 9, 310, 8000, 0), + (7281, 10, 139, 8032, 0), + (7281, 11, 310, 8000, 0), + (7281, 12, 385, 6131, 0), + (7281, 13, 385, 6231, 0), + (7281, 14, 385, 6331, 0), + (7281, 15, 385, 6431, 0), + (7281, 16, 385, 6531, 0), + (7281, 17, 385, 6631, 0), + (7282, 1, 310, 9000, 0), + (7282, 2, 139, 11903, 0), + (7282, 3, 310, 9000, 0), + (7282, 4, 139, 11904, 0), + (7282, 5, 310, 9000, 0), + (7282, 6, 139, 11905, 0), + (7282, 7, 310, 9000, 0), + (7282, 8, 139, 1362, 0), + (7282, 9, 310, 9000, 0), + (7282, 10, 139, 8032, 0), + (7282, 11, 310, 9000, 0), + (7282, 12, 385, 6131, 0), + (7282, 13, 385, 6231, 0), + (7282, 14, 385, 6331, 0), + (7282, 15, 385, 6431, 0), + (7282, 16, 385, 6531, 0), + (7282, 17, 385, 6631, 0), + (7283, 1, 310, 10000, 0), + (7283, 2, 139, 11903, 0), + (7283, 3, 310, 10000, 0), + (7283, 4, 139, 11904, 0), + (7283, 5, 310, 10000, 0), + (7283, 6, 139, 11905, 0), + (7283, 7, 310, 10000, 0), + (7283, 8, 139, 1362, 0), + (7283, 9, 310, 10000, 0), + (7283, 10, 139, 8032, 0), + (7283, 11, 310, 10000, 0), + (7283, 12, 385, 6131, 0), + (7283, 13, 385, 6231, 0), + (7283, 14, 385, 6331, 0), + (7283, 15, 385, 6431, 0), + (7283, 16, 385, 6531, 0), + (7283, 17, 385, 6631, 0), + (7284, 1, 287, 3, 0), + (7284, 2, 137, 31, 0), + (7284, 3, 136, 5, 0), + (7313, 1, 244, 40, 0), + (7314, 1, 244, 30, 0), + (7315, 1, 244, 20, 0), + (7316, 1, 264, 1080, 41), + (7317, 1, 264, 1260, 41), + (7318, 1, 339, 25, 16015), + (7318, 2, 137, 21, 0), + (7319, 1, 339, 25, 16016), + (7319, 2, 137, 21, 0), + (7320, 1, 339, 25, 16017), + (7320, 2, 137, 21, 0), + (7321, 1, 339, 25, 16018), + (7321, 2, 137, 21, 0), + (7322, 1, 339, 25, 16019), + (7322, 2, 137, 21, 0), + (7323, 1, 264, 720, 254), + (7324, 1, 264, 900, 254), + (7325, 1, 264, 1080, 254), + (7326, 1, 264, 1728, 286), + (7326, 2, 264, 1728, 10753), + (7326, 3, 264, 1728, 9101), + (7327, 1, 264, 2160, 286), + (7327, 2, 264, 2160, 10753), + (7327, 3, 264, 2160, 9101), + (7328, 1, 264, 2592, 286), + (7328, 2, 264, 2592, 10753), + (7328, 3, 264, 2592, 9101), + (7336, 1, 85, 16029, 0), + (7337, 1, 85, 16030, 0), + (7338, 1, 85, 16031, 0), + (7353, 1, 216, 115, 0), + (7353, 2, 216, 115, 1), + (7353, 3, 216, 115, 2), + (7353, 4, 216, 115, 3), + (7353, 5, 216, 115, 10), + (7353, 6, 216, 115, 28), + (7353, 7, 216, 115, 30), + (7353, 8, 216, 115, 36), + (7353, 9, 216, 115, 77), + (7354, 1, 216, 120, 0), + (7354, 2, 216, 120, 1), + (7354, 3, 216, 120, 2), + (7354, 4, 216, 120, 3), + (7354, 5, 216, 120, 10), + (7354, 6, 216, 120, 28), + (7354, 7, 216, 120, 30), + (7354, 8, 216, 120, 36), + (7354, 9, 216, 120, 77), + (7355, 1, 216, 125, 0), + (7355, 2, 216, 125, 1), + (7355, 3, 216, 125, 2), + (7355, 4, 216, 125, 3), + (7355, 5, 216, 125, 10), + (7355, 6, 216, 125, 28), + (7355, 7, 216, 125, 30), + (7355, 8, 216, 125, 36), + (7355, 9, 216, 125, 77), + (7356, 1, 360, 60, 16056), + (7357, 1, 360, 60, 16057), + (7358, 1, 360, 60, 16058), + (7359, 1, 217, 0, 82600), + (7359, 2, 346, 78, 22), + (7360, 1, 217, 0, 88880), + (7360, 2, 346, 80, 22), + (7361, 1, 217, 0, 95440), + (7361, 2, 346, 82, 22), + (7362, 1, 59, -18, 0), + (7363, 1, 59, -21, 0), + (7364, 1, 59, -24, 0), + (7365, 1, 59, -27, 0), + (7366, 1, 59, -30, 0), + (7373, 1, 2, 108, 0), + (7374, 1, 2, 112, 0), + (7375, 1, 2, 116, 0), + (7376, 1, 2, 120, 0), + (7377, 1, 2, 124, 0), + (7378, 1, 347, 14, 0), + (7379, 1, 347, 16, 0), + (7380, 1, 347, 18, 0), + (7381, 1, 347, 20, 0), + (7382, 1, 347, 22, 0), + (7383, 1, 347, 24, 0), + (7384, 1, 360, 25, 16063), + (7385, 1, 360, 25, 16064), + (7386, 1, 360, 25, 16065), + (7390, 1, 303, 6000, 6000), + (7390, 2, 139, 2766, 0), + (7391, 1, 303, 6500, 6500), + (7391, 2, 139, 2766, 0), + (7392, 1, 303, 7500, 8500), + (7392, 2, 139, 2766, 0), + (7393, 1, 85, 16066, 0), + (7394, 1, 85, 16067, 0), + (7395, 1, 85, 16068, 0), + (7396, 1, 85, 16069, 0), + (7397, 1, 85, 16070, 0), + (7398, 1, 85, 16071, 0), + (7399, 1, 302, 350, 350), + (7399, 2, 385, 99, 0), + (7400, 1, 302, 370, 370), + (7400, 2, 385, 99, 0), + (7401, 1, 302, 400, 400), + (7401, 2, 385, 99, 0), + (7402, 1, 59, -33, 0), + (7403, 1, 59, -36, 0), + (7404, 1, 59, -39, 0), + (7405, 1, 59, -42, 0), + (7406, 1, 59, -45, 0), + (7407, 1, 181, 100, -1), + (7448, 1, 264, 240, 553), + (7449, 1, 264, 300, 553), + (7450, 1, 264, 360, 553), + (7451, 1, 264, 720, 777), + (7452, 1, 264, 900, 777), + (7453, 1, 264, 1080, 777), + (7478, 1, 264, 2880, 245), + (7489, 1, 218, 16, 0), + (7490, 1, 218, 17, 0), + (7491, 1, 218, 18, 0), + (7492, 1, 218, 19, 0), + (7493, 1, 218, 20, 0), + (7494, 1, 280, 65, 0), + (7495, 1, 280, 66, 0), + (7496, 1, 280, 67, 0), + (7500, 1, 363, 3, 0), + (7501, 1, 172, 45, 0), + (7502, 1, 172, 46, 0), + (7503, 1, 172, 47, 0), + (7504, 1, 172, 48, 0), + (7505, 1, 172, 49, 0), + (7506, 1, 259, 51, 0), + (7507, 1, 259, 52, 0), + (7508, 1, 259, 53, 0), + (7509, 1, 259, 54, 0), + (7510, 1, 259, 55, 0), + (7511, 1, 328, 1050, 0), + (7512, 1, 328, 1100, 0), + (7513, 1, 328, 1150, 0), + (7514, 1, 328, 1200, 0), + (7515, 1, 328, 1250, 0), + (7516, 1, 262, 30, 7), + (7516, 2, 262, 30, 8), + (7516, 3, 262, 30, 9), + (7516, 4, 262, 30, 10), + (7516, 5, 262, 30, 11), + (7517, 1, 262, 35, 7), + (7517, 2, 262, 35, 8), + (7517, 3, 262, 35, 9), + (7517, 4, 262, 35, 10), + (7517, 5, 262, 35, 11), + (7518, 1, 262, 40, 7), + (7518, 2, 262, 40, 8), + (7518, 3, 262, 40, 9), + (7518, 4, 262, 40, 10), + (7518, 5, 262, 40, 11), + (7519, 1, 262, 45, 7), + (7519, 2, 262, 45, 8), + (7519, 3, 262, 45, 9), + (7519, 4, 262, 45, 10), + (7519, 5, 262, 45, 11), + (7520, 1, 262, 50, 7), + (7520, 2, 262, 50, 8), + (7520, 3, 262, 50, 9), + (7520, 4, 262, 50, 10), + (7520, 5, 262, 50, 11), + (7521, 1, 317, 11, 0), + (7522, 1, 317, 12, 0), + (7523, 1, 317, 13, 0), + (7524, 1, 317, 14, 0), + (7525, 1, 317, 15, 0), + (7526, 1, 69, 600, 0), + (7527, 1, 69, 700, 0), + (7528, 1, 69, 800, 0), + (7529, 1, 69, 900, 0), + (7530, 1, 69, 1000, 0), + (7534, 1, 0, 21, 0), + (7535, 1, 0, 22, 0), + (7536, 1, 0, 23, 0), + (7537, 1, 0, 24, 0), + (7538, 1, 0, 25, 0), + (7539, 1, 327, 8, 0), + (7540, 1, 327, 9, 0), + (7541, 1, 214, 1100, 0), + (7542, 1, 214, 1200, 0), + (7543, 1, 214, 1300, 0), + (7544, 1, 221, 27, 0), + (7545, 1, 221, 30, 0), + (7546, 1, 221, 33, 0), + (7547, 1, 262, 80, 0), + (7547, 2, 262, 80, 1), + (7547, 3, 262, 80, 2), + (7547, 4, 262, 80, 3), + (7547, 5, 262, 80, 4), + (7547, 6, 262, 80, 5), + (7547, 7, 262, 80, 6), + (7548, 1, 262, 85, 0), + (7548, 2, 262, 85, 1), + (7548, 3, 262, 85, 2), + (7548, 4, 262, 85, 3), + (7548, 5, 262, 85, 4), + (7548, 6, 262, 85, 5), + (7548, 7, 262, 85, 6), + (7549, 1, 262, 90, 0), + (7549, 2, 262, 90, 1), + (7549, 3, 262, 90, 2), + (7549, 4, 262, 90, 3), + (7549, 5, 262, 90, 4), + (7549, 6, 262, 90, 5), + (7549, 7, 262, 90, 6), + (7550, 1, 262, 95, 0), + (7550, 2, 262, 95, 1), + (7550, 3, 262, 95, 2), + (7550, 4, 262, 95, 3), + (7550, 5, 262, 95, 4), + (7550, 6, 262, 95, 5), + (7550, 7, 262, 95, 6), + (7551, 1, 262, 100, 0), + (7551, 2, 262, 100, 1), + (7551, 3, 262, 100, 2), + (7551, 4, 262, 100, 3), + (7551, 5, 262, 100, 4), + (7551, 6, 262, 100, 5), + (7551, 7, 262, 100, 6), + (7553, 1, 326, 3, 0), + (7554, 1, 339, 20, 16194), + (7554, 2, 138, 1, 0), + (7554, 3, 141, 1, 0), + (7554, 4, 142, 65, 0), + (7554, 5, 137, 0, 0), + (7554, 6, 311, 0, 0), + (7554, 7, 134, 85, 0), + (7554, 8, 139, -265, 0), + (7554, 9, 139, -754, 0), + (7554, 10, 139, -1332, 0), + (7554, 11, 139, -1572, 0), + (7554, 12, 139, -2749, 0), + (7554, 13, 139, -4979, 0), + (7554, 14, 139, -5418, 0), + (7554, 15, 139, -5403, 0), + (7554, 16, 348, 10, 0), + (7555, 1, 339, 21, 16195), + (7555, 2, 138, 1, 0), + (7555, 3, 141, 1, 0), + (7555, 4, 142, 65, 0), + (7555, 5, 137, 0, 0), + (7555, 6, 311, 0, 0), + (7555, 7, 134, 85, 0), + (7555, 8, 139, -265, 0), + (7555, 9, 139, -754, 0), + (7555, 10, 139, -1332, 0), + (7555, 11, 139, -1572, 0), + (7555, 12, 139, -2749, 0), + (7555, 13, 139, -4979, 0), + (7555, 14, 139, -5418, 0), + (7555, 15, 139, -5403, 0), + (7555, 16, 348, 10, 0), + (7556, 1, 339, 22, 16196), + (7556, 2, 138, 1, 0), + (7556, 3, 141, 1, 0), + (7556, 4, 142, 65, 0), + (7556, 5, 137, 0, 0), + (7556, 6, 311, 0, 0), + (7556, 7, 134, 85, 0), + (7556, 8, 139, -265, 0), + (7556, 9, 139, -754, 0), + (7556, 10, 139, -1332, 0), + (7556, 11, 139, -1572, 0), + (7556, 12, 139, -2749, 0), + (7556, 13, 139, -4979, 0), + (7556, 14, 139, -5418, 0), + (7556, 15, 139, -5403, 0), + (7556, 16, 348, 10, 0), + (7557, 1, 339, 23, 16417), + (7557, 2, 138, 1, 0), + (7557, 3, 141, 1, 0), + (7557, 4, 142, 65, 0), + (7557, 5, 137, 0, 0), + (7557, 6, 311, 0, 0), + (7557, 7, 134, 85, 0), + (7557, 8, 139, -265, 0), + (7557, 9, 139, -754, 0), + (7557, 10, 139, -1332, 0), + (7557, 11, 139, -1572, 0), + (7557, 12, 139, -2749, 0), + (7557, 13, 139, -4979, 0), + (7557, 14, 139, -5418, 0), + (7557, 15, 139, -5403, 0), + (7557, 16, 348, 10, 0), + (7558, 1, 339, 24, 16418), + (7558, 2, 138, 1, 0), + (7558, 3, 141, 1, 0), + (7558, 4, 142, 65, 0), + (7558, 5, 137, 0, 0), + (7558, 6, 311, 0, 0), + (7558, 7, 134, 85, 0), + (7558, 8, 139, -265, 0), + (7558, 9, 139, -754, 0), + (7558, 10, 139, -1332, 0), + (7558, 11, 139, -1572, 0), + (7558, 12, 139, -2749, 0), + (7558, 13, 139, -4979, 0), + (7558, 14, 139, -5418, 0), + (7558, 15, 139, -5403, 0), + (7558, 16, 348, 10, 0), + (7559, 1, 266, 23, 0), + (7560, 1, 266, 24, 0), + (7561, 1, 266, 25, 0), + (7562, 1, 330, 125, 0), + (7562, 2, 330, 125, 1), + (7562, 3, 330, 125, 2), + (7562, 4, 330, 125, 3), + (7562, 5, 330, 125, 28), + (7562, 6, 330, 125, 36), + (7562, 7, 330, 125, 77), + (7563, 1, 330, 130, 0), + (7563, 2, 330, 130, 1), + (7563, 3, 330, 130, 2), + (7563, 4, 330, 130, 3), + (7563, 5, 330, 130, 28), + (7563, 6, 330, 130, 36), + (7563, 7, 330, 130, 77), + (7564, 1, 330, 135, 0), + (7564, 2, 330, 135, 1), + (7564, 3, 330, 135, 2), + (7564, 4, 330, 135, 3), + (7564, 5, 330, 135, 28), + (7564, 6, 330, 135, 36), + (7564, 7, 330, 135, 77), + (7565, 1, 278, 800, 54510), + (7565, 2, 440, 76, 100), + (7566, 1, 278, 850, 58400), + (7566, 2, 440, 78, 100), + (7567, 1, 278, 900, 62680), + (7567, 2, 440, 80, 100), + (7568, 1, 341, 160, 0), + (7569, 1, 341, 170, 0), + (7570, 1, 341, 180, 0), + (7571, 1, 341, 190, 0), + (7572, 1, 341, 200, 0), + (7573, 1, 360, 70, 11023), + (7574, 1, 360, 80, 11023), + (7575, 1, 360, 90, 11023), + (7576, 1, 318, 16, 0), + (7577, 1, 318, 17, 0), + (7578, 1, 318, 18, 0), + (7579, 1, 318, 19, 0), + (7580, 1, 318, 20, 0), + (7581, 1, 294, 0, 160), + (7582, 1, 294, 0, 165), + (7583, 1, 294, 0, 170), + (7584, 1, 114, -60, 0), + (7585, 1, 114, -61, 0), + (7586, 1, 114, -62, 0), + (7587, 1, 319, 22, 0), + (7588, 1, 319, 23, 0), + (7589, 1, 319, 24, 0), + (7590, 1, 274, 35, 0), + (7591, 1, 274, 36, 0), + (7592, 1, 274, 37, 0), + (7593, 1, 15, 14, 0), + (7594, 1, 15, 15, 0), + (7595, 1, 15, 16, 0), + (7596, 1, 15, 17, 0), + (7597, 1, 15, 18, 0), + (7598, 1, 114, -60, 0), + (7599, 1, 114, -61, 0), + (7600, 1, 114, -62, 0), + (7601, 1, 213, 7, 0), + (7602, 1, 213, 9, 0), + (7603, 1, 213, 11, 0), + (7604, 1, 189, 14, 0), + (7605, 1, 189, 15, 0), + (7612, 1, 270, 70, 0), + (7613, 1, 270, 75, 0), + (7614, 1, 270, 80, 0), + (7615, 1, 264, 720, 494), + (7616, 1, 264, 900, 494), + (7617, 1, 264, 1080, 494), + (7618, 1, 264, 720, 500), + (7619, 1, 264, 900, 500), + (7620, 1, 264, 1080, 500), + (7621, 1, 339, 10, 8105), + (7621, 2, 142, 65, 0), + (7621, 3, 311, 0, 0), + (7621, 4, 134, 70, 0), + (7621, 5, 348, 10, 0), + (7621, 6, 137, 0, 0), + (7621, 7, 339, 10, 8105), + (7621, 8, 142, 65, 0), + (7621, 9, 311, 0, 0), + (7621, 10, 134, 70, 0), + (7621, 11, 348, 10, 0), + (7621, 12, 137, 100, 0), + (7621, 13, 339, 10, 8105), + (7621, 14, 142, 65, 0), + (7621, 15, 311, 0, 0), + (7621, 16, 134, 70, 0), + (7621, 17, 348, 10, 0), + (7621, 18, 137, 79, 0), + (7621, 19, 339, 10, 8105), + (7621, 20, 142, 65, 0), + (7621, 21, 311, 0, 0), + (7621, 22, 134, 70, 0), + (7621, 23, 348, 10, 0), + (7621, 24, 137, 147, 0), + (7621, 25, 339, 10, 11404), + (7621, 26, 142, 71, 0), + (7621, 27, 311, 0, 0), + (7621, 28, 134, 75, 0), + (7621, 29, 348, 10, 0), + (7621, 30, 137, 0, 0), + (7621, 31, 339, 10, 11404), + (7621, 32, 142, 71, 0), + (7621, 33, 311, 0, 0), + (7621, 34, 134, 75, 0), + (7621, 35, 348, 10, 0), + (7621, 36, 137, 100, 0), + (7621, 37, 339, 10, 11404), + (7621, 38, 142, 71, 0), + (7621, 39, 311, 0, 0), + (7621, 40, 134, 75, 0), + (7621, 41, 348, 10, 0), + (7621, 42, 137, 79, 0), + (7621, 43, 339, 10, 11404), + (7621, 44, 142, 71, 0), + (7621, 45, 311, 0, 0), + (7621, 46, 134, 75, 0), + (7621, 47, 348, 10, 0), + (7621, 48, 137, 147, 0), + (7621, 49, 339, 10, 13199), + (7621, 50, 142, 76, 0), + (7621, 51, 311, 0, 0), + (7621, 52, 134, 80, 0), + (7621, 53, 348, 10, 0), + (7621, 54, 137, 0, 0), + (7621, 55, 339, 10, 13199), + (7621, 56, 142, 76, 0), + (7621, 57, 311, 0, 0), + (7621, 58, 134, 80, 0), + (7621, 59, 348, 10, 0), + (7621, 60, 137, 100, 0), + (7621, 61, 339, 10, 13199), + (7621, 62, 142, 76, 0), + (7621, 63, 311, 0, 0), + (7621, 64, 134, 80, 0), + (7621, 65, 348, 10, 0), + (7621, 66, 137, 79, 0), + (7621, 67, 339, 10, 13199), + (7621, 68, 142, 76, 0), + (7621, 69, 311, 0, 0), + (7621, 70, 134, 80, 0), + (7621, 71, 348, 10, 0), + (7621, 72, 137, 147, 0), + (7621, 73, 339, 10, 13830), + (7621, 74, 142, 81, 0), + (7621, 75, 311, 0, 0), + (7621, 76, 134, 85, 0), + (7621, 77, 348, 10, 0), + (7621, 78, 137, 0, 0), + (7621, 79, 339, 10, 13830), + (7621, 80, 142, 81, 0), + (7621, 81, 311, 0, 0), + (7621, 82, 134, 85, 0), + (7621, 83, 348, 10, 0), + (7621, 84, 137, 100, 0), + (7621, 85, 339, 10, 13830), + (7621, 86, 142, 81, 0), + (7621, 87, 311, 0, 0), + (7621, 88, 134, 85, 0), + (7621, 89, 348, 10, 0), + (7621, 90, 137, 79, 0), + (7621, 91, 339, 10, 13830), + (7621, 92, 142, 81, 0), + (7621, 93, 311, 0, 0), + (7621, 94, 134, 85, 0), + (7621, 95, 348, 10, 0), + (7621, 96, 137, 147, 0), + (7622, 1, 265, 79, 0), + (7623, 1, 265, 80, 0), + (7624, 1, 265, 81, 0), + (7625, 1, 265, 79, 0), + (7626, 1, 265, 80, 0), + (7627, 1, 265, 81, 0), + (7628, 1, 292, 46, 0), + (7629, 1, 292, 47, 0), + (7630, 1, 292, 48, 0), + (7631, 1, 279, 34, 0), + (7632, 1, 279, 35, 0), + (7633, 1, 279, 36, 0), + (7634, 1, 279, 34, 0), + (7635, 1, 279, 35, 0), + (7636, 1, 279, 36, 0), + (7637, 1, 279, 34, 0), + (7638, 1, 279, 35, 0), + (7639, 1, 279, 36, 0), + (7640, 1, 200, 60, 0), + (7641, 1, 294, 17, 100), + (7642, 1, 294, 19, 100), + (7643, 1, 294, 21, 100), + (7644, 1, 375, 130, 0), + (7645, 1, 375, 135, 0), + (7646, 1, 375, 140, 0), + (7647, 1, 229, 20, 0), + (7648, 1, 229, 25, 0), + (7649, 1, 229, 30, 0), + (7650, 1, 330, 125, 0), + (7650, 2, 330, 125, 1), + (7650, 3, 330, 125, 2), + (7650, 4, 330, 125, 3), + (7650, 5, 330, 125, 28), + (7650, 6, 330, 125, 36), + (7651, 1, 330, 130, 0), + (7651, 2, 330, 130, 1), + (7651, 3, 330, 130, 2), + (7651, 4, 330, 130, 3), + (7651, 5, 330, 130, 28), + (7651, 6, 330, 130, 36), + (7652, 1, 330, 135, 0), + (7652, 2, 330, 135, 1), + (7652, 3, 330, 135, 2), + (7652, 4, 330, 135, 3), + (7652, 5, 330, 135, 28), + (7652, 6, 330, 135, 36), + (7653, 1, 330, 125, 0), + (7653, 2, 330, 125, 1), + (7653, 3, 330, 125, 2), + (7653, 4, 330, 125, 3), + (7653, 5, 330, 125, 28), + (7653, 6, 330, 125, 36), + (7653, 7, 330, 125, 77), + (7654, 1, 330, 130, 0), + (7654, 2, 330, 130, 1), + (7654, 3, 330, 130, 2), + (7654, 4, 330, 130, 3), + (7654, 5, 330, 130, 28), + (7654, 6, 330, 130, 36), + (7654, 7, 330, 130, 77), + (7655, 1, 330, 135, 0), + (7655, 2, 330, 135, 1), + (7655, 3, 330, 135, 2), + (7655, 4, 330, 135, 3), + (7655, 5, 330, 135, 28), + (7655, 6, 330, 135, 36), + (7655, 7, 330, 135, 77), + (7656, 1, 330, 100, 0), + (7656, 2, 330, 100, 1), + (7656, 3, 330, 100, 2), + (7656, 4, 330, 100, 3), + (7656, 5, 330, 100, 28), + (7656, 6, 330, 100, 36), + (7656, 7, 330, 100, 77), + (7657, 1, 330, 105, 0), + (7657, 2, 330, 105, 1), + (7657, 3, 330, 105, 2), + (7657, 4, 330, 105, 3), + (7657, 5, 330, 105, 28), + (7657, 6, 330, 105, 36), + (7657, 7, 330, 105, 77), + (7658, 1, 330, 110, 0), + (7658, 2, 330, 110, 1), + (7658, 3, 330, 110, 2), + (7658, 4, 330, 110, 3), + (7658, 5, 330, 110, 28), + (7658, 6, 330, 110, 36), + (7658, 7, 330, 110, 77), + (7659, 1, 264, 72, 153), + (7660, 1, 264, 90, 153), + (7661, 1, 264, 108, 153), + (7663, 1, 375, 150, 0), + (7664, 1, 264, 10, 170), + (7665, 1, 264, 20, 170), + (7666, 1, 264, 30, 170), + (7667, 1, 264, 40, 170), + (7668, 1, 264, 50, 170), + (7670, 1, 229, 35, 0), + (7671, 1, 229, 40, 0), + (7672, 1, 229, 45, 0), + (7673, 1, 220, 50, 10), + (7674, 1, 220, 65, 10), + (7675, 1, 220, 80, 10), + (7676, 1, 220, 95, 10), + (7677, 1, 220, 110, 10), + (7678, 1, 231, 11, 0), + (7679, 1, 231, 13, 0), + (7680, 1, 231, 15, 0), + (7681, 1, 326, 4, 0), + (7682, 1, 264, 5400, 68), + (7683, 1, 327, 10, 0), + (7684, 1, 327, 11, 0), + (7685, 1, 327, 12, 0), + (7686, 1, 349, 55, 0), + (7687, 1, 349, 60, 0), + (7688, 1, 349, 65, 0), + (7690, 1, 353, 1, 0), + (7692, 1, 319, 25, 0), + (7693, 1, 319, 26, 0), + (7694, 1, 319, 27, 0), + (7695, 1, 127, 5, 0), + (7695, 2, 385, 14232, 0), + (7696, 1, 127, 10, 0), + (7696, 2, 385, 14232, 0), + (7697, 1, 127, 15, 0), + (7697, 2, 385, 14232, 0), + (7699, 1, 181, 100, 0), + (7700, 1, 279, 7, 0), + (7701, 1, 279, 11, 0), + (7702, 1, 279, 15, 0), + (7704, 1, 264, 540, 3707), + (7705, 1, 264, 720, 3707), + (7706, 1, 264, 900, 3707), + (7707, 1, 303, 8500, 9500), + (7707, 2, 139, 2766, 0), + (7708, 1, 303, 9500, 11000), + (7708, 2, 139, 2766, 0), + (7709, 1, 303, 11000, 14000), + (7709, 2, 139, 2766, 0), + (7713, 1, 274, 34, 0), + (7714, 1, 274, 36, 0), + (7715, 1, 264, 2, 901), + (7716, 1, 264, 4, 901), + (7717, 1, 264, 6, 901), + (7718, 1, 281, 90, 0), + (7722, 1, 339, 25, 23492), + (7722, 2, 138, 1, 0), + (7722, 3, 141, 1, 0), + (7722, 4, 142, 70, 0), + (7722, 5, 137, 0, 0), + (7722, 6, 311, 0, 0), + (7722, 7, 134, 90, 0), + (7722, 8, 139, -265, 0), + (7722, 9, 139, -754, 0), + (7722, 10, 139, -1332, 0), + (7722, 11, 139, -1572, 0), + (7722, 12, 139, -2749, 0), + (7722, 13, 139, -4979, 0), + (7722, 14, 139, -5418, 0), + (7722, 15, 139, -5403, 0), + (7722, 16, 348, 10, 0), + (7723, 1, 339, 26, 23493), + (7723, 2, 138, 1, 0), + (7723, 3, 141, 1, 0), + (7723, 4, 142, 70, 0), + (7723, 5, 137, 0, 0), + (7723, 6, 311, 0, 0), + (7723, 7, 134, 90, 0), + (7723, 8, 139, -265, 0), + (7723, 9, 139, -754, 0), + (7723, 10, 139, -1332, 0), + (7723, 11, 139, -1572, 0), + (7723, 12, 139, -2749, 0), + (7723, 13, 139, -4979, 0), + (7723, 14, 139, -5418, 0), + (7723, 15, 139, -5403, 0), + (7723, 16, 348, 10, 0), + (7724, 1, 339, 27, 23494), + (7724, 2, 138, 1, 0), + (7724, 3, 141, 1, 0), + (7724, 4, 142, 70, 0), + (7724, 5, 137, 0, 0), + (7724, 6, 311, 0, 0), + (7724, 7, 134, 90, 0), + (7724, 8, 139, -265, 0), + (7724, 9, 139, -754, 0), + (7724, 10, 139, -1332, 0), + (7724, 11, 139, -1572, 0), + (7724, 12, 139, -2749, 0), + (7724, 13, 139, -4979, 0), + (7724, 14, 139, -5418, 0), + (7724, 15, 139, -5403, 0), + (7724, 16, 348, 10, 0), + (7725, 1, 339, 28, 23495), + (7725, 2, 138, 1, 0), + (7725, 3, 141, 1, 0), + (7725, 4, 142, 70, 0), + (7725, 5, 137, 0, 0), + (7725, 6, 311, 0, 0), + (7725, 7, 134, 90, 0), + (7725, 8, 139, -265, 0), + (7725, 9, 139, -754, 0), + (7725, 10, 139, -1332, 0), + (7725, 11, 139, -1572, 0), + (7725, 12, 139, -2749, 0), + (7725, 13, 139, -4979, 0), + (7725, 14, 139, -5418, 0), + (7725, 15, 139, -5403, 0), + (7725, 16, 348, 10, 0), + (7726, 1, 339, 29, 23496), + (7726, 2, 138, 1, 0), + (7726, 3, 141, 1, 0), + (7726, 4, 142, 70, 0), + (7726, 5, 137, 0, 0), + (7726, 6, 311, 0, 0), + (7726, 7, 134, 90, 0), + (7726, 8, 139, -265, 0), + (7726, 9, 139, -754, 0), + (7726, 10, 139, -1332, 0), + (7726, 11, 139, -1572, 0), + (7726, 12, 139, -2749, 0), + (7726, 13, 139, -4979, 0), + (7726, 14, 139, -5418, 0), + (7726, 15, 139, -5403, 0), + (7726, 16, 348, 10, 0), + (7733, 1, 257, 1, 0), + (7733, 2, 267, 1, 31), + (7733, 3, 267, 1, 32), + (7733, 4, 267, 1, 33), + (7733, 5, 267, 1, 15), + (7733, 6, 267, 1, 16), + (7733, 7, 267, 1, 17), + (7733, 8, 267, 1, 18), + (7733, 9, 267, 1, 19), + (7733, 10, 267, 1, 20), + (7743, 1, 264, 90, 184), + (7744, 1, 264, 180, 184), + (7745, 1, 264, 270, 184), + (7746, 1, 310, 2000, 0), + (7746, 2, 385, 11233, 0), + (7746, 3, 385, 11333, 0), + (7746, 4, 411, 16, 0), + (7748, 1, 271, 5, 0), + (7749, 1, 271, 10, 0), + (7750, 1, 271, 15, 0), + (7751, 1, 264, 60, 2234), + (7752, 1, 264, 120, 2234), + (7753, 1, 264, 180, 2234), + (7757, 1, 264, 120, 9403), + (7758, 1, 264, 240, 9403), + (7759, 1, 264, 360, 9403), + (7760, 1, 264, 2, 824), + (7761, 1, 264, 4, 824), + (7762, 1, 264, 6, 824), + (7763, 1, 310, 4000, 0), + (7763, 2, 385, 11233, 0), + (7763, 3, 385, 11333, 0), + (7763, 4, 411, 16, 0), + (7764, 1, 310, 6000, 0), + (7764, 2, 385, 11233, 0), + (7764, 3, 385, 11333, 0), + (7764, 4, 411, 16, 0), + (7765, 1, 392, 1000, 0), + (7765, 2, 139, 21820, 0), + (7765, 3, 411, 4, 0), + (7766, 1, 392, 2000, 0), + (7766, 2, 139, 21820, 0), + (7766, 3, 411, 4, 0), + (7767, 1, 392, 3000, 0), + (7767, 2, 139, 21820, 0), + (7767, 3, 411, 4, 0), + (7768, 1, 392, 4000, 0), + (7768, 2, 139, 21820, 0), + (7768, 3, 411, 4, 0), + (7818, 1, 288, 200, 51), + (7818, 2, 288, 50, 51), + (7819, 1, 405, 7, 0), + (7820, 1, 405, 9, 0), + (7821, 1, 405, 11, 0), + (7822, 1, 264, 1, 1154), + (7823, 1, 264, 2, 1154), + (7824, 1, 264, 3, 1154), + (7825, 1, 264, 4, 1154), + (7826, 1, 264, 5, 1154), + (7827, 1, 398, 9000, 0), + (7827, 2, 385, 7225, 0), + (7827, 3, 385, 7325, 0), + (7827, 4, 385, 7425, 0), + (7828, 1, 310, 2000, 0), + (7828, 2, 385, 7225, 0), + (7828, 3, 385, 7325, 0), + (7828, 4, 385, 7425, 0), + (7828, 5, 385, 7525, 0), + (7828, 6, 385, 7625, 0), + (7829, 1, 310, 4000, 0), + (7829, 2, 385, 7225, 0), + (7829, 3, 385, 7325, 0), + (7829, 4, 385, 7425, 0), + (7829, 5, 385, 7525, 0), + (7829, 6, 385, 7625, 0), + (7830, 1, 310, 6000, 0), + (7830, 2, 385, 7225, 0), + (7830, 3, 385, 7325, 0), + (7830, 4, 385, 7425, 0), + (7830, 5, 385, 7525, 0), + (7830, 6, 385, 7625, 0), + (7832, 1, 264, 60, 60), + (7833, 2, 264, 120, 60), + (7834, 3, 264, 180, 60), + (7835, 4, 264, 240, 60), + (7836, 5, 264, 300, 60), + (7837, 1, 262, 55, 7), + (7837, 2, 262, 55, 8), + (7837, 3, 262, 55, 9), + (7837, 4, 262, 55, 10), + (7837, 5, 262, 55, 11), + (7838, 1, 262, 60, 7), + (7838, 2, 262, 60, 8), + (7838, 3, 262, 60, 9), + (7838, 4, 262, 60, 10), + (7838, 5, 262, 60, 11), + (7839, 1, 262, 65, 7), + (7839, 2, 262, 65, 8), + (7839, 3, 262, 65, 9), + (7839, 4, 262, 65, 10), + (7839, 5, 262, 65, 11), + (7840, 1, 262, 70, 7), + (7840, 2, 262, 70, 8), + (7840, 3, 262, 70, 9), + (7840, 4, 262, 70, 10), + (7840, 5, 262, 70, 11), + (7841, 1, 262, 75, 7), + (7841, 2, 262, 75, 8), + (7841, 3, 262, 75, 9), + (7841, 4, 262, 75, 10), + (7841, 5, 262, 75, 11), + (7842, 1, 339, 30, 27695), + (7842, 2, 138, 1, 0), + (7842, 3, 141, 1, 0), + (7842, 4, 142, 70, 0), + (7842, 5, 137, 0, 0), + (7842, 6, 311, 0, 0), + (7842, 7, 134, 100, 0), + (7842, 8, 139, -265, 0), + (7842, 9, 139, -754, 0), + (7842, 10, 139, -1332, 0), + (7842, 11, 139, -1572, 0), + (7842, 12, 139, -2749, 0), + (7842, 13, 139, -4979, 0), + (7842, 14, 139, -5418, 0), + (7842, 15, 139, -5403, 0), + (7842, 16, 348, 10, 0), + (7843, 1, 339, 31, 27696), + (7843, 2, 138, 1, 0), + (7843, 3, 141, 1, 0), + (7843, 4, 142, 70, 0), + (7843, 5, 137, 0, 0), + (7843, 6, 311, 0, 0), + (7843, 7, 134, 100, 0), + (7843, 8, 139, -265, 0), + (7843, 9, 139, -754, 0), + (7843, 10, 139, -1332, 0), + (7843, 11, 139, -1572, 0), + (7843, 12, 139, -2749, 0), + (7843, 13, 139, -4979, 0), + (7843, 14, 139, -5418, 0), + (7843, 15, 139, -5403, 0), + (7843, 16, 348, 10, 0), + (7844, 1, 339, 32, 27697), + (7844, 2, 138, 1, 0), + (7844, 3, 141, 1, 0), + (7844, 4, 142, 70, 0), + (7844, 5, 137, 0, 0), + (7844, 6, 311, 0, 0), + (7844, 7, 134, 100, 0), + (7844, 8, 139, -265, 0), + (7844, 9, 139, -754, 0), + (7844, 10, 139, -1332, 0), + (7844, 11, 139, -1572, 0), + (7844, 12, 139, -2749, 0), + (7844, 13, 139, -4979, 0), + (7844, 14, 139, -5418, 0), + (7844, 15, 139, -5403, 0), + (7844, 16, 348, 10, 0), + (7881, 1, 405, 13, 0), + (7882, 1, 405, 15, 0), + (7883, 1, 405, 17, 0), + (7884, 1, 287, 1, 0), + (7884, 2, 139, 4691, 0), + (7884, 3, 411, 128, 0), + (7885, 1, 287, 1, 0), + (7885, 2, 385, 8111, 0), + (7885, 3, 385, 15008, 0), + (7885, 4, 385, 8411, 0), + (7885, 5, 385, 8511, 0), + (7885, 6, 411, 128, 0), + (7886, 1, 328, 1300, 0), + (7887, 1, 328, 1350, 0), + (7888, 1, 328, 1400, 0), + (7889, 1, 328, 1450, 0), + (7890, 1, 328, 1500, 0), + (7900, 1, 339, 45, 16189), + (7900, 2, 136, 11, 0), + (7900, 3, 383, 45, 16189), + (7900, 4, 385, 11012, 0), + (7900, 5, 383, 45, 16189), + (7900, 6, 385, 5130, 0), + (7900, 7, 383, 45, 16189), + (7900, 8, 385, 5230, 0), + (7900, 9, 383, 45, 16189), + (7900, 10, 136, 22, 0), + (7900, 11, 383, 45, 16189), + (7900, 12, 385, 5330, 0), + (7900, 13, 385, 5430, 0), + (7900, 14, 385, 5530, 0), + (7901, 1, 339, 45, 16190), + (7901, 2, 136, 11, 0), + (7901, 3, 383, 45, 16190), + (7901, 4, 385, 11012, 0), + (7901, 5, 383, 45, 16190), + (7901, 6, 385, 5130, 0), + (7901, 7, 383, 45, 16190), + (7901, 8, 385, 5230, 0), + (7901, 9, 383, 45, 16190), + (7901, 10, 136, 22, 0), + (7901, 11, 383, 45, 16190), + (7901, 12, 385, 5330, 0), + (7901, 13, 385, 5430, 0), + (7901, 14, 385, 5530, 0), + (7902, 1, 339, 45, 16191), + (7902, 2, 136, 11, 0), + (7902, 3, 383, 45, 16191), + (7902, 4, 385, 11012, 0), + (7902, 5, 383, 45, 16191), + (7902, 6, 385, 5130, 0), + (7902, 7, 383, 45, 16191), + (7902, 8, 385, 5230, 0), + (7902, 9, 383, 45, 16191), + (7902, 10, 136, 22, 0), + (7902, 11, 383, 45, 16191), + (7902, 12, 385, 5330, 0), + (7902, 13, 385, 5430, 0), + (7902, 14, 385, 5530, 0), + (7904, 1, 0, 26, 0), + (7905, 1, 0, 27, 0), + (7906, 1, 0, 28, 0), + (7907, 1, 0, 29, 0), + (7908, 1, 0, 30, 0), + (7940, 1, 264, 15, 558), + (7941, 1, 264, 30, 558), + (7942, 1, 264, 45, 558), + (7945, 1, 310, 2000, 0), + (7945, 2, 139, 8007, 0), + (7945, 3, 310, 2000, 0), + (7945, 4, 385, 4140, 0), + (7945, 5, 385, 4240, 0), + (7945, 6, 385, 4340, 0), + (7945, 7, 385, 4440, 0), + (7945, 8, 385, 4540, 0), + (7945, 9, 385, 4640, 0), + (7946, 1, 310, 4000, 0), + (7946, 2, 139, 8007, 0), + (7946, 3, 310, 4000, 0), + (7946, 4, 385, 4140, 0), + (7946, 5, 385, 4240, 0), + (7946, 6, 385, 4340, 0), + (7946, 7, 385, 4440, 0), + (7946, 8, 385, 4540, 0), + (7946, 9, 385, 4640, 0), + (7947, 1, 310, 6000, 0), + (7947, 2, 139, 8007, 0), + (7947, 3, 310, 6000, 0), + (7947, 4, 385, 4140, 0), + (7947, 5, 385, 4240, 0), + (7947, 6, 385, 4340, 0), + (7947, 7, 385, 4440, 0), + (7947, 8, 385, 4540, 0), + (7947, 9, 385, 4640, 0), + (7948, 1, 339, 25, 16197), + (7948, 2, 138, 1, 0), + (7948, 3, 142, 60, 0), + (7948, 4, 137, 35, 0), + (7948, 5, 134, 75, 0), + (7948, 6, 339, 25, 16197), + (7948, 7, 138, 1, 0), + (7948, 8, 142, 60, 0), + (7948, 9, 137, 36, 0), + (7948, 10, 134, 75, 0), + (7948, 11, 339, 25, 16197), + (7948, 12, 138, 1, 0), + (7948, 13, 142, 60, 0), + (7948, 14, 137, 369, 0), + (7948, 15, 134, 75, 0), + (7948, 16, 339, 25, 16197), + (7948, 17, 138, 1, 0), + (7948, 18, 142, 60, 0), + (7948, 19, 137, 116, 0), + (7948, 20, 134, 75, 0), + (7949, 1, 339, 25, 16198), + (7949, 2, 138, 1, 0), + (7949, 3, 142, 60, 0), + (7949, 4, 137, 35, 0), + (7949, 5, 134, 80, 0), + (7949, 6, 339, 25, 16198), + (7949, 7, 138, 1, 0), + (7949, 8, 142, 60, 0), + (7949, 9, 137, 36, 0), + (7949, 10, 134, 80, 0), + (7949, 11, 339, 25, 16198), + (7949, 12, 138, 1, 0), + (7949, 13, 142, 60, 0), + (7949, 14, 137, 369, 0), + (7949, 15, 134, 80, 0), + (7949, 16, 339, 25, 16198), + (7949, 17, 138, 1, 0), + (7949, 18, 142, 60, 0), + (7949, 19, 137, 116, 0), + (7949, 20, 134, 80, 0), + (7950, 1, 339, 25, 16199), + (7950, 2, 138, 1, 0), + (7950, 3, 142, 60, 0), + (7950, 4, 137, 35, 0), + (7950, 5, 134, 85, 0), + (7950, 6, 339, 25, 16199), + (7950, 7, 138, 1, 0), + (7950, 8, 142, 60, 0), + (7950, 9, 137, 36, 0), + (7950, 10, 134, 85, 0), + (7950, 11, 339, 25, 16199), + (7950, 12, 138, 1, 0), + (7950, 13, 142, 60, 0), + (7950, 14, 137, 369, 0), + (7950, 15, 134, 85, 0), + (7950, 16, 339, 25, 16199), + (7950, 17, 138, 1, 0), + (7950, 18, 142, 60, 0), + (7950, 19, 137, 116, 0), + (7950, 20, 134, 85, 0), + (7980, 1, 243, 15, 0), + (7981, 1, 243, 25, 0), + (7982, 1, 243, 35, 0), + (7983, 1, 264, 120, 520), + (7984, 1, 264, 240, 520), + (7985, 1, 264, 360, 520), + (7989, 1, 264, 30, 705), + (7989, 2, 264, 30, 1092), + (7989, 3, 264, 30, 10396), + (7989, 4, 264, 30, 10397), + (7990, 1, 264, 60, 705), + (7990, 2, 264, 60, 1092), + (7990, 3, 264, 60, 10396), + (7990, 4, 264, 60, 10397), + (7991, 1, 264, 90, 705), + (7991, 2, 264, 90, 1092), + (7991, 3, 264, 90, 10396), + (7991, 4, 264, 90, 10397), + (7992, 1, 264, 120, 705), + (7992, 2, 264, 120, 1092), + (7992, 3, 264, 120, 10396), + (7992, 4, 264, 120, 10397), + (7994, 1, 264, 240, 39), + (7994, 2, 264, 3456, 1061), + (7995, 1, 264, 300, 39), + (7995, 2, 264, 4320, 1061), + (8000, 1, 69, 200, 0), + (8000, 2, 2, 75, 0), + (8000, 3, 97, 200, 0), + (8000, 4, 317, 8, 0), + (8031, 1, 264, 30, 791), + (8032, 1, 264, 60, 791), + (8033, 1, 264, 90, 791), + (8035, 1, 264, 180, 521), + (8036, 1, 264, 360, 521), + (8037, 1, 264, 540, 521), + (8040, 1, 128, 5, 5), + (8040, 2, 138, 1, 0), + (8040, 3, 140, 1, 0), + (8040, 4, 311, 0, 0), + (8040, 5, 411, 256, 0), + (8040, 6, 137, -40, 0), + (8040, 7, 391, 1, 0), + (8041, 1, 128, 15, 15), + (8041, 2, 138, 1, 0), + (8041, 3, 140, 1, 0), + (8041, 4, 311, 0, 0), + (8041, 5, 411, 256, 0), + (8041, 6, 137, -40, 0), + (8041, 7, 391, 1, 0), + (8042, 1, 128, 30, 30), + (8042, 2, 138, 1, 0), + (8042, 3, 140, 1, 0), + (8042, 4, 311, 0, 0), + (8042, 5, 411, 256, 0), + (8042, 6, 137, -40, 0), + (8042, 7, 391, 1, 0), + (8043, 1, 128, 50, 50), + (8043, 2, 138, 1, 0), + (8043, 3, 140, 1, 0), + (8043, 4, 311, 0, 0), + (8043, 5, 411, 256, 0), + (8043, 6, 137, -40, 0), + (8043, 7, 391, 1, 0), + (8059, 1, 128, 50, 50), + (8059, 2, 138, 1, 0), + (8059, 3, 140, 1, 0), + (8059, 4, 311, 0, 0), + (8059, 5, 411, 66434, 0), + (8059, 6, 137, -40, 0), + (8069, 1, 244, -10, 0), + (8070, 1, 244, -15, 0), + (8071, 1, 244, -20, 0), + (8076, 1, 264, 360, 565), + (8076, 2, 264, 360, 793), + (8076, 3, 264, 360, 794), + (8077, 1, 264, 720, 565), + (8077, 2, 264, 720, 793), + (8077, 3, 264, 720, 794), + (8078, 1, 264, 1080, 565), + (8078, 2, 264, 1080, 793), + (8078, 3, 264, 1080, 794), + (8079, 1, 264, 1440, 565), + (8079, 2, 264, 1440, 793), + (8079, 3, 264, 1440, 794), + (8080, 1, 264, 1800, 565), + (8080, 2, 264, 1800, 793), + (8080, 3, 264, 1800, 794), + (8081, 1, 264, 2160, 565), + (8081, 2, 264, 2160, 793), + (8081, 3, 264, 2160, 794), + (8082, 1, 264, 60, 208), + (8083, 1, 264, 120, 208), + (8084, 1, 264, 180, 208), + (8190, 1, 280, 2, 0), + (8191, 1, 280, 4, 0), + (8192, 1, 280, 6, 0), + (8193, 1, 339, 100, 16225), + (8193, 2, 139, 6838, 0), + (8195, 1, 264, 120, 3707), + (8196, 1, 264, 240, 3707), + (8197, 1, 264, 360, 3707), + (8198, 1, 294, 0, 110), + (8199, 1, 294, 0, 120), + (8200, 1, 294, 0, 130), + (8201, 1, 218, 1, 0), + (8202, 1, 218, 2, 0), + (8203, 1, 218, 3, 0), + (8204, 1, 127, 10, 0), + (8204, 2, 137, 154, 0), + (8204, 3, 403, 2, 0), + (8204, 4, 404, 10, 0), + (8205, 1, 127, 20, 0), + (8205, 2, 137, 154, 0), + (8205, 3, 403, 2, 0), + (8205, 4, 404, 10, 0), + (8206, 1, 127, 30, 0), + (8206, 2, 137, 154, 0), + (8206, 3, 403, 2, 0), + (8206, 4, 404, 10, 0), + (8207, 1, 127, 10, 0), + (8207, 2, 137, 154, 0), + (8207, 3, 403, 2, 0), + (8207, 4, 404, 10, 0), + (8208, 1, 127, 20, 0), + (8208, 2, 137, 154, 0), + (8208, 3, 403, 2, 0), + (8208, 4, 404, 10, 0), + (8209, 1, 127, 30, 0), + (8209, 2, 137, 154, 0), + (8209, 3, 403, 2, 0), + (8209, 4, 404, 10, 0), + (8210, 1, 97, 50, 0), + (8211, 1, 97, 100, 0), + (8212, 1, 97, 150, 0), + (8213, 1, 97, 200, 0), + (8214, 1, 97, 250, 0), + (8215, 1, 190, 50, 0), + (8216, 1, 190, 100, 0), + (8217, 1, 190, 150, 0), + (8218, 1, 190, 200, 0), + (8219, 1, 190, 250, 0), + (8223, 1, 128, 50, 50), + (8223, 2, 138, 1, 0), + (8223, 3, 140, 1, 0), + (8223, 4, 139, -2741, 0), + (8223, 5, 139, -16843, 0), + (8223, 6, 385, -16192, 0), + (8224, 1, 339, 10, 16230), + (8224, 2, 138, 1, 0), + (8224, 3, 141, 1, 0), + (8224, 4, 142, 60, 0), + (8224, 5, 137, 0, 0), + (8224, 6, 311, 0, 0), + (8224, 7, 134, 80, 0), + (8224, 8, 139, -265, 0), + (8224, 9, 139, -754, 0), + (8224, 10, 139, -1332, 0), + (8224, 11, 139, -1572, 0), + (8224, 12, 139, -2749, 0), + (8224, 13, 139, -4979, 0), + (8224, 14, 139, -5418, 0), + (8224, 15, 139, -5403, 0), + (8225, 1, 339, 10, 16231), + (8225, 2, 138, 1, 0), + (8225, 3, 141, 1, 0), + (8225, 4, 142, 65, 0), + (8225, 5, 137, 0, 0), + (8225, 6, 311, 0, 0), + (8225, 7, 134, 85, 0), + (8225, 8, 139, -265, 0), + (8225, 9, 139, -754, 0), + (8225, 10, 139, -1332, 0), + (8225, 11, 139, -1572, 0), + (8225, 12, 139, -2749, 0), + (8225, 13, 139, -4979, 0), + (8225, 14, 139, -5418, 0), + (8225, 15, 139, -5403, 0), + (8226, 1, 339, 10, 16232), + (8226, 2, 138, 1, 0), + (8226, 3, 141, 1, 0), + (8226, 4, 142, 70, 0), + (8226, 5, 137, 0, 0), + (8226, 6, 311, 0, 0), + (8226, 7, 134, 90, 0), + (8226, 8, 139, -265, 0), + (8226, 9, 139, -754, 0), + (8226, 10, 139, -1332, 0), + (8226, 11, 139, -1572, 0), + (8226, 12, 139, -2749, 0), + (8226, 13, 139, -4979, 0), + (8226, 14, 139, -5418, 0), + (8226, 15, 139, -5403, 0), + (8228, 1, 378, 5, 22), + (8229, 1, 378, 10, 22), + (8230, 1, 378, 15, 22), + (8232, 1, 128, 5, 5), + (8232, 2, 138, 1, 0), + (8232, 3, 140, 1, 0), + (8232, 4, 311, 0, 0), + (8232, 5, 411, 66434, 0), + (8232, 6, 137, -40, 0), + (8233, 1, 128, 15, 15), + (8233, 2, 138, 1, 0), + (8233, 3, 140, 1, 0), + (8233, 4, 311, 0, 0), + (8233, 5, 411, 66434, 0), + (8233, 6, 137, -40, 0), + (8234, 1, 128, 30, 30), + (8234, 2, 138, 1, 0), + (8234, 3, 140, 1, 0), + (8234, 4, 311, 0, 0), + (8234, 5, 411, 66434, 0), + (8234, 6, 137, -40, 0), + (8235, 1, 1, 29, 0), + (8236, 1, 1, 58, 0), + (8237, 1, 1, 87, 0), + (8238, 1, 1, 116, 0), + (8239, 1, 1, 145, 0), + (8240, 1, 1, 31, 0), + (8241, 1, 1, 62, 0), + (8242, 1, 1, 93, 0), + (8243, 1, 1, 124, 0), + (8244, 1, 1, 155, 0), + (8245, 1, 1, 33, 0), + (8246, 1, 1, 66, 0), + (8247, 1, 1, 99, 0), + (8248, 1, 1, 132, 0), + (8249, 1, 1, 165, 0), + (8250, 1, 1, 40, 0), + (8251, 1, 1, 80, 0), + (8252, 1, 1, 120, 0), + (8253, 1, 1, 160, 0), + (8254, 1, 1, 200, 0), + (8255, 1, 1, 50, 0), + (8256, 1, 1, 100, 0), + (8257, 1, 1, 150, 0), + (8258, 1, 1, 200, 0), + (8259, 1, 1, 250, 0), + (8261, 1, 128, 65, 65), + (8261, 2, 138, 1, 0), + (8261, 3, 140, 1, 0), + (8261, 4, 311, 0, 0), + (8261, 5, 411, 66434, 0), + (8261, 6, 137, -40, 0), + (8262, 1, 128, 70, 70), + (8262, 2, 138, 1, 0), + (8262, 3, 140, 1, 0), + (8262, 4, 139, -2741, 0), + (8262, 5, 139, -16843, 0), + (8262, 6, 385, -16192, 0), + (8263, 1, 262, 5, 0), + (8264, 1, 262, 10, 0), + (8265, 1, 262, 15, 0), + (8266, 1, 262, 20, 0), + (8267, 1, 262, 25, 0), + (8268, 1, 262, 5, 1), + (8269, 1, 262, 10, 1), + (8270, 1, 262, 15, 1), + (8271, 1, 262, 20, 1), + (8272, 1, 262, 25, 1), + (8273, 1, 262, 5, 2), + (8274, 1, 262, 10, 2), + (8275, 1, 262, 15, 2), + (8276, 1, 262, 20, 2), + (8277, 1, 262, 25, 2), + (8278, 1, 262, 5, 3), + (8279, 1, 262, 10, 3), + (8280, 1, 262, 15, 3), + (8281, 1, 262, 20, 3), + (8282, 1, 262, 25, 3), + (8283, 1, 262, 5, 4), + (8284, 1, 262, 10, 4), + (8285, 1, 262, 15, 4), + (8286, 1, 262, 20, 4), + (8287, 1, 262, 25, 4), + (8288, 1, 262, 5, 5), + (8289, 1, 262, 10, 5), + (8290, 1, 262, 15, 5), + (8291, 1, 262, 20, 5), + (8292, 1, 262, 25, 5), + (8293, 1, 262, 5, 6), + (8294, 1, 262, 10, 6), + (8295, 1, 262, 15, 6), + (8296, 1, 262, 20, 6), + (8297, 1, 262, 25, 6), + (8304, 1, 1, 174, 0), + (8305, 1, 1, 203, 0), + (8306, 1, 1, 232, 0), + (8307, 1, 1, 261, 0), + (8308, 1, 1, 290, 0), + (8313, 1, 128, 65, 65), + (8313, 2, 138, 1, 0), + (8313, 3, 140, 1, 0), + (8313, 4, 311, 0, 0), + (8313, 5, 411, 256, 0), + (8313, 6, 137, -40, 0), + (8313, 7, 391, 1, 0), + (8314, 1, 378, 2, 3), + (8315, 1, 378, 3, 3), + (8316, 1, 378, 4, 3), + (8317, 1, 264, 1, 8205), + (8318, 1, 264, 2, 8205), + (8319, 1, 264, 2, 199), + (8320, 1, 264, 4, 199), + (8321, 1, 264, 6, 199), + (8322, 1, 378, 15, 31), + (8323, 1, 378, 20, 31), + (8324, 1, 378, 25, 31), + (8325, 1, 114, -3, 0), + (8326, 1, 114, -6, 0), + (8327, 1, 114, -9, 0), + (8328, 1, 268, 75, 56), + (8328, 2, 234, 1000, 0), + (8329, 1, 227, 4, 29), + (8329, 2, 227, 4, 42), + (8331, 1, 413, 10, 0), + (8331, 2, 139, 8001, 0), + (8331, 3, 385, 12529, 0), + (8331, 4, 411, 512, 0), + (8332, 1, 287, 1, 0), + (8332, 2, 385, 116121, 0), + (8333, 1, 287, 2, 0), + (8333, 2, 385, 116121, 0), + (8334, 1, 287, 3, 0), + (8334, 2, 385, 116121, 0), + (8335, 1, 127, 10, 0), + (8335, 2, 385, 16188, 0), + (8336, 1, 127, 20, 0), + (8336, 2, 385, 16188, 0), + (8337, 1, 127, 30, 0), + (8337, 2, 385, 16188, 0), + (8338, 1, 127, 40, 0), + (8338, 2, 385, 16188, 0), + (8339, 1, 127, 50, 0), + (8339, 2, 385, 16188, 0), + (8344, 1, 294, 0, 175), + (8345, 1, 294, 0, 180), + (8346, 1, 294, 0, 185), + (8347, 1, 264, 600, 616), + (8348, 1, 264, 1200, 616), + (8349, 1, 264, 1800, 616), + (8350, 1, 310, 1200, 0), + (8350, 2, 385, 6212, 0), + (8350, 3, 310, 600, 0), + (8350, 4, 385, 6215, 0), + (8350, 5, 310, 150, 0), + (8350, 6, 385, 6218, 0), + (8350, 7, 310, 9000, 0), + (8350, 8, 385, 6232, 0), + (8350, 9, 310, 600, 0), + (8350, 10, 385, 6243, 0), + (8350, 11, 310, 150, 0), + (8350, 12, 385, 6245, 0), + (8350, 13, 310, 1200, 0), + (8350, 14, 385, 6412, 0), + (8350, 15, 310, 600, 0), + (8350, 16, 385, 6415, 0), + (8350, 17, 310, 150, 0), + (8350, 18, 385, 6418, 0), + (8350, 19, 310, 9000, 0), + (8350, 20, 385, 6432, 0), + (8350, 21, 310, 600, 0), + (8350, 22, 385, 6443, 0), + (8350, 23, 310, 150, 0), + (8350, 24, 385, 6445, 0), + (8351, 1, 262, 30, 0), + (8352, 1, 262, 35, 0), + (8353, 1, 262, 40, 0), + (8354, 1, 262, 45, 0), + (8355, 1, 262, 50, 0), + (8356, 1, 262, 55, 0), + (8357, 1, 262, 60, 0), + (8358, 1, 262, 65, 0), + (8359, 1, 262, 70, 0), + (8360, 1, 262, 75, 0), + (8361, 1, 262, 30, 1), + (8362, 1, 262, 35, 1), + (8363, 1, 262, 40, 1), + (8364, 1, 262, 45, 1), + (8365, 1, 262, 50, 1), + (8366, 1, 262, 55, 1), + (8367, 1, 262, 60, 1), + (8368, 1, 262, 65, 1), + (8369, 1, 262, 70, 1), + (8370, 1, 262, 75, 1), + (8371, 1, 262, 30, 2), + (8372, 1, 262, 35, 2), + (8373, 1, 262, 40, 2), + (8374, 1, 262, 45, 2), + (8375, 1, 262, 50, 2), + (8376, 1, 262, 55, 2), + (8377, 1, 262, 60, 2), + (8378, 1, 262, 65, 2), + (8379, 1, 262, 70, 2), + (8380, 1, 262, 75, 2), + (8381, 1, 262, 30, 3), + (8382, 1, 262, 35, 3), + (8383, 1, 262, 40, 3), + (8384, 1, 262, 45, 3), + (8385, 1, 262, 50, 3), + (8386, 1, 262, 55, 3), + (8387, 1, 262, 60, 3), + (8388, 1, 262, 65, 3), + (8389, 1, 262, 70, 3), + (8390, 1, 262, 75, 3), + (8391, 1, 262, 30, 4), + (8392, 1, 262, 35, 4), + (8393, 1, 262, 40, 4), + (8394, 1, 262, 45, 4), + (8395, 1, 262, 50, 4), + (8396, 1, 262, 55, 4), + (8397, 1, 262, 60, 4), + (8398, 1, 262, 65, 4), + (8399, 1, 262, 70, 4), + (8400, 1, 262, 75, 4), + (8401, 1, 262, 30, 5), + (8402, 1, 262, 35, 5), + (8403, 1, 262, 40, 5), + (8404, 1, 262, 45, 5), + (8405, 1, 262, 50, 5), + (8406, 1, 262, 55, 5), + (8407, 1, 262, 60, 5), + (8408, 1, 262, 65, 5), + (8409, 1, 262, 70, 5), + (8410, 1, 262, 75, 5), + (8411, 1, 262, 30, 6), + (8412, 1, 262, 35, 6), + (8413, 1, 262, 40, 6), + (8414, 1, 262, 45, 6), + (8415, 1, 262, 50, 6), + (8416, 1, 262, 55, 6), + (8417, 1, 262, 60, 6), + (8418, 1, 262, 65, 6), + (8419, 1, 262, 70, 6), + (8420, 1, 262, 75, 6), + (8421, 1, 339, 10, 27535), + (8421, 2, 138, 1, 0), + (8421, 3, 141, 1, 0), + (8421, 4, 142, 75, 0), + (8421, 5, 137, 0, 0), + (8421, 6, 311, 0, 0), + (8421, 7, 134, 95, 0), + (8421, 8, 139, -265, 0), + (8421, 9, 139, -754, 0), + (8421, 10, 139, -1332, 0), + (8421, 11, 139, -1572, 0), + (8421, 12, 139, -2749, 0), + (8421, 13, 139, -4979, 0), + (8421, 14, 139, -5418, 0), + (8421, 15, 139, -5403, 0), + (8422, 1, 1, 198, 0), + (8423, 1, 1, 231, 0), + (8424, 1, 1, 264, 0), + (8425, 1, 1, 297, 0), + (8426, 1, 1, 330, 0), + (8427, 1, 264, 1260, 254), + (8428, 1, 264, 1440, 254), + (8429, 1, 264, 1620, 254), + (8430, 1, 328, 1600, 0), + (8435, 1, 0, 35, 0), + (8440, 1, 259, 66, 0), + (8445, 1, 426, 3, 0), + (8446, 1, 426, 4, 0), + (8447, 1, 426, 5, 0), + (8448, 1, 69, 2200, 0), + (8463, 1, 172, 60, 0), + (8464, 1, 172, 61, 0), + (8470, 1, 262, 80, 7), + (8470, 2, 262, 80, 8), + (8470, 3, 262, 80, 9), + (8470, 4, 262, 80, 10), + (8470, 5, 262, 80, 11), + (9001, 1, 247, 10, 58), + (9002, 1, 247, 20, 58), + (9003, 1, 247, 30, 58), + (9004, 1, 247, 40, 58), + (9005, 1, 247, 50, 58), + (9006, 1, 247, 60, 58), + (9007, 1, 247, 70, 58), + (9008, 1, 247, 80, 58), + (9009, 1, 247, 90, 58), + (9010, 1, 247, 100, 58), + (9011, 1, 247, 10, 58), + (9012, 1, 247, 20, 58), + (9013, 1, 247, 30, 58), + (9014, 1, 247, 40, 58), + (9015, 1, 247, 50, 58), + (9016, 1, 247, 60, 58), + (9017, 1, 247, 70, 58), + (9018, 1, 247, 80, 58), + (9019, 1, 247, 90, 58), + (9020, 1, 247, 100, 58), + (9021, 1, 247, 10, 58), + (9022, 1, 247, 20, 58), + (9023, 1, 247, 30, 58), + (9024, 1, 247, 40, 58), + (9025, 1, 247, 50, 58), + (9026, 1, 247, 60, 58), + (9027, 1, 247, 70, 58), + (9028, 1, 247, 80, 58), + (9029, 1, 247, 90, 58), + (9030, 1, 247, 100, 58), + (9033, 1, 264, 18000, 481), + (9033, 2, 264, 18000, 482), + (9033, 3, 264, 18000, 483), + (9033, 4, 264, 147600, 484), + (9033, 5, 264, 18000, 485), + (9033, 6, 264, 61200, 486), + (9033, 7, 264, 3600, 487), + (9033, 8, 264, 1080, 511), + (9033, 9, 264, 18000, 182), + (9033, 10, 264, 18000, 8081), + (9033, 11, 264, 18000, 8130), + (9033, 12, 264, 18000, 453), + (9033, 13, 264, 18000, 2000), + (9100, 1, 97, 10, 0), + (9100, 2, 262, 1, 5), + (9101, 1, 97, 20, 0), + (9101, 2, 262, 2, 5), + (9102, 1, 97, 30, 0), + (9102, 2, 262, 3, 5), + (9103, 1, 97, 40, 0), + (9103, 2, 262, 4, 5), + (9104, 1, 97, 50, 0), + (9104, 2, 262, 5, 5), + (9105, 1, 97, 60, 0), + (9105, 2, 262, 6, 5), + (9106, 1, 97, 70, 0), + (9106, 2, 262, 7, 5), + (9107, 1, 97, 80, 0), + (9107, 2, 262, 8, 5), + (9108, 1, 97, 90, 0), + (9108, 2, 262, 9, 5), + (9109, 1, 69, 10, 0), + (9109, 2, 262, 1, 1), + (9110, 1, 69, 20, 0), + (9110, 2, 262, 2, 1), + (9111, 1, 69, 30, 0), + (9111, 2, 262, 3, 1), + (9112, 1, 69, 40, 0), + (9112, 2, 262, 4, 1), + (9113, 1, 69, 50, 0), + (9113, 2, 262, 5, 1), + (9114, 1, 69, 60, 0), + (9114, 2, 262, 6, 1), + (9115, 1, 69, 70, 0), + (9115, 2, 262, 7, 1), + (9116, 1, 69, 80, 0), + (9116, 2, 262, 8, 1), + (9117, 1, 69, 90, 0), + (9117, 2, 262, 9, 1), + (9118, 1, 97, 10, 0), + (9118, 2, 262, 1, 5), + (9119, 1, 97, 20, 0), + (9119, 2, 262, 2, 5), + (9120, 1, 97, 30, 0), + (9120, 2, 262, 3, 5), + (9121, 1, 97, 40, 0), + (9121, 2, 262, 4, 5), + (9122, 1, 97, 50, 0), + (9122, 2, 262, 5, 5), + (9123, 1, 97, 60, 0), + (9123, 2, 262, 6, 5), + (9124, 1, 97, 70, 0), + (9124, 2, 262, 7, 5), + (9125, 1, 97, 80, 0), + (9125, 2, 262, 8, 5), + (9126, 1, 97, 90, 0), + (9126, 2, 262, 9, 5), + (9127, 1, 69, 10, 0), + (9127, 2, 262, 1, 5), + (9128, 1, 69, 20, 0), + (9128, 2, 262, 2, 5), + (9129, 1, 69, 30, 0), + (9129, 2, 262, 3, 5), + (9130, 1, 69, 40, 0), + (9130, 2, 262, 4, 5), + (9131, 1, 69, 50, 0), + (9131, 2, 262, 5, 5), + (9132, 1, 69, 60, 0), + (9132, 2, 262, 6, 5), + (9133, 1, 69, 70, 0), + (9133, 2, 262, 7, 5), + (9134, 1, 69, 80, 0), + (9134, 2, 262, 8, 5), + (9135, 1, 69, 90, 0), + (9135, 2, 262, 9, 5), + (9136, 1, 97, 10, 0), + (9136, 2, 262, 1, 4), + (9137, 1, 97, 20, 0), + (9137, 2, 262, 2, 4), + (9138, 1, 97, 30, 0), + (9138, 2, 262, 3, 4), + (9139, 1, 97, 40, 0), + (9139, 2, 262, 4, 4), + (9140, 1, 97, 50, 0), + (9140, 2, 262, 5, 4), + (9141, 1, 97, 60, 0), + (9141, 2, 262, 6, 4), + (9142, 1, 97, 70, 0), + (9142, 2, 262, 7, 4), + (9143, 1, 97, 80, 0), + (9143, 2, 262, 8, 4), + (9144, 1, 97, 90, 0), + (9144, 2, 262, 9, 4), + (9145, 1, 97, 10, 0), + (9145, 2, 262, 1, 4), + (9146, 1, 97, 20, 0), + (9146, 2, 262, 2, 4), + (9147, 1, 97, 30, 0), + (9147, 2, 262, 3, 4), + (9148, 1, 97, 40, 0), + (9148, 2, 262, 4, 4), + (9149, 1, 97, 50, 0), + (9149, 2, 262, 5, 4), + (9150, 1, 97, 60, 0), + (9150, 2, 262, 6, 4), + (9151, 1, 97, 70, 0), + (9151, 2, 262, 7, 4), + (9152, 1, 97, 80, 0), + (9152, 2, 262, 8, 4), + (9153, 1, 97, 90, 0), + (9153, 2, 262, 9, 4), + (9154, 1, 69, 10, 0), + (9154, 2, 262, 1, 1), + (9155, 1, 69, 20, 0), + (9155, 2, 262, 2, 1), + (9156, 1, 69, 30, 0), + (9156, 2, 262, 3, 1), + (9157, 1, 69, 40, 0), + (9157, 2, 262, 4, 1), + (9158, 1, 69, 50, 0), + (9158, 2, 262, 5, 1), + (9159, 1, 69, 60, 0), + (9159, 2, 262, 6, 1), + (9160, 1, 69, 70, 0), + (9160, 2, 262, 7, 1), + (9161, 1, 69, 80, 0), + (9161, 2, 262, 8, 1), + (9162, 1, 69, 90, 0), + (9162, 2, 262, 9, 1), + (9163, 1, 69, 10, 0), + (9163, 2, 262, 1, 3), + (9164, 1, 69, 20, 0), + (9164, 2, 262, 2, 3), + (9165, 1, 69, 30, 0), + (9165, 2, 262, 3, 3), + (9166, 1, 69, 40, 0), + (9166, 2, 262, 4, 3), + (9167, 1, 69, 50, 0), + (9167, 2, 262, 5, 3), + (9168, 1, 69, 60, 0), + (9168, 2, 262, 6, 3), + (9169, 1, 69, 70, 0), + (9169, 2, 262, 7, 3), + (9170, 1, 69, 80, 0), + (9170, 2, 262, 8, 3), + (9171, 1, 69, 90, 0), + (9171, 2, 262, 9, 3), + (9172, 1, 69, 10, 0), + (9172, 2, 262, 1, 0), + (9173, 1, 69, 20, 0), + (9173, 2, 262, 2, 0), + (9174, 1, 69, 30, 0), + (9174, 2, 262, 3, 0), + (9175, 1, 69, 40, 0), + (9175, 2, 262, 4, 0), + (9176, 1, 69, 50, 0), + (9176, 2, 262, 5, 0), + (9177, 1, 69, 60, 0), + (9177, 2, 262, 6, 0), + (9178, 1, 69, 70, 0), + (9178, 2, 262, 7, 0), + (9179, 1, 69, 80, 0), + (9179, 2, 262, 8, 0), + (9180, 1, 69, 90, 0), + (9180, 2, 262, 9, 0), + (9181, 1, 69, 10, 0), + (9181, 2, 262, 1, 0), + (9182, 1, 69, 20, 0), + (9182, 2, 262, 2, 0), + (9183, 1, 69, 30, 0), + (9183, 2, 262, 3, 0), + (9184, 1, 69, 40, 0), + (9184, 2, 262, 4, 0), + (9185, 1, 69, 50, 0), + (9185, 2, 262, 5, 0), + (9186, 1, 69, 60, 0), + (9186, 2, 262, 6, 0), + (9187, 1, 69, 70, 0), + (9187, 2, 262, 7, 0), + (9188, 1, 69, 80, 0), + (9188, 2, 262, 8, 0), + (9189, 1, 69, 90, 0), + (9189, 2, 262, 9, 0), + (9190, 1, 69, 10, 0), + (9190, 2, 262, 1, 0), + (9191, 1, 69, 20, 0), + (9191, 2, 262, 2, 0), + (9192, 1, 69, 30, 0), + (9192, 2, 262, 3, 0), + (9193, 1, 69, 40, 0), + (9193, 2, 262, 4, 0), + (9194, 1, 69, 50, 0), + (9194, 2, 262, 5, 0), + (9195, 1, 69, 60, 0), + (9195, 2, 262, 6, 0), + (9196, 1, 69, 70, 0), + (9196, 2, 262, 7, 0), + (9197, 1, 69, 80, 0), + (9197, 2, 262, 8, 0), + (9198, 1, 69, 90, 0), + (9198, 2, 262, 9, 0), + (9199, 1, 97, 10, 0), + (9199, 2, 262, 1, 0), + (9200, 1, 97, 20, 0), + (9200, 2, 262, 2, 0), + (9201, 1, 97, 30, 0), + (9201, 2, 262, 3, 0), + (9202, 1, 97, 40, 0), + (9202, 2, 262, 4, 0), + (9203, 1, 97, 50, 0), + (9203, 2, 262, 5, 0), + (9204, 1, 97, 60, 0), + (9204, 2, 262, 6, 0), + (9205, 1, 97, 70, 0), + (9205, 2, 262, 7, 0), + (9206, 1, 97, 80, 0), + (9206, 2, 262, 8, 0), + (9207, 1, 97, 90, 0), + (9207, 2, 262, 9, 0), + (9208, 1, 69, 10, 0), + (9208, 2, 262, 1, 0), + (9209, 1, 69, 20, 0), + (9209, 2, 262, 2, 0), + (9210, 1, 69, 30, 0), + (9210, 2, 262, 3, 0), + (9211, 1, 69, 40, 0), + (9211, 2, 262, 4, 0), + (9212, 1, 69, 50, 0), + (9212, 2, 262, 5, 0), + (9213, 1, 69, 60, 0), + (9213, 2, 262, 6, 0), + (9214, 1, 69, 70, 0), + (9214, 2, 262, 7, 0), + (9215, 1, 69, 80, 0), + (9215, 2, 262, 8, 0), + (9216, 1, 69, 90, 0), + (9216, 2, 262, 9, 0), + (9217, 1, 190, 10, 0), + (9217, 2, 262, 1, 0), + (9218, 1, 190, 20, 0), + (9218, 2, 262, 2, 0), + (9219, 1, 190, 30, 0), + (9219, 2, 262, 3, 0), + (9220, 1, 190, 40, 0), + (9220, 2, 262, 4, 0), + (9221, 1, 190, 50, 0), + (9221, 2, 262, 5, 0), + (9222, 1, 190, 60, 0), + (9222, 2, 262, 6, 0), + (9223, 1, 190, 70, 0), + (9223, 2, 262, 7, 0), + (9224, 1, 190, 80, 0), + (9224, 2, 262, 8, 0), + (9225, 1, 190, 90, 0), + (9225, 2, 262, 9, 0), + (9226, 1, 69, 10, 0), + (9226, 2, 262, 1, 0), + (9227, 1, 69, 20, 0), + (9227, 2, 262, 2, 0), + (9228, 1, 69, 30, 0), + (9228, 2, 262, 3, 0), + (9229, 1, 69, 40, 0), + (9229, 2, 262, 4, 0), + (9230, 1, 69, 50, 0), + (9230, 2, 262, 5, 0), + (9231, 1, 69, 60, 0), + (9231, 2, 262, 6, 0), + (9232, 1, 69, 70, 0), + (9232, 2, 262, 7, 0), + (9233, 1, 69, 80, 0), + (9233, 2, 262, 8, 0), + (9234, 1, 69, 90, 0), + (9234, 2, 262, 9, 0), + (9235, 1, 190, 10, 0), + (9235, 2, 262, 1, 0), + (9236, 1, 190, 20, 0), + (9236, 2, 262, 2, 0), + (9237, 1, 190, 30, 0), + (9237, 2, 262, 3, 0), + (9238, 1, 190, 40, 0), + (9238, 2, 262, 4, 0), + (9239, 1, 190, 50, 0), + (9239, 2, 262, 5, 0), + (9240, 1, 190, 60, 0), + (9240, 2, 262, 6, 0), + (9241, 1, 190, 70, 0), + (9241, 2, 262, 7, 0), + (9242, 1, 190, 80, 0), + (9242, 2, 262, 8, 0), + (9243, 1, 190, 90, 0), + (9243, 2, 262, 9, 0), + (9503, 1, 397, 100, 0), + (9504, 1, 397, 200, 0), + (9505, 1, 397, 300, 0), + (9506, 1, 398, 1000, 0), + (9506, 2, 137, 152, 0), + (9507, 1, 398, 2000, 0), + (9507, 2, 137, 152, 0), + (9508, 1, 398, 3000, 0), + (9508, 2, 137, 152, 0), + (9509, 1, 399, 1, 0), + (9509, 2, 141, 1, 0), + (9509, 3, 138, 0, 0), + (9509, 4, 134, 254, 0), + (9509, 5, 348, 10, 0), + (9509, 6, 137, 0, 0), + (9509, 7, 311, 0, 0), + (9509, 8, 137, -152, 0), + (9509, 9, 137, -39, 0), + (9510, 1, 399, 2, 0), + (9510, 2, 141, 1, 0), + (9510, 3, 138, 0, 0), + (9510, 4, 134, 254, 0), + (9510, 5, 348, 10, 0), + (9510, 6, 137, 0, 0), + (9510, 7, 311, 0, 0), + (9510, 8, 137, -152, 0), + (9510, 9, 137, -39, 0), + (9511, 1, 399, 3, 0), + (9511, 2, 141, 1, 0), + (9511, 3, 138, 0, 0), + (9511, 4, 134, 254, 0), + (9511, 5, 348, 10, 0), + (9511, 6, 137, 0, 0), + (9511, 7, 311, 0, 0), + (9511, 8, 137, -152, 0), + (9511, 9, 137, -39, 0), + (9512, 1, 405, 1, 0), + (9513, 1, 405, 3, 0), + (9514, 1, 405, 5, 0), + (9515, 1, 399, 4, 0), + (9515, 2, 141, 1, 0), + (9515, 3, 138, 0, 0), + (9515, 4, 134, 254, 0), + (9515, 5, 348, 10, 0), + (9515, 6, 137, 0, 0), + (9515, 7, 311, 0, 0), + (9515, 8, 137, -152, 0), + (9515, 9, 137, -39, 0), + (10004, 1, 310, 480000, 0), + (10004, 2, 139, 4674, 0), + (10005, 1, 310, 600000, 0), + (10005, 2, 139, 4674, 0), + (10007, 1, 85, 16500, 50), + (10008, 1, 85, 16501, 50), + (10009, 1, 85, 16502, 50), + (10025, 1, 339, 25, 16517), + (10025, 2, 137, 21, 0), + (10026, 1, 339, 25, 16518), + (10026, 2, 137, 21, 0), + (10027, 1, 339, 25, 16519), + (10027, 2, 137, 21, 0), + (10028, 1, 339, 25, 16520), + (10028, 2, 137, 21, 0), + (10029, 1, 339, 25, 16555), + (10029, 2, 137, 21, 0), + (10030, 1, 264, 60, 558), + (10031, 1, 264, 75, 558), + (10032, 1, 264, 90, 558), + (10033, 1, 310, 8000, 0), + (10033, 2, 139, 8007, 0), + (10033, 3, 310, 8000, 0), + (10033, 4, 385, 4140, 0), + (10033, 5, 385, 4240, 0), + (10033, 6, 385, 4340, 0), + (10033, 7, 385, 4440, 0), + (10033, 8, 385, 4540, 0), + (10033, 9, 385, 4640, 0), + (10034, 1, 310, 10000, 0), + (10034, 2, 139, 8007, 0), + (10034, 3, 310, 10000, 0), + (10034, 4, 385, 4140, 0), + (10034, 5, 385, 4240, 0), + (10034, 6, 385, 4340, 0), + (10034, 7, 385, 4440, 0), + (10034, 8, 385, 4540, 0), + (10034, 9, 385, 4640, 0), + (10035, 1, 339, 25, 16556), + (10035, 2, 138, 1, 0), + (10035, 3, 142, 60, 0), + (10035, 4, 137, 35, 0), + (10035, 5, 134, 85, 0), + (10035, 6, 339, 25, 16556), + (10035, 7, 138, 1, 0), + (10035, 8, 142, 60, 0), + (10035, 9, 137, 36, 0), + (10035, 10, 134, 85, 0), + (10035, 11, 339, 25, 16556), + (10035, 12, 138, 1, 0), + (10035, 13, 142, 60, 0), + (10035, 14, 137, 369, 0), + (10035, 15, 134, 85, 0), + (10035, 16, 339, 25, 16556), + (10035, 17, 138, 1, 0), + (10035, 18, 142, 60, 0), + (10035, 19, 137, 116, 0), + (10035, 20, 134, 85, 0), + (10036, 1, 339, 25, 16557), + (10036, 2, 138, 1, 0), + (10036, 3, 142, 60, 0), + (10036, 4, 137, 35, 0), + (10036, 5, 134, 85, 0), + (10036, 6, 339, 25, 16557), + (10036, 7, 138, 1, 0), + (10036, 8, 142, 60, 0), + (10036, 9, 137, 36, 0), + (10036, 10, 134, 85, 0), + (10036, 11, 339, 25, 16557), + (10036, 12, 138, 1, 0), + (10036, 13, 142, 60, 0), + (10036, 14, 137, 369, 0), + (10036, 15, 134, 85, 0), + (10036, 16, 339, 25, 16557), + (10036, 17, 138, 1, 0), + (10036, 18, 142, 60, 0), + (10036, 19, 137, 116, 0), + (10036, 20, 134, 85, 0), + (10037, 1, 339, 25, 16558), + (10037, 2, 138, 1, 0), + (10037, 3, 142, 60, 0), + (10037, 4, 137, 35, 0), + (10037, 5, 134, 85, 0), + (10037, 6, 339, 25, 16558), + (10037, 7, 138, 1, 0), + (10037, 8, 142, 60, 0), + (10037, 9, 137, 36, 0), + (10037, 10, 134, 85, 0), + (10037, 11, 339, 25, 16558), + (10037, 12, 138, 1, 0), + (10037, 13, 142, 60, 0), + (10037, 14, 137, 369, 0), + (10037, 15, 134, 85, 0), + (10037, 16, 339, 25, 16558), + (10037, 17, 138, 1, 0), + (10037, 18, 142, 60, 0), + (10037, 19, 137, 116, 0), + (10037, 20, 134, 85, 0), + (10041, 1, 294, 0, 135), + (10042, 1, 294, 0, 145), + (10043, 1, 294, 0, 155), + (10044, 1, 339, 20, 16564), + (10044, 2, 137, 21, 0), + (10044, 3, 385, -18000, 0), + (10044, 4, 339, 20, 16564), + (10044, 5, 137, 343, 0), + (10044, 6, 385, -18000, 0), + (10045, 1, 339, 20, 16565), + (10045, 2, 137, 21, 0), + (10045, 3, 385, -18000, 0), + (10045, 4, 339, 20, 16565), + (10045, 5, 137, 343, 0), + (10045, 6, 385, -18000, 0), + (10046, 1, 339, 20, 16566), + (10046, 2, 137, 21, 0), + (10046, 3, 385, -18000, 0), + (10046, 4, 339, 20, 16566), + (10046, 5, 137, 343, 0), + (10046, 6, 385, -18000, 0), + (10050, 1, 85, 16567, 0), + (10051, 1, 85, 16568, 0), + (10052, 1, 85, 16569, 0), + (10058, 1, 330, 55, 7), + (10059, 1, 330, 60, 7), + (10060, 1, 330, 65, 7), + (10064, 1, 347, 25, 0), + (10065, 1, 347, 26, 0), + (10066, 1, 347, 27, 0), + (10067, 1, 347, 28, 0), + (10068, 1, 347, 29, 0), + (10069, 1, 347, 30, 0), + (10070, 1, 218, 6, 0), + (10071, 1, 218, 7, 0), + (10072, 1, 218, 8, 0), + (10073, 1, 218, 9, 0), + (10074, 1, 218, 10, 0), + (10075, 1, 339, 10, 16581), + (10075, 2, 138, 0, 0), + (10075, 3, 142, 70, 0), + (10075, 4, 403, 4, 0), + (10075, 5, 348, 1, 0), + (10075, 6, 404, 2, 0), + (10075, 7, 141, 1, 0), + (10076, 1, 339, 10, 16582), + (10076, 2, 138, 0, 0), + (10076, 3, 142, 70, 0), + (10076, 4, 403, 4, 0), + (10076, 5, 348, 1, 0), + (10076, 6, 404, 2, 0), + (10076, 7, 141, 1, 0), + (10077, 1, 339, 10, 16583), + (10077, 2, 138, 0, 0), + (10077, 3, 142, 70, 0), + (10077, 4, 403, 4, 0), + (10077, 5, 348, 1, 0), + (10077, 6, 404, 2, 0), + (10077, 7, 141, 1, 0), + (10081, 1, 85, 16584, 0), + (10082, 1, 85, 16585, 0), + (10083, 1, 85, 16586, 0), + (10084, 1, 375, 175, 0), + (10085, 1, 375, 200, 0), + (10086, 1, 375, 215, 0), + (10087, 1, 397, 400, 0), + (10088, 1, 397, 600, 0), + (10089, 1, 397, 800, 0), + (10105, 1, 264, 60, 170), + (10106, 1, 264, 70, 170), + (10107, 1, 264, 80, 170), + (10108, 1, 264, 90, 170), + (10109, 1, 264, 100, 170), + (10110, 1, 264, 480, 520), + (10111, 1, 264, 600, 520), + (10112, 1, 264, 720, 520), + (10122, 1, 227, 210, 32), + (10123, 1, 227, 240, 32), + (10124, 1, 283, 180, 0), + (10125, 1, 283, 200, 0), + (10126, 1, 283, 220, 0), + (10130, 1, 264, 720, 544), + (10131, 1, 264, 900, 544), + (10132, 1, 264, 1080, 544), + (10133, 1, 279, 19, 0), + (10134, 1, 279, 23, 0), + (10135, 1, 279, 27, 0), + (10136, 1, 375, 130, 0), + (10137, 1, 375, 135, 0), + (10138, 1, 375, 140, 0), + (10153, 1, 264, 420, 553), + (10154, 1, 264, 480, 553), + (10155, 1, 264, 540, 553), + (10165, 1, 220, 195, 8), + (10166, 1, 220, 225, 8), + (10167, 1, 220, 255, 8), + (10171, 1, 252, 90, 0), + (10172, 1, 252, 95, 0), + (10173, 1, 258, 70, 0), + (10174, 1, 258, 71, 0), + (10175, 1, 258, 72, 0), + (10176, 1, 264, 40, 171), + (10177, 1, 264, 50, 171), + (10178, 1, 264, 60, 171), + (10182, 1, 264, 180, 177), + (10183, 1, 264, 210, 177), + (10184, 1, 264, 240, 177), + (10185, 1, 264, 270, 177), + (10186, 1, 264, 300, 177), + (10203, 1, 264, 720, 524), + (10204, 1, 264, 900, 524), + (10205, 1, 264, 1080, 524), + (10206, 1, 264, 1080, 320), + (10207, 1, 264, 1260, 320), + (10213, 1, 218, 16, 0), + (10214, 1, 218, 17, 0), + (10215, 1, 218, 18, 0), + (10216, 1, 218, 19, 0), + (10217, 1, 218, 20, 0), + (10219, 1, 280, 63, 0), + (10220, 1, 280, 64, 0), + (10221, 1, 280, 65, 0), + (10222, 1, 280, 66, 0), + (10223, 1, 280, 67, 0), + (10227, 1, 360, 60, 16720), + (10228, 1, 360, 60, 16721), + (10229, 1, 360, 60, 16722), + (10249, 1, 264, 240, 208), + (10250, 1, 264, 300, 208), + (10251, 1, 264, 360, 208), + (10262, 1, 274, 23, 0), + (10263, 1, 274, 24, 0), + (10264, 1, 274, 25, 0), + (10265, 1, 280, 57, 0), + (10266, 1, 280, 58, 0), + (10267, 1, 280, 59, 0), + (10268, 1, 339, 45, 16736), + (10268, 2, 136, 11, 0), + (10268, 3, 383, 45, 16736), + (10268, 4, 385, 11012, 0), + (10268, 5, 383, 45, 16736), + (10268, 6, 385, 5130, 0), + (10268, 7, 383, 45, 16736), + (10268, 8, 385, 5230, 0), + (10268, 9, 383, 45, 16736), + (10268, 10, 136, 22, 0), + (10268, 11, 383, 45, 16736), + (10268, 12, 385, 5330, 0), + (10268, 13, 385, 5430, 0), + (10268, 14, 385, 5530, 0), + (10269, 1, 339, 45, 16737), + (10269, 2, 136, 11, 0), + (10269, 3, 383, 45, 16737), + (10269, 4, 385, 11012, 0), + (10269, 5, 383, 45, 16737), + (10269, 6, 385, 5130, 0), + (10269, 7, 383, 45, 16737), + (10269, 8, 385, 5230, 0), + (10269, 9, 383, 45, 16737), + (10269, 10, 136, 22, 0), + (10269, 11, 383, 45, 16737), + (10269, 12, 385, 5330, 0), + (10269, 13, 385, 5430, 0), + (10269, 14, 385, 5530, 0), + (10270, 1, 339, 45, 16738), + (10270, 2, 136, 11, 0), + (10270, 3, 383, 45, 16738), + (10270, 4, 385, 11012, 0), + (10270, 5, 383, 45, 16738), + (10270, 6, 385, 5130, 0), + (10270, 7, 383, 45, 16738), + (10270, 8, 385, 5230, 0), + (10270, 9, 383, 45, 16738), + (10270, 10, 136, 22, 0), + (10270, 11, 383, 45, 16738), + (10270, 12, 385, 5330, 0), + (10270, 13, 385, 5430, 0), + (10270, 14, 385, 5530, 0), + (10282, 1, 264, 120, 791), + (10283, 1, 264, 150, 791), + (10284, 1, 264, 180, 791), + (10285, 1, 264, 720, 521), + (10286, 1, 264, 900, 521), + (10287, 1, 264, 1080, 521), + (10291, 1, 264, 15, 247), + (10291, 2, 264, 8, 986), + (10291, 3, 264, 8, 987), + (10291, 4, 264, 8, 988), + (10292, 1, 264, 18, 247), + (10292, 2, 264, 10, 986), + (10292, 3, 264, 10, 987), + (10292, 4, 264, 10, 988), + (10293, 1, 264, 21, 247), + (10293, 2, 264, 12, 986), + (10293, 3, 264, 12, 987), + (10293, 4, 264, 12, 988), + (10305, 1, 280, 68, 0), + (10306, 1, 280, 69, 0), + (10307, 1, 280, 70, 0), + (10311, 1, 220, 608, 74), + (10312, 1, 220, 640, 74), + (10313, 1, 220, 672, 74), + (10314, 1, 220, 704, 74), + (10315, 1, 220, 736, 74), + (10316, 1, 216, 160, 74), + (10317, 1, 216, 200, 74), + (10318, 1, 216, 240, 74), + (10329, 1, 264, 60, 3701), + (10332, 1, 287, 1, 0), + (10332, 2, 137, 22, 0), + (10332, 3, 411, 256, 0), + (10340, 1, 220, 100, 26), + (10341, 1, 220, 160, 26), + (10342, 1, 220, 235, 26), + (10343, 1, 264, 5, 469), + (10344, 1, 264, 10, 469), + (10345, 1, 264, 15, 469), + (10347, 1, 310, 12000, 0), + (10347, 2, 139, 8007, 0), + (10347, 3, 310, 12000, 0), + (10347, 4, 385, 4140, 0), + (10347, 5, 385, 4240, 0), + (10347, 6, 385, 4340, 0), + (10347, 7, 385, 4440, 0), + (10347, 8, 385, 4540, 0), + (10347, 9, 385, 4640, 0), + (10348, 1, 244, 60, 0), + (10349, 1, 244, 50, 0), + (10350, 1, 244, 40, 0), + (10355, 1, 124, 50, 50), + (10355, 2, 385, 19, 0), + (10355, 3, 144, 0, 0), + (10355, 4, 403, 3, 0), + (10355, 5, 404, 48, 0), + (10355, 6, 385, -21768, 0), + (10356, 1, 124, 100, 100), + (10356, 2, 385, 19, 0), + (10356, 3, 144, 0, 0), + (10356, 4, 403, 3, 0), + (10356, 5, 404, 48, 0), + (10356, 6, 385, -21768, 0), + (10357, 1, 124, 150, 150), + (10357, 2, 385, 19, 0), + (10357, 3, 144, 0, 0), + (10357, 4, 403, 3, 0), + (10357, 5, 404, 48, 0), + (10357, 6, 385, -21768, 0), + (10358, 1, 310, 10000, 0), + (10358, 2, 139, 1546, 0), + (10358, 3, 310, 10000, 0), + (10358, 4, 385, 4357, 0), + (10358, 5, 385, 4457, 0), + (10358, 6, 385, 4557, 0), + (10358, 7, 385, 4657, 0), + (10358, 8, 411, 4, 0), + (10359, 1, 310, 20000, 0), + (10359, 2, 139, 1546, 0), + (10359, 3, 310, 20000, 0), + (10359, 4, 385, 4357, 0), + (10359, 5, 385, 4457, 0), + (10359, 6, 385, 4557, 0), + (10359, 7, 385, 4657, 0), + (10359, 8, 411, 4, 0), + (10360, 1, 310, 30000, 0), + (10360, 2, 139, 1546, 0), + (10360, 3, 310, 30000, 0), + (10360, 4, 385, 4357, 0), + (10360, 5, 385, 4457, 0), + (10360, 6, 385, 4557, 0), + (10360, 7, 385, 4657, 0), + (10360, 8, 411, 4, 0), + (10361, 1, 232, 17, 4544), + (10362, 1, 232, 19, 4544), + (10363, 1, 232, 21, 4544), + (10364, 1, 413, -5, 0), + (10364, 2, 139, 480, 0), + (10364, 3, 385, 4352, 0), + (10364, 4, 385, 4452, 0), + (10365, 1, 413, -10, 0), + (10365, 2, 139, 480, 0), + (10365, 3, 385, 4352, 0), + (10365, 4, 385, 4452, 0), + (10366, 1, 413, -15, 0), + (10366, 2, 139, 480, 0), + (10366, 3, 385, 4352, 0), + (10366, 4, 385, 4452, 0), + (10370, 1, 114, -5, 0), + (10371, 1, 114, -10, 0), + (10372, 1, 114, -20, 0), + (10380, 1, 126, 5, 0), + (10380, 2, 134, 85, 0), + (10380, 3, 135, 4, 0), + (10380, 4, 135, 5, 0), + (10381, 1, 126, 10, 0), + (10381, 2, 134, 85, 0), + (10381, 3, 135, 4, 0), + (10381, 4, 135, 5, 0), + (10382, 1, 126, 15, 0), + (10382, 2, 134, 85, 0), + (10382, 3, 135, 4, 0), + (10382, 4, 135, 5, 0), + (10383, 1, 360, 25, 21770), + (10384, 1, 360, 25, 21771), + (10385, 1, 360, 25, 21772), + (10388, 1, 323, 21850, 0), + (10389, 1, 287, 5, 0), + (10389, 2, 385, 16107, 0), + (10389, 3, 411, 512, 0), + (10390, 1, 287, 10, 0), + (10390, 2, 385, 16107, 0), + (10390, 3, 411, 512, 0), + (10391, 1, 287, 15, 0), + (10391, 2, 385, 16107, 0), + (10391, 3, 411, 512, 0), + (10398, 1, 264, 120, 3701), + (10399, 1, 264, 180, 3701), + (10401, 1, 310, 30000, 0), + (10401, 2, 385, 3107, 0), + (10401, 3, 385, 3207, 0), + (10401, 4, 385, 3307, 0), + (10401, 5, 385, 3407, 0), + (10401, 6, 385, 3507, 0), + (10401, 7, 385, 3607, 0), + (10402, 1, 310, 60000, 0), + (10402, 2, 385, 3107, 0), + (10402, 3, 385, 3207, 0), + (10402, 4, 385, 3307, 0), + (10402, 5, 385, 3407, 0), + (10402, 6, 385, 3507, 0), + (10402, 7, 385, 3607, 0), + (10403, 1, 310, 90000, 0), + (10403, 2, 385, 3107, 0), + (10403, 3, 385, 3207, 0), + (10403, 4, 385, 3307, 0), + (10403, 5, 385, 3407, 0), + (10403, 6, 385, 3507, 0), + (10403, 7, 385, 3607, 0), + (10404, 1, 287, 1, 0), + (10404, 2, 139, 8003, 0), + (10405, 1, 310, 120000, 0), + (10405, 2, 139, 4590, 0), + (10406, 1, 310, 240000, 0), + (10406, 2, 139, 4590, 0), + (10407, 1, 310, 360000, 0), + (10407, 2, 139, 4590, 0), + (10408, 1, 310, 480000, 0), + (10408, 2, 139, 4590, 0), + (10409, 1, 310, 600000, 0), + (10409, 2, 139, 4590, 0), + (10410, 1, 247, 130, 76), + (10413, 1, 264, 60, 207), + (10414, 2, 264, 120, 207), + (10415, 3, 264, 180, 207), + (10416, 4, 264, 240, 207), + (10417, 5, 264, 300, 207), + (10431, 1, 264, 210, 791), + (10432, 1, 264, 240, 791), + (10433, 1, 264, 270, 791), + (10434, 1, 127, 16, 0), + (10434, 2, 385, 5921, 0), + (10435, 1, 127, 33, 0), + (10435, 2, 385, 5921, 0), + (10436, 1, 127, 50, 0), + (10436, 2, 385, 5921, 0), + (10437, 1, 339, 25, 23523), + (10437, 2, 137, 21, 0), + (10438, 1, 339, 25, 23524), + (10438, 2, 137, 21, 0), + (10439, 1, 339, 25, 23525), + (10439, 2, 137, 21, 0), + (10440, 1, 339, 25, 23526), + (10440, 2, 137, 21, 0), + (10442, 1, 413, -20, 0), + (10442, 2, 139, 480, 0), + (10442, 3, 385, 4352, 0), + (10442, 4, 385, 4452, 0), + (10443, 1, 413, -25, 0), + (10443, 2, 139, 480, 0), + (10443, 3, 385, 4352, 0), + (10443, 4, 385, 4452, 0), + (10453, 1, 126, 1, 1), + (10453, 2, 137, 21, 0), + (10453, 3, 231, 1, 0), + (10454, 1, 126, 2, 2), + (10454, 2, 137, 21, 0), + (10454, 3, 231, 2, 0), + (10455, 1, 126, 3, 3), + (10455, 2, 137, 21, 0), + (10455, 3, 231, 3, 0), + (10456, 1, 127, 15, 15), + (10456, 2, 139, 12786, 0), + (10457, 1, 127, 30, 30), + (10457, 2, 139, 12786, 0), + (10458, 1, 127, 50, 50), + (10458, 2, 139, 12786, 0), + (10459, 1, 310, 3000, 0), + (10459, 2, 139, 480, 0), + (10459, 3, 310, 3000, 0), + (10459, 4, 385, 4352, 0), + (10459, 5, 385, 4452, 0), + (10459, 6, 385, 4552, 0), + (10460, 1, 310, 6000, 0), + (10460, 2, 139, 480, 0), + (10460, 3, 310, 6000, 0), + (10460, 4, 385, 4352, 0), + (10460, 5, 385, 4452, 0), + (10460, 6, 385, 4552, 0), + (10461, 1, 310, 10000, 0), + (10461, 2, 139, 480, 0), + (10461, 3, 310, 10000, 0), + (10461, 4, 385, 4352, 0), + (10461, 5, 385, 4452, 0), + (10461, 6, 385, 4552, 0), + (10464, 1, 264, 120, 391), + (10465, 1, 264, 240, 391), + (10466, 1, 264, 360, 391), + (10467, 1, 128, 70, 70), + (10467, 2, 138, 1, 0), + (10467, 3, 140, 1, 0), + (10467, 4, 139, -2741, 0), + (10467, 5, 139, -16843, 0), + (10467, 6, 385, -16192, 0), + (10467, 7, 385, -10547, 0), + (10467, 8, 385, -13543, 0), + (10470, 1, 127, 10, 0), + (10470, 2, 385, 8048, 0), + (10471, 1, 127, 20, 0), + (10471, 2, 385, 8048, 0), + (10472, 1, 127, 30, 0), + (10472, 2, 385, 8048, 0), + (10473, 1, 265, 82, 0), + (10474, 1, 265, 83, 0), + (10475, 1, 265, 84, 0), + (10476, 1, 265, 85, 0), + (10477, 1, 265, 86, 0), + (10478, 1, 360, 3, 46246), + (10511, 1, 264, 60, 185), + (10511, 2, 264, 60, 10426), + (10512, 1, 264, 120, 185), + (10512, 2, 264, 120, 10426), + (10513, 1, 264, 180, 185), + (10513, 2, 264, 180, 10426), + (10514, 1, 264, 60, 519), + (10514, 2, 264, 60, 10427), + (10515, 1, 264, 180, 519), + (10515, 2, 264, 180, 10427), + (10516, 1, 264, 120, 519), + (10516, 2, 264, 120, 10427), + (10519, 1, 264, 60, 3213), + (10522, 1, 264, 2, 3732), + (10527, 1, 264, 30, 1400), + (10532, 1, 264, 30, 1401), + (10537, 1, 264, 30, 1402), + (10548, 1, 349, 10, 0), + (10548, 2, 200, 10, 0), + (10548, 3, 419, 27672, 20), + (10551, 1, 339, 10, 16825), + (10551, 2, 137, 31, 0), + (10552, 1, 339, 10, 16826), + (10552, 2, 137, 31, 0), + (10553, 1, 339, 10, 16827), + (10553, 2, 137, 31, 0), + (10554, 1, 339, 12, 8265), + (10554, 2, 138, 0, 0), + (10554, 3, 137, 31, 0), + (10554, 4, 311, 0, 0), + (10555, 1, 339, 14, 8265), + (10555, 2, 138, 0, 0), + (10555, 3, 137, 31, 0), + (10555, 4, 311, 0, 0), + (10556, 1, 339, 16, 8265), + (10556, 2, 138, 0, 0), + (10556, 3, 137, 31, 0), + (10556, 4, 311, 0, 0), + (10558, 1, 264, 60, 1120), + (10559, 1, 264, 120, 1120), + (10560, 1, 264, 180, 1120), + (10561, 1, 126, 5, 5), + (10561, 2, 139, 12576, 0), + (10561, 3, 126, 5, 5), + (10561, 4, 139, 12828, 0), + (10562, 1, 126, 10, 10), + (10562, 2, 139, 12576, 0), + (10562, 3, 126, 10, 10), + (10562, 4, 139, 12828, 0), + (10563, 1, 126, 15, 15), + (10563, 2, 139, 12576, 0), + (10563, 3, 126, 15, 15), + (10563, 4, 139, 12828, 0), + (10568, 1, 85, 23614, 50), + (10574, 1, 310, 720000, 0), + (10574, 2, 139, 4670, 0), + (10575, 1, 310, 720000, 0), + (10575, 2, 139, 4674, 0), + (10576, 1, 264, 420, 109), + (10579, 1, 264, 40, 3646), + (10580, 1, 264, 50, 3646), + (10588, 1, 264, 2, 601), + (10589, 1, 264, 4, 601), + (10590, 1, 264, 6, 601), + (10591, 1, 264, 8, 601), + (10592, 1, 264, 10, 601), + (10604, 1, 213, 13, 0), + (10605, 1, 213, 15, 0), + (10606, 1, 213, 17, 0), + (10607, 1, 215, 12, 0), + (10608, 1, 215, 14, 0), + (10609, 1, 215, 16, 0), + (10610, 1, 129, 25, 25), + (10610, 2, 385, 100265, 0), + (10611, 1, 129, 25, 25), + (10611, 2, 385, 100265, 0), + (10612, 1, 129, 25, 25), + (10612, 2, 385, 100265, 0), + (10621, 1, 264, 960, 180), + (10622, 1, 264, 1200, 180), + (10623, 1, 279, 19, 0), + (10624, 1, 279, 24, 0), + (10625, 1, 279, 30, 0), + (10627, 1, 224, 20, 74), + (10627, 2, 173, 1, 0), + (10628, 1, 224, 35, 74), + (10628, 2, 173, 2, 0), + (10629, 1, 224, 50, 74), + (10629, 2, 173, 3, 0), + (10632, 1, 265, 82, 0), + (10633, 1, 265, 83, 0), + (10634, 1, 265, 84, 0), + (10635, 1, 265, 85, 0), + (10636, 1, 265, 86, 0), + (10637, 1, 320, 12, 0), + (10638, 1, 320, 13, 0), + (10639, 1, 320, 14, 0), + (10641, 2, 385, 11064, 0), + (10643, 1, 124, 200, 200), + (10643, 2, 385, 19, 0), + (10643, 3, 144, 0, 0), + (10643, 4, 403, 3, 0), + (10643, 5, 404, 48, 0), + (10643, 6, 385, -21768, 0), + (10644, 1, 124, 250, 250), + (10644, 2, 385, 19, 0), + (10644, 3, 144, 0, 0), + (10644, 4, 403, 3, 0), + (10644, 5, 404, 48, 0), + (10644, 6, 385, -21768, 0), + (10645, 1, 124, 300, 300), + (10645, 2, 385, 19, 0), + (10645, 3, 144, 0, 0), + (10645, 4, 403, 3, 0), + (10645, 5, 404, 48, 0), + (10645, 6, 385, -21768, 0), + (10650, 1, 378, 1, 3), + (10651, 1, 378, 2, 3), + (10652, 1, 378, 3, 3), + (10653, 1, 310, 120000, 0), + (10653, 2, 139, 4502, 0), + (10653, 3, 139, 4509, 0), + (10654, 1, 310, 240000, 0), + (10654, 2, 139, 4502, 0), + (10654, 3, 139, 4509, 0), + (10655, 1, 310, 360000, 0), + (10655, 2, 139, 4502, 0), + (10655, 3, 139, 4509, 0), + (10656, 1, 287, 1, 0), + (10656, 2, 385, 15002, 0), + (10656, 3, 385, 15003, 0), + (10656, 4, 411, 128, 0), + (10657, 1, 264, 300, 276), + (10658, 1, 264, 600, 276), + (10659, 1, 264, 900, 276), + (10660, 1, 220, 175, 26), + (10660, 2, 220, 175, 30), + (10660, 3, 220, 175, 38), + (10661, 1, 220, 200, 26), + (10661, 2, 220, 200, 30), + (10661, 3, 220, 200, 38), + (10662, 1, 220, 225, 26), + (10662, 2, 220, 225, 30), + (10662, 3, 220, 225, 38), + (10663, 1, 220, 165, 21), + (10663, 2, 220, 165, 23), + (10663, 3, 220, 330, 52), + (10663, 4, 220, 165, 28), + (10664, 1, 220, 175, 21), + (10664, 2, 220, 175, 23), + (10664, 3, 220, 350, 52), + (10664, 4, 220, 175, 28), + (10665, 1, 220, 185, 21), + (10665, 2, 220, 185, 23), + (10665, 3, 220, 370, 52), + (10665, 4, 220, 185, 28), + (10666, 1, 264, 1200, 98), + (10667, 1, 264, 1320, 98), + (10668, 1, 264, 1440, 98), + (10671, 1, 310, 720000, 0), + (10671, 2, 139, 4590, 0), + (10672, 1, 310, 840000, 0), + (10672, 2, 139, 4590, 0), + (10673, 1, 310, 960000, 0), + (10673, 2, 139, 4590, 0), + (10674, 1, 310, 1080000, 0), + (10674, 2, 139, 4590, 0), + (10675, 1, 310, 1200000, 0), + (10675, 2, 139, 4590, 0), + (10676, 1, 339, 20, 23623), + (10676, 2, 137, 21, 0), + (10676, 3, 385, -18000, 0), + (10676, 4, 339, 20, 23623), + (10676, 5, 137, 343, 0), + (10676, 6, 385, -18000, 0), + (10677, 1, 339, 20, 23624), + (10677, 2, 137, 21, 0), + (10677, 3, 385, -18000, 0), + (10677, 4, 339, 20, 23624), + (10677, 5, 137, 343, 0), + (10677, 6, 385, -18000, 0), + (10678, 1, 339, 20, 23625), + (10678, 2, 137, 21, 0), + (10678, 3, 385, -18000, 0), + (10678, 4, 339, 20, 23625), + (10678, 5, 137, 343, 0), + (10678, 6, 385, -18000, 0), + (10685, 1, 266, 34, 0), + (10686, 1, 266, 39, 0), + (10687, 1, 266, 45, 0), + (10688, 1, 220, 125, 10), + (10689, 1, 220, 145, 10), + (10690, 1, 220, 165, 10), + (10691, 1, 220, 190, 10), + (10692, 1, 220, 220, 10), + (10705, 1, 85, 23542, 0), + (10706, 1, 85, 23543, 0), + (10707, 1, 85, 23544, 0), + (10714, 1, 264, 90, 873), + (10715, 1, 264, 180, 873), + (10717, 1, 264, 360, 184), + (10718, 1, 264, 450, 184), + (10719, 1, 264, 120, 872), + (10720, 1, 264, 240, 872), + (10721, 1, 264, 360, 872), + (10722, 1, 264, 120, 778), + (10723, 1, 264, 240, 778), + (10724, 1, 264, 360, 778), + (10725, 1, 264, 480, 778), + (10726, 1, 264, 600, 778), + (10727, 1, 264, 120, 2235), + (10728, 1, 264, 240, 2235), + (10730, 1, 264, 10, 870), + (10731, 1, 264, 20, 870), + (10733, 1, 264, 1, 219), + (10734, 1, 264, 2, 219), + (10735, 1, 264, 3, 219), + (10743, 1, 220, 135, 7), + (10744, 1, 220, 170, 7), + (10745, 1, 220, 205, 7), + (10748, 1, 59, -35, 0), + (10749, 1, 59, -42, 0), + (10750, 1, 264, 3024, 286), + (10750, 2, 264, 3024, 10753), + (10750, 3, 264, 3024, 9101), + (10751, 1, 264, 3456, 286), + (10751, 2, 264, 3456, 10753), + (10751, 3, 264, 3456, 9101), + (10755, 1, 59, -50, 0), + (10763, 1, 292, 50, 0), + (10764, 1, 292, 60, 0), + (10766, 1, 330, 70, 7), + (10767, 1, 330, 75, 7), + (10768, 1, 330, 80, 7), + (10769, 1, 310, 1440000, 0), + (10769, 2, 139, 4519, 0), + (10770, 1, 310, 1680000, 0), + (10770, 2, 139, 4519, 0), + (10778, 1, 274, 38, 0), + (10779, 1, 274, 40, 0), + (10780, 1, 274, 42, 0), + (10781, 1, 1, 186, 0), + (10782, 1, 1, 217, 0), + (10783, 1, 1, 248, 0), + (10784, 1, 1, 279, 0), + (10785, 1, 1, 310, 0), + (10788, 1, 363, 4, 0), + (10792, 1, 287, 1, 0), + (10792, 2, 385, 5240, 0), + (10792, 3, 385, 5340, 0), + (10792, 4, 385, 5440, 0), + (10792, 5, 385, 5540, 0), + (10792, 6, 385, 5640, 0), + (10793, 1, 287, 2, 0), + (10793, 2, 385, 5240, 0), + (10793, 3, 385, 5340, 0), + (10793, 4, 385, 5440, 0), + (10793, 5, 385, 5540, 0), + (10793, 6, 385, 5640, 0), + (10794, 1, 287, 3, 0), + (10794, 2, 385, 5240, 0), + (10794, 3, 385, 5340, 0), + (10794, 4, 385, 5440, 0), + (10794, 5, 385, 5540, 0), + (10794, 6, 385, 5640, 0), + (10795, 1, 287, 4, 0), + (10795, 2, 385, 5240, 0), + (10795, 3, 385, 5340, 0), + (10795, 4, 385, 5440, 0), + (10795, 5, 385, 5540, 0), + (10795, 6, 385, 5640, 0), + (10796, 1, 287, 5, 0), + (10796, 2, 385, 5240, 0), + (10796, 3, 385, 5340, 0), + (10796, 4, 385, 5440, 0), + (10796, 5, 385, 5540, 0), + (10796, 6, 385, 5640, 0), + (10800, 1, 264, 60, 462), + (10801, 1, 264, 120, 462), + (10802, 1, 264, 180, 462), + (10803, 1, 293, 25, 0), + (10804, 1, 293, 50, 0), + (10805, 1, 293, 75, 0), + (10815, 1, 185, 2, 1), + (10815, 2, 185, 2, 3), + (10816, 1, 185, 4, 1), + (10816, 2, 185, 4, 3), + (10817, 1, 185, 6, 1), + (10817, 2, 185, 6, 3), + (10818, 1, 185, 1, 36), + (10819, 1, 185, 3, 36), + (10820, 1, 185, 5, 36), + (10821, 1, 185, 2, 0), + (10821, 2, 185, 2, 2), + (10822, 1, 185, 4, 0), + (10822, 2, 185, 4, 2), + (10823, 1, 185, 6, 0), + (10823, 2, 185, 6, 2), + (10850, 1, 288, 100, 8), + (10851, 1, 288, 100, 8), + (10852, 1, 288, 100, 8), + (10853, 1, 292, 5, 0), + (10854, 1, 292, 10, 0), + (10855, 1, 292, 15, 0), + (10856, 1, 292, 20, 0), + (10857, 1, 292, 25, 0), + (10858, 1, 292, 30, 0), + (10859, 1, 292, 35, 0), + (10860, 1, 292, 40, 0), + (10861, 1, 292, 45, 0), + (10862, 1, 292, 46, 0), + (10863, 1, 292, 47, 0), + (10864, 1, 292, 48, 0), + (10865, 1, 216, 500, 8), + (10866, 1, 216, 550, 8), + (10867, 1, 216, 650, 8), + (10903, 1, 281, 25, 0), + (10904, 1, 281, 50, 0), + (10905, 1, 281, 75, 0), + (10906, 1, 59, -48, 0), + (10907, 1, 59, -51, 0), + (10908, 1, 59, -54, 0), + (10909, 1, 264, 60, 7007), + (10910, 1, 264, 120, 7007), + (10911, 1, 264, 180, 7007), + (10915, 1, 339, 10, 16876), + (10915, 2, 138, 0, 0), + (10915, 3, 142, 70, 0), + (10915, 4, 411, 32, 0), + (10915, 5, 348, 1, 0), + (10915, 6, 141, 1, 0), + (10916, 1, 339, 10, 16877), + (10916, 2, 138, 0, 0), + (10916, 3, 142, 70, 0), + (10916, 4, 411, 32, 0), + (10916, 5, 348, 1, 0), + (10916, 6, 141, 1, 0), + (10917, 1, 339, 10, 16878), + (10917, 2, 138, 0, 0), + (10917, 3, 142, 70, 0), + (10917, 4, 411, 32, 0), + (10917, 5, 348, 1, 0), + (10917, 6, 141, 1, 0), + (10950, 1, 287, 1, 0), + (10950, 2, 403, 4, 0), + (10950, 3, 404, 38, 0), + (10950, 4, 348, 1, 0), + (10950, 5, 137, 11, 0), + (10950, 6, 140, 2, 0), + (10951, 1, 264, 60, 447), + (10952, 1, 264, 120, 447), + (10953, 1, 264, 180, 447), + (10954, 1, 264, 60, 662), + (10955, 1, 264, 120, 662), + (10956, 1, 264, 180, 662), + (11000, 1, 227, 1, 73), + (11001, 1, 227, 2, 73), + (11002, 1, 227, 3, 73), + (11003, 1, 287, 1, 0), + (11003, 2, 137, 158, 0), + (11003, 3, 411, 2, 0), + (11004, 1, 287, 1, 0), + (11004, 2, 139, 8000, 0), + (11005, 1, 287, 2, 0), + (11005, 2, 139, 8000, 0), + (11006, 1, 287, 3, 0), + (11006, 2, 139, 8000, 0), + (11011, 1, 264, 480, 3710), + (11012, 1, 264, 600, 3710), + (11013, 1, 264, 720, 3710), + (11014, 1, 264, 10, 3899), + (11014, 2, 264, 10, 611), + (11014, 3, 264, 10, 960), + (11014, 4, 264, 10, 1252), + (11015, 1, 264, 20, 3899), + (11015, 2, 264, 20, 611), + (11015, 3, 264, 20, 960), + (11015, 4, 264, 20, 1252), + (11016, 1, 264, 30, 3899), + (11016, 2, 264, 30, 611), + (11016, 3, 264, 30, 960), + (11016, 4, 264, 30, 1252), + (11020, 1, 264, 40, 3899), + (11020, 2, 264, 40, 611), + (11020, 3, 264, 40, 960), + (11020, 4, 264, 40, 1252), + (11050, 1, 264, 360, 452), + (11050, 2, 264, 360, 6106), + (11050, 3, 264, 360, 493), + (11051, 1, 264, 720, 452), + (11051, 2, 264, 720, 6106), + (11051, 3, 264, 720, 493), + (11052, 1, 264, 1080, 452), + (11052, 2, 264, 1080, 6106), + (11052, 3, 264, 1080, 493), + (11053, 1, 264, 1260, 500), + (11054, 1, 264, 1440, 500), + (11059, 1, 264, 1440, 452), + (11059, 2, 264, 1440, 6106), + (11059, 3, 264, 1440, 493), + (11060, 1, 264, 1800, 452), + (11060, 2, 264, 1800, 6106), + (11060, 3, 264, 1800, 493), + (11061, 1, 114, -63, 0), + (11062, 1, 114, -64, 0), + (11063, 1, 114, -65, 0), + (11074, 1, 247, 100, 39), + (11075, 1, 247, 150, 39), + (11076, 1, 247, 200, 39), + (11077, 1, 264, 10, 986), + (11078, 1, 264, 10, 988), + (11079, 1, 264, 10, 987), + (11082, 1, 185, 40, 51), + (11083, 1, 185, 50, 51), + (11084, 1, 185, 60, 51), + (11085, 1, 247, 20, 2), + (11085, 2, 247, 20, 3), + (11085, 3, 247, 20, 77), + (11085, 4, 220, 25, 77), + (11085, 5, 220, 25, 2), + (11085, 6, 220, 25, 3), + (11086, 1, 247, 40, 2), + (11086, 2, 247, 40, 3), + (11086, 3, 247, 40, 77), + (11086, 4, 220, 35, 77), + (11086, 5, 220, 35, 2), + (11086, 6, 220, 35, 3), + (11087, 1, 247, 60, 2), + (11087, 2, 247, 60, 3), + (11087, 3, 247, 60, 77), + (11087, 4, 220, 50, 77), + (11087, 5, 220, 50, 2), + (11087, 6, 220, 50, 3), + (11088, 1, 264, 180, 505), + (11089, 1, 264, 360, 505), + (11090, 1, 264, 540, 505), + (11091, 1, 264, 720, 505), + (12396, 1, 172, 50, 0), + (12397, 1, 172, 51, 0), + (12398, 1, 172, 52, 0), + (12399, 1, 172, 53, 0), + (12400, 1, 172, 54, 0), + (12401, 1, 259, 56, 0), + (12402, 1, 259, 57, 0), + (12403, 1, 259, 58, 0), + (12404, 1, 259, 59, 0), + (12405, 1, 259, 60, 0), + (12406, 1, 69, 1100, 0), + (12407, 1, 69, 1200, 0), + (12408, 1, 69, 1300, 0), + (12409, 1, 69, 1400, 0), + (12410, 1, 69, 1500, 0), + (12411, 1, 1, 300, 0), + (12412, 1, 1, 350, 0), + (12413, 1, 1, 400, 0), + (12414, 1, 1, 450, 0), + (12415, 1, 1, 500, 0), + (12416, 1, 399, 3, 0), + (12416, 2, 141, 1, 0), + (12416, 3, 138, 0, 0), + (12416, 4, 142, 255, 0), + (12416, 5, 391, 0, 0), + (12416, 6, 311, 0, 0), + (12416, 7, 137, -152, 0), + (12416, 8, 411, 100350, 0), + (12416, 9, 137, -39, 0), + (12417, 1, 399, 6, 0), + (12417, 2, 141, 1, 0), + (12417, 3, 138, 0, 0), + (12417, 4, 142, 255, 0), + (12417, 5, 391, 0, 0), + (12417, 6, 311, 0, 0), + (12417, 7, 137, -152, 0), + (12417, 8, 411, 100350, 0), + (12417, 9, 137, -39, 0), + (12418, 1, 399, 9, 0), + (12418, 2, 141, 1, 0), + (12418, 3, 138, 0, 0), + (12418, 4, 142, 255, 0), + (12418, 5, 391, 0, 0), + (12418, 6, 311, 0, 0), + (12418, 7, 137, -152, 0), + (12418, 8, 411, 100350, 0), + (12418, 9, 137, -39, 0), + (12419, 1, 292, 15, 0), + (12420, 1, 292, 30, 0), + (12421, 1, 292, 45, 0), + (12423, 1, 273, 21, 0), + (12424, 1, 273, 24, 0), + (12425, 1, 273, 27, 0), + (12426, 1, 273, 21, 0), + (12427, 1, 273, 24, 0), + (12428, 1, 273, 27, 0), + (12432, 1, 294, 17, 100), + (12433, 1, 294, 19, 100), + (12434, 1, 294, 21, 100), + (12435, 1, 294, 23, 100), + (12436, 1, 294, 25, 100), + (12437, 1, 294, 27, 100), + (12438, 1, 200, 70, 0), + (12439, 1, 341, 210, 0), + (12440, 1, 341, 220, 0), + (12441, 1, 341, 230, 0), + (12442, 1, 341, 240, 0), + (12443, 1, 341, 250, 0), + (12444, 1, 318, 21, 0), + (12445, 1, 318, 22, 0), + (12446, 1, 318, 23, 0), + (12447, 1, 318, 24, 0), + (12448, 1, 318, 25, 0), + (12449, 1, 125, 31, 31), + (12449, 2, 137, 0, 0), + (12449, 3, 141, 1, 0), + (12449, 4, 139, -6233, 0), + (12449, 5, 139, -6265, 0), + (12449, 6, 125, 31, 31), + (12449, 7, 137, 147, 0), + (12449, 8, 141, 1, 0), + (12450, 1, 125, 34, 34), + (12450, 2, 137, 0, 0), + (12450, 3, 141, 1, 0), + (12450, 4, 139, -6233, 0), + (12450, 5, 139, -6265, 0), + (12450, 6, 125, 34, 34), + (12450, 7, 137, 147, 0), + (12450, 8, 141, 1, 0), + (12451, 1, 125, 37, 37), + (12451, 2, 137, 0, 0), + (12451, 3, 141, 1, 0), + (12451, 4, 139, -6233, 0), + (12451, 5, 139, -6265, 0), + (12451, 6, 125, 37, 37), + (12451, 7, 137, 147, 0), + (12451, 8, 141, 1, 0), + (12452, 1, 274, 38, 0), + (12453, 1, 274, 39, 0), + (12454, 1, 274, 40, 0), + (12455, 1, 15, 19, 0), + (12456, 1, 15, 20, 0), + (12457, 1, 15, 21, 0), + (12458, 1, 15, 22, 0), + (12459, 1, 15, 23, 0), + (12463, 1, 320, 9, 0), + (12464, 1, 320, 10, 0), + (12465, 1, 320, 11, 0), + (12466, 1, 320, 9, 0), + (12467, 1, 320, 10, 0), + (12468, 1, 320, 11, 0), + (12469, 1, 320, 9, 0), + (12470, 1, 320, 10, 0), + (12471, 1, 320, 11, 0), + (12472, 1, 320, 6, 0), + (12473, 1, 320, 7, 0), + (12474, 1, 320, 8, 0), + (12475, 1, 264, 180, 7003), + (12476, 1, 264, 360, 7003), + (12477, 1, 264, 540, 7003), + (12478, 1, 264, 60, 3705), + (12479, 1, 264, 120, 3705), + (12480, 1, 264, 180, 3705), + (12481, 1, 247, 40, 76), + (12482, 1, 247, 45, 76), + (12483, 1, 247, 65, 76), + (12484, 1, 247, 70, 76), + (12485, 1, 247, 30, 76), + (12486, 1, 247, 35, 76), + (12487, 1, 247, 25, 76), + (12488, 1, 247, 30, 76), + (12492, 1, 69, 1600, 0), + (12493, 1, 69, 1700, 0), + (12494, 1, 69, 1800, 0), + (12495, 1, 69, 1900, 0), + (12496, 1, 69, 2000, 0), + (12497, 1, 125, 40, 40), + (12497, 2, 137, 0, 0), + (12497, 3, 141, 1, 0), + (12497, 4, 139, -6233, 0), + (12497, 5, 139, -6265, 0), + (12497, 6, 125, 40, 40), + (12497, 7, 137, 147, 0), + (12497, 8, 141, 1, 0), + (12498, 1, 125, 43, 43), + (12498, 2, 137, 0, 0), + (12498, 3, 141, 1, 0), + (12498, 4, 139, -6233, 0), + (12498, 5, 139, -6265, 0), + (12498, 6, 125, 43, 43), + (12498, 7, 137, 147, 0), + (12498, 8, 141, 1, 0), + (12499, 1, 125, 46, 46), + (12499, 2, 137, 0, 0), + (12499, 3, 141, 1, 0), + (12499, 4, 139, -6233, 0), + (12499, 5, 139, -6265, 0), + (12499, 6, 125, 46, 46), + (12499, 7, 137, 147, 0), + (12499, 8, 141, 1, 0), + (12500, 1, 310, 1000, 0), + (12500, 2, 385, 4004, 0), + (12500, 3, 385, 11202, 0), + (12500, 4, 385, 11302, 0), + (12500, 5, 385, 11402, 0), + (12500, 6, 385, 11502, 0), + (12500, 7, 385, 11602, 0), + (12501, 1, 310, 2000, 0), + (12501, 2, 385, 4004, 0), + (12501, 3, 385, 11202, 0), + (12501, 4, 385, 11302, 0), + (12501, 5, 385, 11402, 0), + (12501, 6, 385, 11502, 0), + (12501, 7, 385, 11602, 0), + (12502, 1, 310, 3000, 0), + (12502, 2, 385, 4004, 0), + (12502, 3, 385, 11202, 0), + (12502, 4, 385, 11302, 0), + (12502, 5, 385, 11402, 0), + (12502, 6, 385, 11502, 0), + (12502, 7, 385, 11602, 0), + (12505, 1, 310, 4000, 0), + (12505, 2, 385, 4004, 0), + (12505, 3, 385, 11202, 0), + (12505, 4, 385, 11302, 0), + (12505, 5, 385, 11402, 0), + (12505, 6, 385, 11502, 0), + (12505, 7, 385, 11602, 0), + (12506, 1, 310, 5000, 0), + (12506, 2, 385, 4004, 0), + (12506, 3, 385, 11202, 0), + (12506, 4, 385, 11302, 0), + (12506, 5, 385, 11402, 0), + (12506, 6, 385, 11502, 0), + (12506, 7, 385, 11602, 0), + (12507, 1, 301, 120, 0), + (12508, 1, 247, 50, 76), + (12509, 1, 247, 55, 76), + (12510, 1, 247, 60, 76), + (12511, 1, 247, 75, 76), + (12512, 1, 247, 80, 76), + (12513, 1, 247, 85, 76), + (12514, 1, 247, 40, 76), + (12515, 1, 247, 45, 76), + (12516, 1, 247, 50, 76), + (12517, 1, 247, 35, 76), + (12518, 1, 247, 40, 76), + (12519, 1, 247, 45, 76), + (12523, 1, 294, 0, 200), + (12526, 1, 294, 0, 190), + (12527, 1, 294, 0, 195), + (12528, 1, 294, 0, 200), + (12529, 1, 294, 0, 165), + (12530, 1, 294, 0, 175), + (12531, 1, 294, 0, 185), + (12532, 1, 341, 260, 0), + (12533, 1, 341, 270, 0), + (12534, 1, 341, 280, 0), + (12535, 1, 341, 290, 0), + (12536, 1, 341, 300, 0), + (12537, 1, 318, 26, 0), + (12538, 1, 318, 27, 0), + (12539, 1, 318, 28, 0), + (12540, 1, 318, 29, 0), + (12541, 1, 318, 30, 0), + (12548, 1, 278, 900, 79230), + (12548, 2, 440, 87, 100), + (12549, 1, 278, 900, 86260), + (12549, 2, 440, 88, 100), + (12550, 1, 278, 900, 88260), + (12550, 2, 440, 89, 100), + (12551, 1, 278, 900, 91510), + (12551, 2, 440, 90, 100), + (12552, 1, 278, 900, 96305), + (12552, 2, 440, 91, 100), + (12553, 1, 294, 29, 102), + (12554, 1, 294, 31, 104), + (12555, 1, 294, 33, 106), + (12556, 1, 294, 23, 100), + (12557, 1, 294, 25, 100), + (12558, 1, 294, 27, 100), + (12559, 1, 190, 300, 0), + (12560, 1, 190, 350, 0), + (12561, 1, 190, 400, 0), + (12562, 1, 190, 450, 0), + (12563, 1, 190, 500, 0), + (12564, 1, 319, 28, 0), + (12565, 1, 319, 29, 0), + (12566, 1, 319, 30, 0), + (12567, 1, 274, 41, 0), + (12568, 1, 274, 42, 0), + (12569, 1, 274, 43, 0), + (12570, 1, 15, 24, 0), + (12571, 1, 15, 25, 0), + (12572, 1, 15, 26, 0), + (12573, 1, 15, 27, 0), + (12574, 1, 15, 28, 0), + (12575, 1, 292, 60, 0), + (12576, 1, 231, 17, 0), + (12577, 1, 231, 19, 0), + (12578, 1, 231, 21, 0), + (12579, 1, 85, 23569, 0), + (12580, 1, 85, 23570, 0), + (12581, 1, 85, 23571, 0), + (12582, 1, 264, 10, 9400), + (12583, 1, 264, 20, 9400), + (12584, 1, 264, 30, 9400), + (12587, 1, 264, 480, 9403), + (12588, 1, 264, 600, 9403), + (12589, 1, 264, 720, 9403), + (12591, 1, 247, 90, 76), + (12594, 1, 247, 55, 76), + (12597, 1, 247, 50, 76), + (12598, 1, 247, 55, 76), + (12600, 1, 310, 60000, 0), + (12600, 2, 139, 6197, 0), + (12600, 3, 411, 512, 0), + (12603, 1, 287, 1, 0), + (12603, 2, 139, 6197, 0), + (12603, 3, 411, 512, 0), + (12606, 1, 271, 5, 0), + (12607, 1, 310, 12000, 0), + (12607, 2, 385, 13007, 0), + (12607, 3, 385, 12105, 0), + (12607, 4, 385, 12205, 0), + (12607, 5, 310, 36000, 0), + (12607, 6, 385, 12305, 0), + (12607, 7, 385, 12405, 0), + (12607, 8, 385, 12505, 0), + (12607, 9, 411, 512, 0), + (12610, 1, 279, 19, 0), + (12612, 1, 439, 0, 124480), + (12612, 2, 345, 84, 25), + (12613, 1, 439, 0, 132440), + (12613, 2, 345, 86, 25), + (12615, 1, 310, 120000, 0), + (12615, 2, 139, 4695, 0), + (12615, 3, 411, 512, 0), + (12616, 1, 310, 240000, 0), + (12616, 2, 139, 4695, 0), + (12616, 3, 411, 512, 0), + (12617, 1, 310, 360000, 0), + (12617, 2, 139, 4695, 0), + (12617, 3, 411, 512, 0), + (12636, 1, 426, 1, 0), + (12637, 1, 426, 2, 0), + (12639, 1, 264, 240, 519), + (12639, 2, 264, 240, 10427), + (12642, 1, 264, 240, 185), + (12642, 2, 264, 240, 10426), + (12645, 1, 287, 1, 0), + (12645, 2, 385, 8190, 0), + (12645, 3, 287, 1, 0), + (12645, 4, 385, 21818, 0), + (12645, 5, 411, 64, 0), + (12646, 1, 287, 1, 0), + (12646, 2, 385, 3277, 0), + (12646, 3, 287, 1, 0), + (12646, 4, 385, 21816, 0), + (12652, 1, 399, 1, 0), + (12652, 2, 138, 1, 0), + (12652, 3, 137, 0, 0), + (12652, 4, 348, 10, 0), + (12652, 5, 311, 0, 0), + (12652, 6, 141, 1, 0), + (12652, 7, 134, 254, 0), + (12652, 8, 137, -39, 0), + (12653, 1, 399, 2, 0), + (12653, 2, 138, 1, 0), + (12653, 3, 137, 0, 0), + (12653, 4, 348, 10, 0), + (12653, 5, 311, 0, 0), + (12653, 6, 141, 1, 0), + (12653, 7, 134, 254, 0), + (12653, 8, 137, -39, 0), + (12654, 1, 399, 3, 0), + (12654, 2, 138, 1, 0), + (12654, 3, 137, 0, 0), + (12654, 4, 348, 10, 0), + (12654, 5, 311, 0, 0), + (12654, 6, 141, 1, 0), + (12654, 7, 134, 254, 0), + (12654, 8, 137, -39, 0), + (12664, 1, 264, 2, 3728), + (12667, 1, 220, 250, 26), + (12667, 2, 220, 250, 30), + (12667, 3, 220, 250, 38), + (12668, 1, 220, 275, 26), + (12668, 2, 220, 275, 30), + (12668, 3, 220, 275, 38), + (12669, 1, 220, 300, 26), + (12669, 2, 220, 300, 30), + (12669, 3, 220, 300, 38), + (12670, 1, 220, 200, 21), + (12670, 2, 220, 200, 23), + (12670, 3, 220, 400, 52), + (12670, 4, 220, 200, 28), + (12671, 1, 220, 215, 21), + (12671, 2, 220, 215, 23), + (12671, 3, 220, 450, 52), + (12671, 4, 220, 215, 28), + (12672, 1, 220, 235, 21), + (12672, 2, 220, 235, 23), + (12672, 3, 220, 510, 52), + (12672, 4, 220, 235, 28), + (12673, 1, 264, 960, 420), + (12674, 1, 227, 270, 32), + (12675, 1, 227, 300, 32), + (12676, 1, 227, 330, 32), + (12677, 1, 275, 92, 0), + (12678, 1, 287, 2, 0), + (12678, 2, 385, 15002, 0), + (12678, 3, 385, 15003, 0), + (12678, 4, 411, 128, 0), + (12679, 1, 264, 1200, 276), + (12680, 1, 264, 1500, 276), + (12681, 1, 264, 1800, 276), + (12685, 1, 292, 49, 0), + (12686, 1, 292, 50, 0), + (12687, 1, 292, 51, 0), + (12688, 1, 287, 1, 0), + (12688, 2, 385, 8473, 0), + (12688, 3, 385, 8318, 0), + (12688, 4, 385, 8418, 0), + (12688, 5, 385, 8518, 0), + (12688, 6, 411, 128, 0), + (12689, 1, 287, 2, 0), + (12689, 2, 139, 4691, 0), + (12689, 3, 411, 128, 0), + (12690, 1, 287, 2, 0), + (12690, 2, 385, 8111, 0), + (12690, 3, 385, 15008, 0), + (12690, 4, 385, 8411, 0), + (12690, 5, 385, 8511, 0), + (12690, 6, 411, 128, 0), + (12691, 1, 287, 1, 0), + (12691, 2, 385, 15007, 0), + (12691, 3, 411, 128, 0), + (12691, 4, 385, 8316, 0), + (12692, 1, 220, 255, 21), + (12692, 2, 220, 255, 23), + (12692, 3, 220, 570, 52), + (12692, 4, 220, 255, 28), + (12693, 1, 220, 275, 21), + (12693, 2, 220, 275, 23), + (12693, 3, 220, 630, 52), + (12693, 4, 220, 275, 28), + (12694, 1, 189, 16, 0), + (12695, 1, 189, 17, 0), + (12696, 1, 189, 18, 0), + (12697, 1, 330, 140, 0), + (12697, 2, 330, 140, 1), + (12697, 3, 330, 140, 2), + (12697, 4, 330, 140, 3), + (12697, 5, 330, 140, 28), + (12697, 6, 330, 140, 36), + (12697, 7, 330, 140, 77), + (12698, 1, 330, 145, 0), + (12698, 2, 330, 145, 1), + (12698, 3, 330, 145, 2), + (12698, 4, 330, 145, 3), + (12698, 5, 330, 145, 28), + (12698, 6, 330, 145, 36), + (12698, 7, 330, 145, 77), + (12699, 1, 330, 150, 0), + (12699, 2, 330, 150, 1), + (12699, 3, 330, 150, 2), + (12699, 4, 330, 150, 3), + (12699, 5, 330, 150, 28), + (12699, 6, 330, 150, 36), + (12699, 7, 330, 150, 77), + (12703, 1, 283, 240, 0), + (12704, 1, 283, 260, 0), + (12705, 1, 283, 280, 0), + (12706, 1, 220, 60, 28), + (12706, 2, 220, 60, 0), + (12706, 3, 427, 23598, 3), + (12706, 4, 428, 28, 0), + (12706, 5, 428, 0, 0), + (12707, 1, 220, 85, 28), + (12707, 2, 220, 85, 0), + (12707, 3, 427, 23598, 5), + (12707, 4, 428, 28, 0), + (12707, 5, 428, 0, 0), + (12708, 1, 220, 115, 28), + (12708, 2, 220, 115, 0), + (12708, 3, 427, 23598, 7), + (12708, 4, 428, 28, 0), + (12708, 5, 428, 0, 0), + (12709, 1, 287, 1, 0), + (12709, 2, 139, 4516, 0), + (12709, 3, 411, 256, 0), + (12710, 1, 310, 360000, 0), + (12710, 2, 139, 4516, 0), + (12710, 3, 411, 256, 0), + (12711, 1, 310, 720000, 0), + (12711, 2, 139, 4516, 0), + (12711, 3, 411, 256, 0), + (12712, 1, 310, 1080000, 0), + (12712, 2, 139, 4516, 0), + (12712, 3, 411, 256, 0), + (12713, 1, 264, 2, 8202), + (12714, 1, 264, 4, 8202), + (12715, 1, 264, 6, 8202), + (12716, 1, 264, 30, 3702), + (12717, 1, 264, 60, 3702), + (12718, 1, 264, 90, 3702), + (12719, 1, 128, 10, 0), + (12719, 2, 385, 12769, 0), + (12719, 3, 411, 256, 0), + (12720, 1, 287, 1, 0), + (12720, 2, 139, 12519, 0), + (12720, 3, 411, 256, 0), + (12721, 1, 264, 60, 3506), + (12722, 1, 264, 120, 3506), + (12723, 1, 264, 180, 3506), + (12727, 1, 264, 960, 359), + (12728, 1, 264, 1200, 359), + (12729, 1, 264, 1440, 359), + (12733, 1, 287, 2, 0), + (12733, 2, 137, 22, 0), + (12733, 3, 411, 256, 0), + (12734, 1, 375, 145, 0), + (12735, 1, 375, 150, 0), + (12736, 1, 375, 155, 0), + (12737, 1, 129, 5, 0), + (12737, 2, 385, 12768, 0), + (12737, 3, 411, 256, 0), + (12738, 1, 129, 10, 0), + (12738, 2, 385, 12768, 0), + (12738, 3, 411, 256, 0), + (12739, 1, 129, 15, 0), + (12739, 2, 385, 12768, 0), + (12739, 3, 411, 256, 0), + (12757, 1, 264, 6000, 68), + (12758, 1, 264, 6600, 68), + (12759, 1, 264, 7200, 68), + (12767, 1, 229, 50, 0), + (12768, 1, 229, 55, 0), + (12769, 1, 229, 60, 0), + (12773, 1, 264, 60, 1580), + (12774, 1, 264, 120, 1580), + (12775, 1, 264, 180, 1580), + (12776, 1, 264, 240, 1580), + (12777, 1, 264, 300, 1580), + (12779, 1, 264, 0, 826), + (12780, 1, 264, 1, 826), + (12781, 1, 264, 1, 826), + (12782, 1, 129, 10, 0), + (12782, 2, 385, 16106, 0), + (12783, 1, 129, 20, 0), + (12783, 2, 385, 16106, 0), + (12784, 1, 129, 30, 0), + (12784, 2, 385, 16106, 0), + (12792, 1, 397, 1000, 0), + (12793, 1, 397, 1200, 0), + (12794, 1, 397, 1250, 0), + (12795, 1, 213, 19, 0), + (12796, 1, 213, 21, 0), + (12797, 1, 213, 23, 0), + (12798, 1, 218, 21, 0), + (12799, 1, 218, 22, 0), + (12800, 1, 218, 23, 0), + (12801, 1, 215, 18, 0), + (12802, 1, 215, 20, 0), + (12803, 1, 215, 22, 0), + (12813, 1, 320, 2, 0), + (12814, 1, 320, 4, 0), + (12815, 1, 320, 6, 0), + (12816, 1, 128, 1, 0), + (12816, 2, 385, 2223, 0), + (12816, 3, 385, 2323, 0), + (12816, 4, 385, 2240, 0), + (12816, 5, 385, 2340, 0), + (12816, 6, 385, 2440, 0), + (12816, 7, 385, 2540, 0), + (12816, 8, 398, 6000, 0), + (12816, 9, 385, 11872, 0), + (12816, 10, 385, 14154, 0), + (12816, 11, 385, 18166, 0), + (12816, 12, 385, 27225, 0), + (12816, 13, 385, 2419, 0), + (12816, 14, 385, 2427, 0), + (12816, 15, 385, 30374, 0), + (12816, 16, 385, 2527, 0), + (12816, 17, 385, 36431, 0), + (12819, 1, 310, 23400, 0), + (12819, 2, 139, 4671, 0), + (12819, 3, 411, 32768, 0), + (12820, 1, 310, 46800, 0), + (12820, 2, 139, 4671, 0), + (12820, 3, 411, 32768, 0), + (12822, 1, 310, 153000, 0), + (12822, 2, 139, 8233, 0), + (12822, 3, 310, 120000, 0), + (12822, 4, 385, 2439, 0), + (12822, 5, 385, 2539, 0), + (12822, 6, 411, 32768, 0), + (12831, 1, 127, 17, 0), + (12831, 2, 385, 3291, 0), + (12831, 3, 385, 3817, 0), + (12831, 4, 411, 32768, 0), + (12834, 1, 264, 180, 128), + (12835, 1, 264, 225, 128), + (12840, 1, 264, 24, 3817), + (12841, 1, 264, 30, 3817), + (12843, 1, 225, 42, 0), + (12846, 1, 288, 20, 28), + (12846, 2, 288, 20, 0), + (12849, 1, 127, 14, 0), + (12849, 2, 385, 16794, 0), + (12849, 3, 411, 32768, 0), + (12860, 1, 294, 21, 102), + (12863, 1, 127, 15, 15), + (12863, 2, 137, 0, 0), + (12863, 3, 138, 0, 0), + (12863, 4, 141, 1, 0), + (12863, 5, 143, 3000, 0), + (12863, 6, 127, 15, 15), + (12863, 7, 385, 16555, 0), + (12863, 8, 385, 16655, 0), + (12871, 1, 264, 2160, 452), + (12871, 2, 264, 2160, 6106), + (12871, 3, 264, 2160, 493), + (12872, 1, 264, 2520, 452), + (12872, 2, 264, 2520, 6106), + (12872, 3, 264, 2520, 493), + (12874, 1, 264, 2572, 451), + (12876, 1, 264, 900, 7003), + (12877, 1, 264, 1260, 7003), + (12878, 1, 264, 1620, 7003), + (12881, 1, 264, 45, 172), + (12886, 1, 10, 0, 0), + (12887, 1, 10, 0, 0), + (12888, 1, 10, 0, 0), + (12889, 1, 10, 0, 0), + (12890, 1, 10, 0, 0), + (12894, 1, 264, 30, 1122), + (12899, 1, 264, 3456, 57), + (12899, 2, 264, 3456, 616), + (12900, 1, 264, 4320, 57), + (12900, 2, 264, 4320, 616), + (12902, 1, 264, 30, 1380), + (12903, 1, 264, 60, 1380), + (12907, 1, 264, 30, 1381), + (12908, 1, 264, 60, 1381), + (12912, 1, 264, 30, 1382), + (12913, 1, 264, 60, 1382), + (12920, 1, 130, 10, 10), + (12920, 2, 139, 2569, 0), + (12920, 3, 130, -10, -10), + (12920, 4, 139, 2568, 0), + (12929, 1, 287, 4, 0), + (12929, 2, 137, 3, 0), + (12929, 3, 137, 99, 0), + (12929, 4, 138, 0, 0), + (12929, 5, 244, 20, 0), + (12930, 1, 287, 5, 0), + (12930, 2, 137, 3, 0), + (12930, 3, 137, 99, 0), + (12930, 4, 138, 0, 0), + (12930, 5, 244, 15, 0), + (12945, 1, 280, 60, 0), + (12946, 1, 280, 61, 0), + (12947, 1, 280, 62, 0), + (12948, 1, 280, 63, 0), + (12949, 1, 280, 64, 0), + (12950, 1, 218, 21, 0), + (12951, 1, 218, 22, 0), + (12952, 1, 218, 23, 0), + (12953, 1, 218, 24, 0), + (12954, 1, 218, 25, 0), + (12966, 1, 131, 25, 25), + (12966, 2, 348, 10, 0), + (12966, 3, 137, -32, 0), + (12967, 1, 131, 50, 50), + (12967, 2, 348, 10, 0), + (12967, 3, 137, -32, 0), + (12968, 1, 264, 3, 1041), + (12969, 1, 264, 6, 1041), + (12970, 1, 264, 9, 1041), + (12977, 1, 287, 2, 0), + (12977, 2, 385, 16188, 0), + (12978, 1, 287, 4, 0), + (12978, 2, 385, 16188, 0), + (12979, 1, 287, 6, 0), + (12979, 2, 385, 16188, 0), + (12980, 1, 287, 8, 0), + (12980, 2, 385, 16188, 0), + (12981, 1, 287, 10, 0), + (12981, 2, 385, 16188, 0), + (12988, 1, 287, 3, 0), + (12988, 2, 140, 3, 0), + (12988, 3, 348, 1, 0), + (12988, 4, 138, 0, 0), + (12988, 5, 137, 0, 0), + (13001, 1, 264, 60, 9504), + (13002, 1, 264, 120, 9504), + (13003, 1, 264, 180, 9504), + (13005, 1, 264, 70, 171), + (13006, 1, 264, 80, 171), + (13007, 1, 264, 90, 171), + (13010, 1, 264, 10, 47), + (13011, 1, 264, 20, 47), + (13012, 1, 264, 30, 47), + (13013, 1, 264, 120, 446), + (13014, 1, 264, 240, 446), + (13015, 1, 264, 360, 446), + (13017, 1, 375, 15, 0), + (13018, 1, 375, 25, 0), + (13019, 1, 375, 35, 0), + (13021, 1, 247, 80, 2), + (13021, 2, 247, 80, 3), + (13021, 3, 247, 80, 77), + (13021, 4, 220, 75, 77), + (13021, 5, 220, 75, 2), + (13021, 6, 220, 75, 3), + (13023, 1, 330, 115, 0), + (13023, 2, 330, 115, 1), + (13023, 3, 330, 115, 2), + (13023, 4, 330, 115, 3), + (13023, 5, 330, 115, 28), + (13023, 6, 330, 115, 36), + (13023, 7, 330, 115, 77), + (13026, 1, 266, 26, 0), + (13027, 1, 266, 27, 0), + (13028, 1, 266, 28, 0), + (13029, 1, 288, 250, 51), + (13029, 2, 288, 60, 51), + (13032, 1, 185, 70, 51), + (13033, 1, 185, 80, 51), + (13035, 1, 220, 768, 74), + (13040, 1, 216, 280, 74), + (13043, 1, 169, 35, -1), + (13046, 1, 1, 240, 0), + (13047, 1, 1, 280, 0), + (13048, 1, 1, 320, 0), + (13049, 1, 1, 360, 0), + (13050, 1, 1, 400, 0), + (13051, 1, 287, 2, 0), + (13051, 2, 139, 8003, 0), + (13052, 1, 310, 120000, 0), + (13052, 2, 385, 3107, 0), + (13052, 3, 385, 3207, 0), + (13052, 4, 385, 3307, 0), + (13052, 5, 385, 3407, 0), + (13052, 6, 385, 3507, 0), + (13052, 7, 385, 3607, 0), + (13055, 1, 264, 60, 8400), + (13067, 1, 264, 120, 643), + (13072, 1, 310, 120000, 0), + (13072, 2, 139, 6197, 0), + (13072, 3, 411, 512, 0), + (13073, 1, 310, 180000, 0), + (13073, 2, 139, 6197, 0), + (13073, 3, 411, 512, 0), + (13074, 1, 330, 140, 0), + (13074, 2, 330, 140, 1), + (13074, 3, 330, 140, 2), + (13074, 4, 330, 140, 3), + (13074, 5, 330, 140, 28), + (13074, 6, 330, 140, 36), + (13075, 1, 330, 145, 0), + (13075, 2, 330, 145, 1), + (13075, 3, 330, 145, 2), + (13075, 4, 330, 145, 3), + (13075, 5, 330, 145, 28), + (13075, 6, 330, 145, 36), + (13076, 1, 330, 150, 0), + (13076, 2, 330, 150, 1), + (13076, 3, 330, 150, 2), + (13076, 4, 330, 150, 3), + (13076, 5, 330, 150, 28), + (13076, 6, 330, 150, 36), + (13077, 1, 330, 140, 0), + (13077, 2, 330, 140, 1), + (13077, 3, 330, 140, 2), + (13077, 4, 330, 140, 3), + (13077, 5, 330, 140, 28), + (13077, 6, 330, 140, 36), + (13077, 7, 330, 140, 77), + (13078, 1, 330, 145, 0), + (13078, 2, 330, 145, 1), + (13078, 3, 330, 145, 2), + (13078, 4, 330, 145, 3), + (13078, 5, 330, 145, 28), + (13078, 6, 330, 145, 36), + (13078, 7, 330, 145, 77), + (13080, 1, 172, 55, 0), + (13081, 1, 172, 56, 0), + (13082, 1, 172, 57, 0), + (13083, 1, 172, 58, 0), + (13084, 1, 172, 59, 0), + (13085, 1, 259, 61, 0), + (13086, 1, 259, 62, 0), + (13087, 1, 259, 63, 0), + (13088, 1, 259, 64, 0), + (13089, 1, 259, 65, 0), + (13090, 1, 339, 10, 8105), + (13090, 2, 142, 65, 0), + (13090, 3, 311, 0, 0), + (13090, 4, 134, 70, 0), + (13090, 5, 348, 10, 0), + (13090, 6, 137, 0, 0), + (13090, 7, 339, 10, 8105), + (13090, 8, 142, 65, 0), + (13090, 9, 311, 0, 0), + (13090, 10, 134, 70, 0), + (13090, 11, 348, 10, 0), + (13090, 12, 137, 100, 0), + (13090, 13, 339, 10, 8105), + (13090, 14, 142, 65, 0), + (13090, 15, 311, 0, 0), + (13090, 16, 134, 70, 0), + (13090, 17, 348, 10, 0), + (13090, 18, 137, 79, 0), + (13090, 19, 339, 10, 8105), + (13090, 20, 142, 65, 0), + (13090, 21, 311, 0, 0), + (13090, 22, 134, 70, 0), + (13090, 23, 348, 10, 0), + (13090, 24, 137, 147, 0), + (13090, 25, 339, 10, 11404), + (13090, 26, 142, 71, 0), + (13090, 27, 311, 0, 0), + (13090, 28, 134, 75, 0), + (13090, 29, 348, 10, 0), + (13090, 30, 137, 0, 0), + (13090, 31, 339, 10, 11404), + (13090, 32, 142, 71, 0), + (13090, 33, 311, 0, 0), + (13090, 34, 134, 75, 0), + (13090, 35, 348, 10, 0), + (13090, 36, 137, 100, 0), + (13090, 37, 339, 10, 11404), + (13090, 38, 142, 71, 0), + (13090, 39, 311, 0, 0), + (13090, 40, 134, 75, 0), + (13090, 41, 348, 10, 0), + (13090, 42, 137, 79, 0), + (13090, 43, 339, 10, 11404), + (13090, 44, 142, 71, 0), + (13090, 45, 311, 0, 0), + (13090, 46, 134, 75, 0), + (13090, 47, 348, 10, 0), + (13090, 48, 137, 147, 0), + (13090, 49, 339, 10, 13199), + (13090, 50, 142, 76, 0), + (13090, 51, 311, 0, 0), + (13090, 52, 134, 80, 0), + (13090, 53, 348, 10, 0), + (13090, 54, 137, 0, 0), + (13090, 55, 339, 10, 13199), + (13090, 56, 142, 76, 0), + (13090, 57, 311, 0, 0), + (13090, 58, 134, 80, 0), + (13090, 59, 348, 10, 0), + (13090, 60, 137, 100, 0), + (13090, 61, 339, 10, 13199), + (13090, 62, 142, 76, 0), + (13090, 63, 311, 0, 0), + (13090, 64, 134, 80, 0), + (13090, 65, 348, 10, 0), + (13090, 66, 137, 79, 0), + (13090, 67, 339, 10, 13199), + (13090, 68, 142, 76, 0), + (13090, 69, 311, 0, 0), + (13090, 70, 134, 80, 0), + (13090, 71, 348, 10, 0), + (13090, 72, 137, 147, 0), + (13090, 73, 339, 10, 13830), + (13090, 74, 142, 81, 0), + (13090, 75, 311, 0, 0), + (13090, 76, 134, 85, 0), + (13090, 77, 348, 10, 0), + (13090, 78, 137, 0, 0), + (13090, 79, 339, 10, 13830), + (13090, 80, 142, 81, 0), + (13090, 81, 311, 0, 0), + (13090, 82, 134, 85, 0), + (13090, 83, 348, 10, 0), + (13090, 84, 137, 100, 0), + (13090, 85, 339, 10, 13830), + (13090, 86, 142, 81, 0), + (13090, 87, 311, 0, 0), + (13090, 88, 134, 85, 0), + (13090, 89, 348, 10, 0), + (13090, 90, 137, 79, 0), + (13090, 91, 339, 10, 13830), + (13090, 92, 142, 81, 0), + (13090, 93, 311, 0, 0), + (13090, 94, 134, 85, 0), + (13090, 95, 348, 10, 0), + (13090, 96, 137, 147, 0), + (13090, 97, 339, 10, 27527), + (13090, 98, 142, 86, 0), + (13090, 99, 311, 0, 0), + (13090, 100, 134, 90, 0), + (13090, 101, 348, 10, 0), + (13090, 102, 137, 0, 0), + (13090, 103, 339, 10, 27527), + (13090, 104, 142, 86, 0), + (13090, 105, 311, 0, 0), + (13090, 106, 134, 90, 0), + (13090, 107, 348, 10, 0), + (13090, 108, 137, 100, 0), + (13090, 109, 339, 10, 27527), + (13090, 110, 142, 86, 0), + (13090, 111, 311, 0, 0), + (13090, 112, 134, 90, 0), + (13090, 113, 348, 10, 0), + (13090, 114, 137, 79, 0), + (13090, 115, 339, 10, 27527), + (13090, 116, 142, 86, 0), + (13090, 117, 311, 0, 0), + (13090, 118, 134, 90, 0), + (13090, 119, 348, 10, 0), + (13090, 120, 137, 147, 0), + (13091, 1, 339, 10, 8105), + (13091, 2, 142, 65, 0), + (13091, 3, 311, 0, 0), + (13091, 4, 134, 70, 0), + (13091, 5, 348, 10, 0), + (13091, 6, 137, 0, 0), + (13091, 7, 339, 10, 8105), + (13091, 8, 142, 65, 0), + (13091, 9, 311, 0, 0), + (13091, 10, 134, 70, 0), + (13091, 11, 348, 10, 0), + (13091, 12, 137, 100, 0), + (13091, 13, 339, 10, 8105), + (13091, 14, 142, 65, 0), + (13091, 15, 311, 0, 0), + (13091, 16, 134, 70, 0), + (13091, 17, 348, 10, 0), + (13091, 18, 137, 79, 0), + (13091, 19, 339, 10, 8105), + (13091, 20, 142, 65, 0), + (13091, 21, 311, 0, 0), + (13091, 22, 134, 70, 0), + (13091, 23, 348, 10, 0), + (13091, 24, 137, 147, 0), + (13091, 25, 339, 10, 11404), + (13091, 26, 142, 71, 0), + (13091, 27, 311, 0, 0), + (13091, 28, 134, 75, 0), + (13091, 29, 348, 10, 0), + (13091, 30, 137, 0, 0), + (13091, 31, 339, 10, 11404), + (13091, 32, 142, 71, 0), + (13091, 33, 311, 0, 0), + (13091, 34, 134, 75, 0), + (13091, 35, 348, 10, 0), + (13091, 36, 137, 100, 0), + (13091, 37, 339, 10, 11404), + (13091, 38, 142, 71, 0), + (13091, 39, 311, 0, 0), + (13091, 40, 134, 75, 0), + (13091, 41, 348, 10, 0), + (13091, 42, 137, 79, 0), + (13091, 43, 339, 10, 11404), + (13091, 44, 142, 71, 0), + (13091, 45, 311, 0, 0), + (13091, 46, 134, 75, 0), + (13091, 47, 348, 10, 0), + (13091, 48, 137, 147, 0), + (13091, 49, 339, 10, 13199), + (13091, 50, 142, 76, 0), + (13091, 51, 311, 0, 0), + (13091, 52, 134, 80, 0), + (13091, 53, 348, 10, 0), + (13091, 54, 137, 0, 0), + (13091, 55, 339, 10, 13199), + (13091, 56, 142, 76, 0), + (13091, 57, 311, 0, 0), + (13091, 58, 134, 80, 0), + (13091, 59, 348, 10, 0), + (13091, 60, 137, 100, 0), + (13091, 61, 339, 10, 13199), + (13091, 62, 142, 76, 0), + (13091, 63, 311, 0, 0), + (13091, 64, 134, 80, 0), + (13091, 65, 348, 10, 0), + (13091, 66, 137, 79, 0), + (13091, 67, 339, 10, 13199), + (13091, 68, 142, 76, 0), + (13091, 69, 311, 0, 0), + (13091, 70, 134, 80, 0), + (13091, 71, 348, 10, 0), + (13091, 72, 137, 147, 0), + (13091, 73, 339, 10, 13830), + (13091, 74, 142, 81, 0), + (13091, 75, 311, 0, 0), + (13091, 76, 134, 85, 0), + (13091, 77, 348, 10, 0), + (13091, 78, 137, 0, 0), + (13091, 79, 339, 10, 13830), + (13091, 80, 142, 81, 0), + (13091, 81, 311, 0, 0), + (13091, 82, 134, 85, 0), + (13091, 83, 348, 10, 0), + (13091, 84, 137, 100, 0), + (13091, 85, 339, 10, 13830), + (13091, 86, 142, 81, 0), + (13091, 87, 311, 0, 0), + (13091, 88, 134, 85, 0), + (13091, 89, 348, 10, 0), + (13091, 90, 137, 79, 0), + (13091, 91, 339, 10, 13830), + (13091, 92, 142, 81, 0), + (13091, 93, 311, 0, 0), + (13091, 94, 134, 85, 0), + (13091, 95, 348, 10, 0), + (13091, 96, 137, 147, 0), + (13091, 97, 339, 10, 27527), + (13091, 98, 142, 86, 0), + (13091, 99, 311, 0, 0), + (13091, 100, 134, 90, 0), + (13091, 101, 348, 10, 0), + (13091, 102, 137, 0, 0), + (13091, 103, 339, 10, 27527), + (13091, 104, 142, 86, 0), + (13091, 105, 311, 0, 0), + (13091, 106, 134, 90, 0), + (13091, 107, 348, 10, 0), + (13091, 108, 137, 100, 0), + (13091, 109, 339, 10, 27527), + (13091, 110, 142, 86, 0), + (13091, 111, 311, 0, 0), + (13091, 112, 134, 90, 0), + (13091, 113, 348, 10, 0), + (13091, 114, 137, 79, 0), + (13091, 115, 339, 10, 27527), + (13091, 116, 142, 86, 0), + (13091, 117, 311, 0, 0), + (13091, 118, 134, 90, 0), + (13091, 119, 348, 10, 0), + (13091, 120, 137, 147, 0), + (13092, 1, 217, 0, 102280), + (13092, 2, 346, 84, 18), + (13093, 1, 217, 0, 109400), + (13093, 2, 346, 86, 18), + (13094, 1, 217, 0, 116800), + (13094, 2, 346, 88, 18), + (13095, 1, 439, 0, 140680), + (13095, 2, 345, 88, 25), + (13096, 1, 287, 1, 0), + (13096, 2, 140, 3, 0), + (13096, 3, 348, 1, 0), + (13096, 4, 138, 0, 0), + (13096, 5, 137, 0, 0), + (13097, 1, 287, 2, 0), + (13097, 2, 140, 3, 0), + (13097, 3, 348, 1, 0), + (13097, 4, 138, 0, 0), + (13097, 5, 137, 0, 0), + (13098, 1, 287, 3, 0), + (13098, 2, 140, 3, 0), + (13098, 3, 348, 1, 0), + (13098, 4, 138, 0, 0), + (13098, 5, 137, 0, 0), + (13099, 1, 132, 15, 15), + (13101, 1, 360, 25, 27537), + (13102, 1, 360, 25, 27538), + (13103, 1, 360, 25, 27539), + (13104, 1, 303, 14000, 18000), + (13104, 2, 139, 2766, 0), + (13105, 1, 303, 18000, 22500), + (13105, 2, 139, 2766, 0), + (13106, 1, 303, 22500, 27500), + (13106, 2, 139, 2766, 0), + (13110, 1, 185, 8, 1), + (13110, 2, 185, 8, 3), + (13111, 1, 185, 10, 1), + (13111, 2, 185, 10, 3), + (13113, 1, 185, 7, 36), + (13114, 1, 185, 9, 36), + (13116, 1, 185, 8, 0), + (13116, 2, 185, 8, 2), + (13117, 1, 185, 10, 0), + (13117, 2, 185, 10, 2), + (13122, 1, 2, 128, 0), + (13123, 1, 2, 132, 0), + (13124, 1, 2, 136, 0), + (13127, 1, 287, 4, 0), + (13127, 2, 140, 3, 0), + (13127, 3, 348, 1, 0), + (13127, 4, 138, 0, 0), + (13127, 5, 137, 0, 0), + (13130, 1, 264, 1440, 7003), + (13140, 1, 264, 480, 391), + (13141, 1, 264, 600, 391), + (13142, 1, 264, 720, 391), + (13143, 1, 127, 17, 0), + (13143, 2, 385, 8054, 0), + (13144, 1, 127, 34, 0), + (13144, 2, 385, 8054, 0), + (13145, 1, 127, 50, 0), + (13145, 2, 385, 8054, 0), + (13146, 1, 127, 17, 0), + (13146, 2, 385, 8054, 0), + (13147, 1, 127, 34, 0), + (13147, 2, 385, 8054, 0), + (13148, 1, 127, 50, 0), + (13148, 2, 385, 8054, 0), + (13149, 1, 97, 550, 0), + (13150, 1, 97, 600, 0), + (13151, 1, 97, 650, 0), + (13152, 1, 97, 700, 0), + (13153, 1, 97, 750, 0), + (13166, 1, 264, 5, 749), + (13166, 2, 264, 5, 822), + (13166, 3, 264, 5, 1274), + (13166, 4, 264, 5, 1275), + (13167, 1, 264, 10, 749), + (13167, 2, 264, 10, 822), + (13167, 3, 264, 10, 1274), + (13167, 4, 264, 10, 1275), + (13168, 1, 264, 15, 749), + (13168, 2, 264, 15, 822), + (13168, 3, 264, 15, 1274), + (13168, 4, 264, 15, 1275), + (13184, 1, 220, 315, 26), + (13185, 1, 220, 400, 26), + (13186, 1, 220, 500, 26), + (13187, 1, 405, 19, 0), + (13188, 1, 405, 21, 0), + (13189, 1, 405, 23, 0), + (13196, 1, 279, 31, 0), + (13197, 1, 279, 35, 0), + (13198, 1, 279, 39, 0), + (13199, 1, 378, 30, 31), + (13200, 1, 378, 35, 31), + (13201, 1, 378, 40, 31), + (13204, 1, 264, 180, 8261), + (13205, 1, 264, 360, 8261), + (13206, 1, 264, 540, 8261), + (13207, 1, 288, 100, 8), + (13208, 1, 288, 100, 8), + (13209, 1, 288, 100, 8), + (13210, 1, 325, 70, 0), + (13211, 1, 325, 75, 0), + (13212, 1, 325, 80, 0), + (13213, 1, 220, 285, 8), + (13214, 1, 220, 315, 8), + (13215, 1, 220, 350, 8), + (13216, 1, 220, 390, 8), + (13217, 1, 220, 440, 8), + (13218, 1, 216, 750, 8), + (13219, 1, 114, -12, 0), + (13220, 1, 114, -15, 0), + (13221, 1, 114, -18, 0), + (13222, 1, 310, 240000, 0), + (13222, 2, 139, 6197, 0), + (13222, 3, 411, 512, 0), + (13223, 1, 310, 300000, 0), + (13223, 2, 139, 6197, 0), + (13223, 3, 411, 512, 0), + (13226, 1, 360, 60, 27593), + (13238, 1, 320, 9, 0), + (13239, 1, 320, 10, 0), + (13240, 1, 320, 11, 0), + (13262, 1, 264, 1008, 102), + (13263, 1, 264, 1152, 102), + (13264, 1, 264, 1290, 102), + (13278, 1, 213, 25, 0), + (13281, 1, 318, 31, 0), + (13286, 1, 278, 900, 102200), + (13286, 2, 440, 92, 100), + (13294, 1, 339, 10, 8105), + (13294, 2, 142, 65, 0), + (13294, 3, 311, 0, 0), + (13294, 4, 134, 70, 0), + (13294, 5, 348, 10, 0), + (13294, 6, 137, 0, 0), + (13294, 7, 339, 10, 8105), + (13294, 8, 142, 65, 0), + (13294, 9, 311, 0, 0), + (13294, 10, 134, 70, 0), + (13294, 11, 348, 10, 0), + (13294, 12, 137, 100, 0), + (13294, 13, 339, 10, 8105), + (13294, 14, 142, 65, 0), + (13294, 15, 311, 0, 0), + (13294, 16, 134, 70, 0), + (13294, 17, 348, 10, 0), + (13294, 18, 137, 79, 0), + (13294, 19, 339, 10, 8105), + (13294, 20, 142, 65, 0), + (13294, 21, 311, 0, 0), + (13294, 22, 134, 70, 0), + (13294, 23, 348, 10, 0), + (13294, 24, 137, 147, 0), + (13294, 25, 339, 10, 11404), + (13294, 26, 142, 71, 0), + (13294, 27, 311, 0, 0), + (13294, 28, 134, 75, 0), + (13294, 29, 348, 10, 0), + (13294, 30, 137, 0, 0), + (13294, 31, 339, 10, 11404), + (13294, 32, 142, 71, 0), + (13294, 33, 311, 0, 0), + (13294, 34, 134, 75, 0), + (13294, 35, 348, 10, 0), + (13294, 36, 137, 100, 0), + (13294, 37, 339, 10, 11404), + (13294, 38, 142, 71, 0), + (13294, 39, 311, 0, 0), + (13294, 40, 134, 75, 0), + (13294, 41, 348, 10, 0), + (13294, 42, 137, 79, 0), + (13294, 43, 339, 10, 11404), + (13294, 44, 142, 71, 0), + (13294, 45, 311, 0, 0), + (13294, 46, 134, 75, 0), + (13294, 47, 348, 10, 0), + (13294, 48, 137, 147, 0), + (13294, 49, 339, 10, 13199), + (13294, 50, 142, 76, 0), + (13294, 51, 311, 0, 0), + (13294, 52, 134, 80, 0), + (13294, 53, 348, 10, 0), + (13294, 54, 137, 0, 0), + (13294, 55, 339, 10, 13199), + (13294, 56, 142, 76, 0), + (13294, 57, 311, 0, 0), + (13294, 58, 134, 80, 0), + (13294, 59, 348, 10, 0), + (13294, 60, 137, 100, 0), + (13294, 61, 339, 10, 13199), + (13294, 62, 142, 76, 0), + (13294, 63, 311, 0, 0), + (13294, 64, 134, 80, 0), + (13294, 65, 348, 10, 0), + (13294, 66, 137, 79, 0), + (13294, 67, 339, 10, 13199), + (13294, 68, 142, 76, 0), + (13294, 69, 311, 0, 0), + (13294, 70, 134, 80, 0), + (13294, 71, 348, 10, 0), + (13294, 72, 137, 147, 0), + (13294, 73, 339, 10, 13830), + (13294, 74, 142, 81, 0), + (13294, 75, 311, 0, 0), + (13294, 76, 134, 85, 0), + (13294, 77, 348, 10, 0), + (13294, 78, 137, 0, 0), + (13294, 79, 339, 10, 13830), + (13294, 80, 142, 81, 0), + (13294, 81, 311, 0, 0), + (13294, 82, 134, 85, 0), + (13294, 83, 348, 10, 0), + (13294, 84, 137, 100, 0), + (13294, 85, 339, 10, 13830), + (13294, 86, 142, 81, 0), + (13294, 87, 311, 0, 0), + (13294, 88, 134, 85, 0), + (13294, 89, 348, 10, 0), + (13294, 90, 137, 79, 0), + (13294, 91, 339, 10, 13830), + (13294, 92, 142, 81, 0), + (13294, 93, 311, 0, 0), + (13294, 94, 134, 85, 0), + (13294, 95, 348, 10, 0), + (13294, 96, 137, 147, 0), + (13294, 97, 339, 10, 27527), + (13294, 98, 142, 86, 0), + (13294, 99, 311, 0, 0), + (13294, 100, 134, 90, 0), + (13294, 101, 348, 10, 0), + (13294, 102, 137, 0, 0), + (13294, 103, 339, 10, 27527), + (13294, 104, 142, 86, 0), + (13294, 105, 311, 0, 0), + (13294, 106, 134, 90, 0), + (13294, 107, 348, 10, 0), + (13294, 108, 137, 100, 0), + (13294, 109, 339, 10, 27527), + (13294, 110, 142, 86, 0), + (13294, 111, 311, 0, 0), + (13294, 112, 134, 90, 0), + (13294, 113, 348, 10, 0), + (13294, 114, 137, 79, 0), + (13294, 115, 339, 10, 27527), + (13294, 116, 142, 86, 0), + (13294, 117, 311, 0, 0), + (13294, 118, 134, 90, 0), + (13294, 119, 348, 10, 0), + (13294, 120, 137, 147, 0), + (13294, 121, 339, 10, 30644), + (13294, 122, 142, 91, 0), + (13294, 123, 311, 0, 0), + (13294, 124, 134, 95, 0), + (13294, 125, 348, 10, 0), + (13294, 126, 137, 0, 0), + (13294, 127, 339, 10, 30644), + (13294, 128, 142, 91, 0), + (13294, 129, 311, 0, 0), + (13294, 130, 134, 95, 0), + (13294, 131, 348, 10, 0), + (13294, 132, 137, 100, 0), + (13294, 133, 339, 10, 30644), + (13294, 134, 142, 91, 0), + (13294, 135, 311, 0, 0), + (13294, 136, 134, 95, 0), + (13294, 137, 348, 10, 0), + (13294, 138, 137, 79, 0), + (13294, 139, 339, 10, 30644), + (13294, 140, 142, 91, 0), + (13294, 141, 311, 0, 0), + (13294, 142, 134, 95, 0), + (13294, 143, 348, 10, 0), + (13294, 144, 137, 147, 0), + (13295, 1, 339, 10, 8105), + (13295, 2, 142, 65, 0), + (13295, 3, 311, 0, 0), + (13295, 4, 134, 70, 0), + (13295, 5, 348, 10, 0), + (13295, 6, 137, 0, 0), + (13295, 7, 339, 10, 8105), + (13295, 8, 142, 65, 0), + (13295, 9, 311, 0, 0), + (13295, 10, 134, 70, 0), + (13295, 11, 348, 10, 0), + (13295, 12, 137, 100, 0), + (13295, 13, 339, 10, 8105), + (13295, 14, 142, 65, 0), + (13295, 15, 311, 0, 0), + (13295, 16, 134, 70, 0), + (13295, 17, 348, 10, 0), + (13295, 18, 137, 79, 0), + (13295, 19, 339, 10, 8105), + (13295, 20, 142, 65, 0), + (13295, 21, 311, 0, 0), + (13295, 22, 134, 70, 0), + (13295, 23, 348, 10, 0), + (13295, 24, 137, 147, 0), + (13295, 25, 339, 10, 11404), + (13295, 26, 142, 71, 0), + (13295, 27, 311, 0, 0), + (13295, 28, 134, 75, 0), + (13295, 29, 348, 10, 0), + (13295, 30, 137, 0, 0), + (13295, 31, 339, 10, 11404), + (13295, 32, 142, 71, 0), + (13295, 33, 311, 0, 0), + (13295, 34, 134, 75, 0), + (13295, 35, 348, 10, 0), + (13295, 36, 137, 100, 0), + (13295, 37, 339, 10, 11404), + (13295, 38, 142, 71, 0), + (13295, 39, 311, 0, 0), + (13295, 40, 134, 75, 0), + (13295, 41, 348, 10, 0), + (13295, 42, 137, 79, 0), + (13295, 43, 339, 10, 11404), + (13295, 44, 142, 71, 0), + (13295, 45, 311, 0, 0), + (13295, 46, 134, 75, 0), + (13295, 47, 348, 10, 0), + (13295, 48, 137, 147, 0), + (13295, 49, 339, 10, 13199), + (13295, 50, 142, 76, 0), + (13295, 51, 311, 0, 0), + (13295, 52, 134, 80, 0), + (13295, 53, 348, 10, 0), + (13295, 54, 137, 0, 0), + (13295, 55, 339, 10, 13199), + (13295, 56, 142, 76, 0), + (13295, 57, 311, 0, 0), + (13295, 58, 134, 80, 0), + (13295, 59, 348, 10, 0), + (13295, 60, 137, 100, 0), + (13295, 61, 339, 10, 13199), + (13295, 62, 142, 76, 0), + (13295, 63, 311, 0, 0), + (13295, 64, 134, 80, 0), + (13295, 65, 348, 10, 0), + (13295, 66, 137, 79, 0), + (13295, 67, 339, 10, 13199), + (13295, 68, 142, 76, 0), + (13295, 69, 311, 0, 0), + (13295, 70, 134, 80, 0), + (13295, 71, 348, 10, 0), + (13295, 72, 137, 147, 0), + (13295, 73, 339, 10, 13830), + (13295, 74, 142, 81, 0), + (13295, 75, 311, 0, 0), + (13295, 76, 134, 85, 0), + (13295, 77, 348, 10, 0), + (13295, 78, 137, 0, 0), + (13295, 79, 339, 10, 13830), + (13295, 80, 142, 81, 0), + (13295, 81, 311, 0, 0), + (13295, 82, 134, 85, 0), + (13295, 83, 348, 10, 0), + (13295, 84, 137, 100, 0), + (13295, 85, 339, 10, 13830), + (13295, 86, 142, 81, 0), + (13295, 87, 311, 0, 0), + (13295, 88, 134, 85, 0), + (13295, 89, 348, 10, 0), + (13295, 90, 137, 79, 0), + (13295, 91, 339, 10, 13830), + (13295, 92, 142, 81, 0), + (13295, 93, 311, 0, 0), + (13295, 94, 134, 85, 0), + (13295, 95, 348, 10, 0), + (13295, 96, 137, 147, 0), + (13295, 97, 339, 10, 27527), + (13295, 98, 142, 86, 0), + (13295, 99, 311, 0, 0), + (13295, 100, 134, 90, 0), + (13295, 101, 348, 10, 0), + (13295, 102, 137, 0, 0), + (13295, 103, 339, 10, 27527), + (13295, 104, 142, 86, 0), + (13295, 105, 311, 0, 0), + (13295, 106, 134, 90, 0), + (13295, 107, 348, 10, 0), + (13295, 108, 137, 100, 0), + (13295, 109, 339, 10, 27527), + (13295, 110, 142, 86, 0), + (13295, 111, 311, 0, 0), + (13295, 112, 134, 90, 0), + (13295, 113, 348, 10, 0), + (13295, 114, 137, 79, 0), + (13295, 115, 339, 10, 27527), + (13295, 116, 142, 86, 0), + (13295, 117, 311, 0, 0), + (13295, 118, 134, 90, 0), + (13295, 119, 348, 10, 0), + (13295, 120, 137, 147, 0), + (13295, 121, 339, 10, 30644), + (13295, 122, 142, 91, 0), + (13295, 123, 311, 0, 0), + (13295, 124, 134, 95, 0), + (13295, 125, 348, 10, 0), + (13295, 126, 137, 0, 0), + (13295, 127, 339, 10, 30644), + (13295, 128, 142, 91, 0), + (13295, 129, 311, 0, 0), + (13295, 130, 134, 95, 0), + (13295, 131, 348, 10, 0), + (13295, 132, 137, 100, 0), + (13295, 133, 339, 10, 30644), + (13295, 134, 142, 91, 0), + (13295, 135, 311, 0, 0), + (13295, 136, 134, 95, 0), + (13295, 137, 348, 10, 0), + (13295, 138, 137, 79, 0), + (13295, 139, 339, 10, 30644), + (13295, 140, 142, 91, 0), + (13295, 141, 311, 0, 0), + (13295, 142, 134, 95, 0), + (13295, 143, 348, 10, 0), + (13295, 144, 137, 147, 0), + (13296, 1, 125, 49, 49), + (13296, 2, 137, 0, 0), + (13296, 3, 141, 1, 0), + (13296, 4, 139, -6233, 0), + (13296, 5, 139, -6265, 0), + (13296, 6, 125, 49, 49), + (13296, 7, 137, 147, 0), + (13296, 8, 141, 1, 0), + (13297, 1, 125, 52, 52), + (13297, 2, 137, 0, 0), + (13297, 3, 141, 1, 0), + (13297, 4, 139, -6233, 0), + (13297, 5, 139, -6265, 0), + (13297, 6, 125, 52, 52), + (13297, 7, 137, 147, 0), + (13297, 8, 141, 1, 0), + (13299, 1, 319, 31, 0), + (13302, 1, 274, 44, 0), + (13305, 1, 189, 19, 0), + (13308, 1, 265, 87, 0), + (13313, 1, 15, 29, 0), + (13318, 1, 97, 850, 0), + (13323, 1, 320, 15, 0), + (13326, 1, 330, 155, 0), + (13326, 2, 330, 155, 1), + (13326, 3, 330, 155, 2), + (13326, 4, 330, 155, 3), + (13326, 5, 330, 155, 28), + (13326, 6, 330, 155, 36), + (13332, 1, 330, 155, 0), + (13332, 2, 330, 155, 1), + (13332, 3, 330, 155, 2), + (13332, 4, 330, 155, 3), + (13332, 5, 330, 155, 28), + (13332, 6, 330, 155, 36), + (13332, 7, 330, 155, 77), + (13338, 1, 1, 370, 0), + (13343, 1, 1, 340, 0), + (13348, 1, 1, 440, 0), + (13353, 1, 1, 330, 0), + (13358, 1, 1, 540, 0), + (13396, 1, 375, 40, 0), + (13404, 1, 273, 8, 0), + (13411, 1, 399, 4, 0), + (13411, 2, 138, 1, 0), + (13411, 3, 137, 0, 0), + (13411, 4, 348, 10, 0), + (13411, 5, 311, 0, 0), + (13411, 6, 141, 1, 0), + (13411, 7, 134, 254, 0), + (13411, 8, 137, -39, 0), + (13413, 1, 399, 12, 0), + (13413, 2, 141, 1, 0), + (13413, 3, 138, 0, 0), + (13413, 4, 142, 255, 0), + (13413, 5, 391, 0, 0), + (13413, 6, 311, 0, 0), + (13413, 7, 137, -152, 0), + (13413, 8, 411, 100350, 0), + (13413, 9, 137, -39, 0), + (13415, 1, 264, 150, 705), + (13415, 2, 264, 150, 1092), + (13415, 3, 264, 150, 10396), + (13415, 4, 264, 150, 10397), + (13416, 1, 264, 20, 626), + (13438, 1, 266, 29, 0), + (13449, 1, 264, 2, 11073), + (13463, 1, 264, 90, 458), + (13474, 1, 264, 120, 444), + (13477, 1, 126, 20, 0), + (13477, 2, 134, 95, 0), + (13477, 3, 135, 4, 0), + (13477, 4, 135, 5, 0), + (13485, 1, 279, 3, 0), + (13502, 1, 375, 160, 0), + (13508, 1, 378, 5, 3), + (13511, 1, 279, 43, 0), + (13520, 1, 292, 70, 0), + (13521, 1, 293, 25, 0), + (13533, 1, 378, 55, 96), + (13545, 1, 323, 30787, 0), + (13562, 1, 264, 480, 872), + (13565, 1, 264, 60, 3804), + (13568, 1, 264, 60, 876), + (13578, 1, 244, 30, 0), + (13589, 1, 279, 34, 0), + (13590, 1, 279, 38, 0), + (13598, 1, 339, 20, 30809), + (13598, 2, 137, 21, 0), + (13598, 3, 385, -18000, 0), + (13598, 4, 339, 20, 30809), + (13598, 5, 137, 343, 0), + (13598, 6, 385, -18000, 0), + (13601, 1, 231, 22, 0), + (13607, 1, 126, 4, 4), + (13607, 2, 137, 21, 0), + (13607, 3, 231, 4, 4), + (13610, 1, 266, 47, 0), + (13613, 1, 220, 260, 10), + (13616, 1, 220, 150, 2), + (13616, 2, 220, 150, 3), + (13616, 3, 220, 150, 77), + (13617, 1, 220, 375, 2), + (13617, 2, 220, 375, 3), + (13617, 3, 220, 375, 77), + (13618, 1, 220, 500, 2), + (13618, 2, 220, 500, 3), + (13618, 3, 220, 500, 77), + (13621, 1, 218, 11, 0), + (13627, 1, 59, -59, 0), + (13628, 1, 59, -64, 0), + (13630, 1, 398, 10000, 0), + (13630, 2, 137, 152, 0), + (13667, 1, 287, 1, 0), + (13667, 2, 385, 8054, 0), + (13675, 1, 218, 24, 0), + (13684, 1, 399, 2, 0), + (13684, 2, 140, 2, 0), + (13684, 3, 348, 10, 0), + (13684, 4, 138, 0, 0), + (13684, 5, 137, -152, 0), + (13684, 6, 137, -39, 0), + (13685, 1, 399, 3, 0), + (13685, 2, 140, 2, 0), + (13685, 3, 348, 10, 0), + (13685, 4, 138, 0, 0), + (13685, 5, 137, -152, 0), + (13685, 6, 137, -39, 0), + (13686, 1, 399, 4, 0), + (13686, 2, 140, 2, 0), + (13686, 3, 348, 10, 0), + (13686, 4, 138, 0, 0), + (13686, 5, 137, -152, 0), + (13686, 6, 137, -39, 0), + (13689, 1, 127, 10, 0), + (13689, 2, 139, 27592, 0), + (13689, 3, 139, 31548, 0), + (13707, 1, 274, 26, 0), + (13710, 1, 280, 65, 0), + (13713, 1, 218, 26, 0), + (13753, 1, 264, 360, 534), + (13758, 1, 264, 360, 602), + (13763, 1, 287, 4, 0), + (13763, 2, 137, 31, 0), + (13763, 3, 136, 5, 0), + (13764, 1, 264, 60, 535), + (13767, 1, 439, 0, 153514), + (13767, 2, 345, 90, 22), + (13773, 1, 279, 21, 0), + (13774, 1, 279, 23, 0), + (13775, 1, 279, 25, 0), + (13779, 1, 288, 100, 8), + (13782, 1, 220, 490, 8), + (13789, 1, 216, 850, 8), + (13790, 1, 216, 950, 8), + (13795, 1, 258, 73, 0), + (13798, 1, 114, -21, 0), + (13804, 1, 378, 4, 3), + (13813, 1, 220, 150, 28), + (13813, 2, 220, 150, 0), + (13813, 3, 427, 23598, 9), + (13813, 4, 428, 28, 0), + (13813, 5, 428, 0, 0), + (13820, 1, 220, 325, 26), + (13820, 2, 220, 325, 30), + (13820, 3, 220, 325, 38), + (13823, 1, 220, 295, 21), + (13823, 2, 220, 295, 23), + (13823, 3, 220, 670, 52), + (13823, 4, 220, 295, 28), + (13826, 1, 405, 25, 0), + (13829, 1, 220, 550, 26), + (13835, 1, 283, 300, 0), + (13841, 1, 264, 17, 469), + (13873, 1, 264, 30, 961), + (13878, 1, 264, 60, 609), + (13881, 1, 264, 60, 387), + (13884, 1, 265, 87, 0), + (13889, 1, 264, 60, 1012), + (13894, 1, 327, 13, 0), + (13905, 1, 310, 24000, 0), + (13905, 2, 385, 15319, 0), + (13908, 1, 310, 3000, 0), + (13908, 2, 385, 15307, 0), + (13908, 3, 385, 15407, 0), + (13908, 4, 385, 15507, 0), + (13908, 5, 385, 15607, 0), + (13911, 1, 310, 3000, 0), + (13911, 2, 385, 16005, 0), + (13911, 3, 310, 3000, 0), + (13911, 4, 385, 15405, 0), + (13911, 5, 385, 15505, 0), + (13911, 6, 385, 15605, 0), + (13911, 7, 411, 2, 0), + (13917, 1, 264, 120, 606), + (13921, 1, 114, -66, 0), + (13924, 1, 114, -64, 0), + (13927, 1, 114, -25, 0), + (13930, 1, 341, 310, 0), + (13933, 1, 262, 80, 0), + (13943, 1, 262, 80, 1), + (13953, 1, 262, 80, 2), + (13963, 1, 262, 80, 3), + (13973, 1, 262, 80, 4), + (13983, 1, 262, 80, 5), + (13993, 1, 262, 80, 6), + (14011, 1, 264, 30, 10394), + (14017, 1, 69, 10, 0), + (14018, 1, 69, 10, 0), + (14026, 1, 185, 3, 2), + (14026, 2, 185, 3, 3), + (14026, 3, 185, 3, 77), + (14026, 4, 220, 50, 2), + (14026, 5, 220, 50, 3), + (14026, 6, 220, 50, 77), + (14029, 1, 395, 5, 5), + (14029, 2, 385, 9758, 0), + (14029, 3, 385, 9858, 0), + (14029, 4, 385, 9958, 0), + (14032, 1, 181, 100, 0), + (14037, 1, 264, 180, 804), + (14040, 1, 264, 180, 300), + (14043, 1, 85, 32197, 0), + (14046, 1, 264, 90, 87), + (14056, 1, 310, 360000, 0), + (14056, 2, 139, 4504, 0), + (14059, 1, 310, -180000, 0), + (14059, 2, 139, 4520, 0), + (14062, 1, 264, 60, 821), + (14065, 1, 264, 60, 3215), + (14068, 1, 264, 60, 3216), + (14076, 1, 310, 480000, 0), + (14076, 2, 139, 4518, 0), + (14082, 1, 360, 26, 32314), + (14085, 1, 264, 2, 741), + (14088, 1, 264, 30, 769), + (14091, 1, 264, 120, 701), + (14094, 1, 124, 325, 350), + (14094, 2, 385, 19, 0), + (14094, 3, 144, 0, 0), + (14094, 4, 403, 3, 0), + (14094, 5, 404, 48, 0), + (14094, 6, 385, -21768, 0), + (14097, 1, 85, 32317, 5), + (14100, 1, 127, 50, 0), + (14100, 2, 137, 21, 0), + (14100, 3, 143, 1, 0), + (14100, 4, 134, 253, 0), + (14100, 5, 348, 1, 0), + (14101, 1, 310, 2520000, 0), + (14101, 2, 139, 4506, 0), + (14101, 3, 310, 2520000, 0), + (14101, 4, 385, 11122, 0), + (14101, 5, 385, 11222, 0), + (14101, 6, 385, 11322, 0), + (14101, 7, 385, 11522, 0), + (14115, 1, 287, 1, 0), + (14115, 2, 385, 16130, 0), + (14129, 1, 220, 60, 36), + (14129, 2, 427, 32327, 3), + (14129, 3, 428, 36, 0), + (14130, 1, 220, 90, 36), + (14130, 2, 427, 32327, 5), + (14130, 3, 428, 36, 0), + (14132, 1, 264, 240, 2234), + (14135, 1, 310, 132000, 0), + (14135, 2, 385, 13005, 0), + (14135, 3, 385, 12423, 0), + (14135, 4, 385, 12504, 0), + (14135, 5, 310, 132000, 0), + (14135, 6, 139, 4676, 0), + (14135, 7, 411, 512, 0), + (14138, 1, 310, 480000, 0), + (14138, 2, 139, 4695, 0), + (14138, 3, 411, 512, 0), + (14140, 1, 310, 24000, 0), + (14140, 2, 385, 13007, 0), + (14140, 3, 385, 12105, 0), + (14140, 4, 385, 12205, 0), + (14140, 5, 310, 72000, 0), + (14140, 6, 385, 12305, 0), + (14140, 7, 385, 12405, 0), + (14140, 8, 385, 12505, 0), + (14140, 9, 411, 512, 0), + (14141, 1, 185, 2, 36), + (14144, 1, 287, 1, 0), + (14144, 2, 385, 13204, 0), + (14144, 3, 411, 512, 0), + (14148, 1, 310, 90000, 0), + (14148, 2, 139, 4691, 0), + (14151, 1, 185, 2, 26), + (14151, 2, 220, 100, 26), + (14154, 1, 264, 2100, 276), + (14157, 1, 216, 150, 26), + (14160, 1, 264, 60, 7001), + (14163, 1, 287, 1, 0), + (14163, 2, 385, 16178, 0), + (14163, 3, 411, 128, 0), + (14166, 1, 264, 60, 945), + (14169, 1, 310, 202500, 0), + (14169, 2, 139, 8030, 0), + (14169, 3, 411, 256, 0), + (14173, 1, 310, 1440000, 0), + (14173, 2, 139, 4516, 0), + (14173, 3, 411, 256, 0), + (14176, 1, 264, 660, 8261), + (14179, 1, 287, 1, 0), + (14179, 2, 385, 5830, 0), + (14179, 3, 411, 256, 0), + (14180, 1, 287, 1, 0), + (14180, 2, 139, 8030, 0), + (14180, 3, 411, 256, 0), + (14181, 1, 247, 25, 20), + (14186, 1, 247, 25, 76), + (14196, 1, 264, 2340, 465), + (14199, 1, 264, 720, 499), + (14200, 1, 288, 15, 2), + (14200, 2, 288, 15, 3), + (14200, 3, 288, 15, 51), + (14200, 4, 288, 15, 77), + (14203, 1, 310, 150000, 0), + (14203, 2, 385, 3419, 0), + (14203, 3, 385, 14005, 0), + (14203, 4, 385, 3519, 0), + (14203, 5, 411, 65536, 0), + (14210, 1, 310, 40000, 0), + (14210, 2, 139, 1546, 0), + (14210, 3, 310, 40000, 0), + (14210, 4, 385, 4357, 0), + (14210, 5, 385, 4457, 0), + (14210, 6, 385, 4557, 0), + (14210, 7, 385, 4657, 0), + (14210, 8, 411, 4, 0), + (14213, 1, 264, 120, 1065), + (14218, 1, 232, 23, 4544), + (14223, 1, 264, 40, 47), + (14225, 1, 127, 16, 0), + (14225, 2, 385, 3283, 0), + (14225, 3, 411, 1024, 0), + (14238, 1, 264, 12, 1041), + (14241, 1, 264, 180, 386), + (14244, 1, 286, 100, 0), + (14244, 2, 138, 0, 0), + (14244, 3, 143, 1, 0), + (14244, 4, 348, 1, 0), + (14244, 5, 411, 64, 0), + (14249, 1, 392, 200, 0), + (14249, 2, 138, 1, 0), + (14249, 3, 348, 1, 0), + (14254, 1, 287, 1, 0), + (14254, 2, 385, 2025, 0), + (14254, 3, 385, 5121, 0), + (14254, 4, 385, 5221, 0), + (14254, 5, 385, 5562, 0), + (14259, 1, 287, 1, 0), + (14259, 2, 139, 23585, 0), + (14275, 1, 239, 20, 0), + (14278, 1, 287, 4, 0), + (14278, 2, 385, 16439, 0), + (14278, 3, 411, 32768, 0), + (14279, 1, 320, 8, 0), + (14283, 1, 127, 17, 0), + (14283, 2, 385, 3151, 0), + (14283, 3, 385, 5887, 0), + (14286, 1, 287, 1, 0), + (14286, 2, 385, 4877, 0), + (14289, 1, 127, 10, 0), + (14289, 2, 385, 2754, 0), + (14292, 1, 127, 10, 0), + (14292, 2, 385, 3286, 0), + (14295, 1, 264, 1, 3816), + (14301, 1, 405, 5, 0), + (14304, 1, 264, 45, 8341), + (14308, 1, 264, 20, 431), + (14311, 1, 264, 360, 430), + (14314, 1, 264, 8, 901), + (14318, 1, 127, 10, 0), + (14318, 2, 139, 21754, 0), + (14328, 1, 264, 6, 1154), + (14331, 1, 264, 120, 515), + (14341, 1, 264, 360, 748), + (14349, 1, 294, 0, 205), + (14361, 1, 294, 35, 109), + (14364, 1, 264, 90, 173), + (14367, 1, 445, 1, 0), + (14764, 1, 339, 10, 33950), + (14764, 2, 137, 31, 0), + (15074, 1, 264, 5, 15073), + (15100, 1, 264, 2, 467), + (15105, 1, 264, 120, 131), + (15108, 1, 310, 60000, 0), + (15108, 2, 385, 15521, 0), + (15108, 3, 411, 2, 0), + (15111, 1, 287, 1, 0), + (15111, 2, 385, 21778, 0), + (15113, 1, 287, 3, 0), + (15113, 2, 385, 21778, 0), + (15113, 3, 411, 2, 0), + (15120, 1, 264, 60, 800), + (15123, 1, 310, 120000, 0), + (15123, 2, 385, 15422, 0), + (15123, 3, 411, 2, 0), + (15126, 1, 310, 1000, 0), + (15126, 2, 385, 15212, 0), + (15126, 3, 411, 2, 0), + (15132, 1, 264, 10, 660), + (15135, 1, 287, 1, 0), + (15135, 2, 139, 32313, 0), + (15141, 1, 219, 420, 2400), + (15150, 1, 127, 10, 0), + (15150, 2, 385, 10505, 0), + (15150, 3, 385, 10105, 0), + (15150, 4, 385, 10205, 0), + (15150, 5, 385, 10305, 0), + (15150, 6, 385, 10405, 0), + (15150, 7, 385, 10605, 0), + (15153, 1, 287, 1, 0), + (15153, 2, 139, 4518, 0), + (15154, 1, 287, 1, 0), + (15154, 2, 139, 32312, 0), + (15155, 1, 287, 1, 0), + (15155, 2, 385, 10320, 0), + (15155, 3, 385, 10420, 0), + (15155, 4, 385, 10520, 0), + (15158, 1, 287, 1, 0), + (15158, 2, 385, 32307, 0), + (15159, 1, 287, 1, 0), + (15159, 2, 385, 27537, 0), + (15162, 1, 264, 120, 659), + (15168, 1, 264, 60, 657), + (15172, 1, 302, 430, 430), + (15172, 2, 385, 99, 0), + (15174, 1, 264, 40, 9400), + (15179, 1, 127, 10, 0), + (15179, 2, 139, 21804, 0), + (15179, 3, 139, 38280, 0), + (15182, 1, 264, 840, 9403), + (15188, 1, 239, 62, 0), + (15194, 1, 287, 1, 0), + (15194, 2, 385, 13407, 0), + (15194, 3, 385, 13507, 0), + (15204, 1, 264, 60, 390), + (15207, 1, 264, 60, 323), + (15217, 1, 339, 10, 38319), + (15217, 2, 385, 11006, 0), + (15217, 3, 385, 7108, 0), + (15217, 4, 385, 7208, 0), + (15217, 5, 385, 7308, 0), + (15217, 6, 385, 7408, 0), + (15217, 7, 385, 7508, 0), + (15217, 8, 385, 7608, 0), + (15220, 1, 287, 1, 0), + (15220, 2, 385, 11065, 0), + (15223, 1, 287, 1, 0), + (15223, 2, 385, 11067, 0), + (15226, 1, 287, 1, 0), + (15226, 2, 385, 11064, 0), + (15229, 1, 287, 1, 0), + (15229, 2, 385, 11066, 0), + (15232, 1, 339, 100, 38322), + (15232, 2, 385, 7518, 0), + (15238, 1, 264, 240, 621), + (15238, 2, 264, 240, 622), + (15238, 3, 264, 240, 623), + (15238, 4, 264, 240, 784), + (15238, 5, 264, 240, 785), + (15238, 6, 264, 240, 786), + (15238, 7, 264, 240, 787), + (15238, 8, 264, 240, 624), + (15253, 1, 127, 10, 0), + (15253, 2, 385, 32322, 0), + (15258, 1, 264, 540, 184), + (15270, 1, 264, 1980, 7003), + (15280, 1, 264, 720, 778), + (15283, 1, 310, 1000, 0), + (15283, 2, 385, 11402, 0), + (15283, 3, 385, 11502, 0), + (15283, 4, 385, 11441, 0), + (15283, 5, 385, 11541, 0), + (15283, 6, 385, 11641, 0), + (15288, 1, 220, 50, 0), + (15288, 2, 220, 50, 1), + (15288, 3, 220, 100, 2), + (15288, 4, 220, 100, 3), + (15288, 5, 220, 50, 36), + (15288, 6, 220, 100, 77), + (15295, 1, 127, 10, 0), + (15295, 2, 385, 21654, 0), + (15314, 1, 264, 25920, 36), + (15317, 1, 264, 1728, 35), + (15320, 1, 264, 150, 558), + (15328, 1, 339, 25, 38037), + (15328, 2, 138, 1, 0), + (15328, 3, 142, 65, 0), + (15328, 4, 137, 35, 0), + (15328, 5, 134, 90, 0), + (15328, 6, 339, 25, 38037), + (15328, 7, 138, 1, 0), + (15328, 8, 142, 65, 0), + (15328, 9, 137, 36, 0), + (15328, 10, 134, 90, 0), + (15328, 11, 339, 25, 38037), + (15328, 12, 138, 1, 0), + (15328, 13, 142, 65, 0), + (15328, 14, 137, 369, 0), + (15328, 15, 134, 90, 0), + (15328, 16, 339, 25, 38037), + (15328, 17, 138, 1, 0), + (15328, 18, 142, 65, 0), + (15328, 19, 137, 116, 0), + (15328, 20, 134, 90, 0), + (15342, 1, 287, 1, 0), + (15342, 2, 385, 23605, 0), + (15344, 1, 264, 360, 38), + (15348, 1, 264, 240, 9504), + (15356, 1, 232, 20, 4544), + (15358, 1, 287, 1, 0), + (15358, 2, 385, 32350, 0), + (15359, 1, 264, 960, 50), + (15363, 1, 264, 240, 447), + (15371, 1, 264, 1, 3729), + (15374, 1, 195, 20, 0), + (15383, 1, 310, 1000, 0), + (15383, 2, 385, 5132, 0), + (15383, 3, 385, 5232, 0), + (15383, 4, 385, 5332, 0), + (15383, 5, 385, 5432, 0), + (15383, 6, 385, 5532, 0), + (15383, 7, 385, 5032, 0), + (15383, 8, 385, 5632, 0), + (15389, 1, 127, 16, 0), + (15389, 2, 385, 23575, 0), + (15396, 1, 127, 20, 20), + (15396, 2, 137, 0, 0), + (15396, 3, 138, 0, 0), + (15396, 4, 141, 1, 0), + (15396, 5, 143, 3000, 0), + (15396, 6, 127, 20, 20), + (15396, 7, 385, 16555, 0), + (15396, 8, 385, 16655, 0), + (15397, 1, 264, 1260, 494), + (15403, 1, 264, 10, 8604), + (15406, 1, 127, 10, 10), + (15406, 2, 385, 37097, 0), + (15414, 1, 287, 1, 0), + (15414, 2, 139, 30736, 0), + (15421, 1, 264, 3600, 245), + (15422, 1, 132, 15, 15), + (15426, 1, 239, 62, 0), + (15429, 1, 220, 135, 2), + (15432, 1, 184, 5, -1), + (15438, 1, 310, 180000, 0), + (15438, 2, 385, 8316, 0), + (15438, 3, 411, 128, 0), + (15441, 1, 279, 38, 0), + (15444, 1, 288, 60, 26), + (15450, 1, 310, 3000, 0), + (15450, 2, 385, 8202, 0), + (15450, 3, 385, 8302, 0), + (15450, 4, 385, 8402, 0), + (15450, 5, 385, 8502, 0), + (15450, 6, 385, 8602, 0), + (15450, 7, 411, 128, 0), + (15453, 1, 310, 60000, 0), + (15453, 2, 385, 8421, 0), + (15453, 3, 411, 128, 0), + (15456, 1, 264, 5, 470), + (15466, 1, 126, 20, 20), + (15466, 2, 139, 12576, 0), + (15466, 3, 126, 20, 20), + (15466, 4, 139, 12828, 0), + (15469, 1, 264, 240, 1120), + (15472, 1, 264, 1260, 521), + (15478, 1, 264, 120, 578), + (15485, 1, 339, 10, 38417), + (15485, 2, 142, 96, 0), + (15485, 3, 311, 0, 0), + (15485, 4, 134, 105, 0), + (15485, 5, 348, 10, 0), + (15485, 6, 137, 0, 0), + (15485, 7, 339, 10, 38417), + (15485, 8, 142, 96, 0), + (15485, 9, 311, 0, 0), + (15485, 10, 134, 105, 0), + (15485, 11, 348, 10, 0), + (15485, 12, 137, 100, 0), + (15485, 13, 339, 10, 38417), + (15485, 14, 142, 96, 0), + (15485, 15, 311, 0, 0), + (15485, 16, 134, 105, 0), + (15485, 17, 348, 10, 0), + (15485, 18, 137, 79, 0), + (15485, 19, 339, 10, 38417), + (15485, 20, 142, 96, 0), + (15485, 21, 311, 0, 0), + (15485, 22, 134, 105, 0), + (15485, 23, 348, 10, 0), + (15485, 24, 137, 147, 0), + (15493, 1, 127, 10, 0), + (15493, 2, 137, 31, 0), + (15502, 1, 310, 240000, 0), + (15502, 2, 139, 4673, 0), + (15502, 3, 411, 512, 0), + (15509, 1, 310, 3000, 0), + (15509, 2, 385, 12315, 0), + (15509, 3, 385, 12415, 0), + (15509, 4, 385, 12515, 0), + (15509, 5, 385, 12615, 0), + (15509, 10, 411, 512, 0), + (15512, 1, 288, 50, 8), + (15516, 1, 126, 20, 0), + (15516, 2, 139, 3066, 0), + (15516, 3, 411, 256, 0), + (15517, 1, 127, 16, 0), + (15517, 2, 139, 3066, 0), + (15517, 3, 411, 256, 0), + (15526, 1, 264, 120, 3702), + (15529, 1, 247, 60, 53), + (15540, 1, 185, 5, 1), + (15543, 1, 185, 5, 0), + (15546, 1, 185, 5, 36), + (15549, 1, 264, 15, 244), + (15552, 1, 264, 840, 3710), + (15555, 1, 339, 5, 38103), + (15555, 2, 385, 3208, 0), + (15555, 3, 385, 3308, 0), + (15555, 4, 385, 3408, 0), + (15555, 5, 385, 3508, 0), + (15564, 1, 220, 68, 51), + (15571, 1, 264, 180, 351), + (15579, 1, 287, 2, 0), + (15579, 2, 139, 16106, 0), + (15585, 1, 274, 44, 0), + (15591, 1, 127, 10, 0), + (15591, 2, 139, 16839, 0), + (15598, 1, 264, 180, 759), + (15598, 2, 264, 180, 1150), + (15598, 3, 264, 180, 1151), + (15598, 4, 264, 180, 1152), + (15602, 1, 124, 1, 0), + (15602, 2, 138, 0, 0), + (15602, 3, 141, 1, 0), + (15602, 4, 348, 10, 0), + (15606, 1, 244, -25, 0), + (15609, 1, 383, 10, 38134), + (15609, 2, 141, 1, 0), + (15609, 3, 348, 10, 0), + (15609, 4, 142, 85, 0), + (15609, 5, 143, 3000, 0), + (15622, 1, 127, 5, 5), + (15622, 2, 137, 0, 0), + (15622, 3, 138, 0, 0), + (15622, 4, 141, 1, 0), + (15625, 1, 330, 10, 8), + (15632, 1, 264, 1728, 789), + (15634, 1, 310, 1500, 0), + (15634, 2, 385, 12110, 0), + (15634, 3, 385, 12210, 0), + (15634, 4, 385, 12310, 0), + (15634, 5, 385, 12410, 0), + (15634, 6, 385, 12510, 0), + (15635, 1, 310, 3000, 0), + (15635, 2, 385, 12110, 0), + (15635, 3, 385, 12210, 0), + (15635, 4, 385, 12310, 0), + (15635, 5, 385, 12410, 0), + (15635, 6, 385, 12510, 0), + (15648, 1, 185, 3, 74), + (15694, 1, 190, 550, 0), + (15714, 1, 320, 12, 0), + (15719, 1, 320, 12, 0), + (15746, 1, 421, 20, 0), + (15746, 2, 139, 16097, 0), + (15746, 3, 139, 23612, 0), + (15746, 4, 139, 32196, 0), + (15746, 5, 139, 32565, 0), + (15746, 6, 423, 6, 0), + (15746, 7, 422, 5, 0), + (15746, 8, 411, 2, 0), + (15768, 1, 125, 1, 2), + (15768, 2, 136, 46, 0), + (15772, 1, 128, 80, 80), + (15772, 2, 138, 1, 0), + (15772, 3, 140, 1, 0), + (15772, 4, 311, 0, 0), + (15772, 5, 411, 66434, 0), + (15772, 6, 137, -40, 0), + (15773, 1, 128, 80, 80), + (15773, 2, 138, 1, 0), + (15773, 3, 140, 1, 0), + (15773, 4, 311, 0, 0), + (15773, 5, 411, 256, 0), + (15773, 6, 137, -40, 0), + (15773, 7, 391, 1, 0), + (15778, 1, 303, 27500, 32500), + (15778, 2, 139, 2766, 0), + (15833, 1, 264, 60, 2045), + (15836, 1, 264, 60, 463), + (15891, 1, 264, 20, 988), + (15893, 1, 264, 20, 987), + (15895, 1, 264, 20, 986), + (15908, 1, 220, 125, 0), + (15908, 2, 220, 200, 2), + (15909, 1, 220, 155, 0), + (15909, 2, 220, 290, 2), + (15910, 1, 220, 185, 0), + (15910, 2, 220, 385, 2), + (15954, 1, 292, 49, 0), + (15961, 1, 129, 20, 0), + (15961, 2, 385, 12768, 0), + (15961, 3, 411, 256, 0), + (16062, 1, 339, 20, 40941), + (16062, 2, 138, 0, 0), + (16062, 3, 137, 31, 0), + (16062, 4, 311, 0, 0), + (16084, 1, 158, 1, 0), + (16087, 1, 264, 432, 53), + (16094, 1, 264, 3024, 43), + (16104, 1, 10, 0, 0), + (16109, 1, 69, 3000, 0), + (16114, 1, 114, 2, 0), + (16117, 1, 171, 2, 0), + (16120, 1, 226, 1, 0), + (16121, 1, 310, 840000, 0), + (16121, 2, 139, 4670, 0), + (16124, 1, 264, 2, 3711), + (16128, 1, 127, 8, 0), + (16128, 2, 139, 13143, 0), + (16131, 1, 130, 10, 0), + (16131, 2, 385, 18000, 0), + (16137, 1, 287, 1, 0), + (16137, 2, 385, 21821, 0), + (16140, 1, 287, 1, 0), + (16140, 2, 385, 30666, 0), + (16146, 1, 339, 2, 41107), + (16146, 2, 142, 95, 0), + (16146, 3, 138, 1, 0), + (16146, 4, 137, 0, 0), + (16146, 5, 348, 10, 0), + (16146, 6, 141, 1, 0), + (16149, 1, 129, 20, 0), + (16149, 2, 385, 4357, 0), + (16149, 3, 385, 4457, 0), + (16149, 4, 385, 4557, 0), + (16149, 5, 411, 4, 0), + (16152, 1, 339, 3, 41108), + (16152, 2, 142, 90, 0), + (16152, 3, 138, 0, 0), + (16152, 4, 137, 0, 0), + (16152, 5, 348, 10, 0), + (16152, 6, 141, 1, 0), + (16156, 1, 392, 1000, 0), + (16156, 2, 385, 32341, 0), + (16159, 1, 287, 1, 0), + (16159, 2, 385, 32307, 0), + (16164, 1, 294, 0, 195), + (16170, 1, 360, 70, 41119), + (16173, 1, 320, 12, 0), + (16176, 1, 264, 2, 337), + (16179, 1, 288, 8, 7), + (16180, 1, 264, 5, 584), + (16186, 1, 288, 100, 30), + (16189, 1, 339, 12, 41127), + (16189, 2, 138, 0, 0), + (16189, 3, 142, 70, 0), + (16189, 4, 411, 32, 0), + (16189, 5, 348, 1, 0), + (16189, 6, 141, 1, 0), + (16192, 1, 339, 12, 41130), + (16192, 2, 138, 0, 0), + (16192, 3, 142, 70, 0), + (16192, 4, 403, 4, 0), + (16192, 5, 348, 1, 0), + (16192, 6, 404, 2, 0), + (16192, 7, 141, 1, 0), + (16208, 1, 247, 5, 27), + (16211, 1, 287, 1, 0), + (16211, 2, 139, 23581, 0), + (16211, 3, 139, 32359, 0), + (16218, 1, 264, 10, 403), + (16221, 1, 287, 1, 0), + (16221, 2, 385, 23586, 0), + (16225, 1, 264, 1, 219), + (16230, 1, 310, 1000, 0), + (16230, 2, 385, 2431, 0), + (16230, 3, 385, 2531, 0), + (16230, 4, 385, 2545, 0), + (16230, 5, 385, 2631, 0), + (16235, 1, 126, 35, 0), + (16235, 2, 134, 100, 0), + (16235, 3, 135, 3, 0), + (16238, 1, 287, 2, 0), + (16238, 2, 385, 23693, 0), + (16238, 3, 460, 1, 0), + (16249, 1, 275, 100, 0), + (16257, 1, 429, 37114, 2), + (16257, 2, 428, 52, 0), + (16260, 1, 427, 41160, 3), + (16260, 2, 428, 23, 0), + (16266, 1, 224, 50, 8), + (16266, 2, 173, 4, 0), + (16267, 1, 250, 52, 0), + (16272, 1, 175, 2, 0), + (16276, 1, 247, 10, 36), + (16287, 1, 264, 20, 669), + (16297, 1, 264, 600, 553), + (16300, 1, 264, 60, 668), + (16303, 1, 264, 240, 3506), + (16306, 1, 264, 1260, 777), + (16317, 1, 220, 100, -1), + (16327, 1, 310, 720000, 0), + (16327, 2, 139, 5040, 0), + (16330, 1, 330, 105, 74), + (16336, 1, 264, 30, 1257), + (16339, 1, 264, 10, 773), + (16342, 1, 127, 10, 0), + (16342, 2, 385, 38115, 0), + (16361, 1, 399, 5, 0), + (16361, 2, 141, 1, 0), + (16361, 3, 138, 0, 0), + (16361, 4, 134, 254, 0), + (16361, 5, 348, 10, 0), + (16361, 6, 137, 0, 0), + (16361, 7, 311, 0, 0), + (16361, 8, 137, -152, 0), + (16361, 9, 137, -39, 0), + (16366, 1, 286, 200, 0), + (16366, 2, 138, 0, 0), + (16366, 3, 143, 1, 0), + (16366, 4, 348, 10, 0), + (16371, 1, 129, 20, 0), + (16371, 2, 385, 2754, 0), + (16380, 1, 264, 30, 2061), + (16386, 1, 264, 10, 2064), + (16392, 1, 264, 90, 2202), + (16396, 1, 127, 5, 5), + (16396, 2, 137, 0, 0), + (16396, 3, 138, 0, 0), + (16396, 4, 141, 1, 0), + (16402, 1, 131, 60, 60), + (16402, 2, 348, 10, 0), + (16402, 3, 137, -32, 0), + (16414, 1, 317, 16, 0), + (16419, 1, 426, 6, 0), + (16420, 1, 426, 7, 0), + (16421, 1, 426, 8, 0), + (16440, 1, 247, 65, 76), + (16475, 1, 218, 4, 0), + (16489, 1, 294, 29, 102), + (16536, 1, 405, 3, 0), + (16604, 1, 264, 1440, 180), + (16644, 1, 264, 60, 747), + (16666, 1, 264, 60, 742), + (16730, 1, 347, 31, 0), + (16745, 1, 264, 60, 706), + (16887, 1, 280, 75, 0), + (16890, 1, 218, 21, 0), + (17004, 1, 225, 35, 0), + (17206, 1, 264, 12, 601), + (17209, 1, 264, 180, 111), + (17212, 1, 264, 60, 10367), + (17215, 1, 378, 2, 22), + (17215, 2, 378, 2, 31), + (17215, 3, 378, 2, 3), + (17215, 4, 378, 2, 20), + (17218, 1, 127, 10, 0), + (17218, 2, 139, 27560, 0), + (17229, 1, 220, 900, 3), + (17229, 2, 220, 900, 2), + (17229, 3, 220, 900, 77), + (17235, 1, 127, 15, 0), + (17235, 2, 385, 12609, 0), + (17239, 1, 310, 2400000, 0), + (17239, 2, 139, 4500, 0), + (17239, 3, 411, 8, 0), + (17242, 1, 378, 1, 22), + (17242, 2, 378, 1, 31), + (17242, 3, 378, 1, 3), + (17242, 4, 378, 1, 20), + (17245, 1, 378, 1, 22), + (17245, 2, 378, 1, 31), + (17245, 3, 378, 1, 3), + (17245, 4, 378, 1, 20), + (17249, 1, 264, 120, 651), + (17252, 1, 310, 3000, 0), + (17252, 2, 385, 13438, 0), + (17252, 3, 385, 13538, 0), + (17252, 4, 385, 13638, 0), + (17258, 1, 399, 2, 0), + (17258, 2, 137, 457, 0), + (17258, 3, 399, 2, 0), + (17258, 4, 134, 253, 0), + (17258, 5, 142, 100, 0), + (17258, 6, 138, 0, 0), + (17258, 7, 136, 13, 0), + (17258, 8, 136, 20, 0), + (17258, 9, 137, -39, 0), + (17267, 1, 127, 10, 0), + (17267, 2, 385, 13507, 0), + (17267, 3, 385, 13107, 0), + (17267, 4, 385, 13207, 0), + (17267, 5, 385, 13307, 0), + (17267, 6, 385, 13407, 0), + (17267, 7, 385, 13607, 0), + (17281, 1, 287, 1, 0), + (17281, 2, 385, 16646, 0), + (17288, 1, 264, 1440, 41), + (17289, 1, 264, 180, 1062), + (17295, 1, 229, 62, 0), + (17307, 1, 127, 8, 0), + (17307, 2, 139, 38058, 0), + (17310, 1, 310, 14000, 0), + (17310, 2, 139, 8007, 0), + (17310, 3, 310, 14000, 0), + (17310, 4, 385, 4140, 0), + (17310, 5, 385, 4240, 0), + (17310, 6, 385, 4340, 0), + (17310, 7, 385, 4440, 0), + (17310, 8, 385, 4540, 0), + (17310, 9, 385, 4640, 0), + (17317, 1, 264, 60, 1270), + (17334, 1, 287, 12, 0), + (17334, 2, 385, 16188, 0), + (17336, 1, 287, 1, 0), + (17336, 2, 385, 32348, 0), + (17339, 1, 264, 12, 760), + (17350, 1, 264, 110, 170), + (17357, 1, 287, 1, 0), + (17357, 2, 137, 100, 0), + (17357, 3, 138, 1, 0), + (17361, 1, 264, 60, 405), + (17361, 2, 264, 60, 426), + (17365, 1, 287, 6, 0), + (17365, 2, 385, 5240, 0), + (17365, 3, 385, 5340, 0), + (17365, 4, 385, 5440, 0), + (17365, 5, 385, 5540, 0), + (17365, 6, 385, 5640, 0), + (17370, 1, 287, 1, 0), + (17370, 2, 138, 0, 0), + (17370, 3, 137, 0, 0), + (17370, 4, 137, 100, 0), + (17370, 5, 140, 1, 0), + (17370, 6, 348, 10, 0), + (17375, 1, 127, 10, 0), + (17375, 2, 385, 38078, 0), + (17391, 1, 264, 1560, 98), + (17406, 1, 310, 480000, 0), + (17406, 2, 139, 4502, 0), + (17406, 3, 139, 4509, 0), + (17409, 1, 214, 205, 0), + (17409, 2, 259, 4, 0), + (17409, 3, 172, 4, 0), + (17414, 1, 264, 120, 673), + (17418, 1, 247, 10, 74), + (17428, 1, 288, 5, 51), + (17436, 1, 264, 60, 372), + (17439, 1, 287, 1, 0), + (17439, 2, 385, 6040, 0), + (17441, 1, 279, 37, 0), + (17445, 1, 310, 60000, 0), + (17445, 2, 385, 3312, 0), + (17448, 1, 287, 1, 0), + (17448, 2, 385, 14005, 0), + (17448, 3, 385, 3519, 0), + (17476, 1, 264, 240, 462), + (17492, 1, 264, 120, 840), + (17495, 1, 264, 20, 9702), + (17515, 1, 127, 25, 0), + (17515, 2, 385, 7125, 0), + (17517, 1, 127, 17, 0), + (17517, 2, 385, 23683, 0), + (17517, 3, 460, 1, 0), + (17522, 1, 264, 30, 764), + (17533, 1, 287, 1, 0), + (17533, 2, 139, 32399, 0), + (17533, 3, 460, 1, 0), + (17547, 1, 287, 1, 0), + (17547, 2, 137, 0, 0), + (17547, 3, 137, 100, 0), + (17547, 4, 140, 2, 0), + (17547, 5, 138, 0, 0), + (17547, 6, 348, 10, 0), + (17549, 1, 264, 10, 8700), + (17553, 1, 339, 8, 41768), + (17553, 2, 138, 0, 0), + (17553, 3, 141, 1, 0), + (17553, 4, 134, 253, 0), + (17553, 5, 142, 85, 0), + (17553, 6, 143, 1, 0), + (17553, 7, 311, 0, 0), + (17553, 8, 348, 1, 0), + (17553, 9, 137, 0, 0), + (17554, 1, 227, 2, 74), + (17555, 1, 286, 126, 2), + (17555, 2, 385, 9606, 0), + (17555, 3, 303, 252, 0), + (17555, 4, 385, 9606, 0), + (17558, 1, 413, 2, 2), + (17558, 2, 385, 9603, 0), + (17558, 3, 411, 2048, 0), + (17561, 1, 413, 2, 2), + (17561, 2, 385, 9609, 0), + (17561, 3, 411, 2048, 0), + (17564, 1, 413, 2, 2), + (17564, 2, 385, 9619, 0), + (17564, 3, 411, 2048, 0), + (17567, 1, 413, 2, 2), + (17567, 2, 385, 9613, 0), + (17567, 3, 411, 2048, 0), + (17570, 1, 413, 2, 2), + (17570, 2, 385, 9604, 0), + (17570, 3, 411, 2048, 0), + (17573, 1, 413, 2, 2), + (17573, 2, 385, 9651, 0), + (17573, 3, 411, 2048, 0), + (17576, 1, 413, 2, 2), + (17576, 2, 385, 16652, 0), + (17576, 3, 411, 4096, 0), + (17579, 1, 413, 2, 2), + (17579, 2, 385, 16629, 0), + (17579, 3, 411, 4096, 0), + (17582, 1, 413, 2, 2), + (17582, 2, 385, 16650, 0), + (17582, 3, 411, 4096, 0), + (17585, 1, 413, 2, 2), + (17585, 2, 385, 16608, 0), + (17585, 3, 411, 4096, 0), + (17588, 1, 413, 2, 2), + (17588, 2, 385, 16615, 0), + (17588, 3, 411, 4096, 0), + (17591, 1, 413, 2, 2), + (17591, 2, 385, 16618, 0), + (17591, 3, 411, 4096, 0), + (17594, 1, 413, 2, 2), + (17594, 2, 385, 16625, 0), + (17594, 3, 411, 4096, 0), + (17597, 1, 286, 345, 0), + (17597, 2, 385, 7604, 0), + (17600, 1, 413, 2, 2), + (17600, 2, 385, 7608, 0), + (17600, 3, 411, 8192, 0), + (17603, 1, 413, 2, 2), + (17603, 2, 385, 7612, 0), + (17603, 3, 411, 8192, 0), + (17606, 1, 392, 419, 0), + (17606, 2, 385, 7613, 0), + (17606, 3, 396, 838, 0), + (17606, 4, 385, 7613, 0), + (17609, 1, 413, 2, 2), + (17609, 2, 385, 7636, 0), + (17609, 3, 411, 8192, 0), + (17612, 1, 413, 2, 2), + (17612, 2, 385, 7618, 0), + (17612, 3, 411, 8192, 0), + (17615, 1, 286, 539, 0), + (17615, 2, 385, 7638, 0), + (17618, 1, 413, 2, 2), + (17618, 2, 385, 6664, 0), + (17618, 3, 411, 16384, 0), + (17621, 1, 413, 2, 2), + (17621, 2, 385, 6648, 0), + (17621, 3, 411, 16384, 0), + (17624, 1, 413, 2, 2), + (17624, 2, 385, 6649, 0), + (17624, 3, 411, 16384, 0), + (17627, 1, 413, 2, 2), + (17627, 2, 385, 6611, 0), + (17627, 3, 411, 16384, 0), + (17630, 1, 413, 2, 2), + (17630, 2, 385, 6652, 0), + (17630, 3, 411, 16384, 0), + (17633, 1, 413, 2, 2), + (17633, 2, 385, 6655, 0), + (17633, 3, 411, 16384, 0), + (17639, 1, 323, 37182, 100), + (18972, 1, 214, 210, 0), + (18972, 2, 259, 5, 0), + (18972, 3, 172, 5, 0), + (30050, 1, 69, 25, 0), + (30050, 2, 97, 25, 0), + (30050, 3, 190, 25, 0), + (30050, 4, 328, 25, 0), + (30100, 1, 1, 10, 0), + (30100, 2, 2, 10, 0), + (30100, 3, 341, 10, 0), + (30150, 1, 262, 5, 0), + (30150, 2, 262, 5, 1), + (30150, 3, 262, 5, 2), + (30150, 4, 262, 5, 3), + (30150, 5, 262, 5, 4), + (30150, 6, 262, 5, 5), + (30150, 7, 262, 5, 6), + (30150, 8, 159, 5, 0), + (30150, 9, 0, 2, 0), + (30150, 10, 15, 2, 0), + (30150, 11, 189, 2, 0), + (30150, 12, 317, 2, 0), + (30150, 13, 318, 2, 0), + (30175, 1, 271, 1, 0), + (30180, 1, 264, 1, 8202), + (30185, 1, 264, 1, 1011), + (30195, 1, 432, 1, 0), + (49999, 1, 10, 0, 0); + +DROP TABLE IF EXISTS `aa_rank_prereqs`; +CREATE TABLE IF NOT EXISTS `aa_rank_prereqs` ( + `rank_id` int(10) unsigned NOT NULL, + `aa_id` int(10) NOT NULL, + `points` int(10) NOT NULL, + PRIMARY KEY (`rank_id`,`aa_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +INSERT INTO `aa_rank_prereqs` (`rank_id`, `aa_id`, `points`) VALUES + (129, 19, 3), + (131, 19, 3), + (136, 19, 3), + (141, 23, 3), + (142, 23, 3), + (143, 23, 3), + (146, 224, 3), + (162, 224, 3), + (190, 30, 3), + (191, 30, 3), + (192, 30, 3), + (195, 31, 3), + (230, 17, 3), + (231, 17, 3), + (232, 17, 3), + (255, 309, 3), + (256, 309, 3), + (257, 309, 3), + (260, 31, 3), + (261, 31, 3), + (262, 31, 3), + (263, 17, 3), + (264, 17, 3), + (265, 17, 3), + (267, 23, 3), + (268, 23, 3), + (269, 23, 3), + (446, 26, 3), + (447, 26, 3), + (448, 26, 3), + (462, 39, 1), + (463, 39, 1), + (464, 39, 1), + (468, 41, 1), + (469, 41, 1), + (470, 41, 1), + (471, 57, 1), + (472, 57, 1), + (473, 57, 1), + (474, 50, 1), + (475, 50, 1), + (476, 50, 1), + (477, 43, 1), + (478, 43, 1), + (479, 43, 1), + (480, 117, 1), + (481, 117, 1), + (482, 117, 1), + (483, 58, 1), + (484, 58, 1), + (485, 58, 1), + (489, 110, 1), + (490, 110, 1), + (491, 110, 1), + (492, 109, 1), + (493, 109, 1), + (494, 109, 1), + (495, 98, 1), + (496, 98, 1), + (497, 98, 1), + (498, 102, 1), + (499, 102, 1), + (500, 102, 1), + (501, 107, 1), + (502, 107, 1), + (503, 107, 1), + (531, 19, 3), + (532, 19, 3), + (534, 6001, 11), + (535, 6001, 11), + (536, 6001, 11), + (537, 112, 3), + (538, 112, 3), + (539, 17, 3), + (540, 17, 3), + (541, 17, 3), + (542, 309, 3), + (543, 309, 3), + (544, 309, 3), + (567, 45, 1), + (574, 125, 1), + (575, 125, 1), + (576, 125, 1), + (583, 73, 1), + (584, 73, 1), + (585, 73, 1), + (586, 120, 1), + (587, 120, 1), + (588, 120, 1), + (589, 87, 1), + (590, 87, 1), + (591, 87, 1), + (592, 30, 1), + (593, 6001, 11), + (594, 6001, 11), + (595, 6001, 11), + (596, 6000, 11), + (597, 6000, 11), + (598, 6000, 11), + (637, 23, 3), + (638, 23, 3), + (639, 23, 3), + (640, 23, 3), + (641, 23, 3), + (642, 23, 3), + (643, 55, 1), + (644, 82, 1), + (702, 30, 1), + (703, 30, 1), + (704, 30, 1), + (705, 30, 1), + (706, 30, 1), + (715, 6001, 11), + (716, 6001, 11), + (717, 6001, 11), + (754, 153, 3), + (755, 153, 3), + (756, 153, 3), + (770, 23, 3), + (771, 23, 3), + (772, 23, 3), + (773, 217, 1), + (774, 217, 1), + (775, 217, 1), + (782, 35, 1), + (783, 35, 1), + (784, 35, 1), + (806, 81, 1), + (849, 180, 3), + (850, 180, 3), + (851, 180, 3), + (886, 102, 1), + (887, 102, 1), + (893, 87, 1), + (894, 87, 1), + (924, 23, 3), + (925, 23, 3), + (931, 23, 1), + (932, 23, 1), + (933, 23, 1), + (975, 102, 1), + (1018, 227, 3), + (1041, 30, 6), + (1042, 30, 6), + (1043, 30, 6), + (1044, 310, 6), + (1045, 310, 6), + (1046, 310, 6), + (1047, 311, 3), + (1048, 311, 3), + (1049, 311, 3), + (1050, 309, 6), + (1051, 309, 6), + (1052, 309, 6), + (1102, 30, 1), + (1103, 30, 1), + (1104, 30, 1), + (1105, 30, 1), + (1106, 30, 1), + (1107, 23, 3), + (1108, 23, 3), + (1109, 23, 3), + (1110, 187, 5), + (1111, 187, 5), + (1112, 187, 5), + (1122, 176, 2), + (1126, 58, 1), + (1127, 58, 1), + (1128, 58, 1), + (1129, 125, 1), + (1130, 125, 1), + (1150, 189, 3), + (1151, 189, 3), + (1152, 189, 3), + (1163, 309, 3), + (1164, 309, 3), + (1165, 309, 3), + (1203, 19, 3), + (1204, 19, 3), + (1205, 19, 3), + (1210, 114, 6), + (1211, 114, 6), + (1212, 114, 6), + (1213, 215, 6), + (1214, 215, 6), + (1215, 215, 6), + (1242, 173, 3), + (1243, 173, 3), + (1244, 173, 3), + (1251, 61, 1), + (1252, 64, 1), + (1253, 62, 1), + (1254, 63, 1), + (1274, 175, 3), + (1275, 175, 3), + (1276, 175, 3), + (1278, 6001, 11), + (1279, 6001, 11), + (1280, 6001, 11), + (1323, 47, 1), + (1337, 308, 3), + (1338, 308, 3), + (1339, 308, 3), + (1414, 451, 1), + (1415, 451, 1), + (1416, 451, 1), + (1417, 451, 1), + (1418, 451, 1), + (1420, 17, 3), + (1421, 17, 3), + (1422, 17, 3), + (1423, 17, 3), + (1424, 17, 3), + (1425, 374, 3), + (1426, 374, 3), + (1427, 374, 3), + (1428, 374, 3), + (1429, 374, 3), + (1435, 20, 3), + (1436, 20, 3), + (1437, 20, 3), + (1458, 375, 3), + (1459, 255, 5), + (1460, 255, 5), + (1461, 255, 5), + (1471, 362, 1), + (1472, 362, 1), + (1473, 362, 1), + (1474, 362, 1), + (1475, 362, 1), + (1483, 114, 6), + (1484, 114, 6), + (1485, 114, 6), + (1486, 19, 7), + (1487, 19, 7), + (1488, 19, 7), + (1489, 19, 7), + (1490, 19, 7), + (1494, 80, 1), + (1495, 185, 6), + (1496, 185, 6), + (1497, 185, 6), + (1501, 46, 1), + (1502, 46, 1), + (1503, 46, 1), + (1504, 60, 1), + (1505, 60, 1), + (1506, 60, 1), + (1511, 175, 3), + (1512, 175, 3), + (1513, 175, 3), + (1514, 259, 6), + (1515, 259, 6), + (1516, 259, 6), + (1524, 30, 3), + (1525, 30, 3), + (1526, 30, 3), + (1543, 439, 3), + (1544, 439, 3), + (1545, 439, 3), + (1546, 420, 1), + (1547, 420, 1), + (1548, 420, 1), + (1552, 13, 5), + (1553, 13, 5), + (1554, 13, 5), + (1555, 359, 3), + (1556, 359, 3), + (1557, 359, 3), + (1558, 46, 1), + (1559, 46, 1), + (1560, 46, 1), + (1572, 263, 1), + (1573, 263, 1), + (1574, 263, 1), + (1575, 263, 1), + (1576, 263, 1), + (1577, 58, 1), + (1578, 58, 1), + (1579, 58, 1), + (1583, 300, 6), + (1584, 300, 6), + (1585, 300, 6), + (1586, 300, 6), + (1587, 300, 6), + (1591, 222, 3), + (1601, 82, 1), + (1602, 82, 1), + (1603, 82, 1), + (1608, 82, 3), + (1609, 82, 3), + (1610, 82, 3), + (1611, 181, 2), + (1612, 181, 2), + (1613, 181, 2), + (1614, 181, 2), + (1615, 181, 2), + (1627, 13, 5), + (1628, 13, 5), + (1629, 13, 5), + (1638, 224, 3), + (1639, 565, 1), + (1640, 793, 1), + (1641, 121, 3), + (1642, 121, 3), + (1643, 77, 1), + (1644, 85, 1), + (1645, 77, 1), + (1646, 85, 1), + (1656, 153, 1), + (1657, 153, 1), + (1659, 285, 1), + (1660, 285, 1), + (1667, 570, 1), + (2400, 38, 1), + (2401, 38, 1), + (2402, 38, 1), + (3676, 35, 1), + (4666, 435, 3), + (4667, 435, 3), + (4668, 435, 3), + (4669, 435, 3), + (4670, 435, 3), + (4688, 497, 5), + (4689, 497, 5), + (4690, 497, 5), + (4691, 497, 5), + (4692, 497, 5), + (4707, 30, 6), + (4708, 30, 6), + (4709, 30, 6), + (4710, 310, 6), + (4711, 310, 6), + (4712, 310, 6), + (4713, 311, 3), + (4714, 311, 3), + (4715, 311, 3), + (4716, 309, 6), + (4717, 309, 6), + (4718, 309, 6), + (4749, 23, 3), + (4750, 23, 3), + (4751, 23, 3), + (4752, 114, 6), + (4753, 114, 6), + (4754, 114, 6), + (4755, 215, 6), + (4756, 215, 6), + (4757, 215, 6), + (4761, 526, 3), + (4762, 526, 3), + (4763, 526, 3), + (4773, 20, 3), + (4795, 309, 3), + (4796, 309, 3), + (4797, 309, 3), + (4829, 420, 1), + (4830, 420, 1), + (4831, 420, 1), + (4844, 435, 3), + (4845, 435, 3), + (4846, 435, 3), + (4847, 435, 3), + (4848, 435, 3), + (4861, 68, 1), + (4862, 68, 1), + (4863, 68, 1), + (4864, 175, 3), + (4865, 175, 3), + (4866, 175, 3), + (4887, 413, 3), + (4888, 413, 3), + (4889, 413, 3), + (4890, 57, 1), + (4894, 409, 3), + (4895, 409, 3), + (4896, 409, 3), + (4903, 784, 1), + (4906, 785, 1), + (4909, 786, 1), + (4912, 787, 1), + (4915, 794, 1), + (4916, 794, 1), + (4917, 794, 1), + (4921, 117, 1), + (4922, 117, 1), + (4923, 117, 1), + (4924, 740, 3), + (4925, 740, 3), + (4926, 740, 3), + (4931, 173, 8), + (4932, 173, 8), + (4933, 173, 8), + (4951, 439, 3), + (4952, 439, 3), + (4953, 439, 3), + (4975, 30, 1), + (4976, 30, 1), + (4977, 30, 1), + (4978, 30, 1), + (4979, 30, 1), + (4986, 82, 1), + (4987, 82, 1), + (4988, 82, 1), + (4989, 82, 3), + (4990, 82, 3), + (4991, 82, 3), + (5010, 35, 1), + (5011, 35, 1), + (5012, 35, 1), + (5038, 30, 3), + (5039, 30, 3), + (5040, 30, 3), + (5041, 6001, 11), + (5042, 6001, 11), + (5043, 6001, 11), + (5061, 45, 1), + (5069, 224, 3), + (5070, 19, 3), + (5071, 19, 3), + (5072, 19, 3), + (5080, 255, 5), + (5081, 255, 5), + (5082, 255, 5), + (5098, 73, 2), + (5118, 396, 1), + (5119, 396, 1), + (5120, 396, 1), + (5127, 261, 3), + (5128, 261, 3), + (5129, 261, 3), + (5133, 23, 3), + (5134, 23, 3), + (5135, 23, 3), + (5136, 496, 5), + (5137, 496, 5), + (5138, 496, 5), + (5139, 496, 5), + (5140, 496, 5), + (5251, 447, 3), + (5252, 447, 3), + (5253, 447, 3), + (5264, 278, 5), + (5265, 278, 5), + (5266, 278, 5), + (5267, 278, 5), + (5268, 278, 5), + (5270, 87, 1), + (5271, 87, 1), + (5272, 87, 1), + (5286, 23, 3), + (5287, 23, 3), + (5288, 23, 3), + (5311, 185, 6), + (5312, 185, 6), + (5313, 185, 6), + (5330, 1685, 1), + (5333, 1685, 1), + (5336, 1685, 1), + (5339, 1685, 1), + (5342, 1685, 1), + (5347, 1685, 1), + (5348, 1685, 1), + (5350, 707, 4), + (5350, 1685, 1), + (5353, 1685, 1), + (5356, 1685, 1), + (5357, 1685, 1), + (5360, 1685, 1), + (5363, 447, 3), + (5363, 1685, 1), + (5366, 1685, 1), + (5369, 1685, 1), + (5513, 58, 1), + (5514, 58, 1), + (5515, 58, 1), + (5529, 19, 7), + (5530, 19, 7), + (5531, 19, 7), + (5532, 19, 7), + (5533, 19, 7), + (5542, 30, 6), + (5543, 30, 6), + (5544, 30, 6), + (5545, 310, 6), + (5546, 310, 6), + (5547, 310, 6), + (5548, 311, 3), + (5549, 311, 3), + (5550, 311, 3), + (5551, 309, 6), + (5552, 309, 6), + (5553, 309, 6), + (5571, 23, 3), + (5572, 23, 3), + (5573, 23, 3), + (5574, 114, 6), + (5575, 114, 6), + (5576, 114, 6), + (5577, 215, 6), + (5578, 215, 6), + (5579, 215, 6), + (5595, 309, 3), + (5596, 309, 3), + (5597, 309, 3), + (5607, 794, 1), + (5608, 794, 1), + (5609, 794, 1), + (5617, 23, 3), + (5618, 23, 3), + (5619, 23, 3), + (5702, 30, 1), + (5703, 30, 1), + (5704, 30, 1), + (5705, 30, 1), + (5706, 30, 1), + (5759, 374, 3), + (5760, 374, 3), + (5761, 374, 3), + (5762, 374, 3), + (5763, 374, 3), + (5791, 19, 3), + (5792, 19, 3), + (5793, 19, 3), + (5797, 396, 1), + (5798, 396, 1), + (5799, 396, 1), + (5803, 255, 5), + (5804, 255, 5), + (5805, 255, 5), + (5806, 30, 3), + (5807, 30, 3), + (5808, 30, 3), + (5825, 45, 1), + (5826, 185, 6), + (5827, 185, 6), + (5828, 185, 6), + (5854, 217, 1), + (5855, 217, 1), + (5856, 217, 1), + (5857, 173, 3), + (5858, 173, 3), + (5859, 173, 3), + (5869, 57, 1), + (5871, 57, 1), + (5872, 57, 1), + (5880, 60, 1), + (5881, 60, 1), + (5882, 60, 1), + (5886, 58, 1), + (5887, 58, 1), + (5888, 58, 1), + (5892, 784, 1), + (5893, 785, 1), + (5894, 786, 1), + (5895, 787, 1), + (5939, 278, 5), + (5940, 278, 5), + (5941, 278, 5), + (5942, 278, 5), + (5943, 278, 5), + (5944, 740, 3), + (5945, 740, 3), + (5946, 740, 3), + (5947, 175, 3), + (5948, 175, 3), + (5949, 175, 3), + (5950, 175, 3), + (5951, 175, 3), + (5952, 175, 3), + (5954, 68, 1), + (5955, 68, 1), + (5956, 68, 1), + (5969, 6001, 11), + (5970, 6001, 11), + (5971, 6001, 11), + (5972, 6001, 11), + (5973, 6000, 11), + (5984, 702, 1), + (6017, 82, 1), + (6018, 82, 1), + (6019, 82, 1), + (6026, 826, 1), + (6027, 826, 1), + (6028, 826, 1), + (6042, 439, 3), + (6043, 439, 3), + (6044, 439, 3), + (6054, 173, 8), + (6055, 173, 8), + (6056, 173, 8), + (6063, 87, 1), + (6064, 87, 1), + (6065, 87, 1), + (6088, 392, 1), + (6089, 392, 1), + (6090, 392, 1), + (6092, 447, 3), + (6093, 447, 3), + (6094, 447, 3), + (6102, 224, 3), + (6106, 308, 3), + (6107, 308, 3), + (6108, 308, 3), + (6109, 308, 3), + (6110, 308, 3), + (6111, 308, 3), + (6130, 120, 1), + (6131, 120, 1), + (6132, 120, 1), + (6136, 300, 6), + (6158, 308, 3), + (6159, 308, 3), + (6160, 308, 3), + (6209, 245, 3), + (6210, 245, 3), + (6211, 245, 3), + (6228, 404, 1), + (6229, 404, 1), + (6230, 404, 1), + (6231, 404, 1), + (6233, 43, 1), + (6234, 43, 1), + (6235, 43, 1), + (6260, 98, 1), + (6261, 98, 1), + (6262, 98, 1), + (6272, 672, 1), + (6273, 672, 1), + (6274, 672, 1), + (6275, 790, 1), + (6276, 790, 1), + (6277, 790, 1), + (6302, 3710, 1), + (6303, 3710, 1), + (6304, 3710, 1), + (6319, 107, 1), + (6320, 107, 1), + (6321, 107, 1), + (6333, 125, 1), + (6337, 553, 1), + (6338, 553, 1), + (6339, 553, 1), + (6340, 777, 1), + (6341, 777, 1), + (6342, 777, 1), + (6346, 494, 3), + (6347, 494, 3), + (6348, 494, 3), + (6349, 500, 3), + (6350, 500, 3), + (6351, 500, 3), + (6352, 409, 3), + (6353, 409, 3), + (6354, 409, 3), + (6380, 128, 3), + (6381, 128, 3), + (6382, 128, 3), + (6400, 187, 5), + (6401, 187, 5), + (6402, 187, 5), + (6403, 23, 3), + (6404, 23, 3), + (6405, 23, 3), + (6439, 41, 1), + (6440, 41, 1), + (6441, 420, 1), + (6442, 362, 1), + (6443, 362, 1), + (6445, 176, 1), + (6446, 176, 1), + (6447, 176, 1), + (6478, 3800, 1), + (6479, 3800, 1), + (6480, 3800, 1), + (6481, 36, 1), + (6482, 36, 1), + (6483, 36, 1), + (6484, 558, 1), + (6485, 558, 1), + (6486, 558, 1), + (6499, 611, 1), + (6500, 526, 3), + (6501, 526, 3), + (6502, 526, 3), + (6503, 172, 1), + (6504, 172, 1), + (6505, 172, 1), + (6506, 172, 1), + (6514, 404, 1), + (6515, 404, 1), + (6516, 404, 1), + (6517, 20, 1), + (6528, 107, 1), + (6630, 278, 5), + (6631, 278, 5), + (6632, 278, 5), + (6633, 278, 5), + (6634, 278, 5), + (6636, 358, 3), + (6637, 358, 3), + (6638, 358, 3), + (6668, 672, 3), + (6669, 672, 3), + (6670, 672, 3), + (6697, 857, 1), + (6698, 857, 1), + (6699, 857, 1), + (6700, 857, 1), + (6701, 857, 1), + (6703, 171, 1), + (6704, 171, 1), + (6705, 171, 1), + (6712, 177, 1), + (6713, 177, 1), + (6714, 177, 1), + (6715, 177, 1), + (6716, 177, 1), + (6755, 184, 3), + (6756, 184, 3), + (6757, 184, 3), + (6819, 524, 1), + (6820, 524, 1), + (6821, 524, 1), + (6823, 320, 1), + (6824, 320, 1), + (6825, 320, 1), + (6826, 320, 1), + (6827, 320, 1), + (6870, 544, 1), + (6871, 544, 1), + (6872, 544, 1), + (6873, 3837, 3), + (6874, 3837, 3), + (6875, 3837, 3), + (6876, 259, 3), + (6877, 259, 3), + (6878, 259, 3), + (6900, 465, 3), + (6901, 465, 3), + (6902, 465, 3), + (6903, 465, 3), + (6904, 465, 3), + (6908, 499, 1), + (6909, 499, 1), + (6910, 499, 1), + (6930, 611, 1), + (6935, 465, 3), + (6936, 465, 3), + (6937, 465, 3), + (6941, 962, 1), + (6942, 962, 1), + (6943, 962, 1), + (6944, 962, 1), + (6945, 962, 1), + (6977, 3817, 1), + (6978, 3817, 1), + (6979, 3817, 1), + (6980, 128, 1), + (6981, 128, 1), + (6982, 128, 1), + (6983, 245, 3), + (6988, 985, 1), + (6989, 985, 1), + (6990, 985, 1), + (7005, 789, 1), + (7006, 789, 1), + (7007, 789, 1), + (7033, 804, 1), + (7034, 804, 1), + (7035, 804, 1), + (7036, 3646, 1), + (7037, 3646, 1), + (7038, 3646, 1), + (7050, 26, 3), + (7051, 26, 3), + (7052, 26, 3), + (7053, 26, 3), + (7054, 26, 3), + (7055, 26, 3), + (7063, 26, 3), + (7064, 26, 3), + (7065, 26, 3), + (7100, 254, 3), + (7101, 254, 3), + (7102, 254, 3), + (7103, 286, 1), + (7104, 286, 1), + (7105, 286, 1), + (7116, 110, 1), + (7117, 110, 1), + (7118, 110, 1), + (7122, 435, 3), + (7123, 435, 3), + (7124, 435, 3), + (7125, 435, 3), + (7126, 435, 3), + (7128, 109, 1), + (7129, 109, 1), + (7130, 109, 1), + (7134, 439, 3), + (7135, 439, 3), + (7136, 439, 3), + (7137, 672, 1), + (7138, 672, 1), + (7139, 672, 1), + (7184, 1685, 1), + (7199, 175, 3), + (7200, 175, 3), + (7201, 175, 3), + (7204, 278, 5), + (7205, 278, 5), + (7206, 278, 5), + (7207, 278, 5), + (7208, 278, 5), + (7215, 68, 1), + (7216, 68, 1), + (7232, 114, 6), + (7233, 114, 6), + (7234, 114, 6), + (7246, 794, 1), + (7247, 794, 1), + (7248, 794, 1), + (7253, 784, 1), + (7254, 785, 1), + (7255, 786, 1), + (7256, 787, 1), + (7260, 60, 1), + (7261, 60, 1), + (7262, 60, 1), + (7263, 58, 1), + (7264, 58, 1), + (7265, 58, 1), + (7266, 125, 1), + (7276, 217, 1), + (7277, 217, 1), + (7278, 217, 1), + (7285, 173, 3), + (7286, 173, 3), + (7287, 173, 3), + (7288, 409, 3), + (7289, 409, 3), + (7290, 409, 3), + (7291, 173, 8), + (7292, 173, 8), + (7293, 173, 8), + (7301, 19, 3), + (7302, 19, 3), + (7303, 19, 3), + (7310, 255, 5), + (7311, 255, 5), + (7312, 255, 5), + (7316, 41, 1), + (7317, 41, 1), + (7323, 254, 3), + (7324, 254, 3), + (7325, 254, 3), + (7326, 286, 1), + (7327, 286, 1), + (7328, 286, 1), + (7329, 6001, 11), + (7330, 6001, 11), + (7331, 6001, 11), + (7335, 702, 1), + (7359, 82, 1), + (7360, 82, 1), + (7361, 82, 1), + (7378, 82, 3), + (7379, 82, 3), + (7380, 82, 3), + (7381, 82, 3), + (7382, 82, 3), + (7383, 82, 3), + (7390, 87, 1), + (7391, 87, 1), + (7392, 87, 1), + (7407, 31, 3), + (7414, 185, 6), + (7415, 185, 6), + (7416, 185, 6), + (7433, 30, 1), + (7434, 30, 1), + (7435, 30, 1), + (7436, 30, 1), + (7437, 30, 1), + (7445, 187, 5), + (7446, 187, 5), + (7447, 187, 5), + (7448, 553, 1), + (7449, 553, 1), + (7450, 553, 1), + (7451, 777, 1), + (7452, 777, 1), + (7453, 777, 1), + (7466, 224, 3), + (7472, 447, 3), + (7473, 447, 3), + (7474, 447, 3), + (7478, 245, 3), + (7497, 128, 3), + (7498, 128, 3), + (7499, 128, 3), + (7554, 19, 7), + (7555, 19, 7), + (7556, 19, 7), + (7557, 19, 7), + (7558, 19, 7), + (7562, 30, 6), + (7563, 30, 6), + (7564, 30, 6), + (7581, 215, 6), + (7582, 215, 6), + (7583, 215, 6), + (7615, 494, 3), + (7616, 494, 3), + (7617, 494, 3), + (7618, 500, 3), + (7619, 500, 3), + (7620, 500, 3), + (7621, 20, 1), + (7622, 26, 3), + (7623, 26, 3), + (7624, 26, 3), + (7631, 309, 3), + (7632, 309, 3), + (7633, 309, 3), + (7650, 310, 6), + (7651, 310, 6), + (7652, 310, 6), + (7653, 311, 3), + (7654, 311, 3), + (7655, 311, 3), + (7656, 309, 6), + (7657, 309, 6), + (7658, 309, 6), + (7659, 153, 3), + (7660, 153, 3), + (7661, 153, 3), + (7664, 170, 3), + (7665, 170, 3), + (7666, 170, 3), + (7667, 170, 3), + (7668, 170, 3), + (7682, 68, 1), + (7686, 435, 3), + (7687, 435, 3), + (7688, 435, 3), + (7691, 224, 3), + (7695, 862, 3), + (7696, 862, 3), + (7697, 862, 3), + (7700, 310, 3), + (7701, 310, 3), + (7702, 310, 3), + (7704, 3707, 1), + (7705, 3707, 1), + (7706, 3707, 1), + (7707, 87, 1), + (7708, 87, 1), + (7709, 87, 1), + (7710, 702, 1), + (7711, 702, 1), + (7712, 3826, 1), + (7715, 901, 1), + (7716, 901, 1), + (7717, 901, 1), + (7718, 125, 1), + (7722, 19, 7), + (7723, 19, 7), + (7724, 19, 7), + (7725, 19, 7), + (7726, 19, 7), + (7733, 195, 3), + (7743, 184, 1), + (7744, 184, 1), + (7745, 184, 1), + (7748, 13, 5), + (7749, 13, 5), + (7750, 13, 5), + (7751, 2234, 1), + (7752, 2234, 1), + (7753, 2234, 1), + (7754, 85, 1), + (7757, 9403, 1), + (7758, 9403, 1), + (7759, 9403, 1), + (7760, 824, 1), + (7761, 824, 1), + (7762, 824, 1), + (7765, 7689, 1), + (7766, 7689, 1), + (7767, 7689, 1), + (7768, 7689, 1), + (7770, 19, 3), + (7771, 19, 3), + (7772, 19, 3), + (7773, 19, 3), + (7774, 19, 3), + (7775, 19, 3), + (7822, 1154, 1), + (7823, 1154, 1), + (7824, 1154, 1), + (7825, 1154, 1), + (7826, 1154, 1), + (7827, 1404, 3), + (7832, 60, 1), + (7833, 60, 1), + (7834, 60, 1), + (7835, 60, 1), + (7836, 60, 1), + (7842, 19, 7), + (7843, 19, 7), + (7844, 19, 7), + (7940, 558, 1), + (7941, 558, 1), + (7942, 558, 1), + (7943, 39, 1), + (7944, 41, 1), + (7951, 19, 3), + (7952, 19, 3), + (7953, 19, 3), + (7983, 520, 1), + (7984, 520, 1), + (7985, 520, 1), + (7986, 705, 1), + (7987, 705, 1), + (7988, 705, 1), + (7989, 1092, 1), + (7990, 1092, 1), + (7991, 1092, 1), + (7992, 1092, 1), + (7993, 39, 1), + (7994, 39, 1), + (7995, 39, 1), + (8031, 791, 1), + (8032, 791, 1), + (8033, 791, 1), + (8035, 521, 1), + (8036, 521, 1), + (8037, 521, 1), + (8069, 160, 4), + (8070, 160, 4), + (8071, 160, 4), + (8076, 565, 1), + (8077, 565, 1), + (8078, 565, 1), + (8079, 565, 1), + (8080, 565, 1), + (8081, 565, 1), + (8082, 208, 1), + (8083, 208, 1), + (8084, 208, 1), + (8195, 3707, 1), + (8196, 3707, 1), + (8197, 3707, 1), + (8198, 210, 1), + (8199, 210, 1), + (8200, 210, 1), + (8204, 153, 1), + (8205, 153, 1), + (8206, 153, 1), + (8207, 285, 1), + (8208, 285, 1), + (8209, 285, 1), + (8220, 3812, 1), + (8224, 516, 3), + (8225, 516, 3), + (8226, 516, 3), + (8260, 1211, 1), + (8263, 142, 20), + (8264, 142, 20), + (8265, 142, 20), + (8266, 142, 20), + (8267, 142, 20), + (8268, 142, 20), + (8269, 142, 20), + (8270, 142, 20), + (8271, 142, 20), + (8272, 142, 20), + (8273, 142, 20), + (8274, 142, 20), + (8275, 142, 20), + (8276, 142, 20), + (8277, 142, 20), + (8278, 142, 20), + (8279, 142, 20), + (8280, 142, 20), + (8281, 142, 20), + (8282, 142, 20), + (8283, 142, 20), + (8284, 142, 20), + (8285, 142, 20), + (8286, 142, 20), + (8287, 142, 20), + (8288, 142, 20), + (8289, 142, 20), + (8290, 142, 20), + (8291, 142, 20), + (8292, 142, 20), + (8293, 142, 20), + (8294, 142, 20), + (8295, 142, 20), + (8296, 142, 20), + (8297, 142, 20), + (8303, 309, 6), + (8309, 31, 3), + (8310, 31, 3), + (8311, 31, 3), + (8312, 110, 1), + (8317, 8205, 1), + (8318, 8205, 1), + (8319, 199, 1), + (8320, 199, 1), + (8321, 199, 1), + (8332, 861, 1), + (8333, 861, 1), + (8334, 861, 1), + (8335, 1041, 1), + (8336, 1041, 1), + (8337, 1041, 1), + (8338, 1041, 1), + (8339, 1041, 1), + (8344, 215, 6), + (8345, 215, 6), + (8346, 215, 6), + (8347, 616, 1), + (8348, 616, 1), + (8349, 616, 1), + (8351, 142, 20), + (8352, 142, 20), + (8353, 142, 20), + (8354, 142, 20), + (8355, 142, 20), + (8356, 142, 20), + (8357, 142, 20), + (8358, 142, 20), + (8359, 142, 20), + (8360, 142, 20), + (8361, 142, 20), + (8362, 142, 20), + (8363, 142, 20), + (8364, 142, 20), + (8365, 142, 20), + (8366, 142, 20), + (8367, 142, 20), + (8368, 142, 20), + (8369, 142, 20), + (8370, 142, 20), + (8371, 142, 20), + (8372, 142, 20), + (8373, 142, 20), + (8374, 142, 20), + (8375, 142, 20), + (8376, 142, 20), + (8377, 142, 20), + (8378, 142, 20), + (8379, 142, 20), + (8380, 142, 20), + (8381, 142, 20), + (8382, 142, 20), + (8383, 142, 20), + (8384, 142, 20), + (8385, 142, 20), + (8386, 142, 20), + (8387, 142, 20), + (8388, 142, 20), + (8389, 142, 20), + (8390, 142, 20), + (8391, 142, 20), + (8392, 142, 20), + (8393, 142, 20), + (8394, 142, 20), + (8395, 142, 20), + (8396, 142, 20), + (8397, 142, 20), + (8398, 142, 20), + (8399, 142, 20), + (8400, 142, 20), + (8401, 142, 20), + (8402, 142, 20), + (8403, 142, 20), + (8404, 142, 20), + (8405, 142, 20), + (8406, 142, 20), + (8407, 142, 20), + (8408, 142, 20), + (8409, 142, 20), + (8410, 142, 20), + (8411, 142, 20), + (8412, 142, 20), + (8413, 142, 20), + (8414, 142, 20), + (8415, 142, 20), + (8416, 142, 20), + (8417, 142, 20), + (8418, 142, 20), + (8419, 142, 20), + (8420, 142, 20), + (8421, 516, 3), + (8427, 254, 3), + (8428, 254, 3), + (8429, 254, 3), + (9103, 1350, 3), + (9104, 1350, 3), + (9105, 1350, 3), + (9106, 1351, 3), + (9107, 1351, 3), + (9108, 1351, 3), + (9112, 1390, 3), + (9113, 1390, 3), + (9114, 1390, 3), + (9115, 1391, 3), + (9116, 1391, 3), + (9117, 1391, 3), + (9121, 1370, 3), + (9122, 1370, 3), + (9123, 1370, 3), + (9124, 1371, 3), + (9125, 1371, 3), + (9126, 1371, 3), + (9130, 1380, 3), + (9131, 1380, 3), + (9132, 1380, 3), + (9133, 1381, 3), + (9134, 1381, 3), + (9135, 1381, 3), + (9139, 1470, 3), + (9140, 1470, 3), + (9141, 1470, 3), + (9142, 1471, 3), + (9143, 1471, 3), + (9144, 1471, 3), + (9148, 1480, 3), + (9149, 1480, 3), + (9150, 1480, 3), + (9151, 1481, 3), + (9152, 1481, 3), + (9153, 1481, 3), + (9157, 1490, 3), + (9158, 1490, 3), + (9159, 1490, 3), + (9160, 1491, 3), + (9161, 1491, 3), + (9162, 1491, 3), + (9166, 1460, 3), + (9167, 1460, 3), + (9168, 1460, 3), + (9169, 1461, 3), + (9170, 1461, 3), + (9171, 1461, 3), + (9175, 1450, 3), + (9176, 1450, 3), + (9177, 1450, 3), + (9178, 1451, 3), + (9179, 1451, 3), + (9180, 1451, 3), + (9184, 1440, 3), + (9185, 1440, 3), + (9186, 1440, 3), + (9187, 1441, 3), + (9188, 1441, 3), + (9189, 1441, 3), + (9193, 1420, 3), + (9194, 1420, 3), + (9195, 1420, 3), + (9196, 1421, 3), + (9197, 1421, 3), + (9198, 1421, 3), + (9202, 1430, 3), + (9203, 1430, 3), + (9204, 1430, 3), + (9205, 1431, 3), + (9206, 1431, 3), + (9207, 1431, 3), + (9211, 1400, 3), + (9212, 1400, 3), + (9213, 1400, 3), + (9214, 1401, 3), + (9215, 1401, 3), + (9216, 1401, 3), + (9220, 1360, 3), + (9221, 1360, 3), + (9222, 1360, 3), + (9223, 1361, 3), + (9224, 1361, 3), + (9225, 1361, 3), + (9229, 1500, 3), + (9230, 1500, 3), + (9231, 1500, 3), + (9232, 1501, 3), + (9233, 1501, 3), + (9234, 1501, 3), + (9238, 1410, 3), + (9239, 1410, 3), + (9240, 1410, 3), + (9241, 1411, 3), + (9242, 1411, 3), + (9243, 1411, 3), + (9300, 1300, 3), + (9301, 1300, 3), + (9302, 1300, 3), + (9303, 1300, 6), + (9304, 1300, 6), + (9305, 1300, 6), + (9306, 1300, 9), + (9307, 1300, 9), + (9308, 1300, 9), + (9309, 1313, 3), + (9310, 1313, 3), + (9311, 1313, 3), + (9312, 1313, 6), + (9313, 1313, 6), + (9314, 1313, 6), + (9315, 1313, 9), + (9316, 1313, 9), + (9317, 1313, 9), + (9318, 1302, 3), + (9319, 1302, 3), + (9320, 1302, 3), + (9321, 1302, 6), + (9322, 1302, 6), + (9323, 1302, 6), + (9324, 1302, 9), + (9325, 1302, 9), + (9326, 1302, 9), + (9327, 1303, 3), + (9328, 1303, 3), + (9329, 1303, 3), + (9330, 1303, 6), + (9331, 1303, 6), + (9332, 1303, 6), + (9333, 1303, 9), + (9334, 1303, 9), + (9335, 1303, 9), + (9336, 1301, 3), + (9337, 1301, 3), + (9338, 1301, 3), + (9339, 1301, 6), + (9340, 1301, 6), + (9341, 1301, 6), + (9342, 1301, 9), + (9343, 1301, 9), + (9344, 1301, 9), + (9345, 1312, 3), + (9346, 1312, 3), + (9347, 1312, 3), + (9348, 1312, 6), + (9349, 1312, 6), + (9350, 1312, 6), + (9351, 1312, 9), + (9352, 1312, 9), + (9353, 1312, 9), + (9354, 1315, 3), + (9355, 1315, 3), + (9356, 1315, 3), + (9357, 1315, 6), + (9358, 1315, 6), + (9359, 1315, 6), + (9360, 1315, 9), + (9361, 1315, 9), + (9362, 1315, 9), + (9363, 1310, 3), + (9364, 1310, 3), + (9365, 1310, 3), + (9366, 1310, 6), + (9367, 1310, 6), + (9368, 1310, 6), + (9369, 1310, 9), + (9370, 1310, 9), + (9371, 1310, 9), + (9372, 1311, 3), + (9373, 1311, 3), + (9374, 1311, 3), + (9375, 1311, 6), + (9376, 1311, 6), + (9377, 1311, 6), + (9378, 1311, 9), + (9379, 1311, 9), + (9380, 1311, 9), + (9381, 1309, 3), + (9382, 1309, 3), + (9383, 1309, 3), + (9384, 1309, 6), + (9385, 1309, 6), + (9386, 1309, 6), + (9387, 1309, 9), + (9388, 1309, 9), + (9389, 1309, 9), + (9390, 1308, 3), + (9391, 1308, 3), + (9392, 1308, 3), + (9393, 1308, 6), + (9394, 1308, 6), + (9395, 1308, 6), + (9396, 1308, 9), + (9397, 1308, 9), + (9398, 1308, 9), + (9399, 1307, 3), + (9400, 1307, 3), + (9401, 1307, 3), + (9402, 1307, 6), + (9403, 1307, 6), + (9404, 1307, 6), + (9405, 1307, 9), + (9406, 1307, 9), + (9407, 1307, 9), + (9408, 1304, 3), + (9409, 1304, 3), + (9410, 1304, 3), + (9411, 1304, 6), + (9412, 1304, 6), + (9413, 1304, 6), + (9414, 1304, 9), + (9415, 1304, 9), + (9416, 1304, 9), + (9417, 1305, 3), + (9418, 1305, 3), + (9419, 1305, 3), + (9420, 1305, 6), + (9421, 1305, 6), + (9422, 1305, 6), + (9423, 1305, 9), + (9424, 1305, 9), + (9425, 1305, 9), + (9426, 1306, 3), + (9427, 1306, 3), + (9428, 1306, 3), + (9429, 1306, 6), + (9430, 1306, 6), + (9431, 1306, 6), + (9432, 1306, 9), + (9433, 1306, 9), + (9434, 1306, 9), + (9435, 1314, 3), + (9436, 1314, 3), + (9437, 1314, 3), + (9438, 1314, 6), + (9439, 1314, 6), + (9440, 1314, 6), + (9441, 1314, 9), + (9442, 1314, 9), + (9443, 1314, 9), + (9500, 72, 1), + (10016, 19, 3), + (10017, 19, 3), + (10018, 19, 3), + (10030, 558, 1), + (10031, 558, 1), + (10032, 558, 1), + (10038, 19, 3), + (10039, 19, 3), + (10040, 19, 3), + (10041, 358, 3), + (10042, 358, 3), + (10043, 358, 3), + (10047, 6001, 11), + (10048, 6001, 11), + (10049, 6001, 11), + (10064, 82, 3), + (10065, 82, 3), + (10066, 82, 3), + (10067, 82, 3), + (10068, 82, 3), + (10069, 82, 3), + (10070, 278, 5), + (10071, 278, 5), + (10072, 278, 5), + (10073, 278, 5), + (10074, 278, 5), + (10093, 185, 6), + (10105, 170, 3), + (10106, 170, 3), + (10107, 170, 3), + (10108, 170, 3), + (10109, 170, 3), + (10110, 520, 1), + (10111, 520, 1), + (10112, 520, 1), + (10130, 544, 1), + (10131, 544, 1), + (10132, 544, 1), + (10133, 3837, 3), + (10134, 3837, 3), + (10135, 3837, 3), + (10136, 259, 3), + (10137, 259, 3), + (10138, 259, 3), + (10150, 187, 5), + (10151, 187, 5), + (10152, 187, 5), + (10153, 553, 1), + (10154, 553, 1), + (10155, 553, 1), + (10165, 439, 3), + (10166, 439, 3), + (10167, 439, 3), + (10176, 171, 1), + (10177, 171, 1), + (10178, 171, 1), + (10182, 177, 1), + (10183, 177, 1), + (10184, 177, 1), + (10185, 177, 1), + (10186, 177, 1), + (10197, 447, 3), + (10198, 447, 3), + (10199, 447, 3), + (10203, 524, 1), + (10204, 524, 1), + (10205, 524, 1), + (10206, 320, 1), + (10207, 320, 1), + (10209, 175, 3), + (10210, 175, 3), + (10211, 175, 3), + (10213, 278, 5), + (10214, 278, 5), + (10215, 278, 5), + (10216, 278, 5), + (10217, 278, 5), + (10249, 208, 1), + (10250, 208, 1), + (10251, 208, 1), + (10255, 784, 1), + (10256, 785, 1), + (10257, 786, 1), + (10258, 787, 1), + (10262, 58, 1), + (10263, 58, 1), + (10264, 58, 1), + (10271, 173, 3), + (10272, 173, 3), + (10273, 173, 3), + (10274, 173, 8), + (10275, 173, 8), + (10276, 173, 8), + (10282, 791, 1), + (10283, 791, 1), + (10284, 791, 1), + (10285, 521, 1), + (10286, 521, 1), + (10287, 521, 1), + (10308, 128, 3), + (10309, 128, 3), + (10310, 128, 3), + (10329, 3701, 1), + (10330, 199, 3), + (10332, 943, 3), + (10336, 941, 1), + (10337, 941, 1), + (10338, 941, 1), + (10354, 6001, 17), + (10389, 841, 1), + (10390, 841, 1), + (10391, 841, 1), + (10396, 705, 4), + (10397, 1092, 4), + (10398, 3701, 1), + (10399, 3701, 1), + (10413, 207, 1), + (10414, 207, 1), + (10415, 207, 1), + (10416, 207, 1), + (10417, 207, 1), + (10426, 185, 18), + (10427, 519, 15), + (10428, 173, 8), + (10429, 173, 8), + (10430, 173, 8), + (10431, 791, 1), + (10432, 791, 1), + (10433, 791, 1), + (10434, 792, 1), + (10435, 792, 1), + (10436, 792, 1), + (10450, 19, 9), + (10451, 19, 9), + (10452, 19, 9), + (10456, 3800, 1), + (10457, 3800, 1), + (10458, 3800, 1), + (10462, 396, 1), + (10463, 396, 1), + (10464, 391, 9), + (10465, 391, 9), + (10466, 391, 9), + (10468, 19, 9), + (10469, 19, 9), + (10470, 558, 1), + (10471, 558, 1), + (10472, 558, 1), + (10473, 26, 3), + (10474, 26, 3), + (10475, 26, 3), + (10476, 26, 3), + (10477, 26, 3), + (10510, 705, 1), + (10511, 185, 3), + (10512, 185, 3), + (10513, 185, 3), + (10514, 519, 3), + (10515, 519, 3), + (10516, 519, 3), + (10519, 3213, 1), + (10522, 3732, 1), + (10527, 1400, 1), + (10532, 1401, 1), + (10537, 1402, 1), + (10548, 605, 13), + (10554, 263, 1), + (10555, 263, 1), + (10556, 263, 1), + (10557, 1120, 1), + (10558, 1120, 1), + (10559, 1120, 1), + (10560, 1120, 1), + (10561, 3551, 1), + (10562, 3551, 1), + (10563, 3551, 1), + (10564, 217, 1), + (10565, 217, 1), + (10566, 217, 1), + (10576, 109, 1), + (10579, 3646, 1), + (10580, 3646, 1), + (10588, 601, 1), + (10589, 601, 1), + (10590, 601, 1), + (10591, 601, 1), + (10592, 601, 1), + (10610, 265, 5), + (10611, 265, 5), + (10612, 265, 5), + (10621, 180, 3), + (10622, 180, 3), + (10623, 30, 3), + (10624, 30, 3), + (10625, 30, 3), + (10626, 702, 1), + (10646, 3826, 1), + (10657, 276, 3), + (10658, 276, 3), + (10659, 276, 3), + (10666, 98, 1), + (10667, 98, 1), + (10668, 98, 1), + (10670, 19, 9), + (10708, 6001, 11), + (10709, 6001, 11), + (10710, 6001, 11), + (10711, 30, 6), + (10712, 30, 6), + (10713, 30, 6), + (10714, 873, 1), + (10715, 873, 1), + (10717, 184, 1), + (10718, 184, 1), + (10719, 872, 1), + (10720, 872, 1), + (10721, 872, 1), + (10722, 778, 1), + (10723, 778, 1), + (10724, 778, 1), + (10725, 778, 1), + (10726, 778, 1), + (10727, 2235, 1), + (10728, 2235, 1), + (10730, 870, 1), + (10731, 870, 1), + (10733, 219, 1), + (10734, 219, 1), + (10735, 219, 1), + (10750, 286, 1), + (10751, 286, 1), + (10752, 7108, 1), + (10753, 286, 1), + (10789, 10424, 1), + (10790, 705, 4), + (10791, 1092, 4), + (10800, 462, 3), + (10801, 462, 3), + (10802, 462, 3), + (10903, 125, 1), + (10904, 125, 1), + (10905, 125, 1), + (10909, 7007, 1), + (10910, 7007, 1), + (10911, 7007, 1), + (10915, 823, 3), + (10916, 823, 3), + (10917, 823, 3), + (10951, 447, 3), + (10952, 447, 3), + (10953, 447, 3), + (10954, 662, 3), + (10955, 662, 3), + (10956, 662, 3), + (11011, 3710, 1), + (11012, 3710, 1), + (11013, 3710, 1), + (11014, 3899, 1), + (11015, 3899, 1), + (11016, 3899, 1), + (11020, 3899, 1), + (11050, 452, 3), + (11051, 452, 3), + (11052, 452, 3), + (11053, 500, 3), + (11054, 500, 3), + (11059, 452, 3), + (11060, 452, 3), + (11077, 986, 1), + (11078, 988, 1), + (11079, 987, 1), + (11088, 505, 1), + (11089, 505, 1), + (11090, 505, 1), + (11091, 505, 1), + (12422, 1202, 1), + (12432, 23, 3), + (12433, 23, 3), + (12434, 23, 3), + (12435, 23, 3), + (12436, 23, 3), + (12437, 23, 3), + (12475, 7003, 1), + (12476, 7003, 1), + (12477, 7003, 1), + (12478, 3705, 9), + (12479, 3705, 9), + (12480, 3705, 9), + (12523, 114, 6), + (12526, 215, 6), + (12527, 215, 6), + (12528, 215, 6), + (12529, 358, 3), + (12530, 358, 3), + (12531, 358, 3), + (12553, 23, 3), + (12554, 23, 3), + (12555, 23, 3), + (12556, 23, 3), + (12557, 23, 3), + (12558, 23, 3), + (12582, 9400, 1), + (12583, 9400, 1), + (12584, 9400, 1), + (12587, 9403, 1), + (12588, 9403, 1), + (12589, 9403, 1), + (12600, 3514, 1), + (12606, 13, 5), + (12610, 310, 3), + (12626, 1410, 3), + (12629, 1411, 3), + (12632, 1412, 3), + (12635, 428, 2), + (12639, 519, 3), + (12642, 185, 3), + (12645, 519, 1), + (12646, 185, 1), + (12664, 3728, 1), + (12673, 420, 1), + (12677, 17, 3), + (12679, 276, 3), + (12680, 276, 3), + (12681, 276, 3), + (12697, 30, 6), + (12698, 30, 6), + (12699, 30, 6), + (12713, 8202, 1), + (12714, 8202, 1), + (12715, 8202, 1), + (12716, 3702, 1), + (12717, 3702, 1), + (12718, 3702, 1), + (12719, 3702, 1), + (12720, 3506, 1), + (12721, 3506, 1), + (12722, 3506, 1), + (12723, 3506, 1), + (12727, 359, 3), + (12728, 359, 3), + (12729, 359, 3), + (12730, 941, 1), + (12731, 941, 1), + (12732, 941, 1), + (12733, 943, 3), + (12734, 259, 3), + (12735, 259, 3), + (12736, 259, 3), + (12737, 3701, 1), + (12738, 3701, 1), + (12739, 3701, 1), + (12749, 30, 1), + (12750, 30, 1), + (12751, 30, 1), + (12757, 68, 1), + (12758, 68, 1), + (12759, 68, 1), + (12760, 175, 3), + (12761, 175, 3), + (12762, 175, 3), + (12773, 1580, 1), + (12774, 1580, 1), + (12775, 1580, 1), + (12776, 1580, 1), + (12777, 1580, 1), + (12779, 826, 1), + (12780, 826, 1), + (12781, 826, 1), + (12782, 826, 1), + (12783, 826, 1), + (12784, 826, 1), + (12798, 278, 5), + (12799, 278, 5), + (12800, 278, 5), + (12831, 128, 1), + (12834, 128, 1), + (12835, 128, 1), + (12840, 3817, 1), + (12841, 3817, 1), + (12849, 8303, 1), + (12860, 23, 3), + (12863, 23, 3), + (12865, 1155, 1), + (12866, 639, 1), + (12867, 6106, 6), + (12871, 452, 3), + (12872, 452, 3), + (12874, 451, 1), + (12876, 7003, 1), + (12877, 7003, 1), + (12878, 7003, 1), + (12881, 172, 1), + (12886, 304, 5), + (12887, 303, 5), + (12888, 305, 5), + (12889, 501, 1), + (12890, 507, 1), + (12892, 509, 3), + (12894, 1122, 1), + (12899, 57, 1), + (12900, 57, 1), + (12902, 1380, 1), + (12903, 1380, 1), + (12907, 1381, 1), + (12908, 1381, 1), + (12912, 1382, 1), + (12913, 1382, 1), + (12934, 173, 3), + (12956, 784, 1), + (12957, 786, 1), + (12958, 787, 1), + (12959, 785, 1), + (12964, 596, 1), + (12965, 597, 1), + (12968, 1041, 1), + (12969, 1041, 1), + (12970, 1041, 1), + (12977, 1041, 1), + (12978, 1041, 1), + (12979, 1041, 1), + (12980, 1041, 1), + (12981, 1041, 1), + (12992, 707, 4), + (12993, 707, 4), + (12994, 707, 4), + (13001, 9504, 1), + (13002, 9504, 1), + (13003, 9504, 1), + (13004, 153, 9), + (13005, 171, 1), + (13006, 171, 1), + (13007, 171, 1), + (13008, 859, 1), + (13009, 3730, 1), + (13010, 47, 1), + (13011, 47, 1), + (13012, 47, 1), + (13013, 446, 1), + (13014, 446, 1), + (13015, 446, 1), + (13017, 3815, 10), + (13018, 3815, 10), + (13019, 3815, 10), + (13023, 309, 6), + (13055, 8400, 1), + (13067, 643, 1), + (13072, 3514, 1), + (13073, 3514, 1), + (13074, 310, 6), + (13075, 310, 6), + (13076, 310, 6), + (13077, 311, 3), + (13078, 311, 3), + (13090, 20, 1), + (13092, 82, 1), + (13093, 82, 1), + (13094, 82, 1), + (13104, 87, 1), + (13105, 87, 1), + (13106, 87, 1), + (13130, 1685, 1), + (13140, 391, 9), + (13141, 391, 9), + (13142, 391, 9), + (13143, 500, 1), + (13144, 500, 1), + (13145, 500, 1), + (13146, 494, 1), + (13147, 494, 1), + (13148, 494, 1), + (13155, 705, 1), + (13166, 822, 1), + (13167, 822, 1), + (13168, 822, 1), + (13170, 128, 3), + (13190, 187, 5), + (13191, 187, 5), + (13192, 187, 5), + (13196, 3837, 3), + (13197, 3837, 3), + (13198, 3837, 3), + (13203, 199, 3), + (13204, 8261, 1), + (13205, 8261, 1), + (13206, 8261, 1), + (13213, 439, 3), + (13214, 439, 3), + (13215, 439, 3), + (13216, 439, 3), + (13217, 439, 3), + (13222, 3514, 1), + (13223, 3514, 1), + (13241, 173, 8), + (13244, 46, 1), + (13247, 409, 3), + (13253, 58, 1), + (13254, 58, 1), + (13255, 58, 1), + (13256, 224, 3), + (13257, 224, 3), + (13258, 224, 3), + (13262, 102, 1), + (13263, 102, 1), + (13264, 102, 1), + (13271, 1685, 1), + (13272, 1685, 1), + (13295, 20, 1), + (13308, 26, 3), + (13326, 310, 6), + (13326, 1685, 1), + (13332, 30, 6), + (13363, 1685, 1), + (13383, 1685, 1), + (13385, 1685, 1), + (13388, 1685, 1), + (13389, 1685, 1), + (13396, 1685, 1), + (13396, 3815, 10), + (13401, 1685, 1), + (13404, 259, 6), + (13404, 1685, 1), + (13410, 1685, 1), + (13413, 1685, 1), + (13415, 1092, 1), + (13415, 1685, 1), + (13416, 626, 1), + (13416, 1685, 1), + (13419, 1685, 1), + (13425, 1685, 1), + (13444, 1685, 1), + (13447, 1685, 1), + (13449, 1685, 1), + (13449, 11073, 1), + (13454, 1685, 1), + (13463, 458, 1), + (13463, 1685, 1), + (13466, 1685, 1), + (13467, 1685, 1), + (13468, 1685, 1), + (13472, 1685, 1), + (13474, 444, 1), + (13474, 1685, 1), + (13477, 1685, 1), + (13483, 1685, 1), + (13484, 1685, 1), + (13485, 1685, 1), + (13490, 1685, 1), + (13492, 199, 3), + (13492, 1685, 1), + (13493, 1685, 1), + (13496, 187, 5), + (13496, 1685, 1), + (13499, 30, 1), + (13499, 1685, 1), + (13502, 259, 3), + (13502, 1685, 1), + (13505, 1685, 1), + (13508, 1685, 1), + (13511, 1685, 1), + (13511, 3837, 3), + (13514, 1685, 1), + (13517, 941, 1), + (13517, 1685, 1), + (13520, 1685, 1), + (13521, 1685, 1), + (13524, 1685, 1), + (13527, 1685, 1), + (13528, 1685, 1), + (13529, 1685, 1), + (13530, 1685, 1), + (13533, 1685, 1), + (13542, 184, 3), + (13542, 1685, 1), + (13545, 1685, 1), + (13546, 1685, 1), + (13549, 1685, 1), + (13556, 1685, 1), + (13562, 872, 1), + (13562, 1685, 1), + (13565, 1685, 1), + (13565, 3804, 1), + (13568, 876, 1), + (13568, 1685, 1), + (13571, 1685, 1), + (13575, 1685, 1), + (13578, 1685, 1), + (13584, 1685, 1), + (13585, 1685, 1), + (13585, 3826, 1), + (13586, 1685, 1), + (13589, 30, 3), + (13589, 1685, 1), + (13590, 30, 3), + (13590, 1685, 1), + (13592, 702, 1), + (13592, 1685, 1), + (13595, 1685, 1), + (13595, 6001, 11), + (13598, 1685, 1), + (13601, 1685, 1), + (13604, 1685, 1), + (13607, 1685, 1), + (13610, 1685, 1), + (13613, 1685, 1), + (13616, 1685, 1), + (13617, 1685, 1), + (13618, 1685, 1), + (13619, 1685, 1), + (13621, 278, 5), + (13621, 1685, 1), + (13624, 1685, 1), + (13627, 1685, 1), + (13628, 1685, 1), + (13630, 1685, 1), + (13633, 1685, 1), + (13646, 1668, 1), + (13646, 1685, 1), + (13650, 1685, 1), + (13653, 1685, 1), + (13656, 1685, 1), + (13663, 1685, 1), + (13667, 500, 1), + (13667, 1685, 1), + (13670, 1685, 1), + (13673, 1158, 1), + (13674, 7754, 1), + (13675, 278, 5), + (13675, 1685, 1), + (13678, 1685, 1), + (13682, 1685, 1), + (13683, 1685, 1), + (13684, 1685, 1), + (13685, 1685, 1), + (13686, 1685, 1), + (13687, 1685, 1), + (13688, 1685, 1), + (13689, 751, 1), + (13689, 1685, 1), + (13692, 1685, 1), + (13693, 1685, 1), + (13695, 1685, 1), + (13698, 784, 1), + (13698, 1685, 1), + (13701, 785, 1), + (13701, 1685, 1), + (13704, 787, 1), + (13704, 1685, 1), + (13707, 58, 1), + (13707, 1685, 1), + (13710, 1685, 1), + (13713, 1685, 1), + (13718, 1685, 1), + (13720, 1685, 1), + (13723, 58, 1), + (13723, 1685, 1), + (13726, 1685, 1), + (13727, 25, 3), + (13727, 1685, 1), + (13734, 217, 1), + (13734, 1685, 1), + (13753, 534, 1), + (13753, 1685, 1), + (13758, 602, 1), + (13758, 1685, 1), + (13763, 1685, 1), + (13764, 535, 1), + (13764, 1685, 1), + (13767, 1685, 1), + (13770, 1685, 1), + (13771, 1685, 1), + (13773, 310, 3), + (13773, 1685, 1), + (13774, 310, 3), + (13774, 1685, 1), + (13775, 310, 3), + (13775, 1685, 1), + (13779, 1685, 1), + (13782, 439, 3), + (13782, 1685, 1), + (13785, 1685, 1), + (13789, 1685, 1), + (13790, 1685, 1), + (13792, 1685, 1), + (13795, 1685, 1), + (13798, 1685, 1), + (13804, 1685, 1), + (13807, 1685, 1), + (13810, 1685, 1), + (13813, 1685, 1), + (13816, 1685, 1), + (13819, 1685, 1), + (13820, 1685, 1), + (13823, 1685, 1), + (13826, 1685, 1), + (13829, 1685, 1), + (13832, 1685, 1), + (13835, 1685, 1), + (13838, 1685, 1), + (13841, 1685, 1), + (13845, 1685, 1), + (13872, 1685, 1), + (13873, 961, 1), + (13873, 1685, 1), + (13878, 609, 1), + (13878, 1685, 1), + (13881, 387, 1), + (13881, 1685, 1), + (13889, 1012, 1), + (13889, 1685, 1), + (13899, 1685, 1), + (13905, 1685, 1), + (13908, 1685, 1), + (13911, 1685, 1), + (13914, 1685, 1), + (13917, 606, 1), + (13917, 1685, 1), + (13920, 125, 1), + (13920, 1685, 1), + (13933, 142, 20), + (13943, 142, 20), + (13953, 142, 20), + (13963, 142, 20), + (13973, 142, 20), + (13983, 142, 20), + (13993, 142, 20), + (14003, 1685, 1), + (14006, 30, 6), + (14006, 1685, 1), + (14009, 1685, 1), + (14010, 1685, 1), + (14011, 1685, 1), + (14011, 10394, 1), + (14016, 1685, 1), + (14016, 6001, 17), + (14018, 1684, 1), + (14019, 1685, 1), + (14026, 1685, 1), + (14029, 1685, 1), + (14032, 1685, 1), + (14037, 804, 1), + (14037, 1685, 1), + (14040, 300, 1), + (14040, 1685, 1), + (14043, 1685, 1), + (14046, 87, 1), + (14046, 1685, 1), + (14051, 1685, 1), + (14052, 1685, 1), + (14053, 1685, 1), + (14054, 1685, 1), + (14055, 1685, 1), + (14056, 1685, 1), + (14059, 1685, 1), + (14062, 821, 1), + (14062, 1685, 1), + (14065, 1685, 1), + (14065, 3215, 1), + (14068, 1685, 1), + (14068, 3216, 1), + (14071, 1685, 1), + (14076, 1685, 1), + (14080, 1685, 1), + (14081, 1685, 1), + (14082, 1685, 1), + (14085, 741, 1), + (14085, 1685, 1), + (14088, 769, 1), + (14088, 1685, 1), + (14091, 701, 1), + (14091, 1685, 1), + (14094, 1685, 1), + (14097, 1685, 1), + (14100, 1685, 1), + (14101, 1685, 1), + (14111, 1685, 1), + (14112, 1685, 1), + (14115, 872, 1), + (14115, 1685, 1), + (14129, 1685, 1), + (14130, 1685, 1), + (14132, 1685, 1), + (14132, 2234, 1), + (14135, 1685, 1), + (14138, 1685, 1), + (14139, 1685, 1), + (14140, 1685, 1), + (14141, 1685, 1), + (14144, 1685, 1), + (14144, 3515, 1), + (14148, 1685, 1), + (14151, 1685, 1), + (14154, 276, 3), + (14154, 1685, 1), + (14157, 1685, 1), + (14160, 1685, 1), + (14160, 7001, 1), + (14163, 1685, 1), + (14163, 7001, 1), + (14166, 945, 1), + (14166, 1685, 1), + (14169, 1685, 1), + (14173, 1685, 1), + (14176, 1685, 1), + (14176, 8261, 1), + (14179, 359, 1), + (14179, 1685, 1), + (14180, 1685, 1), + (14181, 1685, 1), + (14181, 3837, 12), + (14186, 809, 5), + (14186, 1685, 1), + (14189, 1685, 1), + (14192, 1685, 1), + (14196, 465, 3), + (14196, 1685, 1), + (14199, 499, 1), + (14199, 1685, 1), + (14200, 1685, 1), + (14203, 1685, 1), + (14206, 1685, 1), + (14207, 1685, 1), + (14208, 1685, 1), + (14208, 7689, 1), + (14209, 1685, 1), + (14210, 1685, 1), + (14213, 1065, 1), + (14213, 1685, 1), + (14218, 1685, 1), + (14221, 1685, 1), + (14222, 224, 3), + (14222, 1685, 1), + (14223, 47, 1), + (14223, 1685, 1), + (14224, 1685, 1), + (14225, 177, 1), + (14225, 1685, 1), + (14229, 135, 1), + (14231, 1685, 1), + (14232, 1685, 1), + (14233, 1685, 1), + (14234, 1685, 1), + (14237, 1685, 1), + (14238, 1041, 1), + (14238, 1685, 1), + (14241, 386, 1), + (14241, 1685, 1), + (14244, 1685, 1), + (14249, 1685, 1), + (14254, 386, 1), + (14254, 1685, 1), + (14256, 1685, 1), + (14259, 384, 1), + (14259, 1685, 1), + (14265, 939, 1), + (14265, 1685, 1), + (14272, 1685, 1), + (14273, 1685, 1), + (14274, 1685, 1), + (14275, 1685, 1), + (14278, 985, 1), + (14278, 1685, 1), + (14280, 57, 1), + (14280, 1685, 1), + (14281, 291, 1), + (14281, 1685, 1), + (14282, 1685, 1), + (14282, 3812, 1), + (14283, 1685, 1), + (14286, 753, 1), + (14286, 1685, 1), + (14289, 1685, 1), + (14292, 207, 1), + (14292, 1685, 1), + (14295, 1685, 1), + (14295, 3816, 1), + (14304, 1685, 1), + (14304, 8341, 1), + (14307, 1685, 1), + (14308, 431, 1), + (14308, 1685, 1), + (14311, 430, 1), + (14311, 1685, 1), + (14314, 901, 1), + (14314, 1685, 1), + (14318, 1685, 1), + (14318, 7703, 1), + (14321, 1685, 1), + (14322, 1685, 1), + (14323, 1685, 1), + (14324, 1685, 1), + (14328, 1154, 1), + (14328, 1685, 1), + (14331, 515, 1), + (14331, 1685, 1), + (14338, 308, 3), + (14338, 1685, 1), + (14341, 748, 1), + (14341, 1685, 1), + (14346, 1685, 1), + (14349, 215, 6), + (14352, 175, 3), + (14352, 1685, 1), + (14355, 1685, 1), + (14358, 1685, 1), + (14359, 1685, 1), + (14360, 1685, 1), + (14361, 23, 3), + (14364, 173, 1), + (14364, 1685, 1), + (14372, 1685, 1), + (14690, 756, 1), + (14733, 786, 1), + (15100, 467, 1), + (15105, 131, 1), + (15113, 130, 1), + (15120, 800, 1), + (15132, 660, 1), + (15135, 660, 1), + (15141, 30, 3), + (15147, 701, 13), + (15154, 659, 1), + (15158, 657, 1), + (15159, 770, 1), + (15162, 659, 1), + (15168, 657, 1), + (15174, 9400, 1), + (15179, 7755, 1), + (15182, 9403, 1), + (15204, 390, 1), + (15207, 323, 1), + (15210, 1041, 1), + (15220, 622, 1), + (15223, 624, 1), + (15226, 621, 1), + (15229, 623, 1), + (15253, 462, 1), + (15258, 184, 1), + (15270, 7003, 1), + (15280, 778, 1), + (15295, 2234, 1), + (15314, 36, 1), + (15317, 35, 1), + (15320, 558, 1), + (15341, 19, 3), + (15342, 8500, 1), + (15344, 38, 1), + (15348, 9504, 1), + (15356, 149, 1), + (15358, 151, 1), + (15359, 50, 1), + (15363, 447, 3), + (15371, 3729, 1), + (15377, 638, 1), + (15389, 935, 1), + (15396, 23, 3), + (15397, 494, 3), + (15403, 8604, 1), + (15406, 3817, 1), + (15414, 241, 1), + (15421, 245, 3), + (15424, 247, 1), + (15424, 982, 6), + (15466, 3551, 1), + (15469, 1120, 1), + (15472, 521, 1), + (15478, 578, 1), + (15481, 398, 24), + (15482, 261, 1), + (15485, 495, 9), + (15486, 534, 3), + (15526, 3702, 1), + (15549, 244, 1), + (15552, 3710, 1), + (15571, 351, 1), + (15579, 826, 1), + (15591, 2899, 1), + (15598, 759, 1), + (15598, 1150, 1), + (15598, 1151, 1), + (15598, 1152, 1), + (15605, 639, 1), + (15606, 160, 4), + (15622, 23, 3), + (15632, 789, 1), + (15639, 749, 1), + (15640, 822, 2), + (15746, 804, 1), + (15778, 87, 1), + (15833, 2045, 1), + (15836, 463, 1), + (15839, 19, 9), + (15855, 153, 9), + (15891, 988, 1), + (15893, 987, 1), + (15895, 986, 1), + (15961, 3701, 1), + (16062, 263, 1), + (16071, 2209, 3), + (16087, 53, 1), + (16094, 43, 1), + (16103, 7703, 1), + (16105, 684, 1), + (16106, 684, 1), + (16107, 684, 1), + (16117, 309, 6), + (16124, 3711, 1), + (16128, 3711, 1), + (16131, 73, 1), + (16137, 10394, 1), + (16140, 489, 1), + (16156, 137, 1), + (16159, 2045, 1), + (16163, 260, 1), + (16163, 7747, 1), + (16164, 358, 3), + (16176, 337, 1), + (16180, 584, 1), + (16185, 9202, 1), + (16185, 9203, 1), + (16189, 823, 3), + (16203, 403, 1), + (16211, 152, 1), + (16218, 403, 1), + (16221, 393, 1), + (16225, 219, 1), + (16238, 443, 1), + (16246, 245, 3), + (16249, 17, 3), + (16257, 470, 20), + (16266, 790, 1), + (16287, 669, 1), + (16297, 553, 1), + (16300, 668, 1), + (16303, 3506, 1), + (16306, 777, 1), + (16336, 1257, 1), + (16339, 773, 1), + (16342, 1257, 1), + (16371, 60, 1), + (16380, 2061, 1), + (16386, 2064, 1), + (16392, 2202, 1), + (16489, 23, 3), + (16604, 180, 3), + (16644, 747, 1), + (16666, 742, 1), + (16730, 82, 3), + (16745, 706, 1), + (17206, 601, 1), + (17209, 111, 1), + (17212, 10367, 1), + (17218, 744, 1), + (17235, 3826, 1), + (17280, 8205, 1), + (17281, 359, 1), + (17288, 41, 1), + (17289, 1062, 1), + (17307, 2047, 1), + (17317, 1270, 1), + (17334, 1041, 1), + (17336, 148, 1), + (17339, 760, 1), + (17342, 148, 1), + (17350, 170, 3), + (17361, 405, 1), + (17361, 426, 1), + (17364, 935, 4), + (17375, 1239, 1), + (17391, 98, 1), + (17409, 120, 1), + (17414, 673, 1), + (17436, 372, 1), + (17439, 372, 1), + (17441, 309, 3), + (17476, 462, 3), + (17492, 840, 1), + (17495, 9702, 1), + (17515, 3841, 1), + (17517, 441, 1), + (17522, 764, 1), + (17533, 677, 1), + (17549, 8700, 1); diff --git a/world/client.cpp b/world/client.cpp index 26a69222b..d2ca3705a 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -1,3 +1,21 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #include "../common/global_define.h" #include "../common/eq_packet.h" #include "../common/eq_stream_intf.h" @@ -14,7 +32,7 @@ #include "../common/skills.h" #include "../common/extprofile.h" #include "../common/string_util.h" -#include "../common/clientversions.h" +#include "../common/emu_versions.h" #include "../common/random.h" #include "../common/shareddb.h" @@ -43,8 +61,8 @@ // Disgrace: for windows compile #ifdef _WINDOWS + #include #include - #include #else #ifdef FREEBSD //Timothy Whitman - January 7, 2003 @@ -80,22 +98,22 @@ Client::Client(EQStreamInterface* ieqs) autobootup_timeout.Disable(); connect.Disable(); - seencharsel = false; + seen_character_select = false; cle = 0; - zoneID = 0; + zone_id = 0; char_name[0] = 0; charid = 0; - pwaitingforbootup = 0; + zone_waiting_for_bootup = 0; StartInTutorial = false; - m_ClientVersion = eqs->GetClientVersion(); - m_ClientVersionBit = ClientBitFromVersion(m_ClientVersion); + m_ClientVersion = eqs->ClientVersion(); + m_ClientVersionBit = EQEmu::versions::ConvertClientVersionToClientVersionBit(m_ClientVersion); numclients++; } Client::~Client() { - if (RunLoops && cle && zoneID == 0) + if (RunLoops && cle && zone_id == 0) cle->SetOnline(CLE_Status_Offline); numclients--; @@ -124,7 +142,7 @@ void Client::SendLogServer() if(RuleB(World, IsGMPetitionWindowEnabled)) l->enable_petition_wnd = 1; - if(RuleI(World, FVNoDropFlag) == 1 || RuleI(World, FVNoDropFlag) == 2 && GetAdmin() > RuleI(Character, MinStatusForNoDropExemptions)) + if((RuleI(World, FVNoDropFlag) == 1 || RuleI(World, FVNoDropFlag) == 2) && GetAdmin() > RuleI(Character, MinStatusForNoDropExemptions)) l->enable_FV = 1; QueuePacket(outapp); @@ -134,7 +152,7 @@ void Client::SendLogServer() void Client::SendEnterWorld(std::string name) { char char_name[64] = { 0 }; - if (pZoning && database.GetLiveChar(GetAccountID(), char_name)) { + if (is_player_zoning && database.GetLiveChar(GetAccountID(), char_name)) { if(database.GetAccountIDByChar(char_name) != GetAccountID()) { eqs->Close(); return; @@ -152,7 +170,13 @@ void Client::SendEnterWorld(std::string name) void Client::SendExpansionInfo() { auto outapp = new EQApplicationPacket(OP_ExpansionInfo, sizeof(ExpansionInfo_Struct)); ExpansionInfo_Struct *eis = (ExpansionInfo_Struct*)outapp->pBuffer; - eis->Expansions = (RuleI(World, ExpansionSettings)); + if(RuleB(World, UseClientBasedExpansionSettings)) { + eis->Expansions = EQEmu::versions::ConvertClientVersionToExpansion(eqs->ClientVersion()); + //eis->Expansions = ExpansionFromClientVersion(this->GetCLE. + } else { + eis->Expansions = (RuleI(World, ExpansionSettings)); + } + QueuePacket(outapp); safe_delete(outapp); } @@ -162,13 +186,13 @@ void Client::SendCharInfo() { cle->SetOnline(CLE_Status_CharSelect); } - if (m_ClientVersionBit & BIT_RoFAndLater) { + if (m_ClientVersionBit & EQEmu::versions::bit_RoFAndLater) { SendMaxCharCreate(); SendMembership(); SendMembershipSettings(); } - seencharsel = true; + seen_character_select = true; // Send OP_SendCharInfo EQApplicationPacket *outapp = nullptr; @@ -187,9 +211,9 @@ void Client::SendMaxCharCreate() { auto outapp = new EQApplicationPacket(OP_SendMaxCharacters, sizeof(MaxCharacters_Struct)); MaxCharacters_Struct* mc = (MaxCharacters_Struct*)outapp->pBuffer; - mc->max_chars = EQLimits::CharacterCreationLimit(m_ClientVersion); - if (mc->max_chars > EmuConstants::CHARACTER_CREATION_LIMIT) - mc->max_chars = EmuConstants::CHARACTER_CREATION_LIMIT; + mc->max_chars = EQEmu::constants::Lookup(m_ClientVersion)->CharacterCreationLimit; + if (mc->max_chars > EQEmu::constants::CharacterCreationMax) + mc->max_chars = EQEmu::constants::CharacterCreationMax; QueuePacket(outapp); safe_delete(outapp); @@ -387,7 +411,7 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app) { return false; } - pZoning=(li->zoning==1); + is_player_zoning=(li->zoning==1); #ifdef IPBASED_AUTH_HACK struct in_addr tmpip; @@ -412,32 +436,33 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app) { #ifdef IPBASED_AUTH_HACK if ((cle = zoneserver_list.CheckAuth(inet_ntoa(tmpip), password))) #else - if (loginserverlist.Connected() == false && !pZoning) { - Log.Out(Logs::Detail, Logs::World_Server,"Error: Login server login while not connected to login server."); + if (loginserverlist.Connected() == false && !is_player_zoning) { + Log.Out(Logs::General, Logs::World_Server,"Error: Login server login while not connected to login server."); return false; } if (((cle = client_list.CheckAuth(name, password)) || (cle = client_list.CheckAuth(id, password)))) #endif { if (cle->AccountID() == 0 || (!minilogin && cle->LSID()==0)) { - Log.Out(Logs::Detail, Logs::World_Server,"ID is 0. Is this server connected to minilogin?"); + Log.Out(Logs::General, Logs::World_Server,"ID is 0. Is this server connected to minilogin?"); if(!minilogin) - Log.Out(Logs::Detail, Logs::World_Server,"If so you forget the minilogin variable..."); + Log.Out(Logs::General, Logs::World_Server,"If so you forget the minilogin variable..."); else - Log.Out(Logs::Detail, Logs::World_Server,"Could not find a minilogin account, verify ip address logging into minilogin is the same that is in your account table."); + Log.Out(Logs::General, Logs::World_Server,"Could not find a minilogin account, verify ip address logging into minilogin is the same that is in your account table."); return false; } cle->SetOnline(); - Log.Out(Logs::Detail, Logs::World_Server,"Logged in. Mode=%s",pZoning ? "(Zoning)" : "(CharSel)"); - if(minilogin){ WorldConfig::DisableStats(); - Log.Out(Logs::Detail, Logs::World_Server,"MiniLogin Account #%d",cle->AccountID()); + Log.Out(Logs::General, Logs::World_Server, "MiniLogin Account #%d",cle->AccountID()); } else { - Log.Out(Logs::Detail, Logs::World_Server,"LS Account #%d",cle->LSID()); + if (!is_player_zoning) { + Log.Out(Logs::General, Logs::World_Server, + "Account (%s) Logging in :: LSID: %d ", cle->AccountName(), cle->LSID()); + } } const WorldConfig *Config=WorldConfig::get(); @@ -455,13 +480,14 @@ bool Client::HandleSendLoginInfoPacket(const EQApplicationPacket *app) { safe_delete(pack); } - if (!pZoning) + if (!is_player_zoning) SendGuildList(); + SendLogServer(); SendApproveWorld(); SendEnterWorld(cle->name()); SendPostEnterWorld(); - if (!pZoning) { + if (!is_player_zoning) { SendExpansionInfo(); SendCharInfo(); database.LoginIP(cle->AccountID(), long2ip(GetIP()).c_str()); @@ -492,7 +518,7 @@ bool Client::HandleNameApprovalPacket(const EQApplicationPacket *app) uchar race = app->pBuffer[64]; uchar clas = app->pBuffer[68]; - Log.Out(Logs::Detail, Logs::World_Server, "Name approval request. Name=%s, race=%s, class=%s", char_name, GetRaceName(race), GetEQClassName(clas)); + Log.Out(Logs::Detail, Logs::World_Server, "Name approval request. Name=%s, race=%s, class=%s", char_name, GetRaceIDName(race), GetClassIDName(clas)); EQApplicationPacket *outapp; outapp = new EQApplicationPacket; @@ -674,7 +700,7 @@ bool Client::HandleCharacterCreatePacket(const EQApplicationPacket *app) { } else { - if (m_ClientVersionBit & BIT_TitaniumAndEarlier) + if (m_ClientVersionBit & EQEmu::versions::bit_TitaniumAndEarlier) StartInTutorial = true; SendCharInfo(); } @@ -705,7 +731,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { EQApplicationPacket *outapp; uint32 tmpaccid = 0; - charid = database.GetCharacterInfo(char_name, &tmpaccid, &zoneID, &instanceID); + charid = database.GetCharacterInfo(char_name, &tmpaccid, &zone_id, &instance_id); if (charid == 0 || tmpaccid != GetAccountID()) { Log.Out(Logs::Detail, Logs::World_Server,"Could not get CharInfo for '%s'",char_name); eqs->Close(); @@ -721,10 +747,10 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { // This can probably be moved outside and have another method return requested info (don't forget to remove the #include "../common/shareddb.h" above) // (This is a literal translation of the original process..I don't see why it can't be changed to a single-target query over account iteration) - if (!pZoning) { - size_t character_limit = EQLimits::CharacterCreationLimit(eqs->GetClientVersion()); - if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT) { character_limit = EmuConstants::CHARACTER_CREATION_LIMIT; } - if (eqs->GetClientVersion() == ClientVersion::Titanium) { character_limit = 8; } + if (!is_player_zoning) { + size_t character_limit = EQEmu::constants::Lookup(eqs->ClientVersion())->CharacterCreationLimit; + if (character_limit > EQEmu::constants::CharacterCreationMax) { character_limit = EQEmu::constants::CharacterCreationMax; } + if (eqs->ClientVersion() == EQEmu::versions::ClientVersion::Titanium) { character_limit = 8; } std::string tgh_query = StringFormat( "SELECT " @@ -753,7 +779,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { } if (home_enabled) { - zoneID = database.MoveCharacterToBind(charid, 4); + zone_id = database.MoveCharacterToBind(charid, 4); } else { Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go home before they're able...", char_name); @@ -776,8 +802,8 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { } if (tutorial_enabled) { - zoneID = RuleI(World, TutorialZoneID); - database.MoveCharacterToZone(charid, database.GetZoneName(zoneID)); + zone_id = RuleI(World, TutorialZoneID); + database.MoveCharacterToZone(charid, database.GetZoneName(zone_id)); } else { Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go to tutorial but are not allowed...", char_name); @@ -788,30 +814,30 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { } } - if (zoneID == 0 || !database.GetZoneName(zoneID)) { + if (zone_id == 0 || !database.GetZoneName(zone_id)) { // This is to save people in an invalid zone, once it's removed from the DB database.MoveCharacterToZone(charid, "arena"); - Log.Out(Logs::Detail, Logs::World_Server, "Zone not found in database zone_id=%i, moveing char to arena character:%s", zoneID, char_name); + Log.Out(Logs::Detail, Logs::World_Server, "Zone not found in database zone_id=%i, moveing char to arena character:%s", zone_id, char_name); } - if(instanceID > 0) + if(instance_id > 0) { - if(!database.VerifyInstanceAlive(instanceID, GetCharID())) + if(!database.VerifyInstanceAlive(instance_id, GetCharID())) { - zoneID = database.MoveCharacterToBind(charid); - instanceID = 0; + zone_id = database.MoveCharacterToBind(charid); + instance_id = 0; } else { - if(!database.VerifyZoneInstance(zoneID, instanceID)) + if(!database.VerifyZoneInstance(zone_id, instance_id)) { - zoneID = database.MoveCharacterToBind(charid); - instanceID = 0; + zone_id = database.MoveCharacterToBind(charid); + instance_id = 0; } } } - if(!pZoning) { + if(!is_player_zoning) { database.SetGroupID(char_name, 0, charid); database.SetLoginFlags(charid, false, false, 1); } @@ -833,12 +859,12 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { } outapp = new EQApplicationPacket(OP_MOTD); - char tmp[500] = {0}; - if (database.GetVariable("MOTD", tmp, 500)) { - outapp->size = strlen(tmp)+1; + std::string tmp; + if (database.GetVariable("MOTD", tmp)) { + outapp->size = tmp.length() + 1; outapp->pBuffer = new uchar[outapp->size]; memset(outapp->pBuffer,0,outapp->size); - strcpy((char*)outapp->pBuffer, tmp); + strcpy((char*)outapp->pBuffer, tmp.c_str()); } else { // Null Message of the Day. :) @@ -855,9 +881,9 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { char ConnectionType; - if (m_ClientVersionBit & BIT_UFAndLater) + if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) ConnectionType = 'U'; - else if (m_ClientVersionBit & BIT_SoFAndLater) + else if (m_ClientVersionBit & EQEmu::versions::bit_SoFAndLater) ConnectionType = 'S'; else ConnectionType = 'C'; @@ -881,7 +907,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { outapp2 = new EQApplicationPacket(OP_SetChatServer2); - if (m_ClientVersionBit & BIT_TitaniumAndEarlier) + if (m_ClientVersionBit & EQEmu::versions::bit_TitaniumAndEarlier) ConnectionType = 'M'; sprintf(buffer,"%s,%i,%s.%s,%c%08X", @@ -915,7 +941,7 @@ bool Client::HandleDeleteCharacterPacket(const EQApplicationPacket *app) { bool Client::HandleZoneChangePacket(const EQApplicationPacket *app) { // HoT sends this to world while zoning and wants it echoed back. - if (m_ClientVersionBit & BIT_RoFAndLater) + if (m_ClientVersionBit & EQEmu::versions::bit_RoFAndLater) { QueuePacket(app); } @@ -1033,8 +1059,8 @@ bool Client::Process() { to.sin_addr.s_addr = ip; if (autobootup_timeout.Check()) { - Log.Out(Logs::Detail, Logs::World_Server, "Zone bootup timer expired, bootup failed or too slow."); - ZoneUnavail(); + Log.Out(Logs::General, Logs::World_Server, "Zone bootup timer expired, bootup failed or too slow."); + TellClientZoneUnavailable(); } if(connect.Check()){ SendGuildList();// Send OPCode: OP_GuildsList @@ -1075,63 +1101,63 @@ bool Client::Process() { } void Client::EnterWorld(bool TryBootup) { - if (zoneID == 0) + if (zone_id == 0) return; - ZoneServer* zs = nullptr; - if(instanceID > 0) + ZoneServer* zone_server = nullptr; + if(instance_id > 0) { - if(database.VerifyInstanceAlive(instanceID, GetCharID())) + if(database.VerifyInstanceAlive(instance_id, GetCharID())) { - if(database.VerifyZoneInstance(zoneID, instanceID)) + if(database.VerifyZoneInstance(zone_id, instance_id)) { - zs = zoneserver_list.FindByInstanceID(instanceID); + zone_server = zoneserver_list.FindByInstanceID(instance_id); } else { - instanceID = 0; - zs = nullptr; + instance_id = 0; + zone_server = nullptr; database.MoveCharacterToBind(GetCharID()); - ZoneUnavail(); + TellClientZoneUnavailable(); return; } } else { - instanceID = 0; - zs = nullptr; + instance_id = 0; + zone_server = nullptr; database.MoveCharacterToBind(GetCharID()); - ZoneUnavail(); + TellClientZoneUnavailable(); return; } } else - zs = zoneserver_list.FindByZoneID(zoneID); + zone_server = zoneserver_list.FindByZoneID(zone_id); - const char *zone_name=database.GetZoneName(zoneID, true); - if (zs) { + const char *zone_name = database.GetZoneName(zone_id, true); + if (zone_server) { // warn the world we're comming, so it knows not to shutdown - zs->IncomingClient(this); + zone_server->IncomingClient(this); } else { if (TryBootup) { - Log.Out(Logs::Detail, Logs::World_Server,"Attempting autobootup of %s (%d:%d)",zone_name,zoneID,instanceID); + Log.Out(Logs::General, Logs::World_Server, "Attempting autobootup of %s (%d:%d)", zone_name, zone_id, instance_id); autobootup_timeout.Start(); - pwaitingforbootup = zoneserver_list.TriggerBootup(zoneID, instanceID); - if (pwaitingforbootup == 0) { - Log.Out(Logs::Detail, Logs::World_Server,"No zoneserver available to boot up."); - ZoneUnavail(); + zone_waiting_for_bootup = zoneserver_list.TriggerBootup(zone_id, instance_id); + if (zone_waiting_for_bootup == 0) { + Log.Out(Logs::General, Logs::World_Server, "No zoneserver available to boot up."); + TellClientZoneUnavailable(); } return; } else { - Log.Out(Logs::Detail, Logs::World_Server,"Requested zone %s is not running.",zone_name); - ZoneUnavail(); + Log.Out(Logs::General, Logs::World_Server, "Requested zone %s is not running.", zone_name); + TellClientZoneUnavailable(); return; } } - pwaitingforbootup = 0; + zone_waiting_for_bootup = 0; if(!cle) { return; @@ -1139,12 +1165,20 @@ void Client::EnterWorld(bool TryBootup) { cle->SetChar(charid, char_name); database.UpdateLiveChar(char_name, GetAccountID()); - Log.Out(Logs::Detail, Logs::World_Server,"%s %s (%d:%d)",seencharsel ? "Entering zone" : "Zoning to",zone_name,zoneID,instanceID); - if (seencharsel) { - if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zoneID)) { - Log.Out(Logs::Detail, Logs::World_Server,"Enter world failed. Zone is locked."); - ZoneUnavail(); + Log.Out(Logs::General, Logs::World_Server, + "(%s) %s %s (Zone ID %d: Instance ID: %d) ", + char_name, + (seen_character_select ? "Zoning from character select" : "Zoning to"), + zone_name, + zone_id, + instance_id + ); + + if (seen_character_select) { + if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zone_id)) { + Log.Out(Logs::General, Logs::World_Server, "Enter world failed. Zone is locked."); + TellClientZoneUnavailable(); return; } @@ -1156,7 +1190,7 @@ void Client::EnterWorld(bool TryBootup) { WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer; wtz->account_id = GetAccountID(); wtz->response = 0; - zs->SendPacket(pack); + zone_server->SendPacket(pack); delete pack; } else { // if they havent seen character select screen, we can assume this is a zone @@ -1168,13 +1202,13 @@ void Client::EnterWorld(bool TryBootup) { void Client::Clearance(int8 response) { ZoneServer* zs = nullptr; - if(instanceID > 0) + if(instance_id > 0) { - zs = zoneserver_list.FindByInstanceID(instanceID); + zs = zoneserver_list.FindByInstanceID(instance_id); } else { - zs = zoneserver_list.FindByZoneID(zoneID); + zs = zoneserver_list.FindByZoneID(zone_id); } if(zs == 0 || response == -1 || response == 0) @@ -1186,7 +1220,7 @@ void Client::Clearance(int8 response) Log.Out(Logs::Detail, Logs::World_Server, "Invalid response %d in Client::Clearance", response); } - ZoneUnavail(); + TellClientZoneUnavailable(); return; } @@ -1194,50 +1228,59 @@ void Client::Clearance(int8 response) if (zs->GetCAddress() == nullptr) { Log.Out(Logs::Detail, Logs::World_Server, "Unable to do zs->GetCAddress() in Client::Clearance!!"); - ZoneUnavail(); + TellClientZoneUnavailable(); return; } - if (zoneID == 0) { + if (zone_id == 0) { Log.Out(Logs::Detail, Logs::World_Server, "zoneID is nullptr in Client::Clearance!!"); - ZoneUnavail(); + TellClientZoneUnavailable(); return; } - const char* zonename = database.GetZoneName(zoneID); + const char* zonename = database.GetZoneName(zone_id); if (zonename == 0) { Log.Out(Logs::Detail, Logs::World_Server, "zonename is nullptr in Client::Clearance!!"); - ZoneUnavail(); + TellClientZoneUnavailable(); return; } - // @bp This is the chat server - /* - char packetData[] = "64.37.148.34.9876,MyServer,Testchar,23cd2c95"; - outapp = new EQApplicationPacket(OP_0x0282, sizeof(packetData)); - strcpy((char*)outapp->pBuffer, packetData); - QueuePacket(outapp); - delete outapp; - */ - // Send zone server IP data outapp = new EQApplicationPacket(OP_ZoneServerInfo, sizeof(ZoneServerInfo_Struct)); ZoneServerInfo_Struct* zsi = (ZoneServerInfo_Struct*)outapp->pBuffer; - const char *zs_addr=zs->GetCAddress(); - if (!zs_addr[0]) { - if (cle->IsLocalClient()) { + + const char *zs_addr = nullptr; + if(cle && cle->IsLocalClient()) { + const char *local_addr = zs->GetCLocalAddress(); + + if(local_addr[0]) { + zs_addr = local_addr; + } else { struct in_addr in; in.s_addr = zs->GetIP(); - zs_addr=inet_ntoa(in); - if (!strcmp(zs_addr,"127.0.0.1")) - zs_addr=WorldConfig::get()->LocalAddress.c_str(); + zs_addr = inet_ntoa(in); + + if(strcmp(zs_addr, "127.0.0.1") == 0) + { + Log.Out(Logs::Detail, Logs::World_Server, "Local zone address was %s, setting local address to: %s", zs_addr, WorldConfig::get()->LocalAddress.c_str()); + zs_addr = WorldConfig::get()->LocalAddress.c_str(); + } else { + Log.Out(Logs::Detail, Logs::World_Server, "Local zone address %s", zs_addr); + } + } + + } else { + const char *addr = zs->GetCAddress(); + if(addr[0]) { + zs_addr = addr; } else { - zs_addr=WorldConfig::get()->WorldAddress.c_str(); + zs_addr = WorldConfig::get()->WorldAddress.c_str(); } } + strcpy(zsi->ip, zs_addr); zsi->port =zs->GetCPort(); - Log.Out(Logs::Detail, Logs::World_Server,"Sending client to zone %s (%d:%d) at %s:%d",zonename,zoneID,instanceID,zsi->ip,zsi->port); + Log.Out(Logs::Detail, Logs::World_Server,"Sending client to zone %s (%d:%d) at %s:%d",zonename,zone_id,instance_id,zsi->ip,zsi->port); QueuePacket(outapp); safe_delete(outapp); @@ -1245,17 +1288,17 @@ void Client::Clearance(int8 response) cle->SetOnline(CLE_Status_Zoning); } -void Client::ZoneUnavail() { +void Client::TellClientZoneUnavailable() { auto outapp = new EQApplicationPacket(OP_ZoneUnavail, sizeof(ZoneUnavail_Struct)); ZoneUnavail_Struct* ua = (ZoneUnavail_Struct*)outapp->pBuffer; - const char* zonename = database.GetZoneName(zoneID); + const char* zonename = database.GetZoneName(zone_id); if (zonename) strcpy(ua->zonename, zonename); QueuePacket(outapp); delete outapp; - zoneID = 0; - pwaitingforbootup = 0; + zone_id = 0; + zone_waiting_for_bootup = 0; autobootup_timeout.Disable(); } @@ -1379,7 +1422,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) Log.Out(Logs::Detail, Logs::World_Server, "Beard: %d Beardcolor: %d", cc->beard, cc->beardcolor); /* Validate the char creation struct */ - if (m_ClientVersionBit & BIT_SoFAndLater) { + if (m_ClientVersionBit & EQEmu::versions::bit_SoFAndLater) { if (!CheckCharCreateInfoSoF(cc)) { Log.Out(Logs::Detail, Logs::World_Server,"CheckCharCreateInfo did not validate the request (bad race/class/stats)"); return false; @@ -1431,8 +1474,8 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) SetClassStartingSkills(&pp); SetClassLanguages(&pp); - pp.skills[SkillSwimming] = RuleI(Skills, SwimmingStartValue); - pp.skills[SkillSenseHeading] = RuleI(Skills, SenseHeadingStartValue); + pp.skills[EQEmu::skills::SkillSwimming] = RuleI(Skills, SwimmingStartValue); + pp.skills[EQEmu::skills::SkillSenseHeading] = RuleI(Skills, SenseHeadingStartValue); // strcpy(pp.servername, WorldConfig::get()->ShortName.c_str()); @@ -1440,7 +1483,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) for (i = 0; i < MAX_PP_REF_SPELLBOOK; i++) pp.spell_book[i] = 0xFFFFFFFF; - for(i = 0; i < MAX_PP_REF_MEMSPELL; i++) + for(i = 0; i < MAX_PP_MEMSPELL; i++) pp.mem_spells[i] = 0xFFFFFFFF; for(i = 0; i < BUFF_COUNT; i++) @@ -1450,7 +1493,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) pp.pvp = database.GetServerType() == 1 ? 1 : 0; /* If it is an SoF Client and the SoF Start Zone rule is set, send new chars there */ - if (m_ClientVersionBit & BIT_SoFAndLater) { + if (m_ClientVersionBit & EQEmu::versions::bit_SoFAndLater) { Log.Out(Logs::Detail, Logs::World_Server,"Found 'SoFStartZoneID' rule setting: %i", RuleI(World, SoFStartZoneID)); if (RuleI(World, SoFStartZoneID) > 0) { pp.zone_id = RuleI(World, SoFStartZoneID); @@ -1466,7 +1509,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) } } /* use normal starting zone logic to either get defaults, or if startzone was set, load that from the db table.*/ - bool ValidStartZone = database.GetStartZone(&pp, cc, m_ClientVersionBit & BIT_TitaniumAndEarlier); + bool ValidStartZone = database.GetStartZone(&pp, cc, m_ClientVersionBit & EQEmu::versions::bit_TitaniumAndEarlier); if (!ValidStartZone){ return false; @@ -1478,7 +1521,25 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) pp.x = pp.y = pp.z = -1; } - /* Set Home Binds */ + /* Set Home Binds -- yep, all of them */ + pp.binds[1].zoneId = pp.zone_id; + pp.binds[1].x = pp.x; + pp.binds[1].y = pp.y; + pp.binds[1].z = pp.z; + pp.binds[1].heading = pp.heading; + + pp.binds[2].zoneId = pp.zone_id; + pp.binds[2].x = pp.x; + pp.binds[2].y = pp.y; + pp.binds[2].z = pp.z; + pp.binds[2].heading = pp.heading; + + pp.binds[3].zoneId = pp.zone_id; + pp.binds[3].x = pp.x; + pp.binds[3].y = pp.y; + pp.binds[3].z = pp.z; + pp.binds[3].heading = pp.heading; + pp.binds[4].zoneId = pp.zone_id; pp.binds[4].x = pp.x; pp.binds[4].y = pp.y; @@ -1788,17 +1849,22 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc) void Client::SetClassStartingSkills(PlayerProfile_Struct *pp) { - for (uint32 i = 0; i <= HIGHEST_SKILL; ++i) { + for (uint32 i = 0; i <= EQEmu::skills::HIGHEST_SKILL; ++i) { if (pp->skills[i] == 0) { // Skip specialized, tradeskills (fishing excluded), Alcohol Tolerance, and Bind Wound - if (EQEmu::IsSpecializedSkill((SkillUseTypes)i) || - (EQEmu::IsTradeskill((SkillUseTypes)i) && i != SkillFishing) || - i == SkillAlcoholTolerance || i == SkillBindWound) + if (EQEmu::skills::IsSpecializedSkill((EQEmu::skills::SkillType)i) || + (EQEmu::skills::IsTradeskill((EQEmu::skills::SkillType)i) && i != EQEmu::skills::SkillFishing) || + i == EQEmu::skills::SkillAlcoholTolerance || i == EQEmu::skills::SkillBindWound) continue; - pp->skills[i] = database.GetSkillCap(pp->class_, (SkillUseTypes)i, 1); + pp->skills[i] = database.GetSkillCap(pp->class_, (EQEmu::skills::SkillType)i, 1); } } + + if (cle->GetClientVersion() < static_cast(EQEmu::versions::ClientVersion::RoF2) && pp->class_ == BERSERKER) { + pp->skills[EQEmu::skills::Skill1HPiercing] = pp->skills[EQEmu::skills::Skill2HPiercing]; + pp->skills[EQEmu::skills::Skill2HPiercing] = 0; + } } void Client::SetRaceStartingSkills( PlayerProfile_Struct *pp ) @@ -1820,41 +1886,41 @@ void Client::SetRaceStartingSkills( PlayerProfile_Struct *pp ) } case DARK_ELF: { - pp->skills[SkillHide] = 50; + pp->skills[EQEmu::skills::SkillHide] = 50; break; } case FROGLOK: { - pp->skills[SkillSwimming] = 125; + pp->skills[EQEmu::skills::SkillSwimming] = 125; break; } case GNOME: { - pp->skills[SkillTinkering] = 50; + pp->skills[EQEmu::skills::SkillTinkering] = 50; break; } case HALFLING: { - pp->skills[SkillHide] = 50; - pp->skills[SkillSneak] = 50; + pp->skills[EQEmu::skills::SkillHide] = 50; + pp->skills[EQEmu::skills::SkillSneak] = 50; break; } case IKSAR: { - pp->skills[SkillForage] = 50; - pp->skills[SkillSwimming] = 100; + pp->skills[EQEmu::skills::SkillForage] = 50; + pp->skills[EQEmu::skills::SkillSwimming] = 100; break; } case WOOD_ELF: { - pp->skills[SkillForage] = 50; - pp->skills[SkillHide] = 50; + pp->skills[EQEmu::skills::SkillForage] = 50; + pp->skills[EQEmu::skills::SkillHide] = 50; break; } case VAHSHIR: { - pp->skills[SkillSafeFall] = 50; - pp->skills[SkillSneak] = 50; + pp->skills[EQEmu::skills::SkillSafeFall] = 50; + pp->skills[EQEmu::skills::SkillSneak] = 50; break; } } @@ -1933,21 +1999,21 @@ void Client::SetRacialLanguages( PlayerProfile_Struct *pp ) } case IKSAR: { - pp->languages[LANG_COMMON_TONGUE] = 95; + pp->languages[LANG_COMMON_TONGUE] = RuleI(Character, IksarCommonTongue); pp->languages[LANG_DARK_SPEECH] = 100; pp->languages[LANG_LIZARDMAN] = 100; break; } case OGRE: { - pp->languages[LANG_COMMON_TONGUE] = 95; + pp->languages[LANG_COMMON_TONGUE] = RuleI(Character, OgreCommonTongue); pp->languages[LANG_DARK_SPEECH] = 100; pp->languages[LANG_OGRE] = 100; break; } case TROLL: { - pp->languages[LANG_COMMON_TONGUE] = 95; + pp->languages[LANG_COMMON_TONGUE] = RuleI(Character, TrollCommonTongue); pp->languages[LANG_DARK_SPEECH] = 100; pp->languages[LANG_TROLL] = 100; break; diff --git a/world/client.h b/world/client.h index d7a42ab28..391a20c1d 100644 --- a/world/client.h +++ b/world/client.h @@ -45,7 +45,7 @@ public: void SendMembership(); void SendMembershipSettings(); void EnterWorld(bool TryBootup = true); - void ZoneUnavail(); + void TellClientZoneUnavailable(); void QueuePacket(const EQApplicationPacket* app, bool ack_req = true); void Clearance(int8 response); void SendGuildList(); @@ -58,9 +58,9 @@ public: inline uint32 GetIP() { return ip; } inline uint16 GetPort() { return port; } - inline uint32 GetZoneID() { return zoneID; } - inline uint32 GetInstanceID() { return instanceID; } - inline uint32 WaitingForBootup() { return pwaitingforbootup; } + inline uint32 GetZoneID() { return zone_id; } + inline uint32 GetInstanceID() { return instance_id; } + inline uint32 WaitingForBootup() { return zone_waiting_for_bootup; } inline const char * GetAccountName() { if (cle) { return cle->AccountName(); } return "NOCLE"; } inline int16 GetAdmin() { if (cle) { return cle->Admin(); } return 0; } inline uint32 GetAccountID() { if (cle) { return cle->AccountID(); } return 0; } @@ -77,14 +77,14 @@ private: uint16 port; uint32 charid; char char_name[64]; - uint32 zoneID; - uint32 instanceID; - bool pZoning; + uint32 zone_id; + uint32 instance_id; + bool is_player_zoning; Timer autobootup_timeout; - uint32 pwaitingforbootup; + uint32 zone_waiting_for_bootup; bool StartInTutorial; - ClientVersion m_ClientVersion; + EQEmu::versions::ClientVersion m_ClientVersion; uint32 m_ClientVersionBit; bool OPCharCreate(char *name, CharCreate_Struct *cc); @@ -97,7 +97,7 @@ private: Timer CLE_keepalive_timer; Timer connect; bool firstlogin; - bool seencharsel; + bool seen_character_select; bool realfirstlogin; bool HandlePacket(const EQApplicationPacket *app); diff --git a/world/cliententry.cpp b/world/cliententry.cpp index 5e896dca0..a67c45c39 100644 --- a/world/cliententry.cpp +++ b/world/cliententry.cpp @@ -277,10 +277,10 @@ bool ClientListEntry::CheckAuth(uint32 iLSID, const char* iKey) { strn0cpy(paccountname, plsname, sizeof(paccountname)); padmin = tmpStatus; } - char lsworldadmin[15] = "0"; - database.GetVariable("honorlsworldadmin", lsworldadmin, sizeof(lsworldadmin)); - if (atoi(lsworldadmin) == 1 && pworldadmin != 0 && (padmin < pworldadmin || padmin == 0)) - padmin = pworldadmin; + std::string lsworldadmin; + if (database.GetVariable("honorlsworldadmin", lsworldadmin)) + if (atoi(lsworldadmin.c_str()) == 1 && pworldadmin != 0 && (padmin < pworldadmin || padmin == 0)) + padmin = pworldadmin; return true; } return false; diff --git a/world/clientlist.cpp b/world/clientlist.cpp index b6b22a6d4..7c83701f4 100644 --- a/world/clientlist.cpp +++ b/world/clientlist.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2005 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,6 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include "../common/global_define.h" #include "clientlist.h" #include "zoneserver.h" @@ -748,7 +749,7 @@ void ClientList::SendWhoAll(uint32 fromid,const char* to, int16 admin, Who_All_S //zoneserver_list.SendPacket(pack2); // NO NO NO WHY WOULD YOU SEND IT TO EVERY ZONE SERVER?!? SendPacket(to,pack2); safe_delete(pack2); - safe_delete(output); + safe_delete_array(output); } catch(...){ Log.Out(Logs::Detail, Logs::World_Server,"Unknown error in world's SendWhoAll (probably mem error), ignoring..."); @@ -1064,7 +1065,7 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct* if (cle->Anon() == 2) { // Roleplay if (admin >= 100 && admin >= cle->Admin()) - sprintf(line, " %s[RolePlay %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetEQClassName(cle->class_(),cle->level()), cle->name(), GetRaceName(cle->race()), tmpguild, tmpZone, LFG, accinfo); + sprintf(line, " %s[RolePlay %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetClassIDName(cle->class_(),cle->level()), cle->name(), GetRaceIDName(cle->race()), tmpguild, tmpZone, LFG, accinfo); else if (cle->Admin() >= 80 && admin < 80 && cle->GetGM()) { iterator.Advance(); continue; @@ -1074,7 +1075,7 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct* } else if (cle->Anon() == 1) { // Anon if (admin >= 100 && admin >= cle->Admin()) - sprintf(line, " %s[ANON %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetEQClassName(cle->class_(),cle->level()), cle->name(), GetRaceName(cle->race()), tmpguild, tmpZone, LFG, accinfo); + sprintf(line, " %s[ANON %i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetClassIDName(cle->class_(),cle->level()), cle->name(), GetRaceIDName(cle->race()), tmpguild, tmpZone, LFG, accinfo); else if (cle->Admin() >= 80 && cle->GetGM()) { iterator.Advance(); continue; @@ -1083,7 +1084,7 @@ void ClientList::ConsoleSendWhoAll(const char* to, int16 admin, Who_All_Struct* sprintf(line, " %s[ANONYMOUS] %s%s%s", tmpgm, cle->name(), LFG, accinfo); } else - sprintf(line, " %s[%i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetEQClassName(cle->class_(),cle->level()), cle->name(), GetRaceName(cle->race()), tmpguild, tmpZone, LFG, accinfo); + sprintf(line, " %s[%i %s] %s (%s)%s zone: %s%s%s", tmpgm, cle->level(), GetClassIDName(cle->class_(),cle->level()), cle->name(), GetRaceIDName(cle->race()), tmpguild, tmpZone, LFG, accinfo); AppendAnyLenString(&output, &outsize, &outlen, line); if (outlen >= 3584) { @@ -1183,7 +1184,7 @@ void ClientList::ZoneBootup(ZoneServer* zs) { iterator.GetData()->EnterWorld(false); } else if (iterator.GetData()->WaitingForBootup() == zs->GetID()) { - iterator.GetData()->ZoneUnavail(); + iterator.GetData()->TellClientZoneUnavailable(); } } iterator.Advance(); diff --git a/world/eqw.cpp b/world/eqw.cpp index 04d5d4c8b..2bed01919 100644 --- a/world/eqw.cpp +++ b/world/eqw.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -193,9 +193,9 @@ std::map EQW::GetPlayerDetails(Const_char *char_name) { res["location_id"] = itoa(cle->zone()); res["ip"] = long2ip(cle->GetIP()); res["level"] = itoa(cle->level()); - res["race"] = GetRaceName(cle->race()); + res["race"] = GetRaceIDName(cle->race()); res["race_id"] = itoa(cle->race()); - res["class"] = GetEQClassName(cle->class_()); + res["class"] = GetClassIDName(cle->class_()); res["class_id"] = itoa(cle->class_()); res["guild_id"] = itoa(cle->GuildID()); res["guild"] = guild_mgr.GetGuildName(cle->GuildID()); diff --git a/world/eqw_parser.cpp b/world/eqw_parser.cpp index 79e73ac22..e01f3db3b 100644 --- a/world/eqw_parser.cpp +++ b/world/eqw_parser.cpp @@ -227,7 +227,7 @@ bool EQWParser::dosub(const char * subname, const std::vector &args ENTER; // everything created after here SAVETMPS; // ...is a temporary variable PUSHMARK(SP); // remember the stack pointer - if(args.size() > 0) + if(!args.empty()) { for (auto i = args.begin(); i != args.end(); ++i) { /* push the arguments onto the perl stack */ XPUSHs(sv_2mortal(newSVpv(i->c_str(), i->length()))); diff --git a/world/launcher_link.cpp b/world/launcher_link.cpp index bd8bfdc4b..33adba6a8 100644 --- a/world/launcher_link.cpp +++ b/world/launcher_link.cpp @@ -60,7 +60,7 @@ bool LauncherLink::Process() { end = m_states.end(); for(; cur != end; ++cur) { if(!cur->second.up) { - StartZone(cur->first.c_str()); + StartZone(cur->first.c_str(), cur->second.port); } } m_bootTimer.Disable(); @@ -184,14 +184,6 @@ bool LauncherLink::Process() { bool LauncherLink::ContainsZone(const char *short_name) const { return(m_states.find(short_name) != m_states.end()); - - /* - * std::map::const_iterator cur, end; - cur = m_states.begin(); - end = m_states.end(); - for(; cur != end; cur++) { - if( - }*/ } void LauncherLink::BootZone(const char *short_name, uint16 port) { @@ -202,15 +194,20 @@ void LauncherLink::BootZone(const char *short_name, uint16 port) { Log.Out(Logs::Detail, Logs::World_Server, "%s: Loaded zone '%s' on port %d", m_name.c_str(), short_name, zs.port); m_states[short_name] = zs; - StartZone(short_name); + StartZone(short_name, port); } void LauncherLink::StartZone(const char *short_name) { + StartZone(short_name, 0); +} + +void LauncherLink::StartZone(const char *short_name, uint16 port) { auto pack = new ServerPacket(ServerOP_LauncherZoneRequest, sizeof(LauncherZoneRequest)); LauncherZoneRequest* s = (LauncherZoneRequest *) pack->pBuffer; strn0cpy(s->short_name, short_name, 32); s->command = ZR_Start; + s->port = port; SendPacket(pack); delete pack; @@ -222,6 +219,7 @@ void LauncherLink::RestartZone(const char *short_name) { strn0cpy(s->short_name, short_name, 32); s->command = ZR_Restart; + s->port = 0; SendPacket(pack); delete pack; @@ -233,6 +231,7 @@ void LauncherLink::StopZone(const char *short_name) { strn0cpy(s->short_name, short_name, 32); s->command = ZR_Stop; + s->port = 0; SendPacket(pack); delete pack; @@ -332,35 +331,3 @@ void LauncherLink::Shutdown() { SendPacket(pack); delete pack; } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/world/launcher_link.h b/world/launcher_link.h index d1d8b6d61..35cbbcfea 100644 --- a/world/launcher_link.h +++ b/world/launcher_link.h @@ -50,6 +50,7 @@ public: void Shutdown(); void BootZone(const char *short_name, uint16 port); void StartZone(const char *short_name); + void StartZone(const char *short_name, uint16 port); void RestartZone(const char *short_name); void StopZone(const char *short_name); void BootDynamics(uint8 new_total); diff --git a/world/login_server.cpp b/world/login_server.cpp index 450ecb0a3..b8c23d573 100644 --- a/world/login_server.cpp +++ b/world/login_server.cpp @@ -25,8 +25,8 @@ #ifdef _WINDOWS #include + #include #include - #include #define snprintf _snprintf #define strncasecmp _strnicmp @@ -145,7 +145,7 @@ bool LoginServer::Process() { break; } case ServerOP_LSClientAuth: { - ServerLSClientAuth* slsca = (ServerLSClientAuth*) pack->pBuffer; + ClientAuth_Struct* slsca = (ClientAuth_Struct*) pack->pBuffer; if (RuleI(World, AccountSessionLimit) >= 0) { // Enforce the limit on the number of characters on the same account that can be @@ -212,8 +212,8 @@ bool LoginServer::InitLoginServer() { } bool LoginServer::Connect() { - char tmp[25]; - if(database.GetVariable("loginType",tmp,sizeof(tmp)) && strcasecmp(tmp,"MinILogin") == 0){ + std::string tmp; + if(database.GetVariable("loginType", tmp) && strcasecmp(tmp.c_str(), "MinILogin") == 0) { minilogin = true; Log.Out(Logs::Detail, Logs::World_Server, "Setting World to MiniLogin Server type"); } diff --git a/world/net.cpp b/world/net.cpp index 6f4b8213e..d20edc32e 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -107,7 +107,7 @@ volatile bool RunLoops = true; uint32 numclients = 0; uint32 numzones = 0; bool holdzones = false; - +const WorldConfig *Config; EQEmuLogSys Log; extern ConsoleList console_list; @@ -117,14 +117,18 @@ void CatchSignal(int sig_num); int main(int argc, char** argv) { RegisterExecutablePlatform(ExePlatformWorld); Log.LoadLogSettingsDefaults(); + + + set_exception_handler(); register_remote_call_handlers(); /* Database Version Check */ uint32 Database_Version = CURRENT_BINARY_DATABASE_VERSION; + uint32 Bots_Database_Version = CURRENT_BINARY_BOTS_DATABASE_VERSION; if (argc >= 2) { if (strcasecmp(argv[1], "db_version") == 0) { - std::cout << "Binary Database Version: " << Database_Version << std::endl; + std::cout << "Binary Database Version: " << Database_Version << " : " << Bots_Database_Version << std::endl; return 0; } } @@ -135,7 +139,7 @@ int main(int argc, char** argv) { Log.Out(Logs::General, Logs::World_Server, "Loading server configuration failed."); return 1; } - const WorldConfig *Config=WorldConfig::get(); + Config=WorldConfig::get(); Log.Out(Logs::General, Logs::World_Server, "CURRENT_VERSION: %s", CURRENT_VERSION); @@ -193,7 +197,7 @@ int main(int argc, char** argv) { bool ignore_db = false; if (argc >= 2) { - char tmp[2]; + std::string tmp; if (strcasecmp(argv[1], "help") == 0 || strcasecmp(argv[1], "?") == 0 || strcasecmp(argv[1], "/?") == 0 || strcasecmp(argv[1], "-?") == 0 || strcasecmp(argv[1], "-h") == 0 || strcasecmp(argv[1], "-help") == 0) { std::cout << "Worldserver command line commands:" << std::endl; std::cout << "adduser username password flag - adds a user account" << std::endl; @@ -206,8 +210,8 @@ int main(int argc, char** argv) { std::cout << "Reboot Zones mode ON" << std::endl; holdzones = true; } - else if (database.GetVariable("disablecommandline", tmp, 2)) { - if (strlen(tmp) == 1) { + else if (database.GetVariable("disablecommandline", tmp)) { + if (tmp.length() == 1) { if (tmp[0] == '1') { std::cerr << "Command line disabled in database... exiting" << std::endl; return 1; @@ -298,6 +302,14 @@ int main(int argc, char** argv) { } Log.Out(Logs::General, Logs::World_Server, "Loading variables.."); database.LoadVariables(); + + std::string hotfix_name; + if(database.GetVariable("hotfix_name", hotfix_name)) { + if (!hotfix_name.empty()) { + Log.Out(Logs::General, Logs::Zone_Server, "Current hotfix in use: '%s'", hotfix_name.c_str()); + } + } + Log.Out(Logs::General, Logs::World_Server, "Loading zones.."); database.LoadZoneNames(); Log.Out(Logs::General, Logs::World_Server, "Clearing groups.."); @@ -306,27 +318,29 @@ int main(int argc, char** argv) { database.ClearRaid(); database.ClearRaidDetails(); database.ClearRaidLeader(); + Log.Out(Logs::General, Logs::World_Server, "Clearing inventory snapshots.."); + database.ClearInvSnapshots(); Log.Out(Logs::General, Logs::World_Server, "Loading items.."); - if (!database.LoadItems()) + if(!database.LoadItems(hotfix_name)) Log.Out(Logs::General, Logs::World_Server, "Error: Could not load item data. But ignoring"); Log.Out(Logs::General, Logs::World_Server, "Loading skill caps.."); - if (!database.LoadSkillCaps()) + if(!database.LoadSkillCaps(std::string(hotfix_name))) Log.Out(Logs::General, Logs::World_Server, "Error: Could not load skill cap data. But ignoring"); Log.Out(Logs::General, Logs::World_Server, "Loading guilds.."); guild_mgr.LoadGuilds(); //rules: { - char tmp[64]; - if (database.GetVariable("RuleSet", tmp, sizeof(tmp)-1)) { - Log.Out(Logs::General, Logs::World_Server, "Loading rule set '%s'", tmp); - if(!RuleManager::Instance()->LoadRules(&database, tmp)) { - Log.Out(Logs::General, Logs::World_Server, "Failed to load ruleset '%s', falling back to defaults.", tmp); + std::string tmp; + if (database.GetVariable("RuleSet", tmp)) { + Log.Out(Logs::General, Logs::World_Server, "Loading rule set '%s'", tmp.c_str()); + if(!RuleManager::Instance()->LoadRules(&database, tmp.c_str())) { + Log.Out(Logs::General, Logs::World_Server, "Failed to load ruleset '%s', falling back to defaults.", tmp.c_str()); } } else { if(!RuleManager::Instance()->LoadRules(&database, "default")) { Log.Out(Logs::General, Logs::World_Server, "No rule set configured, using default rules"); } else { - Log.Out(Logs::General, Logs::World_Server, "Loaded default rule set 'default'", tmp); + Log.Out(Logs::General, Logs::World_Server, "Loaded default rule set 'default'", tmp.c_str()); } } } @@ -335,15 +349,19 @@ int main(int argc, char** argv) { database.ClearMerchantTemp(); } Log.Out(Logs::General, Logs::World_Server, "Loading EQ time of day.."); - if (!zoneserver_list.worldclock.loadFile(Config->EQTimeFile.c_str())) - Log.Out(Logs::General, Logs::World_Server, "Unable to load %s", Config->EQTimeFile.c_str()); + TimeOfDay_Struct eqTime; + time_t realtime; + eqTime = database.LoadTime(realtime); + zoneserver_list.worldclock.SetCurrentEQTimeOfDay(eqTime, realtime); + Timer EQTimeTimer(600000); + EQTimeTimer.Start(600000); + Log.Out(Logs::General, Logs::World_Server, "Loading launcher list.."); launcher_list.LoadList(); - char tmp[20]; - tmp[0] = '\0'; - database.GetVariable("holdzones",tmp, 20); - if ((strcasecmp(tmp, "1") == 0)) { + std::string tmp; + database.GetVariable("holdzones",tmp); + if (tmp.length() == 1 && tmp[0] == '1') { holdzones = true; } Log.Out(Logs::General, Logs::World_Server, "Reboot zone modes %s",holdzones ? "ON" : "OFF"); @@ -412,7 +430,7 @@ int main(int argc, char** argv) { //structures and opcodes for that patch. struct in_addr in; in.s_addr = eqs->GetRemoteIP(); - Log.Out(Logs::General, Logs::World_Server, "New connection from %s:%d", inet_ntoa(in),ntohs(eqs->GetRemotePort())); + Log.Out(Logs::Detail, Logs::World_Server, "New connection from IP %s:%d", inet_ntoa(in),ntohs(eqs->GetRemotePort())); stream_identifier.AddStream(eqs); //takes the stream } @@ -427,9 +445,9 @@ int main(int argc, char** argv) { struct in_addr in; in.s_addr = eqsi->GetRemoteIP(); if (RuleB(World, UseBannedIPsTable)){ //Lieka: Check to see if we have the responsibility for blocking IPs. - Log.Out(Logs::General, Logs::World_Server, "Checking inbound connection %s against BannedIPs table", inet_ntoa(in)); + Log.Out(Logs::Detail, Logs::World_Server, "Checking inbound connection %s against BannedIPs table", inet_ntoa(in)); if (!database.CheckBannedIPs(inet_ntoa(in))){ //Lieka: Check inbound IP against banned IP table. - Log.Out(Logs::General, Logs::World_Server, "Connection %s PASSED banned IPs check. Processing connection.", inet_ntoa(in)); + Log.Out(Logs::Detail, Logs::World_Server, "Connection %s PASSED banned IPs check. Processing connection.", inet_ntoa(in)); auto client = new Client(eqsi); // @merth: client->zoneattempt=0; client_list.Add(client); @@ -439,7 +457,7 @@ int main(int argc, char** argv) { } } if (!RuleB(World, UseBannedIPsTable)){ - Log.Out(Logs::General, Logs::World_Server, "New connection from %s:%d, processing connection", inet_ntoa(in), ntohs(eqsi->GetRemotePort())); + Log.Out(Logs::Detail, Logs::World_Server, "New connection from %s:%d, processing connection", inet_ntoa(in), ntohs(eqsi->GetRemotePort())); auto client = new Client(eqsi); // @merth: client->zoneattempt=0; client_list.Add(client); @@ -451,7 +469,26 @@ int main(int argc, char** argv) { while ((tcpc = tcps.NewQueuePop())) { struct in_addr in; in.s_addr = tcpc->GetrIP(); - Log.Out(Logs::General, Logs::World_Server, "New TCP connection from %s:%d", inet_ntoa(in),tcpc->GetrPort()); + + /* World - Tell what is being connected */ + if (tcpc->GetMode() == EmuTCPConnection::modePacket) { + if (tcpc->GetPacketMode() == EmuTCPConnection::packetModeZone) { + Log.Out(Logs::General, Logs::World_Server, "New Zone Server from %s:%d", inet_ntoa(in), tcpc->GetrPort()); + } + else if (tcpc->GetPacketMode() == EmuTCPConnection::packetModeLauncher) { + Log.Out(Logs::General, Logs::World_Server, "New Launcher from %s:%d", inet_ntoa(in), tcpc->GetrPort()); + } + else if (tcpc->GetPacketMode() == EmuTCPConnection::packetModeUCS) { + Log.Out(Logs::General, Logs::World_Server, "New UCS Connection from %s:%d", inet_ntoa(in), tcpc->GetrPort()); + } + else if (tcpc->GetPacketMode() == EmuTCPConnection::packetModeQueryServ) { + Log.Out(Logs::General, Logs::World_Server, "New QS Connection from %s:%d", inet_ntoa(in), tcpc->GetrPort()); + } + else { + Log.Out(Logs::General, Logs::World_Server, "Unsupported packet mode from %s:%d", inet_ntoa(in), tcpc->GetrPort()); + } + } + console_list.Add(new Console(tcpc)); } @@ -460,6 +497,16 @@ int main(int argc, char** argv) { database.PurgeExpiredInstances(); } + if (EQTimeTimer.Check()) + { + TimeOfDay_Struct tod; + zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(0), &tod); + if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year)) + Log.Out(Logs::General, Logs::World_Server, "Failed to save eqtime."); + else + Log.Out(Logs::Detail, Logs::World_Server, "EQTime successfully saved."); + } + //check for timeouts in other threads timeout_manager.CheckTimeouts(); loginserverlist.Process(); @@ -478,19 +525,16 @@ int main(int argc, char** argv) { if (InterserverTimer.Check()) { InterserverTimer.Start(); database.ping(); - // AsyncLoadVariables(dbasync, &database); - ReconnectCounter++; - if (ReconnectCounter >= 12) { // only create thread to reconnect every 10 minutes. previously we were creating a new thread every 10 seconds - ReconnectCounter = 0; - if (loginserverlist.AllConnected() == false) { + + if (loginserverlist.AllConnected() == false) { #ifdef _WINDOWS - _beginthread(AutoInitLoginServer, 0, nullptr); + _beginthread(AutoInitLoginServer, 0, nullptr); #else - pthread_t thread; - pthread_create(&thread, nullptr, &AutoInitLoginServer, nullptr); + pthread_t thread; + pthread_create(&thread, nullptr, &AutoInitLoginServer, nullptr); #endif - } } + } if (numclients == 0) { Sleep(50); @@ -516,8 +560,6 @@ int main(int argc, char** argv) { void CatchSignal(int sig_num) { Log.Out(Logs::General, Logs::World_Server,"Caught signal %d",sig_num); - if(zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str())==false) - Log.Out(Logs::General, Logs::World_Server,"Failed to save time file."); RunLoops = false; } diff --git a/world/net.h b/world/net.h index b343c8d68..5af1ef96a 100644 --- a/world/net.h +++ b/world/net.h @@ -26,8 +26,8 @@ #else #include #include + #include #include - #include #endif void CatchSignal(int sig_num); diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 4b2a75ac6..8d65f7a78 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -36,15 +36,15 @@ extern std::vector character_create_race_class_combos; void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit) { /* Set Character Creation Limit */ - ClientVersion client_version = ClientVersionFromBit(clientVersionBit); - size_t character_limit = EQLimits::CharacterCreationLimit(client_version); + EQEmu::versions::ClientVersion client_version = EQEmu::versions::ConvertClientVersionBitToClientVersion(clientVersionBit); + size_t character_limit = EQEmu::constants::Lookup(client_version)->CharacterCreationLimit; // Validate against absolute server max - if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT) - character_limit = EmuConstants::CHARACTER_CREATION_LIMIT; + if (character_limit > EQEmu::constants::CharacterCreationMax) + character_limit = EQEmu::constants::CharacterCreationMax; // Force Titanium clients to use '8' - if (client_version == ClientVersion::Titanium) + if (client_version == EQEmu::versions::ClientVersion::Titanium) character_limit = 8; /* Get Character Info */ @@ -105,6 +105,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou memset(&pp, 0, sizeof(PlayerProfile_Struct)); /* Fill CharacterSelectEntry_Struct */ + memset(cse->Name, 0, sizeof(cse->Name)); strcpy(cse->Name, row[1]); cse->Class = (uint8)atoi(row[4]); cse->Race = (uint32)atoi(row[3]); @@ -116,13 +117,13 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou cse->Gender = (uint8)atoi(row[2]); cse->Face = (uint8)atoi(row[15]); - for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) { // Processed below + for (uint32 matslot = 0; matslot < EQEmu::textures::TextureCount; matslot++) { // Processed below cse->Equip[matslot].Material = 0; cse->Equip[matslot].Unknown1 = 0; cse->Equip[matslot].EliteMaterial = 0; cse->Equip[matslot].HeroForgeModel = 0; cse->Equip[matslot].Material2 = 0; - cse->Equip[matslot].Color.Color = 0; + cse->Equip[matslot].Color = 0; } cse->Unknown15 = 0xFF; @@ -158,10 +159,22 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou } /* Set Bind Point Data for any character that may possibly be missing it for any reason */ - cquery = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `is_home` FROM `character_bind` WHERE `id` = %i LIMIT 2", character_id); + cquery = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `slot` FROM `character_bind` WHERE `id` = %i LIMIT 5", character_id); auto results_bind = database.QueryDatabase(cquery); + auto bind_count = results_bind.RowCount(); for (auto row_b = results_bind.begin(); row_b != results_bind.end(); ++row_b) { - if (row_b[6] && atoi(row_b[6]) == 1){ has_home = 1; } + if (row_b[6] && atoi(row_b[6]) == 4) { + has_home = 1; + // If our bind count is less than 5, we need to actually make use of this data so lets parse it + if (bind_count < 5) { + pp.binds[4].zoneId = atoi(row_b[0]); + pp.binds[4].instance_id = atoi(row_b[1]); + pp.binds[4].x = atof(row_b[2]); + pp.binds[4].y = atof(row_b[3]); + pp.binds[4].z = atof(row_b[4]); + pp.binds[4].heading = atof(row_b[5]); + } + } if (row_b[6] && atoi(row_b[6]) == 0){ has_bind = 1; } } @@ -188,19 +201,33 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou pp.binds[0] = pp.binds[4]; /* If no home bind set, set it */ if (has_home == 0) { - std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" + std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)" " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", - character_id, pp.binds[4].zoneId, 0, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z, pp.binds[4].heading, 1); + character_id, pp.binds[4].zoneId, 0, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z, pp.binds[4].heading, 4); auto results_bset = QueryDatabase(query); } /* If no regular bind set, set it */ if (has_bind == 0) { - std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" + std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)" " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", character_id, pp.binds[0].zoneId, 0, pp.binds[0].x, pp.binds[0].y, pp.binds[0].z, pp.binds[0].heading, 0); auto results_bset = QueryDatabase(query); } } + /* If our bind count is less than 5, then we have null data that needs to be filled in. */ + if (bind_count < 5) { + // we know that home and main bind must be valid here, so we don't check those + // we also use home to fill in the null data like live does. + for (int i = 1; i < 4; i++) { + if (pp.binds[i].zoneId != 0) // we assume 0 is the only invalid one ... + continue; + + std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)" + " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", + character_id, pp.binds[4].zoneId, 0, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z, pp.binds[4].heading, i); + auto results_bset = QueryDatabase(query); + } + } /* Bind End */ /* Load Character Material Data for Char Select */ @@ -208,21 +235,21 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou auto results_b = database.QueryDatabase(cquery); uint8 slot = 0; for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) { slot = atoi(row_b[0]); - pp.item_tint[slot].RGB.Red = atoi(row_b[1]); - pp.item_tint[slot].RGB.Green = atoi(row_b[2]); - pp.item_tint[slot].RGB.Blue = atoi(row_b[3]); - pp.item_tint[slot].RGB.UseTint = atoi(row_b[4]); + pp.item_tint.Slot[slot].Red = atoi(row_b[1]); + pp.item_tint.Slot[slot].Green = atoi(row_b[2]); + pp.item_tint.Slot[slot].Blue = atoi(row_b[3]); + pp.item_tint.Slot[slot].UseTint = atoi(row_b[4]); } /* Character Material Data End */ /* Load Inventory */ // If we ensure that the material data is updated appropriately, we can do away with inventory loads if (GetInventory(accountID, cse->Name, &inv)) { - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; const ItemInst* inst = nullptr; int16 invslot = 0; - for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) { + for (uint32 matslot = 0; matslot < EQEmu::textures::TextureCount; matslot++) { invslot = Inventory::CalcSlotFromMaterial(matslot); if (invslot == INVALID_INDEX) { continue; } inst = inv.GetItem(invslot); @@ -243,7 +270,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou cse->Equip[matslot].Material = idfile; } } - if (matslot == MaterialPrimary) { + if (matslot == EQEmu::textures::TexturePrimary) { cse->PrimaryIDFile = idfile; } else { @@ -252,8 +279,8 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou } else { uint32 color = 0; - if (pp.item_tint[matslot].RGB.UseTint) { - color = pp.item_tint[matslot].Color; + if (pp.item_tint.Slot[matslot].UseTint) { + color = pp.item_tint.Slot[matslot].Color; } else { color = inst->GetColor(); @@ -263,7 +290,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou cse->Equip[matslot].Material = item->Material; cse->Equip[matslot].EliteMaterial = item->EliteMaterial; cse->Equip[matslot].HeroForgeModel = inst->GetOrnamentHeroModel(matslot); - cse->Equip[matslot].Color.Color = color; + cse->Equip[matslot].Color = color; } } } @@ -284,7 +311,7 @@ int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) bindnum = 0; } - std::string query = StringFormat("SELECT zone_id, instance_id, x, y, z FROM character_bind WHERE id = %u AND is_home = %u LIMIT 1", CharID, bindnum == 4 ? 1 : 0); + std::string query = StringFormat("SELECT zone_id, instance_id, x, y, z FROM character_bind WHERE id = %u AND slot = %u LIMIT 1", CharID, bindnum); auto results = database.QueryDatabase(query); if(!results.Success() || results.RowCount() == 0) { return 0; diff --git a/world/zonelist.cpp b/world/zonelist.cpp index 22d783f5d..55600c367 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -88,7 +88,7 @@ void ZSList::Process() { Process(); CatchSignal(2); } - if(reminder && reminder->Check()){ + if(reminder && reminder->Check() && shutdowntimer){ SendEmoteMessage(0,0,0,15,":SYSTEM MSG:World coming down, everyone log out now. World will shut down in %i minutes...", ((shutdowntimer->GetRemainingTime()/1000) / 60)); } LinkedListIterator iterator(list); @@ -283,57 +283,84 @@ void ZSList::ListLockedZones(const char* to, WorldTCPConnection* connection) { } void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* connection) { + LinkedListIterator iterator(list); struct in_addr in; iterator.Reset(); char locked[4]; - if (WorldConfig::get()->Locked == true) + if (WorldConfig::get()->Locked == true){ strcpy(locked, "Yes"); - else + } + else { strcpy(locked, "No"); + } char* output = 0; uint32 outsize = 0, outlen = 0; - if (connection->IsConsole()) + + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "World Locked: %s\r\n", locked); - else + } + else{ AppendAnyLenString(&output, &outsize, &outlen, "World Locked: %s^", locked); - if (connection->IsConsole()) + } + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "Zoneservers online:\r\n"); - else + } + else{ AppendAnyLenString(&output, &outsize, &outlen, "Zoneservers online:^"); -// connection->SendEmoteMessage(to, 0, 0, 0, "World Locked: %s", locked); -// connection->SendEmoteMessage(to, 0, 0, 0, "Zoneservers online:"); - int v=0, w=0, x=0, y=0, z=0; - char tmpStatic[2] = { 0, 0 }, tmpZone[64]; - memset(tmpZone, 0, sizeof(tmpZone)); - ZoneServer* zs = 0; - while(iterator.MoreElements()) { - zs = iterator.GetData(); - in.s_addr = zs->GetIP(); + } - if(zs->IsStaticZone()) + int v = 0, w = 0, x = 0, y = 0, z = 0; + char is_static_string[2] = { 0, 0 }, zone_data_string[64]; + memset(zone_data_string, 0, sizeof(zone_data_string)); + + ZoneServer* zone_server_data = 0; + + while (iterator.MoreElements()) { + zone_server_data = iterator.GetData(); + in.s_addr = zone_server_data->GetIP(); + + if (zone_server_data->IsStaticZone()){ z++; - else if (zs->GetZoneID() != 0) + } + else if (zone_server_data->GetZoneID() != 0){ w++; - else if(zs->GetZoneID() == 0 && !zs->IsBootingUp()) + } + else if (zone_server_data->GetZoneID() == 0 && !zone_server_data->IsBootingUp()){ v++; + } - if (zs->IsStaticZone()) - tmpStatic[0] = 'S'; + if (zone_server_data->IsStaticZone()) + is_static_string[0] = 'S'; else - tmpStatic[0] = ' '; + is_static_string[0] = 'D'; if (admin >= 150) { - if (zs->GetZoneID()) - snprintf(tmpZone, sizeof(tmpZone), "%s (%i)", zs->GetZoneName(), zs->GetZoneID()); - else if (zs->IsBootingUp()) - strcpy(tmpZone, "..."); - else - tmpZone[0] = 0; + if (zone_server_data->GetZoneID()){ + snprintf(zone_data_string, sizeof(zone_data_string), "%s (%i)", zone_server_data->GetZoneName(), zone_server_data->GetZoneID()); + } + else if (zone_server_data->IsBootingUp()){ + strcpy(zone_data_string, "..."); + } + else{ + zone_data_string[0] = 0; + } - AppendAnyLenString(&output, &outsize, &outlen, " #%-3i %s %15s:%-5i %2i %s:%i %s", zs->GetID(), tmpStatic, inet_ntoa(in), zs->GetPort(), zs->NumPlayers(), zs->GetCAddress(), zs->GetCPort(), tmpZone); + AppendAnyLenString(&output, &outsize, &outlen, + "#%-3i :: %s :: %15s:%-5i :: %2i :: %s:%i :: %s :: (%u)", + zone_server_data->GetID(), + is_static_string, + inet_ntoa(in), + zone_server_data->GetPort(), + zone_server_data->NumPlayers(), + zone_server_data->GetCAddress(), + zone_server_data->GetCPort(), + zone_data_string, + zone_server_data->GetZoneOSProcessID() + ); + if (outlen >= 3584) { connection->SendEmoteMessageRaw(to, 0, 0, 10, output); safe_delete(output); @@ -348,12 +375,12 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con } x++; } - else if (zs->GetZoneID() != 0) { - if (zs->GetZoneID()) - strcpy(tmpZone, zs->GetZoneName()); + else if (zone_server_data->GetZoneID() != 0) { + if (zone_server_data->GetZoneID()) + strcpy(zone_data_string, zone_server_data->GetZoneName()); else - tmpZone[0] = 0; - AppendAnyLenString(&output, &outsize, &outlen, " #%i %s %s", zs->GetID(), tmpStatic, tmpZone); + zone_data_string[0] = 0; + AppendAnyLenString(&output, &outsize, &outlen, " #%i %s %s", zone_server_data->GetID(), is_static_string, zone_data_string); if (outlen >= 3584) { connection->SendEmoteMessageRaw(to, 0, 0, 10, output); safe_delete(output); @@ -361,25 +388,32 @@ void ZSList::SendZoneStatus(const char* to, int16 admin, WorldTCPConnection* con outlen = 0; } else { - if (connection->IsConsole()) + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "\r\n"); - else + } + else{ AppendAnyLenString(&output, &outsize, &outlen, "^"); + } } x++; } y++; iterator.Advance(); } - if (connection->IsConsole()) + + if (connection->IsConsole()){ AppendAnyLenString(&output, &outsize, &outlen, "%i servers listed. %i servers online.\r\n", x, y); - else + } + else { AppendAnyLenString(&output, &outsize, &outlen, "%i servers listed. %i servers online.^", x, y); - AppendAnyLenString(&output, &outsize, &outlen, "%i zones are static zones, %i zones are booted zones, %i zones available.",z,w,v); -// connection->SendEmoteMessage(to, 0, 0, "%i servers listed. %i servers online.", x, y); -// connection->SendEmoteMessage(to,0,0,"%i zones are static zones, %i zones are booted zones, %i zones available.",z,w,v); - if (output) + } + + AppendAnyLenString(&output, &outsize, &outlen, "%i zones are static zones, %i zones are booted zones, %i zones available.", z, w, v); + + if (output){ connection->SendEmoteMessageRaw(to, 0, 0, 10, output); + } + safe_delete(output); } @@ -564,7 +598,7 @@ void ZSList::RebootZone(const char* ip1,uint16 port,const char* ip2, uint32 skip iterator.Advance(); } if (y == 0) { - safe_delete(tmp); + safe_delete_array(tmp); return; } uint32 z = emu_random.Int(0, y-1); diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index 9a6d69aca..207af4f00 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -51,19 +51,24 @@ extern WebInterfaceConnection WILink; void CatchSignal(int sig_num); ZoneServer::ZoneServer(EmuTCPConnection* itcpc) -: WorldTCPConnection(), tcpc(itcpc), ls_zboot(5000) { - ID = zoneserver_list.GetNextID(); +: WorldTCPConnection(), tcpc(itcpc), zone_boot_timer(5000) { + + /* Set Process tracking variable defaults */ + memset(zone_name, 0, sizeof(zone_name)); memset(compiled, 0, sizeof(compiled)); - zoneID = 0; - instanceID = 0; + memset(client_address, 0, sizeof(client_address)); + memset(client_local_address, 0, sizeof(client_local_address)); - memset(clientaddress, 0, sizeof(clientaddress)); - clientport = 0; - BootingUp = false; - authenticated = false; - staticzone = false; - pNumPlayers = 0; + zone_server_id = zoneserver_list.GetNextID(); + zone_server_zone_id = 0; + instance_id = 0; + zone_os_process_id = 0; + client_port = 0; + is_booting_up = false; + is_authenticated = false; + is_static_zone = false; + zone_player_count = 0; } ZoneServer::~ZoneServer() { @@ -73,7 +78,7 @@ ZoneServer::~ZoneServer() { } bool ZoneServer::SetZone(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { - BootingUp = false; + is_booting_up = false; const char* zn = MakeLowerString(database.GetZoneName(iZoneID)); char* longname; @@ -82,17 +87,17 @@ bool ZoneServer::SetZone(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { Log.Out(Logs::Detail, Logs::World_Server,"Setting to '%s' (%d:%d)%s",(zn) ? zn : "",iZoneID, iInstanceID, iStaticZone ? " (Static)" : ""); - zoneID = iZoneID; - instanceID = iInstanceID; + zone_server_zone_id = iZoneID; + instance_id = iInstanceID; if(iZoneID!=0) - oldZoneID = iZoneID; - if (zoneID == 0) { + zone_server_previous_zone_id = iZoneID; + if (zone_server_zone_id == 0) { client_list.CLERemoveZSRef(this); - pNumPlayers = 0; + zone_player_count = 0; LSSleepUpdate(GetPrevZoneID()); } - staticzone = iStaticZone; + is_static_zone = iStaticZone; if (zn) { @@ -112,7 +117,7 @@ bool ZoneServer::SetZone(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { } client_list.ZoneBootup(this); - ls_zboot.Start(); + zone_boot_timer.Start(); return true; } @@ -173,26 +178,28 @@ void ZoneServer::LSSleepUpdate(uint32 zoneid){ bool ZoneServer::Process() { if (!tcpc->Connected()) return false; - if(ls_zboot.Check()){ + if(zone_boot_timer.Check()){ LSBootUpdate(GetZoneID(), true); - ls_zboot.Disable(); + zone_boot_timer.Disable(); } ServerPacket *pack = 0; while((pack = tcpc->PopPacket())) { - if (!authenticated) { + if (!is_authenticated) { if (WorldConfig::get()->SharedKey.length() > 0) { if (pack->opcode == ServerOP_ZAAuth && pack->size == 16) { uint8 tmppass[16]; MD5::Generate((const uchar*) WorldConfig::get()->SharedKey.c_str(), WorldConfig::get()->SharedKey.length(), tmppass); - if (memcmp(pack->pBuffer, tmppass, 16) == 0) - authenticated = true; + if (memcmp(pack->pBuffer, tmppass, 16) == 0) { + is_authenticated = true; + Log.Out(Logs::Detail, Logs::World_Server, "Zone process connected."); + } else { struct in_addr in; in.s_addr = GetIP(); - Log.Out(Logs::Detail, Logs::World_Server,"Zone authorization failed."); + Log.Out(Logs::General, Logs::Error, "Zone authorization failed."); auto pack = new ServerPacket(ServerOP_ZAAuthFailed); SendPacket(pack); - delete pack; + safe_delete(pack); Disconnect(); return false; } @@ -200,18 +207,18 @@ bool ZoneServer::Process() { else { struct in_addr in; in.s_addr = GetIP(); - Log.Out(Logs::Detail, Logs::World_Server,"Zone authorization failed."); + Log.Out(Logs::General, Logs::Error, "Zone authorization failed."); auto pack = new ServerPacket(ServerOP_ZAAuthFailed); SendPacket(pack); - delete pack; + safe_delete(pack); Disconnect(); return false; } } else { - Log.Out(Logs::Detail, Logs::World_Server,"**WARNING** You have not configured a world shared key in your config file. You should add a STRING element to your element to prevent unauthroized zone access."); - authenticated = true; + Log.Out(Logs::General, Logs::Error, "**WARNING** You have not configured a world shared key in your config file. You should add a STRING element to your element to prevent unauthroized zone access."); + is_authenticated = true; } } switch(pack->opcode) { @@ -583,17 +590,31 @@ bool ZoneServer::Process() { ServerConnectInfo* sci = (ServerConnectInfo*) pack->pBuffer; if (!sci->port) { - clientport=zoneserver_list.GetAvailableZonePort(); + client_port = zoneserver_list.GetAvailableZonePort(); ServerPacket p(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo)); memset(p.pBuffer,0,sizeof(ServerConnectInfo)); ServerConnectInfo* sci = (ServerConnectInfo*) p.pBuffer; - sci->port = clientport; + sci->port = client_port; SendPacket(&p); - Log.Out(Logs::Detail, Logs::World_Server,"Auto zone port configuration. Telling zone to use port %d",clientport); + Log.Out(Logs::Detail, Logs::World_Server,"Auto zone port configuration. Telling zone to use port %d",client_port); } else { - clientport=sci->port; - Log.Out(Logs::Detail, Logs::World_Server,"Zone specified port %d, must be a previously allocated zone reconnecting.",clientport); + client_port = sci->port; + Log.Out(Logs::Detail, Logs::World_Server,"Zone specified port %d.",client_port); + } + + if(sci->address[0]) { + strn0cpy(client_address, sci->address, 250); + Log.Out(Logs::Detail, Logs::World_Server, "Zone specified address %s.", sci->address); + } + + if(sci->local_address[0]) { + strn0cpy(client_local_address, sci->local_address, 250); + Log.Out(Logs::Detail, Logs::World_Server, "Zone specified local address %s.", sci->address); + } + + if (sci->process_id){ + zone_os_process_id = sci->process_id; } } @@ -781,7 +802,7 @@ bool ZoneServer::Process() { whom->wrace = whoall->wrace; strcpy(whom->whom,whoall->whom); client_list.SendWhoAll(whoall->fromid,whoall->from, whoall->admin, whom, this); - delete whom; + safe_delete(whom); break; } case ServerOP_RequestOnlineGuildMembers: { @@ -809,6 +830,11 @@ bool ZoneServer::Process() { RuleManager::Instance()->LoadRules(&database, "default"); break; } + case ServerOP_ReloadPerlExportSettings: + { + zoneserver_list.SendPacket(pack); + break; + } case ServerOP_CameraShake: { zoneserver_list.SendPacket(pack); @@ -960,15 +986,15 @@ bool ZoneServer::Process() { tod->start_eqtime=zoneserver_list.worldclock.getStartEQTime(); tod->start_realtime=zoneserver_list.worldclock.getStartRealTime(); SendPacket(pack); - delete pack; + safe_delete(pack); break; } case ServerOP_SetWorldTime: { Log.Out(Logs::Detail, Logs::World_Server,"Received SetWorldTime"); eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer; - zoneserver_list.worldclock.setEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime); - Log.Out(Logs::Detail, Logs::World_Server,"New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime); - zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str()); + zoneserver_list.worldclock.SetCurrentEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime); + Log.Out(Logs::Detail, Logs::World_Server, "New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime); + database.SaveTime((int)newtime->start_eqtime.minute, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.day, newtime->start_eqtime.month, newtime->start_eqtime.year); zoneserver_list.SendTimeSync(); break; } @@ -1061,8 +1087,7 @@ bool ZoneServer::Process() { } else { - delete pack; - pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); + auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; strcpy(scs->grantname, s->grantname); strcpy(scs->ownername, s->ownername); @@ -1078,6 +1103,7 @@ bool ZoneServer::Process() { else { Log.Out(Logs::Detail, Logs::World_Server, "Unable to locate zone record for instance id %u in zoneserver list for ServerOP_Consent_Response operation.", s->instance_id); } + safe_delete(pack); } } else @@ -1093,8 +1119,7 @@ bool ZoneServer::Process() { } else { // send target not found back to requester - delete pack; - pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); + auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; strcpy(scs->grantname, s->grantname); strcpy(scs->ownername, s->ownername); @@ -1109,13 +1134,13 @@ bool ZoneServer::Process() { else { Log.Out(Logs::Detail, Logs::World_Server, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id); } + safe_delete(pack); } } } else { // send target not found back to requester - delete pack; - pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); + auto pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; strcpy(scs->grantname, s->grantname); strcpy(scs->ownername, s->ownername); @@ -1130,6 +1155,7 @@ bool ZoneServer::Process() { else { Log.Out(Logs::Detail, Logs::World_Server, "Unable to locate zone record for zone id %u in zoneserver list for ServerOP_Consent_Response operation.", s->zone_id); } + safe_delete(pack); } break; } @@ -1307,6 +1333,23 @@ bool ZoneServer::Process() { zoneserver_list.SendPacket(pack); break; } + case ServerOP_ChangeSharedMem: { + std::string hotfix_name = std::string((char*)pack->pBuffer); + + Log.Out(Logs::General, Logs::World_Server, "Loading items..."); + if(!database.LoadItems(hotfix_name)) { + Log.Out(Logs::General, Logs::World_Server, "Error: Could not load item data. But ignoring"); + } + + Log.Out(Logs::General, Logs::World_Server, "Loading skill caps..."); + if(!database.LoadSkillCaps(hotfix_name)) { + Log.Out(Logs::General, Logs::World_Server, "Error: Could not load skill cap data. But ignoring"); + } + + zoneserver_list.SendPacket(pack); + break; + } + case ServerOP_RequestTellQueue: { ServerRequestTellQueue_Struct* rtq = (ServerRequestTellQueue_Struct*) pack->pBuffer; @@ -1319,13 +1362,17 @@ bool ZoneServer::Process() { } default: { - Log.Out(Logs::Detail, Logs::World_Server,"Unknown ServerOPcode from zone 0x%04x, size %d",pack->opcode,pack->size); + Log.Out(Logs::Detail, Logs::World_Server, "Unknown ServerOPcode from zone 0x%04x, size %d", pack->opcode, pack->size); DumpPacket(pack->pBuffer, pack->size); break; } } - - delete pack; + if (pack) { + safe_delete(pack); + } + else { + Log.Out(Logs::Detail, Logs::World_Server, "Zoneserver process attempted to delete pack when pack does not exist."); + } } return true; } @@ -1389,13 +1436,13 @@ void ZoneServer::ChangeWID(uint32 iCharID, uint32 iWID) { void ZoneServer::TriggerBootup(uint32 iZoneID, uint32 iInstanceID, const char* adminname, bool iMakeStatic) { - BootingUp = true; - zoneID = iZoneID; - instanceID = iInstanceID; + is_booting_up = true; + zone_server_zone_id = iZoneID; + instance_id = iInstanceID; auto pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_struct)); ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer; - s->ZoneServerID = ID; + s->ZoneServerID = zone_server_id; if (adminname != 0) strcpy(s->adminname, adminname); @@ -1412,7 +1459,7 @@ void ZoneServer::TriggerBootup(uint32 iZoneID, uint32 iInstanceID, const char* a } void ZoneServer::IncomingClient(Client* client) { - BootingUp = true; + is_booting_up = true; auto pack = new ServerPacket(ServerOP_ZoneIncClient, sizeof(ServerZoneIncomingClient_Struct)); ServerZoneIncomingClient_Struct* s = (ServerZoneIncomingClient_Struct*) pack->pBuffer; s->zoneid = GetZoneID(); diff --git a/world/zoneserver.h b/world/zoneserver.h index 1babecc98..8d26271d1 100644 --- a/world/zoneserver.h +++ b/world/zoneserver.h @@ -44,7 +44,7 @@ public: void LSBootUpdate(uint32 zoneid, uint32 iInstanceID = 0, bool startup = false); void LSSleepUpdate(uint32 zoneid); void LSShutDownUpdate(uint32 zoneid); - uint32 GetPrevZoneID() { return oldZoneID; } + uint32 GetPrevZoneID() { return zone_server_previous_zone_id; } void ChangeWID(uint32 iCharID, uint32 iWID); void SendGroupIDs(); @@ -52,39 +52,45 @@ public: inline const char* GetZoneLongName() const { return long_name; } const char* GetCompileTime() const{ return compiled; } void SetCompile(char* in_compile){ strcpy(compiled,in_compile); } - inline uint32 GetZoneID() const { return zoneID; } + inline uint32 GetZoneID() const { return zone_server_zone_id; } inline uint32 GetIP() const { return tcpc->GetrIP(); } inline uint16 GetPort() const { return tcpc->GetrPort(); } - inline const char* GetCAddress() const { return clientaddress; } - inline uint16 GetCPort() const { return clientport; } - inline uint32 GetID() const { return ID; } - inline bool IsBootingUp() const { return BootingUp; } - inline bool IsStaticZone() const{ return staticzone; } - inline uint32 NumPlayers() const { return pNumPlayers; } - inline void AddPlayer() { pNumPlayers++; } - inline void RemovePlayer() { pNumPlayers--; } + inline const char* GetCAddress() const { return client_address; } + inline const char* GetCLocalAddress() const { return client_local_address; } + inline uint16 GetCPort() const { return client_port; } + inline uint32 GetID() const { return zone_server_id; } + inline bool IsBootingUp() const { return is_booting_up; } + inline bool IsStaticZone() const{ return is_static_zone; } + inline uint32 NumPlayers() const { return zone_player_count; } + inline void AddPlayer() { zone_player_count++; } + inline void RemovePlayer() { zone_player_count--; } inline const char * GetLaunchName() const { return(launcher_name.c_str()); } inline const char * GetLaunchedName() const { return(launched_name.c_str()); } - inline uint32 GetInstanceID() { return instanceID; } - inline void SetInstanceID(uint32 i) { instanceID = i; } + inline uint32 GetInstanceID() { return instance_id; } + inline void SetInstanceID(uint32 i) { instance_id = i; } + + inline uint32 GetZoneOSProcessID() { return zone_os_process_id; } + private: EmuTCPConnection* const tcpc; - uint32 ID; - char clientaddress[250]; - uint16 clientport; - bool BootingUp; - bool staticzone; - bool authenticated; - uint32 pNumPlayers; + uint32 zone_server_id; + char client_address[250]; + char client_local_address[250]; + uint16 client_port; + bool is_booting_up; + bool is_static_zone; + bool is_authenticated; + uint32 zone_player_count; char compiled[25]; char zone_name[32]; char long_name[256]; - uint32 zoneID; - uint32 oldZoneID; - Timer ls_zboot; - uint32 instanceID; //instance ids contain a zone id, and a zone version + uint32 zone_server_zone_id; + uint32 zone_server_previous_zone_id; + Timer zone_boot_timer; + uint32 instance_id; //instance ids contain a zone id, and a zone version + uint32 zone_os_process_id; std::string launcher_name; //the launcher which started us std::string launched_name; //the name of the zone we launched. }; diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index 38d77fb34..534953761 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -2,11 +2,14 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) SET(zone_sources aa.cpp + aa_ability.cpp aggro.cpp attack.cpp beacon.cpp bonuses.cpp bot.cpp + bot_command.cpp + bot_database.cpp botspellsai.cpp client.cpp client_mods.cpp @@ -20,6 +23,7 @@ SET(zone_sources embparser_api.cpp embperl.cpp embxs.cpp + encounter.cpp entity.cpp exp.cpp fearpath.cpp @@ -28,6 +32,7 @@ SET(zone_sources guild.cpp guild_mgr.cpp hate_list.cpp + heal_rotation.cpp horse.cpp inventory.cpp loottables.cpp @@ -35,6 +40,7 @@ SET(zone_sources lua_corpse.cpp lua_client.cpp lua_door.cpp + lua_encounter.cpp lua_entity.cpp lua_entity_list.cpp lua_general.cpp @@ -126,9 +132,12 @@ SET(zone_sources SET(zone_headers aa.h + aa_ability.h basic_functions.h beacon.h bot.h + bot_command.h + bot_database.h bot_structs.h client.h client_packet.h @@ -139,6 +148,7 @@ SET(zone_headers embparser.h embperl.h embxs.h + encounter.h entity.h errmsg.h event_codes.h @@ -146,10 +156,12 @@ SET(zone_headers groups.h guild_mgr.h hate_list.h + heal_rotation.h horse.h lua_bit.h lua_client.h lua_corpse.h + lua_encounter.h lua_entity.h lua_entity_list.h lua_general.h diff --git a/zone/aa.cpp b/zone/aa.cpp index b0208326a..97b444311 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator -Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net) +Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,7 +23,6 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net) #include "../common/races.h" #include "../common/spdat.h" #include "../common/string_util.h" - #include "aa.h" #include "client.h" #include "corpse.h" @@ -37,461 +36,6 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net) extern QueryServ* QServ; - -AA_DBAction AA_Actions[aaHighestID][MAX_AA_ACTION_RANKS]; //[aaid][rank] -std::mapaas_send; -std::map > aa_effects; //stores the effects from the aa_effects table in memory -std::map AARequiredLevelAndCost; - - -int Client::GetAATimerID(aaID activate) -{ - SendAA_Struct* aa2 = zone->FindAA(activate); - - if(!aa2) - { - for(int i = 1;i < MAX_AA_ACTION_RANKS; ++i) - { - int a = activate - i; - - if(a <= 0) - break; - - aa2 = zone->FindAA(a); - - if(aa2 != nullptr) - break; - } - } - - if(aa2) - return aa2->spell_type; - - return 0; -} - -int Client::CalcAAReuseTimer(const AA_DBAction *caa) { - - if(!caa) - return 0; - - int ReuseTime = caa->reuse_time; - - if(ReuseTime > 0) - { - int ReductionPercentage; - - if(caa->redux_aa > 0 && caa->redux_aa < aaHighestID) - { - ReductionPercentage = GetAA(caa->redux_aa) * caa->redux_rate; - - if(caa->redux_aa2 > 0 && caa->redux_aa2 < aaHighestID) - ReductionPercentage += (GetAA(caa->redux_aa2) * caa->redux_rate2); - - ReuseTime = caa->reuse_time * (100 - ReductionPercentage) / 100; - } - - } - return ReuseTime; -} - -void Client::ActivateAA(aaID activate){ - if(activate < 0 || activate >= aaHighestID) - return; - if(IsStunned() || IsFeared() || IsMezzed() || IsSilenced() || IsPet() || IsSitting() || GetFeigned()) - return; - - int AATimerID = GetAATimerID(activate); - - SendAA_Struct* aa2 = nullptr; - aaID aaid = activate; - uint8 activate_val = GetAA(activate); - //this wasn't taking into acct multi tiered act talents before... - if(activate_val == 0){ - aa2 = zone->FindAA(activate); - if(!aa2){ - int i; - int a; - for(i=1;iFindAA(a); - if(aa2 != nullptr) - break; - } - } - if(aa2){ - aaid = (aaID) aa2->id; - activate_val = GetAA(aa2->id); - } - } - - if (activate_val == 0){ - return; - } - - if(aa2) - { - if(aa2->account_time_required) - { - if((Timer::GetTimeSeconds() + account_creation) < aa2->account_time_required) - { - return; - } - } - } - - if(!p_timers.Expired(&database, AATimerID + pTimerAAStart)) - { - uint32 aaremain = p_timers.GetRemainingTime(AATimerID + pTimerAAStart); - uint32 aaremain_hr = aaremain / (60 * 60); - uint32 aaremain_min = (aaremain / 60) % 60; - uint32 aaremain_sec = aaremain % 60; - - if(aa2) { - if (aaremain_hr >= 1) //1 hour or more - Message(13, "You can use the ability %s again in %u hour(s) %u minute(s) %u seconds", - aa2->name, aaremain_hr, aaremain_min, aaremain_sec); - else //less than an hour - Message(13, "You can use the ability %s again in %u minute(s) %u seconds", - aa2->name, aaremain_min, aaremain_sec); - } else { - if (aaremain_hr >= 1) //1 hour or more - Message(13, "You can use this ability again in %u hour(s) %u minute(s) %u seconds", - aaremain_hr, aaremain_min, aaremain_sec); - else //less than an hour - Message(13, "You can use this ability again in %u minute(s) %u seconds", - aaremain_min, aaremain_sec); - } - return; - } - - if(activate_val > MAX_AA_ACTION_RANKS) - activate_val = MAX_AA_ACTION_RANKS; - activate_val--; //to get array index. - - //get our current node, now that the indices are well bounded - const AA_DBAction *caa = &AA_Actions[aaid][activate_val]; - - if((aaid == aaImprovedHarmTouch || aaid == aaLeechTouch) && !p_timers.Expired(&database, pTimerHarmTouch)){ - Message(13,"Ability recovery time not yet met."); - return; - } - - //everything should be configured out now - - uint16 target_id = 0; - - //figure out our target - switch(caa->target) { - case aaTargetUser: - case aaTargetGroup: - target_id = GetID(); - break; - case aaTargetCurrent: - case aaTargetCurrentGroup: - if(GetTarget() == nullptr) { - Message_StringID(MT_DefaultText, AA_NO_TARGET); //You must first select a target for this ability! - p_timers.Clear(&database, AATimerID + pTimerAAStart); - return; - } - target_id = GetTarget()->GetID(); - break; - case aaTargetPet: - if(GetPet() == nullptr) { - Message(0, "A pet is required for this skill."); - return; - } - target_id = GetPetID(); - break; - } - - //handle non-spell action - if(caa->action != aaActionNone) { - if(caa->mana_cost > 0) { - if(GetMana() < caa->mana_cost) { - Message_StringID(13, INSUFFICIENT_MANA); - return; - } - SetMana(GetMana() - caa->mana_cost); - } - if(caa->reuse_time > 0) - { - uint32 timer_base = CalcAAReuseTimer(caa); - if(activate == aaImprovedHarmTouch || activate == aaLeechTouch) - { - p_timers.Start(pTimerHarmTouch, HarmTouchReuseTime); - } - p_timers.Start(AATimerID + pTimerAAStart, timer_base); - SendAATimer(AATimerID, 0, 0); - } - HandleAAAction(aaid); - } - - //cast the spell, if we have one - if(caa->spell_id > 0 && caa->spell_id < SPDAT_RECORDS) { - - if(caa->reuse_time > 0) - { - uint32 timer_base = CalcAAReuseTimer(caa); - SendAATimer(AATimerID, 0, 0); - p_timers.Start(AATimerID + pTimerAAStart, timer_base); - if(activate == aaImprovedHarmTouch || activate == aaLeechTouch) - { - p_timers.Start(pTimerHarmTouch, HarmTouchReuseTime); - } - // Bards can cast instant cast AAs while they are casting another song - if (spells[caa->spell_id].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) { - if(!SpellFinished(caa->spell_id, entity_list.GetMob(target_id), 10, -1, -1, spells[caa->spell_id].ResistDiff, false)) { - //Reset on failed cast - SendAATimer(AATimerID, 0, 0xFFFFFF); - Message_StringID(15,ABILITY_FAILED); - p_timers.Clear(&database, AATimerID + pTimerAAStart); - return; - } - } else { - if (!CastSpell(caa->spell_id, target_id, USE_ITEM_SPELL_SLOT, -1, -1, 0, -1, AATimerID + pTimerAAStart, timer_base, 1)) { - //Reset on failed cast - SendAATimer(AATimerID, 0, 0xFFFFFF); - Message_StringID(15,ABILITY_FAILED); - p_timers.Clear(&database, AATimerID + pTimerAAStart); - return; - } - } - } - else - { - if(!CastSpell(caa->spell_id, target_id)) - return; - } - } - // Check if AA is expendable - if (aas_send[activate - activate_val]->special_category == 7) { - - // Add the AA cost to the extended profile to track overall total - m_epp.expended_aa += aas_send[activate]->cost; - - SetAA(activate, 0); - - SaveAA(); /* Save Character AA */ - SendAA(activate); - SendAATable(); - } -} - -void Client::HandleAAAction(aaID activate) { - if(activate < 0 || activate >= aaHighestID) - return; - - uint8 activate_val = GetAA(activate); - - if (activate_val == 0) - return; - - if(activate_val > MAX_AA_ACTION_RANKS) - activate_val = MAX_AA_ACTION_RANKS; - activate_val--; //to get array index. - - //get our current node, now that the indices are well bounded - const AA_DBAction *caa = &AA_Actions[activate][activate_val]; - - uint16 timer_id = 0; - uint16 timer_duration = caa->duration; - aaTargetType target = aaTargetUser; - - uint16 spell_id = SPELL_UNKNOWN; //gets cast at the end if not still unknown - - switch(caa->action) { - case aaActionAETaunt: - entity_list.AETaunt(this); - break; - - case aaActionFlamingArrows: - //toggle it - if(CheckAAEffect(aaEffectFlamingArrows)) - EnableAAEffect(aaEffectFlamingArrows); - else - DisableAAEffect(aaEffectFlamingArrows); - break; - - case aaActionFrostArrows: - if(CheckAAEffect(aaEffectFrostArrows)) - EnableAAEffect(aaEffectFrostArrows); - else - DisableAAEffect(aaEffectFrostArrows); - break; - - case aaActionRampage: - EnableAAEffect(aaEffectRampage, 10); - break; - - case aaActionSharedHealth: - if(CheckAAEffect(aaEffectSharedHealth)) - EnableAAEffect(aaEffectSharedHealth); - else - DisableAAEffect(aaEffectSharedHealth); - break; - - case aaActionCelestialRegen: { - //special because spell_id depends on a different AA - switch (GetAA(aaCelestialRenewal)) { - case 1: - spell_id = 3250; - break; - case 2: - spell_id = 3251; - break; - default: - spell_id = 2740; - break; - } - target = aaTargetCurrent; - break; - } - - case aaActionDireCharm: { - //special because spell_id depends on class - switch (GetClass()) - { - case DRUID: - spell_id = 2760; //2644? - break; - case NECROMANCER: - spell_id = 2759; //2643? - break; - case ENCHANTER: - spell_id = 2761; //2642? - break; - } - target = aaTargetCurrent; - break; - } - - case aaActionImprovedFamiliar: { - //Spell IDs might be wrong... - if (GetAA(aaAllegiantFamiliar)) - spell_id = 3264; //1994? - else - spell_id = 2758; //2155? - break; - } - - case aaActionActOfValor: - if(GetTarget() != nullptr) { - int curhp = GetTarget()->GetHP(); - target = aaTargetCurrent; - GetTarget()->HealDamage(curhp, this); - Death(this, 0, SPELL_UNKNOWN, SkillHandtoHand); - } - break; - - case aaActionSuspendedMinion: - if (GetPet()) { - target = aaTargetPet; - switch (GetAA(aaSuspendedMinion)) { - case 1: - spell_id = 3248; - break; - case 2: - spell_id = 3249; - break; - } - //do we really need to cast a spell? - - Message(0,"You call your pet to your side."); - GetPet()->WipeHateList(); - GetPet()->GMMove(GetX(),GetY(),GetZ()); - if (activate_val > 1) - entity_list.ClearFeignAggro(GetPet()); - } else { - Message(0,"You have no pet to call."); - } - break; - - case aaActionEscape: - Escape(); - break; - - // Don't think this code is used any longer for Bestial Alignment as the aa.has a spell_id and no nonspell_action. - case aaActionBeastialAlignment: - switch(GetBaseRace()) { - case BARBARIAN: - spell_id = AA_Choose3(activate_val, 4521, 4522, 4523); - break; - case TROLL: - spell_id = AA_Choose3(activate_val, 4524, 4525, 4526); - break; - case OGRE: - spell_id = AA_Choose3(activate_val, 4527, 4527, 4529); - break; - case IKSAR: - spell_id = AA_Choose3(activate_val, 4530, 4531, 4532); - break; - case VAHSHIR: - spell_id = AA_Choose3(activate_val, 4533, 4534, 4535); - break; - } - - case aaActionLeechTouch: - target = aaTargetCurrent; - spell_id = SPELL_HARM_TOUCH2; - EnableAAEffect(aaEffectLeechTouch, 1000); - break; - - case aaActionFadingMemories: - // Do nothing since spell effect works correctly, but mana isn't used. - break; - - default: - Log.Out(Logs::General, Logs::Error, "Unknown AA nonspell action type %d", caa->action); - return; - } - - - uint16 target_id = 0; - //figure out our target - switch(target) { - case aaTargetUser: - case aaTargetGroup: - target_id = GetID(); - break; - case aaTargetCurrent: - case aaTargetCurrentGroup: - if(GetTarget() == nullptr) { - Message_StringID(MT_DefaultText, AA_NO_TARGET); //You must first select a target for this ability! - p_timers.Clear(&database, timer_id + pTimerAAEffectStart); - return; - } - target_id = GetTarget()->GetID(); - break; - case aaTargetPet: - if(GetPet() == nullptr) { - Message(0, "A pet is required for this skill."); - return; - } - target_id = GetPetID(); - break; - } - - //cast the spell, if we have one - if(IsValidSpell(spell_id)) { - int aatid = GetAATimerID(activate); - if (!CastSpell(spell_id, target_id, USE_ITEM_SPELL_SLOT, -1, -1, 0, -1, pTimerAAStart + aatid, CalcAAReuseTimer(caa), 1)) { - SendAATimer(aatid, 0, 0xFFFFFF); - Message_StringID(15,ABILITY_FAILED); - p_timers.Clear(&database, pTimerAAStart + aatid); - return; - } - } - - //handle the duration timer if we have one. - if(timer_id > 0 && timer_duration > 0) { - p_timers.Start(pTimerAAEffectStart + timer_id, timer_duration); - } -} - void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) { //It might not be a bad idea to put these into the database, eventually.. @@ -576,7 +120,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u npca->SetFollowID(GetID()); if(!npca->GetSwarmInfo()){ - AA_SwarmPetInfo* nSI = new AA_SwarmPetInfo; + auto nSI = new AA_SwarmPetInfo; npca->SetSwarmInfo(nSI); npca->GetSwarmInfo()->duration = new Timer(pet_duration*1000); } @@ -673,7 +217,7 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid npca->SetFollowID(GetID()); if(!npca->GetSwarmInfo()){ - AA_SwarmPetInfo* nSI = new AA_SwarmPetInfo; + auto nSI = new AA_SwarmPetInfo; npca->SetSwarmInfo(nSI); npca->GetSwarmInfo()->duration = new Timer(pet_duration*1000); } @@ -716,7 +260,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) //assuming we have pets in our table; we take the first pet as a base type. const NPCType *base_type = database.LoadNPCTypesData(500); - NPCType *make_npc = new NPCType; + auto make_npc = new NPCType; memcpy(make_npc, base_type, sizeof(NPCType)); //combat stats @@ -853,10 +397,10 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) make_npc->d_melee_texture1 = 0; make_npc->d_melee_texture2 = 0; - NPC* npca = new NPC(make_npc, 0, GetPosition(), FlyMode3); + auto npca = new NPC(make_npc, 0, GetPosition(), FlyMode3); if(!npca->GetSwarmInfo()){ - AA_SwarmPetInfo* nSI = new AA_SwarmPetInfo; + auto nSI = new AA_SwarmPetInfo; npca->SetSwarmInfo(nSI); npca->GetSwarmInfo()->duration = new Timer(duration*1000); } @@ -874,13 +418,13 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) //gear stuff, need to make sure there's //no situation where this stuff can be duped - for(int x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::EQUIPMENT_END; x++) // (< 21) added MainAmmo + for (int x = EQEmu::legacy::EQUIPMENT_BEGIN; x <= EQEmu::legacy::EQUIPMENT_END; x++) // (< 21) added MainAmmo { uint32 sitem = 0; sitem = CorpseToUse->GetWornItem(x); if(sitem){ - const Item_Struct * itm = database.GetItem(sitem); - npca->AddLootDrop(itm, &npca->itemlist, 1, 1, 127, true, true); + const EQEmu::ItemBase * itm = database.GetItem(sitem); + npca->AddLootDrop(itm, &npca->itemlist, 1, 1, 255, true, true); } } @@ -895,605 +439,27 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) target->AddToHateList(this, 1, 0); } -//turn on an AA effect -//duration == 0 means no time limit, used for one-shot deals, etc.. -void Client::EnableAAEffect(aaEffectType type, uint32 duration) { - if(type > _maxaaEffectType) - return; //for now, special logic needed. - m_epp.aa_effects |= 1 << (type-1); - - if(duration > 0) { - p_timers.Start(pTimerAAEffectStart + type, duration); - } else { - p_timers.Clear(&database, pTimerAAEffectStart + type); - } -} - -void Client::DisableAAEffect(aaEffectType type) { - if(type > _maxaaEffectType) - return; //for now, special logic needed. - uint32 bit = 1 << (type-1); - if(m_epp.aa_effects & bit) { - m_epp.aa_effects ^= bit; - } - p_timers.Clear(&database, pTimerAAEffectStart + type); -} - -/* -By default an AA effect is a one shot deal, unless -a duration timer is set. -*/ -bool Client::CheckAAEffect(aaEffectType type) { - if(type > _maxaaEffectType) - return(false); //for now, special logic needed. - if(m_epp.aa_effects & (1 << (type-1))) { //is effect enabled? - //has our timer expired? - if(p_timers.Expired(&database, pTimerAAEffectStart + type)) { - DisableAAEffect(type); - return(false); - } - return(true); - } - return(false); -} - -void Client::SendAAStats() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AAExpUpdate, sizeof(AltAdvStats_Struct)); - AltAdvStats_Struct *aps = (AltAdvStats_Struct *)outapp->pBuffer; - aps->experience = m_pp.expAA; - aps->experience = (uint32)(((float)330.0f * (float)m_pp.expAA) / (float)max_AAXP); - aps->unspent = m_pp.aapoints; - aps->percentage = m_epp.perAA; - QueuePacket(outapp); - safe_delete(outapp); -} - -void Client::BuyAA(AA_Action* action) -{ - Log.Out(Logs::Detail, Logs::AA, "Starting to buy AA %d", action->ability); - - //find the AA information from the database - SendAA_Struct* aa2 = zone->FindAA(action->ability); - if(!aa2) { - //hunt for a lower level... - int i; - int a; - for(i=1;iability - i; - if(a <= 0) - break; - Log.Out(Logs::Detail, Logs::AA, "Could not find AA %d, trying potential parent %d", action->ability, a); - aa2 = zone->FindAA(a); - if(aa2 != nullptr) - break; - } - } - if(aa2 == nullptr) - return; //invalid ability... - - if(aa2->special_category == 1 || aa2->special_category == 2) - return; // Not purchasable progression style AAs - - if(aa2->special_category == 8 && aa2->cost == 0) - return; // Not purchasable racial AAs(set a cost to make them purchasable) - - uint32 cur_level = GetAA(aa2->id); - if((aa2->id + cur_level) != action->ability) { //got invalid AA - Log.Out(Logs::Detail, Logs::AA, "Unable to find or match AA %d (found %d + lvl %d)", action->ability, aa2->id, cur_level); - return; - } - - if(aa2->account_time_required) - { - if((Timer::GetTimeSeconds() - account_creation) < aa2->account_time_required) - { - return; - } - } - - uint32 real_cost; - uint8 req_level; - std::map::iterator RequiredLevel = AARequiredLevelAndCost.find(action->ability); - - if(RequiredLevel != AARequiredLevelAndCost.end()) { - real_cost = RequiredLevel->second.Cost; - req_level = RequiredLevel->second.Level; - } - else { - real_cost = aa2->cost + (aa2->cost_inc * cur_level); - req_level = aa2->class_type + (aa2->level_inc * cur_level); - } - - if (req_level > GetLevel()) - return; //Cheater trying to Buy AA... - - if (m_pp.aapoints >= real_cost && cur_level < aa2->max_level) { - SetAA(aa2->id, cur_level + 1); - - Log.Out(Logs::Detail, Logs::AA, "Set AA %d to level %d", aa2->id, cur_level + 1); - - m_pp.aapoints -= real_cost; - - /* Do Player Profile rank calculations and set player profile */ - SaveAA(); - /* Save to Database to avoid having to write the whole AA array to the profile, only write changes*/ - // database.SaveCharacterAA(this->CharacterID(), aa2->id, (cur_level + 1)); - - if ((RuleB(AA, Stacking) && (GetClientVersionBit() >= 4) && (aa2->hotkey_sid == 4294967295u)) - && ((aa2->max_level == (cur_level + 1)) && aa2->sof_next_id)){ - SendAA(aa2->id); - SendAA(aa2->sof_next_id); - } - else - SendAA(aa2->id); - - SendAATable(); - - /* - We are building these messages ourself instead of using the stringID to work around patch discrepencies - these are AA_GAIN_ABILITY (410) & AA_IMPROVE (411), respectively, in both Titanium & SoF. not sure about 6.2 - */ - - /* Initial purchase of an AA ability */ - if (cur_level < 1){ - Message(15, "You have gained the ability \"%s\" at a cost of %d ability %s.", aa2->name, real_cost, (real_cost>1) ? "points" : "point"); - - /* QS: Player_Log_AA_Purchases */ - if (RuleB(QueryServ, PlayerLogAAPurchases)){ - std::string event_desc = StringFormat("Initial AA Purchase :: aa_name:%s aa_id:%i at cost:%i in zoneid:%i instid:%i", aa2->name, aa2->id, real_cost, this->GetZoneID(), this->GetInstanceID()); - QServ->PlayerLogEvent(Player_Log_AA_Purchases, this->CharacterID(), event_desc); - } - } - /* Ranked purchase of an AA ability */ - else{ - Message(15, "You have improved %s %d at a cost of %d ability %s.", aa2->name, cur_level + 1, real_cost, (real_cost > 1) ? "points" : "point"); - - /* QS: Player_Log_AA_Purchases */ - if (RuleB(QueryServ, PlayerLogAAPurchases)){ - std::string event_desc = StringFormat("Ranked AA Purchase :: aa_name:%s aa_id:%i at cost:%i in zoneid:%i instid:%i", aa2->name, aa2->id, real_cost, this->GetZoneID(), this->GetInstanceID()); - QServ->PlayerLogEvent(Player_Log_AA_Purchases, this->CharacterID(), event_desc); - } - } - - SendAAStats(); - - CalcBonuses(); - if(title_manager.IsNewAATitleAvailable(m_pp.aapoints_spent, GetBaseClass())) - NotifyNewTitlesAvailable(); - } -} - -void Client::SendAATimer(uint32 ability, uint32 begin, uint32 end) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AAAction,sizeof(UseAA_Struct)); - UseAA_Struct* uaaout = (UseAA_Struct*)outapp->pBuffer; - uaaout->ability = ability; - uaaout->begin = begin; - uaaout->end = end; - QueuePacket(outapp); - safe_delete(outapp); -} - -//sends all AA timers. -void Client::SendAATimers() { - //we dont use SendAATimer because theres no reason to allocate the EQApplicationPacket every time - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AAAction,sizeof(UseAA_Struct)); - UseAA_Struct* uaaout = (UseAA_Struct*)outapp->pBuffer; - - PTimerList::iterator c,e; - c = p_timers.begin(); - e = p_timers.end(); - for(; c != e; ++c) { - PersistentTimer *cur = c->second; - if(cur->GetType() < pTimerAAStart || cur->GetType() > pTimerAAEnd) - continue; //not an AA timer - //send timer - uaaout->begin = cur->GetStartTime(); - uaaout->end = static_cast(time(nullptr)); - uaaout->ability = cur->GetType() - pTimerAAStart; // uuaaout->ability is really a shared timer number - QueuePacket(outapp); - } - - safe_delete(outapp); -} - -void Client::SendAATable() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RespondAA, sizeof(AATable_Struct)); - - AATable_Struct* aa2 = (AATable_Struct *)outapp->pBuffer; - aa2->aa_spent = GetAAPointsSpent(); - - uint32 i; - for(i=0;i < MAX_PP_AA_ARRAY;i++){ - aa2->aa_list[i].aa_skill = aa[i]->AA; - aa2->aa_list[i].aa_value = aa[i]->value; - aa2->aa_list[i].unknown08 = 0; - } - QueuePacket(outapp); - safe_delete(outapp); -} - -void Client::SendPreviousAA(uint32 id, int seq){ - uint32 value=0; - SendAA_Struct* saa2 = nullptr; - if(id==0) - saa2 = zone->GetAABySequence(seq); - else - saa2 = zone->FindAA(id); - if(!saa2) - return; - int size=sizeof(SendAA_Struct)+sizeof(AA_Ability)*saa2->total_abilities; - uchar* buffer = new uchar[size]; - SendAA_Struct* saa=(SendAA_Struct*)buffer; - value = GetAA(saa2->id); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendAATable); - outapp->size=size; - outapp->pBuffer=(uchar*)saa; - value--; - memcpy(saa,saa2,size); - - if(value>0){ - if(saa->spellid==0) - saa->spellid=0xFFFFFFFF; - saa->id+=value; - saa->next_id=saa->id+1; - if(value==1) - saa->last_id=saa2->id; - else - saa->last_id=saa->id-1; - saa->current_level=value+1; - saa->cost2 = 0; //cost 2 is what the client uses to calc how many points we've spent, so we have to add up the points in order - for(uint32 i = 0; i < (value+1); i++) { - saa->cost2 += saa->cost + (saa->cost_inc * i); - } - } - - database.FillAAEffects(saa); - QueuePacket(outapp); - safe_delete(outapp); -} - -void Client::SendAA(uint32 id, int seq) { - - uint32 value=0; - SendAA_Struct* saa2 = nullptr; - SendAA_Struct* qaa = nullptr; - SendAA_Struct* saa_pp = nullptr; - bool IsBaseLevel = true; - bool aa_stack = false; - - if(id==0) - saa2 = zone->GetAABySequence(seq); - else - saa2 = zone->FindAA(id); - if(!saa2) - return; - - uint16 classes = saa2->classes; - if(!(classes & (1 << GetClass())) && (GetClass()!=BERSERKER || saa2->berserker==0)){ - return; - } - - if(saa2->account_time_required) - { - if((Timer::GetTimeSeconds() - account_creation) < saa2->account_time_required) - { - return; - } - } - - // Hide Quest/Progression AAs unless player has been granted the first level using $client->IncrementAA(skill_id). - if (saa2->special_category == 1 || saa2->special_category == 2 ) { - if(GetAA(saa2->id) == 0) - return; - // For Quest line AA(demiplane AEs) where only 1 is visible at a time, check to make sure only the highest level obtained is shown - if(saa2->aa_expansion > 0) { - qaa = zone->FindAA(saa2->id+1); - if(qaa && (saa2->aa_expansion == qaa->aa_expansion) && GetAA(qaa->id) > 0) - return; - } - } - -/* Beginning of Shroud AAs, these categories are for Passive and Active Shroud AAs - Eventually with a toggle we could have it show player list or shroud list - if (saa2->special_category == 3 || saa2->special_category == 4) - return; -*/ - // Check for racial/Drakkin blood line AAs - if (saa2->special_category == 8) - { - uint32 client_race = this->GetBaseRace(); - - // Drakkin Bloodlines - if (saa2->aa_expansion > 522) - { - if (client_race != 522) - return; // Check for Drakkin Race - - int heritage = this->GetDrakkinHeritage() + 523; // 523 = Drakkin Race(522) + Bloodline - - if (heritage != saa2->aa_expansion) - return; - } - // Racial AAs - else if (client_race != saa2->aa_expansion) - { - return; - } - } - - /* - AA stacking on SoF+ clients. - - Note: There were many ways to achieve this effect - The method used proved to be the most straight forward and consistent. - Stacking does not currently work ideally for AA's that use hotkeys, therefore they will be excluded at this time. - - TODO: Problem with aa.hotkeys - When you reach max rank of an AA tier (ie 5/5), it automatically displays the next AA in - the series and you can not transfer the hotkey to the next AA series. To the best of the my ability and through many - different variations of coding I could not find an ideal solution to this issue. - - How stacking works: - Utilizes two new fields: sof_next_id (which is the next id in the series), sof_current_level (ranks the AA's as the current level) - 1) If no AA's purchased only display the base levels of each AA series. - 2) When you purchase an AA and its rank is maxed it sends the packet for the completed AA, and the packet - for the next aa in the series. The previous tier is removed from your window, and the new AA is displayed. - 3) When you zone/buy your player profile will be checked and determine what AA can be displayed base on what you have already. - */ - - if (RuleB(AA, Stacking) && (GetClientVersionBit() >= 4) && (saa2->hotkey_sid == 4294967295u)) - aa_stack = true; - - if (aa_stack){ - uint32 aa_AA = 0; - uint32 aa_value = 0; - for (int i = 0; i < MAX_PP_AA_ARRAY; i++) { - if (aa[i]) { - aa_AA = aa[i]->AA; - aa_value = aa[i]->value; - - if (aa_AA){ - - if (aa_value > 0) - aa_AA -= aa_value-1; - - saa_pp = zone->FindAA(aa_AA); - - if (saa_pp){ - - if (saa_pp->sof_next_skill == saa2->sof_next_skill){ - - if (saa_pp->id == saa2->id) - break; //You already have this in the player profile. - else if ((saa_pp->sof_current_level < saa2->sof_current_level) && (aa_value < saa_pp->max_level)) - return; //DISABLE DISPLAY HIGHER - You have not reached max level yet of your current AA. - else if ((saa_pp->sof_current_level < saa2->sof_current_level) && (aa_value == saa_pp->max_level) && (saa_pp->sof_next_id == saa2->id)) - IsBaseLevel = false; //ALLOW DISPLAY HIGHER - } - } - } - } - } - } - - //Hide higher tiers of multi tiered AA's if the base level is not fully purchased. - if (aa_stack && IsBaseLevel && saa2->sof_current_level > 0) - return; - - int size=sizeof(SendAA_Struct)+sizeof(AA_Ability)*saa2->total_abilities; - - if(size == 0) - return; - - uchar* buffer = new uchar[size]; - SendAA_Struct* saa=(SendAA_Struct*)buffer; - memcpy(saa,saa2,size); - - if(saa->spellid==0) - saa->spellid=0xFFFFFFFF; - - value=GetAA(saa->id); - uint32 orig_val = value; - - if(value && saa->id){ - - if(value < saa->max_level){ - saa->id+=value; - saa->next_id=saa->id+1; - value++; - } - - else if (aa_stack && saa->sof_next_id){ - saa->id+=value-1; - saa->next_id=saa->sof_next_id; - - //Prevent removal of previous AA from window if next AA belongs to a higher client version. - SendAA_Struct* saa_next = nullptr; - saa_next = zone->FindAA(saa->sof_next_id); - - // hard-coding values like this is dangerous and makes adding/updating clients a nightmare... - if (saa_next && - (((GetClientVersionBit() == 4) && (saa_next->clientver > 4)) - || ((GetClientVersionBit() == 8) && (saa_next->clientver > 5)) - || ((GetClientVersionBit() == 16) && (saa_next->clientver > 6)))){ - saa->next_id=0xFFFFFFFF; - } - } - - else{ - saa->id+=value-1; - saa->next_id=0xFFFFFFFF; - } - - uint32 current_level_mod = 0; - if (aa_stack) - current_level_mod = saa->sof_current_level; - - saa->last_id=saa->id-1; - saa->current_level=value+(current_level_mod); - saa->cost = saa2->cost + (saa2->cost_inc*(value-1)); - saa->cost2 = 0; - for(uint32 i = 0; i < value; i++) { - saa->cost2 += saa2->cost + (saa2->cost_inc * i); - } - saa->class_type = saa2->class_type + (saa2->level_inc*(value-1)); - } - - if (aa_stack){ - - if (saa->sof_current_level >= 1 && value == 0) - saa->current_level = saa->sof_current_level+1; - - saa->max_level = saa->sof_max_level; - } - - database.FillAAEffects(saa); - - if(value > 0) - { - // AA_Action stores the base ID - const AA_DBAction *caa = &AA_Actions[saa->id - value + 1][value - 1]; - - if(caa && caa->reuse_time > 0) - saa->spell_refresh = CalcAAReuseTimer(caa); - } - - //You can now use the level_inc field in the altadv_vars table to accomplish this, though still needed - //for special cases like LOH/HT due to inability to implement correct stacking of AA's that use hotkeys. - std::map::iterator RequiredLevel = AARequiredLevelAndCost.find(saa->id); - - if(RequiredLevel != AARequiredLevelAndCost.end()) - { - saa->class_type = RequiredLevel->second.Level; - saa->cost = RequiredLevel->second.Cost; - } - - - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendAATable); - outapp->size=size; - outapp->pBuffer=(uchar*)saa; - if(id==0 && value && (orig_val < saa->max_level)) //send previous AA only on zone in - SendPreviousAA(id, seq); - - QueuePacket(outapp); - safe_delete(outapp); - //will outapp delete the buffer for us even though it didnt make it? --- Yes, it should -} - -void Client::SendAAList(){ - int total = zone->GetTotalAAs(); - for(int i=0;i < total;i++){ - SendAA(0,i); - } -} - -uint32 Client::GetAA(uint32 aa_id) const { - std::map::const_iterator res; - res = aa_points.find(aa_id); - if(res != aa_points.end()) { - return(res->second); - } - return(0); -} - -bool Client::SetAA(uint32 aa_id, uint32 new_value) { - aa_points[aa_id] = new_value; - uint32 cur; - for(cur=0;cur < MAX_PP_AA_ARRAY;cur++){ - if((aa[cur]->value > 1) && ((aa[cur]->AA - aa[cur]->value + 1)== aa_id)){ - aa[cur]->value = new_value; - if(new_value > 0) - aa[cur]->AA++; - else - aa[cur]->AA = 0; - return true; - } - else if((aa[cur]->value == 1) && (aa[cur]->AA == aa_id)){ - aa[cur]->value = new_value; - if(new_value > 0) - aa[cur]->AA++; - else - aa[cur]->AA = 0; - return true; - } - else if(aa[cur]->AA==0){ //end of list - aa[cur]->AA = aa_id; - aa[cur]->value = new_value; - return true; - } - } - return false; -} - -SendAA_Struct* Zone::FindAA(uint32 id) { - return aas_send[id]; -} - -void Zone::LoadAAs() { - Log.Out(Logs::General, Logs::Status, "Loading AA information..."); - totalAAs = database.CountAAs(); - if(totalAAs == 0) { - Log.Out(Logs::General, Logs::Error, "Failed to load AAs!"); - aas = nullptr; - return; - } - aas = new SendAA_Struct *[totalAAs]; - - database.LoadAAs(aas); - - int i; - for(i=0; i < totalAAs; i++){ - SendAA_Struct* aa = aas[i]; - aas_send[aa->id] = aa; - } - - //load AA Effects into aa_effects - Log.Out(Logs::General, Logs::Status, "Loading AA Effects..."); - if (database.LoadAAEffects2()) - Log.Out(Logs::General, Logs::Status, "Loaded %d AA Effects.", aa_effects.size()); - else - Log.Out(Logs::General, Logs::Error, "Failed to load AA Effects!"); -} - -bool ZoneDatabase::LoadAAEffects2() { - aa_effects.clear(); //start fresh - - const std::string query = "SELECT aaid, slot, effectid, base1, base2 FROM aa_effects ORDER BY aaid ASC, slot ASC"; - auto results = QueryDatabase(query); - if (!results.Success()) { - return false; - } - - if (!results.RowCount()) { //no results - return false; - } - - for(auto row = results.begin(); row != results.end(); ++row) { - int aaid = atoi(row[0]); - int slot = atoi(row[1]); - int effectid = atoi(row[2]); - int base1 = atoi(row[3]); - int base2 = atoi(row[4]); - aa_effects[aaid][slot].skill_id = effectid; - aa_effects[aaid][slot].base1 = base1; - aa_effects[aaid][slot].base2 = base2; - aa_effects[aaid][slot].slot = slot; //not really needed, but we'll populate it just in case - } - - return true; -} - -void Client::ResetAA(){ +void Client::ResetAA() { + SendClearAA(); RefundAA(); - uint32 i; - for (i=0; i < MAX_PP_AA_ARRAY; i++) { - aa[i]->AA = 0; - aa[i]->value = 0; - m_pp.aa_array[MAX_PP_AA_ARRAY].AA = 0; - m_pp.aa_array[MAX_PP_AA_ARRAY].value = 0; - } - std::map::iterator itr; - for(itr = aa_points.begin(); itr != aa_points.end(); ++itr) - aa_points[itr->first] = 0; + memset(&m_pp.aa_array[0], 0, sizeof(AA_Array) * MAX_PP_AA_ARRAY); + + int i = 0; + for(auto &rank_value : aa_ranks) { + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_value.first, rank_value.second.first); + auto ability = ability_rank.first; + auto rank = ability_rank.second; + + if(!rank) { + continue; + } + + m_pp.aa_array[i].AA = rank_value.first; + m_pp.aa_array[i].value = rank_value.second.first; + m_pp.aa_array[i].charges = rank_value.second.second; + ++i; + } for(int i = 0; i < _maxLeaderAA; ++i) m_pp.leader_abilities.ranks[i] = 0; @@ -1503,21 +469,15 @@ void Client::ResetAA(){ m_pp.group_leadership_exp = 0; m_pp.raid_leadership_exp = 0; - database.DeleteCharacterAAs(this->CharacterID()); - SaveAA(); - SendClearAA(); - SendAAList(); - SendAATable(); - SendAAStats(); - database.DeleteCharacterLeadershipAAs(this->CharacterID()); + database.DeleteCharacterLeadershipAAs(CharacterID()); // undefined for these clients - if (GetClientVersionBit() & BIT_TitaniumAndEarlier) + if (ClientVersionBit() & EQEmu::versions::bit_TitaniumAndEarlier) Kick(); } void Client::SendClearAA() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ClearLeadershipAbilities, 0); + auto outapp = new EQApplicationPacket(OP_ClearLeadershipAbilities, 0); FastQueuePacket(&outapp); outapp = new EQApplicationPacket(OP_ClearAA, 0); FastQueuePacket(&outapp); @@ -1773,7 +733,7 @@ void Client::InspectBuffs(Client* Inspector, int Rank) if (!Inspector || Rank == 0) return; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_InspectBuffs, sizeof(InspectBuffs_Struct)); + auto outapp = new EQApplicationPacket(OP_InspectBuffs, sizeof(InspectBuffs_Struct)); InspectBuffs_Struct *ib = (InspectBuffs_Struct *)outapp->pBuffer; uint32 buff_count = GetMaxTotalSlots(); @@ -1790,268 +750,43 @@ void Client::InspectBuffs(Client* Inspector, int Rank) Inspector->FastQueuePacket(&outapp); } -//this really need to be renamed to LoadAAActions() -bool ZoneDatabase::LoadAAEffects() { - memset(AA_Actions, 0, sizeof(AA_Actions)); //I hope the compiler is smart about this size... +void Client::RefundAA() { + int refunded = 0; - const std::string query = "SELECT aaid, rank, reuse_time, spell_id, target, " - "nonspell_action, nonspell_mana, nonspell_duration, " - "redux_aa, redux_rate, redux_aa2, redux_rate2 FROM aa_actions"; - auto results = QueryDatabase(query); - if (!results.Success()) { - return false; - } + auto rank_value = aa_ranks.begin(); + while(rank_value != aa_ranks.end()) { + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_value->first, rank_value->second.first); + auto ability = ability_rank.first; + auto rank = ability_rank.second; - for (auto row = results.begin(); row != results.end(); ++row) { - - int aaid = atoi(row[0]); - int rank = atoi(row[1]); - if(aaid < 0 || aaid >= aaHighestID || rank < 0 || rank >= MAX_AA_ACTION_RANKS) + if(!ability) { + ++rank_value; continue; - AA_DBAction *caction = &AA_Actions[aaid][rank]; - - caction->reuse_time = atoi(row[2]); - caction->spell_id = atoi(row[3]); - caction->target = (aaTargetType) atoi(row[4]); - caction->action = (aaNonspellAction) atoi(row[5]); - caction->mana_cost = atoi(row[6]); - caction->duration = atoi(row[7]); - caction->redux_aa = (aaID) atoi(row[8]); - caction->redux_rate = atoi(row[9]); - caction->redux_aa2 = (aaID) atoi(row[10]); - caction->redux_rate2 = atoi(row[11]); - - } - - return true; -} - -//Returns the number effects an aa.has when we send them to the client -//For the purposes of sizing a packet because every skill does not -//have the same number effects, they can range from none to a few depending on AA. -//counts the # of effects by counting the different slots of an AAID in the DB. - -//AndMetal: this may now be obsolete since we have Zone::GetTotalAALevels() -uint8 ZoneDatabase::GetTotalAALevels(uint32 skill_id) { - - std::string query = StringFormat("SELECT count(slot) FROM aa_effects WHERE aaid = %i", skill_id); - auto results = QueryDatabase(query); - if (!results.Success()) { - return 0; - } - - if (results.RowCount() != 1) - return 0; - - auto row = results.begin(); - - return atoi(row[0]); -} - -//this will allow us to count the number of effects for an AA by pulling the info from memory instead of the database. hopefully this will same some CPU cycles -uint8 Zone::GetTotalAALevels(uint32 skill_id) { - size_t sz = aa_effects[skill_id].size(); - return sz >= 255 ? 255 : static_cast(sz); -} - -/* -Every AA can send the client effects, which are purely for client side effects. -Essentially it's like being able to attach a very simple version of a spell to -Any given AA, it has 4 fields: -skill_id = spell effect id -slot = ID slot, doesn't appear to have any impact on stacking like real spells, just needs to be unique. -base1 = the base field of a spell -base2 = base field 2 of a spell, most AAs do not utilize this -example: - skill_id = SE_STA - slot = 1 - base1 = 15 - This would if you filled the abilities struct with this make the client show if it had - that AA an additional 15 stamina on the client's stats -*/ -void ZoneDatabase::FillAAEffects(SendAA_Struct* aa_struct){ - if(!aa_struct) - return; - - auto it = aa_effects.find(aa_struct->id); - if (it != aa_effects.end()) { - for (uint32 slot = 0; slot < aa_struct->total_abilities; slot++) { - // aa_effects is a map of a map, so the slot reference does not start at 0 - aa_struct->abilities[slot].skill_id = it->second[slot + 1].skill_id; - aa_struct->abilities[slot].base1 = it->second[slot + 1].base1; - aa_struct->abilities[slot].base2 = it->second[slot + 1].base2; - aa_struct->abilities[slot].slot = it->second[slot + 1].slot; } - } -} -uint32 ZoneDatabase::CountAAs(){ - - const std::string query = "SELECT count(title_sid) FROM altadv_vars"; - auto results = QueryDatabase(query); - if (!results.Success()) { - return 0; - } - - if (results.RowCount() != 1) - return 0; - - auto row = results.begin(); - - return atoi(row[0]);; -} - -uint32 ZoneDatabase::CountAAEffects() { - - const std::string query = "SELECT count(id) FROM aa_effects"; - auto results = QueryDatabase(query); - if (!results.Success()) { - return 0; - } - - if (results.RowCount() != 1) - return 0; - - auto row = results.begin(); - - return atoi(row[0]); -} - -uint32 ZoneDatabase::GetSizeAA(){ - int size=CountAAs()*sizeof(SendAA_Struct); - if(size>0) - size+=CountAAEffects()*sizeof(AA_Ability); - return size; -} - -void ZoneDatabase::LoadAAs(SendAA_Struct **load){ - if(!load) - return; - - std::string query = "SELECT skill_id FROM altadv_vars ORDER BY skill_id"; - auto results = QueryDatabase(query); - if (results.Success()) { - int skill = 0, index = 0; - for (auto row = results.begin(); row != results.end(); ++row, ++index) { - skill = atoi(row[0]); - load[index] = GetAASkillVars(skill); - load[index]->seq = index+1; + if(ability->charges > 0 && rank_value->second.second < 1) { + ++rank_value; + continue; } - } else { + + if(ability->grant_only) { + ++rank_value; + continue; + } + + refunded += rank->total_cost; + rank_value = aa_ranks.erase(rank_value); } - AARequiredLevelAndCost.clear(); - query = "SELECT skill_id, level, cost from aa_required_level_cost order by skill_id"; - results = QueryDatabase(query); - if (!results.Success()) { - return; + if(refunded > 0) { + m_pp.aapoints += refunded; + SaveAA(); + Save(); } - AALevelCost_Struct aalcs; - for (auto row = results.begin(); row != results.end(); ++row) { - aalcs.Level = atoi(row[1]); - aalcs.Cost = atoi(row[2]); - AARequiredLevelAndCost[atoi(row[0])] = aalcs; - } -} - -SendAA_Struct* ZoneDatabase::GetAASkillVars(uint32 skill_id) -{ - std::string query = "SET @row = 0"; //initialize "row" variable in database for next query - auto results = QueryDatabase(query); - if (!results.Success()) { - return nullptr; - } - - query = StringFormat("SELECT a.cost, a.max_level, a.hotkey_sid, a.hotkey_sid2, a.title_sid, a.desc_sid, a.type, " - "COALESCE(" //So we can return 0 if it's null. - "(" // this is our derived table that has the row # - // that we can SELECT from, because the client is stupid. - "SELECT p.prereq_index_num " - "FROM (SELECT a2.skill_id, @row := @row + 1 AS prereq_index_num " - "FROM altadv_vars a2) AS p " - "WHERE p.skill_id = a.prereq_skill), 0) " - "AS prereq_skill_index, a.prereq_minpoints, a.spell_type, a.spell_refresh, a.classes, " - "a.berserker, a.spellid, a.class_type, a.name, a.cost_inc, a.aa_expansion, a.special_category, " - "a.sof_type, a.sof_cost_inc, a.sof_max_level, a.sof_next_skill, " - "a.clientver, " // Client Version 0 = None, 1 = All, 2 = Titanium/6.2, 4 = SoF 5 = SOD 6 = UF - "a.account_time_required, a.sof_current_level, a.sof_next_id, a.level_inc " - "FROM altadv_vars a WHERE skill_id=%i", skill_id); - results = QueryDatabase(query); - if (!results.Success()) { - return nullptr; - } - - if (results.RowCount() != 1) - return nullptr; - - int total_abilities = GetTotalAALevels(skill_id); //eventually we'll want to use zone->GetTotalAALevels(skill_id) since it should save queries to the DB - int totalsize = total_abilities * sizeof(AA_Ability) + sizeof(SendAA_Struct); - - SendAA_Struct* sendaa = nullptr; - uchar* buffer; - - buffer = new uchar[totalsize]; - memset(buffer,0,totalsize); - sendaa = (SendAA_Struct*)buffer; - - auto row = results.begin(); - - //ATOI IS NOT UNSIGNED LONG-SAFE!!! - - sendaa->cost = atoul(row[0]); - sendaa->cost2 = sendaa->cost; - sendaa->max_level = atoul(row[1]); - sendaa->hotkey_sid = atoul(row[2]); - sendaa->id = skill_id; - sendaa->hotkey_sid2 = atoul(row[3]); - sendaa->title_sid = atoul(row[4]); - sendaa->desc_sid = atoul(row[5]); - sendaa->type = atoul(row[6]); - sendaa->prereq_skill = atoul(row[7]); - sendaa->prereq_minpoints = atoul(row[8]); - sendaa->spell_type = atoul(row[9]); - sendaa->spell_refresh = atoul(row[10]); - sendaa->classes = static_cast(atoul(row[11])); - sendaa->berserker = static_cast(atoul(row[12])); - sendaa->last_id = 0xFFFFFFFF; - sendaa->current_level=1; - sendaa->spellid = atoul(row[13]); - sendaa->class_type = atoul(row[14]); - strcpy(sendaa->name,row[15]); - - sendaa->total_abilities=total_abilities; - if(sendaa->max_level > 1) - sendaa->next_id=skill_id+1; - else - sendaa->next_id=0xFFFFFFFF; - - sendaa->cost_inc = atoi(row[16]); - - // Begin SoF Specific/Adjusted AA Fields - sendaa->aa_expansion = atoul(row[17]); - sendaa->special_category = atoul(row[18]); - sendaa->sof_type = atoul(row[19]); - sendaa->sof_cost_inc = atoi(row[20]); - sendaa->sof_max_level = atoul(row[21]); - sendaa->sof_next_skill = atoul(row[22]); - sendaa->clientver = atoul(row[23]); - sendaa->account_time_required = atoul(row[24]); - - //Internal use only - not sent to client - sendaa->sof_current_level = atoul(row[25]); - sendaa->sof_next_id = atoul(row[26]); - sendaa->level_inc = static_cast(atoul(row[27])); - - return sendaa; -} - -void Client::DurationRampage(uint32 duration) -{ - if(duration) { - m_epp.aa_effects |= 1 << (aaEffectRampage-1); - p_timers.Start(pTimerAAEffectStart + aaEffectRampage, duration); - } + SendAlternateAdvancementTable(); + SendAlternateAdvancementPoints(); + SendAlternateAdvancementStats(); } AA_SwarmPetInfo::AA_SwarmPetInfo() @@ -2072,3 +807,923 @@ Mob *AA_SwarmPetInfo::GetOwner() { return entity_list.GetMobID(owner_id); } + +//New AA +void Client::SendAlternateAdvancementTable() { + for(auto &aa : zone->aa_abilities) { + uint32 charges = 0; + auto ranks = GetAA(aa.second->first_rank_id, &charges); + if(ranks) { + if(aa.second->GetMaxLevel(this) == ranks) { + SendAlternateAdvancementRank(aa.first, ranks); + } else { + SendAlternateAdvancementRank(aa.first, ranks); + SendAlternateAdvancementRank(aa.first, ranks + 1); + } + } else { + SendAlternateAdvancementRank(aa.first, 1); + } + } +} + +void Client::SendAlternateAdvancementRank(int aa_id, int level) { + if(!zone) + return; + + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa_id, level); + auto ability = ability_rank.first; + auto rank = ability_rank.second; + + if(!ability) { + return; + } + + if(!(ability->classes & (1 << GetClass()))) { + return; + } + + if(!CanUseAlternateAdvancementRank(rank)) { + return; + } + + int size = sizeof(AARankInfo_Struct) + (sizeof(AARankEffect_Struct) * rank->effects.size()) + (sizeof(AARankPrereq_Struct) * rank->prereqs.size()); + auto outapp = new EQApplicationPacket(OP_SendAATable, size); + AARankInfo_Struct *aai = (AARankInfo_Struct*)outapp->pBuffer; + + aai->id = rank->id; + aai->upper_hotkey_sid = rank->upper_hotkey_sid; + aai->lower_hotkey_sid = rank->lower_hotkey_sid; + aai->title_sid = rank->title_sid; + aai->desc_sid = rank->desc_sid; + aai->cost = rank->cost; + aai->seq = aa_id; + aai->type = ability->type; + aai->spell = rank->spell; + aai->spell_type = rank->spell_type; + aai->spell_refresh = rank->recast_time; + aai->classes = ability->classes; + aai->level_req = rank->level_req; + aai->current_level = level; + aai->max_level = ability->GetMaxLevel(this); + aai->prev_id = rank->prev_id; + + if((rank->next && !CanUseAlternateAdvancementRank(rank->next)) || ability->charges > 0) { + aai->next_id = -1; + } else { + aai->next_id = rank->next_id; + } + aai->total_cost = rank->total_cost; + aai->expansion = rank->expansion; + aai->category = ability->category; + aai->charges = ability->charges; + aai->grant_only = ability->grant_only; + aai->total_effects = rank->effects.size(); + aai->total_prereqs = rank->prereqs.size(); + + outapp->SetWritePosition(sizeof(AARankInfo_Struct)); + for(auto &effect : rank->effects) { + outapp->WriteSInt32(effect.effect_id); + outapp->WriteSInt32(effect.base1); + outapp->WriteSInt32(effect.base2); + outapp->WriteSInt32(effect.slot); + } + + for(auto &prereq : rank->prereqs) { + outapp->WriteSInt32(prereq.first); + outapp->WriteSInt32(prereq.second); + } + + QueuePacket(outapp); + safe_delete(outapp); +} + +void Client::SendAlternateAdvancementStats() { + auto outapp = new EQApplicationPacket(OP_AAExpUpdate, sizeof(AltAdvStats_Struct)); + AltAdvStats_Struct *aps = (AltAdvStats_Struct *)outapp->pBuffer; + aps->experience = (uint32)(((float)330.0f * (float)m_pp.expAA) / (float)max_AAXP); + aps->unspent = m_pp.aapoints; + aps->percentage = m_epp.perAA; + QueuePacket(outapp); + safe_delete(outapp); +} + +void Client::SendAlternateAdvancementPoints() { + auto outapp = new EQApplicationPacket(OP_RespondAA, sizeof(AATable_Struct)); + AATable_Struct* aa2 = (AATable_Struct *)outapp->pBuffer; + + int i = 0; + for(auto &aa : zone->aa_abilities) { + uint32 charges = 0; + auto ranks = GetAA(aa.second->first_rank_id, &charges); + if(ranks) { + AA::Rank *rank = aa.second->GetRankByPointsSpent(ranks); + if(rank) { + aa2->aa_list[i].AA = rank->id; + aa2->aa_list[i].value = rank->total_cost; + aa2->aa_list[i].charges = charges; + i++; + } + } + } + + + aa2->aa_spent = GetSpentAA(); + QueuePacket(outapp); + safe_delete(outapp); +} + +void Client::SendAlternateAdvancementTimer(int ability, int begin, int end) { + auto outapp = new EQApplicationPacket(OP_AAAction, sizeof(UseAA_Struct)); + UseAA_Struct* uaaout = (UseAA_Struct*)outapp->pBuffer; + uaaout->ability = ability; + uaaout->begin = begin; + uaaout->end = end; + QueuePacket(outapp); + safe_delete(outapp); +} + +//sends all AA timers. +void Client::SendAlternateAdvancementTimers() { + //we dont use SendAATimer because theres no reason to allocate the EQApplicationPacket every time + auto outapp = new EQApplicationPacket(OP_AAAction, sizeof(UseAA_Struct)); + UseAA_Struct* uaaout = (UseAA_Struct*)outapp->pBuffer; + + PTimerList::iterator c, e; + c = p_timers.begin(); + e = p_timers.end(); + for(; c != e; ++c) { + PersistentTimer *cur = c->second; + if(cur->GetType() < pTimerAAStart || cur->GetType() > pTimerAAEnd) + continue; //not an AA timer + //send timer + uaaout->begin = cur->GetStartTime(); + uaaout->end = static_cast(time(nullptr)); + uaaout->ability = cur->GetType() - pTimerAAStart; // uuaaout->ability is really a shared timer number + QueuePacket(outapp); + } + + safe_delete(outapp); +} + +void Client::ResetAlternateAdvancementTimer(int ability) { + AA::Rank *rank = zone->GetAlternateAdvancementRank(casting_spell_aa_id); + if(rank) { + SendAlternateAdvancementTimer(rank->spell_type, 0, time(0)); + p_timers.Clear(&database, rank->spell_type + pTimerAAStart); + } +} + +void Client::ResetAlternateAdvancementTimers() { + auto outapp = new EQApplicationPacket(OP_AAAction, sizeof(UseAA_Struct)); + UseAA_Struct* uaaout = (UseAA_Struct*)outapp->pBuffer; + + PTimerList::iterator c, e; + c = p_timers.begin(); + e = p_timers.end(); + std::vector r_timers; + for(; c != e; ++c) { + PersistentTimer *cur = c->second; + if(cur->GetType() < pTimerAAStart || cur->GetType() > pTimerAAEnd) + continue; + //send timer + uaaout->begin = 0; + uaaout->end = static_cast(time(nullptr)); + uaaout->ability = cur->GetType() - pTimerAAStart; + r_timers.push_back(cur->GetType()); + QueuePacket(outapp); + } + + for(auto &i : r_timers) { + p_timers.Clear(&database, i); + } + + safe_delete(outapp); +} + +void Client::PurchaseAlternateAdvancementRank(int rank_id) { + AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id); + if(!rank) { + return; + } + + if(!rank->base_ability) { + return; + } + + if(!CanPurchaseAlternateAdvancementRank(rank, true, true)) { + return; + } + + FinishAlternateAdvancementPurchase(rank, false); +} + +bool Client::GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore_cost) { + bool ret = false; + for(int i = 1; i <= points; ++i) { + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa_id, i); + auto ability = ability_rank.first; + auto rank = ability_rank.second; + + if(!rank) { + continue; + } + + if(!rank->base_ability) { + continue; + } + + if(!CanPurchaseAlternateAdvancementRank(rank, !ignore_cost, false)) { + continue; + } + + ret = true; + FinishAlternateAdvancementPurchase(rank, ignore_cost); + } + + return ret; +} + +void Client::FinishAlternateAdvancementPurchase(AA::Rank *rank, bool ignore_cost) { + int rank_id = rank->base_ability->first_rank_id; + + if(rank->base_ability->charges > 0) { + uint32 charges = 0; + GetAA(rank_id, &charges); + + if(charges > 0) { + return; + } + + SetAA(rank_id, rank->current_value, rank->base_ability->charges); + } + else { + SetAA(rank_id, rank->current_value, 0); + + //if not max then send next aa + if(rank->next) { + SendAlternateAdvancementRank(rank->base_ability->id, rank->next->current_value); + } + } + + int cost = !ignore_cost ? rank->cost : 0; + + m_pp.aapoints -= cost ; + SaveAA(); + + SendAlternateAdvancementPoints(); + SendAlternateAdvancementStats(); + + if(rank->prev) { + Message_StringID(15, AA_IMPROVE, + std::to_string(rank->title_sid).c_str(), + std::to_string(rank->prev->current_value).c_str(), + std::to_string(cost).c_str(), + cost == 1 ? std::to_string(AA_POINT).c_str() : std::to_string(AA_POINTS).c_str()); + + /* QS: Player_Log_AA_Purchases */ + if(RuleB(QueryServ, PlayerLogAAPurchases)) { + std::string event_desc = StringFormat("Ranked AA Purchase :: aa_id:%i at cost:%i in zoneid:%i instid:%i", rank->id, cost, GetZoneID(), GetInstanceID()); + QServ->PlayerLogEvent(Player_Log_AA_Purchases, CharacterID(), event_desc); + } + } + else { + Message_StringID(15, AA_GAIN_ABILITY, + std::to_string(rank->title_sid).c_str(), + std::to_string(cost).c_str(), + cost == 1 ? std::to_string(AA_POINT).c_str() : std::to_string(AA_POINTS).c_str()); + /* QS: Player_Log_AA_Purchases */ + if(RuleB(QueryServ, PlayerLogAAPurchases)) { + std::string event_desc = StringFormat("Initial AA Purchase :: aa_id:%i at cost:%i in zoneid:%i instid:%i", rank->id, cost, GetZoneID(), GetInstanceID()); + QServ->PlayerLogEvent(Player_Log_AA_Purchases, CharacterID(), event_desc); + } + } + + CalcBonuses(); + + if(cost > 0) { + if(title_manager.IsNewAATitleAvailable(m_pp.aapoints_spent, GetBaseClass())) + NotifyNewTitlesAvailable(); + } +} + +//need to rewrite this +void Client::IncrementAlternateAdvancementRank(int rank_id) { + AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id); + if(!rank) { + return; + } + + if(!rank->base_ability) { + return; + } + + int points = GetAA(rank_id); + GrantAlternateAdvancementAbility(rank->base_ability->id, points + 1, true); +} + +void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) { + AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id); + if(!rank) { + return; + } + + AA::Ability *ability = rank->base_ability; + if(!ability) { + return; + } + + if(!IsValidSpell(rank->spell)) { + return; + } + + if(!CanUseAlternateAdvancementRank(rank)) { + return; + } + + //make sure it is not a passive + if(!rank->effects.empty()) { + return; + } + + uint32 charges = 0; + // We don't have the AA + if (!GetAA(rank_id, &charges)) + return; + + //if expendable make sure we have charges + if(ability->charges > 0 && charges < 1) + return; + + //check cooldown + if(!p_timers.Expired(&database, rank->spell_type + pTimerAAStart)) { + uint32 aaremain = p_timers.GetRemainingTime(rank->spell_type + pTimerAAStart); + uint32 aaremain_hr = aaremain / (60 * 60); + uint32 aaremain_min = (aaremain / 60) % 60; + uint32 aaremain_sec = aaremain % 60; + + if(aaremain_hr >= 1) { + Message(13, "You can use this ability again in %u hour(s) %u minute(s) %u seconds", + aaremain_hr, aaremain_min, aaremain_sec); + } + else { + Message(13, "You can use this ability again in %u minute(s) %u seconds", + aaremain_min, aaremain_sec); + } + + return; + } + + //calculate cooldown + int cooldown = rank->recast_time - GetAlternateAdvancementCooldownReduction(rank); + if(cooldown < 0) { + cooldown = 0; + } + + if (!IsCastWhileInvis(rank->spell)) + CommonBreakInvisible(); + // Bards can cast instant cast AAs while they are casting another song + if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) { + if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) { + return; + } + ExpendAlternateAdvancementCharge(ability->id); + } else { + if(!CastSpell(rank->spell, target_id, EQEmu::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) { + return; + } + } + + CastToClient()->GetPTimers().Start(rank->spell_type + pTimerAAStart, cooldown); + SendAlternateAdvancementTimer(rank->spell_type, 0, 0); +} + +int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) { + if(!rank_in) { + return 0; + } + + AA::Ability *ability_in = rank_in->base_ability; + if(!ability_in) { + return 0; + } + + for(auto &aa : aa_ranks) { + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first); + auto ability = ability_rank.first; + auto rank = ability_rank.second; + + if(!ability) { + continue; + } + + for(auto &effect : rank->effects) { + if(effect.effect_id == SE_HastenedAASkill && effect.base2 == ability_in->id) { + return effect.base1; + } + } + } + + return 0; +} + +void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) { + for(auto &iter : aa_ranks) { + AA::Ability *ability = zone->GetAlternateAdvancementAbility(iter.first); + if(ability && aa_id == ability->id) { + if(iter.second.second > 0) { + iter.second.second -= 1; + + if(iter.second.second == 0) { + if(IsClient()) { + AA::Rank *r = ability->GetRankByPointsSpent(iter.second.first); + if(r) { + CastToClient()->GetEPP().expended_aa += r->cost; + } + } + if (IsClient()) { + auto c = CastToClient(); + c->RemoveExpendedAA(ability->first_rank_id); + } + aa_ranks.erase(iter.first); + } + + if(IsClient()) { + Client *c = CastToClient(); + c->SaveAA(); + c->SendAlternateAdvancementPoints(); + } + } + + return; + } + } +} + +bool ZoneDatabase::LoadAlternateAdvancement(Client *c) { + c->ClearAAs(); + std::string query = StringFormat( + "SELECT " + "aa_id, " + "aa_value, " + "charges " + "FROM " + "`character_alternate_abilities` " + "WHERE `id` = %u", c->CharacterID()); + MySQLRequestResult results = database.QueryDatabase(query); + + int i = 0; + for(auto row = results.begin(); row != results.end(); ++row) { + uint32 aa = atoi(row[0]); + uint32 value = atoi(row[1]); + uint32 charges = atoi(row[2]); + + auto rank = zone->GetAlternateAdvancementRank(aa); + if(!rank) { + continue; + } + + auto ability = rank->base_ability; + if(!ability) { + continue; + } + + rank = ability->GetRankByPointsSpent(value); + + if(c->CanUseAlternateAdvancementRank(rank)) { + c->GetPP().aa_array[i].AA = aa; + c->GetPP().aa_array[i].value = value; + c->GetPP().aa_array[i].charges = charges; + c->SetAA(aa, value, charges); + i++; + } + } + + return true; +} + +AA::Ability *Zone::GetAlternateAdvancementAbility(int id) { + auto iter = aa_abilities.find(id); + if(iter != aa_abilities.end()) { + return iter->second.get(); + } + + return nullptr; +} + +AA::Ability *Zone::GetAlternateAdvancementAbilityByRank(int rank_id) { + AA::Rank *rank = GetAlternateAdvancementRank(rank_id); + + if(!rank) + return nullptr; + + return rank->base_ability; +} + +AA::Rank *Zone::GetAlternateAdvancementRank(int rank_id) { + auto iter = aa_ranks.find(rank_id); + if(iter != aa_ranks.end()) { + return iter->second.get(); + } + + return nullptr; +} + +std::pair Zone::GetAlternateAdvancementAbilityAndRank(int id, int points_spent) { + AA::Ability *ability = GetAlternateAdvancementAbility(id); + + if(!ability) { + return std::make_pair(nullptr, nullptr); + } + + AA::Rank *rank = ability->GetRankByPointsSpent(points_spent); + if(!rank) { + return std::make_pair(nullptr, nullptr); + } + + return std::make_pair(ability, rank); +} + +uint32 Mob::GetAA(uint32 rank_id, uint32 *charges) const { + if(zone) { + AA::Ability *ability = zone->GetAlternateAdvancementAbilityByRank(rank_id); + if(!ability) + return 0; + + auto iter = aa_ranks.find(ability->id); + if(iter != aa_ranks.end()) { + if(charges) { + *charges = iter->second.second; + } + return iter->second.first; + } + } + return 0; +} + +uint32 Mob::GetAAByAAID(uint32 aa_id, uint32 *charges) const { + if(zone) { + AA::Ability *ability = zone->GetAlternateAdvancementAbility(aa_id); + + if(!ability) + return 0; + + auto iter = aa_ranks.find(ability->id); + if(iter != aa_ranks.end()) { + if(charges) { + *charges = iter->second.second; + } + return iter->second.first; + } + } + + return 0; +} + +bool Mob::SetAA(uint32 rank_id, uint32 new_value, uint32 charges) { + if(zone) { + AA::Ability *ability = zone->GetAlternateAdvancementAbilityByRank(rank_id); + + if(!ability) { + return false; + } + + if(new_value > ability->GetMaxLevel(this)) { + return false; + } + + aa_ranks[ability->id] = std::make_pair(new_value, charges); + } + + return true; +} + + +bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) { + AA::Ability *ability = rank->base_ability; + + if(!ability) + return false; + + if(!(ability->classes & (1 << GetClass()))) { + return false; + } + + // Passive and Active Shroud AAs + // For now we skip them + if(ability->category == 3 || ability->category == 4) { + return false; + } + + //the one titanium hack i will allow + //just to make sure we dont crash the client with newer aas + //we'll exclude any expendable ones + if(IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_TitaniumAndEarlier) { + if(ability->charges > 0) { + return false; + } + } + + if(IsClient()) { + if(rank->expansion && !(CastToClient()->GetPP().expansions & (1 << (rank->expansion - 1)))) { + return false; + } + } else { + if(rank->expansion && !(RuleI(World, ExpansionSettings) & (1 << (rank->expansion - 1)))) { + return false; + } + } + + auto race = GetPlayerRaceValue(GetBaseRace()); + race = race > 16 ? 1 : race; + if(!(ability->races & (1 << (race - 1)))) { + return false; + } + + auto deity = GetDeityBit(); + if(!(ability->deities & deity)) { + return false; + } + + if(IsClient() && CastToClient()->Admin() < ability->status) { + return false; + } + + if(GetBaseRace() == 522) { + //drakkin_heritage + if(!(ability->drakkin_heritage & (1 << GetDrakkinHeritage()))) { + return false; + } + } + + return true; +} + +bool Mob::CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price, bool check_grant) { + AA::Ability *ability = rank->base_ability; + + if(!ability) + return false; + + if(!CanUseAlternateAdvancementRank(rank)) { + return false; + } + + //You can't purchase grant only AAs they can only be assigned + if(check_grant && ability->grant_only) { + return false; + } + + //check level req + if(rank->level_req > GetLevel()) { + return false; + } + + uint32 current_charges = 0; + auto points = GetAA(rank->id, ¤t_charges); + + //check that we are on previous rank already (if exists) + //grant ignores the req to own the previous rank. + if(check_grant && rank->prev) { + if(points != rank->prev->current_value) { + return false; + } + } + + //check that we aren't already on this rank or one ahead of us + if(points >= rank->current_value) { + return false; + } + + //if expendable only let us purchase if we have no charges already + //not quite sure on how this functions client side atm + //I intend to look into it later to make sure the behavior is right + if(ability->charges > 0 && current_charges > 0) { + return false; + } + + //check prereqs + for(auto &prereq : rank->prereqs) { + AA::Ability *prereq_ability = zone->GetAlternateAdvancementAbility(prereq.first); + + if(prereq_ability) { + auto ranks = GetAA(prereq_ability->first_rank_id); + if(ranks < prereq.second) { + return false; + } + } + } + + //check price, if client + if(check_price && IsClient()) { + if(rank->cost > CastToClient()->GetAAPoints()) { + return false; + } + } + + return true; +} + +void Zone::LoadAlternateAdvancement() { + Log.Out(Logs::General, Logs::Status, "Loading Alternate Advancement Data..."); + if(!database.LoadAlternateAdvancementAbilities(aa_abilities, + aa_ranks)) + { + aa_abilities.clear(); + aa_ranks.clear(); + Log.Out(Logs::General, Logs::Status, "Failed to load Alternate Advancement Data"); + return; + } + + Log.Out(Logs::General, Logs::Status, "Processing Alternate Advancement Data..."); + for(const auto &ability : aa_abilities) { + ability.second->first = GetAlternateAdvancementRank(ability.second->first_rank_id); + + //process these ranks + AA::Rank *current = ability.second->first; + int i = 1; + int prev_id = -1; + while(current) { + current->prev_id = prev_id; + current->prev = GetAlternateAdvancementRank(current->prev_id); + current->next = GetAlternateAdvancementRank(current->next_id); + current->base_ability = ability.second.get(); + current->current_value = i; + + if(current->prev) { + current->total_cost = current->cost + current->prev->total_cost; + + //check prereqs here + for(auto &prev_prereq : current->prev->prereqs) { + //if prev has an aa we dont have set + // then set it here too + //if prev has an aa we have + // then set to whichever is highest + + auto iter = current->prereqs.find(prev_prereq.first); + if(iter == current->prereqs.end()) { + //not found + current->prereqs[prev_prereq.first] = prev_prereq.second; + } else { + //they already have it too! + auto points = std::max(iter->second, prev_prereq.second); + current->prereqs[iter->first] = points; + } + } + } + else { + current->prev_id = -1; + current->total_cost = current->cost; + } + + if(!current->next) { + current->next_id = -1; + } + + i++; + prev_id = current->id; + current = current->next; + } + } + + Log.Out(Logs::General, Logs::Status, "Loaded Alternate Advancement Data"); +} + +bool ZoneDatabase::LoadAlternateAdvancementAbilities(std::unordered_map> &abilities, + std::unordered_map> &ranks) +{ + Log.Out(Logs::General, Logs::Status, "Loading Alternate Advancement Abilities..."); + abilities.clear(); + std::string query = "SELECT id, name, category, classes, races, deities, drakkin_heritage, status, type, charges, " + "grant_only, first_rank_id FROM aa_ability WHERE enabled = 1"; + auto results = QueryDatabase(query); + if(results.Success()) { + for(auto row = results.begin(); row != results.end(); ++row) { + auto ability = new AA::Ability; + ability->id = atoi(row[0]); + ability->name = row[1]; + ability->category = atoi(row[2]); + //EQ client has classes left shifted by one bit for some odd reason + ability->classes = atoi(row[3]) << 1; + ability->races = atoi(row[4]); + ability->deities = atoi(row[5]); + ability->drakkin_heritage = atoi(row[6]); + ability->status = atoi(row[7]); + ability->type = atoi(row[8]); + ability->charges = atoi(row[9]); + ability->grant_only = atoi(row[10]) != 0 ? true : false; + ability->first_rank_id = atoi(row[11]); + ability->first = nullptr; + + abilities[ability->id] = std::unique_ptr(ability); + } + } else { + Log.Out(Logs::General, Logs::Error, "Failed to load Alternate Advancement Abilities"); + return false; + } + + Log.Out(Logs::General, Logs::Status, "Loaded %d Alternate Advancement Abilities", (int)abilities.size()); + + Log.Out(Logs::General, Logs::Status, "Loading Alternate Advancement Ability Ranks..."); + ranks.clear(); + query = "SELECT id, upper_hotkey_sid, lower_hotkey_sid, title_sid, desc_sid, cost, level_req, spell, spell_type, recast_time, " + "next_id, expansion FROM aa_ranks"; + results = QueryDatabase(query); + if(results.Success()) { + for(auto row = results.begin(); row != results.end(); ++row) { + auto rank = new AA::Rank; + rank->id = atoi(row[0]); + rank->upper_hotkey_sid = atoi(row[1]); + rank->lower_hotkey_sid = atoi(row[2]); + rank->title_sid = atoi(row[3]); + rank->desc_sid = atoi(row[4]); + rank->cost = atoi(row[5]); + rank->level_req = atoi(row[6]); + rank->spell = atoi(row[7]); + rank->spell_type = atoi(row[8]); + rank->recast_time = atoi(row[9]); + rank->next_id = atoi(row[10]); + rank->expansion = atoi(row[11]); + rank->base_ability = nullptr; + rank->total_cost = 0; + rank->prev_id = -1; + rank->next = nullptr; + rank->prev = nullptr; + + ranks[rank->id] = std::unique_ptr(rank); + } + } else { + Log.Out(Logs::General, Logs::Error, "Failed to load Alternate Advancement Ability Ranks"); + return false; + } + + Log.Out(Logs::General, Logs::Status, "Loaded %d Alternate Advancement Ability Ranks", (int)ranks.size()); + + Log.Out(Logs::General, Logs::Status, "Loading Alternate Advancement Ability Rank Effects..."); + query = "SELECT rank_id, slot, effect_id, base1, base2 FROM aa_rank_effects"; + results = QueryDatabase(query); + if(results.Success()) { + for(auto row = results.begin(); row != results.end(); ++row) { + AA::RankEffect effect; + int rank_id = atoi(row[0]); + effect.slot = atoi(row[1]); + effect.effect_id = atoi(row[2]); + effect.base1 = atoi(row[3]); + effect.base2 = atoi(row[4]); + + if(effect.slot < 1) + continue; + + if(ranks.count(rank_id) > 0) { + AA::Rank *rank = ranks[rank_id].get(); + rank->effects.push_back(effect); + } + } + } else { + Log.Out(Logs::General, Logs::Error, "Failed to load Alternate Advancement Ability Rank Effects"); + return false; + } + + Log.Out(Logs::General, Logs::Status, "Loaded Alternate Advancement Ability Rank Effects"); + + Log.Out(Logs::General, Logs::Status, "Loading Alternate Advancement Ability Rank Prereqs..."); + query = "SELECT rank_id, aa_id, points FROM aa_rank_prereqs"; + results = QueryDatabase(query); + if(results.Success()) { + for(auto row = results.begin(); row != results.end(); ++row) { + int rank_id = atoi(row[0]); + int aa_id = atoi(row[1]); + int points = atoi(row[2]); + + if(aa_id <= 0 || points <= 0) { + continue; + } + + if(ranks.count(rank_id) > 0) { + AA::Rank *rank = ranks[rank_id].get(); + rank->prereqs[aa_id] = points; + } + } + } else { + Log.Out(Logs::General, Logs::Error, "Failed to load Alternate Advancement Ability Rank Prereqs"); + return false; + } + + Log.Out(Logs::General, Logs::Status, "Loaded Alternate Advancement Ability Rank Prereqs"); + + return true; +} + +bool Mob::CheckAATimer(int timer) +{ + if (timer >= aaTimerMax) + return false; + if (aa_timers[timer].Enabled()) { + if (aa_timers[timer].Check(false)) { + aa_timers[timer].Disable(); + return false; + } else { + return true; + } + } + return false; +} diff --git a/zone/aa.h b/zone/aa.h index ad41fc3ae..280f56d53 100644 --- a/zone/aa.h +++ b/zone/aa.h @@ -1,27 +1,8 @@ - #ifndef AA_H #define AA_H -struct AA_Ability; -struct SendAA_Struct; - - -#define MANA_BURN 664 - -#include - #define MAX_SWARM_PETS 12 //this can change as long as you make more coords (swarm_pet_x/swarm_pet_y) -//this might be missing some, and some might not be used... -typedef enum { //AA Targeting Constants - aaTargetUser = 1, - aaTargetCurrent = 2, //use current target - aaTargetGroup = 3, //target group of user - aaTargetCurrentGroup = 4, //target group of current target - aaTargetPet = 5 //target the user's pet -} aaTargetType; - - typedef enum { aaActionNone = 0, aaActionAETaunt = 1, @@ -42,21 +23,6 @@ typedef enum { aaActionFadingMemories = 16 } aaNonspellAction; -//use these for AAs which dont cast spells, yet need effects -//if this list grows beyond 32, more work is needed in *AAEffect -typedef enum { //AA Effect IDs - aaEffectMassGroupBuff = 1, //unused - Handled via spell effect. - aaEffectRampage, - aaEffectSharedHealth, - aaEffectFlamingArrows, - aaEffectFrostArrows, - aaEffectWarcry, - aaEffectLeechTouch, - aaEffectProjectIllusion, // unused - Handled via spell effect - _maxaaEffectType = 32 -} aaEffectType; - - enum { //leadership AA indexes groupAAMarkNPC = 0, groupAANPCHealth, @@ -133,571 +99,6 @@ static const uint8 LeadershipAACosts[_maxLeaderAA][MAX_LEADERSHIP_TIERS] = { { 0, 0, 0, 0, 0, 0 }, //raidAA15 }; -/* -typedef enum { //AA IDs - aaNone = 0, - aaInnateStrength = 2, //works - aaInnateStamina = 7, //works - aaInnateAgility = 12, //works - //aaCompleteHeal = 13,/ //not implemented, but is in dbstr_us.txt - aaInnateDexterity = 17, //works - aaInnateIntelligence = 22, //works - aaInnateWisdom = 27, //works - aaInnateCharisma = 32, //works - aaInnateFireProtection = 37, //works - aaInnateColdProtection = 42, //works - aaInnateMagicProtection = 47, //works - aaInnatePoisonProtection = 52, //works - aaInnateDiseaseProtection = 57, //works - aaInnateRunSpeed = 62, //works - aaInnateRegeneration = 65, //works - aaInnateMetabolism = 68, - aaInnateLungCapacity = 71, //handled by client - aaFirstAid = 74, //untested - aaHealingAdept = 77, //untested - aaHealingGift = 80, //untested - aaSpellCastingMastery = 83, //untested - aaSpellCastingReinforcement = 86, //untested - aaMentalClarity = 89, - aaSpellCastingFury = 92, //untested - aaChanellingFocus = 95, - aaSpellCastingSubtlety = 98, //untested - aaSpellCastingExpertise = 101, //untested - aaSpellCastingDeftness = 104, //untested - aaNaturalDurability = 107, //works - aaNaturalHealing = 110, //untested - aaCombatFury = 113, //untested - aaFearResistance = 116, //untested - aaFinishingBlow = 119, //untested - aaCombatStability = 122, - aaCombatAgility = 125, - aaMassGroupBuff = 128, //untested - aaDivineResurrection = 129, //DB - aaInnateInvisToUndead = 130, //DB - aaCelestialRegeneration = 131, //untested - aaBestowDivineAura = 132, //DB - aaTurnUndead = 133, //DB - aaPurifySoul = 136, //DB - aaQuickEvacuation = 137, //untested - aaExodus = 140, //untested - aaQuickDamage = 141, //untested - aaEnhancedRoot = 144, - aaDireCharm = 145, //untested - aaCannibalization = 146, //DB - aaQuickBuff = 147, //untested - aaAlchemyMastery = 150, - aaRabidBear = 153, //DB - aaManaBurn = 154, //DB - aaImprovedFamiliar = 155, //untested, implemented? - aaNexusGate = 156, //DB - aaUnknown54 = 157, - aaPermanentIllusion = 158, - aaJewelCraftMastery = 159, - aaGatherMana = 162, //DB - aaMendCompanion = 163, //DB - aaQuickSummoning = 164, //untested - aaFrenziedBurnout = 167, //DB - aaElementalFormFire = 168, //DB - aaElementalFormWater = 171, //DB - aaElementalFormEarth = 174, //DB - aaElementalFormAir = 177, //DB - aaImprovedReclaimEnergy = 180, //untested - aaTurnSummoned = 181, //DB - aaElementalPact = 182, //DB - aaLifeBurn = 183, //DB - aaDeadMesmerization = 184, //DB - aaFearstorm = 185, //DB - aaFleshToBone = 186, //DB - aaCallToCorpse = 187, //DB - aaDivineStun = 188, //DB - aaImprovedLayOnHands = 189, - aaSlayUndead = 190, - aaActOfValor = 193, //DB - aaHolySteed = 194, //DB - aaFearless = 195, - aa2HandBash = 196, //works. handled by client? - aaInnateCamouflage = 197, //DB - aaAmbidexterity = 198, //untested - aaArcheryMastery = 199, //untested - aaFletchingMastery = 202, //removed from db? - aaEndlessQuiver = 205, //untested - aaUnholySteed = 206, //DB - aaImprovedHarmTouch = 207, //untested - aaLeechTouch = 208, //DB - aaDeathPeace = 209, - aaSoulAbrasion = 210, //untested - aaInstrumentMastery = 213, //untested - aaUnknown91 = 216, //not used - aaUnknown92 = 219, //not used - aaUnknown93 = 222, //not used - aaJamFest = 225, - aaUnknown95 = 228, - aaSonicCall = 229, - aaCriticalMend = 230, //untested - aaPurifyBody = 233, //DB - aaChainCombo = 234, - aaRapidFeign = 237, //works - aaReturnKick = 240, - aaEscape = 243, //DB - aaPoisonMastery = 244, - aaDoubleRiposte = 247, //untested - aaQuickHide = 250, - aaQuickThrow = 253, //corrected from dbstr_us.txt - aaPurgePoison = 254, //DB - aaFlurry = 255, //untested - aaRampage = 258, //untested - aaAreaTaunt = 259, //untested - aaWarcry = 260, //DB - aaBandageWound = 263, //untested - aaSpellCastingReinforcementMastery = 266, //untested - aaSpellCastingFuryMastery = 267, //untested - aaExtendedNotes = 270, //untested - aaDragonPunch = 273, - aaStrongRoot = 274, //DB - aaSingingMastery = 275, //untested - aaBodyAndMindRejuvenation = 278, //added - aaPhysicalEnhancement = 279, //untested - aaAdvTrapNegotiation = 280, //untested - aaAcrobatics = 283, //untested - aaScribbleNotes = 286, - aaChaoticStab = 287, //untested - aaPetDiscipline = 288, //added - aaHobbleofSpirits = 289, //DB - aaFrenzyofSpirit = 290, //DB - aaParagonofSpirit = 291, //DB - aaAdvancedInnateStrength = 292, //works - aaAdvancedInnateStamina = 302, //works - aaAdvancedInnateAgility = 312, //works - aaAdvancedInnateDexterity = 322, //works - aaAdvancedInnateIntelligence = 332, //works - aaAdvancedInnateWisdom = 342, //works - aaAdvancedInnateCharisma = 352, //works - aaWardingofSolusek = 362, //works - aaBlessingofEci = 372, //works - aaMarrsProtection = 382, //works - aaShroudofTheFaceless = 392, //works - aaBertoxxulousGift = 402, //works - aaNewTanaanCraftingMastery = 412, - aaPlanarPower = 418, //untested - aaPlanarDurability = 423, //added - aaInnateEnlightenment = 426, //added - aaAdvancedSpellCastingMastery = 431,//untested - aaAdvancedHealingAdept = 434, //untested - aaAdvancedHealingGift = 437, //untested - aaCoupdeGrace = 440, //added - aaFuryoftheAges = 443, //added - aaMasteryofthePast = 446, //untested - aaLightningReflexes = 449, //added - aaInnateDefense = 454, //added - aaRadiantCure = 459, //DB - aaHastenedDivinity = 462, //DB - aaHastenedTurning = 465, //DB - aaHastenedPurificationofSoul = 468, //DB - aaHastenedGathering = 471, //DB - aaHastenedRabidity = 474, //DB - aaHastenedExodus = 477, //DB - aaHastenedRoot = 480, //DB - aaHastenedMending = 483, //DB - aaHastenedBanishment = 486, //DB - aaHastenedInstigation = 489, //DB, maybe - aaFuriousRampage = 492, //DB - aaHastenedPurificationoftheBody = 495,//DB - aaHastyExit = 498, //DB - aaHastenedPurification = 501, //DB - aaFlashofSteel = 504, - aaDivineArbitration = 507, //DB - aaWrathoftheWild = 510, //DB - aaVirulentParalysis = 513, //DB - aaHarvestofDruzzil = 516, //DB - aaEldritchRune = 517, //DB - aaServantofRo = 520, //DB - aaWaketheDead = 523, //DB - aaSuspendedMinion = 526, //untested - aaSpiritCall = 528, //DB - aaCelestialRenewal = 531, //DB - aaAllegiantFamiliar = 533, - aaHandofPiety = 534, //DB - aaMithanielsBinding = 537, //untested - aaMendingoftheTranquil = 539, - aaRagingFlurry = 542, - aaGuardianoftheForest = 545, //DB - aaSpiritoftheWood = 548, //DB - aaBestialFrenzy = 551, //untested - aaHarmoniousAttack = 556, //untested - aaKnightsAdvantage = 561, - aaFerocity = 564, - aaViscidRoots = 567, - aaSionachiesCrescendo = 568, //untested - aaAyonaesTutelage = 571, - aaFeignedMinion = 574, - aaUnfailingDivinity = 577, - aaAnimationEmpathy = 580, // Implemented - aaRushtoJudgement = 583, - aaLivingShield = 586, - aaConsumptionoftheSoul = 589, //untested - aaBoastfulBellow = 592, //DB - aaFervrentBlessing = 593, //untested - aaTouchoftheWicked = 596, //untested - aaPunishingBlade = 599, - aaSpeedoftheKnight = 602, - aaShroudofStealth = 605, - aaNimbleEvasion = 606, - aaTechniqueofMasterWu = 611, - aaHostoftheElements = 616, //DB - aaCallofXuzl = 619, //DB - aaHastenedStealth = 622, - aaIngenuity = 625, - aaFleetofFoot = 628, - aaFadingMemories = 630, - aaTacticalMastery = 631, - aaTheftofLife = 634, - aaFuryofMagic = 637, - aaFuryofMagicMastery2 = 640, //whats the difference? - aaProjectIllusion = 643, - aaHeadshot = 644, //added - aaEntrap = 645, //DB - aaUnholyTouch = 646, //untested - aaTotalDomination = 649, // Implemented - aaStalwartEndurance = 652, //implemented as bonus - aaQuickSummoning2 = 655, //whats the difference? - aaMentalClarity2 = 658, //whats the difference? - aaInnateRegeneration2 = 661, //whats the difference? - aaManaBurn2 = 664, //whats the difference? - aaExtendedNotes2 = 665, //not implemented - later expansions replaced Extended Notes with this. - aaSionachiesCrescendo2 = 668, //not implemented - later expansions replaced Sionachies Crescendo with this. - aaImprovedReclaimEnergy2 = 671, //whats the difference? untetsed - aaSwiftJourney = 672, //implemented as bonus - aaConvalescence = 674, //added 9/26/08 - aaLastingBreath = 676, //handled by client - aaPackrat = 678, //added 9/29/08 - aaHeightenedEndurance = 683, - aaWeaponAffinity = 686, //implemented - aaSecondaryForte = 691, - aaPersistantCasting = 692, - aaTuneofPursuance = 695, - aaImprovedInstrumentMastery = 700, - aaImprovedSingingMastery =701, - aaExultantBellowing = 702, - aaEchoofTaelosia = 707, - aaInternalMetronome = 710, //In 2006 this AA was removed. - aaPiousSupplication = 715, - aaBeastialAlignment = 718, //untested - aaWrathofXuzl = 721, - aaFeralSwipe = 723, //DB? - aaWardersFury = 724, - aaWardersAlacrity = 729, - aaPetAffinity = 734, // Implemented - aaMasteryofthePast2 = 735, //whats the difference? - aaSpellCastingSubtlety2 = 738, //whats the difference? - aaTouchoftheDivine = 741, - aaDivineAvatar = 746, //DB - aaExquisiteBenediction = 749, //DB - aaQuickenedCuring = 754, - aaNaturesBoon = 757, //DB - aaAdvancedTracking = 762, - aaCriticalAffliction = 767, - aaFuryofMagicMastery = 770, //whats the difference? - aaDoppelganger = 773, - aaEnchancedForgetfulness = 776, - aaMesmerizationMastery = 781, - aaQuickMassGroupBuff = 782, - aaSharedHealth = 785, - aaElementalFury = 790, - aaElementalAlacrity = 795, - aaElementalAgility = 800, - aaElementalDurability = 803, - aaSinisterStrikes = 806, - aaStrikethrough = 807, - aaStonewall = 810, - aaRapidStrikes = 815, - aaKickMastery = 820, - aaHightenedAwareness = 823, - aaDestructiveForce = 828, //DB - aaSwarmofDecay = 831, //DB - aaDeathsFury = 834, - aaQuickeningofDeath = 839, - aaAdvancedTheftofLife = 844, - aaTripleBackstab = 846, - aaHastenedPiety = 849, - aaImmobilizingBash = 852, - aaViciousSmash = 855, - aaRadiantCure2 = 860, //whats the difference? - aaPurification = 863, - aaPrecisionofthePathfinder = 864, - aaCoatofThistles = 867, - aaFlamingArrows = 872, //untested - aaFrostArrows = 875, //untested - aaSeizedOpportunity = 878, - aaTrapCircumvention = 881, - aaImprovedHastyExit = 886, - aaVirulentVenom = 888, - aaImprovedConsumptionofSoul = 893, - aaIntenseHatred = 895, - aaAdvancedSpiritCall = 900, - aaCalloftheAncients = 902, //DB - aaSturdiness = 907, - aaWarlordsTenacity = 912, //DB - aaStrengthenedStrike = 915, - aaExtendedShielding = 918, - aaRosFlamingFamiliar = 921, //DB - aaEcisIcyFamiliar = 922, //DB - aaDruzzilsMysticalFamiliar = 923, //DB - aaAdvancedFuryofMagicMastery = 924, //added 9/29/08 - aaWardofDestruction = 926, //DB - aaFrenziedDevastation = 931, //DB - aaCombatFury2 = 934, //whats the difference? - aaCombatFury3 = 937, //whats the difference? - aaCombatFury4 = 940, //whats the difference? - aaFuryoftheAges2 = 943, //whats the difference? - aaFuryoftheAges3 = 946, //whats the difference? - aaFuryoftheAges4 = 949, //whats the difference? - aaPlanarDurability2 = 952, //whats the difference? - aaInnateEnlightenment2 = 955, //whats the difference? - aaDireCharm2 = 960, //whats the difference? - aaDireCharm3 = 961, //whats the difference? - aaTouchoftheDivine2 = 962, //whats the difference? - aaTouchofDecay = 967, - aaCalloftheAncients2 = 970, //whats the difference? - aaImprovedVision = 975, - aaEternalBreath = 978, //handled by client - aaBlacksmithingMastery = 979, //added 9/29/08 - aaBakingMastery = 982, //added 9/29/08 - aaBrewingMastery = 985, //added 9/29/08 - aaFletchingMastery2 = 988, //added 9/29/08 - aaPotteryMastery = 991, //added 9/29/08 - aaTailoringMastery = 994, //added 9/29/08 - aaSalvage = 997, - aaOrigin = 1000, //spell - aaChaoticPotential = 1001, //added - aaDiscordantDefiance = 1006, //added 9/29/08 - aaTrialsofMataMuram = 1011, - aaMysticalAttuning = 1021, - aaDelayDeath = 1026, - aaHealthyAura = 1031, - aaFitness = 1036, - aaVeteransWrath = 1041, //added 9/29/08 - aaVeteransWrath2 = 1044, //whats the difference? - aaVeteransWrath3 = 1047, //whats the difference? - aaVeteransWrath4 = 1050, //whats the difference? - aaDeathblow = 1053, - aaReflexiveMastery = 1061, - aaDefensiveInstincts = 1066, - aaMnemonicRetention = 1071, //Implemented - aaExpansiveMind = 1072, //added 9/29/08 - aaSleightofHand = 1077, - aaSleightofHand2 = 1080, //whats the difference? - aaHealingAdeptMastery = 1083, - aaHealingGiftMastery = 1086, - aaArcaneTongues = 1089, - aaMasterofDisguise = 1092, - aaSlipperyAttacks = 1093, - aaImprovedCriticalAffliction = 1099, - aaFortifiedBellowing = 1102, - aaFuryofMagic2 = 1107, //whats the difference? - aaDanceofBlades = 1110, - aaShieldofNotes = 1116, - aaRoarofThunder = 1119, - aaPersistentMinion = 1122, - aaPerfectionofSpirit = 1123, - aaReplentishCompanion = 1126, - aaAdvancedPetDiscipline = 1129, - aaThrowingMastery = 1131, - aaBlurofAxes = 1134, - aaHastenedWarCry = 1137, - aaDeadAim = 1140, - aaFrenziedDefense = 1143, - aaTirelessSprint = 1146, - aaDesperation = 1149, - aaUntamedRage = 1150, - aaEchoingCries = 1155, - aaViciousFrenzy = 1158, - aaCrazedOnslaught = 1163, - aaOverwhelmingAttack = 1172, - aaFuriousRage = 1175, - aaBloodPact = 1178, - aaShieldingResistance = 1181, - aaHealingBoon = 1186, - aaResplendentCure = 1189, - aaCelestialHammer = 1192, - aaDivineRetribution = 1195, - aaCelestialRejuvination = 1203, - aaFerventBenediction = 1206, - aaSanctuary = 1209, - aaDestructiveFury = 1210, //added 9/29/08 - aaDestructiveFury2 = 1213, //whats the difference? - aaBoonoftheForest = 1222, - aaSpiritoftheGrove = 1225, - aaCalloftheWild = 1228, - aaSecondaryRecall = 1229, - aaNaturesBounty = 1230, - aaStasis = 1233, - aaColorShock = 1239, - aaMindOverMatter = 1242, - aaSoothingWords = 1245, - aaElementalSwarm = 1248, - aaHeartofFlames = 1251, - aaHeartofVapor = 1252, - aaHeartofIce = 1253, - aaHeartofStone = 1254, - aaImitateDeath = 1255, - aaCripplingStrike = 1256, - aaStunningKick = 1259, - aaEyeGouge = 1262, - aaIronKicks = 1265, - aaStyleoftheMimic = 1268, - aaDeathPeace2 = 1272, //whats the difference? - aaArmyoftheDead = 1274, - aaCelestialStun = 1277, - aaHandofDevotion = 1278, - aaSteadfastWill = 1284, - aaShieldBlock = 1287, - aaScoutsEfficiency = 1290, - aaGuardianoftheGlade = 1293, - aaTrackingMastery = 1296, - aaFlurryofKnives = 1301, - aaPrecision = 1304, - aaNervesofSteel = 1307, - aaTouchoftheCursed = 1313, - aaSpiritualCorrosion = 1316, - aaSoulThief = 1319, - aaSpiritualChanneling = 1323, - aaBoonoftheAncients = 1324, - aaAncestralAid = 1327, - aaResoluteDefiance = 1330, - aaPresstheAttack = 1333, - aaMindCrash = 1334, - aaProlongedDestruction = 1337, - aaRosGreaterFamiliar = 1340, - aaEcisGreaterFamiliar = 1341, - aaDruzzilsGreaterFamiliar = 1342, - aaTeleportBind = 1343, - aaDevotedFamiliar = 1344, - aaAuspiceoftheHunter = 1345, - aaSavageSpirit = 1348, - aaPresstheAttack2 = 1351, //whats the difference? - aaCripplingStrike2 = 1352, //whats the difference? - aaStunningKick2 = 1353, //whats the difference? - aaEyeGouge2 = 1358, //whats the difference? - - //Dragons of Norrath - //good info here: http://www.eqthieves.com/exp-don-progression.htm and here: http://everquest.allakhazam.com/db/guides.html?guide=811 - aaGiftoftheDarkReign = 1361, //from dbstr_us.txt - aaTenacityoftheDarkReign = 1362, //from dbstr_us.txt - aaEmbraceoftheDarkReign = 1363, //from dbstr_us.txt - aaPoweroftheDarkReign = 1364, //from dbstr_us.txt - aaFervoroftheDarkReign = 1365, //from dbstr_us.txt - aaGiftoftheKeepers = 1366, //from dbstr_us.txt - aaValoroftheKeepers = 1367, //from dbstr_us.txt - aaEmbraceoftheKeepers = 1368, //from dbstr_us.txt - aaPoweroftheKeepers = 1369, //from dbstr_us.txt - aaSanctityoftheKeepers = 1370, //from dbstr_us.txt - - //Veteran AAs - aaLessonoftheDevoted = 1371, //from dbstr_us.txt - aaInfusionoftheFaithful = 1372, //from dbstr_us.txt - aaChaoticJester = 1373, //from dbstr_us.txt - aaExpedientRecovery = 1374, //from dbstr_us.txt - aaSteadfastServant = 1375, //from dbstr_us.txt - aaStaunchRecovery = 1376, //from dbstr_us.txt - aaIntensityoftheResolute = 1377, //from dbstr_us.txt - - //Depths of Darkhollow - - //the following 5 look to be used as flags for completion of the Blood Raids for access to the Demiplane of Blood - //quest info here: http://everquest.allakhazam.com/db/quest.html?quest=3582 - //"You must also complete the five Blood Raids in any order: The Council of Nine, Emperor Draygun, Bloodeye, Matriarch Shyra, Sendaii, the Hive Queen" - //"The AA's you receive are: Curse of Blood (1/5), Affliction of Blood (2/5), Torment of Blood (3/5), Temptation of Blood (4/5), Invitation of Blood (5/5)." - aaCurseofBlood = 1378, //from dbstr_us.txt - aaAfflictionofBlood = 1379, //from dbstr_us.txt - aaTormentofBlood = 1380, //from dbstr_us.txt - aaTemptationofBlood = 1381, //from dbstr_us.txt - aaInvitationofBlood = 1382, //from dbstr_us.txt - - aaTurnUndead2 = 1383, //from dbstr_us.txt, Class AA changed in DoD - aaWrackUndead = 1386, //from dbstr_us.txt, PoP Class AA changed in DoD - aaEradicateUndead = 1387, //from dbstr_us.txt - aaInnateSeeInvis = 1388, //from dbstr_us.txt - aaProlongedMortality = 1389, //from dbstr_us.txt - aaPrecognition = 1394, //from dbstr_us.txt - aaThickSkin = 1399, //from dbstr_us.txt - aaSilentCasting = 1404, //from dbstr_us.txt - aaSilentCasting2 = 1409, //from dbstr_us.txt - aaHastenedMindCrash = 1414, //from dbstr_us.txt - aaFieldDressing = 1417, //from dbstr_us.txt - aaBandageWounds = 1420, //from dbstr_us.txt - aaCascadingRage = 1425, //from dbstr_us.txt - aaElementalFerocity = 1430, //from dbstr_us.txt - aaGiftofMana = 1435, //from dbstr_us.txt - aaRuneofShadows = 1440, //from dbstr_us.txt - aaChannelingMastery = 1445, //from dbstr_us.txt - aaConservation = 1453, //from dbstr_us.txt - aaCryofBattle = 1458, //from dbstr_us.txt - aaWardofPurity = 1459, //from dbstr_us.txt - aaTurnSummoned2 = 1462, //from dbstr_us.txt - aaWrackSummoned = 1465, //from dbstr_us.txt - aaEradicateSummoned = 1466, //from dbstr_us.txt - aaWardersSavagery = 1467, //from dbstr_us.txt - aaShackleofSpirits = 1470, //from dbstr_us.txt - aaHastenedThunder = 1471, //from dbstr_us.txt - aaTranslocationalAnchor = 1474, //from dbstr_us.txt - aaStealthyGetaway = 1477, //from dbstr_us.txt - aaPyromancy = 1478, //from dbstr_us.txt - aaMasteryofFury = 1483, //from dbstr_us.txt - aaAbundantHealing = 1486, //from dbstr_us.txt - aaGreaterAvatar = 1491, //from dbstr_us.txt - aaSharedCamouflage = 1494, //from dbstr_us.txt - aaConvergenceofSpirits = 1495, //from dbstr_us.txt - aaNaturesGuardian = 1498, //from dbstr_us.txt - aaEdictofCommand = 1501, //from dbstr_us.txt - aaExtendedBurnout = 1504, //from dbstr_us.txt - aaGuardianofRo = 1507, //from dbstr_us.txt - aaBloodMagic = 1510, //from dbstr_us.txt - aaGraverobbing = 1511, //from dbstr_us.txt - aaAfflictionMastery = 1514, //from dbstr_us.txt - aaGreaterRabidBear = 1517, //from dbstr_us.txt - aaAncestralGuard = 1520, //from dbstr_us.txt - aaCloakofLight = 1523, //from dbstr_us.txt - aaVanquishUndead = 1524, //from dbstr_us.txt - aaCloakofShadows = 1527, //from dbstr_us.txt - aaWillfulDeath = 1528, //from dbstr_us.txt - aaSwiftBlade = 1533, //from dbstr_us.txt - aaWickedBlade = 1536, //from dbstr_us.txt - aaForcedOpening = 1539, //from dbstr_us.txt - aaAppraisal = 1542, //from dbstr_us.txt - aaPreciseStrikes = 1543, //from dbstr_us.txt - aaHastenedDeath = 1546, //from dbstr_us.txt - aaUnflinchingResolve = 1549, //from dbstr_us.txt - aaWeightlessSteps = 1552, //from dbstr_us.txt - aaHastenedBlades = 1555, //from dbstr_us.txt - aaImprovedHarmoniousAttack = 1563, //from dbstr_us.txt - aaImprovedBestialFrenzy = 1566, //from dbstr_us.txt - aaSongofStone = 1569, //from dbstr_us.txt - aaDeepSleep = 1572, //from dbstr_us.txt - aaCompanionsGift = 1577, //from dbstr_us.txt - aaHastenedDefiance = 1583, //from dbstr_us.txt - aaDauntlessPerseverance = 1586, //from dbstr_us.txt - aaConcentration = 1587, //from dbstr_us.txt - aaEnhancedAggression = 1592, //from dbstr_us.txt - aaCallofChallenge = 1597, //from dbstr_us.txt - aaCacophony = 1598, //from dbstr_us.txt - aaImprovedHeadshot = 1601, //from dbstr_us.txt - aaAnatomy = 1604, //from dbstr_us.txt - aaFetterofSpirits = 1607, //from dbstr_us.txt - aaTrickShot = 1608, //from dbstr_us.txt - aaLightningStrikes = 1616, //from dbstr_us.txt - aaRelentlessAssault = 1621, //from dbstr_us.txt - aaKnightsExpertise = 1624, //from dbstr_us.txt - aaSelosEnduringCadence = 1627, //from dbstr_us.txt - aaHarmTouch = 7800, //from dbstr_us.txt - aaLayonHands = 7850, //from dbstr_us.txt - aaLayonHandsRank16 = 7866, - - aaHighestID //this should always be last, and should always - //follow the highest AA ID -} aaID; -*/ - - typedef enum { //AA IDs aaNone =0, aaInnateStrength =2,//implemented as bonus @@ -2109,21 +1510,6 @@ typedef enum { //AA IDs //follow the highest AA ID } aaID; - -//Structure representing the database's AA actions -struct AA_DBAction { - uint32 reuse_time; //in seconds - uint16 spell_id; //spell to cast, SPELL_UNKNOWN=no spell - aaTargetType target; //from aaTargetType - aaNonspellAction action; //non-spell action to take - uint16 mana_cost; //mana the NON-SPELL action costs - uint16 duration; //duration of NON-SPELL effect, 0=N/A - aaID redux_aa; //AA which reduces reuse time - int32 redux_rate; //%/point in redux_aa reduction in reuse time - aaID redux_aa2; //AA which reduces reuse time - int32 redux_rate2; //%/point in redux_aa reduction in reuse time -}; - //Structure representing the database's swarm pet configs struct AA_SwarmPet { uint8 count; //number to summon @@ -2131,23 +1517,6 @@ struct AA_SwarmPet { uint16 duration; //how long they last, in seconds }; -struct AALevelCost_Struct -{ - uint32 Level; - uint32 Cost; -}; - -//assumes that no activatable aa.has more than 5 ranks -#define MAX_AA_ACTION_RANKS 20 -extern AA_DBAction AA_Actions[aaHighestID][MAX_AA_ACTION_RANKS]; //[aaid][rank] -extern std::map AA_SwarmPets; //key=spell_id - -#define AA_Choose3(val, v1, v2, v3) (val==1?v1:(val==2?v2:v3)) - -extern std::mapaas_send; -extern std::map > aa_effects; -extern std::map AARequiredLevelAndCost; - enum { //values of AA_Action.action aaActionActivate = 0, aaActionSetEXP = 1, @@ -2167,4 +1536,11 @@ public: uint32 owner_id; }; +enum AATimers +{ + aaTimerRampage, + aaTimerWarcry, + aaTimerMax +}; + #endif diff --git a/zone/aa_ability.cpp b/zone/aa_ability.cpp new file mode 100644 index 000000000..3612b00c7 --- /dev/null +++ b/zone/aa_ability.cpp @@ -0,0 +1,70 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "../common/global_define.h" +#include "../common/types.h" +#include "masterentity.h" +#include "aa_ability.h" + +AA::Rank *AA::Ability::GetMaxRank() { + if(!first) + return nullptr; + + Rank *current = first; + while(current->next) { + current = current->next; + } + + return current; +} + +AA::Rank *AA::Ability::GetRankByPointsSpent(int current_level) { + if(current_level == 0) + return nullptr; + + if(!first) + return nullptr; + + int i = 1; + Rank *current = first; + while(current->next) { + if(i == current_level) { + break; + } + + i++; + current = current->next; + } + + return current; +} + +int AA::Ability::GetMaxLevel(Mob *who) { + int max_level = 0; + Rank *current = first; + while(current) { + if(!who->CanUseAlternateAdvancementRank(current)) { + return max_level; + } + + max_level++; + current = current->next; + } + + return max_level; +} \ No newline at end of file diff --git a/zone/aa_ability.h b/zone/aa_ability.h new file mode 100644 index 000000000..0d6a240c4 --- /dev/null +++ b/zone/aa_ability.h @@ -0,0 +1,61 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef EQEMU_ZONE_AA_ABILITY_H +#define EQEMU_ZONE_AA_ABILITY_H + +#include "../common/global_define.h" +#include +#include +#include +#include "aa_rank_effects.h" +#include "aa_rank.h" + +class Mob; + +namespace AA +{ + +class Ability +{ +public: + Ability() { } + ~Ability() { } + + Rank *GetMaxRank(); + Rank *GetRankByPointsSpent(int current_level); + int GetMaxLevel(Mob *who); + + int id; + std::string name; + int category; + int classes; + int races; + int deities; + int drakkin_heritage; + int status; + bool grant_only; + int type; + int charges; + int first_rank_id; + Rank *first; +}; + +} + +#endif diff --git a/zone/aa_rank.h b/zone/aa_rank.h new file mode 100644 index 000000000..c328e4ebb --- /dev/null +++ b/zone/aa_rank.h @@ -0,0 +1,56 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef EQEMU_ZONE_AA_RANK_H +#define EQEMU_ZONE_AA_RANK_H + +namespace AA +{ + +class Ability; +class Rank +{ +public: + Rank() { } + ~Rank() { } + + int id; + int upper_hotkey_sid; + int lower_hotkey_sid; + int title_sid; + int desc_sid; + int cost; + int level_req; + int spell; + int spell_type; + int recast_time; + int prev_id; + Rank *prev; + int next_id; + Rank *next; + int current_value; + int expansion; + int total_cost; + Ability *base_ability; + std::vector effects; + std::map prereqs; +}; + +} + +#endif diff --git a/zone/aa_rank_effects.h b/zone/aa_rank_effects.h new file mode 100644 index 000000000..d68937078 --- /dev/null +++ b/zone/aa_rank_effects.h @@ -0,0 +1,38 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef EQEMU_ZONE_AA_RANK_EFFECTS_H +#define EQEMU_ZONE_AA_RANK_EFFECTS_H + +#include "../common/global_define.h" +#include + +namespace AA +{ + +struct RankEffect +{ + int slot; + int effect_id; + int base1; + int base2; +}; + +} + +#endif diff --git a/zone/aggro.cpp b/zone/aggro.cpp index e983b8ea9..d50c1d43e 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -44,12 +44,8 @@ void EntityList::CheckClientAggro(Client *around) if (mob->IsClient()) //also ensures that mob != around continue; - if (mob->CheckWillAggro(around)) { - if (mob->IsEngaged()) - mob->AddToHateList(around); - else - mob->AddToHateList(around, mob->GetLevel()); - } + if (mob->CheckWillAggro(around) && !mob->CheckAggro(around)) + mob->AddToHateList(around, 25); } } @@ -160,10 +156,21 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) { return; } - if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GREEN ) { - towho->Message(0, "...%s is red to me (basically)", mob->GetName(), - dist2, iAggroRange2); - return; + if (RuleB(Aggro, UseLevelAggro)) + { + if (GetLevel() < 18 && mob->GetLevelCon(GetLevel()) == CON_GREEN && GetBodyType() != 3) + { + towho->Message(0, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2); + return; + } + } + else + { + if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GREEN ) { + towho->Message(0, "...%s is red to me (basically)", mob->GetName(), + dist2, iAggroRange2); + return; + } } if(verbose) { @@ -289,6 +296,14 @@ bool Mob::CheckWillAggro(Mob *mob) { return(false); } + // Don't aggro new clients if we are already engaged unless PROX_AGGRO is set + if (IsEngaged() && (!GetSpecialAbility(PROX_AGGRO) || (GetSpecialAbility(PROX_AGGRO) && !CombatRange(mob)))) { + Log.Out(Logs::Moderate, Logs::Aggro, + "%s is in combat, and does not have prox_aggro, or does and is out of combat range with %s", + GetName(), mob->GetName()); + return false; + } + //im not sure I understand this.. //if I have an owner and it is not this mob, then I cannot //aggro this mob...??? @@ -317,11 +332,12 @@ bool Mob::CheckWillAggro(Mob *mob) { int heroicCHA_mod = mob->itembonuses.HeroicCHA/25; // 800 Heroic CHA cap if(heroicCHA_mod > THREATENLY_ARRGO_CHANCE) heroicCHA_mod = THREATENLY_ARRGO_CHANCE; - if + if (RuleB(Aggro, UseLevelAggro) && ( //old InZone check taken care of above by !mob->CastToClient()->Connected() ( - ( GetINT() <= RuleI(Aggro, IntAggroThreshold) ) + ( GetLevel() >= 18 ) + ||(GetBodyType() == 3) ||( mob->IsClient() && mob->CastToClient()->IsSitting() ) ||( mob->GetLevelCon(GetLevel()) != CON_GREEN ) @@ -340,13 +356,47 @@ bool Mob::CheckWillAggro(Mob *mob) { ) ) ) + ) { //FatherNiwtit: make sure we can see them. last since it is very expensive if(CheckLosFN(mob)) { - Log.Out(Logs::Detail, Logs::Aggro, "Check aggro for %s target %s.", GetName(), mob->GetName()); + Log.Out(Logs::Detail, Logs::Aggro, "Check aggro for %s target %s.", GetName(), mob->GetName()); return( mod_will_aggro(mob, this) ); } } + else + { + if + ( + //old InZone check taken care of above by !mob->CastToClient()->Connected() + ( + ( GetINT() <= RuleI(Aggro, IntAggroThreshold) ) + ||( mob->IsClient() && mob->CastToClient()->IsSitting() ) + ||( mob->GetLevelCon(GetLevel()) != CON_GREEN ) + + ) + && + ( + ( + fv == FACTION_SCOWLS + || + (mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr) + || + ( + fv == FACTION_THREATENLY + && zone->random.Roll(THREATENLY_ARRGO_CHANCE - heroicCHA_mod) + ) + ) + ) + ) + { + //FatherNiwtit: make sure we can see them. last since it is very expensive + if(CheckLosFN(mob)) { + Log.Out(Logs::Detail, Logs::Aggro, "Check aggro for %s target %s.", GetName(), mob->GetName()); + return( mod_will_aggro(mob, this) ); + } + } + } Log.Out(Logs::Detail, Logs::Aggro, "Is In zone?:%d\n", mob->InZone()); Log.Out(Logs::Detail, Logs::Aggro, "Dist^2: %f\n", dist2); @@ -427,11 +477,20 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) { if (sender->GetPrimaryFaction() == 0 ) return; // well, if we dont have a faction set, we're gonna be indiff to everybody + if (sender->HasAssistAggro()) + return; + for (auto it = npc_list.begin(); it != npc_list.end(); ++it) { NPC *mob = it->second; if (!mob) continue; + if (mob->CheckAggro(attacker)) + continue; + + if (sender->NPCAssistCap() >= RuleI(Combat, NPCAssistCap)) + break; + float r = mob->GetAssistRange(); r = r * r; @@ -449,7 +508,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) { { //if they are in range, make sure we are not green... //then jump in if they are our friend - if(attacker->GetLevelCon(mob->GetLevel()) != CON_GREEN) + if(mob->GetLevel() >= 50 || attacker->GetLevelCon(mob->GetLevel()) != CON_GREEN) { bool useprimfaction = false; if(mob->GetPrimaryFaction() == sender->CastToNPC()->GetPrimaryFaction()) @@ -468,11 +527,12 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) { if(mob->CheckLosFN(sender)) { #if (EQDEBUG>=5) Log.Out(Logs::General, Logs::None, "AIYellForHelp(\"%s\",\"%s\") %s attacking %s Dist %f Z %f", - sender->GetName(), attacker->GetName(), mob->GetName(), - attacker->GetName(), DistanceSquared(mob->GetPosition(), + sender->GetName(), attacker->GetName(), mob->GetName(), + attacker->GetName(), DistanceSquared(mob->GetPosition(), sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ())); #endif - mob->AddToHateList(attacker, 1, 0, false); + mob->AddToHateList(attacker, 25, 0, false); + sender->AddAssistCap(); } } } @@ -880,11 +940,11 @@ bool Mob::CombatRange(Mob* other) float _DistNoRoot = DistanceSquared(m_Position, other->GetPosition()); if (GetSpecialAbility(NPC_CHASE_DISTANCE)){ - + bool DoLoSCheck = true; float max_dist = static_cast(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 0)); float min_dist = static_cast(GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 1)); - + if (GetSpecialAbilityParam(NPC_CHASE_DISTANCE, 2)) DoLoSCheck = false; //Ignore line of sight check @@ -897,10 +957,10 @@ bool Mob::CombatRange(Mob* other) min_dist = size_mod; //Default to melee range else min_dist = min_dist * min_dist; - + if ((DoLoSCheck && CheckLastLosState()) && (_DistNoRoot >= min_dist && _DistNoRoot <= max_dist)) - SetPseudoRoot(true); - else + SetPseudoRoot(true); + else SetPseudoRoot(false); } @@ -919,7 +979,7 @@ bool Mob::CheckLosFN(Mob* other) { Result = CheckLosFN(other->GetX(), other->GetY(), other->GetZ(), other->GetSize()); SetLastLosState(Result); - + return Result; } @@ -954,11 +1014,25 @@ bool Mob::CheckLosFN(float posX, float posY, float posZ, float mobSize) { } //offensive spell aggro -int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc) +int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc) { + if (NoDetrimentalSpellAggro(spell_id)) + return 0; + int32 AggroAmount = 0; int32 nonModifiedAggro = 0; uint16 slevel = GetLevel(); + bool dispel = false; + bool on_hatelist = target ? target->CheckAggro(this) : false; + int proc_cap = RuleI(Aggro, MaxScalingProcAggro); + int hate_cap = isproc && proc_cap != -1 ? proc_cap : 1200; + + int32 target_hp = target ? target->GetMaxHP() : 18000; // default to max + int32 default_aggro = 25; + if (target_hp >= 18000) // max + default_aggro = hate_cap; + else if (target_hp >= 390) // min, 390 is the first number with int division that is 26 + default_aggro = target_hp / 15; for (int o = 0; o < EFFECT_COUNT; o++) { switch (spells[spell_id].effectid[o]) { @@ -972,7 +1046,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc) case SE_MovementSpeed: { int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); if (val < 0) - AggroAmount += (2 + ((slevel * slevel) / 8)); + AggroAmount += default_aggro; break; } case SE_AttackSpeed: @@ -980,60 +1054,32 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc) case SE_AttackSpeed3: { int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); if (val < 100) - AggroAmount += (5 + ((slevel * slevel) / 5)); + AggroAmount += default_aggro; break; } - case SE_Stun: { - int val = (5 + ((slevel * slevel) / 6)); - if (isproc && RuleI(Aggro,MaxStunProcAggro) > -1 && (val > RuleI(Aggro,MaxStunProcAggro))) - val = RuleI(Aggro,MaxStunProcAggro); - AggroAmount += val; + case SE_Stun: + case SE_Blind: + case SE_Mez: + case SE_Charm: + case SE_Fear: + AggroAmount += default_aggro; break; - } - case SE_Blind: { - AggroAmount += (5 + ((slevel * slevel) / 6)); + case SE_Root: + AggroAmount += 10; break; - } - case SE_Mez: { - AggroAmount += (5 + ((slevel * slevel) / 5)); - break; - } - case SE_Charm: { - AggroAmount += (5 + ((slevel * slevel) / 5)); - break; - } - case SE_Root: { - AggroAmount += (2 + ((slevel * slevel) / 8)); - break; - } - case SE_Fear: { - AggroAmount += (5 + ((slevel * slevel) / 6)); - break; - } - case SE_ATK: case SE_ACv2: case SE_ArmorClass: { int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); if (val < 0) - AggroAmount -= val * 2; + AggroAmount += default_aggro; break; } + case SE_ATK: case SE_ResistMagic: case SE_ResistFire: case SE_ResistCold: case SE_ResistPoison: - case SE_ResistDisease: { - int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); - if (val < 0) - AggroAmount -= val * 3; - break; - } - case SE_ResistAll: { - int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); - if (val < 0) - AggroAmount -= val * 6; - break; - } + case SE_ResistDisease: case SE_STR: case SE_STA: case SE_DEX: @@ -1043,32 +1089,31 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc) case SE_CHA: { int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); if (val < 0) - AggroAmount -= val * 2; + AggroAmount += 10; + break; + } + case SE_ResistAll: { + int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); + if (val < 0) + AggroAmount += 50; break; } case SE_AllStats: { int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); if (val < 0) - AggroAmount -= val * 6; + AggroAmount += 70; break; } - case SE_BardAEDot: { - AggroAmount += slevel * 2; + case SE_BardAEDot: + AggroAmount += 10; break; - } - case SE_SpinTarget: { - AggroAmount += (5 + ((slevel * slevel) / 5)); - break; - } + case SE_SpinTarget: case SE_Amnesia: - case SE_Silence: { - AggroAmount += slevel * 2; + case SE_Silence: + case SE_Destroy: + AggroAmount += default_aggro; break; - } - case SE_Destroy: { - AggroAmount += slevel * 2; - break; - } + // unsure -- leave them this for now case SE_Harmony: case SE_CastingLevel: case SE_MeleeMitigation: @@ -1091,6 +1136,7 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc) AggroAmount += slevel * 2; break; } + // unsure -- leave them this for now case SE_CurrentMana: case SE_ManaRegen_v2: case SE_ManaPool: @@ -1101,123 +1147,124 @@ int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc) break; } case SE_CancelMagic: - case SE_DispelDetrimental: { - AggroAmount += slevel; + case SE_DispelDetrimental: + dispel = true; break; - } case SE_ReduceHate: - case SE_InstantHate: { + case SE_InstantHate: nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id); break; - } } } - if (IsAEDurationSpell(spell_id)) - AggroAmount /= 2; + if (IsBardSong(spell_id) && AggroAmount > 40) + AggroAmount = 40; // bard songs seem to cap to 40 for most of their spells? - if (spells[spell_id].HateAdded > 0) + if (dispel && target && target->GetHateAmount(this) < 100) + AggroAmount += 50; + + if (spells[spell_id].HateAdded > 0) // overrides the hate (ex. tash) AggroAmount = spells[spell_id].HateAdded; - if (IsBardSong(spell_id)) - AggroAmount = AggroAmount * RuleI(Aggro, SongAggroMod) / 100; if (GetOwner() && IsPet()) AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100; - if (AggroAmount > 0) { - + // hate focus ignored on first action for some reason + if (!on_hatelist && AggroAmount > 0) { int HateMod = RuleI(Aggro, SpellAggroMod); - HateMod += GetFocusEffect(focusSpellHateMod, spell_id); AggroAmount = (AggroAmount * HateMod) / 100; - - //made up number probably scales a bit differently on live but it seems like it will be close enough - //every time you cast on live you get a certain amount of "this is a spell" aggro - //confirmed by EQ devs to be 100 exactly at level 85. From their wording it doesn't seem like it's affected - //by hate modifiers either. - //AggroAmount += (slevel*slevel/72); - // Saved so I can reimplement it; - // this should only be on the spell to aggro the npc not every spell - } + // initial aggro gets a bonus 100 besides for dispel or hate override + // We add this 100 in AddToHateList so we need to account for the oddities here + if (dispel && spells[spell_id].HateAdded > 0 && !on_hatelist) + AggroAmount -= 100; + return AggroAmount + spells[spell_id].bonushate + nonModifiedAggro; } //healing and buffing aggro -int32 Mob::CheckHealAggroAmount(uint16 spell_id, uint32 heal_possible) +int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possible) { int32 AggroAmount = 0; + auto target_level = target ? target->GetLevel() : 1; + bool ignore_default_buff = false; // rune/hot don't use the default 9, HP buffs that heal (virtue) do use the default for (int o = 0; o < EFFECT_COUNT; o++) { switch (spells[spell_id].effectid[o]) { - case SE_CurrentHP: { - AggroAmount += IsBuffSpell(spell_id) ? spells[spell_id].mana / 4 : spells[spell_id].mana; + case SE_CurrentHP: { + if (heal_possible == 0) { + AggroAmount += 1; break; } - case SE_Rune: { - AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[0], spells[spell_id].base[0], spells[spell_id].max[o], GetLevel(), spell_id) * 2; - break; - } - case SE_HealOverTime: { - AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], GetLevel(), spell_id); - break; - } - default: { - break; + // hate based on base healing power of the spell + int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], + spells[spell_id].base[o], spells[spell_id].max[o], GetLevel(), spell_id); + if (val > 0) { + if (heal_possible < val) + val = heal_possible; // capped to amount healed + val = 2 * val / 3; // 3:2 ratio + + if (target_level > 50 && val > 1500) + val = 1500; // target 51+ seems ~1500 + else if (target_level <= 50 && val > 800) + val = 800; // per live patch notes, capped to 800 } + AggroAmount += std::max(val, 1); + break; + } + case SE_Rune: + AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[o], + spells[spell_id].base[o], spells[spell_id].max[o], GetLevel(), spell_id) * 2; + ignore_default_buff = true; + break; + case SE_HealOverTime: + AggroAmount += 10; + ignore_default_buff = true; + break; + default: + break; } } - if (IsBardSong(spell_id)) - AggroAmount = AggroAmount * RuleI(Aggro, SongAggroMod) / 100; if (GetOwner() && IsPet()) AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100; + if (!ignore_default_buff && IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) + AggroAmount = IsBardSong(spell_id) ? 2 : 9; + if (AggroAmount > 0) { int HateMod = RuleI(Aggro, SpellAggroMod); - HateMod += GetFocusEffect(focusSpellHateMod, spell_id); - //Live AA - Spell casting subtlety - HateMod += aabonuses.hatemod + spellbonuses.hatemod + itembonuses.hatemod; - AggroAmount = (AggroAmount * HateMod) / 100; - - //made up number probably scales a bit differently on live but it seems like it will be close enough - //every time you cast on live you get a certain amount of "this is a spell" aggro - //confirmed by EQ devs to be 100 exactly at level 85. From their wording it doesn't seem like it's affected - //by hate modifiers either. - //AggroAmount += (slevel*slevel/72); // Moved Below } - if (AggroAmount < 0) - return 0; - else - return AggroAmount; + return std::max(0, AggroAmount); } void Mob::AddFeignMemory(Client* attacker) { - if(feign_memory_list.empty() && AIfeignremember_timer != nullptr) - AIfeignremember_timer->Start(AIfeignremember_delay); + if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Start(AIfeignremember_delay); feign_memory_list.insert(attacker->CharacterID()); } void Mob::RemoveFromFeignMemory(Client* attacker) { feign_memory_list.erase(attacker->CharacterID()); - if(feign_memory_list.empty() && AIfeignremember_timer != nullptr) - AIfeignremember_timer->Disable(); + if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Disable(); if(feign_memory_list.empty()) { minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); - if(AIfeignremember_timer != nullptr) - AIfeignremember_timer->Disable(); + if(AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Disable(); } } void Mob::ClearFeignMemory() { - std::set::iterator RememberedCharID = feign_memory_list.begin(); + auto RememberedCharID = feign_memory_list.begin(); while (RememberedCharID != feign_memory_list.end()) { Client* remember_client = entity_list.GetClientByCharID(*RememberedCharID); @@ -1229,8 +1276,8 @@ void Mob::ClearFeignMemory() { feign_memory_list.clear(); minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); - if(AIfeignremember_timer != nullptr) - AIfeignremember_timer->Disable(); + if(AI_feign_remember_timer != nullptr) + AI_feign_remember_timer->Disable(); } bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) { @@ -1249,10 +1296,10 @@ bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) { return true; float resist_check = 0; - + if(IsCharmSpell(spell_id)) { - if (spells[spell_id].powerful_flag == -1) //If charm spell has this set(-1), it can not break till end of duration. + if (spells[spell_id].no_resist) //If charm spell has this set(-1), it can not break till end of duration. return true; //1: The mob has a default 25% chance of being allowed a resistance check against the charm. @@ -1265,7 +1312,7 @@ bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) { resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, false,0, false, true); //2: The mob makes a resistance check against the charm - if (resist_check == 100) + if (resist_check == 100) return true; else diff --git a/zone/attack.cpp b/zone/attack.cpp index d45606b04..3cccf43f0 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -23,6 +23,7 @@ #include "../common/skills.h" #include "../common/spdat.h" #include "../common/string_util.h" +#include "../common/data_verification.h" #include "queryserv.h" #include "quest_parser_collection.h" #include "string_ids.h" @@ -51,120 +52,88 @@ extern WorldServer worldserver; extern EntityList entity_list; extern Zone* zone; -bool Mob::AttackAnimation(SkillUseTypes &skillinuse, int Hand, const ItemInst* weapon) +bool Mob::AttackAnimation(EQEmu::skills::SkillType &skillinuse, int Hand, const ItemInst* weapon) { // Determine animation int type = 0; - if (weapon && weapon->IsType(ItemClassCommon)) { - const Item_Struct* item = weapon->GetItem(); + if (weapon && weapon->IsClassCommon()) { + const EQEmu::ItemBase* item = weapon->GetItem(); Log.Out(Logs::Detail, Logs::Attack, "Weapon skill : %i", item->ItemType); - switch (item->ItemType) - { - case ItemType1HSlash: // 1H Slashing - { - skillinuse = Skill1HSlashing; - type = anim1HWeapon; - break; - } - case ItemType2HSlash: // 2H Slashing - { - skillinuse = Skill2HSlashing; - type = anim2HSlashing; - break; - } - case ItemType1HPiercing: // Piercing - { - skillinuse = Skill1HPiercing; - type = animPiercing; - break; - } - case ItemType1HBlunt: // 1H Blunt - { - skillinuse = Skill1HBlunt; - type = anim1HWeapon; - break; - } - case ItemType2HBlunt: // 2H Blunt - { - skillinuse = Skill2HBlunt; - type = anim2HSlashing; //anim2HWeapon - break; - } - case ItemType2HPiercing: // 2H Piercing - { - skillinuse = Skill1HPiercing; // change to Skill2HPiercing once activated - type = anim2HWeapon; - break; - } - case ItemTypeMartial: - { - skillinuse = SkillHandtoHand; - type = animHand2Hand; - break; - } - default: - { - skillinuse = SkillHandtoHand; - type = animHand2Hand; - break; - } + switch (item->ItemType) { + case EQEmu::item::ItemType1HSlash: // 1H Slashing + skillinuse = EQEmu::skills::Skill1HSlashing; + type = anim1HWeapon; + break; + case EQEmu::item::ItemType2HSlash: // 2H Slashing + skillinuse = EQEmu::skills::Skill2HSlashing; + type = anim2HSlashing; + break; + case EQEmu::item::ItemType1HPiercing: // Piercing + skillinuse = EQEmu::skills::Skill1HPiercing; + type = anim1HPiercing; + break; + case EQEmu::item::ItemType1HBlunt: // 1H Blunt + skillinuse = EQEmu::skills::Skill1HBlunt; + type = anim1HWeapon; + break; + case EQEmu::item::ItemType2HBlunt: // 2H Blunt + skillinuse = EQEmu::skills::Skill2HBlunt; + type = anim2HSlashing; //anim2HWeapon + break; + case EQEmu::item::ItemType2HPiercing: // 2H Piercing + if (IsClient() && CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::RoF2) + skillinuse = EQEmu::skills::Skill1HPiercing; + else + skillinuse = EQEmu::skills::Skill2HPiercing; + type = anim2HWeapon; + break; + case EQEmu::item::ItemTypeMartial: + skillinuse = EQEmu::skills::SkillHandtoHand; + type = animHand2Hand; + break; + default: + skillinuse = EQEmu::skills::SkillHandtoHand; + type = animHand2Hand; + break; }// switch } else if(IsNPC()) { - - switch (skillinuse) - { - case Skill1HSlashing: // 1H Slashing - { - type = anim1HWeapon; - break; - } - case Skill2HSlashing: // 2H Slashing - { - type = anim2HSlashing; - break; - } - case Skill1HPiercing: // Piercing - { - type = animPiercing; - break; - } - case Skill1HBlunt: // 1H Blunt - { - type = anim1HWeapon; - break; - } - case Skill2HBlunt: // 2H Blunt - { - type = anim2HSlashing; //anim2HWeapon - break; - } - case 99: // 2H Piercing // change to Skill2HPiercing once activated - { - type = anim2HWeapon; - break; - } - case SkillHandtoHand: - { - type = animHand2Hand; - break; - } - default: - { - type = animHand2Hand; - break; - } + switch (skillinuse) { + case EQEmu::skills::Skill1HSlashing: // 1H Slashing + type = anim1HWeapon; + break; + case EQEmu::skills::Skill2HSlashing: // 2H Slashing + type = anim2HSlashing; + break; + case EQEmu::skills::Skill1HPiercing: // Piercing + type = anim1HPiercing; + break; + case EQEmu::skills::Skill1HBlunt: // 1H Blunt + type = anim1HWeapon; + break; + case EQEmu::skills::Skill2HBlunt: // 2H Blunt + type = anim2HSlashing; //anim2HWeapon + break; + case EQEmu::skills::Skill2HPiercing: // 2H Piercing + type = anim2HWeapon; + break; + case EQEmu::skills::SkillHandtoHand: + type = animHand2Hand; + break; + default: + type = animHand2Hand; + break; }// switch } else { - skillinuse = SkillHandtoHand; + skillinuse = EQEmu::skills::SkillHandtoHand; type = animHand2Hand; } // If we're attacking with the secondary hand, play the dual wield anim - if (Hand == MainSecondary) // DW anim + if (Hand == EQEmu::legacy::SlotSecondary) // DW anim type = animDualWield; DoAnim(type); @@ -173,7 +142,7 @@ bool Mob::AttackAnimation(SkillUseTypes &skillinuse, int Hand, const ItemInst* w // called when a mob is attacked, does the checks to see if it's a hit // and does other mitigation checks. 'this' is the mob being attacked. -bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 chance_mod) +bool Mob::CheckHitChance(Mob* other, EQEmu::skills::SkillType skillinuse, int Hand, int16 chance_mod) { /*/ //Reworked a lot of this code to achieve better balance at higher levels. @@ -251,7 +220,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c if(defender->IsClient()) { - chancetohit += (RuleR(Combat,WeaponSkillFalloff) * (defender->CastToClient()->MaxSkill(SkillDefense) - defender->GetSkill(SkillDefense))); + chancetohit += (RuleR(Combat, WeaponSkillFalloff) * (defender->CastToClient()->MaxSkill(EQEmu::skills::SkillDefense) - defender->GetSkill(EQEmu::skills::SkillDefense))); Log.Out(Logs::Detail, Logs::Attack, "Chance to hit after weapon falloff calc (defense) %.2f", chancetohit); } @@ -287,15 +256,15 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c hitBonus += attacker->itembonuses.HitChanceEffect[skillinuse] + attacker->spellbonuses.HitChanceEffect[skillinuse]+ attacker->aabonuses.HitChanceEffect[skillinuse]+ - attacker->itembonuses.HitChanceEffect[HIGHEST_SKILL+1] + - attacker->spellbonuses.HitChanceEffect[HIGHEST_SKILL+1] + - attacker->aabonuses.HitChanceEffect[HIGHEST_SKILL+1]; + attacker->itembonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] + + attacker->spellbonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] + + attacker->aabonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1]; //Accuracy = Spell Effect , HitChance = 'Accuracy' from Item Effect //Only AA derived accuracy can be skill limited. ie (Precision of the Pathfinder, Dead Aim) - hitBonus += (attacker->itembonuses.Accuracy[HIGHEST_SKILL+1] + - attacker->spellbonuses.Accuracy[HIGHEST_SKILL+1] + - attacker->aabonuses.Accuracy[HIGHEST_SKILL+1] + + hitBonus += (attacker->itembonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] + + attacker->spellbonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] + + attacker->aabonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] + attacker->aabonuses.Accuracy[skillinuse] + attacker->itembonuses.HitChance) / 15.0f; //Item Mod 'Accuracy' @@ -304,7 +273,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c if(attacker->IsNPC()) hitBonus += (attacker->CastToNPC()->GetAccuracyRating() / 10.0f); //Modifier from database - if(skillinuse == SkillArchery) + if (skillinuse == EQEmu::skills::SkillArchery) hitBonus -= hitBonus*RuleR(Combat, ArcheryHitPenalty); //Calculate final chance to hit @@ -342,7 +311,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c return(tohit_roll <= chancetohit); } -bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) +bool Mob::AvoidDamage(Mob *other, int32 &damage, int hand) { /* called when a mob is attacked, does the checks to see if it's a hit * and does other mitigation checks. 'this' is the mob being attacked. @@ -354,22 +323,32 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) * -4 - dodge * */ - float skill; - float bonus; - float RollTable[4] = {0,0,0,0}; - float roll; - Mob *attacker=other; - Mob *defender=this; - //garunteed hit - bool ghit = false; - if((attacker->aabonuses.MeleeSkillCheck + attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500) - ghit = true; + /* Order according to current (SoF+?) dev quotes: + * https://forums.daybreakgames.com/eq/index.php?threads/test-update-06-10-15.223510/page-2#post-3261772 + * https://forums.daybreakgames.com/eq/index.php?threads/test-update-06-10-15.223510/page-2#post-3268227 + * Riposte 50, hDEX, must have weapon/fists, doesn't work on archery/throwing + * Block 25, hDEX, works on archery/throwing, behind block done here if back to attacker base1 is chance + * Parry 45, hDEX, doesn't work on throwing/archery, must be facing target + * Dodge 45, hAGI, works on archery/throwing, monks can dodge attacks from behind + * Shield Block, rand base1 + * Staff Block, rand base1 + * regular strike through + * avoiding the attack (CheckHitChance) + * As soon as one succeeds, none of the rest are checked + * + * Formula (all int math) + * (posted for parry, assume rest at the same) + * Chance = (((SKILL + 100) + [((SKILL+100) * SPA(175).Base1) / 100]) / 45) + [(hDex / 25) - min([hDex / 25], hStrikethrough)]. + * hStrikethrough is a mob stat that was added to counter the bonuses of heroic stats + * Number rolled against 100, if the chance is greater than 100 it happens 100% of time + * + * Things with 10k accuracy mods can be avoided with these skills qq + */ + Mob *attacker = other; + Mob *defender = this; - bool InFront = false; - - if (attacker->InFrontMob(this, attacker->GetX(), attacker->GetY())) - InFront = true; + bool InFront = attacker->InFrontMob(this, attacker->GetX(), attacker->GetY()); /* This special ability adds a negative modifer to the defenders riposte/block/parry/chance @@ -384,48 +363,50 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) int counter_parry = 0; int counter_dodge = 0; - if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)){ - + if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)) { counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0); - counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE,1); + counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 1); counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2); counter_parry = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 3); counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4); } - ////////////////////////////////////////////////////////// - // make enrage same as riposte - ///////////////////////////////////////////////////////// - if (IsEnraged() && InFront) { - damage = -3; - Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack."); - } - - ///////////////////////////////////////////////////////// - // riposte - ///////////////////////////////////////////////////////// - float riposte_chance = 0.0f; - if (CanRiposte && damage > 0 && CanThisClassRiposte() && InFront) - { - riposte_chance = (100.0f + static_cast(aabonuses.RiposteChance + spellbonuses.RiposteChance + - itembonuses.RiposteChance - counter_riposte - counter_all)) / 100.0f; - skill = GetSkill(SkillRiposte); - if (IsClient()) { - CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10); + // riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo + bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance; + // Need to check if we have something in MainHand to actually attack with (or fists) + if (hand != EQEmu::legacy::SlotRange && CanThisClassRiposte() && InFront && !ImmuneRipo) { + if (IsEnraged()) { + damage = -3; + Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack."); + return true; } - - if (!ghit) { //if they are not using a garunteed hit discipline - bonus = 2.0 + skill/60.0 + (GetDEX()/200); - bonus *= riposte_chance; - bonus = mod_riposte_chance(bonus, attacker); - RollTable[0] = bonus + (itembonuses.HeroicDEX / 25); // 25 heroic = 1%, applies to ripo, parry, block + if (IsClient()) + CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillRiposte, other, -10); + // check auto discs ... I guess aa/items too :P + if (spellbonuses.RiposteChance == 10000 || aabonuses.RiposteChance == 10000 || itembonuses.RiposteChance == 10000) { + damage = -3; + return true; + } + int chance = GetSkill(EQEmu::skills::SkillRiposte) + 100; + chance += (chance * (aabonuses.RiposteChance + spellbonuses.RiposteChance + itembonuses.RiposteChance)) / 100; + chance /= 50; + chance += itembonuses.HeroicDEX / 25; // live has "heroic strickthrough" here to counter + if (counter_riposte || counter_all) { + float counter = (counter_riposte + counter_all) / 100.0f; + chance -= chance * counter; + } + // AA Slippery Attacks + if (hand == EQEmu::legacy::SlotSecondary) { + int slip = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail; + chance += chance * slip / 100; + } + if (chance > 0 && zone->random.Roll(chance)) { // could be <0 from offhand stuff + damage = -3; + return true; } } - /////////////////////////////////////////////////////// // block - /////////////////////////////////////////////////////// - bool bBlockFromRear = false; // a successful roll on this does not mean a successful block is forthcoming. only that a chance to block @@ -436,101 +417,100 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) if (BlockBehindChance && zone->random.Roll(BlockBehindChance)) bBlockFromRear = true; - float block_chance = 0.0f; - if (damage > 0 && CanThisClassBlock() && (InFront || bBlockFromRear)) { - block_chance = (100.0f + static_cast(aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance + - itembonuses.IncreaseBlockChance - counter_block - counter_all)) / 100.0f; - skill = CastToClient()->GetSkill(SkillBlock); - if (IsClient()) { - CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10); - } - - if (!ghit) { //if they are not using a garunteed hit discipline - bonus = 2.0 + skill/35.0 + (GetDEX()/200); - bonus = mod_block_chance(bonus, attacker); - RollTable[1] = RollTable[0] + (bonus * block_chance); - } - } - else{ - RollTable[1] = RollTable[0]; - } - - //Try Shield Block OR TwoHandBluntBlockCheck - if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear)) - RollTable[1] += static_cast(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock - counter_block - counter_all); - - else if(damage > 0 && HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear)) - RollTable[1] += static_cast(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock - counter_block - counter_all); - - ////////////////////////////////////////////////////// - // parry - ////////////////////////////////////////////////////// - float parry_chance = 0.0f; - if (damage > 0 && CanThisClassParry() && InFront){ - parry_chance = (100.0f + static_cast(aabonuses.ParryChance + itembonuses.ParryChance + - itembonuses.ParryChance - counter_parry - counter_all)) / 100.0f; - skill = CastToClient()->GetSkill(SkillParry); - if (IsClient()) { - CastToClient()->CheckIncreaseSkill(SkillParry, other, -10); - } - - if (!ghit) { //if they are not using a garunteed hit discipline - bonus = 2.0 + skill/60.0 + (GetDEX()/200); - bonus *= parry_chance; - bonus = mod_parry_chance(bonus, attacker); - RollTable[2] = RollTable[1] + bonus; - } - } - else{ - RollTable[2] = RollTable[1]; - } - - //////////////////////////////////////////////////////// - // dodge - //////////////////////////////////////////////////////// - float dodge_chance = 0.0f; - if (damage > 0 && CanThisClassDodge() && InFront){ - - dodge_chance = (100.0f + static_cast(aabonuses.DodgeChance + spellbonuses.DodgeChance + - itembonuses.DodgeChance - counter_dodge - counter_all)) / 100.0f; - - skill = CastToClient()->GetSkill(SkillDodge); - if (IsClient()) { - CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10); - } - - if (!ghit) { //if they are not using a garunteed hit discipline - bonus = 2.0 + skill/60.0 + (GetAGI()/200); - bonus *= dodge_chance; - //DCBOOMKAR - bonus = mod_dodge_chance(bonus, attacker); - RollTable[3] = RollTable[2] + bonus - (itembonuses.HeroicDEX / 25) + (itembonuses.HeroicAGI / 25); - } - } - else{ - RollTable[3] = RollTable[2]; - } - - if(damage > 0){ - roll = zone->random.Real(0,100); - if(roll <= RollTable[0]){ - damage = -3; - } - else if(roll <= RollTable[1]){ + if (CanThisClassBlock() && (InFront || bBlockFromRear)) { + if (IsClient()) + CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillBlock, other, -10); + // check auto discs ... I guess aa/items too :P + if (spellbonuses.IncreaseBlockChance == 10000 || aabonuses.IncreaseBlockChance == 10000 || + itembonuses.IncreaseBlockChance == 10000) { damage = -1; + return true; } - else if(roll <= RollTable[2]){ - damage = -2; + int chance = GetSkill(EQEmu::skills::SkillBlock) + 100; + chance += (chance * (aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance + itembonuses.IncreaseBlockChance)) / 100; + chance /= 25; + chance += itembonuses.HeroicDEX / 25; // live has "heroic strickthrough" here to counter + if (counter_block || counter_all) { + float counter = (counter_block + counter_all) / 100.0f; + chance -= chance * counter; } - else if(roll <= RollTable[3]){ - damage = -4; + if (zone->random.Roll(chance)) { + damage = -1; + return true; } } - Log.Out(Logs::Detail, Logs::Combat, "Final damage after all avoidances: %d", damage); + // parry + if (CanThisClassParry() && InFront && hand != EQEmu::legacy::SlotRange) { + if (IsClient()) + CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillParry, other, -10); + // check auto discs ... I guess aa/items too :P + if (spellbonuses.ParryChance == 10000 || aabonuses.ParryChance == 10000 || itembonuses.ParryChance == 10000) { + damage = -2; + return true; + } + int chance = GetSkill(EQEmu::skills::SkillParry) + 100; + chance += (chance * (aabonuses.ParryChance + spellbonuses.ParryChance + itembonuses.ParryChance)) / 100; + chance /= 45; + chance += itembonuses.HeroicDEX / 25; // live has "heroic strickthrough" here to counter + if (counter_parry || counter_all) { + float counter = (counter_parry + counter_all) / 100.0f; + chance -= chance * counter; + } + if (zone->random.Roll(chance)) { + damage = -2; + return true; + } + } + + // dodge + if (CanThisClassDodge() && (InFront || GetClass() == MONK) ) { + if (IsClient()) + CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillDodge, other, -10); + // check auto discs ... I guess aa/items too :P + if (spellbonuses.DodgeChance == 10000 || aabonuses.DodgeChance == 10000 || itembonuses.DodgeChance == 10000) { + damage = -4; + return true; + } + int chance = GetSkill(EQEmu::skills::SkillDodge) + 100; + chance += (chance * (aabonuses.DodgeChance + spellbonuses.DodgeChance + itembonuses.DodgeChance)) / 100; + chance /= 45; + chance += itembonuses.HeroicAGI / 25; // live has "heroic strickthrough" here to counter + if (counter_dodge || counter_all) { + float counter = (counter_dodge + counter_all) / 100.0f; + chance -= chance * counter; + } + if (zone->random.Roll(chance)) { + damage = -4; + return true; + } + } + + // Try Shield Block OR TwoHandBluntBlockCheck + if (HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear)) { + int chance = aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock; + if (counter_block || counter_all) { + float counter = (counter_block + counter_all) / 100.0f; + chance -= chance * counter; + } + if (zone->random.Roll(chance)) { + damage = -1; + return true; + } + } + + if (HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear)) { + int chance = aabonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock; + if (counter_block || counter_all) { + float counter = (counter_block + counter_all) / 100.0f; + chance -= chance * counter; + } + if (zone->random.Roll(chance)) { + damage = -1; + return true; + } + } - if (damage < 0) - return true; return false; } @@ -544,7 +524,7 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac spellbonuses.CombatStability) / 100.0f; if (RuleB(Combat, UseIntervalAC)) { - float softcap = (GetSkill(SkillDefense) + GetLevel()) * + float softcap = (GetSkill(EQEmu::skills::SkillDefense) + GetLevel()) * RuleR(Combat, SoftcapFactor) * (1.0 + aa_mit); float mitigation_rating = 0.0; float attack_rating = 0.0; @@ -644,17 +624,17 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac if (GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER) - mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 4.0) + armor + 1; + mitigation_rating = ((GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 4.0) + armor + 1; else - mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 3.0) + (armor * 1.333333) + 1; + mitigation_rating = ((GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 3.0) + (armor * 1.333333) + 1; mitigation_rating *= 0.847; mitigation_rating = mod_mitigation_rating(mitigation_rating, attacker); if (attacker->IsClient()) - attack_rating = (attacker->CastToClient()->CalcATK() + ((attacker->GetSTR()-66) * 0.9) + (attacker->GetSkill(SkillOffense)*1.345)); + attack_rating = (attacker->CastToClient()->CalcATK() + ((attacker->GetSTR() - 66) * 0.9) + (attacker->GetSkill(EQEmu::skills::SkillOffense)*1.345)); else - attack_rating = (attacker->GetATK() + (attacker->GetSkill(SkillOffense)*1.345) + ((attacker->GetSTR()-66) * 0.9)); + attack_rating = (attacker->GetATK() + (attacker->GetSkill(EQEmu::skills::SkillOffense)*1.345) + ((attacker->GetSTR() - 66) * 0.9)); attack_rating = attacker->mod_attack_rating(attack_rating, this); @@ -671,25 +651,25 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac if (damage > 0 && myac > 0) { int acfail=1000; - char tmp[10]; + std::string tmp; - if (database.GetVariable("ACfail", tmp, 9)) { - acfail = (int) (atof(tmp) * 100); + if (database.GetVariable("ACfail", tmp)) { + acfail = (int) (atof(tmp.c_str()) * 100); if (acfail>100) acfail=100; } if (acfail<=0 || zone->random.Int(0, 100)>acfail) { float acreduction=1; int acrandom=300; - if (database.GetVariable("ACreduction", tmp, 9)) + if (database.GetVariable("ACreduction", tmp)) { - acreduction=atof(tmp); + acreduction=atof(tmp.c_str()); if (acreduction>100) acreduction=100; } - if (database.GetVariable("ACrandom", tmp, 9)) + if (database.GetVariable("ACrandom", tmp)) { - acrandom = (int) ((atof(tmp)+1) * 100); + acrandom = (int) ((atof(tmp.c_str())+1) * 100); if (acrandom>10100) acrandom=10100; } @@ -807,9 +787,9 @@ int32 Client::GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, //Returns the weapon damage against the input mob //if we cannot hit the mob with the current weapon we will get a value less than or equal to zero //Else we know we can hit. -//GetWeaponDamage(mob*, const Item_Struct*) is intended to be used for mobs or any other situation where we do not have a client inventory item +//GetWeaponDamage(mob*, const ItemBase*) is intended to be used for mobs or any other situation where we do not have a client inventory item //GetWeaponDamage(mob*, const ItemInst*) is intended to be used for situations where we have a client inventory item -int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { +int Mob::GetWeaponDamage(Mob *against, const EQEmu::ItemBase *weapon_item) { int dmg = 0; int banedmg = 0; @@ -833,7 +813,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { } else{ if((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30){ - dmg = GetMonkHandToHandDamage(); + dmg = GetHandToHandDamage(); } else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){ //pets wouldn't actually use this but... @@ -855,12 +835,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { dmg = dmg <= 0 ? 1 : dmg; } else{ - if(GetClass() == MONK || GetClass() == BEASTLORD){ - dmg = GetMonkHandToHandDamage(); - } - else{ - dmg = 1; - } + dmg = GetHandToHandDamage(); } } @@ -920,232 +895,114 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate int banedmg = 0; int x = 0; - if(!against || against->GetInvul() || against->GetSpecialAbility(IMMUNE_MELEE)){ + if (!against || against->GetInvul() || against->GetSpecialAbility(IMMUNE_MELEE)) return 0; - } - //check for items being illegally attained - if(weapon_item){ - const Item_Struct *mWeaponItem = weapon_item->GetItem(); - if(mWeaponItem){ - if(mWeaponItem->ReqLevel > GetLevel()){ - return 0; - } - - if(!weapon_item->IsEquipable(GetBaseRace(), GetClass())){ - return 0; - } - } - else{ + // check for items being illegally attained + if (weapon_item) { + if (!weapon_item->GetItem()) + return 0; + + if (weapon_item->GetItemRequiredLevel(true) > GetLevel()) + return 0; + + if (!weapon_item->IsEquipable(GetBaseRace(), GetClass())) return 0; - } } - if(against->GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)){ - if(weapon_item){ + if (against->GetSpecialAbility(IMMUNE_MELEE_NONMAGICAL)) { + if (weapon_item) { // check to see if the weapon is magic - bool MagicWeapon = false; - if(weapon_item->GetItem() && weapon_item->GetItem()->Magic) - MagicWeapon = true; - else - if(spellbonuses.MagicWeapon || itembonuses.MagicWeapon) - MagicWeapon = true; - else - // An augment on the weapon that is marked magic makes - // the item magical. - for(x = 0; MagicWeapon == false && x < EmuConstants::ITEM_COMMON_SIZE; x++) - { - if(weapon_item->GetAugment(x) && weapon_item->GetAugment(x)->GetItem()) - { - if (weapon_item->GetAugment(x)->GetItem()->Magic) - MagicWeapon = true; - } - } - - if(MagicWeapon) { - - if(IsClient() && GetLevel() < weapon_item->GetItem()->RecLevel){ - dmg = CastToClient()->CalcRecommendedLevelBonus(GetLevel(), weapon_item->GetItem()->RecLevel, weapon_item->GetItem()->Damage); - } - else{ - dmg = weapon_item->GetItem()->Damage; - } - - for(int x = 0; x < EmuConstants::ITEM_COMMON_SIZE; x++){ - if(weapon_item->GetAugment(x) && weapon_item->GetAugment(x)->GetItem()){ - dmg += weapon_item->GetAugment(x)->GetItem()->Damage; - if (hate) *hate += weapon_item->GetAugment(x)->GetItem()->Damage + weapon_item->GetAugment(x)->GetItem()->ElemDmgAmt; - } - } + bool MagicWeapon = weapon_item->GetItemMagical(true) || spellbonuses.MagicWeapon || itembonuses.MagicWeapon; + if (MagicWeapon) { + auto rec_level = weapon_item->GetItemRecommendedLevel(true); + if (IsClient() && GetLevel() < rec_level) + dmg = CastToClient()->CalcRecommendedLevelBonus( + GetLevel(), rec_level, weapon_item->GetItemWeaponDamage(true)); + else + dmg = weapon_item->GetItemWeaponDamage(true); dmg = dmg <= 0 ? 1 : dmg; + } else { + return 0; } - else + } else { + bool MagicGloves = false; + if (IsClient()) { + const ItemInst *gloves = CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotHands); + if (gloves) + MagicGloves = gloves->GetItemMagical(true); + } + + if (GetClass() == MONK || GetClass() == BEASTLORD) { + if (MagicGloves || GetLevel() >= 30) { + dmg = GetHandToHandDamage(); + if (hate) + *hate += dmg; + } + } else if (GetOwner() && + GetLevel() >= + RuleI(Combat, PetAttackMagicLevel)) { // pets wouldn't actually use this but... + dmg = 1; // it gives us an idea if we can hit + } else if (MagicGloves || GetSpecialAbility(SPECATK_MAGICAL)) { + dmg = 1; + } else return 0; } - else{ - if((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30){ - dmg = GetMonkHandToHandDamage(); - if (hate) *hate += dmg; - } - else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){ //pets wouldn't actually use this but... - dmg = 1; //it gives us an idea if we can hit - } - else if(GetSpecialAbility(SPECATK_MAGICAL)){ - dmg = 1; - } - else - return 0; - } - } - else{ - if(weapon_item){ - if(weapon_item->GetItem()){ - - if(IsClient() && GetLevel() < weapon_item->GetItem()->RecLevel){ - dmg = CastToClient()->CalcRecommendedLevelBonus(GetLevel(), weapon_item->GetItem()->RecLevel, weapon_item->GetItem()->Damage); - } - else{ - dmg = weapon_item->GetItem()->Damage; + } else { + if (weapon_item) { + if (weapon_item->GetItem()) { + auto rec_level = weapon_item->GetItemRecommendedLevel(true); + if (IsClient() && GetLevel() < rec_level) { + dmg = CastToClient()->CalcRecommendedLevelBonus( + GetLevel(), rec_level, weapon_item->GetItemWeaponDamage(true)); + } else { + dmg = weapon_item->GetItemWeaponDamage(true); } - for (int x = 0; x < EmuConstants::ITEM_COMMON_SIZE; x++){ - if(weapon_item->GetAugment(x) && weapon_item->GetAugment(x)->GetItem()){ - dmg += weapon_item->GetAugment(x)->GetItem()->Damage; - if (hate) *hate += weapon_item->GetAugment(x)->GetItem()->Damage + weapon_item->GetAugment(x)->GetItem()->ElemDmgAmt; - } - } dmg = dmg <= 0 ? 1 : dmg; } - } - else{ - if(GetClass() == MONK || GetClass() == BEASTLORD){ - dmg = GetMonkHandToHandDamage(); - if (hate) *hate += dmg; - } - else{ - dmg = 1; - } + } else { + dmg = GetHandToHandDamage(); + if (hate) + *hate += dmg; } } int eledmg = 0; - if(!against->GetSpecialAbility(IMMUNE_MAGIC)){ - if(weapon_item && weapon_item->GetItem() && weapon_item->GetItem()->ElemDmgAmt){ - if(IsClient() && GetLevel() < weapon_item->GetItem()->RecLevel){ - eledmg = CastToClient()->CalcRecommendedLevelBonus(GetLevel(), weapon_item->GetItem()->RecLevel, weapon_item->GetItem()->ElemDmgAmt); - } - else{ - eledmg = weapon_item->GetItem()->ElemDmgAmt; - } - - if(eledmg) - { - eledmg = (eledmg * against->ResistSpell(weapon_item->GetItem()->ElemDmgType, 0, this) / 100); - } - } - - if(weapon_item){ - for (int x = 0; x < EmuConstants::ITEM_COMMON_SIZE; x++){ - if(weapon_item->GetAugment(x) && weapon_item->GetAugment(x)->GetItem()){ - if(weapon_item->GetAugment(x)->GetItem()->ElemDmgAmt) - eledmg += (weapon_item->GetAugment(x)->GetItem()->ElemDmgAmt * against->ResistSpell(weapon_item->GetAugment(x)->GetItem()->ElemDmgType, 0, this) / 100); - } - } - } + if (!against->GetSpecialAbility(IMMUNE_MAGIC)) { + if (weapon_item && weapon_item->GetItem() && weapon_item->GetItemElementalFlag(true)) + // the client actually has the way this is done, it does not appear to check req! + eledmg = against->ResistElementalWeaponDmg(weapon_item); } - if(against->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE)){ - if(weapon_item && weapon_item->GetItem()){ - if(weapon_item->GetItem()->BaneDmgBody == against->GetBodyType()){ - if(IsClient() && GetLevel() < weapon_item->GetItem()->RecLevel){ - banedmg += CastToClient()->CalcRecommendedLevelBonus(GetLevel(), weapon_item->GetItem()->RecLevel, weapon_item->GetItem()->BaneDmgAmt); - } - else{ - banedmg += weapon_item->GetItem()->BaneDmgAmt; - } - } + if (weapon_item && weapon_item->GetItem() && + (weapon_item->GetItemBaneDamageBody(true) || weapon_item->GetItemBaneDamageRace(true))) + banedmg = against->CheckBaneDamage(weapon_item); - if(weapon_item->GetItem()->BaneDmgRace == against->GetRace()){ - if(IsClient() && GetLevel() < weapon_item->GetItem()->RecLevel){ - banedmg += CastToClient()->CalcRecommendedLevelBonus(GetLevel(), weapon_item->GetItem()->RecLevel, weapon_item->GetItem()->BaneDmgRaceAmt); - } - else{ - banedmg += weapon_item->GetItem()->BaneDmgRaceAmt; - } - } - - for (int x = 0; x < EmuConstants::ITEM_COMMON_SIZE; x++){ - if(weapon_item->GetAugment(x) && weapon_item->GetAugment(x)->GetItem()){ - if(weapon_item->GetAugment(x)->GetItem()->BaneDmgBody == against->GetBodyType()){ - banedmg += weapon_item->GetAugment(x)->GetItem()->BaneDmgAmt; - } - - if(weapon_item->GetAugment(x)->GetItem()->BaneDmgRace == against->GetRace()){ - banedmg += weapon_item->GetAugment(x)->GetItem()->BaneDmgRaceAmt; - } - } - } - } - - if(!eledmg && !banedmg) - { - if(!GetSpecialAbility(SPECATK_BANE)) + if (against->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE)) { + if (!eledmg && !banedmg) { + if (!GetSpecialAbility(SPECATK_BANE)) return 0; else return 1; - } - else { + } else { dmg += (banedmg + eledmg); - if (hate) *hate += banedmg; - } - } - else{ - if(weapon_item && weapon_item->GetItem()){ - if(weapon_item->GetItem()->BaneDmgBody == against->GetBodyType()){ - if(IsClient() && GetLevel() < weapon_item->GetItem()->RecLevel){ - banedmg += CastToClient()->CalcRecommendedLevelBonus(GetLevel(), weapon_item->GetItem()->RecLevel, weapon_item->GetItem()->BaneDmgAmt); - } - else{ - banedmg += weapon_item->GetItem()->BaneDmgAmt; - } - } - - if(weapon_item->GetItem()->BaneDmgRace == against->GetRace()){ - if(IsClient() && GetLevel() < weapon_item->GetItem()->RecLevel){ - banedmg += CastToClient()->CalcRecommendedLevelBonus(GetLevel(), weapon_item->GetItem()->RecLevel, weapon_item->GetItem()->BaneDmgRaceAmt); - } - else{ - banedmg += weapon_item->GetItem()->BaneDmgRaceAmt; - } - } - - for (int x = 0; x < EmuConstants::ITEM_COMMON_SIZE; x++){ - if(weapon_item->GetAugment(x) && weapon_item->GetAugment(x)->GetItem()){ - if(weapon_item->GetAugment(x)->GetItem()->BaneDmgBody == against->GetBodyType()){ - banedmg += weapon_item->GetAugment(x)->GetItem()->BaneDmgAmt; - } - - if(weapon_item->GetAugment(x)->GetItem()->BaneDmgRace == against->GetRace()){ - banedmg += weapon_item->GetAugment(x)->GetItem()->BaneDmgRaceAmt; - } - } - } + if (hate) + *hate += banedmg; } + } else { dmg += (banedmg + eledmg); - if (hate) *hate += banedmg; + if (hate) + *hate += banedmg; } - if(dmg <= 0){ - return 0; - } - else - return dmg; + return std::max(0, dmg); } //note: throughout this method, setting `damage` to a negative is a way to //stop the attack calculations // IsFromSpell added to allow spell effects to use Attack. (Mainly for the Rampage AA right now.) -bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) +bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, int special) { if (!other) { SetTarget(nullptr); @@ -1180,12 +1037,12 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b return false; // Rogean: How can you attack while feigned? Moved up from Aggro Code. ItemInst* weapon; - if (Hand == MainSecondary){ // Kaiyodo - Pick weapon from the attacking hand - weapon = GetInv().GetItem(MainSecondary); + if (Hand == EQEmu::legacy::SlotSecondary){ // Kaiyodo - Pick weapon from the attacking hand + weapon = GetInv().GetItem(EQEmu::legacy::SlotSecondary); OffHandAtk(true); } else{ - weapon = GetInv().GetItem(MainPrimary); + weapon = GetInv().GetItem(EQEmu::legacy::SlotPrimary); OffHandAtk(false); } @@ -1201,7 +1058,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b // calculate attack_skill and skillinuse depending on hand and weapon // also send Packet to near clients - SkillUseTypes skillinuse; + EQEmu::skills::SkillType skillinuse; AttackAnimation(skillinuse, Hand, weapon); Log.Out(Logs::Detail, Logs::Combat, "Attacking with %s in slot %d using skill %d", weapon?weapon->GetItem()->Name:"Fist", Hand, skillinuse); @@ -1237,7 +1094,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b max_hit = (RuleI(Combat, HitCapPre20)); CheckIncreaseSkill(skillinuse, other, -15); - CheckIncreaseSkill(SkillOffense, other, -15); + CheckIncreaseSkill(EQEmu::skills::SkillOffense, other, -15); // *************************************************************** // *** Calculate the damage bonus, if applicable, for this hit *** @@ -1253,12 +1110,12 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b int ucDamageBonus = 0; - if( Hand == MainPrimary && GetLevel() >= 28 && IsWarriorClass() ) + if (Hand == EQEmu::legacy::SlotPrimary && GetLevel() >= 28 && IsWarriorClass()) { // Damage bonuses apply only to hits from the main hand (Hand == MainPrimary) by characters level 28 and above // who belong to a melee class. If we're here, then all of these conditions apply. - ucDamageBonus = GetWeaponDamageBonus( weapon ? weapon->GetItem() : (const Item_Struct*) nullptr ); + ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQEmu::ItemBase*) nullptr); min_hit += (int) ucDamageBonus; max_hit += (int) ucDamageBonus; @@ -1266,10 +1123,10 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b } #endif //Live AA - Sinister Strikes *Adds weapon damage bonus to offhand weapon. - if (Hand == MainSecondary) { + if (Hand == EQEmu::legacy::SlotSecondary) { if (aabonuses.SecondaryDmgInc || itembonuses.SecondaryDmgInc || spellbonuses.SecondaryDmgInc){ - ucDamageBonus = GetWeaponDamageBonus( weapon ? weapon->GetItem() : (const Item_Struct*) nullptr ); + ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQEmu::ItemBase*) nullptr, true); min_hit += (int) ucDamageBonus; max_hit += (int) ucDamageBonus; @@ -1277,6 +1134,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b } } + // this effect is actually a min cap that happens after the final damage is calculated min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100; if(max_hit < min_hit) @@ -1303,67 +1161,53 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b } //check to see if we hit.. - if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) { - Log.Out(Logs::Detail, Logs::Combat, "Attack missed. Damage set to 0."); - damage = 0; - } else { //we hit, try to avoid it - other->AvoidDamage(this, damage); - other->MeleeMitigation(this, damage, min_hit, opts); - if(damage > 0) - CommonOutgoingHitSuccess(other, damage, skillinuse); - - Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage); - } - - //riposte - bool slippery_attack = false; // Part of hack to allow riposte to become a miss, but still allow a Strikethrough chance (like on Live) - if (damage == -3) { - if (bRiposte) return false; - else { - if (Hand == MainSecondary) {// Do we even have it & was attack with mainhand? If not, don't bother with other calculations - //Live AA - SlipperyAttacks - //This spell effect most likely directly modifies the actual riposte chance when using offhand attack. - int32 OffhandRiposteFail = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail; - OffhandRiposteFail *= -1; //Live uses a negative value for this. - - if (OffhandRiposteFail && - (OffhandRiposteFail > 99 || zone->random.Roll(OffhandRiposteFail))) { - damage = 0; // Counts as a miss - slippery_attack = true; - } else - DoRiposte(other); - if (IsDead()) return false; + if (other->AvoidDamage(this, damage, Hand)) { + if (!bRiposte && !IsStrikethrough) { + int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; + if(strike_through && zone->random.Roll(strike_through)) { + Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses! + Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit + return false; } - else + // I'm pretty sure you can riposte a riposte + if (damage == -3 && !bRiposte) { DoRiposte(other); - if (IsDead()) return false; + if (IsDead()) + return false; + } + } + Log.Out(Logs::Detail, Logs::Combat, "Avoided damage with code %d", damage); + } else { + if (other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) { + other->MeleeMitigation(this, damage, min_hit, opts); + if (damage > 0) + CommonOutgoingHitSuccess(other, damage, skillinuse,opts); + Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage); + } else { + Log.Out(Logs::Detail, Logs::Combat, "Attack missed. Damage set to 0."); + damage = 0; } } - - if (((damage < 0) || slippery_attack) && !bRiposte && !IsStrikethrough) { // Hack to still allow Strikethrough chance w/ Slippery Attacks AA - int32 bonusStrikeThrough = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; - - if(bonusStrikeThrough && zone->random.Roll(bonusStrikeThrough)) { - Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses! - Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit - return false; - } - } - } - else{ + } else { damage = -5; } // Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same. // If we are this far, this means we are atleast making a swing. - if (!bRiposte) // Ripostes never generate any aggro. - other->AddToHateList(this, hate); + other->AddToHateList(this, hate); /////////////////////////////////////////////////////////// ////// Send Attack Damage /////////////////////////////////////////////////////////// - other->Damage(this, damage, SPELL_UNKNOWN, skillinuse); + if (damage > 0 && aabonuses.SkillAttackProc[0] && aabonuses.SkillAttackProc[1] == skillinuse && + IsValidSpell(aabonuses.SkillAttackProc[2])) { + float chance = aabonuses.SkillAttackProc[0] / 1000.0f; + if (zone->random.Roll(chance)) + SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::CastingSlot::Item, 0, -1, + spells[aabonuses.SkillAttackProc[2]].ResistDiff); + } + other->Damage(this, damage, SPELL_UNKNOWN, skillinuse, true, -1, false, special); if (IsDead()) return false; @@ -1372,10 +1216,10 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b if (damage > 0 && HasSkillProcSuccess() && other && other->GetHP() > 0) TrySkillProc(other, skillinuse, 0, true, Hand); - CommonBreakInvisible(); + CommonBreakInvisibleFromCombat(); if(GetTarget()) - TriggerDefensiveProcs(weapon, other, Hand, damage); + TriggerDefensiveProcs(other, Hand, true, damage); if (damage > 0) return true; @@ -1391,7 +1235,7 @@ void Mob::Heal() SendHPUpdate(); } -void Client::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable, int8 buffslot, bool iBuffTic) +void Client::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, int special) { if(dead || IsCorpse()) return; @@ -1404,7 +1248,7 @@ void Client::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes att //Don't do PvP mitigation if the caster is damaging himself if(other && other->IsClient() && (other != this) && damage > 0) { int PvPMitigation = 100; - if(attack_skill == SkillArchery) + if (attack_skill == EQEmu::skills::SkillArchery) PvPMitigation = 80; else PvPMitigation = 67; @@ -1415,16 +1259,16 @@ void Client::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes att damage = -5; //do a majority of the work... - CommonDamage(other, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic); + CommonDamage(other, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic, special); if (damage > 0) { if (spell_id == SPELL_UNKNOWN) - CheckIncreaseSkill(SkillDefense, other, -15); + CheckIncreaseSkill(EQEmu::skills::SkillDefense, other, -15); } } -bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack_skill) +bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::SkillType attack_skill) { if(!ClientFinishedLoading()) return false; @@ -1606,7 +1450,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att //this generates a lot of 'updates' to the client that the client does not need BuffFadeNonPersistDeath(); if (RuleB(Character, UnmemSpellsOnDeath)) { - if((GetClientVersionBit() & BIT_SoFAndLater) && RuleB(Character, RespawnFromHover)) + if((ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) && RuleB(Character, RespawnFromHover)) UnmemSpellAll(true); else UnmemSpellAll(false); @@ -1615,17 +1459,16 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att if((RuleB(Character, LeaveCorpses) && GetLevel() >= RuleI(Character, DeathItemLossLevel)) || RuleB(Character, LeaveNakedCorpses)) { // creating the corpse takes the cash/items off the player too - Corpse *new_corpse = new Corpse(this, exploss); + auto new_corpse = new Corpse(this, exploss); - char tmp[20]; - database.GetVariable("ServerType", tmp, 9); - if(atoi(tmp)==1 && killerMob != nullptr && killerMob->IsClient()){ - char tmp2[10] = {0}; - database.GetVariable("PvPreward", tmp, 9); - int reward = atoi(tmp); + std::string tmp; + database.GetVariable("ServerType", tmp); + if(tmp[0] == '1' && tmp[1] == '\0' && killerMob != nullptr && killerMob->IsClient()){ + database.GetVariable("PvPreward", tmp); + int reward = atoi(tmp.c_str()); if(reward==3){ - database.GetVariable("PvPitem", tmp2, 9); - int pvpitem = atoi(tmp2); + database.GetVariable("PvPitem", tmp); + int pvpitem = atoi(tmp.c_str()); if(pvpitem>0 && pvpitem<200000) new_corpse->SetPlayerKillItemID(pvpitem); } @@ -1669,7 +1512,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att from these and overwrite what we set in pp anyway */ - if(LeftCorpse && (GetClientVersionBit() & BIT_SoFAndLater) && RuleB(Character, RespawnFromHover)) + if(LeftCorpse && (ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) && RuleB(Character, RespawnFromHover)) { ClearDraggedCorpses(); RespawnFromHoverTimer.Start(RuleI(Character, RespawnFromHoverTimer) * 1000); @@ -1709,7 +1552,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att return true; } -bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) +bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, int special) { int damage = 0; @@ -1740,62 +1583,62 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool FaceTarget(GetTarget()); - SkillUseTypes skillinuse = SkillHandtoHand; - if (Hand == MainPrimary) { - skillinuse = static_cast(GetPrimSkill()); + EQEmu::skills::SkillType skillinuse = EQEmu::skills::SkillHandtoHand; + if (Hand == EQEmu::legacy::SlotPrimary) { + skillinuse = static_cast(GetPrimSkill()); OffHandAtk(false); } - if (Hand == MainSecondary) { - skillinuse = static_cast(GetSecSkill()); + if (Hand == EQEmu::legacy::SlotSecondary) { + skillinuse = static_cast(GetSecSkill()); OffHandAtk(true); } //figure out what weapon they are using, if any - const Item_Struct* weapon = nullptr; - if (Hand == MainPrimary && equipment[MainPrimary] > 0) - weapon = database.GetItem(equipment[MainPrimary]); - else if (equipment[MainSecondary]) - weapon = database.GetItem(equipment[MainSecondary]); + const EQEmu::ItemBase* weapon = nullptr; + if (Hand == EQEmu::legacy::SlotPrimary && equipment[EQEmu::legacy::SlotPrimary] > 0) + weapon = database.GetItem(equipment[EQEmu::legacy::SlotPrimary]); + else if (equipment[EQEmu::legacy::SlotSecondary]) + weapon = database.GetItem(equipment[EQEmu::legacy::SlotSecondary]); //We dont factor much from the weapon into the attack. //Just the skill type so it doesn't look silly using punching animations and stuff while wielding weapons if(weapon) { Log.Out(Logs::Detail, Logs::Combat, "Attacking with weapon: %s (%d) (too bad im not using it for much)", weapon->Name, weapon->ID); - if(Hand == MainSecondary && weapon->ItemType == ItemTypeShield){ + if (Hand == EQEmu::legacy::SlotSecondary && weapon->ItemType == EQEmu::item::ItemTypeShield){ Log.Out(Logs::Detail, Logs::Combat, "Attack with shield canceled."); return false; } - switch(weapon->ItemType){ - case ItemType1HSlash: - skillinuse = Skill1HSlashing; - break; - case ItemType2HSlash: - skillinuse = Skill2HSlashing; - break; - case ItemType1HPiercing: - //skillinuse = Skill1HPiercing; - //break; - case ItemType2HPiercing: - skillinuse = Skill1HPiercing; // change to Skill2HPiercing once activated - break; - case ItemType1HBlunt: - skillinuse = Skill1HBlunt; - break; - case ItemType2HBlunt: - skillinuse = Skill2HBlunt; - break; - case ItemTypeBow: - skillinuse = SkillArchery; - break; - case ItemTypeLargeThrowing: - case ItemTypeSmallThrowing: - skillinuse = SkillThrowing; - break; - default: - skillinuse = SkillHandtoHand; - break; + switch(weapon->ItemType) { + case EQEmu::item::ItemType1HSlash: + skillinuse = EQEmu::skills::Skill1HSlashing; + break; + case EQEmu::item::ItemType2HSlash: + skillinuse = EQEmu::skills::Skill2HSlashing; + break; + case EQEmu::item::ItemType1HPiercing: + skillinuse = EQEmu::skills::Skill1HPiercing; + break; + case EQEmu::item::ItemType2HPiercing: + skillinuse = EQEmu::skills::Skill2HPiercing; + break; + case EQEmu::item::ItemType1HBlunt: + skillinuse = EQEmu::skills::Skill1HBlunt; + break; + case EQEmu::item::ItemType2HBlunt: + skillinuse = EQEmu::skills::Skill2HBlunt; + break; + case EQEmu::item::ItemTypeBow: + skillinuse = EQEmu::skills::SkillArchery; + break; + case EQEmu::item::ItemTypeLargeThrowing: + case EQEmu::item::ItemTypeSmallThrowing: + skillinuse = EQEmu::skills::SkillThrowing; + break; + default: + skillinuse = EQEmu::skills::SkillHandtoHand; + break; } } @@ -1806,11 +1649,6 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool ItemInst weapon_inst(weapon, charges); AttackAnimation(skillinuse, Hand, &weapon_inst); - // Remove this once Skill2HPiercing is activated - //Work-around for there being no 2HP skill - We use 99 for the 2HB animation and 36 for pierce messages - if(skillinuse == 99) - skillinuse = static_cast(36); - //basically "if not immune" then do the attack if((weapon_damage) > 0) { @@ -1871,7 +1709,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool if(other->IsClient() && other->CastToClient()->IsSitting()) { Log.Out(Logs::Detail, Logs::Combat, "Client %s is sitting. Hitting for max damage (%d).", other->GetName(), (max_dmg+eleBane)); damage = (max_dmg+eleBane); - damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse); + damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse, opts) / 100) + GetSkillDmgAmt(skillinuse); if(opts) { damage *= opts->damage_percent; @@ -1896,21 +1734,18 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool hit_chance_bonus += opts->hit_chance; } - if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) { - damage = 0; //miss - } else { //hit, check for damage avoidance - other->AvoidDamage(this, damage); - other->MeleeMitigation(this, damage, min_dmg+eleBane, opts); - if(damage > 0) { - CommonOutgoingHitSuccess(other, damage, skillinuse); + if (other->AvoidDamage(this, damage, Hand)) { + if (!bRiposte && damage == -3) + DoRiposte(other); + } else { + if (other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) { + other->MeleeMitigation(this, damage, min_dmg+eleBane, opts); + CommonOutgoingHitSuccess(other, damage, skillinuse, opts); + } else { + damage = 0; } - Log.Out(Logs::Detail, Logs::Combat, "Generating hate %d towards %s", hate, GetName()); - // now add done damage to the hate list - if(damage > 0) - other->AddToHateList(this, hate); - else - other->AddToHateList(this, 0); } + other->AddToHateList(this, hate); } Log.Out(Logs::Detail, Logs::Combat, "Final damage against %s: %d", other->GetName(), damage); @@ -1923,14 +1758,8 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool else damage = -5; - //cant riposte a riposte - if (bRiposte && damage == -3) { - Log.Out(Logs::Detail, Logs::Combat, "Riposte of riposte canceled."); - return false; - } - if(GetHP() > 0 && !other->HasDied()) { - other->Damage(this, damage, SPELL_UNKNOWN, skillinuse, false); // Not avoidable client already had thier chance to Avoid + other->Damage(this, damage, SPELL_UNKNOWN, skillinuse, true, -1, false, special); // Not avoidable client already had thier chance to Avoid } else return false; @@ -1939,7 +1768,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool MeleeLifeTap(damage); - CommonBreakInvisible(); + CommonBreakInvisibleFromCombat(); //I doubt this works... if (!GetTarget()) @@ -1956,12 +1785,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool } if(GetHP() > 0 && !other->HasDied()) - TriggerDefensiveProcs(nullptr, other, Hand, damage); - - // now check ripostes - if (damage == -3) { // riposting - DoRiposte(other); - } + TriggerDefensiveProcs(other, Hand, true, damage); if (damage > 0) return true; @@ -1970,7 +1794,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool return false; } -void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable, int8 buffslot, bool iBuffTic) { +void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, int special) { if(spell_id==0) spell_id = SPELL_UNKNOWN; @@ -1996,7 +1820,7 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack if(IsLDoNTrapped()) { Message_StringID(13, LDON_ACCIDENT_SETOFF2); - SpellFinished(GetLDoNTrapSpellID(), other, 10, 0, -1, spells[GetLDoNTrapSpellID()].ResistDiff, false); + SpellFinished(GetLDoNTrapSpellID(), other, EQEmu::CastingSlot::Item, 0, -1, spells[GetLDoNTrapSpellID()].ResistDiff, false); SetLDoNTrapSpellID(0); SetLDoNTrapped(false); SetLDoNTrapDetected(false); @@ -2005,7 +1829,7 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack } //do a majority of the work... - CommonDamage(other, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic); + CommonDamage(other, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic, special); if(damage > 0) { //see if we are gunna start fleeing @@ -2013,53 +1837,55 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack } } -bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack_skill) { - Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killerMob->GetName(), damage, spell, attack_skill); +bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::SkillType attack_skill) +{ + Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", + ((killer_mob) ? (killer_mob->GetName()) : ("[nullptr]")), damage, spell, attack_skill); bool MadeCorpse = false; uint16 OrigEntID = this->GetID(); Mob *oos = nullptr; - if(killerMob) { - oos = killerMob->GetOwnerOrSelf(); + if (killer_mob) { + oos = killer_mob->GetOwnerOrSelf(); char buffer[48] = { 0 }; - snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast(attack_skill)); - if(parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0) - { - if(GetHP() < 0) { + snprintf(buffer, 47, "%d %d %d %d", killer_mob->GetID(), damage, spell, static_cast(attack_skill)); + + if (parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0) { + if (GetHP() < 0) { SetHP(0); } return false; } - if(killerMob && killerMob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) { - char val1[20]={0}; + if (killer_mob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) { + char val1[20] = { 0 }; entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE, - killerMob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1)); + killer_mob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1)); } - } else { - + } + else { char buffer[48] = { 0 }; - snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast(attack_skill)); - if(parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0) - { - if(GetHP() < 0) { + snprintf(buffer, 47, "%d %d %d %d", 0, damage, spell, static_cast(attack_skill)); + + if (parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0) { + if (GetHP() < 0) { SetHP(0); } return false; } } - if (IsEngaged()) - { + if (IsEngaged()) { zone->DelAggroMob(); Log.Out(Logs::Detail, Logs::Attack, "%s Mobs currently Aggro %i", __FUNCTION__, zone->MobsAggroCount()); } + SetHP(0); SetPet(0); - if (GetSwarmOwner()){ + if (GetSwarmOwner()) { Mob* owner = entity_list.GetMobID(GetSwarmOwner()); if (owner) owner->SetTempPetCount(owner->GetTempPetCount() - 1); @@ -2069,113 +1895,124 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack entity_list.RemoveFromTargets(this, p_depop); - if(p_depop == true) + if (p_depop == true) return false; HasAISpellEffects = false; BuffFadeAll(); uint8 killed_level = GetLevel(); - EQApplicationPacket* app= new EQApplicationPacket(OP_Death,sizeof(Death_Struct)); + if (GetClass() == LDON_TREASURE) { // open chest + auto outapp = new EQApplicationPacket(OP_Animation, sizeof(Animation_Struct)); + Animation_Struct* anim = (Animation_Struct*)outapp->pBuffer; + anim->spawnid = GetID(); + anim->action = 0x0F; + anim->speed = 10; + entity_list.QueueCloseClients(this, outapp); + safe_delete(outapp); + } + + auto app = new EQApplicationPacket(OP_Death, sizeof(Death_Struct)); Death_Struct* d = (Death_Struct*)app->pBuffer; d->spawn_id = GetID(); - d->killer_id = killerMob ? killerMob->GetID() : 0; + d->killer_id = killer_mob ? killer_mob->GetID() : 0; d->bindzoneid = 0; d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell; d->attack_skill = SkillDamageTypes[attack_skill]; d->damage = damage; app->priority = 6; - entity_list.QueueClients(killerMob, app, false); - - if(respawn2) { - respawn2->DeathReset(1); - } - - if (killerMob) { - if(GetClass() != LDON_TREASURE) - hate_list.AddEntToHateList(killerMob, damage); - } + entity_list.QueueClients(killer_mob, app, false); safe_delete(app); + if (respawn2) { + respawn2->DeathReset(1); + } + + if (killer_mob && GetClass() != LDON_TREASURE) + hate_list.AddEntToHateList(killer_mob, damage); + Mob *give_exp = hate_list.GetDamageTopOnHateList(this); - if(give_exp == nullptr) + if (give_exp == nullptr) give_exp = killer; - if(give_exp && give_exp->HasOwner()) { + if (give_exp && give_exp->HasOwner()) { bool ownerInGroup = false; - if((give_exp->HasGroup() && give_exp->GetGroup()->IsGroupMember(give_exp->GetUltimateOwner())) + if ((give_exp->HasGroup() && give_exp->GetGroup()->IsGroupMember(give_exp->GetUltimateOwner())) || (give_exp->IsPet() && (give_exp->GetOwner()->IsClient() - || ( give_exp->GetOwner()->HasGroup() && give_exp->GetOwner()->GetGroup()->IsGroupMember(give_exp->GetOwner()->GetUltimateOwner()))))) + || (give_exp->GetOwner()->HasGroup() && give_exp->GetOwner()->GetGroup()->IsGroupMember(give_exp->GetOwner()->GetUltimateOwner()))))) ownerInGroup = true; give_exp = give_exp->GetUltimateOwner(); #ifdef BOTS - if(!RuleB(Bots, BotGroupXP) && !ownerInGroup) { + if (!RuleB(Bots, BotGroupXP) && !ownerInGroup) { give_exp = nullptr; } #endif //BOTS } - if(give_exp && give_exp->IsTempPet() && give_exp->IsPetOwnerClient()) { - - if (give_exp->IsNPC() && give_exp->CastToNPC()->GetSwarmOwner()){ - Mob* temp_owner = nullptr; - temp_owner = entity_list.GetMobID(give_exp->CastToNPC()->GetSwarmOwner()); - + if (give_exp && give_exp->IsTempPet() && give_exp->IsPetOwnerClient()) { + if (give_exp->IsNPC() && give_exp->CastToNPC()->GetSwarmOwner()) { + Mob* temp_owner = entity_list.GetMobID(give_exp->CastToNPC()->GetSwarmOwner()); if (temp_owner) give_exp = temp_owner; } } - int PlayerCount = 0; // QueryServ Player Counting Client *give_exp_client = nullptr; - if(give_exp && give_exp->IsClient()) + if (give_exp && give_exp->IsClient()) give_exp_client = give_exp->CastToClient(); + //do faction hits even if we are a merchant, so long as a player killed us + if (give_exp_client && !RuleB(NPC, EnableMeritBasedFaction)) + hate_list.DoFactionHits(GetNPCFactionID()); + bool IsLdonTreasure = (this->GetClass() == LDON_TREASURE); - if (give_exp_client && !IsCorpse()) - { + + if (give_exp_client && !IsCorpse()) { Group *kg = entity_list.GetGroupByClient(give_exp_client); Raid *kr = entity_list.GetRaidByClient(give_exp_client); int32 finalxp = EXP_FORMULA; finalxp = give_exp_client->mod_client_xp(finalxp, this); - if(kr) - { - if(!IsLdonTreasure && MerchantType == 0) { + if (kr) { + if (!IsLdonTreasure && MerchantType == 0) { kr->SplitExp((finalxp), this); - if(killerMob && (kr->IsRaidMember(killerMob->GetName()) || kr->IsRaidMember(killerMob->GetUltimateOwner()->GetName()))) - killerMob->TrySpellOnKill(killed_level,spell); + if (killer_mob && (kr->IsRaidMember(killer_mob->GetName()) || kr->IsRaidMember(killer_mob->GetUltimateOwner()->GetName()))) + killer_mob->TrySpellOnKill(killed_level, spell); } + /* Send the EVENT_KILLED_MERIT event for all raid members */ for (int i = 0; i < MAX_RAID_MEMBERS; i++) { if (kr->members[i].member != nullptr && kr->members[i].member->IsClient()) { // If Group Member is Client Client *c = kr->members[i].member; parse->EventNPC(EVENT_KILLED_MERIT, this, c, "killed", 0); - if(RuleB(NPC, EnableMeritBasedFaction)) + if (RuleB(NPC, EnableMeritBasedFaction)) c->SetFactionLevel(c->CharacterID(), GetNPCFactionID(), c->GetBaseClass(), c->GetBaseRace(), c->GetDeity()); mod_npc_killed_merit(kr->members[i].member); - if(RuleB(TaskSystem, EnableTaskSystem)) + if (RuleB(TaskSystem, EnableTaskSystem)) kr->members[i].member->UpdateTasksOnKill(GetNPCTypeID()); PlayerCount++; } } // QueryServ Logging - Raid Kills - if(RuleB(QueryServ, PlayerLogNPCKills)){ - ServerPacket* pack = new ServerPacket(ServerOP_QSPlayerLogNPCKills, sizeof(QSPlayerLogNPCKill_Struct) + (sizeof(QSPlayerLogNPCKillsPlayers_Struct) * PlayerCount)); + if (RuleB(QueryServ, PlayerLogNPCKills)) { + auto pack = + new ServerPacket(ServerOP_QSPlayerLogNPCKills, + sizeof(QSPlayerLogNPCKill_Struct) + + (sizeof(QSPlayerLogNPCKillsPlayers_Struct) * PlayerCount)); PlayerCount = 0; - QSPlayerLogNPCKill_Struct* QS = (QSPlayerLogNPCKill_Struct*) pack->pBuffer; + QSPlayerLogNPCKill_Struct* QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer; QS->s1.NPCID = this->GetNPCTypeID(); QS->s1.ZoneID = this->GetZoneID(); QS->s1.Type = 2; // Raid Fight @@ -2192,13 +2029,13 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack // End QueryServ Logging } - else if (give_exp_client->IsGrouped() && kg != nullptr) - { - if(!IsLdonTreasure && MerchantType == 0) { + else if (give_exp_client->IsGrouped() && kg != nullptr) { + if (!IsLdonTreasure && MerchantType == 0) { kg->SplitExp((finalxp), this); - if(killerMob && (kg->IsGroupMember(killerMob->GetName()) || kg->IsGroupMember(killerMob->GetUltimateOwner()->GetName()))) - killerMob->TrySpellOnKill(killed_level,spell); + if (killer_mob && (kg->IsGroupMember(killer_mob->GetName()) || kg->IsGroupMember(killer_mob->GetUltimateOwner()->GetName()))) + killer_mob->TrySpellOnKill(killed_level, spell); } + /* Send the EVENT_KILLED_MERIT event and update kill tasks * for all group members */ for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { @@ -2206,12 +2043,12 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack Client *c = kg->members[i]->CastToClient(); parse->EventNPC(EVENT_KILLED_MERIT, this, c, "killed", 0); - if(RuleB(NPC, EnableMeritBasedFaction)) + if (RuleB(NPC, EnableMeritBasedFaction)) c->SetFactionLevel(c->CharacterID(), GetNPCFactionID(), c->GetBaseClass(), c->GetBaseRace(), c->GetDeity()); mod_npc_killed_merit(c); - if(RuleB(TaskSystem, EnableTaskSystem)) + if (RuleB(TaskSystem, EnableTaskSystem)) c->UpdateTasksOnKill(GetNPCTypeID()); PlayerCount++; @@ -2219,10 +2056,13 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack } // QueryServ Logging - Group Kills - if(RuleB(QueryServ, PlayerLogNPCKills)){ - ServerPacket* pack = new ServerPacket(ServerOP_QSPlayerLogNPCKills, sizeof(QSPlayerLogNPCKill_Struct) + (sizeof(QSPlayerLogNPCKillsPlayers_Struct) * PlayerCount)); + if (RuleB(QueryServ, PlayerLogNPCKills)) { + auto pack = + new ServerPacket(ServerOP_QSPlayerLogNPCKills, + sizeof(QSPlayerLogNPCKill_Struct) + + (sizeof(QSPlayerLogNPCKillsPlayers_Struct) * PlayerCount)); PlayerCount = 0; - QSPlayerLogNPCKill_Struct* QS = (QSPlayerLogNPCKill_Struct*) pack->pBuffer; + QSPlayerLogNPCKill_Struct* QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer; QS->s1.NPCID = this->GetNPCTypeID(); QS->s1.ZoneID = this->GetZoneID(); QS->s1.Type = 1; // Group Fight @@ -2238,36 +2078,36 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack } // End QueryServ Logging } - else - { - if(!IsLdonTreasure && MerchantType == 0) { + else { + if (!IsLdonTreasure && MerchantType == 0) { int conlevel = give_exp->GetLevelCon(GetLevel()); - if (conlevel != CON_GREEN) - { - if(!GetOwner() || (GetOwner() && !GetOwner()->IsClient())) - { + if (conlevel != CON_GREEN) { + if (!GetOwner() || (GetOwner() && !GetOwner()->IsClient())) { give_exp_client->AddEXP((finalxp), conlevel); - if(killerMob && (killerMob->GetID() == give_exp_client->GetID() || killerMob->GetUltimateOwner()->GetID() == give_exp_client->GetID())) - killerMob->TrySpellOnKill(killed_level,spell); + if (killer_mob && (killer_mob->GetID() == give_exp_client->GetID() || killer_mob->GetUltimateOwner()->GetID() == give_exp_client->GetID())) + killer_mob->TrySpellOnKill(killed_level, spell); } } } - /* Send the EVENT_KILLED_MERIT event */ + + /* Send the EVENT_KILLED_MERIT event */ parse->EventNPC(EVENT_KILLED_MERIT, this, give_exp_client, "killed", 0); - if(RuleB(NPC, EnableMeritBasedFaction)) + if (RuleB(NPC, EnableMeritBasedFaction)) give_exp_client->SetFactionLevel(give_exp_client->CharacterID(), GetNPCFactionID(), give_exp_client->GetBaseClass(), - give_exp_client->GetBaseRace(), give_exp_client->GetDeity()); + give_exp_client->GetBaseRace(), give_exp_client->GetDeity()); mod_npc_killed_merit(give_exp_client); - if(RuleB(TaskSystem, EnableTaskSystem)) + if (RuleB(TaskSystem, EnableTaskSystem)) give_exp_client->UpdateTasksOnKill(GetNPCTypeID()); // QueryServ Logging - Solo - if(RuleB(QueryServ, PlayerLogNPCKills)){ - ServerPacket* pack = new ServerPacket(ServerOP_QSPlayerLogNPCKills, sizeof(QSPlayerLogNPCKill_Struct) + (sizeof(QSPlayerLogNPCKillsPlayers_Struct) * 1)); - QSPlayerLogNPCKill_Struct* QS = (QSPlayerLogNPCKill_Struct*) pack->pBuffer; + if (RuleB(QueryServ, PlayerLogNPCKills)) { + auto pack = new ServerPacket(ServerOP_QSPlayerLogNPCKills, + sizeof(QSPlayerLogNPCKill_Struct) + + (sizeof(QSPlayerLogNPCKillsPlayers_Struct) * 1)); + QSPlayerLogNPCKill_Struct* QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer; QS->s1.NPCID = this->GetNPCTypeID(); QS->s1.ZoneID = this->GetZoneID(); QS->s1.Type = 0; // Solo Fight @@ -2281,80 +2121,76 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack } } - //do faction hits even if we are a merchant, so long as a player killed us - if(give_exp_client && !RuleB(NPC, EnableMeritBasedFaction)) - hate_list.DoFactionHits(GetNPCFactionID()); - if (!HasOwner() && !IsMerc() && class_ != MERCHANT && class_ != ADVENTUREMERCHANT && !GetSwarmInfo() - && MerchantType == 0 && killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) || + && MerchantType == 0 && ((killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) || (killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient()))) + || (killer_mob && IsLdonTreasure))) { - if(killer != 0) - { - if(killer->GetOwner() != 0 && killer->GetOwner()->IsClient()) + if (killer != 0) { + if (killer->GetOwner() != 0 && killer->GetOwner()->IsClient()) killer = killer->GetOwner(); - if(!killer->CastToClient()->GetGM() && killer->IsClient()) + if (killer->IsClient() && !killer->CastToClient()->GetGM()) this->CheckMinMaxLevel(killer); } + entity_list.RemoveFromAutoXTargets(this); uint16 emoteid = this->GetEmoteID(); - Corpse* corpse = new Corpse(this, &itemlist, GetNPCTypeID(), &NPCTypedata,level>54?RuleI(NPC,MajorNPCCorpseDecayTimeMS):RuleI(NPC,MinorNPCCorpseDecayTimeMS)); - MadeCorpse = true; + auto corpse = new Corpse(this, &itemlist, GetNPCTypeID(), &NPCTypedata, + level > 54 ? RuleI(NPC, MajorNPCCorpseDecayTimeMS) + : RuleI(NPC, MinorNPCCorpseDecayTimeMS)); entity_list.LimitRemoveNPC(this); entity_list.AddCorpse(corpse, GetID()); entity_list.UnMarkNPC(GetID()); entity_list.RemoveNPC(GetID()); this->SetID(0); - if(killer != 0 && emoteid != 0) + + if (killer != 0 && emoteid != 0) corpse->CastToNPC()->DoNPCEmote(AFTERDEATH, emoteid); - if(killer != 0 && killer->IsClient()) { + if (killer != 0 && killer->IsClient()) { corpse->AllowPlayerLoot(killer, 0); - if(killer->IsGrouped()) { + if (killer->IsGrouped()) { Group* group = entity_list.GetGroupByClient(killer->CastToClient()); - if(group != 0) { - for(int i=0;i<6;i++) { // Doesnt work right, needs work - if(group->members[i] != nullptr) { - corpse->AllowPlayerLoot(group->members[i],i); + if (group != 0) { + for (int i = 0; i<6; i++) { // Doesnt work right, needs work + if (group->members[i] != nullptr) { + corpse->AllowPlayerLoot(group->members[i], i); } } } } - else if(killer->IsRaidGrouped()){ + else if (killer->IsRaidGrouped()) { Raid* r = entity_list.GetRaidByClient(killer->CastToClient()); - if(r){ + if (r) { int i = 0; - for(int x = 0; x < MAX_RAID_MEMBERS; x++) - { - switch(r->GetLootType()) - { + for (int x = 0; x < MAX_RAID_MEMBERS; x++) { + switch (r->GetLootType()) { case 0: case 1: - if(r->members[x].member && r->members[x].IsRaidLeader){ + if (r->members[x].member && r->members[x].IsRaidLeader) { corpse->AllowPlayerLoot(r->members[x].member, i); i++; } break; case 2: - if(r->members[x].member && r->members[x].IsRaidLeader){ + if (r->members[x].member && r->members[x].IsRaidLeader) { corpse->AllowPlayerLoot(r->members[x].member, i); i++; } - else if(r->members[x].member && r->members[x].IsGroupLeader){ + else if (r->members[x].member && r->members[x].IsGroupLeader) { corpse->AllowPlayerLoot(r->members[x].member, i); i++; } break; case 3: - if(r->members[x].member && r->members[x].IsLooter){ + if (r->members[x].member && r->members[x].IsLooter) { corpse->AllowPlayerLoot(r->members[x].member, i); i++; } break; case 4: - if(r->members[x].member) - { + if (r->members[x].member) { corpse->AllowPlayerLoot(r->members[x].member, i); i++; } @@ -2364,29 +2200,30 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack } } } + else if (killer_mob && IsLdonTreasure) { + auto u_owner = killer_mob->GetUltimateOwner(); + if (u_owner->IsClient()) + corpse->AllowPlayerLoot(u_owner, 0); + } - if(zone && zone->adv_data) - { + if (zone && zone->adv_data) { ServerZoneAdventureDataReply_Struct *sr = (ServerZoneAdventureDataReply_Struct*)zone->adv_data; - if(sr->type == Adventure_Kill) - { + if (sr->type == Adventure_Kill) { zone->DoAdventureCountIncrease(); } - else if(sr->type == Adventure_Assassinate) - { - if(sr->data_id == GetNPCTypeID()) - { + else if (sr->type == Adventure_Assassinate) { + if (sr->data_id == GetNPCTypeID()) { zone->DoAdventureCountIncrease(); } - else - { + else { zone->DoAdventureAssassinationCountIncrease(); } } } } - else + else { entity_list.RemoveFromXTargets(this); + } /* Web Interface: Entity Death */ if (RemoteCallSubscriptionHandler::Instance()->IsSubscribed("Entity.Events")) { @@ -2398,37 +2235,46 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack } // Parse quests even if we're killed by an NPC - if(oos) { + if (oos) { mod_npc_killed(oos); uint16 emoteid = this->GetEmoteID(); - if(emoteid != 0) + if (emoteid != 0) this->DoNPCEmote(ONDEATH, emoteid); - if(oos->IsNPC()) - { + if (oos->IsNPC()) { parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0); uint16 emoteid = oos->GetEmoteID(); - if(emoteid != 0) + if (emoteid != 0) oos->CastToNPC()->DoNPCEmote(KILLEDNPC, emoteid); - killerMob->TrySpellOnKill(killed_level, spell); + killer_mob->TrySpellOnKill(killed_level, spell); } } WipeHateList(); p_depop = true; - if(killerMob && killerMob->GetTarget() == this) //we can kill things without having them targeted - killerMob->SetTarget(nullptr); //via AE effects and such.. + + if (killer_mob && killer_mob->GetTarget() == this) //we can kill things without having them targeted + killer_mob->SetTarget(nullptr); //via AE effects and such.. entity_list.UpdateFindableNPCState(this, true); char buffer[48] = { 0 }; - snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast(attack_skill)); + snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast(attack_skill)); parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, buffer, 0); - + + /* Zone controller process EVENT_DEATH_ZONE (Death events) */ + if (RuleB(Zone, UseZoneController)) { + if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && this->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID) { + char data_pass[100] = { 0 }; + snprintf(data_pass, 99, "%d %d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast(attack_skill), this->GetNPCTypeID()); + parse->EventNPC(EVENT_DEATH_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0); + } + } + return true; } -void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/) +void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/, uint16 spell_id) { if(!other) return; @@ -2440,24 +2286,35 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b hate = 1; } + if (iYellForHelp) + SetPrimaryAggro(true); + else + SetAssistAggro(true); + bool wasengaged = IsEngaged(); Mob* owner = other->GetOwner(); - Mob* mypet = this->GetPet(); + Mob* mypet = this->GetPet(); Mob* myowner = this->GetOwner(); Mob* targetmob = this->GetTarget(); if(other){ + bool on_hatelist = CheckAggro(other); AddRampage(other); - int hatemod = 100 + other->spellbonuses.hatemod + other->itembonuses.hatemod + other->aabonuses.hatemod; + if (on_hatelist) { // odd reason, if you're not on the hate list, subtlety etc don't apply! + // Spell Casting Subtlety etc + int hatemod = 100 + other->spellbonuses.hatemod + other->itembonuses.hatemod + other->aabonuses.hatemod; - int32 shieldhatemod = other->spellbonuses.ShieldEquipHateMod + other->itembonuses.ShieldEquipHateMod + other->aabonuses.ShieldEquipHateMod; + int32 shieldhatemod = other->spellbonuses.ShieldEquipHateMod + other->itembonuses.ShieldEquipHateMod + other->aabonuses.ShieldEquipHateMod; - if (shieldhatemod && other->HasShieldEquiped()) - hatemod += shieldhatemod; + if (shieldhatemod && other->HasShieldEquiped()) + hatemod += shieldhatemod; - if(hatemod < 1) - hatemod = 1; - hate = ((hate * (hatemod))/100); + if(hatemod < 1) + hatemod = 1; + hate = ((hate * (hatemod))/100); + } else { + hate += 100; // 100 bonus initial aggro + } } if(IsPet() && GetOwner() && GetOwner()->GetAA(aaPetDiscipline) && IsHeld() && !IsFocused()) { //ignore aggro if hold and !focus @@ -2478,6 +2335,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b if(IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO)) return; + if (spell_id != SPELL_UNKNOWN && NoDetrimentalSpellAggro(spell_id)) + return; + if (other == myowner) return; @@ -2636,9 +2496,9 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) { } DS -= DS * attacker->itembonuses.DSMitigation / 100; } - attacker->Damage(this, -DS, spellid, SkillAbjuration/*hackish*/, false); + attacker->Damage(this, -DS, spellid, EQEmu::skills::SkillAbjuration/*hackish*/, false); //we can assume there is a spell now - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); + auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); CombatDamage_Struct* cds = (CombatDamage_Struct*)outapp->pBuffer; cds->target = attacker->GetID(); cds->source = GetID(); @@ -2663,481 +2523,173 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) { if(rev_ds < 0) { Log.Out(Logs::Detail, Logs::Combat, "Applying Reverse Damage Shield of value %d to %s", rev_ds, attacker->GetName()); - attacker->Damage(this, -rev_ds, rev_ds_spell_id, SkillAbjuration/*hackish*/, false); //"this" (us) will get the hate, etc. not sure how this works on Live, but it'll works for now, and tanks will love us for this + attacker->Damage(this, -rev_ds, rev_ds_spell_id, EQEmu::skills::SkillAbjuration/*hackish*/, false); //"this" (us) will get the hate, etc. not sure how this works on Live, but it'll works for now, and tanks will love us for this //do we need to send a damage packet here also? } } -uint8 Mob::GetWeaponDamageBonus( const Item_Struct *Weapon ) +uint8 Mob::GetWeaponDamageBonus(const EQEmu::ItemBase *weapon, bool offhand) { - // This function calculates and returns the damage bonus for the weapon identified by the parameter "Weapon". - // Modified 9/21/2008 by Cantus - - // Assert: This function should only be called for hits by the mainhand, as damage bonuses apply only to the - // weapon in the primary slot. Be sure to check that Hand == MainPrimary before calling. - - // Assert: The caller should ensure that Weapon is actually a weapon before calling this function. - // The ItemInst::IsWeapon() method can be used to quickly determine this. - - // Assert: This function should not be called if the player's level is below 28, as damage bonuses do not begin - // to apply until level 28. - - // Assert: This function should not be called unless the player is a melee class, as casters do not receive a damage bonus. - - if( Weapon == nullptr || Weapon->ItemType == ItemType1HSlash || Weapon->ItemType == ItemType1HBlunt || Weapon->ItemType == ItemTypeMartial || Weapon->ItemType == ItemType1HPiercing ) - { - // The weapon in the player's main (primary) hand is a one-handed weapon, or there is no item equipped at all. - // - // According to player posts on Allakhazam, 1H damage bonuses apply to bare fists (nothing equipped in the mainhand, - // as indicated by Weapon == nullptr). - // - // The following formula returns the correct damage bonus for all 1H weapons: - - return (uint8) ((GetLevel() - 25) / 3); - } - - // If we've gotten to this point, the weapon in the mainhand is a two-handed weapon. - // Calculating damage bonuses for 2H weapons is more complicated, as it's based on PC level AND the delay of the weapon. - // The formula to calculate 2H bonuses is HIDEOUS. It's a huge conglomeration of ternary operators and multiple operations. + // dev quote with old and new formulas + // https://forums.daybreakgames.com/eq/index.php?threads/test-update-09-17-15.226618/page-5#post-3326194 // - // The following is a hybrid approach. In cases where the Level and Delay merit a formula that does not use many operators, - // the formula is used. In other cases, lookup tables are used for speed. - // Though the following code may look bloated and ridiculous, it's actually a very efficient way of calculating these bonuses. + // We assume that the level check is done before calling this function and sinister strikes is checked before + // calling for offhand DB + auto level = GetLevel(); + if (!weapon) + return 1 + ((level - 28) / 3); // how does weaponless scale? - // Player Level is used several times in the code below, so save it into a variable. - // If GetLevel() were an ordinary function, this would DEFINITELY make sense, as it'd cut back on all of the function calling - // overhead involved with multiple calls to GetLevel(). But in this case, GetLevel() is a simple, inline accessor method. - // So it probably doesn't matter. If anyone knows for certain that there is no overhead involved with calling GetLevel(), - // as I suspect, then please feel free to delete the following line, and replace all occurences of "ucPlayerLevel" with "GetLevel()". - uint8 ucPlayerLevel = (uint8) GetLevel(); - - // The following may look cleaner, and would certainly be easier to understand, if it was - // a simple 53x150 cell matrix. - // - // However, that would occupy 7,950 Bytes of memory (7.76 KB), and would likely result - // in "thrashing the cache" when performing lookups. - // - // Initially, I thought the best approach would be to reverse-engineer the formula used by - // Sony/Verant to calculate these 2H weapon damage bonuses. But the more than Reno and I - // worked on figuring out this formula, the more we're concluded that the formula itself ugly - // (that is, it contains so many operations and conditionals that it's fairly CPU intensive). - // Because of that, we're decided that, in most cases, a lookup table is the most efficient way - // to calculate these damage bonuses. - // - // The code below is a hybrid between a pure formulaic approach and a pure, brute-force - // lookup table. In cases where a formula is the best bet, I use a formula. In other places - // where a formula would be ugly, I use a lookup table in the interests of speed. - - if( Weapon->Delay <= 27 ) - { - // Damage Bonuses for all 2H weapons with delays of 27 or less are identical. - // They are the same as the damage bonus would be for a corresponding 1H weapon, plus one. - // This formula applies to all levels 28-80, and will probably continue to apply if - - // the level cap on Live ever is increased beyond 80. - - return (ucPlayerLevel - 22) / 3; - } - - if( ucPlayerLevel == 65 && Weapon->Delay <= 59 ) - { - // Consider these two facts: - // * Level 65 is the maximum level on many EQ Emu servers. - // * If you listed the levels of all characters logged on to a server, odds are that the number you'll - // see most frequently is level 65. That is, there are more level 65 toons than any other single level. - // - // Therefore, if we can optimize this function for level 65 toons, we're speeding up the server! - // - // With that goal in mind, I create an array of Damage Bonuses for level 65 characters wielding 2H weapons with - // delays between 28 and 59 (inclusive). I suspect that this one small lookup array will therefore handle - // many of the calls to this function. - - static const uint8 ucLevel65DamageBonusesForDelays28to59[] = {35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 42, 42, 42, 45, 45, 47, 48, 49, 49, 51, 51, 52, 53, 54, 54, 56, 56, 57, 58, 59}; - - return ucLevel65DamageBonusesForDelays28to59[Weapon->Delay-28]; - } - - if( ucPlayerLevel > 65 ) - { - if( ucPlayerLevel > 80 ) - { - // As level 80 is currently the highest achievable level on Live, we only include - // damage bonus information up to this level. - // - // If there is a custom EQEmu server that allows players to level beyond 80, the - // damage bonus for their 2H weapons will simply not increase beyond their damage - // bonus at level 80. - - ucPlayerLevel = 80; + auto delay = weapon->Delay; + if (weapon->IsType1HWeapon() || weapon->ItemType == EQEmu::item::ItemTypeMartial) { + // we assume sinister strikes is checked before calling here + if (!offhand) { + if (delay <= 39) + return 1 + ((level - 28) / 3); + else if (delay < 43) + return 2 + ((level - 28) / 3) + ((delay - 40) / 3); + else if (delay < 45) + return 3 + ((level - 28) / 3) + ((delay - 40) / 3); + else if (delay >= 45) + return 4 + ((level - 28) / 3) + ((delay - 40) / 3); + } else { + return 1 + ((level - 40) / 3) * (delay / 30); // YOOO shit's useless waste of AAs } - - // Lucy does not list a chart of damage bonuses for players levels 66+, - // so my original version of this function just applied the level 65 damage - // bonus for level 66+ toons. That sucked for higher level toons, as their - // 2H weapons stopped ramping up in DPS as they leveled past 65. - // - // Thanks to the efforts of two guys, this is no longer the case: - // - // Janusd (Zetrakyl) ran a nifty query against the PEQ item database to list - // the name of an example 2H weapon that represents each possible unique 2H delay. - // - // Romai then wrote an excellent script to automatically look up each of those - // weapons, open the Lucy item page associated with it, and iterate through all - // levels in the range 66 - 80. He saved the damage bonus for that weapon for - // each level, and that forms the basis of the lookup tables below. - - if( Weapon->Delay <= 59 ) - { - static const uint8 ucDelay28to59Levels66to80[32][15]= - { - /* Level: */ - /* 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 */ - - {36, 37, 38, 39, 41, 42, 43, 44, 45, 47, 49, 49, 49, 50, 53}, /* Delay = 28 */ - {36, 38, 38, 39, 42, 43, 43, 45, 46, 48, 49, 50, 51, 52, 54}, /* Delay = 29 */ - {37, 38, 39, 40, 43, 43, 44, 46, 47, 48, 50, 51, 52, 53, 55}, /* Delay = 30 */ - {37, 39, 40, 40, 43, 44, 45, 46, 47, 49, 51, 52, 52, 52, 54}, /* Delay = 31 */ - {38, 39, 40, 41, 44, 45, 45, 47, 48, 48, 50, 52, 53, 55, 57}, /* Delay = 32 */ - {38, 40, 41, 41, 44, 45, 46, 48, 49, 50, 52, 53, 54, 56, 58}, /* Delay = 33 */ - {39, 40, 41, 42, 45, 46, 47, 48, 49, 51, 53, 54, 55, 57, 58}, /* Delay = 34 */ - {39, 41, 42, 43, 46, 46, 47, 49, 50, 52, 54, 55, 56, 57, 59}, /* Delay = 35 */ - {40, 41, 42, 43, 46, 47, 48, 50, 51, 53, 55, 55, 56, 58, 60}, /* Delay = 36 */ - {40, 42, 43, 44, 47, 48, 49, 50, 51, 53, 55, 56, 57, 59, 61}, /* Delay = 37 */ - {41, 42, 43, 44, 47, 48, 49, 51, 52, 54, 56, 57, 58, 60, 62}, /* Delay = 38 */ - {41, 43, 44, 45, 48, 49, 50, 52, 53, 55, 57, 58, 59, 61, 63}, /* Delay = 39 */ - {43, 45, 46, 47, 50, 51, 52, 54, 55, 57, 59, 60, 61, 63, 65}, /* Delay = 40 */ - {43, 45, 46, 47, 50, 51, 52, 54, 55, 57, 59, 60, 61, 63, 65}, /* Delay = 41 */ - {44, 46, 47, 48, 51, 52, 53, 55, 56, 58, 60, 61, 62, 64, 66}, /* Delay = 42 */ - {46, 48, 49, 50, 53, 54, 55, 58, 59, 61, 63, 64, 65, 67, 69}, /* Delay = 43 */ - {47, 49, 50, 51, 54, 55, 56, 58, 59, 61, 64, 65, 66, 68, 70}, /* Delay = 44 */ - {48, 50, 51, 52, 56, 57, 58, 60, 61, 63, 65, 66, 68, 70, 72}, /* Delay = 45 */ - {50, 52, 53, 54, 57, 58, 59, 62, 63, 65, 67, 68, 69, 71, 74}, /* Delay = 46 */ - {50, 52, 53, 55, 58, 59, 60, 62, 63, 66, 68, 69, 70, 72, 74}, /* Delay = 47 */ - {51, 53, 54, 55, 58, 60, 61, 63, 64, 66, 69, 69, 71, 73, 75}, /* Delay = 48 */ - {52, 54, 55, 57, 60, 61, 62, 65, 66, 68, 70, 71, 73, 75, 77}, /* Delay = 49 */ - {53, 55, 56, 57, 61, 62, 63, 65, 67, 69, 71, 72, 74, 76, 78}, /* Delay = 50 */ - {53, 55, 57, 58, 61, 62, 64, 66, 67, 69, 72, 73, 74, 77, 79}, /* Delay = 51 */ - {55, 57, 58, 59, 63, 64, 65, 68, 69, 71, 74, 75, 76, 78, 81}, /* Delay = 52 */ - {57, 55, 59, 60, 63, 65, 66, 68, 70, 72, 74, 76, 77, 79, 82}, /* Delay = 53 */ - {56, 58, 59, 61, 64, 65, 67, 69, 70, 73, 75, 76, 78, 80, 82}, /* Delay = 54 */ - {57, 59, 61, 62, 66, 67, 68, 71, 72, 74, 77, 78, 80, 82, 84}, /* Delay = 55 */ - {58, 60, 61, 63, 66, 68, 69, 71, 73, 75, 78, 79, 80, 83, 85}, /* Delay = 56 */ - - /* Important Note: Janusd's search for 2H weapons did not find */ - /* any 2H weapon with a delay of 57. Therefore the values below */ - /* are interpolated, not exact! */ - {59, 61, 62, 64, 67, 69, 70, 72, 74, 76, 77, 78, 81, 84, 86}, /* Delay = 57 INTERPOLATED */ - - {60, 62, 63, 65, 68, 70, 71, 74, 75, 78, 80, 81, 83, 85, 88}, /* Delay = 58 */ - - /* Important Note: Janusd's search for 2H weapons did not find */ - /* any 2H weapon with a delay of 59. Therefore the values below */ - /* are interpolated, not exact! */ - {60, 62, 64, 65, 69, 70, 72, 74, 76, 78, 81, 82, 84, 86, 89}, /* Delay = 59 INTERPOLATED */ - }; - - return ucDelay28to59Levels66to80[Weapon->Delay-28][ucPlayerLevel-66]; - } - else - { - // Delay is 60+ - - const static uint8 ucDelayOver59Levels66to80[6][15] = - { - /* Level: */ - /* 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 */ - - {61, 63, 65, 66, 70, 71, 73, 75, 77, 79, 82, 83, 85, 87, 90}, /* Delay = 60 */ - {65, 68, 69, 71, 75, 76, 78, 80, 82, 85, 87, 89, 91, 93, 96}, /* Delay = 65 */ - - /* Important Note: Currently, the only 2H weapon with a delay */ - /* of 66 is not player equippable (it's None/None). So I'm */ - /* leaving it commented out to keep this table smaller. */ - //{66, 68, 70, 71, 75, 77, 78, 81, 83, 85, 88, 90, 91, 94, 97}, /* Delay = 66 */ - - {70, 72, 74, 76, 80, 81, 83, 86, 88, 88, 90, 95, 97, 99, 102}, /* Delay = 70 */ - {82, 85, 87, 89, 89, 94, 98, 101, 103, 106, 109, 111, 114, 117, 120}, /* Delay = 85 */ - {90, 93, 96, 98, 103, 105, 107, 111, 113, 116, 120, 122, 125, 128, 131}, /* Delay = 95 */ - - /* Important Note: Currently, the only 2H weapons with delay */ - /* 100 are GM-only items purchased from vendors in Sunset Home */ - /* (cshome). Because they are highly unlikely to be used in */ - /* combat, I'm commenting it out to keep the table smaller. */ - //{95, 98, 101, 103, 108, 110, 113, 116, 119, 122, 126, 128, 131, 134, 138},/* Delay = 100 */ - - {136, 140, 144, 148, 154, 157, 161, 166, 170, 174, 179, 183, 187, 191, 196} /* Delay = 150 */ - }; - - if( Weapon->Delay < 65 ) - { - return ucDelayOver59Levels66to80[0][ucPlayerLevel-66]; - } - else if( Weapon->Delay < 70 ) - { - return ucDelayOver59Levels66to80[1][ucPlayerLevel-66]; - } - else if( Weapon->Delay < 85 ) - { - return ucDelayOver59Levels66to80[2][ucPlayerLevel-66]; - } - else if( Weapon->Delay < 95 ) - { - return ucDelayOver59Levels66to80[3][ucPlayerLevel-66]; - } - else if( Weapon->Delay < 150 ) - { - return ucDelayOver59Levels66to80[4][ucPlayerLevel-66]; - } - else - { - return ucDelayOver59Levels66to80[5][ucPlayerLevel-66]; + } else { + // 2h damage bonus + int damage_bonus = 1 + (level - 28) / 3; + if (delay <= 27) + return damage_bonus + 1; + // Client isn't reflecting what the dev quoted, this matches better + if (level > 29) { + int level_bonus = (level - 30) / 5 + 1; + if (level > 50) { + level_bonus++; + int level_bonus2 = level - 50; + if (level > 67) + level_bonus2 += 5; + else if (level > 59) + level_bonus2 += 4; + else if (level > 58) + level_bonus2 += 3; + else if (level > 56) + level_bonus2 += 2; + else if (level > 54) + level_bonus2++; + level_bonus += level_bonus2 * delay / 40; } + damage_bonus += level_bonus; } - } - - // If we've gotten to this point in the function without hitting a return statement, - // we know that the character's level is between 28 and 65, and that the 2H weapon's - // delay is 28 or higher. - - // The Damage Bonus values returned by this function (in the level 28-65 range) are - // based on a table of 2H Weapon Damage Bonuses provided by Lucy at the following address: - // http://lucy.allakhazam.com/dmgbonus.html - - if( Weapon->Delay <= 39 ) - { - if( ucPlayerLevel <= 53) - { - // The Damage Bonus for all 2H weapons with delays between 28 and 39 (inclusive) is the same for players level 53 and below... - static const uint8 ucDelay28to39LevelUnder54[] = {1, 1, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 8, 8, 8, 9, 9, 10, 11, 11, 11, 12, 13, 14, 16, 17}; - - // As a note: The following formula accurately calculates damage bonuses for 2H weapons with delays in the range 28-39 (inclusive) - // for characters levels 28-50 (inclusive): - // return ( (ucPlayerLevel - 22) / 3 ) + ( (ucPlayerLevel - 25) / 5 ); - // - // However, the small lookup array used above is actually much faster. So we'll just use it instead of the formula - // - // (Thanks to Reno for helping figure out the above formula!) - - return ucDelay28to39LevelUnder54[ucPlayerLevel-28]; - } - else - { - // Use a matrix to look up the damage bonus for 2H weapons with delays between 28 and 39 wielded by characters level 54 and above. - static const uint8 ucDelay28to39Level54to64[12][11] = - { - /* Level: */ - /* 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 */ - - {17, 21, 21, 23, 25, 26, 28, 30, 31, 31, 33}, /* Delay = 28 */ - {17, 21, 22, 23, 25, 26, 29, 30, 31, 32, 34}, /* Delay = 29 */ - {18, 21, 22, 23, 25, 27, 29, 31, 32, 32, 34}, /* Delay = 30 */ - {18, 21, 22, 23, 25, 27, 29, 31, 32, 33, 34}, /* Delay = 31 */ - {18, 21, 22, 24, 26, 27, 30, 32, 32, 33, 35}, /* Delay = 32 */ - {18, 21, 22, 24, 26, 27, 30, 32, 33, 34, 35}, /* Delay = 33 */ - {18, 22, 22, 24, 26, 28, 30, 32, 33, 34, 36}, /* Delay = 34 */ - {18, 22, 23, 24, 26, 28, 31, 33, 34, 34, 36}, /* Delay = 35 */ - {18, 22, 23, 25, 27, 28, 31, 33, 34, 35, 37}, /* Delay = 36 */ - {18, 22, 23, 25, 27, 29, 31, 33, 34, 35, 37}, /* Delay = 37 */ - {18, 22, 23, 25, 27, 29, 32, 34, 35, 36, 38}, /* Delay = 38 */ - {18, 22, 23, 25, 27, 29, 32, 34, 35, 36, 38} /* Delay = 39 */ - }; - - return ucDelay28to39Level54to64[Weapon->Delay-28][ucPlayerLevel-54]; - } - } - else if( Weapon->Delay <= 59 ) - { - if( ucPlayerLevel <= 52 ) - { - if( Weapon->Delay <= 45 ) - { - static const uint8 ucDelay40to45Levels28to52[6][25] = - { - /* Level: */ - /* 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52 */ - - {2, 2, 3, 4, 4, 4, 5, 6, 6, 7, 7, 7, 9, 9, 9, 10, 10, 11, 12, 12, 12, 13, 14, 16, 18}, /* Delay = 40 */ - {2, 2, 3, 4, 4, 4, 5, 6, 6, 7, 7, 7, 9, 9, 9, 10, 10, 11, 12, 12, 12, 13, 14, 16, 18}, /* Delay = 41 */ - {2, 2, 3, 4, 4, 4, 5, 6, 6, 7, 7, 7, 9, 9, 9, 10, 10, 11, 12, 12, 12, 13, 14, 16, 18}, /* Delay = 42 */ - {4, 4, 5, 6, 6, 6, 7, 8, 8, 9, 9, 9, 11, 11, 11, 12, 12, 13, 14, 14, 14, 15, 16, 18, 20}, /* Delay = 43 */ - {4, 4, 5, 6, 6, 6, 7, 8, 8, 9, 9, 9, 11, 11, 11, 12, 12, 13, 14, 14, 14, 15, 16, 18, 20}, /* Delay = 44 */ - {5, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 10, 12, 12, 12, 13, 13, 14, 15, 15, 15, 16, 17, 19, 21} /* Delay = 45 */ - }; - - return ucDelay40to45Levels28to52[Weapon->Delay-40][ucPlayerLevel-28]; - } - else - { - static const uint8 ucDelay46Levels28to52[] = {6, 6, 7, 8, 8, 8, 9, 10, 10, 11, 11, 11, 13, 13, 13, 14, 14, 15, 16, 16, 16, 17, 18, 20, 22}; - - return ucDelay46Levels28to52[ucPlayerLevel-28] + ((Weapon->Delay-46) / 3); - } - } - else - { - // Player is in the level range 53 - 64 - - // Calculating damage bonus for 2H weapons with a delay between 40 and 59 (inclusive) involves, unforunately, a brute-force matrix lookup. - static const uint8 ucDelay40to59Levels53to64[20][37] = - { - /* Level: */ - /* 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 */ - - {19, 20, 24, 25, 27, 29, 31, 34, 36, 37, 38, 40}, /* Delay = 40 */ - {19, 20, 24, 25, 27, 29, 31, 34, 36, 37, 38, 40}, /* Delay = 41 */ - {19, 20, 24, 25, 27, 29, 31, 34, 36, 37, 38, 40}, /* Delay = 42 */ - {21, 22, 26, 27, 29, 31, 33, 37, 39, 40, 41, 43}, /* Delay = 43 */ - {21, 22, 26, 27, 29, 32, 34, 37, 39, 40, 41, 43}, /* Delay = 44 */ - {22, 23, 27, 28, 31, 33, 35, 38, 40, 42, 43, 45}, /* Delay = 45 */ - {23, 24, 28, 30, 32, 34, 36, 40, 42, 43, 44, 46}, /* Delay = 46 */ - {23, 24, 29, 30, 32, 34, 37, 40, 42, 43, 44, 47}, /* Delay = 47 */ - {23, 24, 29, 30, 32, 35, 37, 40, 43, 44, 45, 47}, /* Delay = 48 */ - {24, 25, 30, 31, 34, 36, 38, 42, 44, 45, 46, 49}, /* Delay = 49 */ - {24, 26, 30, 31, 34, 36, 39, 42, 44, 46, 47, 49}, /* Delay = 50 */ - {24, 26, 30, 31, 34, 36, 39, 42, 45, 46, 47, 49}, /* Delay = 51 */ - {25, 27, 31, 33, 35, 38, 40, 44, 46, 47, 49, 51}, /* Delay = 52 */ - {25, 27, 31, 33, 35, 38, 40, 44, 46, 48, 49, 51}, /* Delay = 53 */ - {26, 27, 32, 33, 36, 38, 41, 44, 47, 48, 49, 52}, /* Delay = 54 */ - {27, 28, 33, 34, 37, 39, 42, 46, 48, 50, 51, 53}, /* Delay = 55 */ - {27, 28, 33, 34, 37, 40, 42, 46, 49, 50, 51, 54}, /* Delay = 56 */ - {27, 28, 33, 34, 37, 40, 43, 46, 49, 50, 52, 54}, /* Delay = 57 */ - {28, 29, 34, 36, 39, 41, 44, 48, 50, 52, 53, 56}, /* Delay = 58 */ - {28, 29, 34, 36, 39, 41, 44, 48, 51, 52, 54, 56} /* Delay = 59 */ - }; - - return ucDelay40to59Levels53to64[Weapon->Delay-40][ucPlayerLevel-53]; - } - } - else - { - // The following table allows us to look up Damage Bonuses for weapons with delays greater than or equal to 60. - // - // There aren't a lot of 2H weapons with a delay greater than 60. In fact, both a database and Lucy search run by janusd confirm - // that the only unique 2H delays greater than 60 are: 65, 70, 85, 95, and 150. - // - // To be fair, there are also weapons with delays of 66 and 100. But they are either not equippable (None/None), or are - // only available to GMs from merchants in Sunset Home (cshome). In order to keep this table "lean and mean", I will not - // include the values for delays 66 and 100. If they ever are wielded, the 66 delay weapon will use the 65 delay bonuses, - // and the 100 delay weapon will use the 95 delay bonuses. So it's not a big deal. - // - // Still, if someone in the future decides that they do want to include them, here are the tables for these two delays: - // - // {12, 12, 13, 14, 14, 14, 15, 16, 16, 17, 17, 17, 19, 19, 19, 20, 20, 21, 22, 22, 22, 23, 24, 26, 29, 30, 32, 37, 39, 42, 45, 48, 53, 55, 57, 59, 61, 64} /* Delay = 66 */ - // {24, 24, 25, 26, 26, 26, 27, 28, 28, 29, 29, 29, 31, 31, 31, 32, 32, 33, 34, 34, 34, 35, 36, 39, 43, 45, 48, 55, 57, 62, 66, 71, 77, 80, 83, 85, 89, 92} /* Delay = 100 */ - // - // In case there are 2H weapons added in the future with delays other than those listed above (and until the damage bonuses - // associated with that new delay are added to this function), this function is designed to do the following: - // - // For weapons with delays in the range 60-64, use the Damage Bonus that would apply to a 2H weapon with delay 60. - // For weapons with delays in the range 65-69, use the Damage Bonus that would apply to a 2H weapon with delay 65 - // For weapons with delays in the range 70-84, use the Damage Bonus that would apply to a 2H weapon with delay 70. - // For weapons with delays in the range 85-94, use the Damage Bonus that would apply to a 2H weapon with delay 85. - // For weapons with delays in the range 95-149, use the Damage Bonus that would apply to a 2H weapon with delay 95. - // For weapons with delays 150 or higher, use the Damage Bonus that would apply to a 2H weapon with delay 150. - - static const uint8 ucDelayOver59Levels28to65[6][38] = - { - /* Level: */ - /* 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64. 65 */ - - {10, 10, 11, 12, 12, 12, 13, 14, 14, 15, 15, 15, 17, 17, 17, 18, 18, 19, 20, 20, 20, 21, 22, 24, 27, 28, 30, 35, 36, 39, 42, 45, 49, 51, 53, 54, 57, 59}, /* Delay = 60 */ - {12, 12, 13, 14, 14, 14, 15, 16, 16, 17, 17, 17, 19, 19, 19, 20, 20, 21, 22, 22, 22, 23, 24, 26, 29, 30, 32, 37, 39, 42, 45, 48, 52, 55, 57, 58, 61, 63}, /* Delay = 65 */ - {14, 14, 15, 16, 16, 16, 17, 18, 18, 19, 19, 19, 21, 21, 21, 22, 22, 23, 24, 24, 24, 25, 26, 28, 31, 33, 35, 40, 42, 45, 48, 52, 56, 59, 61, 62, 65, 68}, /* Delay = 70 */ - {19, 19, 20, 21, 21, 21, 22, 23, 23, 24, 24, 24, 26, 26, 26, 27, 27, 28, 29, 29, 29, 30, 31, 34, 37, 39, 41, 47, 49, 54, 57, 61, 66, 69, 72, 74, 77, 80}, /* Delay = 85 */ - {22, 22, 23, 24, 24, 24, 25, 26, 26, 27, 27, 27, 29, 29, 29, 30, 30, 31, 32, 32, 32, 33, 34, 37, 40, 43, 45, 52, 54, 59, 62, 67, 73, 76, 79, 81, 84, 88}, /* Delay = 95 */ - {40, 40, 41, 42, 42, 42, 43, 44, 44, 45, 45, 45, 47, 47, 47, 48, 48, 49, 50, 50, 50, 51, 52, 56, 61, 65, 69, 78, 82, 89, 94, 102, 110, 115, 119, 122, 127, 132} /* Delay = 150 */ - }; - - if( Weapon->Delay < 65 ) - { - return ucDelayOver59Levels28to65[0][ucPlayerLevel-28]; - } - else if( Weapon->Delay < 70 ) - { - return ucDelayOver59Levels28to65[1][ucPlayerLevel-28]; - } - else if( Weapon->Delay < 85 ) - { - return ucDelayOver59Levels28to65[2][ucPlayerLevel-28]; - } - else if( Weapon->Delay < 95 ) - { - return ucDelayOver59Levels28to65[3][ucPlayerLevel-28]; - } - else if( Weapon->Delay < 150 ) - { - return ucDelayOver59Levels28to65[4][ucPlayerLevel-28]; - } - else - { - return ucDelayOver59Levels28to65[5][ucPlayerLevel-28]; + if (delay >= 40) { + int delay_bonus = (delay - 40) / 3 + 1; + if (delay >= 45) + delay_bonus += 2; + else if (delay >= 43) + delay_bonus++; + damage_bonus += delay_bonus; } + return damage_bonus; } } -int Mob::GetMonkHandToHandDamage(void) +int Mob::GetHandToHandDamage(void) { - // Kaiyodo - Determine a monk's fist damage. Table data from www.monkly-business.com - // saved as static array - this should speed this function up considerably - static int damage[66] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - 99, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11, - 12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14, - 14,14,15,15,15,15 }; - - // Have a look to see if we have epic fists on - - if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652) - return(9); - else - { - int Level = GetLevel(); - if (Level > 65) - return(19); - else - return damage[Level]; + if (RuleB(Combat, UseRevampHandToHand)) { + // everyone uses this in the revamp! + int skill = GetSkill(EQEmu::skills::SkillHandtoHand); + int epic = 0; + if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 46) + epic = 280; + if (epic > skill) + skill = epic; + return skill / 15 + 3; } + + static uint8 mnk_dmg[] = {99, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, // 1-10 + 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, // 11-20 + 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, // 21-30 + 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, // 31-40 + 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, // 41-50 + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, // 51-60 + 14, 14}; // 61-62 + static uint8 bst_dmg[] = {99, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, // 1-10 + 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, // 11-20 + 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30 + 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40 + 10, 11, 11, 11, 11, 11, 11, 12, 12}; // 41-49 + if (GetClass() == MONK) { + if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50) + return 9; + if (level > 62) + return 15; + return mnk_dmg[level]; + } else if (GetClass() == BEASTLORD) { + if (level > 49) + return 13; + return bst_dmg[level]; + } + return 2; } -int Mob::GetMonkHandToHandDelay(void) +int Mob::GetHandToHandDelay(void) { - // Kaiyodo - Determine a monk's fist delay. Table data from www.monkly-business.com - // saved as static array - this should speed this function up considerably - static int delayshuman[66] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - 99,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,35,35,35,35,35,34,34,34,34,34,33,33,33,33,33, - 32,32,32,32,32,31,31,31,31,31,30,30,30,29,29,29,28,28,28,27, - 26,24,22,20,20,20 }; - static int delaysiksar[66] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - 99,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,36,36,36,36,36,35,35,35,35,35,34,34,34,34,34, - 33,33,33,33,33,32,32,32,32,32,31,31,31,30,30,30,29,29,29,28, - 27,24,22,20,20,20 }; - - // Have a look to see if we have epic fists on - if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652) - return(16); - else - { - int Level = GetLevel(); - if (GetRace() == HUMAN) - { - if (Level > 65) - return(24); - else - return delayshuman[Level]; - } - else //heko: iksar table - { - if (Level > 65) - return(25); - else - return delaysiksar[Level]; - } + if (RuleB(Combat, UseRevampHandToHand)) { + // everyone uses this in the revamp! + int skill = GetSkill(EQEmu::skills::SkillHandtoHand); + int epic = 0; + int iksar = 0; + if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 46) + epic = 280; + else if (GetRace() == IKSAR) + iksar = 1; + if (epic > skill) + skill = epic; + return iksar - skill / 21 + 38; } + + int delay = 35; + static uint8 mnk_hum_delay[] = {99, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10 + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20 + 35, 35, 35, 35, 35, 35, 35, 34, 34, 34, // 21-30 + 34, 33, 33, 33, 33, 32, 32, 32, 32, 31, // 31-40 + 31, 31, 31, 30, 30, 30, 30, 29, 29, 29, // 41-50 + 29, 28, 28, 28, 28, 27, 27, 27, 27, 26, // 51-60 + 24, 22}; // 61-62 + static uint8 mnk_iks_delay[] = {99, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10 + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20 + 35, 35, 35, 35, 35, 35, 35, 35, 35, 34, // 21-30 + 34, 34, 34, 34, 34, 33, 33, 33, 33, 33, // 31-40 + 33, 32, 32, 32, 32, 32, 32, 31, 31, 31, // 41-50 + 31, 31, 31, 30, 30, 30, 30, 30, 30, 29, // 51-60 + 25, 23}; // 61-62 + static uint8 bst_delay[] = {99, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10 + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20 + 35, 35, 35, 35, 35, 35, 35, 35, 34, 34, // 21-30 + 34, 34, 34, 33, 33, 33, 33, 33, 32, 32, // 31-40 + 32, 32, 32, 31, 31, 31, 31, 31, 30, 30, // 41-50 + 30, 30, 30, 29, 29, 29, 29, 29, 28, 28, // 51-60 + 28, 28, 28, 27, 27, 27, 27, 27, 26, 26, // 61-70 + 26, 26, 26}; // 71-73 + + if (GetClass() == MONK) { + // Have a look to see if we have epic fists on + if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50) + return 16; + int level = GetLevel(); + if (level > 62) + return GetRace() == IKSAR ? 21 : 20; + return GetRace() == IKSAR ? mnk_iks_delay[level] : mnk_hum_delay[level]; + } else if (GetClass() == BEASTLORD) { + int level = GetLevel(); + if (level > 73) + return 25; + return bst_delay[level]; + } + return 35; } int32 Mob::ReduceDamage(int32 damage) @@ -3424,41 +2976,39 @@ bool Mob::HasRangedProcs() const return false; } -bool Client::CheckDoubleAttack(bool tripleAttack) { - +bool Client::CheckDoubleAttack() +{ + int chance = 0; + int skill = GetSkill(EQEmu::skills::SkillDoubleAttack); //Check for bonuses that give you a double attack chance regardless of skill (ie Bestial Frenzy/Harmonious Attack AA) - uint32 bonusGiveDA = aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack; - - if(!HasSkill(SkillDoubleAttack) && !bonusGiveDA) + int bonusGiveDA = aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack; + if (skill > 0) + chance = skill + GetLevel(); + else if (!bonusGiveDA) return false; - float chance = 0.0f; + if (bonusGiveDA) + chance += bonusGiveDA / 100.0f * 500; // convert to skill value + int per_inc = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance; + if (per_inc) + chance += chance * per_inc / 100; - uint16 skill = GetSkill(SkillDoubleAttack); + return zone->random.Int(1, 500) <= chance; +} - int32 bonusDA = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance; +// Admittedly these parses were short, but this check worked for 3 toons across multiple levels +// with varying triple attack skill (1-3% error at least) +bool Client::CheckTripleAttack() +{ + int chance = GetSkill(EQEmu::skills::SkillTripleAttack); + if (chance < 1) + return false; - //Use skill calculations otherwise, if you only have AA applied GiveDoubleAttack chance then use that value as the base. - if (skill) - chance = (float(skill+GetLevel()) * (float(100.0f+bonusDA+bonusGiveDA) /100.0f)) /500.0f; - else - chance = (float(bonusGiveDA) * (float(100.0f+bonusDA)/100.0f) ) /100.0f; + int per_inc = aabonuses.TripleAttackChance + spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance; + if (per_inc) + chance += chance * per_inc / 100; - //Live now uses a static Triple Attack skill (lv 46 = 2% lv 60 = 20%) - We do not have this skill on EMU ATM. - //A reasonable forumla would then be TA = 20% * chance - //AA's can also give triple attack skill over cap. (ie Burst of Power) NOTE: Skill ID in spell data is 76 (Triple Attack) - //Kayen: Need to decide if we can implement triple attack skill before working in over the cap effect. - if(tripleAttack) { - // Only some Double Attack classes get Triple Attack [This is already checked in client_processes.cpp] - int32 triple_bonus = spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance; - chance *= 0.2f; //Baseline chance is 20% of your double attack chance. - chance *= float(100.0f+triple_bonus)/100.0f; //Apply modifiers. - } - - if(zone->random.Roll(chance)) - return true; - - return false; + return zone->random.Int(1, 1000) <= chance; } bool Client::CheckDoubleRangedAttack() { @@ -3470,14 +3020,32 @@ bool Client::CheckDoubleRangedAttack() { return false; } -void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, const SkillUseTypes skill_used, bool &avoidable, const int8 buffslot, const bool iBuffTic) { +bool Mob::CheckDoubleAttack() +{ + // Not 100% certain pets follow this or if it's just from pets not always + // having the same skills as most mobs + int chance = GetSkill(EQEmu::skills::SkillDoubleAttack); + if (GetLevel() > 35) + chance += GetLevel(); + + int per_inc = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance; + if (per_inc) + chance += chance * per_inc / 100; + + return zone->random.Int(1, 500) <= chance; +} + +void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, const EQEmu::skills::SkillType skill_used, bool &avoidable, const int8 buffslot, const bool iBuffTic, int special) { // This method is called with skill_used=ABJURE for Damage Shield damage. - bool FromDamageShield = (skill_used == SkillAbjuration); + bool FromDamageShield = (skill_used == EQEmu::skills::SkillAbjuration); + bool ignore_invul = false; + if (IsValidSpell(spell_id)) + ignore_invul = spell_id == 982 || spells[spell_id].cast_not_standing; // cazic touch Log.Out(Logs::Detail, Logs::Combat, "Applying damage %d done by %s with skill %d and spell %d, avoidable? %s, is %sa buff tic in slot %d", damage, attacker?attacker->GetName():"NOBODY", skill_used, spell_id, avoidable?"yes":"no", iBuffTic?"":"not ", buffslot); - if (GetInvul() || DivineAura()) { + if (!ignore_invul && (GetInvul() || DivineAura())) { Log.Out(Logs::Detail, Logs::Combat, "Avoiding %d damage due to invulnerability.", damage); damage = -5; } @@ -3487,7 +3055,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons // only apply DS if physical damage (no spell damage) // damage shield calls this function with spell_id set, so its unavoidable - if (attacker && damage > 0 && spell_id == SPELL_UNKNOWN && skill_used != SkillArchery && skill_used != SkillThrowing) { + if (attacker && damage > 0 && spell_id == SPELL_UNKNOWN && skill_used != EQEmu::skills::SkillArchery && skill_used != EQEmu::skills::SkillThrowing) { DamageShield(attacker); } @@ -3503,28 +3071,20 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons if(!RuleB(Combat, EXPFromDmgShield)) { // Damage shield damage shouldn't count towards who gets EXP if(!attacker->CastToClient()->GetFeigned() && !FromDamageShield) - AddToHateList(attacker, 0, damage, true, false, iBuffTic); + AddToHateList(attacker, 0, damage, true, false, iBuffTic, spell_id); } else { if(!attacker->CastToClient()->GetFeigned()) - AddToHateList(attacker, 0, damage, true, false, iBuffTic); + AddToHateList(attacker, 0, damage, true, false, iBuffTic, spell_id); } } else - AddToHateList(attacker, 0, damage, true, false, iBuffTic); + AddToHateList(attacker, 0, damage, true, false, iBuffTic, spell_id); } if(damage > 0) { //if there is some damage being done and theres an attacker involved if(attacker) { - if(spell_id == SPELL_HARM_TOUCH2 && attacker->IsClient() && attacker->CastToClient()->CheckAAEffect(aaEffectLeechTouch)){ - int healed = damage; - healed = attacker->GetActSpellHealing(spell_id, healed); - attacker->HealDamage(healed); - entity_list.MessageClose(this, true, 300, MT_Emote, "%s beams a smile at %s", attacker->GetCleanName(), this->GetCleanName() ); - attacker->CastToClient()->DisableAAEffect(aaEffectLeechTouch); - } - // if spell is lifetap add hp to the caster if (spell_id != SPELL_UNKNOWN && IsLifetapSpell( spell_id )) { int healed = damage; @@ -3544,7 +3104,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons { if (!pet->IsHeld()) { Log.Out(Logs::Detail, Logs::Aggro, "Sending pet %s into battle due to attack.", pet->GetName()); - pet->AddToHateList(attacker, 1); + pet->AddToHateList(attacker, 1,0, true, false, false, spell_id); pet->SetTarget(attacker); Message_StringID(10, PET_ATTACKING, pet->GetCleanName(), attacker->GetCleanName()); } @@ -3588,6 +3148,9 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons SetHP(GetHP() - damage); + if (IsClient()) + this->CastToClient()->SendHPUpdateMarquee(); + if(HasDied()) { bool IsSaved = false; @@ -3617,67 +3180,63 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons BuffFadeByEffect(SE_Mez); } - //check stun chances if bashing - if (damage > 0 && ((skill_used == SkillBash || skill_used == SkillKick) && attacker)) { - // NPCs can stun with their bash/kick as soon as they receive it. - // Clients can stun mobs under level 56 with their kick when they get level 55 or greater. - // Clients have a chance to stun if the mob is 56+ - - // Calculate the chance to stun - int stun_chance = 0; - if (!GetSpecialAbility(UNSTUNABLE)) { - if (attacker->IsNPC()) { - stun_chance = RuleI(Combat, NPCBashKickStunChance); - } else if (attacker->IsClient()) { - // Less than base immunity - // Client vs. Client always uses the chance - if (!IsClient() && GetLevel() <= RuleI(Spells, BaseImmunityLevel)) { - if (skill_used == SkillBash) // Bash always will - stun_chance = 100; - else if (attacker->GetLevel() >= RuleI(Combat, ClientStunLevel)) - stun_chance = 100; // only if you're over level 55 and using kick - } else { // higher than base immunity or Client vs. Client - // not sure on this number, use same as NPC for now - if (skill_used == SkillKick && attacker->GetLevel() < RuleI(Combat, ClientStunLevel)) - stun_chance = RuleI(Combat, NPCBashKickStunChance); - else if (skill_used == SkillBash) - stun_chance = RuleI(Combat, NPCBashKickStunChance) + - attacker->spellbonuses.StunBashChance + - attacker->itembonuses.StunBashChance + - attacker->aabonuses.StunBashChance; - } - } + // broken up for readability + // This is based on what the client is doing + // We had a bunch of stuff like BaseImmunityLevel checks, which I think is suppose to just be for spells + // This is missing some merc checks, but those mostly just skipped the spell bonuses I think ... + bool can_stun = false; + int stunbash_chance = 0; // bonus + if (attacker) { + if (skill_used == EQEmu::skills::SkillBash) { + can_stun = true; + if (attacker->IsClient()) + stunbash_chance = attacker->spellbonuses.StunBashChance + + attacker->itembonuses.StunBashChance + + attacker->aabonuses.StunBashChance; + } else if (skill_used == EQEmu::skills::SkillKick && + (attacker->GetLevel() > 55 || attacker->IsNPC()) && GetClass() == WARRIOR) { + can_stun = true; } - if (stun_chance && zone->random.Roll(stun_chance)) { - // Passed stun, try to resist now - int stun_resist = itembonuses.StunResist + spellbonuses.StunResist; - int frontal_stun_resist = itembonuses.FrontalStunResist + spellbonuses.FrontalStunResist; - - Log.Out(Logs::Detail, Logs::Combat, "Stun passed, checking resists. Was %d chance.", stun_chance); - if (IsClient()) { - stun_resist += aabonuses.StunResist; - frontal_stun_resist += aabonuses.FrontalStunResist; - } - - // frontal stun check for ogres/bonuses - if (((GetBaseRace() == OGRE && IsClient()) || - (frontal_stun_resist && zone->random.Roll(frontal_stun_resist))) && - !attacker->BehindMob(this, attacker->GetX(), attacker->GetY())) { - Log.Out(Logs::Detail, Logs::Combat, "Frontal stun resisted. %d chance.", frontal_stun_resist); - } else { - // Normal stun resist check. - if (stun_resist && zone->random.Roll(stun_resist)) { + if ((GetBaseRace() == OGRE || GetBaseRace() == OGGOK_CITIZEN) && + !attacker->BehindMob(this, attacker->GetX(), attacker->GetY())) + can_stun = false; + if (GetSpecialAbility(UNSTUNABLE)) + can_stun = false; + } + if (can_stun) { + int bashsave_roll = zone->random.Int(0, 100); + if (bashsave_roll > 98 || bashsave_roll > (55 - stunbash_chance)) { + // did stun -- roll other resists + // SE_FrontalStunResist description says any angle now a days + int stun_resist2 = spellbonuses.FrontalStunResist + itembonuses.FrontalStunResist + + aabonuses.FrontalStunResist; + if (zone->random.Int(1, 100) > stun_resist2) { + // stun resist 2 failed + // time to check SE_StunResist and mod2 stun resist + int stun_resist = + spellbonuses.StunResist + itembonuses.StunResist + aabonuses.StunResist; + if (zone->random.Int(0, 100) >= stun_resist) { + // did stun + // nothing else to check! + Stun(2000); // straight 2 seconds every time + } else { + // stun resist passed! if (IsClient()) Message_StringID(MT_Stun, SHAKE_OFF_STUN); - Log.Out(Logs::Detail, Logs::Combat, "Stun Resisted. %d chance.", stun_resist); - } else { - Log.Out(Logs::Detail, Logs::Combat, "Stunned. %d resist chance.", stun_resist); - Stun(zone->random.Int(0, 2) * 1000); // 0-2 seconds } + } else { + // stun resist 2 passed! + if (IsClient()) + Message_StringID(MT_Stun, AVOID_STUNNING_BLOW); } } else { - Log.Out(Logs::Detail, Logs::Combat, "Stun failed. %d chance.", stun_chance); + // main stun failed -- extra interrupt roll + if (IsCasting() && + !EQEmu::ValueWithin(casting_spell_id, 859, 1023)) // these spells are excluded + // 90% chance >< -- stun immune won't reach this branch though :( + if (zone->random.Int(0, 9) > 1) + InterruptSpell(); } } @@ -3697,12 +3256,12 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons //send an HP update if we are hurt if(GetHP() < GetMaxHP()) - SendHPUpdate(); + SendHPUpdate(!iBuffTic); // the OP_Damage actually updates the client in these cases, so we skip the HP update for them } //end `if damage was done` //send damage packet... - if(!iBuffTic) { //buff ticks do not send damage, instead they just call SendHPUpdate(), which is done below - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); + if(!iBuffTic) { //buff ticks do not send damage, instead they just call SendHPUpdate(), which is done above + auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); CombatDamage_Struct* a = (CombatDamage_Struct*)outapp->pBuffer; a->target = GetID(); if (attacker == nullptr) @@ -3714,6 +3273,24 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons a->type = SkillDamageTypes[skill_used]; // was 0x1c a->damage = damage; a->spellid = spell_id; + a->special = special; + a->meleepush_xy = attacker ? attacker->GetHeading() * 2.0f : 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); + SendPosUpdate(); + } + } 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 //this was done to simplify the code here (since we can only effectively skip one mob on queue) @@ -3830,14 +3407,14 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id) if (IsBuffSpell(spell_id)) { // hots // message to caster if (caster->IsClient() && caster == this) { - if (caster->CastToClient()->GetClientVersionBit() & BIT_SoFAndLater) + if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) FilteredMessage_StringID(caster, MT_NonMelee, FilterHealOverTime, HOT_HEAL_SELF, itoa(acthealed), spells[spell_id].name); else FilteredMessage_StringID(caster, MT_NonMelee, FilterHealOverTime, YOU_HEALED, GetCleanName(), itoa(acthealed)); } else if (caster->IsClient() && caster != this) { - if (caster->CastToClient()->GetClientVersionBit() & BIT_SoFAndLater) + if (caster->CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) caster->FilteredMessage_StringID(caster, MT_NonMelee, FilterHealOverTime, HOT_HEAL_OTHER, GetCleanName(), itoa(acthealed), spells[spell_id].name); @@ -3847,7 +3424,7 @@ void Mob::HealDamage(uint32 amount, Mob *caster, uint16 spell_id) } // message to target if (IsClient() && caster != this) { - if (CastToClient()->GetClientVersionBit() & BIT_SoFAndLater) + if (CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) FilteredMessage_StringID(this, MT_NonMelee, FilterHealOverTime, HOT_HEALED_OTHER, caster->GetCleanName(), itoa(acthealed), spells[spell_id].name); @@ -3921,7 +3498,7 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 h } // argument 'weapon' not used -void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand) { +void Mob::TryDefensiveProc(Mob *on, uint16 hand) { if (!on) { SetTarget(nullptr); @@ -3929,29 +3506,37 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand) { return; } - bool bDefensiveProc = HasDefensiveProcs(); - - if (!bDefensiveProc) + if (!HasDefensiveProcs()) return; - float ProcChance, ProcBonus; - on->GetDefensiveProcChances(ProcBonus, ProcChance, hand , this); + if (!on->HasDied() && on->GetHP() > 0){ - if(hand != MainPrimary) - ProcChance /= 2; + float ProcChance, ProcBonus; + on->GetDefensiveProcChances(ProcBonus, ProcChance, hand , this); - if (bDefensiveProc){ - for (int i = 0; i < MAX_PROCS; i++) { - if (IsValidSpell(DefensiveProcs[i].spellID)) { - float chance = ProcChance * (static_cast(DefensiveProcs[i].chance)/100.0f); - if (zone->random.Roll(chance)) { - ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on); - CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0, - DefensiveProcs[i].base_spellID); - } + if (hand != EQEmu::legacy::SlotPrimary) + ProcChance /= 2; + + int level_penalty = 0; + int level_diff = GetLevel() - on->GetLevel(); + if (level_diff > 6)//10% penalty per level if > 6 levels over target. + level_penalty = (level_diff - 6) * 10; + + ProcChance -= ProcChance*level_penalty/100; + + if (ProcChance < 0) + return; + + for (int i = 0; i < MAX_PROCS; i++) { + if (IsValidSpell(DefensiveProcs[i].spellID)) { + float chance = ProcChance * (static_cast(DefensiveProcs[i].chance)/100.0f); + if (zone->random.Roll(chance)) { + ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on); + CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0,DefensiveProcs[i].base_spellID); } } } + } } void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) { @@ -3972,17 +3557,17 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) { } if(!weapon_g) { - TrySpellProc(nullptr, (const Item_Struct*)nullptr, on); + TrySpellProc(nullptr, (const EQEmu::ItemBase*)nullptr, on); return; } - if(!weapon_g->IsType(ItemClassCommon)) { - TrySpellProc(nullptr, (const Item_Struct*)nullptr, on); + if (!weapon_g->IsClassCommon()) { + TrySpellProc(nullptr, (const EQEmu::ItemBase*)nullptr, on); return; } // Innate + aug procs from weapons - // TODO: powersource procs + // TODO: powersource procs -- powersource procs are on invis augs, so shouldn't need anything extra TryWeaponProc(weapon_g, weapon_g->GetItem(), on, hand); // Procs from Buffs and AA both melee and range TrySpellProc(weapon_g, weapon_g->GetItem(), on, hand); @@ -3990,7 +3575,7 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) { return; } -void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, uint16 hand) +void Mob::TryWeaponProc(const ItemInst *inst, const EQEmu::ItemBase *weapon, Mob *on, uint16 hand) { if (!weapon) @@ -4002,14 +3587,14 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on ProcBonus += static_cast(itembonuses.ProcChance) / 10.0f; // Combat Effects float ProcChance = GetProcChances(ProcBonus, hand); - if (hand != MainPrimary) //Is Archery intened to proc at 50% rate? + if (hand != EQEmu::legacy::SlotPrimary) //Is Archery intened to proc at 50% rate? ProcChance /= 2; // Try innate proc on weapon // We can proc once here, either weapon or one aug bool proced = false; // silly bool to prevent augs from going if weapon does skillinuse = GetSkillByItemType(weapon->ItemType); - if (weapon->Proc.Type == ET_CombatProc) { + if (weapon->Proc.Type == EQEmu::item::ItemEffectCombatProc && IsValidSpell(weapon->Proc.Effect)) { float WPC = ProcChance * (100.0f + // Proc chance for this weapon static_cast(weapon->ProcRate)) / 100.0f; if (zone->random.Roll(WPC)) { // 255 dex = 0.084 chance of proc. No idea what this number should be really. @@ -4039,15 +3624,15 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on proced = false; if (!proced && inst) { - for (int r = 0; r < EmuConstants::ITEM_COMMON_SIZE; r++) { + for (int r = 0; r < EQEmu::legacy::ITEM_COMMON_SIZE; r++) { const ItemInst *aug_i = inst->GetAugment(r); if (!aug_i) // no aug, try next slot! continue; - const Item_Struct *aug = aug_i->GetItem(); + const EQEmu::ItemBase *aug = aug_i->GetItem(); if (!aug) continue; - if (aug->Proc.Type == ET_CombatProc) { + if (aug->Proc.Type == EQEmu::item::ItemEffectCombatProc && IsValidSpell(aug->Proc.Effect)) { float APC = ProcChance * (100.0f + // Proc chance for this aug static_cast(aug->ProcRate)) / 100.0f; if (zone->random.Roll(APC)) { @@ -4068,35 +3653,36 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on } } } - // TODO: Powersource procs + // TODO: Powersource procs -- powersource procs are from augs so shouldn't need anything extra return; } -void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, uint16 hand) +void Mob::TrySpellProc(const ItemInst *inst, const EQEmu::ItemBase *weapon, Mob *on, uint16 hand) { float ProcBonus = static_cast(spellbonuses.SpellProcChance + itembonuses.SpellProcChance + aabonuses.SpellProcChance); float ProcChance = 0.0f; ProcChance = GetProcChances(ProcBonus, hand); - if (hand != MainPrimary) //Is Archery intened to proc at 50% rate? + if (hand != EQEmu::legacy::SlotPrimary) //Is Archery intened to proc at 50% rate? ProcChance /= 2; bool rangedattk = false; - if (weapon && hand == MainRange) { - if (weapon->ItemType == ItemTypeArrow || - weapon->ItemType == ItemTypeLargeThrowing || - weapon->ItemType == ItemTypeSmallThrowing || - weapon->ItemType == ItemTypeBow) + if (weapon && hand == EQEmu::legacy::SlotRange) { + if (weapon->ItemType == EQEmu::item::ItemTypeArrow || + weapon->ItemType == EQEmu::item::ItemTypeLargeThrowing || + weapon->ItemType == EQEmu::item::ItemTypeSmallThrowing || + weapon->ItemType == EQEmu::item::ItemTypeBow) { rangedattk = true; + } } - if (!weapon && hand == MainRange && GetSpecialAbility(SPECATK_RANGED_ATK)) + if (!weapon && hand == EQEmu::legacy::SlotRange && GetSpecialAbility(SPECATK_RANGED_ATK)) rangedattk = true; for (uint32 i = 0; i < MAX_PROCS; i++) { - if (IsPet() && hand != MainPrimary) //Pets can only proc spell procs from their primay hand (ie; beastlord pets) + if (IsPet() && hand != EQEmu::legacy::SlotPrimary) //Pets can only proc spell procs from their primay hand (ie; beastlord pets) continue; // If pets ever can proc from off hand, this will need to change // Not ranged @@ -4122,7 +3708,15 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, Log.Out(Logs::Detail, Logs::Combat, "Spell proc %d procing spell %d (%.2f percent chance)", i, SpellProcs[i].spellID, chance); - ExecWeaponProc(nullptr, SpellProcs[i].spellID, on); + auto outapp = new EQApplicationPacket(OP_BeginCast,sizeof(BeginCast_Struct)); + BeginCast_Struct* begincast = (BeginCast_Struct*)outapp->pBuffer; + begincast->caster_id = GetID(); + begincast->spell_id = SpellProcs[i].spellID; + begincast->cast_time = 0; + outapp->priority = 3; + entity_list.QueueCloseClients(this, outapp, false, 200, 0, true); + safe_delete(outapp); + ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override); CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, SpellProcs[i].base_spellID); } else { @@ -4151,7 +3745,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, } } - if (HasSkillProcs() && hand != MainRange){ //We check ranged skill procs within the attack functions. + if (HasSkillProcs() && hand != EQEmu::legacy::SlotRange){ //We check ranged skill procs within the attack functions. uint16 skillinuse = 28; if (weapon) skillinuse = GetSkillByItemType(weapon->ItemType); @@ -4217,7 +3811,7 @@ void Mob::TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage) void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts) { - if(damage < 1) + if(damage < 1 || !defender) return; // decided to branch this into it's own function since it's going to be duplicating a lot of the @@ -4228,7 +3822,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack } #ifdef BOTS - if (this->IsPet() && this->GetOwner()->IsBot()) { + if (this->IsPet() && this->GetOwner() && this->GetOwner()->IsBot()) { this->TryPetCriticalHit(defender,skill,damage); return; } @@ -4238,8 +3832,8 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack bool IsBerskerSPA = false; //1: Try Slay Undead - if (defender && (defender->GetBodyType() == BT_Undead || - defender->GetBodyType() == BT_SummonedUndead || defender->GetBodyType() == BT_Vampire)) { + if (defender->GetBodyType() == BT_Undead || + defender->GetBodyType() == BT_SummonedUndead || defender->GetBodyType() == BT_Vampire) { int32 SlayRateBonus = aabonuses.SlayUndead[0] + itembonuses.SlayUndead[0] + spellbonuses.SlayUndead[0]; if (SlayRateBonus) { float slayChance = static_cast(SlayRateBonus) / 10000.0f; @@ -4283,10 +3877,10 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack int deadlyChance = 0; int deadlyMod = 0; - if(skill == SkillArchery && GetClass() == RANGER && GetSkill(SkillArchery) >= 65) + if (skill == EQEmu::skills::SkillArchery && GetClass() == RANGER && GetSkill(EQEmu::skills::SkillArchery) >= 65) critChance += 6; - if (skill == SkillThrowing && GetClass() == ROGUE && GetSkill(SkillThrowing) >= 65) { + if (skill == EQEmu::skills::SkillThrowing && GetClass() == ROGUE && GetSkill(EQEmu::skills::SkillThrowing) >= 65) { critChance += RuleI(Combat, RogueCritThrowingChance); deadlyChance = RuleI(Combat, RogueDeadlyStrikeChance); deadlyMod = RuleI(Combat, RogueDeadlyStrikeMod); @@ -4367,7 +3961,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack } } -bool Mob::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) +bool Mob::TryFinishingBlow(Mob *defender, EQEmu::skills::SkillType skillinuse) { if (defender && !defender->IsClient() && defender->GetHPRatio() < 10){ @@ -4392,46 +3986,59 @@ bool Mob::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) return false; } -void Mob::DoRiposte(Mob* defender) { +void Mob::DoRiposte(Mob *defender) +{ Log.Out(Logs::Detail, Logs::Combat, "Preforming a riposte"); if (!defender) return; - defender->Attack(this, MainPrimary, true); - if (HasDied()) return; + defender->Attack(this, EQEmu::legacy::SlotPrimary, true); + if (HasDied()) + return; - int32 DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[0] + - defender->spellbonuses.GiveDoubleRiposte[0] + - defender->itembonuses.GiveDoubleRiposte[0]; + // this effect isn't used on live? See no AAs or spells + int32 DoubleRipChance = defender->aabonuses.DoubleRiposte + defender->spellbonuses.DoubleRiposte + + defender->itembonuses.DoubleRiposte; - DoubleRipChance = defender->aabonuses.DoubleRiposte + - defender->spellbonuses.DoubleRiposte + - defender->itembonuses.DoubleRiposte; - - //Live AA - Double Riposte - if(DoubleRipChance && zone->random.Roll(DoubleRipChance)) { - Log.Out(Logs::Detail, Logs::Combat, "Preforming a double riposed (%d percent chance)", DoubleRipChance); - defender->Attack(this, MainPrimary, true); - if (HasDied()) return; + if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) { + Log.Out(Logs::Detail, Logs::Combat, + "Preforming a double riposted from SE_DoubleRiposte (%d percent chance)", DoubleRipChance); + defender->Attack(this, EQEmu::legacy::SlotPrimary, true); + if (HasDied()) + return; } - //Double Riposte effect, allows for a chance to do RIPOSTE with a skill specfic special attack (ie Return Kick). - //Coded narrowly: Limit to one per client. Limit AA only. [1 = Skill Attack Chance, 2 = Skill] + DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[0] + defender->spellbonuses.GiveDoubleRiposte[0] + + defender->itembonuses.GiveDoubleRiposte[0]; + + // Live AA - Double Riposte + if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) { + Log.Out(Logs::Detail, Logs::Combat, + "Preforming a double riposted from SE_GiveDoubleRiposte base1 == 0 (%d percent chance)", + DoubleRipChance); + defender->Attack(this, EQEmu::legacy::SlotPrimary, true); + if (HasDied()) + return; + } + + // Double Riposte effect, allows for a chance to do RIPOSTE with a skill specific special attack (ie Return Kick). + // Coded narrowly: Limit to one per client. Limit AA only. [1 = Skill Attack Chance, 2 = Skill] DoubleRipChance = defender->aabonuses.GiveDoubleRiposte[1]; - if(DoubleRipChance && zone->random.Roll(DoubleRipChance)) { - Log.Out(Logs::Detail, Logs::Combat, "Preforming a return SPECIAL ATTACK (%d percent chance)", DoubleRipChance); + if (DoubleRipChance && zone->random.Roll(DoubleRipChance)) { + Log.Out(Logs::Detail, Logs::Combat, "Preforming a return SPECIAL ATTACK (%d percent chance)", + DoubleRipChance); if (defender->GetClass() == MONK) defender->MonkSpecialAttack(this, defender->aabonuses.GiveDoubleRiposte[2]); - else if (defender->IsClient()) - defender->CastToClient()->DoClassAttacks(this,defender->aabonuses.GiveDoubleRiposte[2], true); + else if (defender->IsClient() && defender->CastToClient()->HasSkill((EQEmu::skills::SkillType)defender->aabonuses.GiveDoubleRiposte[2])) + defender->CastToClient()->DoClassAttacks(this, defender->aabonuses.GiveDoubleRiposte[2], true); } } -void Mob::ApplyMeleeDamageBonus(uint16 skill, int32 &damage){ +void Mob::ApplyMeleeDamageBonus(uint16 skill, int32 &damage,ExtraAttackOptions *opts){ if(!RuleB(Combat, UseIntervalAC)){ if(IsNPC()){ //across the board NPC damage bonuses. @@ -4444,7 +4051,13 @@ void Mob::ApplyMeleeDamageBonus(uint16 skill, int32 &damage){ } } - damage += damage * GetMeleeDamageMod_SE(skill) / 100; + int dmgbonusmod = 0; + + dmgbonusmod += GetMeleeDamageMod_SE(skill); + if (opts) + dmgbonusmod += opts->melee_damage_bonus_flat; + + damage += damage * dmgbonusmod / 100; } bool Mob::HasDied() { @@ -4459,7 +4072,7 @@ bool Mob::HasDied() { return Result; } -uint16 Mob::GetDamageTable(SkillUseTypes skillinuse) +uint16 Mob::GetDamageTable(EQEmu::skills::SkillType skillinuse) { if(GetLevel() <= 51) { @@ -4552,7 +4165,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui ProcMod = static_cast(spells[base_spell_id].base2[i]); } - else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].base[i] <= HIGHEST_SKILL) { + else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].base[i] <= EQEmu::skills::HIGHEST_SKILL) { if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) { float final_chance = chance * (ProcMod / 100.0f); @@ -4596,7 +4209,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui ProcMod = static_cast(spells[base_spell_id].base2[i]); } - else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].base[i] <= HIGHEST_SKILL) { + else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].base[i] <= EQEmu::skills::HIGHEST_SKILL) { if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) { float final_chance = chance * (ProcMod / 100.0f); @@ -4619,7 +4232,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui if (IsClient() && aabonuses.LimitToSkill[skill]){ CanProc = true; - uint32 effect = 0; + uint32 effect_id = 0; int32 base1 = 0; int32 base2 = 0; uint32 slot = 0; @@ -4638,36 +4251,41 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui proc_spell_id = 0; ProcMod = 0; - std::map >::const_iterator find_iter = aa_effects.find(aaid); - if(find_iter == aa_effects.end()) - break; + for(auto &rank_info : aa_ranks) { + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(rank_info.first, rank_info.second.first); + auto ability = ability_rank.first; + auto rank = ability_rank.second; - for (std::map::const_iterator iter = aa_effects[aaid].begin(); iter != aa_effects[aaid].end(); ++iter) { - effect = iter->second.skill_id; - base1 = iter->second.base1; - base2 = iter->second.base2; - slot = iter->second.slot; - - if (effect == SE_SkillProc || effect == SE_SkillProcSuccess) { - proc_spell_id = base1; - ProcMod = static_cast(base2); + if(!ability) { + continue; } - else if (effect == SE_LimitToSkill && base1 <= HIGHEST_SKILL) { + for(auto &effect : rank->effects) { + effect_id = effect.effect_id; + base1 = effect.base1; + base2 = effect.base2; + slot = effect.slot; - if (CanProc && base1 == skill && IsValidSpell(proc_spell_id)) { - float final_chance = chance * (ProcMod / 100.0f); + if(effect_id == SE_SkillProc || effect_id == SE_SkillProcSuccess) { + proc_spell_id = base1; + ProcMod = static_cast(base2); + } + else if (effect_id == SE_LimitToSkill && base1 <= EQEmu::skills::HIGHEST_SKILL) { - if (zone->random.Roll(final_chance)) { - ExecWeaponProc(nullptr, proc_spell_id, on); - CanProc = false; - break; + if (CanProc && base1 == skill && IsValidSpell(proc_spell_id)) { + float final_chance = chance * (ProcMod / 100.0f); + + if (zone->random.Roll(final_chance)) { + ExecWeaponProc(nullptr, proc_spell_id, on); + CanProc = false; + break; + } } } - } - else { - proc_spell_id = 0; - ProcMod = 0; + else { + proc_spell_id = 0; + ProcMod = 0; + } } } } @@ -4683,7 +4301,7 @@ float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) { if (!ReuseTime && hand) { weapon_speed = GetWeaponSpeedbyHand(hand); ProcChance = static_cast(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f); - if (hand != MainPrimary) + if (hand != EQEmu::legacy::SlotPrimary) ProcChance /= 2; } @@ -4797,18 +4415,18 @@ int32 Mob::RuneAbsorb(int32 damage, uint16 type) return damage; } -void Mob::CommonOutgoingHitSuccess(Mob* defender, int32 &damage, SkillUseTypes skillInUse) +void Mob::CommonOutgoingHitSuccess(Mob* defender, int32 &damage, EQEmu::skills::SkillType skillInUse, ExtraAttackOptions *opts) { if (!defender) return; - ApplyMeleeDamageBonus(skillInUse, damage); - damage += (damage * defender->GetSkillDmgTaken(skillInUse) / 100) + (GetSkillDmgAmt(skillInUse) + defender->GetFcDamageAmtIncoming(this, 0, true, skillInUse)); - TryCriticalHit(defender, skillInUse, damage); + ApplyMeleeDamageBonus(skillInUse, damage, opts); + damage += (damage * defender->GetSkillDmgTaken(skillInUse, opts) / 100) + (GetSkillDmgAmt(skillInUse) + defender->GetFcDamageAmtIncoming(this, 0, true, skillInUse)); + TryCriticalHit(defender, skillInUse, damage,opts); CheckNumHitsRemaining(NumHit::OutgoingHitSuccess); } -void Mob::CommonBreakInvisible() +void Mob::CommonBreakInvisibleFromCombat() { //break invis when you attack if(invisible) { @@ -4829,20 +4447,7 @@ void Mob::CommonBreakInvisible() invisible_animals = false; } - if (spellbonuses.NegateIfCombat) - BuffFadeByEffect(SE_NegateIfCombat); - - if(hidden || improved_hidden){ - hidden = false; - improved_hidden = false; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); - SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer; - sa_out->spawn_id = GetID(); - sa_out->type = 0x03; - sa_out->parameter = 0; - entity_list.QueueClients(this, outapp, true); - safe_delete(outapp); - } + CancelSneakHide(); if (spellbonuses.NegateIfCombat) BuffFadeByEffect(SE_NegateIfCombat); @@ -4885,20 +4490,19 @@ void Client::SetAttackTimer() attack_timer.SetAtTrigger(4000, true); Timer *TimerToUse = nullptr; - const Item_Struct *PrimaryWeapon = nullptr; - for (int i = MainRange; i <= MainSecondary; i++) { + for (int i = EQEmu::legacy::SlotRange; i <= EQEmu::legacy::SlotSecondary; i++) { //pick a timer - if (i == MainPrimary) + if (i == EQEmu::legacy::SlotPrimary) TimerToUse = &attack_timer; - else if (i == MainRange) + else if (i == EQEmu::legacy::SlotRange) TimerToUse = &ranged_timer; - else if (i == MainSecondary) + else if (i == EQEmu::legacy::SlotSecondary) TimerToUse = &attack_dw_timer; else //invalid slot (hands will always hit this) continue; - const Item_Struct *ItemToUse = nullptr; + const EQEmu::ItemBase *ItemToUse = nullptr; //find our item ItemInst *ci = GetInv().GetItem(i); @@ -4906,20 +4510,9 @@ void Client::SetAttackTimer() ItemToUse = ci->GetItem(); //special offhand stuff - if (i == MainSecondary) { - //if we have a 2H weapon in our main hand, no dual - if (PrimaryWeapon != nullptr) { - if (PrimaryWeapon->ItemClass == ItemClassCommon - && (PrimaryWeapon->ItemType == ItemType2HSlash - || PrimaryWeapon->ItemType == ItemType2HBlunt - || PrimaryWeapon->ItemType == ItemType2HPiercing)) { - attack_dw_timer.Disable(); - continue; - } - } - + if (i == EQEmu::legacy::SlotSecondary) { //if we cant dual wield, skip it - if (!CanThisClassDualWield()) { + if (!CanThisClassDualWield() || HasTwoHanderEquipped()) { attack_dw_timer.Disable(); continue; } @@ -4928,16 +4521,16 @@ void Client::SetAttackTimer() //see if we have a valid weapon if (ItemToUse != nullptr) { //check type and damage/delay - if (ItemToUse->ItemClass != ItemClassCommon - || ItemToUse->Damage == 0 - || ItemToUse->Delay == 0) { + if (!ItemToUse->IsClassCommon() + || ItemToUse->Damage == 0 + || ItemToUse->Delay == 0) { //no weapon ItemToUse = nullptr; } // Check to see if skill is valid - else if ((ItemToUse->ItemType > ItemTypeLargeThrowing) && - (ItemToUse->ItemType != ItemTypeMartial) && - (ItemToUse->ItemType != ItemType2HPiercing)) { + else if ((ItemToUse->ItemType > EQEmu::item::ItemTypeLargeThrowing) && + (ItemToUse->ItemType != EQEmu::item::ItemTypeMartial) && + (ItemToUse->ItemType != EQEmu::item::ItemType2HPiercing)) { //no weapon ItemToUse = nullptr; } @@ -4945,32 +4538,28 @@ void Client::SetAttackTimer() int hhe = itembonuses.HundredHands + spellbonuses.HundredHands; int speed = 0; - int delay = 36; - float quiver_haste = 0.0f; + int delay = 3500; //if we have no weapon.. - if (ItemToUse == nullptr) { - //above checks ensure ranged weapons do not fall into here - // Work out if we're a monk - if (GetClass() == MONK || GetClass() == BEASTLORD) - delay = GetMonkHandToHandDelay(); - } else { - //we have a weapon, use its delay - delay = ItemToUse->Delay; - if (ItemToUse->ItemType == ItemTypeBow || ItemToUse->ItemType == ItemTypeLargeThrowing) - quiver_haste = GetQuiverHaste(); - } - if (RuleB(Spells, Jun182014HundredHandsRevamp)) - speed = static_cast(((delay / haste_mod) + ((hhe / 1000.0f) * (delay / haste_mod))) * 100); + if (ItemToUse == nullptr) + delay = 100 * GetHandToHandDelay(); else - speed = static_cast(((delay / haste_mod) + ((hhe / 100.0f) * delay)) * 100); - // this is probably wrong - if (quiver_haste > 0) - speed *= quiver_haste; - TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true); + //we have a weapon, use its delay + delay = 100 * ItemToUse->Delay; - if (i == MainPrimary) - PrimaryWeapon = ItemToUse; + speed = delay / haste_mod; + + if (ItemToUse && ItemToUse->ItemType == EQEmu::item::ItemTypeBow) { + // Live actually had a bug here where they would return the non-modified attack speed + // rather than the cap ... + speed = std::max(speed - GetQuiverHaste(speed), RuleI(Combat, QuiverHasteCap)); + } else { + if (RuleB(Spells, Jun182014HundredHandsRevamp)) + speed = static_cast(speed + ((hhe / 1000.0f) * speed)); + else + speed = static_cast(speed + ((hhe / 100.0f) * delay)); + } + TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true); } } @@ -4995,21 +4584,21 @@ void NPC::SetAttackTimer() else speed = static_cast(((attack_delay / haste_mod) + ((hhe / 100.0f) * attack_delay)) * 100); - for (int i = MainRange; i <= MainSecondary; i++) { + for (int i = EQEmu::legacy::SlotRange; i <= EQEmu::legacy::SlotSecondary; i++) { //pick a timer - if (i == MainPrimary) + if (i == EQEmu::legacy::SlotPrimary) TimerToUse = &attack_timer; - else if (i == MainRange) + else if (i == EQEmu::legacy::SlotRange) TimerToUse = &ranged_timer; - else if (i == MainSecondary) + else if (i == EQEmu::legacy::SlotSecondary) TimerToUse = &attack_dw_timer; else //invalid slot (hands will always hit this) continue; //special offhand stuff - if (i == MainSecondary) { - //NPCs get it for free at 13 - if(GetLevel() < 13) { + if (i == EQEmu::legacy::SlotSecondary) { + // SPECATK_QUAD is uncheesable + if(!CanThisClassDualWield() || (HasTwoHanderEquipped() && !GetSpecialAbility(SPECATK_QUAD))) { attack_dw_timer.Disable(); continue; } @@ -5018,3 +4607,154 @@ void NPC::SetAttackTimer() TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true); } } + +void Client::DoAttackRounds(Mob *target, int hand, bool IsFromSpell) +{ + if (!target) + return; + + Attack(target, hand, false, false, IsFromSpell); + + bool candouble = CanThisClassDoubleAttack(); + // 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::legacy::SlotSecondary) + 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); + // you can only triple from the main hand + if (hand == EQEmu::legacy::SlotPrimary && CanThisClassTripleAttack()) { + CheckIncreaseSkill(EQEmu::skills::SkillTripleAttack, target, -10); + if (CheckTripleAttack()) + Attack(target, hand, false, false, IsFromSpell); + } + } + } + + if (hand == EQEmu::legacy::SlotPrimary) { + // According to http://www.monkly-business.net/forums/showpost.php?p=312095&postcount=168 a dev told them flurry isn't dependant on triple attack + // the parses kind of back that up and all of my parses seemed to be 4 or 5 attacks in the round which would work out to be + // doubles or triples with 2 from flurries or triple with 1 or 2 flurries ... Going with the "dev quote" I guess like we've always had it + auto flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance; + if (flurrychance && zone->random.Roll(flurrychance)) { + Attack(target, hand, false, false, IsFromSpell); + Attack(target, hand, false, false, IsFromSpell); + Message_StringID(MT_NPCFlurry, YOU_FLURRY); + } + // I haven't parsed where this guy happens, but it's not part of the normal chain above so this is fine + auto extraattackchance = aabonuses.ExtraAttackChance + spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance; + if (extraattackchance && HasTwoHanderEquipped() && zone->random.Roll(extraattackchance)) + Attack(target, hand, false, false, IsFromSpell); + } +} + +bool Mob::CheckDualWield() +{ + // Pets /might/ follow a slightly different progression + // although it could all be from pets having different skills than most mobs + int chance = GetSkill(EQEmu::skills::SkillDualWield); + if (GetLevel() > 35) + chance += GetLevel(); + + chance += aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity; + int per_inc = spellbonuses.DualWieldChance + aabonuses.DualWieldChance + itembonuses.DualWieldChance; + if (per_inc) + chance += chance * per_inc / 100; + + return zone->random.Int(1, 375) <= chance; +} + +bool Client::CheckDualWield() +{ + int chance = GetSkill(EQEmu::skills::SkillDualWield) + GetLevel(); + + chance += aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity; + int per_inc = spellbonuses.DualWieldChance + aabonuses.DualWieldChance + itembonuses.DualWieldChance; + if (per_inc) + chance += chance * per_inc / 100; + + return zone->random.Int(1, 375) <= chance; +} + +void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts, int special) +{ + if (!target) + return; + + if (RuleB(Combat, UseLiveCombatRounds)) { + // A "quad" on live really is just a successful dual wield where both double attack + // The mobs that could triple lost the ability to when the triple attack skill was added in + Attack(target, EQEmu::legacy::SlotPrimary, false, false, false, opts, special); + if (CanThisClassDoubleAttack() && CheckDoubleAttack()){ + Attack(target, EQEmu::legacy::SlotPrimary, false, false, false, opts, special); + + if ((IsPet() || IsTempPet()) && IsPetOwnerClient()){ + int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry; + if (chance && zone->random.Roll(chance)) + Flurry(nullptr); + } + } + return; + } + + if (IsNPC()) { + int16 n_atk = CastToNPC()->GetNumberOfAttacks(); + if (n_atk <= 1) { + Attack(target, EQEmu::legacy::SlotPrimary, false, false, false, opts, special); + } else { + for (int i = 0; i < n_atk; ++i) { + Attack(target, EQEmu::legacy::SlotPrimary, false, false, false, opts, special); + } + } + } else { + Attack(target, EQEmu::legacy::SlotPrimary, false, false, false, opts, special); + } + + // we use this random value in three comparisons with different + // thresholds, and if its truely random, then this should work + // out reasonably and will save us compute resources. + int32 RandRoll = zone->random.Int(0, 99); + if ((CanThisClassDoubleAttack() || GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD)) + // check double attack, this is NOT the same rules that clients use... + && + RandRoll < (GetLevel() + NPCDualAttackModifier)) { + Attack(target, EQEmu::legacy::SlotPrimary, false, false, false, opts, special); + // lets see if we can do a triple attack with the main hand + // pets are excluded from triple and quads... + if ((GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD)) && !IsPet() && + RandRoll < (GetLevel() + NPCTripleAttackModifier)) { + Attack(target, EQEmu::legacy::SlotPrimary, false, false, false, opts, special); + // now lets check the quad attack + if (GetSpecialAbility(SPECATK_QUAD) && RandRoll < (GetLevel() + NPCQuadAttackModifier)) { + Attack(target, EQEmu::legacy::SlotPrimary, false, false, false, opts, special); + } + } + } +} + +void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts, int special) +{ + if (!target) + return; + // Mobs will only dual wield w/ the flag or have a secondary weapon + // For now, SPECATK_QUAD means innate DW when Combat:UseLiveCombatRounds is true + if ((GetSpecialAbility(SPECATK_INNATE_DW) || + (RuleB(Combat, UseLiveCombatRounds) && GetSpecialAbility(SPECATK_QUAD))) || + GetEquipment(EQEmu::textures::TextureSecondary) != 0) { + if (CheckDualWield()) { + Attack(target, EQEmu::legacy::SlotSecondary, false, false, false, opts, special); + if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack()){ + Attack(target, EQEmu::legacy::SlotSecondary, false, false, false, opts, special); + + if ((IsPet() || IsTempPet()) && IsPetOwnerClient()){ + int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry; + if (chance && zone->random.Roll(chance)) + Flurry(nullptr); + } + } + } + } +} diff --git a/zone/beacon.cpp b/zone/beacon.cpp index 5a952dc9d..27f86fce7 100644 --- a/zone/beacon.cpp +++ b/zone/beacon.cpp @@ -26,8 +26,10 @@ target to center around. class Zone; #ifdef _WINDOWS - #define snprintf _snprintf - #define vsnprintf _vsnprintf + #if (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER < 1900)) + #define snprintf _snprintf + #define vsnprintf _vsnprintf + #endif #define strncasecmp _strnicmp #define strcasecmp _stricmp #endif @@ -54,7 +56,7 @@ Beacon::Beacon(Mob *at_mob, int lifetime) :Mob ( nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, at_mob->GetPosition(), 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ), remove_timer(lifetime), spell_timer(0) diff --git a/zone/beacon.h b/zone/beacon.h index f7845e91d..398c9680e 100644 --- a/zone/beacon.h +++ b/zone/beacon.h @@ -34,10 +34,10 @@ public: ~Beacon(); //abstract virtual function implementations requird by base abstract class - virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) { return true; } - virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false) { return; } - virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, - ExtraAttackOptions *opts = nullptr) { return false; } + virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; } + virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0) { return; } + virtual bool Attack(Mob* other, int Hand = EQEmu::legacy::SlotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, + ExtraAttackOptions *opts = nullptr, int special = 0) { return false; } virtual bool HasRaid() { return false; } virtual bool HasGroup() { return false; } virtual Raid* GetRaid() { return 0; } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index c17980297..2a8a0c790 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -42,6 +42,7 @@ void Mob::CalcBonuses() { CalcSpellBonuses(&spellbonuses); + CalcAABonuses(&aabonuses); CalcMaxHP(); CalcMaxMana(); SetAttackTimer(); @@ -51,9 +52,7 @@ void Mob::CalcBonuses() void NPC::CalcBonuses() { - Mob::CalcBonuses(); - memset(&aabonuses, 0, sizeof(StatBonuses)); - + memset(&itembonuses, 0, sizeof(StatBonuses)); if(RuleB(NPC, UseItemBonusesForNonPets)){ memset(&itembonuses, 0, sizeof(StatBonuses)); CalcItemBonuses(&itembonuses); @@ -74,12 +73,8 @@ void Client::CalcBonuses() memset(&itembonuses, 0, sizeof(StatBonuses)); CalcItemBonuses(&itembonuses); CalcEdibleBonuses(&itembonuses); - CalcSpellBonuses(&spellbonuses); - - Log.Out(Logs::Detail, Logs::AA, "Calculating AA Bonuses for %s.", this->GetCleanName()); - CalcAABonuses(&aabonuses); //we're not quite ready for this - Log.Out(Logs::Detail, Logs::AA, "Finished calculating AA Bonuses for %s.", this->GetCleanName()); + CalcAABonuses(&aabonuses); ProcessItemCaps(); // caps that depend on spell/aa bonuses @@ -113,6 +108,9 @@ void Client::CalcBonuses() rooted = FindType(SE_Root); XPRate = 100 + spellbonuses.XPRateMod; + + if (GetMaxXTargets() != 5 + aabonuses.extra_xtargets) + SetMaxXTargets(5 + aabonuses.extra_xtargets); } int Client::CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat) @@ -143,42 +141,47 @@ void Client::CalcItemBonuses(StatBonuses* newbon) { ClearItemFactionBonuses(); SetShieldEquiped(false); SetTwoHandBluntEquiped(false); + SetTwoHanderEquipped(false); unsigned int i; - //should not include 21 (SLOT_AMMO) - for (i = MainCharm; i < MainAmmo; i++) { + // Update: MainAmmo should only calc skill mods (TODO: Check for other cases) + for (i = EQEmu::legacy::SlotCharm; i <= EQEmu::legacy::SlotAmmo; i++) { const ItemInst* inst = m_inv[i]; if(inst == 0) continue; - AddItemBonuses(inst, newbon); + AddItemBonuses(inst, newbon, false, false, 0, (i == EQEmu::legacy::SlotAmmo)); //These are given special flags due to how often they are checked for various spell effects. - const Item_Struct *item = inst->GetItem(); - if (i == MainSecondary && (item && item->ItemType == ItemTypeShield)) + const EQEmu::ItemBase *item = inst->GetItem(); + if (i == EQEmu::legacy::SlotSecondary && (item && item->ItemType == EQEmu::item::ItemTypeShield)) SetShieldEquiped(true); - else if (i == MainPrimary && (item && item->ItemType == ItemType2HBlunt)) + else if (i == EQEmu::legacy::SlotPrimary && (item && item->ItemType == EQEmu::item::ItemType2HBlunt)) { SetTwoHandBluntEquiped(true); + SetTwoHanderEquipped(true); + } + else if (i == EQEmu::legacy::SlotPrimary && (item && (item->ItemType == EQEmu::item::ItemType2HSlash || item->ItemType == EQEmu::item::ItemType2HPiercing))) + SetTwoHanderEquipped(true); } //Power Source Slot - if (GetClientVersion() >= ClientVersion::SoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { - const ItemInst* inst = m_inv[MainPowerSource]; + const ItemInst* inst = m_inv[EQEmu::legacy::SlotPowerSource]; if(inst) AddItemBonuses(inst, newbon); } //tribute items - for (i = 0; i < EmuConstants::TRIBUTE_SIZE; i++) { - const ItemInst* inst = m_inv[EmuConstants::TRIBUTE_BEGIN + i]; + for (i = 0; i < EQEmu::legacy::TRIBUTE_SIZE; i++) { + const ItemInst* inst = m_inv[EQEmu::legacy::TRIBUTE_BEGIN + i]; if(inst == 0) continue; AddItemBonuses(inst, newbon, false, true); } //Optional ability to have worn effects calculate as an addititive bonus instead of highest value - if (RuleI(Spells, AdditiveBonusWornType) && RuleI(Spells, AdditiveBonusWornType) != ET_WornEffect){ - for (i = MainCharm; i < MainAmmo; i++) { + if (RuleI(Spells, AdditiveBonusWornType) && RuleI(Spells, AdditiveBonusWornType) != EQEmu::item::ItemEffectWorn){ + for (i = EQEmu::legacy::SlotCharm; i < EQEmu::legacy::SlotAmmo; i++) { const ItemInst* inst = m_inv[i]; if(inst == 0) continue; @@ -205,353 +208,328 @@ void Client::ProcessItemCaps() itembonuses.ATK = std::min(itembonuses.ATK, CalcItemATKCap()); } -void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug, bool isTribute) { - if(!inst || !inst->IsType(ItemClassCommon)) - { +void Client::AddItemBonuses(const ItemInst *inst, StatBonuses *newbon, bool isAug, bool isTribute, int rec_override, bool ammo_slot_item) +{ + if (!inst || !inst->IsClassCommon()) { return; } - if(inst->GetAugmentType()==0 && isAug == true) - { + if (inst->GetAugmentType() == 0 && isAug == true) { return; } - const Item_Struct *item = inst->GetItem(); + const EQEmu::ItemBase *item = inst->GetItem(); - if(!isTribute && !inst->IsEquipable(GetBaseRace(),GetClass())) - { - if(item->ItemType != ItemTypeFood && item->ItemType != ItemTypeDrink) + if (!isTribute && !inst->IsEquipable(GetBaseRace(), GetClass())) { + if (item->ItemType != EQEmu::item::ItemTypeFood && item->ItemType != EQEmu::item::ItemTypeDrink) return; } - if(GetLevel() < item->ReqLevel) - { + if (GetLevel() < inst->GetItemRequiredLevel(true)) { return; } + + // So there isn't a very nice way to get the real rec level from the aug's inst, so we just pass it in, only + // used for augs + auto rec_level = isAug ? rec_override : inst->GetItemRecommendedLevel(true); - if(GetLevel() >= item->RecLevel) - { - newbon->AC += item->AC; - newbon->HP += item->HP; - newbon->Mana += item->Mana; - newbon->Endurance += item->Endur; - newbon->ATK += item->Attack; - newbon->STR += (item->AStr + item->HeroicStr); - newbon->STA += (item->ASta + item->HeroicSta); - newbon->DEX += (item->ADex + item->HeroicDex); - newbon->AGI += (item->AAgi + item->HeroicAgi); - newbon->INT += (item->AInt + item->HeroicInt); - newbon->WIS += (item->AWis + item->HeroicWis); - newbon->CHA += (item->ACha + item->HeroicCha); + if (!ammo_slot_item) { + if (GetLevel() >= rec_level) { + newbon->AC += item->AC; + newbon->HP += item->HP; + newbon->Mana += item->Mana; + newbon->Endurance += item->Endur; + newbon->ATK += item->Attack; + newbon->STR += (item->AStr + item->HeroicStr); + newbon->STA += (item->ASta + item->HeroicSta); + newbon->DEX += (item->ADex + item->HeroicDex); + newbon->AGI += (item->AAgi + item->HeroicAgi); + newbon->INT += (item->AInt + item->HeroicInt); + newbon->WIS += (item->AWis + item->HeroicWis); + newbon->CHA += (item->ACha + item->HeroicCha); - newbon->MR += (item->MR + item->HeroicMR); - newbon->FR += (item->FR + item->HeroicFR); - newbon->CR += (item->CR + item->HeroicCR); - newbon->PR += (item->PR + item->HeroicPR); - newbon->DR += (item->DR + item->HeroicDR); - newbon->Corrup += (item->SVCorruption + item->HeroicSVCorrup); + newbon->MR += (item->MR + item->HeroicMR); + newbon->FR += (item->FR + item->HeroicFR); + newbon->CR += (item->CR + item->HeroicCR); + newbon->PR += (item->PR + item->HeroicPR); + newbon->DR += (item->DR + item->HeroicDR); + newbon->Corrup += (item->SVCorruption + item->HeroicSVCorrup); - newbon->STRCapMod += item->HeroicStr; - newbon->STACapMod += item->HeroicSta; - newbon->DEXCapMod += item->HeroicDex; - newbon->AGICapMod += item->HeroicAgi; - newbon->INTCapMod += item->HeroicInt; - newbon->WISCapMod += item->HeroicWis; - newbon->CHACapMod += item->HeroicCha; - newbon->MRCapMod += item->HeroicMR; - newbon->CRCapMod += item->HeroicFR; - newbon->FRCapMod += item->HeroicCR; - newbon->PRCapMod += item->HeroicPR; - newbon->DRCapMod += item->HeroicDR; - newbon->CorrupCapMod += item->HeroicSVCorrup; + newbon->STRCapMod += item->HeroicStr; + newbon->STACapMod += item->HeroicSta; + newbon->DEXCapMod += item->HeroicDex; + newbon->AGICapMod += item->HeroicAgi; + newbon->INTCapMod += item->HeroicInt; + newbon->WISCapMod += item->HeroicWis; + newbon->CHACapMod += item->HeroicCha; + newbon->MRCapMod += item->HeroicMR; + newbon->CRCapMod += item->HeroicFR; + newbon->FRCapMod += item->HeroicCR; + newbon->PRCapMod += item->HeroicPR; + newbon->DRCapMod += item->HeroicDR; + newbon->CorrupCapMod += item->HeroicSVCorrup; - newbon->HeroicSTR += item->HeroicStr; - newbon->HeroicSTA += item->HeroicSta; - newbon->HeroicDEX += item->HeroicDex; - newbon->HeroicAGI += item->HeroicAgi; - newbon->HeroicINT += item->HeroicInt; - newbon->HeroicWIS += item->HeroicWis; - newbon->HeroicCHA += item->HeroicCha; - newbon->HeroicMR += item->HeroicMR; - newbon->HeroicFR += item->HeroicFR; - newbon->HeroicCR += item->HeroicCR; - newbon->HeroicPR += item->HeroicPR; - newbon->HeroicDR += item->HeroicDR; - newbon->HeroicCorrup += item->HeroicSVCorrup; + newbon->HeroicSTR += item->HeroicStr; + newbon->HeroicSTA += item->HeroicSta; + newbon->HeroicDEX += item->HeroicDex; + newbon->HeroicAGI += item->HeroicAgi; + newbon->HeroicINT += item->HeroicInt; + newbon->HeroicWIS += item->HeroicWis; + newbon->HeroicCHA += item->HeroicCha; + newbon->HeroicMR += item->HeroicMR; + newbon->HeroicFR += item->HeroicFR; + newbon->HeroicCR += item->HeroicCR; + newbon->HeroicPR += item->HeroicPR; + newbon->HeroicDR += item->HeroicDR; + newbon->HeroicCorrup += item->HeroicSVCorrup; - } - else - { - int lvl = GetLevel(); - int reclvl = item->RecLevel; + } + else { + int lvl = GetLevel(); - newbon->AC += CalcRecommendedLevelBonus( lvl, reclvl, item->AC ); - newbon->HP += CalcRecommendedLevelBonus( lvl, reclvl, item->HP ); - newbon->Mana += CalcRecommendedLevelBonus( lvl, reclvl, item->Mana ); - newbon->Endurance += CalcRecommendedLevelBonus( lvl, reclvl, item->Endur ); - newbon->ATK += CalcRecommendedLevelBonus( lvl, reclvl, item->Attack ); - newbon->STR += CalcRecommendedLevelBonus( lvl, reclvl, (item->AStr + item->HeroicStr) ); - newbon->STA += CalcRecommendedLevelBonus( lvl, reclvl, (item->ASta + item->HeroicSta) ); - newbon->DEX += CalcRecommendedLevelBonus( lvl, reclvl, (item->ADex + item->HeroicDex) ); - newbon->AGI += CalcRecommendedLevelBonus( lvl, reclvl, (item->AAgi + item->HeroicAgi) ); - newbon->INT += CalcRecommendedLevelBonus( lvl, reclvl, (item->AInt + item->HeroicInt) ); - newbon->WIS += CalcRecommendedLevelBonus( lvl, reclvl, (item->AWis + item->HeroicWis) ); - newbon->CHA += CalcRecommendedLevelBonus( lvl, reclvl, (item->ACha + item->HeroicCha) ); + newbon->AC += CalcRecommendedLevelBonus(lvl, rec_level, item->AC); + newbon->HP += CalcRecommendedLevelBonus(lvl, rec_level, item->HP); + newbon->Mana += CalcRecommendedLevelBonus(lvl, rec_level, item->Mana); + newbon->Endurance += CalcRecommendedLevelBonus(lvl, rec_level, item->Endur); + newbon->ATK += CalcRecommendedLevelBonus(lvl, rec_level, item->Attack); + newbon->STR += CalcRecommendedLevelBonus(lvl, rec_level, (item->AStr + item->HeroicStr)); + newbon->STA += CalcRecommendedLevelBonus(lvl, rec_level, (item->ASta + item->HeroicSta)); + newbon->DEX += CalcRecommendedLevelBonus(lvl, rec_level, (item->ADex + item->HeroicDex)); + newbon->AGI += CalcRecommendedLevelBonus(lvl, rec_level, (item->AAgi + item->HeroicAgi)); + newbon->INT += CalcRecommendedLevelBonus(lvl, rec_level, (item->AInt + item->HeroicInt)); + newbon->WIS += CalcRecommendedLevelBonus(lvl, rec_level, (item->AWis + item->HeroicWis)); + newbon->CHA += CalcRecommendedLevelBonus(lvl, rec_level, (item->ACha + item->HeroicCha)); - newbon->MR += CalcRecommendedLevelBonus( lvl, reclvl, (item->MR + item->HeroicMR) ); - newbon->FR += CalcRecommendedLevelBonus( lvl, reclvl, (item->FR + item->HeroicFR) ); - newbon->CR += CalcRecommendedLevelBonus( lvl, reclvl, (item->CR + item->HeroicCR) ); - newbon->PR += CalcRecommendedLevelBonus( lvl, reclvl, (item->PR + item->HeroicPR) ); - newbon->DR += CalcRecommendedLevelBonus( lvl, reclvl, (item->DR + item->HeroicDR) ); - newbon->Corrup += CalcRecommendedLevelBonus( lvl, reclvl, (item->SVCorruption + item->HeroicSVCorrup) ); + newbon->MR += CalcRecommendedLevelBonus(lvl, rec_level, (item->MR + item->HeroicMR)); + newbon->FR += CalcRecommendedLevelBonus(lvl, rec_level, (item->FR + item->HeroicFR)); + newbon->CR += CalcRecommendedLevelBonus(lvl, rec_level, (item->CR + item->HeroicCR)); + newbon->PR += CalcRecommendedLevelBonus(lvl, rec_level, (item->PR + item->HeroicPR)); + newbon->DR += CalcRecommendedLevelBonus(lvl, rec_level, (item->DR + item->HeroicDR)); + newbon->Corrup += + CalcRecommendedLevelBonus(lvl, rec_level, (item->SVCorruption + item->HeroicSVCorrup)); - newbon->STRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicStr ); - newbon->STACapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicSta ); - newbon->DEXCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicDex ); - newbon->AGICapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicAgi ); - newbon->INTCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicInt ); - newbon->WISCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicWis ); - newbon->CHACapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicCha ); - newbon->MRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicMR ); - newbon->CRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicFR ); - newbon->FRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicCR ); - newbon->PRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicPR ); - newbon->DRCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicDR ); - newbon->CorrupCapMod += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicSVCorrup ); + newbon->STRCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicStr); + newbon->STACapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicSta); + newbon->DEXCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicDex); + newbon->AGICapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicAgi); + newbon->INTCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicInt); + newbon->WISCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicWis); + newbon->CHACapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicCha); + newbon->MRCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicMR); + newbon->CRCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicFR); + newbon->FRCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicCR); + newbon->PRCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicPR); + newbon->DRCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicDR); + newbon->CorrupCapMod += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicSVCorrup); - newbon->HeroicSTR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicStr ); - newbon->HeroicSTA += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicSta ); - newbon->HeroicDEX += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicDex ); - newbon->HeroicAGI += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicAgi ); - newbon->HeroicINT += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicInt ); - newbon->HeroicWIS += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicWis ); - newbon->HeroicCHA += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicCha ); - newbon->HeroicMR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicMR ); - newbon->HeroicFR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicFR ); - newbon->HeroicCR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicCR ); - newbon->HeroicPR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicPR ); - newbon->HeroicDR += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicDR ); - newbon->HeroicCorrup += CalcRecommendedLevelBonus( lvl, reclvl, item->HeroicSVCorrup ); - } + newbon->HeroicSTR += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicStr); + newbon->HeroicSTA += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicSta); + newbon->HeroicDEX += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicDex); + newbon->HeroicAGI += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicAgi); + newbon->HeroicINT += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicInt); + newbon->HeroicWIS += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicWis); + newbon->HeroicCHA += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicCha); + newbon->HeroicMR += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicMR); + newbon->HeroicFR += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicFR); + newbon->HeroicCR += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicCR); + newbon->HeroicPR += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicPR); + newbon->HeroicDR += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicDR); + newbon->HeroicCorrup += CalcRecommendedLevelBonus(lvl, rec_level, item->HeroicSVCorrup); + } - //FatherNitwit: New style haste, shields, and regens - if(newbon->haste < (int32)item->Haste) { - newbon->haste = item->Haste; - } - if(item->Regen > 0) - newbon->HPRegen += item->Regen; + // FatherNitwit: New style haste, shields, and regens + if (newbon->haste < (int32)item->Haste) { + newbon->haste = item->Haste; + } + if (item->Regen > 0) + newbon->HPRegen += item->Regen; - if(item->ManaRegen > 0) - newbon->ManaRegen += item->ManaRegen; + if (item->ManaRegen > 0) + newbon->ManaRegen += item->ManaRegen; - if(item->EnduranceRegen > 0) - newbon->EnduranceRegen += item->EnduranceRegen; + if (item->EnduranceRegen > 0) + newbon->EnduranceRegen += item->EnduranceRegen; - if(item->DamageShield > 0) { - if((newbon->DamageShield + item->DamageShield) > RuleI(Character, ItemDamageShieldCap)) - newbon->DamageShield = RuleI(Character, ItemDamageShieldCap); - else - newbon->DamageShield += item->DamageShield; - } - if(item->SpellShield > 0) { - if((newbon->SpellShield + item->SpellShield) > RuleI(Character, ItemSpellShieldingCap)) - newbon->SpellShield = RuleI(Character, ItemSpellShieldingCap); - else - newbon->SpellShield += item->SpellShield; - } - if(item->Shielding > 0) { - if((newbon->MeleeMitigation + item->Shielding) > RuleI(Character, ItemShieldingCap)) - newbon->MeleeMitigation = RuleI(Character, ItemShieldingCap); - else - newbon->MeleeMitigation += item->Shielding; - } - if(item->StunResist > 0) { - if((newbon->StunResist + item->StunResist) > RuleI(Character, ItemStunResistCap)) - newbon->StunResist = RuleI(Character, ItemStunResistCap); - else - newbon->StunResist += item->StunResist; - } - if(item->StrikeThrough > 0) { - if((newbon->StrikeThrough + item->StrikeThrough) > RuleI(Character, ItemStrikethroughCap)) - newbon->StrikeThrough = RuleI(Character, ItemStrikethroughCap); - else - newbon->StrikeThrough += item->StrikeThrough; - } - if(item->Avoidance > 0) { - if((newbon->AvoidMeleeChance + item->Avoidance) > RuleI(Character, ItemAvoidanceCap)) - newbon->AvoidMeleeChance = RuleI(Character, ItemAvoidanceCap); - else - newbon->AvoidMeleeChance += item->Avoidance; - } - if(item->Accuracy > 0) { - if((newbon->HitChance + item->Accuracy) > RuleI(Character, ItemAccuracyCap)) - newbon->HitChance = RuleI(Character, ItemAccuracyCap); - else - newbon->HitChance += item->Accuracy; - } - if(item->CombatEffects > 0) { - if((newbon->ProcChance + item->CombatEffects) > RuleI(Character, ItemCombatEffectsCap)) - newbon->ProcChance = RuleI(Character, ItemCombatEffectsCap); - else - newbon->ProcChance += item->CombatEffects; - } - if(item->DotShielding > 0) { - if((newbon->DoTShielding + item->DotShielding) > RuleI(Character, ItemDoTShieldingCap)) - newbon->DoTShielding = RuleI(Character, ItemDoTShieldingCap); - else - newbon->DoTShielding += item->DotShielding; - } + if (item->DamageShield > 0) { + if ((newbon->DamageShield + item->DamageShield) > RuleI(Character, ItemDamageShieldCap)) + newbon->DamageShield = RuleI(Character, ItemDamageShieldCap); + else + newbon->DamageShield += item->DamageShield; + } + if (item->SpellShield > 0) { + if ((newbon->SpellShield + item->SpellShield) > RuleI(Character, ItemSpellShieldingCap)) + newbon->SpellShield = RuleI(Character, ItemSpellShieldingCap); + else + newbon->SpellShield += item->SpellShield; + } + if (item->Shielding > 0) { + if ((newbon->MeleeMitigation + item->Shielding) > RuleI(Character, ItemShieldingCap)) + newbon->MeleeMitigation = RuleI(Character, ItemShieldingCap); + else + newbon->MeleeMitigation += item->Shielding; + } + if (item->StunResist > 0) { + if ((newbon->StunResist + item->StunResist) > RuleI(Character, ItemStunResistCap)) + newbon->StunResist = RuleI(Character, ItemStunResistCap); + else + newbon->StunResist += item->StunResist; + } + if (item->StrikeThrough > 0) { + if ((newbon->StrikeThrough + item->StrikeThrough) > RuleI(Character, ItemStrikethroughCap)) + newbon->StrikeThrough = RuleI(Character, ItemStrikethroughCap); + else + newbon->StrikeThrough += item->StrikeThrough; + } + if (item->Avoidance > 0) { + if ((newbon->AvoidMeleeChance + item->Avoidance) > RuleI(Character, ItemAvoidanceCap)) + newbon->AvoidMeleeChance = RuleI(Character, ItemAvoidanceCap); + else + newbon->AvoidMeleeChance += item->Avoidance; + } + if (item->Accuracy > 0) { + if ((newbon->HitChance + item->Accuracy) > RuleI(Character, ItemAccuracyCap)) + newbon->HitChance = RuleI(Character, ItemAccuracyCap); + else + newbon->HitChance += item->Accuracy; + } + if (item->CombatEffects > 0) { + if ((newbon->ProcChance + item->CombatEffects) > RuleI(Character, ItemCombatEffectsCap)) + newbon->ProcChance = RuleI(Character, ItemCombatEffectsCap); + else + newbon->ProcChance += item->CombatEffects; + } + if (item->DotShielding > 0) { + if ((newbon->DoTShielding + item->DotShielding) > RuleI(Character, ItemDoTShieldingCap)) + newbon->DoTShielding = RuleI(Character, ItemDoTShieldingCap); + else + newbon->DoTShielding += item->DotShielding; + } - if(item->HealAmt > 0) { - if((newbon->HealAmt + item->HealAmt) > RuleI(Character, ItemHealAmtCap)) - newbon->HealAmt = RuleI(Character, ItemHealAmtCap); - else - newbon->HealAmt += item->HealAmt; - } - if(item->SpellDmg > 0) { - if((newbon->SpellDmg + item->SpellDmg) > RuleI(Character, ItemSpellDmgCap)) - newbon->SpellDmg = RuleI(Character, ItemSpellDmgCap); - else - newbon->SpellDmg += item->SpellDmg; - } - if(item->Clairvoyance > 0) { - if((newbon->Clairvoyance + item->Clairvoyance) > RuleI(Character, ItemClairvoyanceCap)) - newbon->Clairvoyance = RuleI(Character, ItemClairvoyanceCap); - else - newbon->Clairvoyance += item->Clairvoyance; - } + if (item->HealAmt > 0) { + if ((newbon->HealAmt + item->HealAmt) > RuleI(Character, ItemHealAmtCap)) + newbon->HealAmt = RuleI(Character, ItemHealAmtCap); + else + newbon->HealAmt += item->HealAmt; + } + if (item->SpellDmg > 0) { + if ((newbon->SpellDmg + item->SpellDmg) > RuleI(Character, ItemSpellDmgCap)) + newbon->SpellDmg = RuleI(Character, ItemSpellDmgCap); + else + newbon->SpellDmg += item->SpellDmg; + } + if (item->Clairvoyance > 0) { + if ((newbon->Clairvoyance + item->Clairvoyance) > RuleI(Character, ItemClairvoyanceCap)) + newbon->Clairvoyance = RuleI(Character, ItemClairvoyanceCap); + else + newbon->Clairvoyance += item->Clairvoyance; + } - if(item->DSMitigation > 0) { - if((newbon->DSMitigation + item->DSMitigation) > RuleI(Character, ItemDSMitigationCap)) - newbon->DSMitigation = RuleI(Character, ItemDSMitigationCap); - else - newbon->DSMitigation += item->DSMitigation; - } - if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects - ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type); - } + if (item->DSMitigation > 0) { + if ((newbon->DSMitigation + item->DSMitigation) > RuleI(Character, ItemDSMitigationCap)) + newbon->DSMitigation = RuleI(Character, ItemDSMitigationCap); + else + newbon->DSMitigation += item->DSMitigation; + } + if (item->Worn.Effect > 0 && item->Worn.Type == EQEmu::item::ItemEffectWorn) { // latent effects + ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type); + } - if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects - ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0); - } + if (item->Focus.Effect > 0 && (item->Focus.Type == EQEmu::item::ItemEffectFocus)) { // focus effects + ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0); + } - switch(item->BardType) - { - case 51: /* All (e.g. Singing Short Sword) */ - { - if(item->BardValue > newbon->singingMod) + switch (item->BardType) { + case 51: /* All (e.g. Singing Short Sword) */ + if (item->BardValue > newbon->singingMod) newbon->singingMod = item->BardValue; - if(item->BardValue > newbon->brassMod) + if (item->BardValue > newbon->brassMod) newbon->brassMod = item->BardValue; - if(item->BardValue > newbon->stringedMod) + if (item->BardValue > newbon->stringedMod) newbon->stringedMod = item->BardValue; - if(item->BardValue > newbon->percussionMod) + if (item->BardValue > newbon->percussionMod) newbon->percussionMod = item->BardValue; - if(item->BardValue > newbon->windMod) + if (item->BardValue > newbon->windMod) newbon->windMod = item->BardValue; break; - } - case 50: /* Singing */ - { - if(item->BardValue > newbon->singingMod) + case 50: /* Singing */ + if (item->BardValue > newbon->singingMod) newbon->singingMod = item->BardValue; break; - } - case 23: /* Wind */ - { - if(item->BardValue > newbon->windMod) + case 23: /* Wind */ + if (item->BardValue > newbon->windMod) newbon->windMod = item->BardValue; break; - } - case 24: /* stringed */ - { - if(item->BardValue > newbon->stringedMod) + case 24: /* stringed */ + if (item->BardValue > newbon->stringedMod) newbon->stringedMod = item->BardValue; break; - } - case 25: /* brass */ - { - if(item->BardValue > newbon->brassMod) + case 25: /* brass */ + if (item->BardValue > newbon->brassMod) newbon->brassMod = item->BardValue; break; - } - case 26: /* Percussion */ - { - if(item->BardValue > newbon->percussionMod) + case 26: /* Percussion */ + if (item->BardValue > newbon->percussionMod) newbon->percussionMod = item->BardValue; break; } + + // Add Item Faction Mods + if (item->FactionMod1) { + if (item->FactionAmt1 > 0 && item->FactionAmt1 > GetItemFactionBonus(item->FactionMod1)) { + AddItemFactionBonus(item->FactionMod1, item->FactionAmt1); + } + else if (item->FactionAmt1 < 0 && item->FactionAmt1 < GetItemFactionBonus(item->FactionMod1)) { + AddItemFactionBonus(item->FactionMod1, item->FactionAmt1); + } + } + if (item->FactionMod2) { + if (item->FactionAmt2 > 0 && item->FactionAmt2 > GetItemFactionBonus(item->FactionMod2)) { + AddItemFactionBonus(item->FactionMod2, item->FactionAmt2); + } + else if (item->FactionAmt2 < 0 && item->FactionAmt2 < GetItemFactionBonus(item->FactionMod2)) { + AddItemFactionBonus(item->FactionMod2, item->FactionAmt2); + } + } + if (item->FactionMod3) { + if (item->FactionAmt3 > 0 && item->FactionAmt3 > GetItemFactionBonus(item->FactionMod3)) { + AddItemFactionBonus(item->FactionMod3, item->FactionAmt3); + } + else if (item->FactionAmt3 < 0 && item->FactionAmt3 < GetItemFactionBonus(item->FactionMod3)) { + AddItemFactionBonus(item->FactionMod3, item->FactionAmt3); + } + } + if (item->FactionMod4) { + if (item->FactionAmt4 > 0 && item->FactionAmt4 > GetItemFactionBonus(item->FactionMod4)) { + AddItemFactionBonus(item->FactionMod4, item->FactionAmt4); + } + else if (item->FactionAmt4 < 0 && item->FactionAmt4 < GetItemFactionBonus(item->FactionMod4)) { + AddItemFactionBonus(item->FactionMod4, item->FactionAmt4); + } + } + + if (item->ExtraDmgSkill != 0 && item->ExtraDmgSkill <= EQEmu::skills::HIGHEST_SKILL) { + if ((newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > + RuleI(Character, ItemExtraDmgCap)) + newbon->SkillDamageAmount[item->ExtraDmgSkill] = RuleI(Character, ItemExtraDmgCap); + else + newbon->SkillDamageAmount[item->ExtraDmgSkill] += item->ExtraDmgAmt; + } } - if (item->SkillModValue != 0 && item->SkillModType <= HIGHEST_SKILL){ + // Process when ammo_slot_item = true or false + if (item->SkillModValue != 0 && item->SkillModType <= EQEmu::skills::HIGHEST_SKILL) { if ((item->SkillModValue > 0 && newbon->skillmod[item->SkillModType] < item->SkillModValue) || - (item->SkillModValue < 0 && newbon->skillmod[item->SkillModType] > item->SkillModValue)) - { + (item->SkillModValue < 0 && newbon->skillmod[item->SkillModType] > item->SkillModValue)) { + newbon->skillmod[item->SkillModType] = item->SkillModValue; + newbon->skillmodmax[item->SkillModType] = item->SkillModMax; } } - // Add Item Faction Mods - if (item->FactionMod1) - { - if (item->FactionAmt1 > 0 && item->FactionAmt1 > GetItemFactionBonus(item->FactionMod1)) - { - AddItemFactionBonus(item->FactionMod1, item->FactionAmt1); - } - else if (item->FactionAmt1 < 0 && item->FactionAmt1 < GetItemFactionBonus(item->FactionMod1)) - { - AddItemFactionBonus(item->FactionMod1, item->FactionAmt1); - } + if (!isAug) { + for (int i = 0; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) + AddItemBonuses(inst->GetAugment(i), newbon, true, false, rec_level, ammo_slot_item); } - if (item->FactionMod2) - { - if (item->FactionAmt2 > 0 && item->FactionAmt2 > GetItemFactionBonus(item->FactionMod2)) - { - AddItemFactionBonus(item->FactionMod2, item->FactionAmt2); - } - else if (item->FactionAmt2 < 0 && item->FactionAmt2 < GetItemFactionBonus(item->FactionMod2)) - { - AddItemFactionBonus(item->FactionMod2, item->FactionAmt2); - } - } - if (item->FactionMod3) - { - if (item->FactionAmt3 > 0 && item->FactionAmt3 > GetItemFactionBonus(item->FactionMod3)) - { - AddItemFactionBonus(item->FactionMod3, item->FactionAmt3); - } - else if (item->FactionAmt3 < 0 && item->FactionAmt3 < GetItemFactionBonus(item->FactionMod3)) - { - AddItemFactionBonus(item->FactionMod3, item->FactionAmt3); - } - } - if (item->FactionMod4) - { - if (item->FactionAmt4 > 0 && item->FactionAmt4 > GetItemFactionBonus(item->FactionMod4)) - { - AddItemFactionBonus(item->FactionMod4, item->FactionAmt4); - } - else if (item->FactionAmt4 < 0 && item->FactionAmt4 < GetItemFactionBonus(item->FactionMod4)) - { - AddItemFactionBonus(item->FactionMod4, item->FactionAmt4); - } - } - - if (item->ExtraDmgSkill != 0 && item->ExtraDmgSkill <= HIGHEST_SKILL) { - if((newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap)) - newbon->SkillDamageAmount[item->ExtraDmgSkill] = RuleI(Character, ItemExtraDmgCap); - else - newbon->SkillDamageAmount[item->ExtraDmgSkill] += item->ExtraDmgAmt; - } - - if (!isAug) - { - int i; - for (i = 0; i < EmuConstants::ITEM_COMMON_SIZE; i++) { - AddItemBonuses(inst->GetAugment(i),newbon,true); - } - } - } void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug) { @@ -559,27 +537,27 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool /* Powerful Non-live like option allows developers to add worn effects on items that can stack with other worn effects of the same spell effect type, instead of only taking the highest value. - Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus. + Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus. To enable use RuleI(Spells, AdditiveBonusWornType) Setting value = 2 Will force all live items to automatically be calculated additivily Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation which will also stack with regular (worntype 2) effects. [Ie set rule = 3 and item worntype = 3] */ - if(!inst || !inst->IsType(ItemClassCommon)) + if (!inst || !inst->IsClassCommon()) return; if(inst->GetAugmentType()==0 && isAug == true) return; - const Item_Struct *item = inst->GetItem(); + const EQEmu::ItemBase *item = inst->GetItem(); if(!inst->IsEquipable(GetBaseRace(),GetClass())) return; if(GetLevel() < item->ReqLevel) return; - + if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType)) ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);// Non-live like - Addititive latent effects @@ -587,7 +565,7 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool if (!isAug) { int i; - for (i = 0; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + for (i = 0; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { AdditiveWornBonuses(inst->GetAugment(i),newbon,true); } } @@ -598,32 +576,32 @@ void Client::CalcEdibleBonuses(StatBonuses* newbon) { bool food = false; bool drink = false; - for (i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_BAGS_BEGIN; i++) + for (i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_BAGS_BEGIN; i++) { if (food && drink) break; const ItemInst* inst = GetInv().GetItem(i); - if (inst && inst->GetItem() && inst->IsType(ItemClassCommon)) { - const Item_Struct *item=inst->GetItem(); - if (item->ItemType == ItemTypeFood && !food) + if (inst && inst->GetItem() && inst->IsClassCommon()) { + const EQEmu::ItemBase *item = inst->GetItem(); + if (item->ItemType == EQEmu::item::ItemTypeFood && !food) food = true; - else if (item->ItemType == ItemTypeDrink && !drink) + else if (item->ItemType == EQEmu::item::ItemTypeDrink && !drink) drink = true; else continue; AddItemBonuses(inst, newbon); } } - for (i = EmuConstants::GENERAL_BAGS_BEGIN; i <= EmuConstants::GENERAL_BAGS_END; i++) + for (i = EQEmu::legacy::GENERAL_BAGS_BEGIN; i <= EQEmu::legacy::GENERAL_BAGS_END; i++) { if (food && drink) break; const ItemInst* inst = GetInv().GetItem(i); - if (inst && inst->GetItem() && inst->IsType(ItemClassCommon)) { - const Item_Struct *item=inst->GetItem(); - if (item->ItemType == ItemTypeFood && !food) + if (inst && inst->GetItem() && inst->IsClassCommon()) { + const EQEmu::ItemBase *item = inst->GetItem(); + if (item->ItemType == EQEmu::item::ItemTypeFood && !food) food = true; - else if (item->ItemType == ItemTypeDrink && !drink) + else if (item->ItemType == EQEmu::item::ItemTypeDrink && !drink) drink = true; else continue; @@ -632,809 +610,894 @@ void Client::CalcEdibleBonuses(StatBonuses* newbon) { } } -void Client::CalcAABonuses(StatBonuses* newbon) { - memset(newbon, 0, sizeof(StatBonuses)); //start fresh +void Mob::CalcAABonuses(StatBonuses *newbon) +{ + memset(newbon, 0, sizeof(StatBonuses)); // start fresh - int i; - uint32 slots = 0; - uint32 aa_AA = 0; - uint32 aa_value = 0; - if(this->aa) { - for (i = 0; i < MAX_PP_AA_ARRAY; i++) { //iterate through all of the client's AAs - if (this->aa[i]) { // make sure aa exists or we'll crash zone - aa_AA = this->aa[i]->AA; //same as aaid from the aa_effects table - aa_value = this->aa[i]->value; //how many points in it - if (aa_AA > 0 || aa_value > 0) { //do we have the AA? if 1 of the 2 is set, we can assume we do - //slots = database.GetTotalAALevels(aa_AA); //find out how many effects from aa_effects table - slots = zone->GetTotalAALevels(aa_AA); //find out how many effects from aa_effects, which is loaded into memory - if (slots > 0) //and does it have any effects? may be able to put this above, not sure if it runs on each iteration - ApplyAABonuses(aa_AA, slots, newbon); //add the bonuses - } - } + for (const auto &aa : aa_ranks) { + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first); + auto ability = ability_rank.first; + auto rank = ability_rank.second; + + if(!ability) { + continue; } + + // bad data or no effects + if (rank->effects.empty()) + continue; + + ApplyAABonuses(*rank, newbon); } } - //A lot of the normal spell functions (IsBlankSpellEffect, etc) are set for just spells (in common/spdat.h). //For now, we'll just put them directly into the code and comment with the corresponding normal function //Maybe we'll fix it later? :-D -void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) +void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon) { - if(slots == 0) //sanity check. why bother if no slots to fill? + if (rank.effects.empty()) // sanity check. why bother if no slots to fill? return; - //from AA_Ability struct uint32 effect = 0; int32 base1 = 0; - int32 base2 = 0; //only really used for SE_RaiseStatCap & SE_ReduceSkillTimer in aa_effects table + int32 base2 = 0; // only really used for SE_RaiseStatCap & SE_ReduceSkillTimer in aa_effects table uint32 slot = 0; - std::map >::const_iterator find_iter = aa_effects.find(aaid); - if(find_iter == aa_effects.end()) - { - return; - } + for (const auto &e : rank.effects) { + effect = e.effect_id; + base1 = e.base1; + base2 = e.base2; + slot = e.slot; - for (std::map::const_iterator iter = aa_effects[aaid].begin(); iter != aa_effects[aaid].end(); ++iter) { - effect = iter->second.skill_id; - base1 = iter->second.base1; - base2 = iter->second.base2; - slot = iter->second.slot; - - //we default to 0 (SE_CurrentHP) for the effect, so if there aren't any base1/2 values, we'll just skip it + // we default to 0 (SE_CurrentHP) for the effect, so if there aren't any base1/2 values, we'll just skip it if (effect == 0 && base1 == 0 && base2 == 0) continue; - //IsBlankSpellEffect() - if (effect == SE_Blank || (effect == SE_CHA && base1 == 0) || effect == SE_StackingCommand_Block || effect == SE_StackingCommand_Overwrite) + // IsBlankSpellEffect() + if (effect == SE_Blank || (effect == SE_CHA && base1 == 0) || effect == SE_StackingCommand_Block || + effect == SE_StackingCommand_Overwrite) continue; - Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName()); - - uint8 focus = IsFocusEffect(0, 0, true,effect); - if (focus) - { + Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", + effect, rank.id, slot, base1, base2, GetCleanName()); + + uint8 focus = IsFocusEffect(0, 0, true, effect); + if (focus) { newbon->FocusEffects[focus] = static_cast(effect); continue; } - switch (effect) - { - //Note: AA effects that use accuracy are skill limited, while spell effect is not. - case SE_Accuracy: - if ((base2 == ALL_SKILLS) && (newbon->Accuracy[HIGHEST_SKILL+1] < base1)) - newbon->Accuracy[HIGHEST_SKILL+1] = base1; - else if (newbon->Accuracy[base2] < base1) - newbon->Accuracy[base2] += base1; - break; - case SE_CurrentHP: //regens - newbon->HPRegen += base1; - break; - case SE_CurrentEndurance: - newbon->EnduranceRegen += base1; - break; - case SE_MovementSpeed: - newbon->movementspeed += base1; //should we let these stack? - /*if (base1 > newbon->movementspeed) //or should we use a total value? - newbon->movementspeed = base1;*/ - break; - case SE_STR: - newbon->STR += base1; - break; - case SE_DEX: - newbon->DEX += base1; - break; - case SE_AGI: - newbon->AGI += base1; - break; - case SE_STA: - newbon->STA += base1; - break; - case SE_INT: - newbon->INT += base1; - break; - case SE_WIS: - newbon->WIS += base1; - break; - case SE_CHA: - newbon->CHA += base1; - break; - case SE_WaterBreathing: - //handled by client - break; - case SE_CurrentMana: - newbon->ManaRegen += base1; - break; - case SE_ItemManaRegenCapIncrease: - newbon->ItemManaRegenCap += base1; - break; - case SE_ResistFire: - newbon->FR += base1; - break; - case SE_ResistCold: - newbon->CR += base1; - break; - case SE_ResistPoison: - newbon->PR += base1; - break; - case SE_ResistDisease: - newbon->DR += base1; - break; - case SE_ResistMagic: - newbon->MR += base1; - break; - case SE_ResistCorruption: - newbon->Corrup += base1; - break; - case SE_IncreaseSpellHaste: - break; - case SE_IncreaseRange: - break; - case SE_MaxHPChange: - newbon->MaxHP += base1; - break; - case SE_Packrat: - newbon->Packrat += base1; - break; - case SE_TwoHandBash: - break; - case SE_SetBreathLevel: - break; - case SE_RaiseStatCap: - switch(base2) - { - //are these #define'd somewhere? - case 0: //str - newbon->STRCapMod += base1; - break; - case 1: //sta - newbon->STACapMod += base1; - break; - case 2: //agi - newbon->AGICapMod += base1; - break; - case 3: //dex - newbon->DEXCapMod += base1; - break; - case 4: //wis - newbon->WISCapMod += base1; - break; - case 5: //int - newbon->INTCapMod += base1; - break; - case 6: //cha - newbon->CHACapMod += base1; - break; - case 7: //mr - newbon->MRCapMod += base1; - break; - case 8: //cr - newbon->CRCapMod += base1; - break; - case 9: //fr - newbon->FRCapMod += base1; - break; - case 10: //pr - newbon->PRCapMod += base1; - break; - case 11: //dr - newbon->DRCapMod += base1; - break; - case 12: //corruption - newbon->CorrupCapMod += base1; - break; - } - break; - case SE_PetDiscipline2: - break; - case SE_SpellSlotIncrease: - break; - case SE_MysticalAttune: - newbon->BuffSlotIncrease += base1; - break; - case SE_TotalHP: - newbon->HP += base1; - break; - case SE_StunResist: - newbon->StunResist += base1; - break; - case SE_SpellCritChance: - newbon->CriticalSpellChance += base1; - break; - case SE_SpellCritDmgIncrease: - newbon->SpellCritDmgIncrease += base1; - break; - case SE_DotCritDmgIncrease: - newbon->DotCritDmgIncrease += base1; - break; - case SE_ResistSpellChance: - newbon->ResistSpellChance += base1; - break; - case SE_CriticalHealChance: - newbon->CriticalHealChance += base1; - break; - case SE_CriticalHealOverTime: - newbon->CriticalHealOverTime += base1; - break; - case SE_CriticalDoTChance: - newbon->CriticalDoTChance += base1; - break; - case SE_ReduceSkillTimer: - newbon->SkillReuseTime[base2] += base1; - break; - case SE_Fearless: - newbon->Fearless = true; - break; - case SE_PersistantCasting: - newbon->PersistantCasting += base1; - break; - case SE_DelayDeath: - newbon->DelayDeath += base1; - break; - case SE_FrontalStunResist: - newbon->FrontalStunResist += base1; - break; - case SE_ImprovedBindWound: - newbon->BindWound += base1; - break; - case SE_MaxBindWound: - newbon->MaxBindWound += base1; - break; - case SE_ExtraAttackChance: - newbon->ExtraAttackChance += base1; - break; - case SE_SeeInvis: - newbon->SeeInvis = base1; - break; - case SE_BaseMovementSpeed: - newbon->BaseMovementSpeed += base1; - break; - case SE_IncreaseRunSpeedCap: - newbon->IncreaseRunSpeedCap += base1; - break; - case SE_ConsumeProjectile: - newbon->ConsumeProjectile += base1; - break; - case SE_ForageAdditionalItems: - newbon->ForageAdditionalItems += base1; - break; - case SE_Salvage: - newbon->SalvageChance += base1; - break; - case SE_ArcheryDamageModifier: - newbon->ArcheryDamageModifier += base1; - break; - case SE_DoubleRangedAttack: - newbon->DoubleRangedAttack += base1; - break; - case SE_DamageShield: - newbon->DamageShield += base1; - break; - case SE_CharmBreakChance: - newbon->CharmBreakChance += base1; - break; - case SE_OffhandRiposteFail: - newbon->OffhandRiposteFail += base1; - break; - case SE_ItemAttackCapIncrease: - newbon->ItemATKCap += base1; - break; - case SE_GivePetGroupTarget: - newbon->GivePetGroupTarget = true; - break; - case SE_ItemHPRegenCapIncrease: - newbon->ItemHPRegenCap = +base1; - break; - case SE_Ambidexterity: - newbon->Ambidexterity += base1; - break; - case SE_PetMaxHP: - newbon->PetMaxHP += base1; - break; - case SE_AvoidMeleeChance: - newbon->AvoidMeleeChanceEffect += base1; - break; - case SE_CombatStability: - newbon->CombatStability += base1; - break; - case SE_AddSingingMod: - switch (base2) - { - case ItemTypeWindInstrument: - newbon->windMod += base1; - break; - case ItemTypeStringedInstrument: - newbon->stringedMod += base1; - break; - case ItemTypeBrassInstrument: - newbon->brassMod += base1; - break; - case ItemTypePercussionInstrument: - newbon->percussionMod += base1; - break; - case ItemTypeSinging: - newbon->singingMod += base1; - break; - } - break; - case SE_SongModCap: - newbon->songModCap += base1; - break; - case SE_PetCriticalHit: - newbon->PetCriticalHit += base1; - break; - case SE_PetAvoidance: - newbon->PetAvoidance += base1; - break; - case SE_ShieldBlock: - newbon->ShieldBlock += base1; - break; - case SE_ShieldEquipHateMod: - newbon->ShieldEquipHateMod += base1; - break; - case SE_ShieldEquipDmgMod: - newbon->ShieldEquipDmgMod[0] += base1; - newbon->ShieldEquipDmgMod[1] += base2; - break; - case SE_SecondaryDmgInc: - newbon->SecondaryDmgInc = true; - break; - case SE_ChangeAggro: - newbon->hatemod += base1; - break; - case SE_EndurancePool: - newbon->Endurance += base1; - break; - case SE_ChannelChanceItems: - newbon->ChannelChanceItems += base1; - break; - case SE_ChannelChanceSpells: - newbon->ChannelChanceSpells += base1; - break; - case SE_DoubleSpecialAttack: - newbon->DoubleSpecialAttack += base1; - break; - case SE_TripleBackstab: - newbon->TripleBackstab += base1; - break; - case SE_FrontalBackstabMinDmg: - newbon->FrontalBackstabMinDmg = true; - break; - case SE_FrontalBackstabChance: - newbon->FrontalBackstabChance += base1; - break; - case SE_BlockBehind: - newbon->BlockBehind += base1; - break; - - case SE_StrikeThrough: - case SE_StrikeThrough2: - newbon->StrikeThrough += base1; - break; - case SE_DoubleAttackChance: - newbon->DoubleAttackChance += base1; - break; - case SE_GiveDoubleAttack: - newbon->GiveDoubleAttack += base1; - break; - case SE_ProcChance: - newbon->ProcChanceSPA += base1; - break; - case SE_RiposteChance: - newbon->RiposteChance += base1; - break; - case SE_Flurry: - newbon->FlurryChance += base1; - break; - case SE_PetFlurry: - newbon->PetFlurry += base1; - break; - case SE_BardSongRange: - newbon->SongRange += base1; - break; - case SE_RootBreakChance: - newbon->RootBreakChance += base1; - break; - case SE_UnfailingDivinity: - newbon->UnfailingDivinity += base1; - break; - case SE_CrippBlowChance: - newbon->CrippBlowChance += base1; - break; - - case SE_HitChance: - { - if(base2 == ALL_SKILLS) - newbon->HitChanceEffect[HIGHEST_SKILL+1] += base1; - else - newbon->HitChanceEffect[base2] += base1; - } - - case SE_ProcOnKillShot: - for(int i = 0; i < MAX_SPELL_TRIGGER*3; i+=3) - { - if(!newbon->SpellOnKill[i] || ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i+1] < base1))) - { - //base1 = chance, base2 = SpellID to be triggered, base3 = min npc level - newbon->SpellOnKill[i] = base2; - newbon->SpellOnKill[i+1] = base1; - - if (GetLevel() > 15) - newbon->SpellOnKill[i+2] = GetLevel() - 15; //AA specifiy "non-trivial" - else - newbon->SpellOnKill[i+2] = 0; - - break; - } - } + switch (effect) { + // Note: AA effects that use accuracy are skill limited, while spell effect is not. + case SE_Accuracy: + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + if ((base2 == ALL_SKILLS) && (newbon->Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] < base1)) + newbon->Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] = base1; + else if (newbon->Accuracy[base2] < base1) + newbon->Accuracy[base2] += base1; break; - - case SE_SpellOnDeath: - for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2) - { - if(!newbon->SpellOnDeath[i]) - { - // base1 = SpellID to be triggered, base2 = chance to fire - newbon->SpellOnDeath[i] = base1; - newbon->SpellOnDeath[i+1] = base2; - break; - } - } + case SE_CurrentHP: // regens + newbon->HPRegen += base1; break; - - case SE_TriggerOnCast: - - for(int i = 0; i < MAX_SPELL_TRIGGER; i++) - { - if (newbon->SpellTriggers[i] == aaid) - break; - - if(!newbon->SpellTriggers[i]) - { - //Save the 'aaid' of each triggerable effect to an array - newbon->SpellTriggers[i] = aaid; - break; - } - } + case SE_CurrentEndurance: + newbon->EnduranceRegen += base1; break; - - case SE_CriticalHitChance: - { - if(base2 == ALL_SKILLS) - newbon->CriticalHitChance[HIGHEST_SKILL+1] += base1; - else - newbon->CriticalHitChance[base2] += base1; + case SE_MovementSpeed: + newbon->movementspeed += base1; // should we let these stack? + /*if (base1 > newbon->movementspeed) //or should we use a total value? + newbon->movementspeed = base1;*/ + break; + case SE_STR: + newbon->STR += base1; + break; + case SE_DEX: + newbon->DEX += base1; + break; + case SE_AGI: + newbon->AGI += base1; + break; + case SE_STA: + newbon->STA += base1; + break; + case SE_INT: + newbon->INT += base1; + break; + case SE_WIS: + newbon->WIS += base1; + break; + case SE_CHA: + newbon->CHA += base1; + break; + case SE_WaterBreathing: + // handled by client + break; + case SE_CurrentMana: + newbon->ManaRegen += base1; + break; + case SE_ManaPool: + newbon->Mana += base1; + break; + case SE_ItemManaRegenCapIncrease: + newbon->ItemManaRegenCap += base1; + break; + case SE_ResistFire: + newbon->FR += base1; + break; + case SE_ResistCold: + newbon->CR += base1; + break; + case SE_ResistPoison: + newbon->PR += base1; + break; + case SE_ResistDisease: + newbon->DR += base1; + break; + case SE_ResistMagic: + newbon->MR += base1; + break; + case SE_ResistCorruption: + newbon->Corrup += base1; + break; + case SE_IncreaseSpellHaste: + break; + case SE_IncreaseRange: + break; + case SE_MaxHPChange: + newbon->MaxHP += base1; + break; + case SE_Packrat: + newbon->Packrat += base1; + break; + case SE_TwoHandBash: + break; + case SE_SetBreathLevel: + break; + case SE_RaiseStatCap: + switch (base2) { + // are these #define'd somewhere? + case 0: // str + newbon->STRCapMod += base1; + break; + case 1: // sta + newbon->STACapMod += base1; + break; + case 2: // agi + newbon->AGICapMod += base1; + break; + case 3: // dex + newbon->DEXCapMod += base1; + break; + case 4: // wis + newbon->WISCapMod += base1; + break; + case 5: // int + newbon->INTCapMod += base1; + break; + case 6: // cha + newbon->CHACapMod += base1; + break; + case 7: // mr + newbon->MRCapMod += base1; + break; + case 8: // cr + newbon->CRCapMod += base1; + break; + case 9: // fr + newbon->FRCapMod += base1; + break; + case 10: // pr + newbon->PRCapMod += base1; + break; + case 11: // dr + newbon->DRCapMod += base1; + break; + case 12: // corruption + newbon->CorrupCapMod += base1; + break; } break; - - case SE_CriticalDamageMob: - { - // base1 = effect value, base2 = skill restrictions(-1 for all) - if(base2 == ALL_SKILLS) - newbon->CritDmgMob[HIGHEST_SKILL+1] += base1; - else - newbon->CritDmgMob[base2] += base1; + case SE_SpellSlotIncrease: + break; + case SE_MysticalAttune: + newbon->BuffSlotIncrease += base1; + break; + case SE_TotalHP: + newbon->HP += base1; + break; + case SE_StunResist: + newbon->StunResist += base1; + break; + case SE_SpellCritChance: + newbon->CriticalSpellChance += base1; + break; + case SE_SpellCritDmgIncrease: + newbon->SpellCritDmgIncrease += base1; + break; + case SE_DotCritDmgIncrease: + newbon->DotCritDmgIncrease += base1; + break; + case SE_ResistSpellChance: + newbon->ResistSpellChance += base1; + break; + case SE_CriticalHealChance: + newbon->CriticalHealChance += base1; + break; + case SE_CriticalHealOverTime: + newbon->CriticalHealOverTime += base1; + break; + case SE_CriticalDoTChance: + newbon->CriticalDoTChance += base1; + break; + case SE_ReduceSkillTimer: + newbon->SkillReuseTime[base2] += base1; + break; + case SE_Fearless: + newbon->Fearless = true; + break; + case SE_PersistantCasting: + newbon->PersistantCasting += base1; + break; + case SE_DelayDeath: + newbon->DelayDeath += base1; + break; + case SE_FrontalStunResist: + newbon->FrontalStunResist += base1; + break; + case SE_ImprovedBindWound: + newbon->BindWound += base1; + break; + case SE_MaxBindWound: + newbon->MaxBindWound += base1; + break; + case SE_ExtraAttackChance: + newbon->ExtraAttackChance += base1; + break; + case SE_SeeInvis: + newbon->SeeInvis = base1; + break; + case SE_BaseMovementSpeed: + newbon->BaseMovementSpeed += base1; + break; + case SE_IncreaseRunSpeedCap: + newbon->IncreaseRunSpeedCap += base1; + break; + case SE_ConsumeProjectile: + newbon->ConsumeProjectile += base1; + break; + case SE_ForageAdditionalItems: + newbon->ForageAdditionalItems += base1; + break; + case SE_Salvage: + newbon->SalvageChance += base1; + break; + case SE_ArcheryDamageModifier: + newbon->ArcheryDamageModifier += base1; + break; + case SE_DoubleRangedAttack: + newbon->DoubleRangedAttack += base1; + break; + case SE_DamageShield: + newbon->DamageShield += base1; + break; + case SE_CharmBreakChance: + newbon->CharmBreakChance += base1; + break; + case SE_OffhandRiposteFail: + newbon->OffhandRiposteFail += base1; + break; + case SE_ItemAttackCapIncrease: + newbon->ItemATKCap += base1; + break; + case SE_GivePetGroupTarget: + newbon->GivePetGroupTarget = true; + break; + case SE_ItemHPRegenCapIncrease: + newbon->ItemHPRegenCap = +base1; + break; + case SE_Ambidexterity: + newbon->Ambidexterity += base1; + break; + case SE_PetMaxHP: + newbon->PetMaxHP += base1; + break; + case SE_AvoidMeleeChance: + newbon->AvoidMeleeChanceEffect += base1; + break; + case SE_CombatStability: + newbon->CombatStability += base1; + break; + case SE_AddSingingMod: + switch (base2) { + case EQEmu::item::ItemTypeWindInstrument: + newbon->windMod += base1; + break; + case EQEmu::item::ItemTypeStringedInstrument: + newbon->stringedMod += base1; + break; + case EQEmu::item::ItemTypeBrassInstrument: + newbon->brassMod += base1; + break; + case EQEmu::item::ItemTypePercussionInstrument: + newbon->percussionMod += base1; + break; + case EQEmu::item::ItemTypeSinging: + newbon->singingMod += base1; break; } + break; + case SE_SongModCap: + newbon->songModCap += base1; + break; + case SE_PetCriticalHit: + newbon->PetCriticalHit += base1; + break; + case SE_PetAvoidance: + newbon->PetAvoidance += base1; + break; + case SE_ShieldBlock: + newbon->ShieldBlock += base1; + break; + case SE_ShieldEquipHateMod: + newbon->ShieldEquipHateMod += base1; + break; + case SE_ShieldEquipDmgMod: + newbon->ShieldEquipDmgMod[0] += base1; + newbon->ShieldEquipDmgMod[1] += base2; + break; + case SE_SecondaryDmgInc: + newbon->SecondaryDmgInc = true; + break; + case SE_ChangeAggro: + newbon->hatemod += base1; + break; + case SE_EndurancePool: + newbon->Endurance += base1; + break; + case SE_ChannelChanceItems: + newbon->ChannelChanceItems += base1; + break; + case SE_ChannelChanceSpells: + newbon->ChannelChanceSpells += base1; + break; + case SE_DoubleSpecialAttack: + newbon->DoubleSpecialAttack += base1; + break; + case SE_TripleBackstab: + newbon->TripleBackstab += base1; + break; + case SE_FrontalBackstabMinDmg: + newbon->FrontalBackstabMinDmg = true; + break; + case SE_FrontalBackstabChance: + newbon->FrontalBackstabChance += base1; + break; + case SE_BlockBehind: + newbon->BlockBehind += base1; + break; - case SE_CriticalSpellChance: - { - newbon->CriticalSpellChance += base1; - - if (base2 > newbon->SpellCritDmgIncNoStack) - newbon->SpellCritDmgIncNoStack = base2; + case SE_StrikeThrough: + case SE_StrikeThrough2: + newbon->StrikeThrough += base1; + break; + case SE_DoubleAttackChance: + newbon->DoubleAttackChance += base1; + break; + case SE_GiveDoubleAttack: + newbon->GiveDoubleAttack += base1; + break; + case SE_ProcChance: + newbon->ProcChanceSPA += base1; + break; + case SE_RiposteChance: + newbon->RiposteChance += base1; + break; + case SE_Flurry: + newbon->FlurryChance += base1; + break; + case SE_PetFlurry: + newbon->PetFlurry += base1; + break; + case SE_BardSongRange: + newbon->SongRange += base1; + break; + case SE_RootBreakChance: + newbon->RootBreakChance += base1; + break; + case SE_UnfailingDivinity: + newbon->UnfailingDivinity += base1; + break; + case SE_CrippBlowChance: + newbon->CrippBlowChance += base1; + break; + case SE_HitChance: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) break; - } - - case SE_ResistFearChance: - { - if(base1 == 100) // If we reach 100% in a single spell/item then we should be immune to negative fear resist effects until our immunity is over - newbon->Fearless = true; - - newbon->ResistFearChance += base1; // these should stack - break; - } - - case SE_SkillDamageAmount: - { - if(base2 == ALL_SKILLS) - newbon->SkillDamageAmount[HIGHEST_SKILL+1] += base1; - else - newbon->SkillDamageAmount[base2] += base1; - break; - } - - case SE_SpecialAttackKBProc: - { - //You can only have one of these per client. [AA Dragon Punch] - newbon->SpecialAttackKBProc[0] = base1; //Chance base 100 = 25% proc rate - newbon->SpecialAttackKBProc[1] = base2; //Skill to KB Proc Off - break; - } - - case SE_DamageModifier: - { - if(base2 == ALL_SKILLS) - newbon->DamageModifier[HIGHEST_SKILL+1] += base1; - else - newbon->DamageModifier[base2] += base1; - break; - } - - case SE_DamageModifier2: - { - if(base2 == ALL_SKILLS) - newbon->DamageModifier2[HIGHEST_SKILL+1] += base1; - else - newbon->DamageModifier2[base2] += base1; - break; - } - - case SE_SlayUndead: - { - if(newbon->SlayUndead[1] < base1) - newbon->SlayUndead[0] = base1; // Rate - newbon->SlayUndead[1] = base2; // Damage Modifier - break; - } - - case SE_DoubleRiposte: - { - newbon->DoubleRiposte += base1; - } - - case SE_GiveDoubleRiposte: - { - //0=Regular Riposte 1=Skill Attack Riposte 2=Skill - if(base2 == 0){ - if(newbon->GiveDoubleRiposte[0] < base1) - newbon->GiveDoubleRiposte[0] = base1; - } - //Only for special attacks. - else if(base2 > 0 && (newbon->GiveDoubleRiposte[1] < base1)){ - newbon->GiveDoubleRiposte[1] = base1; - newbon->GiveDoubleRiposte[2] = base2; - } - - break; - } - - //Kayen: Not sure best way to implement this yet. - //Physically raises skill cap ie if 55/55 it will raise to 55/60 - case SE_RaiseSkillCap: - { - if(newbon->RaiseSkillCap[0] < base1){ - newbon->RaiseSkillCap[0] = base1; //value - newbon->RaiseSkillCap[1] = base2; //skill - } - break; - } - - case SE_MasteryofPast: - { - if(newbon->MasteryofPast < base1) - newbon->MasteryofPast = base1; - break; - } - - case SE_CastingLevel2: - case SE_CastingLevel: - { - newbon->effective_casting_level += base1; - break; - } - - case SE_DivineSave: - { - if(newbon->DivineSaveChance[0] < base1) - { - newbon->DivineSaveChance[0] = base1; - newbon->DivineSaveChance[1] = base2; - } - break; - } - - - case SE_SpellEffectResistChance: - { - for(int e = 0; e < MAX_RESISTABLE_EFFECTS*2; e+=2) - { - if(newbon->SEResist[e+1] && (newbon->SEResist[e] == base2) && (newbon->SEResist[e+1] < base1)){ - newbon->SEResist[e] = base2; //Spell Effect ID - newbon->SEResist[e+1] = base1; //Resist Chance - break; - } - else if (!newbon->SEResist[e+1]){ - newbon->SEResist[e] = base2; //Spell Effect ID - newbon->SEResist[e+1] = base1; //Resist Chance - break; - } - } - break; - } - - case SE_MitigateDamageShield: - { - if (base1 < 0) - base1 = base1*(-1); - - newbon->DSMitigationOffHand += base1; - break; - } - - case SE_FinishingBlow: - { - //base1 = chance, base2 = damage - if (newbon->FinishingBlow[1] < base2){ - newbon->FinishingBlow[0] = base1; - newbon->FinishingBlow[1] = base2; - } - break; - } - - case SE_FinishingBlowLvl: - { - //base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?) - if (newbon->FinishingBlowLvl[0] < base1){ - newbon->FinishingBlowLvl[0] = base1; - newbon->FinishingBlowLvl[1] = base2; - } - break; - } - - case SE_StunBashChance: - newbon->StunBashChance += base1; - break; - - case SE_IncreaseChanceMemwipe: - newbon->IncreaseChanceMemwipe += base1; - break; - - case SE_CriticalMend: - newbon->CriticalMend += base1; - break; - - case SE_HealRate: - newbon->HealRate += base1; - break; - - case SE_MeleeLifetap: - { - - if((base1 < 0) && (newbon->MeleeLifetap > base1)) - newbon->MeleeLifetap = base1; - - else if(newbon->MeleeLifetap < base1) - newbon->MeleeLifetap = base1; - break; - } - - case SE_Vampirism: - newbon->Vampirism += base1; - break; - - case SE_FrenziedDevastation: - newbon->FrenziedDevastation += base2; - break; - - case SE_SpellProcChance: - newbon->SpellProcChance += base1; - break; - - case SE_Berserk: - newbon->BerserkSPA = true; - break; - - case SE_Metabolism: - newbon->Metabolism += base1; - break; - - case SE_ImprovedReclaimEnergy: - { - if((base1 < 0) && (newbon->ImprovedReclaimEnergy > base1)) - newbon->ImprovedReclaimEnergy = base1; - - else if(newbon->ImprovedReclaimEnergy < base1) - newbon->ImprovedReclaimEnergy = base1; - break; - } - - case SE_HeadShot: - { - if(newbon->HeadShot[1] < base2){ - newbon->HeadShot[0] = base1; - newbon->HeadShot[1] = base2; - } - break; - } - - case SE_HeadShotLevel: - { - if(newbon->HSLevel < base1) - newbon->HSLevel = base1; - break; - } - - case SE_Assassinate: - { - if(newbon->Assassinate[1] < base2){ - newbon->Assassinate[0] = base1; - newbon->Assassinate[1] = base2; - } - break; - } - - case SE_AssassinateLevel: - { - if(newbon->AssassinateLevel < base1) - newbon->AssassinateLevel = base1; - break; - } - - case SE_PetMeleeMitigation: - newbon->PetMeleeMitigation += base1; - break; - - case SE_MeleeVulnerability: - newbon->MeleeVulnerability += base1; - break; - - case SE_FactionModPct: - { - if((base1 < 0) && (newbon->FactionModPct > base1)) - newbon->FactionModPct = base1; - - else if(newbon->FactionModPct < base1) - newbon->FactionModPct = base1; - break; - } - - case SE_IllusionPersistence: - newbon->IllusionPersistence = true; - break; - - case SE_LimitToSkill:{ - if (base1 <= HIGHEST_SKILL) - newbon->LimitToSkill[base1] = true; - break; - } - - case SE_SkillProc:{ - for(int e = 0; e < MAX_SKILL_PROCS; e++) - { - if(newbon->SkillProc[e] && newbon->SkillProc[e] == aaid) - break; //Do not use the same aa id more than once. - - else if(!newbon->SkillProc[e]){ - newbon->SkillProc[e] = aaid; - break; - } - } - break; - } - - case SE_SkillProcSuccess:{ - - for(int e = 0; e < MAX_SKILL_PROCS; e++) - { - if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid) - break; //Do not use the same spell id more than once. - - else if(!newbon->SkillProcSuccess[e]){ - newbon->SkillProcSuccess[e] = aaid; - break; - } - } - break; - } - - case SE_MeleeMitigation: - newbon->MeleeMitigationEffect -= base1; - break; - + if (base2 == ALL_SKILLS) + newbon->HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] += base1; + else + newbon->HitChanceEffect[base2] += base1; } + + case SE_ProcOnKillShot: + for (int i = 0; i < MAX_SPELL_TRIGGER * 3; i += 3) { + if (!newbon->SpellOnKill[i] || + ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i + 1] < base1))) { + // base1 = chance, base2 = SpellID to be triggered, base3 = min npc level + newbon->SpellOnKill[i] = base2; + newbon->SpellOnKill[i + 1] = base1; + + if (GetLevel() > 15) + newbon->SpellOnKill[i + 2] = + GetLevel() - 15; // AA specifiy "non-trivial" + else + newbon->SpellOnKill[i + 2] = 0; + + break; + } + } + break; + + case SE_SpellOnDeath: + for (int i = 0; i < MAX_SPELL_TRIGGER * 2; i += 2) { + if (!newbon->SpellOnDeath[i]) { + // base1 = SpellID to be triggered, base2 = chance to fire + newbon->SpellOnDeath[i] = base1; + newbon->SpellOnDeath[i + 1] = base2; + break; + } + } + break; + + case SE_TriggerOnCast: + + for (int i = 0; i < MAX_SPELL_TRIGGER; i++) { + if (newbon->SpellTriggers[i] == rank.id) + break; + + if (!newbon->SpellTriggers[i]) { + // Save the 'rank.id' of each triggerable effect to an array + newbon->SpellTriggers[i] = rank.id; + break; + } + } + break; + + case SE_CriticalHitChance: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + if (base2 == ALL_SKILLS) + newbon->CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 1] += base1; + else + newbon->CriticalHitChance[base2] += base1; + } break; + + case SE_CriticalDamageMob: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + // base1 = effect value, base2 = skill restrictions(-1 for all) + if (base2 == ALL_SKILLS) + newbon->CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 1] += base1; + else + newbon->CritDmgMob[base2] += base1; + break; + } + + case SE_CriticalSpellChance: { + newbon->CriticalSpellChance += base1; + + if (base2 > newbon->SpellCritDmgIncNoStack) + newbon->SpellCritDmgIncNoStack = base2; + + break; + } + + case SE_ResistFearChance: { + if (base1 == 100) // If we reach 100% in a single spell/item then we should be immune to + // negative fear resist effects until our immunity is over + newbon->Fearless = true; + + newbon->ResistFearChance += base1; // these should stack + break; + } + + case SE_SkillDamageAmount: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + if (base2 == ALL_SKILLS) + newbon->SkillDamageAmount[EQEmu::skills::HIGHEST_SKILL + 1] += base1; + else + newbon->SkillDamageAmount[base2] += base1; + break; + } + + case SE_SkillAttackProc: { + // You can only have one of these per client. [AA Dragon Punch] + newbon->SkillAttackProc[0] = base1; // Chance base 1000 = 100% proc rate + newbon->SkillAttackProc[1] = base2; // Skill to Proc Off + newbon->SkillAttackProc[2] = rank.spell; // spell to proc + break; + } + + case SE_DamageModifier: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + if (base2 == ALL_SKILLS) + newbon->DamageModifier[EQEmu::skills::HIGHEST_SKILL + 1] += base1; + else + newbon->DamageModifier[base2] += base1; + break; + } + + case SE_DamageModifier2: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + if (base2 == ALL_SKILLS) + newbon->DamageModifier2[EQEmu::skills::HIGHEST_SKILL + 1] += base1; + else + newbon->DamageModifier2[base2] += base1; + break; + } + + case SE_SlayUndead: { + if (newbon->SlayUndead[1] < base1) + newbon->SlayUndead[0] = base1; // Rate + newbon->SlayUndead[1] = base2; // Damage Modifier + break; + } + + case SE_DoubleRiposte: { + newbon->DoubleRiposte += base1; + break; + } + + case SE_GiveDoubleRiposte: { + // 0=Regular Riposte 1=Skill Attack Riposte 2=Skill + if (base2 == 0) { + if (newbon->GiveDoubleRiposte[0] < base1) + newbon->GiveDoubleRiposte[0] = base1; + } + // Only for special attacks. + else if (base2 > 0 && (newbon->GiveDoubleRiposte[1] < base1)) { + newbon->GiveDoubleRiposte[1] = base1; + newbon->GiveDoubleRiposte[2] = base2; + } + + break; + } + + // Physically raises skill cap ie if 55/55 it will raise to 55/60 + case SE_RaiseSkillCap: { + + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + + if (newbon->RaiseSkillCap[base2] < base1) + newbon->RaiseSkillCap[base2] = base1; + break; + } + + case SE_MasteryofPast: { + if (newbon->MasteryofPast < base1) + newbon->MasteryofPast = base1; + break; + } + + case SE_CastingLevel2: + case SE_CastingLevel: { + newbon->effective_casting_level += base1; + break; + } + + case SE_DivineSave: { + if (newbon->DivineSaveChance[0] < base1) { + newbon->DivineSaveChance[0] = base1; + newbon->DivineSaveChance[1] = base2; + } + break; + } + + case SE_SpellEffectResistChance: { + for (int e = 0; e < MAX_RESISTABLE_EFFECTS * 2; e += 2) { + if (newbon->SEResist[e + 1] && (newbon->SEResist[e] == base2) && + (newbon->SEResist[e + 1] < base1)) { + newbon->SEResist[e] = base2; // Spell Effect ID + newbon->SEResist[e + 1] = base1; // Resist Chance + break; + } else if (!newbon->SEResist[e + 1]) { + newbon->SEResist[e] = base2; // Spell Effect ID + newbon->SEResist[e + 1] = base1; // Resist Chance + break; + } + } + break; + } + + case SE_MitigateDamageShield: { + if (base1 < 0) + base1 = base1 * (-1); + + newbon->DSMitigationOffHand += base1; + break; + } + + case SE_FinishingBlow: { + // base1 = chance, base2 = damage + if (newbon->FinishingBlow[1] < base2) { + newbon->FinishingBlow[0] = base1; + newbon->FinishingBlow[1] = base2; + } + break; + } + + case SE_FinishingBlowLvl: { + // base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?) + if (newbon->FinishingBlowLvl[0] < base1) { + newbon->FinishingBlowLvl[0] = base1; + newbon->FinishingBlowLvl[1] = base2; + } + break; + } + + case SE_StunBashChance: + newbon->StunBashChance += base1; + break; + + case SE_IncreaseChanceMemwipe: + newbon->IncreaseChanceMemwipe += base1; + break; + + case SE_CriticalMend: + newbon->CriticalMend += base1; + break; + + case SE_HealRate: + newbon->HealRate += base1; + break; + + case SE_MeleeLifetap: { + + if ((base1 < 0) && (newbon->MeleeLifetap > base1)) + newbon->MeleeLifetap = base1; + + else if (newbon->MeleeLifetap < base1) + newbon->MeleeLifetap = base1; + break; + } + + case SE_Vampirism: + newbon->Vampirism += base1; + break; + + case SE_FrenziedDevastation: + newbon->FrenziedDevastation += base2; + break; + + case SE_SpellProcChance: + newbon->SpellProcChance += base1; + break; + + case SE_Berserk: + newbon->BerserkSPA = true; + break; + + case SE_Metabolism: + newbon->Metabolism += base1; + break; + + case SE_ImprovedReclaimEnergy: { + if ((base1 < 0) && (newbon->ImprovedReclaimEnergy > base1)) + newbon->ImprovedReclaimEnergy = base1; + + else if (newbon->ImprovedReclaimEnergy < base1) + newbon->ImprovedReclaimEnergy = base1; + break; + } + + case SE_HeadShot: { + if (newbon->HeadShot[1] < base2) { + newbon->HeadShot[0] = base1; + newbon->HeadShot[1] = base2; + } + break; + } + + case SE_HeadShotLevel: { + if (newbon->HSLevel < base1) + newbon->HSLevel = base1; + break; + } + + case SE_Assassinate: { + if (newbon->Assassinate[1] < base2) { + newbon->Assassinate[0] = base1; + newbon->Assassinate[1] = base2; + } + break; + } + + case SE_AssassinateLevel: { + if (newbon->AssassinateLevel < base1) + newbon->AssassinateLevel = base1; + break; + } + + case SE_PetMeleeMitigation: + newbon->PetMeleeMitigation += base1; + break; + + case SE_FactionModPct: { + if ((base1 < 0) && (newbon->FactionModPct > base1)) + newbon->FactionModPct = base1; + + else if (newbon->FactionModPct < base1) + newbon->FactionModPct = base1; + break; + } + + case SE_IllusionPersistence: + newbon->IllusionPersistence = true; + break; + + case SE_LimitToSkill: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + if (base1 <= EQEmu::skills::HIGHEST_SKILL) + newbon->LimitToSkill[base1] = true; + break; + } + + case SE_SkillProc: { + for (int e = 0; e < MAX_SKILL_PROCS; e++) { + if (newbon->SkillProc[e] && newbon->SkillProc[e] == rank.id) + break; // Do not use the same aa id more than once. + + else if (!newbon->SkillProc[e]) { + newbon->SkillProc[e] = rank.id; + break; + } + } + break; + } + + case SE_SkillProcSuccess: { + + for (int e = 0; e < MAX_SKILL_PROCS; e++) { + if (newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == rank.id) + break; // Do not use the same spell id more than once. + + else if (!newbon->SkillProcSuccess[e]) { + newbon->SkillProcSuccess[e] = rank.id; + break; + } + } + break; + } + + case SE_MeleeMitigation: + newbon->MeleeMitigationEffect -= base1; + break; + + case SE_ATK: + newbon->ATK += base1; + break; + case SE_IncreaseExtTargetWindow: + newbon->extra_xtargets += base1; + break; + + case SE_PC_Pet_Rampage: { + newbon->PC_Pet_Rampage[0] += base1; //Chance to rampage + if (newbon->PC_Pet_Rampage[1] < base2) + newbon->PC_Pet_Rampage[1] = base2; //Damage modifer - take highest + break; + } + + case SE_PC_Pet_Flurry_Chance: + newbon->PC_Pet_Flurry += base1; //Chance to Flurry + break; + + case SE_ShroudofStealth: + newbon->ShroudofStealth = true; + break; + + case SE_ReduceFallDamage: + newbon->ReduceFallDamage += base1; + break; + + case SE_ReduceTradeskillFail:{ + + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + + newbon->ReduceTradeskillFail[base2] += base1; + break; + } + + case SE_TradeSkillMastery: + if (newbon->TradeSkillMastery < base1) + newbon->TradeSkillMastery = base1; + break; + + case SE_NoBreakAESneak: + if (newbon->NoBreakAESneak < base1) + newbon->NoBreakAESneak = base1; + break; + + case SE_FeignedCastOnChance: + if (newbon->FeignedCastOnChance < base1) + newbon->FeignedCastOnChance = base1; + break; + + // to do + case SE_PetDiscipline: + break; + case SE_PetDiscipline2: + break; + case SE_PotionBeltSlots: + break; + case SE_BandolierSlots: + break; + case SE_ForageSkill: + break; + case SE_SecondaryForte: + break; + case SE_ExtendedShielding: + break; + case SE_ShieldDuration: + break; + case SE_ReduceApplyPoisonTime: + break; + case SE_NimbleEvasion: + break; + case SE_TrapCircumvention: + break; + case SE_FeignedMinion: + break; + + // not handled here + case SE_HastenedAASkill: + // not handled here but don't want to clutter debug log -- these may need to be verified to ignore + case SE_LimitMaxLevel: + case SE_LimitResist: + case SE_LimitTarget: + case SE_LimitEffect: + case SE_LimitSpellType: + case SE_LimitMinDur: + case SE_LimitInstant: + case SE_LimitMinLevel: + case SE_LimitCastTimeMin: + case SE_LimitCastTimeMax: + case SE_LimitSpell: + case SE_LimitCombatSkills: + case SE_LimitManaMin: + case SE_LimitSpellGroup: + case SE_LimitSpellClass: + case SE_LimitSpellSubclass: + case SE_LimitHPPercent: + case SE_LimitManaPercent: + case SE_LimitEndPercent: + case SE_LimitClass: + case SE_LimitRace: + case SE_LimitCastingSkill: + case SE_LimitUseMin: + case SE_LimitUseType: + break; + + default: + Log.Out(Logs::Detail, Logs::AA, "SPA %d not accounted for in AA %s (%d)", effect, rank.base_ability->name.c_str(), rank.id); + break; + } + } } @@ -1449,7 +1512,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon) int buff_count = GetMaxTotalSlots(); for(i = 0; i < buff_count; i++) { if(buffs[i].spellid != SPELL_UNKNOWN){ - ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining,i); + ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining, i, buffs[i].instrument_mod); if (buffs[i].numhits > 0) Numhits(true); @@ -1467,24 +1530,24 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon) NegateSpellsBonuses(buffs[i].spellid); } } + + // THIS IS WRONG, leaving for now //this prolly suffer from roundoff error slightly... - newbon->AC = newbon->AC * 10 / 34; //ratio determined impirically from client. - if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells. + newbon->AC = newbon->AC * 10 / 34; //ratio determined impirically from client. + if (GetClass() == BARD) + newbon->ManaRegen = 0; // Bards do not get mana regen from spells. } -void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, uint8 WornType, uint32 ticsremaining, int buffslot, - bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max) +void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *new_bonus, uint16 casterId, + uint8 WornType, int32 ticsremaining, int buffslot, int instrument_mod, + bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max) { int i, effect_value, base2, max, effectid; bool AdditiveWornBonus = false; - Mob *caster = nullptr; if(!IsAISpellEffect && !IsValidSpell(spell_id)) return; - if(casterId > 0) - caster = entity_list.GetMob(casterId); - for (i = 0; i < EFFECT_COUNT; i++) { //Buffs/Item effects @@ -1509,9 +1572,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType)) AdditiveWornBonus = true; - + effectid = spells[spell_id].effectid[i]; - effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining); + effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, instrument_mod, nullptr, ticsremaining, casterId); base2 = spells[spell_id].base2[i]; max = spells[spell_id].max[i]; } @@ -1620,10 +1683,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) { effect_value -= ((effect_value * GetSlowMitigation()/100)); - if (effect_value > new_bonus->inhibitmelee) + if (effect_value > new_bonus->inhibitmelee) new_bonus->inhibitmelee = effect_value; } - + break; } @@ -1839,7 +1902,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne new_bonus->DamageShieldType = GetDamageShieldType(spell_id, max); else new_bonus->DamageShieldType = GetDamageShieldType(spell_id); - + break; } @@ -1874,24 +1937,27 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_CriticalHitChance: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; if (AdditiveWornBonus) { if(base2 == ALL_SKILLS) - new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value; + new_bonus->CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 1] += effect_value; else new_bonus->CriticalHitChance[base2] += effect_value; } else if(effect_value < 0) { - if(base2 == ALL_SKILLS && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] > effect_value) - new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value; + if (base2 == ALL_SKILLS && new_bonus->CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 1] > effect_value) + new_bonus->CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 1] = effect_value; else if(base2 != ALL_SKILLS && new_bonus->CriticalHitChance[base2] > effect_value) new_bonus->CriticalHitChance[base2] = effect_value; } - else if(base2 == ALL_SKILLS && new_bonus->CriticalHitChance[HIGHEST_SKILL+1] < effect_value) - new_bonus->CriticalHitChance[HIGHEST_SKILL+1] = effect_value; + else if (base2 == ALL_SKILLS && new_bonus->CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 1] < effect_value) + new_bonus->CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 1] = effect_value; else if(base2 != ALL_SKILLS && new_bonus->CriticalHitChance[base2] < effect_value) new_bonus->CriticalHitChance[base2] = effect_value; @@ -2020,7 +2086,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_Vampirism: new_bonus->Vampirism += effect_value; - break; + break; case SE_AllInstrumentMod: { @@ -2077,22 +2143,25 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_HitChance: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; if (AdditiveWornBonus){ if(base2 == ALL_SKILLS) - new_bonus->HitChanceEffect[HIGHEST_SKILL+1] += effect_value; + new_bonus->HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] += effect_value; else new_bonus->HitChanceEffect[base2] += effect_value; } else if(base2 == ALL_SKILLS){ - if ((effect_value < 0) && (new_bonus->HitChanceEffect[HIGHEST_SKILL+1] > effect_value)) - new_bonus->HitChanceEffect[HIGHEST_SKILL+1] = effect_value; + if ((effect_value < 0) && (new_bonus->HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] > effect_value)) + new_bonus->HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] = effect_value; - else if (!new_bonus->HitChanceEffect[HIGHEST_SKILL+1] || - ((new_bonus->HitChanceEffect[HIGHEST_SKILL+1] > 0) && (new_bonus->HitChanceEffect[HIGHEST_SKILL+1] < effect_value))) - new_bonus->HitChanceEffect[HIGHEST_SKILL+1] = effect_value; + else if (!new_bonus->HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] || + ((new_bonus->HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] > 0) && (new_bonus->HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] < effect_value))) + new_bonus->HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] = effect_value; } else { @@ -2111,28 +2180,40 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_DamageModifier: { - if(base2 == ALL_SKILLS) - new_bonus->DamageModifier[HIGHEST_SKILL+1] += effect_value; - else - new_bonus->DamageModifier[base2] += effect_value; + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + int skill = base2 == ALL_SKILLS ? EQEmu::skills::HIGHEST_SKILL + 1 : base2; + if (effect_value < 0 && new_bonus->DamageModifier[skill] > effect_value) + new_bonus->DamageModifier[skill] = effect_value; + else if (effect_value > 0 && new_bonus->DamageModifier[skill] < effect_value) + new_bonus->DamageModifier[skill] = effect_value; break; } case SE_DamageModifier2: { - if(base2 == ALL_SKILLS) - new_bonus->DamageModifier2[HIGHEST_SKILL+1] += effect_value; - else - new_bonus->DamageModifier2[base2] += effect_value; + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + int skill = base2 == ALL_SKILLS ? EQEmu::skills::HIGHEST_SKILL + 1 : base2; + if (effect_value < 0 && new_bonus->DamageModifier2[skill] > effect_value) + new_bonus->DamageModifier2[skill] = effect_value; + else if (effect_value > 0 && new_bonus->DamageModifier2[skill] < effect_value) + new_bonus->DamageModifier2[skill] = effect_value; break; } case SE_MinDamageModifier: { - if(base2 == ALL_SKILLS) - new_bonus->MinDamageModifier[HIGHEST_SKILL+1] += effect_value; - else - new_bonus->MinDamageModifier[base2] += effect_value; + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + int skill = base2 == ALL_SKILLS ? EQEmu::skills::HIGHEST_SKILL + 1 : base2; + if (effect_value < 0 && new_bonus->MinDamageModifier[skill] > effect_value) + new_bonus->MinDamageModifier[skill] = effect_value; + else if (effect_value > 0 && new_bonus->MinDamageModifier[skill] < effect_value) + new_bonus->MinDamageModifier[skill] = effect_value; break; } @@ -2202,12 +2283,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_Accuracy: { - if ((effect_value < 0) && (new_bonus->Accuracy[HIGHEST_SKILL+1] > effect_value)) - new_bonus->Accuracy[HIGHEST_SKILL+1] = effect_value; + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + if ((effect_value < 0) && (new_bonus->Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] > effect_value)) + new_bonus->Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] = effect_value; - else if (!new_bonus->Accuracy[HIGHEST_SKILL+1] || - ((new_bonus->Accuracy[HIGHEST_SKILL+1] > 0) && (new_bonus->Accuracy[HIGHEST_SKILL+1] < effect_value))) - new_bonus->Accuracy[HIGHEST_SKILL+1] = effect_value; + else if (!new_bonus->Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] || + ((new_bonus->Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] > 0) && (new_bonus->Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] < effect_value))) + new_bonus->Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] = effect_value; break; } @@ -2225,17 +2309,20 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_SkillDamageTaken: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; //When using npc_spells_effects if MAX value set, use stackable quest based modifier. if (IsAISpellEffect && max){ if(base2 == ALL_SKILLS) - SkillDmgTaken_Mod[HIGHEST_SKILL+1] = effect_value; + SkillDmgTaken_Mod[EQEmu::skills::HIGHEST_SKILL + 1] = effect_value; else SkillDmgTaken_Mod[base2] = effect_value; } else { if(base2 == ALL_SKILLS) - new_bonus->SkillDmgTaken[HIGHEST_SKILL+1] += effect_value; + new_bonus->SkillDmgTaken[EQEmu::skills::HIGHEST_SKILL + 1] += effect_value; else new_bonus->SkillDmgTaken[base2] += effect_value; @@ -2263,7 +2350,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_CriticalSpellChance: { new_bonus->CriticalSpellChance += effect_value; - + if (base2 > new_bonus->SpellCritDmgIncNoStack) new_bonus->SpellCritDmgIncNoStack = base2; break; @@ -2343,8 +2430,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_CriticalDamageMob: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; if(base2 == ALL_SKILLS) - new_bonus->CritDmgMob[HIGHEST_SKILL+1] += effect_value; + new_bonus->CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 1] += effect_value; else new_bonus->CritDmgMob[base2] += effect_value; break; @@ -2359,8 +2449,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_SkillDamageAmount: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; if(base2 == ALL_SKILLS) - new_bonus->SkillDamageAmount[HIGHEST_SKILL+1] += effect_value; + new_bonus->SkillDamageAmount[EQEmu::skills::HIGHEST_SKILL + 1] += effect_value; else new_bonus->SkillDamageAmount[base2] += effect_value; break; @@ -2464,8 +2557,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_SkillDamageAmount2: { + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; if(base2 == ALL_SKILLS) - new_bonus->SkillDamageAmount2[HIGHEST_SKILL+1] += effect_value; + new_bonus->SkillDamageAmount2[EQEmu::skills::HIGHEST_SKILL + 1] += effect_value; else new_bonus->SkillDamageAmount2[base2] += effect_value; break; @@ -2473,7 +2569,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_NegateAttacks: { - if (!new_bonus->NegateAttacks[0] || + if (!new_bonus->NegateAttacks[0] || ((new_bonus->NegateAttacks[0] && new_bonus->NegateAttacks[2]) && (new_bonus->NegateAttacks[2] < max))){ new_bonus->NegateAttacks[0] = 1; new_bonus->NegateAttacks[1] = buffslot; @@ -2493,7 +2589,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } - + case SE_MeleeThresholdGuard: { if (new_bonus->MeleeThresholdGuard[0] < effect_value){ @@ -2657,23 +2753,24 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; case SE_AddSingingMod: - switch (base2) - { - case ItemTypeWindInstrument: - new_bonus->windMod += effect_value; - break; - case ItemTypeStringedInstrument: - new_bonus->stringedMod += effect_value; - break; - case ItemTypeBrassInstrument: - new_bonus->brassMod += effect_value; - break; - case ItemTypePercussionInstrument: - new_bonus->percussionMod += effect_value; - break; - case ItemTypeSinging: - new_bonus->singingMod += effect_value; - break; + switch (base2) { + case EQEmu::item::ItemTypeWindInstrument: + new_bonus->windMod += effect_value; + break; + case EQEmu::item::ItemTypeStringedInstrument: + new_bonus->stringedMod += effect_value; + break; + case EQEmu::item::ItemTypeBrassInstrument: + new_bonus->brassMod += effect_value; + break; + case EQEmu::item::ItemTypePercussionInstrument: + new_bonus->percussionMod += effect_value; + break; + case EQEmu::item::ItemTypeSinging: + new_bonus->singingMod += effect_value; + break; + default: + break; } break; @@ -2860,17 +2957,17 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne new_bonus->NegateIfCombat = true; break; - case SE_Screech: + case SE_Screech: new_bonus->Screech = effect_value; break; case SE_AlterNPCLevel: if (IsNPC()){ - if (!new_bonus->AlterNPCLevel - || ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value)) + if (!new_bonus->AlterNPCLevel + || ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value)) || ((effect_value > 0) && (new_bonus->AlterNPCLevel < effect_value))) { - + int tmp_lv = GetOrigLevel() + effect_value; if (tmp_lv < 1) tmp_lv = 1; @@ -2908,7 +3005,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne new_bonus->BerserkSPA = true; break; - + case SE_Metabolism: new_bonus->Metabolism += effect_value; break; @@ -2979,10 +3076,6 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne new_bonus->PetMeleeMitigation += effect_value; break; - case SE_MeleeVulnerability: - new_bonus->MeleeVulnerability += effect_value; - break; - case SE_Sanctuary: new_bonus->Sanctuary = true; break; @@ -3002,14 +3095,17 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; case SE_LimitToSkill:{ - if (effect_value <= HIGHEST_SKILL){ + // Bad data or unsupported new skill + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + if (effect_value <= EQEmu::skills::HIGHEST_SKILL){ new_bonus->LimitToSkill[effect_value] = true; } break; } case SE_SkillProc:{ - + for(int e = 0; e < MAX_SKILL_PROCS; e++) { if(new_bonus->SkillProc[e] && new_bonus->SkillProc[e] == spell_id) @@ -3024,7 +3120,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne } case SE_SkillProcSuccess:{ - + for(int e = 0; e < MAX_SKILL_PROCS; e++) { if(new_bonus->SkillProcSuccess[e] && new_bonus->SkillProcSuccess[e] == spell_id) @@ -3038,11 +3134,63 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_PC_Pet_Rampage: { + new_bonus->PC_Pet_Rampage[0] += effect_value; //Chance to rampage + if (new_bonus->PC_Pet_Rampage[1] < base2) + new_bonus->PC_Pet_Rampage[1] = base2; //Damage modifer - take highest + break; + } + + case SE_PC_Pet_Flurry_Chance: + new_bonus->PC_Pet_Flurry += effect_value; //Chance to Flurry + break; + + case SE_ShroudofStealth: + new_bonus->ShroudofStealth = true; + break; + + case SE_ReduceFallDamage: + new_bonus->ReduceFallDamage += effect_value; + break; + + case SE_ReduceTradeskillFail:{ + + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + + new_bonus->ReduceTradeskillFail[base2] += effect_value; + break; + } + + case SE_TradeSkillMastery: + if (new_bonus->TradeSkillMastery < effect_value) + new_bonus->TradeSkillMastery = effect_value; + break; + + case SE_RaiseSkillCap: { + if (base2 > EQEmu::skills::HIGHEST_SKILL) + break; + + if (new_bonus->RaiseSkillCap[base2] < effect_value) + new_bonus->RaiseSkillCap[base2] = effect_value; + break; + } + + case SE_NoBreakAESneak: + if (new_bonus->NoBreakAESneak < effect_value) + new_bonus->NoBreakAESneak = effect_value; + break; + + case SE_FeignedCastOnChance: + if (new_bonus->FeignedCastOnChance < effect_value) + new_bonus->FeignedCastOnChance = effect_value; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { - + //Non-Focused Effect to modify incoming spell damage by resist type. - case SE_FcSpellVulnerability: + case SE_FcSpellVulnerability: ModVulnerability(base2, effect_value); break; } @@ -3054,8 +3202,8 @@ void NPC::CalcItemBonuses(StatBonuses *newbon) { if(newbon){ - for(int i = 0; i < EmuConstants::EQUIPMENT_SIZE; i++){ - const Item_Struct *cur = database.GetItem(equipment[i]); + for (int i = 0; i < EQEmu::legacy::EQUIPMENT_SIZE; i++){ + const EQEmu::ItemBase *cur = database.GetItem(equipment[i]); if(cur){ //basic stats newbon->AC += cur->AC; @@ -3110,12 +3258,12 @@ void NPC::CalcItemBonuses(StatBonuses *newbon) if(cur->CombatEffects > 0) { newbon->ProcChance += cur->CombatEffects; } - if (cur->Worn.Effect>0 && (cur->Worn.Type == ET_WornEffect)) { // latent effects + if (cur->Worn.Effect>0 && (cur->Worn.Type == EQEmu::item::ItemEffectWorn)) { // latent effects ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon, 0, cur->Worn.Type); } if (RuleB(Spells, NPC_UseFocusFromItems)){ - if (cur->Focus.Effect>0 && (cur->Focus.Type == ET_Focus)){ // focus effects + if (cur->Focus.Effect>0 && (cur->Focus.Type == EQEmu::item::ItemEffectFocus)){ // focus effects ApplySpellsBonuses(cur->Focus.Effect, cur->Focus.Level, newbon); } } @@ -3132,24 +3280,24 @@ void Client::CalcItemScale() { bool changed = false; // MainAmmo excluded in helper function below - if(CalcItemScale(EmuConstants::EQUIPMENT_BEGIN, EmuConstants::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21) + if (CalcItemScale(EQEmu::legacy::EQUIPMENT_BEGIN, EQEmu::legacy::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21) changed = true; - if(CalcItemScale(EmuConstants::GENERAL_BEGIN, EmuConstants::GENERAL_END)) // original coding excluded MainCursor (< 30) + if (CalcItemScale(EQEmu::legacy::GENERAL_BEGIN, EQEmu::legacy::GENERAL_END)) // original coding excluded MainCursor (< 30) changed = true; // I excluded cursor bag slots here because cursor was excluded above..if this is incorrect, change 'slot_y' here to CURSOR_BAG_END // and 'slot_y' above to CURSOR from GENERAL_END above - or however it is supposed to be... - if(CalcItemScale(EmuConstants::GENERAL_BAGS_BEGIN, EmuConstants::GENERAL_BAGS_END)) // (< 341) + if (CalcItemScale(EQEmu::legacy::GENERAL_BAGS_BEGIN, EQEmu::legacy::GENERAL_BAGS_END)) // (< 341) changed = true; - if(CalcItemScale(EmuConstants::TRIBUTE_BEGIN, EmuConstants::TRIBUTE_END)) // (< 405) + if (CalcItemScale(EQEmu::legacy::TRIBUTE_BEGIN, EQEmu::legacy::TRIBUTE_END)) // (< 405) changed = true; //Power Source Slot - if (GetClientVersion() >= ClientVersion::SoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { - if(CalcItemScale(MainPowerSource, MainPowerSource)) + if (CalcItemScale(EQEmu::legacy::SlotPowerSource, EQEmu::legacy::SlotPowerSource)) changed = true; } @@ -3164,7 +3312,7 @@ bool Client::CalcItemScale(uint32 slot_x, uint32 slot_y) { bool changed = false; uint32 i; for (i = slot_x; i <= slot_y; i++) { - if (i == MainAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot + if (i == EQEmu::legacy::SlotAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot continue; ItemInst* inst = m_inv.GetItem(i); @@ -3174,7 +3322,7 @@ bool Client::CalcItemScale(uint32 slot_x, uint32 slot_y) { // TEST CODE: test for bazaar trader crashing with charm items if (Trader) - if (i >= EmuConstants::GENERAL_BAGS_BEGIN && i <= EmuConstants::GENERAL_BAGS_END) { + if (i >= EQEmu::legacy::GENERAL_BAGS_BEGIN && i <= EQEmu::legacy::GENERAL_BAGS_END) { ItemInst* parent_item = m_inv.GetItem(Inventory::CalcSlotId(i)); if (parent_item && parent_item->GetItem()->ID == 17899) // trader satchel continue; @@ -3194,7 +3342,7 @@ bool Client::CalcItemScale(uint32 slot_x, uint32 slot_y) { } //iterate all augments - for (int x = AUG_BEGIN; x < EmuConstants::ITEM_COMMON_SIZE; ++x) + for (int x = AUG_INDEX_BEGIN; x < EQEmu::legacy::ITEM_COMMON_SIZE; ++x) { ItemInst * a_inst = inst->GetAugment(x); if(!a_inst) @@ -3226,24 +3374,24 @@ void Client::DoItemEnterZone() { bool changed = false; // MainAmmo excluded in helper function below - if(DoItemEnterZone(EmuConstants::EQUIPMENT_BEGIN, EmuConstants::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21) + if (DoItemEnterZone(EQEmu::legacy::EQUIPMENT_BEGIN, EQEmu::legacy::EQUIPMENT_END)) // original coding excluded MainAmmo (< 21) changed = true; - if(DoItemEnterZone(EmuConstants::GENERAL_BEGIN, EmuConstants::GENERAL_END)) // original coding excluded MainCursor (< 30) + if (DoItemEnterZone(EQEmu::legacy::GENERAL_BEGIN, EQEmu::legacy::GENERAL_END)) // original coding excluded MainCursor (< 30) changed = true; // I excluded cursor bag slots here because cursor was excluded above..if this is incorrect, change 'slot_y' here to CURSOR_BAG_END // and 'slot_y' above to CURSOR from GENERAL_END above - or however it is supposed to be... - if(DoItemEnterZone(EmuConstants::GENERAL_BAGS_BEGIN, EmuConstants::GENERAL_BAGS_END)) // (< 341) + if (DoItemEnterZone(EQEmu::legacy::GENERAL_BAGS_BEGIN, EQEmu::legacy::GENERAL_BAGS_END)) // (< 341) changed = true; - if(DoItemEnterZone(EmuConstants::TRIBUTE_BEGIN, EmuConstants::TRIBUTE_END)) // (< 405) + if (DoItemEnterZone(EQEmu::legacy::TRIBUTE_BEGIN, EQEmu::legacy::TRIBUTE_END)) // (< 405) changed = true; //Power Source Slot - if (GetClientVersion() >= ClientVersion::SoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { - if(DoItemEnterZone(MainPowerSource, MainPowerSource)) + if (DoItemEnterZone(EQEmu::legacy::SlotPowerSource, EQEmu::legacy::SlotPowerSource)) changed = true; } @@ -3257,7 +3405,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) { // behavior change: 'slot_y' is now [RANGE]_END and not [RANGE]_END + 1 bool changed = false; for(uint32 i = slot_x; i <= slot_y; i++) { - if (i == MainAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot + if (i == EQEmu::legacy::SlotAmmo) // moved here from calling procedure to facilitate future range changes where MainAmmo may not be the last slot continue; ItemInst* inst = m_inv.GetItem(i); @@ -3267,7 +3415,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) { // TEST CODE: test for bazaar trader crashing with charm items if (Trader) - if (i >= EmuConstants::GENERAL_BAGS_BEGIN && i <= EmuConstants::GENERAL_BAGS_END) { + if (i >= EQEmu::legacy::GENERAL_BAGS_BEGIN && i <= EQEmu::legacy::GENERAL_BAGS_END) { ItemInst* parent_item = m_inv.GetItem(Inventory::CalcSlotId(i)); if (parent_item && parent_item->GetItem()->ID == 17899) // trader satchel continue; @@ -3279,7 +3427,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) { uint16 oldexp = inst->GetExp(); parse->EventItem(EVENT_ITEM_ENTER_ZONE, this, inst, nullptr, "", 0); - if(i <= MainAmmo || i == MainPowerSource) { + if (i <= EQEmu::legacy::SlotAmmo || i == EQEmu::legacy::SlotPowerSource) { parse->EventItem(EVENT_EQUIP_ITEM, this, inst, nullptr, "", i); } @@ -3289,7 +3437,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) { update_slot = true; } } else { - if(i <= MainAmmo || i == MainPowerSource) { + if (i <= EQEmu::legacy::SlotAmmo || i == EQEmu::legacy::SlotPowerSource) { parse->EventItem(EVENT_EQUIP_ITEM, this, inst, nullptr, "", i); } @@ -3297,7 +3445,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) { } //iterate all augments - for (int x = AUG_BEGIN; x < EmuConstants::ITEM_COMMON_SIZE; ++x) + for (int x = AUG_INDEX_BEGIN; x < EQEmu::legacy::ITEM_COMMON_SIZE; ++x) { ItemInst *a_inst = inst->GetAugment(x); if(!a_inst) @@ -3341,6 +3489,8 @@ uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_eff { case SE_ImprovedDamage: return focusImprovedDamage; + case SE_ImprovedDamage2: + return focusImprovedDamage2; case SE_ImprovedHeal: return focusImprovedHeal; case SE_ReduceManaCost: @@ -3379,6 +3529,8 @@ uint8 Mob::IsFocusEffect(uint16 spell_id,int effect_index, bool AA,uint32 aa_eff return focusSympatheticProc; case SE_FcDamageAmt: return focusFcDamageAmt; + case SE_FcDamageAmt2: + return focusFcDamageAmt2; case SE_FcDamageAmtCrit: return focusFcDamageAmtCrit; case SE_FcDamagePctCrit: @@ -3714,7 +3866,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_CriticalHitChance: { - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { spellbonuses.CriticalHitChance[e] = effect_value; aabonuses.CriticalHitChance[e] = effect_value; @@ -3832,7 +3984,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_HitChance: { - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { spellbonuses.HitChanceEffect[e] = effect_value; aabonuses.HitChanceEffect[e] = effect_value; @@ -3843,7 +3995,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_DamageModifier: { - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { spellbonuses.DamageModifier[e] = effect_value; aabonuses.DamageModifier[e] = effect_value; @@ -3854,7 +4006,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_DamageModifier2: { - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { spellbonuses.DamageModifier2[e] = effect_value; aabonuses.DamageModifier2[e] = effect_value; @@ -3865,7 +4017,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_MinDamageModifier: { - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { spellbonuses.MinDamageModifier[e] = effect_value; aabonuses.MinDamageModifier[e] = effect_value; @@ -3906,10 +4058,10 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_Accuracy: { - spellbonuses.Accuracy[HIGHEST_SKILL+1] = effect_value; - itembonuses.Accuracy[HIGHEST_SKILL+1] = effect_value; + spellbonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] = effect_value; + itembonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] = effect_value; - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { aabonuses.Accuracy[e] = effect_value; } @@ -3936,7 +4088,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_SkillDamageTaken: { - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { spellbonuses.SkillDmgTaken[e] = effect_value; aabonuses.SkillDmgTaken[e] = effect_value; @@ -4041,7 +4193,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_CriticalDamageMob: { - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { spellbonuses.CritDmgMob[e] = effect_value; aabonuses.CritDmgMob[e] = effect_value; @@ -4052,7 +4204,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_SkillDamageAmount: { - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { spellbonuses.SkillDamageAmount[e] = effect_value; aabonuses.SkillDamageAmount[e] = effect_value; @@ -4103,7 +4255,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) case SE_SkillDamageAmount2: { - for(int e = 0; e < HIGHEST_SKILL+1; e++) + for (int e = 0; e < EQEmu::skills::HIGHEST_SKILL + 1; e++) { spellbonuses.SkillDamageAmount2[e] = effect_value; aabonuses.SkillDamageAmount2[e] = effect_value; @@ -4394,7 +4546,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) aabonuses.SlayUndead[0] = effect_value; aabonuses.SlayUndead[1] = effect_value; break; - + case SE_DoubleRangedAttack: spellbonuses.DoubleRangedAttack = effect_value; aabonuses.DoubleRangedAttack = effect_value; @@ -4414,7 +4566,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) aabonuses.ShieldEquipDmgMod[1] = effect_value; itembonuses.ShieldEquipDmgMod[0] = effect_value; itembonuses.ShieldEquipDmgMod[1] = effect_value; - break; + break; case SE_TriggerMeleeThreshold: spellbonuses.TriggerMeleeThreshold = false; @@ -4559,12 +4711,6 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) aabonuses.FactionModPct = effect_value; break; - case SE_MeleeVulnerability: - spellbonuses.MeleeVulnerability = effect_value; - itembonuses.MeleeVulnerability = effect_value; - aabonuses.MeleeVulnerability = effect_value; - break; - case SE_IllusionPersistence: spellbonuses.IllusionPersistence = false; itembonuses.IllusionPersistence = false; diff --git a/zone/bot.cpp b/zone/bot.cpp index ea48727ec..a3dd19b2d 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -1,3 +1,21 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #ifdef BOTS #include "bot.h" @@ -5,27 +23,25 @@ #include "doors.h" #include "quest_parser_collection.h" #include "../common/string_util.h" +#include "../common/say_link.h" -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; // This constructor is used during the bot create command Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm::vec4(), 0, false), rest_timer(1) { if(botOwner) { this->SetBotOwner(botOwner); this->_botOwnerCharacterID = botOwner->CharacterID(); - } - else { + } else { this->SetBotOwner(0); this->_botOwnerCharacterID = 0; } _guildRank = 0; _guildId = 0; - _lastTotalPlayTime = 0; _startTotalPlayTime = time(&_startTotalPlayTime); _lastZoneId = 0; - _baseMR = npcTypeData.MR; _baseCR = npcTypeData.CR; _baseDR = npcTypeData.DR; @@ -46,7 +62,6 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm RestRegenHP = 0; RestRegenMana = 0; RestRegenEndurance = 0; - SetBotID(0); SetBotSpellID(0); SetSpawnStatus(false); @@ -57,65 +72,46 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm SetHasBeenSummoned(false); SetTaunting(GetClass() == WARRIOR); SetDefaultBotStance(); - SetInHealRotation(false); - SetHealRotationActive(false); - SetHasHealedThisCycle(false); - ClearHealRotationLeader(); - ClearHealRotationTargets(); - ClearHealRotationMembers(); - SetHealRotationNextHealTime(0); - SetHealRotationTimer(0); - SetNumHealRotationMembers(0); - SetBardUseOutOfCombatSongs(GetClass() == BARD); + + SetAltOutOfCombatBehavior(GetClass() == BARD); // will need to be updated if more classes make use of this flag + SetShowHelm(true); + SetPauseAI(false); CalcChanceToCast(); rest_timer.Disable(); - - SetFollowDistance(184); - + SetFollowDistance(BOT_DEFAULT_FOLLOW_DISTANCE); // Do this once and only in this constructor GenerateAppearance(); - GenerateBaseStats(); GenerateArmorClass(); - // Calculate HitPoints Last As It Uses Base Stats cur_hp = GenerateBaseHitPoints(); cur_mana = GenerateBaseManaPoints(); cur_end = CalcBaseEndurance(); - hp_regen = CalcHPRegen(); mana_regen = CalcManaRegen(); end_regen = CalcEnduranceRegen(); - - for (int i = 0; i < MaxTimer; i++) { + for (int i = 0; i < MaxTimer; i++) timers[i] = 0; - } - - for(int i = 0; i < MaxHealRotationTargets; i++) { - _healRotationTargets[i] = 0; - } strcpy(this->name, this->GetCleanName()); - - memset(&m_Light, 0, sizeof(LightProfile_Struct)); + memset(&_botInspectMessage, 0, sizeof(InspectMessage_Struct)); } // This constructor is used when the bot is loaded out of the database -Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType npcTypeData) : NPC(&npcTypeData, nullptr, glm::vec4(), 0, false), rest_timer(1) { +Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType npcTypeData) : NPC(&npcTypeData, nullptr, glm::vec4(), 0, false), rest_timer(1) +{ this->_botOwnerCharacterID = botOwnerCharacterID; - - if(this->_botOwnerCharacterID > 0) { + if(this->_botOwnerCharacterID > 0) this->SetBotOwner(entity_list.GetClientByCharID(this->_botOwnerCharacterID)); - } + + auto bot_owner = GetBotOwner(); _guildRank = 0; _guildId = 0; - _lastTotalPlayTime = totalPlayTime; _startTotalPlayTime = time(&_startTotalPlayTime); _lastZoneId = lastZoneId; berserk = false; - _baseMR = npcTypeData.MR; _baseCR = npcTypeData.CR; _baseDR = npcTypeData.DR; @@ -135,11 +131,9 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to _baseGender = npcTypeData.gender; cur_hp = npcTypeData.cur_hp; cur_mana = npcTypeData.Mana; - RestRegenHP = 0; RestRegenMana = 0; RestRegenEndurance = 0; - SetBotID(botID); SetBotSpellID(botSpellsID); SetSpawnStatus(false); @@ -148,75 +142,73 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to SetPetChooser(false); SetRangerAutoWeaponSelect(false); SetHasBeenSummoned(false); - LoadStance(); + + bool stance_flag = false; + if (!botdb.LoadStance(this, stance_flag) && bot_owner) + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::LoadStance(), GetCleanName()); + if (!stance_flag && bot_owner) + bot_owner->Message(13, "Could not locate stance for '%s'", GetCleanName()); + SetTaunting((GetClass() == WARRIOR || GetClass() == PALADIN || GetClass() == SHADOWKNIGHT) && (GetBotStance() == BotStanceAggressive)); - SetGroupMessagesOn(GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN || GetClass() == ENCHANTER); - SetInHealRotation(false); - SetHealRotationActive(false); - SetHasHealedThisCycle(false); - SetHealRotationUseFastHeals(false); - ClearHealRotationLeader(); - ClearHealRotationTargets(); - ClearHealRotationMembers(); - SetHealRotationNextHealTime(0); - SetHealRotationTimer(0); - SetNumHealRotationMembers(0); + SetPauseAI(false); + CalcChanceToCast(); rest_timer.Disable(); - - SetFollowDistance(184); - + SetFollowDistance(BOT_DEFAULT_FOLLOW_DISTANCE); strcpy(this->name, this->GetCleanName()); - database.GetBotInspectMessage(this->GetBotID(), &_botInspectMessage); + memset(&_botInspectMessage, 0, sizeof(InspectMessage_Struct)); + if (!botdb.LoadInspectMessage(GetBotID(), _botInspectMessage) && bot_owner) + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::LoadInspectMessage(), GetCleanName()); - LoadGuildMembership(&_guildId, &_guildRank, &_guildName); + if (!botdb.LoadGuildMembership(GetBotID(), _guildId, _guildRank, _guildName) && bot_owner) + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::LoadGuildMembership(), GetCleanName()); + + std::string error_message; - std::string TempErrorMessage; - - EquipBot(&TempErrorMessage); - - if(!TempErrorMessage.empty()) { - // TODO: log error message to zone error log - if(GetBotOwner()) - GetBotOwner()->Message(13, TempErrorMessage.c_str()); + EquipBot(&error_message); + if(!error_message.empty()) { + if(bot_owner) + bot_owner->Message(13, error_message.c_str()); + error_message.clear(); } - for (int i = 0; i < MaxTimer; i++) { + for (int i = 0; i < MaxTimer; i++) timers[i] = 0; - } - - for(int i = 0; i < MaxHealRotationTargets; i++) { - _healRotationTargets[i] = 0; - } GenerateBaseStats(); - LoadTimers(); + if (!botdb.LoadTimers(this) && bot_owner) + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::LoadTimers(), GetCleanName()); + LoadAAs(); - LoadBuffs(); + + if (!botdb.LoadBuffs(this) && bot_owner) + bot_owner->Message(13, "&s for '%s'", BotDatabase::fail::LoadBuffs(), GetCleanName()); CalcBotStats(false); - hp_regen = CalcHPRegen(); mana_regen = CalcManaRegen(); end_regen = CalcEnduranceRegen(); - if(cur_hp > max_hp) cur_hp = max_hp; + if(cur_hp <= 0) { SetHP(max_hp/5); SetMana(0); BuffFadeAll(); SpellOnTarget(756, this); // Rezz effects } + if(cur_mana > max_mana) cur_mana = max_mana; + cur_end = max_end; } Bot::~Bot() { AI_Stop(); + LeaveHealRotationMemberPool(); if(HasGroup()) Bot::RemoveBotFromGroup(this, GetGroup()); @@ -236,65 +228,45 @@ void Bot::SetBotSpellID(uint32 newSpellID) { this->npc_spells_id = newSpellID; } -uint32 Bot::GetBotArcheryRange() -{ - const ItemInst *range_inst = GetBotItem(MainRange); - const ItemInst *ammo_inst = GetBotItem(MainAmmo); - - // empty slots +uint32 Bot::GetBotArcheryRange() { + const ItemInst *range_inst = GetBotItem(EQEmu::legacy::SlotRange); + const ItemInst *ammo_inst = GetBotItem(EQEmu::legacy::SlotAmmo); if (!range_inst || !ammo_inst) return 0; - const Item_Struct *range_item = range_inst->GetItem(); - const Item_Struct *ammo_item = ammo_inst->GetItem(); - - // no item struct for whatever reason - if (!range_item || !ammo_item) - return 0; - - // bad item types - if (range_item->ItemType != ItemTypeBow || ammo_item->ItemType != ItemTypeArrow) + const EQEmu::ItemBase *range_item = range_inst->GetItem(); + const EQEmu::ItemBase *ammo_item = ammo_inst->GetItem(); + if (!range_item || !ammo_item || range_item->ItemType != EQEmu::item::ItemTypeBow || ammo_item->ItemType != EQEmu::item::ItemTypeArrow) return 0; // everything is good! - return range_item->Range + ammo_item->Range; + return (range_item->Range + ammo_item->Range); } void Bot::ChangeBotArcherWeapons(bool isArcher) { - if((GetClass()==WARRIOR) || (GetClass()==PALADIN) || (GetClass()==RANGER) - || (GetClass()==SHADOWKNIGHT) || (GetClass()==ROGUE)) - { + if((GetClass()==WARRIOR) || (GetClass()==PALADIN) || (GetClass()==RANGER) || (GetClass()==SHADOWKNIGHT) || (GetClass()==ROGUE)) { if(!isArcher) { - BotAddEquipItem(MainPrimary, GetBotItemBySlot(MainPrimary)); - BotAddEquipItem(MainSecondary, GetBotItemBySlot(MainSecondary)); - //archerbot->SendWearChange(MATERIAL_PRIMARY); - //archerbot->SendWearChange(MATERIAL_SECONDARY); + BotAddEquipItem(EQEmu::legacy::SlotPrimary, GetBotItemBySlot(EQEmu::legacy::SlotPrimary)); + BotAddEquipItem(EQEmu::legacy::SlotSecondary, GetBotItemBySlot(EQEmu::legacy::SlotSecondary)); SetAttackTimer(); - Say("My blade is ready."); - } - else { - //archerbot->SendWearChange(MATERIAL_PRIMARY); - //archerbot->SendWearChange(MATERIAL_SECONDARY); - BotRemoveEquipItem(MainPrimary); - BotRemoveEquipItem(MainSecondary); - //archerbot->SendBotArcheryWearChange(MATERIAL_PRIMARY, archeryMaterial, archeryColor); - BotAddEquipItem(MainAmmo, GetBotItemBySlot(MainAmmo)); - BotAddEquipItem(MainSecondary, GetBotItemBySlot(MainRange)); + BotGroupSay(this, "My blade is ready"); + } else { + BotRemoveEquipItem(EQEmu::legacy::SlotPrimary); + BotRemoveEquipItem(EQEmu::legacy::SlotSecondary); + BotAddEquipItem(EQEmu::legacy::SlotAmmo, GetBotItemBySlot(EQEmu::legacy::SlotAmmo)); + BotAddEquipItem(EQEmu::legacy::SlotSecondary, GetBotItemBySlot(EQEmu::legacy::SlotRange)); SetAttackTimer(); - Say("My bow is true and ready."); + BotGroupSay(this, "My bow is true and ready"); } } - else { - Say("I don't know how to use a bow."); - } + else + BotGroupSay(this, "I don't know how to use a bow"); } void Bot::Sit() { if(IsMoving()) { moved = false; - // SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); tar_ndx = 0; } @@ -307,7 +279,6 @@ void Bot::Stand() { bool Bot::IsSitting() { bool result = false; - if(GetAppearance() == eaSitting && !IsMoving()) result = true; @@ -316,7 +287,6 @@ bool Bot::IsSitting() { bool Bot::IsStanding() { bool result = false; - if(GetAppearance() == eaStanding) result = true; @@ -326,15 +296,12 @@ bool Bot::IsStanding() { NPCType Bot::FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender, float size, uint32 face, uint32 hairStyle, uint32 hairColor, uint32 eyeColor, uint32 eyeColor2, uint32 beardColor, uint32 beard, uint32 drakkinHeritage, uint32 drakkinTattoo, uint32 drakkinDetails, int32 hp, int32 mana, int32 mr, int32 cr, int32 dr, int32 fr, int32 pr, int32 corrup, int32 ac, uint32 str, uint32 sta, uint32 dex, uint32 agi, uint32 _int, uint32 wis, uint32 cha, uint32 attack) { NPCType BotNPCType; int CopyLength = 0; - CopyLength = botName.copy(BotNPCType.name, 63); BotNPCType.name[CopyLength] = '\0'; CopyLength = 0; - CopyLength = botLastName.copy(BotNPCType.lastname, 69); BotNPCType.lastname[CopyLength] = '\0'; CopyLength = 0; - BotNPCType.npc_spells_id = botSpellsID; BotNPCType.level = botLevel; BotNPCType.race = botRace; @@ -368,42 +335,35 @@ NPCType Bot::FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::str BotNPCType.WIS = wis; BotNPCType.CHA = cha; BotNPCType.ATK = attack; - BotNPCType.npc_id = 0; BotNPCType.texture = 0; BotNPCType.d_melee_texture1 = 0; BotNPCType.d_melee_texture2 = 0; BotNPCType.qglobal = false; BotNPCType.attack_speed = 0; - BotNPCType.runspeed = 1.25; + BotNPCType.runspeed = 0.7f; BotNPCType.bodytype = 1; BotNPCType.findable = 0; BotNPCType.hp_regen = 1; BotNPCType.mana_regen = 1; BotNPCType.maxlevel = botLevel; - - BotNPCType.light = NOT_USED; // due to the way that bots are coded..this is sent post-spawn - + BotNPCType.light = 0; // due to the way that bots are coded..this is sent post-spawn return BotNPCType; } NPCType Bot::CreateDefaultNPCTypeStructForBot(std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender) { NPCType Result; int CopyLength = 0; - CopyLength = botName.copy(Result.name, 63); Result.name[CopyLength] = '\0'; CopyLength = 0; - CopyLength = botLastName.copy(Result.lastname, 69); Result.lastname[CopyLength] = '\0'; CopyLength = 0; - Result.level = botLevel; Result.race = botRace; Result.class_ = botClass; Result.gender = gender; - // default values Result.maxlevel = botLevel; Result.size = 6.0; @@ -412,7 +372,7 @@ NPCType Bot::CreateDefaultNPCTypeStructForBot(std::string botName, std::string b Result.drakkin_details = 0; Result.drakkin_heritage = 0; Result.drakkin_tattoo = 0; - Result.runspeed = 1.25; + Result.runspeed = 0.7f; Result.bodytype = 1; Result.findable = 0; Result.hp_regen = 1; @@ -438,13 +398,11 @@ NPCType Bot::CreateDefaultNPCTypeStructForBot(std::string botName, std::string b Result.CR = 25; Result.Corrup = 15; Result.AC = 12; - return Result; } void Bot::GenerateBaseStats() { int BotSpellID = 0; - // base stats uint32 Strength = _baseSTR; uint32 Stamina = _baseSTA; @@ -460,286 +418,284 @@ void Bot::GenerateBaseStats() { int32 PoisonResist = _basePR; int32 ColdResist = _baseCR; int32 CorruptionResist = _baseCorrup; - switch(this->GetClass()) { - case 1: // Warrior (why not just use 'case WARRIOR:'?) - Strength += 10; - Stamina += 20; - Agility += 10; - Dexterity += 10; - Attack += 12; - break; - case 2: // Cleric - BotSpellID = 701; - Strength += 5; - Stamina += 5; - Agility += 10; - Wisdom += 30; - Attack += 8; - break; - case 3: // Paladin - BotSpellID = 708; - Strength += 15; - Stamina += 5; - Wisdom += 15; - Charisma += 10; - Dexterity += 5; - Attack += 17; - break; - case 4: // Ranger - BotSpellID = 710; - Strength += 15; - Stamina += 10; - Agility += 10; - Wisdom += 15; - Attack += 17; - break; - case 5: // Shadowknight - BotSpellID = 709; - Strength += 10; - Stamina += 15; - Intelligence += 20; - Charisma += 5; - Attack += 17; - break; - case 6: // Druid - BotSpellID = 707; - Stamina += 15; - Wisdom += 35; - Attack += 5; - break; - case 7: // Monk - Strength += 5; - Stamina += 15; - Agility += 15; - Dexterity += 15; - Attack += 17; - break; - case 8: // Bard - BotSpellID = 711; - Strength += 15; - Dexterity += 10; - Charisma += 15; - Intelligence += 10; - Attack += 17; - break; - case 9: // Rogue - Strength += 10; - Stamina += 20; - Agility += 10; - Dexterity += 10; - Attack += 12; - break; - case 10: // Shaman - BotSpellID = 706; - Stamina += 10; - Wisdom += 30; - Charisma += 10; - Attack += 28; - break; - case 11: // Necromancer - BotSpellID = 703; - Dexterity += 10; - Agility += 10; - Intelligence += 30; - Attack += 5; - break; - case 12: // Wizard - BotSpellID = 702; - Stamina += 20; - Intelligence += 30; - Attack += 5; - break; - case 13: // Magician - BotSpellID = 704; - Stamina += 20; - Intelligence += 30; - Attack += 5; - break; - case 14: // Enchanter - BotSpellID = 705; - Intelligence += 25; - Charisma += 25; - Attack += 5; - break; - case 15: // Beastlord - BotSpellID = 712; - Stamina += 10; - Agility += 10; - Dexterity += 5; - Wisdom += 20; - Charisma += 5; - Attack += 31; - break; - case 16: // Berserker - Strength += 10; - Stamina += 15; - Dexterity += 15; - Agility += 10; - Attack += 25; - break; + case 1: // Warrior (why not just use 'case WARRIOR:'?) + Strength += 10; + Stamina += 20; + Agility += 10; + Dexterity += 10; + Attack += 12; + break; + case 2: // Cleric + BotSpellID = 701; + Strength += 5; + Stamina += 5; + Agility += 10; + Wisdom += 30; + Attack += 8; + break; + case 3: // Paladin + BotSpellID = 708; + Strength += 15; + Stamina += 5; + Wisdom += 15; + Charisma += 10; + Dexterity += 5; + Attack += 17; + break; + case 4: // Ranger + BotSpellID = 710; + Strength += 15; + Stamina += 10; + Agility += 10; + Wisdom += 15; + Attack += 17; + break; + case 5: // Shadowknight + BotSpellID = 709; + Strength += 10; + Stamina += 15; + Intelligence += 20; + Charisma += 5; + Attack += 17; + break; + case 6: // Druid + BotSpellID = 707; + Stamina += 15; + Wisdom += 35; + Attack += 5; + break; + case 7: // Monk + Strength += 5; + Stamina += 15; + Agility += 15; + Dexterity += 15; + Attack += 17; + break; + case 8: // Bard + BotSpellID = 711; + Strength += 15; + Dexterity += 10; + Charisma += 15; + Intelligence += 10; + Attack += 17; + break; + case 9: // Rogue + Strength += 10; + Stamina += 20; + Agility += 10; + Dexterity += 10; + Attack += 12; + break; + case 10: // Shaman + BotSpellID = 706; + Stamina += 10; + Wisdom += 30; + Charisma += 10; + Attack += 28; + break; + case 11: // Necromancer + BotSpellID = 703; + Dexterity += 10; + Agility += 10; + Intelligence += 30; + Attack += 5; + break; + case 12: // Wizard + BotSpellID = 702; + Stamina += 20; + Intelligence += 30; + Attack += 5; + break; + case 13: // Magician + BotSpellID = 704; + Stamina += 20; + Intelligence += 30; + Attack += 5; + break; + case 14: // Enchanter + BotSpellID = 705; + Intelligence += 25; + Charisma += 25; + Attack += 5; + break; + case 15: // Beastlord + BotSpellID = 712; + Stamina += 10; + Agility += 10; + Dexterity += 5; + Wisdom += 20; + Charisma += 5; + Attack += 31; + break; + case 16: // Berserker + Strength += 10; + Stamina += 15; + Dexterity += 15; + Agility += 10; + Attack += 25; + break; } float BotSize = GetSize(); switch(this->GetRace()) { - case 1: // Humans have no race bonus - break; - case 2: // Barbarian - Strength += 28; - Stamina += 20; - Agility += 7; - Dexterity -= 5; - Wisdom -= 5; - Intelligence -= 10; - Charisma -= 20; - BotSize = 7.0; - ColdResist += 10; - break; - case 3: // Erudite - Strength -= 15; - Stamina -= 5; - Agility -= 5; - Dexterity -= 5; - Wisdom += 8; - Intelligence += 32; - Charisma -= 5; - MagicResist += 5; - DiseaseResist -= 5; - break; - case 4: // Wood Elf - Strength -= 10; - Stamina -= 10; - Agility += 20; - Dexterity += 5; - Wisdom += 5; - BotSize = 5.0; - break; - case 5: // High Elf - Strength -= 20; - Stamina -= 10; - Agility += 10; - Dexterity -= 5; - Wisdom += 20; - Intelligence += 12; - Charisma += 5; - break; - case 6: // Dark Elf - Strength -= 15; - Stamina -= 10; - Agility += 15; - Wisdom += 8; - Intelligence += 24; - Charisma -= 15; - BotSize = 5.0; - break; - case 7: // Half Elf - Strength -= 5; - Stamina -= 5; - Agility += 15; - Dexterity += 10; - Wisdom -= 15; - BotSize = 5.5; - break; - case 8: // Dwarf - Strength += 15; - Stamina += 15; - Agility -= 5; - Dexterity += 15; - Wisdom += 8; - Intelligence -= 15; - Charisma -= 30; - BotSize = 4.0; - MagicResist -= 5; - PoisonResist += 5; - break; - case 9: // Troll - Strength += 33; - Stamina += 34; - Agility += 8; - Wisdom -= 15; - Intelligence -= 23; - Charisma -= 35; - BotSize = 8.0; - FireResist -= 20; - break; - case 10: // Ogre - Strength += 55; - Stamina += 77; - Agility -= 5; - Dexterity -= 5; - Wisdom -= 8; - Intelligence -= 15; - Charisma -= 38; - BotSize = 9.0; - break; - case 11: // Halfling - Strength -= 5; - Agility += 20; - Dexterity += 15; - Wisdom += 5; - Intelligence -= 8; - Charisma -= 25; - BotSize = 3.5; - PoisonResist += 5; - DiseaseResist += 5; - break; - case 12: // Gnome - Strength -= 15; - Stamina -= 5; - Agility += 10; - Dexterity += 10; - Wisdom -= 8; - Intelligence += 23; - Charisma -= 15; - BotSize = 3.0; - break; - case 128: // Iksar - Strength -= 5; - Stamina -= 5; - Agility += 15; - Dexterity += 10; - Wisdom += 5; - Charisma -= 20; - MagicResist -= 5; - FireResist -= 5; - break; - case 130: // Vah Shir - Strength += 15; - Agility += 15; - Dexterity -= 5; - Wisdom -= 5; - Intelligence -= 10; - Charisma -= 10; - BotSize = 7.0; - MagicResist -= 5; - FireResist -= 5; - break; - case 330: // Froglok - Strength -= 5; - Stamina += 5; - Agility += 25; - Dexterity += 25; - Charisma -= 25; - BotSize = 5.0; - MagicResist -= 5; - FireResist -= 5; - break; - case 522: // Drakkin - Strength -= 5; - Stamina += 5; - Agility += 10; - Intelligence += 10; - Wisdom += 5; - BotSize = 5.0; - PoisonResist += 2; - DiseaseResist += 2; - MagicResist += 2; - FireResist += 2; - ColdResist += 2; - break; + case 1: // Humans have no race bonus + break; + case 2: // Barbarian + Strength += 28; + Stamina += 20; + Agility += 7; + Dexterity -= 5; + Wisdom -= 5; + Intelligence -= 10; + Charisma -= 20; + BotSize = 7.0; + ColdResist += 10; + break; + case 3: // Erudite + Strength -= 15; + Stamina -= 5; + Agility -= 5; + Dexterity -= 5; + Wisdom += 8; + Intelligence += 32; + Charisma -= 5; + MagicResist += 5; + DiseaseResist -= 5; + break; + case 4: // Wood Elf + Strength -= 10; + Stamina -= 10; + Agility += 20; + Dexterity += 5; + Wisdom += 5; + BotSize = 5.0; + break; + case 5: // High Elf + Strength -= 20; + Stamina -= 10; + Agility += 10; + Dexterity -= 5; + Wisdom += 20; + Intelligence += 12; + Charisma += 5; + break; + case 6: // Dark Elf + Strength -= 15; + Stamina -= 10; + Agility += 15; + Wisdom += 8; + Intelligence += 24; + Charisma -= 15; + BotSize = 5.0; + break; + case 7: // Half Elf + Strength -= 5; + Stamina -= 5; + Agility += 15; + Dexterity += 10; + Wisdom -= 15; + BotSize = 5.5; + break; + case 8: // Dwarf + Strength += 15; + Stamina += 15; + Agility -= 5; + Dexterity += 15; + Wisdom += 8; + Intelligence -= 15; + Charisma -= 30; + BotSize = 4.0; + MagicResist -= 5; + PoisonResist += 5; + break; + case 9: // Troll + Strength += 33; + Stamina += 34; + Agility += 8; + Wisdom -= 15; + Intelligence -= 23; + Charisma -= 35; + BotSize = 8.0; + FireResist -= 20; + break; + case 10: // Ogre + Strength += 55; + Stamina += 77; + Agility -= 5; + Dexterity -= 5; + Wisdom -= 8; + Intelligence -= 15; + Charisma -= 38; + BotSize = 9.0; + break; + case 11: // Halfling + Strength -= 5; + Agility += 20; + Dexterity += 15; + Wisdom += 5; + Intelligence -= 8; + Charisma -= 25; + BotSize = 3.5; + PoisonResist += 5; + DiseaseResist += 5; + break; + case 12: // Gnome + Strength -= 15; + Stamina -= 5; + Agility += 10; + Dexterity += 10; + Wisdom -= 8; + Intelligence += 23; + Charisma -= 15; + BotSize = 3.0; + break; + case 128: // Iksar + Strength -= 5; + Stamina -= 5; + Agility += 15; + Dexterity += 10; + Wisdom += 5; + Charisma -= 20; + MagicResist -= 5; + FireResist -= 5; + break; + case 130: // Vah Shir + Strength += 15; + Agility += 15; + Dexterity -= 5; + Wisdom -= 5; + Intelligence -= 10; + Charisma -= 10; + BotSize = 7.0; + MagicResist -= 5; + FireResist -= 5; + break; + case 330: // Froglok + Strength -= 5; + Stamina += 5; + Agility += 25; + Dexterity += 25; + Charisma -= 25; + BotSize = 5.0; + MagicResist -= 5; + FireResist -= 5; + break; + case 522: // Drakkin + Strength -= 5; + Stamina += 5; + Agility += 10; + Intelligence += 10; + Wisdom += 5; + BotSize = 5.0; + PoisonResist += 2; + DiseaseResist += 2; + MagicResist += 2; + FireResist += 2; + ColdResist += 2; + break; } - this->STR = Strength; this->STA = Stamina; this->DEX = Dexterity; @@ -753,20 +709,23 @@ void Bot::GenerateBaseStats() { this->DR = DiseaseResist; this->PR = PoisonResist; this->CR = ColdResist; + this->PhR = 0; this->Corrup = CorruptionResist; SetBotSpellID(BotSpellID); this->size = BotSize; + this->pAggroRange = 0; + this->pAssistRange = 0; + this->raid_target = false; + this->deity = 396; } void Bot::GenerateAppearance() { // Randomize facial appearance int iFace = 0; - if(this->GetRace() == 2) { // Barbarian w/Tatoo + if(this->GetRace() == 2) // Barbarian w/Tatoo iFace = zone->random.Int(0, 79); - } - else { + else iFace = zone->random.Int(0, 7); - } int iHair = 0; int iBeard = 0; @@ -775,40 +734,32 @@ void Bot::GenerateAppearance() { iHair = zone->random.Int(0, 8); iBeard = zone->random.Int(0, 11); iBeardColor = zone->random.Int(0, 3); - } - else if(this->GetGender()) { + } else if(this->GetGender()) { iHair = zone->random.Int(0, 2); if(this->GetRace() == 8) { // Dwarven Females can have a beard - if(zone->random.Int(1, 100) < 50) { + if(zone->random.Int(1, 100) < 50) iFace += 10; - } } - } - else { + } else { iHair = zone->random.Int(0, 3); iBeard = zone->random.Int(0, 5); iBeardColor = zone->random.Int(0, 19); } int iHairColor = 0; - if(this->GetRace() == 522) { + if(this->GetRace() == 522) iHairColor = zone->random.Int(0, 3); - } - else { + else iHairColor = zone->random.Int(0, 19); - } uint8 iEyeColor1 = (uint8)zone->random.Int(0, 9); uint8 iEyeColor2 = 0; - if(this->GetRace() == 522) { + if(this->GetRace() == 522) iEyeColor1 = iEyeColor2 = (uint8)zone->random.Int(0, 11); - } - else if(zone->random.Int(1, 100) > 96) { + else if(zone->random.Int(1, 100) > 96) iEyeColor2 = zone->random.Int(0, 9); - } - else { + else iEyeColor2 = iEyeColor1; - } int iHeritage = 0; int iTattoo = 0; @@ -818,7 +769,6 @@ void Bot::GenerateAppearance() { iTattoo = zone->random.Int(0, 7); iDetails = zone->random.Int(0, 7); } - this->luclinface = iFace; this->hairstyle = iHair; this->beard = iBeard; @@ -829,77 +779,71 @@ void Bot::GenerateAppearance() { this->drakkin_heritage = iHeritage; this->drakkin_tattoo = iTattoo; this->drakkin_details = iDetails; - } -int32 Bot::acmod() -{ +int32 Bot::acmod() { int agility = GetAGI(); int level = GetLevel(); if(agility < 1 || level < 1) return 0; - if(agility <= 74) - { + if(agility <= 74) { if(agility == 1) return -24; - else if(agility <=3) + else if(agility <= 3) return -23; else if(agility == 4) return -22; - else if(agility <=6) + else if(agility <= 6) return -21; - else if(agility <=8) + else if(agility <= 8) return -20; else if(agility == 9) return -19; - else if(agility <=11) + else if(agility <= 11) return -18; else if(agility == 12) return -17; - else if(agility <=14) + else if(agility <= 14) return -16; - else if(agility <=16) + else if(agility <= 16) return -15; else if(agility == 17) return -14; - else if(agility <=19) + else if(agility <= 19) return -13; else if(agility == 20) return -12; - else if(agility <=22) + else if(agility <= 22) return -11; - else if(agility <=24) + else if(agility <= 24) return -10; else if(agility == 25) return -9; - else if(agility <=27) + else if(agility <= 27) return -8; else if(agility == 28) return -7; - else if(agility <=30) + else if(agility <= 30) return -6; - else if(agility <=32) + else if(agility <= 32) return -5; else if(agility == 33) return -4; - else if(agility <=35) + else if(agility <= 35) return -3; else if(agility == 36) return -2; - else if(agility <=38) + else if(agility <= 38) return -1; - else if(agility <=65) + else if(agility <= 65) return 0; - else if(agility <=70) + else if(agility <= 70) return 1; - else if(agility <=74) + else if(agility <= 74) return 5; - } - else if(agility <= 137) - { - if(agility == 75) - { + } else if(agility <= 137) { + if(agility == 75) { if(level <= 6) return 9; else if(level <= 19) @@ -908,9 +852,7 @@ int32 Bot::acmod() return 33; else return 39; - } - else if(agility >= 76 && agility <= 79) - { + } else if(agility >= 76 && agility <= 79) { if(level <= 6) return 10; else if(level <= 19) @@ -919,9 +861,7 @@ int32 Bot::acmod() return 33; else return 40; - } - else if(agility == 80) - { + } else if(agility == 80) { if(level <= 6) return 11; else if(level <= 19) @@ -930,9 +870,7 @@ int32 Bot::acmod() return 34; else return 41; - } - else if(agility >= 81 && agility <= 85) - { + } else if(agility >= 81 && agility <= 85) { if(level <= 6) return 12; else if(level <= 19) @@ -941,9 +879,7 @@ int32 Bot::acmod() return 35; else return 42; - } - else if(agility >= 86 && agility <= 90) - { + } else if(agility >= 86 && agility <= 90) { if(level <= 6) return 12; else if(level <= 19) @@ -952,9 +888,7 @@ int32 Bot::acmod() return 36; else return 42; - } - else if(agility >= 91 && agility <= 95) - { + } else if(agility >= 91 && agility <= 95) { if(level <= 6) return 13; else if(level <= 19) @@ -963,8 +897,7 @@ int32 Bot::acmod() return 36; else return 43; - } - else if(agility >= 96 && agility <= 99){ + } else if(agility >= 96 && agility <= 99) { if(level <= 6) return 14; else if(level <= 19) @@ -973,9 +906,7 @@ int32 Bot::acmod() return 37; else return 44; - } - else if(agility == 100 && level >= 7) - { + } else if(agility == 100 && level >= 7) { if(level <= 19) return 28; else if (level <= 39) @@ -984,39 +915,30 @@ int32 Bot::acmod() return 45; } else if(level <= 6) - { return 15; - } //level is >6 - else if(agility >= 101 && agility <= 105) - { + else if(agility >= 101 && agility <= 105) { if(level <= 19) return 29; else if(level <= 39) return 39;// not verified else return 45; - } - else if(agility >= 106 && agility <= 110) - { + } else if(agility >= 106 && agility <= 110) { if(level <= 19) return 29; else if(level <= 39) return 39;// not verified else return 46; - } - else if(agility >= 111 && agility <= 115) - { + } else if(agility >= 111 && agility <= 115) { if(level <= 19) return 30; else if(level <= 39) return 40;// not verified else return 47; - } - else if(agility >= 116 && agility <= 119) - { + } else if(agility >= 116 && agility <= 119) { if(level <= 19) return 31; else if(level <= 39) @@ -1025,329 +947,280 @@ int32 Bot::acmod() return 47; } else if(level <= 19) - { return 32; - } //level is > 19 - else if(agility == 120) - { + else if(agility == 120) { if(level <= 39) return 42; else return 48; - } - else if(agility <= 125) - { + } else if(agility <= 125) { if(level <= 39) return 42; else return 49; - } - else if(agility <= 135) - { + } else if(agility <= 135) { if(level <= 39) return 42; else return 50; - } - else { + } else { if(level <= 39) return 42; else return 51; } - } - else if(agility <= 300) - { + } else if(agility <= 300) { if(level <= 6) { if(agility <= 139) - return(21); + return 21; else if(agility == 140) - return(22); + return 22; else if(agility <= 145) - return(23); + return 23; else if(agility <= 150) - return(23); + return 23; else if(agility <= 155) - return(24); + return 24; else if(agility <= 159) - return(25); + return 25; else if(agility == 160) - return(26); + return 26; else if(agility <= 165) - return(26); + return 26; else if(agility <= 170) - return(27); + return 27; else if(agility <= 175) - return(28); + return 28; else if(agility <= 179) - return(28); + return 28; else if(agility == 180) - return(29); + return 29; else if(agility <= 185) - return(30); + return 30; else if(agility <= 190) - return(31); + return 31; else if(agility <= 195) - return(31); + return 31; else if(agility <= 199) - return(32); + return 32; else if(agility <= 219) - return(33); + return 33; else if(agility <= 239) - return(34); + return 34; else - return(35); - } - else if(level <= 19) - { + return 35; + } else if(level <= 19) { if(agility <= 139) - return(34); + return 34; else if(agility == 140) - return(35); + return 35; else if(agility <= 145) - return(36); + return 36; else if(agility <= 150) - return(37); + return 37; else if(agility <= 155) - return(37); + return 37; else if(agility <= 159) - return(38); + return 38; else if(agility == 160) - return(39); + return 39; else if(agility <= 165) - return(40); + return 40; else if(agility <= 170) - return(40); + return 40; else if(agility <= 175) - return(41); + return 41; else if(agility <= 179) - return(42); + return 42; else if(agility == 180) - return(43); + return 43; else if(agility <= 185) - return(43); + return 43; else if(agility <= 190) - return(44); + return 44; else if(agility <= 195) - return(45); + return 45; else if(agility <= 199) - return(45); + return 45; else if(agility <= 219) - return(46); + return 46; else if(agility <= 239) - return(47); + return 47; else - return(48); - } - else if(level <= 39) - { + return 48; + } else if(level <= 39) { if(agility <= 139) - return(44); + return 44; else if(agility == 140) - return(45); + return 45; else if(agility <= 145) - return(46); + return 46; else if(agility <= 150) - return(47); + return 47; else if(agility <= 155) - return(47); + return 47; else if(agility <= 159) - return(48); + return 48; else if(agility == 160) - return(49); + return 49; else if(agility <= 165) - return(50); + return 50; else if(agility <= 170) - return(50); + return 50; else if(agility <= 175) - return(51); + return 51; else if(agility <= 179) - return(52); + return 52; else if(agility == 180) - return(53); + return 53; else if(agility <= 185) - return(53); + return 53; else if(agility <= 190) - return(54); + return 54; else if(agility <= 195) - return(55); + return 55; else if(agility <= 199) - return(55); + return 55; else if(agility <= 219) - return(56); + return 56; else if(agility <= 239) - return(57); + return 57; else - return(58); - } - else - { //lvl >= 40 + return 58; + } else { //lvl >= 40 if(agility <= 139) - return(51); + return 51; else if(agility == 140) - return(52); + return 52; else if(agility <= 145) - return(53); + return 53; else if(agility <= 150) - return(53); + return 53; else if(agility <= 155) - return(54); + return 54; else if(agility <= 159) - return(55); + return 55; else if(agility == 160) - return(56); + return 56; else if(agility <= 165) - return(56); + return 56; else if(agility <= 170) - return(57); + return 57; else if(agility <= 175) - return(58); + return 58; else if(agility <= 179) - return(58); + return 58; else if(agility == 180) - return(59); + return 59; else if(agility <= 185) - return(60); + return 60; else if(agility <= 190) - return(61); + return 61; else if(agility <= 195) - return(61); + return 61; else if(agility <= 199) - return(62); + return 62; else if(agility <= 219) - return(63); + return 63; else if(agility <= 239) - return(64); + return 64; else - return(65); + return 65; } } else - { - //seems about 21 agil per extra AC pt over 300... - return (65 + ((agility-300) / 21)); - } + return (65 + ((agility - 300) / 21)); #if EQDEBUG >= 11 Log.Out(Logs::General, Logs::Error, "Error in Bot::acmod(): Agility: %i, Level: %i",agility,level); #endif return 0; } -void Bot::GenerateArmorClass() -{ +void Bot::GenerateArmorClass() { /// new formula int avoidance = 0; - avoidance = (acmod() + ((GetSkill(SkillDefense)*16)/9)); + avoidance = (acmod() + ((GetSkill(EQEmu::skills::SkillDefense) * 16) / 9)); if(avoidance < 0) avoidance = 0; int mitigation = 0; - if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER) - { - mitigation = GetSkill(SkillDefense)/4 + (itembonuses.AC+1); + if(GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER) { + mitigation = (GetSkill(EQEmu::skills::SkillDefense) / 4 + (itembonuses.AC + 1)); mitigation -= 4; - } - else - { - mitigation = GetSkill(SkillDefense)/3 + ((itembonuses.AC*4)/3); + } else { + mitigation = (GetSkill(EQEmu::skills::SkillDefense) / 3 + ((itembonuses.AC * 4) / 3)); if(GetClass() == MONK) - mitigation += GetLevel() * 13/10; //the 13/10 might be wrong, but it is close... + mitigation += (GetLevel() * 13 / 10); //the 13/10 might be wrong, but it is close... } int displayed = 0; - displayed += ((avoidance+mitigation)*1000)/847; //natural AC + displayed += (((avoidance + mitigation) * 1000) / 847); //natural AC //Iksar AC, untested - if(GetRace() == IKSAR) - { + if(GetRace() == IKSAR) { displayed += 12; int iksarlevel = GetLevel(); iksarlevel -= 10; if(iksarlevel > 25) iksarlevel = 25; + if(iksarlevel > 0) - displayed += iksarlevel * 12 / 10; + displayed += (iksarlevel * 12 / 10); } //spell AC bonuses are added directly to natural total displayed += spellbonuses.AC; - this->AC = displayed; } -uint16 Bot::GetPrimarySkillValue() -{ - SkillUseTypes skill = HIGHEST_SKILL; //because nullptr == 0, which is 1H Slashing, & we want it to return 0 from GetSkill - bool equiped = m_inv.GetItem(MainPrimary); - +uint16 Bot::GetPrimarySkillValue() { + EQEmu::skills::SkillType skill = EQEmu::skills::HIGHEST_SKILL; //because nullptr == 0, which is 1H Slashing, & we want it to return 0 from GetSkill + bool equiped = m_inv.GetItem(EQEmu::legacy::SlotPrimary); if(!equiped) - { - skill = SkillHandtoHand; - } - else - { - uint8 type = m_inv.GetItem(MainPrimary)->GetItem()->ItemType; //is this the best way to do this? - switch(type) - { - case ItemType1HSlash: // 1H Slashing - { - skill = Skill1HSlashing; - break; - } - case ItemType2HSlash: // 2H Slashing - { - skill = Skill2HSlashing; - break; - } - case ItemType1HPiercing: // Piercing - { - skill = Skill1HPiercing; - break; - } - case ItemType1HBlunt: // 1H Blunt - { - skill = Skill1HBlunt; - break; - } - case ItemType2HBlunt: // 2H Blunt - { - skill = Skill2HBlunt; - break; - } - case ItemType2HPiercing: // 2H Piercing - { - skill = Skill1HPiercing; // change to Skill2HPiercing once activated - break; - } - case ItemTypeMartial: // Hand to Hand - { - skill = SkillHandtoHand; - break; - } - default: // All other types default to Hand to Hand - { - skill = SkillHandtoHand; - break; - } + skill = EQEmu::skills::SkillHandtoHand; + else { + uint8 type = m_inv.GetItem(EQEmu::legacy::SlotPrimary)->GetItem()->ItemType; //is this the best way to do this? + switch(type) { + case EQEmu::item::ItemType1HSlash: + skill = EQEmu::skills::Skill1HSlashing; + break; + case EQEmu::item::ItemType2HSlash: + skill = EQEmu::skills::Skill2HSlashing; + break; + case EQEmu::item::ItemType1HPiercing: + skill = EQEmu::skills::Skill1HPiercing; + break; + case EQEmu::item::ItemType1HBlunt: + skill = EQEmu::skills::Skill1HBlunt; + break; + case EQEmu::item::ItemType2HBlunt: + skill = EQEmu::skills::Skill2HBlunt; + break; + case EQEmu::item::ItemType2HPiercing: + skill = EQEmu::skills::Skill2HPiercing; + break; + case EQEmu::item::ItemTypeMartial: + skill = EQEmu::skills::SkillHandtoHand; + break; + default: + skill = EQEmu::skills::SkillHandtoHand; + break; } } return GetSkill(skill); } -uint16 Bot::MaxSkill(SkillUseTypes skillid, uint16 class_, uint16 level) const { +uint16 Bot::MaxSkill(EQEmu::skills::SkillType skillid, uint16 class_, uint16 level) const { return(database.GetSkillCap(class_, skillid, level)); } -uint32 Bot::GetTotalATK() -{ +uint32 Bot::GetTotalATK() { uint32 AttackRating = 0; uint32 WornCap = itembonuses.ATK; - if(IsBot()) { - AttackRating = ((WornCap * 1.342) + (GetSkill(SkillOffense) * 1.345) + ((GetSTR() - 66) * 0.9) + (GetPrimarySkillValue() * 2.69)); + AttackRating = ((WornCap * 1.342) + (GetSkill(EQEmu::skills::SkillOffense) * 1.345) + ((GetSTR() - 66) * 0.9) + (GetPrimarySkillValue() * 2.69)); AttackRating += aabonuses.ATK + GroupLeadershipAAOffenseEnhancement(); - if (AttackRating < 10) AttackRating = 10; } @@ -1355,34 +1228,27 @@ uint32 Bot::GetTotalATK() AttackRating = GetATK(); AttackRating += spellbonuses.ATK; - return AttackRating; } -uint32 Bot::GetATKRating() -{ +uint32 Bot::GetATKRating() { uint32 AttackRating = 0; if(IsBot()) { - AttackRating = (GetSkill(SkillOffense) * 1.345) + ((GetSTR() - 66) * 0.9) + (GetPrimarySkillValue() * 2.69); - + AttackRating = (GetSkill(EQEmu::skills::SkillOffense) * 1.345) + ((GetSTR() - 66) * 0.9) + (GetPrimarySkillValue() * 2.69); if (AttackRating < 10) AttackRating = 10; } return AttackRating; } -int32 Bot::GenerateBaseHitPoints() -{ +int32 Bot::GenerateBaseHitPoints() { // Calc Base Hit Points int new_base_hp = 0; uint32 lm = GetClassLevelFactor(); - uint32 Post255; - uint32 NormalSTA = GetSTA(); - - if(GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->GetClientVersion() >= ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) - { + int32 Post255; + int32 NormalSTA = GetSTA(); + if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { float SoDPost255; - if(((NormalSTA - 255) / 2) > 0) SoDPost255 = ((NormalSTA - 255) / 2); else @@ -1391,1038 +1257,396 @@ int32 Bot::GenerateBaseHitPoints() int hp_factor = GetClassHPFactor(); if(level < 41) - { new_base_hp = (5 + (GetLevel() * hp_factor / 12) + ((NormalSTA - SoDPost255) * GetLevel() * hp_factor / 3600)); - } else if(level < 81) - { - new_base_hp = (5 + (40 * hp_factor / 12) + ((GetLevel() - 40) * hp_factor / 6) + - ((NormalSTA - SoDPost255) * hp_factor / 90) + - ((NormalSTA - SoDPost255) * (GetLevel() - 40) * hp_factor / 1800)); - } + new_base_hp = (5 + (40 * hp_factor / 12) + ((GetLevel() - 40) * hp_factor / 6) + ((NormalSTA - SoDPost255) * hp_factor / 90) + ((NormalSTA - SoDPost255) * (GetLevel() - 40) * hp_factor / 1800)); else - { - new_base_hp = (5 + (80 * hp_factor / 8) + ((GetLevel() - 80) * hp_factor / 10) + - ((NormalSTA - SoDPost255) * hp_factor / 90) + - ((NormalSTA - SoDPost255) * hp_factor / 45)); - } - } - else - { - if((NormalSTA-255)/2 > 0) - Post255 = (NormalSTA-255)/2; + new_base_hp = (5 + (80 * hp_factor / 8) + ((GetLevel() - 80) * hp_factor / 10) + ((NormalSTA - SoDPost255) * hp_factor / 90) + ((NormalSTA - SoDPost255) * hp_factor / 45)); + } else { + if(((NormalSTA - 255) / 2) > 0) + Post255 = ((NormalSTA - 255) / 2); else Post255 = 0; - new_base_hp = (5)+(GetLevel()*lm/10) + (((NormalSTA-Post255)*GetLevel()*lm/3000)) + ((Post255*1)*lm/6000); + new_base_hp = (5) + (GetLevel() * lm / 10) + (((NormalSTA - Post255) * GetLevel() * lm / 3000)) + ((Post255 * 1) * lm / 6000); } this->base_hp = new_base_hp; - return new_base_hp; } -void Bot::GenerateAABonuses(StatBonuses* newbon) { - // General AA bonus - uint8 botClass = GetClass(); - uint8 botLevel = GetLevel(); - - memset(newbon, 0, sizeof(StatBonuses)); //start fresh - - if(botLevel >= 51) { - //level 51 = 1 AA level - - int i; - int totalAAs = database.CountAAs(); - uint32 slots = 0; - uint32 aa_AA = 0; - uint32 aa_value = 0; - for (i = 0; i < totalAAs; i++) { //iterate through all of the client's AAs - std::map::iterator aa = botAAs.find(i); - if(aa != botAAs.end()) { // make sure aa exists or we'll crash zone - aa_AA = aa->second.aa_id; //same as aaid from the aa_effects table - aa_value = aa->second.total_levels; //how many points in it - if (aa_AA > 0 || aa_value > 0) { //do we have the AA? if 1 of the 2 is set, we can assume we do - //slots = database.GetTotalAALevels(aa_AA); //find out how many effects from aa_effects table - slots = zone->GetTotalAALevels(aa_AA); //find out how many effects from aa_effects, which is loaded into memory - if (slots > 0) //and does it have any effects? may be able to put this above, not sure if it runs on each iteration - ApplyAABonuses(aa_AA + aa_value -1, slots, newbon); //add the bonuses - } - } - } - } -} - void Bot::LoadAAs() { - int maxAAExpansion = RuleI(Bots, BotAAExpansion); //get expansion to get AAs up to - botAAs.clear(); //start fresh + int maxAAExpansion = RuleI(Bots, AAExpansion); //get expansion to get AAs up to + aa_ranks.clear(); - std::string query; + int id = 0; + int points = 0; + auto iter = zone->aa_abilities.begin(); + while(iter != zone->aa_abilities.end()) { + AA::Ability *ability = (*iter).second.get(); - if(GetClass() == BERSERKER) - query = StringFormat("SELECT skill_id FROM altadv_vars WHERE berserker = 1 AND class_type > 1 AND class_type <= %i AND aa_expansion <= %i ORDER BY skill_id;", GetLevel(), maxAAExpansion); - else - query = StringFormat("SELECT skill_id FROM altadv_vars WHERE ((classes & ( 1 << %i )) >> %i) = 1 AND class_type > 1 AND class_type <= %i AND aa_expansion <= %i ORDER BY skill_id;", GetClass(), GetClass(), GetLevel(), maxAAExpansion); + //skip expendables + if(!ability->first || ability->charges > 0) { + ++iter; + continue; + } - auto results = database.QueryDatabase(query); + id = ability->first->id; + points = 0; - if(!results.Success()) { - Log.Out(Logs::General, Logs::Error, "Error in Bot::LoadAAs()"); - return; + AA::Rank *current = ability->first; + + if (current->level_req > GetLevel()) { + ++iter; + continue; + } + + while(current) { + if(!CanUseAlternateAdvancementRank(current)) { + current = nullptr; + } else { + current = current->next; + points++; + } + } + + if(points > 0) { + SetAA(id, points); + } + + ++iter; } - - int totalAAs = database.CountAAs(); - - for (auto row = results.begin(); row != results.end(); ++row) { - uint32 skill_id = 0; - skill_id = atoi(row[0]); - - if(skill_id <= 0 || skill_id >= totalAAs) - continue; - - SendAA_Struct *sendAA = zone->FindAA(skill_id); - - if(!sendAA) - continue; - - for(int i=0; imax_level; i++) { - //Get AA info & add to list - uint32 aaid = sendAA->id + i; - uint8 total_levels = 0; - uint8 req_level; - std::map::iterator RequiredLevel = AARequiredLevelAndCost.find(aaid); - - //Get level required for AA - if(RequiredLevel != AARequiredLevelAndCost.end()) - req_level = RequiredLevel->second.Level; - else - req_level = (sendAA->class_type + i * sendAA->level_inc); - - if(req_level > GetLevel()) - break; - - //Bot is high enough level for AA - std::map::iterator foundAA = botAAs.find(aaid); - - // AA is already in list - if(foundAA != botAAs.end()) - continue; - - if(sendAA->id == aaid) { - BotAA newAA; - - newAA.total_levels = 0; - newAA.aa_id = aaid; - newAA.req_level = req_level; - newAA.total_levels += 1; - - botAAs[aaid] = newAA; //add to list - } - else //update master AA record with number of levels a bot has in AA, based on level. - botAAs[sendAA->id].total_levels+=1; - } - } - } -uint32 Bot::GetAA(uint32 aa_id) { - - std::map::const_iterator find_iter = botAAs.find(aa_id); - int aaLevel = 0; - - if(find_iter != botAAs.end()) { - aaLevel = find_iter->second.total_levels; - } - - return aaLevel; -} - -//current with Client::ApplyAABonuses 9/26/12 -void Bot::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) +bool Bot::IsValidRaceClassCombo() { - if(slots == 0) //sanity check. why bother if no slots to fill? - return; - - //from AA_Ability struct - uint32 effect = 0; - int32 base1 = 0; - int32 base2 = 0; //only really used for SE_RaiseStatCap & SE_ReduceSkillTimer in aa_effects table - uint32 slot = 0; - - std::map >::const_iterator find_iter = aa_effects.find(aaid); - if(find_iter == aa_effects.end()) - { - return; - } - - for (std::map::const_iterator iter = aa_effects[aaid].begin(); iter != aa_effects[aaid].end(); ++iter) { - effect = iter->second.skill_id; - base1 = iter->second.base1; - base2 = iter->second.base2; - slot = iter->second.slot; - - //we default to 0 (SE_CurrentHP) for the effect, so if there aren't any base1/2 values, we'll just skip it - if (effect == 0 && base1 == 0 && base2 == 0) - continue; - - //IsBlankSpellEffect() - if (effect == SE_Blank || (effect == SE_CHA && base1 == 0) || effect == SE_StackingCommand_Block || effect == SE_StackingCommand_Overwrite) - continue; - - Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName()); - - uint8 focus = IsFocusEffect(0, 0, true,effect); - if (focus) - { - newbon->FocusEffects[focus] = effect; - continue; - } - - switch (effect) - { - //Note: AA effects that use accuracy are skill limited, while spell effect is not. - case SE_Accuracy: - if ((base2 == -1) && (newbon->Accuracy[HIGHEST_SKILL+1] < base1)) - newbon->Accuracy[HIGHEST_SKILL+1] = base1; - else if (newbon->Accuracy[base2] < base1) - newbon->Accuracy[base2] += base1; - break; - case SE_CurrentHP: //regens - newbon->HPRegen += base1; - break; - case SE_CurrentEndurance: - newbon->EnduranceRegen += base1; - break; - case SE_MovementSpeed: - newbon->movementspeed += base1; //should we let these stack? - /*if (base1 > newbon->movementspeed) //or should we use a total value? - newbon->movementspeed = base1;*/ - break; - case SE_STR: - newbon->STR += base1; - break; - case SE_DEX: - newbon->DEX += base1; - break; - case SE_AGI: - newbon->AGI += base1; - break; - case SE_STA: - newbon->STA += base1; - break; - case SE_INT: - newbon->INT += base1; - break; - case SE_WIS: - newbon->WIS += base1; - break; - case SE_CHA: - newbon->CHA += base1; - break; - case SE_WaterBreathing: - //handled by client - break; - case SE_CurrentMana: - newbon->ManaRegen += base1; - break; - case SE_ItemManaRegenCapIncrease: - newbon->ItemManaRegenCap += base1; - break; - case SE_ResistFire: - newbon->FR += base1; - break; - case SE_ResistCold: - newbon->CR += base1; - break; - case SE_ResistPoison: - newbon->PR += base1; - break; - case SE_ResistDisease: - newbon->DR += base1; - break; - case SE_ResistMagic: - newbon->MR += base1; - break; - case SE_ResistCorruption: - newbon->Corrup += base1; - break; - case SE_IncreaseSpellHaste: - break; - case SE_IncreaseRange: - break; - case SE_MaxHPChange: - newbon->MaxHP += base1; - break; - case SE_Packrat: - newbon->Packrat += base1; - break; - case SE_TwoHandBash: - break; - case SE_SetBreathLevel: - break; - case SE_RaiseStatCap: - switch(base2) - { - //are these #define'd somewhere? - case 0: //str - newbon->STRCapMod += base1; - break; - case 1: //sta - newbon->STACapMod += base1; - break; - case 2: //agi - newbon->AGICapMod += base1; - break; - case 3: //dex - newbon->DEXCapMod += base1; - break; - case 4: //wis - newbon->WISCapMod += base1; - break; - case 5: //int - newbon->INTCapMod += base1; - break; - case 6: //cha - newbon->CHACapMod += base1; - break; - case 7: //mr - newbon->MRCapMod += base1; - break; - case 8: //cr - newbon->CRCapMod += base1; - break; - case 9: //fr - newbon->FRCapMod += base1; - break; - case 10: //pr - newbon->PRCapMod += base1; - break; - case 11: //dr - newbon->DRCapMod += base1; - break; - case 12: //corruption - newbon->CorrupCapMod += base1; - break; - } - break; - case SE_PetDiscipline2: - break; - case SE_SpellSlotIncrease: - break; - case SE_MysticalAttune: - newbon->BuffSlotIncrease += base1; - break; - case SE_TotalHP: - newbon->HP += base1; - break; - case SE_StunResist: - newbon->StunResist += base1; - break; - case SE_SpellCritChance: - newbon->CriticalSpellChance += base1; - break; - case SE_SpellCritDmgIncrease: - newbon->SpellCritDmgIncrease += base1; - break; - case SE_DotCritDmgIncrease: - newbon->DotCritDmgIncrease += base1; - break; - case SE_ResistSpellChance: - newbon->ResistSpellChance += base1; - break; - case SE_CriticalHealChance: - newbon->CriticalHealChance += base1; - break; - case SE_CriticalHealOverTime: - newbon->CriticalHealOverTime += base1; - break; - case SE_CriticalDoTChance: - newbon->CriticalDoTChance += base1; - break; - case SE_ReduceSkillTimer: - newbon->SkillReuseTime[base2] += base1; - break; - case SE_Fearless: - newbon->Fearless = true; - break; - case SE_PersistantCasting: - newbon->PersistantCasting += base1; - break; - case SE_DelayDeath: - newbon->DelayDeath += base1; - break; - case SE_FrontalStunResist: - newbon->FrontalStunResist += base1; - break; - case SE_ImprovedBindWound: - newbon->BindWound += base1; - break; - case SE_MaxBindWound: - newbon->MaxBindWound += base1; - break; - case SE_ExtraAttackChance: - newbon->ExtraAttackChance += base1; - break; - case SE_SeeInvis: - newbon->SeeInvis = base1; - break; - case SE_BaseMovementSpeed: - newbon->BaseMovementSpeed += base1; - break; - case SE_IncreaseRunSpeedCap: - newbon->IncreaseRunSpeedCap += base1; - break; - case SE_ConsumeProjectile: - newbon->ConsumeProjectile += base1; - break; - case SE_ArcheryDamageModifier: - newbon->ArcheryDamageModifier += base1; - break; - case SE_DamageShield: - newbon->DamageShield += base1; - break; - case SE_CharmBreakChance: - newbon->CharmBreakChance += base1; - break; - case SE_OffhandRiposteFail: - newbon->OffhandRiposteFail += base1; - break; - case SE_ItemAttackCapIncrease: - newbon->ItemATKCap += base1; - break; - case SE_GivePetGroupTarget: - newbon->GivePetGroupTarget = true; - break; - case SE_ItemHPRegenCapIncrease: - newbon->ItemHPRegenCap = +base1; - break; - case SE_Ambidexterity: - newbon->Ambidexterity += base1; - break; - case SE_PetMaxHP: - newbon->PetMaxHP += base1; - break; - case SE_AvoidMeleeChance: - newbon->AvoidMeleeChance += base1; - break; - case SE_CombatStability: - newbon->CombatStability += base1; - break; - case SE_PetCriticalHit: - newbon->PetCriticalHit += base1; - break; - case SE_PetAvoidance: - newbon->PetAvoidance += base1; - break; - case SE_ShieldBlock: - newbon->ShieldBlock += base1; - break; - case SE_SecondaryDmgInc: - newbon->SecondaryDmgInc = true; - break; - case SE_ChangeAggro: - newbon->hatemod += base1; - break; - case SE_EndurancePool: - newbon->Endurance += base1; - break; - case SE_ChannelChanceItems: - newbon->ChannelChanceItems += base1; - break; - case SE_ChannelChanceSpells: - newbon->ChannelChanceSpells += base1; - break; - case SE_DoubleSpecialAttack: - newbon->DoubleSpecialAttack += base1; - break; - case SE_TripleBackstab: - newbon->TripleBackstab += base1; - break; - case SE_FrontalBackstabMinDmg: - newbon->FrontalBackstabMinDmg = true; - break; - case SE_FrontalBackstabChance: - newbon->FrontalBackstabChance += base1; - break; - case SE_BlockBehind: - newbon->BlockBehind += base1; - break; - case SE_StrikeThrough2: - newbon->StrikeThrough += base1; - break; - case SE_DoubleAttackChance: - newbon->DoubleAttackChance += base1; - break; - case SE_GiveDoubleAttack: - newbon->GiveDoubleAttack += base1; - break; - case SE_ProcChance: - newbon->ProcChance += base1; - break; - case SE_RiposteChance: - newbon->RiposteChance += base1; - break; - case SE_Flurry: - newbon->FlurryChance += base1; - break; - case SE_PetFlurry: - newbon->PetFlurry = base1; - break; - case SE_BardSongRange: - newbon->SongRange += base1; - break; - case SE_RootBreakChance: - newbon->RootBreakChance += base1; - break; - case SE_UnfailingDivinity: - newbon->UnfailingDivinity += base1; - break; - - case SE_ProcOnKillShot: - for(int i = 0; i < MAX_SPELL_TRIGGER*3; i+=3) - { - if(!newbon->SpellOnKill[i] || ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i+1] < base1))) - { - //base1 = chance, base2 = SpellID to be triggered, base3 = min npc level - newbon->SpellOnKill[i] = base2; - newbon->SpellOnKill[i+1] = base1; - - if (GetLevel() > 15) - newbon->SpellOnKill[i+2] = GetLevel() - 15; //AA specifiy "non-trivial" - else - newbon->SpellOnKill[i+2] = 0; - - break; - } - } - break; - - case SE_SpellOnDeath: - for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2) - { - if(!newbon->SpellOnDeath[i]) - { - // base1 = SpellID to be triggered, base2 = chance to fire - newbon->SpellOnDeath[i] = base1; - newbon->SpellOnDeath[i+1] = base2; - break; - } - } - break; - - case SE_TriggerOnCast: - - for(int i = 0; i < MAX_SPELL_TRIGGER; i++) - { - if (newbon->SpellTriggers[i] == aaid) - break; - - if(!newbon->SpellTriggers[i]) - { - //Save the 'aaid' of each triggerable effect to an array - newbon->SpellTriggers[i] = aaid; - break; - } - } - break; - - case SE_CriticalHitChance: - { - if(base2 == -1) - newbon->CriticalHitChance[HIGHEST_SKILL+1] += base1; - else - newbon->CriticalHitChance[base2] += base1; - } - break; - - case SE_CriticalDamageMob: - { - // base1 = effect value, base2 = skill restrictions(-1 for all) - if(base2 == -1) - newbon->CritDmgMob[HIGHEST_SKILL+1] += base1; - else - newbon->CritDmgMob[base2] += base1; - break; - } - - case SE_CriticalSpellChance: - { - newbon->CriticalSpellChance += base1; - - if (base2 > newbon->SpellCritDmgIncrease) - newbon->SpellCritDmgIncrease = base2; - - break; - } - - case SE_ResistFearChance: - { - if(base1 == 100) // If we reach 100% in a single spell/item then we should be immune to negative fear resist effects until our immunity is over - newbon->Fearless = true; - - newbon->ResistFearChance += base1; // these should stack - break; - } - - case SE_SkillDamageAmount: - { - if(base2 == -1) - newbon->SkillDamageAmount[HIGHEST_SKILL+1] += base1; - else - newbon->SkillDamageAmount[base2] += base1; - break; - } - - case SE_SpecialAttackKBProc: - { - //You can only have one of these per client. [AA Dragon Punch] - newbon->SpecialAttackKBProc[0] = base1; //Chance base 100 = 25% proc rate - newbon->SpecialAttackKBProc[1] = base2; //Skill to KB Proc Off - break; - } - - case SE_DamageModifier: - { - if(base2 == -1) - newbon->DamageModifier[HIGHEST_SKILL+1] += base1; - else - newbon->DamageModifier[base2] += base1; - break; - } - - case SE_SlayUndead: - { - if(newbon->SlayUndead[1] < base1) - newbon->SlayUndead[0] = base1; // Rate - newbon->SlayUndead[1] = base2; // Damage Modifier - break; - } - - case SE_GiveDoubleRiposte: - { - //0=Regular Riposte 1=Skill Attack Riposte 2=Skill - if(base2 == 0){ - if(newbon->GiveDoubleRiposte[0] < base1) - newbon->GiveDoubleRiposte[0] = base1; - } - //Only for special attacks. - else if(base2 > 0 && (newbon->GiveDoubleRiposte[1] < base1)){ - newbon->GiveDoubleRiposte[1] = base1; - newbon->GiveDoubleRiposte[2] = base2; - } - - break; - } - - //Kayen: Not sure best way to implement this yet. - //Physically raises skill cap ie if 55/55 it will raise to 55/60 - case SE_RaiseSkillCap: - { - if(newbon->RaiseSkillCap[0] < base1){ - newbon->RaiseSkillCap[0] = base1; //value - newbon->RaiseSkillCap[1] = base2; //skill - } - break; - } - - case SE_MasteryofPast: - { - if(newbon->MasteryofPast < base1) - newbon->MasteryofPast = base1; - break; - } - - case SE_CastingLevel2: - case SE_CastingLevel: - { - newbon->effective_casting_level += base1; - break; - } - - - case SE_DivineSave: - { - if(newbon->DivineSaveChance[0] < base1) - { - newbon->DivineSaveChance[0] = base1; - newbon->DivineSaveChance[1] = base2; - } - break; - } - - case SE_SpellEffectResistChance: - { - for(int e = 0; e < MAX_RESISTABLE_EFFECTS*2; e+=2) - { - if(!newbon->SEResist[e] || ((newbon->SEResist[e] = base2) && (newbon->SEResist[e+1] < base1)) ){ - newbon->SEResist[e] = base2; - newbon->SEResist[e+1] = base1; - break; - } - } - break; - } - - case SE_MitigateDamageShield: - { - if (base1 < 0) - base1 = base1*(-1); - - newbon->DSMitigationOffHand += base1; - break; - } - - case SE_FinishingBlow: - { - - //base1 = chance, base2 = damage - if (newbon->FinishingBlow[1] < base2){ - newbon->FinishingBlow[0] = base1; - newbon->FinishingBlow[1] = base2; - } - break; - } - - case SE_FinishingBlowLvl: - { - //base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?) - if (newbon->FinishingBlowLvl[0] < base1){ - newbon->FinishingBlowLvl[0] = base1; - newbon->FinishingBlowLvl[1] = base2; - } - break; - } - } - } + return Bot::IsValidRaceClassCombo(GetRace(), GetClass()); } -bool Bot::IsValidRaceClassCombo() { - bool Result = false; - - switch(GetRace()) { - case 1: // Human - switch(GetClass()) { - case 1: // Warrior - case 2: // Cleric - case 3: // Paladin - case 4: // Ranger - case 5: // Shadowknight - case 6: // Druid - case 7: // Monk - case 8: // Bard - case 9: // Rogue - case 11: // Necromancer - case 12: // Wizard - case 13: // Magician - case 14: // Enchanter - Result = true; - break; - } - break; - case 2: // Barbarian - switch(GetClass()) { - case 1: // Warrior - case 9: // Rogue - case 10: // Shaman - case 15: // Beastlord - case 16: // Berserker - Result = true; - break; - } - break; - case 3: // Erudite - switch(GetClass()) { - case 2: // Cleric - case 3: // Paladin - case 5: // Shadowknight - case 11: // Necromancer - case 12: // Wizard - case 13: // Magician - case 14: // Enchanter - Result = true; - break; - } - break; - case 4: // Wood Elf - switch(GetClass()) { - case 1: // Warrior - case 4: // Ranger - case 6: // Druid - case 8: // Bard - case 9: // Rogue - Result = true; - break; - } - break; - case 5: // High Elf - switch(GetClass()) { - case 2: // Cleric - case 3: // Paladin - case 12: // Wizard - case 13: // Magician - case 14: // Enchanter - Result = true; - break; - } - break; - case 6: // Dark Elf - switch(GetClass()) { - case 1: // Warrior - case 2: // Cleric - case 5: // Shadowknight - case 9: // Rogue - case 11: // Necromancer - case 12: // Wizard - case 13: // Magician - case 14: // Enchanter - Result = true; - break; - } - break; - case 7: // Half Elf - switch(GetClass()) { - case 1: // Warrior - case 3: // Paladin - case 4: // Ranger - case 6: // Druid - case 8: // Bard - case 9: // Rogue - Result = true; - break; - } - break; - case 8: // Dwarf - switch(GetClass()) { - case 1: // Warrior - case 2: // Cleric - case 3: // Paladin - case 9: // Rogue - case 16: // Berserker - Result = true; - break; - } - break; - case 9: // Troll - switch(GetClass()) { - case 1: // Warrior - case 5: // Shadowknight - case 10: // Shaman - case 15: // Beastlord - case 16: // Berserker - Result = true; - break; - } - break; - case 10: // Ogre - switch(GetClass()) { - case 1: // Warrior - case 5: // Shadowknight - case 10: // Shaman - case 15: // Beastlord - case 16: // Berserker - Result = true; - break; - } - break; - case 11: // Halfling - switch(GetClass()) { - case 1: // Warrior - case 2: // Cleric - case 3: // Paladin - case 4: // Ranger - case 6: // Druid - case 9: // Rogue - Result = true; - break; - } - break; - case 12: // Gnome - switch(GetClass()) { - case 1: // Warrior - case 2: // Cleric - case 3: // Paladin - case 5: // Shadowknight - case 9: // Rogue - case 11: // Necromancer - case 12: // Wizard - case 13: // Magician - case 14: // Enchanter - Result = true; - break; - } - break; - case 128: // Iksar - switch(GetClass()) { - case 1: // Warrior - case 5: // Shadowknight - case 7: // Monk - case 10: // Shaman - case 11: // Necromancer - case 15: // Beastlord - Result = true; - break; - } - break; - case 130: // Vah Shir - switch(GetClass()) { - case 1: // Warrior - case 8: // Bard - case 9: // Rogue - case 10: // Shaman - case 15: // Beastlord - case 16: // Berserker - Result = true; - break; - } - break; - case 330: // Froglok - switch(GetClass()) { - case 1: // Warrior - case 2: // Cleric - case 3: // Paladin - case 5: // Shadowknight - case 9: // Rogue - case 10: // Shaman - case 11: // Necromancer - case 12: // Wizard - Result = true; - break; - } - break; - case 522: // Drakkin - switch(GetClass()) { - case 1: // Warrior - case 2: // Cleric - case 3: // Paladin - case 4: // Ranger - case 5: // Shadowknight - case 6: // Druid - case 7: // Monk - case 8: // Bard - case 9: // Rogue - case 11: // Necromancer - case 12: // Wizard - case 13: // Magician - case 14: // Enchanter - Result = true; - break; - } - break; - } - - return Result; -} - -bool Bot::IsValidName() { - bool Result = false; - std::string TempBotName = std::string(this->GetCleanName()); - - for(int iCounter = 0; iCounter < TempBotName.length(); iCounter++) { - if(isalpha(TempBotName[iCounter]) || TempBotName[iCounter] == '_') { - Result = true; +bool Bot::IsValidRaceClassCombo(uint16 r, uint8 c) +{ + switch (r) { + case HUMAN: + switch (c) { + case WARRIOR: + case CLERIC: + case PALADIN: + case RANGER: + case SHADOWKNIGHT: + case DRUID: + case MONK: + case BARD: + case ROGUE: + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return true; } + break; + case BARBARIAN: + switch (c) { + case WARRIOR: + case ROGUE: + case SHAMAN: + case BEASTLORD: + case BERSERKER: + return true; + } + break; + case ERUDITE: + switch (c) { + case CLERIC: + case PALADIN: + case SHADOWKNIGHT: + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return true; + } + break; + case WOOD_ELF: + switch (c) { + case WARRIOR: + case RANGER: + case DRUID: + case BARD: + case ROGUE: + return true; + } + break; + case HIGH_ELF: + switch (c) { + case CLERIC: + case PALADIN: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return true; + } + break; + case DARK_ELF: + switch (c) { + case WARRIOR: + case CLERIC: + case SHADOWKNIGHT: + case ROGUE: + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return true; + } + break; + case HALF_ELF: + switch (c) { + case WARRIOR: + case PALADIN: + case RANGER: + case DRUID: + case BARD: + case ROGUE: + return true; + } + break; + case DWARF: + switch (c) { + case WARRIOR: + case CLERIC: + case PALADIN: + case ROGUE: + case BERSERKER: + return true; + } + break; + case TROLL: + switch (c) { + case WARRIOR: + case SHADOWKNIGHT: + case SHAMAN: + case BEASTLORD: + case BERSERKER: + return true; + } + break; + case OGRE: + switch (c) { + case WARRIOR: + case SHADOWKNIGHT: + case SHAMAN: + case BEASTLORD: + case BERSERKER: + return true; + } + break; + case HALFLING: + switch (c) { + case WARRIOR: + case CLERIC: + case PALADIN: + case RANGER: + case DRUID: + case ROGUE: + return true; + } + break; + case GNOME: + switch (c) { + case WARRIOR: + case CLERIC: + case PALADIN: + case SHADOWKNIGHT: + case ROGUE: + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return true; + } + break; + case IKSAR: + switch (c) { + case WARRIOR: + case SHADOWKNIGHT: + case MONK: + case SHAMAN: + case NECROMANCER: + case BEASTLORD: + return true; + } + break; + case VAHSHIR: + switch (c) { + case WARRIOR: + case BARD: + case ROGUE: + case SHAMAN: + case BEASTLORD: + case BERSERKER: + return true; + } + break; + case FROGLOK: + switch (c) { + case WARRIOR: + case CLERIC: + case PALADIN: + case SHADOWKNIGHT: + case ROGUE: + case SHAMAN: + case NECROMANCER: + case WIZARD: + return true; + } + break; + case DRAKKIN: + switch (c) { + case WARRIOR: + case CLERIC: + case PALADIN: + case RANGER: + case SHADOWKNIGHT: + case DRUID: + case MONK: + case BARD: + case ROGUE: + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + return true; + } + break; + default: + break; } - return Result; + return false; } -bool Bot::IsBotNameAvailable(std::string* errorMessage) { +bool Bot::IsValidName() +{ + std::string name = this->GetCleanName(); + return Bot::IsValidName(name); +} - if(!this->GetCleanName()) - return false; - - std::string query = StringFormat("SELECT COUNT(id) FROM vwBotCharacterMobs " - "WHERE name LIKE '%s'", this->GetCleanName()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); +bool Bot::IsValidName(std::string& name) +{ + if (name.length() < 4) return false; - } - - uint32 existingNameCount = 0; - - for (auto row = results.begin(); row != results.end(); ++row) { - existingNameCount = atoi(row[0]); - break; - } - - if(existingNameCount != 0) - return false; + if (!isupper(name[0])) + return false; + + for (int i = 1; i < name.length(); ++i) { + if ((!RuleB(Bots, AllowCamelCaseNames) && !islower(name[i])) && name[i] != '_') { + return false; + } + } return true; } -bool Bot::Save() { +bool Bot::Save() +{ + auto bot_owner = GetBotOwner(); + if (!bot_owner) + return false; - if(this->GetBotID() == 0) { - // New bot record - std::string query = StringFormat("INSERT INTO bots (BotOwnerCharacterID, BotSpellsID, Name, LastName, " - "BotLevel, Race, Class, Gender, Size, Face, LuclinHairStyle, " - "LuclinHairColor, LuclinEyeColor, LuclinEyeColor2, LuclinBeardColor, " - "LuclinBeard, DrakkinHeritage, DrakkinTattoo, DrakkinDetails, HP, Mana, " - "MR, CR, DR, FR, PR, Corrup, AC, STR, STA, DEX, AGI, _INT, WIS, CHA, ATK, " - "LastSpawnDate, TotalPlayTime, LastZoneId) " - "VALUES('%u', '%u', '%s', '%s', '%u', '%i', '%i', '%i', '%f', '%i', '%i', " - "'%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', " - "'%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', " - "'%i', NOW(), 0, %i)", - this->_botOwnerCharacterID, this->GetBotSpellID(), this->GetCleanName(), - this->lastname, this->GetLevel(), GetRace(), GetClass(), GetGender(), - GetSize(), this->GetLuclinFace(), this->GetHairStyle(), GetHairColor(), - this->GetEyeColor1(), this->GetEyeColor2(), this->GetBeardColor(), - this->GetBeard(), this->GetDrakkinHeritage(), this->GetDrakkinTattoo(), - this->GetDrakkinDetails(), GetHP(), GetMana(), GetMR(), GetCR(), GetDR(), - GetFR(), GetPR(), GetCorrup(), GetAC(), GetSTR(), GetSTA(), GetDEX(), - GetAGI(), GetINT(), GetWIS(), GetCHA(), GetATK(), _lastZoneId); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - auto botOwner = GetBotOwner(); - if (botOwner) - botOwner->Message(13, results.ErrorMessage().c_str()); - return false; + std::string error_message; + + if(!GetBotID()) { // New bot record + uint32 bot_id = 0; + if (!botdb.SaveNewBot(this, bot_id) || !bot_id) { + bot_owner->Message(13, "%s '%s'", BotDatabase::fail::SaveNewBot(), GetCleanName()); + return false; } + SetBotID(bot_id); + } + else { // Update existing bot record + if (!botdb.SaveBot(this)) { + bot_owner->Message(13, "%s '%s'", BotDatabase::fail::SaveBot(), GetCleanName()); + return false; + } + } + + // All of these continue to process if any fail + if (!botdb.SaveBuffs(this)) + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::SaveBuffs(), GetCleanName()); + if (!botdb.SaveTimers(this)) + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::SaveTimers(), GetCleanName()); + if (!botdb.SaveStance(this)) + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::SaveStance(), GetCleanName()); + + if (!SavePet()) + bot_owner->Message(13, "Failed to save pet for '%s'", GetCleanName()); + + return true; +} - SetBotID(results.LastInsertedID()); - SaveBuffs(); - SavePet(); - SaveStance(); - SaveTimers(); - return true; +bool Bot::DeleteBot() +{ + auto bot_owner = GetBotOwner(); + if (!bot_owner) + return false; + + if (!botdb.DeleteHealRotation(GetBotID())) { + bot_owner->Message(13, "%s", BotDatabase::fail::DeleteHealRotation()); + return false; } - // Update existing bot record - std::string query = StringFormat("UPDATE bots SET BotOwnerCharacterID = '%u', BotSpellsID = '%u', " - "Name = '%s', LastName = '%s', BotLevel = '%u', Race = '%i', " - "Class = '%i', Gender = '%i', Size = '%f', Face = '%i', " - "LuclinHairStyle = '%i', LuclinHairColor = '%i', " - "LuclinEyeColor = '%i', LuclinEyeColor2 = '%i', " - "LuclinBeardColor = '%i', LuclinBeard = '%i', DrakkinHeritage = '%i', " - "DrakkinTattoo = '%i', DrakkinDetails = '%i', HP = '%i', Mana = '%i', " - "MR = '%i', CR = '%i', DR = '%i', FR = '%i', PR = '%i', " - "Corrup = '%i', AC = '%i', STR = '%i', STA = '%i', DEX = '%i', " - "AGI = '%i', _INT = '%i', WIS = '%i', CHA = '%i', ATK = '%i', " - "LastSpawnDate = NOW(), TotalPlayTime = '%u', LastZoneId = %i " - "WHERE BotID = '%u'", - _botOwnerCharacterID, this->GetBotSpellID(), this->GetCleanName(), - this->lastname, this->GetLevel(), _baseRace, this->GetClass(), - _baseGender, GetSize(), this->GetLuclinFace(), this->GetHairStyle(), - GetHairColor(), this->GetEyeColor1(), this->GetEyeColor2(), - this->GetBeardColor(), this->GetBeard(), this->GetDrakkinHeritage(), - GetDrakkinTattoo(), GetDrakkinDetails(), GetHP(), GetMana(), - _baseMR, _baseCR, _baseDR, _baseFR, _basePR, _baseCorrup, _baseAC, - _baseSTR, _baseSTA, _baseDEX, _baseAGI, _baseINT, _baseWIS, _baseCHA, - _baseATK, GetTotalPlayTime(), _lastZoneId, GetBotID()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - auto botOwner = GetBotOwner(); - if (botOwner) - botOwner->Message(13, results.ErrorMessage().c_str()); - return false; - } + std::string query = StringFormat("DELETE FROM `bot_heal_rotation_members` WHERE `bot_id` = '%u'", GetBotID()); + auto results = botdb.QueryDatabase(query); + if (!results.Success()) { + bot_owner->Message(13, "Failed to delete heal rotation member '%s'", GetCleanName()); + return false; + } - SaveBuffs(); - SavePet(); - SaveStance(); - SaveTimers(); + query = StringFormat("DELETE FROM `bot_heal_rotation_targets` WHERE `target_name` LIKE '%s'", GetCleanName()); + results = botdb.QueryDatabase(query); + if (!results.Success()) { + bot_owner->Message(13, "Failed to delete heal rotation target '%s'", GetCleanName()); + return false; + } + + if (!DeletePet()) { + bot_owner->Message(13, "Failed to delete pet for '%s'", GetCleanName()); + return false; + } + + if (GetGroup()) + RemoveBotFromGroup(this, GetGroup()); + + std::string error_message; + + if (!botdb.RemoveMemberFromBotGroup(GetBotID())) { + bot_owner->Message(13, "%s - '%s'", BotDatabase::fail::RemoveMemberFromBotGroup(), GetCleanName()); + return false; + } + + if (!botdb.DeleteItems(GetBotID())) { + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::DeleteItems(), GetCleanName()); + return false; + } + + if (!botdb.DeleteTimers(GetBotID())) { + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::DeleteTimers(), GetCleanName()); + return false; + } + + if (!botdb.DeleteBuffs(GetBotID())) { + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::DeleteBuffs(), GetCleanName()); + return false; + } + + if (!botdb.DeleteStance(GetBotID())) { + bot_owner->Message(13, "%s for '%s'", BotDatabase::fail::DeleteStance(), GetCleanName()); + return false; + } + + if (!botdb.DeleteBot(GetBotID())) { + bot_owner->Message(13, "%s '%s'", BotDatabase::fail::DeleteBot(), GetCleanName()); + return false; + } return true; } @@ -2430,444 +1654,160 @@ bool Bot::Save() { // Returns the current total play time for the bot uint32 Bot::GetTotalPlayTime() { uint32 Result = 0; - double TempTotalPlayTime = 0; - time_t currentTime = time(¤tTime); - TempTotalPlayTime = difftime(currentTime, _startTotalPlayTime); - TempTotalPlayTime += _lastTotalPlayTime; - Result = (uint32)TempTotalPlayTime; - return Result; } -void Bot::SaveBuffs() { - - // Remove any existing buff saves - std::string query = StringFormat("DELETE FROM botbuffs WHERE BotId = %u", GetBotID()); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return; - - for (int buffIndex = 0; buffIndex < BUFF_COUNT; buffIndex++) { - if (buffs[buffIndex].spellid <= 0 || buffs[buffIndex].spellid == SPELL_UNKNOWN) - continue; - - int isPersistent = buffs[buffIndex].persistant_buff? 1: 0; - query = StringFormat("INSERT INTO botbuffs (BotId, SpellId, CasterLevel, DurationFormula, " - "TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, " - "CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, " - "caston_x, Persistent, caston_y, caston_z, ExtraDIChance) " - "VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %i, %u, " - "%i, %i, %i);", - GetBotID(), buffs[buffIndex].spellid, buffs[buffIndex].casterlevel, - spells[buffs[buffIndex].spellid].buffdurationformula, - buffs[buffIndex].ticsremaining, - CalculatePoisonCounters(buffs[buffIndex].spellid) > 0 ? buffs[buffIndex].counters : 0, - CalculateDiseaseCounters(buffs[buffIndex].spellid) > 0 ? buffs[buffIndex].counters : 0, - CalculateCurseCounters(buffs[buffIndex].spellid) > 0 ? buffs[buffIndex].counters : 0, - CalculateCorruptionCounters(buffs[buffIndex].spellid) > 0 ? buffs[buffIndex].counters : 0, - buffs[buffIndex].numhits, buffs[buffIndex].melee_rune, - buffs[buffIndex].magic_rune, buffs[buffIndex].dot_rune, - buffs[buffIndex].caston_x, isPersistent, buffs[buffIndex].caston_y, - buffs[buffIndex].caston_z, buffs[buffIndex].ExtraDIChance); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return; - - } - -} - -void Bot::LoadBuffs() { - - std::string query = StringFormat("SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, " - "PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, " - "HitCount, MeleeRune, MagicRune, dot_rune, caston_x, Persistent, " - "caston_y, caston_z, ExtraDIChance FROM botbuffs WHERE BotId = %u", - GetBotID()); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return; - - int buffCount = 0; - - for (auto row = results.begin(); row != results.end(); ++row) { - if(buffCount == BUFF_COUNT) - break; - - buffs[buffCount].spellid = atoi(row[0]); - buffs[buffCount].casterlevel = atoi(row[1]); - buffs[buffCount].ticsremaining = atoi(row[3]); - - if(CalculatePoisonCounters(buffs[buffCount].spellid) > 0) - buffs[buffCount].counters = atoi(row[4]); - else if(CalculateDiseaseCounters(buffs[buffCount].spellid) > 0) - buffs[buffCount].counters = atoi(row[5]); - else if(CalculateCurseCounters(buffs[buffCount].spellid) > 0) - buffs[buffCount].counters = atoi(row[6]); - else if(CalculateCorruptionCounters(buffs[buffCount].spellid) > 0) - buffs[buffCount].counters = atoi(row[7]); - - buffs[buffCount].numhits = atoi(row[8]); - buffs[buffCount].melee_rune = atoi(row[9]); - buffs[buffCount].magic_rune = atoi(row[10]); - buffs[buffCount].dot_rune = atoi(row[11]); - buffs[buffCount].caston_x = atoi(row[12]); - buffs[buffCount].casterid = 0; - - buffs[buffCount].persistant_buff = atoi(row[13])? true: false; - - buffs[buffCount].caston_y = atoi(row[14]); - buffs[buffCount].caston_z = atoi(row[15]); - buffs[buffCount].ExtraDIChance = atoi(row[16]); - - buffCount++; - } - - query = StringFormat("DELETE FROM botbuffs WHERE BotId = %u", GetBotID()); - results = database.QueryDatabase(query); - -} - -uint32 Bot::GetPetSaveId() { - - std::string query = StringFormat("SELECT BotPetsId FROM botpets WHERE BotId = %u;", GetBotID()); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return 0; - - if (results.RowCount() == 0) - return 0; - - auto row = results.begin(); - - return atoi(row[0]); -} - -void Bot::LoadPet() { - uint32 PetSaveId = GetPetSaveId(); - - if(PetSaveId > 0 && !GetPet() && PetSaveId <= SPDAT_RECORDS) { - std::string petName; - uint32 petMana = 0; - uint32 petHitPoints = 0; - uint32 botPetId = 0; - - LoadPetStats(&petName, &petMana, &petHitPoints, &botPetId, PetSaveId); - - MakePet(botPetId, spells[botPetId].teleport_zone, petName.c_str()); - - if(GetPet() && GetPet()->IsNPC()) { - NPC *pet = GetPet()->CastToNPC(); - SpellBuff_Struct petBuffs[BUFF_COUNT]; - memset(petBuffs, 0, sizeof(petBuffs)); - uint32 petItems[EmuConstants::EQUIPMENT_SIZE]; - - LoadPetBuffs(petBuffs, PetSaveId); - LoadPetItems(petItems, PetSaveId); - - pet->SetPetState(petBuffs, petItems); - pet->CalcBonuses(); - pet->SetHP(petHitPoints); - pet->SetMana(petMana); - } - - DeletePetStats(PetSaveId); - } -} - -void Bot::LoadPetStats(std::string* petName, uint32* petMana, uint32* petHitPoints, uint32* botPetId, uint32 botPetSaveId) { - if(botPetSaveId == 0) - return; - - std::string query = StringFormat("SELECT PetId, Name, Mana, HitPoints " - "FROM botpets WHERE BotPetsId = %u;", - botPetSaveId); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return; - - if (results.RowCount() == 0) - return; - - auto row = results.begin(); - - *botPetId = atoi(row[0]); - *petName = std::string(row[1]); - *petMana = atoi(row[2]); - *petHitPoints = atoi(row[3]); -} - -void Bot::LoadPetBuffs(SpellBuff_Struct* petBuffs, uint32 botPetSaveId) { - if(!petBuffs || botPetSaveId == 0) - return; - - std::string query = StringFormat("SELECT SpellId, CasterLevel, Duration " - "FROM botpetbuffs WHERE BotPetsId = %u;", botPetSaveId); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return; - - - int buffIndex = 0; - - for (auto row = results.begin();row != results.end(); ++row) { - if(buffIndex == BUFF_COUNT) - break; - - petBuffs[buffIndex].spellid = atoi(row[0]); - petBuffs[buffIndex].level = atoi(row[1]); - petBuffs[buffIndex].duration = atoi(row[2]); - - buffIndex++; - } - - query = StringFormat("DELETE FROM botpetbuffs WHERE BotPetsId = %u;", botPetSaveId); - results = database.QueryDatabase(query); - -} - -void Bot::LoadPetItems(uint32* petItems, uint32 botPetSaveId) { - if(!petItems || botPetSaveId == 0) - return; - - std::string query = StringFormat("SELECT ItemId FROM botpetinventory " - "WHERE BotPetsId = %u;", botPetSaveId); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return; - - int itemIndex = 0; - - for(auto row = results.begin(); row != results.end(); ++row) { - if(itemIndex == EmuConstants::EQUIPMENT_SIZE) - break; - - petItems[itemIndex] = atoi(row[0]); - - itemIndex++; - } - - query = StringFormat("DELETE FROM botpetinventory WHERE BotPetsId = %u;", botPetSaveId); - results = database.QueryDatabase(query); - -} - -void Bot::SavePet() { - if(GetPet() && !GetPet()->IsFamiliar() && GetPet()->CastToNPC()->GetPetSpellID() /*&& !dead*/) { - NPC *pet = GetPet()->CastToNPC(); - uint16 petMana = pet->GetMana(); - uint16 petHitPoints = pet->GetHP(); - uint32 botPetId = pet->CastToNPC()->GetPetSpellID(); - char* tempPetName = new char[64]; - SpellBuff_Struct petBuffs[BUFF_COUNT]; - uint32 petItems[EmuConstants::EQUIPMENT_SIZE]; - - pet->GetPetState(petBuffs, petItems, tempPetName); - - uint32 existingBotPetSaveId = GetPetSaveId(); - - if(existingBotPetSaveId > 0) { - // Remove any existing pet buffs - DeletePetBuffs(existingBotPetSaveId); - - // Remove any existing pet items - DeletePetItems(existingBotPetSaveId); - } - - // Save pet stats and get a new bot pet save id - uint32 botPetSaveId = SavePetStats(std::string(tempPetName), petMana, petHitPoints, botPetId); - - // Save pet buffs - SavePetBuffs(petBuffs, botPetSaveId); - - // Save pet items - SavePetItems(petItems, botPetSaveId); - - if(tempPetName) - safe_delete_array(tempPetName); - } -} - -uint32 Bot::SavePetStats(std::string petName, uint32 petMana, uint32 petHitPoints, uint32 botPetId) { - - std::string query = StringFormat("REPLACE INTO botpets SET PetId = %u, BotId = %u, Name = '%s', " - "Mana = %u, HitPoints = %u;", botPetId, GetBotID(), petName.c_str(), - petMana, petHitPoints); - auto results = database.QueryDatabase(query); - - return 0; -} - -void Bot::SavePetBuffs(SpellBuff_Struct* petBuffs, uint32 botPetSaveId) { - if(!petBuffs || botPetSaveId == 0) - return; - - int buffIndex = 0; - - while(buffIndex < BUFF_COUNT) { - if(petBuffs[buffIndex].spellid > 0 && petBuffs[buffIndex].spellid != SPELL_UNKNOWN) { - - std::string query = StringFormat("INSERT INTO botpetbuffs " - "(BotPetsId, SpellId, CasterLevel, Duration) " - "VALUES(%u, %u, %u, %u);", - botPetSaveId, petBuffs[buffIndex].spellid, - petBuffs[buffIndex].level, petBuffs[buffIndex].duration); - auto results = database.QueryDatabase(query); - if(!results.Success()) - break; - - } - - buffIndex++; - } - -} - -void Bot::SavePetItems(uint32* petItems, uint32 botPetSaveId) { - if(!petItems || botPetSaveId == 0) - return; - - for (int itemIndex = 0;itemIndex < EmuConstants::EQUIPMENT_SIZE; itemIndex++) { - if(petItems[itemIndex] == 0) - continue; - - std::string query = StringFormat("INSERT INTO botpetinventory " - "(BotPetsId, ItemId) VALUES(%u, %u);", - botPetSaveId, petItems[itemIndex]); - auto results = database.QueryDatabase(query); - if(!results.Success()) - break; - } - -} - -void Bot::DeletePetBuffs(uint32 botPetSaveId) { - if(botPetSaveId == 0) - return; - - std::string query = StringFormat("DELETE FROM botpetbuffs WHERE BotPetsId = %u;", botPetSaveId); - auto results = database.QueryDatabase(query); - -} - -void Bot::DeletePetItems(uint32 botPetSaveId) { - if(botPetSaveId == 0) - return; - - std::string query = StringFormat("DELETE FROM botpetinventory WHERE BotPetsId = %u;", botPetSaveId); - auto results = database.QueryDatabase(query); - -} - -void Bot::DeletePetStats(uint32 botPetSaveId) { - if(botPetSaveId == 0) - return; - - std::string query = StringFormat("DELETE from botpets where BotPetsId = %u;", botPetSaveId); - auto results = database.QueryDatabase(query); - -} - -void Bot::LoadStance() { - - std::string query = StringFormat("SELECT StanceID FROM botstances WHERE BotID = %u;", GetBotID()); - auto results = database.QueryDatabase(query); - if(!results.Success() || results.RowCount() == 0) { - Log.Out(Logs::General, Logs::Error, "Error in Bot::LoadStance()"); - SetDefaultBotStance(); - return; - } - - auto row = results.begin(); - - SetBotStance((BotStanceType)atoi(row[0])); -} - -void Bot::SaveStance() { - if(_baseBotStance == _botStance) - return; - - std::string query = StringFormat("REPLACE INTO botstances (BotID, StanceId) " - "VALUES(%u, %u);", GetBotID(), GetBotStance()); - auto results = database.QueryDatabase(query); - if(!results.Success()) - Log.Out(Logs::General, Logs::Error, "Error in Bot::SaveStance()"); - -} - -void Bot::LoadTimers() { - - std::string query = StringFormat("SELECT IfNull(bt.TimerID, 0) As TimerID, IfNull(bt.Value, 0) As Value, " - "IfNull(MAX(sn.recast_time), 0) AS MaxTimer FROM bottimers bt, spells_new sn " - "WHERE bt.BotID = %u AND sn.EndurTimerIndex = " - "(SELECT case WHEN TimerID > %i THEN TimerID - %i ELSE TimerID END AS TimerID " - "FROM bottimers WHERE TimerID = bt.TimerID AND BotID = bt.BotID ) " - "AND sn.classes%i <= %i;", - GetBotID(), DisciplineReuseStart-1, DisciplineReuseStart-1, GetClass(), GetLevel()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - Log.Out(Logs::General, Logs::Error, "Error in Bot::LoadTimers()"); - return; - } - - int timerID = 0; - uint32 value = 0; - uint32 maxValue = 0; - - for (auto row = results.begin(); row != results.end(); ++row) { - timerID = atoi(row[0]) - 1; - value = atoi(row[1]); - maxValue = atoi(row[2]); - - if(timerID >= 0 && timerID < MaxTimer && value < (Timer::GetCurrentTime() + maxValue)) - timers[timerID] = value; - } - -} - -void Bot::SaveTimers() { - bool hadError = false; - - std::string query = StringFormat("DELETE FROM bottimers WHERE BotID = %u;", GetBotID()); - auto results = database.QueryDatabase(query); - if(!results.Success()) - hadError = true; - - for(int timerIndex = 0; timerIndex < MaxTimer; timerIndex++) { - if(timers[timerIndex] <= Timer::GetCurrentTime()) - continue; - - query = StringFormat("REPLACE INTO bottimers (BotID, TimerID, Value) VALUES(%u, %u, %u);", - GetBotID(), timerIndex+1, timers[timerIndex]); - results = database.QueryDatabase(query); - - if(!results.Success()) - hadError = true; - } - - if(hadError) - Log.Out(Logs::General, Logs::Error, "Error in Bot::SaveTimers()"); - -} - -bool Bot::Process() +bool Bot::LoadPet() { - if(IsStunned() && stunned_timer.Check()) - { - this->stunned = false; - this->stunned_timer.Disable(); + if (GetPet()) + return true; + + auto bot_owner = GetBotOwner(); + if (!bot_owner) + return false; + + std::string error_message; + + uint32 pet_index = 0; + if (!botdb.LoadPetIndex(GetBotID(), pet_index)) { + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::LoadPetIndex(), GetCleanName()); + return false; } + if (!pet_index) + return true; + + uint32 saved_pet_spell_id = 0; + if (!botdb.LoadPetSpellID(GetBotID(), saved_pet_spell_id)) { + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::LoadPetSpellID(), GetCleanName()); + } + if (!saved_pet_spell_id || saved_pet_spell_id > SPDAT_RECORDS) { + bot_owner->Message(13, "Invalid spell id for %s's pet", GetCleanName()); + DeletePet(); + return false; + } + + std::string pet_name; + uint32 pet_mana = 0; + uint32 pet_hp = 0; + uint32 pet_spell_id = 0; + + if (!botdb.LoadPetStats(GetBotID(), pet_name, pet_mana, pet_hp, pet_spell_id)) { + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::LoadPetStats(), GetCleanName()); + return false; + } + + MakePet(pet_spell_id, spells[pet_spell_id].teleport_zone, pet_name.c_str()); + if (!GetPet() || !GetPet()->IsNPC()) { + DeletePet(); + return false; + } + + NPC *pet_inst = GetPet()->CastToNPC(); + + SpellBuff_Struct pet_buffs[PET_BUFF_COUNT]; + memset(pet_buffs, 0, (sizeof(SpellBuff_Struct) * PET_BUFF_COUNT)); + if (!botdb.LoadPetBuffs(GetBotID(), pet_buffs)) + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::LoadPetBuffs(), GetCleanName()); + + uint32 pet_items[EQEmu::legacy::EQUIPMENT_SIZE]; + memset(pet_items, 0, (sizeof(uint32) * EQEmu::legacy::EQUIPMENT_SIZE)); + if (!botdb.LoadPetItems(GetBotID(), pet_items)) + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::LoadPetItems(), GetCleanName()); + + pet_inst->SetPetState(pet_buffs, pet_items); + pet_inst->CalcBonuses(); + pet_inst->SetHP(pet_hp); + pet_inst->SetMana(pet_mana); + + return true; +} + +bool Bot::SavePet() +{ + if (!GetPet() /*|| dead*/) + return true; + + NPC *pet_inst = GetPet()->CastToNPC(); + if (pet_inst->IsFamiliar() || !pet_inst->GetPetSpellID() || pet_inst->GetPetSpellID() > SPDAT_RECORDS) + return false; + + auto bot_owner = GetBotOwner(); + if (!bot_owner) + return false; + + char* pet_name = new char[64]; + SpellBuff_Struct pet_buffs[PET_BUFF_COUNT]; + uint32 pet_items[EQEmu::legacy::EQUIPMENT_SIZE]; + + memset(pet_name, 0, 64); + memset(pet_buffs, 0, (sizeof(SpellBuff_Struct) * PET_BUFF_COUNT)); + memset(pet_items, 0, (sizeof(uint32) * EQEmu::legacy::EQUIPMENT_SIZE)); + + pet_inst->GetPetState(pet_buffs, pet_items, pet_name); + + std::string pet_name_str = pet_name; + safe_delete_array(pet_name); + + std::string error_message; + + if (!botdb.SavePetStats(GetBotID(), pet_name_str, pet_inst->GetMana(), pet_inst->GetHP(), pet_inst->GetPetSpellID())) { + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::SavePetStats(), GetCleanName()); + return false; + } + + if (!botdb.SavePetBuffs(GetBotID(), pet_buffs)) + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::SavePetBuffs(), GetCleanName()); + if (!botdb.SavePetItems(GetBotID(), pet_items)) + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::SavePetItems(), GetCleanName()); + + return true; +} + +bool Bot::DeletePet() +{ + auto bot_owner = GetBotOwner(); + if (!bot_owner) + return false; + + std::string error_message; + + if (!botdb.DeletePetItems(GetBotID())) { + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::DeletePetItems(), GetCleanName()); + return false; + } + if (!botdb.DeletePetBuffs(GetBotID())) { + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::DeletePetBuffs(), GetCleanName()); + return false; + } + if (!botdb.DeletePetStats(GetBotID())) { + bot_owner->Message(13, "%s for %s's pet", BotDatabase::fail::DeletePetStats(), GetCleanName()); + return false; + } + + if (!GetPet() || !GetPet()->IsNPC()) + return true; + + NPC* pet_inst = GetPet()->CastToNPC(); + pet_inst->SetOwnerID(0); + + SetPet(nullptr); + + return true; +} + +bool Bot::Process() { + if(IsStunned() && stunned_timer.Check()) + Mob::UnStun(); if(!GetBotOwner()) return false; - if (GetDepop()) - { + if (GetDepop()) { _botOwner = 0; _botOwnerCharacterID = 0; _previousTarget = 0; @@ -2876,26 +1816,19 @@ bool Bot::Process() SpellProcess(); - if(tic_timer.Check()) - { + if(tic_timer.Check()) { //6 seconds, or whatever the rule is set to has passed, send this position to everyone to avoid ghosting - if(!IsMoving() && !IsEngaged()) - { + if(!IsMoving() && !IsEngaged()) { SendPosition(); - if(IsSitting()) - { + if(IsSitting()) { if(!rest_timer.Enabled()) - { rest_timer.Start(RuleI(Character, RestRegenTimeToActivate) * 1000); - } } } BuffProcess(); - CalcRestState(); - - if(curfp) + if(currently_fleeing) ProcessFlee(); if(GetHP() < GetMaxHP()) @@ -2909,9 +1842,8 @@ bool Bot::Process() SetEndurance(GetEndurance() + CalcEnduranceRegen() + RestRegenEndurance); } - if (sendhpupdate_timer.Check()) { + if (sendhpupdate_timer.Check(false)) { SendHPUpdate(); - if(HasPet()) GetPet()->SendHPUpdate(); } @@ -2922,24 +1854,14 @@ bool Bot::Process() if (IsStunned() || IsMezzed()) return true; - //Handle assists... - /*if(assist_timer.Check() && !Charmed() && GetTarget() != nullptr) { - entity_list.AIYellForHelp(this, GetTarget()); - }*/ - // Bot AI AI_Process(); - return true; } -void Bot::SpellProcess() -{ - // check the rapid recast prevention timer - if(spellend_timer.Check(false)) - { +void Bot::SpellProcess() { + if(spellend_timer.Check(false)) { NPC::SpellProcess(); - if(GetClass() == BARD) { if (casting_spell_id != 0) casting_spell_id = 0; @@ -2949,34 +1871,24 @@ void Bot::SpellProcess() void Bot::BotMeditate(bool isSitting) { if(isSitting) { - // If the bot is a caster has less than 99% mana while its not engaged, he needs to sit to meditate - if(GetManaRatio() < 99.0f || GetHPRatio() < 99.0f) - { + if(GetManaRatio() < 99.0f || GetHPRatio() < 99.0f) { if (!IsEngaged() && !IsSitting()) Sit(); - } - else - { + } else { if(IsSitting()) Stand(); } - } - else - { + } else { if(IsSitting()) Stand(); } - if(IsSitting()) - { + + if(IsSitting()) { if(!rest_timer.Enabled()) - { rest_timer.Start(RuleI(Character, RestRegenTimeToActivate) * 1000); - } } else - { rest_timer.Disable(); - } } void Bot::BotRangedAttack(Mob* other) { @@ -2988,13 +1900,13 @@ void Bot::BotRangedAttack(Mob* other) { return; } - ItemInst* rangedItem = GetBotItem(MainRange); - const Item_Struct* RangeWeapon = 0; + ItemInst* rangedItem = GetBotItem(EQEmu::legacy::SlotRange); + const EQEmu::ItemBase* RangeWeapon = 0; if(rangedItem) RangeWeapon = rangedItem->GetItem(); - ItemInst* ammoItem = GetBotItem(MainAmmo); - const Item_Struct* Ammo = 0; + ItemInst* ammoItem = GetBotItem(EQEmu::legacy::SlotAmmo); + const EQEmu::ItemBase* Ammo = 0; if(ammoItem) Ammo = ammoItem->GetItem(); @@ -3002,20 +1914,12 @@ void Bot::BotRangedAttack(Mob* other) { return; Log.Out(Logs::Detail, Logs::Combat, "Shooting %s with bow %s (%d) and arrow %s (%d)", other->GetCleanName(), RangeWeapon->Name, RangeWeapon->ID, Ammo->Name, Ammo->ID); - - if(!IsAttackAllowed(other) || - IsCasting() || - DivineAura() || - IsStunned() || - IsMezzed() || - (GetAppearance() == eaDead)) - { + if(!IsAttackAllowed(other) || IsCasting() || DivineAura() || IsStunned() || IsMezzed() || (GetAppearance() == eaDead)) return; - } - SendItemAnimation(other, Ammo, SkillArchery); - - DoArcheryAttackDmg(GetTarget(), rangedItem, ammoItem); + SendItemAnimation(other, Ammo, EQEmu::skills::SkillArchery); + //DoArcheryAttackDmg(GetTarget(), rangedItem, ammoItem); + DoArcheryAttackDmg(other, rangedItem, ammoItem); // watch //break invis when you attack if(invisible) { @@ -3024,13 +1928,15 @@ void Bot::BotRangedAttack(Mob* other) { BuffFadeByEffect(SE_Invisibility2); invisible = false; } + if(invisible_undead) { Log.Out(Logs::Detail, Logs::Combat, "Removing invisibility vs. undead due to melee attack."); BuffFadeByEffect(SE_InvisVsUndead); BuffFadeByEffect(SE_InvisVsUndead2); invisible_undead = false; } - if(invisible_animals){ + + if(invisible_animals) { Log.Out(Logs::Detail, Logs::Combat, "Removing invisibility vs. animals due to melee attack."); BuffFadeByEffect(SE_InvisVsAnimals); invisible_animals = false; @@ -3053,26 +1959,21 @@ void Bot::BotRangedAttack(Mob* other) { } bool Bot::CheckBotDoubleAttack(bool tripleAttack) { - //Check for bonuses that give you a double attack chance regardless of skill (ie Bestial Frenzy/Harmonious Attack AA) - uint32 bonusGiveDA = aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack; - + uint32 bonusGiveDA = (aabonuses.GiveDoubleAttack + spellbonuses.GiveDoubleAttack + itembonuses.GiveDoubleAttack); // If you don't have the double attack skill, return - if(!GetSkill(SkillDoubleAttack) && !(GetClass() == BARD || GetClass() == BEASTLORD)) + if (!GetSkill(EQEmu::skills::SkillDoubleAttack) && !(GetClass() == BARD || GetClass() == BEASTLORD)) return false; // You start with no chance of double attacking float chance = 0.0f; - - uint16 skill = GetSkill(SkillDoubleAttack); - - int32 bonusDA = aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance; - + uint16 skill = GetSkill(EQEmu::skills::SkillDoubleAttack); + int32 bonusDA = (aabonuses.DoubleAttackChance + spellbonuses.DoubleAttackChance + itembonuses.DoubleAttackChance); //Use skill calculations otherwise, if you only have AA applied GiveDoubleAttack chance then use that value as the base. if (skill) - chance = (float(skill+GetLevel()) * (float(100.0f+bonusDA+bonusGiveDA) /100.0f)) /500.0f; + chance = ((float(skill + GetLevel()) * (float(100.0f + bonusDA + bonusGiveDA) / 100.0f)) / 500.0f); else - chance = (float(bonusGiveDA) * (float(100.0f+bonusDA)/100.0f) ) /100.0f; + chance = ((float(bonusGiveDA) * (float(100.0f + bonusDA) / 100.0f)) / 100.0f); //Live now uses a static Triple Attack skill (lv 46 = 2% lv 60 = 20%) - We do not have this skill on EMU ATM. //A reasonable forumla would then be TA = 20% * chance @@ -3080,9 +1981,9 @@ bool Bot::CheckBotDoubleAttack(bool tripleAttack) { //Kayen: Need to decide if we can implement triple attack skill before working in over the cap effect. if(tripleAttack) { // Only some Double Attack classes get Triple Attack [This is already checked in client_processes.cpp] - int32 triple_bonus = spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance; + int32 triple_bonus = (spellbonuses.TripleAttackChance + itembonuses.TripleAttackChance); chance *= 0.2f; //Baseline chance is 20% of your double attack chance. - chance *= float(100.0f+triple_bonus)/100.0f; //Apply modifiers. + chance *= (float(100.0f + triple_bonus) / 100.0f); //Apply modifiers. } if((zone->random.Real(0, 1) < chance)) @@ -3091,44 +1992,37 @@ bool Bot::CheckBotDoubleAttack(bool tripleAttack) { return false; } -void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime) -{ +void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime) { if (!CanDoSpecialAttack(other)) return; //For spells using skill value 98 (feral swipe ect) server sets this to 67 automatically. - //Kayen: This is unlikely to be completely accurate but use OFFENSE skill value for these effects. - if (skillinuse == SkillBegging) - skillinuse = SkillOffense; + if (skillinuse == EQEmu::skills::SkillBegging) + skillinuse = EQEmu::skills::SkillOffense; int damage = 0; uint32 hate = 0; - int Hand = MainPrimary; - if (hate == 0 && weapon_damage > 1) hate = weapon_damage; + int Hand = EQEmu::legacy::SlotPrimary; + if (hate == 0 && weapon_damage > 1) + hate = weapon_damage; - if(weapon_damage > 0){ - - if(GetClass() == BERSERKER){ - int bonus = 3 + GetLevel()/10; - weapon_damage = weapon_damage * (100+bonus) / 100; + if(weapon_damage > 0) { + if(GetClass() == BERSERKER) { + int bonus = (3 + GetLevel( )/ 10); + weapon_damage = (weapon_damage * (100 + bonus) / 100); } int32 min_hit = 1; - int32 max_hit = (2*weapon_damage*GetDamageTable(skillinuse)) / 100; - - if(GetLevel() >= 28 && IsWarriorClass() ) - { - int ucDamageBonus = GetWeaponDamageBonus((const Item_Struct*) nullptr ); - + int32 max_hit = ((2 * weapon_damage * GetDamageTable(skillinuse)) / 100); + if(GetLevel() >= 28 && IsWarriorClass()) { + int ucDamageBonus = GetWeaponDamageBonus((const EQEmu::ItemBase*) nullptr); min_hit += (int) ucDamageBonus; max_hit += (int) ucDamageBonus; hate += ucDamageBonus; } ApplySpecialAttackMod(skillinuse, max_hit, min_hit); - - min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100; - + min_hit += (min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100); if(max_hit < min_hit) max_hit = min_hit; @@ -3137,61 +2031,61 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes else damage = zone->random.Int(min_hit, max_hit); - if(!other->CheckHitChance(this, skillinuse, Hand, chance_mod)) { - damage = 0; + if (other->AvoidDamage(this, damage, CanRiposte ? EQEmu::legacy::SlotRange : EQEmu::legacy::SlotPrimary)) { // MainRange excludes ripo, primary doesn't have any extra behavior + if (damage == -3) { + DoRiposte(other); + if (HasDied()) + return; + } } else { - other->AvoidDamage(this, damage, CanRiposte); - other->MeleeMitigation(this, damage, min_hit); - if(damage > 0) { - damage += damage*focus/100; - ApplyMeleeDamageBonus(skillinuse, damage); - damage += other->GetFcDamageAmtIncoming(this, 0, true, skillinuse); - damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse); - TryCriticalHit(other, skillinuse, damage, nullptr); + if (other->CheckHitChance(this, skillinuse, Hand, chance_mod)) { + other->MeleeMitigation(this, damage, min_hit); + if (damage > 0) { + damage += damage*focus/100; + ApplyMeleeDamageBonus(skillinuse, damage); + damage += other->GetFcDamageAmtIncoming(this, 0, true, skillinuse); + damage += ((itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse)); + TryCriticalHit(other, skillinuse, damage, nullptr); + } + } else { + damage = 0; } } - - if (damage == -3) { - DoRiposte(other); - if (HasDied()) - return; - } } - else damage = -5; - if(skillinuse == SkillBash){ - const ItemInst* inst = GetBotItem(MainSecondary); - const Item_Struct* botweapon = 0; + if (skillinuse == EQEmu::skills::SkillBash){ + const ItemInst* inst = GetBotItem(EQEmu::legacy::SlotSecondary); + const EQEmu::ItemBase* botweapon = 0; if(inst) botweapon = inst->GetItem(); + if(botweapon) { - if(botweapon->ItemType == ItemTypeShield) { + if (botweapon->ItemType == EQEmu::item::ItemTypeShield) hate += botweapon->AC; - } - hate = hate * (100 + GetFuriousBash(botweapon->Focus.Effect)) / 100; + + hate = (hate * (100 + GetFuriousBash(botweapon->Focus.Effect)) / 100); } } other->AddToHateList(this, hate); bool CanSkillProc = true; - if (skillinuse == SkillOffense){ //Hack to allow damage to display. - skillinuse = SkillTigerClaw; //'strike' your opponent - Arbitrary choice for message. + if (skillinuse == EQEmu::skills::SkillOffense){ //Hack to allow damage to display. + skillinuse = EQEmu::skills::SkillTigerClaw; //'strike' your opponent - Arbitrary choice for message. CanSkillProc = false; //Disable skill procs } other->Damage(this, damage, SPELL_UNKNOWN, skillinuse); - if (HasDied()) return; if (damage > 0) CheckNumHitsRemaining(NumHit::OutgoingHitSuccess); - if((skillinuse == SkillDragonPunch) && GetAA(aaDragonPunch) && zone->random.Int(0, 99) < 25){ - SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff); + if ((skillinuse == EQEmu::skills::SkillDragonPunch) && GetAA(aaDragonPunch) && zone->random.Int(0, 99) < 25){ + SpellFinished(904, other, EQEmu::CastingSlot::Item, 0, -1, spells[904].ResistDiff); other->Stun(100); } @@ -3202,42 +2096,37 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes TrySkillProc(other, skillinuse, ReuseTime, true); } -void Bot::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) { - +void Bot::ApplySpecialAttackMod(EQEmu::skills::SkillType skill, int32 &dmg, int32 &mindmg) { int item_slot = -1; //1: Apply bonus from AC (BOOT/SHIELD/HANDS) est. 40AC=6dmg - - switch (skill){ - - case SkillFlyingKick: - case SkillRoundKick: - case SkillKick: - item_slot = MainFeet; + switch (skill) { + case EQEmu::skills::SkillFlyingKick: + case EQEmu::skills::SkillRoundKick: + case EQEmu::skills::SkillKick: + item_slot = EQEmu::legacy::SlotFeet; break; - - case SkillBash: - item_slot = MainSecondary; + case EQEmu::skills::SkillBash: + item_slot = EQEmu::legacy::SlotSecondary; break; - - case SkillDragonPunch: - case SkillEagleStrike: - case SkillTigerClaw: - item_slot = MainHands; + case EQEmu::skills::SkillDragonPunch: + case EQEmu::skills::SkillEagleStrike: + case EQEmu::skills::SkillTigerClaw: + item_slot = EQEmu::legacy::SlotHands; break; } - if (item_slot >= EmuConstants::EQUIPMENT_BEGIN){ + if (item_slot >= EQEmu::legacy::EQUIPMENT_BEGIN){ const ItemInst* inst = GetBotItem(item_slot); - const Item_Struct* botweapon = 0; + const EQEmu::ItemBase* botweapon = 0; if(inst) botweapon = inst->GetItem(); + if(botweapon) dmg += botweapon->AC * (RuleI(Combat, SpecialAttackACBonus))/100; } } -bool Bot::CanDoSpecialAttack(Mob *other) -{ +bool Bot::CanDoSpecialAttack(Mob *other) { //Make sure everything is valid before doing any attacks. if (!other) { SetTarget(nullptr); @@ -3247,12 +2136,7 @@ bool Bot::CanDoSpecialAttack(Mob *other) if(!GetTarget()) SetTarget(other); - if ((other == nullptr || ((GetAppearance() == eaDead) || (other->IsClient() && other->CastToClient()->IsDead())) - || HasDied() || (!IsAttackAllowed(other)))) { - return false; - } - - if(other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)) + if ((other == nullptr || ((GetAppearance() == eaDead) || (other->IsClient() && other->CastToClient()->IsDead())) || HasDied() || (!IsAttackAllowed(other))) || other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)) return false; return true; @@ -3269,7 +2153,6 @@ 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(); @@ -3284,22 +2167,19 @@ float Bot::GetMaxMeleeRangeToTarget(Mob* target) { else if (other_size_mod < 6.0) other_size_mod = 8.0f; - if (other_size_mod > size_mod) { + if (other_size_mod > size_mod) size_mod = other_size_mod; - } - - // this could still use some work, but for now it's an improvement.... if (size_mod > 29) size_mod *= size_mod; else if (size_mod > 19) - size_mod *= size_mod * 2; + size_mod *= (size_mod * 2); else - size_mod *= size_mod * 4; + size_mod *= (size_mod * 4); // prevention of ridiculously sized hit boxes if (size_mod > 10000) - size_mod = size_mod / 7; + size_mod = (size_mod / 7); result = size_mod; } @@ -3309,26 +2189,42 @@ float Bot::GetMaxMeleeRangeToTarget(Mob* target) { // AI Processing for the Bot object void Bot::AI_Process() { - if(!IsAIControlled()) + if (!IsAIControlled()) + return; + if (GetPauseAI()) return; uint8 botClass = GetClass(); uint8 botLevel = GetLevel(); - if(IsCasting() && (botClass != BARD)) - return; - - // A bot wont start its AI if not grouped - if(!GetBotOwner() || !IsGrouped()) { - return; + if (IsCasting()) { + 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) + ) { + InterruptSpell(); + } + else if (AmICastingForHealRotation() && m_member_of_heal_rotation->CastingMember() == this) { + AdvanceHealRotation(false); + return; + } + else if (botClass != BARD) { + return; + } + } + else if (IsHealRotationMember()) { + m_member_of_heal_rotation->SetMemberIsCasting(this, false); } - if(GetAppearance() == eaDead) + // A bot wont start its AI if not grouped + if(!GetBotOwner() || !IsGrouped() || GetAppearance() == eaDead) return; Mob* BotOwner = GetBotOwner(); - - // The bots need an owner if(!BotOwner) return; @@ -3345,27 +2241,35 @@ void Bot::AI_Process() { return; } - if(GetHealRotationActive() && GetHealRotationTarget() && !GetHasHealedThisCycle() && GetHealRotationNextHealTime() < Timer::GetCurrentTime()) { - if(AIHealRotation(GetHealRotationTarget(), GetHealRotationUseFastHeals())) { - SetHasHealedThisCycle(true); - NotifyNextHealRotationMember(); + if(IsMyHealRotationSet()) { + Mob* delete_me = HealRotationTarget(); + if (AIHealRotation(HealRotationTarget(), UseHealRotationFastHeals())) { +#if (EQDEBUG >= 12) + Log.Out(Logs::General, Logs::Error, "Bot::AI_Process() - Casting succeeded (m: %s, t: %s) : AdvHR(true)", GetCleanName(), ((delete_me) ? (delete_me->GetCleanName()) : ("nullptr"))); +#endif + m_member_of_heal_rotation->SetMemberIsCasting(this); + m_member_of_heal_rotation->UpdateTargetHealingStats(HealRotationTarget()); + AdvanceHealRotation(); } else { - NotifyNextHealRotationMember(true); +#if (EQDEBUG >= 12) + Log.Out(Logs::General, Logs::Error, "Bot::AI_Process() - Casting failed (m: %s, t: %s) : AdvHR(false)", GetCleanName(), ((delete_me) ? (delete_me->GetCleanName()) : ("nullptr"))); +#endif + m_member_of_heal_rotation->SetMemberIsCasting(this, false); + AdvanceHealRotation(false); } } if(GetHasBeenSummoned()) { if(IsBotCaster() || IsBotArcher()) { - if (AImovement_timer->Check()) { + if (AI_movement_timer->Check()) { if(!GetTarget() || (IsBotCaster() && !IsBotCasterCombatRange(GetTarget())) || (IsBotArcher() && IsArcheryRange(GetTarget())) || (DistanceSquaredNoZ(static_cast(m_Position), m_PreSummonLocation) < 10)) { if(GetTarget()) FaceTarget(GetTarget()); + SetHasBeenSummoned(false); - } - else if(!IsRooted()) { - if(GetTarget() && GetTarget()->GetHateTop() && GetTarget()->GetHateTop() != this) - { + } else if(!IsRooted()) { + if(GetTarget() && GetTarget()->GetHateTop() && GetTarget()->GetHateTop() != this) { Log.Out(Logs::Detail, Logs::AI, "Returning to location prior to being summoned."); CalculateNewPosition2(m_PreSummonLocation.x, m_PreSummonLocation.y, m_PreSummonLocation.z, GetRunspeed()); SetHeading(CalculateHeadingToTarget(m_PreSummonLocation.x, m_PreSummonLocation.y)); @@ -3378,35 +2282,29 @@ void Bot::AI_Process() { else SendPosition(); } - } - else { + } else { if(GetTarget()) FaceTarget(GetTarget()); + SetHasBeenSummoned(false); } - return; } if(!IsEngaged()) { if(GetFollowID()) { - if(BotOwner && BotOwner->GetTarget() && BotOwner->GetTarget()->IsNPC() && (BotOwner->GetTarget()->GetHateAmount(BotOwner) - || BotOwner->CastToClient()->AutoAttackEnabled()) && IsAttackAllowed(BotOwner->GetTarget())) { + 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 { + } 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); @@ -3419,9 +2317,7 @@ void Bot::AI_Process() { } } - if(IsEngaged()) - { - + if(IsEngaged()) { if(rest_timer.Enabled()) rest_timer.Disable(); @@ -3447,31 +2343,25 @@ void Bot::AI_Process() { // Else, it was causing the bot to aggro behind wall etc... causing massive trains. if(!CheckLosFN(GetTarget()) || GetTarget()->IsMezzed() || !IsAttackAllowed(GetTarget())) { WipeHateList(); - if(IsMoving()) { SetHeading(0); SetRunAnimSpeed(0); - - if(moved) { - moved = false; - SendPosition(); - SetMoving(false); - } + SetCurrentSpeed(GetRunspeed()); + if(moved) + SetCurrentSpeed(0); } - 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 { + if(botClass == SHADOWKNIGHT || botClass == PALADIN || botClass == WARRIOR) + meleeDistance = (meleeDistance * .30); + else meleeDistance *= (float)zone->random.Real(.50, .85); - } bool atArcheryRange = IsArcheryRange(GetTarget()); @@ -3481,8 +2371,7 @@ void Bot::AI_Process() { if(atArcheryRange && !IsBotArcher()) { SetBotArcher(true); changeWeapons = true; - } - else if(!atArcheryRange && IsBotArcher()) { + } else if(!atArcheryRange && IsBotArcher()) { SetBotArcher(false); changeWeapons = true; } @@ -3495,43 +2384,36 @@ void Bot::AI_Process() { if(IsMoving()) { SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); SetRunAnimSpeed(0); - + SetCurrentSpeed(0); if(moved) { moved = false; - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); } } - atCombatRange = true; - } - else if(IsBotCaster() && GetLevel() > 12) { + } else if(IsBotCaster() && GetLevel() > 12) { if(IsBotCasterCombatRange(GetTarget())) atCombatRange = true; } - else if(DistanceSquared(m_Position, GetTarget()->GetPosition()) <= meleeDistance) { + else if(DistanceSquared(m_Position, GetTarget()->GetPosition()) <= meleeDistance) atCombatRange = true; - } if(atCombatRange) { if(IsMoving()) { SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); - SetRunAnimSpeed(0); - + SetCurrentSpeed(0); if(moved) { moved = false; - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); } } - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { if(!IsMoving() && GetClass() == ROGUE && !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, GetRunspeed()); return; @@ -3542,7 +2424,6 @@ void Bot::AI_Process() { float newX = 0; float newY = 0; float newZ = 0; - if(PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) { CalculateNewPosition2(newX, newY, newZ, GetRunspeed()); return; @@ -3557,73 +2438,53 @@ void Bot::AI_Process() { if(IsBotArcher() && ranged_timer.Check(false)) { if(GetTarget()->GetHPRatio() <= 99.0f) - // Mob::DoArcheryAttackDmg() takes care of Bot Range and Ammo procs BotRangedAttack(GetTarget()); } else if(!IsBotArcher() && (!(IsBotCaster() && GetLevel() > 12)) && GetTarget() && !IsStunned() && !IsMezzed() && (GetAppearance() != eaDead)) { // 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()) - return; - - if(GetBotStance() == BotStancePassive) + if((IsEngaged() && !BehindMob(GetTarget(), GetX(), GetY()) && GetTarget()->IsEnraged()) || GetBotStance() == BotStancePassive) return; // First, special attack per class (kick, backstab etc..) DoClassAttacks(GetTarget()); - - //try main hand first if(attack_timer.Check()) { - Attack(GetTarget(), MainPrimary); - - ItemInst *wpn = GetBotItem(MainPrimary); - TryWeaponProc(wpn, GetTarget(), MainPrimary); - + Attack(GetTarget(), EQEmu::legacy::SlotPrimary); + TriggerDefensiveProcs(GetTarget(), EQEmu::legacy::SlotPrimary, false); + ItemInst *wpn = GetBotItem(EQEmu::legacy::SlotPrimary); + TryWeaponProc(wpn, GetTarget(), EQEmu::legacy::SlotPrimary); bool tripleSuccess = false; - if(BotOwner && GetTarget() && CanThisClassDoubleAttack()) { - - if(BotOwner && CheckBotDoubleAttack()) { - Attack(GetTarget(), MainPrimary, true); - } + if(BotOwner && CheckBotDoubleAttack()) + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, true); if(BotOwner && GetTarget() && GetSpecialAbility(SPECATK_TRIPLE) && CheckBotDoubleAttack(true)) { tripleSuccess = true; - Attack(GetTarget(), MainPrimary, true); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, true); } //quad attack, does this belong here?? - if(BotOwner && GetTarget() && GetSpecialAbility(SPECATK_QUAD) && CheckBotDoubleAttack(true)) { - Attack(GetTarget(), MainPrimary, true); - } + if(BotOwner && GetTarget() && GetSpecialAbility(SPECATK_QUAD) && CheckBotDoubleAttack(true)) + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, true); } //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) - { + int32 flurrychance = (aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance); + if (GetTarget() && flurrychance) { + if(zone->random.Int(0, 100) < flurrychance) { Message_StringID(MT_NPCFlurry, YOU_FLURRY); - Attack(GetTarget(), MainPrimary, false); - Attack(GetTarget(), MainPrimary, false); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, false); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, false); } } - int32 ExtraAttackChanceBonus = spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance; - + int32 ExtraAttackChanceBonus = (spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance); if (GetTarget() && ExtraAttackChanceBonus) { - ItemInst *wpn = GetBotItem(MainPrimary); - if(wpn){ - if(wpn->GetItem()->ItemType == ItemType2HSlash || - wpn->GetItem()->ItemType == ItemType2HBlunt || - wpn->GetItem()->ItemType == ItemType2HPiercing ) - { + ItemInst *wpn = GetBotItem(EQEmu::legacy::SlotPrimary); + if(wpn) { + if (wpn->GetItem()->IsType2HWeapon()) { if(zone->random.Int(0, 100) < ExtraAttackChanceBonus) - { - Attack(GetTarget(), MainPrimary, false); - } + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, false); } } } @@ -3634,6 +2495,7 @@ void Bot::AI_Process() { 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; @@ -3642,8 +2504,8 @@ void Bot::AI_Process() { //now off hand if(GetTarget() && attack_dw_timer.Check() && CanThisClassDualWield()) { - const ItemInst* instweapon = GetBotItem(MainSecondary); - const Item_Struct* weapon = 0; + const ItemInst* instweapon = GetBotItem(EQEmu::legacy::SlotSecondary); + const EQEmu::ItemBase* weapon = 0; //can only dual wield without a weapon if you're a monk if(instweapon || (botClass == MONK)) { if(instweapon) @@ -3651,47 +2513,39 @@ void Bot::AI_Process() { int weapontype = 0; // No weapon type. bool bIsFist = true; - if(weapon) { weapontype = weapon->ItemType; bIsFist = false; } - if(bIsFist || ((weapontype != ItemType2HSlash) && (weapontype != ItemType2HPiercing) && (weapontype != ItemType2HBlunt))) { + if (bIsFist || !weapon->IsType2HWeapon()) { float DualWieldProbability = 0.0f; - - int32 Ambidexterity = aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity; - DualWieldProbability = (GetSkill(SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f; // 78.0 max - int32 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance; - DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.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(), MainSecondary); // Single attack with offhand - - ItemInst *wpn = GetBotItem(MainSecondary); - TryWeaponProc(wpn, GetTarget(), MainSecondary); - + Attack(GetTarget(), EQEmu::legacy::SlotSecondary); // Single attack with offhand + ItemInst *wpn = GetBotItem(EQEmu::legacy::SlotSecondary); + TryWeaponProc(wpn, GetTarget(), EQEmu::legacy::SlotSecondary); if( CanThisClassDoubleAttack() && CheckBotDoubleAttack()) { if(GetTarget() && GetTarget()->GetHP() > -10) - Attack(GetTarget(), MainSecondary); // Single attack with offhand + Attack(GetTarget(), EQEmu::legacy::SlotSecondary); // Single attack with offhand } } } } } } - } // end in combat range - else { + } 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 (AImovement_timer->Check()) { + if (AI_movement_timer->Check()) { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName()); CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed()); @@ -3709,54 +2563,43 @@ void Bot::AI_Process() { if(GetBotStance() == BotStancePassive) return; - if(AI_EngagedCastCheck()) { + if(AI_EngagedCastCheck()) BotMeditate(false); - } else if(GetArchetype() == ARCHETYPE_CASTER) BotMeditate(true); } - } // end IsEngaged() - else { - // Not engaged in combat + } else { SetTarget(0); + if (m_PlayerState & static_cast(PlayerState::Aggressive)) + SendRemovePlayerState(PlayerState::Aggressive); - if(!IsMoving() && AIthink_timer->Check() && !spellend_timer.Enabled()) { + if(!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { if(GetBotStance() != BotStancePassive) { if(!AI_IdleCastCheck() && !IsCasting()) BotMeditate(true); } - else { + else BotMeditate(true); - } - } - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { if(GetFollowID()) { Mob* follow = entity_list.GetMob(GetFollowID()); - if(follow) { float dist = DistanceSquared(m_Position, follow->GetPosition()); - float speed = follow->GetRunspeed(); - + int speed = follow->GetRunspeed(); if(dist < GetFollowDistance() + 1000) speed = follow->GetWalkspeed(); - SetRunAnimSpeed(0); - if(dist > GetFollowDistance()) { CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed); if(rest_timer.Enabled()) rest_timer.Disable(); return; - } - else - { - if(moved) - { - moved=false; - SendPosition(); - SetMoving(false); + } else { + if(moved) { + moved = false; + SetCurrentSpeed(0); } } } @@ -3767,33 +2610,20 @@ void Bot::AI_Process() { // AI Processing for a Bot object's pet 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()) { Kill(); return; } - if (!botPet->IsAIControlled()) - return; - - if(botPet->GetAttackTimer().Check(false)) - return; - - if (botPet->IsCasting()) - return; - - // Return if the owner of the bot pet isnt a bot. - if (!botPet->GetOwner()->IsBot()) + if (!botPet->IsAIControlled() || botPet->GetAttackTimer().Check(false) || botPet->IsCasting() || !botPet->GetOwner()->IsBot()) return; if (IsEngaged()) { - if (botPet->IsRooted()) botPet->SetTarget(hate_list.GetClosestEntOnHateList(botPet)); else @@ -3805,43 +2635,23 @@ void Bot::PetAIProcess() { if(!botPet->CheckLosFN(botPet->GetTarget()) || botPet->GetTarget()->IsMezzed() || !botPet->IsAttackAllowed(GetTarget())) { botPet->WipeHateList(); botPet->SetTarget(botPet->GetOwner()); - return; } botPet->FaceTarget(botPet->GetTarget()); - - // Lets see if we can let the main tank build a little aggro - /*if(GetBotRaidID()) { - BotRaids *br = entity_list.GetBotRaidByMob(GetOwner()); - if(br) { - if(br->GetBotMainTank() && (br->GetBotMainTank() != this)) { - if(br->GetBotMainTarget() && (br->GetBotMainTarget()->GetHateAmount(br->GetBotMainTank()) < 5000)) { - if(GetTarget() == br->GetBotMainTarget()) { - return; - } - } - } - } - }*/ - bool is_combat_range = botPet->CombatRange(botPet->GetTarget()); - // Ok, we're engaged, each class type has a special AI // Only melee class will go to melee. Casters and healers will stay behind, following the leader by default. // I should probably make the casters staying in place so they can cast.. // Ok, we 're a melee or any other class lvl<12. Yes, because after it becomes hard to go in melee for casters.. even for bots.. - if( is_combat_range ) { + if(is_combat_range) { botPet->GetAIMovementTimer()->Check(); - if(botPet->IsMoving()) { - botPet->SetRunAnimSpeed(0); botPet->SetHeading(botPet->GetTarget()->GetHeading()); if(moved) { - moved=false; - botPet->SendPosition(); - botPet->SetMoving(false); + moved = false; + botPet->SetRunAnimSpeed(0); } } @@ -3850,10 +2660,8 @@ void Bot::PetAIProcess() { float newY = 0; float newZ = 0; bool petHasAggro = false; - - if(botPet->GetTarget() && botPet->GetTarget()->GetHateTop() && botPet->GetTarget()->GetHateTop() == botPet) { + if(botPet->GetTarget() && botPet->GetTarget()->GetHateTop() && botPet->GetTarget()->GetHateTop() == botPet) petHasAggro = true; - } if(botPet->GetClass() == ROGUE && !petHasAggro && !botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY())) { // Move the rogue to behind the mob @@ -3873,7 +2681,6 @@ void Bot::PetAIProcess() { // Let's try to adjust our melee range so we don't appear to be bunched up bool isBehindMob = false; bool moveBehindMob = false; - if(botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY())) isBehindMob = true; @@ -3895,15 +2702,12 @@ void Bot::PetAIProcess() { if(!botPet->BehindMob(botPet->GetTarget(), botPet->GetX(), botPet->GetY()) && botPet->GetTarget()->IsEnraged()) return; - if(botPet->Attack(GetTarget(), MainPrimary)) // try the main hand - if (botPet->GetTarget()) // Do we still have a target? - { + if (botPet->Attack(GetTarget(), EQEmu::legacy::SlotPrimary)) // try the main hand + if (botPet->GetTarget()) { // We're a pet so we re able to dual attack int32 RandRoll = zone->random.Int(0, 99); - if (botPet->CanThisClassDoubleAttack() && (RandRoll < (botPet->GetLevel() + NPCDualAttackModifier))) - { - if(botPet->Attack(botPet->GetTarget(), MainPrimary)) - {} + if (botPet->CanThisClassDoubleAttack() && (RandRoll < (botPet->GetLevel() + NPCDualAttackModifier))) { + if (botPet->Attack(botPet->GetTarget(), EQEmu::legacy::SlotPrimary)) {} } } @@ -3916,19 +2720,18 @@ void Bot::PetAIProcess() { aa_skill += botPet->GetOwner()->GetAA(aaQuickeningofDeath); // Beastlord AA aa_skill += botPet->GetOwner()->GetAA(aaWardersAlacrity); + if(aa_skill >= 1) + aa_chance += ((aa_skill > 5 ? 5 : aa_skill) * 4); + + if(aa_skill >= 6) + aa_chance += ((aa_skill - 5 > 3 ? 3 : aa_skill - 5) * 7); + + if(aa_skill >= 9) + aa_chance += ((aa_skill - 8 > 3 ? 3 : aa_skill - 8) * 3); + + if(aa_skill >= 12) + aa_chance += ((aa_skill - 11) * 1); - if(aa_skill >= 1) { - aa_chance += (aa_skill > 5 ? 5 : aa_skill) * 4; - } - if(aa_skill >= 6) { - aa_chance += (aa_skill-5 > 3 ? 3 : aa_skill-5) * 7; - } - if(aa_skill >= 9) { - aa_chance += (aa_skill-8 > 3 ? 3 : aa_skill-8) * 3; - } - if(aa_skill >= 12) { - aa_chance += (aa_skill - 11) * 1; - } //aa_chance += botPet->GetOwner()->GetAA(aaCompanionsAlacrity) * 3; @@ -3937,21 +2740,16 @@ void Bot::PetAIProcess() { } // Ok now, let's check pet's offhand. - if (botPet->GetAttackDWTimer().Check() && botPet->GetOwnerID() && botPet->GetOwner() && ((botPet->GetOwner()->GetClass() == MAGICIAN) || (botPet->GetOwner()->GetClass() == NECROMANCER) || (botPet->GetOwner()->GetClass() == SHADOWKNIGHT) || (botPet->GetOwner()->GetClass() == BEASTLORD))) - { - if(botPet->GetOwner()->GetLevel() >= 24) - { - float DualWieldProbability = (botPet->GetSkill(SkillDualWield) + botPet->GetLevel()) / 400.0f; + if (botPet->GetAttackDWTimer().Check() && botPet->GetOwnerID() && botPet->GetOwner() && ((botPet->GetOwner()->GetClass() == MAGICIAN) || (botPet->GetOwner()->GetClass() == NECROMANCER) || (botPet->GetOwner()->GetClass() == SHADOWKNIGHT) || (botPet->GetOwner()->GetClass() == BEASTLORD))) { + if(botPet->GetOwner()->GetLevel() >= 24) { + float DualWieldProbability = ((botPet->GetSkill(EQEmu::skills::SkillDualWield) + botPet->GetLevel()) / 400.0f); DualWieldProbability -= zone->random.Real(0, 1); - if(DualWieldProbability < 0){ - botPet->Attack(botPet->GetTarget(), MainSecondary); - if (botPet->CanThisClassDoubleAttack()) - { + if(DualWieldProbability < 0) { + botPet->Attack(botPet->GetTarget(), EQEmu::legacy::SlotSecondary); + if (botPet->CanThisClassDoubleAttack()) { int32 RandRoll = zone->random.Int(0, 99); if (RandRoll < (botPet->GetLevel() + 20)) - { - botPet->Attack(botPet->GetTarget(), MainSecondary); - } + botPet->Attack(botPet->GetTarget(), EQEmu::legacy::SlotSecondary); } } } @@ -3965,25 +2763,21 @@ void Bot::PetAIProcess() { // See if the pet can cast any spell botPet->AI_EngagedCastCheck(); } - }// end of the combat in range - else{ + } else { // Now, if we cannot reach our target - if (!botPet->HateSummon()) - { - if(botPet->GetTarget() && botPet->AI_PursueCastCheck()) - {} - else if (botPet->GetTarget() && botPet->GetAIMovementTimer()->Check()) - { + if (!botPet->HateSummon()) { + if(botPet->GetTarget() && botPet->AI_PursueCastCheck()) {} + else if (botPet->GetTarget() && botPet->GetAIMovementTimer()->Check()) { botPet->SetRunAnimSpeed(0); if(!botPet->IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", botPet->GetTarget()->GetCleanName()); botPet->CalculateNewPosition2(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ(), botPet->GetOwner()->GetRunspeed()); return; - } - else { + } else { botPet->SetHeading(botPet->GetTarget()->GetHeading()); if(moved) { - moved=false; + moved = false; + SetCurrentSpeed(0); botPet->SendPosition(); botPet->SetMoving(false); } @@ -3991,38 +2785,33 @@ void Bot::PetAIProcess() { } } } - } - else{ - // Franck: EQoffline + } else { // Ok if we're not engaged, what's happening.. - if(botPet->GetTarget() != botPet->GetOwner()) { + if(botPet->GetTarget() != botPet->GetOwner()) botPet->SetTarget(botPet->GetOwner()); - } - if(!IsMoving()) { + if(!IsMoving()) botPet->AI_IdleCastCheck(); - } if(botPet->GetAIMovementTimer()->Check()) { switch(pStandingPetOrder) { - case SPO_Follow: - { - float dist = DistanceSquared(botPet->GetPosition(), botPet->GetTarget()->GetPosition()); - botPet->SetRunAnimSpeed(0); - if(dist > 184) { - botPet->CalculateNewPosition2(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ(), botPet->GetTarget()->GetRunspeed()); - return; - } - else { - botPet->SetHeading(botPet->GetTarget()->GetHeading()); - if(moved) { - moved=false; - botPet->SendPosition(); - botPet->SetMoving(false); - } + case SPO_Follow: { + float dist = DistanceSquared(botPet->GetPosition(), botPet->GetTarget()->GetPosition()); + botPet->SetRunAnimSpeed(0); + if(dist > 184) { + botPet->CalculateNewPosition2(botPet->GetTarget()->GetX(), botPet->GetTarget()->GetY(), botPet->GetTarget()->GetZ(), botPet->GetTarget()->GetRunspeed()); + return; + } else { + botPet->SetHeading(botPet->GetTarget()->GetHeading()); + if(moved) { + moved = false; + SetCurrentSpeed(0); + botPet->SendPosition(); + botPet->SetMoving(false); } } break; + } case SPO_Sit: botPet->SetAppearance(eaSitting); break; @@ -4036,62 +2825,20 @@ void Bot::PetAIProcess() { void Bot::Depop() { WipeHateList(); - entity_list.RemoveFromHateLists(this); - if(HasGroup()) Bot::RemoveBotFromGroup(this, GetGroup()); - if(HasPet()) { + if(HasPet()) GetPet()->Depop(); - } _botOwner = 0; _botOwnerCharacterID = 0; _previousTarget = 0; - NPC::Depop(false); } -bool Bot::DeleteBot(std::string* errorMessage) { - bool hadError = false; - - if(this->GetBotID() == 0) - return false; - - // TODO: These queries need to be ran together as a transaction.. ie, if one or more fail then they all will fail to commit to the database. - std::string query = StringFormat("DELETE FROM botinventory WHERE botid = '%u'", this->GetBotID()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - hadError = true; - } - - query = StringFormat("DELETE FROM botbuffs WHERE botid = '%u'", this->GetBotID()); - results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - hadError = true; - } - - query = StringFormat("DELETE FROM botstances WHERE BotID = '%u'", this->GetBotID()); - results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - hadError = true; - } - - query = StringFormat("DELETE FROM bots WHERE BotID = '%u'", this->GetBotID()); - results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - hadError = true; - } - - return !hadError; -} - -void Bot::Spawn(Client* botCharacterOwner, std::string* errorMessage) { +void 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()); @@ -4115,25 +2862,17 @@ void Bot::Spawn(Client* botCharacterOwner, std::string* errorMessage) { // Make the bot look at the bot owner FaceTarget(botCharacterOwner); - - // Level the bot to the same level as the bot owner - //this->SetLevel(botCharacterOwner->GetLevel()); - UpdateEquipmentLight(); UpdateActiveLight(); - entity_list.AddBot(this, true, true); - // Load pet LoadPet(); - this->SendPosition(); - // there is something askew with spawn struct appearance fields... // I re-enabled this until I can sort it out uint32 itemID = 0; uint8 materialFromSlot = 0xFF; - for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) { + for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= EQEmu::legacy::EQUIPMENT_END; ++i) { itemID = GetBotItemBySlot(i); if(itemID != 0) { materialFromSlot = Inventory::CalcMaterialFromSlot(i); @@ -4144,219 +2883,56 @@ void Bot::Spawn(Client* botCharacterOwner, std::string* errorMessage) { } } -// Saves the specified item as an inventory record in the database for this bot. -void Bot::SetBotItemInSlot(uint32 slotID, uint32 itemID, const ItemInst* inst, std::string *errorMessage) { - - uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM }; - - if (this->GetBotID() == 0 || slotID < EmuConstants::EQUIPMENT_BEGIN || itemID <= NO_ITEM) - return; - - if (inst && inst->IsType(ItemClassCommon)) { - for(int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; ++i) { - ItemInst* auginst = inst->GetItem(i); - augslot[i] = (auginst && auginst->GetItem()) ? auginst->GetItem()->ID : 0; - } - } - - std::string query = StringFormat("REPLACE INTO botinventory (botid, slotid, itemid, charges, instnodrop, color, " - "augslot1, augslot2, augslot3, augslot4, augslot5) " - "VALUES(%lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu, %lu)", - (unsigned long)this->GetBotID(), (unsigned long)slotID, (unsigned long)itemID, - (unsigned long)inst->GetCharges(), (unsigned long)(inst->IsAttuned()? 1: 0), - (unsigned long)inst->GetColor(), (unsigned long)augslot[0], (unsigned long)augslot[1], - (unsigned long)augslot[2], (unsigned long)augslot[3], (unsigned long)augslot[4]); - auto results = database.QueryDatabase(query); - if(!results.Success()) - *errorMessage = std::string(results.ErrorMessage()); -} - // Deletes the inventory record for the specified item from the database for this bot. -void Bot::RemoveBotItemBySlot(uint32 slotID, std::string *errorMessage) { - - if(this->GetBotID() == 0) +void Bot::RemoveBotItemBySlot(uint32 slotID, std::string *errorMessage) +{ + if(!GetBotID()) return; - std::string query = StringFormat("DELETE FROM botinventory " - "WHERE botid = %i AND slotid = %i", - this->GetBotID(), slotID); - auto results = database.QueryDatabase(query); - if(!results.Success()) - *errorMessage = std::string(results.ErrorMessage()); + if(!botdb.DeleteItemBySlot(GetBotID(), slotID)) + *errorMessage = BotDatabase::fail::DeleteItemBySlot(); m_inv.DeleteItem(slotID); UpdateEquipmentLight(); } // Retrieves all the inventory records from the database for this bot. -void Bot::GetBotItems(std::string* errorMessage, Inventory &inv) { +void Bot::GetBotItems(Inventory &inv, std::string* errorMessage) +{ + if(!GetBotID()) + return; - if(this->GetBotID() == 0) - return; - - std::string query = StringFormat("SELECT slotid, itemid, charges, color, " - "augslot1, augslot2, augslot3, augslot4, " - "augslot5, instnodrop FROM botinventory " - "WHERE botid = %i ORDER BY slotid", this->GetBotID()); - auto results = database.QueryDatabase(query); - if (!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return; - } - - for (auto row = results.begin(); row != results.end(); ++row) { - int16 slot_id = atoi(row[0]); - uint32 item_id = atoi(row[1]); - uint16 charges = atoi(row[2]); - uint32 color = atoul(row[3]); - uint32 aug[EmuConstants::ITEM_COMMON_SIZE]; - aug[0] = (uint32)atoul(row[4]); - aug[1] = (uint32)atoul(row[5]); - aug[2] = (uint32)atoul(row[6]); - aug[3] = (uint32)atoul(row[7]); - aug[4] = (uint32)atoul(row[8]); - bool instnodrop = (row[9] && (uint16)atoi(row[9])) ? true : false; - - ItemInst* inst = database.CreateItem(item_id, charges, aug[0], aug[1], aug[2], aug[3], aug[4]); - if (!inst) { - Log.Out(Logs::General, Logs::Error, "Warning: botid %i has an invalid item_id %i in inventory slot %i", this->GetBotID(), item_id, slot_id); - continue; - } - - int16 put_slot_id = INVALID_INDEX; - - if (instnodrop || ((slot_id >= EmuConstants::EQUIPMENT_BEGIN) && (slot_id <= EmuConstants::EQUIPMENT_END) && inst->GetItem()->Attuneable)) - inst->SetAttuned(true); - - if (color > 0) - inst->SetColor(color); - - if (charges==255) - inst->SetCharges(-1); - else - inst->SetCharges(charges); - - if (slot_id < 8000 || slot_id > 8999) - put_slot_id = inv.PutItem(slot_id, *inst); - - safe_delete(inst); - - // Save ptr to item in inventory - if (put_slot_id == INVALID_INDEX) - Log.Out(Logs::General, Logs::Error, "Warning: Invalid slot_id for item in inventory: botid=%i, item_id=%i, slot_id=%i",this->GetBotID(), item_id, slot_id); - - } + if (!botdb.LoadItems(GetBotID(), inv)) { + *errorMessage = BotDatabase::fail::LoadItems(); + return; + } UpdateEquipmentLight(); } // Returns the inventory record for this bot from the database for the specified equipment slot. -uint32 Bot::GetBotItemBySlot(uint32 slotID) { +uint32 Bot::GetBotItemBySlot(uint32 slotID) +{ + uint32 item_id = 0; + if(!GetBotID()) + return item_id; - if(this->GetBotID() == 0 || slotID < EmuConstants::EQUIPMENT_BEGIN) - return 0; - - std::string query = StringFormat("SELECT itemid FROM botinventory WHERE botid=%i AND slotid = %i", GetBotID(), slotID); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return 0; - - if(results.RowCount() != 1) - return 0; - - auto row = results.begin(); - - return atoi(row[0]); -} - -// Returns the number of inventory records the bot has in the database. -uint32 Bot::GetBotItemsCount(std::string *errorMessage) { - - if(this->GetBotID() == 0) - return 0; - - std::string query = StringFormat("SELECT COUNT(*) FROM botinventory WHERE botid = %i", this->GetBotID()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return 0; - } - - if(results.RowCount() != 1) - return 0; - - auto row = results.begin(); - return atoi(row[0]); -} - -bool Bot::MesmerizeTarget(Mob* target) { - bool Result = false; - - if(target) { - int mezid = 0; - int mezlevel = GetLevel(); - - if(mezlevel >= 69) { - mezid = 5520; - } - else if(mezlevel == 68) { - mezid = 8035; - } - else if(mezlevel == 67) { - mezid = 5503; - } - else if(mezlevel >= 64) { - mezid = 3358; - } - else if(mezlevel == 63) { - mezid = 3354; - } - else if(mezlevel >= 61) { - mezid = 3341; - } - else if(mezlevel == 60) { - mezid = 2120; - } - else if(mezlevel == 59) { - mezid = 1692; - } - else if(mezlevel >= 54) { - mezid = 1691; - } - else if(mezlevel >= 47) { - mezid = 190; - } - else if(mezlevel >= 30) { - mezid = 188; - } - else if(mezlevel >= 13) { - mezid = 187; - } - else if(mezlevel >= 2) { - mezid = 292; - } - if(mezid > 0) { - uint32 DontRootMeBeforeTime = 0; - CastSpell(mezid, target->GetID(), 1, -1, -1, &DontRootMeBeforeTime); - target->SetDontRootMeBefore(DontRootMeBeforeTime); - Result = true; - } + if (!botdb.LoadItemBySlot(GetBotID(), slotID, item_id)) { + if (GetBotOwner() && GetBotOwner()->IsClient()) + GetBotOwner()->CastToClient()->Message(13, "%s", BotDatabase::fail::LoadItemBySlot()); } - return Result; + return item_id; } void Bot::SetLevel(uint8 in_level, bool command) { - if(in_level > 0) { + if(in_level > 0) Mob::SetLevel(in_level, command); - } } void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { - if(ns) - { + if(ns) { Mob::FillSpawnStruct(ns, ForWho); - ns->spawn.afk = 0; ns->spawn.lfg = 0; ns->spawn.anon = 0; @@ -4368,161 +2944,71 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { ns->spawn.is_npc = 0; // 0=no, 1=yes ns->spawn.is_pet = 0; ns->spawn.guildrank = 0; - ns->spawn.showhelm = 1; + ns->spawn.showhelm = GetShowHelm() ? 1 : 0; ns->spawn.flymode = 0; ns->spawn.size = 0; ns->spawn.NPC = 0; // 0=player,1=npc,2=pc corpse,3=npc corpse - UpdateActiveLight(); - ns->spawn.light = m_Light.Type.Active; - - ns->spawn.helm = helmtexture; //0xFF; + ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive]; + ns->spawn.helm = helmtexture; //(GetShowHelm() ? helmtexture : 0); //0xFF; ns->spawn.equip_chest2 = texture; //0xFF; - - const Item_Struct* item = 0; + const EQEmu::ItemBase* item = 0; const ItemInst* inst = 0; - uint32 spawnedbotid = 0; spawnedbotid = this->GetBotID(); - - for (int i = 0; i < MaterialPrimary; i++) - { + for (int i = 0; i < EQEmu::textures::TexturePrimary; i++) { inst = GetBotItem(i); - if (inst) - { + if (inst) { item = inst->GetItem(); - if (item != 0) - { - ns->spawn.equipment[i].Material = item->Material; - ns->spawn.equipment[i].EliteMaterial = item->EliteMaterial; - ns->spawn.equipment[i].HeroForgeModel = item->HerosForgeModel; - if (armor_tint[i]) - { - ns->spawn.colors[i].Color = armor_tint[i]; - - } + if (item != 0) { + ns->spawn.equipment.Slot[i].Material = item->Material; + ns->spawn.equipment.Slot[i].EliteMaterial = item->EliteMaterial; + ns->spawn.equipment.Slot[i].HeroForgeModel = item->HerosForgeModel; + if (armor_tint.Slot[i].Color) + ns->spawn.equipment_tint.Slot[i].Color = armor_tint.Slot[i].Color; else - { - ns->spawn.colors[i].Color = item->Color; - } - } - else - { - if (armor_tint[i]) - { - ns->spawn.colors[i].Color = armor_tint[i]; - } + ns->spawn.equipment_tint.Slot[i].Color = item->Color; + } else { + if (armor_tint.Slot[i].Color) + ns->spawn.equipment_tint.Slot[i].Color = armor_tint.Slot[i].Color; } } } - inst = GetBotItem(MainPrimary); - if(inst) - { + inst = GetBotItem(EQEmu::legacy::SlotPrimary); + if(inst) { item = inst->GetItem(); - if(item) - { + if(item) { if(strlen(item->IDFile) > 2) - { - ns->spawn.equipment[MaterialPrimary].Material = atoi(&item->IDFile[2]); - } - ns->spawn.colors[MaterialPrimary].Color = GetEquipmentColor(MaterialPrimary); + ns->spawn.equipment.Primary.Material = atoi(&item->IDFile[2]); + + ns->spawn.equipment_tint.Primary.Color = GetEquipmentColor(EQEmu::textures::TexturePrimary); } } - inst = GetBotItem(MainSecondary); - if(inst) - { + inst = GetBotItem(EQEmu::legacy::SlotSecondary); + if(inst) { item = inst->GetItem(); - if(item) - { + if(item) { if(strlen(item->IDFile) > 2) - { - ns->spawn.equipment[MaterialSecondary].Material = atoi(&item->IDFile[2]); - } - ns->spawn.colors[MaterialSecondary].Color = GetEquipmentColor(MaterialSecondary); + ns->spawn.equipment.Secondary.Material = atoi(&item->IDFile[2]); + + ns->spawn.equipment_tint.Secondary.Color = GetEquipmentColor(EQEmu::textures::TextureSecondary); } } } } -uint32 Bot::GetBotIDByBotName(std::string botName) { - if(botName.empty()) - return 0; - - std::string query = StringFormat("SELECT BotID FROM bots WHERE Name = '%s'", botName.c_str()); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return 0; - - if (results.RowCount() == 0) - return 0; - - auto row = results.begin(); - return atoi(row[0]); -} - -Bot* Bot::LoadBot(uint32 botID, std::string* errorMessage) { - Bot* loadedBot = nullptr; - - if(botID == 0) - return nullptr; - - std::string query = StringFormat("SELECT BotOwnerCharacterID, BotSpellsID, Name, LastName, BotLevel, " - "Race, Class, Gender, Size, Face, LuclinHairStyle, LuclinHairColor, " - "LuclinEyeColor, LuclinEyeColor2, LuclinBeardColor, LuclinBeard, " - "DrakkinHeritage, DrakkinTattoo, DrakkinDetails, HP, Mana, MR, CR, " - "DR, FR, PR, Corrup, AC, STR, STA, DEX, AGI, _INT, WIS, CHA, ATK, " - "BotCreateDate, LastSpawnDate, TotalPlayTime, LastZoneId " - "FROM bots WHERE BotID = '%u'", botID); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return nullptr; - } - - if (results.RowCount() == 0) - return nullptr; - - auto row = results.begin(); - NPCType defaultNPCTypeStruct = CreateDefaultNPCTypeStructForBot(std::string(row[2]), std::string(row[3]), - atoi(row[4]), atoi(row[5]), atoi(row[6]), atoi(row[7])); - - NPCType tempNPCStruct = FillNPCTypeStruct(atoi(row[1]), std::string(row[2]), std::string(row[3]), atoi(row[4]), - atoi(row[5]), atoi(row[6]), atoi(row[7]), atof(row[8]), atoi(row[9]), - atoi(row[10]), atoi(row[11]), atoi(row[12]), atoi(row[13]), atoi(row[14]), - atoi(row[15]), atoi(row[16]), atoi(row[17]), atoi(row[18]), atoi(row[19]), - atoi(row[20]), defaultNPCTypeStruct.MR, defaultNPCTypeStruct.CR, - defaultNPCTypeStruct.DR, defaultNPCTypeStruct.FR, defaultNPCTypeStruct.PR, - defaultNPCTypeStruct.Corrup, defaultNPCTypeStruct.AC, defaultNPCTypeStruct.STR, - defaultNPCTypeStruct.STA, defaultNPCTypeStruct.DEX, defaultNPCTypeStruct.AGI, - defaultNPCTypeStruct.INT, defaultNPCTypeStruct.WIS, defaultNPCTypeStruct.CHA, - defaultNPCTypeStruct.ATK); - - loadedBot = new Bot(botID, atoi(row[0]), atoi(row[1]), atof(row[38]), atoi(row[39]), tempNPCStruct); - - return loadedBot; -} - -std::list Bot::GetGroupedBotsByGroupId(uint32 groupId, std::string* errorMessage) { - std::list groupedBots; - - if(groupId == 0) - return groupedBots; - - std::string query = StringFormat("SELECT g.mobid AS BotID FROM vwGroups AS g " - "JOIN bots AS b ON g.mobid = b.BotId AND g.mobtype = 'B' " - "WHERE g.groupid = %u", groupId); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return groupedBots; - } - - for (auto row = results.begin(); row != results.end(); ++row) - groupedBots.push_back(atoi(row[0])); - - return groupedBots; +Bot* Bot::LoadBot(uint32 botID) +{ + Bot* loaded_bot = nullptr; + if (!botID) + return loaded_bot; + + if (!botdb.LoadBot(botID, loaded_bot)) // TODO: Consider update to message handler + return loaded_bot; + + return loaded_bot; } // Load and spawn all zoned bots by bot owner character @@ -4532,23 +3018,19 @@ void Bot::LoadAndSpawnAllZonedBots(Client* botOwner) { Group* g = botOwner->GetGroup(); if(g) { uint32 TempGroupId = g->GetID(); - std::string errorMessage; - std::list ActiveBots = Bot::GetGroupedBotsByGroupId(botOwner->GetGroup()->GetID(), &errorMessage); - - if(errorMessage.empty() && !ActiveBots.empty()) { + std::list ActiveBots; + if (!botdb.LoadGroupedBotsByGroupID(TempGroupId, ActiveBots)) { + botOwner->Message(13, "%s", BotDatabase::fail::LoadGroupedBotsByGroupID()); + return; + } + + if(!ActiveBots.empty()) { for(std::list::iterator itr = ActiveBots.begin(); itr != ActiveBots.end(); ++itr) { - Bot* activeBot = Bot::LoadBot(*itr, &errorMessage); - - if(!errorMessage.empty()) { - safe_delete(activeBot); - break; - } + Bot* activeBot = Bot::LoadBot(*itr); if(activeBot) { - activeBot->Spawn(botOwner, &errorMessage); - + activeBot->Spawn(botOwner); g->UpdatePlayer(activeBot); - if(g->GetLeader()) activeBot->SetFollowID(g->GetLeader()->GetID()); } @@ -4557,11 +3039,6 @@ void Bot::LoadAndSpawnAllZonedBots(Client* botOwner) { database.SetGroupID(activeBot->GetCleanName(), 0, activeBot->GetBotID()); } } - - // Catch all condition for error messages destined for the zone error log - if(!errorMessage.empty()) { - // TODO: Log this error message to zone error log - } } } } @@ -4570,12 +3047,10 @@ void Bot::LoadAndSpawnAllZonedBots(Client* botOwner) { // Returns TRUE if there is atleast 1 bot in the specified group bool Bot::GroupHasBot(Group* group) { bool Result = false; - if(group) { for(int Counter = 0; Counter < MAX_GROUP_MEMBERS; Counter++) { - if (group->members[Counter] == nullptr) { + if (group->members[Counter] == nullptr) continue; - } if(group->members[Counter]->IsBot()) { Result = true; @@ -4583,336 +3058,18 @@ bool Bot::GroupHasBot(Group* group) { } } } - return Result; } -std::list Bot::GetBotList(uint32 botOwnerCharacterID, std::string* errorMessage) { - std::list ownersBots; - - if(botOwnerCharacterID == 0) - return ownersBots; - - std::string query = StringFormat("SELECT BotID, Name, Class, BotLevel, Race " - "FROM bots WHERE BotOwnerCharacterID = '%u'", botOwnerCharacterID); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return ownersBots; - } - - for (auto row = results.begin(); row != results.end(); ++row) { - BotsAvailableList availableBot; - availableBot.BotID = atoi(row[0]); - strcpy(availableBot.BotName, row[1]); - availableBot.BotClass = atoi(row[2]); - availableBot.BotLevel = atoi(row[3]); - availableBot.BotRace = atoi(row[4]); - - ownersBots.push_back(availableBot); - } - - return ownersBots; -} - -std::list Bot::ListSpawnedBots(uint32 characterID, std::string* errorMessage) { - std::list spawnedBots; - - if(characterID == 0) - return spawnedBots; - - std::string query = StringFormat("SELECT bot_name, zone_name FROM botleader WHERE leaderid=%i", characterID); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return spawnedBots; - } - - for(auto row = results.begin(); row != results.end(); ++row) { - SpawnedBotsList spawnedBotsList; - spawnedBotsList.BotLeaderCharID = characterID; - strcpy(spawnedBotsList.BotName, row[0]); - strcpy(spawnedBotsList.ZoneName, row[1]); - - spawnedBots.push_back(spawnedBotsList); - } - - return spawnedBots; -} - -void Bot::SaveBotGroup(Group* botGroup, std::string botGroupName, std::string* errorMessage) { - if(!botGroup || botGroupName.empty()) - return; - - Mob* tempGroupLeader = botGroup->GetLeader(); - - if(!tempGroupLeader->IsBot()) - return; - - uint32 botGroupId = 0; - uint32 botGroupLeaderBotId = tempGroupLeader->CastToBot()->GetBotID(); - - std::string query = StringFormat("INSERT INTO botgroup (BotGroupLeaderBotId, BotGroupName) " - "VALUES (%u, '%s')", botGroupLeaderBotId, botGroupName.c_str()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return; - } - - if(botGroupId == 0) - return; - - for(int groupMemberIndex = 0; groupMemberIndex < botGroup->GroupCount(); groupMemberIndex++) { - Mob* tempBot = botGroup->members[groupMemberIndex]; - - if(!tempBot || !tempBot->IsBot()) - continue; - - uint32 botGroupMemberBotId = tempBot->CastToBot()->GetBotID(); - - query = StringFormat("INSERT INTO botgroupmembers (BotGroupId, BotId) " - "VALUES (%u, %u)", botGroupId, botGroupMemberBotId); - results = database.QueryDatabase(query); - if(!results.Success()) - *errorMessage = std::string(results.ErrorMessage()); - } - -} - -void Bot::DeleteBotGroup(std::string botGroupName, std::string* errorMessage) { - - if(botGroupName.empty()) - return; - - uint32 botGroupId = GetBotGroupIdByBotGroupName(botGroupName, errorMessage); - - if(!errorMessage->empty() || botGroupId== 0) - return; - - std::string query = StringFormat("DELETE FROM botgroupmembers WHERE BotGroupId = %u", botGroupId); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return; - } - - query = StringFormat("DELETE FROM botgroup WHERE BotGroupId = %u", botGroupId); - results = database.QueryDatabase(query); - if(!results.Success()) - *errorMessage = std::string(results.ErrorMessage()); -} - -std::list Bot::LoadBotGroup(std::string botGroupName, std::string* errorMessage) { - std::list botGroup; - - if(botGroupName.empty()) - return botGroup; - - uint32 botGroupId = GetBotGroupIdByBotGroupName(botGroupName, errorMessage); - - if(botGroupId == 0) - return botGroup; - - std::string query = StringFormat("SELECT BotId FROM botgroupmembers WHERE BotGroupId = %u", botGroupId); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return botGroup; - } - - for(auto row = results.begin(); row != results.end(); ++row) { - BotGroup tempBotGroup; - tempBotGroup.BotGroupID = botGroupId; - tempBotGroup.BotID = atoi(row[0]); - - botGroup.push_back(tempBotGroup); - } - - return botGroup; -} - -std::list Bot::GetBotGroupListByBotOwnerCharacterId(uint32 botOwnerCharacterId, std::string* errorMessage) { - std::list botGroups; - - if(botOwnerCharacterId == 0) - return botGroups; - - std::string query = StringFormat("SELECT BotGroupName, BotGroupLeaderName FROM vwBotGroups " - "WHERE BotOwnerCharacterId = %u", botOwnerCharacterId); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return botGroups; - } - - for(auto row = results.begin(); row != results.end(); ++row) { - BotGroupList botGroupList; - botGroupList.BotGroupName = std::string(row[0]); - botGroupList.BotGroupLeaderName = std::string(row[1]); - - botGroups.push_back(botGroupList); - } - - return botGroups; -} - -bool Bot::DoesBotGroupNameExist(std::string botGroupName) { - - if(botGroupName.empty()) - return false; - - std::string query = StringFormat("SELECT BotGroupId FROM vwBotGroups " - "WHERE BotGroupName = '%s'", botGroupName.c_str()); - auto results = database.QueryDatabase(query); - if (!results.Success() || results.RowCount() == 0) - return false; - - for(auto row = results.begin(); row != results.end(); ++row) { - uint32 tempBotGroupId = atoi(row[0]); - std::string tempBotGroupName = std::string(row[1]); - - if (botGroupName == tempBotGroupName && tempBotGroupId != 0) - return true; - } - - return false; -} - -uint32 Bot::CanLoadBotGroup(uint32 botOwnerCharacterId, std::string botGroupName, std::string* errorMessage) { - - if(botOwnerCharacterId == 0 || botGroupName.empty()) - return 0; - - std::string query = StringFormat("SELECT BotGroupId, BotGroupName FROM vwBotGroups " - "WHERE BotOwnerCharacterId = %u", botOwnerCharacterId); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return 0; - } - - if(results.RowCount() == 0) - return 0; - - for(auto row = results.begin(); row != results.end(); ++row) { - - uint32 tempBotGroupId = atoi(row[0]); - std::string tempBotGroupName = std::string(row[1]); - - if(botGroupName == tempBotGroupName) - return tempBotGroupId; - } - - return 0; -} - -uint32 Bot::GetBotGroupIdByBotGroupName(std::string botGroupName, std::string* errorMessage) { - - if(botGroupName.empty()) - return 0; - - std::string query = StringFormat("SELECT BotGroupId FROM vwBotGroups " - "WHERE BotGroupName = '%s'", botGroupName.c_str()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return 0; - } - - if (results.RowCount() == 0) - return 0; - - auto row = results.begin(); - return atoi(row[0]); -} - -uint32 Bot::GetBotGroupLeaderIdByBotGroupName(std::string botGroupName) { - - if(botGroupName.empty()) - return 0; - - std::string query = StringFormat("SELECT BotGroupLeaderBotId FROM vwBotGroups WHERE BotGroupName = '%s'", botGroupName.c_str()); - auto results = database.QueryDatabase(query); - if (!results.Success() || results.RowCount() == 0) - return 0; - - auto row = results.begin(); - return atoi(row[0]); -} - -uint32 Bot::AllowedBotSpawns(uint32 botOwnerCharacterID, std::string* errorMessage) { - - if(botOwnerCharacterID == 0) - return 0; - - std::string query = StringFormat("SELECT value FROM quest_globals " - "WHERE name = 'bot_spawn_limit' AND charid = %i", - botOwnerCharacterID); - auto results = database.QueryDatabase(query); - if (!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return 0; - } - - if (results.RowCount() != 1) - return 0; - - auto row = results.begin(); - return atoi(row[0]); -} - -uint32 Bot::SpawnedBotCount(uint32 botOwnerCharacterID, std::string* errorMessage) { +uint32 Bot::SpawnedBotCount(uint32 botOwnerCharacterID) { uint32 Result = 0; - if(botOwnerCharacterID > 0) { std::list SpawnedBots = entity_list.GetBotsByBotOwnerCharacterID(botOwnerCharacterID); - Result = SpawnedBots.size(); } - return Result; } -uint32 Bot::CreatedBotCount(uint32 botOwnerCharacterID, std::string* errorMessage) { - - if(botOwnerCharacterID == 0) - return 0; - - std::string query = StringFormat("SELECT COUNT(BotID) FROM bots " - "WHERE BotOwnerCharacterID=%i", botOwnerCharacterID); - auto results = database.QueryDatabase(query); - if (!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return 0; - } - - if (results.RowCount() != 1) - return 0; - - auto row = results.begin(); - return atoi(row[0]); -} - -uint32 Bot::GetBotOwnerCharacterID(uint32 botID, std::string* errorMessage) { - - if(botID == 0) - return 0; - - std::string query = StringFormat("SELECT BotOwnerCharacterID FROM bots WHERE BotID = %u", botID); - auto results = database.QueryDatabase(query); - if (!results.Success()) { - *errorMessage = std::string(results.ErrorMessage()); - return 0; - } - - if (results.RowCount() != 1) - return 0; - - auto row = results.begin(); - return atoi(row[0]); -} - void Bot::LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp) { // This essentially performs a '#bot update,' with appearance packets, based on the current methods. // This should not be called outside of Client::SetEXP() due to it's lack of rule checks. @@ -5069,9 +3226,8 @@ void Bot::SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 // Returns the item id that is in the bot inventory collection for the specified slot. ItemInst* Bot::GetBotItem(uint32 slotID) { ItemInst* item = m_inv.GetItem(slotID); - if(item){ + if(item) return item; - } return nullptr; } @@ -5081,7 +3237,7 @@ void Bot::BotAddEquipItem(int slot, uint32 id) { if(slot > 0 && id > 0) { uint8 materialFromSlot = Inventory::CalcMaterialFromSlot(slot); - if(materialFromSlot != _MaterialInvalid) { + if (materialFromSlot != EQEmu::textures::TextureInvalid) { equipment[slot] = id; // npc has more than just material slots. Valid material should mean valid inventory index SendWearChange(materialFromSlot); } @@ -5097,11 +3253,11 @@ void Bot::BotRemoveEquipItem(int slot) { if(slot > 0) { uint8 materialFromSlot = Inventory::CalcMaterialFromSlot(slot); - if(materialFromSlot != _MaterialInvalid) { + if (materialFromSlot != EQEmu::textures::TextureInvalid) { equipment[slot] = 0; // npc has more than just material slots. Valid material should mean valid inventory index SendWearChange(materialFromSlot); - if(materialFromSlot == MaterialChest) - SendWearChange(MaterialArms); + if (materialFromSlot == EQEmu::textures::TextureChest) + SendWearChange(EQEmu::textures::TextureArms); } UpdateEquipmentLight(); @@ -5133,208 +3289,52 @@ void Bot::BotTradeSwapItem(Client* client, int16 lootSlot, const ItemInst* inst, } } -void Bot::BotTradeAddItem(uint32 id, const ItemInst* inst, int16 charges, uint32 equipableSlots, uint16 lootSlot, std::string* errorMessage, bool addToDb) { +void Bot::BotTradeAddItem(uint32 id, const ItemInst* inst, int16 charges, uint32 equipableSlots, uint16 lootSlot, std::string* errorMessage, bool addToDb) +{ if(addToDb) { - this->SetBotItemInSlot(lootSlot, id, inst, errorMessage); - if(!errorMessage->empty()) + if (!botdb.SaveItemBySlot(this, lootSlot, inst)) { + *errorMessage = BotDatabase::fail::SaveItemBySlot(); return; + } + m_inv.PutItem(lootSlot, *inst); } this->BotAddEquipItem(lootSlot, id); } -bool Bot::Bot_Command_Resist(int resisttype, int level) { - int resistid = 0; - switch(resisttype) { - case 1: // Poison Cleric - if(level >= 30) { - resistid = 62; - } - else if(level >= 6) { - resistid = 227; - } - break; - case 2: // Disease Cleric - if(level >= 36) { - resistid = 63; - } - else if(level >= 11) { - resistid = 226; - } - break; - case 3: // Fire Cleric - if(level >= 33) { - resistid = 60; - } - else if(level >= 8) { - resistid = 224; - } - break; - case 4: // Cold Cleric - if(level >= 38) { - resistid = 61; - } - else if(level >= 13) { - resistid = 225; - } - break; - case 5: // Magic Cleric - if(level >= 43) { - resistid = 64; - } - else if(level >= 16) { - resistid = 228; - } - break; - case 6: // Magic Enchanter - if(level >= 37) { - resistid = 64; - } - else if(level >= 17) { - resistid = 228; - } - break; - case 7: // Poison Druid - if(level >= 44) { - resistid = 62; - } - else if(level >= 19) { - resistid = 227; - } - break; - case 8: // Disease Druid - if(level >= 44) { - resistid = 63; - } - else if(level >= 19) { - resistid = 226; - } - break; - case 9: // Fire Druid - if(level >= 20) { - resistid = 60; - } - else if(level >= 1) { - resistid = 224; - } - break; - case 10: // Cold Druid - if(level >= 30) { - resistid = 61; - } - else if(level >= 9) { - resistid = 225; - } - break; - case 11: // Magic Druid - if(level >= 49) { - resistid = 64; - } - else if(level >= 34) { - resistid = 228; - } - break; - case 12: // Poison Shaman - if(level >= 35) { - resistid = 62; - } - else if(level >= 20) { - resistid = 227; - } - break; - case 13: // Disease Shaman - if(level >= 30) { - resistid = 63; - } - else if(level >= 8) { - resistid = 226; - } - break; - case 14: // Fire Shaman - if(level >= 27) { - resistid = 60; - } - else if(level >= 5) { - resistid = 224; - } - break; - case 15: // Cold Shaman - if(level >= 24) { - resistid = 61; - } - else if(level >= 1) { - resistid = 225; - } - break; - case 16: // Magic Shaman - if(level >= 43) { - resistid = 64; - } - else if(level >= 19) { - resistid = 228; - } - break; - } - - if(resistid > 0) { - Group* g = GetGroup(); - if(g) { - for(int k=0; kmembers[k]) { - SpellOnTarget(resistid, g->members[k]); - } - } - return true; - } - } - - return false; -} - bool Bot::RemoveBotFromGroup(Bot* bot, Group* group) { bool Result = false; - if(bot && group) { if(bot->HasGroup()) { if(!group->IsLeader(bot)) { bot->SetFollowID(0); - if(group->DelMember(bot)) database.SetGroupID(bot->GetCleanName(), 0, bot->GetBotID()); - - if(group->GroupCount() <= 1 && ZoneLoaded) - group->DisbandGroup(); - } - else { + } else { for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { if(!group->members[i]) continue; group->members[i]->SetFollowID(0); } - group->DisbandGroup(); database.SetGroupID(bot->GetCleanName(), 0, bot->GetBotID()); } - Result = true; } } - return Result; } bool Bot::AddBotToGroup(Bot* bot, Group* group) { bool Result = false; - if(bot && group) { if(!bot->HasGroup()) { // Add bot to this group if(group->AddMember(bot)) { if(group->GetLeader()) { bot->SetFollowID(group->GetLeader()->GetID()); - // Need to send this only once when a group is formed with a bot so the client knows it is also the group leader if(group->GroupCount() == 2 && group->GetLeader()->IsClient()) { group->UpdateGroupAAs(); @@ -5342,310 +3342,25 @@ bool Bot::AddBotToGroup(Bot* bot, Group* group) { group->SendUpdate(groupActUpdate, TempLeader); } } - Result = true; } } } - return Result; } -bool Bot::BotGroupCreate(std::string botGroupLeaderName) { - bool Result = false; - - if(!botGroupLeaderName.empty()) { - Bot* botGroupLeader = entity_list.GetBotByBotName(botGroupLeaderName); - - if(botGroupLeader) - Result = BotGroupCreate(botGroupLeader); - } - - return Result; -} - -bool Bot::BotGroupCreate(Bot* botGroupLeader) { - bool Result = false; - - if(botGroupLeader && !botGroupLeader->HasGroup()) { - Group* newGroup = new Group(botGroupLeader); - - if(newGroup) { - entity_list.AddGroup(newGroup); - database.SetGroupID(botGroupLeader->GetName(), newGroup->GetID(), botGroupLeader->GetBotID()); - database.SetGroupLeaderName(newGroup->GetID(), botGroupLeader->GetName()); - - botGroupLeader->SetFollowID(botGroupLeader->GetBotOwner()->GetID()); - - Result = true; - } - } - - return Result; -} - -bool Bot::Bot_Command_CharmTarget(int charmtype, Mob *target) { - int charmid = 0; - int charmlevel = GetLevel(); - if(target) { - switch(charmtype) { - case 1: // Enchanter - if((charmlevel >= 64) && (charmlevel <= 75)) { - charmid = 3355; - } - else if((charmlevel >= 62) && (charmlevel <= 63)) { - charmid = 3347; - } - else if((charmlevel >= 60) && (charmlevel <= 61)) { - charmid = 1707; - } - else if((charmlevel >= 53) && (charmlevel <= 59)) { - charmid = 1705; - } - else if((charmlevel >= 37) && (charmlevel <= 52)) { - charmid = 183; - } - else if((charmlevel >= 23) && (charmlevel <= 36)) { - charmid = 182; - } - else if((charmlevel >= 11) && (charmlevel <= 22)) { - charmid = 300; - } - break; - case 2: // Necromancer - if((charmlevel >= 60) && (charmlevel <= 75)) { - charmid = 1629; - } - else if((charmlevel >=47) && (charmlevel <= 59)) { - charmid = 198; - } - else if((charmlevel >= 31) && (charmlevel <= 46)) { - charmid = 197; - } - else if((charmlevel >= 18) && (charmlevel <= 30)) { - charmid = 196; - } - break; - case 3: // Druid - if((charmlevel >= 63) && (charmlevel <= 75)) { - charmid = 3445; - } - else if((charmlevel >= 55) && (charmlevel <= 62)) { - charmid = 1556; - } - else if((charmlevel >= 52) && (charmlevel <= 54)) { - charmid = 1553; - } - else if((charmlevel >= 43) && (charmlevel <= 51)) { - charmid = 142; - } - else if((charmlevel >= 33) && (charmlevel <= 42)) { - charmid = 141; - } - else if((charmlevel >= 23) && (charmlevel <= 32)) { - charmid = 260; - } - else if((charmlevel >= 13) && (charmlevel <= 22)) { - charmid = 242; - } - break; - } - if(charmid > 0) { - uint32 DontRootMeBeforeTime = 0; - CastSpell(charmid, target->GetID(), 1, -1, -1, &DontRootMeBeforeTime); - target->SetDontRootMeBefore(DontRootMeBeforeTime); - return true; - } - } - return false; -} - -bool Bot::Bot_Command_DireTarget(int diretype, Mob *target) { - int direid = 0; - int direlevel = GetLevel(); - if(target) { - switch(diretype) { - case 1: // Enchanter - if(direlevel >= 65) { - direid = 5874; - } - else if(direlevel >= 55) { - direid = 2761; - } - break; - case 2: // Necromancer - if(direlevel >= 65) { - direid = 5876; - } - else if(direlevel >= 55) { - direid = 2759; - } - break; - case 3: // Druid - if(direlevel >= 65) { - direid = 5875; - } - else if(direlevel >= 55) { - direid = 2760; - } - break; - } - if(direid > 0) { - uint32 DontRootMeBeforeTime = 0; - CastSpell(direid, target->GetID(), 1, -1, -1, &DontRootMeBeforeTime); - target->SetDontRootMeBefore(DontRootMeBeforeTime); - return true; - } - } - return false; -} - -bool Bot::Bot_Command_CalmTarget(Mob *target) { - if(target) { - int calmid = 0; - int calmlevel = GetLevel(); - if((calmlevel >= 67) && (calmlevel <= 75)) { - calmid = 5274; - } - else if((calmlevel >= 62) && (calmlevel <= 66)) { - calmid = 3197; - } - else if((calmlevel >= 35) && (calmlevel <= 61)) { - calmid = 45; - } - else if((calmlevel >= 18) && (calmlevel <= 34)) { - calmid = 47; - } - else if((calmlevel >= 6) && (calmlevel <= 17)) { - calmid = 501; - } - else if((calmlevel >= 1) && (calmlevel <= 5)) { - calmid = 208; - } - if(calmid > 0) { - uint32 DontRootMeBeforeTime = 0; - CastSpell(calmid, target->GetID(), 1, -1, -1, &DontRootMeBeforeTime); - target->SetDontRootMeBefore(DontRootMeBeforeTime); - return true; - } - } - return false; -} - -bool Bot::Bot_Command_RezzTarget(Mob *target) { - if(target) { - int rezid = 0; - int rezlevel = GetLevel(); - if(rezlevel >= 56) { - rezid = 1524; - } - else if(rezlevel >= 47) { - rezid = 392; - } - else if(rezlevel >= 42) { - rezid = 2172; - } - else if(rezlevel >= 37) { - rezid = 388; - } - else if(rezlevel >= 32) { - rezid = 2171; - } - else if(rezlevel >= 27) { - rezid = 391; - } - else if(rezlevel >= 22) { - rezid = 2170; - } - else if(rezlevel >= 18) { - rezid = 2169; - } - if(rezid > 0) { - uint32 DontRootMeBeforeTime = 0; - CastSpell(rezid, target->GetID(), 1, -1, -1, &DontRootMeBeforeTime); - target->SetDontRootMeBefore(DontRootMeBeforeTime); - return true; - } - } - return false; -} - -bool Bot::Bot_Command_Cure(int curetype, int level) { - int cureid = 0; - switch(curetype) { - case 1: // Poison - if(level >= 58) { - cureid = 1525; - } - else if(level >= 48) { - cureid = 97; - } - else if(level >= 22) { - cureid = 95; - } - else if(level >= 1) { - cureid = 203; - } - break; - case 2: // Disease - if(level >= 51) { - cureid = 3693; - } - else if(level >= 28) { - cureid = 96; - } - else if(level >= 4) { - cureid = 213; - } - break; - case 3: // Curse - if(level >= 54) { - cureid = 2880; - } - else if(level >= 38) { - cureid = 2946; - } - else if(level >= 23) { - cureid = 4057; - } - else if(level >= 8) { - cureid = 4056; - } - break; - case 4: // Blindness - if(level >= 3) { - cureid = 212; - } - break; - } - - if(cureid > 0) { - Group* g = GetGroup(); - if(g) { - for(int k=0; kmembers[k]) { - SpellOnTarget(cureid, g->members[k]); - } - } - return true; - } - } - - return false; -} - // Completes a trade with a client bot owner void Bot::FinishTrade(Client* client, BotTradeType tradeType) { if(client && !client->GetTradeskillObject() && (client->trade->state != Trading)) { if(tradeType == BotTradeClientNormal) { // Items being traded are found in the normal trade window used to trade between a Client and a Client or NPC // Items in this mode are found in slot ids 3000 thru 3003 - thought bots used the full 8-slot window..? - PerformTradeWithClient(EmuConstants::TRADE_BEGIN, EmuConstants::TRADE_END, client); // {3000..3007} + PerformTradeWithClient(EQEmu::legacy::TRADE_BEGIN, EQEmu::legacy::TRADE_END, client); // {3000..3007} } else if(tradeType == BotTradeClientNoDropNoTrade) { // Items being traded are found on the Client's cursor slot, slot id 30. This item can be either a single item or it can be a bag. // If it is a bag, then we have to search for items in slots 331 thru 340 - PerformTradeWithClient(MainCursor, MainCursor, client); + PerformTradeWithClient(EQEmu::legacy::SlotCursor, EQEmu::legacy::SlotCursor, client); // TODO: Add logic here to test if the item in SLOT_CURSOR is a container type, if it is then we need to call the following: // PerformTradeWithClient(331, 340, client); @@ -5657,12 +3372,12 @@ void Bot::FinishTrade(Client* client, BotTradeType tradeType) { void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* client) { if(client) { // TODO: Figure out what the actual max slot id is - const int MAX_SLOT_ID = EmuConstants::TRADE_BAGS_END; // was the old incorrect 3179.. + const int MAX_SLOT_ID = EQEmu::legacy::TRADE_BAGS_END; // was the old incorrect 3179.. uint32 items[MAX_SLOT_ID] = {0}; uint8 charges[MAX_SLOT_ID] = {0}; bool botCanWear[MAX_SLOT_ID] = {0}; - for(int16 i=beginSlotID; i<=endSlotID; ++i) { + for(int16 i = beginSlotID; i <= endSlotID; ++i) { bool BotCanWear = false; bool UpdateClient = false; bool already_returned = false; @@ -5674,15 +3389,15 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli charges[i] = inst->GetCharges(); } - if (i == MainCursor) + if (i == EQEmu::legacy::SlotCursor) UpdateClient = true; //EQoffline: will give the items to the bots and change the bot stats if(inst && (GetBotOwner() == client->CastToMob()) && !IsEngaged()) { std::string TempErrorMessage; - const Item_Struct* mWeaponItem = inst->GetItem(); + const EQEmu::ItemBase* mWeaponItem = inst->GetItem(); bool failedLoreCheck = false; - for (int m = AUG_BEGIN; m GetAugment(m); if(itm) { @@ -5702,26 +3417,29 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli botCanWear[i] = BotCanWear; ItemInst* swap_item = nullptr; - const char* equipped[EmuConstants::EQUIPMENT_SIZE] = {"Charm", "Left Ear", "Head", "Face", "Right Ear", "Neck", "Shoulders", "Arms", "Back", + const char* equipped[EQEmu::legacy::EQUIPMENT_SIZE + 1] = { "Charm", "Left Ear", "Head", "Face", "Right Ear", "Neck", "Shoulders", "Arms", "Back", "Left Wrist", "Right Wrist", "Range", "Hands", "Primary Hand", "Secondary Hand", - "Left Finger", "Right Finger", "Chest", "Legs", "Feet", "Waist", "Ammo" }; + "Left Finger", "Right Finger", "Chest", "Legs", "Feet", "Waist", "Ammo", "Powersource" }; bool success = false; int how_many_slots = 0; - for(int j = EmuConstants::EQUIPMENT_BEGIN; j <= EmuConstants::EQUIPMENT_END; ++j) { + for (int j = EQEmu::legacy::EQUIPMENT_BEGIN; j <= (EQEmu::legacy::EQUIPMENT_END + 1); ++j) { if((mWeaponItem->Slots & (1 << j))) { + if (j == 22) + j = 9999; + how_many_slots++; if(!GetBotItem(j)) { - if(j == MainPrimary) { - if((mWeaponItem->ItemType == ItemType2HSlash) || (mWeaponItem->ItemType == ItemType2HBlunt) || (mWeaponItem->ItemType == ItemType2HPiercing)) { - if(GetBotItem(MainSecondary)) { - if(mWeaponItem && (mWeaponItem->ItemType == ItemType2HSlash) || (mWeaponItem->ItemType == ItemType2HBlunt) || (mWeaponItem->ItemType == ItemType2HPiercing)) { - if(client->CheckLoreConflict(GetBotItem(MainSecondary)->GetItem())) { + if (j == EQEmu::legacy::SlotPrimary) { + if (mWeaponItem->IsType2HWeapon()) { + if (GetBotItem(EQEmu::legacy::SlotSecondary)) { + if (mWeaponItem && mWeaponItem->IsType2HWeapon()) { + if (client->CheckLoreConflict(GetBotItem(EQEmu::legacy::SlotSecondary)->GetItem())) { failedLoreCheck = true; } } else { - ItemInst* remove_item = GetBotItem(MainSecondary); - BotTradeSwapItem(client, MainSecondary, 0, remove_item, remove_item->GetItem()->Slots, &TempErrorMessage, false); + ItemInst* remove_item = GetBotItem(EQEmu::legacy::SlotSecondary); + BotTradeSwapItem(client, EQEmu::legacy::SlotSecondary, 0, remove_item, remove_item->GetItem()->Slots, &TempErrorMessage, false); } } } @@ -5731,14 +3449,14 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli } break; } - else if(j == MainSecondary) { + else if (j == EQEmu::legacy::SlotSecondary) { if(inst->IsWeapon()) { if(CanThisClassDualWield()) { BotTradeAddItem(mWeaponItem->ID, inst, inst->GetCharges(), mWeaponItem->Slots, j, &TempErrorMessage); success = true; } else { - Say("I can't Dual Wield yet."); + BotGroupSay(this, "I can't Dual Wield yet."); --how_many_slots; } } @@ -5747,10 +3465,10 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli success = true; } if(success) { - if(GetBotItem(MainPrimary)) { - ItemInst* remove_item = GetBotItem(MainPrimary); - if((remove_item->GetItem()->ItemType == ItemType2HSlash) || (remove_item->GetItem()->ItemType == ItemType2HBlunt) || (remove_item->GetItem()->ItemType == ItemType2HPiercing)) { - BotTradeSwapItem(client, MainPrimary, 0, remove_item, remove_item->GetItem()->Slots, &TempErrorMessage, false); + if (GetBotItem(EQEmu::legacy::SlotPrimary)) { + ItemInst* remove_item = GetBotItem(EQEmu::legacy::SlotPrimary); + if (remove_item->GetItem()->IsType2HWeapon()) { + BotTradeSwapItem(client, EQEmu::legacy::SlotPrimary, 0, remove_item, remove_item->GetItem()->Slots, &TempErrorMessage, false); } } break; @@ -5765,11 +3483,14 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli } } if(!success) { - for(int j = EmuConstants::EQUIPMENT_BEGIN; j <= EmuConstants::EQUIPMENT_END; ++j) { + for (int j = EQEmu::legacy::EQUIPMENT_BEGIN; j <= (EQEmu::legacy::EQUIPMENT_END + 1); ++j) { if((mWeaponItem->Slots & (1 << j))) { + if (j == 22) + j = 9999; + swap_item = GetBotItem(j); failedLoreCheck = false; - for (int k = AUG_BEGIN; k < EmuConstants::ITEM_COMMON_SIZE; ++k) { + for (int k = AUG_INDEX_BEGIN; k < EQEmu::legacy::ITEM_COMMON_SIZE; ++k) { ItemInst *itm = swap_item->GetAugment(k); if(itm) { @@ -5782,43 +3503,43 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli failedLoreCheck = true; } if(!failedLoreCheck) { - if(j == MainPrimary) { - if((mWeaponItem->ItemType == ItemType2HSlash) || (mWeaponItem->ItemType == ItemType2HBlunt) || (mWeaponItem->ItemType == ItemType2HPiercing)) { - if(GetBotItem(MainSecondary)) { - if(client->CheckLoreConflict(GetBotItem(MainSecondary)->GetItem())) { + if (j == EQEmu::legacy::SlotPrimary) { + if (mWeaponItem->IsType2HWeapon()) { + if (GetBotItem(EQEmu::legacy::SlotSecondary)) { + if (client->CheckLoreConflict(GetBotItem(EQEmu::legacy::SlotSecondary)->GetItem())) { failedLoreCheck = true; } else { - ItemInst* remove_item = GetBotItem(MainSecondary); - BotTradeSwapItem(client, MainSecondary, 0, remove_item, remove_item->GetItem()->Slots, &TempErrorMessage, false); + ItemInst* remove_item = GetBotItem(EQEmu::legacy::SlotSecondary); + BotTradeSwapItem(client, EQEmu::legacy::SlotSecondary, 0, remove_item, remove_item->GetItem()->Slots, &TempErrorMessage, false); } } } if(!failedLoreCheck) { - BotTradeSwapItem(client, MainPrimary, inst, swap_item, mWeaponItem->Slots, &TempErrorMessage); + BotTradeSwapItem(client, EQEmu::legacy::SlotPrimary, inst, swap_item, mWeaponItem->Slots, &TempErrorMessage); success = true; } break; } - else if(j == MainSecondary) { + else if (j == EQEmu::legacy::SlotSecondary) { if(inst->IsWeapon()) { if(CanThisClassDualWield()) { - BotTradeSwapItem(client, MainSecondary, inst, swap_item, mWeaponItem->Slots, &TempErrorMessage); + BotTradeSwapItem(client, EQEmu::legacy::SlotSecondary, inst, swap_item, mWeaponItem->Slots, &TempErrorMessage); success = true; } else { botCanWear[i] = false; - Say("I can't Dual Wield yet."); + BotGroupSay(this, "I can't Dual Wield yet."); } } else { - BotTradeSwapItem(client, MainSecondary, inst, swap_item, mWeaponItem->Slots, &TempErrorMessage); + BotTradeSwapItem(client, EQEmu::legacy::SlotSecondary, inst, swap_item, mWeaponItem->Slots, &TempErrorMessage); success = true; } - if(success && GetBotItem(MainPrimary)) { - ItemInst* remove_item = GetBotItem(MainPrimary); - if((remove_item->GetItem()->ItemType == ItemType2HSlash) || (remove_item->GetItem()->ItemType == ItemType2HBlunt) || (remove_item->GetItem()->ItemType == ItemType2HPiercing)) { - BotTradeSwapItem(client, MainPrimary, 0, remove_item, remove_item->GetItem()->Slots, &TempErrorMessage, false); + if (success && GetBotItem(EQEmu::legacy::SlotPrimary)) { + ItemInst* remove_item = GetBotItem(EQEmu::legacy::SlotPrimary); + if (remove_item->GetItem()->IsType2HWeapon()) { + BotTradeSwapItem(client, EQEmu::legacy::SlotPrimary, 0, remove_item, remove_item->GetItem()->Slots, &TempErrorMessage, false); } } break; @@ -5846,71 +3567,71 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli } } if(inst) { + client->DeleteItemInInventory(i, 0, UpdateClient); if(!botCanWear[i]) { client->PushItemOnCursor(*inst, true); } - client->DeleteItemInInventory(i, 0, UpdateClient); } } - const Item_Struct* item2 = 0; - for(int y=beginSlotID; y<=endSlotID; ++y) { + const EQEmu::ItemBase* item2 = 0; + for(int y = beginSlotID; y <= endSlotID; ++y) { item2 = database.GetItem(items[y]); if(item2) { if(botCanWear[y]) { - Say("Thank you for the %s, %s.", item2->Name, client->GetName()); + BotGroupSay(this, "Thank you for the %s, %s!", item2->Name, client->GetName()); } else { - Say("I can't use this %s!", item2->Name); + BotGroupSay(this, "I can't use this %s!", item2->Name); } } } } } -bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) { +bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { if(!NPC::Death(killerMob, damage, spell_id, attack_skill)) return false; Save(); - Mob *give_exp = hate_list.GetDamageTopOnHateList(this); Client *give_exp_client = nullptr; - if(give_exp && give_exp->IsClient()) give_exp_client = give_exp->CastToClient(); bool IsLdonTreasure = (this->GetClass() == LDON_TREASURE); - if(entity_list.GetCorpseByID(GetID())) entity_list.GetCorpseByID(GetID())->Depop(); Group *g = GetGroup(); if(g) { - for(int i=0; imembers[i]) { if(g->members[i] == this) { // If the leader dies, make the next bot the leader // and reset all bots followid if(g->IsLeader(g->members[i])) { - if(g->members[i+1]) { - g->SetLeader(g->members[i+1]); - g->members[i+1]->SetFollowID(g->members[i]->GetFollowID()); - for(int j=0; jmembers[j] && (g->members[j] != g->members[i+1])) { - g->members[j]->SetFollowID(g->members[i+1]->GetID()); - } + if(g->members[i + 1]) { + g->SetLeader(g->members[i + 1]); + g->members[i + 1]->SetFollowID(g->members[i]->GetFollowID()); + for(int j = 0; j < MAX_GROUP_MEMBERS; j++) { + if(g->members[j] && (g->members[j] != g->members[i + 1])) + g->members[j]->SetFollowID(g->members[i + 1]->GetID()); } } } // delete from group data RemoveBotFromGroup(this, g); + //Make sure group still exists if it doesnt they were already updated in RemoveBotFromGroup + g = GetGroup(); + if (!g) + break; // if group members exist below this one, move // them all up one slot in the group list - int j = i+1; - for(; jmembers[j]) { g->members[j-1] = g->members[j]; strcpy(g->membername[j-1], g->members[j]->GetCleanName()); @@ -5926,55 +3647,25 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, SkillUseTypes att gu->action = groupActLeave; strcpy(gu->membername, GetCleanName()); if(g) { - for(int k=0; kmembers[k] && g->members[k]->IsClient()) g->members[k]->CastToClient()->QueuePacket(outapp); } } safe_delete(outapp); - - // now that's done, lets see if all we have left is the client - // and we can clean up the clients raid group and group - /*if(GetBotRaidID()) { - BotRaids* br = entity_list.GetBotRaidByMob(this); - if(br) { - if(this == br->botmaintank) { - br->botmaintank = nullptr; - } - if(this == br->botsecondtank) { - br->botsecondtank = nullptr; - } - } - if(g->GroupCount() == 0) { - uint32 gid = g->GetID(); - if(br) { - br->RemoveEmptyBotGroup(); - } - entity_list.RemoveGroup(gid); - } - if(br && (br->RaidBotGroupsCount() == 1)) { - br->RemoveClientGroup(br->GetRaidBotLeader()); - } - if(br && (br->RaidBotGroupsCount() == 0)) { - br->DisbandBotRaid(); - } - }*/ } } } } - if(GetInHealRotation()) { - GetHealRotationLeader()->RemoveHealRotationMember(this); - } + LeaveHealRotationMemberPool(); entity_list.RemoveBot(this->GetID()); - return true; } -void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable, int8 buffslot, bool iBuffTic) { - if(spell_id==0) +void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, int special) { + if(spell_id == 0) spell_id = SPELL_UNKNOWN; //handle EVENT_ATTACK. Resets after we have not been attacked for 12 seconds @@ -5984,11 +3675,6 @@ void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, SkillUseTypes attack_ } attacked_timer.Start(CombatEventTimer_expire); - - // TODO: A bot doesnt call this, right? - /*if (!IsEngaged()) - zone->AddAggroMob();*/ - // if spell is lifetap add hp to the caster if (spell_id != SPELL_UNKNOWN && IsLifetapSpell(spell_id)) { int healed = GetActSpellHealing(spell_id, damage); @@ -5997,8 +3683,7 @@ void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, SkillUseTypes attack_ entity_list.MessageClose(this, true, 300, MT_Spells, "%s beams a smile at %s", GetCleanName(), from->GetCleanName() ); } - CommonDamage(from, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic); - + CommonDamage(from, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic, special); if(GetHP() < 0) { if(IsCasting()) InterruptSpell(); @@ -6006,35 +3691,26 @@ void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, SkillUseTypes attack_ } SendHPUpdate(); - - if(this == from) { + if(this == from) return; - } // Aggro the bot's group members - if(IsGrouped()) - { + if(IsGrouped()) { Group *g = GetGroup(); - if(g) - { - for(int i=0; imembers[i] && g->members[i]->IsBot() && from && !g->members[i]->CheckAggro(from) && g->members[i]->IsAttackAllowed(from)) - { g->members[i]->AddToHateList(from, 1); - } } } } } -void Bot::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/) -{ +void Bot::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/) { Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, iBuffTic); } -bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) -{ +bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, int special) { if (!other) { SetTarget(nullptr); Log.Out(Logs::General, Logs::Error, "A null Mob object was passed to Bot::Attack for evaluation!"); @@ -6045,15 +3721,10 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b SetTarget(other); Log.Out(Logs::Detail, Logs::Combat, "Attacking %s with hand %d %s", other?other->GetCleanName():"(nullptr)", Hand, FromRiposte?"(this is a riposte)":""); - - if ((IsCasting() && (GetClass() != BARD) && !IsFromSpell) || - other == nullptr || - (GetHP() < 0) || - (GetAppearance() == eaDead) || - (!IsAttackAllowed(other))) - { + if ((IsCasting() && (GetClass() != BARD) && !IsFromSpell) || other == nullptr || (GetHP() < 0) || (GetAppearance() == eaDead) || (!IsAttackAllowed(other))) { if(this->GetOwnerID()) entity_list.MessageClose(this, 1, 200, 10, "%s says, '%s is not a legal target master.'", this->GetCleanName(), this->GetTarget()->GetCleanName()); + if(other) { RemoveFromHateList(other); Log.Out(Logs::Detail, Logs::Combat, "I am not allowed to attack %s", other->GetCleanName()); @@ -6066,69 +3737,61 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b return false; } - // TODO: Uncomment this block after solved the bug that is assigning a null value to GetTarget() for bots while in combat. Appears to happen at random, but frequently. - /*if(HasGroup() && _previousTarget != GetTarget()) { - std::ostringstream attackMessage; - attackMessage << "Attacking " << other->GetCleanName() << "."; - - GetGroup()->GroupMessage(this, 0, 100, attackMessage.str().c_str()); - }*/ - FaceTarget(GetTarget()); - ItemInst* weapon = nullptr; - if(Hand == MainPrimary) { - weapon = GetBotItem(MainPrimary); + if (Hand == EQEmu::legacy::SlotPrimary) { + weapon = GetBotItem(EQEmu::legacy::SlotPrimary); OffHandAtk(false); } - if(Hand == MainSecondary) { - weapon = GetBotItem(MainSecondary); + + if (Hand == EQEmu::legacy::SlotSecondary) { + weapon = GetBotItem(EQEmu::legacy::SlotSecondary); OffHandAtk(true); } if(weapon != nullptr) { if (!weapon->IsWeapon()) { Log.Out(Logs::Detail, Logs::Combat, "Attack canceled, Item %s (%d) is not a weapon.", weapon->GetItem()->Name, weapon->GetID()); - return(false); + return false; } Log.Out(Logs::Detail, Logs::Combat, "Attacking with weapon: %s (%d)", weapon->GetItem()->Name, weapon->GetID()); - } else { - Log.Out(Logs::Detail, Logs::Combat, "Attacking without a weapon."); } + else + Log.Out(Logs::Detail, Logs::Combat, "Attacking without a weapon."); // calculate attack_skill and skillinuse depending on hand and weapon // also send Packet to near clients - SkillUseTypes skillinuse; + EQEmu::skills::SkillType skillinuse; AttackAnimation(skillinuse, Hand, weapon); Log.Out(Logs::Detail, Logs::Combat, "Attacking with %s in slot %d using skill %d", weapon?weapon->GetItem()->Name:"Fist", Hand, skillinuse); - /// Now figure out damage int damage = 0; uint8 mylevel = GetLevel() ? GetLevel() : 1; uint32 hate = 0; - if (weapon) hate = weapon->GetItem()->Damage + weapon->GetItem()->ElemDmgAmt; + if (weapon) + hate = (weapon->GetItem()->Damage + weapon->GetItem()->ElemDmgAmt); + int weapon_damage = GetWeaponDamage(other, weapon, &hate); - if (hate == 0 && weapon_damage > 1) hate = weapon_damage; + if (hate == 0 && weapon_damage > 1) + hate = weapon_damage; //if weapon damage > 0 then we know we can hit the target with this weapon //otherwise we cannot and we set the damage to -5 later on - if(weapon_damage > 0){ - + if(weapon_damage > 0) { //Berserker Berserk damage bonus if(berserk && (GetClass() == BERSERKER)){ - int bonus = 3 + GetLevel()/10; //unverified - weapon_damage = weapon_damage * (100+bonus) / 100; + int bonus = (3 + GetLevel() / 10); //unverified + weapon_damage = (weapon_damage * (100 + bonus) / 100); Log.Out(Logs::Detail, Logs::Combat, "Berserker damage bonus increases DMG to %d", weapon_damage); } //try a finishing blow.. if successful end the attack - if(TryFinishingBlow(other, skillinuse)) { - return (true); - } + if(TryFinishingBlow(other, skillinuse)) + return true; //damage formula needs some work int min_hit = 1; - int max_hit = (2*weapon_damage*GetDamageTable(skillinuse)) / 100; + int max_hit = ((2 * weapon_damage * GetDamageTable(skillinuse)) / 100); if(GetLevel() < 10 && max_hit > RuleI(Combat, HitCapPre10)) max_hit = (RuleI(Combat, HitCapPre10)); @@ -6146,34 +3809,27 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b // // This is not recommended for normal usage, as the damage bonus represents a non-trivial component of the DPS output // of weapons wielded by higher-level melee characters (especially for two-handed weapons). - int ucDamageBonus = 0; - - if( Hand == MainPrimary && GetLevel() >= 28 && IsWarriorClass() ) - { + if (Hand == EQEmu::legacy::SlotPrimary && GetLevel() >= 28 && IsWarriorClass()) { // Damage bonuses apply only to hits from the main hand (Hand == MainPrimary) by characters level 28 and above // who belong to a melee class. If we're here, then all of these conditions apply. - - ucDamageBonus = GetWeaponDamageBonus( weapon ? weapon->GetItem() : (const Item_Struct*) nullptr ); - + ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQEmu::ItemBase*) nullptr); min_hit += (int) ucDamageBonus; max_hit += (int) ucDamageBonus; hate += ucDamageBonus; } #endif //Live AA - Sinister Strikes *Adds weapon damage bonus to offhand weapon. - if (Hand==MainSecondary) { + if (Hand == EQEmu::legacy::SlotSecondary) { if (aabonuses.SecondaryDmgInc || itembonuses.SecondaryDmgInc || spellbonuses.SecondaryDmgInc){ - - ucDamageBonus = GetWeaponDamageBonus( weapon ? weapon->GetItem() : (const Item_Struct*) nullptr ); - + ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQEmu::ItemBase*) nullptr); min_hit += (int) ucDamageBonus; max_hit += (int) ucDamageBonus; hate += ucDamageBonus; } } - min_hit = min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100; + min_hit = (min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100); if(max_hit < min_hit) max_hit = min_hit; @@ -6194,77 +3850,46 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b } //check to see if we hit.. - if(!other->CheckHitChance(other, skillinuse, Hand)) { - Log.Out(Logs::Detail, Logs::Combat, "Attack missed. Damage set to 0."); - damage = 0; - other->AddToHateList(this, 0); - } else { //we hit, try to avoid it - other->AvoidDamage(this, damage); - other->MeleeMitigation(this, damage, min_hit, opts); - if(damage > 0) { - ApplyMeleeDamageBonus(skillinuse, damage); - damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse); - TryCriticalHit(other, skillinuse, damage, opts); - Log.Out(Logs::Detail, Logs::Combat, "Generating hate %d towards %s", hate, GetCleanName()); - // now add done damage to the hate list - //other->AddToHateList(this, hate); - } - else - other->AddToHateList(this, 0); - Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage); - } - - //riposte - bool slippery_attack = false; // Part of hack to allow riposte to become a miss, but still allow a Strikethrough chance (like on Live) - if (damage == -3) { - if (FromRiposte) return false; - else { - if (Hand == MainSecondary) {// Do we even have it & was attack with mainhand? If not, don't bother with other calculations - //Live AA - SlipperyAttacks - //This spell effect most likely directly modifies the actual riposte chance when using offhand attack. - int32 OffhandRiposteFail = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail; - OffhandRiposteFail *= -1; //Live uses a negative value for this. - - if (OffhandRiposteFail && - (OffhandRiposteFail > 99 || (zone->random.Int(0, 100) < OffhandRiposteFail))) { - damage = 0; // Counts as a miss - slippery_attack = true; - } else - DoRiposte(other); - if (GetHP() < 0) return false; + if (other->AvoidDamage(this, damage, Hand)) { + if (!FromRiposte && !IsStrikethrough) { + int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; + if(strike_through && zone->random.Roll(strike_through)) { + Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses! + Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit + return false; } - else + if (damage == -3 && !FromRiposte) { DoRiposte(other); - if (GetHP() < 0) return false; - } - } - - if (((damage < 0) || slippery_attack) && !FromRiposte && !IsStrikethrough) { // Hack to still allow Strikethrough chance w/ Slippery Attacks AA - int32 bonusStrikeThrough = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; - - if(bonusStrikeThrough && (zone->random.Int(0, 100) < bonusStrikeThrough)) { - Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses! - Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit - return false; + if (HasDied()) + return false; + } + } + } else { + if (other->CheckHitChance(this, skillinuse, Hand)) { + other->MeleeMitigation(this, damage, min_hit, opts); + ApplyMeleeDamageBonus(skillinuse, damage); + damage += ((itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse)); + TryCriticalHit(other, skillinuse, damage, opts); + } else { + damage = 0; } } + Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage); } - else{ + else damage = -5; - } // Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same. // If we are this far, this means we are atleast making a swing. - if (!FromRiposte) {// Ripostes never generate any aggro. - other->AddToHateList(this, hate); - } + other->AddToHateList(this, hate); /////////////////////////////////////////////////////////// ////// Send Attack Damage /////////////////////////////////////////////////////////// other->Damage(this, damage, SPELL_UNKNOWN, skillinuse); - if (GetHP() < 0) return false; + if (GetHP() < 0) + return false; MeleeLifeTap(damage); @@ -6278,12 +3903,14 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b BuffFadeByEffect(SE_Invisibility2); invisible = false; } + if(invisible_undead) { Log.Out(Logs::Detail, Logs::Combat, "Removing invisibility vs. undead due to melee attack."); BuffFadeByEffect(SE_InvisVsUndead); BuffFadeByEffect(SE_InvisVsUndead2); invisible_undead = false; } + if(invisible_animals){ Log.Out(Logs::Detail, Logs::Combat, "Removing invisibility vs. animals due to melee attack."); BuffFadeByEffect(SE_InvisVsAnimals); @@ -6306,19 +3933,17 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b BuffFadeByEffect(SE_NegateIfCombat); if(GetTarget()) - TriggerDefensiveProcs(weapon, other, Hand, damage); + TriggerDefensiveProcs(other, Hand, true, damage); if (damage > 0) return true; - else return false; } -int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) +int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint32 points, uint16 spell_id) { const SPDat_Spell_Struct &spell = spells[spell_id]; - int32 value = 0; int lvlModifier = 100; int spell_level = 0; @@ -6329,116 +3954,100 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) int32 base1 = 0; int32 base2 = 0; uint32 slot = 0; - bool LimitFound = false; int FocusCount = 0; - std::map >::const_iterator find_iter = aa_effects.find(aa_ID); - if(find_iter == aa_effects.end()) - { + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa_ID, points); + auto ability = ability_rank.first; + auto rank = ability_rank.second; + + if(!ability) { return 0; } - for (std::map::const_iterator iter = aa_effects[aa_ID].begin(); iter != aa_effects[aa_ID].end(); ++iter) - { - effect = iter->second.skill_id; - base1 = iter->second.base1; - base2 = iter->second.base2; - slot = iter->second.slot; + for(auto &eff : rank->effects) { + effect = eff.effect_id; + base1 = eff.base1; + base2 = eff.base2; + slot = eff.slot; //AA Foci's can contain multiple focus effects within the same AA. //To handle this we will not automatically return zero if a limit is found. //Instead if limit is found and multiple effects, we will reset the limit check //when the next valid focus effect is found. - if (IsFocusEffect(0, 0, true,effect) || (effect == SE_TriggerOnCast)){ + if (IsFocusEffect(0, 0, true,effect) || (effect == SE_TriggerOnCast)) { FocusCount++; //If limit found on prior check next, else end loop. - if (FocusCount > 1){ - if (LimitFound){ + if (FocusCount > 1) { + if (LimitFound) { value = 0; LimitFound = false; } - - else{ + else break; - } } } - switch (effect) - { + switch (effect) { case SE_Blank: break; - - //Handle Focus Limits case SE_LimitResist: - if(base1) - { + if(base1) { if(spell.resisttype != base1) LimitFound = true; } - break; + break; case SE_LimitInstant: if(spell.buffduration) LimitFound = true; - break; + break; case SE_LimitMaxLevel: - spell_level = spell.classes[(GetClass()%16) - 1]; + spell_level = spell.classes[(GetClass() % 17) - 1]; lvldiff = spell_level - base1; //every level over cap reduces the effect by base2 percent unless from a clicky when ItemCastsUseFocus is true - if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)) - { - if(base2 > 0) - { - lvlModifier -= base2*lvldiff; + if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)) { + if(base2 > 0) { + lvlModifier -= (base2 * lvldiff); if(lvlModifier < 1) LimitFound = true; } - else { + else LimitFound = true; - } } - break; + break; case SE_LimitMinLevel: - if((spell.classes[(GetClass()%16) - 1]) < base1) + if((spell.classes[(GetClass() % 17) - 1]) < base1) LimitFound = true; - break; + break; case SE_LimitCastTimeMin: if (spell.cast_time < base1) LimitFound = true; - break; + break; case SE_LimitSpell: - // Exclude spell(any but this) if(base1 < 0) { if (spell_id == (base1*-1)) LimitFound = true; - } - else { - // Include Spell(only this) + } else { if (spell_id != base1) LimitFound = true; } - break; + break; case SE_LimitMinDur: if (base1 > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) LimitFound = true; - break; + break; case SE_LimitEffect: - // Exclude effect(any but this) if(base1 < 0) { if(IsEffectInSpell(spell_id,(base1*-1))) LimitFound = true; - } - else { - // Include effect(only this) + } else { if(!IsEffectInSpell(spell_id,base1)) LimitFound = true; } - break; + break; case SE_LimitSpellType: - switch(base1) - { + switch(base1) { case 0: if (!IsDetrimentalSpell(spell_id)) LimitFound = true; @@ -6448,130 +4057,93 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) LimitFound = true; break; } - break; + break; case SE_LimitManaMin: if(spell.mana < base1) LimitFound = true; - break; - + break; case SE_LimitTarget: - // Exclude - if(base1 < 0){ - if(-base1 == spell.targettype) - LimitFound = true; - } - // Include - else { - if(base1 != spell.targettype) - LimitFound = true; - } - break; - + if(base1 < 0) { + if(-base1 == spell.targettype) + LimitFound = true; + } else { + if(base1 != spell.targettype) + LimitFound = true; + } + break; case SE_LimitCombatSkills: - // 1 is for disciplines only - if(base1 == 1 && !IsDiscipline(spell_id)) - LimitFound = true; - // 0 is spells only - else if(base1 == 0 && IsDiscipline(spell_id)) + if((base1 == 1 && !IsDiscipline(spell_id)) || (base1 == 0 && IsDiscipline(spell_id))) LimitFound = true; break; - case SE_LimitSpellGroup: - if(base1 > 0 && base1 != spell.spellgroup) + if((base1 > 0 && base1 != spell.spellgroup) || (base1 < 0 && base1 == spell.spellgroup)) LimitFound = true; - else if(base1 < 0 && base1 == spell.spellgroup) - LimitFound = true; - break; - - + break; case SE_LimitCastingSkill: LimitSpellSkill = true; if(base1 == spell.skill) SpellSkill_Found = true; - break; - + break; case SE_LimitClass: //Do not use this limit more then once per spell. If multiple class, treat value like items would. - if (!PassLimitClass(base1, GetClass())) - LimitFound = true; - break; - - + if (!PassLimitClass(base1, GetClass())) + LimitFound = true; + break; //Handle Focus Effects case SE_ImprovedDamage: if (type == focusImprovedDamage && base1 > value) value = base1; - break; - + break; case SE_ImprovedHeal: if (type == focusImprovedHeal && base1 > value) value = base1; - break; - + break; case SE_ReduceManaCost: - if (type == focusManaCost ) + if (type == focusManaCost) value = base1; - break; - + break; case SE_IncreaseSpellHaste: if (type == focusSpellHaste && base1 > value) value = base1; break; - case SE_IncreaseSpellDuration: if (type == focusSpellDuration && base1 > value) value = base1; break; - case SE_SpellDurationIncByTic: if (type == focusSpellDurByTic && base1 > value) value = base1; break; - case SE_SwarmPetDuration: if (type == focusSwarmPetDuration && base1 > value) value = base1; break; - case SE_IncreaseRange: if (type == focusRange && base1 > value) value = base1; break; - case SE_ReduceReagentCost: if (type == focusReagentCost && base1 > value) value = base1; break; - case SE_PetPowerIncrease: if (type == focusPetPower && base1 > value) value = base1; break; - case SE_SpellResistReduction: if (type == focusResistRate && base1 > value) value = base1; break; - case SE_SpellHateMod: - if (type == focusSpellHateMod) - { - if(value != 0) - { - if(value > 0) - { + if (type == focusSpellHateMod) { + if(value != 0) { + if(value > 0) { if(base1 > value) - { value = base1; - } - } - else - { + } else { if(base1 < value) - { value = base1; - } } } else @@ -6579,55 +4151,39 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) } break; - case SE_ReduceReuseTimer: - { + case SE_ReduceReuseTimer: { if(type == focusReduceRecastTime) - value = base1 / 1000; - + value = (base1 / 1000); break; } - - case SE_TriggerOnCast: - { - if(type == focusTriggerOnCast) - { - if(zone->random.Int(0, 100) <= base1){ + case SE_TriggerOnCast: { + if(type == focusTriggerOnCast) { + if(zone->random.Int(0, 100) <= base1) value = base2; - } - - else{ + else { value = 0; LimitFound = true; } } break; } - case SE_FcSpellVulnerability: - { + case SE_FcSpellVulnerability: { if(type == focusSpellVulnerability) - { value = base1; - } break; } - case SE_BlockNextSpellFocus: - { - if(type == focusBlockNextSpell) - { + case SE_BlockNextSpellFocus: { + if(type == focusBlockNextSpell) { if(zone->random.Int(1, 100) <= base1) value = 1; } break; } - case SE_FcTwincast: - { + case SE_FcTwincast: { if(type == focusTwincast) - { value = base1; - } break; } - /* case SE_SympatheticProc: { @@ -6645,92 +4201,68 @@ int32 Bot::CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id) value = 0; } break; - } - */ - case SE_FcDamageAmt: - { + }*/ + case SE_FcDamageAmt: { if(type == focusFcDamageAmt) value = base1; - break; } - - case SE_FcDamageAmtCrit: - { + case SE_FcDamageAmtCrit: { if(type == focusFcDamageAmtCrit) value = base1; - break; } - - case SE_FcDamageAmtIncoming: - { + case SE_FcDamageAmtIncoming: { if(type == focusFcDamageAmtIncoming) value = base1; - break; } - case SE_FcHealAmtIncoming: if(type == focusFcHealAmtIncoming) value = base1; break; - case SE_FcHealPctCritIncoming: if (type == focusFcHealPctCritIncoming) value = base1; break; - case SE_FcHealAmtCrit: if(type == focusFcHealAmtCrit) value = base1; break; - case SE_FcHealAmt: if(type == focusFcHealAmt) value = base1; break; - case SE_FcHealPctIncoming: if(type == focusFcHealPctIncoming) value = base1; break; - - case SE_FcBaseEffects: - { + case SE_FcBaseEffects: { if (type == focusFcBaseEffects) value = base1; - break; } - case SE_FcDamagePctCrit: - { + case SE_FcDamagePctCrit: { if(type == focusFcDamagePctCrit) value = base1; - break; } - - case SE_FcIncreaseNumHits: - { + case SE_FcIncreaseNumHits: { if(type == focusIncreaseNumHits) value = base1; - break; } //Check for spell skill limits. - if ((LimitSpellSkill) && (!SpellSkill_Found)) - return 0; - + if ((LimitSpellSkill) && (!SpellSkill_Found)) + return 0; } } - if (LimitFound){ + if (LimitFound) return 0; - } - return(value*lvlModifier/100); + return (value * lvlModifier / 100); } int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { @@ -6741,54 +4273,39 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { int32 realTotal2 = 0; int32 realTotal3 = 0; bool rand_effectiveness = false; - //Improved Healing, Damage & Mana Reduction are handled differently in that some are random percentages //In these cases we need to find the most powerful effect, so that each piece of gear wont get its own chance - if((bottype == BotfocusManaCost || bottype == BotfocusImprovedHeal || bottype == BotfocusImprovedDamage) - && RuleB(Spells, LiveLikeFocusEffects)) - { + if((bottype == BotfocusManaCost || bottype == BotfocusImprovedHeal || bottype == BotfocusImprovedDamage) && RuleB(Spells, LiveLikeFocusEffects)) rand_effectiveness = true; - } //Check if item focus effect exists for the client. - if (itembonuses.FocusEffects[bottype]){ - - const Item_Struct* TempItem = 0; - const Item_Struct* UsedItem = 0; + if (itembonuses.FocusEffects[bottype]) { + const EQEmu::ItemBase* TempItem = 0; + const EQEmu::ItemBase* UsedItem = 0; const ItemInst* TempInst = 0; uint16 UsedFocusID = 0; int32 Total = 0; int32 focus_max = 0; int32 focus_max_real = 0; - //item focus - for(int x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::EQUIPMENT_END; x++) - { + for (int x = EQEmu::legacy::EQUIPMENT_BEGIN; x <= EQEmu::legacy::EQUIPMENT_END; x++) { TempItem = nullptr; ItemInst* ins = GetBotItem(x); if (!ins) continue; + TempItem = ins->GetItem(); if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) { if(rand_effectiveness) { focus_max = CalcBotFocusEffect(bottype, TempItem->Focus.Effect, spell_id, true); - if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) { - focus_max_real = focus_max; - UsedItem = TempItem; - UsedFocusID = TempItem->Focus.Effect; - } else if (focus_max < 0 && focus_max < focus_max_real) { + if ((focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) || (focus_max < 0 && focus_max < focus_max_real)) { focus_max_real = focus_max; UsedItem = TempItem; UsedFocusID = TempItem->Focus.Effect; } - } - else { + } else { Total = CalcBotFocusEffect(bottype, TempItem->Focus.Effect, spell_id); - if (Total > 0 && realTotal >= 0 && Total > realTotal) { - realTotal = Total; - UsedItem = TempItem; - UsedFocusID = TempItem->Focus.Effect; - } else if (Total < 0 && Total < realTotal) { + if ((Total > 0 && realTotal >= 0 && Total > realTotal) || (Total < 0 && Total < realTotal)) { realTotal = Total; UsedItem = TempItem; UsedFocusID = TempItem->Focus.Effect; @@ -6796,33 +4313,22 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { } } - for (int y = AUG_BEGIN; y < EmuConstants::ITEM_COMMON_SIZE; ++y) - { + for (int y = AUG_INDEX_BEGIN; y < EQEmu::legacy::ITEM_COMMON_SIZE; ++y) { ItemInst *aug = nullptr; aug = ins->GetAugment(y); - if(aug) - { - const Item_Struct* TempItemAug = aug->GetItem(); + if(aug) { + const EQEmu::ItemBase* TempItemAug = aug->GetItem(); if (TempItemAug && TempItemAug->Focus.Effect > 0 && TempItemAug->Focus.Effect != SPELL_UNKNOWN) { if(rand_effectiveness) { focus_max = CalcBotFocusEffect(bottype, TempItemAug->Focus.Effect, spell_id, true); - if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) { - focus_max_real = focus_max; - UsedItem = TempItem; - UsedFocusID = TempItemAug->Focus.Effect; - } else if (focus_max < 0 && focus_max < focus_max_real) { + if ((focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) || (focus_max < 0 && focus_max < focus_max_real)) { focus_max_real = focus_max; UsedItem = TempItem; UsedFocusID = TempItemAug->Focus.Effect; } - } - else { + } else { Total = CalcBotFocusEffect(bottype, TempItemAug->Focus.Effect, spell_id); - if (Total > 0 && realTotal >= 0 && Total > realTotal) { - realTotal = Total; - UsedItem = TempItem; - UsedFocusID = TempItemAug->Focus.Effect; - } else if (Total < 0 && Total < realTotal) { + if ((Total > 0 && realTotal >= 0 && Total > realTotal) || (Total < 0 && Total < realTotal)) { realTotal = Total; UsedItem = TempItem; UsedFocusID = TempItemAug->Focus.Effect; @@ -6838,13 +4344,11 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { } //Check if spell focus effect exists for the client. - if (spellbonuses.FocusEffects[bottype]){ - + if (spellbonuses.FocusEffects[bottype]) { //Spell Focus int32 Total2 = 0; int32 focus_max2 = 0; int32 focus_max_real2 = 0; - int buff_tracker = -1; int buff_slot = 0; uint32 focusspellid = 0; @@ -6857,23 +4361,14 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { if(rand_effectiveness) { focus_max2 = CalcBotFocusEffect(bottype, focusspellid, spell_id, true); - if (focus_max2 > 0 && focus_max_real2 >= 0 && focus_max2 > focus_max_real2) { - focus_max_real2 = focus_max2; - buff_tracker = buff_slot; - focusspell_tracker = focusspellid; - } else if (focus_max2 < 0 && focus_max2 < focus_max_real2) { + if ((focus_max2 > 0 && focus_max_real2 >= 0 && focus_max2 > focus_max_real2) || (focus_max2 < 0 && focus_max2 < focus_max_real2)) { focus_max_real2 = focus_max2; buff_tracker = buff_slot; focusspell_tracker = focusspellid; } - } - else { + } else { Total2 = CalcBotFocusEffect(bottype, focusspellid, spell_id); - if (Total2 > 0 && realTotal2 >= 0 && Total2 > realTotal2) { - realTotal2 = Total2; - buff_tracker = buff_slot; - focusspell_tracker = focusspellid; - } else if (Total2 < 0 && Total2 < realTotal2) { + if ((Total2 > 0 && realTotal2 >= 0 && Total2 > realTotal2) || (Total2 < 0 && Total2 < realTotal2)) { realTotal2 = Total2; buff_tracker = buff_slot; focusspell_tracker = focusspellid; @@ -6885,35 +4380,37 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { realTotal2 = CalcBotFocusEffect(bottype, focusspell_tracker, spell_id); // For effects like gift of mana that only fire once, save the spellid into an array that consists of all available buff slots. - if(buff_tracker >= 0 && buffs[buff_tracker].numhits > 0) { + if(buff_tracker >= 0 && buffs[buff_tracker].numhits > 0) m_spellHitsLeft[buff_tracker] = focusspell_tracker; - } } // AA Focus - if (aabonuses.FocusEffects[bottype]){ - - int totalAAs = database.CountAAs(); + if (aabonuses.FocusEffects[bottype]) { int32 Total3 = 0; uint32 slots = 0; uint32 aa_AA = 0; uint32 aa_value = 0; - for (int i = 0; i < totalAAs; i++) { //iterate through all of the client's AAs - std::map::iterator aa = botAAs.find(i); - if(aa != botAAs.end()) { // make sure aa exists or we'll crash zone - aa_AA = aa->second.aa_id; //same as aaid from the aa_effects table - aa_value = aa->second.total_levels; //how many points in it - if (aa_AA < 1 || aa_value < 1) - continue; + for(auto &aa : aa_ranks) { + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first); + auto ability = ability_rank.first; + auto rank = ability_rank.second; - Total3 = CalcBotAAFocus(bottype, aa_AA, spell_id); - if (Total3 > 0 && realTotal3 >= 0 && Total3 > realTotal3) { - realTotal3 = Total3; - } - else if (Total3 < 0 && Total3 < realTotal3) { - realTotal3 = Total3; - } + if(!ability) { + continue; + } + + aa_AA = ability->id; + aa_value = aa.second.first; + if (aa_AA < 1 || aa_value < 1) + continue; + + Total3 = CalcBotAAFocus(bottype, aa_AA, aa_value, spell_id); + if (Total3 > 0 && realTotal3 >= 0 && Total3 > realTotal3) { + realTotal3 = Total3; + } + else if (Total3 < 0 && Total3 < realTotal3) { + realTotal3 = Total3; } } } @@ -6921,13 +4418,10 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) { if(bottype == BotfocusReagentCost && IsSummonPetSpell(spell_id) && GetAA(aaElementalPact)) return 100; - if(bottype == BotfocusReagentCost && (IsEffectInSpell(spell_id, SE_SummonItem) || IsSacrificeSpell(spell_id))){ + if(bottype == BotfocusReagentCost && (IsEffectInSpell(spell_id, SE_SummonItem) || IsSacrificeSpell(spell_id))) return 0; - //Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected - //by reagent conservation for obvious reasons. - } - return realTotal + realTotal2; + return (realTotal + realTotal2); } int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus) { @@ -6936,433 +4430,317 @@ int32 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel const SPDat_Spell_Struct &focus_spell = spells[focus_id]; const SPDat_Spell_Struct &spell = spells[spell_id]; - int32 value = 0; int lvlModifier = 100; int spell_level = 0; int lvldiff = 0; bool LimitSpellSkill = false; bool SpellSkill_Found = false; - for (int i = 0; i < EFFECT_COUNT; i++) { switch (focus_spell.effectid[i]) { - case SE_Blank: - break; - //check limits - - case SE_LimitResist:{ - if(focus_spell.base[i]){ - if(spell.resisttype != focus_spell.base[i]) - return(0); - } - break; - } - case SE_LimitInstant:{ - if(spell.buffduration) - return(0); - break; - } - - case SE_LimitMaxLevel:{ - if (IsNPC()) + case SE_Blank: break; - spell_level = spell.classes[(GetClass()%16) - 1]; - lvldiff = spell_level - focus_spell.base[i]; - //every level over cap reduces the effect by focus_spell.base2[i] percent unless from a clicky when ItemCastsUseFocus is true - if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)) - { - if(focus_spell.base2[i] > 0) - { - lvlModifier -= focus_spell.base2[i]*lvldiff; - if(lvlModifier < 1) + case SE_LimitResist:{ + if(focus_spell.base[i]) { + if(spell.resisttype != focus_spell.base[i]) return 0; } - else - { - return 0; - } - } - break; - } - - case SE_LimitMinLevel: - if (IsNPC()) break; - if (spell.classes[(GetClass()%16) - 1] < focus_spell.base[i]) - return(0); - break; - - case SE_LimitCastTimeMin: - if (spells[spell_id].cast_time < (uint32)focus_spell.base[i]) - return(0); - break; - - case SE_LimitSpell: - if(focus_spell.base[i] < 0) { //exclude spell - if (spell_id == (focus_spell.base[i]*-1)) - return(0); - } else { - //this makes the assumption that only one spell can be explicitly included... - if (spell_id != focus_spell.base[i]) - return(0); } - break; - - case SE_LimitMinDur: - if (focus_spell.base[i] > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) - return(0); - break; - - case SE_LimitEffect: - if(focus_spell.base[i] < 0){ - if(IsEffectInSpell(spell_id,focus_spell.base[i])){ //we limit this effect, can't have + case SE_LimitInstant: { + if(spell.buffduration) return 0; - } + break; } - else{ - if(focus_spell.base[i] == SE_SummonPet) //summoning haste special case - { //must have one of the three pet effects to qualify - if(!IsEffectInSpell(spell_id, SE_SummonPet) && - !IsEffectInSpell(spell_id, SE_NecPet) && - !IsEffectInSpell(spell_id, SE_SummonBSTPet)) - { - return 0; + case SE_LimitMaxLevel:{ + if (IsNPC()) + break; + spell_level = spell.classes[(GetClass() % 17) - 1]; + lvldiff = (spell_level - focus_spell.base[i]); + if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)) { + if(focus_spell.base2[i] > 0) { + lvlModifier -= (focus_spell.base2[i] * lvldiff); + if(lvlModifier < 1) + return 0; } + else + return 0; } - else if(!IsEffectInSpell(spell_id,focus_spell.base[i])){ //we limit this effect, must have + break; + } + case SE_LimitMinLevel: + if (IsNPC()) + break; + if (spell.classes[(GetClass() % 17) - 1] < focus_spell.base[i]) return 0; + break; + + case SE_LimitCastTimeMin: + if (spells[spell_id].cast_time < (uint32)focus_spell.base[i]) + return 0; + break; + case SE_LimitSpell: + if(focus_spell.base[i] < 0) { + if (spell_id == (focus_spell.base[i] * -1)) + return 0; + } else { + if (spell_id != focus_spell.base[i]) + return 0; } - } - break; - - - case SE_LimitSpellType: - switch( focus_spell.base[i] ) - { - case 0: - if (!IsDetrimentalSpell(spell_id)) + break; + case SE_LimitMinDur: + if (focus_spell.base[i] > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) + return 0; + break; + case SE_LimitEffect: + if(focus_spell.base[i] < 0) { + if(IsEffectInSpell(spell_id,focus_spell.base[i])) return 0; - break; - case 1: - if (!IsBeneficialSpell(spell_id)) + } else { + if(focus_spell.base[i] == SE_SummonPet) { + if(!IsEffectInSpell(spell_id, SE_SummonPet) && !IsEffectInSpell(spell_id, SE_NecPet) && !IsEffectInSpell(spell_id, SE_SummonBSTPet)) { + return 0; + } + } else if(!IsEffectInSpell(spell_id,focus_spell.base[i])) return 0; - break; - default: - Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown limit spelltype %d", focus_spell.base[i]); - } - break; + } + break; - case SE_LimitManaMin: + + case SE_LimitSpellType: + switch(focus_spell.base[i]) { + case 0: + if (!IsDetrimentalSpell(spell_id)) + return 0; + break; + case 1: + if (!IsBeneficialSpell(spell_id)) + return 0; + break; + default: + Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown limit spelltype %d", focus_spell.base[i]); + } + break; + + case SE_LimitManaMin: if(spell.mana < focus_spell.base[i]) return 0; - break; - - case SE_LimitTarget: - // Exclude - if((focus_spell.base[i] < 0) && -focus_spell.base[i] == spell.targettype) - return 0; - // Include - else if (focus_spell.base[i] > 0 && focus_spell.base[i] != spell.targettype) - return 0; - - break; - - case SE_LimitCombatSkills: - // 1 is for disciplines only + break; + case SE_LimitTarget: + if((focus_spell.base[i] < 0) && -focus_spell.base[i] == spell.targettype) + return 0; + else if (focus_spell.base[i] > 0 && focus_spell.base[i] != spell.targettype) + return 0; + break; + case SE_LimitCombatSkills: if(focus_spell.base[i] == 1 && !IsDiscipline(spell_id)) return 0; - // 0 is for spells only else if(focus_spell.base[i] == 0 && IsDiscipline(spell_id)) return 0; - break; - - case SE_LimitSpellGroup: + break; + case SE_LimitSpellGroup: if(focus_spell.base[i] > 0 && focus_spell.base[i] != spell.spellgroup) return 0; else if(focus_spell.base[i] < 0 && focus_spell.base[i] == spell.spellgroup) return 0; - break; - - case SE_LimitCastingSkill: + break; + case SE_LimitCastingSkill: LimitSpellSkill = true; if(focus_spell.base[i] == spell.skill) SpellSkill_Found = true; - break; - - case SE_LimitClass: - //Do not use this limit more then once per spell. If multiple class, treat value like items would. - if (!PassLimitClass(focus_spell.base[i], GetClass())) - return 0; - break; - - //handle effects - case SE_ImprovedDamage: - // No Spell used this, its handled by different spell effect IDs. - if (bottype == BotfocusImprovedDamage) { - // This is used to determine which focus should be used for the random calculation - if(best_focus) { - // If the spell contains a value in the base2 field then that is the max value - if (focus_spell.base2[i] != 0) { - value = focus_spell.base2[i]; - } - // If the spell does not contain a base2 value, then its a straight non random value - else { - value = focus_spell.base[i]; - } - } - // Actual focus calculation starts here - else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; - } - else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); - } - } - break; - case SE_ImprovedHeal: - if (bottype == BotfocusImprovedHeal) { - if(best_focus) { - if (focus_spell.base2[i] != 0) { - value = focus_spell.base2[i]; - } - else { - value = focus_spell.base[i]; - } - } - else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; - } - else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); - } - } - break; - case SE_ReduceManaCost: - if (bottype == BotfocusManaCost) { - if(best_focus) { - if (focus_spell.base2[i] != 0) { - value = focus_spell.base2[i]; - } - else { - value = focus_spell.base[i]; - } - } - else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; - } - else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); - } - } - break; - - case SE_IncreaseSpellHaste: - if (bottype == BotfocusSpellHaste && focus_spell.base[i] > value) - { - value = focus_spell.base[i]; - } - break; - case SE_IncreaseSpellDuration: - if (bottype == BotfocusSpellDuration && focus_spell.base[i] > value) - { - value = focus_spell.base[i]; - } - break; - case SE_SpellDurationIncByTic: - if (bottype == BotfocusSpellDurByTic && focus_spell.base[i] > value) - { - value = focus_spell.base[i]; - } - break; - case SE_SwarmPetDuration: - if (bottype == BotfocusSwarmPetDuration && focus_spell.base[i] > value) - { - value = focus_spell.base[i]; - } - break; - case SE_IncreaseRange: - if (bottype == BotfocusRange && focus_spell.base[i] > value) - { - value = focus_spell.base[i]; - } - break; - case SE_ReduceReagentCost: - if (bottype == BotfocusReagentCost && focus_spell.base[i] > value) - { - value = focus_spell.base[i]; - } - break; - case SE_PetPowerIncrease: - if (bottype == BotfocusPetPower && focus_spell.base[i] > value) - { - value = focus_spell.base[i]; - } - break; - case SE_SpellResistReduction: - if (bottype == BotfocusResistRate && focus_spell.base[i] > value) - { - value = focus_spell.base[i]; - } - break; - case SE_SpellHateMod: - if (bottype == BotfocusSpellHateMod) - { - if(value != 0) - { - if(value > 0) - { - if(focus_spell.base[i] > value) - { + break; + case SE_LimitClass: + if (!PassLimitClass(focus_spell.base[i], GetClass())) + return 0; + break; + case SE_ImprovedDamage: + if (bottype == BotfocusImprovedDamage) { + if(best_focus) { + if (focus_spell.base2[i] != 0) + value = focus_spell.base2[i]; + else value = focus_spell.base[i]; - } } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) + value = focus_spell.base[i]; else - { - if(focus_spell.base[i] < value) - { - value = focus_spell.base[i]; - } - } + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } - else + break; + case SE_ImprovedHeal: + if (bottype == BotfocusImprovedHeal) { + if(best_focus) { + if (focus_spell.base2[i] != 0) + value = focus_spell.base2[i]; + else + value = focus_spell.base[i]; + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) + value = focus_spell.base[i]; + else + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); + } + break; + case SE_ReduceManaCost: + if (bottype == BotfocusManaCost) { + if(best_focus) { + if (focus_spell.base2[i] != 0) + value = focus_spell.base2[i]; + else + value = focus_spell.base[i]; + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) + value = focus_spell.base[i]; + else + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); + } + break; + case SE_IncreaseSpellHaste: + if (bottype == BotfocusSpellHaste && focus_spell.base[i] > value) value = focus_spell.base[i]; + break; + case SE_IncreaseSpellDuration: + if (bottype == BotfocusSpellDuration && focus_spell.base[i] > value) + value = focus_spell.base[i]; + break; + case SE_SpellDurationIncByTic: + if (bottype == BotfocusSpellDurByTic && focus_spell.base[i] > value) + value = focus_spell.base[i]; + break; + case SE_SwarmPetDuration: + if (bottype == BotfocusSwarmPetDuration && focus_spell.base[i] > value) + value = focus_spell.base[i]; + break; + case SE_IncreaseRange: + if (bottype == BotfocusRange && focus_spell.base[i] > value) + value = focus_spell.base[i]; + break; + case SE_ReduceReagentCost: + if (bottype == BotfocusReagentCost && focus_spell.base[i] > value) + value = focus_spell.base[i]; + break; + case SE_PetPowerIncrease: + if (bottype == BotfocusPetPower && focus_spell.base[i] > value) + value = focus_spell.base[i]; + break; + case SE_SpellResistReduction: + if (bottype == BotfocusResistRate && focus_spell.base[i] > value) + value = focus_spell.base[i]; + break; + case SE_SpellHateMod: + if (bottype == BotfocusSpellHateMod) { + if(value != 0) { + if(value > 0) { + if(focus_spell.base[i] > value) + value = focus_spell.base[i]; + } + else { + if(focus_spell.base[i] < value) + value = focus_spell.base[i]; + } + } else + value = focus_spell.base[i]; + } + break; + case SE_ReduceReuseTimer: { + if(bottype == BotfocusReduceRecastTime) + value = (focus_spell.base[i] / 1000); + break; } - break; - - case SE_ReduceReuseTimer: - { - if(bottype == BotfocusReduceRecastTime) - value = focus_spell.base[i] / 1000; - - break; - } - - case SE_TriggerOnCast: - { - if(bottype == BotfocusTriggerOnCast) - - if(zone->random.Int(0, 100) <= focus_spell.base[i]) - value = focus_spell.base2[i]; - - else - value = 0; - - break; - } - case SE_FcSpellVulnerability: - { - if(bottype == BotfocusSpellVulnerability) - { - value = focus_spell.base[i]; + case SE_TriggerOnCast: { + if(bottype == BotfocusTriggerOnCast) { + if(zone->random.Int(0, 100) <= focus_spell.base[i]) + value = focus_spell.base2[i]; + else + value = 0; + } + break; } - break; - } - case SE_BlockNextSpellFocus: - { - if(bottype == BotfocusBlockNextSpell) - { - if(zone->random.Int(1, 100) <= focus_spell.base[i]) - value = 1; + case SE_FcSpellVulnerability: { + if(bottype == BotfocusSpellVulnerability) + value = focus_spell.base[i]; + break; } - break; - } - case SE_FcTwincast: - { - if(bottype == BotfocusTwincast) - { - value = focus_spell.base[i]; + case SE_BlockNextSpellFocus: { + if(bottype == BotfocusBlockNextSpell) { + if(zone->random.Int(1, 100) <= focus_spell.base[i]) + value = 1; + } + break; } - break; - } - case SE_SympatheticProc: - { - if(bottype == BotfocusSympatheticProc) - { - - float ProcChance = GetSympatheticProcChances(spell_id, focus_spell.base[i]); - - if(zone->random.Real(0, 1) <= ProcChance) - value = focus_id; - - else - value = 0; + case SE_FcTwincast: { + if(bottype == BotfocusTwincast) + value = focus_spell.base[i]; + break; } - break; - } - case SE_FcDamageAmt: - { - if(bottype == BotfocusFcDamageAmt) - value = focus_spell.base[i]; + case SE_SympatheticProc: { + if(bottype == BotfocusSympatheticProc) { + float ProcChance = GetSympatheticProcChances(spell_id, focus_spell.base[i]); + if(zone->random.Real(0, 1) <= ProcChance) + value = focus_id; + else + value = 0; + } + break; + } + case SE_FcDamageAmt: { + if(bottype == BotfocusFcDamageAmt) + value = focus_spell.base[i]; + break; + } + case SE_FcDamageAmtCrit: { + if(bottype == BotfocusFcDamageAmtCrit) + value = focus_spell.base[i]; + break; + } + case SE_FcHealAmtIncoming: + if(bottype == BotfocusFcHealAmtIncoming) + value = focus_spell.base[i]; + break; + case SE_FcHealPctCritIncoming: + if (bottype == BotfocusFcHealPctCritIncoming) + value = focus_spell.base[i]; + break; + case SE_FcHealAmtCrit: + if(bottype == BotfocusFcHealAmtCrit) + value = focus_spell.base[i]; + break; + case SE_FcHealAmt: + if(bottype == BotfocusFcHealAmt) + value = focus_spell.base[i]; + break; + case SE_FcHealPctIncoming: + if(bottype == BotfocusFcHealPctIncoming) + value = focus_spell.base[i]; + break; + case SE_FcBaseEffects: { + if (bottype == BotfocusFcBaseEffects) + value = focus_spell.base[i]; - break; - } + break; + } + case SE_FcDamagePctCrit: { + if(bottype == BotfocusFcDamagePctCrit) + value = focus_spell.base[i]; - case SE_FcDamageAmtCrit: - { - if(bottype == BotfocusFcDamageAmtCrit) - value = focus_spell.base[i]; + break; + } + case SE_FcIncreaseNumHits: { + if(bottype == BotfocusIncreaseNumHits) + value = focus_spell.base[i]; - break; - } - - case SE_FcHealAmtIncoming: - if(bottype == BotfocusFcHealAmtIncoming) - value = focus_spell.base[i]; - break; - - case SE_FcHealPctCritIncoming: - if (bottype == BotfocusFcHealPctCritIncoming) - value = focus_spell.base[i]; - break; - - case SE_FcHealAmtCrit: - if(bottype == BotfocusFcHealAmtCrit) - value = focus_spell.base[i]; - break; - - case SE_FcHealAmt: - if(bottype == BotfocusFcHealAmt) - value = focus_spell.base[i]; - break; - - case SE_FcHealPctIncoming: - if(bottype == BotfocusFcHealPctIncoming) - value = focus_spell.base[i]; - break; - - case SE_FcBaseEffects: - { - if (bottype == BotfocusFcBaseEffects) - value = focus_spell.base[i]; - - break; - } - case SE_FcDamagePctCrit: - { - if(bottype == BotfocusFcDamagePctCrit) - value = focus_spell.base[i]; - - break; - } - - case SE_FcIncreaseNumHits: - { - if(bottype == BotfocusIncreaseNumHits) - value = focus_spell.base[i]; - - break; - } - //this spits up a lot of garbage when calculating spell focuses - //since they have all kinds of extra effects on them. - default: - Log.Out(Logs::General, Logs::Spells, "CalcFocusEffect: unknown effectid %d", focus_spell.effectid[i]); + break; + } + default: + Log.Out(Logs::General, Logs::Spells, "CalcFocusEffect: unknown effectid %d", focus_spell.effectid[i]); + break; } } //Check for spell skill limits. if ((LimitSpellSkill) && (!SpellSkill_Found)) return 0; - return(value*lvlModifier/100); + return(value * lvlModifier / 100); } //proc chance includes proc bonus @@ -7371,271 +4749,87 @@ float Bot::GetProcChances(float ProcBonus, uint16 hand) { float ProcChance = 0.0f; uint32 weapon_speed = 0; switch (hand) { - case MainPrimary: - weapon_speed = attack_timer.GetDuration(); - break; - case MainSecondary: - weapon_speed = attack_dw_timer.GetDuration(); - break; - case MainRange: - weapon_speed = ranged_timer.GetDuration(); - break; + case EQEmu::legacy::SlotPrimary: + weapon_speed = attack_timer.GetDuration(); + break; + case EQEmu::legacy::SlotSecondary: + weapon_speed = attack_dw_timer.GetDuration(); + break; + case EQEmu::legacy::SlotRange: + weapon_speed = ranged_timer.GetDuration(); + break; } - //calculate the weapon speed in ms, so we can use the rule to compare against. - // fast as a client can swing, so should be the floor of the proc chance if (weapon_speed < RuleI(Combat, MinHastedDelay)) weapon_speed = RuleI(Combat, MinHastedDelay); if (RuleB(Combat, AdjustProcPerMinute)) { - ProcChance = (static_cast(weapon_speed) * - RuleR(Combat, AvgProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms + ProcChance = (static_cast(weapon_speed) * RuleR(Combat, AvgProcsPerMinute) / 60000.0f); ProcBonus += static_cast(mydex) * RuleR(Combat, ProcPerMinDexContrib); - ProcChance += ProcChance * ProcBonus / 100.0f; + ProcChance += (ProcChance * ProcBonus / 100.0f); } else { - ProcChance = RuleR(Combat, BaseProcChance) + - static_cast(mydex) / RuleR(Combat, ProcDexDivideBy); - ProcChance += ProcChance*ProcBonus / 100.0f; + ProcChance = (RuleR(Combat, BaseProcChance) + static_cast(mydex) / RuleR(Combat, ProcDexDivideBy)); + ProcChance += (ProcChance * ProcBonus / 100.0f); } Log.Out(Logs::Detail, Logs::Combat, "Proc chance %.2f (%.2f from bonuses)", ProcChance, ProcBonus); return ProcChance; } -bool Bot::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) -{ - /* called when a mob is attacked, does the checks to see if it's a hit - * and does other mitigation checks. 'this' is the mob being attacked. - * - * special return values: - * -1 - block - * -2 - parry - * -3 - riposte - * -4 - dodge - * - */ - if(GetAppearance() == eaDead) - return false; - - float skill = 0; - float bonus = 0; - float RollTable[4] = {0,0,0,0}; - float roll = 0; - Mob *attacker=other; - Mob *defender=this; - - //garunteed hit - bool ghit = false; - if((attacker->GetSpellBonuses().MeleeSkillCheck + attacker->GetItemBonuses().MeleeSkillCheck) > 500) - ghit = true; - - ////////////////////////////////////////////////////////// - // make enrage same as riposte - ///////////////////////////////////////////////////////// - if (IsEnraged() && !other->BehindMob(this, other->GetX(), other->GetY())) { - damage = -3; - Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack."); +int Bot::GetHandToHandDamage(void) { + if (RuleB(Combat, UseRevampHandToHand)) { + // everyone uses this in the revamp! + int skill = GetSkill(EQEmu::skills::SkillHandtoHand); + int epic = 0; + if (CastToNPC()->GetEquipment(EQEmu::textures::TextureHands) == 10652 && GetLevel() > 46) + epic = 280; + if (epic > skill) + skill = epic; + return skill / 15 + 3; } - ///////////////////////////////////////////////////////// - // riposte - ///////////////////////////////////////////////////////// - float riposte_chance = 0.0f; - if (CanRiposte && damage > 0 && CanThisClassRiposte() && !other->BehindMob(this, other->GetX(), other->GetY())) - { - riposte_chance = (100.0f + (float)defender->GetAABonuses().RiposteChance + (float)defender->GetSpellBonuses().RiposteChance + (float)defender->GetItemBonuses().RiposteChance) / 100.0f; - skill = GetSkill(SkillRiposte); - - if (!ghit) { //if they are not using a garunteed hit discipline - bonus = 2.0 + skill/60.0 + (GetDEX()/200); - bonus *= riposte_chance; - RollTable[0] = bonus + (itembonuses.HeroicDEX / 25); // 25 heroic = 1%, applies to ripo, parry, block - } - } - - /////////////////////////////////////////////////////// - // block - /////////////////////////////////////////////////////// - - bool bBlockFromRear = false; - bool bShieldBlockFromRear = false; - - if (this->IsBot()) { - int aaChance = 0; - - // a successful roll on this does not mean a successful block is forthcoming. only that a chance to block - // from a direction other than the rear is granted. - - //Live AA - HightenedAwareness - int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind; - - if (BlockBehindChance && (BlockBehindChance > zone->random.Int(1, 100))){ - bBlockFromRear = true; - - if (spellbonuses.BlockBehind || itembonuses.BlockBehind) - bShieldBlockFromRear = true; //This bonus should allow a chance to Shield Block from behind. - } - } - - float block_chance = 0.0f; - if (damage > 0 && CanThisClassBlock() && (!other->BehindMob(this, other->GetX(), other->GetY()) || bBlockFromRear)) { - block_chance = (100.0f + (float)spellbonuses.IncreaseBlockChance + (float)itembonuses.IncreaseBlockChance) / 100.0f; - skill = GetSkill(SkillBlock); - - if (!ghit) { //if they are not using a garunteed hit discipline - bonus = 2.0 + skill/35.0 + (GetDEX()/200); - RollTable[1] = RollTable[0] + (bonus * block_chance) - riposte_chance; - block_chance *= bonus; // set this so we can remove it from the parry calcs - } - } - else{ - RollTable[1] = RollTable[0]; - } - - if(damage > 0 && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) - && (!other->BehindMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) { - bool equiped = GetBotItem(MainSecondary); - if(equiped) { - uint8 shield = GetBotItem(MainSecondary)->GetItem()->ItemType; - float bonusShieldBlock = 0.0f; - if(shield == ItemTypeShield) { - - //Live AA - Shield Block - bonusShieldBlock = aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock; - RollTable[1] = RollTable[0] + bonusShieldBlock; - } - } - } - - if(damage > 0 && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) - && (!other->BehindMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) { - bool equiped2 = GetBotItem(MainPrimary); - if(equiped2) { - uint8 TwoHandBlunt = GetBotItem(MainPrimary)->GetItem()->ItemType; - float bonusStaffBlock = 0.0f; - if(TwoHandBlunt == ItemType2HBlunt) { - - bonusStaffBlock = aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock; - RollTable[1] = RollTable[0] + bonusStaffBlock; - } - } - } - - ////////////////////////////////////////////////////// - // parry - ////////////////////////////////////////////////////// - float parry_chance = 0.0f; - if (damage > 0 && CanThisClassParry() && !other->BehindMob(this, other->GetX(), other->GetY())) - { - parry_chance = (100.0f + (float)defender->GetSpellBonuses().ParryChance + (float)defender->GetItemBonuses().ParryChance) / 100.0f; - skill = GetSkill(SkillParry); - - if (!ghit) { //if they are not using a garunteed hit discipline - bonus = 2.0 + skill/60.0 + (GetDEX()/200); - bonus *= parry_chance; - RollTable[2] = RollTable[1] + bonus - block_chance; - } - } - else{ - RollTable[2] = RollTable[1] - block_chance; - } - - //////////////////////////////////////////////////////// - // dodge - //////////////////////////////////////////////////////// - float dodge_chance = 0.0f; - if (damage > 0 && CanThisClassDodge() && !other->BehindMob(this, other->GetX(), other->GetY())) - { - dodge_chance = (100.0f + (float)defender->GetSpellBonuses().DodgeChance + (float)defender->GetItemBonuses().DodgeChance) / 100.0f; - skill = GetSkill(SkillDodge); - - if (!ghit) { //if they are not using a garunteed hit discipline - bonus = 2.0 + skill/60.0 + (GetAGI()/200); - bonus *= dodge_chance; - RollTable[3] = RollTable[2] + bonus - (itembonuses.HeroicDEX / 25) + (itembonuses.HeroicAGI / 25) - parry_chance; // Remove the dex as it doesnt count for dodge - } - } - else{ - RollTable[3] = RollTable[2] - (itembonuses.HeroicDEX / 25) + (itembonuses.HeroicAGI / 25) - parry_chance; - } - - if(damage > 0) - { - roll = zone->random.Real(0,100); - if(roll <= RollTable[0]){ - damage = -3; - } - else if(roll <= RollTable[1]){ - damage = -1; - } - else if(roll <= RollTable[2]){ - damage = -2; - } - else if(roll <= RollTable[3]){ - damage = -4; - } - } - - Log.Out(Logs::Detail, Logs::Combat, "Final damage after all avoidances: %d", damage); - - if (damage < 0) - return true; - return false; -} - -int Bot::GetMonkHandToHandDamage(void) -{ - // Kaiyodo - Determine a monk's fist damage. Table data from www.monkly-business.com - // saved as static array - this should speed this function up considerably - static int damage[66] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - 99, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11, - 12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14, - 14,14,15,15,15,15 }; - - // Have a look to see if we have epic fists on - - uint32 botWeaponId = INVALID_ID; - botWeaponId = CastToNPC()->GetEquipment(MaterialHands); - if(botWeaponId == 10652) { //Monk Epic ID + static uint8 mnk_dmg[] = {99, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, // 1-10 + 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, // 11-20 + 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, // 21-30 + 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, // 31-40 + 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, // 41-50 + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, // 51-60 + 14, 14}; // 61-62 + static uint8 bst_dmg[] = {99, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, // 1-10 + 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, // 11-20 + 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30 + 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40 + 10, 11, 11, 11, 11, 11, 11, 12, 12}; // 41-49 + if (GetClass() == MONK) { + if (CastToNPC()->GetEquipment(EQEmu::textures::TextureHands) == 10652 && GetLevel() > 50) return 9; - } - else - { - int Level = GetLevel(); - if(Level > 65) - return 19; - else - return damage[Level]; - } - - int Level = GetLevel(); - if (Level > 65) - return(19); - else - return damage[Level]; + if (level > 62) + return 15; + return mnk_dmg[level]; + } else if (GetClass() == BEASTLORD) { + if (level > 49) + return 13; + return bst_dmg[level]; + } + return 2; } -bool Bot::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) -{ +bool Bot::TryFinishingBlow(Mob *defender, EQEmu::skills::SkillType skillinuse) { if (!defender) return false; - if (aabonuses.FinishingBlow[1] && !defender->IsClient() && defender->GetHPRatio() < 10){ - - uint32 chance = aabonuses.FinishingBlow[0]/10; //500 = 5% chance. + if (aabonuses.FinishingBlow[1] && !defender->IsClient() && defender->GetHPRatio() < 10) { + uint32 chance = (aabonuses.FinishingBlow[0] / 10); uint32 damage = aabonuses.FinishingBlow[1]; uint16 levelreq = aabonuses.FinishingBlowLvl[0]; - if(defender->GetLevel() <= levelreq && (chance >= zone->random.Int(0, 1000))){ Log.Out(Logs::Detail, Logs::Combat, "Landed a finishing blow: levelreq at %d, other level %d", levelreq , defender->GetLevel()); entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FINISHING_BLOW, GetName()); defender->Damage(this, damage, SPELL_UNKNOWN, skillinuse); return true; - } - else - { + } else { Log.Out(Logs::Detail, Logs::Combat, "FAILED a finishing blow: levelreq at %d, other level %d", levelreq , defender->GetLevel()); return false; } @@ -7645,27 +4839,17 @@ bool Bot::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) void Bot::DoRiposte(Mob* defender) { Log.Out(Logs::Detail, Logs::Combat, "Preforming a riposte"); - if (!defender) return; - defender->Attack(this, MainPrimary, true); - - //double riposte - int32 DoubleRipChance = defender->GetAABonuses().GiveDoubleRiposte[0] + - defender->GetSpellBonuses().GiveDoubleRiposte[0] + - defender->GetItemBonuses().GiveDoubleRiposte[0]; - + defender->Attack(this, EQEmu::legacy::SlotPrimary, true); + int32 DoubleRipChance = (defender->GetAABonuses().GiveDoubleRiposte[0] + defender->GetSpellBonuses().GiveDoubleRiposte[0] + defender->GetItemBonuses().GiveDoubleRiposte[0]); if(DoubleRipChance && (DoubleRipChance >= zone->random.Int(0, 100))) { Log.Out(Logs::Detail, Logs::Combat, "Preforming a double riposte (%d percent chance)", DoubleRipChance); - - defender->Attack(this, MainPrimary, true); + defender->Attack(this, EQEmu::legacy::SlotPrimary, true); } - //Double Riposte effect, allows for a chance to do RIPOSTE with a skill specfic special attack (ie Return Kick). - //Coded narrowly: Limit to one per client. Limit AA only. [1 = Skill Attack Chance, 2 = Skill] DoubleRipChance = defender->GetAABonuses().GiveDoubleRiposte[1]; - if(DoubleRipChance && (DoubleRipChance >= zone->random.Int(0, 100))) { if (defender->GetClass() == MONK) defender->MonkSpecialAttack(this, defender->GetAABonuses().GiveDoubleRiposte[2]); @@ -7674,77 +4858,69 @@ void Bot::DoRiposte(Mob* defender) { } } -void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime, bool HitChance) { - //this really should go through the same code as normal melee damage to - //pick up all the special behavior there - +void Bot::DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32 max_damage, int32 min_damage, int32 hate_override, int ReuseTime, bool HitChance) { int32 hate = max_damage; if(hate_override > -1) hate = hate_override; - if(skill == SkillBash) { - const ItemInst* inst = GetBotItem(MainSecondary); - const Item_Struct* botweapon = 0; + if (skill == EQEmu::skills::SkillBash) { + const ItemInst* inst = GetBotItem(EQEmu::legacy::SlotSecondary); + const EQEmu::ItemBase* botweapon = 0; if(inst) botweapon = inst->GetItem(); + if(botweapon) { - if(botweapon->ItemType == ItemTypeShield) { + if (botweapon->ItemType == EQEmu::item::ItemTypeShield) hate += botweapon->AC; - } - hate = hate * (100 + GetFuriousBash(botweapon->Focus.Effect)) / 100; + + hate = (hate * (100 + GetFuriousBash(botweapon->Focus.Effect)) / 100); } } - min_damage += min_damage * GetMeleeMinDamageMod_SE(skill) / 100; - - if(HitChance && !who->CheckHitChance(this, skill, MainPrimary)) - max_damage = 0; - - else{ - bool CanRiposte = true; - if(skill == SkillThrowing || skill == SkillArchery) // changed from '&&' - CanRiposte = false; - - who->AvoidDamage(this, max_damage, CanRiposte); - who->MeleeMitigation(this, max_damage, min_damage); - - if(max_damage > 0) { + min_damage += (min_damage * GetMeleeMinDamageMod_SE(skill) / 100); + int hand = EQEmu::legacy::SlotPrimary; + if (skill == EQEmu::skills::SkillThrowing || skill == EQEmu::skills::SkillArchery) + hand = EQEmu::legacy::SlotRange; + if (who->AvoidDamage(this, max_damage, hand)) { + if (max_damage == -3) + DoRiposte(who); + } else { + if (HitChance || who->CheckHitChance(this, skill, EQEmu::legacy::SlotPrimary)) { + who->MeleeMitigation(this, max_damage, min_damage); ApplyMeleeDamageBonus(skill, max_damage); max_damage += who->GetFcDamageAmtIncoming(this, 0, true, skill); - max_damage += (itembonuses.HeroicSTR / 10) + (max_damage * who->GetSkillDmgTaken(skill) / 100) + GetSkillDmgAmt(skill); + max_damage += ((itembonuses.HeroicSTR / 10) + (max_damage * who->GetSkillDmgTaken(skill) / 100) + GetSkillDmgAmt(skill)); TryCriticalHit(who, skill, max_damage); + } else { + max_damage = 0; } } - if(max_damage >= 0) //You should probably get aggro no matter what, but unclear why it was set like this. - who->AddToHateList(this, hate); + who->AddToHateList(this, hate); who->Damage(this, max_damage, SPELL_UNKNOWN, skill, false); - if(!GetTarget())return; - if (HasDied()) return; + if(!GetTarget() || HasDied()) + return; if (max_damage > 0) CheckNumHitsRemaining(NumHit::OutgoingHitSuccess); //[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill - if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ +/* if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ int kb_chance = 25; - kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100; + kb_chance += (kb_chance * (100 - aabonuses.SpecialAttackKBProc[0]) / 100); if (zone->random.Int(0, 99) < kb_chance) SpellFinished(904, who, 10, 0, -1, spells[904].ResistDiff); //who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC. - } + }*/ if (HasSkillProcs()) - TrySkillProc(who, skill, ReuseTime*1000); + TrySkillProc(who, skill, (ReuseTime * 1000)); if (max_damage > 0 && HasSkillProcSuccess()) - TrySkillProc(who, skill, ReuseTime*1000, true); - - if(max_damage == -3 && !(who->GetHP() <= 0)) - DoRiposte(who); + TrySkillProc(who, skill, (ReuseTime * 1000), true); } void Bot::TryBackstab(Mob *other, int ReuseTime) { @@ -7753,53 +4929,35 @@ void Bot::TryBackstab(Mob *other, int ReuseTime) { bool bIsBehind = false; bool bCanFrontalBS = false; - - const ItemInst* inst = GetBotItem(MainPrimary); - const Item_Struct* botpiercer = nullptr; + const ItemInst* inst = GetBotItem(EQEmu::legacy::SlotPrimary); + const EQEmu::ItemBase* botpiercer = nullptr; if(inst) botpiercer = inst->GetItem(); - if(!botpiercer || (botpiercer->ItemType != ItemType1HPiercing)) { - Say("I can't backstab with this weapon!"); + + if (!botpiercer || (botpiercer->ItemType != EQEmu::item::ItemType1HPiercing)) { + BotGroupSay(this, "I can't backstab with this weapon!"); return; } - //Live AA - Triple Backstab - int tripleChance = itembonuses.TripleBackstab + spellbonuses.TripleBackstab + aabonuses.TripleBackstab; - - if (BehindMob(other, GetX(), GetY())) { + int tripleChance = (itembonuses.TripleBackstab + spellbonuses.TripleBackstab + aabonuses.TripleBackstab); + if (BehindMob(other, GetX(), GetY())) bIsBehind = true; - } else { - //Live AA - Seized Opportunity - int FrontalBSChance = itembonuses.FrontalBackstabChance + spellbonuses.FrontalBackstabChance + aabonuses.FrontalBackstabChance; - + int FrontalBSChance = (itembonuses.FrontalBackstabChance + spellbonuses.FrontalBackstabChance + aabonuses.FrontalBackstabChance); if (FrontalBSChance && (FrontalBSChance > zone->random.Int(0, 100))) bCanFrontalBS = true; } - if (bIsBehind || bCanFrontalBS){ // Bot is behind other OR can do Frontal Backstab - - // chance to assassinate - int chance = 10 + (GetDEX()/10) + (itembonuses.HeroicDEX/10); //18.5% chance at 85 dex 40% chance at 300 dex - if( - level >= 60 && // bot is 60 or higher - other->GetLevel() <= 45 && // mob 45 or under - !other->CastToNPC()->IsEngaged() && // not aggro - other->GetHP()<=32000 - && other->IsNPC() - && zone->random.Real(0, 99) < chance // chance - ) { + if (bIsBehind || bCanFrontalBS) { + int chance = (10 + (GetDEX() / 10) + (itembonuses.HeroicDEX / 10)); + if(level >= 60 && other->GetLevel() <= 45 && !other->CastToNPC()->IsEngaged() && other->GetHP()<= 32000 && other->IsNPC() && zone->random.Real(0, 99) < chance) { entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName()); RogueAssassinate(other); - } - else { + } else { RogueBackstab(other); if (level > 54) { - float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max - // Check for double attack with main hand assuming maxed DA Skill (MS) - - if(zone->random.Real(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA - { + float DoubleAttackProbability = ((GetSkill(EQEmu::skills::SkillDoubleAttack) + GetLevel()) / 500.0f); + if(zone->random.Real(0, 1) < DoubleAttackProbability) { if(other->GetHP() > 0) RogueBackstab(other,false,ReuseTime); @@ -7808,169 +4966,125 @@ void Bot::TryBackstab(Mob *other, int ReuseTime) { } } } - } - //Live AA - Chaotic Backstab - else if(aabonuses.FrontalBackstabMinDmg || itembonuses.FrontalBackstabMinDmg || spellbonuses.FrontalBackstabMinDmg) { - - //we can stab from any angle, we do min damage though. + } else if(aabonuses.FrontalBackstabMinDmg || itembonuses.FrontalBackstabMinDmg || spellbonuses.FrontalBackstabMinDmg) { RogueBackstab(other, true); if (level > 54) { - float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max - // Check for double attack with main hand assuming maxed DA Skill (MS) - if(zone->random.Real(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA + float DoubleAttackProbability = ((GetSkill(EQEmu::skills::SkillDoubleAttack) + GetLevel()) / 500.0f); + if(zone->random.Real(0, 1) < DoubleAttackProbability) if(other->GetHP() > 0) RogueBackstab(other,true, ReuseTime); if (tripleChance && other->GetHP() > 0 && tripleChance > zone->random.Int(0, 100)) - RogueBackstab(other,false,ReuseTime); + RogueBackstab(other,false,ReuseTime); } } - else { //We do a single regular attack if we attack from the front without chaotic stab - Attack(other, MainPrimary); - } + else + Attack(other, EQEmu::legacy::SlotPrimary); } -//heko: backstab -void Bot::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) -{ +void Bot::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) { int32 ndamage = 0; int32 max_hit = 0; int32 min_hit = 0; int32 hate = 0; int32 primaryweapondamage = 0; int32 backstab_dmg = 0; - - ItemInst* botweaponInst = GetBotItem(MainPrimary); + ItemInst* botweaponInst = GetBotItem(EQEmu::legacy::SlotPrimary); if(botweaponInst) { primaryweapondamage = GetWeaponDamage(other, botweaponInst); backstab_dmg = botweaponInst->GetItem()->BackstabDmg; - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; ++i) - { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) { ItemInst *aug = botweaponInst->GetAugment(i); if(aug) - { backstab_dmg += aug->GetItem()->BackstabDmg; - } } - } - else - { - primaryweapondamage = (GetLevel()/7)+1; // fallback incase it's a npc without a weapon, 2 dmg at 10, 10 dmg at 65 + } else { + primaryweapondamage = ((GetLevel() / 7) + 1); backstab_dmg = primaryweapondamage; } - if(primaryweapondamage > 0){ - if(level > 25){ - max_hit = (((2*backstab_dmg) * GetDamageTable(SkillBackstab) / 100) * 10 * GetSkill(SkillBackstab) / 355) + ((level-25)/3) + 1; - hate = 20 * backstab_dmg * GetSkill(SkillBackstab) / 355; - } - else{ - max_hit = (((2*backstab_dmg) * GetDamageTable(SkillBackstab) / 100) * 10 * GetSkill(SkillBackstab) / 355) + 1; - hate = 20 * backstab_dmg * GetSkill(SkillBackstab) / 355; + if(primaryweapondamage > 0) { + if(level > 25) { + max_hit = (((((2 * backstab_dmg) * GetDamageTable(EQEmu::skills::SkillBackstab) / 100) * 10 * GetSkill(EQEmu::skills::SkillBackstab) / 355) + ((level - 25) / 3) + 1) * ((100 + RuleI(Combat, BackstabBonus)) / 100)); + hate = (20 * backstab_dmg * GetSkill(EQEmu::skills::SkillBackstab) / 355); + } else { + max_hit = (((((2 * backstab_dmg) * GetDamageTable(EQEmu::skills::SkillBackstab) / 100) * 10 * GetSkill(EQEmu::skills::SkillBackstab) / 355) + 1) * ((100 + RuleI(Combat, BackstabBonus)) / 100)); + hate = (20 * backstab_dmg * GetSkill(EQEmu::skills::SkillBackstab) / 355); } - // determine minimum hits if (level < 51) - { - min_hit = (level*15/10); - } + min_hit = (level * 15 / 10); else - { - // Trumpcard: Replaced switch statement with formula calc. This will give minhit increases all the way to 65. - min_hit = (level * ( level*5 - 105)) / 100; - } + min_hit = ((level * ( level * 5 - 105)) / 100); - if(!other->CheckHitChance(this, SkillBackstab, 0)) { + if (!other->CheckHitChance(this, EQEmu::skills::SkillBackstab, 0)) ndamage = 0; - } - else{ - if(min_damage){ + else { + if (min_damage) { ndamage = min_hit; - } - else - { + } else { if (max_hit < min_hit) max_hit = min_hit; - if(RuleB(Combat, UseIntervalAC)) - ndamage = max_hit; - else - ndamage = zone->random.Int(min_hit, max_hit); - + ndamage = (RuleB(Combat, UseIntervalAC) ? max_hit : zone->random.Int(min_hit, max_hit)); } } - } - else{ + } else ndamage = -5; - } - DoSpecialAttackDamage(other, SkillBackstab, ndamage, min_hit, hate, ReuseTime); - DoAnim(animPiercing); + DoSpecialAttackDamage(other, EQEmu::skills::SkillBackstab, ndamage, min_hit, hate, ReuseTime); + DoAnim(anim1HPiercing); } -void Bot::RogueAssassinate(Mob* other) -{ - ItemInst* botweaponInst = GetBotItem(MainPrimary); +void Bot::RogueAssassinate(Mob* other) { + ItemInst* botweaponInst = GetBotItem(EQEmu::legacy::SlotPrimary); if(botweaponInst) { - if(GetWeaponDamage(other, botweaponInst)) { - other->Damage(this, 32000, SPELL_UNKNOWN, SkillBackstab); - } - else { - other->Damage(this, -5, SPELL_UNKNOWN, SkillBackstab); - } + if(GetWeaponDamage(other, botweaponInst)) + other->Damage(this, 32000, SPELL_UNKNOWN, EQEmu::skills::SkillBackstab); + else + other->Damage(this, -5, SPELL_UNKNOWN, EQEmu::skills::SkillBackstab); } - DoAnim(animPiercing); //piercing animation + DoAnim(anim1HPiercing); } void Bot::DoClassAttacks(Mob *target, bool IsRiposte) { - if(!target) - return; - - if(spellend_timer.Enabled() || IsFeared() || IsStunned() || IsMezzed() || DivineAura() || GetHP() < 0) - return; - - if(!IsAttackAllowed(target)) + if(!target || spellend_timer.Enabled() || IsFeared() || IsStunned() || IsMezzed() || DivineAura() || GetHP() < 0 || !IsAttackAllowed(target)) return; bool taunt_time = taunt_timer.Check(); bool ca_time = classattack_timer.Check(false); bool ka_time = knightattack_timer.Check(false); - - //only check attack allowed if we are going to do something if((taunt_time || ca_time || ka_time) && !IsAttackAllowed(target)) return; if(ka_time){ - int knightreuse = 1000; //lets give it a small cooldown actually. + int knightreuse = 1000; switch(GetClass()){ - case SHADOWKNIGHT: case SHADOWKNIGHTGM:{ + case SHADOWKNIGHT: + case SHADOWKNIGHTGM: { CastSpell(SPELL_NPC_HARM_TOUCH, target->GetID()); - knightreuse = HarmTouchReuseTime * 1000; + knightreuse = (HarmTouchReuseTime * 1000); break; } - case PALADIN: case PALADINGM:{ + case PALADIN: + case PALADINGM: { if(GetHPRatio() < 20) { CastSpell(SPELL_LAY_ON_HANDS, GetID()); - knightreuse = LayOnHandsReuseTime * 1000; - } else { - knightreuse = 2000; //Check again in two seconds. + knightreuse = (LayOnHandsReuseTime * 1000); } + else + knightreuse = 2000; + break; } } knightattack_timer.Start(knightreuse); } - //general stuff, for all classes.... - //only gets used when their primary ability get used too - - //franck-add: EQoffline. Warrior bots must taunt the target. - if(taunting && target && target->IsNPC() && taunt_time ) { - //Only taunt if we are not top on target's hate list - //This ensures we have taunt available to regain aggro if needed + if(taunting && target && target->IsNPC() && taunt_time) { if(GetTarget() && GetTarget()->GetHateTop() && GetTarget()->GetHateTop() != this) { - Say("Taunting %s", target->GetCleanName()); + BotGroupSay(this, "Taunting %s", target->GetCleanName()); Taunt(target->CastToNPC(), false); taunt_timer.Start(TauntReuseTime * 1000); } @@ -7979,287 +5093,193 @@ void Bot::DoClassAttacks(Mob *target, bool IsRiposte) { if(!ca_time) return; - float HasteModifier = GetHaste() * 0.01f; + float HasteModifier = (GetHaste() * 0.01f); int32 dmg = 0; - uint16 skill_to_use = -1; - int level = GetLevel(); - int reuse = TauntReuseTime * 1000; //make this very long since if they dont use it once, they prolly never will + int reuse = (TauntReuseTime * 1000); bool did_attack = false; + switch(GetClass()) { + case WARRIOR: + if(level >= RuleI(Combat, NPCBashKickLevel)){ + bool canBash = false; + if ((GetRace() == OGRE || GetRace() == TROLL || GetRace() == BARBARIAN) || (m_inv.GetItem(EQEmu::legacy::SlotSecondary) && m_inv.GetItem(EQEmu::legacy::SlotSecondary)->GetItem()->ItemType == EQEmu::item::ItemTypeShield) || (m_inv.GetItem(EQEmu::legacy::SlotPrimary) && m_inv.GetItem(EQEmu::legacy::SlotPrimary)->GetItem()->IsType2HWeapon() && GetAA(aa2HandBash) >= 1)) + canBash = true; - switch(GetClass()) - { - case WARRIOR: - if(level >= RuleI(Combat, NPCBashKickLevel)){ - bool canBash = false; - if((GetRace() == OGRE || GetRace() == TROLL || GetRace() == BARBARIAN) // Racial Slam - || (m_inv.GetItem(MainSecondary) && m_inv.GetItem(MainSecondary)->GetItem()->ItemType == ItemTypeShield) //Using Shield - || (m_inv.GetItem(MainPrimary) && (m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HSlash - || m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HBlunt - || m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HPiercing) - && GetAA(aa2HandBash) >= 1)) { //Using 2 hand weapon, but has AA 2 Hand Bash - canBash = true; + if(!canBash || zone->random.Int(0, 100) > 25) + skill_to_use = EQEmu::skills::SkillKick; + else + skill_to_use = EQEmu::skills::SkillBash; } - - if(!canBash || zone->random.Int(0, 100) > 25) { //tested on live, warrior mobs both kick and bash, kick about 75% of the time, casting doesn't seem to make a difference. - skill_to_use = SkillKick; + case RANGER: + case BEASTLORD: + skill_to_use = EQEmu::skills::SkillKick; + break; + case BERSERKER: + skill_to_use = EQEmu::skills::SkillFrenzy; + break; + case CLERIC: + case SHADOWKNIGHT: + case PALADIN: + if(level >= RuleI(Combat, NPCBashKickLevel)){ + if ((GetRace() == OGRE || GetRace() == TROLL || GetRace() == BARBARIAN) || (m_inv.GetItem(EQEmu::legacy::SlotSecondary) && m_inv.GetItem(EQEmu::legacy::SlotSecondary)->GetItem()->ItemType == EQEmu::item::ItemTypeShield) || (m_inv.GetItem(EQEmu::legacy::SlotPrimary) && m_inv.GetItem(EQEmu::legacy::SlotPrimary)->GetItem()->IsType2HWeapon() && GetAA(aa2HandBash) >= 1)) + skill_to_use = EQEmu::skills::SkillBash; } - else { - skill_to_use = SkillBash; - } - } - case RANGER: - case BEASTLORD: - skill_to_use = SkillKick; - break; - case BERSERKER: - skill_to_use = SkillFrenzy; - break; - case CLERIC: - case SHADOWKNIGHT: - case PALADIN: - if(level >= RuleI(Combat, NPCBashKickLevel)){ - if((GetRace() == OGRE || GetRace() == TROLL || GetRace() == BARBARIAN) // Racial Slam - || (m_inv.GetItem(MainSecondary) && m_inv.GetItem(MainSecondary)->GetItem()->ItemType == ItemTypeShield) //Using Shield - || (m_inv.GetItem(MainPrimary) && (m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HSlash - || m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HBlunt - || m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HPiercing) - && GetAA(aa2HandBash) >= 1)) { //Using 2 hand weapon, but has AA 2 Hand Bash - skill_to_use = SkillBash; - } - } - break; - case MONK: - if(GetLevel() >= 30) - { - skill_to_use = SkillFlyingKick; - } - else if(GetLevel() >= 25) - { - skill_to_use = SkillDragonPunch; - } - else if(GetLevel() >= 20) - { - skill_to_use = SkillEagleStrike; - } - else if(GetLevel() >= 10) - { - skill_to_use = SkillTigerClaw; - } - else if(GetLevel() >= 5) - { - skill_to_use = SkillRoundKick; - } - else - { - skill_to_use = SkillKick; - } - break; - case ROGUE: - skill_to_use = SkillBackstab; - break; + break; + case MONK: + if(GetLevel() >= 30) + skill_to_use = EQEmu::skills::SkillFlyingKick; + else if(GetLevel() >= 25) + skill_to_use = EQEmu::skills::SkillDragonPunch; + else if(GetLevel() >= 20) + skill_to_use = EQEmu::skills::SkillEagleStrike; + else if(GetLevel() >= 10) + skill_to_use = EQEmu::skills::SkillTigerClaw; + else if(GetLevel() >= 5) + skill_to_use = EQEmu::skills::SkillRoundKick; + else + skill_to_use = EQEmu::skills::SkillKick; + break; + case ROGUE: + skill_to_use = EQEmu::skills::SkillBackstab; + break; } if(skill_to_use == -1) return; - - if(skill_to_use == SkillBash) - { - if (target!=this) - { + if (skill_to_use == EQEmu::skills::SkillBash) { + if (target != this) { DoAnim(animTailRake); - - if(GetWeaponDamage(target, GetBotItem(MainSecondary)) <= 0 && - GetWeaponDamage(target, GetBotItem(MainShoulders)) <= 0){ + if (GetWeaponDamage(target, GetBotItem(EQEmu::legacy::SlotSecondary)) <= 0 && GetWeaponDamage(target, GetBotItem(EQEmu::legacy::SlotShoulders)) <= 0) dmg = -5; - } - else{ - if(!target->CheckHitChance(this, SkillBash, 0)) { + else { + if (!target->CheckHitChance(this, EQEmu::skills::SkillBash, 0)) dmg = 0; - } - else{ + else { if(RuleB(Combat, UseIntervalAC)) dmg = GetBashDamage(); else dmg = zone->random.Int(1, GetBashDamage()); - } } - - reuse = BashReuseTime * 1000; - //reuse = (reuse*HasteModifier)/100; - - DoSpecialAttackDamage(target, SkillBash, dmg, 1,-1,reuse); - + reuse = (BashReuseTime * 1000); + DoSpecialAttackDamage(target, EQEmu::skills::SkillBash, dmg, 1, -1, reuse); did_attack = true; - - if(reuse > 0 && !IsRiposte) - { - //p_timers.Start(pTimerCombatAbility, reuse); - } } } - if(skill_to_use == SkillFrenzy) - { + if (skill_to_use == EQEmu::skills::SkillFrenzy) { int AtkRounds = 3; int skillmod = 0; + if (MaxSkill(EQEmu::skills::SkillFrenzy) > 0) + skillmod = (100 * GetSkill(EQEmu::skills::SkillFrenzy) / MaxSkill(EQEmu::skills::SkillFrenzy)); - if(MaxSkill(SkillFrenzy) > 0) - skillmod = 100*GetSkill(SkillFrenzy)/MaxSkill(SkillFrenzy); - - int32 max_dmg = (26 + ((((GetLevel()-6) * 2)*skillmod)/100)) * ((100+RuleI(Combat, FrenzyBonus))/100); + int32 max_dmg = (26 + ((((GetLevel() - 6) * 2) * skillmod) / 100)) * ((100 + RuleI(Combat, FrenzyBonus)) / 100); int32 min_dmg = 0; DoAnim(anim2HSlashing); if (GetLevel() < 51) min_dmg = 1; else - min_dmg = GetLevel()*8/10; + min_dmg = (GetLevel() * 8 / 10); if (min_dmg > max_dmg) max_dmg = min_dmg; - reuse = FrenzyReuseTime * 1000; - //reuse = (reuse * HasteModifier)/100; - + reuse = (FrenzyReuseTime * 1000); did_attack = true; - - //Live parses show around 55% Triple 35% Double 10% Single, you will always get first hit. while(AtkRounds > 0) { - - if (GetTarget() && (AtkRounds == 1 || zone->random.Int(0,100) < 75)){ - DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, max_dmg , reuse, true); + if (GetTarget() && (AtkRounds == 1 || zone->random.Int(0, 100) < 75)) { + DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillFrenzy, max_dmg, min_dmg, max_dmg, reuse, true); } - AtkRounds--; - } - if(reuse > 0 && !IsRiposte) { - //p_timers.Start(pTimerCombatAbility, reuse); + AtkRounds--; } } - if(skill_to_use == SkillKick) - { - if(target!=this) - { + if (skill_to_use == EQEmu::skills::SkillKick) { + if(target != this) { DoAnim(animKick); - - if(GetWeaponDamage(target, GetBotItem(MainFeet)) <= 0){ + if (GetWeaponDamage(target, GetBotItem(EQEmu::legacy::SlotFeet)) <= 0) dmg = -5; - } - else{ - if(!target->CheckHitChance(this, SkillKick, 0)) { + else { + if (!target->CheckHitChance(this, EQEmu::skills::SkillKick, 0)) dmg = 0; - } - else{ + else { if(RuleB(Combat, UseIntervalAC)) dmg = GetKickDamage(); else dmg = zone->random.Int(1, GetKickDamage()); } } - - reuse = KickReuseTime * 1000; - - DoSpecialAttackDamage(target, SkillKick, dmg, 1,-1, reuse); - + reuse = (KickReuseTime * 1000); + DoSpecialAttackDamage(target, EQEmu::skills::SkillKick, dmg, 1, -1, reuse); did_attack = true; } } - if(skill_to_use == SkillFlyingKick || - skill_to_use == SkillDragonPunch || - skill_to_use == SkillEagleStrike || - skill_to_use == SkillTigerClaw || - skill_to_use == SkillRoundKick) - { - reuse = MonkSpecialAttack(target, skill_to_use) - 1; + if (skill_to_use == EQEmu::skills::SkillFlyingKick || skill_to_use == EQEmu::skills::SkillDragonPunch || skill_to_use == EQEmu::skills::SkillEagleStrike || skill_to_use == EQEmu::skills::SkillTigerClaw || skill_to_use == EQEmu::skills::SkillRoundKick) { + reuse = (MonkSpecialAttack(target, skill_to_use) - 1); MonkSpecialAttack(target, skill_to_use); - - //Live AA - Technique of Master Wu - uint32 bDoubleSpecialAttack = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack; - if( bDoubleSpecialAttack && (bDoubleSpecialAttack >= 100 || bDoubleSpecialAttack > zone->random.Int(0,100))) { - - int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick }; - MonkSpecialAttack(target, MonkSPA[zone->random.Int(0,4)]); - + uint32 bDoubleSpecialAttack = (itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack); + if(bDoubleSpecialAttack && (bDoubleSpecialAttack >= 100 || bDoubleSpecialAttack > zone->random.Int(0, 100))) { + int MonkSPA[5] = { EQEmu::skills::SkillFlyingKick, EQEmu::skills::SkillDragonPunch, EQEmu::skills::SkillEagleStrike, EQEmu::skills::SkillTigerClaw, EQEmu::skills::SkillRoundKick }; + MonkSpecialAttack(target, MonkSPA[zone->random.Int(0, 4)]); int TripleChance = 25; - if (bDoubleSpecialAttack > 100) - TripleChance += TripleChance*(100-bDoubleSpecialAttack)/100; + TripleChance += (TripleChance * (100 - bDoubleSpecialAttack) / 100); - if(TripleChance > zone->random.Int(0,100)) { - MonkSpecialAttack(target, MonkSPA[zone->random.Int(0,4)]); - } + if(TripleChance > zone->random.Int(0,100)) + MonkSpecialAttack(target, MonkSPA[zone->random.Int(0, 4)]); } reuse *= 1000; did_attack = true; } - if(skill_to_use == SkillBackstab) - { - reuse = BackstabReuseTime * 1000; + if (skill_to_use == EQEmu::skills::SkillBackstab) { + reuse = (BackstabReuseTime * 1000); did_attack = true; - if (IsRiposte) - reuse=0; + reuse = 0; TryBackstab(target,reuse); } - classattack_timer.Start(reuse / HasteModifier); } -bool Bot::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { +bool Bot::TryHeadShot(Mob* defender, EQEmu::skills::SkillType skillInUse) { bool Result = false; - - if(defender && (defender->GetBodyType() == BT_Humanoid) && (skillInUse == SkillArchery) && (GetClass() == RANGER) && (GetLevel() >= 62)) { + if (defender && (defender->GetBodyType() == BT_Humanoid) && (skillInUse == EQEmu::skills::SkillArchery) && (GetClass() == RANGER) && (GetLevel() >= 62)) { int defenderLevel = defender->GetLevel(); int rangerLevel = GetLevel(); - // Bot Ranger Headshot AA through level 85(Underfoot) - if( GetAA(aaHeadshot) && ((defenderLevel - 46) <= GetAA(aaHeadshot) * 2) ) { - // WildcardX: These chance formula's below are arbitrary. If someone has a better formula that is more - // consistent with live, feel free to update these. + if(GetAA(aaHeadshot) && ((defenderLevel - 46) <= GetAA(aaHeadshot) * 2)) { float AttackerChance = 0.20f + ((float)(rangerLevel - 51) * 0.005f); float DefenderChance = (float)zone->random.Real(0.00f, 1.00f); if(AttackerChance > DefenderChance) { Log.Out(Logs::Detail, Logs::Combat, "Landed a headshot: Attacker chance was %f and Defender chance was %f.", AttackerChance, DefenderChance); - // WildcardX: At the time I wrote this, there wasnt a string id for something like HEADSHOT_BLOW - //entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FINISHING_BLOW, GetName()); entity_list.MessageClose(this, false, 200, MT_CritMelee, "%s has scored a leathal HEADSHOT!", GetName()); defender->Damage(this, (defender->GetMaxHP()+50), SPELL_UNKNOWN, skillInUse); Result = true; - } - else { + } else Log.Out(Logs::Detail, Logs::Combat, "FAILED a headshot: Attacker chance was %f and Defender chance was %f.", AttackerChance, DefenderChance); - } } } - return Result; } -//offensive spell aggro int32 Bot::CheckAggroAmount(uint16 spellid) { - int32 AggroAmount = Mob::CheckAggroAmount(spellid); - + int32 AggroAmount = Mob::CheckAggroAmount(spellid, nullptr); int32 focusAggro = GetBotFocusEffect(BotfocusSpellHateMod, spellid); - AggroAmount = (AggroAmount * (100+focusAggro) / 100); - + AggroAmount = (AggroAmount * (100 + focusAggro) / 100); return AggroAmount; } -int32 Bot::CheckHealAggroAmount(uint16 spellid, uint32 heal_possible) { - int32 AggroAmount = Mob::CheckHealAggroAmount(spellid, heal_possible); - +int32 Bot::CheckHealAggroAmount(uint16 spellid, Mob *target, uint32 heal_possible) { + int32 AggroAmount = Mob::CheckHealAggroAmount(spellid, target, heal_possible); int32 focusAggro = GetBotFocusEffect(BotfocusSpellHateMod, spellid); - AggroAmount = (AggroAmount * (100 + focusAggro) / 100); - return AggroAmount; } @@ -8272,20 +5292,15 @@ void Bot::AI_Stop() { Mob::AI_Stop(); } -//this is called with 'this' as the mob being looked at, and -//iOther the mob who is doing the looking. It should figure out -//what iOther thinks about 'this' FACTION_VALUE Bot::GetReverseFactionCon(Mob* iOther) { - if(iOther->IsBot()) { + if(iOther->IsBot()) return FACTION_ALLY; - } return NPC::GetReverseFactionCon(iOther); } Mob* Bot::GetOwnerOrSelf() { Mob* Result = 0; - if(this->GetBotOwner()) Result = GetBotOwner(); else @@ -8296,106 +5311,64 @@ Mob* Bot::GetOwnerOrSelf() { Mob* Bot::GetOwner() { Mob* Result = 0; - Result = GetBotOwner(); - - if(!Result) { + if(!Result) this->SetBotOwner(0); - } return Result; } -bool Bot::IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined) -{ +bool Bot::IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined) { bool Result = false; - - if(attacker && target) - { - if(attacker == target) - { + if(attacker && target) { + if(attacker == target) { hasRuleDefined = true; Result = false; - } - else if(attacker->IsClient() && target->IsBot() && attacker->CastToClient()->GetPVP() && target->CastToBot()->GetBotOwner()->CastToClient()->GetPVP()) - { + } else if(attacker->IsClient() && target->IsBot() && attacker->CastToClient()->GetPVP() && target->CastToBot()->GetBotOwner()->CastToClient()->GetPVP()) { hasRuleDefined = true; Result = true; - } - else if(attacker->IsClient() && target->IsBot()) - { + } else if(attacker->IsClient() && target->IsBot()) { hasRuleDefined = true; Result = false; - } - else if(attacker->IsBot() && target->IsNPC()) - { + } else if(attacker->IsBot() && target->IsNPC()) { hasRuleDefined = true; Result = true; - } - else if(attacker->IsBot() && !target->IsNPC()) - { + } else if(attacker->IsBot() && !target->IsNPC()) { hasRuleDefined = true; Result = false; - } - else if(attacker->IsPet() && attacker->IsFamiliar()) - { + } else if(attacker->IsPet() && attacker->IsFamiliar()) { hasRuleDefined = true; Result = false; - } - else if(attacker->IsBot() && attacker->CastToBot()->GetBotOwner() && attacker->CastToBot()->GetBotOwner()->CastToClient()->GetPVP()) - { - if(target->IsBot() && target->GetOwner() && target->GetOwner()->CastToClient()->GetPVP()) - { - // my target is a bot and it's owner is pvp + } else if(attacker->IsBot() && attacker->CastToBot()->GetBotOwner() && attacker->CastToBot()->GetBotOwner()->CastToClient()->GetPVP()) { + if(target->IsBot() && target->GetOwner() && target->GetOwner()->CastToClient()->GetPVP()) { hasRuleDefined = true; - if(target->GetOwner() == attacker->GetOwner()) - { - // no attacking if my target's owner is my owner Result = false; - } else - { Result = true; - } - } - else if(target->IsClient() && target->CastToClient()->GetPVP()) - { - // my target is a player and it's pvp + } else if(target->IsClient() && target->CastToClient()->GetPVP()) { hasRuleDefined = true; - if(target == attacker->GetOwner()) - { - // my target cannot be my owner Result = false; - } else - { Result = true; - } - } - else if(target->IsNPC()) - { + } else if(target->IsNPC()) { hasRuleDefined = true; Result = true; - } - else if(!target->IsNPC()) - { + } else if(!target->IsNPC()) { hasRuleDefined = true; Result = false; } } } - return Result; } void Bot::EquipBot(std::string* errorMessage) { - GetBotItems(errorMessage, m_inv); - + GetBotItems(m_inv, errorMessage); const ItemInst* inst = 0; - const Item_Struct* item = 0; - for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) { + const EQEmu::ItemBase* item = 0; + for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= EQEmu::legacy::EQUIPMENT_END; ++i) { inst = GetBotItem(i); if(inst) { item = inst->GetItem(); @@ -8404,33 +5377,14 @@ void Bot::EquipBot(std::string* errorMessage) { return; } } - UpdateEquipmentLight(); } -//// This method is meant to be called by zone or client methods to clean up objects when a client camps, goes LD, zones out or something like that. -//void Bot::DestroyBotRaidObjects(Client* client) { -// if(client) { -// if(client->GetBotRaidID() > 0) { -// BotRaids* br = entity_list.GetBotRaidByMob(client); -// if(br) { -// br->RemoveRaidBots(); -// br = nullptr; -// } -// } -// -// //BotOrderCampAll(client); -// } -//} - -// Orders all the bots owned by the specified client bot owner to camp out of the game void Bot::BotOrderCampAll(Client* c) { if(c) { std::list BotList = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID()); - - for(std::list::iterator botListItr = BotList.begin(); botListItr != BotList.end(); ++botListItr) { + for(std::list::iterator botListItr = BotList.begin(); botListItr != BotList.end(); ++botListItr) (*botListItr)->Camp(); - } } } @@ -8438,11 +5392,9 @@ void Bot::ProcessBotOwnerRefDelete(Mob* botOwner) { if(botOwner) { if(botOwner->IsClient()) { std::list BotList = entity_list.GetBotsByBotOwnerCharacterID(botOwner->CastToClient()->CharacterID()); - if(!BotList.empty()) { for(std::list::iterator botListItr = BotList.begin(); botListItr != BotList.end(); ++botListItr) { Bot* tempBot = *botListItr; - if(tempBot) { tempBot->SetTarget(0); tempBot->SetBotOwner(0); @@ -8455,31 +5407,27 @@ void Bot::ProcessBotOwnerRefDelete(Mob* botOwner) { void Bot::ProcessGuildInvite(Client* guildOfficer, Bot* botToGuild) { if(guildOfficer && botToGuild) { - // Bots can be only guild member rank if(!botToGuild->IsInAGuild()) { - //they are not in this or any other guild, this is an invite if (!guild_mgr.CheckPermission(guildOfficer->GuildID(), guildOfficer->GuildRank(), GUILD_INVITE)) { guildOfficer->Message(13, "You dont have permission to invite."); return; } - // Log.Out(Logs::Detail, Logs::Guilds, "Inviting %s (%d) into guild %s (%d)", botToGuild->GetName(), botToGuild->GetBotID(), guild_mgr.GetGuildName(client->GuildID()), client->GuildID()); - - SetBotGuildMembership(botToGuild->GetBotID(), guildOfficer->GuildID(), GUILD_MEMBER); - - //Log.LogDebugType(Logs::Detail, Logs::Guilds, "Sending char refresh for BOT %s from guild %d to world", botToGuild->GetName(), guildOfficer->GuildID(); - + if (!botdb.SaveGuildMembership(botToGuild->GetBotID(), guildOfficer->GuildID(), GUILD_MEMBER)) { + guildOfficer->Message(13, "%s for '%s'", BotDatabase::fail::SaveGuildMembership(), botToGuild->GetCleanName()); + return; + } + ServerPacket* pack = new ServerPacket(ServerOP_GuildCharRefresh, sizeof(ServerGuildCharRefresh_Struct)); ServerGuildCharRefresh_Struct *s = (ServerGuildCharRefresh_Struct *) pack->pBuffer; s->guild_id = guildOfficer->GuildID(); s->old_guild_id = GUILD_NONE; s->char_id = botToGuild->GetBotID(); worldserver.SendPacket(pack); - safe_delete(pack); + safe_delete(pack); } else { - //they are in some other guild - guildOfficer->Message(13, "Player is in a guild."); + guildOfficer->Message(13, "Bot is in a guild."); return; } } @@ -8487,21 +5435,20 @@ void Bot::ProcessGuildInvite(Client* guildOfficer, Bot* botToGuild) { bool Bot::ProcessGuildRemoval(Client* guildOfficer, std::string botName) { bool Result = false; - if(guildOfficer && !botName.empty()) { Bot* botToUnGuild = entity_list.GetBotByBotName(botName); if(botToUnGuild) { - SetBotGuildMembership(botToUnGuild->GetBotID(), 0, 0); - Result = true; - } - else { - uint32 botId = GetBotIDByBotName(botName); - - if(botId > 0) { - // Bot is camped or in another zone - SetBotGuildMembership(botId, 0, 0); + if (botdb.SaveGuildMembership(botToUnGuild->GetBotID(), 0, 0)) + Result = true; + } else { + uint32 ownerId = 0; + if (!botdb.LoadOwnerID(botName, ownerId)) + guildOfficer->Message(13, "%s for '%s'", BotDatabase::fail::LoadOwnerID(), botName.c_str()); + uint32 botId = 0; + if (!botdb.LoadBotID(ownerId, botName, botId)) + guildOfficer->Message(13, "%s for '%s'", BotDatabase::fail::LoadBotID(), botName.c_str()); + if (botId && botdb.SaveGuildMembership(botId, 0, 0)) Result = true; - } } if(Result) { @@ -8514,226 +5461,138 @@ bool Bot::ProcessGuildRemoval(Client* guildOfficer, std::string botName) { safe_delete(outapp); } } - return Result; } -void Bot::SetBotGuildMembership(uint32 botId, uint32 guildid, uint8 rank) { - if(botId == 0) - return; - - if(guildid > 0) { - std::string query = StringFormat("REPLACE INTO botguildmembers " - "SET char_id = %u, guild_id = %u, rank = %u;", - botId, guildid, rank); - auto results = database.QueryDatabase(query); - return; - } - - std::string query = StringFormat("DELETE FROM botguildmembers WHERE char_id = %u;", botId); - auto results = database.QueryDatabase(query); -} - -void Bot::LoadGuildMembership(uint32* guildId, uint8* guildRank, std::string* guildName) { - - if(guildId == nullptr || guildRank == nullptr || guildName == nullptr) - return; - - std::string query = StringFormat("SELECT gm.guild_id, gm.rank, g.name " - "FROM vwGuildMembers AS gm JOIN guilds AS g " - "ON gm.guild_id = g.id " - "WHERE gm.char_id = %u AND gm.mobtype = 'B';", - GetBotID()); - auto results = database.QueryDatabase(query); - if(!results.Success() || results.RowCount() == 0) - return; - - auto row = results.begin(); - *guildId = atoi(row[0]); - *guildRank = atoi(row[1]); - *guildName = std::string(row[2]); -} - int32 Bot::CalcMaxMana() { - switch(GetCasterClass()) - { + switch(GetCasterClass()) { case 'I': - case 'W': - { + case 'W': { max_mana = (GenerateBaseManaPoints() + itembonuses.Mana + spellbonuses.Mana + GroupLeadershipAAManaEnhancement()); break; } - case 'N': - { + case 'N': { max_mana = 0; break; } - default: - { + default: { Log.Out(Logs::General, Logs::None, "Invalid Class '%c' in CalcMaxMana", GetCasterClass()); max_mana = 0; break; } } - if(cur_mana > max_mana) { + if(cur_mana > max_mana) cur_mana = max_mana; - } - else if(max_mana < 0) { + else if(max_mana < 0) max_mana = 0; - } return max_mana; } void Bot::SetAttackTimer() { - float haste_mod = GetHaste() * 0.01f; - - //default value for attack timer in case they have - //an invalid weapon equipped: + float haste_mod = (GetHaste() * 0.01f); attack_timer.SetAtTrigger(4000, true); - Timer* TimerToUse = nullptr; - const Item_Struct* PrimaryWeapon = nullptr; - - for (int i = MainRange; i <= MainSecondary; i++) { - //pick a timer - if (i == MainPrimary) + const EQEmu::ItemBase* PrimaryWeapon = nullptr; + for (int i = EQEmu::legacy::SlotRange; i <= EQEmu::legacy::SlotSecondary; i++) { + if (i == EQEmu::legacy::SlotPrimary) TimerToUse = &attack_timer; - else if (i == MainRange) + else if (i == EQEmu::legacy::SlotRange) TimerToUse = &ranged_timer; - else if (i == MainSecondary) + else if (i == EQEmu::legacy::SlotSecondary) TimerToUse = &attack_dw_timer; - else //invalid slot (hands will always hit this) + else continue; - const Item_Struct* ItemToUse = nullptr; + const EQEmu::ItemBase* ItemToUse = nullptr; ItemInst* ci = GetBotItem(i); if (ci) ItemToUse = ci->GetItem(); - //special offhand stuff - if (i == MainSecondary) { - //if we have a 2H weapon in our main hand, no dual + if (i == EQEmu::legacy::SlotSecondary) { if (PrimaryWeapon != nullptr) { - if (PrimaryWeapon->ItemClass == ItemClassCommon - && (PrimaryWeapon->ItemType == ItemType2HSlash - || PrimaryWeapon->ItemType == ItemType2HBlunt - || PrimaryWeapon->ItemType == ItemType2HPiercing)) { + if (PrimaryWeapon->IsClassCommon() && PrimaryWeapon->IsType2HWeapon()) { attack_dw_timer.Disable(); continue; } } - //clients must have the skill to use it... - if (!GetSkill(SkillDualWield)) { + if (!GetSkill(EQEmu::skills::SkillDualWield)) { attack_dw_timer.Disable(); continue; } } - //see if we have a valid weapon if (ItemToUse != nullptr) { - //check type and damage/delay - if (ItemToUse->ItemClass != ItemClassCommon - || ItemToUse->Damage == 0 - || ItemToUse->Delay == 0) { - //no weapon + if (!ItemToUse->IsClassCommon() || ItemToUse->Damage == 0 || ItemToUse->Delay == 0 || ((ItemToUse->ItemType > EQEmu::item::ItemTypeLargeThrowing) && (ItemToUse->ItemType != EQEmu::item::ItemTypeMartial) && (ItemToUse->ItemType != EQEmu::item::ItemType2HPiercing))) ItemToUse = nullptr; - } - // Check to see if skill is valid - else if ((ItemToUse->ItemType > ItemTypeLargeThrowing) && (ItemToUse->ItemType != ItemTypeMartial) && (ItemToUse->ItemType != ItemType2HPiercing)) { - //no weapon - ItemToUse = nullptr; - } } - int hhe = itembonuses.HundredHands + spellbonuses.HundredHands; + int hhe = (itembonuses.HundredHands + spellbonuses.HundredHands); int speed = 0; int delay = 36; - - //if we have no weapon.. if (ItemToUse == nullptr) { - //above checks ensure ranged weapons do not fall into here - // Work out if we're a monk - if ((GetClass() == MONK) || (GetClass() == BEASTLORD)) - delay = GetMonkHandToHandDelay(); + delay = GetHandToHandDelay(); } else { - //we have a weapon, use its delay delay = ItemToUse->Delay; } - if (RuleB(Spells, Jun182014HundredHandsRevamp)) - speed = static_cast(((delay / haste_mod) + ((hhe / 1000.0f) * (delay / haste_mod))) * 100); - else - speed = static_cast(((delay / haste_mod) + ((hhe / 100.0f) * delay)) * 100); + + speed = (RuleB(Spells, Jun182014HundredHandsRevamp) ? static_cast(((delay / haste_mod) + ((hhe / 1000.0f) * (delay / haste_mod))) * 100) : static_cast(((delay / haste_mod) + ((hhe / 100.0f) * delay)) * 100)); TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true); - if(i == MainPrimary) + if (i == EQEmu::legacy::SlotPrimary) PrimaryWeapon = ItemToUse; } } int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { - if (spells[spell_id].targettype == ST_Self) return value; bool Critical = false; int32 value_BaseEffect = 0; - - value_BaseEffect = value + (value*GetBotFocusEffect(BotfocusFcBaseEffects, spell_id)/100); - + value_BaseEffect = (value + (value*GetBotFocusEffect(BotfocusFcBaseEffects, spell_id) / 100)); // Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40. if ( (spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40) - value -= (GetLevel() - 40) * 20; + value -= ((GetLevel() - 40) * 20); //This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch. if (spell_id == SPELL_IMP_HARM_TOUCH) //Improved Harm Touch - value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch + value -= (GetAA(aaUnholyTouch) * 450); //Unholy Touch int chance = RuleI(Spells, BaseCritChance); - chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance; + chance += (itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance); - if (chance > 0){ + if (chance > 0) { + int32 ratio = RuleI(Spells, BaseCritRatio); + if (spell_id == SPELL_IMP_HARM_TOUCH && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0)) + chance = 100; - int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals. - - //Improved Harm Touch is a guaranteed crit if you have at least one level of SCF. - if (spell_id == SPELL_IMP_HARM_TOUCH && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0)) - chance = 100; - - if (zone->random.Int(1,100) <= chance){ + if (zone->random.Int(1, 100) <= chance){ Critical = true; - ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease; - ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack; - } - - else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (zone->random.Int(1,100) <= RuleI(Spells, WizCritChance))) { - ratio = zone->random.Int(1,100); //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. + ratio += (itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease); + ratio += (itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack); + } else if (GetClass() == WIZARD && (GetLevel() >= RuleI(Spells, WizCritLevel)) && (zone->random.Int(1, 100) <= RuleI(Spells, WizCritChance))) { + ratio = zone->random.Int(1, 100); Critical = true; } - - ratio += RuleI(Spells, WizCritRatio); //Default is zero - - if (Critical){ - - value = value_BaseEffect*ratio/100; - - value += value_BaseEffect*GetBotFocusEffect(BotfocusImprovedDamage, spell_id)/100; - - value += int(value_BaseEffect*GetBotFocusEffect(BotfocusFcDamagePctCrit, spell_id)/100)*ratio/100; - + ratio += RuleI(Spells, WizCritRatio); + if (Critical) { + value = (value_BaseEffect * ratio / 100); + value += (value_BaseEffect * GetBotFocusEffect(BotfocusImprovedDamage, spell_id) / 100); + value += (int(value_BaseEffect * GetBotFocusEffect(BotfocusFcDamagePctCrit, spell_id) / 100) * ratio / 100); if (target) { - value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100; + value += (int(value_BaseEffect * target->GetVulnerability(this, spell_id, 0) / 100) * ratio / 100); value -= target->GetFcDamageAmtIncoming(this, spell_id); } - value -= GetBotFocusEffect(BotfocusFcDamageAmtCrit, spell_id)*ratio/100; + value -= (GetBotFocusEffect(BotfocusFcDamageAmtCrit, spell_id) * ratio / 100); value -= GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); - if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; + if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) + value += (GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value) * ratio / 100); entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value); @@ -8741,29 +5600,23 @@ int32 Bot::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { } } - value = value_BaseEffect; - - value += value_BaseEffect*GetBotFocusEffect(BotfocusImprovedDamage, spell_id)/100; - - value += value_BaseEffect*GetBotFocusEffect(BotfocusFcDamagePctCrit, spell_id)/100; - - if (target) { - value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100; + value = value_BaseEffect; + value += (value_BaseEffect * GetBotFocusEffect(BotfocusImprovedDamage, spell_id) / 100); + value += (value_BaseEffect * GetBotFocusEffect(BotfocusFcDamagePctCrit, spell_id) / 100); + if (target) { + value += (value_BaseEffect * target->GetVulnerability(this, spell_id, 0) / 100); value -= target->GetFcDamageAmtIncoming(this, spell_id); - } + } - value -= GetBotFocusEffect(BotfocusFcDamageAmtCrit, spell_id); - - value -= GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); - - if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); + value -= GetBotFocusEffect(BotfocusFcDamageAmtCrit, spell_id); + value -= GetBotFocusEffect(BotfocusFcDamageAmt, spell_id); + if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) + value += GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); return value; } int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { - if (target == nullptr) target = this; @@ -8771,72 +5624,52 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { int32 chance = 0; int8 modifier = 1; bool Critical = false; - - value_BaseEffect = value + (value*GetBotFocusEffect(BotfocusFcBaseEffects, spell_id)/100); - + value_BaseEffect = (value + (value*GetBotFocusEffect(BotfocusFcBaseEffects, spell_id) / 100)); value = value_BaseEffect; - - value += int(value_BaseEffect*GetBotFocusEffect(BotfocusImprovedHeal, spell_id)/100); - - // Instant Heals + value += int(value_BaseEffect*GetBotFocusEffect(BotfocusImprovedHeal, spell_id) / 100); if(spells[spell_id].buffduration < 1) { - - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - + chance += (itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance); chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); - if (spellbonuses.CriticalHealDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); - if(chance && (zone->random.Int(0,99) < chance)) { + if(chance && (zone->random.Int(0, 99) < chance)) { Critical = true; - modifier = 2; //At present time no critical heal amount modifier SPA exists. + modifier = 2; } value *= modifier; - value += GetBotFocusEffect(BotfocusFcHealAmtCrit, spell_id) * modifier; + value += (GetBotFocusEffect(BotfocusFcHealAmtCrit, spell_id) * modifier); value += GetBotFocusEffect(BotfocusFcHealAmt, spell_id); value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); - if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier; - - value += value*target->GetHealRate(spell_id, this)/100; + if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) + value += (GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier); + value += (value * target->GetHealRate(spell_id, this) / 100); if (Critical) entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value); return value; - } - - //Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value] - else { - - chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; - + } else { + chance = (itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime); chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); - if (spellbonuses.CriticalRegenDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); if(chance && (zone->random.Int(0,99) < chance)) return (value * 2); } - return value; } int32 Bot::GetActSpellCasttime(uint16 spell_id, int32 casttime) { int32 cast_reducer = 0; cast_reducer += GetBotFocusEffect(BotfocusSpellHaste, spell_id); - uint8 botlevel = GetLevel(); uint8 botclass = GetClass(); - - if (botlevel >= 51 && casttime >= 3000 && !BeneficialSpell(spell_id) - && (botclass == SHADOWKNIGHT || botclass == RANGER - || botclass == PALADIN || botclass == BEASTLORD )) - cast_reducer += (GetLevel()-50)*3; + if (botlevel >= 51 && casttime >= 3000 && !BeneficialSpell(spell_id) && (botclass == SHADOWKNIGHT || botclass == RANGER || botclass == PALADIN || botclass == BEASTLORD )) + cast_reducer += ((GetLevel() - 50) * 3); if((casttime >= 4000) && BeneficialSpell(spell_id) && IsBuffSpell(spell_id)) { switch (GetAA(aaSpellCastingDeftness)) { @@ -8909,86 +5742,70 @@ int32 Bot::GetActSpellCasttime(uint16 spell_id, int32 casttime) { if (cast_reducer > RuleI(Spells, MaxCastTimeReduction)) cast_reducer = RuleI(Spells, MaxCastTimeReduction); - casttime = (casttime*(100 - cast_reducer)/100); - + casttime = (casttime * (100 - cast_reducer) / 100); return casttime; } int32 Bot::GetActSpellCost(uint16 spell_id, int32 cost) { - // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell - if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) - { - int32 mana_back = this->itembonuses.Clairvoyance * zone->random.Int(1, 100) / 100; - // Doesnt generate mana, so best case is a free spell + if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%17) - 1] >= GetLevel() - 5) { + int32 mana_back = (this->itembonuses.Clairvoyance * zone->random.Int(1, 100) / 100); if(mana_back > cost) mana_back = cost; cost -= mana_back; } - // This formula was derived from the following resource: - // http://www.eqsummoners.com/eq1/specialization-library.html - // WildcardX float PercentManaReduction = 0; float SpecializeSkill = GetSpecializeSkillValue(spell_id); int SuccessChance = zone->random.Int(0, 100); - float bonus = 1.0; - switch(GetAA(aaSpellCastingMastery)) - { - case 1: - bonus += 0.05; - break; - case 2: - bonus += 0.15; - break; - case 3: - bonus += 0.30; - break; + switch(GetAA(aaSpellCastingMastery)) { + case 1: + bonus += 0.05; + break; + case 2: + bonus += 0.15; + break; + case 3: + bonus += 0.30; + break; } - bonus += 0.05 * GetAA(aaAdvancedSpellCastingMastery); + bonus += (0.05 * GetAA(aaAdvancedSpellCastingMastery)); - if(SuccessChance <= (SpecializeSkill * 0.3 * bonus)) - { - PercentManaReduction = 1 + 0.05 * SpecializeSkill; - switch(GetAA(aaSpellCastingMastery)) - { - case 1: - PercentManaReduction += 2.5; - break; - case 2: - PercentManaReduction += 5.0; - break; - case 3: - PercentManaReduction += 10.0; - break; + if(SuccessChance <= (SpecializeSkill * 0.3 * bonus)) { + PercentManaReduction = (1 + 0.05 * SpecializeSkill); + switch(GetAA(aaSpellCastingMastery)) { + case 1: + PercentManaReduction += 2.5; + break; + case 2: + PercentManaReduction += 5.0; + break; + case 3: + PercentManaReduction += 10.0; + break; } - switch(GetAA(aaAdvancedSpellCastingMastery)) - { - case 1: - PercentManaReduction += 2.5; - break; - case 2: - PercentManaReduction += 5.0; - break; - case 3: - PercentManaReduction += 10.0; - break; + switch(GetAA(aaAdvancedSpellCastingMastery)) { + case 1: + PercentManaReduction += 2.5; + break; + case 2: + PercentManaReduction += 5.0; + break; + case 3: + PercentManaReduction += 10.0; + break; } } int32 focus_redux = GetBotFocusEffect(BotfocusManaCost, spell_id); if(focus_redux > 0) - { PercentManaReduction += zone->random.Real(1, (double)focus_redux); - } cost -= (cost * (PercentManaReduction / 100)); - - // Gift of Mana - reduces spell cost to 1 mana if(focus_redux >= 100) { uint32 buff_max = GetMaxTotalSlots(); for (int buffSlot = 0; buffSlot < buff_max; buffSlot++) { @@ -9011,17 +5828,15 @@ int32 Bot::GetActSpellCost(uint16 spell_id, int32 cost) { float Bot::GetActSpellRange(uint16 spell_id, float range) { float extrange = 100; extrange += GetBotFocusEffect(BotfocusRange, spell_id); - return (range * extrange) / 100; + return ((range * extrange) / 100); } int32 Bot::GetActSpellDuration(uint16 spell_id, int32 duration) { int increase = 100; increase += GetBotFocusEffect(BotfocusSpellDuration, spell_id); - int tic_inc = 0; - tic_inc = GetBotFocusEffect(BotfocusSpellDurByTic, spell_id); + int tic_inc = 0; tic_inc = GetBotFocusEffect(BotfocusSpellDurByTic, spell_id); - if(IsBeneficialSpell(spell_id)) - { + if(IsBeneficialSpell(spell_id)) { switch (GetAA(aaSpellCastingReinforcement)) { case 1: increase += 5; @@ -9033,6 +5848,7 @@ int32 Bot::GetActSpellDuration(uint16 spell_id, int32 duration) { increase += 30; if (GetAA(aaSpellCastingReinforcementMastery) == 1) increase += 20; + break; } @@ -9040,142 +5856,120 @@ int32 Bot::GetActSpellDuration(uint16 spell_id, int32 duration) { increase += 20; } - if(IsMezSpell(spell_id)) { + if(IsMezSpell(spell_id)) tic_inc += GetAA(aaMesmerizationMastery); - } return (((duration * increase) / 100) + tic_inc); } float Bot::GetAOERange(uint16 spell_id) { float range; - range = spells[spell_id].aoerange; - if(range == 0) //for TGB spells, they prolly do not have an aoe range - range = spells[spell_id].range; if(range == 0) - range = 10; //something.... + range = spells[spell_id].range; + + if(range == 0) + range = 10; if(IsBardSong(spell_id) && IsBeneficialSpell(spell_id)) { - //Live AA - Extended Notes, SionachiesCrescendo - float song_bonus = aabonuses.SongRange + spellbonuses.SongRange + itembonuses.SongRange; - range += range*song_bonus /100.0f; + float song_bonus = (aabonuses.SongRange + spellbonuses.SongRange + itembonuses.SongRange); + range += (range * song_bonus / 100.0f); } - range = GetActSpellRange(spell_id, range); - return range; } bool Bot::SpellEffect(Mob* caster, uint16 spell_id, float partial) { bool Result = false; - Result = Mob::SpellEffect(caster, spell_id, partial); - - // Franck-add: If healed/doted, a bot must show its new HP to its leader if(IsGrouped()) { Group *g = GetGroup(); if(g) { EQApplicationPacket hp_app; CreateHPPacket(&hp_app); - for(int i=0; imembers[i] && g->members[i]->IsClient()) { + for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { + if(g->members[i] && g->members[i]->IsClient()) g->members[i]->CastToClient()->QueuePacket(&hp_app); - } } } } - return Result; } -void Bot::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster) { - Mob::DoBuffTic(spell_id, slot, ticsremaining, caster_level, caster); +void Bot::DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster) { + Mob::DoBuffTic(buff, slot, caster); } -bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, int16 *resist_adjust) { +bool Bot::CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot, int32 cast_time, int32 mana_cost, + uint32* oSpellWillFinish, uint32 item_slot, int16 *resist_adjust, uint32 aa_id) { bool Result = false; - if(zone && !zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))) { - - Log.Out(Logs::Detail, Logs::Spells, "CastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item slot %d", - spells[spell_id].name, spell_id, target_id, slot, cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot); + Log.Out(Logs::Detail, Logs::Spells, "CastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item slot %d", spells[spell_id].name, spell_id, target_id, slot, cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot); if(casting_spell_id == spell_id) ZeroCastingVars(); if(GetClass() != BARD) { if(!IsValidSpell(spell_id) || casting_spell_id || delaytimer || spellend_timer.Enabled() || IsStunned() || IsFeared() || IsMezzed() || (IsSilenced() && !IsDiscipline(spell_id)) || (IsAmnesiad() && IsDiscipline(spell_id))) { - Log.Out(Logs::Detail, Logs::Spells, "Spell casting canceled: not able to cast now. Valid? %d, casting %d, waiting? %d, spellend? %d, stunned? %d, feared? %d, mezed? %d, silenced? %d", - IsValidSpell(spell_id), casting_spell_id, delaytimer, spellend_timer.Enabled(), IsStunned(), IsFeared(), IsMezzed(), IsSilenced() ); + Log.Out(Logs::Detail, Logs::Spells, "Spell casting canceled: not able to cast now. Valid? %d, casting %d, waiting? %d, spellend? %d, stunned? %d, feared? %d, mezed? %d, silenced? %d", IsValidSpell(spell_id), casting_spell_id, delaytimer, spellend_timer.Enabled(), IsStunned(), IsFeared(), IsMezzed(), IsSilenced() ); if(IsSilenced() && !IsDiscipline(spell_id)) Message_StringID(13, SILENCED_STRING); + if(IsAmnesiad() && IsDiscipline(spell_id)) + Message_StringID(13, MELEE_SILENCE); + if(casting_spell_id) - AI_Event_SpellCastFinished(false, casting_spell_slot); - return(false); + AI_Event_SpellCastFinished(false, static_cast(casting_spell_slot)); + + return false; } } if(IsDetrimentalSpell(spell_id) && !zone->CanDoCombat()){ Message_StringID(13, SPELL_WOULDNT_HOLD); if(casting_spell_id) - AI_Event_SpellCastFinished(false, casting_spell_slot); - return(false); + AI_Event_SpellCastFinished(false, static_cast(casting_spell_slot)); + + return false; } - //cannot cast under deivne aura if(DivineAura()) { Log.Out(Logs::Detail, Logs::Spells, "Spell casting canceled: cannot cast while Divine Aura is in effect."); InterruptSpell(173, 0x121, false); - return(false); + return false; } - // check for fizzle - // note that CheckFizzle itself doesn't let NPCs fizzle, - // but this code allows for it. - if(slot < MAX_PP_MEMSPELL && !CheckFizzle(spell_id)) - { + if(slot < EQEmu::CastingSlot::MaxGems && !CheckFizzle(spell_id)) { int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE; InterruptSpell(fizzle_msg, 0x121, spell_id); uint32 use_mana = ((spells[spell_id].mana) / 4); Log.Out(Logs::Detail, Logs::Spells, "Spell casting canceled: fizzled. %d mana has been consumed", use_mana); - - // fizzle 1/4 the mana away SetMana(GetMana() - use_mana); - return(false); + return false; } if (HasActiveSong()) { Log.Out(Logs::Detail, Logs::Spells, "Casting a new spell/song while singing a song. Killing old song %d.", bardsong); - //Note: this does NOT tell the client - //_StopSong(); bardsong = 0; bardsong_target_id = 0; - bardsong_slot = 0; + bardsong_slot = EQEmu::CastingSlot::Gem1; bardsong_timer.Disable(); } - Result = DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot); + Result = DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, aa_id); } - return Result; } bool Bot::SpellOnTarget(uint16 spell_id, Mob* spelltar) { bool Result = false; - if(!IsValidSpell(spell_id)) return false; if(spelltar) { if(spelltar->IsBot() && (spells[spell_id].targettype == ST_GroupTeleport)) { - // So I made this check because teleporting a group of bots tended to crash the zone - // It seems several group spells also show up as ST_GroupTeleport for some - // reason so I now have to check by spell id. These appear to be Group v1 spells and - // Heal over Time spells. switch(spell_id) { // Paladin case 3577: // Wave of Life @@ -9246,50 +6040,39 @@ bool Bot::SpellOnTarget(uint16 spell_id, Mob* spelltar) { } } - //Franck-add: can't detrimental spell on bots and bots can't detriment on you or the others bots if(((IsDetrimentalSpell(spell_id) && spelltar->IsBot()) || (IsDetrimentalSpell(spell_id) && spelltar->IsClient())) && !IsResurrectionEffects(spell_id)) return false; if(spelltar->IsPet()) { - for(int i=0; iGetZoneID() == 202) && !(this == caster)) { Result = Mob::IsImmuneToSpell(spell_id, caster); - if(!Result) { if(caster->IsBot()) { if(spells[spell_id].targettype == ST_Undead) { if((GetBodyType() != BT_SummonedUndead) && (GetBodyType() != BT_Undead) && (GetBodyType() != BT_Vampire)) { - Log.Out(Logs::Detail, Logs::Spells, "Bot's target is not an undead."); - return true; + Log.Out(Logs::Detail, Logs::Spells, "Bot's target is not an undead."); + return true; } } if(spells[spell_id].targettype == ST_Summoned) { - if((GetBodyType() != BT_SummonedUndead) - && (GetBodyType() != BT_Summoned) - && (GetBodyType() != BT_Summoned2) - && (GetBodyType() != BT_Summoned3) - ) { - Log.Out(Logs::Detail, Logs::Spells, "Bot's target is not a summoned creature."); - return true; + if((GetBodyType() != BT_SummonedUndead) && (GetBodyType() != BT_Summoned) && (GetBodyType() != BT_Summoned2) && (GetBodyType() != BT_Summoned3)) { + Log.Out(Logs::Detail, Logs::Spells, "Bot's target is not a summoned creature."); + return true; } } } @@ -9301,192 +6084,151 @@ bool Bot::IsImmuneToSpell(uint16 spell_id, Mob *caster) { return Result; } -bool Bot::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction) { +bool Bot::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQEmu::CastingSlot slot) { bool Result = false; - SpellTargetType targetType = spells[spell_id].targettype; - - - // This is so PoK NPC Necro/Shd can create essence emeralds for pc's from perl scripts if(targetType == ST_GroupClientAndPet) { - if(((spell_id == 1768) && (zone->GetZoneID() == 202)) || (!IsDetrimentalSpell(spell_id))) { + if((spell_id == 1768 && zone->GetZoneID() == 202) || (!IsDetrimentalSpell(spell_id))) { CastAction = SingleTarget; return true; } } - - Result = Mob::DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction); - + Result = Mob::DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction, slot); return Result; } -bool Bot::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot) { +bool Bot::DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, uint32 aa_id) { bool Result = false; - - if(GetClass() == BARD) { - // Bard bots casting time is interrupting thier melee + if(GetClass() == BARD) cast_time = 0; - } - Result = Mob::DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot); + Result = Mob::DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, aa_id); if(oSpellWillFinish) { const SPDat_Spell_Struct &spell = spells[spell_id]; *oSpellWillFinish = Timer::GetCurrentTime() + ((spell.recast_time > 20000) ? 10000 : spell.recast_time); } - return Result; } -int32 Bot::GenerateBaseManaPoints() -{ - // Now, we need to calc the base mana. +int32 Bot::GenerateBaseManaPoints() { int32 bot_mana = 0; int32 WisInt = 0; int32 MindLesserFactor, MindFactor; int wisint_mana = 0; int base_mana = 0; int ConvertedWisInt = 0; - - switch(GetCasterClass()) - { + switch(GetCasterClass()) { case 'I': WisInt = INT; - if(GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->GetClientVersion() >= ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { if(WisInt > 100) { ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100); - if(WisInt > 201) { + if(WisInt > 201) ConvertedWisInt -= ((WisInt - 201) * 5 / 4); - } } - else { + else ConvertedWisInt = WisInt; - } + if(GetLevel() < 41) { wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000); base_mana = (GetLevel() * 15); - } - else if(GetLevel() < 81) { + } else if(GetLevel() < 81) { wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100)); base_mana = (600 + ((GetLevel() - 40) * 30)); - } - else { + } else { wisint_mana = (9 * ConvertedWisInt); base_mana = (1800 + ((GetLevel() - 80) * 18)); } - bot_mana = base_mana + wisint_mana; - } - else { - if((( WisInt - 199 ) / 2) > 0) { - MindLesserFactor = ( WisInt - 199 ) / 2; - } - else { + bot_mana = (base_mana + wisint_mana); + } else { + if(((WisInt - 199) / 2) > 0) + MindLesserFactor = ((WisInt - 199) / 2); + else MindLesserFactor = 0; - } + MindFactor = WisInt - MindLesserFactor; - if(WisInt > 100) { + if(WisInt > 100) bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40); - } - else { + else bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100); - } } break; - case 'W': WisInt = WIS; - if(GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->GetClientVersion() >= ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { if(WisInt > 100) { ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100); - if(WisInt > 201) { + if(WisInt > 201) ConvertedWisInt -= ((WisInt - 201) * 5 / 4); - } - } - else { + } else ConvertedWisInt = WisInt; - } + if(GetLevel() < 41) { wisint_mana = (GetLevel() * 75 * ConvertedWisInt / 1000); base_mana = (GetLevel() * 15); - } - else if(GetLevel() < 81) { + } else if(GetLevel() < 81) { wisint_mana = ((3 * ConvertedWisInt) + ((GetLevel() - 40) * 15 * ConvertedWisInt / 100)); base_mana = (600 + ((GetLevel() - 40) * 30)); - } - else { + } else { wisint_mana = (9 * ConvertedWisInt); base_mana = (1800 + ((GetLevel() - 80) * 18)); } - bot_mana = base_mana + wisint_mana; - } - else { - if((( WisInt - 199 ) / 2) > 0) { - MindLesserFactor = ( WisInt - 199 ) / 2; - } - else { + bot_mana = (base_mana + wisint_mana); + } else { + if(((WisInt - 199) / 2) > 0) + MindLesserFactor = ((WisInt - 199) / 2); + else MindLesserFactor = 0; - } - MindFactor = WisInt - MindLesserFactor; - if(WisInt > 100) { + + MindFactor = (WisInt - MindLesserFactor); + if(WisInt > 100) bot_mana = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40); - } - else { + else bot_mana = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100); - } } break; - default: bot_mana = 0; break; } - max_mana = bot_mana; - return bot_mana; } -void Bot::GenerateSpecialAttacks() -{ - // Special Attacks - if(((GetClass() == MONK) || (GetClass() == WARRIOR) || (GetClass() == RANGER) || (GetClass() == BERSERKER)) && (GetLevel() >= 60)) { +void Bot::GenerateSpecialAttacks() { + if(((GetClass() == MONK) || (GetClass() == WARRIOR) || (GetClass() == RANGER) || (GetClass() == BERSERKER)) && (GetLevel() >= 60)) SetSpecialAbility(SPECATK_TRIPLE, 1); - } } -bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool& stopLogic) { +bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool& stopLogic) { if(GetClass() == BARD) { - if(!ApplyNextBardPulse(bardsong, this, bardsong_slot)) { + if(!ApplyNextBardPulse(bardsong, this, bardsong_slot)) InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong); - } + stopLogic = true; } - return true; } -bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool& stopLogic) { +bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool& stopLogic) { if(spellTarget) { - if(IsGrouped() && (spellTarget->IsBot() || spellTarget->IsClient()) && RuleB(Bots, BotGroupBuffing)) { - //NPC *bot = this->CastToNPC(); + if(IsGrouped() && (spellTarget->IsBot() || spellTarget->IsClient()) && RuleB(Bots, GroupBuffing)) { bool noGroupSpell = false; uint16 thespell = spell_id; - - for(int i=0; i < AIspells.size(); i++) { + for(int i = 0; i < AIspells.size(); i++) { int j = BotGetSpells(i); int spelltype = BotGetSpellType(i); bool spellequal = (j == thespell); bool spelltypeequal = ((spelltype == 2) || (spelltype == 16) || (spelltype == 32)); bool spelltypetargetequal = ((spelltype == 8) && (spells[thespell].targettype == ST_Self)); bool spelltypeclassequal = ((spelltype == 1024) && (GetClass() == SHAMAN)); - bool slotequal = (slot == USE_ITEM_SPELL_SLOT); - - // if it's a targeted heal or escape spell or pet spell or it's self only buff or self buff weapon proc, we only want to cast it once + bool slotequal = (slot == EQEmu::CastingSlot::Item); if(spellequal || slotequal) { if((spelltypeequal || spelltypetargetequal) || spelltypeclassequal || slotequal) { - // Don't let the Shaman canni themselves to death if(((spells[thespell].effectid[0] == 0) && (spells[thespell].base[0] < 0)) && (spellTarget->GetHP() < ((spells[thespell].base[0] * (-1)) + 100))) { + Log.Out(Logs::General, Logs::Spells, "Bot::DoFinishedSpellSingleTarget - GroupBuffing failure"); return false; } @@ -9500,81 +6242,55 @@ bool Bot::DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, uint16 if(!noGroupSpell) { Group *g = GetGroup(); if(g) { - for(int i=0; imembers[i]) { - if((g->members[i]->GetClass() == NECROMANCER) && - (IsEffectInSpell(thespell, SE_AbsorbMagicAtt) || IsEffectInSpell(thespell, SE_Rune))) { - // don't cast this on necro's, their health to mana - // spell eats up the rune spell and it just keeps - // getting recast over and over + if((g->members[i]->GetClass() == NECROMANCER) && (IsEffectInSpell(thespell, SE_AbsorbMagicAtt) || IsEffectInSpell(thespell, SE_Rune))) { } else - { SpellOnTarget(thespell, g->members[i]); - } - if(g->members[i] && g->members[i]->GetPetID()) { + + if(g->members[i] && g->members[i]->GetPetID()) SpellOnTarget(thespell, g->members[i]->GetPet()); - } } } SetMana(GetMana() - (GetActSpellCost(thespell, spells[thespell].mana) * (g->GroupCount() - 1))); } } - stopLogic = true; } } - return true; } -bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool& stopLogic) { +bool Bot::DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool& stopLogic) { bool isMainGroupMGB = false; - - //if(GetBotRaidID() > 0) { - // BotRaids *br = entity_list.GetBotRaidByMob(this); - // if(br) { - // for(int n=0; nBotRaidGroups[0] && (br->BotRaidGroups[0]->members[n] == this)) { - // if(GetLevel() >= 59) // MGB AA - // isMainGroupMGB = true; - // break; - // } - // } - // } - //} - if(isMainGroupMGB && (GetClass() != BARD)) { - Say("MGB %s", spells[spell_id].name); + BotGroupSay(this, "MGB %s", spells[spell_id].name); SpellOnTarget(spell_id, this); entity_list.AESpell(this, this, spell_id, true); - } - else { + } else { Group *g = GetGroup(); if(g) { - for(int i=0; imembers[i]) { SpellOnTarget(spell_id, g->members[i]); - if(g->members[i] && g->members[i]->GetPetID()) { + if(g->members[i] && g->members[i]->GetPetID()) SpellOnTarget(spell_id, g->members[i]->GetPet()); - } } } } } - stopLogic = true; - return true; } void Bot::CalcBonuses() { + memset(&itembonuses, 0, sizeof(StatBonuses)); GenerateBaseStats(); - CalcItemBonuses(); + CalcItemBonuses(&itembonuses); CalcSpellBonuses(&spellbonuses); - GenerateAABonuses(&aabonuses); + CalcAABonuses(&aabonuses); SetAttackTimer(); - CalcATK(); CalcSTR(); CalcSTA(); @@ -9583,16 +6299,13 @@ void Bot::CalcBonuses() { CalcINT(); CalcWIS(); CalcCHA(); - CalcMR(); CalcFR(); CalcDR(); CalcPR(); CalcCR(); CalcCorrup(); - GenerateArmorClass(); - CalcMaxHP(); CalcMaxMana(); CalcMaxEndurance(); @@ -9604,17 +6317,14 @@ void Bot::CalcBonuses() { int32 Bot::CalcHPRegenCap(){ int level = GetLevel(); int32 hpregen_cap = 0; - hpregen_cap = RuleI(Character, ItemHealthRegenCap) + itembonuses.HeroicSTA/25; - - hpregen_cap += aabonuses.ItemHPRegenCap + spellbonuses.ItemHPRegenCap + itembonuses.ItemHPRegenCap; - + hpregen_cap = (RuleI(Character, ItemHealthRegenCap) + itembonuses.HeroicSTA / 25); + hpregen_cap += (aabonuses.ItemHPRegenCap + spellbonuses.ItemHPRegenCap + itembonuses.ItemHPRegenCap); return (hpregen_cap * RuleI(Character, HPRegenMultiplier) / 100); } int32 Bot::CalcManaRegenCap(){ int32 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap; - switch(GetCasterClass()) - { + switch(GetCasterClass()) { case 'I': cap += (itembonuses.HeroicINT / 25); break; @@ -9622,36 +6332,27 @@ int32 Bot::CalcManaRegenCap(){ cap += (itembonuses.HeroicWIS / 25); break; } - return (cap * RuleI(Character, ManaRegenMultiplier) / 100); } -// Return max stat value for level int32 Bot::GetMaxStat() { int level = GetLevel(); int32 base = 0; - - if (level < 61) { + if (level < 61) base = 255; - } - else if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->GetClientVersion() >= ClientVersion::SoF) { - base = 255 + 5 * (level - 60); - } - else if (level < 71) { - base = 255 + 5 * (level - 60); - } - else { + else if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoF) + base = (255 + 5 * (level - 60)); + else if (level < 71) + base = (255 + 5 * (level - 60)); + else base = 330; - } - return(base); + return base; } int32 Bot::GetMaxResist() { int level = GetLevel(); - int32 base = 500; - if(level > 60) base += ((level - 60) * 5); @@ -9659,93 +6360,63 @@ int32 Bot::GetMaxResist() { } int32 Bot::GetMaxSTR() { - return GetMaxStat() - + itembonuses.STRCapMod - + spellbonuses.STRCapMod - + aabonuses.STRCapMod; + return (GetMaxStat() + itembonuses.STRCapMod + spellbonuses.STRCapMod + aabonuses.STRCapMod); } + int32 Bot::GetMaxSTA() { - return GetMaxStat() - + itembonuses.STACapMod - + spellbonuses.STACapMod - + aabonuses.STACapMod; + return (GetMaxStat() + itembonuses.STACapMod + spellbonuses.STACapMod + aabonuses.STACapMod); } + int32 Bot::GetMaxDEX() { - return GetMaxStat() - + itembonuses.DEXCapMod - + spellbonuses.DEXCapMod - + aabonuses.DEXCapMod; + return (GetMaxStat() + itembonuses.DEXCapMod + spellbonuses.DEXCapMod + aabonuses.DEXCapMod); } + int32 Bot::GetMaxAGI() { - return GetMaxStat() - + itembonuses.AGICapMod - + spellbonuses.AGICapMod - + aabonuses.AGICapMod; + return (GetMaxStat() + itembonuses.AGICapMod + spellbonuses.AGICapMod + aabonuses.AGICapMod); } + int32 Bot::GetMaxINT() { - return GetMaxStat() - + itembonuses.INTCapMod - + spellbonuses.INTCapMod - + aabonuses.INTCapMod; + return (GetMaxStat() + itembonuses.INTCapMod + spellbonuses.INTCapMod + aabonuses.INTCapMod); } + int32 Bot::GetMaxWIS() { - return GetMaxStat() - + itembonuses.WISCapMod - + spellbonuses.WISCapMod - + aabonuses.WISCapMod; + return (GetMaxStat() + itembonuses.WISCapMod + spellbonuses.WISCapMod + aabonuses.WISCapMod); } int32 Bot::GetMaxCHA() { - return GetMaxStat() - + itembonuses.CHACapMod - + spellbonuses.CHACapMod - + aabonuses.CHACapMod; + return (GetMaxStat() + itembonuses.CHACapMod + spellbonuses.CHACapMod + aabonuses.CHACapMod); } + int32 Bot::GetMaxMR() { - return GetMaxResist() - + itembonuses.MRCapMod - + spellbonuses.MRCapMod - + aabonuses.MRCapMod; + return (GetMaxResist() + itembonuses.MRCapMod + spellbonuses.MRCapMod + aabonuses.MRCapMod); } + int32 Bot::GetMaxPR() { - return GetMaxResist() - + itembonuses.PRCapMod - + spellbonuses.PRCapMod - + aabonuses.PRCapMod; + return (GetMaxResist() + itembonuses.PRCapMod + spellbonuses.PRCapMod + aabonuses.PRCapMod); } + int32 Bot::GetMaxDR() { - return GetMaxResist() - + itembonuses.DRCapMod - + spellbonuses.DRCapMod - + aabonuses.DRCapMod; + return (GetMaxResist() + itembonuses.DRCapMod + spellbonuses.DRCapMod + aabonuses.DRCapMod); } + int32 Bot::GetMaxCR() { - return GetMaxResist() - + itembonuses.CRCapMod - + spellbonuses.CRCapMod - + aabonuses.CRCapMod; + return (GetMaxResist() + itembonuses.CRCapMod + spellbonuses.CRCapMod + aabonuses.CRCapMod); } + int32 Bot::GetMaxFR() { - return GetMaxResist() - + itembonuses.FRCapMod - + spellbonuses.FRCapMod - + aabonuses.FRCapMod; + return (GetMaxResist() + itembonuses.FRCapMod + spellbonuses.FRCapMod + aabonuses.FRCapMod); } + int32 Bot::GetMaxCorrup() { - return GetMaxResist() - + itembonuses.CorrupCapMod - + spellbonuses.CorrupCapMod - + aabonuses.CorrupCapMod; + return (GetMaxResist() + itembonuses.CorrupCapMod + spellbonuses.CorrupCapMod + aabonuses.CorrupCapMod); } int32 Bot::CalcSTR() { - int32 val = STR + itembonuses.STR + spellbonuses.STR; - + int32 val = (STR + itembonuses.STR + spellbonuses.STR); int32 mod = aabonuses.STR; - - if(val>255 && GetLevel() <= 60) + if(val > 255 && GetLevel() <= 60) val = 255; - STR = val + mod; + STR = (val + mod); if(STR < 1) STR = 1; @@ -9753,18 +6424,16 @@ int32 Bot::CalcSTR() { if(STR > m) STR = m; - return(STR); + return STR; } int32 Bot::CalcSTA() { - int32 val = STA + itembonuses.STA + spellbonuses.STA; - + int32 val = (STA + itembonuses.STA + spellbonuses.STA); int32 mod = aabonuses.STA; - - if(val>255 && GetLevel() <= 60) + if(val > 255 && GetLevel() <= 60) val = 255; - STA = val + mod; + STA = (val + mod); if(STA < 1) STA = 1; @@ -9772,18 +6441,16 @@ int32 Bot::CalcSTA() { if(STA > m) STA = m; - return(STA); + return STA; } int32 Bot::CalcAGI() { - int32 val = AGI + itembonuses.AGI + spellbonuses.AGI; + int32 val = (AGI + itembonuses.AGI + spellbonuses.AGI); int32 mod = aabonuses.AGI; - - if(val>255 && GetLevel() <= 60) + if(val > 255 && GetLevel() <= 60) val = 255; - AGI = val + mod; - + AGI = (val + mod); if(AGI < 1) AGI = 1; @@ -9791,18 +6458,16 @@ int32 Bot::CalcAGI() { if(AGI > m) AGI = m; - return(AGI); + return AGI; } int32 Bot::CalcDEX() { - int32 val = DEX + itembonuses.DEX + spellbonuses.DEX; - + int32 val = (DEX + itembonuses.DEX + spellbonuses.DEX); int32 mod = aabonuses.DEX; - - if(val>255 && GetLevel() <= 60) + if(val > 255 && GetLevel() <= 60) val = 255; - DEX = val + mod; + DEX = (val + mod); if(DEX < 1) DEX = 1; @@ -9810,35 +6475,34 @@ int32 Bot::CalcDEX() { if(DEX > m) DEX = m; - return(DEX); + return DEX; } int32 Bot::CalcINT() { - int32 val = INT + itembonuses.INT + spellbonuses.INT; - + int32 val = (INT + itembonuses.INT + spellbonuses.INT); int32 mod = aabonuses.INT; - - if(val>255 && GetLevel() <= 60) + if(val > 255 && GetLevel() <= 60) val = 255; - INT = val + mod; + + INT = (val + mod); if(INT < 1) INT = 1; + int m = GetMaxINT(); if(INT > m) INT = m; - return(INT); + return INT; } int32 Bot::CalcWIS() { - int32 val = WIS + itembonuses.WIS + spellbonuses.WIS; - + int32 val = (WIS + itembonuses.WIS + spellbonuses.WIS); int32 mod = aabonuses.WIS; - - if(val>255 && GetLevel() <= 60) + if(val > 255 && GetLevel() <= 60) val = 255; - WIS = val + mod; + + WIS = (val + mod); if(WIS < 1) WIS = 1; @@ -9847,17 +6511,16 @@ int32 Bot::CalcWIS() { if(WIS > m) WIS = m; - return(WIS); + return WIS; } int32 Bot::CalcCHA() { - int32 val = CHA + itembonuses.CHA + spellbonuses.CHA; - + int32 val = (CHA + itembonuses.CHA + spellbonuses.CHA); int32 mod = aabonuses.CHA; - - if(val>255 && GetLevel() <= 60) + if(val > 255 && GetLevel() <= 60) val = 255; - CHA = val + mod; + + CHA = (val + mod); if(CHA < 1) CHA = 1; @@ -9866,18 +6529,13 @@ int32 Bot::CalcCHA() { if(CHA > m) CHA = m; - return(CHA); + return CHA; } -//The AA multipliers are set to be 5, but were 2 on WR -//The resistant discipline which I think should be here is implemented -//in Mob::ResistSpell -int32 Bot::CalcMR() -{ - MR += itembonuses.MR + spellbonuses.MR + aabonuses.MR; - +int32 Bot::CalcMR() { + MR += (itembonuses.MR + spellbonuses.MR + aabonuses.MR); if(GetClass() == WARRIOR) - MR += GetLevel() / 2; + MR += (GetLevel() / 2); if(MR < 1) MR = 1; @@ -9885,21 +6543,19 @@ int32 Bot::CalcMR() if(MR > GetMaxMR()) MR = GetMaxMR(); - return(MR); + return MR; } -int32 Bot::CalcFR() -{ +int32 Bot::CalcFR() { int c = GetClass(); if(c == RANGER) { FR += 4; - int l = GetLevel(); if(l > 49) - FR += l - 49; + FR += (l - 49); } - FR += itembonuses.FR + spellbonuses.FR + aabonuses.FR; + FR += (itembonuses.FR + spellbonuses.FR + aabonuses.FR); if(FR < 1) FR = 1; @@ -9907,57 +6563,48 @@ int32 Bot::CalcFR() if(FR > GetMaxFR()) FR = GetMaxFR(); - return(FR); + return FR; } -int32 Bot::CalcDR() -{ +int32 Bot::CalcDR() { int c = GetClass(); if(c == PALADIN) { DR += 8; - int l = GetLevel(); if(l > 49) - DR += l - 49; - + DR += (l - 49); } else if(c == SHADOWKNIGHT) { DR += 4; - int l = GetLevel(); if(l > 49) - DR += l - 49; + DR += (l - 49); } - DR += itembonuses.DR + spellbonuses.DR + aabonuses.DR; - + DR += (itembonuses.DR + spellbonuses.DR + aabonuses.DR); if(DR < 1) DR = 1; if(DR > GetMaxDR()) DR = GetMaxDR(); - return(DR); + return DR; } -int32 Bot::CalcPR() -{ +int32 Bot::CalcPR() { int c = GetClass(); if(c == ROGUE) { PR += 8; - int l = GetLevel(); if(l > 49) - PR += l - 49; - + PR += (l - 49); } else if(c == SHADOWKNIGHT) { PR += 4; - int l = GetLevel(); if(l > 49) - PR += l - 49; + PR += (l - 49); } - PR += itembonuses.PR + spellbonuses.PR + aabonuses.PR; + PR += (itembonuses.PR + spellbonuses.PR + aabonuses.PR); if(PR < 1) PR = 1; @@ -9965,21 +6612,19 @@ int32 Bot::CalcPR() if(PR > GetMaxPR()) PR = GetMaxPR(); - return(PR); + return PR; } -int32 Bot::CalcCR() -{ +int32 Bot::CalcCR() { int c = GetClass(); if(c == RANGER) { CR += 4; - int l = GetLevel(); if(l > 49) - CR += l - 49; + CR += (l - 49); } - CR += itembonuses.CR + spellbonuses.CR + aabonuses.CR; + CR += (itembonuses.CR + spellbonuses.CR + aabonuses.CR); if(CR < 1) CR = 1; @@ -9987,39 +6632,28 @@ int32 Bot::CalcCR() if(CR > GetMaxCR()) CR = GetMaxCR(); - return(CR); + return CR; } -int32 Bot::CalcCorrup() -{ - Corrup = Corrup + itembonuses.Corrup + spellbonuses.Corrup + aabonuses.Corrup; - +int32 Bot::CalcCorrup() { + Corrup = (Corrup + itembonuses.Corrup + spellbonuses.Corrup + aabonuses.Corrup); if(Corrup > GetMaxCorrup()) Corrup = GetMaxCorrup(); - return(Corrup); + return Corrup; } int32 Bot::CalcATK() { - ATK = itembonuses.ATK + spellbonuses.ATK + aabonuses.ATK + GroupLeadershipAAOffenseEnhancement(); - return(ATK); + ATK = (itembonuses.ATK + spellbonuses.ATK + aabonuses.ATK + GroupLeadershipAAOffenseEnhancement()); + return ATK; } void Bot::CalcRestState() { - - // This method calculates rest state HP and mana regeneration. - // The bot must have been out of combat for RuleI(Character, RestRegenTimeToActivate) seconds, - // must be sitting down, and must not have any detrimental spells affecting them. - // if(!RuleI(Character, RestRegenPercent)) return; RestRegenHP = RestRegenMana = RestRegenEndurance = 0; - - if(IsEngaged() || !IsSitting()) - return; - - if(!rest_timer.Check(false)) + if(IsEngaged() || !IsSitting() || !rest_timer.Check(false)) return; uint32 buff_count = GetMaxTotalSlots(); @@ -10032,44 +6666,35 @@ void Bot::CalcRestState() { } RestRegenHP = (GetMaxHP() * RuleI(Character, RestRegenPercent) / 100); - RestRegenMana = (GetMaxMana() * RuleI(Character, RestRegenPercent) / 100); - if(RuleB(Character, RestRegenEndurance)) RestRegenEndurance = (GetMaxEndurance() * RuleI(Character, RestRegenPercent) / 100); } -int32 Bot::LevelRegen() -{ +int32 Bot::LevelRegen() { int level = GetLevel(); - bool bonus = GetRaceBitmask(_baseRace) & RuleI(Character, BaseHPRegenBonusRaces); + bool bonus = GetPlayerRaceBit(_baseRace) & RuleI(Character, BaseHPRegenBonusRaces); uint8 multiplier1 = bonus ? 2 : 1; int32 hp = 0; - - //these calculations should match up with the info from Monkly Business, which was last updated ~05/2008: http://www.monkly-business.net/index.php?pageid=abilities if (level < 51) { if (IsSitting()) { if (level < 20) - hp += 2 * multiplier1; + hp += (2 * multiplier1); else if (level < 50) - hp += 3 * multiplier1; - else //level == 50 - hp += 4 * multiplier1; - } - else //feigned or standing - hp += 1 * multiplier1; - } - //there may be an easier way to calculate this next part, but I don't know what it is - else { //level >= 51 + hp += (3 * multiplier1); + else + hp += (4 * multiplier1); + } else + hp += (1 * multiplier1); + } else { int32 tmp = 0; float multiplier2 = 1; if (level < 56) { tmp = 2; if (bonus) multiplier2 = 3; - } - else if (level < 60) { - tmp = 3; + } else if (level < 60) { + tmp = 3; if (bonus) multiplier2 = 3.34; } @@ -10077,56 +6702,44 @@ int32 Bot::LevelRegen() tmp = 4; if (bonus) multiplier2 = 3; - } - else if (level < 63) { + } else if (level < 63) { tmp = 5; if (bonus) multiplier2 = 2.8; - } - else if (level < 65) { + } else if (level < 65) { tmp = 6; if (bonus) multiplier2 = 2.67; - } - else { //level >= 65 + } else { tmp = 7; if (bonus) multiplier2 = 2.58; } - - hp += int32(float(tmp) * multiplier2); + hp += (int32(float(tmp) * multiplier2)); } - return hp; } int32 Bot::CalcHPRegen() { - int32 regen = LevelRegen() + itembonuses.HPRegen + spellbonuses.HPRegen; - regen += aabonuses.HPRegen + GroupLeadershipAAHealthRegeneration(); - - regen = (regen * RuleI(Character, HPRegenMultiplier)) / 100; + int32 regen = (LevelRegen() + itembonuses.HPRegen + spellbonuses.HPRegen); + regen += (aabonuses.HPRegen + GroupLeadershipAAHealthRegeneration()); + regen = ((regen * RuleI(Character, HPRegenMultiplier)) / 100); return regen; } -int32 Bot::CalcManaRegen() -{ +int32 Bot::CalcManaRegen() { uint8 level = GetLevel(); uint8 botclass = GetClass(); int32 regen = 0; - //this should be changed so we dont med while camping, etc... - if (IsSitting()) - { + if (IsSitting()) { BuffFadeBySitModifier(); if(botclass != WARRIOR && botclass != MONK && botclass != ROGUE && botclass != BERSERKER) { - regen = (((GetSkill(SkillMeditate) / 10) + (level - (level / 4))) / 4) + 4; - regen += spellbonuses.ManaRegen + itembonuses.ManaRegen; - } - else - regen = 2 + spellbonuses.ManaRegen + itembonuses.ManaRegen; - } - else { - regen = 2 + spellbonuses.ManaRegen + itembonuses.ManaRegen; - } + regen = ((((GetSkill(EQEmu::skills::SkillMeditate) / 10) + (level - (level / 4))) / 4) + 4); + regen += (spellbonuses.ManaRegen + itembonuses.ManaRegen); + } else + regen = (2 + spellbonuses.ManaRegen + itembonuses.ManaRegen); + } else + regen = (2 + spellbonuses.ManaRegen + itembonuses.ManaRegen); if(GetCasterClass() == 'I') regen += (itembonuses.HeroicINT / 25); @@ -10136,37 +6749,18 @@ int32 Bot::CalcManaRegen() regen = 0; regen += aabonuses.ManaRegen; - - regen = (regen * RuleI(Character, ManaRegenMultiplier)) / 100; - - float mana_regen_rate = RuleR(Bots, BotManaRegen); + regen = ((regen * RuleI(Character, ManaRegenMultiplier)) / 100); + float mana_regen_rate = RuleR(Bots, ManaRegen); if(mana_regen_rate < 0.0f) mana_regen_rate = 0.0f; - regen = regen * mana_regen_rate; // 90% of people wouldnt guess that manaregen would decrease the larger the number they input, this makes more sense - + regen = (regen * mana_regen_rate); return regen; } -// This is for calculating Base HPs + STA bonus for SoD or later clients. uint32 Bot::GetClassHPFactor() { - - int factor; - - // Note: Base HP factor under level 41 is equal to factor / 12, and from level 41 to 80 is factor / 6. - // Base HP over level 80 is factor / 10 - // HP per STA point per level is factor / 30 for level 80+ - // HP per STA under level 40 is the level 80 HP Per STA / 120, and for over 40 it is / 60. - - switch(GetClass()) - { - case DRUID: - case ENCHANTER: - case NECROMANCER: - case MAGICIAN: - case WIZARD: - factor = 240; - break; + uint32 factor; + switch(GetClass()) { case BEASTLORD: case BERSERKER: case MONK: @@ -10198,47 +6792,36 @@ uint32 Bot::GetClassHPFactor() { int32 Bot::CalcMaxHP() { int32 bot_hp = 0; uint32 nd = 10000; - - bot_hp += GenerateBaseHitPoints() + itembonuses.HP; - - nd += aabonuses.MaxHP; //Natural Durability, Physical Enhancement, Planar Durability - - bot_hp = (float)bot_hp * (float)nd / (float)10000; //this is to fix the HP-above-495k issue - bot_hp += spellbonuses.HP + aabonuses.HP; - + bot_hp += (GenerateBaseHitPoints() + itembonuses.HP); + nd += aabonuses.MaxHP; + bot_hp = ((float)bot_hp * (float)nd / (float)10000); + bot_hp += (spellbonuses.HP + aabonuses.HP); bot_hp += GroupLeadershipAAHealthEnhancement(); - - bot_hp += bot_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f); + bot_hp += (bot_hp * ((spellbonuses.MaxHPChange + itembonuses.MaxHPChange) / 10000.0f)); max_hp = bot_hp; - if (cur_hp > max_hp) cur_hp = max_hp; int hp_perc_cap = spellbonuses.HPPercCap[0]; if(hp_perc_cap) { - int curHP_cap = (max_hp * hp_perc_cap) / 100; + int curHP_cap = ((max_hp * hp_perc_cap) / 100); if (cur_hp > curHP_cap || (spellbonuses.HPPercCap[1] && cur_hp > spellbonuses.HPPercCap[1])) cur_hp = curHP_cap; } - return max_hp; } -int32 Bot::CalcMaxEndurance() -{ - max_end = CalcBaseEndurance() + spellbonuses.Endurance + itembonuses.Endurance; - - if (max_end < 0) { +int32 Bot::CalcMaxEndurance() { + max_end = (CalcBaseEndurance() + spellbonuses.Endurance + itembonuses.Endurance); + if (max_end < 0) max_end = 0; - } - if (cur_end > max_end) { + if (cur_end > max_end) cur_end = max_end; - } int end_perc_cap = spellbonuses.EndPercCap[0]; if(end_perc_cap) { - int curEnd_cap = (max_end * end_perc_cap) / 100; + int curEnd_cap = ((max_end * end_perc_cap) / 100); if (cur_end > curEnd_cap || (spellbonuses.EndPercCap[1] && cur_end > spellbonuses.EndPercCap[1])) cur_end = curEnd_cap; } @@ -10246,49 +6829,37 @@ int32 Bot::CalcMaxEndurance() return max_end; } -int32 Bot::CalcBaseEndurance() -{ +int32 Bot::CalcBaseEndurance() { int32 base_end = 0; int32 base_endurance = 0; int32 ConvertedStats = 0; int32 sta_end = 0; int Stats = 0; - - if(GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->GetClientVersion() >= ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { int HeroicStats = 0; - Stats = ((GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4); HeroicStats = ((GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4); - if (Stats > 100) { ConvertedStats = (((Stats - 100) * 5 / 2) + 100); - if (Stats > 201) { + if (Stats > 201) ConvertedStats -= ((Stats - 201) * 5 / 4); - } - } - else { + } else ConvertedStats = Stats; - } if (GetLevel() < 41) { sta_end = (GetLevel() * 75 * ConvertedStats / 1000); base_endurance = (GetLevel() * 15); - } - else if (GetLevel() < 81) { + } else if (GetLevel() < 81) { sta_end = ((3 * ConvertedStats) + ((GetLevel() - 40) * 15 * ConvertedStats / 100)); base_endurance = (600 + ((GetLevel() - 40) * 30)); - } - else { + } else { sta_end = (9 * ConvertedStats); base_endurance = (1800 + ((GetLevel() - 80) * 18)); } base_end = (base_endurance + sta_end + (HeroicStats * 10)); - } - else - { - Stats = GetSTR()+GetSTA()+GetDEX()+GetAGI(); - int LevelBase = GetLevel() * 15; - + } else { + Stats = (GetSTR()+GetSTA()+GetDEX()+GetAGI()); + int LevelBase = (GetLevel() * 15); int at_most_800 = Stats; if(at_most_800 > 800) at_most_800 = 800; @@ -10297,57 +6868,45 @@ int32 Bot::CalcBaseEndurance() int HalfBonus400to800 = 0; int Bonus800plus = 0; int HalfBonus800plus = 0; - - int BonusUpto800 = int( at_most_800 / 4 ) ; + int BonusUpto800 = int(at_most_800 / 4) ; if(Stats > 400) { - Bonus400to800 = int( (at_most_800 - 400) / 4 ); - HalfBonus400to800 = int( std::max( ( at_most_800 - 400 ), 0 ) / 8 ); - + Bonus400to800 = int((at_most_800 - 400) / 4); + HalfBonus400to800 = int(std::max((at_most_800 - 400), 0) / 8); if(Stats > 800) { - Bonus800plus = int( (Stats - 800) / 8 ) * 2; - HalfBonus800plus = int( (Stats - 800) / 16 ); + Bonus800plus = (int((Stats - 800) / 8) * 2); + HalfBonus800plus = int((Stats - 800) / 16); } } - int bonus_sum = BonusUpto800 + Bonus400to800 + HalfBonus400to800 + Bonus800plus + HalfBonus800plus; - + int bonus_sum = (BonusUpto800 + Bonus400to800 + HalfBonus400to800 + Bonus800plus + HalfBonus800plus); base_end = LevelBase; - - //take all of the sums from above, then multiply by level*0.075 - base_end += ( bonus_sum * 3 * GetLevel() ) / 40; + base_end += ((bonus_sum * 3 * GetLevel()) / 40); } return base_end; } int32 Bot::CalcEnduranceRegen() { - int32 regen = int32(GetLevel() * 4 / 10) + 2; - regen += spellbonuses.EnduranceRegen + itembonuses.EnduranceRegen; - + int32 regen = (int32(GetLevel() * 4 / 10) + 2); + regen += (spellbonuses.EnduranceRegen + itembonuses.EnduranceRegen); return (regen * RuleI(Character, EnduranceRegenMultiplier) / 100); } int32 Bot::CalcEnduranceRegenCap() { - int cap = (RuleI(Character, ItemEnduranceRegenCap) + itembonuses.HeroicSTR/25 + itembonuses.HeroicDEX/25 + itembonuses.HeroicAGI/25 + itembonuses.HeroicSTA/25); - + int cap = (RuleI(Character, ItemEnduranceRegenCap) + itembonuses.HeroicSTR / 25 + itembonuses.HeroicDEX / 25 + itembonuses.HeroicAGI / 25 + itembonuses.HeroicSTA / 25); return (cap * RuleI(Character, EnduranceRegenMultiplier) / 100); } -void Bot::SetEndurance(int32 newEnd) -{ - /*Endurance can't be less than 0 or greater than max*/ +void Bot::SetEndurance(int32 newEnd) { if(newEnd < 0) newEnd = 0; - else if(newEnd > GetMaxEndurance()){ + else if(newEnd > GetMaxEndurance()) newEnd = GetMaxEndurance(); - } cur_end = newEnd; } void Bot::DoEnduranceUpkeep() { int upkeep_sum = 0; - - int cost_redux = spellbonuses.EnduranceReduction + itembonuses.EnduranceReduction; - + int cost_redux = (spellbonuses.EnduranceReduction + itembonuses.EnduranceReduction); uint32 buffs_i; uint32 buff_count = GetMaxTotalSlots(); for (buffs_i = 0; buffs_i < buff_count; buffs_i++) { @@ -10356,15 +6915,15 @@ void Bot::DoEnduranceUpkeep() { if(upkeep > 0) { if(cost_redux > 0) { if(upkeep <= cost_redux) - continue; //reduced to 0 + continue; + upkeep -= cost_redux; } - if((upkeep+upkeep_sum) > GetEndurance()) { - //they do not have enough to keep this one going. + + if((upkeep+upkeep_sum) > GetEndurance()) BuffFadeBySlot(buffs_i); - } else { + else upkeep_sum += upkeep; - } } } } @@ -10376,13 +6935,10 @@ void Bot::DoEnduranceUpkeep() { void Bot::Camp(bool databaseSave) { Sit(); - if(IsGrouped()) { + if(IsGrouped()) RemoveBotFromGroup(this, GetGroup()); - } - if(GetInHealRotation()) { - GetHealRotationLeader()->RemoveHealRotationMember(this); - } + LeaveHealRotationMemberPool(); if(databaseSave) Save(); @@ -10391,9 +6947,8 @@ void Bot::Camp(bool databaseSave) { } void Bot::Zone() { - if(HasGroup()) { + if(HasGroup()) GetGroup()->MemberZoned(this); - } Save(); Depop(); @@ -10401,38 +6956,26 @@ void Bot::Zone() { bool Bot::IsArcheryRange(Mob *target) { bool result = false; - if(target) { - float range = GetBotArcheryRange() + 5.0; //Fudge it a little, client will let you hit something at 0 0 0 when you are at 205 0 0 - + float range = (GetBotArcheryRange() + 5.0); range *= range; - float targetDistance = DistanceSquaredNoZ(m_Position, target->GetPosition()); - - float minRuleDistance = RuleI(Combat, MinRangedAttackDist) * RuleI(Combat, MinRangedAttackDist); - + float minRuleDistance = (RuleI(Combat, MinRangedAttackDist) * RuleI(Combat, MinRangedAttackDist)); if((targetDistance > range) || (targetDistance < minRuleDistance)) result = false; else result = true; } - return result; } bool Bot::IsBotCasterCombatRange(Mob *target) { bool result = false; - if(target) { float range = BotAISpellRange; - range *= range; - - // half the max so the bot doesn't always stop at max range to allow combat movement range *= .5; - float targetDistance = DistanceSquaredNoZ(m_Position, target->GetPosition()); - if(targetDistance > range) result = false; else @@ -10445,36 +6988,28 @@ bool Bot::IsBotCasterCombatRange(Mob *target) { bool Bot::IsGroupPrimaryHealer() { bool result = false; uint8 botclass = GetClass(); - if(HasGroup()) { Group *g = GetGroup(); - - switch(botclass) - { - case CLERIC: - { + switch(botclass) { + case CLERIC: { result = true; break; } - case DRUID: - { + case DRUID: { result = GroupHasClericClass(g) ? false : true; break; } - case SHAMAN: - { + case SHAMAN: { result = (GroupHasClericClass(g) || GroupHasDruidClass(g)) ? false : true; break; } case PALADIN: case RANGER: - case BEASTLORD: - { + case BEASTLORD: { result = GroupHasPriestClass(g) ? false : true; break; } - default: - { + default: { result = false; break; } @@ -10487,29 +7022,22 @@ bool Bot::IsGroupPrimaryHealer() { bool Bot::IsGroupPrimarySlower() { bool result = false; uint8 botclass = GetClass(); - if(HasGroup()) { Group *g = GetGroup(); - - switch(botclass) - { - case SHAMAN: - { + switch(botclass) { + case SHAMAN: { result = true; break; } - case ENCHANTER: - { + case ENCHANTER: { result = GroupHasShamanClass(g) ? false : true; break; } - case BEASTLORD: - { + case BEASTLORD: { result = (GroupHasShamanClass(g) || GroupHasEnchanterClass(g)) ? false : true; break; } - default: - { + default: { result = false; break; } @@ -10532,177 +7060,20 @@ bool Bot::CanHeal() { botSpell = GetFirstBotSpellBySpellType(this, SpellType_Heal); - if(botSpell.SpellId != 0){ + if(botSpell.SpellId != 0) result = true; - } - - /*if(GetFirstBotSpellBySpellType(this, SpellType_Heal)){ - result = true; - }*/ return result; } bool Bot::CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ) { - // 2.5625 is the inverse of 0.3902439. The only difference is in implementation. - // NOTE: You can not change just one of the constants below. They are the same number, just expressed inversly of each other. - // const float clientOverServerRatio = 2.5625f; - const float serverOverClientRatio = 0.3902439f; - - // Use this block if using 2.5625 as the ratio. - // const int clientAnimationMovementRateTypeMultiple = 8; - - // WildcardX: These are valid rates and observations based on painstaking testing of the client response to these values - // - // - // 0 * 8 = 0 : No Movement - // 1 * 8 = 8 : Death Walk - // 2 * 8 = 16 : Slow Walk - // 3 * 8 = 24 : Normal Walk - // 4 * 8 = 32 : Jog - // 5 * 8 = 40 : Normal Run - // 6 * 8 = 48 : Faster Run - // 7 * 8 = 56 : Even Faster Run - // 8 * 8 = 64 : Fastest Yet Run (Bard Song Speed?) - // 9 * 8 = 72 : Faster Fastest Yet Run - // 10 * 8 = 80 : .... you get the idea, this is pretty fast - // 11 * 8 = 88 : .... warp speed anyone? - // 12 * 8 = 96 : .... transwarp drive was invented by gnomes in Norrath - // 13 * 8 = 104 : ... who needs warp drives when you can just displace through time and space? - // - // - // You get the idea here with these... These seem to be "benchmark values" of animation movement and how fast - // the client thinks the Mob is moving so it can make it all look seemless between updates from the server. - // This chart is scalable by the client so you can pass an animation rate of 50 and get a "faster run" but not quite a "even faster run" - - // Convert the Bot movement rate to a value the client understands based on the chart above - // Use this block if using 2.5625 as the ratio. - // speed *= clientMovementRateTypeMultiple; - - - // This sets the movement animation rate with the client - // Use this block if using 2.5625 as the ratio. - // pRunAnimSpeed = speed; - pRunAnimSpeed = ((serverOverClientRatio * 10.0f) * speed) * 10.0f; - - // Now convert our "speed" from the value necessary for the client to animate the correct movement type rate to the server side speed - // Use this block if using 2.5625 as the ratio. - // speed *= serverOverClientRatio; - speed = pRunAnimSpeed / serverOverClientRatio; - return MakeNewPositionAndSendUpdate(x, y, z, speed, checkZ); } -// Orders all bots in the specified group to follow their group leader. -void Bot::BotGroupOrderFollow(Group* group, Client* client) { - if(group && client) { - Mob* groupLeader = group->GetLeader(); - - if(groupLeader) { - for(int i = 0; i< MAX_GROUP_MEMBERS; i++) { - if(group->members[i] && group->members[i]->IsBot()) { - Bot* botGroupMember = group->members[i]->CastToBot(); - - if(botGroupMember && botGroupMember->GetBotOwnerCharacterID() == client->CharacterID()) { - if(group->IsLeader(botGroupMember) && botGroupMember->GetBotOwner()) { - botGroupMember->SetFollowID(botGroupMember->GetBotOwner()->GetID()); - if(botGroupMember->GetBotOwner()) - botGroupMember->Say("Following %s.", botGroupMember->GetBotOwner()->GetName()); - } - else { - botGroupMember->SetFollowID(groupLeader->GetID()); - botGroupMember->Say("Following %s.", groupLeader->GetCleanName()); - } - - botGroupMember->WipeHateList(); - - if(botGroupMember->HasPet() && botGroupMember->GetPet()) { - botGroupMember->GetPet()->WipeHateList(); - } - } - } - } - } - } -} - -// Orders all bots in the specified group to guard their current location. -void Bot::BotGroupOrderGuard(Group* group, Client* client) { - if(group && client) { - for(int i = 0; i< MAX_GROUP_MEMBERS; i++) { - if(group->members[i] && group->members[i]->IsBot()) { - Bot* botGroupMember = group->members[i]->CastToBot(); - - if(botGroupMember && botGroupMember->GetBotOwnerCharacterID() == client->CharacterID()) { - botGroupMember->SetFollowID(0); - botGroupMember->Say("Guarding here."); - - botGroupMember->WipeHateList(); - - if(botGroupMember->HasPet() && botGroupMember->GetPet()) { - botGroupMember->GetPet()->WipeHateList(); - } - } - } - } - } -} - -// Orders all bots in the specified group to attack their group leader's target. -void Bot::BotGroupOrderAttack(Group* group, Mob* target, Client* client) { - if(group && target) { - Mob* groupLeader = group->GetLeader(); - - if(groupLeader) { - for(int i=0; i < MAX_GROUP_MEMBERS; i++) { - if(group->members[i] && group->members[i]->IsBot()) { - Bot* botGroupMember = group->members[i]->CastToBot(); - - if(botGroupMember->GetBotOwnerCharacterID() == client->CharacterID()) { - botGroupMember->WipeHateList(); - botGroupMember->AddToHateList(target, 1); - - if(botGroupMember->HasPet() && botGroupMember->GetPet()) { - botGroupMember->GetPet()->WipeHateList(); - botGroupMember->GetPet()->AddToHateList(target, 1); - } - } - } - } - } - } -} - -// Summons all bot group members to ther owners location. -void Bot::BotGroupSummon(Group* group, Client* client) { - if(group) { - for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { - if(group->members[i] && group->members[i]->IsBot()) { - Bot* botMember = group->members[i]->CastToBot(); - - if(botMember->GetBotOwnerCharacterID() == client->CharacterID()) { - botMember->SetTarget(botMember->GetBotOwner()); - botMember->WipeHateList(); - botMember->Warp(glm::vec3(botMember->GetBotOwner()->GetPosition())); - - if(botMember->HasPet() && botMember->GetPet()) { - botMember->GetPet()->SetTarget(botMember); - botMember->GetPet()->WipeHateList(); - botMember->GetPet()->Warp(glm::vec3(botMember->GetBotOwner()->GetPosition())); - } - } - } - } - } -} - -// Finds a bot in the entitity list by bot owner character id and the bot first name Bot* Bot::GetBotByBotClientOwnerAndBotName(Client* c, std::string botName) { Bot* Result = 0; - if(c) { std::list BotList = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID()); - if(!BotList.empty()) { for(std::list::iterator botListItr = BotList.begin(); botListItr != BotList.end(); ++botListItr) { if(std::string((*botListItr)->GetCleanName()) == botName) { @@ -10712,11 +7083,9 @@ Bot* Bot::GetBotByBotClientOwnerAndBotName(Client* c, std::string botName) { } } } - return Result; } -// Processes a group invite from a Client for a Bot character. void Bot::ProcessBotGroupInvite(Client* c, std::string botName) { if(c) { Bot* invitedBot = GetBotByBotClientOwnerAndBotName(c, botName); @@ -10731,16 +7100,11 @@ void Bot::ProcessBotGroupInvite(Client* c, std::string botName) { database.SetGroupID(c->GetName(), g->GetID(), c->CharacterID()); database.SetGroupID(invitedBot->GetCleanName(), g->GetID(), invitedBot->GetBotID()); } - } - else { + } else { AddBotToGroup(invitedBot, c->GetGroup()); database.SetGroupID(invitedBot->GetCleanName(), c->GetGroup()->GetID(), invitedBot->GetBotID()); } - - /*if(c->GetBotRaidID() > 0) - invitedBot->SetBotRaidID(c->GetBotRaidID());*/ } - // TODO: if there is a bot but the bot is already in a group, do we send an group invitation cancel message back to the client? } } @@ -10816,13 +7180,13 @@ void Bot::ProcessBotInspectionRequest(Bot* inspectedBot, Client* client) { insr->TargetID = inspectedBot->GetNPCTypeID(); insr->playerid = inspectedBot->GetID(); - const Item_Struct* item = 0; + const EQEmu::ItemBase* item = 0; const ItemInst* inst = 0; // Modded to display power source items (will only show up on SoF+ client inspect windows though.) // I don't think bots are currently coded to use them..but, you'll have to use '#bot inventory list' // to see them on a Titanium client when/if they are activated. - for(int16 L = EmuConstants::EQUIPMENT_BEGIN; L <= MainWaist; L++) { + for (int16 L = EQEmu::legacy::EQUIPMENT_BEGIN; L <= EQEmu::legacy::SlotWaist; L++) { inst = inspectedBot->GetBotItem(L); if(inst) { @@ -10836,28 +7200,28 @@ void Bot::ProcessBotInspectionRequest(Bot* inspectedBot, Client* client) { } } - inst = inspectedBot->GetBotItem(MainPowerSource); + inst = inspectedBot->GetBotItem(EQEmu::legacy::SlotPowerSource); if(inst) { item = inst->GetItem(); if(item) { - strcpy(insr->itemnames[SoF::slots::MainPowerSource], item->Name); - insr->itemicons[SoF::slots::MainPowerSource] = item->Icon; + strcpy(insr->itemnames[SoF::invslot::PossessionsPowerSource], item->Name); + insr->itemicons[SoF::invslot::PossessionsPowerSource] = item->Icon; } else - insr->itemicons[SoF::slots::MainPowerSource] = 0xFFFFFFFF; + insr->itemicons[SoF::invslot::PossessionsPowerSource] = 0xFFFFFFFF; } - inst = inspectedBot->GetBotItem(MainAmmo); + inst = inspectedBot->GetBotItem(EQEmu::legacy::SlotAmmo); if(inst) { item = inst->GetItem(); if(item) { - strcpy(insr->itemnames[SoF::slots::MainAmmo], item->Name); - insr->itemicons[SoF::slots::MainAmmo] = item->Icon; + strcpy(insr->itemnames[SoF::invslot::PossessionsAmmo], item->Name); + insr->itemicons[SoF::invslot::PossessionsAmmo] = item->Icon; } else - insr->itemicons[SoF::slots::MainAmmo] = 0xFFFFFFFF; + insr->itemicons[SoF::invslot::PossessionsAmmo] = 0xFFFFFFFF; } strcpy(insr->text, inspectedBot->GetInspectMessage().text); @@ -10866,191 +7230,348 @@ void Bot::ProcessBotInspectionRequest(Bot* inspectedBot, Client* client) { } } -void Bot::CalcItemBonuses() +void Bot::CalcItemBonuses(StatBonuses* newbon) { - memset(&itembonuses, 0, sizeof(StatBonuses)); - const Item_Struct* itemtmp = 0; + const EQEmu::ItemBase* itemtmp = 0; - for (int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) { - const ItemInst* item = GetBotItem(i); + for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= (EQEmu::legacy::EQUIPMENT_END + 1); ++i) { + const ItemInst* item = GetBotItem((i == 22 ? 9999 : i)); if(item) { - for(int j = AUG_BEGIN; j < EmuConstants::ITEM_COMMON_SIZE; ++j) { - const ItemInst* aug = item->GetAugment(j); - if(aug) { - itemtmp = aug->GetItem(); - if(itemtmp->AC != 0) - itembonuses.AC += itemtmp->AC; - if(itemtmp->HP != 0) - itembonuses.HP += itemtmp->HP; - if(itemtmp->Mana != 0) - itembonuses.Mana += itemtmp->Mana; - if(itemtmp->Endur != 0) - itembonuses.Endurance += itemtmp->Endur; - if(itemtmp->AStr != 0) - itembonuses.STR += itemtmp->AStr; - if(itemtmp->ASta != 0) - itembonuses.STA += itemtmp->ASta; - if(itemtmp->ADex != 0) - itembonuses.DEX += itemtmp->ADex; - if(itemtmp->AAgi != 0) - itembonuses.AGI += itemtmp->AAgi; - if(itemtmp->AInt != 0) - itembonuses.INT += itemtmp->AInt; - if(itemtmp->AWis != 0) - itembonuses.WIS += itemtmp->AWis; - if(itemtmp->ACha != 0) - itembonuses.CHA += itemtmp->ACha; - if(itemtmp->MR != 0) - itembonuses.MR += itemtmp->MR; - if(itemtmp->FR != 0) - itembonuses.FR += itemtmp->FR; - if(itemtmp->CR != 0) - itembonuses.CR += itemtmp->CR; - if(itemtmp->PR != 0) - itembonuses.PR += itemtmp->PR; - if(itemtmp->DR != 0) - itembonuses.DR += itemtmp->DR; - if(itemtmp->SVCorruption != 0) - itembonuses.Corrup += itemtmp->SVCorruption; - if(itemtmp->Regen != 0) - itembonuses.HPRegen += itemtmp->Regen; - if(itemtmp->ManaRegen != 0) - itembonuses.ManaRegen += itemtmp->ManaRegen; - if(itemtmp->Attack != 0) - itembonuses.ATK += itemtmp->Attack; - if(itemtmp->DamageShield != 0) - itembonuses.DamageShield += itemtmp->DamageShield; - if(itemtmp->SpellShield != 0) - itembonuses.SpellDamageShield += itemtmp->SpellShield; - if(itemtmp->Shielding != 0) - itembonuses.MeleeMitigation += itemtmp->Shielding; - if(itemtmp->StunResist != 0) - itembonuses.StunResist += itemtmp->StunResist; - if(itemtmp->StrikeThrough != 0) - itembonuses.StrikeThrough += itemtmp->StrikeThrough; - if(itemtmp->Avoidance != 0) - itembonuses.AvoidMeleeChance += itemtmp->Avoidance; - if(itemtmp->Accuracy != 0) - itembonuses.HitChance += itemtmp->Accuracy; - if(itemtmp->CombatEffects != 0) - itembonuses.ProcChance += itemtmp->CombatEffects; - if(itemtmp->Haste != 0) - if(itembonuses.haste < itemtmp->Haste) - itembonuses.haste = itemtmp->Haste; - if(GetClass() == BARD && itemtmp->BardValue != 0) { - if(itemtmp->BardType == ItemTypeBrassInstrument) - itembonuses.brassMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypePercussionInstrument) - itembonuses.percussionMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypeSinging) - itembonuses.singingMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypeStringedInstrument) - itembonuses.stringedMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypeWindInstrument) - itembonuses.windMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypeAllInstrumentTypes) { - itembonuses.brassMod += itemtmp->BardValue; - itembonuses.percussionMod += itemtmp->BardValue; - itembonuses.singingMod += itemtmp->BardValue; - itembonuses.stringedMod += itemtmp->BardValue; - itembonuses.windMod += itemtmp->BardValue; - } - } - if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects - ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type); - } - } - } - itemtmp = item->GetItem(); - if(itemtmp->AC != 0) - itembonuses.AC += itemtmp->AC; - if(itemtmp->HP != 0) - itembonuses.HP += itemtmp->HP; - if(itemtmp->Mana != 0) - itembonuses.Mana += itemtmp->Mana; - if(itemtmp->Endur != 0) - itembonuses.Endurance += itemtmp->Endur; - if(itemtmp->AStr != 0) - itembonuses.STR += itemtmp->AStr; - if(itemtmp->ASta != 0) - itembonuses.STA += itemtmp->ASta; - if(itemtmp->ADex != 0) - itembonuses.DEX += itemtmp->ADex; - if(itemtmp->AAgi != 0) - itembonuses.AGI += itemtmp->AAgi; - if(itemtmp->AInt != 0) - itembonuses.INT += itemtmp->AInt; - if(itemtmp->AWis != 0) - itembonuses.WIS += itemtmp->AWis; - if(itemtmp->ACha != 0) - itembonuses.CHA += itemtmp->ACha; - if(itemtmp->MR != 0) - itembonuses.MR += itemtmp->MR; - if(itemtmp->FR != 0) - itembonuses.FR += itemtmp->FR; - if(itemtmp->CR != 0) - itembonuses.CR += itemtmp->CR; - if(itemtmp->PR != 0) - itembonuses.PR += itemtmp->PR; - if(itemtmp->DR != 0) - itembonuses.DR += itemtmp->DR; - if(itemtmp->SVCorruption != 0) - itembonuses.Corrup += itemtmp->SVCorruption; - if(itemtmp->Regen != 0) - itembonuses.HPRegen += itemtmp->Regen; - if(itemtmp->ManaRegen != 0) - itembonuses.ManaRegen += itemtmp->ManaRegen; - if(itemtmp->Attack != 0) - itembonuses.ATK += itemtmp->Attack; - if(itemtmp->DamageShield != 0) - itembonuses.DamageShield += itemtmp->DamageShield; - if(itemtmp->SpellShield != 0) - itembonuses.SpellDamageShield += itemtmp->SpellShield; - if(itemtmp->Shielding != 0) - itembonuses.MeleeMitigation += itemtmp->Shielding; - if(itemtmp->StunResist != 0) - itembonuses.StunResist += itemtmp->StunResist; - if(itemtmp->StrikeThrough != 0) - itembonuses.StrikeThrough += itemtmp->StrikeThrough; - if(itemtmp->Avoidance != 0) - itembonuses.AvoidMeleeChance += itemtmp->Avoidance; - if(itemtmp->Accuracy != 0) - itembonuses.HitChance += itemtmp->Accuracy; - if(itemtmp->CombatEffects != 0) - itembonuses.ProcChance += itemtmp->CombatEffects; - if(itemtmp->Haste != 0) - if(itembonuses.haste < itemtmp->Haste) - itembonuses.haste = itemtmp->Haste; - if(GetClass() == BARD && itemtmp->BardValue != 0) { - if(itemtmp->BardType == ItemTypeBrassInstrument) - itembonuses.brassMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypePercussionInstrument) - itembonuses.percussionMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypeSinging) - itembonuses.singingMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypeStringedInstrument) - itembonuses.stringedMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypeWindInstrument) - itembonuses.windMod += itemtmp->BardValue; - else if(itemtmp->BardType == ItemTypeAllInstrumentTypes) { - itembonuses.brassMod += itemtmp->BardValue; - itembonuses.percussionMod += itemtmp->BardValue; - itembonuses.singingMod += itemtmp->BardValue; - itembonuses.stringedMod += itemtmp->BardValue; - itembonuses.windMod += itemtmp->BardValue; - } - } - if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects - ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type); - } + AddItemBonuses(item, newbon); } } - if(itembonuses.HPRegen > CalcHPRegenCap()) - itembonuses.HPRegen = CalcHPRegenCap(); + // Caps + if(newbon->HPRegen > CalcHPRegenCap()) + newbon->HPRegen = CalcHPRegenCap(); - if(itembonuses.ManaRegen > CalcManaRegenCap()) - itembonuses.ManaRegen = CalcManaRegenCap(); + if(newbon->ManaRegen > CalcManaRegenCap()) + newbon->ManaRegen = CalcManaRegenCap(); + + if(newbon->EnduranceRegen > CalcEnduranceRegenCap()) + newbon->EnduranceRegen = CalcEnduranceRegenCap(); +} + +void Bot::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug, bool isTribute, int rec_override) { + if (!inst || !inst->IsClassCommon()) + { + return; + } + + if(inst->GetAugmentType()==0 && isAug == true) + { + return; + } + + const EQEmu::ItemBase *item = inst->GetItem(); + + if(!isTribute && !inst->IsEquipable(GetBaseRace(),GetClass())) + { + if (item->ItemType != EQEmu::item::ItemTypeFood && item->ItemType != EQEmu::item::ItemTypeDrink) + return; + } + + if(GetLevel() < inst->GetItemRequiredLevel(true)) + { + return; + } + + auto rec_level = isAug ? rec_override : inst->GetItemRecommendedLevel(true); + if(GetLevel() >= rec_level) + { + newbon->AC += item->AC; + newbon->HP += item->HP; + newbon->Mana += item->Mana; + newbon->Endurance += item->Endur; + newbon->ATK += item->Attack; + newbon->STR += (item->AStr + item->HeroicStr); + newbon->STA += (item->ASta + item->HeroicSta); + newbon->DEX += (item->ADex + item->HeroicDex); + newbon->AGI += (item->AAgi + item->HeroicAgi); + newbon->INT += (item->AInt + item->HeroicInt); + newbon->WIS += (item->AWis + item->HeroicWis); + newbon->CHA += (item->ACha + item->HeroicCha); + + newbon->MR += (item->MR + item->HeroicMR); + newbon->FR += (item->FR + item->HeroicFR); + newbon->CR += (item->CR + item->HeroicCR); + newbon->PR += (item->PR + item->HeroicPR); + newbon->DR += (item->DR + item->HeroicDR); + newbon->Corrup += (item->SVCorruption + item->HeroicSVCorrup); + + newbon->STRCapMod += item->HeroicStr; + newbon->STACapMod += item->HeroicSta; + newbon->DEXCapMod += item->HeroicDex; + newbon->AGICapMod += item->HeroicAgi; + newbon->INTCapMod += item->HeroicInt; + newbon->WISCapMod += item->HeroicWis; + newbon->CHACapMod += item->HeroicCha; + newbon->MRCapMod += item->HeroicMR; + newbon->CRCapMod += item->HeroicFR; + newbon->FRCapMod += item->HeroicCR; + newbon->PRCapMod += item->HeroicPR; + newbon->DRCapMod += item->HeroicDR; + newbon->CorrupCapMod += item->HeroicSVCorrup; + + newbon->HeroicSTR += item->HeroicStr; + newbon->HeroicSTA += item->HeroicSta; + newbon->HeroicDEX += item->HeroicDex; + newbon->HeroicAGI += item->HeroicAgi; + newbon->HeroicINT += item->HeroicInt; + newbon->HeroicWIS += item->HeroicWis; + newbon->HeroicCHA += item->HeroicCha; + newbon->HeroicMR += item->HeroicMR; + newbon->HeroicFR += item->HeroicFR; + newbon->HeroicCR += item->HeroicCR; + newbon->HeroicPR += item->HeroicPR; + newbon->HeroicDR += item->HeroicDR; + newbon->HeroicCorrup += item->HeroicSVCorrup; + + } + else + { + int lvl = GetLevel(); + + newbon->AC += CalcRecommendedLevelBonus( lvl, rec_level, item->AC ); + newbon->HP += CalcRecommendedLevelBonus( lvl, rec_level, item->HP ); + newbon->Mana += CalcRecommendedLevelBonus( lvl, rec_level, item->Mana ); + newbon->Endurance += CalcRecommendedLevelBonus( lvl, rec_level, item->Endur ); + newbon->ATK += CalcRecommendedLevelBonus( lvl, rec_level, item->Attack ); + newbon->STR += CalcRecommendedLevelBonus( lvl, rec_level, (item->AStr + item->HeroicStr) ); + newbon->STA += CalcRecommendedLevelBonus( lvl, rec_level, (item->ASta + item->HeroicSta) ); + newbon->DEX += CalcRecommendedLevelBonus( lvl, rec_level, (item->ADex + item->HeroicDex) ); + newbon->AGI += CalcRecommendedLevelBonus( lvl, rec_level, (item->AAgi + item->HeroicAgi) ); + newbon->INT += CalcRecommendedLevelBonus( lvl, rec_level, (item->AInt + item->HeroicInt) ); + newbon->WIS += CalcRecommendedLevelBonus( lvl, rec_level, (item->AWis + item->HeroicWis) ); + newbon->CHA += CalcRecommendedLevelBonus( lvl, rec_level, (item->ACha + item->HeroicCha) ); + + newbon->MR += CalcRecommendedLevelBonus( lvl, rec_level, (item->MR + item->HeroicMR) ); + newbon->FR += CalcRecommendedLevelBonus( lvl, rec_level, (item->FR + item->HeroicFR) ); + newbon->CR += CalcRecommendedLevelBonus( lvl, rec_level, (item->CR + item->HeroicCR) ); + newbon->PR += CalcRecommendedLevelBonus( lvl, rec_level, (item->PR + item->HeroicPR) ); + newbon->DR += CalcRecommendedLevelBonus( lvl, rec_level, (item->DR + item->HeroicDR) ); + newbon->Corrup += CalcRecommendedLevelBonus( lvl, rec_level, (item->SVCorruption + item->HeroicSVCorrup) ); + + newbon->STRCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicStr ); + newbon->STACapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicSta ); + newbon->DEXCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicDex ); + newbon->AGICapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicAgi ); + newbon->INTCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicInt ); + newbon->WISCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicWis ); + newbon->CHACapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicCha ); + newbon->MRCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicMR ); + newbon->CRCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicFR ); + newbon->FRCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicCR ); + newbon->PRCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicPR ); + newbon->DRCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicDR ); + newbon->CorrupCapMod += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicSVCorrup ); + + newbon->HeroicSTR += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicStr ); + newbon->HeroicSTA += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicSta ); + newbon->HeroicDEX += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicDex ); + newbon->HeroicAGI += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicAgi ); + newbon->HeroicINT += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicInt ); + newbon->HeroicWIS += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicWis ); + newbon->HeroicCHA += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicCha ); + newbon->HeroicMR += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicMR ); + newbon->HeroicFR += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicFR ); + newbon->HeroicCR += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicCR ); + newbon->HeroicPR += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicPR ); + newbon->HeroicDR += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicDR ); + newbon->HeroicCorrup += CalcRecommendedLevelBonus( lvl, rec_level, item->HeroicSVCorrup ); + } + + //FatherNitwit: New style haste, shields, and regens + if(newbon->haste < (int32)item->Haste) { + newbon->haste = item->Haste; + } + if(item->Regen > 0) + newbon->HPRegen += item->Regen; + + if(item->ManaRegen > 0) + newbon->ManaRegen += item->ManaRegen; + + if(item->EnduranceRegen > 0) + newbon->EnduranceRegen += item->EnduranceRegen; + + if(item->DamageShield > 0) { + if((newbon->DamageShield + item->DamageShield) > RuleI(Character, ItemDamageShieldCap)) + newbon->DamageShield = RuleI(Character, ItemDamageShieldCap); + else + newbon->DamageShield += item->DamageShield; + } + if(item->SpellShield > 0) { + if((newbon->SpellShield + item->SpellShield) > RuleI(Character, ItemSpellShieldingCap)) + newbon->SpellShield = RuleI(Character, ItemSpellShieldingCap); + else + newbon->SpellShield += item->SpellShield; + } + if(item->Shielding > 0) { + if((newbon->MeleeMitigation + item->Shielding) > RuleI(Character, ItemShieldingCap)) + newbon->MeleeMitigation = RuleI(Character, ItemShieldingCap); + else + newbon->MeleeMitigation += item->Shielding; + } + if(item->StunResist > 0) { + if((newbon->StunResist + item->StunResist) > RuleI(Character, ItemStunResistCap)) + newbon->StunResist = RuleI(Character, ItemStunResistCap); + else + newbon->StunResist += item->StunResist; + } + if(item->StrikeThrough > 0) { + if((newbon->StrikeThrough + item->StrikeThrough) > RuleI(Character, ItemStrikethroughCap)) + newbon->StrikeThrough = RuleI(Character, ItemStrikethroughCap); + else + newbon->StrikeThrough += item->StrikeThrough; + } + if(item->Avoidance > 0) { + if((newbon->AvoidMeleeChance + item->Avoidance) > RuleI(Character, ItemAvoidanceCap)) + newbon->AvoidMeleeChance = RuleI(Character, ItemAvoidanceCap); + else + newbon->AvoidMeleeChance += item->Avoidance; + } + if(item->Accuracy > 0) { + if((newbon->HitChance + item->Accuracy) > RuleI(Character, ItemAccuracyCap)) + newbon->HitChance = RuleI(Character, ItemAccuracyCap); + else + newbon->HitChance += item->Accuracy; + } + if(item->CombatEffects > 0) { + if((newbon->ProcChance + item->CombatEffects) > RuleI(Character, ItemCombatEffectsCap)) + newbon->ProcChance = RuleI(Character, ItemCombatEffectsCap); + else + newbon->ProcChance += item->CombatEffects; + } + if(item->DotShielding > 0) { + if((newbon->DoTShielding + item->DotShielding) > RuleI(Character, ItemDoTShieldingCap)) + newbon->DoTShielding = RuleI(Character, ItemDoTShieldingCap); + else + newbon->DoTShielding += item->DotShielding; + } + + if(item->HealAmt > 0) { + if((newbon->HealAmt + item->HealAmt) > RuleI(Character, ItemHealAmtCap)) + newbon->HealAmt = RuleI(Character, ItemHealAmtCap); + else + newbon->HealAmt += item->HealAmt; + } + if(item->SpellDmg > 0) { + if((newbon->SpellDmg + item->SpellDmg) > RuleI(Character, ItemSpellDmgCap)) + newbon->SpellDmg = RuleI(Character, ItemSpellDmgCap); + else + newbon->SpellDmg += item->SpellDmg; + } + if(item->Clairvoyance > 0) { + if((newbon->Clairvoyance + item->Clairvoyance) > RuleI(Character, ItemClairvoyanceCap)) + newbon->Clairvoyance = RuleI(Character, ItemClairvoyanceCap); + else + newbon->Clairvoyance += item->Clairvoyance; + } + + if(item->DSMitigation > 0) { + if((newbon->DSMitigation + item->DSMitigation) > RuleI(Character, ItemDSMitigationCap)) + newbon->DSMitigation = RuleI(Character, ItemDSMitigationCap); + else + newbon->DSMitigation += item->DSMitigation; + } + if (item->Worn.Effect > 0 && item->Worn.Type == EQEmu::item::ItemEffectWorn) {// latent effects + ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type); + } + + if (item->Focus.Effect>0 && (item->Focus.Type == EQEmu::item::ItemEffectFocus)) { // focus effects + ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0); + } + + switch(item->BardType) + { + case 51: /* All (e.g. Singing Short Sword) */ + { + if(item->BardValue > newbon->singingMod) + newbon->singingMod = item->BardValue; + if(item->BardValue > newbon->brassMod) + newbon->brassMod = item->BardValue; + if(item->BardValue > newbon->stringedMod) + newbon->stringedMod = item->BardValue; + if(item->BardValue > newbon->percussionMod) + newbon->percussionMod = item->BardValue; + if(item->BardValue > newbon->windMod) + newbon->windMod = item->BardValue; + break; + } + case 50: /* Singing */ + { + if(item->BardValue > newbon->singingMod) + newbon->singingMod = item->BardValue; + break; + } + case 23: /* Wind */ + { + if(item->BardValue > newbon->windMod) + newbon->windMod = item->BardValue; + break; + } + case 24: /* stringed */ + { + if(item->BardValue > newbon->stringedMod) + newbon->stringedMod = item->BardValue; + break; + } + case 25: /* brass */ + { + if(item->BardValue > newbon->brassMod) + newbon->brassMod = item->BardValue; + break; + } + case 26: /* Percussion */ + { + if(item->BardValue > newbon->percussionMod) + newbon->percussionMod = item->BardValue; + break; + } + } + + if (item->SkillModValue != 0 && item->SkillModType <= EQEmu::skills::HIGHEST_SKILL){ + if ((item->SkillModValue > 0 && newbon->skillmod[item->SkillModType] < item->SkillModValue) || + (item->SkillModValue < 0 && newbon->skillmod[item->SkillModType] > item->SkillModValue)) + { + newbon->skillmod[item->SkillModType] = item->SkillModValue; + } + } + + if (item->ExtraDmgSkill != 0 && item->ExtraDmgSkill <= EQEmu::skills::HIGHEST_SKILL) { + if((newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap)) + newbon->SkillDamageAmount[item->ExtraDmgSkill] = RuleI(Character, ItemExtraDmgCap); + else + newbon->SkillDamageAmount[item->ExtraDmgSkill] += item->ExtraDmgAmt; + } + + if (!isAug) + { + for (int i = 0; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) + AddItemBonuses(inst->GetAugment(i),newbon,true, false, rec_level); + } + +} + +int Bot::CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat) +{ + if( (reclevel > 0) && (level < reclevel) ) + { + int32 statmod = (level * 10000 / reclevel) * basestat; + + if( statmod < 0 ) + { + statmod -= 5000; + return (statmod/10000); + } + else + { + statmod += 5000; + return (statmod/10000); + } + } + + return 0; } // This method is intended to call all necessary methods to do all bot stat calculations, including spell buffs, equipment, AA bonsues, etc. @@ -11059,11 +7580,11 @@ void Bot::CalcBotStats(bool showtext) { return; if(showtext) { - GetBotOwner()->Message(15, "Bot updating..."); + GetBotOwner()->Message(15, "Updating %s...", GetCleanName()); } if(!IsValidRaceClassCombo()) { - GetBotOwner()->Message(15, "A %s - %s bot was detected. Is this Race/Class combination allowed?.", GetRaceName(GetRace()), GetEQClassName(GetClass(), GetLevel())); + GetBotOwner()->Message(15, "A %s - %s bot was detected. Is this Race/Class combination allowed?.", GetRaceIDName(GetRace()), GetClassIDName(GetClass(), GetLevel())); GetBotOwner()->Message(15, "Previous Bots Code releases did not check Race/Class combinations during create."); GetBotOwner()->Message(15, "Unless you are experiencing heavy lag, you should delete and remake this bot."); } @@ -11080,7 +7601,7 @@ void Bot::CalcBotStats(bool showtext) { // Test Code if(GetClass() == BARD) GetBotOwner()->Message(15, "Bard Skills-- Brass: %i, Percussion: %i, Singing: %i, Stringed: %i, Wind: %i", - GetSkill(SkillBrassInstruments), GetSkill(SkillPercussionInstruments), GetSkill(SkillSinging), GetSkill(SkillStringedInstruments), GetSkill(SkillWindInstruments)); + GetSkill(EQEmu::skills::SkillBrassInstruments), GetSkill(EQEmu::skills::SkillPercussionInstruments), GetSkill(EQEmu::skills::SkillSinging), GetSkill(EQEmu::skills::SkillStringedInstruments), GetSkill(EQEmu::skills::SkillWindInstruments)); } /*if(this->Save()) @@ -11093,26 +7614,24 @@ void Bot::CalcBotStats(bool showtext) { AI_AddNPCSpells(this->GetBotSpellID()); if(showtext) { - GetBotOwner()->Message(15, "I'm updated."); + GetBotOwner()->Message(15, "%s has been updated.", GetCleanName()); GetBotOwner()->Message(15, "Level: %i HP: %i AC: %i Mana: %i STR: %i STA: %i DEX: %i AGI: %i INT: %i WIS: %i CHA: %i", GetLevel(), max_hp, GetAC(), max_mana, GetSTR(), GetSTA(), GetDEX(), GetAGI(), GetINT(), GetWIS(), GetCHA()); GetBotOwner()->Message(15, "Resists-- Magic: %i, Poison: %i, Fire: %i, Cold: %i, Disease: %i, Corruption: %i.",GetMR(),GetPR(),GetFR(),GetCR(),GetDR(),GetCorrup()); // Test Code if(GetClass() == BARD) { GetBotOwner()->Message(15, "Bard Skills-- Brass: %i, Percussion: %i, Singing: %i, Stringed: %i, Wind: %i", - GetSkill(SkillBrassInstruments) + GetBrassMod(), - GetSkill(SkillPercussionInstruments) + GetPercMod(), - GetSkill(SkillSinging) + GetSingMod(), - GetSkill(SkillStringedInstruments) + GetStringMod(), - GetSkill(SkillWindInstruments) + GetWindMod()); + GetSkill(EQEmu::skills::SkillBrassInstruments) + GetBrassMod(), + GetSkill(EQEmu::skills::SkillPercussionInstruments) + GetPercMod(), + GetSkill(EQEmu::skills::SkillSinging) + GetSingMod(), + GetSkill(EQEmu::skills::SkillStringedInstruments) + GetStringMod(), + GetSkill(EQEmu::skills::SkillWindInstruments) + GetWindMod()); GetBotOwner()->Message(15, "Bard Skill Mods-- Brass: %i, Percussion: %i, Singing: %i, Stringed: %i, Wind: %i", GetBrassMod(), GetPercMod(), GetSingMod(), GetStringMod(), GetWindMod()); } } } -bool Bot::CheckLoreConflict(const Item_Struct* item) { - if (!item) - return false; - if (!(item->LoreFlag)) +bool Bot::CheckLoreConflict(const EQEmu::ItemBase* item) { + if (!item || !(item->LoreFlag)) return false; if (item->LoreGroup == -1) // Standard lore items; look everywhere except the shared bank, return the result @@ -11137,4353 +7656,13 @@ bool Bot::GroupHasClass(Group* group, uint8 classId) { return result; } -void Bot::ProcessBotCommands(Client *c, const Seperator *sep) { - // All bot command processing occurs here now instead of in command.cpp - - // TODO: Log any possible error messages as most of these will be MySQL error messages. - std::string TempErrorMessage; - - if(sep->arg[1][0] == '\0') { - c->Message(13, "Bad argument, type #bot help"); - return; - } - if(!strcasecmp( sep->arg[1], "help") && !strcasecmp( sep->arg[2], "\0")){ - c->Message(0, "List of commands availables for bots :"); - c->Message(0, "#bot help - show this"); - c->Message(0, "#bot create [name] [class (id)] [race (id)] [model (male/female)] - create a permanent bot. See #bot help create."); - c->Message(0, "#bot help create - show all the race/class id. (make it easier to create bots)"); - c->Message(0, "#bot delete - completely destroy forever the targeted bot and all its items."); - c->Message(0, "#bot list [all/class(1-16)] - list your bots all or by class. Classes: 1(Warrior), 2(Cleric), 3(Paladin), 4(Ranger), 5(Sk), 6(Druid), 7(Monk), 8(Bard), 9(Rogue), 10(Shaman), 11(Necro), 12(Wiz), 13(Mag), 14(Ench), 15(Beast), 16(Bersek)"); - c->Message(0, "#bot spawn [bot name] - spawn a bot from it's name (use list to see all the bots). "); - c->Message(0, "#bot inventory list - show the inventory (and the slots IDs) of the targetted bot."); - c->Message(0, "#bot inventory remove [slotid] - remove the item at the given slot in the inventory of the targetted bot."); - c->Message(0, "#bot update - you must type that command once you gain a level."); - c->Message(0, "#bot summon - It will summon your targeted bot to you."); - c->Message(0, "#bot ai mez - If you're grouped with an enchanter, he will mez your target."); - c->Message(0, "#bot picklock - You must have a targeted rogue bot in your group and be right on the door."); - c->Message(0, "#bot cure [poison|disease|curse|blindness] Cleric has most options"); - c->Message(0, "#bot bindme - You must have a Cleric in your group to get Bind Affinity cast on you."); - c->Message(0, "#bot track - look at mobs in the zone (ranger has options)"); - c->Message(0, "#bot target calm - attempts to pacify your target mob."); - c->Message(0, "#bot evac - transports your pc group to safe location in the current zone. bots are lost"); - c->Message(0, "#bot resurrectme - Your bot Cleric will rez you."); - c->Message(0, "#bot corpse summon - Necromancers summon corpse."); - c->Message(0, "#bot lore - cast Identify on the item on your mouse pointer."); - c->Message(0, "#bot sow - Bot sow on you (Druid has options)"); - c->Message(0, "#bot invis - Bot invisiblity (must have proper class in group)"); - c->Message(0, "#bot levitate - Bot levitation (must have proper class in group)"); - c->Message(0, "#bot resist - Bot resist buffs (must have proper class in group)"); - c->Message(0, "#bot runeme - Enchanter Bot cast Rune spell on you"); - c->Message(0, "#bot shrink - Shaman or Beastlord will shrink target"); - c->Message(0, "#bot endureb - Bot enduring breath (must have proper class in group)"); - c->Message(0, "#bot charm - (must have proper class in group)"); - c->Message(0, "#bot dire charm - (must have proper class in group)"); - c->Message(0, "#bot pet remove - (remove pet before charm)"); - c->Message(0, "#bot gate - you need a Druid or Wizard in your group)"); - c->Message(0, "#bot archery - Toggle Archery Skilled bots between using a Bow or using Melee weapons."); - c->Message(0, "#bot magepet [earth|water|air|fire|monster] - Select the pet type you want your Mage bot to use."); - c->Message(0, "#bot giveitem - Gives your targetted bot the item you have on your cursor."); - c->Message(0, "#bot augmentitem - Allows you to augment items for other classes. You must have the Augmentation Sealer window filled."); - c->Message(0, "#bot camp - Tells your bot to camp out of the game."); - c->Message(0, "#bot group help - Displays the commands available to manage any BOTs in your group."); - c->Message(0, "#bot botgroup help - Displays the commands available to manage BOT ONLY groups."); - c->Message(0, "#bot mana [ | all] - Displays a mana report for all your spawned bots."); - c->Message(0, "#bot setfollowdistance ### - sets target bots follow distance to ### (ie 30 or 250)."); - c->Message(0, "#bot [hair|haircolor|beard|beardcolor|face|eyes|heritage|tattoo|details ] - Change your BOTs appearance."); - c->Message(0, "#bot armorcolor - #bot help armorcolor for info"); - c->Message(0, "#bot taunt [on|off] - Turns taunt on/off for targeted bot"); - c->Message(0, "#bot stance [name] [stance (id)|list] - Sets/lists stance for named bot (Passive = 0, Balanced = 1, Efficient = 2, Reactive = 3, Aggressive = 4, Burn = 5, BurnAE = 6)"); - c->Message(0, "#bot groupmessages [on|off] [bot name|all] - Turns group messages on/off for named bot/all bots."); - c->Message(0, "#bot defensive [bot name] - Causes warrior or knight bot to use defensive discipline / buff."); - c->Message(0, "#bot healrotation help - Displays the commands available to manage BOT heal rotations."); - // TODO: - // c->Message(0, "#bot illusion - Enchanter Bot cast an illusion buff spell on you or your target."); - c->Message(0, "#bot pull [] [target] - Bot Pulling Target NPC's"); - c->Message(0, "#bot setinspectmessage - Copies your inspect message to a targeted bot that you own"); - c->Message(0, "#bot bardoutofcombat [on|off] - Determines wheter bard bots use out of combat songs."); - return; - } - - // pull - if(!strcasecmp(sep->arg[1], "pull")) { - Mob *target = c->GetTarget(); - if(target == nullptr || target == c || target->IsBot() || (target->IsPet() && target->GetOwner()->IsBot())) - { - c->Message(15, "You must select a monster"); - return; - } - - if(c->IsGrouped()) - { - bool haspuller = false; - Group *g = c->GetGroup(); - for(int i=0; imembers[i] && g->members[i]->IsBot() && !strcasecmp(g->members[i]->GetName() , sep->arg[2])) - { - haspuller = true; - Mob *puller = g->members[i]; - if (puller->CastToBot()->IsArcheryRange(target)) - { - puller->Say("Trying to Pull %s \n", target->GetCleanName()); - puller->CastToBot()->BotRangedAttack(target); - } - else { - puller->Say("Out of Range %s \n", target->GetCleanName()); - } - } - } - if(!haspuller) { - c->Message(15, "You must have an Puller in your group."); - } - } - return; - } - - // added Bot follow distance - SetFollowDistance - if(!strcasecmp(sep->arg[1], "setfollowdistance")) { - if((c->GetTarget() == nullptr) || (c->GetTarget() == c) || (!c->GetTarget()->IsBot()) || (c->GetTarget()->CastToBot()->GetBotOwner() != c)) { - c->Message(15, "You must target a bot you own!"); - } - else { - uint32 BotFollowDistance = atoi(sep->arg[2]); - c->GetTarget()->SetFollowDistance(BotFollowDistance); - - } - - return; - } - - //bot armor colors - if(!strcasecmp(sep->arg[1], "armorcolor")) { - if(c->GetTarget() && c->GetTarget()->IsBot() && (c->GetTarget()->CastToBot()->GetBotOwner() == c)) { - - if(sep->arg[2][0] == '\0' || sep->arg[3][0] == '\0' || sep->arg[4][0] == '\0' || sep->arg[5][0] == '\0') { - c->Message(0, "Usage: #bot armorcolor [slot] [red] [green] [blue] - use #bot help armorcolor for info"); - return; - } - - uint32 botid = c->GetTarget()->CastToBot()->GetBotID(); - std::string errorMessage; - - - int setslot = atoi(sep->arg[2]); - uint8 red = atoi(sep->arg[3]); - uint8 green = atoi(sep->arg[4]); - uint8 blue = atoi(sep->arg[5]); - uint32 setcolor = (red << 16) | (green << 8) | blue; - std::string query = StringFormat("UPDATE botinventory SET color = %u " - "WHERE slotID = %i AND botID = %u", - setcolor, setslot, botid); - auto results = database.QueryDatabase(query); - if(!results.Success()) - return; - - uint8 slotmaterial = Inventory::CalcMaterialFromSlot(setslot); - c->GetTarget()->CastToBot()->SendWearChange(slotmaterial); - } - else { - c->Message(15, "You must target a bot you own to do this."); - } - return; - } - // Help for coloring bot armor - if(!strcasecmp(sep->arg[1], "help") && !strcasecmp(sep->arg[2], "armorcolor") ){ - //read from db - - c->Message(0, "-----------------#bot armorcolor help-----------------------------"); - c->Message(0, "Armor: 17(Chest/Robe), 7(Arms), 9(Bracer), 12(Hands), 18(Legs), 19(Boots), 2(Helm)"); - c->Message(0, "------------------------------------------------------------------"); - c->Message(0, "Color: [red] [green] [blue] (enter a number from 0-255 for each"); - c->Message(0, "------------------------------------------------------------------"); - c->Message(0, "Example: #bot armorcolor 17 0 255 0 - this would make the chest bright green"); - return; - } - - if(!strcasecmp(sep->arg[1], "augmentitem")) { - AugmentItem_Struct* in_augment = new AugmentItem_Struct[sizeof(AugmentItem_Struct)]; - in_augment->container_slot = 1000; // - in_augment->augment_slot = -1; - Object::HandleAugmentation(c, in_augment, c->GetTradeskillObject()); - return; - } - - if(!strcasecmp(sep->arg[1], "giveitem")) { - if(c->GetTarget() && c->GetTarget()->IsBot() && (c->GetTarget()->CastToBot()->GetBotOwner() == c)) { - // Its a bot targetted and this client is the bots owner - Bot* targetedBot = c->GetTarget()->CastToBot(); - if(targetedBot) - targetedBot->FinishTrade(c, BotTradeClientNoDropNoTrade); - } - else { - c->Message(15, "You must target a bot you own to do this."); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "camp")) { - if(!strcasecmp(sep->arg[2], "all")) { - // Camp out all bots owned by this bot owner - BotOrderCampAll(c); - } - else { - // Camp only the targetted bot - if(c->GetTarget() && c->GetTarget()->IsBot() && (c->GetTarget()->CastToBot()->GetBotOwner()->CastToClient() == c)) { - Bot* targetedBot = c->GetTarget()->CastToBot(); - if(targetedBot) - targetedBot->Camp(); - } - else - c->Message(15, "You must target a bot you own to do this."); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "create")) { - if(sep->arg[2][0] == '\0' || sep->arg[3][0] == '\0' || sep->arg[4][0] == '\0' || sep->arg[5][0] == '\0' || sep->arg[6][0] != '\0') { - c->Message(0, "Usage: #bot create [name] [class(id)] [race(id)] [gender (male/female)]"); - return; - } - else if(strcasecmp(sep->arg[3],"1") && strcasecmp(sep->arg[3],"2") && strcasecmp(sep->arg[3],"3") && strcasecmp(sep->arg[3],"4") && strcasecmp(sep->arg[3],"5") && strcasecmp(sep->arg[3],"6") && strcasecmp(sep->arg[3],"7") && strcasecmp(sep->arg[3],"8") && strcasecmp(sep->arg[3],"9") && strcasecmp(sep->arg[3],"10") && strcasecmp(sep->arg[3],"11") && strcasecmp(sep->arg[3],"12") && strcasecmp(sep->arg[3],"13") && strcasecmp(sep->arg[3],"14") && strcasecmp(sep->arg[3],"15") && strcasecmp(sep->arg[3],"16")) { - c->Message(0, "Usage: #bot create [name] [class(id)] [race(id)] [gender (male/female)]"); - return; - } - else if(strcasecmp(sep->arg[4],"1") && strcasecmp(sep->arg[4],"2") && strcasecmp(sep->arg[4],"3") && strcasecmp(sep->arg[4],"4") && strcasecmp(sep->arg[4],"5") && strcasecmp(sep->arg[4],"6") && strcasecmp(sep->arg[4],"7") && strcasecmp(sep->arg[4],"8") && strcasecmp(sep->arg[4],"9") && strcasecmp(sep->arg[4],"10") && strcasecmp(sep->arg[4],"11") && strcasecmp(sep->arg[4],"12") && strcasecmp(sep->arg[4],"330") && strcasecmp(sep->arg[4],"128") && strcasecmp(sep->arg[4],"130") && strcasecmp(sep->arg[4],"522")) { - c->Message(0, "Usage: #bot create [name] [class(1-16)] [race(1-12,128,130,330,522)] [gender (male/female)]"); - return; - } - else if(strcasecmp(sep->arg[5],"male") && strcasecmp(sep->arg[5],"female")) { - c->Message(0, "Usage: #bot create [name] [class(1-16)] [race(1-12,128,130,330,522)] [gender (male/female)]"); - return; - } - - uint32 MaxBotCreate = RuleI(Bots, CreateBotCount); - if(CreatedBotCount(c->CharacterID(), &TempErrorMessage) >= MaxBotCreate) { - c->Message(0, "You cannot create more than %i bots.", MaxBotCreate); - return; - } - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - int gender = 0; - if(!strcasecmp(sep->arg[5], "female")) - gender = 1; - - NPCType DefaultNPCTypeStruct = CreateDefaultNPCTypeStructForBot(std::string(sep->arg[2]), std::string(), c->GetLevel(), atoi(sep->arg[4]), atoi(sep->arg[3]), gender); - Bot* NewBot = new Bot(DefaultNPCTypeStruct, c); - - if(NewBot) { - if(!NewBot->IsValidRaceClassCombo()) { - c->Message(0, "That Race/Class combination cannot be created."); - return; - } - - if(!NewBot->IsValidName()) { - c->Message(0, "%s has invalid characters. You can use only the A-Z, a-z and _ characters in a bot name.", NewBot->GetCleanName()); - return; - } - - if(!NewBot->IsBotNameAvailable(&TempErrorMessage)) { - c->Message(0, "The name %s is already being used. Please choose a different name.", NewBot->GetCleanName()); - return; - } - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - // Now that all validation is complete, we can save our newly created bot - if(!NewBot->Save()) - c->Message(0, "Unable to save %s as a bot.", NewBot->GetCleanName()); - else - c->Message(0, "%s saved as bot %u.", NewBot->GetCleanName(), NewBot->GetBotID()); - } - else { - // TODO: Log error message here - } - - // Bot creation is complete - return; - } - - if(!strcasecmp(sep->arg[1], "help") && !strcasecmp(sep->arg[2], "create") ){ - c->Message(0, "Classes: 1(Warrior), 2(Cleric), 3(Paladin), 4(Ranger), 5(Sk), 6(Druid), 7(Monk), 8(Bard), 9(Rogue), 10(Shaman), 11(Necro), 12(Wiz), 13(Mag), 14(Ench), 15(Beast), 16(Bersek)"); - c->Message(0, "------------------------------------------------------------------"); - c->Message(0, "Races: 1(Human), 2(Barb), 3(Erudit), 4(Wood elf), 5(High elf), 6(Dark elf), 7(Half elf), 8(Dwarf), 9(Troll), 10(Ogre), 11(Halfling), 12(Gnome), 128(Iksar), 130(Vah shir), 330(Froglok), 522(Drakkin)"); - c->Message(0, "------------------------------------------------------------------"); - c->Message(0, "Usage: #bot create [name] [class(1-16)] [race(1-12,128,130,330,522)] [gender(male/female)]"); - c->Message(0, "Example: #bot create Sneaky 9 6 male"); - return; - } - - if(!strcasecmp(sep->arg[1], "delete") ) { - if((c->GetTarget() == nullptr) || !c->GetTarget()->IsBot()) - { - c->Message(15, "You must target a bot!"); - return; - } - else if(c->GetTarget()->CastToBot()->GetBotOwnerCharacterID() != c->CharacterID()) - { - c->Message(15, "You can't delete a bot that you don't own."); - return; - } - - if(c->GetTarget()->IsBot()) { - Bot* BotTargeted = c->GetTarget()->CastToBot(); - - if(BotTargeted) { - BotTargeted->DeleteBot(&TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - BotTargeted->Camp(false); - } - } - - return; - } - - if(!strcasecmp(sep->arg[1], "list")) { - bool listAll = true; - int iClass = atoi(sep->arg[2]); - - if(iClass > 0 && iClass < 17) - listAll = false; - - std::list AvailableBots = GetBotList(c->CharacterID(), &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - if(!AvailableBots.empty()) { - for(std::list::iterator TempAvailableBotsList = AvailableBots.begin(); TempAvailableBotsList != AvailableBots.end(); ++TempAvailableBotsList) { - if(!listAll && TempAvailableBotsList->BotClass != iClass) - continue; - - c->Message(0, "Name: %s -- Class: %s -- Level: %u -- Race: %s", TempAvailableBotsList->BotName, ClassIdToString(TempAvailableBotsList->BotClass).c_str(), TempAvailableBotsList->BotLevel, RaceIdToString(TempAvailableBotsList->BotRace).c_str()); - } - } - else { - c->Message(0, "You have no bots created. Use the #bot create command to create a bot."); - } - } - - if(!strcasecmp(sep->arg[1], "mana")) { - bool listAll = false; - Bot* bot = 0; - - if(sep->argnum == 2) { - if(std::string(sep->arg[2]).compare("all") == 0) - listAll = true; - else { - std::string botName = std::string(sep->arg[2]); - - Bot* tempBot = entity_list.GetBotByBotName(botName); - - if(tempBot && tempBot->GetBotOwner() == c) { - bot = tempBot; - } - } - } - else { - if(c->GetTarget() && c->GetTarget()->IsBot()) - bot = c->GetTarget()->CastToBot(); - } - - if(bot && !listAll) { - // Specific bot only - if(bot->GetClass() != WARRIOR && bot->GetClass() != MONK && bot->GetClass() != BARD && bot->GetClass() != BERSERKER && bot->GetClass() != ROGUE) - c->Message(0, "Name: %s -- Class: %s -- Mana: %3.1f%%", bot->GetCleanName(), ClassIdToString(bot->GetClass()).c_str(), bot->GetManaRatio()); - } - else { - // List all - std::list spawnedBots = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID()); - - if(!spawnedBots.empty()) { - for(std::list::iterator botsListItr = spawnedBots.begin(); botsListItr != spawnedBots.end(); ++botsListItr) { - Bot* tempBot = *botsListItr; - if(tempBot) { - if(tempBot->GetClass() != WARRIOR && tempBot->GetClass() != MONK && tempBot->GetClass() != BARD && tempBot->GetClass() != BERSERKER && tempBot->GetClass() != ROGUE) - c->Message(0, "Name: %s -- Class: %s -- Mana: %3.1f%%", tempBot->GetCleanName(), ClassIdToString(tempBot->GetClass()).c_str(), tempBot->GetManaRatio()); - } - } - } - else { - c->Message(0, "You have no spawned bots in this zone."); - } - } - - return; - } - - if(!strcasecmp(sep->arg[1], "spawn") ) { - uint32 botId = GetBotIDByBotName(std::string(sep->arg[2])); - - if(GetBotOwnerCharacterID(botId, &TempErrorMessage) != c->CharacterID()) { - c->Message(0, "You can't spawn a bot that you don't own."); - return; - } - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - if(c->GetFeigned()) { - c->Message(0, "You can't summon bots while you are feigned."); - return; - } - - /*if(c->GetBotRaidID() > 0) { - BotRaids *br = entity_list.GetBotRaidByMob(c->CastToMob()); - if(br) { - if(br->GetBotRaidAggro()) { - c->Message(15, "You can't summon bots while you are engaged."); - return; - } - } - }*/ - - if(c->IsGrouped()) { - Group *g = entity_list.GetGroupByClient(c); - for (int i=0; imembers[i] && !g->members[i]->qglobal && (g->members[i]->GetAppearance() != eaDead) - && (g->members[i]->IsEngaged() || (g->members[i]->IsClient() && g->members[i]->CastToClient()->GetAggroCount()))) { - c->Message(0, "You can't summon bots while you are engaged."); - return; - } - if(g && g->members[i] && g->members[i]->qglobal) { - return; - } - } - } - else { - if(c->GetAggroCount() > 0) { - c->Message(0, "You can't spawn bots while you are engaged."); - return; - } - } - - Mob* TempBotMob = entity_list.GetMobByBotID(botId); - - if(TempBotMob) { - c->Message(0, "This bot is already in the zone."); - return; - } - - int spawnedBotCount = SpawnedBotCount(c->CharacterID(), &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - if(RuleB(Bots, BotQuest) && !c->GetGM()) { - const int allowedBots = AllowedBotSpawns(c->CharacterID(), &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - if(allowedBots == 0) { - c->Message(0, "You cannot spawn any bots."); - return; - } - - if(spawnedBotCount >= allowedBots) { - c->Message(0, "You cannot spawn more than %i bots.", spawnedBotCount); - return; - } - - } - - if(spawnedBotCount >= RuleI(Bots, SpawnBotCount) && !c->GetGM()) { - c->Message(0, "You cannot spawn more than %i bots.", spawnedBotCount); - return; - } - - Bot* TempBot = LoadBot(botId, &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - safe_delete(TempBot); - return; - } - - if(TempBot) { - // We have a bot loaded from the database - TempBot->Spawn(c, &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - safe_delete(TempBot); - return; - } - - TempBot->CastToMob()->Say("I am ready for battle."); - } - else { - // We did not find a bot for the specified bot id from the database - c->Message(0, "BotID: %i not found", atoi(sep->arg[2])); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "archery")) { - if((c->GetTarget() == nullptr) || (c->GetTarget() == c) || !c->GetTarget()->IsBot()) { - c->Message(15, "You must target a bot!"); - return; - } - - Bot* archerBot = c->GetTarget()->CastToBot(); - - if(archerBot) { - if(archerBot->IsBotArcher()) - archerBot->SetBotArcher(false); - else - archerBot->SetBotArcher(true); - - archerBot->ChangeBotArcherWeapons(archerBot->IsBotArcher()); - - if(archerBot->GetClass() == RANGER && archerBot->GetLevel() >= 61) - archerBot->SetRangerAutoWeaponSelect(archerBot->IsBotArcher()); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "picklock")) { - if((c->GetTarget() == nullptr) || (c->GetTarget() == c) || !c->GetTarget()->IsBot() || (c->GetTarget()->GetClass() != ROGUE)) { - c->Message(15, "You must target a rogue bot!"); - } - else { - entity_list.BotPickLock(c->GetTarget()->CastToBot()); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "summon")) { - if((c->GetTarget() == nullptr) || (c->GetTarget() == c) || !c->GetTarget()->IsBot() || c->GetTarget()->IsPet()) - { - c->Message(15, "You must target a bot!"); - } - else if(c->GetTarget()->IsMob() && !c->GetTarget()->IsPet()) - { - Mob *b = c->GetTarget(); - if(b) - { - // Is our target "botable" ? - if(!b->IsBot()){ - c->Message(15, "You must target a bot!"); - } - else if((b->CastToBot()->GetBotOwnerCharacterID() != c->CharacterID())) - { - b->Say("You can only summon your own bots."); - } - else - { - b->SetTarget(c->CastToMob()); - b->Warp(glm::vec3(c->GetPosition())); - } - } - } - - return; - } - - if(!strcasecmp(sep->arg[1], "inventory") && !strcasecmp(sep->arg[2], "list")) { - if(c->GetTarget() != nullptr) { - if(c->GetTarget()->IsBot() && c->GetTarget()->CastToBot()->GetBotOwnerCharacterID() == c->CharacterID()) { - Mob* b = c->GetTarget(); - int x = c->GetTarget()->CastToBot()->GetBotItemsCount(&TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - const char* equipped[EmuConstants::EQUIPMENT_SIZE] = {"Charm", "Left Ear", "Head", "Face", "Right Ear", "Neck", "Shoulders", "Arms", "Back", - "Left Wrist", "Right Wrist", "Range", "Hands", "Primary Hand", "Secondary Hand", - "Left Finger", "Right Finger", "Chest", "Legs", "Feet", "Waist", "Ammo" }; - - const ItemInst* inst = nullptr; - const Item_Struct* item = nullptr; - bool is2Hweapon = false; - - std::string item_link; - Client::TextLink linker; - linker.SetLinkType(linker.linkItemInst); - - for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) { - if((i == MainSecondary) && is2Hweapon) { - continue; - } - - inst = b->CastToBot()->GetBotItem(i); - if (inst) - item = inst->GetItem(); - else - item = nullptr; - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - if(item == nullptr) { - c->Message(15, "I need something for my %s (Item %i)", equipped[i], i); - continue; - } - if((i == MainPrimary) && ((item->ItemType == ItemType2HSlash) || (item->ItemType == ItemType2HBlunt) || (item->ItemType == ItemType2HPiercing))) { - is2Hweapon = true; - } - - // I could not find a difference between the criteria positive code and the criteria negative code.. - // ..so, I deleted the check (old criteria: i = { MainCharm, MainRange, MainPrimary, MainSecondary, MainAmmo }) - - linker.SetItemInst(inst); - - item_link = linker.GenerateLink(); - - c->Message(15, "Using %s in my %s (Item %i)", item_link.c_str(), equipped[i], i); - } - } - else { - c->Message(15, "You must group your bot first."); - } - } - else { - c->Message(15, "You must target a bot first."); - } - return; - } - - if(!strcasecmp(sep->arg[1], "inventory") && !strcasecmp(sep->arg[2], "remove")) { - if((c->GetTarget() == nullptr) || (sep->arg[3][0] == '\0') || !c->GetTarget()->IsBot()) - { - c->Message(15, "Usage: #bot inventory remove [slotid] (You must have a bot targetted) "); - return; - } - else if(c->GetTarget()->IsBot() && c->GetTarget()->CastToBot()->GetBotOwnerCharacterID() == c->CharacterID()) - { - if(c->GetTradeskillObject() || (c->trade->state == Trading)) - return; - - int slotId = atoi(sep->arg[3]); - if(slotId > EmuConstants::EQUIPMENT_END || slotId < EmuConstants::EQUIPMENT_BEGIN) { - c->Message(15, "A bot has 21 slots in its inventory, please choose a slot between 0 and 21."); - return; - } - const char* equipped[EmuConstants::EQUIPMENT_SIZE] = {"Charm", "Left Ear", "Head", "Face", "Right Ear", "Neck", "Shoulders", "Arms", "Back", - "Left Wrist", "Right Wrist", "Range", "Hands", "Primary Hand", "Secondary Hand", - "Left Finger", "Right Finger", "Chest", "Legs", "Feet", "Waist", "Ammo" }; - - const Item_Struct* itm = nullptr; - const ItemInst* itminst = c->GetTarget()->CastToBot()->GetBotItem(slotId); - if(itminst) - itm = itminst->GetItem(); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - // Don't allow the player to remove a lore item they already possess and cause a crash - bool failedLoreCheck = false; - if(itminst) { - for (int m = AUG_BEGIN; m < EmuConstants::ITEM_COMMON_SIZE; ++m) { - ItemInst *itma = itminst->GetAugment(m); - if(itma) - { - if(c->CheckLoreConflict(itma->GetItem())) { - failedLoreCheck = true; - } - } - } - if(c->CheckLoreConflict(itm)) { - failedLoreCheck = true; - } - } - if(!failedLoreCheck) { - if(itm) { - c->PushItemOnCursor(*itminst, true); - Bot *gearbot = c->GetTarget()->CastToBot(); - if((slotId == MainRange)||(slotId == MainAmmo)||(slotId == MainPrimary)||(slotId == MainSecondary)) { - gearbot->SetBotArcher(false); - } - gearbot->RemoveBotItemBySlot(slotId, &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - gearbot->BotRemoveEquipItem(slotId); - gearbot->CalcBotStats(); - switch(slotId) { - case MainCharm: - case MainEar1: - case MainHead: - case MainFace: - case MainEar2: - case MainNeck: - case MainBack: - case MainWrist1: - case MainWrist2: - case MainRange: - case MainPrimary: - case MainSecondary: - case MainFinger1: - case MainFinger2: - case MainChest: - case MainWaist: - //case MainPowerSource: - case MainAmmo: - gearbot->Say("My %s is now unequipped.", equipped[slotId]); - break; - case MainShoulders: - case MainArms: - case MainHands: - case MainLegs: - case MainFeet: - gearbot->Say("My %s are now unequipped.", equipped[slotId]); - break; - default: - break; - } - } - else { - switch(slotId) { - case MainCharm: - case MainEar1: - case MainHead: - case MainFace: - case MainEar2: - case MainNeck: - case MainBack: - case MainWrist1: - case MainWrist2: - case MainRange: - case MainPrimary: - case MainSecondary: - case MainFinger1: - case MainFinger2: - case MainChest: - case MainWaist: - //case MainPowerSource: - case MainAmmo: - c->GetTarget()->Say("My %s is already unequipped.", equipped[slotId]); - break; - case MainShoulders: - case MainArms: - case MainHands: - case MainLegs: - case MainFeet: - c->GetTarget()->Say("My %s are already unequipped.", equipped[slotId]); - break; - default: - break; - } - } - } - else { - c->Message_StringID(0, PICK_LORE); - } - } - return; - } - - if(!strcasecmp(sep->arg[1], "update")) { - // Congdar: add IsEngaged check for exploit to keep bots alive by repeatedly using #bot update. - if((c->GetTarget() != nullptr) && c->GetTarget()->IsBot()) { - if(c->GetLevel() <= c->GetTarget()->GetLevel()) { - c->Message(15, "This bot has already been updated."); - return; - } - - if(c->IsGrouped()) - { - Group *g = entity_list.GetGroupByClient(c); - for (int i=0; imembers[i] && g->members[i]->IsEngaged()) - { - c->Message(15, "You can't update bots while you are engaged."); - return; - } - } - } - - if((c->GetTarget()->CastToBot()->GetBotOwner() == c->CastToMob()) && !c->GetFeigned()) { - Bot* bot = c->GetTarget()->CastToBot(); - //bot->SetLevel(c->GetLevel()); - bot->SetPetChooser(false); - bot->CalcBotStats(); - } - else { - if(c->GetFeigned()) { - c->Message(15, "You cannot update bots while feigned."); - } - else { - c->Message(15, "You must target your bot first"); - } - } - } - else { - c->Message(15, "You must target a bot first"); - } - - return; - } - - //Bind - if(!strcasecmp(sep->arg[1], "bindme")) { - Mob *binder = nullptr; - bool hasbinder = false; - if(c->IsGrouped()) - { - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == CLERIC)) - { - hasbinder = true; - binder = g->members[i]; - } - } - if(!hasbinder) { - c->Message(15, "You must have a Cleric in your group."); - } - } - } - if(hasbinder) { - binder->Say("Attempting to bind you %s.", c->GetName()); - binder->CastToNPC()->CastSpell(35, c->GetID(), 1, -1, -1); - } - return; - } - - // Rune - if(!strcasecmp(sep->arg[1], "runeme")) { - Mob *runeer = nullptr; - bool hasruneer = false; - if(c->IsGrouped()) - { - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == ENCHANTER)) - { - hasruneer = true; - runeer = g->members[i]; - } - } - if(!hasruneer) { - c->Message(15, "You must have an Enchanter in your group."); - } - } - } - if(hasruneer) { - if (c->GetLevel() <= 12) { - runeer->Say("I need to be level 13 or higher for this..."); - } - else if ((c->GetLevel() >= 13) && (c->GetLevel() <= 21)) { - runeer->Say("Casting Rune I..."); - runeer->CastSpell(481, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() >= 22) && (c->GetLevel() <= 32)) { - runeer->Say("Casting Rune II..."); - runeer->CastSpell(482, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() >= 33) && (c->GetLevel() <= 39)) { - runeer->Say("Casting Rune III..."); - runeer->CastSpell(483, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() >= 40) && (c->GetLevel() <= 51)) { - runeer->Say("Casting Rune IV..."); - runeer->CastSpell(484, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() >= 52) && (c->GetLevel() <= 60)) { - runeer->Say("Casting Rune V..."); - runeer->CastSpell(1689, c->GetID(), 1, -1, -1); - } - else if (c->GetLevel() >= 61){ - runeer->Say("Casting Rune of Zebuxoruk..."); - runeer->CastSpell(3343, c->GetID(), 1, -1, -1); - } - } - return; - } - - //Tracking - if(!strcasecmp(sep->arg[1], "track") && c->IsGrouped()) { - Mob *Tracker; - uint32 TrackerClass = 0; - - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case RANGER: - Tracker = g->members[i]; - TrackerClass = RANGER; - break; - case DRUID: - // Unless we have a ranger, druid is next best. - if(TrackerClass != RANGER) { - Tracker = g->members[i]; - TrackerClass = DRUID; - } - break; - case BARD: - // If we haven't found a tracker yet, use bard. - if(TrackerClass == 0) { - Tracker = g->members[i]; - TrackerClass = BARD; - } - break; - default: - break; - } - } - } - - int Level = (c->GetLevel()); - int RangeR = (Level*80); //Ranger - int RangeD = (Level*30); //Druid - int RangeB = (Level*20); //Bard - switch(TrackerClass) { - case RANGER: - if(!strcasecmp(sep->arg[2], "all")) { - Tracker->Say("Tracking everything", c->GetName()); - entity_list.ShowSpawnWindow(c, RangeR, false); - } - else if(!strcasecmp(sep->arg[2], "rare")) { - Tracker->Say("Selective tracking", c->GetName()); - entity_list.ShowSpawnWindow(c, RangeR, true); - } - else if(!strcasecmp(sep->arg[2], "near")) { - Tracker->Say("Tracking mobs nearby", c->GetName()); - entity_list.ShowSpawnWindow(c, RangeD, false); - } - else - Tracker->Say("You want to [track all], [track near], or [track rare]?", c->GetName()); - - break; - - case BARD: - - if(TrackerClass != RANGER) - Tracker->Say("Tracking up", c->GetName()); - entity_list.ShowSpawnWindow(c, RangeB, false); - break; - - case DRUID: - - if(TrackerClass = BARD) - Tracker->Say("Tracking up", c->GetName()); - entity_list.ShowSpawnWindow(c, RangeD, false); - break; - - default: - c->Message(15, "You must have a Ranger, Druid, or Bard in your group."); - break; - } - } - } - - //Cure - if ((!strcasecmp(sep->arg[1], "cure")) && (c->IsGrouped())) { - Mob *Curer; - uint32 CurerClass = 0; - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case CLERIC: - Curer = g->members[i]; - CurerClass = CLERIC; - break; - case SHAMAN: - if(CurerClass != CLERIC){ - Curer = g->members[i]; - CurerClass = SHAMAN; - } - case DRUID: - if (CurerClass == 0){ - Curer = g->members[i]; - CurerClass = DRUID; - } - break; - break; - default: - break; - } - } - } - switch(CurerClass) { - case CLERIC: - if (!strcasecmp(sep->arg[2], "poison") && (c->GetLevel() >= 1)) { - Curer->Say("Trying to cure us of %s.", sep->arg[2]); - Curer->CastToBot()->Bot_Command_Cure(1, Curer->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "disease") && (c->GetLevel() >= 4)) { - Curer->Say("Trying to cure us of %s.", sep->arg[2]); - Curer->CastToBot()->Bot_Command_Cure(2, Curer->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "curse") && (c->GetLevel() >= 8)) { - Curer->Say("Trying to cure us of %s.", sep->arg[2]); - Curer->CastToBot()->Bot_Command_Cure(3, Curer->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "blindness") && (c->GetLevel() >= 3)) { - Curer->Say("Trying to cure us of %s.", sep->arg[2]); - Curer->CastToBot()->Bot_Command_Cure(4, Curer->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "curse") && (c->GetLevel() <= 8) - || !strcasecmp(sep->arg[2], "blindness") && (c->GetLevel() <= 3) - || !strcasecmp(sep->arg[2], "disease") && (c->GetLevel() <= 4) - || !strcasecmp(sep->arg[2], "poison") && (c->GetLevel() <= 1)) { - Curer->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Curer->Say("Do you want [cure poison], [cure disease], [cure curse], or [cure blindness]?", c->GetName()); - - break; - - case SHAMAN: - if (!strcasecmp(sep->arg[2], "poison") && (c->GetLevel() >= 2)) { - Curer->Say("Trying to cure us of %s.", sep->arg[2]); - Curer->CastToBot()->Bot_Command_Cure(1, Curer->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "disease") && (c->GetLevel() >= 1)) { - Curer->Say("Trying to cure us of %s.", sep->arg[2]); - Curer->CastToBot()->Bot_Command_Cure(2, Curer->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "curse")) { - Curer->Say("I don't have that spell", sep->arg[2]); - } - else if(!strcasecmp(sep->arg[2], "blindness") && (c->GetLevel() >= 7)) { - Curer->Say("Trying to cure us of %s.", sep->arg[2]); - Curer->CastToBot()->Bot_Command_Cure(4, Curer->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "blindness") && (c->GetLevel() <= 7) - || !strcasecmp(sep->arg[2], "disease") && (c->GetLevel() <= 1) - || !strcasecmp(sep->arg[2], "poison") && (c->GetLevel() <= 2)) { - Curer->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Curer->Say("Do you want [cure poison], [cure disease], or [cure blindness]?", c->GetName()); - - break; - - case DRUID: - - if (!strcasecmp(sep->arg[2], "poison") && (c->GetLevel() >= 5)) { - Curer->Say("Trying to cure us of %s.", sep->arg[2]); - Curer->CastToBot()->Bot_Command_Cure(1, Curer->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "disease") && (c->GetLevel() >= 4)) { - Curer->Say("Trying to cure us of %s.", sep->arg[2]); - Curer->CastToBot()->Bot_Command_Cure(2, Curer->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "curse")) { // Fire level 1 - Curer->Say("I don't have that spell", sep->arg[2]); - } - else if(!strcasecmp(sep->arg[2], "blindness") && (c->GetLevel() >= 13)) { - Curer->Say("I don't have that spell", sep->arg[2]); - } - else if (!strcasecmp(sep->arg[2], "disease") && (c->GetLevel() <= 4) - || !strcasecmp(sep->arg[2], "poison") && (c->GetLevel() <= 5)) { - Curer->Say("I don't have the needed level yet", sep->arg[2]) ; - } - else - Curer->Say("Do you want [cure poison], or [cure disease]?", c->GetName()); - - break; - - default: - c->Message(15, "You must have a Cleric, Shaman, or Druid in your group."); - break; - } - } - } - - //Mez - if(!strcasecmp(sep->arg[1], "ai") && !strcasecmp(sep->arg[2], "mez")) - { - Mob *target = c->GetTarget(); - if(target == nullptr || target == c || target->IsBot() || (target->IsPet() && target->GetOwner()->IsBot())) - { - c->Message(15, "You must select a monster"); - return; - } - - if(c->IsGrouped()) - { - bool hasmezzer = false; - Group *g = c->GetGroup(); - for(int i=0; imembers[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == ENCHANTER)) - { - hasmezzer = true; - Mob *mezzer = g->members[i]; - mezzer->Say("Trying to mez %s \n", target->GetCleanName()); - mezzer->CastToBot()->MesmerizeTarget(target); - } - } - if(!hasmezzer) { - c->Message(15, "You must have an Enchanter in your group."); - } - } - return; - } - - //Lore (Identify item) - if(!strcasecmp(sep->arg[1], "lore")) { - if(c->IsGrouped()) - { - bool hascaster = false; - Group *g = c->GetGroup(); - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - uint8 casterlevel = g->members[i]->GetLevel(); - switch(g->members[i]->GetClass()) { - case ENCHANTER: - if(casterlevel >= 15) { - hascaster = true; - } - break; - case WIZARD: - if(casterlevel >= 14) { - hascaster = true; - } - break; - case NECROMANCER: - if(casterlevel >= 17) { - hascaster = true; - } - break; - case MAGICIAN: - if(casterlevel >= 13) { - hascaster = true; - } - break; - default: - break; - } - if(hascaster) { - g->members[i]->Say("Trying to Identify your item..."); - g->members[i]->CastSpell(305, c->GetID(), 1, -1, -1); - break; - } - } - } - if(!hascaster) { - c->Message(15, "You don't see anyone in your group that can cast Identify."); - } - } - else { - c->Message(15, "You don't see anyone in your group that can cast Identify."); - } - return; - } - - //Resurrect - if(!strcasecmp(sep->arg[1], "resurrectme")) - { - Mob *target = c->GetTarget(); - if(target == nullptr || !target->IsCorpse()) - { - c->Message(15, "You must select a corpse"); - return; - } - - if(c->IsGrouped()) - { - bool hasrezzer = false; - Group *g = c->GetGroup(); - for(int i=0; imembers[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == CLERIC)) - { - hasrezzer = true; - Mob *rezzer = g->members[i]; - rezzer->Say("Trying to rez %s", target->GetCleanName()); - rezzer->CastToBot()->Bot_Command_RezzTarget(target); - break; - } - } - if(!hasrezzer) { - c->Message(15, "You must have a Cleric in your group."); - } - } - else { - c->Message(15, "You must have a Cleric in your group."); - } - return; - } - - if(!strcasecmp(sep->arg[1], "magepet")) - { - if(c->GetTarget() && c->GetTarget()->IsBot() && (c->GetTarget()->GetClass() == MAGICIAN)) - { - if(c->GetTarget()->CastToBot()->GetBotOwnerCharacterID() == c->CharacterID()) - { - int botlevel = c->GetTarget()->GetLevel(); - c->GetTarget()->CastToBot()->SetPetChooser(true); - if(botlevel == 1) - { - c->GetTarget()->Say("I don't have any pets yet."); - return; - } - if(!strcasecmp(sep->arg[2], "water")) - { - c->GetTarget()->CastToBot()->SetPetChooserID(0); - } - else if(!strcasecmp(sep->arg[2], "fire")) - { - if(botlevel < 3) - { - c->GetTarget()->Say("I don't have that pet yet."); - return; - } - else - { - c->GetTarget()->CastToBot()->SetPetChooserID(1); - } - } - else if(!strcasecmp(sep->arg[2], "air")) - { - if(botlevel < 4) - { - c->GetTarget()->Say("I don't have that pet yet."); - return; - } - else - { - c->GetTarget()->CastToBot()->SetPetChooserID(2); - } - } - else if(!strcasecmp(sep->arg[2], "earth")) - { - if(botlevel < 5) - { - c->GetTarget()->Say("I don't have that pet yet."); - return; - } - else - { - c->GetTarget()->CastToBot()->SetPetChooserID(3); - } - } - else if(!strcasecmp(sep->arg[2], "monster")) - { - if(botlevel < 30) - { - c->GetTarget()->Say("I don't have that pet yet."); - return; - } - else - { - c->GetTarget()->CastToBot()->SetPetChooserID(4); - } - } - if(c->GetTarget()->GetPet()) - { - // cast reclaim energy - uint16 id = c->GetTarget()->GetPetID(); - c->GetTarget()->SetPetID(0); - c->GetTarget()->CastSpell(331, id); - } - } - } - else - { - c->Message(15, "You must target your Magician bot."); - } - return; - } - - //Summon Corpse - if(!strcasecmp(sep->arg[1], "corpse") && !strcasecmp(sep->arg[2], "summon")) { - if(c->GetTarget() == nullptr) { - c->Message(15, "You must select player with his corpse in the zone."); - return; - } - if(c->IsGrouped()) { - bool hassummoner = false; - Mob *t = c->GetTarget(); - Group *g = c->GetGroup(); - int summonerlevel = 0; - for(int i=0; imembers[i] && g->members[i]->IsBot() && ((g->members[i]->GetClass() == NECROMANCER)||(g->members[i]->GetClass() == SHADOWKNIGHT))) { - hassummoner = true; - summonerlevel = g->members[i]->GetLevel(); - g->members[i]->InterruptSpell(); - if(!t->IsClient()) { - g->members[i]->Say("You have to target a player with a corpse in the zone"); - return; - } - else { - g->members[i]->SetTarget(t); - - if(summonerlevel < 12) { - g->members[i]->Say("I don't have that spell yet."); - } - else if((summonerlevel > 11) && (summonerlevel < 35)) { - g->members[i]->Say("Attempting to summon %s\'s corpse.", t->GetCleanName()); - g->members[i]->CastSpell(2213, t->GetID(), 1, -1, -1); - return; - } - else if((summonerlevel > 34) && (summonerlevel < 71)) { - g->members[i]->Say("Attempting to summon %s\'s corpse.", t->GetCleanName()); - g->members[i]->CastSpell(3, t->GetID(), 1, -1, -1); - return; - } - else if(summonerlevel > 70) { - g->members[i]->Say("Attempting to summon %s\'s corpse.", t->GetCleanName()); - g->members[i]->CastSpell(10042, t->GetID(), 1, -1, -1); - return; - } - } - } - } - if (!hassummoner) { - c->Message(15, "You must have a Necromancer or Shadowknight in your group."); - } - return; - } - } - - //Pacify - if(!strcasecmp(sep->arg[1], "target") && !strcasecmp(sep->arg[2], "calm")) - { - Mob *target = c->GetTarget(); - - if(target == nullptr || target->IsClient() || target->IsBot() || target->IsPet() && target->GetOwner()->IsBot()) - c->Message(15, "You must select a monster"); - else { - if(c->IsGrouped()) { - Group *g = c->GetGroup(); - - for(int i=0; imembers[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == ENCHANTER)) { - Bot *pacer = g->members[i]->CastToBot(); - pacer->Say("Trying to pacify %s \n", target->GetCleanName()); - - if(pacer->Bot_Command_CalmTarget(target)) { - if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_InstantHate)) - //if(pacer->IsPacified(target)) - c->Message(0, "I have successfully pacified %s.", target->GetCleanName()); - return; - /*else - c->Message(0, "I failed to pacify %s.", target->GetCleanName());*/ - } - else - c->Message(0, "I failed to pacify %s.", target->GetCleanName()); - } - // seperated cleric and chanter so chanter is primary - if(g && g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == CLERIC) && (GroupHasEnchanterClass(g) == false)) { - Bot *pacer = g->members[i]->CastToBot(); - pacer->Say("Trying to pacify %s \n", target->GetCleanName()); - - if(pacer->Bot_Command_CalmTarget(target)) { - if(target->FindType(SE_Lull) || target->FindType(SE_Harmony) || target->FindType(SE_InstantHate)) - //if(pacer->IsPacified(target)) - c->Message(0, "I have successfully pacified %s.", target->GetCleanName()); - return; - /*else - c->Message(0, "I failed to pacify %s.", target->GetCleanName());*/ - } - else - c->Message(0, "I failed to pacify %s.", target->GetCleanName()); - } - /*else - c->Message(15, "You must have an Enchanter or Cleric in your group.");*/ - } - } - } - - return; - } - - //Charm - if(!strcasecmp(sep->arg[1], "charm")) - { - Mob *target = c->GetTarget(); - if(target == nullptr || target->IsClient() || target->IsBot() || (target->IsPet() && target->GetOwner()->IsBot())) - { - c->Message(15, "You must select a monster"); - return; - } - uint32 DBtype = c->GetTarget()->GetBodyType(); - Mob *Charmer; - uint32 CharmerClass = 0; - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case ENCHANTER: - Charmer = g->members[i]; - CharmerClass = ENCHANTER; - break; - case NECROMANCER: - if(CharmerClass != ENCHANTER){ - Charmer = g->members[i]; - CharmerClass = NECROMANCER; - } - case DRUID: - if (CharmerClass == 0){ - Charmer = g->members[i]; - CharmerClass = DRUID; - } - break; - break; - default: - break; - } - } - } - switch(CharmerClass) { - case ENCHANTER: - if (c->GetLevel() >= 11) { - Charmer->Say("Trying to charm %s \n", target->GetCleanName(), sep->arg[2]); - Charmer->CastToBot()->Bot_Command_CharmTarget (1,target); - } - else if (c->GetLevel() <= 10){ - Charmer->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Charmer->Say("Mob level is too high or can't be charmed", c->GetName()); - break; - - case NECROMANCER: - if ((c->GetLevel() >= 18) && (DBtype == 3)) { - Charmer->Say("Trying to Charm %s \n", target->GetCleanName(), sep->arg[2]); - Charmer->CastToBot()->Bot_Command_CharmTarget (2,target); - } - else if (c->GetLevel() <= 17){ - Charmer->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Charmer->Say("Mob Is not undead...", c->GetName()); - break; - - case DRUID: - if ((c->GetLevel() >= 13) && (DBtype == 21)) { - Charmer->Say("Trying to charm %s \n", target->GetCleanName(), sep->arg[2]); - Charmer->CastToBot()->Bot_Command_CharmTarget (3,target); - } - else if (c->GetLevel() <= 12){ - Charmer->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Charmer->Say("Mob is not an animal...", c->GetName()); - break; - - default: - c->Message(15, "You must have an Enchanter, Necromancer or Druid in your group."); - break; - } - } - } - - // Remove Bot's Pet - if(!strcasecmp(sep->arg[1], "pet") && !strcasecmp(sep->arg[2], "remove")) { - if(c->GetTarget() != nullptr) { - if (c->IsGrouped() && c->GetTarget()->IsBot() && (c->GetTarget()->CastToBot()->GetBotOwner() == c) && - ((c->GetTarget()->GetClass() == NECROMANCER) || (c->GetTarget()->GetClass() == ENCHANTER) || (c->GetTarget()->GetClass() == DRUID))) { - if(c->GetTarget()->CastToBot()->IsBotCharmer()) { - c->GetTarget()->CastToBot()->SetBotCharmer(false); - c->GetTarget()->Say("Using a summoned pet."); - } - else { - if(c->GetTarget()->GetPet()) - { - c->GetTarget()->GetPet()->Say_StringID(PET_GETLOST_STRING); - // c->GetTarget()->GetPet()->Kill(); - c->GetTarget()->GetPet()->Depop(false); - c->GetTarget()->SetPetID(0); - } - c->GetTarget()->CastToBot()->SetBotCharmer(true); - c->GetTarget()->Say("Available for Dire Charm command."); - } - } - else { - c->Message(15, "You must target your Enchanter, Necromancer, or Druid bot."); - } - } - else { - c->Message(15, "You must target an Enchanter, Necromancer, or Druid bot."); - } - return; - } - - //Dire Charm - if(!strcasecmp(sep->arg[1], "Dire") && !strcasecmp(sep->arg[2], "Charm")) - { - Mob *target = c->GetTarget(); - if(target == nullptr || target->IsClient() || target->IsBot() || (target->IsPet() && target->GetOwner()->IsBot())) - { - c->Message(15, "You must select a monster"); - return; - } - uint32 DBtype = c->GetTarget()->GetBodyType(); - Mob *Direr; - uint32 DirerClass = 0; - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case ENCHANTER: - Direr = g->members[i]; - DirerClass = ENCHANTER; - break; - case NECROMANCER: - if(DirerClass != ENCHANTER){ - Direr = g->members[i]; - DirerClass = NECROMANCER; - } - case DRUID: - if (DirerClass == 0){ - Direr = g->members[i]; - DirerClass = DRUID; - } - break; - break; - default: - break; - } - } - } - switch(DirerClass) { - case ENCHANTER: - if (c->GetLevel() >= 55) { - Direr->Say("Trying to dire charm %s \n", target->GetCleanName(), sep->arg[2]); - Direr->CastToBot()->Bot_Command_DireTarget (1,target); - } - else if (c->GetLevel() <= 55){ - Direr->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Direr->Say("Mob level is too high or can't be charmed", c->GetName()); - break; - - case NECROMANCER: - if ((c->GetLevel() >= 55) && (DBtype == 3)) { - Direr->Say("Trying to dire charm %s \n", target->GetCleanName(), sep->arg[2]); - Direr->CastToBot()->Bot_Command_DireTarget (2,target); - } - else if (c->GetLevel() <= 55){ - Direr->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Direr->Say("Mob Is not undead...", c->GetName()); - break; - - case DRUID: - if ((c->GetLevel() >= 55) && (DBtype == 21)) { - Direr->Say("Trying to dire charm %s \n", target->GetCleanName(), sep->arg[2]); - Direr->CastToBot()->Bot_Command_DireTarget (3,target); - } - else if (c->GetLevel() <= 55){ - Direr->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Direr->Say("Mob is not an animal...", c->GetName()); - break; - - default: - c->Message(15, "You must have an Enchanter, Necromancer or Druid in your group."); - break; - } - } - } - - // Evacuate - if(!strcasecmp(sep->arg[1], "evac")) { - Mob *evac = nullptr; - bool hasevac = false; - if(c->IsGrouped()) - { - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == DRUID)) - || (g->members[i] && g->members[i]->IsBot() && (g->members[i]->GetClass() == WIZARD))) - { - hasevac = true; - evac = g->members[i]; - } - } - if(!hasevac) { - c->Message(15, "You must have a Druid in your group."); - } - } - } - if((hasevac) && (c->GetLevel() >= 18)) { - evac->Say("Attempting to Evac you %s.", c->GetName()); - evac->CastToClient()->CastSpell(2183, c->GetID(), 1, -1, -1); - } - else if((hasevac) && (c->GetLevel() <= 17)) { - evac->Say("I'm not level 18 yet.", c->GetName()); - } - return; - } - - // Sow - if ((!strcasecmp(sep->arg[1], "sow")) && (c->IsGrouped())) { - Mob *Sower; - uint32 SowerClass = 0; - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case DRUID: - Sower = g->members[i]; - SowerClass = DRUID; - break; - case SHAMAN: - if (SowerClass != DRUID){ - Sower = g->members[i]; - SowerClass = SHAMAN; - } - break; - case RANGER: - if (SowerClass == 0){ - Sower = g->members[i]; - SowerClass = RANGER; - } - break; - case BEASTLORD: - if (SowerClass == 0){ - Sower = g->members[i]; - SowerClass = BEASTLORD; - } - break; - default: - break; - } - } - } - switch(SowerClass) { - case DRUID: - if ((!strcasecmp(sep->arg[2], "regular")) && (zone->CanCastOutdoor()) && (c->GetLevel() >= 10) ) { - Sower->Say("Casting sow..."); - Sower->CastSpell(278, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "regular")) && (zone->CanCastOutdoor()) && (c->GetLevel() <= 10) ) { - Sower->Say("I'm not level 10 yet."); - } - else if ((!strcasecmp(sep->arg[2], "wolf")) && zone->CanCastOutdoor() && (c->GetLevel() >= 20)) { - Sower->Say("Casting group wolf..."); - Sower->CastSpell(428, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "wolf")) && (c->GetLevel() <= 20)) { - Sower->Say("I'm not level 20 yet."); - } - else if ((!strcasecmp(sep->arg[2], "feral")) && (c->GetLevel() >= 50)) { - Sower->Say("Casting Feral Pack..."); - Sower->CastSpell(4058, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "feral")) && (c->GetLevel() <= 50)) { - Sower->Say("I'm not level 50 yet."); - } - else if ((!strcasecmp(sep->arg[2], "shrew")) && (c->GetLevel() >= 35)) { - Sower->Say("Casting Pack Shrew..."); - Sower->CastSpell(4055, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "wolf")) && (c->GetLevel() <= 35)) { - Sower->Say("I'm not level 35 yet."); - } - else if ((!zone->CanCastOutdoor()) && (!strcasecmp(sep->arg[2], "regular")) || - (!zone->CanCastOutdoor()) && (!strcasecmp(sep->arg[2], "wolf"))) { - Sower->Say("I can't cast this spell indoors, try [sow shrew] if you're 35 or higher, or [sow feral] if you're 50 or higher,", c->GetName()); - } - else if (!zone->CanCastOutdoor()) { - Sower->Say("I can't cast this spell indoors, try [sow shrew] if you're 35 or higher, or [sow feral] if you're 50 or higher,", c->GetName()); - } - else if (zone->CanCastOutdoor()) { - Sower->Say("Do you want [sow regular] or [sow wolf]?", c->GetName()); - } - else if (!zone->CanCastOutdoor()) { - Sower->Say("I can't cast this spell indoors, try [sow shrew] if you're 35 or higher, or [sow feral] if you're 50 or higher,", c->GetName()); - } - break; - - case SHAMAN: - - if ((zone->CanCastOutdoor()) && (c->GetLevel() >= 9)) { - Sower->Say("Casting SoW..."); - Sower->CastToClient()->CastSpell(278, c->GetID(), 1, -1, -1); - } - else if (!zone->CanCastOutdoor()) { - Sower->Say("I can't cast this spell indoors", c->GetName()); - } - else if (c->GetLevel() <= 9) { - Sower->Say("I'm not level 9 yet."); - } - break; - - case RANGER: - - if ((zone->CanCastOutdoor()) && (c->GetLevel() >= 28)){ - Sower->Say("Casting SoW..."); - Sower->CastToClient()->CastSpell(278, c->GetID(), 1, -1, -1); - } - else if (!zone->CanCastOutdoor()) { - Sower->Say("I can't cast this spell indoors", c->GetName()); - } - else if (c->GetLevel() <= 28) { - Sower->Say("I'm not level 28 yet."); - } - break; - - case BEASTLORD: - - if((zone->CanCastOutdoor()) && (c->GetLevel() >= 24)) { - Sower->Say("Casting SoW..."); - Sower->CastToClient()->CastSpell(278, c->GetID(), 1, -1, -1); - } - else if (!zone->CanCastOutdoor()) { - Sower->Say("I can't cast this spell indoors", c->GetName()); - } - else if (c->GetLevel() <= 24) { - Sower->Say("I'm not level 24 yet."); - } - break; - - - default: - c->Message(15, "You must have a Druid, Shaman, Ranger, or Beastlord in your group."); - break; - } - } - } - - // Shrink - if ((!strcasecmp(sep->arg[1], "shrink")) && (c->IsGrouped())) { - Mob *Shrinker; - uint32 ShrinkerClass = 0; - Group *g = c->GetGroup(); - Mob *target = c->GetTarget(); - - if(target == nullptr || (!target->IsClient() && (c->GetTarget()->CastToBot()->GetBotOwner() != c))) - c->Message(15, "You must select a player or bot you own"); - - else if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case SHAMAN: - Shrinker = g->members[i]; - ShrinkerClass = SHAMAN; - break; - case BEASTLORD: - if (ShrinkerClass != SHAMAN){ - Shrinker = g->members[i]; - ShrinkerClass = BEASTLORD; - } - break; - default: - break; - } - } - } - switch(ShrinkerClass) { - case SHAMAN: - - if (c->GetLevel() >= 15) { - Shrinker->Say("Casting Shrink..."); - Shrinker->CastToBot()->SpellOnTarget(345, target); - } - else if (c->GetLevel() <= 14) { - Shrinker->Say("I'm not level 15 yet."); - } - break; - - case BEASTLORD: - - if (c->GetLevel() >= 23) { - Shrinker->Say("Casting Shrink..."); - Shrinker->CastToBot()->SpellOnTarget(345, target); - } - else if (c->GetLevel() <= 22) { - Shrinker->Say("I'm not level 23 yet."); - } - break; - - default: - c->Message(15, "You must have a Shaman or Beastlord in your group."); - break; - } - } - } - - // Gate - if ((!strcasecmp(sep->arg[1], "gate")) && (c->IsGrouped())) { - Mob *Gater; - uint32 GaterClass = 0; - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case DRUID: - Gater = g->members[i]; - GaterClass = DRUID; - break; - case WIZARD: - if (GaterClass == 0){ - Gater = g->members[i]; - GaterClass = WIZARD; - } - break; - default: - break; - } - } - } - switch(GaterClass) { - case DRUID: - if ((!strcasecmp(sep->arg[2], "karana")) && (c->GetLevel() >= 25) ) { - Gater->Say("Casting Circle of Karana..."); - Gater->CastSpell(550, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "commons")) && (c->GetLevel() >= 27)) { - Gater->Say("Casting Circle of Commons..."); - Gater->CastSpell(551, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "tox")) && (c->GetLevel() >= 25)) { - Gater->Say("Casting Circle of Toxxulia..."); - Gater->CastSpell(552, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "butcher")) && (c->GetLevel() >= 25)) { - Gater->Say("Casting Circle of Butcherblock..."); - Gater->CastSpell(553, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "lava")) && (c->GetLevel() >= 30)) { - Gater->Say("Casting Circle of Lavastorm..."); - Gater->CastSpell(554, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "ro")) && (c->GetLevel() >= 32)) { - Gater->Say("Casting Circle of Ro..."); - Gater->CastSpell(555, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "feerrott")) && (c->GetLevel() >= 32)) { - Gater->Say("Casting Circle of feerrott..."); - Gater->CastSpell(556, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "steamfont")) && (c->GetLevel() >= 31)) { - Gater->Say("Casting Circle of Steamfont..."); - Gater->CastSpell(557, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "misty")) && (c->GetLevel() >= 36)) { - Gater->Say("Casting Circle of Misty..."); - Gater->CastSpell(558, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "wakening")) && (c->GetLevel() >= 40)) { - Gater->Say("Casting Circle of Wakening Lands..."); - Gater->CastSpell(1398, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "iceclad")) && (c->GetLevel() >= 32)) { - Gater->Say("Casting Circle of Iceclad Ocean..."); - Gater->CastSpell(1434, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "divide")) && (c->GetLevel() >= 36)) { - Gater->Say("Casting Circle of The Great Divide..."); - Gater->CastSpell(1438, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "cobalt")) && (c->GetLevel() >= 42)) { - Gater->Say("Casting Circle of Cobalt Scar..."); - Gater->CastSpell(1440, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "combines")) && (c->GetLevel() >= 33)) { - Gater->Say("Casting Circle of The Combines..."); - Gater->CastSpell(1517, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "surefall")) && (c->GetLevel() >= 26)) { - Gater->Say("Casting Circle of Surefall Glade..."); - Gater->CastSpell(2020, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "grimling")) && (c->GetLevel() >= 29)) { - Gater->Say("Casting Circle of Grimling Forest..."); - Gater->CastSpell(2419, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "twilight")) && (c->GetLevel() >= 33)) { - Gater->Say("Casting Circle of Twilight..."); - Gater->CastSpell(2424, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "dawnshroud")) && (c->GetLevel() >= 37)) { - Gater->Say("Casting Circle of Dawnshroud..."); - Gater->CastSpell(2429, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "nexus")) && (c->GetLevel() >= 26)) { - Gater->Say("Casting Circle of The Nexus..."); - Gater->CastSpell(2432, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "pok")) && (c->GetLevel() >= 38)) { - Gater->Say("Casting Circle of Knowledge..."); - Gater->CastSpell(3184, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "stonebrunt")) && (c->GetLevel() >= 28)) { - Gater->Say("Casting Circle of Stonebrunt Mountains..."); - Gater->CastSpell(3792, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "bloodfields")) && (c->GetLevel() >= 55)) { - Gater->Say("Casting Circle of Bloodfields..."); - Gater->CastSpell(6184, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "emerald")) && (c->GetLevel() >= 39)) { - Gater->Say("Casting Wind of the South..."); - Gater->CastSpell(1737, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "skyfire")) && (c->GetLevel() >= 44)) { - Gater->Say("Casting Wind of the North..."); - Gater->CastSpell(1736, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "slaughter")) && (c->GetLevel() >= 64)) { - Gater->Say("Casting Circle of Slaughter..."); - Gater->CastSpell(6179, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "karana") - || !strcasecmp(sep->arg[2], "tox") - || !strcasecmp(sep->arg[2], "butcher") && (c->GetLevel() <= 25)) - || !strcasecmp(sep->arg[2], "commons") && (c->GetLevel() <= 27) - || (!strcasecmp(sep->arg[2], "ro") - || !strcasecmp(sep->arg[2], "feerrott") && (c->GetLevel() <= 32)) - || !strcasecmp(sep->arg[2], "steamfont") && (c->GetLevel() <= 31) - || !strcasecmp(sep->arg[2], "misty") && (c->GetLevel() <= 36) - || !strcasecmp(sep->arg[2], "lava") && (c->GetLevel() <= 30) - || !strcasecmp(sep->arg[2], "wakening") && (c->GetLevel() <= 40) - || !strcasecmp(sep->arg[2], "iceclad") && (c->GetLevel() <= 32) - || !strcasecmp(sep->arg[2], "divide") && (c->GetLevel() <= 38) - || !strcasecmp(sep->arg[2], "cobalt") && (c->GetLevel() <= 42) - || !strcasecmp(sep->arg[2], "combines") && (c->GetLevel() <= 33) - || !strcasecmp(sep->arg[2], "surefall") && (c->GetLevel() <= 26) - || !strcasecmp(sep->arg[2], "grimling") && (c->GetLevel() <= 29) - || !strcasecmp(sep->arg[2], "twilight") && (c->GetLevel() <= 33) - || !strcasecmp(sep->arg[2], "dawnshroud") && (c->GetLevel() <= 37) - || !strcasecmp(sep->arg[2], "nexus") && (c->GetLevel() <= 26) - || !strcasecmp(sep->arg[2], "pok") && (c->GetLevel() <= 38) - || !strcasecmp(sep->arg[2], "stonebrunt") && (c->GetLevel() <= 28) - || !strcasecmp(sep->arg[2], "bloodfields") && (c->GetLevel() <= 55) - || !strcasecmp(sep->arg[2], "emerald") && (c->GetLevel() <= 38) - || !strcasecmp(sep->arg[2], "skyfire") && (c->GetLevel() <= 43) - || !strcasecmp(sep->arg[2], "wos") && (c->GetLevel() <= 64)) { - Gater->Say("I don't have the needed level yet", sep->arg[2]); - } - else { - Gater->Say("With the proper level I can [gate] to [karana],[commons],[tox],[butcher],[lava],[ro],[feerrott],[steamfont],[misty],[wakening],[iceclad],[divide],[cobalt],[combines],[surefall],[grimling],[twilight],[dawnshroud],[nexus],[pok],[stonebrunt],[bloodfields],[emerald],[skyfire] or [wos].", c->GetName()); - } - break; - - case WIZARD: - - if ((!strcasecmp(sep->arg[2], "commons")) && (c->GetLevel() >= 35) ) { - Gater->Say("Casting Common Portal..."); - Gater->CastSpell(566, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "fay")) && (c->GetLevel() >= 27)) { - Gater->Say("Casting Fay Portal..."); - Gater->CastSpell(563, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "ro")) && (c->GetLevel() >= 37)) { - Gater->Say("Casting Ro Portal..."); - Gater->CastSpell(567, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "tox")) && (c->GetLevel() >= 25)) { - Gater->Say("Casting Toxxula Portal..."); - Gater->CastSpell(561, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "nk")) && (c->GetLevel() >= 27)) { - Gater->Say("Casting North Karana Portal..."); - Gater->CastSpell(562, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "nek")) && (c->GetLevel() >= 32)) { - Gater->Say("Casting Nektulos Portal..."); - Gater->CastSpell(564, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "wakening")) && (c->GetLevel() >= 43)) { - Gater->Say("Casting Wakening Lands Portal..."); - Gater->CastSpell(1399, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "iceclad")) && (c->GetLevel() >= 33)) { - Gater->Say("Casting Iceclad Ocean Portal..."); - Gater->CastSpell(1418, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "divide")) && (c->GetLevel() >= 36)) { - Gater->Say("Casting Great Divide Portal..."); - Gater->CastSpell(1423, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "cobalt")) && (c->GetLevel() >= 43)) { - Gater->Say("Casting Cobalt Scar Portal..."); - Gater->CastSpell(1425, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "combines")) && (c->GetLevel() >= 34)) { - Gater->Say("Casting Combines Portal..."); - Gater->CastSpell(1516, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "wk")) && (c->GetLevel() >= 27)) { - Gater->Say("Casting West Karana Portal..."); - Gater->CastSpell(568, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "twilight")) && (c->GetLevel() >= 27)) { - Gater->Say("Casting Twilight Portal..."); - Gater->CastSpell(2425, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "dawnshroud")) && (c->GetLevel() >= 27)) { - Gater->Say("Casting Dawnshroud Portal..."); - Gater->CastSpell(2430, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "nexus")) && (c->GetLevel() >= 29)) { - Gater->Say("Casting Nexus Portal..."); - Gater->CastSpell(2944, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "pok")) && (c->GetLevel() >= 27)) { - Gater->Say("Casting Plane of Knowledge Portal..."); - Gater->CastSpell(3180, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "wos")) && (c->GetLevel() >= 27)) { - Gater->Say("Casting Wall of Slaughter Portal..."); - Gater->CastSpell(6178, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "grimling")) && (c->GetLevel() >= 29)) { - Gater->Say("Casting Fay Portal..."); - Gater->CastSpell(2420, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "emerald")) && (c->GetLevel() >= 37)) { - Gater->Say("Porting to Emerald Jungle..."); - Gater->CastSpell(1739, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "hateplane")) && (c->GetLevel() >= 39)) { - Gater->Say("Porting to Hate Plane..."); - Gater->CastSpell(666, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "airplane")) && (c->GetLevel() >= 39)) { - Gater->Say("Porting to airplane..."); - Gater->CastSpell(674, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "skyfire")) && (c->GetLevel() >= 36)) { - Gater->Say("Porting to Skyfire..."); - Gater->CastSpell(1738, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "bloodfields")) && (c->GetLevel() >= 55)) { - Gater->Say("Casting Bloodfields Portal..."); - Gater->CastSpell(6183, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "stonebrunt")) && (c->GetLevel() >= 27)) { - Gater->Say("Casting Stonebrunt Portal..."); - Gater->CastSpell(3793, c->GetID(), 1, -1, -1); - } - else if ((!strcasecmp(sep->arg[2], "commons") && (c->GetLevel() <= 35)) - || !strcasecmp(sep->arg[2], "fay") && (c->GetLevel() <= 27) - || (!strcasecmp(sep->arg[2], "ro") && (c->GetLevel() <= 37)) - || !strcasecmp(sep->arg[2], "tox") && (c->GetLevel() <= 25) - || !strcasecmp(sep->arg[2], "nk") && (c->GetLevel() <= 25) - || !strcasecmp(sep->arg[2], "nek") && (c->GetLevel() <= 32) - || !strcasecmp(sep->arg[2], "wakening") && (c->GetLevel() <= 43) - || !strcasecmp(sep->arg[2], "iceclad") && (c->GetLevel() <= 33) - || !strcasecmp(sep->arg[2], "divide") && (c->GetLevel() <= 36) - || !strcasecmp(sep->arg[2], "cobalt") && (c->GetLevel() <= 43) - || !strcasecmp(sep->arg[2], "combines") && (c->GetLevel() <= 34) - || !strcasecmp(sep->arg[2], "wk") && (c->GetLevel() <= 37) - || !strcasecmp(sep->arg[2], "twilight") && (c->GetLevel() <= 33) - || !strcasecmp(sep->arg[2], "dawnshroud") && (c->GetLevel() <= 39) - || !strcasecmp(sep->arg[2], "nexus") && (c->GetLevel() <= 29) - || (!strcasecmp(sep->arg[2], "pok") - || !strcasecmp(sep->arg[2], "hateplane") - || !strcasecmp(sep->arg[2], "airplane") && (c->GetLevel() <= 38)) - || !strcasecmp(sep->arg[2], "grimling") && (c->GetLevel() <= 29) - || !strcasecmp(sep->arg[2], "bloodfields") && (c->GetLevel() <= 55) - || !strcasecmp(sep->arg[2], "stonebrunt") && (c->GetLevel() <= 27) - || !strcasecmp(sep->arg[2], "emerald") && (c->GetLevel() <= 36) - || !strcasecmp(sep->arg[2], "skyfire") && (c->GetLevel() <= 36) - || !strcasecmp(sep->arg[2], "wos") && (c->GetLevel() <= 64)) { - Gater->Say("I don't have the needed level yet", sep->arg[2]); - } - else { - Gater->Say("With the proper level I can [gate] to [commons],[fay],[ro],[tox],[nk],[wakening],[iceclad],[divide],[cobalt],[combines],[wk],[grimling],[twilight],[dawnshroud],[nexus],[pok],[stonebrunt],[bloodfields],[emerald],[skyfire],[hateplane],[airplane] or [wos].", c->GetName()); - } - break; - default: - c->Message(15, "You must have a Druid or Wizard in your group."); - break; - } - } - } - - //Endure Breath - if ((!strcasecmp(sep->arg[1], "endureb")) && (c->IsGrouped())) { - Mob *Endurer; - uint32 EndurerClass = 0; - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case DRUID: - Endurer = g->members[i]; - EndurerClass = DRUID; - break; - case SHAMAN: - if (EndurerClass != DRUID){ - Endurer = g->members[i]; - EndurerClass = SHAMAN; - } - break; - case ENCHANTER: - if(EndurerClass == 0){ - Endurer = g->members[i]; - EndurerClass = ENCHANTER; - } - break; - case RANGER: - if(EndurerClass == 0) { - Endurer = g->members[i]; - EndurerClass = RANGER; - } - break; - case BEASTLORD: - if(EndurerClass == 0) { - Endurer = g->members[i]; - EndurerClass = BEASTLORD; - } - break; - default: - break; - } - } - } - switch(EndurerClass) { - case DRUID: - if (c->GetLevel() < 6) { - Endurer->Say("I'm not level 6 yet."); - } - else { - Endurer->Say("Casting Enduring Breath..."); - Endurer->CastSpell(86, c->GetID(), 1, -1, -1); - break; - } - break; - case SHAMAN: - if (c->GetLevel() < 12) { - Endurer->Say("I'm not level 12 yet."); - } - else { - Endurer->Say("Casting Enduring Breath..."); - Endurer->CastSpell(86, c->GetID(), 1, -1, -1); - } - break; - case RANGER: - if (c->GetLevel() < 20) { - Endurer->Say("I'm not level 20 yet."); - } - else { - Endurer->Say("Casting Enduring Breath..."); - Endurer->CastSpell(86, c->GetID(), 1, -1, -1); - } - break; - case ENCHANTER: - if (c->GetLevel() < 12) { - Endurer->Say("I'm not level 12 yet."); - } - else { - Endurer->Say("Casting Enduring Breath..."); - Endurer->CastSpell(86, c->GetID(), 1, -1, -1); - } - break; - case BEASTLORD: - if (c->GetLevel() < 25) { - Endurer->Say("I'm not level 25 yet."); - } - else { - Endurer->Say("Casting Enduring Breath..."); - Endurer->CastSpell(86, c->GetID(), 1, -1, -1); - } - break; - default: - c->Message(15, "You must have a Druid, Shaman, Ranger, Enchanter, or Beastlord in your group."); - break; - } - } - } - - //Invisible - if ((!strcasecmp(sep->arg[1], "invis")) && (c->IsGrouped())) { - Mob *Inviser; - uint32 InviserClass = 0; - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case ENCHANTER: - Inviser = g->members[i]; - InviserClass = ENCHANTER; - break; - case MAGICIAN: - if (InviserClass != ENCHANTER){ - Inviser = g->members[i]; - InviserClass = MAGICIAN; - } - break; - case WIZARD: - if((InviserClass != ENCHANTER) && (InviserClass != MAGICIAN)){ - Inviser = g->members[i]; - InviserClass = WIZARD; - } - break; - case NECROMANCER: - if(InviserClass == 0){ - Inviser = g->members[i]; - InviserClass = NECROMANCER; - } - break; - case DRUID: - if((InviserClass != ENCHANTER) && (InviserClass != WIZARD) - || (InviserClass != MAGICIAN)){ - Inviser = g->members[i]; - InviserClass = DRUID; - } - break; - default: - break; - } - } - } - switch(InviserClass) { - case ENCHANTER: - if ((c->GetLevel() <= 14) && (!strcasecmp(sep->arg[2], "undead"))) { - Inviser->Say("I'm not level 14 yet."); - } - else if ((!c->IsInvisible(c)) && (!c->invisible_undead) && (c->GetLevel() >= 14) && (!strcasecmp(sep->arg[2], "undead"))) { - Inviser->Say("Casting invis undead..."); - Inviser->CastSpell(235, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() <= 4) && (!strcasecmp(sep->arg[2], "live"))) { - Inviser->Say("I'm not level 4 yet."); - } - else if ((!c->IsInvisible(c))&& (!c->invisible_undead) && (c->GetLevel() >= 4) && (!strcasecmp(sep->arg[2], "live"))) { - Inviser->Say("Casting invisibilty..."); - Inviser->CastSpell(42, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() <= 6) && (!strcasecmp(sep->arg[2], "see"))) { - Inviser->Say("I'm not level 6 yet."); - } - else if ((c->GetLevel() >= 6) && (!strcasecmp(sep->arg[2], "see"))) { - Inviser->Say("Casting see invisible..."); - Inviser->CastSpell(80, c->GetID(), 1, -1, -1); - } - else if ((c->IsInvisible(c)) || (c->invisible_undead)) { - Inviser->Say("I can't cast this if you're already invis-buffed..."); - } - else { - Inviser->Say("Do you want [invis undead], [invis live] or [invis see] ?", c->GetName()); - } - break; - case MAGICIAN: - if (!strcasecmp(sep->arg[2], "undead")) { - Inviser->Say("I don't have that spell."); - } - else if ((c->GetLevel() <= 8) && (!strcasecmp(sep->arg[2], "live"))) { - Inviser->Say("I'm not level 8 yet."); - } - else if ((!c->IsInvisible(c))&& (!c->invisible_undead) && (c->GetLevel() >= 8) && (!strcasecmp(sep->arg[2], "live"))) { - Inviser->Say("Casting invisibilty..."); - Inviser->CastSpell(42, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() <= 16) && (!strcasecmp(sep->arg[2], "see"))) { - Inviser->Say("I'm not level 16 yet."); - } - else if ((c->GetLevel() >= 16) && (!strcasecmp(sep->arg[2], "see"))) { - Inviser->Say("Casting see invisible..."); - Inviser->CastSpell(80, c->GetID(), 1, -1, -1); - } - else if ((c->IsInvisible(c)) || (c->invisible_undead)) { - Inviser->Say("I can't cast this if you're already invis-buffed..."); - } - else { - Inviser->Say("Do you want [invis live] or [invis see] ?", c->GetName()); - } - break; - case WIZARD: - if ((c->GetLevel() <= 39) && (!strcasecmp(sep->arg[2], "undead"))) { - Inviser->Say("I'm not level 39 yet."); - } - else if ((!c->IsInvisible(c))&& (!c->invisible_undead) && (c->GetLevel() >= 39) && (!strcasecmp(sep->arg[2], "undead"))) { - Inviser->Say("Casting invis undead..."); - Inviser->CastSpell(235, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() <= 16) && (!strcasecmp(sep->arg[2], "live"))) { - Inviser->Say("I'm not level 16 yet."); - } - else if ((!c->IsInvisible(c))&& (!c->invisible_undead) && (c->GetLevel() >= 16) && (!strcasecmp(sep->arg[2], "live"))) { - Inviser->Say("Casting invisibilty..."); - Inviser->CastSpell(42, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() <= 4) && (!strcasecmp(sep->arg[2], "see"))) { - Inviser->Say("I'm not level 6 yet."); - } - else if ((c->GetLevel() >= 4) && (!strcasecmp(sep->arg[2], "see"))) { - Inviser->Say("Casting see invisible..."); - Inviser->CastSpell(80, c->GetID(), 1, -1, -1); - } - else if ((c->IsInvisible(c)) || (c->invisible_undead)) { - Inviser->Say("I can't cast this if you're already invis-buffed..."); - } - else { - Inviser->Say("Do you want [invis undead], [invis live] or [invis see] ?", c->GetName()); - } - break; - case NECROMANCER: - if ((!c->IsInvisible(c))&& (!c->invisible_undead) && (!strcasecmp(sep->arg[2], "undead"))) { - Inviser->Say("Casting invis undead..."); - Inviser->CastSpell(235, c->GetID(), 1, -1, -1); - } - else if (!strcasecmp(sep->arg[2], "see")) { - Inviser->Say("I don't have that spell..."); - } - else if (!strcasecmp(sep->arg[2], "live")) { - Inviser->Say("I don't have that spell..."); - } - else if ((c->IsInvisible(c))|| (c->invisible_undead)) { - Inviser->Say("I can't cast this if you're already invis-buffed..."); - } - else { - Inviser->Say("I only have [invis undead]", c->GetName()); - } - break; - case DRUID: - if (!strcasecmp(sep->arg[2], "undead")) { - Inviser->Say("I don't have that spell..."); - } - else if ((c->GetLevel() <= 4) && (!strcasecmp(sep->arg[2], "live"))) { - Inviser->Say("I'm not level 4 yet."); - } - else if ((!c->IsInvisible(c))&& (!c->invisible_undead) && (c->GetLevel() >= 18) && (!strcasecmp(sep->arg[2], "live"))) { - Inviser->Say("Casting Superior Camouflage..."); - Inviser->CastSpell(34, c->GetID(), 1, -1, -1); - } - else if ((!c->IsInvisible(c))&& (!c->invisible_undead) && (c->GetLevel() >= 4) && (!strcasecmp(sep->arg[2], "live")) && (zone->CanCastOutdoor())) { - Inviser->Say("Casting Camouflage..."); - Inviser->CastSpell(247, c->GetID(), 1, -1, -1); - } - else if ((c->GetLevel() >= 4) && (!strcasecmp(sep->arg[2], "live")) && (!zone->CanCastOutdoor())) { - Inviser->Say("I can't cast this spell indoors..."); - } - else if ((c->GetLevel() <= 13) && (!strcasecmp(sep->arg[2], "see"))) { - Inviser->Say("I'm not level 13 yet."); - } - else if ((c->GetLevel() >= 13) && (!strcasecmp(sep->arg[2], "see"))) { - Inviser->Say("Casting see invisible..."); - Inviser->CastSpell(80, c->GetID(), 1, -1, -1); - } - else if ((c->IsInvisible(c)) || (c->invisible_undead)) { - Inviser->Say("I can't cast this if you're already invis-buffed..."); - } - else { - Inviser->Say("Do you want [invis live] or [invis see] ?", c->GetName()); - } - break; - default: - c->Message(15, "You must have a Enchanter, Magician, Wizard, Druid, or Necromancer in your group."); - break; - } - } - } - - //Levitate - if ((!strcasecmp(sep->arg[1], "levitate")) && (c->IsGrouped())) { - Mob *Lever; - uint32 LeverClass = 0; - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case DRUID: - Lever = g->members[i]; - LeverClass = DRUID; - break; - case SHAMAN: - if (LeverClass != DRUID){ - Lever = g->members[i]; - LeverClass = SHAMAN; - } - break; - case WIZARD: - if(LeverClass == 0){ - Lever = g->members[i]; - LeverClass = WIZARD; - } - break; - case ENCHANTER: - if (LeverClass == 0) { - Lever = g->members[i]; - LeverClass = ENCHANTER; - } - break; - default: - break; - } - } - } - switch(LeverClass) { - case DRUID: - if (c->GetLevel() <= 14) { - Lever->Say("I'm not level 14 yet."); - } - else if (zone->CanCastOutdoor()) { - Lever->Say("Casting Levitate..."); - Lever->CastSpell(261, c->GetID(), 1, -1, -1); - break; - } - else if (!zone->CanCastOutdoor()) { - Lever->Say("I can't cast this spell indoors", c->GetName()); - } - break; - - case SHAMAN: - - if ((zone->CanCastOutdoor()) && (c->GetLevel() >= 10)) { - Lever->Say("Casting Levitate..."); - Lever->CastToClient()->CastSpell(261, c->GetID(), 1, -1, -1); - } - else if (!zone->CanCastOutdoor()) { - Lever->Say("I can't cast this spell indoors", c->GetName()); - } - else if (c->GetLevel() <= 10) { - Lever->Say("I'm not level 10 yet."); - } - break; - - case WIZARD: - - if((zone->CanCastOutdoor()) && (c->GetLevel() >= 22)){ - Lever->Say("Casting Levitate..."); - Lever->CastToClient()->CastSpell(261, c->GetID(), 1, -1, -1); - } - else if (!zone->CanCastOutdoor()) { - Lever->Say("I can't cast this spell indoors", c->GetName()); - } - else if (c->GetLevel() <= 22) { - Lever->Say("I'm not level 22 yet."); - } - break; - - case ENCHANTER: - - if((zone->CanCastOutdoor()) && (c->GetLevel() >= 15)) { - Lever->Say("Casting Levitate..."); - Lever->CastToClient()->CastSpell(261, c->GetID(), 1, -1, -1); - } - else if (!zone->CanCastOutdoor()) { - Lever->Say("I can't cast this spell indoors", c->GetName()); - } - else if (c->GetLevel() <= 15) { - Lever->Say("I'm not level 15 yet."); - } - break; - - - default: - c->Message(15, "You must have a Druid, Shaman, Wizard, or Enchanter in your group."); - break; - } - } - } - - //Resists - if ((!strcasecmp(sep->arg[1], "resist")) && (c->IsGrouped())) { - Mob *Resister; - uint32 ResisterClass = 0; - Group *g = c->GetGroup(); - if(g) { - for(int i=0; imembers[i] && g->members[i]->IsBot()) { - switch(g->members[i]->GetClass()) { - case CLERIC: - Resister = g->members[i]; - ResisterClass = CLERIC; - break; - case SHAMAN: - if(ResisterClass != CLERIC){ - Resister = g->members[i]; - ResisterClass = SHAMAN; - } - case DRUID: - if (ResisterClass == 0){ - Resister = g->members[i]; - ResisterClass = DRUID; - } - break; - break; - default: - break; - } - } - } - switch(ResisterClass) { - case CLERIC: - if (!strcasecmp(sep->arg[2], "poison") && (c->GetLevel() >= 6)) { - Resister->Say("Casting poison protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(1, Resister->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "disease") && (c->GetLevel() >= 11)) { - Resister->Say("Casting disease protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(2, Resister->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "fire") && (c->GetLevel() >= 8)) { - Resister->Say("Casting fire protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(3, Resister->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "cold") && (c->GetLevel() >= 13)) { - Resister->Say("Casting cold protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(4, Resister->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "magic") && (c->GetLevel() >= 16)) { - Resister->Say("Casting magic protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(5, Resister->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "magic") && (c->GetLevel() <= 16) - || !strcasecmp(sep->arg[2], "cold") && (c->GetLevel() <= 13) - || !strcasecmp(sep->arg[2], "fire") && (c->GetLevel() <= 8) - || !strcasecmp(sep->arg[2], "disease") && (c->GetLevel() <= 11) - || !strcasecmp(sep->arg[2], "poison") && (c->GetLevel() <= 6)) { - Resister->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Resister->Say("Do you want [resist poison], [resist disease], [resist fire], [resist cold], or [resist magic]?", c->GetName()); - - break; - - case SHAMAN: - if (!strcasecmp(sep->arg[2], "poison") && (c->GetLevel() >= 20)) { - Resister->Say("Casting poison protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(12, Resister->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "disease") && (c->GetLevel() >= 8)) { - Resister->Say("Casting disease protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(13, Resister->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "fire") && (c->GetLevel() >= 5)) { - Resister->Say("Casting fire protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(14, Resister->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "cold") && (c->GetLevel() >= 1)) { - Resister->Say("Casting cold protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(15, Resister->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "magic") && (c->GetLevel() >= 19)) { - Resister->Say("Casting magic protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(16, Resister->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "magic") && (c->GetLevel() <= 19) - || !strcasecmp(sep->arg[2], "cold") && (c->GetLevel() <= 1) - || !strcasecmp(sep->arg[2], "fire") && (c->GetLevel() <= 5) - || !strcasecmp(sep->arg[2], "disease") && (c->GetLevel() <= 8) - || !strcasecmp(sep->arg[2], "poison") && (c->GetLevel() <= 20)) { - Resister->Say("I don't have the needed level yet", sep->arg[2]); - } - else - Resister->Say("Do you want [resist poison], [resist disease], [resist fire], [resist cold], or [resist magic]?", c->GetName()); - - break; - - case DRUID: - - if (!strcasecmp(sep->arg[2], "poison") && (c->GetLevel() >= 19)) { - Resister->Say("Casting poison protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(7, Resister->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "disease") && (c->GetLevel() >= 19)) { - Resister->Say("Casting disease protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(8, Resister->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "fire")) { // Fire level 1 - Resister->Say("Casting fire protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(9, Resister->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "cold") && (c->GetLevel() >= 13)) { - Resister->Say("Casting cold protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(10, Resister->GetLevel()); - } - else if(!strcasecmp(sep->arg[2], "magic") && (c->GetLevel() >= 16)) { - Resister->Say("Casting magic protection...", sep->arg[2]); - Resister->CastToBot()->Bot_Command_Resist(11, Resister->GetLevel()); - } - else if (!strcasecmp(sep->arg[2], "magic") && (c->GetLevel() <= 16) - || !strcasecmp(sep->arg[2], "cold") && (c->GetLevel() <= 9) - || !strcasecmp(sep->arg[2], "disease") && (c->GetLevel() <= 19) - || !strcasecmp(sep->arg[2], "poison") && (c->GetLevel() <= 19)) { - Resister->Say("I don't have the needed level yet", sep->arg[2]) ; - } - else - Resister->Say("Do you want [resist poison], [resist disease], [resist fire], [resist cold], or [resist magic]?", c->GetName()); - - break; - - default: - c->Message(15, "You must have a Cleric, Shaman, or Druid in your group."); - break; - } - } - } - - // debug commands - if(!strcasecmp(sep->arg[1], "debug") && !strcasecmp(sep->arg[2], "inventory")) { - Mob *target = c->GetTarget(); - - if(target && target->IsBot()) { - for(int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) { - c->Message(15,"Equiped slot: %i , item: %i \n", i, target->CastToBot()->GetEquipment(i)); - } - if(target->CastToBot()->GetEquipment(MaterialSecondary) > 0) - c->Message(15,"This bot has an item in off-hand."); - } - return; - } - - if(!strcasecmp(sep->arg[1], "debug") && !strcasecmp(sep->arg[2], "botcaracs")) - { - Mob *target = c->GetTarget(); - if(target && target->IsBot()) - { - if(target->CanThisClassDualWield()) - c->Message(15, "This class can dual wield."); - if(target->CanThisClassDoubleAttack()) - c->Message(15, "This class can double attack."); - } - if(target->GetPetID()) - c->Message(15, "I've a pet and its name is %s", target->GetPet()->GetCleanName() ); - return; - } - - if(!strcasecmp(sep->arg[1], "debug") && !strcasecmp(sep->arg[2], "spells")) - { - Mob *target = c->GetTarget(); - if(target && target->IsBot()) - { - for(int i=0; iCastToBot()->AIspells.size(); i++) - { - if(target->CastToBot()->BotGetSpells(i) != 0) - { - SPDat_Spell_Struct botspell = spells[target->CastToBot()->BotGetSpells(i)]; - c->Message(15, "(DEBUG) %s , Slot(%i), Spell (%s) Priority (%i) \n", target->GetCleanName(), i, botspell.name, target->CastToBot()->BotGetSpellPriority(i)); - } - } - } - return; - } - - // #bot group ... - if(!strcasecmp(sep->arg[1], "group") && !strcasecmp(sep->arg[2], "help")) { - c->Message(0, "#bot group help - will show this help."); - c->Message(0, "#bot group summon . Summons the bot group to your location."); - c->Message(0, "#bot group follow "); - c->Message(0, "#bot group guard "); - c->Message(0, "#bot group attack "); - - return; - } - - if(!strcasecmp(sep->arg[1], "group")) { - if(!strcasecmp(sep->arg[2], "follow")) { - if(c->IsGrouped()) - BotGroupOrderFollow(c->GetGroup(), c); - } - else if(!strcasecmp(sep->arg[2], "guard")) { - if(c->IsGrouped()) - BotGroupOrderGuard(c->GetGroup(), c); - } - else if(!strcasecmp(sep->arg[2], "attack")) { - if(c->IsGrouped() && (c->GetTarget() != nullptr) && c->IsAttackAllowed(c->GetTarget())) { - BotGroupOrderAttack(c->GetGroup(), c->GetTarget(), c); - } - else - c->Message(15, "You must target a monster."); - } - else if(!strcasecmp(sep->arg[2], "summon")) { - if(c->IsGrouped()) - BotGroupSummon(c->GetGroup(), c); - } - - return; - } - - // #bot botgroup ... - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "help")) { - c->Message(0, "#bot botgroup help - will show this help."); - c->Message(0, "#bot botgroup create . This will designate a bot to be a bot group leader."); - c->Message(0, "#bot botgroup add "); - c->Message(0, "#bot botgroup remove "); - c->Message(0, "#bot botgroup disband . Disbands the designated bot group leader's bot group."); - c->Message(0, "#bot botgroup summon . Summons the bot group to your location."); - c->Message(0, "#bot botgroup follow "); - c->Message(0, "#bot botgroup guard "); - c->Message(0, "#bot botgroup attack "); - c->Message(0, "#bot botgroup list"); - c->Message(0, "#bot botgroup load "); - c->Message(0, "#bot botgroup save "); - c->Message(0, "#bot botgroup delete "); - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "create")) { - Mob* targetMob = c->GetTarget(); - std::string targetName = std::string(sep->arg[3]); - Bot* botGroupLeader = 0; - - if(!targetName.empty()) { - botGroupLeader = entity_list.GetBotByBotName(targetName); - } - else if(targetMob) { - if(targetMob->IsBot()) - botGroupLeader = targetMob->CastToBot(); - } - - if(botGroupLeader) { - if(Bot::BotGroupCreate(botGroupLeader)) - botGroupLeader->Say("I am prepared to lead."); - else - botGroupLeader->Say("I can not lead."); - } - else - c->Message(13, "You must target a spawned bot first."); - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "add")) { - int argCount = 0; - - argCount = sep->argnum; - - std::string botGroupLeaderName; - std::string botGroupMemberName; - - if(argCount >= 3) - botGroupMemberName = std::string(sep->arg[3]); - - Bot* botGroupMember = entity_list.GetBotByBotName(botGroupMemberName); - - if(!botGroupMember) { - if(botGroupMemberName.empty()) - c->Message(13, "You must target a bot in this zone. Please try again."); - else - c->Message(13, "%s is not a bot in this zone. Please try again.", botGroupMemberName.c_str()); - - return; - } - - Bot* botGroupLeader = 0; - - if(argCount == 4) { - botGroupLeaderName = std::string(sep->arg[4]); - - botGroupLeader = entity_list.GetBotByBotName(botGroupLeaderName); - } - else if(c->GetTarget() && c->GetTarget()->IsBot()) - botGroupLeader = c->GetTarget()->CastToBot(); - - if(!botGroupLeader) { - if(botGroupLeaderName.empty()) - c->Message(13, "You must target a bot in this zone. Please try again."); - else - c->Message(13, "%s is not a bot in this zone. Please try again.", botGroupLeaderName.c_str()); - - return; - } - - if(botGroupLeader->HasGroup()) { - Group* g = botGroupLeader->GetGroup(); - - if(g) { - if(g->IsLeader(botGroupLeader)) { - if(g->GroupCount() < MAX_GROUP_MEMBERS) { - if(!botGroupMemberName.empty() && botGroupMember) { - botGroupMember = entity_list.GetBotByBotName(botGroupMemberName); - } - - if(botGroupMember) { - if(!botGroupMember->HasGroup()) { - // invite - if(Bot::AddBotToGroup(botGroupMember, g)) { - database.SetGroupID(botGroupMember->GetName(), g->GetID(), botGroupMember->GetBotID()); - botGroupMember->Say("I have joined %s\'s group.", botGroupLeader->GetName()); - } - else { - botGroupMember->Say("I can not join %s\'s group.", botGroupLeader->GetName()); - } - } - else { - // "I am already in a group." - Group* tempGroup = botGroupMember->GetGroup(); - if(tempGroup) - botGroupMember->Say("I can not join %s\'s group. I am already a member in %s\'s group.", botGroupLeader->GetName(), tempGroup->GetLeaderName()); - } - } - else { - // must target a bot message - c->Message(13, "You must target a spawned bot first."); - } - } - else { - // "My group is full." - botGroupLeader->Say("I have no more openings in my group, %s.", c->GetName()); - } - } - else { - // "I am not a group leader." - Group* tempGroup = botGroupLeader->GetGroup(); - if(tempGroup) - botGroupLeader->Say("I can not lead anyone because I am a member in %s\'s group.", tempGroup->GetLeaderName()); - } - } - } - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "remove")) { - Mob* targetMob = c->GetTarget(); - std::string targetName = std::string(sep->arg[3]); - Bot* botGroupMember = 0; - - if(!targetName.empty()) { - botGroupMember = entity_list.GetBotByBotName(targetName); - } - else if(targetMob) { - if(targetMob->IsBot()) - botGroupMember = targetMob->CastToBot(); - } - - if(botGroupMember) { - if(botGroupMember->HasGroup()) { - Group* g = botGroupMember->GetGroup(); - - if(Bot::RemoveBotFromGroup(botGroupMember, g)) - botGroupMember->Say("I am no longer in a group."); - else - botGroupMember->Say("I can not leave %s\'s group.", g->GetLeaderName()); - } - else - botGroupMember->Say("I am not in a group."); - } - else - c->Message(13, "You must target a spawned bot first."); - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "disband")) { - Mob* targetMob = c->GetTarget(); - std::string targetName = std::string(sep->arg[3]); - Bot* botGroupLeader = 0; - - if(!targetName.empty()) { - botGroupLeader = entity_list.GetBotByBotName(targetName); - } - else if(targetMob) { - if(targetMob->IsBot()) - botGroupLeader = targetMob->CastToBot(); - } - - if(botGroupLeader) { - if(botGroupLeader->HasGroup()) { - Group* g = botGroupLeader->GetGroup(); - - if(g->IsLeader(botGroupLeader)) { - if(Bot::RemoveBotFromGroup(botGroupLeader, g)) - botGroupLeader->Say("I have disbanded my group, %s.", c->GetName()); - else - botGroupLeader->Say("I was not able to disband my group, %s.", c->GetName()); - } - else { - botGroupLeader->Say("I can not disband my group, %s, because I am not the leader. %s is the leader of my group.", c->GetName(), g->GetLeaderName()); - } - } - else - botGroupLeader->Say("I am not a group leader, %s.", c->GetName()); - } - else - c->Message(13, "You must target a spawned bot group leader first."); - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "summon") ) { - Mob* targetMob = c->GetTarget(); - std::string targetName = std::string(sep->arg[3]); - Bot* botGroupLeader = 0; - - if(!targetName.empty()) { - botGroupLeader = entity_list.GetBotByBotName(targetName); - } - else if(targetMob) { - if(targetMob->IsBot()) - botGroupLeader = targetMob->CastToBot(); - } - - if(botGroupLeader) { - if(botGroupLeader->HasGroup()) { - Group* g = botGroupLeader->GetGroup(); - - if(g->IsLeader(botGroupLeader)) - BotGroupSummon(g, c); - } - } - else if(c->HasGroup()) - BotGroupSummon(c->GetGroup(), c); - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "follow") ) { - Mob* targetMob = c->GetTarget(); - std::string targetName = std::string(sep->arg[3]); - Bot* botGroupLeader = 0; - - if(!targetName.empty()) { - botGroupLeader = entity_list.GetBotByBotName(targetName); - } - else if(targetMob) { - if(targetMob->IsBot()) - botGroupLeader = targetMob->CastToBot(); - } - - if(botGroupLeader) { - if(botGroupLeader->HasGroup()) { - Group* g = botGroupLeader->GetGroup(); - - if(g->IsLeader(botGroupLeader)) - BotGroupOrderFollow(g, c); - } - } - else if(c->HasGroup()) - BotGroupOrderFollow(c->GetGroup(), c); - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "guard") ) { - Mob* targetMob = c->GetTarget(); - std::string targetName = std::string(sep->arg[3]); - Bot* botGroupLeader = 0; - - if(!targetName.empty()) { - botGroupLeader = entity_list.GetBotByBotName(targetName); - } - else if(targetMob) { - if(targetMob->IsBot()) - botGroupLeader = targetMob->CastToBot(); - } - - if(botGroupLeader) { - if(botGroupLeader->HasGroup()) { - Group* g = botGroupLeader->GetGroup(); - - if(g->IsLeader(botGroupLeader)) - BotGroupOrderGuard(g, c); - } - } - else if(c->HasGroup()) - BotGroupOrderGuard(c->GetGroup(), c); - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "attack") ) { - Mob* targetMob = c->GetTarget(); - Bot* botGroupLeader = 0; - std::string botGroupLeaderName = std::string(sep->arg[3]); - std::string targetName = std::string(sep->arg[4]); - - if(!botGroupLeaderName.empty()) { - botGroupLeader = entity_list.GetBotByBotName(botGroupLeaderName); - - if(botGroupLeader) { - if(!targetName.empty()) { - targetMob = entity_list.GetMob(targetName.c_str()); - } - - if(targetMob) { - if(c->IsAttackAllowed(targetMob)) { - if(botGroupLeader->HasGroup()) { - Group* g = botGroupLeader->GetGroup(); - - if(g) { - if(g->IsLeader(botGroupLeader)) - BotGroupOrderAttack(g, targetMob, c); - } - } - else if(c->HasGroup()) - BotGroupOrderAttack(c->GetGroup(), targetMob, c); - } - else - c->Message(13, "You must target a monster."); - } - else - c->Message(13, "You must target a monster."); - } - else - c->Message(13, "You must target a spawned bot group leader first."); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "list")) { - std::list botGroupList = GetBotGroupListByBotOwnerCharacterId(c->CharacterID(), &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - if(!botGroupList.empty()) { - for(std::list::iterator botGroupListItr = botGroupList.begin(); botGroupListItr != botGroupList.end(); ++botGroupListItr) { - c->Message(0, "Bot Group Name: %s -- Bot Group Leader: %s", botGroupListItr->BotGroupName.c_str(), botGroupListItr->BotGroupLeaderName.c_str()); - } - } - else { - c->Message(0, "You have no bot groups created. Use the #bot botgroup save command to save bot groups."); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "load")) { - - // If client is grouped, check for aggro on each group member. - Group *g = c->GetGroup(); - if(g) { - for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { - // Skip invalid group members. - if(!g->members[i]) { continue; } - - // Fail if current group member is client and has aggro - // OR has a popuplated hate list (assume bot). - if((g->members[i]->IsClient() && g->members[i]->CastToClient()->GetAggroCount()) - || g->members[i]->IsEngaged()) { - c->Message(0, "You can't spawn bots while your group is engaged."); - return; - } - } - } - // Fail if ungrouped client has aggro. - else { - if(c->GetAggroCount() > 0) { - c->Message(0, "You can't spawn bots while you are engaged."); - return; - } - } - - // Parse botgroup name. - std::string botGroupName = std::string(sep->arg[3]); - if(botGroupName.empty()) { - c->Message(13, "Invalid botgroup name supplied."); - return; - } - - // Get botgroup id. - uint32 botGroupID = CanLoadBotGroup(c->CharacterID(), botGroupName, &TempErrorMessage); - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - if(botGroupID <= 0) { - c->Message(13, "Invalid botgroup id found."); - return; - } - - // Get list of bots in specified group. - std::list botGroup = LoadBotGroup(botGroupName, &TempErrorMessage); - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - // Count of client's currently spawned bots. - int spawnedBots = SpawnedBotCount(c->CharacterID(), &TempErrorMessage); - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - // BotQuest rule value in database is True. - if(RuleB(Bots, BotQuest)) { - // Max number of allowed spawned bots for client. - const int allowedBotsBQ = AllowedBotSpawns(c->CharacterID(), &TempErrorMessage); - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - // Fail if no bots allowed for client. - if(allowedBotsBQ == 0) { - c->Message(0, "You can't spawn any bots."); - return; - } - - // Fail if maximum number of spawned bots allowed for client met or exceeded - // OR will be when bot group is spawned. - if(spawnedBots >= allowedBotsBQ - || spawnedBots + (int)botGroup.size() > allowedBotsBQ) { - c->Message(0, "You can't spawn more than %i bot(s). [Rule:BQ]", allowedBotsBQ); - return; - } - } - - // Fail if maximum number of spawned bots allowed for client met or exceeded - // OR will be when bot group is spawned. - const int allowedBotsSBC = RuleI(Bots, SpawnBotCount); - if(spawnedBots >= allowedBotsSBC - || spawnedBots + (int)botGroup.size() > allowedBotsSBC) { - c->Message(0, "You can't spawn more than %i bots. [Rule:SBC]", allowedBotsSBC); - return; - } - - // Passed all checks. Spawn requested bot group. - - // Get botgroup's leader's id. - uint32 botGroupLeaderBotID = GetBotGroupLeaderIdByBotGroupName(botGroupName); - - // Load botgroup's leader. - Bot *botGroupLeader = LoadBot(botGroupLeaderBotID, &TempErrorMessage); - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - safe_delete(botGroupLeader); - return; - } - if(!botGroupLeader) { - c->Message(13, "Failed to load botgroup leader."); - safe_delete(botGroupLeader); - return; - } - - // Spawn botgroup's leader. - botGroupLeader->Spawn(c, &TempErrorMessage); - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - safe_delete(botGroupLeader); - return; - } - - // Create botgroup. - if(!BotGroupCreate(botGroupLeader)) { - c->Message(13, "Unable to create botgroup."); - return; - } - Group *newBotGroup = botGroupLeader->GetGroup(); - if(!newBotGroup) { - c->Message(13, "Unable to find valid botgroup"); - return; - } - - for(auto botGroupItr = botGroup.begin(); botGroupItr != botGroup.end(); ++botGroupItr) { - // Don't try to re-spawn the botgroup's leader. - if(botGroupItr->BotID == botGroupLeader->GetBotID()) { continue; } - - // Load current botgroup member - Bot *botGroupMember = LoadBot(botGroupItr->BotID, &TempErrorMessage); - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - safe_delete(botGroupMember); - return; - } - // Skip invalid botgroup members. - if(!botGroupMember) { - safe_delete(botGroupMember); - continue; - } - - // Spawn current botgroup member. - botGroupMember->Spawn(c, &TempErrorMessage); - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - safe_delete(botGroupMember); - return; - } - - // Add current botgroup member to botgroup. - AddBotToGroup(botGroupMember, newBotGroup); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "delete")) { - std::string botGroupName = std::string(sep->arg[3]); - - if(!botGroupName.empty()) { - uint32 botGroupId = CanLoadBotGroup(c->CharacterID(), botGroupName, &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - - if(botGroupId > 0) { - DeleteBotGroup(botGroupName, &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return; - } - } - } - - return; - } - - if(!strcasecmp(sep->arg[1], "botgroup") && !strcasecmp(sep->arg[2], "save")) { - std::string botGroupName = std::string(sep->arg[3]); - - if(!botGroupName.empty()) { - if(!DoesBotGroupNameExist(botGroupName)) { - Bot* groupLeader = 0; - - if(c->GetTarget() && c->GetTarget()->IsBot()) - groupLeader = c->GetTarget()->CastToBot(); - else - groupLeader = entity_list.GetBotByBotName(std::string(sep->arg[4])); - - if(groupLeader) { - if(groupLeader->HasGroup() && groupLeader->GetGroup()->IsLeader(groupLeader)) { - SaveBotGroup(groupLeader->GetGroup(), botGroupName, &TempErrorMessage); - - if(!TempErrorMessage.empty()) { - c->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - } - else - c->Message(0, "%s's bot group has been saved as %s.", groupLeader->GetName(), botGroupName.c_str()); - } - else - c->Message(0, "You must target a bot group leader only."); - } - else - c->Message(0, "You must target a bot that is in the same zone as you."); - } - else - c->Message(0, "The bot group name already exists. Please choose another name to save your bot group as."); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "haircolor") || !strcasecmp(sep->arg[1], "hair") || !strcasecmp(sep->arg[1], "beard") || !strcasecmp(sep->arg[1], "beardcolor") || !strcasecmp(sep->arg[1], "face") - || !strcasecmp(sep->arg[1], "eyes") || !strcasecmp(sep->arg[1], "heritage") || !strcasecmp(sep->arg[1], "tattoo") || !strcasecmp(sep->arg[1], "details")) { - if(c->GetTarget() && c->GetTarget()->IsBot()) { - if (sep->IsNumber(2)) { - if (c->GetTarget()->CastToBot()->GetBotOwnerCharacterID() == c->CharacterID()) { - Bot *target = c->GetTarget()->CastToBot(); - uint16 Race = target->GetRace(); - uint8 Gender = target->GetGender(); - uint8 Texture = 0xFF; - uint8 HelmTexture = 0xFF; - uint8 HairStyle = target->GetHairStyle(); - uint8 HairColor = target->GetHairColor(); - uint8 BeardColor = target->GetBeardColor(); - uint8 EyeColor1 = target->GetEyeColor1(); - uint8 EyeColor2 = target->GetEyeColor2(); - - uint8 LuclinFace = target->GetLuclinFace(); - uint8 Beard = target->GetBeard(); - uint32 DrakkinHeritage = target->GetDrakkinHeritage(); - uint32 DrakkinTattoo = target->GetDrakkinTattoo(); - uint32 DrakkinDetails = target->GetDrakkinDetails(); - float Size = target->GetSize(); - - if (!strcasecmp(sep->arg[1], "hair")) - HairStyle = atoi(sep->arg[2]); - if (!strcasecmp(sep->arg[1], "haircolor")) - HairColor = atoi(sep->arg[2]); - if (!strcasecmp(sep->arg[1], "beard") || !strcasecmp(sep->arg[1], "beardcolor")) { - if (!Gender || Race == 8) { - if (!strcasecmp(sep->arg[1], "beard")) - Beard = atoi(sep->arg[2]); - if (!strcasecmp(sep->arg[1], "beardcolor")) - BeardColor = atoi(sep->arg[2]); - } else { - c->Message(0, "Must be a male bot, or dwarf."); - return; - } - } - if (!strcasecmp(sep->arg[1], "face")) - LuclinFace = atoi(sep->arg[2]); - - if (!strcasecmp(sep->arg[1], "eyes")) { - EyeColor1 = EyeColor2 = atoi(sep->arg[2]); - c->Message(0, "Eye Values = 0 - 11"); - } - if(!strcasecmp(sep->arg[1], "heritage") || !strcasecmp(sep->arg[1], "tattoo") || !strcasecmp(sep->arg[1], "details")) { - if(Race == 522) { - if(!strcasecmp(sep->arg[1], "heritage")) { - DrakkinHeritage = atoi(sep->arg[2]); - c->Message(0, "Heritage Values = 0 - 6"); - } - if(!strcasecmp(sep->arg[1], "tattoo")) { - DrakkinTattoo = atoi(sep->arg[2]); - c->Message(0, "Tattoo Values = 0 - 7"); - } - if(!strcasecmp(sep->arg[1], "details")) { - DrakkinDetails = atoi(sep->arg[2]); - c->Message(0, "Details Values = 0 - 7"); - } - } - else { - c->Message(0, "Drakkin only."); - return; - } - } - - target->SendIllusionPacket(Race, Gender, Texture, HelmTexture, HairColor, BeardColor, - EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF, - DrakkinHeritage, DrakkinTattoo, DrakkinDetails, Size); - - if(target->CastToBot()->Save()) - c->Message(0, "%s saved.", target->GetCleanName()); - else - c->Message(13, "%s save failed!", target->GetCleanName()); - - c->Message(0,"Feature changed."); - } else { - c->Message(0, "You must own the bot to make changes."); - } - } else { - c->Message(0, "Requires a value."); - } - } else { - c->Message(0,"A bot needs to be targetted."); - } - return; - } - - if(!strcasecmp(sep->arg[1], "taunt")) { - bool taunt = false; - bool toggle = false; - - if(sep->arg[2]){ - if(!strcasecmp(sep->arg[2], "on")) - taunt = true; - else if (!strcasecmp(sep->arg[2], "off")) - taunt = false; - else { - c->Message(0, "Usage #bot taunt [on|off]"); - return; - } - - Bot *targetedBot = nullptr; - - if(c->GetTarget() != nullptr) { - if (c->GetTarget()->IsBot() && (c->GetTarget()->CastToBot()->GetBotOwner() == c)) - targetedBot = c->GetTarget()->CastToBot(); - else - c->Message(13, "You must target a bot that you own."); - - if(targetedBot) { - if(targetedBot->GetSkill(SkillTaunt) > 0) { - if(toggle) - taunt = !targetedBot->taunting; - - if(taunt) { - if(!targetedBot->taunting) - targetedBot->Say("I am now taunting."); - } - else { - if(targetedBot->taunting) - targetedBot->Say("I am no longer taunting."); - } - - targetedBot->SetTaunting(taunt); - } - else - c->Message(13, "You must select a bot with the taunt skill."); - } - else { - c->Message(13, "You must target a spawned bot."); - } - } - } - else { - c->Message(0, "Usage #bot taunt [on|off]"); - } - - return; - } - - if(!strcasecmp(sep->arg[1], "stance")) { - if(sep->argnum == 3){ - Bot* tempBot = nullptr; - std::string botName = std::string(sep->arg[2]); - - if(!botName.empty()) - tempBot = entity_list.GetBotByBotName(botName); - else - c->Message(13, "You must name a valid bot."); - - if(tempBot) { - std::string stanceName; - BotStanceType botStance; - - if (tempBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - if(!strcasecmp(sep->arg[3], "list")) { - botStance = tempBot->GetBotStance(); - } - else { - int stance = atoi(sep->arg[3]); - - if(stance >= MaxStances || stance < 0){ - c->Message(0, "Usage #bot stance [name] [stance (id)] (Passive = 0, Balanced = 1, Efficient = 2, Reactive = 3, Aggressive = 4, Burn = 5, BurnAE = 6)"); - return; - } - else { - botStance = (BotStanceType)stance; - if(botStance != tempBot->GetBotStance()) { - tempBot->SetBotStance(botStance); - tempBot->CalcChanceToCast(); - tempBot->Save(); - } - } - } - - switch(botStance) { - case BotStancePassive: { - stanceName = "Passive"; - break; - } - case BotStanceBalanced: { - stanceName = "Balanced"; - break; - } - case BotStanceEfficient: { - stanceName = "Efficient"; - break; - } - case BotStanceReactive: { - stanceName = "Reactive"; - break; - } - case BotStanceAggressive: { - stanceName = "Aggressive"; - break; - } - case BotStanceBurn: { - stanceName = "Burn"; - break; - } - case BotStanceBurnAE: { - stanceName = "BurnAE"; - break; - } - default: { - stanceName = "None"; - break; - } - } - c->Message(0, "Stance for %s: %s.", tempBot->GetCleanName(), stanceName.c_str()); - } - else { - c->Message(13, "You must name a valid bot."); - } - } - else { - c->Message(0, "Usage #bot stance [name] [stance (id)] (Passive = 0, Balanced = 1, Efficient = 2, Reactive = 3, Aggressive = 4, Burn = 5, BurnAE = 6)"); - } - return; - } - - if(!strcasecmp(sep->arg[1], "groupmessages")) { - bool groupMessages = false; - - if(sep->arg[2] && sep->arg[3]){ - if(!strcasecmp(sep->arg[2], "on")) - groupMessages = true; - else if (!strcasecmp(sep->arg[2], "off")) - groupMessages = false; - else { - c->Message(0, "Usage #bot groupmessages [on|off] [bot name|all]"); - return; - } - - Bot* tempBot; - - if(!strcasecmp(sep->arg[3], "all")) { - std::list spawnedBots = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID()); - - if(!spawnedBots.empty()) { - for(std::list::iterator botsListItr = spawnedBots.begin(); botsListItr != spawnedBots.end(); ++botsListItr) { - Bot* tempBot = *botsListItr; - if(tempBot) { - tempBot->SetGroupMessagesOn(groupMessages); - } - } - } - else { - c->Message(0, "You have no spawned bots in this zone."); - } - - c->Message(0, "Group messages now %s for all bots.", groupMessages?"on":"off"); - } - else { - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - tempBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid bot."); - return; - } - - if(tempBot) { - if (tempBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - tempBot->SetGroupMessagesOn(groupMessages); - c->Message(0, "Group messages now %s.", groupMessages?"on":"off"); - } - else { - c->Message(13, "You must name a valid bot."); - } - } - } - else { - c->Message(0, "Usage #bot groupmessages [on|off] [bot name|all]"); - } - return; - } - - if(!strcasecmp(sep->arg[1], "defensive")) { - Bot* tempBot; - std::string botName = std::string(sep->arg[2]); - - if(!botName.empty()) - tempBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid bot."); - return; - } - - if(tempBot) { - uint8 botlevel = tempBot->GetLevel(); - uint32 defensiveSpellID = 0; - - if (tempBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - switch (tempBot->GetClass()) { - case WARRIOR: - if(botlevel >= 72) - defensiveSpellID = 10965; //Final Stand discipline - else if(botlevel >= 65) - defensiveSpellID = 4688; //Stonewall discipline - else if(botlevel >= 55) - defensiveSpellID = 4499; //Defensive discipline - else if(botlevel >= 52) - defensiveSpellID = 4503; //Evasive discipline - else - c->Message(0, "Error: warrior must be level 52+"); - break; - case PALADIN: - if(botlevel >= 73) - defensiveSpellID = 11854; //Armor of Righteousness - else if(botlevel >= 69) - defensiveSpellID = 6663; //Guard of Righteousness - else if(botlevel >= 61) - defensiveSpellID = 6731; //Guard of Humility - else if(botlevel >= 56) - defensiveSpellID = 7004; //Guard of Piety - else - c->Message(0, "Error: paladin must be level 56+"); - break; - case SHADOWKNIGHT: - if(botlevel >= 73) - defensiveSpellID = 11866; //Soul Carapace - else if(botlevel >= 69) - defensiveSpellID = 6673; //Soul shield - else if(botlevel >= 61) - defensiveSpellID = 6741; //Soul guard - else if(botlevel >= 56) - defensiveSpellID = 7005; //Ichor guard - else - c->Message(0, "Error: shadowknight must be level 56+"); - break; - default: - c->Message(0, "Error: you must select a warrior or knight"); - break; - } - - if(defensiveSpellID > 0) { - tempBot->UseDiscipline(defensiveSpellID, tempBot->GetID()); - } - } - else { - c->Message(13, "You must name a valid bot."); - } - return; - } - - // #bot healrotation ... - if(!strcasecmp(sep->arg[1], "healrotation")) { - if(!strcasecmp(sep->arg[2], "help")) { - c->Message(0, "#bot healrotation help - will show this help."); - c->Message(0, "#bot healrotation create [target]. This will create a heal rotation with the designated leader."); - c->Message(0, "#bot healrotation addmember "); - c->Message(0, "#bot healrotation removemember "); - c->Message(0, "#bot healrotation addtarget [bot healrotation target name to add] "); - c->Message(0, "#bot healrotation removetarget "); - c->Message(0, "#bot healrotation cleartargets "); - c->Message(0, "#bot healrotation fastheals "); - c->Message(0, "#bot healrotation start "); - c->Message(0, "#bot healrotation stop "); - c->Message(0, "#bot healrotation list "); - - return; - } - - if(!strcasecmp(sep->arg[2], "create")) { - if(sep->argnum == 5 || sep->argnum == 6) { //allows for target or not - Bot* leaderBot; - - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid heal rotation leader."); - return; - } - - if(leaderBot) { - Mob* target = nullptr; - uint32 timer; - bool fastHeals = false; - - if (!sep->IsNumber(4)) { - c->Message(0, "Usage #bot healrotation create [target]."); - return; - } - - timer = (uint32)(atof(sep->arg[4]) * 1000); - - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - if (!(leaderBot->IsBotCaster() && leaderBot->CanHeal())) { - c->Message(13, "Heal rotation members must be able to heal."); - return; - } - - //get percentage heals - if(!strcasecmp(sep->arg[5], "fasthealson")) - fastHeals = true; - else if(strcasecmp(sep->arg[5], "fasthealsoff")) { - c->Message(0, "Usage #bot healrotation create [target]."); - return; - } - - if(!leaderBot->GetInHealRotation()) { - //check for target - if(sep->argnum == 6) { - std::string targetName = std::string(sep->arg[6]); - - if(!targetName.empty()) - target = entity_list.GetMob(targetName.c_str()); - else { - c->Message(13, "You must name a valid target."); - return; - } - - if(!target) { - c->Message(13, "You must name a valid target."); - return; - } - } - - //create rotation - leaderBot->CreateHealRotation(target, timer); - leaderBot->SetHealRotationUseFastHeals(fastHeals); - c->Message(0, "Bot heal rotation created successfully."); - } - else { - c->Message(13, "That bot is already in a heal rotation."); - return; - } - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - else { - c->Message(0, "Usage #bot healrotation create [target]."); - return; - } - } - - if(!strcasecmp(sep->arg[2], "addmember")) { - if(sep->argnum == 4) { - Bot* leaderBot; - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid bot."); - return; - } - - if(leaderBot) { - Bot* healer; - std::string healerName = std::string(sep->arg[4]); - - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - if(!healerName.empty()) - healer = entity_list.GetBotByBotName(healerName); - else { - c->Message(13, "You must name a valid bot."); - return; - } - - if(healer) { - if (healer->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - if (!(healer->IsBotCaster() && healer->CanHeal())) { - c->Message(13, "Heal rotation members must be able to heal."); - return; - } - - //add to rotation - if(leaderBot->AddHealRotationMember(healer)) { - c->Message(0, "Bot heal rotation member added successfully."); - } - else { - c->Message(13, "Unable to add bot to rotation. "); - } - } - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - else { - c->Message(0, "#bot healrotation addmember "); - return; - } - } - - if(!strcasecmp(sep->arg[2], "removemember")) { - if(sep->argnum == 4) { - Bot* leaderBot; - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid bot."); - return; - } - - if(leaderBot) { - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - Bot* healer; - std::string healerName = std::string(sep->arg[4]); - - if(!healerName.empty()) - healer = entity_list.GetBotByBotName(healerName); - else { - c->Message(13, "You must name a valid bot."); - return; - } - - if(healer) { - if (healer->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - //remove from rotation - if(leaderBot->RemoveHealRotationMember(healer)) { - c->Message(0, "Bot heal rotation member removed successfully."); - } - else { - c->Message(13, "Unable to remove bot from rotation. "); - } - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - else { - c->Message(0, "#bot healrotation removemember "); - return; - } - } - - if(!strcasecmp(sep->arg[2], "addtarget")) { - if(sep->argnum == 3 || sep->argnum == 4) { - Bot* leaderBot; - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid heal rotation leader."); - return; - } - - if(leaderBot) { - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - Mob* target = nullptr; - std::string targetName = std::string(sep->arg[4]); - - if(!targetName.empty()) - target = entity_list.GetMob(targetName.c_str()); - else { - if(c->GetTarget() != nullptr) { - target = c->GetTarget(); - } - } - - if(target) { - //add target - if(leaderBot->AddHealRotationTarget(target)) { - c->Message(0, "Bot heal rotation target added successfully."); - } - else { - c->Message(13, "Unable to add rotation target. "); - } - } - else { - c->Message(13, "Invalid target."); - return; - } - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - else { - c->Message(0, "#bot healrotation addtarget [bot healrotation target name to add] "); - return; - } - } - - if(!strcasecmp(sep->arg[2], "removetarget")) { - if(sep->argnum == 4) { - Bot* leaderBot; - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid heal rotation leader."); - return; - } - - if(leaderBot) { - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - Mob* target; - std::string targetName = std::string(sep->arg[4]); - - if(!targetName.empty()) - target = entity_list.GetMob(targetName.c_str()); - else { - c->Message(13, "You must name a valid target."); - return; - } - - if(target) { - //add to rotation - if(leaderBot->RemoveHealRotationTarget(target)) { - c->Message(0, "Bot heal rotation target removed successfully."); - } - else { - c->Message(13, "Unable to remove rotation target. "); - } - } - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - else { - c->Message(0, "#bot healrotation removetarget "); - return; - } - } - - if(!strcasecmp(sep->arg[2], "start")) { - if(sep->argnum == 3) { - if(!strcasecmp(sep->arg[3], "all")) { - std::list BotList = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID()); - - for(std::list::iterator botListItr = BotList.begin(); botListItr != BotList.end(); ++botListItr) { - Bot* leaderBot = *botListItr; - if(leaderBot->GetInHealRotation() && leaderBot->GetHealRotationLeader() == leaderBot) { - //start all heal rotations - std::list rotationMemberList; - int index = 0; - - rotationMemberList = GetBotsInHealRotation(leaderBot); - - for(std::list::iterator rotationMemberItr = rotationMemberList.begin(); rotationMemberItr != rotationMemberList.end(); ++rotationMemberItr) { - Bot* tempBot = *rotationMemberItr; - - if(tempBot) { - tempBot->SetHealRotationActive(true); - tempBot->SetHealRotationNextHealTime(Timer::GetCurrentTime() + index * leaderBot->GetHealRotationTimer() * 1000); - tempBot->SetHasHealedThisCycle(false); - } - - index++; - } - - c->Message(0, "Bot heal rotation started successfully."); - } - } - } - else { - Bot* leaderBot; - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid heal rotation leader."); - return; - } - - if(leaderBot) { - std::list botList; - int index = 0; - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - botList = GetBotsInHealRotation(leaderBot); - - for(std::list::iterator botListItr = botList.begin(); botListItr != botList.end(); ++botListItr) { - Bot* tempBot = *botListItr; - - if(tempBot) { - tempBot->SetHealRotationActive(true); - tempBot->SetHealRotationNextHealTime(Timer::GetCurrentTime() + index * leaderBot->GetHealRotationTimer() * 1000); - tempBot->SetHasHealedThisCycle(false); - } - - index++; - } - - c->Message(0, "Bot heal rotation started successfully."); - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - } - else { - c->Message(0, "#bot healrotation start "); - return; - } - } - - if(!strcasecmp(sep->arg[2], "stop")) { - if(sep->argnum == 3) { - if(!strcasecmp(sep->arg[3], "all")) { - std::list BotList = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID()); - - for(std::list::iterator botListItr = BotList.begin(); botListItr != BotList.end(); ++botListItr) { - Bot* leaderBot = *botListItr; - if(leaderBot->GetInHealRotation() && leaderBot->GetHealRotationLeader() == leaderBot) { - //start all heal rotations - std::list rotationMemberList; - - rotationMemberList = GetBotsInHealRotation(leaderBot); - - for(std::list::iterator rotationMemberItr = rotationMemberList.begin(); rotationMemberItr != rotationMemberList.end(); ++rotationMemberItr) { - Bot* tempBot = *rotationMemberItr; - - if(tempBot) { - tempBot->SetHealRotationActive(false); - tempBot->SetHasHealedThisCycle(false); - } - } - - c->Message(0, "Bot heal rotation started successfully."); - } - } - } - else { - Bot* leaderBot; - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid heal rotation leader."); - return; - } - - if(leaderBot) { - std::list botList; - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - botList = GetBotsInHealRotation(leaderBot); - - for(std::list::iterator botListItr = botList.begin(); botListItr != botList.end(); ++botListItr) { - Bot* tempBot = *botListItr; - - if(tempBot && tempBot->GetBotOwnerCharacterID() == c->CharacterID()) { - tempBot->SetHealRotationActive(false); - tempBot->SetHasHealedThisCycle(false); - } - } - - c->Message(0, "Bot heal rotation stopped successfully."); - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - } - else { - c->Message(0, "#bot healrotation stop "); - return; - } - } - - if(!strcasecmp(sep->arg[2], "list")) { - if(sep->argnum == 3) { - bool showAll = false; - Bot* leaderBot; - std::string botName = std::string(sep->arg[3]); - - if(!strcasecmp(sep->arg[3], "all")) { - std::list BotList = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID()); - - for(std::list::iterator botListItr = BotList.begin(); botListItr != BotList.end(); ++botListItr) { - Bot* tempBot = *botListItr; - if(tempBot->GetInHealRotation() && tempBot->GetHealRotationLeader() == tempBot) { - //list leaders and number of bots per rotation - c->Message(0, "Bot Heal Rotation- Leader: %s, Number of Members: %i, Timer: %1.1f", tempBot->GetCleanName(), tempBot->GetNumHealRotationMembers(), (float)(tempBot->GetHealRotationTimer()/1000)); - } - } - } - else { - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid heal rotation leader."); - return; - } - - if(leaderBot) { - std::list botList; - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - botList = GetBotsInHealRotation(leaderBot); - - //list leader and number of members - c->Message(0, "Bot Heal Rotation- Leader: %s", leaderBot->GetCleanName()); - c->Message(0, "Bot Heal Rotation- Timer: %1.1f", ((float)leaderBot->GetHealRotationTimer()/1000.0f)); - - for(std::list::iterator botListItr = botList.begin(); botListItr != botList.end(); ++botListItr) { - Bot* tempBot = *botListItr; - - if(tempBot && tempBot->GetBotOwnerCharacterID() == c->CharacterID()) { - //list rotation members - c->Message(0, "Bot Heal Rotation- Member: %s", tempBot->GetCleanName()); - } - } - - for(int i=0; iGetHealRotationTarget(i)) { - Mob* tempTarget = leaderBot->GetHealRotationTarget(i); - - if(tempTarget) { - std::string targetInfo = ""; - - targetInfo += tempTarget->GetHPRatio() < 0 ? "(dead) " : ""; - targetInfo += tempTarget->GetZoneID() != leaderBot->GetZoneID() ? "(not in zone) " : ""; - - //list targets - c->Message(0, "Bot Heal Rotation- Target: %s %s", tempTarget->GetCleanName(), targetInfo.c_str()); - } - } - } - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - } - else { - c->Message(0, "#bot healrotation list "); - return; - } - } - - if(!strcasecmp(sep->arg[2], "cleartargets")) { - if(sep->argnum == 3) { - Bot* leaderBot; - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid heal rotation leader."); - return; - } - - if(leaderBot) { - std::list botList; - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - botList = GetBotsInHealRotation(leaderBot); - - for(std::list::iterator botListItr = botList.begin(); botListItr != botList.end(); ++botListItr) { - Bot* tempBot = *botListItr; - - if(tempBot && tempBot->GetBotOwnerCharacterID() == c->CharacterID()) - tempBot->ClearHealRotationTargets(); - } - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - else { - c->Message(0, "#bot healrotation cleartargets "); - return; - } - } - - if(!strcasecmp(sep->arg[2], "fastheals")) { - if(sep->argnum == 3) { - Bot* leaderBot; - std::string botName = std::string(sep->arg[3]); - - if(!botName.empty()) - leaderBot = entity_list.GetBotByBotName(botName); - else { - c->Message(13, "You must name a valid heal rotation leader."); - return; - } - - if(leaderBot) { - bool fastHeals = false; - std::list botList; - if (leaderBot->GetBotOwner() != c) { - c->Message(13, "You must target a bot that you own."); - return; - } - - //get percentage heals & target - if(!strcasecmp(sep->arg[4], "on")) - fastHeals = true; - else if(strcasecmp(sep->arg[4], "off")) { - c->Message(0, "Usage #bot healrotation fastheals ."); - return; - } - - botList = GetBotsInHealRotation(leaderBot); - - for(std::list::iterator botListItr = botList.begin(); botListItr != botList.end(); ++botListItr) { - Bot* tempBot = *botListItr; - - if(tempBot && tempBot->GetBotOwnerCharacterID() == c->CharacterID()) - tempBot->SetHealRotationUseFastHeals(fastHeals); - } - } - else { - c->Message(13, "You must name a valid bot."); - return; - } - } - else { - c->Message(0, "#bot healrotation fastheals "); - return; - } - } - - if(!strcasecmp(sep->arg[2], "load")) { - } - - if(!strcasecmp(sep->arg[2], "save")) { - } - - if(!strcasecmp(sep->arg[2], "delete")) { - } - } - - // #bot setinspectmessage - if(!strcasecmp(sep->arg[1], "setinspectmessage")) { - if(!strcasecmp(sep->arg[2], "help")) { - c->Message(0, "[Titanium clients:]"); - c->Message(0, "- Self-inspect and type your bot's inspect message"); - c->Message(0, "- Close the self-inspect window"); - c->Message(0, "- Self-inspect again to update the server"); - c->Message(0, "- Target a bot that you own and wish to update"); - c->Message(0, "- type #bot setinspectmessage to set the bot's message"); - c->Message(0, "[Secrets of Faydwer and higher clients:]"); - c->Message(0, "- Self-inspect and type your bot's inspect message"); - c->Message(0, "- Close the self-inspect window to update the server"); - c->Message(0, "- Target a bot that you own and wish to update"); - c->Message(0, "- type #bot setinspectmessage to set the bot's message"); - } - else { - Mob *target = c->GetTarget(); - - if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) { - const InspectMessage_Struct& playermessage = c->GetInspectMessage(); - InspectMessage_Struct& botmessage = target->CastToBot()->GetInspectMessage(); - - memcpy(&botmessage, &playermessage, sizeof(InspectMessage_Struct)); - database.SetBotInspectMessage(target->CastToBot()->GetBotID(), &botmessage); - - c->Message(0, "Bot %s's inspect message now reflects your inspect message.", target->GetName()); - } - else { - c->Message(0, "Your target must be a bot that you own."); - } - } - } - - if(!strcasecmp(sep->arg[1], "bardoutofcombat")) { - bool useOutOfCombatSongs = false; - - if(sep->arg[2] && sep->arg[3]){ - if(!strcasecmp(sep->arg[2], "on")) - useOutOfCombatSongs = true; - else if (!strcasecmp(sep->arg[2], "off")) - useOutOfCombatSongs = false; - else { - c->Message(0, "Usage #bot bardoutofcombat [on|off]"); - return; - } - - Mob *target = c->GetTarget(); - - if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) { - Bot* bardBot = target->CastToBot(); - - if(bardBot) { - bardBot->SetBardUseOutOfCombatSongs(useOutOfCombatSongs); - c->Message(0, "Bard use of out of combat songs updated."); - } - } - else { - c->Message(0, "Your target must be a bot that you own."); - } - } - else { - c->Message(0, "Usage #bot bardoutofcombat [on|off]"); - } - return; - } -} - -// franck: EQoffline -// This function has been reworked for the caster bots, when engaged. -// Healers bots must heal thoses who loose HP. bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint16 iSpellTypes) { - if((iSpellTypes&SpellTypes_Detrimental) != 0) { - //according to live, you can buff and heal through walls... - //now with PCs, this only applies if you can TARGET the target, but - // according to Rogean, Live NPCs will just cast through walls/floors, no problem.. - // - // This check was put in to address an idle-mob CPU issue Log.Out(Logs::General, Logs::Error, "Error: detrimental spells requested from AICheckCloseBeneficialSpells!!"); - return(false); + return false; } - if(!caster) - return false; - - if(!caster->AI_HasSpells()) + if(!caster || !caster->AI_HasSpells()) return false; if (iChance < 100) { @@ -15495,30 +7674,22 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl uint8 botCasterClass = caster->GetClass(); if( iSpellTypes == SpellType_Heal ) { - // Changed so heal based on health percentage is different for hybrids if( botCasterClass == CLERIC || botCasterClass == DRUID || botCasterClass == SHAMAN) { - //If AI_EngagedCastCheck() said to the healer that he had to heal - - // check in group if(caster->HasGroup()) { Group *g = caster->GetGroup(); - if(g) { for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { if(g->members[i] && !g->members[i]->qglobal) { if(g->members[i]->IsClient() && g->members[i]->GetHPRatio() < 90) { if(caster->AICastSpell(g->members[i], 100, SpellType_Heal)) return true; - } - else if((g->members[i]->GetClass() == WARRIOR || g->members[i]->GetClass() == PALADIN || g->members[i]->GetClass() == SHADOWKNIGHT) && g->members[i]->GetHPRatio() < 95) { + } else if((g->members[i]->GetClass() == WARRIOR || g->members[i]->GetClass() == PALADIN || g->members[i]->GetClass() == SHADOWKNIGHT) && g->members[i]->GetHPRatio() < 95) { if(caster->AICastSpell(g->members[i], 100, SpellType_Heal)) return true; - } - else if(g->members[i]->GetClass() == ENCHANTER && g->members[i]->GetHPRatio() < 80) { + } else if(g->members[i]->GetClass() == ENCHANTER && g->members[i]->GetHPRatio() < 80) { if(caster->AICastSpell(g->members[i], 100, SpellType_Heal)) return true; - } - else if(g->members[i]->GetHPRatio() < 70) { + } else if(g->members[i]->GetHPRatio() < 70) { if(caster->AICastSpell(g->members[i], 100, SpellType_Heal)) return true; } @@ -15534,26 +7705,13 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } } } - - // TODO: raid heals } - // Changed so heal based on health percentage is different for hybrids if( botCasterClass == PALADIN || botCasterClass == BEASTLORD || botCasterClass == RANGER) { - //If AI_EngagedCastCheck() said to the healer that he had to heal - - // check in group if(caster->HasGroup()) { Group *g = caster->GetGroup(); - float hpRatioToHeal = 25.0f; - - switch(caster->GetBotStance()) - { - case BotStanceAggressive: - case BotStanceEfficient: - hpRatioToHeal = 25.0f; - break; + switch(caster->GetBotStance()) { case BotStanceReactive: case BotStanceBalanced: hpRatioToHeal = 50.0f; @@ -15562,6 +7720,8 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl case BotStanceBurnAE: hpRatioToHeal = 20.0f; break; + case BotStanceAggressive: + case BotStanceEfficient: default: hpRatioToHeal = 25.0f; break; @@ -15573,16 +7733,13 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl if(g->members[i]->IsClient() && g->members[i]->GetHPRatio() < hpRatioToHeal) { if(caster->AICastSpell(g->members[i], 100, SpellType_Heal)) return true; - } - else if((g->members[i]->GetClass() == WARRIOR || g->members[i]->GetClass() == PALADIN || g->members[i]->GetClass() == SHADOWKNIGHT) && g->members[i]->GetHPRatio() < hpRatioToHeal) { + } else if((g->members[i]->GetClass() == WARRIOR || g->members[i]->GetClass() == PALADIN || g->members[i]->GetClass() == SHADOWKNIGHT) && g->members[i]->GetHPRatio() < hpRatioToHeal) { if(caster->AICastSpell(g->members[i], 100, SpellType_Heal)) return true; - } - else if(g->members[i]->GetClass() == ENCHANTER && g->members[i]->GetHPRatio() < hpRatioToHeal) { + } else if(g->members[i]->GetClass() == ENCHANTER && g->members[i]->GetHPRatio() < hpRatioToHeal) { if(caster->AICastSpell(g->members[i], 100, SpellType_Heal)) return true; - } - else if(g->members[i]->GetHPRatio() < hpRatioToHeal/2) { + } else if(g->members[i]->GetHPRatio() < hpRatioToHeal/2) { if(caster->AICastSpell(g->members[i], 100, SpellType_Heal)) return true; } @@ -15598,15 +7755,11 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } } } - - // TODO: raid heals } } - //Ok for the buffs.. if( iSpellTypes == SpellType_Buff) { - uint8 chanceToCast = caster->IsEngaged()?caster->GetChanceToCastBySpellType(SpellType_Buff):100; - // Let's try to make Bard working... + uint8 chanceToCast = caster->IsEngaged() ? caster->GetChanceToCastBySpellType(SpellType_Buff) : 100; if(botCasterClass == BARD) { if(caster->AICastSpell(caster, chanceToCast, SpellType_Buff)) return true; @@ -15616,29 +7769,22 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl if(caster->HasGroup()) { Group *g = caster->GetGroup(); - if(g) { - for( int i = 0; i < MAX_GROUP_MEMBERS; i++) { + for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { if(g->members[i]) { - if(caster->AICastSpell(g->members[i], chanceToCast, SpellType_Buff)) - return true; - - if(caster->AICastSpell(g->members[i]->GetPet(), chanceToCast, SpellType_Buff)) + if(caster->AICastSpell(g->members[i], chanceToCast, SpellType_Buff) || caster->AICastSpell(g->members[i]->GetPet(), chanceToCast, SpellType_Buff)) return true; } } } } - - // TODO: raid buffs } if( iSpellTypes == SpellType_Cure) { if(caster->HasGroup()) { Group *g = caster->GetGroup(); - if(g) { - for( int i = 0; i < MAX_GROUP_MEMBERS; i++) { + for(int i = 0; i < MAX_GROUP_MEMBERS; i++) { if(g->members[i] && caster->GetNeedsCured(g->members[i])) { if(caster->AICastSpell(g->members[i], caster->GetChanceToCastBySpellType(SpellType_Cure), SpellType_Cure)) return true; @@ -15653,157 +7799,98 @@ bool EntityList::Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, fl } } } - - // TODO: raid buffs } - return false; } Mob* EntityList::GetMobByBotID(uint32 botID) { Mob* Result = 0; - if(botID > 0) { auto it = mob_list.begin(); + for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { + if(!it->second) + continue; - for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { - if(!it->second) continue; if(it->second->IsBot() && it->second->CastToBot()->GetBotID() == botID) { Result = it->second; break; } } } - return Result; } Bot* EntityList::GetBotByBotID(uint32 botID) { Bot* Result = 0; - if(botID > 0) { for(std::list::iterator botListItr = bot_list.begin(); botListItr != bot_list.end(); ++botListItr) { Bot* tempBot = *botListItr; - if(tempBot && tempBot->GetBotID() == botID) { Result = tempBot; break; } } } - return Result; } Bot* EntityList::GetBotByBotName(std::string botName) { Bot* Result = 0; - if(!botName.empty()) { for(std::list::iterator botListItr = bot_list.begin(); botListItr != bot_list.end(); ++botListItr) { Bot* tempBot = *botListItr; - if(tempBot && std::string(tempBot->GetName()) == botName) { Result = tempBot; break; } } } - return Result; } void EntityList::AddBot(Bot *newBot, bool SendSpawnPacket, bool dontqueue) { if(newBot) { newBot->SetID(GetFreeID()); - + newBot->SetSpawned(); if(SendSpawnPacket) { if(dontqueue) { - // Send immediately EQApplicationPacket* outapp = new EQApplicationPacket(); newBot->CreateSpawnPacket(outapp); outapp->priority = 6; QueueClients(newBot, outapp, true); safe_delete(outapp); - } - else { - // Queue the packet + } else { NewSpawn_Struct* ns = new NewSpawn_Struct; memset(ns, 0, sizeof(NewSpawn_Struct)); newBot->FillSpawnStruct(ns, newBot); AddToSpawnQueue(newBot->GetID(), &ns); safe_delete(ns); } - parse->EventNPC(EVENT_SPAWN, newBot, nullptr, "", 0); } - bot_list.push_back(newBot); - mob_list.insert(std::pair(newBot->GetID(), newBot)); } } std::list EntityList::GetBotsByBotOwnerCharacterID(uint32 botOwnerCharacterID) { std::list Result; - if(botOwnerCharacterID > 0) { for(std::list::iterator botListItr = bot_list.begin(); botListItr != bot_list.end(); ++botListItr) { Bot* tempBot = *botListItr; - if(tempBot && tempBot->GetBotOwnerCharacterID() == botOwnerCharacterID) Result.push_back(tempBot); } } - return Result; } -void EntityList::BotPickLock(Bot* rogue) -{ - for (auto it = door_list.begin(); it != door_list.end(); ++it) { - Doors *cdoor = it->second; - if(!cdoor || cdoor->IsDoorOpen()) - continue; - - auto diff = rogue->GetPosition() - cdoor->GetPosition(); - - float curdist = diff.x * diff.x + diff.y * diff.y; - - if((diff.z * diff.z >= 10) || (curdist > 130)) - continue; - - // All rogue items with lock pick bonuses are hands or primary - const ItemInst* item1 = rogue->GetBotItem(MainHands); - const ItemInst* item2 = rogue->GetBotItem(MainPrimary); - - float bonus1 = 0.0f; - float bonus2 = 0.0f; - float skill = rogue->GetSkill(SkillPickLock); - - if(item1) // Hand slot item - if(item1->GetItem()->SkillModType == SkillPickLock) - bonus1 = skill * (((float)item1->GetItem()->SkillModValue) / 100.0f); - - if(item2) // Primary slot item - if(item2->GetItem()->SkillModType == SkillPickLock) - bonus2 = skill * (((float)item2->GetItem()->SkillModValue) / 100.0f); - - if((skill+bonus1+bonus2) >= cdoor->GetLockpick()) - cdoor->ForceOpen(rogue); - else - rogue->Say("I am not skilled enough for this lock."); - } -} - bool EntityList::RemoveBot(uint16 entityID) { bool Result = false; - if(entityID > 0) { - for(std::list::iterator botListItr = bot_list.begin(); botListItr != bot_list.end(); ++botListItr) - { + for(std::list::iterator botListItr = bot_list.begin(); botListItr != bot_list.end(); ++botListItr) { Bot* tempBot = *botListItr; - if(tempBot && tempBot->GetID() == entityID) { bot_list.erase(botListItr); Result = true; @@ -15811,23 +7898,17 @@ bool EntityList::RemoveBot(uint16 entityID) { } } } - return Result; } void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) { - const char *WindowTitle = "Bot Tracking Window"; - std::string WindowText; int LastCon = -1; int CurrentCon = 0; Mob* curMob = nullptr; - uint32 array_counter = 0; - auto it = mob_list.begin(); - for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { curMob = it->second; if (curMob && DistanceNoZ(curMob->GetPosition(), client->GetPosition()) <= Distance) { @@ -15866,36 +7947,34 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) { "stone_","lava_","_","" }; unsigned int MyArraySize; - for ( MyArraySize = 0; true; MyArraySize++) { //Find empty string & get size - if (!(*(MyArray[MyArraySize]))) break; //Checks for null char in 1st pos + for ( MyArraySize = 0; true; MyArraySize++) { + if (!(*(MyArray[MyArraySize]))) + break; }; if (NamedOnly) { bool ContinueFlag = false; - const char *CurEntityName = cur_entity->GetName(); //Call function once + const char *CurEntityName = cur_entity->GetName(); for (int Index = 0; Index < MyArraySize; Index++) { if (!strncasecmp(CurEntityName, MyArray[Index], strlen(MyArray[Index])) || (Extras)) { ContinueFlag = true; - break; //From Index for + break; }; }; - if (ContinueFlag) continue; //Moved here or would apply to Index for + if (ContinueFlag) + continue; }; CurrentCon = client->GetLevelCon(cur_entity->GetLevel()); if(CurrentCon != LastCon) { - if(LastCon != -1) WindowText += ""; LastCon = CurrentCon; - switch(CurrentCon) { - case CON_GREEN: { WindowText += ""; break; } - case CON_LIGHTBLUE: { WindowText += ""; break; @@ -15904,7 +7983,6 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) { WindowText += ""; break; } - case CON_YELLOW: { WindowText += ""; break; @@ -15919,89 +7997,52 @@ void EntityList::ShowSpawnWindow(Client* client, int Distance, bool NamedOnly) { } } } - WindowText += cur_entity->GetCleanName(); WindowText += "
"; - if(strlen(WindowText.c_str()) > 4000) { - // Popup window is limited to 4096 characters. - WindowText += "


List truncated ... too many mobs to display"; + WindowText += "


List truncated... too many mobs to display"; break; } } } } WindowText += "
"; - client->SendPopupToClient(WindowTitle, WindowText.c_str()); - return; } uint8 Bot::GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets) { uint8 needHealed = 0; Group *g; - if(this->HasGroup()) { g = this->GetGroup(); - if(g) { - for( int i = 0; imembers[i] && !g->members[i]->qglobal) { - if(g->members[i]->GetHPRatio() <= hpr) needHealed++; if(includePets) { - if(g->members[i]->GetPet() && g->members[i]->GetPet()->GetHPRatio() <= hpr) { + if(g->members[i]->GetPet() && g->members[i]->GetPet()->GetHPRatio() <= hpr) needHealed++; - } } } } } } - return needHealed; } -uint32 Bot::GetEquipmentColor(uint8 material_slot) const -{ - //Bot tints - int16 slotid = 0; - uint32 botid = this->GetBotID(); - - //Translate code slot # to DB slot # - slotid = Inventory::CalcSlotFromMaterial(material_slot); - if (slotid == INVALID_INDEX) - return 0; - - //read from db - std::string query = StringFormat("SELECT color FROM botinventory " - "WHERE BotID = %u AND SlotID = %u", botid, slotid); - auto results = database.QueryDatabase(query); - if (!results.Success() || results.RowCount() != 1) - return 0; - - auto row = results.begin(); - return atoul(row[0]); -} - -int Bot::GetRawACNoShield(int &shield_ac) -{ +int Bot::GetRawACNoShield(int &shield_ac) { int ac = itembonuses.AC + spellbonuses.AC; shield_ac = 0; - ItemInst* inst = GetBotItem(MainSecondary); - if(inst) - { - if(inst->GetItem()->ItemType == ItemTypeShield) - { + ItemInst* inst = GetBotItem(EQEmu::legacy::SlotSecondary); + if(inst) { + if (inst->GetItem()->ItemType == EQEmu::item::ItemTypeShield) { ac -= inst->GetItem()->AC; shield_ac = inst->GetItem()->AC; - for (uint8 i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) - { - if(inst->GetAugment(i)) - { + for (uint8 i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { + if(inst->GetAugment(i)) { ac -= inst->GetAugment(i)->GetItem()->AC; shield_ac += inst->GetAugment(i)->GetItem()->AC; } @@ -16012,38 +8053,32 @@ int Bot::GetRawACNoShield(int &shield_ac) } uint32 Bot::CalcCurrentWeight() { - - const Item_Struct* TempItem = 0; + const EQEmu::ItemBase* TempItem = 0; ItemInst* inst; uint32 Total = 0; - - for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) { + for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= EQEmu::legacy::EQUIPMENT_END; ++i) { inst = GetBotItem(i); if(inst) { TempItem = inst->GetItem(); - if (TempItem) - Total += TempItem->Weight; + if (TempItem) + Total += TempItem->Weight; } } - float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat; - + float Packrat = ((float)spellbonuses.Packrat + (float)aabonuses.Packrat); if (Packrat > 0) - Total = (uint32)((float)Total * (1.0f - ((Packrat * 1.0f) / 100.0f))); //AndMetal: 1% per level, up to 5% (calculated from Titanium client). verified thru client that it reduces coin weight by the same % - //without casting to float & back to uint32, this didn't work right + Total = (uint32)((float)Total * (1.0f - ((Packrat * 1.0f) / 100.0f))); return Total; } -int Bot::GroupLeadershipAAHealthEnhancement() -{ +int Bot::GroupLeadershipAAHealthEnhancement() { Group *g = GetGroup(); if(!g || (g->GroupCount() < 3)) return 0; - switch(g->GetLeadershipAA(groupAAHealthEnhancement)) - { + switch(g->GetLeadershipAA(groupAAHealthEnhancement)) { case 0: return 0; case 1: @@ -16053,19 +8088,15 @@ int Bot::GroupLeadershipAAHealthEnhancement() case 3: return 100; } - return 0; } -int Bot::GroupLeadershipAAManaEnhancement() -{ +int Bot::GroupLeadershipAAManaEnhancement() { Group *g = GetGroup(); - if(!g || (g->GroupCount() < 3)) return 0; - switch(g->GetLeadershipAA(groupAAManaEnhancement)) - { + switch(g->GetLeadershipAA(groupAAManaEnhancement)) { case 0: return 0; case 1: @@ -16075,19 +8106,15 @@ int Bot::GroupLeadershipAAManaEnhancement() case 3: return 100; } - return 0; } -int Bot::GroupLeadershipAAHealthRegeneration() -{ +int Bot::GroupLeadershipAAHealthRegeneration() { Group *g = GetGroup(); - if(!g || (g->GroupCount() < 3)) return 0; - switch(g->GetLeadershipAA(groupAAHealthRegeneration)) - { + switch(g->GetLeadershipAA(groupAAHealthRegeneration)) { case 0: return 0; case 1: @@ -16101,15 +8128,13 @@ int Bot::GroupLeadershipAAHealthRegeneration() return 0; } -int Bot::GroupLeadershipAAOffenseEnhancement() -{ +int Bot::GroupLeadershipAAOffenseEnhancement() { Group *g = GetGroup(); if(!g || (g->GroupCount() < 3)) return 0; - switch(g->GetLeadershipAA(groupAAOffenseEnhancement)) - { + switch(g->GetLeadershipAA(groupAAOffenseEnhancement)) { case 0: return 0; case 1: @@ -16128,23 +8153,34 @@ int Bot::GroupLeadershipAAOffenseEnhancement() bool Bot::GetNeedsCured(Mob *tar) { bool needCured = false; - if(tar) { if(tar->FindType(SE_PoisonCounter) || tar->FindType(SE_DiseaseCounter) || tar->FindType(SE_CurseCounter) || tar->FindType(SE_CorruptionCounter)) { uint32 buff_count = GetMaxTotalSlots(); int buffsWithCounters = 0; needCured = true; - for (unsigned int j = 0; j < buff_count; j++) { - if(tar->GetBuffs()[j].spellid != SPELL_UNKNOWN) { + // this should prevent crashes until the cause can be found + if (!tar->GetBuffs()) { + std::string mob_type = "Unknown"; + if (tar->IsClient()) + mob_type = "Client"; + else if (tar->IsBot()) + mob_type = "Bot"; + else if (tar->IsMerc()) + mob_type = "Merc"; + else if (tar->IsPet()) + mob_type = "Pet"; + else if (tar->IsNPC()) + mob_type = "NPC"; + + Log.Out(Logs::General, Logs::Error, "Bot::GetNeedsCured() processed mob type '%s' with a null buffs pointer (mob: '%s')", mob_type.c_str(), tar->GetName()); + + continue; + } + else if(tar->GetBuffs()[j].spellid != SPELL_UNKNOWN) { if(CalculateCounters(tar->GetBuffs()[j].spellid) > 0) { buffsWithCounters++; - if(buffsWithCounters == 1 && (tar->GetBuffs()[j].ticsremaining < 2 || (int32)((tar->GetBuffs()[j].ticsremaining * 6) / tar->GetBuffs()[j].counters) < 2)) { - // Spell has ticks remaining but may have too many counters to cure in the time remaining; - // We should try to just wait it out. Could spend entire time trying to cure spell instead of healing, buffing, etc. - // Since this is the first buff with counters, don't try to cure. Cure spell will be wasted, as cure will try to - // remove counters from the first buff that has counters remaining. needCured = false; break; } @@ -16153,27 +8189,23 @@ bool Bot::GetNeedsCured(Mob *tar) { } } } - return needCured; } bool Bot::HasOrMayGetAggro() { bool mayGetAggro = false; - if(GetTarget() && GetTarget()->GetHateTop()) { Mob *topHate = GetTarget()->GetHateTop(); - if(topHate == this) - mayGetAggro = true; //I currently have aggro + mayGetAggro = true; else { uint32 myHateAmt = GetTarget()->GetHateAmount(this); uint32 topHateAmt = GetTarget()->GetHateAmount(topHate); - if(myHateAmt > 0 && topHateAmt > 0 && (uint8)((myHateAmt/topHateAmt)*100) > 90) //I have 90% as much hate as top, next action may give me aggro + if(myHateAmt > 0 && topHateAmt > 0 && (uint8)((myHateAmt / topHateAmt) * 100) > 90) mayGetAggro = true; } } - return mayGetAggro; } @@ -16181,483 +8213,282 @@ void Bot::SetHasBeenSummoned(bool wasSummoned) { _hasBeenSummoned = wasSummoned; if(!wasSummoned) m_PreSummonLocation = glm::vec3(); - } void Bot::SetDefaultBotStance() { - BotStanceType defaultStance; + BotStanceType defaultStance = BotStanceBalanced; + if (GetClass() == WARRIOR) + defaultStance = BotStanceAggressive; - switch(GetClass()) - { - case DRUID: - case CLERIC: - case SHAMAN: - case ENCHANTER: - case NECROMANCER: - case MAGICIAN: - case WIZARD: - case BEASTLORD: - case BERSERKER: - case MONK: - case ROGUE: - case BARD: - case SHADOWKNIGHT: - case PALADIN: - case RANGER: - defaultStance = BotStanceBalanced; - break; - case WARRIOR: - defaultStance = BotStanceAggressive; - break; - default: - defaultStance = BotStanceBalanced; - break; - } _baseBotStance = BotStancePassive; _botStance = defaultStance; } -void Bot::BotGroupSay(Mob *speaker, const char *msg, ...) -{ - +void Bot::BotGroupSay(Mob *speaker, const char *msg, ...) { char buf[1000]; va_list ap; - va_start(ap, msg); vsnprintf(buf, 1000, msg, ap); va_end(ap); - if(speaker->HasGroup()) { Group *g = speaker->GetGroup(); - if(g) g->GroupMessage(speaker->CastToMob(), 0, 100, buf); - } + } else + speaker->Say("%s", buf); } bool Bot::UseDiscipline(uint32 spell_id, uint32 target) { - //make sure we have the spell... - int r; - /*for(r = 0; r < MAX_PP_DISCIPLINES; r++) { - if(m_pp.disciplines.values[r] == spell_id) - break; - } - if(r == MAX_PP_DISCIPLINES) - return(false); //not found. - - //Check the disc timer - pTimerType DiscTimer = pTimerDisciplineReuseStart + spells[spell_id].EndurTimerIndex; - if(!p_timers.Expired(&database, DiscTimer)) { - uint32 remain = p_timers.GetRemainingTime(DiscTimer); - //Message_StringID(0, DISCIPLINE_CANUSEIN, ConvertArray((remain)/60,val1), ConvertArray(remain%60,val2)); - Message(0, "You can use this discipline in %d minutes %d seconds.", ((remain)/60), (remain%60)); - return(false); - }*/ - - //make sure we can use it.. if(!IsValidSpell(spell_id)) { - Say("Not a valid spell"); - return(false); + BotGroupSay(this, "Not a valid spell."); + return false; } - //can we use the spell? const SPDat_Spell_Struct &spell = spells[spell_id]; uint8 level_to_use = spell.classes[GetClass() - 1]; - if(level_to_use == 255) { - return(false); + if(level_to_use == 255 || level_to_use > GetLevel()) { + return false; } - if(level_to_use > GetLevel()) { - return(false); - } - - if(GetEndurance() > spell.EndurCost) { + if(GetEndurance() > spell.EndurCost) SetEndurance(GetEndurance() - spell.EndurCost); - } else { - return(false); - } + else + return false; - if(spell.recast_time > 0) - { + if(spell.recast_time > 0) { if(CheckDisciplineRecastTimers(this, spells[spell_id].EndurTimerIndex)) { - - //CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT); - if(spells[spell_id].EndurTimerIndex > 0 && spells[spell_id].EndurTimerIndex < MAX_DISCIPLINE_TIMERS) { + if(spells[spell_id].EndurTimerIndex > 0 && spells[spell_id].EndurTimerIndex < MAX_DISCIPLINE_TIMERS) SetDisciplineRecastTimer(spells[spell_id].EndurTimerIndex, spell.recast_time); - } - } - else { - uint32 remain = GetDisciplineRemainingTime(this, spells[spell_id].EndurTimerIndex) / 1000; - GetOwner()->Message(0, "%s can use this discipline in %d minutes %d seconds.", GetCleanName(), ((remain)/60), (remain%60)); - return(false); + } else { + uint32 remain = (GetDisciplineRemainingTime(this, spells[spell_id].EndurTimerIndex) / 1000); + GetOwner()->Message(0, "%s can use this discipline in %d minutes %d seconds.", GetCleanName(), (remain / 60), (remain % 60)); + return false; } } if(IsCasting()) InterruptSpell(); - CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT); - - return(true); + CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline); + return true; } -void Bot::CreateHealRotation( Mob* target, uint32 timer ) { - SetInHealRotation(true); - SetHealRotationActive(false); - SetNumHealRotationMembers(GetNumHealRotationMembers()+1); - SetHealRotationLeader(this); - SetNextHealRotationMember(this); - SetPrevHealRotationMember(this); - SetHealRotationTimer(timer); - SetHasHealedThisCycle(false); +// new healrotation code +bool Bot::CreateHealRotation(uint32 interval_ms, bool fast_heals, bool adaptive_targeting, bool casting_override) +{ + if (IsHealRotationMember()) + return false; + if (!IsHealRotationMemberClass(GetClass())) + return false; + + m_member_of_heal_rotation = std::make_shared(this, interval_ms, fast_heals, adaptive_targeting, casting_override); - if(target) - AddHealRotationTarget(target); + return IsHealRotationMember(); } -bool Bot::AddHealRotationMember( Bot* healer ) { - if(healer) { - if(GetNumHealRotationMembers() > 0 && GetNumHealRotationMembers() < MaxHealRotationMembers) { - Bot* tempBot = GetPrevHealRotationMember(); +bool Bot::DestroyHealRotation() +{ + if (!IsHealRotationMember()) + return true; - if(tempBot) { - //add new healer to rotation at end of list - for(int i=0; i<3; i++){ - healer->ClearHealRotationMembers(); - healer->ClearHealRotationTargets(); - healer->AddHealRotationTarget(entity_list.GetMob(_healRotationTargets[i])); // add all targets.. - } - healer->SetHealRotationTimer(tempBot->GetHealRotationTimer()); - healer->SetHealRotationLeader(this); - healer->SetNextHealRotationMember(this); - healer->SetPrevHealRotationMember(tempBot); - healer->SetInHealRotation(true); - healer->SetHasHealedThisCycle(false); - healer->SetHealRotationUseFastHeals(tempBot->GetHealRotationUseFastHeals()); + m_member_of_heal_rotation->ClearTargetPool(); + m_member_of_heal_rotation->ClearMemberPool(); - //set previous rotation member's next member to new member - tempBot->SetNextHealRotationMember(healer); - - //update leader's previous member (end of list) to new member and update rotation data - SetPrevHealRotationMember(healer); - - std::list botList = GetBotsInHealRotation(this); - - for(std::list::iterator botListItr = botList.begin(); botListItr != botList.end(); ++botListItr) { - Bot* tempBot = *botListItr; - - if(tempBot) - tempBot->SetNumHealRotationMembers(GetNumHealRotationMembers()+1); - } - - return true; - } - } - } - - return false; + return !IsHealRotationMember(); } -bool Bot::RemoveHealRotationMember( Bot* healer ) { - if(healer && GetNumHealRotationMembers() > 0) { - Bot* leader = healer->GetHealRotationLeader(); - Bot* prevBot = healer->GetPrevHealRotationMember(); - Bot* nextBot = healer->GetNextHealRotationMember(); +bool Bot::JoinHealRotationMemberPool(std::shared_ptr* heal_rotation) +{ + if (IsHealRotationMember()) + return false; + if (!heal_rotation->use_count()) + return false; + if (!(*heal_rotation)) + return false; + if (!IsHealRotationMemberClass(GetClass())) + return false; - if(healer == this) { - if(nextBot != this) { - //get new leader - leader = nextBot; - } - } + if (!(*heal_rotation)->AddMemberToPool(this)) + return false; - //remove healer from list - healer->SetHealRotationTimer(0); - healer->ClearHealRotationMembers(); - healer->ClearHealRotationTargets(); - healer->ClearHealRotationLeader(); - healer->SetHasHealedThisCycle(false); - healer->SetHealRotationActive(false); - healer->SetInHealRotation(false); + m_member_of_heal_rotation = *heal_rotation; - if(prevBot && nextBot && GetNumHealRotationMembers() > 1) { - //set previous rotation member's next member to new member - prevBot->SetNextHealRotationMember(nextBot); - - //set previous rotation member's next member to new member - nextBot->SetPrevHealRotationMember(prevBot); - } - - //update rotation data - std::list botList = GetBotsInHealRotation(leader); - - for(std::list::iterator botListItr = botList.begin(); botListItr != botList.end(); ++botListItr) { - Bot* tempBot = *botListItr; - - if(tempBot) { - tempBot->SetNumHealRotationMembers(GetNumHealRotationMembers()-1); - - if(tempBot->GetHealRotationLeader() != leader) { - // change leader if leader is being removed - tempBot->SetHealRotationLeader(leader); - } - } - } + return true; +} +bool Bot::LeaveHealRotationMemberPool() +{ + if (!IsHealRotationMember()) { + m_member_of_heal_rotation.reset(); return true; } - return false; + m_member_of_heal_rotation->RemoveMemberFromPool(this); + m_member_of_heal_rotation.reset(); + + return !IsHealRotationMember(); } -void Bot::SetHealRotationLeader( Bot* leader ) { - _healRotationLeader = leader->GetBotID(); +bool Bot::UseHealRotationFastHeals() +{ + if (!IsHealRotationMember()) + return false; + + return m_member_of_heal_rotation->FastHeals(); } -void Bot::SetNextHealRotationMember( Bot* healer ) { - _healRotationMemberNext = healer->GetBotID(); +bool Bot::UseHealRotationAdaptiveTargeting() +{ + if (!IsHealRotationMember()) + return false; + + return m_member_of_heal_rotation->AdaptiveTargeting(); } -void Bot::SetPrevHealRotationMember( Bot* healer ) { - _healRotationMemberPrev = healer->GetBotID(); +bool Bot::IsHealRotationActive() +{ + if (!IsHealRotationMember()) + return false; + + return m_member_of_heal_rotation->IsActive(); } -Bot* Bot::GetHealRotationLeader( ) { - if(_healRotationLeader) - return entity_list.GetBotByBotID(_healRotationLeader); - return 0; +bool Bot::IsHealRotationReady() +{ + if (!IsHealRotationMember()) + return false; + + return m_member_of_heal_rotation->CastingReady(); } -Bot* Bot::GetNextHealRotationMember( ) { - if(_healRotationMemberNext) - return entity_list.GetBotByBotID(_healRotationMemberNext); - return 0; +bool Bot::IsHealRotationCaster() +{ + if (!IsHealRotationMember()) + return false; + + return (m_member_of_heal_rotation->CastingMember() == this); } -Bot* Bot::GetPrevHealRotationMember( ) { - if(_healRotationMemberNext) - return entity_list.GetBotByBotID(_healRotationMemberPrev); - return 0; +bool Bot::HealRotationPokeTarget() +{ + if (!IsHealRotationMember()) + return false; + + return m_member_of_heal_rotation->PokeCastingTarget(); } -bool Bot::AddHealRotationTarget( Mob* target ) { - if(target) { +Mob* Bot::HealRotationTarget() +{ + if (!IsHealRotationMember()) + return nullptr; - for (int i = 0; i < MaxHealRotationTargets; ++i) { - if(_healRotationTargets[i] > 0) { - Mob* tempTarget = entity_list.GetMob(_healRotationTargets[i]); + return m_member_of_heal_rotation->CastingTarget(); +} - if(!tempTarget) { - _healRotationTargets[i] = 0; - } - else if(!strcasecmp(tempTarget->GetCleanName(), target->GetCleanName())) { - //check to see if target's ID is incorrect (could have zoned, died, etc) - if(tempTarget->GetID() != target->GetID()) { - _healRotationTargets[i] = target->GetID(); - } - //target already in list - return false; - } - } +bool Bot::AdvanceHealRotation(bool use_interval) +{ + if (!IsHealRotationMember()) + return false; - if (_healRotationTargets[i] == 0) - { - std::list botList = GetBotsInHealRotation(this); + return m_member_of_heal_rotation->AdvanceRotation(use_interval); +} - _healRotationTargets[i] = target->GetID(); +bool Bot::IsMyHealRotationSet() +{ + if (!IsHealRotationMember()) + return false; + if (!m_member_of_heal_rotation->IsActive() && !m_member_of_heal_rotation->IsHOTActive()) + return false; + if (!m_member_of_heal_rotation->CastingReady()) + return false; + if (m_member_of_heal_rotation->CastingMember() != this) + return false; + if (m_member_of_heal_rotation->MemberIsCasting(this)) + return false; + if (!m_member_of_heal_rotation->PokeCastingTarget()) + return false; - for(std::list::iterator botListItr = botList.begin(); botListItr != botList.end(); ++botListItr) { - Bot* tempBot = *botListItr; + return true; +} - if(tempBot && tempBot != this) { - //add target to all members - tempBot->AddHealRotationTarget(target, i); - } - } +bool Bot::AmICastingForHealRotation() +{ + if (!IsHealRotationMember()) + return false; - return true; - } + return m_member_of_heal_rotation->MemberIsCasting(this); +} + +void Bot::SetMyCastingForHealRotation(bool flag) +{ + if (!IsHealRotationMember()) + return; + + m_member_of_heal_rotation->SetMemberIsCasting(this, flag); +} + +bool Bot::DyeArmor(int16 slot_id, uint32 rgb, bool all_flag, bool save_flag) +{ + if (all_flag) { + if (slot_id != INVALID_INDEX) + return false; + + for (uint8 i = 0; i < EQEmu::textures::TexturePrimary; ++i) { + uint8 inv_slot = Inventory::CalcSlotFromMaterial(i); + ItemInst* inst = m_inv.GetItem(inv_slot); + if (!inst) + continue; + + inst->SetColor(rgb); + SendWearChange(i); + } + } + else { + uint8 mat_slot = Inventory::CalcMaterialFromSlot(slot_id); + if (mat_slot == EQEmu::textures::TextureInvalid || mat_slot >= EQEmu::textures::TexturePrimary) + return false; + + ItemInst* inst = m_inv.GetItem(slot_id); + if (!inst) + return false; + + inst->SetColor(rgb); + SendWearChange(mat_slot); + } + + if (save_flag) { + int16 save_slot = slot_id; + if (all_flag) + save_slot = -2; + + if (!botdb.SaveEquipmentColor(GetBotID(), save_slot, rgb)) { + if (GetBotOwner() && GetBotOwner()->IsClient()) + GetBotOwner()->CastToClient()->Message(13, "%s", BotDatabase::fail::SaveEquipmentColor()); + return false; } } - return false; + return true; } -bool Bot::AddHealRotationTarget( Mob *target, int index ) { - if (target && index < MaxHealRotationTargets) { - //add target to list of targets at specified index - _healRotationTargets[index] = target->GetID(); - return true; - } - return false; -} +std::string Bot::CreateSayLink(Client* c, const char* message, const char* name) +{ + int saylink_size = strlen(message); + char* escaped_string = new char[saylink_size * 2]; -bool Bot::RemoveHealRotationTarget( Mob* target ) { - int index = 0; - bool removed = false; - if(target) { - //notify all heal rotation members to remove target - for(int i=0; iGetID()) { - std::list botList = GetBotsInHealRotation(this); - _healRotationTargets[i] = 0; - index = i; - removed = true; + database.DoEscapeString(escaped_string, message, saylink_size); - for(std::list::iterator botListItr = botList.begin(); botListItr != botList.end(); ++botListItr) { - Bot* tempBot = *botListItr; + uint32 saylink_id = database.LoadSaylinkID(escaped_string); + safe_delete_array(escaped_string); - if(tempBot) - tempBot->RemoveHealRotationTarget(i); - } - } - } - } + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemData); + linker.SetProxyItemID(SAYLINK_ITEM_ID); + linker.SetProxyAugment1ID(saylink_id); + linker.SetProxyText(name); - return removed; -} - -bool Bot::RemoveHealRotationTarget( int index ) { - if(index >= 0) { - //clear rotation target at index - _healRotationTargets[index] = 0; - - if(index < MaxHealRotationTargets) { - for(int i=index; i 0) { - - //get first target in list - target = entity_list.GetMob(_healRotationTargets[i]); - - if(target) { - //check if valid target - if(target->GetZoneID() == GetZoneID() - && !(target->GetAppearance() == eaDead - && !(target->IsClient() && target->CastToClient()->GetFeigned()))) { - - count++; - - //get first valid target - if(!first) { - first = target; - } - - //check to see if target is group main tank - //(target first, in case top target has died and was rez'd - - //we don't want to heal them then) - if(!tank) { - Group* g = target->GetGroup(); - if(g && !strcasecmp(g->GetMainTankName(), target->GetCleanName())) { - tank = target; - } - } - } - } - else { - //if not valid target, remove from list - if(removeIndex == 0) - removeIndex = i; - } - } - } - - if (removeIndex > 0) { - RemoveHealRotationTarget( removeIndex ); - } - - if(tank) - return tank; - - return first; -} - -Mob* Bot::GetHealRotationTarget( uint8 index ) { - Mob* target = nullptr; - - if(_healRotationTargets[index] > 0) { - //get target at specified index - target = entity_list.GetMob(_healRotationTargets[index]); - } - - return target; -} - -std::list Bot::GetBotsInHealRotation(Bot* rotationLeader) { - std::list Result; - - if(rotationLeader != nullptr) { - Result.push_back(rotationLeader); - Bot* rotationMember = rotationLeader->GetNextHealRotationMember(); - - while(rotationMember && rotationMember != rotationLeader) { - Result.push_back(rotationMember); - rotationMember = rotationMember->GetNextHealRotationMember(); - } - } - - return Result; -} - -void Bot::NotifyNextHealRotationMember(bool notifyNow) { - //check if we need to notify to start now, or after timer - uint32 nextHealTime = notifyNow ? Timer::GetCurrentTime() : Timer::GetCurrentTime() + GetHealRotationTimer(); - - Bot* nextMember = GetNextHealRotationMember(); - if(nextMember && nextMember != this) { - nextMember->SetHealRotationNextHealTime(nextHealTime); - nextMember->SetHasHealedThisCycle(false); - } -} - -void Bot::BotHealRotationsClear(Client* c) { - if(c) { - std::list BotList = entity_list.GetBotsByBotOwnerCharacterID(c->CharacterID()); - - for(std::list::iterator botListItr = BotList.begin(); botListItr != BotList.end(); ++botListItr) { - Bot* tempBot = *botListItr; - if(tempBot->GetInHealRotation()) { - //clear all heal rotation data for bots in a heal rotation - tempBot->SetInHealRotation(false); - tempBot->SetHealRotationActive(false); - tempBot->SetHasHealedThisCycle(false); - tempBot->SetHealRotationTimer(0); - tempBot->ClearHealRotationMembers(); - tempBot->ClearHealRotationTargets(); - tempBot->SetNumHealRotationMembers(0); - tempBot->ClearHealRotationLeader(); - } - } - } + auto saylink = linker.GenerateLink(); + return saylink; } #endif diff --git a/zone/bot.h b/zone/bot.h index 42d0b7f65..3d45475a3 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -1,3 +1,21 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #ifndef BOT_H #define BOT_H @@ -7,9 +25,11 @@ #include "mob.h" #include "client.h" #include "pets.h" +#include "heal_rotation.h" #include "groups.h" #include "corpse.h" #include "zonedb.h" +#include "bot_database.h" #include "string_ids.h" #include "../common/misc_functions.h" #include "../common/global_define.h" @@ -18,6 +38,8 @@ #include +#define BOT_DEFAULT_FOLLOW_DISTANCE 184 + 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 @@ -27,8 +49,6 @@ const int DisciplineReuseStart = MaxSpellTimer + 1; const int MaxTimer = MaxSpellTimer + MaxDisciplineTimer; const int MaxStances = 7; const int MaxSpellTypes = 16; -const int MaxHealRotationMembers = 6; -const int MaxHealRotationTargets = 3; enum BotStanceType { BotStancePassive, @@ -37,9 +57,58 @@ enum BotStanceType { BotStanceReactive, BotStanceAggressive, BotStanceBurn, - BotStanceBurnAE + BotStanceBurnAE, + BotStanceUnknown }; +#define BOT_STANCE_COUNT 8 +#define VALIDBOTSTANCE(x) ((x >= (int)BotStancePassive && x <= (int)BotStanceBurnAE) ? ((BotStanceType)x) : (BotStanceUnknown)) + +static const std::string bot_stance_name[BOT_STANCE_COUNT] = { + "Passive", // 0 + "Balanced", // 1 + "Efficient", // 2 + "Reactive", // 3 + "Aggressive", // 4 + "Burn", // 5 + "BurnAE", // 6 + "Unknown" // 7 +}; + +static const char* GetBotStanceName(int stance_id) { return bot_stance_name[VALIDBOTSTANCE(stance_id)].c_str(); } + +#define VALIDBOTEQUIPSLOT(x) ((x >= EQEmu::legacy::EQUIPMENT_BEGIN && x <= EQEmu::legacy::EQUIPMENT_END) ? (x) : ((x == EQEmu::legacy::SlotPowerSource) ? (22) : (23))) + +static std::string bot_equip_slot_name[EQEmu::legacy::EQUIPMENT_SIZE + 2] = +{ + "Charm", // MainCharm + "Left Ear", // MainEar1 + "Head", // MainHead + "Face", // MainFace + "Right Ear", // MainEar2 + "Neck", // MainNeck + "Shoulders", // MainShoulders + "Arms", // MainArms + "Back", // MainBack + "Left Wrist", // MainWrist1 + "Right Wrist", // MainWrist2 + "Range", // MainRange + "Hands", // MainHands + "Primary Hand", // MainPrimary + "Secondary Hand", // MainSecondary + "Left Finger", // MainFinger1 + "Right Finger", // MainFinger2 + "Chest", // MainChest + "Legs", // MainLegs + "Feet", // MainFeet + "Waist", // MainWaist + "Ammo", // MainAmmo + "Power Source", // 22 (MainPowerSource = 9999) + "Unknown" +}; + +static const char* GetBotEquipSlotName(int slot_id) { return bot_equip_slot_name[VALIDBOTEQUIPSLOT(slot_id)].c_str(); } + enum SpellTypeIndex { SpellType_NukeIndex, SpellType_HealIndex, @@ -60,6 +129,7 @@ enum SpellTypeIndex { }; class Bot : public NPC { + friend class Mob; public: // Class enums enum BotfocusType { //focus types @@ -107,7 +177,7 @@ public: BotRoleRaidHealer }; - enum EqExpansions { + enum EqExpansions { // expansions are off..EQ should be '0' ExpansionNone, ExpansionEQ, ExpansionRoK, @@ -135,10 +205,10 @@ public: Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double totalPlayTime, uint32 lastZoneId, NPCType npcTypeData); //abstract virtual function implementations requird by base abstract class - virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill); - virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false); - virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, - ExtraAttackOptions *opts = nullptr); + virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill); + virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0); + virtual bool Attack(Mob* other, int Hand = EQEmu::legacy::SlotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, + ExtraAttackOptions *opts = nullptr, int special = 0); virtual bool HasRaid() { return (GetRaid() ? true : false); } virtual bool HasGroup() { return (GetGroup() ? true : false); } virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); } @@ -153,10 +223,10 @@ public: // Class Methods bool IsValidRaceClassCombo(); + static bool IsValidRaceClassCombo(uint16 r, uint8 c); bool IsValidName(); - bool IsBotNameAvailable(std::string* errorMessage); - bool DeleteBot(std::string* errorMessage); - void Spawn(Client* botCharacterOwner, std::string* errorMessage); + static bool IsValidName(std::string& name); + void Spawn(Client* botCharacterOwner); virtual void SetLevel(uint8 in_level, bool command = false); virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); virtual bool Process(); @@ -168,29 +238,30 @@ public: uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; } uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; } virtual float GetProcChances(float ProcBonus, uint16 hand); - virtual bool AvoidDamage(Mob* other, int32 &damage, bool CanRiposte); - virtual int GetMonkHandToHandDamage(void); - virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse); + virtual int GetHandToHandDamage(void); + virtual bool TryFinishingBlow(Mob *defender, EQEmu::skills::SkillType skillinuse); virtual void DoRiposte(Mob* defender); - inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(SkillOffense)) * 9 / 10); } + inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(EQEmu::skills::SkillOffense)) * 9 / 10); } inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; } uint32 GetTotalATK(); uint32 GetATKRating(); uint16 GetPrimarySkillValue(); - uint16 MaxSkill(SkillUseTypes skillid, uint16 class_, uint16 level) const; - inline uint16 MaxSkill(SkillUseTypes skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); } - virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false); + uint16 MaxSkill(EQEmu::skills::SkillType skillid, uint16 class_, uint16 level) const; + inline uint16 MaxSkill(EQEmu::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); } + virtual void DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance = false); virtual void TryBackstab(Mob *other,int ReuseTime = 10); virtual void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10); virtual void RogueAssassinate(Mob* other); virtual void DoClassAttacks(Mob *target, bool IsRiposte=false); - virtual bool TryHeadShot(Mob* defender, SkillUseTypes skillInUse); - virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false, int ReuseTime =0); - virtual void ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg); + virtual bool TryHeadShot(Mob* defender, EQEmu::skills::SkillType skillInUse); + virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod = 0, int16 focus = 0, bool CanRiposte = false, int ReuseTime = 0); + virtual void ApplySpecialAttackMod(EQEmu::skills::SkillType skill, int32 &dmg, int32 &mindmg); bool CanDoSpecialAttack(Mob *other); virtual int32 CheckAggroAmount(uint16 spellid); virtual void CalcBonuses(); - void CalcItemBonuses(); + void CalcItemBonuses(StatBonuses* newbon); + void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false, int rec_override = 0); + int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat); virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr); virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther); inline virtual bool IsPet() { return false; } @@ -198,14 +269,14 @@ public: virtual Mob* GetOwner(); virtual Mob* GetOwnerOrSelf(); inline virtual bool HasOwner() { return (GetBotOwner() ? true : false); } - virtual int32 CheckHealAggroAmount(uint16 spellid, uint32 heal_possible = 0); + virtual int32 CheckHealAggroAmount(uint16 spellid, Mob *target, uint32 heal_possible = 0); virtual int32 CalcMaxMana(); virtual void SetAttackTimer(); uint32 GetClassHPFactor(); virtual int32 CalcMaxHP(); - bool DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic); - bool DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic); - bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic); + bool DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic); + bool DoFinishedSpellSingleTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic); + bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, EQEmu::CastingSlot slot, bool &stopLogic); void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color); void Camp(bool databaseSave = true); virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false); @@ -226,18 +297,7 @@ public: bool HasOrMayGetAggro(); void SetDefaultBotStance(); void CalcChanceToCast(); - void CreateHealRotation( Mob* target, uint32 timer = 10000 ); - bool AddHealRotationMember( Bot* healer ); - bool RemoveHealRotationMember( Bot* healer ); - bool AddHealRotationTarget( Mob* target ); - //bool AddHealRotationTarget( const char *targetName, int index); - bool AddHealRotationTarget( Mob* target, int index); - bool RemoveHealRotationTarget( Mob* target ); - bool RemoveHealRotationTarget( int index); - void NotifyNextHealRotationMember( bool notifyNow = false ); - void ClearHealRotationLeader() { _healRotationLeader = 0; } - void ClearHealRotationMembers(); - void ClearHealRotationTargets(); + inline virtual int32 GetMaxStat(); inline virtual int32 GetMaxResist(); inline virtual int32 GetMaxSTR(); @@ -295,6 +355,9 @@ public: virtual bool AI_PursueCastCheck(); virtual bool AI_IdleCastCheck(); bool AIHealRotation(Mob* tar, bool useFastHeals); + bool GetPauseAI() { return _pauseAI; } + void SetPauseAI(bool pause_flag) { _pauseAI = pause_flag; } + // Mob AI Virtual Override Methods virtual void AI_Process(); @@ -310,65 +373,35 @@ public: virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration); virtual float GetAOERange(uint16 spell_id); virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100); - virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0); - virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr); + virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr); + virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, + uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr, uint32 aa_id = 0); virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar); virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster); - virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction); - virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF); - - // Bot Action Command Methods - bool MesmerizeTarget(Mob* target); - bool Bot_Command_Resist(int resisttype, int level); - bool Bot_Command_DireTarget(int diretype, Mob *target); - bool Bot_Command_CharmTarget(int charmtype, Mob *target); - bool Bot_Command_CalmTarget(Mob *target); - bool Bot_Command_RezzTarget(Mob *target); - bool Bot_Command_Cure(int curetype, int level); + virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQEmu::CastingSlot slot); + virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, uint32 aa_id = 0); // Bot Equipment & Inventory Class Methods void BotTradeSwapItem(Client* client, int16 lootSlot, const ItemInst* inst, const ItemInst* inst_swap, uint32 equipableSlots, std::string* errorMessage, bool swap = true); void BotTradeAddItem(uint32 id, const ItemInst* inst, int16 charges, uint32 equipableSlots, uint16 lootSlot, std::string* errorMessage, bool addToDb = true); void EquipBot(std::string* errorMessage); - bool CheckLoreConflict(const Item_Struct* item); - uint32 GetEquipmentColor(uint8 material_slot) const; - virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = m_inv.FindBrightestLightType(); m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); } + bool CheckLoreConflict(const EQEmu::ItemBase* item); + virtual void UpdateEquipmentLight() { m_Light.Type[EQEmu::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } - // Static Class Methods - static void SaveBotGroup(Group* botGroup, std::string botGroupName, std::string* errorMessage); - static void DeleteBotGroup(std::string botGroupName, std::string* errorMessage); - static std::list LoadBotGroup(std::string botGroupName, std::string* errorMessage); - static uint32 CanLoadBotGroup(uint32 botOwnerCharacterId, std::string botGroupName, std::string* errorMessage); - static uint32 GetBotGroupIdByBotGroupName(std::string botGroupName, std::string* errorMessage); - static uint32 GetBotGroupLeaderIdByBotGroupName(std::string botGroupName); - static std::list GetBotGroupListByBotOwnerCharacterId(uint32 botOwnerCharacterId, std::string* errorMessage); - static bool DoesBotGroupNameExist(std::string botGroupName); + // Static Class Methods //static void DestroyBotRaidObjects(Client* client); // Can be removed after bot raids are dumped - static uint32 GetBotIDByBotName(std::string botName); - static Bot* LoadBot(uint32 botID, std::string* errorMessage); - static std::list GetBotList(uint32 botOwnerCharacterID, std::string* errorMessage); - static void ProcessBotCommands(Client *c, const Seperator *sep); - static std::list ListSpawnedBots(uint32 characterID, std::string* errorMessage); - static uint32 SpawnedBotCount(uint32 botOwnerCharacterID, std::string* errorMessage); - static uint32 CreatedBotCount(uint32 botOwnerCharacterID, std::string* errorMessage); - static uint32 AllowedBotSpawns(uint32 botOwnerCharacterID, std::string* errorMessage); - static uint32 GetBotOwnerCharacterID(uint32 botID, std::string* errorMessage); + static Bot* LoadBot(uint32 botID); + static uint32 SpawnedBotCount(uint32 botOwnerCharacterID); static void LevelBotWithClient(Client* client, uint8 level, bool sendlvlapp); //static bool SetBotOwnerCharacterID(uint32 botID, uint32 botOwnerCharacterID, std::string* errorMessage); static std::string ClassIdToString(uint16 classId); static std::string RaceIdToString(uint16 raceId); static bool IsBotAttackAllowed(Mob* attacker, Mob* target, bool& hasRuleDefined); - static void BotGroupOrderFollow(Group* group, Client* client); - static void BotGroupOrderGuard(Group* group, Client* client); - static void BotGroupOrderAttack(Group* group, Mob* target, Client* client); - static void BotGroupSummon(Group* group, Client* client); static Bot* GetBotByBotClientOwnerAndBotName(Client* c, std::string botName); static void ProcessBotGroupInvite(Client* c, std::string botName); static void ProcessBotGroupDisband(Client* c, std::string botName); static void BotOrderCampAll(Client* c); - static void BotHealRotationsClear( Client* c ); static void ProcessBotInspectionRequest(Bot* inspectedBot, Client* client); - static std::list GetGroupedBotsByGroupId(uint32 groupId, std::string* errorMessage); static void LoadAndSpawnAllZonedBots(Client* botOwner); static bool GroupHasBot(Group* group); static Bot* GetFirstBotInGroup(Group* group); @@ -406,13 +439,10 @@ public: static BotSpell GetBestBotSpellForCure(Bot* botCaster, Mob* target); static BotSpell GetBestBotSpellForResistDebuff(Bot* botCaster, Mob* target); static NPCType CreateDefaultNPCTypeStructForBot(std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender); - static std::list GetBotsInHealRotation( Bot* leader ); // Static Bot Group Methods static bool AddBotToGroup(Bot* bot, Group* group); static bool RemoveBotFromGroup(Bot* bot, Group* group); - static bool BotGroupCreate(std::string botGroupLeaderName); - static bool BotGroupCreate(Bot* botGroupLeader); static bool GroupHasClass(Group* group, uint8 classId); static bool GroupHasClericClass(Group* group) { return GroupHasClass(group, CLERIC); } static bool GroupHasDruidClass(Group* group) { return GroupHasClass(group, DRUID); } @@ -440,30 +470,39 @@ public: uint8 GetChanceToCastBySpellType(uint16 spellType); bool IsGroupPrimaryHealer(); bool IsGroupPrimarySlower(); - bool IsBotCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN || GetClass() == NECROMANCER || GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == ENCHANTER); } - bool IsBotINTCaster() { return (GetClass() == NECROMANCER || GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == ENCHANTER); } - bool IsBotWISCaster() { return (GetClass() == CLERIC || GetClass() == DRUID || GetClass() == SHAMAN); } + bool IsBotCaster() { return IsCasterClass(GetClass()); } + bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); } + bool IsBotWISCaster() { return IsWISCasterClass(GetClass()); } bool CanHeal(); int GetRawACNoShield(int &shield_ac); - void LoadAAs(); - uint32 GetAA(uint32 aa_id); - void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon); bool GetHasBeenSummoned() { return _hasBeenSummoned; } const glm::vec3 GetPreSummonLocation() const { return m_PreSummonLocation; } - bool GetGroupMessagesOn() { return _groupMessagesOn; } - bool GetInHealRotation() { return _isInHealRotation; } - bool GetHealRotationActive() { return (GetInHealRotation() && _isHealRotationActive); } - bool GetHealRotationUseFastHeals() { return _healRotationUseFastHeals; } - bool GetHasHealedThisCycle() { return _hasHealedThisCycle; } - Mob* GetHealRotationTarget(); - Mob* GetHealRotationTarget(uint8 index); - Bot* GetHealRotationLeader(); - Bot* GetNextHealRotationMember(); - Bot* GetPrevHealRotationMember(); - uint8 GetNumHealRotationMembers () { return _numHealRotationMembers; } - uint32 GetHealRotationNextHealTime() { return _healRotationNextHeal; } - uint32 GetHealRotationTimer () { return _healRotationTimer; } - bool GetBardUseOutOfCombatSongs() { return _bardUseOutOfCombatSongs;} + + // 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(); + bool JoinHealRotationMemberPool(std::shared_ptr* heal_rotation); + bool LeaveHealRotationMemberPool(); + + bool IsHealRotationMember() { return (m_member_of_heal_rotation.use_count() && m_member_of_heal_rotation.get()); } + bool UseHealRotationFastHeals(); + bool UseHealRotationAdaptiveTargeting(); + + bool IsHealRotationActive(); + bool IsHealRotationReady(); + bool IsHealRotationCaster(); + bool HealRotationPokeTarget(); + Mob* HealRotationTarget(); + bool AdvanceHealRotation(bool use_interval = true); + + bool IsMyHealRotationSet(); + bool AmICastingForHealRotation(); + void SetMyCastingForHealRotation(bool flag = true); + + std::shared_ptr* MemberOfHealRotation() { return &m_member_of_heal_rotation; } + + bool GetAltOutOfCombatBehavior() { return _altoutofcombatbehavior;} + bool GetShowHelm() { return _showhelm; } inline virtual int32 GetAC() const { return AC; } inline virtual int32 GetSTR() const { return STR; } inline virtual int32 GetSTA() const { return STA; } @@ -530,42 +569,71 @@ public: // void SetBotOwnerCharacterID(uint32 botOwnerCharacterID) { _botOwnerCharacterID = botOwnerCharacterID; } void SetRangerAutoWeaponSelect(bool enable) { GetClass() == RANGER ? _rangerAutoWeaponSelect = enable : _rangerAutoWeaponSelect = false; } void SetBotRole(BotRoleType botRole) { _botRole = botRole; } - void SetBotStance(BotStanceType botStance) { _botStance = botStance; } + 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 SetGroupMessagesOn(bool groupMessagesOn) { _groupMessagesOn = groupMessagesOn; } - void SetInHealRotation( bool inRotation ) { _isInHealRotation = inRotation; } - void SetHealRotationActive( bool isActive ) { _isHealRotationActive = isActive; } - void SetHealRotationUseFastHeals( bool useFastHeals ) { _healRotationUseFastHeals = useFastHeals; } - void SetHasHealedThisCycle( bool hasHealed ) { _hasHealedThisCycle = hasHealed; } - void SetHealRotationLeader( Bot* leader ); - void SetNextHealRotationMember( Bot* healer ); - void SetPrevHealRotationMember( Bot* healer ); - void SetHealRotationNextHealTime( uint32 nextHealTime ) { _healRotationNextHeal = nextHealTime; } - void SetHealRotationTimer( uint32 timer ) { _healRotationTimer = timer; } - void SetNumHealRotationMembers( uint8 numMembers ) { _numHealRotationMembers = numMembers; } - void SetBardUseOutOfCombatSongs(bool useOutOfCombatSongs) { _bardUseOutOfCombatSongs = useOutOfCombatSongs;} + + void SetAltOutOfCombatBehavior(bool behavior_flag) { _altoutofcombatbehavior = behavior_flag;} + void SetShowHelm(bool showhelm) { _showhelm = showhelm; } + void SetBeardColor(uint8 value) { beardcolor = value; } + void SetBeard(uint8 value) { beard = value; } + void SetEyeColor1(uint8 value) { eyecolor1 = value; } + void SetEyeColor2(uint8 value) { eyecolor2 = value; } + void SetLuclinFace(uint8 value) { luclinface = value; } + void SetHairColor(uint8 value) { haircolor = value; } + void SetHairStyle(uint8 value) { hairstyle = value; } + void SetDrakkinDetails(uint32 value) { drakkin_details = value; } + void SetDrakkinHeritage(uint32 value) { drakkin_heritage = value; } + void SetDrakkinTattoo(uint32 value) { drakkin_tattoo = value; } + bool DyeArmor(int16 slot_id, uint32 rgb, bool all_flag = false, bool save_flag = true); + + std::string CreateSayLink(Client* botOwner, const char* message, const char* name); // Class Destructors virtual ~Bot(); + // Publicized protected functions + virtual void BotRangedAttack(Mob* other); + + // Publicized private functions + static NPCType FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender, float size, uint32 face, uint32 hairStyle, uint32 hairColor, uint32 eyeColor, uint32 eyeColor2, uint32 beardColor, uint32 beard, uint32 drakkinHeritage, uint32 drakkinTattoo, uint32 drakkinDetails, int32 hp, int32 mana, int32 mr, int32 cr, int32 dr, int32 fr, int32 pr, int32 corrup, int32 ac, uint32 str, uint32 sta, uint32 dex, uint32 agi, uint32 _int, uint32 wis, uint32 cha, uint32 attack); + void BotRemoveEquipItem(int slot); + void RemoveBotItemBySlot(uint32 slotID, std::string* errorMessage); + uint32 GetTotalPlayTime(); + + // New accessors for BotDatabase access + bool DeleteBot(); + uint32* GetTimers() { return timers; } + uint32 GetLastZoneID() { return _lastZoneId; } + int32 GetBaseAC() { return _baseAC; } + int32 GetBaseATK() { return _baseATK; } + int32 GetBaseSTR() { return _baseSTR; } + int32 GetBaseSTA() { return _baseSTA; } + int32 GetBaseCHA() { return _baseCHA; } + int32 GetBaseDEX() { return _baseDEX; } + int32 GetBaseINT() { return _baseINT; } + int32 GetBaseAGI() { return _baseAGI; } + int32 GetBaseWIS() { return _baseWIS; } + int32 GetBaseFR() { return _baseFR; } + int32 GetBaseCR() { return _baseCR; } + int32 GetBaseMR() { return _baseMR; } + int32 GetBasePR() { return _basePR; } + int32 GetBaseDR() { return _baseDR; } + int32 GetBaseCorrup() { return _baseCorrup; } + protected: virtual void PetAIProcess(); - static NPCType FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::string botLastName, uint8 botLevel, uint16 botRace, uint8 botClass, uint8 gender, float size, uint32 face, uint32 hairStyle, uint32 hairColor, uint32 eyeColor, uint32 eyeColor2, uint32 beardColor, uint32 beard, uint32 drakkinHeritage, uint32 drakkinTattoo, uint32 drakkinDetails, int32 hp, int32 mana, int32 mr, int32 cr, int32 dr, int32 fr, int32 pr, int32 corrup, int32 ac, uint32 str, uint32 sta, uint32 dex, uint32 agi, uint32 _int, uint32 wis, uint32 cha, uint32 attack); virtual void BotMeditate(bool isSitting); - virtual void BotRangedAttack(Mob* other); virtual bool CheckBotDoubleAttack(bool Triple = false); virtual int32 GetBotFocusEffect(BotfocusType bottype, uint16 spell_id); virtual int32 CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spell_id, bool best_focus=false); - virtual int32 CalcBotAAFocus(BotfocusType type, uint32 aa_ID, uint16 spell_id); + 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); - static void SetBotGuildMembership(uint32 botId, uint32 guildid, uint8 rank); - private: // Class Members uint32 _botID; @@ -603,22 +671,14 @@ private: bool _hasBeenSummoned; glm::vec3 m_PreSummonLocation; uint8 _spellCastingChances[MaxStances][MaxSpellTypes]; - bool _groupMessagesOn; - bool _isInHealRotation; - bool _isHealRotationActive; - bool _healRotationUseFastHeals; - bool _hasHealedThisCycle; - uint32 _healRotationTimer; - uint32 _healRotationNextHeal; - //char _healRotationTargets[MaxHealRotationTargets][64]; - uint16 _healRotationTargets[MaxHealRotationTargets]; - uint32 _healRotationLeader; - uint32 _healRotationMemberNext; - uint32 _healRotationMemberPrev; - uint8 _numHealRotationMembers; + + std::shared_ptr m_member_of_heal_rotation; + std::map botAAs; InspectMessage_Struct _botInspectMessage; - bool _bardUseOutOfCombatSongs; + bool _altoutofcombatbehavior; + bool _showhelm; + bool _pauseAI; // Private "base stats" Members int32 _baseMR; @@ -640,44 +700,25 @@ private: uint8 _baseGender; // Bots gender. Necessary to preserve the original value otherwise it can be changed by illusions. // Class Methods + void LoadAAs(); int32 acmod(); void GenerateBaseStats(); void GenerateAppearance(); void GenerateArmorClass(); int32 GenerateBaseHitPoints(); - void GenerateAABonuses(StatBonuses* newbon); int32 GenerateBaseManaPoints(); void GenerateSpecialAttacks(); void SetBotID(uint32 botID); // Private "Inventory" Methods - void GetBotItems(std::string* errorMessage, Inventory &inv); - void BotRemoveEquipItem(int slot); + void GetBotItems(Inventory &inv, std::string* errorMessage); void BotAddEquipItem(int slot, uint32 id); uint32 GetBotItemBySlot(uint32 slotID); - void RemoveBotItemBySlot(uint32 slotID, std::string* errorMessage); - void SetBotItemInSlot(uint32 slotID, uint32 itemID, const ItemInst* inst, std::string* errorMessage); - uint32 GetBotItemsCount(std::string* errorMessage); - uint32 GetTotalPlayTime(); - void SaveBuffs(); // Saves existing buffs to the database to persist zoning and camping - void LoadBuffs(); // Retrieves saved buffs from the database on spawning - void LoadPetBuffs(SpellBuff_Struct* petBuffs, uint32 botPetSaveId); - void SavePetBuffs(SpellBuff_Struct* petBuffs, uint32 botPetSaveId); - void LoadPetItems(uint32* petItems, uint32 botPetSaveId); - void SavePetItems(uint32* petItems, uint32 botPetSaveId); - void LoadPetStats(std::string* petName, uint32* petMana, uint32* petHitPoints, uint32* botPetId, uint32 botPetSaveId); - uint32 SavePetStats(std::string petName, uint32 petMana, uint32 petHitPoints, uint32 botPetId); - void LoadPet(); // Load and spawn bot pet if there is one - void SavePet(); // Save and depop bot pet if there is one - uint32 GetPetSaveId(); - void DeletePetBuffs(uint32 botPetSaveId); - void DeletePetItems(uint32 botPetSaveId); - void DeletePetStats(uint32 botPetSaveId); - void LoadGuildMembership(uint32* guildId, uint8* guildRank, std::string* guildName); - void LoadStance(); - void SaveStance(); - void LoadTimers(); - void SaveTimers(); + + // Private "Pet" Methods + bool LoadPet(); // Load and spawn bot pet if there is one + bool SavePet(); // Save and depop bot pet if there is one + bool DeletePet(); }; #endif // BOTS diff --git a/zone/bot_command.cpp b/zone/bot_command.cpp new file mode 100644 index 000000000..6b07bbdda --- /dev/null +++ b/zone/bot_command.cpp @@ -0,0 +1,7752 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + + To add a new bot command 3 things must be done: + + 1. At the bottom of bot_command.h you must add a prototype for it. + 2. Add the function in this file. + 3. In the bot_command_init function you must add a call to bot_command_add + for your function. + + Notes: If you want an alias for your bot command, add an entry to the + `bot_command_settings` table in your database. The access level you + set with bot_command_add is the default setting if the bot command isn't + listed in the `bot_command_settings` db table. + +*/ + +#ifdef BOTS + +#include +#include +#include +#include +#include +#include + +#ifdef _WINDOWS +#define strcasecmp _stricmp +#endif + +#include "../common/global_define.h" +#include "../common/eq_packet.h" +#include "../common/features.h" +#include "../common/guilds.h" +#include "../common/patches/patches.h" +#include "../common/ptimer.h" +#include "../common/rulesys.h" +#include "../common/serverinfo.h" +#include "../common/string_util.h" +#include "../common/say_link.h" +#include "../common/eqemu_logsys.h" + + +#include "bot_command.h" +#include "bot_database.h" +#include "guild_mgr.h" +#include "map.h" +#include "doors.h" +#include "pathing.h" +#include "qglobals.h" +#include "queryserv.h" +#include "quest_parser_collection.h" +#include "string_ids.h" +#include "titles.h" +#include "water_map.h" +#include "worldserver.h" + +extern QueryServ* QServ; +extern WorldServer worldserver; +extern TaskManager *taskmanager; +void CatchSignal(int sig_num); + + +/* + * file-scope helper objects + */ +namespace +{ +//#define BCSTSPELLDUMP // only needed if you're adding/tailoring bot command spells and need a file dump + +#define m_message CC_WhiteSmoke +#define m_action CC_Yellow +#define m_note CC_Gray +#define m_usage CC_Cyan +#define m_fail CC_Red +#define m_unknown CC_Magenta + +#define HP_RATIO_DELTA 5.0f + + enum { EffectIDFirst = 1, EffectIDLast = 12 }; + +#define CLASSIDTOINDEX(x) ((x >= WARRIOR && x <= BERSERKER) ? (x - 1) : (0)) +#define EFFECTIDTOINDEX(x) ((x >= EffectIDFirst && x <= EffectIDLast) ? (x - 1) : (0)) +#define AILMENTIDTOINDEX(x) ((x >= BCEnum::AT_Blindness && x <= BCEnum::AT_Corruption) ? (x - 1) : (0)) +#define RESISTANCEIDTOINDEX(x) ((x >= BCEnum::RT_Fire && x <= BCEnum::RT_Corruption) ? (x - 1) : (0)) + + // ActionableTarget action_type +#define FRIENDLY true +#define ENEMY false +} + +bcst_map bot_command_spells; +bcst_required_bot_classes_map required_bots_map; +bcst_required_bot_classes_map_by_class required_bots_map_by_class; + + +class BCSpells +{ +public: + // + static void Load() { + bot_command_spells.clear(); + bcst_levels_map bot_levels_map; + + for (int i = BCEnum::SpellTypeFirst; i <= BCEnum::SpellTypeLast; ++i) { + bot_command_spells[static_cast(i)]; + bot_levels_map[static_cast(i)]; + } + + for (int spell_id = 2; spell_id < SPDAT_RECORDS; ++spell_id) { + if (spells[spell_id].player_1[0] == '\0') + continue; + if (spells[spell_id].targettype != ST_Target && spells[spell_id].CastRestriction != 0) // watch + continue; + + auto target_type = BCEnum::TT_None; + switch (spells[spell_id].targettype) { + case ST_GroupTeleport: + target_type = BCEnum::TT_GroupV1; + break; + case ST_AECaster: + // Disabled until bot code works correctly + //target_type = BCEnum::TT_AECaster; + break; + case ST_AEBard: + // Disabled until bot code works correctly + //target_type = BCEnum::TT_AEBard; + break; + case ST_Target: + switch (spells[spell_id].CastRestriction) { + case 0: + target_type = BCEnum::TT_Single; + break; + case 104: + target_type = BCEnum::TT_Animal; + break; + case 105: + target_type = BCEnum::TT_Plant; + break; + case 118: + target_type = BCEnum::TT_Summoned; + break; + case 120: + target_type = BCEnum::TT_Undead; + break; + default: + break; + } + break; + case ST_Self: + target_type = BCEnum::TT_Self; + break; + case ST_AETarget: + // Disabled until bot code works correctly + //target_type = BCEnum::TT_AETarget; + break; + case ST_Animal: + target_type = BCEnum::TT_Animal; + break; + case ST_Undead: + target_type = BCEnum::TT_Undead; + break; + case ST_Summoned: + target_type = BCEnum::TT_Summoned; + break; + case ST_Corpse: + target_type = BCEnum::TT_Corpse; + break; + case ST_Plant: + target_type = BCEnum::TT_Plant; + break; + case ST_Group: + target_type = BCEnum::TT_GroupV2; + break; + default: + break; + } + if (target_type == BCEnum::TT_None) + continue; + + uint8 class_levels[16] = { 0 }; + bool player_spell = false; + for (int class_type = WARRIOR; class_type <= BERSERKER; ++class_type) { + int class_index = CLASSIDTOINDEX(class_type); + if (spells[spell_id].classes[class_index] == 0 || spells[spell_id].classes[class_index] > HARD_LEVEL_CAP) + continue; + + class_levels[class_index] = spells[spell_id].classes[class_index]; + player_spell = true; + } + if (!player_spell) + continue; + + STBaseEntry* entry_prototype = nullptr; + while (true) { + switch (spells[spell_id].effectid[EFFECTIDTOINDEX(1)]) { + case SE_BindAffinity: + entry_prototype = new STBaseEntry(BCEnum::SpT_BindAffinity); + break; + case SE_Charm: + if (spells[spell_id].SpellAffectIndex != 12) + break; + entry_prototype = new STCharmEntry(); + if (spells[spell_id].ResistDiff <= -1000) + entry_prototype->SafeCastToCharm()->dire = true; + break; + case SE_Teleport: + entry_prototype = new STDepartEntry; + entry_prototype->SafeCastToDepart()->single = !BCSpells::IsGroupType(target_type); + break; + case SE_Succor: + if (!strcmp(spells[spell_id].teleport_zone, "same")) { + entry_prototype = new STEscapeEntry; + } + else { + entry_prototype = new STDepartEntry; + entry_prototype->SafeCastToDepart()->single = !BCSpells::IsGroupType(target_type); + } + break; + case SE_Translocate: + if (spells[spell_id].teleport_zone[0] == '\0') { + entry_prototype = new STSendHomeEntry(); + entry_prototype->SafeCastToSendHome()->group = BCSpells::IsGroupType(target_type); + } + else { + entry_prototype = new STDepartEntry; + entry_prototype->SafeCastToDepart()->single = !BCSpells::IsGroupType(target_type); + } + break; + case SE_ModelSize: + if (spells[spell_id].base[EFFECTIDTOINDEX(1)] > 100) { + entry_prototype = new STSizeEntry; + entry_prototype->SafeCastToSize()->size_type = BCEnum::SzT_Enlarge; + } + else if (spells[spell_id].base[EFFECTIDTOINDEX(1)] > 0 && spells[spell_id].base[EFFECTIDTOINDEX(1)] < 100) { + entry_prototype = new STSizeEntry; + entry_prototype->SafeCastToSize()->size_type = BCEnum::SzT_Reduce; + } + break; + case SE_Identify: + entry_prototype = new STBaseEntry(BCEnum::SpT_Identify); + break; + case SE_Invisibility: + if (spells[spell_id].SpellAffectIndex != 9) + break; + entry_prototype = new STInvisibilityEntry; + entry_prototype->SafeCastToInvisibility()->invis_type = BCEnum::IT_Living; + break; + case SE_SeeInvis: + if (spells[spell_id].SpellAffectIndex != 5) + break; + entry_prototype = new STInvisibilityEntry; + entry_prototype->SafeCastToInvisibility()->invis_type = BCEnum::IT_See; + break; + case SE_InvisVsUndead: + if (spells[spell_id].SpellAffectIndex != 9) + break; + entry_prototype = new STInvisibilityEntry; + entry_prototype->SafeCastToInvisibility()->invis_type = BCEnum::IT_Undead; + break; + case SE_InvisVsAnimals: + if (spells[spell_id].SpellAffectIndex != 9) + break; + entry_prototype = new STInvisibilityEntry; + entry_prototype->SafeCastToInvisibility()->invis_type = BCEnum::IT_Animal; + break; + case SE_Mez: + if (spells[spell_id].SpellAffectIndex != 12) + break; + entry_prototype = new STBaseEntry(BCEnum::SpT_Mesmerize); + break; + case SE_Revive: + if (spells[spell_id].SpellAffectIndex != 1) + break; + entry_prototype = new STResurrectEntry(); + entry_prototype->SafeCastToResurrect()->aoe = BCSpells::IsCasterCentered(target_type); + break; + case SE_Rune: + if (spells[spell_id].SpellAffectIndex != 2) + break; + entry_prototype = new STBaseEntry(BCEnum::SpT_Rune); + break; + case SE_SummonCorpse: + entry_prototype = new STBaseEntry(BCEnum::SpT_SummonCorpse); + break; + case SE_WaterBreathing: + entry_prototype = new STBaseEntry(BCEnum::SpT_WaterBreathing); + break; + default: + break; + } + if (entry_prototype) + break; + + switch (spells[spell_id].effectid[EFFECTIDTOINDEX(2)]) { + case SE_Succor: + entry_prototype = new STEscapeEntry; + std::string is_lesser = spells[spell_id].name; + if (is_lesser.find("Lesser") != std::string::npos) + entry_prototype->SafeCastToEscape()->lesser = true; + break; + } + if (entry_prototype) + break; + + switch (spells[spell_id].effectid[EFFECTIDTOINDEX(3)]) { + case SE_Lull: + entry_prototype = new STBaseEntry(BCEnum::SpT_Lull); + break; + case SE_Levitate: // needs more criteria + entry_prototype = new STBaseEntry(BCEnum::SpT_Levitation); + break; + default: + break; + } + if (entry_prototype) + break; + + while (spells[spell_id].typedescnum == 27) { + if (!spells[spell_id].goodEffect) + break; + if (spells[spell_id].skill != EQEmu::skills::SkillOffense && spells[spell_id].skill != EQEmu::skills::SkillDefense) + break; + + entry_prototype = new STStanceEntry(); + if (spells[spell_id].skill == EQEmu::skills::SkillOffense) + entry_prototype->SafeCastToStance()->stance_type = BCEnum::StT_Aggressive; + else + entry_prototype->SafeCastToStance()->stance_type = BCEnum::StT_Defensive; + + break; + } + if (entry_prototype) + break; + + switch (spells[spell_id].SpellAffectIndex) { + case 1: { + bool valid_spell = false; + entry_prototype = new STCureEntry; + + for (int i = EffectIDFirst; i <= EffectIDLast; ++i) { + int effect_index = EFFECTIDTOINDEX(i); + if (spells[spell_id].effectid[effect_index] != SE_Blind && spells[spell_id].base[effect_index] >= 0) + continue; + else if (spells[spell_id].effectid[effect_index] == SE_Blind && !spells[spell_id].goodEffect) + continue; + + switch (spells[spell_id].effectid[effect_index]) { + case SE_Blind: + entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Blindness)] += spells[spell_id].base[effect_index]; + break; + case SE_DiseaseCounter: + entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Disease)] += spells[spell_id].base[effect_index]; + break; + case SE_PoisonCounter: + entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Poison)] += spells[spell_id].base[effect_index]; + break; + case SE_CurseCounter: + entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Curse)] += spells[spell_id].base[effect_index]; + break; + case SE_CorruptionCounter: + entry_prototype->SafeCastToCure()->cure_value[AILMENTIDTOINDEX(BCEnum::AT_Corruption)] += spells[spell_id].base[effect_index]; + break; + default: + continue; + } + entry_prototype->SafeCastToCure()->cure_total += spells[spell_id].base[effect_index]; + valid_spell = true; + } + if (!valid_spell) { + safe_delete(entry_prototype); + entry_prototype = nullptr; + } + + break; + } + case 2: { + bool valid_spell = false; + entry_prototype = new STResistanceEntry; + + for (int i = EffectIDFirst; i <= EffectIDLast; ++i) { + int effect_index = EFFECTIDTOINDEX(i); + if (spells[spell_id].base[effect_index] <= 0) + continue; + + switch (spells[spell_id].effectid[effect_index]) { + case SE_ResistFire: + entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Fire)] += spells[spell_id].base[effect_index]; + break; + case SE_ResistCold: + entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Cold)] += spells[spell_id].base[effect_index]; + break; + case SE_ResistPoison: + entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Poison)] += spells[spell_id].base[effect_index]; + break; + case SE_ResistDisease: + entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Disease)] += spells[spell_id].base[effect_index]; + break; + case SE_ResistMagic: + entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Magic)] += spells[spell_id].base[effect_index]; + break; + case SE_ResistCorruption: + entry_prototype->SafeCastToResistance()->resist_value[RESISTANCEIDTOINDEX(BCEnum::RT_Corruption)] += spells[spell_id].base[effect_index]; + break; + default: + continue; + } + entry_prototype->SafeCastToResistance()->resist_total += spells[spell_id].base[effect_index]; + valid_spell = true; + } + if (!valid_spell) { + safe_delete(entry_prototype); + entry_prototype = nullptr; + } + + break; + } + case 7: + case 10: + if (spells[spell_id].effectdescnum != 65) + break; + entry_prototype = new STMovementSpeedEntry(); + entry_prototype->SafeCastToMovementSpeed()->group = BCSpells::IsGroupType(target_type); + break; + default: + break; + } + if (entry_prototype) + break; + + break; + } + if (!entry_prototype) + continue; + + if (target_type == BCEnum::TT_Self && (entry_prototype->BCST() != BCEnum::SpT_Stance && entry_prototype->BCST() != BCEnum::SpT_SummonCorpse)) { +#ifdef BCSTSPELLDUMP + Log.Out(Logs::General, Logs::Error, "DELETING entry_prototype (primary clause) - name: %s, target_type: %s, BCST: %s", + spells[spell_id].name, BCEnum::TargetTypeEnumToString(target_type).c_str(), BCEnum::SpellTypeEnumToString(entry_prototype->BCST()).c_str()); +#endif + safe_delete(entry_prototype); + continue; + } + if (entry_prototype->BCST() == BCEnum::SpT_Stance && target_type != BCEnum::TT_Self) { +#ifdef BCSTSPELLDUMP + Log.Out(Logs::General, Logs::Error, "DELETING entry_prototype (secondary clause) - name: %s, BCST: %s, target_type: %s", + spells[spell_id].name, BCEnum::SpellTypeEnumToString(entry_prototype->BCST()).c_str(), BCEnum::TargetTypeEnumToString(target_type).c_str()); +#endif + safe_delete(entry_prototype); + continue; + } + + assert(entry_prototype->BCST() != BCEnum::SpT_None); + + entry_prototype->spell_id = spell_id; + entry_prototype->target_type = target_type; + + bcst_levels& bot_levels = bot_levels_map[entry_prototype->BCST()]; + for (int class_type = WARRIOR; class_type <= BERSERKER; ++class_type) { + int class_index = CLASSIDTOINDEX(class_type); + if (!class_levels[class_index]) + continue; + + STBaseEntry* spell_entry = nullptr; + switch (entry_prototype->BCST()) { + case BCEnum::SpT_Charm: + if (entry_prototype->IsCharm()) + spell_entry = new STCharmEntry(entry_prototype->SafeCastToCharm()); + break; + case BCEnum::SpT_Cure: + if (entry_prototype->IsCure()) + spell_entry = new STCureEntry(entry_prototype->SafeCastToCure()); + break; + case BCEnum::SpT_Depart: + if (entry_prototype->IsDepart()) + spell_entry = new STDepartEntry(entry_prototype->SafeCastToDepart()); + break; + case BCEnum::SpT_Escape: + if (entry_prototype->IsEscape()) + spell_entry = new STEscapeEntry(entry_prototype->SafeCastToEscape()); + break; + case BCEnum::SpT_Invisibility: + if (entry_prototype->IsInvisibility()) + spell_entry = new STInvisibilityEntry(entry_prototype->SafeCastToInvisibility()); + break; + case BCEnum::SpT_MovementSpeed: + if (entry_prototype->IsMovementSpeed()) + spell_entry = new STMovementSpeedEntry(entry_prototype->SafeCastToMovementSpeed()); + break; + case BCEnum::SpT_Resistance: + if (entry_prototype->IsResistance()) + spell_entry = new STResistanceEntry(entry_prototype->SafeCastToResistance()); + break; + case BCEnum::SpT_Resurrect: + if (entry_prototype->IsResurrect()) + spell_entry = new STResurrectEntry(entry_prototype->SafeCastToResurrect()); + break; + case BCEnum::SpT_SendHome: + if (entry_prototype->IsSendHome()) + spell_entry = new STSendHomeEntry(entry_prototype->SafeCastToSendHome()); + break; + case BCEnum::SpT_Size: + if (entry_prototype->IsSize()) + spell_entry = new STSizeEntry(entry_prototype->SafeCastToSize()); + break; + case BCEnum::SpT_Stance: + if (entry_prototype->IsStance()) + spell_entry = new STStanceEntry(entry_prototype->SafeCastToStance()); + break; + default: + spell_entry = new STBaseEntry(entry_prototype); + break; + } + + assert(spell_entry); + + spell_entry->caster_class = class_type; + spell_entry->spell_level = class_levels[class_index]; + + bot_command_spells[spell_entry->BCST()].push_back(spell_entry); + + if (bot_levels.find(class_type) == bot_levels.end() || bot_levels[class_type] > class_levels[class_index]) + bot_levels[class_type] = class_levels[class_index]; + } + + delete(entry_prototype); + } + + remove_inactive(); + order_all(); + load_teleport_zone_names(); + build_strings(bot_levels_map); + status_report(); + +#ifdef BCSTSPELLDUMP + spell_dump(); +#endif + + } + + static void Unload() { + for (auto map_iter : bot_command_spells) { + if (map_iter.second.empty()) + continue; + for (auto list_iter : map_iter.second) + safe_delete(list_iter); + map_iter.second.clear(); + } + bot_command_spells.clear(); + required_bots_map.clear(); + required_bots_map_by_class.clear(); + } + + static bool IsCasterCentered(BCEnum::TType target_type) { + switch (target_type) { + case BCEnum::TT_AECaster: + case BCEnum::TT_AEBard: + return true; + default: + return false; + } + } + + static bool IsGroupType(BCEnum::TType target_type) { + switch (target_type) { + case BCEnum::TT_GroupV1: + case BCEnum::TT_GroupV2: + return true; + default: + return false; + } + } + +private: + static void remove_inactive() { + if (bot_command_spells.empty()) + return; + + for (auto map_iter = bot_command_spells.begin(); map_iter != bot_command_spells.end(); ++map_iter) { + if (map_iter->second.empty()) + continue; + + bcst_list* spells_list = &map_iter->second; + bcst_list* removed_spells_list = new bcst_list; + + spells_list->remove(nullptr); + spells_list->remove_if([removed_spells_list](STBaseEntry* l) { + if (l->spell_id < 2 || l->spell_id >= SPDAT_RECORDS || strlen(spells[l->spell_id].name) < 3) { + removed_spells_list->push_back(l); + return true; + } + else { + return false; + } + }); + + for (auto del_iter : *removed_spells_list) + safe_delete(del_iter); + removed_spells_list->clear(); + + if (RuleI(Bots, CommandSpellRank) == 1) { + spells_list->sort([](STBaseEntry* l, STBaseEntry* r) { + if (spells[l->spell_id].spellgroup < spells[r->spell_id].spellgroup) + return true; + if (spells[l->spell_id].spellgroup == spells[r->spell_id].spellgroup && l->caster_class < r->caster_class) + return true; + if (spells[l->spell_id].spellgroup == spells[r->spell_id].spellgroup && l->caster_class == r->caster_class && spells[l->spell_id].rank < spells[r->spell_id].rank) + return true; + + return false; + }); + spells_list->unique([removed_spells_list](STBaseEntry* l, STBaseEntry* r) { + std::string r_name = spells[r->spell_id].name; + if (spells[l->spell_id].spellgroup == spells[r->spell_id].spellgroup && l->caster_class == r->caster_class && spells[l->spell_id].rank < spells[r->spell_id].rank) { + removed_spells_list->push_back(r); + return true; + } + + return false; + }); + + for (auto del_iter : *removed_spells_list) + safe_delete(del_iter); + removed_spells_list->clear(); + } + + if (RuleI(Bots, CommandSpellRank) == 2) { + spells_list->remove_if([removed_spells_list](STBaseEntry* l) { + std::string l_name = spells[l->spell_id].name; + if (spells[l->spell_id].rank == 10) { + removed_spells_list->push_back(l); + return true; + } + if (l_name.find("III") == (l_name.size() - 3)) { + removed_spells_list->push_back(l); + return true; + } + if (l_name.find("III ") == (l_name.size() - 4)) { + removed_spells_list->push_back(l); + return true; + } + + return false; + }); + + for (auto del_iter : *removed_spells_list) + safe_delete(del_iter); + removed_spells_list->clear(); + } + + // needs rework + if (RuleI(Bots, CommandSpellRank) == 2 || RuleI(Bots, CommandSpellRank) == 3) { + spells_list->sort([](STBaseEntry* l, STBaseEntry* r) { + if (spells[l->spell_id].spellgroup < spells[r->spell_id].spellgroup) + return true; + if (spells[l->spell_id].spellgroup == spells[r->spell_id].spellgroup && l->caster_class < r->caster_class) + return true; + if (spells[l->spell_id].spellgroup == spells[r->spell_id].spellgroup && l->caster_class == r->caster_class && spells[l->spell_id].rank > spells[r->spell_id].rank) + return true; + + return false; + }); + spells_list->unique([removed_spells_list](STBaseEntry* l, STBaseEntry* r) { + std::string l_name = spells[l->spell_id].name; + if (spells[l->spell_id].spellgroup == spells[r->spell_id].spellgroup && l->caster_class == r->caster_class && spells[l->spell_id].rank > spells[r->spell_id].rank) { + removed_spells_list->push_back(r); + return true; + } + + return false; + }); + + for (auto del_iter : *removed_spells_list) + safe_delete(del_iter); + removed_spells_list->clear(); + } + + safe_delete(removed_spells_list); + } + } + + static void order_all() { + // Example of a macro'd lambda using anonymous property dereference: + // #define XXX(p) ([](const <_Ty>* l, const <_Ty>* r) { return (l->p < r->p); }) + + +#define LT_STBASE(l, r, p) (l->p < r->p) +#define LT_STCHARM(l, r, p) (l->SafeCastToCharm()->p < r->SafeCastToCharm()->p) +#define LT_STCURE(l, r, p) (l->SafeCastToCure()->p < r->SafeCastToCure()->p) +#define LT_STCURE_VAL_ID(l, r, p, ctid) (l->SafeCastToCure()->p[AILMENTIDTOINDEX(ctid)] < r->SafeCastToCure()->p[AILMENTIDTOINDEX(ctid)]) +#define LT_STDEPART(l, r, p) (l->SafeCastToDepart()->p < r->SafeCastToDepart()->p) +#define LT_STESCAPE(l, r, p) (l->SafeCastToEscape()->p < r->SafeCastToEscape()->p) +#define LT_STINVISIBILITY(l, r, p) (l->SafeCastToInvisibility()->p < r->SafeCastToInvisibility()->p) +#define LT_STRESISTANCE(l, r, p) (l->SafeCastToResistance()->p < r->SafeCastToResistance()->p) +#define LT_STRESISTANCE_VAL_ID(l, r, p, rtid) (l->SafeCastToResistance()->p[RESISTANCEIDTOINDEX(rtid)] < r->SafeCastToResistance()->p[RESISTANCEIDTOINDEX(rtid)) +#define LT_STSTANCE(l, r, p) (l->SafeCastToStance()->p < r->SafeCastToStance()->p) +#define LT_SPELLS(l, r, p) (spells[l->spell_id].p < spells[r->spell_id].p) +#define LT_SPELLS_EFFECT_ID(l, r, p, eid) (spells[l->spell_id].p[EFFECTIDTOINDEX(eid)] < spells[r->spell_id].p[EFFECTIDTOINDEX(eid)]) +#define LT_SPELLS_STR(l, r, s) (strcasecmp(spells[l->spell_id].s, spells[r->spell_id].s) < 0) + +#define EQ_STBASE(l, r, p) (l->p == r->p) +#define EQ_STCHARM(l, r, p) (l->SafeCastToCharm()->p == r->SafeCastToCharm()->p) +#define EQ_STCURE(l, r, p) (l->SafeCastToCure()->p == r->SafeCastToCure()->p) +#define EQ_STCURE_VAL_ID(l, r, p, ctid) (l->SafeCastToCure()->p[AILMENTIDTOINDEX(ctid)] == r->SafeCastToCure()->p[AILMENTIDTOINDEX(ctid)]) +#define EQ_STDEPART(l, r, p) (l->SafeCastToDepart()->p == r->SafeCastToDepart()->p) +#define EQ_STESCAPE(l, r, p) (l->SafeCastToEscape()->p == r->SafeCastToEscape()->p) +#define EQ_STINVISIBILITY(l, r, p) (l->SafeCastToInvisibility()->p == r->SafeCastToInvisibility()->p) +#define EQ_STRESISTANCE(l, r, p) (l->SafeCastToResistance()->p == r->SafeCastToResistance()->p) +#define EQ_STRESISTANCE_VAL_ID(l, r, p, rtid) (l->SafeCastToResistance()->p[RESISTANCEIDTOINDEX(rtid)] == r->SafeCastToResistance()->p[RESISTANCEIDTOINDEX(rtid)) +#define EQ_STSTANCE(l, r, p) (l->SafeCastToStance()->p == r->SafeCastToStance()->p) +#define EQ_SPELLS(l, r, p) (spells[l->spell_id].p == spells[r->spell_id].p) +#define EQ_SPELLS_EFFECT_ID(l, r, p, eid) (spells[l->spell_id].p[EFFECTIDTOINDEX(eid)] == spells[r->spell_id].p[EFFECTIDTOINDEX(eid)]) +#define EQ_SPELLS_STR(l, r, s) (strcasecmp(spells[l->spell_id].s, spells[r->spell_id].s) == 0) + +#define GT_STBASE(l, r, p) (l->p > r->p) +#define GT_STCHARM(l, r, p) (l->SafeCastToCharm()->p > r->SafeCastToCharm()->p) +#define GT_STCURE(l, r, p) (l->SafeCastToCure()->p > r->SafeCastToCure()->p) +#define GT_STCURE_VAL_ID(l, r, p, ctid) (l->SafeCastToCure()->p[AILMENTIDTOINDEX(ctid)] > r->SafeCastToCure()->p[AILMENTIDTOINDEX(ctid)]) +#define GT_STDEPART(l, r, p) (l->SafeCastToDepart()->p > r->SafeCastToDepart()->p) +#define GT_STESCAPE(l, r, p) (l->SafeCastToEscape()->p > r->SafeCastToEscape()->p) +#define GT_STINVISIBILITY(l, r, p) (l->SafeCastToInvisibility()->p > r->SafeCastToInvisibility()->p) +#define GT_STRESISTANCE(l, r, p) (l->SafeCastToResistance()->p > r->SafeCastToResistance()->p) +#define GT_STRESISTANCE_VAL_ID(l, r, p, rtid) (l->SafeCastToResistance()->p[RESISTANCEIDTOINDEX(rtid)] > r->SafeCastToResistance()->p[RESISTANCEIDTOINDEX(rtid)) +#define GT_STSTANCE(l, r, p) (l->SafeCastToStance()->p > r->SafeCastToStance()->p) +#define GT_SPELLS(l, r, p) (spells[l->spell_id].p > spells[r->spell_id].p) +#define GT_SPELLS_EFFECT_ID(l, r, p, eid) (spells[l->spell_id].p[EFFECTIDTOINDEX(eid)] > spells[r->spell_id].p[EFFECTIDTOINDEX(eid)]) +#define GT_SPELLS_STR(l, r, s) (strcasecmp(spells[l->spell_id].s, spells[r->spell_id].s) > 0) + + + for (auto map_iter = bot_command_spells.begin(); map_iter != bot_command_spells.end(); ++map_iter) { + if (map_iter->second.size() < 2) + continue; + + auto spell_type = map_iter->first; + bcst_list* spell_list = &map_iter->second; + switch (spell_type) { + case BCEnum::SpT_BindAffinity: + if (RuleB(Bots, PreferNoManaCommandSpells)) { + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_SPELLS(l, r, mana)) + return true; + if (EQ_SPELLS(l, r, mana) && LT_STBASE(l, r, target_type)) + return true; + if (EQ_SPELLS(l, r, mana) && EQ_STBASE(l, r, target_type) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_SPELLS(l, r, mana) && EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + } + else { + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_STBASE(l, r, target_type)) + return true; + if (EQ_STBASE(l, r, target_type) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + } + continue; + case BCEnum::SpT_Charm: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_SPELLS(l, r, ResistDiff)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && LT_STBASE(l, r, target_type)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && EQ_STBASE(l, r, target_type) && GT_SPELLS_EFFECT_ID(l, r, max, 1)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, max, 1) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, max, 1) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Cure: // per-use sorting in command handler + spell_list->sort([](STBaseEntry* l, STBaseEntry* r) { + if (l->spell_id < r->spell_id) + return true; + if (l->spell_id == r->spell_id && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Depart: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_STBASE(l, r, target_type)) + return true; + if (EQ_STBASE(l, r, target_type) && LT_STBASE(l, r, caster_class)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, caster_class) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, caster_class) && EQ_STBASE(l, r, spell_level) && LT_SPELLS_STR(l, r, name)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Escape: + spell_list->sort([](STBaseEntry* l, STBaseEntry* r) { + if (LT_STESCAPE(l, r, lesser)) + return true; + if (EQ_STESCAPE(l, r, lesser) && LT_STBASE(l, r, target_type)) + return true; + if (EQ_STESCAPE(l, r, lesser) && EQ_STBASE(l, r, target_type) && GT_STBASE(l, r, spell_level)) + return true; + if (EQ_STESCAPE(l, r, lesser) && EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Identify: + if (RuleB(Bots, PreferNoManaCommandSpells)) { + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_SPELLS(l, r, mana)) + return true; + if (EQ_SPELLS(l, r, mana) && LT_STBASE(l, r, target_type)) + return true; + if (EQ_SPELLS(l, r, mana) && EQ_STBASE(l, r, target_type) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_SPELLS(l, r, mana) && EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + } + else { + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_STBASE(l, r, target_type)) + return true; + if (EQ_STBASE(l, r, target_type) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + } + continue; + case BCEnum::SpT_Invisibility: + spell_list->sort([](STBaseEntry* l, STBaseEntry* r) { + if (LT_STINVISIBILITY(l, r, invis_type)) + return true; + if (EQ_STINVISIBILITY(l, r, invis_type) && LT_STBASE(l, r, target_type)) + return true; + if (EQ_STINVISIBILITY(l, r, invis_type) && EQ_STBASE(l, r, target_type) && GT_STBASE(l, r, spell_level)) + return true; + if (EQ_STINVISIBILITY(l, r, invis_type) && EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + return false; + }); + continue; + case BCEnum::SpT_Levitation: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_STBASE(l, r, target_type)) + return true; + if (EQ_STBASE(l, r, target_type) && LT_SPELLS(l, r, zonetype)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS(l, r, zonetype) && GT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS(l, r, zonetype) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Lull: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_SPELLS(l, r, ResistDiff)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && LT_STBASE(l, r, target_type)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && EQ_STBASE(l, r, target_type) && GT_SPELLS_EFFECT_ID(l, r, max, 3)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, max, 3) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, max, 3) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Mesmerize: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (GT_SPELLS(l, r, ResistDiff)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && LT_STBASE(l, r, target_type)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && EQ_STBASE(l, r, target_type) && GT_SPELLS_EFFECT_ID(l, r, max, 1)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, max, 1) && GT_STBASE(l, r, spell_level)) + return true; + if (EQ_SPELLS(l, r, ResistDiff) && EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, max, 1) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_MovementSpeed: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_STBASE(l, r, target_type)) + return true; + if (EQ_STBASE(l, r, target_type) && GT_SPELLS_EFFECT_ID(l, r, base, 2)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, base, 2) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, base, 2) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Resistance: // per-use sorting in command handler + spell_list->sort([](STBaseEntry* l, STBaseEntry* r) { + if (l->spell_id < r->spell_id) + return true; + if (l->spell_id == r->spell_id && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Resurrect: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (GT_SPELLS_EFFECT_ID(l, r, base, 1)) + return true; + if (EQ_SPELLS_EFFECT_ID(l, r, base, 1) && LT_STBASE(l, r, target_type)) + return true; + if (EQ_SPELLS_EFFECT_ID(l, r, base, 1) && EQ_STBASE(l, r, target_type) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_SPELLS_EFFECT_ID(l, r, base, 1) && EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Rune: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_STBASE(l, r, target_type)) + return true; + if (EQ_STBASE(l, r, target_type) && GT_SPELLS_EFFECT_ID(l, r, max, 1)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, max, 1) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, max, 1) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_SendHome: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_STBASE(l, r, target_type)) + return true; + if (EQ_STBASE(l, r, target_type) && GT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_Size: + spell_list->sort([](STBaseEntry* l, STBaseEntry* r) { + if (LT_STBASE(l, r, target_type)) + return true; + + auto l_size_type = l->SafeCastToSize()->size_type; + auto r_size_type = r->SafeCastToSize()->size_type; + if (l_size_type < r_size_type) + return true; + if (l_size_type == BCEnum::SzT_Enlarge && r_size_type == BCEnum::SzT_Enlarge) { + if (EQ_STBASE(l, r, target_type) && GT_SPELLS_EFFECT_ID(l, r, base, 1)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, base, 1) && GT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, base, 1) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + } + if (l_size_type == BCEnum::SzT_Reduce && r_size_type == BCEnum::SzT_Reduce) { + if (EQ_STBASE(l, r, target_type) && LT_SPELLS_EFFECT_ID(l, r, base, 1)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, base, 1) && GT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_SPELLS_EFFECT_ID(l, r, base, 1) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + } + + return false; + }); + continue; + case BCEnum::SpT_Stance: + spell_list->sort([](STBaseEntry* l, STBaseEntry* r) { + if (LT_STSTANCE(l, r, stance_type)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_SummonCorpse: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (GT_SPELLS_EFFECT_ID(l, r, base, 1)) + return true; + if (EQ_SPELLS_EFFECT_ID(l, r, base, 1) && LT_STBASE(l, r, spell_level)) + return true; + if (EQ_SPELLS_EFFECT_ID(l, r, base, 1) && EQ_STBASE(l, r, spell_level) && EQ_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + case BCEnum::SpT_WaterBreathing: + spell_list->sort([](const STBaseEntry* l, const STBaseEntry* r) { + if (LT_STBASE(l, r, target_type)) + return true; + if (EQ_STBASE(l, r, target_type) && GT_STBASE(l, r, spell_level)) + return true; + if (EQ_STBASE(l, r, target_type) && EQ_STBASE(l, r, spell_level) && LT_STBASE(l, r, caster_class)) + return true; + + return false; + }); + continue; + default: + continue; + } + } + } + + static void load_teleport_zone_names() { + auto depart_list = &bot_command_spells[BCEnum::SpT_Depart]; + if (depart_list->empty()) + return; + + std::string query = "SELECT `short_name`, `long_name` FROM `zone` WHERE '' NOT IN (`short_name`, `long_name`)"; + auto results = database.QueryDatabase(query); + if (!results.Success()) { + Log.Out(Logs::General, Logs::Error, "load_teleport_zone_names() - Error in zone names query: %s", results.ErrorMessage().c_str()); + return; + } + + std::map zone_names; + for (auto row = results.begin(); row != results.end(); ++row) + zone_names[row[0]] = row[1]; + + for (auto list_iter = depart_list->begin(); list_iter != depart_list->end();) { + auto test_iter = zone_names.find(spells[(*list_iter)->spell_id].teleport_zone); + if (test_iter == zone_names.end()) { + list_iter = depart_list->erase(list_iter); + continue; + } + + (*list_iter)->SafeCastToDepart()->long_name = test_iter->second; + ++list_iter; + } + + } + + static void build_strings(bcst_levels_map& bot_levels_map) { + for (int i = BCEnum::SpellTypeFirst; i <= BCEnum::SpellTypeLast; ++i) + helper_bots_string(static_cast(i), bot_levels_map[static_cast(i)]); + } + + static void status_report() { + Log.Out(Logs::General, Logs::Commands, "load_bot_command_spells(): - 'RuleI(Bots, CommandSpellRank)' set to %i.", RuleI(Bots, CommandSpellRank)); + if (bot_command_spells.empty()) { + Log.Out(Logs::General, Logs::Error, "load_bot_command_spells() - 'bot_command_spells' is empty."); + return; + } + + for (int i = BCEnum::SpellTypeFirst; i <= BCEnum::SpellTypeLast; ++i) + Log.Out(Logs::General, Logs::Commands, "load_bot_command_spells(): - '%s' returned %u spell entries.", + BCEnum::SpellTypeEnumToString(static_cast(i)).c_str(), bot_command_spells[static_cast(i)].size()); + } + + static void helper_bots_string(BCEnum::SpType type_index, bcst_levels& bot_levels) { + for (int i = WARRIOR; i <= BERSERKER; ++i) + required_bots_map_by_class[type_index][i] = "Unavailable..."; + + if (bot_levels.empty()) { + required_bots_map[type_index] = "This command is currently unavailable..."; + return; + } + + required_bots_map[type_index] = ""; + + auto map_size = bot_levels.size(); + while (bot_levels.size()) { + bcst_levels::iterator test_iter = bot_levels.begin(); + for (bcst_levels::iterator levels_iter = bot_levels.begin(); levels_iter != bot_levels.end(); ++levels_iter) { + if (levels_iter->second < test_iter->second) + test_iter = levels_iter; + if (strcasecmp(Bot::ClassIdToString(levels_iter->first).c_str(), Bot::ClassIdToString(test_iter->first).c_str()) < 0 && levels_iter->second <= test_iter->second) + test_iter = levels_iter; + } + + std::string bot_segment; + if (bot_levels.size() == map_size) + bot_segment = "%s(%u)"; + else if (bot_levels.size() > 1) + bot_segment = ", %s(%u)"; + else + bot_segment = " or %s(%u)"; + + required_bots_map[type_index].append(StringFormat(bot_segment.c_str(), Bot::ClassIdToString(test_iter->first).c_str(), test_iter->second)); + required_bots_map_by_class[type_index][test_iter->first] = StringFormat("%s(%u)", Bot::ClassIdToString(test_iter->first).c_str(), test_iter->second); + bot_levels.erase(test_iter); + } + } + +#ifdef BCSTSPELLDUMP + static void spell_dump() { + std::ofstream spell_dump; + spell_dump.open(StringFormat("bcs_dump/spell_dump_%i.txt", getpid()), std::ios_base::app | std::ios_base::out); + + if (bot_command_spells.empty()) { + spell_dump << "BCSpells::spell_dump() - 'bot_command_spells' map is empty.\n"; + spell_dump.close(); + return; + } + + int entry_count = 0; + for (int i = BCEnum::SpellTypeFirst; i <= BCEnum::SpellTypeLast; ++i) { + auto bcst_id = static_cast(i); + spell_dump << StringFormat("BCSpells::spell_dump(): - '%s' returned %u spells:\n", + BCEnum::SpellTypeEnumToString(bcst_id).c_str(), bot_command_spells[bcst_id].size()); + + bcst_list& map_entry = bot_command_spells[bcst_id]; + for (auto list_iter = map_entry.begin(); list_iter != map_entry.end(); ++list_iter) { + STBaseEntry* list_entry = *list_iter; + int spell_id = list_entry->spell_id; + spell_dump << StringFormat("\"%20s\" tt:%02u/cc:%02u/cl:%03u", + ((strlen(spells[spell_id].name) > 20) ? (std::string(spells[spell_id].name).substr(0, 20).c_str()) : (spells[spell_id].name)), + list_entry->target_type, + list_entry->caster_class, + list_entry->spell_level + ); + + spell_dump << StringFormat(" /mn:%05u/RD:%06i/zt:%02i/d#:%06i/td#:%05i/ed#:%05i/SAI:%03u", + spells[spell_id].mana, + spells[spell_id].ResistDiff, + spells[spell_id].zonetype, + spells[spell_id].descnum, + spells[spell_id].typedescnum, + spells[spell_id].effectdescnum, + spells[spell_id].SpellAffectIndex + ); + + for (int i = EffectIDFirst; i <= 3/*EffectIDLast*/; ++i) { + int effect_index = EFFECTIDTOINDEX(i); + spell_dump << StringFormat(" /e%02i:%04i/b%02i:%06i/m%02i:%06i", + i, spells[spell_id].effectid[effect_index], i, spells[spell_id].base[effect_index], i, spells[spell_id].max[effect_index]); + } + + switch (list_entry->BCST()) { + case BCEnum::SpT_Charm: + spell_dump << StringFormat(" /d:%c", ((list_entry->SafeCastToCharm()->dire) ? ('T') : ('F'))); + break; + case BCEnum::SpT_Cure: + spell_dump << ' '; + for (int i = 0; i < BCEnum::AilmentTypeCount; ++i) { + spell_dump << StringFormat("/cv%02i:%03i", i, list_entry->SafeCastToCure()->cure_value[i]); + } + break; + case BCEnum::SpT_Depart: { + std::string long_name = list_entry->SafeCastToDepart()->long_name.c_str(); + spell_dump << StringFormat(" /ln:%20s", ((long_name.size() > 20) ? (long_name.substr(0, 20).c_str()) : (long_name.c_str()))); + break; + } + case BCEnum::SpT_Escape: + spell_dump << StringFormat(" /l:%c", ((list_entry->SafeCastToEscape()->lesser) ? ('T') : ('F'))); + break; + case BCEnum::SpT_Invisibility: + spell_dump << StringFormat(" /it:%02i", list_entry->SafeCastToInvisibility()->invis_type); + break; + case BCEnum::SpT_MovementSpeed: + spell_dump << StringFormat(" /g:%c", ((list_entry->SafeCastToMovementSpeed()->group) ? ('T') : ('F'))); + break; + case BCEnum::SpT_Resistance: + spell_dump << ' '; + for (int i = 0; i < BCEnum::ResistanceTypeCount; ++i) { + spell_dump << StringFormat("/rv%02i:%03i", i, list_entry->SafeCastToResistance()->resist_value[i]); + } + break; + case BCEnum::SpT_Resurrect: + spell_dump << StringFormat(" /aoe:%c", ((list_entry->SafeCastToResurrect()->aoe) ? ('T') : ('F'))); + break; + case BCEnum::SpT_SendHome: + spell_dump << StringFormat(" /g:%c", ((list_entry->SafeCastToSendHome()->group) ? ('T') : ('F'))); + break; + case BCEnum::SpT_Size: + spell_dump << StringFormat(" /st:%02i", list_entry->SafeCastToSize()->size_type); + break; + case BCEnum::SpT_Stance: + spell_dump << StringFormat(" /st:%02i", list_entry->SafeCastToStance()->stance_type); + break; + default: + break; + } + + spell_dump << "\n"; + ++entry_count; + } + + spell_dump << StringFormat("required_bots_map[%s] = \"%s\"\n", + BCEnum::SpellTypeEnumToString(static_cast(i)).c_str(), required_bots_map[static_cast(i)].c_str()); + + spell_dump << "\n"; + } + + spell_dump << StringFormat("Total bcs entry count: %i\n", entry_count); + spell_dump.close(); + } +#endif +}; + + +//struct bcl_struct *bot_command_list; // the actual linked list of bot commands +int bot_command_count; // how many bot commands we have + +// this is the pointer to the dispatch function, updated once +// init has been performed to point at the real function +int (*bot_command_dispatch)(Client *,char const *) = bot_command_not_avail; + +// TODO: Find out what these are for... +void bot_command_bestz(Client *c, const Seperator *message); +void bot_command_pf(Client *c, const Seperator *message); + +std::map bot_command_list; +std::map bot_command_aliases; + +// All allocated BotCommandRecords get put in here so they get deleted on shutdown +LinkedList cleanup_bot_command_list; + + +/* + * bot_command_not_avail + * This is the default dispatch function when commands aren't loaded. + * + * Parameters: + * not used + * + */ +int bot_command_not_avail(Client *c, const char *message) +{ + c->Message(m_fail, "Bot commands not available."); + return -1; +} + + +/************************************************************************** +/* the rest below here could be in a dynamically loaded module eventually * +/*************************************************************************/ + +/* + +Access Levels: + +0 Normal +10 * Steward * +20 * Apprentice Guide * +50 * Guide * +80 * QuestTroupe * +81 * Senior Guide * +85 * GM-Tester * +90 * EQ Support * +95 * GM-Staff * +100 * GM-Admin * +150 * GM-Lead Admin * +160 * QuestMaster * +170 * GM-Areas * +180 * GM-Coder * +200 * GM-Mgmt * +250 * GM-Impossible * + +*/ + +/* + * bot_command_init + * initializes the bot command list, call at startup + * + * Parameters: + * none + * + * When adding a new bot command, only hard-code 'real' bot commands - + * all command aliases are added later through a database call + * + */ +int bot_command_init(void) +{ + bot_command_aliases.clear(); + + if ( + bot_command_add("actionable", "Lists actionable command arguments and use descriptions", 0, bot_command_actionable) || + bot_command_add("aggressive", "Orders a bot to use a aggressive discipline", 0, bot_command_aggressive) || + bot_command_add("attack", "Orders bots to attack a designated target", 0, bot_command_attack) || + bot_command_add("bindaffinity", "Orders a bot to attempt an affinity binding", 0, bot_command_bind_affinity) || + bot_command_add("bot", "Lists the available bot management [subcommands]", 0, bot_command_bot) || + bot_command_add("botappearance", "Lists the available bot appearance [subcommands]", 0, bot_subcommand_bot_appearance) || + bot_command_add("botbeardcolor", "Changes the beard color of a bot", 0, bot_subcommand_bot_beard_color) || + bot_command_add("botbeardstyle", "Changes the beard style of a bot", 0, bot_subcommand_bot_beard_style) || + bot_command_add("botcamp", "Orders a bot(s) to camp", 0, bot_subcommand_bot_camp) || + bot_command_add("botclone", "Creates a copy of a bot", 200, bot_subcommand_bot_clone) || + bot_command_add("botcreate", "Creates a new bot", 0, bot_subcommand_bot_create) || + bot_command_add("botdelete", "Deletes all record of a bot", 0, bot_subcommand_bot_delete) || + bot_command_add("botdetails", "Changes the Drakkin details of a bot", 0, bot_subcommand_bot_details) || + bot_command_add("botdyearmor", "Changes the color of a bot's (bots') armor", 0, bot_subcommand_bot_dye_armor) || + bot_command_add("boteyes", "Changes the eye colors of a bot", 0, bot_subcommand_bot_eyes) || + bot_command_add("botface", "Changes the facial appearance of your bot", 0, bot_subcommand_bot_face) || + bot_command_add("botfollowdistance", "Changes the follow distance(s) of a bot(s)", 0, bot_subcommand_bot_follow_distance) || + bot_command_add("botgroup", "Lists the available bot-group [subcommands]", 0, bot_command_botgroup) || + bot_command_add("botgroupaddmember", "Adds a member to a bot-group", 0, bot_subcommand_botgroup_add_member) || + bot_command_add("botgroupcreate", "Creates a bot-group and designates a leader", 0, bot_subcommand_botgroup_create) || + bot_command_add("botgroupdelete", "Deletes a bot-group and releases its members", 0, bot_subcommand_botgroup_delete) || + bot_command_add("botgrouplist", "Lists all of your existing bot-groups", 0, bot_subcommand_botgroup_list) || + bot_command_add("botgroupload", "Loads all members of a bot-group", 0, bot_subcommand_botgroup_load) || + bot_command_add("botgroupremovemember", "Removes a bot from its bot-group", 0, bot_subcommand_botgroup_remove_member) || + bot_command_add("bothaircolor", "Changes the hair color of a bot", 0, bot_subcommand_bot_hair_color) || + bot_command_add("bothairstyle", "Changes the hairstyle of a bot", 0, bot_subcommand_bot_hairstyle) || + bot_command_add("botheritage", "Changes the Drakkin heritage of a bot", 0, bot_subcommand_bot_heritage) || + bot_command_add("botinspectmessage", "Changes the inspect message of a bot", 0, bot_subcommand_bot_inspect_message) || + bot_command_add("botlist", "Lists the bots that you own", 0, bot_subcommand_bot_list) || + bot_command_add("botoutofcombat", "Toggles your bot between standard and out-of-combat spell/skill use - if any specialized behaviors exist", 0, bot_subcommand_bot_out_of_combat) || + bot_command_add("botreport", "Orders a bot to report its readiness", 0, bot_subcommand_bot_report) || + bot_command_add("botspawn", "Spawns a created bot", 0, bot_subcommand_bot_spawn) || + bot_command_add("botstance", "Changes the stance of a bot", 0, bot_subcommand_bot_stance) || + bot_command_add("botsummon", "Summons bot(s) to your location", 0, bot_subcommand_bot_summon) || + bot_command_add("bottattoo", "Changes the Drakkin tattoo of a bot", 0, bot_subcommand_bot_tattoo) || + bot_command_add("bottogglearcher", "Toggles a archer bot between melee and ranged weapon use", 0, bot_subcommand_bot_toggle_archer) || + bot_command_add("bottogglehelm", "Toggles the helm visibility of a bot between shown and hidden", 0, bot_subcommand_bot_toggle_helm) || + bot_command_add("botupdate", "Updates a bot to reflect any level changes that you have experienced", 0, bot_subcommand_bot_update) || + bot_command_add("botwoad", "Changes the Barbarian woad of a bot", 0, bot_subcommand_bot_woad) || + bot_command_add("charm", "Attempts to have a bot charm your target", 0, bot_command_charm) || + bot_command_add("circle", "Orders a Druid bot to open a magical doorway to a specified destination", 0, bot_subcommand_circle) || + bot_command_add("cure", "Orders a bot to remove any ailments", 0, bot_command_cure) || + bot_command_add("defensive", "Orders a bot to use a defensive discipline", 0, bot_command_defensive) || + bot_command_add("depart", "Orders a bot to open a magical doorway to a specified destination", 0, bot_command_depart) || + bot_command_add("escape", "Orders a bot to send a target group to a safe location within the zone", 0, bot_command_escape) || + bot_command_add("findaliases", "Find available aliases for a bot command", 0, bot_command_find_aliases) || + bot_command_add("follow", "Orders bots to follow a designated target", 0, bot_command_follow) || + bot_command_add("guard", "Orders bots to guard their current positions", 0, bot_command_guard) || + bot_command_add("healrotation", "Lists the available bot heal rotation [subcommands]", 0, bot_command_heal_rotation) || + bot_command_add("healrotationadaptivetargeting", "Enables or disables adaptive targeting within the heal rotation instance", 0, bot_subcommand_heal_rotation_adaptive_targeting) || + bot_command_add("healrotationaddmember", "Adds a bot to a heal rotation instance", 0, bot_subcommand_heal_rotation_add_member) || + bot_command_add("healrotationaddtarget", "Adds target to a heal rotation instance", 0, bot_subcommand_heal_rotation_add_target) || + bot_command_add("healrotationadjustcritical", "Adjusts the critial HP limit of the heal rotation instance's Class Armor Type criteria", 0, bot_subcommand_heal_rotation_adjust_critical) || + bot_command_add("healrotationadjustsafe", "Adjusts the safe HP limit of the heal rotation instance's Class Armor Type criteria", 0, bot_subcommand_heal_rotation_adjust_safe) || + bot_command_add("healrotationcastingoverride", "Enables or disables casting overrides within the heal rotation instance", 0, bot_subcommand_heal_rotation_casting_override) || + bot_command_add("healrotationchangeinterval", "Changes casting interval between members within the heal rotation instance", 0, bot_subcommand_heal_rotation_change_interval) || + bot_command_add("healrotationclearhot", "Clears the HOT of a heal rotation instance", 0, bot_subcommand_heal_rotation_clear_hot) || + bot_command_add("healrotationcleartargets", "Removes all targets from a heal rotation instance", 0, bot_subcommand_heal_rotation_clear_targets) || + bot_command_add("healrotationcreate", "Creates a bot heal rotation instance and designates a leader", 0, bot_subcommand_heal_rotation_create) || + bot_command_add("healrotationdelete", "Deletes a bot heal rotation entry by leader", 0, bot_subcommand_heal_rotation_delete) || + bot_command_add("healrotationfastheals", "Enables or disables fast heals within the heal rotation instance", 0, bot_subcommand_heal_rotation_fast_heals) || + bot_command_add("healrotationlist", "Reports heal rotation instance(s) information", 0, bot_subcommand_heal_rotation_list) || + bot_command_add("healrotationremovemember", "Removes a bot from a heal rotation instance", 0, bot_subcommand_heal_rotation_remove_member) || + bot_command_add("healrotationremovetarget", "Removes target from a heal rotations instance", 0, bot_subcommand_heal_rotation_remove_target) || + bot_command_add("healrotationresetlimits", "Resets all Class Armor Type HP limit criteria in a heal rotation to its default value", 0, bot_subcommand_heal_rotation_reset_limits) || + bot_command_add("healrotationsave", "Saves a bot heal rotation entry by leader", 0, bot_subcommand_heal_rotation_save) || + bot_command_add("healrotationsethot", "Sets the HOT in a heal rotation instance", 0, bot_subcommand_heal_rotation_set_hot) || + bot_command_add("healrotationstart", "Starts a heal rotation", 0, bot_subcommand_heal_rotation_start) || + bot_command_add("healrotationstop", "Stops a heal rotation", 0, bot_subcommand_heal_rotation_stop) || + bot_command_add("help", "List available commands and their description - specify partial command as argument to search", 0, bot_command_help) || + bot_command_add("hold", "Suspends a bot's AI processing until released", 0, bot_command_hold) || + bot_command_add("identify", "Orders a bot to cast an item identification spell", 0, bot_command_identify) || + bot_command_add("inventory", "Lists the available bot inventory [subcommands]", 0, bot_command_inventory) || + bot_command_add("inventorygive", "Gives the item on your cursor to a bot", 0, bot_subcommand_inventory_give) || + bot_command_add("inventorylist", "Lists all items in a bot's inventory", 0, bot_subcommand_inventory_list) || + bot_command_add("inventoryremove", "Removes an item from a bot's inventory", 0, bot_subcommand_inventory_remove) || + bot_command_add("inventorywindow", "Displays all items in a bot's inventory in a pop-up window", 0, bot_subcommand_inventory_window) || + bot_command_add("invisibility", "Orders a bot to cast a cloak of invisibility, or allow them to be seen", 0, bot_command_invisibility) || + bot_command_add("levitation", "Orders a bot to cast a levitation spell", 0, bot_command_levitation) || + bot_command_add("lull", "Orders a bot to cast a pacification spell", 0, bot_command_lull) || + bot_command_add("mesmerize", "Orders a bot to cast a mesmerization spell", 0, bot_command_mesmerize) || + bot_command_add("movementspeed", "Orders a bot to cast a movement speed enhancement spell", 0, bot_command_movement_speed) || + bot_command_add("pet", "Lists the available bot pet [subcommands]", 0, bot_command_pet) || + bot_command_add("petremove", "Orders a bot to remove its pet", 0, bot_subcommand_pet_remove) || + bot_command_add("petsettype", "Orders a Magician bot to use a specified pet type", 0, bot_subcommand_pet_set_type) || + bot_command_add("picklock", "Orders a capable bot to pick the lock of the closest door", 0, bot_command_pick_lock) || + bot_command_add("portal", "Orders a Wizard bot to open a magical doorway to a specified destination", 0, bot_subcommand_portal) || + bot_command_add("pull", "Orders a designated bot to 'pull' an enemy", 0, bot_command_pull) || + bot_command_add("release", "Releases a suspended bot's AI processing (with hate list wipe)", 0, bot_command_release) || + bot_command_add("resistance", "Orders a bot to cast a specified resistance buff", 0, bot_command_resistance) || + bot_command_add("resurrect", "Orders a bot to resurrect a player's (players') corpse(s)", 0, bot_command_resurrect) || + bot_command_add("rune", "Orders a bot to cast a rune of protection", 0, bot_command_rune) || + bot_command_add("sendhome", "Orders a bot to open a magical doorway home", 0, bot_command_send_home) || + bot_command_add("size", "Orders a bot to change a player's size", 0, bot_command_size) || + bot_command_add("summoncorpse", "Orders a bot to summon a corpse to its feet", 0, bot_command_summon_corpse) || + bot_command_add("taunt", "Toggles taunt use by a bot", 0, bot_command_taunt) || + bot_command_add("track", "Orders a capable bot to track enemies", 0, bot_command_track) || + bot_command_add("waterbreathing", "Orders a bot to cast a water breathing spell", 0, bot_command_water_breathing) + ) { + bot_command_deinit(); + return -1; + } + + std::map>> bot_command_settings; + botdb.LoadBotCommandSettings(bot_command_settings); + + auto working_bcl = bot_command_list; + for (auto working_bcl_iter : working_bcl) { + auto bot_command_settings_iter = bot_command_settings.find(working_bcl_iter.first); + if (bot_command_settings_iter == bot_command_settings.end()) { + if (working_bcl_iter.second->access == 0) + Log.Out(Logs::General, Logs::Commands, "bot_command_init(): Warning: Bot Command '%s' defaulting to access level 0!", working_bcl_iter.first.c_str()); + continue; + } + + working_bcl_iter.second->access = bot_command_settings_iter->second.first; + Log.Out(Logs::General, Logs::Commands, "bot_command_init(): - Bot Command '%s' set to access level %d.", working_bcl_iter.first.c_str(), bot_command_settings_iter->second.first); + if (bot_command_settings_iter->second.second.empty()) + continue; + + for (auto alias_iter : bot_command_settings_iter->second.second) { + if (alias_iter.empty()) + continue; + if (bot_command_list.find(alias_iter) != bot_command_list.end()) { + Log.Out(Logs::General, Logs::Commands, "bot_command_init(): Warning: Alias '%s' already exists as a bot command - skipping!", alias_iter.c_str()); + continue; + } + + bot_command_list[alias_iter] = working_bcl_iter.second; + bot_command_aliases[alias_iter] = working_bcl_iter.first; + + Log.Out(Logs::General, Logs::Commands, "bot_command_init(): - Alias '%s' added to bot command '%s'.", alias_iter.c_str(), bot_command_aliases[alias_iter].c_str()); + } + } + + bot_command_dispatch = bot_command_real_dispatch; + + BCSpells::Load(); + + return bot_command_count; +} + + +/* + * bot_command_deinit + * clears the bot command list, freeing resources + * + * Parameters: + * none + * + */ +void bot_command_deinit(void) +{ + bot_command_list.clear(); + bot_command_aliases.clear(); + + bot_command_dispatch = bot_command_not_avail; + bot_command_count = 0; + + BCSpells::Unload(); +} + + +/* + * bot_command_add + * adds a bot command to the bot command list; used by bot_command_init + * + * Parameters: + * bot_command_string - the command ex: "spawn" + * desc - text description of bot command for #help + * access - default access level required to use command + * function - pointer to function that handles command + * + */ +int bot_command_add(std::string bot_command_name, const char *desc, int access, BotCmdFuncPtr function) +{ + if (bot_command_name.empty()) { + Log.Out(Logs::General, Logs::Error, "bot_command_add() - Bot command added with empty name string - check bot_command.cpp."); + return -1; + } + if (function == nullptr) { + Log.Out(Logs::General, Logs::Error, "bot_command_add() - Bot command '%s' added without a valid function pointer - check bot_command.cpp.", bot_command_name.c_str()); + return -1; + } + if (bot_command_list.count(bot_command_name) != 0) { + Log.Out(Logs::General, Logs::Error, "bot_command_add() - Bot command '%s' is a duplicate bot command name - check bot_command.cpp.", bot_command_name.c_str()); + return -1; + } + for (auto iter : bot_command_list) { + if (iter.second->function != function) + continue; + Log.Out(Logs::General, Logs::Error, "bot_command_add() - Bot command '%s' equates to an alias of '%s' - check bot_command.cpp.", bot_command_name.c_str(), iter.first.c_str()); + return -1; + } + + BotCommandRecord *bcr = new BotCommandRecord; + bcr->access = access; + bcr->desc = desc; + bcr->function = function; + + bot_command_list[bot_command_name] = bcr; + bot_command_aliases[bot_command_name] = bot_command_name; + cleanup_bot_command_list.Append(bcr); + bot_command_count++; + + return 0; +} + + +/* + * + * bot_command_real_dispatch + * Calls the correct function to process the client's command string. + * Called from Client::ChannelMessageReceived if message starts with + * bot command character (^). + * + * Parameters: + * c - pointer to the calling client object + * message - what the client typed + * + */ +int bot_command_real_dispatch(Client *c, const char *message) +{ + Seperator sep(message, ' ', 10, 100, true); // "three word argument" should be considered 1 arg + + bot_command_log_command(c, message); + + std::string cstr(sep.arg[0]+1); + + if(bot_command_list.count(cstr) != 1) { + return(-2); + } + + BotCommandRecord *cur = bot_command_list[cstr]; + if(c->Admin() < cur->access){ + c->Message(m_fail, "Your access level is not high enough to use this bot command."); + return(-1); + } + + /* QS: Player_Log_Issued_Commands */ + if (RuleB(QueryServ, PlayerLogIssuedCommandes)){ + std::string event_desc = StringFormat("Issued bot command :: '%s' in zoneid:%i instid:%i", message, c->GetZoneID(), c->GetInstanceID()); + QServ->PlayerLogEvent(Player_Log_Issued_Commands, c->CharacterID(), event_desc); + } + + if(cur->access >= COMMANDS_LOGGING_MIN_STATUS) { + Log.Out(Logs::General, Logs::Commands, "%s (%s) used bot command: %s (target=%s)", c->GetName(), c->AccountName(), message, c->GetTarget()?c->GetTarget()->GetName():"NONE"); + } + + if(cur->function == nullptr) { + Log.Out(Logs::General, Logs::Error, "Bot command '%s' has a null function\n", cstr.c_str()); + return(-1); + } else { + //dispatch C++ bot command + cur->function(c, &sep); // dispatch bot command + } + return 0; + +} + +void bot_command_log_command(Client *c, const char *message) +{ + int admin = c->Admin(); + + bool continueevents = false; + switch (zone->loglevelvar) { //catch failsafe + case 9: // log only LeadGM + if ((admin >= 150) && (admin <200)) + continueevents = true; + break; + case 8: // log only GM + if ((admin >= 100) && (admin <150)) + continueevents = true; + break; + case 1: + if ((admin >= 200)) + continueevents = true; + break; + case 2: + if ((admin >= 150)) + continueevents = true; + break; + case 3: + if ((admin >= 100)) + continueevents = true; + break; + case 4: + if ((admin >= 80)) + continueevents = true; + break; + case 5: + if ((admin >= 20)) + continueevents = true; + break; + case 6: + if ((admin >= 10)) + continueevents = true; + break; + case 7: + continueevents = true; + break; + default: + break; + } + + if (continueevents) + database.logevents(c->AccountName(), c->AccountID(), admin,c->GetName(), c->GetTarget()?c->GetTarget()->GetName():"None", "BotCommand", message, 1); +} + + +/* + * helper functions by use + */ +namespace MyBots +{ + static bool IsMyBot(Client *bot_owner, Mob *my_bot) { + if (!bot_owner || !my_bot || !my_bot->IsBot()) + return false; + + auto test_bot = my_bot->CastToBot(); + if (!test_bot->GetOwner() || !test_bot->GetOwner()->IsClient() || test_bot->GetOwner()->CastToClient() != bot_owner) + return false; + + return true; + } + + static bool IsMyBotInTargetsGroup(Client *bot_owner, Mob *grouped_bot) { + if (!bot_owner || !grouped_bot || !grouped_bot->GetGroup() || !IsMyBot(bot_owner, grouped_bot)) + return false; + + auto target_mob = bot_owner->GetTarget(); + if (!target_mob) + return false; + + if (!target_mob->GetGroup() || (!target_mob->IsClient() && !target_mob->IsBot())) + return false; + + return (grouped_bot->GetGroup() == target_mob->GetGroup()); + } + + static bool IsMyBotInPlayerGroup(Client *bot_owner, Mob *grouped_bot, Client *grouped_player) { + if (!bot_owner || !grouped_player || !grouped_player->GetGroup() || !grouped_bot || !grouped_bot->GetGroup() || !IsMyBot(bot_owner, grouped_bot)) + return false; + + return (grouped_player->GetGroup() == grouped_bot->GetGroup()); + } + + static void UniquifySBL(std::list &sbl) { + sbl.remove(nullptr); + sbl.sort(); + sbl.unique(); + } + + static void PopulateSBL_ByTargetedBot(Client *bot_owner, std::list &sbl, bool clear_list = true) { + if (clear_list) + sbl.clear(); + + if (IsMyBot(bot_owner, bot_owner->GetTarget())) + sbl.push_back(bot_owner->GetTarget()->CastToBot()); + + if (!clear_list) + UniquifySBL(sbl); + } + + static void PopulateSBL_ByNamedBot(Client *bot_owner, std::list &sbl, const char* name, bool clear_list = true) { + if (clear_list) + sbl.clear(); + if (!bot_owner || !name) + return; + + auto selectable_bot_list = entity_list.GetBotsByBotOwnerCharacterID(bot_owner->CharacterID()); + for (auto bot_iter : selectable_bot_list) { + if (!strcasecmp(bot_iter->GetCleanName(), name)) { + sbl.push_back(bot_iter); + return; + } + } + + if (!clear_list) + UniquifySBL(sbl); + } + + static void PopulateSBL_ByMyGroupedBots(Client *bot_owner, std::list &sbl, bool clear_list = true) { + if (clear_list) + sbl.clear(); + if (!bot_owner) + return; + + if (!bot_owner->GetGroup()) + return; + + std::list group_list; + bot_owner->GetGroup()->GetBotList(group_list); + for (auto member_iter : group_list) { + if (IsMyBot(bot_owner, member_iter)) + sbl.push_back(member_iter); + } + + if (!clear_list) + UniquifySBL(sbl); + } + + static void PopulateSBL_ByTargetsGroupedBots(Client *bot_owner, std::list &sbl, bool clear_list = true) { + if (clear_list) + sbl.clear(); + if (!bot_owner) + return; + + auto target_mob = bot_owner->GetTarget(); + if (!target_mob || !target_mob->GetGroup() || (!target_mob->IsClient() && !target_mob->IsBot())) + return; + + std::list group_list; + target_mob->GetGroup()->GetBotList(group_list); + for (auto member_iter : group_list) { + if (IsMyBot(bot_owner, member_iter)) + sbl.push_back(member_iter); + } + + if (!clear_list) + UniquifySBL(sbl); + } + + static void PopulateSBL_ByNamesGroupedBots(Client *bot_owner, std::list &sbl, const char* name, bool clear_list = true) { + if (clear_list) + sbl.clear(); + if (!bot_owner || !name) + return; + + Mob* named_mob = nullptr; + std::list l_mob_list; + entity_list.GetMobList(l_mob_list); + for (auto mob_iter : l_mob_list) { + if (!strcasecmp(mob_iter->GetCleanName(), name)) { + named_mob = mob_iter; + break; + } + } + if (!named_mob || !named_mob->GetGroup() || (!named_mob->IsClient() && !named_mob->IsBot())) + return; + + std::list group_list; + named_mob->GetGroup()->GetBotList(group_list); + for (auto member_iter : group_list) { + if (IsMyBot(bot_owner, member_iter)) + sbl.push_back(member_iter); + } + + if (!clear_list) + UniquifySBL(sbl); + } + + static void PopulateSBL_ByHealRotation(Client *bot_owner, std::list &sbl, const char* name, bool clear_list = true) { + if (clear_list) + sbl.clear(); + if (!bot_owner || (!name && !bot_owner->GetTarget())) + return; + + std::list selectable_bot_list; + if (name) + PopulateSBL_ByNamedBot(bot_owner, selectable_bot_list, name); + else + PopulateSBL_ByTargetedBot(bot_owner, selectable_bot_list); + + if (selectable_bot_list.empty() || !selectable_bot_list.front()->IsHealRotationMember()) + return; + + auto hrm = (*selectable_bot_list.front()->MemberOfHealRotation())->MemberList(); + for (auto hrm_iter : *hrm) { + if (IsMyBot(bot_owner, hrm_iter)) + sbl.push_back(hrm_iter); + } + + auto hrt = (*selectable_bot_list.front()->MemberOfHealRotation())->TargetList(); + for (auto hrt_iter : *hrt) { + if (IsMyBot(bot_owner, hrt_iter)) + sbl.push_back(hrt_iter->CastToBot()); + } + + UniquifySBL(sbl); + } + + static void PopulateSBL_ByHealRotationMembers(Client *bot_owner, std::list &sbl, const char* name, bool clear_list = true) { + if (clear_list) + sbl.clear(); + if (!bot_owner || (!name && !bot_owner->GetTarget())) + return; + + std::list selectable_bot_list; + if (name) + PopulateSBL_ByNamedBot(bot_owner, selectable_bot_list, name); + else + PopulateSBL_ByTargetedBot(bot_owner, selectable_bot_list); + + if (selectable_bot_list.empty() || !selectable_bot_list.front()->IsHealRotationMember()) + return; + + auto hrm = (*selectable_bot_list.front()->MemberOfHealRotation())->MemberList(); + for (auto hrm_iter : *hrm) { + if (IsMyBot(bot_owner, hrm_iter)) + sbl.push_back(hrm_iter); + } + + if (!clear_list) + UniquifySBL(sbl); + } + + static void PopulateSBL_ByHealRotationTargets(Client *bot_owner, std::list &sbl, const char* name, bool clear_list = true) { + if (clear_list) + sbl.clear(); + if (!bot_owner || (!name && !bot_owner->GetTarget())) + return; + + std::list selectable_bot_list; + if (name) + PopulateSBL_ByNamedBot(bot_owner, selectable_bot_list, name); + else + PopulateSBL_ByTargetedBot(bot_owner, selectable_bot_list); + + if (selectable_bot_list.empty() || !selectable_bot_list.front()->IsHealRotationMember()) + return; + + auto hrm = (*selectable_bot_list.front()->MemberOfHealRotation())->TargetList(); + for (auto hrm_iter : *hrm) { + if (IsMyBot(bot_owner, hrm_iter)) + sbl.push_back(static_cast(hrm_iter)); + } + + if (!clear_list) + UniquifySBL(sbl); + } + + static void PopulateSBL_BySpawnedBots(Client *bot_owner, std::list &sbl) { // should be used for most spell casting commands + sbl.clear(); + if (!bot_owner) + return; + + sbl = entity_list.GetBotsByBotOwnerCharacterID(bot_owner->CharacterID()); + sbl.remove(nullptr); + } + + static void PopulateSBL_ByBotGroup(Client *bot_owner, std::list &sbl, const char* name, bool clear_list = true) { + if (clear_list) + sbl.clear(); + if (!bot_owner || !name) + return; + + std::string group_name = name; + + uint32 botgroup_id = 0; + if (!botdb.LoadBotGroupIDForLoadBotGroup(bot_owner->CharacterID(), group_name, botgroup_id) || !botgroup_id) + return; + + std::map> botgroup_list; + if (!botdb.LoadBotGroup(group_name, botgroup_list) || botgroup_list.find(botgroup_id) == botgroup_list.end() || !botgroup_list[botgroup_id].size()) + return; + + std::list selectable_bot_list; + PopulateSBL_BySpawnedBots(bot_owner, selectable_bot_list); + if (selectable_bot_list.empty()) + return; + + selectable_bot_list.remove(nullptr); + for (auto group_iter : botgroup_list[botgroup_id]) { + for (auto bot_iter : selectable_bot_list) { + if (bot_iter->GetBotID() != group_iter) + continue; + + if (IsMyBot(bot_owner, bot_iter)) { + sbl.push_back(bot_iter); + break; + } + } + } + + if (!clear_list) + UniquifySBL(sbl); + } +}; + +namespace ActionableTarget +{ + static bool AmIInPlayerGroup(Client *bot_owner, Client *grouped_player) { + if (!bot_owner || !grouped_player || !bot_owner->GetGroup() || !grouped_player->GetGroup()) + return false; + + return (bot_owner->GetGroup() == grouped_player->GetGroup()); + } + + static bool IsAttackable(Client *bot_owner, Mob* target_mob) { + if (!bot_owner || !target_mob || bot_owner == target_mob) + return false; + + return bot_owner->IsAttackAllowed(target_mob); + } + + static Client* AsSingle_ByPlayer(Client *bot_owner, bool return_me_on_null_target = true) { + if (!bot_owner) + return nullptr; + + if (!bot_owner->GetTarget()) { + if (return_me_on_null_target) + return bot_owner; + else + return nullptr; + } + + if (!bot_owner->GetTarget()->IsClient()) + return nullptr; + + return bot_owner->GetTarget()->CastToClient(); + } + + static Client* AsGroupMember_ByPlayer(Client *bot_owner, bool return_me_on_null_target = true) { + if (!bot_owner) + return nullptr; + + if (!bot_owner->GetTarget()) { + if (return_me_on_null_target) + return bot_owner; + else + return nullptr; + } + + if (!bot_owner->GetTarget()->IsClient() || !AmIInPlayerGroup(bot_owner, bot_owner->GetTarget()->CastToClient())) + return nullptr; + + return bot_owner->GetTarget()->CastToClient(); + } + + static Corpse* AsCorpse_ByPlayer(Client *bot_owner) { + if (!bot_owner || !bot_owner->GetTarget() || !bot_owner->GetTarget()->IsPlayerCorpse()) + return nullptr; + + return bot_owner->GetTarget()->CastToCorpse(); + } + + static Mob* AsSingle_ByAttackable(Client *bot_owner) { + if (!IsAttackable(bot_owner, bot_owner->GetTarget())) + return nullptr; + + return bot_owner->GetTarget(); + } + + static bool IsFriendlyAllowed(Mob* target_mob) { + if (!target_mob || target_mob->IsClient() || target_mob->IsBot() || (target_mob->IsPet() && target_mob->GetOwner() && (target_mob->GetOwner()->IsClient() || target_mob->GetOwner()->IsBot())) || target_mob->IsPlayerCorpse()) + return true; + + return false; + } + + static Mob* VerifyFriendly(Client* bot_owner, BCEnum::TType target_type, bool return_me_on_null_target = true) { + if (IsAttackable(bot_owner, bot_owner->GetTarget()) || target_type == BCEnum::TT_None) + return nullptr; + + auto target_mob = bot_owner->GetTarget(); + Mob* verified_friendly = nullptr; + switch (target_type) { + case BCEnum::TT_Single: + case BCEnum::TT_GroupV1: + case BCEnum::TT_GroupV2: + case BCEnum::TT_AETarget: + verified_friendly = target_mob; + break; + case BCEnum::TT_Animal: + if (target_mob && target_mob->GetBodyType() == BT_Animal) + verified_friendly = target_mob; + break; + case BCEnum::TT_Undead: + if (target_mob && target_mob->GetBodyType() == BT_Undead) + verified_friendly = target_mob; + break; + case BCEnum::TT_Summoned: + if (target_mob && target_mob->GetBodyType() == BT_Summoned) + verified_friendly = target_mob; + break; + case BCEnum::TT_Plant: + if (target_mob && target_mob->GetBodyType() == BT_Plant) + verified_friendly = target_mob; + break; + case BCEnum::TT_Corpse: + if (target_mob && target_mob->IsCorpse()) + verified_friendly = target_mob; + break; + default: + return nullptr; + } + + if (return_me_on_null_target && !target_mob && !verified_friendly) { + switch (target_type) { + case BCEnum::TT_Single: + case BCEnum::TT_GroupV1: + case BCEnum::TT_GroupV2: + case BCEnum::TT_AETarget: + verified_friendly = bot_owner; + break; + default: + break; + } + } + + return verified_friendly; + } + + static Mob* VerifyEnemy(Client* bot_owner, BCEnum::TType target_type) { + if (!IsAttackable(bot_owner, bot_owner->GetTarget()) || target_type == BCEnum::TT_None) + return nullptr; + + auto target_mob = bot_owner->GetTarget(); + Mob* verified_enemy = nullptr; + switch (target_type) { + case BCEnum::TT_Animal: + if (target_mob->GetBodyType() == BT_Animal) + verified_enemy = target_mob; + break; + case BCEnum::TT_Undead: + if (target_mob->GetBodyType() == BT_Undead) + verified_enemy = target_mob; + break; + case BCEnum::TT_Summoned: + if (target_mob->GetBodyType() == BT_Summoned) + verified_enemy = target_mob; + break; + case BCEnum::TT_Plant: + if (target_mob->GetBodyType() == BT_Plant) + verified_enemy = target_mob; + break; + case BCEnum::TT_Single: + case BCEnum::TT_GroupV1: + case BCEnum::TT_GroupV2: + case BCEnum::TT_AETarget: + verified_enemy = target_mob; + break; + case BCEnum::TT_Corpse: + if (target_mob->IsCorpse()) + verified_enemy = target_mob; + break; + default: + return nullptr; + } + + return verified_enemy; + } + + class Types { + Mob* target[BCEnum::TargetTypeCount]; + bool target_set[BCEnum::TargetTypeCount]; + + public: + Types() { Clear(); } + + void Clear() { + for (int i = BCEnum::TT_None; i <= BCEnum::TargetTypeLast; ++i) { + target[i] = nullptr; + target_set[i] = false; + } + target_set[BCEnum::TT_None] = true; + } + + Mob* Select(Client* bot_owner, BCEnum::TType target_type, bool action_type, bool return_me_on_null_target = true) { + if (target_set[target_type]) + return target[target_type]; + + if (action_type == FRIENDLY) + target[target_type] = VerifyFriendly(bot_owner, target_type, return_me_on_null_target); + else + target[target_type] = VerifyEnemy(bot_owner, target_type); + target_set[target_type] = true; + + return target[target_type]; + } + }; +}; + +namespace ActionableBots +{ + enum ABType { + ABT_None = 0, + ABT_Target, + ABT_ByName, + ABT_OwnerGroup, + ABT_BotGroup, + ABT_TargetGroup, + ABT_NamesGroup, + ABT_HealRotation, + ABT_HealRotationMembers, + ABT_HealRotationTargets, + ABT_Spawned, + ABT_All + }; + + enum ABMask { + ABM_None = 0, + ABM_Target = (1 << (ABT_Target - 1)), + ABM_ByName = (1 << (ABT_ByName - 1)), + ABM_OwnerGroup = (1 << (ABT_OwnerGroup - 1)), + ABM_BotGroup = (1 << (ABT_BotGroup - 1)), + ABM_TargetGroup = (1 << (ABT_TargetGroup - 1)), + ABM_NamesGroup = (1 << (ABT_NamesGroup - 1)), + ABM_HealRotation = (1 << (ABT_HealRotation - 1)), + ABM_HealRotationMembers = (1 << (ABT_HealRotationMembers - 1)), + ABM_HealRotationTargets = (1 << (ABT_HealRotationTargets - 1)), + ABM_Spawned = (1 << (ABT_Spawned - 1)), + ABM_All = (1 << (ABT_All - 1)), + ABM_Spawned_All = (3 << (ABT_Spawned - 1)), + ABM_NoFilter = ~0, + // grouped values + ABM_Type1 = (ABM_Target | ABM_ByName | ABM_OwnerGroup | ABM_BotGroup | ABM_TargetGroup | ABM_NamesGroup | ABM_HealRotationTargets | ABM_Spawned), + ABM_Type2 = (ABM_ByName | ABM_OwnerGroup | ABM_BotGroup | ABM_NamesGroup | ABM_HealRotation | ABM_Spawned) + }; + + // Populates 'sbl' + static ABType PopulateSBL(Client* bot_owner, std::string ab_type_arg, std::list &sbl, int ab_mask, const char* name = nullptr, bool clear_list = true, bool suppress_message = false) { + if (clear_list) + sbl.clear(); + if (!bot_owner) + return ABT_None; + + auto ab_type = ABT_None; + if (!ab_type_arg.compare("target") || ab_type_arg.empty()) + ab_type = ABT_Target; + else if (!ab_type_arg.compare("byname")) + ab_type = ABT_ByName; + else if (!ab_type_arg.compare("ownergroup")) + ab_type = ABT_OwnerGroup; + else if (!ab_type_arg.compare("botgroup")) + ab_type = ABT_BotGroup; + else if (!ab_type_arg.compare("targetgroup")) + ab_type = ABT_TargetGroup; + else if (!ab_type_arg.compare("namesgroup")) + ab_type = ABT_NamesGroup; + else if (!ab_type_arg.compare("healrotation")) + ab_type = ABT_HealRotation; + else if (!ab_type_arg.compare("healrotationmembers")) + ab_type = ABT_HealRotationMembers; + else if (!ab_type_arg.compare("healrotationtargets")) + ab_type = ABT_HealRotationTargets; + else if (!ab_type_arg.compare("spawned")) + ab_type = ABT_Spawned; + else if (!ab_type_arg.compare("all")) + ab_type = ABT_All; + + if (ab_type_arg.empty()) + ab_type_arg = "target"; + + switch (ab_type) { + case ABT_Target: + if (ab_mask & ABM_Target) + MyBots::PopulateSBL_ByTargetedBot(bot_owner, sbl, clear_list); + break; + case ABT_ByName: + if (ab_mask & ABM_ByName) + MyBots::PopulateSBL_ByNamedBot(bot_owner, sbl, name, clear_list); + break; + case ABT_OwnerGroup: + if (ab_mask & ABM_OwnerGroup) + MyBots::PopulateSBL_ByMyGroupedBots(bot_owner, sbl, clear_list); + break; + case ABT_BotGroup: + if (ab_mask & ABM_BotGroup) + MyBots::PopulateSBL_ByBotGroup(bot_owner, sbl, name, clear_list); + break; + case ABT_TargetGroup: + if (ab_mask & ABM_TargetGroup) + MyBots::PopulateSBL_ByTargetsGroupedBots(bot_owner, sbl, clear_list); + break; + case ABT_NamesGroup: + if (ab_mask & ABM_NamesGroup) + MyBots::PopulateSBL_ByNamesGroupedBots(bot_owner, sbl, name, clear_list); + break; + case ABT_HealRotation: + if (ab_mask & ABM_HealRotation) + MyBots::PopulateSBL_ByHealRotation(bot_owner, sbl, name, clear_list); + break; + case ABT_HealRotationMembers: + if (ab_mask & ABM_HealRotationMembers) + MyBots::PopulateSBL_ByHealRotationMembers(bot_owner, sbl, name, clear_list); + break; + case ABT_HealRotationTargets: + if (ab_mask & ABM_HealRotationTargets) + MyBots::PopulateSBL_ByHealRotationTargets(bot_owner, sbl, name, clear_list); + break; + case ABT_Spawned: + case ABT_All: + if (ab_mask & ABM_Spawned_All) + MyBots::PopulateSBL_BySpawnedBots(bot_owner, sbl); + break; + default: + break; + } + if (sbl.empty() && ab_type != ABT_All) { + if (suppress_message) + return ABT_None; + + if (!ab_mask) + bot_owner->Message(m_fail, "Command passed null 'ActionableBot' criteria"); + else if (ab_mask & ab_type) + bot_owner->Message(m_fail, "You have no spawned bots meeting this criteria - type: '%s', name: '%s'", ab_type_arg.c_str(), ((name) ? (name) : (""))); + else + bot_owner->Message(m_fail, "This command does not allow 'ActionableBot' criteria '%s'", ab_type_arg.c_str()); + return ABT_None; + } + + return ab_type; + } + + // Returns single, scoped bot + static Bot* AsGroupMember_ByClass(Client *bot_owner, Client *bot_grouped_player, uint8 cls, bool petless = false) { + if (!bot_owner || !bot_grouped_player) + return nullptr; + if (!bot_grouped_player->GetGroup()) + return nullptr; + + std::list group_list; + bot_grouped_player->GetGroup()->GetMemberList(group_list); + for (auto member_iter : group_list) { + if (!MyBots::IsMyBot(bot_owner, member_iter)) + continue; + if (member_iter->GetClass() != cls) + continue; + if (petless && member_iter->GetPet()) + continue; + + return static_cast(member_iter); + } + + return nullptr; + } + + static Bot* AsGroupMember_ByMinLevelAndClass(Client *bot_owner, Client *bot_grouped_player, uint8 minlvl, uint8 cls, bool petless = false) { + // This function can be nixed if we can enforce bot level as owner level..and the level check can then be moved to the spell loop in the command function + if (!bot_owner || !bot_grouped_player) + return nullptr; + if (!bot_grouped_player->GetGroup()) + return nullptr; + + std::list group_list; + bot_grouped_player->GetGroup()->GetMemberList(group_list); + for (auto member_iter : group_list) { + if (!MyBots::IsMyBot(bot_owner, member_iter)) + continue; + if (member_iter->GetLevel() < minlvl || member_iter->GetClass() != cls) + continue; + if (petless && member_iter->GetPet()) + continue; + + return static_cast(member_iter); + } + + return nullptr; + } + + static Bot* AsSpawned_ByClass(Client *bot_owner, std::list &sbl, uint8 cls, bool petless = false) { + if (!bot_owner) + return nullptr; + + for (auto bot_iter : sbl) { + if (!MyBots::IsMyBot(bot_owner, bot_iter)) + continue; + if (bot_iter->GetClass() != cls) + continue; + if (petless && bot_iter->GetPet()) + continue; + + return bot_iter; + } + + return nullptr; + } + + static Bot* AsSpawned_ByMinLevelAndClass(Client *bot_owner, std::list &sbl, uint8 minlvl, uint8 cls, bool petless = false) { + // This function can be nixed if we can enforce bot level as owner level..and the level check can then be moved to the spell loop in the command function + if (!bot_owner) + return nullptr; + + for (auto bot_iter : sbl) { + if (!MyBots::IsMyBot(bot_owner, bot_iter)) + continue; + if (bot_iter->GetLevel() < minlvl || bot_iter->GetClass() != cls) + continue; + if (petless && bot_iter->GetPet()) + continue; + + return bot_iter; + } + + return nullptr; + } + + static Bot* AsTarget_ByBot(Client *bot_owner) { + if (!bot_owner || !MyBots::IsMyBot(bot_owner, bot_owner->GetTarget())) + return nullptr; + + return bot_owner->GetTarget()->CastToBot(); + } + + static Bot* AsNamed_ByBot(Client *bot_owner, std::string bot_name) { + if (!bot_owner || bot_name.empty()) + return nullptr; + + std::list selectable_bot_list; + MyBots::PopulateSBL_BySpawnedBots(bot_owner, selectable_bot_list); + for (auto bot_iter : selectable_bot_list) { + if (!bot_name.compare(bot_iter->GetCleanName())) + return bot_iter; + } + + return nullptr; + } + + static Bot* Select_ByClass(Client* bot_owner, BCEnum::TType target_type, std::list& sbl, uint8 cls, Mob* target_mob = nullptr, bool petless = false) { + if (!bot_owner || sbl.empty()) + return nullptr; + + for (auto bot_iter : sbl) { + if (!MyBots::IsMyBot(bot_owner, bot_iter)) + continue; + if (bot_iter->GetClass() != cls) + continue; + if (petless && bot_iter->GetPet()) + continue; + if (target_type == BCEnum::TT_GroupV1) { + if (!target_mob) + return nullptr; + else if (bot_iter->GetGroup() != target_mob->GetGroup()) + continue; + } + + return bot_iter; + } + + return nullptr; + } + + static Bot* Select_ByMinLevelAndClass(Client* bot_owner, BCEnum::TType target_type, std::list& sbl, uint8 minlvl, uint8 cls, Mob* target_mob = nullptr, bool petless = false) { + if (!bot_owner || sbl.empty()) + return nullptr; + + for (auto bot_iter : sbl) { + if (!MyBots::IsMyBot(bot_owner, bot_iter)) + continue; + if (bot_iter->GetLevel() < minlvl || bot_iter->GetClass() != cls) + continue; + if (petless && bot_iter->GetPet()) + continue; + if (target_type == BCEnum::TT_GroupV1) { + if (!target_mob) + return nullptr; + else if (bot_iter->GetGroup() != target_mob->GetGroup()) + continue; + } + + return bot_iter; + } + + return nullptr; + } + + // Filters actual 'sbl' list + static void Filter_ByClasses(Client* bot_owner, std::list& sbl, uint16 class_mask) { + sbl.remove_if([bot_owner](Bot* l) { return (!MyBots::IsMyBot(bot_owner, l)); }); + sbl.remove_if([class_mask](const Bot* l) { return (GetPlayerClassBit(l->GetClass()) & (~class_mask)); }); + } + + static void Filter_ByMinLevel(Client* bot_owner, std::list& sbl, uint8 min_level) { + sbl.remove_if([bot_owner](Bot* l) { return (!MyBots::IsMyBot(bot_owner, l)); }); + sbl.remove_if([min_level](const Bot* l) { return (l->GetLevel() < min_level); }); + } + + static void Filter_ByArcher(Client* bot_owner, std::list& sbl) { + sbl.remove_if([bot_owner](Bot* l) { return (!MyBots::IsMyBot(bot_owner, l)); }); + sbl.remove_if([bot_owner](Bot* l) { return (!l->IsBotArcher()); }); + } + + static void Filter_ByHighestSkill(Client* bot_owner, std::list& sbl, EQEmu::skills::SkillType skill_type, float& skill_value) { + sbl.remove_if([bot_owner](Bot* l) { return (!MyBots::IsMyBot(bot_owner, l)); }); + skill_value = 0.0f; + + float mod_skill_value = 0.0f; + const Bot* skilled_bot = nullptr; + for (auto bot_iter : sbl) { + float base_skill_value = bot_iter->GetSkill(skill_type); + if (base_skill_value == 0.0f) + continue; + + mod_skill_value = base_skill_value; + for (int16 index = EQEmu::legacy::EQUIPMENT_BEGIN; index <= EQEmu::legacy::EQUIPMENT_END; ++index) { + const ItemInst* indexed_item = bot_iter->GetBotItem(index); + if (indexed_item && indexed_item->GetItem()->SkillModType == skill_type) + mod_skill_value += (base_skill_value * (((float)indexed_item->GetItem()->SkillModValue) / 100.0f)); + } + + if (!skilled_bot) { + skill_value = mod_skill_value; + skilled_bot = bot_iter; + } + else if (mod_skill_value > skill_value) { + skill_value = mod_skill_value; + skilled_bot = bot_iter; + } + } + + sbl.remove_if([skilled_bot](const Bot* l) { return (l != skilled_bot); }); + } + + static void Filter_ByHighestPickLock(Client* bot_owner, std::list& sbl, float& pick_lock_value) { + sbl.remove_if([bot_owner](Bot* l) { return (!MyBots::IsMyBot(bot_owner, l)); }); + sbl.remove_if([bot_owner](const Bot* l) { return (l->GetClass() != ROGUE && l->GetClass() != BARD); }); + sbl.remove_if([bot_owner](const Bot* l) { return (l->GetClass() == ROGUE && l->GetLevel() < 5); }); + sbl.remove_if([bot_owner](const Bot* l) { return (l->GetClass() == BARD && l->GetLevel() < 40); }); + + ActionableBots::Filter_ByHighestSkill(bot_owner, sbl, EQEmu::skills::SkillPickLock, pick_lock_value); + } +}; + + +/* + * bot commands go below here + */ +void bot_command_actionable(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_actionable", sep->arg[0], "actionable")) + return; + + c->Message(m_message, "Actionable command arguments:"); + + c->Message(m_usage, "target - selects target as single bot .. use ^command [target] or imply by empty actionable argument"); + c->Message(m_usage, "byname [name] - selects single bot by name"); + c->Message(m_usage, "ownergroup - selects all bots in the owner's group"); + c->Message(m_usage, "botgroup [name] - selects members of a bot-group by its name"); + c->Message(m_usage, "targetgroup - selects all bots in target's group"); + c->Message(m_usage, "namesgroup [name] - selects all bots in name's group"); + c->Message(m_usage, "healrotation [name] - selects all member and target bots of a heal rotation where name is a member"); + c->Message(m_usage, "healrotationmembers [name] - selects all member bots of a heal rotation where name is a member"); + c->Message(m_usage, "healrotationtargets [name] - selects all target bots of a heal rotation where name is a member"); + c->Message(m_usage, "spawned - selects all spawned bots"); + c->Message(m_usage, "all - selects all spawned bots .. argument use indicates en masse database updating"); + + c->Message(m_message, "You may only select your bots as actionable"); +} + +void bot_command_aggressive(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Stance]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Stance) || helper_command_alias_fail(c, "bot_command_aggressive", sep->arg[0], "aggressive")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotationtargets | spawned] ([actionable_name]))", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Stance); + return; + } + const int ab_mask = ActionableBots::ABM_Type1; + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + sbl.remove(nullptr); + + int success_count = 0; + int candidate_count = sbl.size(); + for (auto list_iter : *local_list) { + if (sbl.empty()) + break; + + auto local_entry = list_iter->SafeCastToStance(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->stance_type != BCEnum::StT_Aggressive) + continue; + + for (auto bot_iter = sbl.begin(); bot_iter != sbl.end(); ) { + Bot* my_bot = *bot_iter; + if (local_entry->caster_class != my_bot->GetClass()) { + ++bot_iter; + continue; + } + if (local_entry->spell_level > my_bot->GetLevel()) { + ++bot_iter; + continue; + } + + my_bot->InterruptSpell(); + if (candidate_count == 1) + Bot::BotGroupSay(my_bot, "Using '%s'", spells[local_entry->spell_id].name); + my_bot->UseDiscipline(local_entry->spell_id, my_bot->GetID()); + ++success_count; + + bot_iter = sbl.erase(bot_iter); + } + } + + c->Message(m_action, "%i of %i bots have used aggressive disciplines", success_count, candidate_count); +} + +void bot_command_attack(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_attack", sep->arg[0], "attack")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [actionable: byname | ownergroup | botgroup | namesgroup | healrotation | spawned] ([actionable_name])", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_Type2; + + Mob* target_mob = ActionableTarget::AsSingle_ByAttackable(c); + if (!target_mob) { + c->Message(m_fail, "You must an enemy to use this command"); + return; + } + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + sbl.remove(nullptr); + for (auto bot_iter : sbl) { + bot_iter->WipeHateList(); + bot_iter->AddToHateList(target_mob, 1); + if (!bot_iter->GetPet()) + continue; + + bot_iter->GetPet()->WipeHateList(); + bot_iter->GetPet()->AddToHateList(target_mob, 1); + } + if (sbl.size() == 1) + Bot::BotGroupSay(sbl.front(), "Attacking %s", target_mob->GetCleanName()); + else + c->Message(m_action, "%i of your bots are attacking %s", sbl.size(), target_mob->GetCleanName()); +} + +void bot_command_bind_affinity(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_BindAffinity]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_BindAffinity) || helper_command_alias_fail(c, "bot_command_bind_affinity", sep->arg[0], "bindaffinity")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_BindAffinity); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + for (auto list_iter : *local_list) { + auto local_entry = list_iter; + if (helper_spell_check_fail(local_entry)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + // Cast effect message is not being generated + if (helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id)) + c->Message(m_action, "Successfully bound %s to this location", target_mob->GetCleanName()); + else + c->Message(m_fail, "Failed to bind %s to this location", target_mob->GetCleanName()); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_bot(Client *c, const Seperator *sep) +{ + /* VS2012 code - begin */ + std::list subcommand_list; + subcommand_list.push_back("botappearance"); + subcommand_list.push_back("botcamp"); + subcommand_list.push_back("botclone"); + subcommand_list.push_back("botcreate"); + subcommand_list.push_back("botdelete"); + subcommand_list.push_back("botdetails"); + subcommand_list.push_back("botdyearmor"); + subcommand_list.push_back("botinspectmessage"); + subcommand_list.push_back("botfollowdistance"); + subcommand_list.push_back("botlist"); + subcommand_list.push_back("botoutofcombat"); + subcommand_list.push_back("botreport"); + subcommand_list.push_back("botspawn"); + subcommand_list.push_back("botstance"); + subcommand_list.push_back("botsummon"); + subcommand_list.push_back("bottogglearcher"); + subcommand_list.push_back("bottogglehelm"); + subcommand_list.push_back("botupdate"); + /* VS2012 code - end */ + + /* VS2013 code + const std::list subcommand_list = { + "botappearance", "botcamp", "botclone", "botcreate", "botdelete", "botdetails", "botdyearmor", "botinspectmessage", "botfollowdistance", + "botlist", "botoutofcombat", "botreport", "botspawn", "botstance", "botsummon", "bottogglearcher", "bottogglehelm", "botupdate" + }; + */ + + if (helper_command_alias_fail(c, "bot_command_bot", sep->arg[0], "bot")) + return; + + helper_send_available_subcommands(c, "bot", subcommand_list); +} + +void bot_command_botgroup(Client *c, const Seperator *sep) +{ + /* VS2012 code - begin */ + std::list subcommand_list; + subcommand_list.push_back("botgroupaddmember"); + subcommand_list.push_back("botgroupcreate"); + subcommand_list.push_back("botgroupdelete"); + subcommand_list.push_back("botgrouplist"); + subcommand_list.push_back("botgroupload"); + subcommand_list.push_back("botgroupremovemember"); + /* VS2012 code - end */ + + /* VS2013 code + const std::list subcommand_list = { + "botgroupaddmember", "botgroupcreate", "botgroupdelete", "botgrouplist", "botgroupload", "botgroupremovemember" + }; + */ + + if (helper_command_alias_fail(c, "bot_command_botgroup", sep->arg[0], "botgroup")) + return; + + helper_send_available_subcommands(c, "bot-group", subcommand_list); +} + +void bot_command_charm(Client *c, const Seperator *sep) +{ + auto local_list = &bot_command_spells[BCEnum::SpT_Charm]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Charm) || helper_command_alias_fail(c, "bot_command_charm", sep->arg[0], "charm")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([option: dire])", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Charm); + return; + } + + bool dire = false; + std::string dire_arg = sep->arg[1]; + if (!dire_arg.compare("dire")) + dire = true; + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToCharm(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->dire != dire) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, ENEMY); + if (!target_mob) + continue; + if (target_mob->IsCharmed()) { + c->Message(m_fail, "Your is already charmed"); + return; + } + + if (spells[local_entry->spell_id].max[EFFECTIDTOINDEX(1)] < target_mob->GetLevel()) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob, true); + if (!my_bot) + continue; + + uint32 dont_root_before = 0; + if (helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id, true, &dont_root_before)) + target_mob->SetDontRootMeBefore(dont_root_before); + + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_cure(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Cure]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Cure) || helper_command_alias_fail(c, "bot_command_cure", sep->arg[0], "cure")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [ailment: blindness | disease | poison | curse | corruption]", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Cure); + return; + } + + std::string ailment_arg = sep->arg[1]; + + auto ailment_type = BCEnum::AT_None; + if (!ailment_arg.compare("blindness")) + ailment_type = BCEnum::AT_Blindness; + else if (!ailment_arg.compare("disease")) + ailment_type = BCEnum::AT_Disease; + else if (!ailment_arg.compare("poison")) + ailment_type = BCEnum::AT_Poison; + else if (!ailment_arg.compare("curse")) + ailment_type = BCEnum::AT_Curse; + else if (!ailment_arg.compare("corruption")) + ailment_type = BCEnum::AT_Corruption; + + if (ailment_type == BCEnum::AT_None) { + c->Message(m_fail, "You must specify a cure [ailment] to use this command"); + return; + } + + local_list->sort([ailment_type](STBaseEntry* l, STBaseEntry* r) { + auto _l = l->SafeCastToCure(), _r = r->SafeCastToCure(); + if (_l->cure_value[AILMENTIDTOINDEX(ailment_type)] < _r->cure_value[AILMENTIDTOINDEX(ailment_type)]) + return true; + if (_l->cure_value[AILMENTIDTOINDEX(ailment_type)] == _r->cure_value[AILMENTIDTOINDEX(ailment_type)] && spells[_l->spell_id].mana < spells[_r->spell_id].mana) + return true; + if (_l->cure_value[AILMENTIDTOINDEX(ailment_type)] == _r->cure_value[AILMENTIDTOINDEX(ailment_type)] && spells[_l->spell_id].mana == spells[_r->spell_id].mana && _l->cure_total < _r->cure_total) + return true; + + return false; + }); + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToCure(); + if (helper_spell_check_fail(local_entry)) + continue; + if (!local_entry->cure_value[AILMENTIDTOINDEX(ailment_type)]) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_defensive(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Stance]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Stance) || helper_command_alias_fail(c, "bot_command_defensive", sep->arg[0], "defensive")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotationtargets | spawned] ([actionable_name]))", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Stance); + return; + } + const int ab_mask = ActionableBots::ABM_Type1; + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + sbl.remove(nullptr); + + int success_count = 0; + int candidate_count = sbl.size(); + for (auto list_iter : *local_list) { + if (sbl.empty()) + break; + + auto local_entry = list_iter->SafeCastToStance(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->stance_type != BCEnum::StT_Aggressive) + continue; + + for (auto bot_iter = sbl.begin(); bot_iter != sbl.end(); ) { + Bot* my_bot = *bot_iter; + if (local_entry->caster_class != my_bot->GetClass()) { + ++bot_iter; + continue; + } + if (local_entry->spell_level > my_bot->GetLevel()) { + ++bot_iter; + continue; + } + + my_bot->InterruptSpell(); + if (candidate_count == 1) + Bot::BotGroupSay(my_bot, "Using '%s'", spells[local_entry->spell_id].name); + my_bot->UseDiscipline(local_entry->spell_id, my_bot->GetID()); + ++success_count; + + bot_iter = sbl.erase(bot_iter); + } + } + + c->Message(m_action, "%i of %i bots have used defensive disciplines", success_count, candidate_count); +} + +void bot_command_depart(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Depart]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Depart) || helper_command_alias_fail(c, "bot_command_depart", sep->arg[0], "depart")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [list | destination] ([option: single])", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Depart); + return; + } + + bool single = false; + std::string single_arg = sep->arg[2]; + if (!single_arg.compare("single")) + single = true; + + std::string destination = sep->arg[1]; + if (!destination.compare("list")) { + Bot* my_druid_bot = ActionableBots::AsGroupMember_ByClass(c, c, DRUID); + Bot* my_wizard_bot = ActionableBots::AsGroupMember_ByClass(c, c, WIZARD); + helper_command_depart_list(c, my_druid_bot, my_wizard_bot, local_list, single); + return; + } + else if (destination.empty()) { + c->Message(m_fail, "A [destination] or [list] argument is required to use this command"); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToDepart(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->single != single) + continue; + if (destination.compare(spells[local_entry->spell_id].teleport_zone)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_escape(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Escape]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Escape) || helper_command_alias_fail(c, "bot_command_escape", sep->arg[0], "escape")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([option: lesser])", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Escape); + return; + } + + bool use_lesser = false; + if (!strcasecmp(sep->arg[1], "lesser")) + use_lesser = true; + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToEscape(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->lesser != use_lesser) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_find_aliases(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_find_aliases", sep->arg[0], "findaliases")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [alias | command]", sep->arg[0]); + return; + } + + auto find_iter = bot_command_aliases.find(sep->arg[1]); + if (find_iter == bot_command_aliases.end()) { + c->Message(m_fail, "No bot commands or aliases match '%s'", sep->arg[1]); + return; + } + + auto command_iter = bot_command_list.find(find_iter->second); + if (find_iter->second.empty() || command_iter == bot_command_list.end()) { + c->Message(m_unknown, "An unknown condition has occurred..."); + return; + } + + c->Message(m_message, "Available bot command aliases for '%s':", command_iter->first.c_str()); + + int bot_command_aliases_shown = 0; + for (auto alias_iter : bot_command_aliases) { + if (strcasecmp(find_iter->second.c_str(), alias_iter.second.c_str()) || c->Admin() < command_iter->second->access) + continue; + + c->Message(m_usage, "%c%s", BOT_COMMAND_CHAR, alias_iter.first.c_str()); + ++bot_command_aliases_shown; + } + c->Message(m_message, "%d bot command alias%s listed.", bot_command_aliases_shown, bot_command_aliases_shown != 1 ? "es" : ""); +} + +void bot_command_follow(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_follow", sep->arg[0], "follow")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([option: reset]) [actionable: byname | ownergroup | botgroup | namesgroup | healrotation | spawned] ([actionable_name])", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_Type2; + + bool reset = false; + int ab_arg = 1; + int name_arg = 2; + Mob* target_mob = nullptr; + + std::string reset_arg = sep->arg[1]; + if (!reset_arg.compare("reset")) { + reset = true; + ab_arg = 2; + name_arg = 3; + } + else { + target_mob = ActionableTarget::VerifyFriendly(c, BCEnum::TT_Single); + if (!target_mob) { + c->Message(m_fail, "You must a friendly mob to use this command"); + return; + } + } + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, sep->arg[name_arg]) == ActionableBots::ABT_None) + return; + + sbl.remove(nullptr); + for (auto bot_iter : sbl) { + bot_iter->WipeHateList(); + auto my_group = bot_iter->GetGroup(); + if (my_group) { + if (reset) { + if (!my_group->GetLeader() || my_group->GetLeader() == bot_iter) + bot_iter->SetFollowID(c->GetID()); + else + bot_iter->SetFollowID(my_group->GetLeader()->GetID()); + } + else { + if (bot_iter == target_mob) + bot_iter->SetFollowID(c->GetID()); + else + bot_iter->SetFollowID(target_mob->GetID()); + } + } + else { + bot_iter->SetFollowID(0); + } + if (!bot_iter->GetPet()) + continue; + + bot_iter->GetPet()->WipeHateList(); + bot_iter->GetPet()->SetFollowID(bot_iter->GetID()); + } + if (sbl.size() == 1) { + Mob* follow_mob = entity_list.GetMob(sbl.front()->GetFollowID()); + Bot::BotGroupSay(sbl.front(), "Following %s", ((follow_mob) ? (follow_mob->GetCleanName()) : ("'nullptr'"))); + } + else { + if (reset) + c->Message(m_action, "%i of your bots are following their default assignments", sbl.size()); + else + c->Message(m_action, "%i of your bots are following %s", sbl.size(), target_mob->GetCleanName()); + } +} + +void bot_command_guard(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_guard", sep->arg[0], "guard")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [actionable: target | byname | ownergroup | botgroup | namesgroup | healrotation | spawned] ([actionable_name])", sep->arg[0]); + return; + } + const int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_Type2); + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + 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); + } + if (sbl.size() == 1) + Bot::BotGroupSay(sbl.front(), "Guarding this position"); + else + c->Message(m_action, "%i of your bots are guarding their positions", sbl.size()); +} + +void bot_command_heal_rotation(Client *c, const Seperator *sep) +{ + /* VS2012 code - begin */ + std::list subcommand_list; + subcommand_list.push_back("healrotationadaptivetargeting"); + subcommand_list.push_back("healrotationaddmember"); + subcommand_list.push_back("healrotationaddtarget"); + subcommand_list.push_back("healrotationadjustcritical"); + subcommand_list.push_back("healrotationadjustsafe"); + subcommand_list.push_back("healrotationcastoverride"); + subcommand_list.push_back("healrotationchangeinterval"); + subcommand_list.push_back("healrotationclearhot"); + subcommand_list.push_back("healrotationcleartargets"); + subcommand_list.push_back("healrotationcreate"); + subcommand_list.push_back("healrotationdelete"); + subcommand_list.push_back("healrotationfastheals"); + subcommand_list.push_back("healrotationlist"); + subcommand_list.push_back("healrotationremovemember"); + subcommand_list.push_back("healrotationremovetarget"); + subcommand_list.push_back("healrotationresetlimits"); + subcommand_list.push_back("healrotationsave"); + subcommand_list.push_back("healrotationsethot"); + subcommand_list.push_back("healrotationstart"); + subcommand_list.push_back("healrotationstop"); + /* VS2012 code - end */ + + /* VS2013 code + const std::list subcommand_list = { + "healrotationadaptivetargeting", "healrotationaddmember", "healrotationaddtarget", "healrotationadjustcritical", "healrotationadjustsafe", + "healrotationcastoverride", "healrotationchangeinterval", "healrotationclearhot", "healrotationcleartargets", "healrotationcreate", + "healrotationdelete", "healrotationfastheals", "healrotationlist", "healrotationremovemember", "healrotationremovetarget", "healrotationsave", + "healrotationresetlimits", "healrotationsethot", "healrotationstart", "healrotationstop" + }; + */ + + if (helper_command_alias_fail(c, "bot_command_heal_rotation", sep->arg[0], "healrotation")) + return; + +#if (EQDEBUG >= 12) + while (c->Admin() >= 250) { + if (strcasecmp(sep->arg[1], "shone")) { break; } + Bot* my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot || !(my_bot->IsHealRotationMember())) { break; } + auto tlist = (*my_bot->MemberOfHealRotation())->TargetList(); + if (tlist->empty()) { break; } + for (auto tlist_iter : *tlist) { + if (tlist_iter) + tlist_iter->SetHP((tlist_iter->GetMaxHP() / 100 + 1)); + } + return; + } +#endif + + helper_send_available_subcommands(c, "bot heal rotation", subcommand_list); +} + +void bot_command_help(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_help", sep->arg[0], "help")) + return; + + c->Message(m_message, "Available EQEMu bot commands:"); + + int bot_commands_shown = 0; + for (auto command_iter : bot_command_list) { + if (sep->arg[1][0] && command_iter.first.find(sep->arg[1]) == std::string::npos) + continue; + if (c->Admin() < command_iter.second->access) + continue; + + c->Message(m_usage, "%c%s - %s", BOT_COMMAND_CHAR, command_iter.first.c_str(), command_iter.second->desc == nullptr ? "[no description]" : command_iter.second->desc); + ++bot_commands_shown; + } + c->Message(m_message, "%d bot command%s listed.", bot_commands_shown, bot_commands_shown != 1 ? "s" : ""); + c->Message(m_note, "type %ccommand [help | usage] for more information", BOT_COMMAND_CHAR); +} + +void bot_command_hold(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_hold", sep->arg[0], "hold")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: ] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_NoFilter; + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + sbl.remove(nullptr); + for (auto bot_iter : sbl) + bot_iter->SetPauseAI(true); + + c->Message(m_action, "%i of your bots %s suspended", sbl.size(), ((sbl.size() != 1) ? ("are") : ("is"))); +} + +void bot_command_identify(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Identify]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Identify) || helper_command_alias_fail(c, "bot_command_identify", sep->arg[0], "identify")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Identify); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter; + if (helper_spell_check_fail(local_entry)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_inventory(Client *c, const Seperator *sep) +{ + /* VS2012 code - begin */ + std::list subcommand_list; + subcommand_list.push_back("inventorygive"); + subcommand_list.push_back("inventorylist"); + subcommand_list.push_back("inventoryremove"); + subcommand_list.push_back("inventorywindow"); + /* VS2012 code - end */ + + /* VS2013 code + const std::list subcommand_list = { "inventorygive", "inventorylist", "inventoryremove", "inventorywindow" }; + */ + + if (helper_command_alias_fail(c, "bot_command_inventory", sep->arg[0], "inventory")) + return; + + helper_send_available_subcommands(c, "bot inventory", subcommand_list); +} + +void bot_command_invisibility(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Invisibility]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Invisibility) || helper_command_alias_fail(c, "bot_command_invisibility", sep->arg[0], "invisibility")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [invisibility: living | undead | animal | see]", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Invisibility); + return; + } + + std::string invisibility = sep->arg[1]; + + BCEnum::IType invisibility_type = BCEnum::IT_None; + if (!invisibility.compare("living")) + invisibility_type = BCEnum::IT_Living; + else if (!invisibility.compare("undead")) + invisibility_type = BCEnum::IT_Undead; + else if (!invisibility.compare("animal")) + invisibility_type = BCEnum::IT_Animal; + else if (!invisibility.compare("see")) + invisibility_type = BCEnum::IT_See; + + if (invisibility_type == BCEnum::IT_None) { + c->Message(m_fail, "You must specify an [invisibility]"); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToInvisibility(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->invis_type != invisibility_type) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_levitation(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Levitation]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Levitation) || helper_command_alias_fail(c, "bot_command_levitation", sep->arg[0], "levitation")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Levitation); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter; + if (helper_spell_check_fail(local_entry)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_lull(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Lull]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Lull) || helper_command_alias_fail(c, "bot_command_lull", sep->arg[0], "lull")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Lull); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + for (auto list_iter : *local_list) { + auto local_entry = list_iter; + if (helper_spell_check_fail(local_entry)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, ENEMY); + if (!target_mob) + continue; + + //if (spells[local_entry->spell_id].max[EFFECTIDTOINDEX(3)] && spells[local_entry->spell_id].max[EFFECTIDTOINDEX(3)] < target_mob->GetLevel()) + // continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + uint32 dont_root_before = 0; + if (helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id, true, &dont_root_before)) + target_mob->SetDontRootMeBefore(dont_root_before); + + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_mesmerize(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Mesmerize]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Mesmerize) || helper_command_alias_fail(c, "bot_command_mesmerize", sep->arg[0], "mesmerize")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Mesmerize); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + for (auto list_iter : *local_list) { + auto local_entry = list_iter; + if (helper_spell_check_fail(local_entry)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, ENEMY); + if (!target_mob) + continue; + + if (spells[local_entry->spell_id].max[EFFECTIDTOINDEX(1)] < target_mob->GetLevel()) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + uint32 dont_root_before = 0; + if (helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id, true, &dont_root_before)) + target_mob->SetDontRootMeBefore(dont_root_before); + + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_movement_speed(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_MovementSpeed]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_MovementSpeed) || helper_command_alias_fail(c, "bot_command_movement_speed", sep->arg[0], "movementspeed")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([group])", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_MovementSpeed); + return; + } + + bool group = false; + std::string group_arg = sep->arg[1]; + if (!group_arg.compare("group")) + group = true; + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToMovementSpeed(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->group != group) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_pet(Client *c, const Seperator *sep) +{ + /* VS2012 code - begin */ + std::list subcommand_list; + subcommand_list.push_back("petremove"); + subcommand_list.push_back("petsettype"); + /* VS2012 code - end */ + + /* VS2013 code + const std::list subcommand_list = { "petremove", "petsettype" }; + */ + + if (helper_command_alias_fail(c, "bot_command_pet", sep->arg[0], "pet")) + return; + + helper_send_available_subcommands(c, "bot pet", subcommand_list); +} + +void bot_command_pick_lock(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_pick_lock", sep->arg[0], "picklock")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s", sep->arg[0]); + c->Message(m_note, "requires one of the following bot classes:"); + c->Message(m_message, "Rogue(5) or Bard(40)"); + return; + } + + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + float pick_lock_value = 0.0f; + ActionableBots::Filter_ByHighestPickLock(c, sbl, pick_lock_value); + if (sbl.empty()) { + c->Message(m_fail, "No bots are capable of performing this action"); + return; + } + + Bot* my_bot = sbl.front(); + + my_bot->InterruptSpell(); + Bot::BotGroupSay(my_bot, "Attempting to pick the lock.."); + + std::list door_list; + entity_list.GetDoorsList(door_list); + + int door_count = 0, open_count = 0; + for (auto door_iter : door_list) { + if (!door_iter || door_iter->IsDoorOpen()) + continue; + + glm::tvec4 diff = (c->GetPosition() - door_iter->GetPosition()); + + float curdist = ((diff.x * diff.x) + (diff.y * diff.y)); + float curelev = (diff.z * diff.z); +#if (EQDEBUG >= 11) + if (curdist <= 130 && curelev <= 65 && curelev >= 25) // 2D limit is '130' (x^2 + y^2), 1D theoretically should be '65' (z^2) + Log.Out(Logs::Detail, Logs::Doors, "bot_command_pick_lock(): DoorID: %i - Elevation difference failure within theoretical limit (%f <= 65.0)", door_iter->GetDoorID(), curelev); +#endif + if (curelev >= 25 || curdist > 130) // changed curelev from '10' to '25' - requiring diff.z to be less than '5' + continue; + + ++door_count; + if (pick_lock_value >= door_iter->GetLockpick()) { + door_iter->ForceOpen(my_bot); + ++open_count; + } + else { + Bot::BotGroupSay(my_bot, "I am not skilled enough for this lock..."); + } + } + c->Message(m_action, "%i door%s attempted - %i door%s successful", door_count, ((door_count != 1) ? ("s") : ("")), open_count, ((open_count != 1) ? ("s") : (""))); +} + +void bot_command_pull(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_pull", sep->arg[0], "pull")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s", sep->arg[0]); + return; + } + int ab_mask = ActionableBots::ABM_OwnerGroup; // existing behavior - need to add c->IsGrouped() check and modify code if different behavior is desired + + std::list sbl; + if (ActionableBots::PopulateSBL(c, "ownergroup", sbl, ab_mask) == ActionableBots::ABT_None) + return; + sbl.remove(nullptr); + + auto target_mob = ActionableTarget::VerifyEnemy(c, BCEnum::TT_Single); + if (!target_mob) { + c->Message(m_fail, "Your current target is not attackable"); + return; + } + + Bot* bot_puller = nullptr; + for (auto bot_iter : sbl) { + if (!bot_iter->IsArcheryRange(target_mob)) + continue; + + Bot::BotGroupSay(bot_iter, "Attempting to pull %s..", target_mob->GetCleanName()); + bot_iter->InterruptSpell(); + bot_iter->BotRangedAttack(target_mob); + bot_puller = bot_iter; + break; + } + + helper_no_available_bots(c, bot_puller); +} + +void bot_command_release(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_release", sep->arg[0], "release")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: ] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_NoFilter; + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + sbl.remove(nullptr); + for (auto bot_iter : sbl) { + bot_iter->WipeHateList(); + bot_iter->SetPauseAI(false); + } + + c->Message(m_action, "%i of your bots %s unsuspended", sbl.size(), ((sbl.size() != 1) ? ("are") : ("is"))); +} + +void bot_command_resistance(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Resistance]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Resistance) || helper_command_alias_fail(c, "bot_command_resistance", sep->arg[0], "resistance")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [resistance: fire | cold | poison | disease | magic | corruption]", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Resistance); + return; + } + + std::string resistance_arg = sep->arg[1]; + + auto resistance_type = BCEnum::RT_None; + if (!resistance_arg.compare("fire")) + resistance_type = BCEnum::RT_Fire; + else if (!resistance_arg.compare("cold")) + resistance_type = BCEnum::RT_Cold; + else if (!resistance_arg.compare("poison")) + resistance_type = BCEnum::RT_Poison; + else if (!resistance_arg.compare("disease")) + resistance_type = BCEnum::RT_Disease; + else if (!resistance_arg.compare("magic")) + resistance_type = BCEnum::RT_Magic; + else if (!resistance_arg.compare("corruption")) + resistance_type = BCEnum::RT_Corruption; + + if (resistance_type == BCEnum::RT_None) { + c->Message(m_fail, "You must specify a [resistance]"); + return; + } + + local_list->sort([resistance_type](STBaseEntry* l, STBaseEntry* r) { + auto _l = l->SafeCastToResistance(), _r = r->SafeCastToResistance(); + if (_l->resist_value[RESISTANCEIDTOINDEX(resistance_type)] > _r->resist_value[RESISTANCEIDTOINDEX(resistance_type)]) + return true; + if (_l->resist_value[RESISTANCEIDTOINDEX(resistance_type)] == _r->resist_value[RESISTANCEIDTOINDEX(resistance_type)] && spells[_l->spell_id].mana < spells[_r->spell_id].mana) + return true; + if (_l->resist_value[RESISTANCEIDTOINDEX(resistance_type)] == _r->resist_value[RESISTANCEIDTOINDEX(resistance_type)] && spells[_l->spell_id].mana == spells[_r->spell_id].mana && _l->resist_total > _r->resist_total) + return true; + + return false; + }); + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToResistance(); + if (helper_spell_check_fail(local_entry)) + continue; + if (!local_entry->resist_value[RESISTANCEIDTOINDEX(resistance_type)]) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_resurrect(Client *c, const Seperator *sep) +{ + // Obscure bot spell code prohibits the aoe portion from working correctly... + + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Resurrect]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Resurrect) || helper_command_alias_fail(c, "bot_command_resurrect", sep->arg[0], "resurrect")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + //c->Message(m_usage, "usage: %s ([option: aoe])", sep->arg[0]); + c->Message(m_usage, "usage: %s", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Resurrect); + return; + } + + bool aoe = false; + //std::string aoe_arg = sep->arg[1]; + //if (!aoe_arg.compare("aoe")) + // aoe = true; + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToResurrect(); + if (helper_spell_check_fail(local_entry)) + continue; + //if (local_entry->aoe != aoe) + // continue; + if (local_entry->aoe) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + //if (!target_mob && !local_entry->aoe) + // continue; + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + //if (local_entry->aoe) + // target_mob = my_bot; + + uint32 dont_root_before = 0; + if (helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id, true, &dont_root_before)) + target_mob->SetDontRootMeBefore(dont_root_before); + + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_rune(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Rune]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Rune) || helper_command_alias_fail(c, "bot_command_rune", sep->arg[0], "rune")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Rune); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter; + if (helper_spell_check_fail(local_entry)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_send_home(Client *c, const Seperator *sep) +{ + // Obscure bot spell code prohibits the aoe portion from working correctly... + + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_SendHome]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_SendHome) || helper_command_alias_fail(c, "bot_command_send_home", sep->arg[0], "sendhome")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([option: group])", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_SendHome); + return; + } + + bool group = false; + std::string group_arg = sep->arg[1]; + if (!group_arg.compare("group")) + group = true; + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToSendHome(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->group != group) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_size(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Size]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Size) || helper_command_alias_fail(c, "bot_command_size", sep->arg[0], "size")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [grow | shrink]", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Size); + return; + } + + std::string size_arg = sep->arg[1]; + auto size_type = BCEnum::SzT_Reduce; + if (!size_arg.compare("grow")) { + size_type = BCEnum::SzT_Enlarge; + } + else if (size_arg.compare("shrink")) { + c->Message(m_fail, "This command requires a [grow | shrink] argument"); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToSize(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->size_type != size_type) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_summon_corpse(Client *c, const Seperator *sep) +{ + // Same methodology as old command..but, does not appear to work... (note: didn't work there, either...) + + // temp + c->Message(m_fail, "This command is currently unavailable..."); + return; + + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_SummonCorpse]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_SummonCorpse) || helper_command_alias_fail(c, "bot_command_summon_corpse", sep->arg[0], "summoncorpse")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_SummonCorpse); + return; + } + + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter; + if (helper_spell_check_fail(local_entry)) + continue; + + auto target_mob = ActionableTarget::AsSingle_ByPlayer(c); + if (!target_mob) + continue; + + if (spells[local_entry->spell_id].base[EFFECTIDTOINDEX(1)] < target_mob->GetLevel()) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_command_taunt(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_taunt", sep->arg[0], "taunt")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([option: on | off]) ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotationtargets | spawned] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_Type1; + + std::string arg1 = sep->arg[1]; + + bool taunt_state = false; + bool toggle_taunt = true; + int ab_arg = 1; + if (!arg1.compare("on")) { + taunt_state = true; + toggle_taunt = false; + ab_arg = 2; + } + else if (!arg1.compare("off")) { + toggle_taunt = false; + ab_arg = 2; + } + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, sep->arg[(ab_arg + 1)]) == ActionableBots::ABT_None) + return; + sbl.remove(nullptr); + + int taunting_count = 0; + for (auto bot_iter : sbl) { + if (!bot_iter->GetSkill(EQEmu::skills::SkillTaunt)) + continue; + + if (toggle_taunt) + bot_iter->SetTaunting(!bot_iter->IsTaunting()); + else + bot_iter->SetTaunting(taunt_state); + + if (sbl.size() == 1) + Bot::BotGroupSay(bot_iter, "I am %s taunting", bot_iter->IsTaunting() ? "now" : "no longer"); + + ++taunting_count; + } + + if (taunting_count) { + if (toggle_taunt) + c->Message(m_action, "%i of your bots %s toggled their taunting state", taunting_count, ((taunting_count != 1) ? ("have") : ("has"))); + else + c->Message(m_action, "%i of your bots %s %s taunting", taunting_count, ((taunting_count != 1) ? ("have") : ("has")), ((taunt_state) ? ("started") : ("stopped"))); + } + else { + c->Message(m_fail, "None of your bots are capable of taunting"); + } +} + +void bot_command_track(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_command_track", sep->arg[0], "track")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s (Ranger: [option=all: all | rare | local])", sep->arg[0]); + c->Message(m_note, "requires one of the following bot classes:"); + c->Message(m_message, "Ranger(1), Druid(20) or Bard(35)"); + return; + } + + std::string tracking_scope = sep->arg[1]; + + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + uint16 class_mask = (PLAYER_CLASS_RANGER_BIT | PLAYER_CLASS_DRUID_BIT | PLAYER_CLASS_BARD_BIT); + ActionableBots::Filter_ByClasses(c, sbl, class_mask); + + Bot* my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 1, RANGER); + if (tracking_scope.empty()) { + if (!my_bot) + my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 20, DRUID); + if (!my_bot) + my_bot = ActionableBots::AsSpawned_ByMinLevelAndClass(c, sbl, 35, BARD); + } + if (!my_bot) { + c->Message(m_fail, "No bots are capable of performing this action"); + return; + } + + int base_distance = 0; + bool track_named = false; + std::string tracking_msg; + switch (my_bot->GetClass()) { + case RANGER: + if (!tracking_scope.compare("local")) { + base_distance = 30; + tracking_msg = "Local tracking..."; + } + else if (!tracking_scope.compare("rare")) { + base_distance = 80; + bool track_named = true; + tracking_msg = "Master tracking..."; + } + else { // default to 'all' + base_distance = 80; + tracking_msg = "Advanced tracking..."; + } + break; + case DRUID: + base_distance = 30; + tracking_msg = "Local tracking..."; + break; + case BARD: + base_distance = 20; + tracking_msg = "Near tracking..."; + break; + default: + return; + } + if (!base_distance) { + c->Message(m_unknown, "An unknown codition has occurred"); + return; + } + + my_bot->InterruptSpell(); + Bot::BotGroupSay(my_bot, tracking_msg.c_str()); + entity_list.ShowSpawnWindow(c, (c->GetLevel() * base_distance), track_named); +} + +void bot_command_water_breathing(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_WaterBreathing]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_WaterBreathing) || helper_command_alias_fail(c, "bot_command_water_breathing", sep->arg[0], "waterbreathing")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_WaterBreathing); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter; + if (helper_spell_check_fail(local_entry)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + + +/* + * bot subcommands go below here + */ +void bot_subcommand_bot_appearance(Client *c, const Seperator *sep) +{ + /* VS2012 code - begin */ + std::list subcommand_list; + subcommand_list.push_back("botbeardcolor"); + subcommand_list.push_back("botbeardstyle"); + subcommand_list.push_back("botdetails"); + subcommand_list.push_back("boteyes"); + subcommand_list.push_back("botface"); + subcommand_list.push_back("bothaircolor"); + subcommand_list.push_back("bothairstyle"); + subcommand_list.push_back("botheritage"); + subcommand_list.push_back("bottattoo"); + subcommand_list.push_back("botwoad"); + /* VS2012 code - end */ + + /* VS2013 code + const std::list subcommand_list = { + "botbeardcolor", "botbeardstyle", "botdetails", "boteyes", "botface", + "bothaircolor", "bothairstyle", "botheritage", "bottattoo", "botwoad" + }; + */ + + if (helper_command_alias_fail(c, "bot_subcommand_bot_appearance", sep->arg[0], "botappearance")) + return; + + helper_send_available_subcommands(c, "bot appearance", subcommand_list); +} + +void bot_subcommand_bot_beard_color(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_beard_color", sep->arg[0], "botbeardcolor")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [value: 0-n] (Dwarves or male bots only)", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint8 uvalue = atoi(sep->arg[1]); + + auto fail_type = BCEnum::AFT_None; + if (my_bot->GetGender() != MALE && my_bot->GetRace() != DWARF) + fail_type = BCEnum::AFT_GenderRace; + else if (!PlayerAppearance::IsValidBeardColor(my_bot->GetRace(), my_bot->GetGender(), uvalue)) + fail_type = BCEnum::AFT_Value; + else + my_bot->SetBeardColor(uvalue); + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "beard color")) + return; + + helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_bot_beard_style(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_beard_style", sep->arg[0], "botbeardstyle")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [value: 0-n] (Dwarves or male bots only)", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint8 uvalue = atoi(sep->arg[1]); + + auto fail_type = BCEnum::AFT_None; + if (my_bot->GetGender() != MALE && my_bot->GetRace() != DWARF) + fail_type = BCEnum::AFT_GenderRace; + else if (!PlayerAppearance::IsValidBeard(my_bot->GetRace(), my_bot->GetGender(), uvalue)) + fail_type = BCEnum::AFT_Value; + else + my_bot->SetBeard(uvalue); + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "beard style")) + return; + + helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_bot_camp(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_camp", sep->arg[0], "botcamp")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotation | spawned] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_NoFilter; + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + for (auto bot_iter : sbl) + bot_iter->Camp(); +} + +void bot_subcommand_bot_clone(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_clone", sep->arg[0], "botclone")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [clone_name]", sep->arg[0]); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + if (!my_bot->GetBotID()) { + c->Message(m_unknown, "An unknown error has occured - BotName: %s, BotID: %u", my_bot->GetCleanName(), my_bot->GetBotID()); + Log.Out(Logs::General, Logs::Commands, "bot_command_clone(): - Error: Active bot reported invalid ID (BotName: %s, BotID: %u, OwnerName: %s, OwnerID: %u, AcctName: %s, AcctID: %u)", + my_bot->GetCleanName(), my_bot->GetBotID(), c->GetCleanName(), c->CharacterID(), c->AccountName(), c->AccountID()); + return; + } + + if (sep->arg[1][0] == '\0' || sep->IsNumber(1)) { + c->Message(m_fail, "You must [name] your bot clone"); + return; + } + std::string bot_name = sep->arg[1]; + + if (!Bot::IsValidName(bot_name)) { + c->Message(m_fail, "'%s' is an invalid name. You may only use characters 'A-Z', 'a-z' and '_'", bot_name.c_str()); + return; + } + + std::string error_message; + + bool available_flag = false; + if (!botdb.QueryNameAvailablity(bot_name, available_flag)) { + c->Message(m_fail, "%s", BotDatabase::fail::QueryNameAvailablity()); + return; + } + if (!available_flag) { + c->Message(m_fail, "The name %s is already being used. Please choose a different name", bot_name.c_str()); + return; + } + + uint32 max_bot_count = RuleI(Bots, CreationLimit); + + uint32 bot_count = 0; + if (!botdb.QueryBotCount(c->CharacterID(), bot_count)) { + c->Message(m_fail, "%s", BotDatabase::fail::QueryBotCount()); + return; + } + if (bot_count >= max_bot_count) { + c->Message(m_fail, "You have reached the maximum limit of %i bots", max_bot_count); + return; + } + + uint32 clone_id = 0; + if (!botdb.CreateCloneBot(c->CharacterID(), my_bot->GetBotID(), bot_name, clone_id) || !clone_id) { + c->Message(m_fail, "%s '%s'", BotDatabase::fail::CreateCloneBot(), bot_name.c_str()); + return; + } + + int clone_stance = BotStancePassive; + if (!botdb.LoadStance(my_bot->GetBotID(), clone_stance)) + c->Message(m_fail, "%s for bot '%s'", BotDatabase::fail::LoadStance(), my_bot->GetCleanName()); + if (!botdb.SaveStance(clone_id, clone_stance)) + c->Message(m_fail, "%s for clone '%s'", BotDatabase::fail::SaveStance(), bot_name.c_str()); + + if (!botdb.CreateCloneBotInventory(c->CharacterID(), my_bot->GetBotID(), clone_id)) + c->Message(m_fail, "%s for clone '%s'", BotDatabase::fail::CreateCloneBotInventory(), bot_name.c_str()); + + c->Message(m_action, "Bot '%s' was successfully cloned to bot '%s'", my_bot->GetCleanName(), bot_name.c_str()); +} + +void bot_subcommand_bot_create(Client *c, const Seperator *sep) +{ + const std::string msg_class = StringFormat("class: %u(WAR), %u(CLR), %u(PAL), %u(RNG), %u(SHD), %u(DRU), %u(MNK), %u(BRD), %u(ROG), %u(SHM), %u(NEC), %u(WIZ), %u(MAG), %u(ENC), %u(BST), %u(BER)", + WARRIOR, CLERIC, PALADIN, RANGER, SHADOWKNIGHT, DRUID, MONK, BARD, ROGUE, SHAMAN, NECROMANCER, WIZARD, MAGICIAN, ENCHANTER, BEASTLORD, BERSERKER); + const std::string msg_race = StringFormat("race: %u(HUM), %u(BAR), %u(ERU), %u(ELF), %u(HIE), %u(DEF), %u(HEF), %u(DWF), %u(TRL), %u(OGR), %u(HFL), %u(GNM), %u(IKS), %u(VAH), %u(FRG), %u(DRK)", + HUMAN, BARBARIAN, ERUDITE, WOOD_ELF, HIGH_ELF, DARK_ELF, HALF_ELF, DWARF, TROLL, OGRE, HALFLING, GNOME, IKSAR, VAHSHIR, FROGLOK, DRAKKIN); + const std::string msg_gender = StringFormat("gender: %u(M), %u(F)", MALE, FEMALE); + + if (helper_command_alias_fail(c, "bot_subcommand_bot_create", sep->arg[0], "botcreate")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [bot_name] [bot_class] [bot_race] [bot_gender]", sep->arg[0]); + c->Message(m_note, msg_class.c_str()); + c->Message(m_note, msg_race.c_str()); + c->Message(m_note, msg_gender.c_str()); + return; + } + + if (sep->arg[1][0] == '\0' || sep->IsNumber(1)) { + c->Message(m_fail, "You must [name] your bot"); + return; + } + std::string bot_name = sep->arg[1]; + + if (sep->arg[2][0] == '\0' || !sep->IsNumber(2)) { + c->Message(m_fail, msg_class.c_str()); + return; + } + uint8 bot_class = atoi(sep->arg[2]); + + if (sep->arg[3][0] == '\0' || !sep->IsNumber(3)) { + c->Message(m_fail, msg_race.c_str()); + return; + } + uint16 bot_race = atoi(sep->arg[3]); + + if (sep->arg[4][0] == '\0') { + c->Message(m_fail, msg_gender.c_str()); + return; + } + uint8 bot_gender = atoi(sep->arg[4]); + + helper_bot_create(c, bot_name, bot_class, bot_race, bot_gender); +} + +void bot_subcommand_bot_delete(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_delete", sep->arg[0], "botdelete")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s", sep->arg[0]); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + std::string error_message; + + if (!my_bot->DeleteBot()) { + c->Message(m_unknown, "Failed to delete '%s' due to database error", my_bot->GetCleanName()); + return; + } + + auto bid = my_bot->GetBotID(); + std::string bot_name = my_bot->GetCleanName(); + + my_bot->Camp(false); + + c->Message(m_action, "Successfully deleted bot '%s' (id: %i)", bot_name.c_str(), bid); +} + +void bot_subcommand_bot_details(Client *c, const Seperator *sep) +{ + // TODO: Trouble-shoot model update issue + + if (helper_command_alias_fail(c, "bot_subcommand_bot_details", sep->arg[0], "botdetails")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [value: 0-n] (Drakkin bots only)", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint32 uvalue = atoi(sep->arg[1]); + + auto fail_type = BCEnum::AFT_None; + if (my_bot->GetRace() != DRAKKIN) + fail_type = BCEnum::AFT_Race; + else if (!PlayerAppearance::IsValidDetail(my_bot->GetRace(), my_bot->GetGender(), uvalue)) + fail_type = BCEnum::AFT_Value; + else + my_bot->SetDrakkinDetails(uvalue); + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "details")) + return; + + helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_bot_dye_armor(Client *c, const Seperator *sep) +{ + // TODO: Trouble-shoot model update issue + + const std::string msg_matslot = StringFormat("mat_slot: %c(All), %i(Head), %i(Chest), %i(Arms), %i(Wrists), %i(Hands), %i(Legs), %i(Feet)", + '*', EQEmu::textures::TextureHead, EQEmu::textures::TextureChest, EQEmu::textures::TextureArms, EQEmu::textures::TextureWrist, EQEmu::textures::TextureHands, EQEmu::textures::TextureLegs, EQEmu::textures::TextureFeet); + + if (helper_command_alias_fail(c, "bot_subcommand_bot_dye_armor", sep->arg[0], "botdyearmor")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [mat_slot] [red: 0-255] [green: 0-255] [blue: 0-255] ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotation | spawned] ([actionable_name]))", sep->arg[0]); + c->Message(m_note, msg_matslot.c_str()); + return; + } + const int ab_mask = ActionableBots::ABM_NoFilter; + + uint8 material_slot = EQEmu::textures::TextureInvalid; + int16 slot_id = INVALID_INDEX; + + bool dye_all = (sep->arg[1][0] == '*'); + if (!dye_all) { + material_slot = atoi(sep->arg[1]); + slot_id = Inventory::CalcSlotFromMaterial(material_slot); + + if (!sep->IsNumber(1) || slot_id == INVALID_INDEX || material_slot > EQEmu::textures::TextureFeet) { + c->Message(m_fail, "Valid [mat_slot]s for this command are:"); + c->Message(m_fail, msg_matslot.c_str()); + return; + } + } + + uint32 red_value = atoi(sep->arg[2]); + if (!sep->IsNumber(2) || red_value > 255) { + c->Message(m_fail, "Valid [red] values for this command are [0-255]"); + return; + } + + uint32 green_value = atoi(sep->arg[3]); + if (!sep->IsNumber(3) || green_value > 255) { + c->Message(m_fail, "Valid [green] values for this command are [0-255]"); + return; + } + + uint32 blue_value = atoi(sep->arg[4]); + if (!sep->IsNumber(4) || blue_value > 255) { + c->Message(m_fail, "Valid [blue] values for this command are [0-255]"); + return; + } + + uint32 rgb_value = ((0xFF) | (red_value << 16) | (green_value << 8) | (blue_value)); // watch the leading '(0xFF) | ' + + std::list sbl; + auto ab_type = ActionableBots::PopulateSBL(c, sep->arg[5], sbl, ab_mask); + if (ab_type == ActionableBots::ABT_None) + return; + + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + if (!bot_iter->DyeArmor(slot_id, rgb_value, dye_all, (ab_type != ActionableBots::ABT_All))) { + c->Message(m_fail, "Failed to change armor color for '%s' due to unknown cause", bot_iter->GetCleanName()); + return; + } + + //if (dye_all) + // helper_bot_appearance_form_update(bot_iter); + } + + if (ab_type == ActionableBots::ABT_All) { + if (dye_all) { + if (!botdb.SaveAllArmorColors(c->CharacterID(), rgb_value)) + c->Message(m_fail, "%s", BotDatabase::fail::SaveAllArmorColors()); + } + else { + if (!botdb.SaveAllArmorColorBySlot(c->CharacterID(), slot_id, rgb_value)) + c->Message(m_fail, "%s", BotDatabase::fail::SaveAllArmorColorBySlot()); + } + } +} + +void bot_subcommand_bot_eyes(Client *c, const Seperator *sep) +{ + // TODO: Trouble-shoot model update issue + + // not sure if left/right bias is allowed in pc-type entities (something is keeping them from being different) + if (helper_command_alias_fail(c, "bot_subcommand_bot_eyes", sep->arg[0], "boteyes")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + //c->Message(m_usage, "usage: %s [value:0-n] ([option: left | right])", sep->arg[0]); + c->Message(m_usage, "usage: %s [value: 0-n]", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint8 uvalue = atoi(sep->arg[1]); + + //uint8 eye_bias = 0; + //std::string arg2 = sep->arg[2]; + //if (!arg2.compare("left")) + // eye_bias = 1; + //else if (!arg2.compare("right")) + // eye_bias = 2; + + auto fail_type = BCEnum::AFT_None; + if (!PlayerAppearance::IsValidEyeColor(my_bot->GetRace(), my_bot->GetGender(), uvalue)) { + fail_type = BCEnum::AFT_Value; + } + else { + //if (eye_bias == 1) { + // my_bot->SetEyeColor1(uvalue); + //} + //else if (eye_bias == 2) { + // my_bot->SetEyeColor2(uvalue); + //} + //else { + my_bot->SetEyeColor1(uvalue); + my_bot->SetEyeColor2(uvalue); + //} + } + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "eyes")) + return; + + c->Message(m_action, "This feature will update the next time your bot is spawned"); + //helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_bot_face(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_face", sep->arg[0], "botface")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [value: 0-n]", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint8 uvalue = atoi(sep->arg[1]); + + auto fail_type = BCEnum::AFT_None; + if (!PlayerAppearance::IsValidFace(my_bot->GetRace(), my_bot->GetGender(), uvalue)) { + fail_type = BCEnum::AFT_Value; + } + else { + uint8 old_woad = 0; + if (my_bot->GetRace() == BARBARIAN) + old_woad = ((my_bot->GetLuclinFace() / 10) * 10); + my_bot->SetLuclinFace((old_woad + uvalue)); + } + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "face")) + return; + + helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_bot_follow_distance(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_follow_distance", sep->arg[0], "botfollowdistance")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [set] [distance] ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotation | spawned] ([actionable_name]))", sep->arg[0]); + c->Message(m_usage, "usage: %s [clear] ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotation | spawned] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_NoFilter; + + uint32 bfd = BOT_DEFAULT_FOLLOW_DISTANCE; + bool set_flag = false; + int ab_arg = 2; + + if (!strcasecmp(sep->arg[1], "set")) { + if (!sep->IsNumber(2)) { + c->Message(m_fail, "A numeric [distance] is required to use this command"); + return; + } + + bfd = atoi(sep->arg[2]); + set_flag = true; + ab_arg = 3; + } + else if (strcasecmp(sep->arg[1], "clear")) { + c->Message(m_fail, "This command requires a [set | clear] argument"); + return; + } + + std::list sbl; + auto ab_type = ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, sep->arg[(ab_arg + 1)]); + if (ab_type == ActionableBots::ABT_None) + return; + + int bot_count = 0; + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + bot_iter->SetFollowDistance(bfd); + if (ab_type != ActionableBots::ABT_All && !botdb.SaveFollowDistance(c->CharacterID(), bot_iter->GetBotID(), bfd)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::SaveFollowDistance(), bot_iter->GetCleanName()); + return; + } + + ++bot_count; + } + + if (ab_type == ActionableBots::ABT_All) { + if (!botdb.SaveAllFollowDistances(c->CharacterID(), bfd)) { + c->Message(m_fail, "%s", BotDatabase::fail::SaveAllFollowDistances()); + return; + } + + c->Message(m_action, "%s all of your bot follow distances", set_flag ? "Set" : "Cleared"); + } + else { + c->Message(m_action, "%s %i of your spawned bot follow distances", (set_flag ? "Set" : "Cleared"), bot_count); + } +} + +void bot_subcommand_bot_hair_color(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_hair_color", sep->arg[0], "bothaircolor")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [value: 0-n]", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint8 uvalue = atoi(sep->arg[1]); + + auto fail_type = BCEnum::AFT_None; + if (!PlayerAppearance::IsValidHairColor(my_bot->GetRace(), my_bot->GetGender(), uvalue)) + fail_type = BCEnum::AFT_Value; + else + my_bot->SetHairColor(uvalue); + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "hair color")) + return; + + helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_bot_hairstyle(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_hairstyle", sep->arg[0], "bothairstyle")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [value: 0-n]", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint8 uvalue = atoi(sep->arg[1]); + + auto fail_type = BCEnum::AFT_None; + if (!PlayerAppearance::IsValidHair(my_bot->GetRace(), my_bot->GetGender(), uvalue)) + fail_type = BCEnum::AFT_Value; + else + my_bot->SetHairStyle(uvalue); + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "hair style")) + return; + + helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_bot_heritage(Client *c, const Seperator *sep) +{ + // TODO: Trouble-shoot model update issue + + if (helper_command_alias_fail(c, "bot_subcommand_bot_heritage", sep->arg[0], "botheritage")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [value: 0-n] (Drakkin bots only)", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint32 uvalue = atoi(sep->arg[1]); + + auto fail_type = BCEnum::AFT_None; + if (my_bot->GetRace() != DRAKKIN) + fail_type = BCEnum::AFT_Race; + else if (!PlayerAppearance::IsValidHeritage(my_bot->GetRace(), my_bot->GetGender(), uvalue)) + fail_type = BCEnum::AFT_Value; + else + my_bot->SetDrakkinHeritage(uvalue); + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "heritage")) + return; + + helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_bot_inspect_message(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_inspect_message", sep->arg[0], "botinspectmessage")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [set | clear] ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotation | spawned] ([actionable_name]))", sep->arg[0]); + c->Message(m_note, "Notes:"); + if (c->ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { + c->Message(m_message, "- Self-inspect and type your bot's inspect message"); + c->Message(m_message, "- Close the self-inspect window to update the server"); + c->Message(m_message, "- Type '%s set' to set the bot's inspect message", sep->arg[0]); + } + else { + c->Message(m_message, "- Self-inspect and type your bot's inspect message"); + c->Message(m_message, "- Close the self-inspect window"); + c->Message(m_message, "- Self-inspect again to update the server"); + c->Message(m_message, "- Type '%s set' to set the bot's inspect message", sep->arg[0]); + } + return; + } + const int ab_mask = ActionableBots::ABM_NoFilter; + + bool set_flag = false; + if (!strcasecmp(sep->arg[1], "set")) { + set_flag = true; + } + else if (strcasecmp(sep->arg[1], "clear")) { + c->Message(15, "This command requires a [set | clear] argument"); + return; + } + + std::list sbl; + auto ab_type = ActionableBots::PopulateSBL(c, sep->arg[2], sbl, ab_mask, sep->arg[3]); + if (ab_type == ActionableBots::ABT_None) + return; + + const auto client_message_struct = &c->GetInspectMessage(); + + int bot_count = 0; + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + auto bot_message_struct = &bot_iter->GetInspectMessage(); + memset(bot_message_struct, 0, sizeof(InspectMessage_Struct)); + if (set_flag) + memcpy(bot_message_struct, client_message_struct, sizeof(InspectMessage_Struct)); + + if (ab_type != ActionableBots::ABT_All && !botdb.SaveInspectMessage(bot_iter->GetBotID(), *bot_message_struct)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::SaveInspectMessage(), bot_iter->GetCleanName()); + return; + } + + ++bot_count; + } + + if (ab_type == ActionableBots::ABT_All) { + InspectMessage_Struct bot_message_struct; + memset(&bot_message_struct, 0, sizeof(InspectMessage_Struct)); + if (set_flag) + memcpy(&bot_message_struct, client_message_struct, sizeof(InspectMessage_Struct)); + + if (!botdb.SaveAllInspectMessages(c->CharacterID(), bot_message_struct)) { + c->Message(m_fail, "%s", BotDatabase::fail::SaveAllInspectMessages()); + return; + } + + c->Message(m_action, "%s all of your bot inspect messages", set_flag ? "Set" : "Cleared"); + } + else { + c->Message(m_action, "%s %i of your spawned bot inspect messages", set_flag ? "Set" : "Cleared", bot_count); + } +} + +void bot_subcommand_bot_list(Client *c, const Seperator *sep) +{ + // TODO: Consider re-working to use player race values instead of actual race + + enum { FilterClass, FilterRace, FilterName, FilterCount, MaskClass = (1 << FilterClass), MaskRace = (1 << FilterRace), MaskName = (1 << FilterName) }; + + if (helper_command_alias_fail(c, "bot_subcommand_bot_list", sep->arg[0], "botlist")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([class] [value]) ([race] [value]) ([name] [partial-full])", sep->arg[0]); + c->Message(m_note, "Note: filter criteria is orderless and optional"); + return; + } + + uint32 filter_value[FilterCount]; + int name_criteria_arg = 0; + memset(&filter_value, 0, sizeof(uint32) * FilterCount); + + int filter_mask = 0; + for (int i = 1; i < (FilterCount * 2); i += 2) { + if (sep->arg[i][0] == '\0') + break; + + if (!strcasecmp(sep->arg[i], "class")) { + filter_mask |= MaskClass; + filter_value[FilterClass] = atoi(sep->arg[i + 1]); + continue; + } + if (!strcasecmp(sep->arg[i], "race")) { + filter_mask |= MaskRace; + filter_value[FilterRace] = atoi(sep->arg[i + 1]); + continue; + } + if (!strcasecmp(sep->arg[i], "name")) { + filter_mask |= MaskName; + name_criteria_arg = (i + 1); + continue; + } + + c->Message(m_fail, "A numeric value or name is required to use the filter property of this command (f: '%s', v: '%s')", sep->arg[i], sep->arg[i + 1]); + return; + } + + std::list bots_list; + if (!botdb.LoadBotsList(c->CharacterID(), bots_list)) { + c->Message(m_fail, "%s", BotDatabase::fail::LoadBotsList()); + return; + } + if (bots_list.empty()) { + c->Message(m_fail, "You have no bots"); + return; + } + + int bot_count = 0; + for (auto bots_iter : bots_list) { + if (filter_mask) { + if ((filter_mask & MaskClass) && filter_value[FilterClass] != bots_iter.Class) + continue; + if ((filter_mask & MaskRace) && filter_value[FilterRace] != bots_iter.Race) + continue; + if (filter_mask & MaskName) { + std::string name_criteria = sep->arg[name_criteria_arg]; + std::transform(name_criteria.begin(), name_criteria.end(), name_criteria.begin(), ::tolower); + std::string name_check = bots_iter.Name; + std::transform(name_check.begin(), name_check.end(), name_check.begin(), ::tolower); + if (name_check.find(name_criteria) == std::string::npos) + continue; + } + } + + c->Message(m_message, "%s is a level %u %s %s %s", + bots_iter.Name, + bots_iter.Level, + Bot::RaceIdToString(bots_iter.Race).c_str(), + ((bots_iter.Gender == FEMALE) ? ("Female") : ((bots_iter.Gender == MALE) ? ("Male") : ("Neuter"))), + Bot::ClassIdToString(bots_iter.Class).c_str() + ); + + ++bot_count; + } + if (!bot_count) { + c->Message(m_fail, "You have no bots meeting this criteria"); + } + else { + c->Message(m_action, "%i of %i bot%s shown", bot_count, bots_list.size(), ((bot_count != 1) ? ("s") : (""))); + c->Message(m_message, "Your limit is %i bot%s", RuleI(Bots, CreationLimit), ((RuleI(Bots, CreationLimit) != 1) ? ("s") : (""))); + } +} + +void bot_subcommand_bot_out_of_combat(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_out_of_combat", sep->arg[0], "botoutofcombat")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([option: on | off]) ([actionable: target | byname] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName); + + std::string arg1 = sep->arg[1]; + + bool behavior_state = false; + bool toggle_behavior = true; + int ab_arg = 1; + if (!arg1.compare("on")) { + behavior_state = true; + toggle_behavior = false; + ab_arg = 2; + } + else if (!arg1.compare("off")) { + toggle_behavior = false; + ab_arg = 2; + } + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, sep->arg[(ab_arg + 1)]) == ActionableBots::ABT_None) + return; + + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + if (toggle_behavior) + bot_iter->SetAltOutOfCombatBehavior(!bot_iter->GetAltOutOfCombatBehavior()); + else + bot_iter->SetAltOutOfCombatBehavior(behavior_state); + + helper_bot_out_of_combat(c, bot_iter); + } +} + +void bot_subcommand_bot_report(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_report", sep->arg[0], "botreport")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotation | spawned] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_NoFilter; + + std::string ab_type_arg = sep->arg[1]; + if (ab_type_arg.empty()) { + if (c->GetTarget()) { + if (c->GetTarget()->IsClient() && c->GetTarget()->CastToClient() == c) + ab_type_arg = "ownergroup"; + else if (c->GetTarget()->IsClient() && c->GetTarget()->CastToClient() != c) + ab_type_arg = "targetgroup"; + } + else { + ab_type_arg = "spawned"; + } + } + + std::list sbl; + if (ActionableBots::PopulateSBL(c, ab_type_arg.c_str(), sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + std::string report_msg = StringFormat("%s %s reports", Bot::ClassIdToString(bot_iter->GetClass()).c_str(), bot_iter->GetCleanName()); + report_msg.append(StringFormat(": %3.1f%% health", bot_iter->GetHPRatio())); + if (!IsNonSpellFighterClass(bot_iter->GetClass())) + report_msg.append(StringFormat(": %3.1f%% mana", bot_iter->GetManaRatio())); + + c->Message(m_message, "%s", report_msg.c_str()); + } +} + +void bot_subcommand_bot_spawn(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_spawn", sep->arg[0], "botspawn")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [bot_name]", sep->arg[0]); + return; + } + + int rule_level = RuleI(Bots, BotCharacterLevel); + if (c->GetLevel() < rule_level) { + c->Message(m_fail, "You must be level %i to use bots", rule_level); + return; + } + + if (c->GetFeigned()) { + c->Message(m_fail, "You can not spawn a bot while feigned"); + return; + } + + int spawned_bot_count = Bot::SpawnedBotCount(c->CharacterID()); + + int rule_limit = RuleI(Bots, SpawnLimit); + if (spawned_bot_count >= rule_limit && !c->GetGM()) { + c->Message(m_fail, "You can not have more than %i spawned bots", rule_limit); + return; + } + + if (RuleB(Bots, QuestableSpawnLimit) && !c->GetGM()) { + int allowed_bot_count = 0; + if (!botdb.LoadQuestableSpawnCount(c->CharacterID(), allowed_bot_count)) { + c->Message(m_fail, "%s", BotDatabase::fail::LoadQuestableSpawnCount()); + return; + } + if (!allowed_bot_count) { + c->Message(m_fail, "You are not currently allowed any spawned bots"); + return; + } + if (spawned_bot_count >= allowed_bot_count) { + c->Message(m_fail, "You have reached your current limit of %i spawned bots", allowed_bot_count); + return; + } + } + + if (sep->arg[1][0] == '\0' || sep->IsNumber(1)) { + c->Message(m_fail, "You must specify a [name] to use this command"); + return; + } + std::string bot_name = sep->arg[1]; + + uint32 bot_id = 0; + if (!botdb.LoadBotID(c->CharacterID(), bot_name, bot_id)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotID(), bot_name.c_str()); + return; + } + if (!bot_id) { + c->Message(m_fail, "You don't own a bot named '%s'", bot_name.c_str()); + return; + } + + if (entity_list.GetMobByBotID(bot_id)) { + c->Message(m_fail, "'%s' is already spawned in zone", bot_name.c_str()); + return; + } + + // this probably needs work... + if (c->GetGroup()) { + std::list group_list; + c->GetGroup()->GetMemberList(group_list); + for (auto member_iter : group_list) { + if (!member_iter) + continue; + if (member_iter->qglobal) // what is this?? really should have had a message to describe failure... (can't spawn bots if you are assigned to a task/instance?) + return; + if (!member_iter->qglobal && (member_iter->GetAppearance() != eaDead) && (member_iter->IsEngaged() || (member_iter->IsClient() && member_iter->CastToClient()->GetAggroCount()))) { + c->Message(m_fail, "You can't summon bots while you are engaged."); + return; + } + } + } + else if (c->GetAggroCount() > 0) { + c->Message(m_fail, "You can't spawn bots while you are engaged."); + return; + } + + //if (c->IsEngaged()) { + // c->Message(m_fail, "You can't spawn bots while you are engaged."); + // return; + //} + + auto my_bot = Bot::LoadBot(bot_id); + if (!my_bot) { + c->Message(m_fail, "No valid bot '%s' (id: %i) exists", bot_name.c_str(), bot_id); + return; + } + + my_bot->Spawn(c); + + static const char* bot_spawn_message[16] = { + "A solid weapon is my ally!", // WARRIOR / 'generic' + "The pious shall never die!", // CLERIC + "I am the symbol of Light!", // PALADIN + "There are enemies near!", // RANGER + "Out of the shadows, I step!", // SHADOWKNIGHT + "Nature's fury shall be wrought!", // DRUID + "Your punishment will be my fist!", // MONK + "Music is the overture of battle! ", // BARD + "Daggers into the backs of my enemies!", // ROGUE + "More bones to grind!", // SHAMAN + "Death is only the beginning!", // NECROMANCER + "I am the harbinger of demise!", // WIZARD + "The elements are at my command!", // MAGICIAN + "No being can resist my charm!", // ENCHANTER + "Battles are won by hand and paw!", // BEASTLORD + "My bloodthirst shall not be quenched!" // BERSERKER + }; + + Bot::BotGroupSay(my_bot, "%s", bot_spawn_message[CLASSIDTOINDEX(my_bot->GetClass())]); +} + +void bot_subcommand_bot_stance(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_stance", sep->arg[0], "botstance")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [current | value: 0-6] ([actionable: target | byname] ([actionable_name]))", sep->arg[0]); + c->Message(m_note, "value: %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s), %u(%s)", + BotStancePassive, GetBotStanceName(BotStancePassive), + BotStanceBalanced, GetBotStanceName(BotStanceBalanced), + BotStanceEfficient, GetBotStanceName(BotStanceEfficient), + BotStanceReactive, GetBotStanceName(BotStanceReactive), + BotStanceAggressive, GetBotStanceName(BotStanceAggressive), + BotStanceBurn, GetBotStanceName(BotStanceBurn), + BotStanceBurnAE, GetBotStanceName(BotStanceBurnAE) + ); + return; + } + int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName); + + bool current_flag = false; + auto bst = BotStanceUnknown; + + if (!strcasecmp(sep->arg[1], "current")) + current_flag = true; + else if (sep->IsNumber(1)) + bst = VALIDBOTSTANCE(atoi(sep->arg[1])); + + if (!current_flag && bst == BotStanceUnknown) { + c->Message(m_fail, "A [current] argument or valid numeric [value] is required to use this command"); + return; + } + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[2], sbl, ab_mask, sep->arg[3]) == ActionableBots::ABT_None) + return; + + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + if (!current_flag) { + bot_iter->SetBotStance(bst); + bot_iter->CalcChanceToCast(); + bot_iter->Save(); + } + + Bot::BotGroupSay(bot_iter, "My current stance is '%s' (%u)", GetBotStanceName(bot_iter->GetBotStance()), bot_iter->GetBotStance()); + } +} + +void bot_subcommand_bot_summon(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_summon", sep->arg[0], "botsummon")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotation | spawned] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_NoFilter; + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + Bot::BotGroupSay(bot_iter, "Whee!"); + + bot_iter->WipeHateList(); + bot_iter->SetTarget(bot_iter->GetBotOwner()); + bot_iter->Warp(glm::vec3(c->GetPosition())); + + if (!bot_iter->HasPet()) + continue; + + bot_iter->GetPet()->WipeHateList(); + bot_iter->GetPet()->SetTarget(bot_iter); + bot_iter->GetPet()->Warp(glm::vec3(c->GetPosition())); + } + + if (sbl.size() == 1) + c->Message(m_action, "Summoned %s to you", ((sbl.front()) ? (sbl.front()->GetCleanName()) : ("'nullptr'"))); + else + c->Message(m_action, "Summoned %i bots to you", sbl.size()); +} + +void bot_subcommand_bot_tattoo(Client *c, const Seperator *sep) +{ + // TODO: Trouble-shoot model update issue + + if (helper_command_alias_fail(c, "bot_subcommand_bot_tattoo", sep->arg[0], "bottattoo")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [value: 0-n] (Drakkin bots only)", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint32 uvalue = atoi(sep->arg[1]); + + auto fail_type = BCEnum::AFT_None; + if (my_bot->GetRace() != DRAKKIN) + fail_type = BCEnum::AFT_Race; + else if (!PlayerAppearance::IsValidTattoo(my_bot->GetRace(), my_bot->GetGender(), uvalue)) + fail_type = BCEnum::AFT_Value; + else + my_bot->SetDrakkinTattoo(uvalue); + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "tattoo")) + return; + + helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_bot_toggle_archer(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_toggle_archer", sep->arg[0], "bottogglearcher")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([option: on | off]) ([actionable: target | byname] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName); + + std::string arg1 = sep->arg[1]; + + bool archer_state = false; + bool toggle_archer = true; + int ab_arg = 1; + if (!arg1.compare("on")) { + archer_state = true; + toggle_archer = false; + ab_arg = 2; + } + else if (!arg1.compare("off")) { + toggle_archer = false; + ab_arg = 2; + } + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, sep->arg[(ab_arg + 1)]) == ActionableBots::ABT_None) + return; + + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + if (toggle_archer) + bot_iter->SetBotArcher(!bot_iter->IsBotArcher()); + else + bot_iter->SetBotArcher(archer_state); + bot_iter->ChangeBotArcherWeapons(bot_iter->IsBotArcher()); + + if (bot_iter->GetClass() == RANGER && bot_iter->GetLevel() >= 61) + bot_iter->SetRangerAutoWeaponSelect(bot_iter->IsBotArcher()); + } +} + +void bot_subcommand_bot_toggle_helm(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_toggle_helm", sep->arg[0], "bottogglehelm")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([option: on | off]) ([actionable: target | byname | ownergroup | botgroup | targetgroup | namesgroup | healrotation | spawned] ([actionable_name]))", sep->arg[0]); + return; + } + const int ab_mask = ActionableBots::ABM_NoFilter; + + std::string arg1 = sep->arg[1]; + + bool helm_state = false; + bool toggle_helm = true; + int ab_arg = 1; + if (!arg1.compare("on")) { + helm_state = true; + toggle_helm = false; + ab_arg = 2; + } + else if (!arg1.compare("off")) { + toggle_helm = false; + ab_arg = 2; + } + + std::list sbl; + auto ab_type = ActionableBots::PopulateSBL(c, sep->arg[ab_arg], sbl, ab_mask, sep->arg[(ab_arg + 1)]); + if (ab_type == ActionableBots::ABT_None) + return; + + int bot_count = 0; + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + if (toggle_helm) + bot_iter->SetShowHelm(!bot_iter->GetShowHelm()); + else + bot_iter->SetShowHelm(helm_state); + + if (ab_type != ActionableBots::ABT_All) { + if (!botdb.SaveHelmAppearance(c->CharacterID(), bot_iter->GetBotID(), bot_iter->GetShowHelm())) { + c->Message(m_unknown, "%s for '%s'", bot_iter->GetCleanName()); + return; + } + + EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + SpawnAppearance_Struct* saptr = (SpawnAppearance_Struct*)outapp->pBuffer; + saptr->spawn_id = bot_iter->GetID(); + saptr->type = AT_ShowHelm; + saptr->parameter = bot_iter->GetShowHelm(); + + entity_list.QueueClients(bot_iter, outapp); + safe_delete(outapp); + + //helper_bot_appearance_form_update(bot_iter); + } + ++bot_count; + } + + if (ab_type == ActionableBots::ABT_All) { + std::string query; + if (toggle_helm) { + if (!botdb.ToggleAllHelmAppearances(c->CharacterID())) + c->Message(m_fail, "%s", BotDatabase::fail::ToggleAllHelmAppearances()); + } + else { + if (!botdb.SaveAllHelmAppearances(c->CharacterID(), helm_state)) + c->Message(m_fail, "%s", BotDatabase::fail::SaveAllHelmAppearances()); + } + + c->Message(m_action, "%s all of your bot show helm flags", toggle_helm ? "Toggled" : (helm_state ? "Set" : "Cleared")); + } + else { + c->Message(m_action, "%s %i of your spawned bot show helm flags", toggle_helm ? "Toggled" : (helm_state ? "Set" : "Cleared"), bot_count); + } + + // Notes: + /* + [CLIENT OPCODE TEST] + [10-16-2015 :: 14:57:56] [Packet :: Client -> Server (Dump)] [OP_SpawnAppearance - 0x01d1] [Size: 10] + 0: A4 02 [2B 00] 01 00 00 00 - showhelm = true (client) + [10-16-2015 :: 14:57:56] [Packet :: Server -> Client (Dump)] [OP_SpawnAppearance - 0x01d1] [Size: 10] + 0: A4 02 [2B 00] 01 00 00 00 - showhelm = true (client) + + [10-16-2015 :: 14:58:02] [Packet :: Client -> Server (Dump)] [OP_SpawnAppearance - 0x01d1] [Size: 10] + 0: A4 02 [2B 00] 00 00 00 00 - showhelm = false (client) + [10-16-2015 :: 14:58:02] [Packet :: Server -> Client (Dump)] [OP_SpawnAppearance - 0x01d1] [Size: 10] + 0: A4 02 [2B 00] 00 00 00 00 - showhelm = false (client) + + [BOT OPCODE TEST] + [10-16-2015 :: 22:15:34] [Packet :: Client -> Server (Dump)] [OP_ChannelMessage - 0x0045] [Size: 167] + 0: 43 6C 65 72 69 63 62 6F - 74 00 00 00 00 00 00 00 | Clericbot....... + 16: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 32: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 48: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 64: 43 6C 65 72 69 63 62 6F - 74 00 00 00 00 00 00 00 | Clericbot....... + 80: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 96: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 112: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 128: 00 00 00 00 08 00 00 00 - CD CD CD CD CD CD CD CD | ................ + 144: 64 00 00 00 23 62 6F 74 - 20 73 68 6F 77 68 65 6C | d...#bot showhel + 160: 6D 20 6F 6E 00 | m on. + + [10-16-2015 :: 22:15:34] [Packet :: Server -> Client (Dump)] [OP_SpawnAppearance - 0x01d1] [Size: 10] + 0: A2 02 2B 00 01 00 00 00 - showhelm = true + + [10-16-2015 :: 22:15:40] [Packet :: Client -> Server (Dump)] [OP_ChannelMessage - 0x0045] [Size: 168] + 0: 43 6C 65 72 69 63 62 6F - 74 00 00 00 00 00 00 00 | Clericbot....... + 16: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 32: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 48: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 64: 43 6C 65 72 69 63 62 6F - 74 00 00 00 00 00 00 00 | Clericbot....... + 80: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 96: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 112: 00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00 | ................ + 128: 00 00 00 00 08 00 00 00 - CD CD CD CD CD CD CD CD | ................ + 144: 64 00 00 00 23 62 6F 74 - 20 73 68 6F 77 68 65 6C | d...#bot showhel + 160: 6D 20 6F 66 66 00 | m off. + + [10-16-2015 :: 22:15:40] [Packet :: Server -> Client (Dump)] [OP_SpawnAppearance - 0x01d1] [Size: 10] + 0: A2 02 2B 00 00 00 00 00 - showhelm = false + + *** Bot did not update using the OP_SpawnAppearance packet with AT_ShowHelm appearance type *** + */ +} + +void bot_subcommand_bot_update(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_update", sep->arg[0], "botupdate")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You currently have no spawned bots"); + return; + } + + int bot_count = 0; + for (auto bot_iter : sbl) { + if (!bot_iter || bot_iter->IsEngaged() || bot_iter->GetLevel() == c->GetLevel()) + continue; + + bot_iter->SetPetChooser(false); + bot_iter->CalcBotStats((sbl.size() == 1)); + ++bot_count; + } + + c->Message(m_action, "Updated %i of your %i spawned bots", bot_count, sbl.size()); +} + +void bot_subcommand_bot_woad(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_bot_woad", sep->arg[0], "botwoad")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [value: 0-n] (Barbarian bots only)", sep->arg[0]); + c->Message(m_note, "note: Actual limit is filter-based"); + return; + } + + auto my_bot = ActionableBots::AsTarget_ByBot(c); + if (!my_bot) { + c->Message(m_fail, "You must a bot that you own to use this command"); + return; + } + + if (!sep->IsNumber(1)) { + c->Message(m_fail, "A numeric [value] is required to use this command"); + return; + } + + uint8 uvalue = atoi(sep->arg[1]); + + auto fail_type = BCEnum::AFT_None; + if (my_bot->GetRace() != BARBARIAN) { + fail_type = BCEnum::AFT_Race; + } + else if (!PlayerAppearance::IsValidWoad(my_bot->GetRace(), my_bot->GetGender(), uvalue)) { + fail_type = BCEnum::AFT_Value; + } + else { + uint8 old_face = (my_bot->GetLuclinFace() % 10); + my_bot->SetLuclinFace(((uvalue * 10) + old_face)); + } + + if (helper_bot_appearance_fail(c, my_bot, fail_type, "woad")) + return; + + helper_bot_appearance_form_final(c, my_bot); +} + +void bot_subcommand_botgroup_add_member(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_botgroup_add_member", sep->arg[0], "botgroupaddmember")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [member_name] ([leader_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) { + c->Message(m_fail, "You must [name] a new member as a bot that you own to use this command"); + return; + } + + auto new_member = sbl.front(); + if (!new_member) { + c->Message(m_unknown, "Error: New member bot dereferenced to nullptr"); + return; + } + + if (new_member->HasGroup()) { + c->Message(m_fail, "%s is already a current member of a group and can not join another one", new_member->GetCleanName()); + return; + } + + uint32 botgroup_id = 0; + if (!botdb.LoadBotGroupIDByMemberID(new_member->GetBotID(), botgroup_id)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDByMemberID(), new_member->GetCleanName()); + return; + } + if (botgroup_id) { + c->Message(m_fail, "%s is already a current member of a bot-group", new_member->GetCleanName()); + return; + } + + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[2]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a group leader as a bot that you own to use this command"); + return; + } + + auto botgroup_leader = sbl.front(); + if (!botgroup_leader) { + c->Message(m_unknown, "Error: Group leader bot dereferenced to nullptr"); + return; + } + + Group* group_inst = botgroup_leader->GetGroup(); + if (!group_inst || group_inst->GetLeader() != botgroup_leader) { + c->Message(m_fail, "%s is not the current leader of a group", botgroup_leader->GetCleanName()); + return; + } + + botgroup_id = 0; + if (!botdb.LoadBotGroupIDByLeaderID(botgroup_leader->GetBotID(), botgroup_id)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDByLeaderID(), botgroup_leader->GetCleanName()); + return; + } + if (!botgroup_id) { + c->Message(m_fail, "%s is not the current leader of a bot-group", botgroup_leader->GetCleanName()); + return; + } + + if (!Bot::AddBotToGroup(new_member, group_inst)) { + c->Message(m_fail, "Could not add %s as a new member to %s's group", new_member->GetCleanName(), botgroup_leader->GetCleanName()); + return; + } + + database.SetGroupID(new_member->GetName(), group_inst->GetID(), new_member->GetBotID()); + + if (!botdb.AddMemberToBotGroup(botgroup_leader->GetBotID(), new_member->GetBotID())) { + c->Message(m_fail, "%s - %s->%s", BotDatabase::fail::AddMemberToBotGroup(), new_member->GetCleanName(), botgroup_leader->GetCleanName()); + Bot::RemoveBotFromGroup(new_member, botgroup_leader->GetGroup()); + return; + } + + std::string botgroup_name; + if (!botdb.LoadBotGroupNameByLeaderID(botgroup_leader->GetBotID(), botgroup_name)) + c->Message(m_fail, "%s", BotDatabase::fail::LoadBotGroupNameByLeaderID()); + + c->Message(m_action, "Successfully added %s to bot-group %s", new_member->GetCleanName(), botgroup_name.c_str()); +} + +void bot_subcommand_botgroup_create(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_botgroup_create", sep->arg[0], "botgroupcreate")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [group_name] ([leader_name])", sep->arg[0]); + return; + } + + std::string botgroup_name_arg = sep->arg[1]; + if (botgroup_name_arg.empty()) { + c->Message(m_fail, "You must specify a [name] for this bot-group to use this command"); + return; + } + + bool extant_flag = false; + if (!botdb.QueryBotGroupExistence(botgroup_name_arg, extant_flag)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::QueryBotGroupExistence(), botgroup_name_arg.c_str()); + return; + } + if (extant_flag) { + c->Message(m_fail, "The [name] %s already exists for a bot-group. Please choose another", botgroup_name_arg.c_str()); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[2]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a group leader as a bot that you own to use this command"); + return; + } + + auto botgroup_leader = sbl.front(); + if (!botgroup_leader) { + c->Message(m_unknown, "Error: Group leader bot dereferenced to nullptr"); + return; + } + + if (botgroup_leader->HasGroup()) { + c->Message(m_fail, "%s is already a current member of a group", botgroup_leader->GetCleanName()); + return; + } + + uint32 botgroup_id = 0; + if (!botdb.LoadBotGroupIDByLeaderID(botgroup_leader->GetBotID(), botgroup_id)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDByLeaderID(), botgroup_leader->GetCleanName()); + return; + } + if (botgroup_id) { + c->Message(m_fail, "%s is already the current leader of a bot-group", botgroup_leader->GetCleanName()); + return; + } + + botgroup_id = 0; + if (!botdb.LoadBotGroupIDByMemberID(botgroup_leader->GetBotID(), botgroup_id)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDByMemberID(), botgroup_leader->GetCleanName()); + return; + } + if (botgroup_id) { + c->Message(m_fail, "%s is already a current member of a bot-group", botgroup_leader->GetCleanName()); + return; + } + + Group* group_inst = new Group(botgroup_leader); + if (!group_inst) { + c->Message(m_unknown, "Could not create a new group instance"); + return; + } + + if (!botdb.CreateBotGroup(botgroup_name_arg, botgroup_leader->GetBotID())) { + c->Message(m_fail, "%s '%s'", BotDatabase::fail::CreateBotGroup(), botgroup_name_arg.c_str()); + safe_delete(group_inst); + return; + } + + entity_list.AddGroup(group_inst); + database.SetGroupID(botgroup_leader->GetCleanName(), group_inst->GetID(), botgroup_leader->GetBotID()); + database.SetGroupLeaderName(group_inst->GetID(), botgroup_leader->GetCleanName()); + botgroup_leader->SetFollowID(c->GetID()); + + c->Message(m_action, "Successfully created bot-group '%s' with '%s' as its leader", botgroup_name_arg.c_str(), botgroup_leader->GetCleanName()); +} + +void bot_subcommand_botgroup_delete(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_botgroup_delete", sep->arg[0], "botgroupdelete")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [botgroup_name]", sep->arg[0]); + return; + } + + std::string botgroup_name_arg = sep->arg[1]; + if (botgroup_name_arg.empty()) { + c->Message(m_fail, "You must specify a [name] for this bot-group to use this command"); + return; + } + + uint32 botgroup_id = 0; + if (!botdb.LoadBotGroupIDForLoadBotGroup(c->CharacterID(), botgroup_name_arg, botgroup_id)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDForLoadBotGroup(), botgroup_name_arg.c_str()); + return; + } + if (!botgroup_id) { + c->Message(m_fail, "Could not locate group id for '%s'", botgroup_name_arg.c_str()); + return; + } + + uint32 leader_id = 0; + if (!botdb.LoadLeaderIDByBotGroupID(botgroup_id, leader_id)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadLeaderIDByBotGroupID(), botgroup_name_arg.c_str()); + return; + } + if (!leader_id) { + c->Message(m_fail, "Could not locate leader id for '%s'", botgroup_name_arg.c_str()); + return; + } + + std::list gbl; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + std::map> member_list; + if (!botdb.LoadBotGroup(botgroup_name_arg, member_list)) { + c->Message(m_fail, "%s '%s'", BotDatabase::fail::LoadBotGroup(), botgroup_name_arg.c_str()); + return; + } + if (member_list.find(botgroup_id) == member_list.end() || member_list[botgroup_id].empty()) { + c->Message(m_fail, "Could not locate member list for bot-group '%s'", botgroup_name_arg.c_str()); + return; + } + + for (auto bot_iter : sbl) { + for (auto group_iter : member_list[botgroup_id]) { + if (bot_iter->GetBotID() == group_iter) { + gbl.push_back(bot_iter); + break; + } + } + } + gbl.unique(); + + for (auto group_member : gbl) { + if (group_member->HasGroup()) + Bot::RemoveBotFromGroup(group_member, group_member->GetGroup()); + } + + if (!botdb.DeleteBotGroup(leader_id)) { + c->Message(m_fail, "%s '%s'", BotDatabase::fail::DeleteBotGroup(), botgroup_name_arg.c_str()); + return; + } + + c->Message(m_action, "Successfully deleted bot-group %s", botgroup_name_arg.c_str()); +} + +void bot_subcommand_botgroup_list(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_botgroup_list", sep->arg[0], "botgrouplist")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s", sep->arg[0]); + return; + } + + std::list> botgroups_list; + if (!botdb.LoadBotGroupsListByOwnerID(c->CharacterID(), botgroups_list)) { + c->Message(m_fail, "%s", BotDatabase::fail::LoadBotGroupsListByOwnerID()); + return; + } + if (botgroups_list.empty()) { + c->Message(m_fail, "You have no saved bot-groups"); + return; + } + + int botgroup_count = 0; + for (auto botgroups_iter : botgroups_list) + c->Message(m_message, "(%i) Bot-group name: %s | Leader: %s", (++botgroup_count), botgroups_iter.first.c_str(), botgroups_iter.second.c_str()); + + c->Message(m_action, "%i bot-groups listed", botgroup_count); +} + +void bot_subcommand_botgroup_load(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_botgroup_load", sep->arg[0], "botgroupload")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [botgroup_name]", sep->arg[0]); + return; + } + + std::string botgroup_name_arg = sep->arg[1]; + if (botgroup_name_arg.empty()) { + c->Message(m_fail, "You must specify the [name] of a bot-group to load to use this command"); + return; + } + + bool extant_flag = false; + if (!botdb.QueryBotGroupExistence(botgroup_name_arg, extant_flag)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::QueryBotGroupExistence(), botgroup_name_arg.c_str()); + return; + } + if (!extant_flag) { + c->Message(m_fail, "Bot-group %s does not exist", botgroup_name_arg.c_str()); + return; + } + + Group* owner_group = c->GetGroup(); + if (owner_group) { + std::list member_list; + owner_group->GetClientList(member_list); + member_list.remove(nullptr); + + for (auto member_iter : member_list) { + if (member_iter->IsEngaged() || member_iter->GetAggroCount() > 0) { + c->Message(m_fail, "You can't spawn bots while your group is engaged"); + return; + } + } + } + else { + if (c->GetAggroCount() > 0) { + c->Message(m_fail, "You can't spawn bots while you are engaged"); + return; + } + } + + uint32 botgroup_id = 0; + if (!botdb.LoadBotGroupIDForLoadBotGroup(c->CharacterID(), botgroup_name_arg, botgroup_id) || !botgroup_id) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroupIDForLoadBotGroup(), botgroup_name_arg.c_str()); + return; + } + + std::map> member_list; + if (!botdb.LoadBotGroup(botgroup_name_arg, member_list)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadBotGroup(), botgroup_name_arg.c_str()); + return; + } + if (member_list.find(botgroup_id) == member_list.end() || member_list[botgroup_id].empty()) { + c->Message(m_fail, "Database returned an empty list for bot-group '%s'", botgroup_name_arg.c_str()); + return; + } + + int spawned_bot_count = Bot::SpawnedBotCount(c->CharacterID()); + + if (RuleB(Bots, QuestableSpawnLimit)) { + int allowed_bot_count = 0; + if (!botdb.LoadQuestableSpawnCount(c->CharacterID(), allowed_bot_count)) { + c->Message(m_fail, "%s", BotDatabase::fail::LoadQuestableSpawnCount()); + return; + } + + if (!allowed_bot_count) { + c->Message(m_fail, "You can not spawn any bots"); + return; + } + + if (spawned_bot_count >= allowed_bot_count || (spawned_bot_count + member_list.begin()->second.size()) > allowed_bot_count) { + c->Message(m_fail, "You can not spawn more than %i bot%s (quest-limit)", allowed_bot_count, ((allowed_bot_count == 1) ? ("") : ("s"))); + return; + } + } + + const int allowed_bot_limit = RuleI(Bots, SpawnLimit); + if (spawned_bot_count >= allowed_bot_limit || (spawned_bot_count + member_list.begin()->second.size()) > allowed_bot_limit) { + c->Message(m_fail, "You can not spawn more than %i bot%s (hard-limit)", allowed_bot_limit, ((allowed_bot_limit == 1) ? ("") : ("s"))); + return; + } + + uint32 leader_id = 0; + if (!botdb.LoadLeaderIDByBotGroupName(botgroup_name_arg, leader_id)) { + c->Message(m_fail, "%s for '%s'", BotDatabase::fail::LoadLeaderIDByBotGroupName(), botgroup_name_arg.c_str()); + return; + } + if (!leader_id) { + c->Message(m_fail, "Can not 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()); + safe_delete(botgroup_leader); + return; + } + + botgroup_leader->Spawn(c); + + Group* group_inst = new Group(botgroup_leader); + + entity_list.AddGroup(group_inst); + database.SetGroupID(botgroup_leader->GetCleanName(), group_inst->GetID(), botgroup_leader->GetBotID()); + database.SetGroupLeaderName(group_inst->GetID(), botgroup_leader->GetCleanName()); + botgroup_leader->SetFollowID(c->GetID()); + + member_list[botgroup_id].remove(0); + member_list[botgroup_id].remove(botgroup_leader->GetBotID()); + for (auto member_iter : member_list[botgroup_id]) { + auto botgroup_member = Bot::LoadBot(member_iter); + if (!botgroup_member) { + c->Message(m_fail, "Could not load bot id %i", member_iter); + safe_delete(botgroup_member); + return; + } + + botgroup_member->Spawn(c); + Bot::AddBotToGroup(botgroup_member, group_inst); + } + + c->Message(m_action, "Successfully loaded bot-group %s", botgroup_name_arg.c_str()); +} + +void bot_subcommand_botgroup_remove_member(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_botgroup_remove_member", sep->arg[0], "botgroupremovemember")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a group member as a bot that you own to use this command"); + return; + } + + auto group_member = sbl.front(); + if (!group_member) { + c->Message(m_unknown, "Error: Group member bot dereferenced to nullptr"); + return; + } + + if (!group_member->HasGroup()) { + c->Message(m_fail, "%s is not a current member of a group", group_member->GetCleanName()); + return; + } + + if (!Bot::RemoveBotFromGroup(group_member, group_member->GetGroup())) { + c->Message(m_fail, "Could not remove %s from their group", group_member->GetCleanName()); + return; + } + + if (!botdb.RemoveMemberFromBotGroup(group_member->GetBotID())) { + c->Message(m_fail, "%s - '%s'", BotDatabase::fail::RemoveMemberFromBotGroup(), group_member->GetCleanName()); + return; + } + + c->Message(m_action, "Successfully removed %s from their bot-group", group_member->GetCleanName()); +} + +void bot_subcommand_circle(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Depart]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Depart) || helper_command_alias_fail(c, "bot_subcommand_circle", sep->arg[0], "circle")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [list | destination] ([option: single])", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Depart, DRUID); + return; + } + + bool single = false; + std::string single_arg = sep->arg[2]; + if (!single_arg.compare("single")) + single = true; + + std::string destination = sep->arg[1]; + if (!destination.compare("list")) { + auto my_druid_bot = ActionableBots::AsGroupMember_ByClass(c, c, DRUID); + helper_command_depart_list(c, my_druid_bot, nullptr, local_list, single); + return; + } + else if (destination.empty()) { + c->Message(m_fail, "A [destination] or [list] argument is required to use this command"); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToDepart(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->caster_class != DRUID) + continue; + if (local_entry->single != single) + continue; + if (destination.compare(spells[local_entry->spell_id].teleport_zone)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + +void bot_subcommand_heal_rotation_adaptive_targeting(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_adaptive_targeting", sep->arg[0], "healrotationadaptivetargeting")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name]) ([option: on | off])", sep->arg[0]); + return; + } + + std::string adaptive_targeting_arg; + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (!sbl.empty()) { + adaptive_targeting_arg = sep->arg[2]; + } + else { + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + adaptive_targeting_arg = sep->arg[1]; + } + + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + bool hr_adaptive_targeting = false; + + if (!adaptive_targeting_arg.compare("on")) { + hr_adaptive_targeting = true; + } + else if (adaptive_targeting_arg.compare("off")) { + c->Message(m_action, "Adaptive targeting is currently '%s' for %s's Heal Rotation", (((*current_member->MemberOfHealRotation())->AdaptiveTargeting()) ? ("on") : ("off")), current_member->GetCleanName()); + return; + } + + (*current_member->MemberOfHealRotation())->SetAdaptiveTargeting(hr_adaptive_targeting); + + c->Message(m_action, "Adaptive targeting is now '%s' for %s's Heal Rotation", (((*current_member->MemberOfHealRotation())->AdaptiveTargeting()) ? ("on") : ("off")), current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_add_member(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_add_member", sep->arg[0], "healrotationaddmember")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [new_member_name] ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) { + c->Message(m_fail, "You must [name] a new member as a bot that you own to use this command"); + return; + } + + auto new_member = sbl.front(); + if (!new_member) { + c->Message(m_unknown, "Error: New member bot dereferenced to nullptr"); + return; + } + + if (new_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is already a current member of a Heal Rotation and can not join another one", new_member->GetCleanName()); + return; + } + + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[2]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + if (!new_member->JoinHealRotationMemberPool(current_member->MemberOfHealRotation())) { + c->Message(m_fail, "Failed to add %s as a current member of this Heal Rotation", new_member->GetCleanName()); + return; + } + + c->Message(m_action, "Successfully added %s as a current member of this Heal Rotation", new_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_add_target(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_add_target", sep->arg[0], "healrotationaddtarget")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [heal_target_name] ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[2]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + auto heal_target = entity_list.GetMob(sep->arg[1]); + if (!heal_target) { + c->Message(m_fail, "No target exists by the name '%s'", sep->arg[1]); + return; + } + + if ((!heal_target->IsClient() && !heal_target->IsBot() && !heal_target->IsPet()) || + (heal_target->IsPet() && (!heal_target->GetOwner() || (!heal_target->GetOwner()->IsClient() && !heal_target->GetOwner()->IsBot())))) + { + c->Message(m_fail, "%s's entity type is not an allowable heal target", heal_target->GetCleanName()); + return; + } + + if (!heal_target->JoinHealRotationTargetPool(current_member->MemberOfHealRotation())) { + c->Message(m_fail, "Failed to add heal target with a name of '%s'", heal_target->GetCleanName()); + return; + } + + c->Message(m_action, "Successfully added heal target %s to %s's Heal Rotation", heal_target->GetCleanName(), current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_adjust_critical(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_adjust_critical", sep->arg[0], "healrotationadjustcritical")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [armor_type] [value: %3.1f-%3.1f | + | -] ([member_name])", sep->arg[0], CRITICAL_HP_RATIO_BASE, SAFE_HP_RATIO_BASE); + c->Message(m_note, "armor_types: %u(Base), %u(Cloth), %u(Leather), %u(Chain), %u(Plate)", + ARMOR_TYPE_UNKNOWN, ARMOR_TYPE_CLOTH, ARMOR_TYPE_LEATHER, ARMOR_TYPE_CHAIN, ARMOR_TYPE_PLATE); + return; + } + + std::string armor_type_arg = sep->arg[1]; + std::string critical_arg = sep->arg[2]; + + uint8 armor_type_value = 255; + if (sep->IsNumber(1)) + armor_type_value = atoi(armor_type_arg.c_str()); + + if (armor_type_value > ARMOR_TYPE_LAST) { + c->Message(m_fail, "You must specify a valid [armor_type: %u-%u] to use this command", ARMOR_TYPE_FIRST, ARMOR_TYPE_LAST); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[3]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + float critical_ratio = CRITICAL_HP_RATIO_BASE; + if (sep->IsNumber(2)) + critical_ratio = atof(critical_arg.c_str()); + else if (!critical_arg.compare("+")) + critical_ratio = (*current_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(armor_type_value) + HP_RATIO_DELTA; + else if (!critical_arg.compare("-")) + critical_ratio = (*current_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(armor_type_value) - HP_RATIO_DELTA; + + if (critical_ratio > SAFE_HP_RATIO_ABS) + critical_ratio = SAFE_HP_RATIO_ABS; + if (critical_ratio < CRITICAL_HP_RATIO_ABS) + critical_ratio = CRITICAL_HP_RATIO_ABS; + + if (!(*current_member->MemberOfHealRotation())->SetArmorTypeCriticalHPRatio(armor_type_value, critical_ratio)) { + c->Message(m_fail, "Critical value %3.1f%%(%u) exceeds safe value %3.1f%%(%u) for %s's Heal Rotation", + critical_ratio, armor_type_value, (*current_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(armor_type_value), armor_type_value, current_member->GetCleanName()); + return; + } + + c->Message(m_action, "Class Armor Type %u critical value %3.1f%% set for %s's Heal Rotation", + armor_type_value, (*current_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(armor_type_value), current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_adjust_safe(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_adjust_safe", sep->arg[0], "healrotationadjustsafe")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [armor_type] [value: %3.1f-%3.1f | + | -] ([member_name])", sep->arg[0], CRITICAL_HP_RATIO_BASE, SAFE_HP_RATIO_BASE); + c->Message(m_note, "armor_types: %u(Base), %u(Cloth), %u(Leather), %u(Chain), %u(Plate)", + ARMOR_TYPE_UNKNOWN, ARMOR_TYPE_CLOTH, ARMOR_TYPE_LEATHER, ARMOR_TYPE_CHAIN, ARMOR_TYPE_PLATE); + return; + } + + std::string armor_type_arg = sep->arg[1]; + std::string safe_arg = sep->arg[2]; + + uint8 armor_type_value = 255; + if (sep->IsNumber(1)) + armor_type_value = atoi(armor_type_arg.c_str()); + + if (armor_type_value > ARMOR_TYPE_LAST) { + c->Message(m_fail, "You must specify a valid [armor_type: %u-%u] to use this command", ARMOR_TYPE_FIRST, ARMOR_TYPE_LAST); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[3]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + float safe_ratio = SAFE_HP_RATIO_BASE; + if (sep->IsNumber(2)) + safe_ratio = atof(safe_arg.c_str()); + else if (!safe_arg.compare("+")) + safe_ratio = (*current_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(armor_type_value) + HP_RATIO_DELTA; + else if (!safe_arg.compare("-")) + safe_ratio = (*current_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(armor_type_value) - HP_RATIO_DELTA; + + if (safe_ratio > SAFE_HP_RATIO_ABS) + safe_ratio = SAFE_HP_RATIO_ABS; + if (safe_ratio < CRITICAL_HP_RATIO_ABS) + safe_ratio = CRITICAL_HP_RATIO_ABS; + + if (!(*current_member->MemberOfHealRotation())->SetArmorTypeSafeHPRatio(armor_type_value, safe_ratio)) { + c->Message(m_fail, "Safe value %3.1f%%(%u) does not exceed critical value %3.1f%%(%u) for %s's Heal Rotation", + safe_ratio, armor_type_value, (*current_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(armor_type_value), armor_type_value, current_member->GetCleanName()); + return; + } + + c->Message(m_action, "Class Armor Type %u safe value %3.1f%% set for %s's Heal Rotation", + armor_type_value, (*current_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(armor_type_value), current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_casting_override(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_casting_override", sep->arg[0], "healrotationcastingoverride")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name]) ([option: on | off])", sep->arg[0]); + return; + } + + std::string casting_override_arg; + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (!sbl.empty()) { + casting_override_arg = sep->arg[2]; + } + else { + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + casting_override_arg = sep->arg[1]; + } + + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + bool hr_casting_override = false; + + if (!casting_override_arg.compare("on")) { + hr_casting_override = true; + } + else if (casting_override_arg.compare("off")) { + c->Message(m_action, "Casting override is currently '%s' for %s's Heal Rotation", (((*current_member->MemberOfHealRotation())->CastingOverride()) ? ("on") : ("off")), current_member->GetCleanName()); + return; + } + + (*current_member->MemberOfHealRotation())->SetCastingOverride(hr_casting_override); + + c->Message(m_action, "Casting override is now '%s' for %s's Heal Rotation", (((*current_member->MemberOfHealRotation())->CastingOverride()) ? ("on") : ("off")), current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_change_interval(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_change_interval", sep->arg[0], "healrotationchangeinterval")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name]) ([interval=%u: %u-%u(seconds)])", + sep->arg[0], CASTING_CYCLE_DEFAULT_INTERVAL_S, CASTING_CYCLE_MINIMUM_INTERVAL_S, CASTING_CYCLE_MAXIMUM_INTERVAL_S); + return; + } + + std::string change_interval_arg; + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (!sbl.empty()) { + change_interval_arg = sep->arg[2]; + } + else { + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + change_interval_arg = sep->arg[1]; + } + + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + uint32 hr_change_interval_s = CASTING_CYCLE_DEFAULT_INTERVAL_S; + + if (!change_interval_arg.empty()) { + hr_change_interval_s = atoi(change_interval_arg.c_str()); + } + else { + hr_change_interval_s = (*current_member->MemberOfHealRotation())->IntervalS(); + c->Message(m_action, "Casting interval is currently '%i' second%s for %s's Heal Rotation", hr_change_interval_s, ((hr_change_interval_s == 1) ? ("") : ("s")), current_member->GetCleanName()); + return; + } + + if (hr_change_interval_s < CASTING_CYCLE_MINIMUM_INTERVAL_S || hr_change_interval_s > CASTING_CYCLE_MAXIMUM_INTERVAL_S) + hr_change_interval_s = CASTING_CYCLE_DEFAULT_INTERVAL_S; + + (*current_member->MemberOfHealRotation())->SetIntervalS(hr_change_interval_s); + + hr_change_interval_s = (*current_member->MemberOfHealRotation())->IntervalS(); + c->Message(m_action, "Casting interval is now '%i' second%s for %s's Heal Rotation", hr_change_interval_s, ((hr_change_interval_s == 1) ? ("") : ("s")), current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_clear_hot(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_clear_hot", sep->arg[0], "healrotationclearhot")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + if (!(*current_member->MemberOfHealRotation())->ClearHOTTarget()) { + c->Message(m_fail, "Failed to clear %s's Heal Rotation HOT", current_member->GetCleanName()); + } + + c->Message(m_action, "Succeeded in clearing %s's Heal Rotation HOT", current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_clear_targets(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_clear_targets", sep->arg[0], "healrotationcleartargets")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + if (!(*current_member->MemberOfHealRotation())->ClearTargetPool()) { + c->Message(m_fail, "Failed to clear all targets from %s's Heal Rotation", current_member->GetCleanName()); + return; + } + + c->Message(m_action, "All targets have been cleared from %s's Heal Rotation", current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_create(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_create", sep->arg[0], "healrotationcreate")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([creator_name]) ([interval=%u: %u-%u(seconds)] [fastheals=off: on | off] [adaptivetargeting=off: on | off] [castingoverride=off: on | off])", + sep->arg[0], CASTING_CYCLE_DEFAULT_INTERVAL_S, CASTING_CYCLE_MINIMUM_INTERVAL_S, CASTING_CYCLE_MAXIMUM_INTERVAL_S); + return; + } + + std::string interval_arg; + std::string fast_heals_arg; + std::string adaptive_targeting_arg; + std::string casting_override_arg; + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (!sbl.empty()) { + interval_arg = sep->arg[2]; + fast_heals_arg = sep->arg[3]; + adaptive_targeting_arg = sep->arg[4]; + casting_override_arg = sep->arg[5]; + } + else { + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + interval_arg = sep->arg[1]; + fast_heals_arg = sep->arg[2]; + adaptive_targeting_arg = sep->arg[3]; + casting_override_arg = sep->arg[4]; + } + + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a creator as a bot that you own to use this command"); + return; + } + + auto creator_member = sbl.front(); + if (!creator_member) { + c->Message(m_unknown, "Error: Creator bot dereferenced to nullptr"); + return; + } + + if (creator_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is already a current member of a Heal Rotation", creator_member->GetCleanName()); + return; + } + + uint32 hr_interval_s = CASTING_CYCLE_DEFAULT_INTERVAL_S; + bool hr_fast_heals = false; + bool hr_adaptive_targeting = false; + bool hr_casting_override = false; + + if (!casting_override_arg.compare("on")) { + hr_casting_override = true; + if (!adaptive_targeting_arg.compare("on")) + hr_adaptive_targeting = true; + if (!fast_heals_arg.compare("on")) + hr_fast_heals = true; + hr_interval_s = atoi(interval_arg.c_str()); + } + else if (!casting_override_arg.compare("off")) { + if (!adaptive_targeting_arg.compare("on")) + hr_adaptive_targeting = true; + if (!fast_heals_arg.compare("on")) + hr_fast_heals = true; + hr_interval_s = atoi(interval_arg.c_str()); + } + + if (hr_interval_s < CASTING_CYCLE_MINIMUM_INTERVAL_S || hr_interval_s > CASTING_CYCLE_MAXIMUM_INTERVAL_S) + hr_interval_s = CASTING_CYCLE_DEFAULT_INTERVAL_S; + + hr_interval_s *= 1000; // convert to milliseconds for Bot/HealRotation constructor + + if (!creator_member->CreateHealRotation(hr_interval_s, hr_fast_heals, hr_adaptive_targeting, hr_casting_override)) { + c->Message(m_fail, "Failed to add %s as a current member to a new Heal Rotation", creator_member->GetCleanName()); + return; + } + + std::list member_list; + std::list target_list; + bool load_flag = false; + bool member_fail = false; + bool target_fail = false; + + if (!botdb.LoadHealRotation(creator_member, member_list, target_list, load_flag, member_fail, target_fail)) + c->Message(m_fail, "%s", BotDatabase::fail::LoadHealRotation()); + + if (!load_flag) { + c->Message(m_action, "Successfully added %s as a current member to a new Heal Rotation", creator_member->GetCleanName()); + return; + } + + if (!member_fail) { + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + for (auto member_iter : member_list) { + if (!member_iter || member_iter == creator_member->GetBotID()) + continue; + + bool member_found = false; + for (auto bot_iter : sbl) { + if (bot_iter->GetBotID() != member_iter) + continue; + + if (!bot_iter->JoinHealRotationMemberPool(creator_member->MemberOfHealRotation())) + c->Message(m_fail, "Failed to add member '%s'", bot_iter->GetCleanName()); + member_found = true; + + break; + } + + if (!member_found) + c->Message(m_fail, "Could not locate member with bot id '%u'", member_iter); + } + } + else { + c->Message(m_fail, "%s", BotDatabase::fail::LoadHealRotationMembers()); + } + + if (!target_fail) { + for (auto target_iter : target_list) { + if (target_iter.empty()) + continue; + + auto target_mob = entity_list.GetMob(target_iter.c_str()); + if (!target_mob) { + c->Message(m_fail, "Could not locate target '%s'", target_iter.c_str()); + continue; + } + + if (!target_mob->JoinHealRotationTargetPool(creator_member->MemberOfHealRotation())) + c->Message(m_fail, "Failed to add target '%s'", target_mob->GetCleanName()); + } + } + else { + c->Message(m_fail, "%s", BotDatabase::fail::LoadHealRotationTargets()); + } + + c->Message(m_action, "Successfully loaded %s's Heal Rotation", creator_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_delete(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_delete", sep->arg[0], "healrotationdelete")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([option: all]) ([member_name])", sep->arg[0]); + return; + } + + bool all_flag = false; + int name_arg = 1; + if (!strcasecmp(sep->arg[1], "all")) { + all_flag = true; + name_arg = 2; + } + + if (all_flag) { + if (botdb.DeleteAllHealRotations(c->CharacterID())) + c->Message(m_action, "Succeeded in deleting all heal rotations"); + else + c->Message(m_fail, "%s", BotDatabase::fail::DeleteAllHealRotations()); + + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[name_arg]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!botdb.DeleteHealRotation(current_member->GetBotID())) { + c->Message(m_fail, "%s", BotDatabase::fail::DeleteHealRotation()); + return; + } + + c->Message(m_action, "Succeeded in deleting %s's heal rotation", current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_fast_heals(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_fast_heals", sep->arg[0], "healrotationfastheals")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name]) ([option: on | off])", sep->arg[0]); + return; + } + + std::string fast_heals_arg; + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (!sbl.empty()) { + fast_heals_arg = sep->arg[2]; + } + else { + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + fast_heals_arg = sep->arg[1]; + } + + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + bool hr_fast_heals = false; + + if (!fast_heals_arg.compare("on")) { + hr_fast_heals = true; + } + else if (fast_heals_arg.compare("off")) { + c->Message(m_action, "Fast heals are currently '%s' for %s's Heal Rotation", (((*current_member->MemberOfHealRotation())->FastHeals()) ? ("on") : ("off")), current_member->GetCleanName()); + return; + } + + (*current_member->MemberOfHealRotation())->SetFastHeals(hr_fast_heals); + + c->Message(m_action, "Fast heals are now '%s' for %s's Heal Rotation", (((*current_member->MemberOfHealRotation())->FastHeals()) ? ("on") : ("off")), current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_list(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_list", sep->arg[0], "healrotationlist")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + c->Message(m_note, "Heal Rotation Settings:"); + + c->Message(m_message, "Current state: %s", (((*current_member->MemberOfHealRotation())->IsActive()) ? ("active") : ("inactive"))); + c->Message(m_message, "Casting interval: %i seconds", (*current_member->MemberOfHealRotation())->IntervalS()); + c->Message(m_message, "Fast heals: '%s'", (((*current_member->MemberOfHealRotation())->FastHeals()) ? ("on") : ("off"))); + c->Message(m_message, "Adaptive targeting: '%s'", (((*current_member->MemberOfHealRotation())->AdaptiveTargeting()) ? ("on") : ("off"))); + c->Message(m_message, "Casting override: '%s'", (((*current_member->MemberOfHealRotation())->CastingOverride()) ? ("on") : ("off"))); + c->Message(m_message, "HOT state: %s", (((*current_member->MemberOfHealRotation())->IsHOTActive()) ? ("active") : ("inactive"))); + c->Message(m_message, "HOT target: %s", (((*current_member->MemberOfHealRotation())->HOTTarget()) ? ((*current_member->MemberOfHealRotation())->HOTTarget()->GetCleanName()) : ("null"))); + + c->Message(m_message, "Base hp limits - critical: %3.1f%%, safe: %3.1f%%", + (*current_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_UNKNOWN), + (*current_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_UNKNOWN)); + c->Message(m_message, "Cloth hp limits - critical: %3.1f%%, safe: %3.1f%%", + (*current_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_CLOTH), + (*current_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_CLOTH)); + c->Message(m_message, "Leather hp limits - critical: %3.1f%%, safe: %3.1f%%", + (*current_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_LEATHER), + (*current_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_LEATHER)); + c->Message(m_message, "Chain hp limits - critical: %3.1f%%, safe: %3.1f%%", + (*current_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_CHAIN), + (*current_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_CHAIN)); + c->Message(m_message, "Plate hp limits - critical: %3.1f%%, safe: %3.1f%%", + (*current_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_PLATE), + (*current_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_PLATE)); + + c->Message(m_note, "Heal Rotation Members:"); + + int member_index = 0; + auto member_pool = (*current_member->MemberOfHealRotation())->MemberList(); + for (auto member_iter : *member_pool) { + if (!member_iter) + continue; + + c->Message(m_message, "(%i) %s", (++member_index), member_iter->GetCleanName()); + } + if (!member_index) + c->Message(m_fail, "(0) None"); + + c->Message(m_note, "Heal Rotation Targets:"); + + int target_index = 0; + auto target_pool = (*current_member->MemberOfHealRotation())->TargetList(); + for (auto target_iter : *target_pool) { + if (!target_iter) + continue; + + c->Message(m_message, "(%i) %s", (++target_index), target_iter->GetCleanName()); + } + if (!target_index) + c->Message(m_message, "(0) None"); +} + +void bot_subcommand_heal_rotation_remove_member(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_remove_member", sep->arg[0], "healrotationremovemember")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + if (!current_member->LeaveHealRotationMemberPool()) { + c->Message(m_fail, "Failed to remove %s from their Heal Rotation", current_member->GetCleanName()); + return; + } + + c->Message(m_action, "%s has been removed from their Heal Rotation", current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_remove_target(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_remove_target", sep->arg[0], "healrotationremovetarget")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [heal_target_name] ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[2]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + auto heal_target = entity_list.GetMob(sep->arg[1]); + if (!heal_target) { + c->Message(m_fail, "No target exists by the name '%s'", sep->arg[1]); + return; + } + + if (!current_member->MemberOfHealRotation()->get()->IsTargetInPool(heal_target) || !heal_target->LeaveHealRotationTargetPool()) { + c->Message(m_fail, "Failed to remove heal target with a name of '%s'", heal_target->GetCleanName()); + return; + } + + c->Message(m_action, "Successfully removed heal target %s from %s's Heal Rotation", heal_target->GetCleanName(), current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_reset_limits(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_reset_limits", sep->arg[0], "healrotationresetlimits")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + (*current_member->MemberOfHealRotation())->ResetArmorTypeHPLimits(); + + c->Message(m_action, "Class Armor Type HP limit criteria has been set to default values for %s's Heal Rotation", current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_save(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_save", sep->arg[0], "healrotationsave")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + bool member_fail = false; + bool target_fail = false; + if (!botdb.SaveHealRotation(current_member, member_fail, target_fail)) { + c->Message(m_fail, "%s", BotDatabase::fail::SaveHealRotation()); + return; + } + if (member_fail) + c->Message(m_fail, "Failed to save heal rotation members"); + if (target_fail) + c->Message(m_fail, "Failed to save heal rotation targets"); + + c->Message(m_action, "Succeeded in saving %s's heal rotation", current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_set_hot(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_set_hot", sep->arg[0], "healrotationsethot")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s [heal_override_target_name] ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[2]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + auto hot_target = entity_list.GetMob(sep->arg[1]); + if (!hot_target) { + c->Message(m_fail, "No target exists by the name '%s'", sep->arg[1]); + return; + } + + if (!(*current_member->MemberOfHealRotation())->IsTargetInPool(hot_target)) { + c->Message(m_fail, "%s is not a target in %s's Heal Rotation", hot_target->GetCleanName(), current_member->GetCleanName()); + return; + } + + if (!(*current_member->MemberOfHealRotation())->SetHOTTarget(hot_target)) { + c->Message(m_fail, "Failed to set %s as the HOT in %s's Heal Rotation", hot_target->GetCleanName(), current_member->GetCleanName()); + return; + } + + c->Message(m_action, "Succeeded in setting %s as the HOT in %s's Heal Rotation", hot_target->GetCleanName(), current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_start(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_start", sep->arg[0], "healrotationstart")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + if ((*current_member->MemberOfHealRotation())->IsActive()) { + c->Message(m_fail, "%s's Heal Rotation is already active", current_member->GetCleanName()); + return; + } + + if (!current_member->MemberOfHealRotation()->get()->Start()) { + c->Message(m_fail, "Failed to start %s's Heal Rotation", current_member->GetCleanName()); + return; + } + + c->Message(m_action, "%s's Heal Rotation is now active", current_member->GetCleanName()); +} + +void bot_subcommand_heal_rotation_stop(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_heal_rotation_stop", sep->arg[0], "healrotationstop")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: () %s ([member_name])", sep->arg[0]); + return; + } + + std::list sbl; + MyBots::PopulateSBL_ByNamedBot(c, sbl, sep->arg[1]); + if (sbl.empty()) + MyBots::PopulateSBL_ByTargetedBot(c, sbl); + if (sbl.empty()) { + c->Message(m_fail, "You must or [name] a current member as a bot that you own to use this command"); + return; + } + + auto current_member = sbl.front(); + if (!current_member) { + c->Message(m_unknown, "Error: Current member bot dereferenced to nullptr"); + return; + } + + if (!current_member->IsHealRotationMember()) { + c->Message(m_fail, "%s is not a current member of a Heal Rotation", current_member->GetCleanName()); + return; + } + + if (!(*current_member->MemberOfHealRotation())->IsActive()) { + c->Message(m_fail, "%s's Heal Rotation is already inactive", current_member->GetCleanName()); + return; + } + + if (!current_member->MemberOfHealRotation()->get()->Stop()) { + c->Message(m_fail, "Failed to stop %s's Heal Rotation", current_member->GetCleanName()); + return; + } + + c->Message(m_action, "%s's Heal Rotation is now inactive", current_member->GetCleanName()); +} + +void bot_subcommand_inventory_give(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_inventory_give", sep->arg[0], "inventorygive")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: target | byname] ([actionable_name]))", sep->arg[0]); + return; + } + int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName); + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + auto my_bot = sbl.front(); + if (!my_bot) { + c->Message(m_unknown, "ActionableBots returned 'nullptr'"); + return; + } + + my_bot->FinishTrade(c, Bot::BotTradeClientNoDropNoTrade); +} + +void bot_subcommand_inventory_list(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_inventory_list", sep->arg[0], "inventorylist")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: target | byname] ([actionable_name]))", sep->arg[0]); + return; + } + int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName); + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + auto my_bot = sbl.front(); + if (!my_bot) { + c->Message(m_unknown, "ActionableBots returned 'nullptr'"); + return; + } + + const ItemInst* inst = nullptr; + const EQEmu::ItemBase* item = nullptr; + bool is2Hweapon = false; + + std::string item_link; + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemInst); + + uint32 inventory_count = 0; + for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= (EQEmu::legacy::EQUIPMENT_END + 1); ++i) { + if ((i == EQEmu::legacy::SlotSecondary) && is2Hweapon) + continue; + + inst = my_bot->CastToBot()->GetBotItem(i == 22 ? EQEmu::legacy::SlotPowerSource : i); + if (!inst || !inst->GetItem()) { + c->Message(m_message, "I need something for my %s (slot %i)", GetBotEquipSlotName(i), (i == 22 ? EQEmu::legacy::SlotPowerSource : i)); + continue; + } + + item = inst->GetItem(); + if ((i == EQEmu::legacy::SlotPrimary) && item->IsType2HWeapon()) { + is2Hweapon = true; + } + + 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::legacy::SlotPowerSource : i)); + + ++inventory_count; + } + + uint32 database_count = 0; + if (!botdb.QueryInventoryCount(my_bot->GetBotID(), database_count)) + c->Message(m_unknown, "%s", BotDatabase::fail::QueryInventoryCount()); + + if (inventory_count != database_count) + c->Message(m_unknown, "Inventory-database item count mismatch: inv = '%u', db = '%u'", inventory_count, database_count); +} + +void bot_subcommand_inventory_remove(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_inventory_remove", sep->arg[0], "inventoryremove")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [slotid: 0-22] ([actionable: target | byname] ([actionable_name]))", sep->arg[0]); + return; + } + int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName); + + if (c->GetTradeskillObject() || (c->trade->state == Trading)) { + c->Message_StringID(MT_Tell, MERCHANT_BUSY); + return; + } + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[2], sbl, ab_mask, sep->arg[3]) == ActionableBots::ABT_None) + return; + + auto my_bot = sbl.front(); + if (!my_bot) { + c->Message(m_unknown, "ActionableBots returned 'nullptr'"); + return; + } + + int slotId = atoi(sep->arg[1]); + if (!sep->IsNumber(1) || ((slotId > EQEmu::legacy::EQUIPMENT_END || slotId < EQEmu::legacy::EQUIPMENT_BEGIN) && slotId != EQEmu::legacy::SlotPowerSource)) { + c->Message(m_fail, "Valid slots are 0-21 or 9999"); + return; + } + + const EQEmu::ItemBase* itm = nullptr; + const ItemInst* itminst = my_bot->GetBotItem(slotId); + if (itminst) + itm = itminst->GetItem(); + + if (itminst && itm && c->CheckLoreConflict(itm)) { + c->Message_StringID(0, PICK_LORE); + return; + } + + for (int m = AUG_INDEX_BEGIN; m < EQEmu::legacy::ITEM_COMMON_SIZE; ++m) { + if (!itminst) + break; + + ItemInst *itma = itminst->GetAugment(m); + if (!itma) + continue; + if (!c->CheckLoreConflict(itma->GetItem())) + continue; + + c->Message_StringID(0, PICK_LORE); + return; + } + + std::string error_message; + if (itm) { + c->PushItemOnCursor(*itminst, true); + if ((slotId == EQEmu::legacy::SlotRange) || (slotId == EQEmu::legacy::SlotAmmo) || (slotId == EQEmu::legacy::SlotPrimary) || (slotId == EQEmu::legacy::SlotSecondary)) + my_bot->SetBotArcher(false); + + my_bot->RemoveBotItemBySlot(slotId, &error_message); + if (!error_message.empty()) { + c->Message(m_unknown, "Database Error: %s", error_message.c_str()); + return; + } + + my_bot->BotRemoveEquipItem(slotId); + my_bot->CalcBotStats(); + } + + switch (slotId) { + case EQEmu::legacy::SlotCharm: + case EQEmu::legacy::SlotEar1: + case EQEmu::legacy::SlotHead: + case EQEmu::legacy::SlotFace: + case EQEmu::legacy::SlotEar2: + case EQEmu::legacy::SlotNeck: + case EQEmu::legacy::SlotBack: + case EQEmu::legacy::SlotWrist1: + case EQEmu::legacy::SlotWrist2: + case EQEmu::legacy::SlotRange: + case EQEmu::legacy::SlotPrimary: + case EQEmu::legacy::SlotSecondary: + case EQEmu::legacy::SlotFinger1: + case EQEmu::legacy::SlotFinger2: + case EQEmu::legacy::SlotChest: + case EQEmu::legacy::SlotWaist: + case EQEmu::legacy::SlotPowerSource: + case EQEmu::legacy::SlotAmmo: + c->Message(m_message, "My %s is %s unequipped", GetBotEquipSlotName(slotId), ((itm) ? ("now") : ("already"))); + break; + case EQEmu::legacy::SlotShoulders: + case EQEmu::legacy::SlotArms: + case EQEmu::legacy::SlotHands: + case EQEmu::legacy::SlotLegs: + case EQEmu::legacy::SlotFeet: + c->Message(m_message, "My %s are %s unequipped", GetBotEquipSlotName(slotId), ((itm) ? ("now") : ("already"))); + break; + default: + c->Message(m_fail, "I'm soo confused..."); + break; + } +} + +void bot_subcommand_inventory_window(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_inventory_window", sep->arg[0], "inventorywindow")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [actionable: target]", sep->arg[0]); + return; + } + int ab_mask = ActionableBots::ABM_Target; + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + auto my_bot = sbl.front(); + if (!my_bot) { + c->Message(m_unknown, "ActionableBots returned 'nullptr'"); + return; + } + + std::string window_title = my_bot->GetCleanName(); + window_title.append("`s Inventory"); + + std::string window_text; + //std::string item_link; + //Client::TextLink linker; + //linker.SetLinkType(linker.linkItemInst); + + for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= (EQEmu::legacy::EQUIPMENT_END + 1); ++i) { + const EQEmu::ItemBase* item = nullptr; + const ItemInst* inst = my_bot->CastToBot()->GetBotItem(i == 22 ? EQEmu::legacy::SlotPowerSource : i); + if (inst) + item = inst->GetItem(); + + window_text.append(""); + window_text.append(GetBotEquipSlotName(i == 22 ? EQEmu::legacy::SlotPowerSource : i)); + window_text.append(": "); + if (item) { + //window_text.append(""); + //linker.SetItemInst(inst); + //item_link = linker.GenerateLink(); + //window_text.append(item_link.c_str()); + + window_text.append(""); + window_text.append(StringFormat("%s", item->Name)); + } + else { + window_text.append(""); + window_text.append("[empty]"); + } + window_text.append("
"); + } + window_text.append("
"); + + c->SendPopupToClient(window_title.c_str(), window_text.c_str()); +} + +void bot_subcommand_pet_remove(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_pet_remove", sep->arg[0], "petremove")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s ([actionable: target | byname] ([actionable_name]))", sep->arg[0]); + return; + } + int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName); + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[1], sbl, ab_mask, sep->arg[2]) == ActionableBots::ABT_None) + return; + + uint16 class_mask = (PLAYER_CLASS_DRUID_BIT | PLAYER_CLASS_NECROMANCER_BIT | PLAYER_CLASS_ENCHANTER_BIT); + ActionableBots::Filter_ByClasses(c, sbl, class_mask); + if (sbl.empty()) { + c->Message(m_fail, "You have no spawned bots capable of charming"); + return; + } + sbl.remove(nullptr); + + int charmed_pet = 0; + int summoned_pet = 0; + for (auto bot_iter : sbl) { // Probably needs some work to release charmed pets + if (bot_iter->IsBotCharmer()) { + bot_iter->SetBotCharmer(false); + if (sbl.size() == 1) + Bot::BotGroupSay(bot_iter, "Using a summoned pet"); + ++summoned_pet; + continue; + } + + if (bot_iter->GetPet()) { + bot_iter->GetPet()->Say_StringID(PET_GETLOST_STRING); + bot_iter->GetPet()->Depop(false); + bot_iter->SetPetID(0); + } + bot_iter->SetBotCharmer(true); + if (sbl.size() == 1) + Bot::BotGroupSay(bot_iter, "Available for Charming"); + ++charmed_pet; + } + + if (sbl.size() != 1) + c->Message(m_action, "%i of your bots set for charming, %i of your bots set for summoned pet use", charmed_pet, summoned_pet); +} + +void bot_subcommand_pet_set_type(Client *c, const Seperator *sep) +{ + if (helper_command_alias_fail(c, "bot_subcommand_pet_set_type", sep->arg[0], "petsettype")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [type: water | fire | air | earth | monster] ([actionable: target | byname] ([actionable_name]))", sep->arg[0]); + c->Message(m_note, "requires one of the following bot classes:"); + c->Message(m_message, "Magician(1)"); + return; + } + int ab_mask = (ActionableBots::ABM_Target | ActionableBots::ABM_ByName); // this can be expanded without code modification + + std::string pet_arg = sep->arg[1]; + + uint8 pet_type = 255; + uint8 level_req = 255; + if (!pet_arg.compare("water")) { + pet_type = 0; + level_req = 1; + } + else if (!pet_arg.compare("fire")) { + pet_type = 1; + level_req = 3; + } + else if (!pet_arg.compare("air")) { + pet_type = 2; + level_req = 4; + } + else if (!pet_arg.compare("earth")) { + pet_type = 3; + level_req = 5; + } + else if (!pet_arg.compare("monster")) { + pet_type = 4; + level_req = 30; + } + + if (pet_type == 255) { + c->Message(m_fail, "You must specify a pet [type: water | fire | air | earth | monster]"); + return; + } + + std::list sbl; + if (ActionableBots::PopulateSBL(c, sep->arg[2], sbl, ab_mask, sep->arg[3]) == ActionableBots::ABT_None) + return; + + uint16 class_mask = PLAYER_CLASS_MAGICIAN_BIT; + ActionableBots::Filter_ByClasses(c, sbl, class_mask); + if (sbl.empty()) { + c->Message(m_fail, "You have no spawned Magician bots"); + return; + } + + ActionableBots::Filter_ByMinLevel(c, sbl, level_req); + if (sbl.empty()) { + c->Message(m_fail, "You have no spawned Magician bots capable of using this pet type: '%s'", pet_arg.c_str()); + return; + } + + uint16 reclaim_energy_id = 331; + for (auto bot_iter : sbl) { + if (!bot_iter) + continue; + + bot_iter->SetPetChooser(true); + bot_iter->SetPetChooserID(pet_type); + if (bot_iter->GetPet()) { + auto pet_id = bot_iter->GetPetID(); + bot_iter->SetPetID(0); + bot_iter->CastSpell(reclaim_energy_id, pet_id); + } + } +} + +void bot_subcommand_portal(Client *c, const Seperator *sep) +{ + bcst_list* local_list = &bot_command_spells[BCEnum::SpT_Depart]; + if (helper_spell_list_fail(c, local_list, BCEnum::SpT_Depart) || helper_command_alias_fail(c, "bot_subcommand_portal", sep->arg[0], "portal")) + return; + if (helper_is_help_or_usage(sep->arg[1])) { + c->Message(m_usage, "usage: %s [list | destination] ([option: single])", sep->arg[0]); + helper_send_usage_required_bots(c, BCEnum::SpT_Depart, WIZARD); + return; + } + + bool single = false; + std::string single_arg = sep->arg[2]; + if (!single_arg.compare("single")) + single = true; + + std::string destination = sep->arg[1]; + if (!destination.compare("list")) { + auto my_wizard_bot = ActionableBots::AsGroupMember_ByClass(c, c, WIZARD); + helper_command_depart_list(c, nullptr, my_wizard_bot, local_list, single); + return; + } + else if (destination.empty()) { + c->Message(m_fail, "A [destination] or [list] argument is required to use this command"); + return; + } + + ActionableTarget::Types actionable_targets; + Bot* my_bot = nullptr; + std::list sbl; + MyBots::PopulateSBL_BySpawnedBots(c, sbl); + + bool cast_success = false; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToDepart(); + if (helper_spell_check_fail(local_entry)) + continue; + if (local_entry->caster_class != WIZARD) + continue; + if (local_entry->single != single) + continue; + if (destination.compare(spells[local_entry->spell_id].teleport_zone)) + continue; + + auto target_mob = actionable_targets.Select(c, local_entry->target_type, FRIENDLY); + if (!target_mob) + continue; + + my_bot = ActionableBots::Select_ByMinLevelAndClass(c, local_entry->target_type, sbl, local_entry->spell_level, local_entry->caster_class, target_mob); + if (!my_bot) + continue; + + cast_success = helper_cast_standard_spell(my_bot, target_mob, local_entry->spell_id); + break; + } + + helper_no_available_bots(c, my_bot); +} + + +/* + * bot command helpers go below here + */ +bool helper_bot_appearance_fail(Client *bot_owner, Bot *my_bot, BCEnum::AFType fail_type, const char* type_desc) +{ + switch (fail_type) { + case BCEnum::AFT_Value: + bot_owner->Message(m_fail, "Failed to change '%s' for %s due to invalid value for this command", type_desc, my_bot->GetCleanName()); + return true; + case BCEnum::AFT_GenderRace: + bot_owner->Message(m_fail, "Failed to change '%s' for %s due to invalid bot gender and/or race for this command", type_desc, my_bot->GetCleanName()); + return true; + case BCEnum::AFT_Race: + bot_owner->Message(m_fail, "Failed to change '%s' for %s due to invalid bot race for this command", type_desc, my_bot->GetCleanName()); + return true; + default: + return false; + } +} + +void helper_bot_appearance_form_final(Client *bot_owner, Bot *my_bot) +{ + if (!MyBots::IsMyBot(bot_owner, my_bot)) + return; + if (!my_bot->Save()) { + bot_owner->Message(m_unknown, "Failed to save appearance change for %s due to unknown cause...", my_bot->GetCleanName()); + return; + } + + helper_bot_appearance_form_update(my_bot); + bot_owner->Message(m_action, "Successfully changed appearance for %s!", my_bot->GetCleanName()); +} + +void helper_bot_appearance_form_update(Bot *my_bot) +{ + if (!my_bot) + return; + + my_bot->SendIllusionPacket( + my_bot->GetRace(), + my_bot->GetGender(), + 0xFF, //my_bot->GetTexture(), // 0xFF - change back if issues arise + 0xFF, //my_bot->GetHelmTexture(), // 0xFF - change back if issues arise + my_bot->GetHairColor(), + my_bot->GetBeardColor(), + my_bot->GetEyeColor1(), + my_bot->GetEyeColor2(), + my_bot->GetHairStyle(), + my_bot->GetLuclinFace(), + my_bot->GetBeard(), + 0xFF, // aa_title (0xFF) + my_bot->GetDrakkinHeritage(), + my_bot->GetDrakkinTattoo(), + my_bot->GetDrakkinDetails(), + my_bot->GetSize() + ); +} + +uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_class, uint16 bot_race, uint8 bot_gender) +{ + uint32 bot_id = 0; + if (!bot_owner) + return bot_id; + if (!Bot::IsValidName(bot_name)) { + bot_owner->Message(m_fail, "'%s' is an invalid name. You may only use characters 'A-Z', 'a-z' and '_'", bot_name.c_str()); + return bot_id; + } + + bool available_flag = false; + if (!botdb.QueryNameAvailablity(bot_name, available_flag)) { + bot_owner->Message(m_fail, "%s for '%s'", BotDatabase::fail::QueryNameAvailablity(), bot_name.c_str()); + return bot_id; + } + if (!available_flag) { + bot_owner->Message(m_fail, "The name %s is already being used. Please choose a different name", bot_name.c_str()); + return bot_id; + } + + if (!Bot::IsValidRaceClassCombo(bot_race, bot_class)) { + bot_owner->Message(m_fail, "'%s'(%u):'%s'(%u) is an invalid race-class combination", + Bot::RaceIdToString(bot_race).c_str(), bot_race, Bot::ClassIdToString(bot_class).c_str(), bot_class); + return bot_id; + } + + if (bot_gender > FEMALE) { + bot_owner->Message(m_fail, "gender: %u(M), %u(F)", MALE, FEMALE); + return bot_id; + } + + uint32 max_bot_count = RuleI(Bots, CreationLimit); + + uint32 bot_count = 0; + if (!botdb.QueryBotCount(bot_owner->CharacterID(), bot_count)) { + bot_owner->Message(m_fail, "%s", BotDatabase::fail::QueryBotCount()); + return bot_id; + } + if (bot_count >= max_bot_count) { + bot_owner->Message(m_fail, "You have reached the maximum limit of %i bots", max_bot_count); + return bot_id; + } + + auto DefaultNPCTypeStruct = Bot::CreateDefaultNPCTypeStructForBot( + bot_name.c_str(), + "", + bot_owner->GetLevel(), + bot_race, + bot_class, + bot_gender + ); + + auto my_bot = new Bot(DefaultNPCTypeStruct, bot_owner); + + if (!my_bot->Save()) { + bot_owner->Message(m_unknown, "Failed to create '%s' due to unknown cause", my_bot->GetCleanName()); + return bot_id; + } + + bot_owner->Message(m_action, "Successfully created '%s' (id: %u)", my_bot->GetCleanName(), my_bot->GetBotID()); + + bot_id = my_bot->GetBotID(); + safe_delete(my_bot); + + return bot_id; +} + +void helper_bot_out_of_combat(Client *bot_owner, Bot *my_bot) +{ + if (!bot_owner || !my_bot) + return; + + switch (my_bot->GetClass()) { + case WARRIOR: + case CLERIC: + case PALADIN: + case RANGER: + case SHADOWKNIGHT: + case DRUID: + case MONK: + bot_owner->Message(m_unknown, "%s has no out-of-combat behavior defined", my_bot->GetCleanName()); + break; + case BARD: + bot_owner->Message(m_action, "%s will %s use out-of-combat behavior for bard songs", my_bot->GetCleanName(), ((my_bot->GetAltOutOfCombatBehavior()) ? ("now") : ("no longer"))); + break; + case ROGUE: + case SHAMAN: + case NECROMANCER: + case WIZARD: + case MAGICIAN: + case ENCHANTER: + case BEASTLORD: + case BERSERKER: + bot_owner->Message(m_unknown, "%s has no out-of-combat behavior defined", my_bot->GetCleanName()); + break; + default: + break; + bot_owner->Message(m_fail, "Undefined bot class for %s", my_bot->GetCleanName()); + } +} + +bool helper_cast_standard_spell(Bot* casting_bot, Mob* target_mob, int spell_id, bool annouce_cast, uint32* dont_root_before) +{ + if (!casting_bot || !target_mob) + return false; + + casting_bot->InterruptSpell(); + if (annouce_cast) + Bot::BotGroupSay(casting_bot, "Attempting to cast '%s' on %s", spells[spell_id].name, target_mob->GetCleanName()); + + return casting_bot->CastSpell(spell_id, target_mob->GetID(), EQEmu::CastingSlot::Gem2, -1, -1, dont_root_before); +} + +bool helper_command_alias_fail(Client *bot_owner, const char* command_handler, const char *alias, const char *command) +{ + auto alias_iter = bot_command_aliases.find(&alias[1]); + if (alias_iter == bot_command_aliases.end() || alias_iter->second.compare(command)) { + bot_owner->Message(m_fail, "Undefined linker usage in %s (%s)", command_handler, &alias[1]); + return true; + } + + return false; +} + +void helper_command_depart_list(Client* bot_owner, Bot* druid_bot, Bot* wizard_bot, bcst_list* local_list, bool single_flag) +{ + if (!bot_owner) + return; + + if (!MyBots::IsMyBot(bot_owner, druid_bot)) + druid_bot = nullptr; + if (!MyBots::IsMyBot(bot_owner, wizard_bot)) + wizard_bot = nullptr; + if (!druid_bot && !wizard_bot) { + bot_owner->Message(m_fail, "No bots are capable of performing this action"); + return; + } + + bot_owner->Message(m_message, "The following destinations are available:"); + if (!local_list) { + bot_owner->Message(m_fail, "None"); + return; + } + + std::string msg; + std::string text_link; + + int destinations = 0; + for (auto list_iter : *local_list) { + auto local_entry = list_iter->SafeCastToDepart(); + if (!local_entry) + continue; + + if (druid_bot && druid_bot->GetClass() == local_entry->caster_class && druid_bot->GetLevel() >= local_entry->spell_level) { + if (local_entry->single != single_flag) + continue; + msg = StringFormat("%ccircle %s%s", BOT_COMMAND_CHAR, spells[local_entry->spell_id].teleport_zone, ((single_flag) ? (" single") : (""))); + text_link = druid_bot->CreateSayLink(bot_owner, msg.c_str(), local_entry->long_name.c_str()); + Bot::BotGroupSay(druid_bot, "dest: '%s' click: %s", spells[local_entry->spell_id].teleport_zone, text_link.c_str()); + ++destinations; + continue; + } + if (wizard_bot && wizard_bot->GetClass() == local_entry->caster_class && wizard_bot->GetLevel() >= local_entry->spell_level) { + if (local_entry->single != single_flag) + continue; + msg = StringFormat("%cportal %s%s", BOT_COMMAND_CHAR, spells[local_entry->spell_id].teleport_zone, ((single_flag) ? (" single") : (""))); + text_link = wizard_bot->CreateSayLink(bot_owner, msg.c_str(), local_entry->long_name.c_str()); + Bot::BotGroupSay(wizard_bot, "dest: '%s' click: %s", spells[local_entry->spell_id].teleport_zone, text_link.c_str()); + ++destinations; + continue; + } + } + if (!destinations) + bot_owner->Message(m_fail, "None"); +} + +bool helper_is_help_or_usage(const char* arg) +{ + if (!arg) + return false; + if (strcasecmp(arg, "help") && strcasecmp(arg, "usage")) + return false; + + return true; +} + +bool helper_no_available_bots(Client *bot_owner, Bot *my_bot) +{ + if (!bot_owner) + return true; + if (!my_bot) { + bot_owner->Message(m_fail, "No bots are capable of performing this action"); + return true; + } + + return false; +} + +void helper_send_available_subcommands(Client *bot_owner, const char* command_simile, const std::list& subcommand_list) +{ + bot_owner->Message(m_message, "Available %s management subcommands:", command_simile); + + int bot_subcommands_shown = 0; + for (const auto subcommand_iter : subcommand_list) { + auto find_iter = bot_command_list.find(subcommand_iter); + if (find_iter == bot_command_list.end()) + continue; + if (bot_owner->Admin() < find_iter->second->access) + continue; + + bot_owner->Message(m_usage, "%c%s - %s", BOT_COMMAND_CHAR, subcommand_iter, ((find_iter != bot_command_list.end()) ? (find_iter->second->desc) : ("[no description]"))); + ++bot_subcommands_shown; + } + + bot_owner->Message(m_message, "%d bot subcommand%s listed.", bot_subcommands_shown, bot_subcommands_shown != 1 ? "s" : ""); +} + +void helper_send_usage_required_bots(Client *bot_owner, BCEnum::SpType spell_type, uint8 bot_class) +{ + bot_owner->Message(m_note, "requires one of the following bot classes:"); + if (bot_class) + bot_owner->Message(m_message, "%s", required_bots_map_by_class[spell_type][bot_class].c_str()); + else + bot_owner->Message(m_message, "%s", required_bots_map[spell_type].c_str()); +} + +bool helper_spell_check_fail(STBaseEntry* local_entry) +{ + if (!local_entry) + return true; + if (spells[local_entry->spell_id].zonetype && zone->GetZoneType() && !(spells[local_entry->spell_id].zonetype & zone->GetZoneType())) + return true; + + return false; +} + +bool helper_spell_list_fail(Client *bot_owner, bcst_list* spell_list, BCEnum::SpType spell_type) +{ + if (!spell_list || spell_list->empty()) { + bot_owner->Message(m_fail, "%s", required_bots_map[spell_type].c_str()); + return true; + } + + return false; +} + +#endif // BOTS diff --git a/zone/bot_command.h b/zone/bot_command.h new file mode 100644 index 000000000..c25c7b0eb --- /dev/null +++ b/zone/bot_command.h @@ -0,0 +1,676 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef BOT_COMMAND_H +#define BOT_COMMAND_H + +#ifdef BOTS + +class Client; +class Seperator; + +#include "../common/types.h" +#include "bot.h" + + +class BCEnum +{ +public: + typedef enum SpellType { + SpT_None = 0, + SpT_BindAffinity, + SpT_Charm, + SpT_Cure, + SpT_Depart, + SpT_Escape, + SpT_Identify, + SpT_Invisibility, + SpT_Levitation, + SpT_Lull, + SpT_Mesmerize, + SpT_MovementSpeed, + SpT_Resistance, + SpT_Resurrect, + SpT_Rune, + SpT_SendHome, + SpT_Size, + SpT_Stance, + SpT_SummonCorpse, + SpT_WaterBreathing + } SpType; + static const int SpellTypeFirst = SpT_BindAffinity; + static const int SpellTypeLast = SpT_WaterBreathing; + + typedef enum TargetType { + TT_None = 0, + TT_Corpse, + TT_Self, + TT_Animal, + TT_Undead, + TT_Summoned, + TT_Plant, + TT_Single, + TT_GroupV1, + TT_GroupV2, + TT_AECaster, + TT_AEBard, + TT_AETarget + } TType; + static const int TargetTypeFirst = TT_Corpse; + static const int TargetTypeLast = TT_AETarget; + static const int TargetTypeCount = 13; + + typedef enum TargetMask { + TM_None = 0, + TM_Corpse = 1, + TM_Self = 2, + TM_Animal = 4, + TM_Undead = 8, + TM_Summoned = 16, + TM_Plant = 32, + TM_Single = 124, // currently, 2^6 + 2^{2..5}) -or- (64+32+16+8+4) + TM_GroupV1 = 128, + TM_GroupV2 = 256, + TM_AECaster = 512, + TM_AEBard = 1024, + TM_AETarget = 2048 + } TMask; + + typedef enum AppearanceFailType { + AFT_None = 0, + AFT_Value, + AFT_GenderRace, + AFT_Race + } AFType; + + typedef enum AilmentType { + AT_None = 0, + AT_Blindness, // SE: 20 + AT_Disease, // SE: 35 + AT_Poison, // SE: 36 + AT_Curse, // SE: 116 + AT_Corruption // SE: 369 + } AType; + static const int AilmentTypeCount = 5; + + typedef enum InvisibilityType { + IT_None = 0, + IT_Animal, + IT_Undead, + IT_Living, + IT_See + } IType; + + typedef enum ResistanceType { + RT_None = 0, + RT_Fire, // SE: 46 + RT_Cold, // SE: 47 + RT_Poison, // SE: 48 + RT_Disease, // SE: 49 + RT_Magic, // SE: 50 + RT_Corruption // SE: 370 + } RType; + static const int ResistanceTypeCount = 6; + + typedef enum SizeType { + SzT_None = 0, + SzT_Enlarge, + SzT_Reduce + } SzType; + + typedef enum StanceType { + StT_None = 0, + StT_Aggressive, + StT_Defensive + } StType; + + static std::string SpellTypeEnumToString(BCEnum::SpType spell_type) { + switch (spell_type) { + case SpT_BindAffinity: + return "SpT_BindAffinity"; + case SpT_Charm: + return "SpT_Charm"; + case SpT_Cure: + return "SpT_Cure"; + case SpT_Depart: + return "SpT_Depart"; + case SpT_Escape: + return "SpT_Escape"; + case SpT_Identify: + return "SpT_Identify"; + case SpT_Invisibility: + return "SpT_Invisibility"; + case SpT_Levitation: + return "SpT_Levitation"; + case SpT_Lull: + return "SpT_Lull"; + case SpT_Mesmerize: + return "SpT_Mesmerize"; + case SpT_MovementSpeed: + return "SpT_MovementSpeed"; + case SpT_Resistance: + return "SpT_Resistance"; + case SpT_Resurrect: + return "SpT_Resurrect"; + case SpT_Rune: + return "SpT_Rune"; + case SpT_SendHome: + return "SpT_SendHome"; + case SpT_Size: + return "SpT_Size"; + case SpT_Stance: + return "SpT_Stance"; + case SpT_SummonCorpse: + return "SpT_SummonCorpse"; + case SpT_WaterBreathing: + return "SpT_WaterBreathing"; + default: + return "SpT_None"; + } + } + + static std::string TargetTypeEnumToString(BCEnum::TType target_type) { + switch (target_type) { + case TT_Self: + return "TT_Self"; + case TT_Animal: + return "TT_Animal"; + case TT_Undead: + return "TT_Undead"; + case TT_Summoned: + return "TT_Summoned"; + case TT_Plant: + return "TT_Plant"; + case TT_Single: + return "TT_Single"; + case TT_GroupV1: + return "TT_GroupV1"; + case TT_GroupV2: + return "TT_GroupV2"; + case TT_AECaster: + return "TT_AECaster"; + case TT_AEBard: + return "TT_AEBard"; + case TT_AETarget: + return "TT_AETarget"; + case TT_Corpse: + return "TT_Corpse"; + default: + return "TT_None"; + } + } +}; + + +class STBaseEntry; +class STCharmEntry; +class STCureEntry; +class STDepartEntry; +class STEscapeEntry; +class STInvisibilityEntry; +class STMovementSpeedEntry; +class STResistanceEntry; +class STResurrectEntry; +class STSendHomeEntry; +class STSizeEntry; +class STStanceEntry; + +class STBaseEntry +{ +protected: + BCEnum::SpType m_bcst; + +public: + int spell_id; + uint8 spell_level; + uint8 caster_class; + BCEnum::TType target_type; + + // A non-polymorphic constructor requires an appropriate, non-'ST_None' BCEnum::SType + STBaseEntry(BCEnum::SpType init_bcst = BCEnum::SpT_None) { + spell_id = 0; + spell_level = 255; + caster_class = 255; + target_type = BCEnum::TT_None; + m_bcst = init_bcst; + } + STBaseEntry(STBaseEntry* prototype) { + spell_id = prototype->spell_id; + spell_level = 255; + caster_class = 255; + target_type = prototype->target_type; + m_bcst = prototype->BCST(); + } + virtual ~STBaseEntry() { return; }; + + BCEnum::SpType BCST() { return m_bcst; } + + virtual bool IsDerived() { return false; } + + bool IsCharm() const { return (m_bcst == BCEnum::SpT_Charm); } + bool IsCure() const { return (m_bcst == BCEnum::SpT_Cure); } + bool IsDepart() const { return (m_bcst == BCEnum::SpT_Depart); } + bool IsEscape() const { return (m_bcst == BCEnum::SpT_Escape); } + bool IsInvisibility() const { return (m_bcst == BCEnum::SpT_Invisibility); } + bool IsMovementSpeed() const { return (m_bcst == BCEnum::SpT_MovementSpeed); } + bool IsResistance() const { return (m_bcst == BCEnum::SpT_Resistance); } + bool IsResurrect() const { return (m_bcst == BCEnum::SpT_Resurrect); } + bool IsSendHome() const { return (m_bcst == BCEnum::SpT_SendHome); } + bool IsSize() const { return (m_bcst == BCEnum::SpT_Size); } + bool IsStance() const { return (m_bcst == BCEnum::SpT_Stance); } + + virtual STCharmEntry* SafeCastToCharm() { return nullptr; } + virtual STCureEntry* SafeCastToCure() { return nullptr; } + virtual STDepartEntry* SafeCastToDepart() { return nullptr; } + virtual STEscapeEntry* SafeCastToEscape() { return nullptr; } + virtual STInvisibilityEntry* SafeCastToInvisibility() { return nullptr; } + virtual STMovementSpeedEntry* SafeCastToMovementSpeed() { return nullptr; } + virtual STResistanceEntry* SafeCastToResistance() { return nullptr; } + virtual STResurrectEntry* SafeCastToResurrect() { return nullptr; } + virtual STSendHomeEntry* SafeCastToSendHome() { return nullptr; } + virtual STSizeEntry* SafeCastToSize() { return nullptr; } + virtual STStanceEntry* SafeCastToStance() { return nullptr; } +}; + +class STCharmEntry : public STBaseEntry +{ +public: + bool dire; + + STCharmEntry() { + m_bcst = BCEnum::SpT_Charm; + dire = false; + } + STCharmEntry(STCharmEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_Charm; + dire = prototype->dire; + } + virtual ~STCharmEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STCharmEntry* SafeCastToCharm() { return ((m_bcst == BCEnum::SpT_Charm) ? (static_cast(this)) : (nullptr)); } +}; + +class STCureEntry : public STBaseEntry +{ +public: + int cure_value[BCEnum::AilmentTypeCount]; + int cure_total; + + STCureEntry() { + m_bcst = BCEnum::SpT_Cure; + memset(&cure_value, 0, (sizeof(int) * BCEnum::AilmentTypeCount)); + cure_total = 0; + } + STCureEntry(STCureEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_Cure; + memcpy(&cure_value, prototype->cure_value, (sizeof(int) * BCEnum::AilmentTypeCount)); + cure_total = prototype->cure_total; + } + virtual ~STCureEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STCureEntry* SafeCastToCure() { return ((m_bcst == BCEnum::SpT_Cure) ? (static_cast(this)) : (nullptr)); } +}; + +class STDepartEntry : public STBaseEntry +{ +public: + bool single; + std::string long_name; + + STDepartEntry() { + m_bcst = BCEnum::SpT_Depart; + single = false; + long_name.clear(); + } + STDepartEntry(STDepartEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_Depart; + single = prototype->single; + long_name = prototype->long_name; + } + virtual ~STDepartEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STDepartEntry* SafeCastToDepart() { return ((m_bcst == BCEnum::SpT_Depart) ? (static_cast(this)) : (nullptr)); } +}; + +class STEscapeEntry : public STBaseEntry +{ +public: + bool lesser; + + STEscapeEntry() { + m_bcst = BCEnum::SpT_Escape; + lesser = false; + } + STEscapeEntry(STEscapeEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_Escape; + lesser = prototype->lesser; + } + virtual ~STEscapeEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STEscapeEntry* SafeCastToEscape() { return ((m_bcst == BCEnum::SpT_Escape) ? (static_cast(this)) : (nullptr)); } +}; + +class STInvisibilityEntry : public STBaseEntry +{ +public: + BCEnum::IType invis_type; + + STInvisibilityEntry() { + m_bcst = BCEnum::SpT_Invisibility; + invis_type = BCEnum::IT_None; + } + STInvisibilityEntry(STInvisibilityEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_Invisibility; + invis_type = prototype->invis_type; + } + virtual ~STInvisibilityEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STInvisibilityEntry* SafeCastToInvisibility() { return ((m_bcst == BCEnum::SpT_Invisibility) ? (static_cast(this)) : (nullptr)); } +}; + +class STMovementSpeedEntry : public STBaseEntry +{ +public: + bool group; + + STMovementSpeedEntry() { + m_bcst = BCEnum::SpT_MovementSpeed; + group = false; + } + STMovementSpeedEntry(STMovementSpeedEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_MovementSpeed; + group = prototype->group; + } + virtual ~STMovementSpeedEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STMovementSpeedEntry* SafeCastToMovementSpeed() { return ((m_bcst == BCEnum::SpT_MovementSpeed) ? (static_cast(this)) : (nullptr)); } +}; + +class STResistanceEntry : public STBaseEntry +{ +public: + int resist_value[BCEnum::ResistanceTypeCount]; + int resist_total; + + STResistanceEntry() { + m_bcst = BCEnum::SpT_Resistance; + memset(&resist_value, 0, (sizeof(int) * BCEnum::ResistanceTypeCount)); + resist_total = 0; + } + STResistanceEntry(STResistanceEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_Resistance; + memcpy(&resist_value, prototype->resist_value, (sizeof(int) * BCEnum::ResistanceTypeCount)); + resist_total = prototype->resist_total; + } + virtual ~STResistanceEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STResistanceEntry* SafeCastToResistance() { return ((m_bcst == BCEnum::SpT_Resistance) ? (static_cast(this)) : (nullptr)); } +}; + +class STResurrectEntry : public STBaseEntry +{ +public: + bool aoe; + + STResurrectEntry() { + m_bcst = BCEnum::SpT_Resurrect; + aoe = false; + } + STResurrectEntry(STResurrectEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_Resurrect; + aoe = prototype->aoe; + } + virtual ~STResurrectEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STResurrectEntry* SafeCastToResurrect() { return ((m_bcst == BCEnum::SpT_Resurrect) ? (static_cast(this)) : (nullptr)); } +}; + +class STSendHomeEntry : public STBaseEntry +{ +public: + bool group; + + STSendHomeEntry() { + m_bcst = BCEnum::SpT_SendHome; + group = false; + } + STSendHomeEntry(STSendHomeEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_SendHome; + group = prototype->group; + } + virtual ~STSendHomeEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STSendHomeEntry* SafeCastToSendHome() { return ((m_bcst == BCEnum::SpT_SendHome) ? (static_cast(this)) : (nullptr)); } +}; + +class STSizeEntry : public STBaseEntry +{ +public: + BCEnum::SzType size_type; + + STSizeEntry() { + m_bcst = BCEnum::SpT_Size; + size_type = BCEnum::SzT_None; + } + STSizeEntry(STSizeEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_Size; + size_type = prototype->size_type; + } + virtual ~STSizeEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STSizeEntry* SafeCastToSize() { return ((m_bcst == BCEnum::SpT_Size) ? (static_cast(this)) : (nullptr)); } +}; + +class STStanceEntry : public STBaseEntry { +public: + BCEnum::StType stance_type; + + STStanceEntry() { + m_bcst = BCEnum::SpT_Stance; + stance_type = BCEnum::StT_None; + } + STStanceEntry(STStanceEntry* prototype) : STBaseEntry(prototype) { + m_bcst = BCEnum::SpT_Stance; + stance_type = prototype->stance_type; + } + virtual ~STStanceEntry() { return; }; + + virtual bool IsDerived() { return true; } + + virtual STStanceEntry* SafeCastToStance() { return ((m_bcst == BCEnum::SpT_Stance) ? (static_cast(this)) : (nullptr)); } +}; + + +typedef std::list bcst_list; +typedef std::map bcst_map; + +typedef std::map bcst_required_bot_classes_map; +typedef std::map> bcst_required_bot_classes_map_by_class; + +typedef std::map bcst_levels; +typedef std::map bcst_levels_map; + + +#define BOT_COMMAND_CHAR '^' + +typedef void (*BotCmdFuncPtr)(Client *,const Seperator *); + +typedef struct { + int access; + const char *desc; // description of bot command + BotCmdFuncPtr function; // null means perl function +} BotCommandRecord; + +extern int (*bot_command_dispatch)(Client *,char const*); +extern int bot_command_count; // number of bot commands loaded + + +// the bot command system: +int bot_command_init(void); +void bot_command_deinit(void); +int bot_command_add(std::string bot_command_name, const char *desc, int access, BotCmdFuncPtr function); +int bot_command_not_avail(Client *c, const char *message); +int bot_command_real_dispatch(Client *c, char const *message); +void bot_command_log_command(Client *c, const char *message); + + +// bot commands +void bot_command_actionable(Client *c, const Seperator *sep); +void bot_command_aggressive(Client *c, const Seperator *sep); +void bot_command_attack(Client *c, const Seperator *sep); +void bot_command_bind_affinity(Client *c, const Seperator *sep); +void bot_command_bot(Client *c, const Seperator *sep); +void bot_command_botgroup(Client *c, const Seperator *sep); +void bot_command_charm(Client *c, const Seperator *sep); +void bot_command_cure(Client *c, const Seperator *sep); +void bot_command_defensive(Client *c, const Seperator *sep); +void bot_command_depart(Client *c, const Seperator *sep); +void bot_command_escape(Client *c, const Seperator *sep); +void bot_command_find_aliases(Client *c, const Seperator *sep); +void bot_command_follow(Client *c, const Seperator *sep); +void bot_command_guard(Client *c, const Seperator *sep); +void bot_command_heal_rotation(Client *c, const Seperator *sep); +void bot_command_help(Client *c, const Seperator *sep); +void bot_command_hold(Client *c, const Seperator *sep); +void bot_command_identify(Client *c, const Seperator *sep); +void bot_command_inventory(Client *c, const Seperator *sep); +void bot_command_invisibility(Client *c, const Seperator *sep); +void bot_command_levitation(Client *c, const Seperator *sep); +void bot_command_lull(Client *c, const Seperator *sep); +void bot_command_mesmerize(Client *c, const Seperator *sep); +void bot_command_movement_speed(Client *c, const Seperator *sep); +void bot_command_pet(Client *c, const Seperator *sep); +void bot_command_pick_lock(Client *c, const Seperator *sep); +void bot_command_pull(Client *c, const Seperator *sep); +void bot_command_release(Client *c, const Seperator *sep); +void bot_command_resistance(Client *c, const Seperator *sep); +void bot_command_resurrect(Client *c, const Seperator *sep); +void bot_command_rune(Client *c, const Seperator *sep); +void bot_command_send_home(Client *c, const Seperator *sep); +void bot_command_size(Client *c, const Seperator *sep); +void bot_command_summon_corpse(Client *c, const Seperator *sep); +void bot_command_taunt(Client *c, const Seperator *sep); +void bot_command_track(Client *c, const Seperator *sep); +void bot_command_water_breathing(Client *c, const Seperator *sep); + + +// bot subcommands +void bot_subcommand_bot_appearance(Client *c, const Seperator *sep); +void bot_subcommand_bot_beard_color(Client *c, const Seperator *sep); +void bot_subcommand_bot_beard_style(Client *c, const Seperator *sep); +void bot_subcommand_bot_camp(Client *c, const Seperator *sep); +void bot_subcommand_bot_clone(Client *c, const Seperator *sep); +void bot_subcommand_bot_create(Client *c, const Seperator *sep); +void bot_subcommand_bot_delete(Client *c, const Seperator *sep); +void bot_subcommand_bot_details(Client *c, const Seperator *sep); +void bot_subcommand_bot_dye_armor(Client *c, const Seperator *sep); +void bot_subcommand_bot_eyes(Client *c, const Seperator *sep); +void bot_subcommand_bot_face(Client *c, const Seperator *sep); +void bot_subcommand_bot_follow_distance(Client *c, const Seperator *sep); +void bot_subcommand_bot_hair_color(Client *c, const Seperator *sep); +void bot_subcommand_bot_hairstyle(Client *c, const Seperator *sep); +void bot_subcommand_bot_heritage(Client *c, const Seperator *sep); +void bot_subcommand_bot_inspect_message(Client *c, const Seperator *sep); +void bot_subcommand_bot_list(Client *c, const Seperator *sep); +void bot_subcommand_bot_out_of_combat(Client *c, const Seperator *sep); +void bot_subcommand_bot_report(Client *c, const Seperator *sep); +void bot_subcommand_bot_spawn(Client *c, const Seperator *sep); +void bot_subcommand_bot_stance(Client *c, const Seperator *sep); +void bot_subcommand_bot_summon(Client *c, const Seperator *sep); +void bot_subcommand_bot_tattoo(Client *c, const Seperator *sep); +void bot_subcommand_bot_toggle_archer(Client *c, const Seperator *sep); +void bot_subcommand_bot_toggle_helm(Client *c, const Seperator *sep); +void bot_subcommand_bot_update(Client *c, const Seperator *sep); +void bot_subcommand_bot_woad(Client *c, const Seperator *sep); +void bot_subcommand_botgroup_add_member(Client *c, const Seperator *sep); +void bot_subcommand_botgroup_create(Client *c, const Seperator *sep); +void bot_subcommand_botgroup_delete(Client *c, const Seperator *sep); +void bot_subcommand_botgroup_list(Client *c, const Seperator *sep); +void bot_subcommand_botgroup_load(Client *c, const Seperator *sep); +void bot_subcommand_botgroup_remove_member(Client *c, const Seperator *sep); +void bot_subcommand_circle(Client *c, const Seperator *sep); +void bot_subcommand_evacuate(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_adaptive_targeting(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_add_member(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_add_target(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_adjust_critical(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_adjust_safe(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_casting_override(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_change_interval(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_clear_hot(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_clear_targets(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_create(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_delete(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_fast_heals(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_list(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_remove_member(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_remove_target(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_reset_limits(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_save(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_set_hot(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_start(Client *c, const Seperator *sep); +void bot_subcommand_heal_rotation_stop(Client *c, const Seperator *sep); +void bot_subcommand_inventory_give(Client *c, const Seperator *sep); +void bot_subcommand_inventory_list(Client *c, const Seperator *sep); +void bot_subcommand_inventory_remove(Client *c, const Seperator *sep); +void bot_subcommand_inventory_window(Client *c, const Seperator *sep); +void bot_subcommand_pet_remove(Client *c, const Seperator *sep); +void bot_subcommand_pet_set_type(Client *c, const Seperator *sep); +void bot_subcommand_portal(Client *c, const Seperator *sep); +void bot_subcommand_succor(Client *c, const Seperator *sep); + + +// bot command helpers +bool helper_bot_appearance_fail(Client *bot_owner, Bot *my_bot, BCEnum::AFType fail_type, const char* type_desc); +void helper_bot_appearance_form_final(Client *bot_owner, Bot *my_bot); +void helper_bot_appearance_form_update(Bot *my_bot); +uint32 helper_bot_create(Client *bot_owner, std::string bot_name, uint8 bot_class, uint16 bot_race, uint8 bot_gender); +void helper_bot_out_of_combat(Client *bot_owner, Bot *my_bot); +bool helper_cast_standard_spell(Bot* casting_bot, Mob* target_mob, int spell_id, bool annouce_cast = true, uint32* dont_root_before = nullptr); +bool helper_command_alias_fail(Client *bot_owner, const char* command_handler, const char *alias, const char *command); +void helper_command_depart_list(Client* bot_owner, Bot* druid_bot, Bot* wizard_bot, bcst_list* local_list, bool single_flag = false); +bool helper_is_help_or_usage(const char* arg); +bool helper_no_available_bots(Client *bot_owner, Bot *my_bot = nullptr); +void helper_send_available_subcommands(Client *bot_owner, const char* command_simile, const std::list& subcommand_list); +void helper_send_usage_required_bots(Client *bot_owner, BCEnum::SpType spell_type, uint8 bot_class = 0); +bool helper_spell_check_fail(STBaseEntry* local_entry); +bool helper_spell_list_fail(Client *bot_owner, bcst_list* spell_list, BCEnum::SpType spell_type); +#endif + +#endif // BOTS diff --git a/zone/bot_database.cpp b/zone/bot_database.cpp new file mode 100644 index 000000000..db9827a8a --- /dev/null +++ b/zone/bot_database.cpp @@ -0,0 +1,2810 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef BOTS + +#include "../common/global_define.h" +#include "../common/rulesys.h" +#include "../common/string_util.h" +#include "../common/eqemu_logsys.h" + +#include "bot_database.h" +#include "bot.h" + + +BotDatabase botdb; + + +BotDatabase::BotDatabase() +{ + +} + +BotDatabase::BotDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port) +{ + Connect(host, user, passwd, database, port); +} + +BotDatabase::~BotDatabase() +{ + +} + +bool BotDatabase::Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port) { + uint32 errnum = 0; + char errbuf[MYSQL_ERRMSG_SIZE]; + if (!Open(host, user, passwd, database, port, &errnum, errbuf)) { + Log.Out(Logs::General, Logs::Error, "Failed to connect to bot database: Error: %s", errbuf); + return false; + } + else { + Log.Out(Logs::General, Logs::Status, "Using bot database '%s' at %s:%d", database, host, port); + return true; + } +} + +bool BotDatabase::LoadBotCommandSettings(std::map>> &bot_command_settings) +{ + bot_command_settings.clear(); + + query = "SELECT `bot_command`, `access`, `aliases` FROM `bot_command_settings`"; + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + for (auto row = results.begin(); row != results.end(); ++row) { + bot_command_settings[row[0]].first = atoi(row[1]); + if (row[2][0] == 0) + continue; + + auto aliases = SplitString(row[2], '|'); + for (auto iter : aliases) { + if (!iter.empty()) + bot_command_settings[row[0]].second.push_back(iter); + } + } + + return true; +} + + +/* Bot functions */ +bool BotDatabase::QueryNameAvailablity(const std::string& bot_name, bool& available_flag) +{ + if (bot_name.empty() || bot_name.size() > 60 || !database.CheckUsedName(bot_name.c_str())) + return false; + + query = StringFormat("SELECT `id` FROM `vw_bot_character_mobs` WHERE `name` LIKE '%s' LIMIT 1", bot_name.c_str()); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (results.RowCount()) + return true; + + available_flag = true; + + return true; +} + +bool BotDatabase::QueryBotCount(const uint32 owner_id, uint32& bot_count) +{ + if (!owner_id) + return false; + + query = StringFormat("SELECT COUNT(`bot_id`) FROM `bot_data` WHERE `owner_id` = '%i'", owner_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + bot_count = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadQuestableSpawnCount(const uint32 owner_id, int& spawn_count) +{ + if (!owner_id) + return false; + + query = StringFormat("SELECT `value` FROM `quest_globals` WHERE `name` = 'bot_spawn_limit' AND `charid` = '%i' LIMIT 1", owner_id); + auto results = database.QueryDatabase(query); // use 'database' for non-bot table calls + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + spawn_count = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadBotsList(const uint32 owner_id, std::list& bots_list) +{ + if (!owner_id) + return false; + + query = StringFormat("SELECT `bot_id`, `name`, `class`, `level`, `race`, `gender` FROM `bot_data` WHERE `owner_id` = '%u'", owner_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + for (auto row = results.begin(); row != results.end(); ++row) { + BotsAvailableList bot_entry; + + bot_entry.ID = atoi(row[0]); + + memset(&bot_entry.Name, 0, sizeof(bot_entry.Name)); + std::string bot_name = row[1]; + if (bot_name.size() > 63) + bot_name = bot_name.substr(0, 63); + if (!bot_name.empty()) + strcpy(bot_entry.Name, bot_name.c_str()); + + bot_entry.Class = atoi(row[2]); + bot_entry.Level = atoi(row[3]); + bot_entry.Race = atoi(row[4]); + bot_entry.Gender = atoi(row[5]); + + bots_list.push_back(bot_entry); + } + + return true; +} + +bool BotDatabase::LoadOwnerID(const std::string& bot_name, uint32& owner_id) +{ + if (bot_name.empty()) + return false; + + query = StringFormat("SELECT `owner_id` FROM `bot_data` WHERE `name` = '%s' LIMIT 1", bot_name.c_str()); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + owner_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadOwnerID(const uint32 bot_id, uint32& owner_id) +{ + if (!bot_id) + return false; + + query = StringFormat("SELECT `owner_id` FROM `bot_data` WHERE `bot_id` = '%u' LIMIT 1", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + owner_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadBotID(const uint32 owner_id, const std::string& bot_name, uint32& bot_id) +{ + 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()); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + bot_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadBot(const uint32 bot_id, Bot*& loaded_bot) +{ + if (!bot_id || loaded_bot) + return false; + + query = StringFormat( + "SELECT" + " `owner_id`," + " `spells_id`," + " `name`," + " `last_name`," + " `title`," /* planned use[4] */ + " `suffix`," /* planned use[5] */ + " `zone_id`," + " `gender`," + " `race`," + " `class`," + " `level`," + " `deity`," /* planned use[11] */ + " `creation_day`," /* not in-use[12] */ + " `last_spawn`," /* not in-use[13] */ + " `time_spawned`," + " `size`," + " `face`," + " `hair_color`," + " `hair_style`," + " `beard`," + " `beard_color`," + " `eye_color_1`," + " `eye_color_2`," + " `drakkin_heritage`," + " `drakkin_tattoo`," + " `drakkin_details`," + " `ac`," /* not in-use[26] */ + " `atk`," /* not in-use[27] */ + " `hp`," + " `mana`," + " `str`," /* not in-use[30] */ + " `sta`," /* not in-use[31] */ + " `cha`," /* not in-use[32] */ + " `dex`," /* not in-use[33] */ + " `int`," /* not in-use[34] */ + " `agi`," /* not in-use[35] */ + " `wis`," /* not in-use[36] */ + " `fire`," /* not in-use[37] */ + " `cold`," /* not in-use[38] */ + " `magic`," /* not in-use[39] */ + " `poison`," /* not in-use[40] */ + " `disease`," /* not in-use[41] */ + " `corruption`," /* not in-use[42] */ + " `show_helm`," // 43 + " `follow_distance`" // 44 + " FROM `bot_data`" + " WHERE `bot_id` = '%u'" + " LIMIT 1", + bot_id + ); + + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + // TODO: Consider removing resists and basic attributes from the load query above since we're using defaultNPCType values instead + auto row = results.begin(); + NPCType defaultNPCTypeStruct = Bot::CreateDefaultNPCTypeStructForBot(std::string(row[2]), std::string(row[3]), atoi(row[10]), atoi(row[8]), atoi(row[9]), atoi(row[7])); + NPCType tempNPCStruct = Bot::FillNPCTypeStruct( + atoi(row[1]), + std::string(row[2]), + std::string(row[3]), + atoi(row[10]), + atoi(row[8]), + atoi(row[9]), + atoi(row[7]), + atof(row[15]), + atoi(row[16]), + atoi(row[18]), + atoi(row[17]), + atoi(row[21]), + atoi(row[22]), + atoi(row[20]), + atoi(row[19]), + atoi(row[23]), + atoi(row[24]), + atoi(row[25]), + atoi(row[28]), + atoi(row[29]), + defaultNPCTypeStruct.MR, + defaultNPCTypeStruct.CR, + defaultNPCTypeStruct.DR, + defaultNPCTypeStruct.FR, + defaultNPCTypeStruct.PR, + defaultNPCTypeStruct.Corrup, + defaultNPCTypeStruct.AC, + defaultNPCTypeStruct.STR, + defaultNPCTypeStruct.STA, + defaultNPCTypeStruct.DEX, + defaultNPCTypeStruct.AGI, + defaultNPCTypeStruct.INT, + defaultNPCTypeStruct.WIS, + defaultNPCTypeStruct.CHA, + defaultNPCTypeStruct.ATK + ); + + loaded_bot = new Bot(bot_id, atoi(row[0]), atoi(row[1]), atof(row[14]), atoi(row[6]), tempNPCStruct); + if (loaded_bot) { + loaded_bot->SetShowHelm((atoi(row[43]) > 0 ? true : false)); + loaded_bot->SetFollowDistance(atoi(row[44])); + } + + return true; +} + +bool BotDatabase::SaveNewBot(Bot* bot_inst, uint32& bot_id) +{ + if (!bot_inst) + return false; + + query = StringFormat( + "INSERT INTO `bot_data` (" + " `owner_id`," + " `spells_id`," + " `name`," + " `last_name`," + " `zone_id`," + " `gender`," + " `race`," + " `class`," + " `level`," + " `creation_day`," + " `last_spawn`," + " `time_spawned`," + " `size`," + " `face`," + " `hair_color`," + " `hair_style`," + " `beard`," + " `beard_color`," + " `eye_color_1`," + " `eye_color_2`," + " `drakkin_heritage`," + " `drakkin_tattoo`," + " `drakkin_details`," + " `ac`," + " `atk`," + " `hp`," + " `mana`," + " `str`," + " `sta`," + " `cha`," + " `dex`," + " `int`," + " `agi`," + " `wis`," + " `fire`," + " `cold`," + " `magic`," + " `poison`," + " `disease`," + " `corruption`," + " `show_helm`," + " `follow_distance`" + ")" + " VALUES (" + "'%u'," /* owner_id */ + " '%u'," /* spells_id */ + " '%s'," /* name */ + " '%s'," /* last_name */ + " '%i'," /* zone_id */ + " '%i'," /* gender */ + " '%i'," /* race */ + " '%i'," /* class */ + " '%u'," /* level */ + " UNIX_TIMESTAMP()," /* creation_day */ + " UNIX_TIMESTAMP()," /* last_spawn */ + " 0," /* time_spawned */ + " '%f'," /* size */ + " '%i'," /* face */ + " '%i'," /* hair_color */ + " '%i'," /* hair_style */ + " '%i'," /* beard */ + " '%i'," /* beard_color */ + " '%i'," /* eye_color_1 */ + " '%i'," /* eye_color_2 */ + " '%i'," /* drakkin_heritage */ + " '%i'," /* drakkin_tattoo */ + " '%i'," /* drakkin_details */ + " '%i'," /* ac */ + " '%i'," /* atk */ + " '%i'," /* hp */ + " '%i'," /* mana */ + " '%i'," /* str */ + " '%i'," /* sta */ + " '%i'," /* cha */ + " '%i'," /* dex */ + " '%i'," /* int */ + " '%i'," /* agi */ + " '%i'," /* wis */ + " '%i'," /* fire */ + " '%i'," /* cold */ + " '%i'," /* magic */ + " '%i'," /* poison */ + " '%i'," /* disease */ + " '%i'," /* corruption */ + " '1'," /* show_helm */ + " '%i'" /* follow_distance */ + ")", + bot_inst->GetBotOwnerCharacterID(), + bot_inst->GetBotSpellID(), + bot_inst->GetCleanName(), + bot_inst->GetLastName(), + bot_inst->GetLastZoneID(), + bot_inst->GetGender(), + bot_inst->GetRace(), + bot_inst->GetClass(), + bot_inst->GetLevel(), + bot_inst->GetSize(), + bot_inst->GetLuclinFace(), + bot_inst->GetHairColor(), + bot_inst->GetHairStyle(), + bot_inst->GetBeard(), + bot_inst->GetBeardColor(), + bot_inst->GetEyeColor1(), + bot_inst->GetEyeColor2(), + bot_inst->GetDrakkinHeritage(), + bot_inst->GetDrakkinTattoo(), + bot_inst->GetDrakkinDetails(), + bot_inst->GetAC(), + bot_inst->GetATK(), + bot_inst->GetHP(), + bot_inst->GetMana(), + bot_inst->GetSTR(), + bot_inst->GetSTA(), + bot_inst->GetCHA(), + bot_inst->GetDEX(), + bot_inst->GetINT(), + bot_inst->GetAGI(), + bot_inst->GetWIS(), + bot_inst->GetFR(), + bot_inst->GetCR(), + bot_inst->GetMR(), + bot_inst->GetPR(), + bot_inst->GetDR(), + bot_inst->GetCorrup(), + BOT_DEFAULT_FOLLOW_DISTANCE + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + bot_id = results.LastInsertedID(); + + return true; +} + +bool BotDatabase::SaveBot(Bot* bot_inst) +{ + if (!bot_inst) + return false; + + query = StringFormat( + "UPDATE `bot_data`" + " SET" + " `owner_id` = '%u'," + " `spells_id` = '%u'," + " `name` = '%s'," + " `last_name` = '%s'," + " `zone_id` = '%i'," + " `gender` = '%i'," + " `race` = '%i'," + " `class` = '%i'," + " `level` = '%u'," + " `last_spawn` = UNIX_TIMESTAMP()," + " `time_spawned` = '%u'," + " `size` = '%f'," + " `face` = '%i'," + " `hair_color` = '%i'," + " `hair_style` = '%i'," + " `beard` = '%i'," + " `beard_color` = '%i'," + " `eye_color_1` = '%i'," + " `eye_color_2` = '%i'," + " `drakkin_heritage` = '%i'," + " `drakkin_tattoo` = '%i'," + " `drakkin_details` = '%i'," + " `ac` = '%i'," + " `atk` = '%i'," + " `hp` = '%i'," + " `mana` = '%i'," + " `str` = '%i'," + " `sta` = '%i'," + " `cha` = '%i'," + " `dex` = '%i'," + " `int` = '%i'," + " `agi` = '%i'," + " `wis` = '%i'," + " `fire` = '%i'," + " `cold` = '%i'," + " `magic` = '%i'," + " `poison` = '%i'," + " `disease` = '%i'," + " `corruption` = '%i'," + " `show_helm` = '%i'," + " `follow_distance` = '%i'" + " WHERE `bot_id` = '%u'", + bot_inst->GetBotOwnerCharacterID(), + bot_inst->GetBotSpellID(), + bot_inst->GetCleanName(), + bot_inst->GetLastName(), + bot_inst->GetLastZoneID(), + bot_inst->GetBaseGender(), + bot_inst->GetBaseRace(), + bot_inst->GetClass(), + bot_inst->GetLevel(), + bot_inst->GetTotalPlayTime(), + bot_inst->GetBaseSize(), + bot_inst->GetLuclinFace(), + bot_inst->GetHairColor(), + bot_inst->GetHairStyle(), + bot_inst->GetBeard(), + bot_inst->GetBeardColor(), + bot_inst->GetEyeColor1(), + bot_inst->GetEyeColor2(), + bot_inst->GetDrakkinHeritage(), + bot_inst->GetDrakkinTattoo(), + bot_inst->GetDrakkinDetails(), + bot_inst->GetBaseAC(), + bot_inst->GetBaseATK(), + bot_inst->GetHP(), + bot_inst->GetMana(), + bot_inst->GetBaseSTR(), + bot_inst->GetBaseSTA(), + bot_inst->GetBaseCHA(), + bot_inst->GetBaseDEX(), + bot_inst->GetBaseINT(), + bot_inst->GetBaseAGI(), + bot_inst->GetBaseWIS(), + bot_inst->GetBaseFR(), + bot_inst->GetBaseCR(), + bot_inst->GetBaseMR(), + bot_inst->GetBasePR(), + bot_inst->GetBaseDR(), + bot_inst->GetBaseCorrup(), + ((bot_inst->GetShowHelm()) ? (1) : (0)), + bot_inst->GetFollowDistance(), + bot_inst->GetBotID() + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::DeleteBot(const uint32 bot_id) +{ + if (!bot_id) + return false; + + query = StringFormat("DELETE FROM `bot_data` WHERE `bot_id` = '%u'", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::LoadBuffs(Bot* bot_inst) +{ + if (!bot_inst) + return false; + + query = StringFormat( + "SELECT" + " `spell_id`," + " `caster_level`," + " `duration_formula`," + " `tics_remaining`," + " `poison_counters`," + " `disease_counters`," + " `curse_counters`," + " `corruption_counters`," + " `numhits`," + " `melee_rune`," + " `magic_rune`," + " `dot_rune`," + " `persistent`," + " `caston_x`," + " `caston_y`," + " `caston_z`," + " `extra_di_chance`" + " FROM `bot_buffs`" + " WHERE `bot_id` = '%u'", + bot_inst->GetBotID() + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + Buffs_Struct* bot_buffs = bot_inst->GetBuffs(); + if (!bot_buffs) + return false; + + int buff_count = 0; + for (auto row = results.begin(); row != results.end() && buff_count < BUFF_COUNT; ++row) { + bot_buffs[buff_count].spellid = atoi(row[0]); + bot_buffs[buff_count].casterlevel = atoi(row[1]); + //row[2] (duration_formula) can probably be removed + bot_buffs[buff_count].ticsremaining = atoi(row[3]); + + if (CalculatePoisonCounters(bot_buffs[buff_count].spellid) > 0) + bot_buffs[buff_count].counters = atoi(row[4]); + else if (CalculateDiseaseCounters(bot_buffs[buff_count].spellid) > 0) + bot_buffs[buff_count].counters = atoi(row[5]); + else if (CalculateCurseCounters(bot_buffs[buff_count].spellid) > 0) + bot_buffs[buff_count].counters = atoi(row[6]); + else if (CalculateCorruptionCounters(bot_buffs[buff_count].spellid) > 0) + bot_buffs[buff_count].counters = atoi(row[7]); + + bot_buffs[buff_count].numhits = atoi(row[8]); + bot_buffs[buff_count].melee_rune = atoi(row[9]); + bot_buffs[buff_count].magic_rune = atoi(row[10]); + bot_buffs[buff_count].dot_rune = atoi(row[11]); + bot_buffs[buff_count].persistant_buff = ((atoi(row[12])) ? (true) : (false)); + bot_buffs[buff_count].caston_x = atoi(row[13]); + bot_buffs[buff_count].caston_y = atoi(row[14]); + bot_buffs[buff_count].caston_z = atoi(row[15]); + bot_buffs[buff_count].ExtraDIChance = atoi(row[16]); + bot_buffs[buff_count].casterid = 0; + ++buff_count; + } + + return true; +} + +bool BotDatabase::SaveBuffs(Bot* bot_inst) +{ + if (!bot_inst) + return false; + + if (!DeleteBuffs(bot_inst->GetBotID())) + return false; + + Buffs_Struct* bot_buffs = bot_inst->GetBuffs(); + if (!bot_buffs) + return false; + + for (int buff_index = 0; buff_index < BUFF_COUNT; ++buff_index) { + if (bot_buffs[buff_index].spellid <= 0 || bot_buffs[buff_index].spellid == SPELL_UNKNOWN) + continue; + + query = StringFormat( + "INSERT INTO `bot_buffs` (" + "`bot_id`," + " `spell_id`," + " `caster_level`," + " `duration_formula`," + " `tics_remaining`," + " `poison_counters`," + " `disease_counters`," + " `curse_counters`," + " `corruption_counters`," + " `numhits`," + " `melee_rune`," + " `magic_rune`," + " `dot_rune`," + " `persistent`," + " `caston_x`," + " `caston_y`," + " `caston_z`," + " `extra_di_chance`" + ")" + " VALUES (" + "'%u'," /* bot_id */ + " '%u'," /* spell_id */ + " '%u'," /* caster_level */ + " '%u'," /* duration_formula */ + " '%u'," /* tics_remaining */ + " '%u'," /* poison_counters */ + " '%u'," /* disease_counters */ + " '%u'," /* curse_counters */ + " '%u'," /* corruption_counters */ + " '%u'," /* numhits */ + " '%u'," /* melee_rune */ + " '%u'," /* magic_rune */ + " '%u'," /* dot_rune */ + " '%u'," /* persistent */ + " '%i'," /* caston_x */ + " '%i'," /* caston_y */ + " '%i'," /* caston_z */ + " '%i'" /* extra_di_chance */ + ")", + bot_inst->GetBotID(), + bot_buffs[buff_index].spellid, + bot_buffs[buff_index].casterlevel, + spells[bot_buffs[buff_index].spellid].buffdurationformula, + bot_buffs[buff_index].ticsremaining, + ((CalculatePoisonCounters(bot_buffs[buff_index].spellid) > 0) ? (bot_buffs[buff_index].counters) : (0)), + ((CalculateDiseaseCounters(bot_buffs[buff_index].spellid) > 0) ? (bot_buffs[buff_index].counters) : (0)), + ((CalculateCurseCounters(bot_buffs[buff_index].spellid) > 0) ? (bot_buffs[buff_index].counters) : (0)), + ((CalculateCorruptionCounters(bot_buffs[buff_index].spellid) > 0) ? (bot_buffs[buff_index].counters) : (0)), + bot_buffs[buff_index].numhits, + bot_buffs[buff_index].melee_rune, + bot_buffs[buff_index].magic_rune, + bot_buffs[buff_index].dot_rune, + ((bot_buffs[buff_index].persistant_buff) ? (1) : (0)), + bot_buffs[buff_index].caston_x, + bot_buffs[buff_index].caston_y, + bot_buffs[buff_index].caston_z, + bot_buffs[buff_index].ExtraDIChance + ); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteBuffs(bot_inst->GetBotID()); + return false; + } + } + + return true; +} + +bool BotDatabase::DeleteBuffs(const uint32 bot_id) +{ + if (!bot_id) + return false; + + query = StringFormat("DELETE FROM `bot_buffs` WHERE `bot_id` = '%u'", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::LoadStance(const uint32 bot_id, int& bot_stance) +{ + if (!bot_id) + return false; + + query = StringFormat("SELECT `stance_id` FROM `bot_stances` WHERE `bot_id` = '%u' LIMIT 1", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + bot_stance = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadStance(Bot* bot_inst, bool& stance_flag) +{ + if (!bot_inst) + return false; + + bot_inst->SetDefaultBotStance(); + + query = StringFormat("SELECT `stance_id` FROM `bot_stances` WHERE `bot_id` = '%u' LIMIT 1", bot_inst->GetBotID()); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + bot_inst->SetBotStance((BotStanceType)atoi(row[0])); + stance_flag = true; + + return true; +} + +bool BotDatabase::SaveStance(const uint32 bot_id, const int bot_stance) +{ + if (!bot_id) + return false; + + if (!DeleteStance(bot_id)) + return false; + + query = StringFormat("INSERT INTO `bot_stances` (`bot_id`, `stance_id`) VALUES ('%u', '%u')", bot_id, bot_stance); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteStance(bot_id); + return false; + } + + return true; +} + +bool BotDatabase::SaveStance(Bot* bot_inst) +{ + if (!bot_inst) + return false; + + if (!DeleteStance(bot_inst->GetBotID())) + return false; + + query = StringFormat("INSERT INTO `bot_stances` (`bot_id`, `stance_id`) VALUES ('%u', '%u')", bot_inst->GetBotID(), bot_inst->GetBotStance()); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteStance(bot_inst->GetBotID()); + return false; + } + + return true; +} + +bool BotDatabase::DeleteStance(const uint32 bot_id) +{ + if (!bot_id) + return false; + + query = StringFormat("DELETE FROM `bot_stances` WHERE `bot_id` = '%u'", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::LoadTimers(Bot* bot_inst) +{ + if (!bot_inst) + return false; + + query = StringFormat( + "SELECT" + " IfNull(bt.`timer_id`, '0') As timer_id," + " IfNull(bt.`timer_value`, '0') As timer_value," + " IfNull(MAX(sn.`recast_time`), '0') AS MaxTimer" + " FROM `bot_timers` bt, `spells_new` sn" + " WHERE bt.`bot_id` = '%u' AND sn.`EndurTimerIndex` = (" + "SELECT case" + " WHEN timer_id > '%i' THEN timer_id - '%i'" + " ELSE timer_id END AS timer_id" + " FROM `bot_timers` WHERE `timer_id` = bt.`timer_id` AND `bot_id` = bt.`bot_id`" // double-check validity + ")" + " AND sn.`classes%i` <= '%i'", + bot_inst->GetBotID(), + (DisciplineReuseStart - 1), + (DisciplineReuseStart - 1), + bot_inst->GetClass(), + bot_inst->GetLevel() + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + uint32* bot_timers = bot_inst->GetTimers(); + if (!bot_timers) + return false; + + int timer_id = 0; + uint32 timer_value = 0; + uint32 max_value = 0; + for (auto row = results.begin(); row != results.end(); ++row) { + timer_id = atoi(row[0]) - 1; + timer_value = atoi(row[1]); + max_value = atoi(row[2]); + + if (timer_id >= 0 && timer_id < MaxTimer && timer_value < (Timer::GetCurrentTime() + max_value)) + bot_timers[timer_id] = timer_value; + } + + return true; +} + +bool BotDatabase::SaveTimers(Bot* bot_inst) +{ + if (!bot_inst) + return false; + + if (!DeleteTimers(bot_inst->GetBotID())) + return false; + + uint32* bot_timers = bot_inst->GetTimers(); + if (!bot_timers) + return false; + + for (int timer_index = 0; timer_index < MaxTimer; ++timer_index) { + if (bot_timers[timer_index] <= Timer::GetCurrentTime()) + continue; + + query = StringFormat("INSERT INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) VALUES ('%u', '%u', '%u')", bot_inst->GetBotID(), (timer_index + 1), bot_timers[timer_index]); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteTimers(bot_inst->GetBotID()); + return false; + } + } + + return true; +} + +bool BotDatabase::DeleteTimers(const uint32 bot_id) +{ + if (!bot_id) + return false; + + query = StringFormat("DELETE FROM `bot_timers` WHERE `bot_id` = '%u'", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::LoadGuildMembership(const uint32 bot_id, uint32& guild_id, uint8& guild_rank, std::string& guild_name) +{ + if (!bot_id) + return false; + + query = StringFormat( + "SELECT" + " gm.`guild_id`," + " gm.`rank`," + " g.`name`" + " FROM `vw_guild_members` AS gm" + " JOIN `guilds` AS g" + " ON gm.`guild_id` = g.`id`" + " WHERE gm.`char_id` = '%u'" + " AND gm.`mob_type` = 'B'" + " LIMIT 1", + bot_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + guild_id = atoi(row[0]); + guild_rank = atoi(row[1]); + guild_name = row[2]; + + return true; +} + +bool BotDatabase::SaveGuildMembership(const uint32 bot_id, const uint32 guild_id, const uint8 guild_rank) +{ + if (!bot_id || !guild_id) + return false; + + if (!DeleteGuildMembership(bot_id)) + return false; + + query = StringFormat("INSERT INTO `bot_guild_members` SET `bot_id` = '%u', `guild_id` = '%u', `rank` = '%u'", bot_id, guild_id, guild_rank); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteGuildMembership(bot_id); + return false; + } + + return true; +} + +bool BotDatabase::DeleteGuildMembership(const uint32 bot_id) +{ + if (!bot_id) + return false; + + query = StringFormat("DELETE FROM `bot_guild_members` WHERE `bot_id` = '%u'", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + + +/* Bot inventory functions */ +bool BotDatabase::QueryInventoryCount(const uint32 bot_id, uint32& item_count) +{ + if (!bot_id) + return false; + + query = StringFormat("SELECT COUNT(`inventories_index`) FROM `bot_inventories` WHERE `bot_id` = '%u'", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + item_count = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadItems(const uint32 bot_id, Inventory& inventory_inst) +{ + if (!bot_id) + return false; + + query = StringFormat( + "SELECT" + " `slot_id`," + " `item_id`," + " `inst_charges`," + " `inst_color`," + " `inst_no_drop`," + " `inst_custom_data`," + " `ornament_icon`," + " `ornament_id_file`," + " `ornament_hero_model`," + " `augment_1`," + " `augment_2`," + " `augment_3`," + " `augment_4`, " + " `augment_5`," + " `augment_6`" + " FROM `bot_inventories`" + " WHERE `bot_id` = '%i'" + " ORDER BY `slot_id`", + bot_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + for (auto row = results.begin(); row != results.end(); ++row) { + int16 slot_id = atoi(row[0]); + if ((slot_id < EQEmu::legacy::EQUIPMENT_BEGIN || slot_id > EQEmu::legacy::EQUIPMENT_END) && slot_id != EQEmu::legacy::SlotPowerSource) + continue; + + uint32 item_id = atoi(row[1]); + uint16 item_charges = (uint16)atoi(row[2]); + + ItemInst* item_inst = database.CreateItem( + item_id, + item_charges, + (uint32)atoul(row[9]), + (uint32)atoul(row[10]), + (uint32)atoul(row[11]), + (uint32)atoul(row[12]), + (uint32)atoul(row[13]), + (uint32)atoul(row[14]) + ); + if (!item_inst) { + Log.Out(Logs::General, Logs::Error, "Warning: bot_id '%i' has an invalid item_id '%i' in inventory slot '%i'", bot_id, item_id, slot_id); + continue; + } + + if (item_charges == 0x7FFF) + item_inst->SetCharges(-1); + else if (item_charges == 0 && item_inst->IsStackable()) // Stackable items need a minimum charge of 1 remain moveable. + item_inst->SetCharges(1); + else + item_inst->SetCharges(item_charges); + + uint32 item_color = atoul(row[3]); + if (item_color > 0) + item_inst->SetColor(item_color); + + if (item_inst->GetItem()->Attuneable) { + if (atoi(row[4])) + item_inst->SetAttuned(true); + else if (((slot_id >= EQEmu::legacy::EQUIPMENT_BEGIN) && (slot_id <= EQEmu::legacy::EQUIPMENT_END) || slot_id == EQEmu::legacy::SlotPowerSource)) + item_inst->SetAttuned(true); + } + + if (row[5]) { + std::string data_str(row[5]); + std::string idAsString; + std::string value; + bool use_id = true; + + for (int i = 0; i < data_str.length(); ++i) { + if (data_str[i] == '^') { + if (!use_id) { + item_inst->SetCustomData(idAsString, value); + idAsString.clear(); + value.clear(); + } + + use_id = !use_id; + continue; + } + + char v = data_str[i]; + if (use_id) + idAsString.push_back(v); + else + value.push_back(v); + } + } + + item_inst->SetOrnamentIcon((uint32)atoul(row[6])); + item_inst->SetOrnamentationIDFile((uint32)atoul(row[7])); + item_inst->SetOrnamentHeroModel((uint32)atoul(row[8])); + + if (inventory_inst.PutItem(slot_id, *item_inst) == INVALID_INDEX) + Log.Out(Logs::General, Logs::Error, "Warning: Invalid slot_id for item in inventory: bot_id = '%i', item_id = '%i', slot_id = '%i'", bot_id, item_id, slot_id); + + safe_delete(item_inst); + } + + return true; +} + +bool BotDatabase::SaveItems(Bot* bot_inst) +{ + return false; +} + +bool BotDatabase::DeleteItems(const uint32 bot_id) +{ + if (!bot_id) + return false; + + query = StringFormat("DELETE FROM `bot_inventories` WHERE `bot_id` = '%u'", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::LoadItemBySlot(Bot* bot_inst) +{ + return false; +} + +bool BotDatabase::LoadItemBySlot(const uint32 bot_id, const uint32 slot_id, uint32& item_id) +{ + if (!bot_id || (slot_id > EQEmu::legacy::EQUIPMENT_END && slot_id != EQEmu::legacy::SlotPowerSource)) + return false; + + query = StringFormat("SELECT `item_id` FROM `bot_inventories` WHERE `bot_id` = '%i' AND `slot_id` = '%i' LIMIT 1", bot_id, slot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + item_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::SaveItemBySlot(Bot* bot_inst, const uint32 slot_id, const ItemInst* item_inst) +{ + if (!bot_inst || !bot_inst->GetBotID() || (slot_id > EQEmu::legacy::EQUIPMENT_END && slot_id != EQEmu::legacy::SlotPowerSource)) + return false; + + if (!DeleteItemBySlot(bot_inst->GetBotID(), slot_id)) + return false; + + if (!item_inst || !item_inst->GetID()) + return true; + + uint32 augment_id[] = { 0, 0, 0, 0, 0, 0 }; + for (int augment_iter = 0; augment_iter < EQEmu::legacy::ITEM_COMMON_SIZE; ++augment_iter) + augment_id[augment_iter] = item_inst->GetAugmentItemID(augment_iter); + + uint16 item_charges = 0; + if (item_inst->GetCharges() >= 0) + item_charges = item_inst->GetCharges(); + else + item_charges = 0x7FFF; + + query = StringFormat( + "INSERT INTO `bot_inventories` (" + "`bot_id`," + " `slot_id`," + " `item_id`," + " `inst_charges`," + " `inst_color`," + " `inst_no_drop`," + " `inst_custom_data`," + " `ornament_icon`," + " `ornament_id_file`," + " `ornament_hero_model`," + " `augment_1`," + " `augment_2`," + " `augment_3`," + " `augment_4`," + " `augment_5`," + " `augment_6`" + ")" + " VALUES (" + "'%lu'," /* bot_id */ + " '%lu'," /* slot_id */ + " '%lu'," /* item_id */ + " '%lu'," /* inst_charges */ + " '%lu'," /* inst_color */ + " '%lu'," /* inst_no_drop */ + " '%s'," /* inst_custom_data */ + " '%lu'," /* ornament_icon */ + " '%lu'," /* ornament_id_file */ + " '%lu'," /* ornament_hero_model */ + " '%lu'," /* augment_1 */ + " '%lu'," /* augment_2 */ + " '%lu'," /* augment_3 */ + " '%lu'," /* augment_4 */ + " '%lu'," /* augment_5 */ + " '%lu'" /* augment_6 */ + ")", + (unsigned long)bot_inst->GetBotID(), + (unsigned long)slot_id, + (unsigned long)item_inst->GetID(), + (unsigned long)item_charges, + (unsigned long)item_inst->GetColor(), + (unsigned long)(item_inst->IsAttuned() ? 1 : 0), + item_inst->GetCustomDataString().c_str(), + (unsigned long)item_inst->GetOrnamentationIcon(), + (unsigned long)item_inst->GetOrnamentationIDFile(), + (unsigned long)item_inst->GetOrnamentHeroModel(), + (unsigned long)augment_id[0], + (unsigned long)augment_id[1], + (unsigned long)augment_id[2], + (unsigned long)augment_id[3], + (unsigned long)augment_id[4], + (unsigned long)augment_id[5] + ); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteItemBySlot(bot_inst->GetBotID(), slot_id); + return false; + } + + return true; +} + +bool BotDatabase::DeleteItemBySlot(const uint32 bot_id, const uint32 slot_id) +{ + if (!bot_id || (slot_id > EQEmu::legacy::EQUIPMENT_END && slot_id != EQEmu::legacy::SlotPowerSource)) + return false; + + query = StringFormat("DELETE FROM `bot_inventories` WHERE `bot_id` = '%u' AND `slot_id` = '%u'", bot_id, slot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::LoadEquipmentColor(const uint32 bot_id, const uint8 material_slot_id, uint32& rgb) +{ + if (!bot_id) + return false; + + int16 slot_id = Inventory::CalcSlotFromMaterial(material_slot_id); + if (slot_id == INVALID_INDEX) + return false; + + query = StringFormat("SELECT `inst_color` FROM `bot_inventories` WHERE `bot_id` = '%u' AND `slot_id` = '%u' LIMIT 1", bot_id, slot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + rgb = atoul(row[0]); + + return true; +} + +bool BotDatabase::SaveEquipmentColor(const uint32 bot_id, const int16 slot_id, const uint32 rgb) +{ + if (!bot_id) + return false; + + bool all_flag = (slot_id == -2); + if ((slot_id < EQEmu::legacy::EQUIPMENT_BEGIN || slot_id > EQEmu::legacy::EQUIPMENT_END) && slot_id != EQEmu::legacy::SlotPowerSource && !all_flag) + return false; + + std::string where_clause; + if (all_flag) + where_clause = StringFormat(" AND `slot_id` IN ('%u', '%u', '%u', '%u', '%u', '%u', '%u')", EQEmu::legacy::SlotHead, EQEmu::legacy::SlotArms, EQEmu::legacy::SlotWrist1, EQEmu::legacy::SlotHands, EQEmu::legacy::SlotChest, EQEmu::legacy::SlotLegs, EQEmu::legacy::SlotFeet); + else + where_clause = StringFormat(" AND `slot_id` = '%u'", slot_id); + + query = StringFormat( + "UPDATE `bot_inventories`" + " SET `inst_color` = '%u'" + " WHERE `bot_id` = '%u'" + " %s", + rgb, + where_clause.c_str(), + bot_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + + +/* Bot pet functions */ +bool BotDatabase::LoadPetIndex(const uint32 bot_id, uint32& pet_index) +{ + if (!bot_id) + return false; + + query = StringFormat("SELECT `pets_index` FROM `bot_pets` WHERE `bot_id` = '%u' LIMIT 1", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + pet_index = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadPetSpellID(const uint32 bot_id, uint32& pet_spell_id) +{ + if (!bot_id) + return false; + + query = StringFormat("SELECT `spell_id` FROM `bot_pets` WHERE `bot_id` = '%u' LIMIT 1", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + pet_spell_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadPetStats(const uint32 bot_id, std::string& pet_name, uint32& pet_mana, uint32& pet_hp, uint32& pet_spell_id) +{ + if (!bot_id) + return false; + + uint32 saved_pet_index = 0; + if (!LoadPetIndex(bot_id, saved_pet_index)) + return false; + if (!saved_pet_index) + return true; + + query = StringFormat("SELECT `spell_id`, `name`, `mana`, `hp` FROM `bot_pets` WHERE `pets_index` = '%u' LIMIT 1", saved_pet_index); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + pet_spell_id = atoi(row[0]); + pet_name = row[1]; + pet_mana = atoi(row[2]); + pet_hp = atoi(row[3]); + + return true; +} + +bool BotDatabase::SavePetStats(const uint32 bot_id, const std::string& pet_name, const uint32 pet_mana, const uint32 pet_hp, const uint32 pet_spell_id) +{ + if (!bot_id || pet_name.empty() || !pet_spell_id || pet_spell_id > SPDAT_RECORDS) + return false; + + if (!DeletePetItems(bot_id)) + return false; + if (!DeletePetBuffs(bot_id)) + return false; + if (!DeletePetStats(bot_id)) + return false; + + query = StringFormat( + "INSERT INTO `bot_pets` (" + "`spell_id`," + " `bot_id`," + " `name`," + " `mana`," + " `hp`" + ")" + " VALUES (" + "'%u'," + " '%u'," + " '%s'," + " '%u'," + " '%u'" + ")", + pet_spell_id, + bot_id, + pet_name.c_str(), + pet_mana, + pet_hp + ); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeletePetStats(bot_id); + return false; + } + + return true; +} + +bool BotDatabase::DeletePetStats(const uint32 bot_id) +{ + if (!bot_id) + return false; + + uint32 saved_pet_index = 0; + if (!LoadPetIndex(bot_id, saved_pet_index)) + return false; + if (!saved_pet_index) + return true; + + query = StringFormat("DELETE FROM `bot_pets` WHERE `pets_index` = '%u'", saved_pet_index); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::LoadPetBuffs(const uint32 bot_id, SpellBuff_Struct* pet_buffs) +{ + if (!bot_id) + return false; + + uint32 saved_pet_index = 0; + if (!LoadPetIndex(bot_id, saved_pet_index)) + return false; + if (!saved_pet_index) + return true; + + query = StringFormat("SELECT `spell_id`, `caster_level`, `duration` FROM `bot_pet_buffs` WHERE `pets_index` = '%u'", saved_pet_index); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + int buff_index = 0; + for (auto row = results.begin(); row != results.end() && buff_index < PET_BUFF_COUNT; ++row) { + pet_buffs[buff_index].spellid = atoi(row[0]); + pet_buffs[buff_index].level = atoi(row[1]); + pet_buffs[buff_index].duration = atoi(row[2]); + + // Work around for loading the counters and setting them back to max. Need entry in DB for saved counters + if (CalculatePoisonCounters(pet_buffs[buff_index].spellid) > 0) + pet_buffs[buff_index].counters = CalculatePoisonCounters(pet_buffs[buff_index].spellid); + else if (CalculateDiseaseCounters(pet_buffs[buff_index].spellid) > 0) + pet_buffs[buff_index].counters = CalculateDiseaseCounters(pet_buffs[buff_index].spellid); + else if (CalculateCurseCounters(pet_buffs[buff_index].spellid) > 0) + pet_buffs[buff_index].counters = CalculateCurseCounters(pet_buffs[buff_index].spellid); + else if (CalculateCorruptionCounters(pet_buffs[buff_index].spellid) > 0) + pet_buffs[buff_index].counters = CalculateCorruptionCounters(pet_buffs[buff_index].spellid); + + ++buff_index; + } + + return true; +} + +bool BotDatabase::SavePetBuffs(const uint32 bot_id, const SpellBuff_Struct* pet_buffs, bool delete_flag) +{ + // Only use 'delete_flag' if not invoked after a botdb.SavePetStats() call + + if (!bot_id || !pet_buffs) + return false; + + if (delete_flag && !DeletePetBuffs(bot_id)) + return false; + + uint32 saved_pet_index = 0; + if (!LoadPetIndex(bot_id, saved_pet_index)) + return false; + if (!saved_pet_index) + return true; + + for (int buff_index = 0; buff_index < PET_BUFF_COUNT; ++buff_index) { + if (!pet_buffs[buff_index].spellid || pet_buffs[buff_index].spellid == SPELL_UNKNOWN) + continue; + + query = StringFormat( + "INSERT INTO `bot_pet_buffs` (" + "`pets_index`," + " `spell_id`," + " `caster_level`," + " `duration`" + ")" + " VALUES (" + "'%u'," + " '%u'," + " '%u'," + " '%u'" + ")", + saved_pet_index, + pet_buffs[buff_index].spellid, + pet_buffs[buff_index].level, + pet_buffs[buff_index].duration + ); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeletePetBuffs(bot_id); + return false; + } + } + + return true; +} + +bool BotDatabase::DeletePetBuffs(const uint32 bot_id) +{ + if (!bot_id) + return false; + + uint32 saved_pet_index = 0; + if (!LoadPetIndex(bot_id, saved_pet_index)) + return false; + if (!saved_pet_index) + return true; + + query = StringFormat("DELETE FROM `bot_pet_buffs` WHERE `pets_index` = '%u'", saved_pet_index); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::LoadPetItems(const uint32 bot_id, uint32* pet_items) +{ + if (!bot_id || !pet_items) + return false; + + uint32 saved_pet_index = 0; + if (!LoadPetIndex(bot_id, saved_pet_index)) + return false; + if (!saved_pet_index) + return true; + + query = StringFormat("SELECT `item_id` FROM `bot_pet_inventories` WHERE `pets_index` = '%u'", saved_pet_index); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + int item_index = 0; + for (auto row = results.begin(); row != results.end() && item_index < EQEmu::legacy::EQUIPMENT_SIZE; ++row) { + pet_items[item_index] = atoi(row[0]); + ++item_index; + } + + return true; +} + +bool BotDatabase::SavePetItems(const uint32 bot_id, const uint32* pet_items, bool delete_flag) +{ + // Only use 'delete_flag' if not invoked after a botdb.SavePetStats() call + + if (!bot_id || !pet_items) + return false; + + if (delete_flag && !DeletePetItems(bot_id)) + return false; + + uint32 saved_pet_index = 0; + if (!LoadPetIndex(bot_id, saved_pet_index)) + return false; + if (!saved_pet_index) + return true; + + for (int item_index = 0; item_index < EQEmu::legacy::EQUIPMENT_SIZE; ++item_index) { + if (!pet_items[item_index]) + continue; + + query = StringFormat("INSERT INTO `bot_pet_inventories` (`pets_index`, `item_id`) VALUES ('%u', '%u')", saved_pet_index, pet_items[item_index]); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeletePetItems(bot_id); + return false; + } + } + + return true; +} + +bool BotDatabase::DeletePetItems(const uint32 bot_id) +{ + if (!bot_id) + return false; + + uint32 saved_pet_index = 0; + if (!LoadPetIndex(bot_id, saved_pet_index)) + return false; + if (!saved_pet_index) + return true; + + query = StringFormat("DELETE FROM `bot_pet_inventories` WHERE `pets_index` = '%u'", saved_pet_index); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + + +/* Bot command functions */ +bool BotDatabase::LoadInspectMessage(const uint32 bot_id, InspectMessage_Struct& inspect_message) +{ + if (!bot_id) + return false; + + query = StringFormat("SELECT `inspect_message` FROM `bot_inspect_messages` WHERE `bot_id` = '%u' LIMIT 1", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + std::string bot_message = row[0]; + if (bot_message.size() > 255) + bot_message = bot_message.substr(0, 255); + if (bot_message.empty()) + return true; + + memcpy(inspect_message.text, bot_message.c_str(), bot_message.size()); + + return true; +} + +bool BotDatabase::SaveInspectMessage(const uint32 bot_id, const InspectMessage_Struct& inspect_message) +{ + if (!bot_id) + return false; + + if (!DeleteInspectMessage(bot_id)) + return false; + + std::string bot_message = inspect_message.text; + if (bot_message.size() > 255) + bot_message = bot_message.substr(0, 255); + if (bot_message.empty()) + return true; + + query = StringFormat("INSERT INTO `bot_inspect_messages` (`bot_id`, `inspect_message`) VALUES ('%u', '%s')", bot_id, bot_message.c_str()); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteInspectMessage(bot_id); + return false; + } + + return true; +} + +bool BotDatabase::DeleteInspectMessage(const uint32 bot_id) +{ + if (!bot_id) + return false; + + query = StringFormat("DELETE FROM `bot_inspect_messages` WHERE `bot_id` = '%u'", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::SaveAllInspectMessages(const uint32 owner_id, const InspectMessage_Struct& inspect_message) +{ + if (!owner_id) + return false; + + if (!DeleteAllInspectMessages(owner_id)) + return false; + + std::string bot_message = inspect_message.text; + if (bot_message.size() > 255) + bot_message = bot_message.substr(0, 255); + if (bot_message.empty()) + return true; + + query = StringFormat("INSERT INTO `bot_inspect_messages` (`bot_id`, `inspect_message`) SELECT `bot_id`, '%s' inspect_message FROM `bot_data` WHERE `owner_id` = '%u'", bot_message.c_str(), owner_id); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteAllInspectMessages(owner_id); + return false; + } + + return true; +} + +bool BotDatabase::DeleteAllInspectMessages(const uint32 owner_id) +{ + if (!owner_id) + return false; + + query = StringFormat("DELETE FROM `bot_inspect_messages` WHERE `bot_id` IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u')", owner_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::SaveAllArmorColorBySlot(const uint32 owner_id, const int16 slot_id, const uint32 rgb_value) +{ + if (!owner_id) + return false; + + query = StringFormat( + "UPDATE `bot_inventories` bi" + " INNER JOIN `bot_data` bd" + " ON bd.`owner_id` = '%u'" + " SET bi.`inst_color` = '%u'" + " WHERE bi.`bot_id` = bd.`bot_id`" + " AND bi.`slot_id` IN ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')" + " AND bi.`slot_id` = '%i'", + owner_id, + rgb_value, + EQEmu::legacy::SlotHead, EQEmu::legacy::SlotChest, EQEmu::legacy::SlotArms, EQEmu::legacy::SlotWrist1, EQEmu::legacy::SlotWrist2, EQEmu::legacy::SlotHands, EQEmu::legacy::SlotLegs, EQEmu::legacy::SlotFeet, + slot_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::SaveAllArmorColors(const uint32 owner_id, const uint32 rgb_value) +{ + if (!owner_id) + return false; + + query = StringFormat( + "UPDATE `bot_inventories` bi" + " INNER JOIN `bot_data` bd" + " ON bd.`owner_id` = '%u'" + " SET bi.`inst_color` = '%u'" + " WHERE bi.`bot_id` = bd.`bot_id`" + " AND bi.`slot_id` IN ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", + owner_id, + rgb_value, + EQEmu::legacy::SlotHead, EQEmu::legacy::SlotChest, EQEmu::legacy::SlotArms, EQEmu::legacy::SlotWrist1, EQEmu::legacy::SlotWrist2, EQEmu::legacy::SlotHands, EQEmu::legacy::SlotLegs, EQEmu::legacy::SlotFeet + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::SaveHelmAppearance(const uint32 owner_id, const uint32 bot_id, const bool show_flag) +{ + if (!owner_id || !bot_id) + return false; + + query = StringFormat( + "UPDATE `bot_data`" + " SET `show_helm` = '%u'" + " WHERE `owner_id` = '%u'" + " AND `bot_id` = '%u'", + (show_flag ? 1 : 0), + owner_id, + bot_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::SaveAllHelmAppearances(const uint32 owner_id, const bool show_flag) +{ + if (!owner_id) + return false; + + query = StringFormat( + "UPDATE `bot_data`" + " SET `show_helm` = '%u'" + " WHERE `owner_id` = '%u'", + (show_flag ? 1 : 0), + owner_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::ToggleHelmAppearance(const uint32 owner_id, const uint32 bot_id) +{ + if (!owner_id || !bot_id) + return false; + + query = StringFormat( + "UPDATE `bot_data`" + " SET `show_helm` = (`show_helm` XOR '1')" + " WHERE `owner_id` = '%u'" + " AND `bot_id` = '%u'", + owner_id, + bot_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::ToggleAllHelmAppearances(const uint32 owner_id) +{ + if (!owner_id) + return false; + + query = StringFormat( + "UPDATE `bot_data`" + " SET `show_helm` = (`show_helm` XOR '1')" + " WHERE `owner_id` = '%u'", + owner_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::SaveFollowDistance(const uint32 owner_id, const uint32 bot_id, const uint32 follow_distance) +{ + if (!owner_id || !bot_id || !follow_distance) + return false; + + query = StringFormat( + "UPDATE `bot_data`" + " SET `follow_distance` = '%u'" + " WHERE `owner_id` = '%u'" + " AND `bot_id` = '%u'", + follow_distance, + owner_id, + bot_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::SaveAllFollowDistances(const uint32 owner_id, const uint32 follow_distance) +{ + if (!owner_id || !follow_distance) + return false; + + query = StringFormat( + "UPDATE `bot_data`" + " SET `follow_distance` = '%u'" + " WHERE `owner_id` = '%u'", + follow_distance, + owner_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::CreateCloneBot(const uint32 owner_id, const uint32 bot_id, const std::string& clone_name, uint32& clone_id) +{ + if (!owner_id || !bot_id || clone_name.empty()) + return false; + + query = StringFormat( + "INSERT INTO `bot_data`" + " (" + "`owner_id`," + " `spells_id`," + " `name`," + " `last_name`," + " `title`," + " `suffix`," + " `zone_id`," + " `gender`," + " `race`," + " `class`," + " `level`," + " `deity`," + " `creation_day`," + " `last_spawn`," + " `time_spawned`," + " `size`," + " `face`," + " `hair_color`," + " `hair_style`," + " `beard`," + " `beard_color`," + " `eye_color_1`," + " `eye_color_2`," + " `drakkin_heritage`," + " `drakkin_tattoo`," + " `drakkin_details`," + " `ac`," + " `atk`," + " `hp`," + " `mana`," + " `str`," + " `sta`," + " `cha`," + " `dex`," + " `int`," + " `agi`," + " `wis`," + " `fire`," + " `cold`," + " `magic`," + " `poison`," + " `disease`," + " `corruption`," + " `show_helm`," + " `follow_distance`" + ")" + " SELECT" + " bd.`owner_id`," + " bd.`spells_id`," + " '%s'," + " ''," + " bd.`title`," + " bd.`suffix`," + " bd.`zone_id`," + " bd.`gender`," + " bd.`race`," + " bd.`class`," + " bd.`level`," + " bd.`deity`," + " UNIX_TIMESTAMP()," + " UNIX_TIMESTAMP()," + " '0'," + " bd.`size`," + " bd.`face`," + " bd.`hair_color`," + " bd.`hair_style`," + " bd.`beard`," + " bd.`beard_color`," + " bd.`eye_color_1`," + " bd.`eye_color_2`," + " bd.`drakkin_heritage`," + " bd.`drakkin_tattoo`," + " bd.`drakkin_details`," + " bd.`ac`," + " bd.`atk`," + " bd.`hp`," + " bd.`mana`," + " bd.`str`," + " bd.`sta`," + " bd.`cha`," + " bd.`dex`," + " bd.`int`," + " bd.`agi`," + " bd.`wis`," + " bd.`fire`," + " bd.`cold`," + " bd.`magic`," + " bd.`poison`," + " bd.`disease`," + " bd.`corruption`," + " bd.`show_helm`," + " bd.`follow_distance`" + " FROM `bot_data` bd" + " WHERE" + " bd.`owner_id` = '%u'" + " AND" + " bd.`bot_id` = '%u'", + clone_name.c_str(), + owner_id, + bot_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + clone_id = results.LastInsertedID(); + + return true; +} + +bool BotDatabase::CreateCloneBotInventory(const uint32 owner_id, const uint32 bot_id, const uint32 clone_id) +{ + if (!owner_id || !bot_id || !clone_id) + return false; + + query = StringFormat( + "INSERT INTO `bot_inventories`" + " (" + "bot_id," + " `slot_id`," + " `item_id`," + " `inst_charges`," + " `inst_color`," + " `inst_no_drop`," + " `inst_custom_data`," + " `ornament_icon`," + " `ornament_id_file`," + " `ornament_hero_model`," + " `augment_1`," + " `augment_2`," + " `augment_3`," + " `augment_4`," + " `augment_5`," + " `augment_6`" + ")" + " SELECT" + " '%u' bot_id," + " bi.`slot_id`," + " bi.`item_id`," + " bi.`inst_charges`," + " bi.`inst_color`," + " bi.`inst_no_drop`," + " bi.`inst_custom_data`," + " bi.`ornament_icon`," + " bi.`ornament_id_file`," + " bi.`ornament_hero_model`," + " bi.`augment_1`," + " bi.`augment_2`," + " bi.`augment_3`," + " bi.`augment_4`," + " bi.`augment_5`," + " bi.`augment_6`" + " FROM `bot_inventories` bi" + " WHERE" + " bi.`bot_id` = '%u'" + " AND" + " '%u' = (SELECT `owner_id` FROM `bot_data` WHERE `bot_id` = '%u')", + clone_id, + bot_id, + owner_id, + bot_id + ); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteItems(clone_id); + return false; + } + + return true; +} + + +/* Bot bot-group functions */ +bool BotDatabase::QueryBotGroupExistence(const std::string& group_name, bool& extant_flag) +{ + if (group_name.empty()) + return false; + + query = StringFormat("SELECT `group_name` FROM `vw_bot_groups` WHERE `group_name` LIKE '%s' LIMIT 1", group_name.c_str()); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + extant_flag = true; + + return true; +} + +bool BotDatabase::LoadBotGroupIDByBotGroupName(const std::string& group_name, uint32& botgroup_id) +{ + if (group_name.empty()) + return false; + + query = StringFormat("SELECT `groups_index` FROM `bot_groups` WHERE `group_name` = '%s' LIMIT 1", group_name.c_str()); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + botgroup_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadBotGroupIDByLeaderID(const uint32 leader_id, uint32& botgroup_id) +{ + if (!leader_id) + return false; + + query = StringFormat("SELECT `groups_index` FROM `bot_groups` WHERE `group_leader_id` = '%u' LIMIT 1", leader_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + botgroup_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadBotGroupIDByMemberID(const uint32 member_id, uint32& botgroup_id) +{ + if (!member_id) + return false; + + query = StringFormat("SELECT `groups_index` FROM `bot_group_members` WHERE `bot_id` = '%u' LIMIT 1", member_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + botgroup_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadLeaderIDByBotGroupName(const std::string& group_name, uint32& leader_id) +{ + if (group_name.empty()) + return false; + + query = StringFormat("SELECT `group_leader_id` FROM `bot_groups` WHERE `group_name` = '%s' LIMIT 1", group_name.c_str()); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + leader_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadLeaderIDByBotGroupID(const uint32 group_id, uint32& leader_id) +{ + if (!group_id) + return false; + + query = StringFormat("SELECT `group_leader_id` FROM `bot_groups` WHERE `groups_index` = '%u' LIMIT 1", group_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + leader_id = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadBotGroupNameByBotGroupID(const uint32 group_id, std::string& botgroup_name) +{ + if (!group_id) + false; + + query = StringFormat("SELECT `group_name` FROM `bot_groups` WHERE `groups_index` = '%u' LIMIT 1", group_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + botgroup_name = row[0]; + + return true; +} + +bool BotDatabase::LoadBotGroupNameByLeaderID(const uint32 leader_id, std::string& botgroup_name) +{ + if (!leader_id) + return false; + + query = StringFormat("SELECT `group_name` FROM `bot_groups` WHERE `group_leader_id` = '%u' LIMIT 1", leader_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + botgroup_name = row[0]; + + return true; +} + +bool BotDatabase::CreateBotGroup(const std::string& group_name, const uint32 leader_id) +{ + if (group_name.empty() || !leader_id) + return false; + + bool extant_flag = false; + if (!QueryBotGroupExistence(group_name, extant_flag)) + return false; + if (extant_flag) + return true; + + query = StringFormat("INSERT INTO `bot_groups` (`group_leader_id`, `group_name`) VALUES ('%u', '%s')", leader_id, group_name.c_str()); + auto results = QueryDatabase(query); + if (!results.Success()) { + DeleteBotGroup(leader_id); + return false; + } + + auto botgroup_id = results.LastInsertedID(); + if (!botgroup_id) { + DeleteBotGroup(leader_id); + return false; + } + + query = StringFormat("INSERT INTO `bot_group_members` (`groups_index`, `bot_id`) VALUES ('%u', '%u')", botgroup_id, leader_id); + results = QueryDatabase(query); + if (!results.Success()) { + RemoveMemberFromBotGroup(leader_id); + return false; + } + + return true; +} + +bool BotDatabase::DeleteBotGroup(const uint32 leader_id) +{ + if (!leader_id) + return false; + + uint32 botgroup_id = 0; + if (!LoadBotGroupIDByLeaderID(leader_id, botgroup_id)) + return false; + if (!botgroup_id) + return true; + + query = StringFormat("DELETE FROM `bot_group_members` WHERE `groups_index` = '%u'", botgroup_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + query = StringFormat("DELETE FROM `bot_groups` WHERE `groups_index` = '%u'", botgroup_id); + results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::AddMemberToBotGroup(const uint32 leader_id, const uint32 member_id) +{ + if (!leader_id || !member_id) + return false; + + uint32 botgroup_id = 0; + if (!LoadBotGroupIDByLeaderID(leader_id, botgroup_id)) + return false; + if (!botgroup_id) + return true; + + query = StringFormat("INSERT INTO `bot_group_members` (`groups_index`, `bot_id`) VALUES ('%u', '%u')", botgroup_id, member_id); + auto results = QueryDatabase(query); + if (!results.Success()) { + RemoveMemberFromBotGroup(member_id); + return false; + } + + return true; +} + +bool BotDatabase::RemoveMemberFromBotGroup(const uint32 member_id) +{ + if (!member_id) + return false; + + uint32 botgroup_id = 0; + if (!LoadBotGroupIDByLeaderID(member_id, botgroup_id)) + return false; + if (botgroup_id) + return DeleteBotGroup(member_id); + + query = StringFormat("DELETE FROM `bot_group_members` WHERE `bot_id` = '%u'", member_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::LoadBotGroupIDForLoadBotGroup(const uint32 owner_id, const std::string& group_name, uint32& botgroup_id) +{ + if (!owner_id || group_name.empty()) + return false; + + query = StringFormat("SELECT `groups_index`, `group_name` FROM `vw_bot_groups` WHERE `owner_id` = '%u'", owner_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + for (auto row = results.begin(); row != results.end(); ++row) { + if (!group_name.compare(row[1])) { + botgroup_id = atoi(row[0]); + break; + } + } + + return true; +} + +bool BotDatabase::LoadBotGroup(const std::string& group_name, std::map>& member_list) +{ + if (group_name.empty()) + return false; + + uint32 botgroup_id = 0; + if (!LoadBotGroupIDByBotGroupName(group_name, botgroup_id)) + return false; + if (!botgroup_id) + return true; + + query = StringFormat("SELECT `bot_id` FROM `bot_group_members` WHERE `groups_index` = '%u' LIMIT 6", botgroup_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + for (auto row = results.begin(); row != results.end(); ++row) + member_list[botgroup_id].push_back(atoi(row[0])); + + return true; +} + +bool BotDatabase::LoadBotGroupsListByOwnerID(const uint32 owner_id, std::list>& botgroups_list) +{ + if (!owner_id) + return false; + + query = StringFormat("SELECT `group_name`, `group_leader_name` FROM `vw_bot_groups` WHERE `owner_id` = '%u'", owner_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + for (auto row = results.begin(); row != results.end(); ++row) + botgroups_list.push_back(std::pair(row[0], row[1])); + + return true; +} + + +/* Bot owner group functions */ +bool BotDatabase::LoadGroupedBotsByGroupID(const uint32 group_id, std::list& group_list) +{ + if (!group_id) + return false; + + query = StringFormat( + "SELECT `charid`" + " FROM `group_id`" + " WHERE `groupid` = '%u'" + " AND `charid` IN (" + " SELECT `bot_id`" + " FROM `bot_data`" + " WHERE `owner_id` IN (" + " SELECT `charid`" + " FROM `group_id`" + " WHERE `groupid` = '%u'" + " AND `name` IN (" + " SELECT `name`" + " FROM `character_data`" + " )" + " )" + " )", + group_id, + group_id + ); + + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + for (auto row = results.begin(); row != results.end(); ++row) + group_list.push_back(atoi(row[0])); + + return true; +} + + +/* Bot heal rotation functions */ +bool BotDatabase::LoadHealRotationIDByBotID(const uint32 bot_id, uint32& hr_index) +{ + if (!bot_id) + return false; + + query = StringFormat("SELECT `heal_rotation_index` FROM `bot_heal_rotations` WHERE `bot_id` = '%u' LIMIT 1", bot_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + hr_index = atoi(row[0]); + + return true; +} + +bool BotDatabase::LoadHealRotation(Bot* hr_member, std::list& member_list, std::list& target_list, bool& load_flag, bool& member_fail, bool& target_fail) +{ + if (!hr_member) + return false; + + uint32 hr_index = 0; + if (!LoadHealRotationIDByBotID(hr_member->GetBotID(), hr_index)) + return false; + if (!hr_index) + return true; + + if (!hr_member->IsHealRotationMember()) + return false; + + query = StringFormat( + "SELECT " + " `interval`," + " `fast_heals`," + " `adaptive_targeting`," + " `casting_override`," + " `safe_hp_base`," + " `safe_hp_cloth`," + " `safe_hp_leather`," + " `safe_hp_chain`," + " `safe_hp_plate`," + " `critical_hp_base`," + " `critical_hp_cloth`," + " `critical_hp_leather`," + " `critical_hp_chain`," + " `critical_hp_plate`" + " FROM `bot_heal_rotations`" + " WHERE `heal_rotation_index` = '%u'" + " LIMIT 1", + hr_index + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + auto row = results.begin(); + (*hr_member->MemberOfHealRotation())->SetIntervalS((uint32)atoi(row[0])); + (*hr_member->MemberOfHealRotation())->SetFastHeals((bool)atoi(row[1])); + (*hr_member->MemberOfHealRotation())->SetAdaptiveTargeting((bool)atoi(row[2])); + (*hr_member->MemberOfHealRotation())->SetCastingOverride((bool)atoi(row[3])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeSafeHPRatio(ARMOR_TYPE_UNKNOWN, atof(row[4])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeSafeHPRatio(ARMOR_TYPE_CLOTH, atof(row[5])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeSafeHPRatio(ARMOR_TYPE_LEATHER, atof(row[6])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeSafeHPRatio(ARMOR_TYPE_CHAIN, atof(row[7])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeSafeHPRatio(ARMOR_TYPE_PLATE, atof(row[8])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeCriticalHPRatio(ARMOR_TYPE_UNKNOWN, atof(row[9])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeCriticalHPRatio(ARMOR_TYPE_CLOTH, atof(row[10])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeCriticalHPRatio(ARMOR_TYPE_LEATHER, atof(row[11])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeCriticalHPRatio(ARMOR_TYPE_CHAIN, atof(row[12])); + (*hr_member->MemberOfHealRotation())->SetArmorTypeCriticalHPRatio(ARMOR_TYPE_PLATE, atof(row[13])); + + load_flag = true; + + if (!LoadHealRotationMembers(hr_index, member_list)) + member_fail = true; + + if (!LoadHealRotationTargets(hr_index, target_list)) + target_fail = true; + + return true; +} + +bool BotDatabase::LoadHealRotationMembers(const uint32 hr_index, std::list& member_list) +{ + if (!hr_index) + return false; + + query = StringFormat("SELECT `bot_id` FROM `bot_heal_rotation_members` WHERE `heal_rotation_index` = '%u'", hr_index); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + for (auto row : results) { + if (row[0]) + member_list.push_back(atoi(row[0])); + } + + return true; +} + +bool BotDatabase::LoadHealRotationTargets(const uint32 hr_index, std::list& target_list) +{ + if (!hr_index) + return false; + + query = StringFormat("SELECT `target_name` FROM `bot_heal_rotation_targets` WHERE `heal_rotation_index` = '%u'", hr_index); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + if (!results.RowCount()) + return true; + + for (auto row : results) { + if (row[0]) + target_list.push_back(row[0]); + } + + return true; +} + +bool BotDatabase::SaveHealRotation(Bot* hr_member, bool& member_fail, bool& target_fail) +{ + if (!hr_member) + return false; + + if (!DeleteHealRotation(hr_member->GetBotID())) + return false; + + if (!hr_member->IsHealRotationMember()) + return false; + + query = StringFormat( + "INSERT INTO `bot_heal_rotations` (" + "`bot_id`," + " `interval`," + " `fast_heals`," + " `adaptive_targeting`," + " `casting_override`," + " `safe_hp_base`," + " `safe_hp_cloth`," + " `safe_hp_leather`," + " `safe_hp_chain`," + " `safe_hp_plate`," + " `critical_hp_base`," + " `critical_hp_cloth`," + " `critical_hp_leather`," + " `critical_hp_chain`," + " `critical_hp_plate`" + ")" + " VALUES (" + "'%u'," + " '%u'," + " '%u'," + " '%u'," + " '%u'," + " '%f'," + " '%f'," + " '%f'," + " '%f'," + " '%f'," + " '%f'," + " '%f'," + " '%f'," + " '%f'," + " '%f'" + ")", + hr_member->GetBotID(), + ((*hr_member->MemberOfHealRotation())->IntervalS()), + ((*hr_member->MemberOfHealRotation())->FastHeals()), + ((*hr_member->MemberOfHealRotation())->AdaptiveTargeting()), + ((*hr_member->MemberOfHealRotation())->CastingOverride()), + ((*hr_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_UNKNOWN)), + ((*hr_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_CLOTH)), + ((*hr_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_LEATHER)), + ((*hr_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_CHAIN)), + ((*hr_member->MemberOfHealRotation())->ArmorTypeSafeHPRatio(ARMOR_TYPE_PLATE)), + ((*hr_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_UNKNOWN)), + ((*hr_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_CLOTH)), + ((*hr_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_LEATHER)), + ((*hr_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_CHAIN)), + ((*hr_member->MemberOfHealRotation())->ArmorTypeCriticalHPRatio(ARMOR_TYPE_PLATE)) + ); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + uint32 hr_index = results.LastInsertedID(); + if (!hr_index) + return false; + + std::list* member_list = (*hr_member->MemberOfHealRotation())->MemberList(); + + for (auto member_iter : *member_list) { + if (!member_iter) + continue; + + query = StringFormat("INSERT INTO `bot_heal_rotation_members` (`heal_rotation_index`, `bot_id`) VALUES ('%u', '%u')", hr_index, member_iter->GetBotID()); + auto results = QueryDatabase(query); + if (!results.Success()) { + member_fail = true; + break; + } + } + + std::list* target_list = (*hr_member->MemberOfHealRotation())->TargetList(); + + for (auto target_iter : *target_list) { + if (!target_iter) + continue; + + query = StringFormat("INSERT INTO `bot_heal_rotation_targets` (`heal_rotation_index`, `target_name`) VALUES ('%u', '%s')", hr_index, target_iter->GetCleanName()); + auto results = QueryDatabase(query); + if (!results.Success()) { + target_fail = true; + break; + } + } + + return true; +} + +bool BotDatabase::DeleteHealRotation(const uint32 creator_id) +{ + if (!creator_id) + return false; + + uint32 hr_index = 0; + if (!LoadHealRotationIDByBotID(creator_id, hr_index)) + return false; + if (!hr_index) + return true; + + query = StringFormat("DELETE FROM `bot_heal_rotation_targets` WHERE `heal_rotation_index` = '%u'", hr_index); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + query = StringFormat("DELETE FROM `bot_heal_rotation_members` WHERE `heal_rotation_index` = '%u'", hr_index); + results = QueryDatabase(query); + if (!results.Success()) + return false; + + query = StringFormat("DELETE FROM `bot_heal_rotations` WHERE `heal_rotation_index` = '%u'", hr_index); + results = QueryDatabase(query); + if (!results.Success()) + return false; + + return true; +} + +bool BotDatabase::DeleteAllHealRotations(const uint32 owner_id) +{ + if (!owner_id) + return false; + + query = StringFormat("SELECT `bot_id` FROM `bot_heal_rotations` WHERE `bot_id` IN (SELECT `bot_id` FROM `bot_data` WHERE `owner_id` = '%u')", owner_id); + auto results = QueryDatabase(query); + if (!results.Success()) + return false; + + for (auto row : results) { + if (!row[0]) + continue; + + DeleteHealRotation(atoi(row[0])); + } + + return true; +} + + +/* Bot miscellaneous functions */ + + +/* fail::Bot functions */ +const char* BotDatabase::fail::QueryNameAvailablity() { return "Failed to query name availability"; } +const char* BotDatabase::fail::QueryBotCount() { return "Failed to query bot count"; } +const char* BotDatabase::fail::LoadQuestableSpawnCount() { return "Failed to load questable spawn count"; } +const char* BotDatabase::fail::LoadBotsList() { return "Failed to bots list"; } +const char* BotDatabase::fail::LoadOwnerID() { return "Failed to load owner id"; } +const char* BotDatabase::fail::LoadBotID() { return "Failed to load bot id"; } +const char* BotDatabase::fail::LoadBot() { return "Failed to load bot"; } +const char* BotDatabase::fail::SaveNewBot() { return "Failed to save new bot"; } +const char* BotDatabase::fail::SaveBot() { return "Failed to save bot"; } +const char* BotDatabase::fail::DeleteBot() { return "Failed to delete bot"; } +const char* BotDatabase::fail::LoadBuffs() { return "Failed to load buffs"; } +const char* BotDatabase::fail::SaveBuffs() { return "Failed to save buffs"; } +const char* BotDatabase::fail::DeleteBuffs() { return "Failed to delete buffs"; } +const char* BotDatabase::fail::LoadStance() { return "Failed to load stance"; } +const char* BotDatabase::fail::SaveStance() { return "Failed to save stance"; } +const char* BotDatabase::fail::DeleteStance() { return "Failed to delete stance"; } +const char* BotDatabase::fail::LoadTimers() { return "Failed to load timers"; } +const char* BotDatabase::fail::SaveTimers() { return "Failed to save timers"; } +const char* BotDatabase::fail::DeleteTimers() { return "Failed to delete timers"; } +const char* BotDatabase::fail::LoadGuildMembership() { return "Failed to load guild membership"; } +const char* BotDatabase::fail::SaveGuildMembership() { return "Failed to save guild membership"; } +const char* BotDatabase::fail::DeleteGuildMembership() { return "Failed to delete guild membership"; } + +/* fail::Bot inventory functions */ +const char* BotDatabase::fail::QueryInventoryCount() { return "Failed to query inventory count"; } +const char* BotDatabase::fail::LoadItems() { return "Failed to load items"; } +const char* BotDatabase::fail::SaveItems() { return "Failed to save items"; } +const char* BotDatabase::fail::DeleteItems() { return "Failed to delete items"; } +const char* BotDatabase::fail::LoadItemBySlot() { return "Failed to load item by slot"; } +const char* BotDatabase::fail::SaveItemBySlot() { return "Failed to save item by slot"; } +const char* BotDatabase::fail::DeleteItemBySlot() { return "Failed to delete item by slot"; } +const char* BotDatabase::fail::LoadEquipmentColor() { return "Failed to load equipment color"; } +const char* BotDatabase::fail::SaveEquipmentColor() { return "Failed to save equipment color"; } + +/* fail::Bot pet functions */ +const char* BotDatabase::fail::LoadPetIndex() { return "Failed to load pet index"; } +const char* BotDatabase::fail::LoadPetSpellID() { return "Failed to load pet spell id"; } +const char* BotDatabase::fail::LoadPetStats() { return "Failed to load pet stats"; } +const char* BotDatabase::fail::SavePetStats() { return "Failed to save pet stats"; } +const char* BotDatabase::fail::DeletePetStats() { return "Failed to delete pet stats"; } +const char* BotDatabase::fail::LoadPetBuffs() { return "Failed to load pet buffs"; } +const char* BotDatabase::fail::SavePetBuffs() { return "Failed to save pet buffs"; } +const char* BotDatabase::fail::DeletePetBuffs() { return "Failed to delete pet buffs"; } +const char* BotDatabase::fail::LoadPetItems() { return "Failed to load pet items"; } +const char* BotDatabase::fail::SavePetItems() { return "Failed to save pet items"; } +const char* BotDatabase::fail::DeletePetItems() { return "Failed to delete pet items"; } + +/* fail::Bot command functions */ +const char* BotDatabase::fail::LoadInspectMessage() { return "Failed to load inspect message"; } +const char* BotDatabase::fail::SaveInspectMessage() { return "Failed to save inspect message"; } +const char* BotDatabase::fail::DeleteInspectMessage() { return "Failed to delete inspect message"; } +const char* BotDatabase::fail::SaveAllInspectMessages() { return "Failed to save all inspect messages"; } +const char* BotDatabase::fail::DeleteAllInspectMessages() { return "Failed to delete all inspect messages"; } +const char* BotDatabase::fail::SaveAllArmorColorBySlot() { return "Failed to save all armor color by slot"; } +const char* BotDatabase::fail::SaveAllArmorColors() { return "Failed to save all armor colors"; } +const char* BotDatabase::fail::SaveHelmAppearance() { return "Failed to save helm appearance"; } +const char* BotDatabase::fail::SaveAllHelmAppearances() { return "Failed to save all helm appearances"; } +const char* BotDatabase::fail::ToggleHelmAppearance() { return "Failed to save toggle helm appearance"; } +const char* BotDatabase::fail::ToggleAllHelmAppearances() { return "Failed to save toggle all helm appearance"; } +const char* BotDatabase::fail::SaveFollowDistance() { return "Failed to save follow distance"; } +const char* BotDatabase::fail::SaveAllFollowDistances() { return "Failed to save all follow distances"; } +const char* BotDatabase::fail::CreateCloneBot() { return "Failed to create clone bot"; } +const char* BotDatabase::fail::CreateCloneBotInventory() { return "Failed to create clone bot inventory"; } + +/* fail::Bot bot-group functions */ +const char* BotDatabase::fail::QueryBotGroupExistence() { return "Failed to query bot-group existence"; } +const char* BotDatabase::fail::LoadBotGroupIDByBotGroupName() { return "Failed to load bot-group id by bot-group name"; } +const char* BotDatabase::fail::LoadBotGroupIDByLeaderID() { return "Failed to load bot-group id by leader id"; } +const char* BotDatabase::fail::LoadBotGroupIDByMemberID() { return "Failed to load bot-group id by member id"; } +const char* BotDatabase::fail::LoadLeaderIDByBotGroupName() { return "Failed to load leader id by bot-group name"; } +const char* BotDatabase::fail::LoadLeaderIDByBotGroupID() { return "Failed to load leader id by bot-group id"; } +const char* BotDatabase::fail::LoadBotGroupNameByBotGroupID() { return "Failed to load bot-group name by bot-group id"; } +const char* BotDatabase::fail::LoadBotGroupNameByLeaderID() { return "Failed to load bot-group name by leader id"; } +const char* BotDatabase::fail::CreateBotGroup() { return "Failed to create bot-group"; } +const char* BotDatabase::fail::DeleteBotGroup() { return "Failed to delete bot-group"; } +const char* BotDatabase::fail::AddMemberToBotGroup() { return "Failed to add member to bot-group"; } +const char* BotDatabase::fail::RemoveMemberFromBotGroup() { return "Failed to remove member from bot-group"; } +const char* BotDatabase::fail::LoadBotGroupIDForLoadBotGroup() { return "Failed to load bot-group id for load bot-group"; } +const char* BotDatabase::fail::LoadBotGroup() { return "Failed to load bot-group"; } +const char* BotDatabase::fail::LoadBotGroupsListByOwnerID() { return "Failed to load bot-groups list by owner id"; } + +/* fail::Bot group functions */ +const char* BotDatabase::fail::LoadGroupedBotsByGroupID() { return "Failed to load grouped bots by group id"; } + +/* fail::Bot heal rotation functions */ +const char* BotDatabase::fail::LoadHealRotationIDByBotID() { return "Failed to load heal rotation id by bot id"; } +const char* BotDatabase::fail::LoadHealRotation() { return "Failed to load heal rotation"; } +const char* BotDatabase::fail::LoadHealRotationMembers() { return "Failed to load heal rotation members"; } +const char* BotDatabase::fail::LoadHealRotationTargets() { return "Failed to load heal rotation targets"; } +const char* BotDatabase::fail::SaveHealRotation() { return "Failed to save heal rotation"; } +const char* BotDatabase::fail::DeleteHealRotation() { return "Failed to delete heal rotation"; } +const char* BotDatabase::fail::DeleteAllHealRotations() { return "Failed to delete all heal rotations"; } + +/* fail::Bot miscellaneous functions */ + +#endif // BOTS diff --git a/zone/bot_database.h b/zone/bot_database.h new file mode 100644 index 000000000..5ade661c2 --- /dev/null +++ b/zone/bot_database.h @@ -0,0 +1,291 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef BOT_DATABASE_H +#define BOT_DATABASE_H + +#ifdef BOTS + +#include "../common/dbcore.h" +#include "../common/eq_packet_structs.h" + +#include +#include +#include + + +class Bot; +class ItemInst; +class Inventory; +struct BotsAvailableList; + + +class BotDatabase : public DBcore +{ +public: + BotDatabase(); + BotDatabase(const char* host, const char* user, const char* passwd, const char* database, uint32 port); + virtual ~BotDatabase(); + + bool Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port); + + bool LoadBotCommandSettings(std::map>> &bot_command_settings); + + + /* Bot functions */ + bool QueryNameAvailablity(const std::string& bot_name, bool& available_flag); + bool QueryBotCount(const uint32 owner_id, uint32& bot_count); + bool LoadQuestableSpawnCount(const uint32 owner_id, int& spawn_count); + bool LoadBotsList(const uint32 owner_id, std::list& bots_list); + + bool LoadOwnerID(const std::string& bot_name, uint32& owner_id); + bool LoadOwnerID(const uint32 bot_id, uint32& owner_id); + bool LoadBotID(const uint32 owner_id, const std::string& bot_name, uint32& bot_id); + + bool LoadBot(const uint32 bot_id, Bot*& loaded_bot); + bool SaveNewBot(Bot* bot_inst, uint32& bot_id); + bool SaveBot(Bot* bot_inst); + bool DeleteBot(const uint32 bot_id); + + bool LoadBuffs(Bot* bot_inst); + bool SaveBuffs(Bot* bot_inst); + bool DeleteBuffs(const uint32 bot_id); + + bool LoadStance(const uint32 bot_id, int& bot_stance); + bool LoadStance(Bot* bot_inst, bool& stance_flag); + bool SaveStance(const uint32 bot_id, const int bot_stance); + bool SaveStance(Bot* bot_inst); + bool DeleteStance(const uint32 bot_id); + + bool LoadTimers(Bot* bot_inst); + bool SaveTimers(Bot* bot_inst); + bool DeleteTimers(const uint32 bot_id); + + bool LoadGuildMembership(const uint32 bot_id, uint32& guild_id, uint8& guild_rank, std::string& guild_name); + bool SaveGuildMembership(const uint32 bot_id, const uint32 guild_id, const uint8 guild_rank); + bool DeleteGuildMembership(const uint32 bot_id); + + + /* Bot inventory functions */ + bool QueryInventoryCount(const uint32 bot_id, uint32& item_count); + + bool LoadItems(const uint32 bot_id, Inventory &inventory_inst); + bool SaveItems(Bot* bot_inst); + bool DeleteItems(const uint32 bot_id); + + bool LoadItemBySlot(Bot* bot_inst); + bool LoadItemBySlot(const uint32 bot_id, const uint32 slot_id, uint32& item_id); + bool SaveItemBySlot(Bot* bot_inst, const uint32 slot_id, const ItemInst* item_inst); + bool DeleteItemBySlot(const uint32 bot_id, const uint32 slot_id); + + bool LoadEquipmentColor(const uint32 bot_id, const uint8 material_slot_id, uint32& rgb); + bool SaveEquipmentColor(const uint32 bot_id, const int16 slot_id, const uint32 rgb); + + + /* Bot pet functions */ + bool LoadPetIndex(const uint32 bot_id, uint32& pet_index); + bool LoadPetSpellID(const uint32 bot_id, uint32& pet_spell_id); + + bool LoadPetStats(const uint32 bot_id, std::string& pet_name, uint32& pet_mana, uint32& pet_hp, uint32& pet_spell_id); + bool SavePetStats(const uint32 bot_id, const std::string& pet_name, const uint32 pet_mana, const uint32 pet_hp, const uint32 pet_spell_id); + bool DeletePetStats(const uint32 bot_id); + + bool LoadPetBuffs(const uint32 bot_id, SpellBuff_Struct* pet_buffs); + bool SavePetBuffs(const uint32 bot_id, const SpellBuff_Struct* pet_buffs, bool delete_flag = false); + bool DeletePetBuffs(const uint32 bot_id); + + bool LoadPetItems(const uint32 bot_id, uint32* pet_items); + bool SavePetItems(const uint32 bot_id, const uint32* pet_items, bool delete_flag = false); + bool DeletePetItems(const uint32 bot_id); + + + /* Bot command functions */ + bool LoadInspectMessage(const uint32 bot_id, InspectMessage_Struct& inspect_message); + bool SaveInspectMessage(const uint32 bot_id, const InspectMessage_Struct& inspect_message); + bool DeleteInspectMessage(const uint32 bot_id); + + bool SaveAllInspectMessages(const uint32 owner_id, const InspectMessage_Struct& inspect_message); + bool DeleteAllInspectMessages(const uint32 owner_id); + + bool SaveAllArmorColorBySlot(const uint32 owner_id, const int16 slot_id, const uint32 rgb_value); + bool SaveAllArmorColors(const uint32 owner_id, const uint32 rgb_value); + + bool SaveHelmAppearance(const uint32 owner_id, const uint32 bot_id, const bool show_flag = true); + bool SaveAllHelmAppearances(const uint32 owner_id, const bool show_flag = true); + + bool ToggleHelmAppearance(const uint32 owner_id, const uint32 bot_id); + bool ToggleAllHelmAppearances(const uint32 owner_id); + + bool SaveFollowDistance(const uint32 owner_id, const uint32 bot_id, const uint32 follow_distance); + bool SaveAllFollowDistances(const uint32 owner_id, const uint32 follow_distance); + + bool CreateCloneBot(const uint32 owner_id, const uint32 bot_id, const std::string& clone_name, uint32& clone_id); + bool CreateCloneBotInventory(const uint32 owner_id, const uint32 bot_id, const uint32 clone_id); + + + /* Bot bot-group functions */ + bool QueryBotGroupExistence(const std::string& botgroup_name, bool& extant_flag); + + bool LoadBotGroupIDByBotGroupName(const std::string& botgroup_name, uint32& botgroup_id); + bool LoadBotGroupIDByLeaderID(const uint32 leader_id, uint32& botgroup_id); + bool LoadBotGroupIDByMemberID(const uint32 member_id, uint32& botgroup_id); + + bool LoadLeaderIDByBotGroupName(const std::string& botgroup_name, uint32& leader_id); + bool LoadLeaderIDByBotGroupID(const uint32 botgroup_id, uint32& leader_id); + + bool LoadBotGroupNameByBotGroupID(const uint32 botgroup_id, std::string& botgroup_name); + bool LoadBotGroupNameByLeaderID(const uint32 leader_id, std::string& botgroup_name); + + bool CreateBotGroup(const std::string& botgroup_name, const uint32 leader_id); + bool DeleteBotGroup(const uint32 leader_id); + bool AddMemberToBotGroup(const uint32 leader_id, const uint32 member_id); + bool RemoveMemberFromBotGroup(const uint32 member_id); + + bool LoadBotGroupIDForLoadBotGroup(const uint32 owner_id, const std::string& botgroup_name, uint32& botgroup_id); + bool LoadBotGroup(const std::string& botgroup_name, std::map>& member_list); + + bool LoadBotGroupsListByOwnerID(const uint32 owner_id, std::list>& botgroups_list); + + + /* Bot group functions */ + bool LoadGroupedBotsByGroupID(const uint32 group_id, std::list& group_list); + + + /* Bot heal rotation functions */ + bool LoadHealRotationIDByBotID(const uint32 bot_id, uint32& hr_index); + + bool LoadHealRotation(Bot* hr_member, std::list& member_list, std::list& target_list, bool& load_flag, bool& member_fail, bool& target_fail); + bool LoadHealRotationMembers(const uint32 hr_index, std::list& member_list); + bool LoadHealRotationTargets(const uint32 hr_index, std::list& target_list); + bool SaveHealRotation(Bot* hr_member, bool& member_fail, bool& target_fail); + bool DeleteHealRotation(const uint32 creator_id); + + bool DeleteAllHealRotations(const uint32 owner_id); + + /* Bot miscellaneous functions */ + + + class fail { + public: + /* fail::Bot functions */ + static const char* QueryNameAvailablity(); + static const char* QueryBotCount(); + static const char* LoadQuestableSpawnCount(); + static const char* LoadBotsList(); + static const char* LoadOwnerID(); + static const char* LoadBotID(); + static const char* LoadBot(); + static const char* SaveNewBot(); + static const char* SaveBot(); + static const char* DeleteBot(); + static const char* LoadBuffs(); + static const char* SaveBuffs(); + static const char* DeleteBuffs(); + static const char* LoadStance(); + static const char* SaveStance(); + static const char* DeleteStance(); + static const char* LoadTimers(); + static const char* SaveTimers(); + static const char* DeleteTimers(); + static const char* LoadGuildMembership(); + static const char* SaveGuildMembership(); + static const char* DeleteGuildMembership(); + + /* fail::Bot inventory functions */ + static const char* QueryInventoryCount(); + static const char* LoadItems(); + static const char* SaveItems(); + static const char* DeleteItems(); + static const char* LoadItemBySlot(); + static const char* SaveItemBySlot(); + static const char* DeleteItemBySlot(); + static const char* LoadEquipmentColor(); + static const char* SaveEquipmentColor(); + + /* fail::Bot pet functions */ + static const char* LoadPetIndex(); + static const char* LoadPetSpellID(); + static const char* LoadPetStats(); + static const char* SavePetStats(); + static const char* DeletePetStats(); + static const char* LoadPetBuffs(); + static const char* SavePetBuffs(); + static const char* DeletePetBuffs(); + static const char* LoadPetItems(); + static const char* SavePetItems(); + static const char* DeletePetItems(); + + /* fail::Bot command functions */ + static const char* LoadInspectMessage(); + static const char* SaveInspectMessage(); + static const char* DeleteInspectMessage(); + static const char* SaveAllInspectMessages(); + static const char* DeleteAllInspectMessages(); + static const char* SaveAllArmorColorBySlot(); + static const char* SaveAllArmorColors(); + static const char* SaveHelmAppearance(); + static const char* SaveAllHelmAppearances(); + static const char* ToggleHelmAppearance(); + static const char* ToggleAllHelmAppearances(); + static const char* SaveFollowDistance(); + static const char* SaveAllFollowDistances(); + static const char* CreateCloneBot(); + static const char* CreateCloneBotInventory(); + + /* fail::Bot bot-group functions */ + static const char* QueryBotGroupExistence(); + static const char* LoadBotGroupIDByBotGroupName(); + static const char* LoadBotGroupIDByLeaderID(); + static const char* LoadBotGroupIDByMemberID(); + static const char* LoadLeaderIDByBotGroupName(); + static const char* LoadLeaderIDByBotGroupID(); + static const char* LoadBotGroupNameByBotGroupID(); + static const char* LoadBotGroupNameByLeaderID(); + static const char* CreateBotGroup(); + static const char* DeleteBotGroup(); + static const char* AddMemberToBotGroup(); + static const char* RemoveMemberFromBotGroup(); + static const char* LoadBotGroupIDForLoadBotGroup(); + static const char* LoadBotGroup(); + static const char* LoadBotGroupsListByOwnerID(); + + /* fail::Bot group functions */ + static const char* LoadGroupedBotsByGroupID(); + + /* fail::Bot heal rotation functions */ + static const char* LoadHealRotationIDByBotID(); + static const char* LoadHealRotation(); + static const char* LoadHealRotationMembers(); + static const char* LoadHealRotationTargets(); + static const char* SaveHealRotation(); + static const char* DeleteHealRotation(); + static const char* DeleteAllHealRotations(); + + /* fail::Bot miscellaneous functions */ + }; + + private: + std::string query; +}; + +extern BotDatabase botdb; + +#endif + +#endif // BOTS diff --git a/zone/bot_structs.h b/zone/bot_structs.h index 09140ae60..996fbff41 100644 --- a/zone/bot_structs.h +++ b/zone/bot_structs.h @@ -1,3 +1,21 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #ifndef BOT_STRUCTS #define BOT_STRUCTS @@ -8,11 +26,12 @@ #include struct BotsAvailableList { - uint32 BotID; - char BotName[64]; - uint16 BotClass; - uint8 BotLevel; - uint16 BotRace; + uint32 ID; + char Name[64]; + uint16 Class; + uint8 Level; + uint16 Race; + uint8 Gender; }; struct BotGroup { diff --git a/zone/botspellsai.cpp b/zone/botspellsai.cpp index fcbb052fe..a35760535 100644 --- a/zone/botspellsai.cpp +++ b/zone/botspellsai.cpp @@ -1,8 +1,34 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + #ifdef BOTS #include "bot.h" #include "../common/string_util.h" +#if EQDEBUG >= 12 + #define BotAI_DEBUG_Spells 25 +#elif EQDEBUG >= 9 + #define BotAI_DEBUG_Spells 10 +#else + #define BotAI_DEBUG_Spells -1 +#endif + bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { if (!tar) { @@ -75,7 +101,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { MakeAnyLenString(&gmsg, "Attempting to mez %s.", addMob->GetCleanName()); - if(gmsg && GetGroupMessagesOn()) + if(gmsg) BotGroupSay(this, gmsg); } } @@ -262,7 +288,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { } } - if(gmsg && GetGroupMessagesOn()) + if(gmsg) BotGroupSay(this, gmsg); } } @@ -793,7 +819,7 @@ bool Bot::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { MakeAnyLenString(&gmsg, "Attempting to slow %s.", tar->GetCleanName()); - if(gmsg && GetGroupMessagesOn()) + if(gmsg) BotGroupSay(this, gmsg); } } @@ -883,7 +909,7 @@ bool Bot::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain int32 hasMana = GetMana(); // Allow bots to cast buff spells even if they are out of mana - if(RuleB(Bots, BotFinishBuffing)) { + if(RuleB(Bots, FinishBuffing)) { if(manaCost > hasMana) { // Let's have the bots complete the buff time process if(AIspells[i].type & SpellType_Buff) { @@ -977,8 +1003,8 @@ bool Bot::AI_IdleCastCheck() { bool result = false; if (AIautocastspell_timer->Check(false)) { -#if MobAI_DEBUG_Spells >= 25 - std::cout << "Non-Engaged autocast check triggered: " << this->GetCleanName() << std::endl; // cout undefine [CODEBUG] +#if BotAI_DEBUG_Spells >= 25 + Log.Out(Logs::Detail, Logs::AI, "Bot Non-Engaged autocast check triggered: %s", this->GetCleanName()); #endif AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. @@ -1025,7 +1051,7 @@ bool Bot::AI_IdleCastCheck() { // bard bots if(!AICastSpell(this, 100, SpellType_Cure)) { if(!AICastSpell(this, 100, SpellType_Heal)) { - if((!RuleB(Bots, BotBardUseOutOfCombatSongs) || !GetBardUseOutOfCombatSongs()) || !AICastSpell(this, 100, SpellType_Buff)) { // skips if rule is false + if((!RuleB(Bots, BotBardUseOutOfCombatSongs) || !GetAltOutOfCombatBehavior()) || !AICastSpell(this, 100, SpellType_Buff)) { // skips if rule is false if(!AICastSpell(this, 100, SpellType_InCombatBuff)) { // this tries to keep some combat buffs on the group until engaged code can pick up the buffing // } @@ -1261,7 +1287,7 @@ bool Bot::AIHealRotation(Mob* tar, bool useFastHeals) { return false; } - if(!AI_HasSpells()) + if (!AI_HasSpells()) return false; if(tar->GetAppearance() == eaDead) { @@ -1302,12 +1328,20 @@ bool Bot::AIHealRotation(Mob* tar, bool useFastHeals) { } } +#if BotAI_DEBUG_Spells >= 10 + Log.Out(Logs::Detail, Logs::AI, "Bot::AIHealRotation: heal spellid = %u, fastheals = %c, casterlevel = %u", + botSpell.SpellId, ((useFastHeals) ? ('T') : ('F')), GetLevel()); +#endif +#if BotAI_DEBUG_Spells >= 25 + Log.Out(Logs::Detail, Logs::AI, "Bot::AIHealRotation: target = %s, current_time = %u, donthealmebefore = %u", tar->GetCleanName(), Timer::GetCurrentTime(), tar->DontHealMeBefore()); +#endif + // If there is still no spell id, then there isn't going to be one so we are done - if(botSpell.SpellId == 0) + if (botSpell.SpellId == 0) return false; // Can we cast this spell on this target? - if(!(spells[botSpell.SpellId].targettype==ST_GroupTeleport || spells[botSpell.SpellId].targettype == ST_Target || tar == this) + if (!(spells[botSpell.SpellId].targettype == ST_GroupTeleport || spells[botSpell.SpellId].targettype == ST_Target || tar == this) && !(tar->CanBuffStack(botSpell.SpellId, botLevel, true) >= 0)) return false; diff --git a/zone/client.cpp b/zone/client.cpp index 8246e12a8..59998bfdb 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -44,6 +44,10 @@ extern volatile bool RunLoops; #include "zonedb.h" #include "petitions.h" #include "command.h" +#include "water_map.h" +#ifdef BOTS +#include "bot_command.h" +#endif #include "string_ids.h" #include "guild_mgr.h" @@ -53,7 +57,7 @@ extern volatile bool RunLoops; extern QueryServ* QServ; extern EntityList entity_list; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern uint32 numclients; extern PetitionList petition_list; @@ -97,7 +101,7 @@ Client::Client(EQStreamInterface* ieqs) 0, // Drakkin Heritage 0, // Drakkin Tattoo 0, // Drakkin Details - 0, // Armor Tint + EQEmu::TintProfile(), // Armor Tint 0xff, // AA Title 0, // see_invis 0, // see_invis_undead @@ -107,16 +111,20 @@ Client::Client(EQStreamInterface* ieqs) 0, 0, // qglobal 0, // maxlevel - 0 // scalerate - + 0, // scalerate + 0, + 0, + 0, + 0, + 0 ), //these must be listed in the order they appear in client.h position_timer(250), - hpupdate_timer(1800), + hpupdate_timer(2000), camp_timer(29000), process_timer(100), stamina_timer(40000), - zoneinpacket_timer(3000), + zoneinpacket_timer(1000), linkdead_timer(RuleI(Zone,ClientLinkdeadMS)), dead_timer(2000), global_channel_timer(1000), @@ -148,7 +156,8 @@ Client::Client(EQStreamInterface* ieqs) m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f), m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f), - m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f) + m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f), + last_region_type(RegionTypeUnsupported) { for(int cf=0; cf < _FilterCount; cf++) ClientFilters[cf] = FilterShow; @@ -172,7 +181,6 @@ Client::Client(EQStreamInterface* ieqs) admin = 0; lsaccountid = 0; shield_target = nullptr; - SQL_log = nullptr; guild_id = GUILD_NONE; guildrank = 0; GuildBanker = false; @@ -194,6 +202,7 @@ Client::Client(EQStreamInterface* ieqs) SetTarget(0); auto_attack = false; auto_fire = false; + runmode = false; linkdead_timer.Disable(); zonesummon_id = 0; zonesummon_ignorerestrictions = 0; @@ -204,6 +213,7 @@ Client::Client(EQStreamInterface* ieqs) npclevel = 0; pQueuedSaveWorkID = 0; position_timer_counter = 0; + position_update_same_count = 0; fishing_timer.Disable(); shield_timer.Disable(); dead_timer.Disable(); @@ -249,7 +259,7 @@ Client::Client(EQStreamInterface* ieqs) GlobalChatLimiterTimer = new Timer(RuleI(Chat, IntervalDurationMS)); AttemptedMessages = 0; TotalKarma = 0; - m_ClientVersion = ClientVersion::Unknown; + m_ClientVersion = EQEmu::versions::ClientVersion::Unknown; m_ClientVersionBit = 0; AggroCount = 0; RestRegenHP = 0; @@ -295,6 +305,7 @@ Client::Client(EQStreamInterface* ieqs) XTargets[i].Type = Auto; XTargets[i].ID = 0; XTargets[i].Name[0] = 0; + XTargets[i].dirty = false; } MaxXTargets = 5; XTargetAutoAddHaters = true; @@ -365,7 +376,7 @@ Client::~Client() { GetTarget()->IsTargeted(-1); //if we are in a group and we are not zoning, force leave the group - if(isgrouped && !zoning && ZoneLoaded) + if(isgrouped && !zoning && is_zone_loaded) LeaveGroup(); UpdateWho(2); @@ -415,7 +426,7 @@ void Client::SendZoneInPackets() { ////////////////////////////////////////////////////// // Spawn Appearance Packet - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer; sa->type = AT_SpawnID; // Is 0x10 used to set the player id? sa->parameter = GetID(); // Four bytes for this parameter... @@ -430,12 +441,13 @@ void Client::SendZoneInPackets() outapp->priority = 6; 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); //Send AA Exp packet: if (GetLevel() >= 51) - SendAAStats(); + SendAlternateAdvancementStats(); // Send exp packets outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct)); @@ -452,7 +464,7 @@ void Client::SendZoneInPackets() } safe_delete(outapp); - SendAATimers(); + SendAlternateAdvancementTimers(); outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct)); ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer; @@ -476,7 +488,7 @@ void Client::SendZoneInPackets() void Client::SendLogoutPackets() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_CancelTrade, sizeof(CancelTrade_Struct)); + auto outapp = new EQApplicationPacket(OP_CancelTrade, sizeof(CancelTrade_Struct)); CancelTrade_Struct* ct = (CancelTrade_Struct*) outapp->pBuffer; ct->fromid = GetID(); ct->action = groupActUpdate; @@ -519,46 +531,47 @@ void Client::ReportConnectingState() { }; } -bool Client::SaveAA(){ - int first_entry = 0; - std::string rquery; - /* Save Player AA */ +bool Client::SaveAA() { + std::string iquery; int spentpoints = 0; - for (int a = 0; a < MAX_PP_AA_ARRAY; a++) { - uint32 points = aa[a]->value; - if (points > HIGHEST_AA_VALUE) { - aa[a]->value = HIGHEST_AA_VALUE; - points = HIGHEST_AA_VALUE; - } - if (points > 0) { - SendAA_Struct* curAA = zone->FindAA(aa[a]->AA - aa[a]->value + 1); - if (curAA) { - for (int rank = 0; rank::iterator RequiredLevel = AARequiredLevelAndCost.find(aa[a]->AA - aa[a]->value + 1 + rank); - if (RequiredLevel != AARequiredLevelAndCost.end()) { - spentpoints += RequiredLevel->second.Cost; - } - else - spentpoints += (curAA->cost + (curAA->cost_inc * rank)); - } + int i = 0; + for(auto &rank : aa_ranks) { + AA::Ability *ability = zone->GetAlternateAdvancementAbility(rank.first); + if(!ability) + continue; + + if(rank.second.first > 0) { + AA::Rank *r = ability->GetRankByPointsSpent(rank.second.first); + + if(!r) + continue; + + spentpoints += r->total_cost; + + if(i == 0) { + iquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value, charges)" + " VALUES (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second); + } else { + iquery += StringFormat(", (%u, %u, %u, %u)", character_id, ability->first_rank_id, rank.second.first, rank.second.second); } + i++; } } + m_pp.aapoints_spent = spentpoints + m_epp.expended_aa; - for (int a = 0; a < MAX_PP_AA_ARRAY; a++) { - if (aa[a]->AA > 0 && aa[a]->value){ - if (first_entry != 1){ - rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, slot, aa_id, aa_value)" - " VALUES (%u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value); - first_entry = 1; - } - rquery = rquery + StringFormat(", (%u, %u, %u, %u)", character_id, a, aa[a]->AA, aa[a]->value); - } + + if(iquery.length() > 0) { + database.QueryDatabase(iquery); } - auto results = database.QueryDatabase(rquery); + return true; } +void Client::RemoveExpendedAA(int aa_id) +{ + database.QueryDatabase(StringFormat("DELETE from `character_alternate_abilities` WHERE `id` = %d and `aa_id` = %d", character_id, aa_id)); +} + bool Client::Save(uint8 iCommitNow) { if(!ClientDataLoaded()) return false; @@ -585,10 +598,9 @@ bool Client::Save(uint8 iCommitNow) { database.SaveCharacterCurrency(CharacterID(), &m_pp); /* Save Current Bind Points */ - auto regularBindPosition = glm::vec4(m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, 0.0f); - auto homeBindPosition = glm::vec4(m_pp.binds[4].x, m_pp.binds[4].y, m_pp.binds[4].z, 0.0f); - database.SaveCharacterBindPoint(CharacterID(), m_pp.binds[0].zoneId, m_pp.binds[0].instance_id, regularBindPosition, 0); /* Regular bind */ - database.SaveCharacterBindPoint(CharacterID(), m_pp.binds[4].zoneId, m_pp.binds[4].instance_id, homeBindPosition, 1); /* Home Bind */ + for (int i = 0; i < 5; i++) + if (m_pp.binds[i].zoneId) + database.SaveCharacterBindPoint(CharacterID(), m_pp.binds[i], i); /* Save Character Buffs */ database.SaveBuffs(this); @@ -640,6 +652,17 @@ bool Client::Save(uint8 iCommitNow) { m_pp.hunger_level = EQEmu::Clamp(m_pp.hunger_level, 0, 50000); m_pp.thirst_level = EQEmu::Clamp(m_pp.thirst_level, 0, 50000); + + // perform snapshot before SaveCharacterData() so that m_epp will contain the updated time + if (RuleB(Character, ActiveInvSnapshots) && time(nullptr) >= GetNextInvSnapshotTime()) { + if (database.SaveCharacterInventorySnapshot(CharacterID())) { + SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM)); + } + else { + SetNextInvSnapshot(RuleI(Character, InvSnapshotMinRetryM)); + } + } + database.SaveCharacterData(this->CharacterID(), this->AccountID(), &m_pp, &m_epp); /* Save Character Data */ return true; @@ -667,7 +690,7 @@ bool Client::AddPacket(const EQApplicationPacket *pApp, bool bAckreq) { //drop the packet because it will never get sent. return(false); } - CLIENTPACKET *c = new CLIENTPACKET; + auto c = new CLIENTPACKET; c->ack_req = bAckreq; c->app = pApp->Copy(); @@ -684,7 +707,7 @@ bool Client::AddPacket(EQApplicationPacket** pApp, bool bAckreq) { //drop the packet because it will never get sent. return(false); } - CLIENTPACKET *c = new CLIENTPACKET; + auto c = new CLIENTPACKET; c->ack_req = bAckreq; c->app = *pApp; @@ -805,7 +828,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s /* Logs Player Chat */ if (RuleB(QueryServ, PlayerLogChat)) { - ServerPacket* pack = new ServerPacket(ServerOP_Speech, sizeof(Server_Speech_Struct) + strlen(message) + 1); + auto pack = new ServerPacket(ServerOP_Speech, sizeof(Server_Speech_Struct) + strlen(message) + 1); Server_Speech_Struct* sem = (Server_Speech_Struct*) pack->pBuffer; if(chan_num == 0) @@ -870,7 +893,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s } case 3: { /* Shout */ Mob *sender = this; - if (GetPet() && GetPet()->FindType(SE_VoiceGraft)) + if (GetPet() && GetTarget() == GetPet() && GetPet()->FindType(SE_VoiceGraft)) sender = GetPet(); entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message); @@ -908,7 +931,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s else if(!RuleB(Chat, ServerWideAuction)) { Mob *sender = this; - if (GetPet() && GetPet()->FindType(SE_VoiceGraft)) + if (GetPet() && GetTarget() == GetPet() && GetPet()->FindType(SE_VoiceGraft)) sender = GetPet(); entity_list.ChannelMessage(sender, chan_num, language, message); @@ -955,7 +978,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s { Mob *sender = this; - if (GetPet() && GetPet()->FindType(SE_VoiceGraft)) + if (GetPet() && GetTarget() == GetPet() && GetPet()->FindType(SE_VoiceGraft)) sender = GetPet(); entity_list.ChannelMessage(sender, chan_num, language, message); @@ -1034,8 +1057,26 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s break; } +#ifdef BOTS + if (message[0] == BOT_COMMAND_CHAR) { + if (bot_command_dispatch(this, message) == -2) { + if (parse->PlayerHasQuestSub(EVENT_COMMAND)) { + int i = parse->EventPlayer(EVENT_COMMAND, this, message, 0); + if (i == 0 && !RuleB(Chat, SuppressCommandErrors)) { + Message(13, "Bot command '%s' not recognized.", message); + } + } + else { + if (!RuleB(Chat, SuppressCommandErrors)) + Message(13, "Bot command '%s' not recognized.", message); + } + } + break; + } +#endif + Mob* sender = this; - if (GetPet() && GetPet()->FindType(SE_VoiceGraft)) + if (GetPet() && GetTarget() == GetPet() && GetPet()->FindType(SE_VoiceGraft)) sender = GetPet(); entity_list.ChannelMessage(sender, chan_num, language, lang_skill, message); @@ -1047,12 +1088,12 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s if(quest_manager.ProximitySayInUse()) entity_list.ProcessProximitySay(message, this, language); - if (GetTarget() != 0 && GetTarget()->IsNPC()) { + if (GetTarget() != 0 && GetTarget()->IsNPC() && + !IsInvisible(GetTarget())) { if(!GetTarget()->CastToNPC()->IsEngaged()) { CheckLDoNHail(GetTarget()); CheckEmoteHail(GetTarget(), message); - if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= 200) { NPC *tar = GetTarget()->CastToNPC(); parse->EventNPC(EVENT_SAY, tar->CastToNPC(), this, message, language); @@ -1089,7 +1130,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s if (msg_len > 512) message[512] = '\0'; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Emote, 4 + msg_len + strlen(GetName()) + 2); + auto outapp = new EQApplicationPacket(OP_Emote, 4 + msg_len + strlen(GetName()) + 2); Emote_Struct* es = (Emote_Struct*)outapp->pBuffer; char *Buffer = (char *)es; Buffer += 4; @@ -1184,7 +1225,7 @@ void Client::Message(uint32 type, const char* message, ...) { return; va_list argptr; - char *buffer = new char[4096]; + auto buffer = new char[4096]; va_start(argptr, message); vsnprintf(buffer, 4096, message, argptr); va_end(argptr); @@ -1197,7 +1238,7 @@ void Client::Message(uint32 type, const char* message, ...) { //len = 4096 - sizeof(SpecialMesg_Struct); uint32 len_packet = sizeof(SpecialMesg_Struct)+len; - EQApplicationPacket* app = new EQApplicationPacket(OP_SpecialMesg, len_packet); + auto app = new EQApplicationPacket(OP_SpecialMesg, len_packet); SpecialMesg_Struct* sm=(SpecialMesg_Struct*)app->pBuffer; sm->header[0] = 0x00; // Header used for #emote style messages.. sm->header[1] = 0x00; // Play around with these to see other types @@ -1228,7 +1269,7 @@ void Client::QuestJournalledMessage(const char *npcname, const char* message) { snprintf(OutMessage, MaxMessageLength, "%s", message); OutMessage[MaxMessageLength]='\0'; uint32 len_packet = sizeof(SpecialMesg_Struct) + strlen(OutNPCName) + strlen(OutMessage); - EQApplicationPacket* app = new EQApplicationPacket(OP_SpecialMesg, len_packet); + auto app = new EQApplicationPacket(OP_SpecialMesg, len_packet); SpecialMesg_Struct* sm=(SpecialMesg_Struct*)app->pBuffer; sm->header[0] = 0; @@ -1383,7 +1424,7 @@ bool Client::UpdateLDoNPoints(int32 points, uint32 theme) } m_pp.ldon_points_available += points; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventurePointsUpdate, sizeof(AdventurePoints_Update_Struct)); + auto outapp = new EQApplicationPacket(OP_AdventurePointsUpdate, sizeof(AdventurePoints_Update_Struct)); AdventurePoints_Update_Struct* apus = (AdventurePoints_Update_Struct*)outapp->pBuffer; apus->ldon_available_points = m_pp.ldon_points_available; apus->ldon_guk_points = m_pp.ldon_points_guk; @@ -1399,14 +1440,14 @@ bool Client::UpdateLDoNPoints(int32 points, uint32 theme) return(false); } -void Client::SetSkill(SkillUseTypes skillid, uint16 value) { - if (skillid > HIGHEST_SKILL) +void Client::SetSkill(EQEmu::skills::SkillType skillid, uint16 value) { + if (skillid > EQEmu::skills::HIGHEST_SKILL) return; m_pp.skills[skillid] = value; // We need to be able to #setskill 254 and 255 to reset skills database.SaveCharacterSkill(this->CharacterID(), skillid, value); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct)); SkillUpdate_Struct* skill = (SkillUpdate_Struct*)outapp->pBuffer; skill->skillId=skillid; skill->value=value; @@ -1426,7 +1467,7 @@ void Client::IncreaseLanguageSkill(int skill_id, int value) { database.SaveCharacterLanguage(this->CharacterID(), skill_id, m_pp.languages[skill_id]); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct)); SkillUpdate_Struct* skill = (SkillUpdate_Struct*)outapp->pBuffer; skill->skillId = 100 + skill_id; skill->value = m_pp.languages[skill_id]; @@ -1436,8 +1477,8 @@ void Client::IncreaseLanguageSkill(int skill_id, int value) { Message_StringID( MT_Skills, LANG_SKILL_IMPROVED ); //Notify client } -void Client::AddSkill(SkillUseTypes skillid, uint16 value) { - if (skillid > HIGHEST_SKILL) +void Client::AddSkill(EQEmu::skills::SkillType skillid, uint16 value) { + if (skillid > EQEmu::skills::HIGHEST_SKILL) return; value = GetRawSkill(skillid) + value; uint16 max = GetMaxSkillAfterSpecializationRules(skillid, MaxSkill(skillid)); @@ -1447,7 +1488,7 @@ void Client::AddSkill(SkillUseTypes skillid, uint16 value) { } void Client::SendSound(){//Makes a sound. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Sound, 68); + auto outapp = new EQApplicationPacket(OP_Sound, 68); unsigned char x[68]; memset(x, 0, 68); x[0]=0x22; @@ -1473,7 +1514,7 @@ void Client::UpdateWho(uint8 remove) { return; if (!worldserver.Connected()) return; - ServerPacket* pack = new ServerPacket(ServerOP_ClientList, sizeof(ServerClientList_Struct)); + auto pack = new ServerPacket(ServerOP_ClientList, sizeof(ServerClientList_Struct)); ServerClientList_Struct* scl = (ServerClientList_Struct*) pack->pBuffer; scl->remove = remove; scl->wid = this->GetWID(); @@ -1499,7 +1540,7 @@ void Client::UpdateWho(uint8 remove) { else if (m_pp.anon >= 2) scl->anon = 2; - scl->ClientVersion = static_cast(GetClientVersion()); + scl->ClientVersion = static_cast(ClientVersion()); scl->tellsoff = tellsoff; scl->guild_id = guild_id; scl->LFG = LFG; @@ -1519,7 +1560,7 @@ void Client::WhoAll(Who_All_Struct* whom) { if (!worldserver.Connected()) Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_Who, sizeof(ServerWhoAll_Struct)); + auto pack = new ServerPacket(ServerOP_Who, sizeof(ServerWhoAll_Struct)); ServerWhoAll_Struct* whoall = (ServerWhoAll_Struct*) pack->pBuffer; whoall->admin = this->Admin(); whoall->fromid=this->GetID(); @@ -1540,7 +1581,8 @@ void Client::FriendsWho(char *FriendsString) { if (!worldserver.Connected()) Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_FriendsWho, sizeof(ServerFriendsWho_Struct) + strlen(FriendsString)); + auto pack = + new ServerPacket(ServerOP_FriendsWho, sizeof(ServerFriendsWho_Struct) + strlen(FriendsString)); ServerFriendsWho_Struct* FriendsWho = (ServerFriendsWho_Struct*) pack->pBuffer; FriendsWho->FromID = this->GetID(); strcpy(FriendsWho->FromName, GetName()); @@ -1575,7 +1617,7 @@ void Client::SetStats(uint8 type,int16 set_val){ printf("Error in Client::IncStats, received invalid type of: %i\n",type); return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_IncreaseStats,sizeof(IncreaseStat_Struct)); + auto outapp = new EQApplicationPacket(OP_IncreaseStats, sizeof(IncreaseStat_Struct)); IncreaseStat_Struct* iss=(IncreaseStat_Struct*)outapp->pBuffer; switch(type){ case STAT_STR: @@ -1658,7 +1700,7 @@ void Client::IncStats(uint8 type,int16 increase_val){ printf("Error in Client::IncStats, received invalid type of: %i\n",type); return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_IncreaseStats,sizeof(IncreaseStat_Struct)); + auto outapp = new EQApplicationPacket(OP_IncreaseStats, sizeof(IncreaseStat_Struct)); IncreaseStat_Struct* iss=(IncreaseStat_Struct*)outapp->pBuffer; switch(type){ case STAT_STR: @@ -1752,23 +1794,22 @@ const int32& Client::SetMana(int32 amount) { } void Client::SendManaUpdatePacket() { - if (!Connected() || IsCasting()) + if (!Connected()) return; - if (GetClientVersion() >= ClientVersion::SoD) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { SendManaUpdate(); SendEnduranceUpdate(); } if (last_reported_mana != cur_mana || last_reported_endur != cur_end) { - - - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ManaChange, sizeof(ManaChange_Struct)); + auto outapp = new EQApplicationPacket(OP_ManaChange, sizeof(ManaChange_Struct)); ManaChange_Struct* manachange = (ManaChange_Struct*)outapp->pBuffer; manachange->new_mana = cur_mana; manachange->stamina = cur_end; - manachange->spell_id = casting_spell_id; //always going to be 0... since we check IsCasting() + manachange->spell_id = casting_spell_id; + manachange->keepcasting = 1; outapp->priority = 6; QueuePacket(outapp); safe_delete(outapp); @@ -1778,7 +1819,8 @@ void Client::SendManaUpdatePacket() { if(g) { outapp = new EQApplicationPacket(OP_MobManaUpdate, sizeof(MobManaUpdate_Struct)); - EQApplicationPacket *outapp2 = new EQApplicationPacket(OP_MobEnduranceUpdate, sizeof(MobEnduranceUpdate_Struct)); + auto outapp2 = + new EQApplicationPacket(OP_MobEnduranceUpdate, sizeof(MobEnduranceUpdate_Struct)); MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp->pBuffer; MobEnduranceUpdate_Struct *meus = (MobEnduranceUpdate_Struct *)outapp2->pBuffer; @@ -1790,7 +1832,7 @@ void Client::SendManaUpdatePacket() { for(int i = 0; i < MAX_GROUP_MEMBERS; ++i) - if(g->members[i] && g->members[i]->IsClient() && (g->members[i] != this) && (g->members[i]->CastToClient()->GetClientVersion() >= ClientVersion::SoD)) + if (g->members[i] && g->members[i]->IsClient() && (g->members[i] != this) && (g->members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD)) { g->members[i]->CastToClient()->QueuePacket(outapp); g->members[i]->CastToClient()->QueuePacket(outapp2); @@ -1809,7 +1851,7 @@ void Client::SendManaUpdatePacket() { // sends mana update to self void Client::SendManaUpdate() { - EQApplicationPacket* mana_app = new EQApplicationPacket(OP_ManaUpdate,sizeof(ManaUpdate_Struct)); + auto mana_app = new EQApplicationPacket(OP_ManaUpdate, sizeof(ManaUpdate_Struct)); ManaUpdate_Struct* mus = (ManaUpdate_Struct*)mana_app->pBuffer; mus->cur_mana = GetMana(); mus->max_mana = GetMaxMana(); @@ -1822,7 +1864,7 @@ void Client::SendManaUpdate() // sends endurance update to self void Client::SendEnduranceUpdate() { - EQApplicationPacket* end_app = new EQApplicationPacket(OP_EnduranceUpdate,sizeof(EnduranceUpdate_Struct)); + auto end_app = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct)); EnduranceUpdate_Struct* eus = (EnduranceUpdate_Struct*)end_app->pBuffer; eus->cur_end = GetEndurance(); eus->max_end = GetMaxEndurance(); @@ -1868,7 +1910,7 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) UpdateEquipmentLight(); UpdateActiveLight(); - ns->spawn.light = m_Light.Type.Active; + ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive]; } bool Client::GMHideMe(Client* client) { @@ -1895,7 +1937,7 @@ void Client::Stand() { void Client::ChangeLastName(const char* in_lastname) { memset(m_pp.last_name, 0, sizeof(m_pp.last_name)); strn0cpy(m_pp.last_name, in_lastname, sizeof(m_pp.last_name)); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct)); + auto outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct)); GMLastName_Struct* gmn = (GMLastName_Struct*)outapp->pBuffer; strcpy(gmn->name, name); strcpy(gmn->gmname, name); @@ -1928,7 +1970,7 @@ bool Client::ChangeFirstName(const char* in_firstname, const char* gmname) Save(); // send name update packet - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMNameChange, sizeof(GMName_Struct)); + auto outapp = new EQApplicationPacket(OP_GMNameChange, sizeof(GMName_Struct)); GMName_Struct* gmn=(GMName_Struct*)outapp->pBuffer; strn0cpy(gmn->gmname,gmname,64); strn0cpy(gmn->oldname,GetName(),64); @@ -1969,11 +2011,11 @@ void Client::ReadBook(BookRequest_Struct *book) { #if EQDEBUG >= 6 Log.Out(Logs::General, Logs::Normal, "Client::ReadBook() textfile:%s Text:%s", txtfile, booktxt2.c_str()); #endif - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ReadBook, length + sizeof(BookText_Struct)); + auto outapp = new EQApplicationPacket(OP_ReadBook, length + sizeof(BookText_Struct)); BookText_Struct *out = (BookText_Struct *) outapp->pBuffer; out->window = book->window; - if(GetClientVersion() >= ClientVersion::SoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { const ItemInst *inst = m_inv[book->invslot]; if(inst) @@ -1997,7 +2039,7 @@ void Client::QuestReadBook(const char* text, uint8 type) { std::string booktxt2 = text; int length = booktxt2.length(); if (booktxt2[0] != '\0') { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ReadBook, length + sizeof(BookText_Struct)); + auto outapp = new EQApplicationPacket(OP_ReadBook, length + sizeof(BookText_Struct)); BookText_Struct *out = (BookText_Struct *) outapp->pBuffer; out->window = 0xFF; out->type = type; @@ -2009,7 +2051,7 @@ void Client::QuestReadBook(const char* text, uint8 type) { } void Client::SendClientMoneyUpdate(uint8 type,uint32 amount){ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeMoneyUpdate,sizeof(TradeMoneyUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_TradeMoneyUpdate, sizeof(TradeMoneyUpdate_Struct)); TradeMoneyUpdate_Struct* mus= (TradeMoneyUpdate_Struct*)outapp->pBuffer; mus->amount=amount; mus->trader=0; @@ -2207,7 +2249,7 @@ void Client::AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 plat } void Client::SendMoneyUpdate() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoneyUpdate,sizeof(MoneyUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_MoneyUpdate, sizeof(MoneyUpdate_Struct)); MoneyUpdate_Struct* mus= (MoneyUpdate_Struct*)outapp->pBuffer; mus->platinum = m_pp.platinum; @@ -2255,12 +2297,12 @@ uint64 Client::GetAllMoney() { (static_cast(m_pp.platinum_shared) * 1000))))); } -bool Client::CheckIncreaseSkill(SkillUseTypes skillid, Mob *against_who, int chancemodi) { +bool Client::CheckIncreaseSkill(EQEmu::skills::SkillType skillid, Mob *against_who, int chancemodi) { if (IsDead() || IsUnconscious()) return false; if (IsAIControlled()) // no skillups while chamred =p return false; - if (skillid > HIGHEST_SKILL) + if (skillid > EQEmu::skills::HIGHEST_SKILL) return false; int skillval = GetRawSkill(skillid); int maxskill = GetMaxSkillAfterSpecializationRules(skillid, MaxSkill(skillid)); @@ -2325,24 +2367,34 @@ void Client::CheckLanguageSkillIncrease(uint8 langid, uint8 TeacherSkill) { } } -bool Client::HasSkill(SkillUseTypes skill_id) const { +bool Client::HasSkill(EQEmu::skills::SkillType skill_id) const { return((GetSkill(skill_id) > 0) && CanHaveSkill(skill_id)); } -bool Client::CanHaveSkill(SkillUseTypes skill_id) const { +bool Client::CanHaveSkill(EQEmu::skills::SkillType skill_id) const { + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF2 && class_ == BERSERKER && skill_id == EQEmu::skills::Skill1HPiercing) + skill_id = EQEmu::skills::Skill2HPiercing; + return(database.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)) > 0); //if you don't have it by max level, then odds are you never will? } -uint16 Client::MaxSkill(SkillUseTypes skillid, uint16 class_, uint16 level) const { +uint16 Client::MaxSkill(EQEmu::skills::SkillType skillid, uint16 class_, uint16 level) const { + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF2 && class_ == BERSERKER && skillid == EQEmu::skills::Skill1HPiercing) + skillid = EQEmu::skills::Skill2HPiercing; + return(database.GetSkillCap(class_, skillid, level)); } -uint8 Client::SkillTrainLevel(SkillUseTypes skillid, uint16 class_){ +uint8 Client::SkillTrainLevel(EQEmu::skills::SkillType skillid, uint16 class_) +{ + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF2 && class_ == BERSERKER && skillid == EQEmu::skills::Skill1HPiercing) + skillid = EQEmu::skills::Skill2HPiercing; + return(database.GetTrainLevel(class_, skillid, RuleI(Character, MaxLevel))); } -uint16 Client::GetMaxSkillAfterSpecializationRules(SkillUseTypes skillid, uint16 maxSkill) +uint16 Client::GetMaxSkillAfterSpecializationRules(EQEmu::skills::SkillType skillid, uint16 maxSkill) { uint16 Result = maxSkill; @@ -2352,13 +2404,13 @@ uint16 Client::GetMaxSkillAfterSpecializationRules(SkillUseTypes skillid, uint16 uint16 MaxSpecializations = GetAA(aaSecondaryForte) ? 2 : 1; - if(skillid >= SkillSpecializeAbjure && skillid <= SkillSpecializeEvocation) + if (skillid >= EQEmu::skills::SkillSpecializeAbjure && skillid <= EQEmu::skills::SkillSpecializeEvocation) { bool HasPrimarySpecSkill = false; int NumberOfPrimarySpecSkills = 0; - for(int i = SkillSpecializeAbjure; i <= SkillSpecializeEvocation; ++i) + for (int i = EQEmu::skills::SkillSpecializeAbjure; i <= EQEmu::skills::SkillSpecializeEvocation; ++i) { if(m_pp.skills[i] > 50) { @@ -2415,8 +2467,8 @@ uint16 Client::GetMaxSkillAfterSpecializationRules(SkillUseTypes skillid, uint16 Message(13, "Your spell casting specializations skills have been reset. " "Only %i primary specialization skill is allowed.", MaxSpecializations); - for(int i = SkillSpecializeAbjure; i <= SkillSpecializeEvocation; ++i) - SetSkill((SkillUseTypes)i, 1); + for (int i = EQEmu::skills::SkillSpecializeAbjure; i <= EQEmu::skills::SkillSpecializeEvocation; ++i) + SetSkill((EQEmu::skills::SkillType)i, 1); Save(); @@ -2426,36 +2478,28 @@ uint16 Client::GetMaxSkillAfterSpecializationRules(SkillUseTypes skillid, uint16 } } - // This should possibly be handled by bonuses rather than here. - switch(skillid) - { - case SkillTracking: - { - Result += ((GetAA(aaAdvancedTracking) * 10) + (GetAA(aaTuneofPursuance) * 10)); - break; - } - - default: - break; - } + + Result += spellbonuses.RaiseSkillCap[skillid] + itembonuses.RaiseSkillCap[skillid] + aabonuses.RaiseSkillCap[skillid]; return Result; } -void Client::SetPVP(bool toggle) { +void Client::SetPVP(bool toggle, bool message) { m_pp.pvp = toggle ? 1 : 0; - if(GetPVP()) - this->Message_StringID(MT_Shout,PVP_ON); - else - Message(13, "You no longer follow the ways of discord."); + if (message) { + if(GetPVP()) + this->Message_StringID(MT_Shout,PVP_ON); + else + Message(13, "You no longer follow the ways of discord."); + } SendAppearancePacket(AT_PVP, GetPVP()); Save(); } void Client::WorldKick() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMKick, sizeof(GMKick_Struct)); + auto outapp = new EQApplicationPacket(OP_GMKick, sizeof(GMKick_Struct)); GMKick_Struct* gmk = (GMKick_Struct *)outapp->pBuffer; strcpy(gmk->name,GetName()); QueuePacket(outapp); @@ -2464,7 +2508,7 @@ void Client::WorldKick() { } void Client::GMKill() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMKill, sizeof(GMKill_Struct)); + auto outapp = new EQApplicationPacket(OP_GMKill, sizeof(GMKill_Struct)); GMKill_Struct* gmk = (GMKill_Struct *)outapp->pBuffer; strcpy(gmk->name,GetName()); QueuePacket(outapp); @@ -2479,7 +2523,7 @@ bool Client::CheckAccess(int16 iDBLevel, int16 iDefaultLevel) { } void Client::MemorizeSpell(uint32 slot,uint32 spellid,uint32 scribing){ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MemorizeSpell,sizeof(MemorizeSpell_Struct)); + auto outapp = new EQApplicationPacket(OP_MemorizeSpell, sizeof(MemorizeSpell_Struct)); MemorizeSpell_Struct* mss=(MemorizeSpell_Struct*)outapp->pBuffer; mss->scribing=scribing; mss->slot=slot; @@ -2505,7 +2549,7 @@ void Client::SetFeigned(bool in_feigned) { feigned=in_feigned; } -void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const Item_Struct* item, bool buying) +void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQEmu::ItemBase* item, bool buying) { if(!player || !merchant || !item) return; @@ -2534,25 +2578,25 @@ void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 } } -bool Client::BindWound(Mob* bindmob, bool start, bool fail){ - EQApplicationPacket* outapp = 0; - if(!fail) - { +bool Client::BindWound(Mob *bindmob, bool start, bool fail) +{ + EQApplicationPacket *outapp = nullptr; + if (!fail) { outapp = new EQApplicationPacket(OP_Bind_Wound, sizeof(BindWound_Struct)); - BindWound_Struct* bind_out = (BindWound_Struct*) outapp->pBuffer; + BindWound_Struct *bind_out = (BindWound_Struct *)outapp->pBuffer; // Start bind - if(!bindwound_timer.Enabled()) - { - //make sure we actually have a bandage... and consume it. - int16 bslot = m_inv.HasItemByUse(ItemTypeBandage, 1, invWhereWorn|invWherePersonal); + if (!bindwound_timer.Enabled()) { + // make sure we actually have a bandage... and consume it. + int16 bslot = m_inv.HasItemByUse(EQEmu::item::ItemTypeBandage, 1, invWhereWorn | invWherePersonal); if (bslot == INVALID_INDEX) { bind_out->type = 3; QueuePacket(outapp); - bind_out->type = 7; //this is the wrong message, dont know the right one. + bind_out->type = 7; // this is the wrong message, dont know the right one. QueuePacket(outapp); - return(true); + safe_delete(outapp); + return (true); } - DeleteItemInInventory(bslot, 1, true); //do we need client update? + DeleteItemInInventory(bslot, 1, true); // do we need client update? // start complete timer bindwound_timer.Start(10000); @@ -2563,116 +2607,110 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){ QueuePacket(outapp); bind_out->type = 0; // Client Unlocked - if(!bindmob) { + if (!bindmob) { // send "bindmob dead" to client bind_out->type = 4; QueuePacket(outapp); bind_out->type = 0; bindwound_timer.Disable(); bindwound_target = 0; - } - else { + } else { // send bindmob "stand still" - if(!bindmob->IsAIControlled() && bindmob != this ) { - bind_out->type = 2; // ? - //bind_out->type = 3; // ? - bind_out->to = GetID(); // ? - bindmob->CastToClient()->QueuePacket(outapp); - bind_out->type = 0; - bind_out->to = 0; - } - else if (bindmob->IsAIControlled() && bindmob != this ){ + if (!bindmob->IsAIControlled() && bindmob != this) { + bindmob->CastToClient()->Message_StringID(clientMessageYellow, + YOU_ARE_BEING_BANDAGED); + } else if (bindmob->IsAIControlled() && bindmob != this) { ; // Tell IPC to stand still? - } - else { + } else { ; // Binding self } } - } - else if (bindwound_timer.Check()) // Did the timer finish? - { - // finish bind + } else if (bindwound_timer.Check()) // Did the timer finish? + { + // finish bind // disable complete timer bindwound_timer.Disable(); bindwound_target = 0; - if(!bindmob){ - // send "bindmob gone" to client - bind_out->type = 5; // not in zone - QueuePacket(outapp); - bind_out->type = 0; + if (!bindmob) { + // send "bindmob gone" to client + bind_out->type = 5; // not in zone + QueuePacket(outapp); + bind_out->type = 0; } else { - if (!GetFeigned() && (DistanceSquared(bindmob->GetPosition(), m_Position) <= 400)) { + if (!GetFeigned() && (DistanceSquared(bindmob->GetPosition(), m_Position) <= 400)) { // send bindmob bind done - if(!bindmob->IsAIControlled() && bindmob != this ) { + if (!bindmob->IsAIControlled() && bindmob != this) { - } - else if(bindmob->IsAIControlled() && bindmob != this ) { - // Tell IPC to resume?? - } - else { - // Binding self + } else if (bindmob->IsAIControlled() && bindmob != this) { + // Tell IPC to resume?? + } else { + // Binding self } // Send client bind done bind_out->type = 1; // Done QueuePacket(outapp); bind_out->type = 0; - CheckIncreaseSkill(SkillBindWound, nullptr, 5); + CheckIncreaseSkill(EQEmu::skills::SkillBindWound, nullptr, 5); - int maxHPBonus = spellbonuses.MaxBindWound + itembonuses.MaxBindWound + aabonuses.MaxBindWound; + int maxHPBonus = spellbonuses.MaxBindWound + itembonuses.MaxBindWound + + aabonuses.MaxBindWound; int max_percent = 50 + 10 * maxHPBonus; - if(GetClass() == MONK && GetSkill(SkillBindWound) > 200) { + if (GetClass() == MONK && GetSkill(EQEmu::skills::SkillBindWound) > 200) { max_percent = 70 + 10 * maxHPBonus; } max_percent = mod_bindwound_percent(max_percent, bindmob); - int max_hp = bindmob->GetMaxHP()*max_percent/100; + int max_hp = bindmob->GetMaxHP() * max_percent / 100; // send bindmob new hp's - if (bindmob->GetHP() < bindmob->GetMaxHP() && bindmob->GetHP() <= (max_hp)-1){ + if (bindmob->GetHP() < bindmob->GetMaxHP() && bindmob->GetHP() <= (max_hp)-1) { // 0.120 per skill point, 0.60 per skill level, minimum 3 max 30 int bindhps = 3; - - if (GetSkill(SkillBindWound) > 200) { - bindhps += GetSkill(SkillBindWound)*4/10; - } else if (GetSkill(SkillBindWound) >= 10) { - bindhps += GetSkill(SkillBindWound)/4; + if (GetSkill(EQEmu::skills::SkillBindWound) > 200) { + bindhps += GetSkill(EQEmu::skills::SkillBindWound) * 4 / 10; + } + else if (GetSkill(EQEmu::skills::SkillBindWound) >= 10) { + bindhps += GetSkill(EQEmu::skills::SkillBindWound) / 4; } - //Implementation of aaMithanielsBinding is a guess (the multiplier) - int bindBonus = spellbonuses.BindWound + itembonuses.BindWound + aabonuses.BindWound; + // Implementation of aaMithanielsBinding is a guess (the multiplier) + int bindBonus = spellbonuses.BindWound + itembonuses.BindWound + + aabonuses.BindWound; - bindhps += bindhps*bindBonus / 100; + bindhps += bindhps * bindBonus / 100; bindhps = mod_bindwound_hp(bindhps, bindmob); - //if the bind takes them above the max bindable - //cap it at that value. Dont know if live does it this way - //but it makes sense to me. + // if the bind takes them above the max bindable + // cap it at that value. Dont know if live does it this way + // but it makes sense to me. int chp = bindmob->GetHP() + bindhps; - if(chp > max_hp) + if (chp > max_hp) chp = max_hp; bindmob->SetHP(chp); bindmob->SendHPUpdate(); - } - else { - //I dont have the real, live - Message(15, "You cannot bind wounds above %d%% hitpoints.", max_percent); - if(bindmob->IsClient()) - bindmob->CastToClient()->Message(15, "You cannot have your wounds bound above %d%% hitpoints.", max_percent); + } else { + // I dont have the real, live + Message(15, "You cannot bind wounds above %d%% hitpoints.", + max_percent); + if (bindmob != this && bindmob->IsClient()) + bindmob->CastToClient()->Message( + 15, + "You cannot have your wounds bound above %d%% hitpoints.", + max_percent); // Too many hp message goes here. } - } - else { + } else { // Send client bind failed - if(bindmob != this) + if (bindmob != this) bind_out->type = 6; // They moved else bind_out->type = 7; // Bandager moved @@ -2682,11 +2720,10 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){ } } } - } - else if (bindwound_timer.Enabled()) { + } else if (bindwound_timer.Enabled()) { // You moved outapp = new EQApplicationPacket(OP_Bind_Wound, sizeof(BindWound_Struct)); - BindWound_Struct* bind_out = (BindWound_Struct*) outapp->pBuffer; + BindWound_Struct *bind_out = (BindWound_Struct *)outapp->pBuffer; bindwound_timer.Disable(); bindwound_target = 0; bind_out->type = 7; @@ -2699,13 +2736,13 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){ } void Client::SetMaterial(int16 in_slot, uint32 item_id) { - const Item_Struct* item = database.GetItem(item_id); - if (item && (item->ItemClass==ItemClassCommon)) + const EQEmu::ItemBase* item = database.GetItem(item_id); + if (item && item->IsClassCommon()) { uint8 matslot = Inventory::CalcMaterialFromSlot(in_slot); - if (matslot != _MaterialInvalid) + if (matslot != EQEmu::textures::TextureInvalid) { - m_pp.item_material[matslot] = GetEquipmentMaterial(matslot); + m_pp.item_material.Slot[matslot].Material = GetEquipmentMaterial(matslot); } } } @@ -2788,7 +2825,7 @@ void Client::ServerFilter(SetServerFilter_Struct* filter){ Filter0(FilterMissedMe); Filter1(FilterDamageShields); - if (GetClientVersionBit() & BIT_SoDAndLater) { + if (ClientVersionBit() & EQEmu::versions::bit_SoDAndLater) { if (filter->filters[FilterDOT] == 0) ClientFilters[FilterDOT] = FilterShow; else if (filter->filters[FilterDOT] == 1) @@ -2809,7 +2846,7 @@ void Client::ServerFilter(SetServerFilter_Struct* filter){ Filter1(FilterFocusEffects); Filter1(FilterPetSpells); - if (GetClientVersionBit() & BIT_SoDAndLater) { + if (ClientVersionBit() & EQEmu::versions::bit_SoDAndLater) { if (filter->filters[FilterHealOverTime] == 0) ClientFilters[FilterHealOverTime] = FilterShow; // This is called 'Show Mine Only' in the clients, but functions the same as show @@ -2833,7 +2870,7 @@ void Client::Message_StringID(uint32 type, uint32 string_id, uint32 distance) return; if (GetFilter(FilterSpellCrits) == FilterHide && type == MT_SpellCrits) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SimpleMessage,12); + auto outapp = new EQApplicationPacket(OP_SimpleMessage, 12); SimpleMessage_Struct* sms = (SimpleMessage_Struct*)outapp->pBuffer; sms->color=type; sms->string_id=string_id; @@ -2895,7 +2932,7 @@ void Client::Message_StringID(uint32 type, uint32 string_id, const char* message length += 1; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_FormattedMessage, sizeof(FormattedMessage_Struct) + length); + auto outapp = new EQApplicationPacket(OP_FormattedMessage, sizeof(FormattedMessage_Struct) + length); FormattedMessage_Struct *fm = (FormattedMessage_Struct *)outapp->pBuffer; fm->string_id = string_id; fm->type = type; @@ -2961,7 +2998,7 @@ void Client::FilteredMessage_StringID(Mob *sender, uint32 type, if (!FilteredMessageCheck(sender, filter)) return; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SimpleMessage, 12); + auto outapp = new EQApplicationPacket(OP_SimpleMessage, 12); SimpleMessage_Struct *sms = (SimpleMessage_Struct *)outapp->pBuffer; sms->color = type; sms->string_id = string_id; @@ -3009,7 +3046,7 @@ void Client::FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType fil length += 1; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_FormattedMessage, sizeof(FormattedMessage_Struct) + length); + auto outapp = new EQApplicationPacket(OP_FormattedMessage, sizeof(FormattedMessage_Struct) + length); FormattedMessage_Struct *fm = (FormattedMessage_Struct *)outapp->pBuffer; fm->string_id = string_id; fm->type = type; @@ -3035,19 +3072,19 @@ void Client::Tell_StringID(uint32 string_id, const char *who, const char *messag } void Client::SetTint(int16 in_slot, uint32 color) { - Color_Struct new_color; + EQEmu::Tint_Struct new_color; new_color.Color = color; SetTint(in_slot, new_color); database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color); } // Still need to reconcile bracer01 versus bracer02 -void Client::SetTint(int16 in_slot, Color_Struct& color) { +void Client::SetTint(int16 in_slot, EQEmu::Tint_Struct& color) { uint8 matslot = Inventory::CalcMaterialFromSlot(in_slot); - if (matslot != _MaterialInvalid) + if (matslot != EQEmu::textures::TextureInvalid) { - m_pp.item_tint[matslot].Color = color.Color; + m_pp.item_tint.Slot[matslot].Color = color.Color; database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color.Color); } @@ -3087,7 +3124,7 @@ void Client::SetLanguageSkill(int langid, int value) m_pp.languages[langid] = value; database.SaveCharacterLanguage(this->CharacterID(), langid, value); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_SkillUpdate, sizeof(SkillUpdate_Struct)); SkillUpdate_Struct* skill = (SkillUpdate_Struct*)outapp->pBuffer; skill->skillId = 100 + langid; skill->value = m_pp.languages[langid]; @@ -3120,60 +3157,60 @@ void Client::LinkDead() } uint8 Client::SlotConvert(uint8 slot,bool bracer){ - uint8 slot2=0; // why are we returning MainCharm instead of INVALID_INDEX? (must be a pre-charm segment...) + uint8 slot2 = 0; // why are we returning MainCharm instead of INVALID_INDEX? (must be a pre-charm segment...) if(bracer) - return MainWrist2; - switch(slot){ - case MaterialHead: - slot2=MainHead; - break; - case MaterialChest: - slot2=MainChest; - break; - case MaterialArms: - slot2=MainArms; - break; - case MaterialWrist: - slot2=MainWrist1; - break; - case MaterialHands: - slot2=MainHands; - break; - case MaterialLegs: - slot2=MainLegs; - break; - case MaterialFeet: - slot2=MainFeet; - break; - } + return EQEmu::legacy::SlotWrist2; + switch(slot) { + case EQEmu::textures::TextureHead: + slot2 = EQEmu::legacy::SlotHead; + break; + case EQEmu::textures::TextureChest: + slot2 = EQEmu::legacy::SlotChest; + break; + case EQEmu::textures::TextureArms: + slot2 = EQEmu::legacy::SlotArms; + break; + case EQEmu::textures::TextureWrist: + slot2 = EQEmu::legacy::SlotWrist1; + break; + case EQEmu::textures::TextureHands: + slot2 = EQEmu::legacy::SlotHands; + break; + case EQEmu::textures::TextureLegs: + slot2 = EQEmu::legacy::SlotLegs; + break; + case EQEmu::textures::TextureFeet: + slot2 = EQEmu::legacy::SlotFeet; + break; + } return slot2; } uint8 Client::SlotConvert2(uint8 slot){ - uint8 slot2=0; // same as above... + uint8 slot2 = 0; // same as above... switch(slot){ - case MainHead: - slot2=MaterialHead; - break; - case MainChest: - slot2=MaterialChest; - break; - case MainArms: - slot2=MaterialArms; - break; - case MainWrist1: - slot2=MaterialWrist; - break; - case MainHands: - slot2=MaterialHands; - break; - case MainLegs: - slot2=MaterialLegs; - break; - case MainFeet: - slot2=MaterialFeet; - break; - } + case EQEmu::legacy::SlotHead: + slot2 = EQEmu::textures::TextureHead; + break; + case EQEmu::legacy::SlotChest: + slot2 = EQEmu::textures::TextureChest; + break; + case EQEmu::legacy::SlotArms: + slot2 = EQEmu::textures::TextureArms; + break; + case EQEmu::legacy::SlotWrist1: + slot2 = EQEmu::textures::TextureWrist; + break; + case EQEmu::legacy::SlotHands: + slot2 = EQEmu::textures::TextureHands; + break; + case EQEmu::legacy::SlotLegs: + slot2 = EQEmu::textures::TextureLegs; + break; + case EQEmu::legacy::SlotFeet: + slot2 = EQEmu::textures::TextureFeet; + break; + } return slot2; } @@ -3558,7 +3595,7 @@ void Client::Insight(uint32 t_id) } strcat(resists," to disease."); - Message(0,"Your target is a level %i %s. It appears %s and %s for its level. It seems %s",who->GetLevel(),GetEQClassName(who->GetClass(),1),dmg,hitpoints,resists); + Message(0,"Your target is a level %i %s. It appears %s and %s for its level. It seems %s",who->GetLevel(),GetClassIDName(who->GetClass(),1),dmg,hitpoints,resists); } void Client::GetGroupAAs(GroupLeadershipAA_Struct *into) const { @@ -3572,10 +3609,8 @@ void Client::GetRaidAAs(RaidLeadershipAA_Struct *into) const { void Client::EnteringMessages(Client* client) { //server rules - char *rules; - rules = new char [4096]; - - if(database.GetVariable("Rules", rules, 4096)) + std::string rules; + if(database.GetVariable("Rules", rules)) { uint8 flag = database.GetAgreementFlag(client->AccountID()); if(!flag) @@ -3586,25 +3621,18 @@ void Client::EnteringMessages(Client* client) client->SendAppearancePacket(AT_Anim, ANIM_FREEZE); } } - safe_delete_array(rules); } void Client::SendRules(Client* client) { - char *rules; - rules = new char [4096]; - char *ptr; + std::string rules; - database.GetVariable("Rules", rules, 4096); + if (!database.GetVariable("Rules", rules)) + return; - ptr = strtok(rules, "\n"); - while(ptr != nullptr) - { - - client->Message(0,"%s",ptr); - ptr = strtok(nullptr, "\n"); - } - safe_delete_array(rules); + auto lines = SplitString(rules, '\n'); + for (auto&& e : lines) + client->Message(0, "%s", e.c_str()); } void Client::SetEndurance(int32 newEnd) @@ -3620,19 +3648,25 @@ void Client::SetEndurance(int32 newEnd) SendManaUpdatePacket(); } -void Client::SacrificeConfirm(Client *caster) { +void Client::SacrificeConfirm(Client *caster) +{ + auto outapp = new EQApplicationPacket(OP_Sacrifice, sizeof(Sacrifice_Struct)); + Sacrifice_Struct *ss = (Sacrifice_Struct *)outapp->pBuffer; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Sacrifice, sizeof(Sacrifice_Struct)); - Sacrifice_Struct *ss = (Sacrifice_Struct*)outapp->pBuffer; - - if(!caster || PendingSacrifice) return; - - if(GetLevel() < RuleI(Spells, SacrificeMinLevel)){ - caster->Message_StringID(13, SAC_TOO_LOW); //This being is not a worthy sacrifice. + if (!caster || PendingSacrifice) { + safe_delete(outapp); return; } + + if (GetLevel() < RuleI(Spells, SacrificeMinLevel)) { + caster->Message_StringID(13, SAC_TOO_LOW); // This being is not a worthy sacrifice. + safe_delete(outapp); + return; + } + if (GetLevel() > RuleI(Spells, SacrificeMaxLevel)) { caster->Message_StringID(13, SAC_TOO_HIGH); + safe_delete(outapp); return; } @@ -3650,58 +3684,58 @@ void Client::SacrificeConfirm(Client *caster) { //Essentially a special case death function void Client::Sacrifice(Client *caster) { - if(GetLevel() >= RuleI(Spells, SacrificeMinLevel) && GetLevel() <= RuleI(Spells, SacrificeMaxLevel)){ - int exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000); - if(exploss < GetEXP()){ - SetEXP(GetEXP()-exploss, GetAAXP()); - SendLogoutPackets(); + if (GetLevel() >= RuleI(Spells, SacrificeMinLevel) && GetLevel() <= RuleI(Spells, SacrificeMaxLevel)) { + int exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000); + if (exploss < GetEXP()) { + SetEXP(GetEXP() - exploss, GetAAXP()); + SendLogoutPackets(); - //make our become corpse packet, and queue to ourself before OP_Death. - EQApplicationPacket app2(OP_BecomeCorpse, sizeof(BecomeCorpse_Struct)); - BecomeCorpse_Struct* bc = (BecomeCorpse_Struct*)app2.pBuffer; - bc->spawn_id = GetID(); - bc->x = GetX(); - bc->y = GetY(); - bc->z = GetZ(); - QueuePacket(&app2); + // make our become corpse packet, and queue to ourself before OP_Death. + EQApplicationPacket app2(OP_BecomeCorpse, sizeof(BecomeCorpse_Struct)); + BecomeCorpse_Struct *bc = (BecomeCorpse_Struct *)app2.pBuffer; + bc->spawn_id = GetID(); + bc->x = GetX(); + bc->y = GetY(); + bc->z = GetZ(); + QueuePacket(&app2); - // make death packet - EQApplicationPacket app(OP_Death, sizeof(Death_Struct)); - Death_Struct* d = (Death_Struct*)app.pBuffer; - d->spawn_id = GetID(); - d->killer_id = caster ? caster->GetID() : 0; - d->bindzoneid = GetPP().binds[0].zoneId; - d->spell_id = SPELL_UNKNOWN; - d->attack_skill = 0xe7; - d->damage = 0; - app.priority = 6; - entity_list.QueueClients(this, &app); + // make death packet + EQApplicationPacket app(OP_Death, sizeof(Death_Struct)); + Death_Struct *d = (Death_Struct *)app.pBuffer; + d->spawn_id = GetID(); + d->killer_id = caster ? caster->GetID() : 0; + d->bindzoneid = GetPP().binds[0].zoneId; + d->spell_id = SPELL_UNKNOWN; + d->attack_skill = 0xe7; + d->damage = 0; + app.priority = 6; + entity_list.QueueClients(this, &app); - BuffFadeAll(); - UnmemSpellAll(); - Group *g = GetGroup(); - if(g){ - g->MemberZoned(this); - } - Raid *r = entity_list.GetRaidByClient(this); - if(r){ - r->MemberZoned(this); - } - ClearAllProximities(); - if(RuleB(Character, LeaveCorpses)){ - Corpse *new_corpse = new Corpse(this, 0); - entity_list.AddCorpse(new_corpse, GetID()); - SetID(0); - entity_list.QueueClients(this, &app2, true); - } - Save(); - GoToDeath(); - caster->SummonItem(RuleI(Spells, SacrificeItemID)); - } - } - else{ - caster->Message_StringID(13, SAC_TOO_LOW); //This being is not a worthy sacrifice. - } + BuffFadeAll(); + UnmemSpellAll(); + Group *g = GetGroup(); + if (g) { + g->MemberZoned(this); + } + Raid *r = entity_list.GetRaidByClient(this); + if (r) { + r->MemberZoned(this); + } + ClearAllProximities(); + if (RuleB(Character, LeaveCorpses)) { + auto new_corpse = new Corpse(this, 0); + entity_list.AddCorpse(new_corpse, GetID()); + SetID(0); + entity_list.QueueClients(this, &app2, true); + } + Save(); + GoToDeath(); + if (caster) // I guess it's possible? + caster->SummonItem(RuleI(Spells, SacrificeItemID)); + } + } else { + caster->Message_StringID(13, SAC_TOO_LOW); // This being is not a worthy sacrifice. + } } void Client::SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID) { @@ -3711,7 +3745,7 @@ void Client::SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID) { const SPDat_Spell_Struct &Spell = spells[SpellID]; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Translocate, sizeof(Translocate_Struct)); + auto outapp = new EQApplicationPacket(OP_Translocate, sizeof(Translocate_Struct)); Translocate_Struct *ts = (Translocate_Struct*)outapp->pBuffer; strcpy(ts->Caster, Caster->GetName()); @@ -3745,49 +3779,52 @@ void Client::SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID) { return; } -void Client::SendPickPocketResponse(Mob *from, uint32 amt, int type, const Item_Struct* item){ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_PickPocket, sizeof(sPickPocket_Struct)); - sPickPocket_Struct* pick_out = (sPickPocket_Struct*) outapp->pBuffer; - pick_out->coin = amt; - pick_out->from = GetID(); - pick_out->to = from->GetID(); - pick_out->myskill = GetSkill(SkillPickPockets); +void Client::SendPickPocketResponse(Mob *from, uint32 amt, int type, const EQEmu::ItemBase* item){ + auto outapp = new EQApplicationPacket(OP_PickPocket, sizeof(sPickPocket_Struct)); + sPickPocket_Struct *pick_out = (sPickPocket_Struct *)outapp->pBuffer; + pick_out->coin = amt; + pick_out->from = GetID(); + pick_out->to = from->GetID(); + pick_out->myskill = GetSkill(EQEmu::skills::SkillPickPockets); - if((type >= PickPocketPlatinum) && (type <= PickPocketCopper) && (amt == 0)) - type = PickPocketFailed; + if ((type >= PickPocketPlatinum) && (type <= PickPocketCopper) && (amt == 0)) + type = PickPocketFailed; - pick_out->type = type; - if(item) - strcpy(pick_out->itemname, item->Name); - else - pick_out->itemname[0] = '\0'; - //if we do not send this packet the client will lock up and require the player to relog. - QueuePacket(outapp); - safe_delete(outapp); + pick_out->type = type; + if (item) + strcpy(pick_out->itemname, item->Name); + else + pick_out->itemname[0] = '\0'; + // if we do not send this packet the client will lock up and require the player to relog. + QueuePacket(outapp); + safe_delete(outapp); } void Client::SetHoTT(uint32 mobid) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_TargetHoTT, sizeof(ClientTarget_Struct)); + auto outapp = new EQApplicationPacket(OP_TargetHoTT, sizeof(ClientTarget_Struct)); ClientTarget_Struct *ct = (ClientTarget_Struct *) outapp->pBuffer; ct->new_target = mobid; QueuePacket(outapp); safe_delete(outapp); } -void Client::SendPopupToClient(const char *Title, const char *Text, uint32 PopupID, uint32 Buttons, uint32 Duration) { +void Client::SendPopupToClient(const char *Title, const char *Text, uint32 PopupID, uint32 Buttons, uint32 Duration) +{ - EQApplicationPacket *outapp = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct)); - OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *) outapp->pBuffer; + auto outapp = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct)); + OnLevelMessage_Struct *olms = (OnLevelMessage_Struct *)outapp->pBuffer; - if((strlen(Title) > (sizeof(olms->Title)-1)) || - (strlen(Text) > (sizeof(olms->Text)-1))) return; + if ((strlen(Title) > (sizeof(olms->Title) - 1)) || (strlen(Text) > (sizeof(olms->Text) - 1))) { + safe_delete(outapp); + return; + } strcpy(olms->Title, Title); strcpy(olms->Text, Text); olms->Buttons = Buttons; - if(Duration > 0) + if (Duration > 0) olms->Duration = Duration * 1000; else olms->Duration = 0xffffffff; @@ -3811,11 +3848,13 @@ void Client::SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const size_t len = strlen(buffer); - EQApplicationPacket* app = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct)); + auto app = new EQApplicationPacket(OP_OnLevelMessage, sizeof(OnLevelMessage_Struct)); OnLevelMessage_Struct* olms=(OnLevelMessage_Struct*)app->pBuffer; - if(strlen(Text) > (sizeof(olms->Text)-1)) + if(strlen(Text) > (sizeof(olms->Text)-1)) { + safe_delete(app); return; + } if(!target) title_type = 0; @@ -3904,10 +3943,7 @@ void Client::KeyRingAdd(uint32 item_id) bool Client::KeyRingCheck(uint32 item_id) { - for(std::list::iterator iter = keyring.begin(); - iter != keyring.end(); - ++iter) - { + for (auto iter = keyring.begin(); iter != keyring.end(); ++iter) { if(*iter == item_id) return true; } @@ -3917,11 +3953,8 @@ bool Client::KeyRingCheck(uint32 item_id) void Client::KeyRingList() { Message(4,"Keys on Keyring:"); - const Item_Struct *item = 0; - for(std::list::iterator iter = keyring.begin(); - iter != keyring.end(); - ++iter) - { + const EQEmu::ItemBase *item = 0; + for (auto iter = keyring.begin(); iter != keyring.end(); ++iter) { if ((item = database.GetItem(*iter))!=nullptr) { Message(4,item->Name); } @@ -4094,9 +4127,9 @@ bool Client::GroupFollow(Client* inviter) { group->UpdateGroupAAs(); //Invite the inviter into the group first.....dont ask - if (inviter->GetClientVersion() < ClientVersion::SoD) + if (inviter->ClientVersion() < EQEmu::versions::ClientVersion::SoD) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* outgj = (GroupJoin_Struct*)outapp->pBuffer; strcpy(outgj->membername, inviter->GetName()); strcpy(outgj->yourname, inviter->GetName()); @@ -4140,13 +4173,13 @@ bool Client::GroupFollow(Client* inviter) { return false; } - if (GetClientVersion() >= ClientVersion::SoD) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { SendGroupJoinAcknowledge(); } // Temporary hack for SoD, as things seem to work quite differently - if (inviter->IsClient() && inviter->GetClientVersion() >= ClientVersion::SoD) + if (inviter->IsClient() && inviter->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { database.RefreshGroupFromDB(inviter); } @@ -4174,58 +4207,44 @@ bool Client::GroupFollow(Client* inviter) { uint16 Client::GetPrimarySkillValue() { - SkillUseTypes skill = HIGHEST_SKILL; //because nullptr == 0, which is 1H Slashing, & we want it to return 0 from GetSkill - bool equiped = m_inv.GetItem(MainPrimary); + EQEmu::skills::SkillType skill = EQEmu::skills::HIGHEST_SKILL; //because nullptr == 0, which is 1H Slashing, & we want it to return 0 from GetSkill + bool equiped = m_inv.GetItem(EQEmu::legacy::SlotPrimary); if (!equiped) - skill = SkillHandtoHand; + skill = EQEmu::skills::SkillHandtoHand; else { - uint8 type = m_inv.GetItem(MainPrimary)->GetItem()->ItemType; //is this the best way to do this? + uint8 type = m_inv.GetItem(EQEmu::legacy::SlotPrimary)->GetItem()->ItemType; //is this the best way to do this? - switch (type) - { - case ItemType1HSlash: // 1H Slashing - { - skill = Skill1HSlashing; - break; - } - case ItemType2HSlash: // 2H Slashing - { - skill = Skill2HSlashing; - break; - } - case ItemType1HPiercing: // Piercing - { - skill = Skill1HPiercing; - break; - } - case ItemType1HBlunt: // 1H Blunt - { - skill = Skill1HBlunt; - break; - } - case ItemType2HBlunt: // 2H Blunt - { - skill = Skill2HBlunt; - break; - } - case ItemType2HPiercing: // 2H Piercing - { - skill = Skill1HPiercing; // change to Skill2HPiercing once activated - break; - } - case ItemTypeMartial: // Hand to Hand - { - skill = SkillHandtoHand; - break; - } - default: // All other types default to Hand to Hand - { - skill = SkillHandtoHand; - break; - } + switch (type) { + case EQEmu::item::ItemType1HSlash: // 1H Slashing + skill = EQEmu::skills::Skill1HSlashing; + break; + case EQEmu::item::ItemType2HSlash: // 2H Slashing + skill = EQEmu::skills::Skill2HSlashing; + break; + case EQEmu::item::ItemType1HPiercing: // Piercing + skill = EQEmu::skills::Skill1HPiercing; + break; + case EQEmu::item::ItemType1HBlunt: // 1H Blunt + skill = EQEmu::skills::Skill1HBlunt; + break; + case EQEmu::item::ItemType2HBlunt: // 2H Blunt + skill = EQEmu::skills::Skill2HBlunt; + break; + case EQEmu::item::ItemType2HPiercing: // 2H Piercing + if (IsClient() && CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::RoF2) + skill = EQEmu::skills::Skill1HPiercing; + else + skill = EQEmu::skills::Skill2HPiercing; + break; + case EQEmu::item::ItemTypeMartial: // Hand to Hand + skill = EQEmu::skills::SkillHandtoHand; + break; + default: // All other types default to Hand to Hand + skill = EQEmu::skills::SkillHandtoHand; + break; } } @@ -4238,7 +4257,7 @@ uint32 Client::GetTotalATK() uint32 WornCap = itembonuses.ATK; if(IsClient()) { - AttackRating = ((WornCap * 1.342) + (GetSkill(SkillOffense) * 1.345) + ((GetSTR() - 66) * 0.9) + (GetPrimarySkillValue() * 2.69)); + AttackRating = ((WornCap * 1.342) + (GetSkill(EQEmu::skills::SkillOffense) * 1.345) + ((GetSTR() - 66) * 0.9) + (GetPrimarySkillValue() * 2.69)); AttackRating += aabonuses.ATK + GroupLeadershipAAOffenseEnhancement(); if (AttackRating < 10) @@ -4256,7 +4275,7 @@ uint32 Client::GetATKRating() { uint32 AttackRating = 0; if(IsClient()) { - AttackRating = (GetSkill(SkillOffense) * 1.345) + ((GetSTR() - 66) * 0.9) + (GetPrimarySkillValue() * 2.69); + AttackRating = (GetSkill(EQEmu::skills::SkillOffense) * 1.345) + ((GetSTR() - 66) * 0.9) + (GetPrimarySkillValue() * 2.69); if (AttackRating < 10) AttackRating = 10; @@ -4380,9 +4399,9 @@ void Client::IncrementAggroCount() { if (AggroCount == 1) SavedRaidRestTimer = rest_timer.GetRemainingTime(); - if(GetClientVersion() >= ClientVersion::SoF) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RestState, 1); + auto outapp = new EQApplicationPacket(OP_RestState, 1); char *Buffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0x01); QueuePacket(outapp); @@ -4425,9 +4444,9 @@ void Client::DecrementAggroCount() { rest_timer.Start(time_until_rest); - if(GetClientVersion() >= ClientVersion::SoF) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RestState, 5); + auto outapp = new EQApplicationPacket(OP_RestState, 5); char *Buffer = (char *)outapp->pBuffer; VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0x00); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, (uint32)(time_until_rest / 1000)); @@ -4443,7 +4462,7 @@ void Client::SendPVPStats() // When the PVP Stats window is opened, no opcode is sent. Therefore this method should be called // from Client::CompleteConnect, and also when the player makes a PVP kill. // - EQApplicationPacket *outapp = new EQApplicationPacket(OP_PVPStats, sizeof(PVPStats_Struct)); + auto outapp = new EQApplicationPacket(OP_PVPStats, sizeof(PVPStats_Struct)); PVPStats_Struct *pvps = (PVPStats_Struct *)outapp->pBuffer; pvps->Kills = m_pp.PVPKills; @@ -4462,7 +4481,7 @@ void Client::SendPVPStats() void Client::SendCrystalCounts() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_CrystalCountUpdate, sizeof(CrystalCountUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_CrystalCountUpdate, sizeof(CrystalCountUpdate_Struct)); CrystalCountUpdate_Struct *ccus = (CrystalCountUpdate_Struct *)outapp->pBuffer; ccus->CurrentRadiantCrystals = GetRadiantCrystals(); @@ -4478,7 +4497,7 @@ void Client::SendCrystalCounts() void Client::SendDisciplineTimers() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_DisciplineTimer, sizeof(DisciplineTimer_Struct)); + auto outapp = new EQApplicationPacket(OP_DisciplineTimer, sizeof(DisciplineTimer_Struct)); DisciplineTimer_Struct *dts = (DisciplineTimer_Struct *)outapp->pBuffer; for(unsigned int i = 0; i < MAX_DISCIPLINE_TIMERS; ++i) @@ -4542,7 +4561,7 @@ void Client::SendRespawnBinds() PacketLength += opt->name.size() + 1; //+1 for cstring } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RespawnWindow, PacketLength); + auto outapp = new EQApplicationPacket(OP_RespawnWindow, PacketLength); char* buffer = (char*)outapp->pBuffer; //Packet header @@ -4595,7 +4614,7 @@ void Client::HandleLDoNOpen(NPC *target) if(target->GetLDoNTrapSpellID() != 0) { Message_StringID(13, LDON_ACCIDENT_SETOFF2); - target->SpellFinished(target->GetLDoNTrapSpellID(), this, 10, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff); + target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff); target->SetLDoNTrapSpellID(0); target->SetLDoNTrapped(false); target->SetLDoNTrapDetected(false); @@ -4631,7 +4650,7 @@ void Client::HandleLDoNOpen(NPC *target) AddEXP(target->GetLevel()*target->GetLevel()*2625/10, GetLevelCon(target->GetLevel())); } } - target->Death(this, 1, SPELL_UNKNOWN, SkillHandtoHand); + target->Death(this, 0, SPELL_UNKNOWN, EQEmu::skills::SkillHandtoHand); } } } @@ -4717,7 +4736,7 @@ void Client::HandleLDoNDisarm(NPC *target, uint16 skill, uint8 type) break; case -1: Message_StringID(13, LDON_ACCIDENT_SETOFF2); - target->SpellFinished(target->GetLDoNTrapSpellID(), this, 10, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff); + target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff); target->SetLDoNTrapSpellID(0); target->SetLDoNTrapped(false); target->SetLDoNTrapDetected(false); @@ -4736,7 +4755,7 @@ void Client::HandleLDoNPickLock(NPC *target, uint16 skill, uint8 type) if(target->IsLDoNTrapped()) { Message_StringID(13, LDON_ACCIDENT_SETOFF2); - target->SpellFinished(target->GetLDoNTrapSpellID(), this, 10, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff); + target->SpellFinished(target->GetLDoNTrapSpellID(), this, EQEmu::CastingSlot::Item, 0, -1, spells[target->GetLDoNTrapSpellID()].ResistDiff); target->SetLDoNTrapSpellID(0); target->SetLDoNTrapped(false); target->SetLDoNTrapDetected(false); @@ -4806,7 +4825,7 @@ void Client::SummonAndRezzAllCorpses() { PendingRezzXP = -1; - ServerPacket *Pack = new ServerPacket(ServerOP_DepopAllPlayersCorpses, sizeof(ServerDepopAllPlayersCorpses_Struct)); + auto Pack = new ServerPacket(ServerOP_DepopAllPlayersCorpses, sizeof(ServerDepopAllPlayersCorpses_Struct)); ServerDepopAllPlayersCorpses_Struct *sdapcs = (ServerDepopAllPlayersCorpses_Struct*)Pack->pBuffer; @@ -4841,7 +4860,7 @@ void Client::SummonAllCorpses(const glm::vec4& position) if(IsOrigin(position) && position.w == 0.0f) summonLocation = GetPosition(); - ServerPacket *Pack = new ServerPacket(ServerOP_DepopAllPlayersCorpses, sizeof(ServerDepopAllPlayersCorpses_Struct)); + auto Pack = new ServerPacket(ServerOP_DepopAllPlayersCorpses, sizeof(ServerDepopAllPlayersCorpses_Struct)); ServerDepopAllPlayersCorpses_Struct *sdapcs = (ServerDepopAllPlayersCorpses_Struct*)Pack->pBuffer; @@ -4860,7 +4879,7 @@ void Client::SummonAllCorpses(const glm::vec4& position) void Client::DepopAllCorpses() { - ServerPacket *Pack = new ServerPacket(ServerOP_DepopAllPlayersCorpses, sizeof(ServerDepopAllPlayersCorpses_Struct)); + auto Pack = new ServerPacket(ServerOP_DepopAllPlayersCorpses, sizeof(ServerDepopAllPlayersCorpses_Struct)); ServerDepopAllPlayersCorpses_Struct *sdapcs = (ServerDepopAllPlayersCorpses_Struct*)Pack->pBuffer; @@ -4877,7 +4896,7 @@ void Client::DepopAllCorpses() void Client::DepopPlayerCorpse(uint32 dbid) { - ServerPacket *Pack = new ServerPacket(ServerOP_DepopPlayerCorpse, sizeof(ServerDepopPlayerCorpse_Struct)); + auto Pack = new ServerPacket(ServerOP_DepopPlayerCorpse, sizeof(ServerDepopPlayerCorpse_Struct)); ServerDepopPlayerCorpse_Struct *sdpcs = (ServerDepopPlayerCorpse_Struct*)Pack->pBuffer; @@ -4899,7 +4918,7 @@ void Client::BuryPlayerCorpses() void Client::NotifyNewTitlesAvailable() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_NewTitlesAvailable, 0); + auto outapp = new EQApplicationPacket(OP_NewTitlesAvailable, 0); QueuePacket(outapp); @@ -4944,41 +4963,31 @@ void Client::ShowSkillsWindow() { const char *WindowTitle = "Skills"; std::string WindowText; - // using a map for easy alphabetizing of the skills list - std::map Skills; - std::map::iterator it; + std::map Skills = EQEmu::skills::GetSkillTypeMap(); - // this list of names must keep the same order as that in common/skills.h - const char* SkillName[] = {"1H Blunt","1H Slashing","2H Blunt","2H Slashing","Abjuration","Alteration","Apply Poison","Archery", - "Backstab","Bind Wound","Bash","Block","Brass Instruments","Channeling","Conjuration","Defense","Disarm","Disarm Traps","Divination", - "Dodge","Double Attack","Dragon Punch","Dual Wield","Eagle Strike","Evocation","Feign Death","Flying Kick","Forage","Hand to Hand", - "Hide","Kick","Meditate","Mend","Offense","Parry","Pick Lock","Piercing","Ripost","Round Kick","Safe Fall","Sense Heading", - "Singing","Sneak","Specialize Abjuration","Specialize Alteration","Specialize Conjuration","Specialize Divination","Specialize Evocation","Pick Pockets", - "Stringed Instruments","Swimming","Throwing","Tiger Claw","Tracking","Wind Instruments","Fishing","Make Poison","Tinkering","Research", - "Alchemy","Baking","Tailoring","Sense Traps","Blacksmithing","Fletching","Brewing","Alcohol Tolerance","Begging","Jewelry Making", - "Pottery","Percussion Instruments","Intimidation","Berserking","Taunt","Frenzy"}; - for(int i = 0; i <= (int)HIGHEST_SKILL; i++) - Skills[SkillName[i]] = (SkillUseTypes)i; + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF2) + Skills[EQEmu::skills::Skill1HPiercing] = "Piercing"; // print out all available skills - for(it = Skills.begin(); it != Skills.end(); ++it) { - if(GetSkill(it->second) > 0 || MaxSkill(it->second) > 0) { - WindowText += it->first; - // line up the values - for (int j = 0; j < EmuConstants::ITEM_COMMON_SIZE; j++) - WindowText += " "; - WindowText += itoa(this->GetSkill(it->second)); - if (MaxSkill(it->second) > 0) { - WindowText += "/"; - WindowText += itoa(this->GetMaxSkillAfterSpecializationRules(it->second,this->MaxSkill(it->second))); - } - WindowText += "
"; + for (auto skills_iter : Skills) { + if (skills_iter.first == EQEmu::skills::Skill2HPiercing && ClientVersion() < EQEmu::versions::ClientVersion::RoF2) + continue; + if (!GetSkill(skills_iter.first) && !MaxSkill(skills_iter.first)) + continue; + + WindowText += skills_iter.second; + // line up the values + WindowText += "      "; + WindowText += itoa(this->GetSkill(skills_iter.first)); + if (MaxSkill(skills_iter.first) > 0) { + WindowText += "/"; + WindowText += itoa(this->GetMaxSkillAfterSpecializationRules(skills_iter.first, this->MaxSkill(skills_iter.first))); } + WindowText += "
"; } this->SendPopupToClient(WindowTitle, WindowText.c_str()); } - void Client::SetShadowStepExemption(bool v) { if(v == true) @@ -4987,7 +4996,7 @@ void Client::SetShadowStepExemption(bool v) if((cur_time - m_TimeSinceLastPositionCheck) > 1000) { float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); - float runs = GetRunspeed(); + int runs = GetRunspeed(); if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) { printf("%s %i moving too fast! moved: %.2f in %ims, speed %.2f\n", __FILE__, __LINE__, @@ -5044,7 +5053,7 @@ void Client::SetKnockBackExemption(bool v) if((cur_time - m_TimeSinceLastPositionCheck) > 1000) { float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); - float runs = GetRunspeed(); + int runs = GetRunspeed(); if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) { if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) @@ -5101,7 +5110,7 @@ void Client::SetPortExemption(bool v) if((cur_time - m_TimeSinceLastPositionCheck) > 1000) { float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); - float runs = GetRunspeed(); + int runs = GetRunspeed(); if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) { if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) @@ -5329,10 +5338,10 @@ void Client::SendRewards() rewards.push_back(cr); } - if(rewards.size() == 0) + if(rewards.empty()) return; - EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(InternalVeteranReward) * rewards.size())); + auto vetapp = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(InternalVeteranReward) * rewards.size())); uchar *data = vetapp->pBuffer; for(int i = 0; i < rewards.size(); ++i) { InternalVeteranReward *ivr = (InternalVeteranReward*)data; @@ -5370,7 +5379,7 @@ bool Client::TryReward(uint32 claim_id) // save uint32 free_slot = 0xFFFFFFFF; - for (int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; ++i) { + for (int i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; ++i) { ItemInst *item = GetInv().GetItem(i); if (!item) { free_slot = i; @@ -5682,12 +5691,12 @@ void Client::AddCrystals(uint32 Radiant, uint32 Ebon) // Processes a client request to inspect a SoF+ client's equipment. void Client::ProcessInspectRequest(Client* requestee, Client* requester) { if(requestee && requester) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_InspectAnswer, sizeof(InspectResponse_Struct)); + auto outapp = new EQApplicationPacket(OP_InspectAnswer, sizeof(InspectResponse_Struct)); InspectResponse_Struct* insr = (InspectResponse_Struct*) outapp->pBuffer; insr->TargetID = requester->GetID(); insr->playerid = requestee->GetID(); - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; const ItemInst* inst = nullptr; int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); for(int16 L = 0; L <= 20; L++) { @@ -5699,14 +5708,14 @@ void Client::ProcessInspectRequest(Client* requestee, Client* requester) { strcpy(insr->itemnames[L], item->Name); if (inst && inst->GetOrnamentationAug(ornamentationAugtype)) { - const Item_Struct *aug_item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); + const EQEmu::ItemBase *aug_item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); insr->itemicons[L] = aug_item->Icon; } else if (inst && inst->GetOrnamentationIcon()) { insr->itemicons[L] = inst->GetOrnamentationIcon(); - } - else + } + else { insr->itemicons[L] = item->Icon; } @@ -5716,30 +5725,30 @@ void Client::ProcessInspectRequest(Client* requestee, Client* requester) { } } - inst = requestee->GetInv().GetItem(MainPowerSource); + inst = requestee->GetInv().GetItem(EQEmu::legacy::SlotPowerSource); if(inst) { item = inst->GetItem(); if(item) { // we shouldn't do this..but, that's the way it's coded atm... // (this type of action should be handled exclusively in the client translator) - strcpy(insr->itemnames[SoF::slots::MainPowerSource], item->Name); - insr->itemicons[SoF::slots::MainPowerSource] = item->Icon; + strcpy(insr->itemnames[SoF::invslot::PossessionsPowerSource], item->Name); + insr->itemicons[SoF::invslot::PossessionsPowerSource] = item->Icon; } else - insr->itemicons[SoF::slots::MainPowerSource] = 0xFFFFFFFF; + insr->itemicons[SoF::invslot::PossessionsPowerSource] = 0xFFFFFFFF; } - inst = requestee->GetInv().GetItem(MainAmmo); + inst = requestee->GetInv().GetItem(EQEmu::legacy::SlotAmmo); if(inst) { item = inst->GetItem(); if(item) { - strcpy(insr->itemnames[SoF::slots::MainAmmo], item->Name); - insr->itemicons[SoF::slots::MainAmmo] = item->Icon; + strcpy(insr->itemnames[SoF::invslot::PossessionsAmmo], item->Name); + insr->itemicons[SoF::invslot::PossessionsAmmo] = item->Icon; } else - insr->itemicons[SoF::slots::MainAmmo] = 0xFFFFFFFF; + insr->itemicons[SoF::invslot::PossessionsAmmo] = 0xFFFFFFFF; } strcpy(insr->text, requestee->GetInspectMessage().text); @@ -5754,7 +5763,7 @@ void Client::ProcessInspectRequest(Client* requestee, Client* requester) { void Client::GuildBankAck() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankAck_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankAck_Struct)); GuildBankAck_Struct *gbas = (GuildBankAck_Struct*) outapp->pBuffer; @@ -5766,7 +5775,7 @@ void Client::GuildBankAck() void Client::GuildBankDepositAck(bool Fail, int8 action) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankDepositAck_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankDepositAck_Struct)); GuildBankDepositAck_Struct *gbdas = (GuildBankDepositAck_Struct*) outapp->pBuffer; @@ -5779,7 +5788,7 @@ void Client::GuildBankDepositAck(bool Fail, int8 action) void Client::ClearGuildBank() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankClear_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankClear_Struct)); GuildBankClear_Struct *gbcs = (GuildBankClear_Struct*) outapp->pBuffer; @@ -5794,7 +5803,7 @@ void Client::SendGroupCreatePacket() { // For SoD and later clients, this is sent the Group Leader upon initial creation of the group // - EQApplicationPacket *outapp=new EQApplicationPacket(OP_GroupUpdateB, 32 + strlen(GetName())); + auto outapp = new EQApplicationPacket(OP_GroupUpdateB, 32 + strlen(GetName())); char *Buffer = (char *)outapp->pBuffer; // Header @@ -5820,7 +5829,7 @@ void Client::SendGroupLeaderChangePacket(const char *LeaderName) { // For SoD and later, send name of Group Leader to this client - EQApplicationPacket *outapp=new EQApplicationPacket(OP_GroupLeaderChange, sizeof(GroupLeaderChange_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupLeaderChange, sizeof(GroupLeaderChange_Struct)); GroupLeaderChange_Struct *glcs = (GroupLeaderChange_Struct*)outapp->pBuffer; @@ -5832,14 +5841,14 @@ void Client::SendGroupLeaderChangePacket(const char *LeaderName) void Client::SendGroupJoinAcknowledge() { // For SoD and later, This produces the 'You have joined the group' message. - EQApplicationPacket* outapp=new EQApplicationPacket(OP_GroupAcknowledge, 4); + auto outapp = new EQApplicationPacket(OP_GroupAcknowledge, 4); FastQueuePacket(&outapp); } void Client::SendAdventureError(const char *error) { size_t error_size = strlen(error); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureInfo, (error_size + 2)); + auto outapp = new EQApplicationPacket(OP_AdventureInfo, (error_size + 2)); strn0cpy((char*)outapp->pBuffer, error, error_size); FastQueuePacket(&outapp); } @@ -5849,7 +5858,7 @@ void Client::SendAdventureDetails() if(adv_data) { ServerSendAdventureData_Struct *ad = (ServerSendAdventureData_Struct*)adv_data; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureData, sizeof(AdventureRequestResponse_Struct)); + auto outapp = new EQApplicationPacket(OP_AdventureData, sizeof(AdventureRequestResponse_Struct)); AdventureRequestResponse_Struct *arr = (AdventureRequestResponse_Struct*)outapp->pBuffer; arr->unknown000 = 0xBFC40100; arr->unknown2080 = 0x0A; @@ -5878,14 +5887,14 @@ void Client::SendAdventureDetails() else { ServerSendAdventureData_Struct *ad = (ServerSendAdventureData_Struct*)adv_data; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureData, sizeof(AdventureRequestResponse_Struct)); + auto outapp = new EQApplicationPacket(OP_AdventureData, sizeof(AdventureRequestResponse_Struct)); FastQueuePacket(&outapp); } } void Client::SendAdventureCount(uint32 count, uint32 total) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureUpdate, sizeof(AdventureCountUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_AdventureUpdate, sizeof(AdventureCountUpdate_Struct)); AdventureCountUpdate_Struct *acu = (AdventureCountUpdate_Struct*)outapp->pBuffer; acu->current = count; acu->total = total; @@ -5895,7 +5904,7 @@ void Client::SendAdventureCount(uint32 count, uint32 total) void Client::NewAdventure(int id, int theme, const char *text, int member_count, const char *members) { size_t text_size = strlen(text); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureDetails, text_size + 2); + auto outapp = new EQApplicationPacket(OP_AdventureDetails, text_size + 2); strn0cpy((char*)outapp->pBuffer, text, text_size); FastQueuePacket(&outapp); @@ -5937,7 +5946,7 @@ void Client::LeaveAdventure() if(!GetPendingAdventureLeave()) { PendingAdventureLeave(); - ServerPacket *pack = new ServerPacket(ServerOP_AdventureLeave, 64); + auto pack = new ServerPacket(ServerOP_AdventureLeave, 64); strcpy((char*)pack->pBuffer, GetName()); pack->Deflate(); worldserver.SendPacket(pack); @@ -5974,7 +5983,7 @@ void Client::ClearCurrentAdventure() void Client::AdventureFinish(bool win, int theme, int points) { UpdateLDoNPoints(points, theme); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureFinish, sizeof(AdventureFinish_Struct)); + auto outapp = new EQApplicationPacket(OP_AdventureFinish, sizeof(AdventureFinish_Struct)); AdventureFinish_Struct *af = (AdventureFinish_Struct*)outapp->pBuffer; af->win_lose = win ? 1 : 0; af->points = points; @@ -6070,7 +6079,8 @@ void Client::CheckEmoteHail(Mob *target, const char* message) void Client::MarkSingleCompassLoc(float in_x, float in_y, float in_z, uint8 count) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_DzCompass, sizeof(ExpeditionInfo_Struct) + sizeof(ExpeditionCompassEntry_Struct) * count); + auto outapp = new EQApplicationPacket(OP_DzCompass, sizeof(ExpeditionInfo_Struct) + + sizeof(ExpeditionCompassEntry_Struct) * count); ExpeditionCompass_Struct *ecs = (ExpeditionCompass_Struct*)outapp->pBuffer; //ecs->clientid = GetID(); ecs->count = count; @@ -6093,7 +6103,7 @@ void Client::SendZonePoints() while(iterator.MoreElements()) { ZonePoint* data = iterator.GetData(); - if(GetClientVersionBit() & data->client_version_mask) + if(ClientVersionBit() & data->client_version_mask) { count++; } @@ -6101,7 +6111,7 @@ void Client::SendZonePoints() } uint32 zpsize = sizeof(ZonePoints) + ((count + 1) * sizeof(ZonePoint_Entry)); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendZonepoints, zpsize); + auto outapp = new EQApplicationPacket(OP_SendZonepoints, zpsize); ZonePoints* zp = (ZonePoints*)outapp->pBuffer; zp->count = count; @@ -6110,7 +6120,7 @@ void Client::SendZonePoints() while(iterator.MoreElements()) { ZonePoint* data = iterator.GetData(); - if(GetClientVersionBit() & data->client_version_mask) + if(ClientVersionBit() & data->client_version_mask) { zp->zpe[i].iterator = data->number; zp->zpe[i].x = data->target_x; @@ -6128,7 +6138,7 @@ void Client::SendZonePoints() void Client::SendTargetCommand(uint32 EntityID) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TargetCommand, sizeof(ClientTarget_Struct)); + auto outapp = new EQApplicationPacket(OP_TargetCommand, sizeof(ClientTarget_Struct)); ClientTarget_Struct *cts = (ClientTarget_Struct*)outapp->pBuffer; cts->new_target = EntityID; FastQueuePacket(&outapp); @@ -6271,8 +6281,8 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid made_npc->Corrup = GetCorrup(); made_npc->PhR = GetPhR(); // looks - made_npc->texture = GetEquipmentMaterial(MaterialChest); - made_npc->helmtexture = GetEquipmentMaterial(MaterialHead); + made_npc->texture = GetEquipmentMaterial(EQEmu::textures::TextureChest); + made_npc->helmtexture = GetEquipmentMaterial(EQEmu::textures::TextureHead); made_npc->haircolor = GetHairColor(); made_npc->beardcolor = GetBeardColor(); made_npc->eyecolor1 = GetEyeColor1(); @@ -6283,10 +6293,10 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid made_npc->drakkin_heritage = GetDrakkinHeritage(); made_npc->drakkin_tattoo = GetDrakkinTattoo(); made_npc->drakkin_details = GetDrakkinDetails(); - made_npc->d_melee_texture1 = GetEquipmentMaterial(MaterialPrimary); - made_npc->d_melee_texture2 = GetEquipmentMaterial(MaterialSecondary); - for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) { - made_npc->armor_tint[i] = GetEquipmentColor(i); + made_npc->d_melee_texture1 = GetEquipmentMaterial(EQEmu::textures::TexturePrimary); + made_npc->d_melee_texture2 = GetEquipmentMaterial(EQEmu::textures::TextureSecondary); + for (int i = EQEmu::textures::TextureBegin; i <= EQEmu::textures::LastTexture; i++) { + made_npc->armor_tint.Slot[i].Color = GetEquipmentColor(i); } made_npc->loottable_id = 0; @@ -6318,7 +6328,7 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid FlyMode3); if(!npca->GetSwarmInfo()){ - AA_SwarmPetInfo* nSI = new AA_SwarmPetInfo; + auto nSI = new AA_SwarmPetInfo; npca->SetSwarmInfo(nSI); npca->GetSwarmInfo()->duration = new Timer(pet_duration*1000); } @@ -6751,7 +6761,7 @@ void Client::SendStatsWindow(Client* client, bool use_window) }; std::string skill_mods = ""; - for(int j = 0; j <= HIGHEST_SKILL; j++) { + for (int j = 0; j <= EQEmu::skills::HIGHEST_SKILL; j++) { if(itembonuses.skillmod[j] > 0) skill_mods += indP + skill_list[j] + " : +" + itoa(itembonuses.skillmod[j]) + "%
"; else if(itembonuses.skillmod[j] < 0) @@ -6759,7 +6769,7 @@ void Client::SendStatsWindow(Client* client, bool use_window) } std::string skill_dmgs = ""; - for(int j = 0; j <= HIGHEST_SKILL; j++) { + for (int j = 0; j <= EQEmu::skills::HIGHEST_SKILL; j++) { if((itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]) > 0) skill_dmgs += indP + skill_list[j] + " : +" + itoa(itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]) + "
"; else if((itembonuses.SkillDamageAmount[j] + spellbonuses.SkillDamageAmount[j]) < 0) @@ -6769,10 +6779,7 @@ void Client::SendStatsWindow(Client* client, bool use_window) std::string faction_item_string = ""; char faction_buf[256]; - for(std::map ::iterator iter = item_faction_bonuses.begin(); - iter != item_faction_bonuses.end(); - ++iter) - { + for (auto iter = item_faction_bonuses.begin(); iter != item_faction_bonuses.end(); ++iter) { memset(&faction_buf, 0, sizeof(faction_buf)); if(!database.GetFactionName((int32)((*iter).first), faction_buf, sizeof(faction_buf))) @@ -6806,7 +6813,8 @@ void Client::SendStatsWindow(Client* client, bool use_window) /* AC */ indP << "AC: " << CalcAC() << "
" << /* AC2 */ indP << "- Mit: " << GetACMit() << " | Avoid: " << GetACAvoid() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "
" << /* Haste */ indP << "Haste: " << GetHaste() << "
" << - /* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "

" << + /* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "
" << + /* RunSpeed*/ indP << "Runspeed: " << GetRunspeed() << "
" << /* RegenLbl */ indL << indS << "Regen
" << indS << indP << indP << " Base | Items (Cap) " << indP << " | Spell | A.A.s | Total
" << /* Regen */ regen_string << "
" << /* Stats */ stat_field << "

" << @@ -6829,7 +6837,7 @@ void Client::SendStatsWindow(Client* client, bool use_window) if(use_window) { if(final_stats.size() < 4096) { - uint32 Buttons = (client->GetClientVersion() < ClientVersion::SoD) ? 0 : 1; + uint32 Buttons = (client->ClientVersion() < EQEmu::versions::ClientVersion::SoD) ? 0 : 1; client->SendWindow(0, POPUPID_UPDATE_SHOWSTATSWINDOW, Buttons, "Cancel", "Update", 0, 1, this, "", "%s", final_stats.c_str()); goto Extra_Info; } @@ -6865,22 +6873,23 @@ void Client::SendStatsWindow(Client* client, bool use_window) } void Client::SendAltCurrencies() { - if(GetClientVersion() >= ClientVersion::SoF) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { uint32 count = zone->AlternateCurrencies.size(); if(count == 0) { return; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_AltCurrency, - sizeof(AltCurrencyPopulate_Struct) + sizeof(AltCurrencyPopulateEntry_Struct) * count); + auto outapp = + new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyPopulate_Struct) + + sizeof(AltCurrencyPopulateEntry_Struct) * count); AltCurrencyPopulate_Struct *altc = (AltCurrencyPopulate_Struct*)outapp->pBuffer; altc->opcode = ALT_CURRENCY_OP_POPULATE; altc->count = count; uint32 i = 0; - std::list::iterator iter = zone->AlternateCurrencies.begin(); + auto iter = zone->AlternateCurrencies.begin(); while(iter != zone->AlternateCurrencies.end()) { - const Item_Struct* item = database.GetItem((*iter).item_id); + const EQEmu::ItemBase* item = database.GetItem((*iter).item_id); altc->entries[i].currency_number = (*iter).id; altc->entries[i].unknown00 = 1; altc->entries[i].currency_number2 = (*iter).id; @@ -6929,7 +6938,7 @@ void Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 me } int new_value = 0; - std::map::iterator iter = alternate_currency.find(currency_id); + auto iter = alternate_currency.find(currency_id); if(iter == alternate_currency.end()) { new_value = amount; } else { @@ -6948,7 +6957,7 @@ void Client::AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 me void Client::SendAlternateCurrencyValues() { - std::list::iterator iter = zone->AlternateCurrencies.begin(); + auto iter = zone->AlternateCurrencies.begin(); while(iter != zone->AlternateCurrencies.end()) { SendAlternateCurrencyValue((*iter).id, false); ++iter; @@ -6959,7 +6968,7 @@ void Client::SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null) { uint32 value = GetAlternateCurrencyValue(currency_id); if(value > 0 || (value == 0 && send_if_null)) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_AltCurrency, sizeof(AltCurrencyUpdate_Struct)); AltCurrencyUpdate_Struct *update = (AltCurrencyUpdate_Struct*)outapp->pBuffer; update->opcode = 7; strcpy(update->name, GetName()); @@ -6972,7 +6981,7 @@ void Client::SendAlternateCurrencyValue(uint32 currency_id, bool send_if_null) uint32 Client::GetAlternateCurrencyValue(uint32 currency_id) const { - std::map::const_iterator iter = alternate_currency.find(currency_id); + auto iter = alternate_currency.find(currency_id); if(iter == alternate_currency.end()) { return 0; } else { @@ -6992,7 +7001,7 @@ void Client::ProcessAlternateCurrencyQueue() { void Client::OpenLFGuildWindow() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LFGuild, 8); + auto outapp = new EQApplicationPacket(OP_LFGuild, 8); outapp->WriteUInt32(6); @@ -7041,7 +7050,7 @@ void Client::UpdateClientXTarget(Client *c) } } -void Client::AddAutoXTarget(Mob *m) +void Client::AddAutoXTarget(Mob *m, bool send) { if(!XTargettingAvailable() || !XTargetAutoAddHaters) return; @@ -7054,7 +7063,10 @@ void Client::AddAutoXTarget(Mob *m) if((XTargets[i].Type == Auto) && (XTargets[i].ID == 0)) { XTargets[i].ID = m->GetID(); - SendXTargetPacket(i, m); + if (send) // if we don't send we're bulk sending updates later on + SendXTargetPacket(i, m); + else + XTargets[i].dirty = true; break; } } @@ -7062,42 +7074,60 @@ void Client::AddAutoXTarget(Mob *m) void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots) { - if(!XTargettingAvailable()) + if (!XTargettingAvailable()) return; bool HadFreeAutoSlotsBefore = false; int FreedAutoSlots = 0; - if(m->GetID() == 0) + if (m->GetID() == 0) return; - for(int i = 0; i < GetMaxXTargets(); ++i) - { - if(OnlyAutoSlots && (XTargets[i].Type !=Auto)) + for (int i = 0; i < GetMaxXTargets(); ++i) { + if (OnlyAutoSlots && XTargets[i].Type != Auto) continue; - if(XTargets[i].ID == m->GetID()) - { - if(XTargets[i].Type == CurrentTargetNPC) + if (XTargets[i].ID == m->GetID()) { + if (XTargets[i].Type == CurrentTargetNPC) XTargets[i].Type = Auto; - if(XTargets[i].Type == Auto) + if (XTargets[i].Type == Auto) ++FreedAutoSlots; XTargets[i].ID = 0; - - SendXTargetPacket(i, nullptr); - } - else - { - if((XTargets[i].Type == Auto) && (XTargets[i].ID == 0)) + XTargets[i].dirty = true; + } else { + if (XTargets[i].Type == Auto && XTargets[i].ID == 0) HadFreeAutoSlotsBefore = true; } } - // If there are more mobs aggro on us than we had auto-hate slots, add one of those haters into the slot(s) we just freed up. - if(!HadFreeAutoSlotsBefore && FreedAutoSlots) + + // move shit up! If the removed NPC was in a CurrentTargetNPC slot it becomes Auto + // and we need to potentially fill it + std::queue empty_slots; + for (int i = 0; i < GetMaxXTargets(); ++i) { + if (XTargets[i].Type != Auto) + continue; + + if (XTargets[i].ID == 0) { + empty_slots.push(i); + continue; + } + + if (XTargets[i].ID != 0 && !empty_slots.empty()) { + int temp = empty_slots.front(); + std::swap(XTargets[i], XTargets[temp]); + XTargets[i].dirty = XTargets[temp].dirty = true; + empty_slots.pop(); + empty_slots.push(i); + } + } + // If there are more mobs aggro on us than we had auto-hate slots, add one of those haters into the slot(s) we + // just freed up. + if (!HadFreeAutoSlotsBefore && FreedAutoSlots) entity_list.RefreshAutoXTargets(this); + SendXTargetUpdates(); } void Client::UpdateXTargetType(XTargetType Type, Mob *m, const char *Name) @@ -7136,7 +7166,7 @@ void Client::SendXTargetPacket(uint32 Slot, Mob *m) PacketSize += strlen(XTargets[Slot].Name); } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_XTargetResponse, PacketSize); + auto outapp = new EQApplicationPacket(OP_XTargetResponse, PacketSize); outapp->WriteUInt32(GetMaxXTargets()); outapp->WriteUInt32(1); outapp->WriteUInt32(Slot); @@ -7166,6 +7196,46 @@ void Client::SendXTargetPacket(uint32 Slot, Mob *m) FastQueuePacket(&outapp); } +// This is a bulk packet, we use it when we remove something since we need to reorder the xtargets and maybe +// add new mobs! Currently doesn't check if there is a dirty flag set, so it should only be called when there is +void Client::SendXTargetUpdates() +{ + if (!XTargettingAvailable()) + return; + + int count = 0; + // header is 4 bytes max xtargets, 4 bytes count + // entry is 4 bytes slot, 1 byte unknown, 4 bytes ID, 65 char name + auto outapp = new EQApplicationPacket(OP_XTargetResponse, 8 + 74 * GetMaxXTargets()); // fuck it max size + outapp->WriteUInt32(GetMaxXTargets()); + outapp->WriteUInt32(1); // we will correct this later + for (int i = 0; i < GetMaxXTargets(); ++i) { + if (XTargets[i].dirty) { + outapp->WriteUInt32(i); + outapp->WriteUInt8(0); // no idea what this is + outapp->WriteUInt32(XTargets[i].ID); + outapp->WriteString(XTargets[i].Name); + count++; + XTargets[i].dirty = false; + } + } + + // RemoveXTarget probably got called with a mob not on our xtargets + if (count == 0) { + safe_delete(outapp); + return; + } + + auto newbuff = new uchar[outapp->GetWritePosition()]; + memcpy(newbuff, outapp->pBuffer, outapp->GetWritePosition()); + safe_delete_array(outapp->pBuffer); + outapp->pBuffer = newbuff; + outapp->size = outapp->GetWritePosition(); + outapp->SetWritePosition(4); + outapp->WriteUInt32(count); + FastQueuePacket(&outapp); +} + void Client::RemoveGroupXTargets() { if(!XTargettingAvailable()) @@ -7234,7 +7304,7 @@ void Client::SetMaxXTargets(uint8 NewMax) XTargets[i].Name[0] = 0; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_XTargetResponse, 8); + auto outapp = new EQApplicationPacket(OP_XTargetResponse, 8); outapp->WriteUInt32(GetMaxXTargets()); outapp->WriteUInt32(0); FastQueuePacket(&outapp); @@ -7326,7 +7396,7 @@ void Client::SendWebLink(const char *website) size_t len = strlen(website) + 1; if(website != 0 && len > 1) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weblink, sizeof(Weblink_Struct) + len); + auto outapp = new EQApplicationPacket(OP_Weblink, sizeof(Weblink_Struct) + len); Weblink_Struct *wl = (Weblink_Struct*)outapp->pBuffer; memcpy(wl->weblink, website, len); wl->weblink[len] = '\0'; @@ -7355,11 +7425,12 @@ void Client::SendMercPersonalInfo() if(mercData) { - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { if (mercCount > 0) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, sizeof(MercenaryDataUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_MercenaryDataUpdate, sizeof(MercenaryDataUpdate_Struct)); MercenaryDataUpdate_Struct* mdus = (MercenaryDataUpdate_Struct*)outapp->pBuffer; mdus->MercStatus = 0; mdus->MercCount = mercCount; @@ -7383,7 +7454,7 @@ void Client::SendMercPersonalInfo() uint32 stanceindex = 0; if (mdus->MercData[i].StanceCount != 0) { - std::list::iterator iter = zone->merc_stance_list[mercData->MercTemplateID].begin(); + auto iter = zone->merc_stance_list[mercData->MercTemplateID].begin(); while(iter != zone->merc_stance_list[mercData->MercTemplateID].end()) { mdus->MercData[i].Stances[stanceindex].StanceIndex = stanceindex; @@ -7403,7 +7474,8 @@ void Client::SendMercPersonalInfo() { if(mercTypeCount > 0 && mercCount > 0) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, sizeof(MercenaryMerchantList_Struct)); + auto outapp = new EQApplicationPacket(OP_MercenaryDataResponse, + sizeof(MercenaryMerchantList_Struct)); MercenaryMerchantList_Struct* mml = (MercenaryMerchantList_Struct*)outapp->pBuffer; mml->MercTypeCount = mercTypeCount; //We should only have one merc entry. mml->MercGrades[i] = 1; @@ -7428,7 +7500,7 @@ void Client::SendMercPersonalInfo() int stanceindex = 0; if(mml->Mercs[i].StanceCount != 0) { - std::list::iterator iter = zone->merc_stance_list[mercData->MercTemplateID].begin(); + auto iter = zone->merc_stance_list[mercData->MercTemplateID].begin(); while(iter != zone->merc_stance_list[mercData->MercTemplateID].end()) { mml->Mercs[i].Stances[stanceindex].StanceIndex = stanceindex; @@ -7455,7 +7527,7 @@ void Client::SendMercPersonalInfo() void Client::SendClearMercInfo() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, sizeof(NoMercenaryHired_Struct)); + auto outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, sizeof(NoMercenaryHired_Struct)); NoMercenaryHired_Struct *nmhs = (NoMercenaryHired_Struct*)outapp->pBuffer; nmhs->MercStatus = -1; nmhs->MercCount = 0; @@ -7466,13 +7538,13 @@ void Client::SendClearMercInfo() void Client::DuplicateLoreMessage(uint32 ItemID) { - if (!(m_ClientVersionBit & BIT_RoFAndLater)) + if (!(m_ClientVersionBit & EQEmu::versions::bit_RoFAndLater)) { Message_StringID(0, PICK_LORE); return; } - const Item_Struct *item = database.GetItem(ItemID); + const EQEmu::ItemBase *item = database.GetItem(ItemID); if(!item) return; @@ -7487,16 +7559,25 @@ void Client::GarbleMessage(char *message, uint8 variance) const char delimiter = 0x12; int delimiter_count = 0; + // Don't garble # commands + if (message[0] == COMMAND_CHAR) + return; + +#ifdef BOTS + if (message[0] == BOT_COMMAND_CHAR) + return; +#endif + for (size_t i = 0; i < strlen(message); i++) { // Client expects hex values inside of a text link body if (message[i] == delimiter) { - if (!(delimiter_count & 1)) { i += EmuConstants::TEXT_LINK_BODY_LENGTH; } + if (!(delimiter_count & 1)) { i += EQEmu::legacy::TEXT_LINK_BODY_LENGTH; } ++delimiter_count; continue; } uint8 chance = (uint8)zone->random.Int(0, 115); // variation just over worst possible scrambling - if (isalpha(message[i]) && (chance <= variance)) { + if (isalpha((unsigned char)message[i]) && (chance <= variance)) { uint8 rand_char = (uint8)zone->random.Int(0,51); // choose a random character from the alpha list message[i] = alpha_list[rand_char]; } @@ -7580,7 +7661,7 @@ FACTION_VALUE Client::GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_ra } //Sets the characters faction standing with the specified NPC. -void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity) +void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity, bool quest) { int32 faction_id[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int32 npc_value[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -7604,9 +7685,18 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui // Find out starting faction for this faction // It needs to be used to adj max and min personal // The range is still the same, 1200-3000(4200), but adjusted for base - database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(), + database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(), faction_id[i]); + if (quest) + { + //The ole switcheroo + if (npc_value[i] > 0) + npc_value[i] = -abs(npc_value[i]); + else if (npc_value[i] < 0) + npc_value[i] = abs(npc_value[i]); + } + // Adjust the amount you can go up or down so the resulting range // is PERSONAL_MAX - PERSONAL_MIN // @@ -7645,7 +7735,7 @@ void Client::SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class // Find out starting faction for this faction // It needs to be used to adj max and min personal // The range is still the same, 1200-3000(4200), but adjusted for base - database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(), + database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(), faction_id); // Adjust the amount you can go up or down so the resulting range @@ -7763,7 +7853,8 @@ void Client::MerchantRejectMessage(Mob *merchant, int primaryfaction) if (primaryfaction > 0) { if (database.GetFactionData(&fmod, GetClass(), GetRace(), GetDeity(), primaryfaction)) { tmpFactionValue = GetCharacterFactionLevel(primaryfaction); - lowestvalue = std::min(tmpFactionValue, std::min(fmod.class_mod, fmod.race_mod)); + lowestvalue = std::min(std::min(tmpFactionValue, fmod.deity_mod), + std::min(fmod.class_mod, fmod.race_mod)); } } // If no primary faction or biggest influence is your faction hit @@ -7811,6 +7902,11 @@ void Client::MerchantRejectMessage(Mob *merchant, int primaryfaction) } } else if (lowestvalue == fmod.class_mod) { merchant->Say_StringID(zone->random.Int(WONT_SELL_CLASS1, WONT_SELL_CLASS5), itoa(GetClass())); + } else { + // Must be deity - these two sound the best for that. + // Can't use a message with a field, GUI wants class/race names. + // for those message IDs. These are straight text. + merchant->Say_StringID(zone->random.Int(WONT_SELL_DEEDS1, WONT_SELL_DEEDS2)); } return; } @@ -7825,14 +7921,14 @@ void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_ char name[50]; int32 faction_value; - // If we're dropping from MAX or raising from MIN or repairing, + // If we're dropping from MAX or raising from MIN or repairing, // we should base the message on the new updated value so we don't show // a min MAX message // // If we're changing any other place, we use the value before the // hit. For example, if we go from 1199 to 1200 which is the MAX // we still want to say faction got better this time around. - + if ( (faction_before_hit >= this_faction_max) || (faction_before_hit <= this_faction_min)) faction_value = totalvalue; @@ -7900,17 +7996,17 @@ void Client::TickItemCheck() if(zone->tick_items.empty()) { return; } //Scan equip slots for items - for(i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; i++) + for (i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= EQEmu::legacy::EQUIPMENT_END; i++) { TryItemTick(i); } //Scan main inventory + cursor - for(i = EmuConstants::GENERAL_BEGIN; i <= MainCursor; i++) + for (i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::SlotCursor; i++) { TryItemTick(i); } //Scan bags - for(i = EmuConstants::GENERAL_BAGS_BEGIN; i <= EmuConstants::CURSOR_BAG_END; i++) + for (i = EQEmu::legacy::GENERAL_BAGS_BEGIN; i <= EQEmu::legacy::CURSOR_BAG_END; i++) { TryItemTick(i); } @@ -7926,7 +8022,7 @@ void Client::TryItemTick(int slot) if(zone->tick_items.count(iid) > 0) { - if( GetLevel() >= zone->tick_items[iid].level && zone->random.Int(0, 100) >= (100 - zone->tick_items[iid].chance) && (zone->tick_items[iid].bagslot || slot <= EmuConstants::EQUIPMENT_END) ) + if (GetLevel() >= zone->tick_items[iid].level && zone->random.Int(0, 100) >= (100 - zone->tick_items[iid].chance) && (zone->tick_items[iid].bagslot || slot <= EQEmu::legacy::EQUIPMENT_END)) { ItemInst* e_inst = (ItemInst*)inst; parse->EventItem(EVENT_ITEM_TICK, this, e_inst, nullptr, "", slot); @@ -7934,9 +8030,9 @@ void Client::TryItemTick(int slot) } //Only look at augs in main inventory - if(slot > EmuConstants::EQUIPMENT_END) { return; } + if (slot > EQEmu::legacy::EQUIPMENT_END) { return; } - for (int x = AUG_BEGIN; x < EmuConstants::ITEM_COMMON_SIZE; ++x) + for (int x = AUG_INDEX_BEGIN; x < EQEmu::legacy::ITEM_COMMON_SIZE; ++x) { ItemInst * a_inst = inst->GetAugment(x); if(!a_inst) { continue; } @@ -7957,17 +8053,17 @@ void Client::TryItemTick(int slot) void Client::ItemTimerCheck() { int i; - for(i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; i++) + for (i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= EQEmu::legacy::EQUIPMENT_END; i++) { TryItemTimer(i); } - for(i = EmuConstants::GENERAL_BEGIN; i <= MainCursor; i++) + for (i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::SlotCursor; i++) { TryItemTimer(i); } - for(i = EmuConstants::GENERAL_BAGS_BEGIN; i <= EmuConstants::CURSOR_BAG_END; i++) + for (i = EQEmu::legacy::GENERAL_BAGS_BEGIN; i <= EQEmu::legacy::CURSOR_BAG_END; i++) { TryItemTimer(i); } @@ -7989,11 +8085,11 @@ void Client::TryItemTimer(int slot) ++it_iter; } - if(slot > EmuConstants::EQUIPMENT_END) { + if (slot > EQEmu::legacy::EQUIPMENT_END) { return; } - for (int x = AUG_BEGIN; x < EmuConstants::ITEM_COMMON_SIZE; ++x) + for (int x = AUG_INDEX_BEGIN; x < EQEmu::legacy::ITEM_COMMON_SIZE; ++x) { ItemInst * a_inst = inst->GetAugment(x); if(!a_inst) { @@ -8011,56 +8107,6 @@ void Client::TryItemTimer(int slot) } } -void Client::RefundAA() { - int cur = 0; - bool refunded = false; - - for(int x = 0; x < aaHighestID; x++) { - cur = GetAA(x); - if(cur > 0){ - SendAA_Struct* curaa = zone->FindAA(x); - if(cur){ - SetAA(x, 0); - for(int j = 0; j < cur; j++) { - m_pp.aapoints += curaa->cost + (curaa->cost_inc * j); - refunded = true; - } - } - else - { - m_pp.aapoints += cur; - SetAA(x, 0); - refunded = true; - } - } - } - - if(refunded) { - SaveAA(); - Save(); - // Kick(); - } -} - -void Client::IncrementAA(int aa_id) { - SendAA_Struct* aa2 = zone->FindAA(aa_id); - - if(aa2 == nullptr) - return; - - if(GetAA(aa_id) == aa2->max_level) - return; - - SetAA(aa_id, GetAA(aa_id) + 1); - - SaveAA(); - - SendAA(aa_id); - SendAATable(); - SendAAStats(); - CalcBonuses(); -} - void Client::SendItemScale(ItemInst *inst) { int slot = m_inv.GetSlotByItemInst(inst); if(slot != -1) { @@ -8215,7 +8261,7 @@ void Client::SetConsumption(int32 in_hunger, int32 in_thirst) safe_delete(outapp); } -void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_consume) +void Client::Consume(const EQEmu::ItemBase *item, uint8 type, int16 slot, bool auto_consume) { if(!item) { return; } @@ -8228,7 +8274,7 @@ void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_ else cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100; - if(type == ItemTypeFood) + if (type == EQEmu::item::ItemTypeFood) { int hchange = item->CastTime * cons_mod; hchange = mod_food_value(item, hchange); @@ -8287,7 +8333,7 @@ void Client::SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, ui void Client::PlayMP3(const char* fname) { std::string filename = fname; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_PlayMP3, filename.length() + 1); + auto outapp = new EQApplicationPacket(OP_PlayMP3, filename.length() + 1); PlayMP3_Struct* buf = (PlayMP3_Struct*)outapp->pBuffer; strncpy(buf->filename, fname, filename.length()); QueuePacket(outapp); @@ -8328,21 +8374,19 @@ void Client::ShowNumHits() return; } -float Client::GetQuiverHaste() +int Client::GetQuiverHaste(int delay) { - float quiver_haste = 0; - for (int r = EmuConstants::GENERAL_BEGIN; r <= EmuConstants::GENERAL_END; r++) { - const ItemInst *pi = GetInv().GetItem(r); - if (!pi) - continue; - if (pi->IsType(ItemClassContainer) && pi->GetItem()->BagType == BagTypeQuiver) { - float temp_wr = (pi->GetItem()->BagWR / RuleI(Combat, QuiverWRHasteDiv)); - quiver_haste = std::max(temp_wr, quiver_haste); - } + const ItemInst *pi = nullptr; + for (int r = EQEmu::legacy::GENERAL_BEGIN; r <= EQEmu::legacy::GENERAL_END; r++) { + pi = GetInv().GetItem(r); + if (pi && pi->IsClassBag() && pi->GetItem()->BagType == EQEmu::item::BagTypeQuiver && + pi->GetItem()->BagWR > 0) + break; + if (r == EQEmu::legacy::GENERAL_END) + // we will get here if we don't find a valid quiver + return 0; } - if (quiver_haste > 0) - quiver_haste = 1.0f / (1.0f + static_cast(quiver_haste) / 100.0f); - return quiver_haste; + return (pi->GetItem()->BagWR * 0.0025f * delay) + 1; } void Client::SendColoredText(uint32 color, std::string message) @@ -8350,8 +8394,7 @@ void Client::SendColoredText(uint32 color, std::string message) // arbitrary size limit if (message.size() > 512) // live does send this with empty strings sometimes ... return; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ColoredText, - sizeof(ColoredText_Struct) + message.size()); + auto outapp = new EQApplicationPacket(OP_ColoredText, sizeof(ColoredText_Struct) + message.size()); ColoredText_Struct *cts = (ColoredText_Struct *)outapp->pBuffer; cts->color = color; strcpy(cts->msg, message.c_str()); @@ -8360,213 +8403,161 @@ void Client::SendColoredText(uint32 color, std::string message) } -// -// class Client::TextLink -// -std::string Client::TextLink::GenerateLink() -{ - m_Link.clear(); - m_LinkBody.clear(); - m_LinkText.clear(); - - generate_body(); - generate_text(); - - if ((m_LinkBody.length() == EmuConstants::TEXT_LINK_BODY_LENGTH) && (m_LinkText.length() > 0)) { - m_Link.push_back(0x12); - m_Link.append(m_LinkBody); - m_Link.append(m_LinkText); - m_Link.push_back(0x12); +void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction) { + + auto outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct)); + memset(outapp->pBuffer, 0, sizeof(QuestReward_Struct)); + QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer; + + qr->mob_id = target->GetID(); // Entity ID for the from mob name + qr->target_id = GetID(); // The Client ID (this) + qr->copper = copper; + qr->silver = silver; + qr->gold = gold; + qr->platinum = platinum; + qr->item_id = itemid; + qr->exp_reward = exp; + + if (copper > 0 || silver > 0 || gold > 0 || platinum > 0) + AddMoneyToPP(copper, silver, gold, platinum, false); + + if (itemid > 0) + SummonItem(itemid, 0, 0, 0, 0, 0, 0, false, EQEmu::legacy::SlotPowerSource); + + if (faction) + { + if (target->IsNPC()) + { + int32 nfl_id = target->CastToNPC()->GetNPCFactionID(); + SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true); + qr->faction = target->CastToNPC()->GetPrimaryFaction(); + qr->faction_mod = 1; // Too lazy to get real value, not sure if this is even used by client anyhow. + } } - if ((m_Link.length() == 0) || (m_Link.length() > 250)) { - m_Error = true; - m_Link = ""; - Log.Out(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.Out(Logs::General, Logs::Error, ">> LinkBody: %s", m_LinkBody.c_str()); - Log.Out(Logs::General, Logs::Error, ">> LinkText: %s", m_LinkText.c_str()); - } + if (exp > 0) + AddEXP(exp); - return m_Link; + QueuePacket(outapp, false, Client::CLIENT_CONNECTED); + safe_delete(outapp); } -void Client::TextLink::Reset() -{ - m_LinkType = linkBlank; - m_ItemData = nullptr; - m_LootData = nullptr; - m_ItemInst = nullptr; - m_ProxyItemID = NOT_USED; - m_ProxyText = nullptr; - m_TaskUse = false; - m_Link.clear(); - m_LinkBody.clear(); - m_LinkText.clear(); - m_Error = false; -} - -void Client::TextLink::generate_body() -{ - /* - Current server mask: EQClientRoF2 - - RoF2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X" (56) - RoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (55) - SoF: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X" (50) - 6.2: "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X" (45) - */ - - memset(&m_LinkBodyStruct, 0, sizeof(TextLinkBody_Struct)); - - const Item_Struct* item_data = nullptr; - - switch (m_LinkType) { - case linkBlank: - break; - case linkItemData: - if (m_ItemData == nullptr) { break; } - m_LinkBodyStruct.item_id = m_ItemData->ID; - m_LinkBodyStruct.evolve_group = m_ItemData->LoreGroup; // this probably won't work for all items - //m_LinkBodyStruct.evolve_level = m_ItemData->EvolvingLevel; - // TODO: add hash call - break; - case linkLootItem: - if (m_LootData == nullptr) { break; } - item_data = database.GetItem(m_LootData->item_id); - if (item_data == nullptr) { break; } - m_LinkBodyStruct.item_id = item_data->ID; - m_LinkBodyStruct.augment_1 = m_LootData->aug_1; - m_LinkBodyStruct.augment_2 = m_LootData->aug_2; - m_LinkBodyStruct.augment_3 = m_LootData->aug_3; - m_LinkBodyStruct.augment_4 = m_LootData->aug_4; - m_LinkBodyStruct.augment_5 = m_LootData->aug_5; - m_LinkBodyStruct.augment_6 = m_LootData->aug_6; - m_LinkBodyStruct.evolve_group = item_data->LoreGroup; // see note above - //m_LinkBodyStruct.evolve_level = item_data->EvolvingLevel; - // TODO: add hash call - break; - case linkItemInst: - if (m_ItemInst == nullptr) { break; } - if (m_ItemInst->GetItem() == nullptr) { break; } - m_LinkBodyStruct.item_id = m_ItemInst->GetItem()->ID; - m_LinkBodyStruct.augment_1 = m_ItemInst->GetAugmentItemID(0); - m_LinkBodyStruct.augment_2 = m_ItemInst->GetAugmentItemID(1); - m_LinkBodyStruct.augment_3 = m_ItemInst->GetAugmentItemID(2); - m_LinkBodyStruct.augment_4 = m_ItemInst->GetAugmentItemID(3); - m_LinkBodyStruct.augment_5 = m_ItemInst->GetAugmentItemID(4); - m_LinkBodyStruct.augment_6 = m_ItemInst->GetAugmentItemID(5); - m_LinkBodyStruct.is_evolving = (m_ItemInst->IsEvolving() ? 1 : 0); - m_LinkBodyStruct.evolve_group = m_ItemInst->GetItem()->LoreGroup; // see note above - m_LinkBodyStruct.evolve_level = m_ItemInst->GetEvolveLvl(); - m_LinkBodyStruct.ornament_icon = m_ItemInst->GetOrnamentationIcon(); - // TODO: add hash call - break; - default: - break; - } - - if (m_ProxyItemID != NOT_USED) { - m_LinkBodyStruct.item_id = m_ProxyItemID; - } - - if (m_TaskUse) { - m_LinkBodyStruct.hash = 0x14505DC2; - } - - m_LinkBody = StringFormat( - "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X", - (0x0F & m_LinkBodyStruct.unknown_1), - (0x000FFFFF & m_LinkBodyStruct.item_id), - (0x000FFFFF & m_LinkBodyStruct.augment_1), - (0x000FFFFF & m_LinkBodyStruct.augment_2), - (0x000FFFFF & m_LinkBodyStruct.augment_3), - (0x000FFFFF & m_LinkBodyStruct.augment_4), - (0x000FFFFF & m_LinkBodyStruct.augment_5), - (0x000FFFFF & m_LinkBodyStruct.augment_6), - (0x0F & m_LinkBodyStruct.is_evolving), - (0x0000FFFF & m_LinkBodyStruct.evolve_group), - (0xFF & m_LinkBodyStruct.evolve_level), - (0x000FFFFF & m_LinkBodyStruct.ornament_icon), - (0xFFFFFFFF & m_LinkBodyStruct.hash) - ); -} - -void Client::TextLink::generate_text() -{ - if (m_ProxyText != nullptr) { - m_LinkText = m_ProxyText; +void Client::SendHPUpdateMarquee(){ + if (!RuleB(Character, MarqueeHPUpdates)) return; + + if (!this || !this->IsClient() || !this->cur_hp || !this->max_hp) + return; + + /* Health Update Marquee Display: Custom*/ + uint32 health_percentage = (uint32)(this->cur_hp * 100 / this->max_hp); + if (health_percentage == 100) + return; + + std::string health_update_notification = StringFormat("Health: %u%%", health_percentage); + this->SendMarqueeMessage(15, 510, 0, 3000, 3000, health_update_notification); +} + +uint32 Client::GetMoney(uint8 type, uint8 subtype) { + uint32 value = 0; + switch (type) { + case 0: { + switch (subtype) { + case 0: + value = static_cast(m_pp.copper); + break; + case 1: + value = static_cast(m_pp.copper_bank); + break; + case 2: + value = static_cast(m_pp.copper_cursor); + break; + default: + break; + } + break; + } + case 1: { + switch (subtype) { + case 0: + value = static_cast(m_pp.silver); + break; + case 1: + value = static_cast(m_pp.silver_bank); + break; + case 2: + value = static_cast(m_pp.silver_cursor); + break; + default: + break; + } + break; + } + case 2: { + switch (subtype) { + case 0: + value = static_cast(m_pp.gold); + break; + case 1: + value = static_cast(m_pp.gold_bank); + break; + case 2: + value = static_cast(m_pp.gold_cursor); + break; + default: + break; + } + break; + } + case 3: { + switch (subtype) { + case 0: + value = static_cast(m_pp.platinum); + break; + case 1: + value = static_cast(m_pp.platinum_bank); + break; + case 2: + value = static_cast(m_pp.platinum_cursor); + break; + case 3: + value = static_cast(m_pp.platinum_shared); + break; + default: + break; + } + break; + } + default: + break; } - - const Item_Struct* item_data = nullptr; - - switch (m_LinkType) { - case linkBlank: - break; - case linkItemData: - if (m_ItemData == nullptr) { break; } - m_LinkText = m_ItemData->Name; - return; - case linkLootItem: - if (m_LootData == nullptr) { break; } - item_data = database.GetItem(m_LootData->item_id); - if (item_data == nullptr) { break; } - m_LinkText = item_data->Name; - return; - case linkItemInst: - if (m_ItemInst == nullptr) { break; } - if (m_ItemInst->GetItem() == nullptr) { break; } - m_LinkText = m_ItemInst->GetItem()->Name; - return; - default: - break; - } - - m_LinkText = "null"; + return value; } -bool Client::TextLink::DegenerateLinkBody(TextLinkBody_Struct& textLinkBodyStruct, const std::string& textLinkBody) +int Client::GetAccountAge() { + return (time(nullptr) - GetAccountCreation()); +} + +void Client::CheckRegionTypeChanges() { - memset(&textLinkBodyStruct, 0, sizeof(TextLinkBody_Struct)); - if (textLinkBody.length() != EmuConstants::TEXT_LINK_BODY_LENGTH) { return false; } + if (!zone->HasWaterMap()) + return; - textLinkBodyStruct.unknown_1 = (uint8)strtol(textLinkBody.substr(0, 1).c_str(), nullptr, 16); - textLinkBodyStruct.item_id = (uint32)strtol(textLinkBody.substr(1, 5).c_str(), nullptr, 16); - textLinkBodyStruct.augment_1 = (uint32)strtol(textLinkBody.substr(6, 5).c_str(), nullptr, 16); - textLinkBodyStruct.augment_2 = (uint32)strtol(textLinkBody.substr(11, 5).c_str(), nullptr, 16); - textLinkBodyStruct.augment_3 = (uint32)strtol(textLinkBody.substr(16, 5).c_str(), nullptr, 16); - textLinkBodyStruct.augment_4 = (uint32)strtol(textLinkBody.substr(21, 5).c_str(), nullptr, 16); - textLinkBodyStruct.augment_5 = (uint32)strtol(textLinkBody.substr(26, 5).c_str(), nullptr, 16); - textLinkBodyStruct.augment_6 = (uint32)strtol(textLinkBody.substr(31, 5).c_str(), nullptr, 16); - textLinkBodyStruct.is_evolving = (uint8)strtol(textLinkBody.substr(36, 1).c_str(), nullptr, 16); - textLinkBodyStruct.evolve_group = (uint32)strtol(textLinkBody.substr(37, 4).c_str(), nullptr, 16); - textLinkBodyStruct.evolve_level = (uint8)strtol(textLinkBody.substr(41, 2).c_str(), nullptr, 16); - textLinkBodyStruct.ornament_icon = (uint32)strtol(textLinkBody.substr(43, 5).c_str(), nullptr, 16); - textLinkBodyStruct.hash = (int)strtol(textLinkBody.substr(48, 8).c_str(), nullptr, 16); + auto new_region = zone->watermap->ReturnRegionType(glm::vec3(m_Position)); - return true; -} - -bool Client::TextLink::GenerateLinkBody(std::string& textLinkBody, const TextLinkBody_Struct& textLinkBodyStruct) -{ - textLinkBody = StringFormat( - "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%02X" "%05X" "%08X", - (0x0F & textLinkBodyStruct.unknown_1), - (0x000FFFFF & textLinkBodyStruct.item_id), - (0x000FFFFF & textLinkBodyStruct.augment_1), - (0x000FFFFF & textLinkBodyStruct.augment_2), - (0x000FFFFF & textLinkBodyStruct.augment_3), - (0x000FFFFF & textLinkBodyStruct.augment_4), - (0x000FFFFF & textLinkBodyStruct.augment_5), - (0x000FFFFF & textLinkBodyStruct.augment_6), - (0x0F & textLinkBodyStruct.is_evolving), - (0x0000FFFF & textLinkBodyStruct.evolve_group), - (0xFF & textLinkBodyStruct.evolve_level), - (0x000FFFFF & textLinkBodyStruct.ornament_icon), - (0xFFFFFFFF & textLinkBodyStruct.hash) - ); - - if (textLinkBody.length() != EmuConstants::TEXT_LINK_BODY_LENGTH) { return false; } - return true; + // still same region, do nothing + if (last_region_type == new_region) + return; + + // region type changed + last_region_type = new_region; + + // PVP is the only state we need to keep track of, so we can just return now for PVP servers + if (RuleI(World, PVPSettings) > 0) + return; + + if (last_region_type == RegionTypePVP) + SetPVP(true, false); + else if (GetPVP()) + SetPVP(false, false); } diff --git a/zone/client.h b/zone/client.h index 3a90e87eb..df7c1fce3 100644 --- a/zone/client.h +++ b/zone/client.h @@ -27,13 +27,18 @@ class Object; class Raid; class Seperator; class ServerPacket; -struct Item_Struct; +enum WaterRegionType : int; + +namespace EQEmu +{ + struct ItemBase; +} #include "../common/timer.h" #include "../common/ptimer.h" #include "../common/emu_opcodes.h" #include "../common/eq_packet_structs.h" -#include "../common/eq_constants.h" +#include "../common/emu_constants.h" #include "../common/eq_stream_intf.h" #include "../common/eq_packet.h" #include "../common/linked_list.h" @@ -42,10 +47,8 @@ struct Item_Struct; #include "../common/seperator.h" #include "../common/item.h" #include "../common/guilds.h" -#include "../common/item_struct.h" -#include "../common/clientversions.h" +#include "../common/item_base.h" -#include "aa.h" #include "common.h" #include "merc.h" #include "mob.h" @@ -103,6 +106,7 @@ enum { //Type arguments to the Message* routines. #define SPELLBAR_UNLOCK 0x2bc enum { //scribing argument to MemorizeSpell + memSpellUnknown = -1, // this modifies some state data memSpellScribing = 0, memSpellMemorize = 1, memSpellForget = 2, @@ -176,6 +180,7 @@ typedef enum struct XTarget_Struct { XTargetType Type; + bool dirty; uint16 ID; char Name[65]; }; @@ -215,10 +220,10 @@ public: ~Client(); //abstract virtual function implementations required by base abstract class - virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill); - virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false); - virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, - ExtraAttackOptions *opts = nullptr); + virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill); + virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0); + virtual bool Attack(Mob* other, int Hand = EQEmu::legacy::SlotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, + ExtraAttackOptions *opts = nullptr, int special = 0); virtual bool HasRaid() { return (GetRaid() ? true : false); } virtual bool HasGroup() { return (GetGroup() ? true : false); } virtual Raid* GetRaid() { return entity_list.GetRaidByClient(this); } @@ -226,7 +231,8 @@ public: virtual inline bool IsBerserk() { return berserk; } virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); virtual void SetAttackTimer(); - float GetQuiverHaste(); + int GetQuiverHaste(int delay); + void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false); void AI_Init(); void AI_Start(uint32 iMoveDelay = 0); @@ -249,7 +255,7 @@ public: void SendBuyerPacket(Client* Buyer); GetItems_Struct* GetTraderItems(); void SendBazaarWelcome(); - void DyeArmor(DyeStruct* dye); + void DyeArmor(EQEmu::TintProfile* dye); uint8 SlotConvert(uint8 slot,bool bracer=false); void Message_StringID(uint32 type, uint32 string_id, uint32 distance = 0); void Message_StringID(uint32 type, uint32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, uint32 distance = 0); @@ -288,7 +294,7 @@ public: void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); virtual bool Process(); - void LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const Item_Struct* item, bool buying); + void LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQEmu::ItemBase* item, bool buying); void SendPacketQueue(bool Block = true); void QueuePacket(const EQApplicationPacket* app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL, eqFilterType filter=FilterNone); void FastQueuePacket(EQApplicationPacket** app, bool ack_req = true, CLIENT_CONN_STATUS = CLIENT_CONNECTINGALL); @@ -300,7 +306,7 @@ public: void VoiceMacroReceived(uint32 Type, char *Target, uint32 MacroNumber); void SendSound(); void LearnRecipe(uint32 recipeID); - bool CanIncreaseTradeskill(SkillUseTypes tradeskill); + bool CanIncreaseTradeskill(EQEmu::skills::SkillType tradeskill); EQApplicationPacket* ReturnItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type); @@ -322,6 +328,7 @@ public: /* New PP Save Functions */ bool SaveCurrency(){ return database.SaveCharacterCurrency(this->CharacterID(), &m_pp); } bool SaveAA(); + void RemoveExpendedAA(int aa_id); inline bool ClientDataLoaded() const { return client_data_loaded; } inline bool Connected() const { return (client_state == CLIENT_CONNECTED); } @@ -355,9 +362,9 @@ public: int32 LevelRegen(); void HPTick(); void SetGM(bool toggle); - void SetPVP(bool toggle); + void SetPVP(bool toggle, bool message = true); - inline bool GetPVP() const { return zone->GetZoneID() == 77 ? true : (m_pp.pvp != 0); } + inline bool GetPVP() const { return m_pp.pvp != 0; } inline bool GetGM() const { return m_pp.gm != 0; } inline void SetBaseClass(uint32 i) { m_pp.class_=i; } @@ -396,7 +403,7 @@ public: inline uint8 GetLanguageSkill(uint16 n) const { return m_pp.languages[n]; } - void SendPickPocketResponse(Mob *from, uint32 amt, int type, const Item_Struct* item = nullptr); + void SendPickPocketResponse(Mob *from, uint32 amt, int type, const EQEmu::ItemBase* item = nullptr); inline const char* GetLastName() const { return lastname; } @@ -412,7 +419,7 @@ public: virtual void CalcBonuses(); //these are all precalculated now inline virtual int32 GetAC() const { return AC; } - inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(SkillOffense)) * 9 / 10); } + inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(EQEmu::skills::SkillOffense)) * 9 / 10); } inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; } inline virtual int GetHaste() const { return Haste; } int GetRawACNoShield(int &shield_ac) const; @@ -506,6 +513,8 @@ public: virtual int GetMaxSongSlots() const { return 12; } virtual int GetMaxDiscSlots() const { return 1; } virtual int GetMaxTotalSlots() const { return 38; } + virtual uint32 GetFirstBuffSlot(bool disc, bool song); + virtual uint32 GetLastBuffSlot(bool disc, bool song); virtual void InitializeBuffSlots(); virtual void UninitializeBuffSlots(); @@ -541,7 +550,6 @@ public: bool Flurry(); bool Rampage(); - void DurationRampage(uint32 duration); inline uint32 GetEXP() const { return m_pp.exp; } @@ -557,6 +565,7 @@ public: void SendCrystalCounts(); void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false); + uint32 CalcEXP(uint8 conlevel = 0xFF); 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); @@ -581,8 +590,8 @@ public: void GoToBind(uint8 bindnum = 0); void GoToSafeCoords(uint16 zone_id, uint16 instance_id); - void Gate(); - void SetBindPoint(int to_zone = -1, int to_instance = 0, const glm::vec3& location = glm::vec3()); + void Gate(uint8 bindnum = 0); + void SetBindPoint(int bind_num = 0, int to_zone = -1, int to_instance = 0, const glm::vec3& location = glm::vec3()); void SetStartZone(uint32 zoneid, float x = 0.0f, float y =0.0f, float z = 0.0f); uint32 GetStartZone(void); void MovePC(const char* zonename, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); @@ -592,7 +601,7 @@ public: void AssignToInstance(uint16 instance_id); void RemoveFromInstance(uint16 instance_id); void WhoAll(); - bool CheckLoreConflict(const Item_Struct* item); + bool CheckLoreConflict(const EQEmu::ItemBase* item); void ChangeLastName(const char* in_lastname); void GetGroupAAs(GroupLeadershipAA_Struct *into) const; void GetRaidAAs(RaidLeadershipAA_Struct *into) const; @@ -611,7 +620,7 @@ public: void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max); void UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max); - void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity); + void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity, bool quest = false); void SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp); int32 GetRawItemAC(); uint16 GetCombinedAC_TEST(); @@ -622,6 +631,7 @@ public: inline uint32 AccountID() const { return account_id; } inline const char* AccountName()const { return account_name; } + inline int GetAccountCreation() const { return account_creation; } inline int16 Admin() const { return admin; } inline uint32 CharacterID() const { return character_id; } void UpdateAdmin(bool iFromDB = true); @@ -662,6 +672,8 @@ public: bool HasMoney(uint64 copper); uint64 GetCarriedMoney(); uint64 GetAllMoney(); + uint32 GetMoney(uint8 type, uint8 subtype); + int GetAccountAge(); bool IsDiscovered(uint32 itemid); void DiscoverItem(uint32 itemid); @@ -673,31 +685,31 @@ public: uint16 GetSkillPoints() { return m_pp.points;} void SetSkillPoints(int inp) { m_pp.points = inp;} - void IncreaseSkill(int skill_id, int value = 1) { if (skill_id <= HIGHEST_SKILL) { m_pp.skills[skill_id] += value; } } + void IncreaseSkill(int skill_id, int value = 1) { if (skill_id <= EQEmu::skills::HIGHEST_SKILL) { m_pp.skills[skill_id] += value; } } void IncreaseLanguageSkill(int skill_id, int value = 1); - virtual uint16 GetSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return((itembonuses.skillmod[skill_id] > 0) ? m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100 : m_pp.skills[skill_id]); } return 0; } - uint32 GetRawSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; } - bool HasSkill(SkillUseTypes skill_id) const; - bool CanHaveSkill(SkillUseTypes skill_id) const; - void SetSkill(SkillUseTypes skill_num, uint16 value); - void AddSkill(SkillUseTypes skillid, uint16 value); + virtual uint16 GetSkill(EQEmu::skills::SkillType skill_id) const { if (skill_id <= EQEmu::skills::HIGHEST_SKILL) { return(itembonuses.skillmod[skill_id] > 0 ? (itembonuses.skillmodmax[skill_id] > 0 ? std::min(m_pp.skills[skill_id] + itembonuses.skillmodmax[skill_id], m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id]); } return 0; } + uint32 GetRawSkill(EQEmu::skills::SkillType skill_id) const { if (skill_id <= EQEmu::skills::HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; } + bool HasSkill(EQEmu::skills::SkillType skill_id) const; + bool CanHaveSkill(EQEmu::skills::SkillType skill_id) const; + void SetSkill(EQEmu::skills::SkillType skill_num, uint16 value); + void AddSkill(EQEmu::skills::SkillType skillid, uint16 value); void CheckSpecializeIncrease(uint16 spell_id); void CheckSongSkillIncrease(uint16 spell_id); - bool CheckIncreaseSkill(SkillUseTypes skillid, Mob *against_who, int chancemodi = 0); + bool CheckIncreaseSkill(EQEmu::skills::SkillType skillid, Mob *against_who, int chancemodi = 0); void CheckLanguageSkillIncrease(uint8 langid, uint8 TeacherSkill); void SetLanguageSkill(int langid, int value); void SetHoTT(uint32 mobid); void ShowSkillsWindow(); void SendStatsWindow(Client* client, bool use_window); - uint16 MaxSkill(SkillUseTypes skillid, uint16 class_, uint16 level) const; - inline uint16 MaxSkill(SkillUseTypes skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); } - uint8 SkillTrainLevel(SkillUseTypes skillid, uint16 class_); + uint16 MaxSkill(EQEmu::skills::SkillType skillid, uint16 class_, uint16 level) const; + inline uint16 MaxSkill(EQEmu::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); } + uint8 SkillTrainLevel(EQEmu::skills::SkillType skillid, uint16 class_); - void TradeskillSearchResults(const std::string query, unsigned long objtype, unsigned long someid); + void TradeskillSearchResults(const std::string &query, unsigned long objtype, unsigned long someid); void SendTradeskillDetails(uint32 recipe_id); bool TradeskillExecute(DBTradeskillRecipe_Struct *spec); - void CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, SkillUseTypes tradeskill); + void CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, EQEmu::skills::SkillType tradeskill); void GMKill(); inline bool IsMedding() const {return medding;} @@ -708,6 +720,7 @@ public: // use this one instead void MemSpell(uint16 spell_id, int slot, bool update_client = true); void UnmemSpell(int slot, bool update_client = true); + void UnmemSpellBySpellID(int32 spell_id); void UnmemSpellAll(bool update_client = true); void ScribeSpell(uint16 spell_id, int slot, bool update_client = true); void UnscribeSpell(int slot, bool update_client = true); @@ -731,7 +744,7 @@ public: #endif uint32 GetEquipment(uint8 material_slot) const; // returns item id uint32 GetEquipmentColor(uint8 material_slot) const; - virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = m_inv.FindBrightestLightType(); m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); } + virtual void UpdateEquipmentLight() { m_Light.Type[EQEmu::lightsource::LightEquipment] = m_inv.FindBrightestLightType(); m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } inline bool AutoSplitEnabled() { return m_pp.autosplit != 0; } @@ -758,45 +771,35 @@ public: inline PTimerList &GetPTimers() { return(p_timers); } - //AA Methods - void SendAAList(); - void ResetAA(); - void SendClearAA(); - void SendAA(uint32 id, int seq=1); - void SendPreviousAA(uint32 id, int seq=1); - void BuyAA(AA_Action* action); - //this function is used by some AA stuff - void MemorizeSpell(uint32 slot,uint32 spellid,uint32 scribing); - void SetAATitle(const char *Title); - void SetTitleSuffix(const char *txt); - inline uint32 GetMaxAAXP(void) const { return max_AAXP; } - inline uint32 GetAAXP() const { return m_pp.expAA; } - void SendAAStats(); - void SendAATable(); - void SendAATimers(); - int GetAATimerID(aaID activate); - int CalcAAReuseTimer(const AA_DBAction *caa); - void ActivateAA(aaID activate); - void SendAATimer(uint32 ability, uint32 begin, uint32 end); - void EnableAAEffect(aaEffectType type, uint32 duration = 0); - void DisableAAEffect(aaEffectType type); - bool CheckAAEffect(aaEffectType type); - void HandleAAAction(aaID activate); - uint32 GetAA(uint32 aa_id) const; - bool SetAA(uint32 aa_id, uint32 new_value); - inline uint32 GetAAPointsSpent() { return m_pp.aapoints_spent; } - int16 CalcAAFocusEffect(focusType type, uint16 focus_spell, uint16 spell_id); - int16 CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id); - void SetAAPoints(uint32 points) { m_pp.aapoints = points; SendAAStats(); } - void AddAAPoints(uint32 points) { m_pp.aapoints += points; SendAAStats(); } + //New AA Methods + void SendAlternateAdvancementRank(int aa_id, int level); + void SendAlternateAdvancementTable(); + void SendAlternateAdvancementStats(); + void PurchaseAlternateAdvancementRank(int rank_id); + bool GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore_cost = false); + void IncrementAlternateAdvancementRank(int rank_id); + void ActivateAlternateAdvancementAbility(int rank_id, int target_id); + void SendAlternateAdvancementPoints(); + void SendAlternateAdvancementTimer(int ability, int begin, int end); + void SendAlternateAdvancementTimers(); + void ResetAlternateAdvancementTimer(int ability); + void ResetAlternateAdvancementTimers(); + + void SetAAPoints(uint32 points) { m_pp.aapoints = points; SendAlternateAdvancementStats(); } + void AddAAPoints(uint32 points) { m_pp.aapoints += points; SendAlternateAdvancementStats(); } int GetAAPoints() { return m_pp.aapoints; } int GetSpentAA() { return m_pp.aapoints_spent; } + + //old AA methods that we still use + void ResetAA(); void RefundAA(); - void IncrementAA(int aa_id); - int32 GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2); - int32 GetAAEffectid(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, true, false,false); } - int32 GetAABase1(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, true,false); } - int32 GetAABase2(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, false,true); } + void SendClearAA(); + inline uint32 GetMaxAAXP(void) const { return max_AAXP; } + inline uint32 GetAAXP() const { return m_pp.expAA; } + int16 CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id); + void SetAATitle(const char *Title); + void SetTitleSuffix(const char *txt); + void MemorizeSpell(uint32 slot, uint32 spellid, uint32 scribing); int32 acmod(); // Item methods @@ -804,7 +807,7 @@ public: uint32 NukeItem(uint32 itemnum, uint8 where_to_check = (invWhereWorn | invWherePersonal | invWhereBank | invWhereSharedBank | invWhereTrading | invWhereCursor)); void SetTint(int16 slot_id, uint32 color); - void SetTint(int16 slot_id, Color_Struct& color); + void SetTint(int16 slot_id, EQEmu::Tint_Struct& color); void SetMaterial(int16 slot_id, uint32 item_id); void Undye(); int32 GetItemIDAt(int16 slot_id); @@ -818,59 +821,12 @@ public: void QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call = false); void PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data = 0); bool AutoPutLootInInventory(ItemInst& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0); - bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = MainCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0); + bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = EQEmu::legacy::SlotCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0); void SetStats(uint8 type,int16 set_val); void IncStats(uint8 type,int16 increase_val); void DropItem(int16 slot_id); - // - // class Client::TextLink - // - class TextLink { - public: - enum LinkType { linkBlank = 0, linkItemData, linkLootItem, linkItemInst }; - - TextLink() { Reset(); } - - void SetLinkType(LinkType linkType) { m_LinkType = linkType; } - void SetItemData(const Item_Struct* itemData) { m_ItemData = itemData; } - void SetLootData(const ServerLootItem_Struct* lootData) { m_LootData = lootData; } - void SetItemInst(const ItemInst* itemInst) { m_ItemInst = itemInst; } - void SetProxyItemID(uint32 proxyItemID) { m_ProxyItemID = proxyItemID; } // mainly for saylinks..but, not limited to - void SetProxyText(const char* proxyText) { m_ProxyText = proxyText; } // overrides standard text use - void SetTaskUse() { m_TaskUse = true; } - - std::string GenerateLink(); - bool LinkError() { return m_Error; } - - std::string GetLink() { return m_Link; } // contains full string format: '/12x' '' '' '/12x' - std::string GetLinkBody() { return m_LinkBody; } // contains string format: '' - std::string GetLinkText() { return m_LinkText; } // contains string format: '' - - void Reset(); - - static bool DegenerateLinkBody(TextLinkBody_Struct& textLinkBodyStruct, const std::string& textLinkBody); - static bool GenerateLinkBody(std::string& textLinkBody, const TextLinkBody_Struct& textLinkBodyStruct); - - private: - void generate_body(); - void generate_text(); - - int m_LinkType; - const Item_Struct* m_ItemData; - const ServerLootItem_Struct* m_LootData; - const ItemInst* m_ItemInst; - uint32 m_ProxyItemID; - const char* m_ProxyText; - bool m_TaskUse; - TextLinkBody_Struct m_LinkBodyStruct; - std::string m_Link; - std::string m_LinkBody; - std::string m_LinkText; - bool m_Error; - }; - - int GetItemLinkHash(const ItemInst* inst); // move to Item_Struct..or make use of the pre-calculated database field + int GetItemLinkHash(const ItemInst* inst); // move to ItemBase..or make use of the pre-calculated database field void SendItemLink(const ItemInst* inst, bool sendtoall=false); void SendLootItemInPacket(const ItemInst* inst, int16 slot_id); @@ -883,7 +839,10 @@ public: eqFilterMode GetFilter(eqFilterType filter_id) const { return ClientFilters[filter_id]; } void SetFilter(eqFilterType filter_id, eqFilterMode value) { ClientFilters[filter_id]=value; } + void CancelSneakHide(); void BreakInvis(); + void BreakSneakWhenCastOn(Mob* caster, bool IsResisted); + void BreakFeignDeathWhenCastOn(bool IsResisted); void LeaveGroup(); bool Hungry() const {if (GetGM()) return false; return m_pp.hunger_level <= 3000;} @@ -897,14 +856,17 @@ public: bool CheckTradeLoreConflict(Client* other); void LinkDead(); void Insight(uint32 t_id); - bool CheckDoubleAttack(bool tripleAttack = false); + bool CheckDoubleAttack(); + bool CheckTripleAttack(); bool CheckDoubleRangedAttack(); + bool CheckDualWield(); //remove charges/multiple objects from inventory: //bool DecreaseByType(uint32 type, uint8 amt); bool DecreaseByID(uint32 type, uint8 amt); uint8 SlotConvert2(uint8 slot); //Maybe not needed. void Escape(); //AA Escape + void DisenchantSummonedBags(bool client_update = true); void RemoveNoRent(bool client_update = true); void RemoveDuplicateLore(bool client_update = true); void MoveSlotNotAllowed(bool client_update = true); @@ -926,10 +888,15 @@ public: void ResetTrade(); void DropInst(const ItemInst* inst); bool TrainDiscipline(uint32 itemid); + void TrainDiscBySpellID(int32 spell_id); + int GetDiscSlotBySpellID(int32 spellid); void SendDisciplineUpdate(); void SendDisciplineTimer(uint32 timer_id, uint32 duration); bool UseDiscipline(uint32 spell_id, uint32 target); + void SetLinkedSpellReuseTimer(uint32 timer_id, uint32 duration); + bool IsLinkedSpellReuseTimerReady(uint32 timer_id); + bool CheckTitle(int titleset); void EnableTitle(int titleset); void RemoveTitle(int titleset); @@ -959,7 +926,7 @@ public: //This is used to later set the buff duration of the spell, in slot to duration. //Doesn't appear to work directly after the client recieves an action packet. - void SendBuffDurationPacket(Buffs_Struct &buff); + void SendBuffDurationPacket(Buffs_Struct &buff, int slot); void SendBuffNumHitPacket(Buffs_Struct &buff, int slot); void ProcessInspectRequest(Client* requestee, Client* requester); @@ -968,7 +935,7 @@ public: int GetNextAvailableSpellBookSlot(int starting_slot = 0); inline uint32 GetSpellByBookSlot(int book_slot) { return m_pp.spell_book[book_slot]; } inline bool HasSpellScribed(int spellid) { return (FindSpellBookSlotBySpellID(spellid) != -1 ? true : false); } - uint16 GetMaxSkillAfterSpecializationRules(SkillUseTypes skillid, uint16 maxSkill); + uint16 GetMaxSkillAfterSpecializationRules(EQEmu::skills::SkillType skillid, uint16 maxSkill); void SendPopupToClient(const char *Title, const char *Text, uint32 PopupID = 0, uint32 Buttons = 0, uint32 Duration = 0); void SendWindow(uint32 PopupID, uint32 NegativeID, uint32 Buttons, const char *ButtonName0, const char *ButtonName1, uint32 Duration, int title_type, Client* target, const char *Title, const char *Text, ...); bool PendingTranslocate; @@ -997,13 +964,13 @@ public: inline void UpdateTasksForItem(ActivityType Type, int ItemID, int Count=1) { if(taskstate) taskstate->UpdateTasksForItem(this, Type, ItemID, Count); } inline void UpdateTasksOnExplore(int ExploreID) { if(taskstate) taskstate->UpdateTasksOnExplore(this, ExploreID); } inline bool UpdateTasksOnSpeakWith(int NPCTypeID) { if(taskstate) return taskstate->UpdateTasksOnSpeakWith(this, NPCTypeID); else return false; } - inline bool UpdateTasksOnDeliver(uint32 *Items, int Cash, int NPCTypeID) { if(taskstate) return taskstate->UpdateTasksOnDeliver(this, Items, Cash, NPCTypeID); else return false; } + inline bool UpdateTasksOnDeliver(std::list& Items, int Cash, int NPCTypeID) { if (taskstate) return taskstate->UpdateTasksOnDeliver(this, Items, Cash, NPCTypeID); else return false; } inline void TaskSetSelector(Mob *mob, int TaskSetID) { if(taskmanager) taskmanager->TaskSetSelector(this, taskstate, mob, TaskSetID); } inline void EnableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->EnableTask(CharacterID(), TaskCount, TaskList); } inline void DisableTask(int TaskCount, int *TaskList) { if(taskstate) taskstate->DisableTask(CharacterID(), TaskCount, TaskList); } inline bool IsTaskEnabled(int TaskID) { return (taskstate ? taskstate->IsTaskEnabled(TaskID) : false); } inline void ProcessTaskProximities(float X, float Y, float Z) { if(taskstate) taskstate->ProcessTaskProximities(this, X, Y, Z); } - inline void AssignTask(int TaskID, int NPCID) { if(taskstate) taskstate->AcceptNewTask(this, TaskID, NPCID); } + inline void AssignTask(int TaskID, int NPCID, bool enforce_level_requirement = false) { if (taskstate) taskstate->AcceptNewTask(this, TaskID, NPCID, enforce_level_requirement); } inline int ActiveSpeakTask(int NPCID) { if(taskstate) return taskstate->ActiveSpeakTask(NPCID); else return 0; } inline int ActiveSpeakActivity(int NPCID, int TaskID) { if(taskstate) return taskstate->ActiveSpeakActivity(NPCID, TaskID); else return 0; } inline void FailTask(int TaskID) { if(taskstate) taskstate->FailTask(this, TaskID); } @@ -1021,9 +988,9 @@ public: inline int ActiveTasksInSet(int TaskSet) { return (taskstate ? taskstate->ActiveTasksInSet(TaskSet) :0); } inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); } - inline const ClientVersion GetClientVersion() const { return m_ClientVersion; } - inline const uint32 GetClientVersionBit() const { return m_ClientVersionBit; } - inline void SetClientVersion(ClientVersion in) { m_ClientVersion = in; } + inline const EQEmu::versions::ClientVersion ClientVersion() const { return m_ClientVersion; } + inline const uint32 ClientVersionBit() const { return m_ClientVersionBit; } + inline void SetClientVersion(EQEmu::versions::ClientVersion client_version) { m_ClientVersion = client_version; } /** Adventure Stuff **/ void SendAdventureError(const char *error); @@ -1129,6 +1096,7 @@ public: inline bool IsDraggingCorpse() { return (DraggedCorpses.size() > 0); } void DragCorpses(); inline void ClearDraggedCorpses() { DraggedCorpses.clear(); } + inline void ResetPositionTimer() { position_timer_counter = 0; } void SendAltCurrencies(); void SetAlternateCurrencyValue(uint32 currency_id, uint32 new_amount); void AddAlternateCurrencyValue(uint32 currency_id, int32 amount, int8 method = 0); @@ -1140,20 +1108,22 @@ public: void HandleLFGuildResponse(ServerPacket *pack); void SendLFGuildStatus(); void SendGuildLFGuildStatus(); - inline bool XTargettingAvailable() const { return ((m_ClientVersionBit & BIT_UFAndLater) && RuleB(Character, EnableXTargetting)); } + inline bool XTargettingAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) && RuleB(Character, EnableXTargetting)); } inline uint8 GetMaxXTargets() const { return MaxXTargets; } void SetMaxXTargets(uint8 NewMax); bool IsXTarget(const Mob *m) const; bool IsClientXTarget(const Client *c) const; void UpdateClientXTarget(Client *c); void UpdateXTargetType(XTargetType Type, Mob *m, const char *Name = nullptr); - void AddAutoXTarget(Mob *m); + void AddAutoXTarget(Mob *m, bool send = true); void RemoveXTarget(Mob *m, bool OnlyAutoSlots); void SendXTargetPacket(uint32 Slot, Mob *m); + void SendXTargetUpdates(); void RemoveGroupXTargets(); void RemoveAutoXTargets(); void ShowXTargets(Client *c); bool GroupFollow(Client* inviter); + inline bool GetRunMode() const { return runmode; } void InitializeMercInfo(); bool CheckCanSpawnMerc(uint32 template_id); @@ -1213,13 +1183,14 @@ public: int32 GetActCHA() { return( std::min(GetMaxCHA(), GetCHA()) ); } void LoadAccountFlags(); void SetAccountFlag(std::string flag, std::string val); - std::string GetAccountFlag(std::string flag); float GetDamageMultiplier(SkillUseTypes); - void Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_consume); + std::string GetAccountFlag(std::string flag); + float GetDamageMultiplier(EQEmu::skills::SkillType how_long_has_this_been_missing); + void Consume(const EQEmu::ItemBase *item, uint8 type, int16 slot, bool auto_consume); void PlayMP3(const char* fname); void ExpeditionSay(const char *str, int ExpID); - int mod_client_damage(int damage, SkillUseTypes skillinuse, int hand, const ItemInst* weapon, Mob* other); + int mod_client_damage(int damage, EQEmu::skills::SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other); bool mod_client_message(char* message, uint8 chan_num); - bool mod_can_increase_skill(SkillUseTypes skillid, Mob* against_who); + bool mod_can_increase_skill(EQEmu::skills::SkillType skillid, Mob* against_who); int16 mod_increase_skill_chance(int16 chance, Mob* against_who); int mod_bindwound_percent(int max_percent, Mob* bindmob); int mod_bindwound_hp(int bindhps, Mob* bindmob); @@ -1236,9 +1207,9 @@ public: int32 mod_client_xp(int32 in_exp, NPC *npc); uint32 mod_client_xp_for_level(uint32 xp, uint16 check_level); int mod_client_haste_cap(int cap); - int mod_consume(Item_Struct *item, ItemUseTypes type, int change); - int mod_food_value(const Item_Struct *item, int change); - int mod_drink_value(const Item_Struct *item, int change); + int mod_consume(EQEmu::ItemBase *item, EQEmu::item::ItemType type, int change); + int mod_food_value(const EQEmu::ItemBase *item, int change); + int mod_drink_value(const EQEmu::ItemBase *item, int change); void SetEngagedRaidTarget(bool value) { EngagedRaidTarget = value; } bool GetEngagedRaidTarget() const { return EngagedRaidTarget; } @@ -1250,25 +1221,40 @@ public: bool InterrogateInventory(Client* requester, bool log, bool silent, bool allowtrip, bool& error, bool autolog = true); + void SetNextInvSnapshot(uint32 interval_in_min) { + m_epp.last_invsnapshot_time = time(nullptr); + m_epp.next_invsnapshot_time = m_epp.last_invsnapshot_time + (interval_in_min * 60); + } + uint32 GetLastInvSnapshotTime() { return m_epp.last_invsnapshot_time; } + uint32 GetNextInvSnapshotTime() { return m_epp.next_invsnapshot_time; } + //Command #Tune functions virtual int32 Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); int32 GetMeleeDamage(Mob* other, bool GetMinDamage = false); + void QuestReward(Mob* target, uint32 copper = 0, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0, uint32 itemid = 0, uint32 exp = 0, bool faction = false); + + void ResetHPUpdateTimer() { hpupdate_timer.Start(); } + + void SendHPUpdateMarquee(); + + void CheckRegionTypeChanges(); + protected: friend class Mob; void CalcItemBonuses(StatBonuses* newbon); - void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false); + void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false, int rec_override = 0, bool ammo_slot_item = false); void AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false); int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat); void CalcEdibleBonuses(StatBonuses* newbon); - void CalcAABonuses(StatBonuses* newbon); - void ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon); void ProcessItemCaps(); void MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message = true); bool client_data_loaded; int16 GetFocusEffect(focusType type, uint16 spell_id); - int16 GetSympatheticFocusEffect(focusType type, uint16 spell_id); + uint16 GetSympatheticFocusEffect(focusType type, uint16 spell_id); + + void FinishAlternateAdvancementPurchase(AA::Rank *rank, bool ignore_cost); Mob* bind_sight_target; @@ -1379,6 +1365,7 @@ private: bool AFK; bool auto_attack; bool auto_fire; + bool runmode; uint8 gmspeed; bool medding; uint16 horseId; @@ -1437,10 +1424,14 @@ private: uint8 zonesummon_ignorerestrictions; ZoneMode zone_mode; + WaterRegionType last_region_type; Timer position_timer; uint8 position_timer_counter; + // this is used to try to cut back on position update reflections + int position_update_same_count; + PTimerList p_timers; //persistent timers Timer hpupdate_timer; Timer camp_timer; @@ -1483,11 +1474,7 @@ private: uint32 tribute_master_id; - FILE *SQL_log; uint32 max_AAXP; - uint32 staminacount; - AA_Array* aa[MAX_PP_AA_ARRAY]; //this list contains pointers into our player profile - std::map aa_points; bool npcflag; uint8 npclevel; bool feigned; @@ -1518,7 +1505,7 @@ private: Timer *GlobalChatLimiterTimer; //60 seconds uint32 AttemptedMessages; - ClientVersion m_ClientVersion; + EQEmu::versions::ClientVersion m_ClientVersion; uint32 m_ClientVersionBit; int XPRate; diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 6aae0d0e9..c57fc340f 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -1,5 +1,5 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,7 +42,7 @@ int32 Client::GetMaxStat() const if (level < 61) { base = 255; } - else if (GetClientVersion() >= ClientVersion::SoF) { + else if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { base = 255 + 5 * (level - 60); } else if (level < 71) { @@ -58,8 +58,8 @@ int32 Client::GetMaxResist() const { int level = GetLevel(); int32 base = 500; - if (level > 60) { - base += ((level - 60) * 5); + if (level > 65) { + base += ((level - 65) * 5); } return base; } @@ -160,7 +160,7 @@ int32 Client::LevelRegen() bool sitting = IsSitting(); bool feigned = GetFeigned(); int level = GetLevel(); - bool bonus = GetRaceBitmask(GetBaseRace()) & RuleI(Character, BaseHPRegenBonusRaces); + bool bonus = GetPlayerRaceBit(GetBaseRace()) & RuleI(Character, BaseHPRegenBonusRaces); uint8 multiplier1 = bonus ? 2 : 1; int32 hp = 0; //these calculations should match up with the info from Monkly Business, which was last updated ~05/2008: http://www.monkly-business.net/index.php?pageid=abilities @@ -409,7 +409,7 @@ uint32 Mob::GetClassLevelFactor() int32 Client::CalcBaseHP() { - if (GetClientVersion() >= ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { int stats = GetSTA(); if (stats > 255) { stats = (stats - 255) / 2; @@ -485,9 +485,9 @@ int32 Client::GetRawItemAC() { int32 Total = 0; // this skips MainAmmo..add an '=' conditional if that slot is required (original behavior) - for (int16 slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id < EmuConstants::EQUIPMENT_END; slot_id++) { + for (int16 slot_id = EQEmu::legacy::EQUIPMENT_BEGIN; slot_id < EQEmu::legacy::EQUIPMENT_END; slot_id++) { const ItemInst* inst = m_inv[slot_id]; - if (inst && inst->IsType(ItemClassCommon)) { + if (inst && inst->IsClassCommon()) { Total += inst->GetItem()->AC; } } @@ -1032,21 +1032,28 @@ int32 Client::acmod() int32 Client::CalcAC() { // new formula - int avoidance = (acmod() + ((GetSkill(SkillDefense) + itembonuses.HeroicAGI / 10) * 16) / 9); + int avoidance = (acmod() + ((GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) * 16) / 9); if (avoidance < 0) { avoidance = 0; } + + if (RuleB(Character, EnableAvoidanceCap)) { + if (avoidance > RuleI(Character, AvoidanceCap)) { + avoidance = RuleI(Character, AvoidanceCap); + } + } + int mitigation = 0; if (m_pp.class_ == WIZARD || m_pp.class_ == MAGICIAN || m_pp.class_ == NECROMANCER || m_pp.class_ == ENCHANTER) { //something is wrong with this, naked casters have the wrong natural AC // mitigation = (spellbonuses.AC/3) + (GetSkill(DEFENSE)/2) + (itembonuses.AC+1); - mitigation = (GetSkill(SkillDefense) + itembonuses.HeroicAGI / 10) / 4 + (itembonuses.AC + 1); + mitigation = (GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 4 + (itembonuses.AC + 1); //this might be off by 4.. mitigation -= 4; } else { // mitigation = (spellbonuses.AC/4) + (GetSkill(DEFENSE)/3) + ((itembonuses.AC*4)/3); - mitigation = (GetSkill(SkillDefense) + itembonuses.HeroicAGI / 10) / 3 + ((itembonuses.AC * 4) / 3); + mitigation = (GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 3 + ((itembonuses.AC * 4) / 3); if (m_pp.class_ == MONK) { mitigation += GetLevel() * 13 / 10; //the 13/10 might be wrong, but it is close... } @@ -1067,10 +1074,10 @@ int32 Client::CalcAC() } // Shield AC bonus for HeroicSTR if (itembonuses.HeroicSTR) { - bool equiped = CastToClient()->m_inv.GetItem(MainSecondary); + bool equiped = CastToClient()->m_inv.GetItem(EQEmu::legacy::SlotSecondary); if (equiped) { - uint8 shield = CastToClient()->m_inv.GetItem(MainSecondary)->GetItem()->ItemType; - if (shield == ItemTypeShield) { + uint8 shield = CastToClient()->m_inv.GetItem(EQEmu::legacy::SlotSecondary)->GetItem()->ItemType; + if (shield == EQEmu::item::ItemTypeShield) { displayed += itembonuses.HeroicSTR / 2; } } @@ -1085,21 +1092,21 @@ int32 Client::GetACMit() { int mitigation = 0; if (m_pp.class_ == WIZARD || m_pp.class_ == MAGICIAN || m_pp.class_ == NECROMANCER || m_pp.class_ == ENCHANTER) { - mitigation = (GetSkill(SkillDefense) + itembonuses.HeroicAGI / 10) / 4 + (itembonuses.AC + 1); + mitigation = (GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 4 + (itembonuses.AC + 1); mitigation -= 4; } else { - mitigation = (GetSkill(SkillDefense) + itembonuses.HeroicAGI / 10) / 3 + ((itembonuses.AC * 4) / 3); + mitigation = (GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 3 + ((itembonuses.AC * 4) / 3); if (m_pp.class_ == MONK) { mitigation += GetLevel() * 13 / 10; //the 13/10 might be wrong, but it is close... } } // Shield AC bonus for HeroicSTR if (itembonuses.HeroicSTR) { - bool equiped = CastToClient()->m_inv.GetItem(MainSecondary); + bool equiped = CastToClient()->m_inv.GetItem(EQEmu::legacy::SlotSecondary); if (equiped) { - uint8 shield = CastToClient()->m_inv.GetItem(MainSecondary)->GetItem()->ItemType; - if (shield == ItemTypeShield) { + uint8 shield = CastToClient()->m_inv.GetItem(EQEmu::legacy::SlotSecondary)->GetItem()->ItemType; + if (shield == EQEmu::item::ItemTypeShield) { mitigation += itembonuses.HeroicSTR / 2; } } @@ -1109,10 +1116,17 @@ int32 Client::GetACMit() int32 Client::GetACAvoid() { - int32 avoidance = (acmod() + ((GetSkill(SkillDefense) + itembonuses.HeroicAGI / 10) * 16) / 9); + int32 avoidance = (acmod() + ((GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) * 16) / 9); if (avoidance < 0) { avoidance = 0; } + + if (RuleB(Character, EnableAvoidanceCap)) { + if ((avoidance * 1000 / 847) > RuleI(Character, AvoidanceCap)) { + return RuleI(Character, AvoidanceCap); + } + } + return (avoidance * 1000 / 847); } @@ -1121,7 +1135,7 @@ int32 Client::CalcMaxMana() switch (GetCasterClass()) { case 'I': case 'W': { - max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + GroupLeadershipAAManaEnhancement()); + max_mana = (CalcBaseMana() + itembonuses.Mana + spellbonuses.Mana + aabonuses.Mana + GroupLeadershipAAManaEnhancement()); break; } case 'N': { @@ -1162,7 +1176,7 @@ int32 Client::CalcBaseMana() switch (GetCasterClass()) { case 'I': WisInt = GetINT(); - if (GetClientVersion() >= ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { if (WisInt > 100) { ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100); if (WisInt > 201) { @@ -1195,7 +1209,7 @@ int32 Client::CalcBaseMana() break; case 'W': WisInt = GetWIS(); - if (GetClientVersion() >= ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { if (WisInt > 100) { ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100); if (WisInt > 201) { @@ -1247,8 +1261,8 @@ int32 Client::CalcBaseManaRegen() uint8 clevel = GetLevel(); int32 regen = 0; if (IsSitting() || (GetHorseId() != 0)) { - if (HasSkill(SkillMeditate)) { - regen = (((GetSkill(SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4; + if (HasSkill(EQEmu::skills::SkillMeditate)) { + regen = (((GetSkill(EQEmu::skills::SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4; } else { regen = 2; @@ -1267,11 +1281,11 @@ int32 Client::CalcManaRegen() //this should be changed so we dont med while camping, etc... if (IsSitting() || (GetHorseId() != 0)) { BuffFadeBySitModifier(); - if (HasSkill(SkillMeditate)) { + if (HasSkill(EQEmu::skills::SkillMeditate)) { this->medding = true; - regen = (((GetSkill(SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4; + regen = (((GetSkill(EQEmu::skills::SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4; regen += spellbonuses.ManaRegen + itembonuses.ManaRegen; - CheckIncreaseSkill(SkillMeditate, nullptr, -5); + CheckIncreaseSkill(EQEmu::skills::SkillMeditate, nullptr, -5); } else { regen = 2 + spellbonuses.ManaRegen + itembonuses.ManaRegen; @@ -1302,11 +1316,11 @@ int32 Client::CalcManaRegenCap() uint32 Client::CalcCurrentWeight() { - const Item_Struct* TempItem = 0; + const EQEmu::ItemBase* TempItem = 0; ItemInst* ins; uint32 Total = 0; int x; - for (x = EmuConstants::EQUIPMENT_BEGIN; x <= MainCursor; x++) { // include cursor or not? + for (x = EQEmu::legacy::EQUIPMENT_BEGIN; x <= EQEmu::legacy::SlotCursor; x++) { // include cursor or not? TempItem = 0; ins = GetInv().GetItem(x); if (ins) { @@ -1316,7 +1330,7 @@ uint32 Client::CalcCurrentWeight() Total += TempItem->Weight; } } - for (x = EmuConstants::GENERAL_BAGS_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++) { // include cursor bags or not? + for (x = EQEmu::legacy::GENERAL_BAGS_BEGIN; x <= EQEmu::legacy::GENERAL_BAGS_END; x++) { // include cursor bags or not? int TmpWeight = 0; TempItem = 0; ins = GetInv().GetItem(x); @@ -1329,15 +1343,15 @@ uint32 Client::CalcCurrentWeight() if (TmpWeight > 0) { // this code indicates that weight redux bags can only be in the first general inventory slot to be effective... // is this correct? or can we scan for the highest weight redux and use that? (need client verifications) - int bagslot = MainGeneral1; + int bagslot = EQEmu::legacy::SlotGeneral1; int reduction = 0; - for (int m = EmuConstants::GENERAL_BAGS_BEGIN + 10; m <= EmuConstants::GENERAL_BAGS_END; m += 10) { // include cursor bags or not? + for (int m = EQEmu::legacy::GENERAL_BAGS_BEGIN + 10; m <= EQEmu::legacy::GENERAL_BAGS_END; m += 10) { // include cursor bags or not? if (x >= m) { bagslot += 1; } } ItemInst* baginst = GetInv().GetItem(bagslot); - if (baginst && baginst->GetItem() && baginst->IsType(ItemClassContainer)) { + if (baginst && baginst->GetItem() && baginst->IsClassBag()) { reduction = baginst->GetItem()->BagWR; } if (reduction > 0) { @@ -1355,7 +1369,7 @@ uint32 Client::CalcCurrentWeight() This is the ONLY instance I have seen where the client is hard coded to particular Item IDs to set a certain property for an item. It is very odd. */ // SoD+ client has no weight for coin - if (EQLimits::CoinHasWeight(GetClientVersion())) { + if (EQEmu::behavior::Lookup(EQEmu::versions::ConvertClientVersionToInventoryVersion(ClientVersion()))->CoinHasWeight) { Total += (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4; } float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat + (float)itembonuses.Packrat; @@ -1633,13 +1647,19 @@ int32 Client::CalcMR() MR = 30; break; case DRAKKIN: - MR = 35; + { + MR = 25; + if (GetDrakkinHeritage() == 2) + MR += 10; + else if (GetDrakkinHeritage() == 5) + MR += 2; break; + } default: MR = 20; } MR += itembonuses.MR + spellbonuses.MR + aabonuses.MR; - if (GetClass() == WARRIOR) { + if (GetClass() == WARRIOR || GetClass() == BERSERKER) { MR += GetLevel() / 2; } if (MR < 1) { @@ -1701,8 +1721,14 @@ int32 Client::CalcFR() FR = 25; break; case DRAKKIN: + { FR = 25; + if (GetDrakkinHeritage() == 0) + FR += 10; + else if (GetDrakkinHeritage() == 5) + FR += 2; break; + } default: FR = 20; } @@ -1714,6 +1740,13 @@ int32 Client::CalcFR() FR += l - 49; } } + if (c == MONK) { + FR += 8; + int l = GetLevel(); + if (l > 49) { + FR += l - 49; + } + } FR += itembonuses.FR + spellbonuses.FR + aabonuses.FR; if (FR < 1) { FR = 1; @@ -1774,12 +1807,24 @@ int32 Client::CalcDR() DR = 15; break; case DRAKKIN: + { DR = 15; + if (GetDrakkinHeritage() == 1) + DR += 10; + else if (GetDrakkinHeritage() == 5) + DR += 2; break; + } default: DR = 15; } int c = GetClass(); + // the monk one is part of base resist + if (c == MONK) { + int l = GetLevel(); + if (l > 50) + DR += l - 50; + } if (c == PALADIN) { DR += 8; int l = GetLevel(); @@ -1787,7 +1832,7 @@ int32 Client::CalcDR() DR += l - 49; } } - else if (c == SHADOWKNIGHT) { + else if (c == SHADOWKNIGHT || c == BEASTLORD) { DR += 4; int l = GetLevel(); if (l > 49) { @@ -1854,12 +1899,24 @@ int32 Client::CalcPR() PR = 30; break; case DRAKKIN: + { PR = 15; + if (GetDrakkinHeritage() == 3) + PR += 10; + else if (GetDrakkinHeritage() == 5) + PR += 2; break; + } default: PR = 15; } int c = GetClass(); + // this monk bonus is part of the base + if (c == MONK) { + int l = GetLevel(); + if (l > 50) + PR += l - 50; + } if (c == ROGUE) { PR += 8; int l = GetLevel(); @@ -1934,13 +1991,19 @@ int32 Client::CalcCR() CR = 25; break; case DRAKKIN: + { CR = 25; + if (GetDrakkinHeritage() == 4) + CR += 10; + else if (GetDrakkinHeritage() == 5) + CR += 2; break; + } default: CR = 25; } int c = GetClass(); - if (c == RANGER) { + if (c == RANGER || c == BEASTLORD) { CR += 4; int l = GetLevel(); if (l > 49) { @@ -1974,101 +2037,99 @@ int32 Client::CalcATK() uint32 Mob::GetInstrumentMod(uint16 spell_id) const { - if (GetClass() != BARD) { + if (GetClass() != BARD || spells[spell_id].IsDisciplineBuff) // Puretone is Singing but doesn't get any mod return 10; - } + uint32 effectmod = 10; - int effectmodcap = RuleI(Character, BaseInstrumentSoftCap); - //this should never use spell modifiers... - //if a spell grants better modifers, they are copied into the item mods - //because the spells are supposed to act just like having the intrument. - //item mods are in 10ths of percent increases + int effectmodcap = 0; + bool nocap = false; + if (RuleB(Character, UseSpellFileSongCap)) { + effectmodcap = spells[spell_id].songcap / 10; + // this looks a bit weird, but easiest way I could think to keep both systems working + if (effectmodcap == 0) + nocap = true; + else + effectmodcap += 10; + } else { + effectmodcap = RuleI(Character, BaseInstrumentSoftCap); + } + // this should never use spell modifiers... + // if a spell grants better modifers, they are copied into the item mods + // because the spells are supposed to act just like having the intrument. + // item mods are in 10ths of percent increases + // clickies (Symphony of Battle) that have a song skill don't get AA bonus for some reason + // but clickies that are songs (selo's on Composers Greaves) do get AA mod as well switch (spells[spell_id].skill) { - case SkillPercussionInstruments: - if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0) { - effectmod = 10; - } - else if (GetSkill(SkillPercussionInstruments) == 0) { - effectmod = 10; - } - else if (itembonuses.percussionMod > spellbonuses.percussionMod) { - effectmod = itembonuses.percussionMod; - } - else { - effectmod = spellbonuses.percussionMod; - } - effectmod += aabonuses.percussionMod; - break; - case SkillStringedInstruments: - if (itembonuses.stringedMod == 0 && spellbonuses.stringedMod == 0) { - effectmod = 10; - } - else if (GetSkill(SkillStringedInstruments) == 0) { - effectmod = 10; - } - else if (itembonuses.stringedMod > spellbonuses.stringedMod) { - effectmod = itembonuses.stringedMod; - } - else { - effectmod = spellbonuses.stringedMod; - } - effectmod += aabonuses.stringedMod; - break; - case SkillWindInstruments: - if (itembonuses.windMod == 0 && spellbonuses.windMod == 0) { - effectmod = 10; - } - else if (GetSkill(SkillWindInstruments) == 0) { - effectmod = 10; - } - else if (itembonuses.windMod > spellbonuses.windMod) { - effectmod = itembonuses.windMod; - } - else { - effectmod = spellbonuses.windMod; - } - effectmod += aabonuses.windMod; - break; - case SkillBrassInstruments: - if (itembonuses.brassMod == 0 && spellbonuses.brassMod == 0) { - effectmod = 10; - } - else if (GetSkill(SkillBrassInstruments) == 0) { - effectmod = 10; - } - else if (itembonuses.brassMod > spellbonuses.brassMod) { - effectmod = itembonuses.brassMod; - } - else { - effectmod = spellbonuses.brassMod; - } - effectmod += aabonuses.brassMod; - break; - case SkillSinging: - if (itembonuses.singingMod == 0 && spellbonuses.singingMod == 0) { - effectmod = 10; - } - else if (itembonuses.singingMod > spellbonuses.singingMod) { - effectmod = itembonuses.singingMod; - } - else { - effectmod = spellbonuses.singingMod; - } - effectmod += aabonuses.singingMod + spellbonuses.Amplification; - break; - default: + case EQEmu::skills::SkillPercussionInstruments: + if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0) effectmod = 10; - break; - } - effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap; - if (effectmod < 10) { + else if (GetSkill(EQEmu::skills::SkillPercussionInstruments) == 0) + effectmod = 10; + else if (itembonuses.percussionMod > spellbonuses.percussionMod) + effectmod = itembonuses.percussionMod; + else + effectmod = spellbonuses.percussionMod; + if (IsBardSong(spell_id)) + effectmod += aabonuses.percussionMod; + break; + case EQEmu::skills::SkillStringedInstruments: + if (itembonuses.stringedMod == 0 && spellbonuses.stringedMod == 0) + effectmod = 10; + else if (GetSkill(EQEmu::skills::SkillStringedInstruments) == 0) + effectmod = 10; + else if (itembonuses.stringedMod > spellbonuses.stringedMod) + effectmod = itembonuses.stringedMod; + else + effectmod = spellbonuses.stringedMod; + if (IsBardSong(spell_id)) + effectmod += aabonuses.stringedMod; + break; + case EQEmu::skills::SkillWindInstruments: + if (itembonuses.windMod == 0 && spellbonuses.windMod == 0) + effectmod = 10; + else if (GetSkill(EQEmu::skills::SkillWindInstruments) == 0) + effectmod = 10; + else if (itembonuses.windMod > spellbonuses.windMod) + effectmod = itembonuses.windMod; + else + effectmod = spellbonuses.windMod; + if (IsBardSong(spell_id)) + effectmod += aabonuses.windMod; + break; + case EQEmu::skills::SkillBrassInstruments: + if (itembonuses.brassMod == 0 && spellbonuses.brassMod == 0) + effectmod = 10; + else if (GetSkill(EQEmu::skills::SkillBrassInstruments) == 0) + effectmod = 10; + else if (itembonuses.brassMod > spellbonuses.brassMod) + effectmod = itembonuses.brassMod; + else + effectmod = spellbonuses.brassMod; + if (IsBardSong(spell_id)) + effectmod += aabonuses.brassMod; + break; + case EQEmu::skills::SkillSinging: + if (itembonuses.singingMod == 0 && spellbonuses.singingMod == 0) + effectmod = 10; + else if (itembonuses.singingMod > spellbonuses.singingMod) + effectmod = itembonuses.singingMod; + else + effectmod = spellbonuses.singingMod; + if (IsBardSong(spell_id)) + effectmod += aabonuses.singingMod + spellbonuses.Amplification; + break; + default: effectmod = 10; + return effectmod; } - if (effectmod > effectmodcap) { + if (!RuleB(Character, UseSpellFileSongCap)) + effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap; + if (effectmod < 10) + effectmod = 10; + if (!nocap && effectmod > effectmodcap) // if the cap is calculated to be 0 using new rules, no cap. effectmod = effectmodcap; - } - Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n", - GetName(), spell_id, effectmod, effectmodcap); + Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n", GetName(), spell_id, + effectmod, effectmodcap); return effectmod; } @@ -2093,7 +2154,7 @@ void Client::CalcMaxEndurance() int32 Client::CalcBaseEndurance() { int32 base_end = 0; - if (GetClientVersion() >= ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { double heroic_stats = (GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4.0f; double stats = (GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4.0f; if (stats > 201.0f) { @@ -2158,12 +2219,12 @@ int Client::GetRawACNoShield(int &shield_ac) const { int ac = itembonuses.AC + spellbonuses.AC + aabonuses.AC; shield_ac = 0; - const ItemInst *inst = m_inv.GetItem(MainSecondary); + const ItemInst *inst = m_inv.GetItem(EQEmu::legacy::SlotSecondary); if (inst) { - if (inst->GetItem()->ItemType == ItemTypeShield) { + if (inst->GetItem()->ItemType == EQEmu::item::ItemTypeShield) { ac -= inst->GetItem()->AC; shield_ac = inst->GetItem()->AC; - for (uint8 i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + for (uint8 i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { if (inst->GetAugment(i)) { ac -= inst->GetAugment(i)->GetItem()->AC; shield_ac += inst->GetAugment(i)->GetItem()->AC; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 6b0961e59..23276b302 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2009 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -69,7 +69,7 @@ extern QueryServ* QServ; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern PetitionList petition_list; extern EntityList entity_list; @@ -308,6 +308,8 @@ void MapOpcodes() ConnectedOpcodes[OP_PetitionRefresh] = &Client::Handle_OP_PetitionRefresh; ConnectedOpcodes[OP_PetitionResolve] = &Client::Handle_OP_PetitionResolve; ConnectedOpcodes[OP_PetitionUnCheckout] = &Client::Handle_OP_PetitionUnCheckout; + ConnectedOpcodes[OP_PlayerStateAdd] = &Client::Handle_OP_PlayerStateAdd; + ConnectedOpcodes[OP_PlayerStateRemove] = &Client::Handle_OP_PlayerStateRemove; ConnectedOpcodes[OP_PickPocket] = &Client::Handle_OP_PickPocket; ConnectedOpcodes[OP_PopupResponse] = &Client::Handle_OP_PopupResponse; ConnectedOpcodes[OP_PotionBelt] = &Client::Handle_OP_PotionBelt; @@ -339,7 +341,7 @@ void MapOpcodes() // Use or Ignore sense heading based on rule. bool train=RuleB(Skills, TrainSenseHeading); - ConnectedOpcodes[OP_SenseHeading] = + ConnectedOpcodes[OP_SenseHeading] = (train) ? &Client::Handle_OP_SenseHeading : &Client::Handle_OP_Ignore; ConnectedOpcodes[OP_SenseTraps] = &Client::Handle_OP_SenseTraps; @@ -387,9 +389,11 @@ void MapOpcodes() ConnectedOpcodes[OP_WhoAllRequest] = &Client::Handle_OP_WhoAllRequest; ConnectedOpcodes[OP_WorldUnknown001] = &Client::Handle_OP_Ignore; ConnectedOpcodes[OP_XTargetAutoAddHaters] = &Client::Handle_OP_XTargetAutoAddHaters; + ConnectedOpcodes[OP_XTargetOpen] = &Client::Handle_OP_XTargetOpen; ConnectedOpcodes[OP_XTargetRequest] = &Client::Handle_OP_XTargetRequest; ConnectedOpcodes[OP_YellForHelp] = &Client::Handle_OP_YellForHelp; ConnectedOpcodes[OP_ZoneChange] = &Client::Handle_OP_ZoneChange; + ConnectedOpcodes[OP_ResetAA] = &Client::Handle_OP_ResetAA; } void ClearMappedOpcode(EmuOpcode op) @@ -415,10 +419,10 @@ int Client::HandlePacket(const EQApplicationPacket *app) if (Log.log_settings[Logs::Client_Server_Packet].is_category_enabled == 1) Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size()); - + if (Log.log_settings[Logs::Client_Server_Packet_With_Dump].is_category_enabled == 1) Log.Out(Logs::General, Logs::Client_Server_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); - + EmuOpcode opcode = app->GetOpcode(); if (opcode == OP_AckPacket) { return true; @@ -460,7 +464,7 @@ int Client::HandlePacket(const EQApplicationPacket *app) case CLIENT_CONNECTED: { ClientPacketProc p; p = ConnectedOpcodes[opcode]; - if(p == nullptr) { + if(p == nullptr) { std::vector args; args.push_back(const_cast(app)); parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 0, &args); @@ -494,7 +498,7 @@ void Client::CompleteConnect() { UpdateWho(); client_state = CLIENT_CONNECTED; - + SendAllPackets(); hpupdate_timer.Start(); position_timer.Start(); autosave_timer.Start(); @@ -509,7 +513,7 @@ void Client::CompleteConnect() if (IsInAGuild()){ uint8 rank = GuildRank(); - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { switch (rank) { case 0: { rank = 5; break; } // GUILD_MEMBER 0 @@ -605,14 +609,14 @@ void Client::CompleteConnect() gender = 1; SendIllusionPacket(GetRace(), gender, 0xFF, 0xFF); } - else if (spell.base[x1] == -2) + else if (spell.base[x1] == -2) // WTF IS THIS { if (GetRace() == 128 || GetRace() == 130 || GetRace() <= 12) - SendIllusionPacket(GetRace(), GetGender(), spell.max[x1], spell.max[x1]); + SendIllusionPacket(GetRace(), GetGender(), spell.base2[x1], spell.max[x1]); } else if (spell.max[x1] > 0) { - SendIllusionPacket(spell.base[x1], 0xFF, spell.max[x1], spell.max[x1]); + SendIllusionPacket(spell.base[x1], 0xFF, spell.base2[x1], spell.max[x1]); } else { @@ -705,7 +709,7 @@ void Client::CompleteConnect() case SE_AddMeleeProc: case SE_WeaponProc: { - AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid); + AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].base2[x1], buffs[j1].spellid, buffs[j1].casterlevel); break; } case SE_DefensiveProc: @@ -749,8 +753,6 @@ void Client::CompleteConnect() entity_list.SendTraders(this); - zoneinpacket_timer.Start(); - if (GetPet()){ GetPet()->SendPetBuffsToClient(); } @@ -832,7 +834,7 @@ void Client::CompleteConnect() if (zone->GetZoneID() == RuleI(World, GuildBankZoneID) && GuildBanks) GuildBanks->SendGuildBank(this); - if (GetClientVersion() >= ClientVersion::SoD) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) entity_list.SendFindableNPCList(this); if (IsInAGuild()) { @@ -842,12 +844,12 @@ void Client::CompleteConnect() } /** Request adventure info **/ - ServerPacket *pack = new ServerPacket(ServerOP_AdventureDataRequest, 64); + auto pack = new ServerPacket(ServerOP_AdventureDataRequest, 64); strcpy((char*)pack->pBuffer, GetName()); worldserver.SendPacket(pack); delete pack; - if (IsClient() && CastToClient()->GetClientVersionBit() & BIT_UFAndLater) { + if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) { EQApplicationPacket *outapp = MakeBuffsPacket(false); CastToClient()->FastQueuePacket(&outapp); } @@ -1005,7 +1007,8 @@ void Client::Handle_Connect_OP_ClientError(const EQApplicationPacket *app) void Client::Handle_Connect_OP_ClientReady(const EQApplicationPacket *app) { conn_state = ClientReadyReceived; - + if (!Spawned()) + SendZoneInPackets(); CompleteConnect(); SendHPUpdate(); } @@ -1022,7 +1025,7 @@ void Client::Handle_Connect_OP_ReqClientSpawn(const EQApplicationPacket *app) { conn_state = ClientSpawnRequested; - EQApplicationPacket* outapp = new EQApplicationPacket; + auto outapp = new EQApplicationPacket; // Send Zone Doors if (entity_list.MakeDoorSpawnPacket(outapp, this)) @@ -1044,7 +1047,7 @@ void Client::Handle_Connect_OP_ReqClientSpawn(const EQApplicationPacket *app) outapp = new EQApplicationPacket(OP_SendExpZonein, 0); FastQueuePacket(&outapp); - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { outapp = new EQApplicationPacket(OP_ClientReady, 0); FastQueuePacket(&outapp); @@ -1083,8 +1086,8 @@ void Client::Handle_Connect_OP_ReqNewZone(const EQApplicationPacket *app) void Client::Handle_Connect_OP_SendAAStats(const EQApplicationPacket *app) { - SendAATimers(); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendAAStats, 0); + SendAlternateAdvancementTimers(); + auto outapp = new EQApplicationPacket(OP_SendAAStats, 0); QueuePacket(outapp); safe_delete(outapp); return; @@ -1092,18 +1095,18 @@ void Client::Handle_Connect_OP_SendAAStats(const EQApplicationPacket *app) void Client::Handle_Connect_OP_SendAATable(const EQApplicationPacket *app) { - SendAAList(); + SendAlternateAdvancementTable(); return; } void Client::Handle_Connect_OP_SendExpZonein(const EQApplicationPacket *app) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendExpZonein, 0); + auto outapp = new EQApplicationPacket(OP_SendExpZonein, 0); QueuePacket(outapp); safe_delete(outapp); // SoF+ Gets Zone-In packets after sending OP_WorldObjectsSent - if (GetClientVersion() < ClientVersion::SoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::SoF) { SendZoneInPackets(); } @@ -1153,7 +1156,7 @@ void Client::Handle_Connect_OP_TGB(const EQApplicationPacket *app) void Client::Handle_Connect_OP_UpdateAA(const EQApplicationPacket *app) { - SendAATable(); + SendAlternateAdvancementPoints(); } void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app) @@ -1165,7 +1168,7 @@ void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app) void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app) { // New for SoF+ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0); + auto outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0); QueuePacket(outapp); safe_delete(outapp); @@ -1182,7 +1185,7 @@ void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app) void Client::Handle_Connect_OP_ZoneComplete(const EQApplicationPacket *app) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_0x0347, 0); + auto outapp = new EQApplicationPacket(OP_0x0347, 0); QueuePacket(outapp); safe_delete(outapp); return; @@ -1199,8 +1202,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) conn_state = ReceivedZoneEntry; - SetClientVersion(Connection()->GetClientVersion()); - m_ClientVersionBit = ClientBitFromVersion(Connection()->GetClientVersion()); + SetClientVersion(Connection()->ClientVersion()); + m_ClientVersionBit = EQEmu::versions::ConvertClientVersionToClientVersionBit(Connection()->ClientVersion()); bool siv = m_inv.SetInventoryVersion(m_ClientVersion); Log.Out(Logs::General, Logs::None, "%s inventory version to %s(%i)", (siv ? "Succeeded in setting" : "Failed to set"), ClientVersionName(m_ClientVersion), m_ClientVersion); @@ -1313,11 +1316,11 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) } /* Set item material tint */ - for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) + for (int i = EQEmu::textures::TextureBegin; i <= EQEmu::textures::LastTexture; i++) { - if (m_pp.item_tint[i].RGB.UseTint == 1 || m_pp.item_tint[i].RGB.UseTint == 255) + if (m_pp.item_tint.Slot[i].UseTint == 1 || m_pp.item_tint.Slot[i].UseTint == 255) { - m_pp.item_tint[i].RGB.UseTint = 0xFF; + m_pp.item_tint.Slot[i].UseTint = 0xFF; } } @@ -1387,7 +1390,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) m_pp.guild_id = GuildID(); uint8 rank = guild_mgr.GetDisplayedRank(GuildID(), GuildRank(), CharacterID()); // FIXME: RoF guild rank - if (GetClientVersion() >= ClientVersion::RoF) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { switch (rank) { case 0: rank = 5; @@ -1440,48 +1443,15 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000){ m_pp.ldon_points_tak = 0; } if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; } - /* Initialize AA's : Move to function eventually */ - for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ aa[a] = &m_pp.aa_array[a]; } - query = StringFormat( - "SELECT " - "slot, " - "aa_id, " - "aa_value " - "FROM " - "`character_alternate_abilities` " - "WHERE `id` = %u ORDER BY `slot`", this->CharacterID()); - results = database.QueryDatabase(query); i = 0; - for (auto row = results.begin(); row != results.end(); ++row) { - i = atoi(row[0]); - m_pp.aa_array[i].AA = atoi(row[1]); - m_pp.aa_array[i].value = atoi(row[2]); - aa[i]->AA = atoi(row[1]); - aa[i]->value = atoi(row[2]); + if(RuleB(World, UseClientBasedExpansionSettings)) { + m_pp.expansions = EQEmu::versions::ConvertClientVersionToExpansion(ClientVersion()); + } + else { + m_pp.expansions = RuleI(World, ExpansionSettings); } - for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ - uint32 id = aa[a]->AA; - //watch for invalid AA IDs - if (id == aaNone) - continue; - if (id >= aaHighestID) { - aa[a]->AA = aaNone; - aa[a]->value = 0; - continue; - } - if (aa[a]->value == 0) { - aa[a]->AA = aaNone; - continue; - } - if (aa[a]->value > HIGHEST_AA_VALUE) { - aa[a]->AA = aaNone; - aa[a]->value = 0; - continue; - } - if (aa[a]->value > 1) /* hack in some stuff for sony's new AA method (where each level of each aa.has a seperate ID) */ - aa_points[(id - aa[a]->value + 1)] = aa[a]->value; - else - aa_points[id] = aa[a]->value; + if(!database.LoadAlternateAdvancement(this)) { + Log.Out(Logs::General, Logs::Error, "Error loading AA points for %s", GetName()); } if (SPDAT_RECORDS > 0) { @@ -1495,23 +1465,25 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) for (int i = 0; i < max_slots; i++) { if (buffs[i].spellid != SPELL_UNKNOWN) { m_pp.buffs[i].spellid = buffs[i].spellid; - m_pp.buffs[i].bard_modifier = 10; - m_pp.buffs[i].slotid = 2; + m_pp.buffs[i].bard_modifier = buffs[i].instrument_mod; + m_pp.buffs[i].effect_type = 2; m_pp.buffs[i].player_id = 0x2211; m_pp.buffs[i].level = buffs[i].casterlevel; - m_pp.buffs[i].effect = 0; + m_pp.buffs[i].unknown003 = 0; m_pp.buffs[i].duration = buffs[i].ticsremaining; m_pp.buffs[i].counters = buffs[i].counters; + m_pp.buffs[i].num_hits = buffs[i].numhits; } else { m_pp.buffs[i].spellid = SPELLBOOK_UNKNOWN; m_pp.buffs[i].bard_modifier = 10; - m_pp.buffs[i].slotid = 0; + m_pp.buffs[i].effect_type = 0; m_pp.buffs[i].player_id = 0; m_pp.buffs[i].level = 0; - m_pp.buffs[i].effect = 0; + m_pp.buffs[i].unknown003 = 0; m_pp.buffs[i].duration = 0; m_pp.buffs[i].counters = 0; + m_pp.buffs[i].num_hits = 0; } } } @@ -1606,11 +1578,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) /* Update LFP in case any (or all) of our group disbanded while we were zoning. */ if (IsLFP()) { UpdateLFP(); } - /* Get Expansions from variables table and ship via PP */ - char val[20] = { 0 }; - if (database.GetVariable("Expansions", val, 20)){ m_pp.expansions = atoi(val); } - else{ m_pp.expansions = 0x3FF; } - p_timers.SetCharID(CharacterID()); if (!p_timers.Load(&database)) { Log.Out(Logs::General, Logs::Error, "Unable to load ability timers from the database for %s (%i)!", GetCleanName(), CharacterID()); @@ -1704,7 +1671,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) /* Time of Day packet */ outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer; - zone->zone_time.getEQTimeOfDay(time(0), tod); + zone->zone_time.GetCurrentEQTimeOfDay(time(0), tod); outapp->priority = 6; FastQueuePacket(&outapp); @@ -1727,20 +1694,20 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (iter == m_inv.cursor_cbegin()) continue; const ItemInst *inst = *iter; - SendItemPacket(MainCursor, inst, ItemPacketSummonItem); + SendItemPacket(EQEmu::legacy::SlotCursor, inst, ItemPacketLimbo); } } /* Task Packets */ LoadClientTaskState(); - if (GetClientVersion() >= ClientVersion::RoF) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { outapp = new EQApplicationPacket(OP_ReqNewZone, 0); Handle_Connect_OP_ReqNewZone(outapp); safe_delete(outapp); } - if (m_ClientVersionBit & BIT_UFAndLater) { + if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) { outapp = new EQApplicationPacket(OP_XTargetResponse, 8); outapp->WriteUInt32(GetMaxXTargets()); outapp->WriteUInt32(0); @@ -1766,7 +1733,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) SetAttackTimer(); conn_state = ZoneInfoSent; - + zoneinpacket_timer.Start(); return; } @@ -1785,38 +1752,39 @@ void Client::Handle_OP_AAAction(const EQApplicationPacket *app) Log.Out(Logs::Detail, Logs::AA, "Received OP_AAAction"); if (app->size != sizeof(AA_Action)){ - printf("Error! OP_AAAction size didnt match!\n"); + Log.Out(Logs::General, Logs::AA, "Error! OP_AAAction size didnt match!"); return; } AA_Action* action = (AA_Action*)app->pBuffer; if (action->action == aaActionActivate) {//AA Hotkey Log.Out(Logs::Detail, Logs::AA, "Activating AA %d", action->ability); - ActivateAA((aaID)action->ability); + ActivateAlternateAdvancementAbility(action->ability, action->target_id); } else if (action->action == aaActionBuy) { - BuyAA(action); + PurchaseAlternateAdvancementRank(action->ability); } else if (action->action == aaActionDisableEXP){ //Turn Off AA Exp if (m_epp.perAA > 0) Message_StringID(0, AA_OFF); + m_epp.perAA = 0; - SendAAStats(); + SendAlternateAdvancementStats(); } else if (action->action == aaActionSetEXP) { if (m_epp.perAA == 0) Message_StringID(0, AA_ON); m_epp.perAA = action->exp_value; - if (m_epp.perAA<0 || m_epp.perAA>100) m_epp.perAA = 0; // stop exploit with sanity check + if (m_epp.perAA < 0 || m_epp.perAA > 100) + m_epp.perAA = 0; // stop exploit with sanity check + // send an update - SendAAStats(); - SendAATable(); + SendAlternateAdvancementStats(); + SendAlternateAdvancementTable(); } else { - printf("Unknown AA action: %u %u 0x%x %d\n", action->action, action->ability, action->unknown08, action->exp_value); + Log.Out(Logs::General, Logs::AA, "Unknown AA action : %u %u %u %d", action->action, action->ability, action->target_id, action->exp_value); } - - return; } void Client::Handle_OP_AcceptNewTask(const EQApplicationPacket *app) @@ -1849,7 +1817,7 @@ void Client::Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app) it = zone->adventure_entry_list_flavor.find(m->CastToNPC()->GetAdventureTemplate()); if (it != zone->adventure_entry_list_flavor.end()) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureInfo, (it->second.size() + 2)); + auto outapp = new EQApplicationPacket(OP_AdventureInfo, (it->second.size() + 2)); strn0cpy((char*)outapp->pBuffer, it->second.c_str(), it->second.size()); FastQueuePacket(&outapp); } @@ -1858,7 +1826,7 @@ void Client::Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app) if (m->CastToNPC()->GetAdventureTemplate() != 0) { std::string text = "Choose your difficulty and preferred adventure type."; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureInfo, (text.size() + 2)); + auto outapp = new EQApplicationPacket(OP_AdventureInfo, (text.size() + 2)); strn0cpy((char*)outapp->pBuffer, text.c_str(), text.size()); FastQueuePacket(&outapp); } @@ -1879,7 +1847,7 @@ void Client::Handle_OP_AdventureLeaderboardRequest(const EQApplicationPacket *ap } adventure_leaderboard_timer = new Timer(4000); - ServerPacket *pack = new ServerPacket(ServerOP_AdventureLeaderboard, sizeof(ServerLeaderboardRequest_Struct)); + auto pack = new ServerPacket(ServerOP_AdventureLeaderboard, sizeof(ServerLeaderboardRequest_Struct)); ServerLeaderboardRequest_Struct *lr = (ServerLeaderboardRequest_Struct*)pack->pBuffer; strcpy(lr->player, GetName()); @@ -1918,7 +1886,7 @@ void Client::Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app) merchantid = tmp->CastToNPC()->MerchantType; - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; bool found = false; std::list merlist = zone->merchanttable[merchantid]; std::list::const_iterator itr; @@ -2064,7 +2032,7 @@ void Client::Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app) ItemInst *inst = database.CreateItem(item, charges); if (!AutoPutLootInInventory(*inst, true, true)) { - PutLootInInventory(MainCursor, *inst); + PutLootInInventory(EQEmu::legacy::SlotCursor, *inst); } Save(1); } @@ -2094,7 +2062,7 @@ void Client::Handle_OP_AdventureMerchantRequest(const EQApplicationPacket *app) merchantid = tmp->CastToNPC()->MerchantType; tmp->CastToNPC()->FaceTarget(this->CastToMob()); - const Item_Struct *item = 0; + const EQEmu::ItemBase *item = 0; std::list merlist = zone->merchanttable[merchantid]; std::list::const_iterator itr; for (itr = merlist.begin(); itr != merlist.end() && count<255; ++itr){ @@ -2193,7 +2161,7 @@ void Client::Handle_OP_AdventureMerchantSell(const EQApplicationPacket *app) return; } - const Item_Struct* item = database.GetItem(itemid); + const EQEmu::ItemBase* item = database.GetItem(itemid); ItemInst* inst = GetInv().GetItem(ams_in->slot); if (!item || !inst){ Message(13, "You seemed to have misplaced that item..."); @@ -2225,7 +2193,8 @@ void Client::Handle_OP_AdventureMerchantSell(const EQApplicationPacket *app) return; } - int32 price = item->LDoNPrice * 70 / 100; + // 06/11/2016 This formula matches RoF2 client side calculation. + int32 price = (item->LDoNPrice + 1) * item->LDoNSellBackRate / 100; if (price == 0) { @@ -2257,7 +2226,7 @@ void Client::Handle_OP_AdventureMerchantSell(const EQApplicationPacket *app) price *= ams_in->charges; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureMerchantSell, sizeof(Adventure_Sell_Struct)); + auto outapp = new EQApplicationPacket(OP_AdventureMerchantSell, sizeof(Adventure_Sell_Struct)); Adventure_Sell_Struct *ams = (Adventure_Sell_Struct*)outapp->pBuffer; ams->slot = ams_in->slot; ams->unknown000 = 1; @@ -2350,7 +2319,8 @@ void Client::Handle_OP_AdventureRequest(const EQApplicationPacket *app) return; } - ServerPacket *packet = new ServerPacket(ServerOP_AdventureRequest, sizeof(ServerAdventureRequest_Struct)+(64 * group_members)); + auto packet = + new ServerPacket(ServerOP_AdventureRequest, sizeof(ServerAdventureRequest_Struct) + (64 * group_members)); ServerAdventureRequest_Struct *sar = (ServerAdventureRequest_Struct*)packet->pBuffer; sar->member_count = group_members; sar->risk = ars->risk; @@ -2411,7 +2381,7 @@ void Client::Handle_OP_AdventureStatsRequest(const EQApplicationPacket *app) } adventure_stats_timer = new Timer(8000); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureStatsReply, sizeof(AdventureStats_Struct)); + auto outapp = new EQApplicationPacket(OP_AdventureStatsReply, sizeof(AdventureStats_Struct)); AdventureStats_Struct *as = (AdventureStats_Struct*)outapp->pBuffer; if (database.GetAdventureStats(CharacterID(), as)) @@ -2449,7 +2419,7 @@ void Client::Handle_OP_AltCurrencyMerchantRequest(const EQApplicationPacket *app return; } - std::list::iterator altc_iter = zone->AlternateCurrencies.begin(); + auto altc_iter = zone->AlternateCurrencies.begin(); bool found = false; while (altc_iter != zone->AlternateCurrencies.end()) { if ((*altc_iter).id == alt_cur_id) { @@ -2468,7 +2438,7 @@ void Client::Handle_OP_AltCurrencyMerchantRequest(const EQApplicationPacket *app ss << alt_cur_id << "|1|" << alt_cur_id; uint32 count = 0; uint32 merchant_id = tar->MerchantType; - const Item_Struct *item = nullptr; + const EQEmu::ItemBase *item = nullptr; std::list merlist = zone->merchanttable[merchant_id]; std::list::const_iterator itr; @@ -2528,7 +2498,7 @@ void Client::Handle_OP_AltCurrencyPurchase(const EQApplicationPacket *app) return; } - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; uint32 cost = 0; uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id); uint32 merchant_id = tar->MerchantType; @@ -2587,7 +2557,7 @@ void Client::Handle_OP_AltCurrencyPurchase(const EQApplicationPacket *app) ItemInst *inst = database.CreateItem(item, charges); if (!AutoPutLootInInventory(*inst, true, true)) { - PutLootInInventory(MainCursor, *inst); + PutLootInInventory(EQEmu::legacy::SlotCursor, *inst); } Save(1); @@ -2599,7 +2569,7 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app) VERIFY_PACKET_LENGTH(OP_AltCurrencyReclaim, app, AltCurrencyReclaim_Struct); AltCurrencyReclaim_Struct *reclaim = (AltCurrencyReclaim_Struct*)app->pBuffer; uint32 item_id = 0; - std::list::iterator iter = zone->AlternateCurrencies.begin(); + auto iter = zone->AlternateCurrencies.begin(); while (iter != zone->AlternateCurrencies.end()) { if ((*iter).id == reclaim->currency_id) { item_id = (*iter).item_id; @@ -2628,13 +2598,16 @@ void Client::Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app) else { uint32 max_currency = GetAlternateCurrencyValue(reclaim->currency_id); + if(max_currency == 0 || reclaim->count == 0) + return; + /* If you input more than you have currency wise, just give the max of the currency you currently have */ if (reclaim->count > max_currency) { SummonItem(item_id, max_currency); SetAlternateCurrencyValue(reclaim->currency_id, 0); } else { - SummonItem(item_id, reclaim->count, 0, 0, 0, 0, 0, 0, false, MainCursor); + SummonItem(item_id, reclaim->count, 0, 0, 0, 0, 0, 0, false, EQEmu::legacy::SlotCursor); AddAlternateCurrencyValue(reclaim->currency_id, -((int32)reclaim->count)); } /* QS: PlayerLogAlternateCurrencyTransactions :: Cursor to Item Storage */ @@ -2674,7 +2647,7 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app) return; } - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; uint32 cost = 0; uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id); uint32 merchant_id = tar->MerchantType; @@ -2767,7 +2740,7 @@ void Client::Handle_OP_AltCurrencySellSelection(const EQApplicationPacket *app) return; } - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; uint32 cost = 0; uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id); uint32 merchant_id = tar->MerchantType; @@ -2806,7 +2779,8 @@ void Client::Handle_OP_AltCurrencySellSelection(const EQApplicationPacket *app) cost = 0; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AltCurrencySellSelection, sizeof(AltCurrencySelectItemReply_Struct)); + auto outapp = + new EQApplicationPacket(OP_AltCurrencySellSelection, sizeof(AltCurrencySelectItemReply_Struct)); AltCurrencySelectItemReply_Struct *reply = (AltCurrencySelectItemReply_Struct*)outapp->pBuffer; reply->unknown004 = 0xFF; reply->unknown005 = 0xFF; @@ -2831,8 +2805,7 @@ void Client::Handle_OP_Animation(const EQApplicationPacket *app) Animation_Struct *s = (Animation_Struct *)app->pBuffer; //might verify spawn ID, but it wouldent affect anything - - DoAnim(s->action, s->value); + DoAnim(s->action, s->speed); return; } @@ -2846,11 +2819,11 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app) } uint32 ApplyPoisonSuccessResult = 0; ApplyPoison_Struct* ApplyPoisonData = (ApplyPoison_Struct*)app->pBuffer; - const ItemInst* PrimaryWeapon = GetInv().GetItem(MainPrimary); - const ItemInst* SecondaryWeapon = GetInv().GetItem(MainSecondary); + const ItemInst* PrimaryWeapon = GetInv().GetItem(EQEmu::legacy::SlotPrimary); + const ItemInst* SecondaryWeapon = GetInv().GetItem(EQEmu::legacy::SlotSecondary); const ItemInst* PoisonItemInstance = GetInv()[ApplyPoisonData->inventorySlot]; - bool IsPoison = PoisonItemInstance && (PoisonItemInstance->GetItem()->ItemType == ItemTypePoison); + bool IsPoison = PoisonItemInstance && (PoisonItemInstance->GetItem()->ItemType == EQEmu::item::ItemTypePoison); if (!IsPoison) { @@ -2861,12 +2834,12 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app) } else if (GetClass() == ROGUE) { - if ((PrimaryWeapon && PrimaryWeapon->GetItem()->ItemType == ItemType1HPiercing) || - (SecondaryWeapon && SecondaryWeapon->GetItem()->ItemType == ItemType1HPiercing)) { - float SuccessChance = (GetSkill(SkillApplyPoison) + GetLevel()) / 400.0f; + if ((PrimaryWeapon && PrimaryWeapon->GetItem()->ItemType == EQEmu::item::ItemType1HPiercing) || + (SecondaryWeapon && SecondaryWeapon->GetItem()->ItemType == EQEmu::item::ItemType1HPiercing)) { + float SuccessChance = (GetSkill(EQEmu::skills::SkillApplyPoison) + GetLevel()) / 400.0f; double ChanceRoll = zone->random.Real(0, 1); - CheckIncreaseSkill(SkillApplyPoison, nullptr, 10); + CheckIncreaseSkill(EQEmu::skills::SkillApplyPoison, nullptr, 10); if (ChanceRoll < SuccessChance) { ApplyPoisonSuccessResult = 1; @@ -2881,7 +2854,7 @@ void Client::Handle_OP_ApplyPoison(const EQApplicationPacket *app) } } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ApplyPoison, nullptr, sizeof(ApplyPoison_Struct)); + auto outapp = new EQApplicationPacket(OP_ApplyPoison, nullptr, sizeof(ApplyPoison_Struct)); ApplyPoison_Struct* ApplyPoisonResult = (ApplyPoison_Struct*)outapp->pBuffer; ApplyPoisonResult->success = ApplyPoisonSuccessResult; ApplyPoisonResult->inventorySlot = ApplyPoisonData->inventorySlot; @@ -2942,7 +2915,7 @@ void Client::Handle_OP_AugmentInfo(const EQApplicationPacket *app) } AugmentInfo_Struct* AugInfo = (AugmentInfo_Struct*)app->pBuffer; - const Item_Struct * item = database.GetItem(AugInfo->itemid); + const EQEmu::ItemBase * item = database.GetItem(AugInfo->itemid); if (item) { strn0cpy(AugInfo->augment_info, item->Name, 64); @@ -2959,150 +2932,292 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) return; } - // Delegate to tradeskill object to perform combine AugmentItem_Struct* in_augment = (AugmentItem_Struct*)app->pBuffer; bool deleteItems = false; - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { ItemInst *itemOneToPush = nullptr, *itemTwoToPush = nullptr; - //Message(15, "%i %i %i %i %i %i", in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); + //Log.Out(Logs::DebugLevel::Moderate, Logs::Debug, "cslot: %i aslot: %i cidx: %i aidx: %i act: %i dest: %i", + // in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); - // Adding augment - if (in_augment->augment_action == 0) + ItemInst *tobe_auged = nullptr, *old_aug = nullptr, *new_aug = nullptr, *aug = nullptr, *solvent = nullptr; + Inventory& user_inv = GetInv(); + + uint16 item_slot = in_augment->container_slot; + uint16 solvent_slot = in_augment->augment_slot; + uint8 mat = Inventory::CalcMaterialFromSlot(item_slot); // for when player is augging a piece of equipment while they're wearing it + + if (item_slot == INVALID_INDEX || solvent_slot == INVALID_INDEX) { - ItemInst *tobe_auged = nullptr, *auged_with = nullptr; - int8 slot = -1; - Inventory& user_inv = GetInv(); + Message(13, "Error: Invalid Aug Index."); + return; + } - uint16 slot_id = in_augment->container_slot; - uint16 aug_slot_id = in_augment->augment_slot; - if (slot_id == INVALID_INDEX || aug_slot_id == INVALID_INDEX) + tobe_auged = user_inv.GetItem(item_slot); + solvent = user_inv.GetItem(solvent_slot); + + if (!tobe_auged) + { + Message(13, "Error: Invalid item passed for augmenting."); + return; + } + + if ((in_augment->augment_action == 1) || (in_augment->augment_action == 2)) + { + // Check for valid distiller if safely removing / swapping an augmentation + + if (!solvent) { - Message(13, "Error: Invalid Aug Index."); + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment without a distiller."); + Message(13, "Error: Missing an augmentation distiller for safely removing this augment."); return; } - - tobe_auged = user_inv.GetItem(slot_id); - auged_with = user_inv.GetItem(MainCursor); - - if (tobe_auged && auged_with) + else if (solvent->GetItem()->ItemType == EQEmu::item::ItemTypeAugmentationDistiller) { - if (((tobe_auged->IsAugmentSlotAvailable(auged_with->GetAugmentType(), in_augment->augment_index)) != -1) && - (tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots))) + old_aug = tobe_auged->GetAugment(in_augment->augment_index); + + if (!old_aug) { - tobe_auged->PutAugment(in_augment->augment_index, *auged_with); - tobe_auged->UpdateOrnamentationInfo(); + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove a nonexistent augment."); + Message(13, "Error: No augment found in slot %i for safely removing.", in_augment->augment_index); + return; + } + else if (solvent->GetItem()->ID != old_aug->GetItem()->AugDistiller) + { + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with the wrong distiller (item %u vs expected %u).", solvent->GetItem()->ID, old_aug->GetItem()->AugDistiller); + Message(13, "Error: Wrong augmentation distiller for safely removing this augment."); + return; + } + } + else if (solvent->GetItem()->ItemType != EQEmu::item::ItemTypePerfectedAugmentationDistiller) + { + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with a non-distiller item."); + Message(13, "Error: Invalid augmentation distiller for safely removing this augment."); + return; + } + } - ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_index); - if (aug) { - std::vector args; - args.push_back(aug); - parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); - - args.assign(1, tobe_auged); - parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args); - } - else - { - Message(13, "Error: Could not find augmentation at index %i. Aborting.", in_augment->augment_index); - return; - } - - itemOneToPush = tobe_auged->Clone(); - // Must push items after the items in inventory are deleted - necessary due to lore items... - if (itemOneToPush) - { - DeleteItemInInventory(slot_id, 0, true); - DeleteItemInInventory(MainCursor, 0, true); - - if (PutItemInInventory(slot_id, *itemOneToPush, true)) - { - CalcBonuses(); - // Successfully added an augment to the item - return; - } - else - { - Message(13, "Error: No available slot for end result. Please free up the augment slot."); - } - } - else - { - Message(13, "Error in cloning item for augment. Aborted."); - } + switch (in_augment->augment_action) + { + case 0: // Adding an augment + case 2: // Swapping augment + new_aug = user_inv.GetItem(EQEmu::legacy::SlotCursor); + if (!new_aug) // Shouldn't get the OP code without the augment on the user's cursor, but maybe it's h4x. + { + Log.Out(Logs::General, Logs::Error, "AugmentItem OpCode with 'Insert' or 'Swap' action received, but no augment on client's cursor."); + Message(13, "Error: No augment found on cursor for inserting."); + return; } else { - Message(13, "Error: No available slot for augment in that item."); + if (((tobe_auged->IsAugmentSlotAvailable(new_aug->GetAugmentType(), in_augment->augment_index)) != -1) && + (tobe_auged->AvailableWearSlot(new_aug->GetItem()->Slots))) + { + old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); + if (old_aug) + { + // An old augment was removed in order to be replaced with the new one (augment_action 2) + + CalcBonuses(); + + std::vector args; + args.push_back(old_aug); + parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + + args.assign(1, tobe_auged); + args.push_back(false); + parse->EventItem(EVENT_AUGMENT_REMOVE, this, old_aug, nullptr, "", in_augment->augment_index, &args); + } + + tobe_auged->PutAugment(in_augment->augment_index, *new_aug); + tobe_auged->UpdateOrnamentationInfo(); + + aug = tobe_auged->GetAugment(in_augment->augment_index); + if (aug) + { + std::vector args; + args.push_back(aug); + parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + + args.assign(1, tobe_auged); + parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args); + } + else + { + Message(13, "Error: Could not properly insert augmentation into augment slot %i. Aborting.", in_augment->augment_index); + return; + } + + itemOneToPush = tobe_auged->Clone(); + if (old_aug) + { + itemTwoToPush = old_aug->Clone(); + } + + // Must push items after the items in inventory are deleted - necessary due to lore items... + if (itemOneToPush) + { + DeleteItemInInventory(item_slot, 0, true); + DeleteItemInInventory(EQEmu::legacy::SlotCursor, new_aug->IsStackable() ? 1 : 0, true); + + if (solvent) + { + // Consume the augment distiller + DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true); + } + + if (itemTwoToPush) + { + // This is a swap. Return the old aug to the player's cursor. + if (!PutItemInInventory(EQEmu::legacy::SlotCursor, *itemTwoToPush, true)) + { + Log.Out(Logs::General, Logs::Error, "Problem returning old augment to player's cursor after augmentation swap."); + Message(15, "Error: Failed to retrieve old augment after augmentation swap!"); + } + } + + if (PutItemInInventory(item_slot, *itemOneToPush, true)) + { + // Successfully added an augment to the item + + CalcBonuses(); + + if (mat != EQEmu::textures::TextureInvalid) + { + SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed. + } + } + else + { + Message(13, "Error: No available slot for end result. Please free up the augment slot."); + } + } + else + { + Message(13, "Error in cloning item for augment. Aborted."); + } + } + else + { + Message(13, "Error: No available slot for augment in that item."); + } } - } - } - else if (in_augment->augment_action == 1) - { - ItemInst *tobe_auged = nullptr, *auged_with = nullptr; - int8 slot = -1; - Inventory& user_inv = GetInv(); - - uint16 slot_id = in_augment->container_slot; - uint16 aug_slot_id = in_augment->augment_slot; //it's actually solvent slot - if (slot_id == INVALID_INDEX || aug_slot_id == INVALID_INDEX) - { - Message(13, "Error: Invalid Aug Index."); - return; - } - - tobe_auged = user_inv.GetItem(slot_id); - auged_with = user_inv.GetItem(aug_slot_id); - - ItemInst *old_aug = nullptr; - if (!auged_with) - return; - const uint32 id = auged_with->GetID(); - ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_index); - if (aug) { - std::vector args; - args.push_back(aug); - parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); - - args.assign(1, tobe_auged); - - args.push_back(false); - - parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); - } - else - { - Message(13, "Error: Could not find augmentation at index %i. Aborting."); - return; - } - old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); - tobe_auged->UpdateOrnamentationInfo(); - - itemOneToPush = tobe_auged->Clone(); - if (old_aug) - itemTwoToPush = old_aug->Clone(); - if (itemOneToPush && itemTwoToPush && auged_with) - { - DeleteItemInInventory(slot_id, 0, true); - DeleteItemInInventory(aug_slot_id, auged_with->IsStackable() ? 1 : 0, true); - - if (!PutItemInInventory(slot_id, *itemOneToPush, true)) + break; + case 1: // Removing augment safely (distiller) + aug = tobe_auged->GetAugment(in_augment->augment_index); + if (aug) { - Message(15, "Failed to remove augment properly!"); + std::vector args; + args.push_back(aug); + parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + + args.assign(1, tobe_auged); + + args.push_back(false); + + parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); } - - if (PutItemInInventory(MainCursor, *itemTwoToPush, true)) + else { + Message(13, "Error: Could not find augmentation to remove at index %i. Aborting.", in_augment->augment_index); + return; + } + + old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); + tobe_auged->UpdateOrnamentationInfo(); + + itemOneToPush = tobe_auged->Clone(); + if (old_aug) + itemTwoToPush = old_aug->Clone(); + + if (itemOneToPush && itemTwoToPush) + { + // Consume the augment distiller + DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true); + + // Remove the augmented item + DeleteItemInInventory(item_slot, 0, true); + + // Replace it with the unaugmented item + if (!PutItemInInventory(item_slot, *itemOneToPush, true)) + { + Log.Out(Logs::General, Logs::Error, "Problem returning equipment item to player's inventory after safe augment removal."); + Message(15, "Error: Failed to return item after de-augmentation!"); + } + CalcBonuses(); - //Message(15, "Successfully removed an augmentation!"); + + if (mat != EQEmu::textures::TextureInvalid) + { + SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed. + } + + // Drop the removed augment on the player's cursor + if (!PutItemInInventory(EQEmu::legacy::SlotCursor, *itemTwoToPush, true)) + { + Log.Out(Logs::General, Logs::Error, "Problem returning augment to player's cursor after safe removal."); + Message(15, "Error: Failed to return augment after removal from item!"); + return; + } } - } + break; + case 3: // Destroying augment (formerly done in birdbath/sealer with a solvent) + + // RoF client does not require an augmentation solvent for destroying an augmentation in an item. + // Augments can be destroyed with a right click -> Destroy at any time. + + aug = tobe_auged->GetAugment(in_augment->augment_index); + if (aug) + { + std::vector args; + args.push_back(aug); + parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + + args.assign(1, tobe_auged); + + args.push_back(true); + + parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); + } + else + { + Message(13, "Error: Could not find augmentation to remove at index %i. Aborting."); + return; + } + + tobe_auged->DeleteAugment(in_augment->augment_index); + tobe_auged->UpdateOrnamentationInfo(); + + itemOneToPush = tobe_auged->Clone(); + if (itemOneToPush) + { + DeleteItemInInventory(item_slot, 0, true); + + if (!PutItemInInventory(item_slot, *itemOneToPush, true)) + { + Log.Out(Logs::General, Logs::Error, "Problem returning equipment item to player's inventory after augment deletion."); + Message(15, "Error: Failed to return item after destroying augment!"); + } + } + + CalcBonuses(); + + if (mat != EQEmu::textures::TextureInvalid) + { + SendWearChange(mat); + } + break; + default: // Unknown + Log.Out(Logs::General, Logs::Inventory, "Unrecognized augmentation action - cslot: %i aslot: %i cidx: %i aidx: %i act: %i dest: %i", + in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); + break; } } else { + // Delegate to tradeskill object to perform combine Object::HandleAugmentation(this, in_augment, m_tradeskill_object); } return; @@ -3240,7 +3355,7 @@ void Client::Handle_OP_BankerChange(const EQApplicationPacket *app) return; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_BankerChange, nullptr, sizeof(BankerChange_Struct)); + auto outapp = new EQApplicationPacket(OP_BankerChange, nullptr, sizeof(BankerChange_Struct)); BankerChange_Struct *bc = (BankerChange_Struct *)outapp->pBuffer; if (m_pp.platinum < 0) @@ -3397,7 +3512,7 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app) { BarterItemSearchLinkRequest_Struct* bislr = (BarterItemSearchLinkRequest_Struct*)app->pBuffer; - const Item_Struct* item = database.GetItem(bislr->ItemID); + const EQEmu::ItemBase* item = database.GetItem(bislr->ItemID); if (!item) Message(13, "Error: This item does not exist!"); @@ -3430,7 +3545,7 @@ void Client::Handle_OP_Barter(const EQApplicationPacket *app) { BuyerItemSearchLinkRequest_Struct* bislr = (BuyerItemSearchLinkRequest_Struct*)app->pBuffer; - const Item_Struct* item = database.GetItem(bislr->ItemID); + const EQEmu::ItemBase* item = database.GetItem(bislr->ItemID); if (!item) Message(13, "Error: This item does not exist!"); @@ -3469,7 +3584,7 @@ void Client::Handle_OP_BazaarInspect(const EQApplicationPacket *app) BazaarInspect_Struct* bis = (BazaarInspect_Struct*)app->pBuffer; - const Item_Struct* item = database.GetItem(bis->ItemID); + const EQEmu::ItemBase* item = database.GetItem(bis->ItemID); if (!item) { Message(13, "Error: This item does not exist!"); @@ -3529,14 +3644,14 @@ void Client::Handle_OP_Begging(const EQApplicationPacket *app) { Message(13, "Ability recovery time not yet met."); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Begging, sizeof(BeggingResponse_Struct)); + auto outapp = new EQApplicationPacket(OP_Begging, sizeof(BeggingResponse_Struct)); BeggingResponse_Struct *brs = (BeggingResponse_Struct*)outapp->pBuffer; brs->Result = 0; FastQueuePacket(&outapp); return; } - if (!HasSkill(SkillBegging) || !GetTarget()) + if (!HasSkill(EQEmu::skills::SkillBegging) || !GetTarget()) return; if (GetTarget()->GetClass() == LDON_TREASURE) @@ -3544,7 +3659,7 @@ void Client::Handle_OP_Begging(const EQApplicationPacket *app) p_timers.Start(pTimerBeggingPickPocket, 8); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Begging, sizeof(BeggingResponse_Struct)); + auto outapp = new EQApplicationPacket(OP_Begging, sizeof(BeggingResponse_Struct)); BeggingResponse_Struct *brs = (BeggingResponse_Struct*)outapp->pBuffer; brs->Result = 0; // Default, Fail. @@ -3574,7 +3689,7 @@ void Client::Handle_OP_Begging(const EQApplicationPacket *app) return; } - uint16 CurrentSkill = GetSkill(SkillBegging); + uint16 CurrentSkill = GetSkill(EQEmu::skills::SkillBegging); float ChanceToBeg = ((float)(CurrentSkill / 700.0f) + 0.15f) * 100; @@ -3596,7 +3711,7 @@ void Client::Handle_OP_Begging(const EQApplicationPacket *app) } QueuePacket(outapp); safe_delete(outapp); - CheckIncreaseSkill(SkillBegging, nullptr, -10); + CheckIncreaseSkill(EQEmu::skills::SkillBegging, nullptr, -10); } void Client::Handle_OP_Bind_Wound(const EQApplicationPacket *app) @@ -3651,7 +3766,7 @@ void Client::Handle_OP_BlockedBuffs(const EQApplicationPacket *app) } } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_BlockedBuffs, sizeof(BlockedBuffs_Struct)); + auto outapp = new EQApplicationPacket(OP_BlockedBuffs, sizeof(BlockedBuffs_Struct)); BlockedBuffs_Struct *obbs = (BlockedBuffs_Struct*)outapp->pBuffer; @@ -3679,7 +3794,7 @@ void Client::Handle_OP_BlockedBuffs(const EQApplicationPacket *app) if ((bbs->Initialise == 0) && (bbs->Count > 0)) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_BlockedBuffs, sizeof(BlockedBuffs_Struct)); + auto outapp = new EQApplicationPacket(OP_BlockedBuffs, sizeof(BlockedBuffs_Struct)); BlockedBuffs_Struct *obbs = (BlockedBuffs_Struct*)outapp->pBuffer; @@ -3738,15 +3853,15 @@ void Client::Handle_OP_BoardBoat(const EQApplicationPacket *app) void Client::Handle_OP_Buff(const EQApplicationPacket *app) { - if (app->size != sizeof(SpellBuffFade_Struct)) + if (app->size != sizeof(SpellBuffPacket_Struct)) { - Log.Out(Logs::General, Logs::Error, "Size mismatch in OP_Buff. expected %i got %i", sizeof(SpellBuffFade_Struct), app->size); + Log.Out(Logs::General, Logs::Error, "Size mismatch in OP_Buff. expected %i got %i", sizeof(SpellBuffPacket_Struct), app->size); DumpPacket(app); return; } - SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*)app->pBuffer; - uint32 spid = sbf->spellid; + SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*)app->pBuffer; + uint32 spid = sbf->buff.spellid; Log.Out(Logs::Detail, Logs::Spells, "Client requested that buff with spell id %d be canceled.", spid); //something about IsDetrimentalSpell() crashes this portion of code.. @@ -3784,7 +3899,7 @@ void Client::Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app) uint16 SpellID = m->GetSpellIDFromSlot(brrs->SlotID); - if (SpellID && IsBeneficialSpell(SpellID)) + if (SpellID && IsBeneficialSpell(SpellID) && !spells[SpellID].no_remove) m->BuffFadeBySlot(brrs->SlotID, true); } @@ -3803,7 +3918,6 @@ void Client::Handle_OP_Camp(const EQApplicationPacket *app) { #ifdef BOTS // This block is necessary to clean up any bot objects owned by a Client - Bot::BotHealRotationsClear(this); Bot::BotOrderCampAll(this); #endif if (IsLFP()) @@ -3870,6 +3984,7 @@ void Client::Handle_OP_CancelTrade(const EQApplicationPacket *app) void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) { + using EQEmu::CastingSlot; if (app->size != sizeof(CastSpell_Struct)) { std::cout << "Wrong size: OP_CastSpell, size=" << app->size << ", expected " << sizeof(CastSpell_Struct) << std::endl; return; @@ -3882,13 +3997,13 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) CastSpell_Struct* castspell = (CastSpell_Struct*)app->pBuffer; - m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos); + m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos); Log.Out(Logs::General, Logs::Spells, "OP CastSpell: slot=%d, spell=%d, target=%d, inv=%lx", castspell->slot, castspell->spell_id, castspell->target_id, (unsigned long)castspell->inventoryslot); + CastingSlot slot = static_cast(castspell->slot); /* Memorized Spell */ - if (m_pp.mem_spells[castspell->slot] && m_pp.mem_spells[castspell->slot] == castspell->spell_id){ - + if (m_pp.mem_spells[castspell->slot] && m_pp.mem_spells[castspell->slot] == castspell->spell_id) { uint16 spell_to_cast = 0; if (castspell->slot < MAX_PP_MEMSPELL) { spell_to_cast = m_pp.mem_spells[castspell->slot]; @@ -3902,29 +4017,19 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) return; } - m_TargetRing = glm::vec3(castspell->x_pos, castspell->y_pos, castspell->z_pos); - - CastSpell(spell_to_cast, castspell->target_id, castspell->slot); + CastSpell(spell_to_cast, castspell->target_id, slot); } /* Spell Slot or Potion Belt Slot */ - else if ((castspell->slot == USE_ITEM_SPELL_SLOT) || (castspell->slot == POTION_BELT_SPELL_SLOT)|| (castspell->slot == TARGET_RING_SPELL_SLOT)) // ITEM or POTION cast + else if (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt) // ITEM or POTION cast { - //discipline, using the item spell slot - if (castspell->inventoryslot == INVALID_INDEX) { - if (!UseDiscipline(castspell->spell_id, castspell->target_id)) { - Log.Out(Logs::General, Logs::Spells, "Unknown ability being used by %s, spell being cast is: %i\n", GetName(), castspell->spell_id); - InterruptSpell(castspell->spell_id); - } - return; - } - else if (m_inv.SupportsClickCasting(castspell->inventoryslot) || (castspell->slot == POTION_BELT_SPELL_SLOT) || (castspell->slot == TARGET_RING_SPELL_SLOT)) // sanity check + if (m_inv.SupportsClickCasting(castspell->inventoryslot) || slot == CastingSlot::PotionBelt) // sanity check { // packet field types will be reviewed as packet transistions occur const ItemInst* inst = m_inv[castspell->inventoryslot]; //slot values are int16, need to check packet on this field //bool cancast = true; - if (inst && inst->IsType(ItemClassCommon)) + if (inst && inst->IsClassCommon()) { - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); if (item->Click.Effect != (uint32)castspell->spell_id) { database.SetMQDetectionFlag(account_name, name, "OP_CastSpell with item, tried to cast a different spell.", zone->GetShortName()); @@ -3932,7 +4037,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) return; } - if ((item->Click.Type == ET_ClickEffect) || (item->Click.Type == ET_Expendable) || (item->Click.Type == ET_EquipClick) || (item->Click.Type == ET_ClickEffect2)) + if ((item->Click.Type == EQEmu::item::ItemEffectClick) || (item->Click.Type == EQEmu::item::ItemEffectExpendable) || (item->Click.Type == EQEmu::item::ItemEffectEquipClick) || (item->Click.Type == EQEmu::item::ItemEffectClick2)) { if (item->Click.Level2 > 0) { @@ -3942,7 +4047,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) int i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot); if (i == 0) { - CastSpell(item->Click.Effect, castspell->target_id, castspell->slot, item->CastTime, 0, 0, castspell->inventoryslot); + CastSpell(item->Click.Effect, castspell->target_id, slot, item->CastTime, 0, 0, castspell->inventoryslot); } else { InterruptSpell(castspell->spell_id); @@ -3962,7 +4067,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) int i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot); if (i == 0) { - CastSpell(item->Click.Effect, castspell->target_id, castspell->slot, item->CastTime, 0, 0, castspell->inventoryslot); + CastSpell(item->Click.Effect, castspell->target_id, slot, item->CastTime, 0, 0, castspell->inventoryslot); } else { InterruptSpell(castspell->spell_id); @@ -3983,12 +4088,12 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) } else { - Message(0, "Error: castspell->inventoryslot >= %i (0x%04x)", MainCursor, castspell->inventoryslot); + Message(0, "Error: castspell->inventoryslot >= %i (0x%04x)", EQEmu::legacy::SlotCursor, castspell->inventoryslot); InterruptSpell(castspell->spell_id); } } - /* Discipline */ - else if (castspell->slot == DISCIPLINE_SPELL_SLOT) { + /* Discipline -- older clients use the same slot as items, but we translate to it's own */ + else if (slot == CastingSlot::Discipline) { if (!UseDiscipline(castspell->spell_id, castspell->target_id)) { Log.Out(Logs::General, Logs::Spells, "Unknown ability being used by %s, spell being cast is: %i\n", GetName(), castspell->spell_id); InterruptSpell(castspell->spell_id); @@ -3996,7 +4101,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) } } /* ABILITY cast (LoH and Harm Touch) */ - else if (castspell->slot == ABILITY_SPELL_SLOT) { + else if (slot == CastingSlot::Ability) { uint16 spell_to_cast = 0; if (castspell->spell_id == SPELL_LAY_ON_HANDS && GetClass() == PALADIN) { @@ -4026,7 +4131,7 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app) } if (spell_to_cast > 0) // if we've matched LoH or HT, cast now - CastSpell(spell_to_cast, castspell->target_id, castspell->slot); + CastSpell(spell_to_cast, castspell->target_id, slot); } return; } @@ -4142,7 +4247,7 @@ void Client::Handle_OP_ClickObject(const EQApplicationPacket *app) char buf[10]; snprintf(buf, 9, "%u", click_object->drop_id); buf[9] = '\0'; - parse->EventPlayer(EVENT_CLICK_OBJECT, this, buf, 0, &args); + parse->EventPlayer(EVENT_CLICK_OBJECT, this, buf, GetID(), &args); } // Observed in RoF after OP_ClickObjectAction: @@ -4162,15 +4267,11 @@ void Client::Handle_OP_ClickObjectAction(const EQApplicationPacket *app) EQApplicationPacket end_trade2(OP_FinishWindow2, 0); QueuePacket(&end_trade2); - return; - // RoF sends a 0 sized packet for closing objects - /* - Object* object = GetTradeskillObject(); - if (object) { - object->CastToObject()->Close(); - } - */ + if (GetTradeskillObject() && ClientVersion() >= EQEmu::versions::ClientVersion::RoF) + GetTradeskillObject()->CastToObject()->Close(); + + return; } else { @@ -4262,7 +4363,8 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) auto boatDelta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, ppu->delta_heading); boat->SetDelta(boatDelta); // send an update to everyone nearby except the client controlling the boat - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + auto outapp = + new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); PlayerPositionUpdateServer_Struct* ppus = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer; boat->MakeSpawnUpdate(ppus); entity_list.QueueCloseClients(boat,outapp,true,300,this,false); @@ -4293,7 +4395,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) if((cur_time - m_TimeSinceLastPositionCheck) > 0) { float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); - float runs = GetRunspeed(); + int runs = GetRunspeed(); if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) { if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) @@ -4361,7 +4463,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) if((cur_time - m_TimeSinceLastPositionCheck) > 2500) { float speed = (m_DistanceSinceLastPositionCheck * 100) / (float)(cur_time - m_TimeSinceLastPositionCheck); - float runs = GetRunspeed(); + int runs = GetRunspeed(); if(speed > (runs * RuleR(Zone, MQWarpDetectionDistanceFactor))) { if(!GetGMSpeed() && (runs >= GetBaseRunspeed() || (speed > (GetBaseRunspeed() * RuleR(Zone, MQWarpDetectionDistanceFactor))))) @@ -4451,7 +4553,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) if(IsTracking() && ((m_Position.x!=ppu->x_pos) || (m_Position.y!=ppu->y_pos))){ if(zone->random.Real(0, 100) < 70)//should be good - CheckIncreaseSkill(SkillTracking, nullptr, -20); + CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, -20); } // Break Hide if moving without sneaking and set rewind timer if moved @@ -4460,7 +4562,8 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) hidden = false; improved_hidden = false; if(!invisible) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + auto outapp = + new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer; sa_out->spawn_id = GetID(); sa_out->type = 0x03; @@ -4474,17 +4577,27 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) // Outgoing client packet float tmpheading = EQ19toFloat(ppu->heading); + /* The clients send an update at best every 1.3 seconds + * We want to avoid reflecting these updates to other clients as much as possible + * The client also sends an update every 280 ms while turning, if we prevent + * sending these by checking if the location is the same too aggressively, clients end up spinning + * so keep a count of how many packets are the same within a tolerance and stop when we get there */ - if (!FCMP(ppu->y_pos, m_Position.y) || !FCMP(ppu->x_pos, m_Position.x) || !FCMP(tmpheading, m_Position.w) || ppu->animation != animation) + bool pos_same = FCMP(ppu->y_pos, m_Position.y) && FCMP(ppu->x_pos, m_Position.x) && FCMP(tmpheading, m_Position.w) && ppu->animation == animation; + if (!pos_same || (pos_same && position_update_same_count < 6)) { + if (pos_same) + position_update_same_count++; + else + position_update_same_count = 0; + m_Position.x = ppu->x_pos; m_Position.y = ppu->y_pos; m_Position.z = ppu->z_pos; m_Position.w = tmpheading; animation = ppu->animation; - - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + auto outapp = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); PlayerPositionUpdateServer_Struct* ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer; MakeSpawnUpdate(ppu); if (gmhideme) @@ -4494,8 +4607,11 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) safe_delete(outapp); } - if(zone->watermap && zone->watermap->InLiquid(glm::vec3(m_Position))) - CheckIncreaseSkill(SkillSwimming, nullptr, -17); + if (zone->watermap) { + if (zone->watermap->InLiquid(glm::vec3(m_Position))) + CheckIncreaseSkill(EQEmu::skills::SkillSwimming, nullptr, -17); + CheckRegionTypeChanges(); + } return; } @@ -4541,7 +4657,7 @@ void Client::Handle_OP_Consent(const EQApplicationPacket *app) if(app->size<64){ Consent_Struct* c = (Consent_Struct*)app->pBuffer; if(strcmp(c->name, GetName()) != 0) { - ServerPacket* pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); + auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; strcpy(scs->grantname, c->name); strcpy(scs->ownername, GetName()); @@ -4564,7 +4680,7 @@ void Client::Handle_OP_ConsentDeny(const EQApplicationPacket *app) { if(app->size<64){ Consent_Struct* c = (Consent_Struct*)app->pBuffer; - ServerPacket* pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); + auto pack = new ServerPacket(ServerOP_Consent, sizeof(ServerOP_Consent_Struct)); ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; strcpy(scs->grantname, c->name); strcpy(scs->ownername, GetName()); @@ -4597,7 +4713,7 @@ void Client::Handle_OP_Consider(const EQApplicationPacket *app) return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Consider, sizeof(Consider_Struct)); + auto outapp = new EQApplicationPacket(OP_Consider, sizeof(Consider_Struct)); Consider_Struct* con = (Consider_Struct*)outapp->pBuffer; con->playerid = GetID(); con->targetid = conin->targetid; @@ -4778,12 +4894,12 @@ void Client::Handle_OP_Consume(const EQApplicationPacket *app) return; } - const Item_Struct* eat_item = myitem->GetItem(); + const EQEmu::ItemBase* eat_item = myitem->GetItem(); if (pcs->type == 0x01) { - Consume(eat_item, ItemTypeFood, pcs->slot, (pcs->auto_consumed == 0xffffffff)); + Consume(eat_item, EQEmu::item::ItemTypeFood, pcs->slot, (pcs->auto_consumed == 0xffffffff)); } else if (pcs->type == 0x02) { - Consume(eat_item, ItemTypeDrink, pcs->slot, (pcs->auto_consumed == 0xffffffff)); + Consume(eat_item, EQEmu::item::ItemTypeDrink, pcs->slot, (pcs->auto_consumed == 0xffffffff)); } else { Log.Out(Logs::General, Logs::Error, "OP_Consume: unknown type, type:%i", (int)pcs->type); @@ -4837,7 +4953,7 @@ void Client::Handle_OP_ControlBoat(const EQApplicationPacket *app) else boat->SetTarget(0); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ControlBoat, 0); + auto outapp = new EQApplicationPacket(OP_ControlBoat, 0); FastQueuePacket(&outapp); safe_delete(outapp); // have the boat signal itself, so quests can be triggered by boat use @@ -4908,7 +5024,7 @@ void Client::Handle_OP_CrashDump(const EQApplicationPacket *app) void Client::Handle_OP_CreateObject(const EQApplicationPacket *app) { - DropItem(MainCursor); + DropItem(EQEmu::legacy::SlotCursor); return; } @@ -4917,38 +5033,49 @@ void Client::Handle_OP_CrystalCreate(const EQApplicationPacket *app) VERIFY_PACKET_LENGTH(OP_CrystalCreate, app, CrystalReclaim_Struct); CrystalReclaim_Struct *cr = (CrystalReclaim_Struct*)app->pBuffer; - if (cr->type == 5) { - if (cr->amount > GetEbonCrystals()) { - SummonItem(RuleI(Zone, EbonCrystalItemID), GetEbonCrystals()); - m_pp.currentEbonCrystals = 0; - m_pp.careerEbonCrystals = 0; - SaveCurrency(); - SendCrystalCounts(); - } - else { - SummonItem(RuleI(Zone, EbonCrystalItemID), cr->amount); - m_pp.currentEbonCrystals -= cr->amount; - m_pp.careerEbonCrystals -= cr->amount; - SaveCurrency(); - SendCrystalCounts(); - } + const uint32 requestQty = cr->amount; + const bool isRadiant = cr->type == 4; + const bool isEbon = cr->type == 5; + + // Check: Valid type requested. + if (!isRadiant && !isEbon) { + return; } - else if (cr->type == 4) { - if (cr->amount > GetRadiantCrystals()) { - SummonItem(RuleI(Zone, RadiantCrystalItemID), GetRadiantCrystals()); - m_pp.currentRadCrystals = 0; - m_pp.careerRadCrystals = 0; - SaveCurrency(); - SendCrystalCounts(); - } - else { - SummonItem(RuleI(Zone, RadiantCrystalItemID), cr->amount); - m_pp.currentRadCrystals -= cr->amount; - m_pp.careerRadCrystals -= cr->amount; - SaveCurrency(); - SendCrystalCounts(); - } + // Check: Valid quantity requested. + if (requestQty < 1) { + return; } + + // Check: Valid client state to make request. + // In this situation the client is either desynced or attempting an exploit. + const uint32 currentQty = isRadiant ? GetRadiantCrystals() : GetEbonCrystals(); + if (currentQty == 0) { + return; + } + + // Prevent the client from creating more than they have. + const uint32 amount = EQEmu::ClampUpper(requestQty, currentQty); + const uint32 itemID = isRadiant ? RuleI(Zone, RadiantCrystalItemID) : RuleI(Zone, EbonCrystalItemID); + + // Summon crystals for player. + const bool success = SummonItem(itemID, amount); + + if (!success) { + return; + } + + // Deduct crystals from client and update them. + if (isRadiant) { + m_pp.currentRadCrystals -= amount; + m_pp.careerRadCrystals -= amount; + } + else if (isEbon) { + m_pp.currentEbonCrystals -= amount; + m_pp.careerEbonCrystals -= amount; + } + + SaveCurrency(); + SendCrystalCounts(); } void Client::Handle_OP_CrystalReclaim(const EQApplicationPacket *app) @@ -4984,7 +5111,7 @@ void Client::Handle_OP_Death(const EQApplicationPacket *app) Death_Struct* ds = (Death_Struct*)app->pBuffer; //I think this attack_skill value is really a value from SkillDamageTypes... - if (ds->attack_skill > HIGHEST_SKILL) { + if (ds->attack_skill > EQEmu::skills::HIGHEST_SKILL) { return; } @@ -4992,7 +5119,7 @@ void Client::Handle_OP_Death(const EQApplicationPacket *app) return; Mob* killer = entity_list.GetMob(ds->killer_id); - Death(killer, ds->damage, ds->spell_id, (SkillUseTypes)ds->attack_skill); + Death(killer, ds->damage, ds->spell_id, (EQEmu::skills::SkillType)ds->attack_skill); return; } @@ -5051,14 +5178,14 @@ void Client::Handle_OP_DeleteItem(const EQApplicationPacket *app) DeleteItem_Struct* alc = (DeleteItem_Struct*)app->pBuffer; const ItemInst *inst = GetInv().GetItem(alc->from_slot); - if (inst && inst->GetItem()->ItemType == ItemTypeAlcohol) { + if (inst && inst->GetItem()->ItemType == EQEmu::item::ItemTypeAlcohol) { entity_list.MessageClose_StringID(this, true, 50, 0, DRINKING_MESSAGE, GetName(), inst->GetItem()->Name); - CheckIncreaseSkill(SkillAlcoholTolerance, nullptr, 25); + CheckIncreaseSkill(EQEmu::skills::SkillAlcoholTolerance, nullptr, 25); - int16 AlcoholTolerance = GetSkill(SkillAlcoholTolerance); + int16 AlcoholTolerance = GetSkill(EQEmu::skills::SkillAlcoholTolerance); int16 IntoxicationIncrease; - if (GetClientVersion() < ClientVersion::SoD) + if (ClientVersion() < EQEmu::versions::ClientVersion::SoD) IntoxicationIncrease = (200 - AlcoholTolerance) * 30 / 200 + 10; else IntoxicationIncrease = (270 - AlcoholTolerance) * 0.111111108 + 10; @@ -5082,7 +5209,7 @@ void Client::Handle_OP_DeleteSpawn(const EQApplicationPacket *app) //eqs->RemoveData(); // Flushing the queue of packet data to allow for proper zoning //just make sure this gets out - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LogoutReply); + auto outapp = new EQApplicationPacket(OP_LogoutReply); FastQueuePacket(&outapp); outapp = new EQApplicationPacket(OP_DeleteSpawn, sizeof(EntityId_Struct)); @@ -5123,31 +5250,25 @@ void Client::Handle_OP_DeleteSpell(const EQApplicationPacket *app) void Client::Handle_OP_DisarmTraps(const EQApplicationPacket *app) { - if (!HasSkill(SkillDisarmTraps)) + if (!HasSkill(EQEmu::skills::SkillDisarmTraps)) return; if (!p_timers.Expired(&database, pTimerDisarmTraps, false)) { Message(13, "Ability recovery time not yet met."); return; } - int reuse = DisarmTrapsReuseTime; - switch (GetAA(aaAdvTrapNegotiation)) { - case 1: - reuse -= 1; - break; - case 2: - reuse -= 3; - break; - case 3: - reuse -= 5; - break; - } + + int reuse = DisarmTrapsReuseTime - GetSkillReuseTime(EQEmu::skills::SkillDisarmTraps); + + if (reuse < 1) + reuse = 1; + p_timers.Start(pTimerDisarmTraps, reuse - 1); Trap* trap = entity_list.FindNearbyTrap(this, 60); if (trap && trap->detected) { - int uskill = GetSkill(SkillDisarmTraps); + int uskill = GetSkill(EQEmu::skills::SkillDisarmTraps); if ((zone->random.Int(0, 49) + uskill) >= (zone->random.Int(0, 49) + trap->skill)) { Message(MT_Skills, "You disarm a trap."); @@ -5165,7 +5286,7 @@ void Client::Handle_OP_DisarmTraps(const EQApplicationPacket *app) Message(MT_Skills, "You failed to disarm a trap."); } } - CheckIncreaseSkill(SkillDisarmTraps, nullptr); + CheckIncreaseSkill(EQEmu::skills::SkillDisarmTraps, nullptr); return; } Message(MT_Skills, "You did not find any traps close enough to disarm."); @@ -5266,7 +5387,7 @@ void Client::Handle_OP_DuelResponse2(const EQApplicationPacket *app) Entity* initiator = entity_list.GetID(ds->duel_initiator); if (entity && initiator && entity == this && initiator->IsClient()) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RequestDuel, sizeof(Duel_Struct)); + auto outapp = new EQApplicationPacket(OP_RequestDuel, sizeof(Duel_Struct)); Duel_Struct* ds2 = (Duel_Struct*)outapp->pBuffer; ds2->duel_initiator = entity->GetID(); @@ -5299,10 +5420,10 @@ void Client::Handle_OP_DumpName(const EQApplicationPacket *app) void Client::Handle_OP_Dye(const EQApplicationPacket *app) { - if (app->size != sizeof(DyeStruct)) - printf("Wrong size of DyeStruct, Got: %i, Expected: %zu\n", app->size, sizeof(DyeStruct)); + if (app->size != sizeof(EQEmu::TintProfile)) + printf("Wrong size of DyeStruct, Got: %i, Expected: %zu\n", app->size, sizeof(EQEmu::TintProfile)); else{ - DyeStruct* dye = (DyeStruct*)app->pBuffer; + EQEmu::TintProfile* dye = (EQEmu::TintProfile*)app->pBuffer; DyeArmor(dye); } return; @@ -5334,7 +5455,7 @@ void Client::Handle_OP_Emote(const EQApplicationPacket *app) + len_msg + 1; // Construct outgoing packet - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Emote, len_packet); + auto outapp = new EQApplicationPacket(OP_Emote, len_packet); Emote_Struct* out = (Emote_Struct*)outapp->pBuffer; out->type = in->type; memcpy(out->message, name, len_name); @@ -5376,7 +5497,7 @@ void Client::Handle_OP_EndLootRequest(const EQApplicationPacket *app) Entity* entity = entity_list.GetID(*((uint16*)app->pBuffer)); if (entity == 0) { Message(13, "Error: OP_EndLootRequest: Corpse not found (ent = 0)"); - if (GetClientVersion() >= ClientVersion::SoD) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) Corpse::SendEndLootErrorPacket(this); else Corpse::SendLootReqErrorPacket(this); @@ -5413,17 +5534,9 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app) if (ed->dmgtype == 252) { - switch (GetAA(aaAcrobatics)) { //Don't know what acrobatics effect is yet but it should be done client side via aa effect.. till then - case 1: - damage = damage * 95 / 100; - break; - case 2: - damage = damage * 90 / 100; - break; - case 3: - damage = damage * 80 / 100; - break; - } + int mod = spellbonuses.ReduceFallDamage + itembonuses.ReduceFallDamage + aabonuses.ReduceFallDamage; + + damage -= damage * mod / 100; } if (damage < 0) @@ -5449,13 +5562,13 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app) /* EVENT_ENVIRONMENTAL_DAMAGE */ int final_damage = (damage * RuleR(Character, EnvironmentDamageMulipliter)); char buf[24]; - snprintf(buf, 23, "%u %u %i", ed->damage, ed->dmgtype, final_damage); + snprintf(buf, 23, "%u %u %i", ed->damage, ed->dmgtype, final_damage); parse->EventPlayer(EVENT_ENVIRONMENTAL_DAMAGE, this, buf, 0); } if (GetHP() <= 0) { - mod_client_death_env(); - Death(0, 32000, SPELL_UNKNOWN, SkillHandtoHand); + mod_client_death_env(); + Death(0, 32000, SPELL_UNKNOWN, EQEmu::skills::SkillHandtoHand); } SendHPUpdate(); return; @@ -5497,25 +5610,19 @@ void Client::Handle_OP_FeignDeath(const EQApplicationPacket *app) Message(13, "Ability recovery time not yet met."); return; } + int reuse = FeignDeathReuseTime; - switch (GetAA(aaRapidFeign)) - { - case 1: - reuse -= 1; - break; - case 2: - reuse -= 2; - break; - case 3: - reuse -= 5; - break; - } + reuse -= GetSkillReuseTime(EQEmu::skills::SkillFeignDeath); + + if (reuse < 1) + reuse = 1; + p_timers.Start(pTimerFeignDeath, reuse - 1); //BreakInvis(); - uint16 primfeign = GetSkill(SkillFeignDeath); - uint16 secfeign = GetSkill(SkillFeignDeath); + uint16 primfeign = GetSkill(EQEmu::skills::SkillFeignDeath); + uint16 secfeign = GetSkill(EQEmu::skills::SkillFeignDeath); if (primfeign > 100) { primfeign = 100; secfeign = secfeign - 100; @@ -5533,7 +5640,7 @@ void Client::Handle_OP_FeignDeath(const EQApplicationPacket *app) SetFeigned(true); } - CheckIncreaseSkill(SkillFeignDeath, nullptr, 5); + CheckIncreaseSkill(EQEmu::skills::SkillFeignDeath, nullptr, 5); return; } @@ -5593,7 +5700,7 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app) { std::deque pathlist = zone->pathing->FindRoute(Start, End); - if (pathlist.size() == 0) + if (pathlist.empty()) { EQApplicationPacket outapp(OP_FindPersonReply, 0); QueuePacket(&outapp); @@ -5822,7 +5929,7 @@ void Client::Handle_OP_GMFind(const EQApplicationPacket *app) //Break down incoming GMSummon_Struct* request = (GMSummon_Struct*)app->pBuffer; //Create a new outgoing - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GMFind, sizeof(GMSummon_Struct)); + auto outapp = new EQApplicationPacket(OP_GMFind, sizeof(GMSummon_Struct)); GMSummon_Struct* foundplayer = (GMSummon_Struct*)outapp->pBuffer; //Copy the constants strcpy(foundplayer->charname, request->charname); @@ -5861,7 +5968,7 @@ void Client::Handle_OP_GMGoto(const EQApplicationPacket *app) else if (!worldserver.Connected()) Message(0, "Error: World server disconnected."); else { - ServerPacket* pack = new ServerPacket(ServerOP_GMGoto, sizeof(ServerGMGoto_Struct)); + auto pack = new ServerPacket(ServerOP_GMGoto, sizeof(ServerGMGoto_Struct)); memset(pack->pBuffer, 0, pack->size); ServerGMGoto_Struct* wsgmg = (ServerGMGoto_Struct*)pack->pBuffer; strcpy(wsgmg->myname, this->GetName()); @@ -5907,7 +6014,7 @@ void Client::Handle_OP_GMKick(const EQApplicationPacket *app) if (!worldserver.Connected()) Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); + auto pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*)pack->pBuffer; strcpy(skp->adminname, gmk->gmname); strcpy(skp->name, gmk->name); @@ -5949,7 +6056,7 @@ void Client::Handle_OP_GMKill(const EQApplicationPacket *app) if (!worldserver.Connected()) Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_KillPlayer, sizeof(ServerKillPlayer_Struct)); + auto pack = new ServerPacket(ServerOP_KillPlayer, sizeof(ServerKillPlayer_Struct)); ServerKillPlayer_Struct* skp = (ServerKillPlayer_Struct*)pack->pBuffer; strcpy(skp->gmname, gmk->gmname); strcpy(skp->target, gmk->name); @@ -6059,10 +6166,10 @@ void Client::Handle_OP_GMSearchCorpse(const EQApplicationPacket *app) GMSearchCorpse_Struct *gmscs = (GMSearchCorpse_Struct *)app->pBuffer; gmscs->Name[63] = '\0'; - char *escSearchString = new char[129]; + auto escSearchString = new char[129]; database.DoEscapeString(escSearchString, gmscs->Name, strlen(gmscs->Name)); - std::string query = StringFormat("SELECT charname, zoneid, x, y, z, time_of_death, rezzed, IsBurried " + std::string query = StringFormat("SELECT charname, zone_id, x, y, z, time_of_death, is_rezzed, is_buried " "FROM character_corpses WheRE charname LIKE '%%%s%%' ORDER BY charname LIMIT %i", escSearchString, maxResults); safe_delete_array(escSearchString); @@ -6121,7 +6228,7 @@ void Client::Handle_OP_GMServers(const EQApplicationPacket *app) if (!worldserver.Connected()) Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_ZoneStatus, strlen(this->GetName()) + 2); + auto pack = new ServerPacket(ServerOP_ZoneStatus, strlen(this->GetName()) + 2); memset(pack->pBuffer, (uint8)admin, 1); strcpy((char *)&pack->pBuffer[1], this->GetName()); worldserver.SendPacket(pack); @@ -6223,7 +6330,7 @@ void Client::Handle_OP_GMZoneRequest(const EQApplicationPacket *app) tarzone[0] = 0; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMZoneRequest, sizeof(GMZoneRequest_Struct)); + auto outapp = new EQApplicationPacket(OP_GMZoneRequest, sizeof(GMZoneRequest_Struct)); GMZoneRequest_Struct* gmzr2 = (GMZoneRequest_Struct*)outapp->pBuffer; strcpy(gmzr2->charname, this->GetName()); gmzr2->zone_id = gmzr->zone_id; @@ -6283,7 +6390,7 @@ void Client::Handle_OP_GroupCancelInvite(const EQApplicationPacket *app) } else { - ServerPacket* pack = new ServerPacket(ServerOP_GroupCancelInvite, sizeof(GroupCancel_Struct)); + auto pack = new ServerPacket(ServerOP_GroupCancelInvite, sizeof(GroupCancel_Struct)); memcpy(pack->pBuffer, gf, sizeof(GroupCancel_Struct)); worldserver.SendPacket(pack); safe_delete(pack); @@ -6381,15 +6488,25 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app) Bot::ProcessBotGroupDisband(this, std::string()); } else { - Mob* tempMember = entity_list.GetMob(gd->name2); - if (tempMember) { - if (tempMember->IsBot()) - Bot::ProcessBotGroupDisband(this, std::string(tempMember->GetCleanName())); + Mob* tempMember = entity_list.GetMob(gd->name1); //Name1 is the target you are disbanding + if (tempMember && tempMember->IsBot()) { + tempMember->CastToBot()->RemoveBotFromGroup(tempMember->CastToBot(), group); + if (LFP) + { + // If we are looking for players, update to show we are on our own now. + UpdateLFP(); + } + return; //No need to continue from here we were removing a bot from party } } } } + + group = GetGroup(); + if (!group) //We must recheck this here.. incase the final bot disbanded the party..otherwise we crash + return; #endif + if (group->GroupCount() < 3) { group->DisbandGroup(); @@ -6509,7 +6626,7 @@ void Client::Handle_OP_GroupFollow2(const EQApplicationPacket *app) // Inviter is in another zone - Remove merc from group now if any LeaveGroup(); - ServerPacket* pack = new ServerPacket(ServerOP_GroupFollow, sizeof(ServerGroupFollow_Struct)); + auto pack = new ServerPacket(ServerOP_GroupFollow, sizeof(ServerGroupFollow_Struct)); ServerGroupFollow_Struct *sgfs = (ServerGroupFollow_Struct *)pack->pBuffer; sgfs->CharacterID = CharacterID(); strn0cpy(sgfs->gf.name1, gf->name1, sizeof(sgfs->gf.name1)); @@ -6553,7 +6670,8 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app) { //Make a new packet using all the same information but make sure it's a fixed GroupInvite opcode so we //Don't have to deal with GroupFollow2 crap. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupInvite, sizeof(GroupInvite_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupInvite, sizeof(GroupInvite_Struct)); memcpy(outapp->pBuffer, app->pBuffer, outapp->size); Invitee->CastToClient()->QueuePacket(outapp); safe_delete(outapp); @@ -6574,7 +6692,7 @@ void Client::Handle_OP_GroupInvite2(const EQApplicationPacket *app) } else { - ServerPacket* pack = new ServerPacket(ServerOP_GroupInvite, sizeof(GroupInvite_Struct)); + auto pack = new ServerPacket(ServerOP_GroupInvite, sizeof(GroupInvite_Struct)); memcpy(pack->pBuffer, gis, sizeof(GroupInvite_Struct)); worldserver.SendPacket(pack); safe_delete(pack); @@ -6746,20 +6864,6 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) uint32 Action = VARSTRUCT_DECODE_TYPE(uint32, Buffer); uint32 sentAction = Action; - if (GetClientVersion() >= ClientVersion::RoF) - { - Action += 1; - /* - // Need to find all of the action types for RoF and switch case here - switch(Action) - { - case 4: - Action = 5; - break; - } - */ - } - if (!IsInAGuild()) { Message(13, "You must be in a Guild to use the Guild Bank."); @@ -6846,7 +6950,7 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) return; } - ItemInst *CursorItemInst = GetInv().GetItem(MainCursor); + ItemInst *CursorItemInst = GetInv().GetItem(EQEmu::legacy::SlotCursor); bool Allowed = true; @@ -6859,7 +6963,7 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) return; } - const Item_Struct* CursorItem = CursorItemInst->GetItem(); + const EQEmu::ItemBase* CursorItem = CursorItemInst->GetItem(); if (!CursorItem->NoDrop || CursorItemInst->IsAttuned()) { @@ -6894,7 +6998,7 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) { GuildBankDepositAck(false, sentAction); - DeleteItemInInventory(MainCursor, 0, false); + DeleteItemInInventory(EQEmu::legacy::SlotCursor, 0, false); } break; @@ -6915,7 +7019,7 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) case GuildBankWithdraw: { - if (GetInv()[MainCursor]) + if (GetInv()[EQEmu::legacy::SlotCursor]) { Message_StringID(13, GUILD_BANK_EMPTY_HANDS); @@ -6961,7 +7065,7 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app) { PushItemOnCursor(*inst); - SendItemPacket(MainCursor, inst, ItemPacketSummonItem); + SendItemPacket(EQEmu::legacy::SlotCursor, inst, ItemPacketLimbo); GuildBanks->DeleteItem(GuildID(), gbwis->Area, gbwis->SlotID, gbwis->Quantity); } @@ -7274,11 +7378,11 @@ void Client::Handle_OP_GuildInvite(const EQApplicationPacket *app) gc->guildeqid = GuildID(); // Convert Membership Level between RoF and previous clients. - if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF) + if (client->ClientVersion() < EQEmu::versions::ClientVersion::RoF && ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { gc->officer = 0; } - if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF) + if (client->ClientVersion() >= EQEmu::versions::ClientVersion::RoF && ClientVersion() < EQEmu::versions::ClientVersion::RoF) { gc->officer = 8; } @@ -7319,7 +7423,7 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app) uint32 guildrank = gj->response; - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { if (gj->response > 9) { @@ -7354,11 +7458,11 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app) { Client* client = inviter->CastToClient(); // Convert Membership Level between RoF and previous clients. - if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF) + if (client->ClientVersion() < EQEmu::versions::ClientVersion::RoF && ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { guildrank = 0; } - if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF) + if (client->ClientVersion() >= EQEmu::versions::ClientVersion::RoF && ClientVersion() < EQEmu::versions::ClientVersion::RoF) { guildrank = 8; } @@ -7395,7 +7499,7 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app) guildrank = gj->response; - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { if (gj->response == 8) { @@ -7681,7 +7785,7 @@ void Client::Handle_OP_GuildRemove(const EQApplicationPacket *app) } if (!guild_mgr.SetGuild(char_id, GUILD_NONE, 0)) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GuildManageRemove, sizeof(GuildManageRemove_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildManageRemove, sizeof(GuildManageRemove_Struct)); GuildManageRemove_Struct* gm = (GuildManageRemove_Struct*)outapp->pBuffer; gm->guildeqid = GuildID(); strcpy(gm->member, gc->othername); @@ -7796,7 +7900,15 @@ void Client::Handle_OP_Heartbeat(const EQApplicationPacket *app) void Client::Handle_OP_Hide(const EQApplicationPacket *app) { - if (!HasSkill(SkillHide) && GetSkill(SkillHide) == 0) + // newer client respond to OP_CancelSneakHide with OP_Hide with a size of 4 and 0 data + if (app->size == 4) { + auto data = app->ReadUInt32(0); + if (data) + Log.Out(Logs::Detail, Logs::None, "Got OP_Hide with unexpected data %d", data); + return; + } + + if (!HasSkill(EQEmu::skills::SkillHide) && GetSkill(EQEmu::skills::SkillHide) == 0) { //Can not be able to train hide but still have it from racial though return; //You cannot hide if you do not have hide @@ -7806,21 +7918,25 @@ void Client::Handle_OP_Hide(const EQApplicationPacket *app) Message(13, "Ability recovery time not yet met."); return; } - int reuse = HideReuseTime - GetAA(209); + int reuse = HideReuseTime - GetSkillReuseTime(EQEmu::skills::SkillHide); + + if (reuse < 1) + reuse = 1; + p_timers.Start(pTimerHide, reuse - 1); - float hidechance = ((GetSkill(SkillHide) / 250.0f) + .25) * 100; + float hidechance = ((GetSkill(EQEmu::skills::SkillHide) / 250.0f) + .25) * 100; float random = zone->random.Real(0, 100); - CheckIncreaseSkill(SkillHide, nullptr, 5); + CheckIncreaseSkill(EQEmu::skills::SkillHide, nullptr, 5); if (random < hidechance) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer; sa_out->spawn_id = GetID(); sa_out->type = 0x03; sa_out->parameter = 1; entity_list.QueueClients(this, outapp, true); safe_delete(outapp); - if (GetAA(aaShroudofStealth)){ + if (spellbonuses.ShroudofStealth || aabonuses.ShroudofStealth || itembonuses.ShroudofStealth){ improved_hidden = true; hidden = true; } @@ -7828,13 +7944,13 @@ void Client::Handle_OP_Hide(const EQApplicationPacket *app) hidden = true; } if (GetClass() == ROGUE){ - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct)); + auto outapp = new EQApplicationPacket(OP_SimpleMessage, sizeof(SimpleMessage_Struct)); SimpleMessage_Struct *msg = (SimpleMessage_Struct *)outapp->pBuffer; msg->color = 0x010E; Mob *evadetar = GetTarget(); if (!auto_attack && (evadetar && evadetar->CheckAggro(this) && evadetar->IsNPC())) { - if (zone->random.Int(0, 260) < (int)GetSkill(SkillHide)) { + if (zone->random.Int(0, 260) < (int)GetSkill(EQEmu::skills::SkillHide)) { msg->string_id = EVADE_SUCCESS; RogueEvade(evadetar); } @@ -7928,17 +8044,17 @@ void Client::Handle_OP_InspectAnswer(const EQApplicationPacket *app) EQApplicationPacket* outapp = app->Copy(); InspectResponse_Struct* insr = (InspectResponse_Struct*)outapp->pBuffer; Mob* tmp = entity_list.GetMob(insr->TargetID); - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - for (int16 L = EmuConstants::EQUIPMENT_BEGIN; L <= MainWaist; L++) { + for (int16 L = EQEmu::legacy::EQUIPMENT_BEGIN; L <= EQEmu::legacy::SlotWaist; L++) { const ItemInst* inst = GetInv().GetItem(L); item = inst ? inst->GetItem() : nullptr; if (item) { strcpy(insr->itemnames[L], item->Name); if (inst && inst->GetOrnamentationAug(ornamentationAugtype)) { - const Item_Struct *aug_item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); + const EQEmu::ItemBase *aug_item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem(); insr->itemicons[L] = aug_item->Icon; } else if (inst->GetOrnamentationIcon()) { @@ -7951,15 +8067,15 @@ void Client::Handle_OP_InspectAnswer(const EQApplicationPacket *app) else { insr->itemicons[L] = 0xFFFFFFFF; } } - const ItemInst* inst = GetInv().GetItem(MainAmmo); + const ItemInst* inst = GetInv().GetItem(EQEmu::legacy::SlotAmmo); item = inst ? inst->GetItem() : nullptr; if (item) { // another one..I did these, didn't I!!? - strcpy(insr->itemnames[SoF::slots::MainAmmo], item->Name); - insr->itemicons[SoF::slots::MainAmmo] = item->Icon; + strcpy(insr->itemnames[SoF::invslot::PossessionsAmmo], item->Name); + insr->itemicons[SoF::invslot::PossessionsAmmo] = item->Icon; } - else { insr->itemicons[SoF::slots::MainAmmo] = 0xFFFFFFFF; } + else { insr->itemicons[SoF::invslot::PossessionsAmmo] = 0xFFFFFFFF; } InspectMessage_Struct* newmessage = (InspectMessage_Struct*)insr->text; InspectMessage_Struct& playermessage = this->GetInspectMessage(); @@ -7997,7 +8113,7 @@ void Client::Handle_OP_InspectRequest(const EQApplicationPacket *app) Mob* tmp = entity_list.GetMob(ins->TargetID); if (tmp != 0 && tmp->IsClient()) { - if (tmp->CastToClient()->GetClientVersion() < ClientVersion::SoF) { tmp->CastToClient()->QueuePacket(app); } // Send request to target + if (tmp->CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::SoF) { tmp->CastToClient()->QueuePacket(app); } // Send request to target // Inspecting an SoF or later client will make the server handle the request else { ProcessInspectRequest(tmp->CastToClient(), this); } } @@ -8025,97 +8141,80 @@ void Client::Handle_OP_InstillDoubt(const EQApplicationPacket *app) void Client::Handle_OP_ItemLinkClick(const EQApplicationPacket *app) { - if (app->size != sizeof(ItemViewRequest_Struct)){ - Log.Out(Logs::General, Logs::Error, "Wrong size on OP_ItemLinkClick. Got: %i, Expected: %i", app->size, sizeof(ItemViewRequest_Struct)); + if (app->size != sizeof(ItemViewRequest_Struct)) { + Log.Out(Logs::General, Logs::Error, "Wrong size on OP_ItemLinkClick. Got: %i, Expected: %i", app->size, + sizeof(ItemViewRequest_Struct)); DumpPacket(app); return; } DumpPacket(app); - ItemViewRequest_Struct* ivrs = (ItemViewRequest_Struct*)app->pBuffer; + ItemViewRequest_Struct *ivrs = (ItemViewRequest_Struct *)app->pBuffer; - //todo: verify ivrs->link_hash based on a rule, in case we don't care about people being able to sniff data from the item DB + // todo: verify ivrs->link_hash based on a rule, in case we don't care about people being able to sniff data + // from the item DB - const Item_Struct* item = database.GetItem(ivrs->item_id); + const EQEmu::ItemBase *item = database.GetItem(ivrs->item_id); if (!item) { - if (ivrs->item_id > 500000) - { - std::string response = ""; - int sayid = ivrs->item_id - 500000; - bool silentsaylink = false; - - if (sayid > 250000) //Silent Saylink - { - sayid = sayid - 250000; - silentsaylink = true; - } - - if (sayid > 0) - { - - std::string query = StringFormat("SELECT `phrase` FROM saylink WHERE `id` = '%i'", sayid); - auto results = database.QueryDatabase(query); - if (!results.Success()) { - Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str()); - return; - } - - if (results.RowCount() != 1) { - Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str()); - return; - } - - auto row = results.begin(); - response = row[0]; - - } - - if ((response).size() > 0) - { - if (!mod_saylink(response, silentsaylink)) { return; } - - if (GetTarget() && GetTarget()->IsNPC()) - { - if (silentsaylink) - { - parse->EventNPC(EVENT_SAY, GetTarget()->CastToNPC(), this, response.c_str(), 0); - parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); - } - else - { - Message(7, "You say, '%s'", response.c_str()); - ChannelMessageReceived(8, 0, 100, response.c_str()); - } - return; - } - else - { - if (silentsaylink) - { - parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); - } - else - { - Message(7, "You say, '%s'", response.c_str()); - ChannelMessageReceived(8, 0, 100, response.c_str()); - } - return; - } - } - else - { - Message(13, "Error: Say Link not found or is too long."); - return; - } - } - else { + if (ivrs->item_id != SAYLINK_ITEM_ID) { Message(13, "Error: The item for the link you have clicked on does not exist!"); return; } + // This new scheme will shuttle the ID in the first augment for non-silent links + // and the second augment for silent. + std::string response = ""; + bool silentsaylink = ivrs->augments[1] > 0 ? true : false; + int sayid = silentsaylink ? ivrs->augments[1] : ivrs->augments[0]; + if (sayid > 0) { + std::string query = StringFormat("SELECT `phrase` FROM saylink WHERE `id` = '%i'", sayid); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str()); + return; + } + + if (results.RowCount() != 1) { + Message(13, "Error: The saylink (%s) was not found in the database.", response.c_str()); + return; + } + + auto row = results.begin(); + response = row[0]; + } + + if ((response).size() > 0) { + if (!mod_saylink(response, silentsaylink)) { + return; + } + + if (GetTarget() && GetTarget()->IsNPC()) { + if (silentsaylink) { + parse->EventNPC(EVENT_SAY, GetTarget()->CastToNPC(), this, response.c_str(), 0); + parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); + } else { + Message(7, "You say, '%s'", response.c_str()); + ChannelMessageReceived(8, 0, 100, response.c_str()); + } + return; + } else { + if (silentsaylink) { + parse->EventPlayer(EVENT_SAY, this, response.c_str(), 0); + } else { + Message(7, "You say, '%s'", response.c_str()); + ChannelMessageReceived(8, 0, 100, response.c_str()); + } + return; + } + } else { + Message(13, "Error: Say Link not found or is too long."); + return; + } } - ItemInst* inst = database.CreateItem(item, item->MaxCharges, ivrs->augments[0], ivrs->augments[1], ivrs->augments[2], ivrs->augments[3], ivrs->augments[4], ivrs->augments[5]); + ItemInst *inst = + database.CreateItem(item, item->MaxCharges, ivrs->augments[0], ivrs->augments[1], ivrs->augments[2], + ivrs->augments[3], ivrs->augments[4], ivrs->augments[5]); if (inst) { SendItemPacket(0, inst, ItemPacketViewLink); safe_delete(inst); @@ -8146,9 +8245,9 @@ void Client::Handle_OP_ItemName(const EQApplicationPacket *app) return; } ItemNamePacket_Struct *p = (ItemNamePacket_Struct*)app->pBuffer; - const Item_Struct *item = 0; + const EQEmu::ItemBase *item = 0; if ((item = database.GetItem(p->item_id)) != nullptr) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ItemName, sizeof(ItemNamePacket_Struct)); + auto outapp = new EQApplicationPacket(OP_ItemName, sizeof(ItemNamePacket_Struct)); p = (ItemNamePacket_Struct*)outapp->pBuffer; memset(p, 0, sizeof(ItemNamePacket_Struct)); strcpy(p->name, item->Name); @@ -8162,10 +8261,11 @@ void Client::Handle_OP_ItemPreview(const EQApplicationPacket *app) VERIFY_PACKET_LENGTH(OP_ItemPreview, app, ItemPreview_Struct); ItemPreview_Struct *ips = (ItemPreview_Struct *)app->pBuffer; - const Item_Struct* item = database.GetItem(ips->itemid); + const EQEmu::ItemBase* item = database.GetItem(ips->itemid); if (item) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ItemPreview, strlen(item->Name) + strlen(item->Lore) + strlen(item->IDFile) + 898); + auto outapp = new EQApplicationPacket(OP_ItemPreview, strlen(item->Name) + strlen(item->Lore) + + strlen(item->IDFile) + 898); int spacer; for (spacer = 0; spacer < 16; spacer++) { @@ -8337,6 +8437,7 @@ void Client::Handle_OP_ItemPreview(const EQApplicationPacket *app) void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) { + using EQEmu::CastingSlot; if (app->size != sizeof(ItemVerifyRequest_Struct)) { Log.Out(Logs::General, Logs::Error, "OP size error: OP_ItemVerifyRequest expected:%i got:%i", sizeof(ItemVerifyRequest_Struct), app->size); @@ -8378,7 +8479,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) return; } - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); if (!item) { Message(0, "Error: item not found in inventory slot #%i", slot_id); DeleteItemInInventory(slot_id, 0, true); @@ -8412,7 +8513,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) Log.Out(Logs::General, Logs::None, "OP ItemVerifyRequest: spell=%i, target=%i, inv=%i", spell_id, target_id, slot_id); - if (m_inv.SupportsClickCasting(slot_id) || ((item->ItemType == ItemTypePotion || item->PotionBelt) && m_inv.SupportsPotionBeltCasting(slot_id))) // sanity check + if (m_inv.SupportsClickCasting(slot_id) || ((item->ItemType == EQEmu::item::ItemTypePotion || item->PotionBelt) && m_inv.SupportsPotionBeltCasting(slot_id))) // sanity check { ItemInst* p_inst = (ItemInst*)inst; @@ -8426,42 +8527,42 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) int r; bool tryaug = false; ItemInst* clickaug = 0; - Item_Struct* augitem = 0; + EQEmu::ItemBase* augitem = 0; - for (r = 0; r < EmuConstants::ITEM_COMMON_SIZE; r++) { + for (r = 0; r < EQEmu::legacy::ITEM_COMMON_SIZE; r++) { const ItemInst* aug_i = inst->GetAugment(r); if (!aug_i) continue; - const Item_Struct* aug = aug_i->GetItem(); + const EQEmu::ItemBase* aug = aug_i->GetItem(); if (!aug) continue; - if ((aug->Click.Type == ET_ClickEffect) || (aug->Click.Type == ET_Expendable) || (aug->Click.Type == ET_EquipClick) || (aug->Click.Type == ET_ClickEffect2)) + if ((aug->Click.Type == EQEmu::item::ItemEffectClick) || (aug->Click.Type == EQEmu::item::ItemEffectExpendable) || (aug->Click.Type == EQEmu::item::ItemEffectEquipClick) || (aug->Click.Type == EQEmu::item::ItemEffectClick2)) { tryaug = true; clickaug = (ItemInst*)aug_i; - augitem = (Item_Struct*)aug; + augitem = (EQEmu::ItemBase*)aug; spell_id = aug->Click.Effect; break; } } - if ((spell_id <= 0) && (item->ItemType != ItemTypeFood && item->ItemType != ItemTypeDrink && item->ItemType != ItemTypeAlcohol && item->ItemType != ItemTypeSpell)) + if ((spell_id <= 0) && (item->ItemType != EQEmu::item::ItemTypeFood && item->ItemType != EQEmu::item::ItemTypeDrink && item->ItemType != EQEmu::item::ItemTypeAlcohol && item->ItemType != EQEmu::item::ItemTypeSpell)) { Log.Out(Logs::General, Logs::None, "Item with no effect right clicked by %s", GetName()); } - else if (inst->IsType(ItemClassCommon)) + else if (inst->IsClassCommon()) { - if (item->ItemType == ItemTypeSpell && (strstr((const char*)item->Name, "Tome of ") || strstr((const char*)item->Name, "Skill: "))) + if (item->ItemType == EQEmu::item::ItemTypeSpell && (strstr((const char*)item->Name, "Tome of ") || strstr((const char*)item->Name, "Skill: "))) { DeleteItemInInventory(slot_id, 1, true); TrainDiscipline(item->ID); } - else if (item->ItemType == ItemTypeSpell) + else if (item->ItemType == EQEmu::item::ItemTypeSpell) { return; } - else if ((item->Click.Type == ET_ClickEffect) || (item->Click.Type == ET_Expendable) || (item->Click.Type == ET_EquipClick) || (item->Click.Type == ET_ClickEffect2)) + else if ((item->Click.Type == EQEmu::item::ItemEffectClick) || (item->Click.Type == EQEmu::item::ItemEffectExpendable) || (item->Click.Type == EQEmu::item::ItemEffectEquipClick) || (item->Click.Type == EQEmu::item::ItemEffectClick2)) { if (inst->GetCharges() == 0) { @@ -8479,7 +8580,9 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) } if (i == 0) { - CastSpell(item->Click.Effect, target_id, USE_ITEM_SPELL_SLOT, item->CastTime, 0, 0, slot_id); + if (!IsCastWhileInvis(item->Click.Effect)) + CommonBreakInvisible(); // client can't do this for us :( + CastSpell(item->Click.Effect, target_id, CastingSlot::Item, item->CastTime, 0, 0, slot_id); } } else @@ -8506,7 +8609,9 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) } if (i == 0) { - CastSpell(augitem->Click.Effect, target_id, USE_ITEM_SPELL_SLOT, augitem->CastTime, 0, 0, slot_id); + if (!IsCastWhileInvis(augitem->Click.Effect)) + CommonBreakInvisible(); // client can't do this for us :( + CastSpell(augitem->Click.Effect, target_id, CastingSlot::Item, augitem->CastTime, 0, 0, slot_id); } } else @@ -8517,24 +8622,24 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) } else { - if (GetClientVersion() >= ClientVersion::SoD && !inst->IsEquipable(GetBaseRace(), GetClass())) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD && !inst->IsEquipable(GetBaseRace(), GetClass())) { - if (item->ItemType != ItemTypeFood && item->ItemType != ItemTypeDrink && item->ItemType != ItemTypeAlcohol) + if (item->ItemType != EQEmu::item::ItemTypeFood && item->ItemType != EQEmu::item::ItemTypeDrink && item->ItemType != EQEmu::item::ItemTypeAlcohol) { Log.Out(Logs::General, Logs::None, "Error: unknown item->Click.Type (%i)", item->Click.Type); } else { //This is food/drink - consume it - if (item->ItemType == ItemTypeFood && m_pp.hunger_level < 5000) + if (item->ItemType == EQEmu::item::ItemTypeFood && m_pp.hunger_level < 5000) { Consume(item, item->ItemType, slot_id, false); } - else if (item->ItemType == ItemTypeDrink && m_pp.thirst_level < 5000) + else if (item->ItemType == EQEmu::item::ItemTypeDrink && m_pp.thirst_level < 5000) { Consume(item, item->ItemType, slot_id, false); } - else if (item->ItemType == ItemTypeAlcohol) + else if (item->ItemType == EQEmu::item::ItemTypeAlcohol) { #if EQDEBUG >= 1 Log.Out(Logs::General, Logs::None, "Drinking Alcohol from slot:%i", slot_id); @@ -8612,7 +8717,9 @@ void Client::Handle_OP_LDoNButton(const EQApplicationPacket *app) bool* p = (bool*)app->pBuffer; if (*p == true) { - ServerPacket *pack = new ServerPacket(ServerOP_AdventureRequestCreate, sizeof(ServerAdventureRequestCreate_Struct)+(64 * adv_requested_member_count)); + auto pack = + new ServerPacket(ServerOP_AdventureRequestCreate, + sizeof(ServerAdventureRequestCreate_Struct) + (64 * adv_requested_member_count)); ServerAdventureRequestCreate_Struct *sac = (ServerAdventureRequestCreate_Struct*)pack->pBuffer; strcpy(sac->leader, GetName()); sac->id = adv_requested_id; @@ -8636,14 +8743,14 @@ void Client::Handle_OP_LDoNDisarmTraps(const EQApplicationPacket *app) Mob * target = GetTarget(); if (target->IsNPC()) { - if (HasSkill(SkillDisarmTraps)) + if (HasSkill(EQEmu::skills::SkillDisarmTraps)) { if (DistanceSquaredNoZ(m_Position, target->GetPosition()) > RuleI(Adventure, LDoNTrapDistanceUse)) { Message(13, "%s is too far away.", target->GetCleanName()); return; } - HandleLDoNDisarm(target->CastToNPC(), GetSkill(SkillDisarmTraps), LDoNTypeMechanical); + HandleLDoNDisarm(target->CastToNPC(), GetSkill(EQEmu::skills::SkillDisarmTraps), LDoNTypeMechanical); } else Message(13, "You do not have the disarm trap skill."); @@ -8669,14 +8776,14 @@ void Client::Handle_OP_LDoNPickLock(const EQApplicationPacket *app) Mob * target = GetTarget(); if (target->IsNPC()) { - if (HasSkill(SkillPickLock)) + if (HasSkill(EQEmu::skills::SkillPickLock)) { if (DistanceSquaredNoZ(m_Position, target->GetPosition()) > RuleI(Adventure, LDoNTrapDistanceUse)) { Message(13, "%s is too far away.", target->GetCleanName()); return; } - HandleLDoNPickLock(target->CastToNPC(), GetSkill(SkillPickLock), LDoNTypeMechanical); + HandleLDoNPickLock(target->CastToNPC(), GetSkill(EQEmu::skills::SkillPickLock), LDoNTypeMechanical); } else Message(13, "You do not have the pick locks skill."); @@ -8688,14 +8795,14 @@ void Client::Handle_OP_LDoNSenseTraps(const EQApplicationPacket *app) Mob * target = GetTarget(); if (target->IsNPC()) { - if (HasSkill(SkillSenseTraps)) + if (HasSkill(EQEmu::skills::SkillSenseTraps)) { if (DistanceSquaredNoZ(m_Position, target->GetPosition()) > RuleI(Adventure, LDoNTrapDistanceUse)) { Message(13, "%s is too far away.", target->GetCleanName()); return; } - HandleLDoNSenseTraps(target->CastToNPC(), GetSkill(SkillSenseTraps), LDoNTypeMechanical); + HandleLDoNSenseTraps(target->CastToNPC(), GetSkill(EQEmu::skills::SkillSenseTraps), LDoNTypeMechanical); } else Message(13, "You do not have the sense traps skill."); @@ -8778,7 +8885,7 @@ void Client::Handle_OP_LFGCommand(const EQApplicationPacket *app) UpdateWho(); // Issue outgoing packet to notify other clients - EQApplicationPacket* outapp = new EQApplicationPacket(OP_LFGAppearance, sizeof(LFG_Appearance_Struct)); + auto outapp = new EQApplicationPacket(OP_LFGAppearance, sizeof(LFG_Appearance_Struct)); LFG_Appearance_Struct* lfga = (LFG_Appearance_Struct*)outapp->pBuffer; lfga->spawn_id = this->GetID(); lfga->lfg = (uint8)LFG; @@ -8801,7 +8908,7 @@ void Client::Handle_OP_LFGGetMatchesRequest(const EQApplicationPacket *app) if (!worldserver.Connected()) Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_LFGMatches, sizeof(ServerLFGMatchesRequest_Struct)); + auto pack = new ServerPacket(ServerOP_LFGMatches, sizeof(ServerLFGMatchesRequest_Struct)); ServerLFGMatchesRequest_Struct* smrs = (ServerLFGMatchesRequest_Struct*)pack->pBuffer; smrs->FromID = GetID(); smrs->QuerierLevel = GetLevel(); @@ -8839,7 +8946,7 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app) #endif // DARWIN return; - ServerPacket* pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + strlen(pts->Comment) + 38); + auto pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + strlen(pts->Comment) + 38); pack->WriteUInt32(zone->GetZoneID()); pack->WriteUInt32(zone->GetInstanceID()); @@ -8848,7 +8955,7 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app) pack->WriteUInt32(QSG_LFGuild_UpdatePlayerInfo); pack->WriteUInt32(GetBaseClass()); pack->WriteUInt32(GetLevel()); - pack->WriteUInt32(GetAAPointsSpent()); + pack->WriteUInt32(GetSpentAA()); pack->WriteString(pts->Comment); pack->WriteUInt32(pts->Toggle); pack->WriteUInt32(pts->TimeZone); @@ -8874,7 +8981,9 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app) #endif // __DARWIN return; - ServerPacket* pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + strlen(gts->Comment) + strlen(guild_mgr.GetGuildName(GuildID())) + 43); + auto pack = + new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + strlen(gts->Comment) + + strlen(guild_mgr.GetGuildName(GuildID())) + 43); pack->WriteUInt32(zone->GetZoneID()); pack->WriteUInt32(zone->GetInstanceID()); @@ -8899,7 +9008,7 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app) { VERIFY_PACKET_LENGTH(OP_LFGuild, app, LFGuild_SearchPlayer_Struct); - ServerPacket* pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + 37); + auto pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + 37); pack->WriteUInt32(zone->GetZoneID()); pack->WriteUInt32(zone->GetInstanceID()); @@ -8923,7 +9032,7 @@ void Client::Handle_OP_LFGuild(const EQApplicationPacket *app) { VERIFY_PACKET_LENGTH(OP_LFGuild, app, LFGuild_SearchGuild_Struct); - ServerPacket* pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + 33); + auto pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + 33); pack->WriteUInt32(zone->GetZoneID()); pack->WriteUInt32(zone->GetInstanceID()); @@ -9023,7 +9132,7 @@ void Client::Handle_OP_LFPGetMatchesRequest(const EQApplicationPacket *app) if (!worldserver.Connected()) Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_LFPMatches, sizeof(ServerLFPMatchesRequest_Struct)); + auto pack = new ServerPacket(ServerOP_LFPMatches, sizeof(ServerLFPMatchesRequest_Struct)); ServerLFPMatchesRequest_Struct* smrs = (ServerLFPMatchesRequest_Struct*)pack->pBuffer; smrs->FromID = GetID(); smrs->FromLevel = gmrs->FromLevel; @@ -9058,7 +9167,7 @@ void Client::Handle_OP_Logout(const EQApplicationPacket *app) SendLogoutPackets(); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LogoutReply); + auto outapp = new EQApplicationPacket(OP_LogoutReply); FastQueuePacket(&outapp); Disconnect(); @@ -9110,39 +9219,7 @@ void Client::Handle_OP_LootRequest(const EQApplicationPacket *app) if (ent->IsCorpse()) { SetLooting(ent->GetID()); //store the entity we are looting - Corpse *ent_corpse = ent->CastToCorpse(); - if (DistanceSquaredNoZ(m_Position, ent_corpse->GetPosition()) > 625) - { - Message(13, "Corpse too far away."); - Corpse::SendLootReqErrorPacket(this); - return; - } - if (invisible) { - BuffFadeByEffect(SE_Invisibility); - BuffFadeByEffect(SE_Invisibility2); - invisible = false; - } - if (invisible_undead) { - BuffFadeByEffect(SE_InvisVsUndead); - BuffFadeByEffect(SE_InvisVsUndead2); - invisible_undead = false; - } - if (invisible_animals){ - BuffFadeByEffect(SE_InvisVsAnimals); - invisible_animals = false; - } - if (hidden || improved_hidden){ - hidden = false; - improved_hidden = false; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); - SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer; - sa_out->spawn_id = GetID(); - sa_out->type = 0x03; - sa_out->parameter = 0; - entity_list.QueueClients(this, outapp, true); - safe_delete(outapp); - } ent->CastToCorpse()->MakeLootRequestPackets(this, app); return; } @@ -9196,7 +9273,7 @@ void Client::Handle_OP_MemorizeSpell(const EQApplicationPacket *app) void Client::Handle_OP_Mend(const EQApplicationPacket *app) { - if (!HasSkill(SkillMend)) + if (!HasSkill(EQEmu::skills::SkillMend)) return; if (!p_timers.Expired(&database, pTimerMend, false)) { @@ -9207,7 +9284,7 @@ void Client::Handle_OP_Mend(const EQApplicationPacket *app) int mendhp = GetMaxHP() / 4; int currenthp = GetHP(); - if (zone->random.Int(0, 199) < (int)GetSkill(SkillMend)) { + if (zone->random.Int(0, 199) < (int)GetSkill(EQEmu::skills::SkillMend)) { int criticalchance = spellbonuses.CriticalMend + itembonuses.CriticalMend + aabonuses.CriticalMend; @@ -9226,7 +9303,7 @@ void Client::Handle_OP_Mend(const EQApplicationPacket *app) 0 skill - 25% chance to worsen 20 skill - 23% chance to worsen 50 skill - 16% chance to worsen */ - if ((GetSkill(SkillMend) <= 75) && (zone->random.Int(GetSkill(SkillMend), 100) < 75) && (zone->random.Int(1, 3) == 1)) + if ((GetSkill(EQEmu::skills::SkillMend) <= 75) && (zone->random.Int(GetSkill(EQEmu::skills::SkillMend), 100) < 75) && (zone->random.Int(1, 3) == 1)) { SetHP(currenthp > mendhp ? (GetHP() - mendhp) : 1); SendHPUpdate(); @@ -9236,7 +9313,7 @@ void Client::Handle_OP_Mend(const EQApplicationPacket *app) Message_StringID(4, MEND_FAIL); } - CheckIncreaseSkill(SkillMend, nullptr, 10); + CheckIncreaseSkill(EQEmu::skills::SkillMend, nullptr, 10); return; } @@ -9273,7 +9350,7 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app) //get number of available stances for the current merc std::list mercStanceList = zone->merc_stance_list[merc->GetMercTemplateID()]; - std::list::iterator iter = mercStanceList.begin(); + auto iter = mercStanceList.begin(); while (iter != mercStanceList.end()) { numStances++; ++iter; @@ -9345,34 +9422,34 @@ void Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app) return; } - mercTypeCount = tar->GetNumMercTypes(static_cast(GetClientVersion())); - mercCount = tar->GetNumMercs(static_cast(GetClientVersion())); + mercTypeCount = tar->GetNumMercTypes(static_cast(ClientVersion())); + mercCount = tar->GetNumMercs(static_cast(ClientVersion())); if (mercCount > MAX_MERC) return; - std::list mercTypeList = tar->GetMercTypesList(static_cast(GetClientVersion())); - std::list mercDataList = tar->GetMercsList(static_cast(GetClientVersion())); + std::list mercTypeList = tar->GetMercTypesList(static_cast(ClientVersion())); + std::list mercDataList = tar->GetMercsList(static_cast(ClientVersion())); int i = 0; int StanceCount = 0; - for (std::list::iterator mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) - { - std::list::iterator siter = zone->merc_stance_list[mercListItr->MercTemplateID].begin(); + for (auto mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) { + auto siter = zone->merc_stance_list[mercListItr->MercTemplateID].begin(); for (siter = zone->merc_stance_list[mercListItr->MercTemplateID].begin(); siter != zone->merc_stance_list[mercListItr->MercTemplateID].end(); ++siter) { StanceCount++; } } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, sizeof(MercenaryMerchantList_Struct)); + auto outapp = new EQApplicationPacket(OP_MercenaryDataResponse, sizeof(MercenaryMerchantList_Struct)); MercenaryMerchantList_Struct* mml = (MercenaryMerchantList_Struct*)outapp->pBuffer; mml->MercTypeCount = mercTypeCount; if (mercTypeCount > 0) { - for (std::list::iterator mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); ++mercTypeListItr) { + for (auto mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); + ++mercTypeListItr) { mml->MercGrades[i] = mercTypeListItr->Type; // DBStringID for Type i++; } @@ -9382,8 +9459,8 @@ void Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app) if (mercCount > 0) { i = 0; - for (std::list::iterator mercListIter = mercDataList.begin(); mercListIter != mercDataList.end(); ++mercListIter) - { + for (auto mercListIter = mercDataList.begin(); mercListIter != mercDataList.end(); + ++mercListIter) { mml->Mercs[i].MercID = mercListIter->MercTemplateID; mml->Mercs[i].MercType = mercListIter->MercType; mml->Mercs[i].MercSubType = mercListIter->MercSubType; @@ -9398,7 +9475,7 @@ void Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app) mml->Mercs[i].MerchantSlot = i + 1; mml->Mercs[i].MercUnk02 = 1; int mercStanceCount = 0; - std::list::iterator iter = zone->merc_stance_list[mercListIter->MercTemplateID].begin(); + auto iter = zone->merc_stance_list[mercListIter->MercTemplateID].begin(); for (iter = zone->merc_stance_list[mercListIter->MercTemplateID].begin(); iter != zone->merc_stance_list[mercListIter->MercTemplateID].end(); ++iter) { mercStanceCount++; @@ -9410,7 +9487,7 @@ void Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app) int stanceindex = 0; if (mercStanceCount > 0) { - std::list::iterator iter2 = zone->merc_stance_list[mercListIter->MercTemplateID].begin(); + auto iter2 = zone->merc_stance_list[mercListIter->MercTemplateID].begin(); while (iter2 != zone->merc_stance_list[mercListIter->MercTemplateID].end()) { mml->Mercs[i].Stances[stanceindex].StanceIndex = stanceindex; @@ -9629,7 +9706,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app) MoveItem_Struct* mi = (MoveItem_Struct*)app->pBuffer; if (spellend_timer.Enabled() && casting_spell_id && !IsBardSong(casting_spell_id)) { - if (mi->from_slot != mi->to_slot && (mi->from_slot <= EmuConstants::GENERAL_END || mi->from_slot > 39) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) + if (mi->from_slot != mi->to_slot && (mi->from_slot <= EQEmu::legacy::GENERAL_END || mi->from_slot > 39) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) { char *detect = nullptr; const ItemInst *itm_from = GetInv().GetItem(mi->from_slot); @@ -9650,22 +9727,22 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app) // Illegal bagslot usage checks. Currently, user only receives a message if this check is triggered. bool mi_hack = false; - if (mi->from_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->from_slot <= EmuConstants::CURSOR_BAG_END) { - if (mi->from_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; } + if (mi->from_slot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && mi->from_slot <= EQEmu::legacy::CURSOR_BAG_END) { + if (mi->from_slot >= EQEmu::legacy::CURSOR_BAG_BEGIN) { mi_hack = true; } else { int16 from_parent = m_inv.CalcSlotId(mi->from_slot); if (!m_inv[from_parent]) { mi_hack = true; } - else if (!m_inv[from_parent]->IsType(ItemClassContainer)) { mi_hack = true; } + else if (!m_inv[from_parent]->IsClassBag()) { mi_hack = true; } else if (m_inv.CalcBagIdx(mi->from_slot) >= m_inv[from_parent]->GetItem()->BagSlots) { mi_hack = true; } } } - if (mi->to_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->to_slot <= EmuConstants::CURSOR_BAG_END) { - if (mi->to_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; } + if (mi->to_slot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && mi->to_slot <= EQEmu::legacy::CURSOR_BAG_END) { + if (mi->to_slot >= EQEmu::legacy::CURSOR_BAG_BEGIN) { mi_hack = true; } else { int16 to_parent = m_inv.CalcSlotId(mi->to_slot); if (!m_inv[to_parent]) { mi_hack = true; } - else if (!m_inv[to_parent]->IsType(ItemClassContainer)) { mi_hack = true; } + else if (!m_inv[to_parent]->IsClassBag()) { mi_hack = true; } else if (m_inv.CalcBagIdx(mi->to_slot) >= m_inv[to_parent]->GetItem()->BagSlots) { mi_hack = true; } } } @@ -9781,6 +9858,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) char val1[20] = { 0 }; PetCommand_Struct* pet = (PetCommand_Struct*)app->pBuffer; Mob* mypet = this->GetPet(); + Mob *target = entity_list.GetMob(pet->target); if (!mypet || pet->command == PET_LEADER) { @@ -9828,22 +9906,22 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) switch (PetCommand) { case PET_ATTACK: { - if (!GetTarget()) + if (!target) break; - if (GetTarget()->IsMezzed()) { - Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), GetTarget()->GetCleanName()); + if (target->IsMezzed()) { + Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), target->GetCleanName()); break; } if (mypet->IsFeared()) break; //prevent pet from attacking stuff while feared - if (!mypet->IsAttackAllowed(GetTarget())) { + if (!mypet->IsAttackAllowed(target)) { mypet->Say_StringID(NOT_LEGAL_TARGET); break; } if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) { - if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { + if (target != this && DistanceSquaredNoZ(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { if (mypet->IsHeld()) { if (!mypet->IsFocused()) { mypet->SetHeld(false); //break the hold and guard if we explicitly tell the pet to attack. @@ -9851,12 +9929,12 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) mypet->SetPetOrder(SPO_Follow); } else { - mypet->SetTarget(GetTarget()); + mypet->SetTarget(target); } } zone->AddAggroMob(); - mypet->AddToHateList(GetTarget(), 1); - Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName()); + mypet->AddToHateList(target, 1); + Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), target->GetCleanName()); } } break; @@ -9871,7 +9949,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) Message_StringID(10, CANNOT_WAKE, mypet->GetCleanName(), GetTarget()->GetCleanName()); break; } - + if (!mypet->IsAttackAllowed(GetTarget())) { mypet->Say_StringID(NOT_LEGAL_TARGET); break; @@ -9967,7 +10045,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) } } break; - } + } case PET_TAUNT_ON: { if ((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) { Message_StringID(MT_PetResponse, PET_DO_TAUNT); @@ -10208,7 +10286,7 @@ void Client::Handle_OP_Petition(const EQApplicationPacket *app) Message(0, "You already have a petition in the queue, you must wait for it to be answered or use /deletepetition to delete it."); return; } - Petition* pet = new Petition(CharacterID()); + auto pet = new Petition(CharacterID()); pet->SetAName(this->AccountName()); pet->SetClass(this->GetClass()); pet->SetLevel(this->GetLevel()); @@ -10288,7 +10366,7 @@ void Client::Handle_OP_PetitionDelete(const EQApplicationPacket *app) Log.Out(Logs::General, Logs::Error, "Wrong size: OP_PetitionDelete, size=%i, expected %i", app->size, sizeof(PetitionUpdate_Struct)); return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_PetitionUpdate, sizeof(PetitionUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_PetitionUpdate, sizeof(PetitionUpdate_Struct)); PetitionUpdate_Struct* pet = (PetitionUpdate_Struct*)outapp->pBuffer; pet->petnumber = *((int*)app->pBuffer); pet->color = 0x00; @@ -10351,6 +10429,31 @@ void Client::Handle_OP_PetitionUnCheckout(const EQApplicationPacket *app) return; } +void Client::Handle_OP_PlayerStateAdd(const EQApplicationPacket *app) +{ + if (app->size != sizeof(PlayerState_Struct)) { + std::cout << "Wrong size: OP_PlayerStateAdd, size=" << app->size << ", expected " << sizeof(PlayerState_Struct) << std::endl; + return; + } + + PlayerState_Struct *ps = (PlayerState_Struct *)app->pBuffer; + AddPlayerState(ps->state); + + entity_list.QueueClients(this, app, true); +} + +void Client::Handle_OP_PlayerStateRemove(const EQApplicationPacket *app) +{ + if (app->size != sizeof(PlayerState_Struct)) { + std::cout << "Wrong size: OP_PlayerStateRemove, size=" << app->size << ", expected " << sizeof(PlayerState_Struct) << std::endl; + return; + } + PlayerState_Struct *ps = (PlayerState_Struct *)app->pBuffer; + RemovePlayerState(ps->state); + + entity_list.QueueClients(this, app, true); +} + void Client::Handle_OP_PickPocket(const EQApplicationPacket *app) { if (app->size != sizeof(PickPocket_Struct)) @@ -10359,7 +10462,7 @@ void Client::Handle_OP_PickPocket(const EQApplicationPacket *app) DumpPacket(app); } - if (!HasSkill(SkillPickPockets)) + if (!HasSkill(EQEmu::skills::SkillPickPockets)) { return; } @@ -10379,12 +10482,12 @@ void Client::Handle_OP_PickPocket(const EQApplicationPacket *app) p_timers.Start(pTimerBeggingPickPocket, 8); if (victim == this){ Message(0, "You catch yourself red-handed."); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_PickPocket, sizeof(sPickPocket_Struct)); + auto outapp = new EQApplicationPacket(OP_PickPocket, sizeof(sPickPocket_Struct)); sPickPocket_Struct* pick_out = (sPickPocket_Struct*)outapp->pBuffer; pick_out->coin = 0; pick_out->from = victim->GetID(); pick_out->to = GetID(); - pick_out->myskill = GetSkill(SkillPickPockets); + pick_out->myskill = GetSkill(EQEmu::skills::SkillPickPockets); pick_out->type = 0; //if we do not send this packet the client will lock up and require the player to relog. QueuePacket(outapp); @@ -10392,12 +10495,12 @@ void Client::Handle_OP_PickPocket(const EQApplicationPacket *app) } else if (victim->GetOwnerID()){ Message(0, "You cannot steal from pets!"); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_PickPocket, sizeof(sPickPocket_Struct)); + auto outapp = new EQApplicationPacket(OP_PickPocket, sizeof(sPickPocket_Struct)); sPickPocket_Struct* pick_out = (sPickPocket_Struct*)outapp->pBuffer; pick_out->coin = 0; pick_out->from = victim->GetID(); pick_out->to = GetID(); - pick_out->myskill = GetSkill(SkillPickPockets); + pick_out->myskill = GetSkill(EQEmu::skills::SkillPickPockets); pick_out->type = 0; //if we do not send this packet the client will lock up and require the player to relog. QueuePacket(outapp); @@ -10408,12 +10511,12 @@ void Client::Handle_OP_PickPocket(const EQApplicationPacket *app) } else{ Message(0, "Stealing from clients not yet supported."); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_PickPocket, sizeof(sPickPocket_Struct)); + auto outapp = new EQApplicationPacket(OP_PickPocket, sizeof(sPickPocket_Struct)); sPickPocket_Struct* pick_out = (sPickPocket_Struct*)outapp->pBuffer; pick_out->coin = 0; pick_out->from = victim->GetID(); pick_out->to = GetID(); - pick_out->myskill = GetSkill(SkillPickPockets); + pick_out->myskill = GetSkill(EQEmu::skills::SkillPickPockets); pick_out->type = 0; //if we do not send this packet the client will lock up and require the player to relog. QueuePacket(outapp); @@ -10473,7 +10576,7 @@ void Client::Handle_OP_PotionBelt(const EQApplicationPacket *app) } if (mptbs->Action == 0) { - const Item_Struct *BaseItem = database.GetItem(mptbs->ItemID); + const EQEmu::ItemBase *BaseItem = database.GetItem(mptbs->ItemID); if (BaseItem) { m_pp.potionbelt.Items[mptbs->SlotNumber].ID = BaseItem->ID; m_pp.potionbelt.Items[mptbs->SlotNumber].Icon = BaseItem->Icon; @@ -10541,7 +10644,7 @@ void Client::Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app) } //success, send them an update - EQApplicationPacket *outapp = new EQApplicationPacket(OP_UpdateLeadershipAA, sizeof(UpdateLeadershipAA_Struct)); + auto outapp = new EQApplicationPacket(OP_UpdateLeadershipAA, sizeof(UpdateLeadershipAA_Struct)); UpdateLeadershipAA_Struct *u = (UpdateLeadershipAA_Struct *)outapp->pBuffer; u->ability_id = aaid; u->new_rank = m_pp.leader_abilities.ranks[aaid]; @@ -10589,7 +10692,7 @@ void Client::Handle_OP_PVPLeaderBoardDetailsRequest(const EQApplicationPacket *a return; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_PVPLeaderBoardDetailsReply, sizeof(PVPLeaderBoardDetailsReply_Struct)); + auto outapp = new EQApplicationPacket(OP_PVPLeaderBoardDetailsReply, sizeof(PVPLeaderBoardDetailsReply_Struct)); PVPLeaderBoardDetailsReply_Struct *pvplbdrs = (PVPLeaderBoardDetailsReply_Struct *)outapp->pBuffer; // TODO: Record and send this data. @@ -10617,7 +10720,7 @@ void Client::Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app) } /*PVPLeaderBoardRequest_Struct *pvplbrs = (PVPLeaderBoardRequest_Struct *)app->pBuffer;*/ //unused - EQApplicationPacket *outapp = new EQApplicationPacket(OP_PVPLeaderBoardReply, sizeof(PVPLeaderBoard_Struct)); + auto outapp = new EQApplicationPacket(OP_PVPLeaderBoardReply, sizeof(PVPLeaderBoard_Struct)); /*PVPLeaderBoard_Struct *pvplb = (PVPLeaderBoard_Struct *)outapp->pBuffer;*/ //unused // TODO: Record and send this data. @@ -10653,7 +10756,7 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) break; } //This sends an "invite" to the client in question. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; strn0cpy(rg->leader_name, ri->leader_name, 64); strn0cpy(rg->player_name, ri->player_name, 64); @@ -10959,7 +11062,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) if (c) r->SendGroupDisband(c); else{ - ServerPacket *pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = + new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); rga->zoneid = zone->GetZoneID(); @@ -11014,7 +11118,10 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } } else{ - ServerPacket *pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket( + ServerOP_RaidChangeGroup, + sizeof( + ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = r->GetID(); strn0cpy(rga->playername, r->members[x].membername, 64); @@ -11039,7 +11146,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) r->SendGroupDisband(c); } else{ - ServerPacket *pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidGroupDisband, + sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = r->GetID(); rga->zoneid = zone->GetZoneID(); @@ -11083,7 +11191,9 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) } } else{ - ServerPacket *pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket( + ServerOP_RaidChangeGroup, + sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = r->GetID(); strn0cpy(rga->playername, r->members[x].membername, 64); @@ -11101,7 +11211,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) r->SendGroupDisband(c); } else{ - ServerPacket *pack = new ServerPacket(ServerOP_RaidGroupDisband, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidGroupDisband, + sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = r->GetID(); rga->zoneid = zone->GetZoneID(); @@ -11229,7 +11340,7 @@ void Client::Handle_OP_RandomReq(const EQApplicationPacket *app) } randResult = zone->random.Int(randLow, randHigh); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RandomReply, sizeof(RandomReply_Struct)); + auto outapp = new EQApplicationPacket(OP_RandomReply, sizeof(RandomReply_Struct)); RandomReply_Struct* rr = (RandomReply_Struct*)outapp->pBuffer; rr->low = randLow; rr->high = randHigh; @@ -11248,7 +11359,7 @@ void Client::Handle_OP_ReadBook(const EQApplicationPacket *app) } BookRequest_Struct* book = (BookRequest_Struct*)app->pBuffer; ReadBook(book); - if (GetClientVersion() >= ClientVersion::SoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { EQApplicationPacket EndOfBook(OP_FinishWindow, 0); QueuePacket(&EndOfBook); @@ -11432,7 +11543,7 @@ void Client::Handle_OP_RemoveBlockedBuffs(const EQApplicationPacket *app) { std::set::iterator Iterator; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RemoveBlockedBuffs, sizeof(BlockedBuffs_Struct)); + auto outapp = new EQApplicationPacket(OP_RemoveBlockedBuffs, sizeof(BlockedBuffs_Struct)); BlockedBuffs_Struct *obbs = (BlockedBuffs_Struct*)outapp->pBuffer; @@ -11650,8 +11761,8 @@ void Client::Handle_OP_Sacrifice(const EQApplicationPacket *app) void Client::Handle_OP_SafeFallSuccess(const EQApplicationPacket *app) // bit of a misnomer, sent whenever safe fall is used (success of fail) { - if (HasSkill(SkillSafeFall)) //this should only get called if the client has safe fall, but just in case... - CheckIncreaseSkill(SkillSafeFall, nullptr); //check for skill up + if (HasSkill(EQEmu::skills::SkillSafeFall)) //this should only get called if the client has safe fall, but just in case... + CheckIncreaseSkill(EQEmu::skills::SkillSafeFall, nullptr); //check for skill up } void Client::Handle_OP_SafePoint(const EQApplicationPacket *app) @@ -11688,7 +11799,7 @@ void Client::Handle_OP_SelectTribute(const EQApplicationPacket *app) void Client::Handle_OP_SenseHeading(const EQApplicationPacket *app) { - if (!HasSkill(SkillSenseHeading)) + if (!HasSkill(EQEmu::skills::SkillSenseHeading)) return; int chancemod=0; @@ -11701,41 +11812,35 @@ void Client::Handle_OP_SenseHeading(const EQApplicationPacket *app) // eventually sends a message. if (GetLevel() <= 8) chancemod += (9-level) * 10; - - CheckIncreaseSkill(SkillSenseHeading, nullptr, chancemod); + + CheckIncreaseSkill(EQEmu::skills::SkillSenseHeading, nullptr, chancemod); return; } void Client::Handle_OP_SenseTraps(const EQApplicationPacket *app) { - if (!HasSkill(SkillSenseTraps)) + if (!HasSkill(EQEmu::skills::SkillSenseTraps)) return; if (!p_timers.Expired(&database, pTimerSenseTraps, false)) { Message(13, "Ability recovery time not yet met."); return; } - int reuse = SenseTrapsReuseTime; - switch (GetAA(aaAdvTrapNegotiation)) { - case 1: - reuse -= 1; - break; - case 2: - reuse -= 3; - break; - case 3: - reuse -= 5; - break; - } + + int reuse = SenseTrapsReuseTime - GetSkillReuseTime(EQEmu::skills::SkillSenseTraps); + + if (reuse < 1) + reuse = 1; + p_timers.Start(pTimerSenseTraps, reuse - 1); Trap* trap = entity_list.FindNearbyTrap(this, 800); - CheckIncreaseSkill(SkillSenseTraps, nullptr); + CheckIncreaseSkill(EQEmu::skills::SkillSenseTraps, nullptr); if (trap && trap->skill > 0) { - int uskill = GetSkill(SkillSenseTraps); + int uskill = GetSkill(EQEmu::skills::SkillSenseTraps); if ((zone->random.Int(0, 99) + uskill) >= (zone->random.Int(0, 99) + trap->skill*0.75)) { auto diff = trap->m_Position - glm::vec3(GetPosition()); @@ -11806,6 +11911,18 @@ void Client::Handle_OP_SetGuildMOTD(const EQApplicationPacket *app) void Client::Handle_OP_SetRunMode(const EQApplicationPacket *app) { + if (app->size < sizeof(SetRunMode_Struct)) { + Log.Out(Logs::General, Logs::Error, "Received invalid sized " + "OP_SetRunMode: got %d, expected %d", app->size, + sizeof(SetRunMode_Struct)); + DumpPacket(app); + return; + } + SetRunMode_Struct* rms = (SetRunMode_Struct*)app->pBuffer; + if (rms->mode) + runmode = true; + else + runmode = false; return; } @@ -11879,7 +11996,7 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app) if (!results.Success()) return; - Message(15, "Use \"/startcity #\" to choose a home city from the following list:"); + Message(15, "Use \"/setstartcity #\" to choose a home city from the following list:"); for (auto row = results.begin(); row != results.end(); ++row) { if (atoi(row[1]) != 0) @@ -11945,13 +12062,13 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app) Shielding_Struct* shield = (Shielding_Struct*)app->pBuffer; shield_target = entity_list.GetMob(shield->target_id); bool ack = false; - ItemInst* inst = GetInv().GetItem(MainSecondary); + ItemInst* inst = GetInv().GetItem(EQEmu::legacy::SlotSecondary); if (!shield_target) return; if (inst) { - const Item_Struct* shield = inst->GetItem(); - if (shield && shield->ItemType == ItemTypeShield) + const EQEmu::ItemBase* shield = inst->GetItem(); + if (shield && shield->ItemType == EQEmu::item::ItemTypeShield) { for (int x = 0; x < 2; x++) { @@ -12058,7 +12175,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) break; } } - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; uint32 prevcharges = 0; if (item_id == 0) { //check to see if its on the temporary table std::list tmp_merlist = zone->tmpmerchanttable[tmp->GetNPCTypeID()]; @@ -12078,7 +12195,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) if (!item){ //error finding item, client didnt get the update packet for whatever reason, roleplay a tad Message(15, "%s tells you 'Sorry, that item is for display purposes only.' as they take the item off the shelf.", tmp->GetCleanName()); - EQApplicationPacket* delitempacket = new EQApplicationPacket(OP_ShopDelItem, sizeof(Merchant_DelItem_Struct)); + auto delitempacket = new EQApplicationPacket(OP_ShopDelItem, sizeof(Merchant_DelItem_Struct)); Merchant_DelItem_Struct* delitem = (Merchant_DelItem_Struct*)delitempacket->pBuffer; delitem->itemslot = mp->itemslot; delitem->npcid = mp->npcid; @@ -12105,7 +12222,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) if (item->Stackable && mp->quantity > item->StackSize) mp->quantity = item->StackSize; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerBuy, sizeof(Merchant_Sell_Struct)); + auto outapp = new EQApplicationPacket(OP_ShopPlayerBuy, sizeof(Merchant_Sell_Struct)); Merchant_Sell_Struct* mpo = (Merchant_Sell_Struct*)outapp->pBuffer; mpo->quantity = mp->quantity; mpo->playerid = mp->playerid; @@ -12162,8 +12279,8 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) // shouldn't we be reimbursing if these two fail? //make sure we are not completely full... - if (freeslotid == MainCursor) { - if (m_inv.GetItem(MainCursor) != nullptr) { + if (freeslotid == EQEmu::legacy::SlotCursor) { + if (m_inv.GetItem(EQEmu::legacy::SlotCursor) != nullptr) { Message(13, "You do not have room for any more items."); safe_delete(outapp); safe_delete(inst); @@ -12192,7 +12309,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) int32 new_charges = prevcharges - mp->quantity; zone->SaveTempItem(merchantid, tmp->GetNPCTypeID(), item_id, new_charges); if (new_charges <= 0){ - EQApplicationPacket* delitempacket = new EQApplicationPacket(OP_ShopDelItem, sizeof(Merchant_DelItem_Struct)); + auto delitempacket = new EQApplicationPacket(OP_ShopDelItem, sizeof(Merchant_DelItem_Struct)); Merchant_DelItem_Struct* delitem = (Merchant_DelItem_Struct*)delitempacket->pBuffer; delitem->itemslot = mp->itemslot; delitem->npcid = mp->npcid; @@ -12217,7 +12334,9 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) // start QS code // stacking purchases not supported at this time - entire process will need some work to catch them properly if (RuleB(QueryServ, PlayerLogMerchantTransactions)) { - ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogMerchantTransactions, sizeof(QSMerchantLogTransaction_Struct)+sizeof(QSTransactionItems_Struct)); + auto qspack = + new ServerPacket(ServerOP_QSPlayerLogMerchantTransactions, + sizeof(QSMerchantLogTransaction_Struct) + sizeof(QSTransactionItems_Struct)); QSMerchantLogTransaction_Struct* qsaudit = (QSMerchantLogTransaction_Struct*)qspack->pBuffer; qsaudit->zone_id = zone->GetZoneID(); @@ -12238,20 +12357,29 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) qsaudit->items[0].item_id = item->ID; qsaudit->items[0].charges = mpo->quantity; - if (freeslotid == INVALID_INDEX) { + const ItemInst* audit_inst = m_inv[freeslotid]; + + if (audit_inst) { + qsaudit->items[0].aug_1 = audit_inst->GetAugmentItemID(0); + qsaudit->items[0].aug_2 = audit_inst->GetAugmentItemID(1); + qsaudit->items[0].aug_3 = audit_inst->GetAugmentItemID(2); + qsaudit->items[0].aug_4 = audit_inst->GetAugmentItemID(3); + qsaudit->items[0].aug_5 = audit_inst->GetAugmentItemID(4); + } + else { qsaudit->items[0].aug_1 = 0; qsaudit->items[0].aug_2 = 0; qsaudit->items[0].aug_3 = 0; qsaudit->items[0].aug_4 = 0; qsaudit->items[0].aug_5 = 0; + + if (freeslotid != INVALID_INDEX) { + Log.Out(Logs::General, Logs::Error, "Handle_OP_ShopPlayerBuy: QS Audit could not locate merchant (%u) purchased item in player (%u) inventory slot (%i)", + qsaudit->merchant_id, qsaudit->char_id, freeslotid); + } } - else { - qsaudit->items[0].aug_1 = m_inv[freeslotid]->GetAugmentItemID(0); - qsaudit->items[0].aug_2 = m_inv[freeslotid]->GetAugmentItemID(1); - qsaudit->items[0].aug_3 = m_inv[freeslotid]->GetAugmentItemID(2); - qsaudit->items[0].aug_4 = m_inv[freeslotid]->GetAugmentItemID(3); - qsaudit->items[0].aug_5 = m_inv[freeslotid]->GetAugmentItemID(4); - } + + audit_inst = nullptr; qspack->Deflate(); if (worldserver.Connected()) { worldserver.SendPacket(qspack); } @@ -12295,7 +12423,7 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app) uint32 itemid = GetItemIDAt(mp->itemslot); if (itemid == 0) return; - const Item_Struct* item = database.GetItem(itemid); + const EQEmu::ItemBase* item = database.GetItem(itemid); ItemInst* inst = GetInv().GetItem(mp->itemslot); if (!item || !inst){ Message(13, "You seemed to have misplaced that item.."); @@ -12342,7 +12470,7 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app) int freeslot = 0; if (charges > 0 && (freeslot = zone->SaveTempItem(vendor->CastToNPC()->MerchantType, vendor->GetNPCTypeID(), itemid, charges, true)) > 0){ ItemInst* inst2 = inst->Clone(); - + while (true) { if (inst2 == nullptr) break; @@ -12370,7 +12498,9 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app) // start QS code if (RuleB(QueryServ, PlayerLogMerchantTransactions)) { - ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogMerchantTransactions, sizeof(QSMerchantLogTransaction_Struct)+sizeof(QSTransactionItems_Struct)); + auto qspack = + new ServerPacket(ServerOP_QSPlayerLogMerchantTransactions, + sizeof(QSMerchantLogTransaction_Struct) + sizeof(QSTransactionItems_Struct)); QSMerchantLogTransaction_Struct* qsaudit = (QSMerchantLogTransaction_Struct*)qspack->pBuffer; qsaudit->zone_id = zone->GetZoneID(); @@ -12412,7 +12542,7 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app) if (inst->IsCharged()) mp->quantity = 1; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerSell, sizeof(Merchant_Purchase_Struct)); + auto outapp = new EQApplicationPacket(OP_ShopPlayerSell, sizeof(Merchant_Purchase_Struct)); Merchant_Purchase_Struct* mco = (Merchant_Purchase_Struct*)outapp->pBuffer; mco->npcid = vendor->GetID(); mco->itemslot = mp->itemslot; @@ -12454,7 +12584,7 @@ void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app) int action = 1; if (merchantid == 0) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(Merchant_Click_Struct)); + auto outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(Merchant_Click_Struct)); Merchant_Click_Struct* mco = (Merchant_Click_Struct*)outapp->pBuffer; mco->npcid = mc->npcid; mco->playerid = 0; @@ -12489,7 +12619,7 @@ void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app) action = 0; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(Merchant_Click_Struct)); + auto outapp = new EQApplicationPacket(OP_ShopRequest, sizeof(Merchant_Click_Struct)); Merchant_Click_Struct* mco = (Merchant_Click_Struct*)outapp->pBuffer; mco->npcid = mc->npcid; @@ -12513,7 +12643,7 @@ void Client::Handle_OP_ShopRequest(const EQApplicationPacket *app) void Client::Handle_OP_Sneak(const EQApplicationPacket *app) { - if (!HasSkill(SkillSneak) && GetSkill(SkillSneak) == 0) { + if (!HasSkill(EQEmu::skills::SkillSneak) && GetSkill(EQEmu::skills::SkillSneak) == 0) { return; //You cannot sneak if you do not have sneak } @@ -12528,7 +12658,7 @@ void Client::Handle_OP_Sneak(const EQApplicationPacket *app) sneaking = false; hidden = false; improved_hidden = false; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer; sa_out->spawn_id = GetID(); sa_out->type = 0x03; @@ -12537,14 +12667,14 @@ void Client::Handle_OP_Sneak(const EQApplicationPacket *app) safe_delete(outapp); } else { - CheckIncreaseSkill(SkillSneak, nullptr, 5); + CheckIncreaseSkill(EQEmu::skills::SkillSneak, nullptr, 5); } - float hidechance = ((GetSkill(SkillSneak) / 300.0f) + .25) * 100; + float hidechance = ((GetSkill(EQEmu::skills::SkillSneak) / 300.0f) + .25) * 100; float random = zone->random.Real(0, 99); if (!was && random < hidechance) { sneaking = true; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer; sa_out->spawn_id = GetID(); sa_out->type = 0x0F; @@ -12580,9 +12710,9 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) if (sa->type == AT_Invis) { if (sa->parameter != 0) { - if (!HasSkill(SkillHide) && GetSkill(SkillHide) == 0) + if (!HasSkill(EQEmu::skills::SkillHide) && GetSkill(EQEmu::skills::SkillHide) == 0) { - if (GetClientVersion() < ClientVersion::SoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::SoF) { char *hack_str = nullptr; MakeAnyLenString(&hack_str, "Player sent OP_SpawnAppearance with AT_Invis: %i", sa->parameter); @@ -12636,7 +12766,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) } else { - std::cerr << "Client " << name << " unknown apperance " << (int)sa->parameter << std::endl; + Log.Out(Logs::Detail, Logs::Error, "Client %s :: unknown appearance %i", name, (int)sa->parameter); return; } @@ -12658,7 +12788,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) m_pp.anon = 0; } else { - std::cerr << "Client " << name << " unknown Anon/Roleplay Switch " << (int)sa->parameter << std::endl; + Log.Out(Logs::Detail, Logs::Error, "Client %s :: unknown Anon/Roleplay Switch %i", name, (int)sa->parameter); return; } entity_list.QueueClients(this, app, true); @@ -12682,7 +12812,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) if (sa->parameter != 0) { - if (!HasSkill(SkillSneak)) + if (!HasSkill(EQEmu::skills::SkillSneak)) { char *hack_str = nullptr; MakeAnyLenString(&hack_str, "Player sent OP_SpawnAppearance with AT_Sneak: %i", sa->parameter); @@ -12888,7 +13018,7 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app) inspect_buffs = group->GetLeadershipAA(groupAAInspectBuffs); } } - if (nt == this || inspect_buffs || (nt->IsClient() && !nt->CastToClient()->GetPVP()) || + if (GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs) || nt == this || inspect_buffs || (nt->IsClient() && !nt->CastToClient()->GetPVP()) || (nt->IsPet() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()) || (nt->IsMerc() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP())) nt->SendBuffsToClient(this); @@ -12952,7 +13082,7 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app) { //Targeting something we shouldn't with /target //but the client allows this without MQ so you don't flag it - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TargetReject, sizeof(TargetReject_Struct)); + auto outapp = new EQApplicationPacket(OP_TargetReject, sizeof(TargetReject_Struct)); outapp->pBuffer[0] = 0x2f; outapp->pBuffer[1] = 0x01; outapp->pBuffer[4] = 0x0d; @@ -12973,7 +13103,7 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app) } else { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TargetReject, sizeof(TargetReject_Struct)); + auto outapp = new EQApplicationPacket(OP_TargetReject, sizeof(TargetReject_Struct)); outapp->pBuffer[0] = 0x2f; outapp->pBuffer[1] = 0x01; outapp->pBuffer[4] = 0x0d; @@ -13126,10 +13256,10 @@ void Client::Handle_OP_Track(const EQApplicationPacket *app) if (GetClass() != RANGER && GetClass() != DRUID && GetClass() != BARD) return; - if (GetSkill(SkillTracking) == 0) - SetSkill(SkillTracking, 1); + if (GetSkill(EQEmu::skills::SkillTracking) == 0) + SetSkill(EQEmu::skills::SkillTracking, 1); else - CheckIncreaseSkill(SkillTracking, nullptr, 15); + CheckIncreaseSkill(EQEmu::skills::SkillTracking, nullptr, 15); if (!entity_list.MakeTrackPacket(this)) Log.Out(Logs::General, Logs::Error, "Unable to generate OP_Track packet requested by client."); @@ -13204,14 +13334,18 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app) event_entry._detail_count = event_details.size(); - ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogTrades, sizeof(QSPlayerLogTrade_Struct)+(sizeof(QSTradeItems_Struct)* event_entry._detail_count)); + auto qs_pack = new ServerPacket( + ServerOP_QSPlayerLogTrades, + sizeof(QSPlayerLogTrade_Struct) + + (sizeof(QSTradeItems_Struct) * event_entry._detail_count)); QSPlayerLogTrade_Struct* qs_buf = (QSPlayerLogTrade_Struct*)qs_pack->pBuffer; memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogTrade_Struct)); int offset = 0; - for (std::list::iterator iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) { + for (auto iter = event_details.begin(); iter != event_details.end(); + ++iter, ++offset) { QSTradeItems_Struct* detail = reinterpret_cast(*iter); qs_buf->items[offset] = *detail; safe_delete(detail); @@ -13236,14 +13370,14 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app) trade->Reset(); } // All done - EQApplicationPacket* outapp = new EQApplicationPacket(OP_FinishTrade, 0); + auto outapp = new EQApplicationPacket(OP_FinishTrade, 0); other->QueuePacket(outapp); this->FastQueuePacket(&outapp); } } // Trading with a Mob object that is not a Client. else if (with) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_FinishTrade, 0); + auto outapp = new EQApplicationPacket(OP_FinishTrade, 0); QueuePacket(outapp); safe_delete(outapp); if (with->IsNPC()) { @@ -13258,14 +13392,17 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app) event_entry._detail_count = event_details.size(); - ServerPacket* qs_pack = new ServerPacket(ServerOP_QSPlayerLogHandins, sizeof(QSPlayerLogHandin_Struct)+(sizeof(QSHandinItems_Struct)* event_entry._detail_count)); + auto qs_pack = + new ServerPacket(ServerOP_QSPlayerLogHandins, + sizeof(QSPlayerLogHandin_Struct) + + (sizeof(QSHandinItems_Struct) * event_entry._detail_count)); QSPlayerLogHandin_Struct* qs_buf = (QSPlayerLogHandin_Struct*)qs_pack->pBuffer; memcpy(qs_buf, &event_entry, sizeof(QSPlayerLogHandin_Struct)); int offset = 0; - for (std::list::iterator iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) { + for (auto iter = event_details.begin(); iter != event_details.end(); ++iter, ++offset) { QSHandinItems_Struct* detail = reinterpret_cast(*iter); qs_buf->items[offset] = *detail; safe_delete(detail); @@ -13392,7 +13529,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) TradeItemsValid = false; break; } - const Item_Struct *Item = database.GetItem(gis->Items[i]); + const EQEmu::ItemBase *Item = database.GetItem(gis->Items[i]); if (!Item) { Message(13, "Unexpected error. Unable to start trader mode"); @@ -13416,6 +13553,10 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) if (database.GetItem(gis->Items[i])) { database.SaveTraderItem(this->CharacterID(), gis->Items[i], gis->SerialNumber[i], gis->Charges[i], ints->ItemCost[i], i); + + auto inst = FindTraderItemBySerialNumber(gis->SerialNumber[i]); + if(inst) + inst->SetPrice(ints->ItemCost[i]); } else { //return; //sony doesnt memset so assume done on first bad item @@ -13426,11 +13567,11 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) safe_delete(gis); this->Trader_StartTrader(); - + // This refreshes the Trader window to display the End Trader button - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderStatus_Struct)); + auto outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderStatus_Struct)); TraderStatus_Struct* tss = (TraderStatus_Struct*)outapp->pBuffer; tss->Code = BazaarTrader_StartTraderMode2; QueuePacket(outapp); @@ -13519,7 +13660,7 @@ void Client::Handle_OP_TradeRequest(const EQApplicationPacket *app) // Client requesting a trade session from an npc/client // Trade session not started until OP_TradeRequestAck is sent - BreakInvis(); + CommonBreakInvisible(); // Pass trade request on to recipient TradeRequest_Struct* msg = (TradeRequest_Struct*)app->pBuffer; @@ -13536,7 +13677,7 @@ void Client::Handle_OP_TradeRequest(const EQApplicationPacket *app) //npcs always accept trade->Start(msg->to_mob_id); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeRequestAck, sizeof(TradeRequest_Struct)); + auto outapp = new EQApplicationPacket(OP_TradeRequestAck, sizeof(TradeRequest_Struct)); TradeRequest_Struct* acc = (TradeRequest_Struct*)outapp->pBuffer; acc->from_mob_id = msg->to_mob_id; acc->to_mob_id = msg->from_mob_id; @@ -13571,7 +13712,7 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app) if (app->size == sizeof(TraderClick_Struct)) { - + TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer; Log.Out(Logs::Detail, Logs::Trading, "Handle_OP_TraderShop: TraderClick_Struct TraderID %d, Code %d, Unknown008 %d, Approval %d", @@ -13586,7 +13727,7 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app) { // This is when a potential purchaser right clicks on this client who is in Trader mode to // browse their goods. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct)); + auto outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct)); TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer; @@ -13600,6 +13741,7 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app) else { Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)" " returned a nullptr pointer"); + safe_delete(outapp); return; } @@ -13863,7 +14005,7 @@ void Client::Handle_OP_VetClaimRequest(const EQApplicationPacket *app) return; } // try to claim something! - EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaim)); + auto vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaim)); VeteranClaim *cr = (VeteranClaim *)vetapp->pBuffer; strcpy(cr->name, GetName()); cr->claim_id = vcr->claim_id; @@ -13940,6 +14082,18 @@ void Client::Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app) XTargetAutoAddHaters = app->ReadUInt8(0); } +void Client::Handle_OP_XTargetOpen(const EQApplicationPacket *app) +{ + if (app->size != 4) { + Log.Out(Logs::General, Logs::None, "Size mismatch in OP_XTargetOpen, expected 1, got %i", app->size); + DumpPacket(app); + return; + } + + auto outapp = new EQApplicationPacket(OP_XTargetOpenResponse, 0); + FastQueuePacket(&outapp); +} + void Client::Handle_OP_XTargetRequest(const EQApplicationPacket *app) { if (app->size < 12) @@ -14175,16 +14329,19 @@ void Client::Handle_OP_XTargetRequest(const EQApplicationPacket *app) void Client::Handle_OP_YellForHelp(const EQApplicationPacket *app) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_YellForHelp, 4); + auto outapp = new EQApplicationPacket(OP_YellForHelp, 4); *(uint32 *)outapp->pBuffer = GetID(); entity_list.QueueCloseClients(this, outapp, true, 100.0); safe_delete(outapp); return; } -/* -void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) +void Client::Handle_OP_ResetAA(const EQApplicationPacket *app) { + if(Admin() >= 50) { + Message(0, "Resetting AA points."); + ResetAA(); + } return; } -*/ + diff --git a/zone/client_packet.h b/zone/client_packet.h index 51b6713b7..2635724dd 100644 --- a/zone/client_packet.h +++ b/zone/client_packet.h @@ -218,6 +218,8 @@ void Handle_OP_PetitionRefresh(const EQApplicationPacket *app); void Handle_OP_PetitionResolve(const EQApplicationPacket *app); void Handle_OP_PetitionUnCheckout(const EQApplicationPacket *app); + void Handle_OP_PlayerStateAdd(const EQApplicationPacket *app); + void Handle_OP_PlayerStateRemove(const EQApplicationPacket *app); void Handle_OP_PickPocket(const EQApplicationPacket *app); void Handle_OP_PopupResponse(const EQApplicationPacket *app); void Handle_OP_PotionBelt(const EQApplicationPacket *app); @@ -290,6 +292,8 @@ void Handle_OP_WearChange(const EQApplicationPacket *app); void Handle_OP_WhoAllRequest(const EQApplicationPacket *app); void Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app); + void Handle_OP_XTargetOpen(const EQApplicationPacket *app); void Handle_OP_XTargetRequest(const EQApplicationPacket *app); void Handle_OP_YellForHelp(const EQApplicationPacket *app); void Handle_OP_ZoneChange(const EQApplicationPacket *app); + void Handle_OP_ResetAA(const EQApplicationPacket *app); diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 40e8e6d1b..e1a769743 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -26,8 +26,8 @@ #include #ifdef _WINDOWS + #include #include - #include #define snprintf _snprintf #define strncasecmp _strnicmp #define strcasecmp _stricmp @@ -55,7 +55,7 @@ extern QueryServ* QServ; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern PetitionList petition_list; extern EntityList entity_list; @@ -66,7 +66,7 @@ bool Client::Process() { if(Connected() || IsLD()) { // try to send all packets that weren't sent before - if(!IsLD() && zoneinpacket_timer.Check()) + if (!IsLD() && zoneinpacket_timer.Check()) { SendAllPackets(); } @@ -126,17 +126,19 @@ bool Client::Process() { HandleRespawnFromHover(0); } - if(IsTracking() && (GetClientVersion() >= ClientVersion::SoD) && TrackingTimer.Check()) + if (IsTracking() && (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) && TrackingTimer.Check()) DoTracking(); - if(hpupdate_timer.Check()) + // SendHPUpdate calls hpupdate_timer.Start so it can delay this timer, so lets not reset with the check + // since the function will anyways + if(hpupdate_timer.Check(false)) SendHPUpdate(); if(mana_timer.Check()) SendManaUpdatePacket(); - if(dead && dead_timer.Check()) { - database.MoveCharacterToZone(GetName(), database.GetZoneName(m_pp.binds[0].zoneId)); + if(dead && dead_timer.Check()) { + database.MoveCharacterToZone(GetName(), database.GetZoneName(m_pp.binds[0].zoneId)); m_pp.zone_id = m_pp.binds[0].zoneId; m_pp.zoneInstance = m_pp.binds[0].instance_id; @@ -197,10 +199,8 @@ bool Client::Process() { instalog = true; } - if (IsStunned() && stunned_timer.Check()) { - this->stunned = false; - this->stunned_timer.Disable(); - } + if (IsStunned() && stunned_timer.Check()) + Mob::UnStun(); if(!m_CheatDetectMoved) { @@ -262,7 +262,7 @@ bool Client::Process() { } if(light_update_timer.Check()) { - + UpdateEquipmentLight(); if(UpdateActiveLight()) { SendAppearancePacket(AT_Light, GetActiveLightType()); @@ -296,10 +296,10 @@ bool Client::Process() { } if(AutoFireEnabled()){ - ItemInst *ranged = GetInv().GetItem(MainRange); + ItemInst *ranged = GetInv().GetItem(EQEmu::legacy::SlotRange); if(ranged) { - if(ranged->GetItem() && ranged->GetItem()->ItemType == ItemTypeBow){ + if (ranged->GetItem() && ranged->GetItem()->ItemType == EQEmu::item::ItemTypeBow){ if(ranged_timer.Check(false)){ if(GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())){ if(GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())){ @@ -319,7 +319,7 @@ bool Client::Process() { ranged_timer.Start(); } } - else if(ranged->GetItem() && (ranged->GetItem()->ItemType == ItemTypeLargeThrowing || ranged->GetItem()->ItemType == ItemTypeSmallThrowing)){ + else if (ranged->GetItem() && (ranged->GetItem()->ItemType == EQEmu::item::ItemTypeLargeThrowing || ranged->GetItem()->ItemType == EQEmu::item::ItemTypeSmallThrowing)){ if(ranged_timer.Check(false)){ if(GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())){ if(GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())){ @@ -391,73 +391,12 @@ bool Client::Process() { } else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP { - if(CheckAAEffect(aaEffectRampage)) - { + ItemInst *wpn = GetInv().GetItem(EQEmu::legacy::SlotPrimary); + TryWeaponProc(wpn, auto_attack_target, EQEmu::legacy::SlotPrimary); + + DoAttackRounds(auto_attack_target, EQEmu::legacy::SlotPrimary); + if (CheckAATimer(aaTimerRampage)) entity_list.AEAttack(this, 30); - } else { - Attack(auto_attack_target, MainPrimary); // Kaiyodo - added attacking hand to arguments - } - ItemInst *wpn = GetInv().GetItem(MainPrimary); - TryWeaponProc(wpn, auto_attack_target, MainPrimary); - - bool tripleAttackSuccess = false; - if( auto_attack_target && CanThisClassDoubleAttack() ) { - - CheckIncreaseSkill(SkillDoubleAttack, auto_attack_target, -10); - if(CheckDoubleAttack()) { - //should we allow rampage on double attack? - if(CheckAAEffect(aaEffectRampage)) { - entity_list.AEAttack(this, 30); - } else { - Attack(auto_attack_target, MainPrimary, false); - } - } - - //triple attack: rangers, monks, warriors, berserkers over level 60 - if((((GetClass() == MONK || GetClass() == WARRIOR || GetClass() == RANGER || GetClass() == BERSERKER) - && GetLevel() >= 60) || GetSpecialAbility(SPECATK_TRIPLE)) - && CheckDoubleAttack(true)) - { - tripleAttackSuccess = true; - Attack(auto_attack_target, MainPrimary, false); - } - - //quad attack, does this belong here?? - if(GetSpecialAbility(SPECATK_QUAD) && CheckDoubleAttack(true)) - { - Attack(auto_attack_target, MainPrimary, false); - } - } - - //Live AA - Flurry, Rapid Strikes ect (Flurry does not require Triple Attack). - int16 flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance; - - if (auto_attack_target && flurrychance) - { - if(zone->random.Int(0, 99) < flurrychance) - { - Message_StringID(MT_NPCFlurry, YOU_FLURRY); - Attack(auto_attack_target, MainPrimary, false); - Attack(auto_attack_target, MainPrimary, false); - } - } - - int16 ExtraAttackChanceBonus = spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance; - - if (auto_attack_target && ExtraAttackChanceBonus) { - ItemInst *wpn = GetInv().GetItem(MainPrimary); - if(wpn){ - if(wpn->GetItem()->ItemType == ItemType2HSlash || - wpn->GetItem()->ItemType == ItemType2HBlunt || - wpn->GetItem()->ItemType == ItemType2HPiercing ) - { - if(zone->random.Int(0, 99) < ExtraAttackChanceBonus) - { - Attack(auto_attack_target, MainPrimary, false); - } - } - } - } } } @@ -489,32 +428,12 @@ bool Client::Process() { //you can't see your target } else if(auto_attack_target->GetHP() > -10) { - float DualWieldProbability = 0.0f; + CheckIncreaseSkill(EQEmu::skills::SkillDualWield, auto_attack_target, -10); + if (CheckDualWield()) { + ItemInst *wpn = GetInv().GetItem(EQEmu::legacy::SlotSecondary); + TryWeaponProc(wpn, auto_attack_target, EQEmu::legacy::SlotSecondary); - int16 Ambidexterity = aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity; - DualWieldProbability = (GetSkill(SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f; // 78.0 max - int16 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance; - DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f; - - float random = zone->random.Real(0, 1); - CheckIncreaseSkill(SkillDualWield, auto_attack_target, -10); - if (random < DualWieldProbability){ // Max 78% of DW - if(CheckAAEffect(aaEffectRampage)) { - entity_list.AEAttack(this, 30, MainSecondary); - } else { - Attack(auto_attack_target, MainSecondary); // Single attack with offhand - } - ItemInst *wpn = GetInv().GetItem(MainSecondary); - TryWeaponProc(wpn, auto_attack_target, MainSecondary); - - if( CanThisClassDoubleAttack() && CheckDoubleAttack()) { - if(CheckAAEffect(aaEffectRampage)) { - entity_list.AEAttack(this, 30, MainSecondary); - } else { - if(auto_attack_target && auto_attack_target->GetHP() > -10) - Attack(auto_attack_target, MainSecondary); // Single attack with offhand - } - } + DoAttackRounds(auto_attack_target, EQEmu::legacy::SlotSecondary); } } } @@ -522,9 +441,7 @@ bool Client::Process() { if (position_timer.Check()) { if (IsAIControlled()) { - if(IsMoving()) - SendPosUpdate(2); - else + if(!IsMoving()) { animation = 0; m_Delta = glm::vec4(0.0f, 0.0f, 0.0f, m_Delta.w); @@ -562,7 +479,7 @@ bool Client::Process() { } ProjectileAttack(); - + if(spellbonuses.GravityEffect == 1) { if(gravity_timer.Check()) DoGravityEffect(); @@ -707,7 +624,7 @@ bool Client::Process() { { //client logged out or errored out //ResetTrade(); - if (client_state != CLIENT_KICKED) { + if (client_state != CLIENT_KICKED && !zoning && !instalog) { Save(); } @@ -793,7 +710,7 @@ void Client::OnDisconnect(bool hard_disconnect) { Mob *Other = trade->With(); if(Other) { - Log.Out(Logs::Detail, Logs::Trading, "Client disconnected during a trade. Returning their items."); + Log.Out(Logs::Detail, Logs::Trading, "Client disconnected during a trade. Returning their items."); FinishTrade(this); if(Other->IsClient()) @@ -809,27 +726,22 @@ void Client::OnDisconnect(bool hard_disconnect) { /* Remove ourself from all proximities */ ClearAllProximities(); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LogoutReply); + auto outapp = new EQApplicationPacket(OP_LogoutReply); FastQueuePacket(&outapp); Disconnect(); } // Sends the client complete inventory used in character login - -// DO WE STILL NEED THE 'ITEMCOMBINED' CONDITIONAL CODE? - -//#ifdef ITEMCOMBINED -void Client::BulkSendInventoryItems() { - int16 slot_id = 0; - +void Client::BulkSendInventoryItems() +{ // LINKDEAD TRADE ITEMS // Move trade slot items back into normal inventory..need them there now for the proceeding validity checks - for(slot_id = EmuConstants::TRADE_BEGIN; slot_id <= EmuConstants::TRADE_END; slot_id++) { + for (int16 slot_id = EQEmu::legacy::TRADE_BEGIN; slot_id <= EQEmu::legacy::TRADE_END; slot_id++) { ItemInst* inst = m_inv.PopItem(slot_id); if(inst) { - bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false; - int16 free_slot_id = m_inv.FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow); + bool is_arrow = (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow) ? true : false; + int16 free_slot_id = m_inv.FindFreeSlot(inst->IsClassBag(), true, inst->GetItem()->Size, is_arrow); Log.Out(Logs::Detail, Logs::Inventory, "Incomplete Trade Transaction: Moving %s from slot %i to %i", inst->GetItem()->Name, slot_id, free_slot_id); PutItemInInventory(free_slot_id, *inst, false); database.SaveInventory(character_id, nullptr, slot_id); @@ -838,141 +750,87 @@ void Client::BulkSendInventoryItems() { } bool deletenorent = database.NoRentExpired(GetName()); - if(deletenorent){ RemoveNoRent(false); } //client was offline for more than 30 minutes, delete no rent items + if (deletenorent) { //client was offline for more than 30 minutes, delete no rent items + if (RuleB(Inventory, TransformSummonedBags)) + DisenchantSummonedBags(false); + RemoveNoRent(false); + } RemoveDuplicateLore(false); MoveSlotNotAllowed(false); - // The previous three method calls took care of moving/removing expired/illegal item placements + EQEmu::OutBuffer ob; + EQEmu::OutBuffer::pos_type last_pos = ob.tellp(); - //TODO: this function is just retarded... it re-allocates the buffer for every - //new item. It should be changed to loop through once, gather the - //lengths, and item packet pointers into an array (fixed length), and - //then loop again to build the packet. - //EQApplicationPacket *packets[50]; - //unsigned long buflen = 0; - //unsigned long pos = 0; - //memset(packets, 0, sizeof(packets)); - //foreach item in the invendor sections - // packets[pos++] = ReturnItemPacket(...) - // buflen += temp->size - //... - //allocat the buffer - //for r from 0 to pos - // put pos[r]->pBuffer into the buffer - //for r from 0 to pos - // safe_delete(pos[r]); - - uint32 size = 0; - uint16 i = 0; - std::map ser_items; - std::map::iterator itr; - - //Inventory items - for(slot_id = MAIN_BEGIN; slot_id < EmuConstants::MAP_POSSESSIONS_SIZE; slot_id++) { + // Possessions items + for (int16 slot_id = SLOT_BEGIN; slot_id < EQEmu::legacy::TYPE_POSSESSIONS_SIZE; slot_id++) { const ItemInst* inst = m_inv[slot_id]; - if(inst) { - std::string packet = inst->Serialize(slot_id); - ser_items[i++] = packet; - size += packet.length(); - } + if (!inst) + continue; + + inst->Serialize(ob, slot_id); + + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Inventory, "Serialization failed on item slot %d during BulkSendInventoryItems. Item skipped.", slot_id); + + last_pos = ob.tellp(); } - // Power Source - if(GetClientVersion() >= ClientVersion::SoF) { - const ItemInst* inst = m_inv[MainPowerSource]; - if(inst) { - std::string packet = inst->Serialize(MainPowerSource); - ser_items[i++] = packet; - size += packet.length(); + // PowerSource item + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { + const ItemInst* inst = m_inv[EQEmu::legacy::SlotPowerSource]; + if (inst) { + inst->Serialize(ob, EQEmu::legacy::SlotPowerSource); + + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Inventory, "Serialization failed on item slot %d during BulkSendInventoryItems. Item skipped.", EQEmu::legacy::SlotPowerSource); + + last_pos = ob.tellp(); } } // Bank items - for(slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; slot_id++) { + for (int16 slot_id = EQEmu::legacy::BANK_BEGIN; slot_id <= EQEmu::legacy::BANK_END; slot_id++) { const ItemInst* inst = m_inv[slot_id]; - if(inst) { - std::string packet = inst->Serialize(slot_id); - ser_items[i++] = packet; - size += packet.length(); - } + if (!inst) + continue; + + inst->Serialize(ob, slot_id); + + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Inventory, "Serialization failed on item slot %d during BulkSendInventoryItems. Item skipped.", slot_id); + + last_pos = ob.tellp(); } - // Shared Bank items - for(slot_id = EmuConstants::SHARED_BANK_BEGIN; slot_id <= EmuConstants::SHARED_BANK_END; slot_id++) { + // SharedBank items + for (int16 slot_id = EQEmu::legacy::SHARED_BANK_BEGIN; slot_id <= EQEmu::legacy::SHARED_BANK_END; slot_id++) { const ItemInst* inst = m_inv[slot_id]; - if(inst) { - std::string packet = inst->Serialize(slot_id); - ser_items[i++] = packet; - size += packet.length(); - } + if (!inst) + continue; + + inst->Serialize(ob, slot_id); + + if (ob.tellp() == last_pos) + Log.Out(Logs::General, Logs::Inventory, "Serialization failed on item slot %d during BulkSendInventoryItems. Item skipped.", slot_id); + + last_pos = ob.tellp(); } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_CharInventory, size); - uchar* ptr = outapp->pBuffer; - for(itr = ser_items.begin(); itr != ser_items.end(); ++itr){ - int length = itr->second.length(); - if(length > 5) { - memcpy(ptr, itr->second.c_str(), length); - ptr += length; - } - } + auto outapp = new EQApplicationPacket(OP_CharInventory); + outapp->size = ob.size(); + outapp->pBuffer = ob.detach(); QueuePacket(outapp); safe_delete(outapp); } -/*#else -void Client::BulkSendInventoryItems() -{ - // Search all inventory buckets for items - bool deletenorent=database.NoRentExpired(GetName()); - // Worn items and Inventory items - int16 slot_id = 0; - if(deletenorent){//client was offline for more than 30 minutes, delete no rent items - RemoveNoRent(); - } - for (slot_id=EmuConstants::POSSESSIONS_BEGIN; slot_id<=EmuConstants::POSSESSIONS_END; slot_id++) { - const ItemInst* inst = m_inv[slot_id]; - if (inst){ - SendItemPacket(slot_id, inst, ItemPacketCharInventory); - } - } - // Bank items - for (slot_id=EmuConstants::BANK_BEGIN; slot_id<=EmuConstants::BANK_END; slot_id++) { // 2015... - const ItemInst* inst = m_inv[slot_id]; - if (inst){ - SendItemPacket(slot_id, inst, ItemPacketCharInventory); - } - } - - // Shared Bank items - for (slot_id=EmuConstants::SHARED_BANK_BEGIN; slot_id<=EmuConstants::SHARED_BANK_END; slot_id++) { - const ItemInst* inst = m_inv[slot_id]; - if (inst){ - SendItemPacket(slot_id, inst, ItemPacketCharInventory); - } - } - - // LINKDEAD TRADE ITEMS - // If player went LD during a trade, they have items in the trade inventory - // slots. These items are now being put into their inventory (then queue up on cursor) - for (int16 trade_slot_id=EmuConstants::TRADE_BEGIN; trade_slot_id<=EmuConstants::TRADE_END; trade_slot_id++) { - const ItemInst* inst = m_inv[slot_id]; - if (inst) { - int16 free_slot_id = m_inv.FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size); - DeleteItemInInventory(trade_slot_id, 0, false); - PutItemInInventory(free_slot_id, *inst, true); - } - } -} -#endif*/ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) { - const Item_Struct* handyitem = nullptr; + const EQEmu::ItemBase* handyitem = nullptr; uint32 numItemSlots = 80; //The max number of items passed in the transaction. - if (m_ClientVersionBit & BIT_RoFAndLater) { // RoF+ can send 200 items + if (m_ClientVersionBit & EQEmu::versions::bit_RoFAndLater) { // RoF+ can send 200 items numItemSlots = 200; } - const Item_Struct *item; + const EQEmu::ItemBase *item; std::list merlist = zone->merchanttable[merchant_id]; std::list::const_iterator itr; Mob* merch = entity_list.GetMobByNpcTypeID(npcid); @@ -1011,7 +869,7 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) { else handychance--; int charges = 1; - if (item->ItemClass == ItemClassCommon) + if (item->IsClassCommon()) charges = item->MaxCharges; ItemInst* inst = database.CreateItem(item, charges); if (inst) { @@ -1158,7 +1016,10 @@ void Client::OPRezzAnswer(uint32 Action, uint32 SpellID, uint16 ZoneID, uint16 I if((SpellEffectDescNum == 82) || (SpellEffectDescNum == 39067)) { SetMana(0); SetHP(GetMaxHP()/5); - SpellOnTarget(756, this); // Rezz effects + int rez_eff = 756; + if (GetRace() == BARBARIAN || GetRace() == DWARF || GetRace() == TROLL || GetRace() == OGRE) + rez_eff = 757; + SpellOnTarget(rez_eff, this); // Rezz effects } else { SetMana(GetMaxMana()); @@ -1226,16 +1087,21 @@ void Client::OPMemorizeSpell(const EQApplicationPacket* app) switch(memspell->scribing) { case memSpellScribing: { // scribing spell to book - const ItemInst* inst = m_inv[MainCursor]; + const ItemInst* inst = m_inv[EQEmu::legacy::SlotCursor]; - if(inst && inst->IsType(ItemClassCommon)) + if (inst && inst->IsClassCommon()) { - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); + + if (RuleB(Character, RestrictSpellScribing) && !item->IsEquipable(GetRace(), GetClass())) { + Message_StringID(13, CANNOT_USE_ITEM); + break; + } if(item && item->Scroll.Effect == (int32)(memspell->spell_id)) { ScribeSpell(memspell->spell_id, memspell->slot); - DeleteItemInInventory(MainCursor, 1, true); + DeleteItemInInventory(EQEmu::legacy::SlotCursor, 1, true); } else Message(0,"Scribing spell: inst exists but item does not or spell ids do not match."); @@ -1264,11 +1130,26 @@ void Client::OPMemorizeSpell(const EQApplicationPacket* app) Save(); } +void Client::CancelSneakHide() +{ + if (hidden || improved_hidden) { + auto app = new EQApplicationPacket(OP_CancelSneakHide, 0); + FastQueuePacket(&app); + // SoF and Tit send back a OP_SpawnAppearance turning off AT_Invis + // so we need to handle our sneaking flag only + // The later clients send back a OP_Hide (this has a size but data is 0) + // as well as OP_SpawnAppearance with AT_Invis and one with AT_Sneak + // So we don't have to handle any of those flags + if (ClientVersionBit() & EQEmu::versions::bit_SoFAndEarlier) + sneaking = false; + } +} + void Client::BreakInvis() { if (invisible) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer; sa_out->spawn_id = GetID(); sa_out->type = 0x03; @@ -1581,7 +1462,7 @@ void Client::OPMoveCoin(const EQApplicationPacket* app) trade->sp, trade->cp ); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeCoins,sizeof(TradeCoin_Struct)); + auto outapp = new EQApplicationPacket(OP_TradeCoins, sizeof(TradeCoin_Struct)); TradeCoin_Struct* tcs = (TradeCoin_Struct*)outapp->pBuffer; tcs->trader = trader->GetID(); tcs->slot = mc->cointype2; @@ -1618,15 +1499,20 @@ void Client::OPGMTraining(const EQApplicationPacket *app) // if this for-loop acts up again (crashes linux), try enabling the before and after #pragmas //#pragma GCC push_options //#pragma GCC optimize ("O0") - for (int sk = Skill1HBlunt; sk <= HIGHEST_SKILL; ++sk) { - if(sk == SkillTinkering && GetRace() != GNOME) { + for (int sk = EQEmu::skills::Skill1HBlunt; sk <= EQEmu::skills::HIGHEST_SKILL; ++sk) { + if (sk == EQEmu::skills::SkillTinkering && GetRace() != GNOME) { gmtrain->skills[sk] = 0; //Non gnomes can't tinker! } else { - gmtrain->skills[sk] = GetMaxSkillAfterSpecializationRules((SkillUseTypes)sk, MaxSkill((SkillUseTypes)sk, GetClass(), RuleI(Character, MaxLevel))); + gmtrain->skills[sk] = GetMaxSkillAfterSpecializationRules((EQEmu::skills::SkillType)sk, MaxSkill((EQEmu::skills::SkillType)sk, GetClass(), RuleI(Character, MaxLevel))); //this is the highest level that the trainer can train you to, this is enforced clientside so we can't just //Set it to 1 with CanHaveSkill or you wont be able to train past 1. } } + + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF2 && GetClass() == BERSERKER) { + gmtrain->skills[EQEmu::skills::Skill1HPiercing] = gmtrain->skills[EQEmu::skills::Skill2HPiercing]; + gmtrain->skills[EQEmu::skills::Skill2HPiercing] = 0; + } //#pragma GCC pop_options uchar ending[]={0x34,0x87,0x8a,0x3F,0x01 @@ -1645,7 +1531,7 @@ void Client::OPGMTraining(const EQApplicationPacket *app) void Client::OPGMEndTraining(const EQApplicationPacket *app) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GMEndTrainingResponse, 0); + auto outapp = new EQApplicationPacket(OP_GMEndTrainingResponse, 0); GMTrainEnd_Struct *p = (GMTrainEnd_Struct *)app->pBuffer; FastQueuePacket(&outapp); @@ -1710,14 +1596,14 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app) else if (gmskill->skillbank == 0x00) { // normal skills go here - if (gmskill->skill_id > HIGHEST_SKILL) + if (gmskill->skill_id > EQEmu::skills::HIGHEST_SKILL) { std::cout << "Wrong Training Skill (abilities)" << std::endl; DumpPacket(app); return; } - SkillUseTypes skill = (SkillUseTypes) gmskill->skill_id; + EQEmu::skills::SkillType skill = (EQEmu::skills::SkillType)gmskill->skill_id; if(!CanHaveSkill(skill)) { Log.Out(Logs::Detail, Logs::Skills, "Tried to train skill %d, which is not allowed.", skill); @@ -1742,27 +1628,27 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app) SetSkill(skill, t_level); } else { switch(skill) { - case SkillBrewing: - case SkillMakePoison: - case SkillTinkering: - case SkillResearch: - case SkillAlchemy: - case SkillBaking: - case SkillTailoring: - case SkillBlacksmithing: - case SkillFletching: - case SkillJewelryMaking: - case SkillPottery: + case EQEmu::skills::SkillBrewing: + case EQEmu::skills::SkillMakePoison: + case EQEmu::skills::SkillTinkering: + case EQEmu::skills::SkillResearch: + case EQEmu::skills::SkillAlchemy: + case EQEmu::skills::SkillBaking: + case EQEmu::skills::SkillTailoring: + case EQEmu::skills::SkillBlacksmithing: + case EQEmu::skills::SkillFletching: + case EQEmu::skills::SkillJewelryMaking: + case EQEmu::skills::SkillPottery: if(skilllevel >= RuleI(Skills, MaxTrainTradeskills)) { Message_StringID(13, MORE_SKILLED_THAN_I, pTrainer->GetCleanName()); return; } break; - case SkillSpecializeAbjure: - case SkillSpecializeAlteration: - case SkillSpecializeConjuration: - case SkillSpecializeDivination: - case SkillSpecializeEvocation: + case EQEmu::skills::SkillSpecializeAbjure: + case EQEmu::skills::SkillSpecializeAlteration: + case EQEmu::skills::SkillSpecializeConjuration: + case EQEmu::skills::SkillSpecializeDivination: + case EQEmu::skills::SkillSpecializeEvocation: if(skilllevel >= RuleI(Skills, MaxTrainSpecializations)) { Message_StringID(13, MORE_SKILLED_THAN_I, pTrainer->GetCleanName()); return; @@ -1779,7 +1665,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app) return; } - if(gmskill->skill_id >= SkillSpecializeAbjure && gmskill->skill_id <= SkillSpecializeEvocation) + if (gmskill->skill_id >= EQEmu::skills::SkillSpecializeAbjure && gmskill->skill_id <= EQEmu::skills::SkillSpecializeEvocation) { int MaxSpecSkill = GetMaxSkillAfterSpecializationRules(skill, MaxSkillValue); if (skilllevel >= MaxSpecSkill) @@ -1803,11 +1689,11 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app) } } - if(GetClientVersion() >= ClientVersion::SoF) { + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { // The following packet decreases the skill points left in the Training Window and // produces the 'You have increased your skill / learned the basics of' message. // - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMTrainSkillConfirm, sizeof(GMTrainSkillConfirm_Struct)); + auto outapp = new EQApplicationPacket(OP_GMTrainSkillConfirm, sizeof(GMTrainSkillConfirm_Struct)); GMTrainSkillConfirm_Struct *gmtsc = (GMTrainSkillConfirm_Struct *)outapp->pBuffer; gmtsc->SkillID = gmskill->skill_id; @@ -1817,7 +1703,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app) gmtsc->SkillID += 100; } else - gmtsc->NewSkill = (GetRawSkill((SkillUseTypes)gmtsc->SkillID) == 1); + gmtsc->NewSkill = (GetRawSkill((EQEmu::skills::SkillType)gmtsc->SkillID) == 1); gmtsc->Cost = Cost; @@ -1865,7 +1751,7 @@ void Client::OPGMSummon(const EQApplicationPacket *app) } else if (tmp < '0' || tmp > '9') // dont send to world if it's not a player's name { - ServerPacket* pack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct)); + auto pack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct)); ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*) pack->pBuffer; strcpy(szp->adminname, this->GetName()); szp->adminrank = this->Admin(); @@ -1907,7 +1793,7 @@ void Client::DoStaminaUpdate() { if(!stamina_timer.Check()) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Stamina, sizeof(Stamina_Struct)); + auto outapp = new EQApplicationPacket(OP_Stamina, sizeof(Stamina_Struct)); Stamina_Struct* sta = (Stamina_Struct*)outapp->pBuffer; if(zone->GetZoneID() != 151) { @@ -2133,7 +2019,8 @@ void Client::HandleRespawnFromHover(uint32 Option) m_Position.z = corpse->GetZ(); } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZonePlayerToBind, sizeof(ZonePlayerToBind_Struct) + 10); + auto outapp = + new EQApplicationPacket(OP_ZonePlayerToBind, sizeof(ZonePlayerToBind_Struct) + 10); ZonePlayerToBind_Struct* gmg = (ZonePlayerToBind_Struct*) outapp->pBuffer; gmg->bind_zone_id = zone->GetZoneID(); @@ -2165,7 +2052,8 @@ void Client::HandleRespawnFromHover(uint32 Option) { PendingRezzSpellID = 0; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZonePlayerToBind, sizeof(ZonePlayerToBind_Struct) + chosen->name.length() + 1); + auto outapp = new EQApplicationPacket(OP_ZonePlayerToBind, sizeof(ZonePlayerToBind_Struct) + + chosen->name.length() + 1); ZonePlayerToBind_Struct* gmg = (ZonePlayerToBind_Struct*) outapp->pBuffer; gmg->bind_zone_id = zone->GetZoneID(); @@ -2232,7 +2120,7 @@ void Client::ClearHover() // Our Entity ID is currently zero, set in Client::Death SetID(entity_list.GetFreeID()); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ZoneEntry, sizeof(ServerZoneEntry_Struct)); + auto outapp = new EQApplicationPacket(OP_ZoneEntry, sizeof(ServerZoneEntry_Struct)); ServerZoneEntry_Struct* sze = (ServerZoneEntry_Struct*)outapp->pBuffer; FillSpawnStruct(&sze->player,CastToMob()); @@ -2243,7 +2131,7 @@ void Client::ClearHover() entity_list.QueueClients(this, outapp, false); safe_delete(outapp); - if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UFAndLater) + if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) { EQApplicationPacket *outapp = MakeBuffsPacket(false); CastToClient()->FastQueuePacket(&outapp); @@ -2284,7 +2172,7 @@ void Client::HandleLFGuildResponse(ServerPacket *pack) --i; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LFGuild, PacketSize); + auto outapp = new EQApplicationPacket(OP_LFGuild, PacketSize); outapp->WriteUInt32(3); outapp->WriteUInt32(0xeb63); // Don't know the significance of this value. outapp->WriteUInt32(NumberOfMatches); @@ -2312,7 +2200,7 @@ void Client::HandleLFGuildResponse(ServerPacket *pack) } case QSG_LFGuild_RequestPlayerInfo: { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LFGuild, sizeof(LFGuild_PlayerToggle_Struct)); + auto outapp = new EQApplicationPacket(OP_LFGuild, sizeof(LFGuild_PlayerToggle_Struct)); LFGuild_PlayerToggle_Struct *pts = (LFGuild_PlayerToggle_Struct *)outapp->pBuffer; pts->Command = 0; @@ -2342,7 +2230,7 @@ void Client::HandleLFGuildResponse(ServerPacket *pack) --i; } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LFGuild, PacketSize); + auto outapp = new EQApplicationPacket(OP_LFGuild, PacketSize); outapp->WriteUInt32(4); outapp->WriteUInt32(0xeb63); outapp->WriteUInt32(NumberOfMatches); @@ -2376,7 +2264,7 @@ void Client::HandleLFGuildResponse(ServerPacket *pack) TimeZone = pack->ReadUInt32(); TimePosted = pack->ReadUInt32(); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LFGuild, sizeof(LFGuild_GuildToggle_Struct)); + auto outapp = new EQApplicationPacket(OP_LFGuild, sizeof(LFGuild_GuildToggle_Struct)); LFGuild_GuildToggle_Struct *gts = (LFGuild_GuildToggle_Struct *)outapp->pBuffer; gts->Command = 1; @@ -2403,7 +2291,7 @@ void Client::HandleLFGuildResponse(ServerPacket *pack) void Client::SendLFGuildStatus() { - ServerPacket* pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + 17); + auto pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + 17); pack->WriteUInt32(zone->GetZoneID()); pack->WriteUInt32(zone->GetInstanceID()); @@ -2418,7 +2306,8 @@ void Client::SendLFGuildStatus() void Client::SendGuildLFGuildStatus() { - ServerPacket* pack = new ServerPacket(ServerOP_QueryServGeneric, strlen(GetName()) + +strlen(guild_mgr.GetGuildName(GuildID())) + 18); + auto pack = new ServerPacket(ServerOP_QueryServGeneric, + strlen(GetName()) + +strlen(guild_mgr.GetGuildName(GuildID())) + 18); pack->WriteUInt32(zone->GetZoneID()); pack->WriteUInt32(zone->GetInstanceID()); diff --git a/zone/command.cpp b/zone/command.cpp index b383e09b3..4c60ad65b 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemulator.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,12 +23,12 @@ 1. At the bottom of command.h you must add a prototype for it. 2. Add the function in this file. 3. In the command_init function you must add a call to command_add - for your function. If you want an alias for your command, add - a second call to command_add with the description and access args - set to nullptr and 0 respectively since they aren't used when adding - an alias. The function pointers being equal is makes it an alias. - The access level you set with command_add is only a default if - the command isn't listed in the commands db table. + for your function. + + Notes: If you want an alias for your command, add an entry to the + `command_settings` table in your database. The access level you + set with command_add is the default setting if the command isn't + listed in the `command_settings` db table. */ @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef _WINDOWS #define strcasecmp _stricmp @@ -51,6 +52,7 @@ #include "../common/rulesys.h" #include "../common/serverinfo.h" #include "../common/string_util.h" +#include "../say_link.h" #include "../common/eqemu_logsys.h" @@ -72,9 +74,7 @@ extern TaskManager *taskmanager; void CatchSignal(int sig_num); - -//struct cl_struct *commandlist; // the actual linked list of commands -int commandcount; // how many commands we have +int commandcount; // how many commands we have // this is the pointer to the dispatch function, updated once // init has been performed to point at the real function @@ -85,11 +85,11 @@ void command_bestz(Client *c, const Seperator *message); void command_pf(Client *c, const Seperator *message); std::map commandlist; +std::map commandaliases; -//All allocated CommandRecords get put in here so they get deleted on shutdown +// All allocated CommandRecords get put in here so they get deleted on shutdown LinkedList cleanup_commandlist; - /* * command_notavail * This is the default dispatch function when commands aren't loaded. @@ -104,9 +104,9 @@ int command_notavail(Client *c, const char *message) return -1; } -/*****************************************************************************/ -/* the rest below here could be in a dynamically loaded module eventually */ -/*****************************************************************************/ +/************************************************************************** +/* the rest below here could be in a dynamically loaded module eventually * +/*************************************************************************/ /* @@ -138,37 +138,23 @@ Access Levels: * Parameters: * none * - * When adding a command, if it's the first time that function pointer is - * used it is a new command. If that function pointer is used for another - * command, the command is added as an alias; description and access level - * are not used and can be nullptr. + * When adding a new command, only hard-code 'real' commands - + * all command aliases are added later through a database call * */ -int command_init(void) { +int command_init(void) +{ + commandaliases.clear(); - if - ( - -#ifdef PACKET_PROFILER - command_add("packetprofile", "- Dump packet profile for target or self.", 250, command_packetprofile) || -#endif -#ifdef EQPROFILE - command_add("profiledump", "- Dump profiling info to logs", 250, command_profiledump) || - command_add("profilereset", "- Reset profiling info", 250, command_profilereset) || -#endif -#ifdef BOTS - command_add("bot", "- Type \"#bot help\" to the see the list of available commands for bots.", 0, command_bot) || -#endif - + if ( command_add("acceptrules", "[acceptrules] - Accept the EQEmu Agreement", 0, command_acceptrules) || - command_add("advnpc", "analog for advnpcspawn [maketype|makegroup|addgroupentry|addgroupspawn][removegroupspawn|movespawn|editgroupbox|cleargroupbox]", 150, command_advnpcspawn) || command_add("advnpcspawn", "[maketype|makegroup|addgroupentry|addgroupspawn][removegroupspawn|movespawn|editgroupbox|cleargroupbox]", 150, command_advnpcspawn) || command_add("aggro", "(range) [-v] - Display aggro information for all mobs 'range' distance from your target. -v is verbose faction info.", 80, command_aggro) || command_add("aggrozone", "[aggro] - Aggro every mob in the zone with X aggro. Default is 0. Not recommend if you're not invulnerable.", 100, command_aggrozone) || command_add("ai", "[factionid/spellslist/con/guard/roambox/stop/start] - Modify AI on NPC target", 100, command_ai) || - command_add("altactivate", "[argument] - activates alternate advancement abilities, use altactivate help for more information", 0, command_altactivate) || command_add("appearance", "[type] [value] - Send an appearance packet for you or your target", 150, command_appearance) || + command_add("apply_shared_memory", "[shared_memory_name] - Tells every zone and world to apply a specific shared memory segment by name.", 250, command_apply_shared_memory) || command_add("attack", "[targetname] - Make your NPC target attack targetname", 150, command_attack) || command_add("augmentitem", "Force augments an item. Must have the augment item window open.", 250, command_augmentitem) || command_add("ban", "[name] [reason]- Ban by character name", 150, command_ban) || @@ -176,20 +162,22 @@ int command_init(void) { command_add("beardcolor", "- Change the beard color of your target", 80, command_beardcolor) || command_add("bestz", "- Ask map for a good Z coord for your x,y coords.", 0, command_bestz) || command_add("bind", "- Sets your targets bind spot to their current location", 200, command_bind) || + +#ifdef BOTS + command_add("bot", "- Type \"#bot help\" or \"^help\" to the see the list of available commands for bots.", 0, command_bot) || +#endif + command_add("camerashake", "Shakes the camera on everyone's screen globally.", 80, command_camerashake) || - command_add("cast", nullptr,0, command_castspell) || command_add("castspell", "[spellid] - Cast a spell", 50, command_castspell) || command_add("chat", "[channel num] [message] - Send a channel message to all zones", 200, command_chat) || command_add("checklos", "- Check for line of sight to your target", 50, command_checklos) || - command_add("close_shop", nullptr, 100, command_merchantcloseshop) || - command_add("connectworld", nullptr,0, command_connectworldserver) || + command_add("clearinvsnapshots", "[use rule] - Clear inventory snapshot history (true - elapsed entries, false - all entries)", 200, command_clearinvsnapshots) || command_add("connectworldserver", "- Make zone attempt to connect to worldserver", 200, command_connectworldserver) || command_add("corpse", "- Manipulate corpses, use with no arguments for help", 50, command_corpse) || - command_add("crashtest", "- Crash the zoneserver", 255, command_crashtest) || - command_add("cvs", "- Summary of client versions currently online.", 200, command_cvs) || + command_add("crashtest", "- Crash the zoneserver", 255, command_crashtest) || + command_add("cvs", "- Summary of client versions currently online.", 200, command_cvs) || command_add("damage", "[amount] - Damage your target", 100, command_damage) || command_add("date", "[yyyy] [mm] [dd] [HH] [MM] - Set EQ time", 90, command_date) || - command_add("dbspawn", nullptr,10, command_npctypespawn) || command_add("dbspawn2", "[spawngroup] [respawn] [variance] - Spawn an NPC from a predefined row in the spawn2 table", 100, command_dbspawn2) || command_add("delacct", "[accountname] - Delete an account", 150, command_delacct) || command_add("deletegraveyard", "[zone name] - Deletes the graveyard for the specified zone.", 200, command_deletegraveyard) || @@ -207,8 +195,7 @@ int command_init(void) { command_add("enablerecipe", "[recipe_id] - Enables a recipe using the recipe id.", 80, command_enablerecipe) || command_add("equipitem", "[slotid(0-21)] - Equip the item on your cursor into the specified slot", 50, command_equipitem) || command_add("face", "- Change the face of your target", 80, command_face) || - command_add("fi", nullptr,10, command_itemsearch) || - command_add("finditem", nullptr,10, command_itemsearch) || + command_add("findaliases", "[search term]- Searches for available command aliases, by alias or command", 0, command_findaliases) || command_add("findnpctype", "[search criteria] - Search database NPC types", 100, command_findnpctype) || command_add("findspell", "[searchstring] - Search for a spell", 50, command_findspell) || command_add("findzone", "[search criteria] - Search database zones", 100, command_findzone) || @@ -221,15 +208,13 @@ int command_init(void) { command_add("freeze", "- Freeze your target", 80, command_freeze) || command_add("gassign", "[id] - Assign targetted NPC to predefined wandering grid id", 100, command_gassign) || command_add("gender", "[0/1/2] - Change your or your target's gender to male/female/neuter", 50, command_gender) || - command_add("getplayerburriedcorpsecount", "- Get the target's total number of burried player corpses.", 100, command_getplayerburriedcorpsecount) || + command_add("getplayerburiedcorpsecount", "- Get the target's total number of buried player corpses.", 100, command_getplayerburiedcorpsecount) || command_add("getvariable", "[varname] - Get the value of a variable from the database", 200, command_getvariable) || - command_add("gi", nullptr,200, command_giveitem) || command_add("ginfo", "- get group info on target.", 20, command_ginfo) || command_add("giveitem", "[itemid] [charges] - Summon an item onto your target's cursor. Charges are optional.", 200, command_giveitem) || command_add("givemoney", "[pp] [gp] [sp] [cp] - Gives specified amount of money to the target player.", 200, command_givemoney) || command_add("globalview", "Lists all qglobals in cache if you were to do a quest with this target.", 80, command_globalview) || command_add("gm", "- Turn player target's or your GM flag on or off", 80, command_gm) || - command_add("gmhideme", nullptr,0, command_hideme) || command_add("gmspeed", "[on/off] - Turn GM speed hack on/off for you or your player target", 100, command_gmspeed) || command_add("goto", "[x] [y] [z] - Teleport to the provided coordinates or to your target", 10, command_goto) || command_add("grid", "[add/delete] [grid_num] [wandertype] [pausetype] - Create/delete a wandering grid", 170, command_grid) || @@ -237,7 +222,6 @@ int command_init(void) { command_add("guildapprove", "[guildapproveid] - Approve a guild with specified ID (guild creator receives the id)", 0, command_guildapprove) || command_add("guildcreate", "[guildname] - Creates an approval setup for guild name specified", 0, command_guildcreate) || command_add("guildlist", "[guildapproveid] - Lists character names who have approved the guild specified by the approve id", 0, command_guildlist) || - command_add("guilds", nullptr,0, command_guild) || command_add("hair", "- Change the hair style of your target", 80, command_hair) || command_add("haircolor", "- Change the hair color of your target", 80, command_haircolor) || command_add("haste", "[percentage] - Set your haste percentage", 100, command_haste) || @@ -248,14 +232,14 @@ int command_init(void) { command_add("heritage", "- Change the heritage of your target (Drakkin Only)", 80, command_heritage) || command_add("heromodel", "[hero model] [slot] - Full set of Hero's Forge Armor appearance. If slot is set, sends exact model just to slot.", 200, command_heromodel) || command_add("hideme", "[on/off] - Hide yourself from spawn lists.", 80, command_hideme) || - command_add("hm", "[hero model] [slot] - Full set of Hero's Forge Armor appearance. If slot is set, sends exact model just to slot.)", 200, command_heromodel) || + command_add("hotfix", "[hotfix_name] - Reloads shared memory into a hotfix, equiv to load_shared_memory followed by apply_shared_memory", 250, command_hotfix) || command_add("hp", "- Refresh your HP bar from the server.", 0, command_hp) || command_add("incstat", "- Increases or Decreases a client's stats permanently.", 200, command_incstat) || command_add("instance", "- Modify Instances", 200, command_instance) || command_add("interrogateinv", "- use [help] argument for available options", 0, command_interrogateinv) || command_add("interrupt", "[message id] [color] - Interrupt your casting. Arguments are optional.", 50, command_interrupt) || - command_add("invul", nullptr,0, command_invul) || - command_add("invulnerable", "[on/off] - Turn player target's or your invulnerable flag on or off", 80, command_invul) || + command_add("invsnapshot", "- Takes an inventory snapshot of your current target", 80, command_invsnapshot) || + command_add("invul", "[on/off] - Turn player target's or your invulnerable flag on or off", 80, command_invul) || command_add("ipban", "[IP address] - Ban IP by character name", 200, command_ipban) || command_add("iplookup", "[charname] - Look up IP address of charname", 200, command_iplookup) || command_add("iteminfo", "- Get information about the item on your cursor", 10, command_iteminfo) || @@ -266,15 +250,14 @@ int command_init(void) { command_add("level", "[level] - Set your or your target's level", 10, command_level) || command_add("listnpcs", "[name/range] - Search NPCs", 20, command_listnpcs) || command_add("listpetition", "- List petitions", 50, command_listpetition) || + command_add("load_shared_memory", "[shared_memory_name] - Reloads shared memory and uses the input as output", 250, command_load_shared_memory) || command_add("loc", "- Print out your or your target's current location and heading", 0, command_loc) || command_add("lock", "- Lock the worldserver", 150, command_lock) || command_add("logs", "Manage anything to do with logs", 250, command_logs) || command_add("logtest", "Performs log performance testing.", 250, command_logtest) || - command_add("los", nullptr,0, command_checklos) || command_add("makepet", "[level] [class] [race] [texture] - Make a pet", 50, command_makepet) || command_add("mana", "- Fill your or your target's mana", 50, command_mana) || - command_add("manaburn", "- Use AA Wizard class skill manaburn on target", 10, command_manaburn) || - command_add("maxskills", "Maxes skills for you.", 200, command_max_all_skills) || + command_add("maxskills", "Maxes skills for you.", 200, command_max_all_skills) || command_add("memspell", "[slotid] [spellid] - Memorize spellid in the specified slot", 50, command_memspell) || command_add("merchant_close_shop", "Closes a merchant shop", 100, command_merchantcloseshop) || command_add("merchant_open_shop", "Opens a merchants shop", 100, command_merchantopenshop) || @@ -283,7 +266,7 @@ int command_init(void) { command_add("movechar", "[charname] [zonename] - Move charname to zonename", 50, command_movechar) || command_add("myskills", "- Show details about your current skill levels", 0, command_myskills) || command_add("mysqltest", "Akkadius MySQL Bench Test", 250, command_mysqltest) || - command_add("mysql", "Mysql CLI, see 'help' for options.", 250, command_mysql) || + command_add("mysql", "Mysql CLI, see 'help' for options.", 250, command_mysql) || command_add("mystats", "- Show details about you or your pet", 50, command_mystats) || command_add("name", "[newname] - Rename your player target", 150, command_name) || command_add("netstats", "- Gets the network stats for a stream.", 200, command_netstats) || @@ -294,8 +277,6 @@ int command_init(void) { command_add("npcsay", "[message] - Make your NPC target say a message.", 150, command_npcsay) || command_add("npcshout", "[message] - Make your NPC target shout a message.", 150, command_npcshout) || command_add("npcspawn", "[create/add/update/remove/delete] - Manipulate spawn DB", 170, command_npcspawn) || - command_add("npcspecialatk", nullptr,0, command_npcspecialattk) || - command_add("npcspecialattack", nullptr,0, command_npcspecialattk) || command_add("npcspecialattk", "[flagchar] [perm] - Set NPC special attack flags. Flags are E(nrage) F(lurry) R(ampage) S(ummon).", 80, command_npcspecialattk) || command_add("npcstats", "- Show stats about target NPC", 80, command_npcstats) || command_add("npctype_cache", "[id] or all - Clears the npc type cache for either the id or all npcs.", 250, command_npctype_cache) || @@ -305,7 +286,11 @@ int command_init(void) { command_add("object", "List|Add|Edit|Move|Rotate|Copy|Save|Undo|Delete - Manipulate static and tradeskill objects within the zone", 100, command_object) || command_add("oocmute", "[1/0] - Mutes OOC chat", 200, command_oocmute) || command_add("opcode", "- opcode management", 250, command_opcode) || - command_add("open_shop", nullptr, 100, command_merchantopenshop) || + +#ifdef PACKET_PROFILER + command_add("packetprofile", "- Dump packet profile for target or self.", 250, command_packetprofile) || +#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("peqzone", "[zonename] - Go to specified zone, if you have > 75% health", 0, command_peqzone) || @@ -315,46 +300,48 @@ int command_init(void) { command_add("petitioninfo", "[petition number] - Get info about a petition", 20, command_petitioninfo) || command_add("pf", "- Display additional mob coordinate and wandering data", 0, command_pf) || command_add("picklock", "Analog for ldon pick lock for the newer clients since we still don't have it working.", 0, command_picklock) || + +#ifdef EQPROFILE + command_add("profiledump", "- Dump profiling info to logs", 250, command_profiledump) || + command_add("profilereset", "- Reset profiling info", 250, command_profilereset) || +#endif + 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) || + command_add("questerrors", "Shows quest errors.", 100, command_questerrors) || command_add("race", "[racenum] - Change your or your target's race. Use racenum 0 to return to normal", 50, command_race) || command_add("raidloot", "LEADER|GROUPLEADER|SELECTED|ALL - Sets your raid loot settings if you have permission to do so.", 0, command_raidloot) || command_add("randomfeatures", "- Temporarily randomizes the Facial Features of your target", 80, command_randomfeatures) || command_add("refreshgroup", "- Refreshes Group.", 0, command_refreshgroup) || + command_add("reloadaa", "Reloads AA data", 200, command_reloadaa) || 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("reloadlevelmods", nullptr, 255, command_reloadlevelmods) || + 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("reloadquest", " - 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) || command_add("reloadstatic", "- Reload Static Zone Data", 150, command_reloadstatic) || command_add("reloadtitles", "- Reload player titles from the database", 150, command_reloadtitles) || command_add("reloadworld", "[0|1] - Clear quest cache (0 - no repop, 1 - repop)", 255, command_reloadworld) || - command_add("reloadzonepoints", "- Reload zone points from database", 150, command_reloadzps) || - command_add("reloadzps", nullptr,0, command_reloadzps) || + command_add("reloadzps", "- Reload zone points from database", 150, command_reloadzps) || command_add("repop", "[delay] - Repop the zone with optional delay", 100, command_repop) || - command_add("resetaa", "- Resets a Player's AA in their profile and refunds spent AA's to unspent, disconnects player.", 200, command_resetaa) || + command_add("repopclose", "[distance in units] Repops only NPC's nearby for fast development purposes", 100, command_repopclose) || + command_add("resetaa", "- Resets a Player's AA in their profile and refunds spent AA's to unspent, may disconnect player.", 200, command_resetaa) || + command_add("resetaa_timer", "Command to reset AA cooldown timers.", 200, command_resetaa_timer) || command_add("revoke", "[charname] [1/0] - Makes charname unable to talk on OOC", 200, command_revoke) || - command_add("rules", "(subcommand) - Manage server rules", 250, command_rules) || + command_add("rules", "(subcommand) - Manage server rules", 250, command_rules) || command_add("save", "- Force your player or player corpse target to be saved to the database", 50, command_save) || - command_add("scribespell", "[spellid] - Scribe specified spell in your target's spell book.", 180, command_scribespell) || + command_add("scribespell", "[spellid] - Scribe specified spell in your target's spell book.", 180, command_scribespell) || command_add("scribespells", "[max level] [min level] - Scribe all spells for you or your player target that are usable by them, up to level specified. (may freeze client for a few seconds)", 150, command_scribespells) || - command_add("search", nullptr,10, command_itemsearch) || command_add("sendzonespawns", "- Refresh spawn list for all clients in zone", 150, command_sendzonespawns) || command_add("sensetrap", "Analog for ldon sense trap for the newer clients since we still don't have it working.", 0, command_sensetrap) || command_add("serverinfo", "- Get OS info about server host", 200, command_serverinfo) || command_add("serverrules", "- Read this server's rules", 0, command_serverrules) || - command_add("setaaexp", nullptr,0, command_setaaxp) || - command_add("setaapoints", nullptr,0, command_setaapts) || command_add("setaapts", "[value] - Set your or your player target's available AA points", 100, command_setaapts) || command_add("setaaxp", "[value] - Set your or your player target's AA experience", 100, command_setaaxp) || command_add("setadventurepoints", "- Set your or your player target's available adventure points", 150, command_set_adventure_points) || - command_add("setallskill", nullptr,0, command_setskillall) || - command_add("setallskills", nullptr,0, command_setskillall) || command_add("setanim", "[animnum] - Set target's appearance to animnum", 200, command_setanim) || command_add("setcrystals", "[value] - Set your or your player target's available radiant or ebon crystals", 100, command_setcrystals) || - command_add("setexp", nullptr,0, command_setxp) || command_add("setfaction", "[faction number] - Sets targeted NPC's faction in the database", 170, command_setfaction) || command_add("setgraveyard", "[zone name] - Creates a graveyard for the specified zone based on your target's LOC.", 200, command_setgraveyard) || command_add("setlanguage", "[language ID] [value] - Set your target's language skillnum to value", 50, command_setlanguage) || @@ -373,18 +360,16 @@ int command_init(void) { 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("shutdown", "- Shut this zone process down", 150, command_shutdown) || - command_add("si", nullptr,200, command_summonitem) || 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) || command_add("spawnfix", "- Find targeted NPC in database based on its X/Y/heading and update the database to make it spawn at your current location/heading.", 170, command_spawnfix) || command_add("spawnstatus", "- Show respawn timer status", 100, command_spawnstatus) || command_add("spellinfo", "[spellid] - Get detailed info about a spell", 10, command_spellinfo) || - command_add("spfind", nullptr,0, command_findspell) || command_add("spoff", "- Sends OP_ManaChange", 80, command_spoff) || command_add("spon", "- Sends OP_MemorizeSpell", 80, command_spon) || command_add("stun", "[duration] - Stuns you or your target for duration", 100, command_stun) || command_add("summon", "[charname] - Summons your player/npc/corpse target, or charname if specified", 80, command_summon) || - command_add("summonburriedplayercorpse", "- Summons the target's oldest burried corpse, if any exist.", 100, command_summonburriedplayercorpse) || + command_add("summonburiedplayercorpse", "- Summons the target's oldest buried corpse, if any exist.", 100, command_summonburiedplayercorpse) || command_add("summonitem", "[itemid] [charges] - Summon an item onto your cursor. Charges are optional.", 200, command_summonitem) || command_add("suspend", "[name] [days] [reason] - Suspend by character name and for specificed number of days", 150, command_suspend) || command_add("task", "(subcommand) - Task system commands", 150, command_task) || @@ -401,8 +386,10 @@ int command_init(void) { 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) || - command_add("unscribespell", "[spellid] - Unscribe specified spell from your target's spell book.", 180, command_unscribespell) || + command_add("unscribespell", "[spellid] - Unscribe specified spell from your target's spell book.", 180, command_unscribespell) || command_add("unscribespells", "- Clear out your or your player target's spell book.", 180, command_unscribespells) || + command_add("untraindisc", "[spellid] - Untrain specified discipline from your target.", 180, command_untraindisc) || + command_add("untraindiscs", "- Untrains all disciplines from your target.", 180, command_untraindiscs) || command_add("uptime", "[zone server id] - Get uptime of worldserver, or zone server if argument provided", 10, command_uptime) || command_add("version", "- Display current version of EQEmu server", 0, command_version) || command_add("viewnpctype", "[npctype id] - Show info about an npctype", 100, command_viewnpctype) || @@ -429,29 +416,43 @@ int command_init(void) { command_add("zsave", " - Saves zheader to the database", 80, command_zsave) || command_add("zsky", "[skytype] - Change zone sky type", 80, command_zsky) || command_add("zstats", "- Show info about zone header", 80, command_zstats) || - command_add("zunderworld", "[zcoord] - Sets the underworld using zcoord", 80, command_zunderworld) || + command_add("zunderworld", "[zcoord] - Sets the underworld using zcoord", 80, command_zunderworld) || command_add("zuwcoords", "[z coord] - Set underworld coord", 80, command_zuwcoords) - ) - { + ) { command_deinit(); return -1; } - - std::map::iterator cur,end; - cur = commandlist.begin(); - end = commandlist.end(); - std::map command_settings; - std::map::iterator itr; + + std::map>> command_settings; database.GetCommandSettings(command_settings); - for(; cur != end; ++cur) { - if ((itr=command_settings.find(cur->first))!=command_settings.end()) { - cur->second->access = itr->second; - Log.Out(Logs::General, Logs::Commands, "command_init(): - Command '%s' set to access level %d.", cur->first.c_str(), itr->second); + + std::map working_cl = commandlist; + for (auto iter_cl = working_cl.begin(); iter_cl != working_cl.end(); ++iter_cl) { + auto iter_cs = command_settings.find(iter_cl->first); + if (iter_cs == command_settings.end()) { + if (iter_cl->second->access == 0) + Log.Out(Logs::General, Logs::Commands, "command_init(): Warning: Command '%s' defaulting to access level 0!", iter_cl->first.c_str()); + continue; } - else - { - if(cur->second->access == 0) - Log.Out(Logs::General, Logs::Commands, "command_init(): Warning: Command '%s' defaulting to access level 0!" , cur->first.c_str()); + + iter_cl->second->access = iter_cs->second.first; + Log.Out(Logs::General, Logs::Commands, "command_init(): - Command '%s' set to access level %d.", iter_cl->first.c_str(), iter_cs->second.first); + if (iter_cs->second.second.empty()) + continue; + + for (auto iter_aka = iter_cs->second.second.begin(); iter_aka != iter_cs->second.second.end(); + ++iter_aka) { + if (iter_aka->empty()) + continue; + if (commandlist.find(*iter_aka) != commandlist.end()) { + Log.Out(Logs::General, Logs::Commands, "command_init(): Warning: Alias '%s' already exists as a command - skipping!", iter_aka->c_str()); + continue; + } + + commandlist[*iter_aka] = iter_cl->second; + commandaliases[*iter_aka] = iter_cl->first; + + Log.Out(Logs::General, Logs::Commands, "command_init(): - Alias '%s' added to command '%s'.", iter_aka->c_str(), commandaliases[*iter_aka].c_str()); } } @@ -471,6 +472,7 @@ int command_init(void) { void command_deinit(void) { commandlist.clear(); + commandaliases.clear(); command_dispatch = command_notavail; commandcount = 0; @@ -481,53 +483,43 @@ void command_deinit(void) * adds a command to the command list; used by command_init * * Parameters: - * command_string - the command ex: "spawn" - * desc - text description of command for #help - * access - default access level required to use command + * command_name - the command ex: "spawn" + * desc - text description of command for #help + * access - default access level required to use command * function - pointer to function that handles command * */ -int command_add(const char *command_string, const char *desc, int access, CmdFuncPtr function) +int command_add(std::string command_name, const char *desc, int access, CmdFuncPtr function) { - if(function == nullptr) - return(-1); - - std::string cstr(command_string); - - if(commandlist.count(cstr) != 0) { - Log.Out(Logs::General, Logs::Error, "command_add() - Command '%s' is a duplicate - check command.cpp." , command_string); - return(-1); + if (command_name.empty()) { + Log.Out(Logs::General, Logs::Error, "command_add() - Command added with empty name string - check command.cpp."); + return -1; + } + if (function == nullptr) { + Log.Out(Logs::General, Logs::Error, "command_add() - Command '%s' added without a valid function pointer - check command.cpp.", command_name.c_str()); + return -1; + } + if (commandlist.count(command_name) != 0) { + Log.Out(Logs::General, Logs::Error, "command_add() - Command '%s' is a duplicate command name - check command.cpp.", command_name.c_str()); + return -1; + } + for (auto iter = commandlist.begin(); iter != commandlist.end(); ++iter) { + if (iter->second->function != function) + continue; + Log.Out(Logs::General, Logs::Error, "command_add() - Command '%s' equates to an alias of '%s' - check command.cpp.", command_name.c_str(), iter->first.c_str()); + return -1; } - //look for aliases... - std::map::iterator cur,end,del; - cur = commandlist.begin(); - end = commandlist.end(); - for(; cur != end; ++cur) { - if(cur->second->function == function) { - int r; - for(r = 1; r < CMDALIASES; r++) { - if(cur->second->command[r] == nullptr) { - cur->second->command[r] = command_string; - break; - } - } - commandlist[cstr] = cur->second; - return(0); - } - } - - CommandRecord *c = new CommandRecord; - cleanup_commandlist.Append(c); - c->desc = desc; + auto c = new CommandRecord; c->access = access; + c->desc = desc; c->function = function; - memset(c->command, 0, sizeof(c->command)); - c->command[0] = command_string; - - commandlist[cstr] = c; + commandlist[command_name] = c; + commandaliases[command_name] = command_name; + cleanup_commandlist.Append(c); commandcount++; + return 0; } @@ -639,8 +631,8 @@ void command_logcommand(Client *c, const char *message) c->AccountName(), c->AccountID(), admin,c->GetName(), - c->GetTarget()?c->GetTarget()->GetName():"None", - "Command", + c->GetTarget()?c->GetTarget()->GetName():"None", + "Command", message, 1 ); @@ -673,8 +665,8 @@ void command_incstat(Client* c, const Seperator* sep){ } } -void command_resetaa(Client* c,const Seperator *sep){ - if(c->GetTarget()!=0 && c->GetTarget()->IsClient()){ +void command_resetaa(Client* c,const Seperator *sep) { + if(c->GetTarget() && c->GetTarget()->IsClient()){ c->GetTarget()->CastToClient()->ResetAA(); c->Message(13,"Successfully reset %s's AAs", c->GetTarget()->GetName()); } @@ -726,7 +718,7 @@ void command_setfaction(Client *c, const Seperator *sep) auto npcTypeID = c->GetTarget()->CastToNPC()->GetNPCTypeID(); c->Message(15,"Setting NPC %u to faction %i", npcTypeID, atoi(sep->argplus[1])); - std::string query = StringFormat("UPDATE npc_types SET npc_faction_id = %i WHERE id = %i", + std::string query = StringFormat("UPDATE npc_types SET npc_faction_id = %i WHERE id = %i", atoi(sep->argplus[1]), npcTypeID); database.QueryDatabase(query); } @@ -866,9 +858,9 @@ char buffer[255]; void command_getvariable(Client *c, const Seperator *sep) { - char tmp[512]; - if (database.GetVariable(sep->argplus[1], tmp, sizeof(tmp))) - c->Message(0, "%s = %s", sep->argplus[1], tmp); + std::string tmp; + if (database.GetVariable(sep->argplus[1], tmp)) + c->Message(0, "%s = %s", sep->argplus[1], tmp.c_str()); else c->Message(0, "GetVariable(%s) returned false", sep->argplus[1]); } @@ -1005,7 +997,7 @@ void command_summon(Client *c, const Seperator *sep) //c->Message(0, "Summoning player from another zone not yet implemented."); //return; - ServerPacket* pack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct)); + auto pack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct)); ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*) pack->pBuffer; strcpy(szp->adminname, c->GetName()); szp->adminrank = c->Admin(); @@ -1369,7 +1361,7 @@ void command_date(Client *c, const Seperator *sep) else { int h=0, m=0; TimeOfDay_Struct eqTime; - zone->zone_time.getEQTimeOfDay( time(0), &eqTime); + zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime); if(!sep->IsNumber(4)) h=eqTime.hour; else @@ -1400,9 +1392,9 @@ void command_timezone(Client *c, const Seperator *sep) database.SetZoneTZ(zone->GetZoneID(), zone->GetInstanceVersion(), ntz); // Update all clients with new TZ. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); + auto outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer; - zone->zone_time.getEQTimeOfDay(time(0), tod); + zone->zone_time.GetCurrentEQTimeOfDay(time(0), tod); entity_list.QueueClients(c, outapp); safe_delete(outapp); } @@ -1484,7 +1476,7 @@ void command_npcstats(Client *c, const Seperator *sep) c->Message(0, "Current HP: %i Max HP: %i", c->GetTarget()->GetHP(), c->GetTarget()->GetMaxHP()); //c->Message(0, "Weapon Item Number: %s", c->GetTarget()->GetWeapNo()); c->Message(0, "Gender: %i Size: %f Bodytype: %d", c->GetTarget()->GetGender(), c->GetTarget()->GetSize(), c->GetTarget()->GetBodyType()); - c->Message(0, "Runspeed: %f Walkspeed: %f", c->GetTarget()->GetRunspeed(), c->GetTarget()->GetWalkspeed()); + c->Message(0, "Runspeed: %.3f Walkspeed: %.3f", static_cast(0.025f * c->GetTarget()->GetRunspeed()), static_cast(0.025f * c->GetTarget()->GetWalkspeed())); c->Message(0, "Spawn Group: %i Grid: %i", c->GetTarget()->CastToNPC()->GetSp2(), c->GetTarget()->CastToNPC()->GetGrid()); c->Message(0, "EmoteID: %i", c->GetTarget()->CastToNPC()->GetEmoteID()); c->GetTarget()->CastToNPC()->QueryLoot(c); @@ -1513,7 +1505,7 @@ void command_zclip(Client *c, const Seperator *sep) zone->newzone_data.fog_maxclip[0]=atof(sep->arg[5]); if(sep->arg[6][0]!=0) zone->newzone_data.fog_maxclip[1]=atof(sep->arg[6]); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); entity_list.QueueClients(c, outapp); safe_delete(outapp); @@ -1627,7 +1619,7 @@ void command_weather(Client *c, const Seperator *sep) if(sep->arg[2][0] != 0 && sep->arg[3][0] != 0) { c->Message(0, "Sending weather packet... TYPE=%s, INTENSITY=%s", sep->arg[2], sep->arg[3]); zone->zone_weather = atoi(sep->arg[2]); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weather, 8); + auto outapp = new EQApplicationPacket(OP_Weather, 8); outapp->pBuffer[0] = atoi(sep->arg[2]); outapp->pBuffer[4] = atoi(sep->arg[3]); // This number changes in the packets, intensity? entity_list.QueueClients(c, outapp); @@ -1640,7 +1632,7 @@ void command_weather(Client *c, const Seperator *sep) else if(sep->arg[1][0] == '2') { entity_list.Message(0, 0, "Snowflakes begin to fall from the sky."); zone->zone_weather = 2; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weather, 8); + auto outapp = new EQApplicationPacket(OP_Weather, 8); outapp->pBuffer[0] = 0x01; outapp->pBuffer[4] = 0x02; // This number changes in the packets, intensity? entity_list.QueueClients(c, outapp); @@ -1649,7 +1641,7 @@ void command_weather(Client *c, const Seperator *sep) else if(sep->arg[1][0] == '1') { entity_list.Message(0, 0, "Raindrops begin to fall from the sky."); zone->zone_weather = 1; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weather, 8); + auto outapp = new EQApplicationPacket(OP_Weather, 8); outapp->pBuffer[4] = 0x01; // This is how it's done in Fear, and you can see a decent distance with it at this value entity_list.QueueClients(c, outapp); safe_delete(outapp); @@ -1659,7 +1651,7 @@ void command_weather(Client *c, const Seperator *sep) if(zone->zone_weather == 1) { // Doing this because if you have rain/snow on, you can only turn one off. entity_list.Message(0, 0, "The sky clears as the rain ceases to fall."); zone->zone_weather = 0; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weather, 8); + auto outapp = new EQApplicationPacket(OP_Weather, 8); // To shutoff weather you send an empty 8 byte packet (You get this everytime you zone even if the sky is clear) entity_list.QueueClients(c, outapp); safe_delete(outapp); @@ -1667,7 +1659,7 @@ void command_weather(Client *c, const Seperator *sep) else if(zone->zone_weather == 2) { entity_list.Message(0, 0, "The sky clears as the snow stops falling."); zone->zone_weather = 0; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weather, 8); + auto outapp = new EQApplicationPacket(OP_Weather, 8); // To shutoff weather you send an empty 8 byte packet (You get this everytime you zone even if the sky is clear) outapp->pBuffer[0] = 0x01; // Snow has it's own shutoff packet entity_list.QueueClients(c, outapp); @@ -1676,7 +1668,7 @@ void command_weather(Client *c, const Seperator *sep) else { entity_list.Message(0, 0, "The sky clears."); zone->zone_weather = 0; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weather, 8); + auto outapp = new EQApplicationPacket(OP_Weather, 8); // To shutoff weather you send an empty 8 byte packet (You get this everytime you zone even if the sky is clear) entity_list.QueueClients(c, outapp); safe_delete(outapp); @@ -1698,7 +1690,7 @@ void command_zheader(Client *c, const Seperator *sep) c->Message(0, "Successfully loaded zone header for %s from database.", sep->argplus[1]); else c->Message(0, "Failed to load zone header %s from database", sep->argplus[1]); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); entity_list.QueueClients(c, outapp); safe_delete(outapp); @@ -1714,7 +1706,7 @@ void command_zsky(Client *c, const Seperator *sep) c->Message(0, "ERROR: Sky type can not be less than 0 or greater than 255!"); else { zone->newzone_data.sky = atoi(sep->arg[1]); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); entity_list.QueueClients(c, outapp); safe_delete(outapp); @@ -1738,7 +1730,7 @@ void command_zcolor(Client *c, const Seperator *sep) zone->newzone_data.fog_green[z] = atoi(sep->arg[2]); zone->newzone_data.fog_blue[z] = atoi(sep->arg[3]); } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); entity_list.QueueClients(c, outapp); safe_delete(outapp); @@ -1752,7 +1744,7 @@ void command_spon(Client *c, const Seperator *sep) void command_spoff(Client *c, const Seperator *sep) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ManaChange, 0); + auto outapp = new EQApplicationPacket(OP_ManaChange, 0); outapp->priority = 5; c->QueuePacket(outapp); safe_delete(outapp); @@ -1771,7 +1763,7 @@ void command_itemtest(Client *c, const Seperator *sep) fread(chBuffer, sizeof(chBuffer), sizeof(char), f); fclose(f); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ItemLinkResponse, strlen(chBuffer)+5); + auto outapp = new EQApplicationPacket(OP_ItemLinkResponse, strlen(chBuffer) + 5); memcpy(&outapp->pBuffer[4], chBuffer, strlen(chBuffer)); c->QueuePacket(outapp); safe_delete(outapp); @@ -1894,7 +1886,7 @@ void command_worldshutdown(Client *c, const Seperator *sep) if(sep->IsNumber(1) && sep->IsNumber(2) && ((time=atoi(sep->arg[1]))>0) && ((interval=atoi(sep->arg[2]))>0)) { worldserver.SendEmoteMessage(0,0,15,":SYSTEM MSG:World coming down in %i minutes, everyone log out before this time.", (time / 60 )); c->Message(0, "Sending shutdown packet now, World will shutdown in: %i minutes with an interval of: %i seconds", (time / 60), interval); - ServerPacket* pack = new ServerPacket(ServerOP_ShutdownAll,sizeof(WorldShutDown_Struct)); + auto pack = new ServerPacket(ServerOP_ShutdownAll, sizeof(WorldShutDown_Struct)); WorldShutDown_Struct* wsd = (WorldShutDown_Struct*)pack->pBuffer; wsd->time=time*1000; wsd->interval=(interval*1000); @@ -1904,7 +1896,7 @@ void command_worldshutdown(Client *c, const Seperator *sep) else if(strcasecmp(sep->arg[1], "now") == 0){ worldserver.SendEmoteMessage(0,0,15,":SYSTEM MSG:World coming down, everyone log out now."); c->Message(0, "Sending shutdown packet"); - ServerPacket* pack = new ServerPacket; + auto pack = new ServerPacket; pack->opcode = ServerOP_ShutdownAll; pack->size=0; worldserver.SendPacket(pack); @@ -1912,7 +1904,7 @@ void command_worldshutdown(Client *c, const Seperator *sep) } else if(strcasecmp(sep->arg[1], "disable") == 0){ c->Message(0, "Shutdown prevented, next time I may not be so forgiving..."); - ServerPacket* pack = new ServerPacket(ServerOP_ShutdownAll,sizeof(WorldShutDown_Struct)); + auto pack = new ServerPacket(ServerOP_ShutdownAll, sizeof(WorldShutDown_Struct)); WorldShutDown_Struct* wsd = (WorldShutDown_Struct*)pack->pBuffer; wsd->time=0; wsd->interval=0; @@ -2001,7 +1993,7 @@ void command_setlsinfo(Client *c, const Seperator *sep) if(sep->argnum != 2) c->Message(0, "Format: #setlsinfo email password"); else { - ServerPacket* pack = new ServerPacket(ServerOP_LSAccountUpdate, sizeof(ServerLSAccountUpdate_Struct)); + auto pack = new ServerPacket(ServerOP_LSAccountUpdate, sizeof(ServerLSAccountUpdate_Struct)); ServerLSAccountUpdate_Struct* s = (ServerLSAccountUpdate_Struct *) pack->pBuffer; s->useraccountid = c->LSAccountID(); strn0cpy(s->useraccount, c->AccountName(), 30); @@ -2050,7 +2042,8 @@ void command_wp(Client *c, const Seperator *sep) void command_iplookup(Client *c, const Seperator *sep) { - ServerPacket* pack = new ServerPacket(ServerOP_IPLookup, sizeof(ServerGenericWorldQuery_Struct) + strlen(sep->argplus[1]) + 1); + auto pack = + new ServerPacket(ServerOP_IPLookup, sizeof(ServerGenericWorldQuery_Struct) + strlen(sep->argplus[1]) + 1); ServerGenericWorldQuery_Struct* s = (ServerGenericWorldQuery_Struct *) pack->pBuffer; strcpy(s->from, c->GetName()); s->admin = c->Admin(); @@ -2137,7 +2130,7 @@ void command_showskills(Client *c, const Seperator *sep) t=c->GetTarget()->CastToClient(); c->Message(0, "Skills for %s", t->GetName()); - for (SkillUseTypes i=Skill1HBlunt; i <= HIGHEST_SKILL; i=(SkillUseTypes)(i+1)) + for (EQEmu::skills::SkillType i = EQEmu::skills::Skill1HBlunt; i <= EQEmu::skills::HIGHEST_SKILL; i = (EQEmu::skills::SkillType)(i + 1)) c->Message(0, "Skill [%d] is at [%d] - %u", i, t->GetSkill(i), t->GetRawSkill(i)); } @@ -2206,14 +2199,14 @@ void command_castspell(Client *c, const Seperator *sep) else if (c->GetTarget() == 0) if(c->Admin() >= commandInstacast) - c->SpellFinished(spellid, 0, USE_ITEM_SPELL_SLOT, 0, -1, spells[spellid].ResistDiff); + c->SpellFinished(spellid, 0, EQEmu::CastingSlot::Item, 0, -1, spells[spellid].ResistDiff); else - c->CastSpell(spellid, 0, USE_ITEM_SPELL_SLOT, 0); + c->CastSpell(spellid, 0, EQEmu::CastingSlot::Item, 0); else if(c->Admin() >= commandInstacast) - c->SpellFinished(spellid, c->GetTarget(), 10, 0, -1, spells[spellid].ResistDiff); + c->SpellFinished(spellid, c->GetTarget(), EQEmu::CastingSlot::Item, 0, -1, spells[spellid].ResistDiff); else - c->CastSpell(spellid, c->GetTarget()->GetID(), USE_ITEM_SPELL_SLOT, 0); + c->CastSpell(spellid, c->GetTarget()->GetID(), EQEmu::CastingSlot::Item, 0); } } @@ -2285,20 +2278,20 @@ void command_setskill(Client *c, const Seperator *sep) c->Message(0, "Error: #setskill: Target must be a client."); } else if ( - !sep->IsNumber(1) || atoi(sep->arg[1]) < 0 || atoi(sep->arg[1]) > HIGHEST_SKILL || + !sep->IsNumber(1) || atoi(sep->arg[1]) < 0 || atoi(sep->arg[1]) > EQEmu::skills::HIGHEST_SKILL || !sep->IsNumber(2) || atoi(sep->arg[2]) < 0 || atoi(sep->arg[2]) > HIGHEST_CAN_SET_SKILL ) { c->Message(0, "Usage: #setskill skill x "); - c->Message(0, " skill = 0 to %d", HIGHEST_SKILL); + c->Message(0, " skill = 0 to %d", EQEmu::skills::HIGHEST_SKILL); c->Message(0, " x = 0 to %d", HIGHEST_CAN_SET_SKILL); } else { Log.Out(Logs::General, Logs::Normal, "Set skill request from %s, target:%s skill_id:%i value:%i", c->GetName(), c->GetTarget()->GetName(), atoi(sep->arg[1]), atoi(sep->arg[2]) ); int skill_num = atoi(sep->arg[1]); uint16 skill_value = atoi(sep->arg[2]); - if(skill_num < HIGHEST_SKILL) - c->GetTarget()->CastToClient()->SetSkill((SkillUseTypes)skill_num, skill_value); + if (skill_num <= EQEmu::skills::HIGHEST_SKILL) + c->GetTarget()->CastToClient()->SetSkill((EQEmu::skills::SkillType)skill_num, skill_value); } } @@ -2316,7 +2309,7 @@ void command_setskillall(Client *c, const Seperator *sep) if (c->Admin() >= commandSetSkillsOther || c->GetTarget()==c || c->GetTarget()==0) { Log.Out(Logs::General, Logs::Normal, "Set ALL skill request from %s, target:%s", c->GetName(), c->GetTarget()->GetName()); uint16 level = atoi(sep->arg[1]); - for(SkillUseTypes skill_num=Skill1HBlunt;skill_num <= HIGHEST_SKILL;skill_num=(SkillUseTypes)(skill_num+1)) { + for (EQEmu::skills::SkillType skill_num = EQEmu::skills::Skill1HBlunt; skill_num <= EQEmu::skills::HIGHEST_SKILL; skill_num = (EQEmu::skills::SkillType)(skill_num + 1)) { c->GetTarget()->CastToClient()->SetSkill(skill_num, level); } } @@ -2423,14 +2416,14 @@ void command_texture(Client *c, const Seperator *sep) // Player Races Wear Armor, so Wearchange is sent instead int i; if (!c->GetTarget()) - for (i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_TINT_END; i++) + for (i = EQEmu::textures::TextureBegin; i <= EQEmu::textures::LastTintableTexture; i++) { c->SendTextureWC(i, texture); } else if ((c->GetTarget()->GetRace() > 0 && c->GetTarget()->GetRace() <= 12) || c->GetTarget()->GetRace() == 128 || c->GetTarget()->GetRace() == 130 || c->GetTarget()->GetRace() == 330 || c->GetTarget()->GetRace() == 522) { - for (i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_TINT_END; i++) + for (i = EQEmu::textures::TextureBegin; i <= EQEmu::textures::LastTintableTexture; i++) { c->GetTarget()->SendTextureWC(i, texture); } @@ -2463,7 +2456,7 @@ void command_npctypespawn(Client *c, const Seperator *sep) const NPCType* tmp = 0; if ((tmp = database.LoadNPCTypesData(atoi(sep->arg[1])))) { //tmp->fixedZ = 1; - NPC* npc = new NPC(tmp, 0, c->GetPosition(), FlyMode3); + auto npc = new NPC(tmp, 0, c->GetPosition(), FlyMode3); if (npc && sep->IsNumber(2)) npc->SetNPCFactionID(atoi(sep->arg[2])); @@ -2553,55 +2546,55 @@ void command_peekinv(Client *c, const Seperator *sep) Client* targetClient = c->GetTarget()->CastToClient(); const ItemInst* inst_main = nullptr; const ItemInst* inst_sub = nullptr; - const Item_Struct* item_data = nullptr; + const EQEmu::ItemBase* item_data = nullptr; std::string item_link; - Client::TextLink linker; - linker.SetLinkType(linker.linkItemInst); + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemInst); c->Message(0, "Displaying inventory for %s...", targetClient->GetName()); // worn - for (int16 indexMain = EmuConstants::EQUIPMENT_BEGIN; (scopeWhere & peekWorn) && (indexMain <= EmuConstants::EQUIPMENT_END); ++indexMain) { + 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); item_link = linker.GenerateLink(); - c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i", + 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())); } - if ((scopeWhere & peekWorn) && (targetClient->GetClientVersion() >= ClientVersion::SoF)) { - inst_main = targetClient->GetInv().GetItem(MainPowerSource); + if ((scopeWhere & peekWorn) && (targetClient->ClientVersion() >= EQEmu::versions::ClientVersion::SoF)) { + inst_main = targetClient->GetInv().GetItem(EQEmu::legacy::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", - MainPowerSource, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); + c->Message((item_data == nullptr), "WornSlot: %i, Item: %i (%s), Charges: %i", + EQEmu::legacy::SlotPowerSource, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); } // inv - for (int16 indexMain = EmuConstants::GENERAL_BEGIN; (scopeWhere & peekInv) && (indexMain <= EmuConstants::GENERAL_END); ++indexMain) { + 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", + 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 = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + for (uint8 indexSub = SUB_INDEX_BEGIN; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++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", + c->Message((item_data == nullptr), " InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); } } @@ -2613,8 +2606,8 @@ void command_peekinv(Client *c, const Seperator *sep) item_link = linker.GenerateLink(); - c->Message(1, "CursorSlot: %i, Item: %i (%s), Charges: %i", - MainCursor, 0, item_link.c_str(), 0); + c->Message(1, "CursorSlot: %i, Item: %i (%s), Charges: %i", + EQEmu::legacy::SlotCursor, 0, item_link.c_str(), 0); } else { int cursorDepth = 0; @@ -2625,99 +2618,99 @@ void command_peekinv(Client *c, const Seperator *sep) item_link = linker.GenerateLink(); - c->Message((item_data == nullptr), "CursorSlot: %i, Depth: %i, Item: %i (%s), Charges: %i", - MainCursor, cursorDepth, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); + c->Message((item_data == nullptr), "CursorSlot: %i, Depth: %i, Item: %i (%s), Charges: %i", + EQEmu::legacy::SlotCursor, cursorDepth, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); - for (uint8 indexSub = SUB_BEGIN; (cursorDepth == 0) && inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + for (uint8 indexSub = SUB_INDEX_BEGIN; (cursorDepth == 0) && inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++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), " CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", - Inventory::CalcSlotId(MainCursor, indexSub), MainCursor, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.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", + Inventory::CalcSlotId(EQEmu::legacy::SlotCursor, indexSub), EQEmu::legacy::SlotCursor, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); } } } } // trib - for (int16 indexMain = EmuConstants::TRIBUTE_BEGIN; (scopeWhere & peekTrib) && (indexMain <= EmuConstants::TRIBUTE_END); ++indexMain) { + 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", + 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 = EmuConstants::BANK_BEGIN; (scopeWhere & peekBank) && (indexMain <= EmuConstants::BANK_END); ++indexMain) { + 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", + 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 = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + for (uint8 indexSub = SUB_INDEX_BEGIN; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++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", + c->Message((item_data == nullptr), " BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", Inventory::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 = EmuConstants::SHARED_BANK_BEGIN; (scopeWhere & peekBank) && (indexMain <= EmuConstants::SHARED_BANK_END); ++indexMain) { + 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", + + 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 = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + for (uint8 indexSub = SUB_INDEX_BEGIN; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++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", + c->Message((item_data == nullptr), " SharedBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", Inventory::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 = EmuConstants::TRADE_BEGIN; (scopeWhere & peekTrade) && (indexMain <= EmuConstants::TRADE_END); ++indexMain) { + 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", + 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 = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + for (uint8 indexSub = SUB_INDEX_BEGIN; inst_main && inst_main->IsClassBag() && (indexSub < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++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", + c->Message((item_data == nullptr), " TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%s), Charges: %i", Inventory::CalcSlotId(indexMain, indexSub), indexMain, indexSub, ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())); } } @@ -2732,24 +2725,24 @@ void command_peekinv(Client *c, const Seperator *sep) else { c->Message(0, "[WorldObject DBID: %i (entityid: %i)]", objectTradeskill->GetDBID(), objectTradeskill->GetID()); - for (int16 indexMain = MAIN_BEGIN; indexMain < EmuConstants::MAP_WORLD_SIZE; ++indexMain) { + for (int16 indexMain = SLOT_BEGIN; 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", - (EmuConstants::WORLD_BEGIN + indexMain), ((item_data == nullptr) ? 0 : item_data->ID), item_link.c_str(), ((inst_main == nullptr) ? 0 : inst_main->GetCharges())); + 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 = SUB_BEGIN; inst_main && inst_main->IsType(ItemClassContainer) && (indexSub < EmuConstants::ITEM_CONTAINER_SIZE); ++indexSub) { + for (uint8 indexSub = SUB_INDEX_BEGIN; inst_main && inst_main->IsType(EQEmu::item::ItemClassBag) && (indexSub < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++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", + 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())); } } @@ -2825,6 +2818,36 @@ void command_interrogateinv(Client *c, const Seperator *sep) c->Message(13, "An unknown error occurred while processing Client::InterrogateInventory()"); } +void command_invsnapshot(Client *c, const Seperator *sep) +{ + auto t = c->GetTarget(); + if (!t || !t->IsClient()) { + c->Message(0, "Target must be a client"); + return; + } + + if (database.SaveCharacterInventorySnapshot(((Client*)t)->CharacterID())) { + c->SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM)); + c->Message(0, "Successful inventory snapshot taken of %s", t->GetName()); + } + else { + c->SetNextInvSnapshot(RuleI(Character, InvSnapshotMinRetryM)); + c->Message(0, "Failed to take inventory snapshot of %s", t->GetName()); + } +} + +void command_clearinvsnapshots(Client *c, const Seperator *sep) +{ + if (strcmp(sep->arg[1], "false") == 0) { + database.ClearInvSnapshots(false); + c->Message(0, "Inventory snapshots cleared using current time"); + } + else { + database.ClearInvSnapshots(); + c->Message(0, "Inventory snapshots cleared using RuleI(Character, InvSnapshotHistoryD) (%i days)", RuleI(Character, InvSnapshotHistoryD)); + } +} + void command_findnpctype(Client *c, const Seperator *sep) { if(sep->arg[1][0] == 0) { @@ -2880,12 +2903,13 @@ void command_findzone(Client *c, const Seperator *sep) std::string query; int id = atoi((const char *)sep->arg[1]); if (id == 0) { // If id evaluates to 0, then search as if user entered a string. - char *escName = new char[strlen(sep->arg[1]) * 2 + 1]; - database.DoEscapeString(escName, sep->arg[1], strlen(sep->arg[1])); + auto escName = new char[strlen(sep->arg[1]) * 2 + 1]; + database.DoEscapeString(escName, sep->arg[1], strlen(sep->arg[1])); - query = StringFormat("SELECT zoneidnumber, short_name, long_name FROM zone " - "WHERE long_name RLIKE '%s' AND version = 0", escName); - safe_delete_array(escName); + query = StringFormat("SELECT zoneidnumber, short_name, long_name FROM zone " + "WHERE long_name RLIKE '%s' AND version = 0", + escName); + safe_delete_array(escName); } else // Otherwise, look for just that zoneidnumber. query = StringFormat("SELECT zoneidnumber, short_name, long_name FROM zone " @@ -2963,7 +2987,7 @@ void command_reloadqst(Client *c, const Seperator *sep) void command_reloadworld(Client *c, const Seperator *sep) { c->Message(0, "Reloading quest cache and repopping zones worldwide."); - ServerPacket* pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); + auto pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); ReloadWorld_Struct* RW = (ReloadWorld_Struct*) pack->pBuffer; RW->Option = ((atoi(sep->arg[1]) == 1) ? 1 : 0); worldserver.SendPacket(pack); @@ -2996,7 +3020,7 @@ void command_zoneshutdown(Client *c, const Seperator *sep) else if (sep->arg[1][0] == 0) c->Message(0, "Usage: #zoneshutdown zoneshortname"); else { - ServerPacket* pack = new ServerPacket(ServerOP_ZoneShutdown, sizeof(ServerZoneStateChange_struct)); + auto pack = new ServerPacket(ServerOP_ZoneShutdown, sizeof(ServerZoneStateChange_struct)); ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer; strcpy(s->adminname, c->GetName()); if (sep->arg[1][0] >= '0' && sep->arg[1][0] <= '9') @@ -3016,7 +3040,7 @@ void command_zonebootup(Client *c, const Seperator *sep) c->Message(0, "Usage: #zonebootup ZoneServerID# zoneshortname"); } else { - ServerPacket* pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_struct)); + auto pack = new ServerPacket(ServerOP_ZoneBootup, sizeof(ServerZoneStateChange_struct)); ServerZoneStateChange_struct* s = (ServerZoneStateChange_struct *) pack->pBuffer; s->ZoneServerID = atoi(sep->arg[1]); strcpy(s->adminname, c->GetName()); @@ -3036,7 +3060,7 @@ void command_kick(Client *c, const Seperator *sep) if (client != 0) { if (client->Admin() <= c->Admin()) { client->Message(0, "You have been kicked by %s", c->GetName()); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMKick,0); + auto outapp = new EQApplicationPacket(OP_GMKick, 0); client->QueuePacket(outapp); client->Kick(); c->Message(0, "Kick: local: kicking %s", sep->arg[1]); @@ -3045,7 +3069,7 @@ void command_kick(Client *c, const Seperator *sep) else if (!worldserver.Connected()) c->Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); + auto pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer; strcpy(skp->adminname, c->GetName()); strcpy(skp->name, sep->arg[1]); @@ -3071,7 +3095,7 @@ void command_attack(Client *c, const Seperator *sep) void command_lock(Client *c, const Seperator *sep) { - ServerPacket* outpack = new ServerPacket(ServerOP_Lock, sizeof(ServerLock_Struct)); + auto outpack = new ServerPacket(ServerOP_Lock, sizeof(ServerLock_Struct)); ServerLock_Struct* lss = (ServerLock_Struct*) outpack->pBuffer; strcpy(lss->myname, c->GetName()); lss->mode = 1; @@ -3081,7 +3105,7 @@ void command_lock(Client *c, const Seperator *sep) void command_unlock(Client *c, const Seperator *sep) { - ServerPacket* outpack = new ServerPacket(ServerOP_Lock, sizeof(ServerLock_Struct)); + auto outpack = new ServerPacket(ServerOP_Lock, sizeof(ServerLock_Struct)); ServerLock_Struct* lss = (ServerLock_Struct*) outpack->pBuffer; strcpy(lss->myname, c->GetName()); lss->mode = 0; @@ -3091,7 +3115,7 @@ void command_unlock(Client *c, const Seperator *sep) void command_motd(Client *c, const Seperator *sep) { - ServerPacket* outpack = new ServerPacket(ServerOP_Motd, sizeof(ServerMotd_Struct)); + auto outpack = new ServerPacket(ServerOP_Motd, sizeof(ServerMotd_Struct)); ServerMotd_Struct* mss = (ServerMotd_Struct*) outpack->pBuffer; strn0cpy(mss->myname, c->GetName(),64); strn0cpy(mss->motd, sep->argplus[1],512); @@ -3120,16 +3144,16 @@ void command_listpetition(Client *c, const Seperator *sep) void command_equipitem(Client *c, const Seperator *sep) { uint32 slot_id = atoi(sep->arg[1]); - if (sep->IsNumber(1) && ((slot_id >= EmuConstants::EQUIPMENT_BEGIN) && (slot_id <= EmuConstants::EQUIPMENT_END) || (slot_id == MainPowerSource))) { - const ItemInst* from_inst = c->GetInv().GetItem(MainCursor); + if (sep->IsNumber(1) && ((slot_id >= EQEmu::legacy::EQUIPMENT_BEGIN) && (slot_id <= EQEmu::legacy::EQUIPMENT_END) || (slot_id == EQEmu::legacy::SlotPowerSource))) { + const ItemInst* from_inst = c->GetInv().GetItem(EQEmu::legacy::SlotCursor); const ItemInst* to_inst = c->GetInv().GetItem(slot_id); // added (desync issue when forcing stack to stack) bool partialmove = false; int16 movecount; - if (from_inst && from_inst->IsType(ItemClassCommon)) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct)); + if (from_inst && from_inst->IsClassCommon()) { + auto outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct)); MoveItem_Struct* mi = (MoveItem_Struct*)outapp->pBuffer; - mi->from_slot = MainCursor; + mi->from_slot = EQEmu::legacy::SlotCursor; mi->to_slot = slot_id; // mi->number_in_stack = from_inst->GetCharges(); // replaced with con check for stacking @@ -3151,6 +3175,7 @@ void command_equipitem(Client *c, const Seperator *sep) if (partialmove) { // remove this con check if someone can figure out removing charges from cursor stack issue below // mi->number_in_stack is always from_inst->GetCharges() when partialmove is false c->Message(13, "Error: Partial stack added to existing stack exceeds allowable stacksize"); + safe_delete(outapp); return; } else if(c->SwapItem(mi)) { @@ -3194,7 +3219,7 @@ void command_equipitem(Client *c, const Seperator *sep) void command_zonelock(Client *c, const Seperator *sep) { - ServerPacket* pack = new ServerPacket(ServerOP_LockZone, sizeof(ServerLockZone_Struct)); + auto pack = new ServerPacket(ServerOP_LockZone, sizeof(ServerLockZone_Struct)); ServerLockZone_Struct* s = (ServerLockZone_Struct*) pack->pBuffer; strn0cpy(s->adminname, c->GetName(), sizeof(s->adminname)); if (strcasecmp(sep->arg[1], "list") == 0) { @@ -3747,7 +3772,7 @@ void command_spellinfo(Client *c, const Seperator *sep) c->Message(0, " zonetype: %d", s->zonetype); c->Message(0, " EnvironmentType: %d", s->EnvironmentType); c->Message(0, " TimeOfDay: %d", s->TimeOfDay); - c->Message(0, " classes[15]: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", + c->Message(0, " classes[15]: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", s->classes[0], s->classes[1], s->classes[2], s->classes[3], s->classes[4], s->classes[5], s->classes[6], s->classes[7], s->classes[8], s->classes[9], s->classes[10], s->classes[11], s->classes[12], s->classes[13], s->classes[14]); @@ -3877,9 +3902,11 @@ void command_repop(Client *c, const Seperator *sep) LinkedListIterator iterator(zone->spawn2_list); iterator.Reset(); while (iterator.MoreElements()) { - std::string query = StringFormat("DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", - (unsigned long)iterator.GetData()->GetID(), - (unsigned long)zone->GetInstanceID()); + std::string query = StringFormat( + "DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", + (unsigned long)iterator.GetData()->GetID(), + (unsigned long)zone->GetInstanceID() + ); auto results = database.QueryDatabase(query); iterator.Advance(); } @@ -3896,6 +3923,33 @@ void command_repop(Client *c, const Seperator *sep) zone->Repop(atoi(sep->arg[timearg])*1000); } +void command_repopclose(Client *c, const Seperator *sep) +{ + int repop_distance = 500; + + if (sep->arg[1] && strcasecmp(sep->arg[1], "force") == 0) { + + LinkedListIterator iterator(zone->spawn2_list); + iterator.Reset(); + while (iterator.MoreElements()) { + std::string query = StringFormat( + "DELETE FROM respawn_times WHERE id = %lu AND instance_id = %lu", + (unsigned long)iterator.GetData()->GetID(), + (unsigned long)zone->GetInstanceID() + ); + auto results = database.QueryDatabase(query); + iterator.Advance(); + } + c->Message(0, "Zone depop: Force resetting spawn timers."); + } + if (sep->IsNumber(1)) { + repop_distance = atoi(sep->arg[1]); + } + + c->Message(0, "Zone depoped. Repopping NPC's within %i distance units", repop_distance); + zone->RepopClose(c->GetPosition(), repop_distance); +} + void command_spawnstatus(Client *c, const Seperator *sep) { if((sep->arg[1][0] == 'e') | (sep->arg[1][0] == 'E')) @@ -3944,7 +3998,7 @@ void command_zuwcoords(Client *c, const Seperator *sep) zone->newzone_data.underworld = atof(sep->arg[1]); //float newdata = atof(sep->arg[1]); //memcpy(&zone->zone_header_data[130], &newdata, sizeof(float)); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); entity_list.QueueClients(c, outapp); safe_delete(outapp); @@ -3976,7 +4030,7 @@ void command_zsafecoords(Client *c, const Seperator *sep) //memcpy(&zone->zone_header_data[118], &newdatay, sizeof(float)); //memcpy(&zone->zone_header_data[122], &newdataz, sizeof(float)); //zone->SetSafeCoords(); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); entity_list.QueueClients(c, outapp); safe_delete(outapp); @@ -4144,7 +4198,7 @@ void command_damage(Client *c, const Seperator *sep) if (nkdmg > 2100000000) c->Message(0, "Enter a value less then 2,100,000,000."); else - c->GetTarget()->Damage(c, nkdmg, SPELL_UNKNOWN, SkillHandtoHand, false); + c->GetTarget()->Damage(c, nkdmg, SPELL_UNKNOWN, EQEmu::skills::SkillHandtoHand, false); } } @@ -4251,7 +4305,7 @@ void command_spawnfix(Client *c, const Seperator *sep) { return; } - std::string query = StringFormat("UPDATE spawn2 SET x = '%f', y = '%f', z = '%f', heading = '%f' WHERE id = '%i'", + std::string query = StringFormat("UPDATE spawn2 SET x = '%f', y = '%f', z = '%f', heading = '%f' WHERE id = '%i'", c->GetX(), c->GetY(), c->GetZ(), c->GetHeading(),s2->GetID()); auto results = database.QueryDatabase(query); if (!results.Success()) { @@ -4284,16 +4338,20 @@ void command_goto(Client *c, const Seperator *sep) void command_iteminfo(Client *c, const Seperator *sep) { - auto inst = c->GetInv()[MainCursor]; - if (!inst) { c->Message(13, "Error: You need an item on your cursor for this command"); } + auto inst = c->GetInv()[EQEmu::legacy::SlotCursor]; + if (!inst) { + c->Message(13, "Error: You need an item on your cursor for this command"); + return; + } auto item = inst->GetItem(); if (!item) { Log.Out(Logs::General, Logs::Inventory, "(%s) Command #iteminfo processed an item with no data pointer"); c->Message(13, "Error: This item has no data reference"); + return; } - Client::TextLink linker; - linker.SetLinkType(linker.linkItemInst); + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemInst); linker.SetItemInst(inst); auto item_link = linker.GenerateLink(); @@ -4307,10 +4365,10 @@ void command_iteminfo(Client *c, const Seperator *sep) c->Message(0, ">> NoDrop: %u, NoRent: %u, NoPet: %u, NoTransfer: %u, FVNoDrop: %u", item->NoDrop, item->NoRent, (uint8)item->NoPet, (uint8)item->NoTransfer, item->FVNoDrop); - if (item->ItemClass == ItemClassBook) { + if (item->IsClassBook()) { c->Message(0, "*** This item is a Book (filename:'%s') ***", item->Filename); } - else if (item->ItemClass == ItemClassContainer) { + else if (item->IsClassBag()) { c->Message(0, "*** This item is a Container (%u slots) ***", item->BagSlots); } else { @@ -4335,7 +4393,7 @@ void command_uptime(Client *c, const Seperator *sep) c->Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_Uptime, sizeof(ServerUptime_Struct)); + auto pack = new ServerPacket(ServerOP_Uptime, sizeof(ServerUptime_Struct)); ServerUptime_Struct* sus = (ServerUptime_Struct*) pack->pBuffer; strcpy(sus->adminname, c->GetName()); if (sep->IsNumber(1) && atoi(sep->arg[1]) > 0) @@ -4348,8 +4406,14 @@ void command_uptime(Client *c, const Seperator *sep) void command_flag(Client *c, const Seperator *sep) { if(sep->arg[2][0] == 0) { - c->UpdateAdmin(); - c->Message(0, "Refreshed your admin flag from DB."); + if (!c->GetTarget() || (c->GetTarget() && c->GetTarget() == c)) { + c->UpdateAdmin(); + c->Message(0, "Refreshed your admin flag from DB."); + } else if (c->GetTarget() && c->GetTarget() != c && c->GetTarget()->IsClient()) { + c->GetTarget()->CastToClient()->UpdateAdmin(); + c->Message(0, "%s's admin flag has been refreshed.", c->GetTarget()->GetName()); + c->GetTarget()->Message(0, "%s refreshed your admin flag.", c->GetName()); + } } else if (!sep->IsNumber(1) || atoi(sep->arg[1]) < -2 || atoi(sep->arg[1]) > 255 || strlen(sep->arg[2]) == 0) c->Message(0, "Usage: #flag [status] [acctname]"); @@ -4369,7 +4433,7 @@ void command_flag(Client *c, const Seperator *sep) c->Message(0, "Unable to set GM Flag."); else { c->Message(0, "Set GM Flag on account."); - ServerPacket* pack = new ServerPacket(ServerOP_FlagUpdate, 6); + auto pack = new ServerPacket(ServerOP_FlagUpdate, 6); *((uint32*) pack->pBuffer) = database.GetAccountIDByName(sep->argplus[2]); *((int16*) &pack->pBuffer[4]) = atoi(sep->arg[1]); worldserver.SendPacket(pack); @@ -4393,12 +4457,12 @@ void command_time(Client *c, const Seperator *sep) else { c->Message(13, "To set the Time: #time HH [MM]"); TimeOfDay_Struct eqTime; - zone->zone_time.getEQTimeOfDay( time(0), &eqTime); - sprintf(timeMessage,"%02d:%s%d %s (Timezone: %ih %im)", + zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime); + sprintf(timeMessage,"%02d:%s%d %s (Timezone: %ih %im)", ((eqTime.hour - 1) % 12) == 0 ? 12 : ((eqTime.hour - 1) % 12), - (eqTime.minute < 10) ? "0" : "", + (eqTime.minute < 10) ? "0" : "", eqTime.minute, - (eqTime.hour >= 13) ? "pm" : "am", + (eqTime.hour >= 13) ? "pm" : "am", zone->zone_time.getEQTimeZoneHr(), zone->zone_time.getEQTimeZoneMin() ); @@ -4832,7 +4896,7 @@ void command_zonestatus(Client *c, const Seperator *sep) if (!worldserver.Connected()) c->Message(0, "Error: World server disconnected"); else { - ServerPacket* pack = new ServerPacket(ServerOP_ZoneStatus, strlen(c->GetName())+2); + auto pack = new ServerPacket(ServerOP_ZoneStatus, strlen(c->GetName()) + 2); memset(pack->pBuffer, (uint8) c->Admin(), 1); strcpy((char *) &pack->pBuffer[1], c->GetName()); worldserver.SendPacket(pack); @@ -4840,36 +4904,6 @@ void command_zonestatus(Client *c, const Seperator *sep) } } -void command_manaburn(Client *c, const Seperator *sep) -{ - Mob* target=c->GetTarget(); - - if (c->GetTarget() == 0) - c->Message(0, "#Manaburn needs a target."); - else { - int cur_level=c->GetAA(MANA_BURN);//ManaBurn ID - if (DistanceSquared(c->GetPosition(), target->GetPosition()) > 200) - c->Message(0,"You are too far away from your target."); - else { - if(cur_level == 1) { - if(c->IsAttackAllowed(target)) - { - c->SetMana(0); - int nukedmg=(c->GetMana())*2; - if (nukedmg>0) - { - target->Damage(c, nukedmg, 2751, SkillAbjuration/*hackish*/); - c->Message(4,"You unleash an enormous blast of magical energies."); - } - Log.Out(Logs::General, Logs::Normal, "Manaburn request from %s, damage: %d", c->GetName(), nukedmg); - } - } - else - c->Message(0, "You have not learned this skill."); - } - } -} - void command_doanim(Client *c, const Seperator *sep) { if (!sep->IsNumber(1)) @@ -4929,6 +4963,38 @@ void command_face(Client *c, const Seperator *sep) } } +void command_findaliases(Client *c, const Seperator *sep) +{ + if (!sep->arg[1][0]) { + c->Message(0, "Usage: #findaliases [alias | command]"); + return; + } + + auto find_iter = commandaliases.find(sep->arg[1]); + if (find_iter == commandaliases.end()) { + c->Message(15, "No commands or aliases match '%s'", sep->arg[1]); + return; + } + + auto command_iter = commandlist.find(find_iter->second); + if (find_iter->second.empty() || command_iter == commandlist.end()) { + c->Message(0, "An unknown condition occurred..."); + return; + } + + c->Message(0, "Available command aliases for '%s':", command_iter->first.c_str()); + + int commandaliasesshown = 0; + for (auto alias_iter = commandaliases.begin(); alias_iter != commandaliases.end(); ++alias_iter) { + if (strcasecmp(find_iter->second.c_str(), alias_iter->second.c_str()) || c->Admin() < command_iter->second->access) + continue; + + c->Message(0, "%c%s", COMMAND_CHAR, alias_iter->first.c_str()); + ++commandaliasesshown; + } + c->Message(0, "%d command alias%s listed.", commandaliasesshown, commandaliasesshown != 1 ? "es" : ""); +} + void command_details(Client *c, const Seperator *sep) { Mob *target=c->GetTarget(); @@ -5338,6 +5404,27 @@ void command_unscribespells(Client *c, const Seperator *sep) t->UnscribeSpellAll(); } +void command_untraindisc(Client *c, const Seperator *sep) { + Client *t = c; + if (c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM()) + t = c->GetTarget()->CastToClient(); + + for (int i = 0; i < MAX_PP_DISCIPLINES; i++) { + if (t->GetPP().disciplines.values[i] == atoi(sep->arg[1])) { + t->UntrainDisc(i, 1); + return; + } + } +} + +void command_untraindiscs(Client *c, const Seperator *sep) { + Client *t = c; + if (c->GetTarget() && c->GetTarget()->IsClient() && c->GetGM()) + t = c->GetTarget()->CastToClient(); + + t->UntrainDiscAll(); +} + void command_wpinfo(Client *c, const Seperator *sep) { Mob *t=c->GetTarget(); @@ -5408,36 +5495,54 @@ void command_interrupt(Client *c, const Seperator *sep) void command_summonitem(Client *c, const Seperator *sep) { - if (!sep->IsNumber(1)) - c->Message(0, "Usage: #summonitem [item id] [charges], charges are optional"); - else { - uint32 itemid = atoi(sep->arg[1]); - int16 item_status = 0; - const Item_Struct* item = database.GetItem(itemid); - if(item) { - item_status = static_cast(item->MinStatus); - } + uint32 itemid = 0; - if (item_status > c->Admin()) - c->Message(13, "Error: Insufficient status to summon this item."); - else if (sep->argnum==2 && sep->IsNumber(2)) - c->SummonItem(itemid, atoi(sep->arg[2])); - else if (sep->argnum==3) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3])); - else if (sep->argnum==4) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); - else if (sep->argnum==5) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5])); - else if (sep->argnum==6) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6])); - else if (sep->argnum==7) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]), atoi(sep->arg[7])); - else if (sep->argnum==8) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]), atoi(sep->arg[7]), atoi(sep->arg[8])); - else { - c->SummonItem(itemid); - } + 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) { + EQEmu::SayLinkBody_Struct link_body; + EQEmu::saylink::DegenerateLinkBody(link_body, cmd_msg.substr(link_open + 1, EQEmu::legacy::TEXT_LINK_BODY_LENGTH)); + itemid = link_body.item_id; } + else if (!sep->IsNumber(1)) { + c->Message(0, "Usage: #summonitem [item id | link] [charges], charges are optional"); + return; + } + else { + itemid = atoi(sep->arg[1]); + } + if (!itemid) { + c->Message(0, "A valid item id number is required (derived: 0)"); + return; + } + + int16 item_status = 0; + const EQEmu::ItemBase* item = database.GetItem(itemid); + if (item) { + item_status = static_cast(item->MinStatus); + } + + if (item_status > c->Admin()) + c->Message(13, "Error: Insufficient status to summon this item."); + else if (sep->argnum == 2 && sep->IsNumber(2)) + c->SummonItem(itemid, atoi(sep->arg[2])); + else if (sep->argnum == 3) + c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3])); + else if (sep->argnum == 4) + c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); + else if (sep->argnum == 5) + c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5])); + else if (sep->argnum == 6) + c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6])); + else if (sep->argnum == 7) + c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]), atoi(sep->arg[7])); + else if (sep->argnum == 8) + c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]), atoi(sep->arg[7]), atoi(sep->arg[8])); + else { + c->SummonItem(itemid); + } + } void command_giveitem(Client *c, const Seperator *sep) @@ -5452,7 +5557,7 @@ void command_giveitem(Client *c, const Seperator *sep) Client *t = c->GetTarget()->CastToClient(); uint32 itemid = atoi(sep->arg[1]); int16 item_status = 0; - const Item_Struct* item = database.GetItem(itemid); + const EQEmu::ItemBase* item = database.GetItem(itemid); if(item) { item_status = static_cast(item->MinStatus); } @@ -5505,10 +5610,10 @@ void command_itemsearch(Client *c, const Seperator *sep) { const char *search_criteria=sep->argplus[1]; - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; std::string item_link; - Client::TextLink linker; - linker.SetLinkType(linker.linkItemData); + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemData); if (Seperator::IsNumber(search_criteria)) { item = database.GetItem(atoi(search_criteria)); @@ -5526,13 +5631,13 @@ void command_itemsearch(Client *c, const Seperator *sep) return; } - int count = NOT_USED; + int count = 0; char sName[64]; char sCriteria[255]; strn0cpy(sCriteria, search_criteria, sizeof(sCriteria)); strupr(sCriteria); char* pdest; - uint32 it = NOT_USED; + uint32 it = 0; while ((item = database.IterateItems(&it))) { strn0cpy(sName, item->Name, sizeof(sName)); strupr(sName); @@ -5584,16 +5689,23 @@ void command_setaapts(Client *c, const Seperator *sep) if(sep->arg[1][0] == '\0' || sep->arg[2][0] == '\0') c->Message(0, "Usage: #setaapts "); - else if(atoi(sep->arg[2]) <= 0 || atoi(sep->arg[2]) > 200) - c->Message(0, "You must have a number greater than 0 for points and no more than 200."); + else if(atoi(sep->arg[2]) <= 0 || atoi(sep->arg[2]) > 5000) + c->Message(0, "You must have a number greater than 0 for points and no more than 5000."); else if(!strcasecmp(sep->arg[1], "group")) { - t->SetLeadershipEXP(atoi(sep->arg[2])*GROUP_EXP_PER_POINT, t->GetRaidEXP()); + t->GetPP().group_leadership_points = atoi(sep->arg[2]); + t->GetPP().group_leadership_exp = 0; + t->Message(MT_Experience, "Setting Group AA points to %u", t->GetPP().group_leadership_points); + t->SendLeadershipEXPUpdate(); } else if(!strcasecmp(sep->arg[1], "raid")) { - t->SetLeadershipEXP(t->GetGroupEXP(), atoi(sep->arg[2])*RAID_EXP_PER_POINT); + t->GetPP().raid_leadership_points = atoi(sep->arg[2]); + t->GetPP().raid_leadership_exp = 0; + t->Message(MT_Experience, "Setting Raid AA points to %u", t->GetPP().raid_leadership_points); + t->SendLeadershipEXPUpdate(); } else { - t->SetEXP(t->GetEXP(),t->GetMaxAAXP()*atoi(sep->arg[2]),false); - t->SendAAStats(); - t->SendAATable(); + t->GetPP().aapoints = atoi(sep->arg[2]); + t->GetPP().expAA = 0; + t->Message(MT_Experience, "Setting personal AA points to %u", t->GetPP().aapoints); + t->SendAlternateAdvancementStats(); } } @@ -5741,7 +5853,7 @@ void command_suspend(Client *c, const Seperator *sep) } } - char *escName = new char[strlen(sep->arg[1]) * 2 + 1]; + auto escName = new char[strlen(sep->arg[1]) * 2 + 1]; database.DoEscapeString(escName, sep->arg[1], strlen(sep->arg[1])); int accountID = database.GetAccountIDByChar(escName); safe_delete_array(escName); @@ -5752,7 +5864,7 @@ void command_suspend(Client *c, const Seperator *sep) } std::string query = StringFormat("UPDATE `account` SET `suspendeduntil` = DATE_ADD(NOW(), INTERVAL %i DAY), " - "suspend_reason = '%s' WHERE `id` = %i", + "suspend_reason = '%s' WHERE `id` = %i", duration, EscapeString(message).c_str(), accountID); auto results = database.QueryDatabase(query); @@ -5768,16 +5880,16 @@ void command_suspend(Client *c, const Seperator *sep) return; } - ServerPacket* pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); - ServerKickPlayer_Struct* sks = (ServerKickPlayer_Struct*) pack->pBuffer; + auto pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); + ServerKickPlayer_Struct *sks = (ServerKickPlayer_Struct *)pack->pBuffer; - strn0cpy(sks->adminname, c->GetName(), sizeof(sks->adminname)); - strn0cpy(sks->name, sep->arg[1], sizeof(sks->name)); - sks->adminrank = c->Admin(); + strn0cpy(sks->adminname, c->GetName(), sizeof(sks->adminname)); + strn0cpy(sks->name, sep->arg[1], sizeof(sks->name)); + sks->adminrank = c->Admin(); - worldserver.SendPacket(pack); + worldserver.SendPacket(pack); - safe_delete(pack); + safe_delete(pack); } void command_ipban(Client *c, const Seperator *sep) @@ -5822,13 +5934,13 @@ void command_revoke(Client *c, const Seperator *sep) c->Message(13, "#revoke: Couldn't find %s in this zone, passing request to worldserver.", sep->arg[1]); - ServerPacket * outapp = new ServerPacket (ServerOP_Revoke,sizeof(RevokeStruct)); - RevokeStruct* revoke = (RevokeStruct*)outapp->pBuffer; - strn0cpy(revoke->adminname, c->GetName(), 64); - strn0cpy(revoke->name, sep->arg[1], 64); - revoke->toggle = flag; - worldserver.SendPacket(outapp); - safe_delete(outapp); + auto outapp = new ServerPacket(ServerOP_Revoke, sizeof(RevokeStruct)); + RevokeStruct *revoke = (RevokeStruct *)outapp->pBuffer; + strn0cpy(revoke->adminname, c->GetName(), 64); + strn0cpy(revoke->name, sep->arg[1], 64); + revoke->toggle = flag; + worldserver.SendPacket(outapp); + safe_delete(outapp); } void command_oocmute(Client *c, const Seperator *sep) @@ -5836,10 +5948,10 @@ void command_oocmute(Client *c, const Seperator *sep) if(sep->arg[1][0] == 0 || !(sep->arg[1][0] == '1' || sep->arg[1][0] == '0')) c->Message(0, "Usage: #oocmute [1/0]"); else { - ServerPacket * outapp = new ServerPacket (ServerOP_OOCMute,1); - *(outapp->pBuffer)=atoi(sep->arg[1]); - worldserver.SendPacket(outapp); - safe_delete(outapp); + auto outapp = new ServerPacket(ServerOP_OOCMute, 1); + *(outapp->pBuffer) = atoi(sep->arg[1]); + worldserver.SendPacket(outapp); + safe_delete(outapp); } } @@ -6224,21 +6336,21 @@ void command_npcedit(Client *c, const Seperator *sep) database.QueryDatabase(query); return; } - + if (strcasecmp(sep->arg[1], "meleetype") == 0) { c->Message(15,"NPCID %u now has a primary melee type of %i and a secondary melee type of %i.", npcTypeID, atoi(sep->arg[2]), atoi(sep->arg[3])); std::string query = StringFormat("UPDATE npc_types SET prim_melee_type = %i, sec_melee_type = %i WHERE id = %i", atoi(sep->arg[2]), atoi(sep->arg[3]), npcTypeID); database.QueryDatabase(query); return; } - + if (strcasecmp(sep->arg[1], "rangedtype") == 0) { c->Message(15,"NPCID %u now has a ranged type of %i.", npcTypeID, atoi(sep->argplus[2])); - std::string query = StringFormat("UPDATE npc_types SET rangedtype = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); + std::string query = StringFormat("UPDATE npc_types SET ranged_type = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); database.QueryDatabase(query); return; } - + if (strcasecmp(sep->arg[1], "ammoidfile") == 0) { c->Message(15,"NPCID %u's ammo id file is now %i", npcTypeID, atoi(sep->argplus[2])); std::string query = StringFormat("UPDATE npc_types SET ammoidfile = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); @@ -6273,7 +6385,7 @@ void command_npcedit(Client *c, const Seperator *sep) database.QueryDatabase(query); return; } - + if (strcasecmp(sep->arg[1], "walkspeed") == 0) { c->Message(15,"NPCID %u now walks at %f", npcTypeID, atof(sep->argplus[2])); std::string query = StringFormat("UPDATE npc_types SET walkspeed = %f WHERE id = %i", atof(sep->argplus[2]), npcTypeID); @@ -6427,7 +6539,7 @@ void command_npcedit(Client *c, const Seperator *sep) database.QueryDatabase(query); return; } - + if (strcasecmp(sep->arg[1], "Avoidance") == 0) { c->Message(15,"NPCID %u now has %i Avoidance.", npcTypeID, atoi(sep->argplus[2])); std::string query = StringFormat("UPDATE npc_types SET avoidance = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); @@ -6483,7 +6595,7 @@ void command_npcedit(Client *c, const Seperator *sep) database.QueryDatabase(query); return; } - + if (strcasecmp(sep->arg[1], "Attackcount") == 0) { c->Message(15,"NPCID %u now has attack_count set to %i", npcTypeID,atoi(sep->arg[2])); std::string query = StringFormat("UPDATE npc_types SET attack_count = %i WHERE id = %i", atoi(sep->argplus[2]),npcTypeID); @@ -6520,7 +6632,7 @@ void command_npcedit(Client *c, const Seperator *sep) "luclin_hairstyle = %i, luclin_beard = %i, " "face = %i, drakkin_heritage = %i, " "drakkin_tattoo = %i, drakkin_details = %i " - "WHERE id = %i", + "WHERE id = %i", target->GetHairColor(), target->GetBeardColor(), target->GetHairStyle(), target->GetBeard(), target->GetLuclinFace(), target->GetDrakkinHeritage(), @@ -6606,7 +6718,7 @@ void command_npcedit(Client *c, const Seperator *sep) database.QueryDatabase(query); return; } - + if (strcasecmp(sep->arg[1], "slow_mitigation") == 0) { c->Message(15, "NPCID %u's slow mitigation limit is now %i.", npcTypeID, atoi(sep->arg[2])); std::string query = StringFormat("UPDATE npc_types SET slow_mitigation = %i WHERE id = %i", atoi(sep->argplus[2]), npcTypeID); @@ -6661,7 +6773,7 @@ void command_qglobal(Client *c, const Seperator *sep) { } if(!strcasecmp(sep->arg[1], "on")) { - std::string query = StringFormat("UPDATE npc_types SET qglobal = 1 WHERE id = '%i'", + std::string query = StringFormat("UPDATE npc_types SET qglobal = 1 WHERE id = '%i'", target->GetNPCTypeID()); auto results = database.QueryDatabase(query); if(!results.Success()) { @@ -6674,7 +6786,7 @@ void command_qglobal(Client *c, const Seperator *sep) { } if(!strcasecmp(sep->arg[1], "off")) { - std::string query = StringFormat("UPDATE npc_types SET qglobal = 0 WHERE id = '%i'", + std::string query = StringFormat("UPDATE npc_types SET qglobal = 0 WHERE id = '%i'", target->GetNPCTypeID()); auto results = database.QueryDatabase(query); if(!results.Success()) { @@ -7011,7 +7123,7 @@ void command_path(Client *c, const Seperator *sep) } void Client::Undye() { - for (int cur_slot = EmuConstants::MATERIAL_BEGIN; cur_slot <= EmuConstants::MATERIAL_END; cur_slot++ ) { + for (int cur_slot = EQEmu::textures::TextureBegin; cur_slot <= EQEmu::textures::LastTexture; cur_slot++) { uint8 slot2=SlotConvert(cur_slot); ItemInst* inst = m_inv.GetItem(slot2); @@ -7020,7 +7132,7 @@ void Client::Undye() { database.SaveInventory(CharacterID(), inst, slot2); } - m_pp.item_tint[cur_slot].Color = 0; + m_pp.item_tint.Slot[cur_slot].Color = 0; SendWearChange(cur_slot); } @@ -7070,13 +7182,13 @@ void command_ginfo(Client *c, const Seperator *sep) if(g->membername[r][0] == '\0') continue; c->Message(0, "...Zoned Member: %s, Roles: %s %s %s", g->membername[r], - (g->MemberRoles[r] & RoleAssist) ? "Assist" : "", - (g->MemberRoles[r] & RoleTank) ? "Tank" : "", + (g->MemberRoles[r] & RoleAssist) ? "Assist" : "", + (g->MemberRoles[r] & RoleTank) ? "Tank" : "", (g->MemberRoles[r] & RolePuller) ? "Puller" : ""); } else { c->Message(0, "...In-Zone Member: %s (0x%x) Roles: %s %s %s", g->membername[r], g->members[r], - (g->MemberRoles[r] & RoleAssist) ? "Assist" : "", - (g->MemberRoles[r] & RoleTank) ? "Tank" : "", + (g->MemberRoles[r] & RoleAssist) ? "Assist" : "", + (g->MemberRoles[r] & RoleTank) ? "Tank" : "", (g->MemberRoles[r] & RolePuller) ? "Puller" : ""); } @@ -7239,7 +7351,7 @@ void command_flagedit(Client *c, const Seperator *sep) { flag_name[127] = '\0'; std::string query = StringFormat("UPDATE zone SET flag_needed = '%s' " - "WHERE zoneidnumber = %d AND version = %d", + "WHERE zoneidnumber = %d AND version = %d", flag_name, zoneid, zone->GetInstanceVersion()); auto results = database.QueryDatabase(query); if(!results.Success()) { @@ -7266,7 +7378,7 @@ void command_flagedit(Client *c, const Seperator *sep) { } std::string query = StringFormat("UPDATE zone SET flag_needed = '' " - "WHERE zoneidnumber = %d AND version = %d", + "WHERE zoneidnumber = %d AND version = %d", zoneid, zone->GetInstanceVersion()); auto results = database.QueryDatabase(query); if(!results.Success()) { @@ -7669,63 +7781,13 @@ void command_task(Client *c, const Seperator *sep) { } void command_reloadtitles(Client *c, const Seperator *sep) { - ServerPacket* pack = new ServerPacket(ServerOP_ReloadTitles, 0); + auto pack = new ServerPacket(ServerOP_ReloadTitles, 0); worldserver.SendPacket(pack); safe_delete(pack); c->Message(15, "Player Titles Reloaded."); } -void command_altactivate(Client *c, const Seperator *sep){ - if(sep->arg[1][0] == '\0'){ - c->Message(10, "Invalid argument, usage:"); - c->Message(10, "#altactivate list - lists the AA ID numbers that are available to you"); - c->Message(10, "#altactivate time [argument] - returns the time left until you can use the AA with the ID that matches the argument."); - c->Message(10, "#altactivate [argument] - activates the AA with the ID that matches the argument."); - return; - } - if(!strcasecmp(sep->arg[1], "help")){ - c->Message(10, "Usage:"); - c->Message(10, "#altactivate list - lists the AA ID numbers that are available to you"); - c->Message(10, "#altactivate time [argument] - returns the time left until you can use the AA with the ID that matches the argument."); - c->Message(10, "#altactivate [argument] - activates the AA with the ID that matches the argument."); - return; - } - if(!strcasecmp(sep->arg[1], "list")){ - c->Message(10, "You have access to the following AA Abilities:"); - int x, val; - SendAA_Struct* saa = nullptr; - for(x = 0; x < aaHighestID; x++){ - if(AA_Actions[x][0].spell_id || AA_Actions[x][0].action){ //if there's an action or spell associated we assume it's a valid - val = 0; //and assume if they don't have a value for the first rank then it isn't valid for any rank - saa = nullptr; - val = c->GetAA(x); - if(val){ - saa = zone->FindAA(x); - c->Message(10, "%d: %s %d", x, saa->name, val); - } - } - } - } - else if(!strcasecmp(sep->arg[1], "time")){ - int ability = atoi(sep->arg[2]); - if(c->GetAA(ability)){ - int remain = c->GetPTimers().GetRemainingTime(pTimerAAStart + ability); - if(remain) - c->Message(10, "You may use that ability in %d minutes and %d seconds.", (remain/60), (remain%60)); - else - c->Message(10, "You may use that ability now."); - } - else{ - c->Message(10, "You do not have access to that ability."); - } - } - else - { - c->ActivateAA((aaID) atoi(sep->arg[1])); - } -} - void command_traindisc(Client *c, const Seperator *sep) { uint8 max_level, min_level; @@ -7781,7 +7843,7 @@ void command_traindisc(Client *c, const Seperator *sep) break; //continue the 1st loop } else if(t->GetPP().disciplines.values[r] == 0) { t->GetPP().disciplines.values[r] = curspell; - database.SaveCharacterDisc(c->CharacterID(), r, curspell); + database.SaveCharacterDisc(t->CharacterID(), r, curspell); t->SendDisciplineUpdate(); t->Message(0, "You have learned a new discipline!"); count++; //success counter @@ -7872,7 +7934,7 @@ void command_deletegraveyard(Client *c, const Seperator *sep) return; } -void command_summonburriedplayercorpse(Client *c, const Seperator *sep) +void command_summonburiedplayercorpse(Client *c, const Seperator *sep) { Client *t=c; @@ -7886,12 +7948,12 @@ void command_summonburriedplayercorpse(Client *c, const Seperator *sep) Corpse* PlayerCorpse = database.SummonBuriedCharacterCorpses(t->CharacterID(), t->GetZoneID(), zone->GetInstanceID(), t->GetPosition()); if(!PlayerCorpse) - c->Message(0, "Your target doesn't have any burried corpses."); + c->Message(0, "Your target doesn't have any buried corpses."); return; } -void command_getplayerburriedcorpsecount(Client *c, const Seperator *sep) +void command_getplayerburiedcorpsecount(Client *c, const Seperator *sep) { Client *t=c; @@ -7905,9 +7967,9 @@ void command_getplayerburriedcorpsecount(Client *c, const Seperator *sep) uint32 CorpseCount = database.GetCharacterBuriedCorpseCount(t->CharacterID()); if(CorpseCount > 0) - c->Message(0, "Your target has a total of %u burried corpses.", CorpseCount); + c->Message(0, "Your target has a total of %u buried corpses.", CorpseCount); else - c->Message(0, "Your target doesn't have any burried corpses."); + c->Message(0, "Your target doesn't have any buried corpses."); return; } @@ -7948,7 +8010,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep) std::string query = StringFormat("INSERT INTO spawngroup " "(name, spawn_limit, dist, max_x, min_x, max_y, min_y, delay) " - "VALUES (\"%s\", %i, %f, %f, %f, %f, %f, %i)", + "VALUES (\"%s\", %i, %f, %f, %f, %f, %f, %i)", sep->arg[2], (sep->arg[3]? atoi(sep->arg[3]): 0), (sep->arg[4]? atof(sep->arg[4]): 0), @@ -7975,7 +8037,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep) } std::string query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) " - "VALUES (%i, %i, %i)", + "VALUES (%i, %i, %i)", atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); auto results = database.QueryDatabase(query); if (!results.Success()) { @@ -7996,7 +8058,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep) } std::string query = StringFormat("UPDATE spawngroup SET dist = '%f', max_x = '%f', min_x = '%f', " - "max_y = '%f', min_y = '%f', delay = '%i' WHERE id = '%i'", + "max_y = '%f', min_y = '%f', delay = '%i' WHERE id = '%i'", atof(sep->arg[3]), atof(sep->arg[4]), atof(sep->arg[5]), atof(sep->arg[6]), atof(sep->arg[7]), atoi(sep->arg[8]), atoi(sep->arg[2])); @@ -8081,7 +8143,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep) } std::string query = StringFormat("UPDATE spawn2 SET x = '%f', y = '%f', z = '%f', heading = '%f' " - "WHERE id = '%i'", + "WHERE id = '%i'", c->GetX(), c->GetY(), c->GetZ(), c->GetHeading(),s2->GetID()); auto results = database.QueryDatabase(query); if (!results.Success()) { @@ -8152,7 +8214,7 @@ void command_advnpcspawn(Client *c, const Seperator *sep) int16 version = atoi(sep->arg[2]); std::string query = StringFormat("UPDATE spawn2 SET version = %i " - "WHERE spawngroupID = '%i'", + "WHERE spawngroupID = '%i'", version, c->GetTarget()->CastToNPC()->GetSp2()); auto results = database.QueryDatabase(query); if (!results.Success()) { @@ -8549,20 +8611,20 @@ void command_object(Client *c, const Seperator *sep) od.object_type = atoi(row[7]); icon = atoi(row[8]); - od.unknown008 = atoi(row[9]); - od.unknown010 = atoi(row[10]); + od.size = atoi(row[9]); + od.solidtype = atoi(row[10]); od.unknown020 = atoi(row[11]); switch (od.object_type) { case 0: // Static Object case staticType: // Static Object unlocked for changes - if (od.unknown008 == 0) // Unknown08 field is optional Size parameter for static objects - od.unknown008 = 100; // Static object default Size is 100% + if (od.size == 0) // Unknown08 field is optional Size parameter for static objects + od.size = 100; // Static object default Size is 100% c->Message(0, "- STATIC Object (%s): id %u, x %.1f, y %.1f, z %.1f, h %.1f, model %s, " "size %u, solidtype %u, incline %u", (od.object_type == 0) ? "locked" : "unlocked", id, od.x, od.y, od.z, - od.heading, od.object_name, od.unknown008, od.unknown010, od.unknown020); + od.heading, od.object_name, od.size, od.solidtype, od.unknown020); break; case OT_DROPPEDITEM: // Ground Spawn @@ -8620,10 +8682,10 @@ void command_object(Client *c, const Seperator *sep) switch (od.object_type) { case 0: // Static Object if ((sep->argnum - col) > 3) { - od.unknown008 = atoi(sep->arg[4 + col]); // Size specified + od.size = atoi(sep->arg[4 + col]); // Size specified if ((sep->argnum - col) > 4) { - od.unknown010 = atoi(sep->arg[5 + col]); // SolidType specified + od.solidtype = atoi(sep->arg[5 + col]); // SolidType specified if ((sep->argnum - col) > 5) od.unknown020 = atoi(sep->arg[6 + col]); // Incline specified @@ -8922,16 +8984,16 @@ void command_object(Client *c, const Seperator *sep) return; } - od.unknown008 = atoi(sep->arg[4]); + od.size = atoi(sep->arg[4]); o->SetObjectData(&od); - if (od.unknown008 == 0) // 0 == unspecified == 100% - od.unknown008 = 100; + if (od.size == 0) // 0 == unspecified == 100% + od.size = 100; c->Message(0, "Static Object %u set to %u%% size. Size will take effect when you commit to the " "database with '#object Save', after which the object will be unchangeable until " "you unlock it again with '#object Edit' and zone out and back in.", - id, od.unknown008); + id, od.size); } else if (strcmp(sep->arg[3], "solidtype") == 0) { if (od.object_type != staticType) { @@ -8946,13 +9008,13 @@ void command_object(Client *c, const Seperator *sep) return; } - od.unknown010 = atoi(sep->arg[4]); + od.solidtype = atoi(sep->arg[4]); o->SetObjectData(&od); c->Message(0, "Static Object %u set to SolidType %u. Change will take effect when you commit " "to the database with '#object Save'. Support for this property is on a " "per-model basis, mostly seen in smaller objects such as chests and tables.", - id, od.unknown010); + id, od.solidtype); } else if (strcmp(sep->arg[3], "icon") == 0) { if ((od.object_type < 2) || (od.object_type == staticType)) { @@ -9239,24 +9301,24 @@ void command_object(Client *c, const Seperator *sep) "unknown08 = %u, unknown10 = %u, unknown20 = %u " "WHERE ID = %u", zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z, - od.heading, od.object_name, od.object_type, icon, od.unknown008, - od.unknown010, od.unknown020, id); + od.heading, od.object_name, od.object_type, icon, od.size, + od.solidtype, od.unknown020, id); else if (id == 0) query = StringFormat("INSERT INTO object " "(zoneid, version, xpos, ypos, zpos, heading, objectname, " "type, icon, unknown08, unknown10, unknown20) " "VALUES (%u, %u, %.1f, %.1f, %.1f, %.1f, '%s', %u, %u, %u, %u, %u)", zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z, - od.heading, od.object_name, od.object_type, icon, od.unknown008, - od.unknown010, od.unknown020); + od.heading, od.object_name, od.object_type, icon, od.size, + od.solidtype, od.unknown020); else query = StringFormat("INSERT INTO object " "(id, zoneid, version, xpos, ypos, zpos, heading, objectname, " "type, icon, unknown08, unknown10, unknown20) " "VALUES (%u, %u, %u, %.1f, %.1f, %.1f, %.1f, '%s', %u, %u, %u, %u, %u)", id, zone->GetZoneID(), zone->GetInstanceVersion(), od.x, od.y, od.z, - od.heading, od.object_name, od.object_type, icon, od.unknown008, - od.unknown010, od.unknown020); + od.heading, od.object_name, od.object_type, icon, od.size, + od.solidtype, od.unknown020); results = database.QueryDatabase(query); if (!results.Success()) { @@ -9314,12 +9376,12 @@ void command_object(Client *c, const Seperator *sep) memcpy(door.dest_zone, "NONE", 5); - if ((door.size = od.unknown008) == 0) // unknown08 = optional size percentage + if ((door.size = od.size) == 0) // unknown08 = optional size percentage door.size = 100; switch ( door.opentype = - od.unknown010) // unknown10 = optional request_nonsolid (0 or 1 or experimental number) + od.solidtype) // unknown10 = optional request_nonsolid (0 or 1 or experimental number) { case 0: door.opentype = 31; @@ -9576,8 +9638,8 @@ void command_object(Client *c, const Seperator *sep) strn0cpy(od.object_name, row[4], sizeof(od.object_name)); od.object_type = atoi(row[5]); icon = atoi(row[6]); - od.unknown008 = atoi(row[7]); - od.unknown010 = atoi(row[8]); + od.size = atoi(row[7]); + od.solidtype = atoi(row[8]); od.unknown020 = atoi(row[9]); if (od.object_type == 0) @@ -9612,14 +9674,6 @@ void command_showspellslist(Client *c, const Seperator *sep) return; } -// All new code added to command.cpp ought to be BEFORE this comment line. Do no append code to this file below the BOTS code block. -#ifdef BOTS -// Function delegate to support the command interface for Bots with the client. -void command_bot(Client *c, const Seperator *sep) { - Bot::ProcessBotCommands(c, sep); -} -#endif - void command_raidloot(Client *c, const Seperator *sep) { if(!sep->arg[1][0]) { @@ -9816,7 +9870,7 @@ void command_globalview(Client *c, const Seperator *sep) QGlobalCache::Combine(globalMap, zone_c->GetBucket(), ntype, c->CharacterID(), zone->GetZoneID()); } - std::list::iterator iter = globalMap.begin(); + auto iter = globalMap.begin(); uint32 gcount = 0; c->Message(0, "Name, Value"); @@ -9849,7 +9903,7 @@ void command_globalview(Client *c, const Seperator *sep) QGlobalCache::Combine(globalMap, zone_c->GetBucket(), ntype, c->CharacterID(), zone->GetZoneID()); } - std::list::iterator iter = globalMap.begin(); + auto iter = globalMap.begin(); uint32 gcount = 0; c->Message(0, "Name, Value"); @@ -9875,7 +9929,8 @@ void command_cvs(Client *c, const Seperator *sep) { if(c) { - ServerPacket *pack = new ServerPacket(ServerOP_ClientVersionSummary, sizeof(ServerRequestClientVersionSummary_Struct)); + auto pack = + new ServerPacket(ServerOP_ClientVersionSummary, sizeof(ServerRequestClientVersionSummary_Struct)); ServerRequestClientVersionSummary_Struct *srcvss = (ServerRequestClientVersionSummary_Struct*)pack->pBuffer; @@ -9892,16 +9947,16 @@ void command_max_all_skills(Client *c, const Seperator *sep) { if(c) { - for(int i = 0; i <= HIGHEST_SKILL; ++i) + for (int i = 0; i <= EQEmu::skills::HIGHEST_SKILL; ++i) { - if(i >= SkillSpecializeAbjure && i <= SkillSpecializeEvocation) + if (i >= EQEmu::skills::SkillSpecializeAbjure && i <= EQEmu::skills::SkillSpecializeEvocation) { - c->SetSkill((SkillUseTypes)i, 50); + c->SetSkill((EQEmu::skills::SkillType)i, 50); } else { - int max_skill_level = database.GetSkillCap(c->GetClass(), (SkillUseTypes)i, c->GetLevel()); - c->SetSkill((SkillUseTypes)i, max_skill_level); + int max_skill_level = database.GetSkillCap(c->GetClass(), (EQEmu::skills::SkillType)i, c->GetLevel()); + c->SetSkill((EQEmu::skills::SkillType)i, max_skill_level); } } } @@ -9935,7 +9990,7 @@ void command_reloadallrules(Client *c, const Seperator *sep) { if(c) { - ServerPacket *pack = new ServerPacket(ServerOP_ReloadRules, 0); + auto pack = new ServerPacket(ServerOP_ReloadRules, 0); worldserver.SendPacket(pack); c->Message(13, "Successfully sent the packet to world to reload rules globally. (including world)"); safe_delete(pack); @@ -9947,7 +10002,7 @@ void command_reloadworldrules(Client *c, const Seperator *sep) { if(c) { - ServerPacket *pack = new ServerPacket(ServerOP_ReloadRulesWorld, 0); + auto pack = new ServerPacket(ServerOP_ReloadRulesWorld, 0); worldserver.SendPacket(pack); c->Message(13, "Successfully sent the packet to world to reload rules. (only world)"); safe_delete(pack); @@ -9960,7 +10015,7 @@ void command_camerashake(Client *c, const Seperator *sep) { if(sep->arg[1][0] && sep->arg[2][0]) { - ServerPacket *pack = new ServerPacket(ServerOP_CameraShake, sizeof(ServerCameraShake_Struct)); + auto pack = new ServerPacket(ServerOP_CameraShake, sizeof(ServerCameraShake_Struct)); ServerCameraShake_Struct* scss = (ServerCameraShake_Struct*) pack->pBuffer; scss->duration = atoi(sep->arg[1]); scss->intensity = atoi(sep->arg[2]); @@ -9987,14 +10042,14 @@ void command_disarmtrap(Client *c, const Seperator *sep) if(target->IsNPC()) { - if(c->HasSkill(SkillDisarmTraps)) + if (c->HasSkill(EQEmu::skills::SkillDisarmTraps)) { if(DistanceSquaredNoZ(c->GetPosition(), target->GetPosition()) > RuleI(Adventure, LDoNTrapDistanceUse)) { c->Message(13, "%s is too far away.", target->GetCleanName()); return; } - c->HandleLDoNDisarm(target->CastToNPC(), c->GetSkill(SkillDisarmTraps), LDoNTypeMechanical); + c->HandleLDoNDisarm(target->CastToNPC(), c->GetSkill(EQEmu::skills::SkillDisarmTraps), LDoNTypeMechanical); } else c->Message(13, "You do not have the disarm trap skill."); @@ -10012,14 +10067,14 @@ void command_sensetrap(Client *c, const Seperator *sep) if(target->IsNPC()) { - if(c->HasSkill(SkillSenseTraps)) + if (c->HasSkill(EQEmu::skills::SkillSenseTraps)) { if(DistanceSquaredNoZ(c->GetPosition(), target->GetPosition()) > RuleI(Adventure, LDoNTrapDistanceUse)) { c->Message(13, "%s is too far away.", target->GetCleanName()); return; } - c->HandleLDoNSenseTraps(target->CastToNPC(), c->GetSkill(SkillSenseTraps), LDoNTypeMechanical); + c->HandleLDoNSenseTraps(target->CastToNPC(), c->GetSkill(EQEmu::skills::SkillSenseTraps), LDoNTypeMechanical); } else c->Message(13, "You do not have the sense traps skill."); @@ -10037,14 +10092,14 @@ void command_picklock(Client *c, const Seperator *sep) if(target->IsNPC()) { - if(c->HasSkill(SkillPickLock)) + if (c->HasSkill(EQEmu::skills::SkillPickLock)) { if(DistanceSquaredNoZ(c->GetPosition(), target->GetPosition()) > RuleI(Adventure, LDoNTrapDistanceUse)) { c->Message(13, "%s is too far away.", target->GetCleanName()); return; } - c->HandleLDoNPickLock(target->CastToNPC(), c->GetSkill(SkillPickLock), LDoNTypeMechanical); + c->HandleLDoNPickLock(target->CastToNPC(), c->GetSkill(EQEmu::skills::SkillPickLock), LDoNTypeMechanical); } else c->Message(13, "You do not have the pick locks skill."); @@ -10172,14 +10227,14 @@ void command_zopp(Client *c, const Seperator *sep) packettype = ItemPacketTrade; } else { - packettype = ItemPacketSummonItem; + packettype = ItemPacketLimbo; } int16 slotid = atoi(sep->arg[2]); uint32 itemid = atoi(sep->arg[3]); int16 charges = sep->argnum == 4 ? atoi(sep->arg[4]) : 1; // defaults to 1 charge if not specified - const Item_Struct* FakeItem = database.GetItem(itemid); + const EQEmu::ItemBase* FakeItem = database.GetItem(itemid); if (!FakeItem) { c->Message(13, "Error: Item [%u] is not a valid item id.", itemid); @@ -10187,7 +10242,7 @@ void command_zopp(Client *c, const Seperator *sep) } int16 item_status = 0; - const Item_Struct* item = database.GetItem(itemid); + const EQEmu::ItemBase* item = database.GetItem(itemid); if(item) { item_status = static_cast(item->MinStatus); } @@ -10203,7 +10258,7 @@ void command_zopp(Client *c, const Seperator *sep) ItemInst* FakeItemInst = database.CreateItem(FakeItem, charges); c->SendItemPacket(slotid, FakeItemInst, packettype); - c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u) with %i %s to slot %i.", + c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u) with %i %s to slot %i.", packettype == ItemPacketTrade ? "Trade" : "Summon", FakeItem->Name, itemid, charges, std::abs(charges == 1) ? "charge" : "charges", slotid); safe_delete(FakeItemInst); @@ -10215,10 +10270,10 @@ void command_augmentitem(Client *c, const Seperator *sep) if (!c) return; - AugmentItem_Struct* in_augment = new AugmentItem_Struct[sizeof(AugmentItem_Struct)]; - in_augment->container_slot = 1000; // - in_augment->augment_slot = -1; - if(c->GetTradeskillObject() != nullptr) + auto in_augment = new AugmentItem_Struct[sizeof(AugmentItem_Struct)]; + in_augment->container_slot = 1000; // + in_augment->augment_slot = -1; + if (c->GetTradeskillObject() != nullptr) Object::HandleAugmentation(c, in_augment, c->GetTradeskillObject()); safe_delete_array(in_augment); } @@ -10422,7 +10477,7 @@ void command_tune(Client *c, const Seperator *sep) ac_override = 0; if (!info_level) info_level = 1; - + if(!strcasecmp(sep->arg[2], "A")) c->Tune_FindATKByPctMitigation(defender, attacker, pct_mitigation, interval, max_loop,ac_override,info_level); else if(!strcasecmp(sep->arg[2], "B")) @@ -10457,7 +10512,7 @@ void command_tune(Client *c, const Seperator *sep) atk_override = 0; if (!info_level) info_level = 1; - + if(!strcasecmp(sep->arg[2], "A")) c->Tune_FindACByPctMitigation(defender, attacker, pct_mitigation, interval, max_loop,atk_override,info_level); else if(!strcasecmp(sep->arg[2], "B")) @@ -10499,7 +10554,7 @@ void command_tune(Client *c, const Seperator *sep) c->Message(10, "#Tune - Error hit chance out of bounds. [Max %.2f Min .2f]", RuleR(Combat,MaxChancetoHit),RuleR(Combat,MinChancetoHit)); return; } - + if(!strcasecmp(sep->arg[2], "A")) c->Tune_FindAccuaryByHitChance(defender, attacker, hit_chance, interval, max_loop,avoid_override,info_level); else if(!strcasecmp(sep->arg[2], "B")) @@ -10541,7 +10596,7 @@ void command_tune(Client *c, const Seperator *sep) c->Message(10, "#Tune - Error hit chance out of bounds. [Max %.2f Min .2f]", RuleR(Combat,MaxChancetoHit),RuleR(Combat,MinChancetoHit)); return; } - + if(!strcasecmp(sep->arg[2], "A")) c->Tune_FindAvoidanceByHitChance(defender, attacker, hit_chance, interval, max_loop,acc_override, info_level); else if(!strcasecmp(sep->arg[2], "B")) @@ -10567,7 +10622,7 @@ void command_logtest(Client *c, const Seperator *sep){ for (i = 0; i < atoi(sep->arg[1]); i++){ Log.Out(Logs::General, Logs::Debug, "[%u] Test #2... Took %f seconds", i, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); } - + } } @@ -10583,7 +10638,7 @@ void command_logs(Client *c, const Seperator *sep){ if (sep->argnum > 0) { /* #logs reload_all */ if (strcasecmp(sep->arg[1], "reload_all") == 0){ - ServerPacket *pack = new ServerPacket(ServerOP_ReloadLogs, 0); + auto pack = new ServerPacket(ServerOP_ReloadLogs, 0); worldserver.SendPacket(pack); c->Message(13, "Successfully sent the packet to world to reload log settings from the database for all zones"); safe_delete(pack); @@ -10623,7 +10678,7 @@ void command_logs(Client *c, const Seperator *sep){ c->Message(15, "Your Log Settings have been applied"); c->Message(15, "Output Method: %s :: Debug Level: %i - Category: %s", sep->arg[2], atoi(sep->arg[4]), Logs::LogCategoryName[atoi(sep->arg[3])]); } - /* We use a general 'is_category_enabled' now, let's update when we update any output settings + /* We use a general 'is_category_enabled' now, let's update when we update any output settings This is used in hot places of code to check if its enabled in any way before triggering logs */ if (sep->arg[4] > 0){ @@ -10651,7 +10706,171 @@ void command_mysqltest(Client *c, const Seperator *sep) for (i = 0; i < atoi(sep->arg[1]); i++){ std::string query = "SELECT * FROM `zone`"; auto results = database.QueryDatabase(query); - } + } } - Log.Out(Logs::General, Logs::Debug, "MySQL Test... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC); + Log.Out(Logs::General, Logs::Debug, "MySQL Test... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC); } + +void command_resetaa_timer(Client *c, const Seperator *sep) { + Client *target = nullptr; + if(!c->GetTarget() || !c->GetTarget()->IsClient()) { + target = c; + } else { + target = c->GetTarget()->CastToClient(); + } + + if(sep->IsNumber(1)) + { + int timer_id = atoi(sep->arg[1]); + c->Message(0, "Reset of timer %i for %s", timer_id, c->GetName()); + c->ResetAlternateAdvancementTimer(timer_id); + } + else if(!strcasecmp(sep->arg[1], "all")) + { + c->Message(0, "Reset all timers for %s", c->GetName()); + c->ResetAlternateAdvancementTimers(); + } + else + { + c->Message(0, "usage: #resetaa_timer [all | timer_id]"); + } +} + +void command_reloadaa(Client *c, const Seperator *sep) { + c->Message(0, "Reloading Alternate Advancement Data..."); + zone->LoadAlternateAdvancement(); + c->Message(0, "Alternate Advancement Data Reloaded"); + entity_list.SendAlternateAdvancementStats(); +} + +void command_hotfix(Client *c, const Seperator *sep) { + std::string hotfix; + database.GetVariable("hotfix_name", hotfix); + + std::string hotfix_name; + if(!strcasecmp(hotfix.c_str(), "hotfix_")) { + hotfix_name = ""; + } else { + hotfix_name = "hotfix_"; + } + + c->Message(0, "Creating and applying hotfix"); + std::thread t1([c,hotfix_name]() { +#ifdef WIN32 + if(hotfix_name.length() > 0) { + system(StringFormat("shared_memory -hotfix=%s", hotfix_name.c_str()).c_str()); + } else { + system(StringFormat("shared_memory").c_str()); + } +#else + if(hotfix_name.length() > 0) { + system(StringFormat("./shared_memory -hotfix=%s", hotfix_name.c_str()).c_str()); + } + else { + system(StringFormat("./shared_memory").c_str()); + } +#endif + database.SetVariable("hotfix_name", hotfix_name); + + ServerPacket pack(ServerOP_ChangeSharedMem, hotfix_name.length() + 1); + if(hotfix_name.length() > 0) { + strcpy((char*)pack.pBuffer, hotfix_name.c_str()); + } + worldserver.SendPacket(&pack); + + c->Message(0, "Hotfix applied"); + }); + + t1.detach(); +} + +void command_load_shared_memory(Client *c, const Seperator *sep) { + std::string hotfix; + database.GetVariable("hotfix_name", hotfix); + + std::string hotfix_name; + if(strcasecmp(hotfix.c_str(), sep->arg[1]) == 0) { + c->Message(0, "Cannot attempt to load this shared memory segment as it is already loaded."); + return; + } + + hotfix_name = sep->arg[1]; + c->Message(0, "Loading shared memory segment %s", hotfix_name.c_str()); + std::thread t1([c,hotfix_name]() { +#ifdef WIN32 + if(hotfix_name.length() > 0) { + system(StringFormat("shared_memory -hotfix=%s", hotfix_name.c_str()).c_str()); + } else { + system(StringFormat("shared_memory").c_str()); + } +#else + if(hotfix_name.length() > 0) { + system(StringFormat("./shared_memory -hotfix=%s", hotfix_name.c_str()).c_str()); + } + else { + system(StringFormat("./shared_memory").c_str()); + } +#endif + c->Message(0, "Shared memory segment finished loading."); + }); + + t1.detach(); +} + +void command_apply_shared_memory(Client *c, const Seperator *sep) { + std::string hotfix; + database.GetVariable("hotfix_name", hotfix); + std::string hotfix_name = sep->arg[1]; + + c->Message(0, "Applying shared memory segment %s", hotfix_name.c_str()); + database.SetVariable("hotfix_name", hotfix_name); + + ServerPacket pack(ServerOP_ChangeSharedMem, hotfix_name.length() + 1); + if(hotfix_name.length() > 0) { + strcpy((char*)pack.pBuffer, hotfix_name.c_str()); + } + worldserver.SendPacket(&pack); +} + +void command_reloadperlexportsettings(Client *c, const Seperator *sep) +{ + if (c) + { + auto pack = new ServerPacket(ServerOP_ReloadPerlExportSettings, 0); + worldserver.SendPacket(pack); + c->Message(13, "Successfully sent the packet to world to reload Perl Export settings"); + safe_delete(pack); + + } +} + + +// All new code added to command.cpp should be BEFORE this comment line. Do no append code to this file below the BOTS code block. +#ifdef BOTS +#include "bot_command.h" +// Function delegate to support the command interface for Bots with the client. +void command_bot(Client *c, const Seperator *sep) +{ + std::string bot_message = sep->msg; + if (bot_message.compare("#bot") == 0) { + bot_message[0] = BOT_COMMAND_CHAR; + } + else { + bot_message = bot_message.substr(bot_message.find_first_not_of("#bot")); + bot_message[0] = BOT_COMMAND_CHAR; + } + + if (bot_command_dispatch(c, bot_message.c_str()) == -2) { + if (parse->PlayerHasQuestSub(EVENT_COMMAND)) { + int i = parse->EventPlayer(EVENT_COMMAND, c, bot_message, 0); + if (i == 0 && !RuleB(Chat, SuppressCommandErrors)) { + c->Message(13, "Bot command '%s' not recognized.", bot_message.c_str()); + } + } + else { + if (!RuleB(Chat, SuppressCommandErrors)) + c->Message(13, "Bot command '%s' not recognized.", bot_message.c_str()); + } + } +} +#endif diff --git a/zone/command.h b/zone/command.h index 0560b8eff..987adf674 100644 --- a/zone/command.h +++ b/zone/command.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,315 +25,312 @@ class Seperator; #include "../common/types.h" -#define COMMAND_CHAR '#' -#define CMDALIASES 5 +#define COMMAND_CHAR '#' typedef void (*CmdFuncPtr)(Client *,const Seperator *); -// this is a command list item -/*struct cl_struct -{ - char *command[CMDALIASES]; // the command(s) - char *desc; // description of command - CmdFuncPtr function; // the function to call - int access; // the required 'status' level - - struct cl_struct *next; // linked list -}; - -extern struct cl_struct *commandlist; // the head of the list -*/ - typedef struct { - const char *command[CMDALIASES]; // the command(s) int access; - const char *desc; // description of command - CmdFuncPtr function; //null means perl function + const char *desc; // description of command + CmdFuncPtr function; // null means perl function } CommandRecord; extern int (*command_dispatch)(Client *,char const*); -extern int commandcount; // number of commands loaded +extern int commandcount; // number of commands loaded // the command system: int command_init(void); void command_deinit(void); -int command_add(const char *command_string, const char *desc, int access, CmdFuncPtr function); +int command_add(std::string command_name, const char *desc, int access, CmdFuncPtr function); int command_notavail(Client *c, const char *message); int command_realdispatch(Client *c, char const *message); void command_logcommand(Client *c, const char *message); //commands -void command_resetaa(Client* c,const Seperator *sep); -void command_bind(Client* c,const Seperator *sep); -void command_sendop(Client *c, const Seperator *sep); -void command_optest(Client *c, const Seperator *sep); -void command_setstat(Client *c, const Seperator *sep); -void command_incstat(Client *c, const Seperator *sep); -void command_help(Client *c, const Seperator *sep); -void command_version(Client *c, const Seperator *sep); -void command_setfaction(Client *c, const Seperator *sep); -void command_serversidename(Client *c, const Seperator *sep); -void command_testspawnkill(Client *c, const Seperator *sep); -void command_testspawn(Client *c, const Seperator *sep); -void command_wc(Client *c, const Seperator *sep); -void command_heromodel(Client *c, const Seperator *sep); -void command_numauths(Client *c, const Seperator *sep); -void command_setanim(Client *c, const Seperator *sep); -void command_connectworldserver(Client *c, const Seperator *sep); -void command_serverinfo(Client *c, const Seperator *sep); -void command_crashtest(Client *c, const Seperator *sep); -void command_getvariable(Client *c, const Seperator *sep); -void command_chat(Client *c, const Seperator *sep); -void command_showpetspell(Client *c, const Seperator *sep); -void command_ipc(Client *c, const Seperator *sep); -void command_npcloot(Client *c, const Seperator *sep); -void command_gm(Client *c, const Seperator *sep); -void command_summon(Client *c, const Seperator *sep); -void command_zone(Client *c, const Seperator *sep); -void command_zone_instance(Client *c, const Seperator *sep); -void command_peqzone(Client *c, const Seperator *sep); -void command_showbuffs(Client *c, const Seperator *sep); -void command_movechar(Client *c, const Seperator *sep); -void command_viewpetition(Client *c, const Seperator *sep); -void command_petitioninfo(Client *c, const Seperator *sep); -void command_delpetition(Client *c, const Seperator *sep); -void command_listnpcs(Client *c, const Seperator *sep); -void command_date(Client *c, const Seperator *sep); -void command_timezone(Client *c, const Seperator *sep); -void command_synctod(Client *c, const Seperator *sep); -void command_invul(Client *c, const Seperator *sep); -void command_hideme(Client *c, const Seperator *sep); -void command_emote(Client *c, const Seperator *sep); -void command_fov(Client *c, const Seperator *sep); -void command_manastat(Client *c, const Seperator *sep); -void command_npcstats(Client *c, const Seperator *sep); -void command_zclip(Client *c, const Seperator *sep); -void command_npccast(Client *c, const Seperator *sep); -void command_zstats(Client *c, const Seperator *sep); -void command_permaclass(Client *c, const Seperator *sep); -void command_permarace(Client *c, const Seperator *sep); -void command_permagender(Client *c, const Seperator *sep); -void command_weather(Client *c, const Seperator *sep); -void command_zheader(Client *c, const Seperator *sep); -void command_zsky(Client *c, const Seperator *sep); -void command_zcolor(Client *c, const Seperator *sep); -void command_spon(Client *c, const Seperator *sep); -void command_spoff(Client *c, const Seperator *sep); -void command_itemtest(Client *c, const Seperator *sep); -void command_gassign(Client *c, const Seperator *sep); +void command_acceptrules(Client *c, const Seperator *sep); +void command_advnpcspawn(Client *c, const Seperator *sep); +void command_aggro(Client *c, const Seperator *sep); +void command_aggrozone(Client *c, const Seperator *sep); void command_ai(Client *c, const Seperator *sep); -void command_worldshutdown(Client *c, const Seperator *sep); -void command_sendzonespawns(Client *c, const Seperator *sep); -void command_zsave(Client *c, const Seperator *sep); -void command_dbspawn2(Client *c, const Seperator *sep); -void command_shutdown(Client *c, const Seperator *sep); -void command_delacct(Client *c, const Seperator *sep); -void command_setpass(Client *c, const Seperator *sep); -void command_setlsinfo(Client *c, const Seperator *sep); -void command_grid(Client *c, const Seperator *sep); -void command_wp(Client *c, const Seperator *sep); -void command_iplookup(Client *c, const Seperator *sep); -void command_size(Client *c, const Seperator *sep); -void command_mana(Client *c, const Seperator *sep); -void command_flymode(Client *c, const Seperator *sep); -void command_showskills(Client *c, const Seperator *sep); -void command_findspell(Client *c, const Seperator *sep); -void command_castspell(Client *c, const Seperator *sep); -void command_setlanguage(Client *c, const Seperator *sep); -void command_setskill(Client *c, const Seperator *sep); -void command_setskillall(Client *c, const Seperator *sep); -void command_race(Client *c, const Seperator *sep); -void command_gender(Client *c, const Seperator *sep); -void command_makepet(Client *c, const Seperator *sep); -void command_level(Client *c, const Seperator *sep); -void command_spawn(Client *c, const Seperator *sep); -void command_texture(Client *c, const Seperator *sep); -void command_npctypespawn(Client *c, const Seperator *sep); -void command_heal(Client *c, const Seperator *sep); void command_appearance(Client *c, const Seperator *sep); -void command_nukeitem(Client *c, const Seperator *sep); -void command_peekinv(Client *c, const Seperator *sep); -void command_interrogateinv(Client *c, const Seperator *sep); -void command_findnpctype(Client *c, const Seperator *sep); -void command_findzone(Client *c, const Seperator *sep); -void command_viewnpctype(Client *c, const Seperator *sep); -void command_reloadqst(Client *c, const Seperator *sep); -void command_reloadworld(Client *c, const Seperator *sep); -void command_reloadzps(Client *c, const Seperator *sep); -void command_zoneshutdown(Client *c, const Seperator *sep); -void command_zonebootup(Client *c, const Seperator *sep); -void command_kick(Client *c, const Seperator *sep); +void command_apply_shared_memory(Client *c, const Seperator *sep); void command_attack(Client *c, const Seperator *sep); -void command_lock(Client *c, const Seperator *sep); -void command_unlock(Client *c, const Seperator *sep); -void command_motd(Client *c, const Seperator *sep); -void command_listpetition(Client *c, const Seperator *sep); -void command_equipitem(Client *c, const Seperator *sep); -void command_zonelock(Client *c, const Seperator *sep); -void command_corpse(Client *c, const Seperator *sep); -void command_fixmob(Client *c, const Seperator *sep); -void command_gmspeed(Client *c, const Seperator *sep); -void command_title(Client *c, const Seperator *sep); -void command_titlesuffix(Client *c, const Seperator *sep); -void command_spellinfo(Client *c, const Seperator *sep); -void command_lastname(Client *c, const Seperator *sep); -void command_memspell(Client *c, const Seperator *sep); -void command_save(Client *c, const Seperator *sep); -void command_showstats(Client *c, const Seperator *sep); -void command_mystats(Client *c, const Seperator *sep); -void command_myskills(Client *c, const Seperator *sep); -void command_depop(Client *c, const Seperator *sep); -void command_depopzone(Client *c, const Seperator *sep); -void command_repop(Client *c, const Seperator *sep); -void command_spawnstatus(Client *c, const Seperator *sep); -void command_nukebuffs(Client *c, const Seperator *sep); -void command_zuwcoords(Client *c, const Seperator *sep); -void command_zunderworld(Client *c, const Seperator *sep); -void command_zsafecoords(Client *c, const Seperator *sep); -void command_freeze(Client *c, const Seperator *sep); -void command_unfreeze(Client *c, const Seperator *sep); -void command_pvp(Client *c, const Seperator *sep); -void command_setxp(Client *c, const Seperator *sep); -void command_setpvppoints(Client *c, const Seperator *sep); -void command_name(Client *c, const Seperator *sep); -void command_tempname(Client *c, const Seperator *sep); -void command_npcspecialattk(Client *c, const Seperator *sep); -void command_kill(Client *c, const Seperator *sep); -void command_haste(Client *c, const Seperator *sep); -void command_damage(Client *c, const Seperator *sep); -void command_zonespawn(Client *c, const Seperator *sep); -void command_npcspawn(Client *c, const Seperator *sep); -void command_spawnfix(Client *c, const Seperator *sep); -void command_loc(Client *c, const Seperator *sep); -void command_goto(Client *c, const Seperator *sep); +void command_augmentitem(Client *c, const Seperator *sep); +void command_ban(Client *c, const Seperator *sep); +void command_beard(Client *c, const Seperator *sep); +void command_beardcolor(Client *c, const Seperator *sep); +void command_bind(Client* c, const Seperator *sep); + #ifdef BUGTRACK void command_bug(Client *c, const Seperator *sep); #endif -void command_iteminfo(Client *c, const Seperator *sep); -void command_uptime(Client *c, const Seperator *sep); -void command_flag(Client *c, const Seperator *sep); -void command_time(Client *c, const Seperator *sep); -void command_guild(Client *c, const Seperator *sep); -bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char* what, const char* value); -void command_zonestatus(Client *c, const Seperator *sep); -void command_manaburn(Client *c, const Seperator *sep); -void command_doanim(Client *c, const Seperator *sep); -void command_randomfeatures(Client *c, const Seperator *sep); -void command_face(Client *c, const Seperator *sep); -void command_helm(Client *c, const Seperator *sep); -void command_hair(Client *c, const Seperator *sep); -void command_haircolor(Client *c, const Seperator *sep); -void command_beard(Client *c, const Seperator *sep); -void command_beardcolor(Client *c, const Seperator *sep); -void command_tattoo(Client *c, const Seperator *sep); -void command_heritage(Client *c, const Seperator *sep); -void command_details(Client *c, const Seperator *sep); -void command_scribespells(Client *c, const Seperator *sep); -void command_unscribespells(Client *c, const Seperator *sep); -void command_wpinfo(Client *c, const Seperator *sep); -void command_wpadd(Client *c, const Seperator *sep); -void command_interrupt(Client *c, const Seperator *sep); + +void command_camerashake(Client *c, const Seperator *sep); +void command_castspell(Client *c, const Seperator *sep); +void command_chat(Client *c, const Seperator *sep); +void command_checklos(Client *c, const Seperator *sep); +void command_clearinvsnapshots(Client *c, const Seperator *sep); +void command_connectworldserver(Client *c, const Seperator *sep); +void command_corpse(Client *c, const Seperator *sep); +void command_crashtest(Client *c, const Seperator *sep); +void command_cvs(Client *c, const Seperator *sep); void command_d1(Client *c, const Seperator *sep); -void command_summonitem(Client *c, const Seperator *sep); +void command_damage(Client *c, const Seperator *sep); +void command_date(Client *c, const Seperator *sep); +void command_dbspawn2(Client *c, const Seperator *sep); +void command_delacct(Client *c, const Seperator *sep); +void command_deletegraveyard(Client *c, const Seperator *sep); +void command_delpetition(Client *c, const Seperator *sep); +void command_depop(Client *c, const Seperator *sep); +void command_depopzone(Client *c, const Seperator *sep); +void command_details(Client *c, const Seperator *sep); +void command_disablerecipe(Client *c, const Seperator *sep); +void command_disarmtrap(Client *c, const Seperator *sep); +void command_distance(Client *c, const Seperator *sep); +void command_doanim(Client *c, const Seperator *sep); +void command_emote(Client *c, const Seperator *sep); +void command_emotesearch(Client* c, const Seperator *sep); +void command_emoteview(Client* c, const Seperator *sep); +void command_enablerecipe(Client *c, const Seperator *sep); +void command_equipitem(Client *c, const Seperator *sep); +void command_face(Client *c, const Seperator *sep); +void command_findaliases(Client *c, const Seperator *sep); +void command_findnpctype(Client *c, const Seperator *sep); +void command_findspell(Client *c, const Seperator *sep); +void command_findzone(Client *c, const Seperator *sep); +void command_fixmob(Client *c, const Seperator *sep); +void command_flag(Client *c, const Seperator *sep); +void command_flagedit(Client *c, const Seperator *sep); +void command_flags(Client *c, const Seperator *sep); +void command_flymode(Client *c, const Seperator *sep); +void command_fov(Client *c, const Seperator *sep); +void command_freeze(Client *c, const Seperator *sep); +void command_gassign(Client *c, const Seperator *sep); +void command_gender(Client *c, const Seperator *sep); +void command_getplayerburiedcorpsecount(Client *c, const Seperator *sep); +void command_getvariable(Client *c, const Seperator *sep); +void command_ginfo(Client *c, const Seperator *sep); void command_giveitem(Client *c, const Seperator *sep); void command_givemoney(Client *c, const Seperator *sep); -void command_itemsearch(Client *c, const Seperator *sep); -void command_setaaxp(Client *c, const Seperator *sep); -void command_setaapts(Client *c, const Seperator *sep); -void command_setcrystals(Client *c, const Seperator *sep); -void command_stun(Client *c, const Seperator *sep); -void command_ban(Client *c, const Seperator *sep); -void command_suspend(Client *c, const Seperator *sep); +void command_globalview(Client* c, const Seperator *sep); +void command_gm(Client *c, const Seperator *sep); +void command_gmspeed(Client *c, const Seperator *sep); +void command_goto(Client *c, const Seperator *sep); +void command_grid(Client *c, const Seperator *sep); +void command_guild(Client *c, const Seperator *sep); +bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char* what, const char* value); +void command_guildapprove(Client *c, const Seperator *sep); +void command_guildcreate(Client *c, const Seperator *sep); +void command_guildlist(Client *c, const Seperator *sep); +void command_hair(Client *c, const Seperator *sep); +void command_haircolor(Client *c, const Seperator *sep); +void command_haste(Client *c, const Seperator *sep); +void command_hatelist(Client *c, const Seperator *sep); +void command_heal(Client *c, const Seperator *sep); +void command_helm(Client *c, const Seperator *sep); +void command_help(Client *c, const Seperator *sep); +void command_heritage(Client *c, const Seperator *sep); +void command_heromodel(Client *c, const Seperator *sep); +void command_hideme(Client *c, const Seperator *sep); +void command_hotfix(Client *c, const Seperator *sep); +void command_hp(Client *c, const Seperator *sep); +void command_incstat(Client *c, const Seperator *sep); +void command_instance(Client *c, const Seperator *sep); +void command_interrogateinv(Client *c, const Seperator *sep); +void command_interrupt(Client *c, const Seperator *sep); +void command_invsnapshot(Client *c, const Seperator *sep); +void command_invul(Client *c, const Seperator *sep); void command_ipban(Client *c, const Seperator *sep); -void command_oocmute(Client *c, const Seperator *sep); -void command_revoke(Client *c, const Seperator *sep); -void command_checklos(Client *c, const Seperator *sep); -void command_set_adventure_points(Client *c, const Seperator *sep); +void command_ipc(Client *c, const Seperator *sep); +void command_iplookup(Client *c, const Seperator *sep); +void command_iteminfo(Client *c, const Seperator *sep); +void command_itemsearch(Client *c, const Seperator *sep); +void command_itemtest(Client *c, const Seperator *sep); +void command_kick(Client *c, const Seperator *sep); +void command_kill(Client *c, const Seperator *sep); +void command_lastname(Client *c, const Seperator *sep); +void command_level(Client *c, const Seperator *sep); +void command_listnpcs(Client *c, const Seperator *sep); +void command_listpetition(Client *c, const Seperator *sep); +void command_load_shared_memory(Client *c, const Seperator *sep); +void command_loc(Client *c, const Seperator *sep); +void command_lock(Client *c, const Seperator *sep); +void command_logs(Client *c, const Seperator *sep); +void command_logtest(Client *c, const Seperator *sep); +void command_makepet(Client *c, const Seperator *sep); +void command_mana(Client *c, const Seperator *sep); +void command_manastat(Client *c, const Seperator *sep); +void command_max_all_skills(Client *c, const Seperator *sep); +void command_memspell(Client *c, const Seperator *sep); +void command_merchantcloseshop(Client *c, const Seperator *sep); +void command_merchantopenshop(Client *c, const Seperator *sep); +void command_modifynpcstat(Client *c, const Seperator *sep); +void command_motd(Client *c, const Seperator *sep); +void command_movechar(Client *c, const Seperator *sep); +void command_myskills(Client *c, const Seperator *sep); +void command_mysql(Client *c, const Seperator *sep); +void command_mysqltest(Client *c, const Seperator *sep); +void command_mystats(Client *c, const Seperator *sep); +void command_name(Client *c, const Seperator *sep); +void command_netstats(Client *c, const Seperator *sep); +void command_npccast(Client *c, const Seperator *sep); +void command_npcedit(Client *c, const Seperator *sep); +void command_npcemote(Client *c, const Seperator *sep); +void command_npcloot(Client *c, const Seperator *sep); void command_npcsay(Client *c, const Seperator *sep); void command_npcshout(Client *c, const Seperator *sep); -void command_npcemote(Client *c, const Seperator *sep); -void command_npcedit(Client *c, const Seperator *sep); -void command_timers(Client *c, const Seperator *sep); -void command_undye(Client *c, const Seperator *sep); -void command_undyeme(Client *c, const Seperator *sep); -void command_hp(Client *c, const Seperator *sep); -void command_ginfo(Client *c, const Seperator *sep); -void command_qglobal(Client *c, const Seperator *sep); -void command_path(Client *c, const Seperator *sep); -void command_ginfo(Client *c, const Seperator *sep); -void command_opcode(Client *c, const Seperator *sep); -void command_aggro(Client *c, const Seperator *sep); -void command_hatelist(Client *c, const Seperator *sep); -void command_aggrozone(Client *c, const Seperator *sep); -void command_reloadstatic(Client *c, const Seperator *sep); -void command_flags(Client *c, const Seperator *sep); -void command_flagedit(Client *c, const Seperator *sep); -void command_serverrules(Client *c, const Seperator *sep); -void command_acceptrules(Client *c, const Seperator *sep); -void command_guildcreate(Client *c, const Seperator *sep); -void command_guildapprove(Client *c, const Seperator *sep); -void command_guildlist(Client *c, const Seperator *sep); -void command_rules(Client *c, const Seperator *sep); -void command_task(Client *c, const Seperator *sep); -void command_reloadtitles(Client *c, const Seperator *sep); -void command_altactivate(Client *c, const Seperator *sep); -void command_refundaa(Client *c, const Seperator *sep); -void command_traindisc(Client *c, const Seperator *sep); -void command_deletegraveyard(Client *c, const Seperator *sep); -void command_setgraveyard(Client *c, const Seperator *sep); -void command_getplayerburriedcorpsecount(Client *c, const Seperator *sep); -void command_summonburriedplayercorpse(Client *c, const Seperator *sep); -void command_unscribespell(Client *c, const Seperator *sep); -void command_scribespell(Client *c, const Seperator *sep); -void command_refreshgroup(Client *c, const Seperator *sep); -void command_advnpcspawn(Client *c, const Seperator *sep); -void command_modifynpcstat(Client *c, const Seperator *sep); -void command_instance(Client *c, const Seperator *sep); -void command_setstartzone(Client *c, const Seperator *sep); -void command_netstats(Client *c, const Seperator *sep); -void command_object(Client* c, const Seperator *sep); -void command_raidloot(Client* c, const Seperator *sep); -void command_globalview(Client* c, const Seperator *sep); -void command_emoteview(Client* c, const Seperator *sep); -void command_reloademote(Client* c, const Seperator *sep); -void command_emotesearch(Client* c, const Seperator *sep); -void command_distance(Client *c, const Seperator *sep); -void command_cvs(Client *c, const Seperator *sep); -void command_max_all_skills(Client *c, const Seperator *sep); -void command_showbonusstats(Client *c, const Seperator *sep); -void command_reloadallrules(Client *c, const Seperator *sep); -void command_reloadworldrules(Client *c, const Seperator *sep); -void command_reloadlevelmods(Client *c, const Seperator *sep); -void command_camerashake(Client *c, const Seperator *sep); -void command_disarmtrap(Client *c, const Seperator *sep); -void command_sensetrap(Client *c, const Seperator *sep); -void command_picklock(Client *c, const Seperator *sep); -void command_qtest(Client *c, const Seperator *sep); -void command_mysql(Client *c, const Seperator *sep); -void command_xtargets(Client *c, const Seperator *sep); -void command_zopp(Client *c, const Seperator *sep); -void command_augmentitem(Client *c, const Seperator *sep); -void command_questerrors(Client *c, const Seperator *sep); -void command_enablerecipe(Client *c, const Seperator *sep); -void command_disablerecipe(Client *c, const Seperator *sep); -void command_showspellslist(Client *c, const Seperator *sep); +void command_npcspawn(Client *c, const Seperator *sep); +void command_npcspecialattk(Client *c, const Seperator *sep); +void command_npcstats(Client *c, const Seperator *sep); void command_npctype_cache(Client *c, const Seperator *sep); -void command_merchantopenshop(Client *c, const Seperator *sep); -void command_merchantcloseshop(Client *c, const Seperator *sep); -void command_shownumhits(Client *c, const Seperator *sep); -void command_tune(Client *c, const Seperator *sep); -void command_logtest(Client *c, const Seperator *sep); -void command_mysqltest(Client *c, const Seperator *sep); -void command_logs(Client *c, const Seperator *sep); - +void command_npctypespawn(Client *c, const Seperator *sep); +void command_nukebuffs(Client *c, const Seperator *sep); +void command_nukeitem(Client *c, const Seperator *sep); +void command_numauths(Client *c, const Seperator *sep); +void command_object(Client* c, const Seperator *sep); +void command_oocmute(Client *c, const Seperator *sep); +void command_opcode(Client *c, const Seperator *sep); +void command_optest(Client *c, const Seperator *sep); + +#ifdef PACKET_PROFILER +void command_packetprofile(Client *c, const Seperator *sep); +#endif + +void command_path(Client *c, const Seperator *sep); +void command_peekinv(Client *c, const Seperator *sep); +void command_peqzone(Client *c, const Seperator *sep); +void command_permaclass(Client *c, const Seperator *sep); +void command_permagender(Client *c, const Seperator *sep); +void command_permarace(Client *c, const Seperator *sep); +void command_petitioninfo(Client *c, const Seperator *sep); +void command_picklock(Client *c, const Seperator *sep); + #ifdef EQPROFILE void command_profiledump(Client *c, const Seperator *sep); void command_profilereset(Client *c, const Seperator *sep); #endif -#ifdef PACKET_PROFILER -void command_packetprofile(Client *c, const Seperator *sep); -#endif +void command_pvp(Client *c, const Seperator *sep); +void command_qglobal(Client *c, const Seperator *sep); +void command_qtest(Client *c, const Seperator *sep); +void command_questerrors(Client *c, const Seperator *sep); +void command_race(Client *c, const Seperator *sep); +void command_raidloot(Client* c, const Seperator *sep); +void command_randomfeatures(Client *c, const Seperator *sep); +void command_refreshgroup(Client *c, const Seperator *sep); +void command_refundaa(Client *c, const Seperator *sep); +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_reloadperlexportsettings(Client *c, const Seperator *sep); +void command_reloadqst(Client *c, const Seperator *sep); +void command_reloadstatic(Client *c, const Seperator *sep); +void command_reloadtitles(Client *c, const Seperator *sep); +void command_reloadworld(Client *c, const Seperator *sep); +void command_reloadworldrules(Client *c, const Seperator *sep); +void command_reloadzps(Client *c, const Seperator *sep); +void command_repop(Client *c, const Seperator *sep); +void command_repopclose(Client *c, const Seperator *sep); +void command_resetaa(Client* c,const Seperator *sep); +void command_resetaa_timer(Client *c, const Seperator *sep); +void command_revoke(Client *c, const Seperator *sep); +void command_rules(Client *c, const Seperator *sep); +void command_save(Client *c, const Seperator *sep); +void command_scribespell(Client *c, const Seperator *sep); +void command_scribespells(Client *c, const Seperator *sep); +void command_sendop(Client *c, const Seperator *sep); +void command_sendzonespawns(Client *c, const Seperator *sep); +void command_sensetrap(Client *c, const Seperator *sep); +void command_serverinfo(Client *c, const Seperator *sep); +void command_serverrules(Client *c, const Seperator *sep); +void command_serversidename(Client *c, const Seperator *sep); +void command_set_adventure_points(Client *c, const Seperator *sep); +void command_setaapts(Client *c, const Seperator *sep); +void command_setaaxp(Client *c, const Seperator *sep); +void command_setanim(Client *c, const Seperator *sep); +void command_setcrystals(Client *c, const Seperator *sep); +void command_setfaction(Client *c, const Seperator *sep); +void command_setgraveyard(Client *c, const Seperator *sep); +void command_setlanguage(Client *c, const Seperator *sep); +void command_setlsinfo(Client *c, const Seperator *sep); +void command_setpass(Client *c, const Seperator *sep); +void command_setpvppoints(Client *c, const Seperator *sep); +void command_setskill(Client *c, const Seperator *sep); +void command_setskillall(Client *c, const Seperator *sep); +void command_setstartzone(Client *c, const Seperator *sep); +void command_setstat(Client *c, const Seperator *sep); +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_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_shutdown(Client *c, const Seperator *sep); +void command_size(Client *c, const Seperator *sep); +void command_spawn(Client *c, const Seperator *sep); +void command_spawnfix(Client *c, const Seperator *sep); +void command_spawnstatus(Client *c, const Seperator *sep); +void command_spellinfo(Client *c, const Seperator *sep); +void command_spoff(Client *c, const Seperator *sep); +void command_spon(Client *c, const Seperator *sep); +void command_stun(Client *c, const Seperator *sep); +void command_summon(Client *c, const Seperator *sep); +void command_summonburiedplayercorpse(Client *c, const Seperator *sep); +void command_summonitem(Client *c, const Seperator *sep); +void command_suspend(Client *c, const Seperator *sep); +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_testspawn(Client *c, const Seperator *sep); +void command_testspawnkill(Client *c, const Seperator *sep); +void command_texture(Client *c, const Seperator *sep); +void command_time(Client *c, const Seperator *sep); +void command_timers(Client *c, const Seperator *sep); +void command_timezone(Client *c, const Seperator *sep); +void command_title(Client *c, const Seperator *sep); +void command_titlesuffix(Client *c, const Seperator *sep); +void command_traindisc(Client *c, const Seperator *sep); +void command_tune(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); +void command_unlock(Client *c, const Seperator *sep); +void command_unscribespell(Client *c, const Seperator *sep); +void command_unscribespells(Client *c, const Seperator *sep); +void command_untraindisc(Client *c, const Seperator *sep); +void command_untraindiscs(Client *c, const Seperator *sep); +void command_uptime(Client *c, const Seperator *sep); +void command_version(Client *c, const Seperator *sep); +void command_viewnpctype(Client *c, const Seperator *sep); +void command_viewpetition(Client *c, const Seperator *sep); +void command_wc(Client *c, const Seperator *sep); +void command_weather(Client *c, const Seperator *sep); +void command_worldshutdown(Client *c, const Seperator *sep); +void command_wp(Client *c, const Seperator *sep); +void command_wpadd(Client *c, const Seperator *sep); +void command_wpinfo(Client *c, const Seperator *sep); +void command_xtargets(Client *c, const Seperator *sep); +void command_zclip(Client *c, const Seperator *sep); +void command_zcolor(Client *c, const Seperator *sep); +void command_zheader(Client *c, const Seperator *sep); +void command_zone(Client *c, const Seperator *sep); +void command_zone_instance(Client *c, const Seperator *sep); +void command_zonebootup(Client *c, const Seperator *sep); +void command_zonelock(Client *c, const Seperator *sep); +void command_zoneshutdown(Client *c, const Seperator *sep); +void command_zonespawn(Client *c, const Seperator *sep); +void command_zonestatus(Client *c, const Seperator *sep); +void command_zopp(Client *c, const Seperator *sep); +void command_zsafecoords(Client *c, const Seperator *sep); +void command_zsave(Client *c, const Seperator *sep); +void command_zsky(Client *c, const Seperator *sep); +void command_zstats(Client *c, const Seperator *sep); +void command_zunderworld(Client *c, const Seperator *sep); +void command_zuwcoords(Client *c, const Seperator *sep); #ifdef BOTS #include "bot.h" @@ -341,4 +338,3 @@ void command_bot(Client*c, const Seperator *sep); #endif #endif - diff --git a/zone/common.h b/zone/common.h index 56ab6f819..9a5768c56 100644 --- a/zone/common.h +++ b/zone/common.h @@ -17,12 +17,6 @@ #define _NPCPET(x) (x && x->IsNPC() && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsNPC()) #define _BECOMENPCPET(x) (x && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsClient() && x->CastToMob()->GetOwner()->CastToClient()->IsBecomeNPC()) -#define USE_ITEM_SPELL_SLOT 10 -#define POTION_BELT_SPELL_SLOT 11 -#define TARGET_RING_SPELL_SLOT 12 -#define DISCIPLINE_SPELL_SLOT 10 -#define ABILITY_SPELL_SLOT 9 - //LOS Parameters: #define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from #define SEE_POSITION 0.5f //ratio of GetSize() where NPCs try to see for LOS @@ -61,6 +55,7 @@ typedef enum { //focus types focusManaCost, focusImprovedHeal, focusImprovedDamage, + focusImprovedDamage2, focusImprovedDOT, //i dont know about this... focusFcDamagePctCrit, focusImprovedUndeadDamage, @@ -72,6 +67,7 @@ typedef enum { //focus types focusTwincast, focusSympatheticProc, focusFcDamageAmt, + focusFcDamageAmt2, focusFcDamageAmtCrit, focusSpellDurByTic, focusSwarmPetDuration, @@ -137,7 +133,8 @@ enum { IGNORE_ROOT_AGGRO_RULES = 42, CASTING_RESIST_DIFF = 43, COUNTER_AVOID_DAMAGE = 44, - MAX_SPECIAL_ATTACK = 45 + PROX_AGGRO = 45, + MAX_SPECIAL_ATTACK = 46 }; typedef enum { //fear states @@ -173,6 +170,28 @@ enum class NumHit { // Numhits type OffensiveSpellProcs = 11 // Offensive buff procs }; +enum class PlayerState : uint32 { + None = 0, + Open = 1, + WeaponSheathed = 2, + Aggressive = 4, + ForcedAggressive = 8, + InstrumentEquipped = 16, + Stunned = 32, + PrimaryWeaponEquipped = 64, + SecondaryWeaponEquipped = 128 +}; + +enum class LootResponse : uint8 { + SomeoneElse = 0, + Normal = 1, + NotAtThisTime = 2, + Normal2 = 3, // acts exactly the same as Normal, maybe group vs ungroup? No idea + Hostiles = 4, + TooFar = 5, + LootAll = 6 // SoD+ +}; + //this is our internal representation of the BUFF struct, can put whatever we want in it struct Buffs_Struct { uint16 spellid; @@ -190,6 +209,7 @@ struct Buffs_Struct { int32 caston_z; int32 ExtraDIChance; int16 RootBreakChance; //Not saved to dbase + uint32 instrument_mod; bool persistant_buff; bool client; //True if the caster is a client bool UpdateClient; @@ -260,7 +280,8 @@ struct StatBonuses { int32 inhibitmelee; float AggroRange; // when calculate just replace original value with this float AssistRange; - int32 skillmod[HIGHEST_SKILL+1]; + int32 skillmod[EQEmu::skills::HIGHEST_SKILL + 1]; + int32 skillmodmax[EQEmu::skills::HIGHEST_SKILL + 1]; int effective_casting_level; int reflect_chance; // chance to reflect incoming spell uint32 singingMod; @@ -276,7 +297,7 @@ struct StatBonuses { int32 StrikeThrough; // PoP: Strike Through % int32 MeleeMitigation; //i = Shielding int32 MeleeMitigationEffect; //i = Spell Effect Melee Mitigation - int32 CriticalHitChance[HIGHEST_SKILL+2]; //i + int32 CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 2]; //i int32 CriticalSpellChance; //i int32 SpellCritDmgIncrease; //i int32 SpellCritDmgIncNoStack; // increase @@ -303,10 +324,10 @@ struct StatBonuses { int32 MeleeSkillCheck; //i uint8 MeleeSkillCheckSkill; int32 HitChance; //HitChance/15 == % increase i = Accuracy (Item: Accuracy) - int32 HitChanceEffect[HIGHEST_SKILL+2]; //Spell effect Chance to Hit, straight percent increase - int32 DamageModifier[HIGHEST_SKILL+2]; //i - int32 DamageModifier2[HIGHEST_SKILL+2]; //i - int32 MinDamageModifier[HIGHEST_SKILL+2]; //i + int32 HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 2]; //Spell effect Chance to Hit, straight percent increase + int32 DamageModifier[EQEmu::skills::HIGHEST_SKILL + 2]; //i + int32 DamageModifier2[EQEmu::skills::HIGHEST_SKILL + 2]; //i + int32 MinDamageModifier[EQEmu::skills::HIGHEST_SKILL + 2]; //i int32 ProcChance; // ProcChance/10 == % increase i = CombatEffects int32 ProcChanceSPA; // ProcChance from spell effects int32 ExtraAttackChance; @@ -314,13 +335,13 @@ struct StatBonuses { int32 DivineSaveChance[2]; // Second Chance (base1 = chance, base2 = spell on trigger) uint32 DeathSave[4]; // Death Pact [0](value = 1 partial 2 = full) [1]=slot [2]=LvLimit [3]=HealAmt int32 FlurryChance; - int32 Accuracy[HIGHEST_SKILL+2]; //Accuracy/15 == % increase [Spell Effect: Accuracy) + int32 Accuracy[EQEmu::skills::HIGHEST_SKILL + 2]; //Accuracy/15 == % increase [Spell Effect: Accuracy) int32 HundredHands; //extra haste, stacks with all other haste i int32 MeleeLifetap; //i int32 Vampirism; //i int32 HealRate; // Spell effect that influences effectiveness of heals int32 MaxHPChange; // Spell Effect - int16 SkillDmgTaken[HIGHEST_SKILL+2]; // All Skills + -1 + int16 SkillDmgTaken[EQEmu::skills::HIGHEST_SKILL + 2]; // All Skills + -1 int32 HealAmt; // Item Effect int32 SpellDmg; // Item Effect int32 Clairvoyance; // Item Effect @@ -329,9 +350,9 @@ struct StatBonuses { uint32 SpellTriggers[MAX_SPELL_TRIGGER]; // Innate/Spell/Item Spells that trigger when you cast uint32 SpellOnKill[MAX_SPELL_TRIGGER*3]; // Chance to proc after killing a mob uint32 SpellOnDeath[MAX_SPELL_TRIGGER*2]; // Chance to have effect cast when you die - int32 CritDmgMob[HIGHEST_SKILL+2]; // All Skills + -1 - int32 SkillReuseTime[HIGHEST_SKILL+1]; // Reduces skill timers - int32 SkillDamageAmount[HIGHEST_SKILL+2]; // All Skills + -1 + int32 CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 2]; // All Skills + -1 + int32 SkillReuseTime[EQEmu::skills::HIGHEST_SKILL + 1]; // Reduces skill timers + int32 SkillDamageAmount[EQEmu::skills::HIGHEST_SKILL + 2]; // All Skills + -1 int32 TwoHandBluntBlock; // chance to block when wielding two hand blunt weapon uint32 ItemManaRegenCap; // Increases the amount of mana you have can over the cap(aa effect) int32 GravityEffect; // Indictor of spell effect @@ -354,7 +375,7 @@ struct StatBonuses { uint8 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have. int16 FocusEffectsWorn[HIGHEST_FOCUS+1]; // Optional to allow focus effects to be applied additively from worn slot bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses) - int32 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage + int32 SkillDamageAmount2[EQEmu::skills::HIGHEST_SKILL + 2]; // Adds skill specific damage uint32 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit uint32 MitigateMeleeRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per hit 3 = Rune Amt uint32 MeleeThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. @@ -387,10 +408,11 @@ struct StatBonuses { int32 Metabolism; // Food/drink consumption rates. bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others. int32 FactionModPct; // Modifies amount of faction gained. - int32 MeleeVulnerability; // Weakness/mitigation to melee damage - bool LimitToSkill[HIGHEST_SKILL+2]; // Determines if we need to search for a skill proc. + bool LimitToSkill[EQEmu::skills::HIGHEST_SKILL + 2]; // Determines if we need to search for a skill proc. uint32 SkillProc[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs. uint32 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success. + uint32 PC_Pet_Rampage[2]; // 0= % chance to rampage, 1=damage modifier + uint32 PC_Pet_Flurry; // Percent chance flurry from double attack // AAs int8 Packrat; //weight reduction for items, 1 point = 10% @@ -399,7 +421,7 @@ struct StatBonuses { int8 BaseMovementSpeed; // Adjust base run speed, does not stack with other movement bonuses. uint8 IncreaseRunSpeedCap; // Increase max run speed above cap. int32 DoubleSpecialAttack; // Chance to to perform a double special attack (ie flying kick 2x) - int32 SpecialAttackKBProc[2]; // Chance to to do a knockback from special attacks. (0 = chance 1 = Skill) + int32 SkillAttackProc[3]; // [0] chance to proc [2] spell on [1] skill usage uint8 FrontalStunResist; // Chance to resist a frontal stun int32 BindWound; // Increase amount of HP by percent. int32 MaxBindWound; // Increase max amount of HP you can bind wound. @@ -421,7 +443,7 @@ struct StatBonuses { int32 CombatStability; // Melee damage mitigation. int32 DoubleRiposte; // Chance to double riposte int32 GiveDoubleRiposte[3]; // 0=Regular Chance, 1=Skill Attack Chance, 2=Skill - uint32 RaiseSkillCap[2]; // Raise a specific skill cap (1 = value, 2=skill) + uint32 RaiseSkillCap[EQEmu::skills::HIGHEST_SKILL + 1]; // Raise a specific skill cap (base1= value, base2=skill) int32 Ambidexterity; // Increase chance to duel wield by adding bonus 'skill'. int32 PetMaxHP; // Increase the max hp of your pet. int32 PetFlurry; // Chance for pet to flurry. @@ -438,7 +460,7 @@ struct StatBonuses { int32 ShieldEquipHateMod; // Hate mod when shield equiped. int32 ShieldEquipDmgMod[2]; // Damage mod when shield equiped. 0 = damage modifier 1 = Unknown bool TriggerOnValueAmount; // Triggers off various different conditions, bool to check if client has effect. - int8 StunBashChance; // chance to stun with bash. + int8 StunBashChance; // chance to stun with bash. int8 IncreaseChanceMemwipe; // increases chance to memory wipe int8 CriticalMend; // chance critical monk mend int32 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy @@ -448,6 +470,13 @@ struct StatBonuses { uint8 AssassinateLevel; // Max Level Assassinate will be effective at. int32 PetMeleeMitigation; // Add AC to owner's pet. bool IllusionPersistence; // Causes illusions not to fade. + uint16 extra_xtargets; // extra xtarget entries + bool ShroudofStealth; // rogue improved invisiblity + uint16 ReduceFallDamage; // reduce fall damage by percent + int32 ReduceTradeskillFail[EQEmu::skills::HIGHEST_SKILL + 1]; // Reduces chance for trade skills to fail by percent. + uint8 TradeSkillMastery; // Allow number of tradeskills to exceed 200 skill. + int16 NoBreakAESneak; // Percent value + int16 FeignedCastOnChance; // Percent Value }; typedef struct @@ -455,6 +484,7 @@ typedef struct uint16 spellID; uint16 chance; uint16 base_spellID; + int level_override; } tProc; struct Shielders_Struct { @@ -484,7 +514,7 @@ typedef struct //make DoAnim take it instead of int, to enforce its use. enum { //type arguments to DoAnim animKick = 1, - animPiercing = 2, //might be piercing? + anim1HPiercing = 2, //might be piercing? anim2HSlashing = 3, anim2HWeapon = 4, anim1HWeapon = 5, @@ -507,7 +537,8 @@ typedef enum { petOther, petCharmed, petNPCFollow, - petTargetLock //remain active as long something is on the hatelist. Don't listen to any commands + petTargetLock, //remain active as long something is on the hatelist. Don't listen to any commands + petNone = 0xFF // not a pet } PetType; typedef enum { @@ -586,7 +617,8 @@ struct ExtraAttackOptions { : damage_percent(1.0f), damage_flat(0), armor_pen_percent(0.0f), armor_pen_flat(0), crit_percent(1.0f), crit_flat(0.0f), - hate_percent(1.0f), hate_flat(0), hit_chance(0) + hate_percent(1.0f), hate_flat(0), hit_chance(0), + melee_damage_bonus_flat(0), skilldmgtaken_bonus_flat(0) { } float damage_percent; @@ -598,6 +630,9 @@ struct ExtraAttackOptions { float hate_percent; int hate_flat; int hit_chance; + int melee_damage_bonus_flat; + int skilldmgtaken_bonus_flat; + }; #endif diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 73205f2fc..492ed8121 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -22,8 +22,10 @@ Child of the Mob class. */ #ifdef _WINDOWS - #define snprintf _snprintf - #define vsnprintf _vsnprintf + #if (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER < 1900)) + #define snprintf _snprintf + #define vsnprintf _vsnprintf + #endif #define strncasecmp _strnicmp #define strcasecmp _stricmp #endif @@ -32,6 +34,7 @@ Child of the Mob class. #include "../common/eqemu_logsys.h" #include "../common/rulesys.h" #include "../common/string_util.h" +#include "../common/say_link.h" #include "client.h" #include "corpse.h" @@ -57,15 +60,15 @@ extern WorldServer worldserver; extern npcDecayTimes_Struct npcCorpseDecayTimes[100]; void Corpse::SendEndLootErrorPacket(Client* client) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_LootComplete, 0); + auto outapp = new EQApplicationPacket(OP_LootComplete, 0); client->QueuePacket(outapp); safe_delete(outapp); } -void Corpse::SendLootReqErrorPacket(Client* client, uint8 response) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct)); +void Corpse::SendLootReqErrorPacket(Client* client, LootResponse response) { + auto outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct)); moneyOnCorpseStruct* d = (moneyOnCorpseStruct*) outapp->pBuffer; - d->response = response; + d->response = static_cast(response); d->unknown1 = 0x5a; d->unknown2 = 0x40; client->QueuePacket(outapp); @@ -74,7 +77,8 @@ void Corpse::SendLootReqErrorPacket(Client* client, uint8 response) { Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard) { uint32 item_count = database.GetCharacterCorpseItemCount(in_dbid); - char *buffer = new char[sizeof(PlayerCorpse_Struct) + (item_count * sizeof(player_lootitem::ServerLootItem_Struct))]; + auto buffer = + new char[sizeof(PlayerCorpse_Struct) + (item_count * sizeof(player_lootitem::ServerLootItem_Struct))]; PlayerCorpse_Struct *pcs = (PlayerCorpse_Struct*)buffer; database.LoadCharacterCorpseData(in_dbid, pcs); @@ -88,41 +92,40 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std: } /* Create Corpse Entity */ - Corpse* pc = new Corpse( - in_dbid, // uint32 in_dbid - in_charid, // uint32 in_charid - in_charname.c_str(), // char* in_charname - &itemlist, // ItemList* in_itemlist - pcs->copper, // uint32 in_copper - pcs->silver, // uint32 in_silver - pcs->gold, // uint32 in_gold - pcs->plat, // uint32 in_plat - position, - pcs->size, // float in_size - pcs->gender, // uint8 in_gender - pcs->race, // uint16 in_race - pcs->class_, // uint8 in_class - pcs->deity, // uint8 in_deity - pcs->level, // uint8 in_level - pcs->texture, // uint8 in_texture - pcs->helmtexture, // uint8 in_helmtexture - pcs->exp, // uint32 in_rezexp - was_at_graveyard // bool wasAtGraveyard - ); + auto pc = new Corpse(in_dbid, // uint32 in_dbid + in_charid, // uint32 in_charid + in_charname.c_str(), // char* in_charname + &itemlist, // ItemList* in_itemlist + pcs->copper, // uint32 in_copper + pcs->silver, // uint32 in_silver + pcs->gold, // uint32 in_gold + pcs->plat, // uint32 in_plat + position, + pcs->size, // float in_size + pcs->gender, // uint8 in_gender + pcs->race, // uint16 in_race + pcs->class_, // uint8 in_class + pcs->deity, // uint8 in_deity + pcs->level, // uint8 in_level + pcs->texture, // uint8 in_texture + pcs->helmtexture, // uint8 in_helmtexture + pcs->exp, // uint32 in_rezexp + was_at_graveyard // bool wasAtGraveyard + ); if (pcs->locked) pc->Lock(); /* Load Item Tints */ - pc->item_tint[0].Color = pcs->item_tint[0].Color; - pc->item_tint[1].Color = pcs->item_tint[1].Color; - pc->item_tint[2].Color = pcs->item_tint[2].Color; - pc->item_tint[3].Color = pcs->item_tint[3].Color; - pc->item_tint[4].Color = pcs->item_tint[4].Color; - pc->item_tint[5].Color = pcs->item_tint[5].Color; - pc->item_tint[6].Color = pcs->item_tint[6].Color; - pc->item_tint[7].Color = pcs->item_tint[7].Color; - pc->item_tint[8].Color = pcs->item_tint[8].Color; + pc->item_tint.Head.Color = pcs->item_tint.Head.Color; + pc->item_tint.Chest.Color = pcs->item_tint.Chest.Color; + pc->item_tint.Arms.Color = pcs->item_tint.Arms.Color; + pc->item_tint.Wrist.Color = pcs->item_tint.Wrist.Color; + pc->item_tint.Hands.Color = pcs->item_tint.Hands.Color; + pc->item_tint.Legs.Color = pcs->item_tint.Legs.Color; + pc->item_tint.Feet.Color = pcs->item_tint.Feet.Color; + pc->item_tint.Primary.Color = pcs->item_tint.Primary.Color; + pc->item_tint.Secondary.Color = pcs->item_tint.Secondary.Color; /* Load Physical Appearance */ pc->haircolor = pcs->haircolor; @@ -138,10 +141,8 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std: pc->IsRezzed(rezzed); pc->become_npc = false; - pc->m_Light.Level.Innate = pc->m_Light.Type.Innate = 0; pc->UpdateEquipmentLight(); // itemlist populated above..need to determine actual values - pc->m_Light.Level.Spell = pc->m_Light.Type.Spell = 0; - + safe_delete_array(pcs); return pc; @@ -153,7 +154,7 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP in_npc->GetDeity(),in_npc->GetLevel(),in_npc->GetNPCTypeID(),in_npc->GetSize(),0, in_npc->GetPosition(), in_npc->GetInnateLightType(), in_npc->GetTexture(),in_npc->GetHelmTexture(), 0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0xff,0,0,0,0,0,0,0,0,0), + 0,0,0,0,0,0,0,0,0,0,EQEmu::TintProfile(),0xff,0,0,0,0,0,0,0,0,0,0,0,0,0,0), corpse_decay_timer(in_decaytime), corpse_rez_timer(0), corpse_delay_timer(RuleI(NPC, CorpseUnlockTimer)), @@ -162,8 +163,6 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP { corpse_graveyard_timer.Disable(); - memset(item_tint, 0, sizeof(item_tint)); - is_corpse_changed = false; is_player_corpse = false; is_locked = false; @@ -244,7 +243,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( client->GetPP().drakkin_heritage, // uint32 in_drakkin_heritage, client->GetPP().drakkin_tattoo, // uint32 in_drakkin_tattoo, client->GetPP().drakkin_details, // uint32 in_drakkin_details, - 0, // uint32 in_armor_tint[_MaterialCount], + EQEmu::TintProfile(), // uint32 in_armor_tint[_MaterialCount], 0xff, // uint8 in_aa_title, 0, // uint8 in_see_invis, // see through invis 0, // uint8 in_see_invis_undead, // see through invis vs. undead @@ -254,7 +253,12 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( 0, // int32 in_mana_regen, 0, // uint8 in_qglobal, 0, // uint8 in_maxlevel, - 0 // uint32 in_scalerate + 0, // uint32 in_scalerate + 0, // uint8 in_armtexture, + 0, // uint8 in_bracertexture, + 0, // uint8 in_handtexture, + 0, // uint8 in_legtexture, + 0 // uint8 in_feettexture, ), corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)), corpse_rez_timer(RuleI(Character, CorpseResTimeMS)), @@ -272,8 +276,6 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( corpse_graveyard_timer.Disable(); } - memset(item_tint, 0, sizeof(item_tint)); - for (i = 0; i < MAX_LOOTERS; i++){ allowed_looters[i] = 0; } @@ -307,7 +309,7 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( // cash // Let's not move the cash when 'RespawnFromHover = true' && 'client->GetClientVersion() < EQClientSoF' since the client doesn't. // (change to first client that supports 'death hover' mode, if not SoF.) - if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < ClientVersion::SoF) { + if (!RuleB(Character, RespawnFromHover) || client->ClientVersion() < EQEmu::versions::ClientVersion::SoF) { SetCash(pp->copper, pp->silver, pp->gold, pp->platinum); pp->copper = 0; pp->silver = 0; @@ -316,18 +318,18 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( } // get their tints - memcpy(item_tint, &client->GetPP().item_tint, sizeof(item_tint)); + memcpy(&item_tint.Slot, &client->GetPP().item_tint, sizeof(item_tint)); // TODO soulbound items need not be added to corpse, but they need // to go into the regular slots on the player, out of bags std::list removed_list; - for(i = MAIN_BEGIN; i < EmuConstants::MAP_POSSESSIONS_SIZE; ++i) { - if(i == MainAmmo && client->GetClientVersion() >= ClientVersion::SoF) { - item = client->GetInv().GetItem(MainPowerSource); + for (i = SLOT_BEGIN; i < EQEmu::legacy::TYPE_POSSESSIONS_SIZE; ++i) { + if (i == EQEmu::legacy::SlotAmmo && client->ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { + item = client->GetInv().GetItem(EQEmu::legacy::SlotPowerSource); if (item != nullptr) { if (!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent)) - MoveItemToCorpse(client, item, MainPowerSource, removed_list); + MoveItemToCorpse(client, item, EQEmu::legacy::SlotPowerSource, removed_list); } } @@ -403,10 +405,10 @@ void Corpse::MoveItemToCorpse(Client *client, ItemInst *inst, int16 equipSlot, s removedList.push_back(equipSlot); while (true) { - if (!inst->IsType(ItemClassContainer)) { break; } - if (equipSlot < EmuConstants::GENERAL_BEGIN || equipSlot > MainCursor) { break; } + if (!inst->IsClassBag()) { break; } + if (equipSlot < EQEmu::legacy::GENERAL_BEGIN || equipSlot > EQEmu::legacy::SlotCursor) { break; } - for (auto sub_index = SUB_BEGIN; sub_index < EmuConstants::ITEM_CONTAINER_SIZE; ++sub_index) { + for (auto sub_index = SUB_INDEX_BEGIN; sub_index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++sub_index) { int16 real_bag_slot = Inventory::CalcSlotId(equipSlot, sub_index); auto bag_inst = client->GetInv().GetItem(real_bag_slot); if (bag_inst == nullptr) { continue; } @@ -469,7 +471,7 @@ in_helmtexture, 0, 0, 0, -0, +EQEmu::TintProfile(), 0xff, 0, 0, @@ -479,6 +481,11 @@ in_helmtexture, 0, 0, 0, +0, +0, +0, +0, +0, 0), corpse_decay_timer(RuleI(Character, CorpseDecayTimeMS)), corpse_rez_timer(RuleI(Character, CorpseResTimeMS)), @@ -492,8 +499,6 @@ in_helmtexture, if (!zone->HasGraveyard() || wasAtGraveyard) corpse_graveyard_timer.Disable(); - memset(item_tint, 0, sizeof(item_tint)); - is_corpse_changed = false; is_player_corpse = true; is_locked = false; @@ -520,7 +525,6 @@ in_helmtexture, SetPlayerKillItemID(0); UpdateEquipmentLight(); - m_Light.Level.Spell = m_Light.Type.Spell = 0; UpdateActiveLight(); } @@ -582,7 +586,7 @@ bool Corpse::Save() { dbpc->helmtexture = this->helmtexture; dbpc->exp = rez_experience; - memcpy(dbpc->item_tint, item_tint, sizeof(dbpc->item_tint)); + memcpy(&dbpc->item_tint.Slot, &item_tint.Slot, sizeof(dbpc->item_tint)); dbpc->haircolor = haircolor; dbpc->beardcolor = beardcolor; dbpc->eyecolor2 = eyecolor1; @@ -657,7 +661,7 @@ void Corpse::AddItem(uint32 itemnum, uint16 charges, int16 slot, uint32 aug1, ui is_corpse_changed = true; - ServerLootItem_Struct* item = new ServerLootItem_Struct; + auto item = new ServerLootItem_Struct; memset(item, 0, sizeof(ServerLootItem_Struct)); item->item_id = itemnum; @@ -689,7 +693,7 @@ ServerLootItem_Struct* Corpse::GetItem(uint16 lootslot, ServerLootItem_Struct** } if (sitem && bag_item_data && Inventory::SupportsContainers(sitem->equip_slot)) { - int16 bagstart = Inventory::CalcSlotId(sitem->equip_slot, SUB_BEGIN); + int16 bagstart = Inventory::CalcSlotId(sitem->equip_slot, SUB_INDEX_BEGIN); cur = itemlist.begin(); end = itemlist.end(); @@ -744,7 +748,7 @@ void Corpse::RemoveItem(ServerLootItem_Struct* item_data) itemlist.erase(iter); uint8 material = Inventory::CalcMaterialFromSlot(sitem->equip_slot); // autos to unsigned char - if (material != _MaterialInvalid) + if (material != EQEmu::textures::TextureInvalid) SendWearChange(material); UpdateEquipmentLight(); @@ -797,7 +801,7 @@ bool Corpse::Process() { database.SendCharacterCorpseToGraveyard(corpse_db_id, zone->graveyard_zoneid(), (zone->GetZoneID() == zone->graveyard_zoneid()) ? zone->GetInstanceID() : 0, zone->GetGraveyardPoint()); corpse_graveyard_timer.Disable(); - ServerPacket* pack = new ServerPacket(ServerOP_SpawnPlayerCorpse, sizeof(SpawnPlayerCorpse_Struct)); + auto pack = new ServerPacket(ServerOP_SpawnPlayerCorpse, sizeof(SpawnPlayerCorpse_Struct)); SpawnPlayerCorpse_Struct* spc = (SpawnPlayerCorpse_Struct*)pack->pBuffer; spc->player_corpse_id = corpse_db_id; spc->zone_id = zone->graveyard_zoneid(); @@ -833,7 +837,7 @@ bool Corpse::Process() { Save(); player_corpse_depop = true; corpse_db_id = 0; - Log.Out(Logs::General, Logs::None, "Tagged %s player corpse has burried.", this->GetName()); + Log.Out(Logs::General, Logs::None, "Tagged %s player corpse has buried.", this->GetName()); } else { Log.Out(Logs::General, Logs::Error, "Unable to bury %s player corpse.", this->GetName()); @@ -879,9 +883,8 @@ void Corpse::AllowPlayerLoot(Mob *them, uint8 slot) { void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* app) { // Added 12/08. Started compressing loot struct on live. - char tmp[10]; if(player_corpse_depop) { - SendLootReqErrorPacket(client, 0); + SendLootReqErrorPacket(client, LootResponse::SomeoneElse); return; } @@ -893,7 +896,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a } if(is_locked && client->Admin() < 100) { - SendLootReqErrorPacket(client, 0); + SendLootReqErrorPacket(client, LootResponse::SomeoneElse); client->Message(13, "Error: Corpse locked by GM."); return; } @@ -904,17 +907,24 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a if(this->being_looted_by != 0xFFFFFFFF) { // lets double check.... Entity* looter = entity_list.GetID(this->being_looted_by); - if(looter == 0) + if(looter == nullptr) this->being_looted_by = 0xFFFFFFFF; } uint8 Loot_Request_Type = 1; bool loot_coin = false; - if(database.GetVariable("LootCoin", tmp, 9)) - loot_coin = (atoi(tmp) == 1); + std::string tmp; + if(database.GetVariable("LootCoin", tmp)) + loot_coin = tmp[0] == 1 && tmp[1] == '\0'; - if (this->being_looted_by != 0xFFFFFFFF && this->being_looted_by != client->GetID()) { - SendLootReqErrorPacket(client, 0); + if (DistanceSquaredNoZ(client->GetPosition(), m_Position) > 625) { + SendLootReqErrorPacket(client, LootResponse::TooFar); + // not sure if we need to send the packet back in this case? Didn't before! + // Will just return for now + return; + } + else if (this->being_looted_by != 0xFFFFFFFF && this->being_looted_by != client->GetID()) { + SendLootReqErrorPacket(client, LootResponse::SomeoneElse); Loot_Request_Type = 0; } else if (IsPlayerCorpse() && char_id == client->CharacterID()) { @@ -935,16 +945,17 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a if (Loot_Request_Type == 1) { if (client->Admin() < 100 || !client->GetGM()) { - SendLootReqErrorPacket(client, 2); + SendLootReqErrorPacket(client, LootResponse::NotAtThisTime); } } if(Loot_Request_Type >= 2 || (Loot_Request_Type == 1 && client->Admin() >= 100 && client->GetGM())) { + client->CommonBreakInvisible(); // we should be "all good" so lets break invis now instead of earlier before all error checking is done this->being_looted_by = client->GetID(); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct)); + auto outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct)); moneyOnCorpseStruct* d = (moneyOnCorpseStruct*) outapp->pBuffer; - d->response = 1; + d->response = static_cast(LootResponse::Normal); d->unknown1 = 0x42; d->unknown2 = 0xef; @@ -976,12 +987,12 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a safe_delete(outapp); if(Loot_Request_Type == 5) { int pkitem = GetPlayerKillItem(); - const Item_Struct* item = database.GetItem(pkitem); + const EQEmu::ItemBase* item = database.GetItem(pkitem); ItemInst* inst = database.CreateItem(item, item->MaxCharges); if(inst) { if (item->RecastDelay) inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0); - client->SendItemPacket(EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot); + client->SendItemPacket(EQEmu::legacy::CORPSE_BEGIN, inst, ItemPacketLoot); safe_delete(inst); } else { client->Message(13, "Could not find item number %i to send!!", GetPlayerKillItem()); } @@ -991,12 +1002,12 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a } int i = 0; - const Item_Struct* item = 0; + const EQEmu::ItemBase* item = 0; ItemList::iterator cur,end; cur = itemlist.begin(); end = itemlist.end(); - int corpselootlimit = EQLimits::InventoryMapSize(MapCorpse, client->GetClientVersion()); + int corpselootlimit = EQEmu::inventory::Lookup(EQEmu::versions::ConvertClientVersionToInventoryVersion(client->ClientVersion()))->InventoryTypeSize[EQEmu::legacy::TypeCorpse]; for(; cur != end; ++cur) { ServerLootItem_Struct* item_data = *cur; @@ -1005,7 +1016,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a // Dont display the item if it's in a bag // Added cursor queue slots to corpse item visibility list. Nothing else should be making it to corpse. - if(!IsPlayerCorpse() || item_data->equip_slot <= MainCursor || item_data->equip_slot == MainPowerSource || Loot_Request_Type>=3 || + if (!IsPlayerCorpse() || item_data->equip_slot <= EQEmu::legacy::SlotCursor || item_data->equip_slot == EQEmu::legacy::SlotPowerSource || Loot_Request_Type >= 3 || (item_data->equip_slot >= 8000 && item_data->equip_slot <= 8999)) { if(i < corpselootlimit) { item = database.GetItem(item_data->item_id); @@ -1014,8 +1025,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a if(inst) { if (item->RecastDelay) inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0); - // MainGeneral1 is the corpse inventory start offset for Ti(EMu) - CORPSE_END = MainGeneral1 + MainCursor - client->SendItemPacket(i + EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot); + // SlotGeneral1 is the corpse inventory start offset for Ti(EMu) - CORPSE_END = SlotGeneral1 + SlotCursor + client->SendItemPacket(i + EQEmu::legacy::CORPSE_BEGIN, inst, ItemPacketLoot); safe_delete(inst); } @@ -1056,7 +1067,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a // This is required for the 'Loot All' feature to work for SoD clients. I expect it is to tell the client that the // server has now sent all the items on the corpse. - if(client->GetClientVersion() >= ClientVersion::SoD) { SendLootReqErrorPacket(client, 6); } + if (client->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) + SendLootReqErrorPacket(client, LootResponse::LootAll); } void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { @@ -1096,7 +1108,7 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { return; } if (is_locked && client->Admin() < 100) { - SendLootReqErrorPacket(client, 0); + SendLootReqErrorPacket(client, LootResponse::SomeoneElse); client->Message(13, "Error: Corpse locked by GM."); return; } @@ -1106,7 +1118,7 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { being_looted_by = 0xFFFFFFFF; return; } - const Item_Struct* item = 0; + const EQEmu::ItemBase* item = 0; ItemInst *inst = 0; ServerLootItem_Struct* item_data = nullptr, *bag_item_data[10]; @@ -1115,10 +1127,10 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { item = database.GetItem(GetPlayerKillItem()); } else if (GetPlayerKillItem() == -1 || GetPlayerKillItem() == 1){ - item_data = GetItem(lootitem->slot_id - EmuConstants::CORPSE_BEGIN); //dont allow them to loot entire bags of items as pvp reward + item_data = GetItem(lootitem->slot_id - EQEmu::legacy::CORPSE_BEGIN); //dont allow them to loot entire bags of items as pvp reward } else{ - item_data = GetItem(lootitem->slot_id - EmuConstants::CORPSE_BEGIN, bag_item_data); + item_data = GetItem(lootitem->slot_id - EQEmu::legacy::CORPSE_BEGIN, bag_item_data); } if (GetPlayerKillItem()<=1 && item_data != 0) { @@ -1144,7 +1156,7 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { } if (inst->IsAugmented()) { - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { ItemInst *itm = inst->GetAugment(i); if (itm) { if (client->CheckLoreConflict(itm->GetItem())) { @@ -1159,9 +1171,9 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { } char buf[88]; - char corpse_name[64]; - strcpy(corpse_name, corpse_name); - snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(corpse_name)); + char q_corpse_name[64]; + strcpy(q_corpse_name, corpse_name); + snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(q_corpse_name)); buf[87] = '\0'; std::vector args; args.push_back(inst); @@ -1186,10 +1198,10 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { /* First add it to the looter - this will do the bag contents too */ if (lootitem->auto_loot) { if (!client->AutoPutLootInInventory(*inst, true, true, bag_item_data)) - client->PutLootInInventory(MainCursor, *inst, bag_item_data); + client->PutLootInInventory(EQEmu::legacy::SlotCursor, *inst, bag_item_data); } else { - client->PutLootInInventory(MainCursor, *inst, bag_item_data); + client->PutLootInInventory(EQEmu::legacy::SlotCursor, *inst, bag_item_data); } /* Update any tasks that have an activity to loot this item */ @@ -1205,8 +1217,8 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { } /* Remove Bag Contents */ - if (item->ItemClass == ItemClassContainer && (GetPlayerKillItem() != -1 || GetPlayerKillItem() != 1)) { - for (int i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) { + if (item->IsClassBag() && (GetPlayerKillItem() != -1 || GetPlayerKillItem() != 1)) { + for (int i = SUB_INDEX_BEGIN; i < EQEmu::legacy::ITEM_CONTAINER_SIZE; i++) { if (bag_item_data[i]) { /* Delete needs to be before RemoveItem because its deletes the pointer for item_data/bag_item_data */ database.DeleteItemOffCharacterCorpse(this->corpse_db_id, bag_item_data[i]->equip_slot, bag_item_data[i]->item_id); @@ -1221,8 +1233,8 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { } /* Send message with item link to groups and such */ - Client::TextLink linker; - linker.SetLinkType(linker.linkItemInst); + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemInst); linker.SetItemInst(inst); auto item_link = linker.GenerateLink(); @@ -1259,7 +1271,7 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) { } void Corpse::EndLoot(Client* client, const EQApplicationPacket* app) { - EQApplicationPacket* outapp = new EQApplicationPacket; + auto outapp = new EQApplicationPacket; outapp->SetOpcode(OP_LootComplete); outapp->size = 0; client->QueuePacket(outapp); @@ -1279,7 +1291,7 @@ void Corpse::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { ns->spawn.NPC = 2; UpdateActiveLight(); - ns->spawn.light = m_Light.Type.Active; + ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive]; } void Corpse::QueryLoot(Client* to) { @@ -1290,18 +1302,18 @@ void Corpse::QueryLoot(Client* to) { cur = itemlist.begin(); end = itemlist.end(); - int corpselootlimit = EQLimits::InventoryMapSize(MapCorpse, to->GetClientVersion()); + int corpselootlimit = EQEmu::inventory::Lookup(EQEmu::versions::ConvertClientVersionToInventoryVersion(to->ClientVersion()))->InventoryTypeSize[EQEmu::legacy::TypeCorpse]; for(; cur != end; ++cur) { ServerLootItem_Struct* sitem = *cur; if (IsPlayerCorpse()) { - if (sitem->equip_slot >= EmuConstants::GENERAL_BAGS_BEGIN && sitem->equip_slot <= EmuConstants::CURSOR_BAG_END) + if (sitem->equip_slot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && sitem->equip_slot <= EQEmu::legacy::CURSOR_BAG_END) sitem->lootslot = 0xFFFF; else x < corpselootlimit ? sitem->lootslot = x : sitem->lootslot = 0xFFFF; - const Item_Struct* item = database.GetItem(sitem->item_id); + const EQEmu::ItemBase* item = database.GetItem(sitem->item_id); if (item) to->Message((sitem->lootslot == 0xFFFF), "LootSlot: %i (EquipSlot: %i) Item: %s (%d), Count: %i", static_cast(sitem->lootslot), sitem->equip_slot, item->Name, item->ID, sitem->charges); @@ -1315,7 +1327,7 @@ void Corpse::QueryLoot(Client* to) { } else { sitem->lootslot=y; - const Item_Struct* item = database.GetItem(sitem->item_id); + const EQEmu::ItemBase* item = database.GetItem(sitem->item_id); if (item) to->Message(0, "LootSlot: %i Item: %s (%d), Count: %i", sitem->lootslot, item->Name, item->ID, sitem->charges); @@ -1389,7 +1401,7 @@ void Corpse::CompleteResurrection(){ } void Corpse::Spawn() { - EQApplicationPacket* app = new EQApplicationPacket; + auto app = new EQApplicationPacket; this->CreateSpawnPacket(app, this); entity_list.QueueClients(this, app); safe_delete(app); @@ -1398,7 +1410,7 @@ void Corpse::Spawn() { uint32 Corpse::GetEquipment(uint8 material_slot) const { int16 invslot; - if(material_slot > EmuConstants::MATERIAL_END) { + if (material_slot > EQEmu::textures::LastTexture) { return NO_ITEM; } @@ -1410,17 +1422,15 @@ uint32 Corpse::GetEquipment(uint8 material_slot) const { } uint32 Corpse::GetEquipmentColor(uint8 material_slot) const { - const Item_Struct *item; + const EQEmu::ItemBase *item; - if(material_slot > EmuConstants::MATERIAL_END) { + if (material_slot > EQEmu::textures::LastTexture) { return 0; } item = database.GetItem(GetEquipment(material_slot)); if(item != NO_ITEM) { - return item_tint[material_slot].RGB.UseTint ? - item_tint[material_slot].Color : - item->Color; + return (item_tint.Slot[material_slot].UseTint ? item_tint.Slot[material_slot].Color : item->Color); } return 0; @@ -1428,38 +1438,38 @@ uint32 Corpse::GetEquipmentColor(uint8 material_slot) const { void Corpse::UpdateEquipmentLight() { - m_Light.Type.Equipment = 0; - m_Light.Level.Equipment = 0; + m_Light.Type[EQEmu::lightsource::LightEquipment] = 0; + m_Light.Level[EQEmu::lightsource::LightEquipment] = 0; for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) { - if (((*iter)->equip_slot < EmuConstants::EQUIPMENT_BEGIN || (*iter)->equip_slot > EmuConstants::EQUIPMENT_END) && (*iter)->equip_slot != MainPowerSource) { continue; } - if ((*iter)->equip_slot == MainAmmo) { continue; } + if (((*iter)->equip_slot < EQEmu::legacy::EQUIPMENT_BEGIN || (*iter)->equip_slot > EQEmu::legacy::EQUIPMENT_END) && (*iter)->equip_slot != EQEmu::legacy::SlotPowerSource) { continue; } + if ((*iter)->equip_slot == EQEmu::legacy::SlotAmmo) { continue; } auto item = database.GetItem((*iter)->item_id); if (item == nullptr) { continue; } - if (m_Light.IsLevelGreater(item->Light, m_Light.Type.Equipment)) - m_Light.Type.Equipment = item->Light; + if (EQEmu::lightsource::IsLevelGreater(item->Light, m_Light.Type[EQEmu::lightsource::LightEquipment])) + m_Light.Type[EQEmu::lightsource::LightEquipment] = item->Light; } uint8 general_light_type = 0; for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) { - if ((*iter)->equip_slot < EmuConstants::GENERAL_BEGIN || (*iter)->equip_slot > EmuConstants::GENERAL_END) { continue; } + if ((*iter)->equip_slot < EQEmu::legacy::GENERAL_BEGIN || (*iter)->equip_slot > EQEmu::legacy::GENERAL_END) { continue; } auto item = database.GetItem((*iter)->item_id); if (item == nullptr) { continue; } - if (item->ItemClass != ItemClassCommon) { continue; } + if (!item->IsClassCommon()) { continue; } if (item->Light < 9 || item->Light > 13) { continue; } - if (m_Light.TypeToLevel(item->Light)) + if (EQEmu::lightsource::TypeToLevel(item->Light)) general_light_type = item->Light; } - if (m_Light.IsLevelGreater(general_light_type, m_Light.Type.Equipment)) - m_Light.Type.Equipment = general_light_type; + if (EQEmu::lightsource::IsLevelGreater(general_light_type, m_Light.Type[EQEmu::lightsource::LightEquipment])) + m_Light.Type[EQEmu::lightsource::LightEquipment] = general_light_type; - m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); + m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } void Corpse::AddLooter(Mob* who) { diff --git a/zone/corpse.h b/zone/corpse.h index 562173e80..509899827 100644 --- a/zone/corpse.h +++ b/zone/corpse.h @@ -37,7 +37,7 @@ class Corpse : public Mob { public: static void SendEndLootErrorPacket(Client* client); - static void SendLootReqErrorPacket(Client* client, uint8 response = 2); + static void SendLootReqErrorPacket(Client* client, LootResponse response = LootResponse::NotAtThisTime); Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NPCType** in_npctypedata, uint32 in_decaytime = 600000); Corpse(Client* client, int32 in_rezexp); @@ -47,9 +47,9 @@ class Corpse : public Mob { static Corpse* LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std::string in_charname, const glm::vec4& position, std::string time_of_death, bool rezzed, bool was_at_graveyard); /* Corpse: General */ - virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) { return true; } - virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false) { return; } - virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = true, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) { return false; } + virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; } + virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0) { return; } + virtual bool Attack(Mob* other, int Hand = EQEmu::legacy::SlotPrimary, bool FromRiposte = false, bool IsStrikethrough = true, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr, int special = 0) { return false; } virtual bool HasRaid() { return false; } virtual bool HasGroup() { return false; } virtual Raid* GetRaid() { return 0; } @@ -154,7 +154,7 @@ private: Timer corpse_delay_timer; Timer corpse_graveyard_timer; Timer loot_cooldown_timer; /* Delay between loot actions on the corpse entity */ - Color_Struct item_tint[9]; + EQEmu::TintProfile item_tint; }; diff --git a/zone/doors.cpp b/zone/doors.cpp index d5ad8064d..9b1f41370 100644 --- a/zone/doors.cpp +++ b/zone/doors.cpp @@ -115,7 +115,7 @@ bool Doors::Process() { if (opentype == 40 || GetTriggerType() == 1) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); + auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); MoveDoor_Struct* md = (MoveDoor_Struct*)outapp->pBuffer; md->doorid = door_id; md->action = invert_state == 0 ? CLOSE_DOOR : CLOSE_INVDOOR; @@ -137,7 +137,7 @@ void Doors::HandleClick(Client* sender, uint8 trigger) Log.Out(Logs::Detail, Logs::Doors, " incline %d, opentype %d, lockpick %d, key %d, nokeyring %d, trigger %d type %d, param %d", incline, opentype, lockpick, keyitem, nokeyring, trigger_door, trigger_type, door_param); Log.Out(Logs::Detail, Logs::Doors, " size %d, invert %d, dest: %s %s", size, invert_state, dest_zone, to_string(m_Destination).c_str()); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); + auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); MoveDoor_Struct* md = (MoveDoor_Struct*)outapp->pBuffer; md->doorid = door_id; ///////////////////////////////////////////////////////////////// @@ -170,15 +170,16 @@ void Doors::HandleClick(Client* sender, uint8 trigger) if(!sender->GetPendingAdventureDoorClick()) { sender->PendingAdventureDoorClick(); - ServerPacket *pack = new ServerPacket(ServerOP_AdventureClickDoor, sizeof(ServerPlayerClickedAdventureDoor_Struct)); + auto pack = new ServerPacket(ServerOP_AdventureClickDoor, + sizeof(ServerPlayerClickedAdventureDoor_Struct)); ServerPlayerClickedAdventureDoor_Struct *ads = (ServerPlayerClickedAdventureDoor_Struct*)pack->pBuffer; strcpy(ads->player, sender->GetName()); ads->zone_id = zone->GetZoneID(); ads->id = GetDoorDBID(); worldserver.SendPacket(pack); safe_delete(pack); - safe_delete(outapp); } + safe_delete(outapp); return; } } @@ -187,7 +188,7 @@ void Doors::HandleClick(Client* sender, uint8 trigger) uint8 keepoffkeyring = GetNoKeyring(); uint32 haskey = 0; uint32 playerkey = 0; - const ItemInst *lockpicks = sender->GetInv().GetItem(MainCursor); + const ItemInst *lockpicks = sender->GetInv().GetItem(EQEmu::legacy::SlotCursor); haskey = sender->GetInv().HasItem(keyneeded, 1); @@ -283,12 +284,12 @@ void Doors::HandleClick(Client* sender, uint8 trigger) } else if(lockpicks != nullptr) { - if(sender->GetSkill(SkillPickLock)) + if (sender->GetSkill(EQEmu::skills::SkillPickLock)) { - if(lockpicks->GetItem()->ItemType == ItemTypeLockPick) + if(lockpicks->GetItem()->ItemType == EQEmu::item::ItemTypeLockPick) { - float modskill=sender->GetSkill(SkillPickLock); - sender->CheckIncreaseSkill(SkillPickLock, nullptr, 1); + float modskill = sender->GetSkill(EQEmu::skills::SkillPickLock); + sender->CheckIncreaseSkill(EQEmu::skills::SkillPickLock, nullptr, 1); Log.Out(Logs::General, Logs::Skills, "Client has lockpicks: skill=%f", modskill); @@ -447,7 +448,7 @@ void Doors::NPCOpen(NPC* sender, bool alt_mode) return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); + auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer; md->doorid = door_id; md->action = invert_state == 0 ? OPEN_DOOR : OPEN_INVDOOR; @@ -473,7 +474,7 @@ void Doors::NPCOpen(NPC* sender, bool alt_mode) void Doors::ForceOpen(Mob *sender, bool alt_mode) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); + auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer; md->doorid = door_id; md->action = invert_state == 0 ? OPEN_DOOR : OPEN_INVDOOR; @@ -498,7 +499,7 @@ void Doors::ForceOpen(Mob *sender, bool alt_mode) void Doors::ForceClose(Mob *sender, bool alt_mode) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); + auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer; md->doorid = door_id; md->action = invert_state == 0 ? CLOSE_DOOR : CLOSE_INVDOOR; // change from original (open to close) @@ -527,7 +528,7 @@ void Doors::ToggleState(Mob *sender) return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); + auto outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct)); MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer; md->doorid = door_id; diff --git a/zone/effects.cpp b/zone/effects.cpp index 8a42b8e09..5b022f97d 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -73,6 +73,9 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (spell_id == SPELL_IMP_HARM_TOUCH && IsClient() && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0)) chance = 100; + if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance) + chance = spells[spell_id].override_crit_chance; + if (zone->random.Roll(chance)) { Critical = true; ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease; @@ -89,12 +92,13 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (IsClient() && GetClass() == WIZARD) ratio += RuleI(Spells, WizCritRatio); //Default is zero - + if (Critical){ value = value_BaseEffect*ratio/100; value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; + value += value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100; value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100; @@ -106,8 +110,12 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100; value -= GetFocusEffect(focusFcDamageAmt, spell_id); + value -= GetFocusEffect(focusFcDamageAmt2, spell_id); - if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) + if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio / 100; + + else if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; else if (IsNPC() && CastToNPC()->GetSpellScale()) @@ -126,6 +134,7 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value = value_BaseEffect; value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; + value += value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100; value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100; @@ -137,8 +146,12 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id); value -= GetFocusEffect(focusFcDamageAmt, spell_id); + value -= GetFocusEffect(focusFcDamageAmt2, spell_id); - if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) + if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); + + else if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); if (IsNPC() && CastToNPC()->GetSpellScale()) @@ -161,7 +174,10 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { chance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance; if (spellbonuses.CriticalDotDecay) - chance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay); + chance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay); + + if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance) + chance = spells[spell_id].override_crit_chance; value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100); @@ -170,11 +186,13 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease; value = value_BaseEffect*ratio/100; value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100; + value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100)*ratio/100; value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100; value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100; - extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + + extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) + - GetFocusEffect(focusFcDamageAmt, spell_id); + GetFocusEffect(focusFcDamageAmt, spell_id) + + GetFocusEffect(focusFcDamageAmt2, spell_id); if (extra_dmg) { int duration = CalcBuffDuration(this, this, spell_id); @@ -188,11 +206,13 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { value = value_BaseEffect; value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; + value += value_BaseEffect*GetFocusEffect(focusImprovedDamage2, spell_id)/100; value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100; value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100; extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) + GetFocusEffect(focusFcDamageAmtCrit, spell_id) + - GetFocusEffect(focusFcDamageAmt, spell_id); + GetFocusEffect(focusFcDamageAmt, spell_id) + + GetFocusEffect(focusFcDamageAmt2, spell_id); if (extra_dmg) { int duration = CalcBuffDuration(this, this, spell_id); @@ -211,6 +231,9 @@ int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg) { + if (RuleB(Spells, FlatItemExtraSpellAmt)) + return extra_spell_amt; + int total_cast_time = 0; if (spells[spell_id].recast_time >= spells[spell_id].recovery_time) @@ -219,11 +242,11 @@ int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_s total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time; if (total_cast_time > 0 && total_cast_time <= 2500) - extra_spell_amt = extra_spell_amt*25/100; - else if (total_cast_time > 2500 && total_cast_time < 7000) - extra_spell_amt = extra_spell_amt*(167*((total_cast_time - 1000)/1000)) / 1000; - else - extra_spell_amt = extra_spell_amt * total_cast_time / 7000; + extra_spell_amt = extra_spell_amt*25/100; + else if (total_cast_time > 2500 && total_cast_time < 7000) + extra_spell_amt = extra_spell_amt*(167*((total_cast_time - 1000)/1000)) / 1000; + else + extra_spell_amt = extra_spell_amt * total_cast_time / 7000; if(extra_spell_amt*2 < base_spell_dmg) return 0; @@ -260,6 +283,9 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { if (spellbonuses.CriticalHealDecay) chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance) + chance = spells[spell_id].override_crit_chance; + if(chance && (zone->random.Roll(chance))) { Critical = true; modifier = 2; //At present time no critical heal amount modifier SPA exists. @@ -270,7 +296,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { value += GetFocusEffect(focusFcHealAmt, spell_id); value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); - if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) + if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%17) - 1] >= GetLevel() - 5) value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier; value += value*target->GetHealRate(spell_id, this)/100; @@ -281,7 +307,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { if (Critical) { entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits, OTHER_CRIT_HEAL, GetName(), itoa(value)); - + if (IsClient()) Message_StringID(MT_SpellCrits, YOU_CRIT_HEAL, itoa(value)); } @@ -319,7 +345,7 @@ int32 Client::GetActSpellCost(uint16 spell_id, int32 cost) cost *= 2; // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell - if(itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) + if(itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%17) - 1] >= GetLevel() - 5) { int16 mana_back = itembonuses.Clairvoyance * zone->random.Int(1, 100) / 100; // Doesnt generate mana, so best case is a free spell @@ -413,24 +439,20 @@ int32 Client::GetActSpellCost(uint16 spell_id, int32 cost) int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration) { - if (spells[spell_id].not_extendable) - return duration; - int increase = 100; increase += GetFocusEffect(focusSpellDuration, spell_id); int tic_inc = 0; tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id); - // Only need this for clients, since the change was for bard songs, I assume we should keep non bard songs getting +1 - // However if its bard or not and is mez, charm or fear, we need to add 1 so that client is in sync - if (IsClient() && !(IsShortDurationBuff(spell_id) && IsBardSong(spell_id)) || - IsFearSpell(spell_id) || - IsCharmSpell(spell_id) || - IsMezSpell(spell_id) || - IsBlindSpell(spell_id)) - tic_inc += 1; + float focused = ((duration * increase) / 100.0f) + tic_inc; + int ifocused = static_cast(focused); - return (((duration * increase) / 100) + tic_inc); + // 7.6 is rounded to 7, 8.6 is rounded to 9 + // 6 is 6, etc + if (FCMP(focused, ifocused) || ifocused % 2) // equal or odd + return ifocused; + else // even and not equal round to odd + return ifocused + 1; } int32 Client::GetActSpellCasttime(uint16 spell_id, int32 casttime) @@ -459,14 +481,14 @@ int32 Client::GetActSpellCasttime(uint16 spell_id, int32 casttime) bool Client::TrainDiscipline(uint32 itemid) { //get the item info - const Item_Struct *item = database.GetItem(itemid); + const EQEmu::ItemBase *item = database.GetItem(itemid); if(item == nullptr) { Message(13, "Unable to find the tome you turned in!"); Log.Out(Logs::General, Logs::Error, "Unable to find turned in tome id %lu\n", (unsigned long)itemid); return(false); } - if(item->ItemClass != ItemClassCommon || item->ItemType != ItemTypeSpell) { + if (!item->IsClassCommon() || item->ItemType != EQEmu::item::ItemTypeSpell) { Message(13, "Invalid item type, you cannot learn from this item."); //summon them the item back... SummonItem(itemid); @@ -558,6 +580,33 @@ bool Client::TrainDiscipline(uint32 itemid) { return(false); } +void Client::TrainDiscBySpellID(int32 spell_id) +{ + int i; + for(i = 0; i < MAX_PP_DISCIPLINES; i++) { + if(m_pp.disciplines.values[i] == 0) { + m_pp.disciplines.values[i] = spell_id; + database.SaveCharacterDisc(this->CharacterID(), i, spell_id); + SendDisciplineUpdate(); + Message(15, "You have learned a new combat ability!"); + return; + } + } +} + +int Client::GetDiscSlotBySpellID(int32 spellid) +{ + int i; + + for(i = 0; i < MAX_PP_DISCIPLINES; i++) + { + if(m_pp.disciplines.values[i] == spellid) + return i; + } + + return -1; +} + void Client::SendDisciplineUpdate() { EQApplicationPacket app(OP_DisciplineUpdate, sizeof(Disciplines_Struct)); Disciplines_Struct *d = (Disciplines_Struct*)app.pBuffer; @@ -613,10 +662,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { return(false); } - if(GetEndurance() > spell.EndurCost) { - SetEndurance(GetEndurance() - spell.EndurCost); - TryTriggerOnValueAmount(false, false, true); - } else { + if(GetEndurance() < spell.EndurCost) { Message(11, "You are too fatigued to use this skill right now."); return(false); } @@ -624,17 +670,23 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { if(spell.recast_time > 0) { uint32 reduced_recast = spell.recast_time / 1000; - reduced_recast -= GetFocusEffect(focusReduceRecastTime, spell_id); - if(reduced_recast <= 0){ + auto focus = GetFocusEffect(focusReduceRecastTime, spell_id); + // do stupid stuff because custom servers. + // we really should be able to just do the -= focus but since custom servers could have shorter reuse timers + // we have to make sure we don't underflow the uint32 ... + // and yes, the focus effect can be used to increase the durations (spell 38944) + if (focus > reduced_recast) { reduced_recast = 0; if (GetPTimers().Enabled((uint32)DiscTimer)) GetPTimers().Clear(&database, (uint32)DiscTimer); + } else { + reduced_recast -= focus; } if (reduced_recast > 0) - CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast); + CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast); else{ - CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT); + CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline); return true; } @@ -642,7 +694,7 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) { } else { - CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT); + CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline); } return(true); } @@ -651,7 +703,7 @@ void Client::SendDisciplineTimer(uint32 timer_id, uint32 duration) { if (timer_id < MAX_DISCIPLINE_TIMERS) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_DisciplineTimer, sizeof(DisciplineTimer_Struct)); + auto outapp = new EQApplicationPacket(OP_DisciplineTimer, sizeof(DisciplineTimer_Struct)); DisciplineTimer_Struct *dts = (DisciplineTimer_Struct *)outapp->pBuffer; dts->TimerID = timer_id; dts->Duration = duration; @@ -660,10 +712,10 @@ void Client::SendDisciplineTimer(uint32 timer_id, uint32 duration) } } -void EntityList::AETaunt(Client* taunter, float range) +void EntityList::AETaunt(Client* taunter, float range, int32 bonus_hate) { if (range == 0) - range = 100; //arbitrary default... + range = 40; //Live AE taunt range - Hardcoded. range = range * range; @@ -677,7 +729,7 @@ void EntityList::AETaunt(Client* taunter, float range) && taunter->IsAttackAllowed(them) && DistanceSquaredNoZ(taunter->GetPosition(), them->GetPosition()) <= range) { if (taunter->CheckLosFN(them)) { - taunter->Taunt(them, true); + taunter->Taunt(them, true,0,true,bonus_hate); } } ++it; @@ -771,7 +823,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust); } } else { - if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets) + if (spells[spell_id].aemaxtargets && iCounter < spells[spell_id].aemaxtargets) caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust); if (!spells[spell_id].aemaxtargets) caster->SpellOnTarget(spell_id, curmob, false, true, resist_adjust); @@ -859,7 +911,7 @@ void EntityList::AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool aff if (!center->CheckLosFN(curmob)) continue; } else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies... - // See notes in AESpell() above for more info. + // See notes in AESpell() above for more info. if (caster->IsAttackAllowed(curmob, true)) continue; if (caster->CheckAggro(curmob)) @@ -873,7 +925,7 @@ void EntityList::AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool aff caster->CastToClient()->CheckSongSkillIncrease(spell_id); } -//Dook- Rampage and stuff for clients. +// Rampage and stuff for clients. Normal and Duration rampages //NPCs handle it differently in Mob::Rampage void EntityList::AEAttack(Mob *attacker, float dist, int Hand, int count, bool IsFromSpell) { //Dook- Will need tweaking, currently no pets or players or horses @@ -891,7 +943,10 @@ void EntityList::AEAttack(Mob *attacker, float dist, int Hand, int count, bool I && curmob->GetRace() != 216 && curmob->GetRace() != 472 /* dont attack horses */ && (DistanceSquared(curmob->GetPosition(), attacker->GetPosition()) <= dist2) ) { - attacker->Attack(curmob, Hand, false, false, IsFromSpell); + if (!attacker->IsClient() || attacker->GetClass() == MONK || attacker->GetClass() == RANGER) + attacker->Attack(curmob, Hand, false, false, IsFromSpell); + else + attacker->CastToClient()->DoAttackRounds(curmob, Hand, IsFromSpell); hit++; if (count != 0 && hit >= count) return; diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 3bfb2e90a..43f4c3cdc 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2006 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -9,11 +9,11 @@ but WITHOUT ANY WARRANTY except by those people which sell it, which are required to give you total support for your newly bought product; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. + A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef EMBPERL @@ -113,7 +113,10 @@ const char *QuestEventSubroutines[_LargestEventID] = { "EVENT_LEAVE_AREA", "EVENT_RESPAWN", "EVENT_DEATH_COMPLETE", - "EVENT_UNHANDLED_OPCODE" + "EVENT_UNHANDLED_OPCODE", + "EVENT_TICK", + "EVENT_SPAWN_ZONE", + "EVENT_DEATH_ZONE", }; PerlembParser::PerlembParser() : perl(nullptr) { @@ -154,7 +157,7 @@ void PerlembParser::ReloadQuests() { spell_quest_status_.clear(); } -int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, +int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, bool global, std::vector *extra_pointers) { if(!perl) @@ -182,15 +185,31 @@ int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * da int char_id = 0; ExportCharID(package_name, char_id, npcmob, mob); - ExportQGlobals(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, - package_name, npcmob, mob, char_id); + + /* Check for QGlobal export event enable */ + if (parse->perl_event_export_settings[event].qglobals){ + ExportQGlobals(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, package_name, npcmob, mob, char_id); + } - //ExportGenericVariables(); - ExportMobVariables(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, - package_name, mob, npcmob); - ExportZoneVariables(package_name); - ExportItemVariables(package_name, mob); - ExportEventVariables(package_name, event, objid, data, npcmob, iteminst, mob, extradata, extra_pointers); + /* Check for Mob export event enable */ + if (parse->perl_event_export_settings[event].mob){ + ExportMobVariables(isPlayerQuest, isGlobalPlayerQuest, isGlobalNPC, isItemQuest, isSpellQuest, package_name, mob, npcmob); + } + + /* Check for Zone export event enable */ + if (parse->perl_event_export_settings[event].zone){ + ExportZoneVariables(package_name); + } + + /* Check for Item export event enable */ + if (parse->perl_event_export_settings[event].item){ + ExportItemVariables(package_name, mob); + } + + /* Check for Event export event enable */ + if (parse->perl_event_export_settings[event].event_variables){ + ExportEventVariables(package_name, event, objid, data, npcmob, iteminst, mob, extradata, extra_pointers); + } if(isPlayerQuest || isGlobalPlayerQuest){ return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, nullptr); @@ -198,8 +217,7 @@ int PerlembParser::EventCommon(QuestEventID event, uint32 objid, const char * da else if(isItemQuest) { return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, iteminst); } - else if(isSpellQuest) - { + else if(isSpellQuest){ if(mob) { return SendCommands(package_name.c_str(), sub_name, 0, mob, mob, nullptr); } else { @@ -459,15 +477,15 @@ void PerlembParser::LoadItemScript(std::string filename, ItemInst *item) { std::stringstream package_name; package_name << "qst_item_" << item->GetID(); - + if(!perl) return; - + auto iter = item_quest_status_.find(item->GetID()); if(iter != item_quest_status_.end()) { return; } - + try { perl->eval_file(package_name.str().c_str(), filename.c_str()); } @@ -480,7 +498,7 @@ void PerlembParser::LoadItemScript(std::string filename, ItemInst *item) { item_quest_status_[item->GetID()] = questFailedToLoad; return; } - + item_quest_status_[item->GetID()] = questLoaded; } @@ -821,10 +839,10 @@ void PerlembParser::MapFunctions() { ); } -void PerlembParser::GetQuestTypes(bool &isPlayerQuest, bool &isGlobalPlayerQuest, bool &isGlobalNPC, bool &isItemQuest, +void PerlembParser::GetQuestTypes(bool &isPlayerQuest, bool &isGlobalPlayerQuest, bool &isGlobalNPC, bool &isItemQuest, bool &isSpellQuest, QuestEventID event, NPC* npcmob, ItemInst* iteminst, Mob* mob, bool global) { - if(event == EVENT_SPELL_EFFECT_CLIENT || + if(event == EVENT_SPELL_EFFECT_CLIENT || event == EVENT_SPELL_EFFECT_NPC || event == EVENT_SPELL_BUFF_TIC_CLIENT || event == EVENT_SPELL_BUFF_TIC_NPC || @@ -843,14 +861,14 @@ void PerlembParser::GetQuestTypes(bool &isPlayerQuest, bool &isGlobalPlayerQuest isPlayerQuest = true; } } - else + else isItemQuest = true; } } } -void PerlembParser::GetQuestPackageName(bool &isPlayerQuest, bool &isGlobalPlayerQuest, bool &isGlobalNPC, bool &isItemQuest, - bool &isSpellQuest, std::string &package_name, QuestEventID event, uint32 objid, const char * data, +void PerlembParser::GetQuestPackageName(bool &isPlayerQuest, bool &isGlobalPlayerQuest, bool &isGlobalNPC, bool &isItemQuest, + bool &isSpellQuest, std::string &package_name, QuestEventID event, uint32 objid, const char * data, NPC* npcmob, ItemInst* iteminst, bool global) { if(!isPlayerQuest && !isGlobalPlayerQuest && !isItemQuest && !isSpellQuest) { @@ -864,7 +882,7 @@ void PerlembParser::GetQuestPackageName(bool &isPlayerQuest, bool &isGlobalPlaye } else if(isItemQuest) { // need a valid ItemInst pointer check here..unsure how to cancel this process - const Item_Struct* item = iteminst->GetItem(); + const EQEmu::ItemBase* item = iteminst->GetItem(); package_name = "qst_item_"; package_name += itoa(item->ID); } @@ -897,7 +915,7 @@ void PerlembParser::ExportCharID(const std::string &package_name, int &char_id, ExportVar(package_name.c_str(), "charid", char_id); } -void PerlembParser::ExportQGlobals(bool isPlayerQuest, bool isGlobalPlayerQuest, bool isGlobalNPC, bool isItemQuest, +void PerlembParser::ExportQGlobals(bool isPlayerQuest, bool isGlobalPlayerQuest, bool isGlobalNPC, bool isItemQuest, bool isSpellQuest, std::string &package_name, NPC *npcmob, Mob *mob, int char_id) { //NPC quest if(!isPlayerQuest && !isGlobalPlayerQuest && !isItemQuest && !isSpellQuest) @@ -953,8 +971,8 @@ void PerlembParser::ExportQGlobals(bool isPlayerQuest, bool isGlobalPlayerQuest, { QGlobalCache::Combine(globalMap, zone_c->GetBucket(), npcmob->GetNPCTypeID(), char_id, zone->GetZoneID()); } - - std::list::iterator iter = globalMap.begin(); + + auto iter = globalMap.begin(); while(iter != globalMap.end()) { globhash[(*iter).name] = (*iter).value; @@ -1002,7 +1020,7 @@ void PerlembParser::ExportQGlobals(bool isPlayerQuest, bool isGlobalPlayerQuest, QGlobalCache::Combine(globalMap, zone_c->GetBucket(), 0, char_id, zone->GetZoneID()); } - std::list::iterator iter = globalMap.begin(); + auto iter = globalMap.begin(); while(iter != globalMap.end()) { globhash[(*iter).name] = (*iter).value; @@ -1013,8 +1031,8 @@ void PerlembParser::ExportQGlobals(bool isPlayerQuest, bool isGlobalPlayerQuest, } } -void PerlembParser::ExportMobVariables(bool isPlayerQuest, bool isGlobalPlayerQuest, bool isGlobalNPC, bool isItemQuest, - bool isSpellQuest, std::string &package_name, Mob *mob, NPC *npcmob) +void PerlembParser::ExportMobVariables(bool isPlayerQuest, bool isGlobalPlayerQuest, bool isGlobalNPC, bool isItemQuest, + bool isSpellQuest, std::string &package_name, Mob *mob, NPC *npcmob) { uint8 fac = 0; if (mob && mob->IsClient()) { @@ -1027,15 +1045,15 @@ void PerlembParser::ExportMobVariables(bool isPlayerQuest, bool isGlobalPlayerQu if (mob && npcmob && mob->IsClient()) { Client* client = mob->CastToClient(); - fac = client->GetFactionLevel(client->CharacterID(), npcmob->GetID(), client->GetRace(), + fac = client->GetFactionLevel(client->CharacterID(), npcmob->GetID(), client->GetRace(), client->GetClass(), client->GetDeity(), npcmob->GetPrimaryFaction(), npcmob); } } if(mob) { ExportVar(package_name.c_str(), "name", mob->GetName()); - ExportVar(package_name.c_str(), "race", GetRaceName(mob->GetRace())); - ExportVar(package_name.c_str(), "class", GetEQClassName(mob->GetClass())); + ExportVar(package_name.c_str(), "race", GetRaceIDName(mob->GetRace())); + ExportVar(package_name.c_str(), "class", GetClassIDName(mob->GetClass())); ExportVar(package_name.c_str(), "ulevel", mob->GetLevel()); ExportVar(package_name.c_str(), "userid", mob->GetID()); } @@ -1072,7 +1090,7 @@ void PerlembParser::ExportZoneVariables(std::string &package_name) { ExportVar(package_name.c_str(), "instanceid", zone->GetInstanceID()); ExportVar(package_name.c_str(), "instanceversion", zone->GetInstanceVersion()); TimeOfDay_Struct eqTime; - zone->zone_time.getEQTimeOfDay( time(0), &eqTime); + zone->zone_time.GetCurrentEQTimeOfDay( time(0), &eqTime); ExportVar(package_name.c_str(), "zonehour", eqTime.hour - 1); ExportVar(package_name.c_str(), "zonemin", eqTime.minute); ExportVar(package_name.c_str(), "zonetime", (eqTime.hour - 1) * 100 + eqTime.minute); @@ -1122,8 +1140,8 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) { #undef HASITEM_LAST #undef HASITEM_ISNULLITEM -void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID event, uint32 objid, const char * data, - NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, std::vector *extra_pointers) +void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID event, uint32 objid, const char * data, + NPC* npcmob, ItemInst* iteminst, Mob* mob, uint32 extradata, std::vector *extra_pointers) { switch (event) { case EVENT_SAY: { @@ -1240,7 +1258,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID ExportVar(package_name.c_str(), "target_zone_id", data); break; } - + case EVENT_CAST_ON: case EVENT_CAST: case EVENT_CAST_BEGIN: { @@ -1277,7 +1295,8 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID case EVENT_PLAYER_PICKUP:{ ExportVar(package_name.c_str(), "picked_up_id", data); - break; + ExportVar(package_name.c_str(), "picked_up_entity_id", extradata); + break; } case EVENT_AGGRO_SAY: { @@ -1320,6 +1339,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID ExportVar(package_name.c_str(), "itemid", objid); ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name); ExportVar(package_name.c_str(), "slotid", extradata); + ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect); break; } @@ -1357,16 +1377,17 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID case EVENT_FORAGE_SUCCESS: { ExportVar(package_name.c_str(), "foraged_item", extradata); - break; + break; } case EVENT_FISH_SUCCESS: { ExportVar(package_name.c_str(), "fished_item", extradata); - break; + break; } case EVENT_CLICK_OBJECT: { ExportVar(package_name.c_str(), "objectid", data); + ExportVar(package_name.c_str(), "clicker_id", extradata); break; } @@ -1397,6 +1418,29 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]); break; } + case EVENT_DROP_ITEM: { + ExportVar(package_name.c_str(), "quantity", iteminst->IsStackable() ? iteminst->GetCharges() : 1); + ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name); + ExportVar(package_name.c_str(), "itemid", iteminst->GetItem()->ID); + ExportVar(package_name.c_str(), "spell_id", iteminst->GetItem()->Click.Effect); + ExportVar(package_name.c_str(), "slotid", extradata); + break; + } + case EVENT_SPAWN_ZONE: { + Seperator sep(data); + ExportVar(package_name.c_str(), "spawned_entity_id", sep.arg[0]); + ExportVar(package_name.c_str(), "spawned_npc_id", sep.arg[1]); + break; + } + case EVENT_DEATH_ZONE: { + Seperator sep(data); + ExportVar(package_name.c_str(), "killer_id", sep.arg[0]); + ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]); + ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]); + ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]); + ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]); + break; + } default: { break; diff --git a/zone/embparser.h b/zone/embparser.h index 1357ae20b..9b33b1ad2 100644 --- a/zone/embparser.h +++ b/zone/embparser.h @@ -75,6 +75,7 @@ public: virtual std::string GetVar(std::string name); virtual void ReloadQuests(); virtual uint32 GetIdentifier() { return 0xf8b05c11; } + private: Embperl *perl; diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 8b49f01b2..b9b28f0a6 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -1182,13 +1182,26 @@ XS(XS__settime); XS(XS__settime) { dXSARGS; - if (items != 2) - Perl_croak(aTHX_ "Usage: settime(new_hour, new_min)"); + if (items < 2) + Perl_croak(aTHX_ "Usage: settime(new_hour, new_min, [update_world = true])"); - int new_hour = (int)SvIV(ST(0)); - int new_min = (int)SvIV(ST(1)); + if (items == 2){ + int new_hour = (int)SvIV(ST(0)); + int new_min = (int)SvIV(ST(1)); + quest_manager.settime(new_hour, new_min, true); + } + else if (items == 3){ + int new_hour = (int)SvIV(ST(0)); + int new_min = (int)SvIV(ST(1)); - quest_manager.settime(new_hour, new_min); + int update_world = (int)SvIV(ST(2)); + if (update_world == 1){ + quest_manager.settime(new_hour, new_min, true); + } + else{ + quest_manager.settime(new_hour, new_min, false); + } + } XSRETURN_EMPTY; } @@ -1735,18 +1748,18 @@ XS(XS__clear_zone_flag) XSRETURN_EMPTY; } -XS(XS__summonburriedplayercorpse); -XS(XS__summonburriedplayercorpse) +XS(XS__summonburiedplayercorpse); +XS(XS__summonburiedplayercorpse) { dXSARGS; if (items != 5) - Perl_croak(aTHX_ "Usage: summonburriedplayercorpse(char_id,dest_x,dest_y,dest_z,dest_heading)"); + Perl_croak(aTHX_ "Usage: summonburiedplayercorpse(char_id,dest_x,dest_y,dest_z,dest_heading)"); bool RETVAL; uint32 char_id = (int)SvIV(ST(0)); auto position = glm::vec4((float)SvIV(ST(1)), (float)SvIV(ST(2)), (float)SvIV(ST(3)),(float)SvIV(ST(4))); - RETVAL = quest_manager.summonburriedplayercorpse(char_id, position); + RETVAL = quest_manager.summonburiedplayercorpse(char_id, position); ST(0) = boolSV(RETVAL); sv_2mortal(ST(0)); @@ -1771,19 +1784,19 @@ XS(XS__summonallplayercorpses) XSRETURN(1); } -XS(XS__getplayerburriedcorpsecount); -XS(XS__getplayerburriedcorpsecount) +XS(XS__getplayerburiedcorpsecount); +XS(XS__getplayerburiedcorpsecount) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: getplayerburriedcorpsecount(char_id)"); + Perl_croak(aTHX_ "Usage: getplayerburiedcorpsecount(char_id)"); uint32 RETVAL; dXSTARG; uint32 char_id = (int)SvIV(ST(0)); - RETVAL = quest_manager.getplayerburriedcorpsecount(char_id); + RETVAL = quest_manager.getplayerburiedcorpsecount(char_id); XSprePUSH; PUSHu((IV)RETVAL); XSRETURN(1); @@ -1917,6 +1930,52 @@ XS(XS__repopzone) XSRETURN_EMPTY; } +XS(XS__ConnectNodeToNode); +XS(XS__ConnectNodeToNode) +{ + dXSARGS; + if (items != 4) + Perl_croak(aTHX_ "Usage: ConnectNodeToNode(node1, node2, teleport, doorid)"); + + int node1 = (int)SvIV(ST(0)); + int node2 = (int)SvIV(ST(1)); + int teleport = (int)SvIV(ST(2)); + int doorid = (int)SvIV(ST(3)); + + quest_manager.ConnectNodeToNode(node1, node2, teleport, doorid); + + XSRETURN_EMPTY; +} + +XS(XS__AddNode); +XS(XS__AddNode) +{ + dXSARGS; + //void QuestManager::AddNode(float x, float y, float z, float best_z, int32 requested_id); + 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)); + int best_z = 0; + int requested_id = 0; + + if (items == 4) + { + best_z = (int)SvIV(ST(3)); + } + else if (items == 5) + { + best_z = (int)SvIV(ST(3)); + requested_id = (int)SvIV(ST(4)); + } + + quest_manager.AddNode(x, y, z, best_z, requested_id); + + XSRETURN_EMPTY; +} + XS(XS__npcrace); XS(XS__npcrace) { @@ -2324,11 +2383,19 @@ XS(XS__assigntask) { dXSARGS; unsigned int taskid; - if(items == 1) { + bool enforce_level_requirement = false; + if(items == 1 || items == 2) { taskid = (int)SvIV(ST(0)); - quest_manager.assigntask(taskid); + if (items == 2) + { + if ((int)SvIV(ST(1)) == 1) + { + enforce_level_requirement = true; + } + } + quest_manager.assigntask(taskid, enforce_level_requirement); } else { - Perl_croak(aTHX_ "Usage: assigntask(taskid)"); + Perl_croak(aTHX_ "Usage: assigntask(taskid, enforce_level_requirement)"); } XSRETURN_EMPTY; @@ -2839,6 +2906,42 @@ XS(XS__DestroyInstance) { XSRETURN_EMPTY; } +XS(XS__UpdateInstanceTimer); +XS(XS__UpdateInstanceTimer) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: UpdateInstanceTimer(instance_id, new_duration)"); + + uint16 instance_id = (uint16)SvUV(ST(0)); + uint32 new_duration = (uint32)SvUV(ST(1)); + quest_manager.UpdateInstanceTimer(instance_id, new_duration); + + XSRETURN_EMPTY; +} + +XS(XS__GetInstanceTimer); +XS(XS__GetInstanceTimer) { + dXSARGS; + if (items != 0) + Perl_croak(aTHX_ "Usage: GetInstanceTimer()"); + + uint32 timer = quest_manager.GetInstanceTimer(); + + XSRETURN_UV(timer); +} + +XS(XS__GetInstanceTimerByID); +XS(XS__GetInstanceTimerByID) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: GetInstanceTimerByID(instance_id)"); + + uint16 instance_id = (uint16)SvUV(ST(0)); + uint32 timer = quest_manager.GetInstanceTimerByID(instance_id); + + XSRETURN_UV(timer); +} + XS(XS__GetInstanceID); XS(XS__GetInstanceID) { dXSARGS; @@ -3214,13 +3317,22 @@ XS(XS__wearchange); XS(XS__wearchange) { dXSARGS; - if (items != 2) - Perl_croak(aTHX_ "Usage: wearchange(slot, texture)"); + if (items < 2) + Perl_croak(aTHX_ "Usage: wearchange(slot, texture, [hero_forge_model], [elite_material])"); uint8 slot = (int)SvUV(ST(0)); uint16 texture = (int)SvUV(ST(1)); - quest_manager.wearchange(slot, texture); + uint32 hero_forge_model = 0; + uint32 elite_material = 0; + + if (items > 2) + hero_forge_model = (int)SvUV(ST(2)); + + if (items > 3) + elite_material = (int)SvUV(ST(3)); + + quest_manager.wearchange(slot, texture, hero_forge_model, elite_material); XSRETURN_EMPTY; } @@ -3429,6 +3541,16 @@ XS(XS__clear_npctype_cache) XSRETURN_EMPTY; } +XS(XS__reloadzonestaticdata); +XS(XS__reloadzonestaticdata) +{ + dXSARGS; + + quest_manager.ReloadZoneStaticData(); + + XSRETURN_EMPTY; +} + XS(XS__qs_send_query); XS(XS__qs_send_query) { @@ -3524,6 +3646,19 @@ XS(XS__debug) XSRETURN_EMPTY; } +XS(XS__UpdateZoneHeader); +XS(XS__UpdateZoneHeader) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: UpdateZoneHeader(type, value)"); + + std::string type = (std::string)SvPV_nolen(ST(0)); + std::string value = (std::string)SvPV_nolen(ST(1)); + quest_manager.UpdateZoneHeader(type, value); + + XSRETURN_EMPTY; +} + /* This is the callback perl will look for to setup the @@ -3559,6 +3694,9 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "ChooseRandom"), XS__ChooseRandom, file); newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file); newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file); + newXS(strcpy(buf, "UpdateInstanceTimer"), XS__UpdateInstanceTimer, file); + newXS(strcpy(buf, "GetInstanceTimer"), XS__GetInstanceTimer, file); + newXS(strcpy(buf, "GetInstanceTimerByID"), XS__GetInstanceTimerByID, file); newXS(strcpy(buf, "FlagInstanceByGroupLeader"), XS__FlagInstanceByGroupLeader, file); newXS(strcpy(buf, "FlagInstanceByRaidLeader"), XS__FlagInstanceByRaidLeader, file); newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file); @@ -3643,7 +3781,7 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file); newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file); newXS(strcpy(buf, "getlevel"), XS__getlevel, file); - newXS(strcpy(buf, "getplayerburriedcorpsecount"), XS__getplayerburriedcorpsecount, file); + newXS(strcpy(buf, "getplayerburiedcorpsecount"), XS__getplayerburiedcorpsecount, file); newXS(strcpy(buf, "gettaskactivitydonecount"), XS__gettaskactivitydonecount, file); newXS(strcpy(buf, "givecash"), XS__givecash, file); newXS(strcpy(buf, "gmmove"), XS__gmmove, file); @@ -3686,8 +3824,11 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "qs_send_query"), XS__qs_send_query, file); newXS(strcpy(buf, "rain"), XS__rain, file); newXS(strcpy(buf, "rebind"), XS__rebind, file); + newXS(strcpy(buf, "reloadzonestaticdata"), XS__reloadzonestaticdata, file); newXS(strcpy(buf, "removetitle"), XS__removetitle, file); newXS(strcpy(buf, "repopzone"), XS__repopzone, file); + newXS(strcpy(buf, "ConnectNodeToNode"), XS__ConnectNodeToNode, file); + newXS(strcpy(buf, "AddNode"), XS__AddNode, file); newXS(strcpy(buf, "resettaskactivity"), XS__resettaskactivity, file); newXS(strcpy(buf, "respawn"), XS__respawn, file); newXS(strcpy(buf, "resume"), XS__resume, file); @@ -3730,7 +3871,7 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "stopalltimers"), XS__stopalltimers, file); newXS(strcpy(buf, "stoptimer"), XS__stoptimer, file); newXS(strcpy(buf, "summonallplayercorpses"), XS__summonallplayercorpses, file); - newXS(strcpy(buf, "summonburriedplayercorpse"), XS__summonburriedplayercorpse, file); + newXS(strcpy(buf, "summonburiedplayercorpse"), XS__summonburiedplayercorpse, file); newXS(strcpy(buf, "summonitem"), XS__summonitem, file); newXS(strcpy(buf, "surname"), XS__surname, file); newXS(strcpy(buf, "targlobal"), XS__targlobal, file); @@ -3747,6 +3888,7 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "untraindiscs"), XS__untraindiscs, file); newXS(strcpy(buf, "updatespawntimer"), XS__UpdateSpawnTimer, file); newXS(strcpy(buf, "updatetaskactivity"), XS__updatetaskactivity, file); + newXS(strcpy(buf, "UpdateZoneHeader"), XS__UpdateZoneHeader, file); newXS(strcpy(buf, "varlink"), XS__varlink, file); newXS(strcpy(buf, "voicetell"), XS__voicetell, file); newXS(strcpy(buf, "we"), XS__we, file); diff --git a/zone/embperl.cpp b/zone/embperl.cpp index 4d27d1269..d881cad5e 100644 --- a/zone/embperl.cpp +++ b/zone/embperl.cpp @@ -173,25 +173,27 @@ void Embperl::DoInit() { Log.Out(Logs::General, Logs::Quests, "Loading perlemb plugins."); try { - eval_pv("main::eval_file('plugin', 'plugin.pl');", FALSE); + std::string perl_command; + perl_command = "main::eval_file('plugin', '" + Config->PluginPlFile + "');"; + eval_pv(perl_command.c_str(), FALSE); } catch(const char *err) { - Log.Out(Logs::General, Logs::Quests, "Warning - plugin.pl: %s", err); + Log.Out(Logs::General, Logs::Quests, "Warning - %s: %s", Config->PluginPlFile.c_str(), err); } try { //should probably read the directory in c, instead, so that //I can echo filenames as I do it, but c'mon... I'm lazy and this 1 line reads in all the plugins - eval_pv( - "if(opendir(D,'plugins')) { " + std::string perl_command = + "if(opendir(D,'" + Config->PluginDir +"')) { " " my @d = readdir(D);" " closedir(D);" " foreach(@d){ " - " main::eval_file('plugin','plugins/'.$_)if/\\.pl$/;" + " main::eval_file('plugin','" + Config->PluginDir + "/'.$_)if/\\.pl$/;" " }" - "}" - ,FALSE); + "}"; + eval_pv(perl_command.c_str(),FALSE); } catch(const char *err) { @@ -276,10 +278,9 @@ int Embperl::dosub(const char * subname, const std::vector * args, ENTER; SAVETMPS; PUSHMARK(SP); - if(args && args->size()) + if(args && !args->empty()) { - for(std::vector::const_iterator i = args->begin(); i != args->end(); ++i) - { + for (auto i = args->begin(); i != args->end(); ++i) { XPUSHs(sv_2mortal(newSVpv(i->c_str(), i->length()))); } } diff --git a/zone/embperl.h b/zone/embperl.h index 919664d0a..ebd76fa0e 100644 --- a/zone/embperl.h +++ b/zone/embperl.h @@ -10,6 +10,8 @@ Eglin #ifdef EMBPERL +#include "zone_config.h" + #include #include #include @@ -52,11 +54,23 @@ extern "C" { //the perl headers dont do this for us... #ifdef Zero #undef Zero #endif +//These need to be cleaned up on FreeBSD + +#ifdef __FreeBSD__ +#ifdef do_open +#undef do_open +#endif + +#ifdef do_close +#undef do_close +#endif +#endif //so embedded scripts can use xs extensions (ala 'use socket;') EXTERN_C void boot_DynaLoader(pTHX_ CV* cv); EXTERN_C void xs_init(pTHX); +extern const ZoneConfig *Config; class Embperl { private: diff --git a/zone/embxs.cpp b/zone/embxs.cpp index 664416587..5c8769895 100644 --- a/zone/embxs.cpp +++ b/zone/embxs.cpp @@ -1,26 +1,30 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which are required to give you total support for your newly bought product; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifdef EMBPERL #include "../common/global_define.h" #include "../common/eqemu_logsys.h" #include "masterentity.h" #include "command.h" +#ifdef BOTS +#include "bot_command.h" +#endif #include "embperl.h" #include "embxs.h" @@ -29,7 +33,7 @@ const char *getItemName(unsigned itemid) { - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; item = database.GetItem(itemid); if (item) diff --git a/zone/encounter.cpp b/zone/encounter.cpp new file mode 100644 index 000000000..1eff0ca59 --- /dev/null +++ b/zone/encounter.cpp @@ -0,0 +1,55 @@ +/* EQEMu: Everquest Server Emulator +Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY except by those people which sell it, which +are required to give you total support for your newly bought product; +without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef _WINDOWS + #if (!defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER < 1900)) + #define snprintf _snprintf + #define vsnprintf _vsnprintf + #endif + #define strncasecmp _strnicmp + #define strcasecmp _stricmp +#endif + +#include "../common/races.h" +#include "encounter.h" +#include "entity.h" +#include "mob.h" + +class Zone; + +Encounter::Encounter(const char* enc_name) + :Mob + ( + nullptr, nullptr, 0, 0, 0, INVISIBLE_MAN, 0, BT_NoTarget, 0, 0, 0, 0, 0, glm::vec4(0,0,0,0), 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, EQEmu::TintProfile(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ) +{ + encounter_name[0] = 0; + strn0cpy(encounter_name, enc_name, 64); + remove_me = false; +} + +Encounter::~Encounter() +{ + +} + +bool Encounter::Process() { + if (remove_me) return false; + return true; +} diff --git a/zone/encounter.h b/zone/encounter.h new file mode 100644 index 000000000..ed8faec34 --- /dev/null +++ b/zone/encounter.h @@ -0,0 +1,62 @@ +/* EQEMu: Everquest Server Emulator +Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY except by those people which sell it, which +are required to give you total support for your newly bought product; +without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef ENCOUNTER_H +#define ENCOUNTER_H + +#include "mob.h" +#include "../common/types.h" +#include "../common/timer.h" + +class Group; +class Raid; +struct ExtraAttackOptions; + +class Encounter : public Mob +{ +public: + Encounter(const char* enc_name); + ~Encounter(); + + //abstract virtual function implementations required by base abstract class + virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) { return true; } + virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0) { return; } + virtual bool Attack(Mob* other, int Hand = EQEmu::legacy::SlotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, + ExtraAttackOptions *opts = nullptr, int special = 0) { + return false; + } + virtual bool HasRaid() { return false; } + virtual bool HasGroup() { return false; } + virtual Raid* GetRaid() { return 0; } + virtual Group* GetGroup() { return 0; } + + bool IsEncounter() const { return true; } + const char* GetEncounterName() const { return encounter_name; } + + bool Process(); + virtual void Depop(bool not_used = true) { remove_me = true; } + + +protected: + bool remove_me; + char encounter_name[64]; + +private: +}; + +#endif diff --git a/zone/entity.cpp b/zone/entity.cpp index 1a9d43601..255bdb3bf 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -54,14 +54,13 @@ #endif extern Zone *zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; extern NetConnection net; extern uint32 numclients; extern PetitionList petition_list; extern char errorname[32]; -extern uint16 adverrornum; Entity::Entity() { @@ -82,7 +81,7 @@ Client *Entity::CastToClient() } #ifdef _EQDEBUG if (!IsClient()) { - Log.Out(Logs::General, Logs::Error, "CastToClient error (not client)"); + Log.Out(Logs::General, Logs::Error, "CastToClient error (not client)"); return 0; } #endif @@ -176,6 +175,11 @@ Beacon *Entity::CastToBeacon() return static_cast(this); } +Encounter *Entity::CastToEncounter() +{ + return static_cast(this); +} + const Client *Entity::CastToClient() const { if (this == 0x00) { @@ -266,6 +270,11 @@ const Beacon* Entity::CastToBeacon() const return static_cast(this); } +const Encounter* Entity::CastToEncounter() const +{ + return static_cast(this); +} + #ifdef BOTS Bot *Entity::CastToBot() { @@ -462,17 +471,27 @@ void EntityList::CorpseProcess() void EntityList::MobProcess() { -#ifdef IDLE_WHEN_EMPTY - if (numclients < 1) - return; -#endif + bool mob_dead; + auto it = mob_list.begin(); while (it != mob_list.end()) { uint16 id = it->first; Mob *mob = it->second; size_t sz = mob_list.size(); - bool p_val = mob->Process(); + +#ifdef IDLE_WHEN_EMPTY + // spawn_events can cause spawns and deaths while zone empty. + // At the very least, process that. + if (numclients < 1) { + mob_dead = mob->CastToNPC()->GetDepop(); + } + else { + mob_dead = !mob->Process(); + } +#else + mob_dead = !mob->Process(); +#endif size_t a_sz = mob_list.size(); if(a_sz > sz) { @@ -485,7 +504,7 @@ void EntityList::MobProcess() ++it; } - if(!p_val) { + if(mob_dead) { if(mob->IsNPC()) { entity_list.RemoveNPC(id); } @@ -536,6 +555,21 @@ void EntityList::BeaconProcess() } } +void EntityList::EncounterProcess() +{ + auto it = encounter_list.begin(); + while (it != encounter_list.end()) { + if (!it->second->Process()) { + safe_delete(it->second); + free_ids.push(it->first); + it = encounter_list.erase(it); + } + else { + ++it; + } + } +} + void EntityList::AddGroup(Group *group) { if (group == nullptr) //this seems to be happening somehow... @@ -543,7 +577,7 @@ void EntityList::AddGroup(Group *group) uint32 gid = worldserver.NextGroupID(); if (gid == 0) { - Log.Out(Logs::General, Logs::Error, + Log.Out(Logs::General, Logs::Error, "Unable to get new group ID from world server. group is going to be broken."); return; } @@ -572,7 +606,7 @@ void EntityList::AddRaid(Raid *raid) uint32 gid = worldserver.NextGroupID(); if (gid == 0) { - Log.Out(Logs::General, Logs::Error, + Log.Out(Logs::General, Logs::Error, "Unable to get new group ID from world server. group is going to be broken."); return; } @@ -610,6 +644,7 @@ 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); /* Web Interface: NPC Spawn (Pop) */ @@ -631,15 +666,17 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) uint16 emoteid = npc->GetEmoteID(); if (emoteid != 0) npc->DoNPCEmote(ONSPAWN, emoteid); - + npc->SetSpawned(); if (SendSpawnPacket) { if (dontqueue) { // aka, SEND IT NOW BITCH! - EQApplicationPacket *app = new EQApplicationPacket; + auto app = new EQApplicationPacket; npc->CreateSpawnPacket(app, npc); QueueClients(npc, app); + npc->SendArmorAppearance(); + npc->SetAppearance(npc->GetGuardPointAnim(),false); safe_delete(app); } else { - NewSpawn_Struct *ns = new NewSpawn_Struct; + auto ns = new NewSpawn_Struct; memset(ns, 0, sizeof(NewSpawn_Struct)); npc->FillSpawnStruct(ns, nullptr); // Not working on player newspawns, so it's safe to use a ForWho of 0 AddToSpawnQueue(npc->GetID(), &ns); @@ -651,6 +688,16 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) npc_list.insert(std::pair(npc->GetID(), npc)); mob_list.insert(std::pair(npc->GetID(), npc)); + + /* Zone controller process EVENT_SPAWN_ZONE */ + if (RuleB(Zone, UseZoneController)) { + if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && npc->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){ + char data_pass[100] = { 0 }; + snprintf(data_pass, 99, "%d %d", npc->GetID(), npc->GetNPCTypeID()); + parse->EventNPC(EVENT_SPAWN_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0); + } + } + } void EntityList::AddMerc(Merc *merc, bool SendSpawnPacket, bool dontqueue) @@ -658,19 +705,19 @@ void EntityList::AddMerc(Merc *merc, bool SendSpawnPacket, bool dontqueue) if (merc) { merc->SetID(GetFreeID()); - + merc->SetSpawned(); if (SendSpawnPacket) { if (dontqueue) { // Send immediately - EQApplicationPacket *outapp = new EQApplicationPacket(); + auto outapp = new EQApplicationPacket(); merc->CreateSpawnPacket(outapp); outapp->priority = 6; QueueClients(merc, outapp, true); safe_delete(outapp); } else { // Queue the packet - NewSpawn_Struct *ns = new NewSpawn_Struct; + auto ns = new NewSpawn_Struct; memset(ns, 0, sizeof(NewSpawn_Struct)); merc->FillSpawnStruct(ns, 0); AddToSpawnQueue(merc->GetID(), &ns); @@ -725,6 +772,12 @@ void EntityList::AddBeacon(Beacon *beacon) beacon_list.insert(std::pair(beacon->GetID(), beacon)); } +void EntityList::AddEncounter(Encounter *encounter) +{ + encounter->SetID(GetFreeID()); + encounter_list.insert(std::pair(encounter->GetID(), encounter)); +} + void EntityList::AddToSpawnQueue(uint16 entityid, NewSpawn_Struct **ns) { uint32 count; @@ -745,10 +798,23 @@ void EntityList::CheckSpawnQueue() EQApplicationPacket *outapp = 0; iterator.Reset(); + NewSpawn_Struct *ns; + while(iterator.MoreElements()) { outapp = new EQApplicationPacket; - Mob::CreateSpawnPacket(outapp, iterator.GetData()); + ns = iterator.GetData(); + Mob::CreateSpawnPacket(outapp, ns); QueueClients(0, outapp); + auto it = npc_list.find(ns->spawn.spawnId); + if (it == npc_list.end()) { + // We must of despawned, hope that's the reason! + Log.Out(Logs::General, Logs::Error, "Error in EntityList::CheckSpawnQueue: Unable to find NPC for spawnId '%u'", ns->spawn.spawnId); + } + else { + NPC *pnpc = it->second; + pnpc->SendArmorAppearance(); + pnpc->SetAppearance(pnpc->GetGuardPointAnim(), false); + } safe_delete(outapp); iterator.RemoveCurrent(); } @@ -820,7 +886,7 @@ bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket *app, Client *client) if (door_list.empty()) return false; - uint32 mask_test = client->GetClientVersionBit(); + uint32 mask_test = client->ClientVersionBit(); int count = 0; auto it = door_list.begin(); @@ -835,7 +901,7 @@ bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket *app, Client *client) return false; uint32 length = count * sizeof(Door_Struct); - uchar *packet_buffer = new uchar[length]; + auto packet_buffer = new uchar[length]; memset(packet_buffer, 0, length); uchar *ptr = packet_buffer; Doors *door; @@ -876,12 +942,18 @@ bool EntityList::MakeDoorSpawnPacket(EQApplicationPacket *app, Client *client) Entity *EntityList::GetEntityMob(uint16 id) { - return mob_list.count(id) ? mob_list.at(id) : nullptr; + auto it = mob_list.find(id); + if (it != mob_list.end()) + return it->second; + return nullptr; } Entity *EntityList::GetEntityMerc(uint16 id) { - return merc_list.count(id) ? merc_list.at(id) : nullptr; + auto it = merc_list.find(id); + if (it != merc_list.end()) + return it->second; + return nullptr; } Entity *EntityList::GetEntityMob(const char *name) @@ -901,12 +973,18 @@ Entity *EntityList::GetEntityMob(const char *name) Entity *EntityList::GetEntityDoor(uint16 id) { - return door_list.count(id) ? door_list.at(id) : nullptr; + auto it = door_list.find(id); + if (it != door_list.end()) + return it->second; + return nullptr; } Entity *EntityList::GetEntityCorpse(uint16 id) { - return corpse_list.count(id) ? corpse_list.at(id) : nullptr; + auto it = corpse_list.find(id); + if (it != corpse_list.end()) + return it->second; + return nullptr; } Entity *EntityList::GetEntityCorpse(const char *name) @@ -926,17 +1004,34 @@ Entity *EntityList::GetEntityCorpse(const char *name) Entity *EntityList::GetEntityTrap(uint16 id) { - return trap_list.count(id) ? trap_list.at(id) : nullptr; + auto it = trap_list.find(id); + if (it != trap_list.end()) + return it->second; + return nullptr; } Entity *EntityList::GetEntityObject(uint16 id) { - return object_list.count(id) ? object_list.at(id) : nullptr; + auto it = object_list.find(id); + if (it != object_list.end()) + return it->second; + return nullptr; } Entity *EntityList::GetEntityBeacon(uint16 id) { - return beacon_list.count(id) ? beacon_list.at(id) : nullptr; + auto it = beacon_list.find(id); + if (it != beacon_list.end()) + return it->second; + return nullptr; +} + +Entity *EntityList::GetEntityEncounter(uint16 id) +{ + auto it = encounter_list.find(id); + if (it != encounter_list.end()) + return it->second; + return nullptr; } Entity *EntityList::GetID(uint16 get_id) @@ -954,6 +1049,8 @@ Entity *EntityList::GetID(uint16 get_id) return ent; else if ((ent=entity_list.GetEntityBeacon(get_id)) != 0) return ent; + else if ((ent = entity_list.GetEntityEncounter(get_id)) != 0) + return ent; else return 0; } @@ -1130,6 +1227,8 @@ void EntityList::ChannelMessage(Mob *from, uint8 chan_num, uint8 language, void EntityList::ChannelMessageSend(Mob *to, uint8 chan_num, uint8 language, const char *message, ...) { + if (!to->IsClient()) + return; va_list argptr; char buffer[4096]; @@ -1137,8 +1236,7 @@ void EntityList::ChannelMessageSend(Mob *to, uint8 chan_num, uint8 language, con vsnprintf(buffer, 4096, message, argptr); va_end(argptr); - if (client_list.count(to->GetID())) - client_list.at(to->GetID())->ChannelMessageSend(0, 0, chan_num, language, buffer); + to->CastToClient()->ChannelMessageSend(0, 0, chan_num, language, buffer); } void EntityList::SendZoneSpawns(Client *client) @@ -1168,19 +1266,64 @@ void EntityList::SendZoneSpawnsBulk(Client *client) NewSpawn_Struct ns; Mob *spawn; uint32 maxspawns = 100; + EQApplicationPacket *app; if (maxspawns > mob_list.size()) maxspawns = mob_list.size(); - BulkZoneSpawnPacket *bzsp = new BulkZoneSpawnPacket(client, maxspawns); + auto bzsp = new BulkZoneSpawnPacket(client, maxspawns); + + bool delaypkt = false; + const glm::vec4& cpos = client->GetPosition(); + const float dmax = 600.0 * 600.0; for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { spawn = it->second; - if (spawn && spawn->InZone()) { + if (spawn && spawn->GetID() > 0 && spawn->Spawned()) { if (spawn->IsClient() && (spawn->CastToClient()->GMHideMe(client) || spawn->CastToClient()->IsHoveringForRespawn())) continue; - memset(&ns, 0, sizeof(NewSpawn_Struct)); - spawn->FillSpawnStruct(&ns, client); - bzsp->AddSpawn(&ns); + +#if 1 + const glm::vec4& spos = spawn->GetPosition(); + + delaypkt = false; + if (DistanceSquared(cpos, spos) > dmax || (spawn->IsClient() && (spawn->GetRace() == MINOR_ILL_OBJ || spawn->GetRace() == TREE))) + delaypkt = true; + + if (delaypkt) { + app = new EQApplicationPacket; + spawn->CreateSpawnPacket(app); + client->QueuePacket(app, true, Client::CLIENT_CONNECTED); + safe_delete(app); + } + else { + memset(&ns, 0, sizeof(NewSpawn_Struct)); + spawn->FillSpawnStruct(&ns, client); + bzsp->AddSpawn(&ns); + } + + spawn->SendArmorAppearance(client); +#else + /* original code kept for spawn packet research */ + int32 race = spawn->GetRace(); + + // Illusion races on PCs don't work as a mass spawn + // But they will work as an add_spawn AFTER CLIENT_CONNECTED. + if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) { + app = new EQApplicationPacket; + spawn->CreateSpawnPacket(app); + client->QueuePacket(app, true, Client::CLIENT_CONNECTED); + safe_delete(app); + } + else { + memset(&ns, 0, sizeof(NewSpawn_Struct)); + spawn->FillSpawnStruct(&ns, client); + bzsp->AddSpawn(&ns); + } + + // Despite being sent in the OP_ZoneSpawns packet, the client + // does not display worn armor correctly so display it. + spawn->SendArmorAppearance(client); +#endif } } safe_delete(bzsp); @@ -1217,7 +1360,7 @@ void EntityList::SendZoneCorpsesBulk(Client *client) Corpse *spawn; uint32 maxspawns = 100; - BulkZoneSpawnPacket *bzsp = new BulkZoneSpawnPacket(client, maxspawns); + auto bzsp = new BulkZoneSpawnPacket(client, maxspawns); for (auto it = corpse_list.begin(); it != corpse_list.end(); ++it) { spawn = it->second; @@ -1234,7 +1377,7 @@ void EntityList::SendZoneObjects(Client *client) { auto it = object_list.begin(); while (it != object_list.end()) { - EQApplicationPacket *app = new EQApplicationPacket; + auto app = new EQApplicationPacket; it->second->CreateSpawnPacket(app); client->FastQueuePacket(&app); ++it; @@ -1320,7 +1463,7 @@ void EntityList::RefreshAutoXTargets(Client *c) continue; if (m->CheckAggro(c) && !c->IsXTarget(m)) { - c->AddAutoXTarget(m); + c->AddAutoXTarget(m, false); // we only call this before a bulk, so lets not send right away break; } @@ -1374,7 +1517,9 @@ void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *ap if (c != sender) { if (Target == sender) { if (inspect_buffs) { // if inspect_buffs is true we're sending a mob's buffs to those with the LAA - if (c->IsRaidGrouped()) { + if (c->GetGM() || RuleB(Spells, AlwaysSendTargetsBuffs)) { + Send = true; + } else if (c->IsRaidGrouped()) { Raid *raid = c->GetRaid(); if (!raid) continue; @@ -1398,7 +1543,7 @@ void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *ap } } - if (Send && (c->GetClientVersionBit() & ClientVersionBits)) + if (Send && (c->ClientVersionBit() & ClientVersionBits)) c->QueuePacket(app, ackreq); } } @@ -1873,13 +2018,13 @@ void EntityList::QueueClientsGuild(Mob *sender, const EQApplicationPacket *app, void EntityList::QueueClientsGuildBankItemUpdate(const GuildBankItemUpdate_Struct *gbius, uint32 GuildID) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); GuildBankItemUpdate_Struct *outgbius = (GuildBankItemUpdate_Struct*)outapp->pBuffer; memcpy(outgbius, gbius, sizeof(GuildBankItemUpdate_Struct)); - const Item_Struct *Item = database.GetItem(gbius->ItemID); + const EQEmu::ItemBase *Item = database.GetItem(gbius->ItemID); auto it = client_list.begin(); while (it != client_list.end()) { @@ -2056,7 +2201,7 @@ void EntityList::RemoveAllDoors() void EntityList::DespawnAllDoors() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RemoveAllDoors, 0); + auto outapp = new EQApplicationPacket(OP_RemoveAllDoors, 0); this->QueueClients(0,outapp); safe_delete(outapp); } @@ -2066,7 +2211,7 @@ void EntityList::RespawnAllDoors() auto it = client_list.begin(); while (it != client_list.end()) { if (it->second) { - EQApplicationPacket *outapp = new EQApplicationPacket(); + auto outapp = new EQApplicationPacket(); MakeDoorSpawnPacket(outapp, it->second); it->second->FastQueuePacket(&outapp); } @@ -2285,7 +2430,7 @@ void EntityList::Clear() void EntityList::UpdateWho(bool iSendFullUpdate) { - if ((!worldserver.Connected()) || !ZoneLoaded) + if ((!worldserver.Connected()) || !is_zone_loaded) return; uint32 tmpNumUpdates = numclients + 5; ServerPacket* pack = 0; @@ -2383,12 +2528,14 @@ void EntityList::Depop(bool StartSpawnTimer) if (pnpc->IsFindable()) UpdateFindableNPCState(pnpc, true); + pnpc->WipeHateList(); + + pnpc->Depop(StartSpawnTimer); + /* Web Interface Depop Entities */ std::vector params; params.push_back(std::to_string((long)pnpc->GetID())); RemoteCallSubscriptionHandler::Instance()->OnEvent("NPC.Depop", params); - - pnpc->Depop(StartSpawnTimer); } } } @@ -2564,7 +2711,7 @@ void EntityList::ListNPCs(Client* client, const char *arg1, const char *arg2, ui } } else if (searchtype == 1) { client->Message(0, "Searching by name method. (%s)",arg1); - char* tmp = new char[strlen(arg1) + 1]; + auto tmp = new char[strlen(arg1) + 1]; strcpy(tmp, arg1); strupr(tmp); while (it != npc_list.end()) { @@ -2635,7 +2782,7 @@ void EntityList::FindPathsToAllNPCs() glm::vec3 Node0 = zone->pathing->GetPathNodeCoordinates(0, false); glm::vec3 Dest(it->second->GetX(), it->second->GetY(), it->second->GetZ()); std::deque Route = zone->pathing->FindRoute(Node0, Dest); - if (Route.size() == 0) + if (Route.empty()) printf("Unable to find a route to %s\n", it->second->GetName()); else printf("Found a route to %s\n", it->second->GetName()); @@ -2679,7 +2826,7 @@ int32 EntityList::DeletePlayerCorpses() void EntityList::SendPetitionToAdmins() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_PetitionUpdate,sizeof(PetitionUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_PetitionUpdate, sizeof(PetitionUpdate_Struct)); PetitionUpdate_Struct *pcus = (PetitionUpdate_Struct*) outapp->pBuffer; pcus->petnumber = 0; // Petition Number pcus->color = 0; @@ -2699,7 +2846,7 @@ void EntityList::SendPetitionToAdmins() void EntityList::SendPetitionToAdmins(Petition *pet) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_PetitionUpdate,sizeof(PetitionUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_PetitionUpdate, sizeof(PetitionUpdate_Struct)); PetitionUpdate_Struct *pcus = (PetitionUpdate_Struct*) outapp->pBuffer; pcus->petnumber = pet->GetID(); // Petition Number if (pet->CheckedOut()) { @@ -2732,7 +2879,7 @@ void EntityList::SendPetitionToAdmins(Petition *pet) void EntityList::ClearClientPetitionQueue() { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_PetitionUpdate,sizeof(PetitionUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_PetitionUpdate, sizeof(PetitionUpdate_Struct)); PetitionUpdate_Struct *pet = (PetitionUpdate_Struct*) outapp->pBuffer; pet->color = 0x00; pet->status = 0xFFFFFFFF; @@ -2800,7 +2947,7 @@ void BulkZoneSpawnPacket::SendBuffer() return; uint32 tmpBufSize = (index * sizeof(NewSpawn_Struct)); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZoneSpawns, (unsigned char *)data, tmpBufSize); + auto outapp = new EQApplicationPacket(OP_ZoneSpawns, (unsigned char *)data, tmpBufSize); if (pSendTo) { pSendTo->FastQueuePacket(&outapp); @@ -2941,11 +3088,11 @@ bool EntityList::MakeTrackPacket(Client *client) float MobDistance; if (client->GetClass() == DRUID) - distance = (client->GetSkill(SkillTracking) * 10); + distance = (client->GetSkill(EQEmu::skills::SkillTracking) * 10); else if (client->GetClass() == RANGER) - distance = (client->GetSkill(SkillTracking) * 12); + distance = (client->GetSkill(EQEmu::skills::SkillTracking) * 12); else if (client->GetClass() == BARD) - distance = (client->GetSkill(SkillTracking) * 7); + distance = (client->GetSkill(EQEmu::skills::SkillTracking) * 7); if (distance <= 0) return false; if (distance < 300) @@ -2967,7 +3114,7 @@ bool EntityList::MakeTrackPacket(Client *client) [](const std::pair &a, const std::pair &b) { return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp(); }); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_Track, sizeof(Track_Struct) * tracking_list.size()); + auto outapp = new EQApplicationPacket(OP_Track, sizeof(Track_Struct) * tracking_list.size()); Tracking_Struct *outtrack = (Tracking_Struct *)outapp->pBuffer; outapp->priority = 6; @@ -3024,56 +3171,24 @@ bool EntityList::Fighting(Mob *targ) return false; } -void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 thedam) +void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 hate) { - NPC *cur = nullptr; - uint16 count = 0; - std::list npc_sub_list; - auto it = npc_list.begin(); - while (it != npc_list.end()) { - cur = it->second; + if (hate == 0) + return; - if (!cur->CheckAggro(target)) { - ++it; + for (auto &e : npc_list) { + auto &npc = e.second; + if (!npc->CheckAggro(target) || npc->IsFeared()) continue; - } - if (!cur->IsMezzed() && !cur->IsStunned() && !cur->IsFeared()) { - npc_sub_list.push_back(cur); - ++count; - } - ++it; - } + if (zone->random.Roll(50)) // witness check -- place holder + // This is either a level check (con color check?) or a stat roll + continue; - if (thedam > 1) { - if (count > 0) - thedam /= count; - - if (thedam < 1) - thedam = 1; - } - - cur = nullptr; - auto sit = npc_sub_list.begin(); - while (sit != npc_sub_list.end()) { - cur = *sit; - - if (cur->IsPet()) { - if (caster) { - if (cur->CheckAggro(caster)) { - cur->AddToHateList(caster, thedam); - } - } - } else { - if (caster) { - if (cur->CheckAggro(caster)) { - cur->AddToHateList(caster, thedam); - } else { - cur->AddToHateList(caster, thedam * 0.33); - } - } - } - ++sit; + if ((npc->IsMezzed() || npc->IsStunned()) && hate > 4) // patch notes say stunned/mezzed NPCs get a fraction of the hate + npc->AddToHateList(caster, hate / 4); // made up number + else + npc->AddToHateList(caster, hate); } } @@ -3419,6 +3534,15 @@ bool EntityList::IsMobInZone(Mob *who) } ++it; } + + auto enc_it = encounter_list.begin(); + while (enc_it != encounter_list.end()) { + if (enc_it->second == who) { + return true; + } + ++enc_it; + } + return false; } @@ -3642,7 +3766,7 @@ void EntityList::QuestJournalledSayClose(Mob *sender, Client *QuestInitiator, // Send the message to the quest initiator such that the client will enter it into the NPC Quest Journal if (QuestInitiator) { - char *buf = new char[strlen(mobname) + strlen(message) + 10]; + auto buf = new char[strlen(mobname) + strlen(message) + 10]; sprintf(buf, "%s says, '%s'", mobname, message); QuestInitiator->QuestJournalledMessage(mobname, buf); safe_delete_array(buf); @@ -3712,7 +3836,7 @@ void EntityList::SendGroupLeave(uint32 gid, const char *name) g = c->GetGroup(); if (g) { if (g->GetID() == gid) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; strcpy(gj->membername, name); gj->action = groupActLeave; @@ -3741,7 +3865,7 @@ void EntityList::SendGroupJoin(uint32 gid, const char *name) g = it->second->GetGroup(); if (g) { if (g->GetID() == gid) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; strcpy(gj->membername, name); gj->action = groupActJoin; @@ -3777,15 +3901,15 @@ void EntityList::GroupMessage(uint32 gid, const char *from, const char *message) uint16 EntityList::CreateGroundObject(uint32 itemid, const glm::vec4& position, uint32 decay_time) { - const Item_Struct *is = database.GetItem(itemid); + const EQEmu::ItemBase *is = database.GetItem(itemid); if (!is) return 0; - ItemInst *i = new ItemInst(is, is->MaxCharges); + auto i = new ItemInst(is, is->MaxCharges); if (!i) return 0; - Object *object = new Object(i, position.x, position.y, position.z, position.w,decay_time); + auto object = new Object(i, position.x, position.y, position.z, position.w, decay_time); entity_list.AddObject(object, true); safe_delete(i); @@ -3800,7 +3924,7 @@ uint16 EntityList::CreateGroundObjectFromModel(const char *model, const glm::vec if (!model) return 0; - Object *object = new Object(model, position.x, position.y, position.z, position.w, type); + auto object = new Object(model, position.x, position.y, position.z, position.w, type); entity_list.AddObject(object, true); if (!object) @@ -3814,7 +3938,7 @@ uint16 EntityList::CreateDoor(const char *model, const glm::vec4& position, uint if (!model) return 0; // fell through everything, this is bad/incomplete from perl - Doors *door = new Doors(model, position, opentype, size); + auto door = new Doors(model, position, opentype, size); RemoveAllDoors(); zone->LoadZoneDoors(zone->GetShortName(), zone->GetInstanceVersion()); entity_list.AddDoor(door); @@ -3989,7 +4113,7 @@ void EntityList::ZoneWho(Client *c, Who_All_Struct *Who) } PacketLength = PacketLength + sizeof(WhoAllReturnStruct) + (47 * Entries); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_WhoAllResponse, PacketLength); + auto outapp = new EQApplicationPacket(OP_WhoAllResponse, PacketLength); char *Buffer = (char *)outapp->pBuffer; WhoAllReturnStruct *WARS = (WhoAllReturnStruct *)Buffer; WARS->id = 0; @@ -4175,7 +4299,7 @@ uint16 EntityList::GetClientCount(){ uint16 ClientCount = 0; std::list client_list; entity_list.GetClientList(client_list); - std::list::iterator iter = client_list.begin(); + auto iter = client_list.begin(); while (iter != client_list.end()) { Client *entry = (*iter); entry->GetCleanName(); @@ -4309,7 +4433,7 @@ void EntityList::SendFindableNPCList(Client *c) if (!c) return; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendFindableNPCs, sizeof(FindableNPC_Struct)); + auto outapp = new EQApplicationPacket(OP_SendFindableNPCs, sizeof(FindableNPC_Struct)); FindableNPC_Struct *fnpcs = (FindableNPC_Struct *)outapp->pBuffer; @@ -4344,7 +4468,7 @@ void EntityList::UpdateFindableNPCState(NPC *n, bool Remove) if (!n || !n->IsFindable()) return; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendFindableNPCs, sizeof(FindableNPC_Struct)); + auto outapp = new EQApplicationPacket(OP_SendFindableNPCs, sizeof(FindableNPC_Struct)); FindableNPC_Struct *fnpcs = (FindableNPC_Struct *)outapp->pBuffer; @@ -4362,7 +4486,7 @@ void EntityList::UpdateFindableNPCState(NPC *n, bool Remove) auto it = client_list.begin(); while (it != client_list.end()) { Client *c = it->second; - if (c && (c->GetClientVersion() >= ClientVersion::SoD)) + if (c && (c->ClientVersion() >= EQEmu::versions::ClientVersion::SoD)) c->QueuePacket(outapp); ++it; @@ -4435,9 +4559,9 @@ void EntityList::AddLootToNPCS(uint32 item_id, uint32 count) if (npc_count == 0) return; - NPC **npcs = new NPC*[npc_count]; - int *counts = new int[npc_count]; - bool *marked = new bool[npc_count]; + auto npcs = new NPC *[npc_count]; + auto counts = new int[npc_count]; + auto marked = new bool[npc_count]; memset(counts, 0, sizeof(int) * npc_count); memset(marked, 0, sizeof(bool) * npc_count); @@ -4459,7 +4583,7 @@ void EntityList::AddLootToNPCS(uint32 item_id, uint32 count) for (int j = 0; j < npc_count; ++j) selection.push_back(j); - while (selection.size() > 0 && count > 0) { + while (!selection.empty() && count > 0) { int k = zone->random.Int(0, selection.size() - 1); counts[selection[k]]++; count--; @@ -4479,7 +4603,7 @@ void EntityList::AddLootToNPCS(uint32 item_id, uint32 count) void EntityList::CameraEffect(uint32 duration, uint32 intensity) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_CameraEffect, sizeof(Camera_Struct)); + auto outapp = new EQApplicationPacket(OP_CameraEffect, sizeof(Camera_Struct)); Camera_Struct* cs = (Camera_Struct*) outapp->pBuffer; cs->duration = duration; // Duration in milliseconds cs->intensity = ((intensity * 6710886) + 1023410176); // Intensity ranges from 1023410176 to 1090519040, so simplify it from 0 to 10. @@ -4513,7 +4637,7 @@ NPC *EntityList::GetClosestBanker(Mob *sender, uint32 &distance) void EntityList::ExpeditionWarning(uint32 minutes_left) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_DzExpeditionEndsWarning, sizeof(ExpeditionExpireWarning)); + auto outapp = new EQApplicationPacket(OP_DzExpeditionEndsWarning, sizeof(ExpeditionExpireWarning)); ExpeditionExpireWarning *ew = (ExpeditionExpireWarning*)outapp->pBuffer; ew->minutes_remaining = minutes_left; @@ -4523,6 +4647,7 @@ void EntityList::ExpeditionWarning(uint32 minutes_left) it->second->QueuePacket(outapp); ++it; } + safe_delete(outapp); } Mob *EntityList::GetClosestMobByBodyType(Mob *sender, bodyType BodyType) @@ -4638,7 +4763,7 @@ Mob *EntityList::GetTargetForVirus(Mob *spreader, int range) ++it; } - if(TargetsInRange.size() == 0) + if(TargetsInRange.empty()) return nullptr; return TargetsInRange[zone->random.Int(0, TargetsInRange.size() - 1)]; @@ -4651,3 +4776,11 @@ void EntityList::StopMobAI() mob.second->AI_ShutDown(); } } + +void EntityList::SendAlternateAdvancementStats() { + for(auto &c : client_list) { + c.second->SendAlternateAdvancementTable(); + c.second->SendAlternateAdvancementStats(); + c.second->SendAlternateAdvancementPoints(); + } +} diff --git a/zone/entity.h b/zone/entity.h index 8af87f649..8abb34ca2 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,6 +30,7 @@ #include "position.h" #include "zonedump.h" +class Encounter; class Beacon; class Client; class Corpse; @@ -40,7 +41,7 @@ class EntityList; class Group; class Merc; class Mob; -class NPC; +class NPC; class Object; class Petition; class Raid; @@ -77,6 +78,7 @@ public: virtual bool IsDoor() const { return false; } virtual bool IsTrap() const { return false; } virtual bool IsBeacon() const { return false; } + virtual bool IsEncounter() const { return false; } virtual bool Process() { return false; } virtual bool Save() { return true; } @@ -91,6 +93,7 @@ public: Doors *CastToDoors(); Trap *CastToTrap(); Beacon *CastToBeacon(); + Encounter *CastToEncounter(); const Client *CastToClient() const; const NPC *CastToNPC() const; @@ -101,6 +104,7 @@ public: const Doors *CastToDoors() const; const Trap *CastToTrap() const; const Beacon *CastToBeacon() const; + const Encounter *CastToEncounter() const; inline const uint16& GetID() const { return id; } inline const time_t& GetSpawnTimeStamp() const { return spawn_timestamp; } @@ -144,14 +148,29 @@ public: bool IsMobSpawnedByNpcTypeID(uint32 get_id); Mob *GetTargetForVirus(Mob* spreader, int range); inline NPC *GetNPCByID(uint16 id) - { return npc_list.count(id) ? npc_list.at(id) : nullptr; } + { + auto it = npc_list.find(id); + if (it != npc_list.end()) + return it->second; + return nullptr; + } NPC *GetNPCByNPCTypeID(uint32 npc_id); inline Merc *GetMercByID(uint16 id) - { return merc_list.count(id) ? merc_list.at(id) : nullptr; } + { + auto it = merc_list.find(id); + if (it != merc_list.end()) + return it->second; + return nullptr; + } Client *GetClientByName(const char *name); Client *GetClientByAccID(uint32 accid); inline Client *GetClientByID(uint16 id) - { return client_list.count(id) ? client_list.at(id) : nullptr; } + { + auto it = client_list.find(id); + if (it != client_list.end()) + return it->second; + return nullptr; + } Client *GetClientByCharID(uint32 iCharID); Client *GetClientByWID(uint32 iWID); Client *GetClient(uint32 ip, uint16 port); @@ -168,7 +187,12 @@ public: Corpse *GetCorpseByOwner(Client* client); Corpse *GetCorpseByOwnerWithinRange(Client* client, Mob* center, int range); inline Corpse *GetCorpseByID(uint16 id) - { return corpse_list.count(id) ? corpse_list.at(id) : nullptr; } + { + auto it = corpse_list.find(id); + if (it != corpse_list.end()) + return it->second; + return nullptr; + } Corpse *GetCorpseByDBID(uint32 dbid); Corpse *GetCorpseByName(const char* name); @@ -177,10 +201,20 @@ public: Client* FindCorpseDragger(uint16 CorpseID); inline Object *GetObjectByID(uint16 id) - { return object_list.count(id) ? object_list.at(id) : nullptr; } + { + auto it = object_list.find(id); + if (it != object_list.end()) + return it->second; + return nullptr; + } Object *GetObjectByDBID(uint32 id); inline Doors *GetDoorsByID(uint16 id) - { return door_list.count(id) ? door_list.at(id) : nullptr; } + { + auto it = door_list.find(id); + if (it != door_list.end()) + return it->second; + return nullptr; + } Doors *GetDoorsByDoorID(uint32 id); Doors *GetDoorsByDBID(uint32 id); void RemoveAllCorpsesByCharID(uint32 charid); @@ -203,6 +237,7 @@ public: void MobProcess(); void TrapProcess(); void BeaconProcess(); + void EncounterProcess(); void ProcessMove(Client *c, const glm::vec3& location); void ProcessMove(NPC *n, float x, float y, float z); void AddArea(int id, int type, float min_x, float max_x, float min_y, float max_y, float min_z, float max_z); @@ -228,6 +263,7 @@ public: void AddDoor(Doors* door); void AddTrap(Trap* trap); void AddBeacon(Beacon *beacon); + void AddEncounter(Encounter *encounter); void AddProximity(NPC *proximity_for); void Clear(); bool RemoveMob(uint16 delete_id); @@ -266,6 +302,7 @@ public: Entity *GetEntityCorpse(uint16 id); Entity *GetEntityTrap(uint16 id); Entity *GetEntityBeacon(uint16 id); + Entity *GetEntityEncounter(uint16 id); Entity *GetEntityMob(const char *name); Entity *GetEntityCorpse(const char *name); @@ -315,8 +352,8 @@ public: void QueueToGroupsForNPCHealthAA(Mob* sender, const EQApplicationPacket* app); void QueueManaged(Mob* sender, const EQApplicationPacket* app, bool ignore_sender=false, bool ackreq = true); - void AEAttack(Mob *attacker, float dist, int Hand = MainPrimary, int count = 0, bool IsFromSpell = false); - void AETaunt(Client *caster, float range = 0); + void AEAttack(Mob *attacker, float dist, int Hand = EQEmu::legacy::SlotPrimary, int count = 0, bool IsFromSpell = false); + void AETaunt(Client *caster, float range=0, int32 bonus_hate=0); void AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true, int16 resist_adjust = 0); void MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true); void AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true); @@ -326,7 +363,7 @@ public: void SendAlarm(Trap* trap, Mob* currenttarget, uint8 kos); Trap* FindNearbyTrap(Mob* searcher, float max_dist); - void AddHealAggro(Mob* target, Mob* caster, uint16 thedam); + void AddHealAggro(Mob* target, Mob* caster, uint16 hate); Mob* FindDefenseNPC(uint32 npcid); void OpenDoorsNear(NPC* opener); void UpdateWho(bool iSendFullUpdate = false); @@ -391,7 +428,6 @@ public: void SaveAllClientsTaskState(); void ReloadAllClientsTaskState(int TaskID=0); - uint16 CreateGroundObject(uint32 itemid, const glm::vec4& position, uint32 decay_time = 300000); uint16 CreateGroundObjectFromModel(const char *model, const glm::vec4& position, uint8 type = 0x00, uint32 decay_time = 0); uint16 CreateDoor(const char *model, const glm::vec4& position, uint8 type = 0, uint16 size = 100); @@ -422,6 +458,7 @@ public: uint16 GetFreeID(); void RefreshAutoXTargets(Client *c); void RefreshClientXTargets(Client *c); + void SendAlternateAdvancementStats(); protected: friend class Zone; @@ -448,6 +485,7 @@ private: std::unordered_map door_list; std::unordered_map trap_list; std::unordered_map beacon_list; + std::unordered_map encounter_list; std::list proximity_list; std::list group_list; std::list raid_list; @@ -458,7 +496,6 @@ private: #ifdef BOTS public: void AddBot(Bot* newBot, bool SendSpawnPacket = true, bool dontqueue = false); - void BotPickLock(Bot* rogue); bool RemoveBot(uint16 entityID); Mob* GetMobByBotID(uint32 botID); Bot* GetBotByBotID(uint32 botID); diff --git a/zone/event_codes.h b/zone/event_codes.h index f793efaf6..1b0e18505 100644 --- a/zone/event_codes.h +++ b/zone/event_codes.h @@ -82,7 +82,9 @@ typedef enum { EVENT_RESPAWN, EVENT_DEATH_COMPLETE, EVENT_UNHANDLED_OPCODE, - + EVENT_TICK, + EVENT_SPAWN_ZONE, + EVENT_DEATH_ZONE, _LargestEventID } QuestEventID; diff --git a/zone/exp.cpp b/zone/exp.cpp index 7e878206a..93c689b7c 100644 --- a/zone/exp.cpp +++ b/zone/exp.cpp @@ -59,6 +59,97 @@ static uint32 MaxBankedRaidLeadershipPoints(int Level) return 10; } +uint32 Client::CalcEXP(uint8 conlevel) { + + uint32 in_add_exp = EXP_FORMULA; + + + if((XPRate != 0)) + in_add_exp = static_cast(in_add_exp * (static_cast(XPRate) / 100.0f)); + + float totalmod = 1.0; + float zemmod = 1.0; + //get modifiers + if(RuleR(Character, ExpMultiplier) >= 0){ + totalmod *= RuleR(Character, ExpMultiplier); + } + + if(zone->newzone_data.zone_exp_multiplier >= 0){ + zemmod *= zone->newzone_data.zone_exp_multiplier; + } + + if(RuleB(Character,UseRaceClassExpBonuses)) + { + if(GetBaseRace() == HALFLING){ + totalmod *= 1.05; + } + + if(GetClass() == ROGUE || GetClass() == WARRIOR){ + totalmod *= 1.05; + } + } + + if(zone->IsHotzone()) + { + totalmod += RuleR(Zone, HotZoneBonus); + } + + in_add_exp = uint32(float(in_add_exp) * totalmod * zemmod); + + if(RuleB(Character,UseXPConScaling)) + { + if (conlevel != 0xFF) { + switch (conlevel) + { + case CON_GREEN: + in_add_exp = 0; + return 0; + case CON_LIGHTBLUE: + in_add_exp = in_add_exp * RuleI(Character, LightBlueModifier)/100; + break; + case CON_BLUE: + in_add_exp = in_add_exp * RuleI(Character, BlueModifier)/100; + break; + case CON_WHITE: + in_add_exp = in_add_exp * RuleI(Character, WhiteModifier)/100; + break; + case CON_YELLOW: + in_add_exp = in_add_exp * RuleI(Character, YellowModifier)/100; + break; + case CON_RED: + in_add_exp = in_add_exp * RuleI(Character, RedModifier)/100; + break; + } + } + } + + 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){ + in_add_exp *= zone->level_exp_mod[GetLevel()].ExpMod; + } + } + + return in_add_exp; +} + void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) { this->EVENT_ITEM_ScriptStopReturn(); @@ -78,7 +169,7 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) { //figure out how much of this goes to AAs add_aaxp = add_exp * m_epp.perAA / 100; - //take that ammount away from regular exp + //take that amount away from regular exp add_exp -= add_aaxp; float totalmod = 1.0; @@ -247,12 +338,22 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) { Message(13, "Error in Client::SetEXP. EXP not set."); return; // Must be invalid class/race } + uint32 i = 0; + uint32 membercount = 0; + if(GetGroup()) + { + for (i = 0; i < MAX_GROUP_MEMBERS; i++) { + if (GetGroup()->members[i] != nullptr) { + membercount++; + } + } + } if ((set_exp + set_aaxp) > (m_pp.exp+m_pp.expAA)) { if (isrezzexp) this->Message_StringID(MT_Experience, REZ_REGAIN); else{ - if(this->IsGrouped()) + if(membercount > 1) this->Message_StringID(MT_Experience, GAIN_GROUPXP); else if(IsRaidGrouped()) Message_StringID(MT_Experience, GAIN_RAIDEXP); @@ -268,12 +369,17 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) { //this ammount of exp (once these loops complete) uint16 check_level = GetLevel()+1; //see if we gained any levels + bool level_increase = true; + int8 level_count = 0; + while (set_exp >= GetEXPForLevel(check_level)) { check_level++; if (check_level > 127) { //hard level cap check_level = 127; break; } + level_count++; + if(GetMercID()) UpdateMercLevel(); } @@ -284,6 +390,7 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) { check_level = 2; break; } + level_increase = false; if(GetMercID()) UpdateMercLevel(); } @@ -364,17 +471,21 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) { if ((GetLevel() != check_level) && !(check_level >= maxlevel)) { char val1[20]={0}; - if (GetLevel() == check_level-1){ - Message_StringID(MT_Experience, GAIN_LEVEL,ConvertArray(check_level,val1)); - SendLevelAppearance(); - /* Message(15, "You have gained a level! Welcome to level %i!", check_level); */ - } - if (GetLevel() == check_level){ - Message_StringID(MT_Experience, LOSE_LEVEL,ConvertArray(check_level,val1)); - /* Message(15, "You lost a level! You are now level %i!", check_level); */ + if (level_increase) + { + if (level_count == 1) + Message_StringID(MT_Experience, GAIN_LEVEL, ConvertArray(check_level, val1)); + else + Message(15, "Welcome to level %i!", check_level); + + if (check_level == RuleI(Character, DeathItemLossLevel)) + Message_StringID(15, CORPSE_ITEM_LOST); + + if (check_level == RuleI(Character, DeathExpLossLevel)) + Message_StringID(15, CORPSE_EXP_LOST); } else - Message(15, "Welcome to level %i!", check_level); + Message_StringID(MT_Experience, LOSE_LEVEL, ConvertArray(check_level, val1)); #ifdef BOTS uint8 myoldlevel = GetLevel(); @@ -404,14 +515,14 @@ void Client::SetEXP(uint32 set_exp, uint32 set_aaxp, bool isrezzexp) { if (GetLevel() < 51) { m_epp.perAA = 0; // turn off aa exp if they drop below 51 } else - SendAAStats(); //otherwise, send them an AA update + SendAlternateAdvancementStats(); //otherwise, send them an AA update //send the expdata in any case so the xp bar isnt stuck after leveling uint32 tmpxp1 = GetEXPForLevel(GetLevel()+1); uint32 tmpxp2 = GetEXPForLevel(GetLevel()); // Quag: crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc) if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct)); ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer; float tmpxp = (float) ( (float) set_exp-tmpxp2 ) / ( (float) tmpxp1-tmpxp2 ); eu->exp = (uint32)(330.0f * tmpxp); @@ -434,7 +545,7 @@ void Client::SetLevel(uint8 set_level, bool command) return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_LevelUpdate, sizeof(LevelUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_LevelUpdate, sizeof(LevelUpdate_Struct)); LevelUpdate_Struct* lu = (LevelUpdate_Struct*)outapp->pBuffer; lu->level = set_level; if(m_pp.level2 != 0) @@ -554,6 +665,41 @@ uint32 Client::GetEXPForLevel(uint16 check_level) mod *= 1000; uint32 finalxp = uint32(base * mod); + + if(RuleB(Character,UseOldRaceExpPenalties)) + { + float racemod = 1.0; + if(GetBaseRace() == TROLL || GetBaseRace() == IKSAR) { + racemod = 1.2; + } else if(GetBaseRace() == OGRE) { + racemod = 1.15; + } else if(GetBaseRace() == BARBARIAN) { + racemod = 1.05; + } else if(GetBaseRace() == HALFLING) { + racemod = 0.95; + } + + finalxp = uint32(finalxp * racemod); + } + + if(RuleB(Character,UseOldClassExpPenalties)) + { + float classmod = 1.0; + if(GetClass() == PALADIN || GetClass() == SHADOWKNIGHT || GetClass() == RANGER || GetClass() == BARD) { + classmod = 1.4; + } else if(GetClass() == MONK) { + classmod = 1.2; + } else if(GetClass() == WIZARD || GetClass() == ENCHANTER || GetClass() == MAGICIAN || GetClass() == NECROMANCER) { + classmod = 1.1; + } else if(GetClass() == ROGUE) { + classmod = 0.91; + } else if(GetClass() == WARRIOR) { + classmod = 0.9; + } + + finalxp = uint32(finalxp * classmod); + } + finalxp = mod_client_xp_for_level(finalxp, check_level); return finalxp; @@ -594,8 +740,8 @@ void Group::SplitExp(uint32 exp, Mob* other) { groupmod = 2.16; else groupmod = 1.0; - - groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier))); + if(membercount > 1 && membercount <= 6) + groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier))); int conlevel = Mob::GetLevelCon(maxlevel, other->GetLevel()); if(conlevel == CON_GREEN) @@ -692,7 +838,7 @@ void Client::AddLeadershipEXP(uint32 group_exp, uint32 raid_exp) { } void Client::SendLeadershipEXPUpdate() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_LeadershipExpUpdate, sizeof(LeadershipExpUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_LeadershipExpUpdate, sizeof(LeadershipExpUpdate_Struct)); LeadershipExpUpdate_Struct* eu = (LeadershipExpUpdate_Struct *) outapp->pBuffer; eu->group_leadership_exp = m_pp.group_leadership_exp; @@ -714,7 +860,7 @@ uint32 Client::GetCharMaxLevelFromQGlobal() { QGlobalCache::Combine(globalMap, char_c->GetBucket(), ntype, this->CharacterID(), zone->GetZoneID()); } - std::list::iterator iter = globalMap.begin(); + auto iter = globalMap.begin(); uint32 gcount = 0; while(iter != globalMap.end()) { if((*iter).name.compare("CharMaxLevel") == 0){ diff --git a/zone/fearpath.cpp b/zone/fearpath.cpp index 0b33a662e..aa369b4c9 100644 --- a/zone/fearpath.cpp +++ b/zone/fearpath.cpp @@ -33,7 +33,7 @@ extern Zone* zone; //this is called whenever we are damaged to process possible fleeing void Mob::CheckFlee() { //if were allready fleeing, dont need to check more... - if(flee_mode && curfp) + if(flee_mode && currently_fleeing) return; //dont bother if we are immune to fleeing @@ -101,7 +101,7 @@ void Mob::ProcessFlee() //When ImmuneToFlee effect fades it will turn fear back on and check if it can still flee. if (flee_mode && (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) && !spellbonuses.IsFeared && !spellbonuses.IsBlind) { - curfp = false; + currently_fleeing = false; return; } @@ -118,34 +118,11 @@ void Mob::ProcessFlee() //see if we are legitimately feared or blind now if (!spellbonuses.IsFeared && !spellbonuses.IsBlind) { //not feared or blind... were done... - curfp = false; + currently_fleeing = false; return; } } -float Mob::GetFearSpeed() -{ - if (flee_mode) { - //we know ratio < FLEE_HP_RATIO - float speed = GetBaseRunspeed(); - float ratio = GetHPRatio(); - float multiplier = RuleR(Combat, FleeMultiplier); - - if (GetSnaredAmount() > 40) - multiplier = multiplier / 6.0f; - - speed = speed * ratio * multiplier / 100; - - //NPC will eventually stop. Snares speeds this up. - if (speed < 0.09) - speed = 0.0001f; - - return speed; - } - // fear and blind use their normal run speed - return GetRunspeed(); -} - void Mob::CalculateNewFearpoint() { if(RuleB(Pathing, Fear) && zone->pathing) @@ -160,10 +137,10 @@ void Mob::CalculateNewFearpoint() std::deque Route = zone->pathing->FindRoute(CurrentPosition, Loc); - if(Route.size() > 0) + if(!Route.empty()) { m_FearWalkTarget = glm::vec3(Loc.x, Loc.y, Loc.z); - curfp = true; + currently_fleeing = true; Log.Out(Logs::Detail, Logs::None, "Feared to node %i (%8.3f, %8.3f, %8.3f)", Node, Loc.x, Loc.y, Loc.z); return; @@ -174,7 +151,7 @@ void Mob::CalculateNewFearpoint() int loop = 0; float ranx, rany, ranz; - curfp = false; + currently_fleeing = false; while (loop < 100) //Max 100 tries { int ran = 250 - (loop*2); @@ -187,11 +164,11 @@ void Mob::CalculateNewFearpoint() float fdist = ranz - GetZ(); if (fdist >= -12 && fdist <= 12 && CheckCoordLosNoZLeaps(GetX(),GetY(),GetZ(),ranx,rany,ranz)) { - curfp = true; + currently_fleeing = true; break; } } - if (curfp) + if (currently_fleeing) m_FearWalkTarget = glm::vec3(ranx, rany, ranz); else //Break fear BuffFadeByEffect(SE_Fear); diff --git a/zone/forage.cpp b/zone/forage.cpp index 96b0efcdc..324467025 100644 --- a/zone/forage.cpp +++ b/zone/forage.cpp @@ -153,21 +153,21 @@ uint32 ZoneDatabase::GetZoneFishing(uint32 ZoneID, uint8 skill, uint32 &npc_id, //we need this function to immediately determine, after we receive OP_Fishing, if we can even try to fish, otherwise we have to wait a while to get the failure bool Client::CanFish() { //make sure we still have a fishing pole on: - const ItemInst* Pole = m_inv[MainPrimary]; - int32 bslot = m_inv.HasItemByUse(ItemTypeFishingBait, 1, invWhereWorn|invWherePersonal); + const ItemInst* Pole = m_inv[EQEmu::legacy::SlotPrimary]; + int32 bslot = m_inv.HasItemByUse(EQEmu::item::ItemTypeFishingBait, 1, invWhereWorn | invWherePersonal); const ItemInst* Bait = nullptr; if (bslot != INVALID_INDEX) Bait = m_inv.GetItem(bslot); - if(!Pole || !Pole->IsType(ItemClassCommon) || Pole->GetItem()->ItemType != ItemTypeFishingPole) { - if (m_inv.HasItemByUse(ItemTypeFishingPole, 1, invWhereWorn|invWherePersonal|invWhereBank|invWhereSharedBank|invWhereTrading|invWhereCursor)) //We have a fishing pole somewhere, just not equipped + if (!Pole || !Pole->IsClassCommon() || Pole->GetItem()->ItemType != EQEmu::item::ItemTypeFishingPole) { + if (m_inv.HasItemByUse(EQEmu::item::ItemTypeFishingPole, 1, invWhereWorn | invWherePersonal | invWhereBank | invWhereSharedBank | invWhereTrading | invWhereCursor)) //We have a fishing pole somewhere, just not equipped Message_StringID(MT_Skills, FISHING_EQUIP_POLE); //You need to put your fishing pole in your primary hand. else //We don't have a fishing pole anywhere Message_StringID(MT_Skills, FISHING_NO_POLE); //You can't fish without a fishing pole, go buy one. return false; } - if (!Bait || !Bait->IsType(ItemClassCommon) || Bait->GetItem()->ItemType != ItemTypeFishingBait) { + if (!Bait || !Bait->IsClassCommon() || Bait->GetItem()->ItemType != EQEmu::item::ItemTypeFishingBait) { Message_StringID(MT_Skills, FISHING_NO_BAIT); //You can't fish without fishing bait, go buy some. return false; } @@ -185,26 +185,35 @@ bool Client::CanFish() { rodPosition.x = m_Position.x + RodLength * sin(HeadingDegrees * M_PI/180.0f); rodPosition.y = m_Position.y + RodLength * cos(HeadingDegrees * M_PI/180.0f); + rodPosition.z = m_Position.z; - // Do BestZ to find where the line hanging from the rod intersects the water (if it is water). - // and go 1 unit into the water. - glm::vec3 dest; - dest.x = rodPosition.x; - dest.y = rodPosition.y; - dest.z = m_Position.z+10; - - rodPosition.z = zone->zonemap->FindBestZ(dest, nullptr) + 4; - bool in_lava = zone->watermap->InLava(rodPosition); - bool in_water = zone->watermap->InWater(rodPosition) || zone->watermap->InVWater(rodPosition); - //Message(0, "Rod is at %4.3f, %4.3f, %4.3f, InWater says %d, InLava says %d", RodX, RodY, RodZ, in_water, in_lava); - if (in_lava) { - Message_StringID(MT_Skills, FISHING_LAVA); //Trying to catch a fire elemental or something? + float bestz = zone->zonemap->FindBestZ(rodPosition, nullptr); + float len = m_Position.z - bestz; + if(len > LineLength || len < 0.0f) { + Message_StringID(MT_Skills, FISHING_LAND); return false; } - if((!in_water) || (m_Position.z-rodPosition.z)>LineLength) { //Didn't hit the water OR the water is too far below us - Message_StringID(MT_Skills, FISHING_LAND); //Trying to catch land sharks perhaps? - return false; + + float step_size = RuleR(Watermap, FishingLineStepSize); + + for(float i = 0.0f; i < len; i += step_size) { + glm::vec3 dest(rodPosition.x, rodPosition.y, m_Position.z - i); + + bool in_lava = zone->watermap->InLava(dest); + bool in_water = zone->watermap->InWater(dest) || zone->watermap->InVWater(dest); + + if (in_lava) { + Message_StringID(MT_Skills, FISHING_LAVA); //Trying to catch a fire elemental or something? + return false; + } + + if(in_water) { + return true; + } } + + Message_StringID(MT_Skills, FISHING_LAND); + return false; } return true; } @@ -240,16 +249,16 @@ void Client::GoFish() //success formula is not researched at all - int fishing_skill = GetSkill(SkillFishing); //will take into account skill bonuses on pole & bait + int fishing_skill = GetSkill(EQEmu::skills::SkillFishing); //will take into account skill bonuses on pole & bait //make sure we still have a fishing pole on: - int32 bslot = m_inv.HasItemByUse(ItemTypeFishingBait, 1, invWhereWorn|invWherePersonal); + int32 bslot = m_inv.HasItemByUse(EQEmu::item::ItemTypeFishingBait, 1, invWhereWorn | invWherePersonal); const ItemInst* Bait = nullptr; if (bslot != INVALID_INDEX) Bait = m_inv.GetItem(bslot); //if the bait isnt equipped, need to add its skill bonus - if(bslot >= EmuConstants::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == SkillFishing) { + if (bslot >= EQEmu::legacy::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == EQEmu::skills::SkillFishing) { fishing_skill += Bait->GetItem()->SkillModValue; } @@ -274,14 +283,14 @@ void Client::GoFish() if(tmp != nullptr) { auto positionNPC = GetPosition(); positionNPC.x = positionNPC.x + 3; - NPC* npc = new NPC(tmp, nullptr, positionNPC, FlyMode3); - npc->AddLootTable(); + auto npc = new NPC(tmp, nullptr, positionNPC, FlyMode3); + npc->AddLootTable(); - 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..."); } } } @@ -295,7 +304,7 @@ void Client::GoFish() food_id = common_fish_ids[index]; } - const Item_Struct* food_item = database.GetItem(food_id); + const EQEmu::ItemBase* food_item = database.GetItem(food_id); Message_StringID(MT_Skills, FISHING_SUCCESS); ItemInst* inst = database.CreateItem(food_item, 1); @@ -308,12 +317,12 @@ void Client::GoFish() else { PushItemOnCursor(*inst); - SendItemPacket(MainCursor, inst, ItemPacketSummonItem); + SendItemPacket(EQEmu::legacy::SlotCursor, inst, ItemPacketLimbo); if(RuleB(TaskSystem, EnableTaskSystem)) UpdateTasksForItem(ActivityFish, food_id); safe_delete(inst); - inst = m_inv.GetItem(MainCursor); + inst = m_inv.GetItem(EQEmu::legacy::SlotCursor); } if(inst) { @@ -345,19 +354,19 @@ void Client::GoFish() //and then swap out items in primary slot... too lazy to fix right now if (zone->random.Int(0, 49) == 1) { Message_StringID(MT_Skills, FISHING_POLE_BROKE); //Your fishing pole broke! - DeleteItemInInventory(MainPrimary, 0, true); + DeleteItemInInventory(EQEmu::legacy::SlotPrimary, 0, true); } - if(CheckIncreaseSkill(SkillFishing, nullptr, 5)) + if (CheckIncreaseSkill(EQEmu::skills::SkillFishing, nullptr, 5)) { - if(title_manager.IsNewTradeSkillTitleAvailable(SkillFishing, GetRawSkill(SkillFishing))) + if (title_manager.IsNewTradeSkillTitleAvailable(EQEmu::skills::SkillFishing, GetRawSkill(EQEmu::skills::SkillFishing))) NotifyNewTitlesAvailable(); } } void Client::ForageItem(bool guarantee) { - int skill_level = GetSkill(SkillForage); + int skill_level = GetSkill(EQEmu::skills::SkillForage); //be wary of the string ids in switch below when changing this. uint32 common_food_ids[MAX_COMMON_FOOD_IDS] = { @@ -387,7 +396,7 @@ void Client::ForageItem(bool guarantee) { foragedfood = common_food_ids[index]; } - const Item_Struct* food_item = database.GetItem(foragedfood); + const EQEmu::ItemBase* food_item = database.GetItem(foragedfood); if(!food_item) { Log.Out(Logs::General, Logs::Error, "nullptr returned from database.GetItem in ClientForageItem"); @@ -398,20 +407,18 @@ void Client::ForageItem(bool guarantee) { stringid = FORAGE_GRUBS; else switch(food_item->ItemType) { - - case ItemTypeFood: - stringid = FORAGE_FOOD; - break; - - case ItemTypeDrink: - if(strstr(food_item->Name, "ater")) - stringid = FORAGE_WATER; - else - stringid = FORAGE_DRINK; - break; - default: - break; - } + case EQEmu::item::ItemTypeFood: + stringid = FORAGE_FOOD; + break; + case EQEmu::item::ItemTypeDrink: + if(strstr(food_item->Name, "ater")) + stringid = FORAGE_WATER; + else + stringid = FORAGE_DRINK; + break; + default: + break; + } Message_StringID(MT_Skills, stringid); ItemInst* inst = database.CreateItem(food_item, 1); @@ -424,12 +431,12 @@ void Client::ForageItem(bool guarantee) { } else { PushItemOnCursor(*inst); - SendItemPacket(MainCursor, inst, ItemPacketSummonItem); + SendItemPacket(EQEmu::legacy::SlotCursor, inst, ItemPacketLimbo); if(RuleB(TaskSystem, EnableTaskSystem)) UpdateTasksForItem(ActivityForage, foragedfood); safe_delete(inst); - inst = m_inv.GetItem(MainCursor); + inst = m_inv.GetItem(EQEmu::legacy::SlotCursor); } if(inst) { @@ -450,7 +457,7 @@ void Client::ForageItem(bool guarantee) { parse->EventPlayer(EVENT_FORAGE_FAILURE, this, "", 0); } - CheckIncreaseSkill(SkillForage, nullptr, 5); + CheckIncreaseSkill(EQEmu::skills::SkillForage, nullptr, 5); } diff --git a/zone/groups.cpp b/zone/groups.cpp index d65bafcfe..2162e735e 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,6 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include "../common/global_define.h" #include "../common/eqemu_logsys.h" #include "masterentity.h" @@ -271,7 +272,7 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte int x=1; //build the template join packet - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; strcpy(gj->membername, NewMemberName); gj->action = groupActJoin; @@ -394,7 +395,7 @@ void Group::SendHPPacketsTo(Mob *member) { members[i]->CreateHPPacket(&hpapp); member->CastToClient()->QueuePacket(&hpapp, false); - if(member->CastToClient()->GetClientVersion() >= ClientVersion::SoD) + if (member->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobManaUpdate); MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp.pBuffer; @@ -425,7 +426,7 @@ void Group::SendHPPacketsFrom(Mob *member) if(members[i] && members[i] != member && members[i]->IsClient()) { members[i]->CastToClient()->QueuePacket(&hp_app); - if(members[i]->CastToClient()->GetClientVersion() >= ClientVersion::SoD) + if (members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobManaUpdate); MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp.pBuffer; @@ -533,7 +534,7 @@ void Group::SendGroupJoinOOZ(Mob* NewMember) { } //send updates to clients out of zone... - ServerPacket* pack = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct)); + auto pack = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct)); ServerGroupJoin_Struct* gj = (ServerGroupJoin_Struct*)pack->pBuffer; gj->gid = GetID(); gj->zoneid = zone->GetZoneID(); @@ -565,7 +566,7 @@ bool Group::DelMemberOOZ(const char *Name) { if(GroupCount() < 3) { UnDelegateMarkNPC(NPCMarkerName.c_str()); - if(GetLeader() && GetLeader()->IsClient() && GetLeader()->CastToClient()->GetClientVersion() < ClientVersion::SoD) { + if (GetLeader() && GetLeader()->IsClient() && GetLeader()->CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::SoD) { UnDelegateMainAssist(MainAssistName.c_str()); } ClearAllNPCMarks(); @@ -633,7 +634,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender) return true; } - ServerPacket* pack = new ServerPacket(ServerOP_GroupLeave, sizeof(ServerGroupLeave_Struct)); + auto pack = new ServerPacket(ServerOP_GroupLeave, sizeof(ServerGroupLeave_Struct)); ServerGroupLeave_Struct* gl = (ServerGroupLeave_Struct*)pack->pBuffer; gl->gid = GetID(); gl->zoneid = zone->GetZoneID(); @@ -642,7 +643,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender) worldserver.SendPacket(pack); safe_delete(pack); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* gu = (GroupJoin_Struct*) outapp->pBuffer; gu->action = groupActLeave; strcpy(gu->membername, oldmember->GetCleanName()); @@ -723,7 +724,7 @@ bool Group::DelMember(Mob* oldmember, bool ignoresender) if(GroupCount() < 3) { UnDelegateMarkNPC(NPCMarkerName.c_str()); - if(GetLeader() && GetLeader()->IsClient() && GetLeader()->CastToClient()->GetClientVersion() < ClientVersion::SoD) { + if (GetLeader() && GetLeader()->IsClient() && GetLeader()->CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::SoD) { UnDelegateMainAssist(MainAssistName.c_str()); } ClearAllNPCMarks(); @@ -846,7 +847,8 @@ void Group::GroupMessage(Mob* sender, uint8 language, uint8 lang_skill, const ch members[i]->CastToClient()->ChannelMessageSend(sender->GetName(),members[i]->GetName(),2,language,lang_skill,message); } - ServerPacket* pack = new ServerPacket(ServerOP_OOZGroupMessage, sizeof(ServerGroupChannelMessage_Struct) + strlen(message) + 1); + auto pack = + new ServerPacket(ServerOP_OOZGroupMessage, sizeof(ServerGroupChannelMessage_Struct) + strlen(message) + 1); ServerGroupChannelMessage_Struct* gcm = (ServerGroupChannelMessage_Struct*)pack->pBuffer; gcm->zoneid = zone->GetZoneID(); gcm->groupid = GetID(); @@ -871,7 +873,7 @@ uint32 Group::GetTotalGroupDamage(Mob* other) { } void Group::DisbandGroup() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate_Struct)); GroupUpdate_Struct* gu = (GroupUpdate_Struct*) outapp->pBuffer; gu->action = groupActDisband; @@ -915,7 +917,7 @@ void Group::DisbandGroup() { ClearAllNPCMarks(); - ServerPacket* pack = new ServerPacket(ServerOP_DisbandGroup, sizeof(ServerDisbandGroup_Struct)); + auto pack = new ServerPacket(ServerOP_DisbandGroup, sizeof(ServerDisbandGroup_Struct)); ServerDisbandGroup_Struct* dg = (ServerDisbandGroup_Struct*)pack->pBuffer; dg->zoneid = zone->GetZoneID(); dg->groupid = GetID(); @@ -938,6 +940,41 @@ void Group::DisbandGroup() { safe_delete(outapp); } +void Group::GetMemberList(std::list& member_list, bool clear_list) +{ + if (clear_list) + member_list.clear(); + + for (auto member_iter : members) { + if (member_iter) + member_list.push_back(member_iter); + } +} + +void Group::GetClientList(std::list& client_list, bool clear_list) +{ + if (clear_list) + client_list.clear(); + + for (auto client_iter : members) { + if (client_iter && client_iter->IsClient()) + client_list.push_back(client_iter->CastToClient()); + } +} + +#ifdef BOTS +void Group::GetBotList(std::list& bot_list, bool clear_list) +{ + if (clear_list) + bot_list.clear(); + + for (auto bot_iter : members) { + if (bot_iter && bot_iter->IsBot()) + bot_list.push_back(bot_iter->CastToBot()); + } +} +#endif + bool Group::Process() { if(disbandcheck && !GroupCount()) return false; @@ -951,7 +988,7 @@ void Group::SendUpdate(uint32 type, Mob* member) if(!member->IsClient()) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct)); GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer; gu->action = type; strcpy(gu->yourname,member->GetName()); @@ -985,7 +1022,7 @@ void Group::SendLeadershipAAUpdate() // If a group member is not in the same zone as the leader when the leader purchases a new AA, they will not become // aware of it until they are next in the same zone as the leader. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* gu = (GroupJoin_Struct*)outapp->pBuffer; gu->action = groupActAAUpdate; gu->leader_aas = LeaderAbilities; @@ -1392,7 +1429,7 @@ void Group::MarkNPC(Mob* Target, int Number) MarkedNPCs[Number - 1] = EntityID; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MarkNPC, sizeof(MarkNPC_Struct)); + auto outapp = new EQApplicationPacket(OP_MarkNPC, sizeof(MarkNPC_Struct)); MarkNPC_Struct* mnpcs = (MarkNPC_Struct *)outapp->pBuffer; @@ -1568,7 +1605,7 @@ void Group::NotifyMainTank(Client *c, uint8 toggle) if(!MainTankName.size()) return; - if(c->GetClientVersion() < ClientVersion::SoD) + if (c->ClientVersion() < EQEmu::versions::ClientVersion::SoD) { if(toggle) c->Message(0, "%s is now Main Tank.", MainTankName.c_str()); @@ -1577,7 +1614,7 @@ void Group::NotifyMainTank(Client *c, uint8 toggle) } else { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupRoles, sizeof(GroupRole_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupRoles, sizeof(GroupRole_Struct)); GroupRole_Struct *grs = (GroupRole_Struct*)outapp->pBuffer; @@ -1608,9 +1645,9 @@ void Group::NotifyMainAssist(Client *c, uint8 toggle) if(!MainAssistName.size()) return; - if(c->GetClientVersion() < ClientVersion::SoD) + if (c->ClientVersion() < EQEmu::versions::ClientVersion::SoD) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_DelegateAbility, sizeof(DelegateAbility_Struct)); + auto outapp = new EQApplicationPacket(OP_DelegateAbility, sizeof(DelegateAbility_Struct)); DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; @@ -1630,7 +1667,7 @@ void Group::NotifyMainAssist(Client *c, uint8 toggle) } else { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupRoles, sizeof(GroupRole_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupRoles, sizeof(GroupRole_Struct)); GroupRole_Struct *grs = (GroupRole_Struct*)outapp->pBuffer; @@ -1663,7 +1700,7 @@ void Group::NotifyPuller(Client *c, uint8 toggle) if(!PullerName.size()) return; - if(c->GetClientVersion() < ClientVersion::SoD) + if (c->ClientVersion() < EQEmu::versions::ClientVersion::SoD) { if(toggle) c->Message(0, "%s is now Puller.", PullerName.c_str()); @@ -1672,7 +1709,7 @@ void Group::NotifyPuller(Client *c, uint8 toggle) } else { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GroupRoles, sizeof(GroupRole_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupRoles, sizeof(GroupRole_Struct)); GroupRole_Struct *grs = (GroupRole_Struct*)outapp->pBuffer; @@ -1724,7 +1761,7 @@ void Group::UnDelegateMainAssist(const char *OldMainAssistName, uint8 toggle) // informing them of the change and update the group_leaders table. // if(OldMainAssistName == MainAssistName) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_DelegateAbility, sizeof(DelegateAbility_Struct)); + auto outapp = new EQApplicationPacket(OP_DelegateAbility, sizeof(DelegateAbility_Struct)); DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; @@ -1882,7 +1919,7 @@ void Group::NotifyAssistTarget(Client *c) if(!c) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SetGroupTarget, sizeof(MarkNPC_Struct)); + auto outapp = new EQApplicationPacket(OP_SetGroupTarget, sizeof(MarkNPC_Struct)); MarkNPC_Struct* mnpcs = (MarkNPC_Struct *)outapp->pBuffer; @@ -1955,7 +1992,7 @@ void Group::NotifyMarkNPC(Client *c) if(!NPCMarkerName.size()) return; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_DelegateAbility, sizeof(DelegateAbility_Struct)); + auto outapp = new EQApplicationPacket(OP_DelegateAbility, sizeof(DelegateAbility_Struct)); DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; @@ -1997,7 +2034,7 @@ void Group::UnDelegateMarkNPC(const char *OldNPCMarkerName) if(!NPCMarkerName.size()) return; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_DelegateAbility, sizeof(DelegateAbility_Struct)); + auto outapp = new EQApplicationPacket(OP_DelegateAbility, sizeof(DelegateAbility_Struct)); DelegateAbility_Struct* das = (DelegateAbility_Struct*)outapp->pBuffer; @@ -2031,8 +2068,8 @@ void Group::SaveGroupLeaderAA() { // Stores the Group Leaders Leadership AA data from the Player Profile as a blob in the group_leaders table. // This is done so that group members not in the same zone as the Leader still have access to this information. - char *queryBuffer = new char[sizeof(GroupLeadershipAA_Struct) * 2 + 1]; - database.DoEscapeString(queryBuffer, (char*)&LeaderAbilities, sizeof(GroupLeadershipAA_Struct)); + auto queryBuffer = new char[sizeof(GroupLeadershipAA_Struct) * 2 + 1]; + database.DoEscapeString(queryBuffer, (char *)&LeaderAbilities, sizeof(GroupLeadershipAA_Struct)); std::string query = "UPDATE group_leaders SET leadershipaa = '"; query += queryBuffer; @@ -2081,7 +2118,7 @@ void Group::SendMarkedNPCsToMember(Client *c, bool Clear) if(!c) return; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MarkNPC, sizeof(MarkNPC_Struct)); + auto outapp = new EQApplicationPacket(OP_MarkNPC, sizeof(MarkNPC_Struct)); MarkNPC_Struct *mnpcs = (MarkNPC_Struct *)outapp->pBuffer; @@ -2216,7 +2253,7 @@ void Group::ChangeLeader(Mob* newleader) Mob* oldleader = GetLeader(); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* gu = (GroupJoin_Struct*) outapp->pBuffer; gu->action = groupActMakeLeader; @@ -2229,7 +2266,7 @@ void Group::ChangeLeader(Mob* newleader) for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) { if (members[i] && members[i]->IsClient()) { - if(members[i]->CastToClient()->GetClientVersion() >= ClientVersion::SoD) + if (members[i]->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) members[i]->CastToClient()->SendGroupLeaderChangePacket(newleader->GetName()); members[i]->CastToClient()->QueuePacket(outapp); @@ -2294,6 +2331,30 @@ void Group::SetPuller(const char *NewPullerName) } } +bool Group::AmIMainTank(const char *mob_name) +{ + if (!mob_name) + return false; + + return !((bool)MainTankName.compare(mob_name)); +} + +bool Group::AmIMainAssist(const char *mob_name) +{ + if (!mob_name) + return false; + + return !((bool)MainTankName.compare(mob_name)); +} + +bool Group::AmIPuller(const char *mob_name) +{ + if (!mob_name) + return false; + + return !((bool)PullerName.compare(mob_name)); +} + bool Group::HasRole(Mob *m, uint8 Role) { if(!m) diff --git a/zone/groups.h b/zone/groups.h index 7dcbd848b..3da2aae54 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -59,6 +59,11 @@ public: bool DelMemberOOZ(const char *Name); bool DelMember(Mob* oldmember,bool ignoresender = false); void DisbandGroup(); + void GetMemberList(std::list& member_list, bool clear_list = true); + void GetClientList(std::list& client_list, bool clear_list = true); +#ifdef BOTS + void GetBotList(std::list& bot_list, bool clear_list = true); +#endif bool IsGroupMember(Mob* client); bool IsGroupMember(const char *Name); bool Process(); @@ -123,6 +128,9 @@ public: const char *GetMainTankName() { return MainTankName.c_str(); } const char *GetMainAssistName() { return MainAssistName.c_str(); } const char *GetPullerName() { return PullerName.c_str(); } + bool AmIMainTank(const char *mob_name); + bool AmIMainAssist(const char *mob_name); + bool AmIPuller(const char *mob_name); void SetNPCMarker(const char *NewNPCMarkerName); void UnMarkNPC(uint16 ID); void SendMarkedNPCsToMember(Client *c, bool Clear = false); diff --git a/zone/guild.cpp b/zone/guild.cpp index 12f785b02..6cba3677a 100644 --- a/zone/guild.cpp +++ b/zone/guild.cpp @@ -26,7 +26,7 @@ extern WorldServer worldserver; void Client::SendGuildMOTD(bool GetGuildMOTDReply) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildMOTD, sizeof(GuildMOTD_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildMOTD, sizeof(GuildMOTD_Struct)); // When the Client gets an OP_GuildMOTD, it compares the text to the version it has previously stored. // If the text in the OP_GuildMOTD packet is the same, it does nothing. If not the same, it displays @@ -63,12 +63,13 @@ void Client::SendGuildMOTD(bool GetGuildMOTDReply) { void Client::SendGuildURL() { - if(GetClientVersion() < ClientVersion::SoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::SoF) return; if(IsInAGuild()) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildUpdateURLAndChannel, sizeof(GuildUpdateURLAndChannel_Struct)); + auto outapp = + new EQApplicationPacket(OP_GuildUpdateURLAndChannel, sizeof(GuildUpdateURLAndChannel_Struct)); GuildUpdateURLAndChannel_Struct *guuacs = (GuildUpdateURLAndChannel_Struct*) outapp->pBuffer; @@ -84,12 +85,13 @@ void Client::SendGuildURL() void Client::SendGuildChannel() { - if(GetClientVersion() < ClientVersion::SoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::SoF) return; if(IsInAGuild()) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildUpdateURLAndChannel, sizeof(GuildUpdateURLAndChannel_Struct)); + auto outapp = + new EQApplicationPacket(OP_GuildUpdateURLAndChannel, sizeof(GuildUpdateURLAndChannel_Struct)); GuildUpdateURLAndChannel_Struct *guuacs = (GuildUpdateURLAndChannel_Struct*) outapp->pBuffer; @@ -106,7 +108,7 @@ void Client::SendGuildChannel() void Client::SendGuildRanks() { - if(GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) return; int permissions = 30 + 1; //Static number of permissions in all EQ clients as of May 2014 @@ -119,7 +121,8 @@ void Client::SendGuildRanks() { while(i < permissions) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildUpdateURLAndChannel, sizeof(GuildUpdateRanks_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildUpdateURLAndChannel, + sizeof(GuildUpdateRanks_Struct)); GuildUpdateRanks_Struct *guuacs = (GuildUpdateRanks_Struct*) outapp->pBuffer; //guuacs->Unknown0008 = this->GuildID(); strncpy(guuacs->Unknown0012, this->GetCleanName(), 64); @@ -149,7 +152,7 @@ void Client::SendGuildSpawnAppearance() { uint8 rank = guild_mgr.GetDisplayedRank(GuildID(), GuildRank(), CharacterID()); Log.Out(Logs::Detail, Logs::Guilds, "Sending spawn appearance for guild %d at rank %d", GuildID(), rank); SendAppearancePacket(AT_GuildID, GuildID()); - if(GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { switch (rank) { case 0: { rank = 5; break; } // GUILD_MEMBER 0 @@ -187,7 +190,7 @@ void Client::SendGuildMembers() { if(data == nullptr) return; //invalid guild, shouldent happen. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GuildMemberList); + auto outapp = new EQApplicationPacket(OP_GuildMemberList); outapp->size = len; outapp->pBuffer = data; data = nullptr; @@ -196,7 +199,8 @@ void Client::SendGuildMembers() { FastQueuePacket(&outapp); - ServerPacket* pack = new ServerPacket(ServerOP_RequestOnlineGuildMembers, sizeof(ServerRequestOnlineGuildMembers_Struct)); + auto pack = + new ServerPacket(ServerOP_RequestOnlineGuildMembers, sizeof(ServerRequestOnlineGuildMembers_Struct)); ServerRequestOnlineGuildMembers_Struct *srogms = (ServerRequestOnlineGuildMembers_Struct*)pack->pBuffer; @@ -235,7 +239,7 @@ void Client::RefreshGuildInfo() { if(WasBanker != GuildBanker) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SetGuildRank, sizeof(GuildSetRank_Struct)); + auto outapp = new EQApplicationPacket(OP_SetGuildRank, sizeof(GuildSetRank_Struct)); GuildSetRank_Struct *gsrs = (GuildSetRank_Struct*)outapp->pBuffer; @@ -248,7 +252,9 @@ void Client::RefreshGuildInfo() if((guild_id != OldGuildID) && GuildBanks) { - ClearGuildBank(); + // Unsure about this for RoF+ ... But they don't have that action anymore so fuck it + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) + ClearGuildBank(); if(guild_id != GUILD_NONE) GuildBanks->SendGuildBank(this); @@ -326,7 +332,7 @@ void EntityList::SendGuildList() { } void Client::SendGuildJoin(GuildJoin_Struct* gj){ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GuildManageAdd, sizeof(GuildJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildManageAdd, sizeof(GuildJoin_Struct)); GuildJoin_Struct* outgj=(GuildJoin_Struct*)outapp->pBuffer; outgj->class_ = gj->class_; outgj->guild_id = gj->guild_id; diff --git a/zone/guild_mgr.cpp b/zone/guild_mgr.cpp index a5188def9..57f83a981 100644 --- a/zone/guild_mgr.cpp +++ b/zone/guild_mgr.cpp @@ -29,11 +29,11 @@ ZoneGuildManager guild_mgr; GuildBankManager *GuildBanks; extern WorldServer worldserver; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; void ZoneGuildManager::SendGuildRefresh(uint32 guild_id, bool name, bool motd, bool rank, bool relation) { Log.Out(Logs::Detail, Logs::Guilds, "Sending guild refresh for %d to world, changes: name=%d, motd=%d, rank=d, relation=%d", guild_id, name, motd, rank, relation); - ServerPacket* pack = new ServerPacket(ServerOP_RefreshGuild, sizeof(ServerGuildRefresh_Struct)); + auto pack = new ServerPacket(ServerOP_RefreshGuild, sizeof(ServerGuildRefresh_Struct)); ServerGuildRefresh_Struct *s = (ServerGuildRefresh_Struct *) pack->pBuffer; s->guild_id = guild_id; s->name_change = name; @@ -58,7 +58,7 @@ void ZoneGuildManager::SendCharRefresh(uint32 old_guild_id, uint32 guild_id, uin Log.Out(Logs::Detail, Logs::Guilds, "Sending char refresh for %d from guild %d to world", charid, guild_id); - ServerPacket* pack = new ServerPacket(ServerOP_GuildCharRefresh, sizeof(ServerGuildCharRefresh_Struct)); + auto pack = new ServerPacket(ServerOP_GuildCharRefresh, sizeof(ServerGuildCharRefresh_Struct)); ServerGuildCharRefresh_Struct *s = (ServerGuildCharRefresh_Struct *) pack->pBuffer; s->guild_id = guild_id; s->old_guild_id = old_guild_id; @@ -74,7 +74,7 @@ void ZoneGuildManager::SendRankUpdate(uint32 CharID) if(!GetCharInfo(CharID, gci)) return; - ServerPacket* pack = new ServerPacket(ServerOP_GuildRankUpdate, sizeof(ServerGuildRankUpdate_Struct)); + auto pack = new ServerPacket(ServerOP_GuildRankUpdate, sizeof(ServerGuildRankUpdate_Struct)); ServerGuildRankUpdate_Struct *sgrus = (ServerGuildRankUpdate_Struct*)pack->pBuffer; @@ -90,7 +90,7 @@ void ZoneGuildManager::SendRankUpdate(uint32 CharID) void ZoneGuildManager::SendGuildDelete(uint32 guild_id) { Log.Out(Logs::Detail, Logs::Guilds, "Sending guild delete for guild %d to world", guild_id); - ServerPacket* pack = new ServerPacket(ServerOP_DeleteGuild, sizeof(ServerGuildID_Struct)); + auto pack = new ServerPacket(ServerOP_DeleteGuild, sizeof(ServerGuildID_Struct)); ServerGuildID_Struct *s = (ServerGuildID_Struct *) pack->pBuffer; s->guild_id = guild_id; worldserver.SendPacket(pack); @@ -322,7 +322,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { else if(c != nullptr && s->guild_id != GUILD_NONE) { //char is in zone, and has changed into a new guild, send MOTD. c->SendGuildMOTD(); - if(c->GetClientVersion() >= ClientVersion::RoF) + if (c->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { c->SendGuildRanks(); } @@ -334,7 +334,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { case ServerOP_GuildRankUpdate: { - if(ZoneLoaded) + if(is_zone_loaded) { if(pack->size != sizeof(ServerGuildRankUpdate_Struct)) { @@ -346,7 +346,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { ServerGuildRankUpdate_Struct *sgrus = (ServerGuildRankUpdate_Struct*)pack->pBuffer; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SetGuildRank, sizeof(GuildSetRank_Struct)); + auto outapp = new EQApplicationPacket(OP_SetGuildRank, sizeof(GuildSetRank_Struct)); GuildSetRank_Struct *gsrs = (GuildSetRank_Struct*)outapp->pBuffer; @@ -388,9 +388,9 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { { ServerGuildMemberUpdate_Struct *sgmus = (ServerGuildMemberUpdate_Struct*)pack->pBuffer; - if(ZoneLoaded) + if(is_zone_loaded) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct)); GuildMemberUpdate_Struct *gmus = (GuildMemberUpdate_Struct*)outapp->pBuffer; @@ -407,7 +407,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { break; } case ServerOP_OnlineGuildMembersResponse: - if (ZoneLoaded) + if (is_zone_loaded) { char *Buffer = (char *)pack->pBuffer; @@ -421,7 +421,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { break; } Log.Out(Logs::Detail, Logs::Guilds,"Processing ServerOP_OnlineGuildMembersResponse"); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildMemberUpdate, sizeof(GuildMemberUpdate_Struct)); GuildMemberUpdate_Struct *gmus = (GuildMemberUpdate_Struct*)outapp->pBuffer; char Name[64]; gmus->LastSeen = time(nullptr); @@ -443,7 +443,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { case ServerOP_LFGuildUpdate: { - if(ZoneLoaded) + if(is_zone_loaded) { char GuildName[33]; char Comments[257]; @@ -464,7 +464,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { if(GuildID == GUILD_NONE) break; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_LFGuild, sizeof(LFGuild_GuildToggle_Struct)); + auto outapp = new EQApplicationPacket(OP_LFGuild, sizeof(LFGuild_GuildToggle_Struct)); LFGuild_GuildToggle_Struct *gts = (LFGuild_GuildToggle_Struct *)outapp->pBuffer; gts->Command = 1; @@ -487,7 +487,7 @@ void ZoneGuildManager::ProcessWorldPacket(ServerPacket *pack) { void ZoneGuildManager::SendGuildMemberUpdateToWorld(const char *MemberName, uint32 GuildID, uint16 ZoneID, uint32 LastSeen) { - ServerPacket* pack = new ServerPacket(ServerOP_GuildMemberUpdate, sizeof(ServerGuildMemberUpdate_Struct)); + auto pack = new ServerPacket(ServerOP_GuildMemberUpdate, sizeof(ServerGuildMemberUpdate_Struct)); ServerGuildMemberUpdate_Struct *sgmus = (ServerGuildMemberUpdate_Struct*)pack->pBuffer; sgmus->GuildID = GuildID; @@ -501,7 +501,8 @@ void ZoneGuildManager::SendGuildMemberUpdateToWorld(const char *MemberName, uint void ZoneGuildManager::RequestOnlineGuildMembers(uint32 FromID, uint32 GuildID) { - ServerPacket* pack = new ServerPacket(ServerOP_RequestOnlineGuildMembers, sizeof(ServerRequestOnlineGuildMembers_Struct)); + auto pack = + new ServerPacket(ServerOP_RequestOnlineGuildMembers, sizeof(ServerRequestOnlineGuildMembers_Struct)); ServerRequestOnlineGuildMembers_Struct *srogm = (ServerRequestOnlineGuildMembers_Struct*)pack->pBuffer; srogm->FromID = FromID; @@ -526,7 +527,7 @@ void ZoneGuildManager::ProcessApproval() void ZoneGuildManager::AddGuildApproval(const char* guildname,Client* owner) { - GuildApproval* tmp = new GuildApproval(guildname,owner,GetFreeID()); + auto tmp = new GuildApproval(guildname, owner, GetFreeID()); list.Insert(tmp); } @@ -586,7 +587,7 @@ GuildApproval* ZoneGuildManager::FindGuildByOwnerApproval(Client* owner) GuildBankManager::~GuildBankManager() { - std::list::iterator Iterator = Banks.begin(); + auto Iterator = Banks.begin(); while(Iterator != Banks.end()) { @@ -606,57 +607,56 @@ bool GuildBankManager::Load(uint32 guildID) return false; } - GuildBank *bank = new GuildBank; + auto bank = new GuildBank; - bank->GuildID = guildID; + bank->GuildID = guildID; - for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) - bank->Items.MainArea[i].ItemID = 0; + for (int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) + bank->Items.MainArea[i].ItemID = 0; - for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) - bank->Items.DepositArea[i].ItemID = 0; + for (int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) + bank->Items.DepositArea[i].ItemID = 0; - char donator[64], whoFor[64]; + char donator[64], whoFor[64]; - for (auto row = results.begin(); row != results.end(); ++row) - { - int area = atoi(row[0]); - int slot = atoi(row[1]); - int itemID = atoi(row[2]); - int qty = atoi(row[3]); + for (auto row = results.begin(); row != results.end(); ++row) { + int area = atoi(row[0]); + int slot = atoi(row[1]); + int itemID = atoi(row[2]); + int qty = atoi(row[3]); - if(row[4]) - strn0cpy(donator, row[4], sizeof(donator)); - else - donator[0] = '\0'; + if (row[4]) + strn0cpy(donator, row[4], sizeof(donator)); + else + donator[0] = '\0'; - int permissions = atoi(row[5]); + int permissions = atoi(row[5]); - if(row[6]) - strn0cpy(whoFor, row[6], sizeof(whoFor)); - else - whoFor[0] = '\0'; + if (row[6]) + strn0cpy(whoFor, row[6], sizeof(whoFor)); + else + whoFor[0] = '\0'; - if(slot < 0) - continue; + if (slot < 0) + continue; - GuildBankItem *itemSection = nullptr; + GuildBankItem *itemSection = nullptr; - if (area == GuildBankMainArea && slot < GUILD_BANK_MAIN_AREA_SIZE) - itemSection = bank->Items.MainArea; - else if (area != GuildBankMainArea && slot < GUILD_BANK_DEPOSIT_AREA_SIZE) - itemSection = bank->Items.DepositArea; - else - continue; + if (area == GuildBankMainArea && slot < GUILD_BANK_MAIN_AREA_SIZE) + itemSection = bank->Items.MainArea; + else if (area != GuildBankMainArea && slot < GUILD_BANK_DEPOSIT_AREA_SIZE) + itemSection = bank->Items.DepositArea; + else + continue; - itemSection[slot].ItemID = itemID; - itemSection[slot].Quantity = qty; + itemSection[slot].ItemID = itemID; + itemSection[slot].Quantity = qty; - strn0cpy(itemSection[slot].Donator, donator, sizeof(donator)); + strn0cpy(itemSection[slot].Donator, donator, sizeof(donator)); - itemSection[slot].Permissions = permissions; + itemSection[slot].Permissions = permissions; - strn0cpy(itemSection[slot].WhoFor, whoFor, sizeof(whoFor)); + strn0cpy(itemSection[slot].WhoFor, whoFor, sizeof(whoFor)); } Banks.push_back(bank); @@ -666,7 +666,7 @@ bool GuildBankManager::Load(uint32 guildID) bool GuildBankManager::IsLoaded(uint32 GuildID) { - std::list::iterator Iterator = GetGuildBank(GuildID); + auto Iterator = GetGuildBank(GuildID); return (Iterator != Banks.end()); } @@ -679,7 +679,7 @@ void GuildBankManager::SendGuildBank(Client *c) if(!IsLoaded(c->GuildID())) Load(c->GuildID()); - std::list::iterator Iterator = GetGuildBank(c->GuildID()); + auto Iterator = GetGuildBank(c->GuildID()); if(Iterator == Banks.end()) { @@ -688,37 +688,94 @@ void GuildBankManager::SendGuildBank(Client *c) return; } + auto &guild_bank = *Iterator; + + // RoF+ uses a bulk list packet -- This is also how the Action 0 of older clients basically works + if (c->ClientVersionBit() & EQEmu::versions::bit_RoFAndLater) { + auto outapp = new EQApplicationPacket(OP_GuildBankItemList, sizeof(GuildBankItemListEntry_Struct) * 240); + for (int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) { + const EQEmu::ItemBase *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID); + if (Item) { + outapp->WriteUInt8(1); + outapp->WriteUInt32(guild_bank->Items.DepositArea[i].Permissions); + outapp->WriteString(guild_bank->Items.DepositArea[i].WhoFor); + outapp->WriteString(guild_bank->Items.DepositArea[i].Donator); + outapp->WriteUInt32(Item->ID); + outapp->WriteUInt32(Item->Icon); + if (Item->Stackable) { + outapp->WriteUInt32(guild_bank->Items.DepositArea[i].Quantity); + outapp->WriteUInt8(Item->StackSize == guild_bank->Items.DepositArea[i].Quantity ? 0 : 1); + } else { + outapp->WriteUInt32(1); + outapp->WriteUInt8(0); + } + outapp->WriteUInt8(Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()) ? 1 : 0); + outapp->WriteString(Item->Name); + } else { + outapp->WriteUInt8(0); // empty + } + } + outapp->SetWritePosition(outapp->GetWritePosition() + 20); // newer clients have 40 deposit slots, keep them 0 for now + + for (int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) { + const EQEmu::ItemBase *Item = database.GetItem(guild_bank->Items.MainArea[i].ItemID); + if (Item) { + outapp->WriteUInt8(1); + outapp->WriteUInt32(guild_bank->Items.MainArea[i].Permissions); + outapp->WriteString(guild_bank->Items.MainArea[i].WhoFor); + outapp->WriteString(guild_bank->Items.MainArea[i].Donator); + outapp->WriteUInt32(Item->ID); + outapp->WriteUInt32(Item->Icon); + if (Item->Stackable) { + outapp->WriteUInt32(guild_bank->Items.MainArea[i].Quantity); + outapp->WriteUInt8(Item->StackSize == guild_bank->Items.MainArea[i].Quantity ? 0 : 1); + } else { + outapp->WriteUInt32(1); + outapp->WriteUInt8(0); + } + outapp->WriteUInt8(Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()) ? 1 : 0); + outapp->WriteString(Item->Name); + } else { + outapp->WriteUInt8(0); // empty + } + } + + outapp->size = outapp->GetWritePosition(); // truncate to used size + c->FastQueuePacket(&outapp); + return; + } + for(int i = 0; i < GUILD_BANK_DEPOSIT_AREA_SIZE; ++i) { - if((*Iterator)->Items.DepositArea[i].ItemID > 0) + if(guild_bank->Items.DepositArea[i].ItemID > 0) { - const Item_Struct *Item = database.GetItem((*Iterator)->Items.DepositArea[i].ItemID); + const EQEmu::ItemBase *Item = database.GetItem(guild_bank->Items.DepositArea[i].ItemID); if(!Item) continue; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); GuildBankItemUpdate_Struct *gbius = (GuildBankItemUpdate_Struct*)outapp->pBuffer; if(!Item->Stackable) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, 1, - (*Iterator)->Items.DepositArea[i].Permissions, 0, 0); + guild_bank->Items.DepositArea[i].Permissions, 0, 0); else { - if((*Iterator)->Items.DepositArea[i].Quantity == Item->StackSize) + if(guild_bank->Items.DepositArea[i].Quantity == Item->StackSize) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.DepositArea[i].Quantity, (*Iterator)->Items.DepositArea[i].Permissions, 0, 0); + guild_bank->Items.DepositArea[i].Quantity, guild_bank->Items.DepositArea[i].Permissions, 0, 0); else gbius->Init(GuildBankItemUpdate, 1, i, GuildBankDepositArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.DepositArea[i].Quantity, (*Iterator)->Items.DepositArea[i].Permissions, 1, 0); + guild_bank->Items.DepositArea[i].Quantity, guild_bank->Items.DepositArea[i].Permissions, 1, 0); } strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName)); - strn0cpy(gbius->Donator, (*Iterator)->Items.DepositArea[i].Donator, sizeof(gbius->Donator)); + strn0cpy(gbius->Donator, guild_bank->Items.DepositArea[i].Donator, sizeof(gbius->Donator)); - strn0cpy(gbius->WhoFor, (*Iterator)->Items.DepositArea[i].WhoFor, sizeof(gbius->WhoFor)); + strn0cpy(gbius->WhoFor, guild_bank->Items.DepositArea[i].WhoFor, sizeof(gbius->WhoFor)); c->FastQueuePacket(&outapp); } @@ -726,37 +783,37 @@ void GuildBankManager::SendGuildBank(Client *c) for(int i = 0; i < GUILD_BANK_MAIN_AREA_SIZE; ++i) { - if((*Iterator)->Items.MainArea[i].ItemID > 0) + if(guild_bank->Items.MainArea[i].ItemID > 0) { - const Item_Struct *Item = database.GetItem((*Iterator)->Items.MainArea[i].ItemID); + const EQEmu::ItemBase *Item = database.GetItem(guild_bank->Items.MainArea[i].ItemID); if(!Item) continue; bool Useable = Item->IsEquipable(c->GetBaseRace(), c->GetBaseClass()); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_GuildBank, sizeof(GuildBankItemUpdate_Struct)); GuildBankItemUpdate_Struct *gbius = (GuildBankItemUpdate_Struct*)outapp->pBuffer; if(!Item->Stackable) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, 1, - (*Iterator)->Items.MainArea[i].Permissions, 0, Useable); + guild_bank->Items.MainArea[i].Permissions, 0, Useable); else { - if((*Iterator)->Items.MainArea[i].Quantity == Item->StackSize) + if(guild_bank->Items.MainArea[i].Quantity == Item->StackSize) gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[i].Quantity, (*Iterator)->Items.MainArea[i].Permissions, 0, Useable); + guild_bank->Items.MainArea[i].Quantity, guild_bank->Items.MainArea[i].Permissions, 0, Useable); else gbius->Init(GuildBankItemUpdate, 1, i, GuildBankMainArea, 1, Item->ID, Item->Icon, - (*Iterator)->Items.MainArea[i].Quantity, (*Iterator)->Items.MainArea[i].Permissions, 1, Useable); + guild_bank->Items.MainArea[i].Quantity, guild_bank->Items.MainArea[i].Permissions, 1, Useable); } strn0cpy(gbius->ItemName, Item->Name, sizeof(gbius->ItemName)); - strn0cpy(gbius->Donator, (*Iterator)->Items.MainArea[i].Donator, sizeof(gbius->Donator)); + strn0cpy(gbius->Donator, guild_bank->Items.MainArea[i].Donator, sizeof(gbius->Donator)); - strn0cpy(gbius->WhoFor, (*Iterator)->Items.MainArea[i].WhoFor, sizeof(gbius->WhoFor)); + strn0cpy(gbius->WhoFor, guild_bank->Items.MainArea[i].WhoFor, sizeof(gbius->WhoFor)); c->FastQueuePacket(&outapp); } @@ -764,7 +821,7 @@ void GuildBankManager::SendGuildBank(Client *c) } bool GuildBankManager::IsAreaFull(uint32 GuildID, uint16 Area) { - std::list::iterator Iterator = GetGuildBank(GuildID); + auto Iterator = GetGuildBank(GuildID); if(Iterator == Banks.end()) return true; @@ -795,7 +852,7 @@ bool GuildBankManager::IsAreaFull(uint32 GuildID, uint16 Area) bool GuildBankManager::AddItem(uint32 GuildID, uint8 Area, uint32 ItemID, int32 QtyOrCharges, const char *Donator, uint8 Permissions, const char *WhoFor) { - std::list::iterator Iterator = GetGuildBank(GuildID); + auto Iterator = GetGuildBank(GuildID); if(Iterator == Banks.end()) { @@ -859,7 +916,7 @@ bool GuildBankManager::AddItem(uint32 GuildID, uint8 Area, uint32 ItemID, int32 return false; } - const Item_Struct *Item = database.GetItem(ItemID); + const EQEmu::ItemBase *Item = database.GetItem(ItemID); GuildBankItemUpdate_Struct gbius; @@ -925,7 +982,7 @@ int GuildBankManager::Promote(uint32 guildID, int slotID) (*iter)->Items.DepositArea[slotID].ItemID = 0; - const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[mainSlot].ItemID); + const EQEmu::ItemBase *Item = database.GetItem((*iter)->Items.MainArea[mainSlot].ItemID); GuildBankItemUpdate_Struct gbius; @@ -981,7 +1038,7 @@ void GuildBankManager::SetPermissions(uint32 guildID, uint16 slotID, uint32 perm else (*iter)->Items.MainArea[slotID].WhoFor[0] = '\0'; - const Item_Struct *Item = database.GetItem((*iter)->Items.MainArea[slotID].ItemID); + const EQEmu::ItemBase *Item = database.GetItem((*iter)->Items.MainArea[slotID].ItemID); GuildBankItemUpdate_Struct gbius; @@ -1007,7 +1064,7 @@ void GuildBankManager::SetPermissions(uint32 guildID, uint16 slotID, uint32 perm ItemInst* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, uint32 Quantity) { - std::list::iterator Iterator = GetGuildBank(GuildID); + auto Iterator = GetGuildBank(GuildID); if(Iterator == Banks.end()) return nullptr; @@ -1057,7 +1114,7 @@ ItemInst* GuildBankManager::GetItem(uint32 GuildID, uint16 Area, uint16 SlotID, bool GuildBankManager::HasItem(uint32 GuildID, uint32 ItemID) { - std::list::iterator Iterator = GetGuildBank(GuildID); + auto Iterator = GetGuildBank(GuildID); if(Iterator == Banks.end()) return false; @@ -1075,7 +1132,7 @@ bool GuildBankManager::HasItem(uint32 GuildID, uint32 ItemID) std::list::iterator GuildBankManager::GetGuildBank(uint32 GuildID) { - std::list::iterator Iterator = Banks.begin(); + auto Iterator = Banks.begin(); while(Iterator != Banks.end()) { @@ -1112,7 +1169,7 @@ bool GuildBankManager::DeleteItem(uint32 guildID, uint16 area, uint16 slotID, ui bool deleted = true; - const Item_Struct *Item = database.GetItem(BankArea[slotID].ItemID); + const EQEmu::ItemBase *Item = database.GetItem(BankArea[slotID].ItemID); if(!Item->Stackable || (quantity >= BankArea[slotID].Quantity)) { std::string query = StringFormat("DELETE FROM `guild_bank` WHERE `guildid` = %i " @@ -1163,7 +1220,7 @@ bool GuildBankManager::MergeStacks(uint32 GuildID, uint16 SlotID) if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) return false; - std::list::iterator Iterator = GetGuildBank(GuildID); + auto Iterator = GetGuildBank(GuildID); if(Iterator == Banks.end()) return false; @@ -1173,7 +1230,7 @@ bool GuildBankManager::MergeStacks(uint32 GuildID, uint16 SlotID) if(BankArea[SlotID].ItemID == 0) return false; - const Item_Struct *Item = database.GetItem(BankArea[SlotID].ItemID); + const EQEmu::ItemBase *Item = database.GetItem(BankArea[SlotID].ItemID); if(!Item->Stackable) return false; @@ -1255,7 +1312,7 @@ bool GuildBankManager::SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) return false; - std::list::iterator Iterator = GetGuildBank(GuildID); + auto Iterator = GetGuildBank(GuildID); if(Iterator == Banks.end()) return false; @@ -1271,7 +1328,7 @@ bool GuildBankManager::SplitStack(uint32 GuildID, uint16 SlotID, uint32 Quantity if(BankArea[SlotID].Quantity <= Quantity || Quantity == 0) return false; - const Item_Struct *Item = database.GetItem(BankArea[SlotID].ItemID); + const EQEmu::ItemBase *Item = database.GetItem(BankArea[SlotID].ItemID); if(!Item->Stackable) return false; @@ -1306,7 +1363,7 @@ bool GuildBankManager::AllowedToWithdraw(uint32 GuildID, uint16 Area, uint16 Slo if(SlotID > (GUILD_BANK_MAIN_AREA_SIZE - 1)) return false; - std::list::iterator Iterator = GetGuildBank(GuildID); + auto Iterator = GetGuildBank(GuildID); if(Iterator == Banks.end()) return false; @@ -1349,8 +1406,9 @@ bool GuildApproval::ProcessApproval() GuildApproval::GuildApproval(const char* guildname, Client* owner,uint32 id) { - database.GetVariable("GuildCreation", founders, 3); - uint8 tmp = atoi(founders); + std::string founders; + database.GetVariable("GuildCreation", founders); + uint8 tmp = atoi(founders.c_str()); deletion_timer = new Timer(1800000); strcpy(guild,guildname); this->owner = owner; @@ -1368,8 +1426,9 @@ GuildApproval::~GuildApproval() bool GuildApproval::AddMemberApproval(Client* addition) { - database.GetVariable("GuildCreation", founders, 3); - uint8 tmp = atoi(founders); + std::string founders; + database.GetVariable("GuildCreation", founders); + uint8 tmp = atoi(founders.c_str()); for(int i=0;iCharacterID()); guild_mgr.SetGuild(owner->CharacterID(),tmpeq,2); owner->SendAppearancePacket(AT_GuildID,true,false); @@ -1437,7 +1498,7 @@ void GuildApproval::GuildApproved() strncat(petitext,owner->CastToClient()->GetName(),len); strncat(petitext," Members:",len); strncat(petitext,gmembers,len); - Petition* pet = new Petition(owner->CastToClient()->CharacterID()); + auto pet = new Petition(owner->CastToClient()->CharacterID()); pet->SetAName(owner->CastToClient()->AccountName()); pet->SetClass(owner->CastToClient()->GetClass()); pet->SetLevel(owner->CastToClient()->GetLevel()); @@ -1453,7 +1514,7 @@ void GuildApproval::GuildApproved() petition_list.UpdateGMQueue(); petition_list.UpdateZoneListQueue(); worldserver.SendEmoteMessage(0, 0, 80, 15, "%s has made a petition. #%i", owner->CastToClient()->GetName(), pet->GetID()); - ServerPacket* pack = new ServerPacket; + auto pack = new ServerPacket; pack->opcode = ServerOP_RefreshGuild; pack->size = tmp; pack->pBuffer = new uchar[pack->size]; diff --git a/zone/guild_mgr.h b/zone/guild_mgr.h index b7dd6d7e4..d06473392 100644 --- a/zone/guild_mgr.h +++ b/zone/guild_mgr.h @@ -61,7 +61,6 @@ public: private: Timer* deletion_timer; char guild[16]; - char founders[3]; Client* owner; Client* members[6]; uint32 refid; diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index e68924844..b98ca6923 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -67,8 +67,10 @@ void HateList::WipeHateList() { parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0); - if (m->IsClient()) + if (m->IsClient()) { m->CastToClient()->DecrementAggroCount(); + m->CastToClient()->RemoveXTarget(hate_owner, true); + } } delete (*iterator); iterator = list.erase(iterator); @@ -535,37 +537,27 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption if (!target || !caster) return 0; - int ret = 0; - std::list id_list; - auto iterator = list.begin(); - while (iterator != list.end()) - { - struct_HateList *h = (*iterator); - ++iterator; - if (h && h->entity_on_hatelist && h->entity_on_hatelist != caster) - { - if (caster->CombatRange(h->entity_on_hatelist)) - { - id_list.push_back(h->entity_on_hatelist->GetID()); - ++ret; - } + int hit_count = 0; + // This should prevent crashes if something dies (or mainly more than 1 thing goes away) + // This is a temp solution until the hate lists can be rewritten to not have that issue + std::vector id_list; + for (auto &h : list) { + if (h->entity_on_hatelist && h->entity_on_hatelist != caster && + caster->CombatRange(h->entity_on_hatelist)) + id_list.push_back(h->entity_on_hatelist->GetID()); + if (count != -1 && id_list.size() > count) + break; + } + + for (auto &id : id_list) { + auto mob = entity_list.GetMobID(id); + if (mob) { + ++hit_count; + caster->ProcessAttackRounds(mob, opts, 1); } } - std::list::iterator iter = id_list.begin(); - while (iter != id_list.end()) - { - Mob *cur = entity_list.GetMobID((*iter)); - if (cur) - { - for (int i = 0; i < count; ++i) { - caster->Attack(cur, MainPrimary, false, false, false, opts); - } - } - iter++; - } - - return ret; + return hit_count; } void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_center) @@ -607,7 +599,7 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent ++iterator; } - std::list::iterator iter = id_list.begin(); + auto iter = id_list.begin(); while (iter != id_list.end()) { Mob *cur = entity_list.GetMobID((*iter)); diff --git a/zone/heal_rotation.cpp b/zone/heal_rotation.cpp new file mode 100644 index 000000000..6981cc0c1 --- /dev/null +++ b/zone/heal_rotation.cpp @@ -0,0 +1,950 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifdef BOTS + +#include "bot.h" + +#define SAFE_HP_RATIO_CLOTH 95.0f +#define SAFE_HP_RATIO_LEATHER 90.0f +#define SAFE_HP_RATIO_CHAIN 80.0f +#define SAFE_HP_RATIO_PLATE 75.0f + +#define CRITICAL_HP_RATIO_CLOTH 45.0f +#define CRITICAL_HP_RATIO_LEATHER 40.0f +#define CRITICAL_HP_RATIO_CHAIN 35.0f +#define CRITICAL_HP_RATIO_PLATE 30.0f + +HealRotation::HealRotation(Bot* hr_creator, uint32 interval_ms, bool fast_heals, bool adaptive_targeting, bool casting_override) +{ + m_member_pool.push_back(hr_creator); + + m_creation_time_ms = Timer::GetCurrentTime(); + m_last_heal_time_ms = m_creation_time_ms; + m_interval_ms = ((interval_ms >= CASTING_CYCLE_MINIMUM_INTERVAL) ? (interval_ms) : (CASTING_CYCLE_MINIMUM_INTERVAL)); + m_next_cast_time_ms = m_creation_time_ms; + m_next_poke_time_ms = m_creation_time_ms; + m_healing_stats_begin_ms = m_creation_time_ms; + m_fast_heals = fast_heals; + m_adaptive_targeting = adaptive_targeting; + m_casting_override = casting_override; + m_casting_target_poke = true; + m_active_heal_target = false; + + ResetArmorTypeHPLimits(); + + m_is_active = false; + + m_consumed = false; + + m_hot_target = nullptr; + m_hot_active = false; +} + +void HealRotation::SetIntervalMS(uint32 interval_ms) +{ + if (interval_ms > CASTING_CYCLE_MAXIMUM_INTERVAL) + interval_ms = CASTING_CYCLE_MAXIMUM_INTERVAL; + else if (interval_ms < CASTING_CYCLE_MINIMUM_INTERVAL) + interval_ms = CASTING_CYCLE_MINIMUM_INTERVAL; + + m_interval_ms = interval_ms; +} + +void HealRotation::SetIntervalS(uint32 interval_s) +{ + interval_s *= 1000; + if (interval_s > CASTING_CYCLE_MAXIMUM_INTERVAL) + interval_s = CASTING_CYCLE_MAXIMUM_INTERVAL; + else if (interval_s < CASTING_CYCLE_MINIMUM_INTERVAL) + interval_s = CASTING_CYCLE_MINIMUM_INTERVAL; + + m_interval_ms = interval_s; +} + +bool HealRotation::AddMemberToPool(Bot* hr_member) +{ + if (!hr_member) + return false; + if (!IsHealRotationMemberClass(hr_member->GetClass())) + return false; + if (m_member_pool.size() >= RuleI(Bots, HealRotationMaxMembers)) + return false; + + for (auto find_iter : m_member_pool) { + if (find_iter == hr_member) + return false; + } + + m_member_pool.push_back(hr_member); + valid_state(); + + return true; +} + +bool HealRotation::AddTargetToPool(Mob* hr_target) +{ + if (!hr_target) + return false; + if (!valid_state()) + return false; + if (!IsHealRotationTargetMobType(hr_target)) + return false; + if (m_target_pool.size() >= RuleI(Bots, HealRotationMaxTargets)) + return false; + + for (auto find_iter : m_target_pool) { + if (find_iter == hr_target) + return false; + } + + m_target_pool.push_back(hr_target); + + return true; +} + +bool HealRotation::RemoveMemberFromPool(Bot* hr_member) +{ + if (!hr_member) + return true; + + for (auto member_iter : m_member_pool) { + if (member_iter != hr_member) + continue; + + m_member_is_casting.erase(hr_member); + m_member_pool.remove(hr_member); + valid_state(); + return true; + } + return false; +} + +bool HealRotation::RemoveTargetFromPool(Mob* hr_target) +{ + if (!hr_target) + return true; + if (!valid_state()) + return true; + + for (auto target_iter : m_target_pool) { + if (target_iter != hr_target) + continue; + + if (m_hot_target == hr_target) { + m_hot_target = nullptr; + m_hot_active = false; + } + + m_target_healing_stats_2.erase(hr_target); + m_target_healing_stats_1.erase(hr_target); + m_target_pool.remove(hr_target); + m_casting_target_poke = false; + bias_targets(); + return true; + } + + return false; +} + +bool HealRotation::ClearMemberPool() +{ + m_is_active = false; + m_cycle_pool.clear(); + m_casting_target_poke = false; + m_active_heal_target = false; + + ClearTargetPool(); + + auto clear_list = m_member_pool; + for (auto member_iter : clear_list) + member_iter->LeaveHealRotationMemberPool(); + + return true; +} + +bool HealRotation::ClearTargetPool() +{ + m_hot_target = nullptr; + m_hot_active = false; + m_is_active = false; + + auto clear_list = m_target_pool; + for (auto target_iter : clear_list) + target_iter->LeaveHealRotationTargetPool(); + + m_casting_target_poke = false; + bias_targets(); + + return m_target_pool.empty(); +} + +bool HealRotation::SetHOTTarget(Mob* hot_target) +{ + if (!hot_target || !IsTargetInPool(hot_target)) + return false; + + m_hot_target = hot_target; + m_hot_active = true; + + return true; +} + +bool HealRotation::ClearHOTTarget() +{ + m_hot_target = nullptr; + m_hot_active = false; + + return true; +} + +bool HealRotation::Start() +{ + m_is_active = false; + if (m_member_pool.empty() || m_target_pool.empty()) { + validate_hot(); + return false; + } + + m_cycle_pool = m_member_pool; + m_is_active = true; + + return true; +} + +bool HealRotation::Stop() +{ + m_is_active = false; + m_active_heal_target = false; + m_cycle_pool.clear(); + + return true; +} + +Bot* HealRotation::CastingMember() +{ + if (!m_is_active && !m_hot_active) + return nullptr; + + if (m_cycle_pool.empty()) { + cycle_refresh(); + + if (m_cycle_pool.empty()) + return nullptr; + } + + return m_cycle_pool.front(); +} + +bool HealRotation::PokeCastingTarget() +{ + if (m_hot_target && m_hot_active) + return true; + + if (!m_is_active) + return false; + + uint32 current_time = Timer::GetCurrentTime(); + + if (current_time < m_next_poke_time_ms) { + auto hr_target = CastingTarget(); + if (hr_target && hr_target->DontHealMeBefore() > current_time) + m_next_poke_time_ms = current_time; + else + return m_active_heal_target; + } + + m_next_poke_time_ms = (current_time + POKE_PROPAGATION_DELAY); + + if (m_healing_stats_begin_ms + HEALING_STATS_RESET_INTERVAL <= current_time) + StartNewTargetHealingStatsCycle(current_time); + + m_casting_target_poke = false; + bias_targets(); + + return m_active_heal_target; +} + +Mob* HealRotation::CastingTarget() +{ + if (m_hot_target && m_hot_active) + return m_hot_target; + + if (!m_is_active) + return nullptr; + if (!m_active_heal_target) + return nullptr; + + return m_target_pool.front(); +} + +bool HealRotation::AdvanceRotation(bool use_interval) +{ + m_cycle_pool.pop_front(); + m_next_cast_time_ms = Timer::GetCurrentTime(); + if (use_interval) { + m_next_poke_time_ms = m_next_cast_time_ms; + m_next_cast_time_ms += m_interval_ms; + } + else { + m_next_cast_time_ms += ADVANCE_ROTATION_MINIMUM_INTERVAL; + } + + if (m_cycle_pool.empty()) + cycle_refresh(); + + return (!m_cycle_pool.empty()); +} + +bool HealRotation::IsMemberInPool(Bot* hr_member) +{ + if (!hr_member) + return false; + if (m_member_pool.empty()) + return false; + + for (auto find_iter : m_member_pool) { + if (find_iter == hr_member) + return true; + } + + return false; +} + +bool HealRotation::IsTargetInPool(Mob* hr_target) +{ + if (!hr_target) + return false; + if (m_target_pool.empty()) + return false; + + for (auto find_iter : m_target_pool) { + if (find_iter == hr_target) + return true; + } + + return false; +} + +bool HealRotation::IsHOTTarget(Mob* hot_target) +{ + if (!hot_target) + return false; + if (m_hot_target != hot_target) + return false; + + return true; +} + +void HealRotation::SetMemberIsCasting(Bot* hr_member, bool flag) +{ + if (!hr_member) + return; + if (!IsMemberInPool(hr_member)) + return; + + m_member_is_casting[hr_member] = flag; +} + +bool HealRotation::MemberIsCasting(Bot* hr_member) +{ + if (!hr_member) + return false; + if (m_member_is_casting.find(hr_member) == m_member_is_casting.end()) + return false; + + return m_member_is_casting[hr_member]; +} + +void HealRotation::UpdateTargetHealingStats(Mob* hr_target) +{ + if (!hr_target) + return; + if (!IsTargetInPool(hr_target)) + return; + + m_last_heal_time_ms = Timer::GetCurrentTime(); + + m_target_healing_stats_1[hr_target].last_heal_time_ms = m_last_heal_time_ms; + ++m_target_healing_stats_1[hr_target].heal_count; +} + +void HealRotation::StartNewTargetHealingStatsCycle(uint32 current_time) +{ + m_target_healing_stats_2 = m_target_healing_stats_1; + m_target_healing_stats_1.clear(); + + m_healing_stats_begin_ms = current_time; +} + +uint32 HealRotation::HealCount(Mob* hr_target) +{ + if (!hr_target) + return 0; + + uint32 heal_count = 0; + if (m_target_healing_stats_1.find(hr_target) != m_target_healing_stats_1.end()) + heal_count += m_target_healing_stats_1[hr_target].heal_count; + + return heal_count; +} + +uint32 HealRotation::ExtendedHealCount(Mob* hr_target) +{ + if (!hr_target) + return 0; + + uint32 heal_count = 0; + if (m_target_healing_stats_1.find(hr_target) != m_target_healing_stats_1.end()) + heal_count += m_target_healing_stats_1[hr_target].heal_count; + if (m_target_healing_stats_2.find(hr_target) != m_target_healing_stats_2.end()) + heal_count += m_target_healing_stats_2[hr_target].heal_count; + + return heal_count; +} + +float HealRotation::HealFrequency(Mob* hr_target) +{ + if (!hr_target) + return 0.0f; + + float time_base = 0; + uint32 heal_count = 0; + if (m_target_healing_stats_1.find(hr_target) != m_target_healing_stats_1.end()) { + heal_count += m_target_healing_stats_1[hr_target].heal_count; + time_base = (Timer::GetCurrentTime() - m_target_healing_stats_1[hr_target].last_heal_time_ms); + } + + time_base /= 1000; + if (!time_base) + time_base = HEALING_STATS_RESET_INTERVAL_S; + + if (heal_count) + return ((float)1 / (time_base / heal_count)); + else + return ((float)1 / time_base); +} + +float HealRotation::ExtendedHealFrequency(Mob* hr_target) +{ + if (!hr_target) + return 0.0f; + + uint32 current_time = Timer::GetCurrentTime(); + uint32 heal_count = 0; + float time_base = 0; + if (m_target_healing_stats_1.find(hr_target) != m_target_healing_stats_1.end()) { + heal_count += m_target_healing_stats_1[hr_target].heal_count; + time_base = (current_time - m_target_healing_stats_1[hr_target].last_heal_time_ms + HEALING_STATS_RESET_INTERVAL); + } + if (m_target_healing_stats_2.find(hr_target) != m_target_healing_stats_2.end()) { + heal_count += m_target_healing_stats_2[hr_target].heal_count; + time_base = (current_time - m_target_healing_stats_2[hr_target].last_heal_time_ms); + } + + time_base /= 1000; + if (!time_base) + time_base = (HEALING_STATS_RESET_INTERVAL_S * 2); + + if (heal_count) + return ((float)1 / (time_base / heal_count)); + else + return ((float)1 / time_base); +} + +HealingStats* HealRotation::TargetHealingStats1(Mob* hr_target) +{ + if (!hr_target) + return nullptr; + if (m_target_healing_stats_1.find(hr_target) == m_target_healing_stats_1.end()) + return nullptr; + + return &m_target_healing_stats_1[hr_target]; +} + +HealingStats* HealRotation::TargetHealingStats2(Mob* hr_target) +{ + if (!hr_target) + return nullptr; + if (m_target_healing_stats_2.find(hr_target) == m_target_healing_stats_2.end()) + return nullptr; + + return &m_target_healing_stats_2[hr_target]; +} + +bool HealRotation::SetArmorTypeSafeHPRatio(uint8 armor_type, float hp_ratio) +{ + if (armor_type >= ARMOR_TYPE_COUNT) + return false; + if (hp_ratio < CRITICAL_HP_RATIO_ABS || hp_ratio > SAFE_HP_RATIO_ABS) + return false; + if (hp_ratio < m_critical_hp_ratio[armor_type]) + return false; + + m_safe_hp_ratio[armor_type] = hp_ratio; + + return true; +} + +bool HealRotation::SetArmorTypeCriticalHPRatio(uint8 armor_type, float hp_ratio) +{ + if (armor_type >= ARMOR_TYPE_COUNT) + return false; + if (hp_ratio < CRITICAL_HP_RATIO_ABS || hp_ratio > SAFE_HP_RATIO_ABS) + return false; + if (hp_ratio > m_safe_hp_ratio[armor_type]) + return false; + + m_critical_hp_ratio[armor_type] = hp_ratio; + + return true; +} + +float HealRotation::ArmorTypeSafeHPRatio(uint8 armor_type) +{ + if (armor_type < ARMOR_TYPE_COUNT) + return m_safe_hp_ratio[armor_type]; + else + return m_safe_hp_ratio[ARMOR_TYPE_UNKNOWN]; +} + +float HealRotation::ArmorTypeCriticalHPRatio(uint8 armor_type) +{ + if (armor_type < ARMOR_TYPE_COUNT) + return m_critical_hp_ratio[armor_type]; + else + return m_critical_hp_ratio[ARMOR_TYPE_UNKNOWN]; +} + +void HealRotation::ResetArmorTypeHPLimits() +{ + m_safe_hp_ratio[ARMOR_TYPE_UNKNOWN] = SAFE_HP_RATIO_BASE; + m_safe_hp_ratio[ARMOR_TYPE_CLOTH] = SAFE_HP_RATIO_CLOTH; + m_safe_hp_ratio[ARMOR_TYPE_LEATHER] = SAFE_HP_RATIO_LEATHER; + m_safe_hp_ratio[ARMOR_TYPE_CHAIN] = SAFE_HP_RATIO_CHAIN; + m_safe_hp_ratio[ARMOR_TYPE_PLATE] = SAFE_HP_RATIO_PLATE; + + m_critical_hp_ratio[ARMOR_TYPE_UNKNOWN] = CRITICAL_HP_RATIO_BASE; + m_critical_hp_ratio[ARMOR_TYPE_CLOTH] = CRITICAL_HP_RATIO_CLOTH; + m_critical_hp_ratio[ARMOR_TYPE_LEATHER] = CRITICAL_HP_RATIO_LEATHER; + m_critical_hp_ratio[ARMOR_TYPE_CHAIN] = CRITICAL_HP_RATIO_CHAIN; + m_critical_hp_ratio[ARMOR_TYPE_PLATE] = CRITICAL_HP_RATIO_PLATE; +} + +bool HealRotation::valid_state() +{ + m_member_pool.remove(nullptr); + m_member_pool.remove_if([](Mob* l) {return (!IsHealRotationMemberClass(l->GetClass())); }); + + cycle_refresh(); + + if (m_member_pool.empty() && !m_consumed) { // Consumes HealRotation at this point + m_consumed = true; + ClearTargetPool(); + } + + return (!m_member_pool.empty()); +} + +void HealRotation::cycle_refresh() +{ + m_is_active = false; + m_cycle_pool.clear(); + if (m_member_pool.empty()) + return; + + m_cycle_pool = m_member_pool; + + m_is_active = true; +} + +bool HealRotation::healable_target(bool use_class_at, bool critical_only) +{ + if (m_target_pool.empty()) + return false; + + auto healable_target = m_target_pool.front(); + if (!healable_target) + return false; + if (healable_target->DontHealMeBefore() > Timer::GetCurrentTime()) + return false; + if (healable_target->GetAppearance() == eaDead) + return false; + + if (use_class_at) { + if (critical_only && healable_target->GetHPRatio() > m_critical_hp_ratio[ClassArmorType(healable_target->GetClass())]) + return false; + if (healable_target->GetHPRatio() > m_safe_hp_ratio[ClassArmorType(healable_target->GetClass())]) + return false; + if (healable_target->IsBerserk() && (healable_target->GetClass() == WARRIOR || healable_target->GetClass() == BERSERKER)) { + if (healable_target->GetHPRatio() <= RuleI(Combat, BerserkerFrenzyEnd) && healable_target->GetHPRatio() > m_critical_hp_ratio[ClassArmorType(healable_target->GetClass())]) + return false; + } + } + else { + if (critical_only && healable_target->GetHPRatio() > CRITICAL_HP_RATIO_BASE) + return false; + if (healable_target->GetHPRatio() > SAFE_HP_RATIO_BASE) + return false; + if (healable_target->IsBerserk() && (healable_target->GetClass() == WARRIOR || healable_target->GetClass() == BERSERKER)) { + if (healable_target->GetHPRatio() <= RuleI(Combat, BerserkerFrenzyEnd) && healable_target->GetHPRatio() > CRITICAL_HP_RATIO_BASE) + return false; + } + } + + return true; +} + +void HealRotation::bias_targets() +{ +#define LT_HPRATIO(l, r) (l->GetHPRatio() < r->GetHPRatio()) +#define LT_ARMTYPE(l, r) (ClassArmorType(l->GetClass()) < ClassArmorType(r->GetClass())) + +#define EQ_ALIVE(l, r) (l->GetAppearance() != eaDead && r->GetAppearance() != eaDead) +#define EQ_READY(l, r, ct) (l->DontHealMeBefore() <= ct && r->DontHealMeBefore() <= ct) +#define EQ_TANK(l, r) ((l->HasGroup() && l->GetGroup()->AmIMainTank(l->GetCleanName())) && (r->HasGroup() && r->GetGroup()->AmIMainTank(r->GetCleanName()))) +#define EQ_HEALER(l, r) (IsHealRotationMemberClass(l->GetClass()) && IsHealRotationMemberClass(r->GetClass())) +#define EQ_ARMTYPE(l, r) (ClassArmorType(l->GetClass()) == ClassArmorType(r->GetClass())) +#define EQ_ATCRIT(l, r) (l->GetHPRatio() <= (*l->TargetOfHealRotation())->ArmorTypeCriticalHPRatio(ClassArmorType(l->GetClass())) && \ + r->GetHPRatio() <= (*r->TargetOfHealRotation())->ArmorTypeCriticalHPRatio(ClassArmorType(r->GetClass()))) +#define EQ_ATWOUND(l, r) (l->GetHPRatio() <= (*l->TargetOfHealRotation())->ArmorTypeSafeHPRatio(ClassArmorType(l->GetClass())) && \ + r->GetHPRatio() <= (*r->TargetOfHealRotation())->ArmorTypeSafeHPRatio(ClassArmorType(r->GetClass()))) + +#define GT_ALIVE(l, r) (l->GetAppearance() != eaDead && r->GetAppearance() == eaDead) +#define GT_READY(l, r, ct) (l->DontHealMeBefore() <= ct && r->DontHealMeBefore() > ct) +#define GT_TANK(l, r) ((l->HasGroup() && l->GetGroup()->AmIMainTank(l->GetCleanName())) && (!r->HasGroup() || !r->GetGroup()->AmIMainTank(r->GetCleanName()))) +#define GT_HEALER(l, r) (IsHealRotationMemberClass(l->GetClass()) && !IsHealRotationMemberClass(r->GetClass())) +#define GT_HEALFREQ(l, r) (l->HealRotationHealFrequency() > r->HealRotationHealFrequency()) +#define GT_HEALCNT(l, r) (l->HealRotationHealCount() > r->HealRotationHealCount()) +#define GT_ATCRIT(l, r) (l->GetHPRatio() <= (*l->TargetOfHealRotation())->ArmorTypeCriticalHPRatio(ClassArmorType(l->GetClass())) && \ + r->GetHPRatio() > (*r->TargetOfHealRotation())->ArmorTypeCriticalHPRatio(ClassArmorType(r->GetClass()))) +#define GT_XHEALFREQ(l, r) (l->HealRotationExtendedHealFrequency() > r->HealRotationExtendedHealFrequency()) +#define GT_XHEALCNT(l, r) (l->HealRotationExtendedHealCount() > r->HealRotationExtendedHealCount()) +#define GT_ATWOUND(l, r) (l->GetHPRatio() <= (*l->TargetOfHealRotation())->ArmorTypeSafeHPRatio(ClassArmorType(l->GetClass())) && \ + r->GetHPRatio() > (*r->TargetOfHealRotation())->ArmorTypeSafeHPRatio(ClassArmorType(r->GetClass()))) + + if (m_target_pool.empty()) { + m_casting_target_poke = true; + m_active_heal_target = false; + return; + } + + // attempt to clear invalid target pool entries + m_target_pool.remove(nullptr); + m_target_pool.remove_if([](Mob* l) { return (!IsHealRotationTargetMobType(l)); }); + + uint32 sort_type = 0; // debug + + while (m_target_pool.size() > 1 && !m_casting_target_poke && !m_adaptive_targeting) { // standard behavior + sort_type = 1; + m_target_pool.sort([](Mob* l, Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_TANK(l, r)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_TANK(l, r) && LT_HPRATIO(l, r)) + return true; + + return false; + }); + if (m_target_pool.front()->HasGroup() && m_target_pool.front()->GetGroup()->AmIMainTank(m_target_pool.front()->GetCleanName()) && healable_target(false)) + break; + + sort_type = 2; + m_target_pool.sort([](Mob* l, Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_HEALER(l, r)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_HEALER(l, r) && LT_HPRATIO(l, r)) + return true; + + return false; + }); + if (IsHealRotationMemberClass(m_target_pool.front()->GetClass()) && healable_target(false)) + break; + + sort_type = 3; // default + m_target_pool.sort([](const Mob* l, const Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && LT_HPRATIO(l, r)) + return true; + + return false; + }); + + break; + } + + while (m_target_pool.size() > 1 && !m_casting_target_poke && m_adaptive_targeting) { // adaptive targeting behavior + sort_type = 101; + m_target_pool.sort([](Mob* l, Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_HEALFREQ(l, r)) + return true; + + return false; + }); + if (healable_target(true, true)) + break; + + sort_type = 102; + m_target_pool.sort([](Mob* l, Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_HEALCNT(l, r)) + return true; + + return false; + }); + if (healable_target(true, true)) + break; + + sort_type = 103; + m_target_pool.sort([](Mob* l, Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_TANK(l, r)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_TANK(l, r) && LT_HPRATIO(l, r)) + return true; + + return false; + }); + if (m_target_pool.front()->HasGroup() && m_target_pool.front()->GetGroup()->AmIMainTank(m_target_pool.front()->GetCleanName()) && healable_target(true, true)) + break; + + sort_type = 104; + m_target_pool.sort([](const Mob* l, const Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_HEALER(l, r)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_HEALER(l, r) && LT_HPRATIO(l, r)) + return true; + + return false; + }); + if (IsHealRotationMemberClass(m_target_pool.front()->GetClass()) && healable_target(true, true)) + break; + + sort_type = 105; + m_target_pool.sort([](const Mob* l, const Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_ATCRIT(l, r)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_ATCRIT(l, r) && LT_ARMTYPE(l, r)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_ATCRIT(l, r) && EQ_ARMTYPE(l, r) && LT_HPRATIO(l, r)) + return true; + + return false; + }); + if (healable_target(true, true)) + break; + + sort_type = 106; + m_target_pool.sort([](Mob* l, Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_XHEALFREQ(l, r)) + return true; + + return false; + }); + if (healable_target(true)) + break; + + sort_type = 107; + m_target_pool.sort([](Mob* l, Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_XHEALCNT(l, r)) + return true; + + return false; + }); + if (healable_target(true)) + break; + + sort_type = 108; + m_target_pool.sort([](const Mob* l, const Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && GT_ATWOUND(l, r)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_ATWOUND(l, r) && LT_ARMTYPE(l, r)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && EQ_ATWOUND(l, r) && EQ_ARMTYPE(l, r) && LT_HPRATIO(l, r)) + return true; + + return false; + }); + if (healable_target()) + break; + + sort_type = 109; // default + m_target_pool.sort([](const Mob* l, const Mob* r) { + if (GT_ALIVE(l, r)) + return true; + uint32 current_time = Timer::GetCurrentTime(); + if (EQ_ALIVE(l, r) && GT_READY(l, r, current_time)) + return true; + if (EQ_ALIVE(l, r) && EQ_READY(l, r, current_time) && LT_HPRATIO(l, r)) + return true; + + return false; + }); + + break; + } + + m_active_heal_target = healable_target(false); + if (!m_active_heal_target) + m_active_heal_target = healable_target(); + + m_casting_target_poke = true; + +#if (EQDEBUG >= 12) + Log.Out(Logs::General, Logs::Error, "HealRotation::bias_targets() - *** Post-processing state ***"); + Log.Out(Logs::General, Logs::Error, "HealRotation Settings:"); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_interval_ms = %u", m_interval_ms); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_next_cast_time_ms = %u (current_time: %u, time_diff: %i)", m_next_cast_time_ms, Timer::GetCurrentTime(), ((int32)Timer::GetCurrentTime() - (int32)m_next_cast_time_ms)); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_next_poke_time_ms = %u (current_time: %u, time_diff: %i)", m_next_poke_time_ms, Timer::GetCurrentTime(), ((int32)Timer::GetCurrentTime() - (int32)m_next_poke_time_ms)); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_fast_heals = %s", ((m_fast_heals) ? ("true") : ("false"))); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_adaptive_targeting = %s", ((m_adaptive_targeting) ? ("true") : ("false"))); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_casting_override = %s", ((m_casting_override) ? ("true") : ("false"))); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_casting_target_poke = %s", ((m_casting_target_poke) ? ("true") : ("false"))); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_active_heal_target = %s", ((m_active_heal_target) ? ("true") : ("false"))); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_is_active = %s", ((m_is_active) ? ("true") : ("false"))); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_member_list.size() = %i", m_member_pool.size()); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_cycle_list.size() = %i", m_cycle_pool.size()); + Log.Out(Logs::General, Logs::Error, "HealRotation::m_target_list.size() = %i", m_target_pool.size()); + if (m_member_pool.size()) { Log.Out(Logs::General, Logs::Error, "(std::shared_ptr::use_count() = %i", m_member_pool.front()->MemberOfHealRotation()->use_count()); } + else { Log.Out(Logs::General, Logs::Error, "(std::shared_ptr::use_count() = unknown (0)"); } + Log.Out(Logs::General, Logs::Error, "HealRotation Members:"); + int member_index = 0; + for (auto mlist_iter : m_member_pool) { + if (!mlist_iter) { continue; } + Log.Out(Logs::General, Logs::Error, "(%i) %s (hrcast: %c)", (++member_index), mlist_iter->GetCleanName(), ((mlist_iter->AmICastingForHealRotation())?('T'):('F'))); + } + if (!member_index) { Log.Out(Logs::General, Logs::Error, "(0) None"); } + Log.Out(Logs::General, Logs::Error, "HealRotation Cycle:"); + int cycle_index = 0; + for (auto clist_iter : m_cycle_pool) { + if (!clist_iter) { continue; } + Log.Out(Logs::General, Logs::Error, "(%i) %s", (++cycle_index), clist_iter->GetCleanName()); + } + if (!cycle_index) { Log.Out(Logs::General, Logs::Error, "(0) None"); } + Log.Out(Logs::General, Logs::Error, "HealRotation Targets: (sort type: %u)", sort_type); + int target_index = 0; + + for (auto tlist_iter : m_target_pool) { + if (!tlist_iter) { continue; } + Log.Out(Logs::General, Logs::Error, "(%i) %s (hp: %3.1f%%, at: %u, dontheal: %c, crit(base): %c(%c), safe(base): %c(%c), hcnt(ext): %u(%u), hfreq(ext): %f(%f))", + (++target_index), tlist_iter->GetCleanName(), + tlist_iter->GetHPRatio(), + ClassArmorType(tlist_iter->GetClass()), + ((tlist_iter->DontHealMeBefore() > Timer::GetCurrentTime()) ? ('T') : ('F')), + ((tlist_iter->GetHPRatio()>m_critical_hp_ratio[ClassArmorType(tlist_iter->GetClass())]) ? ('F') : ('T')), + ((tlist_iter->GetHPRatio()>m_critical_hp_ratio[ARMOR_TYPE_UNKNOWN]) ? ('F') : ('T')), + ((tlist_iter->GetHPRatio()>m_safe_hp_ratio[ClassArmorType(tlist_iter->GetClass())]) ? ('T') : ('F')), + ((tlist_iter->GetHPRatio()>m_safe_hp_ratio[ARMOR_TYPE_UNKNOWN]) ? ('T') : ('F')), + tlist_iter->HealRotationHealCount(), + tlist_iter->HealRotationExtendedHealCount(), + tlist_iter->HealRotationHealFrequency(), + tlist_iter->HealRotationExtendedHealFrequency()); + } + if (!target_index) { Log.Out(Logs::General, Logs::Error, "(0) None (hp: 0.0\%, at: 0, dontheal: F, crit(base): F(F), safe(base): F(F), hcnt(ext): 0(0), hfreq(ext): 0.0(0.0))"); } +#endif +} + +void HealRotation::validate_hot() +{ + if (!m_hot_target) { + m_hot_active = false; + return; + } + + if (!IsTargetInPool(m_hot_target)) { + m_hot_target = nullptr; + m_hot_active = false; + } +} + +bool IsHealRotationMemberClass(uint8 class_id) +{ + switch (class_id) { + case CLERIC: + case DRUID: + case SHAMAN: + return true; + default: + return false; + } +} + +bool IsHealRotationTargetMobType(Mob* target_mob) +{ + if (!target_mob) + return false; + if (!target_mob->IsClient() && !target_mob->IsBot() && !target_mob->IsPet()) + return false; + if (target_mob->IsPet() && (!target_mob->GetOwner() || (!target_mob->GetOwner()->IsClient() && !target_mob->GetOwner()->IsBot()))) + return false; + + return true; +} + +#endif // BOTS diff --git a/zone/heal_rotation.h b/zone/heal_rotation.h new file mode 100644 index 000000000..19a3f8311 --- /dev/null +++ b/zone/heal_rotation.h @@ -0,0 +1,165 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#ifndef HEAL_ROTATION_H +#define HEAL_ROTATION_H + +#ifdef BOTS + +#include "mob.h" + +#define CASTING_CYCLE_MINIMUM_INTERVAL 1000 +#define CASTING_CYCLE_MINIMUM_INTERVAL_S 1 +#define CASTING_CYCLE_MAXIMUM_INTERVAL 30000 +#define CASTING_CYCLE_MAXIMUM_INTERVAL_S 30 +#define CASTING_CYCLE_DEFAULT_INTERVAL 5000 +#define CASTING_CYCLE_DEFAULT_INTERVAL_S 5 +#define POKE_PROPAGATION_DELAY 250 +#define ADVANCE_ROTATION_MINIMUM_INTERVAL 100 +#define HEALING_STATS_RESET_INTERVAL 60000 +#define HEALING_STATS_RESET_INTERVAL_S 60 + +#define SAFE_HP_RATIO_ABS 100.0f +#define SAFE_HP_RATIO_BASE 95.0f + +#define CRITICAL_HP_RATIO_ABS 0.0f +#define CRITICAL_HP_RATIO_BASE 30.0f + +struct HealingStats +{ + uint32 last_heal_time_ms; + uint32 heal_count; +}; + +// Both members and targets use a shared_ptr to keep track of their HealRotation instance +class HealRotation +{ +public: + HealRotation(Bot* hr_creator, uint32 interval_ms = CASTING_CYCLE_DEFAULT_INTERVAL, bool fast_heals = false, bool adaptive_targeting = false, bool casting_override = false); + HealRotation(HealRotation* allocator_shunt) {}; // use should be limited to the shared_ptr memory allocation call + + void SetIntervalMS(uint32 interval_ms); + void SetIntervalS(uint32 interval_s); + void SetFastHeals(bool flag) { m_fast_heals = flag; } + void SetAdaptiveTargeting(bool flag) { m_adaptive_targeting = flag; } + void SetCastingOverride(bool flag) { m_casting_override = flag; } + bool AddMemberToPool(Bot* hr_member); + bool AddTargetToPool(Mob* hr_target); + + uint32 CreationTimeMS() { return m_creation_time_ms; } + uint32 LastHealTimeMS() { return m_last_heal_time_ms; } + uint32 IntervalMS() { return m_interval_ms; } + uint32 IntervalS() { return (m_interval_ms / 1000); } + bool FastHeals() { return m_fast_heals; } + bool AdaptiveTargeting() { return m_adaptive_targeting; } + bool CastingOverride() { return m_casting_override; } + bool RemoveMemberFromPool(Bot* hr_member); + bool RemoveTargetFromPool(Mob* hr_target); + + bool ClearMemberPool(); + bool ClearTargetPool(); + + Mob* HOTTarget() { return m_hot_target; } + bool SetHOTTarget(Mob* hot_target); + bool ClearHOTTarget(); + + bool Start(); + bool Stop(); + + bool IsActive() { return m_is_active; } + bool IsHOTActive() { return m_hot_active; } + bool CastingReady() { return (Timer::GetCurrentTime() >= m_next_cast_time_ms); } + Bot* CastingMember(); + bool PokeCastingTarget(); + Mob* CastingTarget(); + bool AdvanceRotation(bool use_interval = true); + + std::list* MemberList() { return &m_member_pool; } + std::list* CycleList() { return &m_cycle_pool; } + std::list* TargetList() { return &m_target_pool; } + + bool IsMemberInPool(Bot* hr_member); + bool IsTargetInPool(Mob* hr_target); + bool IsHOTTarget(Mob* hot_target); + + void SetMemberIsCasting(Bot* hr_member, bool flag = true); + bool MemberIsCasting(Bot* hr_member); + + void UpdateTargetHealingStats(Mob* hr_target); + void StartNewTargetHealingStatsCycle(uint32 current_time); + uint32 HealCount(Mob* hr_target); + uint32 ExtendedHealCount(Mob* hr_target); + float HealFrequency(Mob* hr_target); + float ExtendedHealFrequency(Mob* hr_target); + HealingStats* TargetHealingStats1(Mob* hr_target); + HealingStats* TargetHealingStats2(Mob* hr_target); + + bool SetArmorTypeSafeHPRatio(uint8 armor_type, float hp_ratio); + bool SetArmorTypeCriticalHPRatio(uint8 armor_type, float hp_ratio); + + float ArmorTypeSafeHPRatio(uint8 armor_type); + float ArmorTypeCriticalHPRatio(uint8 armor_type); + + void ResetArmorTypeHPLimits(); + +private: + bool valid_state(); + void cycle_refresh(); + bool healable_target(bool use_class_at = true, bool critical_only = false); + void bias_targets(); + void validate_hot(); + + uint32 m_creation_time_ms; + uint32 m_last_heal_time_ms; + uint32 m_interval_ms; + uint32 m_next_cast_time_ms; + uint32 m_next_poke_time_ms; + uint32 m_healing_stats_begin_ms; + bool m_fast_heals; + bool m_adaptive_targeting; + bool m_casting_override; + bool m_casting_target_poke; + bool m_active_heal_target; + + bool m_is_active; + + bool m_consumed; + + Mob* m_hot_target; + bool m_hot_active; + + std::list m_member_pool; + std::list m_cycle_pool; + std::list m_target_pool; + + std::map m_member_is_casting; + + std::map m_target_healing_stats_1; + std::map m_target_healing_stats_2; + + float m_safe_hp_ratio[ARMOR_TYPE_COUNT]; + float m_critical_hp_ratio[ARMOR_TYPE_COUNT]; +}; + +bool IsHealRotationMemberClass(uint8 class_id); +bool IsHealRotationTargetMobType(Mob* target_mob); + +#endif + +#endif // BOTS diff --git a/zone/horse.cpp b/zone/horse.cpp index 2cf76886b..a2cebcdc9 100644 --- a/zone/horse.cpp +++ b/zone/horse.cpp @@ -83,35 +83,35 @@ const NPCType *Horse::BuildHorseType(uint16 spell_id) { auto row = results.begin(); - NPCType* npc_type = new NPCType; - memset(npc_type, 0, sizeof(NPCType)); - strcpy(npc_type->name,"Unclaimed_Mount"); //this should never get used + auto npc_type = new NPCType; + memset(npc_type, 0, sizeof(NPCType)); + strcpy(npc_type->name, "Unclaimed_Mount"); // this should never get used - strcpy(npc_type->special_abilities, "19,1^20,1^24,1"); - npc_type->cur_hp = 1; - npc_type->max_hp = 1; - npc_type->race = atoi(row[0]); - npc_type->gender = atoi(row[1]); // Drogmor's are female horses. Yuck. - npc_type->class_ = 1; - npc_type->deity= 1; - npc_type->level = 1; - npc_type->npc_id = 0; - npc_type->loottable_id = 0; - npc_type->texture = atoi(row[2]); // mount color - npc_type->helmtexture = atoi(row[2]); // mount color - npc_type->runspeed = atof(row[3]); + strcpy(npc_type->special_abilities, "19,1^20,1^24,1"); + npc_type->cur_hp = 1; + npc_type->max_hp = 1; + npc_type->race = atoi(row[0]); + npc_type->gender = atoi(row[1]); // Drogmor's are female horses. Yuck. + npc_type->class_ = 1; + npc_type->deity = 1; + npc_type->level = 1; + npc_type->npc_id = 0; + npc_type->loottable_id = 0; + npc_type->texture = atoi(row[2]); // mount color + npc_type->helmtexture = atoi(row[2]); // mount color + npc_type->runspeed = atof(row[3]); - npc_type->light = 0; - npc_type->STR = 75; - npc_type->STA = 75; - npc_type->DEX = 75; - npc_type->AGI = 75; - npc_type->INT = 75; - npc_type->WIS = 75; - npc_type->CHA = 75; - horses_auto_delete.Insert(npc_type); + npc_type->light = 0; + npc_type->STR = 75; + npc_type->STA = 75; + npc_type->DEX = 75; + npc_type->AGI = 75; + npc_type->INT = 75; + npc_type->WIS = 75; + npc_type->CHA = 75; + horses_auto_delete.Insert(npc_type); - return npc_type; + return npc_type; } void Client::SummonHorse(uint16 spell_id) { @@ -126,7 +126,7 @@ void Client::SummonHorse(uint16 spell_id) { // No Horse, lets get them one. - Horse* horse = new Horse(this, spell_id, GetPosition()); + auto horse = new Horse(this, spell_id, GetPosition()); //we want to manage the spawn packet ourself. //another reason is we dont want quests executing on it. diff --git a/zone/inventory.cpp b/zone/inventory.cpp index badc059e0..d03cac310 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2003 EQEMu Development Team (http://eqemulator.net) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { int i; if(where_to_check & invWhereWorn) { - for (i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; i++) { + for (i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= EQEmu::legacy::EQUIPMENT_END; i++) { if (GetItemIDAt(i) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(i) != INVALID_ID)) { cur = m_inv.GetItem(i); if(cur && cur->GetItem()->Stackable) { @@ -48,34 +48,34 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { } } - if (GetItemIDAt(MainPowerSource) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(MainPowerSource) != INVALID_ID)) { - cur = m_inv.GetItem(MainPowerSource); + if (GetItemIDAt(EQEmu::legacy::SlotPowerSource) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(EQEmu::legacy::SlotPowerSource) != INVALID_ID)) { + cur = m_inv.GetItem(EQEmu::legacy::SlotPowerSource); if(cur && cur->GetItem()->Stackable) { x += cur->GetCharges(); } else { x++; } - if (GetClientVersion() >= ClientVersion::SoF) - DeleteItemInInventory(MainPowerSource, 0, true); + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) + DeleteItemInInventory(EQEmu::legacy::SlotPowerSource, 0, true); else - DeleteItemInInventory(MainPowerSource, 0, false); // Prevents Titanium crash + DeleteItemInInventory(EQEmu::legacy::SlotPowerSource, 0, false); // Prevents Titanium crash } } if(where_to_check & invWhereCursor) { - if (GetItemIDAt(MainCursor) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(MainCursor) != INVALID_ID)) { - cur = m_inv.GetItem(MainCursor); + if (GetItemIDAt(EQEmu::legacy::SlotCursor) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(EQEmu::legacy::SlotCursor) != INVALID_ID)) { + cur = m_inv.GetItem(EQEmu::legacy::SlotCursor); if(cur && cur->GetItem()->Stackable) { x += cur->GetCharges(); } else { x++; } - DeleteItemInInventory(MainCursor, 0, true); + DeleteItemInInventory(EQEmu::legacy::SlotCursor, 0, true); } - for (i = EmuConstants::CURSOR_BAG_BEGIN; i <= EmuConstants::CURSOR_BAG_END; i++) { + for (i = EQEmu::legacy::CURSOR_BAG_BEGIN; i <= EQEmu::legacy::CURSOR_BAG_END; i++) { if (GetItemIDAt(i) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(i) != INVALID_ID)) { cur = m_inv.GetItem(i); if(cur && cur->GetItem()->Stackable) { @@ -90,7 +90,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { } if(where_to_check & invWherePersonal) { - for (i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { + for (i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; i++) { if (GetItemIDAt(i) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(i) != INVALID_ID)) { cur = m_inv.GetItem(i); if(cur && cur->GetItem()->Stackable) { @@ -103,7 +103,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { } } - for (i = EmuConstants::GENERAL_BAGS_BEGIN; i <= EmuConstants::GENERAL_BAGS_END; i++) { + for (i = EQEmu::legacy::GENERAL_BAGS_BEGIN; i <= EQEmu::legacy::GENERAL_BAGS_END; i++) { if (GetItemIDAt(i) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(i) != INVALID_ID)) { cur = m_inv.GetItem(i); if(cur && cur->GetItem()->Stackable) { @@ -118,7 +118,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { } if(where_to_check & invWhereBank) { - for (i = EmuConstants::BANK_BEGIN; i <= EmuConstants::BANK_END; i++) { + for (i = EQEmu::legacy::BANK_BEGIN; i <= EQEmu::legacy::BANK_END; i++) { if (GetItemIDAt(i) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(i) != INVALID_ID)) { cur = m_inv.GetItem(i); if(cur && cur->GetItem()->Stackable) { @@ -131,7 +131,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { } } - for (i = EmuConstants::BANK_BAGS_BEGIN; i <= EmuConstants::BANK_BAGS_END; i++) { + for (i = EQEmu::legacy::BANK_BAGS_BEGIN; i <= EQEmu::legacy::BANK_BAGS_END; i++) { if (GetItemIDAt(i) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(i) != INVALID_ID)) { cur = m_inv.GetItem(i); if(cur && cur->GetItem()->Stackable) { @@ -146,7 +146,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { } if(where_to_check & invWhereSharedBank) { - for (i = EmuConstants::SHARED_BANK_BEGIN; i <= EmuConstants::SHARED_BANK_END; i++) { + for (i = EQEmu::legacy::SHARED_BANK_BEGIN; i <= EQEmu::legacy::SHARED_BANK_END; i++) { if (GetItemIDAt(i) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(i) != INVALID_ID)) { cur = m_inv.GetItem(i); if(cur && cur->GetItem()->Stackable) { @@ -159,7 +159,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { } } - for (i = EmuConstants::SHARED_BANK_BAGS_BEGIN; i <= EmuConstants::SHARED_BANK_BAGS_END; i++) { + for (i = EQEmu::legacy::SHARED_BANK_BAGS_BEGIN; i <= EQEmu::legacy::SHARED_BANK_BAGS_END; i++) { if (GetItemIDAt(i) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(i) != INVALID_ID)) { cur = m_inv.GetItem(i); if(cur && cur->GetItem()->Stackable) { @@ -177,7 +177,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { } -bool Client::CheckLoreConflict(const Item_Struct* item) +bool Client::CheckLoreConflict(const EQEmu::ItemBase* item) { if (!item) { return false; } if (!item->LoreFlag) { return false; } @@ -195,7 +195,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, // TODO: update calling methods and script apis to handle a failure return - const Item_Struct* item = database.GetItem(item_id); + const EQEmu::ItemBase* item = database.GetItem(item_id); // make sure the item exists if(item == nullptr) { @@ -213,7 +213,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, return false; } // check to make sure we are augmenting an augmentable item - else if (((item->ItemClass != ItemClassCommon) || (item->AugType > 0)) && (aug1 | aug2 | aug3 | aug4 | aug5 | aug6)) { + else if (((!item->IsClassCommon()) || (item->AugType > 0)) && (aug1 | aug2 | aug3 | aug4 | aug5 | aug6)) { Message(13, "You can not augment an augment or a non-common class item."); Log.Out(Logs::Detail, Logs::Inventory, "Player %s on account %s attempted to augment an augment or a non-common class item.\n(Item: %u, Aug1: %u, Aug2: %u, Aug3: %u, Aug4: %u, Aug5: %u, Aug5: %u)\n", GetName(), account_name, item->ID, aug1, aug2, aug3, aug4, aug5, aug6); @@ -236,7 +236,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, } */ - uint32 augments[EmuConstants::ITEM_COMMON_SIZE] = { aug1, aug2, aug3, aug4, aug5, aug6 }; + uint32 augments[EQEmu::legacy::ITEM_COMMON_SIZE] = { aug1, aug2, aug3, aug4, aug5, aug6 }; uint32 classes = item->Classes; uint32 races = item->Races; @@ -246,8 +246,8 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, bool enforcerestr = RuleB(Inventory, EnforceAugmentRestriction); bool enforceusable = RuleB(Inventory, EnforceAugmentUsability); - for (int iter = AUG_BEGIN; iter < EmuConstants::ITEM_COMMON_SIZE; ++iter) { - const Item_Struct* augtest = database.GetItem(augments[iter]); + for (int iter = AUG_INDEX_BEGIN; iter < EQEmu::legacy::ITEM_COMMON_SIZE; ++iter) { + const EQEmu::ItemBase* augtest = database.GetItem(augments[iter]); if(augtest == nullptr) { if(augments[iter]) { @@ -290,7 +290,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, // check for augment type allowance if(enforcewear) { - if((item->AugSlotType[iter] == AugTypeNone) || !(((uint32)1 << (item->AugSlotType[iter] - 1)) & augtest->AugType)) { + if ((item->AugSlotType[iter] == EQEmu::item::AugTypeNone) || !(((uint32)1 << (item->AugSlotType[iter] - 1)) & augtest->AugType)) { Message(13, "Augment %u (Aug%i) is not acceptable wear on Item %u.", augments[iter], iter + 1, item->ID); Log.Out(Logs::Detail, Logs::Inventory, "Player %s on account %s attempted to augment an item with an unacceptable augment type (Aug%i).\n(Item: %u, Aug1: %u, Aug2: %u, Aug3: %u, Aug4: %u, Aug5: %u, Aug6: %u)\n", GetName(), account_name, (iter + 1), item->ID, aug1, aug2, aug3, aug4, aug5, aug6); @@ -313,153 +313,153 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, uint8 it = item->ItemType; switch(augtest->AugRestrict) { - case AugRestrAny: + case EQEmu::item::AugRestrictionAny: break; - case AugRestrArmor: + case EQEmu::item::AugRestrictionArmor: switch(it) { - case ItemTypeArmor: + case EQEmu::item::ItemTypeArmor: break; default: restrictfail = true; break; } break; - case AugRestrWeapons: + case EQEmu::item::AugRestrictionWeapons: switch(it) { - case ItemType1HSlash: - case ItemType1HBlunt: - case ItemType1HPiercing: - case ItemTypeMartial: - case ItemType2HSlash: - case ItemType2HBlunt: - case ItemType2HPiercing: - case ItemTypeBow: + case EQEmu::item::ItemType1HSlash: + case EQEmu::item::ItemType1HBlunt: + case EQEmu::item::ItemType1HPiercing: + case EQEmu::item::ItemTypeMartial: + case EQEmu::item::ItemType2HSlash: + case EQEmu::item::ItemType2HBlunt: + case EQEmu::item::ItemType2HPiercing: + case EQEmu::item::ItemTypeBow: break; default: restrictfail = true; break; } break; - case AugRestr1HWeapons: + case EQEmu::item::AugRestriction1HWeapons: switch(it) { - case ItemType1HSlash: - case ItemType1HBlunt: - case ItemType1HPiercing: - case ItemTypeMartial: + case EQEmu::item::ItemType1HSlash: + case EQEmu::item::ItemType1HBlunt: + case EQEmu::item::ItemType1HPiercing: + case EQEmu::item::ItemTypeMartial: break; default: restrictfail = true; break; } break; - case AugRestr2HWeapons: + case EQEmu::item::AugRestriction2HWeapons: switch(it) { - case ItemType2HSlash: - case ItemType2HBlunt: - case ItemType2HPiercing: - case ItemTypeBow: + case EQEmu::item::ItemType2HSlash: + case EQEmu::item::ItemType2HBlunt: + case EQEmu::item::ItemType2HPiercing: + case EQEmu::item::ItemTypeBow: break; default: restrictfail = true; break; } break; - case AugRestr1HSlash: + case EQEmu::item::AugRestriction1HSlash: switch(it) { - case ItemType1HSlash: + case EQEmu::item::ItemType1HSlash: break; default: restrictfail = true; break; } break; - case AugRestr1HBlunt: + case EQEmu::item::AugRestriction1HBlunt: switch(it) { - case ItemType1HBlunt: + case EQEmu::item::ItemType1HBlunt: break; default: restrictfail = true; break; } break; - case AugRestrPiercing: + case EQEmu::item::AugRestrictionPiercing: switch(it) { - case ItemType1HPiercing: + case EQEmu::item::ItemType1HPiercing: break; default: restrictfail = true; break; } break; - case AugRestrHandToHand: + case EQEmu::item::AugRestrictionHandToHand: switch(it) { - case ItemTypeMartial: + case EQEmu::item::ItemTypeMartial: break; default: restrictfail = true; break; } break; - case AugRestr2HSlash: + case EQEmu::item::AugRestriction2HSlash: switch(it) { - case ItemType2HSlash: + case EQEmu::item::ItemType2HSlash: break; default: restrictfail = true; break; } break; - case AugRestr2HBlunt: + case EQEmu::item::AugRestriction2HBlunt: switch(it) { - case ItemType2HBlunt: + case EQEmu::item::ItemType2HBlunt: break; default: restrictfail = true; break; } break; - case AugRestr2HPierce: + case EQEmu::item::AugRestriction2HPierce: switch(it) { - case ItemType2HPiercing: + case EQEmu::item::ItemType2HPiercing: break; default: restrictfail = true; break; } break; - case AugRestrBows: + case EQEmu::item::AugRestrictionBows: switch(it) { - case ItemTypeBow: + case EQEmu::item::ItemTypeBow: break; default: restrictfail = true; break; } break; - case AugRestrShields: + case EQEmu::item::AugRestrictionShields: switch(it) { - case ItemTypeShield: + case EQEmu::item::ItemTypeShield: break; default: restrictfail = true; break; } break; - case AugRestr1HSlash1HBluntOrHandToHand: + case EQEmu::item::AugRestriction1HSlash1HBluntOrHandToHand: switch(it) { - case ItemType1HSlash: - case ItemType1HBlunt: - case ItemTypeMartial: + case EQEmu::item::ItemType1HSlash: + case EQEmu::item::ItemType1HBlunt: + case EQEmu::item::ItemTypeMartial: break; default: restrictfail = true; break; } break; - case AugRestr1HBluntOrHandToHand: + case EQEmu::item::AugRestriction1HBluntOrHandToHand: switch(it) { - case ItemType1HBlunt: - case ItemTypeMartial: + case EQEmu::item::ItemType1HBlunt: + case EQEmu::item::ItemTypeMartial: break; default: restrictfail = true; @@ -467,9 +467,9 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, } break; // These 3 are in-work - case AugRestrUnknown1: - case AugRestrUnknown2: - case AugRestrUnknown3: + case EQEmu::item::AugRestrictionUnknown1: + case EQEmu::item::AugRestrictionUnknown2: + case EQEmu::item::AugRestrictionUnknown3: default: restrictfail = true; break; @@ -540,7 +540,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, } // add any validated augments - for (int iter = AUG_BEGIN; iter < EmuConstants::ITEM_COMMON_SIZE; ++iter) { + for (int iter = AUG_INDEX_BEGIN; iter < EQEmu::legacy::ITEM_COMMON_SIZE; ++iter) { if(augments[iter]) inst->PutAugment(&database, iter, augments[iter]); } @@ -554,22 +554,22 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, inst->SetOrnamentHeroModel(ornament_hero_model); // check to see if item is usable in requested slot - if(enforceusable && (((to_slot >= MainCharm) && (to_slot <= MainAmmo)) || (to_slot == MainPowerSource))) { - uint32 slottest = (to_slot == MainPowerSource) ? 22 : to_slot; // can't change '22' just yet... + if (enforceusable && (((to_slot >= EQEmu::legacy::SlotCharm) && (to_slot <= EQEmu::legacy::SlotAmmo)) || (to_slot == EQEmu::legacy::SlotPowerSource))) { + uint32 slottest = (to_slot == EQEmu::legacy::SlotPowerSource) ? 22 : to_slot; // can't change '22' just yet... if(!(slots & ((uint32)1 << slottest))) { Message(0, "This item is not equipable at slot %u - moving to cursor.", to_slot); Log.Out(Logs::Detail, Logs::Inventory, "Player %s on account %s attempted to equip an item unusable in slot %u - moved to cursor.\n(Item: %u, Aug1: %u, Aug2: %u, Aug3: %u, Aug4: %u, Aug5: %u, Aug6: %u)\n", GetName(), account_name, to_slot, item->ID, aug1, aug2, aug3, aug4, aug5, aug6); - to_slot = MainCursor; + to_slot = EQEmu::legacy::SlotCursor; } } // put item into inventory - if (to_slot == MainCursor) { + if (to_slot == EQEmu::legacy::SlotCursor) { PushItemOnCursor(*inst); - SendItemPacket(MainCursor, inst, ItemPacketSummonItem); + SendItemPacket(EQEmu::legacy::SlotCursor, inst, ItemPacketLimbo); } else { PutItemInInventory(to_slot, *inst, true); @@ -583,7 +583,7 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, DiscoverItem(item_id); /* // Augments should have been discovered prior to being placed on an item. - for (int iter = AUG_BEGIN; iter < EmuConstants::ITEM_COMMON_SIZE; ++iter) { + for (int iter = AUG_BEGIN; iter < EQEmu::constants::ITEM_COMMON_SIZE; ++iter) { if(augments[iter] && !IsDiscovered(augments[iter])) DiscoverItem(augments[iter]); } @@ -606,7 +606,7 @@ void Client::DropItem(int16 slot_id) // Take control of item in client inventory ItemInst *inst = m_inv.PopItem(slot_id); if(inst) { - int i = parse->EventItem(EVENT_DROP_ITEM, this, inst, nullptr, "", 0); + int i = parse->EventItem(EVENT_DROP_ITEM, this, inst, nullptr, "", slot_id); if(i != 0) { safe_delete(inst); } @@ -617,7 +617,7 @@ void Client::DropItem(int16 slot_id) } // Save client inventory change to database - if (slot_id == MainCursor) { + if (slot_id == EQEmu::legacy::SlotCursor) { SendCursorBuffer(); auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(CharacterID(), s, e); @@ -629,7 +629,7 @@ void Client::DropItem(int16 slot_id) return; // Package as zone object - Object* object = new Object(this, inst); + auto object = new Object(this, inst); entity_list.AddObject(object, true); object->StartDecay(); @@ -653,7 +653,7 @@ void Client::DropInst(const ItemInst* inst) } // Package as zone object - Object* object = new Object(this, inst); + auto object = new Object(this, inst); entity_list.AddObject(object, true); object->StartDecay(); } @@ -685,7 +685,7 @@ void Client::SendCursorBuffer() // Temporary work-around for the RoF+ Client Buffer // Instead of dealing with client moving items in cursor buffer, // we can just send the next item in the cursor buffer to the cursor. - if (GetClientVersion() < ClientVersion::RoF) { return; } + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) { return; } if (GetInv().CursorEmpty()) { return; } auto test_inst = GetInv().GetCursorItem(); @@ -706,11 +706,11 @@ void Client::SendCursorBuffer() GetName(), test_item->Name, test_item->ID); Message_StringID(MT_LootMessages, 290); parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0); - DeleteItemInInventory(MainCursor); + DeleteItemInInventory(EQEmu::legacy::SlotCursor); SendCursorBuffer(); } else { - SendItemPacket(MainCursor, test_inst, ItemPacketSummonItem); + SendItemPacket(EQEmu::legacy::SlotCursor, test_inst, ItemPacketLimbo); } } @@ -743,7 +743,9 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd if(m_inv[slot_id]) { delete_count += m_inv.GetItem(slot_id)->GetTotalItemCount(); } - ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogDeletes, sizeof(QSPlayerLogDelete_Struct) + (sizeof(QSDeleteItems_Struct) * delete_count)); + auto qspack = + new ServerPacket(ServerOP_QSPlayerLogDeletes, + sizeof(QSPlayerLogDelete_Struct) + (sizeof(QSDeleteItems_Struct) * delete_count)); QSPlayerLogDelete_Struct* qsaudit = (QSPlayerLogDelete_Struct*)qspack->pBuffer; uint16 parent_offset = 0; @@ -760,8 +762,8 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd qsaudit->items[parent_offset].aug_4 = m_inv[slot_id]->GetAugmentItemID(4); qsaudit->items[parent_offset].aug_5 = m_inv[slot_id]->GetAugmentItemID(5); - if(m_inv[slot_id]->IsType(ItemClassContainer)) { - for(uint8 bag_idx = SUB_BEGIN; bag_idx < m_inv[slot_id]->GetItem()->BagSlots; bag_idx++) { + if (m_inv[slot_id]->IsClassBag()) { + for (uint8 bag_idx = SUB_INDEX_BEGIN; bag_idx < m_inv[slot_id]->GetItem()->BagSlots; bag_idx++) { ItemInst* bagitem = m_inv[slot_id]->GetItem(bag_idx); if(bagitem) { @@ -788,7 +790,7 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd bool isDeleted = m_inv.DeleteItem(slot_id, quantity); const ItemInst* inst = nullptr; - if (slot_id == MainCursor) { + if (slot_id == EQEmu::legacy::SlotCursor) { auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); if(update_db) database.SaveCursor(character_id, s, e); @@ -840,7 +842,7 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update) m_inv.PushCursor(inst); if (client_update) { - SendItemPacket(MainCursor, &inst, ItemPacketSummonItem); + SendItemPacket(EQEmu::legacy::SlotCursor, &inst, ItemPacketLimbo); } auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); @@ -854,7 +856,7 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update) bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) { Log.Out(Logs::Detail, Logs::Inventory, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id); - if (slot_id == MainCursor) { // don't trust macros before conditional statements... + if (slot_id == EQEmu::legacy::SlotCursor) { // don't trust macros before conditional statements... return PushItemOnCursor(inst, client_update); } else { @@ -863,11 +865,11 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client if (client_update) { - SendItemPacket(slot_id, &inst, ((slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade)); + SendItemPacket(slot_id, &inst, ((slot_id == EQEmu::legacy::SlotCursor) ? ItemPacketLimbo : ItemPacketTrade)); //SendWearChange(Inventory::CalcMaterialFromSlot(slot_id)); } - if (slot_id == MainCursor) { + if (slot_id == EQEmu::legacy::SlotCursor) { auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); return database.SaveCursor(this->CharacterID(), s, e); } @@ -885,7 +887,7 @@ void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootI bool cursor_empty = m_inv.CursorEmpty(); - if (slot_id == MainCursor) { + if (slot_id == EQEmu::legacy::SlotCursor) { m_inv.PushCursor(inst); auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(this->CharacterID(), s, e); @@ -896,17 +898,17 @@ void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootI } // Subordinate items in cursor buffer must be sent via ItemPacketSummonItem or we just overwrite the visible cursor and desync the client - if (slot_id == MainCursor && !cursor_empty) { + if (slot_id == EQEmu::legacy::SlotCursor && !cursor_empty) { // RoF+ currently has a specialized cursor handler - if (GetClientVersion() < ClientVersion::RoF) - SendItemPacket(slot_id, &inst, ItemPacketSummonItem); + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) + SendItemPacket(slot_id, &inst, ItemPacketLimbo); } else { SendLootItemInPacket(&inst, slot_id); } if (bag_item_data) { - for (int index = 0; index < EmuConstants::ITEM_CONTAINER_SIZE; ++index) { + for (int index = 0; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; ++index) { if (bag_item_data[index] == nullptr) continue; @@ -924,12 +926,12 @@ void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootI // Dump bag contents to cursor in the event that owning bag is not the first cursor item // (This assumes that the data passed is correctly associated..no safety checks are implemented) - if (slot_id == MainCursor && !cursor_empty) { + if (slot_id == EQEmu::legacy::SlotCursor && !cursor_empty) { Log.Out(Logs::Detail, Logs::Inventory, "Putting bag loot item %s (%d) into slot %d (non-empty cursor override)", - inst.GetItem()->Name, inst.GetItem()->ID, MainCursor); + inst.GetItem()->Name, inst.GetItem()->ID, EQEmu::legacy::SlotCursor); - PutLootInInventory(MainCursor, *bagitem); + PutLootInInventory(EQEmu::legacy::SlotCursor, *bagitem); } else { auto bag_slot = Inventory::CalcSlotId(slot_id, index); @@ -951,7 +953,7 @@ bool Client::TryStacking(ItemInst* item, uint8 type, bool try_worn, bool try_cur return false; int16 i; uint32 item_id = item->GetItem()->ID; - for (i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { + for (i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; i++) { ItemInst* tmp_inst = m_inv.GetItem(i); if(tmp_inst && tmp_inst->GetItem()->ID == item_id && tmp_inst->GetCharges() < tmp_inst->GetItem()->StackSize){ MoveItemCharges(*item, i, type); @@ -962,8 +964,8 @@ bool Client::TryStacking(ItemInst* item, uint8 type, bool try_worn, bool try_cur return true; } } - for (i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { - for (uint8 j = SUB_BEGIN; j < EmuConstants::ITEM_CONTAINER_SIZE; j++) { + for (i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; i++) { + for (uint8 j = SUB_INDEX_BEGIN; j < EQEmu::legacy::ITEM_CONTAINER_SIZE; j++) { uint16 slotid = Inventory::CalcSlotId(i, j); ItemInst* tmp_inst = m_inv.GetItem(slotid); @@ -986,31 +988,30 @@ bool Client::TryStacking(ItemInst* item, uint8 type, bool try_worn, bool try_cur bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_cursor, ServerLootItem_Struct** bag_item_data) { // #1: Try to auto equip - if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel<=level && (!inst.GetItem()->Attuneable || inst.IsAttuned()) && inst.GetItem()->ItemType != ItemTypeAugmentation) { + if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel <= level && (!inst.GetItem()->Attuneable || inst.IsAttuned()) && inst.GetItem()->ItemType != EQEmu::item::ItemTypeAugmentation) { // too messy as-is... - for (int16 i = EmuConstants::EQUIPMENT_BEGIN; i < MainPowerSource; i++) { // originally (i < 22) - if (i == EmuConstants::GENERAL_BEGIN) { + for (int16 i = EQEmu::legacy::EQUIPMENT_BEGIN; i < EQEmu::legacy::SlotPowerSource; i++) { // originally (i < 22) + if (i == EQEmu::legacy::GENERAL_BEGIN) { // added power source check for SoF+ clients - if (this->GetClientVersion() >= ClientVersion::SoF) - i = MainPowerSource; + if (this->ClientVersion() >= EQEmu::versions::ClientVersion::SoF) + i = EQEmu::legacy::SlotPowerSource; else break; } if (!m_inv[i]) { - if (i == MainPrimary && inst.IsWeapon()) { // If item is primary slot weapon - if ((inst.GetItem()->ItemType == ItemType2HSlash) || (inst.GetItem()->ItemType == ItemType2HBlunt) || (inst.GetItem()->ItemType == ItemType2HPiercing)) { // and uses 2hs \ 2hb \ 2hp - if (m_inv[MainSecondary]) { // and if secondary slot is not empty + if (i == EQEmu::legacy::SlotPrimary && inst.IsWeapon()) { // If item is primary slot weapon + if (inst.GetItem()->IsType2HWeapon()) { // and uses 2hs \ 2hb \ 2hp + if (m_inv[EQEmu::legacy::SlotSecondary]) { // and if secondary slot is not empty continue; // Can't auto-equip } } } - if (i == MainSecondary && m_inv[MainPrimary]) { // check to see if primary slot is a two hander - uint8 use = m_inv[MainPrimary]->GetItem()->ItemType; - if (use == ItemType2HSlash || use == ItemType2HBlunt || use == ItemType2HPiercing) + if (i == EQEmu::legacy::SlotSecondary && m_inv[EQEmu::legacy::SlotPrimary]) { // check to see if primary slot is a two hander + if (m_inv[EQEmu::legacy::SlotPrimary]->GetItem()->IsType2HWeapon()) continue; } - if (i == MainSecondary && inst.IsWeapon() && !CanThisClassDualWield()) { + if (i == EQEmu::legacy::SlotSecondary && inst.IsWeapon() && !CanThisClassDualWield()) { continue; } @@ -1018,7 +1019,7 @@ bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_curs //send worn to everyone... PutLootInInventory(i, inst); uint8 worn_slot_material = Inventory::CalcMaterialFromSlot(i); - if (worn_slot_material != _MaterialInvalid) { + if (worn_slot_material != EQEmu::textures::TextureInvalid) { SendWearChange(worn_slot_material); } @@ -1036,8 +1037,8 @@ bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_curs } // #3: put it in inventory - bool is_arrow = (inst.GetItem()->ItemType == ItemTypeArrow) ? true : false; - int16 slot_id = m_inv.FindFreeSlot(inst.IsType(ItemClassContainer), try_cursor, inst.GetItem()->Size, is_arrow); + bool is_arrow = (inst.GetItem()->ItemType == EQEmu::item::ItemTypeArrow) ? true : false; + int16 slot_id = m_inv.FindFreeSlot(inst.IsClassBag(), try_cursor, inst.GetItem()->Size, is_arrow); if (slot_id != INVALID_INDEX) { PutLootInInventory(slot_id, inst, bag_item_data); return true; @@ -1061,7 +1062,7 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type) tmp_inst->SetCharges(tmp_inst->GetCharges() + charges_to_move); from.SetCharges(from.GetCharges() - charges_to_move); SendLootItemInPacket(tmp_inst, to_slot); - if (to_slot == MainCursor) { + if (to_slot == EQEmu::legacy::SlotCursor) { auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(this->CharacterID(), s, e); } @@ -1073,7 +1074,7 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type) #if 0 // TODO: needs clean-up to save references -bool MakeItemLink(char* &ret_link, const Item_Struct *item, uint32 aug0, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint8 evolving, uint8 evolvedlevel) { +bool MakeItemLink(char* &ret_link, const ItemBase *item, uint32 aug0, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint8 evolving, uint8 evolvedlevel) { //we're sending back the entire "link", minus the null characters & item name //that way, we can use it for regular links & Task links //note: initiator needs to pass us ret_link @@ -1188,7 +1189,7 @@ int Client::GetItemLinkHash(const ItemInst* inst) { if (!inst) //have to have an item to make the hash return 0; - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); char* hash_str = 0; /*register */int hash = 0; @@ -1282,9 +1283,9 @@ packet with the item number in it, but I cant seem to find it right now if (!inst) return; - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); const char* name2 = &item->Name[0]; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ItemLinkText,strlen(name2)+68); + auto outapp = new EQApplicationPacket(OP_ItemLinkText, strlen(name2) + 68); char buffer2[135] = {0}; char itemlink[135] = {0}; sprintf(itemlink,"%c0%06u0%05u-%05u-%05u-%05u-%05u00000000%c", @@ -1318,16 +1319,16 @@ void Client::SendLootItemInPacket(const ItemInst* inst, int16 slot_id) bool Client::IsValidSlot(uint32 slot) { if ((slot == (uint32)INVALID_INDEX) || - (slot >= MAIN_BEGIN && slot < EmuConstants::MAP_POSSESSIONS_SIZE) || - (slot >= EmuConstants::GENERAL_BAGS_BEGIN && slot <= EmuConstants::CURSOR_BAG_END) || - (slot >= EmuConstants::TRIBUTE_BEGIN && slot <= EmuConstants::TRIBUTE_END) || - (slot >= EmuConstants::BANK_BEGIN && slot <= EmuConstants::BANK_END) || - (slot >= EmuConstants::BANK_BAGS_BEGIN && slot <= EmuConstants::BANK_BAGS_END) || - (slot >= EmuConstants::SHARED_BANK_BEGIN && slot <= EmuConstants::SHARED_BANK_END) || - (slot >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot <= EmuConstants::SHARED_BANK_BAGS_END) || - (slot >= EmuConstants::TRADE_BEGIN && slot <= EmuConstants::TRADE_END) || - (slot >= EmuConstants::WORLD_BEGIN && slot <= EmuConstants::WORLD_END) || - (slot == MainPowerSource) + (slot >= SLOT_BEGIN && slot < EQEmu::legacy::TYPE_POSSESSIONS_SIZE) || + (slot >= EQEmu::legacy::GENERAL_BAGS_BEGIN && slot <= EQEmu::legacy::CURSOR_BAG_END) || + (slot >= EQEmu::legacy::TRIBUTE_BEGIN && slot <= EQEmu::legacy::TRIBUTE_END) || + (slot >= EQEmu::legacy::BANK_BEGIN && slot <= EQEmu::legacy::BANK_END) || + (slot >= EQEmu::legacy::BANK_BAGS_BEGIN && slot <= EQEmu::legacy::BANK_BAGS_END) || + (slot >= EQEmu::legacy::SHARED_BANK_BEGIN && slot <= EQEmu::legacy::SHARED_BANK_END) || + (slot >= EQEmu::legacy::SHARED_BANK_BAGS_BEGIN && slot <= EQEmu::legacy::SHARED_BANK_BAGS_END) || + (slot >= EQEmu::legacy::TRADE_BEGIN && slot <= EQEmu::legacy::TRADE_END) || + (slot >= EQEmu::legacy::WORLD_BEGIN && slot <= EQEmu::legacy::WORLD_END) || + (slot == EQEmu::legacy::SlotPowerSource) ) { return true; } @@ -1338,10 +1339,10 @@ bool Client::IsValidSlot(uint32 slot) { bool Client::IsBankSlot(uint32 slot) { - if ((slot >= EmuConstants::BANK_BEGIN && slot <= EmuConstants::BANK_END) || - (slot >= EmuConstants::BANK_BAGS_BEGIN && slot <= EmuConstants::BANK_BAGS_END) || - (slot >= EmuConstants::SHARED_BANK_BEGIN && slot <= EmuConstants::SHARED_BANK_END) || - (slot >= EmuConstants::SHARED_BANK_BAGS_BEGIN && slot <= EmuConstants::SHARED_BANK_BAGS_END)) + if ((slot >= EQEmu::legacy::BANK_BEGIN && slot <= EQEmu::legacy::BANK_END) || + (slot >= EQEmu::legacy::BANK_BAGS_BEGIN && slot <= EQEmu::legacy::BANK_BAGS_END) || + (slot >= EQEmu::legacy::SHARED_BANK_BEGIN && slot <= EQEmu::legacy::SHARED_BANK_END) || + (slot >= EQEmu::legacy::SHARED_BANK_BAGS_BEGIN && slot <= EQEmu::legacy::SHARED_BANK_BAGS_END)) { return true; } @@ -1375,10 +1376,10 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit - if (GetClientVersion() >= ClientVersion::RoF) { return true; } // Can't do RoF+ + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { return true; } // Can't do RoF+ - if (move_in->to_slot == MainCursor) { - auto test_inst = m_inv.GetItem(MainCursor); + if (move_in->to_slot == EQEmu::legacy::SlotCursor) { + auto test_inst = m_inv.GetItem(EQEmu::legacy::SlotCursor); if (test_inst == nullptr) { return true; } auto test_item = test_inst->GetItem(); if (test_item == nullptr) { return true; } @@ -1397,18 +1398,18 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { GetName(), test_item->Name, test_item->ID); Message_StringID(MT_LootMessages, 290); parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0); - DeleteItemInInventory(MainCursor, 0, true); + DeleteItemInInventory(EQEmu::legacy::SlotCursor, 0, true); } } return true; } if (move_in->to_slot == (uint32)INVALID_INDEX) { - if (move_in->from_slot == (uint32)MainCursor) { + if (move_in->from_slot == (uint32)EQEmu::legacy::SlotCursor) { Log.Out(Logs::Detail, Logs::Inventory, "Client destroyed item from cursor slot %d", move_in->from_slot); if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit - ItemInst *inst = m_inv.GetItem(MainCursor); + ItemInst *inst = m_inv.GetItem(EQEmu::legacy::SlotCursor); if(inst) { parse->EventItem(EVENT_DESTROY_ITEM, this, inst, nullptr, "", 0); } @@ -1425,9 +1426,9 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { return true; // Item deletion } } - if(auto_attack && (move_in->from_slot == MainPrimary || move_in->from_slot == MainSecondary || move_in->from_slot == MainRange)) + if (auto_attack && (move_in->from_slot == EQEmu::legacy::SlotPrimary || move_in->from_slot == EQEmu::legacy::SlotSecondary || move_in->from_slot == EQEmu::legacy::SlotRange)) SetAttackTimer(); - else if(auto_attack && (move_in->to_slot == MainPrimary || move_in->to_slot == MainSecondary || move_in->to_slot == MainRange)) + else if (auto_attack && (move_in->to_slot == EQEmu::legacy::SlotPrimary || move_in->to_slot == EQEmu::legacy::SlotSecondary || move_in->to_slot == EQEmu::legacy::SlotRange)) SetAttackTimer(); // Step 1: Variables int16 src_slot_id = (int16)move_in->from_slot; @@ -1475,13 +1476,13 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { uint32 dstbagid = 0; //if (src_slot_id >= 250 && src_slot_id < 330) { - if (src_slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && src_slot_id <= EmuConstants::GENERAL_BAGS_END) { + if (src_slot_id >= EQEmu::legacy::GENERAL_BAGS_BEGIN && src_slot_id <= EQEmu::legacy::GENERAL_BAGS_END) { srcbag = m_inv.GetItem(((int)(src_slot_id / 10)) - 3); if (srcbag) srcbagid = srcbag->GetItem()->ID; } //if (dst_slot_id >= 250 && dst_slot_id < 330) { - if (dst_slot_id >= EmuConstants::GENERAL_BAGS_BEGIN && dst_slot_id <= EmuConstants::GENERAL_BAGS_END) { + if (dst_slot_id >= EQEmu::legacy::GENERAL_BAGS_BEGIN && dst_slot_id <= EQEmu::legacy::GENERAL_BAGS_END) { dstbag = m_inv.GetItem(((int)(dst_slot_id / 10)) - 3); if (dstbag) dstbagid = dstbag->GetItem()->ID; @@ -1494,7 +1495,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { // Step 2: Validate item in from_slot // After this, we can assume src_inst is a valid ptr - if (!src_inst && (src_slot_id < EmuConstants::WORLD_BEGIN || src_slot_id > EmuConstants::WORLD_END)) { + if (!src_inst && (src_slot_id < EQEmu::legacy::WORLD_BEGIN || src_slot_id > EQEmu::legacy::WORLD_END)) { if (dst_inst) { // If there is no source item, but there is a destination item, // move the slots around before deleting the invalid source slot item, @@ -1508,14 +1509,14 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { return false; } //verify shared bank transactions in the database - if(src_inst && src_slot_id >= EmuConstants::SHARED_BANK_BEGIN && src_slot_id <= EmuConstants::SHARED_BANK_BAGS_END) { + if (src_inst && src_slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && src_slot_id <= EQEmu::legacy::SHARED_BANK_BAGS_END) { if(!database.VerifyInventory(account_id, src_slot_id, src_inst)) { Log.Out(Logs::General, Logs::Error, "Player %s on account %s was found exploiting the shared bank.\n", GetName(), account_name); DeleteItemInInventory(dst_slot_id,0,true); return(false); } - if(src_slot_id >= EmuConstants::SHARED_BANK_BEGIN && src_slot_id <= EmuConstants::SHARED_BANK_END && src_inst->IsType(ItemClassContainer)){ - for (uint8 idx = SUB_BEGIN; idx < EmuConstants::ITEM_CONTAINER_SIZE; idx++) { + if (src_slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && src_slot_id <= EQEmu::legacy::SHARED_BANK_END && src_inst->IsClassBag()){ + for (uint8 idx = SUB_INDEX_BEGIN; idx < EQEmu::legacy::ITEM_CONTAINER_SIZE; idx++) { const ItemInst* baginst = src_inst->GetItem(idx); if(baginst && !database.VerifyInventory(account_id, Inventory::CalcSlotId(src_slot_id, idx), baginst)){ DeleteItemInInventory(Inventory::CalcSlotId(src_slot_id, idx),0,false); @@ -1523,14 +1524,14 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } } } - if(dst_inst && dst_slot_id >= EmuConstants::SHARED_BANK_BEGIN && dst_slot_id <= EmuConstants::SHARED_BANK_BAGS_END) { + if (dst_inst && dst_slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && dst_slot_id <= EQEmu::legacy::SHARED_BANK_BAGS_END) { if(!database.VerifyInventory(account_id, dst_slot_id, dst_inst)) { Log.Out(Logs::General, Logs::Error, "Player %s on account %s was found exploting the shared bank.\n", GetName(), account_name); DeleteItemInInventory(src_slot_id,0,true); return(false); } - if(dst_slot_id >= EmuConstants::SHARED_BANK_BEGIN && dst_slot_id <= EmuConstants::SHARED_BANK_END && dst_inst->IsType(ItemClassContainer)){ - for (uint8 idx = SUB_BEGIN; idx < EmuConstants::ITEM_CONTAINER_SIZE; idx++) { + if (dst_slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && dst_slot_id <= EQEmu::legacy::SHARED_BANK_END && dst_inst->IsClassBag()){ + for (uint8 idx = SUB_INDEX_BEGIN; idx < EQEmu::legacy::ITEM_CONTAINER_SIZE; idx++) { const ItemInst* baginst = dst_inst->GetItem(idx); if(baginst && !database.VerifyInventory(account_id, Inventory::CalcSlotId(dst_slot_id, idx), baginst)){ DeleteItemInInventory(Inventory::CalcSlotId(dst_slot_id, idx),0,false); @@ -1542,8 +1543,8 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { // Check for No Drop Hacks Mob* with = trade->With(); - if (((with && with->IsClient() && dst_slot_id >= EmuConstants::TRADE_BEGIN && dst_slot_id <= EmuConstants::TRADE_END) || - (dst_slot_id >= EmuConstants::SHARED_BANK_BEGIN && dst_slot_id <= EmuConstants::SHARED_BANK_BAGS_END)) + if (((with && with->IsClient() && dst_slot_id >= EQEmu::legacy::TRADE_BEGIN && dst_slot_id <= EQEmu::legacy::TRADE_END) || + (dst_slot_id >= EQEmu::legacy::SHARED_BANK_BEGIN && dst_slot_id <= EQEmu::legacy::SHARED_BANK_BAGS_END)) && GetInv().CheckNoDrop(src_slot_id) && RuleI(World, FVNoDropFlag) == 0 || RuleI(Character, MinStatusForNoDropExemptions) < Admin() && RuleI(World, FVNoDropFlag) == 2) { auto ndh_inst = m_inv[src_slot_id]; @@ -1554,7 +1555,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { else { auto ndh_item = ndh_inst->GetItem(); if (ndh_item == nullptr) { - ndh_item_data.append("[nullptr on Item_Struct*]"); + ndh_item_data.append("[nullptr on ItemBase*]"); } else { ndh_item_data.append(StringFormat("name=%s", ndh_item->Name)); @@ -1573,7 +1574,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { // Step 3: Check for interaction with World Container (tradeskills) if(m_tradeskill_object != nullptr) { - if (src_slot_id >= EmuConstants::WORLD_BEGIN && src_slot_id <= EmuConstants::WORLD_END) { + if (src_slot_id >= EQEmu::legacy::WORLD_BEGIN && src_slot_id <= EQEmu::legacy::WORLD_END) { // Picking up item from world container ItemInst* inst = m_tradeskill_object->PopItem(Inventory::CalcBagIdx(src_slot_id)); if (inst) { @@ -1585,7 +1586,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { return true; } - else if (dst_slot_id >= EmuConstants::WORLD_BEGIN && dst_slot_id <= EmuConstants::WORLD_END) { + else if (dst_slot_id >= EQEmu::legacy::WORLD_BEGIN && dst_slot_id <= EQEmu::legacy::WORLD_END) { // Putting item into world container, which may swap (or pile onto) with existing item uint8 world_idx = Inventory::CalcBagIdx(dst_slot_id); ItemInst* world_inst = m_tradeskill_object->PopItem(world_idx); @@ -1596,8 +1597,8 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { m_inv.DeleteItem(src_slot_id); } else { - const Item_Struct* world_item = world_inst->GetItem(); - const Item_Struct* src_item = src_inst->GetItem(); + const EQEmu::ItemBase* world_item = world_inst->GetItem(); + const EQEmu::ItemBase* src_item = src_inst->GetItem(); if (world_item && src_item) { // Case 2: Same item on cursor, stacks, transfer of charges needed if ((world_item->ID == src_item->ID) && src_inst->IsStackable()) { @@ -1637,7 +1638,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } safe_delete(world_inst); - if (src_slot_id == MainCursor) + if (src_slot_id == EQEmu::legacy::SlotCursor) { if (dstitemid == 0) { @@ -1658,15 +1659,15 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } // Step 4: Check for entity trade - if (dst_slot_id >= EmuConstants::TRADE_BEGIN && dst_slot_id <= EmuConstants::TRADE_END) { - if (src_slot_id != MainCursor) { + if (dst_slot_id >= EQEmu::legacy::TRADE_BEGIN && dst_slot_id <= EQEmu::legacy::TRADE_END) { + if (src_slot_id != EQEmu::legacy::SlotCursor) { Kick(); return false; } if (with) { Log.Out(Logs::Detail, Logs::Inventory, "Trade item move from slot %d to slot %d (trade with %s)", src_slot_id, dst_slot_id, with->GetName()); // Fill Trade list with items from cursor - if (!m_inv[MainCursor]) { + if (!m_inv[EQEmu::legacy::SlotCursor]) { Message(13, "Error: Cursor item not located on server!"); return false; } @@ -1686,7 +1687,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit SummonItem(src_inst->GetID(), src_inst->GetCharges()); - DeleteItemInInventory(MainCursor); + DeleteItemInInventory(EQEmu::legacy::SlotCursor); return true; } @@ -1751,12 +1752,12 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } else { // Not dealing with charges - just do direct swap - if(src_inst && (dst_slot_id <= EmuConstants::EQUIPMENT_END || dst_slot_id == MainPowerSource) && dst_slot_id >= EmuConstants::EQUIPMENT_BEGIN) { + if (src_inst && (dst_slot_id <= EQEmu::legacy::EQUIPMENT_END || dst_slot_id == EQEmu::legacy::SlotPowerSource) && dst_slot_id >= EQEmu::legacy::EQUIPMENT_BEGIN) { if (src_inst->GetItem()->Attuneable) { src_inst->SetAttuned(true); } if (src_inst->IsAugmented()) { - for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { if (src_inst->GetAugment(i)) { if (src_inst->GetAugment(i)->GetItem()->Attuneable) { src_inst->GetAugment(i)->SetAttuned(true); @@ -1769,7 +1770,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { if(!m_inv.SwapItem(src_slot_id, dst_slot_id)) { return false; } Log.Out(Logs::Detail, Logs::Inventory, "Moving entire item from slot %d to slot %d", src_slot_id, dst_slot_id); - if(src_slot_id <= EmuConstants::EQUIPMENT_END || src_slot_id == MainPowerSource) { + if (src_slot_id <= EQEmu::legacy::EQUIPMENT_END || src_slot_id == EQEmu::legacy::SlotPowerSource) { if(src_inst) { parse->EventItem(EVENT_UNEQUIP_ITEM, this, src_inst, nullptr, "", src_slot_id); } @@ -1779,7 +1780,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } } - if(dst_slot_id <= EmuConstants::EQUIPMENT_END || dst_slot_id == MainPowerSource) { + if (dst_slot_id <= EQEmu::legacy::EQUIPMENT_END || dst_slot_id == EQEmu::legacy::SlotPowerSource) { if(dst_inst) { parse->EventItem(EVENT_UNEQUIP_ITEM, this, dst_inst, nullptr, "", dst_slot_id); } @@ -1791,12 +1792,12 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } int matslot = SlotConvert2(dst_slot_id); - if (dst_slot_id <= EmuConstants::EQUIPMENT_END && matslot != MaterialHead) { // think this is to allow the client to update with /showhelm + if (dst_slot_id <= EQEmu::legacy::EQUIPMENT_END && matslot != EQEmu::textures::TextureHead) { // think this is to allow the client to update with /showhelm SendWearChange(matslot); } // Step 7: Save change to the database - if (src_slot_id == MainCursor) { + if (src_slot_id == EQEmu::legacy::SlotCursor) { // If not swapping another item to cursor and stacking items were depleted if (dstitemid == 0 || all_to_stack == true) { @@ -1809,7 +1810,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { database.SaveInventory(character_id, m_inv.GetItem(src_slot_id), src_slot_id); } - if (dst_slot_id == MainCursor) { + if (dst_slot_id == EQEmu::legacy::SlotCursor) { auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(character_id, s, e); } @@ -1833,18 +1834,18 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) { Log.Out(Logs::Detail, Logs::Inventory, "Inventory desyncronization. (charname: %s, source: %i, destination: %i)", GetName(), move_slots->from_slot, move_slots->to_slot); Message(15, "Inventory Desyncronization detected: Resending slot data..."); - if((move_slots->from_slot >= EmuConstants::EQUIPMENT_BEGIN && move_slots->from_slot <= EmuConstants::CURSOR_BAG_END) || move_slots->from_slot == MainPowerSource) { + if ((move_slots->from_slot >= EQEmu::legacy::EQUIPMENT_BEGIN && move_slots->from_slot <= EQEmu::legacy::CURSOR_BAG_END) || move_slots->from_slot == EQEmu::legacy::SlotPowerSource) { int16 resync_slot = (Inventory::CalcSlotId(move_slots->from_slot) == INVALID_INDEX) ? move_slots->from_slot : Inventory::CalcSlotId(move_slots->from_slot); if (IsValidSlot(resync_slot) && resync_slot != INVALID_INDEX) { // This prevents the client from crashing when closing any 'phantom' bags - const Item_Struct* token_struct = database.GetItem(22292); // 'Copper Coin' + const EQEmu::ItemBase* token_struct = database.GetItem(22292); // 'Copper Coin' ItemInst* token_inst = database.CreateItem(token_struct, 1); SendItemPacket(resync_slot, token_inst, ItemPacketTrade); if(m_inv[resync_slot]) { SendItemPacket(resync_slot, m_inv[resync_slot], ItemPacketTrade); } else { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct)); + auto outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct)); DeleteItem_Struct* delete_slot = (DeleteItem_Struct*)outapp->pBuffer; delete_slot->from_slot = resync_slot; delete_slot->to_slot = 0xFFFFFFFF; @@ -1862,7 +1863,7 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) { int16 resync_slot = (Inventory::CalcSlotId(move_slots->from_slot) == INVALID_INDEX) ? move_slots->from_slot : Inventory::CalcSlotId(move_slots->from_slot); if (IsValidSlot(resync_slot) && resync_slot != INVALID_INDEX) { if(m_inv[resync_slot]) { - const Item_Struct* token_struct = database.GetItem(22292); // 'Copper Coin' + const EQEmu::ItemBase* token_struct = database.GetItem(22292); // 'Copper Coin' ItemInst* token_inst = database.CreateItem(token_struct, 1); SendItemPacket(resync_slot, token_inst, ItemPacketTrade); @@ -1876,17 +1877,17 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) { else { Message(13, "Could not resyncronize source slot %i.", move_slots->from_slot); } } - if((move_slots->to_slot >= EmuConstants::EQUIPMENT_BEGIN && move_slots->to_slot <= EmuConstants::CURSOR_BAG_END) || move_slots->to_slot == MainPowerSource) { + if ((move_slots->to_slot >= EQEmu::legacy::EQUIPMENT_BEGIN && move_slots->to_slot <= EQEmu::legacy::CURSOR_BAG_END) || move_slots->to_slot == EQEmu::legacy::SlotPowerSource) { int16 resync_slot = (Inventory::CalcSlotId(move_slots->to_slot) == INVALID_INDEX) ? move_slots->to_slot : Inventory::CalcSlotId(move_slots->to_slot); if (IsValidSlot(resync_slot) && resync_slot != INVALID_INDEX) { - const Item_Struct* token_struct = database.GetItem(22292); // 'Copper Coin' + const EQEmu::ItemBase* token_struct = database.GetItem(22292); // 'Copper Coin' ItemInst* token_inst = database.CreateItem(token_struct, 1); SendItemPacket(resync_slot, token_inst, ItemPacketTrade); if(m_inv[resync_slot]) { SendItemPacket(resync_slot, m_inv[resync_slot], ItemPacketTrade); } else { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct)); + auto outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct)); DeleteItem_Struct* delete_slot = (DeleteItem_Struct*)outapp->pBuffer; delete_slot->from_slot = resync_slot; delete_slot->to_slot = 0xFFFFFFFF; @@ -1904,7 +1905,7 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) { int16 resync_slot = (Inventory::CalcSlotId(move_slots->to_slot) == INVALID_INDEX) ? move_slots->to_slot : Inventory::CalcSlotId(move_slots->to_slot); if (IsValidSlot(resync_slot) && resync_slot != INVALID_INDEX) { if(m_inv[resync_slot]) { - const Item_Struct* token_struct = database.GetItem(22292); // 'Copper Coin' + const EQEmu::ItemBase* token_struct = database.GetItem(22292); // 'Copper Coin' ItemInst* token_inst = database.CreateItem(token_struct, 1); SendItemPacket(resync_slot, token_inst, ItemPacketTrade); @@ -1931,7 +1932,8 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) { if(m_inv[from_slot_id]) { move_count += m_inv[from_slot_id]->GetTotalItemCount(); } if(to_slot_id != from_slot_id) { if(m_inv[to_slot_id]) { move_count += m_inv[to_slot_id]->GetTotalItemCount(); } } - ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogMoves, sizeof(QSPlayerLogMove_Struct) + (sizeof(QSMoveItems_Struct) * move_count)); + auto qspack = new ServerPacket(ServerOP_QSPlayerLogMoves, + sizeof(QSPlayerLogMove_Struct) + (sizeof(QSMoveItems_Struct) * move_count)); QSPlayerLogMove_Struct* qsaudit = (QSPlayerLogMove_Struct*)qspack->pBuffer; qsaudit->char_id = character_id; @@ -1956,8 +1958,8 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) { qsaudit->items[move_count].aug_4 = from_inst->GetAugmentItemID(4); qsaudit->items[move_count++].aug_5 = from_inst->GetAugmentItemID(5); - if(from_inst->IsType(ItemClassContainer)) { - for(uint8 bag_idx = SUB_BEGIN; bag_idx < from_inst->GetItem()->BagSlots; bag_idx++) { + if (from_inst->IsType(EQEmu::item::ItemClassBag)) { + for (uint8 bag_idx = SUB_INDEX_BEGIN; bag_idx < from_inst->GetItem()->BagSlots; bag_idx++) { const ItemInst* from_baginst = from_inst->GetItem(bag_idx); if(from_baginst) { @@ -1989,8 +1991,8 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) { qsaudit->items[move_count].aug_4 = to_inst->GetAugmentItemID(4); qsaudit->items[move_count++].aug_5 = to_inst->GetAugmentItemID(5); - if(to_inst->IsType(ItemClassContainer)) { - for(uint8 bag_idx = SUB_BEGIN; bag_idx < to_inst->GetItem()->BagSlots; bag_idx++) { + if (to_inst->IsType(EQEmu::item::ItemClassBag)) { + for (uint8 bag_idx = SUB_INDEX_BEGIN; bag_idx < to_inst->GetItem()->BagSlots; bag_idx++) { const ItemInst* to_baginst = to_inst->GetItem(bag_idx); if(to_baginst) { @@ -2017,31 +2019,28 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) { safe_delete(qspack); } -void Client::DyeArmor(DyeStruct* dye){ +void Client::DyeArmor(EQEmu::TintProfile* dye){ int16 slot=0; - for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_TINT_END; i++) { - if (m_pp.item_tint[i].RGB.Blue != dye->dye[i].RGB.Blue || - m_pp.item_tint[i].RGB.Red != dye->dye[i].RGB.Red || - m_pp.item_tint[i].RGB.Green != dye->dye[i].RGB.Green - ) { + for (int i = EQEmu::textures::TextureBegin; i <= EQEmu::textures::LastTintableTexture; i++) { + if ((m_pp.item_tint.Slot[i].Color & 0x00FFFFFF) != (dye->Slot[i].Color & 0x00FFFFFF)) { slot = m_inv.HasItem(32557, 1, invWherePersonal); if (slot != INVALID_INDEX){ DeleteItemInInventory(slot,1,true); uint8 slot2=SlotConvert(i); ItemInst* inst = this->m_inv.GetItem(slot2); if(inst){ - uint32 armor_color = ((uint32)dye->dye[i].RGB.Red << 16) | ((uint32)dye->dye[i].RGB.Green << 8) | ((uint32)dye->dye[i].RGB.Blue); + uint32 armor_color = ((uint32)dye->Slot[i].Red << 16) | ((uint32)dye->Slot[i].Green << 8) | ((uint32)dye->Slot[i].Blue); inst->SetColor(armor_color); database.SaveCharacterMaterialColor(this->CharacterID(), i, armor_color); database.SaveInventory(CharacterID(),inst,slot2); - if(dye->dye[i].RGB.UseTint) - m_pp.item_tint[i].RGB.UseTint = 0xFF; + if(dye->Slot[i].UseTint) + m_pp.item_tint.Slot[i].UseTint = 0xFF; else - m_pp.item_tint[i].RGB.UseTint=0x00; + m_pp.item_tint.Slot[i].UseTint=0x00; } - m_pp.item_tint[i].RGB.Blue=dye->dye[i].RGB.Blue; - m_pp.item_tint[i].RGB.Red=dye->dye[i].RGB.Red; - m_pp.item_tint[i].RGB.Green=dye->dye[i].RGB.Green; + m_pp.item_tint.Slot[i].Blue=dye->Slot[i].Blue; + m_pp.item_tint.Slot[i].Red=dye->Slot[i].Red; + m_pp.item_tint.Slot[i].Green=dye->Slot[i].Green; SendWearChange(i); } else{ @@ -2050,7 +2049,7 @@ void Client::DyeArmor(DyeStruct* dye){ } } } - EQApplicationPacket* outapp=new EQApplicationPacket(OP_Dye,0); + auto outapp = new EQApplicationPacket(OP_Dye, 0); QueuePacket(outapp); safe_delete(outapp); @@ -2058,10 +2057,10 @@ void Client::DyeArmor(DyeStruct* dye){ #if 0 bool Client::DecreaseByItemType(uint32 type, uint8 amt) { - const Item_Struct* TempItem = 0; + const ItemBase* TempItem = 0; ItemInst* ins; int x; - for(x=EmuConstants::POSSESSIONS_BEGIN; x <= EmuConstants::POSSESSIONS_END; x++) + for(x=EQEmu::legacy::POSSESSIONS_BEGIN; x <= EQEmu::legacy::POSSESSIONS_END; x++) { TempItem = 0; ins = GetInv().GetItem(x); @@ -2083,7 +2082,7 @@ bool Client::DecreaseByItemType(uint32 type, uint8 amt) { return true; } } - for(x=EmuConstants::GENERAL_BAGS_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++) + for(x=EQEmu::legacy::GENERAL_BAGS_BEGIN; x <= EQEmu::legacy::GENERAL_BAGS_END; x++) { TempItem = 0; ins = GetInv().GetItem(x); @@ -2110,14 +2109,14 @@ bool Client::DecreaseByItemType(uint32 type, uint8 amt) { #endif bool Client::DecreaseByID(uint32 type, uint8 amt) { - const Item_Struct* TempItem = nullptr; + const EQEmu::ItemBase* TempItem = nullptr; ItemInst* ins = nullptr; int x; int num = 0; - for(x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++) + for(x = EQEmu::legacy::EQUIPMENT_BEGIN; x <= EQEmu::legacy::GENERAL_BAGS_END; x++) { - if (x == MainCursor + 1) - x = EmuConstants::GENERAL_BAGS_BEGIN; + if (x == EQEmu::legacy::SlotCursor + 1) + x = EQEmu::legacy::GENERAL_BAGS_BEGIN; TempItem = nullptr; ins = GetInv().GetItem(x); if (ins) @@ -2131,10 +2130,10 @@ bool Client::DecreaseByID(uint32 type, uint8 amt) { } if (num < amt) return false; - for(x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++) // should this be CURSOR_BAG_END? + for(x = EQEmu::legacy::EQUIPMENT_BEGIN; x <= EQEmu::legacy::GENERAL_BAGS_END; x++) // should this be CURSOR_BAG_END? { - if (x == MainCursor + 1) - x = EmuConstants::GENERAL_BAGS_BEGIN; + if (x == EQEmu::legacy::SlotCursor + 1) + x = EQEmu::legacy::GENERAL_BAGS_BEGIN; TempItem = nullptr; ins = GetInv().GetItem(x); if (ins) @@ -2158,9 +2157,190 @@ bool Client::DecreaseByID(uint32 type, uint8 amt) { return true; } +static bool IsSummonedBagID(uint32 item_id) +{ + switch (item_id) { + case 17147: // "Spiritual Prismatic Pack" + case 17303: // "Spirit Pouch" + case 17304: // "Dimensional Pocket" + case 17305: // "Dimensional Hole" + case 17306: // "Glowing Backpack" + case 17307: // "Quiver of Marr" + case 17308: // "Bandoleer of Luclin" + case 17309: // "Pouch of Quellious" + case 17310: // "Phantom Satchel" + case 17510: // "Glowing Chest" + case 17900: // "Grandmaster's Satchel" + case 57260: // "Glowing Backpack" + case 57261: // "Pouch of Quellious" + case 57262: // "Phantom Satchel" + case 60224: // "Faded-Glyph Tablet" + case 95199: // "Beginner Artisan Satchel" + case 95200: // "Apprentice Artisan Satchel" + case 95201: // "Freshman Artisan Satchel" + case 95202: // "Journeyman Artisan Satchel" + case 95203: // "Expert Artisan Satchel" + case 95204: // "Master Artisan Satchel" + //case 96960: // "Artisan Satchel" - no 12-slot disenchanted bags + return true; + default: + return false; + } +} + +static uint32 GetDisenchantedBagID(uint8 bag_slots) +{ + switch (bag_slots) { + case 4: + return 77772; // "Small Disenchanted Backpack" + case 6: + return 77774; // "Disenchanted Backpack" + case 8: + return 77776; // "Large Disenchanted Backpack" + case 10: + return 77778; // "Huge Disenchanted Backpack" + default: + return 0; // no suitable conversions + } +} + +static bool CopyBagContents(ItemInst* new_bag, const ItemInst* old_bag) +{ + if (!new_bag || !old_bag) { return false; } + if (new_bag->GetItem()->BagSlots < old_bag->GetItem()->BagSlots) { return false; } + + // pre-check for size comparisons + for (auto bag_slot = 0; bag_slot < old_bag->GetItem()->BagSlots; ++bag_slot) { + if (!old_bag->GetItem(bag_slot)) { continue; } + if (old_bag->GetItem(bag_slot)->GetItem()->Size > new_bag->GetItem()->BagSize) { + Log.Out(Logs::General, Logs::Inventory, "Copy Bag Contents: Failure due to %s is larger than size capacity of %s (%i > %i)", + old_bag->GetItem(bag_slot)->GetItem()->Name, new_bag->GetItem()->Name, old_bag->GetItem(bag_slot)->GetItem()->Size, new_bag->GetItem()->BagSize); + return false; + } + } + + for (auto bag_slot = 0; bag_slot < old_bag->GetItem()->BagSlots; ++bag_slot) { + if (!old_bag->GetItem(bag_slot)) { continue; } + new_bag->PutItem(bag_slot, *(old_bag->GetItem(bag_slot))); + } + + return true; +} + +void Client::DisenchantSummonedBags(bool client_update) +{ + for (auto slot_id = EQEmu::legacy::GENERAL_BEGIN; slot_id <= EQEmu::legacy::GENERAL_END; ++slot_id) { + auto inst = m_inv[slot_id]; + if (!inst) { continue; } + if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; } + if (!inst->GetItem()->IsClassBag()) { continue; } + if (inst->GetTotalItemCount() == 1) { continue; } + + auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots); + if (!new_id) { continue; } + auto new_item = database.GetItem(new_id); + if (!new_item) { continue; } + auto new_inst = database.CreateBaseItem(new_item); + if (!new_inst) { continue; } + + if (CopyBagContents(new_inst, inst)) { + Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id); + PutItemInInventory(slot_id, *new_inst, client_update); + } + safe_delete(new_inst); + } + + for (auto slot_id = EQEmu::legacy::BANK_BEGIN; slot_id <= EQEmu::legacy::BANK_END; ++slot_id) { + auto inst = m_inv[slot_id]; + if (!inst) { continue; } + if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; } + if (!inst->GetItem()->IsClassBag()) { continue; } + if (inst->GetTotalItemCount() == 1) { continue; } + + auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots); + if (!new_id) { continue; } + auto new_item = database.GetItem(new_id); + if (!new_item) { continue; } + auto new_inst = database.CreateBaseItem(new_item); + if (!new_inst) { continue; } + + if (CopyBagContents(new_inst, inst)) { + Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id); + PutItemInInventory(slot_id, *new_inst, client_update); + } + safe_delete(new_inst); + } + + for (auto slot_id = EQEmu::legacy::SHARED_BANK_BEGIN; slot_id <= EQEmu::legacy::SHARED_BANK_END; ++slot_id) { + auto inst = m_inv[slot_id]; + if (!inst) { continue; } + if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; } + if (!inst->GetItem()->IsClassBag()) { continue; } + if (inst->GetTotalItemCount() == 1) { continue; } + + auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots); + if (!new_id) { continue; } + auto new_item = database.GetItem(new_id); + if (!new_item) { continue; } + auto new_inst = database.CreateBaseItem(new_item); + if (!new_inst) { continue; } + + if (CopyBagContents(new_inst, inst)) { + Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, slot_id); + PutItemInInventory(slot_id, *new_inst, client_update); + } + safe_delete(new_inst); + } + + while (!m_inv.CursorEmpty()) { + auto inst = m_inv[EQEmu::legacy::SlotCursor]; + if (!inst) { break; } + if (!IsSummonedBagID(inst->GetItem()->ID)) { break; } + if (!inst->GetItem()->IsClassBag()) { break; } + if (inst->GetTotalItemCount() == 1) { break; } + + auto new_id = GetDisenchantedBagID(inst->GetItem()->BagSlots); + if (!new_id) { break; } + auto new_item = database.GetItem(new_id); + if (!new_item) { break; } + auto new_inst = database.CreateBaseItem(new_item); + if (!new_inst) { break; } + + if (CopyBagContents(new_inst, inst)) { + Log.Out(Logs::General, Logs::Inventory, "Disenchant Summoned Bags: Replacing %s with %s in slot %i", inst->GetItem()->Name, new_inst->GetItem()->Name, EQEmu::legacy::SlotCursor); + std::list local; + local.push_front(new_inst); + m_inv.PopItem(EQEmu::legacy::SlotCursor); + safe_delete(inst); + + while (!m_inv.CursorEmpty()) { + auto limbo_inst = m_inv.PopItem(EQEmu::legacy::SlotCursor); + if (limbo_inst == nullptr) { continue; } + local.push_back(limbo_inst); + } + + for (auto iter = local.begin(); iter != local.end(); ++iter) { + auto cur_inst = *iter; + if (cur_inst == nullptr) { continue; } + m_inv.PushCursor(*cur_inst); + safe_delete(cur_inst); + } + local.clear(); + + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); + database.SaveCursor(this->CharacterID(), s, e); + } + else { + safe_delete(new_inst); // deletes disenchanted bag if not used + } + + break; + } +} + void Client::RemoveNoRent(bool client_update) { - for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::EQUIPMENT_BEGIN; slot_id <= EQEmu::legacy::EQUIPMENT_END; ++slot_id) { auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); @@ -2168,7 +2348,7 @@ void Client::RemoveNoRent(bool client_update) } } - for (auto slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::GENERAL_BEGIN; slot_id <= EQEmu::legacy::GENERAL_END; ++slot_id) { auto inst = m_inv[slot_id]; if (inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); @@ -2176,15 +2356,15 @@ void Client::RemoveNoRent(bool client_update) } } - if (m_inv[MainPowerSource]) { - auto inst = m_inv[MainPowerSource]; + if (m_inv[EQEmu::legacy::SlotPowerSource]) { + auto inst = m_inv[EQEmu::legacy::SlotPowerSource]; if (inst && !inst->GetItem()->NoRent) { - Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, MainPowerSource); - DeleteItemInInventory(MainPowerSource, 0, (GetClientVersion() >= ClientVersion::SoF) ? client_update : false); // Ti slot non-existent + Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, EQEmu::legacy::SlotPowerSource); + DeleteItemInInventory(EQEmu::legacy::SlotPowerSource, 0, (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) ? client_update : false); // Ti slot non-existent } } - for (auto slot_id = EmuConstants::GENERAL_BAGS_BEGIN; slot_id <= EmuConstants::CURSOR_BAG_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::GENERAL_BAGS_BEGIN; slot_id <= EQEmu::legacy::CURSOR_BAG_END; ++slot_id) { auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); @@ -2192,7 +2372,7 @@ void Client::RemoveNoRent(bool client_update) } } - for (auto slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::BANK_BEGIN; slot_id <= EQEmu::legacy::BANK_END; ++slot_id) { auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); @@ -2200,7 +2380,7 @@ void Client::RemoveNoRent(bool client_update) } } - for (auto slot_id = EmuConstants::BANK_BAGS_BEGIN; slot_id <= EmuConstants::BANK_BAGS_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::BANK_BAGS_BEGIN; slot_id <= EQEmu::legacy::BANK_BAGS_END; ++slot_id) { auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); @@ -2208,7 +2388,7 @@ void Client::RemoveNoRent(bool client_update) } } - for (auto slot_id = EmuConstants::SHARED_BANK_BEGIN; slot_id <= EmuConstants::SHARED_BANK_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::SHARED_BANK_BEGIN; slot_id <= EQEmu::legacy::SHARED_BANK_END; ++slot_id) { auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); @@ -2216,7 +2396,7 @@ void Client::RemoveNoRent(bool client_update) } } - for (auto slot_id = EmuConstants::SHARED_BANK_BAGS_BEGIN; slot_id <= EmuConstants::SHARED_BANK_BAGS_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::SHARED_BANK_BAGS_BEGIN; slot_id <= EQEmu::legacy::SHARED_BANK_BAGS_END; ++slot_id) { auto inst = m_inv[slot_id]; if(inst && !inst->GetItem()->NoRent) { Log.Out(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id); @@ -2228,7 +2408,7 @@ void Client::RemoveNoRent(bool client_update) std::list local; while (!m_inv.CursorEmpty()) { - auto inst = m_inv.PopItem(MainCursor); + auto inst = m_inv.PopItem(EQEmu::legacy::SlotCursor); if (inst == nullptr) { continue; } local.push_back(inst); } @@ -2254,7 +2434,7 @@ void Client::RemoveNoRent(bool client_update) // Two new methods to alleviate perpetual login desyncs void Client::RemoveDuplicateLore(bool client_update) { - for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::EQUIPMENT_BEGIN; slot_id <= EQEmu::legacy::EQUIPMENT_END; ++slot_id) { auto inst = m_inv.PopItem(slot_id); if (inst == nullptr) { continue; } if(CheckLoreConflict(inst->GetItem())) { @@ -2267,7 +2447,7 @@ void Client::RemoveDuplicateLore(bool client_update) safe_delete(inst); } - for (auto slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::GENERAL_BEGIN; slot_id <= EQEmu::legacy::GENERAL_END; ++slot_id) { auto inst = m_inv.PopItem(slot_id); if (inst == nullptr) { continue; } if (CheckLoreConflict(inst->GetItem())) { @@ -2280,21 +2460,21 @@ void Client::RemoveDuplicateLore(bool client_update) safe_delete(inst); } - if (m_inv[MainPowerSource]) { - auto inst = m_inv.PopItem(MainPowerSource); + if (m_inv[EQEmu::legacy::SlotPowerSource]) { + auto inst = m_inv.PopItem(EQEmu::legacy::SlotPowerSource); if (inst) { if (CheckLoreConflict(inst->GetItem())) { - Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, MainPowerSource); - database.SaveInventory(character_id, nullptr, MainPowerSource); + Log.Out(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, EQEmu::legacy::SlotPowerSource); + database.SaveInventory(character_id, nullptr, EQEmu::legacy::SlotPowerSource); } else { - m_inv.PutItem(MainPowerSource, *inst); + m_inv.PutItem(EQEmu::legacy::SlotPowerSource, *inst); } safe_delete(inst); } } - for (auto slot_id = EmuConstants::GENERAL_BAGS_BEGIN; slot_id <= EmuConstants::CURSOR_BAG_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::GENERAL_BAGS_BEGIN; slot_id <= EQEmu::legacy::CURSOR_BAG_END; ++slot_id) { auto inst = m_inv.PopItem(slot_id); if (inst == nullptr) { continue; } if(CheckLoreConflict(inst->GetItem())) { @@ -2307,7 +2487,7 @@ void Client::RemoveDuplicateLore(bool client_update) safe_delete(inst); } - for (auto slot_id = EmuConstants::BANK_BEGIN; slot_id <= EmuConstants::BANK_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::BANK_BEGIN; slot_id <= EQEmu::legacy::BANK_END; ++slot_id) { auto inst = m_inv.PopItem(slot_id); if (inst == nullptr) { continue; } if(CheckLoreConflict(inst->GetItem())) { @@ -2320,7 +2500,7 @@ void Client::RemoveDuplicateLore(bool client_update) safe_delete(inst); } - for (auto slot_id = EmuConstants::BANK_BAGS_BEGIN; slot_id <= EmuConstants::BANK_BAGS_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::BANK_BAGS_BEGIN; slot_id <= EQEmu::legacy::BANK_BAGS_END; ++slot_id) { auto inst = m_inv.PopItem(slot_id); if (inst == nullptr) { continue; } if(CheckLoreConflict(inst->GetItem())) { @@ -2340,7 +2520,7 @@ void Client::RemoveDuplicateLore(bool client_update) std::list local_2; while (!m_inv.CursorEmpty()) { - auto inst = m_inv.PopItem(MainCursor); + auto inst = m_inv.PopItem(EQEmu::legacy::SlotCursor); if (inst == nullptr) { continue; } local_1.push_back(inst); } @@ -2381,11 +2561,11 @@ void Client::RemoveDuplicateLore(bool client_update) void Client::MoveSlotNotAllowed(bool client_update) { - for (auto slot_id = EmuConstants::EQUIPMENT_BEGIN; slot_id <= EmuConstants::EQUIPMENT_END; ++slot_id) { + for (auto slot_id = EQEmu::legacy::EQUIPMENT_BEGIN; slot_id <= EQEmu::legacy::EQUIPMENT_END; ++slot_id) { if(m_inv[slot_id] && !m_inv[slot_id]->IsSlotAllowed(slot_id)) { auto inst = m_inv.PopItem(slot_id); - bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false; - int16 free_slot_id = m_inv.FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow); + bool is_arrow = (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow) ? true : false; + int16 free_slot_id = m_inv.FindFreeSlot(inst->IsClassBag(), true, inst->GetItem()->Size, is_arrow); Log.Out(Logs::Detail, Logs::Inventory, "Slot Assignment Error: Moving %s from slot %i to %i", inst->GetItem()->Name, slot_id, free_slot_id); PutItemInInventory(free_slot_id, *inst, client_update); database.SaveInventory(character_id, nullptr, slot_id); @@ -2393,13 +2573,13 @@ void Client::MoveSlotNotAllowed(bool client_update) } } - if (m_inv[MainPowerSource] && !m_inv[MainPowerSource]->IsSlotAllowed(MainPowerSource)) { - auto inst = m_inv.PopItem(MainPowerSource); - bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false; - int16 free_slot_id = m_inv.FindFreeSlot(inst->IsType(ItemClassContainer), true, inst->GetItem()->Size, is_arrow); - Log.Out(Logs::Detail, Logs::Inventory, "Slot Assignment Error: Moving %s from slot %i to %i", inst->GetItem()->Name, MainPowerSource, free_slot_id); - PutItemInInventory(free_slot_id, *inst, (GetClientVersion() >= ClientVersion::SoF) ? client_update : false); - database.SaveInventory(character_id, nullptr, MainPowerSource); + if (m_inv[EQEmu::legacy::SlotPowerSource] && !m_inv[EQEmu::legacy::SlotPowerSource]->IsSlotAllowed(EQEmu::legacy::SlotPowerSource)) { + auto inst = m_inv.PopItem(EQEmu::legacy::SlotPowerSource); + bool is_arrow = (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow) ? true : false; + int16 free_slot_id = m_inv.FindFreeSlot(inst->IsClassBag(), true, inst->GetItem()->Size, is_arrow); + Log.Out(Logs::Detail, Logs::Inventory, "Slot Assignment Error: Moving %s from slot %i to %i", inst->GetItem()->Name, EQEmu::legacy::SlotPowerSource, free_slot_id); + PutItemInInventory(free_slot_id, *inst, (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) ? client_update : false); + database.SaveInventory(character_id, nullptr, EQEmu::legacy::SlotPowerSource); safe_delete(inst); } @@ -2413,7 +2593,7 @@ uint32 Client::GetEquipment(uint8 material_slot) const int16 invslot; const ItemInst *item; - if(material_slot > EmuConstants::MATERIAL_END) + if(material_slot > EQEmu::textures::LastTexture) { return 0; } @@ -2437,7 +2617,7 @@ uint32 Client::GetEquipment(uint8 material_slot) const #if 0 int32 Client::GetEquipmentMaterial(uint8 material_slot) { - const Item_Struct *item; + const ItemBase *item; item = database.GetItem(GetEquipment(material_slot)); if(item != 0) @@ -2451,12 +2631,12 @@ int32 Client::GetEquipmentMaterial(uint8 material_slot) uint32 Client::GetEquipmentColor(uint8 material_slot) const { - if (material_slot > EmuConstants::MATERIAL_END) + if (material_slot > EQEmu::textures::LastTexture) return 0; - const Item_Struct *item = database.GetItem(GetEquipment(material_slot)); + const EQEmu::ItemBase *item = database.GetItem(GetEquipment(material_slot)); if(item != nullptr) - return ((m_pp.item_tint[material_slot].RGB.UseTint) ? m_pp.item_tint[material_slot].Color : item->Color); + return ((m_pp.item_tint.Slot[material_slot].UseTint) ? m_pp.item_tint.Slot[material_slot].Color : item->Color); return 0; } @@ -2517,13 +2697,13 @@ static int16 BandolierSlotToWeaponSlot(int BandolierSlot) switch (BandolierSlot) { case bandolierPrimary: - return MainPrimary; + return EQEmu::legacy::SlotPrimary; case bandolierSecondary: - return MainSecondary; + return EQEmu::legacy::SlotSecondary; case bandolierRange: - return MainRange; + return EQEmu::legacy::SlotRange; default: - return MainAmmo; + return EQEmu::legacy::SlotAmmo; } } @@ -2538,9 +2718,11 @@ void Client::CreateBandolier(const EQApplicationPacket *app) strcpy(m_pp.bandoliers[bs->Number].Name, bs->Name); const ItemInst* InvItem = nullptr; - const Item_Struct *BaseItem = nullptr; + const EQEmu::ItemBase *BaseItem = nullptr; int16 WeaponSlot = 0; + database.DeleteCharacterBandolier(this->CharacterID(), bs->Number); + for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) { WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot); InvItem = GetInv()[WeaponSlot]; @@ -2596,13 +2778,13 @@ void Client::SetBandolier(const EQApplicationPacket *app) // removed 'invWhereCursor' argument from above and implemented slots 30, 331-340 checks here if (slot == INVALID_INDEX) { - if (m_inv.GetItem(MainCursor)) { - if (m_inv.GetItem(MainCursor)->GetItem()->ID == m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID && - m_inv.GetItem(MainCursor)->GetCharges() >= 1) { // '> 0' the same, but this matches Inventory::_HasItem conditional check - slot = MainCursor; + if (m_inv.GetItem(EQEmu::legacy::SlotCursor)) { + if (m_inv.GetItem(EQEmu::legacy::SlotCursor)->GetItem()->ID == m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID && + m_inv.GetItem(EQEmu::legacy::SlotCursor)->GetCharges() >= 1) { // '> 0' the same, but this matches Inventory::_HasItem conditional check + slot = EQEmu::legacy::SlotCursor; } - else if (m_inv.GetItem(MainCursor)->GetItem()->ItemClass == 1) { - for(int16 CursorBagSlot = EmuConstants::CURSOR_BAG_BEGIN; CursorBagSlot <= EmuConstants::CURSOR_BAG_END; CursorBagSlot++) { + else if (m_inv.GetItem(EQEmu::legacy::SlotCursor)->GetItem()->ItemClass == 1) { + for(int16 CursorBagSlot = EQEmu::legacy::CURSOR_BAG_BEGIN; CursorBagSlot <= EQEmu::legacy::CURSOR_BAG_END; CursorBagSlot++) { if (m_inv.GetItem(CursorBagSlot)) { if (m_inv.GetItem(CursorBagSlot)->GetItem()->ID == m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID && m_inv.GetItem(CursorBagSlot)->GetCharges() >= 1) { // ditto @@ -2748,7 +2930,7 @@ bool Client::MoveItemToInventory(ItemInst *ItemToReturn, bool UpdateClient) { // if(ItemToReturn->IsStackable()) { - for (int16 i = EmuConstants::GENERAL_BEGIN; i <= MainCursor; i++) { // changed slot max to 30 from 29. client will stack into slot 30 (bags too) before moving. + for (int16 i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::SlotCursor; i++) { // changed slot max to 30 from 29. client will stack into slot 30 (bags too) before moving. ItemInst* InvItem = m_inv.GetItem(i); @@ -2772,14 +2954,14 @@ bool Client::MoveItemToInventory(ItemInst *ItemToReturn, bool UpdateClient) { } // If there is a bag in this slot, look inside it. // - if (InvItem && InvItem->IsType(ItemClassContainer)) { + if (InvItem && InvItem->IsClassBag()) { - int16 BaseSlotID = Inventory::CalcSlotId(i, SUB_BEGIN); + int16 BaseSlotID = Inventory::CalcSlotId(i, SUB_INDEX_BEGIN); uint8 BagSize=InvItem->GetItem()->BagSlots; uint8 BagSlot; - for (BagSlot = SUB_BEGIN; BagSlot < BagSize; BagSlot++) { + for (BagSlot = SUB_INDEX_BEGIN; BagSlot < BagSize; BagSlot++) { InvItem = m_inv.GetItem(BaseSlotID + BagSlot); if (InvItem && (InvItem->GetItem()->ID == ItemID) && (InvItem->GetCharges() < InvItem->GetItem()->StackSize)) { @@ -2807,7 +2989,7 @@ bool Client::MoveItemToInventory(ItemInst *ItemToReturn, bool UpdateClient) { // We have tried stacking items, now just try and find an empty slot. - for (int16 i = EmuConstants::GENERAL_BEGIN; i <= MainCursor; i++) { // changed slot max to 30 from 29. client will move into slot 30 (bags too) before pushing onto cursor. + for (int16 i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::SlotCursor; i++) { // changed slot max to 30 from 29. client will move into slot 30 (bags too) before pushing onto cursor. ItemInst* InvItem = m_inv.GetItem(i); @@ -2824,13 +3006,13 @@ bool Client::MoveItemToInventory(ItemInst *ItemToReturn, bool UpdateClient) { return true; } - if(InvItem->IsType(ItemClassContainer) && Inventory::CanItemFitInContainer(ItemToReturn->GetItem(), InvItem->GetItem())) { + if (InvItem->IsClassBag() && Inventory::CanItemFitInContainer(ItemToReturn->GetItem(), InvItem->GetItem())) { - int16 BaseSlotID = Inventory::CalcSlotId(i, SUB_BEGIN); + int16 BaseSlotID = Inventory::CalcSlotId(i, SUB_INDEX_BEGIN); uint8 BagSize=InvItem->GetItem()->BagSlots; - for (uint8 BagSlot = SUB_BEGIN; BagSlot < BagSize; BagSlot++) { + for (uint8 BagSlot = SUB_INDEX_BEGIN; BagSlot < BagSize; BagSlot++) { InvItem = m_inv.GetItem(BaseSlotID + BagSlot); @@ -2868,27 +3050,27 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool std::map instmap; // build reference map - for (int16 index = MAIN_BEGIN; index < EmuConstants::MAP_POSSESSIONS_SIZE; ++index) { + for (int16 index = SLOT_BEGIN; index < EQEmu::legacy::TYPE_POSSESSIONS_SIZE; ++index) { auto inst = m_inv[index]; if (inst == nullptr) { continue; } instmap[index] = inst; } - for (int16 index = EmuConstants::TRIBUTE_BEGIN; index <= EmuConstants::TRIBUTE_END; ++index) { + for (int16 index = EQEmu::legacy::TRIBUTE_BEGIN; index <= EQEmu::legacy::TRIBUTE_END; ++index) { auto inst = m_inv[index]; if (inst == nullptr) { continue; } instmap[index] = inst; } - for (int16 index = EmuConstants::BANK_BEGIN; index <= EmuConstants::BANK_END; ++index) { + for (int16 index = EQEmu::legacy::BANK_BEGIN; index <= EQEmu::legacy::BANK_END; ++index) { auto inst = m_inv[index]; if (inst == nullptr) { continue; } instmap[index] = inst; } - for (int16 index = EmuConstants::SHARED_BANK_BEGIN; index <= EmuConstants::SHARED_BANK_END; ++index) { + for (int16 index = EQEmu::legacy::SHARED_BANK_BEGIN; index <= EQEmu::legacy::SHARED_BANK_END; ++index) { auto inst = m_inv[index]; if (inst == nullptr) { continue; } instmap[index] = inst; } - for (int16 index = EmuConstants::TRADE_BEGIN; index <= EmuConstants::TRADE_END; ++index) { + for (int16 index = EQEmu::legacy::TRADE_BEGIN; index <= EQEmu::legacy::TRADE_END; ++index) { auto inst = m_inv[index]; if (inst == nullptr) { continue; } instmap[index] = inst; @@ -2896,27 +3078,27 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool auto tsobject = GetTradeskillObject(); if (tsobject != nullptr) { - for (int16 index = MAIN_BEGIN; index < EmuConstants::MAP_WORLD_SIZE; ++index) { + for (int16 index = SLOT_BEGIN; index < EQEmu::legacy::TYPE_WORLD_SIZE; ++index) { auto inst = tsobject->GetItem(index); if (inst == nullptr) { continue; } - instmap[EmuConstants::WORLD_BEGIN + index] = inst; + instmap[EQEmu::legacy::WORLD_BEGIN + index] = inst; } } int limbo = 0; for (auto cursor_itr = m_inv.cursor_cbegin(); cursor_itr != m_inv.cursor_cend(); ++cursor_itr, ++limbo) { - // m_inv.cursor_begin() is referenced as MainCursor in MapPossessions above + // m_inv.cursor_begin() is referenced as SlotCursor in MapPossessions above if (cursor_itr == m_inv.cursor_cbegin()) continue; instmap[8000 + limbo] = *cursor_itr; } - if (m_inv[MainPowerSource]) - instmap[MainPowerSource] = m_inv[MainPowerSource]; + if (m_inv[EQEmu::legacy::SlotPowerSource]) + instmap[EQEmu::legacy::SlotPowerSource] = m_inv[EQEmu::legacy::SlotPowerSource]; // call InterrogateInventory_ for error check - for (std::map::iterator instmap_itr = instmap.begin(); (instmap_itr != instmap.end()) && (!error); ++instmap_itr) { + for (auto instmap_itr = instmap.begin(); (instmap_itr != instmap.end()) && (!error); ++instmap_itr) { InterrogateInventory_(true, requester, instmap_itr->first, INVALID_INDEX, instmap_itr->second, nullptr, log, silent, error, 0); } @@ -2931,7 +3113,7 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool } // call InterrogateInventory_ for report - for (std::map::iterator instmap_itr = instmap.begin(); (instmap_itr != instmap.end()); ++instmap_itr) { + for (auto instmap_itr = instmap.begin(); (instmap_itr != instmap.end()); ++instmap_itr) { InterrogateInventory_(false, requester, instmap_itr->first, INVALID_INDEX, instmap_itr->second, nullptr, log, silent, error, 0); } @@ -2971,7 +3153,7 @@ void Client::InterrogateInventory_(bool errorcheck, Client* requester, int16 hea } else { if (inst) { - for (int16 sub = SUB_BEGIN; (sub < EmuConstants::ITEM_CONTAINER_SIZE) && (!error); ++sub) { // treat any ItemInst as having the max internal slots available + for (int16 sub = SUB_INDEX_BEGIN; (sub < EQEmu::legacy::ITEM_CONTAINER_SIZE) && (!error); ++sub) { // treat any ItemInst as having the max internal slots available if (inst->GetItem(sub)) InterrogateInventory_(true, requester, head, sub, inst->GetItem(sub), inst, log, silent, error, depth + 1); } @@ -3001,7 +3183,7 @@ void Client::InterrogateInventory_(bool errorcheck, Client* requester, int16 hea } if (inst) { - for (int16 sub = SUB_BEGIN; (sub < EmuConstants::ITEM_CONTAINER_SIZE); ++sub) { + for (int16 sub = SUB_INDEX_BEGIN; (sub < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++sub) { if (inst->GetItem(sub)) InterrogateInventory_(false, requester, head, sub, inst->GetItem(sub), inst, log, silent, error, depth + 1); } @@ -3016,11 +3198,11 @@ bool Client::InterrogateInventory_error(int16 head, int16 index, const ItemInst* // very basic error checking - can be elaborated upon if more in-depth testing is needed... if ( - (head >= EmuConstants::EQUIPMENT_BEGIN && head <= EmuConstants::EQUIPMENT_END) || - (head >= EmuConstants::TRIBUTE_BEGIN && head <= EmuConstants::TRIBUTE_END) || - (head >= EmuConstants::WORLD_BEGIN && head <= EmuConstants::WORLD_END) || + (head >= EQEmu::legacy::EQUIPMENT_BEGIN && head <= EQEmu::legacy::EQUIPMENT_END) || + (head >= EQEmu::legacy::TRIBUTE_BEGIN && head <= EQEmu::legacy::TRIBUTE_END) || + (head >= EQEmu::legacy::WORLD_BEGIN && head <= EQEmu::legacy::WORLD_END) || (head >= 8000 && head <= 8101) || - (head == MainPowerSource)) { + (head == EQEmu::legacy::SlotPowerSource)) { switch (depth) { case 0: // requirement: inst is extant @@ -3030,9 +3212,9 @@ bool Client::InterrogateInventory_error(int16 head, int16 index, const ItemInst* case 1: // requirement: parent is common and inst is augment if ((!parent) || (!inst)) return true; - if (!parent->IsType(ItemClassCommon)) + if (!parent->IsType(EQEmu::item::ItemClassCommon)) return true; - if (index >= EmuConstants::ITEM_COMMON_SIZE) + if (index >= EQEmu::legacy::ITEM_COMMON_SIZE) return true; break; default: // requirement: none (something bad happened...) @@ -3040,11 +3222,11 @@ bool Client::InterrogateInventory_error(int16 head, int16 index, const ItemInst* } } else if ( - (head >= EmuConstants::GENERAL_BEGIN && head <= EmuConstants::GENERAL_END) || - (head == MainCursor) || - (head >= EmuConstants::BANK_BEGIN && head <= EmuConstants::BANK_END) || - (head >= EmuConstants::SHARED_BANK_BEGIN && head <= EmuConstants::SHARED_BANK_END) || - (head >= EmuConstants::TRADE_BEGIN && head <= EmuConstants::TRADE_END)) { + (head >= EQEmu::legacy::GENERAL_BEGIN && head <= EQEmu::legacy::GENERAL_END) || + (head == EQEmu::legacy::SlotCursor) || + (head >= EQEmu::legacy::BANK_BEGIN && head <= EQEmu::legacy::BANK_END) || + (head >= EQEmu::legacy::SHARED_BANK_BEGIN && head <= EQEmu::legacy::SHARED_BANK_END) || + (head >= EQEmu::legacy::TRADE_BEGIN && head <= EQEmu::legacy::TRADE_END)) { switch (depth) { case 0: // requirement: inst is extant @@ -3054,28 +3236,28 @@ bool Client::InterrogateInventory_error(int16 head, int16 index, const ItemInst* case 1: // requirement: parent is common and inst is augment ..or.. parent is container and inst is extant if ((!parent) || (!inst)) return true; - if (parent->IsType(ItemClassContainer)) + if (parent->IsType(EQEmu::item::ItemClassBag)) break; - if (parent->IsType(ItemClassBook)) + if (parent->IsClassBook()) return true; - if (parent->IsType(ItemClassCommon)) { + if (parent->IsClassCommon()) { if (!(inst->GetItem()->AugType > 0)) return true; - if (index >= EmuConstants::ITEM_COMMON_SIZE) + if (index >= EQEmu::legacy::ITEM_COMMON_SIZE) return true; } break; case 2: // requirement: parent is common and inst is augment if ((!parent) || (!inst)) return true; - if (parent->IsType(ItemClassContainer)) + if (parent->IsType(EQEmu::item::ItemClassBag)) return true; - if (parent->IsType(ItemClassBook)) + if (parent->IsClassBook()) return true; - if (parent->IsType(ItemClassCommon)) { + if (parent->IsClassCommon()) { if (!(inst->GetItem()->AugType > 0)) return true; - if (index >= EmuConstants::ITEM_COMMON_SIZE) + if (index >= EQEmu::legacy::ITEM_COMMON_SIZE) return true; } break; diff --git a/zone/loottables.cpp b/zone/loottables.cpp index 0d392ec68..910331e27 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -58,7 +58,7 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite if(max_cash > 0 && lts->avgcoin > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) { float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash); float avg_cash_roll = (float)zone->random.Real(0.0, 1.0); - + if(avg_cash_roll < upper_chance) { cash = zone->random.Int(lts->avgcoin, max_cash); } else { @@ -119,8 +119,8 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml int charges = lds->Entries[i].multiplier; for(int j = 0; j < charges; ++j) { if(zone->random.Real(0.0, 100.0) <= lds->Entries[i].chance) { - const Item_Struct* dbitem = GetItem(lds->Entries[i].item_id); - npc->AddLootDrop(dbitem, itemlist, lds->Entries[i].item_charges, lds->Entries[i].minlevel, + const EQEmu::ItemBase* dbitem = GetItem(lds->Entries[i].item_id); + npc->AddLootDrop(dbitem, itemlist, lds->Entries[i].item_charges, lds->Entries[i].minlevel, lds->Entries[i].maxlevel, lds->Entries[i].equip_item > 0 ? true : false, false); } } @@ -137,27 +137,57 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml } float roll_t = 0.0f; + float roll_t_min = 0.0f; bool active_item_list = false; for(uint32 i = 0; i < lds->NumEntries; ++i) { - const Item_Struct* db_item = GetItem(lds->Entries[i].item_id); + const EQEmu::ItemBase* db_item = GetItem(lds->Entries[i].item_id); if(db_item) { roll_t += lds->Entries[i].chance; active_item_list = true; } } + roll_t_min = roll_t; roll_t = EQEmu::ClampLower(roll_t, 100.0f); if(!active_item_list) { return; } - mindrop = EQEmu::ClampLower(mindrop, (uint8)1); - int item_count = zone->random.Int(mindrop, droplimit); - for(int i = 0; i < item_count; ++i) { + for(int i = 0; i < mindrop; ++i) { + float roll = (float)zone->random.Real(0.0, roll_t_min); + for(uint32 j = 0; j < lds->NumEntries; ++j) { + const EQEmu::ItemBase* db_item = GetItem(lds->Entries[j].item_id); + if(db_item) { + if(roll < lds->Entries[j].chance) { + npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel, + lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false); + + int charges = (int)lds->Entries[i].multiplier; + charges = EQEmu::ClampLower(charges, 1); + + for(int k = 1; k < charges; ++k) { + float c_roll = (float)zone->random.Real(0.0, 100.0); + if(c_roll <= lds->Entries[i].chance) { + npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel, + lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false); + } + } + + j = lds->NumEntries; + break; + } + else { + roll -= lds->Entries[j].chance; + } + } + } + } + + for(int i = mindrop; i < droplimit; ++i) { float roll = (float)zone->random.Real(0.0, roll_t); for(uint32 j = 0; j < lds->NumEntries; ++j) { - const Item_Struct* db_item = GetItem(lds->Entries[j].item_id); + const EQEmu::ItemBase* db_item = GetItem(lds->Entries[j].item_id); if(db_item) { if(roll < lds->Entries[j].chance) { npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel, @@ -191,7 +221,7 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml } //if itemlist is null, just send wear changes -void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charges, uint8 minlevel, uint8 maxlevel, bool equipit, bool wearchange) { +void NPC::AddLootDrop(const EQEmu::ItemBase *item2, ItemList* itemlist, int16 charges, uint8 minlevel, uint8 maxlevel, bool equipit, bool wearchange) { if(item2 == nullptr) return; @@ -199,7 +229,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge if(!itemlist && !wearchange) return; - ServerLootItem_Struct* item = new ServerLootItem_Struct; + auto item = new ServerLootItem_Struct; #if EQDEBUG>=11 Log.Out(Logs::General, Logs::None, "Adding drop to npc: %s, Item: %i", GetName(), item2->ID); #endif @@ -228,7 +258,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge if (equipit) { uint8 eslot = 0xFF; char newid[20]; - const Item_Struct* compitem = nullptr; + const EQEmu::ItemBase* compitem = nullptr; bool found = false; // track if we found an empty slot we fit into int32 foundslot = -1; // for multi-slot items @@ -242,7 +272,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge // it is an improvement. if (!item2->NoPet) { - for (int i = 0; !found && iSlots & slots) { if(equipment[i]) @@ -283,7 +313,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge // @merth: IDFile size has been increased, this needs to change uint16 emat; if(item2->Material <= 0 - || item2->Slots & (1 << MainPrimary | 1 << MainSecondary)) { + || item2->Slots & (1 << EQEmu::legacy::SlotPrimary | 1 << EQEmu::legacy::SlotSecondary)) { memset(newid, 0, sizeof(newid)); for(int i=0;i<7;i++){ if (!isalpha(item2->IDFile[i])){ @@ -297,42 +327,47 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge emat = item2->Material; } - if (foundslot == MainPrimary) { + if (foundslot == EQEmu::legacy::SlotPrimary) { if (item2->Proc.Effect != 0) CastToMob()->AddProcToWeapon(item2->Proc.Effect, true); - eslot = MaterialPrimary; + eslot = EQEmu::textures::TexturePrimary; + if (item2->Damage > 0) + SendAddPlayerState(PlayerState::PrimaryWeaponEquipped); + if (item2->IsType2HWeapon()) + SetTwoHanderEquipped(true); } - else if (foundslot == MainSecondary - && (GetOwner() != nullptr || (GetLevel() >= 13 && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) && - (item2->ItemType == ItemType1HSlash || item2->ItemType == ItemType1HBlunt || item2->ItemType == ItemTypeShield || - item2->ItemType == ItemType1HPiercing)) + else if (foundslot == EQEmu::legacy::SlotSecondary + && (GetOwner() != nullptr || (CanThisClassDualWield() && zone->random.Roll(NPC_DW_CHANCE)) || (item2->Damage==0)) && + (item2->IsType1HWeapon() || item2->ItemType == EQEmu::item::ItemTypeShield)) { if (item2->Proc.Effect!=0) CastToMob()->AddProcToWeapon(item2->Proc.Effect, true); - eslot = MaterialSecondary; + eslot = EQEmu::textures::TextureSecondary; + if (item2->Damage > 0) + SendAddPlayerState(PlayerState::SecondaryWeaponEquipped); } - else if (foundslot == MainHead) { - eslot = MaterialHead; + else if (foundslot == EQEmu::legacy::SlotHead) { + eslot = EQEmu::textures::TextureHead; } - else if (foundslot == MainChest) { - eslot = MaterialChest; + else if (foundslot == EQEmu::legacy::SlotChest) { + eslot = EQEmu::textures::TextureChest; } - else if (foundslot == MainArms) { - eslot = MaterialArms; + else if (foundslot == EQEmu::legacy::SlotArms) { + eslot = EQEmu::textures::TextureArms; } - else if (foundslot == MainWrist1 || foundslot == MainWrist2) { - eslot = MaterialWrist; + else if (foundslot == EQEmu::legacy::SlotWrist1 || foundslot == EQEmu::legacy::SlotWrist2) { + eslot = EQEmu::textures::TextureWrist; } - else if (foundslot == MainHands) { - eslot = MaterialHands; + else if (foundslot == EQEmu::legacy::SlotHands) { + eslot = EQEmu::textures::TextureHands; } - else if (foundslot == MainLegs) { - eslot = MaterialLegs; + else if (foundslot == EQEmu::legacy::SlotLegs) { + eslot = EQEmu::textures::TextureLegs; } - else if (foundslot == MainFeet) { - eslot = MaterialFeet; + else if (foundslot == EQEmu::legacy::SlotFeet) { + eslot = EQEmu::textures::TextureFeet; } /* @@ -380,17 +415,17 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge SendAppearancePacket(AT_Light, GetActiveLightType()); } -void NPC::AddItem(const Item_Struct* item, uint16 charges, bool equipitem) { +void NPC::AddItem(const EQEmu::ItemBase* item, uint16 charges, bool equipitem) { //slot isnt needed, its determined from the item. - AddLootDrop(item, &itemlist, charges, 1, 127, equipitem, equipitem); + AddLootDrop(item, &itemlist, charges, 1, 255, equipitem, equipitem); } void NPC::AddItem(uint32 itemid, uint16 charges, bool equipitem) { //slot isnt needed, its determined from the item. - const Item_Struct * i = database.GetItem(itemid); + const EQEmu::ItemBase * i = database.GetItem(itemid); if(i == nullptr) return; - AddLootDrop(i, &itemlist, charges, 1, 127, equipitem, equipitem); + AddLootDrop(i, &itemlist, charges, 1, 255, equipitem, equipitem); } void NPC::AddLootTable() { diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index ac0ddcf99..6c2345856 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -232,27 +232,27 @@ void Lua_Client::SetBindPoint() { void Lua_Client::SetBindPoint(int to_zone) { Lua_Safe_Call_Void(); - self->SetBindPoint(to_zone); + self->SetBindPoint(0, to_zone); } void Lua_Client::SetBindPoint(int to_zone, int to_instance) { Lua_Safe_Call_Void(); - self->SetBindPoint(to_zone, to_instance); + self->SetBindPoint(0, to_zone, to_instance); } void Lua_Client::SetBindPoint(int to_zone, int to_instance, float new_x) { Lua_Safe_Call_Void(); - self->SetBindPoint(to_zone, to_instance, glm::vec3(new_x,0.0f,0.0f)); + self->SetBindPoint(0, to_zone, to_instance, glm::vec3(new_x,0.0f,0.0f)); } void Lua_Client::SetBindPoint(int to_zone, int to_instance, float new_x, float new_y) { Lua_Safe_Call_Void(); - self->SetBindPoint(to_zone, to_instance, glm::vec3(new_x, new_y, 0.0f)); + self->SetBindPoint(0, to_zone, to_instance, glm::vec3(new_x, new_y, 0.0f)); } void Lua_Client::SetBindPoint(int to_zone, int to_instance, float new_x, float new_y, float new_z) { Lua_Safe_Call_Void(); - self->SetBindPoint(to_zone, to_instance, glm::vec3(new_x, new_y, new_z)); + self->SetBindPoint(0, to_zone, to_instance, glm::vec3(new_x, new_y, new_z)); } float Lua_Client::GetBindX() { @@ -350,6 +350,11 @@ const char *Lua_Client::AccountName() { return self->AccountName(); } +int Lua_Client::GetAccountAge() { + Lua_Safe_Call_Int(); + return time(nullptr) - self->GetAccountCreation(); +} + int Lua_Client::Admin() { Lua_Safe_Call_Bool(); return self->Admin(); @@ -427,27 +432,27 @@ void Lua_Client::IncreaseLanguageSkill(int skill_id, int value) { int Lua_Client::GetRawSkill(int skill_id) { Lua_Safe_Call_Int(); - return self->GetRawSkill(static_cast(skill_id)); + return self->GetRawSkill(static_cast(skill_id)); } bool Lua_Client::HasSkill(int skill_id) { Lua_Safe_Call_Bool(); - return self->HasSkill(static_cast(skill_id)); + return self->HasSkill(static_cast(skill_id)); } bool Lua_Client::CanHaveSkill(int skill_id) { Lua_Safe_Call_Bool(); - return self->CanHaveSkill(static_cast(skill_id)); + return self->CanHaveSkill(static_cast(skill_id)); } void Lua_Client::SetSkill(int skill_id, int value) { Lua_Safe_Call_Void(); - self->SetSkill(static_cast(skill_id), value); + self->SetSkill(static_cast(skill_id), value); } void Lua_Client::AddSkill(int skill_id, int value) { Lua_Safe_Call_Void(); - self->AddSkill(static_cast(skill_id), value); + self->AddSkill(static_cast(skill_id), value); } void Lua_Client::CheckSpecializeIncrease(int spell_id) { @@ -457,12 +462,12 @@ void Lua_Client::CheckSpecializeIncrease(int spell_id) { void Lua_Client::CheckIncreaseSkill(int skill_id, Lua_Mob target) { Lua_Safe_Call_Void(); - self->CheckIncreaseSkill(static_cast(skill_id), target); + self->CheckIncreaseSkill(static_cast(skill_id), target); } void Lua_Client::CheckIncreaseSkill(int skill_id, Lua_Mob target, int chance_mod) { Lua_Safe_Call_Void(); - self->CheckIncreaseSkill(static_cast(skill_id), target, chance_mod); + self->CheckIncreaseSkill(static_cast(skill_id), target, chance_mod); } void Lua_Client::SetLanguageSkill(int language, int value) { @@ -472,7 +477,7 @@ void Lua_Client::SetLanguageSkill(int language, int value) { int Lua_Client::MaxSkill(int skill_id) { Lua_Safe_Call_Int(); - return self->MaxSkill(static_cast(skill_id)); + return self->MaxSkill(static_cast(skill_id)); } bool Lua_Client::IsMedding() { @@ -525,6 +530,11 @@ void Lua_Client::UnmemSpell(int slot, bool update_client) { self->UnmemSpell(slot, update_client); } +void Lua_Client::UnmemSpellBySpellID(int32 spell_id) { + Lua_Safe_Call_Void(); + self->UnmemSpellBySpellID(spell_id); +} + void Lua_Client::UnmemSpellAll() { Lua_Safe_Call_Void(); self->UnmemSpellAll(); @@ -570,6 +580,16 @@ void Lua_Client::TrainDisc(int itemid) { self->TrainDiscipline(itemid); } +void Lua_Client::TrainDiscBySpellID(int32 spell_id) { + Lua_Safe_Call_Void(); + self->TrainDiscBySpellID(spell_id); +} + +int Lua_Client::GetDiscSlotBySpellID(int32 spell_id) { + Lua_Safe_Call_Int(); + return self->GetDiscSlotBySpellID(spell_id); +} + void Lua_Client::UntrainDisc(int slot) { Lua_Safe_Call_Void(); self->UntrainDisc(slot); @@ -834,12 +854,12 @@ void Lua_Client::SetAATitle(const char *title) { int Lua_Client::GetClientVersion() { Lua_Safe_Call_Int(); - return static_cast(self->GetClientVersion()); + return static_cast(self->ClientVersion()); } uint32 Lua_Client::GetClientVersionBit() { Lua_Safe_Call_Int(); - return self->GetClientVersionBit(); + return self->ClientVersionBit(); } void Lua_Client::SetTitleSuffix(const char *text) { @@ -1024,7 +1044,17 @@ void Lua_Client::AddLevelBasedExp(int exp_pct, int max_level) { void Lua_Client::IncrementAA(int aa) { Lua_Safe_Call_Void(); - self->IncrementAA(aa); + self->IncrementAlternateAdvancementRank(aa); +} + +bool Lua_Client::GrantAlternateAdvancementAbility(int aa_id, int points) { + Lua_Safe_Call_Bool(); + return self->GrantAlternateAdvancementAbility(aa_id, points); +} + +bool Lua_Client::GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore_cost) { + Lua_Safe_Call_Bool(); + return self->GrantAlternateAdvancementAbility(aa_id, points, ignore_cost); } void Lua_Client::MarkSingleCompassLoc(float in_x, float in_y, float in_z) { @@ -1037,6 +1067,11 @@ void Lua_Client::MarkSingleCompassLoc(float in_x, float in_y, float in_z, int co self->MarkSingleCompassLoc(in_x, in_y, in_z, count); } +void Lua_Client::ClearCompassMark() { + Lua_Safe_Call_Void(); + self->MarkSingleCompassLoc(0,0,0,0); +} + int Lua_Client::GetNextAvailableSpellBookSlot() { Lua_Safe_Call_Int(); return self->GetNextAvailableSpellBookSlot(); @@ -1062,6 +1097,11 @@ void Lua_Client::AssignTask(int task, int npc_id) { self->AssignTask(task, npc_id); } +void Lua_Client::AssignTask(int task, int npc_id, bool enforce_level_requirement) { + Lua_Safe_Call_Void(); + self->AssignTask(task, npc_id, enforce_level_requirement); +} + void Lua_Client::FailTask(int task) { Lua_Safe_Call_Void(); self->FailTask(task); @@ -1255,6 +1295,51 @@ void Lua_Client::PlayMP3(std::string file) self->PlayMP3(file.c_str()); } +void Lua_Client::QuestReward(Lua_Mob target) { + Lua_Safe_Call_Void(); + self->QuestReward(target); +} + +void Lua_Client::QuestReward(Lua_Mob target, uint32 copper) { + Lua_Safe_Call_Void(); + self->QuestReward(target, copper); +} + +void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver) { + Lua_Safe_Call_Void(); + self->QuestReward(target, copper, silver); +} + +void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold) { + Lua_Safe_Call_Void(); + self->QuestReward(target, copper, silver, gold); +} + +void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum) { + Lua_Safe_Call_Void(); + self->QuestReward(target, copper, silver, gold, platinum); +} + +void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid) { + Lua_Safe_Call_Void(); + self->QuestReward(target, copper, silver, gold, platinum, itemid); +} + +void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp) { + Lua_Safe_Call_Void(); + self->QuestReward(target, copper, silver, gold, platinum, itemid, exp); +} + +void Lua_Client::QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction) { + Lua_Safe_Call_Void(); + self->QuestReward(target, copper, silver, gold, platinum, itemid, exp, faction); +} + +uint32 Lua_Client::GetMoney(uint8 type, uint8 subtype) { + Lua_Safe_Call_Int(); + return self->GetMoney(type, subtype); +} + luabind::scope lua_register_client() { return luabind::class_("Client") .def(luabind::constructor<>()) @@ -1325,6 +1410,7 @@ luabind::scope lua_register_client() { .def("GetRawItemAC", (int(Lua_Client::*)(void))&Lua_Client::GetRawItemAC) .def("AccountID", (uint32(Lua_Client::*)(void))&Lua_Client::AccountID) .def("AccountName", (const char *(Lua_Client::*)(void))&Lua_Client::AccountName) + .def("GetAccountAge", (int(Lua_Client::*)(void))&Lua_Client::GetAccountAge) .def("Admin", (int(Lua_Client::*)(void))&Lua_Client::Admin) .def("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID) .def("GuildRank", (int(Lua_Client::*)(void))&Lua_Client::GuildRank) @@ -1360,6 +1446,7 @@ luabind::scope lua_register_client() { .def("MemSpell", (void(Lua_Client::*)(int,int,bool))&Lua_Client::MemSpell) .def("UnmemSpell", (void(Lua_Client::*)(int))&Lua_Client::UnmemSpell) .def("UnmemSpell", (void(Lua_Client::*)(int,bool))&Lua_Client::UnmemSpell) + .def("UnmemSpellBySpellID", (void(Lua_Client::*)(int32))&Lua_Client::UnmemSpellBySpellID) .def("UnmemSpellAll", (void(Lua_Client::*)(void))&Lua_Client::UnmemSpellAll) .def("UnmemSpellAll", (void(Lua_Client::*)(bool))&Lua_Client::UnmemSpellAll) .def("ScribeSpell", (void(Lua_Client::*)(int,int))&Lua_Client::ScribeSpell) @@ -1369,6 +1456,8 @@ luabind::scope lua_register_client() { .def("UnscribeSpellAll", (void(Lua_Client::*)(void))&Lua_Client::UnscribeSpellAll) .def("UnscribeSpellAll", (void(Lua_Client::*)(bool))&Lua_Client::UnscribeSpellAll) .def("TrainDisc", (void(Lua_Client::*)(int))&Lua_Client::TrainDisc) + .def("TrainDiscBySpellID", (void(Lua_Client::*)(int32))&Lua_Client::TrainDiscBySpellID) + .def("GetDiscSlotBySpellID", (int(Lua_Client::*)(int32))&Lua_Client::GetDiscSlotBySpellID) .def("UntrainDisc", (void(Lua_Client::*)(int))&Lua_Client::UntrainDisc) .def("UntrainDisc", (void(Lua_Client::*)(int,bool))&Lua_Client::UntrainDisc) .def("UntrainDiscAll", (void(Lua_Client::*)(void))&Lua_Client::UntrainDiscAll) @@ -1460,13 +1549,17 @@ luabind::scope lua_register_client() { .def("AddLevelBasedExp", (void(Lua_Client::*)(int))&Lua_Client::AddLevelBasedExp) .def("AddLevelBasedExp", (void(Lua_Client::*)(int,int))&Lua_Client::AddLevelBasedExp) .def("IncrementAA", (void(Lua_Client::*)(int))&Lua_Client::IncrementAA) + .def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int))&Lua_Client::GrantAlternateAdvancementAbility) + .def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int, bool))&Lua_Client::GrantAlternateAdvancementAbility) .def("MarkSingleCompassLoc", (void(Lua_Client::*)(float,float,float))&Lua_Client::MarkSingleCompassLoc) .def("MarkSingleCompassLoc", (void(Lua_Client::*)(float,float,float,int))&Lua_Client::MarkSingleCompassLoc) + .def("ClearCompassMark",(void(Lua_Client::*)(void))&Lua_Client::ClearCompassMark) .def("GetNextAvailableSpellBookSlot", (int(Lua_Client::*)(void))&Lua_Client::GetNextAvailableSpellBookSlot) .def("GetNextAvailableSpellBookSlot", (int(Lua_Client::*)(int))&Lua_Client::GetNextAvailableSpellBookSlot) .def("FindSpellBookSlotBySpellID", (int(Lua_Client::*)(int))&Lua_Client::FindSpellBookSlotBySpellID) .def("UpdateTaskActivity", (void(Lua_Client::*)(int,int,int))&Lua_Client::UpdateTaskActivity) .def("AssignTask", (void(Lua_Client::*)(int,int))&Lua_Client::AssignTask) + .def("AssignTask", (void(Lua_Client::*)(int,int,bool))&Lua_Client::AssignTask) .def("FailTask", (void(Lua_Client::*)(int))&Lua_Client::FailTask) .def("IsTaskCompleted", (bool(Lua_Client::*)(int))&Lua_Client::IsTaskCompleted) .def("IsTaskActive", (bool(Lua_Client::*)(int))&Lua_Client::IsTaskActive) @@ -1504,7 +1597,16 @@ luabind::scope lua_register_client() { .def("SetConsumption", (void(Lua_Client::*)(int, int))&Lua_Client::SetConsumption) .def("SendMarqueeMessage", (void(Lua_Client::*)(uint32, uint32, uint32, uint32, uint32, std::string))&Lua_Client::SendMarqueeMessage) .def("SendColoredText", (void(Lua_Client::*)(uint32, std::string))&Lua_Client::SendColoredText) - .def("PlayMP3", (void(Lua_Client::*)(std::string))&Lua_Client::PlayMP3); + .def("PlayMP3", (void(Lua_Client::*)(std::string))&Lua_Client::PlayMP3) + .def("QuestReward", (void(Lua_Client::*)(Lua_Mob))&Lua_Client::QuestReward) + .def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32))&Lua_Client::QuestReward) + .def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32))&Lua_Client::QuestReward) + .def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32))&Lua_Client::QuestReward) + .def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward) + .def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward) + .def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32))&Lua_Client::QuestReward) + .def("QuestReward", (void(Lua_Client::*)(Lua_Mob, uint32, uint32, uint32, uint32, uint32, uint32, bool))&Lua_Client::QuestReward) + .def("GetMoney", (uint32(Lua_Client::*)(uint8, uint8))&Lua_Client::GetMoney); } luabind::scope lua_register_inventory_where() { diff --git a/zone/lua_client.h b/zone/lua_client.h index e2b0a6614..36ea2b8a4 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -131,6 +131,7 @@ public: void MemSpell(int spell_id, int slot, bool update_client); void UnmemSpell(int slot); void UnmemSpell(int slot, bool update_client); + void UnmemSpellBySpellID(int32 spell_id); void UnmemSpellAll(); void UnmemSpellAll(bool update_client); void ScribeSpell(int spell_id, int slot); @@ -140,6 +141,8 @@ public: void UnscribeSpellAll(); void UnscribeSpellAll(bool update_client); void TrainDisc(int itemid); + void TrainDiscBySpellID(int32 spell_id); + int GetDiscSlotBySpellID(int32 spell_id); void UntrainDisc(int slot); void UntrainDisc(int slot, bool update_client); void UntrainDiscAll(); @@ -166,9 +169,9 @@ public: void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3); void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4); void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5); - void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, + void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned); - void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, + void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned, int to_slot); void SetStats(int type, int value); void IncStats(int type, int value); @@ -233,13 +236,17 @@ public: void AddLevelBasedExp(int exp_pct); void AddLevelBasedExp(int exp_pct, int max_level); void IncrementAA(int aa); + bool GrantAlternateAdvancementAbility(int aa_id, int points); + bool GrantAlternateAdvancementAbility(int aa_id, int points, bool ignore_cost); void MarkSingleCompassLoc(float in_x, float in_y, float in_z); void MarkSingleCompassLoc(float in_x, float in_y, float in_z, int count); + void ClearCompassMark(); int GetNextAvailableSpellBookSlot(); int GetNextAvailableSpellBookSlot(int start); int FindSpellBookSlotBySpellID(int spell_id); void UpdateTaskActivity(int task, int activity, int count); void AssignTask(int task, int npc_id); + void AssignTask(int task, int npc_id, bool enforce_level_requirement); void FailTask(int task); bool IsTaskCompleted(int task); bool IsTaskActive(int task); @@ -253,6 +260,7 @@ public: int GetAggroCount(); uint64 GetCarriedMoney(); uint64 GetAllMoney(); + uint32 GetMoney(uint8 type, uint8 subtype); void OpenLFGuildWindow(); void Signal(uint32 id); void AddAlternateCurrencyValue(uint32 currency, int amount); @@ -260,6 +268,7 @@ public: bool HasSpellScribed(int spell_id); void SetAccountFlag(std::string flag, std::string val); std::string GetAccountFlag(std::string flag); + int GetAccountAge(); Lua_Group GetGroup(); Lua_Raid GetRaid(); bool PutItemInInventory(int slot_id, Lua_ItemInst inst); @@ -278,6 +287,14 @@ public: void SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, std::string msg); void SendColoredText(uint32 type, std::string msg); void PlayMP3(std::string file); + void QuestReward(Lua_Mob target); + void QuestReward(Lua_Mob target, uint32 copper); + void QuestReward(Lua_Mob target, uint32 copper, uint32 silver); + void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold); + void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum); + void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid); + void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp); + void QuestReward(Lua_Mob target, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, uint32 itemid, uint32 exp, bool faction); }; #endif diff --git a/zone/lua_encounter.cpp b/zone/lua_encounter.cpp new file mode 100644 index 000000000..08a4f95d3 --- /dev/null +++ b/zone/lua_encounter.cpp @@ -0,0 +1,13 @@ +#ifdef LUA_EQEMU + +#include "lua.hpp" +#include +#include "lua_encounter.h" +#include "encounter.h" + + +luabind::scope lua_register_encounter() { + return luabind::class_("Encounter"); +} + +#endif \ No newline at end of file diff --git a/zone/lua_encounter.h b/zone/lua_encounter.h new file mode 100644 index 000000000..f3d4598f7 --- /dev/null +++ b/zone/lua_encounter.h @@ -0,0 +1,32 @@ +#ifndef EQEMU_LUA_ENCOUNTER_H +#define EQEMU_LUA_ENCOUNTER_H +#ifdef LUA_EQEMU + +#include "lua_ptr.h" + +class Encounter; + +namespace luabind { + struct scope; + namespace adl { + class object; + } +} + +luabind::scope lua_register_encounter(); + +class Lua_Encounter : public Lua_Ptr +{ + typedef Encounter NativeType; +public: + Lua_Encounter() { SetLuaPtrData(nullptr); } + Lua_Encounter(Encounter *d) { SetLuaPtrData(reinterpret_cast(d)); } + virtual ~Lua_Encounter() { } + + operator Encounter*() { + return reinterpret_cast(GetLuaPtrData()); + } + +}; +#endif +#endif diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 50afdb6e9..d47420fe1 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -18,6 +18,8 @@ #include "qglobals.h" #include "../common/timer.h" #include "../common/eqemu_logsys.h" +#include "encounter.h" +#include "lua_encounter.h" struct Events { }; struct Factions { }; @@ -34,6 +36,8 @@ struct lua_registered_event { extern std::map> lua_encounter_events_registered; extern std::map lua_encounters_loaded; +extern std::map lua_encounters; + extern void MapOpcodes(); extern void ClearMappedOpcode(EmuOpcode op); @@ -42,19 +46,23 @@ void unregister_event(std::string package_name, std::string name, int evt); void load_encounter(std::string name) { if(lua_encounters_loaded.count(name) > 0) return; - + auto enc = new Encounter(name.c_str()); + entity_list.AddEncounter(enc); + lua_encounters[name] = enc; lua_encounters_loaded[name] = true; - parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, 0); + parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, "", 0); } void load_encounter_with_data(std::string name, std::string info_str) { if(lua_encounters_loaded.count(name) > 0) return; - + auto enc = new Encounter(name.c_str()); + entity_list.AddEncounter(enc); + lua_encounters[name] = enc; lua_encounters_loaded[name] = true; std::vector info_ptrs; info_ptrs.push_back(&info_str); - parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, 0, &info_ptrs); + parse->EventEncounter(EVENT_ENCOUNTER_LOAD, name, "", 0, &info_ptrs); } void unload_encounter(std::string name) { @@ -80,8 +88,10 @@ void unload_encounter(std::string name) { } } + lua_encounters[name]->Depop(); + lua_encounters.erase(name); lua_encounters_loaded.erase(name); - parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0); + parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, "", 0); } void unload_encounter_with_data(std::string name, std::string info_str) { @@ -109,10 +119,12 @@ void unload_encounter_with_data(std::string name, std::string info_str) { } } + lua_encounters[name]->Depop(); + lua_encounters.erase(name); lua_encounters_loaded.erase(name); std::vector info_ptrs; info_ptrs.push_back(&info_str); - parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0, &info_ptrs); + parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, "", 0, &info_ptrs); } void register_event(std::string package_name, std::string name, int evt, luabind::adl::object func) { @@ -285,6 +297,10 @@ void lua_set_timer(const char *timer, int time_ms, Lua_Mob mob) { quest_manager.settimerMS(timer, time_ms, mob); } +void lua_set_timer(const char *timer, int time_ms, Lua_Encounter enc) { + quest_manager.settimerMS(timer, time_ms, enc); +} + void lua_stop_timer(const char *timer) { quest_manager.stoptimer(timer); } @@ -297,6 +313,10 @@ void lua_stop_timer(const char *timer, Lua_Mob mob) { quest_manager.stoptimer(timer, mob); } +void lua_stop_timer(const char *timer, Lua_Encounter enc) { + quest_manager.stoptimer(timer, enc); +} + void lua_stop_all_timers() { quest_manager.stopalltimers(); } @@ -309,6 +329,10 @@ void lua_stop_all_timers(Lua_Mob mob) { quest_manager.stopalltimers(mob); } +void lua_stop_all_timers(Lua_Encounter enc) { + quest_manager.stopalltimers(enc); +} + void lua_depop() { quest_manager.depop(0); } @@ -386,7 +410,11 @@ void lua_create_guild(const char *name, const char *leader) { } void lua_set_time(int hour, int min) { - quest_manager.settime(hour, min); + quest_manager.settime(hour, min, true); +} + +void lua_set_time(int hour, int min, bool update_world) { + quest_manager.settime(hour, min, update_world); } void lua_signal(int npc_id, int signal_id) { @@ -485,16 +513,16 @@ void lua_toggle_spawn_event(int event_id, bool enable, bool strict, bool reset) quest_manager.toggle_spawn_event(event_id, enable, strict, reset); } -void lua_summon_burried_player_corpse(uint32 char_id, float x, float y, float z, float h) { - quest_manager.summonburriedplayercorpse(char_id, glm::vec4(x, y, z, h)); +void lua_summon_buried_player_corpse(uint32 char_id, float x, float y, float z, float h) { + quest_manager.summonburiedplayercorpse(char_id, glm::vec4(x, y, z, h)); } void lua_summon_all_player_corpses(uint32 char_id, float x, float y, float z, float h) { quest_manager.summonallplayercorpses(char_id, glm::vec4(x, y, z, h)); } -int lua_get_player_burried_corpse_count(uint32 char_id) { - return quest_manager.getplayerburriedcorpsecount(char_id); +int lua_get_player_buried_corpse_count(uint32 char_id) { + return quest_manager.getplayerburiedcorpsecount(char_id); } bool lua_bury_player_corpse(uint32 char_id) { @@ -776,6 +804,18 @@ void lua_destroy_instance(uint32 instance_id) { quest_manager.DestroyInstance(instance_id); } +void lua_update_instance_timer(uint16 instance_id, uint32 new_duration) { + quest_manager.UpdateInstanceTimer(instance_id, new_duration); +} + +uint32 lua_get_instance_timer() { + return quest_manager.GetInstanceTimer(); +} + +uint32 lua_get_instance_timer_by_id(uint16 instance_id) { + return quest_manager.GetInstanceTimerByID(instance_id); +} + int lua_get_instance_id(const char *zone, uint32 version) { return quest_manager.GetInstanceID(zone, version); } @@ -979,7 +1019,7 @@ int lua_get_zone_weather() { luabind::adl::object lua_get_zone_time(lua_State *L) { TimeOfDay_Struct eqTime; - zone->zone_time.getEQTimeOfDay(time(0), &eqTime); + zone->zone_time.GetCurrentEQTimeOfDay(time(0), &eqTime); luabind::adl::object ret = luabind::newtable(L); ret["zone_hour"] = eqTime.hour - 1; @@ -1176,8 +1216,8 @@ void lua_add_spawn_point(luabind::adl::object table) { lua_remove_spawn_point(spawn2_id); - Spawn2 *t = new Spawn2(spawn2_id, spawngroup_id, x, y, z, heading, respawn, variance, timeleft, grid, condition_id, - condition_min_value, enabled, static_cast(animation)); + auto t = new Spawn2(spawn2_id, spawngroup_id, x, y, z, heading, respawn, variance, timeleft, grid, + condition_id, condition_min_value, enabled, static_cast(animation)); zone->spawn2_list.Insert(t); } } @@ -1242,6 +1282,10 @@ void lua_clear_npctype_cache(int npctype_id) { quest_manager.ClearNPCTypeCache(npctype_id); } +void lua_reloadzonestaticdata() { + quest_manager.ReloadZoneStaticData(); +} + double lua_clock() { timeval read_time; gettimeofday(&read_time, nullptr); @@ -1260,6 +1304,10 @@ void lua_debug(std::string message, int level) { Log.Out(static_cast(level), Logs::QuestDebug, message); } +void lua_update_zone_header(std::string type, std::string value) { + quest_manager.UpdateZoneHeader(type, value); +} + #define LuaCreateNPCParse(name, c_type, default_value) do { \ cur = table[#name]; \ if(luabind::type(cur) != LUA_TNIL) { \ @@ -1296,7 +1344,7 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float return; } - NPCType* npc_type = new NPCType; + auto npc_type = new NPCType; memset(npc_type, 0, sizeof(NPCType)); @@ -1352,15 +1400,15 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float LuaCreateNPCParse(drakkin_heritage, uint32, 0); LuaCreateNPCParse(drakkin_tattoo, uint32, 0); LuaCreateNPCParse(drakkin_details, uint32, 0); - LuaCreateNPCParse(armor_tint[0], uint32, 0); - LuaCreateNPCParse(armor_tint[1], uint32, 0); - LuaCreateNPCParse(armor_tint[2], uint32, 0); - LuaCreateNPCParse(armor_tint[3], uint32, 0); - LuaCreateNPCParse(armor_tint[4], uint32, 0); - LuaCreateNPCParse(armor_tint[5], uint32, 0); - LuaCreateNPCParse(armor_tint[6], uint32, 0); - LuaCreateNPCParse(armor_tint[7], uint32, 0); - LuaCreateNPCParse(armor_tint[8], uint32, 0); + LuaCreateNPCParse(armor_tint.Head.Color, uint32, 0); + LuaCreateNPCParse(armor_tint.Chest.Color, uint32, 0); + LuaCreateNPCParse(armor_tint.Arms.Color, uint32, 0); + LuaCreateNPCParse(armor_tint.Wrist.Color, uint32, 0); + LuaCreateNPCParse(armor_tint.Hands.Color, uint32, 0); + LuaCreateNPCParse(armor_tint.Legs.Color, uint32, 0); + LuaCreateNPCParse(armor_tint.Feet.Color, uint32, 0); + LuaCreateNPCParse(armor_tint.Primary.Color, uint32, 0); + LuaCreateNPCParse(armor_tint.Secondary.Color, uint32, 0); LuaCreateNPCParse(min_dmg, uint32, 2); LuaCreateNPCParse(max_dmg, uint32, 4); LuaCreateNPCParse(attack_count, int16, 0); @@ -1438,12 +1486,15 @@ luabind::scope lua_register_general() { luabind::def("set_timer", (void(*)(const char*, int))&lua_set_timer), luabind::def("set_timer", (void(*)(const char*, int, Lua_ItemInst))&lua_set_timer), luabind::def("set_timer", (void(*)(const char*, int, Lua_Mob))&lua_set_timer), + luabind::def("set_timer", (void(*)(const char*, int, Lua_Encounter))&lua_set_timer), luabind::def("stop_timer", (void(*)(const char*))&lua_stop_timer), luabind::def("stop_timer", (void(*)(const char*, Lua_ItemInst))&lua_stop_timer), luabind::def("stop_timer", (void(*)(const char*, Lua_Mob))&lua_stop_timer), + luabind::def("stop_timer", (void(*)(const char*, Lua_Encounter))&lua_stop_timer), luabind::def("stop_all_timers", (void(*)(void))&lua_stop_all_timers), luabind::def("stop_all_timers", (void(*)(Lua_ItemInst))&lua_stop_all_timers), luabind::def("stop_all_timers", (void(*)(Lua_Mob))&lua_stop_all_timers), + luabind::def("stop_all_timers", (void(*)(Lua_Encounter))&lua_stop_all_timers), luabind::def("depop", (void(*)(void))&lua_depop), luabind::def("depop", (void(*)(int))&lua_depop), luabind::def("depop_with_timer", (void(*)(void))&lua_depop_with_timer), @@ -1463,7 +1514,8 @@ luabind::scope lua_register_general() { luabind::def("set_sky", &lua_set_sky), luabind::def("set_guild", &lua_set_guild), luabind::def("create_guild", &lua_create_guild), - luabind::def("set_time", &lua_set_time), + luabind::def("set_time", (void(*)(int, int))&lua_set_time), + luabind::def("set_time", (void(*)(int, int, bool))&lua_set_time), luabind::def("signal", (void(*)(int,int))&lua_signal), luabind::def("signal", (void(*)(int,int,int))&lua_signal), luabind::def("set_global", &lua_set_global), @@ -1488,9 +1540,9 @@ luabind::scope lua_register_general() { luabind::def("spawn_condition", &lua_spawn_condition), luabind::def("get_spawn_condition", &lua_get_spawn_condition), luabind::def("toggle_spawn_event", &lua_toggle_spawn_event), - luabind::def("summon_burried_player_corpse", &lua_summon_burried_player_corpse), + luabind::def("summon_buried_player_corpse", &lua_summon_buried_player_corpse), luabind::def("summon_all_player_corpses", &lua_summon_all_player_corpses), - luabind::def("get_player_burried_corpse_count", &lua_get_player_burried_corpse_count), + luabind::def("get_player_buried_corpse_count", &lua_get_player_buried_corpse_count), luabind::def("bury_player_corpse", &lua_bury_player_corpse), luabind::def("task_selector", &lua_task_selector), luabind::def("task_set_selector", &lua_task_set_selector), @@ -1540,6 +1592,7 @@ luabind::scope lua_register_general() { luabind::def("get_guild_name_by_id", &lua_get_guild_name_by_id), luabind::def("create_instance", &lua_create_instance), luabind::def("destroy_instance", &lua_destroy_instance), + luabind::def("update_instance_timer", &lua_update_instance_timer), luabind::def("get_instance_id", &lua_get_instance_id), luabind::def("get_characters_in_instance", &lua_get_characters_in_instance), luabind::def("assign_to_instance", &lua_assign_to_instance), @@ -1592,6 +1645,7 @@ luabind::scope lua_register_general() { luabind::def("enable_recipe", &lua_enable_recipe), luabind::def("disable_recipe", &lua_disable_recipe), luabind::def("clear_npctype_cache", &lua_clear_npctype_cache), + luabind::def("reloadzonestaticdata", &lua_reloadzonestaticdata), luabind::def("clock", &lua_clock), luabind::def("create_npc", &lua_create_npc), luabind::def("debug", (void(*)(std::string))&lua_debug), @@ -1676,7 +1730,10 @@ luabind::scope lua_register_events() { luabind::value("enter_area", static_cast(EVENT_ENTER_AREA)), luabind::value("leave_area", static_cast(EVENT_LEAVE_AREA)), luabind::value("death_complete", static_cast(EVENT_DEATH_COMPLETE)), - luabind::value("unhandled_opcode", static_cast(EVENT_UNHANDLED_OPCODE)) + luabind::value("unhandled_opcode", static_cast(EVENT_UNHANDLED_OPCODE)), + luabind::value("tick", static_cast(EVENT_TICK)), + luabind::value("spawn_zone", static_cast(EVENT_SPAWN_ZONE)), + luabind::value("death_zone", static_cast(EVENT_DEATH_ZONE)) ]; } @@ -1700,50 +1757,50 @@ luabind::scope lua_register_slot() { return luabind::class_("Slot") .enum_("constants") [ - luabind::value("Charm", static_cast(MainCharm)), - luabind::value("Ear1", static_cast(MainEar1)), - luabind::value("Head", static_cast(MainHead)), - luabind::value("Face", static_cast(MainFace)), - luabind::value("Ear2", static_cast(MainEar2)), - luabind::value("Neck", static_cast(MainNeck)), - luabind::value("Shoulder", static_cast(MainShoulders)), // deprecated - luabind::value("Shoulders", static_cast(MainShoulders)), - luabind::value("Arms", static_cast(MainArms)), - luabind::value("Back", static_cast(MainBack)), - luabind::value("Bracer1", static_cast(MainWrist1)), // deprecated - luabind::value("Wrist1", static_cast(MainWrist1)), - luabind::value("Bracer2", static_cast(MainWrist2)), // deprecated - luabind::value("Wrist2", static_cast(MainWrist2)), - luabind::value("Range", static_cast(MainRange)), - luabind::value("Hands", static_cast(MainHands)), - luabind::value("Primary", static_cast(MainPrimary)), - luabind::value("Secondary", static_cast(MainSecondary)), - luabind::value("Ring1", static_cast(MainFinger1)), // deprecated - luabind::value("Finger1", static_cast(MainFinger1)), - luabind::value("Ring2", static_cast(MainFinger2)), // deprecated - luabind::value("Finger2", static_cast(MainFinger2)), - luabind::value("Chest", static_cast(MainChest)), - luabind::value("Legs", static_cast(MainLegs)), - luabind::value("Feet", static_cast(MainFeet)), - luabind::value("Waist", static_cast(MainWaist)), - luabind::value("PowerSource", static_cast(MainPowerSource)), - luabind::value("Ammo", static_cast(MainAmmo)), - luabind::value("General1", static_cast(MainGeneral1)), - luabind::value("General2", static_cast(MainGeneral2)), - luabind::value("General3", static_cast(MainGeneral3)), - luabind::value("General4", static_cast(MainGeneral4)), - luabind::value("General5", static_cast(MainGeneral5)), - luabind::value("General6", static_cast(MainGeneral6)), - luabind::value("General7", static_cast(MainGeneral7)), - luabind::value("General8", static_cast(MainGeneral8)), - luabind::value("Cursor", static_cast(MainCursor)), - luabind::value("PersonalBegin", static_cast(EmuConstants::GENERAL_BEGIN)), // deprecated - luabind::value("GeneralBegin", static_cast(EmuConstants::GENERAL_BEGIN)), - luabind::value("PersonalEnd", static_cast(EmuConstants::GENERAL_END)), // deprecated - luabind::value("GeneralEnd", static_cast(EmuConstants::GENERAL_END)), + luabind::value("Charm", static_cast(EQEmu::legacy::SlotCharm)), + luabind::value("Ear1", static_cast(EQEmu::legacy::SlotEar1)), + luabind::value("Head", static_cast(EQEmu::legacy::SlotHead)), + luabind::value("Face", static_cast(EQEmu::legacy::SlotFace)), + luabind::value("Ear2", static_cast(EQEmu::legacy::SlotEar2)), + luabind::value("Neck", static_cast(EQEmu::legacy::SlotNeck)), + luabind::value("Shoulder", static_cast(EQEmu::legacy::SlotShoulders)), // deprecated + luabind::value("Shoulders", static_cast(EQEmu::legacy::SlotShoulders)), + luabind::value("Arms", static_cast(EQEmu::legacy::SlotArms)), + luabind::value("Back", static_cast(EQEmu::legacy::SlotBack)), + luabind::value("Bracer1", static_cast(EQEmu::legacy::SlotWrist1)), // deprecated + luabind::value("Wrist1", static_cast(EQEmu::legacy::SlotWrist1)), + luabind::value("Bracer2", static_cast(EQEmu::legacy::SlotWrist2)), // deprecated + luabind::value("Wrist2", static_cast(EQEmu::legacy::SlotWrist2)), + luabind::value("Range", static_cast(EQEmu::legacy::SlotRange)), + luabind::value("Hands", static_cast(EQEmu::legacy::SlotHands)), + luabind::value("Primary", static_cast(EQEmu::legacy::SlotPrimary)), + luabind::value("Secondary", static_cast(EQEmu::legacy::SlotSecondary)), + luabind::value("Ring1", static_cast(EQEmu::legacy::SlotFinger1)), // deprecated + luabind::value("Finger1", static_cast(EQEmu::legacy::SlotFinger1)), + luabind::value("Ring2", static_cast(EQEmu::legacy::SlotFinger2)), // deprecated + luabind::value("Finger2", static_cast(EQEmu::legacy::SlotFinger2)), + luabind::value("Chest", static_cast(EQEmu::legacy::SlotChest)), + luabind::value("Legs", static_cast(EQEmu::legacy::SlotLegs)), + luabind::value("Feet", static_cast(EQEmu::legacy::SlotFeet)), + luabind::value("Waist", static_cast(EQEmu::legacy::SlotWaist)), + luabind::value("PowerSource", static_cast(EQEmu::legacy::SlotPowerSource)), + luabind::value("Ammo", static_cast(EQEmu::legacy::SlotAmmo)), + luabind::value("General1", static_cast(EQEmu::legacy::SlotGeneral1)), + luabind::value("General2", static_cast(EQEmu::legacy::SlotGeneral2)), + luabind::value("General3", static_cast(EQEmu::legacy::SlotGeneral3)), + luabind::value("General4", static_cast(EQEmu::legacy::SlotGeneral4)), + luabind::value("General5", static_cast(EQEmu::legacy::SlotGeneral5)), + luabind::value("General6", static_cast(EQEmu::legacy::SlotGeneral6)), + luabind::value("General7", static_cast(EQEmu::legacy::SlotGeneral7)), + luabind::value("General8", static_cast(EQEmu::legacy::SlotGeneral8)), + luabind::value("Cursor", static_cast(EQEmu::legacy::SlotCursor)), + luabind::value("PersonalBegin", static_cast(EQEmu::legacy::GENERAL_BEGIN)), // deprecated + luabind::value("GeneralBegin", static_cast(EQEmu::legacy::GENERAL_BEGIN)), + luabind::value("PersonalEnd", static_cast(EQEmu::legacy::GENERAL_END)), // deprecated + luabind::value("GeneralEnd", static_cast(EQEmu::legacy::GENERAL_END)), luabind::value("CursorEnd", 0xFFFE), // deprecated - luabind::value("Tradeskill", static_cast(legacy::SLOT_TRADESKILL)), // deprecated - luabind::value("Augment", static_cast(legacy::SLOT_AUGMENT)), // deprecated + luabind::value("Tradeskill", static_cast(EQEmu::legacy::SLOT_TRADESKILL)), // deprecated + luabind::value("Augment", static_cast(EQEmu::legacy::SLOT_AUGMENT)), // deprecated luabind::value("Invalid", INVALID_INDEX) ]; } @@ -1752,19 +1809,19 @@ luabind::scope lua_register_material() { return luabind::class_("Material") .enum_("constants") [ - luabind::value("Head", static_cast(MaterialHead)), - luabind::value("Chest", static_cast(MaterialChest)), - luabind::value("Arms", static_cast(MaterialArms)), - luabind::value("Bracer", static_cast(MaterialWrist)), // deprecated - luabind::value("Wrist", static_cast(MaterialWrist)), - luabind::value("Hands", static_cast(MaterialHands)), - luabind::value("Legs", static_cast(MaterialLegs)), - luabind::value("Feet", static_cast(MaterialFeet)), - luabind::value("Primary", static_cast(MaterialPrimary)), - luabind::value("Secondary", static_cast(MaterialSecondary)), - luabind::value("Max", static_cast(_MaterialCount)), // deprecated - luabind::value("Count", static_cast(_MaterialCount)), - luabind::value("Invalid", static_cast(_MaterialInvalid)) + luabind::value("Head", static_cast(EQEmu::textures::TextureHead)), + luabind::value("Chest", static_cast(EQEmu::textures::TextureChest)), + luabind::value("Arms", static_cast(EQEmu::textures::TextureArms)), + luabind::value("Bracer", static_cast(EQEmu::textures::TextureWrist)), // deprecated + luabind::value("Wrist", static_cast(EQEmu::textures::TextureWrist)), + luabind::value("Hands", static_cast(EQEmu::textures::TextureHands)), + luabind::value("Legs", static_cast(EQEmu::textures::TextureLegs)), + luabind::value("Feet", static_cast(EQEmu::textures::TextureFeet)), + luabind::value("Primary", static_cast(EQEmu::textures::TexturePrimary)), + luabind::value("Secondary", static_cast(EQEmu::textures::TextureSecondary)), + luabind::value("Max", static_cast(EQEmu::textures::TextureCount)), // deprecated + luabind::value("Count", static_cast(EQEmu::textures::TextureCount)), + luabind::value("Invalid", static_cast(EQEmu::textures::TextureInvalid)) ]; } @@ -1772,14 +1829,14 @@ luabind::scope lua_register_client_version() { return luabind::class_("ClientVersion") .enum_("constants") [ - luabind::value("Unknown", static_cast(ClientVersion::Unknown)), - luabind::value("Titanium", static_cast(ClientVersion::Titanium)), - luabind::value("SoF", static_cast(ClientVersion::SoF)), - luabind::value("SoD", static_cast(ClientVersion::SoD)), - luabind::value("Underfoot", static_cast(ClientVersion::UF)), // deprecated - luabind::value("UF", static_cast(ClientVersion::UF)), - luabind::value("RoF", static_cast(ClientVersion::RoF)), - luabind::value("RoF2", static_cast(ClientVersion::RoF2)) + luabind::value("Unknown", static_cast(EQEmu::versions::ClientVersion::Unknown)), + luabind::value("Titanium", static_cast(EQEmu::versions::ClientVersion::Titanium)), + luabind::value("SoF", static_cast(EQEmu::versions::ClientVersion::SoF)), + luabind::value("SoD", static_cast(EQEmu::versions::ClientVersion::SoD)), + luabind::value("Underfoot", static_cast(EQEmu::versions::ClientVersion::UF)), // deprecated + luabind::value("UF", static_cast(EQEmu::versions::ClientVersion::UF)), + luabind::value("RoF", static_cast(EQEmu::versions::ClientVersion::RoF)), + luabind::value("RoF2", static_cast(EQEmu::versions::ClientVersion::RoF2)) ]; } diff --git a/zone/lua_item.cpp b/zone/lua_item.cpp index 16254c52e..d6846abc0 100644 --- a/zone/lua_item.cpp +++ b/zone/lua_item.cpp @@ -7,7 +7,7 @@ #include "lua_item.h" Lua_Item::Lua_Item(uint32 item_id) { - const Item_Struct *t = database.GetItem(item_id); + const EQEmu::ItemBase *t = database.GetItem(item_id); SetLuaPtrData(t); } diff --git a/zone/lua_item.h b/zone/lua_item.h index 961da1333..74294f2a5 100644 --- a/zone/lua_item.h +++ b/zone/lua_item.h @@ -4,7 +4,10 @@ #include "lua_ptr.h" -struct Item_Struct; +namespace EQEmu +{ + struct ItemBase; +} namespace luabind { struct scope; @@ -12,17 +15,17 @@ namespace luabind { luabind::scope lua_register_item(); -class Lua_Item : public Lua_Ptr +class Lua_Item : public Lua_Ptr { - typedef const Item_Struct NativeType; + typedef const EQEmu::ItemBase NativeType; public: Lua_Item(uint32 item_id); Lua_Item() : Lua_Ptr(nullptr) { } - Lua_Item(const Item_Struct *d) : Lua_Ptr(d) { } + Lua_Item(const EQEmu::ItemBase *d) : Lua_Ptr(d) { } virtual ~Lua_Item() { } - operator const Item_Struct*() { - return reinterpret_cast(GetLuaPtrData()); + operator const EQEmu::ItemBase*() { + return reinterpret_cast(GetLuaPtrData()); } int GetMinStatus(); diff --git a/zone/lua_iteminst.cpp b/zone/lua_iteminst.cpp index 4ebc6908f..0b6981358 100644 --- a/zone/lua_iteminst.cpp +++ b/zone/lua_iteminst.cpp @@ -41,7 +41,7 @@ Lua_ItemInst::Lua_ItemInst(const Lua_ItemInst& o) { bool Lua_ItemInst::IsType(int item_class) { Lua_Safe_Call_Bool(); - return self->IsType(static_cast(item_class)); + return self->IsType(static_cast(item_class)); } bool Lua_ItemInst::IsStackable() { diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 04d11566a..f5b8c8382 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -178,22 +178,22 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket void Lua_Mob::Damage(Lua_Mob from, int damage, int spell_id, int attack_skill) { Lua_Safe_Call_Void(); - return self->Damage(from, damage, spell_id, static_cast(attack_skill)); + return self->Damage(from, damage, spell_id, static_cast(attack_skill)); } void Lua_Mob::Damage(Lua_Mob from, int damage, int spell_id, int attack_skill, bool avoidable) { Lua_Safe_Call_Void(); - return self->Damage(from, damage, spell_id, static_cast(attack_skill), avoidable); + return self->Damage(from, damage, spell_id, static_cast(attack_skill), avoidable); } void Lua_Mob::Damage(Lua_Mob from, int damage, int spell_id, int attack_skill, bool avoidable, int buffslot) { Lua_Safe_Call_Void(); - return self->Damage(from, damage, spell_id, static_cast(attack_skill), avoidable, buffslot); + return self->Damage(from, damage, spell_id, static_cast(attack_skill), avoidable, buffslot); } void Lua_Mob::Damage(Lua_Mob from, int damage, int spell_id, int attack_skill, bool avoidable, int buffslot, bool buff_tic) { Lua_Safe_Call_Void(); - return self->Damage(from, damage, spell_id, static_cast(attack_skill), avoidable, buffslot, buff_tic); + return self->Damage(from, damage, spell_id, static_cast(attack_skill), avoidable, buffslot, buff_tic); } void Lua_Mob::RangedAttack(Lua_Mob other) { @@ -759,28 +759,28 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id) { bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot) { Lua_Safe_Call_Bool(); - return self->CastSpell(spell_id, target_id, slot); + return self->CastSpell(spell_id, target_id, static_cast(slot)); } bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time) { Lua_Safe_Call_Bool(); - return self->CastSpell(spell_id, target_id, slot, cast_time); + return self->CastSpell(spell_id, target_id, static_cast(slot), cast_time); } bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost) { Lua_Safe_Call_Bool(); - return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost); + return self->CastSpell(spell_id, target_id, static_cast(slot), cast_time, mana_cost); } bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot) { Lua_Safe_Call_Bool(); - return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost, nullptr, static_cast(item_slot)); + return self->CastSpell(spell_id, target_id, static_cast(slot), cast_time, mana_cost, nullptr, static_cast(item_slot)); } bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration) { Lua_Safe_Call_Bool(); - return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost, nullptr, static_cast(item_slot), + return self->CastSpell(spell_id, target_id, static_cast(slot), cast_time, mana_cost, nullptr, static_cast(item_slot), static_cast(timer), static_cast(timer_duration)); } @@ -789,8 +789,8 @@ bool Lua_Mob::CastSpell(int spell_id, int target_id, int slot, int cast_time, in Lua_Safe_Call_Bool(); int16 res = resist_adjust; - return self->CastSpell(spell_id, target_id, slot, cast_time, mana_cost, nullptr, static_cast(item_slot), - static_cast(timer), static_cast(timer_duration), 0, &res); + return self->CastSpell(spell_id, target_id, static_cast(slot), cast_time, mana_cost, nullptr, static_cast(item_slot), + static_cast(timer), static_cast(timer_duration), &res); } bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target) { @@ -800,27 +800,27 @@ bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target) { bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot) { Lua_Safe_Call_Bool(); - return self->SpellFinished(spell_id, target, slot); + return self->SpellFinished(spell_id, target, static_cast(slot)); } bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used) { Lua_Safe_Call_Bool(); - return self->SpellFinished(spell_id, target, slot, mana_used); + return self->SpellFinished(spell_id, target, static_cast(slot), mana_used); } bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot) { Lua_Safe_Call_Bool(); - return self->SpellFinished(spell_id, target, slot, mana_used, inventory_slot); + return self->SpellFinished(spell_id, target, static_cast(slot), mana_used, inventory_slot); } bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust) { Lua_Safe_Call_Bool(); - return self->SpellFinished(spell_id, target, slot, mana_used, inventory_slot, resist_adjust); + return self->SpellFinished(spell_id, target, static_cast(slot), mana_used, inventory_slot, resist_adjust); } bool Lua_Mob::SpellFinished(int spell_id, Lua_Mob target, int slot, int mana_used, uint32 inventory_slot, int resist_adjust, bool proc) { Lua_Safe_Call_Bool(); - return self->SpellFinished(spell_id, target, slot, mana_used, inventory_slot, resist_adjust, proc); + return self->SpellFinished(spell_id, target, static_cast(slot), mana_used, inventory_slot, resist_adjust, proc); } void Lua_Mob::SpellEffect(Lua_Mob caster, int spell_id, double partial) { @@ -1023,14 +1023,14 @@ int Lua_Mob::GetHaste() { return self->GetHaste(); } -int Lua_Mob::GetMonkHandToHandDamage() { +int Lua_Mob::GetHandToHandDamage() { Lua_Safe_Call_Int(); - return self->GetMonkHandToHandDamage(); + return self->GetHandToHandDamage(); } -int Lua_Mob::GetMonkHandToHandDelay() { +int Lua_Mob::GetHandToHandDelay() { Lua_Safe_Call_Int(); - return self->GetMonkHandToHandDelay(); + return self->GetHandToHandDelay(); } void Lua_Mob::Mesmerize() { @@ -1172,22 +1172,22 @@ bool Lua_Mob::Charmed() { int Lua_Mob::CheckAggroAmount(int spell_id) { Lua_Safe_Call_Int(); - return self->CheckAggroAmount(spell_id); + return self->CheckAggroAmount(spell_id, nullptr); } int Lua_Mob::CheckAggroAmount(int spell_id, bool is_proc) { Lua_Safe_Call_Int(); - return self->CheckAggroAmount(spell_id, is_proc); + return self->CheckAggroAmount(spell_id, nullptr, is_proc); } int Lua_Mob::CheckHealAggroAmount(int spell_id) { Lua_Safe_Call_Int(); - return self->CheckHealAggroAmount(spell_id); + return self->CheckHealAggroAmount(spell_id, nullptr); } int Lua_Mob::CheckHealAggroAmount(int spell_id, uint32 heal_possible) { Lua_Safe_Call_Int(); - return self->CheckHealAggroAmount(spell_id, heal_possible); + return self->CheckHealAggroAmount(spell_id, nullptr, heal_possible); } int Lua_Mob::GetAA(int id) { @@ -1195,6 +1195,21 @@ int Lua_Mob::GetAA(int id) { return self->GetAA(id); } +int Lua_Mob::GetAAByAAID(int id) { + Lua_Safe_Call_Int(); + return self->GetAAByAAID(id); +} + +bool Lua_Mob::SetAA(int rank_id, int new_value) { + Lua_Safe_Call_Bool(); + return self->SetAA(rank_id, new_value); +} + +bool Lua_Mob::SetAA(int rank_id, int new_value, int charges) { + Lua_Safe_Call_Bool(); + return self->SetAA(rank_id, new_value, charges); +} + bool Lua_Mob::DivineAura() { Lua_Safe_Call_Bool(); return self->DivineAura(); @@ -1237,28 +1252,28 @@ bool Lua_Mob::CombatRange(Lua_Mob other) { void Lua_Mob::DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage) { Lua_Safe_Call_Void(); - self->DoSpecialAttackDamage(other, static_cast(skill), max_damage); + self->DoSpecialAttackDamage(other, static_cast(skill), max_damage); } void Lua_Mob::DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, int min_damage) { Lua_Safe_Call_Void(); - self->DoSpecialAttackDamage(other, static_cast(skill), max_damage, min_damage); + self->DoSpecialAttackDamage(other, static_cast(skill), max_damage, min_damage); } void Lua_Mob::DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, int min_damage, int hate_override) { Lua_Safe_Call_Void(); - self->DoSpecialAttackDamage(other, static_cast(skill), max_damage, min_damage, hate_override); + self->DoSpecialAttackDamage(other, static_cast(skill), max_damage, min_damage, hate_override); } void Lua_Mob::DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, int min_damage, int hate_override, int reuse_time) { Lua_Safe_Call_Void(); - self->DoSpecialAttackDamage(other, static_cast(skill), max_damage, min_damage, hate_override, reuse_time); + self->DoSpecialAttackDamage(other, static_cast(skill), max_damage, min_damage, hate_override, reuse_time); } void Lua_Mob::DoSpecialAttackDamage(Lua_Mob other, int skill, int max_damage, int min_damage, int hate_override, int reuse_time, bool hit_chance) { Lua_Safe_Call_Void(); - self->DoSpecialAttackDamage(other, static_cast(skill), max_damage, min_damage, hate_override, reuse_time, hit_chance); + self->DoSpecialAttackDamage(other, static_cast(skill), max_damage, min_damage, hate_override, reuse_time, hit_chance); } void Lua_Mob::DoThrowingAttackDmg(Lua_Mob other) { @@ -1294,22 +1309,22 @@ void Lua_Mob::DoThrowingAttackDmg(Lua_Mob other, Lua_ItemInst range_weapon, Lua_ void Lua_Mob::DoMeleeSkillAttackDmg(Lua_Mob other, int weapon_damage, int skill) { Lua_Safe_Call_Void(); - self->DoMeleeSkillAttackDmg(other, weapon_damage, static_cast(skill)); + self->DoMeleeSkillAttackDmg(other, weapon_damage, static_cast(skill)); } void Lua_Mob::DoMeleeSkillAttackDmg(Lua_Mob other, int weapon_damage, int skill, int chance_mod) { Lua_Safe_Call_Void(); - self->DoMeleeSkillAttackDmg(other, weapon_damage, static_cast(skill), chance_mod); + self->DoMeleeSkillAttackDmg(other, weapon_damage, static_cast(skill), chance_mod); } void Lua_Mob::DoMeleeSkillAttackDmg(Lua_Mob other, int weapon_damage, int skill, int chance_mod, int focus) { Lua_Safe_Call_Void(); - self->DoMeleeSkillAttackDmg(other, weapon_damage, static_cast(skill), chance_mod, focus); + self->DoMeleeSkillAttackDmg(other, weapon_damage, static_cast(skill), chance_mod, focus); } void Lua_Mob::DoMeleeSkillAttackDmg(Lua_Mob other, int weapon_damage, int skill, int chance_mod, int focus, bool can_riposte) { Lua_Safe_Call_Void(); - self->DoMeleeSkillAttackDmg(other, weapon_damage, static_cast(skill), chance_mod, focus, can_riposte); + self->DoMeleeSkillAttackDmg(other, weapon_damage, static_cast(skill), chance_mod, focus, can_riposte); } void Lua_Mob::DoArcheryAttackDmg(Lua_Mob other) { @@ -1590,26 +1605,6 @@ void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { beard, aa_title, drakkin_heritage, drakkin_tattoo, drakkin_details, size); } -void Lua_Mob::QuestReward(Lua_Client c) { - Lua_Safe_Call_Void(); - self->QuestReward(c); -} - -void Lua_Mob::QuestReward(Lua_Client c, uint32 silver) { - Lua_Safe_Call_Void(); - self->QuestReward(c, silver); -} - -void Lua_Mob::QuestReward(Lua_Client c, uint32 silver, uint32 gold) { - Lua_Safe_Call_Void(); - self->QuestReward(c, silver, gold); -} - -void Lua_Mob::QuestReward(Lua_Client c, uint32 silver, uint32 gold, uint32 platinum) { - Lua_Safe_Call_Void(); - self->QuestReward(c, silver, gold, platinum); -} - void Lua_Mob::CameraEffect(uint32 duration, uint32 intensity) { Lua_Safe_Call_Void(); self->CameraEffect(duration, intensity); @@ -1651,6 +1646,11 @@ void Lua_Mob::TempName(const char *newname) { self->TempName(newname); } +std::string Lua_Mob::GetGlobal(const char *varname) { + Lua_Safe_Call_String(); + return self->GetGlobal(varname); +} + void Lua_Mob::SetGlobal(const char *varname, const char *newvalue, int options, const char *duration) { Lua_Safe_Call_Void(); self->SetGlobal(varname, newvalue, options, duration); @@ -1713,17 +1713,17 @@ void Lua_Mob::SetTargetable(bool on) { void Lua_Mob::ModSkillDmgTaken(int skill, int value) { Lua_Safe_Call_Void(); - self->ModSkillDmgTaken(static_cast(skill), value); + self->ModSkillDmgTaken(static_cast(skill), value); } int Lua_Mob::GetModSkillDmgTaken(int skill) { Lua_Safe_Call_Int(); - return self->GetModSkillDmgTaken(static_cast(skill)); + return self->GetModSkillDmgTaken(static_cast(skill)); } int Lua_Mob::GetSkillDmgTaken(int skill) { Lua_Safe_Call_Int(); - return self->GetSkillDmgTaken(static_cast(skill)); + return self->GetSkillDmgTaken(static_cast(skill)); } void Lua_Mob::SetAllowBeneficial(bool value) { @@ -1773,7 +1773,7 @@ int Lua_Mob::GetFlurryChance() { int Lua_Mob::GetSkill(int skill) { Lua_Safe_Call_Int(); - return self->GetSkill(static_cast(skill)); + return self->GetSkill(static_cast(skill)); } int Lua_Mob::GetSpecialAbility(int ability) { @@ -1866,6 +1866,120 @@ int Lua_Mob::CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite return self->CanBuffStack(spell_id, caster_level, fail_if_overwrite); } +void Lua_Mob::SetPseudoRoot(bool in) { + Lua_Safe_Call_Void(); + self->SetPseudoRoot(in); +} + +bool Lua_Mob::IsFeared() { + Lua_Safe_Call_Bool(); + return self->IsFeared(); +} + +bool Lua_Mob::IsBlind() { + Lua_Safe_Call_Bool(); + return self->IsBlind(); +} + +uint8 Lua_Mob::SeeInvisible() { + Lua_Safe_Call_Int(); + return self->SeeInvisible(); +} + +bool Lua_Mob::SeeInvisibleUndead() { + Lua_Safe_Call_Bool(); + return self->SeeInvisibleUndead(); +} + +bool Lua_Mob::SeeHide() { + Lua_Safe_Call_Bool(); + return self->SeeHide(); +} + +bool Lua_Mob::SeeImprovedHide() { + Lua_Safe_Call_Bool(); + return self->SeeImprovedHide(); +} + +uint8 Lua_Mob::GetNimbusEffect1() { + Lua_Safe_Call_Int(); + return self->GetNimbusEffect1(); +} + +uint8 Lua_Mob::GetNimbusEffect2() { + Lua_Safe_Call_Int(); + return self->GetNimbusEffect2(); +} + +uint8 Lua_Mob::GetNimbusEffect3() { + Lua_Safe_Call_Int(); + return self->GetNimbusEffect3(); +} + +bool Lua_Mob::IsTargetable() { + Lua_Safe_Call_Bool(); + return self->IsTargetable(); +} + +bool Lua_Mob::HasShieldEquiped() { + Lua_Safe_Call_Bool(); + return self->HasShieldEquiped(); +} + +bool Lua_Mob::HasTwoHandBluntEquiped() { + Lua_Safe_Call_Bool(); + return self->HasTwoHandBluntEquiped(); +} + +bool Lua_Mob::HasTwoHanderEquipped() { + Lua_Safe_Call_Bool(); + return self->HasTwoHanderEquipped(); +} + +uint32 Lua_Mob::GetHerosForgeModel(uint8 material_slot) { + Lua_Safe_Call_Int(); + return self->GetHerosForgeModel(material_slot); +} + +uint32 Lua_Mob::IsEliteMaterialItem(uint8 material_slot) { + Lua_Safe_Call_Int(); + return self->IsEliteMaterialItem(material_slot); +} + +float Lua_Mob::GetBaseSize() { + Lua_Safe_Call_Real(); + return self->GetBaseSize(); +} + +bool Lua_Mob::HasOwner() { + Lua_Safe_Call_Bool(); + return self->HasOwner(); +} + +bool Lua_Mob::IsPet() { + Lua_Safe_Call_Bool(); + return self->IsPet(); +} + +bool Lua_Mob::HasPet() { + Lua_Safe_Call_Bool(); + return self->HasPet(); +} + +bool Lua_Mob::IsSilenced() { + Lua_Safe_Call_Bool(); + return self->IsSilenced(); +} + +bool Lua_Mob::IsAmnesiad() { + Lua_Safe_Call_Bool(); + return self->IsAmnesiad(); +} + +int32 Lua_Mob::GetMeleeMitigation() { + Lua_Safe_Call_Int(); + return self->GetMeleeMitigation(); +} luabind::scope lua_register_mob() { return luabind::class_("Mob") @@ -2051,8 +2165,8 @@ luabind::scope lua_register_mob() { .def("GetInvul", (bool(Lua_Mob::*)(void))&Lua_Mob::GetInvul) .def("SetExtraHaste", (void(Lua_Mob::*)(int))&Lua_Mob::SetExtraHaste) .def("GetHaste", (int(Lua_Mob::*)(void))&Lua_Mob::GetHaste) - .def("GetMonkHandToHandDamage", (int(Lua_Mob::*)(void))&Lua_Mob::GetMonkHandToHandDamage) - .def("GetMonkHandToHandDelay", (int(Lua_Mob::*)(void))&Lua_Mob::GetMonkHandToHandDelay) + .def("GetHandToHandDamage", (int(Lua_Mob::*)(void))&Lua_Mob::GetHandToHandDamage) + .def("GetHandToHandDelay", (int(Lua_Mob::*)(void))&Lua_Mob::GetHandToHandDelay) .def("Mesmerize", (void(Lua_Mob::*)(void))&Lua_Mob::Mesmerize) .def("IsMezzed", (bool(Lua_Mob::*)(void))&Lua_Mob::IsMezzed) .def("IsEnraged", (bool(Lua_Mob::*)(void))&Lua_Mob::IsEnraged) @@ -2085,6 +2199,9 @@ luabind::scope lua_register_mob() { .def("CheckHealAggroAmount", (int(Lua_Mob::*)(int))&Lua_Mob::CheckHealAggroAmount) .def("CheckHealAggroAmount", (int(Lua_Mob::*)(int,uint32))&Lua_Mob::CheckHealAggroAmount) .def("GetAA", (int(Lua_Mob::*)(int))&Lua_Mob::GetAA) + .def("GetAAByAAID", (int(Lua_Mob::*)(int))&Lua_Mob::GetAAByAAID) + .def("SetAA", (bool(Lua_Mob::*)(int,int))&Lua_Mob::SetAA) + .def("SetAA", (bool(Lua_Mob::*)(int,int,int))&Lua_Mob::SetAA) .def("DivineAura", (bool(Lua_Mob::*)(void))&Lua_Mob::DivineAura) .def("SetOOCRegen", (void(Lua_Mob::*)(int))&Lua_Mob::SetOOCRegen) .def("GetEntityVariable", (const char*(Lua_Mob::*)(const char*))&Lua_Mob::GetEntityVariable) @@ -2132,10 +2249,6 @@ 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("QuestReward", (void(Lua_Mob::*)(Lua_Client))&Lua_Mob::QuestReward) - .def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32))&Lua_Mob::QuestReward) - .def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32,uint32))&Lua_Mob::QuestReward) - .def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32,uint32,uint32))&Lua_Mob::QuestReward) .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) @@ -2144,6 +2257,7 @@ luabind::scope lua_register_mob() { .def("SendSpellEffect", (void(Lua_Mob::*)(uint32,uint32,uint32,bool,uint32,bool,Lua_Client))&Lua_Mob::SendSpellEffect) .def("TempName", (void(Lua_Mob::*)(void))&Lua_Mob::TempName) .def("TempName", (void(Lua_Mob::*)(const char*))&Lua_Mob::TempName) + .def("GetGlobal", (std::string(Lua_Mob::*)(const char*))&Lua_Mob::GetGlobal) .def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*))&Lua_Mob::SetGlobal) .def("SetGlobal", (void(Lua_Mob::*)(const char*,const char*,int,const char*,Lua_Mob))&Lua_Mob::SetGlobal) .def("TarGlobal", (void(Lua_Mob::*)(const char*,const char*,const char*,int,int,int))&Lua_Mob::TarGlobal) @@ -2152,6 +2266,8 @@ luabind::scope lua_register_mob() { .def("WearChange", (void(Lua_Mob::*)(int,int,uint32))&Lua_Mob::WearChange) .def("DoKnockback", (void(Lua_Mob::*)(Lua_Mob,uint32,uint32))&Lua_Mob::DoKnockback) .def("RemoveNimbusEffect", (void(Lua_Mob::*)(int))&Lua_Mob::RemoveNimbusEffect) + .def("IsFeared", (bool(Lua_Mob::*)(void))&Lua_Mob::IsFeared) + .def("IsBlind", (bool(Lua_Mob::*)(void))&Lua_Mob::IsBlind) .def("IsRunning", (bool(Lua_Mob::*)(void))&Lua_Mob::IsRunning) .def("SetRunning", (void(Lua_Mob::*)(bool))&Lua_Mob::SetRunning) .def("SetBodyType", (void(Lua_Mob::*)(int,bool))&Lua_Mob::SetBodyType) @@ -2186,7 +2302,28 @@ luabind::scope lua_register_mob() { .def("BuffFadeBySlot", (void(Lua_Mob::*)(int))&Lua_Mob::BuffFadeBySlot) .def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot) .def("CanBuffStack", (int(Lua_Mob::*)(int,int))&Lua_Mob::CanBuffStack) - .def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack); + .def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack) + .def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot) + .def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible) + .def("SeeInvisibleUndead", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead) + .def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide) + .def("SeeImprovedHide", (bool(Lua_Mob::*)(bool))&Lua_Mob::SeeImprovedHide) + .def("GetNimbusEffect1", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect1) + .def("GetNimbusEffect2", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect2) + .def("GetNimbusEffect3", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect3) + .def("IsTargetable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsTargetable) + .def("HasShieldEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasShieldEquiped) + .def("HasTwoHandBluntEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHandBluntEquiped) + .def("HasTwoHanderEquipped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHanderEquipped) + .def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel) + .def("IsEliteMaterialItem", (uint32(Lua_Mob::*)(uint8))&Lua_Mob::IsEliteMaterialItem) + .def("GetBaseSize", (double(Lua_Mob::*)(void))&Lua_Mob::GetBaseSize) + .def("HasOwner", (bool(Lua_Mob::*)(void))&Lua_Mob::HasOwner) + .def("IsPet", (bool(Lua_Mob::*)(void))&Lua_Mob::IsPet) + .def("HasPet", (bool(Lua_Mob::*)(void))&Lua_Mob::HasPet) + .def("IsSilenced", (bool(Lua_Mob::*)(void))&Lua_Mob::IsSilenced) + .def("IsAmnesiad", (bool(Lua_Mob::*)(void))&Lua_Mob::IsAmnesiad) + .def("GetMeleeMitigation", (int32(Lua_Mob::*)(void))&Lua_Mob::GetMeleeMitigation); } luabind::scope lua_register_special_abilities() { @@ -2229,7 +2366,14 @@ luabind::scope lua_register_special_abilities() { luabind::value("destructible_object", static_cast(DESTRUCTIBLE_OBJECT)), luabind::value("no_harm_from_client", static_cast(NO_HARM_FROM_CLIENT)), luabind::value("always_flee", static_cast(ALWAYS_FLEE)), - luabind::value("flee_percent", static_cast(FLEE_PERCENT)) + luabind::value("flee_percent", static_cast(FLEE_PERCENT)), + luabind::value("allow_beneficial", static_cast(ALLOW_BENEFICIAL)), + luabind::value("disable_melee", static_cast(DISABLE_MELEE)), + luabind::value("npc_chase_distance", static_cast(NPC_CHASE_DISTANCE)), + 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)) ]; } diff --git a/zone/lua_mob.h b/zone/lua_mob.h index f272cd440..48d1f3e14 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -11,7 +11,9 @@ class Lua_ItemInst; namespace luabind { struct scope; - class object; + namespace adl { + class object; + } } luabind::scope lua_register_mob(); @@ -40,6 +42,8 @@ public: void SetLevel(int level, bool command); void SendWearChange(int material_slot); bool IsMoving(); + bool IsFeared(); + bool IsBlind(); void GotoBind(); void Gate(); bool Attack(Lua_Mob other); @@ -169,7 +173,7 @@ public: bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost); bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot); bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration); - bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration, + bool CastSpell(int spell_id, int target_id, int slot, int cast_time, int mana_cost, int item_slot, int timer, int timer_duration, int resist_adjust); bool SpellFinished(int spell_id, Lua_Mob target); bool SpellFinished(int spell_id, Lua_Mob target, int slot); @@ -215,8 +219,8 @@ public: bool GetInvul(); void SetExtraHaste(int haste); int GetHaste(); - int GetMonkHandToHandDamage(); - int GetMonkHandToHandDelay(); + int GetHandToHandDamage(); + int GetHandToHandDelay(); void Mesmerize(); bool IsMezzed(); bool IsEnraged(); @@ -249,6 +253,9 @@ public: int CheckHealAggroAmount(int spell_id); int CheckHealAggroAmount(int spell_id, uint32 heal_possible); int GetAA(int id); + int GetAAByAAID(int id); + bool SetAA(int rank_id, int new_value); + bool SetAA(int rank_id, int new_value, int charges); bool DivineAura(); void SetOOCRegen(int regen); const char* GetEntityVariable(const char *name); @@ -296,10 +303,6 @@ public: void SetRace(int in); void SetGender(int in); void SendIllusionPacket(luabind::adl::object illusion); - void QuestReward(Lua_Client c); - void QuestReward(Lua_Client c, uint32 silver); - void QuestReward(Lua_Client c, uint32 silver, uint32 gold); - void QuestReward(Lua_Client c, uint32 silver, uint32 gold, uint32 platinum); 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); @@ -311,6 +314,7 @@ public: uint32 unk020, bool perm_effect, Lua_Client c); void TempName(); void TempName(const char *newname); + std::string GetGlobal(const char *varname); void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration); void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Lua_Mob other); void TarGlobal(const char *varname, const char *value, const char *duration, int npc_id, int char_id, int zone_id); @@ -355,6 +359,27 @@ public: void BuffFadeBySlot(int slot, bool recalc_bonuses); int CanBuffStack(int spell_id, int caster_level); int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite); + void SetPseudoRoot(bool in); + uint8 SeeInvisible(); + bool SeeInvisibleUndead(); + bool SeeHide(); + bool SeeImprovedHide(); + uint8 GetNimbusEffect1(); + uint8 GetNimbusEffect2(); + uint8 GetNimbusEffect3(); + bool IsTargetable(); + bool HasShieldEquiped(); + bool HasTwoHandBluntEquiped(); + bool HasTwoHanderEquipped(); + uint32 GetHerosForgeModel(uint8 material_slot); + uint32 IsEliteMaterialItem(uint8 material_slot); + float GetBaseSize(); + bool HasOwner(); + bool IsPet(); + bool HasPet(); + bool IsSilenced(); + bool IsAmnesiad(); + int32 GetMeleeMitigation(); }; #endif diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index f7a8ad99c..6d6c69a62 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -428,6 +428,11 @@ float Lua_NPC::GetAttackSpeed() { return self->GetAttackSpeed(); } +int Lua_NPC::GetAttackDelay() { + Lua_Safe_Call_Int(); + return self->GetAttackDelay(); +} + int Lua_NPC::GetAccuracyRating() { Lua_Safe_Call_Int(); return self->GetAccuracyRating(); @@ -550,6 +555,7 @@ luabind::scope lua_register_npc() { .def("GetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::GetSpellFocusHeal) .def("GetSlowMitigation", (int(Lua_NPC::*)(void))&Lua_NPC::GetSlowMitigation) .def("GetAttackSpeed", (float(Lua_NPC::*)(void))&Lua_NPC::GetAttackSpeed) + .def("GetAttackDelay", (int(Lua_NPC::*)(void))&Lua_NPC::GetAttackDelay) .def("GetAccuracyRating", (int(Lua_NPC::*)(void))&Lua_NPC::GetAccuracyRating) .def("GetSpawnKillCount", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnKillCount) .def("GetScore", (int(Lua_NPC::*)(void))&Lua_NPC::GetScore) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index 2b201f323..f5bb4719d 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -111,6 +111,7 @@ public: int GetSpellFocusHeal(); float GetSlowMitigation(); float GetAttackSpeed(); + int GetAttackDelay(); int GetAccuracyRating(); int GetSpawnKillCount(); int GetScore(); diff --git a/zone/lua_packet.cpp b/zone/lua_packet.cpp index e16a85c6d..648d6fa87 100644 --- a/zone/lua_packet.cpp +++ b/zone/lua_packet.cpp @@ -18,7 +18,7 @@ Lua_Packet::Lua_Packet(int opcode, int size, bool raw) { if(raw) { SetLuaPtrData(new EQApplicationPacket(OP_Unknown, size)); owned_ = true; - + EQApplicationPacket *self = reinterpret_cast(d_); self->SetOpcodeBypass(opcode); } else { @@ -692,8 +692,8 @@ luabind::scope lua_register_packet_opcodes() { luabind::value("VetClaimRequest", static_cast(OP_VetClaimRequest)), luabind::value("VetClaimReply", static_cast(OP_VetClaimReply)), luabind::value("WeaponEquip1", static_cast(OP_WeaponEquip1)), - luabind::value("WeaponEquip2", static_cast(OP_WeaponEquip2)), - luabind::value("WeaponUnequip2", static_cast(OP_WeaponUnequip2)), + luabind::value("PlayerStateAdd", static_cast(OP_PlayerStateAdd)), + luabind::value("PlayerStateRemove", static_cast(OP_PlayerStateRemove)), luabind::value("WorldLogout", static_cast(OP_WorldLogout)), luabind::value("SessionReady", static_cast(OP_SessionReady)), luabind::value("Login", static_cast(OP_Login)), @@ -847,7 +847,8 @@ luabind::scope lua_register_packet_opcodes() { luabind::value("OpenContainer", static_cast(OP_OpenContainer)), luabind::value("Marquee", static_cast(OP_Marquee)), luabind::value("ClientTimeStamp", static_cast(OP_ClientTimeStamp)), - luabind::value("GuildPromote", static_cast(OP_GuildPromote)) + luabind::value("GuildPromote", static_cast(OP_GuildPromote)), + luabind::value("Fling", static_cast(OP_Fling)) ]; } diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 7f6412b0f..ea23df73f 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -33,7 +33,9 @@ #include "lua_general.h" #include "questmgr.h" #include "zone.h" +#include "zone_config.h" #include "lua_parser.h" +#include "lua_encounter.h" const char *LuaEvents[_LargestEventID] = { "event_say", @@ -115,7 +117,10 @@ const char *LuaEvents[_LargestEventID] = { "event_leave_area", "event_respawn", "event_death_complete", - "event_unhandled_opcode" + "event_unhandled_opcode", + "event_tick", + "event_spawn_zone", + "event_death_zone" }; extern Zone *zone; @@ -128,6 +133,7 @@ struct lua_registered_event { std::map> lua_encounter_events_registered; std::map lua_encounters_loaded; +std::map lua_encounters; LuaParser::LuaParser() { for(int i = 0; i < _LargestEventID; ++i) { @@ -135,6 +141,7 @@ LuaParser::LuaParser() { PlayerArgumentDispatch[i] = handle_player_null; ItemArgumentDispatch[i] = handle_item_null; SpellArgumentDispatch[i] = handle_spell_null; + EncounterArgumentDispatch[i] = handle_encounter_null; } NPCArgumentDispatch[EVENT_SAY] = handle_npc_event_say; @@ -213,6 +220,10 @@ LuaParser::LuaParser() { SpellArgumentDispatch[EVENT_SPELL_FADE] = handle_spell_fade; SpellArgumentDispatch[EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE] = handle_translocate_finish; + EncounterArgumentDispatch[EVENT_TIMER] = handle_encounter_timer; + EncounterArgumentDispatch[EVENT_ENCOUNTER_LOAD] = handle_encounter_load; + EncounterArgumentDispatch[EVENT_ENCOUNTER_UNLOAD] = handle_encounter_unload; + L = nullptr; } @@ -274,7 +285,7 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M lua_getfield(L, -1, sub_name); npop = 2; } - + lua_createtable(L, 0, 0); //always push self Lua_NPC l_npc(npc); @@ -285,7 +296,7 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M auto arg_function = NPCArgumentDispatch[evt]; arg_function(this, L, npc, init, data, extra_data, extra_pointers); Client *c = (init && init->IsClient()) ? init->CastToClient() : nullptr; - + quest_manager.StartQuest(npc, c, nullptr); if(lua_pcall(L, 1, 1, 0)) { std::string error = lua_tostring(L, -1); @@ -294,13 +305,13 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M return 0; } quest_manager.EndQuest(); - + if(lua_isnumber(L, -1)) { int ret = static_cast(lua_tointeger(L, -1)); lua_pop(L, npop); return ret; } - + lua_pop(L, npop); } catch(std::exception &ex) { std::string error = "Lua Exception: "; @@ -368,17 +379,17 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client * lua_getfield(L, -1, sub_name); npop = 2; } - + lua_createtable(L, 0, 0); //push self Lua_Client l_client(client); luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "self"); - + auto arg_function = PlayerArgumentDispatch[evt]; arg_function(this, L, client, data, extra_data, extra_pointers); - + quest_manager.StartQuest(client, client, nullptr); if(lua_pcall(L, 1, 1, 0)) { std::string error = lua_tostring(L, -1); @@ -387,13 +398,13 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client * return 0; } quest_manager.EndQuest(); - + if(lua_isnumber(L, -1)) { int ret = static_cast(lua_tointeger(L, -1)); lua_pop(L, npop); return ret; } - + lua_pop(L, npop); } catch(std::exception &ex) { std::string error = "Lua Exception: "; @@ -417,15 +428,15 @@ int LuaParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob * if(evt >= _LargestEventID) { return 0; } - + if(!item) { return 0; } - + if(!ItemHasQuestSub(item, evt)) { return 0; } - + std::string package_name = "item_"; package_name += std::to_string(item->GetID()); return _EventItem(package_name, evt, client, item, mob, data, extra_data, extra_pointers); @@ -445,7 +456,7 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str()); lua_getfield(L, -1, sub_name); } - + lua_createtable(L, 0, 0); //always push self Lua_ItemInst l_item(item); @@ -461,7 +472,7 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl //redo this arg function auto arg_function = ItemArgumentDispatch[evt]; arg_function(this, L, client, item, mob, data, extra_data, extra_pointers); - + quest_manager.StartQuest(client, client, item); if(lua_pcall(L, 1, 1, 0)) { std::string error = lua_tostring(L, -1); @@ -470,13 +481,13 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl return 0; } quest_manager.EndQuest(); - + if(lua_isnumber(L, -1)) { int ret = static_cast(lua_tointeger(L, -1)); lua_pop(L, npop); return ret; } - + lua_pop(L, npop); } catch(std::exception &ex) { std::string error = "Lua Exception: "; @@ -513,7 +524,7 @@ int LuaParser::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spe int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, std::vector *extra_pointers, luabind::adl::object *l_func) { const char *sub_name = LuaEvents[evt]; - + int start = lua_gettop(L); try { @@ -525,7 +536,7 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, lua_getfield(L, -1, sub_name); npop = 2; } - + lua_createtable(L, 0, 0); //always push self even if invalid @@ -539,10 +550,10 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, l_spell_o.push(L); } lua_setfield(L, -2, "self"); - + auto arg_function = SpellArgumentDispatch[evt]; arg_function(this, L, npc, client, spell_id, extra_data, extra_pointers); - + quest_manager.StartQuest(npc, client, nullptr); if(lua_pcall(L, 1, 1, 0)) { std::string error = lua_tostring(L, -1); @@ -551,13 +562,13 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, return 0; } quest_manager.EndQuest(); - + if(lua_isnumber(L, -1)) { int ret = static_cast(lua_tointeger(L, -1)); lua_pop(L, npop); return ret; } - + lua_pop(L, npop); } catch(std::exception &ex) { std::string error = "Lua Exception: "; @@ -575,7 +586,7 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, return 0; } -int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, std::vector *extra_pointers) { +int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data, std::vector *extra_pointers) { evt = ConvertLuaEvent(evt); if(evt >= _LargestEventID) { return 0; @@ -586,31 +597,30 @@ int LuaParser::EventEncounter(QuestEventID evt, std::string encounter_name, uint if(!EncounterHasQuestSub(encounter_name, evt)) { return 0; } - - return _EventEncounter(package_name, evt, encounter_name, extra_data, extra_pointers); + + return _EventEncounter(package_name, evt, encounter_name, data, extra_data, extra_pointers); } -int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data, +int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data, std::vector *extra_pointers) { const char *sub_name = LuaEvents[evt]; - + int start = lua_gettop(L); try { lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str()); lua_getfield(L, -1, sub_name); - + lua_createtable(L, 0, 0); lua_pushstring(L, encounter_name.c_str()); lua_setfield(L, -2, "name"); - if(extra_pointers) { - std::string *str = EQEmu::any_cast(extra_pointers->at(0)); - lua_pushstring(L, str->c_str()); - lua_setfield(L, -2, "data"); - } + Encounter *enc = lua_encounters[encounter_name]; - quest_manager.StartQuest(nullptr, nullptr, nullptr, encounter_name); + auto arg_function = EncounterArgumentDispatch[evt]; + arg_function(this, L, enc, data, extra_data, extra_pointers); + + quest_manager.StartQuest(enc, nullptr, nullptr, encounter_name); if(lua_pcall(L, 1, 1, 0)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -618,13 +628,13 @@ int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std:: return 0; } quest_manager.EndQuest(); - + if(lua_isnumber(L, -1)) { int ret = static_cast(lua_tointeger(L, -1)); lua_pop(L, 2); return ret; } - + lua_pop(L, 2); } catch(std::exception &ex) { std::string error = "Lua Exception: "; @@ -786,6 +796,11 @@ void LuaParser::ReloadQuests() { lua_encounter_events_registered.clear(); lua_encounters_loaded.clear(); + for (auto encounter : lua_encounters) { + encounter.second->Depop(); + } + lua_encounters.clear(); + if(L) { lua_close(L); } @@ -832,37 +847,71 @@ void LuaParser::ReloadQuests() { lua_pushnil(L); lua_setglobal(L, "loadfile"); +#endif + + // lua 5.2+ defines these +#if defined(LUA_VERSION_MAJOR) && defined(LUA_VERSION_MINOR) + const char lua_version[] = LUA_VERSION_MAJOR "." LUA_VERSION_MINOR; +#elif LUA_VERSION_NUM == 501 + const char lua_version[] = "5.1"; +#else +#error Incompatible lua version +#endif + +#ifdef WINDOWS + const char libext[] = ".dll"; +#else + // lua doesn't care OSX doesn't use sonames + const char libext[] = ".so"; #endif lua_getglobal(L, "package"); lua_getfield(L, -1, "path"); std::string module_path = lua_tostring(L,-1); - module_path += ";./lua_modules/?.lua"; + module_path += ";./" + Config->LuaModuleDir + "?.lua;./" + Config->LuaModuleDir + "?/init.lua"; + // luarock paths using lua_modules as tree + // to path it adds foo/share/lua/5.1/?.lua and foo/share/lua/5.1/?/init.lua + module_path += ";./" + Config->LuaModuleDir + "share/lua/" + lua_version + "/?.lua"; + module_path += ";./" + Config->LuaModuleDir + "share/lua/" + lua_version + "/?/init.lua"; lua_pop(L, 1); lua_pushstring(L, module_path.c_str()); lua_setfield(L, -2, "path"); lua_pop(L, 1); + lua_getglobal(L, "package"); + lua_getfield(L, -1, "cpath"); + module_path = lua_tostring(L, -1); + module_path += ";./" + Config->LuaModuleDir + "?" + libext; + // luarock paths using lua_modules as tree + // luarocks adds foo/lib/lua/5.1/?.so for cpath + module_path += ";./" + Config->LuaModuleDir + "lib/lua/" + lua_version + "/?" + libext; + lua_pop(L, 1); + lua_pushstring(L, module_path.c_str()); + lua_setfield(L, -2, "cpath"); + lua_pop(L, 1); + MapFunctions(L); //load init - std::string path = "quests/"; + std::string path = Config->QuestDir; + path += "/"; path += QUEST_GLOBAL_DIRECTORY; path += "/script_init.lua"; FILE *f = fopen(path.c_str(), "r"); if(f) { fclose(f); - + if(luaL_dofile(L, path.c_str())) { std::string error = lua_tostring(L, -1); AddError(error); } } - + //zone init - always loads after global if(zone) { - std::string zone_script = "quests/"; + std::string zone_script = Config->QuestDir; + zone_script += "/"; zone_script += zone->GetShortName(); zone_script += "/script_init_v"; zone_script += std::to_string(zone->GetInstanceVersion()); @@ -870,7 +919,7 @@ void LuaParser::ReloadQuests() { f = fopen(zone_script.c_str(), "r"); if(f) { fclose(f); - + if(luaL_dofile(L, zone_script.c_str())) { std::string error = lua_tostring(L, -1); AddError(error); @@ -879,7 +928,8 @@ void LuaParser::ReloadQuests() { return; } - zone_script = "quests/"; + zone_script = Config->QuestDir; + zone_script += "/"; zone_script += zone->GetShortName(); zone_script += "/script_init.lua"; f = fopen(zone_script.c_str(), "r"); @@ -899,7 +949,7 @@ void LuaParser::LoadScript(std::string filename, std::string package_name) { if(iter != loaded_.end()) { return; } - + if(luaL_loadfile(L, filename.c_str())) { std::string error = lua_tostring(L, -1); AddError(error); @@ -968,6 +1018,7 @@ void LuaParser::MapFunctions(lua_State *L) { lua_register_client_version(), lua_register_appearance(), lua_register_entity(), + lua_register_encounter(), lua_register_mob(), lua_register_special_abilities(), lua_register_npc(), @@ -996,7 +1047,7 @@ void LuaParser::MapFunctions(lua_State *L) { lua_register_packet(), lua_register_packet_opcodes() ]; - + } catch(std::exception &ex) { std::string error = ex.what(); AddError(error); @@ -1110,7 +1161,7 @@ int LuaParser::DispatchEventItem(QuestEventID evt, Client *client, ItemInst *ite if(iter == lua_encounter_events_registered.end()) { return ret; } - + auto riter = iter->second.begin(); while(riter != iter->second.end()) { if(riter->event_id == evt) { diff --git a/zone/lua_parser.h b/zone/lua_parser.h index 13cebe0fc..1e4df4740 100644 --- a/zone/lua_parser.h +++ b/zone/lua_parser.h @@ -8,6 +8,10 @@ #include #include +#include "zone_config.h" + +extern const ZoneConfig *Config; + struct lua_State; class ItemInst; class Client; @@ -39,7 +43,7 @@ public: std::vector *extra_pointers); virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, std::vector *extra_pointers); - virtual int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, + virtual int EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data, std::vector *extra_pointers); virtual bool HasQuestSub(uint32 npc_id, QuestEventID evt); @@ -82,7 +86,7 @@ private: uint32 extra_data, std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); - int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data, + int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data, std::vector *extra_pointers); void LoadScript(std::string filename, std::string package_name); @@ -99,6 +103,8 @@ private: PlayerArgumentHandler PlayerArgumentDispatch[_LargestEventID]; ItemArgumentHandler ItemArgumentDispatch[_LargestEventID]; SpellArgumentHandler SpellArgumentDispatch[_LargestEventID]; + EncounterArgumentHandler EncounterArgumentDispatch[_LargestEventID]; + }; #endif diff --git a/zone/lua_parser_events.cpp b/zone/lua_parser_events.cpp index 2780d0212..030e43689 100644 --- a/zone/lua_parser_events.cpp +++ b/zone/lua_parser_events.cpp @@ -22,6 +22,7 @@ #include "lua_door.h" #include "lua_object.h" #include "lua_packet.h" +#include "lua_encounter.h" #include "zone.h" #include "lua_parser_events.h" @@ -297,7 +298,7 @@ void handle_player_timer(QuestInterface *parse, lua_State* L, Client* client, st void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { - const Item_Struct *item = database.GetItem(extra_data); + const EQEmu::ItemBase *item = database.GetItem(extra_data); if(item) { Lua_Item l_item(item); luabind::adl::object l_item_o = luabind::adl::object(L, l_item); @@ -704,4 +705,39 @@ void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* cl std::vector *extra_pointers) { } +void handle_encounter_timer(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data, + std::vector *extra_pointers) { + lua_pushstring(L, data.c_str()); + lua_setfield(L, -2, "timer"); +} + +void handle_encounter_load(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data, + std::vector *extra_pointers) { + if (encounter) { + Lua_Encounter l_enc(encounter); + luabind::adl::object l_enc_o = luabind::adl::object(L, l_enc); + l_enc_o.push(L); + lua_setfield(L, -2, "encounter"); + } + if (extra_pointers) { + std::string *str = EQEmu::any_cast(extra_pointers->at(0)); + lua_pushstring(L, str->c_str()); + lua_setfield(L, -2, "data"); + } +} + +void handle_encounter_unload(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data, + std::vector *extra_pointers) { + if (extra_pointers) { + std::string *str = EQEmu::any_cast(extra_pointers->at(0)); + lua_pushstring(L, str->c_str()); + lua_setfield(L, -2, "data"); + } +} + +void handle_encounter_null(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data, + std::vector *extra_pointers) { + +} + #endif diff --git a/zone/lua_parser_events.h b/zone/lua_parser_events.h index 1965a9189..0a2ab5ad9 100644 --- a/zone/lua_parser_events.h +++ b/zone/lua_parser_events.h @@ -6,6 +6,7 @@ typedef void(*NPCArgumentHandler)(QuestInterface*, lua_State*, NPC*, Mob*, std:: typedef void(*PlayerArgumentHandler)(QuestInterface*, lua_State*, Client*, std::string, uint32, std::vector*); typedef void(*ItemArgumentHandler)(QuestInterface*, lua_State*, Client*, ItemInst*, Mob*, std::string, uint32, std::vector*); typedef void(*SpellArgumentHandler)(QuestInterface*, lua_State*, NPC*, Client*, uint32, uint32, std::vector*); +typedef void(*EncounterArgumentHandler)(QuestInterface*, lua_State*, Encounter* encounter, std::string, uint32, std::vector*); //NPC void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, @@ -127,5 +128,16 @@ void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Cl void handle_spell_null(QuestInterface *parse, lua_State* L, NPC* npc, Client* client, uint32 spell_id, uint32 extra_data, std::vector *extra_pointers); + +//Encounter +void handle_encounter_timer(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data, + std::vector *extra_pointers); +void handle_encounter_load(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data, + std::vector *extra_pointers); +void handle_encounter_unload(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data, + std::vector *extra_pointers); +void handle_encounter_null(QuestInterface *parse, lua_State* L, Encounter* encounter, std::string data, uint32 extra_data, + std::vector *extra_pointers); + #endif #endif diff --git a/zone/lua_spell.cpp b/zone/lua_spell.cpp index e99b9ba84..18353efaa 100644 --- a/zone/lua_spell.cpp +++ b/zone/lua_spell.cpp @@ -406,7 +406,7 @@ int Lua_Spell::GetSpellGroup() { int Lua_Spell::GetPowerfulFlag() { Lua_Safe_Call_Int(); - return self->powerful_flag; + return self->no_resist; } int Lua_Spell::GetCastRestriction() { @@ -436,7 +436,7 @@ int Lua_Spell::GetAEMaxTargets() { int Lua_Spell::GetMaxTargets() { Lua_Safe_Call_Int(); - return self->maxtargets; + return self->no_heal_damage_item_mod; } bool Lua_Spell::GetPersistDeath() { diff --git a/zone/map.cpp b/zone/map.cpp index d4bb5a268..29a386331 100644 --- a/zone/map.cpp +++ b/zone/map.cpp @@ -12,6 +12,48 @@ #include #include + +uint32 EstimateDeflateBuffer(uint32_t len) { + z_stream zstream; + memset(&zstream, 0, sizeof(zstream)); + + zstream.zalloc = Z_NULL; + zstream.zfree = Z_NULL; + zstream.opaque = Z_NULL; + if (deflateInit(&zstream, Z_FINISH) != Z_OK) + return 0; + + return deflateBound(&zstream, len); +} + +uint32_t DeflateData(const char *buffer, uint32_t len, char *out_buffer, uint32_t out_len_max) { + z_stream zstream; + memset(&zstream, 0, sizeof(zstream)); + int zerror; + + zstream.next_in = const_cast(reinterpret_cast(buffer)); + zstream.avail_in = len; + zstream.zalloc = Z_NULL; + zstream.zfree = Z_NULL; + zstream.opaque = Z_NULL; + deflateInit(&zstream, Z_FINISH); + + zstream.next_out = reinterpret_cast(out_buffer); + zstream.avail_out = out_len_max; + zerror = deflate(&zstream, Z_FINISH); + + if (zerror == Z_STREAM_END) + { + deflateEnd(&zstream); + return (uint32_t)zstream.total_out; + } + else + { + zerror = deflateEnd(&zstream); + return 0; + } +} + uint32 InflateData(const char* buffer, uint32 len, char* out_buffer, uint32 out_len_max) { z_stream zstream; int zerror = 0; @@ -64,7 +106,7 @@ Map::~Map() { float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const { if (!imp) - return false; + return BEST_Z_INVALID; glm::vec3 tmp; if(!result) @@ -93,6 +135,41 @@ float Map::FindBestZ(glm::vec3 &start, glm::vec3 *result) const { return BEST_Z_INVALID; } +float Map::FindClosestZ(glm::vec3 &start, glm::vec3 *result) const { + // Unlike FindBestZ, this method finds the closest Z value above or below the specified point. + // + if (!imp) + return false; + + float ClosestZ = BEST_Z_INVALID; + + glm::vec3 tmp; + if (!result) + result = &tmp; + + glm::vec3 from(start.x, start.y, start.z); + glm::vec3 to(start.x, start.y, BEST_Z_INVALID); + float hit_distance; + bool hit = false; + + // first check is below us + hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance); + if (hit) { + ClosestZ = result->z; + + } + + // Find nearest Z above us + to.z = -BEST_Z_INVALID; + hit = imp->rm->raycast((const RmReal*)&from, (const RmReal*)&to, (RmReal*)result, nullptr, &hit_distance); + if (hit) { + if (std::abs(from.z - result->z) < std::abs(ClosestZ - from.z)) + return result->z; + } + + return ClosestZ; +} + bool Map::LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const { if(!imp) return false; @@ -192,13 +269,12 @@ bool Map::CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const { } Map *Map::LoadMapFile(std::string file) { - std::string filename = MAP_DIR; - filename += "/"; + std::string filename = Config->MapDir; std::transform(file.begin(), file.end(), file.begin(), ::tolower); filename += file; filename += ".map"; - Map *m = new Map(); + auto m = new Map(); if (m->Load(filename)) { return m; } @@ -207,7 +283,18 @@ Map *Map::LoadMapFile(std::string file) { return nullptr; } -bool Map::Load(std::string filename) { +#ifdef USE_MAP_MMFS +bool Map::Load(std::string filename, bool force_mmf_overwrite) +{ + if (LoadMMF(filename, force_mmf_overwrite)) { + Log.Out(Logs::General, Logs::Zone_Server, "Zone map mmf found - using it in lieu of '%s'", filename.c_str()); + return true; + } +#else +bool Map::Load(std::string filename) +{ +#endif /*USE_MAP_MMFS*/ + FILE *f = fopen(filename.c_str(), "rb"); if(f) { uint32 version; @@ -219,10 +306,22 @@ bool Map::Load(std::string filename) { if(version == 0x01000000) { bool v = LoadV1(f); fclose(f); + +#ifdef USE_MAP_MMFS + if (v) + return SaveMMF(filename, force_mmf_overwrite); +#endif /*USE_MAP_MMFS*/ + return v; } else if(version == 0x02000000) { bool v = LoadV2(f); fclose(f); + +#ifdef USE_MAP_MMFS + if (v) + return SaveMMF(filename, force_mmf_overwrite); +#endif /*USE_MAP_MMFS*/ + return v; } else { fclose(f); @@ -377,7 +476,9 @@ bool Map::LoadV2(FILE *f) { buf += sizeof(float); std::vector verts; + verts.reserve(vert_count); std::vector indices; + indices.reserve(ind_count); for (uint32 i = 0; i < vert_count; ++i) { float x; @@ -393,16 +494,12 @@ bool Map::LoadV2(FILE *f) { z = *(float*)buf; buf += sizeof(float); - glm::vec3 vert(x, y, z); - verts.push_back(vert); + verts.emplace_back(x, y, z); } for (uint32 i = 0; i < ind_count; ++i) { - uint32 index; - index = *(uint32*)buf; + indices.emplace_back(*(uint32 *)buf); buf += sizeof(uint32); - - indices.push_back(index); } for (uint32 i = 0; i < nc_vert_count; ++i) { @@ -425,7 +522,7 @@ bool Map::LoadV2(FILE *f) { uint32 poly_count = *(uint32*)buf; buf += sizeof(uint32); - me->verts.resize(vert_count); + me->verts.reserve(vert_count); for (uint32 j = 0; j < vert_count; ++j) { float x = *(float*)buf; buf += sizeof(float); @@ -434,10 +531,10 @@ bool Map::LoadV2(FILE *f) { float z = *(float*)buf; buf += sizeof(float); - me->verts[j] = glm::vec3(x, y, z); + me->verts.emplace_back(x, y, z); } - me->polys.resize(poly_count); + me->polys.reserve(poly_count); for (uint32 j = 0; j < poly_count; ++j) { uint32 v1 = *(uint32*)buf; buf += sizeof(uint32); @@ -453,7 +550,7 @@ bool Map::LoadV2(FILE *f) { p.v2 = v2; p.v3 = v3; p.vis = vis; - me->polys[j] = p; + me->polys.push_back(p); } models[name] = std::move(me); @@ -492,6 +589,8 @@ bool Map::LoadV2(FILE *f) { auto &mod_verts = model->verts; for (uint32 j = 0; j < mod_polys.size(); ++j) { auto ¤t_poly = mod_polys[j]; + if (current_poly.vis == 0) + continue; auto v1 = mod_verts[current_poly.v1]; auto v2 = mod_verts[current_poly.v2]; auto v3 = mod_verts[current_poly.v3]; @@ -508,27 +607,13 @@ bool Map::LoadV2(FILE *f) { TranslateVertex(v2, x, y, z); TranslateVertex(v3, x, y, z); - float t = v1.x; - v1.x = v1.y; - v1.y = t; + verts.emplace_back(v1.y, v1.x, v1.z); // x/y swapped + verts.emplace_back(v2.y, v2.x, v2.z); + verts.emplace_back(v3.y, v3.x, v3.z); - t = v2.x; - v2.x = v2.y; - v2.y = t; - - t = v3.x; - v3.x = v3.y; - v3.y = t; - - if (current_poly.vis != 0) { - verts.push_back(v1); - verts.push_back(v2); - verts.push_back(v3); - - indices.push_back((uint32)verts.size() - 3); - indices.push_back((uint32)verts.size() - 2); - indices.push_back((uint32)verts.size() - 1); - } + indices.emplace_back((uint32)verts.size() - 3); + indices.emplace_back((uint32)verts.size() - 2); + indices.emplace_back((uint32)verts.size() - 1); } } @@ -596,6 +681,8 @@ bool Map::LoadV2(FILE *f) { for (size_t k = 0; k < model->polys.size(); ++k) { auto &poly = model->polys[k]; + if (poly.vis == 0) + continue; glm::vec3 v1, v2, v3; v1 = model->verts[poly.v1]; @@ -658,27 +745,13 @@ bool Map::LoadV2(FILE *f) { TranslateVertex(v2, x, y, z); TranslateVertex(v3, x, y, z); - float t = v1.x; - v1.x = v1.y; - v1.y = t; + verts.emplace_back(v1.y, v1.x, v1.z); // x/y swapped + verts.emplace_back(v2.y, v2.x, v2.z); + verts.emplace_back(v3.y, v3.x, v3.z); - t = v2.x; - v2.x = v2.y; - v2.y = t; - - t = v3.x; - v3.x = v3.y; - v3.y = t; - - if (poly.vis != 0) { - verts.push_back(v1); - verts.push_back(v2); - verts.push_back(v3); - - indices.push_back((uint32)verts.size() - 3); - indices.push_back((uint32)verts.size() - 2); - indices.push_back((uint32)verts.size() - 1); - } + indices.emplace_back((uint32)verts.size() - 3); + indices.emplace_back((uint32)verts.size() - 2); + indices.emplace_back((uint32)verts.size() - 1); } } } @@ -724,18 +797,18 @@ bool Map::LoadV2(FILE *f) { float QuadVertex4Z = QuadVertex1Z; uint32 current_vert = (uint32)verts.size() + 3; - verts.push_back(glm::vec3(QuadVertex1X, QuadVertex1Y, QuadVertex1Z)); - verts.push_back(glm::vec3(QuadVertex2X, QuadVertex2Y, QuadVertex2Z)); - verts.push_back(glm::vec3(QuadVertex3X, QuadVertex3Y, QuadVertex3Z)); - verts.push_back(glm::vec3(QuadVertex4X, QuadVertex4Y, QuadVertex4Z)); + verts.emplace_back(QuadVertex1X, QuadVertex1Y, QuadVertex1Z); + verts.emplace_back(QuadVertex2X, QuadVertex2Y, QuadVertex2Z); + verts.emplace_back(QuadVertex3X, QuadVertex3Y, QuadVertex3Z); + verts.emplace_back(QuadVertex4X, QuadVertex4Y, QuadVertex4Z); - indices.push_back(current_vert); - indices.push_back(current_vert - 2); - indices.push_back(current_vert - 1); + indices.emplace_back(current_vert); + indices.emplace_back(current_vert - 2); + indices.emplace_back(current_vert - 1); - indices.push_back(current_vert); - indices.push_back(current_vert - 3); - indices.push_back(current_vert - 2); + indices.emplace_back(current_vert); + indices.emplace_back(current_vert - 3); + indices.emplace_back(current_vert - 2); } else { //read flags @@ -790,7 +863,7 @@ bool Map::LoadV2(FILE *f) { } else { i1 = (uint32)verts.size(); - verts.push_back(glm::vec3(QuadVertex1X, QuadVertex1Y, QuadVertex1Z)); + verts.emplace_back(QuadVertex1X, QuadVertex1Y, QuadVertex1Z); cur_verts[std::make_tuple(QuadVertex1X, QuadVertex1Y, QuadVertex1Z)] = i1; } @@ -801,7 +874,7 @@ bool Map::LoadV2(FILE *f) { } else { i2 = (uint32)verts.size(); - verts.push_back(glm::vec3(QuadVertex2X, QuadVertex2Y, QuadVertex2Z)); + verts.emplace_back(QuadVertex2X, QuadVertex2Y, QuadVertex2Z); cur_verts[std::make_tuple(QuadVertex2X, QuadVertex2Y, QuadVertex2Z)] = i2; } @@ -812,7 +885,7 @@ bool Map::LoadV2(FILE *f) { } else { i3 = (uint32)verts.size(); - verts.push_back(glm::vec3(QuadVertex3X, QuadVertex3Y, QuadVertex3Z)); + verts.emplace_back(QuadVertex3X, QuadVertex3Y, QuadVertex3Z); cur_verts[std::make_tuple(QuadVertex3X, QuadVertex3Y, QuadVertex3Z)] = i3; } @@ -823,17 +896,17 @@ bool Map::LoadV2(FILE *f) { } else { i4 = (uint32)verts.size(); - verts.push_back(glm::vec3(QuadVertex4X, QuadVertex4Y, QuadVertex4Z)); + verts.emplace_back(QuadVertex4X, QuadVertex4Y, QuadVertex4Z); cur_verts[std::make_tuple(QuadVertex4X, QuadVertex4Y, QuadVertex4Z)] = i4; } - indices.push_back(i4); - indices.push_back(i2); - indices.push_back(i3); + indices.emplace_back(i4); + indices.emplace_back(i2); + indices.emplace_back(i3); - indices.push_back(i4); - indices.push_back(i1); - indices.push_back(i2); + indices.emplace_back(i4); + indices.emplace_back(i1); + indices.emplace_back(i2); } } } @@ -862,18 +935,18 @@ bool Map::LoadV2(FILE *f) { void Map::RotateVertex(glm::vec3 &v, float rx, float ry, float rz) { glm::vec3 nv = v; - nv.y = (cos(rx) * v.y) - (sin(rx) * v.z); - nv.z = (sin(rx) * v.y) + (cos(rx) * v.z); + nv.y = (std::cos(rx) * v.y) - (std::sin(rx) * v.z); + nv.z = (std::sin(rx) * v.y) + (std::cos(rx) * v.z); v = nv; - nv.x = (cos(ry) * v.x) + (sin(ry) * v.z); - nv.z = -(sin(ry) * v.x) + (cos(ry) * v.z); + nv.x = (std::cos(ry) * v.x) + (std::sin(ry) * v.z); + nv.z = -(std::sin(ry) * v.x) + (std::cos(ry) * v.z); v = nv; - nv.x = (cos(rz) * v.x) - (sin(rz) * v.y); - nv.y = (sin(rz) * v.x) + (cos(rz) * v.y); + nv.x = (std::cos(rz) * v.x) - (std::sin(rz) * v.y); + nv.y = (std::sin(rz) * v.x) + (std::cos(rz) * v.y); v = nv; } @@ -889,3 +962,199 @@ void Map::TranslateVertex(glm::vec3 &v, float tx, float ty, float tz) { v.y = v.y + ty; v.z = v.z + tz; } + +#ifdef USE_MAP_MMFS +inline void strip_map_extension(std::string& map_file_name) +{ + auto ext_off = map_file_name.find(".map"); + if (ext_off != std::string::npos) + map_file_name.erase(ext_off, strlen(".map")); +} + +inline bool add_mmf_extension(std::string& mmf_file_name) +{ + if (mmf_file_name.empty()) + return false; + + mmf_file_name.append(".mmf"); + size_t dot_check = std::count(mmf_file_name.begin(), mmf_file_name.end(), '.'); + + return (dot_check == 1); +} + +bool Map::LoadMMF(const std::string& map_file_name, bool force_mmf_overwrite) +{ + if (force_mmf_overwrite) + return false; + + std::string mmf_file_name = map_file_name; + strip_map_extension(mmf_file_name); + if (!add_mmf_extension(mmf_file_name)) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s'", mmf_file_name.c_str()); + return false; + } + + FILE *f = fopen(mmf_file_name.c_str(), "rb"); + if (!f) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - could not open file", mmf_file_name.c_str()); + return false; + } + + uint32 file_version; + if (fread(&file_version, sizeof(uint32), 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@file_version", mmf_file_name.c_str()); + return false; + } + + uint32 rm_buffer_size; + if (fread(&rm_buffer_size, sizeof(uint32), 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@rm_buffer_size", mmf_file_name.c_str()); + return false; + } + + uint32 rm_buffer_crc32; + if (fread(&rm_buffer_crc32, sizeof(uint32), 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@rm_buffer_crc32", mmf_file_name.c_str()); + return false; + } + if (rm_buffer_crc32 != /*crc32_check*/ 0) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - bad rm_buffer checksum", mmf_file_name.c_str()); + return false; + } + + uint32 mmf_buffer_size; + if (fread(&mmf_buffer_size, sizeof(uint32), 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@mmf_buffer_size", mmf_file_name.c_str()); + return false; + } + + std::vector mmf_buffer(mmf_buffer_size); + if (fread(mmf_buffer.data(), mmf_buffer_size, 1, f) != 1) { + fclose(f); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - f@mmf_buffer", mmf_file_name.c_str()); + return false; + } + + fclose(f); + + std::vector rm_buffer(rm_buffer_size); + uint32 v = InflateData(mmf_buffer.data(), mmf_buffer_size, rm_buffer.data(), rm_buffer_size); + + if (imp) { + imp->rm->release(); + imp->rm = nullptr; + } + else { + imp = new impl; + } + + bool load_success = false; + imp->rm = loadRaycastMesh(rm_buffer, load_success); + if (imp->rm && !load_success) { + imp->rm->release(); + imp->rm = nullptr; + } + + if (!imp->rm) { + delete imp; + imp = nullptr; + Log.Out(Logs::General, Logs::Zone_Server, "Failed to load Map MMF file: '%s' - null RaycastMesh", mmf_file_name.c_str()); + return false; + } + + return true; +} + +bool Map::SaveMMF(const std::string& map_file_name, bool force_mmf_overwrite) +{ + if (!imp || !imp->rm) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file - No implementation (map_file_name: '%s')", map_file_name.c_str()); + return false; + } + + std::string mmf_file_name = map_file_name; + strip_map_extension(mmf_file_name); + if (!add_mmf_extension(mmf_file_name)) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s'", mmf_file_name.c_str()); + return false; + } + + FILE* f = fopen(mmf_file_name.c_str(), "rb"); + if (f) { + fclose(f); + if (!force_mmf_overwrite) + return true; + } + + std::vector rm_buffer; // size set in MyRaycastMesh::serialize() + serializeRaycastMesh(imp->rm, rm_buffer); + if (rm_buffer.empty()) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - empty RaycastMesh buffer", mmf_file_name.c_str()); + return false; + } + + uint32 rm_buffer_size = rm_buffer.size(); + uint32 mmf_buffer_size = EstimateDeflateBuffer(rm_buffer.size()); + + std::vector mmf_buffer(mmf_buffer_size); + + mmf_buffer_size = DeflateData(rm_buffer.data(), rm_buffer.size(), mmf_buffer.data(), mmf_buffer.size()); + if (!mmf_buffer_size) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - null MMF buffer size", mmf_file_name.c_str()); + return false; + } + + f = fopen(mmf_file_name.c_str(), "wb"); + if (!f) { + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - could not open file", mmf_file_name.c_str()); + return false; + } + + uint32 file_version = 0; + if (fwrite(&file_version, sizeof(uint32), 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@file_version", mmf_file_name.c_str()); + return false; + } + + if (fwrite(&rm_buffer_size, sizeof(uint32), 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@rm_buffer_size", mmf_file_name.c_str()); + return false; + } + + uint32 rm_buffer_crc32 = 0; + if (fwrite(&rm_buffer_crc32, sizeof(uint32), 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@rm_buffer_crc32", mmf_file_name.c_str()); + return false; + } + + if (fwrite(&mmf_buffer_size, sizeof(uint32), 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@mmf_buffer_size", mmf_file_name.c_str()); + return false; + } + + if (fwrite(mmf_buffer.data(), mmf_buffer_size, 1, f) != 1) { + fclose(f); + std::remove(mmf_file_name.c_str()); + Log.Out(Logs::General, Logs::Zone_Server, "Failed to save Map MMF file: '%s' - f@mmf_buffer", mmf_file_name.c_str()); + return false; + } + + fclose(f); + + return true; +} + +#endif /*USE_MAP_MMFS*/ diff --git a/zone/map.h b/zone/map.h index 2bce1c6db..35b5baeda 100644 --- a/zone/map.h +++ b/zone/map.h @@ -25,8 +25,12 @@ #include "position.h" #include +#include "zone_config.h" + #define BEST_Z_INVALID -99999 +extern const ZoneConfig *Config; + class Map { public: @@ -34,10 +38,17 @@ public: ~Map(); float FindBestZ(glm::vec3 &start, glm::vec3 *result) const; + float FindClosestZ(glm::vec3 &start, glm::vec3 *result) const; 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; + +#ifdef USE_MAP_MMFS + bool Load(std::string filename, bool force_mmf_overwrite = false); +#else bool Load(std::string filename); +#endif + static Map *LoadMapFile(std::string file); private: void RotateVertex(glm::vec3 &v, float rx, float ry, float rz); @@ -46,6 +57,11 @@ private: bool LoadV1(FILE *f); bool LoadV2(FILE *f); +#ifdef USE_MAP_MMFS + bool LoadMMF(const std::string& map_file_name, bool force_mmf_overwrite); + bool SaveMMF(const std::string& map_file_name, bool force_mmf_overwrite); +#endif /*USE_MAP_MMFS*/ + struct impl; impl *imp; }; diff --git a/zone/merc.cpp b/zone/merc.cpp index 4609487cf..c787d00c8 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -18,7 +18,15 @@ #include "../common/string_util.h" #include "../common/rulesys.h" -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; + +#if EQDEBUG >= 12 + #define MercAI_DEBUG_Spells 25 +#elif EQDEBUG >= 9 + #define MercAI_DEBUG_Spells 10 +#else + #define MercAI_DEBUG_Spells -1 +#endif Merc::Merc(const NPCType* d, float x, float y, float z, float heading) : NPC(d, nullptr, glm::vec4(x, y, z, heading), 0, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000), check_target_timer(2000) @@ -42,7 +50,7 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading) _baseFR = d->FR; _basePR = d->PR; _baseCorrup = d->Corrup; - _OwnerClientVersion = static_cast(ClientVersion::Titanium); + _OwnerClientVersion = static_cast(EQEmu::versions::ClientVersion::Titanium); RestRegenHP = 0; RestRegenMana = 0; RestRegenEndurance = 0; @@ -62,8 +70,8 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading) rest_timer.Disable(); int r; - for(r = 0; r <= HIGHEST_SKILL; r++) { - skills[r] = database.GetSkillCap(GetClass(),(SkillUseTypes)r,GetLevel()); + for (r = 0; r <= EQEmu::skills::HIGHEST_SKILL; r++) { + skills[r] = database.GetSkillCap(GetClass(), (EQEmu::skills::SkillType)r, GetLevel()); } size = d->size; @@ -206,10 +214,10 @@ void Merc::CalcItemBonuses(StatBonuses* newbon) { unsigned int i; //should not include 21 (SLOT_AMMO) - for (i=0; iReqLevel) { @@ -448,11 +456,11 @@ void Merc::AddItemBonuses(const Item_Struct *item, StatBonuses* newbon) { else newbon->DSMitigation += item->DSMitigation; } - if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects + if (item->Worn.Effect>0 && (item->Worn.Type == EQEmu::item::ItemEffectWorn)) { // latent effects ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type); } - if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects + if (item->Focus.Effect>0 && (item->Focus.Type == EQEmu::item::ItemEffectFocus)) { // focus effects ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0); } @@ -504,7 +512,7 @@ void Merc::AddItemBonuses(const Item_Struct *item, StatBonuses* newbon) { } } - if (item->SkillModValue != 0 && item->SkillModType <= HIGHEST_SKILL){ + if (item->SkillModValue != 0 && item->SkillModType <= EQEmu::skills::HIGHEST_SKILL){ if ((item->SkillModValue > 0 && newbon->skillmod[item->SkillModType] < item->SkillModValue) || (item->SkillModValue < 0 && newbon->skillmod[item->SkillModType] > item->SkillModValue)) { @@ -558,7 +566,7 @@ void Merc::AddItemBonuses(const Item_Struct *item, StatBonuses* newbon) { } } - if (item->ExtraDmgSkill != 0 && item->ExtraDmgSkill <= HIGHEST_SKILL) { + if (item->ExtraDmgSkill != 0 && item->ExtraDmgSkill <= EQEmu::skills::HIGHEST_SKILL) { if((newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap)) newbon->SkillDamageAmount[item->ExtraDmgSkill] = RuleI(Character, ItemExtraDmgCap); else @@ -923,8 +931,8 @@ int32 Merc::CalcBaseManaRegen() int32 regen = 0; if (IsSitting()) { - if(HasSkill(SkillMeditate)) - regen = (((GetSkill(SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4; + if (HasSkill(EQEmu::skills::SkillMeditate)) + regen = (((GetSkill(EQEmu::skills::SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4; else regen = 2; } @@ -940,9 +948,9 @@ int32 Merc::CalcManaRegen() if (IsSitting()) { BuffFadeBySitModifier(); - if(HasSkill(SkillMeditate)) { + if (HasSkill(EQEmu::skills::SkillMeditate)) { this->_medding = true; - regen = ((GetSkill(SkillMeditate) / 10) + mana_regen); + regen = ((GetSkill(EQEmu::skills::SkillMeditate) / 10) + mana_regen); regen += spellbonuses.ManaRegen + itembonuses.ManaRegen; } else @@ -1010,7 +1018,7 @@ int32 Merc::CalcBaseEndurance() int32 sta_end = 0; int Stats = 0; - if(GetClientVersion() >= static_cast(ClientVersion::SoD) && RuleB(Character, SoDClientUseSoDHPManaEnd)) { + if (GetClientVersion() >= static_cast(EQEmu::versions::ClientVersion::SoD) && RuleB(Character, SoDClientUseSoDHPManaEnd)) { int HeroicStats = 0; Stats = ((GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4); @@ -1171,16 +1179,16 @@ void Merc::CalcRestState() { RestRegenEndurance = (GetMaxEndurance() * RuleI(Character, RestRegenPercent) / 100); } -bool Merc::HasSkill(SkillUseTypes skill_id) const { +bool Merc::HasSkill(EQEmu::skills::SkillType skill_id) const { return((GetSkill(skill_id) > 0) && CanHaveSkill(skill_id)); } -bool Merc::CanHaveSkill(SkillUseTypes skill_id) const { +bool Merc::CanHaveSkill(EQEmu::skills::SkillType skill_id) const { return(database.GetSkillCap(GetClass(), skill_id, RuleI(Character, MaxLevel)) > 0); //if you don't have it by max level, then odds are you never will? } -uint16 Merc::MaxSkill(SkillUseTypes skillid, uint16 class_, uint16 level) const { +uint16 Merc::MaxSkill(EQEmu::skills::SkillType skillid, uint16 class_, uint16 level) const { return(database.GetSkillCap(class_, skillid, level)); } @@ -1202,7 +1210,7 @@ void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { ns->spawn.IsMercenary = 1; UpdateActiveLight(); - ns->spawn.light = m_Light.Type.Active; + ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive]; /* // Wear Slots are not setup for Mercs yet @@ -1213,7 +1221,7 @@ void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { { continue; } - const Item_Struct* item = database.GetItem(equipment[i]); + const ItemBase* item = database.GetItem(equipment[i]); if(item) { ns->spawn.equipment[i].material = item->Material; @@ -1236,10 +1244,7 @@ void Merc::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { bool Merc::Process() { if(IsStunned() && stunned_timer.Check()) - { - this->stunned = false; - this->stunned_timer.Disable(); - } + Mob::UnStun(); if (GetDepop()) { @@ -1431,7 +1436,7 @@ void Merc::AI_Process() { if(RuleB(Combat, EnableFearPathing)) { CalculateNewFearpoint(); - if(curfp) { + if(currently_fleeing) { return; } } @@ -1463,14 +1468,16 @@ void Merc::AI_Process() { if(moved) { moved = false; - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); } } return; } + if (!(m_PlayerState & static_cast(PlayerState::Aggressive))) + SendAddPlayerState(PlayerState::Aggressive); + bool atCombatRange = false; float meleeDistance = GetMaxMeleeRangeToTarget(GetTarget()); @@ -1497,13 +1504,11 @@ void Merc::AI_Process() { SetRunAnimSpeed(0); if(moved) { - moved = false; - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); } } - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { if(!IsMoving() && GetClass() == ROGUE && !BehindMob(GetTarget(), GetX(), GetY())) { @@ -1554,24 +1559,24 @@ void Merc::AI_Process() { //try main hand first if(attack_timer.Check()) { - Attack(GetTarget(), MainPrimary); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary); bool tripleSuccess = false; if(GetOwner() && GetTarget() && CanThisClassDoubleAttack()) { if(GetOwner()) { - Attack(GetTarget(), MainPrimary, true); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, true); } if(GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_TRIPLE)) { tripleSuccess = true; - Attack(GetTarget(), MainPrimary, true); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, true); } //quad attack, does this belong here?? if(GetOwner() && GetTarget() && GetSpecialAbility(SPECATK_QUAD)) { - Attack(GetTarget(), MainPrimary, true); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, true); } } @@ -1583,8 +1588,8 @@ void Merc::AI_Process() { if(zone->random.Roll(flurrychance)) { Message_StringID(MT_NPCFlurry, YOU_FLURRY); - Attack(GetTarget(), MainPrimary, false); - Attack(GetTarget(), MainPrimary, false); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, false); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, false); } } @@ -1593,7 +1598,7 @@ void Merc::AI_Process() { if (GetTarget() && ExtraAttackChanceBonus) { if(zone->random.Roll(ExtraAttackChanceBonus)) { - Attack(GetTarget(), MainPrimary, false); + Attack(GetTarget(), EQEmu::legacy::SlotPrimary, false); } } } @@ -1616,23 +1621,24 @@ void Merc::AI_Process() { int weapontype = 0; // No weapon type bool bIsFist = true; - if(bIsFist || ((weapontype != ItemType2HSlash) && (weapontype != ItemType2HPiercing) && (weapontype != ItemType2HBlunt))) + // why are we checking 'weapontype' when we know it's set to '0' above? + if (bIsFist || ((weapontype != EQEmu::item::ItemType2HSlash) && (weapontype != EQEmu::item::ItemType2HPiercing) && (weapontype != EQEmu::item::ItemType2HBlunt))) { float DualWieldProbability = 0.0f; int16 Ambidexterity = aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity; - DualWieldProbability = (GetSkill(SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f; // 78.0 max + DualWieldProbability = (GetSkill(EQEmu::skills::SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f; // 78.0 max int16 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance; DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f; // Max 78% of DW if (zone->random.Roll(DualWieldProbability)) { - Attack(GetTarget(), MainSecondary); // Single attack with offhand + Attack(GetTarget(), EQEmu::legacy::SlotSecondary); // Single attack with offhand if(CanThisClassDoubleAttack()) { if(GetTarget() && GetTarget()->GetHP() > -10) - Attack(GetTarget(), MainSecondary); // Single attack with offhand + Attack(GetTarget(), EQEmu::legacy::SlotSecondary); // Single attack with offhand } } } @@ -1648,7 +1654,7 @@ void Merc::AI_Process() { AI_PursueCastCheck(); } - if (AImovement_timer->Check()) + if (AI_movement_timer->Check()) { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName()); @@ -1684,10 +1690,13 @@ void Merc::AI_Process() { confidence_timer.Disable(); _check_confidence = false; + if (m_PlayerState & static_cast(PlayerState::Aggressive)) + SendRemovePlayerState(PlayerState::Aggressive); + if(!check_target_timer.Enabled()) check_target_timer.Start(2000, false); - if(!IsMoving() && AIthink_timer->Check() && !spellend_timer.Enabled()) + if(!IsMoving() && AI_think_timer->Check() && !spellend_timer.Enabled()) { //TODO: Implement passive stances. //if(GetStance() != MercStancePassive) { @@ -1698,7 +1707,7 @@ void Merc::AI_Process() { } } - if(AImovement_timer->Check()) + if(AI_movement_timer->Check()) { if(GetFollowID()) { @@ -1707,7 +1716,7 @@ void Merc::AI_Process() { if(follow) { float dist = DistanceSquared(m_Position, follow->GetPosition()); - float speed = GetRunspeed(); + int speed = GetRunspeed(); if(dist < GetFollowDistance() + 1000) speed = GetWalkspeed(); @@ -1724,9 +1733,8 @@ void Merc::AI_Process() { { if(moved) { - moved=false; - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); + moved = false; } } } @@ -1739,7 +1747,7 @@ void Merc::AI_Start(int32 iMoveDelay) { if (!pAIControlled) return; - if (merc_spells.size() == 0) { + if (merc_spells.empty()) { AIautocastspell_timer->SetTimer(1000); AIautocastspell_timer->Disable(); } else { @@ -1769,7 +1777,7 @@ bool Merc::AI_EngagedCastCheck() { { AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. - Log.Out(Logs::Detail, Logs::AI, "Engaged autocast check triggered (MERCS)."); + Log.Out(Logs::Detail, Logs::AI, "Merc Engaged autocast check triggered"); int8 mercClass = GetClass(); @@ -1823,8 +1831,8 @@ bool Merc::AI_IdleCastCheck() { bool failedToCast = false; if (AIautocastspell_timer->Check(false)) { -#if MobAI_DEBUG_Spells >= 25 - std::cout << "Non-Engaged autocast check triggered: " << this->GetCleanName() << std::endl; +#if MercAI_DEBUG_Spells >= 25 + Log.Out(Logs::Detail, Logs::AI, "Merc Non-Engaged autocast check triggered: %s", this->GetCleanName()); #endif AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. @@ -1955,7 +1963,7 @@ bool Merc::AIDoSpellCast(uint16 spellid, Mob* tar, int32 mana_cost, uint32* oDon SendPosition(); SetMoving(false); - result = CastSpell(spellid, tar->GetID(), 1, -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0); + result = CastSpell(spellid, tar->GetID(), EQEmu::CastingSlot::Gem2, -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0); if(IsCasting() && IsSitting()) Stand(); @@ -2142,7 +2150,8 @@ bool Merc::AICastSpell(int8 iChance, int32 iSpellTypes) { std::list buffSpellList = GetMercSpellsBySpellType(this, SpellType_Buff); - for(std::list::iterator itr = buffSpellList.begin(); itr != buffSpellList.end(); ++itr) { + for (auto itr = buffSpellList.begin(); + itr != buffSpellList.end(); ++itr) { MercSpell selectedMercSpell = *itr; if(!((spells[selectedMercSpell.spellid].targettype == ST_Target || spells[selectedMercSpell.spellid].targettype == ST_Pet || @@ -2301,14 +2310,15 @@ bool Merc::AICastSpell(int8 iChance, int32 iSpellTypes) { std::list buffSpellList = GetMercSpellsBySpellType(this, SpellType_InCombatBuff); Mob* tar = this; - for(std::list::iterator itr = buffSpellList.begin(); itr != buffSpellList.end(); ++itr) { + for (auto itr = buffSpellList.begin(); + itr != buffSpellList.end(); ++itr) { MercSpell selectedMercSpell = *itr; if(!(spells[selectedMercSpell.spellid].targettype == ST_Self)) { continue; } - if(spells[selectedMercSpell.spellid].skill == SkillBackstab && spells[selectedMercSpell.spellid].targettype == ST_Self) { + if (spells[selectedMercSpell.spellid].skill == EQEmu::skills::SkillBackstab && spells[selectedMercSpell.spellid].targettype == ST_Self) { if(!hidden) { continue; } @@ -2446,7 +2456,7 @@ void Merc::CheckHateList() { std::list npc_list; entity_list.GetNPCList(npc_list); - for(std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { + for (auto itr = npc_list.begin(); itr != npc_list.end(); ++itr) { NPC* npc = *itr; float dist = DistanceSquaredNoZ(m_Position, npc->GetPosition()); int radius = RuleI(Mercs, AggroRadius); @@ -2499,7 +2509,7 @@ bool Merc::CheckAENuke(Merc* caster, Mob* tar, uint16 spell_id, uint8 &numTarget std::list npc_list; entity_list.GetNPCList(npc_list); - for(std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { + for (auto itr = npc_list.begin(); itr != npc_list.end(); ++itr) { NPC* npc = *itr; if(DistanceSquaredNoZ(npc->GetPosition(), tar->GetPosition()) <= spells[spell_id].aoerange * spells[spell_id].aoerange) { @@ -2537,15 +2547,15 @@ int16 Merc::GetFocusEffect(focusType type, uint16 spell_id) { //Check if item focus effect exists for the client. if (itembonuses.FocusEffects[type]){ - const Item_Struct* TempItem = 0; - const Item_Struct* UsedItem = 0; + const EQEmu::ItemBase* TempItem = 0; + const EQEmu::ItemBase* UsedItem = 0; uint16 UsedFocusID = 0; int16 Total = 0; int16 focus_max = 0; int16 focus_max_real = 0; //item focus - for (int x = 0; x < EmuConstants::EQUIPMENT_SIZE; ++x) + for (int x = 0; x < EQEmu::legacy::EQUIPMENT_SIZE; ++x) { TempItem = nullptr; if (equipment[x] == 0) @@ -2679,7 +2689,7 @@ int16 Merc::GetFocusEffect(focusType type, uint16 spell_id) { int32 Merc::GetActSpellCost(uint16 spell_id, int32 cost) { // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell - if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) + if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%17) - 1] >= GetLevel() - 5) { int16 mana_back = this->itembonuses.Clairvoyance * zone->random.Int(1, 100) / 100; // Doesnt generate mana, so best case is a free spell @@ -3058,7 +3068,8 @@ MercSpell Merc::GetBestMercSpellForVeryFastHeal(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsVeryFastHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3090,7 +3101,8 @@ MercSpell Merc::GetBestMercSpellForFastHeal(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsFastHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3122,7 +3134,8 @@ MercSpell Merc::GetBestMercSpellForHealOverTime(Merc* caster) { if(caster) { std::list mercHoTSpellList = GetMercSpellsForSpellEffect(caster, SE_HealOverTime); - for(std::list::iterator mercSpellListItr = mercHoTSpellList.begin(); mercSpellListItr != mercHoTSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercHoTSpellList.begin(); mercSpellListItr != mercHoTSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsHealOverTimeSpell(mercSpellListItr->spellid)) { @@ -3162,7 +3175,8 @@ MercSpell Merc::GetBestMercSpellForPercentageHeal(Merc* caster) { if(caster && caster->AI_HasSpells()) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsCompleteHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3194,7 +3208,8 @@ MercSpell Merc::GetBestMercSpellForRegularSingleTargetHeal(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsRegularSingleTargetHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3226,7 +3241,8 @@ MercSpell Merc::GetFirstMercSpellForSingleTargetHeal(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if((IsRegularSingleTargetHealSpell(mercSpellListItr->spellid) || IsFastHealSpell(mercSpellListItr->spellid)) @@ -3259,7 +3275,8 @@ MercSpell Merc::GetBestMercSpellForGroupHeal(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CurrentHP); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsRegularGroupHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3291,7 +3308,8 @@ MercSpell Merc::GetBestMercSpellForGroupHealOverTime(Merc* caster) { if(caster) { std::list mercHoTSpellList = GetMercSpellsForSpellEffect(caster, SE_HealOverTime); - for(std::list::iterator mercSpellListItr = mercHoTSpellList.begin(); mercSpellListItr != mercHoTSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercHoTSpellList.begin(); mercSpellListItr != mercHoTSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsGroupHealOverTimeSpell(mercSpellListItr->spellid)) { @@ -3331,7 +3349,8 @@ MercSpell Merc::GetBestMercSpellForGroupCompleteHeal(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_CompleteHeal); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsGroupCompleteHealSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3363,7 +3382,8 @@ MercSpell Merc::GetBestMercSpellForAETaunt(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_Taunt); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if((spells[mercSpellListItr->spellid].targettype == ST_AECaster || spells[mercSpellListItr->spellid].targettype == ST_AETarget @@ -3397,7 +3417,8 @@ MercSpell Merc::GetBestMercSpellForTaunt(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_Taunt); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if((spells[mercSpellListItr->spellid].targettype == ST_Target) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3429,7 +3450,8 @@ MercSpell Merc::GetBestMercSpellForHate(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_InstantHate); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { result.spellid = mercSpellListItr->spellid; @@ -3485,7 +3507,7 @@ MercSpell Merc::GetBestMercSpellForCure(Merc* caster, Mob *tar) { //Check for group cure first if(countNeedsCured > 2) { - for(std::list::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) { + for (auto itr = cureList.begin(); itr != cureList.end(); ++itr) { MercSpell selectedMercSpell = *itr; if(IsGroupSpell(itr->spellid) && CheckSpellRecastTimers(caster, itr->spellid)) { @@ -3525,7 +3547,7 @@ MercSpell Merc::GetBestMercSpellForCure(Merc* caster, Mob *tar) { //no group cure for target- try to find single target spell if(!spellSelected) { - for(std::list::iterator itr = cureList.begin(); itr != cureList.end(); ++itr) { + for (auto itr = cureList.begin(); itr != cureList.end(); ++itr) { MercSpell selectedMercSpell = *itr; if(CheckSpellRecastTimers(caster, itr->spellid)) { @@ -3581,7 +3603,8 @@ MercSpell Merc::GetBestMercSpellForStun(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsForSpellEffect(caster, SE_Stun); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { result.spellid = mercSpellListItr->spellid; @@ -3676,7 +3699,8 @@ MercSpell Merc::GetBestMercSpellForTargetedAENuke(Merc* caster, Mob* tar) { if(caster) { std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsAENukeSpell(mercSpellListItr->spellid) && !IsAERainNukeSpell(mercSpellListItr->spellid) && !IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3727,7 +3751,8 @@ MercSpell Merc::GetBestMercSpellForPBAENuke(Merc* caster, Mob* tar) { if(caster) { std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { uint8 numTargets = 0; @@ -3777,7 +3802,8 @@ MercSpell Merc::GetBestMercSpellForAERainNuke(Merc* caster, Mob* tar) { if(caster) { std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsAERainNukeSpell(mercSpellListItr->spellid) && zone->random.Roll(castChance) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { uint8 numTargets = 0; @@ -3815,7 +3841,8 @@ MercSpell Merc::GetBestMercSpellForNuke(Merc* caster) { if(caster) { std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsPureNukeSpell(mercSpellListItr->spellid) && !IsAENukeSpell(mercSpellListItr->spellid) && zone->random.Roll(castChance) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3858,7 +3885,8 @@ MercSpell Merc::GetBestMercSpellForNukeByTargetResists(Merc* caster, Mob* target std::list mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke); - for(std::list::iterator mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); ++mercSpellListItr) { + for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); + ++mercSpellListItr) { // Assuming all the spells have been loaded into this list by level and in descending order if(IsPureNukeSpell(mercSpellListItr->spellid) && !IsAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { @@ -3987,7 +4015,7 @@ bool Merc::UseDiscipline(int32 spell_id, int32 target) { if(IsCasting()) InterruptSpell(); - CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT); + CastSpell(spell_id, target, EQEmu::CastingSlot::Discipline); return(true); } @@ -4097,7 +4125,7 @@ bool Merc::CheckAETaunt() { std::list npc_list; entity_list.GetNPCList(npc_list); - for(std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { + for (auto itr = npc_list.begin(); itr != npc_list.end(); ++itr) { NPC* npc = *itr; float dist = DistanceSquaredNoZ(m_Position, npc->GetPosition()); int range = GetActSpellRange(mercSpell.spellid, spells[mercSpell.spellid].range); @@ -4160,7 +4188,7 @@ bool Merc::TryHide() { return false; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer; sa_out->spawn_id = GetID(); sa_out->type = 0x03; @@ -4182,7 +4210,7 @@ bool Merc::CheckConfidence() { std::list npc_list; entity_list.GetNPCList(npc_list); - for(std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { + for (auto itr = npc_list.begin(); itr != npc_list.end(); ++itr) { NPC* mob = *itr; float ConRating = 1.0; int CurrentCon = 0; @@ -4400,11 +4428,11 @@ void Merc::DoClassAttacks(Mob *target) { DoAnim(animKick); int32 dmg = 0; - if(GetWeaponDamage(target, (const Item_Struct*)nullptr) <= 0){ + if (GetWeaponDamage(target, (const EQEmu::ItemBase*)nullptr) <= 0){ dmg = -5; } else{ - if(target->CheckHitChance(this, SkillKick, 0)) { + if (target->CheckHitChance(this, EQEmu::skills::SkillKick, 0)) { if(RuleB(Combat, UseIntervalAC)) dmg = GetKickDamage(); else @@ -4414,7 +4442,7 @@ void Merc::DoClassAttacks(Mob *target) { } reuse = KickReuseTime * 1000; - DoSpecialAttackDamage(target, SkillKick, dmg, 1, -1, reuse); + DoSpecialAttackDamage(target, EQEmu::skills::SkillKick, dmg, 1, -1, reuse); did_attack = true; } else @@ -4422,11 +4450,11 @@ void Merc::DoClassAttacks(Mob *target) { DoAnim(animTailRake); int32 dmg = 0; - if(GetWeaponDamage(target, (const Item_Struct*)nullptr) <= 0){ + if (GetWeaponDamage(target, (const EQEmu::ItemBase*)nullptr) <= 0){ dmg = -5; } else{ - if(target->CheckHitChance(this, SkillBash, 0)) { + if (target->CheckHitChance(this, EQEmu::skills::SkillBash, 0)) { if(RuleB(Combat, UseIntervalAC)) dmg = GetBashDamage(); else @@ -4435,7 +4463,7 @@ void Merc::DoClassAttacks(Mob *target) { } reuse = BashReuseTime * 1000; - DoSpecialAttackDamage(target, SkillBash, dmg, 1, -1, reuse); + DoSpecialAttackDamage(target, EQEmu::skills::SkillBash, dmg, 1, -1, reuse); did_attack = true; } } @@ -4446,7 +4474,7 @@ void Merc::DoClassAttacks(Mob *target) { classattack_timer.Start(reuse / HasteModifier); } -bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) +bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, int special) { if (!other) { SetTarget(nullptr); @@ -4457,7 +4485,7 @@ bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, boo return NPC::Attack(other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts); } -void Merc::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable, int8 buffslot, bool iBuffTic) +void Merc::Damage(Mob* other, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable, int8 buffslot, bool iBuffTic, int special) { if(IsDead() || IsCorpse()) return; @@ -4465,7 +4493,7 @@ void Merc::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attac if(spell_id==0) spell_id = SPELL_UNKNOWN; - NPC::Damage(other, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic); + NPC::Damage(other, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic, special); //Not needed since we're using NPC damage. //CommonDamage(other, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic); @@ -4498,7 +4526,7 @@ Mob* Merc::GetOwnerOrSelf() { return Result; } -bool Merc::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack_skill) +bool Merc::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::SkillType attack_skill) { if(!NPC::Death(killerMob, damage, spell, attack_skill)) { @@ -4659,7 +4687,7 @@ bool Merc::LoadMercSpells() { int16 attack_proc_spell = -1; int8 proc_chance = 0; - for (std::list::iterator mercSpellEntryItr = spellList.begin(); mercSpellEntryItr != spellList.end(); ++mercSpellEntryItr) { + for (auto mercSpellEntryItr = spellList.begin(); mercSpellEntryItr != spellList.end(); ++mercSpellEntryItr) { if (proficiency_id == mercSpellEntryItr->proficiencyid && GetLevel() >= mercSpellEntryItr->minlevel && GetLevel() <= mercSpellEntryItr->maxlevel && mercSpellEntryItr->spellid > 0) { MercSpell mercSpell; @@ -4680,7 +4708,7 @@ bool Merc::LoadMercSpells() { return a.slot > b.slot; }); - if (merc_spells.size() == 0) + if (merc_spells.empty()) AIautocastspell_timer->Disable(); else { HasAISpell = true; @@ -4717,7 +4745,7 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, if(npc_type_to_copy != nullptr) { //This is actually a very terrible method of assigning stats, and should be changed at some point. See the comment in merc's deconstructor. - NPCType* npc_type = new NPCType; + auto npc_type = new NPCType; memset(npc_type, 0, sizeof(NPCType)); memcpy(npc_type, npc_type_to_copy, sizeof(NPCType)); if(c && !updateFromDB) @@ -4763,7 +4791,7 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, npc_type->maxlevel = 0; //We should hard-set this to override scalerate's functionality in the NPC class when it is constructed. npc_type->no_target_hotkey = 1; - Merc* merc = new Merc(npc_type, c->GetX(), c->GetY(), c->GetZ(), 0); + auto merc = new Merc(npc_type, c->GetX(), c->GetY(), c->GetZ(), 0); merc->GiveNPCTypeData(npc_type); // for clean up, works a bit like pets if(merc) @@ -5018,12 +5046,12 @@ void Merc::ScaleStats(int scalepercent, bool setmax) { void Merc::UpdateMercAppearance() { // Copied from Bot Code: uint32 itemID = NO_ITEM; - uint8 materialFromSlot = _MaterialInvalid; - for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) { + uint8 materialFromSlot = EQEmu::textures::TextureInvalid; + for (int i = EQEmu::legacy::EQUIPMENT_BEGIN; i <= EQEmu::legacy::EQUIPMENT_END; ++i) { itemID = equipment[i]; if(itemID != NO_ITEM) { materialFromSlot = Inventory::CalcMaterialFromSlot(i); - if(materialFromSlot != _MaterialInvalid) + if (materialFromSlot != EQEmu::textures::TextureInvalid) this->SendWearChange(materialFromSlot); } } @@ -5034,18 +5062,18 @@ void Merc::UpdateMercAppearance() { void Merc::UpdateEquipmentLight() { - m_Light.Type.Equipment = 0; - m_Light.Level.Equipment = 0; + m_Light.Type[EQEmu::lightsource::LightEquipment] = 0; + m_Light.Level[EQEmu::lightsource::LightEquipment] = 0; - for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) { - if (index == MainAmmo) { continue; } + for (int index = SLOT_BEGIN; index < EQEmu::legacy::EQUIPMENT_SIZE; ++index) { + if (index == EQEmu::legacy::SlotAmmo) { continue; } auto item = database.GetItem(equipment[index]); if (item == nullptr) { continue; } - if (m_Light.IsLevelGreater(item->Light, m_Light.Type.Equipment)) { - m_Light.Type.Equipment = item->Light; - m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); + if (EQEmu::lightsource::IsLevelGreater(item->Light, m_Light.Type[EQEmu::lightsource::LightEquipment])) { + m_Light.Type[EQEmu::lightsource::LightEquipment] = item->Light; + m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } } @@ -5054,17 +5082,17 @@ void Merc::UpdateEquipmentLight() auto item = database.GetItem((*iter)->item_id); if (item == nullptr) { continue; } - if (item->ItemClass != ItemClassCommon) { continue; } + if (!item->IsClassCommon()) { continue; } if (item->Light < 9 || item->Light > 13) { continue; } - if (m_Light.TypeToLevel(item->Light)) + if (EQEmu::lightsource::TypeToLevel(item->Light)) general_light_type = item->Light; } - if (m_Light.IsLevelGreater(general_light_type, m_Light.Type.Equipment)) - m_Light.Type.Equipment = general_light_type; + if (EQEmu::lightsource::IsLevelGreater(general_light_type, m_Light.Type[EQEmu::lightsource::LightEquipment])) + m_Light.Type[EQEmu::lightsource::LightEquipment] = general_light_type; - m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); + m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } void Merc::AddItem(uint8 slot, uint32 item_id) { @@ -5120,109 +5148,109 @@ void Client::SendMercResponsePackets(uint32 ResponseType) SendMercMerchantResponsePacket(6); break; case 7: //You must dismiss your suspended mercenary before purchasing a new one! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(7); else //You have the maximum number of mercenaries. You must dismiss one before purchasing a new one! SendMercMerchantResponsePacket(6); break; case 8: //You can not purchase a mercenary because your group is full! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(8); else SendMercMerchantResponsePacket(7); break; case 9: //You can not purchase a mercenary because you are in combat! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) //Mercenary failed to spawn! SendMercMerchantResponsePacket(3); else SendMercMerchantResponsePacket(8); break; case 10: //You have recently dismissed a mercenary and must wait a few more seconds before you can purchase a new one! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) //Mercenary failed to spawn! SendMercMerchantResponsePacket(3); else SendMercMerchantResponsePacket(9); break; case 11: //An error occurred created your mercenary! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(9); else SendMercMerchantResponsePacket(10); break; case 12: //Upkeep Charge Message - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(10); else SendMercMerchantResponsePacket(11); break; case 13: // ??? - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(11); else SendMercMerchantResponsePacket(12); break; case 14: //You ran out of funds to pay for your mercenary! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(12); else SendMercMerchantResponsePacket(13); break; case 15: // ??? - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(13); else SendMercMerchantResponsePacket(14); break; case 16: //Your mercenary is about to be suspended due to insufficient funds! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(14); else SendMercMerchantResponsePacket(15); break; case 17: //There is no mercenary liaison nearby! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(15); else SendMercMerchantResponsePacket(16); break; case 18: //You are too far from the liaison! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(16); else SendMercMerchantResponsePacket(17); break; case 19: //You do not meet the requirements for that mercenary! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) SendMercMerchantResponsePacket(17); else SendMercMerchantResponsePacket(18); break; case 20: //You are unable to interact with the liaison! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) //You are too far from the liaison! SendMercMerchantResponsePacket(16); else SendMercMerchantResponsePacket(19); break; case 21: //You do not have a high enough membership level to purchase this mercenary! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) //You do not meet the requirements for that mercenary! SendMercMerchantResponsePacket(17); else SendMercMerchantResponsePacket(20); break; case 22: //Your purchase has failed because this mercenary requires a Gold membership! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) //You do not meet the requirements for that mercenary! SendMercMerchantResponsePacket(17); else SendMercMerchantResponsePacket(21); break; case 23: //Your purchase has failed because this mercenary requires at least a Silver membership! - if (GetClientVersion() < ClientVersion::RoF) + if (ClientVersion() < EQEmu::versions::ClientVersion::RoF) //You do not meet the requirements for that mercenary! SendMercMerchantResponsePacket(17); else @@ -5373,7 +5401,7 @@ bool Client::CheckCanSpawnMerc(uint32 template_id) { } // Check client version - if(static_cast(GetClientVersion()) < mercTemplate->ClientVersion) + if(static_cast(ClientVersion()) < mercTemplate->ClientVersion) { SendMercResponsePackets(3); return false; @@ -5778,7 +5806,7 @@ bool Merc::RemoveMercFromGroup(Merc* merc, Group* group) { { merc->SetFollowID(0); - if (group->GroupCount() <= 2 && merc->GetGroup() == group && ZoneLoaded) + if (group->GroupCount() <= 2 && merc->GetGroup() == group && is_zone_loaded) { group->DisbandGroup(); } @@ -6029,7 +6057,7 @@ void Client::SetMerc(Merc* newmerc) { //Client* oldowner = entity_list.GetClientByID(newmerc->GetOwnerID()); newmerc->SetOwnerID(this->GetID()); newmerc->SetMercCharacterID(this->CharacterID()); - newmerc->SetClientVersion((uint8)this->GetClientVersion()); + newmerc->SetClientVersion((uint8)this->ClientVersion()); GetMercInfo().mercid = newmerc->GetMercID(); GetMercInfo().MercTemplateID = newmerc->GetMercTemplateID(); GetMercInfo().myTemplate = zone->GetMercTemplate(GetMercInfo().MercTemplateID); @@ -6053,9 +6081,9 @@ void Client::UpdateMercLevel() { void Client::SendMercMerchantResponsePacket(int32 response_type) { // This response packet brings up the Mercenary Manager window - if(GetClientVersion() >= ClientVersion::SoD) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryHire, sizeof(MercenaryMerchantResponse_Struct)); + auto outapp = new EQApplicationPacket(OP_MercenaryHire, sizeof(MercenaryMerchantResponse_Struct)); MercenaryMerchantResponse_Struct* mmr = (MercenaryMerchantResponse_Struct*)outapp->pBuffer; mmr->ResponseType = response_type; // send specified response type FastQueuePacket(&outapp); @@ -6065,7 +6093,7 @@ void Client::SendMercMerchantResponsePacket(int32 response_type) { void Client::SendMercenaryUnknownPacket(uint8 type) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryUnknown1, 1); + auto outapp = new EQApplicationPacket(OP_MercenaryUnknown1, 1); outapp->WriteUInt8(type); FastQueuePacket(&outapp); Log.Out(Logs::Moderate, Logs::Mercenaries, "Sent SendMercenaryUnknownPacket Type: %i, Client: %s.", type, GetName()); @@ -6074,7 +6102,7 @@ void Client::SendMercenaryUnknownPacket(uint8 type) { void Client::SendMercenaryUnsuspendPacket(uint8 type) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryUnsuspendResponse, 1); + auto outapp = new EQApplicationPacket(OP_MercenaryUnsuspendResponse, 1); outapp->WriteUInt8(type); FastQueuePacket(&outapp); Log.Out(Logs::Moderate, Logs::Mercenaries, "Sent SendMercenaryUnsuspendPacket Type: %i, Client: %s.", type, GetName()); @@ -6083,7 +6111,7 @@ void Client::SendMercenaryUnsuspendPacket(uint8 type) { void Client::SendMercSuspendResponsePacket(uint32 suspended_time) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenarySuspendResponse, sizeof(SuspendMercenaryResponse_Struct)); + auto outapp = new EQApplicationPacket(OP_MercenarySuspendResponse, sizeof(SuspendMercenaryResponse_Struct)); SuspendMercenaryResponse_Struct* smr = (SuspendMercenaryResponse_Struct*)outapp->pBuffer; smr->SuspendTime = suspended_time; // Seen 0 (not suspended) or c9 c2 64 4f (suspended on Sat Mar 17 11:58:49 2012) - Unix Timestamp FastQueuePacket(&outapp); @@ -6094,7 +6122,7 @@ void Client::SendMercSuspendResponsePacket(uint32 suspended_time) { void Client::SendMercTimerPacket(int32 entity_id, int32 merc_state, int32 suspended_time, int32 update_interval, int32 unk01) { // Send Mercenary Status/Timer packet - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryTimer, sizeof(MercenaryStatus_Struct)); + auto outapp = new EQApplicationPacket(OP_MercenaryTimer, sizeof(MercenaryStatus_Struct)); MercenaryStatus_Struct* mss = (MercenaryStatus_Struct*)outapp->pBuffer; mss->MercEntityID = entity_id; // Seen 0 (no merc spawned) or unknown value when merc is spawned mss->MercState = merc_state; // Seen 5 (normal) or 1 (suspended) @@ -6107,7 +6135,7 @@ void Client::SendMercTimerPacket(int32 entity_id, int32 merc_state, int32 suspen } void Client::SendMercAssignPacket(uint32 entityID, uint32 unk01, uint32 unk02) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryAssign, sizeof(MercenaryAssign_Struct)); + auto outapp = new EQApplicationPacket(OP_MercenaryAssign, sizeof(MercenaryAssign_Struct)); MercenaryAssign_Struct* mas = (MercenaryAssign_Struct*)outapp->pBuffer; mas->MercEntityID = entityID; mas->MercUnk01 = unk01; @@ -6186,7 +6214,7 @@ int NPC::GetNumMercTypes(uint32 clientVersion) { int count = 0; std::list mercTypeList = GetMercTypesList(); - for(std::list::iterator mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); ++mercTypeListItr) { + for (auto mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); ++mercTypeListItr) { if(mercTypeListItr->ClientVersion <= clientVersion) count++; } @@ -6199,7 +6227,7 @@ int NPC::GetNumMercs(uint32 clientVersion) { int count = 0; std::list mercDataList = GetMercsList(); - for(std::list::iterator mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) { + for (auto mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) { if(mercListItr->ClientVersion <= clientVersion) count++; } @@ -6213,8 +6241,8 @@ std::list NPC::GetMercTypesList(uint32 clientVersion) { if(GetNumMercTypes() > 0) { - for(std::list::iterator mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); ++mercTypeListItr) - { + for (auto mercTypeListItr = mercTypeList.begin(); mercTypeListItr != mercTypeList.end(); + ++mercTypeListItr) { if(mercTypeListItr->ClientVersion <= clientVersion) { MercType mercType; @@ -6234,8 +6262,7 @@ std::list NPC::GetMercsList(uint32 clientVersion) { if(GetNumMercs() > 0) { - for(std::list::iterator mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) - { + for (auto mercListItr = mercDataList.begin(); mercListItr != mercDataList.end(); ++mercListItr) { if(mercListItr->ClientVersion <= clientVersion) { MercTemplate *merc_template = zone->GetMercTemplate(mercListItr->MercTemplateID); diff --git a/zone/merc.h b/zone/merc.h index 9c683ed52..00c953288 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -8,11 +8,15 @@ class Corpse; class Group; class Mob; class Raid; -struct Item_Struct; struct MercTemplate; struct NPCType; struct NewSpawn_Struct; +namespace EQEmu +{ + struct ItemBase; +} + #define MAXMERCS 1 #define TANK 1 #define HEALER 2 @@ -60,10 +64,10 @@ public: virtual ~Merc(); //abstract virtual function implementations requird by base abstract class - virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill); - virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false); - virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, - bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr); + virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill); + virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0); + virtual bool Attack(Mob* other, int Hand = EQEmu::legacy::SlotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, + bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr, int special = 0); virtual bool HasRaid() { return false; } virtual bool HasGroup() { return (GetGroup() ? true : false); } virtual Raid* GetRaid() { return 0; } @@ -177,10 +181,10 @@ public: inline const uint8 GetClientVersion() const { return _OwnerClientVersion; } virtual void SetTarget(Mob* mob); - bool HasSkill(SkillUseTypes skill_id) const; - bool CanHaveSkill(SkillUseTypes skill_id) const; - uint16 MaxSkill(SkillUseTypes skillid, uint16 class_, uint16 level) const; - inline uint16 MaxSkill(SkillUseTypes skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); } + bool HasSkill(EQEmu::skills::SkillType skill_id) const; + bool CanHaveSkill(EQEmu::skills::SkillType skill_id) const; + uint16 MaxSkill(EQEmu::skills::SkillType skillid, uint16 class_, uint16 level) const; + inline uint16 MaxSkill(EQEmu::skills::SkillType skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); } virtual void DoClassAttacks(Mob *target); void CheckHateList(); bool CheckTaunt(); @@ -192,6 +196,7 @@ public: virtual void ScaleStats(int scalepercent, bool setmax = false); virtual void CalcBonuses(); int32 GetEndurance() const {return cur_end;} //This gets our current endurance + inline uint8 GetEndurancePercent() { return (uint8)((float)cur_end / (float)max_end * 100.0f); } inline virtual int32 GetAC() const { return AC; } inline virtual int32 GetATK() const { return ATK; } inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; } @@ -278,7 +283,7 @@ public: protected: void CalcItemBonuses(StatBonuses* newbon); - void AddItemBonuses(const Item_Struct *item, StatBonuses* newbon); + void AddItemBonuses(const EQEmu::ItemBase *item, StatBonuses* newbon); int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat); int16 GetFocusEffect(focusType type, uint16 spell_id); @@ -286,8 +291,8 @@ protected: std::vector merc_spells; std::map timers; - uint16 skills[HIGHEST_SKILL+1]; - uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs + uint16 skills[EQEmu::skills::HIGHEST_SKILL + 1]; + uint32 equipment[EQEmu::legacy::EQUIPMENT_SIZE]; //this is an array of item IDs uint16 d_melee_texture1; //this is an item Material value uint16 d_melee_texture2; //this is an item Material value (offhand) uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation @@ -397,4 +402,4 @@ private: Timer check_target_timer; }; -#endif // MERC_H \ No newline at end of file +#endif // MERC_H diff --git a/zone/mob.cpp b/zone/mob.cpp index a3fcef23c..3d594e806 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef BOTS #include "bot.h" @@ -72,7 +73,7 @@ Mob::Mob(const char* in_name, uint32 in_drakkin_heritage, uint32 in_drakkin_tattoo, uint32 in_drakkin_details, - uint32 in_armor_tint[_MaterialCount], + EQEmu::TintProfile in_armor_tint, uint8 in_aa_title, uint8 in_see_invis, // see through invis/ivu @@ -83,7 +84,12 @@ Mob::Mob(const char* in_name, int32 in_mana_regen, uint8 in_qglobal, uint8 in_maxlevel, - uint32 in_scalerate + uint32 in_scalerate, + uint8 in_armtexture, + uint8 in_bracertexture, + uint8 in_handtexture, + uint8 in_legtexture, + uint8 in_feettexture ) : attack_timer(2000), attack_dw_timer(2000), @@ -107,7 +113,7 @@ Mob::Mob(const char* in_name, targeted = 0; tar_ndx=0; tar_vector=0; - curfp = false; + currently_fleeing = false; AI_Init(); SetMoving(false); @@ -143,21 +149,49 @@ Mob::Mob(const char* in_name, size = in_size; base_size = size; runspeed = in_runspeed; + // neotokyo: sanity check + if (runspeed < 0 || runspeed > 20) + runspeed = 1.25f; + base_runspeed = (int)((float)runspeed * 40.0f); + // clients + if (runspeed == 0.7f) { + base_runspeed = 28; + walkspeed = 0.3f; + base_walkspeed = 12; + fearspeed = 0.625f; + base_fearspeed = 25; + // npcs + } else { + base_walkspeed = base_runspeed * 100 / 265; + walkspeed = ((float)base_walkspeed) * 0.025f; + base_fearspeed = base_runspeed * 100 / 127; + fearspeed = ((float)base_fearspeed) * 0.025f; + } + + + current_speed = base_runspeed; + + m_PlayerState = 0; // sanity check if (runspeed < 0 || runspeed > 20) runspeed = 1.25f; - m_Light.Type.Innate = in_light; - m_Light.Level.Innate = m_Light.TypeToLevel(m_Light.Type.Innate); - m_Light.Level.Equipment = m_Light.Type.Equipment = 0; - m_Light.Level.Spell = m_Light.Type.Spell = 0; - m_Light.Type.Active = m_Light.Type.Innate; - m_Light.Level.Active = m_Light.Level.Innate; - + m_Light.Type[EQEmu::lightsource::LightInnate] = in_light; + m_Light.Level[EQEmu::lightsource::LightInnate] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightInnate]); + 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; + armtexture = in_armtexture; + bracertexture = in_bracertexture; + handtexture = in_handtexture; + legtexture = in_legtexture; + feettexture = in_feettexture; + multitexture = (armtexture || bracertexture || handtexture || legtexture || feettexture); + haircolor = in_haircolor; beardcolor = in_beardcolor; eyecolor1 = in_eyecolor1; @@ -175,6 +209,7 @@ Mob::Mob(const char* in_name, trackable = true; has_shieldequiped = false; has_twohandbluntequiped = false; + has_twohanderequipped = false; has_numhits = false; has_MGB = false; has_ProjectIllusion = false; @@ -216,6 +251,7 @@ Mob::Mob(const char* in_name, invulnerable = false; IsFullHP = (cur_hp == max_hp); qglobal=0; + spawned = false; InitializeBuffSlots(); @@ -227,27 +263,24 @@ Mob::Mob(const char* in_name, PermaProcs[j].spellID = SPELL_UNKNOWN; PermaProcs[j].chance = 0; PermaProcs[j].base_spellID = SPELL_UNKNOWN; + PermaProcs[j].level_override = -1; SpellProcs[j].spellID = SPELL_UNKNOWN; SpellProcs[j].chance = 0; SpellProcs[j].base_spellID = SPELL_UNKNOWN; + SpellProcs[j].level_override = -1; DefensiveProcs[j].spellID = SPELL_UNKNOWN; DefensiveProcs[j].chance = 0; DefensiveProcs[j].base_spellID = SPELL_UNKNOWN; + DefensiveProcs[j].level_override = -1; RangedProcs[j].spellID = SPELL_UNKNOWN; RangedProcs[j].chance = 0; RangedProcs[j].base_spellID = SPELL_UNKNOWN; + RangedProcs[j].level_override = -1; } - for (i = 0; i < _MaterialCount; i++) + for (i = 0; i < EQEmu::textures::TextureCount; i++) { - if (in_armor_tint) - { - armor_tint[i] = in_armor_tint[i]; - } - else - { - armor_tint[i] = 0; - } + armor_tint.Slot[i].Color = in_armor_tint.Slot[i].Color; } m_Delta = glm::vec4(); @@ -267,8 +300,8 @@ Mob::Mob(const char* in_name, casting_spell_id = 0; casting_spell_timer = 0; casting_spell_timer_duration = 0; - casting_spell_type = 0; casting_spell_inventory_slot = 0; + casting_spell_aa_id = 0; target = 0; ActiveProjectileATK = false; @@ -298,7 +331,7 @@ Mob::Mob(const char* in_name, pLastChange = 0; SetPetID(0); SetOwnerID(0); - typeofpet = petCharmed; //default to charmed... + typeofpet = petNone; // default to not a pet petpower = 0; held = false; nocast = false; @@ -330,7 +363,7 @@ Mob::Mob(const char* in_name, follow=0; follow_dist = 100; // Default Distance for Follow flee_mode = false; - curfp = false; + currently_fleeing = false; flee_timer.Start(); permarooted = (runspeed > 0) ? false : true; @@ -387,11 +420,15 @@ Mob::Mob(const char* in_name, m_AllowBeneficial = false; m_DisableMelee = false; - for (int i = 0; i < HIGHEST_SKILL+2; i++) { SkillDmgTaken_Mod[i] = 0; } + for (int i = 0; i < EQEmu::skills::HIGHEST_SKILL + 2; i++) { SkillDmgTaken_Mod[i] = 0; } for (int i = 0; i < HIGHEST_RESIST+2; i++) { Vulnerability_Mod[i] = 0; } emoteid = 0; endur_upkeep = false; + degenerating_effects = false; + PrimaryAggro = false; + AssistAggro = false; + npc_assist_cap = 0; } Mob::~Mob() @@ -429,6 +466,10 @@ Mob::~Mob() safe_delete(PathingRouteUpdateTimerShort); safe_delete(PathingRouteUpdateTimerLong); UninitializeBuffSlots(); + +#ifdef BOTS + LeaveHealRotationTargetPool(); +#endif } uint32 Mob::GetAppearanceValue(EmuAppearance iAppearance) { @@ -462,13 +503,9 @@ void Mob::SetInvisible(uint8 state) SendAppearancePacket(AT_Invis, invisible); // Invis and hide breaks charms - if ((this->GetPetType() == petCharmed) && (invisible || hidden || improved_hidden)) - { - Mob* formerpet = this->GetPet(); - - if(formerpet) - formerpet->BuffFadeByEffect(SE_Charm); - } + auto formerpet = GetPet(); + if (formerpet && formerpet->GetPetType() == petCharmed && (invisible || hidden || improved_hidden)) + formerpet->BuffFadeByEffect(SE_Charm); } //check to see if `this` is invisible to `other` @@ -518,48 +555,32 @@ bool Mob::IsInvisible(Mob* other) const return(false); } -float Mob::_GetMovementSpeed(int mod) const -{ - // List of movement speed modifiers, including AAs & spells: - // http://everquest.allakhazam.com/db/item.html?item=1721;page=1;howmany=50#m10822246245352 - if (IsRooted()) - return 0.0f; +int Mob::_GetWalkSpeed() const { + + if (IsRooted() || IsStunned() || IsMezzed()) + return 0; + else if (IsPseudoRooted()) - return 0.00001f; + return 0; - float speed_mod = runspeed; + int aa_mod = 0; + int speed_mod = base_walkspeed; + int base_run = base_runspeed; + bool has_horse = false; + int runspeedcap = RuleI(Character,BaseRunSpeedCap); + runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap; + aa_mod += aabonuses.BaseMovementSpeed; - // These two cases ignore the cap, be wise in the DB for horses. if (IsClient()) { - if (CastToClient()->GetGMSpeed()) { - speed_mod = 3.125f; - if (mod != 0) - speed_mod += speed_mod * static_cast(mod) / 100.0f; + Mob *horse = entity_list.GetMob(CastToClient()->GetHorseId()); + if (horse) { + speed_mod = horse->GetBaseRunspeed(); return speed_mod; - } else { - Mob *horse = entity_list.GetMob(CastToClient()->GetHorseId()); - if (horse) { - speed_mod = horse->GetBaseRunspeed(); - if (mod != 0) - speed_mod += speed_mod * static_cast(mod) / 100.0f; - return speed_mod; - } } } - int aa_mod = 0; - int spell_mod = 0; - int runspeedcap = RuleI(Character,BaseRunSpeedCap); + int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed; int movemod = 0; - float frunspeedcap = 0.0f; - - runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap; - aa_mod += itembonuses.BaseMovementSpeed + spellbonuses.BaseMovementSpeed + aabonuses.BaseMovementSpeed; - spell_mod += spellbonuses.movementspeed + itembonuses.movementspeed; - - // hard cap - if (runspeedcap > 225) - runspeedcap = 225; if (spell_mod < 0) movemod += spell_mod; @@ -568,27 +589,189 @@ float Mob::_GetMovementSpeed(int mod) const else movemod = aa_mod; - // cap negative movemods from snares mostly - if (movemod < -85) + // hard cap + if (runspeedcap > 225) + runspeedcap = 225; + + if(movemod < -85) //cap it at moving very very slow movemod = -85; - if (movemod != 0) - speed_mod += speed_mod * static_cast(movemod) / 100.0f; + if (!has_horse && movemod != 0) + speed_mod += (base_run * movemod / 100); - // runspeed caps - frunspeedcap = static_cast(runspeedcap) / 100.0f; - if (IsClient() && speed_mod > frunspeedcap) - speed_mod = frunspeedcap; + if(speed_mod < 1) + return(0); - // apply final mod such as the -47 for walking - // use runspeed since it should stack with snares - // and if we get here, we know runspeed was the initial - // value before we applied movemod. - if (mod != 0) - speed_mod += runspeed * static_cast(mod) / 100.0f; + //runspeed cap. + if(IsClient()) + { + if(speed_mod > runspeedcap) + speed_mod = runspeedcap; + } + return speed_mod; +} - if (speed_mod <= 0.0f) - speed_mod = IsClient() ? 0.0001f : 0.0f; +int Mob::_GetRunSpeed() const { + if (IsRooted() || IsStunned() || IsMezzed() || IsPseudoRooted()) + return 0; + + int aa_mod = 0; + int speed_mod = base_runspeed; + int base_walk = base_walkspeed; + bool has_horse = false; + if (IsClient()) + { + if(CastToClient()->GetGMSpeed()) + { + speed_mod = 325; + } + else + { + Mob* horse = entity_list.GetMob(CastToClient()->GetHorseId()); + if(horse) + { + speed_mod = horse->GetBaseRunspeed(); + base_walk = horse->GetBaseWalkspeed(); + has_horse = true; + } + } + } + + int runspeedcap = RuleI(Character,BaseRunSpeedCap); + runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap; + + aa_mod = itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap; + int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed; + int movemod = 0; + + if(spell_mod < 0) + { + movemod += spell_mod; + } + else if(spell_mod > aa_mod) + { + movemod = spell_mod; + } + else + { + movemod = aa_mod; + } + + if(movemod < -85) //cap it at moving very very slow + movemod = -85; + + if (!has_horse && movemod != 0) + { + if (IsClient()) + { + speed_mod += (speed_mod * movemod / 100); + } else { + if (movemod < 0) { + speed_mod += (50 * movemod / 100); + // basically stoped + if(speed_mod < 1) + { + return(0); + } + // moving slowly + if (speed_mod < 8) + return(8); + } else { + speed_mod += GetBaseWalkspeed(); + if (movemod > 50) + speed_mod += 4; + if (movemod > 40) + speed_mod += 3; + } + } + } + + if(speed_mod < 1) + { + return(0); + } + //runspeed cap. + if(IsClient()) + { + if(speed_mod > runspeedcap) + speed_mod = runspeedcap; + } + return speed_mod; +} + +int Mob::_GetFearSpeed() const { + + if (IsRooted() || IsStunned() || IsMezzed()) + return 0; + + //float speed_mod = fearspeed; + int speed_mod = GetBaseFearSpeed(); + + // use a max of 1.75f in calcs. + int base_run = std::min(GetBaseRunspeed(), 70); + + int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed; + int movemod = 0; + + if(spell_mod < 0) + { + movemod += spell_mod; + } + + if(movemod < -85) //cap it at moving very very slow + movemod = -85; + + if (IsClient()) { + if (CastToClient()->GetRunMode()) + speed_mod = GetBaseRunspeed(); + else + speed_mod = GetBaseWalkspeed(); + if (movemod < 0) + return GetBaseWalkspeed(); + speed_mod += (base_run * movemod / 100); + return speed_mod; + } else { + int hp_ratio = GetIntHPRatio(); + // very large snares 50% or higher + if (movemod < -49) + { + if (hp_ratio < 25) + { + return (0); + } + if (hp_ratio < 50) + return (8); + else + return (12); + } + if (hp_ratio < 5) { + speed_mod = base_walkspeed / 3; + } else if (hp_ratio < 15) { + speed_mod = base_walkspeed / 2; + } else if (hp_ratio < 25) { + speed_mod = base_walkspeed + 1; // add the +1 so they do the run animation + } else if (hp_ratio < 50) { + speed_mod *= 82; + speed_mod /= 100; + } + if (movemod > 0) { + speed_mod += GetBaseWalkspeed(); + if (movemod > 50) + speed_mod += 4; + if (movemod > 40) + speed_mod += 3; + return speed_mod; + } + else if (movemod < 0) { + speed_mod += (base_run * movemod / 100); + } + } + if (speed_mod < 1) + return (0); + if (speed_mod < 9) + return (8); + if (speed_mod < 13) + return (12); return speed_mod; } @@ -727,7 +910,7 @@ void Mob::CreateSpawnPacket(EQApplicationPacket* app, Mob* ForWho) { NewSpawn_Struct* ns = (NewSpawn_Struct*)app->pBuffer; FillSpawnStruct(ns, ForWho); - if(strlen(ns->spawn.lastName) == 0) + if(RuleB(NPC, UseClassAsLastName) && strlen(ns->spawn.lastName) == 0) { switch(ns->spawn.class_) { @@ -808,7 +991,7 @@ void Mob::CreateSpawnPacket(EQApplicationPacket* app, NewSpawn_Struct* ns) { strcpy(ns2->spawn.name, ns->spawn.name); // Set default Last Names for certain Classes if not defined - if (strlen(ns->spawn.lastName) == 0) + if (RuleB(NPC, UseClassAsLastName) && strlen(ns->spawn.lastName) == 0) { switch (ns->spawn.class_) { @@ -899,16 +1082,17 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) ns->spawn.max_hp = 100; //this field needs a better name ns->spawn.race = race; ns->spawn.runspeed = runspeed; - ns->spawn.walkspeed = runspeed * 0.5f; + ns->spawn.walkspeed = walkspeed; ns->spawn.class_ = class_; ns->spawn.gender = gender; ns->spawn.level = level; + ns->spawn.PlayerState = m_PlayerState; ns->spawn.deity = deity; ns->spawn.animation = 0; ns->spawn.findable = findable?1:0; UpdateActiveLight(); - ns->spawn.light = m_Light.Type.Active; + ns->spawn.light = m_Light.Type[EQEmu::lightsource::LightActive]; ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0; @@ -930,7 +1114,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) ns->spawn.drakkin_heritage = drakkin_heritage; ns->spawn.drakkin_tattoo = drakkin_tattoo; ns->spawn.drakkin_details = drakkin_details; - ns->spawn.equip_chest2 = GetHerosForgeModel(1) != 0 ? 0xff : texture; + ns->spawn.equip_chest2 = GetHerosForgeModel(1) != 0 || multitexture? 0xff : texture; // ns->spawn.invis2 = 0xff;//this used to be labeled beard.. if its not FF it will turn mob invis @@ -955,6 +1139,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) else ns->spawn.flymode = flymode; + if(IsBoat()) { + ns->spawn.flymode = 1; + } + ns->spawn.lastName[0] = '\0'; strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName)); @@ -965,10 +1153,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) // Only Player Races Wear Armor if (Mob::IsPlayerRace(race) || i > 6) { - ns->spawn.equipment[i].Material = GetEquipmentMaterial(i); - ns->spawn.equipment[i].EliteMaterial = IsEliteMaterialItem(i); - ns->spawn.equipment[i].HeroForgeModel = GetHerosForgeModel(i); - ns->spawn.colors[i].Color = GetEquipmentColor(i); + ns->spawn.equipment.Slot[i].Material = GetEquipmentMaterial(i); + ns->spawn.equipment.Slot[i].EliteMaterial = IsEliteMaterialItem(i); + ns->spawn.equipment.Slot[i].HeroForgeModel = GetHerosForgeModel(i); + ns->spawn.equipment_tint.Slot[i].Color = GetEquipmentColor(i); } } @@ -1079,7 +1267,7 @@ void Mob::CreateHPPacket(EQApplicationPacket* app) } // sends hp update of this mob to people who might care -void Mob::SendHPUpdate() +void Mob::SendHPUpdate(bool skip_self) { EQApplicationPacket hp_app; Group *group; @@ -1088,7 +1276,7 @@ void Mob::SendHPUpdate() CreateHPPacket(&hp_app); // send to people who have us targeted - entity_list.QueueClientsByTarget(this, &hp_app, false, 0, false, true, BIT_AllClients); + entity_list.QueueClientsByTarget(this, &hp_app, false, 0, false, true, EQEmu::versions::bit_AllClients); entity_list.QueueClientsByXTarget(this, &hp_app, false); entity_list.QueueToGroupsForNPCHealthAA(this, &hp_app); @@ -1167,10 +1355,13 @@ void Mob::SendHPUpdate() } } + bool dospam = RuleB(Character, SpamHPUpdates); // send to self - we need the actual hps here - if(IsClient()) - { - EQApplicationPacket* hp_app2 = new EQApplicationPacket(OP_HPUpdate,sizeof(SpawnHPUpdate_Struct)); + if(IsClient() && (!skip_self || dospam)) { + + this->CastToClient()->SendHPUpdateMarquee(); + + auto hp_app2 = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct)); SpawnHPUpdate_Struct* ds = (SpawnHPUpdate_Struct*)hp_app2->pBuffer; ds->cur_hp = CastToClient()->GetHP() - itembonuses.HP; ds->spawn_id = GetID(); @@ -1178,12 +1369,14 @@ void Mob::SendHPUpdate() CastToClient()->QueuePacket(hp_app2); safe_delete(hp_app2); } + if (!dospam) + ResetHPUpdateTimer(); // delay the timer } // this one just warps the mob to the current location void Mob::SendPosition() { - EQApplicationPacket* app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)app->pBuffer; MakeSpawnUpdateNoDelta(spu); move_tic_count = 0; @@ -1193,24 +1386,28 @@ void Mob::SendPosition() // this one is for mobs on the move, with deltas - this makes them walk void Mob::SendPosUpdate(uint8 iSendToSelf) { - EQApplicationPacket* app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + auto app = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)app->pBuffer; MakeSpawnUpdate(spu); if (iSendToSelf == 2) { - if (this->IsClient()) - this->CastToClient()->FastQueuePacket(&app,false); + if (IsClient()) { + CastToClient()->FastQueuePacket(&app,false); + } } else { if(move_tic_count == RuleI(Zone, NPCPositonUpdateTicCount)) { - entity_list.QueueClients(this, app, (iSendToSelf==0), false); + entity_list.QueueClients(this, app, (iSendToSelf == 0), false); move_tic_count = 0; } - else + else if(move_tic_count % 2 == 0) { - entity_list.QueueCloseClients(this, app, (iSendToSelf==0), 800, nullptr, false); + entity_list.QueueCloseClients(this, app, (iSendToSelf == 0), 700, nullptr, false); + move_tic_count++; + } + else { move_tic_count++; } } @@ -1302,7 +1499,7 @@ void Mob::ShowStats(Client* client) if(n->respawn2 != 0) spawngroupid = n->respawn2->SpawnGroupID(); client->Message(0, " NPCID: %u SpawnGroupID: %u Grid: %i LootTable: %u FactionID: %i SpellsID: %u ", GetNPCTypeID(),spawngroupid, n->GetGrid(), n->GetLoottableID(), n->GetNPCFactionID(), n->GetNPCSpellsID()); - client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %f Walkspeed: %f", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), n->GetRunspeed(), n->GetWalkspeed()); + client->Message(0, " Accuracy: %i MerchantID: %i EmoteID: %i Runspeed: %.3f Walkspeed: %.3f", n->GetAccuracyRating(), n->MerchantType, n->GetEmoteID(), static_cast(0.025f * n->GetRunspeed()), static_cast(0.025f * n->GetWalkspeed())); n->QueryLoot(client); } if (IsAIControlled()) { @@ -1312,16 +1509,16 @@ void Mob::ShowStats(Client* client) } void Mob::DoAnim(const int animnum, int type, bool ackreq, eqFilterType filter) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Animation, sizeof(Animation_Struct)); + auto outapp = new EQApplicationPacket(OP_Animation, sizeof(Animation_Struct)); Animation_Struct* anim = (Animation_Struct*)outapp->pBuffer; anim->spawnid = GetID(); if(type == 0){ - anim->action = 10; - anim->value=animnum; + anim->action = animnum; + anim->speed = 10; } else{ anim->action = animnum; - anim->value=type; + anim->speed = type; } entity_list.QueueCloseClients(this, outapp, false, 200, 0, ackreq, filter); safe_delete(outapp); @@ -1552,7 +1749,7 @@ void Mob::SendIllusionPacket(uint16 in_race, uint8 in_gender, uint8 in_texture, } } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Illusion, sizeof(Illusion_Struct)); + auto outapp = new EQApplicationPacket(OP_Illusion, sizeof(Illusion_Struct)); Illusion_Struct* is = (Illusion_Struct*) outapp->pBuffer; is->spawnid = GetID(); strcpy(is->charname, GetCleanName()); @@ -1574,14 +1771,17 @@ void Mob::SendIllusionPacket(uint16 in_race, uint8 in_gender, uint8 in_texture, entity_list.QueueClients(this, outapp); safe_delete(outapp); + + /* Refresh armor and tints after send illusion packet */ + this->SendArmorAppearance(); + Log.Out(Logs::Detail, Logs::Spells, "Illusion: Race = %i, Gender = %i, Texture = %i, HelmTexture = %i, HairColor = %i, BeardColor = %i, EyeColor1 = %i, EyeColor2 = %i, HairStyle = %i, Face = %i, DrakkinHeritage = %i, DrakkinTattoo = %i, DrakkinDetails = %i, Size = %f", race, gender, texture, helmtexture, haircolor, beardcolor, eyecolor1, eyecolor2, hairstyle, luclinface, drakkin_heritage, drakkin_tattoo, drakkin_details, size); } bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables) { - if (IsPlayerRace(GetRace())) - { + if (IsPlayerRace(GetRace())) { uint8 Gender = GetGender(); uint8 Texture = 0xFF; uint8 HelmTexture = 0xFF; @@ -1602,160 +1802,158 @@ bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables) LuclinFace = zone->random.Int(0, 7); // Adjust all settings based on the min and max for each feature of each race and gender - switch (GetRace()) - { - case 1: // Human - HairColor = zone->random.Int(0, 19); - if (Gender == 0) { - BeardColor = HairColor; - HairStyle = zone->random.Int(0, 3); - Beard = zone->random.Int(0, 5); - } - if (Gender == 1) { - HairStyle = zone->random.Int(0, 2); - } - break; - case 2: // Barbarian - HairColor = zone->random.Int(0, 19); + switch (GetRace()) { + case HUMAN: + HairColor = zone->random.Int(0, 19); + if (Gender == MALE) { + BeardColor = HairColor; + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); + } + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 2); + } + break; + case BARBARIAN: + HairColor = zone->random.Int(0, 19); + LuclinFace = zone->random.Int(0, 87); + if (Gender == MALE) { + BeardColor = HairColor; + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); + } + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 2); + } + break; + case ERUDITE: + if (Gender == MALE) { + BeardColor = zone->random.Int(0, 19); + Beard = zone->random.Int(0, 5); + LuclinFace = zone->random.Int(0, 57); + } + if (Gender == FEMALE) { LuclinFace = zone->random.Int(0, 87); - if (Gender == 0) { - BeardColor = HairColor; - HairStyle = zone->random.Int(0, 3); - Beard = zone->random.Int(0, 5); - } - if (Gender == 1) { - HairStyle = zone->random.Int(0, 2); - } - break; - case 3: // Erudite - if (Gender == 0) { - BeardColor = zone->random.Int(0, 19); - Beard = zone->random.Int(0, 5); - LuclinFace = zone->random.Int(0, 57); - } - if (Gender == 1) { - LuclinFace = zone->random.Int(0, 87); - } - break; - case 4: // WoodElf - HairColor = zone->random.Int(0, 19); - if (Gender == 0) { - HairStyle = zone->random.Int(0, 3); - } - if (Gender == 1) { - HairStyle = zone->random.Int(0, 2); - } - break; - case 5: // HighElf - HairColor = zone->random.Int(0, 14); - if (Gender == 0) { - HairStyle = zone->random.Int(0, 3); - LuclinFace = zone->random.Int(0, 37); - BeardColor = HairColor; - } - if (Gender == 1) { - HairStyle = zone->random.Int(0, 2); - } - break; - case 6: // DarkElf - HairColor = zone->random.Int(13, 18); - if (Gender == 0) { - HairStyle = zone->random.Int(0, 3); - LuclinFace = zone->random.Int(0, 37); - BeardColor = HairColor; - } - if (Gender == 1) { - HairStyle = zone->random.Int(0, 2); - } - break; - case 7: // HalfElf - HairColor = zone->random.Int(0, 19); - if (Gender == 0) { - HairStyle = zone->random.Int(0, 3); - LuclinFace = zone->random.Int(0, 37); - BeardColor = HairColor; - } - if (Gender == 1) { - HairStyle = zone->random.Int(0, 2); - } - break; - case 8: // Dwarf - HairColor = zone->random.Int(0, 19); + } + break; + case WOOD_ELF: + HairColor = zone->random.Int(0, 19); + if (Gender == MALE) { + HairStyle = zone->random.Int(0, 3); + } + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 2); + } + break; + case HIGH_ELF: + HairColor = zone->random.Int(0, 14); + if (Gender == MALE) { + HairStyle = zone->random.Int(0, 3); + LuclinFace = zone->random.Int(0, 37); BeardColor = HairColor; - if (Gender == 0) { - HairStyle = zone->random.Int(0, 3); - Beard = zone->random.Int(0, 5); - } - if (Gender == 1) { - HairStyle = zone->random.Int(0, 2); - LuclinFace = zone->random.Int(0, 17); - } - break; - case 9: // Troll - EyeColor1 = zone->random.Int(0, 10); - EyeColor2 = zone->random.Int(0, 10); - if (Gender == 1) { - HairStyle = zone->random.Int(0, 3); - HairColor = zone->random.Int(0, 23); - } - break; - case 10: // Ogre - if (Gender == 1) { - HairStyle = zone->random.Int(0, 3); - HairColor = zone->random.Int(0, 23); - } - break; - case 11: // Halfling - HairColor = zone->random.Int(0, 19); - if (Gender == 0) { - BeardColor = HairColor; - HairStyle = zone->random.Int(0, 3); - Beard = zone->random.Int(0, 5); - } - if (Gender == 1) { - HairStyle = zone->random.Int(0, 2); - } - break; - case 12: // Gnome - HairColor = zone->random.Int(0, 24); - if (Gender == 0) { - BeardColor = HairColor; - HairStyle = zone->random.Int(0, 3); - Beard = zone->random.Int(0, 5); - } - if (Gender == 1) { - HairStyle = zone->random.Int(0, 2); - } - break; - case 128: // Iksar - case 130: // VahShir - break; - case 330: // Froglok - LuclinFace = zone->random.Int(0, 9); - case 522: // Drakkin - HairColor = zone->random.Int(0, 3); + } + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 2); + } + break; + case DARK_ELF: + HairColor = zone->random.Int(13, 18); + if (Gender == MALE) { + HairStyle = zone->random.Int(0, 3); + LuclinFace = zone->random.Int(0, 37); BeardColor = HairColor; - EyeColor1 = zone->random.Int(0, 11); - EyeColor2 = zone->random.Int(0, 11); - LuclinFace = zone->random.Int(0, 6); - DrakkinHeritage = zone->random.Int(0, 6); - DrakkinTattoo = zone->random.Int(0, 7); - DrakkinDetails = zone->random.Int(0, 7); - if (Gender == 0) { - Beard = zone->random.Int(0, 12); - HairStyle = zone->random.Int(0, 8); - } - if (Gender == 1) { - Beard = zone->random.Int(0, 3); - HairStyle = zone->random.Int(0, 7); - } - break; - default: - break; + } + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 2); + } + break; + case HALF_ELF: + HairColor = zone->random.Int(0, 19); + if (Gender == MALE) { + HairStyle = zone->random.Int(0, 3); + LuclinFace = zone->random.Int(0, 37); + BeardColor = HairColor; + } + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 2); + } + break; + case DWARF: + HairColor = zone->random.Int(0, 19); + BeardColor = HairColor; + if (Gender == MALE) { + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); + } + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 2); + LuclinFace = zone->random.Int(0, 17); + } + break; + case TROLL: + EyeColor1 = zone->random.Int(0, 10); + EyeColor2 = zone->random.Int(0, 10); + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 3); + HairColor = zone->random.Int(0, 23); + } + break; + case OGRE: + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 3); + HairColor = zone->random.Int(0, 23); + } + break; + case HALFLING: + HairColor = zone->random.Int(0, 19); + if (Gender == MALE) { + BeardColor = HairColor; + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); + } + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 2); + } + break; + case GNOME: + HairColor = zone->random.Int(0, 24); + if (Gender == MALE) { + BeardColor = HairColor; + HairStyle = zone->random.Int(0, 3); + Beard = zone->random.Int(0, 5); + } + if (Gender == FEMALE) { + HairStyle = zone->random.Int(0, 2); + } + break; + case IKSAR: + case VAHSHIR: + break; + case FROGLOK: + LuclinFace = zone->random.Int(0, 9); + case DRAKKIN: + HairColor = zone->random.Int(0, 3); + BeardColor = HairColor; + EyeColor1 = zone->random.Int(0, 11); + EyeColor2 = zone->random.Int(0, 11); + LuclinFace = zone->random.Int(0, 6); + DrakkinHeritage = zone->random.Int(0, 6); + DrakkinTattoo = zone->random.Int(0, 7); + DrakkinDetails = zone->random.Int(0, 7); + if (Gender == MALE) { + Beard = zone->random.Int(0, 12); + HairStyle = zone->random.Int(0, 8); + } + if (Gender == FEMALE) { + Beard = zone->random.Int(0, 3); + HairStyle = zone->random.Int(0, 7); + } + break; + default: + break; } - if (set_variables) - { + if (set_variables) { haircolor = HairColor; beardcolor = BeardColor; eyecolor1 = EyeColor1; @@ -1768,8 +1966,7 @@ bool Mob::RandomizeFeatures(bool send_illusion, bool set_variables) drakkin_details = DrakkinDetails; } - if (send_illusion) - { + if (send_illusion) { SendIllusionPacket(GetRace(), Gender, Texture, HelmTexture, HairColor, BeardColor, EyeColor1, EyeColor2, HairStyle, LuclinFace, Beard, 0xFF, DrakkinHeritage, DrakkinTattoo, DrakkinDetails); @@ -1793,7 +1990,7 @@ bool Mob::IsPlayerRace(uint16 in_race) { uint8 Mob::GetDefaultGender(uint16 in_race, uint8 in_gender) { - if (Mob::IsPlayerRace(in_race) || in_race == 15 || in_race == 50 || in_race == 57 || in_race == 70 || in_race == 98 || in_race == 118) { + if (Mob::IsPlayerRace(in_race) || in_race == 15 || in_race == 50 || in_race == 57 || in_race == 70 || in_race == 98 || in_race == 118 || in_race == 23) { if (in_gender >= 2) { // Male default for PC Races return 0; @@ -1820,7 +2017,7 @@ uint8 Mob::GetDefaultGender(uint16 in_race, uint8 in_gender) { void Mob::SendAppearancePacket(uint32 type, uint32 value, bool WholeZone, bool iIgnoreSelf, Client *specific_target) { if (!GetID()) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); SpawnAppearance_Struct* appearance = (SpawnAppearance_Struct*)outapp->pBuffer; appearance->spawn_id = this->GetID(); appearance->type = type; @@ -1835,7 +2032,7 @@ void Mob::SendAppearancePacket(uint32 type, uint32 value, bool WholeZone, bool i } void Mob::SendLevelAppearance(){ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_LevelAppearance, sizeof(LevelAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_LevelAppearance, sizeof(LevelAppearance_Struct)); LevelAppearance_Struct* la = (LevelAppearance_Struct*)outapp->pBuffer; la->parm1 = 0x4D; la->parm2 = la->parm1 + 1; @@ -1856,7 +2053,7 @@ void Mob::SendLevelAppearance(){ void Mob::SendStunAppearance() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_LevelAppearance, sizeof(LevelAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_LevelAppearance, sizeof(LevelAppearance_Struct)); LevelAppearance_Struct* la = (LevelAppearance_Struct*)outapp->pBuffer; la->parm1 = 58; la->parm2 = 60; @@ -1870,7 +2067,7 @@ void Mob::SendStunAppearance() } void Mob::SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, Client *specific_target){ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_LevelAppearance, sizeof(LevelAppearance_Struct)); + auto outapp = new EQApplicationPacket(OP_LevelAppearance, sizeof(LevelAppearance_Struct)); LevelAppearance_Struct* la = (LevelAppearance_Struct*)outapp->pBuffer; la->spawn_id = GetID(); la->parm1 = parm1; @@ -1900,7 +2097,7 @@ void Mob::SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 } void Mob::SendTargetable(bool on, Client *specific_target) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Untargetable, sizeof(Untargetable_Struct)); + auto outapp = new EQApplicationPacket(OP_Untargetable, sizeof(Untargetable_Struct)); Untargetable_Struct *ut = (Untargetable_Struct*)outapp->pBuffer; ut->id = GetID(); ut->targetable_flag = on == true ? 1 : 0; @@ -1914,28 +2111,12 @@ void Mob::SendTargetable(bool on, Client *specific_target) { safe_delete(outapp); } -void Mob::QuestReward(Client *c, uint32 silver, uint32 gold, uint32 platinum) { - - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct)); - QuestReward_Struct* qr = (QuestReward_Struct*) outapp->pBuffer; - - qr->from_mob = GetID(); // Entity ID for the from mob name - qr->silver = silver; - qr->gold = gold; - qr->platinum = platinum; - - if(c) - c->QueuePacket(outapp, false, Client::CLIENT_CONNECTED); - - safe_delete(outapp); -} - void Mob::CameraEffect(uint32 duration, uint32 intensity, Client *c, bool global) { if(global == true) { - ServerPacket* pack = new ServerPacket(ServerOP_CameraShake, sizeof(ServerCameraShake_Struct)); + auto pack = new ServerPacket(ServerOP_CameraShake, sizeof(ServerCameraShake_Struct)); ServerCameraShake_Struct* scss = (ServerCameraShake_Struct*) pack->pBuffer; scss->duration = duration; scss->intensity = intensity; @@ -1944,7 +2125,7 @@ void Mob::CameraEffect(uint32 duration, uint32 intensity, Client *c, bool global return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_CameraEffect, sizeof(Camera_Struct)); + auto outapp = new EQApplicationPacket(OP_CameraEffect, sizeof(Camera_Struct)); Camera_Struct* cs = (Camera_Struct*) outapp->pBuffer; cs->duration = duration; // Duration in milliseconds cs->intensity = ((intensity * 6710886) + 1023410176); // Intensity ranges from 1023410176 to 1090519040, so simplify it from 0 to 10. @@ -1959,7 +2140,7 @@ void Mob::CameraEffect(uint32 duration, uint32 intensity, Client *c, bool global void Mob::SendSpellEffect(uint32 effectid, uint32 duration, uint32 finish_delay, bool zone_wide, uint32 unk020, bool perm_effect, Client *c) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpellEffect, sizeof(SpellEffect_Struct)); + auto outapp = new EQApplicationPacket(OP_SpellEffect, sizeof(SpellEffect_Struct)); SpellEffect_Struct* se = (SpellEffect_Struct*) outapp->pBuffer; se->EffectID = effectid; // ID of the Particle Effect se->EntityID = GetID(); @@ -2011,7 +2192,7 @@ void Mob::TempName(const char *newname) entity_list.MakeNameUnique(temp_name); // Send the new name to all clients - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MobRename, sizeof(MobRename_Struct)); + auto outapp = new EQApplicationPacket(OP_MobRename, sizeof(MobRename_Struct)); MobRename_Struct* mr = (MobRename_Struct*) outapp->pBuffer; strn0cpy(mr->old_name, old_name, 64); strn0cpy(mr->old_name_again, old_name, 64); @@ -2046,28 +2227,28 @@ const int32& Mob::SetMana(int32 amount) void Mob::SetAppearance(EmuAppearance app, bool iIgnoreSelf) { - if (_appearance != app) { - _appearance = app; - SendAppearancePacket(AT_Anim, GetAppearanceValue(app), true, iIgnoreSelf); - if (this->IsClient() && this->IsAIControlled()) - SendAppearancePacket(AT_Anim, ANIM_FREEZE, false, false); - } + if (_appearance == app) + return; + _appearance = app; + SendAppearancePacket(AT_Anim, GetAppearanceValue(app), true, iIgnoreSelf); + if (this->IsClient() && this->IsAIControlled()) + SendAppearancePacket(AT_Anim, ANIM_FREEZE, false, false); } bool Mob::UpdateActiveLight() { - uint8 old_light_level = m_Light.Level.Active; + uint8 old_light_level = m_Light.Level[EQEmu::lightsource::LightActive]; - m_Light.Type.Active = 0; - m_Light.Level.Active = 0; + m_Light.Type[EQEmu::lightsource::LightActive] = 0; + m_Light.Level[EQEmu::lightsource::LightActive] = 0; - if (m_Light.IsLevelGreater((m_Light.Type.Innate & 0x0F), m_Light.Type.Active)) { m_Light.Type.Active = m_Light.Type.Innate; } - if (m_Light.Level.Equipment > m_Light.Level.Active) { m_Light.Type.Active = m_Light.Type.Equipment; } // limiter in property handler - if (m_Light.Level.Spell > m_Light.Level.Active) { m_Light.Type.Active = m_Light.Type.Spell; } // limiter in property handler + if (EQEmu::lightsource::IsLevelGreater((m_Light.Type[EQEmu::lightsource::LightInnate] & 0x0F), m_Light.Type[EQEmu::lightsource::LightActive])) { m_Light.Type[EQEmu::lightsource::LightActive] = m_Light.Type[EQEmu::lightsource::LightInnate]; } + if (m_Light.Level[EQEmu::lightsource::LightEquipment] > m_Light.Level[EQEmu::lightsource::LightActive]) { m_Light.Type[EQEmu::lightsource::LightActive] = m_Light.Type[EQEmu::lightsource::LightEquipment]; } // limiter in property handler + if (m_Light.Level[EQEmu::lightsource::LightSpell] > m_Light.Level[EQEmu::lightsource::LightActive]) { m_Light.Type[EQEmu::lightsource::LightActive] = m_Light.Type[EQEmu::lightsource::LightSpell]; } // limiter in property handler - m_Light.Level.Active = m_Light.TypeToLevel(m_Light.Type.Active); + m_Light.Level[EQEmu::lightsource::LightActive] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightActive]); - return (m_Light.Level.Active != old_light_level); + return (m_Light.Level[EQEmu::lightsource::LightActive] != old_light_level); } void Mob::ChangeSize(float in_size = 0, bool bNoRestriction) { @@ -2143,8 +2324,10 @@ void Mob::SetOwnerID(uint16 NewOwnerID) { if (NewOwnerID == GetID() && NewOwnerID != 0) // ok, no charming yourself now =p return; ownerid = NewOwnerID; - if (ownerid == 0 && this->IsNPC() && this->GetPetType() != petCharmed) - this->Depop(); + // if we're setting the owner ID to 0 and they're not either charmed or not-a-pet then + // they're a normal pet and should be despawned + if (ownerid == 0 && IsNPC() && GetPetType() != petCharmed && GetPetType() != petNone) + Depop(); } // used in checking for behind (backstab) and checking in front (melee LoS) @@ -2192,28 +2375,27 @@ void Mob::SetZone(uint32 zone_id, uint32 instance_id) { CastToClient()->GetPP().zone_id = zone_id; CastToClient()->GetPP().zoneInstance = instance_id; - CastToClient()->Save(); } Save(); } void Mob::Kill() { - Death(this, 0, SPELL_UNKNOWN, SkillHandtoHand); + Death(this, 0, SPELL_UNKNOWN, EQEmu::skills::SkillHandtoHand); } bool Mob::CanThisClassDualWield(void) const { if(!IsClient()) { - return(GetSkill(SkillDualWield) > 0); + return(GetSkill(EQEmu::skills::SkillDualWield) > 0); } - else if(CastToClient()->HasSkill(SkillDualWield)) { - const ItemInst* pinst = CastToClient()->GetInv().GetItem(MainPrimary); - const ItemInst* sinst = CastToClient()->GetInv().GetItem(MainSecondary); + else if (CastToClient()->HasSkill(EQEmu::skills::SkillDualWield)) { + const ItemInst* pinst = CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotPrimary); + const ItemInst* sinst = CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotSecondary); // 2HS, 2HB, or 2HP if(pinst && pinst->IsWeapon()) { - const Item_Struct* item = pinst->GetItem(); + const EQEmu::ItemBase* item = pinst->GetItem(); - if((item->ItemType == ItemType2HBlunt) || (item->ItemType == ItemType2HSlash) || (item->ItemType == ItemType2HPiercing)) + if (item->IsType2HWeapon()) return false; } @@ -2235,15 +2417,23 @@ bool Mob::CanThisClassDualWield(void) const { bool Mob::CanThisClassDoubleAttack(void) const { if(!IsClient()) { - return(GetSkill(SkillDoubleAttack) > 0); + return(GetSkill(EQEmu::skills::SkillDoubleAttack) > 0); } else { if(aabonuses.GiveDoubleAttack || itembonuses.GiveDoubleAttack || spellbonuses.GiveDoubleAttack) { return true; } - return(CastToClient()->HasSkill(SkillDoubleAttack)); + return(CastToClient()->HasSkill(EQEmu::skills::SkillDoubleAttack)); } } +bool Mob::CanThisClassTripleAttack() const +{ + if (!IsClient()) + return false; // When they added the real triple attack skill, mobs lost the ability to triple + else + return CastToClient()->HasSkill(EQEmu::skills::SkillTripleAttack); +} + bool Mob::IsWarriorClass(void) const { switch(GetClass()) @@ -2280,36 +2470,36 @@ bool Mob::IsWarriorClass(void) const bool Mob::CanThisClassParry(void) const { if(!IsClient()) { - return(GetSkill(SkillParry) > 0); + return(GetSkill(EQEmu::skills::SkillParry) > 0); } else { - return(CastToClient()->HasSkill(SkillParry)); + return(CastToClient()->HasSkill(EQEmu::skills::SkillParry)); } } bool Mob::CanThisClassDodge(void) const { if(!IsClient()) { - return(GetSkill(SkillDodge) > 0); + return(GetSkill(EQEmu::skills::SkillDodge) > 0); } else { - return(CastToClient()->HasSkill(SkillDodge)); + return(CastToClient()->HasSkill(EQEmu::skills::SkillDodge)); } } bool Mob::CanThisClassRiposte(void) const { if(!IsClient()) { - return(GetSkill(SkillRiposte) > 0); + return(GetSkill(EQEmu::skills::SkillRiposte) > 0); } else { - return(CastToClient()->HasSkill(SkillRiposte)); + return(CastToClient()->HasSkill(EQEmu::skills::SkillRiposte)); } } bool Mob::CanThisClassBlock(void) const { if(!IsClient()) { - return(GetSkill(SkillBlock) > 0); + return(GetSkill(EQEmu::skills::SkillBlock) > 0); } else { - return(CastToClient()->HasSkill(SkillBlock)); + return(CastToClient()->HasSkill(EQEmu::skills::SkillBlock)); } } /* @@ -2516,6 +2706,8 @@ bool Mob::RemoveFromHateList(Mob* mob) { AI_Event_NoLongerEngaged(); zone->DelAggroMob(); + if (IsNPC() && !RuleB(Aggro, AllowTickPulling)) + ResetAssistCap(); } } if(GetTarget() == mob) @@ -2558,9 +2750,37 @@ uint32 NPC::GetEquipment(uint8 material_slot) const return equipment[invslot]; } -void Mob::SendWearChange(uint8 material_slot) +void Mob::SendArmorAppearance(Client *one_client) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + // one_client of 0 means sent to all clients + // + // Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the + // armor being worn and its mats, the client doesn't update the display + // on arrival of these packets reliably. + // + // Send Wear changes if mob is a PC race and item is an armor slot. + // The other packets work for primary/secondary. + + if (IsPlayerRace(race)) + { + if (!IsClient()) + { + const EQEmu::ItemBase *item; + for (int i = 0; i < 7; ++i) + { + item = database.GetItem(GetEquipment(i)); + if (item != 0) + { + SendWearChange(i, one_client); + } + } + } + } +} + +void Mob::SendWearChange(uint8 material_slot, Client *one_client) +{ + auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; wc->spawn_id = GetID(); @@ -2570,13 +2790,21 @@ void Mob::SendWearChange(uint8 material_slot) wc->color.Color = GetEquipmentColor(material_slot); wc->wear_slot_id = material_slot; - entity_list.QueueClients(this, outapp); + if (!one_client) + { + entity_list.QueueClients(this, outapp); + } + else + { + one_client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED); + } + safe_delete(outapp); } void Mob::SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model, uint32 elite_material, uint32 unknown06, uint32 unknown18) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; wc->spawn_id = this->GetID(); @@ -2604,9 +2832,9 @@ void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uin color |= (green_tint & 0xFF) << 8; color |= (blue_tint & 0xFF); color |= (color) ? (0xFF << 24) : 0; - armor_tint[material_slot] = color; + armor_tint.Slot[material_slot].Color = color; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; wc->spawn_id = this->GetID(); @@ -2621,9 +2849,9 @@ void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uin void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model) { - armor_tint[material_slot] = color; + armor_tint.Slot[material_slot].Color = color; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); + auto outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; wc->spawn_id = this->GetID(); @@ -2640,13 +2868,13 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const { uint32 equipmaterial = 0; int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - const Item_Struct *item; + const EQEmu::ItemBase *item; item = database.GetItem(GetEquipment(material_slot)); if (item != 0) { // For primary and secondary we need the model, not the material - if (material_slot == MaterialPrimary || material_slot == MaterialSecondary) + if (material_slot == EQEmu::textures::TexturePrimary || material_slot == EQEmu::textures::TextureSecondary) { if (this->IsClient()) { @@ -2690,13 +2918,13 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const int32 Mob::GetHerosForgeModel(uint8 material_slot) const { uint32 HeroModel = 0; - if (material_slot >= 0 && material_slot < MaterialPrimary) + if (material_slot >= 0 && material_slot < EQEmu::textures::TexturePrimary) { uint32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType); - const Item_Struct *item; + const EQEmu::ItemBase *item; item = database.GetItem(GetEquipment(material_slot)); int16 invslot = Inventory::CalcSlotFromMaterial(material_slot); - + if (item != 0 && invslot != INVALID_INDEX) { if (IsClient()) @@ -2747,11 +2975,11 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const uint32 Mob::GetEquipmentColor(uint8 material_slot) const { - const Item_Struct *item; + const EQEmu::ItemBase *item; - if (armor_tint[material_slot]) + if (armor_tint.Slot[material_slot].Color) { - return armor_tint[material_slot]; + return armor_tint.Slot[material_slot].Color; } item = database.GetItem(GetEquipment(material_slot)); @@ -2763,7 +2991,7 @@ uint32 Mob::GetEquipmentColor(uint8 material_slot) const uint32 Mob::IsEliteMaterialItem(uint8 material_slot) const { - const Item_Struct *item; + const EQEmu::ItemBase *item; item = database.GetItem(GetEquipment(material_slot)); if(item != 0) @@ -2954,10 +3182,10 @@ uint32 Mob::GetLevelHP(uint8 tlevel) } int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime) { - + int32 cast_reducer = 0; cast_reducer += GetFocusEffect(focusSpellHaste, spell_id); - + if (level >= 60 && casttime > 1000) { casttime = casttime / 2; @@ -2975,7 +3203,7 @@ int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime) { return casttime; } -void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on) { +void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on, int level_override) { // Changed proc targets to look up based on the spells goodEffect flag. // This should work for the majority of weapons. if(spell_id == SPELL_UNKNOWN || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) { @@ -3013,15 +3241,15 @@ void Mob::ExecWeaponProc(const ItemInst *inst, uint16 spell_id, Mob *on) { if(twinproc_chance && zone->random.Roll(twinproc_chance)) twinproc = true; - if (IsBeneficialSpell(spell_id)) { - SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff, true); + if (IsBeneficialSpell(spell_id) && (!IsNPC() || (IsNPC() && CastToNPC()->GetInnateProcSpellID() != spell_id))) { // NPC innate procs don't take this path ever + SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff, true, level_override); if(twinproc) - SpellOnTarget(spell_id, this, false, false, 0, true); + SpellOnTarget(spell_id, this, false, false, 0, true, level_override); } else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients - SpellFinished(spell_id, on, 10, 0, -1, spells[spell_id].ResistDiff, true); + SpellFinished(spell_id, on, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff, true, level_override); if(twinproc) - SpellOnTarget(spell_id, on, false, false, 0, true); + SpellOnTarget(spell_id, on, false, false, 0, true, level_override); } return; } @@ -3181,31 +3409,32 @@ int Mob::GetSnaredAmount() return worst_snare; } -void Mob::TriggerDefensiveProcs(const ItemInst* weapon, Mob *on, uint16 hand, int damage) +void Mob::TriggerDefensiveProcs(Mob *on, uint16 hand, bool FromSkillProc, int damage) { if (!on) return; - on->TryDefensiveProc(weapon, this, hand); + if (!FromSkillProc) + on->TryDefensiveProc(this, hand); //Defensive Skill Procs if (damage < 0 && damage >= -4) { uint16 skillinuse = 0; switch (damage) { case (-1): - skillinuse = SkillBlock; + skillinuse = EQEmu::skills::SkillBlock; break; case (-2): - skillinuse = SkillParry; + skillinuse = EQEmu::skills::SkillParry; break; case (-3): - skillinuse = SkillRiposte; + skillinuse = EQEmu::skills::SkillRiposte; break; case (-4): - skillinuse = SkillDodge; + skillinuse = EQEmu::skills::SkillDodge; break; } @@ -3229,7 +3458,7 @@ void Mob::SetEntityVariable(const char *id, const char *m_var) const char* Mob::GetEntityVariable(const char *id) { - std::map::iterator iter = m_EntityVariables.find(id); + auto iter = m_EntityVariables.find(id); if(iter != m_EntityVariables.end()) { return iter->second.c_str(); @@ -3239,7 +3468,7 @@ const char* Mob::GetEntityVariable(const char *id) bool Mob::EntityVariableExists(const char *id) { - std::map::iterator iter = m_EntityVariables.find(id); + auto iter = m_EntityVariables.find(id); if(iter != m_EntityVariables.end()) { return true; @@ -3306,27 +3535,30 @@ void Mob::TryTriggerOnCast(uint32 spell_id, bool aa_trigger) } } - void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger) { - if(!IsValidSpell(focus_spell) || !IsValidSpell(spell_id)) + if (!IsValidSpell(focus_spell) || !IsValidSpell(spell_id)) return; uint32 trigger_spell_id = 0; - if (aa_trigger && IsClient()){ - //focus_spell = aaid - trigger_spell_id = CastToClient()->CalcAAFocus(focusTriggerOnCast, focus_spell, spell_id); + if (aa_trigger && IsClient()) { + // focus_spell = aaid + auto rank = zone->GetAlternateAdvancementRank(focus_spell); + if (rank) + trigger_spell_id = CastToClient()->CalcAAFocus(focusTriggerOnCast, *rank, spell_id); - if(IsValidSpell(trigger_spell_id) && GetTarget()) - SpellFinished(trigger_spell_id, GetTarget(), 10, 0, -1, spells[trigger_spell_id].ResistDiff); + if (IsValidSpell(trigger_spell_id) && GetTarget()) + SpellFinished(trigger_spell_id, GetTarget(), EQEmu::CastingSlot::Item, 0, -1, + spells[trigger_spell_id].ResistDiff); } - else{ + else { trigger_spell_id = CalcFocusEffect(focusTriggerOnCast, focus_spell, spell_id); - if(IsValidSpell(trigger_spell_id) && GetTarget()){ - SpellFinished(trigger_spell_id, GetTarget(),10, 0, -1, spells[trigger_spell_id].ResistDiff); + if (IsValidSpell(trigger_spell_id) && GetTarget()) { + SpellFinished(trigger_spell_id, GetTarget(), EQEmu::CastingSlot::Item, 0, -1, + spells[trigger_spell_id].ResistDiff); CheckNumHitsRemaining(NumHit::MatchingSpells, -1, focus_spell); } } @@ -3356,7 +3588,7 @@ bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect) { // If we trigger an effect then its over. if (IsValidSpell(spells[spell_id].base2[i])){ - SpellFinished(spells[spell_id].base2[i], target, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff); + SpellFinished(spells[spell_id].base2[i], target, EQEmu::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff); return true; } } @@ -3375,7 +3607,7 @@ bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect) if(zone->random.Int(0, 100) <= spells[spell_id].base[effect]) { if (IsValidSpell(spells[spell_id].base2[effect])){ - SpellFinished(spells[spell_id].base2[effect], target, 10, 0, -1, spells[spells[spell_id].base2[effect]].ResistDiff); + SpellFinished(spells[spell_id].base2[effect], target, EQEmu::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[effect]].ResistDiff); return true; //Only trigger once of these per spell effect. } } @@ -3452,7 +3684,7 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP } if (use_spell){ - SpellFinished(spells[spell_id].base[i], this, 10, 0, -1, spells[spell_id].ResistDiff); + SpellFinished(spells[spell_id].base[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff); if(!TryFadeEffect(e)) BuffFadeBySlot(e); @@ -3480,7 +3712,7 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id) if(zone->random.Roll(focus)) { Message(MT_Spells,"You twincast %s!",spells[spell_id].name); - SpellFinished(spell_id, target, 10, 0, -1, spells[spell_id].ResistDiff); + SpellFinished(spell_id, target, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff); } } } @@ -3498,7 +3730,7 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id) { if(zone->random.Roll(focus)) { - SpellFinished(spell_id, target, 10, 0, -1, spells[spell_id].ResistDiff); + SpellFinished(spell_id, target, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff); } } } @@ -3564,18 +3796,18 @@ int32 Mob::GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining) return value; } -int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used) +int16 Mob::GetSkillDmgTaken(const EQEmu::skills::SkillType skill_used, ExtraAttackOptions *opts) { int skilldmg_mod = 0; // All skill dmg mod + Skill specific - skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] + + skilldmg_mod += itembonuses.SkillDmgTaken[EQEmu::skills::HIGHEST_SKILL + 1] + spellbonuses.SkillDmgTaken[EQEmu::skills::HIGHEST_SKILL + 1] + itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used]; - - skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1]; + skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[EQEmu::skills::HIGHEST_SKILL + 1]; - skilldmg_mod += spellbonuses.MeleeVulnerability + itembonuses.MeleeVulnerability + aabonuses.MeleeVulnerability; + if (opts) + skilldmg_mod += opts->skilldmgtaken_bonus_flat; if(skilldmg_mod < -100) skilldmg_mod = -100; @@ -3617,10 +3849,10 @@ bool Mob::TryFadeEffect(int slot) if(IsValidSpell(spell_id)) { if (IsBeneficialSpell(spell_id)) { - SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff); + SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff); } else if(!(IsClient() && CastToClient()->dead)) { - SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff); + SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff); } return true; } @@ -3633,36 +3865,41 @@ bool Mob::TryFadeEffect(int slot) void Mob::TrySympatheticProc(Mob *target, uint32 spell_id) { - if(target == nullptr || !IsValidSpell(spell_id)) + if(target == nullptr || !IsValidSpell(spell_id) || !IsClient()) return; - int focus_spell = CastToClient()->GetSympatheticFocusEffect(focusSympatheticProc,spell_id); + uint16 focus_spell = CastToClient()->GetSympatheticFocusEffect(focusSympatheticProc,spell_id); - if(IsValidSpell(focus_spell)){ - int focus_trigger = spells[focus_spell].base2[0]; - // For beneficial spells, if the triggered spell is also beneficial then proc it on the target - // if the triggered spell is detrimental, then it will trigger on the caster(ie cursed items) - if(IsBeneficialSpell(spell_id)) - { - if(IsBeneficialSpell(focus_trigger)) - SpellFinished(focus_trigger, target); + if(!IsValidSpell(focus_spell)) + return; - else - SpellFinished(focus_trigger, this, 10, 0, -1, spells[focus_trigger].ResistDiff); - } - // For detrimental spells, if the triggered spell is beneficial, then it will land on the caster - // if the triggered spell is also detrimental, then it will land on the target - else - { - if(IsBeneficialSpell(focus_trigger)) - SpellFinished(focus_trigger, this); + uint16 focus_trigger = GetSympatheticSpellProcID(focus_spell); - else - SpellFinished(focus_trigger, target, 10, 0, -1, spells[focus_trigger].ResistDiff); - } + if(!IsValidSpell(focus_trigger)) + return; - CheckNumHitsRemaining(NumHit::MatchingSpells, -1, focus_spell); - } + // For beneficial spells, if the triggered spell is also beneficial then proc it on the target + // if the triggered spell is detrimental, then it will trigger on the caster(ie cursed items) + if(IsBeneficialSpell(spell_id)) + { + if(IsBeneficialSpell(focus_trigger)) + SpellFinished(focus_trigger, target); + + else + SpellFinished(focus_trigger, this, EQEmu::CastingSlot::Item, 0, -1, spells[focus_trigger].ResistDiff); + } + // For detrimental spells, if the triggered spell is beneficial, then it will land on the caster + // if the triggered spell is also detrimental, then it will land on the target + else + { + if(IsBeneficialSpell(focus_trigger)) + SpellFinished(focus_trigger, this); + + else + SpellFinished(focus_trigger, target, EQEmu::CastingSlot::Item, 0, -1, spells[focus_trigger].ResistDiff); + } + + CheckNumHitsRemaining(NumHit::MatchingSpells, -1, focus_spell); } int32 Mob::GetItemStat(uint32 itemid, const char *identifier) @@ -3671,7 +3908,7 @@ int32 Mob::GetItemStat(uint32 itemid, const char *identifier) if (!inst) return 0; - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); if (!item) return 0; @@ -4006,6 +4243,39 @@ int32 Mob::GetItemStat(uint32 itemid, const char *identifier) return stat; } +std::string Mob::GetGlobal(const char *varname) { + int qgCharid = 0; + int qgNpcid = 0; + + if (this->IsNPC()) + qgNpcid = this->GetNPCTypeID(); + + if (this->IsClient()) + qgCharid = this->CastToClient()->CharacterID(); + + QGlobalCache *qglobals = nullptr; + std::list globalMap; + + if (this->IsClient()) + qglobals = this->CastToClient()->GetQGlobals(); + + if (this->IsNPC()) + qglobals = this->CastToNPC()->GetQGlobals(); + + if(qglobals) + QGlobalCache::Combine(globalMap, qglobals->GetBucket(), qgNpcid, qgCharid, zone->GetZoneID()); + + auto iter = globalMap.begin(); + while(iter != globalMap.end()) { + if ((*iter).name.compare(varname) == 0) + return (*iter).value; + + ++iter; + } + + return "Undefined"; +} + void Mob::SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Mob *other) { int qgZoneid = zone->GetZoneID(); @@ -4081,7 +4351,7 @@ void Mob::DelGlobal(const char *varname) { if(zone) { - ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); + auto pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer; qgu->npc_id = qgNpcid; @@ -4120,7 +4390,7 @@ void Mob::InsertQuestGlobal(int charid, int npcid, int zoneid, const char *varna if(zone) { //first delete our global - ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); + auto pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer; qgd->npc_id = npcid; qgd->char_id = charid; @@ -4233,7 +4503,7 @@ void Mob::DoKnockback(Mob *caster, uint32 pushback, uint32 pushup) { CastToClient()->SetKnockBackExemption(true); - EQApplicationPacket* outapp_push = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + 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()); @@ -4277,7 +4547,7 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id) if (IsValidSpell(spells[spell_id].base2[i]) && spells[spell_id].max[i] <= level) { if(zone->random.Roll(spells[spell_id].base[i])) - SpellFinished(spells[spell_id].base2[i], this, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff); + SpellFinished(spells[spell_id].base2[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff); } } } @@ -4292,17 +4562,17 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id) if(aabonuses.SpellOnKill[i] && IsValidSpell(aabonuses.SpellOnKill[i]) && (level >= aabonuses.SpellOnKill[i + 2])) { if(zone->random.Roll(static_cast(aabonuses.SpellOnKill[i + 1]))) - SpellFinished(aabonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff); + SpellFinished(aabonuses.SpellOnKill[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff); } if(itembonuses.SpellOnKill[i] && IsValidSpell(itembonuses.SpellOnKill[i]) && (level >= itembonuses.SpellOnKill[i + 2])){ if(zone->random.Roll(static_cast(itembonuses.SpellOnKill[i + 1]))) - SpellFinished(itembonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff); + SpellFinished(itembonuses.SpellOnKill[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff); } if(spellbonuses.SpellOnKill[i] && IsValidSpell(spellbonuses.SpellOnKill[i]) && (level >= spellbonuses.SpellOnKill[i + 2])) { if(zone->random.Roll(static_cast(spellbonuses.SpellOnKill[i + 1]))) - SpellFinished(spellbonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff); + SpellFinished(spellbonuses.SpellOnKill[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff); } } @@ -4319,19 +4589,19 @@ bool Mob::TrySpellOnDeath() for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2) { if(IsClient() && aabonuses.SpellOnDeath[i] && IsValidSpell(aabonuses.SpellOnDeath[i])) { if(zone->random.Roll(static_cast(aabonuses.SpellOnDeath[i + 1]))) { - SpellFinished(aabonuses.SpellOnDeath[i], this, 10, 0, -1, spells[aabonuses.SpellOnDeath[i]].ResistDiff); + SpellFinished(aabonuses.SpellOnDeath[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[aabonuses.SpellOnDeath[i]].ResistDiff); } } if(itembonuses.SpellOnDeath[i] && IsValidSpell(itembonuses.SpellOnDeath[i])) { if(zone->random.Roll(static_cast(itembonuses.SpellOnDeath[i + 1]))) { - SpellFinished(itembonuses.SpellOnDeath[i], this, 10, 0, -1, spells[itembonuses.SpellOnDeath[i]].ResistDiff); + SpellFinished(itembonuses.SpellOnDeath[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[itembonuses.SpellOnDeath[i]].ResistDiff); } } if(spellbonuses.SpellOnDeath[i] && IsValidSpell(spellbonuses.SpellOnDeath[i])) { if(zone->random.Roll(static_cast(spellbonuses.SpellOnDeath[i + 1]))) { - SpellFinished(spellbonuses.SpellOnDeath[i], this, 10, 0, -1, spells[spellbonuses.SpellOnDeath[i]].ResistDiff); + SpellFinished(spellbonuses.SpellOnDeath[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spellbonuses.SpellOnDeath[i]].ResistDiff); } } } @@ -4348,7 +4618,7 @@ int16 Mob::GetCritDmgMob(uint16 skill) int critDmg_mod = 0; // All skill dmg mod + Skill specific - critDmg_mod += itembonuses.CritDmgMob[HIGHEST_SKILL+1] + spellbonuses.CritDmgMob[HIGHEST_SKILL+1] + aabonuses.CritDmgMob[HIGHEST_SKILL+1] + + critDmg_mod += itembonuses.CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 1] + spellbonuses.CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 1] + aabonuses.CritDmgMob[EQEmu::skills::HIGHEST_SKILL + 1] + itembonuses.CritDmgMob[skill] + spellbonuses.CritDmgMob[skill] + aabonuses.CritDmgMob[skill]; if(critDmg_mod < -100) @@ -4393,7 +4663,7 @@ int16 Mob::GetCriticalChanceBonus(uint16 skill) int critical_chance = 0; // All skills + Skill specific - critical_chance += itembonuses.CriticalHitChance[HIGHEST_SKILL+1] + spellbonuses.CriticalHitChance[HIGHEST_SKILL+1] + aabonuses.CriticalHitChance[HIGHEST_SKILL+1] + + critical_chance += itembonuses.CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 1] + spellbonuses.CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 1] + aabonuses.CriticalHitChance[EQEmu::skills::HIGHEST_SKILL + 1] + itembonuses.CriticalHitChance[skill] + spellbonuses.CriticalHitChance[skill] + aabonuses.CriticalHitChance[skill]; if(critical_chance < -100) @@ -4407,10 +4677,10 @@ int16 Mob::GetMeleeDamageMod_SE(uint16 skill) int dmg_mod = 0; // All skill dmg mod + Skill specific - dmg_mod += itembonuses.DamageModifier[HIGHEST_SKILL+1] + spellbonuses.DamageModifier[HIGHEST_SKILL+1] + aabonuses.DamageModifier[HIGHEST_SKILL+1] + + dmg_mod += itembonuses.DamageModifier[EQEmu::skills::HIGHEST_SKILL + 1] + spellbonuses.DamageModifier[EQEmu::skills::HIGHEST_SKILL + 1] + aabonuses.DamageModifier[EQEmu::skills::HIGHEST_SKILL + 1] + itembonuses.DamageModifier[skill] + spellbonuses.DamageModifier[skill] + aabonuses.DamageModifier[skill]; - dmg_mod += itembonuses.DamageModifier2[HIGHEST_SKILL+1] + spellbonuses.DamageModifier2[HIGHEST_SKILL+1] + aabonuses.DamageModifier2[HIGHEST_SKILL+1] + + dmg_mod += itembonuses.DamageModifier2[EQEmu::skills::HIGHEST_SKILL + 1] + spellbonuses.DamageModifier2[EQEmu::skills::HIGHEST_SKILL + 1] + aabonuses.DamageModifier2[EQEmu::skills::HIGHEST_SKILL + 1] + itembonuses.DamageModifier2[skill] + spellbonuses.DamageModifier2[skill] + aabonuses.DamageModifier2[skill]; if (HasShieldEquiped() && !IsOffHandAtk()) @@ -4427,7 +4697,7 @@ int16 Mob::GetMeleeMinDamageMod_SE(uint16 skill) int dmg_mod = 0; dmg_mod = itembonuses.MinDamageModifier[skill] + spellbonuses.MinDamageModifier[skill] + - itembonuses.MinDamageModifier[HIGHEST_SKILL+1] + spellbonuses.MinDamageModifier[HIGHEST_SKILL+1]; + itembonuses.MinDamageModifier[EQEmu::skills::HIGHEST_SKILL + 1] + spellbonuses.MinDamageModifier[EQEmu::skills::HIGHEST_SKILL + 1]; if(dmg_mod < -100) dmg_mod = -100; @@ -4459,10 +4729,10 @@ int16 Mob::GetSkillDmgAmt(uint16 skill) int skill_dmg = 0; // All skill dmg(only spells do this) + Skill specific - skill_dmg += spellbonuses.SkillDamageAmount[HIGHEST_SKILL+1] + itembonuses.SkillDamageAmount[HIGHEST_SKILL+1] + aabonuses.SkillDamageAmount[HIGHEST_SKILL+1] + skill_dmg += spellbonuses.SkillDamageAmount[EQEmu::skills::HIGHEST_SKILL + 1] + itembonuses.SkillDamageAmount[EQEmu::skills::HIGHEST_SKILL + 1] + aabonuses.SkillDamageAmount[EQEmu::skills::HIGHEST_SKILL + 1] + itembonuses.SkillDamageAmount[skill] + spellbonuses.SkillDamageAmount[skill] + aabonuses.SkillDamageAmount[skill]; - skill_dmg += spellbonuses.SkillDamageAmount2[HIGHEST_SKILL+1] + itembonuses.SkillDamageAmount2[HIGHEST_SKILL+1] + skill_dmg += spellbonuses.SkillDamageAmount2[EQEmu::skills::HIGHEST_SKILL + 1] + itembonuses.SkillDamageAmount2[EQEmu::skills::HIGHEST_SKILL + 1] + itembonuses.SkillDamageAmount2[skill] + spellbonuses.SkillDamageAmount2[skill]; return skill_dmg; @@ -4482,7 +4752,7 @@ void Mob::MeleeLifeTap(int32 damage) { if (lifetap_amt > 0) HealDamage(lifetap_amt); //Heal self for modified damage amount. else - Damage(this, -lifetap_amt,0, SkillEvocation,false); //Dmg self for modified damage amount. + Damage(this, -lifetap_amt, 0, EQEmu::skills::SkillEvocation, false); //Dmg self for modified damage amount. } } @@ -4622,7 +4892,7 @@ void Mob::RemoveNimbusEffect(int effectid) else if (effectid == nimbus_effect3) nimbus_effect3 = 0; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RemoveNimbusEffect, sizeof(RemoveNimbusEffect_Struct)); + auto outapp = new EQApplicationPacket(OP_RemoveNimbusEffect, sizeof(RemoveNimbusEffect_Struct)); RemoveNimbusEffect_Struct* rne = (RemoveNimbusEffect_Struct*)outapp->pBuffer; rne->spawnid = GetID(); rne->nimbus_effect = effectid; @@ -4646,7 +4916,7 @@ void Mob::SetBodyType(bodyType new_body, bool overwrite_orig) { bodytype = new_body; if(needs_spawn_packet) { - EQApplicationPacket* app = new EQApplicationPacket; + auto app = new EQApplicationPacket; CreateDespawnPacket(app, true); entity_list.QueueClients(this, app); CreateSpawnPacket(app, this); @@ -4656,21 +4926,21 @@ void Mob::SetBodyType(bodyType new_body, bool overwrite_orig) { } -void Mob::ModSkillDmgTaken(SkillUseTypes skill_num, int value) +void Mob::ModSkillDmgTaken(EQEmu::skills::SkillType skill_num, int value) { if (skill_num == ALL_SKILLS) - SkillDmgTaken_Mod[HIGHEST_SKILL+1] = value; + SkillDmgTaken_Mod[EQEmu::skills::HIGHEST_SKILL + 1] = value; - else if (skill_num >= 0 && skill_num <= HIGHEST_SKILL) + else if (skill_num >= 0 && skill_num <= EQEmu::skills::HIGHEST_SKILL) SkillDmgTaken_Mod[skill_num] = value; } -int16 Mob::GetModSkillDmgTaken(const SkillUseTypes skill_num) +int16 Mob::GetModSkillDmgTaken(const EQEmu::skills::SkillType skill_num) { if (skill_num == ALL_SKILLS) - return SkillDmgTaken_Mod[HIGHEST_SKILL+1]; + return SkillDmgTaken_Mod[EQEmu::skills::HIGHEST_SKILL + 1]; - else if (skill_num >= 0 && skill_num <= HIGHEST_SKILL) + else if (skill_num >= 0 && skill_num <= EQEmu::skills::HIGHEST_SKILL) return SkillDmgTaken_Mod[skill_num]; return 0; @@ -4761,57 +5031,58 @@ void Mob::SlowMitigation(Mob* caster) uint16 Mob::GetSkillByItemType(int ItemType) { - switch (ItemType) - { - case ItemType1HSlash: - return Skill1HSlashing; - case ItemType2HSlash: - return Skill2HSlashing; - case ItemType1HPiercing: - return Skill1HPiercing; - case ItemType1HBlunt: - return Skill1HBlunt; - case ItemType2HBlunt: - return Skill2HBlunt; - case ItemType2HPiercing: - return Skill1HPiercing; // change to 2HPiercing once activated - case ItemTypeBow: - return SkillArchery; - case ItemTypeLargeThrowing: - case ItemTypeSmallThrowing: - return SkillThrowing; - case ItemTypeMartial: - return SkillHandtoHand; - default: - return SkillHandtoHand; + switch (ItemType) { + case EQEmu::item::ItemType1HSlash: + return EQEmu::skills::Skill1HSlashing; + case EQEmu::item::ItemType2HSlash: + return EQEmu::skills::Skill2HSlashing; + case EQEmu::item::ItemType1HPiercing: + return EQEmu::skills::Skill1HPiercing; + case EQEmu::item::ItemType1HBlunt: + return EQEmu::skills::Skill1HBlunt; + case EQEmu::item::ItemType2HBlunt: + return EQEmu::skills::Skill2HBlunt; + case EQEmu::item::ItemType2HPiercing: + if (IsClient() && CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::RoF2) + return EQEmu::skills::Skill1HPiercing; + else + return EQEmu::skills::Skill2HPiercing; + case EQEmu::item::ItemTypeBow: + return EQEmu::skills::SkillArchery; + case EQEmu::item::ItemTypeLargeThrowing: + case EQEmu::item::ItemTypeSmallThrowing: + return EQEmu::skills::SkillThrowing; + case EQEmu::item::ItemTypeMartial: + return EQEmu::skills::SkillHandtoHand; + default: + return EQEmu::skills::SkillHandtoHand; } - return SkillHandtoHand; } -uint8 Mob::GetItemTypeBySkill(SkillUseTypes skill) +uint8 Mob::GetItemTypeBySkill(EQEmu::skills::SkillType skill) { - switch (skill) - { - case SkillThrowing: - return ItemTypeSmallThrowing; - case SkillArchery: - return ItemTypeArrow; - case Skill1HSlashing: - return ItemType1HSlash; - case Skill2HSlashing: - return ItemType2HSlash; - case Skill1HPiercing: - return ItemType1HPiercing; - case Skill1HBlunt: - return ItemType1HBlunt; - case Skill2HBlunt: - return ItemType2HBlunt; - case SkillHandtoHand: - return ItemTypeMartial; - default: - return ItemTypeMartial; + switch (skill) { + case EQEmu::skills::SkillThrowing: + return EQEmu::item::ItemTypeSmallThrowing; + case EQEmu::skills::SkillArchery: + return EQEmu::item::ItemTypeArrow; + case EQEmu::skills::Skill1HSlashing: + return EQEmu::item::ItemType1HSlash; + case EQEmu::skills::Skill2HSlashing: + return EQEmu::item::ItemType2HSlash; + case EQEmu::skills::Skill1HPiercing: + return EQEmu::item::ItemType1HPiercing; + case EQEmu::skills::Skill2HPiercing: // watch for undesired client behavior + return EQEmu::item::ItemType2HPiercing; + case EQEmu::skills::Skill1HBlunt: + return EQEmu::item::ItemType1HBlunt; + case EQEmu::skills::Skill2HBlunt: + return EQEmu::item::ItemType2HBlunt; + case EQEmu::skills::SkillHandtoHand: + return EQEmu::item::ItemTypeMartial; + default: + return EQEmu::item::ItemTypeMartial; } - return ItemTypeMartial; } @@ -4857,7 +5128,7 @@ int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) { if (!IsValidSpell(spell_id)) return false; - int spell_level = spells[spell_id].classes[(GetClass()%16) - 1]; + int spell_level = spells[spell_id].classes[(GetClass()%17) - 1]; int effect_value = 0; int lvlModifier = 100; @@ -5284,7 +5555,7 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot) if (slot < 4){ if (id == "components") { return spells[spell_id].components[slot];} - else if (id == "component_counts") { return spells[spell_id].component_counts[slot];} + else if (id == "component_counts") { return spells[spell_id].component_counts[slot];} else if (id == "NoexpendReagent") {return spells[spell_id].NoexpendReagent[slot];} } @@ -5344,31 +5615,31 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot) else if (id == "NimbusEffect") {return spells[spell_id].NimbusEffect; } else if (id == "directional_start") {return static_cast(spells[spell_id].directional_start); } else if (id == "directional_end") {return static_cast(spells[spell_id].directional_end); } - else if (id == "not_extendable") {return spells[spell_id].not_extendable; } + else if (id == "not_focusable") {return spells[spell_id].not_focusable; } else if (id == "suspendable") {return spells[spell_id].suspendable; } else if (id == "viral_range") {return spells[spell_id].viral_range; } else if (id == "spellgroup") {return spells[spell_id].spellgroup; } else if (id == "rank") {return spells[spell_id].rank; } - else if (id == "powerful_flag") {return spells[spell_id].powerful_flag; } + else if (id == "no_resist") {return spells[spell_id].no_resist; } else if (id == "CastRestriction") {return spells[spell_id].CastRestriction; } else if (id == "AllowRest") {return spells[spell_id].AllowRest; } else if (id == "InCombat") {return spells[spell_id].InCombat; } else if (id == "OutofCombat") {return spells[spell_id].OutofCombat; } else if (id == "aemaxtargets") {return spells[spell_id].aemaxtargets; } - else if (id == "maxtargets") {return spells[spell_id].maxtargets; } + else if (id == "no_heal_damage_item_mod") {return spells[spell_id].no_heal_damage_item_mod; } else if (id == "persistdeath") {return spells[spell_id].persistdeath; } else if (id == "min_dist") {return static_cast(spells[spell_id].min_dist); } else if (id == "min_dist_mod") {return static_cast(spells[spell_id].min_dist_mod); } else if (id == "max_dist") {return static_cast(spells[spell_id].max_dist); } else if (id == "min_range") {return static_cast(spells[spell_id].min_range); } else if (id == "DamageShieldType") {return spells[spell_id].DamageShieldType; } - + return stat; } bool Mob::CanClassEquipItem(uint32 item_id) { - const Item_Struct* itm = nullptr; + const EQEmu::ItemBase* itm = nullptr; itm = database.GetItem(item_id); if (!itm) @@ -5382,9 +5653,309 @@ bool Mob::CanClassEquipItem(uint32 item_id) int bitmask = 1; bitmask = bitmask << (GetClass() - 1); - + if(!(itm->Classes & bitmask)) return false; else return true; } + +void Mob::SendAddPlayerState(PlayerState new_state) +{ + auto app = new EQApplicationPacket(OP_PlayerStateAdd, sizeof(PlayerState_Struct)); + auto ps = (PlayerState_Struct *)app->pBuffer; + + ps->spawn_id = GetID(); + ps->state = static_cast(new_state); + + AddPlayerState(ps->state); + entity_list.QueueClients(nullptr, app); + safe_delete(app); +} + +void Mob::SendRemovePlayerState(PlayerState old_state) +{ + auto app = new EQApplicationPacket(OP_PlayerStateRemove, sizeof(PlayerState_Struct)); + auto ps = (PlayerState_Struct *)app->pBuffer; + + ps->spawn_id = GetID(); + ps->state = static_cast(old_state); + + RemovePlayerState(ps->state); + entity_list.QueueClients(nullptr, app); + safe_delete(app); +} + +void Mob::SetCurrentSpeed(int in){ + if (current_speed != in) + { + current_speed = in; + tar_ndx = 20; + if (in == 0) { + SetRunAnimSpeed(0); + SetMoving(false); + SendPosition(); + } + } +} + +int32 Mob::GetMeleeMitigation() { + int32 mitigation = 0; + mitigation += spellbonuses.MeleeMitigationEffect; + mitigation += itembonuses.MeleeMitigationEffect; + mitigation += aabonuses.MeleeMitigationEffect; + return mitigation; +} + +/* this is the mob being attacked. + * Pass in the weapon's ItemInst + */ +int Mob::ResistElementalWeaponDmg(const ItemInst *item) +{ + if (!item) + return 0; + int magic = 0, fire = 0, cold = 0, poison = 0, disease = 0, chromatic = 0, prismatic = 0, physical = 0, + corruption = 0; + int resist = 0; + int roll = 0; + /* this is how the client does the resist rolls for these. + * Given the difficulty of parsing out these resists, I'll trust the client + */ + if (item->GetItemElementalDamage(magic, fire, cold, poison, disease, chromatic, prismatic, physical, corruption, true)) { + if (magic) { + resist = GetMR(); + if (resist >= 201) { + magic = 0; + } else { + roll = zone->random.Int(0, 200) - resist; + if (roll < 1) + magic = 0; + else if (roll < 100) + magic = magic * roll / 100; + } + } + + if (fire) { + resist = GetFR(); + if (resist >= 201) { + fire = 0; + } else { + roll = zone->random.Int(0, 200) - resist; + if (roll < 1) + fire = 0; + else if (roll < 100) + fire = fire * roll / 100; + } + } + + if (cold) { + resist = GetCR(); + if (resist >= 201) { + cold = 0; + } else { + roll = zone->random.Int(0, 200) - resist; + if (roll < 1) + cold = 0; + else if (roll < 100) + cold = cold * roll / 100; + } + } + + if (poison) { + resist = GetPR(); + if (resist >= 201) { + poison = 0; + } else { + roll = zone->random.Int(0, 200) - resist; + if (roll < 1) + poison = 0; + else if (roll < 100) + poison = poison * roll / 100; + } + } + + if (disease) { + resist = GetDR(); + if (resist >= 201) { + disease = 0; + } else { + roll = zone->random.Int(0, 200) - resist; + if (roll < 1) + disease = 0; + else if (roll < 100) + disease = disease * roll / 100; + } + } + + if (corruption) { + resist = GetCorrup(); + if (resist >= 201) { + corruption = 0; + } else { + roll = zone->random.Int(0, 200) - resist; + if (roll < 1) + corruption = 0; + else if (roll < 100) + corruption = corruption * roll / 100; + } + } + + if (chromatic) { + resist = GetFR(); + int temp = GetCR(); + if (temp < resist) + resist = temp; + + temp = GetMR(); + if (temp < resist) + resist = temp; + + temp = GetDR(); + if (temp < resist) + resist = temp; + + temp = GetPR(); + if (temp < resist) + resist = temp; + + if (resist >= 201) { + chromatic = 0; + } else { + roll = zone->random.Int(0, 200) - resist; + if (roll < 1) + chromatic = 0; + else if (roll < 100) + chromatic = chromatic * roll / 100; + } + } + + if (prismatic) { + resist = (GetFR() + GetCR() + GetMR() + GetDR() + GetPR()) / 5; + if (resist >= 201) { + prismatic = 0; + } else { + roll = zone->random.Int(0, 200) - resist; + if (roll < 1) + prismatic = 0; + else if (roll < 100) + prismatic = prismatic * roll / 100; + } + } + + if (physical) { + resist = GetPhR(); + if (resist >= 201) { + physical = 0; + } else { + roll = zone->random.Int(0, 200) - resist; + if (roll < 1) + physical = 0; + else if (roll < 100) + physical = physical * roll / 100; + } + } + } + + return magic + fire + cold + poison + disease + chromatic + prismatic + physical + corruption; +} + +/* this is the mob being attacked. + * Pass in the weapon's ItemInst + */ +int Mob::CheckBaneDamage(const ItemInst *item) +{ + if (!item) + return 0; + + int damage = item->GetItemBaneDamageBody(GetBodyType(), true); + damage += item->GetItemBaneDamageRace(GetRace(), true); + + return damage; +} + +void Mob::CancelSneakHide() +{ + if (hidden || improved_hidden) { + hidden = false; + improved_hidden = false; + auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + SpawnAppearance_Struct* sa_out = (SpawnAppearance_Struct*)outapp->pBuffer; + sa_out->spawn_id = GetID(); + sa_out->type = 0x03; + sa_out->parameter = 0; + entity_list.QueueClients(this, outapp, true); + safe_delete(outapp); + } +} + +void Mob::CommonBreakInvisible() +{ + BreakInvisibleSpells(); + CancelSneakHide(); +} + +#ifdef BOTS +bool Mob::JoinHealRotationTargetPool(std::shared_ptr* heal_rotation) +{ + if (IsHealRotationTarget()) + return false; + if (!heal_rotation->use_count()) + return false; + if (!(*heal_rotation)) + return false; + if (!IsHealRotationTargetMobType(this)) + return false; + + if (!(*heal_rotation)->AddTargetToPool(this)) + return false; + + m_target_of_heal_rotation = *heal_rotation; + + return IsHealRotationTarget(); +} + +bool Mob::LeaveHealRotationTargetPool() +{ + if (!IsHealRotationTarget()) { + m_target_of_heal_rotation.reset(); + return true; + } + + m_target_of_heal_rotation->RemoveTargetFromPool(this); + m_target_of_heal_rotation.reset(); + + return !IsHealRotationTarget(); +} + +uint32 Mob::HealRotationHealCount() +{ + if (!IsHealRotationTarget()) + return 0; + + return m_target_of_heal_rotation->HealCount(this); +} + +uint32 Mob::HealRotationExtendedHealCount() +{ + if (!IsHealRotationTarget()) + return 0; + + return m_target_of_heal_rotation->ExtendedHealCount(this); +} + +float Mob::HealRotationHealFrequency() +{ + if (!IsHealRotationTarget()) + return 0.0f; + + return m_target_of_heal_rotation->HealFrequency(this); +} + +float Mob::HealRotationExtendedHealFrequency() +{ + if (!IsHealRotationTarget()) + return 0.0f; + + return m_target_of_heal_rotation->ExtendedHealFrequency(this); +} +#endif diff --git a/zone/mob.h b/zone/mob.h index 6d7b386cf..927ecf862 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,10 +23,18 @@ #include "hate_list.h" #include "pathing.h" #include "position.h" +#include "aa_ability.h" +#include "aa.h" +#include "../common/light_source.h" +#include "../common/emu_constants.h" #include #include #include +#ifdef BOTS +#include "heal_rotation.h" +#endif + char* strn0cpy(char* dest, const char* source, uint32 size); #define MAX_SPECIAL_ATTACK_PARAMS 8 @@ -38,10 +46,14 @@ class Group; class ItemInst; class NPC; class Raid; -struct Item_Struct; struct NewSpawn_Struct; struct PlayerPositionUpdateServer_Struct; +namespace EQEmu +{ + struct ItemBase; +} + class Mob : public Entity { public: enum CLIENT_CONN_STATUS { CLIENT_CONNECTING, CLIENT_CONNECTED, CLIENT_LINKDEAD, @@ -102,7 +114,7 @@ public: uint32 in_drakkin_heritage, uint32 in_drakkin_tattoo, uint32 in_drakkin_details, - uint32 in_armor_tint[_MaterialCount], + EQEmu::TintProfile in_armor_tint, uint8 in_aa_title, uint8 in_see_invis, // see through invis uint8 in_see_invis_undead, // see through invis vs. undead @@ -112,7 +124,12 @@ public: int32 in_mana_regen, uint8 in_qglobal, uint8 in_maxlevel, - uint32 in_scalerate + uint32 in_scalerate, + uint8 in_armtexture, + uint8 in_bracertexture, + uint8 in_handtexture, + uint8 in_legtexture, + uint8 in_feettexture ); virtual ~Mob(); @@ -137,28 +154,44 @@ public: virtual void ThrowingAttack(Mob* other) { } uint16 GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg); // 13 = Primary (default), 14 = secondary - virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, - bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) = 0; + virtual bool Attack(Mob* other, int Hand = EQEmu::legacy::SlotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, + bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr, int special = 0) = 0; int MonkSpecialAttack(Mob* other, uint8 skill_used); virtual void TryBackstab(Mob *other,int ReuseTime = 10); - void TriggerDefensiveProcs(const ItemInst* weapon, Mob *on, uint16 hand = MainPrimary, int damage = 0); - virtual bool AvoidDamage(Mob* attacker, int32 &damage, bool CanRiposte = true); - virtual bool CheckHitChance(Mob* attacker, SkillUseTypes skillinuse, int Hand, int16 chance_mod = 0); + bool AvoidDamage(Mob* attacker, int32 &damage, int hand); + virtual bool CheckHitChance(Mob* attacker, EQEmu::skills::SkillType skillinuse, int Hand, int16 chance_mod = 0); virtual void TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts = nullptr); void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage); - virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse); - uint32 TryHeadShot(Mob* defender, SkillUseTypes skillInUse); - uint32 TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 ReuseTime); + virtual bool TryFinishingBlow(Mob *defender, EQEmu::skills::SkillType skillinuse); + uint32 TryHeadShot(Mob* defender, EQEmu::skills::SkillType skillInUse); + uint32 TryAssassinate(Mob* defender, EQEmu::skills::SkillType skillInUse, uint16 ReuseTime); virtual void DoRiposte(Mob* defender); - void ApplyMeleeDamageBonus(uint16 skill, int32 &damage); + void ApplyMeleeDamageBonus(uint16 skill, int32 &damage,ExtraAttackOptions *opts = nullptr); virtual void MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts = nullptr); virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); bool CombatRange(Mob* other); virtual inline bool IsBerserk() { return false; } // only clients void RogueEvade(Mob *other); - void CommonOutgoingHitSuccess(Mob* defender, int32 &damage, SkillUseTypes skillInUse); + void CommonOutgoingHitSuccess(Mob* defender, int32 &damage, EQEmu::skills::SkillType skillInUse, ExtraAttackOptions *opts = nullptr); + void BreakInvisibleSpells(); + virtual void CancelSneakHide(); void CommonBreakInvisible(); + void CommonBreakInvisibleFromCombat(); bool HasDied(); + virtual bool CheckDualWield(); + void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, int special = 0); + void DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, int special = 0); + virtual bool CheckDoubleAttack(); + // inline process for places where we need to do them outside of the AI_Process + void ProcessAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, int special = 0) + { + if (target) { + DoMainHandAttackRounds(target, opts, special); + if (CanThisClassDualWield()) + DoOffHandAttackRounds(target, opts, special); + } + return; + } //Appearance void SendLevelAppearance(); @@ -166,14 +199,15 @@ public: void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, Client *specific_target=nullptr); void SendTargetable(bool on, Client *specific_target = nullptr); - virtual void SendWearChange(uint8 material_slot); + virtual void SendArmorAppearance(Client *one_client = nullptr); + virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr); virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, uint32 unknown06 = 0, uint32 unknown18 = 0); virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint); virtual void WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 hero_forge_model = 0); void DoAnim(const int animnum, int type=0, bool ackreq = true, eqFilterType filter = FilterNone); void ProjectileAnimation(Mob* to, int item_id, bool IsArrow = false, float speed = 0, - float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, SkillUseTypes skillInUse = SkillArchery); + float angle = 0, float tilt = 0, float arc = 0, const char *IDFile = nullptr, EQEmu::skills::SkillType skillInUse = EQEmu::skills::SkillArchery); void ChangeSize(float in_size, bool bNoRestriction = false); inline uint8 SeeInvisible() const { return see_invis; } inline bool SeeInvisibleUndead() const { return see_invis_undead; } @@ -181,11 +215,11 @@ public: inline bool SeeImprovedHide() const { return see_improved_hide; } bool IsInvisible(Mob* other = 0) const; void SetInvisible(uint8 state); - bool AttackAnimation(SkillUseTypes &skillinuse, int Hand, const ItemInst* weapon); + bool AttackAnimation(EQEmu::skills::SkillType &skillinuse, int Hand, const ItemInst* weapon); //Song bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1); - bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, uint16 slot); + bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, EQEmu::CastingSlot slot); void BardPulse(uint16 spell_id, Mob *caster); //Spell @@ -194,7 +228,7 @@ public: bool IsBeneficialAllowed(Mob *target); virtual int GetCasterLevel(uint16 spell_id); void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0, - uint8 WornType = 0, uint32 ticsremaining = 0, int buffslot = -1, + uint8 WornType = 0, int32 ticsremaining = 0, int buffslot = -1, int instrument_mod = 10, bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0); void NegateSpellsBonuses(uint16 spell_id); virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false); @@ -205,34 +239,40 @@ public: virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration); virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); 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 resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false, + int level_override = -1); int ResistPhysical(int level_diff, uint8 caster_level); + int ResistElementalWeaponDmg(const ItemInst *item); + int CheckBaneDamage(const ItemInst *item); uint16 GetSpecializeSkillValue(uint16 spell_id) const; void SendSpellBarDisable(); void SendSpellBarEnable(uint16 spellid); void ZeroCastingVars(); virtual void SpellProcess(); - virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, + virtual bool CastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, - uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, uint32 type = 0, int16 *resist_adjust = nullptr); - virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, + uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 *resist_adjust = nullptr, + uint32 aa_id = 0); + virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, - uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, uint32 type = 0, int16 resist_adjust = 0); - void CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, uint16 mana_used, + uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, int16 resist_adjust = 0, + uint32 aa_id = 0); + void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQEmu::CastingSlot slot, uint16 mana_used, uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0); - bool SpellFinished(uint16 spell_id, Mob *target, uint16 slot = 10, uint16 mana_used = 0, - uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false); + bool SpellFinished(uint16 spell_id, Mob *target, EQEmu::CastingSlot slot = EQEmu::CastingSlot::Item, uint16 mana_used = 0, + uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1); virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect = false, - bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false); - virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100); + bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1); + virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1); virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, - CastAction_type &CastAction); + CastAction_type &CastAction, EQEmu::CastingSlot slot, bool isproc = false); virtual bool CheckFizzle(uint16 spell_id); virtual bool CheckSpellLevelRestriction(uint16 spell_id); virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster); virtual float GetAOERange(uint16 spell_id); void InterruptSpell(uint16 spellid = SPELL_UNKNOWN); void InterruptSpell(uint16, uint16, uint16 spellid = SPELL_UNKNOWN); + void StopCasting(); inline bool IsCasting() const { return((casting_spell_id != 0)); } uint16 CastingSpellID() const { return casting_spell_id; } bool DoCastingChecks(); @@ -247,7 +287,7 @@ public: //Buff void BuffProcess(); - virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0); + virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr); void BuffFadeBySpellID(uint16 spell_id); void BuffFadeByEffect(int effectid, int skipslot = -1); void BuffFadeAll(); @@ -268,6 +308,8 @@ public: virtual int GetMaxSongSlots() const { return 0; } virtual int GetMaxDiscSlots() const { return 0; } virtual int GetMaxTotalSlots() const { return 0; } + virtual uint32 GetFirstBuffSlot(bool disc, bool song); + virtual uint32 GetLastBuffSlot(bool disc, bool song); virtual void InitializeBuffSlots() { buffs = nullptr; current_buff_count = 0; } virtual void UninitializeBuffSlots() { } EQApplicationPacket *MakeBuffsPacket(bool for_target = true); @@ -311,7 +353,9 @@ public: inline void SetShieldEquiped(bool val) { has_shieldequiped = val; } bool HasTwoHandBluntEquiped() const { return has_twohandbluntequiped; } inline void SetTwoHandBluntEquiped(bool val) { has_twohandbluntequiped = val; } - virtual uint16 GetSkill(SkillUseTypes skill_num) const { return 0; } + bool HasTwoHanderEquipped() { return has_twohanderequipped; } + void SetTwoHanderEquipped(bool val) { has_twohanderequipped = val; } + virtual uint16 GetSkill(EQEmu::skills::SkillType skill_num) const { return 0; } virtual uint32 GetEquipment(uint8 material_slot) const { return(0); } virtual int32 GetEquipmentMaterial(uint8 material_slot) const; virtual int32 GetHerosForgeModel(uint8 material_slot) const; @@ -319,9 +363,9 @@ public: virtual uint32 IsEliteMaterialItem(uint8 material_slot) const; bool CanClassEquipItem(uint32 item_id); bool AffectedBySpellExcludingSlot(int slot, int effect); - virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) = 0; - virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, - bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false) = 0; + virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill) = 0; + virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, + bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0) = 0; inline virtual void SetHP(int32 hp) { if (hp >= max_hp) cur_hp = max_hp; else cur_hp = hp;} bool ChangeHP(Mob* other, int32 amount, uint16 spell_id = 0, int8 buffslot = -1, bool iBuffTic = false); inline void SetOOCRegen(int32 newoocregen) {oocregen = newoocregen;} @@ -331,6 +375,7 @@ public: virtual inline uint16 GetBaseRace() const { return base_race; } virtual inline uint8 GetBaseGender() const { return base_gender; } virtual inline uint16 GetDeity() const { return deity; } + virtual EQEmu::deity::DeityTypeBit GetDeityBit() { return EQEmu::deity::ConvertDeityTypeToDeityTypeBit((EQEmu::deity::DeityType)deity); } inline uint16 GetRace() const { return race; } inline uint8 GetGender() const { return gender; } inline uint8 GetTexture() const { return texture; } @@ -345,7 +390,7 @@ public: inline uint8 GetDrakkinHeritage() const { return drakkin_heritage; } inline uint8 GetDrakkinTattoo() const { return drakkin_tattoo; } inline uint8 GetDrakkinDetails() const { return drakkin_details; } - inline uint32 GetArmorTint(uint8 i) const { return armor_tint[(i < _MaterialCount) ? i : 0]; } + inline uint32 GetArmorTint(uint8 i) const { return armor_tint.Slot[(i < EQEmu::textures::TextureCount) ? i : 0].Color; } inline uint8 GetClass() const { return class_; } inline uint8 GetLevel() const { return level; } inline uint8 GetOrigLevel() const { return orig_level; } @@ -358,6 +403,7 @@ public: inline Mob* GetTarget() const { return target; } virtual void SetTarget(Mob* mob); virtual inline float GetHPRatio() const { return max_hp == 0 ? 0 : ((float)cur_hp/max_hp*100); } + virtual inline int GetIntHPRatio() const { return max_hp == 0 ? 0 : static_cast(cur_hp * 100 / max_hp); } inline virtual int32 GetAC() const { return AC + itembonuses.AC + spellbonuses.AC; } inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK; } inline virtual int32 GetATKBonus() const { return itembonuses.ATK + spellbonuses.ATK; } @@ -396,6 +442,8 @@ public: virtual int32 CalcMaxHP(); inline int32 GetMaxMana() const { return max_mana; } inline int32 GetMana() const { return cur_mana; } + virtual int32 GetEndurance() const { return 0; } + virtual void SetEndurance(int32 newEnd) { return; } int32 GetItemHPBonuses(); int32 GetSpellHPBonuses(); virtual const int32& SetMana(int32 amount); @@ -403,6 +451,7 @@ public: ((static_cast(cur_mana) / max_mana) * 100); } virtual int32 CalcMaxMana(); uint32 GetNPCTypeID() const { return npctype_id; } + void SetNPCTypeID(uint32 npctypeid) { npctype_id = npctypeid; } inline const glm::vec4& GetPosition() const { return m_Position; } inline const float GetX() const { return m_Position.x; } inline const float GetY() const { return m_Position.y; } @@ -434,10 +483,13 @@ public: inline bool IsMoving() const { return moving; } virtual void SetMoving(bool move) { moving = move; m_Delta = glm::vec4(); } virtual void GoToBind(uint8 bindnum = 0) { } - virtual void Gate(); - float GetWalkspeed() const { return(_GetMovementSpeed(-47)); } - float GetRunspeed() const { return(_GetMovementSpeed(0)); } - float GetBaseRunspeed() const { return runspeed; } + virtual void Gate(uint8 bindnum = 0); + int GetWalkspeed() const { return(_GetWalkSpeed()); } + int GetRunspeed() const { return(_GetRunSpeed()); } + void SetCurrentSpeed(int in); + int GetBaseRunspeed() const { return base_runspeed; } + int GetBaseWalkspeed() const { return base_walkspeed; } + int GetBaseFearSpeed() const { return base_fearspeed; } float GetMovespeed() const { return IsRunning() ? GetRunspeed() : GetWalkspeed(); } bool IsRunning() const { return m_is_running; } void SetRunning(bool val) { m_is_running = val; } @@ -448,6 +500,8 @@ public: void MakeSpawnUpdateNoDelta(PlayerPositionUpdateServer_Struct* spu); void MakeSpawnUpdate(PlayerPositionUpdateServer_Struct* spu); void SendPosition(); + void SetSpawned() { spawned = true; }; + bool Spawned() { return spawned; }; 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; }; @@ -457,7 +511,7 @@ public: inline uint32 GetLevelCon(uint8 iOtherLevel) const { return this ? GetLevelCon(GetLevel(), iOtherLevel) : CON_GREEN; } virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, - bool bFrenzy = false, bool iBuffTic = false); + bool bFrenzy = false, bool iBuffTic = false, uint16 spell_id = SPELL_UNKNOWN); bool RemoveFromHateList(Mob* mob); void SetHateAmountOnEnt(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.SetHateAmountOnEnt(other,hate,damage);} void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHateAmountOnEnt(other, (in_hate > 1 ? in_hate / 2 : 1)); } @@ -469,6 +523,10 @@ public: Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();} Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();} bool IsEngaged() { return(!hate_list.IsHateListEmpty()); } + bool HasPrimaryAggro() { return PrimaryAggro; } + bool HasAssistAggro() { return AssistAggro; } + void SetPrimaryAggro(bool value) { PrimaryAggro = value; if (value) AssistAggro = false; } + void SetAssistAggro(bool value) { AssistAggro = value; if (PrimaryAggro) AssistAggro = false; } bool HateSummon(); void FaceTarget(Mob* MobToFace = 0); void SetHeading(float iHeading) { if(m_Position.w != iHeading) { pLastChange = Timer::GetCurrentTime(); @@ -487,7 +545,6 @@ public: inline bool CheckLastLosState() const { return last_los_check; } //Quest - void QuestReward(Client *c = nullptr, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0); void CameraEffect(uint32 duration, uint32 intensity, Client *c = nullptr, bool global = false); inline bool GetQglobal() const { return qglobal; } @@ -498,14 +555,15 @@ public: static void CreateSpawnPacket(EQApplicationPacket* app, NewSpawn_Struct* ns); virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); void CreateHPPacket(EQApplicationPacket* app); - void SendHPUpdate(); + void SendHPUpdate(bool skip_self = false); + virtual void ResetHPUpdateTimer() {}; // does nothing //Util static uint32 RandomTimer(int min, int max); static uint8 GetDefaultGender(uint16 in_race, uint8 in_gender = 0xFF); static bool IsPlayerRace(uint16 in_race); uint16 GetSkillByItemType(int ItemType); - uint8 GetItemTypeBySkill(SkillUseTypes skill); + uint8 GetItemTypeBySkill(EQEmu::skills::SkillType skill); virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr); virtual void MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, const char *petname = nullptr, float in_size = 0.0f); bool IsWarriorClass() const; @@ -519,6 +577,7 @@ public: bool lookForAftArc = true); //Procs + void TriggerDefensiveProcs(Mob *on, uint16 hand = EQEmu::legacy::SlotPrimary, bool FromSkillProc = false, int damage = 0); bool AddRangedProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); bool RemoveRangedProc(uint16 spell_id, bool bAll = false); bool HasRangedProcs() const; @@ -527,7 +586,7 @@ public: bool HasDefensiveProcs() const; bool HasSkillProcs() const; bool HasSkillProcSuccess() const; - bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); + bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN, int level_override = -1); bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false); bool HasProcs() const; bool IsCombatProc(uint16 spell_id); @@ -597,7 +656,7 @@ public: int32 GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining); int32 GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill = false, uint16 skill=0); int32 GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id); - int16 GetSkillDmgTaken(const SkillUseTypes skill_used); + int16 GetSkillDmgTaken(const EQEmu::skills::SkillType skill_used, ExtraAttackOptions *opts = nullptr); void DoKnockback(Mob *caster, uint32 pushback, uint32 pushup); int16 CalcResistChanceBonus(); int16 CalcFearResistChance(); @@ -617,7 +676,7 @@ public: bool TryReflectSpell(uint32 spell_id); bool CanBlockSpell() const { return(spellbonuses.BlockNextSpell); } bool DoHPToManaCovert(uint16 mana_cost = 0); - int32 ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard = false); + int32 ApplySpellEffectiveness(int16 spell_id, int32 value, bool IsBard = false, uint16 caster_id=0); int8 GetDecayEffectValue(uint16 spell_id, uint16 spelleffect); int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg); void MeleeLifeTap(int32 damage); @@ -630,8 +689,8 @@ public: inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; }; int32 GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot = 0); - void ModSkillDmgTaken(SkillUseTypes skill_num, int value); - int16 GetModSkillDmgTaken(const SkillUseTypes skill_num); + void ModSkillDmgTaken(EQEmu::skills::SkillType skill_num, int value); + int16 GetModSkillDmgTaken(const EQEmu::skills::SkillType skill_num); void ModVulnerability(uint8 resist, int16 value); int16 GetModVulnerability(const uint8 resist); @@ -655,17 +714,17 @@ public: bool IsDestructibleObject() { return destructibleobject; } void SetDestructibleObject(bool in) { destructibleobject = in; } - inline uint8 GetInnateLightType() { return m_Light.Type.Innate; } - inline uint8 GetEquipmentLightType() { return m_Light.Type.Equipment; } - inline uint8 GetSpellLightType() { return m_Light.Type.Spell; } + inline uint8 GetInnateLightType() { return m_Light.Type[EQEmu::lightsource::LightInnate]; } + inline uint8 GetEquipmentLightType() { return m_Light.Type[EQEmu::lightsource::LightEquipment]; } + inline uint8 GetSpellLightType() { return m_Light.Type[EQEmu::lightsource::LightSpell]; } - virtual void UpdateEquipmentLight() { m_Light.Type.Equipment = 0; m_Light.Level.Equipment = 0; } - inline void SetSpellLightType(uint8 lightType) { m_Light.Type.Spell = (lightType & 0x0F); m_Light.Level.Spell = m_Light.TypeToLevel(m_Light.Type.Spell); } + virtual void UpdateEquipmentLight() { m_Light.Type[EQEmu::lightsource::LightEquipment] = 0; m_Light.Level[EQEmu::lightsource::LightEquipment] = 0; } + inline void SetSpellLightType(uint8 light_type) { m_Light.Type[EQEmu::lightsource::LightSpell] = (light_type & 0x0F); m_Light.Level[EQEmu::lightsource::LightSpell] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightSpell]); } - inline uint8 GetActiveLightType() { return m_Light.Type.Active; } + inline uint8 GetActiveLightType() { return m_Light.Type[EQEmu::lightsource::LightActive]; } bool UpdateActiveLight(); // returns true if change, false if no change - LightProfile_Struct* GetLightProfile() { return &m_Light; } + EQEmu::LightSourceProfile* GetLightProfile() { return &m_Light; } Mob* GetPet(); void SetPet(Mob* newpet); @@ -713,19 +772,21 @@ public: inline bool GetInvul(void) { return invulnerable; } inline void SetExtraHaste(int Haste) { ExtraHaste = Haste; } virtual int GetHaste(); + int32 GetMeleeMitigation(); - uint8 GetWeaponDamageBonus(const Item_Struct* Weapon); - uint16 GetDamageTable(SkillUseTypes skillinuse); - virtual int GetMonkHandToHandDamage(void); + uint8 GetWeaponDamageBonus(const EQEmu::ItemBase* weapon, bool offhand = false); + uint16 GetDamageTable(EQEmu::skills::SkillType skillinuse); + virtual int GetHandToHandDamage(void); bool CanThisClassDoubleAttack(void) const; + bool CanThisClassTripleAttack() const; bool CanThisClassDualWield(void) const; bool CanThisClassRiposte(void) const; bool CanThisClassDodge(void) const; bool CanThisClassParry(void) const; bool CanThisClassBlock(void) const; - int GetMonkHandToHandDelay(void); + int GetHandToHandDelay(void); uint32 GetClassLevelFactor(); void Mesmerize(); inline bool IsMezzed() const { return mezzed; } @@ -737,11 +798,11 @@ public: int32 AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTic, Mob* attacker); int32 ReduceAllDamage(int32 damage); - virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false, bool CanAvoid=true); - virtual void DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const Item_Struct* AmmoItem=nullptr, uint16 weapon_damage=0, int16 chance_mod=0,int16 focus=0, int ReuseTime=0, uint32 range_id=0, int AmmoSlot=0, float speed = 4.0f); - virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false, int ReuseTime=0); - virtual void DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const ItemInst* Ammo=nullptr, uint16 weapon_damage=0, int16 chance_mod=0, int16 focus=0, int ReuseTime=0, uint32 range_id=0, uint32 ammo_id=0, const Item_Struct *AmmoItem=nullptr, int AmmoSlot=0, float speed= 4.0f); - bool TryProjectileAttack(Mob* other, const Item_Struct *item, SkillUseTypes skillInUse, uint16 weapon_dmg, const ItemInst* RangeWeapon, const ItemInst* Ammo, int AmmoSlot, float speed); + virtual void DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool CheckHitChance = false, bool CanAvoid = true); + virtual void DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon = nullptr, const EQEmu::ItemBase* AmmoItem = nullptr, uint16 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, int AmmoSlot = 0, float speed = 4.0f); + virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod = 0, int16 focus = 0, bool CanRiposte = false, int ReuseTime = 0); + virtual void DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon = nullptr, const ItemInst* Ammo = nullptr, uint16 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, uint32 ammo_id = 0, const EQEmu::ItemBase *AmmoItem = nullptr, int AmmoSlot = 0, float speed = 4.0f); + bool TryProjectileAttack(Mob* other, const EQEmu::ItemBase *item, EQEmu::skills::SkillType skillInUse, uint16 weapon_dmg, const ItemInst* RangeWeapon, const ItemInst* Ammo, int AmmoSlot, float speed); void ProjectileAttack(); inline bool HasProjectileAttack() const { return ActiveProjectileATK; } inline void SetProjectileAttack(bool value) { ActiveProjectileATK = value; } @@ -756,7 +817,7 @@ public: void StartEnrage(); void ProcessEnrage(); bool IsEnraged(); - void Taunt(NPC* who, bool always_succeed, float chance_bonus = 0); + void Taunt(NPC* who, bool always_succeed, float chance_bonus=0, bool FromSpell=false, int32 bonus_hate=0); virtual void AI_Init(); virtual void AI_Start(uint32 iMoveDelay = 0); @@ -796,9 +857,8 @@ public: //old fear function //void SetFeared(Mob *caster, uint32 duration, bool flee = false); - float GetFearSpeed(); - bool IsFeared() { return curfp; } // This returns true if the mob is feared or fleeing due to low HP - //old fear: inline void StartFleeing() { SetFeared(GetHateTop(), FLEE_RUN_DURATION, true); } + int GetFearSpeed() { return _GetFearSpeed(); } + bool IsFeared() { return (spellbonuses.IsFeared || flee_mode); } // This returns true if the mob is feared or fleeing due to low HP inline void StartFleeing() { flee_mode = true; CalculateNewFearpoint(); } void ProcessFlee(); void CheckFlee(); @@ -806,8 +866,8 @@ public: 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, float speed, bool checkZ = false); - virtual bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true); + 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); @@ -845,15 +905,14 @@ public: Mob* GetShieldTarget() const { return shield_target; } void SetShieldTarget(Mob* mob) { shield_target = mob; } bool HasActiveSong() const { return(bardsong != 0); } - bool Charmed() const { return charmed; } + bool Charmed() const { return typeofpet == petCharmed; } static uint32 GetLevelHP(uint8 tlevel); uint32 GetZoneID() const; //for perl - virtual int32 CheckAggroAmount(uint16 spell_id, bool isproc = false); - virtual int32 CheckHealAggroAmount(uint16 spell_id, uint32 heal_possible = 0); - virtual uint32 GetAA(uint32 aa_id) const { return(0); } + virtual int32 CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc = false); + virtual int32 CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possible = 0); uint32 GetInstrumentMod(uint16 spell_id) const; - int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, Mob *caster = nullptr, int ticsremaining = 0); + int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0,uint16 casterid=0); int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0); virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1); uint32 GetCastedSpellInvSlot() const { return casting_spell_inventory_slot; } @@ -861,7 +920,7 @@ public: // HP Event inline int GetNextHPEvent() const { return nexthpevent; } void SetNextHPEvent( int hpevent ); - void SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skillInUse, float velocity= 4.0); + void SendItemAnimation(Mob *to, const EQEmu::ItemBase *item, EQEmu::skills::SkillType skillInUse, float velocity = 4.0); inline int& GetNextIncHPEvent() { return nextinchpevent; } void SetNextIncHPEvent( int inchpevent ); @@ -878,6 +937,8 @@ public: Timer *GetSpecialAbilityTimer(int ability); void ClearSpecialAbilities(); void ProcessSpecialAbilities(const std::string &str); + bool IsMoved() { return moved; } + void SetMoved(bool moveflag) { moved = moveflag; } Shielders_Struct shielder[MAX_SHIELDERS]; Trade* trade; @@ -889,8 +950,8 @@ public: virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther) { return FACTION_INDIFFERENT; } inline bool IsTrackable() const { return(trackable); } - Timer* GetAIThinkTimer() { return AIthink_timer.get(); } - Timer* GetAIMovementTimer() { return AImovement_timer.get(); } + Timer* GetAIThinkTimer() { return AI_think_timer.get(); } + Timer* GetAIMovementTimer() { return AI_movement_timer.get(); } Timer GetAttackTimer() { return attack_timer; } Timer GetAttackDWTimer() { return attack_dw_timer; } inline bool IsFindable() { return findable; } @@ -900,6 +961,7 @@ public: inline virtual bool IsBlockedBuff(int16 SpellID) { return false; } inline virtual bool IsBlockedPetBuff(int16 SpellID) { return false; } + std::string GetGlobal(const char *varname); void SetGlobal(const char *varname, const char *newvalue, int options, const char *duration, Mob *other = nullptr); void TarGlobal(const char *varname, const char *value, const char *duration, int npcid, int charid, int zoneid); void DelGlobal(const char *varname); @@ -908,8 +970,8 @@ public: inline uint16 GetEmoteID() { return emoteid; } bool HasSpellEffect(int effectid); - int mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster); - float mod_hit_chance(float chancetohit, SkillUseTypes skillinuse, Mob* attacker); + int mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster, uint16 caster_id); + float mod_hit_chance(float chancetohit, EQEmu::skills::SkillType skillinuse, Mob* attacker); float mod_riposte_chance(float ripostchance, Mob* attacker); float mod_block_chance(float blockchance, Mob* attacker); float mod_parry_chance(float parrychance, Mob* attacker); @@ -920,7 +982,7 @@ public: int32 mod_kick_damage(int32 dmg); int32 mod_bash_damage(int32 dmg); int32 mod_frenzy_damage(int32 dmg); - int32 mod_monk_special_damage(int32 ndamage, SkillUseTypes skill_type); + int32 mod_monk_special_damage(int32 ndamage, EQEmu::skills::SkillType skill_type); int32 mod_backstab_damage(int32 ndamage); int mod_archery_bonus_chance(int bonuschance, const ItemInst* RangeWeapon); uint32 mod_archery_bonus_damage(uint32 MaxDmg, const ItemInst* RangeWeapon); @@ -939,28 +1001,62 @@ public: uint32 Tune_GetMeanDamage(Mob* GM, Mob *attacker, int32 damage, int32 minhit, ExtraAttackOptions *opts = nullptr, int Msg = 0,int ac_override=0, int atk_override=0, int add_ac=0, int add_atk = 0); void Tune_FindATKByPctMitigation(Mob* defender, Mob *attacker, float pct_mitigation, int interval = 50, int max_loop = 100, int ac_override=0,int Msg =0); void Tune_FindACByPctMitigation(Mob* defender, Mob *attacker, float pct_mitigation, int interval = 50, int max_loop = 100, int atk_override=0,int Msg =0); - float Tune_CheckHitChance(Mob* defender, Mob* attacker, SkillUseTypes skillinuse, int Hand, int16 chance_mod, int Msg = 1,int acc_override=0, int avoid_override=0, int add_acc=0, int add_avoid = 0); + float Tune_CheckHitChance(Mob* defender, Mob* attacker, EQEmu::skills::SkillType skillinuse, int Hand, int16 chance_mod, int Msg = 1, int acc_override = 0, int avoid_override = 0, int add_acc = 0, int add_avoid = 0); void Tune_FindAccuaryByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int avoid_override, int Msg = 0); void Tune_FindAvoidanceByHitChance(Mob* defender, Mob *attacker, float hit_chance, int interval, int max_loop, int acc_override, int Msg = 0); + //aa new + uint32 GetAA(uint32 rank_id, uint32 *charges = nullptr) const; + uint32 GetAAByAAID(uint32 aa_id, uint32 *charges = nullptr) const; + bool SetAA(uint32 rank_id, uint32 new_value, uint32 charges = 0); + void ClearAAs() { aa_ranks.clear(); } + bool CanUseAlternateAdvancementRank(AA::Rank *rank); + bool CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price, bool check_grant); + int GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in); + void ExpendAlternateAdvancementCharge(uint32 aa_id); + void CalcAABonuses(StatBonuses* newbon); + void ApplyAABonuses(const AA::Rank &rank, StatBonuses* newbon); + bool CheckAATimer(int timer); + + int NPCAssistCap() { return npc_assist_cap; } + void AddAssistCap() { ++npc_assist_cap; } + void DelAssistCap() { --npc_assist_cap; } + void ResetAssistCap() { npc_assist_cap = 0; } + + // Bots HealRotation methods +#ifdef BOTS + bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); } + bool JoinHealRotationTargetPool(std::shared_ptr* heal_rotation); + bool LeaveHealRotationTargetPool(); + + uint32 HealRotationHealCount(); + uint32 HealRotationExtendedHealCount(); + float HealRotationHealFrequency(); + float HealRotationExtendedHealFrequency(); + + const std::shared_ptr* TargetOfHealRotation() const { return &m_target_of_heal_rotation; } +#endif + protected: - void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic); + void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const EQEmu::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, int special = 0); static uint16 GetProcID(uint16 spell_id, uint8 effect_index); float _GetMovementSpeed(int mod) const; - virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool checkZ); + int _GetWalkSpeed() const; + int _GetRunSpeed() const; + int _GetFearSpeed() const; + virtual bool MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ); virtual bool AI_EngagedCastCheck() { return(false); } virtual bool AI_PursueCastCheck() { return(false); } virtual bool AI_IdleCastCheck() { return(false); } - bool IsFullHP; bool moved; std::vector RampageArray; std::map m_EntityVariables; - int16 SkillDmgTaken_Mod[HIGHEST_SKILL+2]; + int16 SkillDmgTaken_Mod[EQEmu::skills::HIGHEST_SKILL + 2]; int16 Vulnerability_Mod[HIGHEST_RESIST+2]; bool m_AllowBeneficial; bool m_DisableMelee; @@ -971,6 +1067,12 @@ protected: uint16 entity_id_being_looted; //the id of the entity being looted, 0 if not looting. uint8 texture; uint8 helmtexture; + uint8 armtexture; + uint8 bracertexture; + uint8 handtexture; + uint8 legtexture; + uint8 feettexture; + bool multitexture; int AC; int32 ATK; @@ -1015,6 +1117,13 @@ protected: uint32 follow_dist; bool no_target_hotkey; + uint32 m_PlayerState; + uint32 GetPlayerState() { return m_PlayerState; } + void AddPlayerState(uint32 new_state) { m_PlayerState |= new_state; } + void RemovePlayerState(uint32 old_state) { m_PlayerState &= ~old_state; } + void SendAddPlayerState(PlayerState new_state); + void SendRemovePlayerState(PlayerState old_state); + uint8 gender; uint16 race; uint8 base_gender; @@ -1031,31 +1140,39 @@ protected: float base_size; float size; float runspeed; + float walkspeed; + float fearspeed; + int base_runspeed; + int base_walkspeed; + int base_fearspeed; + int current_speed; + uint32 pLastChange; bool held; bool nocast; bool focused; + bool spawned; void CalcSpellBonuses(StatBonuses* newbon); virtual void CalcBonuses(); - void TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success = false, uint16 hand = 0, bool IsDefensive = false); // hand = MainCharm? + void TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success = false, uint16 hand = 0, bool IsDefensive = false); // hand = SlotCharm? bool PassLimitToSkill(uint16 spell_id, uint16 skill); bool PassLimitClass(uint32 Classes_, uint16 Class_); - void TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand = MainPrimary); - void TryWeaponProc(const ItemInst* inst, const Item_Struct* weapon, Mob *on, uint16 hand = MainPrimary); - void TrySpellProc(const ItemInst* inst, const Item_Struct* weapon, Mob *on, uint16 hand = MainPrimary); - void TryWeaponProc(const ItemInst* weapon, Mob *on, uint16 hand = MainPrimary); - void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on); - virtual float GetProcChances(float ProcBonus, uint16 hand = MainPrimary); - virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = MainPrimary, Mob *on = nullptr); + void TryDefensiveProc(Mob *on, uint16 hand = EQEmu::legacy::SlotPrimary); + void TryWeaponProc(const ItemInst* inst, const EQEmu::ItemBase* weapon, Mob *on, uint16 hand = EQEmu::legacy::SlotPrimary); + void TrySpellProc(const ItemInst* inst, const EQEmu::ItemBase* weapon, Mob *on, uint16 hand = EQEmu::legacy::SlotPrimary); + void TryWeaponProc(const ItemInst* weapon, Mob *on, uint16 hand = EQEmu::legacy::SlotPrimary); + void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on, int level_override = -1); + virtual float GetProcChances(float ProcBonus, uint16 hand = EQEmu::legacy::SlotPrimary); + virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = EQEmu::legacy::SlotPrimary, Mob *on = nullptr); virtual float GetSpecialProcChances(uint16 hand); virtual float GetAssassinateProcChances(uint16 ReuseTime); virtual float GetSkillProcChances(uint16 ReuseTime, uint16 hand = 0); // hand = MainCharm? uint16 GetWeaponSpeedbyHand(uint16 hand); - int GetWeaponDamage(Mob *against, const Item_Struct *weapon_item); + int GetWeaponDamage(Mob *against, const EQEmu::ItemBase *weapon_item); int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr); int GetKickDamage(); int GetBashDamage(); - virtual void ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg); + virtual void ApplySpecialAttackMod(EQEmu::skills::SkillType skill, int32 &dmg, int32 &mindmg); 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); @@ -1063,6 +1180,8 @@ protected: void PrintRoute(); virtual float GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate = 0); + int16 GetSympatheticSpellProcRate(uint16 spell_id); + uint16 GetSympatheticSpellProcID(uint16 spell_id); enum {MAX_PROCS = 4}; tProc PermaProcs[MAX_PROCS]; @@ -1077,7 +1196,7 @@ protected: glm::vec4 m_Delta; - LightProfile_Struct m_Light; + EQEmu::LightSourceProfile m_Light; float fixedZ; EmuAppearance _appearance; @@ -1100,16 +1219,17 @@ protected: int attacked_count; bool delaytimer; uint16 casting_spell_targetid; - uint16 casting_spell_slot; + EQEmu::CastingSlot casting_spell_slot; uint16 casting_spell_mana; uint32 casting_spell_inventory_slot; uint32 casting_spell_timer; uint32 casting_spell_timer_duration; uint32 casting_spell_type; int16 casting_spell_resist_adjust; + uint32 casting_spell_aa_id; bool casting_spell_checks; uint16 bardsong; - uint8 bardsong_slot; + EQEmu::CastingSlot bardsong_slot; uint32 bardsong_target_id; bool ActiveProjectileATK; @@ -1134,7 +1254,7 @@ protected: uint32 drakkin_heritage; uint32 drakkin_tattoo; uint32 drakkin_details; - uint32 armor_tint[_MaterialCount]; + EQEmu::TintProfile armor_tint; uint8 aa_title; @@ -1153,6 +1273,7 @@ protected: bool offhand; bool has_shieldequiped; bool has_twohandbluntequiped; + bool has_twohanderequipped; bool has_numhits; bool has_MGB; bool has_ProjectIllusion; @@ -1160,6 +1281,7 @@ protected: bool last_los_check; bool pseudo_rooted; bool endur_upkeep; + bool degenerating_effects; // true if we have a buff that needs to be recalced every tick // Bind wound Timer bindwound_timer; @@ -1178,14 +1300,15 @@ protected: uint32 maxLastFightingDelayMoving; float pAggroRange; float pAssistRange; - std::unique_ptr AIthink_timer; - std::unique_ptr AImovement_timer; - std::unique_ptr AItarget_check_timer; + std::unique_ptr AI_think_timer; + std::unique_ptr AI_movement_timer; + std::unique_ptr AI_target_check_timer; bool movetimercompleted; bool permarooted; - std::unique_ptr AIscanarea_timer; - std::unique_ptr AIwalking_timer; - std::unique_ptr AIfeignremember_timer; + std::unique_ptr AI_scan_area_timer; + std::unique_ptr AI_walking_timer; + std::unique_ptr AI_feign_remember_timer; + std::unique_ptr AI_check_signal_timer; uint32 pLastFightingDelayMoving; HateList hate_list; std::set feign_memory_list; @@ -1216,10 +1339,15 @@ protected: glm::vec4 m_CurrentWayPoint; int cur_wp_pause; + bool PrimaryAggro; + bool AssistAggro; + int npc_assist_cap; + Timer assist_cap_timer; // clear assist cap so more nearby mobs can be called for help + int patrol; glm::vec3 m_FearWalkTarget; - bool curfp; + bool currently_fleeing; // Pathing // @@ -1273,9 +1401,17 @@ protected: bool bEnraged; bool destructibleobject; + std::unordered_map> aa_ranks; + Timer aa_timers[aaTimerMax]; + private: void _StopSong(); //this is not what you think it is Mob* target; + +#ifdef BOTS + std::shared_ptr m_target_of_heal_rotation; +#endif + }; #endif diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index a7752bb3f..754370c8c 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -40,8 +40,10 @@ extern EntityList entity_list; extern Zone *zone; -#ifdef _EQDEBUG - #define MobAI_DEBUG_Spells -1 +#if EQDEBUG >= 12 + #define MobAI_DEBUG_Spells 25 +#elif EQDEBUG >= 9 + #define MobAI_DEBUG_Spells 10 #else #define MobAI_DEBUG_Spells -1 #endif @@ -99,12 +101,8 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { ) { #if MobAI_DEBUG_Spells >= 21 - std::cout << "Mob::AICastSpell: Casting: spellid=" << AIspells[i].spellid - << ", tar=" << tar->GetName() - << ", dist2[" << dist2 << "]<=" << spells[AIspells[i].spellid].range *spells[AIspells[i].spellid].range - << ", mana_cost[" << mana_cost << "]<=" << GetMana() - << ", cancast[" << AIspells[i].time_cancast << "]<=" << Timer::GetCurrentTime() - << ", type=" << AIspells[i].type << std::endl; + Log.Out(Logs::Detail, Logs::AI, "Mob::AICastSpell: Casting: spellid=%u, tar=%s, dist2[%f]<=%f, mana_cost[%i]<=%i, cancast[%u]<=%u, type=%u", + AIspells[i].spellid, tar->GetName(), dist2, (spells[AIspells[i].spellid].range * spells[AIspells[i].spellid].range), mana_cost, GetMana(), AIspells[i].time_cancast, Timer::GetCurrentTime(), AIspells[i].type); #endif switch (AIspells[i].type) { @@ -325,7 +323,8 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { } #if MobAI_DEBUG_Spells >= 21 else { - std::cout << "Mob::AICastSpell: NotCasting: spellid=" << AIspells[i].spellid << ", tar=" << tar->GetName() << ", dist2[" << dist2 << "]<=" << spells[AIspells[i].spellid].range*spells[AIspells[i].spellid].range << ", mana_cost[" << mana_cost << "]<=" << GetMana() << ", cancast[" << AIspells[i].time_cancast << "]<=" << Timer::GetCurrentTime() << std::endl; + Log.Out(Logs::Detail, Logs::AI, "Mob::AICastSpell: NotCasting: spellid=%u, tar=%s, dist2[%f]<=%f, mana_cost[%i]<=%i, cancast[%u]<=%u, type=%u", + AIspells[i].spellid, tar->GetName(), dist2, (spells[AIspells[i].spellid].range * spells[AIspells[i].spellid].range), mana_cost, GetMana(), AIspells[i].time_cancast, Timer::GetCurrentTime(), AIspells[i].type); } #endif } @@ -335,18 +334,16 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) { bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore) { #if MobAI_DEBUG_Spells >= 1 - std::cout << "Mob::AIDoSpellCast: spellid=" << AIspells[i].spellid << ", tar=" << tar->GetName() << ", mana=" << mana_cost << ", Name: " << spells[AIspells[i].spellid].name << std::endl; + Log.Out(Logs::Detail, Logs::AI, "Mob::AIDoSpellCast: spellid = %u, tar = %s, mana = %i, Name: '%s'", AIspells[i].spellid, tar->GetName(), mana_cost, spells[AIspells[i].spellid].name); #endif casting_spell_AIindex = i; //stop moving if were casting a spell and were not a bard... if(!IsBardSong(AIspells[i].spellid)) { - SetRunAnimSpeed(0); - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); } - return CastSpell(AIspells[i].spellid, tar->GetID(), 1, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, 0, &(AIspells[i].resist_adjust)); + return CastSpell(AIspells[i].spellid, tar->GetID(), EQEmu::CastingSlot::Gem2, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, &(AIspells[i].resist_adjust)); } bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint16 iSpellTypes) { @@ -427,12 +424,14 @@ bool EntityList::AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float void Mob::AI_Init() { pAIControlled = false; - AIthink_timer.reset(nullptr); - AIwalking_timer.reset(nullptr); - AImovement_timer.reset(nullptr); - AItarget_check_timer.reset(nullptr); - AIfeignremember_timer.reset(nullptr); - AIscanarea_timer.reset(nullptr); + AI_think_timer.reset(nullptr); + AI_walking_timer.reset(nullptr); + AI_movement_timer.reset(nullptr); + AI_target_check_timer.reset(nullptr); + AI_feign_remember_timer.reset(nullptr); + AI_scan_area_timer.reset(nullptr); + AI_check_signal_timer.reset(nullptr); + minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); @@ -476,16 +475,18 @@ void Mob::AI_Start(uint32 iMoveDelay) { pLastFightingDelayMoving = 0; pAIControlled = true; - AIthink_timer = std::unique_ptr(new Timer(AIthink_duration)); - AIthink_timer->Trigger(); - AIwalking_timer = std::unique_ptr(new Timer(0)); - AImovement_timer = std::unique_ptr(new Timer(AImovement_duration)); - AItarget_check_timer = std::unique_ptr(new Timer(AItarget_check_duration)); - AIfeignremember_timer = std::unique_ptr(new Timer(AIfeignremember_delay)); - AIscanarea_timer = std::unique_ptr(new Timer(AIscanarea_delay)); + AI_think_timer = std::unique_ptr(new Timer(AIthink_duration)); + AI_think_timer->Trigger(); + AI_walking_timer = std::unique_ptr(new Timer(0)); + AI_movement_timer = std::unique_ptr(new Timer(AImovement_duration)); + AI_target_check_timer = std::unique_ptr(new Timer(AItarget_check_duration)); + AI_feign_remember_timer = std::unique_ptr(new Timer(AIfeignremember_delay)); + AI_scan_area_timer = std::unique_ptr(new Timer(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)))); + AI_check_signal_timer = std::unique_ptr(new Timer(AI_check_signal_timer_delay)); + #ifdef REVERSE_AGGRO if(IsNPC() && !CastToNPC()->WillAggroNPCs()) - AIscanarea_timer->Disable(); + AI_scan_area_timer->Disable(); #endif if (GetAggroRange() == 0) @@ -517,7 +518,7 @@ void NPC::AI_Start(uint32 iMoveDelay) { if (!pAIControlled) return; - if (AIspells.size() == 0) { + if (AIspells.empty()) { AIautocastspell_timer = std::unique_ptr(new Timer(1000)); AIautocastspell_timer->Disable(); } else { @@ -542,12 +543,13 @@ void Mob::AI_Stop() { pAIControlled = false; - AIthink_timer.reset(nullptr); - AIwalking_timer.reset(nullptr); - AImovement_timer.reset(nullptr); - AItarget_check_timer.reset(nullptr); - AIscanarea_timer.reset(nullptr); - AIfeignremember_timer.reset(nullptr); + AI_think_timer.reset(nullptr); + AI_walking_timer.reset(nullptr); + AI_movement_timer.reset(nullptr); + AI_target_check_timer.reset(nullptr); + AI_scan_area_timer.reset(nullptr); + AI_feign_remember_timer.reset(nullptr); + AI_check_signal_timer.reset(nullptr); hate_list.WipeHateList(); } @@ -561,7 +563,7 @@ void Client::AI_Stop() { Mob::AI_Stop(); this->Message_StringID(13,PLAYER_REGAIN); - EQApplicationPacket *app = new EQApplicationPacket(OP_Charm, sizeof(Charm_Struct)); + auto app = new EQApplicationPacket(OP_Charm, sizeof(Charm_Struct)); Charm_Struct *ps = (Charm_Struct*)app->pBuffer; ps->owner_id = 0; ps->pet_id = this->GetID(); @@ -673,13 +675,13 @@ void Client::AI_SpellCast() } uint32 spell_to_cast = 0xFFFFFFFF; - uint32 slot_to_use = 10; + EQEmu::CastingSlot slot_to_use = EQEmu::CastingSlot::Item; if(valid_spells.size() == 1) { spell_to_cast = valid_spells[0]; - slot_to_use = slots[0]; + slot_to_use = static_cast(slots[0]); } - else if(valid_spells.size() == 0) + else if(valid_spells.empty()) { return; } @@ -687,7 +689,7 @@ void Client::AI_SpellCast() { uint32 idx = zone->random.Int(0, (valid_spells.size()-1)); spell_to_cast = valid_spells[idx]; - slot_to_use = slots[idx]; + slot_to_use = static_cast(slots[idx]); } if(IsMezSpell(spell_to_cast) || IsFearSpell(spell_to_cast)) @@ -700,9 +702,7 @@ void Client::AI_SpellCast() { if(!IsBardSong(spell_to_cast)) { - SetRunAnimSpeed(0); - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); } CastSpell(spell_to_cast, tar->GetID(), slot_to_use); return; @@ -716,9 +716,7 @@ void Client::AI_SpellCast() { if(!IsBardSong(spell_to_cast)) { - SetRunAnimSpeed(0); - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); } CastSpell(spell_to_cast, tar->GetID(), slot_to_use); return; @@ -733,7 +731,7 @@ void Client::AI_Process() if (!IsAIControlled()) return; - if (!(AIthink_timer->Check() || attack_timer.Check(false))) + if (!(AI_think_timer->Check() || attack_timer.Check(false))) return; if (IsCasting()) @@ -767,23 +765,23 @@ void Client::AI_Process() } if(RuleB(Combat, EnableFearPathing)){ - if(curfp) { + if(currently_fleeing) { if(IsRooted()) { //make sure everybody knows were not moving, for appearance sake if(IsMoving()) { if(GetTarget()) SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); - SetRunAnimSpeed(0); - SendPosition(); - SetMoving(false); - moved=false; + SetCurrentSpeed(0); } //continue on to attack code, ensuring that we execute the engaged code engaged = true; } else { - if(AImovement_timer->Check()) { - animation = GetRunspeed() * 21; + if(AI_movement_timer->Check()) { + int speed = GetFearSpeed(); + animation = speed; + speed *= 2; + SetCurrentSpeed(speed); // Check if we have reached the last fear point if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) && (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { @@ -791,18 +789,18 @@ void Client::AI_Process() CalculateNewFearpoint(); } if(!RuleB(Pathing, Fear) || !zone->pathing) - CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true); + CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, speed, true); else { bool WaypointChanged, NodeReached; glm::vec3 Goal = UpdatePath(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, - GetFearSpeed(), WaypointChanged, NodeReached); + speed, WaypointChanged, NodeReached); if(WaypointChanged) tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetFearSpeed()); + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, speed); } } return; @@ -816,7 +814,7 @@ void Client::AI_Process() SetTarget(hate_list.GetClosestEntOnHateList(this)); else { - if(AItarget_check_timer->Check()) + if(AI_target_check_timer->Check()) { SetTarget(hate_list.GetEntWithMostHateOnList(this)); } @@ -835,146 +833,69 @@ void Client::AI_Process() bool is_combat_range = CombatRange(GetTarget()); - if(is_combat_range) { - if(charm_class_attacks_timer.Check()) { + if (is_combat_range) { + if (charm_class_attacks_timer.Check()) { DoClassAttacks(GetTarget()); } - if (AImovement_timer->Check()) { - SetRunAnimSpeed(0); + if (AI_movement_timer->Check()) { + if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != + m_Position.w) { + SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); + SendPosition(); + } + SetCurrentSpeed(0); } - if(IsMoving()) { - SetMoving(false); - moved=false; - SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); - SendPosition(); - tar_ndx =0; - } - - if(GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) { - if(attack_timer.Check()) { - Attack(GetTarget(), MainPrimary); - if(GetTarget()) { - if(CheckDoubleAttack()) { - Attack(GetTarget(), MainPrimary); - if(GetTarget()) { - bool triple_attack_success = false; - if((((GetClass() == MONK || GetClass() == WARRIOR || GetClass() == RANGER || GetClass() == BERSERKER) - && GetLevel() >= 60) || GetSpecialAbility(SPECATK_TRIPLE)) - && CheckDoubleAttack(true)) - { - Attack(GetTarget(), MainPrimary, true); - triple_attack_success = true; - } - - if(GetTarget()) - { - //Live AA - Flurry, Rapid Strikes ect (Flurry does not require Triple Attack). - int16 flurrychance = aabonuses.FlurryChance + spellbonuses.FlurryChance + itembonuses.FlurryChance; - - if (flurrychance) - { - if(zone->random.Roll(flurrychance)) - { - Message_StringID(MT_NPCFlurry, YOU_FLURRY); - Attack(GetTarget(), MainPrimary, false); - Attack(GetTarget(), MainPrimary, false); - } - } - - int16 ExtraAttackChanceBonus = spellbonuses.ExtraAttackChance + itembonuses.ExtraAttackChance + aabonuses.ExtraAttackChance; - - if (ExtraAttackChanceBonus && GetTarget()) { - ItemInst *wpn = GetInv().GetItem(MainPrimary); - if(wpn){ - if(wpn->GetItem()->ItemType == ItemType2HSlash || - wpn->GetItem()->ItemType == ItemType2HBlunt || - wpn->GetItem()->ItemType == ItemType2HPiercing ) - { - if(zone->random.Roll(ExtraAttackChanceBonus)) - { - Attack(GetTarget(), MainPrimary, false); - } - } - } - } - - if (GetClass() == WARRIOR || GetClass() == BERSERKER) - { - if(!dead && !berserk && this->GetHPRatio() < 30) - { - entity_list.MessageClose_StringID(this, false, 200, 0, BERSERK_START, GetName()); - berserk = true; - } - else if (berserk && this->GetHPRatio() > 30) - { - entity_list.MessageClose_StringID(this, false, 200, 0, BERSERK_END, GetName()); - berserk = false; - } - } - } - } - } - } + if (GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) { + if (attack_timer.Check()) { + // Should charmed clients not be procing? + DoAttackRounds(GetTarget(), EQEmu::legacy::SlotPrimary); } } - if(CanThisClassDualWield() && attack_dw_timer.Check()) - { - if(GetTarget()) - { - float DualWieldProbability = 0.0f; - - int16 Ambidexterity = aabonuses.Ambidexterity + spellbonuses.Ambidexterity + itembonuses.Ambidexterity; - DualWieldProbability = (GetSkill(SkillDualWield) + GetLevel() + Ambidexterity) / 400.0f; // 78.0 max - int16 DWBonus = spellbonuses.DualWieldChance + itembonuses.DualWieldChance; - DualWieldProbability += DualWieldProbability*float(DWBonus)/ 100.0f; - - if(zone->random.Roll(DualWieldProbability)) - { - Attack(GetTarget(), MainSecondary); - if(CheckDoubleAttack()) - { - Attack(GetTarget(), MainSecondary); - } - + if (CanThisClassDualWield() && GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) { + if (attack_dw_timer.Check()) { + if (CheckDualWield()) { + // Should charmed clients not be procing? + DoAttackRounds(GetTarget(), EQEmu::legacy::SlotSecondary); } } } - } - else - { + } else { if(!IsRooted()) { - animation = 21 * GetRunspeed(); - if(!RuleB(Pathing, Aggro) || !zone->pathing) - CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed()); - else + if(AI_movement_timer->Check()) { - bool WaypointChanged, NodeReached; - glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), - GetRunspeed(), WaypointChanged, NodeReached); + int newspeed = GetRunspeed(); + animation = newspeed; + newspeed *= 2; + SetCurrentSpeed(newspeed); + if(!RuleB(Pathing, Aggro) || !zone->pathing) + CalculateNewPosition2(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), newspeed); + else + { + bool WaypointChanged, NodeReached; + glm::vec3 Goal = UpdatePath(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), + GetRunspeed(), WaypointChanged, NodeReached); - if(WaypointChanged) - tar_ndx = 20; + if(WaypointChanged) + tar_ndx = 20; - CalculateNewPosition2(Goal.x, Goal.y, Goal.z, GetRunspeed()); + CalculateNewPosition2(Goal.x, Goal.y, Goal.z, newspeed); + } } } else if(IsMoving()) { SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); - SetRunAnimSpeed(0); - SendPosition(); - SetMoving(false); - moved=false; + SetCurrentSpeed(0); } } AI_SpellCast(); } else { - if(AIfeignremember_timer->Check()) { + if(AI_feign_remember_timer->Check()) { std::set::iterator RememberedCharID; RememberedCharID = feign_memory_list.begin(); while (RememberedCharID != feign_memory_list.end()) { @@ -1000,21 +921,24 @@ void Client::AI_Process() return; float dist = DistanceSquared(m_Position, owner->GetPosition()); - if (dist >= 100) + if (dist >= 400) { - float speed = dist >= 225 ? GetRunspeed() : GetWalkspeed(); - animation = 21 * speed; - CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed); + if(AI_movement_timer->Check()) + { + int nspeed = (dist >= 5625 ? GetRunspeed() : GetWalkspeed()); + animation = nspeed; + nspeed *= 2; + SetCurrentSpeed(nspeed); + + CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), nspeed); + } } else { - SetHeading(owner->GetHeading()); if(moved) { - moved=false; - SetMoving(false); - SendPosition(); - SetRunAnimSpeed(0); + SetCurrentSpeed(0); + moved = false; } } } @@ -1025,7 +949,7 @@ void Mob::AI_Process() { if (!IsAIControlled()) return; - if (!(AIthink_timer->Check() || attack_timer.Check(false))) + if (!(AI_think_timer->Check() || attack_timer.Check(false))) return; if (IsCasting()) @@ -1037,22 +961,20 @@ void Mob::AI_Process() { // Begin: Additions for Wiz Fear Code // if(RuleB(Combat, EnableFearPathing)){ - if(curfp) { + if(currently_fleeing) { if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) { //make sure everybody knows were not moving, for appearance sake if(IsMoving()) { if(target) SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY())); - SetRunAnimSpeed(0); - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); moved=false; } //continue on to attack code, ensuring that we execute the engaged code engaged = true; } else { - if(AImovement_timer->Check()) { + if(AI_movement_timer->Check()) { // Check if we have reached the last fear point if ((std::abs(GetX() - m_FearWalkTarget.x) < 0.1) && (std::abs(GetY() - m_FearWalkTarget.y) < 0.1)) { @@ -1060,7 +982,9 @@ void Mob::AI_Process() { CalculateNewFearpoint(); } if(!RuleB(Pathing, Fear) || !zone->pathing) + { CalculateNewPosition2(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, GetFearSpeed(), true); + } else { bool WaypointChanged, NodeReached; @@ -1080,19 +1004,21 @@ void Mob::AI_Process() { } // trigger EVENT_SIGNAL if required - if(IsNPC()) { + if (AI_check_signal_timer->Check() && IsNPC()) { CastToNPC()->CheckSignal(); } if (engaged) { + if (!(m_PlayerState & static_cast(PlayerState::Aggressive))) + SendAddPlayerState(PlayerState::Aggressive); // 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()) SetTarget(hate_list.GetClosestEntOnHateList(this)); else { - if(AItarget_check_timer->Check()) + if(AI_target_check_timer->Check()) { if (IsFocused()) { if (!target) { @@ -1116,7 +1042,7 @@ void Mob::AI_Process() { } #ifdef BOTS - if (IsPet() && GetOwner()->IsBot() && target == GetOwner()) + if (IsPet() && GetOwner() && GetOwner()->IsBot() && target == GetOwner()) { // this blocks all pet attacks against owner..bot pet test (copied above check) RemoveFromHateList(this); @@ -1154,17 +1080,23 @@ void Mob::AI_Process() { if (is_combat_range) { - if (AImovement_timer->Check()) + if (AI_movement_timer->Check()) { - SetRunAnimSpeed(0); + if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) + { + SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); + SendPosition(); + } + SetCurrentSpeed(0); } if(IsMoving()) { - SetMoving(false); - moved=false; - SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY())); - SendPosition(); - tar_ndx =0; + if(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) + { + SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY())); + SendPosition(); + } + SetCurrentSpeed(0); } //casting checked above... @@ -1175,43 +1107,10 @@ void Mob::AI_Process() { //try main hand first if(attack_timer.Check()) { - if(IsNPC()) { - int16 n_atk = CastToNPC()->GetNumberOfAttacks(); - if(n_atk <= 1) { - Attack(target, MainPrimary); - } else { - for(int i = 0; i < n_atk; ++i) { - Attack(target, MainPrimary); - } - } - } else { - Attack(target, MainPrimary); - } - - if (target) { - //we use this random value in three comparisons with different - //thresholds, and if its truely random, then this should work - //out reasonably and will save us compute resources. - int32 RandRoll = zone->random.Int(0, 99); - if ((CanThisClassDoubleAttack() || GetSpecialAbility(SPECATK_TRIPLE) - || GetSpecialAbility(SPECATK_QUAD)) - //check double attack, this is NOT the same rules that clients use... - && RandRoll < (GetLevel() + NPCDualAttackModifier)) { - Attack(target, MainPrimary); - // lets see if we can do a triple attack with the main hand - //pets are excluded from triple and quads... - if ((GetSpecialAbility(SPECATK_TRIPLE) || GetSpecialAbility(SPECATK_QUAD)) - && !IsPet() && RandRoll < (GetLevel() + NPCTripleAttackModifier)) { - Attack(target, MainPrimary); - // now lets check the quad attack - if (GetSpecialAbility(SPECATK_QUAD) - && RandRoll < (GetLevel() + NPCQuadAttackModifier)) { - Attack(target, MainPrimary); - } - } - } - } + DoMainHandAttackRounds(target); + TriggerDefensiveProcs(target, EQEmu::legacy::SlotPrimary, false); + bool specialed = false; // NPCs can only do one of these a round if (GetSpecialAbility(SPECATK_FLURRY)) { int flurry_chance = GetSpecialAbilityParam(SPECATK_FLURRY, 0); flurry_chance = flurry_chance > 0 ? flurry_chance : RuleI(Combat, NPCFlurryChance); @@ -1243,19 +1142,16 @@ void Mob::AI_Process() { opts.crit_flat = cur; Flurry(&opts); + specialed = true; } } - if (IsPet() || (IsNPC() && CastToNPC()->GetSwarmOwner())) { + if (IsPet() || IsTempPet()) { Mob *owner = nullptr; - - if (IsPet()) - owner = GetOwner(); - else - owner = entity_list.GetMobID(CastToNPC()->GetSwarmOwner()); + owner = GetOwner(); if (owner) { - int16 flurry_chance = owner->aabonuses.PetFlurry + + int16 flurry_chance = owner->aabonuses.PetFlurry + owner->spellbonuses.PetFlurry + owner->itembonuses.PetFlurry; if (flurry_chance && zone->random.Roll(flurry_chance)) @@ -1263,7 +1159,19 @@ void Mob::AI_Process() { } } - if (GetSpecialAbility(SPECATK_RAMPAGE)) + if ((IsPet() || IsTempPet()) && IsPetOwnerClient()){ + if (spellbonuses.PC_Pet_Rampage[0] || itembonuses.PC_Pet_Rampage[0] || aabonuses.PC_Pet_Rampage[0]){ + int chance = spellbonuses.PC_Pet_Rampage[0] + itembonuses.PC_Pet_Rampage[0] + aabonuses.PC_Pet_Rampage[0]; + int dmg_mod = spellbonuses.PC_Pet_Rampage[1] + itembonuses.PC_Pet_Rampage[1] + aabonuses.PC_Pet_Rampage[1]; + if(zone->random.Roll(chance)) { + ExtraAttackOptions opts; + opts.damage_percent = dmg_mod / 100.0f; + Rampage(&opts); + } + } + } + + if (GetSpecialAbility(SPECATK_RAMPAGE) && !specialed) { int rampage_chance = GetSpecialAbilityParam(SPECATK_RAMPAGE, 0); rampage_chance = rampage_chance > 0 ? rampage_chance : 20; @@ -1299,10 +1207,11 @@ void Mob::AI_Process() { opts.crit_flat = cur; } Rampage(&opts); + specialed = true; } } - if (GetSpecialAbility(SPECATK_AREA_RAMPAGE)) + if (GetSpecialAbility(SPECATK_AREA_RAMPAGE) && !specialed) { int rampage_chance = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 0); rampage_chance = rampage_chance > 0 ? rampage_chance : 20; @@ -1339,37 +1248,22 @@ void Mob::AI_Process() { } AreaRampage(&opts); + specialed = true; } } } //now off hand if (attack_dw_timer.Check() && CanThisClassDualWield()) - { - int myclass = GetClass(); - //can only dual wield without a weapon if your a monk - if(GetSpecialAbility(SPECATK_INNATE_DW) || (GetEquipment(MaterialSecondary) != 0 && GetLevel() > 29) || myclass == MONK || myclass == MONKGM) { - float DualWieldProbability = (GetSkill(SkillDualWield) + GetLevel()) / 400.0f; - if(zone->random.Roll(DualWieldProbability)) - { - Attack(target, MainSecondary); - if (CanThisClassDoubleAttack()) - { - if (zone->random.Roll(GetLevel() + 20)) - { - Attack(target, MainSecondary); - } - } - } - } - } + DoOffHandAttackRounds(target); //now special attacks (kick, etc) if(IsNPC()) CastToNPC()->DoClassAttacks(target); + } AI_EngagedCastCheck(); - } //end is within combat range + } //end is within combat rangepet else { //we cannot reach our target... //underwater stuff only works with water maps in the zone! @@ -1381,7 +1275,7 @@ void Mob::AI_Process() { WipeHateList(); Heal(); BuffFadeAll(); - AIwalking_timer->Start(100); + AI_walking_timer->Start(100); pLastFightingDelayMoving = Timer::GetCurrentTime(); return; } else if(tar != nullptr) { @@ -1403,7 +1297,7 @@ void Mob::AI_Process() { if(AI_PursueCastCheck()){ //we did something, so do not process movement. } - else if (AImovement_timer->Check()) + else if (AI_movement_timer->Check()) { if(!IsRooted()) { Log.Out(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName()); @@ -1425,10 +1319,7 @@ void Mob::AI_Process() { } else if(IsMoving()) { SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY())); - SetRunAnimSpeed(0); - SendPosition(); - SetMoving(false); - moved=false; + SetCurrentSpeed(0); } } @@ -1437,7 +1328,9 @@ void Mob::AI_Process() { } else { - if(AIfeignremember_timer->Check()) { + if (m_PlayerState & static_cast(PlayerState::Aggressive)) + SendRemovePlayerState(PlayerState::Aggressive); + if(AI_feign_remember_timer->Check()) { // 6/14/06 // Improved Feign Death Memory // check to see if any of our previous feigned targets have gotten up. @@ -1462,7 +1355,7 @@ void Mob::AI_Process() { { //we processed a spell action, so do nothing else. } - else if (AIscanarea_timer->Check()) + else if (AI_scan_area_timer->Check()) { /* * This is where NPCs look around to see if they want to attack anybody. @@ -1473,13 +1366,17 @@ void Mob::AI_Process() { * */ - Mob* tmptar = entity_list.AICheckCloseAggro(this, GetAggroRange(), GetAssistRange()); - if (tmptar) - AddToHateList(tmptar); + Mob* temp_target = entity_list.AICheckCloseAggro(this, GetAggroRange(), GetAssistRange()); + if (temp_target){ + AddToHateList(temp_target); + } + + AI_scan_area_timer->Disable(); + AI_scan_area_timer->Start(RandomTimer(RuleI(NPC, NPCToNPCAggroTimerMin), RuleI(NPC, NPCToNPCAggroTimerMax)), false); + } - else if (AImovement_timer->Check() && !IsRooted()) + else if (AI_movement_timer->Check() && !IsRooted()) { - SetRunAnimSpeed(0); if (IsPet()) { // we're a pet, do as we're told @@ -1498,18 +1395,18 @@ void Mob::AI_Process() { float dist = DistanceSquared(m_Position, owner->GetPosition()); if (dist >= 400) { - float speed = GetWalkspeed(); + int speed = GetWalkspeed(); if (dist >= 5625) speed = GetRunspeed(); + CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed); } else { if(moved) { - moved=false; - SetMoving(false); - SendPosition(); + SetCurrentSpeed(0); + moved = false; } } @@ -1555,19 +1452,15 @@ void Mob::AI_Process() { if (dist2 >= followdist) // Default follow distance is 100 { - float speed = GetWalkspeed(); + int speed = GetWalkspeed(); if (dist2 >= followdist + 150) speed = GetRunspeed(); CalculateNewPosition2(follow->GetX(), follow->GetY(), follow->GetZ(), speed); } else { - if(moved) - { - SendPosition(); - moved=false; - SetMoving(false); - } + moved = false; + SetCurrentSpeed(0); } } } @@ -1653,103 +1546,50 @@ void NPC::AI_DoMovement() { } else if (roamer) { - if (AIwalking_timer->Check()) + if (AI_walking_timer->Check()) { movetimercompleted=true; - AIwalking_timer->Disable(); + AI_walking_timer->Disable(); } - int16 gridno = CastToNPC()->GetGrid(); + int32 gridno = CastToNPC()->GetGrid(); if (gridno > 0 || cur_wp==-2) { if (movetimercompleted==true) { // time to pause at wp is over - - int32 spawn_id = this->GetSpawnPointID(); - LinkedListIterator iterator(zone->spawn2_list); - iterator.Reset(); - Spawn2 *found_spawn = nullptr; - - while(iterator.MoreElements()) - { - Spawn2* cur = iterator.GetData(); - iterator.Advance(); - if(cur->GetID() == spawn_id) - { - found_spawn = cur; - break; - } - } - - if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) { - CastToNPC()->Depop(true); //depop and resart spawn timer - if(found_spawn) - found_spawn->SetNPCPointerNull(); - } - else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) { - CastToNPC()->Depop(false);//depop without spawn timer - if(found_spawn) - found_spawn->SetNPCPointerNull(); - } - else { - movetimercompleted=false; - - Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp); - - //if we were under quest control (with no grid), we are done now.. - if(cur_wp == -2) { - Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode."); - roamer = false; - cur_wp = 0; - } - - if(GetAppearance() != eaStanding) - SetAppearance(eaStanding, false); - - entity_list.OpenDoorsNear(CastToNPC()); - - if(!DistractedFromGrid) { - //kick off event_waypoint depart - char temp[16]; - sprintf(temp, "%d", cur_wp); - parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0); - - //setup our next waypoint, if we are still on our normal grid - //remember that the quest event above could have done anything it wanted with our grid - if(gridno > 0) { - CastToNPC()->CalculateNewWaypoint(); - } - } - else { - DistractedFromGrid = false; - } - } + AI_SetupNextWaypoint(); } // endif (movetimercompleted==true) - else if (!(AIwalking_timer->Enabled())) + else if (!(AI_walking_timer->Enabled())) { // currently moving + bool doMove = true; if (m_CurrentWayPoint.x == GetX() && m_CurrentWayPoint.y == GetY()) { // are we there yet? then stop Log.Out(Logs::Detail, Logs::AI, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid()); + SetWaypointPause(); - if(GetAppearance() != eaStanding) - SetAppearance(eaStanding, false); + SetAppearance(eaStanding, false); SetMoving(false); if (m_CurrentWayPoint.w >= 0.0) { SetHeading(m_CurrentWayPoint.w); } + 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()) + AI_SetupNextWaypoint(); + else + doMove = false; // wipe feign memory since we reached our first waypoint if(cur_wp == 1) ClearFeignMemory(); } - else - { // not at waypoint yet, so keep moving + if (doMove) + { // not at waypoint yet or at 0 pause WP, so keep moving if(!RuleB(Pathing, AggroReturnToGrid) || !zone->pathing || (DistractedFromGrid == 0)) CalculateNewPosition2(m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, walksp, true); else @@ -1777,8 +1617,7 @@ void NPC::AI_DoMovement() { SetGrid( 0 - GetGrid()); // revert to AI control Log.Out(Logs::Detail, Logs::Pathing, "Quest pathing is finished. Resuming on grid %d", GetGrid()); - if(GetAppearance() != eaStanding) - SetAppearance(eaStanding, false); + SetAppearance(eaStanding, false); CalculateNewWaypoint(); } @@ -1814,35 +1653,94 @@ void NPC::AI_DoMovement() { Log.Out(Logs::Detail, Logs::AI, "Reached guard point (%.3f,%.3f,%.3f)", m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z); ClearFeignMemory(); moved=false; - SetMoving(false); if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5*5 ) { SetHeading(m_GuardPoint.w); } else { FaceTarget(GetTarget()); } - SendPosition(); + SetCurrentSpeed(0); SetAppearance(GetGuardPointAnim()); } } } } +void NPC::AI_SetupNextWaypoint() { + int32 spawn_id = this->GetSpawnPointID(); + LinkedListIterator iterator(zone->spawn2_list); + iterator.Reset(); + Spawn2 *found_spawn = nullptr; + + while (iterator.MoreElements()) + { + Spawn2* cur = iterator.GetData(); + iterator.Advance(); + if (cur->GetID() == spawn_id) + { + found_spawn = cur; + break; + } + } + + if (wandertype == 4 && cur_wp == CastToNPC()->GetMaxWp()) { + CastToNPC()->Depop(true); //depop and restart spawn timer + if (found_spawn) + found_spawn->SetNPCPointerNull(); + } + else if (wandertype == 6 && cur_wp == CastToNPC()->GetMaxWp()) { + CastToNPC()->Depop(false);//depop without spawn timer + if (found_spawn) + found_spawn->SetNPCPointerNull(); + } + else { + movetimercompleted = false; + + Log.Out(Logs::Detail, Logs::Pathing, "We are departing waypoint %d.", cur_wp); + + //if we were under quest control (with no grid), we are done now.. + if (cur_wp == -2) { + Log.Out(Logs::Detail, Logs::Pathing, "Non-grid quest mob has reached its quest ordered waypoint. Leaving pathing mode."); + roamer = false; + cur_wp = 0; + } + + SetAppearance(eaStanding, false); + + entity_list.OpenDoorsNear(CastToNPC()); + + if (!DistractedFromGrid) { + //kick off event_waypoint depart + char temp[16]; + sprintf(temp, "%d", cur_wp); + parse->EventNPC(EVENT_WAYPOINT_DEPART, CastToNPC(), nullptr, temp, 0); + + //setup our next waypoint, if we are still on our normal grid + //remember that the quest event above could have done anything it wanted with our grid + if (GetGrid() > 0) { + CastToNPC()->CalculateNewWaypoint(); + } + } + else { + DistractedFromGrid = false; + } + } +} + // Note: Mob that caused this may not get added to the hate list until after this function call completes void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) { if (!IsAIControlled()) return; - if(GetAppearance() != eaStanding) - { - SetAppearance(eaStanding); - } + SetAppearance(eaStanding); if (iYellForHelp) { if(IsPet()) { GetOwner()->AI_Event_Engaged(attacker, iYellForHelp); - } else { + } else if (!HasAssistAggro() && NPCAssistCap() < RuleI(Combat, NPCAssistCap)) { entity_list.AIYellForHelp(this, attacker); + if (NPCAssistCap() > 0 && !assist_cap_timer.Enabled()) + assist_cap_timer.Start(RuleI(Combat, NPCAssistCapTimer)); } } @@ -1884,7 +1782,7 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) { void Mob::AI_Event_NoLongerEngaged() { if (!IsAIControlled()) return; - this->AIwalking_timer->Start(RandomTimer(3000,20000)); + this->AI_walking_timer->Start(RandomTimer(3000,20000)); pLastFightingDelayMoving = Timer::GetCurrentTime(); if (minLastFightingDelayMoving == maxLastFightingDelayMoving) pLastFightingDelayMoving += minLastFightingDelayMoving; @@ -1892,15 +1790,18 @@ void Mob::AI_Event_NoLongerEngaged() { pLastFightingDelayMoving += zone->random.Int(minLastFightingDelayMoving, maxLastFightingDelayMoving); // So mobs don't keep running as a ghost until AIwalking_timer fires // if they were moving prior to losing all hate - if(IsMoving()){ + // except if we're a pet, then we might run into some issues with pets backing off when they should immediately be moving + if(!IsPet()) + { SetRunAnimSpeed(0); - SetMoving(false); SendPosition(); } ClearRampage(); if(IsNPC()) { + SetPrimaryAggro(false); + SetAssistAggro(false); if(CastToNPC()->GetCombatEvent() && GetHP() > 0) { if(entity_list.GetNPCByID(this->GetID())) @@ -1989,15 +1890,15 @@ bool NPC::AI_PursueCastCheck() { bool NPC::AI_IdleCastCheck() { if (AIautocastspell_timer->Check(false)) { -#if MobAI_DEBUG_Spells >= 25 - std::cout << "Non-Engaged autocast check triggered: " << this->GetName() << std::endl; -#endif AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting. if (!AICastSpell(this, AISpellVar.idle_beneficial_chance, SpellType_Heal | SpellType_Buff | SpellType_Pet)) { if(!entity_list.AICheckCloseBeneficialSpells(this, 33, MobAISpellRange, SpellType_Heal | SpellType_Buff)) { //if we didnt cast any spells, our autocast timer just resets to the //last duration it was set to... try to put up a more reasonable timer... AIautocastspell_timer->Start(RandomTimer(AISpellVar.idle_no_sp_recast_min, AISpellVar.idle_no_sp_recast_max), false); + + Log.Out(Logs::Moderate, Logs::Spells, "Triggering AI_IdleCastCheck :: Mob %s - Min : %u Max : %u", this->GetCleanName(), AISpellVar.idle_no_sp_recast_min, AISpellVar.idle_no_sp_recast_max); + } //else, spell casting finishing will reset the timer. } //else, spell casting finishing will reset the timer. return(true); @@ -2071,7 +1972,7 @@ bool Mob::Flurry(ExtraAttackOptions *opts) int num_attacks = GetSpecialAbilityParam(SPECATK_FLURRY, 1); num_attacks = num_attacks > 0 ? num_attacks : RuleI(Combat, MaxFlurryHits); for (int i = 0; i < num_attacks; i++) - Attack(target, MainPrimary, false, false, false, opts); + Attack(target, EQEmu::legacy::SlotPrimary, false, false, false, opts); } return true; } @@ -2120,14 +2021,14 @@ bool Mob::Rampage(ExtraAttackOptions *opts) if (m_target == GetTarget()) continue; if (CombatRange(m_target)) { - Attack(m_target, MainPrimary, false, false, false, opts); + ProcessAttackRounds(m_target, opts, 2); index_hit++; } } } if (RuleB(Combat, RampageHitsTarget) && index_hit < rampage_targets) - Attack(GetTarget(), MainPrimary, false, false, false, opts); + ProcessAttackRounds(GetTarget(), opts, 2); return true; } @@ -2142,12 +2043,11 @@ void Mob::AreaRampage(ExtraAttackOptions *opts) } int rampage_targets = GetSpecialAbilityParam(SPECATK_AREA_RAMPAGE, 1); - rampage_targets = rampage_targets > 0 ? rampage_targets : 1; + rampage_targets = rampage_targets > 0 ? rampage_targets : -1; index_hit = hate_list.AreaRampage(this, GetTarget(), rampage_targets, opts); - if(index_hit == 0) { - Attack(GetTarget(), MainPrimary, false, false, false, opts); - } + if(index_hit == 0) + ProcessAttackRounds(GetTarget(), opts, 1); } uint32 Mob::GetLevelCon(uint8 mylevel, uint8 iOtherLevel) { @@ -2371,20 +2271,20 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { DBnpcspells_Struct* parentlist = database.GetNPCSpells(spell_list->parent_list); uint32 i; #if MobAI_DEBUG_Spells >= 10 - std::cout << "Loading NPCSpells onto " << this->GetName() << ": dbspellsid=" << iDBSpellsID; + std::string debug_msg = StringFormat("Loading NPCSpells onto %s: dbspellsid=%u", this->GetName(), iDBSpellsID); if (spell_list) { - std::cout << " (found, " << spell_list->numentries << "), parentlist=" << spell_list->parent_list; + debug_msg.append(StringFormat(" (found, %u), parentlist=%u", spell_list->numentries, spell_list->parent_list)); if (spell_list->parent_list) { - if (parentlist) { - std::cout << " (found, " << parentlist->numentries << ")"; - } + if (parentlist) + debug_msg.append(StringFormat(" (found, %u)", parentlist->numentries)); else - std::cout << " (not found)"; + debug_msg.append(" (not found)"); } } - else - std::cout << " (not found)"; - std::cout << std::endl; + else { + debug_msg.append(" (not found)"); + } + Log.Out(Logs::Detail, Logs::AI, "%s", debug_msg.c_str()); #endif uint16 attack_proc_spell = -1; int8 proc_chance = 3; @@ -2482,8 +2382,10 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { return a.priority > b.priority; }); - if (IsValidSpell(attack_proc_spell)) + if (IsValidSpell(attack_proc_spell)) { AddProcToWeapon(attack_proc_spell, true, proc_chance); + innate_proc_spell_id = attack_proc_spell; + } if (IsValidSpell(range_proc_spell)) AddRangedProc(range_proc_spell, (rproc_chance + 100)); @@ -2506,7 +2408,7 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) { AISpellVar.idle_no_sp_recast_max = (_idle_no_sp_recast_max) ? _idle_no_sp_recast_max : RuleI(Spells, AI_IdleNoSpellMaxRecast); AISpellVar.idle_beneficial_chance = (_idle_beneficial_chance) ? _idle_beneficial_chance : RuleI(Spells, AI_IdleBeneficialChance); - if (AIspells.size() == 0) + if (AIspells.empty()) AIautocastspell_timer->Disable(); else AIautocastspell_timer->Trigger(); @@ -2531,20 +2433,20 @@ bool NPC::AI_AddNPCSpellsEffects(uint32 iDBSpellsEffectsID) { uint32 i; #if MobAI_DEBUG_Spells >= 10 - std::cout << "Loading NPCSpellsEffects onto " << this->GetName() << ": dbspellseffectsid=" << iDBSpellsEffectsID; + std::string debug_msg = StringFormat("Loading NPCSpellsEffects onto %s: dbspellseffectid=%u", this->GetName(), iDBSpellsEffectsID); if (spell_effects_list) { - std::cout << " (found, " << spell_effects_list->numentries << "), parentlist=" << spell_effects)list->parent_list; + debug_msg.append(StringFormat(" (found, %u), parentlist=%u", spell_effects_list->numentries, spell_effects_list->parent_list)); if (spell_effects_list->parent_list) { - if (parentlist) { - std::cout << " (found, " << parentlist->numentries << ")"; - } + if (parentlist) + debug_msg.append(StringFormat(" (found, %u)", parentlist->numentries)); else - std::cout << " (not found)"; + debug_msg.append(" (not found)"); } } - else - std::cout << " (not found)"; - std::cout << std::endl; + else { + debug_msg.append(" (not found)"); + } + Log.Out(Logs::Detail, Logs::AI, "%s", debug_msg.c_str()); #endif if (parentlist) { @@ -2577,11 +2479,9 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon) if (!AI_HasSpellsEffects()) return; - for(int i=0; i < AIspellsEffects.size(); i++) - { - ApplySpellsBonuses(0, 0, newbon, 0, 0, 0,-1, - true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max); - } + for (int i = 0; i < AIspellsEffects.size(); i++) + ApplySpellsBonuses(0, 0, newbon, 0, 0, 0, -1, 10, true, AIspellsEffects[i].spelleffectid, + AIspellsEffects[i].base, AIspellsEffects[i].limit, AIspellsEffects[i].max); return; } @@ -2640,11 +2540,15 @@ void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint16 iType, t.resist_adjust = iResistAdjust; 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); } void NPC::RemoveSpellFromNPCList(int16 spell_id) { - std::vector::iterator iter = AIspells.begin(); + auto iter = AIspells.begin(); while(iter != AIspells.end()) { if((*iter).spellid == spell_id) @@ -2661,7 +2565,7 @@ void NPC::AISpellsList(Client *c) if (!c) return; - for (std::vector::iterator it = AIspells.begin(); it != AIspells.end(); ++it) + 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); diff --git a/zone/mod_functions.cpp b/zone/mod_functions.cpp index 6ae0eddad..601041361 100644 --- a/zone/mod_functions.cpp +++ b/zone/mod_functions.cpp @@ -9,7 +9,6 @@ class ItemInst; class Spawn2; struct Consider_Struct; struct DBTradeskillRecipe_Struct; -struct Item_Struct; extern EntityList entity_list; extern Zone* zone; @@ -26,7 +25,7 @@ void Zone::mod_repop() { return; } void NPC::mod_prespawn(Spawn2 *sp) { return; } //Base damage from NPC::Attack -int NPC::mod_npc_damage(int damage, SkillUseTypes skillinuse, int hand, const Item_Struct* weapon, Mob* other) { return(damage); } +int NPC::mod_npc_damage(int damage, EQEmu::skills::SkillType skillinuse, int hand, const EQEmu::ItemBase* weapon, Mob* other) { return(damage); } //Mob c has been given credit for a kill. This is called after the regular EVENT_KILLED_MERIT event. void NPC::mod_npc_killed_merit(Mob* c) { return; } @@ -35,7 +34,7 @@ void NPC::mod_npc_killed_merit(Mob* c) { return; } void NPC::mod_npc_killed(Mob* oos) { return; } //Base damage from Client::Attack - can cover myriad skill types -int Client::mod_client_damage(int damage, SkillUseTypes skillinuse, int hand, const ItemInst* weapon, Mob* other) { return(damage); } +int Client::mod_client_damage(int damage, EQEmu::skills::SkillType skillinuse, int hand, const ItemInst* weapon, Mob* other) { return(damage); } //message is char[4096], don't screw it up. Return true for normal behavior, false to return immediately. // Channels: @@ -55,7 +54,7 @@ bool Client::mod_client_message(char* message, uint8 chan_num) { return(true); } //Skillup override. When this is called the regular skillup check has failed. Return false to proceed with default behavior. //This will NOT allow a client to increase skill past a cap. -bool Client::mod_can_increase_skill(SkillUseTypes skillid, Mob* against_who) { return(false); } +bool Client::mod_can_increase_skill(EQEmu::skills::SkillType skillid, Mob* against_who) { return(false); } //chance of general skill increase, rolled against 0-99 where higher chance is better. int16 Client::mod_increase_skill_chance(int16 chance, Mob* against_who) { return(chance); } @@ -104,14 +103,14 @@ int32 Client::mod_client_xp(int32 in_xp, NPC *npc) { return(in_xp); } uint32 Client::mod_client_xp_for_level(uint32 xp, uint16 check_level) { return(xp); } //Food and drink values as computed by consume requests. Return < 0 to abort the request. -int Client::mod_food_value(const Item_Struct *item, int change) { return(change); } -int Client::mod_drink_value(const Item_Struct *item, int change) { return(change); } +int Client::mod_food_value(const EQEmu::ItemBase *item, int change) { return(change); } +int Client::mod_drink_value(const EQEmu::ItemBase *item, int change) { return(change); } //effect_vallue - Spell effect value as calculated by default formulas. You will want to ignore effects that don't lend themselves to scaling - pet ID's, gate coords, etc. -int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster) { return(effect_value); } +int Mob::mod_effect_value(int effect_value, uint16 spell_id, int effect_type, Mob* caster, uint16 caster_id) { return(effect_value); } //chancetohit - 0 to 100 percent - set over 1000 for a guaranteed hit -float Mob::mod_hit_chance(float chancetohit, SkillUseTypes skillinuse, Mob* attacker) { return(chancetohit); } +float Mob::mod_hit_chance(float chancetohit, EQEmu::skills::SkillType skillinuse, Mob* attacker) { return(chancetohit); } //Final riposte chance float Mob::mod_riposte_chance(float ripostechance, Mob* attacker) { return(ripostechance); } @@ -143,7 +142,7 @@ int32 Mob::mod_bash_damage(int32 dmg) { return(dmg); } int32 Mob::mod_frenzy_damage(int32 dmg) { return(dmg); } //Special attack damage after all other bonuses are applied. -int32 Mob::mod_monk_special_damage(int32 ndamage, SkillUseTypes skill_type) { return(ndamage); } +int32 Mob::mod_monk_special_damage(int32 ndamage, EQEmu::skills::SkillType skill_type) { return(ndamage); } //ndamage - Backstab damage as calculated by default formulas int32 Mob::mod_backstab_damage(int32 ndamage) { return(ndamage); } diff --git a/zone/net.cpp b/zone/net.cpp index a00b93948..e7cd183ef 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,6 @@ #include "../common/eq_packet_structs.h" #include "../common/mutex.h" #include "../common/version.h" - #include "../common/packet_dump_file.h" #include "../common/opcodemgr.h" #include "../common/guilds.h" @@ -53,6 +52,10 @@ #include "zone.h" #include "queryserv.h" #include "command.h" +#ifdef BOTS +#include "bot_command.h" +#include "bot_database.h" +#endif #include "zone_config.h" #include "titles.h" #include "guild_mgr.h" @@ -60,7 +63,6 @@ #include "quest_parser_collection.h" #include "embparser.h" #include "lua_parser.h" - #include "questmgr.h" #include "remote_call.h" #include "remote_call_subscribe.h" @@ -68,7 +70,6 @@ #include #include #include - #include #include #include @@ -89,7 +90,7 @@ #endif volatile bool RunLoops = true; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; TimeoutManager timeout_manager; NetConnection net; @@ -97,7 +98,6 @@ EntityList entity_list; WorldServer worldserver; uint32 numclients = 0; char errorname[32]; -uint16 adverrornum = 0; extern Zone* zone; EQStreamFactory eqsf(ZoneStream); npcDecayTimes_Struct npcCorpseDecayTimes[100]; @@ -106,10 +106,9 @@ QueryServ *QServ = 0; TaskManager *taskmanager = 0; QuestParserCollection *parse = 0; EQEmuLogSys Log; - const SPDat_Spell_Struct* spells; -void LoadSpells(EQEmu::MemoryMappedFile **mmf); int32 SPDAT_RECORDS = -1; +const ZoneConfig *Config; void Shutdown(); extern void MapOpcodes(); @@ -117,32 +116,101 @@ extern void MapOpcodes(); int main(int argc, char** argv) { RegisterExecutablePlatform(ExePlatformZone); Log.LoadLogSettingsDefaults(); + set_exception_handler(); register_remote_call_handlers(); - const char *zone_name; +#ifdef USE_MAP_MMFS + if (argc == 3 && strcasecmp(argv[1], "convert_map") == 0) { + if (!ZoneConfig::LoadConfig()) + return 1; + Config = ZoneConfig::get(); + + std::string mapfile = argv[2]; + std::transform(mapfile.begin(), mapfile.end(), mapfile.begin(), ::tolower); + std::string filename = Config->MapDir; + filename += mapfile; + + auto m = new Map(); + auto success = m->Load(filename, true); + delete m; + std::cout << mapfile.c_str() << " conversion " << (success ? "succeeded" : "failed") << std::endl; + + return 0; + } +#endif /*USE_MAP_MMFS*/ QServ = new QueryServ; - if(argc == 3) { + Log.Out(Logs::General, Logs::Zone_Server, "Loading server configuration.."); + if(!ZoneConfig::LoadConfig()) { + Log.Out(Logs::General, Logs::Error, "Loading server configuration failed."); + return 1; + } + Config = ZoneConfig::get(); + + const char *zone_name; + uint32 instance_id = 0; + std::string z_name; + if(argc == 4) { + instance_id = atoi(argv[3]); worldserver.SetLauncherName(argv[2]); - worldserver.SetLaunchedName(argv[1]); - if(strncmp(argv[1], "dynamic_", 8) == 0) { - //dynamic zone with a launcher name correlation + auto zone_port = SplitString(argv[1], ':'); + + if(!zone_port.empty()) { + z_name = zone_port[0]; + } + + if(zone_port.size() > 1) { + std::string p_name = zone_port[1]; + Config->SetZonePort(atoi(p_name.c_str())); + } + + worldserver.SetLaunchedName(z_name.c_str()); + if(strncmp(z_name.c_str(), "dynamic_", 8) == 0) { + zone_name = "."; + } + else { + zone_name = z_name.c_str(); + } + } else if(argc == 3) { + worldserver.SetLauncherName(argv[2]); + auto zone_port = SplitString(argv[1], ':'); + + if(!zone_port.empty()) { + z_name = zone_port[0]; + } + + if(zone_port.size() > 1) { + std::string p_name = zone_port[1]; + Config->SetZonePort(atoi(p_name.c_str())); + } + + worldserver.SetLaunchedName(z_name.c_str()); + if(strncmp(z_name.c_str(), "dynamic_", 8) == 0) { zone_name = "."; } else { - zone_name = argv[1]; - worldserver.SetLaunchedName(zone_name); + zone_name = z_name.c_str(); } } else if (argc == 2) { worldserver.SetLauncherName("NONE"); - worldserver.SetLaunchedName(argv[1]); - if(strncmp(argv[1], "dynamic_", 8) == 0) { - //dynamic zone with a launcher name correlation + auto zone_port = SplitString(argv[1], ':'); + + if(!zone_port.empty()) { + z_name = zone_port[0]; + } + + if(zone_port.size() > 1) { + std::string p_name = zone_port[1]; + Config->SetZonePort(atoi(p_name.c_str())); + } + + worldserver.SetLaunchedName(z_name.c_str()); + if(strncmp(z_name.c_str(), "dynamic_", 8) == 0) { zone_name = "."; - } else { - zone_name = argv[1]; - worldserver.SetLaunchedName(zone_name); + } + else { + zone_name = z_name.c_str(); } } else { zone_name = "."; @@ -150,15 +218,8 @@ int main(int argc, char** argv) { worldserver.SetLauncherName("NONE"); } - Log.Out(Logs::General, Logs::Zone_Server, "Loading server configuration.."); - if (!ZoneConfig::LoadConfig()) { - Log.Out(Logs::General, Logs::Error, "Loading server configuration failed."); - return 1; - } - const ZoneConfig *Config = ZoneConfig::get(); - worldserver.SetPassword(Config->SharedKey.c_str()); - + Log.Out(Logs::General, Logs::Zone_Server, "Connecting to MySQL..."); if (!database.Connect( Config->DatabaseHost.c_str(), @@ -170,6 +231,18 @@ int main(int argc, char** argv) { return 1; } +#ifdef BOTS + if (!botdb.Connect( + Config->DatabaseHost.c_str(), + Config->DatabaseUsername.c_str(), + Config->DatabasePassword.c_str(), + Config->DatabaseDB.c_str(), + Config->DatabasePort)) { + Log.Out(Logs::General, Logs::Error, "Cannot continue without a bots database connection."); + return 1; + } +#endif + /* Register Log System and Settings */ Log.OnLogHookCallBackZone(&Zone::GMSayHookCallBackProcess); database.LoadLogSettings(Log.log_settings); @@ -205,41 +278,50 @@ int main(int argc, char** argv) { Log.Out(Logs::General, Logs::Zone_Server, "Mapping Incoming Opcodes"); MapOpcodes(); - + Log.Out(Logs::General, Logs::Zone_Server, "Loading Variables"); database.LoadVariables(); - + + std::string hotfix_name; + if(database.GetVariable("hotfix_name", hotfix_name)) { + if(!hotfix_name.empty()) { + Log.Out(Logs::General, Logs::Zone_Server, "Current hotfix in use: '%s'", hotfix_name.c_str()); + } + } + Log.Out(Logs::General, Logs::Zone_Server, "Loading zone names"); database.LoadZoneNames(); - + Log.Out(Logs::General, Logs::Zone_Server, "Loading items"); - if (!database.LoadItems()) { + if(!database.LoadItems(hotfix_name)) { Log.Out(Logs::General, Logs::Error, "Loading items FAILED!"); Log.Out(Logs::General, Logs::Error, "Failed. But ignoring error and going on..."); } Log.Out(Logs::General, Logs::Zone_Server, "Loading npc faction lists"); - if (!database.LoadNPCFactionLists()) { + if(!database.LoadNPCFactionLists(hotfix_name)) { Log.Out(Logs::General, Logs::Error, "Loading npcs faction lists FAILED!"); return 1; } Log.Out(Logs::General, Logs::Zone_Server, "Loading loot tables"); - if (!database.LoadLoot()) { + if(!database.LoadLoot(hotfix_name)) { Log.Out(Logs::General, Logs::Error, "Loading loot FAILED!"); return 1; } Log.Out(Logs::General, Logs::Zone_Server, "Loading skill caps"); - if (!database.LoadSkillCaps()) { + if(!database.LoadSkillCaps(std::string(hotfix_name))) { Log.Out(Logs::General, Logs::Error, "Loading skill caps FAILED!"); return 1; } Log.Out(Logs::General, Logs::Zone_Server, "Loading spells"); - EQEmu::MemoryMappedFile *mmf = nullptr; - LoadSpells(&mmf); + if(!database.LoadSpells(hotfix_name, &SPDAT_RECORDS, &spells)) { + Log.Out(Logs::General, Logs::Error, "Loading spells FAILED!"); + return 1; + } Log.Out(Logs::General, Logs::Zone_Server, "Loading base data"); - if (!database.LoadBaseData()) { + if(!database.LoadBaseData(hotfix_name)) { Log.Out(Logs::General, Logs::Error, "Loading base data FAILED!"); return 1; } @@ -253,9 +335,6 @@ int main(int argc, char** argv) { Log.Out(Logs::General, Logs::Zone_Server, "Loading titles"); title_manager.LoadTitles(); - Log.Out(Logs::General, Logs::Zone_Server, "Loading AA effects"); - database.LoadAAEffects(); - Log.Out(Logs::General, Logs::Zone_Server, "Loading tributes"); database.LoadTributes(); @@ -271,21 +350,30 @@ int main(int argc, char** argv) { //rules: { - char tmp[64]; - if (database.GetVariable("RuleSet", tmp, sizeof(tmp)-1)) { - Log.Out(Logs::General, Logs::Zone_Server, "Loading rule set '%s'", tmp); - if(!RuleManager::Instance()->LoadRules(&database, tmp)) { - Log.Out(Logs::General, Logs::Error, "Failed to load ruleset '%s', falling back to defaults.", tmp); + std::string tmp; + if (database.GetVariable("RuleSet", tmp)) { + Log.Out(Logs::General, Logs::Zone_Server, "Loading rule set '%s'", tmp.c_str()); + if(!RuleManager::Instance()->LoadRules(&database, tmp.c_str())) { + Log.Out(Logs::General, Logs::Error, "Failed to load ruleset '%s', falling back to defaults.", tmp.c_str()); } } else { if(!RuleManager::Instance()->LoadRules(&database, "default")) { Log.Out(Logs::General, Logs::Zone_Server, "No rule set configured, using default rules"); } else { - Log.Out(Logs::General, Logs::Zone_Server, "Loaded default rule set 'default'", tmp); + Log.Out(Logs::General, Logs::Zone_Server, "Loaded default rule set 'default'", tmp.c_str()); } } } +#ifdef BOTS + Log.Out(Logs::General, Logs::Zone_Server, "Loading bot commands"); + int botretval = bot_command_init(); + if (botretval<0) + Log.Out(Logs::General, Logs::Error, "Bot command loading FAILED"); + else + Log.Out(Logs::General, Logs::Zone_Server, "%d bot commands loaded", botretval); +#endif + if(RuleB(TaskSystem, EnableTaskSystem)) { Log.Out(Logs::General, Logs::Tasks, "[INIT] Loading Tasks"); taskmanager = new TaskManager; @@ -294,13 +382,17 @@ int main(int argc, char** argv) { parse = new QuestParserCollection(); #ifdef LUA_EQEMU - LuaParser *lua_parser = new LuaParser(); + auto lua_parser = new LuaParser(); parse->RegisterQuestInterface(lua_parser, "lua"); #endif #ifdef EMBPERL - PerlembParser *perl_parser = new PerlembParser(); + auto perl_parser = new PerlembParser(); parse->RegisterQuestInterface(perl_parser, "pl"); + + /* Load Perl Event Export Settings */ + parse->LoadPerlEventExportSettings(parse->perl_event_export_settings); + #endif //now we have our parser, load the quests @@ -321,7 +413,7 @@ int main(int argc, char** argv) { #endif if (!strlen(zone_name) || !strcmp(zone_name,".")) { Log.Out(Logs::General, Logs::Zone_Server, "Entering sleep mode"); - } else if (!Zone::Bootup(database.GetZoneID(zone_name), 0, true)) { //todo: go above and fix this to allow cmd line instance + } else if (!Zone::Bootup(database.GetZoneID(zone_name), instance_id, true)) { Log.Out(Logs::General, Logs::Error, "Zone Bootup failed :: Zone::Bootup"); zone = 0; } @@ -351,10 +443,10 @@ int main(int argc, char** argv) { worldserver.Process(); - if (!eqsf.IsOpen() && Config->ZonePort!=0) { - Log.Out(Logs::General, Logs::Zone_Server, "Starting EQ Network server on port %d",Config->ZonePort); + if (!eqsf.IsOpen() && Config->ZonePort != 0) { + Log.Out(Logs::General, Logs::Zone_Server, "Starting EQ Network server on port %d", Config->ZonePort); if (!eqsf.Open(Config->ZonePort)) { - Log.Out(Logs::General, Logs::Error, "Failed to open port %d",Config->ZonePort); + Log.Out(Logs::General, Logs::Error, "Failed to open port %d", Config->ZonePort); ZoneConfig::SetZonePort(0); worldserver.Disconnect(); worldwasconnected = false; @@ -368,7 +460,7 @@ int main(int argc, char** argv) { //structures and opcodes for that patch. struct in_addr in; in.s_addr = eqss->GetRemoteIP(); - Log.Out(Logs::Detail, Logs::World_Server, "New connection from %s:%d", inet_ntoa(in),ntohs(eqss->GetRemotePort())); + Log.Out(Logs::Detail, Logs::World_Server, "New connection from %s:%d", inet_ntoa(in), ntohs(eqss->GetRemotePort())); stream_identifier.AddStream(eqss); //takes the stream } @@ -381,7 +473,7 @@ int main(int argc, char** argv) { struct in_addr in; in.s_addr = eqsi->GetRemoteIP(); Log.Out(Logs::Detail, Logs::World_Server, "New client from %s:%d", inet_ntoa(in), ntohs(eqsi->GetRemotePort())); - Client* client = new Client(eqsi); + auto client = new Client(eqsi); entity_list.AddClient(client); } @@ -400,12 +492,12 @@ int main(int argc, char** argv) { worldwasconnected = true; } else { - if (worldwasconnected && ZoneLoaded) + if (worldwasconnected && is_zone_loaded) entity_list.ChannelMessageFromWorld(0, 0, 6, 0, 0, "WARNING: World server connection lost"); worldwasconnected = false; } - if (ZoneLoaded && zoneupdate_timer.Check()) { + if (is_zone_loaded && zoneupdate_timer.Check()) { { if(net.group_timer.Enabled() && net.group_timer.Check()) entity_list.GroupProcess(); @@ -428,6 +520,7 @@ int main(int argc, char** argv) { entity_list.Process(); entity_list.MobProcess(); entity_list.BeaconProcess(); + entity_list.EncounterProcess(); if (zone) { if(!zone->Process()) { @@ -475,7 +568,6 @@ int main(int argc, char** argv) { safe_delete(lua_parser); #endif - safe_delete(mmf); safe_delete(Config); if (zone != 0) @@ -485,6 +577,9 @@ int main(int argc, char** argv) { worldserver.Disconnect(); safe_delete(taskmanager); command_deinit(); +#ifdef BOTS + bot_command_deinit(); +#endif safe_delete(parse); Log.Out(Logs::General, Logs::Zone_Server, "Proper zone shutdown complete."); Log.CloseFileLogs(); @@ -541,16 +636,6 @@ uint32 NetConnection::GetIP(char* name) } -void NetConnection::SaveInfo(char* address, uint32 port, char* waddress, char* filename) { - - ZoneAddress = new char[strlen(address)+1]; - strcpy(ZoneAddress, address); - ZonePort = port; - WorldAddress = new char[strlen(waddress)+1]; - strcpy(WorldAddress, waddress); - strn0cpy(ZoneFileName, filename, sizeof(ZoneFileName)); -} - NetConnection::NetConnection() : object_timer(5000), @@ -560,9 +645,6 @@ NetConnection::NetConnection() raid_timer(1000), trap_timer(1000) { - ZonePort = 0; - ZoneAddress = 0; - WorldAddress = 0; group_timer.Disable(); raid_timer.Disable(); corpse_timer.Disable(); @@ -572,32 +654,6 @@ NetConnection::NetConnection() } NetConnection::~NetConnection() { - if (ZoneAddress != 0) - safe_delete_array(ZoneAddress); - if (WorldAddress != 0) - safe_delete_array(WorldAddress); -} - -void LoadSpells(EQEmu::MemoryMappedFile **mmf) { - int records = database.GetMaxSpellID() + 1; - - try { - EQEmu::IPCMutex mutex("spells"); - mutex.Lock(); - *mmf = new EQEmu::MemoryMappedFile("shared/spells"); - uint32 size = (*mmf)->Size(); - if(size != (records * sizeof(SPDat_Spell_Struct))) { - EQ_EXCEPT("Zone", "Unable to load spells: (*mmf)->Size() != records * sizeof(SPDat_Spell_Struct)"); - } - - spells = reinterpret_cast((*mmf)->Get()); - mutex.Unlock(); - } catch(std::exception &ex) { - Log.Out(Logs::General, Logs::Error, "Error loading spells: %s", ex.what()); - return; - } - - SPDAT_RECORDS = records; } /* Update Window Title with relevant information */ diff --git a/zone/net.h b/zone/net.h index c49e1ec8e..4d44b6058 100644 --- a/zone/net.h +++ b/zone/net.h @@ -16,8 +16,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef _WINDOWS + #include #include - #include #else #include #include @@ -39,20 +39,10 @@ public: uint32 GetIP(); uint32 GetIP(char* name); - void SaveInfo(char* address, uint32 port, char* waddress,char* filename); - char* GetWorldAddress() { return WorldAddress; } - char* GetZoneAddress() { return ZoneAddress; } - char* GetZoneFileName() { return ZoneFileName; } - uint32 GetZonePort() { return ZonePort; } Timer object_timer; Timer door_timer; Timer corpse_timer; Timer group_timer; Timer raid_timer; Timer trap_timer; -private: - uint16 ZonePort; - char* ZoneAddress; - char* WorldAddress; - char ZoneFileName[50]; }; diff --git a/zone/npc.cpp b/zone/npc.cpp index a9a383d55..1fc27dc5a 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -24,20 +24,21 @@ #include "../common/seperator.h" #include "../common/spdat.h" #include "../common/string_util.h" -#include "../common/clientversions.h" +#include "../common/emu_versions.h" #include "../common/features.h" #include "../common/item.h" -#include "../common/item_struct.h" +#include "../common/item_base.h" #include "../common/linked_list.h" #include "../common/servertalk.h" +#include "../common/say_link.h" -#include "aa.h" #include "client.h" #include "entity.h" #include "npc.h" #include "string_ids.h" #include "spawn2.h" #include "zone.h" +#include "quest_parser_collection.h" #include #include @@ -53,7 +54,7 @@ #endif extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern EntityList entity_list; NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int iflymode, bool IsCorpse) @@ -93,7 +94,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if d->drakkin_heritage, d->drakkin_tattoo, d->drakkin_details, - (uint32*)d->armor_tint, + d->armor_tint, 0, d->see_invis, // pass see_invis/see_ivu flags to mob constructor d->see_invis_undead, @@ -103,14 +104,19 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if d->mana_regen, d->qglobal, d->maxlevel, - d->scalerate ), + d->scalerate, + d->armtexture, + d->bracertexture, + d->handtexture, + d->legtexture, + d->feettexture), attacked_timer(CombatEventTimer_expire), swarm_timer(100), classattack_timer(1000), knightattack_timer(1000), assist_timer(AIassistcheck_delay), qglobal_purge_timer(30000), - sendhpupdate_timer(1000), + sendhpupdate_timer(2000), enraged_timer(1000), taunt_timer(TauntReuseTime * 1000), m_SpawnPoint(position), @@ -227,6 +233,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if npc_spells_id = 0; HasAISpell = false; HasAISpellEffects = false; + innate_proc_spell_id = 0; if(GetClass() == MERCERNARY_MASTER && RuleB(Mercs, AllowMercs)) { @@ -271,8 +278,20 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if //give NPCs skill values... int r; - for(r = 0; r <= HIGHEST_SKILL; r++) { - skills[r] = database.GetSkillCap(GetClass(),(SkillUseTypes)r,moblevel); + for (r = 0; r <= EQEmu::skills::HIGHEST_SKILL; r++) { + skills[r] = database.GetSkillCap(GetClass(), (EQEmu::skills::SkillType)r, moblevel); + } + // some overrides -- really we need to be able to set skills for mobs in the DB + // There are some known low level SHM/BST pets that do not follow this, which supports + // the theory of needing to be able to set skills for each mob separately + if (moblevel > 50) { + skills[EQEmu::skills::SkillDoubleAttack] = 250; + skills[EQEmu::skills::SkillDualWield] = 250; + } else if (moblevel > 3) { + skills[EQEmu::skills::SkillDoubleAttack] = moblevel * 5; + skills[EQEmu::skills::SkillDualWield] = skills[EQEmu::skills::SkillDoubleAttack]; + } else { + skills[EQEmu::skills::SkillDoubleAttack] = moblevel * 5; } if(d->trap_template > 0) @@ -286,7 +305,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, const glm::vec4& position, int if trap_list = trap_ent_iter->second; if(trap_list.size() > 0) { - std::list::iterator trap_list_iter = trap_list.begin(); + auto trap_list_iter = trap_list.begin(); std::advance(trap_list_iter, zone->random.Int(0, trap_list.size() - 1)); LDoNTrapTemplate* tt = (*trap_list_iter); if(tt) @@ -462,7 +481,7 @@ void NPC::CheckMinMaxLevel(Mob *them) uint16 themlevel = them->GetLevel(); uint8 material; - std::list::iterator cur = itemlist.begin(); + auto cur = itemlist.begin(); while(cur != itemlist.end()) { if(!(*cur)) @@ -471,7 +490,7 @@ void NPC::CheckMinMaxLevel(Mob *them) if(themlevel < (*cur)->min_level || themlevel > (*cur)->max_level) { material = Inventory::CalcMaterialFromSlot((*cur)->equip_slot); - if (material != _MaterialInvalid) + if (material != EQEmu::textures::TextureInvalid) SendWearChange(material); cur = itemlist.erase(cur); @@ -505,19 +524,19 @@ void NPC::QueryLoot(Client* to) to->Message(0, "Coin: %ip %ig %is %ic", platinum, gold, silver, copper); int x = 0; - for(ItemList::iterator cur = itemlist.begin(); cur != itemlist.end(); ++cur, ++x) { - const Item_Struct* item = database.GetItem((*cur)->item_id); + for (auto cur = itemlist.begin(); cur != itemlist.end(); ++cur, ++x) { + const EQEmu::ItemBase* item = database.GetItem((*cur)->item_id); if (item == nullptr) { Log.Out(Logs::General, Logs::Error, "Database error, invalid item"); continue; } - Client::TextLink linker; - linker.SetLinkType(linker.linkItemData); + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemData); linker.SetItemData(item); auto item_link = linker.GenerateLink(); - + to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", item_link.c_str(), item->ID, (*cur)->min_level, (*cur)->max_level); } @@ -564,8 +583,7 @@ bool NPC::Process() { if (IsStunned() && stunned_timer.Check()) { - this->stunned = false; - this->stunned_timer.Disable(); + Mob::UnStun(); this->spun_timer.Disable(); } @@ -586,9 +604,10 @@ bool NPC::Process() if(tic_timer.Check()) { + parse->EventNPC(EVENT_TICK, this, nullptr, "", 0); BuffProcess(); - if(curfp) + if(currently_fleeing) ProcessFlee(); uint32 bonus = 0; @@ -646,7 +665,8 @@ bool NPC::Process() } } - if (sendhpupdate_timer.Check() && (IsTargeted() || (IsPet() && GetOwner() && GetOwner()->IsClient()))) { + // we might actually want to reset in this check ... won't until issues arise at least :P + if (sendhpupdate_timer.Check(false) && (IsTargeted() || (IsPet() && GetOwner() && GetOwner()->IsClient()))) { if(!IsFullHP || cur_hp 0) + DelAssistCap(); + else + assist_cap_timer.Disable(); + } + + if (assist_timer.Check() && IsEngaged() && !Charmed() && !HasAssistAggro() && + NPCAssistCap() < RuleI(Combat, NPCAssistCap)) { entity_list.AIYellForHelp(this, GetTarget()); + if (NPCAssistCap() > 0 && !assist_cap_timer.Enabled()) + assist_cap_timer.Start(RuleI(Combat, NPCAssistCapTimer)); } if(qGlobals) @@ -717,18 +747,18 @@ uint32 NPC::CountLoot() { void NPC::UpdateEquipmentLight() { - m_Light.Type.Equipment = 0; - m_Light.Level.Equipment = 0; - - for (int index = MAIN_BEGIN; index < EmuConstants::EQUIPMENT_SIZE; ++index) { - if (index == MainAmmo) { continue; } + m_Light.Type[EQEmu::lightsource::LightEquipment] = 0; + m_Light.Level[EQEmu::lightsource::LightEquipment] = 0; + + for (int index = SLOT_BEGIN; index < EQEmu::legacy::EQUIPMENT_SIZE; ++index) { + if (index == EQEmu::legacy::SlotAmmo) { continue; } auto item = database.GetItem(equipment[index]); if (item == nullptr) { continue; } - if (m_Light.IsLevelGreater(item->Light, m_Light.Type.Equipment)) { - m_Light.Type.Equipment = item->Light; - m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); + if (EQEmu::lightsource::IsLevelGreater(item->Light, m_Light.Type[EQEmu::lightsource::LightEquipment])) { + m_Light.Type[EQEmu::lightsource::LightEquipment] = item->Light; + m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } } @@ -737,17 +767,17 @@ void NPC::UpdateEquipmentLight() auto item = database.GetItem((*iter)->item_id); if (item == nullptr) { continue; } - if (item->ItemClass != ItemClassCommon) { continue; } + if (!item->IsClassCommon()) { continue; } if (item->Light < 9 || item->Light > 13) { continue; } - if (m_Light.TypeToLevel(item->Light)) + if (EQEmu::lightsource::TypeToLevel(item->Light)) general_light_type = item->Light; } - if (m_Light.IsLevelGreater(general_light_type, m_Light.Type.Equipment)) - m_Light.Type.Equipment = general_light_type; + if (EQEmu::lightsource::IsLevelGreater(general_light_type, m_Light.Type[EQEmu::lightsource::LightEquipment])) + m_Light.Type[EQEmu::lightsource::LightEquipment] = general_light_type; - m_Light.Level.Equipment = m_Light.TypeToLevel(m_Light.Type.Equipment); + m_Light.Level[EQEmu::lightsource::LightEquipment] = EQEmu::lightsource::TypeToLevel(m_Light.Type[EQEmu::lightsource::LightEquipment]); } void NPC::Depop(bool StartSpawnTimer) { @@ -815,6 +845,54 @@ bool NPC::DatabaseCastAccepted(int spell_id) { return false; } +bool NPC::SpawnZoneController(){ + + if (!RuleB(Zone, UseZoneController)) + return false; + + auto npc_type = new NPCType; + memset(npc_type, 0, sizeof(NPCType)); + + strncpy(npc_type->name, "zone_controller", 60); + npc_type->cur_hp = 2000000000; + npc_type->max_hp = 2000000000; + npc_type->hp_regen = 100000000; + npc_type->race = 240; + npc_type->size = .1; + npc_type->gender = 2; + npc_type->class_ = 1; + npc_type->deity = 1; + npc_type->level = 200; + npc_type->npc_id = ZONE_CONTROLLER_NPC_ID; + npc_type->loottable_id = 0; + npc_type->texture = 3; + npc_type->runspeed = 0; + npc_type->d_melee_texture1 = 0; + npc_type->d_melee_texture2 = 0; + npc_type->merchanttype = 0; + npc_type->bodytype = 11; + + npc_type->prim_melee_type = 28; + npc_type->sec_melee_type = 28; + + npc_type->findable = 0; + npc_type->trackable = 0; + + strcpy(npc_type->special_abilities, "12,1^13,1^14,1^15,1^16,1^17,1^19,1^22,1^24,1^25,1^28,1^31,1^35,1^39,1^42,1"); + + glm::vec4 point; + point.x = 3000; + point.y = 1000; + point.z = 500; + + auto npc = new NPC(npc_type, nullptr, point, FlyMode3); + npc->GiveNPCTypeData(npc_type); + + entity_list.AddNPC(npc); + + return true; +} + NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client) { if(spawncommand == 0 || spawncommand[0] == 0) { return 0; @@ -940,7 +1018,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* } //Time to create the NPC!! - NPCType* npc_type = new NPCType; + auto npc_type = new NPCType; memset(npc_type, 0, sizeof(NPCType)); strncpy(npc_type->name, sep.arg[0], 60); @@ -974,7 +1052,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* npc_type->prim_melee_type = 28; npc_type->sec_melee_type = 28; - NPC* npc = new NPC(npc_type, nullptr, position, FlyMode3); + auto npc = new NPC(npc_type, nullptr, position, FlyMode3); npc->GiveNPCTypeData(npc_type); entity_list.AddNPC(npc); @@ -1029,7 +1107,7 @@ uint32 ZoneDatabase::CreateNewNPCCommand(const char *zone, uint32 zone_version, query = StringFormat("INSERT INTO npc_types (id, name, level, race, class, hp, gender, " "texture, helmtexture, size, loottable_id, merchant_id, face, " "runspeed, prim_melee_type, sec_melee_type) " - "VALUES(%i, \"%s\" , %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)", + "VALUES(%i, \"%s\" , %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %i, %i, %i)", npc_type_id, tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), @@ -1043,7 +1121,7 @@ uint32 ZoneDatabase::CreateNewNPCCommand(const char *zone, uint32 zone_version, query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, " "texture, helmtexture, size, loottable_id, merchant_id, face, " "runspeed, prim_melee_type, sec_melee_type) " - "VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)", + "VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %i, %i, %i)", tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28); @@ -1061,6 +1139,9 @@ uint32 ZoneDatabase::CreateNewNPCCommand(const char *zone, uint32 zone_version, } uint32 spawngroupid = results.LastInsertedID(); + spawn->SetSp2(spawngroupid); + spawn->SetNPCTypeID(npc_type_id); + query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) " "VALUES('%s', %u, %f, %f, %f, %i, %f, %i)", zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), 1200, spawn->GetHeading(), @@ -1293,7 +1374,7 @@ uint32 ZoneDatabase::NPCSpawnDB(uint8 command, const char* zone, uint32 zone_ver int32 NPC::GetEquipmentMaterial(uint8 material_slot) const { - if (material_slot >= _MaterialCount) + if (material_slot >= EQEmu::textures::TextureCount) return 0; int16 invslot = Inventory::CalcSlotFromMaterial(material_slot); @@ -1304,13 +1385,23 @@ int32 NPC::GetEquipmentMaterial(uint8 material_slot) const { switch(material_slot) { - case MaterialHead: + case EQEmu::textures::TextureHead: return helmtexture; - case MaterialChest: + case EQEmu::textures::TextureChest: return texture; - case MaterialPrimary: + case EQEmu::textures::TextureArms: + return armtexture; + case EQEmu::textures::TextureWrist: + return bracertexture; + case EQEmu::textures::TextureHands: + return handtexture; + case EQEmu::textures::TextureLegs: + return legtexture; + case EQEmu::textures::TextureFeet: + return feettexture; + case EQEmu::textures::TexturePrimary: return d_melee_texture1; - case MaterialSecondary: + case EQEmu::textures::TextureSecondary: return d_melee_texture2; default: //they have nothing in the slot, and its not a special slot... they get nothing. @@ -1336,13 +1427,13 @@ uint32 NPC::GetMaxDamage(uint8 tlevel) return dmg; } -void NPC::PickPocket(Client* thief) { +void NPC::PickPocket(Client* thief) +{ + thief->CheckIncreaseSkill(EQEmu::skills::SkillPickPockets, nullptr, 5); - thief->CheckIncreaseSkill(SkillPickPockets, nullptr, 5); - - //make sure were allowed to targte them: - int olevel = GetLevel(); - if(olevel > (thief->GetLevel() + THIEF_PICKPOCKET_OVER)) { + //make sure were allowed to target them: + int over_level = GetLevel(); + if(over_level > (thief->GetLevel() + THIEF_PICKPOCKET_OVER)) { thief->Message(13, "You are too inexperienced to pick pocket this target"); thief->SendPickPocketResponse(this, 0, PickPocketFailed); //should we check aggro @@ -1357,151 +1448,110 @@ void NPC::PickPocket(Client* thief) { return; } - int steal_skill = thief->GetSkill(SkillPickPockets); - int stealchance = steal_skill*100/(5*olevel+5); - ItemInst* inst = 0; - int x = 0; - int slot[50]; - int steal_items[50]; - int charges[50]; - int money[4]; - money[0] = GetPlatinum(); - money[1] = GetGold(); - money[2] = GetSilver(); - money[3] = GetCopper(); - if (steal_skill < 125) - money[0] = 0; - if (steal_skill < 60) - money[1] = 0; - memset(slot,0,50); - memset(steal_items,0,50); - memset(charges,0,50); - //Determine wheter to steal money or an item. - bool no_coin = ((money[0] + money[1] + money[2] + money[3]) == 0); - bool steal_item = (zone->random.Roll(50) || no_coin); - if (steal_item) - { - ItemList::iterator cur,end; - cur = itemlist.begin(); - end = itemlist.end(); - for(; cur != end && x < 49; ++cur) { - ServerLootItem_Struct* citem = *cur; - const Item_Struct* item = database.GetItem(citem->item_id); - if (item) - { - inst = database.CreateItem(item, citem->charges); - bool is_arrow = (item->ItemType == ItemTypeArrow) ? true : false; - int slot_id = thief->GetInv().FindFreeSlot(false, true, inst->GetItem()->Size, is_arrow); - if (/*!Equipped(item->ID) &&*/ - !item->Magic && item->NoDrop != 0 && !inst->IsType(ItemClassContainer) && slot_id != INVALID_INDEX - /*&& steal_skill > item->StealSkill*/ ) - { - slot[x] = slot_id; - steal_items[x] = item->ID; - if (inst->IsStackable()) - charges[x] = 1; - else - charges[x] = citem->charges; - x++; - } - } + int steal_skill = thief->GetSkill(EQEmu::skills::SkillPickPockets); + int steal_chance = steal_skill * 100 / (5 * over_level + 5); + + // Determine whether to steal money or an item. + uint32 money[6] = { 0, ((steal_skill >= 125) ? (GetPlatinum()) : (0)), ((steal_skill >= 60) ? (GetGold()) : (0)), GetSilver(), GetCopper(), 0 }; + bool has_coin = ((money[PickPocketPlatinum] | money[PickPocketGold] | money[PickPocketSilver] | money[PickPocketCopper]) != 0); + bool steal_item = (steal_skill >= steal_chance && (zone->random.Roll(50) || !has_coin)); + + // still needs to have FindFreeSlot vs PutItemInInventory issue worked out + while (steal_item) { + std::vector> loot_selection; // + for (auto item_iter : itemlist) { + if (!item_iter || !item_iter->item_id) + continue; + + auto item_test = database.GetItem(item_iter->item_id); + if (item_test->Magic || !item_test->NoDrop || item_test->IsClassBag() || thief->CheckLoreConflict(item_test)) + continue; + + loot_selection.push_back(std::make_pair(item_test, ((item_test->Stackable) ? (1) : (item_iter->charges)))); } - if (x > 0) - { - int random = zone->random.Int(0, x-1); - inst = database.CreateItem(steal_items[random], charges[random]); - if (inst) - { - const Item_Struct* item = inst->GetItem(); - if (item) - { - if (/*item->StealSkill || */steal_skill >= stealchance) - { - thief->PutItemInInventory(slot[random], *inst); - thief->SendItemPacket(slot[random], inst, ItemPacketTrade); - RemoveItem(item->ID); - thief->SendPickPocketResponse(this, 0, PickPocketItem, item); - } - else - steal_item = false; - } - else - steal_item = false; - } - else - steal_item = false; - } - else if (!no_coin) - { + if (loot_selection.empty()) { steal_item = false; - } - else - { - thief->Message(0, "This target's pockets are empty"); - thief->SendPickPocketResponse(this, 0, PickPocketFailed); - } - } - if (!steal_item) //Steal money - { - uint32 amt = zone->random.Int(1, (steal_skill/25)+1); - int steal_type = 0; - if (!money[0]) - { - steal_type = 1; - if (!money[1]) - { - steal_type = 2; - if (!money[2]) - { - steal_type = 3; - } - } + break; } - if (zone->random.Roll(stealchance)) - { - switch (steal_type) - { - case 0:{ - if (amt > GetPlatinum()) - amt = GetPlatinum(); - SetPlatinum(GetPlatinum()-amt); - thief->AddMoneyToPP(0,0,0,amt,false); - thief->SendPickPocketResponse(this, amt, PickPocketPlatinum); - break; - } - case 1:{ - if (amt > GetGold()) - amt = GetGold(); - SetGold(GetGold()-amt); - thief->AddMoneyToPP(0,0,amt,0,false); - thief->SendPickPocketResponse(this, amt, PickPocketGold); - break; - } - case 2:{ - if (amt > GetSilver()) - amt = GetSilver(); - SetSilver(GetSilver()-amt); - thief->AddMoneyToPP(0,amt,0,0,false); - thief->SendPickPocketResponse(this, amt, PickPocketSilver); - break; - } - case 3:{ - if (amt > GetCopper()) - amt = GetCopper(); - SetCopper(GetCopper()-amt); - thief->AddMoneyToPP(amt,0,0,0,false); - thief->SendPickPocketResponse(this, amt, PickPocketCopper); - break; - } + int random = zone->random.Int(0, (loot_selection.size() - 1)); + uint16 slot_id = thief->GetInv().FindFreeSlot(false, true, (loot_selection[random].first->Size), (loot_selection[random].first->ItemType == EQEmu::item::ItemTypeArrow)); + if (slot_id == INVALID_INDEX) { + steal_item = false; + break; + } + + auto item_inst = database.CreateItem(loot_selection[random].first, loot_selection[random].second); + if (item_inst == nullptr) { + steal_item = false; + break; + } + + // Successful item pickpocket + if (item_inst->IsStackable() && RuleB(Character, UseStackablePickPocketing)) { + if (!thief->TryStacking(item_inst, ItemPacketTrade, false, false)) { + thief->PutItemInInventory(slot_id, *item_inst); + thief->SendItemPacket(slot_id, item_inst, ItemPacketTrade); } } - else - { - thief->SendPickPocketResponse(this, 0, PickPocketFailed); + else { + thief->PutItemInInventory(slot_id, *item_inst); + thief->SendItemPacket(slot_id, item_inst, ItemPacketTrade); } + RemoveItem(item_inst->GetID()); + thief->SendPickPocketResponse(this, 0, PickPocketItem, item_inst->GetItem()); + + return; } - safe_delete(inst); + + while (!steal_item && has_coin) { + uint32 coin_amount = zone->random.Int(1, (steal_skill / 25) + 1); + + int coin_type = PickPocketPlatinum; + while (coin_type <= PickPocketCopper) { + if (money[coin_type]) { + if (coin_amount > money[coin_type]) + coin_amount = money[coin_type]; + break; + } + ++coin_type; + } + if (coin_type > PickPocketCopper) + break; + + memset(money, 0, (sizeof(int) * 6)); + money[coin_type] = coin_amount; + + if (zone->random.Roll(steal_chance)) { // Successful coin pickpocket + switch (coin_type) { + case PickPocketPlatinum: + SetPlatinum(GetPlatinum() - coin_amount); + break; + case PickPocketGold: + SetGold(GetGold() - coin_amount); + break; + case PickPocketSilver: + SetSilver(GetSilver() - coin_amount); + break; + case PickPocketCopper: + SetCopper(GetCopper() - coin_amount); + break; + default: // has_coin..but, doesn't have coin? + thief->SendPickPocketResponse(this, 0, PickPocketFailed); + return; + } + + thief->AddMoneyToPP(money[PickPocketCopper], money[PickPocketSilver], money[PickPocketGold], money[PickPocketPlatinum], false); + thief->SendPickPocketResponse(this, coin_amount, coin_type); + return; + } + + thief->SendPickPocketResponse(this, 0, PickPocketFailed); + return; + } + + thief->Message(0, "This target's pockets are empty"); + thief->SendPickPocketResponse(this, 0, PickPocketFailed); } void Mob::NPCSpecialAttacks(const char* parse, int permtag, bool reset, bool remove) { @@ -1839,7 +1889,7 @@ void NPC::PetOnSpawn(NewSpawn_Struct* ns) if(swarmOwner->IsClient()) { SetPetOwnerClient(true); //Simple flag to determine if pet belongs to a client - SetAllowBeneficial(1);//Allow temp pets to receive buffs and heals if owner is client. + SetAllowBeneficial(true);//Allow temp pets to receive buffs and heals if owner is client. //This will allow CLIENT swarm pets NOT to be targeted with F8. ns->spawn.targetable_with_hotkey = 0; no_target_hotkey = 1; @@ -1913,12 +1963,20 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue) else if(id == "cr") { CR = atoi(val.c_str()); return; } else if(id == "pr") { PR = atoi(val.c_str()); return; } else if(id == "dr") { DR = atoi(val.c_str()); return; } - else if(id == "PhR") { PhR = atoi(val.c_str()); return; } - else if(id == "runspeed") { runspeed = (float)atof(val.c_str()); CalcBonuses(); return; } + else if(id == "phr") { PhR = atoi(val.c_str()); return; } + else if(id == "runspeed") { + runspeed = (float)atof(val.c_str()); + base_runspeed = (int)((float)runspeed * 40.0f); + base_walkspeed = base_runspeed * 100 / 265; + walkspeed = ((float)base_walkspeed) * 0.025f; + base_fearspeed = base_runspeed * 100 / 127; + fearspeed = ((float)base_fearspeed) * 0.025f; + CalcBonuses(); return; + } else if(id == "special_attacks") { NPCSpecialAttacks(val.c_str(), 0, 1); return; } else if(id == "special_abilities") { ProcessSpecialAbilities(val.c_str()); return; } else if(id == "attack_speed") { attack_speed = (float)atof(val.c_str()); CalcBonuses(); return; } - else if(id == "attack_delay") { attack_delay = atoi(val.c_str()); CalcBonuses(); return; } + else if(id == "attack_delay") { attack_delay = atoi(val.c_str()); CalcBonuses(); return; } else if(id == "atk") { ATK = atoi(val.c_str()); return; } else if(id == "accuracy") { accuracy_rating = atoi(val.c_str()); return; } else if(id == "avoidance") { avoidance_rating = atoi(val.c_str()); return; } @@ -1939,6 +1997,8 @@ void NPC::ModifyNPCStat(const char *identifier, const char *newValue) else if(id == "loottable_id") { loottable_id = atof(val.c_str()); return; } else if(id == "healscale") { healscale = atof(val.c_str()); return; } else if(id == "spellscale") { spellscale = atof(val.c_str()); return; } + else if(id == "npc_spells_id") { AI_AddNPCSpells(atoi(val.c_str())); return; } + else if(id == "npc_spells_effects_id") { AI_AddNPCSpellsEffects(atoi(val.c_str())); CalcBonuses(); return; } } void NPC::LevelScale() { @@ -1947,44 +2007,90 @@ void NPC::LevelScale() { float scaling = (((random_level / (float)level) - 1) * (scalerate / 100.0f)); - // Compensate for scale rates at low levels so they don't add too much - uint8 scale_adjust = 1; - if(level > 0 && level <= 5) - scale_adjust = 10; - if(level > 5 && level <= 10) - scale_adjust = 5; - if(level > 10 && level <= 15) - scale_adjust = 3; - if(level > 15 && level <= 25) - scale_adjust = 2; + if (RuleB(NPC, NewLevelScaling)) { + if (scalerate == 0 || maxlevel <= 25) { + // pre-pop seems to scale by 20 HP increments while newer by 100 + // We also don't want 100 increments on newer noobie zones, check level + if (zone->GetZoneID() < 200 || level < 48) { + max_hp += (random_level - level) * 20; + base_hp += (random_level - level) * 20; + } else { + max_hp += (random_level - level) * 100; + base_hp += (random_level - level) * 100; + } - base_hp += (int)(base_hp * scaling); - max_hp += (int)(max_hp * scaling); - cur_hp = max_hp; - STR += (int)(STR * scaling / scale_adjust); - STA += (int)(STA * scaling / scale_adjust); - AGI += (int)(AGI * scaling / scale_adjust); - DEX += (int)(DEX * scaling / scale_adjust); - INT += (int)(INT * scaling / scale_adjust); - WIS += (int)(WIS * scaling / scale_adjust); - CHA += (int)(CHA * scaling / scale_adjust); - if (MR) - MR += (int)(MR * scaling / scale_adjust); - if (CR) - CR += (int)(CR * scaling / scale_adjust); - if (DR) - DR += (int)(DR * scaling / scale_adjust); - if (FR) - FR += (int)(FR * scaling / scale_adjust); - if (PR) - PR += (int)(PR * scaling / scale_adjust); + cur_hp = max_hp; + max_dmg += (random_level - level) * 2; + } else { + uint8 scale_adjust = 1; + + base_hp += (int)(base_hp * scaling); + max_hp += (int)(max_hp * scaling); + cur_hp = max_hp; + + if (max_dmg) { + max_dmg += (int)(max_dmg * scaling / scale_adjust); + min_dmg += (int)(min_dmg * scaling / scale_adjust); + } + + STR += (int)(STR * scaling / scale_adjust); + STA += (int)(STA * scaling / scale_adjust); + AGI += (int)(AGI * scaling / scale_adjust); + DEX += (int)(DEX * scaling / scale_adjust); + INT += (int)(INT * scaling / scale_adjust); + WIS += (int)(WIS * scaling / scale_adjust); + CHA += (int)(CHA * scaling / scale_adjust); + if (MR) + MR += (int)(MR * scaling / scale_adjust); + if (CR) + CR += (int)(CR * scaling / scale_adjust); + if (DR) + DR += (int)(DR * scaling / scale_adjust); + if (FR) + FR += (int)(FR * scaling / scale_adjust); + if (PR) + PR += (int)(PR * scaling / scale_adjust); + } + } else { + // Compensate for scale rates at low levels so they don't add too much + uint8 scale_adjust = 1; + if(level > 0 && level <= 5) + scale_adjust = 10; + if(level > 5 && level <= 10) + scale_adjust = 5; + if(level > 10 && level <= 15) + scale_adjust = 3; + if(level > 15 && level <= 25) + scale_adjust = 2; + + base_hp += (int)(base_hp * scaling); + max_hp += (int)(max_hp * scaling); + cur_hp = max_hp; + STR += (int)(STR * scaling / scale_adjust); + STA += (int)(STA * scaling / scale_adjust); + AGI += (int)(AGI * scaling / scale_adjust); + DEX += (int)(DEX * scaling / scale_adjust); + INT += (int)(INT * scaling / scale_adjust); + WIS += (int)(WIS * scaling / scale_adjust); + CHA += (int)(CHA * scaling / scale_adjust); + if (MR) + MR += (int)(MR * scaling / scale_adjust); + if (CR) + CR += (int)(CR * scaling / scale_adjust); + if (DR) + DR += (int)(DR * scaling / scale_adjust); + if (FR) + FR += (int)(FR * scaling / scale_adjust); + if (PR) + PR += (int)(PR * scaling / scale_adjust); + + if (max_dmg) + { + max_dmg += (int)(max_dmg * scaling / scale_adjust); + min_dmg += (int)(min_dmg * scaling / scale_adjust); + } - if (max_dmg) - { - max_dmg += (int)(max_dmg * scaling / scale_adjust); - min_dmg += (int)(min_dmg * scaling / scale_adjust); } - level = random_level; return; @@ -2258,8 +2364,6 @@ bool NPC::CanTalk() 0,0,420,0,0,0,0,425,0,0,0,0,0,0,0,433,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,458,0,0,0,0,0,0,0,0,467,0,0,470,0,0,473}; - int talk_check = TalkRace[GetRace() - 1]; - if (TalkRace[GetRace() - 1] > 0) return true; @@ -2405,10 +2509,10 @@ void NPC::DoQuestPause(Mob *other) { } -void NPC::ChangeLastName(const char* in_lastname) +void NPC::ChangeLastName(const char* in_lastname) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct)); + auto outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct)); GMLastName_Struct* gmn = (GMLastName_Struct*)outapp->pBuffer; strcpy(gmn->name, GetName()); strcpy(gmn->gmname, GetName()); @@ -2455,9 +2559,9 @@ void NPC::DepopSwarmPets() } if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()){ - + Mob *targMob = entity_list.GetMob(GetPetTargetLockID()); - + if(!targMob || (targMob && targMob->IsCorpse())){ Kill(); return; diff --git a/zone/npc.h b/zone/npc.h index 95a857460..d3e7928a2 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -90,12 +90,17 @@ class Client; class Group; class Raid; class Spawn2; -struct Item_Struct; + +namespace EQEmu +{ + struct ItemBase; +} class NPC : public Mob { public: static NPC* SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client = nullptr); + static bool SpawnZoneController(); static int8 GetAILevel(bool iForceReRead = false); NPC(const NPCType* data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false); @@ -103,10 +108,10 @@ public: virtual ~NPC(); //abstract virtual function implementations requird by base abstract class - virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill); - virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false); - virtual bool Attack(Mob* other, int Hand = MainPrimary, bool FromRiposte = false, bool IsStrikethrough = false, - bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr); + virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill); + virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, int special = 0); + virtual bool Attack(Mob* other, int Hand = EQEmu::legacy::SlotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, + bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr, int special = 0); virtual bool HasRaid() { return false; } virtual bool HasGroup() { return false; } virtual Raid* GetRaid() { return 0; } @@ -119,6 +124,7 @@ public: virtual void AI_Start(uint32 iMoveDelay = 0); virtual void AI_Stop(); void AI_DoMovement(); + void AI_SetupNextWaypoint(); bool AI_AddNPCSpells(uint32 iDBSpellsID); bool AI_AddNPCSpellsEffects(uint32 iDBSpellsEffectsID); virtual bool AI_EngagedCastCheck(); @@ -136,7 +142,7 @@ public: void CalcNPCDamage(); virtual void SetTarget(Mob* mob); - virtual uint16 GetSkill(SkillUseTypes skill_num) const { if (skill_num <= HIGHEST_SKILL) { return skills[skill_num]; } return 0; } + virtual uint16 GetSkill(EQEmu::skills::SkillType skill_num) const { if (skill_num <= EQEmu::skills::HIGHEST_SKILL) { return skills[skill_num]; } return 0; } void CalcItemBonuses(StatBonuses *newbon); virtual void CalcBonuses(); @@ -155,7 +161,7 @@ public: virtual void RangedAttack(Mob* other); virtual void ThrowingAttack(Mob* other) { } int32 GetNumberOfAttacks() const { return attack_count; } - void DoRangedAttackDmg(Mob* other, bool Launch=true, int16 damage_mod=0, int16 chance_mod=0, SkillUseTypes skill=SkillArchery, float speed=4.0f, const char *IDFile = nullptr); + void DoRangedAttackDmg(Mob* other, bool Launch = true, int16 damage_mod = 0, int16 chance_mod = 0, EQEmu::skills::SkillType skill = EQEmu::skills::SkillArchery, float speed = 4.0f, const char *IDFile = nullptr); bool DatabaseCastAccepted(int spell_id); bool IsFactionListAlly(uint32 other_faction); @@ -163,7 +169,7 @@ public: virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther); void GoToBind(uint8 bindnum = 0) { GMMove(m_SpawnPoint.x, m_SpawnPoint.y, m_SpawnPoint.z, m_SpawnPoint.w); } - void Gate(); + void Gate(uint8 bindnum = 0); void GetPetState(SpellBuff_Struct *buffs, uint32 *items, char *name); void SetPetState(SpellBuff_Struct *buffs, uint32 *items); @@ -172,7 +178,7 @@ public: virtual void SpellProcess(); virtual void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho); - void AddItem(const Item_Struct* item, uint16 charges, bool equipitem = true); + void AddItem(const EQEmu::ItemBase* item, uint16 charges, bool equipitem = true); void AddItem(uint32 itemid, uint16 charges, bool equipitem = true); void AddLootTable(); void AddLootTable(uint32 ldid); @@ -264,7 +270,7 @@ public: bool IsTaunting() const { return taunting; } void PickPocket(Client* thief); void StartSwarmTimer(uint32 duration) { swarm_timer.Start(duration); } - void AddLootDrop(const Item_Struct*dbitem, ItemList* itemlistconst, int16 charges, uint8 minlevel, uint8 maxlevel, bool equipit, bool wearchange = false); + void AddLootDrop(const EQEmu::ItemBase*dbitem, ItemList* itemlistconst, int16 charges, uint8 minlevel, uint8 maxlevel, bool equipit, bool wearchange = false); virtual void DoClassAttacks(Mob *target); void CheckSignal(); inline bool IsNotTargetableWithHotkey() const { return no_target_hotkey; } @@ -397,15 +403,17 @@ public: void SetMerchantProbability(uint8 amt) { probability = amt; } uint8 GetMerchantProbability() { return probability; } void mod_prespawn(Spawn2 *sp); - int mod_npc_damage(int damage, SkillUseTypes skillinuse, int hand, const Item_Struct* weapon, Mob* other); + int mod_npc_damage(int damage, EQEmu::skills::SkillType skillinuse, int hand, const EQEmu::ItemBase* weapon, Mob* other); void mod_npc_killed_merit(Mob* c); void mod_npc_killed(Mob* oos); void AISpellsList(Client *c); + uint16 GetInnateProcSpellID() const { return innate_proc_spell_id; } uint32 GetHeroForgeModel() const { return herosforgemodel; } void SetHeroForgeModel(uint32 model) { herosforgemodel = model; } bool IsRaidTarget() const { return raid_target; }; + void ResetHPUpdateTimer() { sendhpupdate_timer.Start(); } protected: @@ -447,6 +455,7 @@ protected: virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0); AISpellsVar_Struct AISpellVar; int16 GetFocusEffect(focusType type, uint16 spell_id); + uint16 innate_proc_spell_id; uint32 npc_spells_effects_id; std::vector AIspellsEffects; @@ -490,9 +499,9 @@ protected: uint32 roambox_delay; uint32 roambox_min_delay; - uint16 skills[HIGHEST_SKILL+1]; + uint16 skills[EQEmu::skills::HIGHEST_SKILL + 1]; - uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs + uint32 equipment[EQEmu::legacy::EQUIPMENT_SIZE]; //this is an array of item IDs uint32 herosforgemodel; //this is the Hero Forge Armor Model (i.e 63 or 84 or 203) uint16 d_melee_texture1; //this is an item Material value diff --git a/zone/object.cpp b/zone/object.cpp index 7dd97d355..f74d2dd0d 100644 --- a/zone/object.cpp +++ b/zone/object.cpp @@ -117,7 +117,7 @@ Object::Object(Client* client, const ItemInst* inst) m_data.heading = client->GetHeading(); m_data.x = client->GetX(); m_data.y = client->GetY(); - if (client->GetClientVersion() >= ClientVersion::RoF2) + if (client->ClientVersion() >= EQEmu::versions::ClientVersion::RoF2) { // RoF2 places items at player's Z, which is 0.625 of their height. m_data.z = client->GetZ() - (client->GetSize() * 0.625f); @@ -138,7 +138,7 @@ Object::Object(Client* client, const ItemInst* inst) // Set object name if (inst) { - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); if (item && item->IDFile) { if (strlen(item->IDFile) == 0) { strcpy(m_data.object_name, DEFAULT_OBJECT_NAME); @@ -194,7 +194,7 @@ Object::Object(const ItemInst *inst, float x, float y, float z, float heading, u // Set object name if (inst) { - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); if (item && item->IDFile) { if (strlen(item->IDFile) == 0) { strcpy(m_data.object_name, DEFAULT_OBJECT_NAME); @@ -324,7 +324,7 @@ void Object::Delete(bool reset_state) } const ItemInst* Object::GetItem(uint8 index) { - if (index < EmuConstants::MAP_WORLD_SIZE) { + if (index < EQEmu::legacy::TYPE_WORLD_SIZE) { return m_inst->GetItem(index); } @@ -339,7 +339,7 @@ void Object::PutItem(uint8 index, const ItemInst* inst) return; } - if (m_inst && m_inst->IsType(ItemClassContainer)) { + if (m_inst && m_inst->IsType(EQEmu::item::ItemClassBag)) { if (inst) { m_inst->PutItem(index, *inst); } @@ -362,7 +362,7 @@ void Object::Close() { ItemInst* container = this->m_inst; if(container != nullptr) { - for (uint8 i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) + for (uint8 i = SUB_INDEX_BEGIN; i < EQEmu::legacy::ITEM_CONTAINER_SIZE; i++) { ItemInst* inst = container->PopItem(i); if(inst != nullptr) @@ -380,7 +380,7 @@ void Object::Close() { // Remove item from container void Object::DeleteItem(uint8 index) { - if (m_inst && m_inst->IsType(ItemClassContainer)) { + if (m_inst && m_inst->IsType(EQEmu::item::ItemClassBag)) { m_inst->DeleteItem(index); // This is _highly_ inefficient, but for now it will work: Save entire object to database @@ -393,7 +393,7 @@ ItemInst* Object::PopItem(uint8 index) { ItemInst* inst = nullptr; - if (m_inst && m_inst->IsType(ItemClassContainer)) { + if (m_inst && m_inst->IsType(EQEmu::item::ItemClassBag)) { inst = m_inst->PopItem(index); // This is _highly_ inefficient, but for now it will work: Save entire object to database @@ -425,7 +425,7 @@ void Object::CreateDeSpawnPacket(EQApplicationPacket* app) bool Object::Process(){ if(m_type == OT_DROPPEDITEM && decay_timer.Enabled() && decay_timer.Check()) { // Send click to all clients (removes entity on client) - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClickObject, sizeof(ClickObject_Struct)); + auto outapp = new EQApplicationPacket(OP_ClickObject, sizeof(ClickObject_Struct)); ClickObject_Struct* click_object = (ClickObject_Struct*)outapp->pBuffer; click_object->drop_id = GetID(); entity_list.QueueClients(nullptr, outapp, false); @@ -485,14 +485,29 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object) buf[9] = '\0'; std::vector args; args.push_back(m_inst); - parse->EventPlayer(EVENT_PLAYER_PICKUP, sender, buf, 0, &args); + if(parse->EventPlayer(EVENT_PLAYER_PICKUP, sender, buf, this->GetID(), &args)) + { + auto outapp = new EQApplicationPacket(OP_ClickObject, sizeof(ClickObject_Struct)); + memcpy(outapp->pBuffer, click_object, sizeof(ClickObject_Struct)); + ClickObject_Struct* co = (ClickObject_Struct*)outapp->pBuffer; + co->drop_id = 0; + entity_list.QueueClients(nullptr, outapp, false); + safe_delete(outapp); + + // No longer using a tradeskill object + sender->SetTradeskillObject(nullptr); + user = nullptr; + + return true; + } + // Transfer item to client - sender->PutItemInInventory(MainCursor, *m_inst, false); - sender->SendItemPacket(MainCursor, m_inst, ItemPacketTrade); + sender->PutItemInInventory(EQEmu::legacy::SlotCursor, *m_inst, false); + sender->SendItemPacket(EQEmu::legacy::SlotCursor, m_inst, ItemPacketTrade); if(cursordelete) // delete the item if it's a duplicate lore. We have to do this because the client expects the item packet - sender->DeleteItemInInventory(MainCursor); + sender->DeleteItemInInventory(EQEmu::legacy::SlotCursor); if(!m_ground_spawn) safe_delete(m_inst); @@ -503,7 +518,7 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object) } // Send click to all clients (removes entity on client) - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClickObject, sizeof(ClickObject_Struct)); + auto outapp = new EQApplicationPacket(OP_ClickObject, sizeof(ClickObject_Struct)); memcpy(outapp->pBuffer, click_object, sizeof(ClickObject_Struct)); entity_list.QueueClients(nullptr, outapp, false); safe_delete(outapp); @@ -514,24 +529,30 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object) entity_list.RemoveEntity(this->GetID()); } else { // Tradeskill item - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClickObjectAction, sizeof(ClickObjectAction_Struct)); + auto outapp = new EQApplicationPacket(OP_ClickObjectAction, sizeof(ClickObjectAction_Struct)); ClickObjectAction_Struct* coa = (ClickObjectAction_Struct*)outapp->pBuffer; //TODO: there is prolly a better way to do this. - //if this is not the main user, send them a close and a message - if(user == nullptr || user == sender) - coa->open = 0x01; - else { - coa->open = 0x00; - //sender->Message(13, "Somebody is allready using that container."); - } - m_inuse = true; - coa->type = m_type; - coa->unknown16 = 0x0a; + m_inuse = true; + coa->type = m_type; + coa->unknown16 = 0x0a; - coa->drop_id = click_object->drop_id; - coa->player_id = click_object->player_id; - coa->icon = m_icon; + coa->drop_id = click_object->drop_id; + coa->player_id = click_object->player_id; + coa->icon = m_icon; + + //if this is not the main user, send them a close and a message + if (user == nullptr || user == sender) { + coa->open = 0x01; + } + else { + coa->open = 0x00; + + if (sender->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { + coa->drop_id = 0xFFFFFFFF; + sender->Message(0, "Someone else is using that. Try again later."); + } + } if(sender->IsLooting()) { @@ -553,16 +574,16 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object) // Send items inside of container - if (m_inst && m_inst->IsType(ItemClassContainer)) { + if (m_inst && m_inst->IsType(EQEmu::item::ItemClassBag)) { //Clear out no-drop and no-rent items first if different player opens it if(user != last_user) m_inst->ClearByFlags(byFlagSet, byFlagSet); - EQApplicationPacket* outapp=new EQApplicationPacket(OP_ClientReady,0); + auto outapp = new EQApplicationPacket(OP_ClientReady, 0); sender->QueuePacket(outapp); safe_delete(outapp); - for (uint8 i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) { + for (uint8 i = SUB_INDEX_BEGIN; i < EQEmu::legacy::ITEM_CONTAINER_SIZE; i++) { const ItemInst* inst = m_inst->GetItem(i); if (inst) { //sender->GetInv().PutItem(i+4000,inst); @@ -589,7 +610,7 @@ uint32 ZoneDatabase::AddObject(uint32 type, uint32 icon, const Object_Struct& ob // SQL Escape object_name uint32 len = strlen(object.object_name) * 2 + 1; - char* object_name = new char[len]; + auto object_name = new char[len]; DoEscapeString(object_name, object.object_name, strlen(object.object_name)); // Save new record for object @@ -607,7 +628,7 @@ uint32 ZoneDatabase::AddObject(uint32 type, uint32 icon, const Object_Struct& ob } // Save container contents, if container - if (inst && inst->IsType(ItemClassContainer)) + if (inst && inst->IsType(EQEmu::item::ItemClassBag)) SaveWorldContainer(object.zone_id, database_id, inst); return database_id; @@ -626,7 +647,7 @@ void ZoneDatabase::UpdateObject(uint32 id, uint32 type, uint32 icon, const Objec // SQL Escape object_name uint32 len = strlen(object.object_name) * 2 + 1; - char* object_name = new char[len]; + auto object_name = new char[len]; DoEscapeString(object_name, object.object_name, strlen(object.object_name)); // Save new record for object @@ -644,7 +665,7 @@ void ZoneDatabase::UpdateObject(uint32 id, uint32 type, uint32 icon, const Objec } // Save container contents, if container - if (inst && inst->IsType(ItemClassContainer)) + if (inst && inst->IsType(EQEmu::item::ItemClassBag)) SaveWorldContainer(object.zone_id, id, inst); } @@ -733,8 +754,8 @@ void Object::SetX(float pos) { this->m_data.x = pos; - EQApplicationPacket* app = new EQApplicationPacket(); - EQApplicationPacket* app2 = new EQApplicationPacket(); + auto app = new EQApplicationPacket(); + auto app2 = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); this->CreateSpawnPacket(app2); entity_list.QueueClients(0, app); @@ -747,8 +768,8 @@ void Object::SetY(float pos) { this->m_data.y = pos; - EQApplicationPacket* app = new EQApplicationPacket(); - EQApplicationPacket* app2 = new EQApplicationPacket(); + auto app = new EQApplicationPacket(); + auto app2 = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); this->CreateSpawnPacket(app2); entity_list.QueueClients(0, app); @@ -759,7 +780,7 @@ void Object::SetY(float pos) void Object::Depop() { - EQApplicationPacket* app = new EQApplicationPacket(); + auto app = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); entity_list.QueueClients(0, app); safe_delete(app); @@ -768,8 +789,8 @@ void Object::Depop() void Object::Repop() { - EQApplicationPacket* app = new EQApplicationPacket(); - EQApplicationPacket* app2 = new EQApplicationPacket(); + auto app = new EQApplicationPacket(); + auto app2 = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); this->CreateSpawnPacket(app2); entity_list.QueueClients(0, app); @@ -784,8 +805,8 @@ void Object::SetZ(float pos) { this->m_data.z = pos; - EQApplicationPacket* app = new EQApplicationPacket(); - EQApplicationPacket* app2 = new EQApplicationPacket(); + auto app = new EQApplicationPacket(); + auto app2 = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); this->CreateSpawnPacket(app2); entity_list.QueueClients(0, app); @@ -797,8 +818,8 @@ void Object::SetZ(float pos) void Object::SetModelName(const char* modelname) { strn0cpy(m_data.object_name, modelname, sizeof(m_data.object_name)); // 32 is the max for chars in object_name, this should be safe - EQApplicationPacket* app = new EQApplicationPacket(); - EQApplicationPacket* app2 = new EQApplicationPacket(); + auto app = new EQApplicationPacket(); + auto app2 = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); this->CreateSpawnPacket(app2); entity_list.QueueClients(0, app); @@ -809,9 +830,9 @@ void Object::SetModelName(const char* modelname) void Object::SetSize(uint16 size) { - m_data.unknown008 = size; - EQApplicationPacket* app = new EQApplicationPacket(); - EQApplicationPacket* app2 = new EQApplicationPacket(); + m_data.size = size; + auto app = new EQApplicationPacket(); + auto app2 = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); this->CreateSpawnPacket(app2); entity_list.QueueClients(0, app); @@ -822,9 +843,9 @@ void Object::SetSize(uint16 size) void Object::SetSolidType(uint16 solidtype) { - m_data.unknown010 = solidtype; - EQApplicationPacket* app = new EQApplicationPacket(); - EQApplicationPacket* app2 = new EQApplicationPacket(); + m_data.solidtype = solidtype; + auto app = new EQApplicationPacket(); + auto app2 = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); this->CreateSpawnPacket(app2); entity_list.QueueClients(0, app); @@ -835,12 +856,12 @@ void Object::SetSolidType(uint16 solidtype) uint16 Object::GetSize() { - return m_data.unknown008; + return m_data.size; } uint16 Object::GetSolidType() { - return m_data.unknown010; + return m_data.solidtype; } const char* Object::GetModelName() @@ -860,7 +881,7 @@ uint32 Object::GetItemID() return 0; } - const Item_Struct* item = this->m_inst->GetItem(); + const EQEmu::ItemBase* item = this->m_inst->GetItem(); if (item == 0) { @@ -919,8 +940,8 @@ void Object::SetLocation(float x, float y, float z) this->m_data.x = x; this->m_data.y = y; this->m_data.z = z; - EQApplicationPacket* app = new EQApplicationPacket(); - EQApplicationPacket* app2 = new EQApplicationPacket(); + auto app = new EQApplicationPacket(); + auto app2 = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); this->CreateSpawnPacket(app2); entity_list.QueueClients(0, app); @@ -940,8 +961,8 @@ void Object::GetHeading(float* heading) void Object::SetHeading(float heading) { this->m_data.heading = heading; - EQApplicationPacket* app = new EQApplicationPacket(); - EQApplicationPacket* app2 = new EQApplicationPacket(); + auto app = new EQApplicationPacket(); + auto app2 = new EQApplicationPacket(); this->CreateDeSpawnPacket(app); this->CreateSpawnPacket(app2); entity_list.QueueClients(0, app); @@ -961,7 +982,7 @@ const char* Object::GetEntityVariable(const char *id) if(!id) return nullptr; - std::map::iterator iter = o_EntityVariables.find(id); + auto iter = o_EntityVariables.find(id); if(iter != o_EntityVariables.end()) { return iter->second.c_str(); @@ -974,7 +995,7 @@ bool Object::EntityVariableExists(const char * id) if(!id) return false; - std::map::iterator iter = o_EntityVariables.find(id); + auto iter = o_EntityVariables.find(id); if(iter != o_EntityVariables.end()) { return true; diff --git a/zone/object.h b/zone/object.h index 9e8fae05d..c7ebdd677 100644 --- a/zone/object.h +++ b/zone/object.h @@ -69,7 +69,7 @@ IT10714_ACTORDEF=Augmentation Sealer IT10725_ACTORDEF=Shuriken */ -#define OT_DROPPEDITEM BagTypeLargeBag +#define OT_DROPPEDITEM EQEmu::item::BagTypeLargeBag // Icon values: //0x0453 a pie @@ -108,7 +108,7 @@ public: static void HandleAugmentation(Client* user, const AugmentItem_Struct* in_augment, Object *worldo); static void HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac); - static SkillUseTypes TypeToSkill(uint32 type); + static EQEmu::skills::SkillType TypeToSkill(uint32 type); // Packet functions void CreateSpawnPacket(EQApplicationPacket* app); diff --git a/zone/oldcode.cpp b/zone/oldcode.cpp index 075923360..600e8ad5c 100644 --- a/zone/oldcode.cpp +++ b/zone/oldcode.cpp @@ -1082,11 +1082,11 @@ int32 Client::GenericFocus(uint16 spell_id, uint16 modspellid) switch( spells[modspellid].effectid[i] ) { case SE_LimitMaxLevel: - if (spell.classes[(GetClass()%16) - 1] > modspell.base[i]) + if (spell.classes[(GetClass()%17) - 1] > modspell.base[i]) return 100; break; case SE_LimitMinLevel: - if (spell.classes[(GetClass()%16) - 1] < modspell.base[i]) + if (spell.classes[(GetClass()%17) - 1] < modspell.base[i]) return 100; break; case SE_IncreaseRange: diff --git a/zone/pathing.cpp b/zone/pathing.cpp index e01cb6916..16b340d94 100644 --- a/zone/pathing.cpp +++ b/zone/pathing.cpp @@ -16,7 +16,7 @@ #define snprintf _snprintf #endif -//#define PATHDEBUG +//#define PATHDEBUG extern Zone *zone; @@ -52,7 +52,7 @@ PathManager* PathManager::LoadPathFile(const char* ZoneName) strlwr(LowerCaseZoneName); - snprintf(ZonePathFileName, 250, MAP_DIR "/%s.path", LowerCaseZoneName); + snprintf(ZonePathFileName, 250, "%s%s.path", Config->MapDir.c_str(), LowerCaseZoneName); if((PathFile = fopen(ZonePathFileName, "rb"))) { @@ -205,10 +205,10 @@ glm::vec3 PathManager::GetPathNodeCoordinates(int NodeNumber, bool BestZ) } std::deque PathManager::FindRoute(int startID, int endID) -{ +{ Log.Out(Logs::Detail, Logs::None, "FindRoute from node %i to %i", startID, endID); - memset(ClosedListFlag, 0, sizeof(int) * Head.PathNodeCount); + memset(ClosedListFlag, 0, sizeof(int) * Head.PathNodeCount); std::deque OpenList, ClosedList; @@ -224,7 +224,7 @@ std::deque PathManager::FindRoute(int startID, int endID) OpenList.push_back(AStarEntry); - while(OpenList.size() > 0) + while(!OpenList.empty()) { // The OpenList is maintained in sorted order, lowest to highest cost. @@ -546,7 +546,7 @@ void PathManager::SpawnPathNodes() for(uint32 i = 0; i < Head.PathNodeCount; ++i) { - NPCType* npc_type = new NPCType; + auto npc_type = new NPCType; memset(npc_type, 0, sizeof(NPCType)); if(PathNodes[i].id < 10) @@ -585,10 +585,10 @@ void PathManager::SpawnPathNodes() npc_type->findable = 1; auto position = glm::vec4(PathNodes[i].v.x, PathNodes[i].v.y, PathNodes[i].v.z, 0.0f); - NPC* npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); + auto npc = new NPC(npc_type, nullptr, position, FlyMode1); + npc->GiveNPCTypeData(npc_type); - entity_list.AddNPC(npc, true, true); + entity_list.AddNPC(npc, true, true); } } @@ -610,7 +610,7 @@ void PathManager::MeshTest() std::deque Route = FindRoute(PathNodes[i].id, PathNodes[j].id); - if(Route.size() == 0) + if(Route.empty()) { ++NoConnections; printf("FindRoute(%i, %i) **** NO ROUTE FOUND ****\n", PathNodes[i].id, PathNodes[j].id); @@ -637,7 +637,7 @@ void PathManager::SimpleMeshTest() { std::deque Route = FindRoute(PathNodes[0].id, PathNodes[j].id); - if(Route.size() == 0) + if(Route.empty()) { ++NoConnections; printf("FindRoute(%i, %i) **** NO ROUTE FOUND ****\n", PathNodes[0].id, PathNodes[j].id); @@ -665,6 +665,9 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa bool SameDestination = (To == PathingDestination); + if (Speed <= 0) // our speed is 0, we cant move so lets return the dest + return To; // this will also avoid the teleports cleanly + int NextNode; if(To == From) @@ -680,7 +683,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa { Log.Out(Logs::Detail, Logs::None, "appears to be stuck. Teleporting them to next position.", GetName()); - if(Route.size() == 0) + if(Route.empty()) { Teleport(To); @@ -712,7 +715,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa PathingLastPosition = From; } - if(Route.size() > 0) + if(!Route.empty()) { // If we are already pathing, and the destination is the same as before ... @@ -787,7 +790,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa WaypointChanged = true; // If there are more nodes on the route, return the coords of the next node - if(Route.size() > 0) + if(!Route.empty()) { NextNode = Route.front(); @@ -796,7 +799,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa // -1 indicates a teleport to the next node Route.pop_front(); - if(Route.size() == 0) + if(Route.empty()) { Log.Out(Logs::Detail, Logs::None, "Missing node after teleport."); return To; @@ -812,7 +815,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa Route.pop_front(); - if(Route.size() == 0) + if(Route.empty()) return To; NextNode = Route.front(); @@ -962,7 +965,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa WaypointChanged = true; - if(Route.size() > 0) + if(!Route.empty()) { NextNode = Route.front(); @@ -971,7 +974,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa // -1 indicates a teleport to the next node Route.pop_front(); - if(Route.size() == 0) + if(Route.empty()) { Log.Out(Logs::Detail, Logs::None, "Missing node after teleport."); return To; @@ -987,7 +990,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa Route.pop_front(); - if(Route.size() == 0) + if(Route.empty()) return To; NextNode = Route.front(); @@ -1058,7 +1061,7 @@ glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &Wa PathingTraversedNodes = 0; - if(Route.size() == 0) + if(Route.empty()) { Log.Out(Logs::Detail, Logs::None, " No route available, running direct."); @@ -1308,7 +1311,7 @@ void Client::SendPathPacket(std::vector &points) { } int len = sizeof(FindPersonResult_Struct) + (points.size()+1) * sizeof(FindPerson_Point); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_FindPersonReply, len); + auto outapp = new EQApplicationPacket(OP_FindPersonReply, len); FindPersonResult_Struct* fpr=(FindPersonResult_Struct*)outapp->pBuffer; std::vector::iterator cur, end; @@ -1478,6 +1481,11 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques { for(uint32 i = 0; i < Head.PathNodeCount; ++i) { + if(PathNodes[i].id - new_id > 1) { + new_id = PathNodes[i].id - 1; + break; + } + if(PathNodes[i].id > new_id) new_id = PathNodes[i].id; } @@ -1501,7 +1509,7 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques Head.PathNodeCount++; if(Head.PathNodeCount > 1) { - PathNode *t_PathNodes = new PathNode[Head.PathNodeCount]; + auto t_PathNodes = new PathNode[Head.PathNodeCount]; for(uint32 x = 0; x < (Head.PathNodeCount - 1); ++x) { t_PathNodes[x].v.x = PathNodes[x].v.x; @@ -1536,7 +1544,7 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques delete[] PathNodes; PathNodes = t_PathNodes; - NPCType* npc_type = new NPCType; + auto npc_type = new NPCType; memset(npc_type, 0, sizeof(NPCType)); if(new_id < 10) sprintf(npc_type->name, "%s", DigitToWord(new_id)); @@ -1573,13 +1581,13 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques npc_type->findable = 1; auto position = glm::vec4(new_node.v.x, new_node.v.y, new_node.v.z, 0.0f); - NPC* npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); - entity_list.AddNPC(npc, true, true); + auto npc = new NPC(npc_type, nullptr, position, FlyMode1); + npc->GiveNPCTypeData(npc_type); + entity_list.AddNPC(npc, true, true); - safe_delete_array(ClosedListFlag); - ClosedListFlag = new int[Head.PathNodeCount]; - return new_id; + safe_delete_array(ClosedListFlag); + ClosedListFlag = new int[Head.PathNodeCount]; + return new_id; } else { @@ -1597,7 +1605,7 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques PathNodes[0].Neighbours[n].Teleport = new_node.Neighbours[n].Teleport; } - NPCType* npc_type = new NPCType; + auto npc_type = new NPCType; memset(npc_type, 0, sizeof(NPCType)); if(new_id < 10) sprintf(npc_type->name, "%s", DigitToWord(new_id)); @@ -1634,13 +1642,13 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques npc_type->findable = 1; auto position = glm::vec4(new_node.v.x, new_node.v.y, new_node.v.z, 0.0f); - NPC* npc = new NPC(npc_type, nullptr, position, FlyMode1); - npc->GiveNPCTypeData(npc_type); - entity_list.AddNPC(npc, true, true); + auto npc = new NPC(npc_type, nullptr, position, FlyMode1); + npc->GiveNPCTypeData(npc_type); + entity_list.AddNPC(npc, true, true); - ClosedListFlag = new int[Head.PathNodeCount]; + ClosedListFlag = new int[Head.PathNodeCount]; - return new_id; + return new_id; } } @@ -1676,7 +1684,7 @@ bool PathManager::DeleteNode(int32 id) if(Head.PathNodeCount > 1) { - PathNode *t_PathNodes = new PathNode[Head.PathNodeCount-1]; + auto t_PathNodes = new PathNode[Head.PathNodeCount - 1]; uint32 index = 0; for(uint32 x = 0; x < Head.PathNodeCount; x++) { @@ -2225,7 +2233,7 @@ void PathManager::SortNodes() sorted_vals.push_back(tmp); } - PathNode *t_PathNodes = new PathNode[Head.PathNodeCount]; + auto t_PathNodes = new PathNode[Head.PathNodeCount]; memcpy(t_PathNodes, PathNodes, sizeof(PathNode)*Head.PathNodeCount); for(uint32 i = 0; i < Head.PathNodeCount; ++i) { diff --git a/zone/pathing.h b/zone/pathing.h index c6cfd9c26..d65ebfdcf 100644 --- a/zone/pathing.h +++ b/zone/pathing.h @@ -2,9 +2,11 @@ #define PATHING_H #include "map.h" - +#include "zone_config.h" #include +extern const ZoneConfig *Config; + class Client; class Mob; diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index d399d7665..76c085714 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -1072,7 +1072,7 @@ XS(XS_Client_SetBindPoint) new_z = (float)SvNV(ST(5)); } - THIS->SetBindPoint(to_zone, to_instance, glm::vec3(new_x, new_y, new_z)); + THIS->SetBindPoint(0, to_zone, to_instance, glm::vec3(new_x, new_y, new_z)); } XSRETURN_EMPTY; } @@ -1940,7 +1940,7 @@ XS(XS_Client_GetSkill) Client * THIS; uint16 RETVAL; dXSTARG; - SkillUseTypes skill_id = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skill_id = (EQEmu::skills::SkillType)SvUV(ST(1)); if (sv_derived_from(ST(0), "Client")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -1967,7 +1967,7 @@ XS(XS_Client_GetRawSkill) Client * THIS; uint32 RETVAL; dXSTARG; - SkillUseTypes skill_id = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skill_id = (EQEmu::skills::SkillType)SvUV(ST(1)); if (sv_derived_from(ST(0), "Client")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -1993,7 +1993,7 @@ XS(XS_Client_HasSkill) { Client * THIS; bool RETVAL; - SkillUseTypes skill_id = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skill_id = (EQEmu::skills::SkillType)SvUV(ST(1)); if (sv_derived_from(ST(0), "Client")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -2020,7 +2020,7 @@ XS(XS_Client_CanHaveSkill) { Client * THIS; bool RETVAL; - SkillUseTypes skill_id = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skill_id = (EQEmu::skills::SkillType)SvUV(ST(1)); if (sv_derived_from(ST(0), "Client")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -2046,7 +2046,7 @@ XS(XS_Client_SetSkill) Perl_croak(aTHX_ "Usage: Client::SetSkill(THIS, skill_num, value)"); { Client * THIS; - SkillUseTypes skill_num = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skill_num = (EQEmu::skills::SkillType)SvUV(ST(1)); uint16 value = (uint16)SvUV(ST(2)); if (sv_derived_from(ST(0), "Client")) { @@ -2071,7 +2071,7 @@ XS(XS_Client_AddSkill) Perl_croak(aTHX_ "Usage: Client::AddSkill(THIS, skillid, value)"); { Client * THIS; - SkillUseTypes skillid = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skillid = (EQEmu::skills::SkillType)SvUV(ST(1)); uint16 value = (uint16)SvUV(ST(2)); if (sv_derived_from(ST(0), "Client")) { @@ -2121,7 +2121,7 @@ XS(XS_Client_CheckIncreaseSkill) { Client * THIS; bool RETVAL; - SkillUseTypes skillid = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skillid = (EQEmu::skills::SkillType)SvUV(ST(1)); int chancemodi; if (sv_derived_from(ST(0), "Client")) { @@ -2180,7 +2180,7 @@ XS(XS_Client_MaxSkill) { Client * THIS; uint16 RETVAL; - SkillUseTypes skillid = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skillid = (EQEmu::skills::SkillType)SvUV(ST(1)); uint16 class_ = 0; uint16 level = 0; dXSTARG; @@ -2445,6 +2445,30 @@ XS(XS_Client_UnmemSpell) XSRETURN_EMPTY; } +XS(XS_Client_UnmemSpellBySpellID); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_UnmemSpellBySpellID) +{ + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Client::UnmemSpellBySpellID(THIS, spell_id)"); + { + Client * THIS; + int32 spell_id = (int32)SvIV(ST(1)); + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + THIS->UnmemSpellBySpellID(spell_id); + } + XSRETURN_EMPTY; +} + XS(XS_Client_UnmemSpellAll); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_UnmemSpellAll) { @@ -2568,6 +2592,57 @@ XS(XS_Client_UnscribeSpellAll) XSRETURN_EMPTY; } +XS(XS_Client_TrainDiscBySpellID); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_TrainDiscBySpellID) +{ + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Client::TrainDiscBySpellID(THIS, spell_id)"); + { + Client * THIS; + int32 spell_id = (int32)SvIV(ST(1)); + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + THIS->TrainDiscBySpellID(spell_id); + } + XSRETURN_EMPTY; +} + +XS(XS_Client_GetDiscSlotBySpellID); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_GetDiscSlotBySpellID) +{ + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Client::GetDiscSlotBySpellID(THIS, spell_id)"); + { + Client * THIS; + int RETVAL; + int32 spell_id = (int32)SvIV(ST(1)); + dXSTARG; + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetDiscSlotBySpellID(spell_id); + XSprePUSH; PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + XS(XS_Client_UntrainDisc); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_UntrainDisc) { @@ -3899,7 +3974,7 @@ XS(XS_Client_GetClientVersion) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = static_cast(THIS->GetClientVersion()); + RETVAL = static_cast(THIS->ClientVersion()); XSprePUSH; PUSHu((UV)RETVAL); } XSRETURN(1); @@ -3925,7 +4000,7 @@ XS(XS_Client_GetClientVersionBit) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->GetClientVersionBit(); + RETVAL = THIS->ClientVersionBit(); XSprePUSH; PUSHu((UV)RETVAL); } XSRETURN(1); @@ -4077,33 +4152,7 @@ XS(XS_Client_RefundAA) { if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - int curpt = 0; - bool refunded = false; - - for(int x1=0;x1GetAA(x1); - if(curpt > 0){ - SendAA_Struct* curaa = zone->FindAA(x1); - if(curaa){ - THIS->SetAA(x1, 0); - for(int x2=0;x2GetPP().aapoints += curaa->cost + (curaa->cost_inc * x2); - refunded = true; - } - } - else //aa doesn't exist.. but if they bought it then it had at least a cost of 1 point each - { //so give back what we can - THIS->GetPP().aapoints += curpt; - THIS->SetAA(x1, 0); - refunded = true; - } - } - } - - if(refunded){ - THIS->Save(); //save of course - THIS->Kick(); //client gets all buggy if we don't immediatly relog so just force it on them - } + THIS->RefundAA(); } XSRETURN_EMPTY; } @@ -4915,11 +4964,44 @@ XS(XS_Client_IncrementAA) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - THIS->IncrementAA(aaskillid); + THIS->IncrementAlternateAdvancementRank(aaskillid); } XSRETURN_EMPTY; } +XS(XS_Client_GrantAlternateAdvancementAbility); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_GrantAlternateAdvancementAbility) +{ + dXSARGS; + if(items < 3 || items > 4) + Perl_croak(aTHX_ "Usage: Client::GrantAlternateAdvancementAbility(THIS, aa_id, points, [ignore_cost])"); + { + Client * THIS; + bool RETVAL; + int aa_id = (int)SvIV(ST(1)); + int points = (int)SvIV(ST(2)); + bool ignore_cost = false; + + if(sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + if(items > 3) { + ignore_cost = (bool)SvTRUE(ST(3)); + } + + RETVAL = THIS->GrantAlternateAdvancementAbility(aa_id, points, ignore_cost); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + XS(XS_Client_GetAALevel); XS(XS_Client_GetAALevel) { @@ -5119,13 +5201,20 @@ XS(XS_Client_AssignTask); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_AssignTask) { dXSARGS; - if (items != 3) - Perl_croak(aTHX_ "Usage: Client::AssignTask(THIS, TaskID, NPCID)"); + if (items != 3 && items != 4) + Perl_croak(aTHX_ "Usage: Client::AssignTask(THIS, TaskID, NPCID, enforce_level_requirement)"); { Client * THIS; int TaskID = (int)SvIV(ST(1)); int NPCID = (int)SvIV(ST(2)); - + bool enforce_level_requirement = false; + if (items == 4) + { + if ((int)SvIV(ST(3)) == 1) + { + enforce_level_requirement = true; + } + } if (sv_derived_from(ST(0), "Client")) { IV tmp = SvIV((SV*)SvRV(ST(0))); THIS = INT2PTR(Client *,tmp); @@ -5135,7 +5224,7 @@ XS(XS_Client_AssignTask) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - THIS->AssignTask(TaskID, NPCID); + THIS->AssignTask(TaskID, NPCID, enforce_level_requirement); } XSRETURN_EMPTY; } @@ -6110,6 +6199,218 @@ XS(XS_Client_SendSpellAnim) XSRETURN_EMPTY; } +XS(XS_Client_GetTargetRingX); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_GetTargetRingX) +{ + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Client::GetTargetRingX(THIS)"); + { + Client * THIS; + float RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetTargetRingX(); + XSprePUSH; PUSHn((double)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Client_GetTargetRingY); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_GetTargetRingY) +{ + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Client::GetTargetRingY(THIS)"); + { + Client * THIS; + float RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetTargetRingY(); + XSprePUSH; PUSHn((double)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Client_GetTargetRingZ); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_GetTargetRingZ) +{ + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Client::GetTargetRingZ(THIS)"); + { + Client * THIS; + float RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetTargetRingZ(); + XSprePUSH; PUSHn((double)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Client_CalcEXP); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_CalcEXP) +{ + dXSARGS; + if (items < 1 || items > 2) + Perl_croak(aTHX_ "Usage: CalcEXP(THIS, uint8 conlevel)"); + { + Client * THIS; + uint8 conlevel = 0xFF; + uint32 RETVAL; + if(items == 2) + conlevel = (uint16)SvUV(ST(1)); + dXSTARG; + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + if(THIS == NULL) + Perl_croak(aTHX_ "THIS is NULL, avoiding crash."); + + RETVAL = THIS->CalcEXP(conlevel); + XSprePUSH; PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Client_QuestReward); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Client_QuestReward) +{ + dXSARGS; + if (items < 1 || items > 9) + Perl_croak(aTHX_ "Usage: Client::QuestReward(THIS, mob, copper, silver, gold, platinum, itemid, exp, faction)"); + { + Client* THIS; + Mob * mob = nullptr; + int32 copper = 0; + int32 silver = 0; + int32 gold = 0; + int32 platinum = 0; + int32 itemid = 0; + int32 exp = 0; + bool faction = false; + + if (sv_derived_from(ST(0), "THIS")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type client"); + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + if (items > 1) { + if (sv_derived_from(ST(1), "mob")) { + IV tmp = SvIV((SV*)SvRV(ST(1))); + mob = INT2PTR(Mob *, tmp); + } + else + Perl_croak(aTHX_ "mob is not of type Mob"); + if (mob == nullptr) + Perl_croak(aTHX_ "mob is nullptr, avoiding crash."); + } + if (items > 2) { copper = (int32)SvIV(ST(2)); } + if (items > 3) { silver = (int32)SvIV(ST(3)); } + if (items > 4) { gold = (int32)SvIV(ST(4)); } + if (items > 5) { platinum = (int32)SvIV(ST(5)); } + if (items > 6) { itemid = (int32)SvIV(ST(6)); } + if (items > 7) { exp = (int32)SvIV(ST(7)); } + if (items > 8) { faction = (bool)SvIV(ST(8)); } + + THIS->QuestReward(mob, copper, silver, gold, platinum, itemid, exp, faction); + } + XSRETURN_EMPTY; +} + +XS(XS_Client_GetMoney); +XS(XS_Client_GetMoney) +{ + dXSARGS; + if (items != 3) + Perl_croak(aTHX_ "Usage: GetMoney(THIS, type, subtype)"); + { + Client* THIS; + uint32 RETVAL; + uint8 type = (uint8)SvUV(ST(1)); + uint8 subtype = (uint8)SvUV(ST(2)); + dXSTARG; + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetMoney(type, subtype); + XSprePUSH; PUSHn((uint32)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Client_GetAccountAge); +XS(XS_Client_GetAccountAge) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: GetAccountAge(THIS)"); + { + Client* THIS; + int RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Client")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Client *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Client"); + + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetAccountAge(); + XSprePUSH; PUSHn((int)RETVAL); + } + XSRETURN(1); +} + + #ifdef __cplusplus extern "C" #endif @@ -6217,10 +6518,13 @@ XS(boot_Client) newXSproto(strcpy(buf, "ResetAA"), XS_Client_ResetAA, file, "$"); newXSproto(strcpy(buf, "MemSpell"), XS_Client_MemSpell, file, "$$$;$"); newXSproto(strcpy(buf, "UnmemSpell"), XS_Client_UnmemSpell, file, "$$;$"); + newXSproto(strcpy(buf, "UnmemSpellBySpellID"), XS_Client_UnmemSpellBySpellID, file, "$$"); newXSproto(strcpy(buf, "UnmemSpellAll"), XS_Client_UnmemSpellAll, file, "$;$"); newXSproto(strcpy(buf, "ScribeSpell"), XS_Client_ScribeSpell, file, "$$$;$"); newXSproto(strcpy(buf, "UnscribeSpell"), XS_Client_UnscribeSpell, file, "$$;$"); newXSproto(strcpy(buf, "UnscribeSpellAll"), XS_Client_UnscribeSpellAll, file, "$;$"); + newXSproto(strcpy(buf, "TrainDiscBySpellID"), XS_Client_TrainDiscBySpellID, file, "$$"); + newXSproto(strcpy(buf, "GetDiscSlotBySpellID"), XS_Client_GetDiscSlotBySpellID, file, "$$"); newXSproto(strcpy(buf, "UntrainDisc"), XS_Client_UntrainDisc, file, "$$;$"); newXSproto(strcpy(buf, "UntrainDiscAll"), XS_Client_UntrainDiscAll, file, "$;$"); newXSproto(strcpy(buf, "IsSitting"), XS_Client_IsSitting, file, "$"); @@ -6307,13 +6611,14 @@ XS(boot_Client) newXSproto(strcpy(buf, "GetIP"), XS_Client_GetIP, file, "$"); newXSproto(strcpy(buf, "AddLevelBasedExp"), XS_Client_AddLevelBasedExp, file, "$$;$"); newXSproto(strcpy(buf, "IncrementAA"), XS_Client_IncrementAA, file, "$$"); + newXSproto(strcpy(buf, "GrantAlternateAdvancementAbility"), XS_Client_GrantAlternateAdvancementAbility, file, "$$$;$"); newXSproto(strcpy(buf, "GetAALevel"), XS_Client_GetAALevel, file, "$$"); newXSproto(strcpy(buf, "MarkCompassLoc"), XS_Client_MarkCompassLoc, file, "$$$$"); newXSproto(strcpy(buf, "ClearCompassMark"), XS_Client_ClearCompassMark, file, "$"); newXSproto(strcpy(buf, "GetFreeSpellBookSlot"), XS_Client_GetFreeSpellBookSlot, file, "$;$"); newXSproto(strcpy(buf, "GetSpellBookSlotBySpellID"), XS_Client_GetSpellBookSlotBySpellID, file, "$$"); newXSproto(strcpy(buf, "UpdateTaskActivity"), XS_Client_UpdateTaskActivity, file, "$$$$;$"); - newXSproto(strcpy(buf, "AssignTask"), XS_Client_AssignTask, file, "$$$"); + newXSproto(strcpy(buf, "AssignTask"), XS_Client_AssignTask, file, "$$$;$"); newXSproto(strcpy(buf, "FailTask"), XS_Client_FailTask, file, "$$"); newXSproto(strcpy(buf, "IsTaskCompleted"), XS_Client_IsTaskCompleted, file, "$$"); newXSproto(strcpy(buf, "IsTaskActive"), XS_Client_IsTaskActive, file, "$$"); @@ -6351,7 +6656,13 @@ XS(boot_Client) newXSproto(strcpy(buf, "SendMarqueeMessage"), XS_Client_SendMarqueeMessage, file, "$$$$$$$"); newXSproto(strcpy(buf, "SendColoredText"), XS_Client_SendColoredText, file, "$$$"); newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$"); - + newXSproto(strcpy(buf, "GetTargetRingX"), XS_Client_GetTargetRingX, file, "$$"); + newXSproto(strcpy(buf, "GetTargetRingY"), XS_Client_GetTargetRingY, file, "$$"); + newXSproto(strcpy(buf, "GetTargetRingZ"), XS_Client_GetTargetRingZ, file, "$$"); + newXSproto(strcpy(buf, "QuestReward"), XS_Client_QuestReward, file, "$$;$$$$$$$"); + newXSproto(strcpy(buf, "CalcEXP"), XS_Client_CalcEXP, file, "$"); + newXSproto(strcpy(buf, "GetMoney"), XS_Client_GetMoney, file, "$$$"); + newXSproto(strcpy(buf, "GetAccountAge"), XS_Client_GetAccountAge, file, "$"); XSRETURN_YES; } diff --git a/zone/perl_entity.cpp b/zone/perl_entity.cpp index 2dd9c17f8..ae6051703 100644 --- a/zone/perl_entity.cpp +++ b/zone/perl_entity.cpp @@ -1904,7 +1904,7 @@ XS(XS_EntityList_GetMobList) std::list mob_list; entity_list.GetMobList(mob_list); - std::list::iterator iter = mob_list.begin(); + auto iter = mob_list.begin(); while(iter != mob_list.end()) { @@ -1941,7 +1941,7 @@ XS(XS_EntityList_GetClientList) std::list client_list; entity_list.GetClientList(client_list); - std::list::iterator iter = client_list.begin(); + auto iter = client_list.begin(); while(iter != client_list.end()) { @@ -1978,7 +1978,7 @@ XS(XS_EntityList_GetNPCList) std::list npc_list; entity_list.GetNPCList(npc_list); - std::list::iterator iter = npc_list.begin(); + auto iter = npc_list.begin(); while(iter != npc_list.end()) { @@ -2015,7 +2015,7 @@ XS(XS_EntityList_GetCorpseList) std::list corpse_list; entity_list.GetCorpseList(corpse_list); - std::list::iterator iter = corpse_list.begin(); + auto iter = corpse_list.begin(); while(iter != corpse_list.end()) { @@ -2052,7 +2052,7 @@ XS(XS_EntityList_GetObjectList) std::list object_list; entity_list.GetObjectList(object_list); - std::list::iterator iter = object_list.begin(); + auto iter = object_list.begin(); while(iter != object_list.end()) { @@ -2089,7 +2089,7 @@ XS(XS_EntityList_GetDoorsList) std::list door_list; entity_list.GetDoorsList(door_list); - std::list::iterator iter = door_list.begin(); + auto iter = door_list.begin(); while(iter != door_list.end()) { diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index 5eeb7be1b..f171d8d79 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -619,7 +619,7 @@ XS(XS_Mob_GetSkill) Mob * THIS; uint32 RETVAL; dXSTARG; - SkillUseTypes skill_num = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skill_num = (EQEmu::skills::SkillType)SvUV(ST(1)); if (sv_derived_from(ST(0), "Mob")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -901,7 +901,7 @@ XS(XS_Mob_Damage) Mob* from; int32 damage = (int32)SvIV(ST(2)); uint16 spell_id = (uint16)SvUV(ST(3)); - SkillUseTypes attack_skill = (SkillUseTypes)SvUV(ST(4)); + EQEmu::skills::SkillType attack_skill = (EQEmu::skills::SkillType)SvUV(ST(4)); bool avoidable; int8 buffslot; bool iBuffTic; @@ -1464,7 +1464,7 @@ XS(XS_Mob_GetBuffSlotFromType) Mob * THIS; int8 RETVAL; dXSTARG; - uint8 type = (uint8)SvUV(ST(1)); + uint16 type = (uint16)SvUV(ST(1)); if (sv_derived_from(ST(0), "Mob")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -2362,6 +2362,37 @@ XS(XS_Mob_GetSpellHPBonuses) XSRETURN(1); } +XS(XS_Mob_GetSpellIDFromSlot); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetSpellIDFromSlot) +{ + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Mob::GetSpellIDFromSlot(THIS, slot)"); + { + Mob * THIS; + int RETVAL; + dXSTARG; + uint8 slot = (uint16)SvUV(ST(1)); + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob *, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + if (slot > THIS->GetMaxBuffSlots()) + RETVAL = -1; + else + RETVAL = THIS->GetSpellIDFromSlot(slot); + + XSprePUSH; PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + XS(XS_Mob_GetWalkspeed); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_GetWalkspeed) { @@ -3951,12 +3982,12 @@ XS(XS_Mob_CastSpell) { dXSARGS; if (items < 3 || items > 7) - Perl_croak(aTHX_ "Usage: Mob::CastSpell(THIS, spell_id, target_id, slot= 10, casttime= -1, mana_cost= -1, resist_adjust = 0)"); + Perl_croak(aTHX_ "Usage: Mob::CastSpell(THIS, spell_id, target_id, slot= 22, casttime= -1, mana_cost= -1, resist_adjust = 0)"); { Mob * THIS; uint16 spell_id = (uint16)SvUV(ST(1)); uint16 target_id = (uint16)SvUV(ST(2)); - uint16 slot; + EQEmu::CastingSlot slot; int32 casttime; int32 mana_cost; int16 resist_adjust; @@ -3971,9 +4002,9 @@ XS(XS_Mob_CastSpell) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); if (items < 4) - slot = 10; + slot = EQEmu::CastingSlot::Item; else { - slot = (uint16)SvUV(ST(3)); + slot = static_cast(SvUV(ST(3))); } if (items < 5) @@ -3998,9 +4029,9 @@ XS(XS_Mob_CastSpell) } if (resist_adjust == 0)//If you do not pass resist adjust as nullptr it will ignore the spells default resist adjust - THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0); + THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0); else - THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, &resist_adjust); + THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, &resist_adjust); } XSRETURN_EMPTY; } @@ -4054,7 +4085,7 @@ XS(XS_Mob_SpellFinished) resist_diff = spells[spell_id].ResistDiff; } - THIS->SpellFinished(spell_id, spell_target, 10, mana_cost, -1, resist_diff); + THIS->SpellFinished(spell_id, spell_target, EQEmu::CastingSlot::Item, mana_cost, -1, resist_diff); } XSRETURN_EMPTY; } @@ -4721,12 +4752,12 @@ XS(XS_Mob_GetHaste) XSRETURN(1); } -XS(XS_Mob_GetMonkHandToHandDamage); /* prototype to pass -Wmissing-prototypes */ -XS(XS_Mob_GetMonkHandToHandDamage) +XS(XS_Mob_GetHandToHandDamage); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetHandToHandDamage) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: Mob::GetMonkHandToHandDamage(THIS)"); + Perl_croak(aTHX_ "Usage: Mob::GetHandToHandDamage(THIS)"); { Mob * THIS; int RETVAL; @@ -4741,7 +4772,7 @@ XS(XS_Mob_GetMonkHandToHandDamage) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->GetMonkHandToHandDamage(); + RETVAL = THIS->GetHandToHandDamage(); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); @@ -4877,12 +4908,12 @@ XS(XS_Mob_CanThisClassParry) XSRETURN(1); } -XS(XS_Mob_GetMonkHandToHandDelay); /* prototype to pass -Wmissing-prototypes */ -XS(XS_Mob_GetMonkHandToHandDelay) +XS(XS_Mob_GetHandToHandDelay); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetHandToHandDelay) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: Mob::GetMonkHandToHandDelay(THIS)"); + Perl_croak(aTHX_ "Usage: Mob::GetHandToHandDelay(THIS)"); { Mob * THIS; int RETVAL; @@ -4897,7 +4928,7 @@ XS(XS_Mob_GetMonkHandToHandDelay) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->GetMonkHandToHandDelay(); + RETVAL = THIS->GetHandToHandDelay(); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); @@ -6316,7 +6347,7 @@ XS(XS_Mob_CheckAggroAmount) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->CheckAggroAmount(spellid); + RETVAL = THIS->CheckAggroAmount(spellid, nullptr); XSprePUSH; PUSHu((UV)RETVAL); } XSRETURN(1); @@ -6349,7 +6380,7 @@ XS(XS_Mob_CheckHealAggroAmount) possible = (uint32)SvUV(ST(2)); } - RETVAL = THIS->CheckHealAggroAmount(spellid, possible); + RETVAL = THIS->CheckHealAggroAmount(spellid, nullptr, possible); XSprePUSH; PUSHu((UV)RETVAL); } XSRETURN(1); @@ -6360,12 +6391,12 @@ XS(XS_Mob_GetAA) { dXSARGS; if (items != 2) - Perl_croak(aTHX_ "Usage: Mob::GetAA(THIS, aa_id)"); + Perl_croak(aTHX_ "Usage: Mob::GetAA(THIS, rank_id)"); { Mob * THIS; uint32 RETVAL; dXSTARG; - uint32 aa_id = (uint32)SvUV(ST(1)); + uint32 rank_id = (uint32)SvUV(ST(1)); if (sv_derived_from(ST(0), "Mob")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -6376,12 +6407,68 @@ XS(XS_Mob_GetAA) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->GetAA(aa_id); + RETVAL = THIS->GetAA(rank_id); XSprePUSH; PUSHu((UV)RETVAL); } XSRETURN(1); } +XS(XS_Mob_GetAAByAAID); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetAAByAAID) +{ + dXSARGS; + if(items != 2) + Perl_croak(aTHX_ "Usage: Mob::GetAAByAAID(THIS, aa_id)"); + { + Mob * THIS; + uint32 RETVAL; + dXSTARG; + uint32 aa_id = (uint32)SvUV(ST(1)); + + if(sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob *, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetAAByAAID(aa_id); + XSprePUSH; PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_SetAA); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_SetAA) +{ + dXSARGS; + if(items < 3 || items > 4) + Perl_croak(aTHX_ "Usage: Mob::SetAA(THIS, aa_id, points, [charges])"); + { + Mob * THIS; + bool RETVAL; + int aa_id = (int)SvIV(ST(1)); + int points = (int)SvIV(ST(2)); + int charges = (items == 4) ? (int)SvIV(ST(3)) : 0; + + if(sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob *, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->SetAA(aa_id, points, charges); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + XS(XS_Mob_DivineAura); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_DivineAura) { @@ -6749,7 +6836,7 @@ XS(XS_Mob_DoSpecialAttackDamage) { Mob * THIS; Mob* target; - SkillUseTypes attack_skill = (SkillUseTypes)SvUV(ST(2)); + EQEmu::skills::SkillType attack_skill = (EQEmu::skills::SkillType)SvUV(ST(2)); int32 max_damage = (int32)SvIV(ST(3)); int32 min_damage = 1; int32 hate_override = -11; @@ -7027,47 +7114,6 @@ XS(XS_Mob_SendAppearanceEffect) XSRETURN_EMPTY; } -XS(XS_Mob_QuestReward); /* prototype to pass -Wmissing-prototypes */ -XS(XS_Mob_QuestReward) -{ - dXSARGS; - if (items < 1 || items > 5) - Perl_croak(aTHX_ "Usage: Mob::QuestReward(THIS, client, silver, gold, platinum)"); - { - Mob * THIS; - Client* client = nullptr; - int32 silver = 0; - int32 gold = 0; - int32 platinum = 0; - - if (sv_derived_from(ST(0), "Mob")) { - IV tmp = SvIV((SV*)SvRV(ST(0))); - THIS = INT2PTR(Mob *,tmp); - } - else - Perl_croak(aTHX_ "THIS is not of type Mob"); - if(THIS == nullptr) - Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - - if (items > 1) { - if (sv_derived_from(ST(1), "Client")) { - IV tmp = SvIV((SV*)SvRV(ST(1))); - client = INT2PTR(Client *,tmp); - } - else - Perl_croak(aTHX_ "client is not of type Client"); - if(client == nullptr) - Perl_croak(aTHX_ "client is nullptr, avoiding crash."); - } - if (items > 2) { silver = (int32)SvIV(ST(2)); } - if (items > 3) { gold = (int32)SvIV(ST(3)); } - if (items > 4) { platinum = (int32)SvIV(ST(4)); } - - THIS->QuestReward(client, silver, gold, platinum); - } - XSRETURN_EMPTY; -} - XS(XS_Mob_SetFlyMode); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_SetFlyMode) { @@ -7362,6 +7408,37 @@ XS(XS_Mob_GetItemStat) XSRETURN(1); } +XS(XS_Mob_GetGlobal); +XS(XS_Mob_GetGlobal) +{ + dXSARGS; + if (items < 2) + Perl_croak(aTHX_ "Usage: GetGlobal(THIS, varname)"); + { + Mob* THIS; + Const_char* varname = (Const_char*)SvPV_nolen(ST(1)); + std::string ret_val = "Undefined"; + Const_char* RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob *, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + if (THIS->GetGlobal(varname) != "Undefined") + ret_val = THIS->GetGlobal(varname); + + RETVAL = ret_val.c_str(); + sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; + } + XSRETURN(1); +} + XS(XS_Mob_SetGlobal); XS(XS_Mob_SetGlobal) { @@ -7758,7 +7835,7 @@ XS(XS_Mob_ModSkillDmgTaken) Perl_croak(aTHX_ "Usage: Mob::ModSkillDmgTaken(THIS, skill, value)"); { Mob * THIS; - SkillUseTypes skill_num = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skill_num = (EQEmu::skills::SkillType)SvUV(ST(1)); int16 value = (int16)SvIV(ST(2)); if (sv_derived_from(ST(0), "Mob")) { @@ -7785,7 +7862,7 @@ XS(XS_Mob_GetModSkillDmgTaken) Mob * THIS; int16 RETVAL; dXSTARG; - SkillUseTypes skill_num = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skill_num = (EQEmu::skills::SkillType)SvUV(ST(1)); if (sv_derived_from(ST(0), "Mob")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -7812,7 +7889,7 @@ XS(XS_Mob_GetSkillDmgTaken) Mob * THIS; int32 RETVAL; dXSTARG; - SkillUseTypes skill_num = (SkillUseTypes)SvUV(ST(1)); + EQEmu::skills::SkillType skill_num = (EQEmu::skills::SkillType)SvUV(ST(1)); if (sv_derived_from(ST(0), "Mob")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -7978,7 +8055,7 @@ XS(XS_Mob_DoMeleeSkillAttackDmg) Mob * THIS; Mob* target; uint16 weapon_damage = (uint16)SvIV(ST(2)); - SkillUseTypes skill = (SkillUseTypes)SvUV(ST(3)); + EQEmu::skills::SkillType skill = (EQEmu::skills::SkillType)SvUV(ST(3)); int16 chance_mod = (int16)SvIV(ST(4)); int16 focus = (int16)SvIV(ST(5)); uint8 CanRiposte = (uint8)SvIV(ST(6)); @@ -8054,7 +8131,7 @@ XS(XS_Mob_DoThrowingAttackDmg) Mob * THIS; Mob* target; ItemInst* RangeWeapon = nullptr; - Item_Struct* item = nullptr; + EQEmu::ItemBase* item = nullptr; uint16 weapon_damage = (uint16)SvIV(ST(4)); int16 chance_mod = (int16)SvIV(ST(5)); int16 focus = (int16)SvIV(ST(6)); @@ -8394,6 +8471,574 @@ XS(XS_Mob_CanClassEquipItem) XSRETURN(1); } +XS(XS_Mob_IsFeared); +XS(XS_Mob_IsFeared) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsFeared(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsFeared(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_IsBlind); +XS(XS_Mob_IsBlind) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsBlind(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsBlind(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_SeeInvisible); +XS(XS_Mob_SeeInvisible) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::SeeInvisible(THIS)"); + { + Mob* THIS; + uint8 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->SeeInvisible(); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_SeeInvisibleUndead); +XS(XS_Mob_SeeInvisibleUndead) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::SeeInvisibleUndead(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->SeeInvisibleUndead(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_SeeHide); +XS(XS_Mob_SeeHide) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::SeeHide(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->SeeHide(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_SeeImprovedHide); +XS(XS_Mob_SeeImprovedHide) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::SeeImprovedHide(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->SeeImprovedHide(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_GetNimbusEffect1); +XS(XS_Mob_GetNimbusEffect1) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect1(THIS)"); + { + Mob* THIS; + uint8 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetNimbusEffect1(); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_GetNimbusEffect2); +XS(XS_Mob_GetNimbusEffect2) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect2(THIS)"); + { + Mob* THIS; + uint8 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetNimbusEffect2(); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_GetNimbusEffect3); +XS(XS_Mob_GetNimbusEffect3) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect3(THIS)"); + { + Mob* THIS; + uint8 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetNimbusEffect3(); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_IsTargetable); +XS(XS_Mob_IsTargetable) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsTargetable(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsTargetable(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_HasShieldEquiped); +XS(XS_Mob_HasShieldEquiped) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasShieldEquiped(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasShieldEquiped(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_HasTwoHandBluntEquiped); +XS(XS_Mob_HasTwoHandBluntEquiped) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasTwoHandBluntEquiped(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasTwoHandBluntEquiped(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_HasTwoHanderEquipped); +XS(XS_Mob_HasTwoHanderEquipped) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasTwoHanderEquipped(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasTwoHanderEquipped(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_GetHerosForgeModel); +XS(XS_Mob_GetHerosForgeModel) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Mob::GetHerosForgeModel(THIS, material_slot)"); + { + Mob* THIS; + int32 RETVAL; + uint8 material_slot = (uint8)SvUV(ST(1)); + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetHerosForgeModel(material_slot); + XSprePUSH; + PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_IsEliteMaterialItem); +XS(XS_Mob_IsEliteMaterialItem) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Mob::IsEliteMaterialItem(THIS, material_slot)"); + { + Mob* THIS; + uint32 RETVAL; + uint8 material_slot = (uint8)SvUV(ST(1)); + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsEliteMaterialItem(material_slot); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_GetBaseSize); +XS(XS_Mob_GetBaseSize) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetBaseSize(THIS)"); + { + Mob* THIS; + float RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetBaseSize(); + XSprePUSH; + PUSHn((double)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_HasOwner); +XS(XS_Mob_HasOwner) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasOwner(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasOwner(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_IsPet); +XS(XS_Mob_IsPet) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsPet(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsPet(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_HasPet); +XS(XS_Mob_HasPet) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasPet(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasPet(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_IsSilenced); +XS(XS_Mob_IsSilenced) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsSilenced(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsSilenced(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_IsAmnesiad); +XS(XS_Mob_IsAmnesiad) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsAmnesiad(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsAmnesiad(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_GetMeleeMitigation); +XS(XS_Mob_GetMeleeMitigation) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetMeleeMitigation(THIS)"); + { + Mob* THIS; + int32 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetMeleeMitigation(); + XSprePUSH; + PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + #ifdef __cplusplus extern "C" #endif @@ -8491,6 +9136,7 @@ XS(boot_Mob) newXSproto(strcpy(buf, "GetMaxHP"), XS_Mob_GetMaxHP, file, "$"); newXSproto(strcpy(buf, "GetItemHPBonuses"), XS_Mob_GetItemHPBonuses, file, "$"); newXSproto(strcpy(buf, "GetSpellHPBonuses"), XS_Mob_GetSpellHPBonuses, file, "$"); + newXSproto(strcpy(buf, "GetSpellIDFromSlot"), XS_Mob_GetSpellIDFromSlot, file, "$$"); newXSproto(strcpy(buf, "GetWalkspeed"), XS_Mob_GetWalkspeed, file, "$"); newXSproto(strcpy(buf, "GetRunspeed"), XS_Mob_GetRunspeed, file, "$"); newXSproto(strcpy(buf, "GetCasterLevel"), XS_Mob_GetCasterLevel, file, "$$"); @@ -8578,13 +9224,13 @@ XS(boot_Mob) newXSproto(strcpy(buf, "GetInvul"), XS_Mob_GetInvul, file, "$"); newXSproto(strcpy(buf, "SetExtraHaste"), XS_Mob_SetExtraHaste, file, "$$"); newXSproto(strcpy(buf, "GetHaste"), XS_Mob_GetHaste, file, "$"); - newXSproto(strcpy(buf, "GetMonkHandToHandDamage"), XS_Mob_GetMonkHandToHandDamage, file, "$"); + newXSproto(strcpy(buf, "GetHandToHandDamage"), XS_Mob_GetHandToHandDamage, file, "$"); newXSproto(strcpy(buf, "CanThisClassDoubleAttack"), XS_Mob_CanThisClassDoubleAttack, file, "$"); newXSproto(strcpy(buf, "CanThisClassDualWield"), XS_Mob_CanThisClassDualWield, file, "$"); newXSproto(strcpy(buf, "CanThisClassRiposte"), XS_Mob_CanThisClassRiposte, file, "$"); newXSproto(strcpy(buf, "CanThisClassDodge"), XS_Mob_CanThisClassDodge, file, "$"); newXSproto(strcpy(buf, "CanThisClassParry"), XS_Mob_CanThisClassParry, file, "$"); - newXSproto(strcpy(buf, "GetMonkHandToHandDelay"), XS_Mob_GetMonkHandToHandDelay, file, "$"); + newXSproto(strcpy(buf, "GetHandToHandDelay"), XS_Mob_GetHandToHandDelay, file, "$"); newXSproto(strcpy(buf, "GetClassLevelFactor"), XS_Mob_GetClassLevelFactor, file, "$"); newXSproto(strcpy(buf, "Mesmerize"), XS_Mob_Mesmerize, file, "$"); newXSproto(strcpy(buf, "IsMezzed"), XS_Mob_IsMezzed, file, "$"); @@ -8635,6 +9281,8 @@ XS(boot_Mob) newXSproto(strcpy(buf, "CheckAggroAmount"), XS_Mob_CheckAggroAmount, file, "$$"); newXSproto(strcpy(buf, "CheckHealAggroAmount"), XS_Mob_CheckHealAggroAmount, file, "$$"); newXSproto(strcpy(buf, "GetAA"), XS_Mob_GetAA, file, "$$"); + newXSproto(strcpy(buf, "GetAAByAAID"), XS_Mob_GetAAByAAID, file, "$$"); + newXSproto(strcpy(buf, "SetAA"), XS_Mob_SetAA, file, "$$$;$"); newXSproto(strcpy(buf, "DivineAura"), XS_Mob_DivineAura, file, "$"); newXSproto(strcpy(buf, "AddFeignMemory"), XS_Mob_AddFeignMemory, file, "$$"); newXSproto(strcpy(buf, "RemoveFromFeignMemory"), XS_Mob_RemoveFromFeignMemory, file, "$$"); @@ -8660,11 +9308,11 @@ XS(boot_Mob) newXSproto(strcpy(buf, "SendIllusion"), XS_Mob_SendIllusion, file, "$$;$$$$$$$$$$$$"); newXSproto(strcpy(buf, "MakeTempPet"), XS_Mob_MakeTempPet, file, "$$;$$$$"); newXSproto(strcpy(buf, "TypesTempPet"), XS_Mob_TypesTempPet, file, "$$;$$$$$"); - newXSproto(strcpy(buf, "QuestReward"), XS_Mob_QuestReward, file, "$$;$$$"); newXSproto(strcpy(buf, "CameraEffect"), XS_Mob_CameraEffect, file, "$$;$$$"); newXSproto(strcpy(buf, "SpellEffect"), XS_Mob_SpellEffect, file, "$$;$$$$$$"); newXSproto(strcpy(buf, "TempName"), XS_Mob_TempName, file, "$:$"); newXSproto(strcpy(buf, "GetItemStat"), XS_Mob_GetItemStat, file, "$$$"); + newXSproto(strcpy(buf, "GetGlobal"), XS_Mob_GetGlobal, file, "$$"); newXSproto(strcpy(buf, "SetGlobal"), XS_Mob_SetGlobal, file, "$$$$$;$"); newXSproto(strcpy(buf, "TarGlobal"), XS_Mob_TarGlobal, file, "$$$$$$$"); newXSproto(strcpy(buf, "DelGlobal"), XS_Mob_DelGlobal, file, "$$"); @@ -8703,6 +9351,28 @@ XS(boot_Mob) newXSproto(strcpy(buf, "ClearSpecialAbilities"), XS_Mob_ClearSpecialAbilities, file, "$"); newXSproto(strcpy(buf, "ProcessSpecialAbilities"), XS_Mob_ProcessSpecialAbilities, file, "$$"); newXSproto(strcpy(buf, "CanClassEquipItem"), XS_Mob_CanClassEquipItem, file, "$$"); + newXSproto(strcpy(buf, "IsFeared"), XS_Mob_IsFeared, file, "$"); + newXSproto(strcpy(buf, "IsBlind"), XS_Mob_IsBlind, file, "$"); + newXSproto(strcpy(buf, "SeeInvisible"), XS_Mob_SeeInvisible, file, "$"); + newXSproto(strcpy(buf, "SeeInvisibleUndead"), XS_Mob_SeeInvisibleUndead, file, "$"); + newXSproto(strcpy(buf, "SeeHide"), XS_Mob_SeeHide, file, "$"); + newXSproto(strcpy(buf, "SeeImprovedHide"), XS_Mob_SeeImprovedHide, file, "$"); + newXSproto(strcpy(buf, "GetNimbusEffect1"), XS_Mob_GetNimbusEffect1, file, "$"); + newXSproto(strcpy(buf, "GetNimbusEffect2"), XS_Mob_GetNimbusEffect2, file, "$"); + newXSproto(strcpy(buf, "GetNimbusEffect3"), XS_Mob_GetNimbusEffect3, file, "$"); + newXSproto(strcpy(buf, "IsTargetable"), XS_Mob_IsTargetable, file, "$"); + newXSproto(strcpy(buf, "HasShieldEquiped"), XS_Mob_HasShieldEquiped, file, "$"); + newXSproto(strcpy(buf, "HasTwoHandBluntEquiped"), XS_Mob_HasTwoHandBluntEquiped, file, "$"); + newXSproto(strcpy(buf, "HasTwoHanderEquipped"), XS_Mob_HasTwoHanderEquipped, file, "$"); + newXSproto(strcpy(buf, "GetHerosForgeModel"), XS_Mob_GetHerosForgeModel, file, "$$"); + newXSproto(strcpy(buf, "IsEliteMaterialItem"), XS_Mob_IsEliteMaterialItem, file, "$$"); + newXSproto(strcpy(buf, "GetBaseSize"), XS_Mob_GetBaseSize, file, "$"); + newXSproto(strcpy(buf, "HasOwner"), XS_Mob_HasOwner, file, "$"); + newXSproto(strcpy(buf, "IsPet"), XS_Mob_IsPet, file, "$"); + newXSproto(strcpy(buf, "HasPet"), XS_Mob_HasPet, file, "$"); + newXSproto(strcpy(buf, "IsSilenced"), XS_Mob_IsSilenced, file, "$"); + newXSproto(strcpy(buf, "IsAmnesiad"), XS_Mob_IsAmnesiad, file, "$"); + newXSproto(strcpy(buf, "GetMeleeMitigation"), XS_Mob_GetMeleeMitigation, file, "$"); XSRETURN_YES; } diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index febee6941..0c9cec797 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -2530,6 +2530,32 @@ XS(XS_NPC_ClearLastName) XSRETURN_EMPTY; } +XS(XS_NPC_GetCombatState); /* prototype to pass -Wmissing-prototypes */ +XS(XS_NPC_GetCombatState) +{ + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: NPC::GetCombatState(THIS)"); + { + NPC * THIS; + bool RETVAL; + + 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."); + + RETVAL = THIS->GetCombatEvent(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + #ifdef __cplusplus extern "C" #endif @@ -2643,6 +2669,7 @@ XS(boot_NPC) newXSproto(strcpy(buf, "RemoveDefensiveProc"), XS_NPC_RemoveDefensiveProc, file, "$$"); newXSproto(strcpy(buf, "ChangeLastName"), XS_NPC_ChangeLastName, file, "$:$"); newXSproto(strcpy(buf, "ClearLastName"), XS_NPC_ClearLastName, file, "$"); + newXSproto(strcpy(buf, "GetCombatState"), XS_NPC_GetCombatState, file, "$"); XSRETURN_YES; } diff --git a/zone/perl_questitem.cpp b/zone/perl_questitem.cpp index 158ee64a4..fa186a9b5 100644 --- a/zone/perl_questitem.cpp +++ b/zone/perl_questitem.cpp @@ -134,7 +134,7 @@ XS(XS_QuestItem_IsType) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->IsType((ItemClassTypes)type); + RETVAL = THIS->IsType((EQEmu::item::ItemClass)type); ST(0) = boolSV(RETVAL); sv_2mortal(ST(0)); } diff --git a/zone/perlpacket.cpp b/zone/perlpacket.cpp index ed0dd9cd3..9f423f089 100644 --- a/zone/perlpacket.cpp +++ b/zone/perlpacket.cpp @@ -62,7 +62,7 @@ void PerlPacket::SendTo(Client *who) { if(!who || op == OP_Unknown || (len > 0 && packet == nullptr)) return; - EQApplicationPacket *outapp = new EQApplicationPacket(op, len); + auto outapp = new EQApplicationPacket(op, len); if(len > 0) memcpy(outapp->pBuffer, packet, len); @@ -76,7 +76,7 @@ void PerlPacket::SendToAll() { if(op == OP_Unknown || (len > 0 && packet == nullptr)) return; - EQApplicationPacket *outapp = new EQApplicationPacket(op, len); + auto outapp = new EQApplicationPacket(op, len); if(len > 0) memcpy(outapp->pBuffer, packet, len); entity_list.QueueClients(nullptr, outapp, false); diff --git a/zone/petitions.cpp b/zone/petitions.cpp index 3e8a836e2..d3c350b5f 100644 --- a/zone/petitions.cpp +++ b/zone/petitions.cpp @@ -44,7 +44,7 @@ PetitionList petition_list; extern WorldServer worldserver; void Petition::SendPetitionToPlayer(Client* clientto) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_PetitionCheckout,sizeof(Petition_Struct)); + auto outapp = new EQApplicationPacket(OP_PetitionCheckout, sizeof(Petition_Struct)); Petition_Struct* pet = (Petition_Struct*) outapp->pBuffer; strcpy(pet->accountid,this->GetAccountName()); strcpy(pet->lastgm,this->GetLastGM()); @@ -136,7 +136,7 @@ bool PetitionList::DeletePetitionByCharName(const char* charname) { return false; } void PetitionList::UpdateZoneListQueue() { - ServerPacket* pack = new ServerPacket(ServerOP_Petition, sizeof(ServerPetitionUpdate_Struct)); + auto pack = new ServerPacket(ServerOP_Petition, sizeof(ServerPetitionUpdate_Struct)); ServerPetitionUpdate_Struct* pupdate = (ServerPetitionUpdate_Struct*) pack->pBuffer; pupdate->petid = 0x00; pupdate->status = 0x00; @@ -229,7 +229,7 @@ void ZoneDatabase::InsertPetitionToDB(Petition* wpet) { uint32 len = strlen(wpet->GetPetitionText()); - char* petitiontext = new char[2*len+1]; + auto petitiontext = new char[2 * len + 1]; memset(petitiontext, 0, 2*len+1); DoEscapeString(petitiontext, wpet->GetPetitionText(), len); diff --git a/zone/pets.cpp b/zone/pets.cpp index 5a6a0be9f..e527d80ce 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -28,6 +28,10 @@ #include "pets.h" #include "zonedb.h" +#ifdef BOTS +#include "bot.h" +#endif + #ifndef WIN32 #include #include "../common/unix.h" @@ -231,6 +235,10 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);//Client only act_power = CastToClient()->mod_pet_power(act_power, spell_id); } +#ifdef BOTS + else if (this->IsBot()) + act_power = CastToBot()->GetBotFocusEffect(Bot::BotfocusPetPower, spell_id); +#endif } else if (petpower > 0) act_power = petpower; @@ -256,11 +264,15 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, } //we copy the npc_type data because we need to edit it a bit - NPCType *npc_type = new NPCType; + auto npc_type = new NPCType; memcpy(npc_type, base, sizeof(NPCType)); // If pet power is set to -1 in the DB, use stat scaling - if (this->IsClient() && record.petpower == -1) + if ((this->IsClient() +#ifdef BOTS + || this->IsBot() +#endif + ) && record.petpower == -1) { float scale_power = (float)act_power / 100.0f; if(scale_power > 0) @@ -268,10 +280,10 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, npc_type->max_hp *= (1 + scale_power); npc_type->cur_hp = npc_type->max_hp; npc_type->AC *= (1 + scale_power); - npc_type->level += 1 + ((int)act_power / 25); // gains an additional level for every 25 pet power + npc_type->level += 1 + ((int)act_power / 25) > npc_type->level + RuleR(Pets, PetPowerLevelCap) ? RuleR(Pets, PetPowerLevelCap) : 1 + ((int)act_power / 25); // gains an additional level for every 25 pet power npc_type->min_dmg = (npc_type->min_dmg * (1 + (scale_power / 2))); npc_type->max_dmg = (npc_type->max_dmg * (1 + (scale_power / 2))); - npc_type->size *= (1 + (scale_power / 2)); + npc_type->size = npc_type->size * (1 + (scale_power / 2)) > npc_type->size * 3 ? npc_type->size * 3 : npc_type-> size * (1 + (scale_power / 2)); } record.petpower = act_power; } @@ -371,6 +383,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, "ORDER BY RAND() LIMIT 1", zone->GetShortName()); auto results = database.QueryDatabase(query); if (!results.Success()) { + safe_delete(npc_type); return; } @@ -399,18 +412,18 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, } //this takes ownership of the npc_type data - Pet *npc = new Pet(npc_type, this, (PetType)record.petcontrol, spell_id, record.petpower); + auto npc = new Pet(npc_type, this, (PetType)record.petcontrol, spell_id, record.petpower); // Now that we have an actual object to interact with, load // the base items for the pet. These are always loaded // so that a rank 1 suspend minion does not kill things // like the special back items some focused pets may receive. - uint32 petinv[EmuConstants::EQUIPMENT_SIZE]; + uint32 petinv[EQEmu::legacy::EQUIPMENT_SIZE]; memset(petinv, 0, sizeof(petinv)); - const Item_Struct *item = 0; + const EQEmu::ItemBase *item = 0; if (database.GetBasePetItems(record.equipmentset, petinv)) { - for (int i = 0; iAddLootDrop(item, &npc->itemlist, 0, 1, 127, true, true); @@ -426,7 +439,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, entity_list.AddNPC(npc, true, true); SetPetID(npc->GetID()); // We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet - + if (record.petcontrol == petTargetLock) { @@ -457,6 +470,22 @@ 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); } @@ -544,23 +573,24 @@ void NPC::GetPetState(SpellBuff_Struct *pet_buffs, uint32 *items, char *name) { strn0cpy(name, GetName(), 64); //save their items, we only care about what they are actually wearing - memcpy(items, equipment, sizeof(uint32)*EmuConstants::EQUIPMENT_SIZE); + memcpy(items, equipment, sizeof(uint32) * EQEmu::legacy::EQUIPMENT_SIZE); //save their buffs. for (int i=0; i < GetPetMaxTotalSlots(); i++) { if (buffs[i].spellid != SPELL_UNKNOWN) { pet_buffs[i].spellid = buffs[i].spellid; - pet_buffs[i].slotid = i+1; + pet_buffs[i].effect_type = i+1; pet_buffs[i].duration = buffs[i].ticsremaining; pet_buffs[i].level = buffs[i].casterlevel; - pet_buffs[i].effect = 10; + pet_buffs[i].bard_modifier = 10; pet_buffs[i].counters = buffs[i].counters; + pet_buffs[i].bard_modifier = buffs[i].instrument_mod; } else { pet_buffs[i].spellid = SPELL_UNKNOWN; pet_buffs[i].duration = 0; pet_buffs[i].level = 0; - pet_buffs[i].effect = 0; + pet_buffs[i].bard_modifier = 10; pet_buffs[i].counters = 0; } } @@ -588,14 +618,15 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) { buffs[i].casterid = 0; buffs[i].counters = pet_buffs[i].counters; buffs[i].numhits = spells[pet_buffs[i].spellid].numhits; + buffs[i].instrument_mod = pet_buffs[i].bard_modifier; } else { buffs[i].spellid = SPELL_UNKNOWN; pet_buffs[i].spellid = 0xFFFFFFFF; - pet_buffs[i].slotid = 0; + pet_buffs[i].effect_type = 0; pet_buffs[i].level = 0; pet_buffs[i].duration = 0; - pet_buffs[i].effect = 0; + pet_buffs[i].bard_modifier = 0; } } for (int j1=0; j1 < GetPetMaxTotalSlots(); j1++) { @@ -617,10 +648,10 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) { case SE_Illusion: buffs[j1].spellid = SPELL_UNKNOWN; pet_buffs[j1].spellid = SPELLBOOK_UNKNOWN; - pet_buffs[j1].slotid = 0; + pet_buffs[j1].effect_type = 0; pet_buffs[j1].level = 0; pet_buffs[j1].duration = 0; - pet_buffs[j1].effect = 0; + pet_buffs[j1].bard_modifier = 0; x1 = EFFECT_COUNT; break; // We can't send appearance packets yet, put down at CompleteConnect @@ -630,15 +661,15 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) { } //restore their equipment... - for (i = 0; i < EmuConstants::EQUIPMENT_SIZE; i++) { + for (i = 0; i < EQEmu::legacy::EQUIPMENT_SIZE; i++) { if(items[i] == 0) continue; - const Item_Struct* item2 = database.GetItem(items[i]); + const EQEmu::ItemBase* 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, 127, true, true); + AddLootDrop(item2, &itemlist, 0, 1, 255, true, true); } } } @@ -692,7 +723,7 @@ bool ZoneDatabase::GetBasePetItems(int32 equipmentset, uint32 *items) { { slot = atoi(row[0]); - if (slot >= EmuConstants::EQUIPMENT_SIZE) + if (slot >= EQEmu::legacy::EQUIPMENT_SIZE) continue; if (items[slot] == 0) @@ -707,3 +738,10 @@ bool ZoneDatabase::GetBasePetItems(int32 equipmentset, uint32 *items) { return true; } +bool Pet::CheckSpellLevelRestriction(uint16 spell_id) +{ + auto owner = GetOwner(); + if (owner) + return owner->CheckSpellLevelRestriction(spell_id); + return true; +} diff --git a/zone/pets.h b/zone/pets.h index f0c71fbe7..8d14d8a48 100644 --- a/zone/pets.h +++ b/zone/pets.h @@ -39,6 +39,8 @@ 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/qglobals.cpp b/zone/qglobals.cpp index 0dced7cb0..f1719def5 100644 --- a/zone/qglobals.cpp +++ b/zone/qglobals.cpp @@ -12,7 +12,7 @@ void QGlobalCache::AddGlobal(uint32 id, QGlobal global) void QGlobalCache::RemoveGlobal(std::string name, uint32 npcID, uint32 charID, uint32 zoneID) { - std::list::iterator iter = qGlobalBucket.begin(); + auto iter = qGlobalBucket.begin(); while(iter != qGlobalBucket.end()) { if(name.compare((*iter).name) == 0) @@ -31,7 +31,7 @@ void QGlobalCache::RemoveGlobal(std::string name, uint32 npcID, uint32 charID, u void QGlobalCache::Combine(std::list &cacheA, std::list cacheB, uint32 npcID, uint32 charID, uint32 zoneID) { - std::list::iterator iter = cacheB.begin(); + auto iter = cacheB.begin(); while(iter != cacheB.end()) { QGlobal cur = (*iter); @@ -123,7 +123,7 @@ void QGlobalCache::PurgeExpiredGlobals() if(!qGlobalBucket.size()) return; - std::list::iterator iter = qGlobalBucket.begin(); + auto iter = qGlobalBucket.begin(); while(iter != qGlobalBucket.end()) { QGlobal cur = (*iter); diff --git a/zone/queryserv.cpp b/zone/queryserv.cpp index d67ca46c7..691943a7c 100644 --- a/zone/queryserv.cpp +++ b/zone/queryserv.cpp @@ -35,7 +35,7 @@ QueryServ::~QueryServ(){ void QueryServ::SendQuery(std::string Query) { - ServerPacket* pack = new ServerPacket(ServerOP_QSSendQuery, Query.length() + 5); + auto pack = new ServerPacket(ServerOP_QSSendQuery, Query.length() + 5); pack->WriteUInt32(Query.length()); /* Pack Query String Size so it can be dynamically broken out at queryserv */ pack->WriteString(Query.c_str()); /* Query */ worldserver.SendPacket(pack); diff --git a/zone/quest_interface.h b/zone/quest_interface.h index 68c79923f..c1cf3dc73 100644 --- a/zone/quest_interface.h +++ b/zone/quest_interface.h @@ -41,7 +41,7 @@ public: std::vector *extra_pointers) { return 0; } virtual int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, std::vector *extra_pointers) { return 0; } - virtual int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, + virtual int EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data, std::vector *extra_pointers) { return 0; } virtual bool HasQuestSub(uint32 npcid, QuestEventID evt) { return false; } diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp index 37e518c24..290b71ab9 100644 --- a/zone/quest_parser_collection.cpp +++ b/zone/quest_parser_collection.cpp @@ -24,6 +24,7 @@ #include "quest_interface.h" #include "zone.h" #include "questmgr.h" +#include "zone_config.h" #include @@ -52,7 +53,7 @@ void QuestParserCollection::ClearInterfaces() { } void QuestParserCollection::AddVar(std::string name, std::string val) { - std::list::iterator iter = _load_precedence.begin(); + auto iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { (*iter)->AddVar(name, val); ++iter; @@ -60,7 +61,7 @@ void QuestParserCollection::AddVar(std::string name, std::string val) { } void QuestParserCollection::Init() { - std::list::iterator iter = _load_precedence.begin(); + auto iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { (*iter)->Init(); ++iter; @@ -80,7 +81,7 @@ void QuestParserCollection::ReloadQuests(bool reset_timers) { _spell_quest_status.clear(); _item_quest_status.clear(); _encounter_quest_status.clear(); - std::list::iterator iter = _load_precedence.begin(); + auto iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { (*iter)->ReloadQuests(); ++iter; @@ -92,12 +93,12 @@ bool QuestParserCollection::HasQuestSub(uint32 npcid, QuestEventID evt) { } bool QuestParserCollection::HasQuestSubLocal(uint32 npcid, QuestEventID evt) { - std::map::iterator iter = _npc_quest_status.find(npcid); - + auto iter = _npc_quest_status.find(npcid); + if(iter != _npc_quest_status.end()) { //loaded or failed to load if(iter->second != QuestFailedToLoad) { - std::map::iterator qiter = _interfaces.find(iter->second); + auto qiter = _interfaces.find(iter->second); if(qiter->second->HasQuestSub(npcid, evt)) { return true; } @@ -132,7 +133,7 @@ bool QuestParserCollection::HasQuestSubGlobal(QuestEventID evt) { } } else { if(_global_npc_quest_status != QuestFailedToLoad) { - std::map::iterator qiter = _interfaces.find(_global_npc_quest_status); + auto qiter = _interfaces.find(_global_npc_quest_status); if(qiter->second->HasGlobalQuestSub(evt)) { return true; } @@ -155,7 +156,7 @@ bool QuestParserCollection::PlayerHasQuestSubLocal(QuestEventID evt) { return qi->PlayerHasQuestSub(evt); } } else if(_player_quest_status != QuestFailedToLoad) { - std::map::iterator iter = _interfaces.find(_player_quest_status); + auto iter = _interfaces.find(_player_quest_status); return iter->second->PlayerHasQuestSub(evt); } return false; @@ -171,18 +172,18 @@ bool QuestParserCollection::PlayerHasQuestSubGlobal(QuestEventID evt) { return qi->GlobalPlayerHasQuestSub(evt); } } else if(_global_player_quest_status != QuestFailedToLoad) { - std::map::iterator iter = _interfaces.find(_global_player_quest_status); + auto iter = _interfaces.find(_global_player_quest_status); return iter->second->GlobalPlayerHasQuestSub(evt); } return false; } bool QuestParserCollection::SpellHasQuestSub(uint32 spell_id, QuestEventID evt) { - std::map::iterator iter = _spell_quest_status.find(spell_id); + auto iter = _spell_quest_status.find(spell_id); if(iter != _spell_quest_status.end()) { //loaded or failed to load if(iter->second != QuestFailedToLoad) { - std::map::iterator qiter = _interfaces.find(iter->second); + auto qiter = _interfaces.find(iter->second); return qiter->second->SpellHasQuestSub(spell_id, evt); } } else { @@ -214,11 +215,11 @@ bool QuestParserCollection::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) { } uint32 item_id = itm->GetID(); - std::map::iterator iter = _item_quest_status.find(item_id); + auto iter = _item_quest_status.find(item_id); if(iter != _item_quest_status.end()) { //loaded or failed to load if(iter->second != QuestFailedToLoad) { - std::map::iterator qiter = _interfaces.find(iter->second); + auto qiter = _interfaces.find(iter->second); return qiter->second->ItemHasQuestSub(itm, evt); } } else { @@ -255,11 +256,11 @@ int QuestParserCollection::EventNPC(QuestEventID evt, NPC *npc, Mob *init, std:: int QuestParserCollection::EventNPCLocal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { - std::map::iterator iter = _npc_quest_status.find(npc->GetNPCTypeID()); + auto iter = _npc_quest_status.find(npc->GetNPCTypeID()); if(iter != _npc_quest_status.end()) { //loaded or failed to load if(iter->second != QuestFailedToLoad) { - std::map::iterator qiter = _interfaces.find(iter->second); + auto qiter = _interfaces.find(iter->second); return qiter->second->EventNPC(evt, npc, init, data, extra_data, extra_pointers); } } else { @@ -279,7 +280,7 @@ int QuestParserCollection::EventNPCLocal(QuestEventID evt, NPC* npc, Mob *init, int QuestParserCollection::EventNPCGlobal(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { if(_global_npc_quest_status != QuestUnloaded && _global_npc_quest_status != QuestFailedToLoad) { - std::map::iterator qiter = _interfaces.find(_global_npc_quest_status); + auto qiter = _interfaces.find(_global_npc_quest_status); return qiter->second->EventGlobalNPC(evt, npc, init, data, extra_data, extra_pointers); } else { std::string filename; @@ -325,7 +326,7 @@ int QuestParserCollection::EventPlayerLocal(QuestEventID evt, Client *client, st } } else { if(_player_quest_status != QuestFailedToLoad) { - std::map::iterator iter = _interfaces.find(_player_quest_status); + auto iter = _interfaces.find(_player_quest_status); return iter->second->EventPlayer(evt, client, data, extra_data, extra_pointers); } } @@ -344,7 +345,7 @@ int QuestParserCollection::EventPlayerGlobal(QuestEventID evt, Client *client, s } } else { if(_global_player_quest_status != QuestFailedToLoad) { - std::map::iterator iter = _interfaces.find(_global_player_quest_status); + auto iter = _interfaces.find(_global_player_quest_status); return iter->second->EventGlobalPlayer(evt, client, data, extra_data, extra_pointers); } } @@ -366,11 +367,11 @@ int QuestParserCollection::EventItem(QuestEventID evt, Client *client, ItemInst } uint32 item_id = item->GetID(); - std::map::iterator iter = _item_quest_status.find(item_id); + auto iter = _item_quest_status.find(item_id); if(iter != _item_quest_status.end()) { //loaded or failed to load if(iter->second != QuestFailedToLoad) { - std::map::iterator qiter = _interfaces.find(iter->second); + auto qiter = _interfaces.find(iter->second); int ret = DispatchEventItem(evt, client, item, mob, data, extra_data, extra_pointers); int i = qiter->second->EventItem(evt, client, item, mob, data, extra_data, extra_pointers); if(i != 0) { @@ -401,11 +402,11 @@ int QuestParserCollection::EventItem(QuestEventID evt, Client *client, ItemInst int QuestParserCollection::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, std::vector *extra_pointers) { - std::map::iterator iter = _spell_quest_status.find(spell_id); + auto iter = _spell_quest_status.find(spell_id); if(iter != _spell_quest_status.end()) { //loaded or failed to load if(iter->second != QuestFailedToLoad) { - std::map::iterator qiter = _interfaces.find(iter->second); + auto qiter = _interfaces.find(iter->second); int ret = DispatchEventSpell(evt, npc, client, spell_id, extra_data, extra_pointers); int i = qiter->second->EventSpell(evt, npc, client, spell_id, extra_data, extra_pointers); if(i != 0) { @@ -434,14 +435,14 @@ int QuestParserCollection::EventSpell(QuestEventID evt, NPC* npc, Client *client return 0; } -int QuestParserCollection::EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, +int QuestParserCollection::EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data, std::vector *extra_pointers) { auto iter = _encounter_quest_status.find(encounter_name); if(iter != _encounter_quest_status.end()) { //loaded or failed to load if(iter->second != QuestFailedToLoad) { - std::map::iterator qiter = _interfaces.find(iter->second); - return qiter->second->EventEncounter(evt, encounter_name, extra_data, extra_pointers); + auto qiter = _interfaces.find(iter->second); + return qiter->second->EventEncounter(evt, encounter_name, data, extra_data, extra_pointers); } } else { std::string filename; @@ -449,7 +450,7 @@ int QuestParserCollection::EventEncounter(QuestEventID evt, std::string encounte if(qi) { _encounter_quest_status[encounter_name] = qi->GetIdentifier(); qi->LoadEncounterScript(filename, encounter_name); - return qi->EventEncounter(evt, encounter_name, extra_data, extra_pointers); + return qi->EventEncounter(evt, encounter_name, data, extra_data, extra_pointers); } else { _encounter_quest_status[encounter_name] = QuestFailedToLoad; } @@ -459,17 +460,17 @@ int QuestParserCollection::EventEncounter(QuestEventID evt, std::string encounte QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string &filename) { //first look for /quests/zone/npcid.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/"; filename += itoa(npcid); std::string tmp; FILE *f = nullptr; - std::list::iterator iter = _load_precedence.begin(); + auto iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -484,10 +485,17 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string //second look for /quests/zone/npcname.ext (precedence) const NPCType *npc_type = database.LoadNPCTypesData(npcid); - if(!npc_type) { + if (!npc_type && npcid != ZONE_CONTROLLER_NPC_ID) { return nullptr; } - std::string npc_name = npc_type->name; + + std::string npc_name; + if (npcid == ZONE_CONTROLLER_NPC_ID){ + npc_name = "zone_controller"; + } + else{ + npc_name = npc_type->name; + } int sz = static_cast(npc_name.length()); for(int i = 0; i < sz; ++i) { if(npc_name[i] == '`') { @@ -495,7 +503,7 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string } } - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/"; filename += npc_name; @@ -503,7 +511,7 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -517,14 +525,14 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string } //third look for /quests/global/npcid.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/"; filename += itoa(npcid); iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -538,14 +546,14 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string } //fourth look for /quests/global/npcname.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/"; filename += npc_name; iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -559,14 +567,14 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string } //fifth look for /quests/zone/default.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/"; filename += "default"; iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -580,14 +588,14 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string } //last look for /quests/global/default.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/"; filename += "default"; iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -608,7 +616,7 @@ QuestInterface *QuestParserCollection::GetQIByPlayerQuest(std::string &filename) return nullptr; //first look for /quests/zone/player_v[instance_version].ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/"; filename += "player_v"; @@ -616,10 +624,10 @@ QuestInterface *QuestParserCollection::GetQIByPlayerQuest(std::string &filename) std::string tmp; FILE *f = nullptr; - std::list::iterator iter = _load_precedence.begin(); + auto iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -633,7 +641,7 @@ QuestInterface *QuestParserCollection::GetQIByPlayerQuest(std::string &filename) } //second look for /quests/zone/player.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/"; filename += "player"; @@ -641,7 +649,7 @@ QuestInterface *QuestParserCollection::GetQIByPlayerQuest(std::string &filename) iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -655,14 +663,14 @@ QuestInterface *QuestParserCollection::GetQIByPlayerQuest(std::string &filename) } //third look for /quests/global/player.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/"; filename += "player"; iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -680,17 +688,17 @@ QuestInterface *QuestParserCollection::GetQIByPlayerQuest(std::string &filename) QuestInterface *QuestParserCollection::GetQIByGlobalNPCQuest(std::string &filename) { // simply look for /quests/global/global_npc.ext - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/"; filename += "global_npc"; std::string tmp; FILE *f = nullptr; - std::list::iterator iter = _load_precedence.begin(); + auto iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -708,17 +716,17 @@ QuestInterface *QuestParserCollection::GetQIByGlobalNPCQuest(std::string &filena QuestInterface *QuestParserCollection::GetQIByGlobalPlayerQuest(std::string &filename) { //first look for /quests/global/player.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/"; filename += "global_player"; std::string tmp; FILE *f = nullptr; - std::list::iterator iter = _load_precedence.begin(); + auto iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -736,17 +744,17 @@ QuestInterface *QuestParserCollection::GetQIByGlobalPlayerQuest(std::string &fil QuestInterface *QuestParserCollection::GetQIBySpellQuest(uint32 spell_id, std::string &filename) { //first look for /quests/zone/spells/spell_id.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/spells/"; filename += itoa(spell_id); std::string tmp; FILE *f = nullptr; - std::list::iterator iter = _load_precedence.begin(); + auto iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -760,7 +768,7 @@ QuestInterface *QuestParserCollection::GetQIBySpellQuest(uint32 spell_id, std::s } //second look for /quests/global/spells/spell_id.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/spells/"; filename += itoa(spell_id); @@ -768,7 +776,7 @@ QuestInterface *QuestParserCollection::GetQIBySpellQuest(uint32 spell_id, std::s iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -782,14 +790,14 @@ QuestInterface *QuestParserCollection::GetQIBySpellQuest(uint32 spell_id, std::s } //third look for /quests/zone/spells/default.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/spells/default"; iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -803,14 +811,14 @@ QuestInterface *QuestParserCollection::GetQIBySpellQuest(uint32 spell_id, std::s } //last look for /quests/global/spells/default.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/spells/default"; iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -828,17 +836,17 @@ QuestInterface *QuestParserCollection::GetQIBySpellQuest(uint32 spell_id, std::s QuestInterface *QuestParserCollection::GetQIByItemQuest(std::string item_script, std::string &filename) { //first look for /quests/zone/items/item_script.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/items/"; filename += item_script; std::string tmp; FILE *f = nullptr; - std::list::iterator iter = _load_precedence.begin(); + auto iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -852,7 +860,7 @@ QuestInterface *QuestParserCollection::GetQIByItemQuest(std::string item_script, } //second look for /quests/global/items/item_script.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/items/"; filename += item_script; @@ -860,7 +868,7 @@ QuestInterface *QuestParserCollection::GetQIByItemQuest(std::string item_script, iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -874,14 +882,14 @@ QuestInterface *QuestParserCollection::GetQIByItemQuest(std::string item_script, } //third look for /quests/zone/items/default.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/items/default"; iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -895,14 +903,14 @@ QuestInterface *QuestParserCollection::GetQIByItemQuest(std::string item_script, } //last look for /quests/global/items/default.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/items/default"; iter = _load_precedence.begin(); while(iter != _load_precedence.end()) { tmp = filename; - std::map::iterator ext = _extensions.find((*iter)->GetIdentifier()); + auto ext = _extensions.find((*iter)->GetIdentifier()); tmp += "."; tmp += ext->second; f = fopen(tmp.c_str(), "r"); @@ -920,7 +928,7 @@ QuestInterface *QuestParserCollection::GetQIByItemQuest(std::string item_script, QuestInterface *QuestParserCollection::GetQIByEncounterQuest(std::string encounter_name, std::string &filename) { //first look for /quests/zone/encounters/encounter_name.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += zone->GetShortName(); filename += "/encounters/"; filename += encounter_name; @@ -944,7 +952,7 @@ QuestInterface *QuestParserCollection::GetQIByEncounterQuest(std::string encount } //second look for /quests/global/encounters/encounter_name.ext (precedence) - filename = "quests/"; + filename = Config->QuestDir; filename += QUEST_GLOBAL_DIRECTORY; filename += "/encounters/"; filename += encounter_name; @@ -1032,3 +1040,42 @@ int QuestParserCollection::DispatchEventSpell(QuestEventID evt, NPC* npc, Client } return ret; } + +void QuestParserCollection::LoadPerlEventExportSettings(PerlEventExportSettings* perl_event_export_settings) { + + Log.Out(Logs::General, Logs::Zone_Server, "Loading Perl Event Export Settings..."); + + /* Write Defaults First (All Enabled) */ + for (int i = 0; i < _LargestEventID; i++){ + perl_event_export_settings[i].qglobals = 1; + perl_event_export_settings[i].mob = 1; + perl_event_export_settings[i].zone = 1; + perl_event_export_settings[i].item = 1; + perl_event_export_settings[i].event_variables = 1; + } + + std::string query = + "SELECT " + "event_id, " + "event_description, " + "export_qglobals, " + "export_mob, " + "export_zone, " + "export_item, " + "export_event " + "FROM " + "perl_event_export_settings " + "ORDER BY event_id"; + + int event_id = 0; + auto results = database.QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + event_id = atoi(row[0]); + perl_event_export_settings[event_id].qglobals = atoi(row[2]); + perl_event_export_settings[event_id].mob = atoi(row[3]); + perl_event_export_settings[event_id].zone = atoi(row[4]); + perl_event_export_settings[event_id].item = atoi(row[5]); + perl_event_export_settings[event_id].event_variables = atoi(row[6]); + } + +} diff --git a/zone/quest_parser_collection.h b/zone/quest_parser_collection.h index 62cb034dc..c17e2ccda 100644 --- a/zone/quest_parser_collection.h +++ b/zone/quest_parser_collection.h @@ -21,6 +21,7 @@ #include "../common/types.h" +#include "encounter.h" #include "beacon.h" #include "client.h" #include "corpse.h" @@ -33,12 +34,15 @@ #include "quest_interface.h" +#include "zone_config.h" + #include #include #define QuestFailedToLoad 0xFFFFFFFF #define QuestUnloaded 0x00 +extern const ZoneConfig *Config; class Client; class ItemInst; class Mob; @@ -71,11 +75,32 @@ public: std::vector *extra_pointers = nullptr); int EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, std::vector *extra_pointers = nullptr); - int EventEncounter(QuestEventID evt, std::string encounter_name, uint32 extra_data, + int EventEncounter(QuestEventID evt, std::string encounter_name, std::string data, uint32 extra_data, std::vector *extra_pointers = nullptr); void GetErrors(std::list &err); + /* + Internally used memory reference for all Perl Event Export Settings + Some exports are very taxing on CPU given how much an event is called. + + These are loaded via DB and have defaults loaded in PerlEventExportSettingsDefaults. + + Database loaded via Database::LoadPerlEventExportSettings(log_settings) + */ + + struct PerlEventExportSettings { + uint8 qglobals; + uint8 mob; + uint8 zone; + uint8 item; + uint8 event_variables; + }; + + PerlEventExportSettings perl_event_export_settings[_LargestEventID]; + + void LoadPerlEventExportSettings(PerlEventExportSettings* perl_event_export_settings); + private: bool HasQuestSubLocal(uint32 npcid, QuestEventID evt); bool HasQuestSubGlobal(QuestEventID evt); diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 97992e0bc..78fc2b206 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -22,6 +22,7 @@ #include "../common/skills.h" #include "../common/spdat.h" #include "../common/string_util.h" +#include "../common/say_link.h" #include "entity.h" #include "event_codes.h" @@ -84,6 +85,8 @@ void QuestManager::Process() { if(entity_list.IsMobInZone(cur->mob)) { if(cur->mob->IsNPC()) { parse->EventNPC(EVENT_TIMER, cur->mob->CastToNPC(), nullptr, cur->name, 0); + } else if (cur->mob->IsEncounter()) { + parse->EventEncounter(EVENT_TIMER, cur->mob->CastToEncounter()->GetEncounterName(), cur->name, 0, nullptr); } else { //this is inheriently unsafe if we ever make it so more than npc/client start timers parse->EventPlayer(EVENT_TIMER, cur->mob->CastToClient(), cur->name, 0); @@ -205,7 +208,7 @@ Mob* QuestManager::spawn2(int npc_type, int grid, int unused, const glm::vec4& p const NPCType* tmp = 0; if (tmp = database.LoadNPCTypesData(npc_type)) { - NPC* npc = new NPC(tmp, nullptr, position, FlyMode3); + auto npc = new NPC(tmp, nullptr, position, FlyMode3); npc->AddLootTable(); entity_list.AddNPC(npc,true,true); if(grid > 0) @@ -227,7 +230,7 @@ Mob* QuestManager::unique_spawn(int npc_type, int grid, int unused, const glm::v const NPCType* tmp = 0; if (tmp = database.LoadNPCTypesData(npc_type)) { - NPC* npc = new NPC(tmp, nullptr, position, FlyMode3); + auto npc = new NPC(tmp, nullptr, position, FlyMode3); npc->AddLootTable(); entity_list.AddNPC(npc,true,true); if(grid > 0) @@ -301,19 +304,20 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id) found_spawn->SetCurrentNPCID(npcid); auto position = glm::vec4(found_spawn->GetX(), found_spawn->GetY(), found_spawn->GetZ(), found_spawn->GetHeading()); - NPC* npc = new NPC(tmp, found_spawn, position, FlyMode3); + auto npc = new NPC(tmp, found_spawn, position, FlyMode3); - found_spawn->SetNPCPointer(npc); - npc->AddLootTable(); - npc->SetSp2(found_spawn->SpawnGroupID()); - entity_list.AddNPC(npc); - entity_list.LimitAddNPC(npc); + found_spawn->SetNPCPointer(npc); + npc->AddLootTable(); + npc->SetSp2(found_spawn->SpawnGroupID()); + entity_list.AddNPC(npc); + entity_list.LimitAddNPC(npc); - if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay && sg->min_delay) - npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay,sg->min_delay); - if(zone->InstantGrids()) - { - found_spawn->LoadGrid(); + if (sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay && + sg->min_delay) + npc->AI_SetRoambox(sg->roamdist, sg->roambox[0], sg->roambox[1], sg->roambox[2], sg->roambox[3], + sg->delay, sg->min_delay); + if (zone->InstantGrids()) { + found_spawn->LoadGrid(); } return npc; @@ -325,7 +329,7 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id) void QuestManager::enable_spawn2(uint32 spawn2_id) { database.UpdateSpawn2Status(spawn2_id, 1); - ServerPacket* pack = new ServerPacket(ServerOP_SpawnStatusChange, sizeof(ServerSpawnStatusChange_Struct)); + auto pack = new ServerPacket(ServerOP_SpawnStatusChange, sizeof(ServerSpawnStatusChange_Struct)); ServerSpawnStatusChange_Struct* ssc = (ServerSpawnStatusChange_Struct*) pack->pBuffer; ssc->id = spawn2_id; ssc->new_status = 1; @@ -336,7 +340,7 @@ void QuestManager::enable_spawn2(uint32 spawn2_id) void QuestManager::disable_spawn2(uint32 spawn2_id) { database.UpdateSpawn2Status(spawn2_id, 0); - ServerPacket* pack = new ServerPacket(ServerOP_SpawnStatusChange, sizeof(ServerSpawnStatusChange_Struct)); + auto pack = new ServerPacket(ServerOP_SpawnStatusChange, sizeof(ServerSpawnStatusChange_Struct)); ServerSpawnStatusChange_Struct* ssc = (ServerSpawnStatusChange_Struct*) pack->pBuffer; ssc->id = spawn2_id; ssc->new_status = 0; @@ -361,14 +365,14 @@ void QuestManager::castspell(int spell_id, int target_id) { if (owner) { Mob *tgt = entity_list.GetMob(target_id); if(tgt != nullptr) - owner->SpellFinished(spell_id, tgt, 10, 0, -1, spells[spell_id].ResistDiff); + owner->SpellFinished(spell_id, tgt, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff); } } void QuestManager::selfcast(int spell_id) { QuestManagerCurrentQuestVars(); if (initiator) - initiator->SpellFinished(spell_id, initiator, 10, 0, -1, spells[spell_id].ResistDiff); + initiator->SpellFinished(spell_id, initiator, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff); } void QuestManager::addloot(int item_id, int charges, bool equipitem) { @@ -383,7 +387,7 @@ void QuestManager::Zone(const char *zone_name) { QuestManagerCurrentQuestVars(); if (initiator && initiator->IsClient()) { - ServerPacket* pack = new ServerPacket(ServerOP_ZoneToZoneRequest, sizeof(ZoneToZone_Struct)); + auto pack = new ServerPacket(ServerOP_ZoneToZoneRequest, sizeof(ZoneToZone_Struct)); ZoneToZone_Struct* ztz = (ZoneToZone_Struct*) pack->pBuffer; ztz->response = 0; ztz->current_zone_id = zone->GetZoneID(); @@ -668,6 +672,79 @@ void QuestManager::repopzone() { } } +void QuestManager::ConnectNodeToNode(int node1, int node2, int teleport, int doorid) { + if (!node1 || !node2) + { + Log.Out(Logs::General, Logs::Quests, "QuestManager::ConnectNodeToNode called without node1 or node2. Probably syntax error in quest file."); + } + else + { + if (!teleport) + { + teleport = 0; + } + else if (teleport == 1 || teleport == -1) + { + teleport = -1; + } + + if (!doorid) + { + doorid = 0; + } + + if (!zone->pathing) + { + // if no pathing bits available, make them available. + zone->pathing = new PathManager(); + } + + if (zone->pathing) + { + zone->pathing->ConnectNodeToNode(node1, node2, teleport, doorid); + Log.Out(Logs::Moderate, Logs::Quests, "QuestManager::ConnectNodeToNode connecting node %i to node %i.", node1, node2); + } + } +} + +void QuestManager::AddNode(float x, float y, float z, float best_z, int32 requested_id) +{ + if (!x || !y || !z) + { + Log.Out(Logs::General, Logs::Quests, "QuestManager::AddNode called without x, y, z. Probably syntax error in quest file."); + } + + if (!best_z || best_z == 0) + { + if (zone->zonemap) + { + glm::vec3 loc(x, y, z); + best_z = zone->zonemap->FindBestZ(loc, nullptr); + } + else + { + best_z = z; + } + } + + if (!requested_id) + { + requested_id = 0; + } + + if (!zone->pathing) + { + // if no pathing bits available, make them available. + zone->pathing = new PathManager(); + } + + if (zone->pathing) + { + zone->pathing->AddNode(x, y, z, best_z, requested_id); + Log.Out(Logs::Moderate, Logs::Quests, "QuestManager::AddNode adding node at (%i, %i, %i).", x, y, z); + } +} + void QuestManager::settarget(const char *type, int target_id) { QuestManagerCurrentQuestVars(); if (!owner || !owner->IsNPC()) @@ -737,12 +814,12 @@ void QuestManager::traindisc(int discipline_tome_item_id) { } bool QuestManager::isdisctome(int item_id) { - const Item_Struct *item = database.GetItem(item_id); + const EQEmu::ItemBase *item = database.GetItem(item_id); if(item == nullptr) { return(false); } - if(item->ItemClass != ItemClassCommon || item->ItemType != ItemTypeSpell) { + if (!item->IsClassCommon() || item->ItemType != EQEmu::item::ItemTypeSpell) { return(false); } @@ -799,13 +876,13 @@ bool QuestManager::isdisctome(int item_id) { void QuestManager::safemove() { QuestManagerCurrentQuestVars(); if (initiator && initiator->IsClient()) - initiator->GoToSafeCoords(zone->GetZoneID(), 0); + initiator->GoToSafeCoords(zone->GetZoneID(), zone->GetInstanceID()); } void QuestManager::rain(int weather) { QuestManagerCurrentQuestVars(); zone->zone_weather = weather; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weather, 8); + auto outapp = new EQApplicationPacket(OP_Weather, 8); *((uint32*) &outapp->pBuffer[4]) = (uint32) weather; // Why not just use 0x01/2/3? entity_list.QueueClients(owner, outapp); safe_delete(outapp); @@ -814,7 +891,7 @@ void QuestManager::rain(int weather) { void QuestManager::snow(int weather) { QuestManagerCurrentQuestVars(); zone->zone_weather = weather + 1; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weather, 8); + auto outapp = new EQApplicationPacket(OP_Weather, 8); outapp->pBuffer[0] = 0x01; *((uint32*) &outapp->pBuffer[4]) = (uint32)weather; entity_list.QueueClients(initiator, outapp); @@ -1076,10 +1153,10 @@ void QuestManager::doanim(int anim_id) { void QuestManager::addskill(int skill_id, int value) { QuestManagerCurrentQuestVars(); - if(skill_id < 0 || skill_id > HIGHEST_SKILL) + if (skill_id < 0 || skill_id > EQEmu::skills::HIGHEST_SKILL) return; if (initiator && initiator->IsClient()) - initiator->AddSkill((SkillUseTypes) skill_id, value); + initiator->AddSkill((EQEmu::skills::SkillType) skill_id, value); } void QuestManager::setlanguage(int skill_id, int value) { @@ -1090,10 +1167,10 @@ void QuestManager::setlanguage(int skill_id, int value) { void QuestManager::setskill(int skill_id, int value) { QuestManagerCurrentQuestVars(); - if(skill_id < 0 || skill_id > HIGHEST_SKILL) + if (skill_id < 0 || skill_id > EQEmu::skills::HIGHEST_SKILL) return; if (initiator && initiator->IsClient()) - initiator->SetSkill((SkillUseTypes) skill_id, value); + initiator->SetSkill((EQEmu::skills::SkillType) skill_id, value); } void QuestManager::setallskill(int value) { @@ -1101,8 +1178,8 @@ void QuestManager::setallskill(int value) { if (!initiator) return; if (initiator && initiator->IsClient()) { - SkillUseTypes sk; - for (sk = Skill1HBlunt; sk <= HIGHEST_SKILL; sk = (SkillUseTypes)(sk+1)) { + EQEmu::skills::SkillType sk; + for (sk = EQEmu::skills::Skill1HBlunt; sk <= EQEmu::skills::HIGHEST_SKILL; sk = (EQEmu::skills::SkillType)(sk + 1)) { initiator->SetSkill(sk, value); } } @@ -1178,7 +1255,7 @@ void QuestManager::setsky(uint8 new_sky) { QuestManagerCurrentQuestVars(); if (zone) zone->newzone_data.sky = new_sky; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); entity_list.QueueClients(initiator, outapp); safe_delete(outapp); @@ -1219,20 +1296,21 @@ void QuestManager::CreateGuild(const char *guild_name, const char *leader) { } } -void QuestManager::settime(uint8 new_hour, uint8 new_min) { +void QuestManager::settime(uint8 new_hour, uint8 new_min, bool update_world /*= true*/) +{ if (zone) - zone->SetTime(new_hour + 1, new_min); + zone->SetTime(new_hour + 1, new_min, update_world); } void QuestManager::itemlink(int item_id) { QuestManagerCurrentQuestVars(); if (initiator) { - const Item_Struct* item = database.GetItem(item_id); + const EQEmu::ItemBase* item = database.GetItem(item_id); if (item == nullptr) return; - Client::TextLink linker; - linker.SetLinkType(linker.linkItemData); + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemData); linker.SetItemData(item); auto item_link = linker.GenerateLink(); @@ -1325,23 +1403,23 @@ int QuestManager::InsertQuestGlobal(int charid, int npcid, int zoneid, const cha return 0; /* Delete existing qglobal data and update zone processes */ - ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); - ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer; - qgd->npc_id = npcid; - qgd->char_id = charid; - qgd->zone_id = zoneid; - qgd->from_zone_id = zone->GetZoneID(); - qgd->from_instance_id = zone->GetInstanceID(); - strcpy(qgd->name, varname); + auto pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); + ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct *)pack->pBuffer; + qgd->npc_id = npcid; + qgd->char_id = charid; + qgd->zone_id = zoneid; + qgd->from_zone_id = zone->GetZoneID(); + qgd->from_instance_id = zone->GetInstanceID(); + strcpy(qgd->name, varname); - entity_list.DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id); - zone->DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id); + entity_list.DeleteQGlobal(std::string((char *)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id); + zone->DeleteQGlobal(std::string((char *)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id); - worldserver.SendPacket(pack); - safe_delete(pack); + worldserver.SendPacket(pack); + safe_delete(pack); - /* Create new qglobal data and update zone processes */ - pack = new ServerPacket(ServerOP_QGlobalUpdate, sizeof(ServerQGlobalUpdate_Struct)); + /* Create new qglobal data and update zone processes */ + pack = new ServerPacket(ServerOP_QGlobalUpdate, sizeof(ServerQGlobalUpdate_Struct)); ServerQGlobalUpdate_Struct *qgu = (ServerQGlobalUpdate_Struct*)pack->pBuffer; qgu->npc_id = npcid; qgu->char_id = charid; @@ -1405,19 +1483,19 @@ void QuestManager::delglobal(const char *varname) { if(!zone) return; - ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); - ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer; + auto pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct)); + ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct *)pack->pBuffer; - qgu->npc_id = qgNpcid; - qgu->char_id = qgCharid; - qgu->zone_id = qgZoneid; - strcpy(qgu->name, varname); + qgu->npc_id = qgNpcid; + qgu->char_id = qgCharid; + qgu->zone_id = qgZoneid; + strcpy(qgu->name, varname); - entity_list.DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id); - zone->DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id); + entity_list.DeleteQGlobal(std::string((char *)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id); + zone->DeleteQGlobal(std::string((char *)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id); - worldserver.SendPacket(pack); - safe_delete(pack); + worldserver.SendPacket(pack); + safe_delete(pack); } // Converts duration string to duration value (in seconds) @@ -1489,7 +1567,7 @@ void QuestManager::ding() { void QuestManager::rebind(int zoneid, const glm::vec3& location) { QuestManagerCurrentQuestVars(); if(initiator && initiator->IsClient()) { - initiator->SetBindPoint(zoneid, 0, location); + initiator->SetBindPoint(0, zoneid, 0, location); } } @@ -1695,10 +1773,10 @@ void QuestManager::clear_zone_flag(int zone_id) { void QuestManager::sethp(int hpperc) { QuestManagerCurrentQuestVars(); int newhp = (owner->GetMaxHP() * (100 - hpperc)) / 100; - owner->Damage(owner, newhp, SPELL_UNKNOWN, SkillHandtoHand, false, 0, false); + owner->Damage(owner, newhp, SPELL_UNKNOWN, EQEmu::skills::SkillHandtoHand, false, 0, false); } -bool QuestManager::summonburriedplayercorpse(uint32 char_id, const glm::vec4& position) { +bool QuestManager::summonburiedplayercorpse(uint32 char_id, const glm::vec4& position) { bool Result = false; if(char_id <= 0) @@ -1722,7 +1800,7 @@ bool QuestManager::summonallplayercorpses(uint32 char_id, const glm::vec4& posit return true; } -uint32 QuestManager::getplayerburriedcorpsecount(uint32 char_id) { +uint32 QuestManager::getplayerburiedcorpsecount(uint32 char_id) { uint32 Result = 0; if(char_id > 0) { @@ -1965,35 +2043,39 @@ void QuestManager::popup(const char *title, const char *text, uint32 popupid, ui #ifdef BOTS int QuestManager::createbotcount() { - return RuleI(Bots, CreateBotCount); + return RuleI(Bots, CreationLimit); } int QuestManager::spawnbotcount() { - return RuleI(Bots, SpawnBotCount); + return RuleI(Bots, SpawnLimit); } bool QuestManager::botquest() { - return RuleB(Bots, BotQuest); + return RuleB(Bots, QuestableSpawnLimit); } bool QuestManager::createBot(const char *name, const char *lastname, uint8 level, uint16 race, uint8 botclass, uint8 gender) { QuestManagerCurrentQuestVars(); - std::string TempErrorMessage; - uint32 MaxBotCreate = RuleI(Bots, CreateBotCount); + uint32 MaxBotCreate = RuleI(Bots, CreationLimit); if (initiator && initiator->IsClient()) { - if(Bot::SpawnedBotCount(initiator->CharacterID(), &TempErrorMessage) >= MaxBotCreate) + if(Bot::SpawnedBotCount(initiator->CharacterID()) >= MaxBotCreate) { initiator->Message(15,"You have the maximum number of bots allowed."); return false; } - if(!TempErrorMessage.empty()) - { - initiator->Message(13, "Database Error: %s", TempErrorMessage.c_str()); + std::string test_name = name; + bool available_flag = false; + if(!botdb.QueryNameAvailablity(test_name, available_flag)) { + initiator->Message(0, "%s for '%s'", BotDatabase::fail::QueryNameAvailablity(), (char*)name); + return false; + } + if (!available_flag) { + initiator->Message(0, "The name %s is already being used or is invalid. Please choose a different name.", (char*)name); return false; } @@ -2012,16 +2094,6 @@ bool QuestManager::createBot(const char *name, const char *lastname, uint8 level return false; } - if(!NewBot->IsBotNameAvailable(&TempErrorMessage)) { - initiator->Message(0, "The name %s is already being used. Please choose a different name.", NewBot->GetCleanName()); - return false; - } - - if(!TempErrorMessage.empty()) { - initiator->Message(13, "Database Error: %s", TempErrorMessage.c_str()); - return false; - } - // Now that all validation is complete, we can save our newly created bot if(!NewBot->Save()) { @@ -2124,11 +2196,11 @@ void QuestManager::taskexploredarea(int exploreid) { initiator->UpdateTasksOnExplore(exploreid); } -void QuestManager::assigntask(int taskid) { +void QuestManager::assigntask(int taskid, bool enforce_level_requirement) { QuestManagerCurrentQuestVars(); - if(RuleB(TaskSystem, EnableTaskSystem) && initiator && owner) - initiator->AssignTask(taskid, owner->GetID()); + if (RuleB(TaskSystem, EnableTaskSystem) && initiator && owner) + initiator->AssignTask(taskid, owner->GetID(), enforce_level_requirement); } void QuestManager::failtask(int taskid) { @@ -2371,12 +2443,12 @@ int QuestManager::collectitems(uint32 item_id, bool remove) int quantity = 0; int slot_id; - for (slot_id = EmuConstants::GENERAL_BEGIN; slot_id <= EmuConstants::GENERAL_END; ++slot_id) + for (slot_id = EQEmu::legacy::GENERAL_BEGIN; slot_id <= EQEmu::legacy::GENERAL_END; ++slot_id) { quantity += collectitems_processSlot(slot_id, item_id, remove); } - for (slot_id = EmuConstants::GENERAL_BAGS_BEGIN; slot_id <= EmuConstants::GENERAL_BAGS_END; ++slot_id) + for (slot_id = EQEmu::legacy::GENERAL_BAGS_BEGIN; slot_id <= EQEmu::legacy::GENERAL_BAGS_END; ++slot_id) { quantity += collectitems_processSlot(slot_id, item_id, remove); } @@ -2409,7 +2481,7 @@ void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime) { //Spawn wasn't in this zone... //Tell the other zones to update their spawn time for this spawn point - ServerPacket *pack = new ServerPacket(ServerOP_UpdateSpawn, sizeof(UpdateSpawnTimer_Struct)); + auto pack = new ServerPacket(ServerOP_UpdateSpawn, sizeof(UpdateSpawnTimer_Struct)); UpdateSpawnTimer_Struct *ust = (UpdateSpawnTimer_Struct*)pack->pBuffer; ust->id = id; ust->duration = newTime; @@ -2425,7 +2497,7 @@ void QuestManager::MerchantSetItem(uint32 NPCid, uint32 itemid, uint32 quantity) if (merchant == 0 || !merchant->IsNPC() || (merchant->GetClass() != MERCHANT)) return; // don't do anything if NPCid isn't a merchant - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; item = database.GetItem(itemid); if (!item) return; // if the item id doesn't correspond to a real item, do nothing @@ -2438,7 +2510,7 @@ uint32 QuestManager::MerchantCountItem(uint32 NPCid, uint32 itemid) { if (merchant == 0 || !merchant->IsNPC() || (merchant->GetClass() != MERCHANT)) return 0; // if it isn't a merchant, it doesn't have any items - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; item = database.GetItem(itemid); if (!item) return 0; // if it isn't a valid item, the merchant doesn't have any @@ -2461,12 +2533,12 @@ uint32 QuestManager::MerchantCountItem(uint32 NPCid, uint32 itemid) { // Item Link for use in Variables - "my $example_link = quest::varlink(item_id);" const char* QuestManager::varlink(char* perltext, int item_id) { QuestManagerCurrentQuestVars(); - const Item_Struct* item = database.GetItem(item_id); + const EQEmu::ItemBase* item = database.GetItem(item_id); if (!item) return "INVALID ITEM ID IN VARLINK"; - Client::TextLink linker; - linker.SetLinkType(linker.linkItemData); + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemData); linker.SetItemData(item); auto item_link = linker.GenerateLink(); @@ -2506,6 +2578,45 @@ void QuestManager::DestroyInstance(uint16 instance_id) database.DeleteInstance(instance_id); } +void QuestManager::UpdateInstanceTimer(uint16 instance_id, uint32 new_duration) +{ + std::string query = StringFormat("UPDATE instance_list SET duration = %lu, start_time = UNIX_TIMESTAMP() WHERE id = %lu", + (unsigned long)new_duration, (unsigned long)instance_id); + auto results = database.QueryDatabase(query); + + if (results.Success()) { + auto pack = new ServerPacket(ServerOP_InstanceUpdateTime, sizeof(ServerInstanceUpdateTime_Struct)); + ServerInstanceUpdateTime_Struct *ut = (ServerInstanceUpdateTime_Struct*)pack->pBuffer; + ut->instance_id = instance_id; + ut->new_duration = new_duration; + worldserver.SendPacket(pack); + safe_delete(pack); + } +} + +uint32 QuestManager::GetInstanceTimer() { + if (zone && zone->GetInstanceID() > 0 && zone->GetInstanceTimer()) { + uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime(); + return ttime; + } + return 0; +} + +uint32 QuestManager::GetInstanceTimerByID(uint16 instance_id) { + if (instance_id == 0) + return 0; + + std::string query = StringFormat("SELECT ((start_time + duration) - UNIX_TIMESTAMP()) AS `remaining` FROM `instance_list` WHERE `id` = %lu", (unsigned long)instance_id); + auto results = database.QueryDatabase(query); + + if (results.Success()) { + auto row = results.begin(); + uint32 timer = atoi(row[0]); + return timer; + } + return 0; +} + uint16 QuestManager::GetInstanceID(const char *zone, int16 version) { QuestManagerCurrentQuestVars(); @@ -2622,7 +2733,7 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam int sayid = 0; int sz = strlen(Phrase); - char *escaped_string = new char[sz * 2]; + auto escaped_string = new char[sz * 2]; database.DoEscapeString(escaped_string, Phrase, sz); // Query for an existing phrase and id in the saylink table @@ -2651,14 +2762,13 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam } safe_delete_array(escaped_string); - if (silent) - sayid = sayid + 750000; - else - sayid = sayid + 500000; - //Create the say link as an item link hash - Client::TextLink linker; - linker.SetProxyItemID(sayid); + EQEmu::SayLinkEngine linker; + linker.SetProxyItemID(SAYLINK_ITEM_ID); + if (silent) + linker.SetProxyAugment2ID(sayid); + else + linker.SetProxyAugment1ID(sayid); linker.SetProxyText(LinkName); auto say_link = linker.GenerateLink(); @@ -2767,11 +2877,11 @@ void QuestManager::removetitle(int titleset) { initiator->RemoveTitle(titleset); } -void QuestManager::wearchange(uint8 slot, uint16 texture) +void QuestManager::wearchange(uint8 slot, uint16 texture, uint32 hero_forge_model /*= 0*/, uint32 elite_material /*= 0*/) { QuestManagerCurrentQuestVars(); if(owner){ - owner->SendTextureWC(slot, texture); + owner->SendTextureWC(slot, texture, hero_forge_model, elite_material); if(owner->IsNPC()) { owner->CastToNPC()->NPCSlotTexture(slot, texture); } @@ -2787,7 +2897,7 @@ void QuestManager::voicetell(const char *str, int macronum, int racenum, int gen if(c) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_VoiceMacroOut, sizeof(VoiceMacroOut_Struct)); + auto outapp = new EQApplicationPacket(OP_VoiceMacroOut, sizeof(VoiceMacroOut_Struct)); VoiceMacroOut_Struct* vmo = (VoiceMacroOut_Struct*)outapp->pBuffer; @@ -2821,7 +2931,7 @@ void QuestManager::SendMail(const char *to, const char *from, const char *subjec } uint32 message_len = strlen(message) + 1; - ServerPacket* pack = new ServerPacket(ServerOP_UCSMailMessage, sizeof(ServerMailMessageHeader_Struct) + message_len); + auto pack = new ServerPacket(ServerOP_UCSMailMessage, sizeof(ServerMailMessageHeader_Struct) + message_len); ServerMailMessageHeader_Struct* mail = (ServerMailMessageHeader_Struct*) pack->pBuffer; strn0cpy(mail->to, to, 64); @@ -2854,7 +2964,7 @@ const char* QuestManager::GetZoneLongName(const char *zone) { } void QuestManager::CrossZoneSignalNPCByNPCTypeID(uint32 npctype_id, uint32 data){ - ServerPacket* pack = new ServerPacket(ServerOP_CZSignalNPC, sizeof(CZNPCSignal_Struct)); + auto pack = new ServerPacket(ServerOP_CZSignalNPC, sizeof(CZNPCSignal_Struct)); CZNPCSignal_Struct* CZSN = (CZNPCSignal_Struct*)pack->pBuffer; CZSN->npctype_id = npctype_id; CZSN->data = data; @@ -2863,7 +2973,7 @@ void QuestManager::CrossZoneSignalNPCByNPCTypeID(uint32 npctype_id, uint32 data) } void QuestManager::CrossZoneSignalPlayerByCharID(int charid, uint32 data){ - ServerPacket* pack = new ServerPacket(ServerOP_CZSignalClient, sizeof(CZClientSignal_Struct)); + auto pack = new ServerPacket(ServerOP_CZSignalClient, sizeof(CZClientSignal_Struct)); CZClientSignal_Struct* CZSC = (CZClientSignal_Struct*) pack->pBuffer; CZSC->charid = charid; CZSC->data = data; @@ -2873,7 +2983,7 @@ void QuestManager::CrossZoneSignalPlayerByCharID(int charid, uint32 data){ void QuestManager::CrossZoneSignalPlayerByName(const char *CharName, uint32 data){ uint32 message_len = strlen(CharName) + 1; - ServerPacket* pack = new ServerPacket(ServerOP_CZSignalClientByName, sizeof(CZClientSignalByName_Struct) + message_len); + auto pack = new ServerPacket(ServerOP_CZSignalClientByName, sizeof(CZClientSignalByName_Struct) + message_len); CZClientSignalByName_Struct* CZSC = (CZClientSignalByName_Struct*) pack->pBuffer; strn0cpy(CZSC->Name, CharName, 64); CZSC->data = data; @@ -2884,7 +2994,8 @@ void QuestManager::CrossZoneSignalPlayerByName(const char *CharName, uint32 data void QuestManager::CrossZoneMessagePlayerByName(uint32 Type, const char *CharName, const char *Message){ uint32 message_len = strlen(CharName) + 1; uint32 message_len2 = strlen(Message) + 1; - ServerPacket* pack = new ServerPacket(ServerOP_CZMessagePlayer, sizeof(CZMessagePlayer_Struct) + message_len + message_len2); + auto pack = + new ServerPacket(ServerOP_CZMessagePlayer, sizeof(CZMessagePlayer_Struct) + message_len + message_len2); CZMessagePlayer_Struct* CZSC = (CZMessagePlayer_Struct*) pack->pBuffer; CZSC->Type = Type; strn0cpy(CZSC->CharName, CharName, 64); @@ -2896,7 +3007,8 @@ void QuestManager::CrossZoneMessagePlayerByName(uint32 Type, const char *CharNam void QuestManager::CrossZoneSetEntityVariableByNPCTypeID(uint32 npctype_id, const char *id, const char *m_var){ uint32 message_len = strlen(id) + 1; uint32 message_len2 = strlen(m_var) + 1; - ServerPacket* pack = new ServerPacket(ServerOP_CZSetEntityVariableByNPCTypeID, sizeof(CZSetEntVarByNPCTypeID_Struct) + message_len + message_len2); + auto pack = new ServerPacket(ServerOP_CZSetEntityVariableByNPCTypeID, + sizeof(CZSetEntVarByNPCTypeID_Struct) + message_len + message_len2); CZSetEntVarByNPCTypeID_Struct* CZSNBYNID = (CZSetEntVarByNPCTypeID_Struct*)pack->pBuffer; CZSNBYNID->npctype_id = npctype_id; strn0cpy(CZSNBYNID->id, id, 256); @@ -2927,6 +3039,13 @@ void QuestManager::ClearNPCTypeCache(int npctype_id) { } } +void QuestManager::ReloadZoneStaticData() +{ + if (zone) { + zone->ReloadStaticData(); + } +} + Client *QuestManager::GetInitiator() const { if(!quests_running_.empty()) { running_quest e = quests_running_.top(); @@ -2971,3 +3090,75 @@ std::string QuestManager::GetEncounter() const { return ""; } + +void QuestManager::UpdateZoneHeader(std::string type, std::string value) { + if (strcasecmp(type.c_str(), "ztype") == 0) + zone->newzone_data.ztype = atoi(value.c_str()); + else if (strcasecmp(type.c_str(), "fog_red") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_red[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "fog_green") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_green[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "fog_blue") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_blue[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "fog_minclip") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_minclip[i] = atof(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "fog_maxclip") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_maxclip[i] = atof(value.c_str()); + } + } + else if (strcasecmp(type.c_str(), "gravity") == 0) + zone->newzone_data.gravity = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "time_type") == 0) + zone->newzone_data.time_type = atoi(value.c_str()); + else if (strcasecmp(type.c_str(), "rain_chance") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.rain_chance[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "rain_duration") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.rain_duration[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "snow_chance") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.snow_chance[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "snow_duration") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.snow_duration[i] = atoi(value.c_str()); + } + } + else if (strcasecmp(type.c_str(), "sky") == 0) + zone->newzone_data.sky = atoi(value.c_str()); + else if (strcasecmp(type.c_str(), "safe_x") == 0) + zone->newzone_data.safe_x = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "safe_y") == 0) + zone->newzone_data.safe_y = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "safe_z") == 0) + zone->newzone_data.safe_z = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "max_z") == 0) + zone->newzone_data.max_z = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "underworld") == 0) + zone->newzone_data.underworld = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "minclip") == 0) + zone->newzone_data.minclip = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "maxclip") == 0) + zone->newzone_data.maxclip = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "fog_density") == 0) + zone->newzone_data.fog_density = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "suspendbuffs") == 0) + zone->newzone_data.SuspendBuffs = atoi(value.c_str()); + + auto outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); + entity_list.QueueClients(0, outapp); + safe_delete(outapp); +} diff --git a/zone/questmgr.h b/zone/questmgr.h index 7051bbb2b..612c7815f 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -87,6 +87,8 @@ public: void depopall(int npc_type = 0); void depopzone(bool StartSpawnTimer = true); void repopzone(); + void ConnectNodeToNode(int node1, int node2, int teleport, int doorid); + void AddNode(float x, float y, float z, float best_z, int32 requested_id); void settarget(const char *type, int target_id); void follow(int entity_id, int distance); void sfollow(); @@ -124,7 +126,7 @@ public: void setsky(uint8 new_sky); void setguild(uint32 new_guild_id, uint8 new_rank); void CreateGuild(const char *guild_name, const char *leader); - void settime(uint8 new_hour, uint8 new_min); + void settime(uint8 new_hour, uint8 new_min, bool update_world = true); void itemlink(int item_id); void signal(int npc_id, int wait_ms = 0); void signalwith(int npc_id, int signal_id, int wait_ms = 0); @@ -157,9 +159,9 @@ public: void set_zone_flag(int zone_id); void clear_zone_flag(int zone_id); void sethp(int hpperc); - bool summonburriedplayercorpse(uint32 char_id, const glm::vec4& position); + bool summonburiedplayercorpse(uint32 char_id, const glm::vec4& position); bool summonallplayercorpses(uint32 char_id, const glm::vec4& position); - uint32 getplayerburriedcorpsecount(uint32 char_id); + uint32 getplayerburiedcorpsecount(uint32 char_id); bool buryplayercorpse(uint32 char_id); void forcedooropen(uint32 doorid, bool altmode); void forcedoorclose(uint32 doorid, bool altmode); @@ -186,7 +188,7 @@ public: void updatetaskactivity(int task, int activity, int count, bool ignore_quest_update = false); void resettaskactivity(int task, int activity); void taskexploredarea(int exploreid); - void assigntask(int taskid); + void assigntask(int taskid, bool enforce_level_requirement = false); void failtask(int taskid); int tasktimeleft(int taskid); int istaskcompleted(int taskid); @@ -215,6 +217,10 @@ public: void MerchantSetItem(uint32 NPCid, uint32 itemid, uint32 quantity = 0); uint32 MerchantCountItem(uint32 NPCid, uint32 itemid); uint16 CreateInstance(const char *zone, int16 version, uint32 duration); + void UpdateInstanceTimer(uint16 instance_id, uint32 new_duration); + void UpdateZoneHeader(std::string type, std::string value); + uint32 GetInstanceTimer(); + uint32 GetInstanceTimerByID(uint16 instance_id = 0); void DestroyInstance(uint16 instance_id); uint16 GetInstanceID(const char *zone, int16 version); void AssignToInstance(uint16 instance_id); @@ -234,7 +240,7 @@ public: bool IsRunning(); void FlyMode(uint8 flymode); uint8 FactionValue(); - void wearchange(uint8 slot, uint16 texture); + void wearchange(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0); void voicetell(const char *str, int macronum, int racenum, int gendernum); void LearnRecipe(uint32 recipe_id); void SendMail(const char *to, const char *from, const char *subject, const char *message); @@ -249,6 +255,7 @@ public: bool EnableRecipe(uint32 recipe_id); bool DisableRecipe(uint32 recipe_id); void ClearNPCTypeCache(int npctype_id); + void ReloadZoneStaticData(); Client *GetInitiator() const; NPC *GetNPC() const; diff --git a/zone/raids.cpp b/zone/raids.cpp index 7406b575f..ff9e84578 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -121,7 +121,7 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo c->SetRaidGrouped(true); SendRaidMOTD(c); - ServerPacket *pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); strn0cpy(rga->playername, c->GetName(), 64); @@ -146,7 +146,7 @@ void Raid::RemoveMember(const char *characterName) if(client) client->SetRaidGrouped(false); - ServerPacket *pack = new ServerPacket(ServerOP_RaidRemove, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidRemove, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); rga->instance_id = zone->GetInstanceID(); @@ -165,7 +165,7 @@ void Raid::DisbandRaid() VerifyRaid(); SendRaidDisbandAll(); - ServerPacket *pack = new ServerPacket(ServerOP_RaidDisband, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidDisband, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); strn0cpy(rga->playername, " ", 64); @@ -187,7 +187,7 @@ void Raid::MoveMember(const char *name, uint32 newGroup) VerifyRaid(); SendRaidMoveAll(name); - ServerPacket *pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidChangeGroup, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); strn0cpy(rga->playername, name, 64); @@ -206,7 +206,7 @@ void Raid::SetGroupLeader(const char *who, bool glFlag) LearnMembers(); VerifyRaid(); - ServerPacket *pack = new ServerPacket(ServerOP_RaidGroupLeader, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidGroupLeader, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); strn0cpy(rga->playername, who, 64); @@ -250,7 +250,7 @@ void Raid::SetRaidLeader(const char *wasLead, const char *name) VerifyRaid(); SendMakeLeaderPacket(name); - ServerPacket *pack = new ServerPacket(ServerOP_RaidLeader, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidLeader, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); strn0cpy(rga->playername, name, 64); @@ -262,7 +262,7 @@ void Raid::SetRaidLeader(const char *wasLead, const char *name) void Raid::SaveGroupLeaderAA(uint32 gid) { - char *queryBuffer = new char[sizeof(GroupLeadershipAA_Struct) * 2 + 1]; + auto queryBuffer = new char[sizeof(GroupLeadershipAA_Struct) * 2 + 1]; database.DoEscapeString(queryBuffer, (char*)&group_aa[gid], sizeof(GroupLeadershipAA_Struct)); std::string query = "UPDATE raid_leaders SET leadershipaa = '"; @@ -276,7 +276,7 @@ void Raid::SaveGroupLeaderAA(uint32 gid) void Raid::SaveRaidLeaderAA() { - char *queryBuffer = new char[sizeof(RaidLeadershipAA_Struct) * 2 + 1]; + auto queryBuffer = new char[sizeof(RaidLeadershipAA_Struct) * 2 + 1]; database.DoEscapeString(queryBuffer, (char*)&raid_aa, sizeof(RaidLeadershipAA_Struct)); std::string query = "UPDATE raid_leaders SET leadershipaa = '"; @@ -414,7 +414,7 @@ void Raid::RaidSay(const char *msg, Client *c) if(!c) return; - ServerPacket *pack = new ServerPacket(ServerOP_RaidSay, sizeof(ServerRaidMessage_Struct) + strlen(msg) + 1); + auto pack = new ServerPacket(ServerOP_RaidSay, sizeof(ServerRaidMessage_Struct) + strlen(msg) + 1); ServerRaidMessage_Struct *rga = (ServerRaidMessage_Struct*)pack->pBuffer; rga->rid = GetID(); rga->gid = 0xFFFFFFFF; @@ -436,7 +436,7 @@ void Raid::RaidGroupSay(const char *msg, Client *c) if(groupToUse > 11) return; - ServerPacket *pack = new ServerPacket(ServerOP_RaidGroupSay, sizeof(ServerRaidMessage_Struct) + strlen(msg) + 1); + auto pack = new ServerPacket(ServerOP_RaidGroupSay, sizeof(ServerRaidMessage_Struct) + strlen(msg) + 1); ServerRaidMessage_Struct *rga = (ServerRaidMessage_Struct*)pack->pBuffer; rga->rid = GetID(); rga->gid = groupToUse; @@ -852,7 +852,7 @@ void Raid::AddRaidLooter(const char* looter) break; } } - ServerPacket *pack = new ServerPacket(ServerOP_DetailsChange, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_DetailsChange, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); rga->zoneid = zone->GetZoneID(); @@ -872,7 +872,7 @@ void Raid::RemoveRaidLooter(const char* looter) break; } - ServerPacket *pack = new ServerPacket(ServerOP_DetailsChange, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_DetailsChange, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); rga->zoneid = zone->GetZoneID(); @@ -925,7 +925,7 @@ void Raid::SendRaidCreate(Client *to){ if(!to) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidJoin,sizeof(RaidCreate_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidJoin, sizeof(RaidCreate_Struct)); RaidCreate_Struct *rc = (RaidCreate_Struct*)outapp->pBuffer; rc->action = raidCreate; strn0cpy(rc->leader_name, leadername, 64); @@ -943,7 +943,7 @@ void Raid::SendRaidAdd(const char *who, Client *to) { if(strcmp(members[x].membername, who) == 0) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer; ram->raidGen.action = raidAdd; ram->raidGen.parameter = members[x].GroupNumber; @@ -965,7 +965,7 @@ void Raid::SendRaidAddAll(const char *who) { if(strcmp(members[x].membername, who) == 0) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidAddMember_Struct)); RaidAddMember_Struct *ram = (RaidAddMember_Struct*)outapp->pBuffer; ram->raidGen.action = raidAdd; ram->raidGen.parameter = members[x].GroupNumber; @@ -990,7 +990,7 @@ void Raid::SendRaidRemove(const char *who, Client *to) { if(strcmp(members[x].membername, who) == 0) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; rg->action = raidRemove2; strn0cpy(rg->leader_name, who, 64); @@ -1009,7 +1009,7 @@ void Raid::SendRaidRemoveAll(const char *who) { if(strcmp(members[x].membername, who) == 0) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; rg->action = raidRemove2; strn0cpy(rg->leader_name, who, 64); @@ -1027,7 +1027,7 @@ void Raid::SendRaidDisband(Client *to) if(!to) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; rg->action = raidDisband; strn0cpy(rg->leader_name, to->GetName(), 64); @@ -1039,7 +1039,7 @@ void Raid::SendRaidDisband(Client *to) void Raid::SendRaidDisbandAll() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; rg->action = raidDisband; strn0cpy(rg->leader_name, "RaidMember", 64); @@ -1110,7 +1110,7 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req) void Raid::SendMakeLeaderPacket(const char *who) //30 { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer; rg->action = raidMakeLeader; strn0cpy(rg->leader_name, who, 64); @@ -1125,7 +1125,7 @@ void Raid::SendMakeLeaderPacketTo(const char *who, Client *to) if(!to) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer; rg->action = raidMakeLeader; strn0cpy(rg->leader_name, who, 64); @@ -1155,7 +1155,7 @@ void Raid::SendGroupUpdate(Client *to) if(!to) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupUpdate2_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct)); GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer; gu->action = groupActUpdate; int index = 0; @@ -1209,7 +1209,7 @@ void Raid::GroupUpdate(uint32 gid, bool initial) } } if(initial){ - ServerPacket *pack = new ServerPacket(ServerOP_UpdateGroup, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_UpdateGroup, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct* rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->gid = gid; rga->rid = GetID(); @@ -1222,7 +1222,7 @@ void Raid::GroupUpdate(uint32 gid, bool initial) void Raid::SendRaidLock() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; rg->action = raidLock; strn0cpy(rg->leader_name, leadername, 64); @@ -1233,7 +1233,7 @@ void Raid::SendRaidLock() void Raid::SendRaidUnlock() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; rg->action = raidUnlock; strn0cpy(rg->leader_name, leadername, 64); @@ -1247,7 +1247,7 @@ void Raid::SendRaidLockTo(Client *c) if(!c) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; rg->action = raidLock; strn0cpy(rg->leader_name, c->GetName(), 64); @@ -1261,7 +1261,7 @@ void Raid::SendRaidUnlockTo(Client *c) if(!c) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct)); RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer; rg->action = raidUnlock; strn0cpy(rg->leader_name, c->GetName(), 64); @@ -1275,7 +1275,7 @@ void Raid::SendGroupDisband(Client *to) if(!to) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate_Struct)); GroupUpdate_Struct* gu = (GroupUpdate_Struct*) outapp->pBuffer; gu->action = groupActDisband; strn0cpy(gu->leadersname, leadername, 64); @@ -1285,7 +1285,7 @@ void Raid::SendGroupDisband(Client *to) void Raid::SendRaidGroupAdd(const char *who, uint32 gid) { - ServerPacket *pack = new ServerPacket(ServerOP_RaidGroupAdd, sizeof(ServerRaidGroupAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidGroupAdd, sizeof(ServerRaidGroupAction_Struct)); ServerRaidGroupAction_Struct * rga = (ServerRaidGroupAction_Struct*)pack->pBuffer; rga->rid = GetID(); rga->gid = gid; @@ -1295,7 +1295,7 @@ void Raid::SendRaidGroupAdd(const char *who, uint32 gid) void Raid::SendRaidGroupRemove(const char *who, uint32 gid) { - ServerPacket *pack = new ServerPacket(ServerOP_RaidGroupRemove, sizeof(ServerRaidGroupAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidGroupRemove, sizeof(ServerRaidGroupAction_Struct)); ServerRaidGroupAction_Struct * rga = (ServerRaidGroupAction_Struct*)pack->pBuffer; rga->rid = GetID(); rga->gid = gid; @@ -1309,7 +1309,7 @@ void Raid::SendRaidMOTD(Client *c) return; size_t size = motd.size() + 1; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidMOTD_Struct) + size); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidMOTD_Struct) + size); RaidMOTD_Struct *rmotd = (RaidMOTD_Struct *)outapp->pBuffer; rmotd->general.action = raidSetMotd; strn0cpy(rmotd->general.player_name, c->GetName(), 64); @@ -1333,7 +1333,7 @@ void Raid::SendRaidMOTDToWorld() return; size_t size = motd.size() + 1; - ServerPacket *pack = new ServerPacket(ServerOP_RaidMOTD, sizeof(ServerRaidMOTD_Struct) + size); + auto pack = new ServerPacket(ServerOP_RaidMOTD, sizeof(ServerRaidMOTD_Struct) + size); ServerRaidMOTD_Struct *smotd = (ServerRaidMOTD_Struct *)pack->pBuffer; smotd->rid = GetID(); strn0cpy(smotd->motd, motd.c_str(), size); @@ -1343,7 +1343,7 @@ void Raid::SendRaidMOTDToWorld() void Raid::SendGroupLeadershipAA(Client *c, uint32 gid) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct)); RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer; rlaa->action = raidSetLeaderAbilities; strn0cpy(rlaa->leader_name, c->GetName(), 64); @@ -1381,7 +1381,7 @@ void Raid::LockRaid(bool lockFlag) else SendRaidUnlock(); - ServerPacket *pack = new ServerPacket(ServerOP_RaidLockFlag, sizeof(ServerRaidGeneralAction_Struct)); + auto pack = new ServerPacket(ServerOP_RaidLockFlag, sizeof(ServerRaidGeneralAction_Struct)); ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer; rga->rid = GetID(); rga->zoneid = zone->GetZoneID(); @@ -1529,7 +1529,7 @@ void Raid::SendHPPacketsTo(Client *c) { members[x].member->CreateHPPacket(&hpapp); c->QueuePacket(&hpapp, false); - if(c->GetClientVersion() >= ClientVersion::SoD) + if (c->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobManaUpdate); MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp.pBuffer; @@ -1565,7 +1565,7 @@ void Raid::SendHPPacketsFrom(Mob *m) if(!m->IsClient() || ((members[x].member != m->CastToClient()) && (members[x].GroupNumber == gid))) { members[x].member->QueuePacket(&hpapp, false); - if(members[x].member->GetClientVersion() >= ClientVersion::SoD) + if (members[x].member->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { outapp.SetOpcode(OP_MobManaUpdate); MobManaUpdate_Struct *mmus = (MobManaUpdate_Struct *)outapp.pBuffer; diff --git a/zone/raycast_mesh.cpp b/zone/raycast_mesh.cpp index 078f225a1..0fa411836 100644 --- a/zone/raycast_mesh.cpp +++ b/zone/raycast_mesh.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -518,8 +519,7 @@ public: // Copy the triangle indices into the leaf triangles array mLeafTriangleIndex = leafTriangles.size(); // assign the array start location for these leaf triangles. leafTriangles.push_back(count); - for (TriVector::const_iterator i=triangles.begin(); i!=triangles.end(); ++i) - { + for (auto i = triangles.begin(); i != triangles.end(); ++i) { RmUint32 tri = *i; leafTriangles.push_back(tri); } @@ -541,8 +541,7 @@ public: // Create two arrays; one of all triangles which intersect the 'left' half of the bounding volume node // and another array that includes all triangles which intersect the 'right' half of the bounding volume node. - for (TriVector::const_iterator i=triangles.begin(); i!=triangles.end(); ++i) - { + for (auto i = triangles.begin(); i != triangles.end(); ++i) { RmUint32 tri = (*i); @@ -916,6 +915,11 @@ public: RmUint32 mMaxNodeCount; NodeAABB *mNodes; TriVector mLeafTriangles; + +#ifdef USE_MAP_MMFS + MyRaycastMesh(std::vector& rm_buffer); + void serialize(std::vector& rm_buffer); +#endif /*USE_MAP_MMFS*/ }; }; @@ -934,8 +938,257 @@ RaycastMesh * createRaycastMesh(RmUint32 vcount, // The number of vertices in t RmReal minAxisSize // once a particular axis is less than this size, stop sub-dividing. ) { - MyRaycastMesh *m = new MyRaycastMesh(vcount,vertices,tcount,indices,maxDepth,minLeafSize,minAxisSize); + auto m = new MyRaycastMesh(vcount, vertices, tcount, indices, maxDepth, minLeafSize, minAxisSize); return static_cast< RaycastMesh * >(m); } +#ifdef USE_MAP_MMFS +RaycastMesh* loadRaycastMesh(std::vector& rm_buffer, bool& load_success) +{ + if (rm_buffer.empty()) + return nullptr; + auto m = new MyRaycastMesh(rm_buffer); + load_success = (m->mNodes != nullptr); + + return static_cast(m); +} + +void serializeRaycastMesh(RaycastMesh* rm, std::vector& rm_buffer) +{ + if (!rm) { + rm_buffer.clear(); + return; + } + + static_cast(rm)->serialize(rm_buffer); +} + +MyRaycastMesh::MyRaycastMesh(std::vector& rm_buffer) +{ + mVcount = 0; + mVertices = nullptr; + mTcount = 0; + mIndices = nullptr; + mRaycastTriangles = nullptr; + mFaceNormals = nullptr; + mRaycastFrame = 0; + mMaxNodeCount = 0; + mNodeCount = 0; + mNodes = nullptr; + mRoot = nullptr; + + size_t chunk_size = 0; + size_t bytes_read = 0; + size_t rm_buffer_size_ = rm_buffer.size(); + if (!rm_buffer_size_) + return; + + char* buf = rm_buffer.data(); + + chunk_size = sizeof(RmUint32); + memcpy(&mVcount, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmReal) * (3 * mVcount)); + mVertices = (RmReal *)::malloc(chunk_size); + memcpy(mVertices, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = sizeof(RmUint32); + memcpy(&mTcount, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmUint32) * (3 * mTcount)); + mIndices = (RmUint32 *)::malloc(chunk_size); + memcpy(mIndices, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmUint32) * mTcount); + mRaycastTriangles = (RmUint32 *)::malloc(chunk_size); + memcpy(mRaycastTriangles, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmReal) * (3 * mTcount)); + mFaceNormals = (RmReal *)::malloc(chunk_size); + memcpy(mFaceNormals, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = sizeof(RmUint32); + memcpy(&mRaycastFrame, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + RmUint32 lt_size; + chunk_size = sizeof(RmUint32); + memcpy(<_size, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + if (lt_size) { + mLeafTriangles.resize(lt_size); + chunk_size = (sizeof(RmUint32) * lt_size); + memcpy(&mLeafTriangles[0], buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + } + + chunk_size = sizeof(RmUint32); + memcpy(&mNodeCount, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + mMaxNodeCount = mNodeCount; + + mNodes = new NodeAABB[mMaxNodeCount]; + mRoot = &mNodes[0]; + + for (RmUint32 index = 0; index < mNodeCount; ++index) { + chunk_size = (sizeof(RmReal) * 3); + memcpy(&mNodes[index].mBounds.mMin, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = (sizeof(RmReal) * 3); + memcpy(&mNodes[index].mBounds.mMax, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + chunk_size = sizeof(RmUint32); + memcpy(&mNodes[index].mLeafTriangleIndex, buf, chunk_size); + buf += chunk_size; + bytes_read += chunk_size; + + RmUint32 lNodeIndex; + chunk_size = sizeof(RmUint32); + memcpy(&lNodeIndex, buf, chunk_size); + if (lNodeIndex != TRI_EOF) + mNodes[index].mLeft = &mNodes[lNodeIndex]; + buf += chunk_size; + bytes_read += chunk_size; + + RmUint32 rNodeIndex; + chunk_size = sizeof(RmUint32); + memcpy(&rNodeIndex, buf, chunk_size); + if (rNodeIndex != TRI_EOF) + mNodes[index].mRight = &mNodes[rNodeIndex]; + buf += chunk_size; + bytes_read += chunk_size; + } + + if (bytes_read != rm_buffer_size_) { + delete[] mNodes; + ::free(mVertices); + ::free(mIndices); + ::free(mFaceNormals); + ::free(mRaycastTriangles); + + mVcount = 0; + mVertices = nullptr; + mTcount = 0; + mIndices = nullptr; + mRaycastTriangles = nullptr; + mFaceNormals = nullptr; + mRaycastFrame = 0; + mLeafTriangles.clear(); + mMaxNodeCount = 0; + mNodeCount = 0; + mNodes = nullptr; + mRoot = nullptr; + } +} + +void MyRaycastMesh::serialize(std::vector& rm_buffer) +{ + rm_buffer.clear(); + + size_t rm_buffer_size_ = 0; + + rm_buffer_size_ += sizeof(RmUint32); // mVcount + rm_buffer_size_ += (sizeof(RmReal) * (3 * mVcount)); // mVertices + rm_buffer_size_ += sizeof(RmUint32); // mTcount + rm_buffer_size_ += (sizeof(RmUint32) * (3 * mTcount)); // mIndices + rm_buffer_size_ += (sizeof(RmUint32) * mTcount); // mRaycastTriangles + rm_buffer_size_ += (sizeof(RmReal) * (3 * mTcount)); // mFaceNormals + rm_buffer_size_ += sizeof(RmUint32); // mRaycastFrame + rm_buffer_size_ += sizeof(RmUint32); // mLeafTriangles.size() + rm_buffer_size_ += (sizeof(RmUint32) * (RmUint32)mLeafTriangles.size()); // mLeafTriangles + rm_buffer_size_ += sizeof(RmUint32); // mNodeCount + rm_buffer_size_ += (sizeof(RmReal) * (3 * mNodeCount)); // mNodes.mBounds.mMin + rm_buffer_size_ += (sizeof(RmReal) * (3 * mNodeCount)); // mNodes.mBounds.mMax + rm_buffer_size_ += (sizeof(RmUint32) * mNodeCount); // mNodes.mLeafTriangleIndex + rm_buffer_size_ += (sizeof(RmUint32) * mNodeCount); // mNodes.mLeft[Index] + rm_buffer_size_ += (sizeof(RmUint32) * mNodeCount); // mNodes.mRight[Index] + + rm_buffer.resize(rm_buffer_size_); + + char* buf = rm_buffer.data(); + + memcpy(buf, &mVcount, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + memcpy(buf, mVertices, (sizeof(RmReal) * (3 * mVcount))); + buf += (sizeof(RmReal) * (3 * mVcount)); + + memcpy(buf, &mTcount, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + memcpy(buf, mIndices, (sizeof(RmUint32) * (3 * mTcount))); + buf += (sizeof(RmUint32) * (3 * mTcount)); + + memcpy(buf, mRaycastTriangles, (sizeof(RmUint32) * mTcount)); + buf += (sizeof(RmUint32) * mTcount); + + if (!mFaceNormals) { + RmReal save_face[3]; + getFaceNormal(0, &save_face[0]); + } + + memcpy(buf, mFaceNormals, (sizeof(RmReal) * (3 * mTcount))); + buf += (sizeof(RmReal) * (3 * mTcount)); + + memcpy(buf, &mRaycastFrame, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + RmUint32 lt_size = (RmUint32)mLeafTriangles.size(); + memcpy(buf, <_size, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + if (lt_size) { + memcpy(buf, &mLeafTriangles[0], (sizeof(RmUint32) * lt_size)); + buf += (sizeof(RmUint32) * lt_size); + } + + memcpy(buf, &mNodeCount, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + for (RmUint32 index = 0; index < mNodeCount; ++index) { + memcpy(buf, &mNodes[index].mBounds.mMin, (sizeof(RmReal) * 3)); + buf += (sizeof(RmReal) * 3); + + memcpy(buf, &mNodes[index].mBounds.mMax, (sizeof(RmReal) * 3)); + buf += (sizeof(RmReal) * 3); + + memcpy(buf, &mNodes[index].mLeafTriangleIndex, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + RmUint32 lNodeIndex = TRI_EOF; + if (mNodes[index].mLeft) + lNodeIndex = ((uintptr_t)mNodes[index].mLeft - (uintptr_t)mNodes) / sizeof(NodeAABB); + memcpy(buf, &lNodeIndex, sizeof(RmUint32)); + buf += sizeof(RmUint32); + + RmUint32 rNodeIndex = TRI_EOF; + if (mNodes[index].mRight) + rNodeIndex = ((uintptr_t)mNodes[index].mRight - (uintptr_t)mNodes) / sizeof(NodeAABB); + memcpy(buf, &rNodeIndex, sizeof(RmUint32)); + buf += sizeof(RmUint32); + } +} +#endif /*USE_MAP_MMFS*/ diff --git a/zone/raycast_mesh.h b/zone/raycast_mesh.h index eec2e0ba4..1aaa100cb 100644 --- a/zone/raycast_mesh.h +++ b/zone/raycast_mesh.h @@ -56,5 +56,11 @@ RaycastMesh * createRaycastMesh(RmUint32 vcount, // The number of vertices in t RmReal minAxisSize=0.01f // once a particular axis is less than this size, stop sub-dividing. ); +#ifdef USE_MAP_MMFS +#include + +RaycastMesh* loadRaycastMesh(std::vector& rm_buffer, bool& load_success); +void serializeRaycastMesh(RaycastMesh* rm, std::vector& rm_buffer); +#endif /*USE_MAP_MMFS*/ #endif \ No newline at end of file diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index c0eafea80..ad5f3d89a 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -351,6 +351,112 @@ void Spawn2::DeathReset(bool realdeath) } } +bool ZoneDatabase::PopulateZoneSpawnListClose(uint32 zoneid, LinkedList &spawn2_list, int16 version, const glm::vec4& client_position, uint32 repop_distance) +{ + std::unordered_map spawn_times; + + float mob_distance = 0; + + timeval tv; + gettimeofday(&tv, nullptr); + + /* Bulk Load NPC Types Data into the cache */ + database.LoadNPCTypesData(0, true); + + std::string spawn_query = StringFormat( + "SELECT " + "respawn_times.id, " + "respawn_times.`start`, " + "respawn_times.duration " + "FROM " + "respawn_times " + "WHERE instance_id = %u", + zone->GetInstanceID() + ); + auto results = QueryDatabase(spawn_query); + for (auto row = results.begin(); row != results.end(); ++row) { + uint32 start_duration = atoi(row[1]) > 0 ? atoi(row[1]) : 0; + uint32 end_duration = atoi(row[2]) > 0 ? atoi(row[2]) : 0; + + /* Our current time was expired */ + if ((start_duration + end_duration) <= tv.tv_sec) { + spawn_times[atoi(row[0])] = 0; + } + /* We still have time left on this timer */ + else { + spawn_times[atoi(row[0])] = ((start_duration + end_duration) - tv.tv_sec) * 1000; + } + } + + const char *zone_name = database.GetZoneName(zoneid); + std::string query = StringFormat( + "SELECT " + "id, " + "spawngroupID, " + "x, " + "y, " + "z, " + "heading, " + "respawntime, " + "variance, " + "pathgrid, " + "_condition, " + "cond_value, " + "enabled, " + "animation " + "FROM " + "spawn2 " + "WHERE zone = '%s' AND version = %u", + zone_name, + version + ); + results = QueryDatabase(query); + + if (!results.Success()) { + return false; + } + + for (auto row = results.begin(); row != results.end(); ++row) { + + uint32 spawn_time_left = 0; + Spawn2* new_spawn = 0; + bool perl_enabled = atoi(row[11]) == 1 ? true : false; + + if (spawn_times.count(atoi(row[0])) != 0) + spawn_time_left = spawn_times[atoi(row[0])]; + + glm::vec4 point; + point.x = atof(row[2]); + point.y = atof(row[3]); + + mob_distance = DistanceNoZ(client_position, point); + + if (mob_distance > repop_distance) + continue; + + new_spawn = new Spawn2( // + atoi(row[0]), // uint32 in_spawn2_id + atoi(row[1]), // uint32 spawngroup_id + atof(row[2]), // float in_x + atof(row[3]), // float in_y + atof(row[4]), // float in_z + atof(row[5]), // float in_heading + atoi(row[6]), // uint32 respawn + atoi(row[7]), // uint32 variance + spawn_time_left, // uint32 timeleft + atoi(row[8]), // uint32 grid + atoi(row[9]), // uint16 in_cond_id + atoi(row[10]), // int16 in_min_value + perl_enabled, // bool in_enabled + (EmuAppearance)atoi(row[12]) // EmuAppearance anim + ); + + spawn2_list.Insert(new_spawn); + } + + return true; +} + bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay) { std::unordered_map spawn_times; @@ -443,6 +549,8 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spa spawn2_list.Insert(new_spawn); } + NPC::SpawnZoneController(); + return true; } @@ -466,9 +574,9 @@ Spawn2* ZoneDatabase::LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2 bool perl_enabled = atoi(row[11]) == 1 ? true : false; - Spawn2* newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), - atof(row[5]), atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]), - atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12])); + auto newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), + atoi(row[6]), atoi(row[7]), timeleft, atoi(row[8]), atoi(row[9]), atoi(row[10]), + perl_enabled, (EmuAppearance)atoi(row[12])); spawn2_list.Insert(newSpawn); @@ -624,7 +732,7 @@ void SpawnConditionManager::Process() { //get our current time TimeOfDay_Struct tod; - zone->zone_time.getEQTimeOfDay(&tod); + zone->zone_time.GetCurrentEQTimeOfDay(&tod); //see if time is past our nearest event. if(EQTime::IsTimeBefore(&next_event, &tod)) @@ -673,7 +781,7 @@ void SpawnConditionManager::ExecEvent(SpawnEvent &event, bool send_update) { } TimeOfDay_Struct tod; - zone->zone_time.getEQTimeOfDay(&tod); + zone->zone_time.GetCurrentEQTimeOfDay(&tod); if(event.strict && (event.next.hour != tod.hour || event.next.day != tod.day || event.next.month != tod.month || event.next.year != tod.year)) { Log.Out(Logs::Detail, Logs::Spawns, "Event %d: Unable to execute. Condition is strict, and event time has already passed.", event.id); @@ -871,7 +979,7 @@ bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 in //better solution, and I just dont care thats much. //get our current time TimeOfDay_Struct tod; - zone->zone_time.getEQTimeOfDay(&tod); + zone->zone_time.GetCurrentEQTimeOfDay(&tod); for(auto cur = spawn_events.begin(); cur != spawn_events.end(); ++cur) { SpawnEvent &cevent = *cur; @@ -1020,7 +1128,7 @@ void SpawnConditionManager::SetCondition(const char *zone_short, uint32 instance UpdateDBCondition(zone_short, instance_id, condition_id, new_value); - ServerPacket* pack = new ServerPacket(ServerOP_SpawnCondition, sizeof(ServerSpawnCondition_Struct)); + auto pack = new ServerPacket(ServerOP_SpawnCondition, sizeof(ServerSpawnCondition_Struct)); ServerSpawnCondition_Struct* ssc = (ServerSpawnCondition_Struct*)pack->pBuffer; ssc->zoneID = database.GetZoneID(zone_short); @@ -1096,7 +1204,7 @@ void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool stri if(reset_base) { Log.Out(Logs::Detail, Logs::Spawns, "Spawn event %d located in this zone. State set. Trigger time reset (period %d).", event_id, cevent.period); //start with the time now - zone->zone_time.getEQTimeOfDay(&cevent.next); + zone->zone_time.GetCurrentEQTimeOfDay(&cevent.next); //advance the next time by our period EQTime::AddMinutes(cevent.period, &cevent.next); } else { @@ -1141,7 +1249,7 @@ void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool stri if(reset_base) { Log.Out(Logs::Detail, Logs::Spawns, "Spawn event %d is in zone %s. State set. Trigger time reset (period %d). Notifying world.", event_id, zone_short_name.c_str(), e.period); //start with the time now - zone->zone_time.getEQTimeOfDay(&e.next); + zone->zone_time.GetCurrentEQTimeOfDay(&e.next); //advance the next time by our period EQTime::AddMinutes(e.period, &e.next); } else { @@ -1152,7 +1260,7 @@ void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool stri //now notify the zone - ServerPacket* pack = new ServerPacket(ServerOP_SpawnEvent, sizeof(ServerSpawnEvent_Struct)); + auto pack = new ServerPacket(ServerOP_SpawnEvent, sizeof(ServerSpawnEvent_Struct)); ServerSpawnEvent_Struct* sse = (ServerSpawnEvent_Struct*)pack->pBuffer; sse->zoneID = database.GetZoneID(zone_short_name.c_str()); diff --git a/zone/spawngroup.cpp b/zone/spawngroup.cpp index 1661e0fe8..94b2ed285 100644 --- a/zone/spawngroup.cpp +++ b/zone/spawngroup.cpp @@ -139,90 +139,97 @@ bool SpawnGroupList::RemoveSpawnGroup(uint32 in_id) { return(true); } -bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list) { - +bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnGroupList *spawn_group_list) +{ std::string query = StringFormat("SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, " - "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, " - "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, " - "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay " - "FROM spawn2, spawngroup WHERE spawn2.spawngroupID = spawngroup.ID " - "AND spawn2.version = %u and zone = '%s'", version, zone_name); - auto results = QueryDatabase(query); - if (!results.Success()) { - return false; - } - - for (auto row = results.begin(); row != results.end(); ++row) { - SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), - atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), - atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); - spawn_group_list->AddSpawnGroup(newSpawnGroup); - } - - query = StringFormat("SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, " - "npc_types.spawn_limit AS sl " - "FROM spawnentry, spawn2, npc_types " - "WHERE spawnentry.npcID=npc_types.id " - "AND spawnentry.spawngroupID = spawn2.spawngroupID " - "AND zone = '%s'", zone_name); - results = QueryDatabase(query); - if (!results.Success()) { - Log.Out(Logs::General, Logs::Error, "Error2 in PopulateZoneLists query '%'", query.c_str()); - return false; - } - - for (auto row = results.begin(); row != results.end(); ++row) { - SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0); - SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); - - if (!sg) { - continue; - } - - sg->AddSpawnEntry(newSpawnEntry); - } - - return true; -} - -bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list) { - - - std::string query = StringFormat("SELECT DISTINCT(spawngroup.id), spawngroup.name, spawngroup.spawn_limit, " - "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, " - "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, " - "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay " - "FROM spawngroup WHERE spawngroup.ID = '%i'", spawngroupid); - auto results = QueryDatabase(query); - if (!results.Success()) { - Log.Out(Logs::General, Logs::Error, "Error2 in PopulateZoneLists query %s", query.c_str()); - return false; - } - - for (auto row = results.begin(); row != results.end(); ++row) { - SpawnGroup* newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11])); - spawn_group_list->AddSpawnGroup(newSpawnGroup); - } - - query = StringFormat("SELECT DISTINCT(spawnentry.spawngroupID), spawnentry.npcid, " - "spawnentry.chance, spawngroup.spawn_limit FROM spawnentry, spawngroup " - "WHERE spawnentry.spawngroupID = '%i' AND spawngroup.spawn_limit = '0' " - "ORDER BY chance", spawngroupid); - results = QueryDatabase(query); + "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, " + "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, " + "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay " + "FROM spawn2, spawngroup WHERE spawn2.spawngroupID = spawngroup.ID " + "AND spawn2.version = %u and zone = '%s'", + version, zone_name); + auto results = QueryDatabase(query); if (!results.Success()) { - Log.Out(Logs::General, Logs::Error, "Error3 in PopulateZoneLists query '%s'", query.c_str()); return false; } - for(auto row = results.begin(); row != results.end(); ++row) { - SpawnEntry* newSpawnEntry = new SpawnEntry( atoi(row[1]), atoi(row[2]), row[3]?atoi(row[3]):0); - SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); - if (!sg) { - continue; - } + for (auto row = results.begin(); row != results.end(); ++row) { + auto newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), + atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), + atoi(row[9]), atoi(row[10]), atoi(row[11])); + spawn_group_list->AddSpawnGroup(newSpawnGroup); + } - sg->AddSpawnEntry(newSpawnEntry); - } + query = StringFormat("SELECT DISTINCT spawnentry.spawngroupID, npcid, chance, " + "npc_types.spawn_limit AS sl " + "FROM spawnentry, spawn2, npc_types " + "WHERE spawnentry.npcID=npc_types.id " + "AND spawnentry.spawngroupID = spawn2.spawngroupID " + "AND zone = '%s'", + zone_name); + results = QueryDatabase(query); + if (!results.Success()) { + Log.Out(Logs::General, Logs::Error, "Error2 in PopulateZoneLists query '%'", query.c_str()); + return false; + } + + for (auto row = results.begin(); row != results.end(); ++row) { + auto newSpawnEntry = new SpawnEntry(atoi(row[1]), atoi(row[2]), row[3] ? atoi(row[3]) : 0); + SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); + + if (!sg) { + safe_delete(newSpawnEntry); + continue; + } + + sg->AddSpawnEntry(newSpawnEntry); + } + + return true; +} + +bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList *spawn_group_list) +{ + std::string query = StringFormat("SELECT DISTINCT(spawngroup.id), spawngroup.name, spawngroup.spawn_limit, " + "spawngroup.dist, spawngroup.max_x, spawngroup.min_x, " + "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, " + "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay " + "FROM spawngroup WHERE spawngroup.ID = '%i'", + spawngroupid); + auto results = QueryDatabase(query); + if (!results.Success()) { + Log.Out(Logs::General, Logs::Error, "Error2 in PopulateZoneLists query %s", query.c_str()); + return false; + } + + for (auto row = results.begin(); row != results.end(); ++row) { + auto newSpawnGroup = new SpawnGroup(atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), + atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), + atoi(row[9]), atoi(row[10]), atoi(row[11])); + spawn_group_list->AddSpawnGroup(newSpawnGroup); + } + + query = StringFormat("SELECT DISTINCT(spawnentry.spawngroupID), spawnentry.npcid, " + "spawnentry.chance, spawngroup.spawn_limit FROM spawnentry, spawngroup " + "WHERE spawnentry.spawngroupID = '%i' AND spawngroup.spawn_limit = '0' " + "ORDER BY chance", + spawngroupid); + results = QueryDatabase(query); + if (!results.Success()) { + Log.Out(Logs::General, Logs::Error, "Error3 in PopulateZoneLists query '%s'", query.c_str()); + return false; + } + + for (auto row = results.begin(); row != results.end(); ++row) { + auto newSpawnEntry = new SpawnEntry(atoi(row[1]), atoi(row[2]), row[3] ? atoi(row[3]) : 0); + SpawnGroup *sg = spawn_group_list->GetSpawnGroup(atoi(row[0])); + if (!sg) { + safe_delete(newSpawnEntry); + continue; + } + + sg->AddSpawnEntry(newSpawnEntry); + } return true; } diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index faae0e3b1..eb7f5aac1 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -30,14 +30,14 @@ int Mob::GetKickDamage() { int multiple=(GetLevel()*100/5); multiple += 100; - int32 dmg=(((GetSkill(SkillKick) + GetSTR() + GetLevel())*100 / 9000) * multiple) + 600; //Set a base of 6 damage, 1 seemed too low at the sub level 30 level. + int32 dmg = (((GetSkill(EQEmu::skills::SkillKick) + GetSTR() + GetLevel()) * 100 / 9000) * multiple) + 600; //Set a base of 6 damage, 1 seemed too low at the sub level 30 level. if(GetClass() == WARRIOR || GetClass() == WARRIORGM ||GetClass() == BERSERKER || GetClass() == BERSERKERGM) { dmg*=12/10;//small increase for warriors } dmg /= 100; int32 mindmg = 1; - ApplySpecialAttackMod(SkillKick, dmg,mindmg); + ApplySpecialAttackMod(EQEmu::skills::SkillKick, dmg, mindmg); dmg = mod_kick_damage(dmg); @@ -49,41 +49,37 @@ int Mob::GetBashDamage() { multiple += 100; //this is complete shite - int32 dmg=((((GetSkill(SkillBash) + GetSTR())*100 + GetLevel()*100/2) / 10000) * multiple) + 600; //Set a base of 6 damage, 1 seemed too low at the sub level 30 level. + int32 dmg = ((((GetSkill(EQEmu::skills::SkillBash) + GetSTR()) * 100 + GetLevel() * 100 / 2) / 10000) * multiple) + 600; //Set a base of 6 damage, 1 seemed too low at the sub level 30 level. dmg /= 100; int32 mindmg = 1; - ApplySpecialAttackMod(SkillBash, dmg, mindmg); + ApplySpecialAttackMod(EQEmu::skills::SkillBash, dmg, mindmg); dmg = mod_bash_damage(dmg); return(dmg); } -void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) { +void Mob::ApplySpecialAttackMod(EQEmu::skills::SkillType skill, int32 &dmg, int32 &mindmg) { int item_slot = -1; //1: Apply bonus from AC (BOOT/SHIELD/HANDS) est. 40AC=6dmg if (IsClient()){ - switch (skill){ - - case SkillFlyingKick: - case SkillRoundKick: - case SkillKick: - item_slot = MainFeet; - break; - - case SkillBash: - item_slot = MainSecondary; - break; - - case SkillDragonPunch: - case SkillEagleStrike: - case SkillTigerClaw: - item_slot = MainHands; - break; - - default: - break; + switch (skill) { + case EQEmu::skills::SkillFlyingKick: + case EQEmu::skills::SkillRoundKick: + case EQEmu::skills::SkillKick: + item_slot = EQEmu::legacy::SlotFeet; + break; + case EQEmu::skills::SkillBash: + item_slot = EQEmu::legacy::SlotSecondary; + break; + case EQEmu::skills::SkillDragonPunch: + case EQEmu::skills::SkillEagleStrike: + case EQEmu::skills::SkillTigerClaw: + item_slot = EQEmu::legacy::SlotHands; + break; + default: + break; } if (item_slot >= 0){ @@ -95,81 +91,79 @@ void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) } } -void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime, - bool HitChance, bool CanAvoid) { +void Mob::DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32 max_damage, int32 min_damage, int32 hate_override, int ReuseTime, + bool CheckHitChance, bool CanAvoid) { //this really should go through the same code as normal melee damage to //pick up all the special behavior there - if (!who) + if ((who == nullptr || ((IsClient() && CastToClient()->dead) || (who->IsClient() && who->CastToClient()->dead)) || HasDied() || (!IsAttackAllowed(who)))) return; + + if(who->GetInvul() || who->GetSpecialAbility(IMMUNE_MELEE)) + max_damage = -5; - if(who->GetInvul() || who->GetSpecialAbility(IMMUNE_MELEE) || who->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE)) - return; //-5? + if (who->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE) && skill != EQEmu::skills::SkillBackstab) + max_damage = -5; uint32 hate = max_damage; if(hate_override > -1) hate = hate_override; - if(skill == SkillBash){ + if (skill == EQEmu::skills::SkillBash){ if(IsClient()){ - ItemInst *item = CastToClient()->GetInv().GetItem(MainSecondary); + ItemInst *item = CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotSecondary); if(item) { - if(item->GetItem()->ItemType == ItemTypeShield) + if (item->GetItem()->ItemType == EQEmu::item::ItemTypeShield) { hate += item->GetItem()->AC; } - const Item_Struct *itm = item->GetItem(); - hate = hate * (100 + GetFuriousBash(itm->Focus.Effect)) / 100; + const EQEmu::ItemBase *itm = item->GetItem(); + auto fbash = GetFuriousBash(itm->Focus.Effect); + hate = hate * (100 + fbash) / 100; + if (fbash) + Message_StringID(MT_Spells, GLOWS_RED, itm->Name); } } } min_damage += min_damage * GetMeleeMinDamageMod_SE(skill) / 100; - if(HitChance && !who->CheckHitChance(this, skill, MainPrimary)) - max_damage = 0; - - else{ - bool CanRiposte = true; - if(skill == SkillThrowing || skill == SkillArchery) // changed from '&&' - CanRiposte = false; - - if (CanAvoid) - who->AvoidDamage(this, max_damage, CanRiposte); - - who->MeleeMitigation(this, max_damage, min_damage); - - if(max_damage > 0) + int hand = EQEmu::legacy::SlotPrimary; // Avoid checks hand for throwing/archery exclusion, primary should work for most + if (skill == EQEmu::skills::SkillThrowing || skill == EQEmu::skills::SkillArchery) + hand = EQEmu::legacy::SlotRange; + if (who->AvoidDamage(this, max_damage, hand)) { + if (max_damage == -3) + DoRiposte(who); + } else { + if (!CheckHitChance || (CheckHitChance && who->CheckHitChance(this, skill, EQEmu::legacy::SlotPrimary))) { + who->MeleeMitigation(this, max_damage, min_damage); CommonOutgoingHitSuccess(who, max_damage, skill); - + } else { + max_damage = 0; + } } who->AddToHateList(this, hate, 0, false); + if (max_damage > 0 && aabonuses.SkillAttackProc[0] && aabonuses.SkillAttackProc[1] == skill && + IsValidSpell(aabonuses.SkillAttackProc[2])) { + float chance = aabonuses.SkillAttackProc[0] / 1000.0f; + if (zone->random.Roll(chance)) + SpellFinished(aabonuses.SkillAttackProc[2], who, EQEmu::CastingSlot::Item, 0, -1, + spells[aabonuses.SkillAttackProc[2]].ResistDiff); + } who->Damage(this, max_damage, SPELL_UNKNOWN, skill, false); //Make sure 'this' has not killed the target and 'this' is not dead (Damage shield ect). if(!GetTarget())return; if (HasDied()) return; - //[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill - if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ - int kb_chance = 25; - kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100; - - if (zone->random.Roll(kb_chance)) - SpellFinished(904, who, 10, 0, -1, spells[904].ResistDiff); - //who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC. - } - if (HasSkillProcs()) TrySkillProc(who, skill, ReuseTime*1000); if (max_damage > 0 && HasSkillProcSuccess()) TrySkillProc(who, skill, ReuseTime*1000, true); - if(max_damage == -3 && !who->HasDied()) - DoRiposte(who); } @@ -181,9 +175,14 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { return; CombatAbility_Struct* ca_atk = (CombatAbility_Struct*) app->pBuffer; + pTimerType timer = pTimerCombatAbility; + // RoF2+ Tiger Claw is unlinked from other monk skills, if they ever do that for other classes there will need + // to be more checks here + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF2 && ca_atk->m_skill == EQEmu::skills::SkillTigerClaw) + timer = pTimerCombatAbility2; /* Check to see if actually have skill */ - if (!MaxSkill(static_cast(ca_atk->m_skill))) + if (!MaxSkill(static_cast(ca_atk->m_skill))) return; if(GetTarget()->GetID() != ca_atk->m_target) @@ -195,8 +194,8 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { //These two are not subject to the combat ability timer, as they //allready do their checking in conjunction with the attack timer //throwing weapons - if(ca_atk->m_atk == MainRange) { - if (ca_atk->m_skill == SkillThrowing) { + if (ca_atk->m_atk == EQEmu::legacy::SlotRange) { + if (ca_atk->m_skill == EQEmu::skills::SkillThrowing) { SetAttackTimer(); ThrowingAttack(GetTarget()); if (CheckDoubleRangedAttack()) @@ -204,7 +203,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { return; } //ranged attack (archery) - if (ca_atk->m_skill == SkillArchery) { + if (ca_atk->m_skill == EQEmu::skills::SkillArchery) { SetAttackTimer(); RangedAttack(GetTarget()); if (CheckDoubleRangedAttack()) @@ -218,7 +217,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { if(!CombatRange(GetTarget())) return; - if(!p_timers.Expired(&database, pTimerCombatAbility, false)) { + if(!p_timers.Expired(&database, timer, false)) { Message(13,"Ability recovery time not yet met."); return; } @@ -237,20 +236,20 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { int32 skill_reduction = this->GetSkillReuseTime(ca_atk->m_skill); - // not sure what the '100' indicates..if ->m_atk is not used as 'slot' reference, then change MainRange above back to '11' - if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == SkillBash)) { // SLAM - Bash without a shield equipped + // not sure what the '100' indicates..if ->m_atk is not used as 'slot' reference, then change SlotRange above back to '11' + if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == EQEmu::skills::SkillBash)) { // SLAM - Bash without a shield equipped if (GetTarget() != this) { - CheckIncreaseSkill(SkillBash, GetTarget(), 10); + CheckIncreaseSkill(EQEmu::skills::SkillBash, GetTarget(), 10); DoAnim(animTailRake); int32 ht = 0; - if(GetWeaponDamage(GetTarget(), GetInv().GetItem(MainSecondary)) <= 0 && - GetWeaponDamage(GetTarget(), GetInv().GetItem(MainShoulders)) <= 0){ + if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::legacy::SlotSecondary)) <= 0 && + GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::legacy::SlotShoulders)) <= 0){ dmg = -5; } else{ - if(!GetTarget()->CheckHitChance(this, SkillBash, 0)) { + if (!GetTarget()->CheckHitChance(this, EQEmu::skills::SkillBash, 0)) { dmg = 0; ht = GetBashDamage(); } @@ -265,19 +264,19 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { ReuseTime = BashReuseTime-1-skill_reduction; ReuseTime = (ReuseTime*HasteMod)/100; - DoSpecialAttackDamage(GetTarget(), SkillBash, dmg, 1, ht, ReuseTime); + DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillBash, dmg, 1, ht, ReuseTime); if(ReuseTime > 0) { - p_timers.Start(pTimerCombatAbility, ReuseTime); + p_timers.Start(timer, ReuseTime); } } return; } - if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == SkillFrenzy)){ - CheckIncreaseSkill(SkillFrenzy, GetTarget(), 10); + if ((ca_atk->m_atk == 100) && (ca_atk->m_skill == EQEmu::skills::SkillFrenzy)){ + CheckIncreaseSkill(EQEmu::skills::SkillFrenzy, GetTarget(), 10); int AtkRounds = 3; - int skillmod = 100*GetSkill(SkillFrenzy)/MaxSkill(SkillFrenzy); + int skillmod = 100 * GetSkill(EQEmu::skills::SkillFrenzy) / MaxSkill(EQEmu::skills::SkillFrenzy); int32 max_dmg = (26 + ((((GetLevel()-6) * 2)*skillmod)/100)) * ((100+RuleI(Combat, FrenzyBonus))/100); int32 min_dmg = 0; DoAnim(anim2HSlashing); @@ -298,13 +297,13 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { //Live parses show around 55% Triple 35% Double 10% Single, you will always get first hit. while(AtkRounds > 0) { if (GetTarget() && (AtkRounds == 1 || zone->random.Roll(75))) { - DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, max_dmg , ReuseTime, true); + DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillFrenzy, max_dmg, min_dmg, max_dmg, ReuseTime, true); } AtkRounds--; } if(ReuseTime > 0) { - p_timers.Start(pTimerCombatAbility, ReuseTime); + p_timers.Start(timer, ReuseTime); } return; } @@ -314,19 +313,19 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { case WARRIOR: case RANGER: case BEASTLORD: - if (ca_atk->m_atk != 100 || ca_atk->m_skill != SkillKick) { + if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQEmu::skills::SkillKick) { break; } if (GetTarget() != this) { - CheckIncreaseSkill(SkillKick, GetTarget(), 10); + CheckIncreaseSkill(EQEmu::skills::SkillKick, GetTarget(), 10); DoAnim(animKick); int32 ht = 0; - if(GetWeaponDamage(GetTarget(), GetInv().GetItem(MainFeet)) <= 0){ + if (GetWeaponDamage(GetTarget(), GetInv().GetItem(EQEmu::legacy::SlotFeet)) <= 0){ dmg = -5; } else{ - if(!GetTarget()->CheckHitChance(this, SkillKick, 0)) { + if (!GetTarget()->CheckHitChance(this, EQEmu::skills::SkillKick, 0)) { dmg = 0; ht = GetKickDamage(); } @@ -339,7 +338,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { } ReuseTime = KickReuseTime-1-skill_reduction; - DoSpecialAttackDamage(GetTarget(), SkillKick, dmg, 1, ht, ReuseTime); + DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillKick, dmg, 1, ht, ReuseTime); } break; @@ -350,7 +349,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack; if (wuchance) { if (wuchance >= 100 || zone->random.Roll(wuchance)) { - int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick }; + int MonkSPA[5] = { EQEmu::skills::SkillFlyingKick, EQEmu::skills::SkillDragonPunch, EQEmu::skills::SkillEagleStrike, EQEmu::skills::SkillTigerClaw, EQEmu::skills::SkillRoundKick }; int extra = 1; // always 1/4 of the double attack chance, 25% at rank 5 (100/4) if (zone->random.Roll(wuchance / 4)) @@ -370,12 +369,12 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { //hackish... but we return a huge reuse time if this is an // invalid skill, otherwise, we can safely assume it is a // valid monk skill and just cast it to a SkillType - CheckIncreaseSkill((SkillUseTypes) ca_atk->m_skill, GetTarget(), 10); + CheckIncreaseSkill((EQEmu::skills::SkillType) ca_atk->m_skill, GetTarget(), 10); } break; } case ROGUE: { - if (ca_atk->m_atk != 100 || ca_atk->m_skill != SkillBackstab) { + if (ca_atk->m_atk != 100 || ca_atk->m_skill != EQEmu::skills::SkillBackstab) { break; } ReuseTime = BackstabReuseTime-1 - skill_reduction; @@ -390,7 +389,7 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { ReuseTime = (ReuseTime*HasteMod)/100; if(ReuseTime > 0){ - p_timers.Start(pTimerCombatAbility, ReuseTime); + p_timers.Start(timer, ReuseTime); } } @@ -404,68 +403,58 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type) int32 max_dmg = 0; int32 min_dmg = 1; int reuse = 0; - SkillUseTypes skill_type; //to avoid casting... even though it "would work" - uint8 itemslot = MainFeet; + EQEmu::skills::SkillType skill_type; //to avoid casting... even though it "would work" + uint8 itemslot = EQEmu::legacy::SlotFeet; - switch(unchecked_type){ - case SkillFlyingKick:{ - skill_type = SkillFlyingKick; - max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, FlyingKickBonus) / 100) + 35; - min_dmg = ((level*8)/10); - ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); - DoAnim(animFlyingKick); - reuse = FlyingKickReuseTime; - break; - } - case SkillDragonPunch:{ - skill_type = SkillDragonPunch; - max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, DragonPunchBonus) / 100) + 26; - itemslot = MainHands; - ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); - DoAnim(animTailRake); - reuse = TailRakeReuseTime; - break; - } - - case SkillEagleStrike:{ - skill_type = SkillEagleStrike; - max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, EagleStrikeBonus) / 100) + 19; - itemslot = MainHands; - ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); - DoAnim(animEagleStrike); - reuse = EagleStrikeReuseTime; - break; - } - - case SkillTigerClaw:{ - skill_type = SkillTigerClaw; - max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, TigerClawBonus) / 100) + 12; - itemslot = MainHands; - ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); - DoAnim(animTigerClaw); - reuse = TigerClawReuseTime; - break; - } - - case SkillRoundKick:{ - skill_type = SkillRoundKick; - max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, RoundKickBonus) / 100) + 10; - ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); - DoAnim(animRoundKick); - reuse = RoundKickReuseTime; - break; - } - - case SkillKick:{ - skill_type = SkillKick; - max_dmg = GetKickDamage(); - DoAnim(animKick); - reuse = KickReuseTime; - break; - } - default: - Log.Out(Logs::Detail, Logs::Attack, "Invalid special attack type %d attempted", unchecked_type); - return(1000); /* nice long delay for them, the caller depends on this! */ + switch(unchecked_type) { + case EQEmu::skills::SkillFlyingKick: + skill_type = EQEmu::skills::SkillFlyingKick; + max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, FlyingKickBonus) / 100) + 35; + min_dmg = ((level*8)/10); + ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); + DoAnim(animFlyingKick); + reuse = FlyingKickReuseTime; + break; + case EQEmu::skills::SkillDragonPunch: + skill_type = EQEmu::skills::SkillDragonPunch; + max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, DragonPunchBonus) / 100) + 26; + itemslot = EQEmu::legacy::SlotHands; + ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); + DoAnim(animTailRake); + reuse = TailRakeReuseTime; + break; + case EQEmu::skills::SkillEagleStrike: + skill_type = EQEmu::skills::SkillEagleStrike; + max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, EagleStrikeBonus) / 100) + 19; + itemslot = EQEmu::legacy::SlotHands; + ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); + DoAnim(animEagleStrike); + reuse = EagleStrikeReuseTime; + break; + case EQEmu::skills::SkillTigerClaw: + skill_type = EQEmu::skills::SkillTigerClaw; + max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, TigerClawBonus) / 100) + 12; + itemslot = EQEmu::legacy::SlotHands; + ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); + DoAnim(animTigerClaw); + reuse = TigerClawReuseTime; + break; + case EQEmu::skills::SkillRoundKick: + skill_type = EQEmu::skills::SkillRoundKick; + max_dmg = ((GetSTR()+GetSkill(skill_type)) * RuleI(Combat, RoundKickBonus) / 100) + 10; + ApplySpecialAttackMod(skill_type, max_dmg, min_dmg); + DoAnim(animRoundKick); + reuse = RoundKickReuseTime; + break; + case EQEmu::skills::SkillKick: + skill_type = EQEmu::skills::SkillKick; + max_dmg = GetKickDamage(); + DoAnim(animKick); + reuse = KickReuseTime; + break; + default: + Log.Out(Logs::Detail, Logs::Attack, "Invalid special attack type %d attempted", unchecked_type); + return(1000); /* nice long delay for them, the caller depends on this! */ } if(IsClient()){ @@ -474,7 +463,7 @@ int Mob::MonkSpecialAttack(Mob* other, uint8 unchecked_type) } } else{ - if(GetWeaponDamage(other, (const Item_Struct*)nullptr) <= 0){ + if (GetWeaponDamage(other, (const EQEmu::ItemBase*)nullptr) <= 0){ ndamage = -5; } } @@ -509,8 +498,8 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { //make sure we have a proper weapon if we are a client. if(IsClient()) { - const ItemInst *wpn = CastToClient()->GetInv().GetItem(MainPrimary); - if(!wpn || (wpn->GetItem()->ItemType != ItemType1HPiercing)){ + const ItemInst *wpn = CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotPrimary); + if (!wpn || (wpn->GetItem()->ItemType != EQEmu::item::ItemType1HPiercing)){ Message_StringID(13, BACKSTAB_WEAPON); return; } @@ -536,7 +525,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { RogueBackstab(other,false,ReuseTime); if (level > 54) { - if(IsClient() && CastToClient()->CheckDoubleAttack(false)) + if(IsClient() && CastToClient()->CheckDoubleAttack()) { if(other->GetHP() > 0) RogueBackstab(other,false,ReuseTime); @@ -547,7 +536,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { } if(IsClient()) - CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10); + CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillBackstab, other, 10); } //Live AA - Chaotic Backstab @@ -558,7 +547,7 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { if (level > 54) { // Check for double attack with main hand assuming maxed DA Skill (MS) - if(IsClient() && CastToClient()->CheckDoubleAttack(false)) + if(IsClient() && CastToClient()->CheckDoubleAttack()) if(other->GetHP() > 0) RogueBackstab(other,true, ReuseTime); @@ -567,10 +556,10 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { } if(IsClient()) - CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10); + CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillBackstab, other, 10); } else { //We do a single regular attack if we attack from the front without chaotic stab - Attack(other, MainPrimary); + Attack(other, EQEmu::legacy::SlotPrimary); } } @@ -589,11 +578,11 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) if(IsClient()){ const ItemInst *wpn = nullptr; - wpn = CastToClient()->GetInv().GetItem(MainPrimary); + wpn = CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotPrimary); if(wpn) { primaryweapondamage = GetWeaponDamage(other, wpn); backstab_dmg = wpn->GetItem()->BackstabDmg; - for (int i = 0; i < EmuConstants::ITEM_COMMON_SIZE; ++i) + for (int i = 0; i < EQEmu::legacy::ITEM_COMMON_SIZE; ++i) { ItemInst *aug = wpn->GetAugment(i); if(aug) @@ -610,12 +599,12 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) if(primaryweapondamage > 0){ if(level > 25){ - max_hit = (((2*backstab_dmg) * GetDamageTable(SkillBackstab) / 100) * 10 * GetSkill(SkillBackstab) / 355) + ((level-25)/3) + 1; - hate = 20 * backstab_dmg * GetSkill(SkillBackstab) / 355; + max_hit = (((((2 * backstab_dmg) * GetDamageTable(EQEmu::skills::SkillBackstab) / 100) * 10 * GetSkill(EQEmu::skills::SkillBackstab) / 355) + ((level - 25) / 3) + 1) * ((100 + RuleI(Combat, BackstabBonus)) / 100)); + hate = 20 * backstab_dmg * GetSkill(EQEmu::skills::SkillBackstab) / 355; } else{ - max_hit = (((2*backstab_dmg) * GetDamageTable(SkillBackstab) / 100) * 10 * GetSkill(SkillBackstab) / 355) + 1;; - hate = 20 * backstab_dmg * GetSkill(SkillBackstab) / 355; + max_hit = (((((2 * backstab_dmg) * GetDamageTable(EQEmu::skills::SkillBackstab) / 100) * 10 * GetSkill(EQEmu::skills::SkillBackstab) / 355) + 1) * ((100 + RuleI(Combat, BackstabBonus)) / 100)); + hate = 20 * backstab_dmg * GetSkill(EQEmu::skills::SkillBackstab) / 355; } // determine minimum hits @@ -627,7 +616,7 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) min_hit = (level * ( level*5 - 105)) / 100; } - if(!other->CheckHitChance(this, SkillBackstab, 0)) { + if (!other->CheckHitChance(this, EQEmu::skills::SkillBackstab, 0)) { ndamage = 0; } else{ @@ -650,17 +639,17 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) } ndamage = mod_backstab_damage(ndamage); - + uint32 Assassinate_Dmg = 0; - Assassinate_Dmg = TryAssassinate(other, SkillBackstab, ReuseTime); - + Assassinate_Dmg = TryAssassinate(other, EQEmu::skills::SkillBackstab, ReuseTime); + if (Assassinate_Dmg) { ndamage = Assassinate_Dmg; entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName()); } - DoSpecialAttackDamage(other, SkillBackstab, ndamage, min_hit, hate, ReuseTime, false, false); - DoAnim(animPiercing); + DoSpecialAttackDamage(other, EQEmu::skills::SkillBackstab, ndamage, min_hit, hate, ReuseTime, false, false); + DoAnim(anim1HPiercing); } // assassinate [No longer used for regular assassinate 6-29-14] @@ -668,12 +657,12 @@ void Mob::RogueAssassinate(Mob* other) { //can you dodge, parry, etc.. an assassinate?? //if so, use DoSpecialAttackDamage(other, BACKSTAB, 32000); instead - if(GetWeaponDamage(other, IsClient()?CastToClient()->GetInv().GetItem(MainPrimary):(const ItemInst*)nullptr) > 0){ - other->Damage(this, 32000, SPELL_UNKNOWN, SkillBackstab); + if (GetWeaponDamage(other, IsClient() ? CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotPrimary) : (const ItemInst*)nullptr) > 0){ + other->Damage(this, 32000, SPELL_UNKNOWN, EQEmu::skills::SkillBackstab); }else{ - other->Damage(this, -5, SPELL_UNKNOWN, SkillBackstab); + other->Damage(this, -5, SPELL_UNKNOWN, EQEmu::skills::SkillBackstab); } - DoAnim(animPiercing); //piercing animation + DoAnim(anim1HPiercing); //piercing animation } void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { @@ -688,34 +677,34 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { //Message(0, "Error: Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime()); return; } - const ItemInst* RangeWeapon = m_inv[MainRange]; + const ItemInst* RangeWeapon = m_inv[EQEmu::legacy::SlotRange]; //locate ammo - int ammo_slot = MainAmmo; - const ItemInst* Ammo = m_inv[MainAmmo]; + int ammo_slot = EQEmu::legacy::SlotAmmo; + const ItemInst* Ammo = m_inv[EQEmu::legacy::SlotAmmo]; - if (!RangeWeapon || !RangeWeapon->IsType(ItemClassCommon)) { - Log.Out(Logs::Detail, Logs::Combat, "Ranged attack canceled. Missing or invalid ranged weapon (%d) in slot %d", GetItemIDAt(MainRange), MainRange); - Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have no bow!", GetItemIDAt(MainRange)); + if (!RangeWeapon || !RangeWeapon->IsClassCommon()) { + Log.Out(Logs::Detail, Logs::Combat, "Ranged attack canceled. Missing or invalid ranged weapon (%d) in slot %d", GetItemIDAt(EQEmu::legacy::SlotRange), EQEmu::legacy::SlotRange); + Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have no bow!", GetItemIDAt(EQEmu::legacy::SlotRange)); return; } - if (!Ammo || !Ammo->IsType(ItemClassCommon)) { - Log.Out(Logs::Detail, Logs::Combat, "Ranged attack canceled. Missing or invalid ammo item (%d) in slot %d", GetItemIDAt(MainAmmo), MainAmmo); - Message(0, "Error: Ammo: GetItem(%i)==0, you have no ammo!", GetItemIDAt(MainAmmo)); + if (!Ammo || !Ammo->IsClassCommon()) { + Log.Out(Logs::Detail, Logs::Combat, "Ranged attack canceled. Missing or invalid ammo item (%d) in slot %d", GetItemIDAt(EQEmu::legacy::SlotAmmo), EQEmu::legacy::SlotAmmo); + Message(0, "Error: Ammo: GetItem(%i)==0, you have no ammo!", GetItemIDAt(EQEmu::legacy::SlotAmmo)); return; } - const Item_Struct* RangeItem = RangeWeapon->GetItem(); - const Item_Struct* AmmoItem = Ammo->GetItem(); + const EQEmu::ItemBase* RangeItem = RangeWeapon->GetItem(); + const EQEmu::ItemBase* AmmoItem = Ammo->GetItem(); - if(RangeItem->ItemType != ItemTypeBow) { + if (RangeItem->ItemType != EQEmu::item::ItemTypeBow) { Log.Out(Logs::Detail, Logs::Combat, "Ranged attack canceled. Ranged item is not a bow. type %d.", RangeItem->ItemType); Message(0, "Error: Rangeweapon: Item %d is not a bow.", RangeWeapon->GetID()); return; } - if(AmmoItem->ItemType != ItemTypeArrow) { + if (AmmoItem->ItemType != EQEmu::item::ItemTypeArrow) { Log.Out(Logs::Detail, Logs::Combat, "Ranged attack canceled. Ammo item is not an arrow. type %d.", AmmoItem->ItemType); - Message(0, "Error: Ammo: type %d != %d, you have the wrong type of ammo!", AmmoItem->ItemType, ItemTypeArrow); + Message(0, "Error: Ammo: type %d != %d, you have the wrong type of ammo!", AmmoItem->ItemType, EQEmu::item::ItemTypeArrow); return; } @@ -726,12 +715,12 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { //first look for quivers int r; bool found = false; - for(r = EmuConstants::GENERAL_BEGIN; r <= EmuConstants::GENERAL_END; r++) { + for (r = EQEmu::legacy::GENERAL_BEGIN; r <= EQEmu::legacy::GENERAL_END; r++) { const ItemInst *pi = m_inv[r]; - if(pi == nullptr || !pi->IsType(ItemClassContainer)) + if (pi == nullptr || !pi->IsClassBag()) continue; - const Item_Struct* bagitem = pi->GetItem(); - if(!bagitem || bagitem->BagType != BagTypeQuiver) + const EQEmu::ItemBase* bagitem = pi->GetItem(); + if (!bagitem || bagitem->BagType != EQEmu::item::BagTypeQuiver) continue; //we found a quiver, look for the ammo in it @@ -797,26 +786,26 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { //EndlessQuiver AA base1 = 100% Chance to avoid consumption arrow. int ChanceAvoidConsume = aabonuses.ConsumeProjectile + itembonuses.ConsumeProjectile + spellbonuses.ConsumeProjectile; - if (!ChanceAvoidConsume || (ChanceAvoidConsume < 100 && zone->random.Int(0,99) > ChanceAvoidConsume)){ + if (RangeItem->ExpendableArrow || !ChanceAvoidConsume || (ChanceAvoidConsume < 100 && zone->random.Int(0,99) > ChanceAvoidConsume)){ DeleteItemInInventory(ammo_slot, 1, true); Log.Out(Logs::Detail, Logs::Combat, "Consumed one arrow from slot %d", ammo_slot); } else { Log.Out(Logs::Detail, Logs::Combat, "Endless Quiver prevented ammo consumption."); } - CheckIncreaseSkill(SkillArchery, GetTarget(), -15); - CommonBreakInvisible(); + CheckIncreaseSkill(EQEmu::skills::SkillArchery, GetTarget(), -15); + CommonBreakInvisibleFromCombat(); } -void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, - uint32 range_id, uint32 ammo_id, const Item_Struct *AmmoItem, int AmmoSlot, float speed) { - - if ((other == nullptr || - ((IsClient() && CastToClient()->dead) || - (other->IsClient() && other->CastToClient()->dead)) || - HasDied() || +void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, + uint32 range_id, uint32 ammo_id, const EQEmu::ItemBase *AmmoItem, int AmmoSlot, float speed) { + + if ((other == nullptr || + ((IsClient() && CastToClient()->dead) || + (other->IsClient() && other->CastToClient()->dead)) || + HasDied() || (!IsAttackAllowed(other)) || - (other->GetInvul() || + (other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)))) { return; @@ -824,7 +813,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite const ItemInst* _RangeWeapon = nullptr; const ItemInst* _Ammo = nullptr; - const Item_Struct* ammo_lost = nullptr; + const EQEmu::ItemBase* ammo_lost = nullptr; /* If LaunchProjectile is false this function will do archery damage on target, @@ -841,12 +830,12 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite LaunchProjectile = true; else{ /* - Item sync check on projectile landing. + Item sync check on projectile landing. Weapon damage is already calculated so this only affects procs! Ammo proc check will use database to find proc if you used up your last ammo. If you change range item mid projectile flight, you loose your chance to proc from bow (Deal with it!). */ - + if (!RangeWeapon && !Ammo && range_id && ammo_id){ ProjectileImpact = true; @@ -856,10 +845,10 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite if (IsClient()){ - _RangeWeapon = CastToClient()->m_inv[MainRange]; + _RangeWeapon = CastToClient()->m_inv[EQEmu::legacy::SlotRange]; if (_RangeWeapon && _RangeWeapon->GetItem() && _RangeWeapon->GetItem()->ID == range_id) - RangeWeapon = _RangeWeapon; - + RangeWeapon = _RangeWeapon; + _Ammo = CastToClient()->m_inv[AmmoSlot]; if (_Ammo && _Ammo->GetItem() && _Ammo->GetItem()->ID == ammo_id) Ammo = _Ammo; @@ -870,22 +859,22 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite } } else if (AmmoItem) - SendItemAnimation(other, AmmoItem, SkillArchery); + SendItemAnimation(other, AmmoItem, EQEmu::skills::SkillArchery); - if (ProjectileMiss || (!ProjectileImpact && !other->CheckHitChance(this, SkillArchery, MainPrimary, chance_mod))) { + if (ProjectileMiss || (!ProjectileImpact && !other->CheckHitChance(this, EQEmu::skills::SkillArchery, EQEmu::legacy::SlotPrimary, chance_mod))) { Log.Out(Logs::Detail, Logs::Combat, "Ranged attack missed %s.", other->GetName()); if (LaunchProjectile){ - TryProjectileAttack(other, AmmoItem, SkillArchery, 0, RangeWeapon, Ammo, AmmoSlot, speed); + TryProjectileAttack(other, AmmoItem, EQEmu::skills::SkillArchery, 0, RangeWeapon, Ammo, AmmoSlot, speed); return; } else - other->Damage(this, 0, SPELL_UNKNOWN, SkillArchery); + other->Damage(this, 0, SPELL_UNKNOWN, EQEmu::skills::SkillArchery); } else { Log.Out(Logs::Detail, Logs::Combat, "Ranged attack hit %s.", other->GetName()); bool HeadShot = false; - uint32 HeadShot_Dmg = TryHeadShot(other, SkillArchery); + uint32 HeadShot_Dmg = TryHeadShot(other, EQEmu::skills::SkillArchery); if (HeadShot_Dmg) HeadShot = true; @@ -901,7 +890,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite WDmg = weapon_damage; if (LaunchProjectile){//1: Shoot the Projectile once we calculate weapon damage. - TryProjectileAttack(other, AmmoItem, SkillArchery, WDmg, RangeWeapon, Ammo, AmmoSlot, speed); + TryProjectileAttack(other, AmmoItem, EQEmu::skills::SkillArchery, (WDmg + ADmg), RangeWeapon, Ammo, AmmoSlot, speed); return; } @@ -913,7 +902,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite WDmg = 0; if(ADmg < 0) ADmg = 0; - uint32 MaxDmg = (RuleR(Combat, ArcheryBaseDamageBonus)*(WDmg+ADmg)*GetDamageTable(SkillArchery)) / 100; + uint32 MaxDmg = (RuleR(Combat, ArcheryBaseDamageBonus)*(WDmg + ADmg)*GetDamageTable(EQEmu::skills::SkillArchery)) / 100; hate = ((WDmg+ADmg)); if (HeadShot) @@ -923,7 +912,10 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite MaxDmg += MaxDmg*bonusArcheryDamageModifier / 100; - Log.Out(Logs::Detail, Logs::Combat, "Bow DMG %d, Arrow DMG %d, Max Damage %d.", WDmg, ADmg, MaxDmg); + if (RuleB(Combat, ProjectileDmgOnImpact)) + Log.Out(Logs::Detail, Logs::Combat, "Bow and Arrow DMG %d, Max Damage %d.", WDmg, MaxDmg); + else + Log.Out(Logs::Detail, Logs::Combat, "Bow DMG %d, Arrow DMG %d, Max Damage %d.", WDmg, ADmg, MaxDmg); bool dobonus = false; if(GetClass() == RANGER && GetLevel() > 50){ @@ -962,16 +954,16 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite //twice, for ammo and weapon TotalDmg += (2*((GetLevel()-25)/3)); minDmg += (2*((GetLevel()-25)/3)); - minDmg += minDmg * GetMeleeMinDamageMod_SE(SkillArchery) / 100; + minDmg += minDmg * GetMeleeMinDamageMod_SE(EQEmu::skills::SkillArchery) / 100; hate += (2*((GetLevel()-25)/3)); } if (!HeadShot) - other->AvoidDamage(this, TotalDmg, false); + other->AvoidDamage(this, TotalDmg, EQEmu::legacy::SlotRange); other->MeleeMitigation(this, TotalDmg, minDmg); if(TotalDmg > 0){ - CommonOutgoingHitSuccess(other, TotalDmg, SkillArchery); + CommonOutgoingHitSuccess(other, TotalDmg, EQEmu::skills::SkillArchery); TotalDmg = mod_archery_damage(TotalDmg, dobonus, RangeWeapon); } } @@ -984,14 +976,14 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite if (IsClient() && !CastToClient()->GetFeigned()) other->AddToHateList(this, hate, 0, false); - other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery); - + other->Damage(this, TotalDmg, SPELL_UNKNOWN, EQEmu::skills::SkillArchery); + //Skill Proc Success if (TotalDmg > 0 && HasSkillProcSuccess() && other && !other->HasDied()){ if (ReuseTime) - TrySkillProc(other, SkillArchery, ReuseTime); + TrySkillProc(other, EQEmu::skills::SkillArchery, ReuseTime); else - TrySkillProc(other, SkillArchery, 0, true, MainRange); + TrySkillProc(other, EQEmu::skills::SkillArchery, 0, true, EQEmu::legacy::SlotRange); } } @@ -1000,24 +992,24 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite //Weapon Proc if(RangeWeapon && other && !other->HasDied()) - TryWeaponProc(RangeWeapon, other, MainRange); + TryWeaponProc(RangeWeapon, other, EQEmu::legacy::SlotRange); //Ammo Proc if (ammo_lost) - TryWeaponProc(nullptr, ammo_lost, other, MainRange); + TryWeaponProc(nullptr, ammo_lost, other, EQEmu::legacy::SlotRange); else if(Ammo && other && !other->HasDied()) - TryWeaponProc(Ammo, other, MainRange); + TryWeaponProc(Ammo, other, EQEmu::legacy::SlotRange); //Skill Proc if (HasSkillProcs() && other && !other->HasDied()){ if (ReuseTime) - TrySkillProc(other, SkillArchery, ReuseTime); + TrySkillProc(other, EQEmu::skills::SkillArchery, ReuseTime); else - TrySkillProc(other, SkillArchery, 0, false, MainRange); + TrySkillProc(other, EQEmu::skills::SkillArchery, 0, false, EQEmu::legacy::SlotRange); } } -bool Mob::TryProjectileAttack(Mob* other, const Item_Struct *item, SkillUseTypes skillInUse, uint16 weapon_dmg, const ItemInst* RangeWeapon, const ItemInst* Ammo, int AmmoSlot, float speed){ +bool Mob::TryProjectileAttack(Mob* other, const EQEmu::ItemBase *item, EQEmu::skills::SkillType skillInUse, uint16 weapon_dmg, const ItemInst* RangeWeapon, const ItemInst* Ammo, int AmmoSlot, float speed){ if (!other) return false; @@ -1047,10 +1039,10 @@ bool Mob::TryProjectileAttack(Mob* other, const Item_Struct *item, SkillUseTypes ProjectileAtk[slot].origin_x = GetX(); ProjectileAtk[slot].origin_y = GetY(); ProjectileAtk[slot].origin_z = GetZ(); - + if (RangeWeapon && RangeWeapon->GetItem()) ProjectileAtk[slot].ranged_id = RangeWeapon->GetItem()->ID; - + if (Ammo && Ammo->GetItem()) ProjectileAtk[slot].ammo_id = Ammo->GetItem()->ID; @@ -1085,7 +1077,7 @@ void Mob::ProjectileAttack() disable = false; Mob* target = entity_list.GetMobID(ProjectileAtk[i].target_id); - + if (target && target->IsMoving()){ //Only recalculate hit increment if target moving //Due to frequency that we need to check increment the targets position variables may not be updated even if moving. Do a simple check before calculating distance. if (ProjectileAtk[i].tlast_x != target->GetX() || ProjectileAtk[i].tlast_y != target->GetY()){ @@ -1102,25 +1094,25 @@ void Mob::ProjectileAttack() if (target){ if (IsNPC()){ - if (ProjectileAtk[i].skill == SkillConjuration){ + if (ProjectileAtk[i].skill == EQEmu::skills::SkillConjuration){ if (IsValidSpell(ProjectileAtk[i].wpn_dmg)) SpellOnTarget(ProjectileAtk[i].wpn_dmg, target, false, true, spells[ProjectileAtk[i].wpn_dmg].ResistDiff, true); } else - CastToNPC()->DoRangedAttackDmg(target, false, ProjectileAtk[i].wpn_dmg,0, static_cast(ProjectileAtk[i].skill)); + CastToNPC()->DoRangedAttackDmg(target, false, ProjectileAtk[i].wpn_dmg, 0, static_cast(ProjectileAtk[i].skill)); } - + else { - if (ProjectileAtk[i].skill == SkillArchery) + if (ProjectileAtk[i].skill == EQEmu::skills::SkillArchery) DoArcheryAttackDmg(target, nullptr, nullptr,ProjectileAtk[i].wpn_dmg,0,0,0,ProjectileAtk[i].ranged_id, ProjectileAtk[i].ammo_id, nullptr, ProjectileAtk[i].ammo_slot); - else if (ProjectileAtk[i].skill == SkillThrowing) + else if (ProjectileAtk[i].skill == EQEmu::skills::SkillThrowing) DoThrowingAttackDmg(target, nullptr, nullptr,ProjectileAtk[i].wpn_dmg,0,0,0, ProjectileAtk[i].ranged_id, ProjectileAtk[i].ammo_slot); - else if (ProjectileAtk[i].skill == SkillConjuration && IsValidSpell(ProjectileAtk[i].wpn_dmg)) + else if (ProjectileAtk[i].skill == EQEmu::skills::SkillConjuration && IsValidSpell(ProjectileAtk[i].wpn_dmg)) SpellOnTarget(ProjectileAtk[i].wpn_dmg, target, false, true, spells[ProjectileAtk[i].wpn_dmg].ResistDiff, true); } } - + ProjectileAtk[i].increment = 0; ProjectileAtk[i].target_id = 0; ProjectileAtk[i].wpn_dmg = 0; @@ -1180,7 +1172,7 @@ float Mob::GetRangeDistTargetSizeMod(Mob* other) mod = 42.0f + (5.8f * (tsize - 15.0f)); else mod = 75.0f; - + return (mod + 2.0f); //Add 2.0f as buffer to prevent any chance of failures, client enforce range check regardless. } @@ -1210,7 +1202,7 @@ void NPC::RangedAttack(Mob* other) float min_range = static_cast(RuleI(Combat, MinRangedAttackDist)); float max_range = 250; // needs to be longer than 200(most spells) - + if (sa_max_range) max_range = static_cast(sa_max_range); @@ -1237,23 +1229,23 @@ void NPC::RangedAttack(Mob* other) DoRangedAttackDmg(other); - CommonBreakInvisible(); + CommonBreakInvisibleFromCombat(); } } -void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 chance_mod, SkillUseTypes skill, float speed, const char *IDFile) { - - if ((other == nullptr || - (other->HasDied())) || - HasDied() || +void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 chance_mod, EQEmu::skills::SkillType skill, float speed, const char *IDFile) { + + if ((other == nullptr || + (other->HasDied())) || + HasDied() || (!IsAttackAllowed(other)) || - (other->GetInvul() || + (other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE))) { return; } - SkillUseTypes skillInUse = static_cast(GetRangedSkill()); + EQEmu::skills::SkillType skillInUse = static_cast(GetRangedSkill()); if (skill != skillInUse) skillInUse = skill; @@ -1268,7 +1260,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha ammo = GetAmmoIDfile(); ProjectileAnimation(other, 0,false,speed,0,0,0,ammo,skillInUse); - + if (RuleB(Combat, ProjectileDmgOnImpact)) { TryProjectileAttack(other, nullptr, skillInUse, damage_mod, nullptr, nullptr, 0, speed); @@ -1276,10 +1268,10 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha } } - if (!chance_mod) + if (!chance_mod) chance_mod = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 2); - if (!other->CheckHitChance(this, skillInUse, MainRange, chance_mod)) + if (!other->CheckHitChance(this, skillInUse, EQEmu::legacy::SlotRange, chance_mod)) { other->Damage(this, 0, SPELL_UNKNOWN, skillInUse); } @@ -1298,11 +1290,11 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha if (!damage_mod) damage_mod = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 3);//Damage modifier - TotalDmg += TotalDmg * damage_mod / 100; + TotalDmg += TotalDmg * damage_mod / 100; - other->AvoidDamage(this, TotalDmg, false); + other->AvoidDamage(this, TotalDmg, EQEmu::legacy::SlotRange); other->MeleeMitigation(this, TotalDmg, MinDmg); - + if (TotalDmg > 0) CommonOutgoingHitSuccess(other, TotalDmg, skillInUse); else if (TotalDmg < -4) @@ -1316,19 +1308,19 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha other->Damage(this, TotalDmg, SPELL_UNKNOWN, skillInUse); if (TotalDmg > 0 && HasSkillProcSuccess() && !other->HasDied()) - TrySkillProc(other, skillInUse, 0, true, MainRange); + TrySkillProc(other, skillInUse, 0, true, EQEmu::legacy::SlotRange); } //try proc on hits and misses if(other && !other->HasDied()) - TrySpellProc(nullptr, (const Item_Struct*)nullptr, other, MainRange); + TrySpellProc(nullptr, (const EQEmu::ItemBase*)nullptr, other, EQEmu::legacy::SlotRange); if (HasSkillProcs() && other && !other->HasDied()) - TrySkillProc(other, skillInUse, 0, false, MainRange); + TrySkillProc(other, skillInUse, 0, false, EQEmu::legacy::SlotRange); } uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) { - uint16 MaxDmg = (((2 * wDmg) * GetDamageTable(SkillThrowing)) / 100); + uint16 MaxDmg = (((2 * wDmg) * GetDamageTable(EQEmu::skills::SkillThrowing)) / 100); if (MaxDmg == 0) MaxDmg = 1; @@ -1342,7 +1334,7 @@ uint16 Mob::GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg) { if(GetLevel() > 25){ TotalDmg += ((GetLevel()-25)/3); minDmg += ((GetLevel()-25)/3); - minDmg += minDmg * GetMeleeMinDamageMod_SE(SkillThrowing) / 100; + minDmg += minDmg * GetMeleeMinDamageMod_SE(EQEmu::skills::SkillThrowing) / 100; } if(MaxDmg < minDmg) @@ -1366,19 +1358,19 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 return; } - int ammo_slot = MainRange; - const ItemInst* RangeWeapon = m_inv[MainRange]; + int ammo_slot = EQEmu::legacy::SlotRange; + const ItemInst* RangeWeapon = m_inv[EQEmu::legacy::SlotRange]; - if (!RangeWeapon || !RangeWeapon->IsType(ItemClassCommon)) { - Log.Out(Logs::Detail, Logs::Combat, "Ranged attack canceled. Missing or invalid ranged weapon (%d) in slot %d", GetItemIDAt(MainRange), MainRange); - Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have nothing to throw!", GetItemIDAt(MainRange)); + if (!RangeWeapon || !RangeWeapon->IsClassCommon()) { + Log.Out(Logs::Detail, Logs::Combat, "Ranged attack canceled. Missing or invalid ranged weapon (%d) in slot %d", GetItemIDAt(EQEmu::legacy::SlotRange), EQEmu::legacy::SlotRange); + Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have nothing to throw!", GetItemIDAt(EQEmu::legacy::SlotRange)); return; } - const Item_Struct* item = RangeWeapon->GetItem(); - if(item->ItemType != ItemTypeLargeThrowing && item->ItemType != ItemTypeSmallThrowing) { + const EQEmu::ItemBase* item = RangeWeapon->GetItem(); + if (item->ItemType != EQEmu::item::ItemTypeLargeThrowing && item->ItemType != EQEmu::item::ItemTypeSmallThrowing) { Log.Out(Logs::Detail, Logs::Combat, "Ranged attack canceled. Ranged item %d is not a throwing weapon. type %d.", item->ItemType); - Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have nothing useful to throw!", GetItemIDAt(MainRange)); + Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have nothing useful to throw!", GetItemIDAt(EQEmu::legacy::SlotRange)); return; } @@ -1386,11 +1378,11 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 if(RangeWeapon->GetCharges() == 1) { //first check ammo - const ItemInst* AmmoItem = m_inv[MainAmmo]; + const ItemInst* AmmoItem = m_inv[EQEmu::legacy::SlotAmmo]; if(AmmoItem != nullptr && AmmoItem->GetID() == RangeWeapon->GetID()) { //more in the ammo slot, use it RangeWeapon = AmmoItem; - ammo_slot = MainAmmo; + ammo_slot = EQEmu::legacy::SlotAmmo; Log.Out(Logs::Detail, Logs::Combat, "Using ammo from ammo slot, stack at slot %d. %d in stack.", ammo_slot, RangeWeapon->GetCharges()); } else { //look through our inventory for more @@ -1432,25 +1424,25 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 //consume ammo DeleteItemInInventory(ammo_slot, 1, true); - CheckIncreaseSkill(SkillThrowing, GetTarget()); - CommonBreakInvisible(); + CheckIncreaseSkill(EQEmu::skills::SkillThrowing, GetTarget()); + CommonBreakInvisibleFromCombat(); } -void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* AmmoItem, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime, uint32 range_id, int AmmoSlot, float speed) +void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const EQEmu::ItemBase* AmmoItem, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, uint32 range_id, int AmmoSlot, float speed) { - if ((other == nullptr || - ((IsClient() && CastToClient()->dead) || - (other->IsClient() && other->CastToClient()->dead)) || - HasDied() || + if ((other == nullptr || + ((IsClient() && CastToClient()->dead) || + (other->IsClient() && other->CastToClient()->dead)) || + HasDied() || (!IsAttackAllowed(other)) || - (other->GetInvul() || + (other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)))) { return; } const ItemInst* _RangeWeapon = nullptr; - const Item_Struct* ammo_lost = nullptr; + const EQEmu::ItemBase* ammo_lost = nullptr; /* If LaunchProjectile is false this function will do archery damage on target, @@ -1485,16 +1477,16 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite } } else if (AmmoItem) - SendItemAnimation(other, AmmoItem, SkillThrowing); + SendItemAnimation(other, AmmoItem, EQEmu::skills::SkillThrowing); - if (ProjectileMiss || (!ProjectileImpact && !other->CheckHitChance(this, SkillThrowing, MainPrimary, chance_mod))){ + if (ProjectileMiss || (!ProjectileImpact && !other->CheckHitChance(this, EQEmu::skills::SkillThrowing, EQEmu::legacy::SlotPrimary, chance_mod))){ Log.Out(Logs::Detail, Logs::Combat, "Ranged attack missed %s.", other->GetName()); if (LaunchProjectile){ - TryProjectileAttack(other, AmmoItem, SkillThrowing, 0, RangeWeapon, nullptr, AmmoSlot, speed); + TryProjectileAttack(other, AmmoItem, EQEmu::skills::SkillThrowing, 0, RangeWeapon, nullptr, AmmoSlot, speed); return; } else - other->Damage(this, 0, SPELL_UNKNOWN, SkillThrowing); + other->Damage(this, 0, SPELL_UNKNOWN, EQEmu::skills::SkillThrowing); } else { Log.Out(Logs::Detail, Logs::Combat, "Throwing attack hit %s.", other->GetName()); @@ -1507,11 +1499,11 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite WDmg = GetWeaponDamage(other, AmmoItem); if (LaunchProjectile){ - TryProjectileAttack(other, AmmoItem, SkillThrowing, WDmg, RangeWeapon, nullptr, AmmoSlot, speed); + TryProjectileAttack(other, AmmoItem, EQEmu::skills::SkillThrowing, WDmg, RangeWeapon, nullptr, AmmoSlot, speed); return; } } - else + else WDmg = weapon_damage; if (focus) //From FcBaseEffects @@ -1521,7 +1513,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite uint32 Assassinate_Dmg = 0; if (GetClass() == ROGUE && (BehindMob(other, GetX(), GetY()))) - Assassinate_Dmg = TryAssassinate(other, SkillThrowing, ranged_timer.GetDuration()); + Assassinate_Dmg = TryAssassinate(other, EQEmu::skills::SkillThrowing, ranged_timer.GetDuration()); if(WDmg > 0){ int minDmg = 1; @@ -1534,11 +1526,11 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite Log.Out(Logs::Detail, Logs::Combat, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg); if (!Assassinate_Dmg) - other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks. - + other->AvoidDamage(this, TotalDmg, EQEmu::legacy::SlotRange); + other->MeleeMitigation(this, TotalDmg, minDmg); if(TotalDmg > 0) - CommonOutgoingHitSuccess(other, TotalDmg, SkillThrowing); + CommonOutgoingHitSuccess(other, TotalDmg, EQEmu::skills::SkillThrowing); } else @@ -1547,13 +1539,13 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite if (IsClient() && !CastToClient()->GetFeigned()) other->AddToHateList(this, 2*WDmg, 0, false); - other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillThrowing); + other->Damage(this, TotalDmg, SPELL_UNKNOWN, EQEmu::skills::SkillThrowing); if (TotalDmg > 0 && HasSkillProcSuccess() && other && !other->HasDied()){ if (ReuseTime) - TrySkillProc(other, SkillThrowing, ReuseTime); + TrySkillProc(other, EQEmu::skills::SkillThrowing, ReuseTime); else - TrySkillProc(other, SkillThrowing, 0, true, MainRange); + TrySkillProc(other, EQEmu::skills::SkillThrowing, 0, true, EQEmu::legacy::SlotRange); } } @@ -1562,20 +1554,20 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite //Throwing item Proc if (ammo_lost) - TryWeaponProc(nullptr, ammo_lost, other, MainRange); + TryWeaponProc(nullptr, ammo_lost, other, EQEmu::legacy::SlotRange); else if(RangeWeapon && other && !other->HasDied()) - TryWeaponProc(RangeWeapon, other, MainRange); + TryWeaponProc(RangeWeapon, other, EQEmu::legacy::SlotRange); if (HasSkillProcs() && other && !other->HasDied()){ if (ReuseTime) - TrySkillProc(other, SkillThrowing, ReuseTime); + TrySkillProc(other, EQEmu::skills::SkillThrowing, ReuseTime); else - TrySkillProc(other, SkillThrowing, 0, false, MainRange); + TrySkillProc(other, EQEmu::skills::SkillThrowing, 0, false, EQEmu::legacy::SlotRange); } } -void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skillInUse, float velocity) { - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SomeItemPacketMaybe, sizeof(Arrow_Struct)); +void Mob::SendItemAnimation(Mob *to, const EQEmu::ItemBase *item, EQEmu::skills::SkillType skillInUse, float velocity) { + auto outapp = new EQApplicationPacket(OP_SomeItemPacketMaybe, sizeof(Arrow_Struct)); Arrow_Struct *as = (Arrow_Struct *) outapp->pBuffer; as->type = 1; as->src_x = GetX(); @@ -1620,11 +1612,11 @@ void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skil safe_delete(outapp); } -void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, SkillUseTypes skillInUse) { +void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, float angle, float tilt, float arc, const char *IDFile, EQEmu::skills::SkillType skillInUse) { if (!to) return; - const Item_Struct* item = nullptr; + const EQEmu::ItemBase* item = nullptr; uint8 item_type = 0; if(!item_id) { @@ -1665,7 +1657,7 @@ void Mob::ProjectileAnimation(Mob* to, int item_id, bool IsArrow, float speed, f item_IDFile = IDFile; // See SendItemAnimation() for some notes on this struct - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SomeItemPacketMaybe, sizeof(Arrow_Struct)); + auto outapp = new EQApplicationPacket(OP_SomeItemPacketMaybe, sizeof(Arrow_Struct)); Arrow_Struct *as = (Arrow_Struct *) outapp->pBuffer; as->type = 1; as->src_x = GetX(); @@ -1747,12 +1739,12 @@ void NPC::DoClassAttacks(Mob *target) { } break; case MONK: case MONKGM: { - uint8 satype = SkillKick; - if(level > 29) { satype = SkillFlyingKick; } - else if(level > 24) { satype = SkillDragonPunch; } - else if(level > 19) { satype = SkillEagleStrike; } - else if(level > 9) { satype = SkillTigerClaw; } - else if(level > 4) { satype = SkillRoundKick; } + uint8 satype = EQEmu::skills::SkillKick; + if (level > 29) { satype = EQEmu::skills::SkillFlyingKick; } + else if (level > 24) { satype = EQEmu::skills::SkillDragonPunch; } + else if (level > 19) { satype = EQEmu::skills::SkillEagleStrike; } + else if (level > 9) { satype = EQEmu::skills::SkillTigerClaw; } + else if (level > 4) { satype = EQEmu::skills::SkillRoundKick; } reuse = MonkSpecialAttack(target, satype); reuse *= 1000; @@ -1765,11 +1757,11 @@ void NPC::DoClassAttacks(Mob *target) { DoAnim(animKick); int32 dmg = 0; - if(GetWeaponDamage(target, (const Item_Struct*)nullptr) <= 0){ + if (GetWeaponDamage(target, (const EQEmu::ItemBase*)nullptr) <= 0){ dmg = -5; } else{ - if(target->CheckHitChance(this, SkillKick, 0)) { + if (target->CheckHitChance(this, EQEmu::skills::SkillKick, 0)) { if(RuleB(Combat, UseIntervalAC)) dmg = GetKickDamage(); else @@ -1779,18 +1771,18 @@ void NPC::DoClassAttacks(Mob *target) { } reuse = (KickReuseTime + 3) * 1000; - DoSpecialAttackDamage(target, SkillKick, dmg, 1, -1, reuse); + DoSpecialAttackDamage(target, EQEmu::skills::SkillKick, dmg, 1, -1, reuse); did_attack = true; } else { DoAnim(animTailRake); int32 dmg = 0; - if(GetWeaponDamage(target, (const Item_Struct*)nullptr) <= 0){ + if (GetWeaponDamage(target, (const EQEmu::ItemBase*)nullptr) <= 0){ dmg = -5; } else{ - if(target->CheckHitChance(this, SkillBash, 0)) { + if (target->CheckHitChance(this, EQEmu::skills::SkillBash, 0)) { if(RuleB(Combat, UseIntervalAC)) dmg = GetBashDamage(); else @@ -1799,7 +1791,7 @@ void NPC::DoClassAttacks(Mob *target) { } reuse = (BashReuseTime + 3) * 1000; - DoSpecialAttackDamage(target, SkillBash, dmg, 1, -1, reuse); + DoSpecialAttackDamage(target, EQEmu::skills::SkillBash, dmg, 1, -1, reuse); did_attack = true; } } @@ -1823,7 +1815,7 @@ void NPC::DoClassAttacks(Mob *target) { while(AtkRounds > 0) { if (GetTarget() && (AtkRounds == 1 || zone->random.Roll(75))) { - DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, -1 , reuse, true); + DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillFrenzy, max_dmg, min_dmg, -1, reuse, true); } AtkRounds--; } @@ -1839,11 +1831,11 @@ void NPC::DoClassAttacks(Mob *target) { DoAnim(animKick); int32 dmg = 0; - if(GetWeaponDamage(target, (const Item_Struct*)nullptr) <= 0){ + if (GetWeaponDamage(target, (const EQEmu::ItemBase*)nullptr) <= 0){ dmg = -5; } else{ - if(target->CheckHitChance(this, SkillKick, 0)) { + if (target->CheckHitChance(this, EQEmu::skills::SkillKick, 0)) { if(RuleB(Combat, UseIntervalAC)) dmg = GetKickDamage(); else @@ -1852,7 +1844,7 @@ void NPC::DoClassAttacks(Mob *target) { } reuse = (KickReuseTime + 3) * 1000; - DoSpecialAttackDamage(target, SkillKick, dmg, 1, -1, reuse); + DoSpecialAttackDamage(target, EQEmu::skills::SkillKick, dmg, 1, -1, reuse); did_attack = true; } break; @@ -1864,11 +1856,11 @@ void NPC::DoClassAttacks(Mob *target) { DoAnim(animTailRake); int32 dmg = 0; - if(GetWeaponDamage(target, (const Item_Struct*)nullptr) <= 0){ + if (GetWeaponDamage(target, (const EQEmu::ItemBase*)nullptr) <= 0){ dmg = -5; } else{ - if(target->CheckHitChance(this, SkillBash, 0)) { + if (target->CheckHitChance(this, EQEmu::skills::SkillBash, 0)) { if(RuleB(Combat, UseIntervalAC)) dmg = GetBashDamage(); else @@ -1877,7 +1869,7 @@ void NPC::DoClassAttacks(Mob *target) { } reuse = (BashReuseTime + 3) * 1000; - DoSpecialAttackDamage(target, SkillBash, dmg, 1, -1, reuse); + DoSpecialAttackDamage(target, EQEmu::skills::SkillBash, dmg, 1, -1, reuse); did_attack = true; } break; @@ -1919,43 +1911,43 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) case WARRIOR: case RANGER: case BEASTLORD: - skill_to_use = SkillKick; + skill_to_use = EQEmu::skills::SkillKick; break; case BERSERKER: - skill_to_use = SkillFrenzy; + skill_to_use = EQEmu::skills::SkillFrenzy; break; case SHADOWKNIGHT: case PALADIN: - skill_to_use = SkillBash; + skill_to_use = EQEmu::skills::SkillBash; break; case MONK: if(GetLevel() >= 30) { - skill_to_use = SkillFlyingKick; + skill_to_use = EQEmu::skills::SkillFlyingKick; } else if(GetLevel() >= 25) { - skill_to_use = SkillDragonPunch; + skill_to_use = EQEmu::skills::SkillDragonPunch; } else if(GetLevel() >= 20) { - skill_to_use = SkillEagleStrike; + skill_to_use = EQEmu::skills::SkillEagleStrike; } else if(GetLevel() >= 10) { - skill_to_use = SkillTigerClaw; + skill_to_use = EQEmu::skills::SkillTigerClaw; } else if(GetLevel() >= 5) { - skill_to_use = SkillRoundKick; + skill_to_use = EQEmu::skills::SkillRoundKick; } else { - skill_to_use = SkillKick; + skill_to_use = EQEmu::skills::SkillKick; } break; case ROGUE: - skill_to_use = SkillBackstab; + skill_to_use = EQEmu::skills::SkillBackstab; break; } } @@ -1966,15 +1958,15 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) if(skill_to_use == -1) return; - if(skill_to_use == SkillBash) { + if (skill_to_use == EQEmu::skills::SkillBash) { if (ca_target!=this) { DoAnim(animTailRake); - if(GetWeaponDamage(ca_target, GetInv().GetItem(MainSecondary)) <= 0 && GetWeaponDamage(ca_target, GetInv().GetItem(MainShoulders)) <= 0){ + if (GetWeaponDamage(ca_target, GetInv().GetItem(EQEmu::legacy::SlotSecondary)) <= 0 && GetWeaponDamage(ca_target, GetInv().GetItem(EQEmu::legacy::SlotShoulders)) <= 0){ dmg = -5; } else{ - if(!ca_target->CheckHitChance(this, SkillBash, 0)) { + if (!ca_target->CheckHitChance(this, EQEmu::skills::SkillBash, 0)) { dmg = 0; } else{ @@ -1988,7 +1980,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) ReuseTime = (BashReuseTime - 1) / HasteMod; - DoSpecialAttackDamage(ca_target, SkillBash, dmg, 1,-1,ReuseTime); + DoSpecialAttackDamage(ca_target, EQEmu::skills::SkillBash, dmg, 1, -1, ReuseTime); if(ReuseTime > 0 && !IsRiposte) { p_timers.Start(pTimerCombatAbility, ReuseTime); @@ -1997,10 +1989,10 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) return; } - if(skill_to_use == SkillFrenzy){ - CheckIncreaseSkill(SkillFrenzy, GetTarget(), 10); + if (skill_to_use == EQEmu::skills::SkillFrenzy){ + CheckIncreaseSkill(EQEmu::skills::SkillFrenzy, GetTarget(), 10); int AtkRounds = 3; - int skillmod = 100*GetSkill(SkillFrenzy)/MaxSkill(SkillFrenzy); + int skillmod = 100 * GetSkill(EQEmu::skills::SkillFrenzy) / MaxSkill(EQEmu::skills::SkillFrenzy); int32 max_dmg = (26 + ((((GetLevel()-6) * 2)*skillmod)/100)) * ((100+RuleI(Combat, FrenzyBonus))/100); int32 min_dmg = 0; DoAnim(anim2HSlashing); @@ -2019,7 +2011,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) while(AtkRounds > 0) { if (GetTarget() && (AtkRounds == 1 || zone->random.Roll(75))) { - DoSpecialAttackDamage(GetTarget(), SkillFrenzy, max_dmg, min_dmg, max_dmg , ReuseTime, true); + DoSpecialAttackDamage(GetTarget(), EQEmu::skills::SkillFrenzy, max_dmg, min_dmg, max_dmg, ReuseTime, true); } AtkRounds--; } @@ -2030,15 +2022,15 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) return; } - if(skill_to_use == SkillKick){ + if (skill_to_use == EQEmu::skills::SkillKick){ if(ca_target!=this){ DoAnim(animKick); - if(GetWeaponDamage(ca_target, GetInv().GetItem(MainFeet)) <= 0){ + if (GetWeaponDamage(ca_target, GetInv().GetItem(EQEmu::legacy::SlotFeet)) <= 0){ dmg = -5; } else{ - if(!ca_target->CheckHitChance(this, SkillKick, 0)) { + if (!ca_target->CheckHitChance(this, EQEmu::skills::SkillKick, 0)) { dmg = 0; } else{ @@ -2051,11 +2043,11 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) ReuseTime = KickReuseTime-1; - DoSpecialAttackDamage(ca_target, SkillKick, dmg, 1,-1, ReuseTime); + DoSpecialAttackDamage(ca_target, EQEmu::skills::SkillKick, dmg, 1, -1, ReuseTime); } } - if(skill_to_use == SkillFlyingKick || skill_to_use == SkillDragonPunch || skill_to_use == SkillEagleStrike || skill_to_use == SkillTigerClaw || skill_to_use == SkillRoundKick) { + if (skill_to_use == EQEmu::skills::SkillFlyingKick || skill_to_use == EQEmu::skills::SkillDragonPunch || skill_to_use == EQEmu::skills::SkillEagleStrike || skill_to_use == EQEmu::skills::SkillTigerClaw || skill_to_use == EQEmu::skills::SkillRoundKick) { ReuseTime = MonkSpecialAttack(ca_target, skill_to_use) - 1; MonkSpecialAttack(ca_target, skill_to_use); @@ -2066,7 +2058,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack; if (wuchance) { if (wuchance >= 100 || zone->random.Roll(wuchance)) { - int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick }; + int MonkSPA[5] = { EQEmu::skills::SkillFlyingKick, EQEmu::skills::SkillDragonPunch, EQEmu::skills::SkillEagleStrike, EQEmu::skills::SkillTigerClaw, EQEmu::skills::SkillRoundKick }; int extra = 1; if (zone->random.Roll(wuchance / 4)) extra++; @@ -2082,7 +2074,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) } } - if(skill_to_use == SkillBackstab){ + if (skill_to_use == EQEmu::skills::SkillBackstab){ ReuseTime = BackstabReuseTime-1; if (IsRiposte) @@ -2092,12 +2084,12 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) } ReuseTime = ReuseTime / HasteMod; - if(ReuseTime > 0 && !IsRiposte){ + if(ReuseTime > 0 && !IsRiposte){ p_timers.Start(pTimerCombatAbility, ReuseTime); } } -void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { +void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus, bool FromSpell, int32 bonus_hate) { if (who == nullptr) return; @@ -2105,11 +2097,11 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { if(DivineAura()) return; - if(!CombatRange(who)) + if(!FromSpell && !CombatRange(who)) return; if(!always_succeed && IsClient()) - CastToClient()->CheckIncreaseSkill(SkillTaunt, who, 10); + CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillTaunt, who, 10); Mob *hate_top = who->GetHateMost(); @@ -2148,7 +2140,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { //TauntSkillFalloff rate is not based on any real data. Default of 33% gives a reasonable result. if (IsClient() && !always_succeed) - tauntchance -= (RuleR(Combat,TauntSkillFalloff) * (CastToClient()->MaxSkill(SkillTaunt) - GetSkill(SkillTaunt))); + tauntchance -= (RuleR(Combat, TauntSkillFalloff) * (CastToClient()->MaxSkill(EQEmu::skills::SkillTaunt) - GetSkill(EQEmu::skills::SkillTaunt))); //From SE_Taunt (Does a taunt with a chance modifier) if (chance_bonus) @@ -2161,7 +2153,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { if (tauntchance > zone->random.Real(0, 1)) { if (hate_top && hate_top != this){ - newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1; + newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1 + bonus_hate; who->CastToNPC()->AddToHateList(this, newhate); Success = true; } @@ -2180,10 +2172,10 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { Message_StringID(MT_SpellFailure,FAILED_TAUNT); if (HasSkillProcs()) - TrySkillProc(who, SkillTaunt, TauntReuseTime*1000); + TrySkillProc(who, EQEmu::skills::SkillTaunt, TauntReuseTime * 1000); if (Success && HasSkillProcSuccess()) - TrySkillProc(who, SkillTaunt, TauntReuseTime*1000, true); + TrySkillProc(who, EQEmu::skills::SkillTaunt, TauntReuseTime * 1000, true); } @@ -2203,14 +2195,14 @@ void Mob::InstillDoubt(Mob *who) { return; if(IsClient()) { - CastToClient()->CheckIncreaseSkill(SkillIntimidation, who, 10); + CastToClient()->CheckIncreaseSkill(EQEmu::skills::SkillIntimidation, who, 10); } //I think this formula needs work int value = 0; //user's bonus - value += GetSkill(SkillIntimidation) + GetCHA()/4; + value += GetSkill(EQEmu::skills::SkillIntimidation) + GetCHA() / 4; //target's counters value -= target->GetLevel()*4 + who->GetWIS()/4; @@ -2232,10 +2224,10 @@ void Mob::InstillDoubt(Mob *who) { } } -uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { +uint32 Mob::TryHeadShot(Mob* defender, EQEmu::skills::SkillType skillInUse) { //Only works on YOUR target. if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() - && (skillInUse == SkillArchery) && (GetTarget() == defender)) { + && (skillInUse == EQEmu::skills::SkillArchery) && (GetTarget() == defender)) { uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1]; uint8 HeadShot_Level = 0; //Get Highest Headshot Level @@ -2246,7 +2238,7 @@ uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { HeadShot_Level = itembonuses.HSLevel; if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){ - float ProcChance = GetSpecialProcChances(MainRange); + float ProcChance = GetSpecialProcChances(EQEmu::legacy::SlotRange); if(zone->random.Roll(ProcChance)) return HeadShot_Dmg; } @@ -2270,7 +2262,7 @@ float Mob::GetSpecialProcChances(uint16 hand) if (RuleB(Combat, AdjustSpecialProcPerMinute)) { ProcChance = (static_cast(weapon_speed) * - RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); + RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); ProcBonus += static_cast(mydex/35) + static_cast(itembonuses.HeroicDEX / 25); ProcChance += ProcChance * ProcBonus / 100.0f; } else { @@ -2283,10 +2275,10 @@ float Mob::GetSpecialProcChances(uint16 hand) return ProcChance; } -uint32 Mob::TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 ReuseTime) { +uint32 Mob::TryAssassinate(Mob* defender, EQEmu::skills::SkillType skillInUse, uint16 ReuseTime) { if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() && - (skillInUse == SkillBackstab || skillInUse == SkillThrowing)) { + (skillInUse == EQEmu::skills::SkillBackstab || skillInUse == EQEmu::skills::SkillThrowing)) { uint32 Assassinate_Dmg = aabonuses.Assassinate[1] + spellbonuses.Assassinate[1] + itembonuses.Assassinate[1]; @@ -2308,8 +2300,8 @@ uint32 Mob::TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 Reuse if(Assassinate_Dmg && Assassinate_Level && (defender->GetLevel() <= Assassinate_Level)){ float ProcChance = 0.0f; - if (skillInUse == SkillThrowing) - ProcChance = GetSpecialProcChances(MainRange); + if (skillInUse == EQEmu::skills::SkillThrowing) + ProcChance = GetSpecialProcChances(EQEmu::legacy::SlotRange); else ProcChance = GetAssassinateProcChances(ReuseTime); @@ -2346,7 +2338,7 @@ float Mob::GetAssassinateProcChances(uint16 ReuseTime) return ProcChance; } -void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime) +void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime) { if (!CanDoSpecialAttack(other)) return; @@ -2355,15 +2347,15 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes For spells using skill value 98 (feral swipe ect) server sets this to 67 automatically. Kayen: This is unlikely to be completely accurate but use OFFENSE skill value for these effects. */ - if (skillinuse == SkillBegging) - skillinuse = SkillOffense; + if (skillinuse == EQEmu::skills::SkillBegging) + skillinuse = EQEmu::skills::SkillOffense; int damage = 0; uint32 hate = 0; - int Hand = MainPrimary; + int Hand = EQEmu::legacy::SlotPrimary; if (hate == 0 && weapon_damage > 1) hate = weapon_damage; - if(weapon_damage > 0){ + if(weapon_damage > 0){ if (focus) //From FcBaseEffects weapon_damage += weapon_damage*focus/100; @@ -2376,20 +2368,20 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes int32 max_hit = (2 * weapon_damage*GetDamageTable(skillinuse)) / 100; if(GetLevel() >= 28 && IsWarriorClass() ) { - int ucDamageBonus = GetWeaponDamageBonus((const Item_Struct*) nullptr ); + int ucDamageBonus = GetWeaponDamageBonus((const EQEmu::ItemBase*) nullptr); min_hit += (int) ucDamageBonus; max_hit += (int) ucDamageBonus; hate += ucDamageBonus; } - if(skillinuse == SkillBash){ + if (skillinuse == EQEmu::skills::SkillBash){ if(IsClient()){ - ItemInst *item = CastToClient()->GetInv().GetItem(MainSecondary); + ItemInst *item = CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotSecondary); if(item){ - if(item->GetItem()->ItemType == ItemTypeShield) { + if (item->GetItem()->ItemType == EQEmu::item::ItemTypeShield) { hate += item->GetItem()->AC; } - const Item_Struct *itm = item->GetItem(); + const EQEmu::ItemBase *itm = item->GetItem(); hate = hate * (100 + GetFuriousBash(itm->Focus.Effect)) / 100; } } @@ -2406,50 +2398,48 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes else damage = zone->random.Int(min_hit, max_hit); - if(!other->CheckHitChance(this, skillinuse, Hand, chance_mod)) { - damage = 0; + if (other->AvoidDamage(this, damage, CanRiposte ? EQEmu::legacy::SlotRange : EQEmu::legacy::SlotPrimary)) { // SlotRange excludes ripo, primary doesn't have any extra behavior + if (damage == -3) { + DoRiposte(other); + if (HasDied()) + return; + } } else { - other->AvoidDamage(this, damage, CanRiposte); - other->MeleeMitigation(this, damage, min_hit); - if(damage > 0) + if (other->CheckHitChance(this, skillinuse, Hand, chance_mod)) { + other->MeleeMitigation(this, damage, min_hit); CommonOutgoingHitSuccess(other, damage, skillinuse); + } else { + damage = 0; + } } - if (damage == -3) { - DoRiposte(other); - if (HasDied()) - return; - } } else damage = -5; - other->AddToHateList(this, hate); - bool CanSkillProc = true; - if (skillinuse == SkillOffense){ //Hack to allow damage to display. - skillinuse = SkillTigerClaw; //'strike' your opponent - Arbitrary choice for message. + if (skillinuse == EQEmu::skills::SkillOffense){ //Hack to allow damage to display. + skillinuse = EQEmu::skills::SkillTigerClaw; //'strike' your opponent - Arbitrary choice for message. CanSkillProc = false; //Disable skill procs } other->AddToHateList(this, hate, 0, false); + if (damage > 0 && aabonuses.SkillAttackProc[0] && aabonuses.SkillAttackProc[1] == skillinuse && + IsValidSpell(aabonuses.SkillAttackProc[2])) { + float chance = aabonuses.SkillAttackProc[0] / 1000.0f; + if (zone->random.Roll(chance)) + SpellFinished(aabonuses.SkillAttackProc[2], other, EQEmu::CastingSlot::Item, 0, -1, + spells[aabonuses.SkillAttackProc[2]].ResistDiff); + } other->Damage(this, damage, SPELL_UNKNOWN, skillinuse); if (HasDied()) return; - if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skillinuse){ - int kb_chance = 25; - kb_chance += kb_chance*(100-aabonuses.SpecialAttackKBProc[0])/100; - - if (zone->random.Roll(kb_chance)) - SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff); - } - if (CanSkillProc && HasSkillProcs()) TrySkillProc(other, skillinuse, ReuseTime); - + if (CanSkillProc && (damage > 0) && HasSkillProcSuccess()) TrySkillProc(other, skillinuse, ReuseTime, true); } diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 24eac51ee..0b67ea523 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -24,6 +24,7 @@ #include "../common/rulesys.h" #include "../common/skills.h" #include "../common/spdat.h" +#include "../common/data_verification.h" #include "quest_parser_collection.h" #include "string_ids.h" @@ -38,13 +39,13 @@ extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; // the spell can still fail here, if the buff can't stack // in this case false will be returned, true otherwise -bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) +bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_override) { int caster_level, buffslot, effect, effect_value, i; ItemInst *SummonedItem=nullptr; @@ -59,31 +60,32 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) const SPDat_Spell_Struct &spell = spells[spell_id]; bool c_override = false; - if(caster && caster->IsClient() && GetCastedSpellInvSlot() > 0) - { - const ItemInst* inst = caster->CastToClient()->GetInv().GetItem(GetCastedSpellInvSlot()); - if(inst) - { - if(inst->GetItem()->Click.Level > 0) - { + if (caster && caster->IsClient() && GetCastedSpellInvSlot() > 0) { + const ItemInst *inst = caster->CastToClient()->GetInv().GetItem(GetCastedSpellInvSlot()); + if (inst) { + if (inst->GetItem()->Click.Level > 0) { caster_level = inst->GetItem()->Click.Level; c_override = true; - } - else - { + } else { caster_level = caster ? caster->GetCasterLevel(spell_id) : GetCasterLevel(spell_id); } - } - else + } else if (level_override > 0) { + caster_level = level_override; + c_override = true; + } else { caster_level = caster ? caster->GetCasterLevel(spell_id) : GetCasterLevel(spell_id); - } - else + } + } else if (level_override > 0) { + caster_level = level_override; + c_override = true; + } else { caster_level = caster ? caster->GetCasterLevel(spell_id) : GetCasterLevel(spell_id); + } if(c_override) { int durat = CalcBuffDuration(caster, this, spell_id, caster_level); - if(durat > 0) + if(durat) // negatives are perma buffs { buffslot = AddBuff(caster, spell_id, durat, caster_level); if(buffslot == -1) // stacking failure @@ -134,7 +136,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (spells[spell_id].EndurUpkeep > 0) SetEndurUpkeep(true); - if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UFAndLater) + if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) { EQApplicationPacket *outapp = MakeBuffsPacket(false); CastToClient()->FastQueuePacket(&outapp); @@ -189,8 +191,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (!IsPowerDistModSpell(spell_id)) SetSpellPowerDistanceMod(0); - - bool SE_SpellTrigger_HasCast = false; + + bool SE_SpellTrigger_HasCast = false; // iterate through the effects in the spell for (i = 0; i < EFFECT_COUNT; i++) @@ -199,7 +201,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) continue; effect = spell.effectid[i]; - effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster ? caster : this); + // if buff slot, use instrument mod there, otherwise calc it + uint32 inst = buffslot > -1 ? buffs[buffslot].instrument_mod : caster ? caster->GetInstrumentMod(spell_id) : 10; + effect_value = CalcSpellEffectValue(spell_id, i, caster_level, inst, caster ? caster : this); if(spell_id == SPELL_LAY_ON_HANDS && caster && caster->GetAA(aaImprovedLayOnHands)) effect_value = GetMaxHP(); @@ -282,9 +286,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) //do any AAs apply to these spells? if(dmg < 0) { + if (!PassCastRestriction(false, spells[spell_id].base2[i], true)) + break; dmg = -dmg; Damage(caster, dmg, spell_id, spell.skill, false, buffslot, false); } else { + if (!PassCastRestriction(false, spells[spell_id].base2[i], false)) + break; HealDamage(dmg, caster); } break; @@ -349,8 +357,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; int32 val = 0; - val = 7500*effect_value; - val = caster->GetActSpellHealing(spell_id, val, this); + val = 7500 * effect_value; + if (caster) + val = caster->GetActSpellHealing(spell_id, val, this); if (val > 0) HealDamage(val, caster); @@ -369,12 +378,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) snprintf(effect_desc, _EDLEN, "Current Mana: %+i", effect_value); #endif SetMana(GetMana() + effect_value); - caster->SetMana(caster->GetMana() + std::abs(effect_value)); + if (caster) + caster->SetMana(caster->GetMana() + std::abs(effect_value)); if (effect_value < 0) TryTriggerOnValueAmount(false, true); #ifdef SPELL_EFFECT_SPAM - caster->Message(0, "You have gained %+i mana!", effect_value); + if (caster) + caster->Message(0, "You have gained %+i mana!", effect_value); #endif } } @@ -424,11 +435,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } case SE_Succor: - { - + { + float x, y, z, heading; const char *target_zone; - + x = static_cast(spell.base[1]); y = static_cast(spell.base[0]); z = static_cast(spell.base[2]); @@ -494,7 +505,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - case SE_GateCastersBindpoint: //Shin: Used on Teleport Bind. + case SE_GateCastersBindpoint: // Used on Teleport Bind. case SE_Teleport: // gates, rings, circles, etc case SE_Teleport2: { @@ -526,14 +537,17 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } } - if (effect == SE_GateCastersBindpoint && caster->IsClient()) - { //Shin: Teleport Bind uses caster's bind point - x = caster->CastToClient()->GetBindX(); - y = caster->CastToClient()->GetBindY(); - z = caster->CastToClient()->GetBindZ(); - heading = caster->CastToClient()->GetBindHeading(); + if (effect == SE_GateCastersBindpoint && caster && caster->IsClient()) + { // Teleport Bind uses caster's bind point + int index = spells[spell_id].base[i] - 1; + if (index < 0 || index > 4) + index = 0; + x = caster->CastToClient()->GetBindX(index); + y = caster->CastToClient()->GetBindY(index); + z = caster->CastToClient()->GetBindZ(index); + heading = caster->CastToClient()->GetBindHeading(index); //target_zone = caster->CastToClient()->GetBindZoneId(); target_zone doesn't work due to const char - CastToClient()->MovePC(caster->CastToClient()->GetBindZoneID(), 0, x, y, z, heading); + CastToClient()->MovePC(caster->CastToClient()->GetBindZoneID(index), 0, x, y, z, heading); break; } @@ -608,8 +622,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) snprintf(effect_desc, _EDLEN, "Flesh To Bone"); #endif if(IsClient()){ - ItemInst* transI = CastToClient()->GetInv().GetItem(MainCursor); - if(transI && transI->IsType(ItemClassCommon) && transI->IsStackable()){ + ItemInst* transI = CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotCursor); + if (transI && transI->IsClassCommon() && transI->IsStackable()){ uint32 fcharges = transI->GetCharges(); //Does it sound like meat... maybe should check if it looks like meat too... if(strstr(transI->GetItem()->Name, "meat") || @@ -618,7 +632,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) strstr(transI->GetItem()->Name, "Flesh") || strstr(transI->GetItem()->Name, "parts") || strstr(transI->GetItem()->Name, "Parts")){ - CastToClient()->DeleteItemInInventory(MainCursor, fcharges, true); + CastToClient()->DeleteItemInInventory(EQEmu::legacy::SlotCursor, fcharges, true); CastToClient()->SummonItem(13073, fcharges); } else{ @@ -637,41 +651,23 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) snprintf(effect_desc, _EDLEN, "Group Fear Immunity"); #endif //Added client messages to give some indication this effect is active. - uint32 group_id_caster = 0; - uint32 time = spell.base[i]*10; - if(caster->IsClient()) - { - if(caster->IsGrouped()) - { - group_id_caster = GetGroup()->GetID(); - } - else if(caster->IsRaidGrouped()) - { - group_id_caster = (GetRaid()->GetGroup(CastToClient()) == 0xFFFF) ? 0 : (GetRaid()->GetGroup(CastToClient()) + 1); + // Is there a message generated? Too disgusted by raids. + uint32 time = spell.base[i] * 10 * 1000; + if (caster && caster->IsClient()) { + if (caster->IsGrouped()) { + auto group = caster->GetGroup(); + for (int i = 0; i < 6; ++i) + if (group->members[i]) + group->members[i]->aa_timers[aaTimerWarcry].Start(time); + } else if (caster->IsRaidGrouped()) { + auto raid = caster->GetRaid(); + uint32 gid = raid->GetGroup(caster->CastToClient()); + if (gid < 12) + for (int i = 0; i < MAX_RAID_MEMBERS; ++i) + if (raid->members[i].member && raid->members[i].GroupNumber == gid) + raid->members[i].member->aa_timers[aaTimerWarcry].Start(time); } } - if(group_id_caster){ - Group *g = entity_list.GetGroupByID(group_id_caster); - uint32 time = spell.base[i]*10; - if(g){ - for(int gi=0; gi < 6; gi++){ - if(g->members[gi] && g->members[gi]->IsClient()) - { - g->members[gi]->CastToClient()->EnableAAEffect(aaEffectWarcry , time); - if (g->members[gi]->GetID() != caster->GetID()) - g->members[gi]->Message(13, "You hear the war cry."); - else - Message(13, "You let loose a fierce war cry."); - } - } - } - } - - else{ - CastToClient()->EnableAAEffect(aaEffectWarcry , time); - Message(13, "You let loose a fierce war cry."); - } - break; } @@ -704,7 +700,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) ((GetLevel() > max_level) && caster && (!caster->IsNPC() || (caster->IsNPC() && !RuleB(Spells, NPCIgnoreBaseImmunity)))))) { - caster->Message_StringID(MT_SpellFailure, IMMUNE_STUN); + if (caster) + caster->Message_StringID(MT_SpellFailure, IMMUNE_STUN); } else { int stun_resist = itembonuses.StunResist+spellbonuses.StunResist; if (IsClient()) @@ -713,7 +710,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (stun_resist <= 0 || zone->random.Int(0,99) >= stun_resist) { Log.Out(Logs::Detail, Logs::Combat, "Stunned. We had %d percent resist chance.", stun_resist); - if (caster->IsClient()) + if (caster && caster->IsClient()) effect_value += effect_value*caster->GetFocusEffect(focusFcStunTimeMod, spell_id)/100; Stun(effect_value); @@ -772,9 +769,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) caster->SetPet(this); SetOwnerID(caster->GetID()); SetPetOrder(SPO_Follow); + SetPetType(petCharmed); if(caster->IsClient()){ - EQApplicationPacket *app = new EQApplicationPacket(OP_Charm, sizeof(Charm_Struct)); + auto app = new EQApplicationPacket(OP_Charm, sizeof(Charm_Struct)); Charm_Struct *ps = (Charm_Struct*)app->pBuffer; ps->owner_id = caster->GetID(); ps->pet_id = this->GetID(); @@ -787,8 +785,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (IsClient()) { - AI_Start(); - SendAppearancePacket(14, 100, true, true); + CastToClient()->AI_Start(); } else if(IsNPC()) { CastToNPC()->SetPetSpellID(0); //not a pet spell. } @@ -797,7 +794,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) // define spells with fixed duration // charm spells with -1 in field 209 are all of fixed duration, so lets use that instead of spell_ids - if(spells[spell_id].powerful_flag == -1) + if(spells[spell_id].no_resist) bBreak = true; if (!bBreak) @@ -828,7 +825,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) { CastToClient()->SetSenseExemption(true); - if(CastToClient()->GetClientVersionBit() & BIT_SoDAndLater) + if (CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoDAndLater) { bodyType bt = BT_Undead; @@ -872,17 +869,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(buffs[buffslot].ticsremaining > RuleI(Character, MaxFearDurationForPlayerCharacter)) buffs[buffslot].ticsremaining = RuleI(Character, MaxFearDurationForPlayerCharacter); } - + if(RuleB(Combat, EnableFearPathing)){ if(IsClient()) { - AI_Start(); - animation = static_cast(GetRunspeed() * 21.0f); //set our animation to match our speed about + CastToClient()->AI_Start(); } CalculateNewFearpoint(); - if(curfp) + if(currently_fleeing) { break; } @@ -903,9 +899,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) { if(CastToClient()->GetGM() || RuleB(Character, BindAnywhere)) { - EQApplicationPacket *action_packet = new EQApplicationPacket(OP_Action, sizeof(Action_Struct)); + auto action_packet = + new EQApplicationPacket(OP_Action, sizeof(Action_Struct)); Action_Struct* action = (Action_Struct*) action_packet->pBuffer; - EQApplicationPacket *message_packet = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); + auto message_packet = + new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); CombatDamage_Struct *cd = (CombatDamage_Struct *)message_packet->pBuffer; action->target = GetID(); @@ -921,17 +919,17 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) cd->source = action->source; cd->type = action->type; cd->spellid = action->spell; - cd->sequence = action->sequence; + cd->meleepush_xy = action->sequence; CastToClient()->QueuePacket(action_packet); - if(caster->IsClient() && caster != this) + if(caster && caster->IsClient() && caster != this) caster->CastToClient()->QueuePacket(action_packet); CastToClient()->QueuePacket(message_packet); - if(caster->IsClient() && caster != this) + if(caster && caster->IsClient() && caster != this) caster->CastToClient()->QueuePacket(message_packet); - CastToClient()->SetBindPoint(); + CastToClient()->SetBindPoint(spells[spell_id].base[i] - 1); Save(); safe_delete(action_packet); safe_delete(message_packet); @@ -952,9 +950,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } else { - EQApplicationPacket *action_packet = new EQApplicationPacket(OP_Action, sizeof(Action_Struct)); + auto action_packet = new EQApplicationPacket( + OP_Action, sizeof(Action_Struct)); Action_Struct* action = (Action_Struct*) action_packet->pBuffer; - EQApplicationPacket *message_packet = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); + auto message_packet = new EQApplicationPacket( + OP_Damage, sizeof(CombatDamage_Struct)); CombatDamage_Struct *cd = (CombatDamage_Struct *)message_packet->pBuffer; action->target = GetID(); @@ -970,7 +970,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) cd->source = action->source; cd->type = action->type; cd->spellid = action->spell; - cd->sequence = action->sequence; + cd->meleepush_xy = action->sequence; CastToClient()->QueuePacket(action_packet); if(caster->IsClient() && caster != this) @@ -980,7 +980,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(caster->IsClient() && caster != this) caster->CastToClient()->QueuePacket(message_packet); - CastToClient()->SetBindPoint(); + CastToClient()->SetBindPoint(spells[spell_id].base[i] - 1); Save(); safe_delete(action_packet); safe_delete(message_packet); @@ -988,9 +988,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } else { - EQApplicationPacket *action_packet = new EQApplicationPacket(OP_Action, sizeof(Action_Struct)); + auto action_packet = + new EQApplicationPacket(OP_Action, sizeof(Action_Struct)); Action_Struct* action = (Action_Struct*) action_packet->pBuffer; - EQApplicationPacket *message_packet = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); + auto message_packet = new EQApplicationPacket( + OP_Damage, sizeof(CombatDamage_Struct)); CombatDamage_Struct *cd = (CombatDamage_Struct *)message_packet->pBuffer; action->target = GetID(); @@ -1006,7 +1008,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) cd->source = action->source; cd->type = action->type; cd->spellid = action->spell; - cd->sequence = action->sequence; + cd->meleepush_xy = action->sequence; CastToClient()->QueuePacket(action_packet); if(caster->IsClient() && caster != this) @@ -1016,7 +1018,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(caster->IsClient() && caster != this) caster->CastToClient()->QueuePacket(message_packet); - CastToClient()->SetBindPoint(); + CastToClient()->SetBindPoint(spells[spell_id].base[i] - 1); Save(); safe_delete(action_packet); safe_delete(message_packet); @@ -1026,7 +1028,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - case SE_Gate: //TO DO: Add support for secondary and tertiary gate abilities (base2) + case SE_Gate: { #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Gate"); @@ -1034,8 +1036,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(!spellbonuses.AntiGate){ if(zone->random.Roll(effect_value)) - Gate(); - else + Gate(spells[spell_id].base2[i] - 1); + else if (caster) caster->Message_StringID(MT_SpellFailure,GATE_FAIL); } break; @@ -1047,7 +1049,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) snprintf(effect_desc, _EDLEN, "Cancel Magic: %d", effect_value); #endif if(GetSpecialAbility(UNDISPELLABLE)){ - caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name); + if (caster) + caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name); break; } @@ -1057,7 +1060,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) spells[buffs[slot].spellid].dispel_flag == 0 && !IsDiscipline(buffs[slot].spellid)) { - if (TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){ + if (caster && TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){ BuffFadeBySlot(slot); slot = buff_count; } @@ -1072,7 +1075,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) snprintf(effect_desc, _EDLEN, "Dispel Detrimental: %d", effect_value); #endif if(GetSpecialAbility(UNDISPELLABLE)){ - caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name); + if (caster) + caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name); break; } @@ -1082,7 +1086,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) IsDetrimentalSpell(buffs[slot].spellid) && spells[buffs[slot].spellid].dispel_flag == 0) { - if (TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){ + if (caster && TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){ BuffFadeBySlot(slot); slot = buff_count; } @@ -1097,7 +1101,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) snprintf(effect_desc, _EDLEN, "Dispel Beneficial: %d", effect_value); #endif if(GetSpecialAbility(UNDISPELLABLE)){ - caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name); + if (caster) + caster->Message_StringID(MT_SpellFailure, SPELL_NO_EFFECT, spells[spell_id].name); break; } @@ -1107,7 +1112,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) IsBeneficialSpell(buffs[slot].spellid) && spells[buffs[slot].spellid].dispel_flag == 0) { - if (TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){ + if (caster && TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){ BuffFadeBySlot(slot); slot = buff_count; } @@ -1124,7 +1129,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (buffs[slot].spellid != SPELL_UNKNOWN && IsDetrimentalSpell(buffs[slot].spellid)) { - if (TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){ + if (caster && TryDispel(caster->GetLevel(),buffs[slot].casterlevel, effect_value)){ BuffFadeBySlot(slot); } } @@ -1143,7 +1148,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_SummonItem: { - const Item_Struct *item = database.GetItem(spell.base[i]); + const EQEmu::ItemBase *item = database.GetItem(spell.base[i]); #ifdef SPELL_EFFECT_SPAM const char *itemname = item ? item->Name : "*Unknown Item*"; snprintf(effect_desc, _EDLEN, "Summon Item: %s (id %d)", itemname, spell.base[i]); @@ -1168,7 +1173,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (SummonedItem) { c->PushItemOnCursor(*SummonedItem); - c->SendItemPacket(MainCursor, SummonedItem, ItemPacketSummonItem); + c->SendItemPacket(EQEmu::legacy::SlotCursor, SummonedItem, ItemPacketLimbo); safe_delete(SummonedItem); } SummonedItem = database.CreateItem(spell.base[i], charges); @@ -1179,14 +1184,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } case SE_SummonItemIntoBag: { - const Item_Struct *item = database.GetItem(spell.base[i]); + const EQEmu::ItemBase *item = database.GetItem(spell.base[i]); #ifdef SPELL_EFFECT_SPAM const char *itemname = item ? item->Name : "*Unknown Item*"; snprintf(effect_desc, _EDLEN, "Summon Item In Bag: %s (id %d)", itemname, spell.base[i]); #endif uint8 slot; - if (!SummonedItem || !SummonedItem->IsType(ItemClassContainer)) { + if (!SummonedItem || !SummonedItem->IsClassBag()) { if (caster) caster->Message(13, "SE_SummonItemIntoBag but no bag has been summoned!"); } else if ((slot = SummonedItem->FirstOpenSlot()) == 0xff) { @@ -1281,7 +1286,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Melee Absorb Rune: %+i", effect_value); #endif - effect_value = ApplySpellEffectiveness(caster, spell_id, effect_value); + if (caster) + effect_value = caster->ApplySpellEffectiveness(spell_id, effect_value); + buffs[buffslot].melee_rune = effect_value; break; } @@ -1291,7 +1298,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Spell Absorb Rune: %+i", effect_value); #endif - if(effect_value > 0) + if(effect_value > 0) buffs[buffslot].magic_rune = effect_value; break; @@ -1329,12 +1336,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_DistanceRemoval: { - buffs[buffslot].caston_x = int(GetX()); - buffs[buffslot].caston_y = int(GetY()); - buffs[buffslot].caston_z = int(GetZ()); + buffs[buffslot].caston_x = int(GetX()); + buffs[buffslot].caston_y = int(GetY()); + buffs[buffslot].caston_z = int(GetZ()); break; } - + case SE_Levitate: { #ifdef SPELL_EFFECT_SPAM @@ -1349,13 +1356,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_DeathSave: { int16 mod = 0; - + if(caster) { mod = caster->aabonuses.UnfailingDivinity + caster->itembonuses.UnfailingDivinity + caster->spellbonuses.UnfailingDivinity; } - + buffs[buffslot].ExtraDIChance = mod; break; } @@ -1438,11 +1445,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) } } - for(int x = EmuConstants::MATERIAL_BEGIN; x <= EmuConstants::MATERIAL_TINT_END; x++) + for (int x = EQEmu::textures::TextureBegin; x <= EQEmu::textures::LastTintableTexture; x++) SendWearChange(x); - - if(caster && (caster->spellbonuses.IllusionPersistence || caster->aabonuses.IllusionPersistence - || caster->itembonuses.IllusionPersistence)) + + if (caster == this && spell.id != 287 && spell.id != 601 && + (spellbonuses.IllusionPersistence || aabonuses.IllusionPersistence || + itembonuses.IllusionPersistence)) buffs[buffslot].persistant_buff = 1; else buffs[buffslot].persistant_buff = 0; @@ -1463,7 +1471,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) ); caster->SendAppearancePacket(AT_Size, static_cast(caster->GetTarget()->GetSize())); - for(int x = EmuConstants::MATERIAL_BEGIN; x <= EmuConstants::MATERIAL_TINT_END; x++) + for (int x = EQEmu::textures::TextureBegin; x <= EQEmu::textures::LastTintableTexture; x++) caster->SendWearChange(x); } } @@ -1510,7 +1518,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) ((GetLevel() > max_level) && caster && (!caster->IsNPC() || (caster->IsNPC() && !RuleB(Spells, NPCIgnoreBaseImmunity))))) { - caster->Message_StringID(MT_Shout, IMMUNE_STUN); + if (caster) + caster->Message_StringID(MT_Shout, IMMUNE_STUN); } else { @@ -1555,8 +1564,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) { uint16 pet_spellid = CastToNPC()->GetPetSpellID(); uint16 pet_ActSpellCost = caster->GetActSpellCost(pet_spellid, spells[pet_spellid].mana); - int16 ImprovedReclaimMod = caster->spellbonuses.ImprovedReclaimEnergy + - caster->itembonuses.ImprovedReclaimEnergy + + int16 ImprovedReclaimMod = caster->spellbonuses.ImprovedReclaimEnergy + + caster->itembonuses.ImprovedReclaimEnergy + caster->aabonuses.ImprovedReclaimEnergy; if (!ImprovedReclaimMod) @@ -1635,7 +1644,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #endif // This is handled by the client prior to SoD. // - if(IsClient() && (CastToClient()->GetClientVersionBit() & BIT_SoDAndLater)) + if (IsClient() && (CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoDAndLater)) CastToClient()->LocateCorpse(); break; @@ -1666,9 +1675,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) // Only allow 2 size changes from Base Size float modifyAmount = (static_cast(effect_value) / 100.0f); float maxModAmount = GetBaseSize() * modifyAmount * modifyAmount; - if ((GetSize() <= GetBaseSize() && GetSize() > maxModAmount) || + if ((GetSize() <= GetBaseSize() && GetSize() > maxModAmount) || (GetSize() >= GetBaseSize() && GetSize() < maxModAmount) || - (GetSize() <= GetBaseSize() && maxModAmount > 1.0f) || + (GetSize() <= GetBaseSize() && maxModAmount > 1.0f) || (GetSize() >= GetBaseSize() && maxModAmount < 1.0f)) { ChangeSize(GetSize() * modifyAmount); @@ -1684,7 +1693,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) rooted = true; if (caster){ - buffs[buffslot].RootBreakChance = caster->aabonuses.RootBreakChance + + buffs[buffslot].RootBreakChance = caster->aabonuses.RootBreakChance + caster->itembonuses.RootBreakChance + caster->spellbonuses.RootBreakChance; } @@ -1727,7 +1736,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } } - else { + else if (caster) { Raid *r = entity_list.GetRaidByClient(caster->CastToClient()); if(r) { @@ -1767,7 +1776,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) Message_StringID(4, CORPSE_CANT_SENSE); } } - else + else if (caster) caster->Message_StringID(MT_SpellFailure, SPELL_LEVEL_REQ); } else { @@ -1787,9 +1796,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #endif if(spells[spell_id].base2[i] == 0) - AddProcToWeapon(procid, false, 100, spell_id); + AddProcToWeapon(procid, false, 100, spell_id, caster_level); else - AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100, spell_id); + AddProcToWeapon(procid, false, spells[spell_id].base2[i]+100, spell_id, caster_level); break; } @@ -2072,7 +2081,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) 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)); - EQApplicationPacket* outapp_push = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + auto outapp_push = + new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); PlayerPositionUpdateServer_Struct* spu = (PlayerPositionUpdateServer_Struct*)outapp_push->pBuffer; spu->spawn_id = GetID(); @@ -2113,7 +2123,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Sacrifice"); #endif - if(!IsClient() || !caster->IsClient()){ + if(!caster || !IsClient() || !caster->IsClient()){ break; } CastToClient()->SacrificeConfirm(caster->CastToClient()); @@ -2122,12 +2132,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_SummonPC: { - if(IsClient()){ - CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), caster->GetX(), caster->GetY(), caster->GetZ(), caster->GetHeading(), 2, SummonPC); + if (!caster) + break; + if (IsClient()) { + CastToClient()->MovePC(zone->GetZoneID(), zone->GetInstanceID(), caster->GetX(), + caster->GetY(), caster->GetZ(), caster->GetHeading(), 2, + SummonPC); Message(15, "You have been summoned!"); entity_list.ClearAggro(this); - } - else + } else caster->Message(13, "This spell can only be cast on players."); break; @@ -2174,6 +2187,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_TemporaryPets: //Dook- swarms and wards: { + if (!caster) + break; // this makes necro epic 1.5/2.0 proc work properly if((spell_id != 6882) && (spell_id != 6884)) // Chaotic Jester/Steadfast Servant { @@ -2224,33 +2239,34 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) snprintf(effect_desc, _EDLEN, "Rampage"); #endif if(caster) - entity_list.AEAttack(caster, 30, MainPrimary, 0, true); // on live wars dont get a duration ramp, its a one shot deal + entity_list.AEAttack(caster, 30, EQEmu::legacy::SlotPrimary, 0, true); // on live wars dont get a duration ramp, its a one shot deal break; } case SE_AEMelee: { + //old aa + #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Duration Rampage"); #endif - if (caster && caster->IsClient()) { // will tidy this up later so that NPCs can duration ramp from spells too - CastToClient()->DurationRampage(effect_value*12); - } + aa_timers[aaTimerRampage].Start(effect_value * 10 * 1000); // Live bug, was suppose to be 1 second per value break; } - case SE_AETaunt://Dook- slapped it in the spell effect so client does the animations - { // and incase there are similar spells we havent found yet + case SE_AETaunt: + { #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "AE Taunt"); #endif if(caster && caster->IsClient()){ - float range = 0.0f; - if (spells[spell_id].base2[i]) - range = (float)spells[spell_id].base[i]; - - entity_list.AETaunt(caster->CastToClient(), range); + //Live AE Taunt range is hardcoded at 40 (Spells for AE taunt all use zero range) Target type should be self only. + float range = 40; + if (spells[spell_id].max[i])//custom support if you want to alter range of AE Taunt. + range = spells[spell_id].max[i]; + + entity_list.AETaunt(caster->CastToClient(), range, spells[spell_id].base[i]); } break; } @@ -2268,21 +2284,20 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) */ int16 focus = 0; int ReuseTime = spells[spell_id].recast_time + spells[spell_id].recovery_time; + if (!caster) + break; focus = caster->GetFocusEffect(focusFcBaseEffects, spell_id); - switch(spells[spell_id].skill) - { - case SkillThrowing: - caster->DoThrowingAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i], focus, ReuseTime); + switch(spells[spell_id].skill) { + case EQEmu::skills::SkillThrowing: + caster->DoThrowingAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i], focus, ReuseTime); break; - - case SkillArchery: - caster->DoArcheryAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i],focus, ReuseTime); + case EQEmu::skills::SkillArchery: + caster->DoArcheryAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i],focus, ReuseTime); break; - - default: - caster->DoMeleeSkillAttackDmg(this, spells[spell_id].base[i], spells[spell_id].skill, spells[spell_id].base2[i], focus, false, ReuseTime); + default: + caster->DoMeleeSkillAttackDmg(this, spells[spell_id].base[i], spells[spell_id].skill, spells[spell_id].base2[i], focus, false, ReuseTime); break; } break; @@ -2294,7 +2309,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) snprintf(effect_desc, _EDLEN, "Wake The Dead"); #endif //meh dupe issue with npc casting this - if(caster->IsClient()){ + if(caster && caster->IsClient()){ int dur = spells[spell_id].max[i]; if (!dur) dur = 60; @@ -2540,7 +2555,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) int mana_damage = 0; int32 mana_to_use = GetMana() - spell.base[i]; if(mana_to_use > -1) { - SetMana(GetMana() - spell.base[i]); + SetMana(GetMana() - spell.base[i]); TryTriggerOnValueAmount(false, true); // we take full dmg(-10 to make the damage the right sign) mana_damage = spell.base[i] / -10 * spell.base2[i]; @@ -2659,11 +2674,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_Taunt: { - if (IsNPC()){ - caster->Taunt(this->CastToNPC(), false, static_cast(spell.base[i])); - - if (spell.base2[i] > 0) - CastToNPC()->SetHateAmountOnEnt(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i])); + if (caster && IsNPC()){ + caster->Taunt(this->CastToNPC(), false, static_cast(spell.base[i]), true, spell.base2[i]); } break; } @@ -2750,7 +2762,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (caster && IsValidSpell(spells[spell_id].base2[i])){ if(zone->random.Roll(spells[spell_id].base[i])) - caster->SpellFinished(spells[spell_id].base2[i], this, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff); + caster->SpellFinished(spells[spell_id].base2[i], this, EQEmu::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff); } break; } @@ -2849,6 +2861,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_Accuracy: case SE_Flurry: case SE_ImprovedDamage: + case SE_ImprovedDamage2: case SE_ImprovedHeal: case SE_IncreaseSpellHaste: case SE_IncreaseSpellDuration: @@ -2882,6 +2895,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_MaxHPChange: case SE_SympatheticProc: case SE_FcDamageAmt: + case SE_FcDamageAmt2: case SE_CriticalSpellChance: case SE_SpellCritChance: case SE_SpellCritDmgIncrease: @@ -2965,14 +2979,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_FcIncreaseNumHits: case SE_CastonFocusEffect: case SE_FcHealAmtIncoming: - case SE_MeleeVulnerability: + case SE_LimitManaMax: case SE_DoubleRangedAttack: case SE_ShieldEquipHateMod: case SE_ShieldEquipDmgMod: case SE_TriggerOnReqTarget: case SE_LimitRace: case SE_FcLimitUse: - case SE_FcMute: + case SE_FcMute: case SE_LimitUseType: case SE_FcStunTimeMod: case SE_StunBashChance: @@ -2981,9 +2995,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_LimitCastTimeMax: case SE_TriggerOnReqCaster: case SE_FrenziedDevastation: - case SE_AStacker: - case SE_BStacker: - case SE_CStacker: + case SE_AStacker: + case SE_BStacker: + case SE_CStacker: case SE_DStacker: case SE_DoubleRiposte: case SE_Berserk: @@ -2999,6 +3013,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_PetMeleeMitigation: case SE_SkillProc: case SE_SkillProcSuccess: + case SE_SpellResistReduction: { break; } @@ -3022,55 +3037,51 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (SummonedItem) { Client *c=CastToClient(); c->PushItemOnCursor(*SummonedItem); - c->SendItemPacket(MainCursor, SummonedItem, ItemPacketSummonItem); + c->SendItemPacket(EQEmu::legacy::SlotCursor, SummonedItem, ItemPacketLimbo); safe_delete(SummonedItem); } return true; } -int Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level, Mob *caster, int ticsremaining) +int Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level, uint32 instrument_mod, Mob *caster, + int ticsremaining, uint16 caster_id) { int formula, base, max, effect_value; - if - ( - !IsValidSpell(spell_id) || - effect_id < 0 || - effect_id >= EFFECT_COUNT - ) + if (!IsValidSpell(spell_id) || effect_id < 0 || effect_id >= EFFECT_COUNT) return 0; formula = spells[spell_id].formula[effect_id]; base = spells[spell_id].base[effect_id]; max = spells[spell_id].max[effect_id]; - if(IsBlankSpellEffect(spell_id, effect_id)) + if (IsBlankSpellEffect(spell_id, effect_id)) return 0; effect_value = CalcSpellEffectValue_formula(formula, base, max, caster_level, spell_id, ticsremaining); - if(caster && IsBardSong(spell_id) && - (spells[spell_id].effectid[effect_id] != SE_AttackSpeed) && - (spells[spell_id].effectid[effect_id] != SE_AttackSpeed2) && - (spells[spell_id].effectid[effect_id] != SE_AttackSpeed3) && - (spells[spell_id].effectid[effect_id] != SE_Lull) && - (spells[spell_id].effectid[effect_id] != SE_ChangeFrenzyRad) && - (spells[spell_id].effectid[effect_id] != SE_Harmony) && - (spells[spell_id].effectid[effect_id] != SE_CurrentMana)&& - (spells[spell_id].effectid[effect_id] != SE_ManaRegen_v2)) - { + // this doesn't actually need to be a song to get mods, just the right skill + if (EQEmu::skills::IsBardInstrumentSkill(spells[spell_id].skill) && + spells[spell_id].effectid[effect_id] != SE_AttackSpeed && + spells[spell_id].effectid[effect_id] != SE_AttackSpeed2 && + spells[spell_id].effectid[effect_id] != SE_AttackSpeed3 && + spells[spell_id].effectid[effect_id] != SE_Lull && + spells[spell_id].effectid[effect_id] != SE_ChangeFrenzyRad && + spells[spell_id].effectid[effect_id] != SE_Harmony && + spells[spell_id].effectid[effect_id] != SE_CurrentMana && + spells[spell_id].effectid[effect_id] != SE_ManaRegen_v2) { int oval = effect_value; - int mod = caster->GetInstrumentMod(spell_id); - mod = ApplySpellEffectiveness(caster, spell_id, mod, true); + int mod = ApplySpellEffectiveness(spell_id, instrument_mod, true, caster_id); effect_value = effect_value * mod / 10; - Log.Out(Logs::Detail, Logs::Spells, "Effect value %d altered with bard modifier of %d to yeild %d", oval, mod, effect_value); + Log.Out(Logs::Detail, Logs::Spells, "Effect value %d altered with bard modifier of %d to yeild %d", + oval, mod, effect_value); } - effect_value = mod_effect_value(effect_value, spell_id, spells[spell_id].effectid[effect_id], caster); + effect_value = mod_effect_value(effect_value, spell_id, spells[spell_id].effectid[effect_id], caster, caster_id); - return(effect_value); + return effect_value; } // generic formula calculations @@ -3150,10 +3161,23 @@ snare has both of them negative, yet their range should work the same: result = updownsign * (ubase + (caster_level * 4)); break; case 107: - //Used on Reckless Strength, I think it should decay over time - result = updownsign * (ubase + (caster_level / 2)); break; + { + int ticdif = CalcBuffDuration_formula(caster_level, spells[spell_id].buffdurationformula, spells[spell_id].buffduration) - std::max((ticsremaining - 1), 0); + if (ticdif < 0) + ticdif = 0; + result = updownsign * (ubase - ticdif); + degenerating_effects = true; + break; + } case 108: - result = updownsign * (ubase + (caster_level / 3)); break; + { + int ticdif = CalcBuffDuration_formula(caster_level, spells[spell_id].buffdurationformula, spells[spell_id].buffduration) - std::max((ticsremaining - 1), 0); + if (ticdif < 0) + ticdif = 0; + result = updownsign * (ubase - (2 * ticdif)); + degenerating_effects = true; + break; + } case 109: // confirmed 2/6/04 result = updownsign * (ubase + (caster_level / 4)); break; @@ -3198,16 +3222,25 @@ snare has both of them negative, yet their range should work the same: case 119: // confirmed 2/6/04 result = ubase + (caster_level / 8); break; + case 120: + { + int ticdif = CalcBuffDuration_formula(caster_level, spells[spell_id].buffdurationformula, spells[spell_id].buffduration) - std::max((ticsremaining - 1), 0); + if (ticdif < 0) + ticdif = 0; + result = updownsign * (ubase - (5 * ticdif)); + degenerating_effects = true; + break; + } case 121: // corrected 2/6/04 result = ubase + (caster_level / 3); break; case 122: { - // May need to account for duration focus effects - int ticdif = spells[spell_id].buffduration - (ticsremaining - 1); + int ticdif = CalcBuffDuration_formula(caster_level, spells[spell_id].buffdurationformula, spells[spell_id].buffduration) - std::max((ticsremaining - 1), 0); if(ticdif < 0) ticdif = 0; result = updownsign * (ubase - (12 * ticdif)); + degenerating_effects = true; break; } case 123: // added 2/6/04 @@ -3314,11 +3347,12 @@ snare has both of them negative, yet their range should work the same: { // These work like splurt, accept instead of being hard coded to 12, it is formula - 1000. // Formula 1999 seems to have a slightly different effect, so is not included here - int ticdif = spells[spell_id].buffduration - (ticsremaining - 1); + int ticdif = CalcBuffDuration_formula(caster_level, spells[spell_id].buffdurationformula, spells[spell_id].buffduration) - std::max((ticsremaining - 1), 0); if(ticdif < 0) ticdif = 0; result = updownsign * (ubase - ((formula - 1000) * ticdif)); + degenerating_effects = true; } else if((formula >= 2000) && (formula <= 2650)) { @@ -3365,30 +3399,19 @@ void Mob::BuffProcess() { if (buffs[buffs_i].spellid != SPELL_UNKNOWN) { - DoBuffTic(buffs[buffs_i].spellid, buffs_i, buffs[buffs_i].ticsremaining, buffs[buffs_i].casterlevel, entity_list.GetMob(buffs[buffs_i].casterid)); + DoBuffTic(buffs[buffs_i], buffs_i, entity_list.GetMob(buffs[buffs_i].casterid)); // If the Mob died during DoBuffTic, then the buff we are currently processing will have been removed if(buffs[buffs_i].spellid == SPELL_UNKNOWN) continue; - if(spells[buffs[buffs_i].spellid].buffdurationformula != DF_Permanent) - { + // DF_Permanent uses -1 DF_Aura uses -4 but we need to check negatives for some spells for some reason? + if (spells[buffs[buffs_i].spellid].buffdurationformula != DF_Permanent && + spells[buffs[buffs_i].spellid].buffdurationformula != DF_Aura) { if(!zone->BuffTimersSuspended() || !IsSuspendableSpell(buffs[buffs_i].spellid)) { --buffs[buffs_i].ticsremaining; - if (buffs[buffs_i].ticsremaining == 0) { - if (!IsShortDurationBuff(buffs[buffs_i].spellid) || - IsFearSpell(buffs[buffs_i].spellid) || - IsCharmSpell(buffs[buffs_i].spellid) || - IsMezSpell(buffs[buffs_i].spellid) || - IsBlindSpell(buffs[buffs_i].spellid)) - { - Log.Out(Logs::Detail, Logs::Spells, "Buff %d in slot %d has expired. Fading.", buffs[buffs_i].spellid, buffs_i); - BuffFadeBySlot(buffs_i); - } - } - else if (buffs[buffs_i].ticsremaining < 0) - { + if (buffs[buffs_i].ticsremaining < 0) { Log.Out(Logs::Detail, Logs::Spells, "Buff %d in slot %d has expired. Fading.", buffs[buffs_i].spellid, buffs_i); BuffFadeBySlot(buffs_i); } @@ -3397,7 +3420,7 @@ void Mob::BuffProcess() Log.Out(Logs::Detail, Logs::Spells, "Buff %d in slot %d has %d tics remaining.", buffs[buffs_i].spellid, buffs_i, buffs[buffs_i].ticsremaining); } } - else if(IsClient() && !(CastToClient()->GetClientVersionBit() & BIT_SoFAndLater)) + else if (IsClient() && !(CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoFAndLater)) { buffs[buffs_i].UpdateClient = true; } @@ -3407,9 +3430,9 @@ void Mob::BuffProcess() { if(buffs[buffs_i].UpdateClient == true) { - CastToClient()->SendBuffDurationPacket(buffs[buffs_i]); + CastToClient()->SendBuffDurationPacket(buffs[buffs_i], buffs_i); // Hack to get UF to play nicer, RoF seems fine without it - if (CastToClient()->GetClientVersion() == ClientVersion::UF && buffs[buffs_i].numhits > 0) + if (CastToClient()->ClientVersion() == EQEmu::versions::ClientVersion::UF && buffs[buffs_i].numhits > 0) CastToClient()->SendBuffNumHitPacket(buffs[buffs_i], buffs_i); buffs[buffs_i].UpdateClient = false; } @@ -3418,335 +3441,309 @@ void Mob::BuffProcess() } } -void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster) { +void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster) +{ int effect, effect_value; - if(!IsValidSpell(spell_id)) + if (!IsValidSpell(buff.spellid)) return; - const SPDat_Spell_Struct &spell = spells[spell_id]; + const SPDat_Spell_Struct &spell = spells[buff.spellid]; - if (spell_id == SPELL_UNKNOWN) - return; - - if(IsNPC()) - { + if (IsNPC()) { std::vector args; - args.push_back(&ticsremaining); - args.push_back(&caster_level); + args.push_back(&buff.ticsremaining); + args.push_back(&buff.casterlevel); args.push_back(&slot); - int i = parse->EventSpell(EVENT_SPELL_BUFF_TIC_NPC, CastToNPC(), nullptr, spell_id, caster ? caster->GetID() : 0, &args); - if(i != 0) { + int i = parse->EventSpell(EVENT_SPELL_BUFF_TIC_NPC, CastToNPC(), nullptr, buff.spellid, + caster ? caster->GetID() : 0, &args); + if (i != 0) { return; } - } - else - { + } else { std::vector args; - args.push_back(&ticsremaining); - args.push_back(&caster_level); + args.push_back(&buff.ticsremaining); + args.push_back(&buff.casterlevel); args.push_back(&slot); - int i = parse->EventSpell(EVENT_SPELL_BUFF_TIC_CLIENT, nullptr, CastToClient(), spell_id, caster ? caster->GetID() : 0, &args); - if(i != 0) { + int i = parse->EventSpell(EVENT_SPELL_BUFF_TIC_CLIENT, nullptr, CastToClient(), buff.spellid, + caster ? caster->GetID() : 0, &args); + if (i != 0) { return; } } - // Check for non buff spell effects to fade - // AE melee effects - if(IsClient()) - CastToClient()->CheckAAEffect(aaEffectRampage); - - for (int i = 0; i < EFFECT_COUNT; i++) - { - if(IsBlankSpellEffect(spell_id, i)) + for (int i = 0; i < EFFECT_COUNT; i++) { + if (IsBlankSpellEffect(buff.spellid, i)) continue; effect = spell.effectid[i]; - //I copied the calculation into each case which needed it instead of - //doing it every time up here, since most buff effects dont need it + // I copied the calculation into each case which needed it instead of + // doing it every time up here, since most buff effects dont need it - switch(effect) - { - case SE_CurrentHP: - { - effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster, ticsremaining); - //Handle client cast DOTs here. - if (caster && effect_value < 0){ - - if (IsDetrimentalSpell(spell_id)){ - if (caster->IsClient()){ - if (!caster->CastToClient()->GetFeigned()) - AddToHateList(caster, -effect_value); - } - else if (!IsClient()) //Allow NPC's to generate hate if casted on other NPC's. + switch (effect) { + case SE_CurrentHP: { + if (!PassCastRestriction(false, spells[buff.spellid].base2[i], true)) + break; + effect_value = CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod, + caster, buff.ticsremaining); + // Handle client cast DOTs here. + if (caster && effect_value < 0) { + + if (IsDetrimentalSpell(buff.spellid)) { + if (caster->IsClient()) { + if (!caster->CastToClient()->GetFeigned()) AddToHateList(caster, -effect_value); - } - - effect_value = caster->GetActDoTDamage(spell_id, effect_value, this); - - caster->ResourceTap(-effect_value, spell_id); - effect_value = -effect_value; - Damage(caster, effect_value, spell_id, spell.skill, false, i, true); - } else if(effect_value > 0) { - // Regen spell... - // handled with bonuses + } else if (!IsClient()) // Allow NPC's to generate hate if casted on other + // NPC's. + AddToHateList(caster, -effect_value); } - break; + + effect_value = caster->GetActDoTDamage(buff.spellid, effect_value, this); + + caster->ResourceTap(-effect_value, buff.spellid); + effect_value = -effect_value; + Damage(caster, effect_value, buff.spellid, spell.skill, false, i, true); + } else if (effect_value > 0) { + // Regen spell... + // handled with bonuses } - case SE_HealOverTime: - { - effect_value = CalcSpellEffectValue(spell_id, i, caster_level); - if(caster) - effect_value = caster->GetActSpellHealing(spell_id, effect_value); + break; + } + case SE_HealOverTime: { + effect_value = CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod); + if (caster) + effect_value = caster->GetActSpellHealing(buff.spellid, effect_value); - HealDamage(effect_value, caster, spell_id); - //healing aggro would go here; removed for now + HealDamage(effect_value, caster, buff.spellid); + // healing aggro would go here; removed for now + break; + } + + case SE_CurrentEndurance: { + // Handled with bonuses + break; + } + + case SE_BardAEDot: { + effect_value = + CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod, caster); + + if ((!RuleB(Spells, PreNerfBardAEDoT) && IsMoving()) || invulnerable || + /*effect_value > 0 ||*/ DivineAura()) break; + + if (effect_value < 0) { + effect_value = -effect_value; + if (caster) { + if (caster->IsClient() && !caster->CastToClient()->GetFeigned()) { + AddToHateList(caster, effect_value); + } else if (!caster->IsClient()) + AddToHateList(caster, effect_value); + } + Damage(caster, effect_value, buff.spellid, spell.skill, false, i, true); + } else if (effect_value > 0) { + // healing spell... + HealDamage(effect_value, caster); + // healing aggro would go here; removed for now } + break; + } - case SE_CurrentEndurance: { - // Handled with bonuses - break; - } - - case SE_BardAEDot: - { - effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster); - - if ((!RuleB(Spells, PreNerfBardAEDoT) && IsMoving()) || invulnerable || /*effect_value > 0 ||*/ DivineAura()) - break; - - if(effect_value < 0) { - effect_value = -effect_value; - if(caster){ - if(caster->IsClient() && !caster->CastToClient()->GetFeigned()){ + case SE_Hate: { + effect_value = CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod); + if (caster) { + if (effect_value > 0) { + if (caster) { + if (caster->IsClient() && !caster->CastToClient()->GetFeigned()) { AddToHateList(caster, effect_value); - } - else if(!caster->IsClient()) + } else if (!caster->IsClient()) AddToHateList(caster, effect_value); } - Damage(caster, effect_value, spell_id, spell.skill, false, i, true); - } else if(effect_value > 0) { - //healing spell... - HealDamage(effect_value, caster); - //healing aggro would go here; removed for now - } - break; - } - - case SE_Hate:{ - effect_value = CalcSpellEffectValue(spell_id, i, caster_level); - if(caster){ - if(effect_value > 0){ - if(caster){ - if(caster->IsClient() && !caster->CastToClient()->GetFeigned()){ - AddToHateList(caster, effect_value); - } - else if(!caster->IsClient()) - AddToHateList(caster, effect_value); - } - }else{ - int32 newhate = GetHateAmount(caster) + effect_value; - if (newhate < 1) { - SetHateAmountOnEnt(caster,1); - } else { - SetHateAmountOnEnt(caster,newhate); - } + } else { + int32 newhate = GetHateAmount(caster) + effect_value; + if (newhate < 1) { + SetHateAmountOnEnt(caster, 1); + } else { + SetHateAmountOnEnt(caster, newhate); } } + } + break; + } + + case SE_WipeHateList: { + if (IsMezSpell(buff.spellid)) break; + + int wipechance = spells[buff.spellid].base[i]; + int bonus = 0; + + if (caster) { + bonus = caster->spellbonuses.IncreaseChanceMemwipe + + caster->itembonuses.IncreaseChanceMemwipe + + caster->aabonuses.IncreaseChanceMemwipe; } - case SE_WipeHateList: - { - if (IsMezSpell(spell_id)) + wipechance += wipechance * bonus / 100; + + if (zone->random.Roll(wipechance)) { + if (IsAIControlled()) { + WipeHateList(); + } + Message(13, "Your mind fogs. Who are my friends? Who are my enemies?... it was all so " + "clear a moment ago..."); + } + break; + } + + case SE_Charm: { + if (!caster || !PassCharismaCheck(caster, buff.spellid)) { + BuffFadeByEffect(SE_Charm); + } + + break; + } + + case SE_Root: { + /* Root formula derived from extensive personal live parses - Kayen + ROOT has a 70% chance to do a resist check to break. + */ + + if (zone->random.Roll(RuleI(Spells, RootBreakCheckChance))) { + float resist_check = + ResistSpell(spells[buff.spellid].resisttype, buff.spellid, caster, 0, 0, 0, 0, true); + + if (resist_check == 100) break; - - int wipechance = spells[spell_id].base[i]; - int bonus = 0; - - if (caster){ - bonus = caster->spellbonuses.IncreaseChanceMemwipe + - caster->itembonuses.IncreaseChanceMemwipe + - caster->aabonuses.IncreaseChanceMemwipe; - } - - wipechance += wipechance*bonus/100; - - if(zone->random.Roll(wipechance)) - { - if(IsAIControlled()) - { - WipeHateList(); - } - Message(13, "Your mind fogs. Who are my friends? Who are my enemies?... it was all so clear a moment ago..."); - } - break; + else if (!TryFadeEffect(slot)) + BuffFadeBySlot(slot); } - case SE_Charm: { - if (!caster || !PassCharismaCheck(caster, spell_id)) { - BuffFadeByEffect(SE_Charm); - } + break; + } - break; - } + case SE_Fear: { + if (zone->random.Roll(RuleI(Spells, FearBreakCheckChance))) { + float resist_check = ResistSpell(spells[buff.spellid].resisttype, buff.spellid, caster); - case SE_Root: { - /* Root formula derived from extensive personal live parses - Kayen - ROOT has a 70% chance to do a resist check to break. - */ - - if (zone->random.Roll(RuleI(Spells, RootBreakCheckChance))) { - float resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, 0,0,0,0,true); - - if(resist_check == 100) - break; - else - if(!TryFadeEffect(slot)) - BuffFadeBySlot(slot); - } - - break; - } - - case SE_Fear: - { - if (zone->random.Roll(RuleI(Spells, FearBreakCheckChance))) { - float resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster); - - if(resist_check == 100) - break; - else - if(!TryFadeEffect(slot)) - BuffFadeBySlot(slot); - } - - break; - } - - case SE_Hunger: { - // this procedure gets called 7 times for every once that the stamina update occurs so we add 1/7 of the subtraction. - // It's far from perfect, but works without any unnecessary buff checks to bog down the server. - if(IsClient()) { - CastToClient()->m_pp.hunger_level += 5; - CastToClient()->m_pp.thirst_level += 5; - } - break; - } - case SE_Invisibility: - case SE_InvisVsAnimals: - case SE_InvisVsUndead: - { - if(ticsremaining > 3) - { - if(!IsBardSong(spell_id)) - { - double break_chance = 2.0; - if(caster) - { - break_chance -= (2 * (((double)caster->GetSkill(SkillDivination) + ((double)caster->GetLevel() * 3.0)) / 650.0)); - } - else - { - break_chance -= (2 * (((double)GetSkill(SkillDivination) + ((double)GetLevel() * 3.0)) / 650.0)); - } - - if(zone->random.Real(0.0, 100.0) < break_chance) - { - BuffModifyDurationBySpellID(spell_id, 3); - } - } - } - } - case SE_Invisibility2: - case SE_InvisVsUndead2: - { - if(ticsremaining <= 3 && ticsremaining > 1) - { - Message_StringID(MT_Spells, INVIS_BEGIN_BREAK); - } - break; - } - case SE_InterruptCasting: - { - if(IsCasting()) - { - if(zone->random.Roll(spells[spell_id].base[i])) - { - InterruptSpell(); - } - } - break; - } - // These effects always trigger when they fade. - case SE_CastOnFadeEffect: - case SE_CastOnFadeEffectNPC: - case SE_CastOnFadeEffectAlways: - { - if (ticsremaining == 1) - { - SpellOnTarget(spells[spell_id].base[i], this); - } - break; - } - case SE_LocateCorpse: - { - // This is handled by the client prior to SoD. - - if(IsClient() && (CastToClient()->GetClientVersionBit() & BIT_SoDAndLater)) - CastToClient()->LocateCorpse(); - } - case SE_TotalHP: - { - if (spell.formula[i] > 1000 && spell.formula[i] < 1999) - { - // These formulas can affect Max HP each tick - // Maybe there is a more efficient way to recalculate this for just Max HP each tic... - //CalcBonuses(); - CalcSpellBonuses(&spellbonuses); - CalcMaxHP(); - } - break; - } - - case SE_DistanceRemoval: - { - if (spellbonuses.DistanceRemoval){ - - int distance = ((int(GetX()) - buffs[slot].caston_x) * (int(GetX()) - buffs[slot].caston_x)) + - ((int(GetY()) - buffs[slot].caston_y) * (int(GetY()) - buffs[slot].caston_y)) + - ((int(GetZ()) - buffs[slot].caston_z) * (int(GetZ()) - buffs[slot].caston_z)); - - if (distance > (spells[spell_id].base[i] * spells[spell_id].base[i])){ - - if(!TryFadeEffect(slot)) - BuffFadeBySlot(slot , true); - } + if (resist_check == 100) break; - } + else if (!TryFadeEffect(slot)) + BuffFadeBySlot(slot); } - case SE_AddHateOverTimePct: - { - if (IsNPC()){ - uint32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100; - if (new_hate <= 0) - new_hate = 1; - - CastToNPC()->SetHateAmountOnEnt(caster, new_hate); - } - break; + break; + } + + case SE_Hunger: { + // this procedure gets called 7 times for every once that the stamina update occurs so we add + // 1/7 of the subtraction. + // It's far from perfect, but works without any unnecessary buff checks to bog down the server. + if (IsClient()) { + CastToClient()->m_pp.hunger_level += 5; + CastToClient()->m_pp.thirst_level += 5; } + break; + } + case SE_Invisibility: + case SE_InvisVsAnimals: + case SE_InvisVsUndead: { + if (buff.ticsremaining > 3) { + if (!IsBardSong(buff.spellid)) { + double break_chance = 2.0; + if (caster) { + break_chance -= (2 * (((double)caster->GetSkill(EQEmu::skills::SkillDivination) + + ((double)caster->GetLevel() * 3.0)) / + 650.0)); + } else { + break_chance -= + (2 * + (((double)GetSkill(EQEmu::skills::SkillDivination) + ((double)GetLevel() * 3.0)) / + 650.0)); + } - - default: - { - // do we need to do anyting here? + if (zone->random.Real(0.0, 100.0) < break_chance) { + BuffModifyDurationBySpellID(buff.spellid, 3); + } + } } } + case SE_Invisibility2: + case SE_InvisVsUndead2: { + if (buff.ticsremaining <= 3 && buff.ticsremaining > 1) { + Message_StringID(MT_Spells, INVIS_BEGIN_BREAK); + } + break; + } + case SE_InterruptCasting: { + if (IsCasting()) { + const auto &spell = spells[casting_spell_id]; + if (!spell.cast_not_standing && zone->random.Roll(spells[buff.spellid].base[i])) { + InterruptSpell(); + } + } + break; + } + // These effects always trigger when they fade. + // Should we have this triggered from else where? + case SE_CastOnFadeEffect: + case SE_CastOnFadeEffectNPC: + case SE_CastOnFadeEffectAlways: { + if (buff.ticsremaining == 0) { + SpellOnTarget(spells[buff.spellid].base[i], this); + } + break; + } + case SE_LocateCorpse: { + // This is handled by the client prior to SoD. + + if (IsClient() && (CastToClient()->ClientVersionBit() & EQEmu::versions::bit_SoDAndLater)) + CastToClient()->LocateCorpse(); + } + + case SE_DistanceRemoval: { + if (spellbonuses.DistanceRemoval) { + + int distance = + ((int(GetX()) - buff.caston_x) * (int(GetX()) - buff.caston_x)) + + ((int(GetY()) - buff.caston_y) * (int(GetY()) - buff.caston_y)) + + ((int(GetZ()) - buff.caston_z) * (int(GetZ()) - buff.caston_z)); + + if (distance > (spells[buff.spellid].base[i] * spells[buff.spellid].base[i])) { + + if (!TryFadeEffect(slot)) + BuffFadeBySlot(slot, true); + } + break; + } + } + + case SE_AddHateOverTimePct: { + if (IsNPC()) { + uint32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100; + if (new_hate <= 0) + new_hate = 1; + + CastToNPC()->SetHateAmountOnEnt(caster, new_hate); + } + break; + } + + default: { + // do we need to do anyting here? + } + } + if (!IsValidSpell(buff.spellid)) // if we faded we're no longer valid! + break; } + + /* Is this the best place for this? + * Ideally we would only recalc spell bonuses + * but we would also have to call all the Calc functions like Max HP + * so lets just call the main CalcBonuses + */ + if (degenerating_effects) + CalcBonuses(); } // removes the buff in the buff slot 'slot' @@ -3858,7 +3855,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) else{ SendAppearancePacket(AT_Size, 6); } - for(int x = EmuConstants::MATERIAL_BEGIN; x <= EmuConstants::MATERIAL_TINT_END; x++){ + for (int x = EQEmu::textures::TextureBegin; x <= EQEmu::textures::LastTintableTexture; x++){ SendWearChange(x); } break; @@ -3950,11 +3947,12 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) if(IsNPC()) { CastToNPC()->RestoreGuardSpotCharm(); - SendAppearancePacket(AT_Pet, 0, true, true); } + SendAppearancePacket(AT_Pet, 0, true, true); Mob* tempmob = GetOwner(); SetOwnerID(0); + SetPetType(petNone); if(tempmob) { tempmob->SetPet(0); @@ -3970,7 +3968,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) } if(tempmob && tempmob->IsClient()) { - EQApplicationPacket *app = new EQApplicationPacket(OP_Charm, sizeof(Charm_Struct)); + auto app = new EQApplicationPacket(OP_Charm, sizeof(Charm_Struct)); Charm_Struct *ps = (Charm_Struct*)app->pBuffer; ps->owner_id = tempmob->GetID(); ps->pet_id = this->GetID(); @@ -3982,12 +3980,12 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) { InterruptSpell(); if (this->CastToClient()->IsLD()) - AI_Start(CLIENT_LD_TIMEOUT); + CastToClient()->AI_Start(CLIENT_LD_TIMEOUT); else { bool feared = FindType(SE_Fear); if(!feared) - AI_Stop(); + CastToClient()->AI_Stop(); } } break; @@ -4001,8 +3999,8 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) } case SE_Blind: - if (curfp && !FindType(SE_Fear)) - curfp = false; + if (currently_fleeing && !FindType(SE_Fear)) + currently_fleeing = false; break; case SE_Fear: @@ -4012,11 +4010,11 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) { bool charmed = FindType(SE_Charm); if(!charmed) - AI_Stop(); + CastToClient()->AI_Stop(); } - if(curfp) { - curfp = false; + if(currently_fleeing) { + currently_fleeing = false; break; } } @@ -4031,7 +4029,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) { if(RuleB(Combat, EnableFearPathing)){ if(flee_mode) { - curfp = true; + currently_fleeing = true; CheckFlee(); break; } @@ -4136,9 +4134,9 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) uint32 buff_max = GetMaxTotalSlots(); bool found_numhits = false; - + for(uint32 d = 0; d < buff_max; d++) { - + if(IsValidSpell(buffs[d].spellid) && (buffs[d].numhits > 0)) { Numhits(true); found_numhits = true; @@ -4148,7 +4146,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) if (!found_numhits) Numhits(false); } - + if (spells[buffs[slot].spellid].NimbusEffect > 0) RemoveNimbusEffect(spells[buffs[slot].spellid].NimbusEffect); @@ -4161,7 +4159,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) { EQApplicationPacket *outapp = MakeBuffsPacket(); - entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, BIT_SoDAndLater); + entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::bit_SoDAndLater); if(IsClient() && GetTarget() == this) { CastToClient()->QueuePacket(outapp); } @@ -4171,58 +4169,23 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) if (IsNPC()) { EQApplicationPacket *outapp = MakeBuffsPacket(); - entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, BIT_SoDAndLater, true); + entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::bit_SoDAndLater, true); safe_delete(outapp); } - if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UFAndLater) + if (IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) { EQApplicationPacket *outapp = MakeBuffsPacket(false); CastToClient()->FastQueuePacket(&outapp); } + // we will eventually call CalcBonuses() even if we skip it right here, so should correct itself if we still have them + degenerating_effects = false; if (iRecalcBonuses) CalcBonuses(); } -int32 Client::GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2) -{ - int32 aa_effects_data[3] = { 0 }; - uint32 effect = 0; - int32 base1 = 0; - int32 base2 = 0; - uint32 slot = 0; - - - std::map >::const_iterator find_iter = aa_effects.find(aa_ID); - if(find_iter == aa_effects.end()) - return 0; - - for (std::map::const_iterator iter = aa_effects[aa_ID].begin(); iter != aa_effects[aa_ID].end(); ++iter) - { - effect = iter->second.skill_id; - base1 = iter->second.base1; - base2 = iter->second.base2; - slot = iter->second.slot; - - if (slot && slot == slot_id) { - - if (GetEffect) - return effect; - - if (GetBase1) - return base1; - - if (GetBase2) - return base2; - } - } - - return 0; -} - - -int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) +int16 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id) { const SPDat_Spell_Struct &spell = spells[spell_id]; @@ -4236,8 +4199,9 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) uint32 slot = 0; bool LimitFailure = false; - bool LimitInclude[MaxLimitInclude] = { false }; - /* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice spells. + bool LimitInclude[MaxLimitInclude] = {false}; + /* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice + spells. 0/1 SE_LimitResist 2/3 SE_LimitSpell 4/5 SE_LimitEffect @@ -4247,22 +4211,15 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) 12/13 SE_LimitSpellClass: 14/15 SE_LimitSpellSubClass: Remember: Update MaxLimitInclude in spdat.h if adding new limits that require Includes - */ + */ int FocusCount = 0; - std::map >::const_iterator find_iter = aa_effects.find(aa_ID); - if(find_iter == aa_effects.end()) - { - return 0; - } + for (const auto &e : rank.effects) { + effect = e.effect_id; + base1 = e.base1; + base2 = e.base2; + slot = e.slot; - for (std::map::const_iterator iter = aa_effects[aa_ID].begin(); iter != aa_effects[aa_ID].end(); ++iter) - { - effect = iter->second.skill_id; - base1 = iter->second.base1; - base2 = iter->second.base2; - slot = iter->second.slot; - /* AA Foci's can contain multiple focus effects within the same AA. To handle this we will not automatically return zero if a limit is found. @@ -4270,431 +4227,439 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) when the next valid focus effect is found. */ - if (IsFocusEffect(0, 0, true,effect) || (effect == SE_TriggerOnCast)){ + if (IsFocusEffect(0, 0, true, effect) || (effect == SE_TriggerOnCast)) { FocusCount++; - //If limit found on prior check next, else end loop. - if (FocusCount > 1){ + // If limit found on prior check next, else end loop. + if (FocusCount > 1) { - for(int e = 0; e < MaxLimitInclude; e+=2) { - if (LimitInclude[e] && !LimitInclude[e+1]) + for (int e = 0; e < MaxLimitInclude; e += 2) { + if (LimitInclude[e] && !LimitInclude[e + 1]) LimitFailure = true; } - if (LimitFailure){ + if (LimitFailure) { value = 0; LimitFailure = false; - - for(int e = 0; e < MaxLimitInclude; e++) { - LimitInclude[e] = false; //Reset array + + for (int e = 0; e < MaxLimitInclude; e++) { + LimitInclude[e] = false; // Reset array } } - else{ + else { break; } } } + switch (effect) { + case SE_Blank: + break; - switch (effect) - { - case SE_Blank: - break; + // Handle Focus Limits - //Handle Focus Limits - - case SE_LimitResist: - if(base1 < 0){ - if(spell.resisttype == -base1) //Exclude - LimitFailure = true; - } - else { + case SE_LimitResist: + if (base1 < 0) { + if (spell.resisttype == -base1) // Exclude + LimitFailure = true; + } else { LimitInclude[0] = true; - if (spell.resisttype == base1) //Include + if (spell.resisttype == base1) // Include LimitInclude[1] = true; - } - break; + } + break; - case SE_LimitInstant: - if(base1 == 1 && spell.buffduration) //Fail if not instant - LimitFailure = true; - if(base1 == 0 && (spell.buffduration == 0)) //Fail if instant - LimitFailure = true; - - break; - - case SE_LimitMaxLevel: - spell_level = spell.classes[(GetClass()%16) - 1]; - lvldiff = spell_level - base1; - //every level over cap reduces the effect by base2 percent unless from a clicky when ItemCastsUseFocus is true - if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)) { - if(base2 > 0){ - lvlModifier -= base2*lvldiff; - if(lvlModifier < 1) - LimitFailure = true; - } - else - LimitFailure = true; - } - break; - - case SE_LimitMinLevel: - if((spell.classes[(GetClass()%16) - 1]) < base1) - LimitFailure = true; - break; - - case SE_LimitCastTimeMin: - if (static_cast(spell.cast_time) < base1) - LimitFailure = true; - break; - - case SE_LimitCastTimeMax: - if (static_cast(spell.cast_time) > base1) - LimitFailure = true; - break; - - case SE_LimitSpell: - if(base1 < 0) { //Exclude - if (spell_id == -base1) - LimitFailure = true; - } - else { - LimitInclude[2] = true; - if (spell_id == base1) //Include - LimitInclude[3] = true; - } - break; - - case SE_LimitMinDur: - if (base1 > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) - LimitFailure = true; - - break; - - case SE_LimitEffect: - if(base1 < 0){ - if(IsEffectInSpell(spell_id,-base1)) //Exclude - LimitFailure = true; - } - else{ - LimitInclude[4] = true; - if(IsEffectInSpell(spell_id,base1)) //Include - LimitInclude[5] = true; - } - break; - - case SE_LimitSpellType: - switch(base1) - { - case 0: - if (!IsDetrimentalSpell(spell_id)) - LimitFailure = true; - break; - case 1: - if (!IsBeneficialSpell(spell_id)) - LimitFailure = true; - break; - } - break; - - case SE_LimitManaMin: - if(spell.mana < base1) - LimitFailure = true; - break; - - case SE_LimitTarget: - if (base1 < 0) { - if (-base1 == spell.targettype) //Exclude - LimitFailure = true; - } - else { - LimitInclude[6] = true; - if (base1 == spell.targettype) //Include - LimitInclude[7] = true; - } - break; - - case SE_LimitCombatSkills: - if (base1 == 0 && (IsCombatSkill(spell_id) || IsCombatProc(spell_id))) //Exclude Discs / Procs - LimitFailure = true; - else if (base1 == 1 && (!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) //Exclude Spells - LimitFailure = true; + case SE_LimitInstant: + if (base1 == 1 && spell.buffduration) // Fail if not instant + LimitFailure = true; + if (base1 == 0 && (spell.buffduration == 0)) // Fail if instant + LimitFailure = true; break; - case SE_LimitSpellGroup: - if(base1 < 0) { - if (-base1 == spell.spellgroup) //Exclude + case SE_LimitMaxLevel: + spell_level = spell.classes[(GetClass() % 17) - 1]; + lvldiff = spell_level - base1; + // every level over cap reduces the effect by base2 percent unless from a clicky when + // ItemCastsUseFocus is true + if (lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || + RuleB(Character, ItemCastsUseFocus) == false)) { + if (base2 > 0) { + lvlModifier -= base2 * lvldiff; + if (lvlModifier < 1) LimitFailure = true; - } - else { - LimitInclude[8] = true; - if (base1 == spell.spellgroup) //Include - LimitInclude[9] = true; - } - break; + } else + LimitFailure = true; + } + break; - case SE_LimitCastingSkill: - if(base1 < 0) { - if(-base1 == spell.skill) - LimitFailure = true; - } - else { - LimitInclude[10] = true; - if(base1 == spell.skill) - LimitInclude[11] = true; - } - break; + case SE_LimitMinLevel: + if ((spell.classes[(GetClass() % 17) - 1]) < base1) + LimitFailure = true; + break; - case SE_LimitSpellClass: - if(base1 < 0) { //Exclude - if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)) - return(0); - } - else { - LimitInclude[12] = true; - if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)) //Include - LimitInclude[13] = true; - } - break; + case SE_LimitCastTimeMin: + if (static_cast(spell.cast_time) < base1) + LimitFailure = true; + break; - case SE_LimitSpellSubclass: - if(base1 < 0) { //Exclude - if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)) - return(0); - } - else { - LimitInclude[14] = true; - if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)) //Include - LimitInclude[15] = true; - } - break; + case SE_LimitCastTimeMax: + if (static_cast(spell.cast_time) > base1) + LimitFailure = true; + break; - case SE_LimitClass: - //Do not use this limit more then once per spell. If multiple class, treat value like items would. + case SE_LimitSpell: + if (base1 < 0) { // Exclude + if (spell_id == -base1) + LimitFailure = true; + } else { + LimitInclude[2] = true; + if (spell_id == base1) // Include + LimitInclude[3] = true; + } + break; + + case SE_LimitMinDur: + if (base1 > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) + LimitFailure = true; + + break; + + case SE_LimitEffect: + if (base1 < 0) { + if (IsEffectInSpell(spell_id, -base1)) // Exclude + LimitFailure = true; + } else { + LimitInclude[4] = true; + // they use 33 here for all classes ... unsure if the type check is really needed + if (base1 == SE_SummonPet && type == focusReagentCost) { + if (IsSummonPetSpell(spell_id) || IsSummonSkeletonSpell(spell_id)) + LimitInclude[5] = true; + } else { + if (IsEffectInSpell(spell_id, base1)) // Include + LimitInclude[5] = true; + } + } + break; + + case SE_LimitSpellType: + switch (base1) { + case 0: + if (!IsDetrimentalSpell(spell_id)) + LimitFailure = true; + break; + case 1: + if (!IsBeneficialSpell(spell_id)) + LimitFailure = true; + break; + } + break; + + case SE_LimitManaMin: + if (spell.mana < base1) + LimitFailure = true; + break; + + case SE_LimitManaMax: + if (spell.mana > base1) + LimitFailure = true; + break; + + case SE_LimitTarget: + if (base1 < 0) { + if (-base1 == spell.targettype) // Exclude + LimitFailure = true; + } else { + LimitInclude[6] = true; + if (base1 == spell.targettype) // Include + LimitInclude[7] = true; + } + break; + + case SE_LimitCombatSkills: + if (base1 == 0 && (IsCombatSkill(spell_id) || IsCombatProc(spell_id))) // Exclude Discs / Procs + LimitFailure = true; + else if (base1 == 1 && (!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) // Exclude Spells + LimitFailure = true; + + break; + + case SE_LimitSpellGroup: + if (base1 < 0) { + if (-base1 == spell.spellgroup) // Exclude + LimitFailure = true; + } else { + LimitInclude[8] = true; + if (base1 == spell.spellgroup) // Include + LimitInclude[9] = true; + } + break; + + case SE_LimitCastingSkill: + if (base1 < 0) { + if (-base1 == spell.skill) + LimitFailure = true; + } else { + LimitInclude[10] = true; + if (base1 == spell.skill) + LimitInclude[11] = true; + } + break; + + case SE_LimitSpellClass: + if (base1 < 0) { // Exclude + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)) + return (0); + } else { + LimitInclude[12] = true; + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)) // Include + LimitInclude[13] = true; + } + break; + + case SE_LimitSpellSubclass: + if (base1 < 0) { // Exclude + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)) + return (0); + } else { + LimitInclude[14] = true; + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)) // Include + LimitInclude[15] = true; + } + break; + + case SE_LimitClass: + // Do not use this limit more then once per spell. If multiple class, treat value like items + // would. if (!PassLimitClass(base1, GetClass())) LimitFailure = true; break; - case SE_LimitRace: - if (base1 != GetRace()) - LimitFailure = true; - break; - - case SE_LimitUseMin: - if (base1 > spell.numhits) - LimitFailure = true; - break; - - case SE_LimitUseType: - if (base1 != spell.numhitstype) - LimitFailure = true; - break; - - //Handle Focus Effects - case SE_ImprovedDamage: - if (type == focusImprovedDamage && base1 > value) - value = base1; - break; - - case SE_ImprovedHeal: - if (type == focusImprovedHeal && base1 > value) - value = base1; - break; - - case SE_ReduceManaCost: - if (type == focusManaCost) - value = base1; + case SE_LimitRace: + if (base1 != GetRace()) + LimitFailure = true; break; - case SE_IncreaseSpellHaste: - if (type == focusSpellHaste && base1 > value) - value = base1; - break; + case SE_LimitUseMin: + if (base1 > spell.numhits) + LimitFailure = true; + break; - case SE_IncreaseSpellDuration: - if (type == focusSpellDuration && base1 > value) - value = base1; - break; + case SE_LimitUseType: + if (base1 != spell.numhitstype) + LimitFailure = true; + break; - case SE_SpellDurationIncByTic: - if (type == focusSpellDurByTic && base1 > value) - value = base1; - break; + // Handle Focus Effects + case SE_ImprovedDamage: + if (type == focusImprovedDamage && base1 > value) + value = base1; + break; - case SE_SwarmPetDuration: - if (type == focusSwarmPetDuration && base1 > value) - value = base1; - break; + case SE_ImprovedDamage2: + if (type == focusImprovedDamage2 && base1 > value) + value = base1; + break; - case SE_IncreaseRange: - if (type == focusRange && base1 > value) - value = base1; - break; + case SE_ImprovedHeal: + if (type == focusImprovedHeal && base1 > value) + value = base1; + break; - case SE_ReduceReagentCost: - if (type == focusReagentCost && base1 > value) - value = base1; - break; + case SE_ReduceManaCost: + if (type == focusManaCost) + value = base1; + break; - case SE_PetPowerIncrease: - if (type == focusPetPower && base1 > value) - value = base1; - break; + case SE_IncreaseSpellHaste: + if (type == focusSpellHaste && base1 > value) + value = base1; + break; - case SE_SpellResistReduction: - if (type == focusResistRate && base1 > value) - value = base1; - break; + case SE_IncreaseSpellDuration: + if (type == focusSpellDuration && base1 > value) + value = base1; + break; - case SE_SpellHateMod: - if (type == focusSpellHateMod ) { - if(value != 0) { - if(value > 0){ - if(base1 > value) - value = base1; - } - else{ - if(base1 < value) - value = base1; - } - } - else - value = base1; - } - break; + case SE_SpellDurationIncByTic: + if (type == focusSpellDurByTic && base1 > value) + value = base1; + break; - case SE_ReduceReuseTimer: - if(type == focusReduceRecastTime) - value = base1 / 1000; - break; + case SE_SwarmPetDuration: + if (type == focusSwarmPetDuration && base1 > value) + value = base1; + break; - case SE_TriggerOnCast: - if(type == focusTriggerOnCast){ - if(zone->random.Roll(base1)) { - value = base2; + case SE_IncreaseRange: + if (type == focusRange && base1 > value) + value = base1; + break; + + case SE_ReduceReagentCost: + if (type == focusReagentCost && base1 > value) + value = base1; + break; + + case SE_PetPowerIncrease: + if (type == focusPetPower && base1 > value) + value = base1; + break; + + case SE_SpellResistReduction: + if (type == focusResistRate && base1 > value) + value = base1; + break; + + case SE_SpellHateMod: + if (type == focusSpellHateMod) { + if (value != 0) { + if (value > 0) { + if (base1 > value) + value = base1; } else { - value = 0; - LimitFailure = true; + if (base1 < value) + value = base1; } - break; - } - - case SE_FcSpellVulnerability: - if(type == focusSpellVulnerability) + } else value = base1; - break; + } + break; - case SE_BlockNextSpellFocus: - if(type == focusBlockNextSpell){ - if(zone->random.Roll(base1)) - value = 1; - } - break; + case SE_ReduceReuseTimer: + if (type == focusReduceRecastTime) + value = base1 / 1000; + break; - case SE_FcTwincast: - if(type == focusTwincast) - value = base1; - break; - - //Note if using these as AA, make sure this is first focus used. - case SE_SympatheticProc: - if(type == focusSympatheticProc) + case SE_TriggerOnCast: + if (type == focusTriggerOnCast) { + if (zone->random.Roll(base1)) { value = base2; - break; + } else { + value = 0; + LimitFailure = true; + } + break; + } - case SE_FcDamageAmt: - if(type == focusFcDamageAmt) - value = base1; - break; + case SE_FcSpellVulnerability: + if (type == focusSpellVulnerability) + value = base1; + break; - case SE_FcDamageAmtCrit: - if(type == focusFcDamageAmtCrit) - value = base1; - break; + case SE_BlockNextSpellFocus: + if (type == focusBlockNextSpell) { + if (zone->random.Roll(base1)) + value = 1; + } + break; - case SE_FcDamageAmtIncoming: - if(type == focusFcDamageAmtIncoming) - value = base1; - break; + case SE_FcTwincast: + if (type == focusTwincast) + value = base1; + break; - case SE_FcHealAmtIncoming: - if(type == focusFcHealAmtIncoming) - value = base1; - break; + // Note if using these as AA, make sure this is first focus used. + case SE_SympatheticProc: + if (type == focusSympatheticProc) + value = base2; + break; - case SE_FcHealPctCritIncoming: - if (type == focusFcHealPctCritIncoming) - value = base1; - break; + case SE_FcDamageAmt: + if (type == focusFcDamageAmt) + value = base1; + break; - case SE_FcHealAmtCrit: - if(type == focusFcHealAmtCrit) - value = base1; - break; + case SE_FcDamageAmt2: + if (type == focusFcDamageAmt2) + value = base1; + break; - case SE_FcHealAmt: - if(type == focusFcHealAmt) - value = base1; - break; + case SE_FcDamageAmtCrit: + if (type == focusFcDamageAmtCrit) + value = base1; + break; - case SE_FcHealPctIncoming: - if(type == focusFcHealPctIncoming) - value = base1; - break; + case SE_FcDamageAmtIncoming: + if (type == focusFcDamageAmtIncoming) + value = base1; + break; - case SE_FcBaseEffects: - if (type == focusFcBaseEffects) - value = base1; - break; + case SE_FcHealAmtIncoming: + if (type == focusFcHealAmtIncoming) + value = base1; + break; - case SE_FcDamagePctCrit: - if(type == focusFcDamagePctCrit) - value = base1; - break; + case SE_FcHealPctCritIncoming: + if (type == focusFcHealPctCritIncoming) + value = base1; + break; - case SE_FcIncreaseNumHits: - if(type == focusIncreaseNumHits) - value = base1; - break; - - case SE_FcLimitUse: - if(type == focusFcLimitUse) - value = base1; - break; - - case SE_FcMute: - if(type == focusFcMute) - value = base1; - break; + case SE_FcHealAmtCrit: + if (type == focusFcHealAmtCrit) + value = base1; + break; - case SE_FcStunTimeMod: - if(type == focusFcStunTimeMod) - value = base1; - break; + case SE_FcHealAmt: + if (type == focusFcHealAmt) + value = base1; + break; + case SE_FcHealPctIncoming: + if (type == focusFcHealPctIncoming) + value = base1; + break; + + case SE_FcBaseEffects: + if (type == focusFcBaseEffects) + value = base1; + break; + + case SE_FcDamagePctCrit: + if (type == focusFcDamagePctCrit) + value = base1; + break; + + case SE_FcIncreaseNumHits: + if (type == focusIncreaseNumHits) + value = base1; + break; + + case SE_FcLimitUse: + if (type == focusFcLimitUse) + value = base1; + break; + + case SE_FcMute: + if (type == focusFcMute) + value = base1; + break; + + case SE_FcStunTimeMod: + if (type == focusFcStunTimeMod) + value = base1; + break; } } - for(int e = 0; e < MaxLimitInclude; e+=2) { - if (LimitInclude[e] && !LimitInclude[e+1]) + for (int e = 0; e < MaxLimitInclude; e += 2) { + if (LimitInclude[e] && !LimitInclude[e + 1]) return 0; } if (LimitFailure) return 0; - - return(value*lvlModifier/100); + + return (value * lvlModifier / 100); } //given an item/spell's focus ID and the spell being cast, determine the focus ammount, if any //assumes that spell_id is not a bard spell and that both ids are valid spell ids -int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, bool best_focus) { - - if(!IsValidSpell(focus_id) || !IsValidSpell(spell_id)) +int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, bool best_focus) +{ + if (!IsValidSpell(focus_id) || !IsValidSpell(spell_id)) return 0; - const SPDat_Spell_Struct &focus_spell = spells[focus_id]; const SPDat_Spell_Struct &spell = spells[spell_id]; @@ -4704,8 +4669,9 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo int lvldiff = 0; uint32 Caston_spell_id = 0; - bool LimitInclude[MaxLimitInclude] = { false }; - /* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice spells. + bool LimitInclude[MaxLimitInclude] = {false}; + /* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice + spells. 0/1 SE_LimitResist 2/3 SE_LimitSpell 4/5 SE_LimitEffect @@ -4715,31 +4681,30 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo 12/13 SE_LimitSpellClass: 14/15 SE_LimitSpellSubClass: Remember: Update MaxLimitInclude in spdat.h if adding new limits that require Includes - */ - + */ + for (int i = 0; i < EFFECT_COUNT; i++) { switch (focus_spell.effectid[i]) { - + case SE_Blank: break; - + case SE_LimitResist: - if(focus_spell.base[i] < 0){ - if (spell.resisttype == -focus_spell.base[i]) //Exclude + if (focus_spell.base[i] < 0) { + if (spell.resisttype == -focus_spell.base[i]) // Exclude return 0; - } - else { + } else { LimitInclude[0] = true; - if (spell.resisttype == focus_spell.base[i]) //Include + if (spell.resisttype == focus_spell.base[i]) // Include LimitInclude[1] = true; } break; - + case SE_LimitInstant: - if(focus_spell.base[i] == 1 && spell.buffduration) //Fail if not instant + if (focus_spell.base[i] == 1 && spell.buffduration) // Fail if not instant return 0; - if(focus_spell.base[i] == 0 && (spell.buffduration == 0)) //Fail if instant + if (focus_spell.base[i] == 0 && (spell.buffduration == 0)) // Fail if instant return 0; break; @@ -4747,133 +4712,138 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo case SE_LimitMaxLevel: if (IsNPC()) break; - spell_level = spell.classes[(GetClass()%16) - 1]; + spell_level = spell.classes[(GetClass() % 17) - 1]; lvldiff = spell_level - focus_spell.base[i]; - //every level over cap reduces the effect by focus_spell.base2[i] percent unless from a clicky when ItemCastsUseFocus is true - if(lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || RuleB(Character, ItemCastsUseFocus) == false)){ - if(focus_spell.base2[i] > 0){ - lvlModifier -= focus_spell.base2[i]*lvldiff; - if(lvlModifier < 1) + // every level over cap reduces the effect by focus_spell.base2[i] percent unless from a clicky + // when ItemCastsUseFocus is true + if (lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || + RuleB(Character, ItemCastsUseFocus) == false)) { + if (focus_spell.base2[i] > 0) { + lvlModifier -= focus_spell.base2[i] * lvldiff; + if (lvlModifier < 1) return 0; - } - else + } else return 0; } break; - + case SE_LimitMinLevel: if (IsNPC()) break; - if (spell.classes[(GetClass()%16) - 1] < focus_spell.base[i]) - return(0); + if (spell.classes[(GetClass() % 17) - 1] < focus_spell.base[i]) + return (0); break; case SE_LimitCastTimeMin: if (spells[spell_id].cast_time < (uint16)focus_spell.base[i]) - return(0); + return (0); break; case SE_LimitCastTimeMax: if (spells[spell_id].cast_time > (uint16)focus_spell.base[i]) - return(0); + return (0); break; - + case SE_LimitSpell: - if(focus_spell.base[i] < 0) { //Exclude + if (focus_spell.base[i] < 0) { // Exclude if (spell_id == -focus_spell.base[i]) - return(0); - } - else { + return (0); + } else { LimitInclude[2] = true; - if (spell_id == focus_spell.base[i]) //Include + if (spell_id == focus_spell.base[i]) // Include LimitInclude[3] = true; } break; case SE_LimitMinDur: - if (focus_spell.base[i] > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) - return(0); + if (focus_spell.base[i] > + CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) + return (0); break; case SE_LimitEffect: - if(focus_spell.base[i] < 0){ - if(IsEffectInSpell(spell_id,-focus_spell.base[i])) //Exclude + if (focus_spell.base[i] < 0) { + if (IsEffectInSpell(spell_id, -focus_spell.base[i])) // Exclude return 0; - } - else{ + } else { LimitInclude[4] = true; - if(IsEffectInSpell(spell_id,focus_spell.base[i])) //Include + if (IsEffectInSpell(spell_id, focus_spell.base[i])) // Include LimitInclude[5] = true; } break; - case SE_LimitSpellType: - switch( focus_spell.base[i]){ - case 0: - if (!IsDetrimentalSpell(spell_id)) - return 0; - break; - case 1: - if (!IsBeneficialSpell(spell_id)) - return 0; - break; - default: - Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown limit spelltype %d", focus_spell.base[i]); + switch (focus_spell.base[i]) { + case 0: + if (!IsDetrimentalSpell(spell_id)) + return 0; + break; + case 1: + if (!IsBeneficialSpell(spell_id)) + return 0; + break; + default: + Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown limit spelltype %d", + focus_spell.base[i]); } break; case SE_LimitManaMin: - if(spell.mana < focus_spell.base[i]) + if (spell.mana < focus_spell.base[i]) + return 0; + break; + + case SE_LimitManaMax: + if (spell.mana > focus_spell.base[i]) return 0; break; case SE_LimitTarget: if (focus_spell.base[i] < 0) { - if (-focus_spell.base[i] == spell.targettype) //Exclude + if (-focus_spell.base[i] == spell.targettype) // Exclude return 0; - } - else { + } else { LimitInclude[6] = true; - if (focus_spell.base[i] == spell.targettype) //Include + if (focus_spell.base[i] == spell.targettype) // Include LimitInclude[7] = true; } break; case SE_LimitCombatSkills: - if (focus_spell.base[i] == 0 && (IsCombatSkill(spell_id) || IsCombatProc(spell_id))) //Exclude Discs / Procs + if (focus_spell.base[i] == 0 && + (IsCombatSkill(spell_id) || IsCombatProc(spell_id))) // Exclude Discs / Procs return 0; - else if (focus_spell.base[i] == 1 && (!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) //Exclude Spells + else if (focus_spell.base[i] == 1 && + (!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) // Exclude Spells return 0; break; case SE_LimitSpellGroup: - if(focus_spell.base[i] < 0) { - if (-focus_spell.base[i] == spell.spellgroup) //Exclude + if (focus_spell.base[i] < 0) { + if (-focus_spell.base[i] == spell.spellgroup) // Exclude return 0; - } - else { + } else { LimitInclude[8] = true; - if (focus_spell.base[i] == spell.spellgroup) //Include + if (focus_spell.base[i] == spell.spellgroup) // Include LimitInclude[9] = true; } break; case SE_LimitCastingSkill: - if(focus_spell.base[i] < 0) { - if(-focus_spell.base[i] == spell.skill) + if (focus_spell.base[i] < 0) { + if (-focus_spell.base[i] == spell.skill) return 0; - } - else { + } else { LimitInclude[10] = true; - if(focus_spell.base[i] == spell.skill) + if (focus_spell.base[i] == spell.skill) LimitInclude[11] = true; } break; - + case SE_LimitClass: - //Do not use this limit more then once per spell. If multiple class, treat value like items would. + // Do not use this limit more then once per spell. If multiple class, treat value like items + // would. if (!PassLimitClass(focus_spell.base[i], GetClass())) return 0; break; @@ -4899,40 +4869,38 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; case SE_LimitSpellClass: - if(focus_spell.base[i] < 0) { //Exclude + if (focus_spell.base[i] < 0) { // Exclude if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)) - return(0); - } - else { + return (0); + } else { LimitInclude[12] = true; - if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)) //Include + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)) // Include LimitInclude[13] = true; } break; case SE_LimitSpellSubclass: - if(focus_spell.base[i] < 0) { //Exclude + if (focus_spell.base[i] < 0) { // Exclude if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)) - return(0); - } - else { + return (0); + } else { LimitInclude[14] = true; - if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)) //Include + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)) // Include LimitInclude[15] = true; } break; - - //handle effects + // handle effects case SE_ImprovedDamage: if (type == focusImprovedDamage) { // This is used to determine which focus should be used for the random calculation - if(best_focus) { + if (best_focus) { // If the spell contains a value in the base2 field then that is the max value if (focus_spell.base2[i] != 0) { value = focus_spell.base2[i]; } - // If the spell does not contain a base2 value, then its a straight non random value + // If the spell does not contain a base2 value, then its a straight non random + // value else { value = focus_spell.base[i]; } @@ -4940,8 +4908,25 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo // Actual focus calculation starts here else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { value = focus_spell.base[i]; + } else { + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } - else { + } + break; + + case SE_ImprovedDamage2: + if (type == focusImprovedDamage2) { + if (best_focus) { + if (focus_spell.base2[i] != 0) { + value = focus_spell.base2[i]; + } + else { + value = focus_spell.base[i]; + } + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + value = focus_spell.base[i]; + } else { value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } } @@ -4949,18 +4934,15 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo case SE_ImprovedHeal: if (type == focusImprovedHeal) { - if(best_focus) { + if (best_focus) { if (focus_spell.base2[i] != 0) { value = focus_spell.base2[i]; - } - else { + } else { value = focus_spell.base[i]; } - } - else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + } else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { value = focus_spell.base[i]; - } - else { + } else { value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } } @@ -4968,18 +4950,15 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo case SE_ReduceManaCost: if (type == focusManaCost) { - if(best_focus) { + if (best_focus) { if (focus_spell.base2[i] != 0) { value = focus_spell.base2[i]; - } - else { + } else { value = focus_spell.base[i]; } - } - else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + } else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { value = focus_spell.base[i]; - } - else { + } else { value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); } } @@ -4989,7 +4968,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo if (type == focusSpellHaste && focus_spell.base[i] > value) value = focus_spell.base[i]; break; - + case SE_IncreaseSpellDuration: if (type == focusSpellDuration && focus_spell.base[i] > value) value = focus_spell.base[i]; @@ -5026,30 +5005,28 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; case SE_SpellHateMod: - if (type == focusSpellHateMod){ - if(value != 0){ - if(value > 0){ - if(focus_spell.base[i] > value) + if (type == focusSpellHateMod) { + if (value != 0) { + if (value > 0) { + if (focus_spell.base[i] > value) + value = focus_spell.base[i]; + } else { + if (focus_spell.base[i] < value) value = focus_spell.base[i]; } - else{ - if(focus_spell.base[i] < value) - value = focus_spell.base[i]; - } - } - else + } else value = focus_spell.base[i]; } break; case SE_ReduceReuseTimer: - if(type == focusReduceRecastTime) + if (type == focusReduceRecastTime) value = focus_spell.base[i] / 1000; break; case SE_TriggerOnCast: - if(type == focusTriggerOnCast){ - if(zone->random.Roll(focus_spell.base[i])) + if (type == focusTriggerOnCast) { + if (zone->random.Roll(focus_spell.base[i])) value = focus_spell.base2[i]; else value = 0; @@ -5057,50 +5034,55 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; case SE_BlockNextSpellFocus: - if(type == focusBlockNextSpell){ - if(zone->random.Roll(focus_spell.base[i])) + if (type == focusBlockNextSpell) { + if (zone->random.Roll(focus_spell.base[i])) value = 1; } break; case SE_SympatheticProc: - if(type == focusSympatheticProc) { + if (type == focusSympatheticProc) { value = focus_id; } break; case SE_FcSpellVulnerability: - if(type == focusSpellVulnerability) + if (type == focusSpellVulnerability) value = focus_spell.base[i]; break; case SE_FcTwincast: - if(type == focusTwincast) + if (type == focusTwincast) value = focus_spell.base[i]; break; case SE_FcDamageAmt: - if(type == focusFcDamageAmt) + if (type == focusFcDamageAmt) + value = focus_spell.base[i]; + break; + + case SE_FcDamageAmt2: + if (type == focusFcDamageAmt2) value = focus_spell.base[i]; break; case SE_FcDamageAmtCrit: - if(type == focusFcDamageAmtCrit) + if (type == focusFcDamageAmtCrit) value = focus_spell.base[i]; break; case SE_FcDamageAmtIncoming: - if(type == focusFcDamageAmtIncoming) + if (type == focusFcDamageAmtIncoming) value = focus_spell.base[i]; break; case SE_FcHealAmtIncoming: - if(type == focusFcHealAmtIncoming) + if (type == focusFcHealAmtIncoming) value = focus_spell.base[i]; break; case SE_FcDamagePctCrit: - if(type == focusFcDamagePctCrit) + if (type == focusFcDamagePctCrit) value = focus_spell.base[i]; break; @@ -5110,17 +5092,17 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; case SE_FcHealAmtCrit: - if(type == focusFcHealAmtCrit) + if (type == focusFcHealAmtCrit) value = focus_spell.base[i]; break; - case SE_FcHealAmt: - if(type == focusFcHealAmt) + case SE_FcHealAmt: + if (type == focusFcHealAmt) value = focus_spell.base[i]; break; case SE_FcHealPctIncoming: - if(type == focusFcHealPctIncoming) + if (type == focusFcHealPctIncoming) value = focus_spell.base[i]; break; @@ -5130,60 +5112,59 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo break; case SE_FcIncreaseNumHits: - if(type == focusIncreaseNumHits) + if (type == focusIncreaseNumHits) value = focus_spell.base[i]; break; case SE_FcLimitUse: - if(type == focusFcLimitUse) + if (type == focusFcLimitUse) value = focus_spell.base[i]; break; case SE_FcMute: - if(type == focusFcMute) + if (type == focusFcMute) value = focus_spell.base[i]; break; case SE_FcStunTimeMod: - if(type == focusFcStunTimeMod) + if (type == focusFcStunTimeMod) value = focus_spell.base[i]; break; case SE_FcTimerRefresh: - if(type == focusFcTimerRefresh) + if (type == focusFcTimerRefresh) value = focus_spell.base[i]; break; #if EQDEBUG >= 6 - //this spits up a lot of garbage when calculating spell focuses - //since they have all kinds of extra effects on them. + // this spits up a lot of garbage when calculating spell focuses + // since they have all kinds of extra effects on them. default: - Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown effectid %d", focus_spell.effectid[i]); + Log.Out(Logs::General, Logs::Normal, "CalcFocusEffect: unknown effectid %d", + focus_spell.effectid[i]); #endif } - } - for(int e = 0; e < MaxLimitInclude; e+=2) { - if (LimitInclude[e] && !LimitInclude[e+1]) + for (int e = 0; e < MaxLimitInclude; e += 2) { + if (LimitInclude[e] && !LimitInclude[e + 1]) return 0; } - - if (Caston_spell_id){ - if(IsValidSpell(Caston_spell_id) && (Caston_spell_id != spell_id)) - SpellFinished(Caston_spell_id, this, 10, 0, -1, spells[Caston_spell_id].ResistDiff); + + if (Caston_spell_id) { + if (IsValidSpell(Caston_spell_id) && (Caston_spell_id != spell_id)) + SpellFinished(Caston_spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[Caston_spell_id].ResistDiff); } - return(value*lvlModifier/100); + return (value * lvlModifier / 100); } -int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { +uint16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { if (IsBardSong(spell_id)) return 0; uint16 proc_spellid = 0; - uint8 MAX_SYMPATHETIC = 10; float ProcChance = 0.0f; std::vector SympatheticProcList; @@ -5191,11 +5172,11 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { //item focus if (itembonuses.FocusEffects[type]){ - const Item_Struct* TempItem = 0; + const EQEmu::ItemBase* TempItem = 0; - for(int x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::EQUIPMENT_END; x++) + for (int x = EQEmu::legacy::EQUIPMENT_BEGIN; x <= EQEmu::legacy::EQUIPMENT_END; x++) { - if (SympatheticProcList.size() > MAX_SYMPATHETIC) + if (SympatheticProcList.size() > MAX_SYMPATHETIC_PROCS) continue; TempItem = nullptr; @@ -5213,16 +5194,16 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { } } - for (int y = AUG_BEGIN; y < EmuConstants::ITEM_COMMON_SIZE; ++y) + for (int y = AUG_INDEX_BEGIN; y < EQEmu::legacy::ITEM_COMMON_SIZE; ++y) { - if (SympatheticProcList.size() > MAX_SYMPATHETIC) + if (SympatheticProcList.size() > MAX_SYMPATHETIC_PROCS) continue; ItemInst *aug = nullptr; aug = ins->GetAugment(y); if(aug) { - const Item_Struct* TempItemAug = aug->GetItem(); + const EQEmu::ItemBase* TempItemAug = aug->GetItem(); if (TempItemAug && TempItemAug->Focus.Effect > 0 && IsValidSpell(TempItemAug->Focus.Effect)) { proc_spellid = CalcFocusEffect(type, TempItemAug->Focus.Effect, spell_id); if (IsValidSpell(proc_spellid)){ @@ -5243,52 +5224,52 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { int buff_max = GetMaxTotalSlots(); for (buff_slot = 0; buff_slot < buff_max; buff_slot++) { - if (SympatheticProcList.size() > MAX_SYMPATHETIC) + if (SympatheticProcList.size() > MAX_SYMPATHETIC_PROCS) continue; focusspellid = buffs[buff_slot].spellid; - if (IsValidSpell(focusspellid)) + if (!IsValidSpell(focusspellid)) continue; proc_spellid = CalcFocusEffect(type, focusspellid, spell_id); if (IsValidSpell(proc_spellid)){ - ProcChance = GetSympatheticProcChances(spell_id, spells[focusspellid].base[0]); + ProcChance = GetSympatheticProcChances(spell_id, GetSympatheticSpellProcRate(proc_spellid)); if(zone->random.Roll(ProcChance)) SympatheticProcList.push_back(proc_spellid); } } } - /*Note: At present, ff designing custom AA to have a sympathetic proc effect, only use one focus + /*Note: At present, ff designing custom AA to have a sympathetic proc effect, only use one focus effect within the aa_effects data for each AA*[No live AA's use this effect to my knowledge]*/ - if (aabonuses.FocusEffects[type]){ + if (aabonuses.FocusEffects[type]) { + for (const auto &aa : aa_ranks) { + if (SympatheticProcList.size() > MAX_SYMPATHETIC_PROCS) + break; - uint32 aa_AA = 0; - uint32 aa_value = 0; + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first); + auto ability = ability_rank.first; + auto rank = ability_rank.second; - for (int i = 0; i < MAX_PP_AA_ARRAY; i++) - { - aa_AA = this->aa[i]->AA; - aa_value = this->aa[i]->value; - if (aa_AA < 1 || aa_value < 1) + if(!ability) { + continue; + } + + if (rank->effects.empty()) continue; - if (SympatheticProcList.size() > MAX_SYMPATHETIC) - continue; - - proc_spellid = CalcAAFocus(type, aa_AA, spell_id); - - if (IsValidSpell(proc_spellid)){ - ProcChance = GetSympatheticProcChances(spell_id, GetAABase1(aa_AA, 1)); - if(zone->random.Roll(ProcChance)) + proc_spellid = CalcAAFocus(type, *rank, spell_id); + if (IsValidSpell(proc_spellid)) { + ProcChance = GetSympatheticProcChances(spell_id, rank->effects[0].base1); + if (zone->random.Roll(ProcChance)) SympatheticProcList.push_back(proc_spellid); } } } - if (SympatheticProcList.size() > 0) + if (!SympatheticProcList.empty()) { uint8 random = zone->random.Int(0, SympatheticProcList.size()-1); int FinalSympatheticProc = SympatheticProcList[random]; @@ -5299,9 +5280,12 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { return 0; } -int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { +int16 Client::GetFocusEffect(focusType type, uint16 spell_id) +{ + if (IsBardSong(spell_id) && type != focusFcBaseEffects && type != focusSpellDuration) + return 0; - if (IsBardSong(spell_id) && type != focusFcBaseEffects) + if (spells[spell_id].not_focusable) return 0; int16 realTotal = 0; @@ -5311,21 +5295,21 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { //Improved Healing, Damage & Mana Reduction are handled differently in that some are random percentages //In these cases we need to find the most powerful effect, so that each piece of gear wont get its own chance - if(RuleB(Spells, LiveLikeFocusEffects) && (type == focusManaCost || type == focusImprovedHeal || type == focusImprovedDamage)) + if(RuleB(Spells, LiveLikeFocusEffects) && (type == focusManaCost || type == focusImprovedHeal || type == focusImprovedDamage || type == focusImprovedDamage2)) rand_effectiveness = true; //Check if item focus effect exists for the client. if (itembonuses.FocusEffects[type]){ - const Item_Struct* TempItem = 0; - const Item_Struct* UsedItem = 0; + const EQEmu::ItemBase* TempItem = 0; + const EQEmu::ItemBase* UsedItem = 0; uint16 UsedFocusID = 0; int16 Total = 0; int16 focus_max = 0; int16 focus_max_real = 0; //item focus - for(int x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::EQUIPMENT_END; x++) + for (int x = EQEmu::legacy::EQUIPMENT_BEGIN; x <= EQEmu::legacy::EQUIPMENT_END; x++) { TempItem = nullptr; ItemInst* ins = GetInv().GetItem(x); @@ -5359,13 +5343,13 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { } } - for (int y = AUG_BEGIN; y < EmuConstants::ITEM_COMMON_SIZE; ++y) + for (int y = AUG_INDEX_BEGIN; y < EQEmu::legacy::ITEM_COMMON_SIZE; ++y) { ItemInst *aug = nullptr; aug = ins->GetAugment(y); if(aug) { - const Item_Struct* TempItemAug = aug->GetItem(); + const EQEmu::ItemBase* TempItemAug = aug->GetItem(); if (TempItemAug && TempItemAug->Focus.Effect > 0 && TempItemAug->Focus.Effect != SPELL_UNKNOWN) { if(rand_effectiveness) { focus_max = CalcFocusEffect(type, TempItemAug->Focus.Effect, spell_id, true); @@ -5397,7 +5381,7 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { } //Tribute Focus - for(int x = EmuConstants::TRIBUTE_BEGIN; x <= EmuConstants::TRIBUTE_END; ++x) + for (int x = EQEmu::legacy::TRIBUTE_BEGIN; x <= EQEmu::legacy::TRIBUTE_END; ++x) { TempItem = nullptr; ItemInst* ins = GetInv().GetItem(x); @@ -5436,8 +5420,47 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { if(UsedItem && rand_effectiveness && focus_max_real != 0) realTotal = CalcFocusEffect(type, UsedFocusID, spell_id); - if (realTotal != 0 && UsedItem) - Message_StringID(MT_Spells, BEGINS_TO_GLOW, UsedItem->Name); + if ((rand_effectiveness && UsedItem) || (realTotal != 0 && UsedItem)) { + // there are a crap ton more of these, I was able to verify these ones though + // the RNG effective ones appear to have a different message for failing to focus + uint32 string_id = BEGINS_TO_GLOW; // this is really just clicky message ... + switch (type) { + case focusSpellHaste: + string_id = SHIMMERS_BRIEFLY; + break; + case focusManaCost: // this might be GROWS_DIM for fail + string_id = FLICKERS_PALE_LIGHT; + break; + case focusSpellDuration: + string_id = SPARKLES; + break; + case focusImprovedDamage: + case focusImprovedDamage2: + if (realTotal) + string_id = ALIVE_WITH_POWER; + else + string_id = SEEMS_DRAINED; + break; + case focusRange: + string_id = PULSES_WITH_LIGHT; + break; + case focusSpellHateMod: // GLOWS_RED for increasing hate + string_id = GLOWS_BLUE; + break; + case focusImprovedHeal: + if (realTotal) + string_id = FEEDS_WITH_POWER; + else + string_id = POWER_DRAIN_INTO; + break; + case focusReagentCost: // this might be GROWS_DIM for fail as well ... + string_id = BEGINS_TO_SHINE; + break; + default: + break; + } + Message_StringID(MT_Spells, string_id, UsedItem->Name); + } } //Check if spell focus effect exists for the client. @@ -5498,18 +5521,20 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { if (aabonuses.FocusEffects[type]){ int16 Total3 = 0; - uint32 slots = 0; - uint32 aa_AA = 0; - uint32 aa_value = 0; - for (int i = 0; i < MAX_PP_AA_ARRAY; i++) - { - aa_AA = this->aa[i]->AA; - aa_value = this->aa[i]->value; - if (aa_AA < 1 || aa_value < 1) + for (const auto &aa : aa_ranks) { + auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first); + auto ability = ability_rank.first; + auto rank = ability_rank.second; + + if(!ability) { + continue; + } + + if (rank->effects.empty()) continue; - Total3 = CalcAAFocus(type, aa_AA, spell_id); + Total3 = CalcAAFocus(type, *rank, spell_id); if (Total3 > 0 && realTotal3 >= 0 && Total3 > realTotal3) { realTotal3 = Total3; } @@ -5519,9 +5544,6 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { } } - if(type == focusReagentCost && IsSummonPetSpell(spell_id) && GetAA(aaElementalPact)) - return 100; - if(type == focusReagentCost && (IsEffectInSpell(spell_id, SE_SummonItem) || IsSacrificeSpell(spell_id))) return 0; //Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected @@ -5537,31 +5559,34 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { int16 NPC::GetFocusEffect(focusType type, uint16 spell_id) { + if (spells[spell_id].not_focusable) + return 0; + int16 realTotal = 0; int16 realTotal2 = 0; bool rand_effectiveness = false; //Improved Healing, Damage & Mana Reduction are handled differently in that some are random percentages //In these cases we need to find the most powerful effect, so that each piece of gear wont get its own chance - if(RuleB(Spells, LiveLikeFocusEffects) && (type == focusManaCost || type == focusImprovedHeal || type == focusImprovedDamage)) + if(RuleB(Spells, LiveLikeFocusEffects) && (type == focusManaCost || type == focusImprovedHeal || type == focusImprovedDamage || type == focusImprovedDamage2)) rand_effectiveness = true; if (RuleB(Spells, NPC_UseFocusFromItems) && itembonuses.FocusEffects[type]){ - const Item_Struct* TempItem = 0; - const Item_Struct* UsedItem = 0; + const EQEmu::ItemBase* TempItem = 0; + const EQEmu::ItemBase* UsedItem = 0; uint16 UsedFocusID = 0; int16 Total = 0; int16 focus_max = 0; int16 focus_max_real = 0; //item focus - for(int i = 0; i < EmuConstants::EQUIPMENT_SIZE; i++){ - const Item_Struct *cur = database.GetItem(equipment[i]); - + for (int i = 0; i < EQEmu::legacy::EQUIPMENT_SIZE; i++){ + const EQEmu::ItemBase *cur = database.GetItem(equipment[i]); + if(!cur) continue; - + TempItem = cur; if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) { @@ -5591,7 +5616,7 @@ int16 NPC::GetFocusEffect(focusType type, uint16 spell_id) { } } } - + if(UsedItem && rand_effectiveness && focus_max_real != 0) realTotal = CalcFocusEffect(type, UsedFocusID, spell_id); } @@ -5910,26 +5935,46 @@ float Mob::GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 I int32 total_cast_time = 0; float cast_time_mod = 0.0f; ProcRateMod -= 100; - + if (spells[spell_id].recast_time >= spells[spell_id].recovery_time) total_cast_time = spells[spell_id].recast_time + spells[spell_id].cast_time; else total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time; - - if (total_cast_time > 0 && total_cast_time <= 2500) - cast_time_mod = 0.25f; - else if (total_cast_time > 2500 && total_cast_time < 7000) - cast_time_mod = 0.167f*((static_cast(total_cast_time) - 1000.0f)/1000.0f); - else - cast_time_mod = static_cast(total_cast_time) / 7000.0f; - ProcChance = (RuleR(Casting, AvgSpellProcsPerMinute)/100.0f) * (static_cast(100.0f + ProcRateMod) / 10.0f) + if (total_cast_time > 0 && total_cast_time <= 2500) + cast_time_mod = 0.25f; + else if (total_cast_time > 2500 && total_cast_time < 7000) + cast_time_mod = 0.167f*((static_cast(total_cast_time) - 1000.0f)/1000.0f); + else + cast_time_mod = static_cast(total_cast_time) / 7000.0f; + + ProcChance = (RuleR(Casting, AvgSpellProcsPerMinute)/100.0f) * (static_cast(100.0f + ProcRateMod) / 10.0f) * cast_time_mod * (static_cast(100.0f + ItemProcRate)/100.0f); return ProcChance; } +int16 Mob::GetSympatheticSpellProcRate(uint16 spell_id) +{ + for (int i = 0; i < EFFECT_COUNT; i++){ + if (spells[spell_id].effectid[i] == SE_SympatheticProc) + return spells[spell_id].base[i]; + } + + return 0; +} + +uint16 Mob::GetSympatheticSpellProcID(uint16 spell_id) +{ + for (int i = 0; i < EFFECT_COUNT; i++){ + if (spells[spell_id].effectid[i] == SE_SympatheticProc) + return spells[spell_id].base2[i]; + } + + return 0; +} + bool Mob::DoHPToManaCovert(uint16 mana_cost) { if (spellbonuses.HPToManaConvert){ @@ -6044,20 +6089,25 @@ int32 Mob::GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spel CheckNumHitsRemaining(NumHit::MatchingSpells, tmp_buffslot); } - + return value; } -int32 Mob::ApplySpellEffectiveness(Mob* caster, int16 spell_id, int32 value, bool IsBard) { +int32 Mob::ApplySpellEffectiveness(int16 spell_id, int32 value, bool IsBard, uint16 caster_id) { // 9-17-12: This is likely causing crashes, disabled till can resolve. if (IsBard) return value; + Mob* caster = this; + + if (caster_id && caster_id != GetID())//Make sure we are checking the casters focus + caster = entity_list.GetMob(caster_id); + if (!caster) return value; - int16 focus = GetFocusEffect(focusFcBaseEffects, spell_id); + int16 focus = caster->GetFocusEffect(focusFcBaseEffects, spell_id); if (IsBard) value += focus; @@ -6128,8 +6178,8 @@ uint16 Mob::GetSpellEffectResistChance(uint16 spell_id) bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){ - /*Live 5-20-14 Patch Note: Updated all spells which use Remove Detrimental and - Cancel Beneficial spell effects to use a new method. The chances for those spells to + /*Live 5-20-14 Patch Note: Updated all spells which use Remove Detrimental and + Cancel Beneficial spell effects to use a new method. The chances for those spells to affect their targets have not changed unless otherwise noted.*/ /*This should provide a somewhat accurate conversion between pre 5/14 base values and post. @@ -6141,7 +6191,7 @@ bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){ //Effect value of dispels are treated as a level modifier. //Values for scaling were obtain from live parses, best estimates. - caster_level += level_modifier - 1; + caster_level += level_modifier - 1; int dispel_chance = 32; //Baseline chance if no level difference and no modifier int level_diff = caster_level - buff_level; @@ -6182,7 +6232,7 @@ bool Mob::ImprovedTaunt(){ else { if(!TryFadeEffect(spellbonuses.ImprovedTaunt[2])) BuffFadeBySlot(spellbonuses.ImprovedTaunt[2], true); //If caster killed removed effect. - } + } } } @@ -6194,7 +6244,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama { /*If return TRUE spell met all restrictions and can continue (this = target). This check is used when the spell_new field CastRestriction is defined OR spell effect '0'(DD/Heal) has a defined limit - Range 1 : UNKNOWN + Range 1 : UNKNOWN -- the spells with this seem to not have a restiction, true for now Range 100 : *Animal OR Humanoid Range 101 : *Dragon Range 102 : *Animal OR Insect @@ -6221,7 +6271,10 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama Range 124 : *Undead HP < 10% Range 125 : *Clockwork HP < 10% Range 126 : *Wisp HP < 10% - Range 127-130 : UNKNOWN + Range 127 : UNKNOWN + Range 128 : pure melee -- guess + Range 129 : pure caster -- guess + Range 130 : hybrid -- guess Range 150 : UNKNOWN Range 190 : No Raid boss flag *not implemented Range 191 : This spell will deal less damage to 'exceptionally strong targets' - Raid boss flag *not implemented @@ -6233,22 +6286,28 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama Range 300 - 303 : UNKOWN *not implemented Range 304 : Chain + Plate class (buffs) Range 399 - 409 : Heal if HP within a specified range (400 = 0-25% 401 = 25 - 35% 402 = 35-45% ect) - Range 410 - 411 : UNKOWN + Range 410 - 411 : UNKOWN -- examples are auras that cast on NPCs maybe in combat/out of combat? Range 500 - 599 : Heal if HP less than a specified value Range 600 - 699 : Limit to Body Type [base2 - 600 = Body] - Range 700 : UNKNOWN + Range 700 : NPC only -- from patch notes "Wizard - Arcane Fusion no longer deals damage to non-NPC targets. This should ensure that wizards who fail their Bucolic Gambit are slightly less likely to annihilate themselves." Range 701 : NOT PET - Range 800 : UKNOWN + Range 800 : UKNOWN -- Target's Target Test (16598) + Range 812 : UNKNOWN -- triggered by Thaumatize Owner + Range 814 : UNKNOWN -- Vegetentacles + Range 815 : UNKNOWN -- Pumpkin Pulp Splash + Range 816 : UNKNOWN -- Rotten Fruit Splash + Range 817 : UNKNOWN -- Tainted Bixie Pollen Splash Range 818 - 819 : If Undead/If Not Undead Range 820 - 822 : UKNOWN Range 835 : Unknown *not implemented - Range 836 - 837 : Progression Server / Live Server *not implemented - Range 839 : Unknown *not implemented + Range 836 - 837 : Progression Server / Live Server *not fully implemented + Range 839 : Progression Server and GoD released -- broken until Oct 21 2015 on live *not fully implemented Range 842 - 844 : Humaniod lv MAX ((842 - 800) * 2) Range 845 - 847 : UNKNOWN + Range 860 - 871 : Humanoid lv MAX 860 = 90, 871 = 104 *not implemented Range 10000 - 11000 : Limit to Race [base2 - 10000 = Race] (*Not on live: Too useful a function to not implement) THIS IS A WORK IN PROGRESS - */ + */ if (value <= 0) return true; @@ -6257,174 +6316,191 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama switch(value) { - case 100: + case 1: + return true; + + case 100: if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Humanoid)) return true; break; - case 101: + case 101: if (GetBodyType() == BT_Dragon || GetBodyType() == BT_VeliousDragon || GetBodyType() == BT_Dragon3) return true; break; - case 102: + case 102: if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Insect)) return true; break; - case 104: + case 104: if (GetBodyType() == BT_Animal) return true; break; - case 105: + case 105: if (GetBodyType() == BT_Plant) return true; break; - case 106: + case 106: if (GetBodyType() == BT_Giant) return true; break; - case 108: + case 108: if ((GetBodyType() != BT_Animal) || (GetBodyType() != BT_Humanoid)) return true; break; - case 109: + case 109: if ((GetRace() == 520) ||(GetRace() == 79)) return true; break; - case 111: + case 111: if ((GetRace() == 527) ||(GetRace() == 11)) return true; break; - case 112: + case 112: if ((GetRace() == 456) ||(GetRace() == 28)) return true; break; - case 113: + case 113: if ((GetRace() == 456) ||(GetRace() == 48)) return true; break; - case 114: + case 114: if (GetRace() == 526) return true; break; - case 115: + case 115: if (GetRace() == 522) return true; break; - case 117: + case 117: if ((GetBodyType() == BT_Animal) || (GetBodyType() == BT_Plant)) return true; break; - case 118: + case 118: if (GetBodyType() == BT_Summoned) return true; break; - case 119: + case 119: if (IsPet() && ((GetRace() == 212) || ((GetRace() == 75) && GetTexture() == 1))) return true; break; - case 120: + case 120: if (GetBodyType() == BT_Undead) return true; break; - case 121: + case 121: if (GetBodyType() != BT_Undead) return true; break; - case 122: + case 122: if ((GetRace() == 473) || (GetRace() == 425)) return true; break; - case 123: + case 123: if (GetBodyType() == BT_Humanoid) return true; break; - case 124: + case 124: if ((GetBodyType() == BT_Undead) && (GetHPRatio() < 10)) return true; break; - case 125: + case 125: if ((GetRace() == 457 || GetRace() == 88) && (GetHPRatio() < 10)) return true; break; - case 126: + case 126: if ((GetRace() == 581 || GetRace() == 69) && (GetHPRatio() < 10)) return true; break; - case 201: + case 201: if (GetHPRatio() > 75) return true; break; - case 204: + case 204: if (GetHPRatio() < 20) return true; break; - case 216: + case 216: if (!IsEngaged()) return true; break; - case 250: + case 250: if (GetHPRatio() < 35) return true; break; - case 304: - if (IsClient() && + case 304: + if (IsClient() && ((GetClass() == WARRIOR) || (GetClass() == BARD) || (GetClass() == SHADOWKNIGHT) || (GetClass() == PALADIN) || (GetClass() == CLERIC) || (GetClass() == RANGER) || (GetClass() == SHAMAN) || (GetClass() == ROGUE) || (GetClass() == BERSERKER))) return true; break; - case 701: + case 700: + if (IsNPC()) + return true; + break; + + case 701: if (!IsPet()) return true; break; - case 818: + case 818: if (GetBodyType() == BT_Undead) return true; break; - case 819: + case 819: if (GetBodyType() != BT_Undead) return true; break; - case 842: + case 836: + return true; // todo implement progression flag assume not progression for now + + case 837: + return false; // todo implement progression flag assume not progression for now + + case 839: + return true; // todo implement progression flag assume not progression for now, this one is a check if GoD is live + + case 842: if (GetBodyType() == BT_Humanoid && GetLevel() <= 84) return true; break; - case 843: + case 843: if (GetBodyType() == BT_Humanoid && GetLevel() <= 86) return true; break; - case 844: + case 844: if (GetBodyType() == BT_Humanoid && GetLevel() <= 88) return true; break; @@ -6433,7 +6509,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama //Limit to amount of pets if (value >= 221 && value <= 249){ int count = hate_list.GetSummonedPetCountOnHateList(this); - + for (int base2_value = 221; base2_value <= 249; ++base2_value){ if (value == base2_value){ if (count >= (base2_value - 220)){ @@ -6457,12 +6533,12 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama } //End Damage if (!IsDamage || UseCastRestriction) { - + //Heal only if HP within specified range. [Doesn't follow a set forumla for all values...] if (value >= 400 && value <= 408){ for (int base2_value = 400; base2_value <= 408; ++base2_value){ if (value == base2_value){ - + if (value == 400 && GetHPRatio() <= 25) return true; @@ -6473,11 +6549,11 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama } } } - + else if (value >= 500 && value <= 549){ for (int base2_value = 500; base2_value <= 520; ++base2_value){ if (value == base2_value){ - if (GetHPRatio() < (base2_value - 500)*5) + if (GetHPRatio() < (base2_value - 500)*5) return true; } } @@ -6488,8 +6564,8 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama return true; } } // End Heal - - + + return false; } @@ -6502,18 +6578,18 @@ bool Mob::TrySpellProjectile(Mob* spell_target, uint16 spell_id, float speed){ and you lose your mana. If there is LOS the bolt will lock onto your target and the damage is applied when it hits the target. -If your target moves the bolt moves with it in any direction or angle (consistent with other projectiles). -The way this is written once a bolt is cast a the distance from the initial cast to the target repeatedly - check and if target is moving recalculates at what predicted time the bolt should hit that target in client_process + check and if target is moving recalculates at what predicted time the bolt should hit that target in client_process When bolt hits its predicted point the damage is then done to target. Note: Projectile speed of 1 takes 3 seconds to go 100 distance units. Calculations are based on this constant. - Live Bolt speed: Projectile speed of X takes 5 seconds to go 300 distance units. + Live Bolt speed: Projectile speed of X takes 5 seconds to go 300 distance units. Pending Implementation: What this code can not do is prevent damage if the bolt hits a barrier after passing the initial LOS check because the target has moved while the bolt is in motion. (it is rare to actual get this to occur on live in normal game play) */ if (!spell_target) return false; - - uint8 anim = spells[spell_id].CastingAnim; + + uint8 anim = spells[spell_id].CastingAnim; int slot = -1; //Make sure there is an avialable bolt to be cast. @@ -6526,9 +6602,9 @@ bool Mob::TrySpellProjectile(Mob* spell_target, uint16 spell_id, float speed){ if (slot < 0) return false; - + if (CheckLosFN(spell_target)) { - + float speed_mod = speed * 0.45f; //Constant for adjusting speeds to match calculated impact time. float distance = spell_target->CalculateDistance(GetX(), GetY(), GetZ()); float hit = 60.0f + (distance / speed_mod); @@ -6540,7 +6616,7 @@ bool Mob::TrySpellProjectile(Mob* spell_target, uint16 spell_id, float speed){ ProjectileAtk[slot].origin_x = GetX(); ProjectileAtk[slot].origin_y = GetY(); ProjectileAtk[slot].origin_z = GetZ(); - ProjectileAtk[slot].skill = SkillConjuration; + ProjectileAtk[slot].skill = EQEmu::skills::SkillConjuration; ProjectileAtk[slot].speed_mod = speed_mod; SetProjectileAttack(true); @@ -6551,18 +6627,18 @@ bool Mob::TrySpellProjectile(Mob* spell_target, uint16 spell_id, float speed){ ProjectileAnimation(spell_target,0, false, speed,0,0,0, spells[spell_id].player_1); } - //This allows limited support for server using older spell files that do not contain data for bolt graphics. + //This allows limited support for server using older spell files that do not contain data for bolt graphics. else { //Only use fire graphic for fire spells. if (spells[spell_id].resisttype == RESIST_FIRE) { - + if (IsClient()){ - if (CastToClient()->GetClientVersionBit() <= 4) //Titanium needs alternate graphic. + if (CastToClient()->ClientVersionBit() <= 4) //Titanium needs alternate graphic. ProjectileAnimation(spell_target,(RuleI(Spells, FRProjectileItem_Titanium)), false, speed); - else + else ProjectileAnimation(spell_target,(RuleI(Spells, FRProjectileItem_SOF)), false, speed); } - + else ProjectileAnimation(spell_target,(RuleI(Spells, FRProjectileItem_NPC)), false, speed); } @@ -6595,7 +6671,7 @@ void Mob::ResourceTap(int32 damage, uint16 spellid) if (damage > 0) HealDamage(damage); else - Damage(this, -damage, 0, SkillEvocation, false); + Damage(this, -damage, 0, EQEmu::skills::SkillEvocation, false); } if (spells[spellid].base2[i] == 1) // Mana Tap @@ -6608,7 +6684,7 @@ void Mob::ResourceTap(int32 damage, uint16 spellid) } void Mob::TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker){ - + if (damage <= 0) return; @@ -6630,16 +6706,16 @@ void Mob::TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker){ uint16 spell_id = spells[buffs[slot].spellid].base[i]; if (damage > spells[buffs[slot].spellid].base2[i]){ - + BuffFadeBySlot(slot); if (IsValidSpell(spell_id)) { - if (IsBeneficialSpell(spell_id)) - SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff); - - else if(attacker) - SpellFinished(spell_id, attacker, 10, 0, -1, spells[spell_id].ResistDiff); + if (IsBeneficialSpell(spell_id)) + SpellFinished(spell_id, this, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff); + + else if(attacker) + SpellFinished(spell_id, attacker, EQEmu::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff); } } } @@ -6710,12 +6786,76 @@ void Mob::CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster) else distance = sqrt(range); + distance = EQEmu::Clamp(distance, spells[spell_id].min_dist, spells[spell_id].max_dist); + float dm_range = spells[spell_id].max_dist - spells[spell_id].min_dist; float dm_mod_interval = spells[spell_id].max_dist_mod - spells[spell_id].min_dist_mod; - float dist_from_min = distance - spells[spell_id].min_dist; + float dist_from_min = distance - spells[spell_id].min_dist; float mod = spells[spell_id].min_dist_mod + (dist_from_min * (dm_mod_interval/dm_range)); mod *= 100.0f; - + SetSpellPowerDistanceMod(static_cast(mod)); } } + +void Mob::BreakInvisibleSpells() +{ + if(invisible) { + BuffFadeByEffect(SE_Invisibility); + BuffFadeByEffect(SE_Invisibility2); + invisible = false; + } + if(invisible_undead) { + BuffFadeByEffect(SE_InvisVsUndead); + BuffFadeByEffect(SE_InvisVsUndead2); + invisible_undead = false; + } + if(invisible_animals){ + BuffFadeByEffect(SE_InvisVsAnimals); + invisible_animals = false; + } +} + +void Client::BreakSneakWhenCastOn(Mob *caster, bool IsResisted) +{ + bool IsCastersTarget = false; // Chance to avoid only applies to AOE spells when not targeted. + if (hidden || improved_hidden) { + if (caster) { + Mob *target = nullptr; + target = caster->GetTarget(); + IsCastersTarget = target && target == this; + } + + if (!IsCastersTarget) { + int chance = + spellbonuses.NoBreakAESneak + itembonuses.NoBreakAESneak + aabonuses.NoBreakAESneak; + + if (IsResisted) + chance *= 2; + + if (chance && zone->random.Roll(chance)) + return; // Do not drop Sneak/Hide + } + + CancelSneakHide(); + } +} + +void Client::BreakFeignDeathWhenCastOn(bool IsResisted) +{ + if(GetFeigned()){ + + int chance = spellbonuses.FeignedCastOnChance + itembonuses.FeignedCastOnChance + aabonuses.FeignedCastOnChance; + + if (IsResisted) + chance *= 2; + + if(chance && (zone->random.Roll(chance))){ + Message_StringID(MT_SpellFailure,FD_CAST_ON_NO_BREAK); + return; + } + + SetFeigned(false); + Message_StringID(MT_SpellFailure,FD_CAST_ON); + } +} diff --git a/zone/spells.cpp b/zone/spells.cpp index b0ed519d9..4e79ede91 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -75,6 +75,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) #include "../common/skills.h" #include "../common/spdat.h" #include "../common/string_util.h" +#include "../common/data_verification.h" #include "quest_parser_collection.h" #include "string_ids.h" @@ -82,6 +83,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) #include #include +#include #ifndef WIN32 #include @@ -99,9 +101,11 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern WorldServer worldserver; +using EQEmu::CastingSlot; + // this is run constantly for every mob void Mob::SpellProcess() { @@ -143,12 +147,13 @@ void NPC::SpellProcess() // the rule is you can cast one triggered (usually timed) spell at a time // but things like SpellFinished() can run concurrent with a triggered cast // to allow procs to work -bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, +bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, - uint32 timer, uint32 timer_duration, uint32 type, int16 *resist_adjust) + uint32 timer, uint32 timer_duration, int16 *resist_adjust, + uint32 aa_id) { Log.Out(Logs::Detail, Logs::Spells, "CastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item slot %d", - (IsValidSpell(spell_id))?spells[spell_id].name:"UNKNOWN SPELL", spell_id, target_id, slot, cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot); + (IsValidSpell(spell_id))?spells[spell_id].name:"UNKNOWN SPELL", spell_id, target_id, static_cast(slot), cast_time, mana_cost, (item_slot==0xFFFFFFFF)?999:item_slot); if(casting_spell_id == spell_id) ZeroCastingVars(); @@ -175,7 +180,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, if(IsClient()) CastToClient()->SendSpellBarEnable(spell_id); if(casting_spell_id && IsNPC()) - CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot); + CastToNPC()->AI_Event_SpellCastFinished(false, static_cast(casting_spell_slot)); return(false); } //It appears that the Sanctuary effect is removed by a check on the client side (keep this however for redundancy) @@ -198,7 +203,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, if(IsClient()) CastToClient()->SendSpellBarEnable(spell_id); if(casting_spell_id && IsNPC()) - CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot); + CastToNPC()->AI_Event_SpellCastFinished(false, static_cast(casting_spell_slot)); return(false); } @@ -228,7 +233,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, // check for fizzle // note that CheckFizzle itself doesn't let NPCs fizzle, // but this code allows for it. - if(slot < MAX_PP_MEMSPELL && !CheckFizzle(spell_id)) + if(slot < CastingSlot::MaxGems && !CheckFizzle(spell_id)) { int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE; InterruptSpell(fizzle_msg, 0x121, spell_id); @@ -249,14 +254,14 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, } //Added to prevent MQ2 exploitation of equipping normally-unequippable/clickable items with effects and clicking them for benefits. - if(item_slot && IsClient() && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT) || (slot == TARGET_RING_SPELL_SLOT))) + if(item_slot && IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt)) { ItemInst *itm = CastToClient()->GetInv().GetItem(item_slot); int bitmask = 1; bitmask = bitmask << (CastToClient()->GetClass() - 1); if( itm && itm->GetItem()->Classes != 65535 ) { - if ((itm->GetItem()->Click.Type == ET_EquipClick) && !(itm->GetItem()->Classes & bitmask)) { - if (CastToClient()->GetClientVersion() < ClientVersion::SoF) { + if ((itm->GetItem()->Click.Type == EQEmu::item::ItemEffectEquipClick) && !(itm->GetItem()->Classes & bitmask)) { + if (CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::SoF) { // They are casting a spell from an item that requires equipping but shouldn't let them equip it Log.Out(Logs::General, Logs::Error, "HACKER: %s (account: %s) attempted to click an equip-only effect on item %s (id: %d) which they shouldn't be able to equip!", CastToClient()->GetCleanName(), CastToClient()->AccountName(), itm->GetItem()->Name, itm->GetItem()->ID); @@ -267,15 +272,15 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, } return(false); } - if ((itm->GetItem()->Click.Type == ET_ClickEffect2) && !(itm->GetItem()->Classes & bitmask)) { - if (CastToClient()->GetClientVersion() < ClientVersion::SoF) { + if ((itm->GetItem()->Click.Type == EQEmu::item::ItemEffectClick2) && !(itm->GetItem()->Classes & bitmask)) { + if (CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::SoF) { // They are casting a spell from an item that they don't meet the race/class requirements to cast Log.Out(Logs::General, Logs::Error, "HACKER: %s (account: %s) attempted to click a race/class restricted effect on item %s (id: %d) which they shouldn't be able to click!", CastToClient()->GetCleanName(), CastToClient()->AccountName(), itm->GetItem()->Name, itm->GetItem()->ID); database.SetHackerFlag(CastToClient()->AccountName(), CastToClient()->GetCleanName(), "Clicking race/class restricted item with an invalid class"); } else { - if (CastToClient()->GetClientVersion() >= ClientVersion::RoF) + if (CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { // Line 181 in eqstr_us.txt was changed in RoF+ Message(15, "Your race, class, or deity cannot use this item."); @@ -288,8 +293,8 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, return(false); } } - if( itm && (itm->GetItem()->Click.Type == ET_EquipClick) && !(item_slot <= MainAmmo || item_slot == MainPowerSource) ){ - if (CastToClient()->GetClientVersion() < ClientVersion::SoF) { + if (itm && (itm->GetItem()->Click.Type == EQEmu::item::ItemEffectEquipClick) && !(item_slot <= EQEmu::legacy::SlotAmmo || item_slot == EQEmu::legacy::SlotPowerSource)){ + if (CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::SoF) { // They are attempting to cast a must equip clicky without having it equipped Log.Out(Logs::General, Logs::Error, "HACKER: %s (account: %s) attempted to click an equip-only effect on item %s (id: %d) without equiping it!", CastToClient()->GetCleanName(), CastToClient()->AccountName(), itm->GetItem()->Name, itm->GetItem()->ID); database.SetHackerFlag(CastToClient()->AccountName(), CastToClient()->GetCleanName(), "Clicking equip-only item without equiping it"); @@ -317,11 +322,11 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, if(resist_adjust) { - return(DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, timer, timer_duration, type, *resist_adjust)); + return(DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, timer, timer_duration, *resist_adjust, aa_id)); } else { - return(DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, timer, timer_duration, type, spells[spell_id].ResistDiff)); + return(DoCastSpell(spell_id, target_id, slot, cast_time, mana_cost, oSpellWillFinish, item_slot, timer, timer_duration, spells[spell_id].ResistDiff, aa_id)); } } @@ -333,14 +338,13 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, // this is the 2nd phase of CastSpell, broken up like this to make it easier // to repeat a spell for bard songs // -bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, +bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, - uint32 item_slot, uint32 timer, uint32 timer_duration, uint32 type, - int16 resist_adjust) + uint32 item_slot, uint32 timer, uint32 timer_duration, + int16 resist_adjust, uint32 aa_id) { Mob* pMob = nullptr; int32 orgcasttime; - EQApplicationPacket *outapp = nullptr; if(!IsValidSpell(spell_id)) { InterruptSpell(); @@ -350,7 +354,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, const SPDat_Spell_Struct &spell = spells[spell_id]; Log.Out(Logs::Detail, Logs::Spells, "DoCastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item %d", - spell.name, spell_id, target_id, slot, cast_time, mana_cost, item_slot==0xFFFFFFFF?999:item_slot); + spell.name, spell_id, target_id, static_cast(slot), cast_time, mana_cost, item_slot==0xFFFFFFFF?999:item_slot); casting_spell_id = spell_id; casting_spell_slot = slot; @@ -360,7 +364,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, casting_spell_timer = timer; casting_spell_timer_duration = timer_duration; } - casting_spell_type = type; + casting_spell_aa_id = aa_id; SaveSpellLoc(); Log.Out(Logs::Detail, Logs::Spells, "Casting %d Started at (%.3f,%.3f,%.3f)", spell_id, m_SpellLocation.x, m_SpellLocation.y, m_SpellLocation.z); @@ -369,6 +373,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, // and a target wasn't provided, then it's us; unless TGB is on and this // is a TGB compatible spell. if((IsGroupSpell(spell_id) || + spell.targettype == ST_AEClientV1 || spell.targettype == ST_Self || spell.targettype == ST_AECaster || spell.targettype == ST_Ring || @@ -392,7 +397,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, // we checked for spells not requiring targets above if(target_id == 0) { - Log.Out(Logs::Detail, Logs::Spells, "Spell Error: no target. spell=%d\n", GetName(), spell_id); + Log.Out(Logs::Detail, Logs::Spells, "Spell Error: no target. spell=%d", spell_id); if(IsClient()) { //clients produce messages... npcs should not for this case Message_StringID(13, SPELL_NEED_TAR); @@ -406,24 +411,19 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, // ok now we know the target casting_spell_targetid = target_id; - if (mana_cost == -1) { + // We don't get actual mana cost here, that's done when we consume the mana + if (mana_cost == -1) mana_cost = spell.mana; - mana_cost = GetActSpellCost(spell_id, mana_cost); - } - - if(HasMGB() && spells[spell_id].can_mgb) - mana_cost *= 2; // mana is checked for clients on the frontend. we need to recheck it for NPCs though - // fix: items dont need mana :-/ // If you're at full mana, let it cast even if you dont have enough mana // we calculated this above, now enforce it - if(mana_cost > 0 && slot != 10) + if(mana_cost > 0 && slot != CastingSlot::Item) { int my_curmana = GetMana(); int my_maxmana = GetMaxMana(); - if(my_curmana < spell.mana) // not enough mana + if(my_curmana < mana_cost) // not enough mana { //this is a special case for NPCs with no mana... if(IsNPC() && my_curmana == my_maxmana) @@ -454,8 +454,26 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Casting time %d (orig %d), mana cost %d", spell_id, cast_time, orgcasttime, mana_cost); + // now tell the people in the area -- we ALWAYS want to send this, even instant cast spells. + // The only time this is skipped is for NPC innate procs and weapon procs. Procs from buffs + // oddly still send this. Since those cases don't reach here, we don't need to check them + if (slot != CastingSlot::Discipline) { + auto outapp = new EQApplicationPacket(OP_BeginCast,sizeof(BeginCast_Struct)); + BeginCast_Struct* begincast = (BeginCast_Struct*)outapp->pBuffer; + begincast->caster_id = GetID(); + begincast->spell_id = spell_id; + begincast->cast_time = orgcasttime; // client calculates reduced time by itself + outapp->priority = 3; + entity_list.QueueCloseClients(this, outapp, false, 200, 0, true); //IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS); + safe_delete(outapp); + } + // cast time is 0, just finish it right now and be done with it if(cast_time == 0) { + if (!DoCastingChecks()) { + StopCasting(); + return false; + } CastedSpellFinished(spell_id, target_id, slot, mana_cost, item_slot, resist_adjust); return(true); } @@ -477,19 +495,14 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, if (oSpellWillFinish) *oSpellWillFinish = Timer::GetCurrentTime() + cast_time + 100; - // now tell the people in the area - outapp = new EQApplicationPacket(OP_BeginCast,sizeof(BeginCast_Struct)); - BeginCast_Struct* begincast = (BeginCast_Struct*)outapp->pBuffer; - begincast->caster_id = GetID(); - begincast->spell_id = spell_id; - begincast->cast_time = orgcasttime; // client calculates reduced time by itself - outapp->priority = 3; - entity_list.QueueCloseClients(this, outapp, false, 200, 0, true); //IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS); - safe_delete(outapp); - outapp = nullptr; + if (IsClient() && slot == CastingSlot::Item && item_slot != 0xFFFFFFFF) { + auto item = CastToClient()->GetInv().GetItem(item_slot); + if (item && item->GetItem()) + Message_StringID(MT_Spells, BEGINS_TO_GLOW, item->GetItem()->Name); + } if (!DoCastingChecks()) { - InterruptSpell(); + StopCasting(); return false; } @@ -545,22 +558,26 @@ bool Mob::DoCastingChecks() } } + if (IsClient() && spells[spell_id].EndurTimerIndex > 0 && casting_spell_slot < CastingSlot::MaxGems) + if (!CastToClient()->IsLinkedSpellReuseTimerReady(spells[spell_id].EndurTimerIndex)) + return false; + casting_spell_checks = true; return true; } uint16 Mob::GetSpecializeSkillValue(uint16 spell_id) const { switch(spells[spell_id].skill) { - case SkillAbjuration: - return(GetSkill(SkillSpecializeAbjure)); - case SkillAlteration: - return(GetSkill(SkillSpecializeAlteration)); - case SkillConjuration: - return(GetSkill(SkillSpecializeConjuration)); - case SkillDivination: - return(GetSkill(SkillSpecializeDivination)); - case SkillEvocation: - return(GetSkill(SkillSpecializeEvocation)); + case EQEmu::skills::SkillAbjuration: + return(GetSkill(EQEmu::skills::SkillSpecializeAbjure)); + case EQEmu::skills::SkillAlteration: + return(GetSkill(EQEmu::skills::SkillSpecializeAlteration)); + case EQEmu::skills::SkillConjuration: + return(GetSkill(EQEmu::skills::SkillSpecializeConjuration)); + case EQEmu::skills::SkillDivination: + return(GetSkill(EQEmu::skills::SkillSpecializeDivination)); + case EQEmu::skills::SkillEvocation: + return(GetSkill(EQEmu::skills::SkillSpecializeEvocation)); default: //wtf... break; @@ -579,20 +596,20 @@ void Client::CheckSpecializeIncrease(uint16 spell_id) { */ switch(spells[spell_id].skill) { - case SkillAbjuration: - CheckIncreaseSkill(SkillSpecializeAbjure, nullptr); + case EQEmu::skills::SkillAbjuration: + CheckIncreaseSkill(EQEmu::skills::SkillSpecializeAbjure, nullptr); break; - case SkillAlteration: - CheckIncreaseSkill(SkillSpecializeAlteration, nullptr); + case EQEmu::skills::SkillAlteration: + CheckIncreaseSkill(EQEmu::skills::SkillSpecializeAlteration, nullptr); break; - case SkillConjuration: - CheckIncreaseSkill(SkillSpecializeConjuration, nullptr); + case EQEmu::skills::SkillConjuration: + CheckIncreaseSkill(EQEmu::skills::SkillSpecializeConjuration, nullptr); break; - case SkillDivination: - CheckIncreaseSkill(SkillSpecializeDivination, nullptr); + case EQEmu::skills::SkillDivination: + CheckIncreaseSkill(EQEmu::skills::SkillSpecializeDivination, nullptr); break; - case SkillEvocation: - CheckIncreaseSkill(SkillSpecializeEvocation, nullptr); + case EQEmu::skills::SkillEvocation: + CheckIncreaseSkill(EQEmu::skills::SkillSpecializeEvocation, nullptr); break; default: //wtf... @@ -612,48 +629,48 @@ void Client::CheckSongSkillIncrease(uint16 spell_id){ switch(spells[spell_id].skill) { - case SkillSinging: - CheckIncreaseSkill(SkillSinging, nullptr, -15); + case EQEmu::skills::SkillSinging: + CheckIncreaseSkill(EQEmu::skills::SkillSinging, nullptr, -15); break; - case SkillPercussionInstruments: + case EQEmu::skills::SkillPercussionInstruments: if(this->itembonuses.percussionMod > 0) { - if(GetRawSkill(SkillPercussionInstruments) > 0) // no skill increases if not trained in the instrument - CheckIncreaseSkill(SkillPercussionInstruments, nullptr, -15); + if (GetRawSkill(EQEmu::skills::SkillPercussionInstruments) > 0) // no skill increases if not trained in the instrument + CheckIncreaseSkill(EQEmu::skills::SkillPercussionInstruments, nullptr, -15); else Message_StringID(13,NO_INSTRUMENT_SKILL); // tell the client that they need instrument training } else - CheckIncreaseSkill(SkillSinging, nullptr, -15); + CheckIncreaseSkill(EQEmu::skills::SkillSinging, nullptr, -15); break; - case SkillStringedInstruments: + case EQEmu::skills::SkillStringedInstruments: if(this->itembonuses.stringedMod > 0) { - if(GetRawSkill(SkillStringedInstruments) > 0) - CheckIncreaseSkill(SkillStringedInstruments, nullptr, -15); + if (GetRawSkill(EQEmu::skills::SkillStringedInstruments) > 0) + CheckIncreaseSkill(EQEmu::skills::SkillStringedInstruments, nullptr, -15); else Message_StringID(13,NO_INSTRUMENT_SKILL); } else - CheckIncreaseSkill(SkillSinging, nullptr, -15); + CheckIncreaseSkill(EQEmu::skills::SkillSinging, nullptr, -15); break; - case SkillWindInstruments: + case EQEmu::skills::SkillWindInstruments: if(this->itembonuses.windMod > 0) { - if(GetRawSkill(SkillWindInstruments) > 0) - CheckIncreaseSkill(SkillWindInstruments, nullptr, -15); + if (GetRawSkill(EQEmu::skills::SkillWindInstruments) > 0) + CheckIncreaseSkill(EQEmu::skills::SkillWindInstruments, nullptr, -15); else Message_StringID(13,NO_INSTRUMENT_SKILL); } else - CheckIncreaseSkill(SkillSinging, nullptr, -15); + CheckIncreaseSkill(EQEmu::skills::SkillSinging, nullptr, -15); break; - case SkillBrassInstruments: + case EQEmu::skills::SkillBrassInstruments: if(this->itembonuses.brassMod > 0) { - if(GetRawSkill(SkillBrassInstruments) > 0) - CheckIncreaseSkill(SkillBrassInstruments, nullptr, -15); + if (GetRawSkill(EQEmu::skills::SkillBrassInstruments) > 0) + CheckIncreaseSkill(EQEmu::skills::SkillBrassInstruments, nullptr, -15); else Message_StringID(13,NO_INSTRUMENT_SKILL); } else - CheckIncreaseSkill(SkillSinging, nullptr, -15); + CheckIncreaseSkill(EQEmu::skills::SkillSinging, nullptr, -15); break; default: break; @@ -746,14 +763,6 @@ bool Client::CheckFizzle(uint16 spell_id) // always at least 1% chance to fail or 5% to succeed fizzlechance = fizzlechance < 1 ? 1 : (fizzlechance > 95 ? 95 : fizzlechance); - /* - if(IsBardSong(spell_id)) - { - //This was a channel chance modifier - no evidence for fizzle reduction - fizzlechance -= GetAA(aaInternalMetronome) * 1.5f; - } - */ - float fizzle_roll = zone->random.Real(0, 100); Log.Out(Logs::Detail, Logs::Spells, "Check Fizzle %s spell %d fizzlechance: %0.2f%% diff: %0.2f roll: %0.2f", GetName(), spell_id, fizzlechance, diff, fizzle_roll); @@ -770,14 +779,14 @@ void Mob::ZeroCastingVars() spellend_timer.Disable(); casting_spell_id = 0; casting_spell_targetid = 0; - casting_spell_slot = 0; + casting_spell_slot = CastingSlot::Gem1; casting_spell_mana = 0; casting_spell_inventory_slot = 0; casting_spell_timer = 0; casting_spell_timer_duration = 0; - casting_spell_type = 0; casting_spell_resist_adjust = 0; casting_spell_checks = false; + casting_spell_aa_id = 0; delaytimer = false; } @@ -805,13 +814,12 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid) } if(casting_spell_id && IsNPC()) { - CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot); + CastToNPC()->AI_Event_SpellCastFinished(false, static_cast(casting_spell_slot)); } - if(casting_spell_type == 1 && IsClient()) { //Rest AA Timer on failed cast - CastToClient()->SendAATimer(casting_spell_timer - pTimerAAStart, 0, 0xFFFFFF); - CastToClient()->Message_StringID(15,ABILITY_FAILED); - CastToClient()->GetPTimers().Clear(&database, casting_spell_timer); + if(casting_spell_aa_id && IsClient()) { //Rest AA Timer on failed cast + CastToClient()->Message_StringID(MT_SpellFailure, ABILITY_FAILED); + CastToClient()->ResetAlternateAdvancementTimer(casting_spell_aa_id); } ZeroCastingVars(); // resets all the state keeping stuff @@ -878,18 +886,44 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid) } +// this is like interrupt, just it doesn't spam interrupt packets to everyone +// There are a few cases where this is what live does :P +void Mob::StopCasting() +{ + if (casting_spell_id && IsNPC()) { + CastToNPC()->AI_Event_SpellCastFinished(false, static_cast(casting_spell_slot)); + } + + if (IsClient()) { + auto c = CastToClient(); + if (casting_spell_aa_id) { //Rest AA Timer on failed cast + c->Message_StringID(MT_SpellFailure, ABILITY_FAILED); + c->ResetAlternateAdvancementTimer(casting_spell_aa_id); + } + + auto outapp = new EQApplicationPacket(OP_ManaChange, sizeof(ManaChange_Struct)); + auto mc = (ManaChange_Struct *)outapp->pBuffer; + mc->new_mana = GetMana(); + mc->stamina = GetEndurance(); + mc->spell_id = casting_spell_id; + mc->keepcasting = 0; + c->FastQueuePacket(&outapp); + } + ZeroCastingVars(); +} + // this is called after the timer is up and the spell is finished // casting. everything goes through here, including items with zero cast time // only to be used from SpellProcess // NOTE: do not put range checking, etc into this function. this should // just check timed spell specific things before passing off to SpellFinished // which figures out proper targets etc -void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, +void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slot, uint16 mana_used, uint32 inventory_slot, int16 resist_adjust) { bool IsFromItem = false; - if(IsClient() && slot != USE_ITEM_SPELL_SLOT && slot != POTION_BELT_SPELL_SLOT && slot != TARGET_RING_SPELL_SLOT && spells[spell_id].recast_time > 1000) { // 10 is item + if(IsClient() && slot != CastingSlot::Item && slot != CastingSlot::PotionBelt && spells[spell_id].recast_time > 1000) { // 10 is item if(!CastToClient()->GetPTimers().Expired(&database, pTimerSpellStart + spell_id, false)) { //should we issue a message or send them a spell gem packet? Message_StringID(13, SPELL_RECAST); @@ -899,7 +933,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } } - if(IsClient() && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT) || (slot == TARGET_RING_SPELL_SLOT))) + if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt)) { IsFromItem = true; ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot); @@ -995,7 +1029,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, channelbonuses += spellbonuses.ChannelChanceSpells + itembonuses.ChannelChanceSpells + aabonuses.ChannelChanceSpells; // max 93% chance at 252 skill - channelchance = 30 + GetSkill(SkillChanneling) / 400.0f * 100; + channelchance = 30 + GetSkill(EQEmu::skills::SkillChanneling) / 400.0f * 100; channelchance -= attacked_count * 2; channelchance += channelchance * channelbonuses / 100.0f; } @@ -1009,7 +1043,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, channelbonuses += spellbonuses.ChannelChanceSpells + itembonuses.ChannelChanceSpells + aabonuses.ChannelChanceSpells; // max 93% chance at 252 skill - channelchance = 30 + GetSkill(SkillChanneling) / 400.0f * 100; + channelchance = 30 + GetSkill(EQEmu::skills::SkillChanneling) / 400.0f * 100; channelchance -= attacked_count * 2; channelchance += channelchance * channelbonuses / 100.0f; } @@ -1041,7 +1075,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } } - Log.Out(Logs::Detail, Logs::Spells, "Checking Interruption: spell x: %f spell y: %f cur x: %f cur y: %f channelchance %f channeling skill %d\n", GetSpellX(), GetSpellY(), GetX(), GetY(), channelchance, GetSkill(SkillChanneling)); + Log.Out(Logs::Detail, Logs::Spells, "Checking Interruption: spell x: %f spell y: %f cur x: %f cur y: %f channelchance %f channeling skill %d\n", GetSpellX(), GetSpellY(), GetX(), GetY(), channelchance, GetSkill(EQEmu::skills::SkillChanneling)); if(!spells[spell_id].uninterruptable && zone->random.Real(0, 100) > channelchance) { Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: interrupted.", spell_id); @@ -1140,7 +1174,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, missingreags=true; } - const Item_Struct *item = database.GetItem(component); + const EQEmu::ItemBase *item = database.GetItem(component); if(item) { c->Message_StringID(13, MISSING_SPELL_COMP_ITEM, item->Name); Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Canceled. Missing required reagent %s (%d)", spell_id, item->Name, component); @@ -1164,12 +1198,14 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } else if (!bard_song_mode) { + int noexpend; for(int t_count = 0; t_count < 4; t_count++) { component = spells[spell_id].components[t_count]; - if (component == -1) + noexpend = spells[spell_id].NoexpendReagent[t_count]; + if (component == -1 || noexpend == component) continue; component_count = spells[spell_id].component_counts[t_count]; - Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Consuming %d of spell component item id %d", spell_id, component, component_count); + Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Consuming %d of spell component item id %d", spell_id, component_count, component); // Components found, Deleting // now we go looking for and deleting the items one by one for(int s = 0; s < component_count; s++) @@ -1195,12 +1231,12 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, int16 DeleteChargeFromSlot = -1; - if(IsClient() && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT) || (slot == TARGET_RING_SPELL_SLOT)) + if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt) && inventory_slot != 0xFFFFFFFF) // 10 is an item { bool fromaug = false; const ItemInst* inst = CastToClient()->GetInv()[inventory_slot]; - Item_Struct* augitem = 0; + EQEmu::ItemBase* augitem = 0; uint32 recastdelay = 0; uint32 recasttype = 0; @@ -1208,12 +1244,12 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, if (inst == nullptr) break; - for (int r = AUG_BEGIN; r < EmuConstants::ITEM_COMMON_SIZE; r++) { + for (int r = AUG_INDEX_BEGIN; r < EQEmu::legacy::ITEM_COMMON_SIZE; r++) { const ItemInst* aug_i = inst->GetAugment(r); if (!aug_i) continue; - const Item_Struct* aug = aug_i->GetItem(); + const EQEmu::ItemBase* aug = aug_i->GetItem(); if (!aug) continue; @@ -1247,9 +1283,9 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } } - if (inst && inst->IsType(ItemClassCommon) && (inst->GetItem()->Click.Effect == spell_id) && inst->GetCharges() || fromaug) + if (inst && inst->IsClassCommon() && (inst->GetItem()->Click.Effect == spell_id) && inst->GetCharges() || fromaug) { - //const Item_Struct* item = inst->GetItem(); + //const ItemBase* item = inst->GetItem(); int16 charges = inst->GetItem()->MaxCharges; if(fromaug) { charges = -1; } //Don't destroy the parent item @@ -1270,6 +1306,14 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } } + // we're done casting, now try to apply the spell + if( !SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust) ) + { + Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: SpellFinished returned false.", spell_id); + InterruptSpell(); + return; + } + if(IsClient()) { CheckNumHitsRemaining(NumHit::MatchingSpells); TrySympatheticProc(target, spell_id); @@ -1279,14 +1323,6 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, TryTriggerOnCast(spell_id, 0); - // we're done casting, now try to apply the spell - if( !SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust) ) - { - Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: SpellFinished returned false.", spell_id); - InterruptSpell(); - return; - } - if(DeleteChargeFromSlot >= 0) CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true); @@ -1308,8 +1344,11 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, { if(IsClient()) { - this->CastToClient()->CheckSongSkillIncrease(spell_id); - this->CastToClient()->MemorizeSpell(slot, spell_id, memSpellSpellbar); + Client *c = CastToClient(); + c->CheckSongSkillIncrease(spell_id); + if (spells[spell_id].EndurTimerIndex > 0 && slot < CastingSlot::MaxGems) + c->SetLinkedSpellReuseTimer(spells[spell_id].EndurTimerIndex, spells[spell_id].recast_time / 1000); + c->MemorizeSpell(static_cast(slot), spell_id, memSpellSpellbar); } Log.Out(Logs::Detail, Logs::Spells, "Bard song %d should be started", spell_id); } @@ -1321,18 +1360,19 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, SendSpellBarEnable(spell_id); // this causes the delayed refresh of the spell bar gems - c->MemorizeSpell(slot, spell_id, memSpellSpellbar); + if (spells[spell_id].EndurTimerIndex > 0 && slot < CastingSlot::MaxGems) + c->SetLinkedSpellReuseTimer(spells[spell_id].EndurTimerIndex, spells[spell_id].recast_time / 1000); + c->MemorizeSpell(static_cast(slot), spell_id, memSpellSpellbar); // this tells the client that casting may happen again SetMana(GetMana()); // skills - if(slot < MAX_PP_MEMSPELL) - { + if (EQEmu::skills::IsCastingSkill(spells[spell_id].skill)) { c->CheckIncreaseSkill(spells[spell_id].skill, nullptr); // increased chance of gaining channel skill if you regained concentration - c->CheckIncreaseSkill(SkillChanneling, nullptr, regain_conc ? 5 : 0); + c->CheckIncreaseSkill(EQEmu::skills::SkillChanneling, nullptr, regain_conc ? 5 : 0); c->CheckSpecializeIncrease(spell_id); } @@ -1350,8 +1390,8 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } -bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction) { - +bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, CastingSlot slot, bool isproc) +{ /* The basic types of spells: @@ -1397,53 +1437,58 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce targetType = ST_GroupClientAndPet; } + // NPC innate procs override the target type to single target. + // Yes. This code will cause issues if they have the proc as innate AND on a weapon. Oh well. + if (isproc && IsNPC() && CastToNPC()->GetInnateProcSpellID() == spell_id) + targetType = ST_Target; + if (spell_target && !spell_target->PassCastRestriction(true, spells[spell_id].CastRestriction)){ Message_StringID(13,SPELL_NEED_TAR); return false; } //Must be out of combat. (If Beneficial checks casters combat state, Deterimental checks targets) - if (!spells[spell_id].InCombat && spells[spell_id].OutofCombat){ + if (!spells[spell_id].InCombat && spells[spell_id].OutofCombat) { if (IsDetrimentalSpell(spell_id)) { - if ( (spell_target->IsNPC() && spell_target->IsEngaged()) || - (spell_target->IsClient() && spell_target->CastToClient()->GetAggroCount())){ - Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string - return false; + if (spell_target && + ((spell_target->IsNPC() && spell_target->IsEngaged()) || + (spell_target->IsClient() && spell_target->CastToClient()->GetAggroCount()))) { + Message_StringID(13, SPELL_NO_EFFECT); // Unsure correct string + return false; } } else if (IsBeneficialSpell(spell_id)) { - if ( (IsNPC() && IsEngaged()) || - (IsClient() && CastToClient()->GetAggroCount())){ - if (IsDiscipline(spell_id)) - Message_StringID(13,NO_ABILITY_IN_COMBAT); - else - Message_StringID(13,NO_CAST_IN_COMBAT); + if ((IsNPC() && IsEngaged()) || (IsClient() && CastToClient()->GetAggroCount())) { + if (IsDiscipline(spell_id)) + Message_StringID(13, NO_ABILITY_IN_COMBAT); + else + Message_StringID(13, NO_CAST_IN_COMBAT); - return false; + return false; } } } - //Must be in combat. (If Beneficial checks casters combat state, Deterimental checks targets) - else if (spells[spell_id].InCombat && !spells[spell_id].OutofCombat){ + // Must be in combat. (If Beneficial checks casters combat state, Deterimental checks targets) + else if (spells[spell_id].InCombat && !spells[spell_id].OutofCombat) { if (IsDetrimentalSpell(spell_id)) { - if ( (spell_target->IsNPC() && !spell_target->IsEngaged()) || - (spell_target->IsClient() && !spell_target->CastToClient()->GetAggroCount())){ - Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string - return false; + if (spell_target && + ((spell_target->IsNPC() && !spell_target->IsEngaged()) || + (spell_target->IsClient() && !spell_target->CastToClient()->GetAggroCount()))) { + Message_StringID(13, SPELL_NO_EFFECT); // Unsure correct string + return false; } } else if (IsBeneficialSpell(spell_id)) { - if ( (IsNPC() && !IsEngaged()) || - (IsClient() && !CastToClient()->GetAggroCount())){ - if (IsDiscipline(spell_id)) - Message_StringID(13,NO_ABILITY_OUT_OF_COMBAT); - else - Message_StringID(13,NO_CAST_OUT_OF_COMBAT); + if ((IsNPC() && !IsEngaged()) || (IsClient() && !CastToClient()->GetAggroCount())) { + if (IsDiscipline(spell_id)) + Message_StringID(13, NO_ABILITY_OUT_OF_COMBAT); + else + Message_StringID(13, NO_CAST_OUT_OF_COMBAT); - return false; + return false; } } } @@ -1477,7 +1522,10 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce { //invalid target Log.Out(Logs::Detail, Logs::Spells, "Spell %d canceled: invalid target of body type %d (undead)", spell_id, mob_body); - Message_StringID(13,SPELL_NEED_TAR); + if(!spell_target) + Message_StringID(13,SPELL_NEED_TAR); + else + Message_StringID(13,CANNOT_AFFECT_NPC); return false; } CastAction = SingleTarget; @@ -1606,6 +1654,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce case ST_AEBard: case ST_AECaster: + case ST_AEClientV1: { spell_target = nullptr; ae_center = this; @@ -1680,7 +1729,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce case ST_Group: case ST_GroupNoPets: { - if(IsClient() && CastToClient()->TGB() && IsTGBCompatibleSpell(spell_id)) { + if(IsClient() && CastToClient()->TGB() && IsTGBCompatibleSpell(spell_id) && (slot != CastingSlot::Item || RuleB(Spells, AllowItemTGB))) { if( (!target) || (target->IsNPC() && !(target->GetOwner() && target->GetOwner()->IsClient())) || (target->IsCorpse()) ) @@ -1726,11 +1775,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce { if(IsGrouped()) { - group_id_caster = GetGroup()->GetID(); + if (Group* group = GetGroup()) { + group_id_caster = group->GetID(); + } } else if(IsRaidGrouped()) { - group_id_caster = (GetRaid()->GetGroup(CastToClient()) == 0xFFFF) ? 0 : (GetRaid()->GetGroup(CastToClient()) + 1); + if (Raid* raid = GetRaid()) { + uint32 group_id = raid->GetGroup(CastToClient()); + group_id_caster = (group_id == 0xFFFFFFFF) ? 0 : (group_id + 1); + } } } else if(IsPet()) @@ -1738,11 +1792,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce Mob *owner = GetOwner(); if(owner->IsGrouped()) { - group_id_caster = owner->GetGroup()->GetID(); + if (Group* group = owner->GetGroup()) { + group_id_caster = group->GetID(); + } } else if(owner->IsRaidGrouped()) { - group_id_caster = (owner->GetRaid()->GetGroup(CastToClient()) == 0xFFFF) ? 0 : (owner->GetRaid()->GetGroup(CastToClient()) + 1); + if (Raid* raid = owner->GetRaid()) { + uint32 group_id = raid->GetGroup(owner->CastToClient()); + group_id_caster = (group_id == 0xFFFFFFFF) ? 0 : (group_id + 1); + } } } #ifdef BOTS @@ -1764,11 +1823,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce { if(spell_target->IsGrouped()) { - group_id_target = spell_target->GetGroup()->GetID(); + if (Group* group = spell_target->GetGroup()) { + group_id_target = group->GetID(); + } } else if(spell_target->IsRaidGrouped()) { - group_id_target = (spell_target->GetRaid()->GetGroup(CastToClient()) == 0xFFFF) ? 0 : (spell_target->GetRaid()->GetGroup(CastToClient()) + 1); + if (Raid* raid = spell_target->GetRaid()) { + uint32 group_id = raid->GetGroup(spell_target->CastToClient()); + group_id_target = (group_id == 0xFFFFFFFF) ? 0 : (group_id + 1); + } } } else if(spell_target->IsPet()) @@ -1776,11 +1840,16 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce Mob *owner = spell_target->GetOwner(); if(owner->IsGrouped()) { - group_id_target = owner->GetGroup()->GetID(); + if (Group* group = owner->GetGroup()) { + group_id_target = group->GetID(); + } } else if(owner->IsRaidGrouped()) { - group_id_target = (owner->GetRaid()->GetGroup(CastToClient()) == 0xFFFF) ? 0 : (owner->GetRaid()->GetGroup(CastToClient()) + 1); + if (Raid* raid = owner->GetRaid()) { + uint32 group_id = raid->GetGroup(owner->CastToClient()); + group_id_target = (group_id == 0xFFFFFFFF) ? 0 : (group_id + 1); + } } } #ifdef BOTS @@ -1890,8 +1959,8 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce // only used from CastedSpellFinished, and procs // we can't interrupt in this, or anything called from this! // if you need to abort the casting, return false -bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 mana_used, - uint32 inventory_slot, int16 resist_adjust, bool isproc) +bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, uint16 mana_used, + uint32 inventory_slot, int16 resist_adjust, bool isproc, int level_override) { //EQApplicationPacket *outapp = nullptr; Mob *ae_center = nullptr; @@ -1933,6 +2002,12 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } } + if (IsClient() && CastToClient()->GetGM()){ + if (zone->IsSpellBlocked(spell_id, glm::vec3(GetPosition()))){ + Log.Out(Logs::Detail, Logs::Spells, "GM Cast Blocked Spell: %s (ID %i)", GetSpellName(spell_id), spell_id); + } + } + if ( this->IsClient() && @@ -1954,7 +2029,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 //determine the type of spell target we have CastAction_type CastAction; - if(!DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction)) + if(!DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction, slot, isproc)) return(false); Log.Out(Logs::Detail, Logs::Spells, "Spell %d: target type %d, target %s, AE center %s", spell_id, CastAction, spell_target?spell_target->GetName():"NONE", ae_center?ae_center->GetName():"NONE"); @@ -1966,7 +2041,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 if(IsAEDurationSpell(spell_id)) { // the spells are AE target, but we aim them on a beacon Mob *beacon_loc = spell_target ? spell_target : this; - Beacon *beacon = new Beacon(beacon_loc, spells[spell_id].AEDuration); + auto beacon = new Beacon(beacon_loc, spells[spell_id].AEDuration); entity_list.AddBeacon(beacon); Log.Out(Logs::Detail, Logs::Spells, "Spell %d: AE duration beacon created, entity id %d", spell_id, beacon->GetName()); spell_target = nullptr; @@ -1991,7 +2066,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } //range check our target, if we have one and it is not us - float range = spells[spell_id].range; + float range = spells[spell_id].range + GetRangeDistTargetSizeMod(spell_target); if(IsClient() && CastToClient()->TGB() && IsTGBCompatibleSpell(spell_id) && IsGroupSpell(spell_id)) range = spells[spell_id].aoerange; @@ -2048,17 +2123,17 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 return(false); } if (isproc) { - SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, true); + SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, true, level_override); } else { if (spells[spell_id].targettype == ST_TargetOptional){ if (!TrySpellProjectile(spell_target, spell_id)) return false; } - else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false)) { + else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false, level_override)) { if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) { // Prevent mana usage/timers being set for beneficial buffs - if(casting_spell_type == 1) + if(casting_spell_aa_id) InterruptSpell(); return false; } @@ -2137,11 +2212,11 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } #endif //BOTS + // We hold off turning MBG off so we can still use it to calc the mana cost if(spells[spell_id].can_mgb && HasMGB()) { SpellOnTarget(spell_id, this); entity_list.MassGroupBuff(this, this, spell_id, true); - SetMGB(false); } else { @@ -2149,15 +2224,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 // caster if they're not using TGB // NOTE: this will always hit the caster, plus the target's group so // it can affect up to 7 people if the targeted group is not our own - + // Allow pets who cast group spells to affect the group. - if (spell_target->IsPetOwnerClient()){ + if (spell_target->IsPetOwnerClient() && IsPetOwnerClient()){ Mob* owner = spell_target->GetOwner(); if (owner) spell_target = owner; } - + if(spell_target->IsGrouped()) { Group *target_group = entity_list.GetGroupByMob(spell_target); @@ -2241,21 +2316,49 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } } + bool mgb = HasMGB() && spells[spell_id].can_mgb; // if this was a spell slot or an ability use up the mana for it - // CastSpell already reduced the cost for it if we're a client with focus - if(slot != USE_ITEM_SPELL_SLOT && slot != POTION_BELT_SPELL_SLOT && slot != TARGET_RING_SPELL_SLOT && mana_used > 0) + if(slot != CastingSlot::Item && slot != CastingSlot::PotionBelt && mana_used > 0) { + mana_used = GetActSpellCost(spell_id, mana_used); + if (mgb) { + mana_used *= 2; + } + // clamp if we some how got focused above our current mana + if (GetMana() < mana_used) + mana_used = GetMana(); Log.Out(Logs::Detail, Logs::Spells, "Spell %d: consuming %d mana", spell_id, mana_used); - if (!DoHPToManaCovert(mana_used)) + if (!DoHPToManaCovert(mana_used)) { SetMana(GetMana() - mana_used); TryTriggerOnValueAmount(false, true); + } } + // one may want to check if this is a disc or not, but we actually don't, there are non disc stuff that have end cost + // lets not consume end for custom items that have disc procs. + // One might also want to filter out USE_ITEM_SPELL_SLOT, but DISCIPLINE_SPELL_SLOT are both #defined to the same thing ... + if (spells[spell_id].EndurCost && !isproc) { + auto end_cost = spells[spell_id].EndurCost; + if (mgb) + end_cost *= 2; + SetEndurance(GetEndurance() - EQEmu::ClampUpper(end_cost, GetEndurance())); + TryTriggerOnValueAmount(false, false, true); + } + if (mgb) + SetMGB(false); //set our reuse timer on long ass reuse_time spells... - if(IsClient()) + if(IsClient() && !isproc) { - if(spell_id == casting_spell_id && casting_spell_timer != 0xFFFFFFFF) + if(casting_spell_aa_id) { + AA::Rank *rank = zone->GetAlternateAdvancementRank(casting_spell_aa_id); + + if(rank && rank->base_ability) { + ExpendAlternateAdvancementCharge(rank->base_ability->id); + } + } + else if(spell_id == casting_spell_id && casting_spell_timer != 0xFFFFFFFF) { + //aa new todo: aa expendable charges here CastToClient()->GetPTimers().Start(casting_spell_timer, casting_spell_timer_duration); Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Setting custom reuse timer %d to %d", spell_id, casting_spell_timer, casting_spell_timer_duration); } @@ -2278,7 +2381,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } } - if(IsClient() && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT) || (slot == TARGET_RING_SPELL_SLOT))) + if(IsClient() && (slot == CastingSlot::Item || slot == CastingSlot::PotionBelt)) { ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot); if(itm && itm->GetItem()->RecastDelay > 0){ @@ -2287,7 +2390,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 database.UpdateItemRecastTimestamps( CastToClient()->CharacterID(), recast_type, CastToClient()->GetPTimers().Get(pTimerItemStart + recast_type)->GetReadyTimestamp()); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct)); + auto outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct)); ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer; ird->recast_delay = itm->GetItem()->RecastDelay; ird->recast_type = recast_type; @@ -2297,7 +2400,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } if(IsNPC()) - CastToNPC()->AI_Event_SpellCastFinished(true, slot); + CastToNPC()->AI_Event_SpellCastFinished(true, static_cast(slot)); return true; } @@ -2312,8 +2415,8 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 * * return false to stop the song */ -bool Mob::ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, uint16 slot) { - if(slot == USE_ITEM_SPELL_SLOT) { +bool Mob::ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, CastingSlot slot) { + if(slot == CastingSlot::Item) { //bard songs should never come from items... Log.Out(Logs::Detail, Logs::Spells, "Bard Song Pulse %d: Supposidly cast from an item. Killing song.", spell_id); return(false); @@ -2322,7 +2425,7 @@ bool Mob::ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, uint16 slot) { //determine the type of spell target we have Mob *ae_center = nullptr; CastAction_type CastAction; - if(!DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction)) { + if(!DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction, slot)) { Log.Out(Logs::Detail, Logs::Spells, "Bard Song Pulse %d: was unable to determine target. Stopping.", spell_id); return(false); } @@ -2482,7 +2585,7 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) { //be a lot of traffic for no reason... //this may be the wrong packet... if(IsClient()) { - EQApplicationPacket *packet = new EQApplicationPacket(OP_Action, sizeof(Action_Struct)); + auto packet = new EQApplicationPacket(OP_Action, sizeof(Action_Struct)); Action_Struct* action = (Action_Struct*) packet->pBuffer; action->source = caster->GetID(); @@ -2510,7 +2613,8 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) { CastToClient()->SetKnockBackExemption(true); action->buff_unknown = 0; - EQApplicationPacket* outapp_push = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + 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()); @@ -2554,13 +2658,13 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) { CastToClient()->QueuePacket(packet); } - EQApplicationPacket *message_packet = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); + auto message_packet = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); CombatDamage_Struct *cd = (CombatDamage_Struct *)message_packet->pBuffer; cd->target = action->target; cd->source = action->source; cd->type = DamageTypeSpell; cd->spellid = action->spell; - cd->sequence = action->sequence; + cd->meleepush_xy = action->sequence; cd->damage = 0; if(!IsEffectInSpell(spell_id, SE_BindAffinity)) { @@ -2612,84 +2716,85 @@ int Mob::CalcBuffDuration(Mob *caster, Mob *target, uint16 spell_id, int32 caste castlevel = caster_level_override; int res = CalcBuffDuration_formula(castlevel, formula, duration); + if (caster == target && (target->aabonuses.IllusionPersistence || target->spellbonuses.IllusionPersistence || + target->itembonuses.IllusionPersistence) && + spell_id != 287 && spell_id != 601 && IsEffectInSpell(spell_id, SE_Illusion)) + res = 10000; // ~16h override res = mod_buff_duration(res, caster, target, spell_id); Log.Out(Logs::Detail, Logs::Spells, "Spell %d: Casting level %d, formula %d, base_duration %d: result %d", spell_id, castlevel, formula, duration, res); - return(res); + return res; } // the generic formula calculations int CalcBuffDuration_formula(int level, int formula, int duration) { - int i; // temp variable + int temp; - switch(formula) - { - case 0: // not a buff - return 0; - - case 1: - i = (int)ceil(level / 2.0f); - return i < duration ? (i < 1 ? 1 : i) : duration; - - case 2: - i = (int)ceil(duration / 5.0f * 3); - return i < duration ? (i < 1 ? 1 : i) : duration; - - case 3: - i = level * 30; - return i < duration ? (i < 1 ? 1 : i) : duration; - - case 4: // only used by 'LowerElement' - return ((duration != 0) ? duration : 50); - - case 5: - i = duration; - // 0 value results in a 3 tick spell, else its between 1-3 ticks. - return i < 3 ? (i < 1 ? 3 : i) : 3; - - case 6: - i = (int)ceil(level / 2.0f); - return i < duration ? (i < 1 ? 1 : i) : duration; - - case 7: - i = level; - return (duration == 0) ? (i < 1 ? 1 : i) : duration; - - case 8: - i = level + 10; - return i < duration ? (i < 1 ? 1 : i) : duration; - - case 9: - i = level * 2 + 10; - return i < duration ? (i < 1 ? 1 : i) : duration; - - case 10: - i = level * 3 + 10; - return i < duration ? (i < 1 ? 1 : i) : duration; - - case 11: - return duration; - - case 12: - return duration; - - case 15: // Don't know what the real formula for this should be. Used by Skinspikes potion. - return duration; - - case 50: // lucy says this is unlimited? - return 72000; // 5 days - - case 3600: - return duration ? duration : 3600; - - default: - Log.Out(Logs::General, Logs::None, "CalcBuffDuration_formula: unknown formula %d", formula); + switch (formula) { + case 1: + temp = level > 3 ? level / 2 : 1; + break; + case 2: + temp = level > 3 ? level / 2 + 5 : 6; + break; + case 3: + temp = 30 * level; + break; + case 4: // only used by 'LowerElement' + temp = 50; + break; + case 5: + temp = 2; + break; + case 6: + temp = level / 2 + 2; + break; + case 7: + temp = level; + break; + case 8: + temp = level + 10; + break; + case 9: + temp = 2 * level + 10; + break; + case 10: + temp = 3 * level + 10; + break; + case 11: + temp = 30 * (level + 3); + break; + case 12: + temp = level > 7 ? level / 4 : 1; + break; + case 13: + temp = 4 * level + 10; + break; + case 14: + temp = 5 * (level + 2); + break; + case 15: + temp = 10 * (level + 10); + break; + case 50: // Permanent. Cancelled by casting/combat for perm invis, non-lev zones for lev, curing poison/curse + // counters, etc. + return -1; + case 51: // Permanent. Cancelled when out of range of aura. + return -4; + default: + // the client function has another bool parameter that if true returns -2 -- unsure + if (formula < 200) return 0; + temp = formula; + break; } + if (duration && duration < temp) + temp = duration; + return temp; } // helper function for AddBuff to determine stacking @@ -2711,11 +2816,20 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, Log.Out(Logs::Detail, Logs::Spells, "Check Stacking on old %s (%d) @ lvl %d (by %s) vs. new %s (%d) @ lvl %d (by %s)", sp1.name, spellid1, caster_level1, (caster1==nullptr)?"Nobody":caster1->GetName(), sp2.name, spellid2, caster_level2, (caster2==nullptr)?"Nobody":caster2->GetName()); - // Same Spells and dot exemption is set to 1 or spell is Manaburn - if (spellid1 == spellid2) { - if (sp1.dot_stacking_exempt == 1 && caster1 != caster2) { // same caster can refresh - Log.Out(Logs::Detail, Logs::Spells, "Blocking spell due to dot stacking exemption."); - return -1; + if (spellid1 == spellid2 ) { + if (!IsStackableDot(spellid1) && !IsEffectInSpell(spellid1, SE_ManaBurn)) { // mana burn spells we need to use the stacking command blocks live actually checks those first, we should probably rework to that too + if (caster_level1 > caster_level2) { // cur buff higher level than new + if (IsEffectInSpell(spellid1, SE_ImprovedTaunt)) { + Log.Out(Logs::Detail, Logs::Spells, "SE_ImprovedTaunt level exception, overwriting."); + return 1; + } else { + Log.Out(Logs::Detail, Logs::Spells, "Spells the same but existing is higher level, stopping."); + return -1; + } + } else { + Log.Out(Logs::Detail, Logs::Spells, "Spells the same but newer is higher or equal level, overwriting."); + return 1; + } } else if (spellid1 == 2751) { Log.Out(Logs::Detail, Logs::Spells, "Blocking spell because manaburn does not stack with itself."); return -1; @@ -2725,23 +2839,6 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int modval = mod_spell_stack(spellid1, caster_level1, caster1, spellid2, caster_level2, caster2); if(modval < 2) { return(modval); } - //resurrection effects wont count for overwrite/block stacking - switch(spellid1) - { - case 756: - case 757: - case 5249: - return (0); - } - - switch (spellid2) - { - case 756: - case 757: - case 5249: - return (0); - } - /* One of these is a bard song and one isn't and they're both beneficial so they should stack. */ @@ -2757,11 +2854,15 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, bool effect_match = true; // Figure out if we're identical in effects on all slots. if (spellid1 != spellid2) { for (i = 0; i < EFFECT_COUNT; i++) { - if (sp1.effectid[i] != sp2.effectid[i]) { + // we don't want this optimization for mana burns + if (sp1.effectid[i] != sp2.effectid[i] || sp1.effectid[i] == SE_ManaBurn) { effect_match = false; break; } } + } else if (IsEffectInSpell(spellid1, SE_ManaBurn)) { + Log.Out(Logs::Detail, Logs::Spells, "We have a Mana Burn spell that is the same, they won't stack"); + return -1; } // check for special stacking overwrite in spell2 against effects in spell1 @@ -2889,28 +2990,8 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, if(effect1 != effect2) continue; - //Effects which really aren't going to affect stacking. - if(effect1 == SE_CurrentHPOnce || - effect1 == SE_CurseCounter || - effect1 == SE_DiseaseCounter || - effect1 == SE_PoisonCounter){ - continue; - } - - /* - Skip check if effect is SE_Limit* - skip checking effect2 since we know they are equal - */ - if(effect1 == SE_LimitMaxLevel || - effect1 == SE_LimitResist || - effect1 == SE_LimitTarget || - effect1 == SE_LimitEffect || - effect1 == SE_LimitSpellType || - effect1 == SE_LimitSpell || - effect1 == SE_LimitMinDur || - effect1 == SE_LimitInstant || - effect1 == SE_LimitMinLevel || - effect1 == SE_LimitCastTimeMin) + // big ol' list according to the client, wasn't that nice! + if (IsEffectIgnoredInStacking(effect1)) continue; /* @@ -2929,18 +3010,6 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, return (-1); } - /* - If the effects are the same and - sp1 = beneficial & sp2 = detrimental or - sp1 = detrimental & sp2 = beneficial - Then this effect should be ignored for stacking purposes. - */ - if(sp_det_mismatch) - { - Log.Out(Logs::Detail, Logs::Spells, "The effects are the same but the spell types are not, passing the effect"); - continue; - } - /* If the spells aren't the same and the effect is a dot we can go ahead and stack it @@ -2958,8 +3027,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, if ( effect1 == SE_AttackSpeed || - effect1 == SE_AttackSpeed2 || - effect1 == SE_AttackSpeed3 + effect1 == SE_AttackSpeed2 ) { sp1_value -= 100; @@ -3033,6 +3101,34 @@ bool Client::CheckSpellLevelRestriction(uint16 spell_id) return true; } +uint32 Mob::GetFirstBuffSlot(bool disc, bool song) +{ + return 0; +} + +uint32 Mob::GetLastBuffSlot(bool disc, bool song) +{ + return GetCurrentBuffSlots(); +} + +uint32 Client::GetFirstBuffSlot(bool disc, bool song) +{ + if (song) + return GetMaxBuffSlots(); + if (disc) + return GetMaxBuffSlots() + GetMaxSongSlots(); + return 0; +} + +uint32 Client::GetLastBuffSlot(bool disc, bool song) +{ + if (song) + return GetMaxBuffSlots() + GetCurrentSongSlots(); + if (disc) + return GetMaxBuffSlots() + GetMaxSongSlots() + GetCurrentDiscSlots(); + return GetCurrentBuffSlots(); +} + // 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 @@ -3052,7 +3148,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid if (duration == 0) { duration = CalcBuffDuration(caster, this, spell_id); - if (caster) + if (caster && duration > 0) // negatives are perma buffs duration = caster->GetActSpellDuration(spell_id, duration); } @@ -3070,18 +3166,8 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid // we also check if overwriting will occur. this is so after this loop // we can determine if there will be room for this buff int buff_count = GetMaxTotalSlots(); - uint32 start_slot = 0; - uint32 end_slot = 0; - if (IsDisciplineBuff(spell_id)) { - start_slot = GetMaxBuffSlots() + GetMaxSongSlots(); - end_slot = start_slot + GetCurrentDiscSlots(); - } else if(spells[spell_id].short_buff_box) { - start_slot = GetMaxBuffSlots(); - end_slot = start_slot + GetCurrentSongSlots(); - } else { - start_slot = 0; - end_slot = GetCurrentBuffSlots(); - } + uint32 start_slot = GetFirstBuffSlot(IsDisciplineBuff(spell_id), spells[spell_id].short_buff_box); + uint32 end_slot = GetLastBuffSlot(IsDisciplineBuff(spell_id), spells[spell_id].short_buff_box); for (buffslot = 0; buffslot < buff_count; buffslot++) { const Buffs_Struct &curbuf = buffs[buffslot]; @@ -3093,13 +3179,16 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid if (ret == -1) { // stop the spell Log.Out(Logs::Detail, Logs::Spells, "Adding buff %d failed: stacking prevented by spell %d in slot %d with caster level %d", spell_id, curbuf.spellid, buffslot, curbuf.casterlevel); + if (caster && caster->IsClient() && RuleB(Client, UseLiveBlockedMessage)) { + caster->Message(13, "Your %s did not take hold on %s. (Blocked by %s.)", spells[spell_id].name, this->GetName(), spells[curbuf.spellid].name); + } return -1; } if (ret == 1) { // set a flag to indicate that there will be overwriting Log.Out(Logs::Detail, Logs::Spells, "Adding buff %d will overwrite spell %d in slot %d with caster level %d", spell_id, curbuf.spellid, buffslot, curbuf.casterlevel); // If this is the first buff it would override, use its slot - if (!will_overwrite) + if (!will_overwrite && !IsDisciplineBuff(spell_id)) emptyslot = buffslot; will_overwrite = true; overwrite_slots.push_back(buffslot); @@ -3149,7 +3238,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid // if we hadn't found a free slot before, or if this is earlier // we use it - if (emptyslot == -1 || *cur < emptyslot) + if (emptyslot == -1 || (*cur < emptyslot && !IsDisciplineBuff(spell_id))) emptyslot = *cur; } } @@ -3175,6 +3264,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid buffs[emptyslot].dot_rune = 0; buffs[emptyslot].ExtraDIChance = 0; buffs[emptyslot].RootBreakChance = 0; + buffs[emptyslot].instrument_mod = caster ? caster->GetInstrumentMod(spell_id) : 10; if (level_override > 0) { buffs[emptyslot].UpdateClient = true; @@ -3192,7 +3282,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid { EQApplicationPacket *outapp = MakeBuffsPacket(); - entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, BIT_SoDAndLater); + entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::bit_SoDAndLater); if(IsClient() && GetTarget() == this) CastToClient()->QueuePacket(outapp); @@ -3202,7 +3292,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid if (IsNPC()) { EQApplicationPacket *outapp = MakeBuffsPacket(); - entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, BIT_SoDAndLater, true); + entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, EQEmu::versions::bit_SoDAndLater, true); safe_delete(outapp); } @@ -3252,6 +3342,7 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite) firstfree = i; } if(ret == -1) { + Log.Out(Logs::Detail, Logs::AI, "Buff %d would conflict with %d in slot %d, reporting stack failure", spellid, curbuf.spellid, i); return -1; // stop the spell, can't stack it } @@ -3278,7 +3369,8 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite) // and if you don't want effects just return false. interrupting here will // break stuff // -bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, bool isproc) +bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, + bool isproc, int level_override) { // well we can't cast a spell on target without a target @@ -3310,7 +3402,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r if(!IsValidSpell(spell_id)) return false; - uint16 caster_level = GetCasterLevel(spell_id); + uint16 caster_level = level_override > 0 ? level_override : GetCasterLevel(spell_id); Log.Out(Logs::Detail, Logs::Spells, "Casting spell %d on %s with effective caster level %d", spell_id, spelltar->GetName(), caster_level); @@ -3649,10 +3741,12 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r // not all unresistable, so changing this to only check certain spells if(IsResistableSpell(spell_id)) { + spelltar->BreakInvisibleSpells(); //Any detrimental spell cast on you will drop invisible (can be AOE, non damage ect). + if (IsCharmSpell(spell_id) || IsMezSpell(spell_id) || IsFearSpell(spell_id)) - spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust,true); + spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust, true, false, false, level_override); else - spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust); + spell_effectiveness = spelltar->ResistSpell(spells[spell_id].resisttype, spell_id, this, use_resist_adjust, resist_adjust, false, false, false, level_override); if(spell_effectiveness < 100) { @@ -3669,25 +3763,24 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r spelltar->Message_StringID(MT_SpellFailure, YOU_RESIST, spells[spell_id].name); } - if(spelltar->IsAIControlled()){ - int32 aggro = CheckAggroAmount(spell_id); - if(aggro > 0) { - if(!IsHarmonySpell(spell_id)) - spelltar->AddToHateList(this, aggro); - else - if(!spelltar->PassCharismaCheck(this, spell_id)) - spelltar->AddToHateList(this, aggro); - } - else{ - uint32 newhate = spelltar->GetHateAmount(this) + aggro; - if (newhate < 1) { - spelltar->SetHateAmountOnEnt(this,1); - } else { - spelltar->SetHateAmountOnEnt(this,newhate); - } + if (spelltar->IsAIControlled()) { + int32 aggro = CheckAggroAmount(spell_id, spelltar); + if (aggro > 0) { + if (!IsHarmonySpell(spell_id)) + spelltar->AddToHateList(this, aggro); + else if (!spelltar->PassCharismaCheck(this, spell_id)) + spelltar->AddToHateList(this, aggro); + } else { + int newhate = spelltar->GetHateAmount(this) + aggro; + spelltar->SetHateAmountOnEnt(this, std::max(1, newhate)); } } + if (spelltar->IsClient()){ + spelltar->CastToClient()->BreakSneakWhenCastOn(this, true); + spelltar->CastToClient()->BreakFeignDeathWhenCastOn(true); + } + spelltar->CheckNumHitsRemaining(NumHit::IncomingSpells); CheckNumHitsRemaining(NumHit::OutgoingSpells); @@ -3695,6 +3788,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r return false; } } + + if (spelltar->IsClient()){ + spelltar->CastToClient()->BreakSneakWhenCastOn(this, false); + spelltar->CastToClient()->BreakFeignDeathWhenCastOn(false); + } } else { @@ -3705,20 +3803,20 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r spelltar->DamageShield(this, true); if (spelltar->IsAIControlled() && IsDetrimentalSpell(spell_id) && !IsHarmonySpell(spell_id)) { - int32 aggro_amount = CheckAggroAmount(spell_id, isproc); - Log.Out(Logs::Detail, Logs::Spells, "Spell %d cast on %s generated %d hate", spell_id, spelltar->GetName(), aggro_amount); - if(aggro_amount > 0) - spelltar->AddToHateList(this, aggro_amount); else{ + int32 aggro_amount = CheckAggroAmount(spell_id, spelltar, isproc); + Log.Out(Logs::Detail, Logs::Spells, "Spell %d cast on %s generated %d hate", spell_id, + spelltar->GetName(), aggro_amount); + if (aggro_amount > 0) { + spelltar->AddToHateList(this, aggro_amount); + } else { int32 newhate = spelltar->GetHateAmount(this) + aggro_amount; - if (newhate < 1) { - spelltar->SetHateAmountOnEnt(this,1); - } else { - spelltar->SetHateAmountOnEnt(this,newhate); - } + spelltar->SetHateAmountOnEnt(this, std::max(newhate, 1)); } + } else if (IsBeneficialSpell(spell_id) && !IsSummonPCSpell(spell_id)) { + entity_list.AddHealAggro( + spelltar, this, + CheckHealAggroAmount(spell_id, spelltar, (spelltar->GetMaxHP() - spelltar->GetHP()))); } - else if (IsBeneficialSpell(spell_id) && !IsSummonPCSpell(spell_id)) - entity_list.AddHealAggro(spelltar, this, CheckHealAggroAmount(spell_id, (spelltar->GetMaxHP() - spelltar->GetHP()))); // make sure spelltar is high enough level for the buff if(RuleB(Spells, BuffLevelRestrictions) && !spelltar->CheckSpellLevelRestriction(spell_id)) @@ -3731,19 +3829,19 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } // cause the effects to the target - if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness)) + if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness, level_override)) { // if SpellEffect returned false there's a problem applying the // spell. It's most likely a buff that can't stack. Log.Out(Logs::Detail, Logs::Spells, "Spell %d could not apply its effects %s -> %s\n", spell_id, GetName(), spelltar->GetName()); - if(casting_spell_type != 1) // AA is handled differently + if(casting_spell_aa_id) Message_StringID(MT_SpellFailure, SPELL_NO_HOLD); safe_delete(action_packet); return false; } if (IsValidSpell(spells[spell_id].RecourseLink) && spells[spell_id].RecourseLink != spell_id) - SpellFinished(spells[spell_id].RecourseLink, this, 10, 0, -1, spells[spells[spell_id].RecourseLink].ResistDiff); + SpellFinished(spells[spell_id].RecourseLink, this, CastingSlot::Item, 0, -1, spells[spells[spell_id].RecourseLink].ResistDiff); if (IsDetrimentalSpell(spell_id)) { @@ -3772,7 +3870,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r spelltar->CastToClient()->SetKnockBackExemption(true); action->buff_unknown = 0; - EQApplicationPacket* outapp_push = new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); + 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()); @@ -3830,7 +3929,7 @@ 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->sequence = action->sequence; + cd->meleepush_xy = action->sequence; cd->damage = 0; if(!IsEffectInSpell(spell_id, SE_BindAffinity)) { @@ -3862,7 +3961,7 @@ void Corpse::CastRezz(uint16 spellid, Mob* Caster) } */ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RezzRequest, sizeof(Resurrect_Struct)); + auto outapp = new EQApplicationPacket(OP_RezzRequest, sizeof(Resurrect_Struct)); Resurrect_Struct* rezz = (Resurrect_Struct*) outapp->pBuffer; // Why are we truncating these names to 30 characters ? memcpy(rezz->your_name,this->corpse_name,30); @@ -4031,11 +4130,11 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) if(GetSpecialAbility(UNMEZABLE)) { Log.Out(Logs::Detail, Logs::Spells, "We are immune to Mez spells."); caster->Message_StringID(MT_Shout, CANNOT_MEZ); - int32 aggro = caster->CheckAggroAmount(spell_id); + int32 aggro = caster->CheckAggroAmount(spell_id, this); if(aggro > 0) { AddToHateList(caster, aggro); } else { - AddToHateList(caster, 1); + AddToHateList(caster, 1,0,true,false,false,spell_id); } return true; } @@ -4058,11 +4157,11 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) { Log.Out(Logs::Detail, Logs::Spells, "We are immune to Slow spells."); caster->Message_StringID(MT_Shout, IMMUNE_ATKSPEED); - int32 aggro = caster->CheckAggroAmount(spell_id); + int32 aggro = caster->CheckAggroAmount(spell_id, this); if(aggro > 0) { AddToHateList(caster, aggro); } else { - AddToHateList(caster, 1); + AddToHateList(caster, 1,0,true,false,false,spell_id); } return true; } @@ -4074,11 +4173,11 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) if(GetSpecialAbility(UNFEARABLE)) { Log.Out(Logs::Detail, Logs::Spells, "We are immune to Fear spells."); caster->Message_StringID(MT_Shout, IMMUNE_FEAR); - int32 aggro = caster->CheckAggroAmount(spell_id); + int32 aggro = caster->CheckAggroAmount(spell_id, this); if(aggro > 0) { AddToHateList(caster, aggro); } else { - AddToHateList(caster, 1); + AddToHateList(caster, 1,0,true,false,false,spell_id); } return true; } else if(IsClient() && caster->IsClient() && (caster->CastToClient()->GetGM() == false)) @@ -4091,16 +4190,15 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) { Log.Out(Logs::Detail, Logs::Spells, "Level is %d, cannot be feared by this spell.", GetLevel()); caster->Message_StringID(MT_Shout, FEAR_TOO_HIGH); - int32 aggro = caster->CheckAggroAmount(spell_id); + int32 aggro = caster->CheckAggroAmount(spell_id, this); if (aggro > 0) { AddToHateList(caster, aggro); } else { - AddToHateList(caster, 1); + AddToHateList(caster, 1,0,true,false,false,spell_id); } return true; } - - else if (IsClient() && CastToClient()->CheckAAEffect(aaEffectWarcry)) + else if (CheckAATimer(aaTimerWarcry)) { Message(13, "Your are immune to fear."); Log.Out(Logs::Detail, Logs::Spells, "Clients has WarCry effect, immune to fear!"); @@ -4115,11 +4213,11 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) { Log.Out(Logs::Detail, Logs::Spells, "We are immune to Charm spells."); caster->Message_StringID(MT_Shout, CANNOT_CHARM); - int32 aggro = caster->CheckAggroAmount(spell_id); + int32 aggro = caster->CheckAggroAmount(spell_id, this); if(aggro > 0) { AddToHateList(caster, aggro); } else { - AddToHateList(caster, 1); + AddToHateList(caster, 1,0,true,false,false,spell_id); } return true; } @@ -4155,11 +4253,11 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) if(GetSpecialAbility(UNSNAREABLE)) { Log.Out(Logs::Detail, Logs::Spells, "We are immune to Snare spells."); caster->Message_StringID(MT_Shout, IMMUNE_MOVEMENT); - int32 aggro = caster->CheckAggroAmount(spell_id); + int32 aggro = caster->CheckAggroAmount(spell_id, this); if(aggro > 0) { AddToHateList(caster, aggro); } else { - AddToHateList(caster, 1); + AddToHateList(caster, 1,0,true,false,false,spell_id); } return true; } @@ -4199,7 +4297,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster) // pvp_resist_base // pvp_resist_calc // pvp_resist_cap -float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override, int resist_override, bool CharismaCheck, bool CharmTick, bool IsRoot) +float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override, int resist_override, bool CharismaCheck, bool CharmTick, bool IsRoot, int level_override) { if(!caster) @@ -4267,7 +4365,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use } //Get the resist chance for the target - if(resist_type == RESIST_NONE) + if(resist_type == RESIST_NONE || spells[spell_id].no_resist) { Log.Out(Logs::Detail, Logs::Spells, "Spell was unresistable"); return 100; @@ -4342,18 +4440,19 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use int level_mod = 0; //Adjust our resist chance based on level modifiers - int temp_level_diff = GetLevel() - caster->GetLevel(); + uint8 caster_level = level_override > 0 ? level_override : caster->GetLevel(); + int temp_level_diff = GetLevel() - caster_level; //Physical Resists are calclated using their own formula derived from extensive parsing. if (resist_type == RESIST_PHYSICAL) { - level_mod = ResistPhysical(temp_level_diff, caster->GetLevel()); + level_mod = ResistPhysical(temp_level_diff, caster_level); } else { if(IsNPC() && GetLevel() >= RuleI(Casting,ResistFalloff)) { - int a = (RuleI(Casting,ResistFalloff)-1) - caster->GetLevel(); + int a = (RuleI(Casting,ResistFalloff)-1) - caster_level; if(a > 0) { temp_level_diff = a; @@ -4380,7 +4479,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use level_mod = -level_mod; } - if(IsNPC() && (caster->GetLevel() - GetLevel()) < -20) + if(IsNPC() && (caster_level - GetLevel()) < -20) { level_mod = 1000; } @@ -4391,7 +4490,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use int level_diff; if(GetLevel() >= RuleI(Casting,ResistFalloff)) { - level_diff = (RuleI(Casting,ResistFalloff)-1) - caster->GetLevel(); + level_diff = (RuleI(Casting,ResistFalloff)-1) - caster_level; if(level_diff < 0) { level_diff = 0; @@ -4399,12 +4498,12 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use } else { - level_diff = GetLevel() - caster->GetLevel(); + level_diff = GetLevel() - caster_level; } level_mod += (2 * level_diff); } } - + if (CharismaCheck) { /* @@ -4510,14 +4609,14 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use if(IsNPC()) { - if(GetLevel() > caster->GetLevel() && GetLevel() >= 17 && caster->GetLevel() <= 50) + if(GetLevel() > caster_level && GetLevel() >= 17 && caster_level <= 50) { partial_modifier += 5; } - if(GetLevel() >= 30 && caster->GetLevel() < 50) + if(GetLevel() >= 30 && caster_level < 50) { - partial_modifier += (caster->GetLevel() - 25); + partial_modifier += (caster_level - 25); } if(GetLevel() < 15) @@ -4528,9 +4627,9 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use if(caster->IsNPC()) { - if((GetLevel() - caster->GetLevel()) >= 20) + if((GetLevel() - caster_level) >= 20) { - partial_modifier += (GetLevel() - caster->GetLevel()) * 1.5; + partial_modifier += (GetLevel() - caster_level) * 1.5; } } @@ -4634,7 +4733,7 @@ float Mob::GetAOERange(uint16 spell_id) { void Mob::Spin() { if(IsClient()) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Action, sizeof(Action_Struct)); + auto outapp = new EQApplicationPacket(OP_Action, sizeof(Action_Struct)); outapp->pBuffer[0] = 0x0B; outapp->pBuffer[1] = 0x0A; outapp->pBuffer[2] = 0x0B; @@ -4681,11 +4780,12 @@ void Mob::SendSpellBarEnable(uint16 spell_id) if(!IsClient()) return; - EQApplicationPacket *outapp = new EQApplicationPacket(OP_ManaChange, sizeof(ManaChange_Struct)); + auto outapp = new EQApplicationPacket(OP_ManaChange, sizeof(ManaChange_Struct)); ManaChange_Struct* manachange = (ManaChange_Struct*)outapp->pBuffer; manachange->new_mana = GetMana(); manachange->spell_id = spell_id; manachange->stamina = CastToClient()->GetEndurance(); + manachange->keepcasting = 0; outapp->priority = 6; CastToClient()->QueuePacket(outapp); safe_delete(outapp); @@ -4708,7 +4808,7 @@ void Mob::Stun(int duration) { stunned = true; stunned_timer.Start(duration); - SendStunAppearance(); + SendAddPlayerState(PlayerState::Stunned); } } @@ -4716,6 +4816,7 @@ void Mob::UnStun() { if(stunned && stunned_timer.Enabled()) { stunned = false; stunned_timer.Disable(); + SendRemovePlayerState(PlayerState::Stunned); } } @@ -4724,7 +4825,7 @@ void Client::Stun(int duration) { Mob::Stun(duration); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Stun, sizeof(Stun_Struct)); + auto outapp = new EQApplicationPacket(OP_Stun, sizeof(Stun_Struct)); Stun_Struct* stunon = (Stun_Struct*) outapp->pBuffer; stunon->duration = duration; outapp->priority = 5; @@ -4735,7 +4836,7 @@ void Client::Stun(int duration) void Client::UnStun() { Mob::UnStun(); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Stun, sizeof(Stun_Struct)); + auto outapp = new EQApplicationPacket(OP_Stun, sizeof(Stun_Struct)); Stun_Struct* stunon = (Stun_Struct*) outapp->pBuffer; stunon->duration = 0; outapp->priority = 5; @@ -4745,14 +4846,12 @@ void Client::UnStun() { void NPC::Stun(int duration) { Mob::Stun(duration); - SetRunAnimSpeed(0); - SendPosition(); + SetCurrentSpeed(0); } void NPC::UnStun() { Mob::UnStun(); - SetRunAnimSpeed(static_cast(GetRunspeed())); - SendPosition(); + SetCurrentSpeed(GetRunspeed()); } void Mob::Mesmerize() @@ -4780,17 +4879,17 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message) { EQApplicationPacket* outapp; - outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct)); - SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer; + outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffPacket_Struct)); + SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer; - sbf->entityid=GetID(); + sbf->entityid = GetID(); // i dont know why but this works.. for now - sbf->slot=2; + sbf->buff.effect_type = 2; // sbf->slot=m_pp.buffs[slot_id].slotid; // sbf->level=m_pp.buffs[slot_id].level; // sbf->effect=m_pp.buffs[slot_id].effect; - sbf->spellid=spell_id; - sbf->slotid=slot_id; + sbf->buff.spellid = spell_id; + sbf->slotid = slot_id; sbf->bufffade = 1; #if EQDEBUG >= 11 printf("Sending SBF 1 from server:\n"); @@ -4803,7 +4902,7 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message) sbf->level=0; sbf->slot=0; */ - sbf->spellid=0xffffffff; + sbf->buff.spellid = 0xffffffff; #if EQDEBUG >= 11 printf("Sending SBF 2 from server:\n"); DumpPacket(outapp); @@ -4821,7 +4920,6 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message) QueuePacket(outapp); safe_delete(outapp); } - } void Client::MemSpell(uint16 spell_id, int slot, bool update_client) @@ -4862,6 +4960,16 @@ void Client::UnmemSpell(int slot, bool update_client) } } +void Client::UnmemSpellBySpellID(int32 spell_id) +{ + for(int i = 0; i < MAX_PP_MEMSPELL; i++) { + if(m_pp.mem_spells[i] == spell_id) { + UnmemSpell(i, true); + break; + } + } +} + void Client::UnmemSpellAll(bool update_client) { int i; @@ -4903,7 +5011,7 @@ void Client::UnscribeSpell(int slot, bool update_client) database.DeleteCharacterSpell(this->CharacterID(), m_pp.spell_book[slot], slot); if(update_client) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_DeleteSpell, sizeof(DeleteSpell_Struct)); + auto outapp = new EQApplicationPacket(OP_DeleteSpell, sizeof(DeleteSpell_Struct)); DeleteSpell_Struct* del = (DeleteSpell_Struct*)outapp->pBuffer; del->spell_slot = slot; del->success = 1; @@ -5053,7 +5161,7 @@ bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) { spells[buffs[i].spellid].base[j], spells[buffs[i].spellid].max[j], buffs[i].casterlevel, buffs[i].spellid); - Log.Out(Logs::General, Logs::Normal, + Log.Out(Logs::General, Logs::Normal, "FindType: type = %d; value = %d; threshold = %d", type, value, threshold); if (value < threshold) @@ -5091,7 +5199,7 @@ bool Mob::IsCombatProc(uint16 spell_id) { return false; } -bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id) { +bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id, int level_override) { if(spell_id == SPELL_UNKNOWN) return(false); @@ -5102,6 +5210,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b PermaProcs[i].spellID = spell_id; PermaProcs[i].chance = iChance; PermaProcs[i].base_spellID = base_spell_id; + PermaProcs[i].level_override = level_override; Log.Out(Logs::Detail, Logs::Spells, "Added permanent proc spell %d with chance %d to slot %d", spell_id, iChance, i); return true; @@ -5114,6 +5223,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b SpellProcs[i].spellID = spell_id; SpellProcs[i].chance = iChance; SpellProcs[i].base_spellID = base_spell_id;; + SpellProcs[i].level_override = level_override; Log.Out(Logs::Detail, Logs::Spells, "Added spell-granted proc spell %d with chance %d to slot %d", spell_id, iChance, i); return true; } @@ -5129,6 +5239,7 @@ bool Mob::RemoveProcFromWeapon(uint16 spell_id, bool bAll) { SpellProcs[i].spellID = SPELL_UNKNOWN; SpellProcs[i].chance = 0; SpellProcs[i].base_spellID = SPELL_UNKNOWN; + SpellProcs[i].level_override = -1; Log.Out(Logs::Detail, Logs::Spells, "Removed proc %d from slot %d", spell_id, i); } } @@ -5207,7 +5318,7 @@ bool Mob::UseBardSpellLogic(uint16 spell_id, int slot) spell_id = casting_spell_id; if(slot == -1) - slot = casting_spell_slot; + slot = static_cast(casting_spell_slot); // should we treat this as a bard singing? return @@ -5235,7 +5346,7 @@ void Mob::_StopSong() { bardsong = 0; bardsong_target_id = 0; - bardsong_slot = 0; + bardsong_slot = CastingSlot::Gem1; bardsong_timer.Disable(); } @@ -5244,28 +5355,43 @@ void Mob::_StopSong() //Thus I use this in the buff process to update the correct duration once after casting //this allows AAs and focus effects that increase buff duration to work correctly, but could probably //be used for other things as well -void Client::SendBuffDurationPacket(Buffs_Struct &buff) +void Client::SendBuffDurationPacket(Buffs_Struct &buff, int slot) { EQApplicationPacket* outapp; - outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct)); - SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer; + outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffPacket_Struct)); + SpellBuffPacket_Struct* sbf = (SpellBuffPacket_Struct*) outapp->pBuffer; sbf->entityid = GetID(); - sbf->slot = 2; - sbf->spellid = buff.spellid; - sbf->slotid = 0; - sbf->effect = buff.casterlevel > 0 ? buff.casterlevel : GetLevel(); - sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel(); + + sbf->buff.effect_type = 2; + + sbf->buff.level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel(); + sbf->buff.bard_modifier = buff.instrument_mod; + sbf->buff.spellid = buff.spellid; + sbf->buff.duration = buff.ticsremaining; + if (buff.dot_rune) + sbf->buff.counters = buff.dot_rune; + else if (buff.magic_rune) + sbf->buff.counters = buff.magic_rune; + else if (buff.melee_rune) + sbf->buff.counters = buff.melee_rune; + else if (buff.counters) + sbf->buff.counters = buff.counters; + sbf->buff.player_id = buff.casterid; + sbf->buff.num_hits = buff.numhits; + sbf->buff.y = buff.caston_y; + sbf->buff.x = buff.caston_x; + sbf->buff.z = buff.caston_z; + + sbf->slotid = slot; sbf->bufffade = 0; - sbf->duration = buff.ticsremaining; - sbf->num_hits = buff.numhits; FastQueuePacket(&outapp); } void Client::SendBuffNumHitPacket(Buffs_Struct &buff, int slot) { // UF+ use this packet - if (GetClientVersion() < ClientVersion::UF) + if (ClientVersion() < EQEmu::versions::ClientVersion::UF) return; EQApplicationPacket *outapp; outapp = new EQApplicationPacket(OP_BuffCreate, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct)); @@ -5273,6 +5399,7 @@ void Client::SendBuffNumHitPacket(Buffs_Struct &buff, int slot) bi->entity_id = GetID(); bi->count = 1; bi->all_buffs = 0; + bi->tic_timer = tic_timer.GetRemainingTime(); bi->entries[0].buff_slot = slot; bi->entries[0].spell_id = buff.spellid; @@ -5290,15 +5417,15 @@ void Mob::SendPetBuffsToClient() int PetBuffCount = 0; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_PetBuffWindow,sizeof(PetBuff_Struct)); + auto outapp = new EQApplicationPacket(OP_PetBuffWindow, sizeof(PetBuff_Struct)); PetBuff_Struct* pbs=(PetBuff_Struct*)outapp->pBuffer; memset(outapp->pBuffer,0,outapp->size); pbs->petid=GetID(); int MaxSlots = GetMaxTotalSlots(); - if(MaxSlots > BUFF_COUNT) - MaxSlots = BUFF_COUNT; + if(MaxSlots > PET_BUFF_COUNT) + MaxSlots = PET_BUFF_COUNT; for(int buffslot = 0; buffslot < MaxSlots; buffslot++) { @@ -5319,7 +5446,7 @@ void Mob::SendBuffsToClient(Client *c) if(!c) return; - if(c->GetClientVersionBit() & BIT_SoDAndLater) + if (c->ClientVersionBit() & EQEmu::versions::bit_SoDAndLater) { EQApplicationPacket *outapp = MakeBuffsPacket(); c->FastQueuePacket(&outapp); @@ -5353,6 +5480,13 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target) buff->entity_id = GetID(); buff->count = count; buff->all_buffs = 1; + buff->tic_timer = tic_timer.GetRemainingTime(); + // there are more types, the client doesn't seem to really care though. The others are also currently hard to fill in here ... + // (see comment in common/eq_packet_structs.h) + if (for_target) + buff->type = IsClient() ? 5 : 7; + else + buff->type = 0; uint32 index = 0; for(unsigned int i = 0; i < buff_count; ++i) @@ -5380,7 +5514,7 @@ void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration) buffs[i].ticsremaining = newDuration; if(IsClient()) { - CastToClient()->SendBuffDurationPacket(buffs[i]); + CastToClient()->SendBuffDurationPacket(buffs[i], i); } } } @@ -5388,10 +5522,14 @@ void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration) int Client::GetCurrentBuffSlots() const { - if(15 + aabonuses.BuffSlotIncrease > 25) - return 25; - else - return 15 + aabonuses.BuffSlotIncrease; + int numbuffs = 15; + // client does check spells and items + numbuffs += aabonuses.BuffSlotIncrease + spellbonuses.BuffSlotIncrease + itembonuses.BuffSlotIncrease; + if (GetLevel() > 70) + numbuffs++; + if (GetLevel() > 74) + numbuffs++; + return EQEmu::ClampUpper(numbuffs, GetMaxBuffSlots()); } int Client::GetCurrentSongSlots() const @@ -5583,3 +5721,25 @@ void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust) ++iter; } } + +// duration in seconds +void Client::SetLinkedSpellReuseTimer(uint32 timer_id, uint32 duration) +{ + if (timer_id > 19) + return; + GetPTimers().Start(pTimerLinkedSpellReuseStart + timer_id, duration); + auto outapp = new EQApplicationPacket(OP_LinkedReuse, sizeof(LinkedSpellReuseTimer_Struct)); + auto lr = (LinkedSpellReuseTimer_Struct *)outapp->pBuffer; + lr->timer_id = timer_id; + lr->start_time = Timer::GetCurrentTime() / 1000; + lr->end_time = lr->start_time + duration; + FastQueuePacket(&outapp); +} + +bool Client::IsLinkedSpellReuseTimerReady(uint32 timer_id) +{ + if (timer_id > 19) + return true; + return GetPTimers().Expired(&database, pTimerLinkedSpellReuseStart + timer_id); +} + diff --git a/zone/string_ids.h b/zone/string_ids.h index ef758dba6..e1fb4de7c 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -27,6 +27,7 @@ #define GAIN_XP 138 //You gain experience!! #define GAIN_GROUPXP 139 //You gain party experience!! #define BOW_DOUBLE_DAMAGE 143 //Your bow shot did double dmg. +#define YOU_ARE_BEING_BANDAGED 147 //Someone is bandaging you. #define FORAGE_GRUBS 150 //You have scrounged up some fishing grubs. #define FORAGE_WATER 151 //You have scrounged up some water. #define FORAGE_FOOD 152 //You have scrounged up some food. @@ -78,6 +79,7 @@ #define ONLY_ONE_PET 246 //You cannot have more than one pet at a time. #define CANNOT_CHARM_YET 248 //Your target is too high of a level for your charm spell. #define CANNOT_AFFECT_NPC 251 //That spell can not affect this target NPC. +#define FD_CAST_ON 254 //You are no longer feigning death, because a spell hit you. #define SUSPEND_MINION_HAS_AGGRO 256 //Your pet is the focus of something's attention. #define NO_PET 255 //You do not have a pet. #define GATE_FAIL 260 //Your gate is too unstable, and collapses. @@ -231,6 +233,17 @@ #define MISSED_NOTE_OTHER 1219 //A missed note brings %1's song to a close! #define SPELL_LEVEL_REQ 1226 //This spell only works on people who are level %1 and under. #define CORPSE_DECAY_NOW 1227 //This corpse is waiting to expire. +#define CORPSE_ITEM_LOST 1228 //Your items will no longer stay with you when you respawn on death. You will now need to return to your corpse for your items. +#define CORPSE_EXP_LOST 1229 //You will now lose experience when you die. +#define FLICKERS_PALE_LIGHT 1230 //Your %1 flickers with a pale light. +#define PULSES_WITH_LIGHT 1231 //Your %1 pulses with light as your vision sharpens. +#define FEEDS_WITH_POWER 1232 //Your %1 feeds you with power. +#define POWER_DRAIN_INTO 1233 //You feel your power drain into your %1. +#define SEEMS_DRAINED 1234 //Your %1 seems drained of power. +#define ALIVE_WITH_POWER 1235 //Your %1 feels alive with power. +#define SPARKLES 1236 //Your %1 sparkles. +#define GROWS_DIM 1237 //Your %1 grows dim. +#define BEGINS_TO_SHINE 1238 //Your %1 begins to shine. #define SURNAME_REJECTED 1374 //Your new surname was rejected. Please try a different name. #define DUEL_DECLINE 1383 //%1 has declined your challenge to duel to the death. #define DUEL_ACCEPTED 1384 //%1 has already accepted a duel with someone else. @@ -284,6 +297,7 @@ #define ADVENTURE_COMPLETE 5147 //You received %1 points for successfully completing the adventure. #define SUCCOR_FAIL 5169 //The portal collapes before you can escape! #define PET_ATTACKING 5501 //%1 tells you, 'Attacking %2 Master.' +#define AVOID_STUNNING_BLOW 5753 //You avoid the stunning blow. #define FATAL_BOW_SHOT 5745 //%1 performs a FATAL BOW SHOT!! #define MELEE_SILENCE 5806 //You *CANNOT* use this melee ability, you are suffering from amnesia! #define DISCIPLINE_REUSE_MSG 5807 //You can use the ability %1 again in %2 hour(s) %3 minute(s) %4 seconds. @@ -339,10 +353,13 @@ #define YOU_HEAL 9068 //You have healed %1 for %2 points of damage. #define YOUR_HIT_DOT 9072 //%1 has taken %2 damage from your %3. #define HIT_NON_MELEE 9073 //%1 hit %2 for %3 points of non-melee damage. -#define SHAKE_OFF_STUN 9077 +#define GLOWS_BLUE 9074 //Your %1 glows blue. +#define GLOWS_RED 9075 //Your %1 glows red. +#define SHAKE_OFF_STUN 9077 //You shake off the stun effect! #define STRIKETHROUGH_STRING 9078 //You strike through your opponent's defenses! #define SPELL_REFLECT 9082 //%1's spell has been reflected by %2. #define NEW_SPELLS_AVAIL 9149 //You have new spells available to you. Check the merchants near your guild master. +#define FD_CAST_ON_NO_BREAK 9174 //The strength of your will allows you to resume feigning death. #define SNEAK_RESTRICT 9240 //You can not use this ability because you have not been hidden for long enough. #define PET_NOW_FOCUSING 9254 //Focusing on one target, Master. #define PET_NOT_FOCUSING 9263 //No longer focusing on one target, Master. @@ -371,8 +388,11 @@ #define TARGET_PLAYER_FOR_GUILD_STATUS 12260 #define GROUP_INVITEE_NOT_FOUND 12268 //You must target a player or use /invite to invite someone to your group. #define GROUP_INVITEE_SELF 12270 //12270 You cannot invite yourself. +#define NO_LONGER_HIDDEN 12337 //You are no longer hidden. +#define STOP_SNEAKING 12338 //You stop sneaking #define NOT_IN_CONTROL 12368 //You do not have control of yourself right now. #define ALREADY_CASTING 12442 //You are already casting a spell! +#define SHIMMERS_BRIEFLY 12444 //Your %1 shimmers briefly. #define SENSE_CORPSE_NOT_NAME 12446 //You don't sense any corpses of that name. #define SENSE_CORPSE_NONE 12447 //You don't sense any corpses. #define SCREECH_BUFF_BLOCK 12448 //Your immunity buff protected you from the spell %1! diff --git a/zone/tasks.cpp b/zone/tasks.cpp index 4f3fe8124..40e7d8b67 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -29,6 +29,7 @@ Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) #include "../common/misc_functions.h" #include "../common/rulesys.h" #include "../common/string_util.h" +#include "../common/say_link.h" #include "client.h" #include "entity.h" @@ -714,16 +715,23 @@ void ClientTaskState::EnableTask(int characterID, int taskCount, int *tasks) { for(unsigned int i=0; i=MAXTASKSETS)) return 0; - if(TaskSets[TaskSetID].size() == 0) return 0; + if(TaskSets[TaskSetID].empty()) return 0; - std::vector::iterator Iterator = TaskSets[TaskSetID].begin(); + auto Iterator = TaskSets[TaskSetID].begin(); while(Iterator != TaskSets[TaskSetID].end()) { if((*Iterator) > 0) @@ -865,7 +881,7 @@ int TaskManager::LastTaskInSet(int TaskSetID) { if((TaskSetID<=0) || (TaskSetID>=MAXTASKSETS)) return 0; - if(TaskSets[TaskSetID].size() == 0) return 0; + if(TaskSets[TaskSetID].empty()) return 0; return TaskSets[TaskSetID][TaskSets[TaskSetID].size()-1]; } @@ -874,7 +890,7 @@ int TaskManager::NextTaskInSet(int TaskSetID, int TaskID) { if((TaskSetID<=0) || (TaskSetID>=MAXTASKSETS)) return 0; - if(TaskSets[TaskSetID].size() == 0) return 0; + if(TaskSets[TaskSetID].empty()) return 0; for(unsigned int i=0; i TaskID) return TaskSets[TaskSetID][i]; @@ -895,6 +911,26 @@ bool TaskManager::AppropriateLevel(int TaskID, int PlayerLevel) { } +int TaskManager::GetTaskMinLevel(int TaskID) +{ + if (Tasks[TaskID]->MinLevel) + { + return Tasks[TaskID]->MinLevel; + } + + return -1; +} + +int TaskManager::GetTaskMaxLevel(int TaskID) +{ + if (Tasks[TaskID]->MaxLevel) + { + return Tasks[TaskID]->MaxLevel; + } + + return -1; +} + void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID) { unsigned int EnabledTaskIndex = 0; @@ -907,14 +943,14 @@ void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, i state->EnabledTasks.size()); if((TaskSetID<=0) || (TaskSetID>=MAXTASKSETS)) return; - if(TaskSets[TaskSetID].size() > 0) { + if(!TaskSets[TaskSetID].empty()) { // A TaskID of 0 in a TaskSet indicates that all Tasks in the set are enabled for all players. if(TaskSets[TaskSetID][0] == 0) { Log.Out(Logs::General, Logs::Tasks, "[UPDATE] TaskSets[%i][0] == 0. All Tasks in Set enabled.", TaskSetID); - std::vector::iterator Iterator = TaskSets[TaskSetID].begin(); + auto Iterator = TaskSets[TaskSetID].begin(); while((Iterator != TaskSets[TaskSetID].end()) && (TaskListIndex < MAXCHOOSERENTRIES)) { if(AppropriateLevel((*Iterator), PlayerLevel) && !state->IsTaskActive((*Iterator)) && @@ -970,7 +1006,7 @@ void TaskManager::TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, i void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList) { - if (c->GetClientVersion() >= ClientVersion::RoF) + if (c->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { SendTaskSelectorNew(c, mob, TaskCount, TaskList); return; @@ -1019,7 +1055,7 @@ void TaskManager::SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *Task if(ValidTasks == 0) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_OpenNewTasksWindow, PacketLength); + auto outapp = new EQApplicationPacket(OP_OpenNewTasksWindow, PacketLength); AvailableTaskHeader = (AvailableTaskHeader_Struct*)outapp->pBuffer; @@ -1144,7 +1180,7 @@ void TaskManager::SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *T if(ValidTasks == 0) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_OpenNewTasksWindow, PacketLength); + auto outapp = new EQApplicationPacket(OP_OpenNewTasksWindow, PacketLength); outapp->WriteUInt32(ValidTasks); // TaskCount outapp->WriteUInt32(2); // Unknown2 @@ -1313,7 +1349,7 @@ bool ClientTaskState::UnlockActivities(int CharID, int TaskIndex) { if(AllActivitiesComplete && RuleB(TaskSystem, RecordCompletedTasks)) { if(RuleB(TasksSystem, KeepOneRecordPerCompletedTask)) { Log.Out(Logs::General, Logs::Tasks, "[UPDATE] KeepOneRecord enabled"); - std::vector::iterator Iterator = CompletedTasks.begin(); + auto Iterator = CompletedTasks.begin(); int ErasedElements = 0; while(Iterator != CompletedTasks.end()) { int TaskID = (*Iterator).TaskID; @@ -1386,7 +1422,7 @@ bool ClientTaskState::UnlockActivities(int CharID, int TaskIndex) { // the same task again, erase the previous completed entry for this task. if(RuleB(TasksSystem, KeepOneRecordPerCompletedTask)) { Log.Out(Logs::General, Logs::Tasks, "[UPDATE] KeepOneRecord enabled"); - std::vector::iterator Iterator = CompletedTasks.begin(); + auto Iterator = CompletedTasks.begin(); int ErasedElements = 0; while(Iterator != CompletedTasks.end()) { int TaskID = (*Iterator).TaskID; @@ -1672,7 +1708,7 @@ void ClientTaskState::UpdateTasksOnExplore(Client *c, int ExploreID) { return; } -bool ClientTaskState::UpdateTasksOnDeliver(Client *c, uint32 *Items, int Cash, int NPCTypeID) { +bool ClientTaskState::UpdateTasksOnDeliver(Client *c, std::list& Items, int Cash, int NPCTypeID) { bool Ret = false; @@ -1711,17 +1747,15 @@ bool ClientTaskState::UpdateTasksOnDeliver(Client *c, uint32 *Items, int Cash, i Ret = true; } else { - for(int k=0; k<4; k++) { - if(Items[k]==0) continue; + for(auto& k : Items) { switch(Task->Activity[j].GoalMethod) { case METHODSINGLEID: - if(Task->Activity[j].GoalID != (int)Items[k]) continue; + if(Task->Activity[j].GoalID != k->GetID()) continue; break; case METHODLIST: - if(!taskmanager->GoalListManager.IsInList(Task->Activity[j].GoalID, - Items[k])) + if (!taskmanager->GoalListManager.IsInList(Task->Activity[j].GoalID, k->GetID())) continue; break; @@ -1731,7 +1765,7 @@ bool ClientTaskState::UpdateTasksOnDeliver(Client *c, uint32 *Items, int Cash, i } // We found an active task related to this item, so increment the done count Log.Out(Logs::General, Logs::Tasks, "[UPDATE] Increment on GiveItem"); - IncrementDoneCount(c, Task, i, j, 1); + IncrementDoneCount(c, Task, i, j, k->GetCharges() <= 0 ? 1 : k->GetCharges()); Ret = true; } } @@ -1866,7 +1900,7 @@ void ClientTaskState::RewardTask(Client *c, TaskInformation *Task) { if(!Task || !c) return; - const Item_Struct* Item; + const EQEmu::ItemBase* Item; std::vector RewardList; switch(Task->RewardMethod) { @@ -2307,9 +2341,7 @@ void ClientTaskState::SendTaskHistory(Client *c, int TaskIndex) { } } - - - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TaskHistoryReply, PacketLength); + auto outapp = new EQApplicationPacket(OP_TaskHistoryReply, PacketLength); ths = (TaskHistoryReplyHeader_Struct*)outapp->pBuffer; @@ -2352,7 +2384,7 @@ void Client::SendTaskActivityComplete(int TaskID, int ActivityID, int TaskIndex, TaskActivityComplete_Struct* tac; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TaskActivityComplete, sizeof(TaskActivityComplete_Struct)); + auto outapp = new EQApplicationPacket(OP_TaskActivityComplete, sizeof(TaskActivityComplete_Struct)); tac = (TaskActivityComplete_Struct*)outapp->pBuffer; @@ -2382,7 +2414,7 @@ void Client::SendTaskFailed(int TaskID, int TaskIndex) { TaskActivityComplete_Struct* tac; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TaskActivityComplete, sizeof(TaskActivityComplete_Struct)); + auto outapp = new EQApplicationPacket(OP_TaskActivityComplete, sizeof(TaskActivityComplete_Struct)); tac = (TaskActivityComplete_Struct*)outapp->pBuffer; @@ -2432,7 +2464,7 @@ void TaskManager::SendCompletedTasksToClient(Client *c, ClientTaskState *State) PacketLength = PacketLength + 8 + strlen(Tasks[TaskID]->Title) + 1; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_CompletedTasks, PacketLength); + auto outapp = new EQApplicationPacket(OP_CompletedTasks, PacketLength); char *buf = (char*)outapp->pBuffer; //*(uint32 *)buf = State->CompletedTasks.size(); @@ -2467,9 +2499,9 @@ void TaskManager::SendTaskActivityShort(Client *c, int TaskID, int ActivityID, i TaskActivityShort_Struct* tass; - if(c->GetClientVersionBit() & BIT_RoFAndLater) + if (c->ClientVersionBit() & EQEmu::versions::bit_RoFAndLater) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TaskActivity, 25); + auto outapp = new EQApplicationPacket(OP_TaskActivity, 25); outapp->WriteUInt32(ClientTaskIndex); outapp->WriteUInt32(2); outapp->WriteUInt32(TaskID); @@ -2482,7 +2514,7 @@ void TaskManager::SendTaskActivityShort(Client *c, int TaskID, int ActivityID, i return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TaskActivity, sizeof(TaskActivityShort_Struct)); + auto outapp = new EQApplicationPacket(OP_TaskActivity, sizeof(TaskActivityShort_Struct)); tass = (TaskActivityShort_Struct*)outapp->pBuffer; @@ -2503,7 +2535,7 @@ void TaskManager::SendTaskActivityShort(Client *c, int TaskID, int ActivityID, i void TaskManager::SendTaskActivityLong(Client *c, int TaskID, int ActivityID, int ClientTaskIndex, bool Optional, bool TaskComplete) { - if (c->GetClientVersion() >= ClientVersion::RoF) + if (c->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { SendTaskActivityNew(c, TaskID, ActivityID, ClientTaskIndex, Optional, TaskComplete); return; @@ -2520,7 +2552,7 @@ void TaskManager::SendTaskActivityLong(Client *c, int TaskID, int ActivityID, in strlen(Tasks[TaskID]->Activity[ActivityID].Text2) + 1 + strlen(Tasks[TaskID]->Activity[ActivityID].Text3) + 1; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TaskActivity, PacketLength); + auto outapp = new EQApplicationPacket(OP_TaskActivity, PacketLength); tah = (TaskActivityHeader_Struct*)outapp->pBuffer; @@ -2601,7 +2633,7 @@ void TaskManager::SendTaskActivityNew(Client *c, int TaskID, int ActivityID, int ((strlen(itoa(Tasks[TaskID]->Activity[ActivityID].ZoneID)) + 1) * 2) + 3 + String2Len; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TaskActivity, PacketLength); + auto outapp = new EQApplicationPacket(OP_TaskActivity, PacketLength); outapp->WriteUInt32(ClientTaskIndex); // TaskSequenceNumber outapp->WriteUInt32(2); // unknown2 @@ -2742,7 +2774,7 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN + sizeof(TaskDescriptionData2_Struct) + 1 + sizeof(TaskDescriptionTrailer_Struct); std::string reward_text; - int ItemID = NOT_USED; + int ItemID = 0; // If there is an item make the Reward text into a link to the item (only the first item if a list // is specified). I have been unable to get multiple item links to work. @@ -2759,10 +2791,10 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN } if(ItemID) { - const Item_Struct* reward_item = database.GetItem(ItemID); + const EQEmu::ItemBase* reward_item = database.GetItem(ItemID); - Client::TextLink linker; - linker.SetLinkType(linker.linkItemData); + EQEmu::SayLinkEngine linker; + linker.SetLinkType(EQEmu::saylink::SayLinkItemData); linker.SetItemData(reward_item); linker.SetTaskUse(); if (strlen(Tasks[TaskID]->Reward) != 0) @@ -2787,7 +2819,7 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN TaskDescriptionData2_Struct* tdd2; TaskDescriptionTrailer_Struct* tdt; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TaskDescription, PacketLength); + auto outapp = new EQApplicationPacket(OP_TaskDescription, PacketLength); tdh = (TaskDescriptionHeader_Struct*)outapp->pBuffer; @@ -2906,7 +2938,7 @@ void ClientTaskState::CancelAllTasks(Client *c) { } void ClientTaskState::CancelTask(Client *c, int SequenceNumber, bool RemoveFromDB) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_CancelTask, sizeof(CancelTask_Struct)); + auto outapp = new EQApplicationPacket(OP_CancelTask, sizeof(CancelTask_Struct)); CancelTask_Struct* cts = (CancelTask_Struct*)outapp->pBuffer; cts->SequenceNumber = SequenceNumber; @@ -2948,7 +2980,7 @@ void ClientTaskState::RemoveTask(Client *c, int sequenceNumber) { } -void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID) { +void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement) { if(!taskmanager || TaskID<0 || TaskID>=MAXTASKS) { c->Message(13, "Task system not functioning, or TaskID %i out of range.", TaskID); @@ -2973,6 +3005,12 @@ void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID) { } } + if (enforce_level_requirement && !taskmanager->AppropriateLevel(TaskID, c->GetLevel())) + { + c->Message(13, "You are outside the level range of this task."); + return; + } + if(!taskmanager->IsTaskRepeatable(TaskID) && IsTaskCompleted(TaskID)) return; // We do it this way, because when the Client cancels a task, it retains the sequence number of the remaining @@ -3019,7 +3057,7 @@ void ClientTaskState::AcceptNewTask(Client *c, int TaskID, int NPCID) { NPC *npc = entity_list.GetID(NPCID)->CastToNPC(); if(!npc) { c->Message(clientMessageYellow, "Task Giver ID is %i", NPCID); - c->Message(clientMessageError, "Unable to find NPC to send EVENT_TASKACCEPTD to. Report this bug."); + c->Message(clientMessageError, "Unable to find NPC to send EVENT_TASKACCEPTED to. Report this bug."); safe_delete_array(buf); return; } diff --git a/zone/tasks.h b/zone/tasks.h index c525bbcd8..9b5543b3d 100644 --- a/zone/tasks.h +++ b/zone/tasks.h @@ -22,6 +22,7 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net) #include "../common/types.h" +#include #include #define MAXTASKS 10000 @@ -44,6 +45,7 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net) class Client; class Mob; +class ItemInst; struct TaskGoalList_Struct { int ListID; @@ -168,7 +170,7 @@ public: int GetTaskActivityDoneCount(int index, int ActivityID); int GetTaskActivityDoneCountFromTaskID(int TaskID, int ActivityID); int GetTaskStartTime(int index); - void AcceptNewTask(Client *c, int TaskID, int NPCID); + void AcceptNewTask(Client *c, int TaskID, int NPCID, bool enforce_level_requirement = false); void FailTask(Client *c, int TaskID); int TaskTimeLeft(int TaskID); int IsTaskCompleted(int TaskID); @@ -185,7 +187,7 @@ public: void UpdateTasksForItem(Client *c, ActivityType Type, int ItemID, int Count=1); void UpdateTasksOnExplore(Client *c, int ExploreID); bool UpdateTasksOnSpeakWith(Client *c, int NPCTypeID); - bool UpdateTasksOnDeliver(Client *c, uint32 *Items, int Cash, int NPCTypeID); + bool UpdateTasksOnDeliver(Client *c, std::list& Items, int Cash, int NPCTypeID); void UpdateTasksOnTouch(Client *c, int ZoneID); void ProcessTaskProximities(Client *c, float X, float Y, float Z); bool TaskOutOfTime(int Index); @@ -230,6 +232,8 @@ public: void SendTaskSelector(Client *c, Mob *mob, int TaskCount, int *TaskList); void SendTaskSelectorNew(Client *c, Mob *mob, int TaskCount, int *TaskList); bool AppropriateLevel(int TaskID, int PlayerLevel); + int GetTaskMinLevel(int TaskID); + int GetTaskMaxLevel(int TaskID); void TaskSetSelector(Client *c, ClientTaskState *state, Mob *mob, int TaskSetID); void SendActiveTasksToClient(Client *c, bool TaskComplete=false); void SendSingleActiveTaskToClient(Client *c, int TaskIndex, bool TaskComplete, bool BringUpTaskJournal=false); diff --git a/zone/titles.cpp b/zone/titles.cpp index 3a4162060..388f12997 100644 --- a/zone/titles.cpp +++ b/zone/titles.cpp @@ -46,7 +46,7 @@ bool TitleManager::LoadTitles() for (auto row = results.begin(); row != results.end(); ++row) { TitleEntry Title; Title.TitleID = atoi(row[0]); - Title.SkillID = (SkillUseTypes) atoi(row[1]); + Title.SkillID = (EQEmu::skills::SkillType) atoi(row[1]); Title.MinSkillValue = atoi(row[2]); Title.MaxSkillValue = atoi(row[3]); Title.MinAAPoints = atoi(row[4]); @@ -91,7 +91,7 @@ EQApplicationPacket *TitleManager::MakeTitlesPacket(Client *c) } - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SendTitleList, Length); + auto outapp = new EQApplicationPacket(OP_SendTitleList, Length); char *Buffer = (char *)outapp->pBuffer; @@ -179,18 +179,18 @@ bool TitleManager::IsClientEligibleForTitle(Client *c, std::vector:: if((Title->Class >= 0) && (c->GetBaseClass() != Title->Class)) return false; - if((Title->MinAAPoints >= 0) && (c->GetAAPointsSpent() < static_cast(Title->MinAAPoints))) + if((Title->MinAAPoints >= 0) && (c->GetSpentAA() < static_cast(Title->MinAAPoints))) return false; - if((Title->MaxAAPoints >= 0) && (c->GetAAPointsSpent() > static_cast(Title->MaxAAPoints))) + if((Title->MaxAAPoints >= 0) && (c->GetSpentAA() > static_cast(Title->MaxAAPoints))) return false; if(Title->SkillID >= 0) { - if((Title->MinSkillValue >= 0) && (c->GetRawSkill(static_cast(Title->SkillID)) < static_cast(Title->MinSkillValue))) + if ((Title->MinSkillValue >= 0) && (c->GetRawSkill(static_cast(Title->SkillID)) < static_cast(Title->MinSkillValue))) return false; - if((Title->MaxSkillValue >= 0) && (c->GetRawSkill(static_cast(Title->SkillID)) > static_cast(Title->MaxSkillValue))) + if ((Title->MaxSkillValue >= 0) && (c->GetRawSkill(static_cast(Title->SkillID)) > static_cast(Title->MaxSkillValue))) return false; } @@ -243,7 +243,7 @@ void TitleManager::CreateNewPlayerTitle(Client *client, const char *title) if(!client || !title) return; - char *escTitle = new char[strlen(title) * 2 + 1]; + auto escTitle = new char[strlen(title) * 2 + 1]; client->SetAATitle(title); @@ -265,7 +265,7 @@ void TitleManager::CreateNewPlayerTitle(Client *client, const char *title) return; } - ServerPacket* pack = new ServerPacket(ServerOP_ReloadTitles, 0); + auto pack = new ServerPacket(ServerOP_ReloadTitles, 0); worldserver.SendPacket(pack); safe_delete(pack); } @@ -277,8 +277,8 @@ void TitleManager::CreateNewPlayerSuffix(Client *client, const char *suffix) client->SetTitleSuffix(suffix); - char *escSuffix = new char[strlen(suffix) * 2 + 1]; - database.DoEscapeString(escSuffix, suffix, strlen(suffix)); + auto escSuffix = new char[strlen(suffix) * 2 + 1]; + database.DoEscapeString(escSuffix, suffix, strlen(suffix)); std::string query = StringFormat("SELECT `id` FROM titles " "WHERE `suffix` = '%s' AND char_id = %i", @@ -297,7 +297,7 @@ void TitleManager::CreateNewPlayerSuffix(Client *client, const char *suffix) return; } - ServerPacket* pack = new ServerPacket(ServerOP_ReloadTitles, 0); + auto pack = new ServerPacket(ServerOP_ReloadTitles, 0); worldserver.SendPacket(pack); safe_delete(pack); } @@ -306,7 +306,7 @@ void Client::SetAATitle(const char *Title) { strn0cpy(m_pp.title, Title, sizeof(m_pp.title)); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SetTitleReply, sizeof(SetTitleReply_Struct)); + auto outapp = new EQApplicationPacket(OP_SetTitleReply, sizeof(SetTitleReply_Struct)); SetTitleReply_Struct *strs = (SetTitleReply_Struct *)outapp->pBuffer; @@ -323,7 +323,7 @@ void Client::SetTitleSuffix(const char *Suffix) { strn0cpy(m_pp.suffix, Suffix, sizeof(m_pp.suffix)); - EQApplicationPacket *outapp = new EQApplicationPacket(OP_SetTitleReply, sizeof(SetTitleReply_Struct)); + auto outapp = new EQApplicationPacket(OP_SetTitleReply, sizeof(SetTitleReply_Struct)); SetTitleReply_Struct *strs = (SetTitleReply_Struct *)outapp->pBuffer; diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index 07ae6d2a5..6deb51778 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -36,7 +36,7 @@ extern QueryServ* QServ; -static const SkillUseTypes TradeskillUnknown = Skill1HBlunt; /* an arbitrary non-tradeskill */ +static const EQEmu::skills::SkillType TradeskillUnknown = EQEmu::skills::Skill1HBlunt; /* an arbitrary non-tradeskill */ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augment, Object *worldo) { @@ -61,15 +61,15 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme inst = user_inv.GetItem(in_augment->container_slot); if (inst) { - const Item_Struct* item = inst->GetItem(); - if (item && inst->IsType(ItemClassContainer) && item->BagType == 53) + const EQEmu::ItemBase* item = inst->GetItem(); + if (item && inst->IsType(EQEmu::item::ItemClassBag) && item->BagType == 53) { // We have found an appropriate inventory augmentation sealer container = inst; // Verify that no more than two items are in container to guarantee no inadvertant wipes. uint8 itemsFound = 0; - for (uint8 i = MAIN_BEGIN; i < EmuConstants::MAP_WORLD_SIZE; i++) + for (uint8 i = SLOT_BEGIN; i < EQEmu::legacy::TYPE_WORLD_SIZE; i++) { const ItemInst* inst = container->GetItem(i); if (inst) @@ -166,25 +166,34 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme else { ItemInst *old_aug = nullptr; - const uint32 id = auged_with->GetID(); + bool isSolvent = auged_with->GetItem()->ItemType == EQEmu::item::ItemTypeAugmentationSolvent; + if (!isSolvent && auged_with->GetItem()->ItemType != EQEmu::item::ItemTypeAugmentationDistiller) + { + Log.Out(Logs::General, Logs::Error, "Player tried to remove an augment without a solvent or distiller."); + user->Message(13, "Error: Missing an augmentation solvent or distiller for removing this augment."); + + return; + } + ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_slot); - if(aug) { + if (aug) { + if (!isSolvent && auged_with->GetItem()->ID != aug->GetItem()->AugDistiller) + { + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with the wrong distiller (item %u vs expected %u).", auged_with->GetItem()->ID, aug->GetItem()->AugDistiller); + user->Message(13, "Error: Wrong augmentation distiller for safely removing this augment."); + return; + } std::vector args; args.push_back(aug); parse->EventItem(EVENT_UNAUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args); args.assign(1, tobe_auged); - bool destroyed = false; - if(id == 40408 || id == 40409 || id == 40410) { - destroyed = true; - } - - args.push_back(&destroyed); + args.push_back(&isSolvent); parse->EventItem(EVENT_AUGMENT_REMOVE, user, aug, nullptr, "", slot, &args); } - if(id == 40408 || id == 40409 || id == 40410) + if (isSolvent) tobe_auged->DeleteAugment(in_augment->augment_slot); else old_aug = tobe_auged->RemoveAugment(in_augment->augment_slot); @@ -203,7 +212,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme if (worldo) { container->Clear(); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ClearObject, sizeof(ClearObject_Struct)); + auto outapp = new EQApplicationPacket(OP_ClearObject, sizeof(ClearObject_Struct)); ClearObject_Struct *cos = (ClearObject_Struct *)outapp->pBuffer; cos->Clear = 1; user->QueuePacket(outapp); @@ -213,7 +222,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme else { // Delete items in our inventory container... - for (uint8 i = MAIN_BEGIN; i < EmuConstants::MAP_WORLD_SIZE; i++) + for (uint8 i = SLOT_BEGIN; i < EQEmu::legacy::TYPE_WORLD_SIZE; i++) { const ItemInst* inst = container->GetItem(i); if (inst) @@ -255,7 +264,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob uint32 some_id = 0; bool worldcontainer=false; - if (in_combine->container_slot == legacy::SLOT_TRADESKILL) { + if (in_combine->container_slot == EQEmu::legacy::SLOT_TRADESKILL) { if(!worldo) { user->Message(13, "Error: Server is not aware of the tradeskill container you are attempting to use"); return; @@ -267,28 +276,28 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob else { inst = user_inv.GetItem(in_combine->container_slot); if (inst) { - const Item_Struct* item = inst->GetItem(); - if (item && inst->IsType(ItemClassContainer)) { + const EQEmu::ItemBase* item = inst->GetItem(); + if (item && inst->IsType(EQEmu::item::ItemClassBag)) { c_type = item->BagType; some_id = item->ID; } } } - if (!inst || !inst->IsType(ItemClassContainer)) { + if (!inst || !inst->IsType(EQEmu::item::ItemClassBag)) { user->Message(13, "Error: Server does not recognize specified tradeskill container"); return; } container = inst; - if (container->GetItem() && container->GetItem()->BagType == BagTypeTransformationmold) { + if (container->GetItem() && container->GetItem()->BagType == EQEmu::item::BagTypeTransformationmold) { const ItemInst* inst = container->GetItem(0); bool AllowAll = RuleB(Inventory, AllowAnyWeaponTransformation); if (inst && ItemInst::CanTransform(inst->GetItem(), container->GetItem(), AllowAll)) { - const Item_Struct* new_weapon = inst->GetItem(); + const EQEmu::ItemBase* new_weapon = inst->GetItem(); user->DeleteItemInInventory(Inventory::CalcSlotId(in_combine->container_slot, 0), 0, true); container->Clear(); - user->SummonItem(new_weapon->ID, inst->GetCharges(), inst->GetAugmentItemID(0), inst->GetAugmentItemID(1), inst->GetAugmentItemID(2), inst->GetAugmentItemID(3), inst->GetAugmentItemID(4), inst->GetAugmentItemID(5), inst->IsAttuned(), MainCursor, container->GetItem()->Icon, atoi(container->GetItem()->IDFile + 2)); + user->SummonItem(new_weapon->ID, inst->GetCharges(), inst->GetAugmentItemID(0), inst->GetAugmentItemID(1), inst->GetAugmentItemID(2), inst->GetAugmentItemID(3), inst->GetAugmentItemID(4), inst->GetAugmentItemID(5), inst->IsAttuned(), EQEmu::legacy::SlotCursor, container->GetItem()->Icon, atoi(container->GetItem()->IDFile + 2)); user->Message_StringID(4, TRANSFORM_COMPLETE, inst->GetItem()->Name); if (RuleB(Inventory, DeleteTransformationMold)) user->DeleteItemInInventory(in_combine->container_slot, 0, true); @@ -296,25 +305,25 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob else if (inst) { user->Message_StringID(4, TRANSFORM_FAILED, inst->GetItem()->Name); } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); + auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); user->QueuePacket(outapp); safe_delete(outapp); return; } - if (container->GetItem() && container->GetItem()->BagType == BagTypeDetransformationmold) { + if (container->GetItem() && container->GetItem()->BagType == EQEmu::item::BagTypeDetransformationmold) { const ItemInst* inst = container->GetItem(0); if (inst && inst->GetOrnamentationIcon() && inst->GetOrnamentationIcon()) { - const Item_Struct* new_weapon = inst->GetItem(); + const EQEmu::ItemBase* new_weapon = inst->GetItem(); user->DeleteItemInInventory(Inventory::CalcSlotId(in_combine->container_slot, 0), 0, true); container->Clear(); - user->SummonItem(new_weapon->ID, inst->GetCharges(), inst->GetAugmentItemID(0), inst->GetAugmentItemID(1), inst->GetAugmentItemID(2), inst->GetAugmentItemID(3), inst->GetAugmentItemID(4), inst->GetAugmentItemID(5), inst->IsAttuned(), MainCursor, 0, 0); + user->SummonItem(new_weapon->ID, inst->GetCharges(), inst->GetAugmentItemID(0), inst->GetAugmentItemID(1), inst->GetAugmentItemID(2), inst->GetAugmentItemID(3), inst->GetAugmentItemID(4), inst->GetAugmentItemID(5), inst->IsAttuned(), EQEmu::legacy::SlotCursor, 0, 0); user->Message_StringID(4, TRANSFORM_COMPLETE, inst->GetItem()->Name); } else if (inst) { user->Message_StringID(4, DETRANSFORM_FAILED, inst->GetItem()->Name); } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); + auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); user->QueuePacket(outapp); safe_delete(outapp); return; @@ -323,7 +332,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob DBTradeskillRecipe_Struct spec; if (!database.GetTradeRecipe(container, c_type, some_id, user->CharacterID(), &spec)) { user->Message_StringID(MT_Emote,TRADESKILL_NOCOMBINE); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); + auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); user->QueuePacket(outapp); safe_delete(outapp); return; @@ -338,7 +347,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob if ((spec.must_learn&0xF) == 1 && !spec.has_learnt) { // Made up message for the client. Just giving a DNC is the other option. user->Message(4, "You need to learn how to combine these first."); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); + auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); user->QueuePacket(outapp); safe_delete(outapp); return; @@ -347,14 +356,14 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob if(spec.skill_needed > 0 && user->GetSkill(spec.tradeskill) < spec.skill_needed ) { // Notify client. user->Message(4, "You are not skilled enough."); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); + auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); user->QueuePacket(outapp); safe_delete(outapp); return; } //changing from a switch to string of if's since we don't need to iterate through all of the skills in the SkillType enum - if (spec.tradeskill == SkillAlchemy) { + if (spec.tradeskill == EQEmu::skills::SkillAlchemy) { if (user_pp.class_ != SHAMAN) { user->Message(13, "This tradeskill can only be performed by a shaman."); return; @@ -364,13 +373,13 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob return; } } - else if (spec.tradeskill == SkillTinkering) { + else if (spec.tradeskill == EQEmu::skills::SkillTinkering) { if (user_pp.race != GNOME) { user->Message(13, "Only gnomes can tinker."); return; } } - else if (spec.tradeskill == SkillMakePoison) { + else if (spec.tradeskill == EQEmu::skills::SkillMakePoison) { if (user_pp.class_ != ROGUE) { user->Message(13, "Only rogues can mix poisons."); return; @@ -378,7 +387,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob } // Send acknowledgement packets to client - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); + auto outapp = new EQApplicationPacket(OP_TradeSkillCombine, 0); user->QueuePacket(outapp); safe_delete(outapp); @@ -392,7 +401,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob safe_delete(outapp); database.DeleteWorldContainer(worldo->m_id, zone->GetZoneID()); } else{ - for (uint8 i = MAIN_BEGIN; i < EmuConstants::MAP_WORLD_SIZE; i++) { + for (uint8 i = SLOT_BEGIN; i < EQEmu::legacy::TYPE_WORLD_SIZE; i++) { const ItemInst* inst = container->GetItem(i); if (inst) { user->DeleteItemInInventory(Inventory::CalcSlotId(in_combine->container_slot,i),0,true); @@ -432,7 +441,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac) { //get our packet ready, gotta send one no matter what... - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RecipeAutoCombine, sizeof(RecipeAutoCombine_Struct)); + auto outapp = new EQApplicationPacket(OP_RecipeAutoCombine, sizeof(RecipeAutoCombine_Struct)); RecipeAutoCombine_Struct *outp = (RecipeAutoCombine_Struct *)outapp->pBuffer; outp->object_type = rac->object_type; outp->some_id = rac->some_id; @@ -527,9 +536,8 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac user->Message_StringID(MT_Skills, TRADESKILL_MISSING_COMPONENTS); - for(std::list::iterator it = MissingItems.begin(); it != MissingItems.end(); ++it) - { - const Item_Struct* item = database.GetItem(*it); + for (auto it = MissingItems.begin(); it != MissingItems.end(); ++it) { + const EQEmu::ItemBase* item = database.GetItem(*it); if(item) user->Message_StringID(MT_Skills, TRADESKILL_MISSING_ITEM, item->Name); @@ -596,82 +604,92 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac parse->EventPlayer(EVENT_COMBINE_FAILURE, user, spec.name.c_str(), spec.recipe_id); } -SkillUseTypes Object::TypeToSkill(uint32 type) +EQEmu::skills::SkillType Object::TypeToSkill(uint32 type) { - switch(type) // grouped and ordered by SkillUseTypes name - new types need to be verified for proper SkillUseTypes and use - { + switch(type) { // grouped and ordered by SkillUseTypes name - new types need to be verified for proper SkillUseTypes and use /*SkillAlchemy*/ - case BagTypeMedicineBag: { return SkillAlchemy; } + case EQEmu::item::BagTypeMedicineBag: + return EQEmu::skills::SkillAlchemy; /*SkillBaking*/ - // case BagTypeMixingBowl: // No idea... - case BagTypeOven: { return SkillBaking; } + //case EQEmu::item::BagTypeMixingBowl: // No idea... + case EQEmu::item::BagTypeOven: + return EQEmu::skills::SkillBaking; /*SkillBlacksmithing*/ - case BagTypeForge: - // case BagTypeKoadaDalForge: - case BagTypeTeirDalForge: - case BagTypeOggokForge: - case BagTypeStormguardForge: - // case BagTypeAkanonForge: - // case BagTypeNorthmanForge: - // case BagTypeCabilisForge: - // case BagTypeFreeportForge: - // case BagTypeRoyalQeynosForge: - // case BagTypeTrollForge: - case BagTypeFierDalForge: - case BagTypeValeForge: { return SkillBlacksmithing; } // Delete return if BagTypeGuktaForge enabled - // case BagTypeErudForge: - // case BagTypeGuktaForge: { return SkillBlacksmithing; } + case EQEmu::item::BagTypeForge: + //case EQEmu::item::BagTypeKoadaDalForge: + case EQEmu::item::BagTypeTeirDalForge: + case EQEmu::item::BagTypeOggokForge: + case EQEmu::item::BagTypeStormguardForge: + //case EQEmu::item::BagTypeAkanonForge: + //case EQEmu::item::BagTypeNorthmanForge: + //case EQEmu::item::BagTypeCabilisForge: + //case EQEmu::item::BagTypeFreeportForge: + //case EQEmu::item::BagTypeRoyalQeynosForge: + //case EQEmu::item::BagTypeTrollForge: + case EQEmu::item::BagTypeFierDalForge: + case EQEmu::item::BagTypeValeForge: + //case EQEmu::item::BagTypeErudForge: + //case EQEmu::item::BagTypeGuktaForge: + return EQEmu::skills::SkillBlacksmithing; /*SkillBrewing*/ - // case BagTypeIceCreamChurn: // No idea... - case BagTypeBrewBarrel: { return SkillBrewing; } + //case EQEmu::item::BagTypeIceCreamChurn: // No idea... + case EQEmu::item::BagTypeBrewBarrel: + return EQEmu::skills::SkillBrewing; /*SkillFishing*/ - case BagTypeTackleBox: { return SkillFishing; } + case EQEmu::item::BagTypeTackleBox: + return EQEmu::skills::SkillFishing; /*SkillFletching*/ - case BagTypeFletchingKit: { return SkillFletching; } // Delete return if BagTypeFierDalFletchingKit enabled - // case BagTypeFierDalFletchingKit: { return SkillFletching; } + case EQEmu::item::BagTypeFletchingKit: + //case EQEmu::item::BagTypeFierDalFletchingKit: + return EQEmu::skills::SkillFletching; /*SkillJewelryMaking*/ - case BagTypeJewelersKit: { return SkillJewelryMaking; } + case EQEmu::item::BagTypeJewelersKit: + return EQEmu::skills::SkillJewelryMaking; /*SkillMakePoison*/ - // This is a guess and needs to be verified... (Could be SkillAlchemy) - // case BagTypeMortar: { return SkillMakePoison; } + // This is a guess and needs to be verified... (Could be SkillAlchemy) + //case EQEmu::item::BagTypeMortar: + // return SkillMakePoison; /*SkillPottery*/ - case BagTypePotteryWheel: - case BagTypeKiln: { return SkillPottery; } // Delete return if BagTypeIksarPotteryWheel enabled - // case BagTypeIksarPotteryWheel: { return SkillPottery; } + case EQEmu::item::BagTypePotteryWheel: + case EQEmu::item::BagTypeKiln: + //case EQEmu::item::BagTypeIksarPotteryWheel: + return EQEmu::skills::SkillPottery; /*SkillResearch*/ - // case BagTypeLexicon: - case BagTypeWizardsLexicon: - case BagTypeMagesLexicon: - case BagTypeNecromancersLexicon: - case BagTypeEnchantersLexicon: { return SkillResearch; } // Delete return if BagTypeConcordanceofResearch enabled - // case BagTypeConcordanceofResearch: { return SkillResearch; } + //case EQEmu::item::BagTypeLexicon: + case EQEmu::item::BagTypeWizardsLexicon: + case EQEmu::item::BagTypeMagesLexicon: + case EQEmu::item::BagTypeNecromancersLexicon: + case EQEmu::item::BagTypeEnchantersLexicon: + //case EQEmu::item::BagTypeConcordanceofResearch: + return EQEmu::skills::SkillResearch; /*SkillTailoring*/ - case BagTypeSewingKit: { return SkillTailoring; } // Delete return if BagTypeFierDalTailoringKit enabled - // case BagTypeHalflingTailoringKit: - // case BagTypeErudTailoringKit: - // case BagTypeFierDalTailoringKit: { return SkillTailoring; } + case EQEmu::item::BagTypeSewingKit: + //case EQEmu::item::BagTypeHalflingTailoringKit: + //case EQEmu::item::BagTypeErudTailoringKit: + //case EQEmu::item::BagTypeFierDalTailoringKit: + return EQEmu::skills::SkillTailoring; /*SkillTinkering*/ - case BagTypeToolBox: { return SkillTinkering; } + case EQEmu::item::BagTypeToolBox: + return EQEmu::skills::SkillTinkering; /*Undefined*/ - default: { break; } + default: + return TradeskillUnknown; } - - return TradeskillUnknown; } -void Client::TradeskillSearchResults(const std::string query, unsigned long objtype, unsigned long someid) { +void Client::TradeskillSearchResults(const std::string &query, unsigned long objtype, unsigned long someid) { auto results = database.QueryDatabase(query); if (!results.Success()) { @@ -700,11 +718,11 @@ void Client::TradeskillSearchResults(const std::string query, unsigned long objt // Recipes that have either been made before or were // explicitly learned are excempt from that limit if (RuleB(Skills, UseLimitTradeskillSearchSkillDiff) - && ((int32)trivial - (int32)GetSkill((SkillUseTypes)tradeskill)) > RuleI(Skills, MaxTradeskillSearchSkillDiff) + && ((int32)trivial - (int32)GetSkill((EQEmu::skills::SkillType)tradeskill)) > RuleI(Skills, MaxTradeskillSearchSkillDiff) && row[4] == nullptr) continue; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RecipeReply, sizeof(RecipeReply_Struct)); + auto outapp = new EQApplicationPacket(OP_RecipeReply, sizeof(RecipeReply_Struct)); RecipeReply_Struct *reply = (RecipeReply_Struct *) outapp->pBuffer; reply->object_type = objtype; @@ -743,7 +761,7 @@ void Client::SendTradeskillDetails(uint32 recipe_id) { //biggest this packet can ever be: // 64 * 10 + 8 * 10 + 4 + 4 * 10 = 764 - char *buf = new char[775]; //dynamic so we can just give it to EQApplicationPacket + auto buf = new char[775]; // dynamic so we can just give it to EQApplicationPacket uint8 r,k; uint32 *header = (uint32 *) buf; @@ -816,7 +834,7 @@ void Client::SendTradeskillDetails(uint32 recipe_id) { uint32 total = sizeof(uint32) + dist + datalen; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RecipeDetails); + auto outapp = new EQApplicationPacket(OP_RecipeDetails); outapp->size = total; outapp->pBuffer = (uchar*) buf; QueuePacket(outapp); @@ -849,18 +867,35 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) { // If you want to customize the stage1 success rate do it here. // Remember: skillup_modifier is (float). Lower is better switch(spec->tradeskill) { - case SkillFletching: - case SkillAlchemy: - case SkillJewelryMaking: - case SkillPottery: - skillup_modifier = 4; + case EQEmu::skills::SkillFletching: + skillup_modifier = RuleI(Character, TradeskillUpFletching); break; - case SkillBaking: - case SkillBrewing: - skillup_modifier = 3; + case EQEmu::skills::SkillAlchemy: + skillup_modifier = RuleI(Character, TradeskillUpAlchemy); break; - case SkillResearch: - skillup_modifier = 1; + case EQEmu::skills::SkillJewelryMaking: + skillup_modifier = RuleI(Character, TradeskillUpJewelcrafting); + break; + case EQEmu::skills::SkillPottery: + skillup_modifier = RuleI(Character, TradeskillUpPottery); + break; + case EQEmu::skills::SkillBaking: + skillup_modifier = RuleI(Character, TradeskillUpBaking); + break; + case EQEmu::skills::SkillBrewing: + skillup_modifier = RuleI(Character, TradeskillUpBrewing); + break; + case EQEmu::skills::SkillBlacksmithing: + skillup_modifier = RuleI(Character, TradeskillUpBlacksmithing); + break; + case EQEmu::skills::SkillResearch: + skillup_modifier = RuleI(Character, TradeskillUpResearch); + break; + case EQEmu::skills::SkillMakePoison: + skillup_modifier = RuleI(Character, TradeskillUpMakePoison); + break; + case EQEmu::skills::SkillTinkering: + skillup_modifier = RuleI(Character, TradeskillUpTinkering); break; default: skillup_modifier = 2; @@ -870,10 +905,11 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) { // Some tradeskills take the higher of one additional stat beside INT and WIS // to determine the skillup rate. Additionally these tradeskills do not have an // -15 modifier on their statbonus. - if (spec->tradeskill == SkillFletching || spec->tradeskill == SkillMakePoison) { + if (spec->tradeskill == EQEmu::skills::SkillFletching || spec->tradeskill == EQEmu::skills::SkillMakePoison) { thirdstat = GetDEX(); stat_modifier = 0; - } else if (spec->tradeskill == SkillBlacksmithing) { + } + else if (spec->tradeskill == EQEmu::skills::SkillBlacksmithing) { thirdstat = GetSTR(); stat_modifier = 0; } @@ -924,135 +960,10 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) { float res = zone->random.Real(0, 99); int aa_chance = 0; - //AA modifiers - //can we do this with nested switches? - if(spec->tradeskill == SkillAlchemy){ - switch(GetAA(aaAlchemyMastery)){ - case 1: - aa_chance = 10; - break; - case 2: - aa_chance = 25; - break; - case 3: - aa_chance = 50; - break; - } - } - - if(spec->tradeskill == SkillJewelryMaking){ - switch(GetAA(aaJewelCraftMastery)){ - case 1: - aa_chance = 10; - break; - case 2: - aa_chance = 25; - break; - case 3: - aa_chance = 50; - break; - } - } - const Item_Struct* item = nullptr; - - if (spec->tradeskill == SkillBlacksmithing) { - switch(GetAA(aaBlacksmithingMastery)) { - case 1: - aa_chance = 10; - break; - case 2: - aa_chance = 25; - break; - case 3: - aa_chance = 50; - break; - } - } - - if (spec->tradeskill == SkillBaking) { - switch(GetAA(aaBakingMastery)) { - case 1: - aa_chance = 10; - break; - case 2: - aa_chance = 25; - break; - case 3: - aa_chance = 50; - break; - } - } - - if (spec->tradeskill == SkillBrewing) { - switch(GetAA(aaBrewingMastery)) { - case 1: - aa_chance = 10; - break; - case 2: - aa_chance = 25; - break; - case 3: - aa_chance = 50; - break; - } - } - - if (spec->tradeskill == SkillFletching) { - switch(GetAA(aaFletchingMastery2)) { - case 1: - aa_chance = 10; - break; - case 2: - aa_chance = 25; - break; - case 3: - aa_chance = 50; - break; - } - } - - if (spec->tradeskill == SkillPottery) { - switch(GetAA(aaPotteryMastery)) { - case 1: - aa_chance = 10; - break; - case 2: - aa_chance = 25; - break; - case 3: - aa_chance = 50; - break; - } - } - - if (spec->tradeskill == SkillTailoring) { - switch(GetAA(aaTailoringMastery)) { - case 1: - aa_chance = 10; - break; - case 2: - aa_chance = 25; - break; - case 3: - aa_chance = 50; - break; - } - } - - if (spec->tradeskill == SkillResearch) { - switch(GetAA(aaArcaneTongues)) { - case 1: - aa_chance = 10; - break; - case 2: - aa_chance = 25; - break; - case 3: - aa_chance = 50; - break; - } - } + aa_chance = spellbonuses.ReduceTradeskillFail[spec->tradeskill] + itembonuses.ReduceTradeskillFail[spec->tradeskill] + aabonuses.ReduceTradeskillFail[spec->tradeskill]; + const EQEmu::ItemBase* item = nullptr; + chance = mod_tradeskill_chance(chance, spec); if (((spec->tradeskill==75) || GetGM() || (chance > res)) || zone->random.Roll(aa_chance)) { @@ -1135,7 +1046,7 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) { return(false); } -void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, SkillUseTypes tradeskill) +void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, EQEmu::skills::SkillType tradeskill) { uint16 current_raw_skill = GetRawSkill(tradeskill); @@ -1202,7 +1113,7 @@ bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint3 if (!inst) continue; - const Item_Struct* item = GetItem(inst->GetItem()->ID); + const EQEmu::ItemBase* item = GetItem(inst->GetItem()->ID); if (!item) continue; @@ -1326,12 +1237,12 @@ bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint3 for (auto row = results.begin(); row != results.end(); ++row) { int ccnt = 0; - for(int x = MAIN_BEGIN; x < EmuConstants::MAP_WORLD_SIZE; x++) { + for (int x = SLOT_BEGIN; x < EQEmu::legacy::TYPE_WORLD_SIZE; x++) { const ItemInst* inst = container->GetItem(x); if(!inst) continue; - const Item_Struct* item = GetItem(inst->GetItem()->ID); + const EQEmu::ItemBase* item = GetItem(inst->GetItem()->ID); if (!item) continue; @@ -1380,7 +1291,7 @@ bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id return false;//just not found i guess.. auto row = results.begin(); - spec->tradeskill = (SkillUseTypes)atoi(row[1]); + spec->tradeskill = (EQEmu::skills::SkillType)atoi(row[1]); spec->skill_needed = (int16)atoi(row[2]); spec->trivial = (uint16)atoi(row[3]); spec->nofail = atoi(row[4]) ? true : false; @@ -1406,7 +1317,7 @@ bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id return false; } - if(results.RowCount() < 1) { + if(results.RowCount() < 1 && !spec->quest) { Log.Out(Logs::General, Logs::Error, "Error in GetTradeRecept success: no success items returned"); return false; } @@ -1496,42 +1407,43 @@ void Client::LearnRecipe(uint32 recipeID) results = database.QueryDatabase(query); } -bool Client::CanIncreaseTradeskill(SkillUseTypes tradeskill) { +bool Client::CanIncreaseTradeskill(EQEmu::skills::SkillType tradeskill) { uint32 rawskill = GetRawSkill(tradeskill); uint16 maxskill = MaxSkill(tradeskill); if (rawskill >= maxskill) //Max skill sanity check return false; - uint8 Baking = (GetRawSkill(SkillBaking) > 200) ? 1 : 0; - uint8 Smithing = (GetRawSkill(SkillBlacksmithing) > 200) ? 1 : 0; - uint8 Brewing = (GetRawSkill(SkillBrewing) > 200) ? 1 : 0; - uint8 Fletching = (GetRawSkill(SkillFletching) > 200) ? 1 : 0; - uint8 Jewelry = (GetRawSkill(SkillJewelryMaking) > 200) ? 1 : 0; - uint8 Pottery = (GetRawSkill(SkillPottery) > 200) ? 1 : 0; - uint8 Tailoring = (GetRawSkill(SkillTailoring) > 200) ? 1 : 0; + uint8 Baking = (GetRawSkill(EQEmu::skills::SkillBaking) > 200) ? 1 : 0; + uint8 Smithing = (GetRawSkill(EQEmu::skills::SkillBlacksmithing) > 200) ? 1 : 0; + uint8 Brewing = (GetRawSkill(EQEmu::skills::SkillBrewing) > 200) ? 1 : 0; + uint8 Fletching = (GetRawSkill(EQEmu::skills::SkillFletching) > 200) ? 1 : 0; + uint8 Jewelry = (GetRawSkill(EQEmu::skills::SkillJewelryMaking) > 200) ? 1 : 0; + uint8 Pottery = (GetRawSkill(EQEmu::skills::SkillPottery) > 200) ? 1 : 0; + uint8 Tailoring = (GetRawSkill(EQEmu::skills::SkillTailoring) > 200) ? 1 : 0; uint8 SkillTotal = Baking + Smithing + Brewing + Fletching + Jewelry + Pottery + Tailoring; //Tradeskills above 200 - uint32 aaLevel = GetAA(aaNewTanaanCraftingMastery); //New Tanaan AA: Each level allows an additional tradeskill above 200 (first one is free) - + //New Tanaan AA: Each level allows an additional tradeskill above 200 (first one is free) + uint8 aaLevel = spellbonuses.TradeSkillMastery + itembonuses.TradeSkillMastery + aabonuses.TradeSkillMastery; + switch (tradeskill) { - case SkillBaking: - case SkillBlacksmithing: - case SkillBrewing: - case SkillFletching: - case SkillJewelryMaking: - case SkillPottery: - case SkillTailoring: - if (aaLevel == 6) - break; //Maxed AA - if (SkillTotal == 0) - break; //First tradeskill freebie - if ((SkillTotal == (aaLevel + 1)) && (rawskill > 200)) - break; //One of the tradeskills already allowed to go over 200 - if ((SkillTotal >= (aaLevel + 1)) && (rawskill >= 200)) - return false; //One or more tradeskills already at or beyond limit - break; - default: - break; //Other skills unchecked and ability to increase assumed true + case EQEmu::skills::SkillBaking: + case EQEmu::skills::SkillBlacksmithing: + case EQEmu::skills::SkillBrewing: + case EQEmu::skills::SkillFletching: + case EQEmu::skills::SkillJewelryMaking: + case EQEmu::skills::SkillPottery: + case EQEmu::skills::SkillTailoring: + if (aaLevel == 6) + break; //Maxed AA + if (SkillTotal == 0) + break; //First tradeskill freebie + if ((SkillTotal == (aaLevel + 1)) && (rawskill > 200)) + break; //One of the tradeskills already allowed to go over 200 + if ((SkillTotal >= (aaLevel + 1)) && (rawskill >= 200)) + return false; //One or more tradeskills already at or beyond limit + break; + default: + break; //Other skills unchecked and ability to increase assumed true } return true; } @@ -1544,6 +1456,8 @@ bool ZoneDatabase::EnableRecipe(uint32 recipe_id) if (!results.Success()) return results.RowsAffected() > 0; + + return false; } bool ZoneDatabase::DisableRecipe(uint32 recipe_id) @@ -1554,4 +1468,6 @@ bool ZoneDatabase::DisableRecipe(uint32 recipe_id) if (!results.Success()) return results.RowsAffected() > 0; + + return false; } diff --git a/zone/trading.cpp b/zone/trading.cpp index 0e44a91bc..aab8ac8ac 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -98,7 +98,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) { // Item always goes into trade bucket from cursor Client* client = owner->CastToClient(); - ItemInst* inst = client->GetInv().GetItem(MainCursor); + ItemInst* inst = client->GetInv().GetItem(EQEmu::legacy::SlotCursor); if (!inst) { client->Message(13, "Error: Could not find item on your cursor!"); @@ -131,7 +131,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) { if (_stack_size > 0) inst->SetCharges(_stack_size); else - client->DeleteItemInInventory(MainCursor); + client->DeleteItemInInventory(EQEmu::legacy::SlotCursor); SendItemData(inst2, trade_slot_id); } @@ -146,7 +146,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) { Log.Out(Logs::Detail, Logs::Trading, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id); client->PutItemInInventory(trade_slot_id, *inst); - client->DeleteItemInInventory(MainCursor); + client->DeleteItemInInventory(EQEmu::legacy::SlotCursor); } } @@ -171,13 +171,13 @@ void Trade::SendItemData(const ItemInst* inst, int16 dest_slot_id) Client* with = mob->CastToClient(); Client* trader = owner->CastToClient(); if (with && with->IsClient()) { - with->SendItemPacket(dest_slot_id - EmuConstants::TRADE_BEGIN, inst, ItemPacketTradeView); + with->SendItemPacket(dest_slot_id - EQEmu::legacy::TRADE_BEGIN, inst, ItemPacketTradeView); if (inst->GetItem()->ItemClass == 1) { - for (uint16 i = SUB_BEGIN; i < EmuConstants::ITEM_CONTAINER_SIZE; i++) { + for (uint16 i = SUB_INDEX_BEGIN; i < EQEmu::legacy::ITEM_CONTAINER_SIZE; i++) { uint16 bagslot_id = Inventory::CalcSlotId(dest_slot_id, i); const ItemInst* bagitem = trader->GetInv().GetItem(bagslot_id); if (bagitem) { - with->SendItemPacket(bagslot_id - EmuConstants::TRADE_BEGIN, bagitem, ItemPacketTradeView); + with->SendItemPacket(bagslot_id - EQEmu::legacy::TRADE_BEGIN, bagitem, ItemPacketTradeView); } } } @@ -199,7 +199,7 @@ void Trade::LogTrade() uint8 item_count = 0; if (zone->tradevar != 0) { - for (uint16 i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_END; i++) { + for (uint16 i = EQEmu::legacy::TRADE_BEGIN; i <= EQEmu::legacy::TRADE_END; i++) { if (trader->GetInv().GetItem(i)) item_count++; } @@ -251,7 +251,7 @@ void Trade::LogTrade() if (item_count > 0) { strcat(logtext, "items {"); - for (uint16 i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_END; i++) { + for (uint16 i = EQEmu::legacy::TRADE_BEGIN; i <= EQEmu::legacy::TRADE_END; i++) { const ItemInst* inst = trader->GetInv().GetItem(i); if (!comma) @@ -266,8 +266,8 @@ void Trade::LogTrade() sprintf(item_num, "%i", inst->GetItem()->ID); strcat(logtext, item_num); - if (inst->IsType(ItemClassContainer)) { - for (uint8 j = SUB_BEGIN; j < EmuConstants::ITEM_CONTAINER_SIZE; j++) { + if (inst->IsClassBag()) { + for (uint8 j = SUB_INDEX_BEGIN; j < EQEmu::legacy::ITEM_CONTAINER_SIZE; j++) { inst = trader->GetInv().GetItem(i, j); if (inst) { strcat(logtext, ","); @@ -303,16 +303,16 @@ void Trade::DumpTrade() return; Client* trader = owner->CastToClient(); - for (uint16 i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_END; i++) { + for (uint16 i = EQEmu::legacy::TRADE_BEGIN; i <= EQEmu::legacy::TRADE_END; i++) { const ItemInst* inst = trader->GetInv().GetItem(i); if (inst) { Log.Out(Logs::Detail, Logs::Trading, "Item %i (Charges=%i, Slot=%i, IsBag=%s)", inst->GetItem()->ID, inst->GetCharges(), - i, ((inst->IsType(ItemClassContainer)) ? "True" : "False")); + i, ((inst->IsClassBag()) ? "True" : "False")); - if (inst->IsType(ItemClassContainer)) { - for (uint8 j = SUB_BEGIN; j < EmuConstants::ITEM_CONTAINER_SIZE; j++) { + if (inst->IsClassBag()) { + for (uint8 j = SUB_INDEX_BEGIN; j < EQEmu::legacy::ITEM_CONTAINER_SIZE; j++) { inst = trader->GetInv().GetItem(i, j); if (inst) { Log.Out(Logs::Detail, Logs::Trading, "\tBagItem %i (Charges=%i, Slot=%i)", @@ -332,10 +332,10 @@ void Client::ResetTrade() { AddMoneyToPP(trade->cp, trade->sp, trade->gp, trade->pp, true); // step 1: process bags - for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + for (int16 trade_slot = EQEmu::legacy::TRADE_BEGIN; trade_slot <= EQEmu::legacy::TRADE_END; ++trade_slot) { const ItemInst* inst = m_inv[trade_slot]; - if (inst && inst->IsType(ItemClassContainer)) { + if (inst && inst->IsClassBag()) { int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst); if (free_slot != INVALID_INDEX) { @@ -351,7 +351,7 @@ void Client::ResetTrade() { } // step 2a: process stackables - for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + for (int16 trade_slot = EQEmu::legacy::TRADE_BEGIN; trade_slot <= EQEmu::legacy::TRADE_END; ++trade_slot) { ItemInst* inst = GetInv().GetItem(trade_slot); if (inst && inst->IsStackable()) { @@ -359,7 +359,7 @@ void Client::ResetTrade() { // there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks int16 free_slot = m_inv.FindFreeSlotForTradeItem(inst); - if ((free_slot == MainCursor) || (free_slot == INVALID_INDEX)) + if ((free_slot == EQEmu::legacy::SlotCursor) || (free_slot == INVALID_INDEX)) break; ItemInst* partial_inst = GetInv().GetItem(free_slot); @@ -398,11 +398,11 @@ void Client::ResetTrade() { // step 2b: adjust trade stack bias // (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur) - for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) { + for (int16 trade_slot = EQEmu::legacy::TRADE_END; trade_slot >= EQEmu::legacy::TRADE_BEGIN; --trade_slot) { ItemInst* inst = GetInv().GetItem(trade_slot); if (inst && inst->IsStackable()) { - for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) { + for (int16 bias_slot = EQEmu::legacy::TRADE_BEGIN; bias_slot <= EQEmu::legacy::TRADE_END; ++bias_slot) { if (bias_slot >= trade_slot) break; @@ -432,7 +432,7 @@ void Client::ResetTrade() { } // step 3: process everything else - for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + for (int16 trade_slot = EQEmu::legacy::TRADE_BEGIN; trade_slot <= EQEmu::legacy::TRADE_END; ++trade_slot) { const ItemInst* inst = m_inv[trade_slot]; if (inst) { @@ -487,10 +487,10 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st } // step 1: process bags - for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + for (int16 trade_slot = EQEmu::legacy::TRADE_BEGIN; trade_slot <= EQEmu::legacy::TRADE_END; ++trade_slot) { const ItemInst* inst = m_inv[trade_slot]; - if (inst && inst->IsType(ItemClassContainer)) { + if (inst && inst->IsClassBag()) { Log.Out(Logs::Detail, Logs::Trading, "Giving container %s (%d) in slot %d to %s", inst->GetItem()->Name, inst->GetItem()->ID, trade_slot, other->GetName()); // TODO: need to check bag items/augments for no drop..everything for attuned... @@ -501,7 +501,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st if (other->PutItemInInventory(free_slot, *inst, true)) { Log.Out(Logs::Detail, Logs::Trading, "Container %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID); if (qs_log) { - QSTradeItems_Struct* detail = new QSTradeItems_Struct; + auto detail = new QSTradeItems_Struct; detail->from_id = this->character_id; detail->from_slot = trade_slot; @@ -523,7 +523,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st 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 = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items + for (uint8 sub_slot = SUB_INDEX_BEGIN; (sub_slot < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items const ItemInst* bag_inst = inst->GetItem(sub_slot); if (bag_inst) { @@ -571,7 +571,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st } // step 2a: process stackables - for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + for (int16 trade_slot = EQEmu::legacy::TRADE_BEGIN; trade_slot <= EQEmu::legacy::TRADE_END; ++trade_slot) { ItemInst* inst = GetInv().GetItem(trade_slot); if (inst && inst->IsStackable()) { @@ -579,7 +579,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st // there's no built-in safety check against an infinite loop..but, it should break on one of the conditional checks int16 partial_slot = other->GetInv().FindFreeSlotForTradeItem(inst); - if ((partial_slot == MainCursor) || (partial_slot == INVALID_INDEX)) + if ((partial_slot == EQEmu::legacy::SlotCursor) || (partial_slot == INVALID_INDEX)) break; ItemInst* partial_inst = other->GetInv().GetItem(partial_slot); @@ -612,7 +612,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st Log.Out(Logs::Detail, Logs::Trading, "Partial stack %s (%d) successfully transferred, deleting %i charges from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID, (old_charges - inst->GetCharges())); if (qs_log) { - QSTradeItems_Struct* detail = new QSTradeItems_Struct; + auto detail = new QSTradeItems_Struct; detail->from_id = this->character_id; detail->from_slot = trade_slot; @@ -653,11 +653,11 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st // step 2b: adjust trade stack bias // (if any partial stacks exist before the final stack, FindFreeSlotForTradeItem() will return that slot in step 3 and an overwrite will occur) - for (int16 trade_slot = EmuConstants::TRADE_END; trade_slot >= EmuConstants::TRADE_BEGIN; --trade_slot) { + for (int16 trade_slot = EQEmu::legacy::TRADE_END; trade_slot >= EQEmu::legacy::TRADE_BEGIN; --trade_slot) { ItemInst* inst = GetInv().GetItem(trade_slot); if (inst && inst->IsStackable()) { - for (int16 bias_slot = EmuConstants::TRADE_BEGIN; bias_slot <= EmuConstants::TRADE_END; ++bias_slot) { + for (int16 bias_slot = EQEmu::legacy::TRADE_BEGIN; bias_slot <= EQEmu::legacy::TRADE_END; ++bias_slot) { if (bias_slot >= trade_slot) break; @@ -680,7 +680,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st } if (qs_log) { - QSTradeItems_Struct* detail = new QSTradeItems_Struct; + auto detail = new QSTradeItems_Struct; detail->from_id = this->character_id; detail->from_slot = trade_slot; @@ -706,7 +706,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st } // step 3: process everything else - for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_END; ++trade_slot) { + for (int16 trade_slot = EQEmu::legacy::TRADE_BEGIN; trade_slot <= EQEmu::legacy::TRADE_END; ++trade_slot) { const ItemInst* inst = m_inv[trade_slot]; if (inst) { @@ -720,7 +720,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st if (other->PutItemInInventory(free_slot, *inst, true)) { Log.Out(Logs::Detail, Logs::Trading, "Item %s (%d) successfully transferred, deleting from trade slot.", inst->GetItem()->Name, inst->GetItem()->ID); if (qs_log) { - QSTradeItems_Struct* detail = new QSTradeItems_Struct; + auto detail = new QSTradeItems_Struct; detail->from_id = this->character_id; detail->from_slot = trade_slot; @@ -743,7 +743,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st // '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 = SUB_BEGIN; (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items + for (uint8 sub_slot = SUB_INDEX_BEGIN; (sub_slot < EQEmu::legacy::ITEM_CONTAINER_SIZE); ++sub_slot) { // this is to catch ALL items const ItemInst* bag_inst = inst->GetItem(sub_slot); if (bag_inst) { @@ -820,11 +820,11 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st } if(qs_log) { // This can be incorporated below when revisions are made - for (int16 trade_slot = EmuConstants::TRADE_BEGIN; trade_slot <= EmuConstants::TRADE_NPC_END; ++trade_slot) { + for (int16 trade_slot = EQEmu::legacy::TRADE_BEGIN; trade_slot <= EQEmu::legacy::TRADE_NPC_END; ++trade_slot) { const ItemInst* trade_inst = m_inv[trade_slot]; if(trade_inst) { - QSHandinItems_Struct* detail = new QSHandinItems_Struct; + auto detail = new QSHandinItems_Struct; strcpy(detail->action_type, "HANDIN"); @@ -840,8 +840,8 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st event_details->push_back(detail); qs_audit->char_count += detail->charges; - if(trade_inst->IsType(ItemClassContainer)) { - for (uint8 sub_slot = SUB_BEGIN; sub_slot < trade_inst->GetItem()->BagSlots; ++sub_slot) { + if (trade_inst->IsClassBag()) { + for (uint8 sub_slot = SUB_INDEX_BEGIN; sub_slot < trade_inst->GetItem()->BagSlots; ++sub_slot) { const ItemInst* trade_baginst = trade_inst->GetItem(sub_slot); if(trade_baginst) { @@ -874,27 +874,27 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st } std::vector item_list; - uint32 items[4] = { 0 }; - for(int i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_NPC_END; ++i) { + std::list items; + for (int i = EQEmu::legacy::TRADE_BEGIN; i <= EQEmu::legacy::TRADE_NPC_END; ++i) { ItemInst *inst = m_inv.GetItem(i); if(inst) { - items[i - EmuConstants::TRADE_BEGIN] = inst->GetItem()->ID; + items.push_back(inst); item_list.push_back(inst); } else { item_list.push_back((ItemInst*)nullptr); continue; } - const Item_Struct* item = inst->GetItem(); + const EQEmu::ItemBase* item = inst->GetItem(); if(item && quest_npc == false) { // 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)) { // pets need to look inside bags and try to equip items found there - if(item->ItemClass == ItemClassContainer && item->BagSlots > 0) { - for(int16 bslot = SUB_BEGIN; bslot < item->BagSlots; bslot++) { + if (item->IsClassBag() && item->BagSlots > 0) { + for (int16 bslot = SUB_INDEX_BEGIN; bslot < item->BagSlots; bslot++) { const ItemInst* baginst = inst->GetItem(bslot); if (baginst) { - const Item_Struct* bagitem = baginst->GetItem(); + const EQEmu::ItemBase* bagitem = baginst->GetItem(); if (bagitem && (GetGM() || (bagitem->NoDrop != 0 && baginst->IsAttuned() == false))) { tradingWith->CastToNPC()->AddLootDrop(bagitem, &tradingWith->CastToNPC()->itemlist, baginst->GetCharges(), 1, 127, true, true); @@ -948,8 +948,8 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st } ItemInst *insts[4] = { 0 }; - for(int i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_NPC_END; ++i) { - insts[i - EmuConstants::TRADE_BEGIN] = m_inv.PopItem(i); + for (int i = EQEmu::legacy::TRADE_BEGIN; i <= EQEmu::legacy::TRADE_NPC_END; ++i) { + insts[i - EQEmu::legacy::TRADE_BEGIN] = m_inv.PopItem(i); database.SaveInventory(CharacterID(), nullptr, i); } @@ -968,7 +968,7 @@ bool Client::CheckTradeLoreConflict(Client* other) if (!other) return true; // Move each trade slot into free inventory slot - for (int16 i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_END; i++){ + for (int16 i = EQEmu::legacy::TRADE_BEGIN; i <= EQEmu::legacy::TRADE_END; i++){ const ItemInst* inst = m_inv[i]; if (inst && inst->GetItem()) { @@ -977,7 +977,7 @@ bool Client::CheckTradeLoreConflict(Client* other) } } - for (int16 i = EmuConstants::TRADE_BAGS_BEGIN; i <= EmuConstants::TRADE_BAGS_END; i++){ + for (int16 i = EQEmu::legacy::TRADE_BAGS_BEGIN; i <= EQEmu::legacy::TRADE_BAGS_END; i++){ const ItemInst* inst = m_inv[i]; if (inst && inst->GetItem()) { @@ -990,7 +990,7 @@ bool Client::CheckTradeLoreConflict(Client* other) } void Client::Trader_ShowItems(){ - EQApplicationPacket* outapp= new EQApplicationPacket(OP_Trader, sizeof(Trader_Struct)); + auto outapp = new EQApplicationPacket(OP_Trader, sizeof(Trader_Struct)); Trader_Struct* outints = (Trader_Struct*)outapp->pBuffer; Trader_Struct* TraderItems = database.LoadTraderItem(this->CharacterID()); @@ -1011,7 +1011,7 @@ void Client::SendTraderPacket(Client* Trader, uint32 Unknown72) if(!Trader) return; - EQApplicationPacket* outapp= new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct)); + auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct)); BecomeTrader_Struct* bts = (BecomeTrader_Struct*)outapp->pBuffer; @@ -1031,7 +1031,7 @@ void Client::SendTraderPacket(Client* Trader, uint32 Unknown72) void Client::Trader_CustomerBrowsing(Client *Customer) { - EQApplicationPacket* outapp= new EQApplicationPacket(OP_Trader, sizeof(Trader_ShowItems_Struct)); + auto outapp = new EQApplicationPacket(OP_Trader, sizeof(Trader_ShowItems_Struct)); Trader_ShowItems_Struct* sis = (Trader_ShowItems_Struct*)outapp->pBuffer; @@ -1047,7 +1047,7 @@ void Client::Trader_StartTrader() { Trader=true; - EQApplicationPacket* outapp= new EQApplicationPacket(OP_Trader, sizeof(Trader_ShowItems_Struct)); + auto outapp = new EQApplicationPacket(OP_Trader, sizeof(Trader_ShowItems_Struct)); Trader_ShowItems_Struct* sis = (Trader_ShowItems_Struct*)outapp->pBuffer; @@ -1087,7 +1087,7 @@ void Client::Trader_EndTrader() { GetItems_Struct* gis=GetTraderItems(); if(Customer && gis) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct)); + auto outapp = new EQApplicationPacket(OP_TraderDelItem, sizeof(TraderDelItem_Struct)); TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer; tdis->Unknown000 = 0; @@ -1098,7 +1098,7 @@ void Client::Trader_EndTrader() { for(int i = 0; i < 80; i++) { if(gis->Items[i] != 0) { - if (Customer->GetClientVersion() >= ClientVersion::RoF) + if (Customer->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { // RoF+ use Item IDs for now tdis->ItemID = gis->Items[i]; @@ -1121,7 +1121,7 @@ void Client::Trader_EndTrader() { // Notify other clients we are no longer in trader mode. // - EQApplicationPacket* outapp= new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct)); + auto outapp = new EQApplicationPacket(OP_BecomeTrader, sizeof(BecomeTrader_Struct)); BecomeTrader_Struct* bts = (BecomeTrader_Struct*)outapp->pBuffer; @@ -1158,7 +1158,7 @@ void Client::SendTraderItem(uint32 ItemID, uint16 Quantity) { std::string Packet; int16 FreeSlotID=0; - const Item_Struct* item = database.GetItem(ItemID); + const EQEmu::ItemBase* item = database.GetItem(ItemID); if(!item){ Log.Out(Logs::Detail, Logs::Trading, "Bogus item deleted in Client::SendTraderItem!\n"); @@ -1169,7 +1169,7 @@ void Client::SendTraderItem(uint32 ItemID, uint16 Quantity) { if (inst) { - bool is_arrow = (inst->GetItem()->ItemType == ItemTypeArrow) ? true : false; + bool is_arrow = (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow) ? true : false; FreeSlotID = m_inv.FindFreeSlot(false, true, inst->GetItem()->Size, is_arrow); PutItemInInventory(FreeSlotID, *inst); @@ -1192,7 +1192,7 @@ void Client::SendSingleTraderItem(uint32 CharID, int SerialNumber) { } void Client::BulkSendTraderInventory(uint32 char_id) { - const Item_Struct *item; + const EQEmu::ItemBase *item; TraderCharges_Struct* TraderItems = database.LoadTraderItemWithCharges(char_id); @@ -1232,10 +1232,10 @@ uint32 Client::FindTraderItemSerialNumber(int32 ItemID) { ItemInst* item = nullptr; uint16 SlotID = 0; - for (int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++){ + for (int i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; i++){ item = this->GetInv().GetItem(i); if (item && item->GetItem()->ID == 17899){ //Traders Satchel - for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; x++) { + for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; x++) { // we already have the parent bag and a contents iterator..why not just iterate the bag!?? SlotID = Inventory::CalcSlotId(i, x); item = this->GetInv().GetItem(SlotID); @@ -1255,10 +1255,10 @@ ItemInst* Client::FindTraderItemBySerialNumber(int32 SerialNumber){ ItemInst* item = nullptr; uint16 SlotID = 0; - for(int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++){ + for (int i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; i++){ item = this->GetInv().GetItem(i); if(item && item->GetItem()->ID == 17899){ //Traders Satchel - for(int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; x++) { + for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; x++) { // we already have the parent bag and a contents iterator..why not just iterate the bag!?? SlotID = Inventory::CalcSlotId(i, x); item = this->GetInv().GetItem(SlotID); @@ -1280,16 +1280,16 @@ GetItems_Struct* Client::GetTraderItems(){ const ItemInst* item = nullptr; uint16 SlotID = 0; - GetItems_Struct* gis= new GetItems_Struct; + auto gis = new GetItems_Struct; memset(gis,0,sizeof(GetItems_Struct)); uint8 ndx = 0; - for(int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { + for (int i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; i++) { item = this->GetInv().GetItem(i); if(item && item->GetItem()->ID == 17899){ //Traders Satchel - for(int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; x++) { + for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; x++) { SlotID = Inventory::CalcSlotId(i, x); item = this->GetInv().GetItem(SlotID); @@ -1310,10 +1310,10 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){ const ItemInst* item= nullptr; uint16 SlotID = 0; - for(int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++) { + for (int i = EQEmu::legacy::GENERAL_BEGIN; i <= EQEmu::legacy::GENERAL_END; i++) { item = this->GetInv().GetItem(i); if(item && item->GetItem()->ID == 17899){ //Traders Satchel - for(int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; x++){ + for (int x = SUB_INDEX_BEGIN; x < EQEmu::legacy::ITEM_CONTAINER_SIZE; x++){ SlotID = Inventory::CalcSlotId(i, x); item = this->GetInv().GetItem(SlotID); @@ -1346,12 +1346,12 @@ void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Cu } else { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct)); + auto outapp = new EQApplicationPacket(OP_TraderDelItem, sizeof(TraderDelItem_Struct)); TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer; tdis->Unknown000 = 0; tdis->TraderID = Customer->GetID(); - if (Customer->GetClientVersion() >= ClientVersion::RoF) + if (Customer->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { // RoF+ use Item IDs for now tdis->ItemID = itemid; @@ -1399,7 +1399,7 @@ void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Cu void Client::TraderUpdate(uint16 SlotID,uint32 TraderID){ // This method is no longer used. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderItemUpdate,sizeof(TraderItemUpdate_Struct)); + auto outapp = new EQApplicationPacket(OP_TraderItemUpdate, sizeof(TraderItemUpdate_Struct)); TraderItemUpdate_Struct* tus=(TraderItemUpdate_Struct*)outapp->pBuffer; tus->Charges = 0xFFFF; tus->FromSlot = SlotID; @@ -1487,7 +1487,7 @@ void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCha EQApplicationPacket* outapp = nullptr; - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderBuy_Struct)); } @@ -1499,7 +1499,7 @@ void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCha TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer; memcpy(outtbs, tbs, app->size); - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { // Convert Serial Number back to Item ID for RoF+ outtbs->ItemID = itemid; @@ -1524,7 +1524,7 @@ void Client::TradeRequestFailed(const EQApplicationPacket* app) { TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct)); + auto outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct)); TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer; @@ -1558,7 +1558,7 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct)); + auto outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct)); TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer; @@ -1567,7 +1567,7 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic const ItemInst* BuyItem = nullptr; uint32 ItemID = 0; - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { // Convert Item ID to Serial Number for RoF+ ItemID = tbs->ItemID; @@ -1583,6 +1583,8 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic return; } + tbs->Price = BuyItem->GetPrice(); + Log.Out(Logs::Detail, Logs::Trading, "Buyitem: Name: %s, IsStackable: %i, Requested Quantity: %i, Charges on Item %i", BuyItem->GetItem()->Name, BuyItem->IsStackable(), tbs->Quantity, BuyItem->GetCharges()); // If the item is not stackable, then we can only be buying one of them. @@ -1624,23 +1626,10 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic return; } - ReturnTraderReq(app, outtbs->Quantity, ItemID); - - outtbs->TraderID = this->GetID(); - outtbs->Action = BazaarBuyItem; - strn0cpy(outtbs->ItemName, BuyItem->GetItem()->Name, 64); - - int TraderSlot = 0; - - if(BuyItem->IsStackable()) - SendTraderItem(BuyItem->GetItem()->ID, outtbs->Quantity); - else - SendTraderItem(BuyItem->GetItem()->ID, BuyItem->GetCharges()); - // This cannot overflow assuming MAX_TRANSACTION_VALUE, checked above, is the default of 2000000000 uint32 TotalCost = tbs->Price * outtbs->Quantity; - if (Trader->GetClientVersion() >= ClientVersion::RoF) + if (Trader->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { // RoF+ uses individual item price where older clients use total price outtbs->Price = tbs->Price; @@ -1650,7 +1639,12 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic outtbs->Price = TotalCost; } - this->TakeMoneyFromPP(TotalCost); + if(!TakeMoneyFromPP(TotalCost)) { + database.SetHackerFlag(account_name, name, "Attempted to buy something in bazaar but did not have enough money."); + TradeRequestFailed(app); + safe_delete(outapp); + return; + } Log.Out(Logs::Detail, Logs::Trading, "Customer Paid: %d in Copper", TotalCost); @@ -1666,6 +1660,19 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic Log.Out(Logs::Detail, Logs::Trading, "Trader Received: %d Platinum, %d Gold, %d Silver, %d Copper", platinum, gold, silver, copper); + ReturnTraderReq(app, outtbs->Quantity, ItemID); + + outtbs->TraderID = this->GetID(); + outtbs->Action = BazaarBuyItem; + strn0cpy(outtbs->ItemName, BuyItem->GetItem()->Name, 64); + + int TraderSlot = 0; + + if(BuyItem->IsStackable()) + SendTraderItem(BuyItem->GetItem()->ID, outtbs->Quantity); + else + SendTraderItem(BuyItem->GetItem()->ID, BuyItem->GetCharges()); + TraderSlot = Trader->FindTraderItem(tbs->ItemID, outtbs->Quantity); if(RuleB(Bazaar, AuditTrail)) @@ -1673,7 +1680,7 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic Trader->FindAndNukeTraderItem(tbs->ItemID, outtbs->Quantity, this, 0); - if (ItemID > 0 && Trader->GetClientVersion() >= ClientVersion::RoF) + if (ItemID > 0 && Trader->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { // Convert Serial Number back to ItemID for RoF+ outtbs->ItemID = ItemID; @@ -1691,7 +1698,7 @@ void Client::SendBazaarWelcome() auto row = results.begin(); EQApplicationPacket* outapp = nullptr; - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BazaarWelcome_Struct)); } @@ -1709,7 +1716,7 @@ void Client::SendBazaarWelcome() bws->Traders = atoi(row[0]); bws->Items = atoi(row[1]); - if (GetClientVersion() >= ClientVersion::RoF) + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { bws->Unknown012 = GetID(); } @@ -1920,98 +1927,95 @@ void Client::SendBazaarResults(uint32 TraderID, uint32 Class_, uint32 Race, uint RuleI(Bazaar, MaxSearchResults)); if(results.RowCount() == 0) { - EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct)); - BazaarReturnDone_Struct* brds = (BazaarReturnDone_Struct*)outapp2->pBuffer; - brds->TraderID = ID; - brds->Type = BazaarSearchDone; - brds->Unknown008 = 0xFFFFFFFF; - brds->Unknown012 = 0xFFFFFFFF; - brds->Unknown016 = 0xFFFFFFFF; - this->QueuePacket(outapp2); - safe_delete(outapp2); - return; + auto outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct)); + BazaarReturnDone_Struct *brds = (BazaarReturnDone_Struct *)outapp2->pBuffer; + brds->TraderID = ID; + brds->Type = BazaarSearchDone; + brds->Unknown008 = 0xFFFFFFFF; + brds->Unknown012 = 0xFFFFFFFF; + brds->Unknown016 = 0xFFFFFFFF; + this->QueuePacket(outapp2); + safe_delete(outapp2); + return; } Size = results.RowCount() * sizeof(BazaarSearchResults_Struct); - uchar *buffer = new uchar[Size]; - uchar *bufptr = buffer; - memset(buffer, 0, Size); + auto buffer = new uchar[Size]; + uchar *bufptr = buffer; + memset(buffer, 0, Size); - int Action = BazaarSearchResults; - uint32 Cost = 0; - int32 SerialNumber = 0; - char temp_buffer[64] = {0}; - int Count = 0; - uint32 StatValue=0; + int Action = BazaarSearchResults; + uint32 Cost = 0; + int32 SerialNumber = 0; + char temp_buffer[64] = {0}; + int Count = 0; + uint32 StatValue = 0; - for (auto row = results.begin(); row != results.end(); ++row) { - VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Action); - Count = atoi(row[0]); - VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Count); - SerialNumber = atoi(row[3]); - VARSTRUCT_ENCODE_TYPE(int32, bufptr, SerialNumber); - Client* Trader2=entity_list.GetClientByCharID(atoi(row[1])); - if(Trader2){ - ID = Trader2->GetID(); - VARSTRUCT_ENCODE_TYPE(uint32, bufptr, ID); - } - else{ - Log.Out(Logs::Detail, Logs::Trading, "Unable to find trader: %i\n",atoi(row[1])); - VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0); - } - Cost = atoi(row[5]); - VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Cost); - StatValue = atoi(row[8]); - VARSTRUCT_ENCODE_TYPE(uint32, bufptr, StatValue); - bool Stackable = atoi(row[10]); - if(Stackable) { - int Charges = atoi(row[9]); - sprintf(temp_buffer, "%s(%i)", row[7], Charges); - } - else - sprintf(temp_buffer,"%s(%i)",row[7], Count); + for (auto row = results.begin(); row != results.end(); ++row) { + VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Action); + Count = atoi(row[0]); + VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Count); + SerialNumber = atoi(row[3]); + VARSTRUCT_ENCODE_TYPE(int32, bufptr, SerialNumber); + Client *Trader2 = entity_list.GetClientByCharID(atoi(row[1])); + if (Trader2) { + ID = Trader2->GetID(); + VARSTRUCT_ENCODE_TYPE(uint32, bufptr, ID); + } else { + Log.Out(Logs::Detail, Logs::Trading, "Unable to find trader: %i\n", atoi(row[1])); + VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0); + } + Cost = atoi(row[5]); + VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Cost); + StatValue = atoi(row[8]); + VARSTRUCT_ENCODE_TYPE(uint32, bufptr, StatValue); + bool Stackable = atoi(row[10]); + if (Stackable) { + int Charges = atoi(row[9]); + sprintf(temp_buffer, "%s(%i)", row[7], Charges); + } else + sprintf(temp_buffer, "%s(%i)", row[7], Count); - memcpy(bufptr,&temp_buffer, strlen(temp_buffer)); + memcpy(bufptr, &temp_buffer, strlen(temp_buffer)); - bufptr += 64; + bufptr += 64; - // Extra fields for SoD+ - // - if(Trader2) - sprintf(temp_buffer, "%s", Trader2->GetName()); - else - sprintf(temp_buffer, "Unknown"); + // Extra fields for SoD+ + // + if (Trader2) + sprintf(temp_buffer, "%s", Trader2->GetName()); + else + sprintf(temp_buffer, "Unknown"); - memcpy(bufptr,&temp_buffer, strlen(temp_buffer)); + memcpy(bufptr, &temp_buffer, strlen(temp_buffer)); - bufptr += 64; + bufptr += 64; - VARSTRUCT_ENCODE_TYPE(uint32, bufptr, atoi(row[1])); // ItemID + VARSTRUCT_ENCODE_TYPE(uint32, bufptr, atoi(row[1])); // ItemID } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, Size); + auto outapp = new EQApplicationPacket(OP_BazaarSearch, Size); - memcpy(outapp->pBuffer, buffer, Size); + memcpy(outapp->pBuffer, buffer, Size); - this->QueuePacket(outapp); + this->QueuePacket(outapp); + safe_delete(outapp); + safe_delete_array(buffer); - safe_delete(outapp); - safe_delete_array(buffer); + auto outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct)); + BazaarReturnDone_Struct *brds = (BazaarReturnDone_Struct *)outapp2->pBuffer; - EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct)); - BazaarReturnDone_Struct* brds = (BazaarReturnDone_Struct*)outapp2->pBuffer; + brds->TraderID = ID; + brds->Type = BazaarSearchDone; - brds->TraderID = ID; - brds->Type = BazaarSearchDone; + brds->Unknown008 = 0xFFFFFFFF; + brds->Unknown012 = 0xFFFFFFFF; + brds->Unknown016 = 0xFFFFFFFF; - brds->Unknown008 = 0xFFFFFFFF; - brds->Unknown012 = 0xFFFFFFFF; - brds->Unknown016 = 0xFFFFFFFF; + this->QueuePacket(outapp2); - this->QueuePacket(outapp2); - - safe_delete(outapp2); + safe_delete(outapp2); } static void UpdateTraderCustomerItemsAdded(uint32 CustomerID, TraderCharges_Struct* gis, uint32 ItemID) { @@ -2023,7 +2027,7 @@ static void UpdateTraderCustomerItemsAdded(uint32 CustomerID, TraderCharges_Stru if(!Customer) return; - const Item_Struct *item = database.GetItem(ItemID); + const EQEmu::ItemBase *item = database.GetItem(ItemID); if(!item) return; @@ -2067,13 +2071,13 @@ static void UpdateTraderCustomerPriceChanged(uint32 CustomerID, TraderCharges_St if(!Customer) return; - const Item_Struct *item = database.GetItem(ItemID); + const EQEmu::ItemBase *item = database.GetItem(ItemID); if(!item) return; if(NewPrice == 0) { // If the new price is 0, remove the item(s) from the window. - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct)); + auto outapp = new EQApplicationPacket(OP_TraderDelItem, sizeof(TraderDelItem_Struct)); TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer; tdis->Unknown000 = 0; @@ -2084,7 +2088,7 @@ static void UpdateTraderCustomerPriceChanged(uint32 CustomerID, TraderCharges_St for(int i = 0; i < 80; i++) { if(gis->ItemID[i] == ItemID) { - if (Customer->GetClientVersion() >= ClientVersion::RoF) + if (Customer->ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { // RoF+ use Item IDs for now tdis->ItemID = gis->ItemID[i]; @@ -2226,7 +2230,7 @@ void Client::HandleTraderPriceUpdate(const EQApplicationPacket *app) { } - const Item_Struct *item = 0; + const EQEmu::ItemBase *item = 0; if(IDOfItemToAdd) item = database.GetItem(IDOfItemToAdd); @@ -2347,7 +2351,7 @@ void Client::SendBuyerResults(char* searchString, uint32 searchID) { // Log.Out(Logs::Detail, Logs::None, "[CLIENT] Client::SendBuyerResults %s\n", searchString); - char* escSearchString = new char[strlen(searchString) * 2 + 1]; + auto escSearchString = new char[strlen(searchString) * 2 + 1]; database.DoEscapeString(escSearchString, searchString, strlen(searchString)); std::string query = StringFormat("SELECT * FROM buyer WHERE itemname LIKE '%%%s%%' ORDER BY charid LIMIT %i", @@ -2388,14 +2392,16 @@ void Client::SendBuyerResults(char* searchString, uint32 searchID) { // to allow item compensation, e.g. a buyer could offer to buy a Blade Of Carnage for 10000pp plus // other items in exchange. Item compensation is not currently supported in EQEmu. // - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 940); + auto outapp = new EQApplicationPacket(OP_Barter, 940); char *buf = (char *)outapp->pBuffer; - const Item_Struct* item = database.GetItem(itemID); + const EQEmu::ItemBase* item = database.GetItem(itemID); - if(!item) + if(!item) { + safe_delete(outapp); continue; + } // Save having to scan the client list when dealing with multiple buylines for the same Character. if(charID != lastCharID) { @@ -2403,8 +2409,10 @@ void Client::SendBuyerResults(char* searchString, uint32 searchID) { lastCharID = charID; } - if(!buyer) + if(!buyer) { + safe_delete(outapp); continue; + } VARSTRUCT_ENCODE_TYPE(uint32, buf, Barter_BuyerSearchResults); // Command VARSTRUCT_ENCODE_TYPE(uint32, buf, searchID); // Match up results with the request @@ -2454,7 +2462,7 @@ void Client::ShowBuyLines(const EQApplicationPacket *app) { if(strlen(WelcomeMessagePointer) > 0) Message(10, "%s greets you, '%s'.", Buyer->GetName(), WelcomeMessagePointer); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, sizeof(BuyerBrowsing_Struct)); + auto outapp = new EQApplicationPacket(OP_Barter, sizeof(BuyerBrowsing_Struct)); BuyerBrowsing_Struct* bb = (BuyerBrowsing_Struct*)outapp->pBuffer; @@ -2480,14 +2488,16 @@ void Client::ShowBuyLines(const EQApplicationPacket *app) { uint32 Quantity = atoi(row[4]); uint32 Price = atoi(row[5]); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 936); + auto outapp = new EQApplicationPacket(OP_Barter, 936); char *Buf = (char *)outapp->pBuffer; - const Item_Struct* item = database.GetItem(ItemID); + const EQEmu::ItemBase* item = database.GetItem(ItemID); - if(!item) + if(!item) { + safe_delete(outapp); continue; + } VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerInspectWindow); VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot); @@ -2526,7 +2536,7 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { /*uint32 BuyerID2 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused /*uint32 Unknown3 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused - const Item_Struct *item = database.GetItem(ItemID); + const EQEmu::ItemBase *item = database.GetItem(ItemID); if(!item || !Quantity || !Price || !QtyBuyerWants) return; @@ -2610,7 +2620,7 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { // Remove the item from inventory, clientside // - EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct)); + auto outapp2 = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct)); MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer; mis->from_slot = SellerSlot; @@ -2664,7 +2674,7 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { safe_delete(ItemToTransfer); // and tell the client to do the same. - EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct)); + auto outapp2 = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct)); MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer; mis->from_slot = SellerSlot; @@ -2696,7 +2706,7 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { safe_delete(ItemToTransfer); - EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem,sizeof(MoveItem_Struct)); + auto outapp2 = new EQApplicationPacket(OP_DeleteItem, sizeof(MoveItem_Struct)); MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer; mis->from_slot = SellerSlot; @@ -2730,7 +2740,7 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { // uint32 PacketLength = 1016; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, PacketLength); + auto outapp = new EQApplicationPacket(OP_Barter, PacketLength); Buf = (char *)outapp->pBuffer; @@ -2738,7 +2748,7 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity); VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price); - if(GetClientVersion() >= ClientVersion::SoD) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price } @@ -2762,7 +2772,7 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity); VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price); - if(Buyer->GetClientVersion() >= ClientVersion::SoD) + if (Buyer->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price } @@ -2785,7 +2795,7 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { // Next we update the Seller's Barter Window to reflect the reduced quantity the Buyer is now looking to buy. // - EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_Barter, 936); + auto outapp3 = new EQApplicationPacket(OP_Barter, 936); Buf = (char *)outapp3->pBuffer; @@ -2819,7 +2829,7 @@ void Client::SellToBuyer(const EQApplicationPacket *app) { // The next packet updates the /buyer window with the reduced quantity, and toggles the buy line off if the // quantity they wanted to buy has been met. // - EQApplicationPacket* outapp4 = new EQApplicationPacket(OP_Barter, 936); + auto outapp4 = new EQApplicationPacket(OP_Barter, 936); Buf = (char*)outapp4->pBuffer; @@ -2854,7 +2864,7 @@ void Client::SendBuyerPacket(Client* Buyer) { // This is the Buyer Appearance packet. This method is called for each Buyer when a Client connects to the zone. // - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 13 + strlen(GetName())); + auto outapp = new EQApplicationPacket(OP_Barter, 13 + strlen(GetName())); char* Buf = (char*)outapp->pBuffer; @@ -2869,7 +2879,7 @@ void Client::SendBuyerPacket(Client* Buyer) { void Client::ToggleBuyerMode(bool TurnOn) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 13 + strlen(GetName())); + auto outapp = new EQApplicationPacket(OP_Barter, 13 + strlen(GetName())); char* Buf = (char*)outapp->pBuffer; @@ -2917,7 +2927,7 @@ void Client::UpdateBuyLine(const EQApplicationPacket *app) { /*uint32 UnknownZ =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused uint32 ItemCount = VARSTRUCT_DECODE_TYPE(uint32, Buf); - const Item_Struct *item = database.GetItem(ItemID); + const EQEmu::ItemBase *item = database.GetItem(ItemID); if(!item) return; @@ -2950,7 +2960,7 @@ void Client::UpdateBuyLine(const EQApplicationPacket *app) { else database.RemoveBuyLine(CharacterID(), BuySlot); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 936); + auto outapp = new EQApplicationPacket(OP_Barter, 936); Buf = (char*)outapp->pBuffer; @@ -2977,11 +2987,11 @@ void Client::BuyerItemSearch(const EQApplicationPacket *app) { BuyerItemSearch_Struct* bis = (BuyerItemSearch_Struct*)app->pBuffer; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, sizeof(BuyerItemSearchResults_Struct)); + auto outapp = new EQApplicationPacket(OP_Barter, sizeof(BuyerItemSearchResults_Struct)); BuyerItemSearchResults_Struct* bisr = (BuyerItemSearchResults_Struct*)outapp->pBuffer; - const Item_Struct* item = 0; + const EQEmu::ItemBase* item = 0; int Count=0; diff --git a/zone/trap.cpp b/zone/trap.cpp index 9462e658a..87000f940 100644 --- a/zone/trap.cpp +++ b/zone/trap.cpp @@ -115,7 +115,7 @@ void Trap::Trigger(Mob* trigger) entity_list.MessageClose(trigger,false,100,13,"%s",message.c_str()); } if(hiddenTrigger){ - hiddenTrigger->SpellFinished(effectvalue, trigger, 10, 0, -1, spells[effectvalue].ResistDiff); + hiddenTrigger->SpellFinished(effectvalue, trigger, EQEmu::CastingSlot::Item, 0, -1, spells[effectvalue].ResistDiff); } break; case trapTypeAlarm: @@ -146,7 +146,7 @@ void Trap::Trigger(Mob* trigger) { auto randomOffset = glm::vec4(zone->random.Int(-5, 5),zone->random.Int(-5, 5),zone->random.Int(-5, 5), zone->random.Int(0, 249)); auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f); - NPC* new_npc = new NPC(tmp, nullptr, spawnPosition, FlyMode3); + auto new_npc = new NPC(tmp, nullptr, spawnPosition, FlyMode3); new_npc->AddLootTable(); entity_list.AddNPC(new_npc); new_npc->AddToHateList(trigger,1); @@ -169,7 +169,7 @@ void Trap::Trigger(Mob* trigger) { auto randomOffset = glm::vec4(zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(0, 249)); auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f); - NPC* new_npc = new NPC(tmp, nullptr, spawnPosition, FlyMode3); + auto new_npc = new NPC(tmp, nullptr, spawnPosition, FlyMode3); new_npc->AddLootTable(); entity_list.AddNPC(new_npc); new_npc->AddToHateList(trigger,1); @@ -187,12 +187,12 @@ void Trap::Trigger(Mob* trigger) } if(trigger->IsClient()) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); + auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); CombatDamage_Struct* a = (CombatDamage_Struct*)outapp->pBuffer; int dmg = zone->random.Int(effectvalue, effectvalue2); trigger->SetHP(trigger->GetHP() - dmg); a->damage = dmg; - a->sequence = zone->random.Int(0, 1234567); + a->meleepush_xy = zone->random.Int(0, 1234567); a->source = GetHiddenTrigger()!=nullptr ? GetHiddenTrigger()->GetID() : trigger->GetID(); a->spellid = 0; a->target = trigger->GetID(); @@ -268,7 +268,7 @@ bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) { } for (auto row = results.begin(); row != results.end(); ++row) { - Trap* trap = new Trap(); + auto trap = new Trap(); trap->trap_id = atoi(row[0]); trap->m_Position = glm::vec3(atof(row[1]), atof(row[2]), atof(row[3])); trap->effect = atoi(row[4]); @@ -295,7 +295,7 @@ void Trap::CreateHiddenTrigger() return; const NPCType *base_type = database.LoadNPCTypesData(500); - NPCType *make_npc = new NPCType; + auto make_npc = new NPCType; memcpy(make_npc, base_type, sizeof(NPCType)); make_npc->max_hp = 100000; make_npc->cur_hp = 100000; diff --git a/zone/tribute.cpp b/zone/tribute.cpp index df01f843e..d40dfa6f2 100644 --- a/zone/tribute.cpp +++ b/zone/tribute.cpp @@ -25,8 +25,8 @@ #include #ifdef _WINDOWS + #include #include - #include #include #define snprintf _snprintf #define vsnprintf _vsnprintf @@ -66,7 +66,7 @@ void Client::ToggleTribute(bool enabled) { int r; uint32 cost = 0; uint32 level = GetLevel(); - for(r = 0; r < EmuConstants::TRIBUTE_SIZE; r++) { + for (r = 0; r < EQEmu::legacy::TRIBUTE_SIZE; r++) { uint32 tid = m_pp.tributes[r].tribute; if(tid == TRIBUTE_NONE) continue; @@ -119,7 +119,7 @@ void Client::DoTributeUpdate() { tis->tribute_master_id = tribute_master_id; //Dont know what this is for int r; - for(r = 0; r < EmuConstants::TRIBUTE_SIZE; r++) { + for (r = 0; r < EQEmu::legacy::TRIBUTE_SIZE; r++) { if(m_pp.tributes[r].tribute != TRIBUTE_NONE) { tis->tributes[r] = m_pp.tributes[r].tribute; tis->tiers[r] = m_pp.tributes[r].tier; @@ -134,24 +134,24 @@ void Client::DoTributeUpdate() { if(m_pp.tribute_active) { //send and equip tribute items... - for(r = 0; r < EmuConstants::TRIBUTE_SIZE; r++) { + for (r = 0; r < EQEmu::legacy::TRIBUTE_SIZE; r++) { uint32 tid = m_pp.tributes[r].tribute; if(tid == TRIBUTE_NONE) { - if(m_inv[EmuConstants::TRIBUTE_BEGIN + r]) - DeleteItemInInventory(EmuConstants::TRIBUTE_BEGIN + r, 0, false); + if (m_inv[EQEmu::legacy::TRIBUTE_BEGIN + r]) + DeleteItemInInventory(EQEmu::legacy::TRIBUTE_BEGIN + r, 0, false); continue; } if(tribute_list.count(tid) != 1) { - if (m_inv[EmuConstants::TRIBUTE_BEGIN + r]) - DeleteItemInInventory(EmuConstants::TRIBUTE_BEGIN + r, 0, false); + if (m_inv[EQEmu::legacy::TRIBUTE_BEGIN + r]) + DeleteItemInInventory(EQEmu::legacy::TRIBUTE_BEGIN + r, 0, false); continue; } //sanity check if(m_pp.tributes[r].tier >= MAX_TRIBUTE_TIERS) { - if (m_inv[EmuConstants::TRIBUTE_BEGIN + r]) - DeleteItemInInventory(EmuConstants::TRIBUTE_BEGIN + r, 0, false); + if (m_inv[EQEmu::legacy::TRIBUTE_BEGIN + r]) + DeleteItemInInventory(EQEmu::legacy::TRIBUTE_BEGIN + r, 0, false); m_pp.tributes[r].tier = 0; continue; } @@ -165,15 +165,15 @@ void Client::DoTributeUpdate() { if(inst == nullptr) continue; - PutItemInInventory(EmuConstants::TRIBUTE_BEGIN + r, *inst, false); - SendItemPacket(EmuConstants::TRIBUTE_BEGIN + r, inst, ItemPacketTributeItem); + PutItemInInventory(EQEmu::legacy::TRIBUTE_BEGIN + r, *inst, false); + SendItemPacket(EQEmu::legacy::TRIBUTE_BEGIN + r, inst, ItemPacketTributeItem); safe_delete(inst); } } else { //unequip tribute items... - for(r = 0; r < EmuConstants::TRIBUTE_SIZE; r++) { - if (m_inv[EmuConstants::TRIBUTE_BEGIN + r]) - DeleteItemInInventory(EmuConstants::TRIBUTE_BEGIN + r, 0, false); + for (r = 0; r < EQEmu::legacy::TRIBUTE_SIZE; r++) { + if (m_inv[EQEmu::legacy::TRIBUTE_BEGIN + r]) + DeleteItemInInventory(EQEmu::legacy::TRIBUTE_BEGIN + r, 0, false); } } CalcBonuses(); @@ -192,7 +192,7 @@ void Client::SendTributeTimer() { void Client::ChangeTributeSettings(TributeInfo_Struct *t) { int r; - for(r = 0; r < EmuConstants::TRIBUTE_SIZE; r++) { + for (r = 0; r < EQEmu::legacy::TRIBUTE_SIZE; r++) { m_pp.tributes[r].tribute = TRIBUTE_NONE; diff --git a/zone/tune.cpp b/zone/tune.cpp index 4153d5b84..ea93a43f3 100644 --- a/zone/tune.cpp +++ b/zone/tune.cpp @@ -255,7 +255,7 @@ int32 Mob::Tune_MeleeMitigation(Mob* GM, Mob *attacker, int32 damage, int32 minh } if (RuleB(Combat, UseIntervalAC)) { - float softcap = (GetSkill(SkillDefense) + GetLevel()) * + float softcap = (GetSkill(EQEmu::skills::SkillDefense) + GetLevel()) * RuleR(Combat, SoftcapFactor) * (1.0 + aa_mit); float mitigation_rating = 0.0; float attack_rating = 0.0; @@ -410,14 +410,14 @@ int32 Mob::Tune_MeleeMitigation(Mob* GM, Mob *attacker, int32 damage, int32 minh int tmp_armor = armor; if (GetClass() == WIZARD || GetClass() == MAGICIAN || GetClass() == NECROMANCER || GetClass() == ENCHANTER){ - mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 4.0) + armor + 1; + mitigation_rating = ((GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 4.0) + armor + 1; if (Msg >= 2) - GM->Message(0, "# + %.2f #### DEFENDER Armor Bonus [Defense Skill %i Heroic Agi %i]", mitigation_rating - tmp_armor, GetSkill(SkillDefense), itembonuses.HeroicAGI); + GM->Message(0, "# + %.2f #### DEFENDER Armor Bonus [Defense Skill %i Heroic Agi %i]", mitigation_rating - tmp_armor, GetSkill(EQEmu::skills::SkillDefense), itembonuses.HeroicAGI); } else{ - mitigation_rating = ((GetSkill(SkillDefense) + itembonuses.HeroicAGI/10) / 3.0) + (armor * 1.333333) + 1; + mitigation_rating = ((GetSkill(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 3.0) + (armor * 1.333333) + 1; if (Msg >= 2) - GM->Message(0, "# + %.2f #### DEFENDER Armor Bonus [Defense Skill %i Heroic Agi %i]", mitigation_rating - tmp_armor, GetSkill(SkillDefense), itembonuses.HeroicAGI); + GM->Message(0, "# + %.2f #### DEFENDER Armor Bonus [Defense Skill %i Heroic Agi %i]", mitigation_rating - tmp_armor, GetSkill(EQEmu::skills::SkillDefense), itembonuses.HeroicAGI); } mitigation_rating *= 0.847; @@ -443,16 +443,16 @@ int32 Mob::Tune_MeleeMitigation(Mob* GM, Mob *attacker, int32 damage, int32 minh if (attacker->IsClient()){ if (atk_override) - attack_rating = (atk_override + ((attacker->GetSTR()-66) * 0.9) + (attacker->GetSkill(SkillOffense)*1.345)); + attack_rating = (atk_override + ((attacker->GetSTR() - 66) * 0.9) + (attacker->GetSkill(EQEmu::skills::SkillOffense)*1.345)); else - attack_rating = ((attacker->CastToClient()->CalcATK() + add_atk) + ((attacker->GetSTR()-66) * 0.9) + (attacker->GetSkill(SkillOffense)*1.345)); + attack_rating = ((attacker->CastToClient()->CalcATK() + add_atk) + ((attacker->GetSTR() - 66) * 0.9) + (attacker->GetSkill(EQEmu::skills::SkillOffense)*1.345)); } else{ if (atk_override) - attack_rating = (atk_override + (attacker->GetSkill(SkillOffense)*1.345) + ((attacker->GetSTR()-66) * 0.9)); + attack_rating = (atk_override + (attacker->GetSkill(EQEmu::skills::SkillOffense)*1.345) + ((attacker->GetSTR() - 66) * 0.9)); else - attack_rating = ((attacker->GetATK() + add_atk) + (attacker->GetSkill(SkillOffense)*1.345) + ((attacker->GetSTR()-66) * 0.9)); + attack_rating = ((attacker->GetATK() + add_atk) + (attacker->GetSkill(EQEmu::skills::SkillOffense)*1.345) + ((attacker->GetSTR() - 66) * 0.9)); } attack_rating = attacker->mod_attack_rating(attack_rating, this); @@ -468,7 +468,7 @@ int32 Mob::Tune_MeleeMitigation(Mob* GM, Mob *attacker, int32 damage, int32 minh GM->Message(0, "# %i #### ATTACKER Worn/Equip ATK Bonus", attacker->itembonuses.ATK); GM->Message(0, "# %i #### ATTACKER Worn/Equip ATK Bonus", attacker->itembonuses.ATK); GM->Message(0, "# %.2f #### ATTACKER Strength Stat ATK Bonus [Stat Amt: %i]", ((attacker->GetSTR()-66) * 0.9),attacker->GetSTR()); - GM->Message(0, "# %.2f #### ATTACKER Offensive Skill ATK Bonus [Stat Amt: %i]", (attacker->GetSkill(SkillOffense)*1.345) ,attacker->GetSkill(SkillOffense)); + GM->Message(0, "# %.2f #### ATTACKER Offensive Skill ATK Bonus [Stat Amt: %i]", (attacker->GetSkill(EQEmu::skills::SkillOffense)*1.345), attacker->GetSkill(EQEmu::skills::SkillOffense)); } else{ @@ -476,7 +476,7 @@ int32 Mob::Tune_MeleeMitigation(Mob* GM, Mob *attacker, int32 damage, int32 minh GM->Message(0, "# %i #### ATTACKER SE_ATK(2) spell Bonus", attacker->spellbonuses.ATK); GM->Message(0, "# %i #### ATTACKER NPC ATK Stat", attacker->CastToNPC()->ATK); GM->Message(0, "# %.2f #### ATTACKER Strength Stat ATK Bonus [Stat Amt: %i]", ((attacker->GetSTR()-66) * 0.9),attacker->GetSTR()); - GM->Message(0, "# %.2f #### ATTACKER Offensive Skill ATK Bonus [Stat Amt: %i]", (attacker->GetSkill(SkillOffense)*1.345) ,attacker->GetSkill(SkillOffense)); + GM->Message(0, "# %.2f #### ATTACKER Offensive Skill ATK Bonus [Stat Amt: %i]", (attacker->GetSkill(EQEmu::skills::SkillOffense)*1.345), attacker->GetSkill(EQEmu::skills::SkillOffense)); } } @@ -582,13 +582,13 @@ int32 Client::Tune_GetMeleeMitDmg(Mob* GM, Mob *attacker, int32 damage, int32 mi int32 Client::GetMeleeDamage(Mob* other, bool GetMinDamage) { - int Hand = MainPrimary; + int Hand = EQEmu::legacy::SlotPrimary; if (!other) return 0; ItemInst* weapon; - weapon = GetInv().GetItem(MainPrimary); + weapon = GetInv().GetItem(EQEmu::legacy::SlotPrimary); if(weapon != nullptr) { if (!weapon->IsWeapon()) { @@ -596,7 +596,7 @@ int32 Client::GetMeleeDamage(Mob* other, bool GetMinDamage) } } - SkillUseTypes skillinuse; + EQEmu::skills::SkillType skillinuse; AttackAnimation(skillinuse, Hand, weapon); int damage = 0; @@ -621,16 +621,16 @@ int32 Client::GetMeleeDamage(Mob* other, bool GetMinDamage) max_hit = (RuleI(Combat, HitCapPre20)); CheckIncreaseSkill(skillinuse, other, -15); - CheckIncreaseSkill(SkillOffense, other, -15); + CheckIncreaseSkill(EQEmu::skills::SkillOffense, other, -15); #ifndef EQEMU_NO_WEAPON_DAMAGE_BONUS int ucDamageBonus = 0; - if( Hand == MainPrimary && GetLevel() >= 28 && IsWarriorClass() ) + if (Hand == EQEmu::legacy::SlotPrimary && GetLevel() >= 28 && IsWarriorClass()) { - ucDamageBonus = GetWeaponDamageBonus( weapon ? weapon->GetItem() : (const Item_Struct*) nullptr ); + ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQEmu::ItemBase*) nullptr); min_hit += (int) ucDamageBonus; max_hit += (int) ucDamageBonus; @@ -658,28 +658,28 @@ void Mob::Tune_FindAccuaryByHitChance(Mob* defender, Mob *attacker, float hit_ch float tmp_hit_chance = 0.0f; bool end = false; - SkillUseTypes skillinuse = SkillHandtoHand; + EQEmu::skills::SkillType skillinuse = EQEmu::skills::SkillHandtoHand; if (attacker->IsClient()) {//Will check first equiped weapon for skill. Ie. remove wepaons to assess bow. ItemInst* weapon; - weapon = attacker->CastToClient()->GetInv().GetItem(MainPrimary); + weapon = attacker->CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotPrimary); if(weapon && weapon->IsWeapon()){ - attacker->CastToClient()->AttackAnimation(skillinuse, MainPrimary, weapon); + attacker->CastToClient()->AttackAnimation(skillinuse, EQEmu::legacy::SlotPrimary, weapon); } else { - weapon = attacker->CastToClient()->GetInv().GetItem(MainSecondary); + weapon = attacker->CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotSecondary); if (weapon && weapon->IsWeapon()) - attacker->CastToClient()->AttackAnimation(skillinuse, MainSecondary, weapon); + attacker->CastToClient()->AttackAnimation(skillinuse, EQEmu::legacy::SlotSecondary, weapon); else { - weapon = attacker->CastToClient()->GetInv().GetItem(MainRange); + weapon = attacker->CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotRange); if (weapon && weapon->IsWeapon()) - attacker->CastToClient()->AttackAnimation(skillinuse, MainRange, weapon); + attacker->CastToClient()->AttackAnimation(skillinuse, EQEmu::legacy::SlotRange, weapon); } } } - tmp_hit_chance = Tune_CheckHitChance(defender,attacker, skillinuse, MainPrimary,0,0,0, avoid_override); + tmp_hit_chance = Tune_CheckHitChance(defender, attacker, skillinuse, EQEmu::legacy::SlotPrimary, 0, 0, 0, avoid_override); Message(0, "#Tune - Begin Parse [Interval %i Max Loop Iterations %i]", interval, max_loop); @@ -691,7 +691,7 @@ void Mob::Tune_FindAccuaryByHitChance(Mob* defender, Mob *attacker, float hit_ch for (int j=0; j < max_loop; j++) { - tmp_hit_chance =Tune_CheckHitChance(defender,attacker, skillinuse, MainPrimary,0,false,0, avoid_override, add_acc); + tmp_hit_chance = Tune_CheckHitChance(defender, attacker, skillinuse, EQEmu::legacy::SlotPrimary, 0, false, 0, avoid_override, add_acc); if (Msg >= 3) Message(15, "#Tune - Processing... [%i] [ACCURACY %i] Hit Chance %.2f ",j,add_acc,tmp_hit_chance); @@ -706,7 +706,7 @@ void Mob::Tune_FindAccuaryByHitChance(Mob* defender, Mob *attacker, float hit_ch if (end){ - Tune_CheckHitChance(defender,attacker, skillinuse, MainPrimary,0,Msg,0,avoid_override);//Display Stat Report + Tune_CheckHitChance(defender, attacker, skillinuse, EQEmu::legacy::SlotPrimary, 0, Msg, 0, avoid_override);//Display Stat Report Message(0, " "); @@ -738,28 +738,28 @@ void Mob::Tune_FindAvoidanceByHitChance(Mob* defender, Mob *attacker, float hit_ float tmp_hit_chance = 0.0f; bool end = false; - SkillUseTypes skillinuse = SkillHandtoHand; + EQEmu::skills::SkillType skillinuse = EQEmu::skills::SkillHandtoHand; if (attacker->IsClient()) {//Will check first equiped weapon for skill. Ie. remove wepaons to assess bow. ItemInst* weapon; - weapon = attacker->CastToClient()->GetInv().GetItem(MainPrimary); + weapon = attacker->CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotPrimary); if(weapon && weapon->IsWeapon()){ - attacker->CastToClient()->AttackAnimation(skillinuse, MainPrimary, weapon); + attacker->CastToClient()->AttackAnimation(skillinuse, EQEmu::legacy::SlotPrimary, weapon); } else { - weapon = attacker->CastToClient()->GetInv().GetItem(MainSecondary); + weapon = attacker->CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotSecondary); if (weapon && weapon->IsWeapon()) - attacker->CastToClient()->AttackAnimation(skillinuse, MainSecondary, weapon); + attacker->CastToClient()->AttackAnimation(skillinuse, EQEmu::legacy::SlotSecondary, weapon); else { - weapon = attacker->CastToClient()->GetInv().GetItem(MainRange); + weapon = attacker->CastToClient()->GetInv().GetItem(EQEmu::legacy::SlotRange); if (weapon && weapon->IsWeapon()) - attacker->CastToClient()->AttackAnimation(skillinuse, MainRange, weapon); + attacker->CastToClient()->AttackAnimation(skillinuse, EQEmu::legacy::SlotRange, weapon); } } } - tmp_hit_chance = Tune_CheckHitChance(defender, attacker, skillinuse, MainPrimary,0,0,acc_override, 0); + tmp_hit_chance = Tune_CheckHitChance(defender, attacker, skillinuse, EQEmu::legacy::SlotPrimary, 0, 0, acc_override, 0); Message(0, "#Tune - Begin Parse [Interval %i Max Loop Iterations %i]", interval, max_loop); Message(0, "#Tune - Processing... Find Avoidance for hit chance on defender of (%.0f) pct from attacker. [Current Hit Chance %.2f]", hit_chance, tmp_hit_chance); @@ -769,7 +769,7 @@ void Mob::Tune_FindAvoidanceByHitChance(Mob* defender, Mob *attacker, float hit_ for (int j=0; j < max_loop; j++) { - tmp_hit_chance = Tune_CheckHitChance(defender, attacker, skillinuse, MainPrimary, 0,0, acc_override, 0,0,add_avoid); + tmp_hit_chance = Tune_CheckHitChance(defender, attacker, skillinuse, EQEmu::legacy::SlotPrimary, 0, 0, acc_override, 0, 0, add_avoid); if (Msg >= 3) Message(0, "#Tune - Processing... [%i] [AVOIDANCE %i] Hit Chance %.2f ",j,add_avoid,tmp_hit_chance); @@ -784,7 +784,7 @@ void Mob::Tune_FindAvoidanceByHitChance(Mob* defender, Mob *attacker, float hit_ if (end){ - Tune_CheckHitChance(defender,attacker, skillinuse, MainPrimary,0,Msg,acc_override, 0);//Display Stat Report + Tune_CheckHitChance(defender, attacker, skillinuse, EQEmu::legacy::SlotPrimary, 0, Msg, acc_override, 0);//Display Stat Report Message(0, " "); @@ -809,7 +809,7 @@ void Mob::Tune_FindAvoidanceByHitChance(Mob* defender, Mob *attacker, float hit_ } -float Mob::Tune_CheckHitChance(Mob* defender, Mob* attacker, SkillUseTypes skillinuse, int Hand, int16 chance_mod, int Msg,int acc_override, int avoid_override, int add_acc, int add_avoid) +float Mob::Tune_CheckHitChance(Mob* defender, Mob* attacker, EQEmu::skills::SkillType skillinuse, int Hand, int16 chance_mod, int Msg, int acc_override, int avoid_override, int add_acc, int add_avoid) { float chancetohit = RuleR(Combat, BaseHitChance); @@ -897,9 +897,9 @@ float Mob::Tune_CheckHitChance(Mob* defender, Mob* attacker, SkillUseTypes skill if(defender->IsClient()) { - chancetohit += (RuleR(Combat,WeaponSkillFalloff) * (defender->CastToClient()->MaxSkill(SkillDefense) - defender->GetSkill(SkillDefense))); + chancetohit += (RuleR(Combat, WeaponSkillFalloff) * (defender->CastToClient()->MaxSkill(EQEmu::skills::SkillDefense) - defender->GetSkill(EQEmu::skills::SkillDefense))); if (Msg >= 2) - Message(0, "# + %.2f Total: %.2f #### DEFENDER Defense Skill Mod", (RuleR(Combat,WeaponSkillFalloff) * (defender->CastToClient()->MaxSkill(SkillDefense) - defender->GetSkill(SkillDefense))), chancetohit); + Message(0, "# + %.2f Total: %.2f #### DEFENDER Defense Skill Mod", (RuleR(Combat, WeaponSkillFalloff) * (defender->CastToClient()->MaxSkill(EQEmu::skills::SkillDefense) - defender->GetSkill(EQEmu::skills::SkillDefense))), chancetohit); } @@ -988,17 +988,17 @@ float Mob::Tune_CheckHitChance(Mob* defender, Mob* attacker, SkillUseTypes skill hitBonus += attacker->itembonuses.HitChanceEffect[skillinuse] + attacker->spellbonuses.HitChanceEffect[skillinuse]+ attacker->aabonuses.HitChanceEffect[skillinuse]+ - attacker->itembonuses.HitChanceEffect[HIGHEST_SKILL+1] + - attacker->spellbonuses.HitChanceEffect[HIGHEST_SKILL+1] + - attacker->aabonuses.HitChanceEffect[HIGHEST_SKILL+1]; + attacker->itembonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] + + attacker->spellbonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1] + + attacker->aabonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1]; if (Msg >= 2){ - if (attacker->aabonuses.HitChanceEffect[HIGHEST_SKILL+1]) - Message(0, "# %i #### ATTACKER SE_HitChance(184) AA Bonus [All Skills]", attacker->aabonuses.HitChanceEffect[HIGHEST_SKILL+1]); - if (attacker->spellbonuses.HitChanceEffect[HIGHEST_SKILL+1]) - Message(0, "# %i #### ATTACKER SE_HitChance(184) Spell Bonus [All Skills]", attacker->spellbonuses.HitChanceEffect[HIGHEST_SKILL+1]); - if (attacker->itembonuses.HitChanceEffect[HIGHEST_SKILL+1]) - Message(0, "# %i #### ATTACKER SE_HitChance(184) Worn Bonus [All Skills]", attacker->itembonuses.HitChanceEffect[HIGHEST_SKILL+1]); + if (attacker->aabonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1]) + Message(0, "# %i #### ATTACKER SE_HitChance(184) AA Bonus [All Skills]", attacker->aabonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1]); + if (attacker->spellbonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1]) + Message(0, "# %i #### ATTACKER SE_HitChance(184) Spell Bonus [All Skills]", attacker->spellbonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1]); + if (attacker->itembonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1]) + Message(0, "# %i #### ATTACKER SE_HitChance(184) Worn Bonus [All Skills]", attacker->itembonuses.HitChanceEffect[EQEmu::skills::HIGHEST_SKILL + 1]); if (attacker->itembonuses.HitChanceEffect[skillinuse]) Message(0, "# %i #### ATTACKER SE_HitChance(184) AA Bonus [Skill]", attacker->aabonuses.HitChanceEffect[skillinuse]); if (attacker->spellbonuses.HitChanceEffect[skillinuse]) @@ -1009,19 +1009,19 @@ float Mob::Tune_CheckHitChance(Mob* defender, Mob* attacker, SkillUseTypes skill //Accuracy = Spell Effect , HitChance = 'Accuracy' from Item Effect //Only AA derived accuracy can be skill limited. ie (Precision of the Pathfinder, Dead Aim) - hitBonus += (attacker->itembonuses.Accuracy[HIGHEST_SKILL+1] + - attacker->spellbonuses.Accuracy[HIGHEST_SKILL+1] + - attacker->aabonuses.Accuracy[HIGHEST_SKILL+1] + + hitBonus += (attacker->itembonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] + + attacker->spellbonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] + + attacker->aabonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1] + attacker->aabonuses.Accuracy[skillinuse] + attacker->itembonuses.HitChance) / 15.0f; //Item Mod 'Accuracy' if (Msg >= 2) { - if (attacker->aabonuses.Accuracy[HIGHEST_SKILL+1]) - Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) AA Bonus [All Skills] [Stat Amt: %i]", static_cast(attacker->aabonuses.Accuracy[HIGHEST_SKILL+1])/15.0f,attacker->aabonuses.Accuracy[HIGHEST_SKILL+1]); - if (attacker->spellbonuses.Accuracy[HIGHEST_SKILL+1]) - Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) Spell Bonus [All Skills] [Stat Amt: %i]", static_cast(attacker->spellbonuses.Accuracy[HIGHEST_SKILL+1])/15.0f,attacker->spellbonuses.Accuracy[HIGHEST_SKILL+1]); - if (attacker->itembonuses.Accuracy[HIGHEST_SKILL+1]) - Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) Worn Bonus [All Skills] [Stat Amt: %i]", static_cast(attacker->itembonuses.Accuracy[HIGHEST_SKILL+1])/15.0f,attacker->itembonuses.Accuracy[HIGHEST_SKILL+1]); + if (attacker->aabonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1]) + Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) AA Bonus [All Skills] [Stat Amt: %i]", static_cast(attacker->aabonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1]) / 15.0f, attacker->aabonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1]); + if (attacker->spellbonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1]) + Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) Spell Bonus [All Skills] [Stat Amt: %i]", static_cast(attacker->spellbonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1]) / 15.0f, attacker->spellbonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1]); + if (attacker->itembonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1]) + Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) Worn Bonus [All Skills] [Stat Amt: %i]", static_cast(attacker->itembonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1]) / 15.0f, attacker->itembonuses.Accuracy[EQEmu::skills::HIGHEST_SKILL + 1]); if (attacker->aabonuses.Accuracy[skillinuse]) Message(0, "# %.2f #### ATTACKER SE_Accuracy(216) AA Bonus [Skill] [Stat Amt: %i]", static_cast(attacker->aabonuses.Accuracy[skillinuse])/15.0f,attacker->aabonuses.Accuracy[skillinuse]); if (attacker->itembonuses.HitChance) @@ -1053,7 +1053,7 @@ float Mob::Tune_CheckHitChance(Mob* defender, Mob* attacker, SkillUseTypes skill hitBonus += (add_acc / 15.0f); //Modifier from database } - if(skillinuse == SkillArchery){ + if (skillinuse == EQEmu::skills::SkillArchery){ hitBonus -= hitBonus*RuleR(Combat, ArcheryHitPenalty); if (Msg >= 2) Message(0, "# %.2f pct #### RuleR(Combat, ArcheryHitPenalty) ", RuleR(Combat, ArcheryHitPenalty)); diff --git a/zone/water_map.cpp b/zone/water_map.cpp index 604875ed6..f3b4c58d8 100644 --- a/zone/water_map.cpp +++ b/zone/water_map.cpp @@ -12,7 +12,7 @@ WaterMap* WaterMap::LoadWaterMapfile(std::string zone_name) { std::transform(zone_name.begin(), zone_name.end(), zone_name.begin(), ::tolower); - std::string file_path = MAP_DIR + std::string("/") + zone_name + std::string(".wtr"); + std::string file_path = Config->MapDir + zone_name + std::string(".wtr"); FILE *f = fopen(file_path.c_str(), "rb"); if(f) { char magic[10]; @@ -33,7 +33,7 @@ WaterMap* WaterMap::LoadWaterMapfile(std::string zone_name) { } if(version == 1) { - WaterMapV1 *wm = new WaterMapV1(); + auto wm = new WaterMapV1(); if(!wm->Load(f)) { delete wm; wm = nullptr; @@ -42,7 +42,7 @@ WaterMap* WaterMap::LoadWaterMapfile(std::string zone_name) { fclose(f); return wm; } else if(version == 2) { - WaterMapV2 *wm = new WaterMapV2(); + auto wm = new WaterMapV2(); if(!wm->Load(f)) { delete wm; wm = nullptr; @@ -57,4 +57,4 @@ WaterMap* WaterMap::LoadWaterMapfile(std::string zone_name) { } return nullptr; -} \ No newline at end of file +} diff --git a/zone/water_map.h b/zone/water_map.h index 01936efbc..975703b40 100644 --- a/zone/water_map.h +++ b/zone/water_map.h @@ -3,10 +3,12 @@ #include "../common/types.h" #include "position.h" +#include "zone_config.h" #include +extern const ZoneConfig *Config; -enum WaterRegionType { +enum WaterRegionType : int { RegionTypeUnsupported = -2, RegionTypeUntagged = -1, RegionTypeNormal = 0, @@ -31,6 +33,8 @@ public: virtual bool InVWater(const glm::vec3& location) const = 0; virtual bool InLava(const glm::vec3& location) const = 0; virtual bool InLiquid(const glm::vec3& location) const = 0; + virtual bool InPvP(const glm::vec3& location) const = 0; + virtual bool InZoneLine(const glm::vec3& location) const = 0; protected: virtual bool Load(FILE *fp) { return false; } diff --git a/zone/water_map_v1.cpp b/zone/water_map_v1.cpp index 431df4224..7d2479a3b 100644 --- a/zone/water_map_v1.cpp +++ b/zone/water_map_v1.cpp @@ -30,6 +30,14 @@ bool WaterMapV1::InLiquid(const glm::vec3& location) const { return InWater(location) || InLava(location); } +bool WaterMapV1::InPvP(const glm::vec3& location) const { + return ReturnRegionType(location) == RegionTypePVP; +} + +bool WaterMapV1::InZoneLine(const glm::vec3& location) const { + return ReturnRegionType(location) == RegionTypeZoneLine; +} + bool WaterMapV1::Load(FILE *fp) { uint32 bsp_tree_size; if (fread(&bsp_tree_size, sizeof(bsp_tree_size), 1, fp) != 1) { diff --git a/zone/water_map_v1.h b/zone/water_map_v1.h index 6697aa0c8..af4d4966f 100644 --- a/zone/water_map_v1.h +++ b/zone/water_map_v1.h @@ -24,6 +24,8 @@ public: virtual bool InVWater(const glm::vec3& location) const; virtual bool InLava(const glm::vec3& location) const; virtual bool InLiquid(const glm::vec3& location) const; + virtual bool InPvP(const glm::vec3& location) const; + virtual bool InZoneLine(const glm::vec3& location) const; protected: virtual bool Load(FILE *fp); diff --git a/zone/water_map_v2.cpp b/zone/water_map_v2.cpp index a57999a48..939b9be97 100644 --- a/zone/water_map_v2.cpp +++ b/zone/water_map_v2.cpp @@ -33,6 +33,14 @@ bool WaterMapV2::InLiquid(const glm::vec3& location) const { return InWater(location) || InLava(location); } +bool WaterMapV2::InPvP(const glm::vec3& location) const { + return ReturnRegionType(location) == RegionTypePVP; +} + +bool WaterMapV2::InZoneLine(const glm::vec3& location) const { + return ReturnRegionType(location) == RegionTypeZoneLine; +} + bool WaterMapV2::Load(FILE *fp) { uint32 region_count; if (fread(®ion_count, sizeof(region_count), 1, fp) != 1) { diff --git a/zone/water_map_v2.h b/zone/water_map_v2.h index 6429937f0..704d1a119 100644 --- a/zone/water_map_v2.h +++ b/zone/water_map_v2.h @@ -17,6 +17,8 @@ public: virtual bool InVWater(const glm::vec3& location) const; virtual bool InLava(const glm::vec3& location) const; virtual bool InLiquid(const glm::vec3& location) const; + virtual bool InPvP(const glm::vec3& location) const; + virtual bool InZoneLine(const glm::vec3& location) const; protected: virtual bool Load(FILE *fp); diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index d3b85bf03..f6c55a5eb 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -94,7 +94,7 @@ void NPC::ResumeWandering() { if (GetGrid() < 0) { // we were paused by a quest - AIwalking_timer->Disable(); + AI_walking_timer->Disable(); SetGrid( 0 - GetGrid()); if (cur_wp==-1) { // got here by a MoveTo() @@ -103,10 +103,10 @@ void NPC::ResumeWandering() } Log.Out(Logs::Detail, Logs::Pathing, "Resume Wandering requested. Grid %d, wp %d", GetGrid(), cur_wp); } - else if (AIwalking_timer->Enabled()) + else if (AI_walking_timer->Enabled()) { // we are at a waypoint paused normally Log.Out(Logs::Detail, Logs::Pathing, "Resume Wandering on timed pause. Grid %d, wp %d", GetGrid(), cur_wp); - AIwalking_timer->Trigger(); // disable timer to end pause now + AI_walking_timer->Trigger(); // disable timer to end pause now } else { @@ -145,7 +145,7 @@ void NPC::PauseWandering(int pausetime) } else { // specified waiting time, he'll resume after that - AIwalking_timer->Start(pausetime*1000); // set the timer + AI_walking_timer->Start(pausetime*1000); // set the timer } } else { Log.Out(Logs::General, Logs::Error, "NPC not on grid - can't pause wandering: %lu", (unsigned long)GetNPCTypeID()); @@ -162,7 +162,7 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot) SetGrid( 0 - GetGrid()); // get him moving again Log.Out(Logs::Detail, Logs::AI, "MoveTo during quest wandering. Canceling quest wandering and going back to grid %d when MoveTo is done.", GetGrid()); } - AIwalking_timer->Disable(); // disable timer in case he is paused at a wp + AI_walking_timer->Disable(); // disable timer in case he is paused at a wp if (cur_wp>=0) { // we've not already done a MoveTo() save_wp=cur_wp; // save the current waypoint @@ -193,8 +193,8 @@ void NPC::MoveTo(const glm::vec4& position, bool saveguardspot) m_CurrentWayPoint = position; cur_wp_pause = 0; pLastFightingDelayMoving = 0; - if(AIwalking_timer->Enabled()) - AIwalking_timer->Start(100); + if(AI_walking_timer->Enabled()) + AI_walking_timer->Start(100); } void NPC::UpdateWaypoint(int wp_index) @@ -212,7 +212,7 @@ void NPC::UpdateWaypoint(int wp_index) Log.Out(Logs::Detail, Logs::AI, "Next waypoint %d: (%.3f, %.3f, %.3f, %.3f)", wp_index, m_CurrentWayPoint.x, m_CurrentWayPoint.y, m_CurrentWayPoint.z, m_CurrentWayPoint.w); //fix up pathing Z - if(zone->HasMap() && RuleB(Map, FixPathingZAtWaypoints)) + if(zone->HasMap() && RuleB(Map, FixPathingZAtWaypoints) && !IsBoat()) { if(!RuleB(Watermap, CheckForWaterAtWaypoints) || !zone->HasWaterMap() || @@ -253,7 +253,7 @@ void NPC::CalculateNewWaypoint() { std::list closest; GetClosestWaypoint(closest, 10, glm::vec3(GetPosition())); - std::list::iterator iter = closest.begin(); + auto iter = closest.begin(); if(closest.size() != 0) { iter = closest.begin(); @@ -310,7 +310,7 @@ void NPC::CalculateNewWaypoint() std::list closest; GetClosestWaypoint(closest, 5, glm::vec3(GetPosition())); - std::list::iterator iter = closest.begin(); + auto iter = closest.begin(); while(iter != closest.end()) { if(CheckLosFN((*iter).x, (*iter).y, (*iter).z, GetSize())) @@ -380,7 +380,7 @@ void NPC::GetClosestWaypoint(std::list &wp_list, int count, const glm::v return a.dist < b.dist; }); - std::list::iterator iter = distances.begin(); + auto iter = distances.begin(); for(int i = 0; i < count; ++i) { wp_list.push_back(Waypoints[(*iter).index]); @@ -393,7 +393,8 @@ void NPC::SetWaypointPause() //Declare time to wait on current WP if (cur_wp_pause == 0) { - AIwalking_timer->Start(100); + AI_walking_timer->Start(100); + AI_walking_timer->Trigger(); } else { @@ -401,13 +402,13 @@ void NPC::SetWaypointPause() switch (pausetype) { case 0: //Random Half - AIwalking_timer->Start((cur_wp_pause - zone->random.Int(0, cur_wp_pause-1)/2)*1000); + AI_walking_timer->Start((cur_wp_pause - zone->random.Int(0, cur_wp_pause-1)/2)*1000); break; case 1: //Full - AIwalking_timer->Start(cur_wp_pause*1000); + AI_walking_timer->Start(cur_wp_pause*1000); break; case 2: //Random Full - AIwalking_timer->Start(zone->random.Int(0, cur_wp_pause-1)*1000); + AI_walking_timer->Start(zone->random.Int(0, cur_wp_pause-1)*1000); break; } } @@ -436,38 +437,16 @@ void NPC::NextGuardPosition() { { if(moved) { - moved=false; - SetMoving(false); - SendPosition(); + moved = false; + SetCurrentSpeed(0); } } } -/* -// we need this for charmed NPCs -void Mob::SaveSpawnSpot() { - spawn_x = x_pos; - spawn_y = y_pos; - spawn_z = z_pos; - spawn_heading = heading; -}*/ - - - - -/*float Mob::CalculateDistanceToNextWaypoint() { - return CalculateDistance(cur_wp_x, cur_wp_y, cur_wp_z); -}*/ - 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)) ); } -/* -uint8 NPC::CalculateHeadingToNextWaypoint() { - return CalculateHeadingToTarget(cur_wp_x, cur_wp_y); -} -*/ float Mob::CalculateHeadingToTarget(float in_x, float in_y) { float angle; @@ -489,17 +468,23 @@ float Mob::CalculateHeadingToTarget(float in_x, float in_y) { return (256*(360-angle)/360.0f); } -bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool checkZ) { +bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ) { if(GetID()==0) return true; + if(speed <= 0) + { + SetCurrentSpeed(0); + return true; + } + if ((m_Position.x-x == 0) && (m_Position.y-y == 0)) {//spawn is at target coords if(m_Position.z-z != 0) { m_Position.z = z; Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): Jumping pure Z.", x, y, z); return true; } - Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f) inWater=%d: We are there.", x, y, z, inWater); + // Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f) inWater=%d: We are there.", x, y, z, inWater); return false; } else if ((std::abs(m_Position.x - x) < 0.1) && (std::abs(m_Position.y - y) < 0.1)) { Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): X/Y difference <0.1, Jumping to target.", x, y, z); @@ -514,7 +499,8 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b return true; } - int compare_steps = IsBoat() ? 1 : 20; + bool send_update = false; + int compare_steps = 20; if(tar_ndx < compare_steps && m_TargetLocation.x==x && m_TargetLocation.y==y) { float new_x = m_Position.x + m_TargetV.x*tar_vector; @@ -586,7 +572,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b m_TargetV.x = x - nx; m_TargetV.y = y - ny; m_TargetV.z = z - nz; - + SetCurrentSpeed((int8)speed); + pRunAnimSpeed = speed; + if(IsClient()) + { + animation = speed / 2; + } //pRunAnimSpeed = (int8)(speed*NPC_RUNANIM_RATIO); //speed *= NPC_SPEED_MULTIPLIER; @@ -596,10 +587,10 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b // 2: get unit vector // -------------------------------------------------------------------------- float mag = sqrtf (m_TargetV.x*m_TargetV.x + m_TargetV.y*m_TargetV.y + m_TargetV.z*m_TargetV.z); - tar_vector = speed / mag; + tar_vector = (float)speed / mag; // mob move fix - int numsteps = (int) ( mag * 20 / speed) + 1; + int numsteps = (int) ( mag * 16.0f / (float)speed + 0.5f); // mob move fix @@ -609,9 +600,9 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b if (numsteps>1) { tar_vector=1.0f ; - m_TargetV.x = m_TargetV.x/numsteps; - m_TargetV.y = m_TargetV.y/numsteps; - m_TargetV.z = m_TargetV.z/numsteps; + m_TargetV.x = m_TargetV.x/(float)numsteps; + m_TargetV.y = m_TargetV.y/(float)numsteps; + m_TargetV.z = m_TargetV.z/(float)numsteps; float new_x = m_Position.x + m_TargetV.x; float new_y = m_Position.y + m_TargetV.y; @@ -624,7 +615,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b m_Position.y = new_y; m_Position.z = new_z; m_Position.w = CalculateHeadingToTarget(x, y); - tar_ndx = 22 - numsteps; + tar_ndx = 20 - numsteps; Log.Out(Logs::Detail, Logs::AI, "Next position2 (%.3f, %.3f, %.3f) (%d steps)", m_Position.x, m_Position.y, m_Position.z, numsteps); } else @@ -643,7 +634,12 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b } else { - tar_vector/=20; + tar_vector/=16.0f; + float dur = Timer::GetCurrentTime() - pLastChange; + if(dur < 1.0f) { + dur = 1.0f; + } + tar_vector = (tar_vector * AImovement_duration) / 100.0f; float new_x = m_Position.x + m_TargetV.x*tar_vector; float new_y = m_Position.y + m_TargetV.y*tar_vector; @@ -699,25 +695,25 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f); if (IsClient()) + { SendPosUpdate(1); + CastToClient()->ResetPositionTimer(); + } else + { SendPosUpdate(); + SetAppearance(eaStanding, false); + } - SetAppearance(eaStanding, false); pLastChange = Timer::GetCurrentTime(); return true; } -bool Mob::CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ) { - if(IsNPC() || IsClient() || IsPet()) { - pRunAnimSpeed = (int8)(speed*NPC_RUNANIM_RATIO); - speed *= NPC_SPEED_MULTIPLIER; - } - +bool Mob::CalculateNewPosition2(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { return MakeNewPositionAndSendUpdate(x, y, z, speed, checkZ); } -bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool checkZ) { +bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ, bool calcHeading) { if(GetID()==0) return true; @@ -726,14 +722,12 @@ bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool chec float nz = m_Position.z; // if NPC is rooted - if (speed == 0.0) { + if (speed == 0) { SetHeading(CalculateHeadingToTarget(x, y)); if(moved){ - SendPosition(); - SetMoving(false); + SetCurrentSpeed(0); moved=false; } - SetRunAnimSpeed(0); Log.Out(Logs::Detail, Logs::AI, "Rooted while calculating new position to (%.3f, %.3f, %.3f)", x, y, z); return true; } @@ -745,8 +739,8 @@ bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool chec if (m_TargetV.x == 0 && m_TargetV.y == 0) return false; - pRunAnimSpeed = (uint8)(speed*NPC_RUNANIM_RATIO); - speed *= NPC_SPEED_MULTIPLIER; + SetCurrentSpeed((int8)(speed)); //*NPC_RUNANIM_RATIO); + //speed *= NPC_SPEED_MULTIPLIER; Log.Out(Logs::Detail, Logs::AI, "Calculating new position to (%.3f, %.3f, %.3f) vector (%.3f, %.3f, %.3f) rate %.3f RAS %d", x, y, z, m_TargetV.x, m_TargetV.y, m_TargetV.z, speed, pRunAnimSpeed); @@ -1039,7 +1033,7 @@ void ZoneDatabase::AssignGrid(Client *client, int grid, int spawn2id) { if (!results.Success()) return; - + if (results.RowsAffected() != 1) { return; } @@ -1192,8 +1186,7 @@ uint32 ZoneDatabase::GetFreeGrid(uint16 zoneid) { return 0; auto row = results.begin(); - uint32 freeGridID = 1; - freeGridID = atoi(row[0]) + 1; + uint32 freeGridID = row[0] ? atoi(row[0]) + 1 : 1; return freeGridID; } diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index bd8f43271..5e0ada143 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemu.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -39,6 +39,7 @@ #include "client.h" #include "corpse.h" #include "entity.h" +#include "quest_parser_collection.h" #include "guild_mgr.h" #include "mob.h" #include "net.h" @@ -54,7 +55,7 @@ extern EntityList entity_list; extern Zone* zone; -extern volatile bool ZoneLoaded; +extern volatile bool is_zone_loaded; extern void CatchSignal(int); extern WorldServer worldserver; extern NetConnection net; @@ -62,6 +63,9 @@ extern PetitionList petition_list; extern uint32 numclients; extern volatile bool RunLoops; extern std::map remote_call_methods; +extern QuestParserCollection *parse; + +// QuestParserCollection *parse = 0; WorldServer::WorldServer() : WorldConnection(EmuTCPConnection::packetModeZone) @@ -87,8 +91,8 @@ WorldServer::~WorldServer() { safe_delete(pack); }*/ -void WorldServer::SetZone(uint32 iZoneID, uint32 iInstanceID) { - ServerPacket* pack = new ServerPacket(ServerOP_SetZone, sizeof(SetZone_Struct)); +void WorldServer::SetZoneData(uint32 iZoneID, uint32 iInstanceID) { + auto pack = new ServerPacket(ServerOP_SetZone, sizeof(SetZone_Struct)); SetZone_Struct* szs = (SetZone_Struct*) pack->pBuffer; szs->zoneid = iZoneID; szs->instanceid = iInstanceID; @@ -101,10 +105,9 @@ void WorldServer::SetZone(uint32 iZoneID, uint32 iInstanceID) { void WorldServer::OnConnected() { WorldConnection::OnConnected(); - ServerPacket* pack; - //tell the launcher what name we were started with. + /* Tell the launcher what our information is */ pack = new ServerPacket(ServerOP_SetLaunchName,sizeof(LaunchName_Struct)); LaunchName_Struct* ln = (LaunchName_Struct*)pack->pBuffer; strn0cpy(ln->launcher_name, m_launcherName.c_str(), 32); @@ -112,19 +115,38 @@ void WorldServer::OnConnected() { SendPacket(pack); safe_delete(pack); + /* Tell the Worldserver basic information about this zone process */ pack = new ServerPacket(ServerOP_SetConnectInfo, sizeof(ServerConnectInfo)); ServerConnectInfo* sci = (ServerConnectInfo*) pack->pBuffer; + + auto config = ZoneConfig::get(); sci->port = ZoneConfig::get()->ZonePort; + if(config->WorldAddress.length() > 0) { + strn0cpy(sci->address, config->WorldAddress.c_str(), 250); + } + if(config->LocalAddress.length() > 0) { + strn0cpy(sci->local_address, config->LocalAddress.c_str(), 250); + } + + /* Fetch process ID */ + if (getpid()){ + sci->process_id = getpid(); + } + else { + sci->process_id = 0; + } + SendPacket(pack); safe_delete(pack); - if (ZoneLoaded) { - this->SetZone(zone->GetZoneID(), zone->GetInstanceID()); + if (is_zone_loaded) { + this->SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); entity_list.UpdateWho(true); this->SendEmoteMessage(0, 0, 15, "Zone connect: %s", zone->GetLongName()); - zone->GetTimeSync(); - } else { - this->SetZone(0); + zone->GetTimeSync(); + } + else { + this->SetZoneData(0); } pack = new ServerPacket(ServerOP_LSZoneBoot,sizeof(ZoneBoot_Struct)); @@ -167,7 +189,7 @@ void WorldServer::Process() { break; } case ServerOP_ChannelMessage: { - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*) pack->pBuffer; if (scm->deliverto[0] == 0) { @@ -200,12 +222,12 @@ void WorldServer::Process() { } case ServerOP_VoiceMacro: { - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*) pack->pBuffer; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_VoiceMacroOut,sizeof(VoiceMacroOut_Struct)); + auto outapp = new EQApplicationPacket(OP_VoiceMacroOut, sizeof(VoiceMacroOut_Struct)); VoiceMacroOut_Struct* vmo = (VoiceMacroOut_Struct*)outapp->pBuffer; strcpy(vmo->From, svm->From); @@ -257,7 +279,7 @@ void WorldServer::Process() { case ServerOP_SpawnCondition: { if(pack->size != sizeof(ServerSpawnCondition_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerSpawnCondition_Struct* ssc = (ServerSpawnCondition_Struct*) pack->pBuffer; @@ -267,7 +289,7 @@ void WorldServer::Process() { case ServerOP_SpawnEvent: { if(pack->size != sizeof(ServerSpawnEvent_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerSpawnEvent_Struct* sse = (ServerSpawnEvent_Struct*) pack->pBuffer; @@ -278,7 +300,7 @@ void WorldServer::Process() { case ServerOP_AcceptWorldEntrance: { if(pack->size != sizeof(WorldToZone_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; WorldToZone_Struct* wtz = (WorldToZone_Struct*) pack->pBuffer; @@ -293,7 +315,7 @@ void WorldServer::Process() { case ServerOP_ZoneToZoneRequest: { if(pack->size != sizeof(ZoneToZone_Struct)) break; - if (!ZoneLoaded) + if (!is_zone_loaded) break; ZoneToZone_Struct* ztz = (ZoneToZone_Struct*) pack->pBuffer; @@ -369,7 +391,7 @@ void WorldServer::Process() { break; } case ServerOP_WhoAllReply:{ - if(!ZoneLoaded) + if(!is_zone_loaded) break; @@ -380,10 +402,10 @@ void WorldServer::Process() { if(pack->size==64)//no results client->Message_StringID(0,WHOALL_NO_RESULTS); else{ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_WhoAllResponse, pack->size); - memcpy(outapp->pBuffer, pack->pBuffer, pack->size); - client->QueuePacket(outapp); - safe_delete(outapp); + auto outapp = new EQApplicationPacket(OP_WhoAllResponse, pack->size); + memcpy(outapp->pBuffer, pack->pBuffer, pack->size); + client->QueuePacket(outapp); + safe_delete(outapp); } } else { @@ -396,7 +418,7 @@ void WorldServer::Process() { break; } case ServerOP_EmoteMessage: { - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer; if (sem->to[0] != 0) { @@ -454,8 +476,8 @@ void WorldServer::Process() { break; } // Annouce the change to the world - if (!ZoneLoaded) { - SetZone(0); + if (!is_zone_loaded) { + SetZoneData(0); } else { SendEmoteMessage(0, 0, 15, "Zone shutdown: %s", zone->GetLongName()); @@ -472,8 +494,8 @@ void WorldServer::Process() { break; } ServerZoneStateChange_struct* zst = (ServerZoneStateChange_struct *) pack->pBuffer; - if (ZoneLoaded) { - SetZone(zone->GetZoneID(), zone->GetInstanceID()); + if (is_zone_loaded) { + SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); if (zst->zoneid == zone->GetZoneID()) { // This packet also doubles as "incoming client" notification, lets not shut down before they get here zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000); @@ -487,9 +509,7 @@ void WorldServer::Process() { if (zst->adminname[0] != 0) std::cout << "Zone bootup by " << zst->adminname << std::endl; - if (!(Zone::Bootup(zst->zoneid, zst->instanceid, zst->makestatic))) { - SendChannelMessage(0, 0, 10, 0, 0, "%s:%i Zone::Bootup failed: %s", net.GetZoneAddress(), net.GetZonePort(), database.GetZoneName(zst->zoneid)); - } + Zone::Bootup(zst->zoneid, zst->instanceid, zst->makestatic); break; } case ServerOP_ZoneIncClient: { @@ -498,8 +518,8 @@ void WorldServer::Process() { break; } ServerZoneIncomingClient_Struct* szic = (ServerZoneIncomingClient_Struct*) pack->pBuffer; - if (ZoneLoaded) { - SetZone(zone->GetZoneID(), zone->GetInstanceID()); + if (is_zone_loaded) { + SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); if (szic->zoneid == zone->GetZoneID()) { zone->AddAuth(szic); // This packet also doubles as "incoming client" notification, lets not shut down before they get here @@ -510,8 +530,6 @@ void WorldServer::Process() { if ((Zone::Bootup(szic->zoneid, szic->instanceid))) { zone->AddAuth(szic); } - else - SendEmoteMessage(0, 0, 100, 0, "%s:%i Zone::Bootup failed: %s (%i)", net.GetZoneAddress(), net.GetZonePort(), database.GetZoneName(szic->zoneid, true), szic->zoneid); } break; } @@ -537,7 +555,7 @@ void WorldServer::Process() { if (client != 0) { if (skp->adminrank >= client->Admin()) { client->WorldKick(); - if (ZoneLoaded) + if (is_zone_loaded) SendEmoteMessage(skp->adminname, 0, 0, "Remote Kick: %s booted in zone %s.", skp->name, zone->GetShortName()); else SendEmoteMessage(skp->adminname, 0, 0, "Remote Kick: %s booted.", skp->name); @@ -553,7 +571,7 @@ void WorldServer::Process() { if (client != 0) { if (skp->admin >= client->Admin()) { client->GMKill(); - if (ZoneLoaded) + if (is_zone_loaded) SendEmoteMessage(skp->gmname, 0, 0, "Remote Kill: %s killed in zone %s.", skp->target, zone->GetShortName()); else SendEmoteMessage(skp->gmname, 0, 0, "Remote Kill: %s killed.", skp->target); @@ -591,13 +609,13 @@ void WorldServer::Process() { std::cout << "Wrong size on ServerOP_GMGoto. Got: " << pack->size << ", Expected: " << sizeof(ServerGMGoto_Struct) << std::endl; break; } - if (!ZoneLoaded) + if (!is_zone_loaded) break; ServerGMGoto_Struct* gmg = (ServerGMGoto_Struct*) pack->pBuffer; Client* client = entity_list.GetClientByName(gmg->gotoname); if (client != 0) { SendEmoteMessage(gmg->myname, 0, 13, "Summoning you to: %s @ %s, %1.1f, %1.1f, %1.1f", client->GetName(), zone->GetShortName(), client->GetX(), client->GetY(), client->GetZ()); - ServerPacket* outpack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct)); + auto outpack = new ServerPacket(ServerOP_ZonePlayer, sizeof(ServerZonePlayer_Struct)); ServerZonePlayer_Struct* szp = (ServerZonePlayer_Struct*) outpack->pBuffer; strcpy(szp->adminname, gmg->myname); strcpy(szp->name, gmg->myname); @@ -618,7 +636,7 @@ void WorldServer::Process() { ServerMultiLineMsg_Struct* mlm = (ServerMultiLineMsg_Struct*) pack->pBuffer; Client* client = entity_list.GetClientByName(mlm->to); if (client) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_MultiLineMsg, strlen(mlm->message)); + auto outapp = new EQApplicationPacket(OP_MultiLineMsg, strlen(mlm->message)); strcpy((char*) outapp->pBuffer, mlm->message); client->QueuePacket(outapp); safe_delete(outapp); @@ -665,7 +683,8 @@ void WorldServer::Process() { { if(client->IsRezzPending()) { - ServerPacket * Response = new ServerPacket(ServerOP_RezzPlayerReject, strlen(srs->rez.rezzer_name) + 1); + auto Response = new ServerPacket(ServerOP_RezzPlayerReject, + strlen(srs->rez.rezzer_name) + 1); char *Buffer = (char *)Response->pBuffer; sprintf(Buffer, "%s", srs->rez.rezzer_name); @@ -678,12 +697,12 @@ void WorldServer::Process() { client->SetPendingRezzData(srs->exp, srs->dbid, srs->rez.spellid, srs->rez.corpse_name); Log.Out(Logs::Detail, Logs::Spells, "OP_RezzRequest in zone %s for %s, spellid:%i", zone->GetShortName(), client->GetName(), srs->rez.spellid); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RezzRequest, - sizeof(Resurrect_Struct)); - memcpy(outapp->pBuffer, &srs->rez, sizeof(Resurrect_Struct)); - client->QueuePacket(outapp); - safe_delete(outapp); - break; + auto outapp = new EQApplicationPacket(OP_RezzRequest, + sizeof(Resurrect_Struct)); + memcpy(outapp->pBuffer, &srs->rez, sizeof(Resurrect_Struct)); + client->QueuePacket(outapp); + safe_delete(outapp); + break; } } if (srs->rezzopcode == OP_RezzComplete){ @@ -717,59 +736,39 @@ void WorldServer::Process() { case ServerOP_ZoneReboot: { std::cout << "Got Server Requested Zone reboot" << std::endl; ServerZoneReboot_Struct* zb = (ServerZoneReboot_Struct*) pack->pBuffer; - // printf("%i\n",zb->zoneid); - struct in_addr in; - in.s_addr = GetIP(); -#ifdef _WINDOWS - char buffer[200]; - snprintf(buffer,200,". %s %i %s",zb->ip2, zb->port, inet_ntoa(in)); - if(zb->zoneid != 0) { - snprintf(buffer,200,"%s %s %i %s",database.GetZoneName(zb->zoneid),zb->ip2, zb->port ,inet_ntoa(in)); - std::cout << "executing: " << buffer; - ShellExecute(0,"Open",net.GetZoneFileName(), buffer, 0, SW_SHOWDEFAULT); - } - else - { - std::cout << "executing: " << net.GetZoneFileName() << " " << buffer; - ShellExecute(0,"Open",net.GetZoneFileName(), buffer, 0, SW_SHOWDEFAULT); - } -#else - char buffer[5]; - snprintf(buffer,5,"%i",zb->port); //just to be sure that it will work on linux - if(zb->zoneid != 0) - execl(net.GetZoneFileName(),net.GetZoneFileName(),database.GetZoneName(zb->zoneid),zb->ip2, buffer,inet_ntoa(in), nullptr); - else - execl(net.GetZoneFileName(),net.GetZoneFileName(),".",zb->ip2, buffer,inet_ntoa(in), nullptr); -#endif break; } case ServerOP_SyncWorldTime: { - if(zone!=0) { + if (zone != 0 && !zone->is_zone_time_localized) { Log.Out(Logs::Moderate, Logs::Zone_Server, "%s Received Message SyncWorldTime", __FUNCTION__); - eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer; - zone->zone_time.setEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); - TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer; - zone->zone_time.getEQTimeOfDay(time(0), tod); + + eqTimeOfDay* newtime = (eqTimeOfDay*)pack->pBuffer; + zone->zone_time.SetCurrentEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime); + auto outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); + TimeOfDay_Struct* time_of_day = (TimeOfDay_Struct*)outapp->pBuffer; + zone->zone_time.GetCurrentEQTimeOfDay(time(0), time_of_day); entity_list.QueueClients(0, outapp, false); safe_delete(outapp); - //TEST - char timeMessage[255]; - time_t timeCurrent = time(nullptr); - TimeOfDay_Struct eqTime; - zone->zone_time.getEQTimeOfDay( timeCurrent, &eqTime); - //if ( eqTime.hour >= 0 && eqTime.minute >= 0 ) - //{ - sprintf(timeMessage,"EQTime [%02d:%s%d %s]", - ((eqTime.hour - 1) % 12) == 0 ? 12 : ((eqTime.hour - 1) % 12), - (eqTime.minute < 10) ? "0" : "", - eqTime.minute, - (eqTime.hour >= 13) ? "pm" : "am" - ); - Log.Out(Logs::General, Logs::Zone_Server, "Time Broadcast Packet: %s", timeMessage); - zone->GotCurTime(true); - //} - //Test + + /* Buffer garbage to generate debug message */ + char time_message[255]; + time_t current_time = time(nullptr); + TimeOfDay_Struct eq_time; + zone->zone_time.GetCurrentEQTimeOfDay(current_time, &eq_time); + + sprintf(time_message, "EQTime [%02d:%s%d %s]", + ((eq_time.hour - 1) % 12) == 0 ? 12 : ((eq_time.hour - 1) % 12), + (eq_time.minute < 10) ? "0" : "", + eq_time.minute, + (eq_time.hour >= 13) ? "pm" : "am" + ); + + Log.Out(Logs::General, Logs::Zone_Server, "Time Broadcast Packet: %s", time_message); + zone->SetZoneHasCurrentTime(true); + + } + if (zone && zone->is_zone_time_localized){ + Log.Out(Logs::General, Logs::Zone_Server, "Received request to sync time from world, but our time is localized currently"); } break; } @@ -829,7 +828,7 @@ void WorldServer::Process() { if(Invitee && Invitee->IsClient() && Invitee->CastToClient()->MercOnlyOrNoGroup() && !Invitee->IsRaidGrouped()) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupInvite, sizeof(GroupInvite_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupInvite, sizeof(GroupInvite_Struct)); memcpy(outapp->pBuffer, gis, sizeof(GroupInvite_Struct)); Invitee->CastToClient()->QueuePacket(outapp); safe_delete(outapp); @@ -868,9 +867,10 @@ void WorldServer::Process() { database.SetGroupLeaderName(group->GetID(), Inviter->GetName()); group->UpdateGroupAAs(); - if(Inviter->CastToClient()->GetClientVersion() < ClientVersion::SoD) + if (Inviter->CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::SoD) { - EQApplicationPacket* outapp=new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupJoin_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* outgj=(GroupJoin_Struct*)outapp->pBuffer; strcpy(outgj->membername, Inviter->GetName()); strcpy(outgj->yourname, Inviter->GetName()); @@ -893,7 +893,7 @@ void WorldServer::Process() { break; } - EQApplicationPacket* outapp=new EQApplicationPacket(OP_GroupFollow, sizeof(GroupGeneric_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupFollow, sizeof(GroupGeneric_Struct)); GroupGeneric_Struct *gg = (GroupGeneric_Struct *)outapp->pBuffer; strn0cpy(gg->name1, sgfs->gf.name1, sizeof(gg->name1)); strn0cpy(gg->name2, sgfs->gf.name2, sizeof(gg->name2)); @@ -906,7 +906,7 @@ void WorldServer::Process() { if(Inviter->CastToClient()->IsLFP()) Inviter->CastToClient()->UpdateLFP(); - ServerPacket* pack2 = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct)); + auto pack2 = new ServerPacket(ServerOP_GroupJoin, sizeof(ServerGroupJoin_Struct)); ServerGroupJoin_Struct* gj = (ServerGroupJoin_Struct*)pack2->pBuffer; gj->gid = group->GetID(); gj->zoneid = zone->GetZoneID(); @@ -918,7 +918,8 @@ void WorldServer::Process() { // Send acknowledgement back to the Invitee to let them know we have added them to the group. - ServerPacket* pack3 = new ServerPacket(ServerOP_GroupFollowAck, sizeof(ServerGroupFollowAck_Struct)); + auto pack3 = + new ServerPacket(ServerOP_GroupFollowAck, sizeof(ServerGroupFollowAck_Struct)); ServerGroupFollowAck_Struct* sgfas = (ServerGroupFollowAck_Struct*)pack3->pBuffer; strn0cpy(sgfas->Name, sgfs->gf.name2, sizeof(sgfas->Name)); worldserver.SendPacket(pack3); @@ -1015,7 +1016,7 @@ void WorldServer::Process() { if(Inviter && Inviter->IsClient()) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupCancelInvite, sizeof(GroupCancel_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupCancelInvite, sizeof(GroupCancel_Struct)); memcpy(outapp->pBuffer, sgcs, sizeof(GroupCancel_Struct)); Inviter->CastToClient()->QueuePacket(outapp); safe_delete(outapp); @@ -1238,7 +1239,8 @@ void WorldServer::Process() { Client *c = entity_list.GetClientByName(rga->playername); if(c) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupUpdate_Struct)); + auto outapp = + new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate_Struct)); GroupUpdate_Struct* gu = (GroupUpdate_Struct*) outapp->pBuffer; gu->action = groupActDisband; strn0cpy(gu->leadersname, c->GetName(), 64); @@ -1256,7 +1258,7 @@ void WorldServer::Process() { if(r){ r->LearnMembers(); r->VerifyRaid(); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; strn0cpy(gj->membername, rga->membername, 64); gj->action = groupActJoin; @@ -1287,7 +1289,7 @@ void WorldServer::Process() { if(r){ r->LearnMembers(); r->VerifyRaid(); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); GroupJoin_Struct* gj = (GroupJoin_Struct*) outapp->pBuffer; strn0cpy(gj->membername, rga->membername, 64); gj->action = groupActLeave; @@ -1391,7 +1393,8 @@ void WorldServer::Process() { else client->consent_list.remove(s->ownername); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); + auto outapp = + new EQApplicationPacket(OP_ConsentResponse, sizeof(ConsentResponse_Struct)); ConsentResponse_Struct* crs = (ConsentResponse_Struct*)outapp->pBuffer; strcpy(crs->grantname, s->grantname); strcpy(crs->ownername, s->ownername); @@ -1408,17 +1411,17 @@ void WorldServer::Process() { // CONSENT_INVALID_NAME = 397 // TARGET_NOT_FOUND = 101 - safe_delete(pack); - pack = new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); - ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)pack->pBuffer; + auto scs_pack = + new ServerPacket(ServerOP_Consent_Response, sizeof(ServerOP_Consent_Struct)); + ServerOP_Consent_Struct* scs = (ServerOP_Consent_Struct*)scs_pack->pBuffer; strcpy(scs->grantname, s->grantname); strcpy(scs->ownername, s->ownername); scs->permission = s->permission; scs->zone_id = s->zone_id; scs->instance_id = s->instance_id; scs->message_string_id = TARGET_NOT_FOUND; - worldserver.SendPacket(pack); - safe_delete(pack); + worldserver.SendPacket(scs_pack); + safe_delete(scs_pack); } break; } @@ -1628,7 +1631,7 @@ void WorldServer::Process() { if(c) { c->ClearAdventureData(); - char * adv_data = new char[pack->size]; + auto adv_data = new char[pack->size]; memcpy(adv_data, pack->pBuffer, pack->size); c->SetAdventureData(adv_data); c->ClearPendingAdventureData(); @@ -1736,7 +1739,8 @@ void WorldServer::Process() { Client *c = entity_list.GetClientByName((const char*)pack->pBuffer); if(c) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_AdventureLeaderboardReply, sizeof(AdventureLeaderboard_Struct)); + auto outapp = new EQApplicationPacket(OP_AdventureLeaderboardReply, + sizeof(AdventureLeaderboard_Struct)); memcpy(outapp->pBuffer, pack->pBuffer+64, sizeof(AdventureLeaderboard_Struct)); c->FastQueuePacket(&outapp); } @@ -1751,6 +1755,10 @@ void WorldServer::Process() { database.LoadLogSettings(Log.log_settings); break; } + case ServerOP_ReloadPerlExportSettings: { + parse->LoadPerlEventExportSettings(parse->perl_event_export_settings); + break; + } case ServerOP_CameraShake: { if(zone) @@ -1883,7 +1891,41 @@ void WorldServer::Process() { } break; - } + } + case ServerOP_ChangeSharedMem: + { + std::string hotfix_name = std::string((char*)pack->pBuffer); + Log.Out(Logs::General, Logs::Zone_Server, "Loading items"); + if(!database.LoadItems(hotfix_name)) { + Log.Out(Logs::General, Logs::Error, "Loading items FAILED!"); + } + + Log.Out(Logs::General, Logs::Zone_Server, "Loading npc faction lists"); + if(!database.LoadNPCFactionLists(hotfix_name)) { + Log.Out(Logs::General, Logs::Error, "Loading npcs faction lists FAILED!"); + } + + Log.Out(Logs::General, Logs::Zone_Server, "Loading loot tables"); + if(!database.LoadLoot(hotfix_name)) { + Log.Out(Logs::General, Logs::Error, "Loading loot FAILED!"); + } + + Log.Out(Logs::General, Logs::Zone_Server, "Loading skill caps"); + if(!database.LoadSkillCaps(std::string(hotfix_name))) { + Log.Out(Logs::General, Logs::Error, "Loading skill caps FAILED!"); + } + + Log.Out(Logs::General, Logs::Zone_Server, "Loading spells"); + if(!database.LoadSpells(hotfix_name, &SPDAT_RECORDS, &spells)) { + Log.Out(Logs::General, Logs::Error, "Loading spells FAILED!"); + } + + Log.Out(Logs::General, Logs::Zone_Server, "Loading base data"); + if(!database.LoadBaseData(hotfix_name)) { + Log.Out(Logs::General, Logs::Error, "Loading base data FAILED!"); + } + break; + } default: { std::cout << " Unknown ZSopcode:" << (int)pack->opcode; std::cout << " size:" << pack->size << std::endl; @@ -1907,7 +1949,7 @@ bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_nu va_end(argptr); buffer[511] = '\0'; - ServerPacket* pack = new ServerPacket(ServerOP_ChannelMessage, sizeof(ServerChannelMessage_Struct) + strlen(buffer) + 1); + auto pack = new ServerPacket(ServerOP_ChannelMessage, sizeof(ServerChannelMessage_Struct) + strlen(buffer) + 1); ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*) pack->pBuffer; if (from == 0) { @@ -1939,10 +1981,10 @@ bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_nu bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 type, const char* message, ...) { va_list argptr; - char buffer[256]; + char buffer[4096] = { 0 }; va_start(argptr, message); - vsnprintf(buffer, 256, message, argptr); + vsnprintf(buffer, sizeof(buffer) - 1, message, argptr); va_end(argptr); return SendEmoteMessage(to, to_guilddbid, 0, type, buffer); @@ -1950,10 +1992,10 @@ bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 t bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...) { va_list argptr; - char buffer[256]; + char buffer[4096] = { 0 }; va_start(argptr, message); - vsnprintf(buffer, 256, message, argptr); + vsnprintf(buffer, sizeof(buffer) - 1, message, argptr); va_end(argptr); if (!Connected() && to == 0) { @@ -1961,7 +2003,7 @@ bool WorldServer::SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to return false; } - ServerPacket* pack = new ServerPacket(ServerOP_EmoteMessage, sizeof(ServerEmoteMessage_Struct)+strlen(buffer)+1); + auto pack = new ServerPacket(ServerOP_EmoteMessage, sizeof(ServerEmoteMessage_Struct) + strlen(buffer) + 1); ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*) pack->pBuffer; sem->type = type; if (to != 0) @@ -1981,7 +2023,7 @@ bool WorldServer::SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 if(!worldserver.Connected() || !From) return false; - ServerPacket* pack = new ServerPacket(ServerOP_VoiceMacro, sizeof(ServerVoiceMacro_Struct)); + auto pack = new ServerPacket(ServerOP_VoiceMacro, sizeof(ServerVoiceMacro_Struct)); ServerVoiceMacro_Struct* svm = (ServerVoiceMacro_Struct*) pack->pBuffer; @@ -2004,7 +2046,7 @@ bool WorldServer::SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 svm->Type = Type; - svm->Voice = (GetArrayRace(From->GetRace()) * 2) + From->GetGender(); + svm->Voice = (GetPlayerRaceValue(From->GetRace()) * 2) + From->GetGender(); svm->MacroNumber = MacroNumber; @@ -2020,7 +2062,7 @@ bool WorldServer::SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 bool WorldServer::RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32 dbid, uint16 opcode) { Log.Out(Logs::Detail, Logs::Spells, "WorldServer::RezzPlayer rezzexp is %i (0 is normal for RezzComplete", rezzexp); - ServerPacket* pack = new ServerPacket(ServerOP_RezzPlayer, sizeof(RezzPlayer_Struct)); + auto pack = new ServerPacket(ServerOP_RezzPlayer, sizeof(RezzPlayer_Struct)); RezzPlayer_Struct* sem = (RezzPlayer_Struct*) pack->pBuffer; sem->rezzopcode = opcode; sem->rez = *(Resurrect_Struct*) rpack->pBuffer; @@ -2037,7 +2079,7 @@ bool WorldServer::RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32 } void WorldServer::SendReloadTasks(int Command, int TaskID) { - ServerPacket* pack = new ServerPacket(ServerOP_ReloadTasks, sizeof(ReloadTasks_Struct)); + auto pack = new ServerPacket(ServerOP_ReloadTasks, sizeof(ReloadTasks_Struct)); ReloadTasks_Struct* rts = (ReloadTasks_Struct*) pack->pBuffer; rts->Command = Command; @@ -2111,7 +2153,7 @@ uint32 WorldServer::NextGroupID() { } if(cur_groupid > (last_groupid - /*50*/995)) { //running low, request more - ServerPacket* pack = new ServerPacket(ServerOP_GroupIDReq); + auto pack = new ServerPacket(ServerOP_GroupIDReq); SendPacket(pack); safe_delete(pack); } @@ -2122,7 +2164,7 @@ uint32 WorldServer::NextGroupID() { void WorldServer::UpdateLFP(uint32 LeaderID, uint8 Action, uint8 MatchFilter, uint32 FromLevel, uint32 ToLevel, uint32 Classes, const char *Comments, GroupLFPMemberEntry *LFPMembers) { - ServerPacket* pack = new ServerPacket(ServerOP_LFPUpdate, sizeof(ServerLFPUpdate_Struct)); + auto pack = new ServerPacket(ServerOP_LFPUpdate, sizeof(ServerLFPUpdate_Struct)); ServerLFPUpdate_Struct* sus = (ServerLFPUpdate_Struct*) pack->pBuffer; sus->LeaderID = LeaderID; @@ -2169,7 +2211,7 @@ void WorldServer::HandleLFGMatches(ServerPacket *pack) { smrs++; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_LFGGetMatchesResponse, PacketLength); + auto outapp = new EQApplicationPacket(OP_LFGGetMatchesResponse, PacketLength); smrs = (ServerLFGMatchesResponse_Struct*)Buffer; @@ -2216,7 +2258,7 @@ void WorldServer::HandleLFPMatches(ServerPacket *pack) { } smrs++; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_LFPGetMatchesResponse, PacketLength); + auto outapp = new EQApplicationPacket(OP_LFPGetMatchesResponse, PacketLength); smrs = (ServerLFPMatchesResponse_Struct*)Buffer; @@ -2259,7 +2301,7 @@ void WorldServer::RequestTellQueue(const char *who) if (!who) return; - ServerPacket* pack = new ServerPacket(ServerOP_RequestTellQueue, sizeof(ServerRequestTellQueue_Struct)); + auto pack = new ServerPacket(ServerOP_RequestTellQueue, sizeof(ServerRequestTellQueue_Struct)); ServerRequestTellQueue_Struct* rtq = (ServerRequestTellQueue_Struct*) pack->pBuffer; strn0cpy(rtq->name, who, sizeof(rtq->name)); diff --git a/zone/worldserver.h b/zone/worldserver.h index c1e86421f..e1831ea4c 100644 --- a/zone/worldserver.h +++ b/zone/worldserver.h @@ -37,7 +37,7 @@ public: bool SendEmoteMessage(const char* to, uint32 to_guilddbid, uint32 type, const char* message, ...); bool SendEmoteMessage(const char* to, uint32 to_guilddbid, int16 to_minstatus, uint32 type, const char* message, ...); bool SendVoiceMacro(Client* From, uint32 Type, char* Target, uint32 MacroNumber, uint32 GroupOrRaidID = 0); - void SetZone(uint32 iZoneID, uint32 iInstanceID = 0); + void SetZoneData(uint32 iZoneID, uint32 iInstanceID = 0); uint32 SendGroupIdRequest(); bool RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32 dbid, uint16 opcode); bool IsOOCMuted() const { return(oocmuted); } diff --git a/zone/zone.cpp b/zone/zone.cpp index 2ae6dea43..209d0e79c 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -69,14 +69,13 @@ extern bool staticzone; extern NetConnection net; extern PetitionList petition_list; extern QuestParserCollection* parse; -extern uint16 adverrornum; extern uint32 numclients; extern WorldServer worldserver; extern Zone* zone; Mutex MZoneShutdown; -volatile bool ZoneLoaded = false; +volatile bool is_zone_loaded = false; Zone* zone = 0; bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { @@ -84,9 +83,9 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { if (iZoneID == 0 || zonename == 0) return false; - if (zone != 0 || ZoneLoaded) { + if (zone != 0 || is_zone_loaded) { std::cerr << "Error: Zone::Bootup call when zone already booted!" << std::endl; - worldserver.SetZone(0); + worldserver.SetZoneData(0); return false; } @@ -99,17 +98,18 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { if (!zone->Init(iStaticZone)) { safe_delete(zone); std::cerr << "Zone->Init failed" << std::endl; - worldserver.SetZone(0); + worldserver.SetZoneData(0); return false; } zone->zonemap = Map::LoadMapFile(zone->map_name); zone->watermap = WaterMap::LoadWaterMapfile(zone->map_name); zone->pathing = PathManager::LoadPathFile(zone->map_name); - char tmp[10]; - if (database.GetVariable("loglevel",tmp, 9)) { + std::string tmp; + if (database.GetVariable("loglevel", tmp)) { int log_levels[4]; - if (atoi(tmp)>9){ //Server is using the new code + int tmp_i = atoi(tmp.c_str()); + if (tmp_i>9){ //Server is using the new code for(int i=0;i<4;i++){ if (((int)tmp[i]>=48) && ((int)tmp[i]<=57)) log_levels[i]=(int)tmp[i]-48; //get the value to convert it to an int from the ascii value @@ -126,19 +126,19 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) { Log.Out(Logs::General, Logs::Status, "Loot logging level: %i", zone->lootvar); } else { - zone->loglevelvar = uint8(atoi(tmp)); //continue supporting only command logging (for now) + zone->loglevelvar = uint8(tmp_i); //continue supporting only command logging (for now) zone->merchantvar = 0; zone->tradevar = 0; zone->lootvar = 0; } - } + } - ZoneLoaded = true; + is_zone_loaded = true; - worldserver.SetZone(iZoneID, iInstanceID); + worldserver.SetZoneData(iZoneID, iInstanceID); if(iInstanceID != 0) { - ServerPacket *pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16)); + auto pack = new ServerPacket(ServerOP_AdventureZoneData, sizeof(uint16)); *((uint16*)pack->pBuffer) = iInstanceID; worldserver.SendPacket(pack); delete pack; @@ -216,12 +216,12 @@ bool Zone::LoadZoneObjects() { d.incline = atoi(row[13]); // unknown20 = optional model incline value d.client_version_mask = 0xFFFFFFFF; //We should load the mask from the zone. - Doors* door = new Doors(&d); - entity_list.AddDoor(door); - } + auto door = new Doors(&d); + entity_list.AddDoor(door); + } - Object_Struct data = {0}; - uint32 id = 0; + Object_Struct data = {0}; + uint32 id = 0; uint32 icon = 0; uint32 type = 0; uint32 itemid = 0; @@ -242,8 +242,8 @@ bool Zone::LoadZoneObjects() { data.object_type = type; data.linked_list_addr[0] = 0; data.linked_list_addr[1] = 0; - data.unknown008 = (uint32)atoi(row[11]); - data.unknown010 = (uint32)atoi(row[12]); + data.size = (uint32)atoi(row[11]); + data.solidtype = (uint32)atoi(row[12]); data.unknown020 = (uint32)atoi(row[13]); data.unknown024 = (uint32)atoi(row[14]); data.unknown076 = (uint32)atoi(row[15]); @@ -267,16 +267,16 @@ bool Zone::LoadZoneObjects() { } // Load child objects if container - if (inst && inst->IsType(ItemClassContainer)) { + if (inst && inst->IsType(EQEmu::item::ItemClassBag)) { database.LoadWorldContainer(id, inst); } - Object* object = new Object(id, type, icon, data, inst); - entity_list.AddObject(object, false); - if(type == OT_DROPPEDITEM && itemid != 0) - entity_list.RemoveObject(object->GetID()); + auto object = new Object(id, type, icon, data, inst); + entity_list.AddObject(object, false); + if (type == OT_DROPPEDITEM && itemid != 0) + entity_list.RemoveObject(object->GetID()); - safe_delete(inst); + safe_delete(inst); } return true; @@ -294,7 +294,7 @@ bool Zone::LoadGroundSpawns() { char* name=0; uint32 gsnumber=0; for(gsindex=0;gsindex<50;gsindex++){ - if(groundspawn.spawn[gsindex].item>0 && groundspawn.spawn[gsindex].item<500000){ + if(groundspawn.spawn[gsindex].item>0 && groundspawn.spawn[gsindex].item::iterator iter = cur->second.begin(); + auto iter = cur->second.begin(); bool found = false; while (iter != cur->second.end()) { if ((*iter).item == ml.id) { @@ -662,24 +667,24 @@ void Zone::LoadMercSpells(){ } bool Zone::IsLoaded() { - return ZoneLoaded; + return is_zone_loaded; } void Zone::Shutdown(bool quite) { - if (!ZoneLoaded) + if (!is_zone_loaded) return; entity_list.StopMobAI(); std::map::iterator itr; - while(zone->npctable.size()) { + while(!zone->npctable.empty()) { itr=zone->npctable.begin(); delete itr->second; zone->npctable.erase(itr); } - while(zone->merctable.size()) { + while(!zone->merctable.empty()) { itr=zone->merctable.begin(); delete itr->second; zone->merctable.erase(itr); @@ -688,7 +693,7 @@ void Zone::Shutdown(bool quite) zone->adventure_entry_list_flavor.clear(); std::map::iterator itr4; - while(zone->ldon_trap_list.size()) + while(!zone->ldon_trap_list.empty()) { itr4 = zone->ldon_trap_list.begin(); delete itr4->second; @@ -698,12 +703,13 @@ void Zone::Shutdown(bool quite) Log.Out(Logs::General, Logs::Status, "Zone Shutdown: %s (%i)", zone->GetShortName(), zone->GetZoneID()); petition_list.ClearPetitions(); - zone->GotCurTime(false); + zone->SetZoneHasCurrentTime(false); if (!quite) Log.Out(Logs::General, Logs::Normal, "Zone shutdown: going to sleep"); - ZoneLoaded = false; + is_zone_loaded = false; RemoteCallSubscriptionHandler::Instance()->ClearAllConnections(); + zone->ResetAuth(); safe_delete(zone); entity_list.ClearAreas(); @@ -724,7 +730,7 @@ void Zone::LoadZoneDoors(const char* zone, int16 version) return; } - Door *dlist = new Door[count]; + auto dlist = new Door[count]; if(!database.LoadDoors(count, dlist, zone, version)) { Log.Out(Logs::General, Logs::Error, "... Failed to load doors."); @@ -735,7 +741,7 @@ void Zone::LoadZoneDoors(const char* zone, int16 version) int r; Door *d = dlist; for(r = 0; r < count; r++, d++) { - Doors* newdoor = new Doors(d); + auto newdoor = new Doors(d); entity_list.AddDoor(newdoor); Log.Out(Logs::Detail, Logs::Doors, "Door Add to Entity List, index: %u db id: %u, door_id %u", r, dlist[r].db_id, dlist[r].door_id); } @@ -762,6 +768,8 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name) qGlobals = nullptr; default_ruleset = 0; + is_zone_time_localized = false; + loglevelvar = 0; merchantvar = 0; tradevar = 0; @@ -805,9 +813,7 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name) weather_intensity = 0; blocked_spells = nullptr; totalBS = 0; - aas = nullptr; - totalAAs = 0; - gottime = false; + zone_has_current_time = false; Instance_Shutdown_Timer = nullptr; bool is_perma = false; @@ -849,7 +855,7 @@ Zone::~Zone() { safe_delete(watermap); safe_delete(pathing); if (worldserver.Connected()) { - worldserver.SetZone(0); + worldserver.SetZoneData(0); } safe_delete_array(short_name); safe_delete_array(long_name); @@ -865,16 +871,6 @@ Zone::~Zone() { safe_delete(qGlobals); safe_delete_array(adv_data); safe_delete_array(map_name); - - if(aas != nullptr) { - int r; - for(r = 0; r < totalAAs; r++) { - uchar *data = (uchar *) aas[r]; - safe_delete_array(data); - } - safe_delete_array(aas); - } - safe_delete(GuildBanks); } @@ -953,16 +949,12 @@ bool Zone::Init(bool iStaticZone) { zone->LoadAlternateCurrencies(); zone->LoadNPCEmotes(&NPCEmoteList); - //Load AA information - adverrornum = 500; - LoadAAs(); + LoadAlternateAdvancement(); //Load merchant data - adverrornum = 501; zone->GetMerchantDataForZoneLoad(); //Load temporary merchant data - adverrornum = 502; zone->LoadTempMerchantData(); // Merc data @@ -974,7 +966,6 @@ bool Zone::Init(bool iStaticZone) { if (RuleB(Zone, LevelBasedEXPMods)) zone->LoadLevelEXPMods(); - adverrornum = 503; petition_list.ClearPetitions(); petition_list.ReadDatabase(); @@ -1093,7 +1084,7 @@ bool Zone::SaveZoneCFG() { } void Zone::AddAuth(ServerZoneIncomingClient_Struct* szic) { - ZoneClientAuth_Struct* zca = new ZoneClientAuth_Struct; + auto zca = new ZoneClientAuth_Struct; memset(zca, 0, sizeof(ZoneClientAuth_Struct)); zca->ip = szic->ip; zca->wid = szic->wid; @@ -1364,7 +1355,6 @@ void Zone::ChangeWeather() weathertimer = (duration*60)*1000; Weather_Timer->Start(weathertimer); - zone->zone_weather = 0; zone->weather_intensity = 0; } else if(tmpOldWeather == 2) @@ -1376,7 +1366,6 @@ void Zone::ChangeWeather() weathertimer = (duration*60)*1000; Weather_Timer->Start(weathertimer); - zone->zone_weather = 0; zone->weather_intensity = 0; } } @@ -1395,6 +1384,10 @@ void Zone::ChangeWeather() { Log.Out(Logs::General, Logs::None, "The weather for zone: %s has changed. Old weather was = %i. New weather is = %i The next check will be in %i seconds. Rain chance: %i, Rain duration: %i, Snow chance %i, Snow duration: %i", zone->GetShortName(), tmpOldWeather, zone_weather,Weather_Timer->GetRemainingTime()/1000,rainchance,rainduration,snowchance,snowduration); this->weatherSend(); + if (zone->weather_intensity == 0) + { + zone->zone_weather = 0; + } } } @@ -1430,7 +1423,7 @@ bool Zone::Depop(bool StartSpawnTimer) { entity_list.Depop(StartSpawnTimer); /* Refresh npctable (cache), getting current info from database. */ - while(npctable.size()) { + while(!npctable.empty()) { itr = npctable.begin(); delete itr->second; npctable.erase(itr); @@ -1461,6 +1454,29 @@ void Zone::ClearNPCTypeCache(int id) { } } +void Zone::RepopClose(const glm::vec4& client_position, uint32 repop_distance) +{ + + if (!Depop()) + return; + + LinkedListIterator iterator(spawn2_list); + + iterator.Reset(); + while (iterator.MoreElements()) { + iterator.RemoveCurrent(); + } + + quest_manager.ClearAllTimers(); + + if (!database.PopulateZoneSpawnListClose(zoneid, spawn2_list, GetInstanceVersion(), client_position, repop_distance)) + Log.Out(Logs::General, Logs::None, "Error in Zone::Repop: database.PopulateZoneSpawnList failed"); + + initgrids_timer.Start(); + + mod_repop(); +} + void Zone::Repop(uint32 delay) { if(!Depop()) @@ -1486,8 +1502,8 @@ void Zone::Repop(uint32 delay) { void Zone::GetTimeSync() { - if (worldserver.Connected() && !gottime) { - ServerPacket* pack = new ServerPacket(ServerOP_GetWorldTime, 0); + if (worldserver.Connected() && !zone_has_current_time) { + auto pack = new ServerPacket(ServerOP_GetWorldTime, 0); worldserver.SendPacket(pack); safe_delete(pack); } @@ -1496,7 +1512,7 @@ void Zone::GetTimeSync() void Zone::SetDate(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute) { if (worldserver.Connected()) { - ServerPacket* pack = new ServerPacket(ServerOP_SetWorldTime, sizeof(eqTimeOfDay)); + auto pack = new ServerPacket(ServerOP_SetWorldTime, sizeof(eqTimeOfDay)); eqTimeOfDay* eqtod = (eqTimeOfDay*)pack->pBuffer; eqtod->start_eqtime.minute=minute; eqtod->start_eqtime.hour=hour; @@ -1510,17 +1526,42 @@ void Zone::SetDate(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute } } -void Zone::SetTime(uint8 hour, uint8 minute) +void Zone::SetTime(uint8 hour, uint8 minute, bool update_world /*= true*/) { if (worldserver.Connected()) { - ServerPacket* pack = new ServerPacket(ServerOP_SetWorldTime, sizeof(eqTimeOfDay)); - eqTimeOfDay* eqtod = (eqTimeOfDay*)pack->pBuffer; - zone_time.getEQTimeOfDay(time(0), &eqtod->start_eqtime); - eqtod->start_eqtime.minute=minute; - eqtod->start_eqtime.hour=hour; - eqtod->start_realtime=time(0); - printf("Setting master time on world server to: %d:%d (%d)\n", hour, minute, (int)eqtod->start_realtime); - worldserver.SendPacket(pack); + auto pack = new ServerPacket(ServerOP_SetWorldTime, sizeof(eqTimeOfDay)); + eqTimeOfDay* eq_time_of_day = (eqTimeOfDay*)pack->pBuffer; + + zone_time.GetCurrentEQTimeOfDay(time(0), &eq_time_of_day->start_eqtime); + + eq_time_of_day->start_eqtime.minute = minute; + eq_time_of_day->start_eqtime.hour = hour; + eq_time_of_day->start_realtime = time(0); + + /* By Default we update worlds time, but we can optionally no update world which updates the rest of the zone servers */ + if (update_world){ + Log.Out(Logs::General, Logs::Zone_Server, "Setting master time on world server to: %d:%d (%d)\n", hour, minute, (int)eq_time_of_day->start_realtime); + worldserver.SendPacket(pack); + + /* Set Time Localization Flag */ + zone->is_zone_time_localized = false; + } + /* When we don't update world, we are localizing ourselves, we become disjointed from normal syncs and set time locally */ + else{ + + Log.Out(Logs::General, Logs::Zone_Server, "Setting zone localized time..."); + + zone->zone_time.SetCurrentEQTimeOfDay(eq_time_of_day->start_eqtime, eq_time_of_day->start_realtime); + auto outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); + TimeOfDay_Struct* time_of_day = (TimeOfDay_Struct*)outapp->pBuffer; + zone->zone_time.GetCurrentEQTimeOfDay(time(0), time_of_day); + entity_list.QueueClients(0, outapp, false); + safe_delete(outapp); + + /* Set Time Localization Flag */ + zone->is_zone_time_localized = true; + } + safe_delete(pack); } } @@ -1534,7 +1575,7 @@ ZonePoint* Zone::GetClosestZonePoint(const glm::vec3& location, uint32 to, Clien while(iterator.MoreElements()) { ZonePoint* zp = iterator.GetData(); - uint32 mask_test = client->GetClientVersionBit(); + uint32 mask_test = client->ClientVersionBit(); if(!(zp->client_version_mask & mask_test)) { iterator.Advance(); @@ -1556,7 +1597,9 @@ ZonePoint* Zone::GetClosestZonePoint(const glm::vec3& location, uint32 to, Clien iterator.Advance(); } - if(closest_dist > 400.0f && closest_dist < max_distance2) + // if we have a water map and it says we're in a zoneline, lets assume it's just a really big zone line + // this shouldn't open up any exploits since those situations are detected later on + if ((zone->HasWaterMap() && !zone->watermap->InZoneLine(glm::vec3(client->GetPosition()))) || (!zone->HasWaterMap() && closest_dist > 400.0f && closest_dist < max_distance2)) { if(client) client->CheatDetected(MQZoneUnknownDest, location.x, location.y, location.z); // Someone is trying to use /zone @@ -1588,7 +1631,7 @@ ZonePoint* Zone::GetClosestZonePointWithoutZone(float x, float y, float z, Clien while(iterator.MoreElements()) { ZonePoint* zp = iterator.GetData(); - uint32 mask_test = client->GetClientVersionBit(); + uint32 mask_test = client->ClientVersionBit(); if(!(zp->client_version_mask & mask_test)) { @@ -1619,39 +1662,39 @@ ZonePoint* Zone::GetClosestZonePointWithoutZone(float x, float y, float z, Clien bool ZoneDatabase::LoadStaticZonePoints(LinkedList* zone_point_list, const char* zonename, uint32 version) { - zone_point_list->Clear(); zone->numzonepoints = 0; std::string query = StringFormat("SELECT x, y, z, target_x, target_y, " - "target_z, target_zone_id, heading, target_heading, " - "number, target_instance, client_version_mask " - "FROM zone_points WHERE zone='%s' AND (version=%i OR version=-1) " - "ORDER BY number", zonename, version); + "target_z, target_zone_id, heading, target_heading, " + "number, target_instance, client_version_mask " + "FROM zone_points WHERE zone='%s' AND (version=%i OR version=-1) " + "ORDER BY number", + zonename, version); auto results = QueryDatabase(query); if (!results.Success()) { return false; } - for (auto row = results.begin(); row != results.end(); ++row) { - ZonePoint* zp = new ZonePoint; + for (auto row = results.begin(); row != results.end(); ++row) { + auto zp = new ZonePoint; - zp->x = atof(row[0]); - zp->y = atof(row[1]); - zp->z = atof(row[2]); - zp->target_x = atof(row[3]); - zp->target_y = atof(row[4]); - zp->target_z = atof(row[5]); - zp->target_zone_id = atoi(row[6]); - zp->heading = atof(row[7]); - zp->target_heading = atof(row[8]); - zp->number = atoi(row[9]); - zp->target_zone_instance = atoi(row[10]); - zp->client_version_mask = (uint32)strtoul(row[11], nullptr, 0); + zp->x = atof(row[0]); + zp->y = atof(row[1]); + zp->z = atof(row[2]); + zp->target_x = atof(row[3]); + zp->target_y = atof(row[4]); + zp->target_z = atof(row[5]); + zp->target_zone_id = atoi(row[6]); + zp->heading = atof(row[7]); + zp->target_heading = atof(row[8]); + zp->number = atoi(row[9]); + zp->target_zone_instance = atoi(row[10]); + zp->client_version_mask = (uint32)strtoul(row[11], nullptr, 0); - zone_point_list->Insert(zp); + zone_point_list->Insert(zp); - zone->numzonepoints++; - } + zone->numzonepoints++; + } return true; } @@ -1805,7 +1848,7 @@ bool ZoneDatabase::GetDecayTimes(npcDecayTimes_Struct* npcCorpseDecayTimes) { void Zone::weatherSend() { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weather, 8); + auto outapp = new EQApplicationPacket(OP_Weather, 8); if(zone_weather>0) outapp->pBuffer[0] = zone_weather-1; if(zone_weather>0) @@ -1902,7 +1945,7 @@ bool Zone::IsSpellBlocked(uint32 spell_id, const glm::vec3& location) } case 2: { - if (!IsWithinAxisAlignedBox(location, blocked_spells[x].m_Location - blocked_spells[x].m_Difference, blocked_spells[x].m_Location + blocked_spells[x].m_Difference)) + if (IsWithinAxisAlignedBox(location, blocked_spells[x].m_Location - blocked_spells[x].m_Difference, blocked_spells[x].m_Location + blocked_spells[x].m_Difference)) return true; break; } @@ -1936,7 +1979,7 @@ const char* Zone::GetSpellBlockedMessage(uint32 spell_id, const glm::vec3& locat } case 2: { - if(!IsWithinAxisAlignedBox(location, blocked_spells[x].m_Location - blocked_spells[x].m_Difference, blocked_spells[x].m_Location + blocked_spells[x].m_Difference)) + if(IsWithinAxisAlignedBox(location, blocked_spells[x].m_Location - blocked_spells[x].m_Difference, blocked_spells[x].m_Location + blocked_spells[x].m_Difference)) return blocked_spells[x].message; break; } @@ -1968,13 +2011,13 @@ void Zone::LoadLDoNTraps() } for (auto row = results.begin();row != results.end(); ++row) { - LDoNTrapTemplate *lt = new LDoNTrapTemplate; - lt->id = atoi(row[0]); - lt->type = (LDoNChestTypes)atoi(row[1]); - lt->spell_id = atoi(row[2]); - lt->skill = atoi(row[3]); - lt->locked = atoi(row[4]); - ldon_trap_list[lt->id] = lt; + auto lt = new LDoNTrapTemplate; + lt->id = atoi(row[0]); + lt->type = (LDoNChestTypes)atoi(row[1]); + lt->spell_id = atoi(row[2]); + lt->skill = atoi(row[3]); + lt->locked = atoi(row[4]); + ldon_trap_list[lt->id] = lt; } } @@ -2133,7 +2176,7 @@ void Zone::DoAdventureCountIncrease() if(sr->count < sr->total) { sr->count++; - ServerPacket *pack = new ServerPacket(ServerOP_AdventureCountUpdate, sizeof(uint16)); + auto pack = new ServerPacket(ServerOP_AdventureCountUpdate, sizeof(uint16)); *((uint16*)pack->pBuffer) = instanceid; worldserver.SendPacket(pack); delete pack; @@ -2146,7 +2189,7 @@ void Zone::DoAdventureAssassinationCountIncrease() if(sr->assa_count < RuleI(Adventure, NumberKillsForBossSpawn)) { sr->assa_count++; - ServerPacket *pack = new ServerPacket(ServerOP_AdventureAssaCountUpdate, sizeof(uint16)); + auto pack = new ServerPacket(ServerOP_AdventureAssaCountUpdate, sizeof(uint16)); *((uint16*)pack->pBuffer) = instanceid; worldserver.SendPacket(pack); delete pack; @@ -2196,12 +2239,12 @@ void Zone::LoadNPCEmotes(LinkedList* NPCEmoteList) for (auto row = results.begin(); row != results.end(); ++row) { - NPC_Emote_Struct* nes = new NPC_Emote_Struct; - nes->emoteid = atoi(row[0]); - nes->event_ = atoi(row[1]); - nes->type = atoi(row[2]); - strn0cpy(nes->text, row[3], sizeof(nes->text)); - NPCEmoteList->Insert(nes); + auto nes = new NPC_Emote_Struct; + nes->emoteid = atoi(row[0]); + nes->event_ = atoi(row[1]); + nes->type = atoi(row[2]); + strn0cpy(nes->text, row[3], sizeof(nes->text)); + NPCEmoteList->Insert(nes); } } @@ -2211,9 +2254,9 @@ void Zone::ReloadWorld(uint32 Option){ entity_list.ClearAreas(); parse->ReloadQuests(); } else if(Option == 1) { - zone->Repop(0); entity_list.ClearAreas(); parse->ReloadQuests(); + zone->Repop(0); } } diff --git a/zone/zone.h b/zone/zone.h index 80e0473f2..d7ecc6237 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -27,6 +27,7 @@ #include "qglobals.h" #include "spawn2.h" #include "spawngroup.h" +#include "aa_ability.h" struct ZonePoint { @@ -43,6 +44,7 @@ struct ZonePoint int32 target_zone_instance; uint32 client_version_mask; }; + struct ZoneClientAuth_Struct { uint32 ip; // client's IP address uint32 wid; // client's WorldID# @@ -85,6 +87,10 @@ public: Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name); ~Zone(); + + /* When zone has its own version of time */ + bool is_zone_time_localized; + bool Init(bool iStaticZone); bool LoadZoneCFG(const char* filename, uint16 instance_id, bool DontLoadDefault = false); bool SaveZoneCFG(); @@ -108,11 +114,13 @@ public: inline const uint32& GetMaxClients() { return pMaxClients; } - void LoadAAs(); - int GetTotalAAs() { return totalAAs; } - SendAA_Struct* GetAABySequence(uint32 seq) { return aas[seq]; } - SendAA_Struct* FindAA(uint32 id); - uint8 GetTotalAALevels(uint32 skill_id); + //new AA + void LoadAlternateAdvancement(); + AA::Ability *GetAlternateAdvancementAbility(int id); + AA::Ability *GetAlternateAdvancementAbilityByRank(int rank_id); + AA::Rank *GetAlternateAdvancementRank(int rank_id); + std::pair GetAlternateAdvancementAbilityAndRank(int id, int points_spent); + void LoadZoneDoors(const char* zone, int16 version); bool LoadZoneObjects(); bool LoadGroundSpawns(); @@ -132,6 +140,7 @@ public: bool Depop(bool StartSpawnTimer = false); void Repop(uint32 delay = 0); + void RepopClose(const glm::vec4& client_position, uint32 repop_distance); void ClearNPCTypeCache(int id); void SpawnStatus(Mob* client); void ShowEnabledSpawnStatus(Mob* client); @@ -153,7 +162,7 @@ public: inline bool InstantGrids() { return(!initgrids_timer.Enabled()); } void SetStaticZone(bool sz) { staticzone = sz; } inline bool IsStaticZone() { return staticzone; } - inline void GotCurTime(bool time) { gottime = time; } + inline void SetZoneHasCurrentTime(bool time) { zone_has_current_time = time; } void SpawnConditionChanged(const SpawnCondition &c, int16 old_value); @@ -188,6 +197,10 @@ public: char *adv_data; bool did_adventure_actions; + //new AA + std::unordered_map> aa_abilities; + std::unordered_map> aa_ranks; + void DoAdventureCountIncrease(); void DoAdventureAssassinationCountIncrease(); void DoAdventureActions(); @@ -206,7 +219,7 @@ public: EQTime zone_time; void GetTimeSync(); void SetDate(uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute); - void SetTime(uint8 hour, uint8 minute); + void SetTime(uint8 hour, uint8 minute, bool update_world = true); void weatherSend(); bool CanBind() const { return(can_bind); } @@ -308,9 +321,6 @@ private: int totalBS; ZoneSpellsBlocked *blocked_spells; - int totalAAs; - SendAA_Struct **aas; //array of AA structs - /* Spawn related things */ @@ -319,7 +329,7 @@ private: bool staticzone; - bool gottime; + bool zone_has_current_time; uint32 pQueuedMerchantsWorkID; uint32 pQueuedTempMerchantsWorkID; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 685fbd3ca..7f86f5110 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -46,7 +46,7 @@ void ZoneDatabase::ZDBInitVars() { ZoneDatabase::~ZoneDatabase() { unsigned int x; if (npc_spells_cache) { - for (x=0; x<=npc_spells_maxid; x++) { + for (x = 0; x <= npc_spells_maxid; x++) { safe_delete_array(npc_spells_cache[x]); } safe_delete_array(npc_spells_cache); @@ -54,7 +54,7 @@ ZoneDatabase::~ZoneDatabase() { safe_delete_array(npc_spells_loadtried); if (npc_spellseffects_cache) { - for (x=0; x<=npc_spellseffects_maxid; x++) { + for (x = 0; x <= npc_spellseffects_maxid; x++) { safe_delete_array(npc_spellseffects_cache[x]); } safe_delete_array(npc_spellseffects_cache); @@ -62,7 +62,7 @@ ZoneDatabase::~ZoneDatabase() { safe_delete_array(npc_spellseffects_loadtried); if (faction_array != nullptr) { - for (x=0; x <= max_faction; x++) { + for (x = 0; x <= max_faction; x++) { if (faction_array[x] != 0) safe_delete(faction_array[x]); } @@ -196,7 +196,7 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct zone_data->time_type = atoi(row[30]); //not in the DB yet: - zone_data->gravity = atof(row[56]); + zone_data->gravity = atof(row[56]); Log.Out(Logs::General, Logs::Debug, "Zone Gravity is %f", zone_data->gravity); allow_mercs = true; @@ -248,7 +248,7 @@ void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint3 if(time_left == 0) { std::string query = StringFormat("DELETE FROM `respawn_times` WHERE `id` = %u AND `instance_id` = %u", spawn2_id, instance_id); - QueryDatabase(query); + QueryDatabase(query); return; } @@ -258,14 +258,14 @@ void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint3 "start, " "duration, " "instance_id) " - "VALUES " + "VALUES " "(%u, " "%u, " "%u, " "%u)", - spawn2_id, + spawn2_id, current_time, - time_left, + time_left, instance_id ); QueryDatabase(query); @@ -315,8 +315,8 @@ bool ZoneDatabase::logevents(const char* accountname,uint32 accountid,uint8 stat uint32 len = strlen(description); uint32 len2 = strlen(target); - char* descriptiontext = new char[2*len+1]; - char* targetarr = new char[2*len2+1]; + auto descriptiontext = new char[2 * len + 1]; + auto targetarr = new char[2 * len2 + 1]; memset(descriptiontext, 0, 2*len+1); memset(targetarr, 0, 2*len2+1); DoEscapeString(descriptiontext, description, len); @@ -382,7 +382,7 @@ void ZoneDatabase::UpdateBug(BugStruct* bug) { void ZoneDatabase::UpdateBug(PetitionBug_Struct* bug){ uint32 len = strlen(bug->text); - char* bugtext = new char[2*len+1]; + auto bugtext = new char[2 * len + 1]; memset(bugtext, 0, 2*len+1); DoEscapeString(bugtext, bug->text, len); @@ -487,7 +487,7 @@ void ZoneDatabase::LoadWorldContainer(uint32 parentid, ItemInst* container) uint8 index = (uint8)atoi(row[0]); uint32 item_id = (uint32)atoi(row[1]); int8 charges = (int8)atoi(row[2]); - uint32 aug[EmuConstants::ITEM_COMMON_SIZE]; + uint32 aug[EQEmu::legacy::ITEM_COMMON_SIZE]; aug[0] = (uint32)atoi(row[3]); aug[1] = (uint32)atoi(row[4]); aug[2] = (uint32)atoi(row[5]); @@ -496,8 +496,8 @@ void ZoneDatabase::LoadWorldContainer(uint32 parentid, ItemInst* container) aug[5] = (uint32)atoi(row[8]); ItemInst* inst = database.CreateItem(item_id, charges); - if (inst && inst->GetItem()->ItemClass == ItemClassCommon) { - for(int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) + if (inst && inst->GetItem()->IsClassCommon()) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) if (aug[i]) inst->PutAugment(&database, i, aug[i]); // Put item inside world container @@ -520,17 +520,17 @@ void ZoneDatabase::SaveWorldContainer(uint32 zone_id, uint32 parent_id, const It DeleteWorldContainer(parent_id,zone_id); // Save all 10 items, if they exist - for (uint8 index = SUB_BEGIN; index < EmuConstants::ITEM_CONTAINER_SIZE; index++) { + for (uint8 index = SUB_INDEX_BEGIN; index < EQEmu::legacy::ITEM_CONTAINER_SIZE; index++) { ItemInst* inst = container->GetItem(index); if (!inst) continue; uint32 item_id = inst->GetItem()->ID; - uint32 augslot[EmuConstants::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM }; + uint32 augslot[EQEmu::legacy::ITEM_COMMON_SIZE] = { NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM, NO_ITEM }; - if (inst->IsType(ItemClassCommon)) { - for(int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + if (inst->IsType(EQEmu::item::ItemClassCommon)) { + for (int i = AUG_INDEX_BEGIN; i < EQEmu::legacy::ITEM_COMMON_SIZE; i++) { ItemInst *auginst=inst->GetAugment(i); augslot[i]=(auginst && auginst->GetItem()) ? auginst->GetItem()->ID : 0; } @@ -562,7 +562,7 @@ void ZoneDatabase::DeleteWorldContainer(uint32 parent_id, uint32 zone_id) Trader_Struct* ZoneDatabase::LoadTraderItem(uint32 char_id) { - Trader_Struct* loadti = new Trader_Struct; + auto loadti = new Trader_Struct; memset(loadti,0,sizeof(Trader_Struct)); std::string query = StringFormat("SELECT * FROM trader WHERE char_id = %i ORDER BY slot_id LIMIT 80", char_id); @@ -587,7 +587,7 @@ Trader_Struct* ZoneDatabase::LoadTraderItem(uint32 char_id) TraderCharges_Struct* ZoneDatabase::LoadTraderItemWithCharges(uint32 char_id) { - TraderCharges_Struct* loadti = new TraderCharges_Struct; + auto loadti = new TraderCharges_Struct; memset(loadti,0,sizeof(TraderCharges_Struct)); std::string query = StringFormat("SELECT * FROM trader WHERE char_id=%i ORDER BY slot_id LIMIT 80", char_id); @@ -629,7 +629,7 @@ ItemInst* ZoneDatabase::LoadSingleTraderItem(uint32 CharID, int SerialNumber) { int Charges = atoi(row[3]); int Cost = atoi(row[4]); - const Item_Struct *item = database.GetItem(ItemID); + const EQEmu::ItemBase *item = database.GetItem(ItemID); if(!item) { Log.Out(Logs::Detail, Logs::Trading, "Unable to create item\n"); @@ -684,7 +684,7 @@ void ZoneDatabase::UpdateTraderItemPrice(int CharID, uint32 ItemID, uint32 Charg Log.Out(Logs::Detail, Logs::Trading, "ZoneDatabase::UpdateTraderPrice(%i, %i, %i, %i)", CharID, ItemID, Charges, NewPrice); - const Item_Struct *item = database.GetItem(ItemID); + const EQEmu::ItemBase *item = database.GetItem(ItemID); if(!item) return; @@ -887,7 +887,8 @@ bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct* "RestTimer, " "`e_aa_effects`, " "`e_percent_to_aa`, " - "`e_expended_aa_spent` " + "`e_expended_aa_spent`, " + "`e_last_invsnapshot` " "FROM " "character_data " "WHERE `id` = %i ", character_id); @@ -983,7 +984,9 @@ bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp->RestTimer = atoi(row[r]); r++; // "RestTimer, " m_epp->aa_effects = atoi(row[r]); r++; // "`e_aa_effects`, " m_epp->perAA = atoi(row[r]); r++; // "`e_percent_to_aa`, " - m_epp->expended_aa = atoi(row[r]); r++; // "`e_expended_aa_spent` " + m_epp->expended_aa = atoi(row[r]); r++; // "`e_expended_aa_spent`, " + m_epp->last_invsnapshot_time = atoi(row[r]); r++; // "`e_last_invsnapshot` " + m_epp->next_invsnapshot_time = m_epp->last_invsnapshot_time + (RuleI(Character, InvSnapshotMinIntervalM) * 60); } return true; } @@ -1054,8 +1057,8 @@ bool ZoneDatabase::LoadCharacterLanguages(uint32 character_id, PlayerProfile_Str for (i = 0; i < MAX_PP_LANGUAGE; ++i) pp->languages[i] = 0; - for (auto row = results.begin(); row != results.end(); ++row) { - i = atoi(row[0]); + for (auto row = results.begin(); row != results.end(); ++row) { + i = atoi(row[0]); if (i < MAX_PP_LANGUAGE){ pp->languages[i] = atoi(row[1]); } @@ -1102,14 +1105,14 @@ bool ZoneDatabase::LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct "FROM " "`character_skills` " "WHERE `id` = %u ORDER BY `skill_id`", character_id); - auto results = database.QueryDatabase(query); + auto results = database.QueryDatabase(query); int i = 0; /* Initialize Skill */ for (i = 0; i < MAX_PP_SKILL; ++i) pp->skills[i] = 0; - for (auto row = results.begin(); row != results.end(); ++row) { - i = atoi(row[0]); + for (auto row = results.begin(); row != results.end(); ++row) { + i = atoi(row[0]); if (i < MAX_PP_SKILL) pp->skills[i] = atoi(row[1]); } @@ -1167,10 +1170,10 @@ bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile for (auto row = results.begin(); row != results.end(); ++row) { r = 0; i = atoi(row[r]); /* Slot */ r++; - pp->item_tint[i].RGB.Blue = atoi(row[r]); r++; - pp->item_tint[i].RGB.Green = atoi(row[r]); r++; - pp->item_tint[i].RGB.Red = atoi(row[r]); r++; - pp->item_tint[i].RGB.UseTint = atoi(row[r]); + pp->item_tint.Slot[i].Blue = atoi(row[r]); r++; + pp->item_tint.Slot[i].Green = atoi(row[r]); r++; + pp->item_tint.Slot[i].Red = atoi(row[r]); r++; + pp->item_tint.Slot[i].UseTint = atoi(row[r]); } return true; } @@ -1178,11 +1181,11 @@ bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp) { std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT %u", - character_id, EmuConstants::BANDOLIERS_SIZE); + character_id, EQEmu::legacy::BANDOLIERS_SIZE); auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0; - for (i = 0; i < EmuConstants::BANDOLIERS_SIZE; i++) { + for (i = 0; i < EQEmu::legacy::BANDOLIERS_SIZE; i++) { pp->bandoliers[i].Name[0] = '\0'; - for (int si = 0; si < EmuConstants::BANDOLIER_ITEM_COUNT; si++) { + for (int si = 0; si < EQEmu::legacy::BANDOLIER_ITEM_COUNT; si++) { pp->bandoliers[i].Items[si].ID = 0; pp->bandoliers[i].Items[si].Icon = 0; pp->bandoliers[i].Items[si].Name[0] = '\0'; @@ -1194,7 +1197,7 @@ bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Str i = atoi(row[r]); /* Bandolier ID */ r++; si = atoi(row[r]); /* Bandolier Slot */ r++; - const Item_Struct* item_data = database.GetItem(atoi(row[r])); + const EQEmu::ItemBase* item_data = database.GetItem(atoi(row[r])); if (item_data) { pp->bandoliers[i].Items[si].ID = item_data->ID; r++; pp->bandoliers[i].Items[si].Icon = atoi(row[r]); r++; // Must use db value in case an Ornamentation is assigned @@ -1216,7 +1219,7 @@ bool ZoneDatabase::LoadCharacterTribute(uint32 character_id, PlayerProfile_Struc std::string query = StringFormat("SELECT `tier`, `tribute` FROM `character_tribute` WHERE `id` = %u", character_id); auto results = database.QueryDatabase(query); int i = 0; - for (i = 0; i < EmuConstants::TRIBUTE_SIZE; i++){ + for (i = 0; i < EQEmu::legacy::TRIBUTE_SIZE; i++){ pp->tributes[i].tribute = 0xFFFFFFFF; pp->tributes[i].tier = 0; } @@ -1235,10 +1238,10 @@ bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struc { std::string query = StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT %u", - character_id, EmuConstants::POTION_BELT_ITEM_COUNT); + character_id, EQEmu::legacy::POTION_BELT_ITEM_COUNT); auto results = database.QueryDatabase(query); int i = 0; - for (i = 0; i < EmuConstants::POTION_BELT_ITEM_COUNT; i++) { + for (i = 0; i < EQEmu::legacy::POTION_BELT_ITEM_COUNT; i++) { pp->potionbelt.Items[i].Icon = 0; pp->potionbelt.Items[i].ID = 0; pp->potionbelt.Items[i].Name[0] = '\0'; @@ -1246,7 +1249,7 @@ bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struc for (auto row = results.begin(); row != results.end(); ++row) { i = atoi(row[0]); - const Item_Struct *item_data = database.GetItem(atoi(row[1])); + const EQEmu::ItemBase *item_data = database.GetItem(atoi(row[1])); if (!item_data) continue; pp->potionbelt.Items[i].ID = item_data->ID; @@ -1257,30 +1260,27 @@ bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struc return true; } -bool ZoneDatabase::LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp){ - std::string query = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `is_home` FROM `character_bind` WHERE `id` = %u LIMIT 2", character_id); - auto results = database.QueryDatabase(query); +bool ZoneDatabase::LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct *pp) +{ + std::string query = StringFormat("SELECT `slot`, `zone_id`, `instance_id`, `x`, `y`, `z`, `heading` FROM " + "`character_bind` WHERE `id` = %u LIMIT 5", + character_id); + auto results = database.QueryDatabase(query); + + if (!results.RowCount()) // SHIT -- this actually isn't good + return true; for (auto row = results.begin(); row != results.end(); ++row) { - - /* Is home bind */ - if (atoi(row[6]) == 1){ - pp->binds[4].zoneId = atoi(row[0]); - pp->binds[4].instance_id = atoi(row[1]); - pp->binds[4].x = atoi(row[2]); - pp->binds[4].y = atoi(row[3]); - pp->binds[4].z = atoi(row[4]); - pp->binds[4].heading = atoi(row[5]); + int index = atoi(row[0]); + if (index < 0 || index > 4) continue; - } - /* Is regular bind point */ - pp->binds[0].zoneId = atoi(row[0]); - pp->binds[0].instance_id = atoi(row[1]); - pp->binds[0].x = atoi(row[2]); - pp->binds[0].y = atoi(row[3]); - pp->binds[0].z = atoi(row[4]); - pp->binds[0].heading = atoi(row[5]); + pp->binds[index].zoneId = atoi(row[1]); + pp->binds[index].instance_id = atoi(row[2]); + pp->binds[index].x = atoi(row[3]); + pp->binds[index].y = atoi(row[4]); + pp->binds[index].z = atoi(row[5]); + pp->binds[index].heading = atoi(row[6]); } return true; @@ -1292,19 +1292,23 @@ bool ZoneDatabase::SaveCharacterLanguage(uint32 character_id, uint32 lang_id, ui return true; } -bool ZoneDatabase::SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, const glm::vec4& position, uint8 is_home){ - if (zone_id <= 0) { - return false; - } - +bool ZoneDatabase::SaveCharacterBindPoint(uint32 character_id, const BindStruct &bind, uint32 bind_num) +{ /* Save Home Bind Point */ - std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" - " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", character_id, zone_id, instance_id, position.x, position.y, position.z, position.w, is_home); - Log.Out(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterBindPoint for character ID: %i zone_id: %u instance_id: %u position: %s ishome: %u", character_id, zone_id, instance_id, to_string(position).c_str(), is_home); + std::string query = + StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot) VALUES (%u, " + "%u, %u, %f, %f, %f, %f, %i)", + character_id, bind.zoneId, bind.instance_id, bind.x, bind.y, bind.z, bind.heading, bind_num); + + Log.Out(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterBindPoint for character ID: %i zone_id: %u " + "instance_id: %u position: %f %f %f %f bind_num: %u", + character_id, bind.zoneId, bind.instance_id, bind.x, bind.y, bind.z, bind.heading, bind_num); + auto results = QueryDatabase(query); - if (!results.RowsAffected()) { - Log.Out(Logs::General, Logs::None, "ERROR Bind Home Save: %s. %s", results.ErrorMessage().c_str(), query.c_str()); - } + if (!results.RowsAffected()) + Log.Out(Logs::General, Logs::None, "ERROR Bind Home Save: %s. %s", results.ErrorMessage().c_str(), + query.c_str()); + return true; } @@ -1335,7 +1339,7 @@ bool ZoneDatabase::SaveCharacterTribute(uint32 character_id, PlayerProfile_Struc std::string query = StringFormat("DELETE FROM `character_tribute` WHERE `id` = %u", character_id); QueryDatabase(query); /* Save Tributes only if we have values... */ - for (int i = 0; i < EmuConstants::TRIBUTE_SIZE; i++){ + for (int i = 0; i < EQEmu::legacy::TRIBUTE_SIZE; i++){ if (pp->tributes[i].tribute > 0 && pp->tributes[i].tribute != TRIBUTE_NONE){ std::string query = StringFormat("REPLACE INTO `character_tribute` (id, tier, tribute) VALUES (%u, %u, %u)", character_id, pp->tributes[i].tier, pp->tributes[i].tribute); QueryDatabase(query); @@ -1377,6 +1381,56 @@ bool ZoneDatabase::SaveCharacterLeadershipAA(uint32 character_id, PlayerProfile_ return true; } +bool ZoneDatabase::SaveCharacterInventorySnapshot(uint32 character_id){ + uint32 time_index = time(nullptr); + std::string query = StringFormat( + "INSERT INTO inventory_snapshots (" + " time_index," + " charid," + " slotid," + " itemid," + " charges," + " color," + " augslot1," + " augslot2," + " augslot3," + " augslot4," + " augslot5," + " augslot6," + " instnodrop," + " custom_data," + " ornamenticon," + " ornamentidfile," + " ornament_hero_model" + ")" + " SELECT" + " %u," + " charid," + " slotid," + " itemid," + " charges," + " color," + " augslot1," + " augslot2," + " augslot3," + " augslot4," + " augslot5," + " augslot6," + " instnodrop," + " custom_data," + " ornamenticon," + " ornamentidfile," + " ornament_hero_model" + " FROM inventory" + " WHERE charid = %u", + time_index, + character_id + ); + auto results = database.QueryDatabase(query); + Log.Out(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterInventorySnapshot %i (%s)", character_id, (results.Success() ? "pass" : "fail")); + return results.Success(); +} + bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp){ clock_t t = std::clock(); /* Function timer start */ std::string query = StringFormat( @@ -1473,7 +1527,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla " RestTimer, " " e_aa_effects, " " e_percent_to_aa, " - " e_expended_aa_spent " + " e_expended_aa_spent, " + " e_last_invsnapshot " ") " "VALUES (" "%u," // id " id, " @@ -1568,7 +1623,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla "%u," // RestTimer pp->RestTimer, " RestTimer) " "%u," // e_aa_effects "%u," // e_percent_to_aa - "%u" // e_expended_aa_spent + "%u," // e_expended_aa_spent + "%u" // e_last_invsnapshot ")", character_id, // " id, " account_id, // " account_id, " @@ -1662,7 +1718,8 @@ bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, Pla pp->RestTimer, // " RestTimer) " m_epp->aa_effects, m_epp->perAA, - m_epp->expended_aa + m_epp->expended_aa, + m_epp->last_invsnapshot_time ); auto results = database.QueryDatabase(query); Log.Out(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterData %i, done... Took %f seconds", character_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); @@ -1705,15 +1762,15 @@ bool ZoneDatabase::SaveCharacterCurrency(uint32 character_id, PlayerProfile_Stru pp->careerRadCrystals, pp->currentEbonCrystals, pp->careerEbonCrystals); - auto results = database.QueryDatabase(query); - Log.Out(Logs::General, Logs::None, "Saving Currency for character ID: %i, done", character_id); + auto results = database.QueryDatabase(query); + Log.Out(Logs::General, Logs::None, "Saving Currency for character ID: %i, done", character_id); return true; } -bool ZoneDatabase::SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level){ - std::string rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value)" - " VALUES (%u, %u, %u)", - character_id, aa_id, current_level); +bool ZoneDatabase::SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level, uint32 charges){ + std::string rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value, charges)" + " VALUES (%u, %u, %u, %u)", + character_id, aa_id, current_level, charges); auto results = QueryDatabase(rquery); Log.Out(Logs::General, Logs::None, "Saving AA for character ID: %u, aa_id: %u current_level: %u", character_id, aa_id, current_level); return true; @@ -1802,7 +1859,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load std::string where_condition = ""; if (bulk_load){ - Log.Out(Logs::General, Logs::Debug, "Performing bulk NPC Types load"); + Log.Out(Logs::General, Logs::Debug, "Performing bulk NPC Types load"); where_condition = StringFormat( "INNER JOIN spawnentry ON npc_types.id = spawnentry.npcID " "INNER JOIN spawn2 ON spawnentry.spawngroupID = spawn2.spawngroupID " @@ -1904,8 +1961,13 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load "npc_types.no_target_hotkey, " "npc_types.raid_target, " "npc_types.attack_delay, " - "npc_types.light " - "FROM npc_types %s", + "npc_types.light, " + "npc_types.armtexture, " + "npc_types.bracertexture, " + "npc_types.handtexture, " + "npc_types.legtexture, " + "npc_types.feettexture " + "FROM npc_types %s", where_condition.c_str() ); @@ -2006,10 +2068,10 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load uint32 armor_tint_id = atoi(row[63]); - temp_npctype_data->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16; - temp_npctype_data->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8; - temp_npctype_data->armor_tint[0] |= (atoi(row[66]) & 0xFF); - temp_npctype_data->armor_tint[0] |= (temp_npctype_data->armor_tint[0]) ? (0xFF << 24) : 0; + temp_npctype_data->armor_tint.Head.Color = (atoi(row[64]) & 0xFF) << 16; + temp_npctype_data->armor_tint.Head.Color |= (atoi(row[65]) & 0xFF) << 8; + temp_npctype_data->armor_tint.Head.Color |= (atoi(row[66]) & 0xFF); + temp_npctype_data->armor_tint.Head.Color |= (temp_npctype_data->armor_tint.Head.Color) ? (0xFF << 24) : 0; if (armor_tint_id != 0) { std::string armortint_query = StringFormat( @@ -2030,18 +2092,18 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load else { auto armorTint_row = armortint_results.begin(); - for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) { - temp_npctype_data->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16; - temp_npctype_data->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8; - temp_npctype_data->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]); - temp_npctype_data->armor_tint[index] |= (temp_npctype_data->armor_tint[index]) ? (0xFF << 24) : 0; + for (int index = EQEmu::textures::TextureBegin; index <= EQEmu::textures::LastTexture; index++) { + temp_npctype_data->armor_tint.Slot[index].Color = atoi(armorTint_row[index * 3]) << 16; + temp_npctype_data->armor_tint.Slot[index].Color |= atoi(armorTint_row[index * 3 + 1]) << 8; + temp_npctype_data->armor_tint.Slot[index].Color |= atoi(armorTint_row[index * 3 + 2]); + temp_npctype_data->armor_tint.Slot[index].Color |= (temp_npctype_data->armor_tint.Slot[index].Color) ? (0xFF << 24) : 0; } } } // Try loading npc_types tint fields if armor tint is 0 or query failed to get results if (armor_tint_id == 0) { - for (int index = MaterialChest; index < _MaterialCount; index++) { - temp_npctype_data->armor_tint[index] = temp_npctype_data->armor_tint[0]; + for (int index = EQEmu::textures::TextureChest; index < EQEmu::textures::TextureCount; index++) { + temp_npctype_data->armor_tint.Slot[index].Color = temp_npctype_data->armor_tint.Slot[0].Color; // odd way to 'zero-out' the array... } } @@ -2074,6 +2136,12 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load temp_npctype_data->attack_delay = atoi(row[90]); temp_npctype_data->light = (atoi(row[91]) & 0x0F); + temp_npctype_data->armtexture = atoi(row[92]); + temp_npctype_data->bracertexture = atoi(row[93]); + temp_npctype_data->handtexture = atoi(row[94]); + temp_npctype_data->legtexture = atoi(row[95]); + temp_npctype_data->feettexture = atoi(row[96]); + // 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()) { @@ -2172,7 +2240,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client return nullptr; } - const NPCType *npc; + const NPCType *npc = nullptr; // Process each row returned. for (auto row = results.begin(); row != results.end(); ++row) { @@ -2233,15 +2301,15 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client tmpNPCType->bodytype = 1; uint32 armor_tint_id = atoi(row[36]); - tmpNPCType->armor_tint[0] = (atoi(row[37]) & 0xFF) << 16; - tmpNPCType->armor_tint[0] |= (atoi(row[38]) & 0xFF) << 8; - tmpNPCType->armor_tint[0] |= (atoi(row[39]) & 0xFF); - tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0; + tmpNPCType->armor_tint.Slot[0].Color = (atoi(row[37]) & 0xFF) << 16; + tmpNPCType->armor_tint.Slot[0].Color |= (atoi(row[38]) & 0xFF) << 8; + tmpNPCType->armor_tint.Slot[0].Color |= (atoi(row[39]) & 0xFF); + tmpNPCType->armor_tint.Slot[0].Color |= (tmpNPCType->armor_tint.Slot[0].Color) ? (0xFF << 24) : 0; if (armor_tint_id == 0) - for (int index = MaterialChest; index <= EmuConstants::MATERIAL_END; index++) - tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0]; - else if (tmpNPCType->armor_tint[0] == 0) { + for (int index = EQEmu::textures::TextureChest; index <= EQEmu::textures::LastTexture; index++) + tmpNPCType->armor_tint.Slot[index].Color = tmpNPCType->armor_tint.Slot[0].Color; + else if (tmpNPCType->armor_tint.Slot[0].Color == 0) { std::string armorTint_query = StringFormat("SELECT red1h, grn1h, blu1h, " "red2c, grn2c, blu2c, " "red3a, grn3a, blu3a, " @@ -2259,11 +2327,11 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client else { auto armorTint_row = results.begin(); - for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) { - tmpNPCType->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16; - tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8; - tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]); - tmpNPCType->armor_tint[index] |= (tmpNPCType->armor_tint[index]) ? (0xFF << 24) : 0; + for (int index = EQEmu::textures::TextureBegin; index <= EQEmu::textures::LastTexture; index++) { + tmpNPCType->armor_tint.Slot[index].Color = atoi(armorTint_row[index * 3]) << 16; + tmpNPCType->armor_tint.Slot[index].Color |= atoi(armorTint_row[index * 3 + 1]) << 8; + tmpNPCType->armor_tint.Slot[index].Color |= atoi(armorTint_row[index * 3 + 2]); + tmpNPCType->armor_tint.Slot[index].Color |= (tmpNPCType->armor_tint.Slot[index].Color) ? (0xFF << 24) : 0; } } } else @@ -2358,7 +2426,7 @@ bool ZoneDatabase::LoadCurrentMerc(Client *client) { if(!results.Success()) return false; - + if(results.RowCount() == 0) return false; @@ -2493,7 +2561,7 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) { "TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, " "CorruptionCounters, HitCount, MeleeRune, MagicRune, dot_rune, " "caston_x, Persistent, caston_y, caston_z, ExtraDIChance) " - "VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);", + "VALUES (%u, %u, %u, %u, %u, %d, %u, %u, %u, %u, %u, %u, %u, %i, %u, %i, %i, %i);", merc->GetMercID(), buffs[buffCount].spellid, buffs[buffCount].casterlevel, spells[buffs[buffCount].spellid].buffdurationformula, buffs[buffCount].ticsremaining, CalculatePoisonCounters(buffs[buffCount].spellid) > 0 ? buffs[buffCount].counters : 0, @@ -2616,7 +2684,7 @@ void ZoneDatabase::LoadMercEquipment(Merc *merc) { int itemCount = 0; for(auto row = results.begin(); row != results.end(); ++row) { - if (itemCount == EmuConstants::EQUIPMENT_SIZE) + if (itemCount == EQEmu::legacy::EQUIPMENT_SIZE) break; if(atoi(row[0]) == 0) @@ -2723,7 +2791,7 @@ void ZoneDatabase::RefreshGroupFromDB(Client *client){ if(!group) return; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_GroupUpdate,sizeof(GroupUpdate2_Struct)); + auto outapp = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupUpdate2_Struct)); GroupUpdate2_Struct* gu = (GroupUpdate2_Struct*)outapp->pBuffer; gu->action = groupActUpdate; @@ -2755,7 +2823,7 @@ void ZoneDatabase::RefreshGroupFromDB(Client *client){ client->QueuePacket(outapp); safe_delete(outapp); - if(client->GetClientVersion() >= ClientVersion::SoD) { + if (client->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) { group->NotifyMainTank(client, 1); group->NotifyPuller(client, 1); } @@ -2969,47 +3037,50 @@ void ZoneDatabase::SaveBuffs(Client *client) { query = StringFormat("INSERT INTO `character_buffs` (character_id, slot_id, spell_id, " "caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, " - "magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z, ExtraDIChance) " - "VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', " - "'%i', '%i', '%i', '%i')", client->CharacterID(), index, buffs[index].spellid, + "magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z, ExtraDIChance, " + "instrument_mod) " + "VALUES('%u', '%u', '%u', '%u', '%s', '%d', '%u', '%u', '%u', '%u', '%u', '%u', " + "'%i', '%i', '%i', '%i', '%i')", client->CharacterID(), index, buffs[index].spellid, buffs[index].casterlevel, buffs[index].caster_name, buffs[index].ticsremaining, buffs[index].counters, buffs[index].numhits, buffs[index].melee_rune, buffs[index].magic_rune, buffs[index].persistant_buff, buffs[index].dot_rune, buffs[index].caston_x, buffs[index].caston_y, buffs[index].caston_z, - buffs[index].ExtraDIChance); + buffs[index].ExtraDIChance, buffs[index].instrument_mod); QueryDatabase(query); } } -void ZoneDatabase::LoadBuffs(Client *client) { +void ZoneDatabase::LoadBuffs(Client *client) +{ Buffs_Struct *buffs = client->GetBuffs(); uint32 max_slots = client->GetMaxBuffSlots(); - for(int index = 0; index < max_slots; ++index) + for (int index = 0; index < max_slots; ++index) buffs[index].spellid = SPELL_UNKNOWN; std::string query = StringFormat("SELECT spell_id, slot_id, caster_level, caster_name, ticsremaining, " - "counters, numhits, melee_rune, magic_rune, persistent, dot_rune, " - "caston_x, caston_y, caston_z, ExtraDIChance " - "FROM `character_buffs` WHERE `character_id` = '%u'", client->CharacterID()); - auto results = QueryDatabase(query); - if (!results.Success()) { + "counters, numhits, melee_rune, magic_rune, persistent, dot_rune, " + "caston_x, caston_y, caston_z, ExtraDIChance, instrument_mod " + "FROM `character_buffs` WHERE `character_id` = '%u'", + client->CharacterID()); + auto results = QueryDatabase(query); + if (!results.Success()) { return; - } + } - for (auto row = results.begin(); row != results.end(); ++row) { - uint32 slot_id = atoul(row[1]); - if(slot_id >= client->GetMaxBuffSlots()) + for (auto row = results.begin(); row != results.end(); ++row) { + uint32 slot_id = atoul(row[1]); + if (slot_id >= client->GetMaxBuffSlots()) continue; - uint32 spell_id = atoul(row[0]); - if(!IsValidSpell(spell_id)) - continue; + uint32 spell_id = atoul(row[0]); + if (!IsValidSpell(spell_id)) + continue; - Client *caster = entity_list.GetClientByName(row[3]); + Client *caster = entity_list.GetClientByName(row[3]); uint32 caster_level = atoi(row[2]); - uint32 ticsremaining = atoul(row[4]); + int32 ticsremaining = atoi(row[4]); uint32 counters = atoul(row[5]); uint32 numhits = atoul(row[6]); uint32 melee_rune = atoul(row[7]); @@ -3020,53 +3091,54 @@ void ZoneDatabase::LoadBuffs(Client *client) { int32 caston_y = atoul(row[12]); int32 caston_z = atoul(row[13]); int32 ExtraDIChance = atoul(row[14]); + uint32 instrument_mod = atoul(row[15]); buffs[slot_id].spellid = spell_id; - buffs[slot_id].casterlevel = caster_level; + buffs[slot_id].casterlevel = caster_level; - if(caster) { - buffs[slot_id].casterid = caster->GetID(); - strcpy(buffs[slot_id].caster_name, caster->GetName()); - buffs[slot_id].client = true; - } else { - buffs[slot_id].casterid = 0; + if (caster) { + buffs[slot_id].casterid = caster->GetID(); + strcpy(buffs[slot_id].caster_name, caster->GetName()); + buffs[slot_id].client = true; + } else { + buffs[slot_id].casterid = 0; strcpy(buffs[slot_id].caster_name, ""); buffs[slot_id].client = false; - } + } - buffs[slot_id].ticsremaining = ticsremaining; + buffs[slot_id].ticsremaining = ticsremaining; buffs[slot_id].counters = counters; buffs[slot_id].numhits = numhits; buffs[slot_id].melee_rune = melee_rune; buffs[slot_id].magic_rune = magic_rune; - buffs[slot_id].persistant_buff = persistent? true: false; + buffs[slot_id].persistant_buff = persistent ? true : false; buffs[slot_id].dot_rune = dot_rune; buffs[slot_id].caston_x = caston_x; - buffs[slot_id].caston_y = caston_y; - buffs[slot_id].caston_z = caston_z; - buffs[slot_id].ExtraDIChance = ExtraDIChance; - buffs[slot_id].RootBreakChance = 0; - buffs[slot_id].UpdateClient = false; - - } + buffs[slot_id].caston_y = caston_y; + buffs[slot_id].caston_z = caston_z; + buffs[slot_id].ExtraDIChance = ExtraDIChance; + buffs[slot_id].RootBreakChance = 0; + buffs[slot_id].UpdateClient = false; + buffs[slot_id].instrument_mod = instrument_mod; + } max_slots = client->GetMaxBuffSlots(); - for(int index = 0; index < max_slots; ++index) { - if(!IsValidSpell(buffs[index].spellid)) + for (int index = 0; index < max_slots; ++index) { + if (!IsValidSpell(buffs[index].spellid)) continue; - for(int effectIndex = 0; effectIndex < 12; ++effectIndex) { + for (int effectIndex = 0; effectIndex < 12; ++effectIndex) { if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Charm) { - buffs[index].spellid = SPELL_UNKNOWN; - break; - } + buffs[index].spellid = SPELL_UNKNOWN; + break; + } - if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Illusion) { - if(buffs[index].persistant_buff) - break; + if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Illusion) { + if (buffs[index].persistant_buff) + break; - buffs[index].spellid = SPELL_UNKNOWN; + buffs[index].spellid = SPELL_UNKNOWN; break; } } @@ -3106,28 +3178,29 @@ void ZoneDatabase::SavePetInfo(Client *client) query.clear(); // pet buffs! - for (int index = 0; index < RuleI(Spells, MaxTotalSlotsPET); index++) { + int max_slots = RuleI(Spells, MaxTotalSlotsPET); + for (int index = 0; index < max_slots; index++) { if (petinfo->Buffs[index].spellid == SPELL_UNKNOWN || petinfo->Buffs[index].spellid == 0) continue; if (query.length() == 0) query = StringFormat("INSERT INTO `character_pet_buffs` " "(`char_id`, `pet`, `slot`, `spell_id`, `caster_level`, " - "`ticsremaining`, `counters`) " - "VALUES (%u, %u, %u, %u, %u, %u, %d)", + "`ticsremaining`, `counters`, `instrument_mod`) " + "VALUES (%u, %u, %u, %u, %u, %d, %d, %u)", client->CharacterID(), pet, index, petinfo->Buffs[index].spellid, petinfo->Buffs[index].level, petinfo->Buffs[index].duration, - petinfo->Buffs[index].counters); + petinfo->Buffs[index].counters, petinfo->Buffs[index].bard_modifier); else - query += StringFormat(", (%u, %u, %u, %u, %u, %u, %d)", + query += StringFormat(", (%u, %u, %u, %u, %u, %d, %d, %u)", client->CharacterID(), pet, index, petinfo->Buffs[index].spellid, petinfo->Buffs[index].level, petinfo->Buffs[index].duration, - petinfo->Buffs[index].counters); + petinfo->Buffs[index].counters, petinfo->Buffs[index].bard_modifier); } database.QueryDatabase(query); query.clear(); // pet inventory! - for (int index = EmuConstants::EQUIPMENT_BEGIN; index <= EmuConstants::EQUIPMENT_END; index++) { + for (int index = EQEmu::legacy::EQUIPMENT_BEGIN; index <= EQEmu::legacy::EQUIPMENT_END; index++) { if (!petinfo->Items[index]) continue; @@ -3159,7 +3232,8 @@ void ZoneDatabase::UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type QueryDatabase(query); } -void ZoneDatabase::LoadPetInfo(Client *client) { +void ZoneDatabase::LoadPetInfo(Client *client) +{ // Load current pet and suspended pet PetInfo *petinfo = client->GetPetInfo(0); @@ -3168,17 +3242,18 @@ void ZoneDatabase::LoadPetInfo(Client *client) { memset(petinfo, 0, sizeof(PetInfo)); memset(suspended, 0, sizeof(PetInfo)); - std::string query = StringFormat("SELECT `pet`, `petname`, `petpower`, `spell_id`, " - "`hp`, `mana`, `size` FROM `character_pet_info` " - "WHERE `char_id` = %u", client->CharacterID()); - auto results = database.QueryDatabase(query); - if(!results.Success()) { + std::string query = StringFormat("SELECT `pet`, `petname`, `petpower`, `spell_id`, " + "`hp`, `mana`, `size` FROM `character_pet_info` " + "WHERE `char_id` = %u", + client->CharacterID()); + auto results = database.QueryDatabase(query); + if (!results.Success()) { return; } - PetInfo *pi; + PetInfo *pi; for (auto row = results.begin(); row != results.end(); ++row) { - uint16 pet = atoi(row[0]); + uint16 pet = atoi(row[0]); if (pet == 0) pi = petinfo; @@ -3187,7 +3262,7 @@ void ZoneDatabase::LoadPetInfo(Client *client) { else continue; - strncpy(pi->Name,row[1],64); + strncpy(pi->Name, row[1], 64); pi->petpower = atoi(row[2]); pi->SpellID = atoi(row[3]); pi->HP = atoul(row[4]); @@ -3195,56 +3270,60 @@ void ZoneDatabase::LoadPetInfo(Client *client) { pi->size = atof(row[6]); } - query = StringFormat("SELECT `pet`, `slot`, `spell_id`, `caster_level`, `castername`, " - "`ticsremaining`, `counters` FROM `character_pet_buffs` " - "WHERE `char_id` = %u", client->CharacterID()); - results = QueryDatabase(query); - if (!results.Success()) { - return; - } - - for (auto row = results.begin(); row != results.end(); ++row) { - uint16 pet = atoi(row[0]); - if (pet == 0) - pi = petinfo; - else if (pet == 1) - pi = suspended; - else - continue; - - uint32 slot_id = atoul(row[1]); - if(slot_id >= RuleI(Spells, MaxTotalSlotsPET)) - continue; - - uint32 spell_id = atoul(row[2]); - if(!IsValidSpell(spell_id)) - continue; - - uint32 caster_level = atoi(row[3]); - int caster_id = 0; - // The castername field is currently unused - uint32 ticsremaining = atoul(row[5]); - uint32 counters = atoul(row[6]); - - pi->Buffs[slot_id].spellid = spell_id; - pi->Buffs[slot_id].level = caster_level; - pi->Buffs[slot_id].player_id = caster_id; - pi->Buffs[slot_id].slotid = 2; // Always 2 in buffs struct for real buffs - - pi->Buffs[slot_id].duration = ticsremaining; - pi->Buffs[slot_id].counters = counters; - } - - query = StringFormat("SELECT `pet`, `slot`, `item_id` " - "FROM `character_pet_inventory` " - "WHERE `char_id`=%u",client->CharacterID()); - results = database.QueryDatabase(query); - if (!results.Success()) { + query = StringFormat("SELECT `pet`, `slot`, `spell_id`, `caster_level`, `castername`, " + "`ticsremaining`, `counters`, `instrument_mod` FROM `character_pet_buffs` " + "WHERE `char_id` = %u", + client->CharacterID()); + results = QueryDatabase(query); + if (!results.Success()) { return; } - for(auto row = results.begin(); row != results.end(); ++row) { - uint16 pet = atoi(row[0]); + for (auto row = results.begin(); row != results.end(); ++row) { + uint16 pet = atoi(row[0]); + if (pet == 0) + pi = petinfo; + else if (pet == 1) + pi = suspended; + else + continue; + + uint32 slot_id = atoul(row[1]); + if (slot_id >= RuleI(Spells, MaxTotalSlotsPET)) + continue; + + uint32 spell_id = atoul(row[2]); + if (!IsValidSpell(spell_id)) + continue; + + uint32 caster_level = atoi(row[3]); + int caster_id = 0; + // The castername field is currently unused + int32 ticsremaining = atoi(row[5]); + uint32 counters = atoul(row[6]); + uint8 bard_mod = atoul(row[7]); + + pi->Buffs[slot_id].spellid = spell_id; + pi->Buffs[slot_id].level = caster_level; + pi->Buffs[slot_id].player_id = caster_id; + pi->Buffs[slot_id].effect_type = 2; // Always 2 in buffs struct for real buffs + + pi->Buffs[slot_id].duration = ticsremaining; + pi->Buffs[slot_id].counters = counters; + pi->Buffs[slot_id].bard_modifier = bard_mod; + } + + query = StringFormat("SELECT `pet`, `slot`, `item_id` " + "FROM `character_pet_inventory` " + "WHERE `char_id`=%u", + client->CharacterID()); + results = database.QueryDatabase(query); + if (!results.Success()) { + return; + } + + for (auto row = results.begin(); row != results.end(); ++row) { + uint16 pet = atoi(row[0]); if (pet == 0) pi = petinfo; else if (pet == 1) @@ -3253,12 +3332,11 @@ void ZoneDatabase::LoadPetInfo(Client *client) { continue; int slot = atoi(row[1]); - if (slot < EmuConstants::EQUIPMENT_BEGIN || slot > EmuConstants::EQUIPMENT_END) - continue; - - pi->Items[slot] = atoul(row[2]); - } + if (slot < EQEmu::legacy::EQUIPMENT_BEGIN || slot > EQEmu::legacy::EQUIPMENT_END) + continue; + pi->Items[slot] = atoul(row[2]); + } } bool ZoneDatabase::GetFactionData(FactionMods* fm, uint32 class_mod, uint32 race_mod, uint32 deity_mod, int32 faction_id) { @@ -3289,7 +3367,7 @@ bool ZoneDatabase::GetFactionData(FactionMods* fm, uint32 class_mod, uint32 race char str[32]; sprintf(str, "r%u", race_mod); - std::map::iterator iter = faction_array[faction_id]->mods.find(str); + auto iter = faction_array[faction_id]->mods.find(str); if(iter != faction_array[faction_id]->mods.end()) { fm->race_mod = iter->second; } else { @@ -3303,7 +3381,7 @@ bool ZoneDatabase::GetFactionData(FactionMods* fm, uint32 class_mod, uint32 race char str[32]; sprintf(str, "d%u", deity_mod); - std::map::iterator iter = faction_array[faction_id]->mods.find(str); + auto iter = faction_array[faction_id]->mods.find(str); if(iter != faction_array[faction_id]->mods.end()) { fm->deity_mod = iter->second; } else { @@ -3378,7 +3456,7 @@ bool ZoneDatabase::SetCharacterFactionLevel(uint32 char_id, int32 faction_id, in "ON DUPLICATE KEY UPDATE `current_value`=%i,`temp`=%i", char_id, faction_id, value, temp, value, temp); auto results = QueryDatabase(query); - + if (!results.Success()) return false; else @@ -3523,7 +3601,7 @@ uint32 ZoneDatabase::GetCharacterCorpseDecayTimer(uint32 corpse_db_id){ auto results = QueryDatabase(query); auto row = results.begin(); if (results.Success() && results.RowsAffected() != 0) - return atoul(row[0]); + return atoul(row[0]); return 0; } @@ -3550,9 +3628,9 @@ uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const c dbpc->plat, dbpc->haircolor, dbpc->beardcolor, dbpc->eyecolor1, dbpc->eyecolor2, dbpc->hairstyle, dbpc->face, dbpc->beard, dbpc->drakkin_heritage, dbpc->drakkin_tattoo, dbpc->drakkin_details, - dbpc->item_tint[0].Color, dbpc->item_tint[1].Color, dbpc->item_tint[2].Color, - dbpc->item_tint[3].Color, dbpc->item_tint[4].Color, dbpc->item_tint[5].Color, - dbpc->item_tint[6].Color, dbpc->item_tint[7].Color, dbpc->item_tint[8].Color, + dbpc->item_tint.Head.Color, dbpc->item_tint.Chest.Color, dbpc->item_tint.Arms.Color, + dbpc->item_tint.Wrist.Color, dbpc->item_tint.Hands.Color, dbpc->item_tint.Legs.Color, + dbpc->item_tint.Feet.Color, dbpc->item_tint.Primary.Color, dbpc->item_tint.Secondary.Color, db_id); auto results = QueryDatabase(query); @@ -3610,8 +3688,8 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui "`wc_6` = %u, " "`wc_7` = %u, " "`wc_8` = %u, " - "`wc_9` = %u ", - EscapeString(charname).c_str(), + "`wc_9` = %u ", + EscapeString(charname).c_str(), zoneid, instanceid, charid, @@ -3643,15 +3721,15 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui dbpc->drakkin_heritage, dbpc->drakkin_tattoo, dbpc->drakkin_details, - dbpc->item_tint[0].Color, - dbpc->item_tint[1].Color, - dbpc->item_tint[2].Color, - dbpc->item_tint[3].Color, - dbpc->item_tint[4].Color, - dbpc->item_tint[5].Color, - dbpc->item_tint[6].Color, - dbpc->item_tint[7].Color, - dbpc->item_tint[8].Color + dbpc->item_tint.Head.Color, + dbpc->item_tint.Chest.Color, + dbpc->item_tint.Arms.Color, + dbpc->item_tint.Wrist.Color, + dbpc->item_tint.Hands.Color, + dbpc->item_tint.Legs.Color, + dbpc->item_tint.Feet.Color, + dbpc->item_tint.Primary.Color, + dbpc->item_tint.Secondary.Color ); auto results = QueryDatabase(query); uint32 last_insert_id = results.LastInsertedID(); @@ -3664,21 +3742,21 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui corpse_items_query = StringFormat("REPLACE INTO `character_corpse_items` \n" " (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n" " VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n", - last_insert_id, + last_insert_id, dbpc->items[i].equip_slot, - dbpc->items[i].item_id, - dbpc->items[i].charges, - dbpc->items[i].aug_1, - dbpc->items[i].aug_2, - dbpc->items[i].aug_3, - dbpc->items[i].aug_4, + dbpc->items[i].item_id, + dbpc->items[i].charges, + dbpc->items[i].aug_1, + dbpc->items[i].aug_2, + dbpc->items[i].aug_3, + dbpc->items[i].aug_4, dbpc->items[i].aug_5, dbpc->items[i].aug_6, dbpc->items[i].attuned ); first_entry = 1; } - else{ + else{ corpse_items_query = corpse_items_query + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n", last_insert_id, dbpc->items[i].equip_slot, @@ -3823,15 +3901,15 @@ bool ZoneDatabase::LoadCharacterCorpseData(uint32 corpse_id, PlayerCorpse_Struct pcs->drakkin_heritage = atoul(row[i++]); // drakkin_heritage, pcs->drakkin_tattoo = atoul(row[i++]); // drakkin_tattoo, pcs->drakkin_details = atoul(row[i++]); // drakkin_details, - pcs->item_tint[0].Color = atoul(row[i++]); // wc_1, - pcs->item_tint[1].Color = atoul(row[i++]); // wc_2, - pcs->item_tint[2].Color = atoul(row[i++]); // wc_3, - pcs->item_tint[3].Color = atoul(row[i++]); // wc_4, - pcs->item_tint[4].Color = atoul(row[i++]); // wc_5, - pcs->item_tint[5].Color = atoul(row[i++]); // wc_6, - pcs->item_tint[6].Color = atoul(row[i++]); // wc_7, - pcs->item_tint[7].Color = atoul(row[i++]); // wc_8, - pcs->item_tint[8].Color = atoul(row[i++]); // wc_9 + pcs->item_tint.Head.Color = atoul(row[i++]); // wc_1, + pcs->item_tint.Chest.Color = atoul(row[i++]); // wc_2, + pcs->item_tint.Arms.Color = atoul(row[i++]); // wc_3, + pcs->item_tint.Wrist.Color = atoul(row[i++]); // wc_4, + pcs->item_tint.Hands.Color = atoul(row[i++]); // wc_5, + pcs->item_tint.Legs.Color = atoul(row[i++]); // wc_6, + pcs->item_tint.Feet.Color = atoul(row[i++]); // wc_7, + pcs->item_tint.Primary.Color = atoul(row[i++]); // wc_8, + pcs->item_tint.Secondary.Color = atoul(row[i++]); // wc_9 } query = StringFormat( "SELECT \n" @@ -4057,3 +4135,36 @@ bool ZoneDatabase::DeleteCharacterCorpse(uint32 db_id) { return false; } + +uint32 ZoneDatabase::LoadSaylinkID(const char* saylink_text, bool auto_insert) +{ + if (!saylink_text || saylink_text[0] == '\0') + return 0; + + std::string query = StringFormat("SELECT `id` FROM `saylink` WHERE `phrase` = '%s' LIMIT 1", saylink_text); + auto results = QueryDatabase(query); + if (!results.Success()) + return 0; + if (!results.RowCount()) { + if (auto_insert) + return SaveSaylinkID(saylink_text); + else + return 0; + } + + auto row = results.begin(); + return atoi(row[0]); +} + +uint32 ZoneDatabase::SaveSaylinkID(const char* saylink_text) +{ + if (!saylink_text || saylink_text[0] == '\0') + return 0; + + std::string query = StringFormat("INSERT INTO `saylink` (`phrase`) VALUES ('%s')", saylink_text); + auto results = QueryDatabase(query); + if (!results.Success()) + return 0; + + return results.LastInsertedID(); +} diff --git a/zone/zonedb.h b/zone/zonedb.h index cac380a96..689f9a82f 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -6,6 +6,8 @@ #include "position.h" #include "../common/faction.h" #include "../common/eqemu_logsys.h" +#include "aa_ability.h" +#include "event_codes.h" class Client; class Corpse; @@ -90,7 +92,7 @@ struct DBnpcspellseffects_Struct { }; struct DBTradeskillRecipe_Struct { - SkillUseTypes tradeskill; + EQEmu::skills::SkillType tradeskill; int16 skill_needed; uint16 trivial; bool nofail; @@ -123,8 +125,8 @@ struct PetInfo { uint32 HP; uint32 Mana; float size; - SpellBuff_Struct Buffs[BUFF_COUNT]; - uint32 Items[EmuConstants::EQUIPMENT_SIZE]; + SpellBuff_Struct Buffs[PET_BUFF_COUNT]; + uint32 Items[EQEmu::legacy::EQUIPMENT_SIZE]; char Name[64]; }; @@ -275,10 +277,10 @@ public: bool LoadCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp); /* Character Data Saves */ - bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, const glm::vec4& position, uint8 is_home); + bool SaveCharacterBindPoint(uint32 character_id, const BindStruct &bind, uint32 bind_num); bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp); bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp); - bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level); + bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level, uint32 charges); bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color); @@ -289,6 +291,7 @@ public: bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name); bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon); bool SaveCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp); + bool SaveCharacterInventorySnapshot(uint32 character_id); /* Character Data Deletes */ bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id); @@ -339,17 +342,10 @@ public: bool SetCharacterFactionLevel(uint32 char_id, int32 faction_id, int32 value, uint8 temp, faction_map &val_list); // needed for factions Dec, 16 2001 bool LoadFactionData(); - /* AAs */ - bool LoadAAEffects(); - bool LoadAAEffects2(); - bool LoadSwarmSpells(); - SendAA_Struct*GetAASkillVars(uint32 skill_id); - uint8 GetTotalAALevels(uint32 skill_id); - uint32 GetSizeAA(); - uint32 CountAAs(); - void LoadAAs(SendAA_Struct **load); - uint32 CountAAEffects(); - void FillAAEffects(SendAA_Struct* aa_struct); + /* AAs New */ + bool LoadAlternateAdvancementAbilities(std::unordered_map> &abilities, + std::unordered_map> &ranks); + bool LoadAlternateAdvancement(Client *c); /* Zone related */ bool GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &allow_mercs, uint8 &zone_type, int &ruleset, char **map_filename); @@ -363,6 +359,7 @@ public: bool LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list); bool LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list); bool PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay = 0); + bool PopulateZoneSpawnListClose(uint32 zoneid, LinkedList &spawn2_list, int16 version, const glm::vec4& client_position, uint32 repop_distance); Spawn2* LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2id, uint32 timeleft); bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value); void UpdateRespawnTime(uint32 id, uint16 instance_id,uint32 timeleft); @@ -483,6 +480,10 @@ public: void LoadAltCurrencyValues(uint32 char_id, std::map ¤cy); void UpdateAltCurrencyValue(uint32 char_id, uint32 currency_id, uint32 value); + /* Saylinks */ + uint32 LoadSaylinkID(const char* saylink_text, bool auto_insert = true); + uint32 SaveSaylinkID(const char* saylink_text); + /* * Misc stuff. * PLEASE DO NOT ADD TO THIS COLLECTION OF CRAP UNLESS YOUR METHOD diff --git a/zone/zonedump.h b/zone/zonedump.h index dc13300e3..6782881fe 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -86,7 +86,7 @@ struct NPCType uint32 drakkin_heritage; uint32 drakkin_tattoo; uint32 drakkin_details; - uint32 armor_tint[_MaterialCount]; + EQEmu::TintProfile armor_tint; uint32 min_dmg; uint32 max_dmg; int16 attack_count; @@ -127,6 +127,11 @@ struct NPCType bool no_target_hotkey; bool raid_target; uint8 probability; + uint8 armtexture; + uint8 bracertexture; + uint8 handtexture; + uint8 legtexture; + uint8 feettexture; }; namespace player_lootitem { @@ -164,7 +169,7 @@ struct PlayerCorpse_Struct { uint32 silver; uint32 gold; uint32 plat; - Color_Struct item_tint[9]; + EQEmu::TintProfile item_tint; uint8 haircolor; uint8 beardcolor; uint8 eyecolor1; diff --git a/zone/zoning.cpp b/zone/zoning.cpp index 5b60448ec..16130f8e2 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -365,7 +365,7 @@ void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instanc if (zone_id == zone->GetZoneID() && instance_id == zone->GetInstanceID()) { // No need to ask worldserver if we're zoning to ourselves (most // likely to a bind point), also fixes a bug since the default response was failure - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZoneChange,sizeof(ZoneChange_Struct)); + auto outapp = new EQApplicationPacket(OP_ZoneChange, sizeof(ZoneChange_Struct)); ZoneChange_Struct* zc2 = (ZoneChange_Struct*) outapp->pBuffer; strcpy(zc2->char_name, GetName()); zc2->zoneID = zone_id; @@ -378,19 +378,19 @@ void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instanc } else { // vesuvias - zoneing to another zone so we need to the let the world server //handle things with the client for a while - ServerPacket* pack = new ServerPacket(ServerOP_ZoneToZoneRequest, sizeof(ZoneToZone_Struct)); - ZoneToZone_Struct* ztz = (ZoneToZone_Struct*) pack->pBuffer; - ztz->response = 0; - ztz->current_zone_id = zone->GetZoneID(); - ztz->current_instance_id = zone->GetInstanceID(); - ztz->requested_zone_id = zone_id; - ztz->requested_instance_id = instance_id; - ztz->admin = admin; - ztz->ignorerestrictions = ignore_r; - strcpy(ztz->name, GetName()); - ztz->guild_id = GuildID(); - worldserver.SendPacket(pack); - safe_delete(pack); + auto pack = new ServerPacket(ServerOP_ZoneToZoneRequest, sizeof(ZoneToZone_Struct)); + ZoneToZone_Struct *ztz = (ZoneToZone_Struct *)pack->pBuffer; + ztz->response = 0; + ztz->current_zone_id = zone->GetZoneID(); + ztz->current_instance_id = zone->GetInstanceID(); + ztz->requested_zone_id = zone_id; + ztz->requested_instance_id = instance_id; + ztz->admin = admin; + ztz->ignorerestrictions = ignore_r; + strcpy(ztz->name, GetName()); + ztz->guild_id = GuildID(); + worldserver.SendPacket(pack); + safe_delete(pack); } //reset to unsolicited. @@ -562,7 +562,7 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z if (entity == 0) { Message(13, "Error: OP_EndLootRequest: Corpse not found (ent = 0)"); - if (GetClientVersion() >= ClientVersion::SoD) + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoD) Corpse::SendEndLootErrorPacket(this); else Corpse::SendLootReqErrorPacket(this); @@ -582,13 +582,14 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z zone_mode = zm; if (zm == ZoneToBindPoint) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_ZonePlayerToBind, sizeof(ZonePlayerToBind_Struct) + iZoneNameLength); + auto outapp = new EQApplicationPacket(OP_ZonePlayerToBind, + sizeof(ZonePlayerToBind_Struct) + iZoneNameLength); ZonePlayerToBind_Struct* gmg = (ZonePlayerToBind_Struct*) outapp->pBuffer; // If we are SoF and later and are respawning from hover, we want the real zone ID, else zero to use the old hack. // if(zone->GetZoneID() == zoneID) { - if((GetClientVersionBit() & BIT_SoFAndLater) && (!RuleB(Character, RespawnFromHover) || !IsHoveringForRespawn())) + if ((ClientVersionBit() & EQEmu::versions::bit_SoFAndLater) && (!RuleB(Character, RespawnFromHover) || !IsHoveringForRespawn())) gmg->bind_zone_id = 0; else gmg->bind_zone_id = zoneID; @@ -607,7 +608,8 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z safe_delete(outapp); } else if(zm == ZoneSolicited || zm == ZoneToSafeCoords) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RequestClientZoneChange, sizeof(RequestClientZoneChange_Struct)); + auto outapp = + new EQApplicationPacket(OP_RequestClientZoneChange, sizeof(RequestClientZoneChange_Struct)); RequestClientZoneChange_Struct* gmg = (RequestClientZoneChange_Struct*) outapp->pBuffer; gmg->zone_id = zoneID; @@ -623,7 +625,8 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z safe_delete(outapp); } else if(zm == EvacToSafeCoords) { - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RequestClientZoneChange, sizeof(RequestClientZoneChange_Struct)); + auto outapp = + new EQApplicationPacket(OP_RequestClientZoneChange, sizeof(RequestClientZoneChange_Struct)); RequestClientZoneChange_Struct* gmg = (RequestClientZoneChange_Struct*) outapp->pBuffer; // if we are in the same zone we want to evac to, client will not send OP_ZoneChange back to do an actual @@ -665,7 +668,8 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z SendPosition(); } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RequestClientZoneChange, sizeof(RequestClientZoneChange_Struct)); + auto outapp = + new EQApplicationPacket(OP_RequestClientZoneChange, sizeof(RequestClientZoneChange_Struct)); RequestClientZoneChange_Struct* gmg = (RequestClientZoneChange_Struct*) outapp->pBuffer; gmg->zone_id = zoneID; @@ -707,37 +711,40 @@ void Client::GoToSafeCoords(uint16 zone_id, uint16 instance_id) { } -void Mob::Gate() { - GoToBind(); +void Mob::Gate(uint8 bindnum) { + GoToBind(bindnum); } -void Client::Gate() { - Mob::Gate(); +void Client::Gate(uint8 bindnum) { + Mob::Gate(bindnum); } -void NPC::Gate() { +void NPC::Gate(uint8 bindnum) { entity_list.MessageClose_StringID(this, true, 200, MT_Spells, GATES, GetCleanName()); - Mob::Gate(); + Mob::Gate(bindnum); } -void Client::SetBindPoint(int to_zone, int to_instance, const glm::vec3& location) { +void Client::SetBindPoint(int bind_num, int to_zone, int to_instance, const glm::vec3 &location) +{ + if (bind_num < 0 || bind_num >= 4) + bind_num = 0; + if (to_zone == -1) { - m_pp.binds[0].zoneId = zone->GetZoneID(); - m_pp.binds[0].instance_id = (zone->GetInstanceID() != 0 && zone->IsInstancePersistent()) ? zone->GetInstanceID() : 0; - m_pp.binds[0].x = m_Position.x; - m_pp.binds[0].y = m_Position.y; - m_pp.binds[0].z = m_Position.z; + m_pp.binds[bind_num].zoneId = zone->GetZoneID(); + m_pp.binds[bind_num].instance_id = + (zone->GetInstanceID() != 0 && zone->IsInstancePersistent()) ? zone->GetInstanceID() : 0; + m_pp.binds[bind_num].x = m_Position.x; + m_pp.binds[bind_num].y = m_Position.y; + m_pp.binds[bind_num].z = m_Position.z; + } else { + m_pp.binds[bind_num].zoneId = to_zone; + m_pp.binds[bind_num].instance_id = to_instance; + m_pp.binds[bind_num].x = location.x; + m_pp.binds[bind_num].y = location.y; + m_pp.binds[bind_num].z = location.z; } - else { - m_pp.binds[0].zoneId = to_zone; - m_pp.binds[0].instance_id = to_instance; - m_pp.binds[0].x = location.x; - m_pp.binds[0].y = location.y; - m_pp.binds[0].z = location.z; - } - auto regularBindPoint = glm::vec4(m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, 0.0f); - database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[0].zoneId, m_pp.binds[0].instance_id, regularBindPoint, 0); + database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[bind_num], bind_num); } void Client::GoToBind(uint8 bindnum) {