Compare commits

...

196 Commits

Author SHA1 Message Date
E Spause a3f21cc9ea Additional fixups. 2017-03-16 13:27:58 -04:00
E Spause 3c9e6d913a Merge remote-tracking branch 'refs/remotes/origin/master' into 2002_fixes 2017-03-16 13:23:56 -04:00
Michael Cook (mackal) 153e587cea Not sure how that happened 2017-03-16 12:56:21 -04:00
Michael Cook (mackal) fbb13ec416 bug found by clang 4 2017-03-16 12:52:58 -04:00
Michael Cook (mackal) e7785d5693 Bash dmg should return 0 with no item (slam) 2017-03-15 15:25:42 -04:00
Michael Cook (mackal) 23bc535e23 Tweaks to most likely wrong PVP damage reduction 2017-03-15 15:07:28 -04:00
Michael Cook (mackal) d04d6750a2 Allow base damage of 0 (ex slam) min damage done to 1 2017-03-15 13:22:45 -04:00
E Spause 9c08d6f25b Fix additional logic cases for merc disbanding. 2017-03-15 07:09:14 -04:00
E Spause f8d000d660 Don't allow disbanding mercs that have their owner in combat if the rule is set. 2017-03-15 06:52:16 -04:00
E Spause b2c6bb4df5 Set default, no-skill value for bash to 1. This is consistent with what demonstar was seeing on live with no skill and slam.
GetBaseDamage is now used for Bash/Slam additionally.
2017-03-15 06:39:57 -04:00
E Spause 542d0795c4 Add rule instead of define for IDLE_WHEN_EMPTY 2017-03-15 06:37:03 -04:00
E Spause c3b7f6d0bf Merge remote-tracking branch 'refs/remotes/origin/master' into 2002_fixes 2017-03-15 06:15:04 -04:00
E Spause 21e53a3cd0 Fix up slam some more 2017-03-15 06:15:01 -04:00
Uleat 2d24237aac Added los movement logic to combat and follow code (los is rule-based and can by disabled by applying the optional 2017_03_14_mercs_use_pathing_rule.sql) 2017-03-14 23:23:42 -04:00
Uleat 750e65f847 Merge branch 'master' of https://github.com/EQEmu/Server 2017-03-14 23:21:24 -04:00
E Spause 3ce99d9f00 Stupid sexy floats 2017-03-14 22:42:14 -04:00
E Spause 598196329d Bash min skill fix 2017-03-14 22:15:22 -04:00
Uleat 31cc6f63d6 Added evade code to rogue mercs 2017-03-14 16:32:10 -04:00
E Spause bbfacd902c Woops 2017-03-13 15:08:20 -04:00
E Spause 5cfb3111a6 SoF-era con system. New rule, UseOldConSystem to disable this functionality. 2017-03-13 15:07:56 -04:00
E Spause 5b674f23bd Merge remote-tracking branch 'refs/remotes/origin/master' into 2002_fixes 2017-03-13 15:05:26 -04:00
E Spause 81cadf3bb2 Merge pull request #593 from EQEmu/2002_fixes
MaxClientsSimplifiedLogic rule. See commit for description
2017-03-13 14:59:30 -04:00
E Spause 54c28117a8 Merge remote-tracking branch 'refs/remotes/origin/master' into 2002_fixes 2017-03-13 06:27:01 -04:00
E Spause 79f9433dfa Merc logic fix for heal spells - allows mercs to select fast healing spells as a 'standard' healing spell & new rule for unsuspend 2017-03-13 06:26:48 -04:00
E Spause 67a95b59a7 Merge remote-tracking branch 'refs/remotes/origin/master' into 2002_fixes 2017-03-12 23:20:55 -04:00
E Spause 09b9d398e2 Rule itself for MaxClientsSimplifiedLogic. Defaults to disabled (false) 2017-03-12 23:19:50 -04:00
E Spause 3dd0d43e96 Add a rule, MaxClientsSimplifiedLogic which allows for P99-style IP restrictions if enabled. Opcode handler for OP_WorldLogout in char sel.
Only uses ExemptAccountLimitStatus and MaxClientsPerIP. Also adds in an
opcode handler so CLEs are cleaned up at char select when ESC is
pressed.
2017-03-12 23:19:24 -04:00
E Spause 8d1fe63e77 Merge pull request #592 from EQEmu/2002_fixes
Remove delay death from Mercs so they function like normal NPCs at 0 health.
2017-03-12 23:17:08 -04:00
E Spause 3fa72218a4 Remove delay death from Mercs so they function like normal NPCs at 0 health. 2017-03-12 23:08:59 -04:00
Uleat f3f034d948 Fix for a combat ability targeting error 2017-03-12 21:46:16 -04:00
Michael Cook (mackal) bd364a4049 Merge pull request #591 from EQEmu/2002_fixes
Added an optional rule value that forces startzones to be the same as…
2017-03-12 19:21:05 -04:00
Akkadius 41b1634199 Update proper file name utils/sql/git/optional/2017_03_12_rule_values_range_update.sql [skip ci] 2017-03-12 17:19:42 -05:00
Akkadius 0159e1cc72 Fix some crapped out formatting [skip ci] 2017-03-12 16:42:26 -05:00
Akkadius ab372b0f6b - Implemented range rules for packets and other functions
RULE_INT ( Range, Say, 135 )
	RULE_INT ( Range, Emote, 135 )
	RULE_INT ( Range, BeginCast, 200)
	RULE_INT ( Range, Anims, 135)
	RULE_INT ( Range, SpellParticles, 135)
	RULE_INT ( Range, DamageMessages, 50)
	RULE_INT ( Range, SpellMessages, 75)
	RULE_INT ( Range, SongMessages, 75)
	RULE_INT ( Range, MobPositionUpdates, 600)
	RULE_INT ( Range, CriticalDamage, 80)

 - (Readability) Also cleaned up some formatting in messaging and packets so it is easier to understand what is going on with the code
2017-03-12 16:10:53 -05:00
Akkadius 14d09485eb Implement new rule based ranges for various range based packet operations (performance)
- the defaults are set in the code and can be tweaked by sourcing utils/sql/git/optional/rule_values_range_update.sql
- Thanks to mackal for gathering live ranges, thanks to takp for initial numbers
- We would send 200 for combat updates and the client will only display <= range 54 anyways, these should help a lot in spammy combat

RULE_CATEGORY( Range )
RULE_INT ( Range, Say, 135 )
RULE_INT ( Range, Emote, 135 )
RULE_INT ( Range, BeginCast, 200)
RULE_INT ( Range, Anims, 135)
RULE_INT ( Range, DamageMessages, 50)
RULE_INT ( Range, SpellMessages, 75)
RULE_INT ( Range, SongMessages, 75)
RULE_CATEGORY_END()
2017-03-12 14:38:14 -05:00
Uleat 8cd6416754 Added ItemData::CheckLoreConflict() 2017-03-12 14:20:22 -04:00
E Spause 4fad93824b Formatting fixes. 2017-03-12 03:49:41 -04:00
E Spause fe70834a6b Enabled a skill check bypass for OGRE, TROLL, and BARBARIAN races so the "Slam" skill works once more. 2017-03-12 03:49:07 -04:00
E Spause 17b5cc1fa5 Remove error message that has honestly bothered me since the dawn of time. Appears most often when doing loot all. EQLive does not have it. 2017-03-12 03:47:26 -04:00
E Spause 04ce4f66ed Added an optional rule value that forces startzones to be the same as the bind zone and enabled bind xyz once again. 2017-03-12 03:41:21 -04:00
Uleat 5b24cbde5d Merge branch 'master' of https://github.com/EQEmu/Server 2017-03-11 13:35:40 -05:00
Uleat 3555791e1f Multi-line remark statements wreck havoc on visual studio's parser (expensive) 2017-03-11 13:35:30 -05:00
Michael Cook (mackal) 262bcf5c29 Fix merc attack delay 2017-03-10 19:17:04 -05:00
Uleat 226a49cb42 Merge branch 'master' of https://github.com/EQEmu/Server 2017-03-10 18:41:14 -05:00
Uleat bf3d9b2d02 Couple of critical fixes for bot trade code 2017-03-10 18:41:04 -05:00
Michael Cook (mackal) 3d229e1da1 Aggro Meter on by default now (seemed fine on PEQ) 2017-03-10 18:15:08 -05:00
Michael Cook (mackal) df5d58f43d Temp pets shouldn't spawn when they're targeting a corpse 2017-03-10 13:00:22 -05:00
Uleat 37d22e17a3 First step of implementing inventory v2.0 2017-03-09 02:46:09 -05:00
Uleat 999650d368 Fixed a few glitches related to bot trading and other affected code 2017-03-09 01:55:01 -05:00
Uleat 09bbfbcc31 Complete rework of the bot trading system (see changelog.txt) 2017-03-08 08:12:04 -05:00
Drajor f26b7a4adc Hacky fix for quantity wrapping when stacked items are sold that have a quantity greater than 255. A better solution will need to implemented long term 2017-03-08 06:22:17 +10:00
Uleat becd7b5c24 This probably resolves a long-term bug with bots who are conscientious objectors to fighting... (Had a rash of reports concerning this -- obscure attack timer bug within inherited NPC class ctor) 2017-03-05 05:12:54 -05:00
Uleat d559e9da10 Fix for bot auto-combat damage (please post any abnormalities) 2017-03-04 14:50:32 -05:00
Uleat 2690d8fed8 Added inspect buff cases for bots (ZombieSoul) 2017-03-03 17:51:02 -05:00
Michael Cook (mackal) 7d13475bac Fix ClearAggro xtarget issue 2017-03-02 14:31:48 -05:00
Uleat 2ab280bef0 Merge branch 'master' of https://github.com/EQEmu/Server 2017-03-01 19:16:09 -05:00
Uleat 15af28720a Bad logic..not used anyways 2017-03-01 19:16:02 -05:00
Akkadius 5213e4c7d4 Remove table that doesn't exist anymore (PEQ Dumps) [skip ci] 2017-03-01 15:19:56 -06:00
Uleat 12d7f242b4 Tweaked bot caster combat range code a little (they shouldn't pile up unless there are los issues...) 2017-03-01 16:11:17 -05:00
Uleat 7ac597270b Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-28 20:29:32 -05:00
Uleat 05ca4669a9 Fix for aberrant bot animations when using ^summon (i.e., swimming in air) 2017-02-28 10:39:26 -05:00
Uleat a7cbe2f60e Fix for npc corpse looting not updating appearance of looted items 2017-02-28 09:44:24 -05:00
Uleat 52d79f89a9 Bots should now /con correctly after a successful ^update 2017-02-28 08:49:25 -05:00
Michael Cook (mackal) a8a1c3f809 Better comment some group shit 2017-02-28 02:21:44 -05:00
Uleat 24bae49401 Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-27 21:32:17 -05:00
Uleat bf239f9691 A 'hack' and a 'fix' (bot movement changes) 2017-02-27 21:32:07 -05:00
Michael Cook (mackal) 666513c4ab Better comment SendGroupCreatePacket 2017-02-27 15:21:50 -05:00
Uleat 1b2df18cea Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-26 22:14:34 -05:00
Uleat b1be667884 Update bot spell casting chances table and implemented 'pre-combat' mode for all bots (only bard is actively coded atm) 2017-02-26 22:13:41 -05:00
Michael Cook (mackal) 91ae6a6613 Secondary aggro meter fix 2017-02-26 19:13:47 -05:00
Uleat 303f056075 Forgot loader... 2017-02-26 07:02:20 -05:00
Uleat ec9af74dc9 Update bot spells entries for new npc spells id values 2017-02-26 07:00:24 -05:00
Uleat a49e3d6471 Update for saved bot data to use new spells id values 2017-02-26 06:26:59 -05:00
Uleat 9ae585dd81 Moved bot npc spells entries to the 3000 + class id range 2017-02-26 05:47:10 -05:00
Uleat 0ee3168241 Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-25 18:02:47 -05:00
Michael Cook (mackal) 3fd40e9449 Make ST_AreaNPCOnly skip faction check
The motivation for this is there a bunch of auras that use this target type
that all would require setting up faction for these NPCs so they would hate
everything.

Also allows Ward of Destruction to work.
2017-02-25 14:36:17 -05:00
Uleat c61c275221 Added position update packet in out-of-combat movement code when movement occurs (rule-based; default: false) - appears to help with rubber-banding effect 2017-02-25 09:02:20 -05:00
Uleat 7a6d5d46f4 Added node pathing to the bot movement dilemma... 2017-02-25 03:48:02 -05:00
Michael Cook (mackal) 14a5ff399a clear xtarget manager on death 2017-02-25 02:37:57 -05:00
Michael Cook (mackal) 31907382c8 Lets not aggro zonign clients 2017-02-25 02:21:48 -05:00
Uleat 5c6492bc0f Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-24 20:09:53 -05:00
Michael Cook (mackal) 0968ce0d60 Add petnaming type 5 (`s ward) 2017-02-24 15:28:22 -05:00
Uleat 171474f1d2 Fix for bot combat line-of-sight issue (let me know if this causes zone training again) 2017-02-24 10:02:50 -05:00
Uleat 3383f65ff7 Updated bot casting roles to not refresh with every spell cast (oversight in recent casting chances commit) 2017-02-24 04:48:33 -05:00
Michael Cook (mackal) 7621bf47c8 Quick fix to resolve some serious group issues
Group leader swapping didn't work and left the client in a bad state
This just disbands the group if the leader leaves

Also prevents a group leader from disbanding other groups ...
Which also lead to bad states

Group leader swapping not working is better than these issues :P
2017-02-24 01:12:46 -05:00
Uleat 72ed770037 Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-23 19:16:54 -05:00
Uleat 4e8a03f7b4 Migrated bot spell casting chance data to the database 2017-02-23 19:16:36 -05:00
Michael Cook (mackal) 602381ebec copy paste fail 2017-02-23 12:27:44 -05:00
Akkadius e098836934 Upload table lists that PEQ uses in daily database dump 2017-02-22 22:49:23 -06:00
Uleat ce3fc0f2c3 Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-21 20:40:35 -05:00
Uleat 9adfe5b9ff Fix for bot wizard repeating familiar casting when pet is dead and buff is active 2017-02-21 20:40:04 -05:00
Michael Cook (mackal) b423ad0d80 Crash fix 2017-02-21 18:02:58 -05:00
Michael Cook (mackal) 9a157fa028 Turn aggro meter off by default until more tested
Reports of it being too spammy and causing DCs
2017-02-21 17:54:25 -05:00
Drajor 7db82a3b14 Fixes issue with calculating the value of items being sold. The loop was starting at 0 instead of 1. 2017-02-22 06:26:49 +10:00
Michael Cook (mackal) 056725b9bd Make timer for aggro meter not a magic number
you can edit AGGRO_METER_UPDATE_MS in common/features.h if you want to
see if a different number would work better
2017-02-21 13:38:00 -05:00
Akkadius 8bbf099636 Merge fix 2017-02-21 03:57:10 -06:00
Akkadius a884639534 Reduce the initial telnet console prompt timer 2017-02-21 03:55:21 -06:00
Uleat 8f67df1f4f Oops! (Won't affect any changes up to this point) [skip ci] 2017-02-20 22:50:43 -05:00
Uleat f851b1a3b4 Added combat-prep song buffing note [skip ci] 2017-02-20 21:47:47 -05:00
Uleat b41bb8e179 Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-20 21:41:25 -05:00
Uleat d9633dfee4 Bard bot song twisting update 2017-02-20 21:41:15 -05:00
Michael Cook (mackal) 46b19e8e6f Disable the aggro meter timer if it's not enabled 2017-02-20 18:41:17 -05:00
Akkadius f0f5c41c30 Fixed an issue where clients would sell x1000 stacks of items where the price overflows data sizes, the code will now make sure not to sell too many items that go over this data size 2017-02-19 21:12:18 -06:00
Michael Cook (mackal) 08c2f73e37 Implement aggro meter for RoF2 (RoF wasn't tested)
I didn't test RoF, so it's disabled for now (change AggroMeterAvaliable if you want to test)

Group member meters probably buggy ... but do later

The "lock target" feature isn't working currently either
2017-02-18 22:27:34 -05:00
Michael Cook (mackal) 9f4604ec3e Rework how XTarget auto haters work
This should cause the auto haters to be shared with other toons who might be
interested (group/raid) like live.

There maybe some bugs since there is a lot of complex interactions here.
2017-02-17 21:04:48 -05:00
Uleat 8177f7d9bb Activation of bot_spells_entries table 2017-02-15 19:04:36 -05:00
Uleat 4ec3fda59d Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-15 18:38:45 -05:00
Uleat e3c8b75259 Moved bot spell entries out of npc spell entries (easier to manage bot changes by committing to non-bot manifest) 2017-02-15 07:42:17 -05:00
Uleat d62a449f9c Missed an npc spells type (or two..) 2017-02-15 07:03:43 -05:00
Michael Cook (mackal) d043c38f71 Make it so enraged NPCs can't be riposted
This should prevent infinite loops
2017-02-14 16:47:22 -05:00
JJ 5b8ad902ce Add character_tasks to the list when deleting a character. 2017-02-13 16:00:39 -05:00
Akkadius ef16522473 Implement Rule Zone:GlobalLootMultiplier (Default 1) - Sets Global Loot drop multiplier for database based drops, useful for double, triple loot etc. 2017-02-13 02:16:40 -06:00
Akkadius fe21564659 Apply KLS' tweaks to Log.Out (CPU saves) https://github.com/EQEmu/Server/commit/1d055b5364a4183a327683dfa13cf33954874616 2017-02-13 01:38:23 -06:00
Akkadius e3173d04d4 Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-13 01:26:44 -06:00
Akkadius 92d4468326 Put a category enabled filter on default switch case so we're not chewing up extra cpu cycles 2017-02-13 01:26:19 -06:00
Akkadius 0f32f780a9 Revert previous change to keep installation memory safe and independent [skip ci] 2017-02-12 23:31:25 -06:00
Akkadius 955514c20f eqemu_server.pl Linux make routine compile with the amount of cores available [skip ci] 2017-02-12 23:16:38 -06:00
Uleat ed717add29 Added a few more SpellType enumerations (uncoded) 2017-02-11 18:33:58 -05:00
Uleat a7b159fe65 Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-09 17:58:08 -05:00
Uleat 38651258fc Updated npc spell types to 32-bit mask 2017-02-09 17:57:55 -05:00
Akkadius 4605540955 Update login_opcodes.conf 2017-02-09 01:33:41 -06:00
Akkadius c83bc038f3 Fix issue with installer pulling down the wrong opcodes for SOD+ clients on Linux Loginserver 2017-02-09 01:32:26 -06:00
Akkadius d3dff3760a Merge pull request #587 from N0ctrnl/patch-1
Update for Ubuntu 16.04
2017-02-08 19:04:29 -06:00
Kurt Gilpin 9e49b2ae0f Update for Ubuntu 16.04
This should be fully working with Ubuntu 16.04 Server.
2017-02-08 19:01:50 -06:00
Akkadius a81212e1b4 Allow admin telnet connections from localhost without requiring credentials to world 2017-02-08 18:00:38 -06:00
Akkadius 57d75572b2 Heavily reduce idle cpu footprint with many zone processes loaded simultaneously and not active 2017-02-08 17:28:54 -06:00
Uleat d1abe4a332 Added dev script for function to retrieve spell type description labels for spells from queries [skip ci] 2017-02-07 21:52:46 -05:00
Uleat cd11d7d1af Added dev script for function to retrieve spell category labels for spells from queries [skip ci] 2017-02-07 21:52:17 -05:00
Uleat 3d1bb6bd08 Updated SpellAffectIndex enumeration remarks [skip ci] 2017-02-06 17:48:44 -05:00
Uleat e9c1681e2c Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-06 16:35:41 -05:00
Uleat 5dbbc5f21c Added some additional SpellAffectIndex declarations to the enumeration (no reference.) Added dev script for function to retrieve spell affect index id labels for spells from queries 2017-02-06 07:14:50 -05:00
Michael Cook (mackal) ef8b4754ea Fix min damage issue 2017-02-06 00:11:26 -05:00
Uleat a13694c859 Implemented cast restrictions in GetSpellTargetTypeToken() [skip ci] 2017-02-05 22:11:02 -05:00
Uleat 51eaf25ea0 Merge branch 'master' of https://github.com/EQEmu/Server 2017-02-05 16:18:16 -05:00
Michael Cook (mackal) 592f9a9cb9 Add rule to allow non-PC pet NPCs to crit
NPCs can't crit at all ever on live
2017-02-05 13:44:04 -05:00
Uleat 409dc3ad35 Added dev script for function to retrieve body type labels from queries [skip ci] 2017-02-05 07:56:37 -05:00
Uleat f8f783fa46 Added dev script for function to retrieve spell target type labels for spells from queries [skip ci] 2017-02-05 05:01:51 -05:00
Uleat 1d1382cb12 * Added dev script for function to retrieve race id labels from queries [skip ci] 2017-02-05 04:32:32 -05:00
Uleat 68680ac9d8 Created sub-d for database tools 2017-02-05 02:37:01 -05:00
Uleat df1d499da6 Imported RoF2 race names 2017-02-05 02:20:40 -05:00
Uleat a6a056ad0d Added rest of public spell effect list. Changed unimplemented effects to "NI_"##token format [skip ci] 2017-02-04 19:52:21 -05:00
Uleat b1f14e1e29 Added dev script for function to retrieve effect id labels for spells from queries [skip ci] 2017-02-04 05:55:10 -05:00
Uleat 1999982e6a Fix for bot load buffs instrument mod. More tweaks to bot movement hack 2017-02-02 19:10:10 -05:00
Uleat b0ad9524bc Bot movement behavior change..still in-work 2017-01-31 20:17:54 -05:00
Michael Cook (mackal) d8519bc270 Weapons allow NPCs to facestab 2017-01-31 17:25:05 -05:00
Uleat da9792160d Added Mob::HasTargetReflection() 2017-01-30 17:38:17 -05:00
Uleat dc308e2ecb Fix for null columns in books.language crash 2017-01-30 03:08:00 -05:00
Uleat 984a009fbb Temp fix for bot armor color issue - may break armor dying (not tested) 2017-01-29 04:35:03 -05:00
Michael Cook (mackal) 5d61cf5bcf Bots are dumb 2017-01-28 23:21:12 -05:00
Michael Cook (mackal) 2db6464d14 Fix last commit 2017-01-28 22:46:02 -05:00
Michael Cook (mackal) c17ac67296 Tweak #showstats so bots don't skip stuff 2017-01-28 22:43:07 -05:00
Michael Cook (mackal) 37e87e8cef Rework combat to make use of a struct to fix some bugs 2017-01-28 19:38:44 -05:00
Uleat e300f82c28 Added "rooted mob" conditional to rogue bot hate redux methods 2017-01-28 16:07:58 -05:00
Uleat 05cb9d56c2 Modded 2017_01_10_book_languages.sql to eliminate error message 2017-01-27 23:17:25 -05:00
Uleat ac0cba64f9 Merge pull request #585 from noudess/master
Use languages when reading books that are in a language other than common.
2017-01-27 22:48:43 -05:00
Uleat 0b3b3fdc88 Merge branch 'master' of https://github.com/EQEmu/Server 2017-01-27 21:28:32 -05:00
Uleat 104a0998ce Added rogue evade to bot combat (nothing is every really fixed until you do it a second time and add a timer...) 2017-01-27 21:28:25 -05:00
Michael Cook (mackal) cdf0d5deb0 Fix crash 2017-01-26 18:04:59 -05:00
Uleat 36300d6df1 Removed SE_NegateIfCombat movement spells from bot commands (i.e., Scale of Wolf) 2017-01-26 17:29:39 -05:00
Uleat 3d54a4edcb Eliminated Rogue Bot twirling combat behavior. 2017-01-26 14:37:51 -05:00
Michael Cook (mackal) 31de6a63cc Fix bot frenzy 2017-01-25 21:08:59 -05:00
Uleat ae81ab8a12 Fix for obscure crash related to bots and GetNeedsCured() 2017-01-21 21:38:32 -05:00
Michael Cook (mackal) 7033d9d919 memleak fix 2017-01-21 01:47:06 -05:00
Michael Cook (mackal) 905e3acab3 Fix bots? 2017-01-20 23:27:19 -05:00
Michael Cook (mackal) 2c6e11b464 Have modify NPC stat AC/AGI recache AC 2017-01-19 23:17:14 -05:00
Michael Cook (mackal) 9aba993888 Add optional rule SQL for combat update [skip ci] 2017-01-17 23:34:52 -05:00
Michael Cook (mackal) f614c35f6e Combat Revamp -- BREAKING CHANGES -- see changelog
Changelog updated for combat revamp
2017-01-17 23:30:50 -05:00
Michael Cook (mackal) 8f21b01b7e Tweak to accuracy based on newer clients 2017-01-17 02:52:16 -05:00
Michael Cook (mackal) 591fa003c6 Merge pull request #586 from huffin/patch-1
Update 2017_01_16_NPCCombatRebalance.sql
2017-01-16 21:00:52 -05:00
huffin f3e09abf22 Update 2017_01_16_NPCCombatRebalance.sql 2017-01-16 19:33:33 -06:00
Michael Cook (mackal) 18e6e5e5e2 Rename Defense to Mitigation on sim (since that's what it is) 2017-01-16 17:05:57 -05:00
Michael Cook (mackal) 698a814fc3 Add KLS' combat sim
This will show you the distribution of hits for a given offense and mitigation

DI 1 is the min hit and DI 20 is the max hit
2017-01-16 17:02:34 -05:00
Michael Cook (mackal) fb820f4fec Add Creamo's SQL to rebalance NPCs 2017-01-16 16:58:32 -05:00
Michael Cook (mackal) 0d84a73e9f Clean up MonkSpecialAttack too 2017-01-15 22:54:50 -05:00
Michael Cook (mackal) b92d6c57a1 Rework OPCombatAbiltiy a bit
This is done to help remove some code duplication in the future
2017-01-15 22:19:32 -05:00
Michael Cook (mackal) 8c6fefa33e Update #showstats 2017-01-15 16:32:15 -05:00
Michael Cook (mackal) e03a90b05d Refactor CheckHitChance
Pulled the accuracy/avoidance spell bonuses into their own functions so
we can show the total values in #showstats
2017-01-15 16:08:22 -05:00
Michael Cook (mackal) c030e1ce8d Add rule Combat:LevelToStopDamageCaps
Setting this to 1 will effectively disable damage caps
Setting this to 20 will give similar results to old incorrect default rules
2017-01-15 15:39:12 -05:00
Michael Cook (mackal) 7e49a21b3b Change NPC skill AC bonus
Basically, live doesn't have an NPC's skill at the max for their class like we
do. So for now, we'll just set their SkillDefense bonus to value / 5
2017-01-15 13:54:10 -05:00
Michael Cook (mackal) 9e824876ba Combat Revamp - MAJOR BREAKING CHANGE
This commit makes combat much more live like. This is based on a lot of parses
done by TAKP and myself. There are numerous things based on dev quotes and
hints. Pretty much all combat has changed, spell effects correct, stacking
correct, etc.

This is the fist stage of the revamp, I will be trying to remove some code
duplication and make things generally cleaner.

Server ops will have to rebalance their NPCs. AC actually means something now.
Rough recommendations?
Level 50 "classic" trash should be no more than 115.
Classic raid mobs should be more 200+ etc
Other "classic" NPCs should be a lot lower as well.
PoP trash probably shouldn't exceed 120 AC
PoP raids should be higher
Devs have said the vast majority of NPCs didn't exceed 600 AC until very
recently. The exceptions were mostly raid encounters.

There really isn't a good "default" for every server, so this will be up to
the devs to find where they want their server stats to be.
2017-01-15 00:03:02 -05:00
Michael Cook (mackal) 891fa0411c Revert "Update travis-ci to use newer VM"
This reverts commit 0a4ccb11aa.
2017-01-12 18:25:32 -05:00
Michael Cook (mackal) a4fda2a951 Revert "Try newer GCC versions?"
This reverts commit 50a67c76e7.
2017-01-12 18:25:25 -05:00
Michael Cook (mackal) ffdc933ce0 Revert "Gotta update env vars too I guess"
This reverts commit da08a622f1.
2017-01-12 18:25:16 -05:00
Michael Cook (mackal) e3f15de1f8 Revert "Gotta set them actually"
This reverts commit 6cef5c6beb.
2017-01-12 18:25:06 -05:00
Michael Cook (mackal) 6cef5c6beb Gotta set them actually 2017-01-12 18:19:04 -05:00
Michael Cook (mackal) da08a622f1 Gotta update env vars too I guess 2017-01-12 18:10:45 -05:00
Michael Cook (mackal) 50a67c76e7 Try newer GCC versions? 2017-01-12 18:06:13 -05:00
Michael Cook (mackal) 0a4ccb11aa Update travis-ci to use newer VM 2017-01-12 17:55:08 -05:00
Paul Coene af4a432745 Missed version.h in original commit 2017-01-10 20:33:01 -05:00
Paul Coene df86e644f4 Now the actual code changes - lol 2017-01-10 20:18:16 -05:00
Paul Coene 80ff535215 Added code so that books/scrolls read that are in a language other
than common get language skill applied.

Added code to support ReadBook slots above and beyond main inventory slots
by decoding additional bag slot field.
2017-01-10 20:15:03 -05:00
Akkadius 30157a37a2 Merge pull request #583 from noudess/master
Alliance spell line for chanters was not working.
2017-01-10 14:09:02 -06:00
Michael Cook (mackal) f5827174ee Make CheckHitChance much more live like
This should be fairly close to live-like.

Based on client decompiling, Torven's write up and parses and more parses.

It will probably break your server.
2016-12-25 21:11:10 -05:00
Michael Cook (mackal) 1d19bd11d0 Add Random::Roll0
This has the same interval ((0,N]) that the client function does
The devs have referenced this in a few posts talking about
mechanics.
2016-12-25 21:06:02 -05:00
Paul Coene 6a2be94282 Alliance spell line for chanters was not working. 2016-12-21 14:38:24 -05:00
Michael Cook (mackal) 630ea0d3c6 Fix RoF2 OP_GMHideMe 2016-12-21 13:45:18 -05:00
131 changed files with 25059 additions and 4872 deletions
+159 -20
View File
@@ -1,5 +1,144 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 03/12/2017 ==
Akkadius:
- Implemented range rules for packets and other functions
RULE_INT ( Range, Say, 135 )
RULE_INT ( Range, Emote, 135 )
RULE_INT ( Range, BeginCast, 200)
RULE_INT ( Range, Anims, 135)
RULE_INT ( Range, SpellParticles, 135)
RULE_INT ( Range, DamageMessages, 50)
RULE_INT ( Range, SpellMessages, 75)
RULE_INT ( Range, SongMessages, 75)
RULE_INT ( Range, MobPositionUpdates, 600)
RULE_INT ( Range, CriticalDamage, 80)
- (Readability) Also cleaned up some formatting in messaging and packets so it is easier to understand what is going on with the code
== 03/09/2017 ==
Uleat: Fixed a few glitches related to bot trading and other affected code
- Added a temporary fail clause for partial stack transfers to prevent client item overwrites
- Return messages no longer repeat the top cursor item when multiple items are pushed there
- Test slot for client returns is now handled appropriately for parent and bag searches
- FindFreeSlotForTradeItem() now begins at the correct bag index on subsequent parent iterations
Uleat: First step of implementing inventory v2.0
== 03/08/2017 ==
Uleat: Complete rework of the bot trading system
- Equipment slot priority can now be tailored..though, a recompile will be required
- All item validations and slot assignments for trades and returns are now performed before any actual item movements occur
- Failed trade/returned items will now go straight into the client's inventory, just like a normal trade transaction
- A 'green' message appears at the end of each successful trade informing the trader of 'accepted' and 'returned' item counts
- Bots respond to the trader directly now instead of using BotGroupSay()
- Bots will still only allow trades from their owner (currently, too high a risk of exploit and/or malicious activity)
- Partial stack movements (i.e., ammo refills) have been scoped..but, not implemented
- I have not been able to reproduce any 'illegal' weapon combinations with this code
- NOTE: The report of item duplication with bot return items appears to be an inventory desync condition
- I experienced this condition both before and after the rework with RoF+ clients (UF- appears ok)
- The bug lies within the actual client inventory system and not with bot trades
- Please post any issues with this change as they arise
== 02/27/2017 ==
Uleat: Notes on bot movement speed changes:
- Clients (players) appear to be on a different speed scale than other entities (NPCs, etc...)
- The server does not calculate deltas/velocities for moving players..those come the client itself
- GetBotWalkspeed() and GetBotRunspeed() are specific to bot movement calculations
- The class Mob equivilents are not scalared so that a 'client-oriented' value can still be attained
- The value of ~1.786f is derived from the ratio of 1.25f/0.7f (npc speed/client speed)
- Modifying the two speeds like this is a rough guess-timate..but, appears to at least bring the incongruous behavior to acceptable levels
== 02/26/2017 ==
Uleat: Moved bot `npc_spells` entries from '701-712' to 3000 + <class_id> .. also, added melee types for future expansion
Uleat: Moved bot spell casting chance values into database - this will allow admins to tailor their bots without having to rebuild server code
- Each entry uses a 3-dimensional identifier: [spell type index][class id][stance index]
- [spell type index] is not the SpellType_## bit value..use SpellType_##Index instead
- [class id] values of 1-16 are valid and hold a direct correlation to server-coded player class values
- [stance index] is a direct correlation (0-6)
- the 'conditional fields' are currently predicated on 4 compounded boolean states:
- `pH_value` represents bit '0'
- `pS_value` represents bit '1'
- `pN_value` represents bit '2'
- `pD_value` represents bit '3'
- all other conditional fields are masked based on these 4 predicates
- the full conditional field enumeration is as follows:
- `nHSND_value` - negative Healer/Slower/Nuker/Doter
- `pH_value` - positive Healer
- `pS_value` - positive Slower
- `pHS_value` - positive Healer/Slower
- `pN_value` - positive Nuker
- `pHN_value` - positive Healer/Nuker
- `pSN_value` - positive Slower/Nuker
- `pHSN_value` - positive Healer/Slower/Nuker
- `pD_value` - positive Doter
- `pHD_value` - positive Healer/Doter
- `pSD_value` - positive Slower/Doter
- `pHSD_value` - positive Healer/Slower/Doter
- `pND_value` - positive Nuker/Doter
- `pHND_value` - positive Healer/Nuker/Doter
- `pSND_value` - positive Slower/Nuker/Doter
- `pHSND_value` - positive Healer/Slower/Nuker/Doter
- Single- and mixed-bits fields should be filled-in based on the boolean 'AND' concept
- (i.e., if 'healer' then `pH_value`=x; if 'slower' then `pS_value`=y; if 'healer' AND 'slower' then `pHS_value`=z; )
- most cases can allow the same value across all fields..but, there are some that shouldn't and this format allows for their discrimination
- Valid `##_value` entries are 0-100..though, the field accepts up to 255... Anything above 100 is clamped to 100 upon loading, however...
- Not all conditions are currently coded and changing a field may not produce any results
- The 'default' database values will be changed and tweaked as bot spell code modifications occur
== 02/25/2017 ==
Uleat: Implemented rule-based node pathing for bots
- This currently applies to out-of-combat following movement and blocked los in-combat movement
- The default is set to 'true' (use node pathing)..so, consider disabling it if cpu use is too high
- If you want to disable node pathing, apply the optional sql '2017_02_25_bots_use_pathing_rule.sql' file located in the utils/sql/git/bots/optional sub-directory. This will apply a 'false' rule..but, it can be changed as desired
- This helps with bot movement..but, there are still issues...
Uleat: Implemented rule-based position update packet with movement timer check for bots
- This currently only applies to out-of-combat movement
- The default is set to 'false' (original behavior) to help save bandwidth (each bot will send an update packet every 1/10th of a second when enabled)
- If you want to enable the position update packet, apply the optional sql '2017_02_25_bots_update_position_with_timer_rule.sql' file located in the utils/sql/git/bots/optional sub-directory. This will apply a 'true' rule..but, it can be changed as desired
- This appears to help with/eliminate rubber banding
== 02/23/2017 ==
** THIS NOTE HAS BEEN SUPERCEDED ON 02/26/2017 **
Uleat: Moved bot spell casting chance values into database - this will allow admins to tailor their bots without having to rebuild server code
- Each entry uses a 4-dimensional identifier: [spell type index][class index][stance index][conditional index]
- [spell type index] is not the SpellType_## bit value..use SpellType_##Index instead
- [class index] values of 0-15 are valid and determined by subtracting 1 from the actual class value
- [stance index] is a direct correlation (0-6)
- the [conditional index] is currently predicated on 2 compounded boolean states:
- not primary healer/not primary slower: 0
- primary healer/not primary slower: 1
- not primary healer/ primary slower: 2
- primary healer/primary slower: 3
- Valid `value` entries are 0-100..though, the field accepts up to 255... Anything above 100 is clamped to 100 upon loading, however
- Not all conditions are currently coded and changing a field may not produce any results
- The 'default' database values will be changed and tweaked as bot spell code modifications occur
== 02/20/2017 ==
Uleat: Reworked bard bot spell twisting and updated their spell (song) list
Uleat: Added ability to shift to pre-combat song buffing by selecting a non-pet npc target, eliminating the need to mix all bard buff songs together
== 2/19/2017 ==
Akkadius: Added a fix for limiting the amount of items sold in a stack when the resulting return coin is higher than the supporting struct for returning coin
== 01/31/2017 ==
Uleat: Modifed bot movement behavior in an attempt to 'normalize' it. This is a hack fix and will be revisited at some point. (Probably just need a follow function rather than use movement, when the leader of the follow chain is moving.)
== 01/26/2017 ==
Uleat: Change rogue bot behavior to eliminate twirling combat. They will only get behind the mob if they are not the mob's target or if the mob is feared or fleeing. This may lower rogue bot dps a small fraction..but, is more in-line with realistic game mechanics.
== 01/17/2017 ==
Mackal: Combat Revamp
- This change brings melee combat into line with how combat is done on live.
- This correctly applies the PC damage tables and corrects stacking order of many spells
- Given the scope of what had to be rewritten, it was not feasible to preserve the old combat system.
This means you will likely have to rebalance your server, which sucks, but this is very
accurate so shouldn't require any more changes, at least none that would cause you to have
to rebalance your server again.
- For rebalancing, I would recommend running the optional SQL and tweaking from there.
- To help with rebalancing there is a simulator included at utils/combat-sim.
- You can enter the mitigation or offense values you would like to balance around (#showstats will show you them)
a 1 on the sim is min damage 20 is max.
- Quick recommendations for best ways to improve PC DPS, give them some worn (or AA) SE_DamageModifier and/or SE_MinDamageModifier
== 12/03/2016 ==
Uleat: Added hack detection to trade code
- If illegal items are found in trade slots when the 'trade' button is clicked, the trade is cancelled and a message is sent to the offending player
@@ -28,7 +167,7 @@ take into account that rogue was sneaking. Now sneaking rogues can see full
inventory on merchants (well, unless an item requires a + faction value).
== 09/12/2016 ==
Akkadius: Massive overhaul of the update system and EQEmu Server management utility framework
Akkadius: Massive overhaul of the update system and EQEmu Server management utility framework
(known as eqemu_update.pl) now known as eqemu_server.pl
- eqemu_server.pl is now a general EQEmu Server management utiltiy framework that can be used
to extend to many purposes. It's main purpose is to simplify server management
@@ -49,7 +188,7 @@ Akkadius: Massive overhaul of the update system and EQEmu Server management util
- Regular bots database schema changes now happen automatically similarily to the above
- Database checks can also be ran manually via the script menu
- CLI Arguments
- Arguments passed to eqemu_server.pl can execute the same name-based operations that
- Arguments passed to eqemu_server.pl can execute the same name-based operations that
are present in the interactive menu
- Example: "perl eqemu_server.pl opcodes" will download opcodes
- Example: "perl eqemu_server.pl backup_player_tables" will backup and export player tables
@@ -64,7 +203,7 @@ Akkadius: Massive overhaul of the update system and EQEmu Server management util
- server_start_dev.sh
- server_start.sh
- server_status.sh
- server_stop.sh
- server_stop.sh
- Usage analytics
- eqemu_server.pl now collects usage analytics, this is very helpful for our developers
- Example: We can see how many installs have been performed:
@@ -76,10 +215,10 @@ Akkadius: Massive overhaul of the update system and EQEmu Server management util
- 'New Server' Utility
- Running 'new_server' from the main menu or 'perl eqemu_server.pl new_server' while in
a completely new folder with just the script present, will allow a server operator
to initiate a full clean PEQ install in that folder. Pulling down all assets and
installing a PEQ database with the name the server operator gives the prompts in the
to initiate a full clean PEQ install in that folder. Pulling down all assets and
installing a PEQ database with the name the server operator gives the prompts in the
script
== 09/10/2016 ==
noudess: Task system experience based on a % of a level did not take into
account the hell levels rule. Now it does.
@@ -133,7 +272,7 @@ Kinglykrab: Implemented optional avoidance cap rules.
- 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%)
@@ -171,7 +310,7 @@ mackal: Fix up the SpellBuff struct
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)
- 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.
@@ -240,7 +379,7 @@ Uleat: Moved database query code out of bot.cpp and into the new BotDatabase cla
== 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).
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 ==
@@ -283,7 +422,7 @@ Kinglykrab: Modified #flag so you can refresh your target's account status (GM s
- 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.
@@ -313,7 +452,7 @@ Kinglykrab: Added GetInstanceTimer() 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
@@ -322,7 +461,7 @@ Natedog: Updated item table fields and added a few missing fields for evolving i
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()
@@ -344,7 +483,7 @@ Kinglykrab: Added many methods to Perl and Lua, list below:
- 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.
@@ -353,7 +492,7 @@ 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`
@@ -366,7 +505,7 @@ Uleat: Command aliases are no longer handled through the command_add() function.
- 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 ==
@@ -388,7 +527,7 @@ Akkadius: Performance boost (exponential) - Adjusted default idle cast check tim
- 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
- 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)
@@ -396,7 +535,7 @@ Akkadius: Performance boost (exponential) - Adjusted default idle cast check tim
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
- 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()
@@ -424,7 +563,7 @@ Akkadius: Added Perl Export Settings which should heavily reduce the Perl footpr
| 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:
@@ -433,7 +572,7 @@ Akkadius: Added Perl Export Settings which should heavily reduce the Perl footpr
(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 [ <target> | spawned | all ]' to coincide with the activation of the load/save feature for follow_distance
@@ -465,7 +604,7 @@ rules:
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.
+1
View File
@@ -307,6 +307,7 @@ bool Database::DeleteCharacter(char *name) {
query = StringFormat("DELETE FROM `quest_globals` WHERE `charid` = '%d'", charid); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_activities` WHERE `charid` = '%d'", charid); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_enabledtasks` WHERE `charid` = '%d'", charid); QueryDatabase(query);
query = StringFormat("DELETE FROM `character_tasks` WHERE `charid` = '%d'", charid); QueryDatabase(query);
query = StringFormat("DELETE FROM `completed_tasks` WHERE `charid` = '%d'", charid); QueryDatabase(query);
query = StringFormat("DELETE FROM `friends` WHERE `charid` = '%d'", charid); QueryDatabase(query);
query = StringFormat("DELETE FROM `mail` WHERE `charid` = '%d'", charid); QueryDatabase(query);
+3
View File
@@ -25,6 +25,9 @@ N(OP_AdventureRequest),
N(OP_AdventureStatsReply),
N(OP_AdventureStatsRequest),
N(OP_AdventureUpdate),
N(OP_AggroMeterLockTarget),
N(OP_AggroMeterTargetInfo),
N(OP_AggroMeterUpdate),
N(OP_AltCurrency),
N(OP_AltCurrencyMerchantReply),
N(OP_AltCurrencyMerchantRequest),
+2
View File
@@ -2243,6 +2243,7 @@ struct GroupFollow_Struct { // SoF Follow Struct
/*0132*/
};
// this is generic struct
struct GroupLeaderChange_Struct
{
/*000*/ char Unknown000[64];
@@ -2495,6 +2496,7 @@ struct BookRequest_Struct {
uint8 window; // where to display the text (0xFF means new window)
uint8 type; //type: 0=scroll, 1=book, 2=item info.. prolly others.
uint32 invslot; // Only used in Sof and later clients;
int16 subslot; // The subslot inside of a bag if it is inside one.
char txtfile[20];
};
+25 -32
View File
@@ -123,26 +123,21 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
std::string EQEmuLogSys::FormatOutMessageString(uint16 log_category, const std::string &in_message)
{
std::string category_string;
if (log_category > 0 && Logs::LogCategoryName[log_category])
category_string = StringFormat("[%s] ", Logs::LogCategoryName[log_category]);
return StringFormat("%s%s", category_string.c_str(), in_message.c_str());
std::string ret;
ret.push_back('[');
ret.append(Logs::LogCategoryName[log_category]);
ret.push_back(']');
ret.push_back(' ');
ret.append(in_message);
return ret;
}
void EQEmuLogSys::ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message)
{
/* Check if category enabled for process */
if (log_settings[log_category].log_to_gmsay == 0)
return;
/* Enabling Netcode based GMSay output creates a feedback loop that ultimately ends in a crash */
if (log_category == Logs::LogCategory::Netcode)
return;
/* Make sure the message inbound is at a debug level we're set at */
if (log_settings[log_category].log_to_gmsay < debug_level)
return;
/* Check to see if the process that actually ran this is zone */
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone)
on_log_gmsay_hook(log_category, message);
@@ -160,14 +155,6 @@ void EQEmuLogSys::ProcessLogWrite(uint16 debug_level, uint16 log_category, const
crash_log.close();
}
/* Check if category enabled for process */
if (log_settings[log_category].log_to_file == 0)
return;
/* Make sure the message inbound is at a debug level we're set at */
if (log_settings[log_category].log_to_file < debug_level)
return;
char time_stamp[80];
EQEmuLogSys::SetCurrentTimeStamp(time_stamp);
@@ -246,13 +233,6 @@ uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category) {
void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message)
{
/* Check if category enabled for process */
if (log_settings[log_category].log_to_console == 0)
return;
/* Make sure the message inbound is at a debug level we're set at */
if (log_settings[log_category].log_to_console < debug_level)
return;
#ifdef _WINDOWS
HANDLE console_handle;
@@ -273,12 +253,25 @@ void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category,
void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::string message, ...)
{
const bool log_to_console = log_settings[log_category].log_to_console > 0;
const bool log_to_file = log_settings[log_category].log_to_file > 0;
const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0;
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay;
if (nothing_to_log) return;
bool log_to_console = true;
if (log_settings[log_category].log_to_console < debug_level) {
log_to_console = false;
}
bool log_to_file = true;
if (log_settings[log_category].log_to_file < debug_level) {
log_to_file = false;
}
bool log_to_gmsay = true;
if (log_settings[log_category].log_to_gmsay < debug_level) {
log_to_gmsay = false;
}
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay;
if (nothing_to_log)
return;
va_list args;
va_start(args, message);
+3
View File
@@ -235,6 +235,9 @@ enum { //some random constants
#define ZONE_CONTROLLER_NPC_ID 10
// Timer to update aggrometer
#define AGGRO_METER_UPDATE_MS 1000
//Some hard coded statuses from commands and other places:
enum {
minStatusToBeGM = 40,
+22 -13
View File
@@ -635,18 +635,23 @@ int16 EQEmu::InventoryProfile::FindFreeSlot(bool for_bag, bool try_cursor, uint8
}
// This is a mix of HasSpaceForItem and FindFreeSlot..due to existing coding behavior, it was better to add a new helper function...
int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst) {
int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start, uint8 bag_start) {
// Do not arbitrarily use this function..it is designed for use with Client::ResetTrade() and Client::FinishTrade().
// If you have a need, use it..but, understand it is not a compatible replacement for InventoryProfile::FindFreeSlot().
// If you have a need, use it..but, understand it is not a suitable replacement for InventoryProfile::FindFreeSlot().
//
// I'll probably implement a bitmask in the new inventory system to avoid having to adjust stack bias
if ((general_start < legacy::GENERAL_BEGIN) || (general_start > legacy::GENERAL_END))
return INVALID_INDEX;
if (bag_start >= inventory::ContainerCount)
return INVALID_INDEX;
if (!inst || !inst->GetID())
return INVALID_INDEX;
// step 1: find room for bags (caller should really ask for slots for bags first to avoid sending them to cursor..and bag item loss)
if (inst->IsClassBag()) {
for (int16 free_slot = legacy::GENERAL_BEGIN; free_slot <= legacy::GENERAL_END; ++free_slot) {
for (int16 free_slot = general_start; free_slot <= legacy::GENERAL_END; ++free_slot) {
if (!m_inv[free_slot])
return free_slot;
}
@@ -656,7 +661,7 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
// step 2: find partial room for stackables
if (inst->IsStackable()) {
for (int16 free_slot = legacy::GENERAL_BEGIN; free_slot <= legacy::GENERAL_END; ++free_slot) {
for (int16 free_slot = general_start; free_slot <= legacy::GENERAL_END; ++free_slot) {
const ItemInstance* main_inst = m_inv[free_slot];
if (!main_inst)
@@ -666,14 +671,15 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
return free_slot;
}
for (int16 free_slot = legacy::GENERAL_BEGIN; free_slot <= legacy::GENERAL_END; ++free_slot) {
for (int16 free_slot = general_start; free_slot <= legacy::GENERAL_END; ++free_slot) {
const ItemInstance* main_inst = m_inv[free_slot];
if (!main_inst)
continue;
if (main_inst->IsClassBag()) { // if item-specific containers already have bad items, we won't fix it here...
for (uint8 free_bag_slot = inventory::containerBegin; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
uint8 _bag_start = (free_slot > general_start) ? inventory::containerBegin : bag_start;
for (uint8 free_bag_slot = _bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
const ItemInstance* sub_inst = main_inst->GetItem(free_bag_slot);
if (!sub_inst)
@@ -688,13 +694,14 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
// step 3a: find room for container-specific items (ItemClassArrow)
if (inst->GetItem()->ItemType == item::ItemTypeArrow) {
for (int16 free_slot = legacy::GENERAL_BEGIN; free_slot <= legacy::GENERAL_END; ++free_slot) {
for (int16 free_slot = general_start; free_slot <= legacy::GENERAL_END; ++free_slot) {
const ItemInstance* main_inst = m_inv[free_slot];
if (!main_inst || (main_inst->GetItem()->BagType != item::BagTypeQuiver) || !main_inst->IsClassBag())
continue;
for (uint8 free_bag_slot = inventory::containerBegin; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
uint8 _bag_start = (free_slot > general_start) ? inventory::containerBegin : bag_start;
for (uint8 free_bag_slot = _bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
if (!main_inst->GetItem(free_bag_slot))
return InventoryProfile::CalcSlotId(free_slot, free_bag_slot);
}
@@ -703,13 +710,14 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
// step 3b: find room for container-specific items (ItemClassSmallThrowing)
if (inst->GetItem()->ItemType == item::ItemTypeSmallThrowing) {
for (int16 free_slot = legacy::GENERAL_BEGIN; free_slot <= legacy::GENERAL_END; ++free_slot) {
for (int16 free_slot = general_start; free_slot <= legacy::GENERAL_END; ++free_slot) {
const ItemInstance* main_inst = m_inv[free_slot];
if (!main_inst || (main_inst->GetItem()->BagType != item::BagTypeBandolier) || !main_inst->IsClassBag())
continue;
for (uint8 free_bag_slot = inventory::containerBegin; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
uint8 _bag_start = (free_slot > general_start) ? inventory::containerBegin : bag_start;
for (uint8 free_bag_slot = _bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
if (!main_inst->GetItem(free_bag_slot))
return InventoryProfile::CalcSlotId(free_slot, free_bag_slot);
}
@@ -717,21 +725,22 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
}
// step 4: just find an empty slot
for (int16 free_slot = legacy::GENERAL_BEGIN; free_slot <= legacy::GENERAL_END; ++free_slot) {
for (int16 free_slot = general_start; free_slot <= legacy::GENERAL_END; ++free_slot) {
const ItemInstance* main_inst = m_inv[free_slot];
if (!main_inst)
return free_slot;
}
for (int16 free_slot = legacy::GENERAL_BEGIN; free_slot <= legacy::GENERAL_END; ++free_slot) {
for (int16 free_slot = general_start; free_slot <= legacy::GENERAL_END; ++free_slot) {
const ItemInstance* main_inst = m_inv[free_slot];
if (main_inst && main_inst->IsClassBag()) {
if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == item::BagTypeBandolier) || (main_inst->GetItem()->BagType == item::BagTypeQuiver))
continue;
for (uint8 free_bag_slot = inventory::containerBegin; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
uint8 _bag_start = (free_slot > general_start) ? inventory::containerBegin : bag_start;
for (uint8 free_bag_slot = _bag_start; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < inventory::ContainerCount); ++free_bag_slot) {
if (!main_inst->GetItem(free_bag_slot))
return InventoryProfile::CalcSlotId(free_slot, free_bag_slot);
}
+1 -1
View File
@@ -155,7 +155,7 @@ namespace EQEmu
// Locate an available inventory slot
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
int16 FindFreeSlotForTradeItem(const ItemInstance* inst);
int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = legacy::GENERAL_BEGIN, uint8 bag_start = inventory::containerBegin);
// Calculate slot_id for an item within a bag
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
+19 -1
View File
@@ -195,7 +195,7 @@ bool EQEmu::ItemData::IsClassBook() const
bool EQEmu::ItemData::IsType1HWeapon() const
{
return ((ItemType == item::ItemType1HBlunt) || (ItemType == item::ItemType1HSlash) || (ItemType == item::ItemType1HPiercing));
return ((ItemType == item::ItemType1HBlunt) || (ItemType == item::ItemType1HSlash) || (ItemType == item::ItemType1HPiercing) || (ItemType == item::ItemTypeMartial));
}
bool EQEmu::ItemData::IsType2HWeapon() const
@@ -207,3 +207,21 @@ bool EQEmu::ItemData::IsTypeShield() const
{
return (ItemType == item::ItemTypeShield);
}
bool EQEmu::ItemData::CheckLoreConflict(const ItemData* l_item, const ItemData* r_item)
{
if (!l_item || !r_item)
return false;
if (!l_item->LoreGroup || !r_item->LoreGroup)
return false;
if (l_item->LoreGroup == r_item->LoreGroup) {
if ((l_item->LoreGroup == -1) && (l_item->ID != r_item->ID))
return false;
return true;
}
return false;
}
+3
View File
@@ -538,6 +538,9 @@ namespace EQEmu
bool IsType1HWeapon() const;
bool IsType2HWeapon() const;
bool IsTypeShield() const;
static bool CheckLoreConflict(const ItemData* l_item, const ItemData* r_item);
bool CheckLoreConflict(const ItemData* item) const { return CheckLoreConflict(this, item); }
};
} /*EQEmu*/
+21 -20
View File
@@ -1182,17 +1182,17 @@ namespace RoF2
// Leader
//
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_STRING(Buffer, gu2->yourname);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // index
VARSTRUCT_ENCODE_STRING(Buffer, gu2->yourname); // name
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0); // owner name of merc
//VARSTRUCT_ENCODE_STRING(Buffer, "");
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x46); // Observed 0x41 and 0x46 here
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x46); // level
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group tank flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group assist flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group puller flag
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // offline
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // timestamp
int MemberNumber = 1;
@@ -1201,17 +1201,17 @@ namespace RoF2
if (gu2->membername[i][0] == '\0')
continue;
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, MemberNumber++);
VARSTRUCT_ENCODE_STRING(Buffer, gu2->membername[i]);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, MemberNumber++); // index
VARSTRUCT_ENCODE_STRING(Buffer, gu2->membername[i]); // name
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0); // merc flag
//VARSTRUCT_ENCODE_STRING(Buffer, "");
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x41); // Observed 0x41 and 0x46 here
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // Low byte is Main Assist Flag
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // owner name fo merc
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0x41); // level
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group tank flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group assist flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group puller flag
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // offline
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // timestamp
}
//Log.Hex(Logs::Netcode, outapp->pBuffer, outapp->size);
@@ -5154,6 +5154,7 @@ namespace RoF2
IN(type);
IN(invslot);
IN(subslot);
emu->window = (uint8)eq->window;
strn0cpy(emu->txtfile, eq->txtfile, sizeof(emu->txtfile));
+7 -3
View File
@@ -2566,9 +2566,12 @@ struct GroupJoin_Struct_Live { // New for Live
};
struct GroupJoin_Struct {
/*000*/ char unknown000[64];
/*000*/ char owner_name[64]; // merc
/*064*/ char membername[64];
/*128*/ uint8 unknown128[20]; // Leadership AA ?
/*128*/ uint8 merc;
/*129*/ uint8 padding129[3];
/*132*/ uint32 level;
/*136*/ uint8 unknown136[12]; // group ID most likely in here judging from like captures (unused by client)
/*148*/
};
@@ -2826,7 +2829,8 @@ struct BookText_Struct {
struct BookRequest_Struct {
/*0000*/ uint32 window; // where to display the text (0xFFFFFFFF means new window).
/*0004*/ uint16 invslot; // Is the slot, but the RoF2 conversion causes it to fail. Turned to 0 since it isnt required anyway.
/*0008*/ uint32 unknown006; // Seen FFFFFFFF
/*0006*/ int16 subslot; // Inventory sub-slot (0-x)
/*0008*/ uint16 unknown006; // Seen FFFF
/*0010*/ uint16 unknown008; // seen 0000
/*0012*/ uint32 type; // 0 = Scroll, 1 = Book, 2 = Item Info. Possibly others
/*0016*/ uint32 unknown0012;
+1316 -43
View File
File diff suppressed because it is too large Load Diff
+735
View File
@@ -113,6 +113,741 @@
#define PLAYER_RACE_ALL_MASK 65535
#define RT_ABHORRENT 193
#define RT_AIR_ELEMENTAL 210
#define RT_AIR_ELEMENTAL_2 475
#define RT_AIR_MEPHIT 291
#define RT_AKHEVA 230
#define RT_AKHEVA_2 722
#define RT_ALARAN 695
#define RT_ALARAN_GHOST 708
#define RT_ALARAN_SENTRY_STONE 703
#define RT_ALLIGATOR 91
#define RT_ALLIGATOR_2 479
#define RT_AMYGDALAN 99
#define RT_AMYGDALAN_2 663
#define RT_ANEUK 395
#define RT_ANIMATED_ARMOR 323
#define RT_ANIMATED_HAND 166
#define RT_ANIMATED_STATUE 442
#define RT_ANIMATED_STATUE_2 448
#define RT_APEXUS 637
#define RT_ARACHNID 326
#define RT_ARCANIST_OF_HATE 352
#define RT_ARMADILLO 87
#define RT_ARMOR_RACK 535
#define RT_AVIAK 13
#define RT_AVIAK_2 558
#define RT_AVIAK_PULL_ALONG 711
#define RT_AYONAE_RO 498
#define RT_BANNER 500
#define RT_BANNER_2 553
#define RT_BANNER_3 554
#define RT_BANNER_4 555
#define RT_BANNER_5 556
#define RT_BANNER_6 557
#define RT_BANNER_7 586
#define RT_BANNER_10TH_ANNIVERSARY 628
#define RT_BANSHEE 250
#define RT_BANSHEE_2 487
#define RT_BANSHEE_3 488
#define RT_BARBARIAN 2
#define RT_BARBARIAN_2 90
#define RT_BARREL 377
#define RT_BARREL_BARGE_SHIP 546
#define RT_BASILISK 436
#define RT_BAT 34
#define RT_BAT_2 260
#define RT_BAT_3 416
#define RT_BAZU 409
#define RT_BEAR 43
#define RT_BEAR_2 305
#define RT_BEAR_3 480
#define RT_BEAR_MOUNT 655
#define RT_BEAR_TRAP 503
#define RT_BEETLE 22
#define RT_BEETLE_2 559
#define RT_BEETLE_3 716
#define RT_BEGGAR 55
#define RT_BELLIKOS 638
#define RT_BERTOXXULOUS 152
#define RT_BERTOXXULOUS_2 255
#define RT_BIXIE 79
#define RT_BIXIE_2 520
#define RT_BLIMP_SHIP 693
#define RT_BLIND_DREAMER 669
#define RT_BLOOD_RAVEN 279
#define RT_BOAT 141
#define RT_BOAT_2 533
#define RT_BOLVIRK 486
#define RT_BONE_GOLEM 362
#define RT_BONE_GOLEM_2 491
#define RT_BONES 383
#define RT_BOOK_DERVISH 660
#define RT_BOT_PORTAL 329
#define RT_BOULDER 585
#define RT_BOX 376
#define RT_BRAXI 688
#define RT_BRAXI_MOUNT 676
#define RT_BRELL 640
#define RT_BRELLS_FIRST_CREATION 639
#define RT_BRISTLEBANE 153
#define RT_BROKEN_CLOCKWORK 274
#define RT_BRONTOTHERIUM 169
#define RT_BROWNIE 15
#define RT_BROWNIE_2 568
#define RT_BUBONIAN 268
#define RT_BUBONIAN_UNDERLING 269
#define RT_BURYNAI 144
#define RT_BURYNAI_2 602
#define RT_CAKE_10TH_ANNIVERSARY 629
#define RT_CAMPFIRE 567
#define RT_CARRIER_HAND 721
#define RT_CAT 713
#define RT_CAZIC_THULE 95
#define RT_CAZIC_THULE_2 670
#define RT_CENTAUR 16
#define RT_CENTAUR_2 521
#define RT_CHEST 378
#define RT_CHEST_2 589
#define RT_CHEST_3 590
#define RT_CHIMERA 412
#define RT_CHIMERA_2 582
#define RT_CHOKIDAI 356
#define RT_CLAM 115
#define RT_CLIKNAR_MOUNT 652
#define RT_CLIKNAR_QUEEN 642
#define RT_CLIKNAR_SOLDIER 643
#define RT_CLIKNAR_WORKER 644
#define RT_CLOCKWORK_BEETLE 276
#define RT_CLOCKWORK_BOAR 472
#define RT_CLOCKWORK_BOMB 504
#define RT_CLOCKWORK_BRAIN 249
#define RT_CLOCKWORK_GNOME 88
#define RT_CLOCKWORK_GOLEM 248
#define RT_CLOCKWORK_GUARDIAN 572
#define RT_COCKATRICE 96
#define RT_COFFIN 382
#define RT_COFFIN_2 592
#define RT_COIN_PURSE 427
#define RT_COLDAIN 183
#define RT_COLDAIN_2 645
#define RT_COLDAIN_3 646
#define RT_CORAL 460
#define RT_CORATHUS 459
#define RT_CRAB 302
#define RT_CRAGBEAST 390
#define RT_CRAGSLITHER 597
#define RT_CROCODILE 259
#define RT_CRYSTAL 591
#define RT_CRYSTAL_SHARD 425
#define RT_CRYSTAL_SPHERE 616
#define RT_CRYSTAL_SPIDER 327
#define RT_CRYSTALSKIN_AMBULOID 641
#define RT_CRYSTALSKIN_SESSILOID 647
#define RT_DAISY_MAN 97
#define RT_DARK_ELF 6
#define RT_DARK_ELF_2 77
#define RT_DARK_LORD 466
#define RT_DEMI_LICH 45
#define RT_DEMON_VULTURE 620
#define RT_DERVISH 100
#define RT_DERVISH_2 372
#define RT_DERVISH_3 431
#define RT_DERVISH_4 704
#define RT_DERVISH_VER_5 726
#define RT_DERVISH_VER_6 727
#define RT_DEVOURER 159
#define RT_DIRE_WOLF 171
#define RT_DISCORD_SHIP 404
#define RT_DISCORDLING 418
#define RT_DISEASED_FIEND 253
#define RT_DJINN 126
#define RT_DRACHNID 57
#define RT_DRACHNID_2 461
#define RT_DRACHNID_COCOON 462
#define RT_DRACOLICH 604
#define RT_DRAGLOCK 132
#define RT_DRAGON 49
#define RT_DRAGON_2 122
#define RT_DRAGON_3 165
#define RT_DRAGON_4 184
#define RT_DRAGON_5 192
#define RT_DRAGON_6 195
#define RT_DRAGON_7 196
#define RT_DRAGON_8 198
#define RT_DRAGON_9 304
#define RT_DRAGON_10 435
#define RT_DRAGON_11 437
#define RT_DRAGON_12 438
#define RT_DRAGON_13 452
#define RT_DRAGON_14 530
#define RT_DRAGON_15 531
#define RT_DRAGON_16 569
#define RT_DRAGON_BONES 423
#define RT_DRAGON_EGG 445
#define RT_DRAGON_STATUE 446
#define RT_DRAGORN 413
#define RT_DRAGORN_BOX 421
#define RT_DRAKE 89
#define RT_DRAKE_2 430
#define RT_DRAKE_3 432
#define RT_DRAKKIN 522
#define RT_DRIXIE 113
#define RT_DROGMORE 348
#define RT_DROLVARG 133
#define RT_DRYAD 243
#define RT_DWARF 8
#define RT_DWARF_2 94
#define RT_DYNAMITE_KEG 505
#define RT_DYNLETH 532
#define RT_EARTH_ELEMENTAL 209
#define RT_EARTH_ELEMENTAL_2 476
#define RT_EARTH_MEPHIT 292
#define RT_EEL 35
#define RT_EFREETI 101
#define RT_EFREETI_2 320
#define RT_ELDDAR 489
#define RT_ELEMENTAL 75
#define RT_ELK_HEAD 714
#define RT_ELVEN_BOAT 544
#define RT_ELVEN_GHOST 587
#define RT_ENCHANTED_ARMOR 175
#define RT_EROLLISI 150
#define RT_ERUDITE 3
#define RT_ERUDITE_2 78
#define RT_ERUDITE_3 678
#define RT_EVAN_TEST 204
#define RT_EVIL_EYE 21
#define RT_EVIL_EYE_2 375
#define RT_EVIL_EYE_3 469
#define RT_EXOSKELETON 570
#define RT_EXPLOSIVE_CART 692
#define RT_EYE 108
#define RT_FAIRY 25
#define RT_FAIRY_2 473
#define RT_FALLEN_KNIGHT 719
#define RT_FAUN 182
#define RT_FAY_DRAKE 154
#define RT_FENNIN_RO 284
#define RT_FERAN 410
#define RT_FERAN_MOUNT 623
#define RT_FIEND 300
#define RT_FIRE_ELEMENTAL 212
#define RT_FIRE_ELEMENTAL_2 477
#define RT_FIRE_MEPHIT 293
#define RT_FISH 24
#define RT_FISH_2 148
#define RT_FLAG 501
#define RT_FLOATING_ISLAND 596
#define RT_FLOATING_SKULL 512
#define RT_FLOATING_TOWER 691
#define RT_FLY 245
#define RT_FLYING_CARPET 720
#define RT_FOREST_GIANT 490
#define RT_FROG 343
#define RT_FROG_2 603
#define RT_FROGLOK 26
#define RT_FROGLOK_2 27
#define RT_FROGLOK_3 330
#define RT_FROGLOK_GHOST 371
#define RT_FROGLOK_SKELETON 349
#define RT_FUNGAL_FIEND 218
#define RT_FUNGUS_PATCH 463
#define RT_FUNGUSMAN 28
#define RT_GALORIAN 228
#define RT_GARGOYLE 29
#define RT_GARGOYLE_2 464
#define RT_GASBAG 30
#define RT_GELATINOUS_CUBE 31
#define RT_GELATINOUS_CUBE_2 712
#define RT_GELIDRAN 417
#define RT_GENARI 648
#define RT_GEONID 178
#define RT_GHOST 32
#define RT_GHOST_2 117
#define RT_GHOST_3 118
#define RT_GHOST_4 334
#define RT_GHOST_SHIP 114
#define RT_GHOST_SHIP_2 552
#define RT_GHOUL 33
#define RT_GHOUL_2 571
#define RT_GIANT 18
#define RT_GIANT_2 140
#define RT_GIANT_3 188
#define RT_GIANT_4 189
#define RT_GIANT_5 306
#define RT_GIANT_6 307
#define RT_GIANT_7 308
#define RT_GIANT_8 309
#define RT_GIANT_9 310
#define RT_GIANT_10 311
#define RT_GIANT_11 312
#define RT_GIANT_12 453
#define RT_GIANT_13 523
#define RT_GIANT_CLOCKWORK 275
#define RT_GIANT_RALLOSIAN_MATS 626
#define RT_GIANT_SHADE 526
#define RT_GIGYN 649
#define RT_GINGERBREAD_MAN 666
#define RT_GIRPLAN 419
#define RT_GNOLL 39
#define RT_GNOLL_2 524
#define RT_GNOLL_3 617
#define RT_GNOME 12
#define RT_GNOMEWORK 457
#define RT_GNOMISH_BALLOON 683
#define RT_GNOMISH_BOAT 545
#define RT_GNOMISH_HOVERING_TRANSPORT 685
#define RT_GNOMISH_ROCKET_PACK 684
#define RT_GOBLIN 40
#define RT_GOBLIN_2 59
#define RT_GOBLIN_3 137
#define RT_GOBLIN_4 369
#define RT_GOBLIN_5 433
#define RT_GOD_LUCLIN_VER_2 728
#define RT_GOD_LUCLIN_VER_3 729
#define RT_GOD_LUCLIN_VER_4 731
#define RT_GOD_OF_DISCORD 622
#define RT_GOLEM 17
#define RT_GOLEM_2 374
#define RT_GOO 145
#define RT_GOO_2 547
#define RT_GOO_3 548
#define RT_GOO_4 549
#define RT_GORAL 687
#define RT_GORAL_MOUNT 673
#define RT_GORGON 121
#define RT_GORILLA 41
#define RT_GORILLA_2 560
#define RT_GRANDFATHER_CLOCK 665
#define RT_GREKEN_YOUNG 651
#define RT_GREKEN_YOUNG_ADULT 650
#define RT_GRENDLAEN 701
#define RT_GRIEG_VENEFICUS 231
#define RT_GRIFFIN 47
#define RT_GRIFFIN_2 525
#define RT_GRIMLING 202
#define RT_GROUND_SHAKER 233
#define RT_GUARD 44
#define RT_GUARD_2 106
#define RT_GUARD_3 112
#define RT_GUARD_4 239
#define RT_GUARD_OF_JUSTICE 251
#define RT_GUARDIAN_CPU 593
#define RT_HADAL 698
#define RT_HAG 185
#define RT_HALF_ELF 7
#define RT_HALFLING 11
#define RT_HALFLING_2 81
#define RT_HARPY 111
#define RT_HARPY_2 527
#define RT_HIGH_ELF 5
#define RT_HIPPOGRIFF 186
#define RT_HOLGRESH 168
#define RT_HOLGRESH_2 715
#define RT_HONEY_POT 536
#define RT_HORSE 216
#define RT_HORSE_2 492
#define RT_HORSE_3 518
#define RT_HOVERING_PLATFORM 699
#define RT_HRAQUIS 261
#define RT_HUMAN 1
#define RT_HUMAN_2 67
#define RT_HUMAN_3 71
#define RT_HUMAN_4 566
#define RT_HUMAN_GHOST 588
#define RT_HUVUL 400
#define RT_HYDRA_CRYSTAL 615
#define RT_HYDRA_MOUNT 631
#define RT_HYDRA_NPC 632
#define RT_HYNID 388
#define RT_ICE_SPECTRE 174
#define RT_IKAAV 394
#define RT_IKSAR 128
#define RT_IKSAR_2 139
#define RT_IKSAR_GHOST 605
#define RT_IKSAR_GOLEM 160
#define RT_IKSAR_SKELETON 606
#define RT_IKSAR_SPIRIT 147
#define RT_IMP 46
#define RT_INNORUUK 123
#define RT_INSECT 370
#define RT_INTERACTIVE_OBJECT 2250
#define RT_INVISIBLE_MAN 127
#define RT_INVISIBLE_MAN_2 681
#define RT_INVISIBLE_MAN_3 690
#define RT_INVISIBLE_MAN_OF_ZOMM 600
#define RT_IXT 393
#define RT_JOKESTER 384
#define RT_JUM_JUM_BUCKET 537
#define RT_JUNK_BEAST 273
#define RT_KANGON 689
#define RT_KANGON_MOUNT 677
#define RT_KARANA 278
#define RT_KEDGE 103
#define RT_KEDGE_2 561
#define RT_KERRAN 23
#define RT_KERRAN_2 562
#define RT_KIRIN 434
#define RT_KIRIN_2 583
#define RT_KNIGHT_OF_HATE 351
#define RT_KNIGHT_OF_PESTILENCE 266
#define RT_KOBOLD 48
#define RT_KOBOLD_2 455
#define RT_KRAKEN 315
#define RT_KYV 396
#define RT_LAUNCH 73
#define RT_LAVA_ROCK 447
#define RT_LAVA_SPIDER 450
#define RT_LAVA_SPIDER_QUEEN 451
#define RT_LEECH 104
#define RT_LEPERTOLOTH 267
#define RT_LIGHTCRAWLER 223
#define RT_LIGHTNING_WARRIOR 407
#define RT_LION 50
#define RT_LIZARD_MAN 51
#define RT_LUCLIN 724
#define RT_LUGGALD 345
#define RT_LUGGALD_2 346
#define RT_LUGGALDS 347
#define RT_MALARIAN 265
#define RT_MAMMOTH 107
#define RT_MAMMOTH_2 528
#define RT_MAN_EATING_PLANT 162
#define RT_MANSION 595
#define RT_MANTICORE 172
#define RT_MANTRAP 573
#define RT_MARIONETTE 659
#define RT_MASTRUQ 402
#define RT_MATA_MURAM 406
#define RT_MEDIUM_PLANT 541
#define RT_MEPHIT 607
#define RT_MERCHANT_SHIP 550
#define RT_MERMAID 110
#define RT_MIMIC 52
#define RT_MINI_POM 252
#define RT_MINOTAUR 53
#define RT_MINOTAUR_2 420
#define RT_MINOTAUR_3 470
#define RT_MINOTAUR_4 574
#define RT_MITHANIEL_MARR 296
#define RT_MORELL_THULE 658
#define RT_MOSQUITO 134
#define RT_MOUTH_OF_INSANITY 281
#define RT_MUDDITE 608
#define RT_MUMMY 368
#define RT_MURAMITE_ARMOR_PILE 424
#define RT_MURKGLIDER 414
#define RT_MURKGLIDER_EGG_SAC 429
#define RT_MUTNA 401
#define RT_NEKHON 614
#define RT_NETHERBIAN 229
#define RT_NIGHTMARE 287
#define RT_NIGHTMARE_GARGOYLE 280
#define RT_NIGHTMARE_GOBLIN 277
#define RT_NIGHTMARE_MEPHIT 294
#define RT_NIGHTMARE_UNICORN 517
#define RT_NIGHTMARE_UNICORN_2 519
#define RT_NIGHTMARE_WRAITH 264
#define RT_NIHIL 385
#define RT_NILBORIEN 317
#define RT_NOC 397
#define RT_NYMPH 242
#define RT_OGRE 10
#define RT_OGRE_2 93
#define RT_OGRE_NPC_MALE 624
#define RT_ORB 730
#define RT_ORC 54
#define RT_ORC_2 458
#define RT_OTHMIR 190
#define RT_OWLBEAR 206
#define RT_PARASITIC_SCAVENGER 700
#define RT_PEGASUS 125
#define RT_PEGASUS_2 493
#define RT_PEGASUS_3 732
#define RT_PHOENIX 303
#define RT_PIRANHA 74
#define RT_PIRATE 335
#define RT_PIRATE_2 336
#define RT_PIRATE_3 337
#define RT_PIRATE_4 338
#define RT_PIRATE_5 339
#define RT_PIRATE_6 340
#define RT_PIRATE_7 341
#define RT_PIRATE_8 342
#define RT_PIRATE_SHIP 551
#define RT_PIXIE 56
#define RT_POISON_FROG 316
#define RT_PORTAL 426
#define RT_POWDER_KEG 636
#define RT_PRESSURE_PLATE 506
#define RT_PUFFER_SPORE 507
#define RT_PUMA 76
#define RT_PUMA_2 439
#define RT_PUMA_3 584
#define RT_PUSLING 270
#define RT_PYRILEN 411
#define RT_RA_TUK 398
#define RT_RABBIT 668
#define RT_RALLOS_ZEK 66
#define RT_RALLOS_ZEK_2 288
#define RT_RALLOS_ZEK_MINION 325
#define RT_RAPTOR 163
#define RT_RAPTOR_2 609
#define RT_RAPTOR_MOUNT 680
#define RT_RAT 36
#define RT_RAT_2 415
#define RT_RAT_MOUNT 656
#define RT_RATMAN 156
#define RT_RATMAN_2 718
#define RT_REANIMATED_HAND 80
#define RT_RECUSO 237
#define RT_REGENERATION_POOL 705
#define RT_RELIC_CASE 707
#define RT_RHINO_BEETLE 207
#define RT_RHINOCEROS 135
#define RT_ROBOCOPTER_OF_ZOMM 601
#define RT_ROCK_PILE 428
#define RT_ROCKHOPPER 200
#define RT_RONNIE_TEST 197
#define RT_ROOT_TENTACLE 509
#define RT_ROT_DOG_MOUNT 672
#define RT_ROTDOG 662
#define RT_ROTOCOPTER 577
#define RT_ROWBOAT 502
#define RT_ROYAL_GUARD 667
#define RT_RUJARKIAN_ORC 361
#define RT_RUJARKIAN_ORC_2 366
#define RT_RUNED_ORB 422
#define RT_RUNIC_SYMBOL 510
#define RT_SABER_TOOTHED_CAT 119
#define RT_SALTPETTER_BOMB 511
#define RT_SAND_ELF 364
#define RT_SANDMAN 664
#define RT_SARNAK 131
#define RT_SARNAK_2 610
#define RT_SARNAK_GOLEM 164
#define RT_SARNAK_SPIRIT 146
#define RT_SARYRN 283
#define RT_SATYR 529
#define RT_SCALED_WOLF 481
#define RT_SCARECROW 82
#define RT_SCARECROW_2 575
#define RT_SCARLET_CHEETAH 221
#define RT_SCLERA_MOUNT 675
#define RT_SCORPION 129
#define RT_SCORPION_2 149
#define RT_SCORPION_3 611
#define RT_SCRYKIN 495
#define RT_SEA_TURTLE 194
#define RT_SEAHORSE 116
#define RT_SELYRAH 686
#define RT_SELYRAH_MOUNT 674
#define RT_SERU 236
#define RT_SERVANT_OF_SHADOW 723
#define RT_SESSILOID_MOUNT 657
#define RT_SHADE 224
#define RT_SHADE_2 373
#define RT_SHADE_3 576
#define RT_SHADEL 205
#define RT_SHAMBLING_MOUND 494
#define RT_SHARK 61
#define RT_SHIKNAR 199
#define RT_SHILISKIN 467
#define RT_SHIP 72
#define RT_SHIP_IN_A_BOTTLE 702
#define RT_SHISSAR 217
#define RT_SHISSAR_2 563
#define RT_SHRIEKER 227
#define RT_SIREN 187
#define RT_SIREN_2 564
#define RT_SKELETAL_HORSE 282
#define RT_SKELETON 60
#define RT_SKELETON_2 367
#define RT_SKELETON_3 484
#define RT_SKUNK 83
#define RT_SKYSTRIDER 709
#define RT_SMALL_PLANT 540
#define RT_SNAKE 37
#define RT_SNAKE_2 468
#define RT_SNAKE_ELEMENTAL 84
#define RT_SNOW_DERVISH 170
#define RT_SNOW_RABBIT 176
#define RT_SOKOKAR 618
#define RT_SOKOKAR_MOUNT 625
#define RT_SOKOKAR_W_SADDLE 627
#define RT_SOLUSEK_RO 58
#define RT_SOLUSEK_RO_2 247
#define RT_SOLUSEK_RO_GUARD 254
#define RT_SONIC_WOLF 232
#define RT_SOUL_DEVOURER 286
#define RT_SPECTRE 85
#define RT_SPECTRE_2 485
#define RT_SPELL_PARTICLE_1 599
#define RT_SPHINX 86
#define RT_SPHINX_2 565
#define RT_SPIDER 38
#define RT_SPIDER_2 440
#define RT_SPIDER_EGG_SACK 449
#define RT_SPIDER_MOUNT 654
#define RT_SPIDER_QUEEN 441
#define RT_SPIKE_TRAP 513
#define RT_SPIRIT_WOLF 483
#define RT_SPORALI 456
#define RT_STONE_JUG 539
#define RT_STONE_PYLON 619
#define RT_STONE_RING 508
#define RT_STONE_WORKER 387
#define RT_STONE_WORKER_2 405
#define RT_STONEGRABBER 220
#define RT_STONEMITE 391
#define RT_STORMRIDER 272
#define RT_SUCCUBUS 408
#define RT_SUCCULENT 167
#define RT_SULLON_ZEK 499
#define RT_SUN_REVENANT 226
#define RT_SUNFLOWER 225
#define RT_SWINETOR 696
#define RT_SWORDFISH 105
#define RT_SYNARCANA 363
#define RT_TABLE 380
#define RT_TADPOLE 102
#define RT_TAELOSIAN 403
#define RT_TALL_PLANT 542
#define RT_TALLON_ZEK 290
#define RT_TANETH 399
#define RT_TAREW_MARR 246
#define RT_TEGI 215
#define RT_TELEPORT_MAN 240
#define RT_TELEPORTATION_STAND 706
#define RT_TELMIRA 653
#define RT_TENTACLE_TERROR 68
#define RT_TENTACLE_TERROR_2 578
#define RT_TERRIS_THULE 257
#define RT_TEST_OBJECT 301
#define RT_THE_RATHE 298
#define RT_THE_TRIBUNAL 256
#define RT_THOUGHT_HORROR 214
#define RT_TIGER 63
#define RT_TIN_SOLDIER 263
#define RT_TOOLBOX 538
#define RT_TOPIARY_LION 661
#define RT_TOPIARY_LION_MOUNT 671
#define RT_TORMENTOR 285
#define RT_TOTEM 173
#define RT_TOTEM_2 514
#define RT_TRAKANON 19
#define RT_TRANQUILION 262
#define RT_TREANT 64
#define RT_TREANT_2 244
#define RT_TREANT_3 496
#define RT_TRIBUNAL 151
#define RT_TRIUMVIRATE 697
#define RT_TROLL 9
#define RT_TROLL_2 92
#define RT_TROLL_3 331
#define RT_TROLL_4 332
#define RT_TROLL_5 333
#define RT_TROLL_ZOMBIE 344
#define RT_TRUSIK 386
#define RT_TSETSIAN 612
#define RT_TUMBLEWEED 694
#define RT_TUNARE 62
#define RT_TUREPTA 389
#define RT_UKUN 392
#define RT_ULTHORK 191
#define RT_UNDEAD_CHOKIDAI 357
#define RT_UNDEAD_FOOTMAN 324
#define RT_UNDEAD_FROGLOK 350
#define RT_UNDEAD_IKSAR 161
#define RT_UNDEAD_KNIGHT 297
#define RT_UNDEAD_SARNAK 155
#define RT_UNDEAD_VEKSAR 358
#define RT_UNDERBULK 201
#define RT_UNICORN 124
#define RT_UNKNOWN_RACE 0
#define RT_UNKNOWN_RACE_2 142
#define RT_UNKNOWN_RACE_3 143
#define RT_UNKNOWN_RACE_4 179
#define RT_UNKNOWN_RACE_5 180
#define RT_UNKNOWN_RACE_6 443
#define RT_UNKNOWN_RACE_7 444
#define RT_VAH_SHIR 130
#define RT_VAH_SHIR_2 238
#define RT_VAH_SHIR_SKELETON 234
#define RT_VALLON_ZEK 289
#define RT_VALORIAN 318
#define RT_VALORIAN_2 322
#define RT_VAMPIRE 65
#define RT_VAMPIRE_2 98
#define RT_VAMPIRE_3 208
#define RT_VAMPIRE_4 219
#define RT_VAMPIRE_5 359
#define RT_VAMPIRE_6 360
#define RT_VAMPIRE_7 365
#define RT_VAMPIRE_8 497
#define RT_VASE 379
#define RT_VEGEROG 258
#define RT_VEKSAR 353
#define RT_VEKSAR_2 354
#define RT_VEKSAR_3 355
#define RT_VENRIL_SATHIR 20
#define RT_VINE_MAW 717
#define RT_WAGON 621
#define RT_WALRUS 177
#define RT_WAR_BOAR 319
#define RT_WAR_BOAR_2 321
#define RT_WAR_WRAITH 313
#define RT_WASP 109
#define RT_WATER_ELEMENTAL 211
#define RT_WATER_ELEMENTAL_2 478
#define RT_WATER_MEPHIT 271
#define RT_WATER_SPOUT 710
#define RT_WEAPON_RACK 381
#define RT_WEAPON_RACK_2 534
#define RT_WEB 515
#define RT_WEDDING_ALTAR 635
#define RT_WEDDING_ARBOR 634
#define RT_WEDDING_FLOWERS 633
#define RT_WEREORC 579
#define RT_WEREWOLF 14
#define RT_WEREWOLF_2 241
#define RT_WEREWOLF_3 454
#define RT_WETFANG_MINNOW 213
#define RT_WHIRLIGIG 682
#define RT_WICKER_BASKET 516
#define RT_WILL_O_WISP 69
#define RT_WINE_CASK 543
#define RT_WINE_CASK_2 630
#define RT_WITHERAN 465
#define RT_WITHERAN_2 474
#define RT_WOLF 42
#define RT_WOLF_2 120
#define RT_WOLF_3 482
#define RT_WOOD_ELF 4
#define RT_WORG 580
#define RT_WORG_2 594
#define RT_WORM 203
#define RT_WRETCH 235
#define RT_WRULON 314
#define RT_WRULON_2 598
#define RT_WURM 158
#define RT_WURM_2 613
#define RT_WURM_MOUNT 679
#define RT_WYVERN 157
#define RT_WYVERN_2 581
#define RT_XALGOZ 136
#define RT_XARIC_THE_UNSPOKEN 725
#define RT_XEGONY 299
#define RT_YAKKAR 181
#define RT_YETI 138
#define RT_ZEBUXORUK 295
#define RT_ZEBUXORUKS_CAGE 328
#define RT_ZELNIAK 222
#define RT_ZOMBIE 70
#define RT_ZOMBIE_2 471
const char* GetRaceIDName(uint16 race_id);
const char* GetPlayerRaceName(uint32 player_race_value);
+9
View File
@@ -65,6 +65,15 @@ namespace EQEmu {
return Real(0.0, 1.0) <= required;
}
// same range as client's roll0
// This is their main high level RNG function
int Roll0(int max)
{
if (max - 1 > 0)
return Int(0, max - 1);
return 0;
}
// std::shuffle requires a RNG engine passed to it, so lets provide a wrapper to use our engine
template<typename RandomAccessIterator>
void Shuffle(RandomAccessIterator first, RandomAccessIterator last)
+31 -7
View File
@@ -56,6 +56,7 @@ RULE_REAL(Character, GroupExpMultiplier, 0.5)
RULE_REAL(Character, RaidExpMultiplier, 0.2)
RULE_BOOL(Character, UseXPConScaling, true)
RULE_INT(Character, ShowExpValues, 0) //0 - normal, 1 - Show raw experience values, 2 - Show raw experience values AND percent.
RULE_INT(Character, GreenModifier, 20)
RULE_INT(Character, LightBlueModifier, 40)
RULE_INT(Character, BlueModifier, 90)
RULE_INT(Character, WhiteModifier, 100)
@@ -114,6 +115,7 @@ RULE_BOOL(Character, CheckCursorEmptyWhenLooting, true) // If true, a player can
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, EnableAggroMeter, true) // Enable Aggro Meter, for users with RoF 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.
@@ -148,6 +150,7 @@ RULE_INT(Character, AvoidanceCap, 750) // 750 Is a pretty good value, seen peopl
RULE_BOOL(Character, AllowMQTarget, false) // Disables putting players in the 'hackers' list for targeting beyond the clip plane or attempting to target something untargetable
RULE_BOOL(Character, UseOldBindWound, false) // Uses the original bind wound behavior
RULE_BOOL(Character, GrantHoTTOnCreate, false) // Grant Health of Target's Target leadership AA on character creation
RULE_BOOL(Character, UseOldConSystem, false) // Grant Health of Target's Target leadership AA on character creation
RULE_CATEGORY_END()
RULE_CATEGORY(Mercs)
@@ -162,6 +165,8 @@ RULE_INT(Mercs, AggroRadius, 100) // Determines the distance from which a merc
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_BOOL(Mercs, MercsUsePathing, true) // Mercs will use node pathing when moving
RULE_BOOL(Mercs, AllowMercSuspendInCombat, true)
RULE_CATEGORY_END()
RULE_CATEGORY(Guild)
@@ -224,7 +229,9 @@ RULE_INT(World, PVPSettings, 0) // Sets the PVP settings for the server, 1 = Ral
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_BOOL(World, MaxClientsSimplifiedLogic, false) // New logic that only uses ExemptMaxClientsStatus and MaxClientsPerIP. Done on the loginserver. This mimics the P99-style special IP rules.
RULE_INT (World, TellQueueSize, 20)
RULE_BOOL(World, StartZoneSameAsBindOnCreation, true) //Should the start zone ALWAYS be the same location as your bind?
RULE_CATEGORY_END()
RULE_CATEGORY(Zone)
@@ -258,6 +265,8 @@ 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_BOOL(Zone, EnableZoneControllerGlobals, false) // Enables the ability to use quest globals with the zone controller NPC
RULE_INT(Zone, GlobalLootMultiplier, 1) // Sets Global Loot drop multiplier for database based drops, useful for double, triple loot etc.
RULE_BOOL(Zone, IdleWhenEmpty, true) // Don't process NPCs while zone is empty. Defaults to true.
RULE_CATEGORY_END()
RULE_CATEGORY(Map)
@@ -392,15 +401,13 @@ RULE_BOOL(Spells, NPCInnateProcOverride, true) // NPC innate procs override the
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, PetBaseCritChance, 0) // Pet Base crit chance
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_INT(Combat, MeleeCritDifficulty, 8900) // lower is easier
RULE_INT(Combat, ArcheryCritDifficulty, 3400) // lower is easier
RULE_INT(Combat, ThrowingCritDifficulty, 1100) // lower is easier
RULE_BOOL(Combat, NPCCanCrit, false) // true allows non PC pet NPCs to crit
RULE_BOOL(Combat, UseIntervalAC, true)
RULE_INT(Combat, PetAttackMagicLevel, 30)
RULE_BOOL(Combat, EnableFearPathing, true)
@@ -492,6 +499,7 @@ RULE_INT(Combat, NPCAssistCap, 5) // Maxiumium number of NPCs that will assist a
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_BOOL(Combat, ClassicMasterWu, false) // classic master wu uses a random special, modern doesn't
RULE_INT(Combat, LevelToStopDamageCaps, 0) // 1 will effectively disable them, 20 should give basically same results as old incorrect system
RULE_CATEGORY_END()
RULE_CATEGORY(NPC)
@@ -542,6 +550,20 @@ RULE_BOOL(TaskSystem, KeepOneRecordPerCompletedTask, true)
RULE_BOOL(TaskSystem, EnableTaskProximity, true)
RULE_CATEGORY_END()
RULE_CATEGORY(Range)
RULE_INT(Range, Say, 135)
RULE_INT(Range, Emote, 135)
RULE_INT(Range, BeginCast, 200)
RULE_INT(Range, Anims, 135)
RULE_INT(Range, SpellParticles, 135)
RULE_INT(Range, DamageMessages, 50)
RULE_INT(Range, SpellMessages, 75)
RULE_INT(Range, SongMessages, 75)
RULE_INT(Range, MobPositionUpdates, 600)
RULE_INT(Range, CriticalDamage, 80)
RULE_CATEGORY_END()
#ifdef BOTS
RULE_CATEGORY(Bots)
RULE_INT(Bots, AAExpansion, 8) // Bots get AAs through this expansion
@@ -557,6 +579,8 @@ RULE_BOOL(Bots, PreferNoManaCommandSpells, true) // Give sorting priority to new
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 pseudo-raid (bots are not raidable at this time)
RULE_BOOL(Bots, UpdatePositionWithTimer, false) // Sends a position update with every positive movement timer check
RULE_BOOL(Bots, UsePathing, true) // Bots will use node pathing when moving
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)
+1
View File
@@ -663,6 +663,7 @@ struct UsertoWorldRequest_Struct {
uint32 worldid;
uint32 FromID;
uint32 ToID;
char IPAddr[64];
};
struct UsertoWorldResponse_Struct {
+3 -2
View File
@@ -1136,13 +1136,13 @@ const EQEmu::ItemData* SharedDatabase::IterateItems(uint32* id) {
return nullptr;
}
std::string SharedDatabase::GetBook(const char *txtfile)
std::string SharedDatabase::GetBook(const char *txtfile, int16 *language)
{
char txtfile2[20];
std::string txtout;
strcpy(txtfile2, txtfile);
std::string query = StringFormat("SELECT txtfile FROM books WHERE name = '%s'", txtfile2);
std::string query = StringFormat("SELECT txtfile, language FROM books WHERE name = '%s'", txtfile2);
auto results = QueryDatabase(query);
if (!results.Success()) {
txtout.assign(" ",1);
@@ -1157,6 +1157,7 @@ std::string SharedDatabase::GetBook(const char *txtfile)
auto row = results.begin();
txtout.assign(row[0],strlen(row[0]));
*language = static_cast<int16>(atoi(row[1]));
return txtout;
}
+1 -1
View File
@@ -94,7 +94,7 @@ class SharedDatabase : public Database
bool SetStartingItems(PlayerProfile_Struct* pp, EQEmu::InventoryProfile* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin);
std::string GetBook(const char *txtfile);
std::string GetBook(const char *txtfile, int16 *language);
/*
Item Methods
+51
View File
@@ -124,6 +124,57 @@ bool EQEmu::skills::IsCastingSkill(SkillType skill)
}
}
int32 EQEmu::skills::GetBaseDamage(SkillType skill)
{
switch (skill) {
case SkillBash:
return 2;
case SkillDragonPunch:
return 12;
case SkillEagleStrike:
return 7;
case SkillFlyingKick:
return 25;
case SkillKick:
return 3;
case SkillRoundKick:
return 5;
case SkillTigerClaw:
return 4;
case SkillFrenzy:
return 10;
default:
return 0;
}
}
bool EQEmu::skills::IsMeleeDmg(SkillType skill)
{
switch (skill) {
case Skill1HBlunt:
case Skill1HSlashing:
case Skill2HBlunt:
case Skill2HSlashing:
case SkillBackstab:
case SkillBash:
case SkillDragonPunch:
case SkillEagleStrike:
case SkillFlyingKick:
case SkillHandtoHand:
case SkillKick:
case Skill1HPiercing:
case SkillRiposte:
case SkillRoundKick:
case SkillThrowing:
case SkillTigerClaw:
case SkillFrenzy:
case Skill2HPiercing:
return true;
default:
return false;
}
}
const std::map<EQEmu::skills::SkillType, std::string>& EQEmu::skills::GetSkillTypeMap()
{
/* VS2013 code
+2
View File
@@ -166,6 +166,8 @@ namespace EQEmu
float GetSkillMeleePushForce(SkillType skill);
bool IsBardInstrumentSkill(SkillType skill);
bool IsCastingSkill(SkillType skill);
int32 GetBaseDamage(SkillType skill);
bool IsMeleeDmg(SkillType skill);
extern const std::map<SkillType, std::string>& GetSkillTypeMap();
+1 -1
View File
@@ -940,7 +940,7 @@ bool IsRegularSingleTargetHealSpell(uint16 spell_id)
{
if(spells[spell_id].effectid[0] == 0 && spells[spell_id].base[0] > 0 &&
spells[spell_id].targettype == ST_Target && spells[spell_id].buffduration == 0 &&
!IsFastHealSpell(spell_id) && !IsCompleteHealSpell(spell_id) &&
!IsCompleteHealSpell(spell_id) &&
!IsHealOverTimeSpell(spell_id) && !IsGroupSpell(spell_id))
return true;
+83 -25
View File
@@ -43,35 +43,93 @@
const int Z_AGGRO=10;
const int MobAISpellRange=100; // max range of buffs
const int SpellType_Nuke=1;
const int SpellType_Heal=2;
const int SpellType_Root=4;
const int SpellType_Buff=8;
const int SpellType_Escape=16;
const int SpellType_Pet=32;
const int SpellType_Lifetap=64;
const int SpellType_Snare=128;
const int SpellType_DOT=256;
const int SpellType_Dispel=512;
const int SpellType_InCombatBuff=1024;
const int SpellType_Mez=2048;
const int SpellType_Charm=4096;
const int SpellType_Slow = 8192;
const int SpellType_Debuff = 16384;
const int SpellType_Cure = 32768;
const int SpellType_Resurrect = 65536;
const uint32 MobAISpellRange=100; // max range of buffs
const int SpellTypes_Detrimental = SpellType_Nuke|SpellType_Root|SpellType_Lifetap|SpellType_Snare|SpellType_DOT|SpellType_Dispel|SpellType_Mez|SpellType_Charm|SpellType_Debuff|SpellType_Slow;
const int SpellTypes_Beneficial = SpellType_Heal|SpellType_Buff|SpellType_Escape|SpellType_Pet|SpellType_InCombatBuff|SpellType_Cure;
enum SpellTypes : uint32
{
SpellType_Nuke = (1 << 0),
SpellType_Heal = (1 << 1),
SpellType_Root = (1 << 2),
SpellType_Buff = (1 << 3),
SpellType_Escape = (1 << 4),
SpellType_Pet = (1 << 5),
SpellType_Lifetap = (1 << 6),
SpellType_Snare = (1 << 7),
SpellType_DOT = (1 << 8),
SpellType_Dispel = (1 << 9),
SpellType_InCombatBuff = (1 << 10),
SpellType_Mez = (1 << 11),
SpellType_Charm = (1 << 12),
SpellType_Slow = (1 << 13),
SpellType_Debuff = (1 << 14),
SpellType_Cure = (1 << 15),
SpellType_Resurrect = (1 << 16),
SpellType_HateRedux = (1 << 17),
SpellType_InCombatBuffSong = (1 << 18), // bard in-combat group/ae buffs
SpellType_OutOfCombatBuffSong = (1 << 19), // bard out-of-combat group/ae buffs
SpellType_PreCombatBuff = (1 << 20),
SpellType_PreCombatBuffSong = (1 << 21),
#define SpellType_Any 0xFFFF
SpellTypes_Detrimental = (SpellType_Nuke | SpellType_Root | SpellType_Lifetap | SpellType_Snare | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Charm | SpellType_Debuff | SpellType_Slow),
SpellTypes_Beneficial = (SpellType_Heal | SpellType_Buff | SpellType_Escape | SpellType_Pet | SpellType_InCombatBuff | SpellType_Cure | SpellType_HateRedux | SpellType_InCombatBuffSong | SpellType_OutOfCombatBuffSong | SpellType_PreCombatBuff | SpellType_PreCombatBuffSong),
SpellType_Any = 0xFFFFFFFF
};
// These should not be used to determine spell category..
// They are a graphical affects (effects?) index only
// TODO: import sai list
enum SpellAffectIndex {
SAI_Calm = 12, // Lull and Alliance Spells
SAI_Dispell_Sight = 14, // Dispells and Spells like Bind Sight
SAI_Memory_Blur = 27,
SAI_Calm_Song = 43 // Lull and Alliance Songs
SAI_Summon_Mount_Unclass = -1,
SAI_Direct_Damage = 0,
SAI_Heal_Cure = 1,
SAI_AC_Buff = 2,
SAI_AE_Damage = 3,
SAI_Summon = 4, // Summoned Pets and Items
SAI_Sight = 5,
SAI_Mana_Regen_Resist_Song = 6,
SAI_Stat_Buff = 7,
SAI_Vanish = 9, // Invisibility and Gate/Port
SAI_Appearance = 10, // Illusion and Size
SAI_Enchanter_Pet = 11,
SAI_Calm = 12, // Lull and Alliance Spells
SAI_Fear = 13,
SAI_Dispell_Sight = 14, // Dispells and Spells like Bind Sight
SAI_Stun = 15,
SAI_Haste_Runspeed = 16, // Haste and SoW
SAI_Combat_Slow = 17,
SAI_Damage_Shield = 18,
SAI_Cannibalize_Weapon_Proc = 19,
SAI_Weaken = 20,
SAI_Banish = 21,
SAI_Blind_Poison = 22,
SAI_Cold_DD = 23,
SAI_Poison_Disease_DD = 24,
SAI_Fire_DD = 25,
SAI_Memory_Blur = 27,
SAI_Gravity_Fling = 28,
SAI_Suffocate = 29,
SAI_Lifetap_Over_Time = 30,
SAI_Fire_AE = 31,
SAI_Cold_AE = 33,
SAI_Poison_Disease_AE = 34,
SAI_Teleport = 40,
SAI_Direct_Damage_Song = 41,
SAI_Combat_Buff_Song = 42,
SAI_Calm_Song = 43, // Lull and Alliance Songs
SAI_Firework = 45,
SAI_Firework_AE = 46,
SAI_Weather_Rocket = 47,
SAI_Convert_Vitals = 50,
SAI_NPC_Special_60 = 60,
SAI_NPC_Special_61 = 61,
SAI_NPC_Special_62 = 62,
SAI_NPC_Special_63 = 63,
SAI_NPC_Special_70 = 70,
SAI_NPC_Special_71 = 71,
SAI_NPC_Special_80 = 80,
SAI_Trap_Lock = 88
};
enum RESISTTYPE
{
+2 -2
View File
@@ -30,9 +30,9 @@
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9101
#define CURRENT_BINARY_DATABASE_VERSION 9107
#ifdef BOTS
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9008
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9015
#else
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
#endif
+5 -3
View File
@@ -99,9 +99,11 @@ bool Client::Process()
}
default:
{
char dump[64];
app->build_header_dump(dump);
Log.Out(Logs::General, Logs::Error, "Recieved unhandled application packet from the client: %s.", dump);
if (Log.log_settings[Logs::Client_Server_Packet_Unhandled].is_category_enabled == 1) {
char dump[64];
app->build_header_dump(dump);
Log.Out(Logs::General, Logs::Error, "Recieved unhandled application packet from the client: %s.", dump);
}
}
}
+115
View File
@@ -0,0 +1,115 @@
var app = angular.module('app', ['nvd3']);
app.controller('MainCtrl', function($scope, $interval) {
$scope.options = {
chart: {
type: 'discreteBarChart',
height: 450,
margin: {
top: 20,
right: 20,
bottom: 50,
left: 55
},
x: function(d) {
return d.label;
},
y: function(d) {
return d.value + (1e-10);
},
showValues: true,
valueFormat: function(d) {
return d3.format(',.2r')(d);
},
duration: 500,
xAxis: {
axisLabel: 'D1-D20'
},
yAxis: {
axisLabel: 'Count'
}
}
};
$scope.offense = 100;
$scope.mitigation = 100;
$scope.data = [{
key: "Cumulative Return",
values: []
}];
for (var i = 0; i < 20; ++i) {
var value = {
"label": i + 1,
"value": 0
};
$scope.data[0].values.push(value);
}
function addRoll(interval) {
$scope.data[0].values[interval - 1].value += 1;
}
var stop;
$scope.clearData = function() {
console.log('Clearing data');
for (var i = 0; i < 20; ++i) {
$scope.data[0].values[i].value = 0;
}
};
$scope.start = function() {
if (angular.isDefined(stop))
return;
stop = $interval(doCombatRound, 100);
};
$scope.stop = function() {
if (angular.isDefined(stop)) {
$interval.cancel(stop);
stop = undefined;
}
};
$scope.$on('$destroy', function() {
$scope.stop();
});
var damage_mods = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
function getRandom(min, max) {
return Math.random() * (max - min) + min;
}
function addChance(bucket, chance, value) {
for (var i = 0; i < chance; ++i) {
bucket.push(value);
}
}
function doCombatRound() {
var offense = getRandomInt(0, $scope.offense + 5);
var mitigation = getRandomInt(0, $scope.mitigation + 5);
var avg = parseInt(($scope.offense + $scope.mitigation + 10) / 2);
var index = parseInt((offense - mitigation) + (avg / 2));
if (index < 0) {
index = 0;
}
index = parseInt((index * 20) / avg);
if (index >= 20)
index = 19;
if (index < 0)
index = 0;
var roll = damage_mods[index];
addRoll(roll);
};
});
+30
View File
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>Combat Visualization</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.min.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-nvd3/1.0.5/angular-nvd3.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<nvd3 options="options" data="data"></nvd3>
<button ng-click=clearData()>Clear Data</button>
<button ng-click=start()>Start</button>
<button ng-click=stop()>Stop</button>
<div class="input-row">
<label>Offense:</label>
<input type="number" name="Offense" ng-model="offense"></input>
</div>
<div class="input-row">
<label>Mitigation:</label>
<input type="number" name="mitigation" ng-model="mitigation"></input>
</div>
</body>
</html>
+3
View File
@@ -0,0 +1,3 @@
.input-row {
padding: 8px;
}
+3
View File
@@ -359,6 +359,9 @@ OP_OpenContainer=0x654f
OP_Marquee=0x288a
OP_Fling=0x6b8e
OP_CancelSneakHide=0x265f
OP_AggroMeterLockTarget=0x70b7
OP_AggroMeterTargetInfo=0x18fe
OP_AggroMeterUpdate=0x75aa
OP_DzQuit=0x5fc8
OP_DzListTimers=0x67b9
+4 -1
View File
@@ -150,7 +150,7 @@ OP_GMZoneRequest=0x62ac
OP_GMZoneRequest2=0x7e1a
OP_GMGoto=0x7d8e
OP_GMSearchCorpse=0x357c
OP_GMHideMe=0x79c5
OP_GMHideMe=0x2fab
OP_GMDelCorpse=0x607e
OP_GMApproval=0x6db5
OP_GMToggle=0x2097
@@ -360,6 +360,9 @@ OP_ItemRecastDelay=0x15a9
OP_ResetAA=0x1669
OP_Fling=0x6f80
OP_CancelSneakHide=0x0927
OP_AggroMeterLockTarget=0x1643
OP_AggroMeterTargetInfo=0x16bc
OP_AggroMeterUpdate=0x1781
# Expeditions
OP_DzAddPlayer=0x4701
@@ -0,0 +1,57 @@
DELIMITER $$
DROP FUNCTION IF EXISTS `GetBodyTypeToken`;
-- This function converts a numeric body type to a string label based on server code designations
-- Note: A preceeding '*' indicates a non-client verified token
--
-- example:
-- SELECT `id`, `name`, GetBodyTypeToken(`bodytype`) FROM `npc_types` WHERE `id` IN ('116539', '154086', '164042');
CREATE FUNCTION `GetBodyTypeToken` (`body_type` INT(11)) RETURNS VARCHAR(64)
BEGIN
DECLARE `token` VARCHAR(64) DEFAULT '';
CASE `body_type`
WHEN '1' THEN SET `token` = 'BT_Humanoid';
WHEN '2' THEN SET `token` = 'BT_Lycanthrope';
WHEN '3' THEN SET `token` = 'BT_Undead';
WHEN '4' THEN SET `token` = 'BT_Giant';
WHEN '5' THEN SET `token` = 'BT_Construct';
WHEN '6' THEN SET `token` = 'BT_Extraplanar';
WHEN '7' THEN SET `token` = 'BT_Magical';
WHEN '8' THEN SET `token` = '*BT_SummonedUndead';
WHEN '9' THEN SET `token` = '*BT_RaidGiant';
WHEN '11' THEN SET `token` = '*BT_NoTarget';
WHEN '12' THEN SET `token` = 'BT_Vampyre';
WHEN '13' THEN SET `token` = 'BT_Atenha_Ra';
WHEN '14' THEN SET `token` = 'BT_Greater_Akheva';
WHEN '15' THEN SET `token` = 'BT_Khati_Sha';
WHEN '16' THEN SET `token` = '*BT_Seru';
WHEN '18' THEN SET `token` = 'BT_Draz_Nurakk';
WHEN '19' THEN SET `token` = 'BT_Zek';
WHEN '20' THEN SET `token` = 'BT_Luggald';
WHEN '21' THEN SET `token` = 'BT_Animal';
WHEN '22' THEN SET `token` = 'BT_Insect';
WHEN '23' THEN SET `token` = 'BT_Monster';
WHEN '24' THEN SET `token` = 'BT_Elemental/*BT_Summoned';
WHEN '25' THEN SET `token` = 'BT_Plant';
WHEN '26' THEN SET `token` = 'BT_Dragon';
WHEN '27' THEN SET `token` = '*BT_Summoned2';
WHEN '28' THEN SET `token` = 'BT_Summoned_Creature/*BT_Summoned3';
WHEN '30' THEN SET `token` = '*BT_VeliousDragon';
WHEN '32' THEN SET `token` = '*BT_Dragon3';
WHEN '33' THEN SET `token` = '*BT_Boxes';
WHEN '34' THEN SET `token` = 'BT_Muramite';
WHEN '60' THEN SET `token` = '*BT_NoTarget2';
WHEN '63' THEN SET `token` = '*BT_SwarmPet';
WHEN '66' THEN SET `token` = '*BT_InvisMan';
WHEN '67' THEN SET `token` = '*BT_Special';
ELSE SET `token` = 'BT_UNKNOWN_BODYTYPE';
END CASE;
SET `token` = CONCAT(`token`, '(', `body_type`, ')');
RETURN `token`;
END$$
DELIMITER ;
@@ -0,0 +1,756 @@
DELIMITER $$
DROP FUNCTION IF EXISTS `GetRaceToken`;
-- This function converts a numeric race id to a string label based on server code designations
--
-- example:
-- SELECT `id`, `name`, GetRaceToken(`race`) FROM `npc_types` WHERE `id` IN ('644', '105153', '261131');
CREATE FUNCTION `GetRaceToken` (`race_id` INT(11)) RETURNS VARCHAR(64)
BEGIN
DECLARE `token` VARCHAR(64) DEFAULT '';
CASE `race_id`
WHEN '0' THEN SET `token` = 'UNKNOWN RACE';
WHEN '1' THEN SET `token` = 'Human';
WHEN '2' THEN SET `token` = 'Barbarian';
WHEN '3' THEN SET `token` = 'Erudite';
WHEN '4' THEN SET `token` = 'Wood Elf';
WHEN '5' THEN SET `token` = 'High Elf';
WHEN '6' THEN SET `token` = 'Dark Elf';
WHEN '7' THEN SET `token` = 'Half Elf';
WHEN '8' THEN SET `token` = 'Dwarf';
WHEN '9' THEN SET `token` = 'Troll';
WHEN '10' THEN SET `token` = 'Ogre';
WHEN '11' THEN SET `token` = 'Halfling';
WHEN '12' THEN SET `token` = 'Gnome';
WHEN '13' THEN SET `token` = 'Aviak';
WHEN '14' THEN SET `token` = 'Werewolf';
WHEN '15' THEN SET `token` = 'Brownie';
WHEN '16' THEN SET `token` = 'Centaur';
WHEN '17' THEN SET `token` = 'Golem';
WHEN '18' THEN SET `token` = 'Giant';
WHEN '19' THEN SET `token` = 'Trakanon';
WHEN '20' THEN SET `token` = 'Venril Sathir';
WHEN '21' THEN SET `token` = 'Evil Eye';
WHEN '22' THEN SET `token` = 'Beetle';
WHEN '23' THEN SET `token` = 'Kerran';
WHEN '24' THEN SET `token` = 'Fish';
WHEN '25' THEN SET `token` = 'Fairy';
WHEN '26' THEN SET `token` = 'Froglok';
WHEN '27' THEN SET `token` = 'Froglok';
WHEN '28' THEN SET `token` = 'Fungusman';
WHEN '29' THEN SET `token` = 'Gargoyle';
WHEN '30' THEN SET `token` = 'Gasbag';
WHEN '31' THEN SET `token` = 'Gelatinous Cube';
WHEN '32' THEN SET `token` = 'Ghost';
WHEN '33' THEN SET `token` = 'Ghoul';
WHEN '34' THEN SET `token` = 'Bat';
WHEN '35' THEN SET `token` = 'Eel';
WHEN '36' THEN SET `token` = 'Rat';
WHEN '37' THEN SET `token` = 'Snake';
WHEN '38' THEN SET `token` = 'Spider';
WHEN '39' THEN SET `token` = 'Gnoll';
WHEN '40' THEN SET `token` = 'Goblin';
WHEN '41' THEN SET `token` = 'Gorilla';
WHEN '42' THEN SET `token` = 'Wolf';
WHEN '43' THEN SET `token` = 'Bear';
WHEN '44' THEN SET `token` = 'Guard';
WHEN '45' THEN SET `token` = 'Demi Lich';
WHEN '46' THEN SET `token` = 'Imp';
WHEN '47' THEN SET `token` = 'Griffin';
WHEN '48' THEN SET `token` = 'Kobold';
WHEN '49' THEN SET `token` = 'Dragon';
WHEN '50' THEN SET `token` = 'Lion';
WHEN '51' THEN SET `token` = 'Lizard Man';
WHEN '52' THEN SET `token` = 'Mimic';
WHEN '53' THEN SET `token` = 'Minotaur';
WHEN '54' THEN SET `token` = 'Orc';
WHEN '55' THEN SET `token` = 'Beggar';
WHEN '56' THEN SET `token` = 'Pixie';
WHEN '57' THEN SET `token` = 'Drachnid';
WHEN '58' THEN SET `token` = 'Solusek Ro';
WHEN '59' THEN SET `token` = 'Goblin';
WHEN '60' THEN SET `token` = 'Skeleton';
WHEN '61' THEN SET `token` = 'Shark';
WHEN '62' THEN SET `token` = 'Tunare';
WHEN '63' THEN SET `token` = 'Tiger';
WHEN '64' THEN SET `token` = 'Treant';
WHEN '65' THEN SET `token` = 'Vampire';
WHEN '66' THEN SET `token` = 'Rallos Zek';
WHEN '67' THEN SET `token` = 'Human';
WHEN '68' THEN SET `token` = 'Tentacle Terror';
WHEN '69' THEN SET `token` = 'Will-O-Wisp';
WHEN '70' THEN SET `token` = 'Zombie';
WHEN '71' THEN SET `token` = 'Human';
WHEN '72' THEN SET `token` = 'Ship';
WHEN '73' THEN SET `token` = 'Launch';
WHEN '74' THEN SET `token` = 'Piranha';
WHEN '75' THEN SET `token` = 'Elemental';
WHEN '76' THEN SET `token` = 'Puma';
WHEN '77' THEN SET `token` = 'Dark Elf';
WHEN '78' THEN SET `token` = 'Erudite';
WHEN '79' THEN SET `token` = 'Bixie';
WHEN '80' THEN SET `token` = 'Reanimated Hand';
WHEN '81' THEN SET `token` = 'Halfling';
WHEN '82' THEN SET `token` = 'Scarecrow';
WHEN '83' THEN SET `token` = 'Skunk';
WHEN '84' THEN SET `token` = 'Snake Elemental';
WHEN '85' THEN SET `token` = 'Spectre';
WHEN '86' THEN SET `token` = 'Sphinx';
WHEN '87' THEN SET `token` = 'Armadillo';
WHEN '88' THEN SET `token` = 'Clockwork Gnome';
WHEN '89' THEN SET `token` = 'Drake';
WHEN '90' THEN SET `token` = 'Barbarian';
WHEN '91' THEN SET `token` = 'Alligator';
WHEN '92' THEN SET `token` = 'Troll';
WHEN '93' THEN SET `token` = 'Ogre';
WHEN '94' THEN SET `token` = 'Dwarf';
WHEN '95' THEN SET `token` = 'Cazic Thule';
WHEN '96' THEN SET `token` = 'Cockatrice';
WHEN '97' THEN SET `token` = 'Daisy Man';
WHEN '98' THEN SET `token` = 'Vampire';
WHEN '99' THEN SET `token` = 'Amygdalan';
WHEN '100' THEN SET `token` = 'Dervish';
WHEN '101' THEN SET `token` = 'Efreeti';
WHEN '102' THEN SET `token` = 'Tadpole';
WHEN '103' THEN SET `token` = 'Kedge';
WHEN '104' THEN SET `token` = 'Leech';
WHEN '105' THEN SET `token` = 'Swordfish';
WHEN '106' THEN SET `token` = 'Guard';
WHEN '107' THEN SET `token` = 'Mammoth';
WHEN '108' THEN SET `token` = 'Eye';
WHEN '109' THEN SET `token` = 'Wasp';
WHEN '110' THEN SET `token` = 'Mermaid';
WHEN '111' THEN SET `token` = 'Harpy';
WHEN '112' THEN SET `token` = 'Guard';
WHEN '113' THEN SET `token` = 'Drixie';
WHEN '114' THEN SET `token` = 'Ghost Ship';
WHEN '115' THEN SET `token` = 'Clam';
WHEN '116' THEN SET `token` = 'Seahorse';
WHEN '117' THEN SET `token` = 'Ghost';
WHEN '118' THEN SET `token` = 'Ghost';
WHEN '119' THEN SET `token` = 'Saber-toothed Cat';
WHEN '120' THEN SET `token` = 'Wolf';
WHEN '121' THEN SET `token` = 'Gorgon';
WHEN '122' THEN SET `token` = 'Dragon';
WHEN '123' THEN SET `token` = 'Innoruuk';
WHEN '124' THEN SET `token` = 'Unicorn';
WHEN '125' THEN SET `token` = 'Pegasus';
WHEN '126' THEN SET `token` = 'Djinn';
WHEN '127' THEN SET `token` = 'Invisible Man';
WHEN '128' THEN SET `token` = 'Iksar';
WHEN '129' THEN SET `token` = 'Scorpion';
WHEN '130' THEN SET `token` = 'Vah Shir';
WHEN '131' THEN SET `token` = 'Sarnak';
WHEN '132' THEN SET `token` = 'Draglock';
WHEN '133' THEN SET `token` = 'Drolvarg';
WHEN '134' THEN SET `token` = 'Mosquito';
WHEN '135' THEN SET `token` = 'Rhinoceros';
WHEN '136' THEN SET `token` = 'Xalgoz';
WHEN '137' THEN SET `token` = 'Goblin';
WHEN '138' THEN SET `token` = 'Yeti';
WHEN '139' THEN SET `token` = 'Iksar';
WHEN '140' THEN SET `token` = 'Giant';
WHEN '141' THEN SET `token` = 'Boat';
WHEN '142' THEN SET `token` = 'UNKNOWN RACE';
WHEN '143' THEN SET `token` = 'UNKNOWN RACE';
WHEN '144' THEN SET `token` = 'Burynai';
WHEN '145' THEN SET `token` = 'Goo';
WHEN '146' THEN SET `token` = 'Sarnak Spirit';
WHEN '147' THEN SET `token` = 'Iksar Spirit';
WHEN '148' THEN SET `token` = 'Fish';
WHEN '149' THEN SET `token` = 'Scorpion';
WHEN '150' THEN SET `token` = 'Erollisi';
WHEN '151' THEN SET `token` = 'Tribunal';
WHEN '152' THEN SET `token` = 'Bertoxxulous';
WHEN '153' THEN SET `token` = 'Bristlebane';
WHEN '154' THEN SET `token` = 'Fay Drake';
WHEN '155' THEN SET `token` = 'Undead Sarnak';
WHEN '156' THEN SET `token` = 'Ratman';
WHEN '157' THEN SET `token` = 'Wyvern';
WHEN '158' THEN SET `token` = 'Wurm';
WHEN '159' THEN SET `token` = 'Devourer';
WHEN '160' THEN SET `token` = 'Iksar Golem';
WHEN '161' THEN SET `token` = 'Undead Iksar';
WHEN '162' THEN SET `token` = 'Man-Eating Plant';
WHEN '163' THEN SET `token` = 'Raptor';
WHEN '164' THEN SET `token` = 'Sarnak Golem';
WHEN '165' THEN SET `token` = 'Dragon';
WHEN '166' THEN SET `token` = 'Animated Hand';
WHEN '167' THEN SET `token` = 'Succulent';
WHEN '168' THEN SET `token` = 'Holgresh';
WHEN '169' THEN SET `token` = 'Brontotherium';
WHEN '170' THEN SET `token` = 'Snow Dervish';
WHEN '171' THEN SET `token` = 'Dire Wolf';
WHEN '172' THEN SET `token` = 'Manticore';
WHEN '173' THEN SET `token` = 'Totem';
WHEN '174' THEN SET `token` = 'Ice Spectre';
WHEN '175' THEN SET `token` = 'Enchanted Armor';
WHEN '176' THEN SET `token` = 'Snow Rabbit';
WHEN '177' THEN SET `token` = 'Walrus';
WHEN '178' THEN SET `token` = 'Geonid';
WHEN '179' THEN SET `token` = 'UNKNOWN RACE';
WHEN '180' THEN SET `token` = 'UNKNOWN RACE';
WHEN '181' THEN SET `token` = 'Yakkar';
WHEN '182' THEN SET `token` = 'Faun';
WHEN '183' THEN SET `token` = 'Coldain';
WHEN '184' THEN SET `token` = 'Dragon';
WHEN '185' THEN SET `token` = 'Hag';
WHEN '186' THEN SET `token` = 'Hippogriff';
WHEN '187' THEN SET `token` = 'Siren';
WHEN '188' THEN SET `token` = 'Giant';
WHEN '189' THEN SET `token` = 'Giant';
WHEN '190' THEN SET `token` = 'Othmir';
WHEN '191' THEN SET `token` = 'Ulthork';
WHEN '192' THEN SET `token` = 'Dragon';
WHEN '193' THEN SET `token` = 'Abhorrent';
WHEN '194' THEN SET `token` = 'Sea Turtle';
WHEN '195' THEN SET `token` = 'Dragon';
WHEN '196' THEN SET `token` = 'Dragon';
WHEN '197' THEN SET `token` = 'Ronnie Test';
WHEN '198' THEN SET `token` = 'Dragon';
WHEN '199' THEN SET `token` = 'Shik\'Nar';
WHEN '200' THEN SET `token` = 'Rockhopper';
WHEN '201' THEN SET `token` = 'Underbulk';
WHEN '202' THEN SET `token` = 'Grimling';
WHEN '203' THEN SET `token` = 'Worm';
WHEN '204' THEN SET `token` = 'Evan Test';
WHEN '205' THEN SET `token` = 'Shadel';
WHEN '206' THEN SET `token` = 'Owlbear';
WHEN '207' THEN SET `token` = 'Rhino Beetle';
WHEN '208' THEN SET `token` = 'Vampire';
WHEN '209' THEN SET `token` = 'Earth Elemental';
WHEN '210' THEN SET `token` = 'Air Elemental';
WHEN '211' THEN SET `token` = 'Water Elemental';
WHEN '212' THEN SET `token` = 'Fire Elemental';
WHEN '213' THEN SET `token` = 'Wetfang Minnow';
WHEN '214' THEN SET `token` = 'Thought Horror';
WHEN '215' THEN SET `token` = 'Tegi';
WHEN '216' THEN SET `token` = 'Horse';
WHEN '217' THEN SET `token` = 'Shissar';
WHEN '218' THEN SET `token` = 'Fungal Fiend';
WHEN '219' THEN SET `token` = 'Vampire';
WHEN '220' THEN SET `token` = 'Stonegrabber';
WHEN '221' THEN SET `token` = 'Scarlet Cheetah';
WHEN '222' THEN SET `token` = 'Zelniak';
WHEN '223' THEN SET `token` = 'Lightcrawler';
WHEN '224' THEN SET `token` = 'Shade';
WHEN '225' THEN SET `token` = 'Sunflower';
WHEN '226' THEN SET `token` = 'Sun Revenant';
WHEN '227' THEN SET `token` = 'Shrieker';
WHEN '228' THEN SET `token` = 'Galorian';
WHEN '229' THEN SET `token` = 'Netherbian';
WHEN '230' THEN SET `token` = 'Akheva';
WHEN '231' THEN SET `token` = 'Grieg Veneficus';
WHEN '232' THEN SET `token` = 'Sonic Wolf';
WHEN '233' THEN SET `token` = 'Ground Shaker';
WHEN '234' THEN SET `token` = 'Vah Shir Skeleton';
WHEN '235' THEN SET `token` = 'Wretch';
WHEN '236' THEN SET `token` = 'Seru';
WHEN '237' THEN SET `token` = 'Recuso';
WHEN '238' THEN SET `token` = 'Vah Shir';
WHEN '239' THEN SET `token` = 'Guard';
WHEN '240' THEN SET `token` = 'Teleport Man';
WHEN '241' THEN SET `token` = 'Werewolf';
WHEN '242' THEN SET `token` = 'Nymph';
WHEN '243' THEN SET `token` = 'Dryad';
WHEN '244' THEN SET `token` = 'Treant';
WHEN '245' THEN SET `token` = 'Fly';
WHEN '246' THEN SET `token` = 'Tarew Marr';
WHEN '247' THEN SET `token` = 'Solusek Ro';
WHEN '248' THEN SET `token` = 'Clockwork Golem';
WHEN '249' THEN SET `token` = 'Clockwork Brain';
WHEN '250' THEN SET `token` = 'Banshee';
WHEN '251' THEN SET `token` = 'Guard of Justice';
WHEN '252' THEN SET `token` = 'Mini POM';
WHEN '253' THEN SET `token` = 'Diseased Fiend';
WHEN '254' THEN SET `token` = 'Solusek Ro Guard';
WHEN '255' THEN SET `token` = 'Bertoxxulous';
WHEN '256' THEN SET `token` = 'The Tribunal';
WHEN '257' THEN SET `token` = 'Terris Thule';
WHEN '258' THEN SET `token` = 'Vegerog';
WHEN '259' THEN SET `token` = 'Crocodile';
WHEN '260' THEN SET `token` = 'Bat';
WHEN '261' THEN SET `token` = 'Hraquis';
WHEN '262' THEN SET `token` = 'Tranquilion';
WHEN '263' THEN SET `token` = 'Tin Soldier';
WHEN '264' THEN SET `token` = 'Nightmare Wraith';
WHEN '265' THEN SET `token` = 'Malarian';
WHEN '266' THEN SET `token` = 'Knight of Pestilence';
WHEN '267' THEN SET `token` = 'Lepertoloth';
WHEN '268' THEN SET `token` = 'Bubonian';
WHEN '269' THEN SET `token` = 'Bubonian Underling';
WHEN '270' THEN SET `token` = 'Pusling';
WHEN '271' THEN SET `token` = 'Water Mephit';
WHEN '272' THEN SET `token` = 'Stormrider';
WHEN '273' THEN SET `token` = 'Junk Beast';
WHEN '274' THEN SET `token` = 'Broken Clockwork';
WHEN '275' THEN SET `token` = 'Giant Clockwork';
WHEN '276' THEN SET `token` = 'Clockwork Beetle';
WHEN '277' THEN SET `token` = 'Nightmare Goblin';
WHEN '278' THEN SET `token` = 'Karana';
WHEN '279' THEN SET `token` = 'Blood Raven';
WHEN '280' THEN SET `token` = 'Nightmare Gargoyle';
WHEN '281' THEN SET `token` = 'Mouth of Insanity';
WHEN '282' THEN SET `token` = 'Skeletal Horse';
WHEN '283' THEN SET `token` = 'Saryrn';
WHEN '284' THEN SET `token` = 'Fennin Ro';
WHEN '285' THEN SET `token` = 'Tormentor';
WHEN '286' THEN SET `token` = 'Soul Devourer';
WHEN '287' THEN SET `token` = 'Nightmare';
WHEN '288' THEN SET `token` = 'Rallos Zek';
WHEN '289' THEN SET `token` = 'Vallon Zek';
WHEN '290' THEN SET `token` = 'Tallon Zek';
WHEN '291' THEN SET `token` = 'Air Mephit';
WHEN '292' THEN SET `token` = 'Earth Mephit';
WHEN '293' THEN SET `token` = 'Fire Mephit';
WHEN '294' THEN SET `token` = 'Nightmare Mephit';
WHEN '295' THEN SET `token` = 'Zebuxoruk';
WHEN '296' THEN SET `token` = 'Mithaniel Marr';
WHEN '297' THEN SET `token` = 'Undead Knight';
WHEN '298' THEN SET `token` = 'The Rathe';
WHEN '299' THEN SET `token` = 'Xegony';
WHEN '300' THEN SET `token` = 'Fiend';
WHEN '301' THEN SET `token` = 'Test Object';
WHEN '302' THEN SET `token` = 'Crab';
WHEN '303' THEN SET `token` = 'Phoenix';
WHEN '304' THEN SET `token` = 'Dragon';
WHEN '305' THEN SET `token` = 'Bear';
WHEN '306' THEN SET `token` = 'Giant';
WHEN '307' THEN SET `token` = 'Giant';
WHEN '308' THEN SET `token` = 'Giant';
WHEN '309' THEN SET `token` = 'Giant';
WHEN '310' THEN SET `token` = 'Giant';
WHEN '311' THEN SET `token` = 'Giant';
WHEN '312' THEN SET `token` = 'Giant';
WHEN '313' THEN SET `token` = 'War Wraith';
WHEN '314' THEN SET `token` = 'Wrulon';
WHEN '315' THEN SET `token` = 'Kraken';
WHEN '316' THEN SET `token` = 'Poison Frog';
WHEN '317' THEN SET `token` = 'Nilborien';
WHEN '318' THEN SET `token` = 'Valorian';
WHEN '319' THEN SET `token` = 'War Boar';
WHEN '320' THEN SET `token` = 'Efreeti';
WHEN '321' THEN SET `token` = 'War Boar';
WHEN '322' THEN SET `token` = 'Valorian';
WHEN '323' THEN SET `token` = 'Animated Armor';
WHEN '324' THEN SET `token` = 'Undead Footman';
WHEN '325' THEN SET `token` = 'Rallos Zek Minion';
WHEN '326' THEN SET `token` = 'Arachnid';
WHEN '327' THEN SET `token` = 'Crystal Spider';
WHEN '328' THEN SET `token` = 'Zebuxoruk\'s Cage';
WHEN '329' THEN SET `token` = 'BoT Portal';
WHEN '330' THEN SET `token` = 'Froglok';
WHEN '331' THEN SET `token` = 'Troll';
WHEN '332' THEN SET `token` = 'Troll';
WHEN '333' THEN SET `token` = 'Troll';
WHEN '334' THEN SET `token` = 'Ghost';
WHEN '335' THEN SET `token` = 'Pirate';
WHEN '336' THEN SET `token` = 'Pirate';
WHEN '337' THEN SET `token` = 'Pirate';
WHEN '338' THEN SET `token` = 'Pirate';
WHEN '339' THEN SET `token` = 'Pirate';
WHEN '340' THEN SET `token` = 'Pirate';
WHEN '341' THEN SET `token` = 'Pirate';
WHEN '342' THEN SET `token` = 'Pirate';
WHEN '343' THEN SET `token` = 'Frog';
WHEN '344' THEN SET `token` = 'Troll Zombie';
WHEN '345' THEN SET `token` = 'Luggald';
WHEN '346' THEN SET `token` = 'Luggald';
WHEN '347' THEN SET `token` = 'Luggalds';
WHEN '348' THEN SET `token` = 'Drogmore';
WHEN '349' THEN SET `token` = 'Froglok Skeleton';
WHEN '350' THEN SET `token` = 'Undead Froglok';
WHEN '351' THEN SET `token` = 'Knight of Hate';
WHEN '352' THEN SET `token` = 'Arcanist of Hate';
WHEN '353' THEN SET `token` = 'Veksar';
WHEN '354' THEN SET `token` = 'Veksar';
WHEN '355' THEN SET `token` = 'Veksar';
WHEN '356' THEN SET `token` = 'Chokidai';
WHEN '357' THEN SET `token` = 'Undead Chokidai';
WHEN '358' THEN SET `token` = 'Undead Veksar';
WHEN '359' THEN SET `token` = 'Vampire';
WHEN '360' THEN SET `token` = 'Vampire';
WHEN '361' THEN SET `token` = 'Rujarkian Orc';
WHEN '362' THEN SET `token` = 'Bone Golem';
WHEN '363' THEN SET `token` = 'Synarcana';
WHEN '364' THEN SET `token` = 'Sand Elf';
WHEN '365' THEN SET `token` = 'Vampire';
WHEN '366' THEN SET `token` = 'Rujarkian Orc';
WHEN '367' THEN SET `token` = 'Skeleton';
WHEN '368' THEN SET `token` = 'Mummy';
WHEN '369' THEN SET `token` = 'Goblin';
WHEN '370' THEN SET `token` = 'Insect';
WHEN '371' THEN SET `token` = 'Froglok Ghost';
WHEN '372' THEN SET `token` = 'Dervish';
WHEN '373' THEN SET `token` = 'Shade';
WHEN '374' THEN SET `token` = 'Golem';
WHEN '375' THEN SET `token` = 'Evil Eye';
WHEN '376' THEN SET `token` = 'Box';
WHEN '377' THEN SET `token` = 'Barrel';
WHEN '378' THEN SET `token` = 'Chest';
WHEN '379' THEN SET `token` = 'Vase';
WHEN '380' THEN SET `token` = 'Table';
WHEN '381' THEN SET `token` = 'Weapon Rack';
WHEN '382' THEN SET `token` = 'Coffin';
WHEN '383' THEN SET `token` = 'Bones';
WHEN '384' THEN SET `token` = 'Jokester';
WHEN '385' THEN SET `token` = 'Nihil';
WHEN '386' THEN SET `token` = 'Trusik';
WHEN '387' THEN SET `token` = 'Stone Worker';
WHEN '388' THEN SET `token` = 'Hynid';
WHEN '389' THEN SET `token` = 'Turepta';
WHEN '390' THEN SET `token` = 'Cragbeast';
WHEN '391' THEN SET `token` = 'Stonemite';
WHEN '392' THEN SET `token` = 'Ukun';
WHEN '393' THEN SET `token` = 'Ixt';
WHEN '394' THEN SET `token` = 'Ikaav';
WHEN '395' THEN SET `token` = 'Aneuk';
WHEN '396' THEN SET `token` = 'Kyv';
WHEN '397' THEN SET `token` = 'Noc';
WHEN '398' THEN SET `token` = 'Ra`tuk';
WHEN '399' THEN SET `token` = 'Taneth';
WHEN '400' THEN SET `token` = 'Huvul';
WHEN '401' THEN SET `token` = 'Mutna';
WHEN '402' THEN SET `token` = 'Mastruq';
WHEN '403' THEN SET `token` = 'Taelosian';
WHEN '404' THEN SET `token` = 'Discord Ship';
WHEN '405' THEN SET `token` = 'Stone Worker';
WHEN '406' THEN SET `token` = 'Mata Muram';
WHEN '407' THEN SET `token` = 'Lightning Warrior';
WHEN '408' THEN SET `token` = 'Succubus';
WHEN '409' THEN SET `token` = 'Bazu';
WHEN '410' THEN SET `token` = 'Feran';
WHEN '411' THEN SET `token` = 'Pyrilen';
WHEN '412' THEN SET `token` = 'Chimera';
WHEN '413' THEN SET `token` = 'Dragorn';
WHEN '414' THEN SET `token` = 'Murkglider';
WHEN '415' THEN SET `token` = 'Rat';
WHEN '416' THEN SET `token` = 'Bat';
WHEN '417' THEN SET `token` = 'Gelidran';
WHEN '418' THEN SET `token` = 'Discordling';
WHEN '419' THEN SET `token` = 'Girplan';
WHEN '420' THEN SET `token` = 'Minotaur';
WHEN '421' THEN SET `token` = 'Dragorn Box';
WHEN '422' THEN SET `token` = 'Runed Orb';
WHEN '423' THEN SET `token` = 'Dragon Bones';
WHEN '424' THEN SET `token` = 'Muramite Armor Pile';
WHEN '425' THEN SET `token` = 'Crystal Shard';
WHEN '426' THEN SET `token` = 'Portal';
WHEN '427' THEN SET `token` = 'Coin Purse';
WHEN '428' THEN SET `token` = 'Rock Pile';
WHEN '429' THEN SET `token` = 'Murkglider Egg Sac';
WHEN '430' THEN SET `token` = 'Drake';
WHEN '431' THEN SET `token` = 'Dervish';
WHEN '432' THEN SET `token` = 'Drake';
WHEN '433' THEN SET `token` = 'Goblin';
WHEN '434' THEN SET `token` = 'Kirin';
WHEN '435' THEN SET `token` = 'Dragon';
WHEN '436' THEN SET `token` = 'Basilisk';
WHEN '437' THEN SET `token` = 'Dragon';
WHEN '438' THEN SET `token` = 'Dragon';
WHEN '439' THEN SET `token` = 'Puma';
WHEN '440' THEN SET `token` = 'Spider';
WHEN '441' THEN SET `token` = 'Spider Queen';
WHEN '442' THEN SET `token` = 'Animated Statue';
WHEN '443' THEN SET `token` = 'UNKNOWN RACE';
WHEN '444' THEN SET `token` = 'UNKNOWN RACE';
WHEN '445' THEN SET `token` = 'Dragon Egg';
WHEN '446' THEN SET `token` = 'Dragon Statue';
WHEN '447' THEN SET `token` = 'Lava Rock';
WHEN '448' THEN SET `token` = 'Animated Statue';
WHEN '449' THEN SET `token` = 'Spider Egg Sack';
WHEN '450' THEN SET `token` = 'Lava Spider';
WHEN '451' THEN SET `token` = 'Lava Spider Queen';
WHEN '452' THEN SET `token` = 'Dragon';
WHEN '453' THEN SET `token` = 'Giant';
WHEN '454' THEN SET `token` = 'Werewolf';
WHEN '455' THEN SET `token` = 'Kobold';
WHEN '456' THEN SET `token` = 'Sporali';
WHEN '457' THEN SET `token` = 'Gnomework';
WHEN '458' THEN SET `token` = 'Orc';
WHEN '459' THEN SET `token` = 'Corathus';
WHEN '460' THEN SET `token` = 'Coral';
WHEN '461' THEN SET `token` = 'Drachnid';
WHEN '462' THEN SET `token` = 'Drachnid Cocoon';
WHEN '463' THEN SET `token` = 'Fungus Patch';
WHEN '464' THEN SET `token` = 'Gargoyle';
WHEN '465' THEN SET `token` = 'Witheran';
WHEN '466' THEN SET `token` = 'Dark Lord';
WHEN '467' THEN SET `token` = 'Shiliskin';
WHEN '468' THEN SET `token` = 'Snake';
WHEN '469' THEN SET `token` = 'Evil Eye';
WHEN '470' THEN SET `token` = 'Minotaur';
WHEN '471' THEN SET `token` = 'Zombie';
WHEN '472' THEN SET `token` = 'Clockwork Boar';
WHEN '473' THEN SET `token` = 'Fairy';
WHEN '474' THEN SET `token` = 'Witheran';
WHEN '475' THEN SET `token` = 'Air Elemental';
WHEN '476' THEN SET `token` = 'Earth Elemental';
WHEN '477' THEN SET `token` = 'Fire Elemental';
WHEN '478' THEN SET `token` = 'Water Elemental';
WHEN '479' THEN SET `token` = 'Alligator';
WHEN '480' THEN SET `token` = 'Bear';
WHEN '481' THEN SET `token` = 'Scaled Wolf';
WHEN '482' THEN SET `token` = 'Wolf';
WHEN '483' THEN SET `token` = 'Spirit Wolf';
WHEN '484' THEN SET `token` = 'Skeleton';
WHEN '485' THEN SET `token` = 'Spectre';
WHEN '486' THEN SET `token` = 'Bolvirk';
WHEN '487' THEN SET `token` = 'Banshee';
WHEN '488' THEN SET `token` = 'Banshee';
WHEN '489' THEN SET `token` = 'Elddar';
WHEN '490' THEN SET `token` = 'Forest Giant';
WHEN '491' THEN SET `token` = 'Bone Golem';
WHEN '492' THEN SET `token` = 'Horse';
WHEN '493' THEN SET `token` = 'Pegasus';
WHEN '494' THEN SET `token` = 'Shambling Mound';
WHEN '495' THEN SET `token` = 'Scrykin';
WHEN '496' THEN SET `token` = 'Treant';
WHEN '497' THEN SET `token` = 'Vampire';
WHEN '498' THEN SET `token` = 'Ayonae Ro';
WHEN '499' THEN SET `token` = 'Sullon Zek';
WHEN '500' THEN SET `token` = 'Banner';
WHEN '501' THEN SET `token` = 'Flag';
WHEN '502' THEN SET `token` = 'Rowboat';
WHEN '503' THEN SET `token` = 'Bear Trap';
WHEN '504' THEN SET `token` = 'Clockwork Bomb';
WHEN '505' THEN SET `token` = 'Dynamite Keg';
WHEN '506' THEN SET `token` = 'Pressure Plate';
WHEN '507' THEN SET `token` = 'Puffer Spore';
WHEN '508' THEN SET `token` = 'Stone Ring';
WHEN '509' THEN SET `token` = 'Root Tentacle';
WHEN '510' THEN SET `token` = 'Runic Symbol';
WHEN '511' THEN SET `token` = 'Saltpetter Bomb';
WHEN '512' THEN SET `token` = 'Floating Skull';
WHEN '513' THEN SET `token` = 'Spike Trap';
WHEN '514' THEN SET `token` = 'Totem';
WHEN '515' THEN SET `token` = 'Web';
WHEN '516' THEN SET `token` = 'Wicker Basket';
WHEN '517' THEN SET `token` = 'Nightmare/Unicorn';
WHEN '518' THEN SET `token` = 'Horse';
WHEN '519' THEN SET `token` = 'Nightmare/Unicorn';
WHEN '520' THEN SET `token` = 'Bixie';
WHEN '521' THEN SET `token` = 'Centaur';
WHEN '522' THEN SET `token` = 'Drakkin';
WHEN '523' THEN SET `token` = 'Giant';
WHEN '524' THEN SET `token` = 'Gnoll';
WHEN '525' THEN SET `token` = 'Griffin';
WHEN '526' THEN SET `token` = 'Giant Shade';
WHEN '527' THEN SET `token` = 'Harpy';
WHEN '528' THEN SET `token` = 'Mammoth';
WHEN '529' THEN SET `token` = 'Satyr';
WHEN '530' THEN SET `token` = 'Dragon';
WHEN '531' THEN SET `token` = 'Dragon';
WHEN '532' THEN SET `token` = 'Dyn\'Leth';
WHEN '533' THEN SET `token` = 'Boat';
WHEN '534' THEN SET `token` = 'Weapon Rack';
WHEN '535' THEN SET `token` = 'Armor Rack';
WHEN '536' THEN SET `token` = 'Honey Pot';
WHEN '537' THEN SET `token` = 'Jum Jum Bucket';
WHEN '538' THEN SET `token` = 'Toolbox';
WHEN '539' THEN SET `token` = 'Stone Jug';
WHEN '540' THEN SET `token` = 'Small Plant';
WHEN '541' THEN SET `token` = 'Medium Plant';
WHEN '542' THEN SET `token` = 'Tall Plant';
WHEN '543' THEN SET `token` = 'Wine Cask';
WHEN '544' THEN SET `token` = 'Elven Boat';
WHEN '545' THEN SET `token` = 'Gnomish Boat';
WHEN '546' THEN SET `token` = 'Barrel Barge Ship';
WHEN '547' THEN SET `token` = 'Goo';
WHEN '548' THEN SET `token` = 'Goo';
WHEN '549' THEN SET `token` = 'Goo';
WHEN '550' THEN SET `token` = 'Merchant Ship';
WHEN '551' THEN SET `token` = 'Pirate Ship';
WHEN '552' THEN SET `token` = 'Ghost Ship';
WHEN '553' THEN SET `token` = 'Banner';
WHEN '554' THEN SET `token` = 'Banner';
WHEN '555' THEN SET `token` = 'Banner';
WHEN '556' THEN SET `token` = 'Banner';
WHEN '557' THEN SET `token` = 'Banner';
WHEN '558' THEN SET `token` = 'Aviak';
WHEN '559' THEN SET `token` = 'Beetle';
WHEN '560' THEN SET `token` = 'Gorilla';
WHEN '561' THEN SET `token` = 'Kedge';
WHEN '562' THEN SET `token` = 'Kerran';
WHEN '563' THEN SET `token` = 'Shissar';
WHEN '564' THEN SET `token` = 'Siren';
WHEN '565' THEN SET `token` = 'Sphinx';
WHEN '566' THEN SET `token` = 'Human';
WHEN '567' THEN SET `token` = 'Campfire';
WHEN '568' THEN SET `token` = 'Brownie';
WHEN '569' THEN SET `token` = 'Dragon';
WHEN '570' THEN SET `token` = 'Exoskeleton';
WHEN '571' THEN SET `token` = 'Ghoul';
WHEN '572' THEN SET `token` = 'Clockwork Guardian';
WHEN '573' THEN SET `token` = 'Mantrap';
WHEN '574' THEN SET `token` = 'Minotaur';
WHEN '575' THEN SET `token` = 'Scarecrow';
WHEN '576' THEN SET `token` = 'Shade';
WHEN '577' THEN SET `token` = 'Rotocopter';
WHEN '578' THEN SET `token` = 'Tentacle Terror';
WHEN '579' THEN SET `token` = 'Wereorc';
WHEN '580' THEN SET `token` = 'Worg';
WHEN '581' THEN SET `token` = 'Wyvern';
WHEN '582' THEN SET `token` = 'Chimera';
WHEN '583' THEN SET `token` = 'Kirin';
WHEN '584' THEN SET `token` = 'Puma';
WHEN '585' THEN SET `token` = 'Boulder';
WHEN '586' THEN SET `token` = 'Banner';
WHEN '587' THEN SET `token` = 'Elven Ghost';
WHEN '588' THEN SET `token` = 'Human Ghost';
WHEN '589' THEN SET `token` = 'Chest';
WHEN '590' THEN SET `token` = 'Chest';
WHEN '591' THEN SET `token` = 'Crystal';
WHEN '592' THEN SET `token` = 'Coffin';
WHEN '593' THEN SET `token` = 'Guardian CPU';
WHEN '594' THEN SET `token` = 'Worg';
WHEN '595' THEN SET `token` = 'Mansion';
WHEN '596' THEN SET `token` = 'Floating Island';
WHEN '597' THEN SET `token` = 'Cragslither';
WHEN '598' THEN SET `token` = 'Wrulon';
WHEN '599' THEN SET `token` = 'Spell Particle 1';
WHEN '600' THEN SET `token` = 'Invisible Man of Zomm';
WHEN '601' THEN SET `token` = 'Robocopter of Zomm';
WHEN '602' THEN SET `token` = 'Burynai';
WHEN '603' THEN SET `token` = 'Frog';
WHEN '604' THEN SET `token` = 'Dracolich';
WHEN '605' THEN SET `token` = 'Iksar Ghost';
WHEN '606' THEN SET `token` = 'Iksar Skeleton';
WHEN '607' THEN SET `token` = 'Mephit';
WHEN '608' THEN SET `token` = 'Muddite';
WHEN '609' THEN SET `token` = 'Raptor';
WHEN '610' THEN SET `token` = 'Sarnak';
WHEN '611' THEN SET `token` = 'Scorpion';
WHEN '612' THEN SET `token` = 'T THEN SET sian';
WHEN '613' THEN SET `token` = 'Wurm';
WHEN '614' THEN SET `token` = 'Nekhon';
WHEN '615' THEN SET `token` = 'Hydra Crystal';
WHEN '616' THEN SET `token` = 'Crystal Sphere';
WHEN '617' THEN SET `token` = 'Gnoll';
WHEN '618' THEN SET `token` = 'Sokokar';
WHEN '619' THEN SET `token` = 'Stone Pylon';
WHEN '620' THEN SET `token` = 'Demon Vulture';
WHEN '621' THEN SET `token` = 'Wagon';
WHEN '622' THEN SET `token` = 'God of Discord';
WHEN '623' THEN SET `token` = 'Feran Mount';
WHEN '624' THEN SET `token` = 'Ogre NPC - Male';
WHEN '625' THEN SET `token` = 'Sokokar Mount';
WHEN '626' THEN SET `token` = 'Giant (Rallosian mats)';
WHEN '627' THEN SET `token` = 'Sokokar (w saddle)';
WHEN '628' THEN SET `token` = '10th Anniversary Banner';
WHEN '629' THEN SET `token` = '10th Anniversary Cake';
WHEN '630' THEN SET `token` = 'Wine Cask';
WHEN '631' THEN SET `token` = 'Hydra Mount';
WHEN '632' THEN SET `token` = 'Hydra NPC';
WHEN '633' THEN SET `token` = 'Wedding Flowers';
WHEN '634' THEN SET `token` = 'Wedding Arbor';
WHEN '635' THEN SET `token` = 'Wedding Altar';
WHEN '636' THEN SET `token` = 'Powder Keg';
WHEN '637' THEN SET `token` = 'Apexus';
WHEN '638' THEN SET `token` = 'Bellikos';
WHEN '639' THEN SET `token` = 'Brell\'s First Creation';
WHEN '640' THEN SET `token` = 'Brell';
WHEN '641' THEN SET `token` = 'Crystalskin Ambuloid';
WHEN '642' THEN SET `token` = 'Cliknar Queen';
WHEN '643' THEN SET `token` = 'Cliknar Soldier';
WHEN '644' THEN SET `token` = 'Cliknar Worker';
WHEN '645' THEN SET `token` = 'Coldain';
WHEN '646' THEN SET `token` = 'Coldain';
WHEN '647' THEN SET `token` = 'Crystalskin Sessiloid';
WHEN '648' THEN SET `token` = 'Genari';
WHEN '649' THEN SET `token` = 'Gigyn';
WHEN '650' THEN SET `token` = 'Greken - Young Adult';
WHEN '651' THEN SET `token` = 'Greken - Young';
WHEN '652' THEN SET `token` = 'Cliknar Mount';
WHEN '653' THEN SET `token` = 'Telmira';
WHEN '654' THEN SET `token` = 'Spider Mount';
WHEN '655' THEN SET `token` = 'Bear Mount';
WHEN '656' THEN SET `token` = 'Rat Mount';
WHEN '657' THEN SET `token` = 'Sessiloid Mount';
WHEN '658' THEN SET `token` = 'Morell Thule';
WHEN '659' THEN SET `token` = 'Marionette';
WHEN '660' THEN SET `token` = 'Book Dervish';
WHEN '661' THEN SET `token` = 'Topiary Lion';
WHEN '662' THEN SET `token` = 'Rotdog';
WHEN '663' THEN SET `token` = 'Amygdalan';
WHEN '664' THEN SET `token` = 'Sandman';
WHEN '665' THEN SET `token` = 'Grandfather Clock';
WHEN '666' THEN SET `token` = 'Gingerbread Man';
WHEN '667' THEN SET `token` = 'Royal Guard';
WHEN '668' THEN SET `token` = 'Rabbit';
WHEN '669' THEN SET `token` = 'Blind Dreamer';
WHEN '670' THEN SET `token` = 'Cazic Thule';
WHEN '671' THEN SET `token` = 'Topiary Lion Mount';
WHEN '672' THEN SET `token` = 'Rot Dog Mount';
WHEN '673' THEN SET `token` = 'Goral Mount';
WHEN '674' THEN SET `token` = 'Selyrah Mount';
WHEN '675' THEN SET `token` = 'Sclera Mount';
WHEN '676' THEN SET `token` = 'Braxi Mount';
WHEN '677' THEN SET `token` = 'Kangon Mount';
WHEN '678' THEN SET `token` = 'Erudite';
WHEN '679' THEN SET `token` = 'Wurm Mount';
WHEN '680' THEN SET `token` = 'Raptor Mount';
WHEN '681' THEN SET `token` = 'Invisible Man';
WHEN '682' THEN SET `token` = 'Whirligig';
WHEN '683' THEN SET `token` = 'Gnomish Balloon';
WHEN '684' THEN SET `token` = 'Gnomish Rocket Pack';
WHEN '685' THEN SET `token` = 'Gnomish Hovering Transport';
WHEN '686' THEN SET `token` = 'Selyrah';
WHEN '687' THEN SET `token` = 'Goral';
WHEN '688' THEN SET `token` = 'Braxi';
WHEN '689' THEN SET `token` = 'Kangon';
WHEN '690' THEN SET `token` = 'Invisible Man';
WHEN '691' THEN SET `token` = 'Floating Tower';
WHEN '692' THEN SET `token` = 'Explosive Cart';
WHEN '693' THEN SET `token` = 'Blimp Ship';
WHEN '694' THEN SET `token` = 'Tumbleweed';
WHEN '695' THEN SET `token` = 'Alaran';
WHEN '696' THEN SET `token` = 'Swinetor';
WHEN '697' THEN SET `token` = 'Triumvirate';
WHEN '698' THEN SET `token` = 'Hadal';
WHEN '699' THEN SET `token` = 'Hovering Platform';
WHEN '700' THEN SET `token` = 'Parasitic Scavenger';
WHEN '701' THEN SET `token` = 'Grendlaen';
WHEN '702' THEN SET `token` = 'Ship in a Bottle';
WHEN '703' THEN SET `token` = 'Alaran Sentry Stone';
WHEN '704' THEN SET `token` = 'Dervish';
WHEN '705' THEN SET `token` = 'Regeneration Pool';
WHEN '706' THEN SET `token` = 'Teleportation Stand';
WHEN '707' THEN SET `token` = 'Relic Case';
WHEN '708' THEN SET `token` = 'Alaran Ghost';
WHEN '709' THEN SET `token` = 'Skystrider';
WHEN '710' THEN SET `token` = 'Water Spout';
WHEN '711' THEN SET `token` = 'Aviak Pull Along';
WHEN '712' THEN SET `token` = 'Gelatinous Cube';
WHEN '713' THEN SET `token` = 'Cat';
WHEN '714' THEN SET `token` = 'Elk Head';
WHEN '715' THEN SET `token` = 'Holgresh';
WHEN '716' THEN SET `token` = 'Beetle';
WHEN '717' THEN SET `token` = 'Vine Maw';
WHEN '718' THEN SET `token` = 'Ratman';
WHEN '719' THEN SET `token` = 'Fallen Knight';
WHEN '720' THEN SET `token` = 'Flying Carpet';
WHEN '721' THEN SET `token` = 'Carrier Hand';
WHEN '722' THEN SET `token` = 'Akheva';
WHEN '723' THEN SET `token` = 'Servant of Shadow';
WHEN '724' THEN SET `token` = 'Luclin';
WHEN '725' THEN SET `token` = 'Xaric the Unspoken';
WHEN '726' THEN SET `token` = 'Dervish (Ver. 5)';
WHEN '727' THEN SET `token` = 'Dervish (Ver. 6)';
WHEN '728' THEN SET `token` = 'God - Luclin (Ver. 2)';
WHEN '729' THEN SET `token` = 'God - Luclin (Ver. 3)';
WHEN '730' THEN SET `token` = 'Orb';
WHEN '731' THEN SET `token` = 'God - Luclin (Ver. 4)';
WHEN '732' THEN SET `token` = 'Pegasus';
WHEN '2250' THEN SET `token` = 'Interactive Object';
ELSE SET `token` = 'unk';
END CASE;
SET `token` = CONCAT(`token`, '(', `race_id`, ')');
RETURN `token`;
END$$
DELIMITER ;
@@ -0,0 +1,71 @@
DELIMITER $$
DROP FUNCTION IF EXISTS `GetSpellAffectIndexToken`;
-- This function converts a numeric spell affect index id to a string label based on server code designations
--
-- example:
-- SELECT `id`, `name`, GetSpellAffectIndexToken(`SpellAffectIndex`) FROM `spells_new` WHERE `id` IN ('73', '2253', '2319');
CREATE FUNCTION `GetSpellAffectIndexToken` (`affect_index_id` INT(11)) RETURNS VARCHAR(64)
BEGIN
DECLARE `token` VARCHAR(64) DEFAULT '';
CASE `affect_index_id`
WHEN '-1' THEN SET `token` = 'SAI_Summon_Mount_Unclass';
WHEN '0' THEN SET `token` = 'SAI_Direct_Damage';
WHEN '1' THEN SET `token` = 'SAI_Heal_Cure';
WHEN '2' THEN SET `token` = 'SAI_AC_Buff';
WHEN '3' THEN SET `token` = 'SAI_AE_Damage';
WHEN '4' THEN SET `token` = 'SAI_Summon';
WHEN '5' THEN SET `token` = 'SAI_Sight';
WHEN '6' THEN SET `token` = 'SAI_Mana_Regen_Resist_Song';
WHEN '7' THEN SET `token` = 'SAI_Stat_Buff';
WHEN '9' THEN SET `token` = 'SAI_Vanish';
WHEN '10' THEN SET `token` = 'SAI_Appearance';
WHEN '11' THEN SET `token` = 'SAI_Enchanter_Pet';
WHEN '12' THEN SET `token` = 'SAI_Calm';
WHEN '13' THEN SET `token` = 'SAI_Fear';
WHEN '14' THEN SET `token` = 'SAI_Dispell_Sight';
WHEN '15' THEN SET `token` = 'SAI_Stun';
WHEN '16' THEN SET `token` = 'SAI_Haste_Runspeed';
WHEN '17' THEN SET `token` = 'SAI_Combat_Slow';
WHEN '18' THEN SET `token` = 'SAI_Damage_Shield';
WHEN '19' THEN SET `token` = 'SAI_Cannibalize_Weapon_Proc';
WHEN '20' THEN SET `token` = 'SAI_Weaken';
WHEN '21' THEN SET `token` = 'SAI_Banish';
WHEN '22' THEN SET `token` = 'SAI_Blind_Poison';
WHEN '23' THEN SET `token` = 'SAI_Cold_DD';
WHEN '24' THEN SET `token` = 'SAI_Poison_Disease_DD';
WHEN '25' THEN SET `token` = 'SAI_Fire_DD';
WHEN '27' THEN SET `token` = 'SAI_Memory_Blur';
WHEN '28' THEN SET `token` = 'SAI_Gravity_Fling';
WHEN '29' THEN SET `token` = 'SAI_Suffocate';
WHEN '30' THEN SET `token` = 'SAI_Lifetap_Over_Time';
WHEN '31' THEN SET `token` = 'SAI_Fire_AE';
WHEN '33' THEN SET `token` = 'SAI_Cold_AE';
WHEN '34' THEN SET `token` = 'SAI_Poison_Disease_AE';
WHEN '40' THEN SET `token` = 'SAI_Teleport';
WHEN '41' THEN SET `token` = 'SAI_Direct_Damage_Song';
WHEN '42' THEN SET `token` = 'SAI_Combat_Buff_Song';
WHEN '43' THEN SET `token` = 'SAI_Calm_Song';
WHEN '45' THEN SET `token` = 'SAI_Firework';
WHEN '46' THEN SET `token` = 'SAI_Firework_AE';
WHEN '47' THEN SET `token` = 'SAI_Weather_Rocket';
WHEN '50' THEN SET `token` = 'SAI_Convert_Vitals';
WHEN '60' THEN SET `token` = 'SAI_NPC_Special_60';
WHEN '61' THEN SET `token` = 'SAI_NPC_Special_61';
WHEN '62' THEN SET `token` = 'SAI_NPC_Special_62';
WHEN '63' THEN SET `token` = 'SAI_NPC_Special_63';
WHEN '70' THEN SET `token` = 'SAI_NPC_Special_70';
WHEN '71' THEN SET `token` = 'SAI_NPC_Special_71';
WHEN '80' THEN SET `token` = 'SAI_NPC_Special_80';
WHEN '88' THEN SET `token` = 'SAI_Lock_Trap';
ELSE SET `token` = 'unk';
END CASE;
SET `token` = CONCAT(`token`, '(', `affect_index_id`, ')');
RETURN `token`;
END$$
DELIMITER ;
@@ -0,0 +1,206 @@
DELIMITER $$
DROP FUNCTION IF EXISTS `GetSpellCategoryToken`;
-- This function converts numeric spell category ids to a string label based on server code designations
--
-- example:
-- SELECT `id`, `name`, GetSpellCategoryToken(`spell_category`) FROM `spells_new` WHERE `id` IN ('39', '129', '3468');
CREATE FUNCTION `GetSpellCategoryToken` (`spell_category` INT(11)) RETURNS VARCHAR(256)
BEGIN
DECLARE `token` VARCHAR(256) DEFAULT '';
CASE `spell_category`
WHEN '-99' THEN SET `token` = 'neg99#';
WHEN '-1' THEN SET `token` = 'neg1#';
WHEN '0' THEN SET `token` = CONCAT('#', `spell_category`);
WHEN '1' THEN SET `token` = 'DD';
WHEN '2' THEN SET `token` = 'DD_Undead';
WHEN '3' THEN SET `token` = 'DD_Summoned';
WHEN '4' THEN SET `token` = 'Lifetap_to_Self';
WHEN '5' THEN SET `token` = 'DoT_Plant';
WHEN '6' THEN SET `token` = 'DD_Body_Type';
WHEN '7' THEN SET `token` = 'DoT';
WHEN '8' THEN SET `token` = 'Divine_DoT';
WHEN '9' THEN SET `token` = 'Lifetap_to_Self_2';
WHEN '10' THEN SET `token` = 'AoE_DD';
WHEN '11' THEN SET `token` = 'AoE_DD_Earth';
WHEN '12' THEN SET `token` = 'AoE_DD_Nature';
WHEN '13' THEN SET `token` = 'Bolt_Fire_Cold';
WHEN '14' THEN SET `token` = 'Stun_Damage';
WHEN '15' THEN SET `token` = 'Target_Stun';
WHEN '16' THEN SET `token` = 'Group_Stun';
WHEN '17' THEN SET `token` = 'Leech_to_Group';
WHEN '18' THEN SET `token` = 'Siphon_Strength';
WHEN '19' THEN SET `token` = 'Weapon_Proc';
WHEN '20' THEN SET `token` = 'Target_Heal';
WHEN '21' THEN SET `token` = 'Target_HoT';
WHEN '22' THEN SET `token` = 'Group_Heal_Cure';
WHEN '23' THEN SET `token` = 'Group_HoT';
WHEN '24' THEN SET `token` = 'Target_Health_Regen';
WHEN '25' THEN SET `token` = 'Group_Health_Regen';
WHEN '26' THEN SET `token` = 'Pet_Heal';
WHEN '27' THEN SET `token` = 'Resurrection';
WHEN '28' THEN SET `token` = 'Dark_Empathy';
WHEN '29' THEN SET `token` = 'Cure_Poison';
WHEN '30' THEN SET `token` = 'Resolution';
WHEN '32' THEN SET `token` = 'Blur';
WHEN '34' THEN SET `token` = 'Hate_Buff';
WHEN '35' THEN SET `token` = 'Attack_Speed_Buff';
WHEN '36' THEN SET `token` = 'Pet_Combat_Buff';
WHEN '37' THEN SET `token` = 'Attack_Speed_Buff_Song';
WHEN '38' THEN SET `token` = 'Attack_Speed_Debuff';
WHEN '39' THEN SET `token` = 'Attack_Speed_Debuff_2';
WHEN '40' THEN SET `token` = 'Cannibalize';
WHEN '41' THEN SET `token` = 'Target_Movement_Speed';
WHEN '42' THEN SET `token` = 'Group_Movement_Speed';
WHEN '43' THEN SET `token` = 'Wolf_Form';
WHEN '44' THEN SET `token` = 'Elemental_Pet_Movement_Speed';
WHEN '45' THEN SET `token` = 'Illusion';
WHEN '46' THEN SET `token` = 'Dark_Pact';
WHEN '47' THEN SET `token` = 'Form_of_the_Bear';
WHEN '48' THEN SET `token` = 'Treeform';
WHEN '49' THEN SET `token` = 'Dead_Man_Floating';
WHEN '50' THEN SET `token` = 'Root';
WHEN '51' THEN SET `token` = 'Summon_Pet';
WHEN '52' THEN SET `token` = 'Summon_Corpse';
WHEN '53' THEN SET `token` = 'Sense';
WHEN '54' THEN SET `token` = 'Divine_Aura';
WHEN '55' THEN SET `token` = 'Evacuate';
WHEN '56' THEN SET `token` = 'Gate';
WHEN '58' THEN SET `token` = 'Teleport_Bind';
WHEN '59' THEN SET `token` = 'Shadow_Step';
WHEN '60' THEN SET `token` = 'Enchant_Material';
WHEN '61' THEN SET `token` = 'Summon_Common_Item';
WHEN '62' THEN SET `token` = 'Fear';
WHEN '63' THEN SET `token` = 'Fear_Animal';
WHEN '64' THEN SET `token` = 'Fear_Undead';
WHEN '65' THEN SET `token` = 'Damage_Shield';
WHEN '66' THEN SET `token` = 'Resist_Buff_Song';
WHEN '67' THEN SET `token` = CONCAT('#', `spell_category`);
WHEN '68' THEN SET `token` = 'Damage_Shield_2';
WHEN '69' THEN SET `token` = 'Resist_Redux';
WHEN '70' THEN SET `token` = 'Resist_Buff';
WHEN '71' THEN SET `token` = 'Warder';
WHEN '72' THEN SET `token` = 'Familiar';
WHEN '73' THEN SET `token` = 'Strength_Buff';
WHEN '74' THEN SET `token` = 'Dexterity_Buff';
WHEN '75' THEN SET `token` = 'Agility_Buff';
WHEN '76' THEN SET `token` = 'Stamina_Buff';
WHEN '77' THEN SET `token` = 'Intelligence_Wisdom_Buff';
WHEN '78' THEN SET `token` = 'Charisma_Buff';
WHEN '79' THEN SET `token` = 'Weaken';
WHEN '80' THEN SET `token` = 'Invisibility_v_Undead';
WHEN '81' THEN SET `token` = 'Invisibility_v_Animals';
WHEN '82' THEN SET `token` = 'Invisibility';
WHEN '83' THEN SET `token` = 'Damage_Absorbtion';
WHEN '84' THEN SET `token` = 'Fizzle_Redux';
WHEN '85' THEN SET `token` = 'Clarity';
WHEN '86' THEN SET `token` = 'Gift_of_Magic';
WHEN '87' THEN SET `token` = 'Mana_Drain';
WHEN '88' THEN SET `token` = 'Mana_Subversion';
WHEN '89' THEN SET `token` = 'Harvest_Mana';
WHEN '90' THEN SET `token` = 'Hate_Redux';
WHEN '91' THEN SET `token` = 'Increase_Aim';
WHEN '92' THEN SET `token` = 'Combat_Buff';
WHEN '93' THEN SET `token` = 'Bind_Sight';
WHEN '94' THEN SET `token` = 'Enduring_Breath';
WHEN '95' THEN SET `token` = 'Alliance';
WHEN '96' THEN SET `token` = 'Charm';
WHEN '97' THEN SET `token` = 'Strip_Enchantment';
WHEN '98' THEN SET `token` = 'Lull';
WHEN '99' THEN SET `token` = 'Mesmerize';
WHEN '100' THEN SET `token` = 'Casting_Enhancement';
WHEN '101' THEN SET `token` = 'Snare_Hamstring';
WHEN '102' THEN SET `token` = 'Shackle';
WHEN '105' THEN SET `token` = 'Feign_Death';
WHEN '106' THEN SET `token` = 'Identify';
WHEN '107' THEN SET `token` = 'Reclaim_Energy';
WHEN '108' THEN SET `token` = 'Locate_Corpse';
WHEN '109' THEN SET `token` = 'Call_of_the_Hero';
WHEN '110' THEN SET `token` = 'Mana_Shield';
WHEN '112' THEN SET `token` = 'Blind';
WHEN '113' THEN SET `token` = 'Gravity_is_for_Suckers'; -- 'Levitation'
WHEN '114' THEN SET `token` = 'Bard_Nerf';
WHEN '115' THEN SET `token` = 'Divine_Intervention';
WHEN '116' THEN SET `token` = 'Memory_Blur';
WHEN '118' THEN SET `token` = 'Size_Change';
WHEN '119' THEN SET `token` = 'Hate_Buff_2';
WHEN '120' THEN SET `token` = CONCAT('#', `spell_category`);
WHEN '121' THEN SET `token` = CONCAT('#', `spell_category`);
WHEN '122' THEN SET `token` = CONCAT('#', `spell_category`);
WHEN '125' THEN SET `token` = 'DD_Fire';
WHEN '126' THEN SET `token` = 'DD_Cold';
WHEN '127' THEN SET `token` = 'Bolt_Poison';
WHEN '128' THEN SET `token` = 'Bolt_Disease';
WHEN '129' THEN SET `token` = 'DoT_Fire';
WHEN '130' THEN SET `token` = 'DoT_Cold';
WHEN '131' THEN SET `token` = 'DoT_Poison';
WHEN '132' THEN SET `token` = 'DoT_Disease';
WHEN '133' THEN SET `token` = 'Destroy_Lock';
WHEN '134' THEN SET `token` = 'Sense_Trap';
WHEN '135' THEN SET `token` = 'Disarm_Trap';
WHEN '136' THEN SET `token` = 'Destroy_Cursed_Lock';
WHEN '137' THEN SET `token` = 'Sense_Cursed_Trap';
WHEN '138' THEN SET `token` = 'Disarm_Cursed_Trap';
WHEN '140' THEN SET `token` = 'Banish_Undead';
WHEN '141' THEN SET `token` = 'Banish';
WHEN '142' THEN SET `token` = 'AoE_DD_Fire_Column';
WHEN '143' THEN SET `token` = 'AoE_DD_Cold_Column';
WHEN '146' THEN SET `token` = 'AoE_DD_Fire';
WHEN '147' THEN SET `token` = 'AoE_DD_Cold';
WHEN '150' THEN SET `token` = 'AoE_DoT_Fire';
WHEN '151' THEN SET `token` = 'AoE_DoT_Cold';
WHEN '152' THEN SET `token` = 'AoE_DoT_Poison';
WHEN '154' THEN SET `token` = 'AoE_Fear_Song';
WHEN '155' THEN SET `token` = 'Target_Heal_2';
WHEN '156' THEN SET `token` = 'Mana_to_HP';
WHEN '157' THEN SET `token` = 'Symbiosis';
WHEN '159' THEN SET `token` = 'Cure_Corruption';
WHEN '160' THEN SET `token` = 'Remove_Curse';
WHEN '161' THEN SET `token` = 'Cure';
WHEN '162' THEN SET `token` = 'Cure_Blindness';
WHEN '163' THEN SET `token` = 'Divine_Cure';
WHEN '164' THEN SET `token` = CONCAT('#', `spell_category`);
WHEN '165' THEN SET `token` = 'Magic_Combat_Buff';
WHEN '166' THEN SET `token` = 'Nature_HP_Attack_Buff';
WHEN '167' THEN SET `token` = 'Divine_HP_Buff';
WHEN '168' THEN SET `token` = 'Divine_HP_AC_Buff';
WHEN '169' THEN SET `token` = CONCAT('#', `spell_category`);
WHEN '170' THEN SET `token` = 'Spell_Rune';
WHEN '171' THEN SET `token` = 'Pet_Rune';
WHEN '172' THEN SET `token` = 'Spell_Reflection';
WHEN '173' THEN SET `token` = 'Damage_Shield_3';
WHEN '174' THEN SET `token` = 'Vital_Regen';
WHEN '175' THEN SET `token` = 'Aggro_Redux';
WHEN '200' THEN SET `token` = 'Cantrips';
WHEN '201' THEN SET `token` = CONCAT('#', `spell_category`);
WHEN '202' THEN SET `token` = 'Combat_Buff_Song';
WHEN '203' THEN SET `token` = 'Summon_Swarm';
WHEN '204' THEN SET `token` = 'Summon_Air_Elemental';
WHEN '205' THEN SET `token` = 'Summon_Water_Elemental';
WHEN '206' THEN SET `token` = 'Summon_Fire_Elemental';
WHEN '207' THEN SET `token` = 'Summon_Earth_Elemental';
WHEN '208' THEN SET `token` = 'Monster_Summoning';
WHEN '209' THEN SET `token` = 'Teleport_Antonica';
WHEN '210' THEN SET `token` = 'Teleport_Odus';
WHEN '211' THEN SET `token` = 'Teleport_Faydwer';
WHEN '212' THEN SET `token` = 'Teleport_Combine';
WHEN '213' THEN SET `token` = 'Teleport_Velious';
WHEN '214' THEN SET `token` = 'Teleport_Luclin';
WHEN '215' THEN SET `token` = 'Teleport_Planes';
WHEN '216' THEN SET `token` = 'Teleport_Gates';
WHEN '217' THEN SET `token` = 'Summon_Weapon';
WHEN '218' THEN SET `token` = 'Summon_Jewelry';
WHEN '219' THEN SET `token` = 'Summon_Sustenance';
WHEN '220' THEN SET `token` = 'Summon_Armor';
WHEN '999' THEN SET `token` = CONCAT('#', `spell_category`);
ELSE SET `token` = 'unk';
END CASE;
SET `token` = CONCAT(`token`, '(', `spell_category`, ')');
RETURN `token`;
END$$
DELIMITER ;
@@ -0,0 +1,519 @@
DELIMITER $$
DROP FUNCTION IF EXISTS `GetSpellEffectToken`;
-- This function converts a numeric spell effect id to a string label based on server code designations
--
-- example:
-- SELECT `id`, `name`, GetSpellEffectToken(`effectid1`), GetSpellEffectToken(`effectid2`) FROM `spells_new` WHERE `id` IN ('1011', '1602', '11091');
CREATE FUNCTION `GetSpellEffectToken` (`effect_id` INT(11)) RETURNS VARCHAR(64)
BEGIN
DECLARE `token` VARCHAR(64) DEFAULT '';
CASE `effect_id`
WHEN '0' THEN SET `token` = 'SE_CurrentHP';
WHEN '1' THEN SET `token` = 'SE_ArmorClass';
WHEN '2' THEN SET `token` = 'SE_ATK';
WHEN '3' THEN SET `token` = 'SE_MovementSpeed';
WHEN '4' THEN SET `token` = 'SE_STR';
WHEN '5' THEN SET `token` = 'SE_DEX';
WHEN '6' THEN SET `token` = 'SE_AGI';
WHEN '7' THEN SET `token` = 'SE_STA';
WHEN '8' THEN SET `token` = 'SE_INT';
WHEN '9' THEN SET `token` = 'SE_WIS';
WHEN '10' THEN SET `token` = 'SE_CHA';
WHEN '11' THEN SET `token` = 'SE_AttackSpeed';
WHEN '12' THEN SET `token` = 'SE_Invisibility';
WHEN '13' THEN SET `token` = 'SE_SeeInvis';
WHEN '14' THEN SET `token` = 'SE_WaterBreathing';
WHEN '15' THEN SET `token` = 'SE_CurrentMana';
WHEN '16' THEN SET `token` = 'NI_NPCFrenzy';
WHEN '17' THEN SET `token` = 'NI_NPCAwareness';
WHEN '18' THEN SET `token` = 'SE_Lull';
WHEN '19' THEN SET `token` = 'SE_AddFaction';
WHEN '20' THEN SET `token` = 'SE_Blind';
WHEN '21' THEN SET `token` = 'SE_Stun';
WHEN '22' THEN SET `token` = 'SE_Charm';
WHEN '23' THEN SET `token` = 'SE_Fear';
WHEN '24' THEN SET `token` = 'SE_Stamina';
WHEN '25' THEN SET `token` = 'SE_BindAffinity';
WHEN '26' THEN SET `token` = 'SE_Gate';
WHEN '27' THEN SET `token` = 'SE_CancelMagic';
WHEN '28' THEN SET `token` = 'SE_InvisVsUndead';
WHEN '29' THEN SET `token` = 'SE_InvisVsAnimals';
WHEN '30' THEN SET `token` = 'SE_ChangeFrenzyRad';
WHEN '31' THEN SET `token` = 'SE_Mez';
WHEN '32' THEN SET `token` = 'SE_SummonItem';
WHEN '33' THEN SET `token` = 'SE_SummonPet';
WHEN '34' THEN SET `token` = 'NI_Confuse';
WHEN '35' THEN SET `token` = 'SE_DiseaseCounter';
WHEN '36' THEN SET `token` = 'SE_PoisonCounter';
WHEN '37' THEN SET `token` = 'NI_DetectHostile';
WHEN '38' THEN SET `token` = 'NI_DetectMagic';
WHEN '39' THEN SET `token` = 'NI_DetectPoison';
WHEN '40' THEN SET `token` = 'SE_DivineAura';
WHEN '41' THEN SET `token` = 'SE_Destroy';
WHEN '42' THEN SET `token` = 'SE_ShadowStep';
WHEN '43' THEN SET `token` = 'SE_Berserk';
WHEN '44' THEN SET `token` = 'SE_Lycanthropy';
WHEN '45' THEN SET `token` = 'SE_Vampirism';
WHEN '46' THEN SET `token` = 'SE_ResistFire';
WHEN '47' THEN SET `token` = 'SE_ResistCold';
WHEN '48' THEN SET `token` = 'SE_ResistPoison';
WHEN '49' THEN SET `token` = 'SE_ResistDisease';
WHEN '50' THEN SET `token` = 'SE_ResistMagic';
WHEN '51' THEN SET `token` = 'NI_DetectTraps';
WHEN '52' THEN SET `token` = 'SE_SenseDead';
WHEN '53' THEN SET `token` = 'SE_SenseSummoned';
WHEN '54' THEN SET `token` = 'SE_SenseAnimals';
WHEN '55' THEN SET `token` = 'SE_Rune';
WHEN '56' THEN SET `token` = 'SE_TrueNorth';
WHEN '57' THEN SET `token` = 'SE_Levitate';
WHEN '58' THEN SET `token` = 'SE_Illusion';
WHEN '59' THEN SET `token` = 'SE_DamageShield';
WHEN '60' THEN SET `token` = 'NI_TransferItem';
WHEN '61' THEN SET `token` = 'SE_Identify';
WHEN '62' THEN SET `token` = 'NI_ItemID';
WHEN '63' THEN SET `token` = 'SE_WipeHateList';
WHEN '64' THEN SET `token` = 'SE_SpinTarget';
WHEN '65' THEN SET `token` = 'SE_InfraVision';
WHEN '66' THEN SET `token` = 'SE_UltraVision';
WHEN '67' THEN SET `token` = 'SE_EyeOfZomm';
WHEN '68' THEN SET `token` = 'SE_ReclaimPet';
WHEN '69' THEN SET `token` = 'SE_TotalHP';
WHEN '70' THEN SET `token` = 'NI_CorpseBomb';
WHEN '71' THEN SET `token` = 'SE_NecPet';
WHEN '72' THEN SET `token` = 'NI_PreserveCorpse';
WHEN '73' THEN SET `token` = 'SE_BindSight';
WHEN '74' THEN SET `token` = 'SE_FeignDeath';
WHEN '75' THEN SET `token` = 'SE_VoiceGraft';
WHEN '76' THEN SET `token` = 'SE_Sentinel';
WHEN '77' THEN SET `token` = 'SE_LocateCorpse';
WHEN '78' THEN SET `token` = 'SE_AbsorbMagicAtt';
WHEN '79' THEN SET `token` = 'SE_CurrentHPOnce';
WHEN '80' THEN SET `token` = 'NI_EnchantLight';
WHEN '81' THEN SET `token` = 'SE_Revive';
WHEN '82' THEN SET `token` = 'SE_SummonPC';
WHEN '83' THEN SET `token` = 'SE_Teleport';
WHEN '84' THEN SET `token` = 'SE_TossUp';
WHEN '85' THEN SET `token` = 'SE_WeaponProc';
WHEN '86' THEN SET `token` = 'SE_Harmony';
WHEN '87' THEN SET `token` = 'SE_MagnifyVision';
WHEN '88' THEN SET `token` = 'SE_Succor';
WHEN '89' THEN SET `token` = 'SE_ModelSize';
WHEN '90' THEN SET `token` = 'NI_Cloak';
WHEN '91' THEN SET `token` = 'SE_SummonCorpse';
WHEN '92' THEN SET `token` = 'SE_InstantHate';
WHEN '93' THEN SET `token` = 'SE_StopRain';
WHEN '94' THEN SET `token` = 'SE_NegateIfCombat';
WHEN '95' THEN SET `token` = 'SE_Sacrifice';
WHEN '96' THEN SET `token` = 'SE_Silence';
WHEN '97' THEN SET `token` = 'SE_ManaPool';
WHEN '98' THEN SET `token` = 'SE_AttackSpeed2';
WHEN '99' THEN SET `token` = 'SE_Root';
WHEN '100' THEN SET `token` = 'SE_HealOverTime';
WHEN '101' THEN SET `token` = 'SE_CompleteHeal';
WHEN '102' THEN SET `token` = 'SE_Fearless';
WHEN '103' THEN SET `token` = 'SE_CallPet';
WHEN '104' THEN SET `token` = 'SE_Translocate';
WHEN '105' THEN SET `token` = 'SE_AntiGate';
WHEN '106' THEN SET `token` = 'SE_SummonBSTPet';
WHEN '107' THEN SET `token` = 'SE_AlterNPCLevel';
WHEN '108' THEN SET `token` = 'SE_Familiar';
WHEN '109' THEN SET `token` = 'SE_SummonItemIntoBag';
WHEN '110' THEN SET `token` = 'NI_IncreaseArchery';
WHEN '111' THEN SET `token` = 'SE_ResistAll';
WHEN '112' THEN SET `token` = 'SE_CastingLevel';
WHEN '113' THEN SET `token` = 'SE_SummonHorse';
WHEN '114' THEN SET `token` = 'SE_ChangeAggro';
WHEN '115' THEN SET `token` = 'SE_Hunger';
WHEN '116' THEN SET `token` = 'SE_CurseCounter';
WHEN '117' THEN SET `token` = 'SE_MagicWeapon';
WHEN '118' THEN SET `token` = 'SE_Amplification';
WHEN '119' THEN SET `token` = 'SE_AttackSpeed3';
WHEN '120' THEN SET `token` = 'SE_HealRate';
WHEN '121' THEN SET `token` = 'SE_ReverseDS';
WHEN '122' THEN SET `token` = 'NI_ReduceSkill';
WHEN '123' THEN SET `token` = 'SE_Screech';
WHEN '124' THEN SET `token` = 'SE_ImprovedDamage';
WHEN '125' THEN SET `token` = 'SE_ImprovedHeal';
WHEN '126' THEN SET `token` = 'SE_SpellResistReduction';
WHEN '127' THEN SET `token` = 'SE_IncreaseSpellHaste';
WHEN '128' THEN SET `token` = 'SE_IncreaseSpellDuration';
WHEN '129' THEN SET `token` = 'SE_IncreaseRange';
WHEN '130' THEN SET `token` = 'SE_SpellHateMod';
WHEN '131' THEN SET `token` = 'SE_ReduceReagentCost';
WHEN '132' THEN SET `token` = 'SE_ReduceManaCost';
WHEN '133' THEN SET `token` = 'SE_FcStunTimeMod';
WHEN '134' THEN SET `token` = 'SE_LimitMaxLevel';
WHEN '135' THEN SET `token` = 'SE_LimitResist';
WHEN '136' THEN SET `token` = 'SE_LimitTarget';
WHEN '137' THEN SET `token` = 'SE_LimitEffect';
WHEN '138' THEN SET `token` = 'SE_LimitSpellType';
WHEN '139' THEN SET `token` = 'SE_LimitSpell';
WHEN '140' THEN SET `token` = 'SE_LimitMinDur';
WHEN '141' THEN SET `token` = 'SE_LimitInstant';
WHEN '142' THEN SET `token` = 'SE_LimitMinLevel';
WHEN '143' THEN SET `token` = 'SE_LimitCastTimeMin';
WHEN '144' THEN SET `token` = 'SE_LimitCastTimeMax';
WHEN '145' THEN SET `token` = 'SE_Teleport2';
WHEN '146' THEN SET `token` = 'NI_ElectricityResist';
WHEN '147' THEN SET `token` = 'SE_PercentalHeal';
WHEN '148' THEN SET `token` = 'SE_StackingCommand_Block';
WHEN '149' THEN SET `token` = 'SE_StackingCommand_Overwrite';
WHEN '150' THEN SET `token` = 'SE_DeathSave';
WHEN '151' THEN SET `token` = 'SE_SuspendPet';
WHEN '152' THEN SET `token` = 'SE_TemporaryPets';
WHEN '153' THEN SET `token` = 'SE_BalanceHP';
WHEN '154' THEN SET `token` = 'SE_DispelDetrimental';
WHEN '155' THEN SET `token` = 'SE_SpellCritDmgIncrease';
WHEN '156' THEN SET `token` = 'SE_IllusionCopy';
WHEN '157' THEN SET `token` = 'SE_SpellDamageShield';
WHEN '158' THEN SET `token` = 'SE_Reflect';
WHEN '159' THEN SET `token` = 'SE_AllStats';
WHEN '160' THEN SET `token` = 'NI_MakeDrunk';
WHEN '161' THEN SET `token` = 'SE_MitigateSpellDamage';
WHEN '162' THEN SET `token` = 'SE_MitigateMeleeDamage';
WHEN '163' THEN SET `token` = 'SE_NegateAttacks';
WHEN '164' THEN SET `token` = 'SE_AppraiseLDonChest';
WHEN '165' THEN SET `token` = 'SE_DisarmLDoNTrap';
WHEN '166' THEN SET `token` = 'SE_UnlockLDoNChest';
WHEN '167' THEN SET `token` = 'SE_PetPowerIncrease';
WHEN '168' THEN SET `token` = 'SE_MeleeMitigation';
WHEN '169' THEN SET `token` = 'SE_CriticalHitChance';
WHEN '170' THEN SET `token` = 'SE_SpellCritChance';
WHEN '171' THEN SET `token` = 'SE_CrippBlowChance';
WHEN '172' THEN SET `token` = 'SE_AvoidMeleeChance';
WHEN '173' THEN SET `token` = 'SE_RiposteChance';
WHEN '174' THEN SET `token` = 'SE_DodgeChance';
WHEN '175' THEN SET `token` = 'SE_ParryChance';
WHEN '176' THEN SET `token` = 'SE_DualWieldChance';
WHEN '177' THEN SET `token` = 'SE_DoubleAttackChance';
WHEN '178' THEN SET `token` = 'SE_MeleeLifetap';
WHEN '179' THEN SET `token` = 'SE_AllInstrumentMod';
WHEN '180' THEN SET `token` = 'SE_ResistSpellChance';
WHEN '181' THEN SET `token` = 'SE_ResistFearChance';
WHEN '182' THEN SET `token` = 'SE_HundredHands';
WHEN '183' THEN SET `token` = 'SE_MeleeSkillCheck';
WHEN '184' THEN SET `token` = 'SE_HitChance';
WHEN '185' THEN SET `token` = 'SE_DamageModifier';
WHEN '186' THEN SET `token` = 'SE_MinDamageModifier';
WHEN '187' THEN SET `token` = 'SE_BalanceMana';
WHEN '188' THEN SET `token` = 'SE_IncreaseBlockChance';
WHEN '189' THEN SET `token` = 'SE_CurrentEndurance';
WHEN '190' THEN SET `token` = 'SE_EndurancePool';
WHEN '191' THEN SET `token` = 'SE_Amnesia';
WHEN '192' THEN SET `token` = 'SE_Hate';
WHEN '193' THEN SET `token` = 'SE_SkillAttack';
WHEN '194' THEN SET `token` = 'SE_FadingMemories';
WHEN '195' THEN SET `token` = 'SE_StunResist';
WHEN '196' THEN SET `token` = 'SE_StrikeThrough';
WHEN '197' THEN SET `token` = 'SE_SkillDamageTaken';
WHEN '198' THEN SET `token` = 'SE_CurrentEnduranceOnce';
WHEN '199' THEN SET `token` = 'SE_Taunt';
WHEN '200' THEN SET `token` = 'SE_ProcChance';
WHEN '201' THEN SET `token` = 'SE_RangedProc';
WHEN '202' THEN SET `token` = 'SE_IllusionOther';
WHEN '203' THEN SET `token` = 'SE_MassGroupBuff';
WHEN '204' THEN SET `token` = 'SE_GroupFearImmunity';
WHEN '205' THEN SET `token` = 'SE_Rampage';
WHEN '206' THEN SET `token` = 'SE_AETaunt';
WHEN '207' THEN SET `token` = 'SE_FleshToBone';
WHEN '208' THEN SET `token` = 'NI_PurgePoison';
WHEN '209' THEN SET `token` = 'SE_DispelBeneficial';
WHEN '210' THEN SET `token` = 'NI_PetShield';
WHEN '211' THEN SET `token` = 'SE_AEMelee';
WHEN '212' THEN SET `token` = 'SE_FrenziedDevastation';
WHEN '213' THEN SET `token` = 'SE_PetMaxHP';
WHEN '214' THEN SET `token` = 'SE_MaxHPChange';
WHEN '215' THEN SET `token` = 'SE_PetAvoidance';
WHEN '216' THEN SET `token` = 'SE_Accuracy';
WHEN '217' THEN SET `token` = 'SE_HeadShot';
WHEN '218' THEN SET `token` = 'SE_PetCriticalHit';
WHEN '219' THEN SET `token` = 'SE_SlayUndead';
WHEN '220' THEN SET `token` = 'SE_SkillDamageAmount';
WHEN '221' THEN SET `token` = 'SE_Packrat';
WHEN '222' THEN SET `token` = 'SE_BlockBehind';
WHEN '223' THEN SET `token` = 'SE_DoubleRiposte';
WHEN '224' THEN SET `token` = 'SE_GiveDoubleRiposte';
WHEN '225' THEN SET `token` = 'SE_GiveDoubleAttack';
WHEN '226' THEN SET `token` = 'SE_TwoHandBash';
WHEN '227' THEN SET `token` = 'SE_ReduceSkillTimer';
WHEN '228' THEN SET `token` = 'SE_ReduceFallDamage';
WHEN '229' THEN SET `token` = 'SE_PersistantCasting';
WHEN '230' THEN SET `token` = 'SE_ExtendedShielding';
WHEN '231' THEN SET `token` = 'SE_StunBashChance';
WHEN '232' THEN SET `token` = 'SE_DivineSave';
WHEN '233' THEN SET `token` = 'SE_Metabolism';
WHEN '234' THEN SET `token` = 'SE_ReduceApplyPoisonTime';
WHEN '235' THEN SET `token` = 'SE_ChannelChanceSpells';
WHEN '236' THEN SET `token` = 'NI_FreePet';
WHEN '237' THEN SET `token` = 'SE_GivePetGroupTarget';
WHEN '238' THEN SET `token` = 'SE_IllusionPersistence';
WHEN '239' THEN SET `token` = 'SE_FeignedCastOnChance';
WHEN '240' THEN SET `token` = 'NI_StringUnbreakable';
WHEN '241' THEN SET `token` = 'SE_ImprovedReclaimEnergy';
WHEN '242' THEN SET `token` = 'SE_IncreaseChanceMemwipe';
WHEN '243' THEN SET `token` = 'SE_CharmBreakChance';
WHEN '244' THEN SET `token` = 'SE_RootBreakChance';
WHEN '245' THEN SET `token` = 'SE_TrapCircumvention';
WHEN '246' THEN SET `token` = 'SE_SetBreathLevel';
WHEN '247' THEN SET `token` = 'SE_RaiseSkillCap';
WHEN '248' THEN SET `token` = 'SE_SecondaryForte';
WHEN '249' THEN SET `token` = 'SE_SecondaryDmgInc';
WHEN '250' THEN SET `token` = 'SE_SpellProcChance';
WHEN '251' THEN SET `token` = 'SE_ConsumeProjectile';
WHEN '252' THEN SET `token` = 'SE_FrontalBackstabChance';
WHEN '253' THEN SET `token` = 'SE_FrontalBackstabMinDmg';
WHEN '254' THEN SET `token` = 'SE_Blank';
WHEN '255' THEN SET `token` = 'SE_ShieldDuration';
WHEN '256' THEN SET `token` = 'SE_ShroudofStealth';
WHEN '257' THEN SET `token` = 'SE_PetDiscipline';
WHEN '258' THEN SET `token` = 'SE_TripleBackstab';
WHEN '259' THEN SET `token` = 'SE_CombatStability';
WHEN '260' THEN SET `token` = 'SE_AddSingingMod';
WHEN '261' THEN SET `token` = 'SE_SongModCap';
WHEN '262' THEN SET `token` = 'SE_RaiseStatCap';
WHEN '263' THEN SET `token` = 'SE_TradeSkillMastery';
WHEN '264' THEN SET `token` = 'SE_HastenedAASkill';
WHEN '265' THEN SET `token` = 'SE_MasteryofPast';
WHEN '266' THEN SET `token` = 'SE_ExtraAttackChance';
WHEN '267' THEN SET `token` = 'SE_PetDiscipline2';
WHEN '268' THEN SET `token` = 'SE_ReduceTradeskillFail';
WHEN '269' THEN SET `token` = 'SE_MaxBindWound';
WHEN '270' THEN SET `token` = 'SE_BardSongRange';
WHEN '271' THEN SET `token` = 'SE_BaseMovementSpeed';
WHEN '272' THEN SET `token` = 'SE_CastingLevel2';
WHEN '273' THEN SET `token` = 'SE_CriticalDoTChance';
WHEN '274' THEN SET `token` = 'SE_CriticalHealChance';
WHEN '275' THEN SET `token` = 'SE_CriticalMend';
WHEN '276' THEN SET `token` = 'SE_Ambidexterity';
WHEN '277' THEN SET `token` = 'SE_UnfailingDivinity';
WHEN '278' THEN SET `token` = 'SE_FinishingBlow';
WHEN '279' THEN SET `token` = 'SE_Flurry';
WHEN '280' THEN SET `token` = 'SE_PetFlurry';
WHEN '281' THEN SET `token` = 'SE_FeignedMinion';
WHEN '282' THEN SET `token` = 'SE_ImprovedBindWound';
WHEN '283' THEN SET `token` = 'SE_DoubleSpecialAttack';
WHEN '284' THEN SET `token` = 'NI_LoHSetHeal';
WHEN '285' THEN SET `token` = 'SE_NimbleEvasion';
WHEN '286' THEN SET `token` = 'SE_FcDamageAmt';
WHEN '287' THEN SET `token` = 'SE_SpellDurationIncByTic';
WHEN '288' THEN SET `token` = 'SE_SkillAttackProc';
WHEN '289' THEN SET `token` = 'SE_CastOnFadeEffect';
WHEN '290' THEN SET `token` = 'SE_IncreaseRunSpeedCap';
WHEN '291' THEN SET `token` = 'SE_Purify';
WHEN '292' THEN SET `token` = 'SE_StrikeThrough2';
WHEN '293' THEN SET `token` = 'SE_FrontalStunResist';
WHEN '294' THEN SET `token` = 'SE_CriticalSpellChance';
WHEN '295' THEN SET `token` = 'NI_ReduceTimerSpecial';
WHEN '296' THEN SET `token` = 'SE_FcSpellVulnerability';
WHEN '297' THEN SET `token` = 'SE_FcDamageAmtIncoming';
WHEN '298' THEN SET `token` = 'SE_ChangeHeight';
WHEN '299' THEN SET `token` = 'SE_WakeTheDead';
WHEN '300' THEN SET `token` = 'SE_Doppelganger';
WHEN '301' THEN SET `token` = 'SE_ArcheryDamageModifier';
WHEN '302' THEN SET `token` = 'SE_FcDamagePctCrit';
WHEN '303' THEN SET `token` = 'SE_FcDamageAmtCrit';
WHEN '304' THEN SET `token` = 'SE_OffhandRiposteFail';
WHEN '305' THEN SET `token` = 'SE_MitigateDamageShield';
WHEN '306' THEN SET `token` = 'NI_ArmyOfTheDead';
WHEN '307' THEN SET `token` = 'NI_Appraisal';
WHEN '308' THEN SET `token` = 'SE_SuspendMinion';
WHEN '309' THEN SET `token` = 'SE_GateCastersBindpoint';
WHEN '310' THEN SET `token` = 'SE_ReduceReuseTimer';
WHEN '311' THEN SET `token` = 'SE_LimitCombatSkills';
WHEN '312' THEN SET `token` = 'SE_Sanctuary';
WHEN '313' THEN SET `token` = 'SE_ForageAdditionalItems';
WHEN '314' THEN SET `token` = 'SE_Invisibility2';
WHEN '315' THEN SET `token` = 'SE_InvisVsUndead2';
WHEN '316' THEN SET `token` = 'NI_ImprovedInvisAnimals';
WHEN '317' THEN SET `token` = 'SE_ItemHPRegenCapIncrease';
WHEN '318' THEN SET `token` = 'SE_ItemManaRegenCapIncrease';
WHEN '319' THEN SET `token` = 'SE_CriticalHealOverTime';
WHEN '320' THEN SET `token` = 'SE_ShieldBlock';
WHEN '321' THEN SET `token` = 'SE_ReduceHate';
WHEN '322' THEN SET `token` = 'SE_GateToHomeCity';
WHEN '323' THEN SET `token` = 'SE_DefensiveProc';
WHEN '324' THEN SET `token` = 'SE_HPToMana';
WHEN '325' THEN SET `token` = 'SE_NoBreakAESneak';
WHEN '326' THEN SET `token` = 'SE_SpellSlotIncrease';
WHEN '327' THEN SET `token` = 'SE_MysticalAttune';
WHEN '328' THEN SET `token` = 'SE_DelayDeath';
WHEN '329' THEN SET `token` = 'SE_ManaAbsorbPercentDamage';
WHEN '330' THEN SET `token` = 'SE_CriticalDamageMob';
WHEN '331' THEN SET `token` = 'SE_Salvage';
WHEN '332' THEN SET `token` = 'SE_SummonToCorpse';
WHEN '333' THEN SET `token` = 'SE_CastOnRuneFadeEffect';
WHEN '334' THEN SET `token` = 'SE_BardAEDot';
WHEN '335' THEN SET `token` = 'SE_BlockNextSpellFocus';
WHEN '336' THEN SET `token` = 'NI_IllusionaryTarget';
WHEN '337' THEN SET `token` = 'SE_PercentXPIncrease';
WHEN '338' THEN SET `token` = 'SE_SummonAndResAllCorpses';
WHEN '339' THEN SET `token` = 'SE_TriggerOnCast';
WHEN '340' THEN SET `token` = 'SE_SpellTrigger';
WHEN '341' THEN SET `token` = 'SE_ItemAttackCapIncrease';
WHEN '342' THEN SET `token` = 'SE_ImmuneFleeing';
WHEN '343' THEN SET `token` = 'SE_InterruptCasting';
WHEN '344' THEN SET `token` = 'SE_ChannelChanceItems';
WHEN '345' THEN SET `token` = 'SE_AssassinateLevel';
WHEN '346' THEN SET `token` = 'SE_HeadShotLevel';
WHEN '347' THEN SET `token` = 'SE_DoubleRangedAttack';
WHEN '348' THEN SET `token` = 'SE_LimitManaMin';
WHEN '349' THEN SET `token` = 'SE_ShieldEquipDmgMod';
WHEN '350' THEN SET `token` = 'SE_ManaBurn';
WHEN '351' THEN SET `token` = 'NI_PersistentEffect';
WHEN '352' THEN SET `token` = 'NI_IncreaseTrapCount';
WHEN '353' THEN SET `token` = 'NI_AdditionalAura';
WHEN '354' THEN SET `token` = 'NI_DeactivateAllTraps';
WHEN '355' THEN SET `token` = 'NI_LearnTrap';
WHEN '356' THEN SET `token` = 'NI_ChangeTriggerType';
WHEN '357' THEN SET `token` = 'SE_FcMute';
WHEN '358' THEN SET `token` = 'SE_CurrentManaOnce';
WHEN '359' THEN SET `token` = 'NI_PassiveSenseTrap';
WHEN '360' THEN SET `token` = 'SE_ProcOnKillShot';
WHEN '361' THEN SET `token` = 'SE_SpellOnDeath';
WHEN '362' THEN SET `token` = 'SE_PotionBeltSlots';
WHEN '363' THEN SET `token` = 'SE_BandolierSlots';
WHEN '364' THEN SET `token` = 'SE_TripleAttackChance';
WHEN '365' THEN SET `token` = 'SE_ProcOnSpellKillShot';
WHEN '366' THEN SET `token` = 'SE_GroupShielding';
WHEN '367' THEN SET `token` = 'SE_SetBodyType';
WHEN '368' THEN SET `token` = 'NI_FactionMod';
WHEN '369' THEN SET `token` = 'SE_CorruptionCounter';
WHEN '370' THEN SET `token` = 'SE_ResistCorruption';
WHEN '371' THEN SET `token` = 'SE_AttackSpeed4';
WHEN '372' THEN SET `token` = 'SE_ForageSkill';
WHEN '373' THEN SET `token` = 'SE_CastOnFadeEffectAlways';
WHEN '374' THEN SET `token` = 'SE_ApplyEffect';
WHEN '375' THEN SET `token` = 'SE_DotCritDmgIncrease';
WHEN '376' THEN SET `token` = 'NI_Fling';
WHEN '377' THEN SET `token` = 'SE_CastOnFadeEffectNPC';
WHEN '378' THEN SET `token` = 'SE_SpellEffectResistChance';
WHEN '379' THEN SET `token` = 'SE_ShadowStepDirectional';
WHEN '380' THEN SET `token` = 'SE_Knockdown';
WHEN '381' THEN SET `token` = 'NI_KnockTowardCaster';
WHEN '382' THEN SET `token` = 'SE_NegateSpellEffect';
WHEN '383' THEN SET `token` = 'SE_SympatheticProc';
WHEN '384' THEN SET `token` = 'SE_Leap';
WHEN '385' THEN SET `token` = 'SE_LimitSpellGroup';
WHEN '386' THEN SET `token` = 'SE_CastOnCurer';
WHEN '387' THEN SET `token` = 'SE_CastOnCure';
WHEN '388' THEN SET `token` = 'NI_SummonCorpseZone';
WHEN '389' THEN SET `token` = 'SE_FcTimerRefresh';
WHEN '390' THEN SET `token` = 'NI_FcTimerLockout';
WHEN '391' THEN SET `token` = 'SE_LimitManaMax';
WHEN '392' THEN SET `token` = 'SE_FcHealAmt';
WHEN '393' THEN SET `token` = 'SE_FcHealPctIncoming';
WHEN '394' THEN SET `token` = 'SE_FcHealAmtIncoming';
WHEN '395' THEN SET `token` = 'SE_FcHealPctCritIncoming';
WHEN '396' THEN SET `token` = 'SE_FcHealAmtCrit';
WHEN '397' THEN SET `token` = 'SE_PetMeleeMitigation';
WHEN '398' THEN SET `token` = 'SE_SwarmPetDuration';
WHEN '399' THEN SET `token` = 'SE_FcTwincast';
WHEN '400' THEN SET `token` = 'SE_HealGroupFromMana';
WHEN '401' THEN SET `token` = 'SE_ManaDrainWithDmg';
WHEN '402' THEN SET `token` = 'SE_EndDrainWithDmg';
WHEN '403' THEN SET `token` = 'SE_LimitSpellClass';
WHEN '404' THEN SET `token` = 'SE_LimitSpellSubclass';
WHEN '405' THEN SET `token` = 'SE_TwoHandBluntBlock';
WHEN '406' THEN SET `token` = 'SE_CastonNumHitFade';
WHEN '407' THEN SET `token` = 'SE_CastonFocusEffect';
WHEN '408' THEN SET `token` = 'SE_LimitHPPercent';
WHEN '409' THEN SET `token` = 'SE_LimitManaPercent';
WHEN '410' THEN SET `token` = 'SE_LimitEndPercent';
WHEN '411' THEN SET `token` = 'SE_LimitClass';
WHEN '412' THEN SET `token` = 'SE_LimitRace';
WHEN '413' THEN SET `token` = 'SE_FcBaseEffects';
WHEN '414' THEN SET `token` = 'SE_LimitCastingSkill';
WHEN '415' THEN SET `token` = 'NI_FFItemClass';
WHEN '416' THEN SET `token` = 'SE_ACv2';
WHEN '417' THEN SET `token` = 'SE_ManaRegen_v2';
WHEN '418' THEN SET `token` = 'SE_SkillDamageAmount2';
WHEN '419' THEN SET `token` = 'SE_AddMeleeProc';
WHEN '420' THEN SET `token` = 'SE_FcLimitUse';
WHEN '421' THEN SET `token` = 'SE_FcIncreaseNumHits';
WHEN '422' THEN SET `token` = 'SE_LimitUseMin';
WHEN '423' THEN SET `token` = 'SE_LimitUseType';
WHEN '424' THEN SET `token` = 'SE_GravityEffect';
WHEN '425' THEN SET `token` = 'NI_Display';
WHEN '426' THEN SET `token` = 'SE_IncreaseExtTargetWindow';
WHEN '427' THEN SET `token` = 'SE_SkillProc';
WHEN '428' THEN SET `token` = 'SE_LimitToSkill';
WHEN '429' THEN SET `token` = 'SE_SkillProcSuccess';
WHEN '430' THEN SET `token` = 'NI_PostEffect';
WHEN '431' THEN SET `token` = 'NI_PostEffectData';
WHEN '432' THEN SET `token` = 'NI_ExpandMaxActiveTrophyBen';
WHEN '433' THEN SET `token` = 'SE_CriticalDotDecay';
WHEN '434' THEN SET `token` = 'SE_CriticalHealDecay';
WHEN '435' THEN SET `token` = 'SE_CriticalRegenDecay';
WHEN '436' THEN SET `token` = 'NI_BeneficialCountDownHold';
WHEN '437' THEN SET `token` = 'NI_TeleporttoAnchor';
WHEN '438' THEN SET `token` = 'NI_TranslocatetoAnchor';
WHEN '439' THEN SET `token` = 'SE_Assassinate';
WHEN '440' THEN SET `token` = 'SE_FinishingBlowLvl';
WHEN '441' THEN SET `token` = 'SE_DistanceRemoval';
WHEN '442' THEN SET `token` = 'SE_TriggerOnReqTarget';
WHEN '443' THEN SET `token` = 'SE_TriggerOnReqCaster';
WHEN '444' THEN SET `token` = 'SE_ImprovedTaunt';
WHEN '445' THEN SET `token` = 'NI_AddMercSlot';
WHEN '446' THEN SET `token` = 'SE_AStacker';
WHEN '447' THEN SET `token` = 'SE_BStacker';
WHEN '448' THEN SET `token` = 'SE_CStacker';
WHEN '449' THEN SET `token` = 'SE_DStacker';
WHEN '450' THEN SET `token` = 'SE_MitigateDotDamage';
WHEN '451' THEN SET `token` = 'SE_MeleeThresholdGuard';
WHEN '452' THEN SET `token` = 'SE_SpellThresholdGuard';
WHEN '453' THEN SET `token` = 'SE_TriggerMeleeThreshold';
WHEN '454' THEN SET `token` = 'SE_TriggerSpellThreshold';
WHEN '455' THEN SET `token` = 'SE_AddHatePct';
WHEN '456' THEN SET `token` = 'SE_AddHateOverTimePct';
WHEN '457' THEN SET `token` = 'SE_ResourceTap';
WHEN '458' THEN SET `token` = 'SE_FactionModPct';
WHEN '459' THEN SET `token` = 'SE_DamageModifier2';
WHEN '460' THEN SET `token` = 'NI_Ff_Override_NotFocusable';
WHEN '461' THEN SET `token` = 'SE_ImprovedDamage2';
WHEN '462' THEN SET `token` = 'SE_FcDamageAmt2';
WHEN '463' THEN SET `token` = 'NI_Shield_Target';
WHEN '464' THEN SET `token` = 'SE_PC_Pet_Rampage';
WHEN '465' THEN SET `token` = 'NI_PC_Pet_AE_Rampage';
WHEN '466' THEN SET `token` = 'SE_PC_Pet_Flurry_Chance';
WHEN '467' THEN SET `token` = 'NI_DS_Mitigation_Amount';
WHEN '468' THEN SET `token` = 'NI_DS_Mitigation_Percentage';
WHEN '469' THEN SET `token` = 'NI_Chance_Best_in_Spell_Grp';
WHEN '470' THEN SET `token` = 'NI_Trigger_Best_in_Spell_Grp';
WHEN '471' THEN SET `token` = 'NI_Double_Melee_Round';
-- these are not defined
WHEN '472' THEN SET `token` = 'NI_Buy_AA_Rank';
WHEN '473' THEN SET `token` = 'NI_Double_Backstab_From_Front';
WHEN '474' THEN SET `token` = 'NI_Pet_Crit_Melee_Damage_Pct';
WHEN '475' THEN SET `token` = 'NI_Trigger_Spell_Non_Item';
WHEN '476' THEN SET `token` = 'NI_Weapon_Stance';
WHEN '477' THEN SET `token` = 'NI_Hatelist_To_Top_Index';
WHEN '478' THEN SET `token` = 'NI_Hatelist_To_Tail_Index';
WHEN '479' THEN SET `token` = 'NI_Ff_Value_Min';
WHEN '480' THEN SET `token` = 'NI_Ff_Value_Max';
WHEN '481' THEN SET `token` = 'NI_Fc_Cast_Spell_On_Land';
WHEN '482' THEN SET `token` = 'NI_Skill_Base_Damage_Mod';
WHEN '483' THEN SET `token` = 'NI_Fc_Spell_Damage_Pct_IncomingPC';
WHEN '484' THEN SET `token` = 'NI_Fc_Spell_Damage_Amt_IncomingPC';
WHEN '485' THEN SET `token` = 'NI_Ff_CasterClass';
WHEN '486' THEN SET `token` = 'NI_Ff_Same_Caster';
WHEN '487' THEN SET `token` = 'NI_Extend_Tradeskill_Cap';
WHEN '488' THEN SET `token` = 'NI_Defender_Melee_Force_Pct';
WHEN '489' THEN SET `token` = 'NI_Worn_Endurance_Regen_Cap';
WHEN '490' THEN SET `token` = 'NI_Ff_ReuseTimeMin';
WHEN '491' THEN SET `token` = 'NI_Ff_ReuseTimeMax';
WHEN '492' THEN SET `token` = 'NI_Ff_Endurance_Min';
WHEN '493' THEN SET `token` = 'NI_Ff_Endurance_Max';
WHEN '494' THEN SET `token` = 'NI_Pet_Add_Atk';
WHEN '495' THEN SET `token` = 'NI_Ff_DurationMax';
ELSE SET `token` = 'unk';
END CASE;
SET `token` = CONCAT(`token`, '(', `effect_id`, ')');
RETURN `token`;
END$$
DELIMITER ;
@@ -0,0 +1,171 @@
DELIMITER $$
DROP FUNCTION IF EXISTS `GetSpellTargetTypeToken`;
-- This function converts a numeric spell target type to a string label based on server code designations
-- Note: `cast_restriction` data taken from MacroQuest2 definitions
--
-- example:
-- SELECT `id`, `name`, GetSpellTargetTypeToken(`targettype`, `CastRestriction`) FROM `spells_new` WHERE `id` IN ('6836', '10763', '25039');
CREATE FUNCTION `GetSpellTargetTypeToken` (`target_type` INT(11), `cast_restriction` INT(11)) RETURNS VARCHAR(128)
BEGIN
DECLARE `token` VARCHAR(128) DEFAULT '';
DECLARE `token2` VARCHAR(64) DEFAULT '';
CASE `target_type`
WHEN '1' THEN SET `token` = 'ST_TargetOptional';
WHEN '2' THEN SET `token` = 'ST_AEClientV1';
WHEN '3' THEN SET `token` = 'ST_GroupTeleport';
WHEN '4' THEN SET `token` = 'ST_AECaster';
WHEN '5' THEN SET `token` = 'ST_Target';
WHEN '6' THEN SET `token` = 'ST_Self';
WHEN '8' THEN SET `token` = 'ST_AETarget';
WHEN '9' THEN SET `token` = 'ST_Animal';
WHEN '10' THEN SET `token` = 'ST_Undead';
WHEN '11' THEN SET `token` = 'ST_Summoned';
WHEN '13' THEN SET `token` = 'ST_Tap';
WHEN '14' THEN SET `token` = 'ST_Pet';
WHEN '15' THEN SET `token` = 'ST_Corpse';
WHEN '16' THEN SET `token` = 'ST_Plant';
WHEN '17' THEN SET `token` = 'ST_Giant';
WHEN '18' THEN SET `token` = 'ST_Dragon';
WHEN '20' THEN SET `token` = 'ST_TargetAETap';
WHEN '24' THEN SET `token` = 'ST_UndeadAE';
WHEN '25' THEN SET `token` = 'ST_SummonedAE';
WHEN '32' THEN SET `token` = 'ST_AETargetHateList';
WHEN '33' THEN SET `token` = 'ST_HateList';
WHEN '34' THEN SET `token` = 'ST_LDoNChest_Cursed';
WHEN '35' THEN SET `token` = 'ST_Muramite';
WHEN '36' THEN SET `token` = 'ST_AreaClientOnly';
WHEN '37' THEN SET `token` = 'ST_AreaNPCOnly';
WHEN '38' THEN SET `token` = 'ST_SummonedPet';
WHEN '39' THEN SET `token` = 'ST_GroupNoPets';
WHEN '40' THEN SET `token` = 'ST_AEBard';
WHEN '41' THEN SET `token` = 'ST_Group';
WHEN '42' THEN SET `token` = 'ST_Directional';
WHEN '43' THEN SET `token` = 'ST_GroupClientAndPet';
WHEN '44' THEN SET `token` = 'ST_Beam';
WHEN '45' THEN SET `token` = 'ST_Ring';
WHEN '46' THEN SET `token` = 'ST_TargetsTarget';
WHEN '47' THEN SET `token` = 'ST_PetMaster';
WHEN '50' THEN SET `token` = 'ST_TargetAENoPlayersPets';
ELSE SET `token` = 'unk';
END CASE;
SET `token` = CONCAT(`token`, '(', `target_type`, ')');
CASE `cast_restriction`
WHEN '0' THEN SET `token2` = 'None';
WHEN '100' THEN SET `token2` = 'Only works on Animal or Humanoid';
WHEN '101' THEN SET `token2` = 'Only works on Dragon';
WHEN '102' THEN SET `token2` = 'Only works on Animal or Insect';
WHEN '104' THEN SET `token2` = 'Only works on Animal';
WHEN '105' THEN SET `token2` = 'Only works on Plant';
WHEN '106' THEN SET `token2` = 'Only works on Giant';
WHEN '108' THEN SET `token2` = 'Doesn\'t work on Animals or Humanoids';
WHEN '109' THEN SET `token2` = 'Only works on Bixie';
WHEN '110' THEN SET `token2` = 'Only works on Harpy';
WHEN '111' THEN SET `token2` = 'Only works on Gnoll';
WHEN '112' THEN SET `token2` = 'Only works on Sporali';
WHEN '113' THEN SET `token2` = 'Only works on Kobold';
WHEN '114' THEN SET `token2` = 'Only works on Shade';
WHEN '115' THEN SET `token2` = 'Only works on Drakkin';
WHEN '117' THEN SET `token2` = 'Only works on Animals or Plants';
WHEN '118' THEN SET `token2` = 'Only works on Summoned';
WHEN '119' THEN SET `token2` = 'Only works on Fire_Pet';
WHEN '120' THEN SET `token2` = 'Only works on Undead';
WHEN '121' THEN SET `token2` = 'Only works on Living';
WHEN '122' THEN SET `token2` = 'Only works on Fairy';
WHEN '123' THEN SET `token2` = 'Only works on Humanoid';
WHEN '124' THEN SET `token2` = 'Undead HP Less Than 10%';
WHEN '125' THEN SET `token2` = 'Clockwork HP Less Than 45%';
WHEN '126' THEN SET `token2` = 'Wisp HP Less Than 10%';
WHEN '190' THEN SET `token2` = 'Doesn\'t work on Raid Bosses';
WHEN '191' THEN SET `token2` = 'Only works on Raid Bosses';
WHEN '201' THEN SET `token2` = 'HP Above 75%';
WHEN '203' THEN SET `token2` = 'HP Less Than 20%';
WHEN '204' THEN SET `token2` = 'HP Less Than 50%';
WHEN '216' THEN SET `token2` = 'Not In Combat';
WHEN '221' THEN SET `token2` = 'At Least 1 Pet On Hatelist';
WHEN '222' THEN SET `token2` = 'At Least 2 Pets On Hatelist';
WHEN '223' THEN SET `token2` = 'At Least 3 Pets On Hatelist';
WHEN '224' THEN SET `token2` = 'At Least 4 Pets On Hatelist';
WHEN '225' THEN SET `token2` = 'At Least 5 Pets On Hatelist';
WHEN '226' THEN SET `token2` = 'At Least 6 Pets On Hatelist';
WHEN '227' THEN SET `token2` = 'At Least 7 Pets On Hatelist';
WHEN '228' THEN SET `token2` = 'At Least 8 Pets On Hatelist';
WHEN '229' THEN SET `token2` = 'At Least 9 Pets On Hatelist';
WHEN '230' THEN SET `token2` = 'At Least 10 Pets On Hatelist';
WHEN '231' THEN SET `token2` = 'At Least 11 Pets On Hatelist';
WHEN '232' THEN SET `token2` = 'At Least 12 Pets On Hatelist';
WHEN '233' THEN SET `token2` = 'At Least 13 Pets On Hatelist';
WHEN '234' THEN SET `token2` = 'At Least 14 Pets On Hatelist';
WHEN '235' THEN SET `token2` = 'At Least 15 Pets On Hatelist';
WHEN '236' THEN SET `token2` = 'At Least 16 Pets On Hatelist';
WHEN '237' THEN SET `token2` = 'At Least 17 Pets On Hatelist';
WHEN '238' THEN SET `token2` = 'At Least 18 Pets On Hatelist';
WHEN '239' THEN SET `token2` = 'At Least 19 Pets On Hatelist';
WHEN '240' THEN SET `token2` = 'At Least 20 Pets On Hatelist';
WHEN '250' THEN SET `token2` = 'HP Less Than 35%';
WHEN '304' THEN SET `token2` = 'Chain Plate Classes';
WHEN '399' THEN SET `token2` = 'HP Between 15 and 25%';
WHEN '400' THEN SET `token2` = 'HP Between 1 and 25%';
WHEN '401' THEN SET `token2` = 'HP Between 25 and 35%';
WHEN '402' THEN SET `token2` = 'HP Between 35 and 45%';
WHEN '403' THEN SET `token2` = 'HP Between 45 and 55%';
WHEN '404' THEN SET `token2` = 'HP Between 55 and 65%';
WHEN '412' THEN SET `token2` = 'HP Above 99%';
WHEN '501' THEN SET `token2` = 'HP Below 5%';
WHEN '502' THEN SET `token2` = 'HP Below 10%';
WHEN '503' THEN SET `token2` = 'HP Below 15%';
WHEN '504' THEN SET `token2` = 'HP Below 20%';
WHEN '505' THEN SET `token2` = 'HP Below 25%';
WHEN '506' THEN SET `token2` = 'HP Below 30%';
WHEN '507' THEN SET `token2` = 'HP Below 35%';
WHEN '508' THEN SET `token2` = 'HP Below 40%';
WHEN '509' THEN SET `token2` = 'HP Below 45%';
WHEN '510' THEN SET `token2` = 'HP Below 50%';
WHEN '511' THEN SET `token2` = 'HP Below 55%';
WHEN '512' THEN SET `token2` = 'HP Below 60%';
WHEN '513' THEN SET `token2` = 'HP Below 65%';
WHEN '514' THEN SET `token2` = 'HP Below 70%';
WHEN '515' THEN SET `token2` = 'HP Below 75%';
WHEN '516' THEN SET `token2` = 'HP Below 80%';
WHEN '517' THEN SET `token2` = 'HP Below 85%';
WHEN '518' THEN SET `token2` = 'HP Below 90%';
WHEN '519' THEN SET `token2` = 'HP Below 95%';
WHEN '521' THEN SET `token2` = 'Mana Below X%';
WHEN '522' THEN SET `token2` = 'End Below 40%';
WHEN '523' THEN SET `token2` = 'Mana Below 40%';
WHEN '603' THEN SET `token2` = 'Only works on Undead2';
WHEN '608' THEN SET `token2` = 'Only works on Undead3';
WHEN '624' THEN SET `token2` = 'Only works on Summoned2';
WHEN '701' THEN SET `token2` = 'Doesn\'t work on Pets';
WHEN '818' THEN SET `token2` = 'Only works on Undead4';
WHEN '819' THEN SET `token2` = 'Doesn\'t work on Undead4';
WHEN '825' THEN SET `token2` = 'End Below 21%';
WHEN '826' THEN SET `token2` = 'End Below 25%';
WHEN '827' THEN SET `token2` = 'End Below 29%';
WHEN '836' THEN SET `token2` = 'Only works on Regular Servers';
WHEN '837' THEN SET `token2` = 'Doesn\'t work on Progression Servers';
WHEN '842' THEN SET `token2` = 'Only works on Humanoid Level 84 Max';
WHEN '843' THEN SET `token2` = 'Only works on Humanoid Level 86 Max';
WHEN '844' THEN SET `token2` = 'Only works on Humanoid Level 88 Max';
WHEN '1000' THEN SET `token2` = 'Between Level 1 and 75';
WHEN '1001' THEN SET `token2` = 'Between Level 76 and 85';
WHEN '1002' THEN SET `token2` = 'Between Level 86 and 95';
WHEN '1003' THEN SET `token2` = 'Between Level 96 and 100';
WHEN '1004' THEN SET `token2` = 'HP Less Than 80%';
WHEN '38311' THEN SET `token2` = 'Mana Below 20%';
WHEN '38312' THEN SET `token2` = 'Mana Below 10%';
ELSE SET `token2` = 'unk';
END CASE;
SET `token2` = CONCAT(`token2`, '(', `cast_restriction`, ')');
SET `token` = CONCAT(`token`, ':', `token2`);
RETURN `token`;
END$$
DELIMITER ;
@@ -0,0 +1,185 @@
DELIMITER $$
DROP FUNCTION IF EXISTS `GetSpellTypeDescriptionToken`;
-- This function converts numeric spell type description ids to a string label based on server code designations
--
-- example:
-- SELECT `id`, `name`, GetSpellTypeDescriptionToken(`typedescnum`) FROM `spells_new` WHERE `id` IN ('16', '42', '23214');
CREATE FUNCTION `GetSpellTypeDescriptionToken` (`type_description_id` INT(11)) RETURNS VARCHAR(256)
BEGIN
DECLARE `token` VARCHAR(256) DEFAULT '';
CASE `type_description_id`
WHEN '1' THEN SET `token` = 'Aegolism';
WHEN '2' THEN SET `token` = 'Agility';
WHEN '3' THEN SET `token` = 'Alliance';
WHEN '4' THEN SET `token` = 'Animal';
WHEN '5' THEN SET `token` = 'Antonica';
WHEN '6' THEN SET `token` = 'Armor_Class';
WHEN '7' THEN SET `token` = 'Attack';
WHEN '8' THEN SET `token` = 'Bane';
WHEN '9' THEN SET `token` = 'Blind';
WHEN '10' THEN SET `token` = 'Block';
WHEN '11' THEN SET `token` = 'Calm';
WHEN '12' THEN SET `token` = 'Charisma';
WHEN '13' THEN SET `token` = 'Charm';
WHEN '14' THEN SET `token` = 'Cold';
WHEN '15' THEN SET `token` = 'Combat_Abilities';
WHEN '16' THEN SET `token` = 'Combat_Innates';
WHEN '17' THEN SET `token` = 'Conversions';
WHEN '18' THEN SET `token` = 'Create_Item';
WHEN '19' THEN SET `token` = 'Cure';
WHEN '20' THEN SET `token` = 'Damage_Over_Time';
WHEN '21' THEN SET `token` = 'Damage_Shield';
WHEN '22' THEN SET `token` = 'Defensive';
WHEN '23' THEN SET `token` = 'Destroy';
WHEN '24' THEN SET `token` = 'Dexterity';
WHEN '25' THEN SET `token` = 'Direct_Damage';
WHEN '26' THEN SET `token` = 'Disarm_Traps';
WHEN '27' THEN SET `token` = 'Disciplines';
WHEN '28' THEN SET `token` = 'Discord';
WHEN '29' THEN SET `token` = 'Disease';
WHEN '30' THEN SET `token` = 'Disempowering';
WHEN '31' THEN SET `token` = 'Dispel';
WHEN '32' THEN SET `token` = 'Duration_Heals';
WHEN '33' THEN SET `token` = 'Duration_Tap';
WHEN '34' THEN SET `token` = 'Enchant_Metal';
WHEN '35' THEN SET `token` = 'Enthrall';
WHEN '36' THEN SET `token` = 'Faydwer';
WHEN '37' THEN SET `token` = 'Fear';
WHEN '38' THEN SET `token` = 'Fire';
WHEN '39' THEN SET `token` = 'Fizzle_Rate';
WHEN '40' THEN SET `token` = 'Fumble';
WHEN '41' THEN SET `token` = 'Haste';
WHEN '42' THEN SET `token` = 'Heals';
WHEN '43' THEN SET `token` = 'Health';
WHEN '44' THEN SET `token` = 'Health_Mana';
WHEN '45' THEN SET `token` = 'HP_Buffs';
WHEN '46' THEN SET `token` = 'HP_type_one';
WHEN '47' THEN SET `token` = 'HP_type_two';
WHEN '48' THEN SET `token` = 'Illusion_Other';
WHEN '49' THEN SET `token` = 'Illusion_Player';
WHEN '50' THEN SET `token` = 'Imbue_Gem';
WHEN '51' THEN SET `token` = 'Invisibility';
WHEN '52' THEN SET `token` = 'Invulnerability';
WHEN '53' THEN SET `token` = 'Jolt';
WHEN '54' THEN SET `token` = 'Kunark';
WHEN '55' THEN SET `token` = 'Levitate';
WHEN '56' THEN SET `token` = 'Life_Flow';
WHEN '57' THEN SET `token` = 'Luclin';
WHEN '58' THEN SET `token` = 'Magic';
WHEN '59' THEN SET `token` = 'Mana';
WHEN '60' THEN SET `token` = 'Mana_Drain';
WHEN '61' THEN SET `token` = 'Mana_Flow';
WHEN '62' THEN SET `token` = 'Melee_Guard';
WHEN '63' THEN SET `token` = 'Memory_Blur';
WHEN '64' THEN SET `token` = 'Misc';
WHEN '65' THEN SET `token` = 'Movement';
WHEN '66' THEN SET `token` = 'Objects';
WHEN '67' THEN SET `token` = 'Odus';
WHEN '68' THEN SET `token` = 'Offensive';
WHEN '69' THEN SET `token` = 'Pet';
WHEN '70' THEN SET `token` = 'Pet_Haste';
WHEN '71' THEN SET `token` = 'Pet_Misc_Buffs';
WHEN '72' THEN SET `token` = 'Physical';
WHEN '73' THEN SET `token` = 'Picklock';
WHEN '74' THEN SET `token` = 'Plant';
WHEN '75' THEN SET `token` = 'Poison';
WHEN '76' THEN SET `token` = 'Power_Tap';
WHEN '77' THEN SET `token` = 'Quick_Heal';
WHEN '78' THEN SET `token` = 'Reflection';
WHEN '79' THEN SET `token` = 'Regen';
WHEN '80' THEN SET `token` = 'Resist_Buff';
WHEN '81' THEN SET `token` = 'Resist_Debuffs';
WHEN '82' THEN SET `token` = 'Resurrection';
WHEN '83' THEN SET `token` = 'Root';
WHEN '84' THEN SET `token` = 'Rune';
WHEN '85' THEN SET `token` = 'Sense_Trap';
WHEN '86' THEN SET `token` = 'Shadowstep';
WHEN '87' THEN SET `token` = 'Shielding';
WHEN '88' THEN SET `token` = 'Slow';
WHEN '89' THEN SET `token` = 'Snare';
WHEN '90' THEN SET `token` = 'Special';
WHEN '91' THEN SET `token` = 'Spell_Focus';
WHEN '92' THEN SET `token` = 'Spell_Guard';
WHEN '93' THEN SET `token` = 'Spellshield';
WHEN '94' THEN SET `token` = 'Stamina';
WHEN '95' THEN SET `token` = 'Statistic_Buffs';
WHEN '96' THEN SET `token` = 'Strength';
WHEN '97' THEN SET `token` = 'Stun';
WHEN '98' THEN SET `token` = 'Sum_Air';
WHEN '99' THEN SET `token` = 'Sum_Animation';
WHEN '100' THEN SET `token` = 'Sum_Earth';
WHEN '101' THEN SET `token` = 'Sum_Familiar';
WHEN '102' THEN SET `token` = 'Sum_Fire';
WHEN '103' THEN SET `token` = 'Sum_Undead';
WHEN '104' THEN SET `token` = 'Sum_Warder';
WHEN '105' THEN SET `token` = 'Sum_Water';
WHEN '106' THEN SET `token` = 'Summon_Armor';
WHEN '107' THEN SET `token` = 'Summon_Focus';
WHEN '108' THEN SET `token` = 'Summon_Food_Water';
WHEN '109' THEN SET `token` = 'Summon_Utility';
WHEN '110' THEN SET `token` = 'Summon_Weapon';
WHEN '111' THEN SET `token` = 'Summoned';
WHEN '112' THEN SET `token` = 'Symbol';
WHEN '113' THEN SET `token` = 'Taelosia';
WHEN '114' THEN SET `token` = 'Taps';
WHEN '115' THEN SET `token` = 'Techniques';
WHEN '116' THEN SET `token` = 'The_Planes';
WHEN '117' THEN SET `token` = 'Timer_1';
WHEN '118' THEN SET `token` = 'Timer_2';
WHEN '119' THEN SET `token` = 'Timer_3';
WHEN '120' THEN SET `token` = 'Timer_4';
WHEN '121' THEN SET `token` = 'Timer_5';
WHEN '122' THEN SET `token` = 'Timer_6';
WHEN '123' THEN SET `token` = 'Transport';
WHEN '124' THEN SET `token` = 'Undead';
WHEN '125' THEN SET `token` = 'Utility_Beneficial';
WHEN '126' THEN SET `token` = 'Utility_Detrimental';
WHEN '127' THEN SET `token` = 'Velious';
WHEN '128' THEN SET `token` = 'Visages';
WHEN '129' THEN SET `token` = 'Vision';
WHEN '130' THEN SET `token` = 'Wisdom_Intelligence';
WHEN '131' THEN SET `token` = 'Traps';
WHEN '132' THEN SET `token` = 'Auras';
WHEN '133' THEN SET `token` = 'Endurance';
WHEN '134' THEN SET `token` = 'Serpent\'s_Spine';
WHEN '135' THEN SET `token` = 'Corruption';
WHEN '136' THEN SET `token` = 'Learning';
WHEN '137' THEN SET `token` = 'Chromatic';
WHEN '138' THEN SET `token` = 'Prismatic';
WHEN '139' THEN SET `token` = 'Sum_Swarm';
WHEN '140' THEN SET `token` = 'Delayed';
WHEN '141' THEN SET `token` = 'Temporary';
WHEN '142' THEN SET `token` = 'Twincast';
WHEN '143' THEN SET `token` = 'Sum_Bodyguard';
WHEN '144' THEN SET `token` = 'Humanoid';
WHEN '145' THEN SET `token` = 'Haste_Spell_Focus';
WHEN '146' THEN SET `token` = 'Timer_7';
WHEN '147' THEN SET `token` = 'Timer_8';
WHEN '148' THEN SET `token` = 'Timer_9';
WHEN '149' THEN SET `token` = 'Timer_10';
WHEN '150' THEN SET `token` = 'Timer_11';
WHEN '151' THEN SET `token` = 'Timer_12';
WHEN '152' THEN SET `token` = 'Hatred';
WHEN '153' THEN SET `token` = 'Fast';
WHEN '154' THEN SET `token` = 'Illusion_Special';
WHEN '155' THEN SET `token` = 'Timer_13';
WHEN '156' THEN SET `token` = 'Timer_14';
WHEN '157' THEN SET `token` = 'Timer_15';
WHEN '158' THEN SET `token` = 'Timer_16';
WHEN '159' THEN SET `token` = 'Timer_17';
WHEN '160' THEN SET `token` = 'Timer_18';
WHEN '161' THEN SET `token` = 'Timer_19';
WHEN '162' THEN SET `token` = 'Timer_20';
WHEN '163' THEN SET `token` = 'Alaris';
ELSE SET `token` = 'unk';
END CASE;
SET `token` = CONCAT(`token`, '(', `type_description_id`, ')');
RETURN `token`;
END$$
DELIMITER ;
+2 -2
View File
@@ -334,7 +334,7 @@ sub build_linux_source {
}
print "Building EQEmu Server code. This will take a while.";
#::: Build
#::: Build
print `make`;
chdir ($current_directory);
@@ -1340,7 +1340,7 @@ sub do_linux_login_server_setup {
get_remote_file($install_repository_request_url . "linux/login.ini", "login_template.ini");
get_remote_file($install_repository_request_url . "linux/login_opcodes.conf", "login_opcodes.conf");
get_remote_file($install_repository_request_url . "linux/login_opcodes.conf", "login_opcodes_sod.conf");
get_remote_file($install_repository_request_url . "linux/login_opcodes_sod.conf", "login_opcodes_sod.conf");
get_installation_variables();
my $db_name = $installation_variables{"mysql_eqemu_db_name"};
+3
View File
@@ -87,6 +87,7 @@ echo "mysql_eqemu_password:$eqemu_db_password" >> install_variables.txt
if [[ "$OS" == "Debian" ]]; then
# Install pre-req packages
apt-get -y update
apt-get $apt_options install bash
apt-get $apt_options install build-essential
apt-get $apt_options install cmake
@@ -105,6 +106,8 @@ if [[ "$OS" == "Debian" ]]; then
apt-get $apt_options install libperl-dev
apt-get $apt_options install libperl5i-perl
apt-get $apt_options install libwtdbomysql-dev
apt-get $apt_options install libmysqlclient-dev
apt-get $apt_options install minizip
apt-get $apt_options install lua5.1
apt-get $apt_options install make
apt-get $apt_options install mariadb-client
+5
View File
@@ -0,0 +1,5 @@
command_settings
launcher
rule_sets
rule_values
variables
+6
View File
@@ -355,6 +355,12 @@
9099|2016_08_27_ip_exemptions.sql|SHOW TABLES LIKE 'ip_exemptions'|empty|
9100|2016_08_27_object_display_name.sql|SHOW COLUMNS FROM `object` LIKE 'display_name'|empty|
9101|2016_12_01_pcnpc_only.sql|SHOW COLUMNS FROM `spells_new` LIKE 'pcnpc_only_flag'|empty|
9102|2017_01_10_book_languages.sql|SHOW COLUMNS FROM `books` LIKE 'language'|empty|
9103|2017_01_30_book_languages_fix.sql|SELECT `language` from `books` WHERE `language` IS NULL|not_empty|
9104|2017_02_09_npc_spells_entries_type_update.sql|SHOW COLUMNS IN `npc_spells_entries` LIKE `type`|contains|smallint(5) unsigned
9105|2017_02_15_bot_spells_entries.sql|SELECT `id` FROM `npc_spells_entries` WHERE `npc_spells_id` >= 701 AND `npc_spells_id` <= 712|not_empty|
9106|2017_02_26_npc_spells_update_for_bots.sql|SELECT * FROM `npc_spells` WHERE `id` = '701' AND `name` = 'Cleric Bot'|not_empty|
9107|2017_03_09_inventory_version.sql|SHOW TABLES LIKE 'inventory_version'|empty|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not
@@ -7,6 +7,13 @@
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|
9009|2017_02_15_bots_bot_spells_entries.sql|SELECT `id` FROM `npc_spells_entries` WHERE `npc_spells_id` >= 701 AND `npc_spells_id` <= 712|not_empty|
9010|2017_02_20_bots_bard_spell_update.sql|SELECT * FROM `bot_spells_entries` WHERE `npc_spells_id` = 711 AND (`type` & 0xFFFF0000) = 0xFFFF0000|empty|
9011|2017_02_23_bots_spell_casting_chances.sql|SHOW TABLES LIKE 'bot_spell_casting_chances'|empty|
9012|2017_02_26_bots_npc_spells_update_for_bots.sql|SELECT * FROM `npc_spells` WHERE `id` = '701' AND `name` = 'Cleric Bot'|not_empty|
9013|2017_02_26_bots_spells_id_update_for_saved_bots.sql|SELECT * FROM `bot_data` WHERE `spells_id` >= '701' AND `spells_id` <= '712'|not_empty|
9014|2017_02_26_bots_spells_id_update_for_bot_spells_entries.sql|SELECT * FROM `bot_spells_entries` WHERE `npc_spells_id` >= '701' AND `npc_spells_id` <= '712'|not_empty|
9015|2017_02_26_bots_spell_casting_chances_update.sql|SHOW COLUMNS FROM `bot_spell_casting_chances` LIKE 'value'|not_empty|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not
@@ -0,0 +1 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Bots:UpdatePositionWithTimer', 'true', 'Sends a position update with every positive movement timer check');
@@ -0,0 +1 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Bots:UsePathing', 'false', 'Bots will use node pathing when moving');
@@ -0,0 +1,29 @@
-- Delete any existing `bots_spells_entries` table
DROP TABLE IF EXISTS `bots_spells_entries`;
-- Create new bot spells entries table (new table does not have spells_id_spellid constraint)
CREATE TABLE `bot_spells_entries` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`npc_spells_id` INT(11) NOT NULL DEFAULT '0',
`spellid` SMALLINT(5) NOT NULL DEFAULT '0',
`type` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`minlevel` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
`maxlevel` TINYINT(3) UNSIGNED NOT NULL DEFAULT '255',
`manacost` SMALLINT(5) NOT NULL DEFAULT '-1',
`recast_delay` INT(11) NOT NULL DEFAULT '-1',
`priority` SMALLINT(5) NOT NULL DEFAULT '0',
`resist_adjust` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;
-- Copy bots spells into new table
INSERT INTO `bot_spells_entries` (`npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`, `manacost`, `recast_delay`, `priority`, `resist_adjust`)
SELECT `npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`, `manacost`, `recast_delay`, `priority`, `resist_adjust`
FROM `npc_spells_entries` WHERE `npc_spells_id` >= '701' AND `npc_spells_id` <= '712';
-- Delete bot spells from old table
DELETE FROM `npc_spells_entries` WHERE `npc_spells_id` >= '701' AND `npc_spells_id` <= '712';
@@ -0,0 +1,153 @@
DELETE FROM `bot_spells_entries` WHERE `npc_spells_id` = '711';
INSERT INTO `bot_spells_entries`(`npc_spells_id`,`spellid`,`type`,`minlevel`,`maxlevel`,`manacost`,`recast_delay`,`priority`,`resist_adjust`) VALUES
-- versioning entry
('711', '0', '4294901760', '0', '0', '-1', '-1', '0', NULL), -- 0xFFFF0000
-- nuke
('711', '704', '1', '12', '54', '-1', '-1', '1', NULL),
('711', '1747', '1', '55', '127', '-1', '-1', '1', NULL),
-- escape
('711', '1749', '16', '60', '127', '-1', '-1', '1', NULL),
-- dot
('711', '743', '256', '38', '64', '-1', '-1', '1', NULL),
('711', '3367', '256', '65', '69', '-1', '-1', '1', NULL),
('711', '5385', '256', '70', '79', '-1', '-1', '1', NULL),
('711', '14074', '256', '80', '84', '-1', '-1', '1', NULL),
('711', '18059', '256', '85', '89', '-1', '-1', '1', NULL),
('711', '26084', '256', '90', '94', '-1', '-1', '1', NULL),
('711', '29182', '256', '95', '127', '-1', '-1', '1', NULL),
('711', '3566', '256', '50', '62', '-1', '-1', '2', NULL),
('711', '3370', '256', '63', '67', '-1', '-1', '2', NULL),
('711', '5378', '256', '68', '77', '-1', '-1', '2', NULL),
('711', '14071', '256', '78', '82', '-1', '-1', '2', NULL),
('711', '18056', '256', '83', '87', '-1', '-1', '2', NULL),
('711', '26033', '256', '88', '92', '-1', '-1', '2', NULL),
('711', '29128', '256', '93', '127', '-1', '-1', '2', NULL),
('711', '744', '256', '46', '62', '-1', '-1', '3', NULL),
('711', '3373', '256', '63', '66', '-1', '-1', '3', NULL),
('711', '5379', '256', '67', '76', '-1', '-1', '3', NULL),
('711', '14068', '256', '77', '81', '-1', '-1', '3', NULL),
('711', '18053', '256', '82', '86', '-1', '-1', '3', NULL),
('711', '26003', '256', '87', '91', '-1', '-1', '3', NULL),
('711', '29101', '256', '92', '127', '-1', '-1', '3', NULL),
('711', '3567', '256', '42', '60', '-1', '-1', '4', NULL),
('711', '3363', '256', '61', '65', '-1', '-1', '4', NULL),
('711', '5371', '256', '66', '75', '-1', '-1', '4', NULL),
('711', '14065', '256', '76', '80', '-1', '-1', '4', NULL),
('711', '18050', '256', '81', '85', '-1', '-1', '4', NULL),
('711', '25976', '256', '86', '90', '-1', '-1', '4', NULL),
('711', '29077', '256', '91', '127', '-1', '-1', '4', NULL),
('711', '707', '256', '30', '59', '-1', '-1', '5', NULL),
('711', '4210', '256', '60', '127', '-1', '-1', '5', NULL),
-- slow
('711', '738', '8192', '23', '50', '-1', '-1', '1', NULL),
('711', '1751', '8192', '51', '59', '-1', '-1', '1', NULL),
('711', '1748', '8192', '60', '63', '-1', '-1', '1', NULL),
('711', '3066', '8192', '64', '127', '-1', '-1', '1', NULL),
('711', '738', '8192', '51', '63', '-1', '-1', '2', NULL),
('711', '1751', '8192', '64', '127', '-1', '-1', '2', NULL),
('711', '738', '8192', '64', '127', '-1', '-1', '3', NULL),
-- cure
('711', '3682', '32768', '45', '85', '-1', '-1', '1', NULL),
('711', '25958', '32768', '86', '90', '-1', '-1', '1', NULL),
('711', '29059', '32768', '91', '127', '-1', '-1', '1', NULL),
('711', '3681', '32768', '52', '127', '-1', '-1', '2', NULL),
('711', '10448', '32768', '74', '78', '-1', '-1', '3', NULL),
('711', '14029', '32768', '79', '83', '-1', '-1', '3', NULL),
('711', '18023', '32768', '84', '127', '-1', '-1', '3', NULL),
-- hate redux
('711', '1754', '131072', '53', '127', '-1', '-1', '1', NULL),
('711', '10436', '131072', '73', '127', '-1', '-1', '2', NULL),
-- in-combat buff songs
('711', '2606', '262144', '52', '59', '-1', '-1', '1', NULL),
('711', '2610', '262144', '60', '127', '-1', '-1', '1', NULL),
('711', '700', '262144', '1', '9', '-1', '-1', '2', NULL),
('711', '701', '262144', '10', '35', '-1', '-1', '2', NULL),
('711', '740', '262144', '36', '41', '-1', '-1', '2', NULL),
('711', '702', '262144', '42', '49', '-1', '-1', '2', NULL),
('711', '747', '262144', '50', '61', '-1', '-1', '2', NULL),
('711', '3374', '262144', '62', '64', '-1', '-1', '2', NULL),
('711', '4871', '262144', '65', '67', '-1', '-1', '2', NULL),
('711', '5376', '262144', '68', '78', '-1', '-1', '2', NULL),
('711', '14080', '262144', '79', '83', '-1', '-1', '2', NULL),
('711', '18065', '262144', '84', '88', '-1', '-1', '2', NULL),
('711', '26042', '262144', '89', '93', '-1', '-1', '2', NULL),
('711', '29143', '262144', '94', '127', '-1', '-1', '2', NULL),
('711', '7', '262144', '6', '19', '-1', '-1', '2', NULL),
('711', '1287', '262144', '20', '31', '-1', '-1', '3', NULL),
('711', '723', '262144', '32', '33', '-1', '-1', '3', NULL),
('711', '1448', '262144', '34', '54', '-1', '-1', '3', NULL),
('711', '1759', '262144', '55', '61', '-1', '-1', '3', NULL),
('711', '3651', '262144', '62', '66', '-1', '-1', '3', NULL),
('711', '5377', '262144', '67', '70', '-1', '-1', '3', NULL),
('711', '10421', '262144', '71', '75', '-1', '-1', '3', NULL),
('711', '14008', '262144', '76', '80', '-1', '-1', '3', NULL),
('711', '18008', '262144', '81', '87', '-1', '-1', '3', NULL),
('711', '26015', '262144', '88', '92', '-1', '-1', '3', NULL),
('711', '29107', '262144', '93', '127', '-1', '-1', '3', NULL),
('711', '734', '262144', '7', '8', '-1', '-1', '4', NULL),
('711', '710', '262144', '9', '12', '-1', '-1', '4', NULL),
('711', '711', '262144', '13', '16', '-1', '-1', '4', NULL),
('711', '709', '262144', '17', '40', '-1', '-1', '4', NULL),
('711', '714', '262144', '41', '46', '-1', '-1', '4', NULL),
('711', '748', '262144', '47', '57', '-1', '-1', '4', NULL),
('711', '1763', '262144', '58', '72', '-1', '-1', '4', NULL),
('711', '11881', '262144', '73', '77', '-1', '-1', '4', NULL),
('711', '14056', '262144', '78', '82', '-1', '-1', '4', NULL),
('711', '18041', '262144', '83', '87', '-1', '-1', '4', NULL),
('711', '26027', '262144', '88', '92', '-1', '-1', '4', NULL),
('711', '29122', '262144', '93', '127', '-1', '-1', '4', NULL),
('711', '734', '262144', '9', '24', '-1', '-1', '5', NULL),
('711', '712', '262144', '25', '28', '-1', '-1', '5', NULL),
('711', '715', '262144', '29', '32', '-1', '-1', '5', NULL),
('711', '713', '262144', '33', '36', '-1', '-1', '5', NULL),
('711', '716', '262144', '37', '44', '-1', '-1', '5', NULL),
('711', '4083', '262144', '45', '52', '-1', '-1', '5', NULL),
('711', '4084', '262144', '53', '63', '-1', '-1', '5', NULL),
('711', '3362', '262144', '64', '64', '-1', '-1', '5', NULL),
('711', '4872', '262144', '65', '68', '-1', '-1', '5', NULL),
('711', '5382', '262144', '69', '75', '-1', '-1', '5', NULL),
('711', '14062', '262144', '76', '80', '-1', '-1', '5', NULL),
('711', '18047', '262144', '81', '85', '-1', '-1', '5', NULL),
('711', '25961', '262144', '86', '90', '-1', '-1', '5', NULL),
('711', '29062', '262144', '91', '127', '-1', '-1', '5', NULL),
('711', '734', '262144', '25', '43', '-1', '-1', '6', NULL),
('711', '4085', '262144', '44', '51', '-1', '-1', '6', NULL),
('711', '4086', '262144', '52', '62', '-1', '-1', '6', NULL),
('711', '4087', '262144', '63', '68', '-1', '-1', '6', NULL),
('711', '5374', '262144', '69', '71', '-1', '-1', '6', NULL),
('711', '10439', '262144', '72', '76', '-1', '-1', '6', NULL),
('711', '14020', '262144', '77', '81', '-1', '-1', '6', NULL),
('711', '18014', '262144', '82', '86', '-1', '-1', '6', NULL),
('711', '25991', '262144', '87', '127', '-1', '-1', '6', NULL),
('711', '734', '262144', '30', '82', '-1', '-1', '7', NULL),
('711', '18020', '262144', '83', '127', '-1', '-1', '7', NULL),
('711', '734', '262144', '83', '127', '-1', '-1', '8', NULL),
('711', '2603', '262144', '30', '127', '-1', '-1', '9', NULL),
-- out-of-combat buff songs
('711', '7', '524288', '6', '19', '-1', '-1', '1', NULL),
('711', '1287', '524288', '20', '31', '-1', '-1', '1', NULL),
('711', '723', '524288', '32', '33', '-1', '-1', '1', NULL),
('711', '1448', '524288', '34', '54', '-1', '-1', '1', NULL),
('711', '1759', '524288', '55', '61', '-1', '-1', '1', NULL),
('711', '3651', '524288', '62', '66', '-1', '-1', '1', NULL),
('711', '5377', '524288', '67', '70', '-1', '-1', '1', NULL),
('711', '10421', '524288', '71', '75', '-1', '-1', '1', NULL),
('711', '14008', '524288', '76', '80', '-1', '-1', '1', NULL),
('711', '18008', '524288', '81', '87', '-1', '-1', '1', NULL),
('711', '26015', '524288', '88', '92', '-1', '-1', '1', NULL),
('711', '29107', '524288', '93', '127', '-1', '-1', '1', NULL),
('711', '717', '524288', '5', '29', '-1', '-1','2', NULL),
('711', '2603', '524288', '30', '127', '-1', '-1','2', NULL),
('711', '717', '524288', '30', '48', '-1', '-1','3', NULL),
('711', '2605', '524288', '49', '127', '-1', '-1','3', NULL),
('711', '2602', '524288', '15', '127', '-1', '-1','4', NULL);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,19 @@
-- Re-ordered entries according to actual class values and added melee types (for future expansion)
DELETE FROM `npc_spells` WHERE `id` >= '701' AND `id` <= '712';
INSERT INTO `npc_spells` VALUES (3001, 'Warrior Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3002, 'Cleric Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3003, 'Paladin Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3004, 'Ranger Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3005, 'Shadowknight Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3006, 'Druid Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3007, 'Monk Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3008, 'Bard Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3009, 'Rogue Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3010, 'Shaman Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3011, 'Necromancer Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3012, 'Wizard Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3013, 'Magician Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3014, 'Enchanter Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3015, 'Beastlord Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3016, 'Berserker Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,13 @@
-- Update npc_spells_id to new values
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3002' WHERE `npc_spells_id` = '701';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3012' WHERE `npc_spells_id` = '702';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3011' WHERE `npc_spells_id` = '703';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3013' WHERE `npc_spells_id` = '704';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3014' WHERE `npc_spells_id` = '705';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3010' WHERE `npc_spells_id` = '706';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3006' WHERE `npc_spells_id` = '707';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3003' WHERE `npc_spells_id` = '708';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3005' WHERE `npc_spells_id` = '709';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3004' WHERE `npc_spells_id` = '710';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3008' WHERE `npc_spells_id` = '711';
UPDATE `bot_spells_entries` SET `npc_spells_id` = '3015' WHERE `npc_spells_id` = '712';
@@ -0,0 +1,17 @@
-- Update spells_id to new values
UPDATE `bot_data` SET `spells_id` = '3001' WHERE `class` = '1';
UPDATE `bot_data` SET `spells_id` = '3002' WHERE `class` = '2';
UPDATE `bot_data` SET `spells_id` = '3003' WHERE `class` = '3';
UPDATE `bot_data` SET `spells_id` = '3004' WHERE `class` = '4';
UPDATE `bot_data` SET `spells_id` = '3005' WHERE `class` = '5';
UPDATE `bot_data` SET `spells_id` = '3006' WHERE `class` = '6';
UPDATE `bot_data` SET `spells_id` = '3007' WHERE `class` = '7';
UPDATE `bot_data` SET `spells_id` = '3008' WHERE `class` = '8';
UPDATE `bot_data` SET `spells_id` = '3009' WHERE `class` = '9';
UPDATE `bot_data` SET `spells_id` = '3010' WHERE `class` = '10';
UPDATE `bot_data` SET `spells_id` = '3011' WHERE `class` = '11';
UPDATE `bot_data` SET `spells_id` = '3012' WHERE `class` = '12';
UPDATE `bot_data` SET `spells_id` = '3013' WHERE `class` = '13';
UPDATE `bot_data` SET `spells_id` = '3014' WHERE `class` = '14';
UPDATE `bot_data` SET `spells_id` = '3015' WHERE `class` = '15';
UPDATE `bot_data` SET `spells_id` = '3016' WHERE `class` = '16';
@@ -0,0 +1,25 @@
update npc_types set attack_speed=0, atk=ceil(1.7*level), accuracy=ceil(1.7*level) where (name like 'Swarm%' or name like '%skel%' or name like 'BLpet%' or name like 'Sum%')
and id >510 and id <860;
update npc_types set attack_speed=0, atk=ceil(0.5*level), accuracy=ceil(0.5*level) where name like 'SumFire%';
update npc_types set attack_speed=0, atk=ceil(1.775*level), accuracy=ceil(1.775*level) where name like 'SumAir%';
update npc_types set attack_speed=0, atk=ceil(1.775*level), accuracy=ceil(1.775*level) where name like 'SumEarth%';
update npc_types set attack_speed=0, atk=ceil(2.26*level), accuracy=ceil(2.26*level),gender=2,size=3 where name like 'BestialAid%';
update npc_types set attack_speed=0, atk=ceil(2.26*level), accuracy=ceil(2.26*level),gender=2,size=3 where name like 'RagingServant%';
update npc_types n
set ac=
ceil(case
when level < 3 then level*2+2
when level < 15 and level >=3 then level*3
when id >= 200000 and id < 224000 then 200*.5+level
else level * 4.1 end
* (case when raid_target=1 then 1.4 else 1 end) + (case when raid_target=1 then level*1.4 else 0 end))
+ 4*ifnull((select min(expansion)from zone where zoneidnumber=floor(n.id/1000)),5)
,str=ceil((level * 4.1)*.75) + case when raid_target=1 then level else 0 end + 4*ifnull((select min(expansion)from zone where zoneidnumber=floor(n.id/1000)),5)
,sta=ceil((level * 4.1)*.75) + case when raid_target=1 then level else 0 end + 4*ifnull((select min(expansion)from zone where zoneidnumber=floor(n.id/1000)),5)
,agi=ceil((level * 4.1)*.75) + case when raid_target=1 then level else 0 end + 4*ifnull((select min(expansion)from zone where zoneidnumber=floor(n.id/1000)),5)
,_int=ceil((level * 4.1)*.75) + case when raid_target=1 then level else 0 end + 4*ifnull((select min(expansion)from zone where zoneidnumber=floor(n.id/1000)),5)
,dex=ceil((level * 4.1)*.75) + case when raid_target=1 then level else 0 end + 4*ifnull((select min(expansion)from zone where zoneidnumber=floor(n.id/1000)),5)
,wis=ceil((level * 4.1)*.75) + case when raid_target=1 then level else 0 end + 4*ifnull((select min(expansion)from zone where zoneidnumber=floor(n.id/1000)),5)
,cha=ceil((level * 4.1)*.75) + case when raid_target=1 then level else 0 end + 4*ifnull((select min(expansion)from zone where zoneidnumber=floor(n.id/1000)),5);
@@ -0,0 +1,2 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:LevelToStopDamageCaps', '0', '1 will effectively disable them, 20 should give basically same results as old incorrect system.');
@@ -0,0 +1,10 @@
INSERT INTO `rule_values` VALUES (1, 'Range:SongMessages', '75', 'The packet range in which song messages are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:Emote', '135', 'The packet range in which emote messages are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:BeginCast', '200', 'The packet range in which begin cast messages are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:Anims', '135', 'The packet range in which animations are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:DamageMessages', '50', 'The packet range in which damage messages are sent (non-crit)');
INSERT INTO `rule_values` VALUES (1, 'Range:SpellMessages', '75', 'The packet range in which spell damage messages are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:Say', '135', 'The range that is required before /say or hail messages will work to an NPC');
INSERT INTO `rule_values` VALUES (1, 'Range:SpellParticles', '135', 'The packet range in which spell particles are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:MobPositionUpdates', '600', 'The packet range in which mob position updates are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:CriticalDamage', '80', 'The packet range in which critical hit messages are sent');
@@ -0,0 +1 @@
INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Mercs:MercsUsePathing', 'false', 'Mercs will use node pathing when moving');
@@ -0,0 +1,15 @@
alter table books add language int not null default 0;
drop table if exists reading_is_fundamental;
create table reading_is_fundamental
(
filename varchar(32),
language int
);
insert into reading_is_fundamental (select items.filename, items.booktype from items where items.filename != "" group by filename);
update books set books.language = (select language from reading_is_fundamental r where r.filename = books.name);
drop table reading_is_fundamental;
@@ -0,0 +1,4 @@
UPDATE `books` SET `language` = '0' WHERE `language` IS NULL;
ALTER TABLE `books` MODIFY COLUMN `language` INT NOT NULL DEFAULT '0';
@@ -0,0 +1 @@
ALTER TABLE `npc_spells_entries` MODIFY COLUMN `type` INT(10) UNSIGNED NOT NULL DEFAULT '0';
@@ -0,0 +1,31 @@
-- Delete any existing `bots_spells_entries` table
DROP TABLE IF EXISTS `bots_spells_entries`;
-- Create new bot spells entries table (new table does not have spells_id_spellid constraint)
CREATE TABLE `bot_spells_entries` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`npc_spells_id` INT(11) NOT NULL DEFAULT '0',
`spellid` SMALLINT(5) NOT NULL DEFAULT '0',
`type` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`minlevel` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
`maxlevel` TINYINT(3) UNSIGNED NOT NULL DEFAULT '255',
`manacost` SMALLINT(5) NOT NULL DEFAULT '-1',
`recast_delay` INT(11) NOT NULL DEFAULT '-1',
`priority` SMALLINT(5) NOT NULL DEFAULT '0',
`resist_adjust` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1
;
-- Copy bots spells into new table
INSERT INTO `bot_spells_entries` (`npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`, `manacost`, `recast_delay`, `priority`, `resist_adjust`)
SELECT `npc_spells_id`, `spellid`, `type`, `minlevel`, `maxlevel`, `manacost`, `recast_delay`, `priority`, `resist_adjust`
FROM `npc_spells_entries` WHERE `npc_spells_id` >= '701' AND `npc_spells_id` <= '712';
-- Delete bot spells from old table
DELETE FROM `npc_spells_entries` WHERE `npc_spells_id` >= '701' AND `npc_spells_id` <= '712';
-- Admins can remove this new table if they are 100% certain they will never use bots
@@ -0,0 +1,19 @@
-- Re-ordered entries according to actual class values and added melee types (for future expansion)
DELETE FROM `npc_spells` WHERE `id` >= '701' AND `id` <= '712';
INSERT INTO `npc_spells` VALUES (3001, 'Warrior Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3002, 'Cleric Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3003, 'Paladin Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3004, 'Ranger Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3005, 'Shadowknight Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3006, 'Druid Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3007, 'Monk Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3008, 'Bard Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3009, 'Rogue Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3010, 'Shaman Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3011, 'Necromancer Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3012, 'Wizard Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3013, 'Magician Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3014, 'Enchanter Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3015, 'Beastlord Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `npc_spells` VALUES (3016, 'Berserker Bot', 0, -1, 3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
@@ -0,0 +1,11 @@
DROP TABLE IF EXISTS `inventory_version`;
CREATE TABLE `inventory_version` (
`version` INT(11) UNSIGNED NOT NULL DEFAULT '0',
`step` INT(11) UNSIGNED NOT NULL DEFAULT '0'
)
COLLATE='latin1_swedish_ci'
ENGINE=MyISAM
;
INSERT INTO `inventory_version` VALUES (2, 0);
+100
View File
@@ -0,0 +1,100 @@
aa_ability
aa_actions
aa_effects
aa_required_level_cost
aa_ranks
aa_rank_effects
aa_rank_prereqs
activities
adventure_template
adventure_template_entry
adventure_template_entry_flavor
altadv_vars
alternate_currency
base_data
blocked_spells
books
char_create_combinations
char_create_point_allocations
class_skill
damageshieldtypes
doors
faction_list
faction_list_mod
fear_hints
fishing
forage
goallists
graveyard
grid
grid_entries
ground_spawns
horses
instance_list
items
ldon_trap_templates
ldon_trap_entries
level_exp_mods
lootdrop
lootdrop_entries
loottable
loottable_entries
merc_armorinfo
merc_weaponinfo
merc_stats
merc_merchant_entries
merc_merchant_template_entries
merc_merchant_templates
merc_stance_entries
merc_templates
merc_npc_types
merc_name_types
merc_subtypes
merc_types
merc_spell_list_entries
merc_spell_lists
merc_buffs
mercs
merc_inventory
merchantlist
npc_emotes
npc_faction
npc_faction_entries
npc_spells
npc_spells_entries
npc_spells_effects
npc_spells_effects_entries
npc_types
npc_types_metadata
npc_types_tint
object
pets
pets_equipmentset
pets_equipmentset_entries
proximities
races
saylink
skill_caps
spawn2
spawn_conditions
spawn_condition_values
spawn_events
spawnentry
spawngroup
spells_new
start_zones
starting_items
tasks
tasksets
titles
tradeskill_recipe
tradeskill_recipe_entries
traps
tribute_levels
tributes
veteran_reward_templates
zone
zone_points
zone_server
zone_state_dump
zoneserver_auth
+92
View File
@@ -0,0 +1,92 @@
aa_timers
account
account_flags
account_ip
account_rewards
adventure_details
adventure_members
adventure_stats
Banned_IPs
bugs
buyer
char_recipe_list
character_data
character_currency
character_alternate_abilities
character_bind
character_corpses
character_corpse_items
character_languages
character_lookup
character_skills
character_spells
character_memmed_spells
character_disciplines
character_material
character_tribute
character_bandolier
character_potionbelt
character_inspect_messages
character_leadership_abilities
character_activities
character_alt_currency
character_buffs
character_enabledtasks
character_pet_buffs
character_pet_info
character_pet_inventory
character_tasks
chatchannels
completed_tasks
discovered_items
eventlog
faction_values
friends
gm_ips
group_id
group_leaders
guilds
guild_bank
guild_ranks
guild_relations
guild_members
hackers
instance_list_player
inventory
item_tick
keyring
launcher_zones
lfguild
mail
merchantlist_temp
name_filter
object_contents
petitions
player_titlesets
qs_player_move_record
qs_player_move_record_entries
qs_player_npc_kill_record
qs_player_npc_kill_record_entries
qs_player_speech
qs_player_trade_record
qs_player_trade_record_entries
qs_merchant_transaction_record
qs_merchant_transaction_record_entries
qs_player_delete_record
qs_player_delete_record_entries
qs_player_handin_record
qs_player_handin_record_entries
qs_player_aa_rate_hourly
qs_player_events
quest_globals
raid_details
raid_leaders
raid_members
reports
respawn_times
sharedbank
spell_globals
timers
trader
trader_audit
zone_flags
+14 -6
View File
@@ -1022,6 +1022,12 @@ bool Client::HandlePacket(const EQApplicationPacket *app) {
eqs->Close();
return true;
}
case OP_WorldLogout:
{
eqs->Close();
cle->SetOnline(CLE_Status_Offline); //allows this player to log in again without an ip restriction.
return false;
}
case OP_ZoneChange:
{
// HoT sends this to world while zoning and wants it echoed back.
@@ -1552,12 +1558,14 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
database.GetSafePoints(pp.zone_id, 0, &pp.x, &pp.y, &pp.z);
}
/* Will either be the same as home or tutorial */
pp.binds[0].zoneId = pp.zone_id;
pp.binds[0].x = pp.x;
pp.binds[0].y = pp.y;
pp.binds[0].z = pp.z;
pp.binds[0].heading = pp.heading;
/* Will either be the same as home or tutorial if enabled. */
if(RuleB(World, StartZoneSameAsBindOnCreation)) {
pp.binds[0].zoneId = pp.zone_id;
pp.binds[0].x = pp.x;
pp.binds[0].y = pp.y;
pp.binds[0].z = pp.z;
pp.binds[0].heading = pp.heading;
}
Log.Out(Logs::Detail, Logs::World_Server,"Current location: %s (%d) %0.2f, %0.2f, %0.2f, %0.2f",
database.GetZoneName(pp.zone_id), pp.zone_id, pp.x, pp.y, pp.z, pp.heading);
+18 -1
View File
@@ -214,6 +214,24 @@ void ClientList::GetCLEIP(uint32 iIP) {
}
}
uint32 ClientList::GetCLEIPCount(uint32 iIP) {
ClientListEntry* countCLEIPs = 0;
LinkedListIterator<ClientListEntry*> iterator(clientlist);
int IPInstances = 0;
iterator.Reset();
while (iterator.MoreElements()) {
countCLEIPs = iterator.GetData();
if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0)) && countCLEIPs->Online() >= CLE_Status_Online) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt)
IPInstances++; // Increment the occurences of this IP address
}
iterator.Advance();
}
return IPInstances;
}
void ClientList::DisconnectByIP(uint32 iIP) {
ClientListEntry* countCLEIPs = 0;
LinkedListIterator<ClientListEntry*> iterator(clientlist);
@@ -252,7 +270,6 @@ ClientListEntry* ClientList::FindCharacter(const char* name) {
return 0;
}
ClientListEntry* ClientList::FindCLEByAccountID(uint32 iAccID) {
LinkedListIterator<ClientListEntry*> iterator(clientlist);
+1
View File
@@ -56,6 +56,7 @@ public:
ClientListEntry* FindCLEByCharacterID(uint32 iCharID);
ClientListEntry* GetCLE(uint32 iID);
void GetCLEIP(uint32 iIP);
uint32 GetCLEIPCount(uint32 iLSAccountID);
void DisconnectByIP(uint32 iIP);
void EnforceSessionLimit(uint32 iLSAccountID);
void CLCheckStale();
+21 -3
View File
@@ -68,7 +68,7 @@ void CatchSignal(int sig_num);
Console::Console(EmuTCPConnection* itcpc)
: WorldTCPConnection(),
timeout_timer(RuleI(Console, SessionTimeOut)),
prompt_timer(1000)
prompt_timer(1)
{
tcpc = itcpc;
tcpc->SetEcho(true);
@@ -224,9 +224,27 @@ bool Console::Process() {
}
//if we have not gotten the special markers after this timer, send login prompt
if(prompt_timer.Check()) {
struct in_addr in;
in.s_addr = GetIP();
std::string connecting_ip = inet_ntoa(in);
SendMessage(2, StringFormat("Establishing connection from IP: %s Port: %d", inet_ntoa(in), GetPort()).c_str());
if (connecting_ip.find("127.0.0.1") != std::string::npos) {
SendMessage(2, StringFormat("Connecting established from local host, auto assuming admin").c_str());
state = CONSOLE_STATE_CONNECTED;
tcpc->SetEcho(false);
admin = 255;
SendPrompt();
}
else {
if (tcpc->GetMode() == EmuTCPConnection::modeConsole)
tcpc->Send((const uchar*) "Username: ", strlen("Username: "));
}
prompt_timer.Disable();
if(tcpc->GetMode() == EmuTCPConnection::modeConsole)
tcpc->Send((const uchar*) "Username: ", strlen("Username: "));
}
if (timeout_timer.Check()) {
+15
View File
@@ -134,11 +134,26 @@ bool LoginServer::Process() {
if( (int32)numplayers >= x && x != -1 && x != 255 && status < 80)
utwrs->response = -3;
if (pack->size == sizeof(UsertoWorldRequest_Struct))
{
uint32 decimalIP = inet_addr(utwr->IPAddr);
if (RuleB(World, MaxClientsSimplifiedLogic)) {
if (client_list.GetCLEIPCount(decimalIP) >= (RuleI(World, MaxClientsPerIP))) {
if ((status < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0)) {
utwrs->response = -4;
}
}
}
}
if(status == -1)
utwrs->response = -1;
if(status == -2)
utwrs->response = -2;
utwrs->worldid = utwr->worldid;
SendPacket(outpack);
delete outpack;
+4 -1
View File
@@ -353,7 +353,7 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct*
in_pp->x = in_pp->y = in_pp->z = in_pp->heading = in_pp->zone_id = 0;
in_pp->binds[0].x = in_pp->binds[0].y = in_pp->binds[0].z = in_pp->binds[0].zoneId = in_pp->binds[0].instance_id = 0;
// see if we have an entry for start_zone. We can support both titanium & SOF+ by having two entries per class/race/deity combo with different zone_ids
std::string query = StringFormat("SELECT x, y, z, heading, start_zone, bind_id FROM start_zones WHERE zone_id = %i "
std::string query = StringFormat("SELECT x, y, z, heading, start_zone, bind_id, bind_x, bind_y, bind_z FROM start_zones WHERE zone_id = %i "
"AND player_class = %i AND player_deity = %i AND player_race = %i",
in_cc->start_zone, in_cc->class_, in_cc->deity, in_cc->race);
auto results = QueryDatabase(query);
@@ -376,6 +376,9 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct*
in_pp->heading = atof(row[3]);
in_pp->zone_id = atoi(row[4]);
in_pp->binds[0].zoneId = atoi(row[5]);
in_pp->binds[0].x = atof(row[6]);
in_pp->binds[0].y = atof(row[7]);
in_pp->binds[0].z = atof(row[8]);
}
if(in_pp->x == 0 && in_pp->y == 0 && in_pp->z == 0)
+4
View File
@@ -4,6 +4,7 @@ SET(zone_sources
aa.cpp
aa_ability.cpp
aggro.cpp
aggromanager.cpp
attack.cpp
beacon.cpp
bonuses.cpp
@@ -122,6 +123,7 @@ SET(zone_sources
water_map_v2.cpp
waypoints.cpp
worldserver.cpp
xtargetautohaters.cpp
zone.cpp
zone_config.cpp
zonedb.cpp
@@ -131,6 +133,7 @@ SET(zone_sources
SET(zone_headers
aa.h
aa_ability.h
aggromanager.h
basic_functions.h
beacon.h
bot.h
@@ -215,6 +218,7 @@ SET(zone_headers
water_map_v1.h
water_map_v2.h
worldserver.h
xtargetautohaters.h
zone.h
zone_config.h
zonedb.h
+4
View File
@@ -42,6 +42,10 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
//Dook- swarms and wards
// do nothing if it's a corpse
if (targ != nullptr && targ->IsCorpse())
return;
PetRecord record;
if(!database.GetPetEntry(spells[spell_id].teleport_zone, &record))
{
+7 -7
View File
@@ -158,7 +158,7 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
if (RuleB(Aggro, UseLevelAggro))
{
if (GetLevel() < 18 && mob->GetLevelCon(GetLevel()) == CON_GREEN && GetBodyType() != 3)
if (GetLevel() < 18 && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3)
{
towho->Message(0, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2);
return;
@@ -166,7 +166,7 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
}
else
{
if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GREEN ) {
if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GRAY ) {
towho->Message(0, "...%s is red to me (basically)", mob->GetName(),
dist2, iAggroRange2);
return;
@@ -253,7 +253,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
//sometimes if a client has some lag while zoning into a dangerous place while either invis or a GM
//they will aggro mobs even though it's supposed to be impossible, to lets make sure we've finished connecting
if (mob->IsClient()) {
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn())
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->zoning)
return false;
}
@@ -339,7 +339,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
( GetLevel() >= 18 )
||(GetBodyType() == 3)
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
||( mob->GetLevelCon(GetLevel()) != CON_GREEN )
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
)
&&
@@ -372,7 +372,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
(
( GetINT() <= RuleI(Aggro, IntAggroThreshold) )
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
||( mob->GetLevelCon(GetLevel()) != CON_GREEN )
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
)
&&
@@ -449,7 +449,7 @@ int EntityList::GetHatedCount(Mob *attacker, Mob *exclude)
if (mob->IsFeared() || mob->IsMezzed())
continue;
if (attacker->GetLevelCon(mob->GetLevel()) == CON_GREEN)
if (attacker->GetLevelCon(mob->GetLevel()) == CON_GRAY)
continue;
if (!mob->CheckAggro(attacker))
@@ -508,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(mob->GetLevel() >= 50 || attacker->GetLevelCon(mob->GetLevel()) != CON_GREEN)
if(mob->GetLevel() >= 50 || attacker->GetLevelCon(mob->GetLevel()) != CON_GRAY)
{
bool useprimfaction = false;
if(mob->GetPrimaryFaction() == sender->CastToNPC()->GetPrimaryFaction())
+11
View File
@@ -0,0 +1,11 @@
#include "aggromanager.h"
AggroMeter::AggroMeter() : lock_id(0), target_id(0), secondary_id(0), lock_changed(false)
{
for (int i = 0; i < AT_Max; ++i) {
data[i].type = i;
data[i].pct = 0;
}
}
+80
View File
@@ -0,0 +1,80 @@
#ifndef AGGROMANAGER_H
#define AGGROMANAGER_H
#include "../common/types.h"
#include <assert.h>
#include <cstddef>
class AggroMeter
{
public:
enum AggroTypes {
AT_Player,
AT_Secondary,
AT_Group1,
AT_Group2,
AT_Group3,
AT_Group4,
AT_Group5,
AT_XTarget1,
AT_XTarget2,
AT_XTarget3,
AT_XTarget4,
AT_XTarget5,
AT_XTarget6,
AT_XTarget7,
AT_XTarget8,
AT_XTarget9,
AT_XTarget10,
AT_XTarget11,
AT_XTarget12,
AT_XTarget13,
AT_XTarget14,
AT_XTarget15,
AT_XTarget16,
AT_XTarget17,
AT_XTarget18,
AT_XTarget19,
AT_XTarget20,
AT_Max
};
private:
struct AggroData {
int16 type;
int16 pct;
};
AggroData data[AT_Max];
int lock_id; // we set this
int target_id; // current target or if PC targeted, their Target
// so secondary depends on if we have aggro or not
// When we are the current target, this will be the 2nd person on list
// When we are not tanking, this will be the current tank
int secondary_id;
// so we need some easy way to detect the client changing but still delaying the packet
bool lock_changed;
public:
AggroMeter();
~AggroMeter() {}
inline void set_lock_id(int in) { lock_id = in; lock_changed = true; }
inline bool update_lock() { bool ret = lock_changed; lock_changed = false; return ret; }
inline void set_target_id(int in) { target_id = in; }
inline void set_secondary_id(int in) { secondary_id = in; }
// returns true when changed
inline bool set_pct(AggroTypes t, int pct) { assert(t >= AT_Player && t < AT_Max); if (data[t].pct == pct) return false; data[t].pct = pct; return true; }
inline int get_lock_id() const { return lock_id; }
inline int get_target_id() const { return target_id; }
inline int get_secondary_id() const { return secondary_id; }
inline int get_pct(AggroTypes t) const { assert(t >= AT_Player && t < AT_Max); return data[t].pct; }
// the ID of the spawn for player entry depends on lock_id
inline int get_player_aggro_id() const { return lock_id ? lock_id : target_id; }
// fuck it, lets just use a buffer the size of the largest to work with
const inline size_t max_packet_size() const { return sizeof(uint8) + sizeof(uint32) + sizeof(uint8) + (sizeof(uint8) + sizeof(uint16)) * AT_Max; }
};
#endif /* !AGGROMANAGER_H */
+1356 -885
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -35,9 +35,9 @@ public:
//abstract virtual function implementations requird 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 void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
ExtraAttackOptions *opts = nullptr, int special = 0) { return false; }
ExtraAttackOptions *opts = nullptr) { return false; }
virtual bool HasRaid() { return false; }
virtual bool HasGroup() { return false; }
virtual Raid* GetRaid() { return 0; }
+35 -20
View File
@@ -46,6 +46,7 @@ void Mob::CalcBonuses()
CalcMaxHP();
CalcMaxMana();
SetAttackTimer();
CalcAC();
rooted = FindType(SE_Root);
}
@@ -669,6 +670,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
switch (effect) {
case SE_ACv2:
case SE_ArmorClass:
newbon->AC += base1;
break;
// Note: AA effects that use accuracy are skill limited, while spell effect is not.
case SE_Accuracy:
// Bad data or unsupported new skill
@@ -1308,8 +1313,9 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
case SE_HeadShotLevel: {
if (newbon->HSLevel < base1)
newbon->HSLevel = base1;
if (newbon->HSLevel[0] < base1)
newbon->HSLevel[0] = base1;
newbon->HSLevel[1] = base2;
break;
}
@@ -1322,8 +1328,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
case SE_AssassinateLevel: {
if (newbon->AssassinateLevel < base1)
newbon->AssassinateLevel = base1;
if (newbon->AssassinateLevel[0] < base1) {
newbon->AssassinateLevel[0] = base1;
newbon->AssassinateLevel[1] = base2;
}
break;
}
@@ -1381,7 +1389,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
case SE_MeleeMitigation:
newbon->MeleeMitigationEffect -= base1;
newbon->MeleeMitigationEffect += base1;
break;
case SE_ATK:
@@ -1527,9 +1535,6 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
}
}
// 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.
}
@@ -1927,8 +1932,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
break;
case SE_MeleeMitigation:
//for some reason... this value is negative for increased mitigation
new_bonus->MeleeMitigationEffect -= effect_value;
// This value is negative because it counteracts another SPA :P
new_bonus->MeleeMitigationEffect += effect_value;
break;
case SE_CriticalHitChance:
@@ -3024,8 +3029,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_HeadShotLevel:
{
if(new_bonus->HSLevel < effect_value)
new_bonus->HSLevel = effect_value;
if(new_bonus->HSLevel[0] < effect_value) {
new_bonus->HSLevel[0] = effect_value;
new_bonus->HSLevel[1] = base2;
}
break;
}
@@ -3040,8 +3047,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_AssassinateLevel:
{
if(new_bonus->AssassinateLevel < effect_value)
new_bonus->AssassinateLevel = effect_value;
if(new_bonus->AssassinateLevel[0] < effect_value) {
new_bonus->AssassinateLevel[0] = effect_value;
new_bonus->AssassinateLevel[1] = base2;
}
break;
}
@@ -4647,9 +4656,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
break;
case SE_HeadShotLevel:
spellbonuses.HSLevel = effect_value;
aabonuses.HSLevel = effect_value;
itembonuses.HSLevel = effect_value;
spellbonuses.HSLevel[0] = effect_value;
aabonuses.HSLevel[0] = effect_value;
itembonuses.HSLevel[0] = effect_value;
spellbonuses.HSLevel[1] = effect_value;
aabonuses.HSLevel[1] = effect_value;
itembonuses.HSLevel[1] = effect_value;
break;
case SE_Assassinate:
@@ -4662,9 +4674,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
break;
case SE_AssassinateLevel:
spellbonuses.AssassinateLevel = effect_value;
aabonuses.AssassinateLevel = effect_value;
itembonuses.AssassinateLevel = effect_value;
spellbonuses.AssassinateLevel[0] = effect_value;
aabonuses.AssassinateLevel[0] = effect_value;
itembonuses.AssassinateLevel[0] = effect_value;
spellbonuses.AssassinateLevel[1] = effect_value;
aabonuses.AssassinateLevel[1] = effect_value;
itembonuses.AssassinateLevel[1] = effect_value;
break;
case SE_FinishingBlow:
+1087 -885
View File
File diff suppressed because it is too large Load Diff
+98 -29
View File
@@ -38,7 +38,9 @@
#include <sstream>
#define BOT_DEFAULT_FOLLOW_DISTANCE 184
#define BOT_FOLLOW_DISTANCE_DEFAULT 184 // as DSq value (~13.565 units)
#define BOT_FOLLOW_DISTANCE_DEFAULT_MAX 2500 // as DSq value (50 units)
#define BOT_FOLLOW_DISTANCE_WALK 1000 // as DSq value (~31.623 units)
extern WorldServer worldserver;
@@ -47,8 +49,6 @@ const int MaxSpellTimer = 15;
const int MaxDisciplineTimer = 10;
const int DisciplineReuseStart = MaxSpellTimer + 1;
const int MaxTimer = MaxSpellTimer + MaxDisciplineTimer;
const int MaxStances = 7;
const int MaxSpellTypes = 16;
enum BotStanceType {
BotStancePassive,
@@ -58,7 +58,8 @@ enum BotStanceType {
BotStanceAggressive,
BotStanceBurn,
BotStanceBurnAE,
BotStanceUnknown
BotStanceUnknown,
MaxStances = BotStanceUnknown
};
#define BOT_STANCE_COUNT 8
@@ -125,9 +126,55 @@ enum SpellTypeIndex {
SpellType_CharmIndex,
SpellType_SlowIndex,
SpellType_DebuffIndex,
SpellType_CureIndex
SpellType_CureIndex,
SpellType_ResurrectIndex,
SpellType_HateReduxIndex,
SpellType_InCombatBuffSongIndex,
SpellType_OutOfCombatBuffSongIndex,
SpellType_PreCombatBuffIndex,
SpellType_PreCombatBuffSongIndex,
MaxSpellTypes
};
// nHSND negative Healer/Slower/Nuker/Doter
// pH positive Healer
// pS positive Slower
// pHS positive Healer/Slower
// pN positive Nuker
// pHN positive Healer/Nuker
// pSN positive Slower/Nuker
// pHSN positive Healer/Slower/Nuker
// pD positive Doter
// pHD positive Healer/Doter
// pSD positive Slower/Doter
// pHSD positive Healer/Slower/Doter
// pND positive Nuker/Doter
// pHND positive Healer/Nuker/Doter
// pSND positive Slower/Nuker/Doter
// pHSND positive Healer/Slower/Nuker/Doter
// cntHSND count Healer/Slower/Nuker/Doter
enum BotCastingChanceConditional : uint8
{
nHSND = 0,
pH,
pS,
pHS,
pN,
pHN,
pSN,
pHSN,
pD,
pHD,
pSD,
pHSD,
pND,
pHND,
pSND,
pHSND,
cntHSND = 16
};
class Bot : public NPC {
friend class Mob;
public:
@@ -206,9 +253,9 @@ public:
//abstract virtual function implementations requird by base abstract class
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 void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
ExtraAttackOptions *opts = nullptr, int special = 0);
ExtraAttackOptions *opts = nullptr);
virtual bool HasRaid() { return (GetRaid() ? true : false); }
virtual bool HasGroup() { return (GetGroup() ? true : false); }
virtual Raid* GetRaid() { return entity_list.GetRaidByMob(this); }
@@ -235,11 +282,11 @@ public:
virtual void Depop();
void CalcBotStats(bool showtext = true);
uint16 BotGetSpells(int spellslot) { return AIspells[spellslot].spellid; }
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
uint32 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
virtual float GetProcChances(float ProcBonus, uint16 hand);
virtual int GetHandToHandDamage(void);
virtual bool TryFinishingBlow(Mob *defender, EQEmu::skills::SkillType skillinuse);
virtual bool TryFinishingBlow(Mob *defender, int &damage);
virtual void DoRiposte(Mob* defender);
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; }
@@ -248,13 +295,12 @@ public:
uint16 GetPrimarySkillValue();
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 int GetBaseSkillDamage(EQEmu::skills::SkillType skill, Mob *target = nullptr);
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, 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);
@@ -289,14 +335,15 @@ public:
void Stand();
bool IsSitting();
bool IsStanding();
bool IsBotCasterCombatRange(Mob *target);
bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true) ;
int GetBotWalkspeed() const { return (int)((float)_GetWalkSpeed() * 1.786f); } // 1.25 / 0.7 = 1.7857142857142857142857142857143
int GetBotRunspeed() const { return (int)((float)_GetRunSpeed() * 1.786f); }
bool IsBotCasterAtCombatRange(Mob *target);
bool UseDiscipline(uint32 spell_id, uint32 target);
uint8 GetNumberNeedingHealedInGroup(uint8 hpr, bool includePets);
bool GetNeedsCured(Mob *tar);
bool GetNeedsHateRedux(Mob *tar);
bool HasOrMayGetAggro();
void SetDefaultBotStance();
void CalcChanceToCast();
inline virtual int32 GetMaxStat();
inline virtual int32 GetMaxResist();
@@ -350,7 +397,7 @@ public:
void DoEnduranceUpkeep(); //does the endurance upkeep
// AI Methods
virtual bool AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes);
virtual bool AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes);
virtual bool AI_EngagedCastCheck();
virtual bool AI_PursueCastCheck();
virtual bool AI_IdleCastCheck();
@@ -414,10 +461,13 @@ public:
static int32 GetDisciplineRecastTimer(Bot *caster, int timer_index);
static bool CheckDisciplineRecastTimers(Bot *caster, int timer_index);
static uint32 GetDisciplineRemainingTime(Bot *caster, int timer_index);
static std::list<BotSpell> GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect);
static std::list<BotSpell> GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType);
static std::list<BotSpell> GetBotSpellsBySpellType(Bot* botCaster, uint16 spellType);
static BotSpell GetFirstBotSpellBySpellType(Bot* botCaster, uint16 spellType);
static std::list<BotSpell> GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType);
static std::list<BotSpell_wPriority> GetPrioritizedBotSpellsBySpellType(Bot* botCaster, uint32 spellType);
static BotSpell GetFirstBotSpellBySpellType(Bot* botCaster, uint32 spellType);
static BotSpell GetBestBotSpellForFastHeal(Bot* botCaster);
static BotSpell GetBestBotSpellForHealOverTime(Bot* botCaster);
static BotSpell GetBestBotSpellForPercentageHeal(Bot* botCaster);
@@ -428,6 +478,7 @@ public:
static BotSpell GetBestBotSpellForGroupHeal(Bot* botCaster);
static BotSpell GetBestBotSpellForMagicBasedSlow(Bot* botCaster);
static BotSpell GetBestBotSpellForDiseaseBasedSlow(Bot* botCaster);
static Mob* GetFirstIncomingMobToMez(Bot* botCaster, BotSpell botSpell);
static BotSpell GetBestBotSpellForMez(Bot* botCaster);
static BotSpell GetBestBotMagicianPetSpell(Bot* botCaster);
@@ -438,17 +489,12 @@ public:
static BotSpell GetDebuffBotSpell(Bot* botCaster, Mob* target);
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 Bot Group Methods
static bool AddBotToGroup(Bot* bot, Group* group);
static bool RemoveBotFromGroup(Bot* bot, Group* group);
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); }
static bool GroupHasShamanClass(Group* group) { return GroupHasClass(group, SHAMAN); }
static bool GroupHasEnchanterClass(Group* group) { return GroupHasClass(group, ENCHANTER); }
static bool GroupHasPriestClass(Group* group) { return GroupHasClass(group, CLERIC | DRUID | SHAMAN); }
static void BotGroupSay(Mob *speaker, const char *msg, ...);
// "GET" Class Methods
@@ -467,9 +513,20 @@ public:
bool GetRangerAutoWeaponSelect() { return _rangerAutoWeaponSelect; }
BotRoleType GetBotRole() { return _botRole; }
BotStanceType GetBotStance() { return _botStance; }
uint8 GetChanceToCastBySpellType(uint16 spellType);
bool IsGroupPrimaryHealer();
bool IsGroupPrimarySlower();
uint8 GetChanceToCastBySpellType(uint32 spellType);
bool IsGroupHealer() { return m_CastingRoles.GroupHealer; }
bool IsGroupSlower() { return m_CastingRoles.GroupSlower; }
bool IsGroupNuker() { return m_CastingRoles.GroupNuker; }
bool IsGroupDoter() { return m_CastingRoles.GroupDoter; }
static void UpdateGroupCastingRoles(const Group* group, bool disband = false);
//bool IsRaidHealer() { return m_CastingRoles.RaidHealer; }
//bool IsRaidSlower() { return m_CastingRoles.RaidSlower; }
//bool IsRaidNuker() { return m_CastingRoles.RaidNuker; }
//bool IsRaidDoter() { return m_CastingRoles.RaidDoter; }
//static void UpdateRaidCastingRoles(const Raid* raid, bool disband = false);
bool IsBotCaster() { return IsCasterClass(GetClass()); }
bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); }
bool IsBotWISCaster() { return IsWISCasterClass(GetClass()); }
@@ -503,7 +560,6 @@ public:
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; }
inline virtual int32 GetDEX() const { return DEX; }
@@ -599,7 +655,7 @@ public:
// 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 BotRemoveEquipItem(int16 slot);
void RemoveBotItemBySlot(uint32 slotID, std::string* errorMessage);
uint32 GetTotalPlayTime();
@@ -634,6 +690,16 @@ protected:
virtual bool AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgainBefore = 0);
virtual float GetMaxMeleeRangeToTarget(Mob* target);
BotCastingRoles& GetCastingRoles() { return m_CastingRoles; }
void SetGroupHealer(bool flag = true) { m_CastingRoles.GroupHealer = flag; }
void SetGroupSlower(bool flag = true) { m_CastingRoles.GroupSlower = flag; }
void SetGroupNuker(bool flag = true) { m_CastingRoles.GroupNuker = flag; }
void SetGroupDoter(bool flag = true) { m_CastingRoles.GroupDoter = flag; }
//void SetRaidHealer(bool flag = true) { m_CastingRoles.RaidHealer = flag; }
//void SetRaidSlower(bool flag = true) { m_CastingRoles.RaidSlower = flag; }
//void SetRaidNuker(bool flag = true) { m_CastingRoles.RaidNuker = flag; }
//void SetRaidDoter(bool flag = true) { m_CastingRoles.RaidDoter = flag; }
private:
// Class Members
uint32 _botID;
@@ -670,7 +736,10 @@ private:
uint32 timers[MaxTimer];
bool _hasBeenSummoned;
glm::vec3 m_PreSummonLocation;
uint8 _spellCastingChances[MaxStances][MaxSpellTypes];
Timer evade_timer; // can be moved to pTimers at some point
BotCastingRoles m_CastingRoles;
std::shared_ptr<HealRotation> m_member_of_heal_rotation;
+9 -2
View File
@@ -436,6 +436,8 @@ public:
case 10:
if (spells[spell_id].effectdescnum != 65)
break;
if (IsEffectInSpell(spell_id, SE_NegateIfCombat))
break;
entry_prototype = new STMovementSpeedEntry();
entry_prototype->SafeCastToMovementSpeed()->group = BCSpells::IsGroupType(target_type);
break;
@@ -4548,7 +4550,7 @@ void bot_subcommand_bot_follow_distance(Client *c, const Seperator *sep)
}
const int ab_mask = ActionableBots::ABM_NoFilter;
uint32 bfd = BOT_DEFAULT_FOLLOW_DISTANCE;
uint32 bfd = BOT_FOLLOW_DISTANCE_DEFAULT;
bool set_flag = false;
int ab_arg = 2;
@@ -4559,6 +4561,10 @@ void bot_subcommand_bot_follow_distance(Client *c, const Seperator *sep)
}
bfd = atoi(sep->arg[2]);
if (bfd < 1)
bfd = 1;
if (bfd > BOT_FOLLOW_DISTANCE_DEFAULT_MAX)
bfd = BOT_FOLLOW_DISTANCE_DEFAULT_MAX;
set_flag = true;
ab_arg = 3;
}
@@ -5115,7 +5121,6 @@ void bot_subcommand_bot_stance(Client *c, const Seperator *sep)
if (!current_flag) {
bot_iter->SetBotStance(bst);
bot_iter->CalcChanceToCast();
bot_iter->Save();
}
@@ -5146,6 +5151,7 @@ void bot_subcommand_bot_summon(Client *c, const Seperator *sep)
bot_iter->WipeHateList();
bot_iter->SetTarget(bot_iter->GetBotOwner());
bot_iter->Warp(glm::vec3(c->GetPosition()));
bot_iter->DoAnim(0);
if (!bot_iter->HasPet())
continue;
@@ -5394,6 +5400,7 @@ void bot_subcommand_bot_update(Client *c, const Seperator *sep)
bot_iter->SetPetChooser(false);
bot_iter->CalcBotStats((sbl.size() == 1));
bot_iter->SendAppearancePacket(AT_WhoLevel, bot_iter->GetLevel(), true, true);
++bot_count;
}
+84 -3
View File
@@ -82,6 +82,66 @@ bool BotDatabase::LoadBotCommandSettings(std::map<std::string, std::pair<uint8,
return true;
}
static uint8 spell_casting_chances[MaxSpellTypes][PLAYER_CLASS_COUNT][MaxStances][cntHSND];
bool BotDatabase::LoadBotSpellCastingChances()
{
memset(spell_casting_chances, 0, sizeof(spell_casting_chances));
query =
"SELECT"
" `spell_type_index`,"
" `class_id`,"
" `stance_index`,"
" `nHSND_value`,"
" `pH_value`,"
" `pS_value`,"
" `pHS_value`,"
" `pN_value`,"
" `pHN_value`,"
" `pSN_value`,"
" `pHSN_value`,"
" `pD_value`,"
" `pHD_value`,"
" `pSD_value`,"
" `pHSD_value`,"
" `pND_value`,"
" `pHND_value`,"
" `pSND_value`,"
" `pHSND_value`"
"FROM"
" `bot_spell_casting_chances`";
auto results = QueryDatabase(query);
if (!results.Success() || !results.RowCount())
return false;
for (auto row = results.begin(); row != results.end(); ++row) {
uint8 spell_type_index = atoi(row[0]);
if (spell_type_index >= MaxSpellTypes)
continue;
uint8 class_index = atoi(row[1]);
if (class_index < WARRIOR || class_index > BERSERKER)
continue;
--class_index;
uint8 stance_index = atoi(row[2]);
if (stance_index >= MaxStances)
continue;
for (uint8 conditional_index = nHSND; conditional_index < cntHSND; ++conditional_index) {
uint8 value = atoi(row[3 + conditional_index]);
if (!value)
continue;
if (value > 100)
value = 100;
spell_casting_chances[spell_type_index][class_index][stance_index][conditional_index] = value;
}
}
return true;
}
/* Bot functions */
bool BotDatabase::QueryNameAvailablity(const std::string& bot_name, bool& available_flag)
@@ -334,7 +394,13 @@ bool BotDatabase::LoadBot(const uint32 bot_id, Bot*& loaded_bot)
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]));
uint32 bfd = atoi(row[44]);
if (bfd < 1)
bfd = 1;
if (bfd > BOT_FOLLOW_DISTANCE_DEFAULT_MAX)
bfd = BOT_FOLLOW_DISTANCE_DEFAULT_MAX;
loaded_bot->SetFollowDistance(bfd);
}
return true;
@@ -471,7 +537,7 @@ bool BotDatabase::SaveNewBot(Bot* bot_inst, uint32& bot_id)
bot_inst->GetPR(),
bot_inst->GetDR(),
bot_inst->GetCorrup(),
BOT_DEFAULT_FOLLOW_DISTANCE
BOT_FOLLOW_DISTANCE_DEFAULT
);
auto results = QueryDatabase(query);
if (!results.Success())
@@ -617,7 +683,8 @@ bool BotDatabase::LoadBuffs(Bot* bot_inst)
" `caston_x`,"
" `caston_y`,"
" `caston_z`,"
" `extra_di_chance`"
" `extra_di_chance`,"
" `instrument_mod`"
" FROM `bot_buffs`"
" WHERE `bot_id` = '%u'",
bot_inst->GetBotID()
@@ -657,6 +724,7 @@ bool BotDatabase::LoadBuffs(Bot* bot_inst)
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].instrument_mod = atoi(row[17]);
bot_buffs[buff_count].casterid = 0;
++buff_count;
}
@@ -2709,6 +2777,19 @@ bool BotDatabase::DeleteAllHealRotations(const uint32 owner_id)
/* Bot miscellaneous functions */
uint8 BotDatabase::GetSpellCastingChance(uint8 spell_type_index, uint8 class_index, uint8 stance_index, uint8 conditional_index) // class_index is 0-based
{
if (spell_type_index >= MaxSpellTypes)
return 0;
if (class_index >= PLAYER_CLASS_COUNT)
return 0;
if (stance_index >= MaxStances)
return 0;
if (conditional_index >= cntHSND)
return 0;
return spell_casting_chances[spell_type_index][class_index][stance_index][conditional_index];
}
/* fail::Bot functions */
+2
View File
@@ -50,6 +50,7 @@ public:
bool Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port);
bool LoadBotCommandSettings(std::map<std::string, std::pair<uint8, std::vector<std::string>>> &bot_command_settings);
bool LoadBotSpellCastingChances();
/* Bot functions */
@@ -183,6 +184,7 @@ public:
bool DeleteAllHealRotations(const uint32 owner_id);
/* Bot miscellaneous functions */
uint8 GetSpellCastingChance(uint8 spell_type_index, uint8 class_index, uint8 stance_index, uint8 conditional_index);
class fail {
+15
View File
@@ -56,6 +56,21 @@ struct BotSpell {
int16 ManaCost;
};
struct BotSpell_wPriority : public BotSpell {
uint8 Priority;
};
struct BotCastingRoles {
bool GroupHealer;
bool GroupSlower;
bool GroupNuker;
bool GroupDoter;
//bool RaidHealer;
//bool RaidSlower;
//bool RaidNuker;
//bool RaidDoter;
};
struct BotAA {
uint32 aa_id;
uint8 req_level;
+457 -1192
View File
File diff suppressed because it is too large Load Diff
+396 -81
View File
@@ -33,6 +33,7 @@ extern volatile bool RunLoops;
#include "../common/eqemu_logsys.h"
#include "../common/features.h"
#include "../common/emu_legacy.h"
#include "../common/spdat.h"
#include "../common/guilds.h"
#include "../common/rulesys.h"
@@ -153,6 +154,7 @@ Client::Client(EQStreamInterface* ieqs)
afk_toggle_timer(250),
helm_toggle_timer(250),
light_update_timer(600),
aggro_meter_timer(AGGRO_METER_UPDATE_MS),
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),
@@ -309,6 +311,8 @@ Client::Client(EQStreamInterface* ieqs)
}
MaxXTargets = 5;
XTargetAutoAddHaters = true;
m_autohatermgr.SetOwner(this, nullptr, nullptr);
m_activeautohatermgr = &m_autohatermgr;
LoadAccountFlags();
initial_respawn_selection = 0;
@@ -1095,7 +1099,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
CheckLDoNHail(GetTarget());
CheckEmoteHail(GetTarget(), message);
if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= 200) {
if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= RuleI(Range, Say)) {
NPC *tar = GetTarget()->CastToNPC();
parse->EventNPC(EVENT_SAY, tar->CastToNPC(), this, message, language);
@@ -1107,7 +1111,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
}
}
else {
if (DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= 200) {
if (DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= RuleI(Range, Say)) {
parse->EventNPC(EVENT_AGGRO_SAY, GetTarget()->CastToNPC(), this, message, language);
}
}
@@ -1136,7 +1140,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
char *Buffer = (char *)es;
Buffer += 4;
snprintf(Buffer, sizeof(Emote_Struct) - 4, "%s %s", GetName(), message);
entity_list.QueueCloseClients(this, outapp, true, 100, 0, true, FilterSocials);
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, Emote), 0, true, FilterSocials);
safe_delete(outapp);
break;
}
@@ -1998,6 +2002,7 @@ void Client::SetGM(bool toggle) {
}
void Client::ReadBook(BookRequest_Struct *book) {
int16 book_language=0;
char *txtfile = book->txtfile;
if(txtfile[0] == '0' && txtfile[1] == '\0') {
@@ -2005,7 +2010,7 @@ void Client::ReadBook(BookRequest_Struct *book) {
return;
}
std::string booktxt2 = database.GetBook(txtfile);
std::string booktxt2 = database.GetBook(txtfile, &book_language);
int length = booktxt2.length();
if (booktxt2[0] != '\0') {
@@ -2016,21 +2021,47 @@ void Client::ReadBook(BookRequest_Struct *book) {
BookText_Struct *out = (BookText_Struct *) outapp->pBuffer;
out->window = book->window;
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
{
const EQEmu::ItemInstance *inst = m_inv[book->invslot];
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) {
// Find out what slot the book was read from.
// SoF+ need to look up book type for the output message.
int16 read_from_slot;
if (book->subslot >= 0) {
uint16 offset;
offset = (book->invslot-23) * 10; // How many packs to skip.
read_from_slot = 251 + offset + book->subslot;
}
else {
read_from_slot = book->invslot -1;
}
const EQEmu::ItemInstance *inst = 0;
if (read_from_slot <= EQEmu::legacy::SLOT_PERSONAL_BAGS_END)
{
inst = m_inv[read_from_slot];
}
if(inst)
out->type = inst->GetItem()->Book;
else
out->type = book->type;
}
else
{
else {
out->type = book->type;
}
out->invslot = book->invslot;
memcpy(out->booktext, booktxt2.c_str(), length);
if (book_language > 0 && book_language < MAX_PP_LANGUAGE) {
if (m_pp.languages[book_language] < 100) {
GarbleMessage(out->booktext, (100 - m_pp.languages[book_language]));
}
}
QueuePacket(outapp);
safe_delete(outapp);
}
@@ -2311,7 +2342,7 @@ bool Client::CheckIncreaseSkill(EQEmu::skills::SkillType skillid, Mob *against_w
if(against_who)
{
if(against_who->GetSpecialAbility(IMMUNE_AGGRO) || against_who->IsClient() ||
GetLevelCon(against_who->GetLevel()) == CON_GREEN)
GetLevelCon(against_who->GetLevel()) == CON_GRAY)
{
//false by default
if( !mod_can_increase_skill(skillid, against_who) ) { return(false); }
@@ -4131,6 +4162,18 @@ bool Client::GroupFollow(Client* inviter) {
}
if (raid->RaidCount() < MAX_RAID_MEMBERS)
{
// okay, so we now have a single client (this) joining a group in a raid
// And they're not already in the raid (which is above and doesn't need xtarget shit)
if (!GetXTargetAutoMgr()->empty()) {
raid->GetXTargetAutoMgr()->merge(*GetXTargetAutoMgr());
GetXTargetAutoMgr()->clear();
RemoveAutoXTargets();
}
SetXTargetAutoMgr(GetXTargetAutoMgr());
if (!GetXTargetAutoMgr()->empty())
SetDirtyAutoHaters();
if (raid->GroupCount(groupToUse) < 6)
{
raid->SendRaidCreate(this);
@@ -4206,7 +4249,9 @@ bool Client::GroupFollow(Client* inviter) {
inviter->SendGroupLeaderChangePacket(inviter->GetName());
inviter->SendGroupJoinAcknowledge();
}
group->GetXTargetAutoMgr()->merge(*inviter->GetXTargetAutoMgr());
inviter->GetXTargetAutoMgr()->clear();
inviter->SetXTargetAutoMgr(group->GetXTargetAutoMgr());
}
if (!group)
@@ -5868,20 +5913,20 @@ void Client::SendGroupCreatePacket()
char *Buffer = (char *)outapp->pBuffer;
// Header
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // Null Leader name
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // group ID probably
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); // count of members in packet
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // Null Leader name, shouldn't be null besides this case
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // Member 0
VARSTRUCT_ENCODE_STRING(Buffer, GetName());
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // This is a string
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, GetLevel());
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0);
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // Member 0, index
VARSTRUCT_ENCODE_STRING(Buffer, GetName()); // group member name
VARSTRUCT_ENCODE_TYPE(uint16, Buffer, 0); // merc flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // owner name (if merc)
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, GetLevel()); // level
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group tank flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group assist flag
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0); // group puller flag
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // offline flag
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); // timestamp
FastQueuePacket(&outapp);
}
@@ -6863,16 +6908,46 @@ void Client::SendStatsWindow(Client* client, bool use_window)
indP + "Wind: " + itoa(GetWindMod()) + "<br>";
}
EQEmu::skills::SkillType skill = EQEmu::skills::SkillHandtoHand;
auto *inst = GetInv().GetItem(EQEmu::inventory::slotPrimary);
if (inst && inst->IsClassCommon()) {
switch (inst->GetItem()->ItemType) {
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:
if (ClientVersion() < EQEmu::versions::ClientVersion::RoF2)
skill = EQEmu::skills::Skill1HPiercing;
else
skill = EQEmu::skills::Skill2HPiercing;
break;
default:
break;
}
}
std::ostringstream final_string;
final_string <<
/* C/L/R */ indP << "Class: " << class_Name << indS << "Level: " << static_cast<int>(GetLevel()) << indS << "Race: " << race_Name << "<br>" <<
/* Runes */ indP << "Rune: " << rune_number << indL << indS << "Spell Rune: " << magic_rune_number << "<br>" <<
/* HP/M/E */ HME_row <<
/* DS */ indP << "DS: " << (itembonuses.DamageShield + spellbonuses.DamageShield*-1) << " (Spell: " << (spellbonuses.DamageShield*-1) << " + Item: " << itembonuses.DamageShield << " / " << RuleI(Character, ItemDamageShieldCap) << ")<br>" <<
/* Atk */ indP << "<c \"#CCFF00\">ATK: " << GetTotalATK() << "</c><br>" <<
/* Atk2 */ indP << "- Base: " << GetATKRating() << " | Item: " << itembonuses.ATK << " (" << RuleI(Character, ItemATKCap) << ")~Used: " << (itembonuses.ATK * 1.342) << " | Spell: " << spellbonuses.ATK << "<br>" <<
/* AC */ indP << "<c \"#CCFF00\">AC: " << CalcAC() << "</c><br>" <<
/* AC2 */ indP << "- Mit: " << GetACMit() << " | Avoid: " << GetACAvoid() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "<br>" <<
/* Atk */ indP << "<c \"#CCFF00\">tohit: " << compute_tohit(skill) << " / " << GetTotalToHit(skill, 0) << "</c><br>" <<
/* Atk2 */ indP << "- Offense: " << offense(skill) << " | Item: " << itembonuses.ATK << " (" << RuleI(Character, ItemATKCap) << ")~Used: " << (itembonuses.ATK * 1.342) << " | Spell: " << spellbonuses.ATK << "<br>" <<
/* AC */ indP << "<c \"#CCFF00\">mitigation AC: " << GetMitigationAC() << "</c><br>" <<
/* AC2 */ indP << "- defense: " << compute_defense() << " / " << GetTotalDefense() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "<br>" <<
/* Haste */ indP << "<c \"#CCFF00\">Haste: " << GetHaste() << "</c><br>" <<
/* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "<br>" <<
/* RunSpeed*/ indP << "<c \"#CCFF00\">Runspeed: " << GetRunspeed() << "</c><br>" <<
@@ -6910,7 +6985,9 @@ void Client::SendStatsWindow(Client* client, bool use_window)
client->Message(15, "~~~~~ %s %s ~~~~~", GetCleanName(), GetLastName());
client->Message(0, " Level: %i Class: %i Race: %i DS: %i/%i Size: %1.1f Weight: %.1f/%d ", GetLevel(), GetClass(), GetRace(), GetDS(), RuleI(Character, ItemDamageShieldCap), GetSize(), (float)CalcCurrentWeight() / 10.0f, GetSTR());
client->Message(0, " HP: %i/%i HP Regen: %i/%i",GetHP(), GetMaxHP(), CalcHPRegen(), CalcHPRegenCap());
client->Message(0, " AC: %i ( Mit.: %i + Avoid.: %i + Spell: %i ) | Shield AC: %i", CalcAC(), GetACMit(), GetACAvoid(), spellbonuses.AC, shield_ac);
client->Message(0, " compute_tohit: %i TotalToHit: %i", compute_tohit(skill), GetTotalToHit(skill, 0));
client->Message(0, " compute_defense: %i TotalDefense: %i", compute_defense(), GetTotalDefense());
client->Message(0, " offense: %i mitigation ac: %i", offense(skill), GetMitigationAC());
if(CalcMaxMana() > 0)
client->Message(0, " Mana: %i/%i Mana Regen: %i/%i", GetMana(), GetMaxMana(), CalcManaRegen(), CalcManaRegenCap());
client->Message(0, " End.: %i/%i End. Regen: %i/%i",GetEndurance(), GetMaxEndurance(), CalcEnduranceRegen(), CalcEnduranceRegenCap());
@@ -7111,12 +7188,12 @@ void Client::UpdateClientXTarget(Client *c)
}
}
// IT IS NOT SAFE TO CALL THIS IF IT'S NOT INITIAL AGGRO
void Client::AddAutoXTarget(Mob *m, bool send)
{
if(!XTargettingAvailable() || !XTargetAutoAddHaters)
return;
m_activeautohatermgr->increment_count(m);
if(IsXTarget(m))
if (!XTargettingAvailable() || !XTargetAutoAddHaters || IsXTarget(m))
return;
for(int i = 0; i < GetMaxXTargets(); ++i)
@@ -7135,60 +7212,15 @@ void Client::AddAutoXTarget(Mob *m, bool send)
void Client::RemoveXTarget(Mob *m, bool OnlyAutoSlots)
{
if (!XTargettingAvailable())
return;
bool HadFreeAutoSlotsBefore = false;
int FreedAutoSlots = 0;
if (m->GetID() == 0)
return;
m_activeautohatermgr->decrement_count(m);
// now we may need to clean up our CurrentTargetNPC entries
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)
XTargets[i].Type = Auto;
if (XTargets[i].Type == Auto)
++FreedAutoSlots;
if (XTargets[i].Type == CurrentTargetNPC && XTargets[i].ID == m->GetID()) {
XTargets[i].Type = Auto;
XTargets[i].ID = 0;
XTargets[i].dirty = true;
} else {
if (XTargets[i].Type == Auto && XTargets[i].ID == 0)
HadFreeAutoSlotsBefore = true;
}
}
// move shit up! If the removed NPC was in a CurrentTargetNPC slot it becomes Auto
// and we need to potentially fill it
std::queue<int> 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)
@@ -7345,6 +7377,123 @@ void Client::ShowXTargets(Client *c)
for(int i = 0; i < GetMaxXTargets(); ++i)
c->Message(0, "Xtarget Slot: %i, Type: %2i, ID: %4i, Name: %s", i, XTargets[i].Type, XTargets[i].ID, XTargets[i].Name);
auto &list = GetXTargetAutoMgr()->get_list();
// yeah, I kept having to do something for debugging to tell if managers were the same object or not :P
// so lets use the address as an "ID"
c->Message(0, "XTargetAutoMgr ID %p size %d", GetXTargetAutoMgr(), list.size());
int count = 0;
for (auto &e : list) {
c->Message(0, "spawn id %d count %d", e.spawn_id, e.count);
count++;
if (count == 20) { // lets not spam too many ...
c->Message(0, " ... ");
break;
}
}
}
void Client::ProcessXTargetAutoHaters()
{
if (!XTargettingAvailable())
return;
// move shit up! If the removed NPC was in a CurrentTargetNPC slot it becomes Auto
// and we need to potentially fill it
std::queue<int> empty_slots;
for (int i = 0; i < GetMaxXTargets(); ++i) {
if (XTargets[i].Type != Auto)
continue;
if (XTargets[i].ID != 0 && !GetXTargetAutoMgr()->contains_mob(XTargets[i].ID)) {
XTargets[i].ID = 0;
XTargets[i].dirty = true;
}
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);
}
}
// okay, now we need to check if we have any empty slots and if we have aggro
// We make the assumption that if we shuffled the NPCs up that they're still on the aggro
// list in the same order. We could probably do this better and try to calc if
// there are new NPCs for our empty slots on the manager, but ahhh fuck it.
if (!empty_slots.empty() && !GetXTargetAutoMgr()->empty() && XTargetAutoAddHaters) {
auto &haters = GetXTargetAutoMgr()->get_list();
for (auto &e : haters) {
auto *mob = entity_list.GetMob(e.spawn_id);
if (mob && !IsXTarget(mob)) {
auto slot = empty_slots.front();
empty_slots.pop();
XTargets[slot].dirty = true;
XTargets[slot].ID = mob->GetID();
strn0cpy(XTargets[slot].Name, mob->GetCleanName(), 64);
}
if (empty_slots.empty())
break;
}
}
m_dirtyautohaters = false;
SendXTargetUpdates();
}
// This function is called when a client is added to a group
// Group leader joining isn't handled by this function
void Client::JoinGroupXTargets(Group *g)
{
if (!g)
return;
if (!GetXTargetAutoMgr()->empty()) {
g->GetXTargetAutoMgr()->merge(*GetXTargetAutoMgr());
GetXTargetAutoMgr()->clear();
RemoveAutoXTargets();
}
SetXTargetAutoMgr(g->GetXTargetAutoMgr());
if (!GetXTargetAutoMgr()->empty())
SetDirtyAutoHaters();
}
// This function is called when a client leaves a group
void Client::LeaveGroupXTargets(Group *g)
{
if (!g)
return;
SetXTargetAutoMgr(nullptr); // this will set it back to our manager
RemoveAutoXTargets();
entity_list.RefreshAutoXTargets(this); // this will probably break the temporal ordering, but whatever
// We now have a rebuilt, valid auto hater manager, so we need to demerge from the groups
if (!GetXTargetAutoMgr()->empty()) {
GetXTargetAutoMgr()->demerge(*g->GetXTargetAutoMgr()); // this will remove entries where we only had aggro
SetDirtyAutoHaters();
}
}
// This function is called when a client leaves a group
void Client::LeaveRaidXTargets(Raid *r)
{
if (!r)
return;
SetXTargetAutoMgr(nullptr); // this will set it back to our manager
RemoveAutoXTargets();
entity_list.RefreshAutoXTargets(this); // this will probably break the temporal ordering, but whatever
// We now have a rebuilt, valid auto hater manager, so we need to demerge from the groups
if (!GetXTargetAutoMgr()->empty()) {
GetXTargetAutoMgr()->demerge(*r->GetXTargetAutoMgr()); // this will remove entries where we only had aggro
SetDirtyAutoHaters();
}
}
void Client::SetMaxXTargets(uint8 NewMax)
@@ -8623,3 +8772,169 @@ void Client::CheckRegionTypeChanges()
else if (GetPVP())
SetPVP(false, false);
}
void Client::ProcessAggroMeter()
{
if (!AggroMeterAvailable()) {
aggro_meter_timer.Disable();
return;
}
// we need to decide if we need to send OP_AggroMeterTargetInfo now
// This packet sends the current lock target ID and the current target ID
// target ID will be either our target or our target of target when we're targeting a PC
bool send_targetinfo = false;
auto cur_tar = GetTarget();
// probably should have PVP rules ...
if (cur_tar && cur_tar != this) {
if (cur_tar->IsNPC() && !cur_tar->IsPetOwnerClient() && cur_tar->GetID() != m_aggrometer.get_target_id()) {
m_aggrometer.set_target_id(cur_tar->GetID());
send_targetinfo = true;
} else if ((cur_tar->IsPetOwnerClient() || cur_tar->IsClient()) && cur_tar->GetTarget() && cur_tar->GetTarget()->GetID() != m_aggrometer.get_target_id()) {
m_aggrometer.set_target_id(cur_tar->GetTarget()->GetID());
send_targetinfo = true;
}
} else if (m_aggrometer.get_target_id()) {
m_aggrometer.set_target_id(0);
send_targetinfo = true;
}
if (m_aggrometer.update_lock())
send_targetinfo = true;
if (send_targetinfo) {
auto app = new EQApplicationPacket(OP_AggroMeterTargetInfo, sizeof(uint32) * 2);
app->WriteUInt32(m_aggrometer.get_lock_id());
app->WriteUInt32(m_aggrometer.get_target_id());
FastQueuePacket(&app);
}
// we could just calculate how big the packet would need to be ... but it's easier this way :P should be 87 bytes
auto app = new EQApplicationPacket(OP_AggroMeterUpdate, m_aggrometer.max_packet_size());
cur_tar = entity_list.GetMob(m_aggrometer.get_target_id());
// first we must check the secondary
// TODO: lock target should affect secondary as well
bool send = false;
Mob *secondary = nullptr;
bool has_aggro = false;
if (cur_tar) {
if (cur_tar->GetTarget() == this) {// we got aggro
secondary = cur_tar->GetSecondaryHate(this);
has_aggro = true;
} else {
secondary = cur_tar->CheckAggro(cur_tar->GetTarget()) ? cur_tar->GetTarget() : nullptr; // make sure they are targeting for aggro reasons
}
}
if (secondary && secondary->GetID() != m_aggrometer.get_secondary_id()) {
m_aggrometer.set_secondary_id(secondary->GetID());
app->WriteUInt8(1);
app->WriteUInt32(m_aggrometer.get_secondary_id());
send = true;
} else if (!secondary && m_aggrometer.get_secondary_id()) {
m_aggrometer.set_secondary_id(0);
app->WriteUInt8(1);
app->WriteUInt32(0);
send = true;
} else { // might not need to send in this case
app->WriteUInt8(0);
}
auto count_offset = app->GetWritePosition();
app->WriteUInt8(0);
int count = 0;
auto add_entry = [&app, &count, this](AggroMeter::AggroTypes i) {
count++;
app->WriteUInt8(i);
app->WriteUInt16(m_aggrometer.get_pct(i));
};
// TODO: Player entry should either be lock or yourself, ignoring lock for now
// player, secondary, and group depend on your target/lock
if (cur_tar) {
if (m_aggrometer.set_pct(AggroMeter::AT_Player, cur_tar->GetHateRatio(cur_tar->GetTarget(), this)))
add_entry(AggroMeter::AT_Player);
if (m_aggrometer.set_pct(AggroMeter::AT_Secondary, has_aggro ? cur_tar->GetHateRatio(this, secondary) : secondary ? 100 : 0))
add_entry(AggroMeter::AT_Secondary);
// fuuuuuuuuuuuuuuuuuuuuuuuucckkkkkkkkkkkkkkk raids
if (IsRaidGrouped()) {
auto raid = GetRaid();
if (raid) {
auto gid = raid->GetGroup(this);
if (gid < 12) {
int at_id = AggroMeter::AT_Group1;
for (int i = 0; i < MAX_RAID_MEMBERS; ++i) {
if (raid->members[i].member && raid->members[i].member != this && raid->members[i].GroupNumber == gid) {
if (m_aggrometer.set_pct(static_cast<AggroMeter::AggroTypes>(at_id), cur_tar->GetHateRatio(cur_tar->GetTarget(), raid->members[i].member)))
add_entry(static_cast<AggroMeter::AggroTypes>(at_id));
at_id++;
if (at_id > AggroMeter::AT_Group5)
break;
}
}
}
}
} else if (IsGrouped()) {
auto group = GetGroup();
if (group) {
int at_id = AggroMeter::AT_Group1;
for (int i = 0; i < MAX_GROUP_MEMBERS; ++i) {
if (group->members[i] && group->members[i] != this) {
if (m_aggrometer.set_pct(static_cast<AggroMeter::AggroTypes>(at_id), cur_tar->GetHateRatio(cur_tar->GetTarget(), group->members[i])))
add_entry(static_cast<AggroMeter::AggroTypes>(at_id));
at_id++;
}
}
}
}
} else { // we might need to clear out some data now
if (m_aggrometer.set_pct(AggroMeter::AT_Player, 0))
add_entry(AggroMeter::AT_Player);
if (m_aggrometer.set_pct(AggroMeter::AT_Secondary, 0))
add_entry(AggroMeter::AT_Secondary);
if (m_aggrometer.set_pct(AggroMeter::AT_Group1, 0))
add_entry(AggroMeter::AT_Group1);
if (m_aggrometer.set_pct(AggroMeter::AT_Group2, 0))
add_entry(AggroMeter::AT_Group2);
if (m_aggrometer.set_pct(AggroMeter::AT_Group3, 0))
add_entry(AggroMeter::AT_Group3);
if (m_aggrometer.set_pct(AggroMeter::AT_Group4, 0))
add_entry(AggroMeter::AT_Group4);
if (m_aggrometer.set_pct(AggroMeter::AT_Group5, 0))
add_entry(AggroMeter::AT_Group5);
}
// now to go over our xtargets
// if the entry is an NPC it's our hate relative to the NPCs current tank
// if it's a PC, it's their hate relative to our current target
for (int i = 0; i < GetMaxXTargets(); ++i) {
if (XTargets[i].ID) {
auto mob = entity_list.GetMob(XTargets[i].ID);
if (mob) {
int ratio = 0;
if (mob->IsNPC())
ratio = mob->GetHateRatio(mob->GetTarget(), this);
else if (cur_tar)
ratio = cur_tar->GetHateRatio(cur_tar->GetTarget(), mob);
if (m_aggrometer.set_pct(static_cast<AggroMeter::AggroTypes>(AggroMeter::AT_XTarget1 + i), ratio))
add_entry(static_cast<AggroMeter::AggroTypes>(AggroMeter::AT_XTarget1 + i));
}
}
}
if (send || count) {
app->size = app->GetWritePosition(); // this should be safe, although not recommended
// but this way we can have a smaller buffer created for the packet dispatched to the client w/o resizing this one
app->SetWritePosition(count_offset);
app->WriteUInt8(count);
FastQueuePacket(&app);
} else {
safe_delete(app);
}
}
+24 -9
View File
@@ -48,6 +48,8 @@ namespace EQEmu
#include "../common/inventory_profile.h"
#include "../common/guilds.h"
//#include "../common/item_data.h"
#include "xtargetautohaters.h"
#include "aggromanager.h"
#include "common.h"
#include "merc.h"
@@ -221,18 +223,18 @@ public:
//abstract virtual function implementations required by base abstract class
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 void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
ExtraAttackOptions *opts = nullptr, int special = 0);
ExtraAttackOptions *opts = nullptr);
virtual bool HasRaid() { return (GetRaid() ? true : false); }
virtual bool HasGroup() { return (GetGroup() ? true : false); }
virtual Raid* GetRaid() { return entity_list.GetRaidByClient(this); }
virtual Group* GetGroup() { return entity_list.GetGroupByClient(this); }
virtual inline bool IsBerserk() { return berserk; }
virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating);
virtual void SetAttackTimer();
int GetQuiverHaste(int delay);
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
int DoDamageCaps(int base_damage);
void AI_Init();
void AI_Start(uint32 iMoveDelay = 0);
@@ -418,8 +420,6 @@ 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(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;
@@ -1124,9 +1124,21 @@ public:
void RemoveGroupXTargets();
void RemoveAutoXTargets();
void ShowXTargets(Client *c);
inline XTargetAutoHaters *GetXTargetAutoMgr() { return m_activeautohatermgr; } // will be either raid or group or self
inline void SetXTargetAutoMgr(XTargetAutoHaters *in) { if (in) m_activeautohatermgr = in; else m_activeautohatermgr = &m_autohatermgr; }
inline void SetDirtyAutoHaters() { m_dirtyautohaters = true; }
void ProcessXTargetAutoHaters(); // fixes up our auto haters
void JoinGroupXTargets(Group *g);
void LeaveGroupXTargets(Group *g);
void LeaveRaidXTargets(Raid *r);
bool GroupFollow(Client* inviter);
inline bool GetRunMode() const { return runmode; }
inline bool AggroMeterAvailable() const { return ((m_ClientVersionBit & EQEmu::versions::bit_RoF2AndLater)) && RuleB(Character, EnableAggroMeter); } // RoF untested
inline void SetAggroMeterLock(int in) { m_aggrometer.set_lock_id(in); }
void ProcessAggroMeter(); // builds packet and sends
void InitializeMercInfo();
bool CheckCanSpawnMerc(uint32 template_id);
bool CheckCanHireMerc(Mob* merchant, uint32 template_id);
@@ -1292,7 +1304,7 @@ private:
void OPGMEndTraining(const EQApplicationPacket *app);
void OPGMTrainSkill(const EQApplicationPacket *app);
void OPGMSummon(const EQApplicationPacket *app);
void OPCombatAbility(const EQApplicationPacket *app);
void OPCombatAbility(const CombatAbility_Struct *ca_atk);
// Bandolier Methods
void CreateBandolier(const EQApplicationPacket *app);
@@ -1301,9 +1313,6 @@ private:
void HandleTraderPriceUpdate(const EQApplicationPacket *app);
int32 CalcAC();
int32 GetACMit();
int32 GetACAvoid();
int32 CalcATK();
int32 CalcItemATKCap();
int32 CalcHaste();
@@ -1467,6 +1476,7 @@ private:
Timer afk_toggle_timer;
Timer helm_toggle_timer;
Timer light_update_timer;
Timer aggro_meter_timer;
glm::vec3 m_Proximity;
@@ -1551,8 +1561,13 @@ private:
uint8 MaxXTargets;
bool XTargetAutoAddHaters;
bool m_dirtyautohaters;
struct XTarget_Struct XTargets[XTARGET_HARDCAP];
XTargetAutoHaters m_autohatermgr;
XTargetAutoHaters *m_activeautohatermgr;
AggroMeter m_aggrometer;
Timer ItemTickTimer;
Timer ItemQuestTimer;
-105
View File
@@ -1025,111 +1025,6 @@ int32 Client::acmod()
return 0;
};
// This is a testing formula for AC, the value this returns should be the same value as the one the client shows...
// ac1 and ac2 are probably the damage migitation and damage avoidance numbers, not sure which is which.
// I forgot to include the iksar defense bonus and i cant find my notes now...
// AC from spells are not included (cant even cast spells yet..)
int32 Client::CalcAC()
{
// new formula
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(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(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...
}
}
int displayed = 0;
displayed += ((avoidance + mitigation) * 1000) / 847; //natural AC
//Iksar AC, untested
if (GetRace() == IKSAR) {
displayed += 12;
int iksarlevel = GetLevel();
iksarlevel -= 10;
if (iksarlevel > 25) {
iksarlevel = 25;
}
if (iksarlevel > 0) {
displayed += iksarlevel * 12 / 10;
}
}
// Shield AC bonus for HeroicSTR
if (itembonuses.HeroicSTR) {
bool equiped = CastToClient()->m_inv.GetItem(EQEmu::inventory::slotSecondary);
if (equiped) {
uint8 shield = CastToClient()->m_inv.GetItem(EQEmu::inventory::slotSecondary)->GetItem()->ItemType;
if (shield == EQEmu::item::ItemTypeShield) {
displayed += itembonuses.HeroicSTR / 2;
}
}
}
//spell AC bonuses are added directly to natural total
displayed += spellbonuses.AC;
AC = displayed;
return (AC);
}
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(EQEmu::skills::SkillDefense) + itembonuses.HeroicAGI / 10) / 4 + (itembonuses.AC + 1);
mitigation -= 4;
}
else {
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(EQEmu::inventory::slotSecondary);
if (equiped) {
uint8 shield = CastToClient()->m_inv.GetItem(EQEmu::inventory::slotSecondary)->GetItem()->ItemType;
if (shield == EQEmu::item::ItemTypeShield) {
mitigation += itembonuses.HeroicSTR / 2;
}
}
}
return (mitigation * 1000 / 847);
}
int32 Client::GetACAvoid()
{
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);
}
int32 Client::CalcMaxMana()
{
switch (GetCasterClass()) {
+192 -43
View File
@@ -120,6 +120,7 @@ void MapOpcodes()
ConnectedOpcodes[OP_AdventureMerchantSell] = &Client::Handle_OP_AdventureMerchantSell;
ConnectedOpcodes[OP_AdventureRequest] = &Client::Handle_OP_AdventureRequest;
ConnectedOpcodes[OP_AdventureStatsRequest] = &Client::Handle_OP_AdventureStatsRequest;
ConnectedOpcodes[OP_AggroMeterLockTarget] = &Client::Handle_OP_AggroMeterLockTarget;
ConnectedOpcodes[OP_AltCurrencyMerchantRequest] = &Client::Handle_OP_AltCurrencyMerchantRequest;
ConnectedOpcodes[OP_AltCurrencyPurchase] = &Client::Handle_OP_AltCurrencyPurchase;
ConnectedOpcodes[OP_AltCurrencyReclaim] = &Client::Handle_OP_AltCurrencyReclaim;
@@ -575,6 +576,11 @@ void Client::CompleteConnect()
}
}
raid->SendGroupLeadershipAA(this, grpID); // this may get sent an extra time ...
SetXTargetAutoMgr(raid->GetXTargetAutoMgr());
if (!GetXTargetAutoMgr()->empty())
SetDirtyAutoHaters();
if (raid->IsLocked())
raid->SendRaidLockTo(this);
}
@@ -1548,8 +1554,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
// we purchased a new one while out-of-zone.
if (group->IsLeader(this))
group->SendLeadershipAAUpdate();
}
JoinGroupXTargets(group);
group->UpdatePlayer(this);
LFG = false;
}
@@ -2395,6 +2401,17 @@ void Client::Handle_OP_AdventureStatsRequest(const EQApplicationPacket *app)
FastQueuePacket(&outapp);
}
void Client::Handle_OP_AggroMeterLockTarget(const EQApplicationPacket *app)
{
if (app->size < sizeof(uint32)) {
Log.Out(Logs::General, Logs::Error, "Handle_OP_AggroMeterLockTarget had a packet that was too small.");
return;
}
SetAggroMeterLock(app->ReadUInt32(0));
ProcessAggroMeter();
}
void Client::Handle_OP_AltCurrencyMerchantRequest(const EQApplicationPacket *app)
{
VERIFY_PACKET_LENGTH(OP_AltCurrencyMerchantRequest, app, uint32);
@@ -3878,10 +3895,19 @@ void Client::Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app)
Mob *m = nullptr;
if (brrs->EntityID == GetID())
if (brrs->EntityID == GetID()) {
m = this;
else if (brrs->EntityID == GetPetID())
}
else if (brrs->EntityID == GetPetID()) {
m = GetPet();
}
#ifdef BOTS
else {
Mob* bot_test = entity_list.GetMob(brrs->EntityID);
if (bot_test && bot_test->IsBot() && bot_test->GetOwner() == this)
m = bot_test;
}
#endif
if (!m)
return;
@@ -4346,7 +4372,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
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);
entity_list.QueueCloseClients(boat, outapp, true, 300, this, false);
safe_delete(outapp);
// update the boat's position on the server, without sending an update
boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ19toFloat(ppu->heading), false);
@@ -4580,9 +4606,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
PlayerPositionUpdateServer_Struct* ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
MakeSpawnUpdate(ppu);
if (gmhideme)
entity_list.QueueClientsStatus(this,outapp,true,Admin(),250);
entity_list.QueueClientsStatus(this, outapp, true, Admin(), 250);
else
entity_list.QueueCloseClients(this,outapp,true,300,nullptr,false);
entity_list.QueueCloseClients(this, outapp, true, 300, nullptr, false);
safe_delete(outapp);
}
@@ -4622,7 +4648,8 @@ void Client::Handle_OP_CombatAbility(const EQApplicationPacket *app)
std::cout << "Wrong size on OP_CombatAbility. Got: " << app->size << ", Expected: " << sizeof(CombatAbility_Struct) << std::endl;
return;
}
OPCombatAbility(app);
auto ca_atk = (CombatAbility_Struct *)app->pBuffer;
OPCombatAbility(ca_atk);
return;
}
@@ -4701,12 +4728,22 @@ void Client::Handle_OP_Consider(const EQApplicationPacket *app)
else
con->faction = 1;
con->level = GetLevelCon(tmob->GetLevel());
if (ClientVersion() <= EQEmu::versions::ClientVersion::Titanium) {
if (con->level == CON_GRAY) {
con->level = CON_GREEN;
}
if (con->level == CON_WHITE) {
con->level = CON_WHITE_TITANIUM;
}
}
if (zone->IsPVPZone()) {
if (!tmob->IsNPC())
con->pvpcon = tmob->CastToClient()->GetPVP();
}
// Mongrel: If we're feigned show NPC as indifferent
// If we're feigned show NPC as indifferent
if (tmob->IsNPC())
{
if (GetFeigned())
@@ -4752,6 +4789,7 @@ void Client::Handle_OP_Consider(const EQApplicationPacket *app)
case CON_BLUE:
color = 4;
break;
case CON_WHITE_TITANIUM:
case CON_WHITE:
color = 10;
break;
@@ -4761,7 +4799,17 @@ void Client::Handle_OP_Consider(const EQApplicationPacket *app)
case CON_RED:
color = 13;
break;
case CON_GRAY:
color = 6;
break;
}
if (ClientVersion() <= EQEmu::versions::ClientVersion::Titanium) {
if (color == 6) {
color = 2;
}
}
SendColoredText(color, std::string("This creature would take an army to defeat!"));
}
safe_delete(outapp);
@@ -5461,7 +5509,7 @@ void Client::Handle_OP_Emote(const EQApplicationPacket *app)
}
else
*/
entity_list.QueueCloseClients(this, outapp, true, 100, 0, true, FilterSocials);
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, Emote), 0, true, FilterSocials);
safe_delete(outapp);
return;
@@ -6488,12 +6536,43 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
if (!group) //We must recheck this here.. incase the final bot disbanded the party..otherwise we crash
return;
#endif
Mob* memberToDisband = GetTarget();
if (!memberToDisband)
memberToDisband = entity_list.GetMob(gd->name2);
if (memberToDisband) {
auto group2 = memberToDisband->GetGroup();
if (group2 != group) // they're not in our group!
memberToDisband = this;
}
if (group->GroupCount() < 3)
{
group->DisbandGroup();
if (GetMerc())
GetMerc()->Suspend();
if (!RuleB(Mercs, AllowMercSuspendInCombat)) {
if (GetMerc())
{
Mob* mercOwner = GetMerc()->GetOwner();
if (mercOwner && mercOwner->IsClient()) {
if (mercOwner->CastToClient()->CheckCanSpawnMerc(mercOwner->CastToClient()->GetMercInfo().MercTemplateID)) {
group->DisbandGroup();
GetMerc()->Suspend();
}
}
}
else
{
group->DisbandGroup();
if (GetMerc())
GetMerc()->Suspend();
}
}
else
{
group->DisbandGroup();
if (GetMerc())
GetMerc()->Suspend();
}
}
else if (group->IsLeader(this) && GetTarget() == nullptr)
{
@@ -6504,12 +6583,33 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
}
else
{
group->DisbandGroup();
if (GetMerc())
GetMerc()->Suspend();
if (!RuleB(Mercs, AllowMercSuspendInCombat)) {
if (GetMerc())
{
Mob* mercOwner = GetMerc()->GetOwner();
if (mercOwner && mercOwner->IsClient()) {
if (mercOwner->CastToClient()->CheckCanSpawnMerc(mercOwner->CastToClient()->GetMercInfo().MercTemplateID)) {
group->DisbandGroup();
GetMerc()->Suspend();
}
}
}
else
{
group->DisbandGroup();
if (GetMerc())
GetMerc()->Suspend();
}
}
else {
group->DisbandGroup();
if (GetMerc())
GetMerc()->Suspend();
}
}
}
else if (group->IsLeader(this) && GetTarget() == this)
else if (group->IsLeader(this) && (GetTarget() == this || memberToDisband == this))
{
LeaveGroup();
if (GetMerc() && !GetMerc()->IsSuspended())
@@ -6519,19 +6619,12 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
}
else
{
Mob* memberToDisband = nullptr;
memberToDisband = GetTarget();
if (!memberToDisband)
memberToDisband = entity_list.GetMob(gd->name2);
if (memberToDisband)
{
if (group->IsLeader(this))
{
// the group leader can kick other members out of the group...
if (memberToDisband->IsClient())
{
if (memberToDisband->IsClient()) {
group->DelMember(memberToDisband, false);
Client* memberClient = memberToDisband->CastToClient();
Merc* memberMerc = memberToDisband->CastToClient()->GetMerc();
@@ -6540,9 +6633,19 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app)
memberMerc->MercJoinClientGroup();
}
}
else if (memberToDisband->IsMerc())
{
memberToDisband->CastToMerc()->Suspend();
else if (memberToDisband->IsMerc()) {
//Can only remove mercs that aren't in combat if the rule is set.
if (!RuleB(Mercs, AllowMercSuspendInCombat)) {
Mob* mercOwner = memberToDisband->CastToMerc()->GetOwner();
if (mercOwner && mercOwner->IsClient()) {
if (mercOwner->CastToClient()->CheckCanSpawnMerc(mercOwner->CastToClient()->GetMercInfo().MercTemplateID)) {
memberToDisband->CastToMerc()->Suspend();
}
}
}
else {
memberToDisband->CastToMerc()->Suspend();
}
}
}
else
@@ -10805,7 +10908,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
}
}
}
g->DisbandGroup();
g->JoinRaidXTarget(r);
g->DisbandGroup(true);
r->GroupUpdate(freeGroup);
}
else{
@@ -10870,7 +10974,8 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
}
}
}
ig->DisbandGroup();
ig->JoinRaidXTarget(r, true);
ig->DisbandGroup(true);
r->GroupUpdate(groupFree);
groupFree = r->GetFreeGroup();
}
@@ -10923,10 +11028,11 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
}
}
}
g->DisbandGroup();
g->JoinRaidXTarget(r);
g->DisbandGroup(true);
r->GroupUpdate(groupFree);
}
else
else // target does not have a group
{
if (ig){
r = new Raid(i);
@@ -10980,14 +11086,15 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app)
r->SendRaidCreate(this);
r->SendMakeLeaderPacketTo(r->leadername, this);
r->SendBulkRaid(this);
ig->JoinRaidXTarget(r, true);
r->AddMember(this);
ig->DisbandGroup();
ig->DisbandGroup(true);
r->GroupUpdate(0);
if (r->IsLocked()) {
r->SendRaidLockTo(this);
}
}
else{
else{ // neither has a group
r = new Raid(i);
entity_list.AddRaid(r);
r->SetRaidDetails();
@@ -12418,14 +12525,33 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
return;
}
int cost_quantity = mp->quantity;
uint32 cost_quantity = mp->quantity;
if (inst->IsCharged())
int cost_quantity = 1;
uint32 cost_quantity = 1;
uint32 i;
if (RuleB(Merchant, UsePriceMod)) {
for (i = 1; i <= cost_quantity; i++) {
price = (uint32)((item->Price * i)*(RuleR(Merchant, BuyCostMod))*Client::CalcPriceMod(vendor, true) + 0.5); // need to round up, because client does it automatically when displaying price
if (price > 4000000000) {
cost_quantity = i;
mp->quantity = i;
break;
}
}
}
else {
for (i = 1; i <= cost_quantity; i++) {
price = (uint32)((item->Price * i)*(RuleR(Merchant, BuyCostMod)) + 0.5); // need to round up, because client does it automatically when displaying price
if (price > 4000000000) {
cost_quantity = i;
mp->quantity = i;
break;
}
}
}
if (RuleB(Merchant, UsePriceMod))
price = (int)((item->Price*cost_quantity)*(RuleR(Merchant, BuyCostMod))*Client::CalcPriceMod(vendor, true) + 0.5); // need to round up, because client does it automatically when displaying price
else
price = (int)((item->Price*cost_quantity)*(RuleR(Merchant, BuyCostMod)) + 0.5);
AddMoneyToPP(price, false);
if (inst->IsStackable() || inst->IsCharged())
@@ -12513,8 +12639,25 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
// Now remove the item from the player, this happens regardless of outcome
if (!inst->IsStackable())
this->DeleteItemInInventory(mp->itemslot, 0, false);
else
this->DeleteItemInInventory(mp->itemslot, mp->quantity, false);
else {
// HACK: DeleteItemInInventory uses int8 for quantity type. There is no consistent use of types in code in this path so for now iteratively delete from inventory.
if (mp->quantity > 255) {
uint32 temp = mp->quantity;
while (temp > 255 && temp != 0) {
// Delete chunks of 255
this->DeleteItemInInventory(mp->itemslot, 255, false);
temp -= 255;
}
if (temp != 0) {
// Delete remaining
this->DeleteItemInInventory(mp->itemslot, temp, false);
}
}
else {
this->DeleteItemInInventory(mp->itemslot, mp->quantity, false);
}
}
//This forces the price to show up correctly for charged items.
if (inst->IsCharged())
@@ -12997,9 +13140,14 @@ void Client::Handle_OP_TargetCommand(const EQApplicationPacket *app)
}
}
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->IsPet() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()) ||
#ifdef BOTS
(nt->IsBot() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()) || // TODO: bot pets
#endif
(nt->IsMerc() && nt->GetOwner() && nt->GetOwner()->IsClient() && !nt->GetOwner()->CastToClient()->GetPVP()))
{
nt->SendBuffsToClient(this);
}
}
else
{
@@ -14086,6 +14234,7 @@ void Client::Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app)
}
XTargetAutoAddHaters = app->ReadUInt8(0);
SetDirtyAutoHaters();
}
void Client::Handle_OP_XTargetOpen(const EQApplicationPacket *app)
+1
View File
@@ -32,6 +32,7 @@
void Handle_OP_AdventureMerchantSell(const EQApplicationPacket *app);
void Handle_OP_AdventureRequest(const EQApplicationPacket *app);
void Handle_OP_AdventureStatsRequest(const EQApplicationPacket *app);
void Handle_OP_AggroMeterLockTarget(const EQApplicationPacket *app);
void Handle_OP_AltCurrencyMerchantRequest(const EQApplicationPacket *app);
void Handle_OP_AltCurrencyPurchase(const EQApplicationPacket *app);
void Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app);
+7
View File
@@ -681,6 +681,13 @@ bool Client::Process() {
Message(0, "Your enemies have forgotten you!");
}
if (client_state == CLIENT_CONNECTED) {
if (m_dirtyautohaters)
ProcessXTargetAutoHaters();
if (aggro_meter_timer.Check())
ProcessAggroMeter();
}
return ret;
}
+1 -1
View File
@@ -10686,7 +10686,7 @@ void command_logs(Client *c, const Seperator *sep){
/* 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){
if (atoi(sep->arg[4]) > 0){
Log.log_settings[atoi(sep->arg[3])].is_category_enabled = 1;
}
else{
+30 -3
View File
@@ -31,9 +31,18 @@
#define CON_GREEN 2
#define CON_LIGHTBLUE 18
#define CON_BLUE 4
#define CON_WHITE 20
#define CON_WHITE 10
#define CON_WHITE_TITANIUM 20
#define CON_YELLOW 15
#define CON_RED 13
#define CON_GRAY 6
#define DMG_BLOCKED -1
#define DMG_PARRIED -2
#define DMG_RIPOSTED -3
#define DMG_DODGED -4
#define DMG_INVULNERABLE -5
#define DMG_RUNE -6
//Spell specialization parameters, not sure of a better place for them
#define SPECIALIZE_FIZZLE 11 //% fizzle chance reduce at 200 specialized
@@ -464,9 +473,9 @@ struct StatBonuses {
int8 CriticalMend; // chance critical monk mend
int32 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy
uint32 HeadShot[2]; // Headshot AA (Massive dmg vs humaniod w/ archery) 0= ? 1= Dmg
uint8 HSLevel; // Max Level Headshot will be effective at.
uint8 HSLevel[2]; // Max Level Headshot will be effective at. and chance mod
uint32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg
uint8 AssassinateLevel; // Max Level Assassinate will be effective at.
uint8 AssassinateLevel[2]; // 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
@@ -638,5 +647,23 @@ struct ExtraAttackOptions {
};
struct DamageTable {
int32 max_extra; // max extra damage
int32 chance; // chance not to apply?
int32 minusfactor; // difficulty of rolling
};
struct DamageHitInfo {
//uint16 attacker; // id
//uint16 defender; // id
int base_damage;
int min_damage;
int damage_done;
int offense;
int tohit;
int hand;
EQEmu::skills::SkillType skill;
};
#endif
-1
View File
@@ -1087,7 +1087,6 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
}
if (!IsBeingLootedBy(client)) {
client->Message(13, "Error: Corpse::LootItem: BeingLootedBy != client");
client->QueuePacket(app);
SendEndLootErrorPacket(client);
return;
+2 -2
View File
@@ -52,8 +52,8 @@ class Corpse : public Mob {
/* Corpse: General */
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::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = true, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr, int special = 0) { return false; }
virtual void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = true, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) { return false; }
virtual bool HasRaid() { return false; }
virtual bool HasGroup() { return false; }
virtual Raid* GetRaid() { return 0; }
+1 -1
View File
@@ -795,7 +795,7 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
continue;
if (dist_targ < min_range2) //make sure they are in range
continue;
if (isnpc && curmob->IsNPC()) { //check npc->npc casting
if (isnpc && curmob->IsNPC() && spells[spell_id].targettype != ST_AreaNPCOnly) { //check npc->npc casting
FACTION_VALUE f = curmob->GetReverseFactionCon(caster);
if (bad) {
//affect mobs that are on our hate list, or
+2 -2
View File
@@ -35,9 +35,9 @@ public:
//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 void Damage(Mob* from, int32 damage, uint16 spell_id, EQEmu::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
virtual bool Attack(Mob* other, int Hand = EQEmu::inventory::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
ExtraAttackOptions *opts = nullptr, int special = 0) {
ExtraAttackOptions *opts = nullptr) {
return false;
}
virtual bool HasRaid() { return false; }
+22 -12
View File
@@ -408,10 +408,10 @@ void EntityList::RaidProcess()
void EntityList::DoorProcess()
{
#ifdef IDLE_WHEN_EMPTY
if (numclients < 1)
return;
#endif
if (RuleB(Zone, IdleWhenEmpty)) {
if (numclients < 1)
return;
}
if (door_list.empty()) {
net.door_timer.Disable();
return;
@@ -477,7 +477,7 @@ void EntityList::MobProcess()
size_t sz = mob_list.size();
#ifdef IDLE_WHEN_EMPTY
if (RuleB(Zone, IdleWhenEmpty)) {
if (numclients > 0 ||
mob->GetWanderType() == 4 || mob->GetWanderType() == 6) {
// Normal processing, or assuring that spawns that should
@@ -490,9 +490,11 @@ void EntityList::MobProcess()
// At the very least, process that.
mob_dead = mob->CastToNPC()->GetDepop();
}
#else
}
else
{
mob_dead = !mob->Process();
#endif
}
size_t a_sz = mob_list.size();
if(a_sz > sz) {
@@ -1404,15 +1406,15 @@ void EntityList::RemoveFromTargets(Mob *mob, bool RemoveFromXTargets)
if (!m)
continue;
m->RemoveFromHateList(mob);
if (RemoveFromXTargets) {
if (m->IsClient())
if (m->IsClient() && mob->CheckAggro(m))
m->CastToClient()->RemoveXTarget(mob, false);
// FadingMemories calls this function passing the client.
else if (mob->IsClient())
else if (mob->IsClient() && m->CheckAggro(mob))
mob->CastToClient()->RemoveXTarget(m, false);
}
m->RemoveFromHateList(mob);
}
}
@@ -2557,6 +2559,8 @@ void EntityList::RemoveFromHateLists(Mob *mob, bool settoone)
it->second->RemoveFromHateList(mob);
else
it->second->SetHateAmountOnEnt(mob, 1);
if (mob->IsClient())
mob->CastToClient()->RemoveXTarget(it->second, false); // gotta do book keeping
}
++it;
}
@@ -2978,10 +2982,16 @@ void EntityList::Evade(Mob *who)
//removes "targ" from all hate lists, including feigned, in the zone
void EntityList::ClearAggro(Mob* targ)
{
Client *c = nullptr;
if (targ->IsClient())
c = targ->CastToClient();
auto it = npc_list.begin();
while (it != npc_list.end()) {
if (it->second->CheckAggro(targ))
if (it->second->CheckAggro(targ)) {
if (c)
c->RemoveXTarget(it->second, false);
it->second->RemoveFromHateList(targ);
}
it->second->RemoveFromFeignMemory(targ->CastToClient()); //just in case we feigned
++it;
}
+2 -2
View File
@@ -413,7 +413,7 @@ public:
Mob* AICheckCloseAggro(Mob* sender, float iAggroRange, float iAssistRange);
int GetHatedCount(Mob *attacker, Mob *exclude);
void AIYellForHelp(Mob* sender, Mob* attacker);
bool AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint16 iSpellTypes);
bool AICheckCloseBeneficialSpells(NPC* caster, uint8 iChance, float iRange, uint32 iSpellTypes);
bool Merc_AICheckCloseBeneficialSpells(Merc* caster, uint8 iChance, float iRange, uint32 iSpellTypes);
Mob* GetTargetForMez(Mob* caster);
uint32 CheckNPCsClose(Mob *center);
@@ -502,7 +502,7 @@ private:
Bot* GetBotByBotName(std::string botName);
std::list<Bot*> GetBotsByBotOwnerCharacterID(uint32 botOwnerCharacterID);
bool Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint16 iSpellTypes); // TODO: Evaluate this closesly in hopes to eliminate
bool Bot_AICheckCloseBeneficialSpells(Bot* caster, uint8 iChance, float iRange, uint32 iSpellTypes); // TODO: Evaluate this closesly in hopes to eliminate
void ShowSpawnWindow(Client* client, int Distance, bool NamedOnly); // TODO: Implement ShowSpawnWindow in the bot class but it needs entity list stuff
private:
std::list<Bot*> bot_list;
+11 -4
View File
@@ -101,9 +101,12 @@ uint32 Client::CalcEXP(uint8 conlevel) {
if (conlevel != 0xFF) {
switch (conlevel)
{
case CON_GREEN:
case CON_GRAY:
in_add_exp = 0;
return 0;
case CON_GREEN:
in_add_exp = in_add_exp * RuleI(Character, GreenModifier) / 100;
break;
case CON_LIGHTBLUE:
in_add_exp = in_add_exp * RuleI(Character, LightBlueModifier)/100;
break;
@@ -206,10 +209,14 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
if (conlevel != 0xFF && !resexp) {
switch (conlevel)
{
case CON_GREEN:
case CON_GRAY:
add_exp = 0;
add_aaxp = 0;
return;
case CON_GREEN:
add_exp = add_exp * RuleI(Character, GreenModifier) / 100;
add_aaxp = add_aaxp * RuleI(Character, GreenModifier) / 100;
break;
case CON_LIGHTBLUE:
add_exp = add_exp * RuleI(Character, LightBlueModifier)/100;
add_aaxp = add_aaxp * RuleI(Character, LightBlueModifier)/100;
@@ -798,7 +805,7 @@ void Group::SplitExp(uint32 exp, Mob* other) {
groupexp += (uint32)((float)exp * groupmod * (RuleR(Character, GroupExpMultiplier)));
int conlevel = Mob::GetLevelCon(maxlevel, other->GetLevel());
if(conlevel == CON_GREEN)
if(conlevel == CON_GRAY)
return; //no exp for greenies...
if (membercount == 0)
@@ -845,7 +852,7 @@ void Raid::SplitExp(uint32 exp, Mob* other) {
groupexp = (uint32)((float)groupexp * (1.0f-(RuleR(Character, RaidExpMultiplier))));
int conlevel = Mob::GetLevelCon(maxlevel, other->GetLevel());
if(conlevel == CON_GREEN)
if(conlevel == CON_GRAY)
return; //no exp for greenies...
if (membercount == 0)
+4 -1
View File
@@ -72,9 +72,12 @@ void Mob::CheckFlee() {
float run_ratio;
switch(con) {
//these values are not 100% researched
case CON_GREEN:
case CON_GRAY:
run_ratio = fleeratio;
break;
case CON_GREEN:
run_ratio = fleeratio * 9 / 10;
break;
case CON_LIGHTBLUE:
run_ratio = fleeratio * 9 / 10;
break;

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