Compare commits

..

347 Commits

Author SHA1 Message Date
FatBoy-DOTC 9965223d9b revert steward and builder sell inventory 3 months ago
FatBoy-DOTC 08b99d0d3a revert steward and builder sell inventory 3 months ago
FatBoy-DOTC 519a6a2b1e revert steward and builder sell inventory 3 months ago
FatBoy-DOTC 524f5d470b protocol error logging 3 months ago
FatBoy-DOTC 6631c6a5d7 protocol error logging 3 months ago
FatBoy-DOTC 10f95fb0d9 fixed banestone roll times 3 months ago
FatBoy-DOTC a315366026 disconnect after 10 minutes dead 3 months ago
FatBoy-DOTC 1901c9a679 disconnect after 10 minutes dead 3 months ago
FatBoy-DOTC 415ad5402f disconnect after 10 minutes dead 3 months ago
FatBoy-DOTC 9a40e12dbc castable enchants removed when item leaves players immediate posession 3 months ago
FatBoy-DOTC a1af663796 irekei healers get blood prophet 3 months ago
FatBoy-DOTC 78b7ddb32a saetor trains undone 3 months ago
FatBoy-DOTC 5e5ee4fed1 saetor trains 3 months ago
FatBoy-DOTC 84c022a39b saetor trains 3 months ago
FatBoy-DOTC 300741b05a saetor trains 3 months ago
FatBoy-DOTC dc685a01c6 remove roots form wildkins chase 3 months ago
FatBoy-DOTC 752f897a34 juiced up droppers 3 months ago
FatBoy-DOTC 722cb6b1fd Revert "high str NPCs" 3 months ago
FatBoy-DOTC 50c095cd09 high str NPCs 3 months ago
FatBoy-DOTC c23546eb46 10% cost for magical random rolls removed 3 months ago
FatBoy-DOTC 36340c4e52 fixed production bug for mines 3 months ago
FatBoy-DOTC a7ab38f40c can teleport to owned mines 3 months ago
FatBoy-DOTC 0901c03b74 can teleport to owned mines 3 months ago
FatBoy-DOTC 50817352c1 teleport to mines 3 months ago
FatBoy-DOTC ee4a7447bc teleport to mines 3 months ago
FatBoy-DOTC a6d3c827ad teleport to mines 3 months ago
FatBoy-DOTC d4ea31b91f teleport to mines 4 months ago
FatBoy-DOTC 210faaec6d refund gold for cancelled rolled items 4 months ago
FatBoy-DOTC 16be9b9dae refund gold for cancelled rolled items 4 months ago
FatBoy-DOTC 2b8f709182 stun grounds 4 months ago
FatBoy-DOTC aec22d8563 disable keyclone audit 4 months ago
FatBoy-DOTC 1996d042f0 fly speed changes finished 4 months ago
FatBoy-DOTC 27b6665717 fly speed changes 4 months ago
FatBoy-DOTC ce20045611 Merge remote-tracking branch 'origin/lakebane-strongholds' into lakebane-strongholds 4 months ago
FatBoy-DOTC 277f8bfd69 fly speed changes 4 months ago
FatBoy-DOTC 1da2db856f fly speed completed 4 months ago
FatBoy-DOTC 33dfe1389c move buff grounding 4 months ago
FatBoy-DOTC 013b69405a move buff grounding 4 months ago
FatBoy-DOTC ca07a53835 cast while flying 4 months ago
FatBoy-DOTC bbdb6ae1f6 cast while flying 4 months ago
FatBoy-DOTC 4a63222318 cast while flying 4 months ago
FatBoy-DOTC 1a1c552964 cast while flying 4 months ago
FatBoy-DOTC 3587dc2d75 builders sell things at proper ranks 4 months ago
FatBoy-DOTC 96eb9a3ad0 builders sell things at proper ranks 4 months ago
FatBoy-DOTC eaa70f43c0 stewards sell things at proper ranks 4 months ago
FatBoy-DOTC a426b773d3 sage on TOL 4 months ago
FatBoy-DOTC 84841edda9 r8 gets extra hireling slot 4 months ago
FatBoy-DOTC d416dbe47b shade hide 4 months ago
FatBoy-DOTC 7052da7e54 shade hide 4 months ago
FatBoy-DOTC 8f2a2f0ba6 Rogue Druids 4 months ago
FatBoy-DOTC d575ba663d displayed maintenance for r8 tree no longer shows resource required 4 months ago
FatBoy-DOTC 964fe7f335 city serilizing bug 4 months ago
FatBoy-DOTC d3e92d6576 city serilizing bug 4 months ago
FatBoy-DOTC 9dbd6069f1 force respawn after 10 minutes dead 4 months ago
FatBoy-DOTC 7ae25c9a1b can now summon in combat 4 months ago
FatBoy-DOTC 689969a005 r* tree buildings acquire 10% more HP 4 months ago
FatBoy-DOTC b270e1ac8d r8 maintenance flat 3 mil 4 months ago
FatBoy-DOTC 95d38cea44 rogue can promote to druid 4 months ago
FatBoy-DOTC 3ed0765fe5 flying while having move buff fix 4 months ago
FatBoy-DOTC 0c90164c24 shade invis bug 4 months ago
FatBoy-DOTC a45fa39afc random roll magic extra cost removed 4 months ago
FatBoy-DOTC 8959f5e1c5 r7 votary grants PR40 boon 4 months ago
FatBoy-DOTC df338ab00e fix resource vendor pricing 4 months ago
FatBoy-DOTC ac7a2452d6 disable strongholds 4 months ago
FatBoy-DOTC 80104e6d07 fixed login bug 4 months ago
FatBoy-DOTC 8f394cd01d fixed login bug 4 months ago
FatBoy-DOTC e5a32c83c5 Revert "mine production values adjusted" 4 months ago
FatBoy-DOTC 8dce20e69f Revert "adjusted hit chance formula" 4 months ago
FatBoy-DOTC 3428a06bb8 adjusted hit chance formula 4 months ago
FatBoy-DOTC 177f9a1ff6 mine production values adjusted 4 months ago
FatBoy-DOTC 9d93944dd1 mob roll levels 4 months ago
FatBoy-DOTC a4cba1a352 better roll chance for high level vendors 4 months ago
FatBoy-DOTC 17b4232d80 better roll chance for high level vendors 4 months ago
FatBoy-DOTC 2eb58eb719 custom hit chance formula 4 months ago
FatBoy-DOTC db5a4195ad custom hit chance formula 4 months ago
FatBoy-DOTC 3fb29f8e2b custom hit chance formula 4 months ago
FatBoy-DOTC dacdb2cf35 stronghold mobs 4 months ago
FatBoy-DOTC c8473cbe03 stronghold mobs 4 months ago
FatBoy-DOTC e9edf8a7ea increase number of strongholds 4 months ago
FatBoy-DOTC 5a73aa3d90 increase number of strongholds 4 months ago
FatBoy-DOTC 04101c1c3e additional 60 second logout timer for players who have enemies nearby and aren't in safezone 4 months ago
FatBoy-DOTC 0c9343f24d additional 60 second logout timer for players who have enemies nearby and aren't in safezone 4 months ago
FatBoy-DOTC b71710871c track list construction 4 months ago
FatBoy-DOTC f6df6db17b level cap increased to 80 4 months ago
FatBoy-DOTC 3f8b3bc6cb PVP xp enabled 4 months ago
FatBoy-DOTC 383ef27128 can use abilities while flying 4 months ago
FatBoy-DOTC d8189768ae mine production cut in half 4 months ago
FatBoy-DOTC a5eb2fce75 mine management to show correct production amount 4 months ago
FatBoy-DOTC 1fe242a284 strip temporary item enchants when transfered 4 months ago
FatBoy-DOTC a4b83ca9a0 increase resists of the droppers 4 months ago
FatBoy-DOTC 2365b26c1c trainer buildinsg capped at r1 with 3 slots 4 months ago
FatBoy-DOTC 8fb044f71b trainer buildinsg capped at r1 with 3 slots 4 months ago
FatBoy-DOTC 5ce42475c4 force respawn after 10 minutes of unreleased corpse 4 months ago
FatBoy-DOTC 57b9d31fff dropper resists 4 months ago
FatBoy-DOTC 7671586cb0 terraform issue 4 months ago
FatBoy-DOTC a1997e31a8 terraform issue 4 months ago
FatBoy-DOTC f5478e9f64 terraform issue 4 months ago
FatBoy-DOTC 06abea3576 terraform issue 4 months ago
FatBoy-DOTC ae6b584a5f DS immunity fixed 4 months ago
FatBoy-DOTC 9e27c69906 trainer buildings get 3 slots at r1 4 months ago
FatBoy-DOTC 00afe27900 stealing from mobs works again 4 months ago
FatBoy-DOTC 4e5c1a32d3 stronghold mob equipsets 4 months ago
FatBoy-DOTC d4f5043a25 toughness sync issue 4 months ago
FatBoy-DOTC 03a5a55974 remove NPC slot error spam onboot 4 months ago
FatBoy-DOTC dbab4c1212 baked in stats null check 4 months ago
FatBoy-DOTC d186a96796 non vorg droppers cannot drop vorg items 4 months ago
FatBoy-DOTC 6880d014c3 elan vendor price increased to 1,000,000 4 months ago
FatBoy-DOTC 6542dec358 saetors can take disc runes 4 months ago
FatBoy-DOTC 1a2738c3a9 saetors can take disc runes 4 months ago
FatBoy-DOTC 12118ff125 fixed saetor promotions 4 months ago
FatBoy-DOTC c3a00186ff saetors allowed to take creation runes 4 months ago
FatBoy-DOTC fafa777e98 saetor creation fixed 4 months ago
FatBoy-DOTC d4da99f61c NPC sell% in safezone = 0 4 months ago
FatBoy-DOTC bb293c0c02 BH eyes get double value for points in skill (20 points = PR40) 4 months ago
FatBoy-DOTC 1e29971b3c safe NPC profits 4 months ago
FatBoy-DOTC 25d70cca4f error message for flying with movement buff 4 months ago
FatBoy-DOTC 362832a196 NPC safezone sell% = 0 4 months ago
FatBoy-DOTC ed150a5ccd gimme command bumps level to 75 4 months ago
FatBoy-DOTC d2247b66f1 safezone NPCs have 0% profit 4 months ago
FatBoy-DOTC 3b58ea716c custom range for booty sim command 4 months ago
FatBoy-DOTC 368e548e46 special case rolls for contracts, glass, resources and runes 4 months ago
FatBoy-DOTC 6f3612d196 Elf Blood Runes Free 4 months ago
FatBoy-DOTC 0f38146fcc extra stats on printstats 4 months ago
FatBoy-DOTC 1a13f3f096 hit roll formula fixed 4 months ago
FatBoy-DOTC 9cc102ca2a scrolls removed from form breaking 4 months ago
FatBoy-DOTC 50ff4b89bf granted concnc pot fixed 4 months ago
FatBoy-DOTC 9b898825ab no move buff while flying 4 months ago
FatBoy-DOTC 5be9033c40 no move buff while flying 4 months ago
FatBoy-DOTC 67e55ab0a0 no move buff while flying 4 months ago
FatBoy-DOTC 227549bf22 no move buff while flying 4 months ago
FatBoy-DOTC 19707d10a3 no move buff while flying 4 months ago
FatBoy-DOTC 91565ced89 no move buff while flying 4 months ago
FatBoy-DOTC 2383b00c8c mobs recall when out of range of their bind loc 4 months ago
FatBoy-DOTC 405063f036 guilds MOTD now persist 4 months ago
FatBoy-DOTC d2f3c6a879 potions and scrolls no longer count as casting a spell 4 months ago
FatBoy-DOTC 4f759c1bd2 shade sneak 4 months ago
FatBoy-DOTC 9d7f9ce7b3 no movement buffs while flying, cannot fly if you have a movement buff applied 4 months ago
FatBoy-DOTC 56f3dfce92 no movement buffs while flying, cannot fly if you have a movement buff applied 4 months ago
FatBoy-DOTC 9a66f18edb extra 60 seconds added to summon if enemies near and not in safezone 4 months ago
FatBoy-DOTC d7270ffb84 group teleport restricted to active banes and active mines 4 months ago
FatBoy-DOTC dd834a3104 cant delete buildings when baned 4 months ago
FatBoy-DOTC e28ed1b882 fortitude handled after resists 4 months ago
FatBoy-DOTC 2370123c72 hit roll formula added 4 months ago
FatBoy-DOTC 8a5133f04b character starts with 1000 gold and a conc pot 4 months ago
FatBoy-DOTC a0f874b319 cannot tax cities in realm 4 months ago
FatBoy-DOTC 415d11ae33 Vorg droppers increased level and resists 4 months ago
FatBoy-DOTC f93b1ce30e teleport to runegate power action fix for closest gate 4 months ago
FatBoy-DOTC 9fb2e4ff1b apply rune message work 4 months ago
FatBoy-DOTC 601d0f4324 special case drop rate for contracts runes and resources completed 4 months ago
FatBoy-DOTC cbf7db3347 mine production issue resolved 4 months ago
FatBoy-DOTC 217be1d234 Special Case rune contract and resource drops 4 months ago
FatBoy-DOTC 7fabd6554d glass chance is 10/100,000 4 months ago
FatBoy-DOTC d673819796 gimme command 4 months ago
FatBoy-DOTC a963a331a2 mobs that spawn with no loot respawn again 4 months ago
FatBoy-DOTC eda5b8995f stronghold mobs power sets 4 months ago
FatBoy-DOTC d5e95eedf3 stronghold loot adjustment 4 months ago
FatBoy-DOTC 032e703704 gimme command for testing 4 months ago
FatBoy-DOTC ad1444f5ba level 70+ is allowed to apply a fifth disc rune 4 months ago
FatBoy-DOTC a4b30b8620 level cap increased to 80 4 months ago
FatBoy-DOTC 9c002c7bff updated stronghold mobs 5 months ago
FatBoy-DOTC 90495a27d9 blood rune dropper issue resolved 5 months ago
FatBoy-DOTC 1246fa699a blood rune boot issue 5 months ago
FatBoy-DOTC 511d37f5e0 blood rune droppers moved to DB with client patch 5 months ago
FatBoy-DOTC 7a03a0eaa9 noob conc pots 5 months ago
FatBoy-DOTC 2f57cb613e noob conc pots 5 months ago
FatBoy-DOTC e386c3078a noob conc pots 5 months ago
FatBoy-DOTC 3802889834 allow applying blood runes 5 months ago
FatBoy-DOTC f825b2baba negate stronghold mobs from dropping equipment 5 months ago
FatBoy-DOTC 6c92abd083 present drops restricted to strongholds 5 months ago
FatBoy-DOTC c652379a5f mob region lookup 5 months ago
FatBoy-DOTC 61d34ab4ad hotfixes 5 months ago
FatBoy-DOTC d511641410 hotfixes 5 months ago
FatBoy-DOTC c8430625bf mob resists fix 6 months ago
FatBoy-DOTC a418224bbb start random roll at 0 to avoid illegal argument 6 months ago
FatBoy-DOTC 9e3c13dea3 generic resists added for mobs to stop crashing AI 6 months ago
FatBoy-DOTC 335850f7ff stronghold epics target playe rnot self 6 months ago
FatBoy-DOTC f6baf8fe83 resistance modifiers for mobs 6 months ago
FatBoy-DOTC 4c9b82b649 def and ATR cuts for stronghold mobs 6 months ago
FatBoy-DOTC f2570992e5 completed custom strongholds 6 months ago
FatBoy-DOTC 6911d6314d epic encounter naming convention 6 months ago
FatBoy-DOTC eaeea9730c epic encounter naming convention 6 months ago
FatBoy-DOTC fb0790a733 epic encounter after clearing a stronghold 6 months ago
FatBoy-DOTC 3230cd53e1 epic encounter after clearing a stronghold 6 months ago
FatBoy-DOTC edbce067b8 epic encounter after clearing a stronghold 6 months ago
FatBoy-DOTC 83877e5107 epic encounter after clearing a stronghold 6 months ago
FatBoy-DOTC 3a67540212 stronghold attack messages 6 months ago
FatBoy-DOTC 1a5db96023 stronghold mobs spawn 2x mines cap size 6 months ago
FatBoy-DOTC ef82f9ab5b stronghold mobs no longer lose bonuses from weapon powers 6 months ago
FatBoy-DOTC bf7e5c6333 stronghold guardian fix 6 months ago
FatBoy-DOTC 443f0f5450 stronghold guardian fix 6 months ago
FatBoy-DOTC cb1dccd630 stronghold guardian fix 6 months ago
FatBoy-DOTC 2e558acbee stronghold guardian fix 6 months ago
FatBoy-DOTC 74162ea54c stronghold guardian fix 6 months ago
FatBoy-DOTC ccbe4fba04 stronghold guardian fix 6 months ago
FatBoy-DOTC 5aeddb6166 stronghold guardian fix 6 months ago
FatBoy-DOTC 49df5203ae stronghold guardian fix 6 months ago
FatBoy-DOTC 0cfe801d18 stronghold guardian fix 6 months ago
FatBoy-DOTC 89c01e8244 random item generation fix 6 months ago
FatBoy-DOTC 6605e4dd61 update regions when changing mesh 6 months ago
FatBoy-DOTC d6239de6fd delete stronghold mobs form DB when finished 6 months ago
FatBoy-DOTC 99ad6f3712 delete stronghold mobs form DB when finished 6 months ago
FatBoy-DOTC f3041e7549 SetLoc for stronghold mobs 6 months ago
FatBoy-DOTC 1269031be3 SetLoc for stronghold mobs 6 months ago
FatBoy-DOTC ce96274f28 SetLoc for stronghold mobs 6 months ago
FatBoy-DOTC a9a9bd0a3d Stronghold variations 6 months ago
FatBoy-DOTC 33789adadc final strongholds update 6 months ago
FatBoy-DOTC 15b50a75c4 commander stats update 6 months ago
FatBoy-DOTC ead34dbb1f commander powers 6 months ago
FatBoy-DOTC a9b1356efa new stronghold mesh 6 months ago
FatBoy-DOTC 33e105bc7b naming convention 6 months ago
FatBoy-DOTC e5041147f4 added disc and rune to commander drops 6 months ago
FatBoy-DOTC 576e627ad1 fixed loot generation array size bug 6 months ago
FatBoy-DOTC 4059664354 stronghold loot 6 months ago
FatBoy-DOTC 974c0ca7e8 force load changes meshes 6 months ago
FatBoy-DOTC 8e7a7b8b6d stronghold scale set 6 months ago
FatBoy-DOTC 1e3b1db905 commander location set 6 months ago
FatBoy-DOTC 51c98746c4 make stronghold mobs aggro 6 months ago
FatBoy-DOTC 4c21439847 serialize the stronghold mine 6 months ago
FatBoy-DOTC 31385ee533 SCALING DOWN THE STRONGHOLD BUILDING 6 months ago
FatBoy-DOTC bd4e34e0e1 SCALING DOWN THE STRONGHOLD BUILDING 6 months ago
FatBoy-DOTC 9f591b166b Initial Stronghold Push 6 months ago
FatBoy-DOTC 7e457fa17b all items form "Noob Helper" cost 2 gold 6 months ago
FatBoy-DOTC 926b9d2bae R8 ToL can have 4 shrines 6 months ago
FatBoy-DOTC c5822b5acf dropper resists and level increase 6 months ago
FatBoy-DOTC 516b66a50a reintroduce blood rune droppers on 3 hour disc cycle 6 months ago
FatBoy-DOTC 39305d63c7 noob island gear 6 months ago
FatBoy-DOTC c0cb856961 noob island gear 6 months ago
FatBoy-DOTC 2fb97a676f allow some dev commands for players (print) 6 months ago
FatBoy-DOTC cbff151dc3 allow some dev commands for players (print) 6 months ago
FatBoy-DOTC eed75fd2fd repair costs calculated properly 6 months ago
FatBoy-DOTC 6374390b34 repair cost synced with server values 6 months ago
FatBoy-DOTC 2185d3ef7c rune merchants pricing adjusts 6 months ago
FatBoy-DOTC 4aaa96e36c resourc emerchant pricing adjust 6 months ago
FatBoy-DOTC bf86680547 higher present drop chance 6 months ago
FatBoy-DOTC 960307e262 rune pricing fix 6 months ago
FatBoy-DOTC eedf96cc31 resource pricing fix 6 months ago
FatBoy-DOTC 6fb5fce4d3 fixed profit error for NPCs 6 months ago
FatBoy-DOTC 7688d21fe6 boons refreshable, boon level determined by votary rank, shrines should work for all, boons nation friendly again 6 months ago
FatBoy-DOTC 23e60b36b4 General Cleanup and drop rates 6 months ago
FatBoy-DOTC ab8fc8e0a0 random vorg droppers, max durability repairable 6 months ago
FatBoy-DOTC b30f04046d uniform disc dropper times 6 months ago
FatBoy-DOTC 9bd03c7d43 pricing corrected for rune vendors 6 months ago
FatBoy-DOTC 78118a1ac1 fix for rune application 6 months ago
FatBoy-DOTC 1f863d0cce resource pricing fix 6 months ago
FatBoy-DOTC c49204aeeb NPC have 0 maint, fix for resource merchant 6 months ago
FatBoy-DOTC b1de3755fd display correct maintenance costs 6 months ago
FatBoy-DOTC 83a1cc5aba maintenance display on buildings 6 months ago
FatBoy-DOTC 9b0b15c31e remove refund for deranked building due to maintenance 6 months ago
FatBoy-DOTC 802651d2d4 rune application error fixed 6 months ago
FatBoy-DOTC 52a48e5618 rune application checks 6 months ago
FatBoy-DOTC 14fe248e19 mine serializing 6 months ago
FatBoy-DOTC 5b81be371e mine serializing 6 months ago
FatBoy-DOTC 82d67f2850 mine serializing 6 months ago
FatBoy-DOTC 1c342bd566 server pop on creation displays amount of realms captured 6 months ago
FatBoy-DOTC bb8ad3c971 character creation population message 6 months ago
FatBoy-DOTC e9fef85b72 set maintenance dates correctly 6 months ago
FatBoy-DOTC c0d1a4f274 mines produce once a day, maintenance system for TOL only 6 months ago
FatBoy-DOTC 94be3335a0 mine production change error tracking 6 months ago
FatBoy-DOTC 7d03f78546 rune application require/restrict actually use values 6 months ago
FatBoy-DOTC 023f933d0b rune application require/restrict actually use values 6 months ago
FatBoy-DOTC 9995cc01b7 rune application require/restrict actually use values 6 months ago
FatBoy-DOTC fd03b263d1 pets follow owners through teleporting 6 months ago
FatBoy-DOTC 6a09a3fd44 pets follow owners through teleporting 6 months ago
FatBoy-DOTC 1322f8610c safe guards dont kill pets anymore 6 months ago
FatBoy-DOTC 90ab6175b5 extra ToL slots 6 months ago
FatBoy-DOTC 2e3e9ee882 extra ToL slots 6 months ago
FatBoy-DOTC 5158329785 Saetor can take Chaos Shrine boon 6 months ago
FatBoy-DOTC b8e0165da2 allowed siege engineer alchemist and banker on ToL 6 months ago
FatBoy-DOTC 0fa6ebc136 fix pets 6 months ago
FatBoy-DOTC 4e5e362197 attempt to fix mine serialization 6 months ago
FatBoy-DOTC 61514fef2b attempt to fix mine serialization 6 months ago
FatBoy-DOTC 59e593ab0d attempt to fix mine serialization 6 months ago
FatBoy-DOTC 2c6ea98ef9 revert instant respawns 6 months ago
FatBoy-DOTC bd3ea16b57 faster respawns 6 months ago
FatBoy-DOTC 45165332f6 faster respawns 6 months ago
FatBoy-DOTC d764a66e55 logging 6 months ago
FatBoy-DOTC ac41e64429 logging 6 months ago
FatBoy-DOTC 462beb30b3 logging 6 months ago
FatBoy-DOTC 3a89e9c087 logging 6 months ago
FatBoy-DOTC e71863cbd2 logging 6 months ago
FatBoy-DOTC 5ec0ff0598 logging 6 months ago
FatBoy-DOTC 2ca9b77cfb logging 6 months ago
FatBoy-DOTC 4f535ef5fe loot manager for glass runes and contracts 6 months ago
FatBoy-DOTC a46ad71bb0 loot manager for glass runes and contracts 6 months ago
FatBoy-DOTC 90d6911d41 loot manager for glass runes and contracts 6 months ago
FatBoy-DOTC e13ebae0df loot manager for glass runes and contracts 6 months ago
FatBoy-DOTC 3e15fc8206 bootysim command work 6 months ago
FatBoy-DOTC 6a400467dd drop rate work 6 months ago
FatBoy-DOTC 488188e9c3 glass chance work 6 months ago
FatBoy-DOTC 0d31bc4280 contract and rune drop work 6 months ago
FatBoy-DOTC 6375b4431c box check 6 months ago
FatBoy-DOTC 683422f8a4 auto identify all items 6 months ago
FatBoy-DOTC e4dbad2669 generic loot system in place 6 months ago
FatBoy-DOTC 34721fdee8 generic loot system in place 6 months ago
FatBoy-DOTC f27668552c corrected pricing for +10 runes 6 months ago
FatBoy-DOTC 306fdf4235 permanent open runegates 6 months ago
FatBoy-DOTC 553b09d827 rune pricing corrected 6 months ago
FatBoy-DOTC 8ee17f0c64 fix resource merchant elan stones pricing 6 months ago
FatBoy-DOTC 7e5ad644d3 fix resource merchant elan stones 6 months ago
FatBoy-DOTC 846b8a7cde fix resource merchant margins 6 months ago
FatBoy-DOTC f27a4f174b error popup when trying to flag unboxed too frequently 6 months ago
FatBoy-DOTC c6d4375aa8 error popup when trying to flag unboxed too frequently 6 months ago
FatBoy-DOTC b9ec54c76a enrollment office removes DS effect 6 months ago
FatBoy-DOTC b351d7c1ae enrollment officer system 6 months ago
FatBoy-DOTC 729ebe7cd0 box checker 6 months ago
FatBoy-DOTC f51c28e708 revert boxing enforcement 6 months ago
FatBoy-DOTC 9fbf55127d sourcetype lookup fix 6 months ago
FatBoy-DOTC f9fd61dc6b revert sourcetype lookup fix 6 months ago
FatBoy-DOTC 4f198e1f53 Merge remote-tracking branch 'origin/lakebane-new' into lakebane-new 6 months ago
FatBoy-DOTC 24c85a5140 revert sourcetype lookup fix 6 months ago
FatBoy-DOTC 3e1a5f4ccd SpurceType lookup fixes for Piercing Crushing and Slashing 6 months ago
FatBoy-DOTC 34e5a3878c SpurceType lookup fixes for Piercing Crushing and Slashing 6 months ago
FatBoy-DOTC 663e285091 Deathshroud applied ot all boxed characters 6 months ago
FatBoy-DOTC d87c03bb79 fixed combat message to reflect proper zerg multiplier values 6 months ago
FatBoy-DOTC abc57688d3 reset zerg multipliers when window closes 6 months ago
FatBoy-DOTC 29671d56fc display zerg multiplier in ./info 6 months ago
FatBoy-DOTC e8cf6a722b remove hotzone form the game 6 months ago
FatBoy-DOTC 2793ec331b mines revert to claimable at 1am CST 6 months ago
FatBoy-DOTC 1a0b91b068 buying larger stacks of resources form resource vendor 7 months ago
FatBoy-DOTC bec6cbe6e6 implement stat modifications for the ZergMultiplier 7 months ago
FatBoy-DOTC f7ab10ff07 altered mine production values 7 months ago
FatBoy-DOTC 9671cbdc1a unlimited sub guilds 7 months ago
FatBoy-DOTC e0af1f5932 no caps on claimable mines for nations 7 months ago
FatBoy-DOTC 8cb52c6142 zerg multiplier resets for players after mine closes 7 months ago
FatBoy-DOTC e5133211a9 Zerg Mechanic for Mines 7 months ago
FatBoy-DOTC 8548612a80 items auto ID 7 months ago
FatBoy-DOTC 41c3193275 irekei movespeed fix 7 months ago
FatBoy-DOTC 15771d2802 new characters start at level 10 7 months ago
FatBoy-DOTC b4a62e5f3e update inventory when junking for gold 7 months ago
FatBoy-DOTC fc7e6735a1 mine tower health scales with cap size 7 months ago
FatBoy-DOTC aeb21c328e max slots for rank adjustments 7 months ago
FatBoy-DOTC 9a34b13c2e junk from inventory 7 months ago
FatBoy-DOTC 231feef7fe mines open during a reboot time frame now open correctly 7 months ago
FatBoy-DOTC 0e6b68139f refactor mine processing to HalfHourlyJob 7 months ago
FatBoy-DOTC ef62c2bb39 mines open and close 7 months ago
FatBoy-DOTC 8f68997f3c terraform size correction 7 months ago
FatBoy-DOTC aebe2698c3 terraform size correction 7 months ago
FatBoy-DOTC 54e7a8fc7f display mine times correctly 7 months ago
FatBoy-DOTC 8b4d37c53c fix for mines loading 7 months ago
FatBoy-DOTC fbfca46d2f fix for mines loading 7 months ago
FatBoy-DOTC 3228f473de fix for mines loading 7 months ago
FatBoy-DOTC 17fcf0ee40 duplicated zone loading disabled 7 months ago
FatBoy-DOTC 395fe31e02 duplicated zone loading disabled 7 months ago
FatBoy-DOTC e98f9cf1f7 duplicated zone loading disabled 7 months ago
FatBoy-DOTC fe0c0f97a5 duplicated zone loading disabled 7 months ago
FatBoy-DOTC 7e27838818 mine changes 7 months ago
FatBoy-DOTC bc8094c20c saetor race as minotaurs 7 months ago
  1. 26
      src/engine/Enum.java
  2. 7
      src/engine/InterestManagement/InterestManager.java
  3. 14
      src/engine/db/handlers/dbCityHandler.java
  4. 10
      src/engine/db/handlers/dbHandlerBase.java
  5. 14
      src/engine/db/handlers/dbItemHandler.java
  6. 47
      src/engine/devcmd/cmds/AddNPCCmd.java
  7. 63
      src/engine/devcmd/cmds/GimmeCmd.java
  8. 77
      src/engine/devcmd/cmds/HotzoneCmd.java
  9. 3
      src/engine/devcmd/cmds/InfoCmd.java
  10. 5
      src/engine/devcmd/cmds/MineActiveCmd.java
  11. 5
      src/engine/devcmd/cmds/PrintStatsCmd.java
  12. 4
      src/engine/devcmd/cmds/SetLevelCmd.java
  13. 14
      src/engine/devcmd/cmds/SimulateBootyCmd.java
  14. 25
      src/engine/gameManager/BuildingManager.java
  15. 38
      src/engine/gameManager/CombatManager.java
  16. 17
      src/engine/gameManager/DevCmdManager.java
  17. 549
      src/engine/gameManager/LootManager.java
  18. 115
      src/engine/gameManager/MaintenanceManager.java
  19. 4
      src/engine/gameManager/NPCManager.java
  20. 181
      src/engine/gameManager/PowersManager.java
  21. 17
      src/engine/gameManager/SimulationManager.java
  22. 347
      src/engine/gameManager/StrongholdManager.java
  23. 92
      src/engine/gameManager/ZergManager.java
  24. 73
      src/engine/gameManager/ZoneManager.java
  25. 10
      src/engine/jobs/FinishSummonsJob.java
  26. 18
      src/engine/loot/ItemTableEntry.java
  27. 4
      src/engine/loot/ModTableEntry.java
  28. 62
      src/engine/mobileAI/MobAI.java
  29. 25
      src/engine/mobileAI/utilities/CombatUtilities.java
  30. 8
      src/engine/net/NetMsgFactory.java
  31. 203
      src/engine/net/client/ClientMessagePump.java
  32. 15
      src/engine/net/client/handlers/ArcMineChangeProductionMsgHandler.java
  33. 2
      src/engine/net/client/handlers/CityDataHandler.java
  34. 2
      src/engine/net/client/handlers/DestroyBuildingHandler.java
  35. 2
      src/engine/net/client/handlers/GroupInviteResponseHandler.java
  36. 5
      src/engine/net/client/handlers/ItemProductionMsgHandler.java
  37. 13
      src/engine/net/client/handlers/MOTDEditHandler.java
  38. 83
      src/engine/net/client/handlers/MerchantMsgHandler.java
  39. 29
      src/engine/net/client/handlers/ObjectActionMsgHandler.java
  40. 3
      src/engine/net/client/handlers/TaxCityMsgHandler.java
  41. 164
      src/engine/net/client/msg/ApplyRuneMsg.java
  42. 6
      src/engine/net/client/msg/BuyFromNPCWindowMsg.java
  43. 8
      src/engine/net/client/msg/CityDataMsg.java
  44. 23
      src/engine/net/client/msg/ManageCityAssetsMsg.java
  45. 40
      src/engine/net/client/msg/ServerInfoMsg.java
  46. 22
      src/engine/net/client/msg/TeleportRepledgeListMsg.java
  47. 43
      src/engine/net/client/msg/VendorDialogMsg.java
  48. 49
      src/engine/objects/AbstractCharacter.java
  49. 94
      src/engine/objects/Blueprint.java
  50. 41
      src/engine/objects/Building.java
  51. 5
      src/engine/objects/CharacterItemManager.java
  52. 13
      src/engine/objects/CharacterSkill.java
  53. 5
      src/engine/objects/City.java
  54. 95
      src/engine/objects/Contract.java
  55. 39
      src/engine/objects/Experience.java
  56. 10
      src/engine/objects/Guild.java
  57. 45
      src/engine/objects/Item.java
  58. 149
      src/engine/objects/ItemBase.java
  59. 53
      src/engine/objects/ItemFactory.java
  60. 385
      src/engine/objects/Mine.java
  61. 45
      src/engine/objects/MineProduction.java
  62. 195
      src/engine/objects/Mob.java
  63. 4
      src/engine/objects/MobEquipment.java
  64. 2
      src/engine/objects/MobLoot.java
  65. 116
      src/engine/objects/NPC.java
  66. 130
      src/engine/objects/PlayerCharacter.java
  67. 1
      src/engine/objects/PromotionClass.java
  68. 108
      src/engine/objects/Resists.java
  69. 27
      src/engine/objects/Shrine.java
  70. 78
      src/engine/objects/Warehouse.java
  71. 5
      src/engine/objects/Zone.java
  72. 9
      src/engine/powers/poweractions/RunegateTeleportPowerAction.java
  73. 19
      src/engine/powers/poweractions/StealPowerAction.java
  74. 2
      src/engine/server/MBServerStatics.java
  75. 4
      src/engine/server/login/LoginServer.java
  76. 46
      src/engine/server/world/WorldServer.java
  77. 174
      src/engine/workthreads/HalfHourlyJobThread.java
  78. 257
      src/engine/workthreads/HourlyJobThread.java

26
src/engine/Enum.java

@ -139,8 +139,8 @@ public class Enum {
HALFGIANTMALE(2010, MonsterType.HalfGiant, RunSpeed.STANDARD, CharacterSex.MALE, 1.15f), HALFGIANTMALE(2010, MonsterType.HalfGiant, RunSpeed.STANDARD, CharacterSex.MALE, 1.15f),
HUMANMALE(2011, MonsterType.Human, RunSpeed.STANDARD, CharacterSex.MALE, 1), HUMANMALE(2011, MonsterType.Human, RunSpeed.STANDARD, CharacterSex.MALE, 1),
HUMANFEMALE(2012, MonsterType.Human, RunSpeed.STANDARD, CharacterSex.FEMALE, 1), HUMANFEMALE(2012, MonsterType.Human, RunSpeed.STANDARD, CharacterSex.FEMALE, 1),
IREKEIMALE(2013, MonsterType.Irekei, RunSpeed.STANDARD, CharacterSex.MALE, 1.1f), IREKEIMALE(2013, MonsterType.Irekei, RunSpeed.IREKEI, CharacterSex.MALE, 1.1f),
IREKEIFEMALE(2014, MonsterType.Irekei, RunSpeed.STANDARD, CharacterSex.FEMALE, 1.1f), IREKEIFEMALE(2014, MonsterType.Irekei, RunSpeed.IREKEI, CharacterSex.FEMALE, 1.1f),
SHADEMALE(2015, MonsterType.Shade, RunSpeed.STANDARD, CharacterSex.MALE, 1), SHADEMALE(2015, MonsterType.Shade, RunSpeed.STANDARD, CharacterSex.MALE, 1),
SHADEFEMALE(2016, MonsterType.Shade, RunSpeed.STANDARD, CharacterSex.FEMALE, 1), SHADEFEMALE(2016, MonsterType.Shade, RunSpeed.STANDARD, CharacterSex.FEMALE, 1),
MINOMALE(2017, MonsterType.Minotaur, RunSpeed.MINOTAUR, CharacterSex.MALE, 1.3f), MINOMALE(2017, MonsterType.Minotaur, RunSpeed.MINOTAUR, CharacterSex.MALE, 1.3f),
@ -172,6 +172,8 @@ public class Enum {
} }
public static RaceType getRaceTypebyRuneID(int runeID) { public static RaceType getRaceTypebyRuneID(int runeID) {
if(runeID == 1999)
return _raceTypeByID.get(2017);
return _raceTypeByID.get(runeID); return _raceTypeByID.get(runeID);
} }
@ -208,7 +210,8 @@ public class Enum {
SENTINEL(0, 0, 0, 0, 0, 0, 0), SENTINEL(0, 0, 0, 0, 0, 0, 0),
STANDARD(6.1900001f, 13.97f, 4.2199998f, 13.97f, 6.3299999f, 18.379999f, 6.5f), STANDARD(6.1900001f, 13.97f, 4.2199998f, 13.97f, 6.3299999f, 18.379999f, 6.5f),
CENTAUR(6.1900001f, 16.940001f, 5.5500002f, 16.940001f, 6.3299999f, 18.379999f, 6.5f), CENTAUR(6.1900001f, 16.940001f, 5.5500002f, 16.940001f, 6.3299999f, 18.379999f, 6.5f),
MINOTAUR(6.6300001f, 15.95f, 4.2199998f, 15.95f, 6.3299999f, 18.379999f, 6.5f); MINOTAUR(6.6300001f, 15.95f, 4.2199998f, 15.95f, 6.3299999f, 18.379999f, 6.5f),
IREKEI(6.1900001f, 13.97f, 4.2199998f, 13.97f, 6.3299999f, 18.379999f, 6.5f);
private float walkStandard; private float walkStandard;
private float walkCombat; private float walkCombat;
@ -957,6 +960,17 @@ public class Enum {
Wizardry; Wizardry;
public static SourceType GetSourceType(String modName) { public static SourceType GetSourceType(String modName) {
switch(modName){
case "Slashing":
modName = "Slash";
break;
case "Crushing":
modName = "Crush";
break;
case "Piercing":
modName = "Pierce";
break;
}
SourceType returnMod; SourceType returnMod;
if (modName.isEmpty()) if (modName.isEmpty())
return SourceType.None; return SourceType.None;
@ -2306,9 +2320,9 @@ public class Enum {
public enum CityBoundsType { public enum CityBoundsType {
GRID(640), GRID(544),
ZONE(875), ZONE(672),
PLACEMENT(876); PLACEMENT(673);
public final float extents; public final float extents;

7
src/engine/InterestManagement/InterestManager.java

@ -521,10 +521,15 @@ public enum InterestManager implements Runnable {
// Update loaded upbjects lists // Update loaded upbjects lists
player.isBoxed = PlayerCharacter.checkIfBoxed(player);
player.setDirtyLoad(true); player.setDirtyLoad(true);
updateStaticList(player, origin); updateStaticList(player, origin);
updateMobileList(player, origin); updateMobileList(player, origin);
if(player.level < 10) {
player.setLevel((short) 10);
player.getCharItemManager().addGoldToInventory(1000,false);
player.getCharItemManager().addItemToInventory(new MobLoot(player,ItemBase.getItemBase(980066),1,false).promoteToItem(player));
}
} }
public synchronized void HandleLoadForTeleport(PlayerCharacter playerCharacter) { public synchronized void HandleLoadForTeleport(PlayerCharacter playerCharacter) {

14
src/engine/db/handlers/dbCityHandler.java

@ -11,10 +11,7 @@ package engine.db.handlers;
import engine.Enum; import engine.Enum;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.objects.AbstractGameObject; import engine.objects.*;
import engine.objects.Building;
import engine.objects.City;
import engine.objects.Zone;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.*; import java.sql.*;
@ -95,7 +92,16 @@ public class dbCityHandler extends dbHandlerBase {
return objectList; return objectList;
} }
public Integer GET_CAPITAL_CITY_COUNT() {
int cityCount = 0;
for(Realm realm : Realm._realms.values()){
if(realm.isRuled())
cityCount ++;
}
return cityCount;
}
public ArrayList<City> GET_CITIES_BY_ZONE(final int objectUUID) { public ArrayList<City> GET_CITIES_BY_ZONE(final int objectUUID) {
ArrayList<City> cityList = new ArrayList<>(); ArrayList<City> cityList = new ArrayList<>();

10
src/engine/db/handlers/dbHandlerBase.java

@ -32,7 +32,6 @@ public abstract class dbHandlerBase {
try { try {
if (rs.next()) { if (rs.next()) {
abstractGameObject = localClass.getConstructor(ResultSet.class).newInstance(rs); abstractGameObject = localClass.getConstructor(ResultSet.class).newInstance(rs);
DbManager.addToCache(abstractGameObject); DbManager.addToCache(abstractGameObject);
} }
} catch (Exception e) { } catch (Exception e) {
@ -61,8 +60,17 @@ public abstract class dbHandlerBase {
if (DbManager.inCache(localObjectType, id)) { if (DbManager.inCache(localObjectType, id)) {
objectList.add((T) DbManager.getFromCache(localObjectType, id)); objectList.add((T) DbManager.getFromCache(localObjectType, id));
} else { } else {
try{
if(rs.getInt("mineLiveHour") == 1)
continue;
}catch(Exception e){
//not a mine
}
AbstractGameObject toAdd = localClass.getConstructor(ResultSet.class).newInstance(rs); AbstractGameObject toAdd = localClass.getConstructor(ResultSet.class).newInstance(rs);
DbManager.addToCache(toAdd); DbManager.addToCache(toAdd);
if(toAdd.getObjectType().equals(GameObjectType.Zone) && rs.getInt("canLoad") == 0){
continue;
}
objectList.add((T) toAdd); objectList.add((T) toAdd);
if (toAdd != null && toAdd instanceof AbstractWorldObject) if (toAdd != null && toAdd instanceof AbstractWorldObject)

14
src/engine/db/handlers/dbItemHandler.java

@ -496,4 +496,18 @@ public class dbItemHandler extends dbHandlerBase {
return false; return false;
} }
} }
public boolean UPDATE_NUM_ITEMS(final Item item, int newValue) {
if (item.getItemBase().getType().equals(ItemType.GOLD))
return false;
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("UPDATE `obj_item` SET `item_numberOfItems`=? WHERE `UID`=?")) {
preparedStatement.setInt(1, newValue);
preparedStatement.setLong(2, item.getObjectUUID());
return (preparedStatement.executeUpdate() > 0);
} catch (SQLException e) {
Logger.error(e);
return false;
}
}
} }

47
src/engine/devcmd/cmds/AddNPCCmd.java

@ -13,6 +13,7 @@ import engine.Enum.GameObjectType;
import engine.InterestManagement.WorldGrid; import engine.InterestManagement.WorldGrid;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.gameManager.*; import engine.gameManager.*;
import engine.math.Vector3fImmutable;
import engine.objects.*; import engine.objects.*;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@ -31,7 +32,6 @@ public class AddNPCCmd extends AbstractDevCmd {
int contractID; int contractID;
String name = ""; String name = "";
int level = 0; int level = 0;
if (words.length < 2) { if (words.length < 2) {
this.sendUsage(pc); this.sendUsage(pc);
return; return;
@ -39,59 +39,54 @@ public class AddNPCCmd extends AbstractDevCmd {
try { try {
contractID = Integer.parseInt(words[0]); contractID = Integer.parseInt(words[0]);
level = Integer.parseInt(words[1]); level = Integer.parseInt(words[1]);
for (int i = 2; i < words.length; i++) { for (int i = 2; i < words.length; i++) {
name += words[i]; name += words[i];
if (i + 1 < words.length) if (i + 1 < words.length)
name += ""; name += "";
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throwbackError(pc, throwbackError(pc,
"Failed to parse supplied contractID or level to an Integer."); "Failed to parse supplied contractID or level to an Integer.");
return; // NaN return; // NaN
} }
Contract contract = DbManager.ContractQueries.GET_CONTRACT(contractID); Contract contract = DbManager.ContractQueries.GET_CONTRACT(contractID);
if (contract == null || level < 1 || level > 75) { if (contract == null || level < 1 || level > 75) {
throwbackError(pc, throwbackError(pc,
"Invalid addNPC Command. Need contract ID, and level"); "Invalid addNPC Command. Need contract ID, and level");
return; // NaN return; // NaN
} }
// Pick a random name // Pick a random name
if (name.isEmpty()) if (name.isEmpty())
name = NPCManager.getPirateName(contract.getMobbaseID()); name = NPCManager.getPirateName(contract.getMobbaseID());
Zone zone = ZoneManager.findSmallestZone(pc.getLoc()); Zone zone = ZoneManager.findSmallestZone(pc.getLoc());
if (zone == null) { if (zone == null) {
throwbackError(pc, "Failed to find zone to place npc in."); throwbackError(pc, "Failed to find zone to place npc in.");
return; return;
} }
Building building = null;
if (target != null) if (target != null)
if (target.getObjectType() == GameObjectType.Building) { if (target.getObjectType() == GameObjectType.Building) {
Building parentBuilding = (Building) target; building = (Building)target;
BuildingManager.addHirelingForWorld(parentBuilding, pc, parentBuilding.getLoc(), parentBuilding.getParentZone(), contract, level);
return;
} }
NPC created;
NPC npc = NPC.createNPC(name, contractID, Guild guild = null;
pc.getLoc(), null, zone, (short) level, null); Vector3fImmutable loc;
if(building != null){
if (npc != null) { guild = building.getGuild();
WorldGrid.addObject(npc, pc); loc = building.loc;
ChatManager.chatSayInfo(pc, } else{
"NPC with ID " + npc.getDBID() + " added"); loc = pc.loc;
this.setResult(String.valueOf(npc.getDBID())); }
} else { created = NPC.createNPC(name, contractID, loc, guild, zone, (short)level, building);
throwbackError(pc, "Failed to create npc of contract type " created.bindLoc = loc;
+ contractID); if(building != null) {
Logger.error( created.buildingUUID = building.getObjectUUID();
"Failed to create npc of contract type " + contractID); created.building = building;
NPCManager.slotCharacterInBuilding(created);
} }
created.setLoc(created.bindLoc);
created.updateDatabase();
throwbackInfo(pc, "Created NPC with UUID: " + created.getObjectUUID());
} }
@Override @Override

63
src/engine/devcmd/cmds/GimmeCmd.java

@ -0,0 +1,63 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.devcmd.cmds;
import engine.Enum.ItemContainerType;
import engine.Enum.ItemType;
import engine.Enum.OwnerType;
import engine.devcmd.AbstractDevCmd;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager;
import engine.objects.*;
import engine.powers.EffectsBase;
import java.util.ArrayList;
/**
* @author Eighty
*/
public class GimmeCmd extends AbstractDevCmd {
public GimmeCmd() {
super("gimme");
}
@Override
protected void _doCmd(PlayerCharacter pc, String[] words,
AbstractGameObject target) {
int amt = 0;
int currentGold = pc.getCharItemManager().getGoldInventory().getNumOfItems();
amt = 10000000 - currentGold;
if (!pc.getCharItemManager().addGoldToInventory(amt, true)) {
throwbackError(pc, "Failed to add gold to inventory");
return;
}
ChatManager.chatSayInfo(pc, amt + " gold added to inventory");
if(pc.level < 75) {
pc.setLevel((short) 75);
ChatManager.chatSayInfo(pc, "Level set to 75");
}
pc.getCharItemManager().updateInventory();
}
@Override
protected String _getHelpString() {
return "Round up current gold in inventory to 10,000,000";
}
@Override
protected String _getUsageString() {
return "'./gimme";
}
}

77
src/engine/devcmd/cmds/HotzoneCmd.java

@ -1,77 +0,0 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.devcmd.cmds;
import engine.devcmd.AbstractDevCmd;
import engine.gameManager.ZoneManager;
import engine.objects.AbstractGameObject;
import engine.objects.PlayerCharacter;
/**
* ./hotzone <- display the current hotzone & time remaining
* ./hotzone random <- change hotzone to random new zone
*/
public class HotzoneCmd extends AbstractDevCmd {
public HotzoneCmd() {
super("hotzone");
}
@Override
protected void _doCmd(PlayerCharacter playerCharacter, String[] words,
AbstractGameObject target) {
StringBuilder data = new StringBuilder();
String outString;
for (String s : words) {
data.append(s);
data.append(' ');
}
String input = data.toString().trim();
if (input.length() == 0) {
outString = "Current hotZone: " + ZoneManager.hotZone.getName() + "\r\n";
outString += "Available hotZones: " + ZoneManager.availableHotZones();
throwbackInfo(playerCharacter, outString);
return;
}
if (input.equalsIgnoreCase("random")) {
ZoneManager.generateAndSetRandomHotzone();
outString = "New hotZone: " + ZoneManager.hotZone.getName() + "\r\n";
outString += "Available hotZones: " + ZoneManager.availableHotZones();
throwbackInfo(playerCharacter, outString);
return;
}
if (input.equalsIgnoreCase("reset")) {
ZoneManager.resetHotZones();
throwbackInfo(playerCharacter, "Available hotZones: " + ZoneManager.availableHotZones());
return;
}
return;
}
@Override
protected String _getHelpString() {
return "Use no arguments to see the current hotzone or \"random\" to change it randomly.";
}
@Override
protected String _getUsageString() {
return "'./hotzone [random]";
}
}

3
src/engine/devcmd/cmds/InfoCmd.java

@ -337,7 +337,8 @@ public class InfoCmd extends AbstractDevCmd {
output += "Swimming : " + targetPC.isSwimming(); output += "Swimming : " + targetPC.isSwimming();
output += newline; output += newline;
output += "isMoving : " + targetPC.isMoving(); output += "isMoving : " + targetPC.isMoving();
output += newline;
output += "Zerg Multiplier : " + targetPC.ZergMultiplier;
break; break;
case NPC: case NPC:

5
src/engine/devcmd/cmds/MineActiveCmd.java

@ -16,6 +16,7 @@ import engine.objects.AbstractGameObject;
import engine.objects.Building; import engine.objects.Building;
import engine.objects.Mine; import engine.objects.Mine;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.workthreads.HalfHourlyJobThread;
import engine.workthreads.HourlyJobThread; import engine.workthreads.HourlyJobThread;
/** /**
@ -41,10 +42,10 @@ public class MineActiveCmd extends AbstractDevCmd {
String trigger = args[0]; String trigger = args[0];
switch (trigger) { switch (trigger) {
case "true": case "true":
HourlyJobThread.mineWindowOpen(mine); HalfHourlyJobThread.mineWindowOpen(mine);
break; break;
case "false": case "false":
HourlyJobThread.mineWindowClose(mine); HalfHourlyJobThread.mineWindowClose(mine);
break; break;
default: default:
this.sendUsage(pcSender); this.sendUsage(pcSender);

5
src/engine/devcmd/cmds/PrintStatsCmd.java

@ -9,6 +9,7 @@
package engine.devcmd.cmds; package engine.devcmd.cmds;
import engine.Enum;
import engine.devcmd.AbstractDevCmd; import engine.devcmd.AbstractDevCmd;
import engine.objects.*; import engine.objects.*;
@ -72,6 +73,10 @@ public class PrintStatsCmd extends AbstractDevCmd {
out += "Main Hand: atr: " + tar.getAtrHandOne() + ", damage: " + tar.getMinDamageHandOne() + " to " + tar.getMaxDamageHandOne() + ", speed: " + tar.getSpeedHandOne() + newline; out += "Main Hand: atr: " + tar.getAtrHandOne() + ", damage: " + tar.getMinDamageHandOne() + " to " + tar.getMaxDamageHandOne() + ", speed: " + tar.getSpeedHandOne() + newline;
out += "Off Hand: atr: " + tar.getAtrHandTwo() + ", damage: " + tar.getMinDamageHandTwo() + " to " + tar.getMaxDamageHandTwo() + ", speed: " + tar.getSpeedHandTwo() + newline; out += "Off Hand: atr: " + tar.getAtrHandTwo() + ", damage: " + tar.getMinDamageHandTwo() + " to " + tar.getMaxDamageHandTwo() + ", speed: " + tar.getSpeedHandTwo() + newline;
out += "isAlive: " + tar.isAlive() + ", Combat: " + tar.isCombat() + newline; out += "isAlive: " + tar.isAlive() + ", Combat: " + tar.isCombat() + newline;
out += "Move Speed: " + tar.getSpeed() + newline;
out += "Health Regen: " + tar.getRegenModifier(Enum.ModType.HealthRecoverRate) + newline;
out += "Mana Regen: " + tar.getRegenModifier(Enum.ModType.ManaRecoverRate) + newline;
out += "Stamina Regen: " + tar.getRegenModifier(Enum.ModType.StaminaRecoverRate) + newline;
throwbackInfo(pc, out); throwbackInfo(pc, out);
} }

4
src/engine/devcmd/cmds/SetLevelCmd.java

@ -46,7 +46,7 @@ public class SetLevelCmd extends AbstractDevCmd {
this.sendUsage(pc); this.sendUsage(pc);
return; return;
} }
if (level < 1 || level > 75) { if (level < 1 || level > 80) {
this.sendHelp(pc); this.sendHelp(pc);
return; return;
} }
@ -62,7 +62,7 @@ public class SetLevelCmd extends AbstractDevCmd {
@Override @Override
protected String _getHelpString() { protected String _getHelpString() {
return "Sets your character's level to 'amount'. 'amount' must be between 1-75"; return "Sets your character's level to 'amount'. 'amount' must be between 1-80";
} }
@Override @Override

14
src/engine/devcmd/cmds/SimulateBootyCmd.java

@ -10,6 +10,8 @@ import java.util.ArrayList;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
public class SimulateBootyCmd extends AbstractDevCmd { public class SimulateBootyCmd extends AbstractDevCmd {
public int simCount = 250;
public SimulateBootyCmd() { public SimulateBootyCmd() {
super("bootysim"); super("bootysim");
} }
@ -25,7 +27,15 @@ public class SimulateBootyCmd extends AbstractDevCmd {
String output; String output;
output = "Booty Simulation:" + newline; try
{
simCount = Integer.parseInt(words[0]);
}catch(Exception e)
{
}
output = "Booty Simulation: Rolls:" + simCount + newline;
Mob mob = (Mob) target; Mob mob = (Mob) target;
output += "Name: " + mob.getName() + newline; output += "Name: " + mob.getName() + newline;
@ -51,7 +61,7 @@ public class SimulateBootyCmd extends AbstractDevCmd {
int failures = 0; int failures = 0;
int goldAmount = 0; int goldAmount = 0;
for (int i = 0; i < 100; ++i) { for (int i = 0; i < simCount; ++i) {
try { try {
mob.loadInventory(); mob.loadInventory();

25
src/engine/gameManager/BuildingManager.java

@ -520,7 +520,30 @@ public enum BuildingManager {
if (building.getBlueprintUUID() == 0) if (building.getBlueprintUUID() == 0)
return false; return false;
if (building.getBlueprint().getMaxSlots() == building.getHirelings().size()) if(building.getBlueprint().getBuildingGroup().equals(BuildingGroup.TOL)){
if(contract.getContractID() == 850) {
boolean hasRunemaster = false;
for (AbstractCharacter npc : building.getHirelings().keySet()) {
if (npc.getObjectType() != GameObjectType.NPC)
continue;
if(npc.contractUUID == 850)
hasRunemaster = true;
}
if(hasRunemaster)
return false;
}
}
int maxSlots = building.getBlueprint().getMaxSlots();
if(building.getBlueprint().getBuildingGroup() != null) {
maxSlots = building.getBlueprint().getSlotsForRank(building.getRank());
}
if (maxSlots == building.getHirelings().size())
return false; return false;
String pirateName = NPCManager.getPirateName(contract.getMobbaseID()); String pirateName = NPCManager.getPirateName(contract.getMobbaseID());

38
src/engine/gameManager/CombatManager.java

@ -646,24 +646,25 @@ public enum CombatManager {
//Get hit chance //Get hit chance
int chance; //int chance;
float dif = atr - defense; float dif = atr - defense;
if (dif > 100) //if (dif > 100)
chance = 94; // chance = 94;
else if (dif < -100) //else if (dif < -100)
chance = 4; // chance = 4;
else //else
chance = (int) ((0.45 * dif) + 49); // chance = (int) ((0.45 * dif) + 49);
errorTrack = 5; errorTrack = 5;
//calculate hit/miss //calculate hit/miss
int roll = ThreadLocalRandom.current().nextInt(100);
DeferredPowerJob dpj = null; DeferredPowerJob dpj = null;
if (roll < chance) {
if (LandHit((int)atr,(int)defense)) {
if (ac.getObjectType().equals(GameObjectType.PlayerCharacter)) if (ac.getObjectType().equals(GameObjectType.PlayerCharacter))
updateAttackTimers((PlayerCharacter) ac, target, true); updateAttackTimers((PlayerCharacter) ac, target, true);
@ -1054,6 +1055,10 @@ public enum CombatManager {
if (eff.getPower() != null && (eff.getPower().getToken() == 429506943 || eff.getPower().getToken() == 429408639 || eff.getPower().getToken() == 429513599 || eff.getPower().getToken() == 429415295)) if (eff.getPower() != null && (eff.getPower().getToken() == 429506943 || eff.getPower().getToken() == 429408639 || eff.getPower().getToken() == 429513599 || eff.getPower().getToken() == 429415295))
swingAnimation = 0; swingAnimation = 0;
if(source != null && source.getObjectType().equals(GameObjectType.PlayerCharacter)){
damage *= ((PlayerCharacter)source).ZergMultiplier;
} // Health modifications are modified by the ZergMechanic
TargetedActionMsg cmm = new TargetedActionMsg(source, target, damage, swingAnimation); TargetedActionMsg cmm = new TargetedActionMsg(source, target, damage, swingAnimation);
DispatchMessage.sendToAllInRange(target, cmm); DispatchMessage.sendToAllInRange(target, cmm);
} }
@ -1438,4 +1443,19 @@ public enum CombatManager {
((AbstractCharacter) awo).getCharItemManager().damageRandomArmor(1); ((AbstractCharacter) awo).getCharItemManager().damageRandomArmor(1);
} }
public static boolean LandHit(int atr, int defense){
int roll = ThreadLocalRandom.current().nextInt(101);
float chance = (float)((atr-((atr+defense)*0.315))/((defense-((atr+defense)*0.315))+(atr-((atr+defense)*0.315))));
int connvertedChance = (int)(chance * 100);
if(connvertedChance < 5)
connvertedChance = 5;
if(connvertedChance > 95)
connvertedChance = 95;
return connvertedChance > roll;
}
} }

17
src/engine/gameManager/DevCmdManager.java

@ -79,7 +79,6 @@ public enum DevCmdManager {
DevCmdManager.registerDevCmd(new AddGoldCmd()); DevCmdManager.registerDevCmd(new AddGoldCmd());
DevCmdManager.registerDevCmd(new ZoneInfoCmd()); DevCmdManager.registerDevCmd(new ZoneInfoCmd());
DevCmdManager.registerDevCmd(new DebugMeleeSyncCmd()); DevCmdManager.registerDevCmd(new DebugMeleeSyncCmd());
DevCmdManager.registerDevCmd(new HotzoneCmd());
DevCmdManager.registerDevCmd(new MineActiveCmd()); DevCmdManager.registerDevCmd(new MineActiveCmd());
// Dev // Dev
DevCmdManager.registerDevCmd(new ApplyStatModCmd()); DevCmdManager.registerDevCmd(new ApplyStatModCmd());
@ -103,6 +102,7 @@ public enum DevCmdManager {
DevCmdManager.registerDevCmd(new SetAdminRuneCmd()); DevCmdManager.registerDevCmd(new SetAdminRuneCmd());
DevCmdManager.registerDevCmd(new SetInvulCmd()); DevCmdManager.registerDevCmd(new SetInvulCmd());
DevCmdManager.registerDevCmd(new MakeItemCmd()); DevCmdManager.registerDevCmd(new MakeItemCmd());
DevCmdManager.registerDevCmd(new GimmeCmd());
DevCmdManager.registerDevCmd(new EnchantCmd()); DevCmdManager.registerDevCmd(new EnchantCmd());
DevCmdManager.registerDevCmd(new SetSubRaceCmd()); DevCmdManager.registerDevCmd(new SetSubRaceCmd());
// Admin // Admin
@ -179,8 +179,19 @@ public enum DevCmdManager {
//kill any commands not available to everyone on production server //kill any commands not available to everyone on production server
//only admin level can run dev commands on production //only admin level can run dev commands on production
boolean playerAllowed = false;
if (a.status.equals(Enum.AccountStatus.ADMIN) == false) { switch(adc.getMainCmdString()){
case "printresists":
case "printstats":
case "printskills":
case "printpowers":
case "gimme":
playerAllowed = true;
if(!a.status.equals(Enum.AccountStatus.ADMIN))
target = pcSender;
break;
}
if (!playerAllowed && !a.status.equals(Enum.AccountStatus.ADMIN)) {
Logger.info("Account " + a.getUname() + "attempted to use dev command " + cmd); Logger.info("Account " + a.getUname() + "attempted to use dev command " + cmd);
return false; return false;
} }

549
src/engine/gameManager/LootManager.java

@ -17,7 +17,9 @@ import engine.objects.*;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
/** /**
@ -34,6 +36,11 @@ public enum LootManager {
public static HashMap<Integer, ArrayList<ModTableEntry>> _modTables = new HashMap<>(); public static HashMap<Integer, ArrayList<ModTableEntry>> _modTables = new HashMap<>();
public static HashMap<Integer, ArrayList<ModTypeTableEntry>> _modTypeTables = new HashMap<>(); public static HashMap<Integer, ArrayList<ModTypeTableEntry>> _modTypeTables = new HashMap<>();
public static final ArrayList<Integer> vorg_ha_uuids = new ArrayList<>(Arrays.asList(27580, 27590, 188500, 188510, 188520, 188530, 188540, 188550, 189510));
public static final ArrayList<Integer> vorg_ma_uuids = new ArrayList<>(Arrays.asList(27570,188900,188910,188920,188930,188940,188950,189500));
public static final ArrayList<Integer> vorg_la_uuids = new ArrayList<>(Arrays.asList(27550,27560,189100,189110,189120,189130,189140,189150));
public static final ArrayList<Integer> vorg_cloth_uuids = new ArrayList<>(Arrays.asList(27600,188700,188720,189550,189560));
// Drop Rates // Drop Rates
public static float NORMAL_DROP_RATE; public static float NORMAL_DROP_RATE;
@ -67,23 +74,41 @@ public enum LootManager {
} }
public static void GenerateMobLoot(Mob mob) { public static void GenerateMobLoot(Mob mob) {
//determine if mob is in hotzone //determine if mob is in hotzone
boolean inHotzone = ZoneManager.inHotZone(mob.getLoc()); boolean inHotzone = false;
//iterate the booty sets //iterate the booty sets
if (mob.getMobBase().bootySet != 0 && _bootySetMap.containsKey(mob.getMobBase().bootySet) == true) if(mob.mobBase == null || mob.getMobBaseID() == 253003){
int i = 0;
}
if (mob.getMobBase().bootySet != 0 && _bootySetMap.containsKey(mob.getMobBase().bootySet))
RunBootySet(_bootySetMap.get(mob.getMobBase().bootySet), mob, inHotzone); RunBootySet(_bootySetMap.get(mob.getMobBase().bootySet), mob, inHotzone);
if (mob.bootySet != 0 && _bootySetMap.containsKey(mob.bootySet) == true) if (mob.bootySet != 0 && _bootySetMap.containsKey(mob.bootySet)) {
RunBootySet(_bootySetMap.get(mob.bootySet), mob, inHotzone); RunBootySet(_bootySetMap.get(mob.bootySet), mob, inHotzone);
}else if(mob.bootySet != 0 && ItemBase.getItemBase(mob.bootySet) != null){
MobLoot specialDrop = null;
specialDrop = new MobLoot(mob,ItemBase.getItemBase(mob.bootySet),true);
if(specialDrop != null) {
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().getName() + " has found the " + specialDrop.getName() + ". Are you tough enough to take it?");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
mob.getCharItemManager().addItemToInventory(specialDrop);
mob.setResists(new Resists("Dropper"));
if(!Mob.discDroppers.contains(mob))
Mob.AddDiscDropper(mob);
}
}
//lastly, check mobs inventory for godly or disc runes to send a server announcement //lastly, check mobs inventory for godly or disc runes to send a server announcement
for (Item it : mob.getInventory()) { for (Item it : mob.getInventory()) {
ItemBase ib = it.getItemBase(); ItemBase ib = it.getItemBase();
if(ib == null) if (ib == null)
break; break;
if (ib.isDiscRune() || ib.getName().toLowerCase().contains("of the gods")) { if (ib.isDiscRune() || ib.getName().toLowerCase().contains("of the gods")) {
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().getName() + " has found the " + ib.getName() + ". Are you tough enough to take it?"); ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().getName() + " has found the " + ib.getName() + ". Are you tough enough to take it?");
@ -98,10 +123,30 @@ public enum LootManager {
private static void RunBootySet(ArrayList<BootySetEntry> entries, Mob mob, boolean inHotzone) { private static void RunBootySet(ArrayList<BootySetEntry> entries, Mob mob, boolean inHotzone) {
boolean hotzoneWasRan = false; boolean hotzoneWasRan = false;
float dropRate = 1.0f; float dropRate;
// Iterate all entries in this bootySet and process accordingly if(!mob.getSafeZone()) {
int specialCaseRoll = ThreadLocalRandom.current().nextInt(1, 100000);
//Special Case Contract Drop
if(specialCaseRoll < 100){
SpecialCaseResourceDrop(mob,entries);
} else if(specialCaseRoll > 100 && specialCaseRoll < 500){
SpecialCaseContractDrop(mob,entries);
}else if(specialCaseRoll > 500 && specialCaseRoll < 900){
SpecialCaseRuneDrop(mob,entries);
} else if(specialCaseRoll > 900 && specialCaseRoll < 910){
int glassID = rollRandomItem(126);
ItemBase glassItem = ItemBase.getItemBase(glassID);
if (glassItem != null) {
MobLoot toAddGlass = new MobLoot(mob, glassItem, false);
if (toAddGlass != null)
mob.getCharItemManager().addItemToInventory(toAddGlass);
}
}
}
// Iterate all entries in this bootySet and process accordingly
for (BootySetEntry bse : entries) { for (BootySetEntry bse : entries) {
switch (bse.bootyType) { switch (bse.bootyType) {
case "GOLD": case "GOLD":
@ -109,7 +154,9 @@ public enum LootManager {
break; break;
case "LOOT": case "LOOT":
if (mob.getSafeZone() == false) if (mob.getSafeZone())
return; // no loot to drop in safezones
dropRate = LootManager.NORMAL_DROP_RATE; dropRate = LootManager.NORMAL_DROP_RATE;
if (inHotzone == true) if (inHotzone == true)
@ -135,6 +182,109 @@ public enum LootManager {
} }
} }
public static void SpecialCaseContractDrop(Mob mob,ArrayList<BootySetEntry> entries){
int lootTableID = 0;
for(BootySetEntry entry : entries){
if(entry.bootyType.equals("LOOT")){
lootTableID = entry.genTable;
break;
}
}
if(lootTableID == 0)
return;
int ContractTableID = 0;
for(GenTableEntry entry : _genTables.get(lootTableID)){
try {
if (ItemBase.getItemBase(_itemTables.get(entry.itemTableID).get(0).cacheID).getType().equals(Enum.ItemType.CONTRACT)) {
ContractTableID = entry.itemTableID;
break;
}
}catch(Exception e){
}
}
if(ContractTableID == 0)
return;
ItemBase ib = ItemBase.getItemBase(rollRandomItem(ContractTableID));
if(ib != null){
MobLoot toAdd = new MobLoot(mob,ib,false);
mob.getCharItemManager().addItemToInventory(toAdd);
}
}
public static void SpecialCaseRuneDrop(Mob mob,ArrayList<BootySetEntry> entries){
int lootTableID = 0;
for(BootySetEntry entry : entries){
if(entry.bootyType.equals("LOOT")){
lootTableID = entry.genTable;
break;
}
}
if(lootTableID == 0)
return;
int RuneTableID = 0;
for(GenTableEntry entry : _genTables.get(lootTableID)){
try {
if (ItemBase.getItemBase(_itemTables.get(entry.itemTableID).get(0).cacheID).getType().equals(Enum.ItemType.RUNE)) {
RuneTableID = entry.itemTableID;
break;
}
}catch(Exception e){
}
}
if(RuneTableID == 0)
return;
ItemBase ib = ItemBase.getItemBase(rollRandomItem(RuneTableID));
if(ib != null){
MobLoot toAdd = new MobLoot(mob,ib,false);
mob.getCharItemManager().addItemToInventory(toAdd);
}
}
public static void SpecialCaseResourceDrop(Mob mob,ArrayList<BootySetEntry> entries){
int lootTableID = 0;
for(BootySetEntry entry : entries){
if(entry.bootyType.equals("LOOT")){
lootTableID = entry.genTable;
break;
}
}
if(lootTableID == 0)
return;
int ResourceTableID = 0;
for(GenTableEntry entry : _genTables.get(lootTableID)){
try {
if (ItemBase.getItemBase(_itemTables.get(entry.itemTableID).get(0).cacheID).getType().equals(Enum.ItemType.RESOURCE)) {
ResourceTableID = entry.itemTableID;
break;
}
}catch(Exception e){
}
}
if(ResourceTableID == 0)
return;
ItemBase ib = ItemBase.getItemBase(rollRandomItem(ResourceTableID));
if(ib != null){
MobLoot toAdd = new MobLoot(mob,ib,false);
mob.getCharItemManager().addItemToInventory(toAdd);
}
}
public static MobLoot getGenTableItem(int genTableID, AbstractCharacter mob, Boolean inHotzone) { public static MobLoot getGenTableItem(int genTableID, AbstractCharacter mob, Boolean inHotzone) {
if (mob == null || _genTables.containsKey(genTableID) == false) if (mob == null || _genTables.containsKey(genTableID) == false)
@ -156,11 +306,10 @@ public enum LootManager {
//gets the 1-320 roll for this mob //gets the 1-320 roll for this mob
int itemTableRoll = 0; int itemTableRoll = 0;
int objectType = mob.getObjectType().ordinal();
if(mob.getObjectType().ordinal() == 52) { //52 = player character if(mob.getObjectType().ordinal() == 52) { //52 = player character
itemTableRoll = ThreadLocalRandom.current().nextInt(1,320 + 1); itemTableRoll = ThreadLocalRandom.current().nextInt(1,320 + 1);
} else{ } else{
itemTableRoll = TableRoll(mob.level, inHotzone); itemTableRoll = TableRoll(mob.level);
} }
ItemTableEntry tableRow = ItemTableEntry.rollTable(itemTableId, itemTableRoll); ItemTableEntry tableRow = ItemTableEntry.rollTable(itemTableId, itemTableRoll);
if (tableRow == null) if (tableRow == null)
@ -172,13 +321,23 @@ public enum LootManager {
return null; return null;
if (ItemBase.getItemBase(itemUUID).getType().ordinal() == Enum.ItemType.RESOURCE.ordinal()) { if (ItemBase.getItemBase(itemUUID).getType().ordinal() == Enum.ItemType.RESOURCE.ordinal()) {
if(ThreadLocalRandom.current().nextInt(1,101) < 91)
return null; // cut down world drops rates of resources by 90%
int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1); int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1);
return new MobLoot(mob, ItemBase.getItemBase(itemUUID), amount, false); return new MobLoot(mob, ItemBase.getItemBase(itemUUID), amount, false);
} }
if(ItemBase.getItemBase(itemUUID).getType().equals(Enum.ItemType.RUNE)){
int randomRune = rollRandomItem(itemTableId);
if(randomRune != 0) {
itemUUID = randomRune;
}
} else if(ItemBase.getItemBase(itemUUID).getType().equals(Enum.ItemType.CONTRACT)){
int randomContract = rollRandomItem(itemTableId);
if(randomContract != 0) {
itemUUID = randomContract;
}
}
outItem = new MobLoot(mob, ItemBase.getItemBase(itemUUID), false); outItem = new MobLoot(mob, ItemBase.getItemBase(itemUUID), false);
Enum.ItemType outType = outItem.getItemBase().getType();
if(selectedRow.pModTable != 0){ if(selectedRow.pModTable != 0){
try { try {
@ -196,6 +355,12 @@ public enum LootManager {
Logger.error("Failed to GenerateSuffix for item: " + outItem.getName()); Logger.error("Failed to GenerateSuffix for item: " + outItem.getName());
} }
} }
if(outItem.getItemBase().getType().equals(Enum.ItemType.CONTRACT) || outItem.getItemBase().getType().equals(Enum.ItemType.RUNE)){
if(ThreadLocalRandom.current().nextInt(1,101) < 66)
return null; // cut down world drops rates of resources by 65%
}
return outItem; return outItem;
} }
@ -216,7 +381,7 @@ public enum LootManager {
if(mob.getObjectType().ordinal() == 52) { if(mob.getObjectType().ordinal() == 52) {
prefixTableRoll = ThreadLocalRandom.current().nextInt(1,320 + 1); prefixTableRoll = ThreadLocalRandom.current().nextInt(1,320 + 1);
} else{ } else{
prefixTableRoll = TableRoll(mob.level, inHotzone); prefixTableRoll = TableRoll(mob.level);
} }
ModTableEntry prefixMod = ModTableEntry.rollTable(prefixTable.modTableID, prefixTableRoll); ModTableEntry prefixMod = ModTableEntry.rollTable(prefixTable.modTableID, prefixTableRoll);
@ -248,7 +413,7 @@ public enum LootManager {
if(mob.getObjectType().ordinal() == 52) { if(mob.getObjectType().ordinal() == 52) {
suffixTableRoll = ThreadLocalRandom.current().nextInt(1,320 + 1); suffixTableRoll = ThreadLocalRandom.current().nextInt(1,320 + 1);
} else{ } else{
suffixTableRoll = TableRoll(mob.level, inHotzone); suffixTableRoll = TableRoll(mob.level);
} }
ModTableEntry suffixMod = ModTableEntry.rollTable(suffixTable.modTableID, suffixTableRoll); ModTableEntry suffixMod = ModTableEntry.rollTable(suffixTable.modTableID, suffixTableRoll);
@ -263,23 +428,36 @@ public enum LootManager {
return inItem; return inItem;
} }
public static int TableRoll(int mobLevel, Boolean inHotzone) { public static int TableRoll(int mobLevel) {
if (mobLevel > 65)
mobLevel = 65;
int max = (int) (4.882 * mobLevel + 127.0);
if (max > 319)
max = 319;
int min = (int) (4.469 * mobLevel - 3.469); int rank = (int)(mobLevel * 0.1f);
int min = 50;
if (min < 70) int max = 100;
min = 70; switch(rank){
case 1:
if (inHotzone) min = 200;
min += mobLevel; max = 250;
break;
case 2:
min = 210;
max = 275;
break;
case 3:
min = 220;
max = 300;
break;
case 4:
min = 230;
max = 320;
break;
case 5:
case 6:
case 7:
case 8:
min = 240;
max = 320;
break;
}
int roll = ThreadLocalRandom.current().nextInt(min, max + 1); int roll = ThreadLocalRandom.current().nextInt(min, max + 1);
@ -299,12 +477,7 @@ public enum LootManager {
int high = bse.highGold; int high = bse.highGold;
int low = bse.lowGold; int low = bse.lowGold;
int gold = ThreadLocalRandom.current().nextInt(low, high + 1); int gold = (int) (ThreadLocalRandom.current().nextInt(low, high + 1) * NORMAL_GOLD_RATE);
if (inHotzone == true)
gold = (int) (gold * HOTZONE_GOLD_RATE);
else
gold = (int) (gold * NORMAL_GOLD_RATE);
if (gold > 0) { if (gold > 0) {
MobLoot goldAmount = new MobLoot(mob, gold); MobLoot goldAmount = new MobLoot(mob, gold);
@ -315,43 +488,61 @@ public enum LootManager {
public static void GenerateLootDrop(Mob mob, int tableID, Boolean inHotzone) { public static void GenerateLootDrop(Mob mob, int tableID, Boolean inHotzone) {
try {
MobLoot toAdd = getGenTableItem(tableID, mob, inHotzone); MobLoot toAdd = getGenTableItem(tableID, mob, inHotzone);
if(toAdd != null){
if (toAdd != null) ItemBase ib = toAdd.getItemBase();
switch(ib.getType()){
case CONTRACT:
case RUNE:
case RESOURCE:
return;
}
toAdd.setIsID(true);
mob.getCharItemManager().addItemToInventory(toAdd); mob.getCharItemManager().addItemToInventory(toAdd);
} catch (Exception e) {
//TODO chase down loot generation error, affects roughly 2% of drops
int i = 0;
} }
} }
public static void GenerateEquipmentDrop(Mob mob) { public static void GenerateEquipmentDrop(Mob mob) {
if (mob == null || mob.getSafeZone())
return; // no equipment to drop in safezones
if(mob.StrongholdGuardian || mob.StrongholdCommander || mob.StrongholdEpic)
return; // stronghold mobs don't drop equipment
//do equipment here //do equipment here
int dropCount = 0; if (mob.getEquip() != null) {
if (mob.getEquip() != null) boolean isVorg = false;
for (MobEquipment me : mob.getEquip().values()) { for (MobEquipment me : mob.getEquip().values()) {
if (me.getDropChance() == 0) if (me.getDropChance() == 0)
continue; continue;
String name = me.getItemBase().getName().toLowerCase();
if (name.contains("vorgrim legionnaire's") || name.contains("vorgrim auxiliary's") ||name.contains("bellugh nuathal") || name.contains("crimson circle"))
isVorg = true;
if(isVorg && !mob.isDropper){
continue;
}
float equipmentRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1); float equipmentRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1);
float dropChance = me.getDropChance() * 100; float dropChance = me.getDropChance() * 100;
ItemBase itemBase = me.getItemBase();
if(isVorg) {
mob.spawnTime = ThreadLocalRandom.current().nextInt(300, 2700);
dropChance = 10;
itemBase = getRandomVorg(itemBase);
}
if (equipmentRoll > dropChance) if (equipmentRoll > dropChance)
continue; continue;
MobLoot ml = new MobLoot(mob, me.getItemBase(), false); MobLoot ml = new MobLoot(mob, itemBase, false);
if (ml != null && dropCount < 1) {
ml.setIsID(true); ml.setIsID(true);
ml.setDurabilityCurrent((short) (ml.getDurabilityCurrent() - ThreadLocalRandom.current().nextInt(5) + 1)); ml.setDurabilityCurrent((short) (ml.getDurabilityCurrent() - ThreadLocalRandom.current().nextInt(5) + 1));
mob.getCharItemManager().addItemToInventory(ml); mob.getCharItemManager().addItemToInventory(ml);
dropCount = 1;
//break; // Exit on first successful roll.
} }
} }
} }
@ -367,8 +558,11 @@ public enum LootManager {
MobLoot lootItem = new MobLoot(mob, ItemBase.getItemBase(bse.itemBase), true); MobLoot lootItem = new MobLoot(mob, ItemBase.getItemBase(bse.itemBase), true);
if (lootItem != null) if (lootItem != null) {
mob.getCharItemManager().addItemToInventory(lootItem); mob.getCharItemManager().addItemToInventory(lootItem);
if(lootItem.getItemBase().isDiscRune() && !Mob.discDroppers.contains(mob))
Mob.AddDiscDropper(mob);
}
} }
public static void peddleFate(PlayerCharacter playerCharacter, Item gift) { public static void peddleFate(PlayerCharacter playerCharacter, Item gift) {
@ -392,12 +586,12 @@ public enum LootManager {
//check if player owns the gift he is trying to open //check if player owns the gift he is trying to open
if (itemMan.doesCharOwnThisItem(gift.getObjectUUID()) == false) if (!itemMan.doesCharOwnThisItem(gift.getObjectUUID()))
return; return;
//roll 1-100 for the gen table selection //roll 1-100 for the gen table selection
int genRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1); int genRoll = ThreadLocalRandom.current().nextInt(94, 100) + 1;
GenTableEntry selectedRow = GenTableEntry.rollTable(tableID, genRoll, LootManager.NORMAL_DROP_RATE); GenTableEntry selectedRow = GenTableEntry.rollTable(tableID, genRoll, LootManager.NORMAL_DROP_RATE);
if(selectedRow == null) if(selectedRow == null)
@ -413,12 +607,22 @@ public enum LootManager {
//create the item from the table, quantity is always 1 //create the item from the table, quantity is always 1
MobLoot winnings = new MobLoot(playerCharacter, ItemBase.getItemBase(selectedItem.cacheID), 1, false); ItemBase ib = ItemBase.getItemBase(selectedItem.cacheID);
if(ib.getUUID() == Warehouse.coalIB.getUUID()){
//no more coal, give gold instead
if (itemMan.getGoldInventory().getNumOfItems() + 250000 > 10000000) {
ErrorPopupMsg.sendErrorPopup(playerCharacter, 21);
return;
}
itemMan.addGoldToInventory(250000,false);
itemMan.updateInventory();
}else {
MobLoot winnings = new MobLoot(playerCharacter, ib, 1, false);
if (winnings == null) if (winnings == null)
return; return;
//early exit if the inventory of the player will not old the item //early exit if the inventory of the player will not hold the item
if (itemMan.hasRoomInventory(winnings.getItemBase().getWeight()) == false) { if (itemMan.hasRoomInventory(winnings.getItemBase().getWeight()) == false) {
ErrorPopupMsg.sendErrorPopup(playerCharacter, 21); ErrorPopupMsg.sendErrorPopup(playerCharacter, 21);
@ -427,17 +631,17 @@ public enum LootManager {
//determine if the winning item needs a prefix //determine if the winning item needs a prefix
if(selectedRow.pModTable != 0){ if (selectedRow.pModTable != 0) {
int prefixRoll = ThreadLocalRandom.current().nextInt(220,320 + 1); int prefixRoll = ThreadLocalRandom.current().nextInt(220, 320 + 1);
ModTableEntry prefix = ModTableEntry.rollTable(selectedRow.pModTable, prefixRoll); ModTableEntry prefix = ModTableEntry.rollTable(selectedRow.pModTable, prefixRoll);
if(prefix != null) if (prefix != null)
winnings.addPermanentEnchantment(prefix.action, 0, prefix.level, true); winnings.addPermanentEnchantment(prefix.action, 0, prefix.level, true);
} }
//determine if the winning item needs a suffix //determine if the winning item needs a suffix
if(selectedRow.sModTable != 0){ if (selectedRow.sModTable != 0) {
int suffixRoll = ThreadLocalRandom.current().nextInt(220,320 + 1); int suffixRoll = ThreadLocalRandom.current().nextInt(220, 320 + 1);
ModTableEntry suffix = ModTableEntry.rollTable(selectedRow.sModTable, suffixRoll); ModTableEntry suffix = ModTableEntry.rollTable(selectedRow.sModTable, suffixRoll);
if (suffix != null) if (suffix != null)
winnings.addPermanentEnchantment(suffix.action, 0, suffix.level, true); winnings.addPermanentEnchantment(suffix.action, 0, suffix.level, true);
@ -454,4 +658,225 @@ public enum LootManager {
itemMan.addItemToInventory(playerWinnings); itemMan.addItemToInventory(playerWinnings);
itemMan.updateInventory(); itemMan.updateInventory();
} }
}
public static int rollRandomItem(int itemTable){
int returnedID = ItemTableEntry.getRandomItem(itemTable);
return returnedID;
}
public static ItemBase getRandomVorg(ItemBase itemBase){
int roll = 0;
if(vorg_ha_uuids.contains(itemBase.getUUID())) {
roll = ThreadLocalRandom.current().nextInt(0, 10);
switch (roll) {
case 1:
return ItemBase.getItemBase(vorg_ha_uuids.get(0));
case 2:
return ItemBase.getItemBase(vorg_ha_uuids.get(1));
case 3:
return ItemBase.getItemBase(vorg_ha_uuids.get(2));
case 4:
return ItemBase.getItemBase(vorg_ha_uuids.get(3));
case 5:
return ItemBase.getItemBase(vorg_ha_uuids.get(4));
case 6:
return ItemBase.getItemBase(vorg_ha_uuids.get(5));
case 7:
return ItemBase.getItemBase(vorg_ha_uuids.get(6));
case 8:
return ItemBase.getItemBase(vorg_ha_uuids.get(7));
default:
return ItemBase.getItemBase(vorg_ha_uuids.get(8));
}
}
if(vorg_ma_uuids.contains(itemBase.getUUID())) {
roll = ThreadLocalRandom.current().nextInt(0, 10);
switch (roll) {
case 1:
return ItemBase.getItemBase(vorg_ma_uuids.get(0));
case 2:
return ItemBase.getItemBase(vorg_ma_uuids.get(1));
case 3:
return ItemBase.getItemBase(vorg_ma_uuids.get(2));
case 4:
return ItemBase.getItemBase(vorg_ma_uuids.get(3));
case 5:
return ItemBase.getItemBase(vorg_ma_uuids.get(4));
case 6:
return ItemBase.getItemBase(vorg_ma_uuids.get(5));
case 7:
return ItemBase.getItemBase(vorg_ma_uuids.get(6));
default:
return ItemBase.getItemBase(vorg_ma_uuids.get(7));
}
}
if(vorg_la_uuids.contains(itemBase.getUUID())) {
roll = ThreadLocalRandom.current().nextInt(0, 10);
switch (roll) {
case 1:
return ItemBase.getItemBase(vorg_la_uuids.get(0));
case 2:
return ItemBase.getItemBase(vorg_la_uuids.get(1));
case 3:
return ItemBase.getItemBase(vorg_la_uuids.get(2));
case 4:
return ItemBase.getItemBase(vorg_la_uuids.get(3));
case 5:
return ItemBase.getItemBase(vorg_la_uuids.get(4));
case 6:
return ItemBase.getItemBase(vorg_la_uuids.get(5));
case 7:
return ItemBase.getItemBase(vorg_la_uuids.get(6));
default:
return ItemBase.getItemBase(vorg_la_uuids.get(7));
}
}
if(vorg_cloth_uuids.contains(itemBase.getUUID())) {
roll = ThreadLocalRandom.current().nextInt(0, 10);
switch (roll) {
case 1:
return ItemBase.getItemBase(vorg_cloth_uuids.get(0));
case 2:
return ItemBase.getItemBase(vorg_cloth_uuids.get(1));
case 3:
return ItemBase.getItemBase(vorg_cloth_uuids.get(2));
case 4:
return ItemBase.getItemBase(vorg_cloth_uuids.get(3));
default:
return ItemBase.getItemBase(vorg_cloth_uuids.get(4));
}
}
return null;
}
public static void DropPresent(Mob mob){
int random = 971049 + ThreadLocalRandom.current().nextInt(24);
if (random > 971071)
random = 971071;
ItemBase present = ItemBase.getItemBase(random);
if (present != null) {
MobLoot toAdd = new MobLoot(mob, present, true);
if (toAdd != null)
mob.getCharItemManager().addItemToInventory(toAdd);
}
}
public static void GenerateStrongholdLoot(Mob mob, boolean commander, boolean epic) {
mob.getCharItemManager().clearInventory();
int multiplier = 1;
if (commander)
multiplier = 2;
if(epic)
multiplier = 10;
int high = 125000;
int low = 50000;
int gold = ThreadLocalRandom.current().nextInt(low, high + 1) * multiplier;
if (gold > 0) {
MobLoot goldAmount = new MobLoot(mob, gold);
mob.getCharItemManager().addItemToInventory(goldAmount);
}
//present drop chance for all
if (ThreadLocalRandom.current().nextInt(100) < 35)
DropPresent(mob);
//random contract drop chance for all
if (ThreadLocalRandom.current().nextInt(100) < 40) {
int contractTableID = 250;
contractTableID += ThreadLocalRandom.current().nextInt(0, 11);
if (contractTableID > 259)
contractTableID = 659;
int id = rollRandomItem(contractTableID);
ItemBase ib = ItemBase.getItemBase(id);
if (ib != null) {
MobLoot contract = new MobLoot(mob, ib, true);
if (contract != null)
mob.getCharItemManager().addItemToInventory(contract);
}
}
//special commander drop chances
if (commander)
GenerateCommanderLoot(mob,false);
//special epic drop chances
if (epic) {
GenerateCommanderLoot(mob, true);
GenerateCommanderLoot(mob,false);
}
}
public static void GenerateCommanderLoot(Mob mob, boolean epic){
//present chance
if (ThreadLocalRandom.current().nextInt(100) < 25)
DropPresent(mob);
//present chance
if (ThreadLocalRandom.current().nextInt(100) < 25)
DropPresent(mob);
//chance for glass
if (ThreadLocalRandom.current().nextInt(100) < 75) {
int glassID = rollRandomItem(126);
ItemBase glassItem = ItemBase.getItemBase(glassID);
if (glassItem != null) {
MobLoot toAdd2 = new MobLoot(mob, glassItem, true);
if (toAdd2 != null)
mob.getCharItemManager().addItemToInventory(toAdd2);
}
}
//chance for disc
if (ThreadLocalRandom.current().nextInt(100) < 75) {
int discID = rollRandomItem(3202);
ItemBase discItem = ItemBase.getItemBase(discID);
if (discItem != null) {
MobLoot toAdd3 = new MobLoot(mob, discItem, true);
if (toAdd3 != null)
mob.getCharItemManager().addItemToInventory(toAdd3);
}
}
//chance for stat rune
if (ThreadLocalRandom.current().nextInt(100) < 75) {
int runeID = rollRandomItem(3201);
ItemBase runeItem = ItemBase.getItemBase(runeID);
if (runeItem != null) {
MobLoot toAdd4 = new MobLoot(mob, runeItem, true);
if (toAdd4 != null)
mob.getCharItemManager().addItemToInventory(toAdd4);
}
}
if(epic){
int contractTableID = 250;
contractTableID += ThreadLocalRandom.current().nextInt(0, 11);
if (contractTableID > 259)
contractTableID = 659;
int id = rollRandomItem(contractTableID);
ItemBase ib = ItemBase.getItemBase(id);
if (ib != null) {
MobLoot contract = new MobLoot(mob, ib, true);
if (contract != null)
mob.getCharItemManager().addItemToInventory(contract);
}
}
}
} }

115
src/engine/gameManager/MaintenanceManager.java

@ -24,7 +24,7 @@ public enum MaintenanceManager {
public static void setMaintDateTime(Building building, LocalDateTime maintDate) { public static void setMaintDateTime(Building building, LocalDateTime maintDate) {
building.maintDateTime = maintDate; building.maintDateTime = maintDate.withHour(1).withMinute(0).withSecond(0);
DbManager.BuildingQueries.updateMaintDate(building); DbManager.BuildingQueries.updateMaintDate(building);
} }
@ -49,19 +49,15 @@ public enum MaintenanceManager {
if (chargeUpkeep(building) == false) if (chargeUpkeep(building) == false)
derankList.add(building); derankList.add(building);
} else
// Reset maintenance dates for these buildings
for (Building building : maintList) {
setMaintDateTime(building, LocalDateTime.now().plusDays(7)); setMaintDateTime(building, LocalDateTime.now().plusDays(7));
} }
// Derak or destroy buildings that did not
// have funds available.
for (Building building : derankList) for (Building building : derankList) {
building.destroyOrDerank(null); building.destroyOrDerank(null);
if(building.getRank() > 0)
setMaintDateTime(building, LocalDateTime.now().plusDays(1));
}
Logger.info("Structures: " + buildingList.size() + " Maint: " + maintList.size() + " Derank: " + derankList.size()); Logger.info("Structures: " + buildingList.size() + " Maint: " + maintList.size() + " Derank: " + derankList.size());
} }
@ -98,6 +94,10 @@ public enum MaintenanceManager {
continue; continue;
} }
//only ToL pays maintenance
if(building.getBlueprint().getBuildingGroup() != null && !building.getBlueprint().getBuildingGroup().equals(Enum.BuildingGroup.TOL))
continue;
// No maintenance on banestones omfg // No maintenance on banestones omfg
if (building.getBlueprint().getBuildingGroup().equals(Enum.BuildingGroup.BANESTONE)) if (building.getBlueprint().getBuildingGroup().equals(Enum.BuildingGroup.BANESTONE))
@ -186,49 +186,8 @@ public enum MaintenanceManager {
// If this is an R8 tree, validate that we can // If this is an R8 tree, validate that we can
// cover the resources required // cover the resources required
if (building.getRank() == 8) {
hasResources = true;
if (warehouse == null)
hasResources = false;
else {
resourceValue = warehouse.getResources().get(Warehouse.stoneIB);
if (resourceValue < 1500)
hasResources = false;
resourceValue = warehouse.getResources().get(Warehouse.lumberIB);
if (resourceValue < 1500)
hasResources = false;
resourceValue = warehouse.getResources().get(Warehouse.galvorIB);
if (resourceValue < 5)
hasResources = false;
resourceValue = warehouse.getResources().get(Warehouse.wormwoodIB);
if (resourceValue < 5)
hasResources = false;
}
}
// Validation completed but has failed. We can derank
// the target building and early exit
if ((hasFunds == false) ||
((building.getRank() == 8) && !hasResources)) {
// Add cash back to strongbox for lost rank if the building isn't being destroyed
// and it's not an R8 deranking
if ((building.getRank() > 1) && (building.getRank() < 8)) {
building.setStrongboxValue(building.getStrongboxValue() + building.getBlueprint().getRankCost(Math.min(building.getRank(), 7)));
}
if (hasFunds == false) {
return false; // Early exit for having failed to meet maintenance return false; // Early exit for having failed to meet maintenance
} }
@ -253,58 +212,6 @@ public enum MaintenanceManager {
} }
} }
// Early exit as we're done if we're not an R8 tree
if (building.getRank() < 8)
return true;
// Now for the resources if it's an R8 tree
// Withdraw Stone
resourceValue = warehouse.getResources().get(Warehouse.stoneIB);
if (DbManager.WarehouseQueries.updateStone(warehouse, resourceValue - 1500) == true) {
warehouse.getResources().put(Warehouse.stoneIB, resourceValue - 1500);
warehouse.AddTransactionToWarehouse(Enum.GameObjectType.Building, building.getObjectUUID(), Enum.TransactionType.WITHDRAWL, Resource.STONE, 1500);
} else {
Logger.error("stone update failed for warehouse of UUID:" + warehouse.getObjectUUID());
return true;
}
// Withdraw Lumber
resourceValue = warehouse.getResources().get(Warehouse.lumberIB);
if (DbManager.WarehouseQueries.updateLumber(warehouse, resourceValue - 1500) == true) {
warehouse.getResources().put(Warehouse.lumberIB, resourceValue - 1500);
warehouse.AddTransactionToWarehouse(Enum.GameObjectType.Building, building.getObjectUUID(), Enum.TransactionType.WITHDRAWL, Resource.LUMBER, 1500);
} else {
Logger.error("lumber update failed for warehouse of UUID:" + warehouse.getObjectUUID());
return true;
}
// Withdraw Galvor
resourceValue = warehouse.getResources().get(Warehouse.galvorIB);
if (DbManager.WarehouseQueries.updateGalvor(warehouse, resourceValue - 5) == true) {
warehouse.getResources().put(Warehouse.galvorIB, resourceValue - 5);
warehouse.AddTransactionToWarehouse(Enum.GameObjectType.Building, building.getObjectUUID(), Enum.TransactionType.WITHDRAWL, Resource.GALVOR, 5);
} else {
Logger.error("galvor update failed for warehouse of UUID:" + warehouse.getObjectUUID());
return true;
}
resourceValue = warehouse.getResources().get(Warehouse.wormwoodIB);
if (DbManager.WarehouseQueries.updateWormwood(warehouse, resourceValue - 5) == true) {
warehouse.getResources().put(Warehouse.wormwoodIB, resourceValue - 5);
warehouse.AddTransactionToWarehouse(Enum.GameObjectType.Building, building.getObjectUUID(), Enum.TransactionType.WITHDRAWL, Resource.WORMWOOD, 5);
} else {
Logger.error("wyrmwood update failed for warehouse of UUID:" + warehouse.getObjectUUID());
}
return true; return true;
} }

4
src/engine/gameManager/NPCManager.java

@ -340,8 +340,8 @@ public enum NPCManager {
else else
buildingSlot = BuildingManager.getAvailableSlot(abstractCharacter.building); buildingSlot = BuildingManager.getAvailableSlot(abstractCharacter.building);
if (buildingSlot == -1) //if (buildingSlot == -1)
Logger.error("No available slot for NPC: " + abstractCharacter.getObjectUUID()); //Logger.error("No available slot for NPC: " + abstractCharacter.getObjectUUID());
abstractCharacter.building.getHirelings().put(abstractCharacter, buildingSlot); abstractCharacter.building.getHirelings().put(abstractCharacter, buildingSlot);

181
src/engine/gameManager/PowersManager.java

@ -8,6 +8,7 @@
package engine.gameManager; package engine.gameManager;
import com.sun.corba.se.spi.orbutil.fsm.ActionBase;
import engine.Enum.*; import engine.Enum.*;
import engine.InterestManagement.HeightMap; import engine.InterestManagement.HeightMap;
import engine.InterestManagement.WorldGrid; import engine.InterestManagement.WorldGrid;
@ -27,6 +28,7 @@ import engine.net.client.ClientConnection;
import engine.net.client.msg.*; import engine.net.client.msg.*;
import engine.objects.*; import engine.objects.*;
import engine.powers.*; import engine.powers.*;
import engine.powers.effectmodifiers.AbstractEffectModifier;
import engine.powers.poweractions.AbstractPowerAction; import engine.powers.poweractions.AbstractPowerAction;
import engine.powers.poweractions.TrackPowerAction; import engine.powers.poweractions.TrackPowerAction;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
@ -205,6 +207,41 @@ public enum PowersManager {
boolean CSRCast = false; boolean CSRCast = false;
if(msg.getPowerUsedID() == 430628895) {
boolean failed = false;// group teleport
City city = ZoneManager.getCityAtLocation(playerCharacter.loc);
if (city == null) {
failed = true;
}else{
Bane bane = city.getBane();
if (bane == null) {
failed = true;
}else{
if(!bane.getSiegePhase().equals(SiegePhase.WAR)){
failed = true;
}
}
}
if(failed){
//check to see if we are at an active mine
Zone zone = ZoneManager.findSmallestZone(playerCharacter.loc);
if(zone != null){
Mine mine = null;
for(Building building : zone.zoneBuildingSet){
if(building.getBlueprint().getBuildingGroup().equals(BuildingGroup.MINE)){
mine = Mine.getMineFromTower(building.getObjectUUID());
}
}
if(mine != null){
failed = !mine.isActive;
}
}
}
if(failed)
return false;
}
if (MBServerStatics.POWERS_DEBUG) { if (MBServerStatics.POWERS_DEBUG) {
ChatManager.chatSayInfo( ChatManager.chatSayInfo(
@ -241,6 +278,7 @@ public enum PowersManager {
// get power // get power
PowersBase pb = PowersManager.powersBaseByToken.get(msg.getPowerUsedID()); PowersBase pb = PowersManager.powersBaseByToken.get(msg.getPowerUsedID());
if (pb == null) { if (pb == null) {
ChatManager.chatSayInfo(playerCharacter, ChatManager.chatSayInfo(playerCharacter,
"This power is not implemented yet."); "This power is not implemented yet.");
@ -252,6 +290,35 @@ public enum PowersManager {
// return false; // return false;
} }
//check for movement buffs while flying
if(playerCharacter.isFlying()) {
switch(pb.token){
case 429005674:
case 429505739:
case 431054700:
case 428005600:
case 431610080:
case 427935608:
case 427857146:
case 427988218:
case 431854842:
case 421074170:
case 429611355:
case 428955899:
case 1794395699:
case 429428796:
case 1514898036:
ChatManager.chatSystemInfo(playerCharacter, "You Cannot Fly While Having A MovementBuff");
//resync stamina
playerCharacter.setStamina(playerCharacter.getStamina(), playerCharacter);
// Update all surrounding clients.
TargetedActionMsg cmm = new TargetedActionMsg(playerCharacter);
DispatchMessage.dispatchMsgToInterestArea(playerCharacter, cmm, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
return true;
}
}
if (playerCharacter.getLastPower() != null) if (playerCharacter.getLastPower() != null)
return true; return true;
@ -279,6 +346,12 @@ public enum PowersManager {
msg.setNumTrains(trains); msg.setNumTrains(trains);
} }
switch(pb.token){
case 429420458: // BH eyes
msg.setNumTrains(msg.getNumTrains() * 2);
break;
}
// can't go over total trains by player // can't go over total trains by player
if (playerCharacter.getPowers() != null && playerCharacter.getPowers().containsKey(msg.getPowerUsedID())) { if (playerCharacter.getPowers() != null && playerCharacter.getPowers().containsKey(msg.getPowerUsedID())) {
CharacterPower cp = playerCharacter.getPowers().get(msg.getPowerUsedID()); CharacterPower cp = playerCharacter.getPowers().get(msg.getPowerUsedID());
@ -370,15 +443,20 @@ public enum PowersManager {
float range = pb.getRange(); float range = pb.getRange();
// verify target is in range // verify target is in range
if(pb.token != 429396028) {
if (verifyInvalidRange(playerCharacter, target, range)) if (verifyInvalidRange(playerCharacter, target, range))
// (pc.getLoc().distance(target.getLoc()) > pb.getRange()) { // (pc.getLoc().distance(target.getLoc()) > pb.getRange()) {
// TODO send message that target is out of range // TODO send message that target is out of range
return true; return true;
// verify target is valid type
// verify target is valid type
if (!validateTarget(target, playerCharacter, pb)) if (!validateTarget(target, playerCharacter, pb))
return true; return true;
}else{
pb.isSpell = false;
}
if (AbstractWorldObject.IsAbstractCharacter(target)) if (AbstractWorldObject.IsAbstractCharacter(target))
@ -487,7 +565,6 @@ public enum PowersManager {
// Validity checks passed, move on to casting spell // Validity checks passed, move on to casting spell
//get caster's live counter //get caster's live counter
int casterLiveCounter = playerCharacter.getLiveCounter(); int casterLiveCounter = playerCharacter.getLiveCounter();
// run recycle job for when cast is available again, don't bother adding the timer for CSRs // run recycle job for when cast is available again, don't bother adding the timer for CSRs
if (time > 0) { if (time > 0) {
FinishRecycleTimeJob frtj = new FinishRecycleTimeJob(playerCharacter, msg); FinishRecycleTimeJob frtj = new FinishRecycleTimeJob(playerCharacter, msg);
@ -522,7 +599,9 @@ public enum PowersManager {
} }
// update cast (use skill) fail condition // update cast (use skill) fail condition
if(pb.token != 429396028) {
playerCharacter.cancelOnCast(); playerCharacter.cancelOnCast();
}
// update castSpell (use spell) fail condition if spell // update castSpell (use spell) fail condition if spell
if (pb.isSpell()) if (pb.isSpell())
@ -541,7 +620,6 @@ public enum PowersManager {
playerCharacter.setLastMovementState(playerCharacter.getMovementState()); playerCharacter.setLastMovementState(playerCharacter.getMovementState());
// run timer job to end cast // run timer job to end cast
if (time < 1) // run immediately if (time < 1) // run immediately
finishUsePower(copyMsg, playerCharacter, casterLiveCounter, targetLiveCounter); finishUsePower(copyMsg, playerCharacter, casterLiveCounter, targetLiveCounter);
@ -706,6 +784,13 @@ public enum PowersManager {
if (playerCharacter == null || msg == null) if (playerCharacter == null || msg == null)
return; return;
if((msg.getPowerUsedID() == 429495514 || msg.getPowerUsedID() == 429407306) && playerCharacter.getRace().getName().toLowerCase().contains("shade")){
//msg.setPowerUsedID(407015607);
applyPower(playerCharacter,playerCharacter,playerCharacter.loc,429397210,msg.getNumTrains(),false);
}
if(msg.getPowerUsedID() == 429494441) {//wildkins chase
playerCharacter.removeEffectBySource(EffectSourceType.Root,40,true);
}
if (playerCharacter.isCasting()) { if (playerCharacter.isCasting()) {
playerCharacter.update(); playerCharacter.update();
playerCharacter.updateStamRegen(-100); playerCharacter.updateStamRegen(-100);
@ -809,6 +894,7 @@ public enum PowersManager {
} }
float range = pb.getRange() + speedRange; float range = pb.getRange() + speedRange;
if(pb.token != 429396028) {
if (verifyInvalidRange(playerCharacter, mainTarget, range)) { if (verifyInvalidRange(playerCharacter, mainTarget, range)) {
@ -817,7 +903,7 @@ public enum PowersManager {
} }
// (pc.getLoc().distance(target.getLoc()) > pb.getRange()) { // (pc.getLoc().distance(target.getLoc()) > pb.getRange()) {
// TODO send message that target is out of range // TODO send message that target is out of range
}
} }
@ -1233,7 +1319,7 @@ public enum PowersManager {
PlayerCharacter target = SessionManager PlayerCharacter target = SessionManager
.getPlayerCharacterByLowerCaseName(msg.getTargetName()); .getPlayerCharacterByLowerCaseName(msg.getTargetName());
if (target == null || target.equals(pc) || target.isCombat()) { if (target == null || target.equals(pc)) {
if (target == null) // Player not found. Send not found message if (target == null) // Player not found. Send not found message
ChatManager.chatInfoError(pc, ChatManager.chatInfoError(pc,
@ -1337,6 +1423,16 @@ public enum PowersManager {
else else
duration = 45000; // Belgosh Summons, 45 seconds duration = 45000; // Belgosh Summons, 45 seconds
boolean enemiesNear = false;
for(AbstractWorldObject awo : WorldGrid.getObjectsInRangePartial(pc.loc,MBServerStatics.CHARACTER_LOAD_RANGE, MBServerStatics.MASK_PLAYER)){
PlayerCharacter playerCharacter = (PlayerCharacter)awo;
if(!playerCharacter.guild.getNation().equals(pc.guild.getNation())){
enemiesNear = true;
}
}
if(enemiesNear && !pc.isInSafeZone())
duration += 60000;
// Teleport to summoners location // Teleport to summoners location
FinishSummonsJob fsj = new FinishSummonsJob(source, pc); FinishSummonsJob fsj = new FinishSummonsJob(source, pc);
@ -1462,8 +1558,17 @@ public enum PowersManager {
} }
// create list of characters // create list of characters
HashSet<AbstractCharacter> trackChars = RangeBasedAwo.getTrackList( HashSet<AbstractCharacter> trackChars;
allTargets, playerCharacter, maxTargets); switch(msg.getPowerToken()){
case 431511776:
case 429578587:
case 429503360:
trackChars = getTrackList(playerCharacter);
break;
default:
trackChars = RangeBasedAwo.getTrackList(allTargets, playerCharacter, maxTargets);
break;
}
TrackWindowMsg trackWindowMsg = new TrackWindowMsg(msg); TrackWindowMsg trackWindowMsg = new TrackWindowMsg(msg);
@ -1476,6 +1581,30 @@ public enum PowersManager {
} }
public static HashSet<AbstractCharacter> getTrackList(PlayerCharacter tracker){
HashSet<AbstractCharacter> list = new HashSet<AbstractCharacter>();
HashSet<AbstractWorldObject> shortList = WorldGrid.getObjectsInRangePartial(tracker.loc,MBServerStatics.CHARACTER_LOAD_RANGE, MBServerStatics.MASK_PLAYER);
HashSet<AbstractWorldObject> fullList = WorldGrid.getObjectsInRangePartial(tracker.loc,1408, MBServerStatics.MASK_PLAYER);
ArrayList<Guild> guildsPresent = new ArrayList<>();
for(AbstractWorldObject awo : shortList){
PlayerCharacter pc = (PlayerCharacter)awo;
if(!guildsPresent.contains(pc.guild.getNation())){
guildsPresent.add(pc.guild.getNation());
}
}
for(AbstractWorldObject awo : fullList){
if(awo.equals(tracker))
continue;
PlayerCharacter pc = (PlayerCharacter)awo;
if(!pc.isAlive())
continue;
if(guildsPresent.contains(pc.guild.getNation()))
list.add(pc);
}
return list;
}
private static void sendRecyclePower(int token, ClientConnection origin) { private static void sendRecyclePower(int token, ClientConnection origin) {
RecyclePowerMsg recyclePowerMsg = new RecyclePowerMsg(token); RecyclePowerMsg recyclePowerMsg = new RecyclePowerMsg(token);
@ -2241,28 +2370,26 @@ public enum PowersManager {
defense = 0f; defense = 0f;
// Get hit chance // Get hit chance
if (pc.getDebug(16)) { //if (pc.getDebug(16)) {
String smsg = "ATR: " + atr + ", Defense: " + defense; // String smsg = "ATR: " + atr + ", Defense: " + defense;
ChatManager.chatSystemInfo(pc, smsg); // ChatManager.chatSystemInfo(pc, smsg);
} //}
int chance; //int chance;
if (atr > defense || defense == 0) //if (atr > defense || defense == 0)
chance = 94; // chance = 94;
else { //else {
float dif = atr / defense; // float dif = atr / defense;
if (dif <= 0.8f) // if (dif <= 0.8f)
chance = 4; // chance = 4;
else // else
chance = ((int) (450 * (dif - 0.8f)) + 4); // chance = ((int) (450 * (dif - 0.8f)) + 4);
} //}
// calculate hit/miss // calculate hit/miss
int roll = ThreadLocalRandom.current().nextInt(100);
boolean disable = true; if (CombatManager.LandHit((int)atr,(int)defense)) {
if (roll < chance) {
// Hit, check if dodge kicked in // Hit, check if dodge kicked in
if (awo instanceof AbstractCharacter) { if (awo instanceof AbstractCharacter) {
AbstractCharacter tarAc = (AbstractCharacter) awo; AbstractCharacter tarAc = (AbstractCharacter) awo;
@ -2562,7 +2689,9 @@ public enum PowersManager {
} }
public static void cancelOnStun(AbstractCharacter ac) { public static void cancelOnStun(AbstractCharacter ac) {
if(ac.getObjectType().equals(GameObjectType.PlayerCharacter)){
PlayerCharacter.GroundPlayer((PlayerCharacter)ac);
}
} }
private static PowersBase getLastPower(AbstractCharacter ac) { private static PowersBase getLastPower(AbstractCharacter ac) {

17
src/engine/gameManager/SimulationManager.java

@ -10,10 +10,7 @@ package engine.gameManager;
import engine.Enum; import engine.Enum;
import engine.Enum.GameObjectType; import engine.Enum.GameObjectType;
import engine.objects.AbstractGameObject; import engine.objects.*;
import engine.objects.City;
import engine.objects.PlayerCharacter;
import engine.objects.Runegate;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
import java.sql.Connection; import java.sql.Connection;
@ -33,7 +30,7 @@ public enum SimulationManager {
SERVERHEARTBEAT; SERVERHEARTBEAT;
private static final long CITY_PULSE = 2000; private static final long CITY_PULSE = 2000;
private static final long RUNEGATE_PULSE = 3000; private static final long RUNEGATE_PULSE = 1000;
private static final long UPDATE_PULSE = 1000; private static final long UPDATE_PULSE = 1000;
private static final long FlIGHT_PULSE = 100; private static final long FlIGHT_PULSE = 100;
public static Duration executionTime = Duration.ofNanos(1); public static Duration executionTime = Duration.ofNanos(1);
@ -203,8 +200,12 @@ public enum SimulationManager {
city = (City) cityObject; city = (City) cityObject;
city.onEnter(); city.onEnter();
} }
for(Mine mine : Mine.getMines()){
if(mine != null && mine.isActive)
mine.onEnter();
}
_cityPulseTime = System.currentTimeMillis() + CITY_PULSE; _cityPulseTime = System.currentTimeMillis() + CITY_PULSE;
} }
/* /*
@ -214,6 +215,10 @@ public enum SimulationManager {
private void pulseRunegates() { private void pulseRunegates() {
for (Runegate runegate : Runegate._runegates.values()) { for (Runegate runegate : Runegate._runegates.values()) {
for(Portal portal : runegate._portals)
if(!portal.isActive())
portal.activate(false);
runegate.collidePortals(); runegate.collidePortals();
} }

347
src/engine/gameManager/StrongholdManager.java

@ -0,0 +1,347 @@
package engine.gameManager;
import engine.Enum;
import engine.InterestManagement.InterestManager;
import engine.InterestManagement.WorldGrid;
import engine.math.Vector3f;
import engine.math.Vector3fImmutable;
import engine.objects.*;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ThreadLocalRandom;
public class StrongholdManager {
public static void processStrongholds() {
ArrayList<Mine> mines = Mine.getMines();
//process strongholds selecting 3 randomly to become active
int count = 0;
while (count < 3) {
int random = ThreadLocalRandom.current().nextInt(1, mines.size()) - 1;
Mine mine = mines.get(random);
if (mine != null) {
if (!mine.isActive && !mine.isStronghold) {
StartStronghold(mine);
count++;
}
}
}
}
public static void StartStronghold(Mine mine){
//remove buildings
Building tower = BuildingManager.getBuilding(mine.getBuildingID());
if(tower == null)
return;
mine.isStronghold = true;
mine.strongholdMobs = new ArrayList<>();
mine.oldBuildings = new HashMap<>();
Zone mineZone = ZoneManager.findSmallestZone(tower.loc);
for(Building building : mineZone.zoneBuildingSet){
mine.oldBuildings.put(building.getObjectUUID(),building.meshUUID);
building.setMeshUUID(407650);
building.setMeshScale(new Vector3f(0,0,0));
InterestManager.setObjectDirty(building);
WorldGrid.updateObject(building);
}
//update tower to become stronghold mesh
tower.setMeshUUID(getStrongholdMeshID(mine.getParentZone()));
tower.setMeshScale(new Vector3f(1,1,1));
InterestManager.setObjectDirty(tower);
WorldGrid.updateObject(tower);
//create elite mobs
for(int i = 0; i < mine.capSize * 2; i++){
Vector3fImmutable loc = Vector3fImmutable.getRandomPointOnCircle(tower.loc,30);
MobBase guardBase = MobBase.getMobBase(getStrongholdGuardianID(tower.meshUUID));
Mob guard = Mob.createStrongholdMob(guardBase.getLoadID(), loc, Guild.getErrantGuild(),true,mineZone,null,0, guardBase.getFirstName(),65);
if(guard != null){
guard.parentZone = mine.getParentZone();
guard.bindLoc = loc;
guard.setLoc(loc);
guard.StrongholdGuardian = true;
guard.equipmentSetID = getStrongholdMobEquipSetID(guard);
guard.runAfterLoad();
guard.setLevel((short)65);
guard.setResists(new Resists("Elite"));
guard.spawnTime = 1000000000;
guard.BehaviourType = Enum.MobBehaviourType.Aggro;
mine.strongholdMobs.add(guard);
LootManager.GenerateStrongholdLoot(guard,false,false);
guard.healthMax = 12500;
guard.setHealth(guard.healthMax);
guard.maxDamageHandOne = 1550;
guard.minDamageHandOne = 750;
guard.atrHandOne = 1800;
guard.defenseRating = 2200;
guard.setFirstName("Elite Guardian");
InterestManager.setObjectDirty(guard);
WorldGrid.addObject(guard,loc.x,loc.z);
WorldGrid.updateObject(guard);
guard.stronghold = mine;
guard.mobPowers.clear();
guard.mobPowers.put(429399948,20); // find weakness
}
}
//create stronghold commander
Vector3fImmutable loc = tower.loc;
MobBase commanderBase = MobBase.getMobBase(getStrongholdCommanderID(tower.meshUUID));
Mob commander = Mob.createStrongholdMob(commanderBase.getLoadID(), loc,Guild.getErrantGuild(),true,mineZone,null,0, commanderBase.getFirstName(),75);
if(commander != null){
commander.parentZone = mine.getParentZone();
commander.bindLoc = loc;
commander.setLoc(loc);
commander.StrongholdCommander = true;
commander.equipmentSetID = getStrongholdMobEquipSetID(commander);
commander.runAfterLoad();
commander.setLevel((short)75);
commander.setResists(new Resists("Elite"));
commander.spawnTime = 1000000000;
commander.BehaviourType = Enum.MobBehaviourType.Aggro;
commander.mobPowers.clear();
commander.mobPowers.put(429032838, 40); // gravechill
commander.mobPowers.put(429757701,20); // magebolt
commander.mobPowers.put(429121388,20); // blight
commander.mobPowers.put(431566891,20); // lightning bolt
commander.mobPowers.put(428716075,20); // fire bolt
commander.mobPowers.put(429010987,20); // ice bolt
mine.strongholdMobs.add(commander);
LootManager.GenerateStrongholdLoot(commander,true, false);
commander.healthMax = 50000;
commander.setHealth(commander.healthMax);
commander.maxDamageHandOne = 3500;
commander.minDamageHandOne = 1500;
commander.atrHandOne = 3500;
commander.defenseRating = 3500;
commander.setFirstName("Guardian Commander");
InterestManager.setObjectDirty(commander);
WorldGrid.addObject(commander,loc.x,loc.z);
WorldGrid.updateObject(commander);
commander.stronghold = mine;
}
mine.isActive = true;
tower.setProtectionState(Enum.ProtectionState.PROTECTED);
tower.getBounds().setRegions(tower);
InterestManager.setObjectDirty(tower);
WorldGrid.updateObject(tower);
ChatManager.chatSystemChannel(mine.getZoneName() + "'s Stronghold Has Begun!");
Logger.info(mine.getZoneName() + "'s Stronghold Has Begun!");
}
public static void EndStronghold(Mine mine){
//restore the buildings
Building tower = BuildingManager.getBuilding(mine.getBuildingID());
if(tower == null)
return;
mine.isStronghold = false;
//get rid of the mobs
for(Mob mob : mine.strongholdMobs) {
mob.despawn();
mob.removeFromCache();
DbManager.MobQueries.DELETE_MOB(mob);
}
//restore the buildings
Zone mineZone = ZoneManager.findSmallestZone(tower.loc);
for(Building building : mineZone.zoneBuildingSet){
if(mine.oldBuildings.containsKey(building.getObjectUUID())) {
building.setMeshUUID(mine.oldBuildings.get(building.getObjectUUID()));
building.setMeshScale(new Vector3f(1, 1, 1));
InterestManager.setObjectDirty(building);
WorldGrid.updateObject(building);
}
}
//update tower to become Mine Tower again
tower.setMeshUUID(1500100);
mine.isActive = false;
tower.setProtectionState(Enum.ProtectionState.NPC);
tower.getBounds().setRegions(tower);
InterestManager.setObjectDirty(tower);
WorldGrid.updateObject(tower);
ChatManager.chatSystemChannel(mine.getZoneName() + "'s Stronghold Has Concluded!");
Logger.info(mine.getZoneName() + "'s Stronghold Has Concluded!");
}
public static int getStrongholdMeshID(Zone parent){
while(!parent.isMacroZone()){
parent = parent.getParent();
if(parent.getName().equalsIgnoreCase("seafloor")){
return 0;
}
}
switch(parent.getObjectUUID()){
case 197:
case 234:
case 178:
case 122:
return 814000; //Frost Giant Hall (ICE)
case 968:
case 951:
case 313:
case 331:
return 5001500; // Lich Queens Keep (UNDEAD)
case 785:
case 761:
case 717:
case 737:
return 1306600; // Temple of the Dragon (DESERT)
case 353:
case 371:
case 388:
case 532:
return 564600; // Undead Lord's Keep (SWAMP)
case 550:
case 508:
case 475:
case 418:
return 1326600; // elven hall
case 437:
case 491:
case 590:
case 569:
return 602400;
case 824:
case 842:
case 632:
return 1600000; // chaos temple
}
return 456100; // small stockade
}
public static int getStrongholdGuardianID(int ID){
switch(ID){
case 814000:
return 253004; // Mountain Giant Raider Axe
case 5001500:
return 253008; // Vampire Spear Warrior
case 1306600:
return 253007; // Desert Orc Warrior
case 564600:
return 253010; // Kolthoss Warrior
case 1326600:
return 253005; //elven warrior
case 602400:
return 253009; // templar missionary
case 1600000:
return 253006; // scourger
}
return 13434; // human sword and board warrior
}
public static int getStrongholdEpicID(int ID){
switch(ID){
case 814000:
return 253023; // Mountain Giant Raider Axe
case 5001500:
return 253022; // Vampire Spear Warrior
case 1306600:
return 253021; // Desert Orc Warrior
case 564600:
return 253018; // Kolthoss Warrior
case 1326600:
return 253019; //elven warrior
case 602400:
return 253024; // templar missionary
case 1600000:
return 253020; // scourger
}
return 13434; // human sword and board warrior
}
public static int getStrongholdCommanderID(int ID){
switch(ID){
case 814000:
return 253017;
case 5001500:
return 253012;
case 1306600:
return 253016; // Desert Orc Xbow
case 564600:
return 253011; // xbow kolthoss
case 1326600:
return 253013; //elven bow warrior
case 602400:
return 253015; // dune giant with xbow
case 1600000:
return 253014; // barbator
}
return 13433;
}
public static int getStrongholdMobEquipSetID(Mob mob) {
if(mob.StrongholdGuardian){
return 6327;
}else{
return 10790;
}
}
public static void CheckToEndStronghold(Mine mine) {
boolean stillAlive = false;
for (Mob mob : mine.strongholdMobs)
if (mob.isAlive())
stillAlive = true;
if (!stillAlive) {
// Epic encounter
Building tower = BuildingManager.getBuilding(mine.getBuildingID());
if (tower == null)
return;
Zone mineZone = ZoneManager.findSmallestZone(tower.loc);
Vector3fImmutable loc = tower.loc;
MobBase commanderBase = MobBase.getMobBase(getStrongholdEpicID(tower.meshUUID));
Mob commander = Mob.createStrongholdMob(commanderBase.getLoadID(), loc, Guild.getErrantGuild(), true, mineZone, null, 0, commanderBase.getFirstName(), 75);
if (commander != null) {
commander.parentZone = mine.getParentZone();
commander.bindLoc = loc;
commander.setLoc(loc);
commander.StrongholdEpic = true;
commander.equipmentSetID = getStrongholdMobEquipSetID(commander);
commander.runAfterLoad();
commander.setLevel((short) 85);
commander.setResists(new Resists("Elite"));
commander.spawnTime = 1000000000;
commander.BehaviourType = Enum.MobBehaviourType.Aggro;
commander.mobPowers.clear();
commander.mobPowers.put(429032838, 40); // gravechill
commander.mobPowers.put(429757701,40); // magebolt
commander.mobPowers.put(429121388,40); // blight
commander.mobPowers.put(431566891,40); // lightning bolt
commander.mobPowers.put(428716075,40); // fire bolt
commander.mobPowers.put(429010987,40); // ice bolt
mine.strongholdMobs.add(commander);
LootManager.GenerateStrongholdLoot(commander, true, true);
commander.healthMax = 250000;
commander.setHealth(commander.healthMax);
commander.maxDamageHandOne = 5000;
commander.minDamageHandOne = 2500;
commander.atrHandOne = 5000;
commander.defenseRating = 3500;
commander.setFirstName("Defender of " + mine.getParentZone().getParent().getName());
InterestManager.setObjectDirty(commander);
WorldGrid.addObject(commander,loc.x,loc.z);
WorldGrid.updateObject(commander);
commander.stronghold = mine;
}
}
}
}

92
src/engine/gameManager/ZergManager.java

@ -0,0 +1,92 @@
package engine.gameManager;
import engine.objects.Guild;
public class ZergManager {
public static float getCurrentMultiplier(int count, int maxCount){
switch(maxCount) {
case 3:
return getMultiplier3Man(count);
case 5:
return getMultiplier5Man(count);
case 10:
return getMultiplier10Man(count);
default:
return getMultiplier20Man(count);
}
}
public static float getMultiplier3Man(int count) {
if(count < 4)
return 1.0f;
if(count > 6)
return 0.0f;
switch(count){
case 4:
return 0.75f;
case 5:
return 0.60f;
case 6:
return 0.37f;
}
return 1.0f;
}
public static float getMultiplier5Man(int count) {
if(count < 6)
return 1.0f;
if(count > 10)
return 0.0f;
switch(count){
case 6:
return 0.75f;
case 7:
return 0.67f;
case 8:
return 0.56f;
case 9:
return 0.43f;
case 10:
return 0.25f;
}
return 1.0f;
}
public static float getMultiplier10Man(int count) {
if(count < 11)
return 1.0f;
if(count > 20)
return 0.0f;
switch(count){
case 11:
return 0.75f;
case 12:
return 0.71f;
case 13:
return 0.67f;
case 14:
return 0.62f;
case 15:
return 0.56f;
case 16:
return 0.50f;
case 17:
return 0.43f;
case 18:
return 0.35f;
case 19:
return 0.25f;
case 20:
return 0.14f;
}
return 1.0f;
}
public static float getMultiplier20Man(int count) {
return getMultiplier10Man(count * 2);
}
}

73
src/engine/gameManager/ZoneManager.java

@ -19,14 +19,12 @@ import engine.objects.Building;
import engine.objects.City; import engine.objects.City;
import engine.objects.Zone; import engine.objects.Zone;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
/* /*
* Class contains methods and structures which * Class contains methods and structures which
@ -109,20 +107,6 @@ public enum ZoneManager {
} }
// Returns the number of available hotZones
// remaining in this cycle (1am)
public static int availableHotZones() {
int count = 0;
for (Zone zone : ZoneManager.macroZones)
if (ZoneManager.validHotZone(zone))
count = count + 1;
return count;
}
// Resets the availability of hotZones // Resets the availability of hotZones
// for this cycle // for this cycle
@ -217,63 +201,6 @@ public enum ZoneManager {
ZoneManager.playerCityZones.add(zone); ZoneManager.playerCityZones.add(zone);
} }
public static final void generateAndSetRandomHotzone() {
Zone hotZone;
ArrayList<Integer> zoneArray = new ArrayList<>();
if (ZoneManager.macroZones.isEmpty())
return;
// Reset hotZone availability if none are left.
if (ZoneManager.availableHotZones() == 0)
ZoneManager.resetHotZones();
for (Zone zone : ZoneManager.macroZones)
if (validHotZone(zone))
zoneArray.add(zone.getObjectUUID());
int entryIndex = ThreadLocalRandom.current().nextInt(zoneArray.size());
hotZone = ZoneManager.getZoneByUUID(zoneArray.get(entryIndex));
if (hotZone == null) {
Logger.error("Hotzone is null");
return;
}
ZoneManager.setHotZone(hotZone);
}
public static final boolean validHotZone(Zone zone) {
if (zone.getSafeZone() == (byte) 1)
return false; // no safe zone hotzones// if (this.hotzone == null)
if (zone.getNodes().isEmpty())
return false;
if (zone.equals(ZoneManager.seaFloor))
return false;
//no duplicate hotZones
if (zone.hasBeenHotzone == true)
return false;
// Enforce min level
if (zone.minLvl < Integer.parseInt(ConfigManager.MB_HOTZONE_MIN_LEVEL.getValue()))
return false;
if (ZoneManager.hotZone != null)
return ZoneManager.hotZone.getObjectUUID() != zone.getObjectUUID();
return true;
}
// Converts world coordinates to coordinates local to a given zone. // Converts world coordinates to coordinates local to a given zone.
public static Vector3fImmutable worldToLocal(Vector3fImmutable worldVector, public static Vector3fImmutable worldToLocal(Vector3fImmutable worldVector,

10
src/engine/jobs/FinishSummonsJob.java

@ -47,13 +47,13 @@ public class FinishSummonsJob extends AbstractScheduleJob {
return; return;
// cannot summon a player in combat // cannot summon a player in combat
if (this.target.isCombat()) { //if (this.target.isCombat()) {
ErrorPopupMsg.sendErrorMsg(this.source, "Cannot summon player in combat."); // ErrorPopupMsg.sendErrorMsg(this.source, "Cannot summon player in combat.");
PowersManager.finishRecycleTime(428523680, this.source, false); // PowersManager.finishRecycleTime(428523680, this.source, false);
return; // return;
} //}
if (this.target.getBonuses() != null && this.target.getBonuses().getBool(ModType.BlockedPowerType, SourceType.SUMMON)) { if (this.target.getBonuses() != null && this.target.getBonuses().getBool(ModType.BlockedPowerType, SourceType.SUMMON)) {
ErrorPopupMsg.sendErrorMsg(this.target, "You have been blocked from receiving summons!"); ErrorPopupMsg.sendErrorMsg(this.target, "You have been blocked from receiving summons!");

18
src/engine/loot/ItemTableEntry.java

@ -9,10 +9,12 @@
package engine.loot; package engine.loot;
import engine.gameManager.LootManager; import engine.gameManager.LootManager;
import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class ItemTableEntry { public class ItemTableEntry {
public int minRoll; public int minRoll;
@ -35,11 +37,23 @@ public class ItemTableEntry {
List<ItemTableEntry> itemTableEntryList; List<ItemTableEntry> itemTableEntryList;
itemTableEntryList = LootManager._itemTables.get(itemTable); itemTableEntryList = LootManager._itemTables.get(itemTable);
if(itemTableEntryList != null) {
for (ItemTableEntry iteration : itemTableEntryList) for (ItemTableEntry iteration : itemTableEntryList)
if (roll >= iteration.minRoll && roll <= iteration.maxRoll) if (roll >= iteration.minRoll && roll <= iteration.maxRoll)
itemTableEntry = iteration; itemTableEntry = iteration;
}
return itemTableEntry; return itemTableEntry;
} }
public static Integer getRandomItem(int itemTable) {
int id = 0;
List<ItemTableEntry> itemTableEntryList;
itemTableEntryList = LootManager._itemTables.get(itemTable);
if(itemTableEntryList != null && itemTableEntryList.size() > 1){
id = itemTableEntryList.get(ThreadLocalRandom.current().nextInt(0,itemTableEntryList.size() - 1)).cacheID;
}
return id;
}
} }

4
src/engine/loot/ModTableEntry.java

@ -33,11 +33,11 @@ public class ModTableEntry {
List<ModTableEntry> itemTableEntryList; List<ModTableEntry> itemTableEntryList;
itemTableEntryList = LootManager._modTables.get(modTablwe); itemTableEntryList = LootManager._modTables.get(modTablwe);
if(itemTableEntryList != null) {
for (ModTableEntry iteration : itemTableEntryList) for (ModTableEntry iteration : itemTableEntryList)
if (roll >= iteration.minRoll && roll <= iteration.maxRoll) if (roll >= iteration.minRoll && roll <= iteration.maxRoll)
modTableEntry = iteration; modTableEntry = iteration;
}
return modTableEntry; return modTableEntry;
} }
} }

62
src/engine/mobileAI/MobAI.java

@ -82,6 +82,16 @@ public class MobAI {
mob.updateLocation(); mob.updateLocation();
if(mob.StrongholdGuardian || mob.StrongholdEpic){
// attempt to ground all players in attack range
for(int i : mob.playerAgroMap.keySet()){
PlayerCharacter tar = PlayerCharacter.getFromCache(i);
if(tar != null && tar.loc.distanceSquared(mob.loc) < 80){
PowersManager.applyPower(mob,tar,tar.loc, 111111,40,false);
}
}
}
} catch (Exception e) { } catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage()); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage());
} }
@ -195,11 +205,11 @@ public class MobAI {
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); mob.setLastAttackTime(System.currentTimeMillis() + attackDelay);
} }
if (mob.isSiege()) { //if (mob.isSiege()) {
PowerProjectileMsg ppm = new PowerProjectileMsg(mob, target); // PowerProjectileMsg ppm = new PowerProjectileMsg(mob, target);
ppm.setRange(50); // ppm.setRange(50);
DispatchMessage.dispatchMsgToInterestArea(mob, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); // DispatchMessage.dispatchMsgToInterestArea(mob, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
} //}
} catch (Exception e) { } catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding" + " " + e.getMessage()); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding" + " " + e.getMessage());
@ -400,7 +410,7 @@ public class MobAI {
PerformActionMsg msg; PerformActionMsg msg;
if (!mobPower.isHarmful() || mobPower.targetSelf) { if (!mob.StrongholdCommander && !mob.StrongholdEpic && (!mobPower.isHarmful() || mobPower.targetSelf)) {
PowersManager.useMobPower(mob, mob, mobPower, powerRank); PowersManager.useMobPower(mob, mob, mobPower, powerRank);
msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, mob); msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, mob);
} else { } else {
@ -625,9 +635,6 @@ public class MobAI {
//check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting //check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting
if (mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal())
CheckToSendMobHome(mob);
return; return;
} }
@ -646,7 +653,7 @@ public class MobAI {
return; return;
} }
if (mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal()) if(mob.isPet() == false && mob.isPlayerGuard == false)
CheckToSendMobHome(mob); CheckToSendMobHome(mob);
if (mob.getCombatTarget() != null) { if (mob.getCombatTarget() != null) {
@ -857,9 +864,7 @@ public class MobAI {
return; return;
} }
//No items in inventory. //No items in inventory.
} else { } else if (aiAgent.isHasLoot()) {
//Mob's Loot has been looted.
if (aiAgent.isHasLoot()) {
if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_ONCE_LOOTED) { if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_ONCE_LOOTED) {
aiAgent.despawn(); aiAgent.despawn();
aiAgent.deathTime = System.currentTimeMillis(); aiAgent.deathTime = System.currentTimeMillis();
@ -874,9 +879,15 @@ public class MobAI {
} }
} }
} }
} else if (System.currentTimeMillis() > (aiAgent.deathTime + (aiAgent.spawnTime * 1000))) {
if (Zone.respawnQue.contains(aiAgent) == false) { if(Mob.discDroppers.contains(aiAgent))
return;
if(aiAgent.StrongholdGuardian || aiAgent.StrongholdEpic || aiAgent.StrongholdCommander)
return;
if (System.currentTimeMillis() > (aiAgent.deathTime + (aiAgent.spawnTime * 1000L))) {
if (!Zone.respawnQue.contains(aiAgent)) {
Zone.respawnQue.add(aiAgent); Zone.respawnQue.add(aiAgent);
} }
} }
@ -912,6 +923,12 @@ public class MobAI {
private static void CheckToSendMobHome(Mob mob) { private static void CheckToSendMobHome(Mob mob) {
try { try {
if(mob.BehaviourType.equals(Enum.MobBehaviourType.Pet1)){
if(mob.loc.distanceSquared(mob.getOwner().loc) > 60 * 60)
mob.teleport(mob.getOwner().loc);
return;
}
if (mob.BehaviourType.isAgressive) { if (mob.BehaviourType.isAgressive) {
if (mob.isPlayerGuard()) { if (mob.isPlayerGuard()) {
@ -922,9 +939,6 @@ public class MobAI {
} }
} }
if (mob.getCombatTarget() != null && CombatUtilities.inRange2D(mob, mob.getCombatTarget(), MobAIThread.AI_BASE_AGGRO_RANGE * 0.5f))
return;
if (mob.isPlayerGuard() && !mob.despawned) { if (mob.isPlayerGuard() && !mob.despawned) {
City current = ZoneManager.getCityAtLocation(mob.getLoc()); City current = ZoneManager.getCityAtLocation(mob.getLoc());
@ -945,7 +959,7 @@ public class MobAI {
} }
} }
} }
} else if (MovementUtilities.inRangeOfBindLocation(mob) == false) { } else if (!MovementUtilities.inRangeOfBindLocation(mob)) {
PowersBase recall = PowersManager.getPowerByToken(-1994153779); PowersBase recall = PowersManager.getPowerByToken(-1994153779);
PowersManager.useMobPower(mob, mob, recall, 40); PowersManager.useMobPower(mob, mob, recall, 40);
@ -953,6 +967,7 @@ public class MobAI {
for (Entry playerEntry : mob.playerAgroMap.entrySet()) for (Entry playerEntry : mob.playerAgroMap.entrySet())
PlayerCharacter.getFromCache((int) playerEntry.getKey()).setHateValue(0); PlayerCharacter.getFromCache((int) playerEntry.getKey()).setHateValue(0);
mob.setCombatTarget(null);
} }
} catch (Exception e) { } catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckToSendMobHome" + " " + e.getMessage()); Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckToSendMobHome" + " " + e.getMessage());
@ -1006,7 +1021,7 @@ public class MobAI {
//dont scan self. //dont scan self.
if (mob.equals(awoMob) || (mob.agentType.equals(Enum.AIAgentType.GUARD)) == true) if (mob.equals(awoMob) || (mob.agentType.equals(Enum.AIAgentType.GUARD)) || (mob.agentType.equals(Enum.AIAgentType.PET)))
continue; continue;
Mob aggroMob = (Mob) awoMob; Mob aggroMob = (Mob) awoMob;
@ -1351,9 +1366,9 @@ public class MobAI {
return null; return null;
} }
public static void RecoverHealth(Mob mob){ public static void RecoverHealth(Mob mob) {
//recover health //recover health
try {
if (mob.getTimestamps().containsKey("HEALTHRECOVERED") == false) if (mob.getTimestamps().containsKey("HEALTHRECOVERED") == false)
mob.getTimestamps().put("HEALTHRECOVERED", System.currentTimeMillis()); mob.getTimestamps().put("HEALTHRECOVERED", System.currentTimeMillis());
@ -1367,5 +1382,8 @@ public class MobAI {
if (mob.getHealth() > mob.getHealthMax()) if (mob.getHealth() > mob.getHealthMax())
mob.setHealth(mob.getHealthMax()); mob.setHealth(mob.getHealthMax());
} }
} catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: RecoverHealth" + " " + e.getMessage());
}
} }
} }

25
src/engine/mobileAI/utilities/CombatUtilities.java

@ -139,37 +139,22 @@ public class CombatUtilities {
} }
public static boolean triggerDefense(Mob agent, AbstractWorldObject target) { public static boolean triggerDefense(Mob agent, AbstractWorldObject target) {
int defenseScore = 0; int defense = 0;
int attackScore = agent.getAtrHandOne(); int atr = agent.getAtrHandOne();
switch (target.getObjectType()) { switch (target.getObjectType()) {
case PlayerCharacter: case PlayerCharacter:
defenseScore = ((AbstractCharacter) target).getDefenseRating(); defense = ((AbstractCharacter) target).getDefenseRating();
break; break;
case Mob: case Mob:
Mob mob = (Mob) target; Mob mob = (Mob) target;
if (mob.isSiege()) if (mob.isSiege())
defenseScore = attackScore; defense = atr;
break; break;
case Building: case Building:
return false; return false;
} }
return CombatManager.LandHit(atr,defense);
int hitChance;
if (attackScore > defenseScore || defenseScore == 0)
hitChance = 94;
else if (attackScore == defenseScore && target.getObjectType() == GameObjectType.Mob)
hitChance = 10;
else {
float dif = attackScore / defenseScore;
if (dif <= 0.8f)
hitChance = 4;
else
hitChance = ((int) (450 * (dif - 0.8f)) + 4);
if (target.getObjectType() == GameObjectType.Building)
hitChance = 100;
}
return ThreadLocalRandom.current().nextInt(100) > hitChance;
} }
public static boolean triggerBlock(Mob agent, AbstractWorldObject ac) { public static boolean triggerBlock(Mob agent, AbstractWorldObject ac) {

8
src/engine/net/NetMsgFactory.java

@ -13,6 +13,8 @@ import engine.exception.FactoryBuildException;
import engine.gameManager.ChatManager; import engine.gameManager.ChatManager;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
import engine.net.client.Protocol; import engine.net.client.Protocol;
import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.PlaceAssetMsg;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -94,11 +96,9 @@ public class NetMsgFactory {
if (origin instanceof ClientConnection) { if (origin instanceof ClientConnection) {
PlayerCharacter player = ((ClientConnection) origin).getPlayerCharacter(); PlayerCharacter player = ((ClientConnection) origin).getPlayerCharacter();
if (player != null) { if (player != null) {
// if (MBServerStatics.worldServerName.equals("Grief"))
Logger.error("Invalid protocol msg for player " + player.getFirstName() + " : " + opcode + " lastopcode: " + origin.lastProtocol.name() + " Error Code : " + errorCode); Logger.error("Invalid protocol msg for player " + player.getFirstName() + " : " + opcode + " lastopcode: " + origin.lastProtocol.name() + " Error Code : " + errorCode);
} else PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "Please Report What You Just Did. Ref Code: " + opcode);
Logger.error("Invalid protocol msg : " + opcode + " lastopcode: " + origin.lastProtocol.name() + " Error Code : " + errorCode); }
} }
return null; return null;

203
src/engine/net/client/ClientMessagePump.java

@ -560,12 +560,30 @@ public class ClientMessagePump implements NetMsgHandler {
if (!itemManager.inventoryContains(i)) if (!itemManager.inventoryContains(i))
return; return;
if (i.isCanDestroy()) //cannot delete gold
if (itemManager.delete(i) == true) { if(i.getItemBaseID() == 7)
return;
if (i.isCanDestroy()) {
int goldValue = i.getBaseValue();
if (i.getItemBase().isRune())
goldValue = 500000;
if (i.getItemBaseID() == 980066)
goldValue = 0;
if(itemManager.getGoldInventory().getNumOfItems() + goldValue > 10000000)
return;
if (itemManager.delete(i)) {
if (goldValue > 0)
itemManager.addGoldToInventory(goldValue, false);
itemManager.updateInventory();
Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg); Dispatch dispatch = Dispatch.borrow(sourcePlayer, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
} }
}
} }
private static void ackBankWindowOpened(AckBankWindowOpenedMsg msg, ClientConnection origin) { private static void ackBankWindowOpened(AckBankWindowOpenedMsg msg, ClientConnection origin) {
@ -654,6 +672,8 @@ public class ClientMessagePump implements NetMsgHandler {
JobScheduler.getInstance().scheduleJob(new RefreshGroupJob(sourcePlayer), MBServerStatics.LOAD_OBJECT_DELAY); JobScheduler.getInstance().scheduleJob(new RefreshGroupJob(sourcePlayer), MBServerStatics.LOAD_OBJECT_DELAY);
} }
private static void lootWindowRequest(LootWindowRequestMsg msg, ClientConnection origin) throws MsgSendException { private static void lootWindowRequest(LootWindowRequestMsg msg, ClientConnection origin) throws MsgSendException {
PlayerCharacter pc = SessionManager.getPlayerCharacter(origin); PlayerCharacter pc = SessionManager.getPlayerCharacter(origin);
@ -1243,6 +1263,8 @@ public class ClientMessagePump implements NetMsgHandler {
cost = sell.getBaseValue(); cost = sell.getBaseValue();
if(sell.getItemBaseID() == 980066)
cost = 0;
//apply damaged value reduction //apply damaged value reduction
float durabilityCurrent = sell.getDurabilityCurrent(); float durabilityCurrent = sell.getDurabilityCurrent();
@ -1347,6 +1369,8 @@ public class ClientMessagePump implements NetMsgHandler {
return; return;
// test within talking range // test within talking range
if(npc.isInSafeZone())
npc.sellPercent = 0;
if (sourcePlayer.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) { if (sourcePlayer.getLoc().distanceSquared2D(npc.getLoc()) > MBServerStatics.NPC_TALK_RANGE * MBServerStatics.NPC_TALK_RANGE) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 14); ErrorPopupMsg.sendErrorPopup(sourcePlayer, 14);
@ -1358,219 +1382,192 @@ public class ClientMessagePump implements NetMsgHandler {
} }
private static void buyFromNPC(BuyFromNPCMsg msg, ClientConnection origin) { private static void buyFromNPC(BuyFromNPCMsg msg, ClientConnection origin) {
PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin); PlayerCharacter sourcePlayer = SessionManager.getPlayerCharacter(origin);
if (sourcePlayer == null) if (sourcePlayer == null)
return; return;
if (origin.buyLock.tryLock()) { if (origin.buyLock.tryLock()) {
try { try {
CharacterItemManager itemMan = sourcePlayer.getCharItemManager(); CharacterItemManager itemMan = sourcePlayer.getCharItemManager();
if (itemMan == null) {
if (itemMan == null)
return; return;
}
NPC npc = NPC.getFromCache(msg.getNPCID()); NPC npc = NPC.getFromCache(msg.getNPCID());
if (npc == null) {
if (npc == null)
return; return;
}
Item gold = itemMan.getGoldInventory(); Item gold = itemMan.getGoldInventory();
if (gold == null) {
if (gold == null)
return; return;
}
Item buy = null; Item buy = null;
if (msg.getItemType() == GameObjectType.MobEquipment.ordinal()) { if (msg.getItemType() == GameObjectType.MobEquipment.ordinal()) {
ArrayList<MobEquipment> sellInventory = npc.getContract().getSellInventory(); ArrayList<MobEquipment> sellInventory = npc.getContract().getSellInventory();
if (sellInventory == null) //if(npc.contract.getObjectUUID() == 890){ // default steward
// sellInventory = npc.getSellInventorySteward();
//}
//if(npc.contract.getObjectUUID() == 889){ // default builder
// sellInventory = npc.getSellInventoryBuilder();
//}
if (sellInventory == null) {
return; return;
}
for (MobEquipment me : sellInventory) { for (MobEquipment me : sellInventory) {
if (me.getObjectUUID() == msg.getItemID()) { if (me.getObjectUUID() == msg.getItemID()) {
ItemBase ib = me.getItemBase(); ItemBase ib = me.getItemBase();
if (ib == null) if (ib == null) {
return; return;
}
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(ib.getWeight())) if (!itemMan.hasRoomInventory(ib.getWeight())) {
return; return;
}
int cost = me.getMagicValue(); int cost = me.getMagicValue();
float bargain = sourcePlayer.getBargain(); float bargain = sourcePlayer.getBargain();
switch(npc.getContractID()){
case 1201:
cost = ItemBase.getDiscPrice(ib.getUUID());
bargain = 0;
break;
case 1202:
cost = ItemBase.getStatPrice(ib.getUUID());
bargain = 0;
break;
case 900:
cost = Warehouse.getCostForResource(ib.getUUID()) * Warehouse.getSellStackSize(ib.getUUID());
bargain = 0;
break;
}
float profit;
float profit = npc.getSellPercent(sourcePlayer) - bargain; if(npc.isInSafeZone())
profit = 0;
if (profit < 1) else
profit = 1; profit = npc.getSellPercent(sourcePlayer) - bargain;
if(profit > 0)
cost *= profit; cost *= profit;
if (gold.getNumOfItems() - cost < 0) { if (gold.getNumOfItems() - cost < 0) {
//dont' have enough goldItem exit! //dont' have enough goldItem exit!
// chatMan.chatSystemInfo(pc, "" + "You dont have enough gold."); // chatMan.chatSystemInfo(pc, "" + "You dont have enough gold.");
return; return;
} }
Building b = (!npc.isStatic()) ? npc.getBuilding() : null; Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
if (b != null && b.getProtectionState().equals(ProtectionState.NPC)) if (b != null && b.getProtectionState().equals(ProtectionState.NPC))
b = null; b = null;
int buildingDeposit = cost - me.getMagicValue(); int buildingDeposit = cost - me.getMagicValue();
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) { if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold() && !b.isOwnerIsNPC()) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206); ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206);
return; return;
} }if(npc.getContractID() == 1502041){
me.fromNoob = true;
if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) { } else if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) {
// chatMan.chatSystemInfo(pc, "" + "You Failed to buy the item."); // chatMan.chatSystemInfo(pc, "" + "You Failed to buy the item.");
ChatManager.chatSystemError(sourcePlayer, "Failed To Buy Item");
return; return;
} }
if(me.getItemBase().getType().equals(ItemType.RESOURCE) && npc.getContractID() == 900){
buy = Item.createItemForPlayer(sourcePlayer, ib); handleResourcePurchase(me,itemMan,sourcePlayer,ib);
}else {
buy = Item.createItemForPlayer(sourcePlayer, ib, me.fromNoob);
if (buy != null) { if (buy != null) {
me.transferEnchants(buy); me.transferEnchants(buy);
itemMan.addItemToInventory(buy); itemMan.addItemToInventory(buy);
if(npc.contractUUID == 900 && buy.getItemBaseID() == 1705032){
buy.setNumOfItems(10);
DbManager.ItemQueries.UPDATE_NUM_ITEMS(buy,buy.getNumOfItems());
}
//itemMan.updateInventory(); //itemMan.updateInventory();
} }
} }
} }
}
} else if (msg.getItemType() == GameObjectType.Item.ordinal()) { } else if (msg.getItemType() == GameObjectType.Item.ordinal()) {
CharacterItemManager npcCim = npc.getCharItemManager(); CharacterItemManager npcCim = npc.getCharItemManager();
if (npcCim == null) if (npcCim == null)
return; return;
buy = Item.getFromCache(msg.getItemID()); buy = Item.getFromCache(msg.getItemID());
if (buy == null) if (buy == null)
return; return;
ItemBase ib = buy.getItemBase(); ItemBase ib = buy.getItemBase();
if (ib == null) if (ib == null)
return; return;
if (!npcCim.inventoryContains(buy)) if (!npcCim.inventoryContains(buy))
return; return;
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(ib.getWeight())) if (!itemMan.hasRoomInventory(ib.getWeight()))
return; return;
//TODO test cost and subtract goldItem //TODO test cost and subtract goldItem
//TODO CHnage this if we ever put NPc city npcs in buildings. //TODO CHnage this if we ever put NPc city npcs in buildings.
int cost = buy.getBaseValue(); int cost = buy.getBaseValue();
if (buy.isID() || buy.isCustomValue()) if (buy.isID() || buy.isCustomValue())
cost = buy.getMagicValue(); cost = buy.getMagicValue();
float bargain = sourcePlayer.getBargain(); float bargain = sourcePlayer.getBargain();
float profit = npc.getSellPercent(sourcePlayer) - bargain; float profit = npc.getSellPercent(sourcePlayer) - bargain;
if (profit < 1) if (profit < 1)
profit = 1; profit = 1;
if (!buy.isCustomValue()) if (!buy.isCustomValue())
cost *= profit; cost *= profit;
else else
cost = buy.getValue(); cost = buy.getValue();
if (gold.getNumOfItems() - cost < 0) { if (gold.getNumOfItems() - cost < 0) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold
return; return;
} }
Building b = (!npc.isStatic()) ? npc.getBuilding() : null; Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
if (b != null) if (b != null)
if (b.getProtectionState().equals(ProtectionState.NPC)) if (b.getProtectionState().equals(ProtectionState.NPC))
b = null; b = null;
int buildingDeposit = cost; int buildingDeposit = cost;
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold() && !b.isOwnerIsNPC()) {
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206); ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206);
return; return;
} }
if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) { if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 110); ErrorPopupMsg.sendErrorPopup(sourcePlayer, 110);
return; return;
} }
if (buy != null) if (buy != null)
itemMan.buyFromNPC(buy, npc); itemMan.buyFromNPC(buy, npc);
} else if (msg.getItemType() == GameObjectType.MobLoot.ordinal()) { } else if (msg.getItemType() == GameObjectType.MobLoot.ordinal()) {
CharacterItemManager npcCim = npc.getCharItemManager(); CharacterItemManager npcCim = npc.getCharItemManager();
if (npcCim == null) if (npcCim == null)
return; return;
buy = MobLoot.getFromCache(msg.getItemID()); buy = MobLoot.getFromCache(msg.getItemID());
if (buy == null) if (buy == null)
return; return;
ItemBase ib = buy.getItemBase(); ItemBase ib = buy.getItemBase();
if (ib == null) if (ib == null)
return; return;
if (!npcCim.inventoryContains(buy)) if (!npcCim.inventoryContains(buy))
return; return;
//test room available for item //test room available for item
if (!itemMan.hasRoomInventory(ib.getWeight())) if (!itemMan.hasRoomInventory(ib.getWeight()))
return; return;
//TODO test cost and subtract goldItem //TODO test cost and subtract goldItem
//TODO CHnage this if we ever put NPc city npcs in buildings. //TODO CHnage this if we ever put NPc city npcs in buildings.
int cost = buy.getMagicValue(); int cost = buy.getMagicValue();
cost *= npc.getSellPercent(sourcePlayer); cost *= npc.getSellPercent(sourcePlayer);
if (gold.getNumOfItems() - cost < 0) { if (gold.getNumOfItems() - cost < 0) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold ErrorPopupMsg.sendErrorPopup(sourcePlayer, 128); // Insufficient Gold
return; return;
} }
Building b = (!npc.isStatic()) ? npc.getBuilding() : null; Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
if (b != null && b.getProtectionState().equals(ProtectionState.NPC)) if (b != null && b.getProtectionState().equals(ProtectionState.NPC))
b = null; b = null;
int buildingDeposit = cost; int buildingDeposit = cost;
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold() && !b.isOwnerIsNPC()) {
if (b != null && (b.getStrongboxValue() + buildingDeposit) > b.getMaxGold()) {
ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206); ErrorPopupMsg.sendErrorPopup(sourcePlayer, 206);
return; return;
} }
if (!itemMan.buyFromNPC(b, cost, buildingDeposit)) if (!itemMan.buyFromNPC(b, cost, buildingDeposit))
return; return;
if (buy != null) if (buy != null)
itemMan.buyFromNPC(buy, npc); itemMan.buyFromNPC(buy, npc);
} else } else
return; return;
if (buy != null) { if (buy != null) {
msg.setItem(buy); msg.setItem(buy);
//send the buy message back to update player //send the buy message back to update player
// msg.setItemType(buy.getObjectType().ordinal()); // msg.setItemType(buy.getObjectType().ordinal());
@ -1579,14 +1576,43 @@ public class ClientMessagePump implements NetMsgHandler {
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
itemMan.updateInventory(); itemMan.updateInventory();
} }
} finally { } finally {
origin.buyLock.unlock(); origin.buyLock.unlock();
} }
} else { } else {
ErrorPopupMsg.sendErrorPopup(origin.getPlayerCharacter(), 12); // All production slots taken ErrorPopupMsg.sendErrorPopup(origin.getPlayerCharacter(), 12); // All production slots taken
} }
}
public static void handleResourcePurchase(MobEquipment me, CharacterItemManager itemMan, PlayerCharacter sourcePlayer, ItemBase ib){
boolean stacked = false;
int buystack = Warehouse.getSellStackSize(me.getItemBase().getUUID());
for(Item item : itemMan.getInventory()){
int itemID = item.getItemBaseID();
int meID = me.getItemBase().getUUID();
if(itemID == meID){
if(Warehouse.maxResources.isEmpty())
Warehouse.getMaxResources();
int maxStack = Warehouse.maxResources.get(itemID);
if(maxStack > item.getNumOfItems() + buystack){
item.setNumOfItems(item.getNumOfItems() + buystack);
stacked = true;
itemMan.updateInventory();
DbManager.ItemQueries.UPDATE_NUM_ITEMS(item,item.getNumOfItems());
break;
}
}
}
if(!stacked){
Item buy = Item.createItemForPlayer(sourcePlayer, ib, false);
if (buy != null) {
me.transferEnchants(buy);
itemMan.addItemToInventory(buy);
buy.setNumOfItems(buystack);
DbManager.ItemQueries.UPDATE_NUM_ITEMS(buy,buy.getNumOfItems());
}
}
itemMan.updateInventory();
} }
private static void Repair(RepairMsg msg, ClientConnection origin) { private static void Repair(RepairMsg msg, ClientConnection origin) {
@ -1646,14 +1672,17 @@ public class ClientMessagePump implements NetMsgHandler {
max *= (1 + (durMod * 0.01f)); max *= (1 + (durMod * 0.01f));
if (dur >= max || dur < 1) { if (dur >= max || dur < 1) {
//redundancy message to clear item from window in client //redundancy message to clear item from window in client
if (!DbManager.ItemQueries.SET_DURABILITY(toRepair, dur))
return;
toRepair.setDurabilityCurrent(max); toRepair.setDurabilityCurrent(max);
msg.setupRepairAck(max - dur); msg.setupRepairAck(max - dur);
dispatch = Dispatch.borrow(player, msg); dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
return; return;
} }
//TODO get cost to repair
int cost = (int) ((max - dur) * 80.1); int cost = (int)((toRepair.getMagicValue()/max*(max - dur)) + (npc.getRepairCost() * npc.buyPercent));
Building b = (!npc.isStatic()) ? npc.getBuilding() : null; Building b = (!npc.isStatic()) ? npc.getBuilding() : null;
if (b != null) if (b != null)

15
src/engine/net/client/handlers/ArcMineChangeProductionMsgHandler.java

@ -11,6 +11,7 @@ import engine.objects.GuildStatusController;
import engine.objects.Mine; import engine.objects.Mine;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import engine.objects.Resource; import engine.objects.Resource;
import org.pmw.tinylog.Logger;
/* /*
* @Author: * @Author:
@ -35,26 +36,28 @@ public class ArcMineChangeProductionMsgHandler extends AbstractClientMsgHandler
//TODO verify this against the warehouse? //TODO verify this against the warehouse?
if (GuildStatusController.isInnerCouncil(playerCharacter.getGuildStatus()) == false) // is this only GL? if (!GuildStatusController.isInnerCouncil(playerCharacter.getGuildStatus())) // is this only GL?
return true; return true;
Mine mine = Mine.getMine(changeProductionMsg.getMineID()); Mine mine = Mine.getMine(changeProductionMsg.getMineID());
if (mine == null) if (mine == null) {
Logger.error("Player Character: " + playerCharacter.getName() + " Tried To Change Mine: " + changeProductionMsg.getMineID() + " and Mine was Null");
return true; return true;
}
//make sure mine belongs to guild //make sure mine belongs to guild
if (mine.getOwningGuild().isEmptyGuild() || if (mine.getOwningGuild().isEmptyGuild() || mine.getOwningGuild().getObjectUUID() != playerCharacter.getGuild().getObjectUUID())
mine.getOwningGuild().getObjectUUID() != playerCharacter.getGuild().getObjectUUID())
return true; return true;
//make sure valid resource //make sure valid resource
Resource resource = Resource.resourceByHash.get(changeProductionMsg.getResourceHash()); Resource resource = Resource.resourceByHash.get(changeProductionMsg.getResourceHash());
if (resource == null) if (resource == null) {
Logger.error("Player Character: " + playerCharacter.getName() + " Tried To Change Mine: " + changeProductionMsg.getMineID() + " and Resource was Null");
return true; return true;
}
//update resource //update resource

2
src/engine/net/client/handlers/CityDataHandler.java

@ -63,7 +63,7 @@ public class CityDataHandler extends AbstractClientMsgHandler {
// If the hotZone has changed then update the client's map accordingly. // If the hotZone has changed then update the client's map accordingly.
if (playerCharacter.getTimeStamp("hotzoneupdate") <= ZoneManager.hotZoneLastUpdate.toEpochMilli() && ZoneManager.hotZone != null) { if (playerCharacter.getTimestamps().containsKey("hotzoneupdate") && playerCharacter.getTimeStamp("hotzoneupdate") <= ZoneManager.hotZoneLastUpdate.toEpochMilli() && ZoneManager.hotZone != null) {
HotzoneChangeMsg hotzoneChangeMsg = new HotzoneChangeMsg(Enum.GameObjectType.Zone.ordinal(), ZoneManager.hotZone.getObjectUUID()); HotzoneChangeMsg hotzoneChangeMsg = new HotzoneChangeMsg(Enum.GameObjectType.Zone.ordinal(), ZoneManager.hotZone.getObjectUUID());
dispatch = Dispatch.borrow(playerCharacter, hotzoneChangeMsg); dispatch = Dispatch.borrow(playerCharacter, hotzoneChangeMsg);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);

2
src/engine/net/client/handlers/DestroyBuildingHandler.java

@ -62,7 +62,7 @@ public class DestroyBuildingHandler extends AbstractClientMsgHandler {
if (city != null) if (city != null)
bane = city.getBane(); bane = city.getBane();
if (bane != null && bane.getSiegePhase() == Enum.SiegePhase.WAR) { if (bane != null){// && bane.getSiegePhase() == Enum.SiegePhase.WAR) {
ErrorPopupMsg.sendErrorPopup(pc, 171); ErrorPopupMsg.sendErrorPopup(pc, 171);
return true; return true;
} }

2
src/engine/net/client/handlers/GroupInviteResponseHandler.java

@ -102,7 +102,7 @@ public class GroupInviteResponseHandler extends AbstractClientMsgHandler {
// Run Keyclone Audit // Run Keyclone Audit
KEYCLONEAUDIT.audit(player, group); //KEYCLONEAUDIT.audit(player, group);
return true; return true;
} }

5
src/engine/net/client/handlers/ItemProductionMsgHandler.java

@ -360,6 +360,11 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
targetItem.recycle(vendor); targetItem.recycle(vendor);
vendor.removeItemFromForge(targetItem); vendor.removeItemFromForge(targetItem);
//refund the gold for cancelled item
if(vendor.building.getStrongboxValue() + targetItem.getItemBase().getBaseValue() < 15000000){
vendor.building.setStrongboxValue(vendor.building.getStrongboxValue() + targetItem.getItemBase().getBaseValue());
}
// Refresh vendor's inventory to client // Refresh vendor's inventory to client
outMsg = new ManageNPCMsg(vendor); outMsg = new ManageNPCMsg(vendor);

13
src/engine/net/client/handlers/MOTDEditHandler.java

@ -62,16 +62,23 @@ public class MOTDEditHandler extends AbstractClientMsgHandler {
return true; return true;
} }
if (type == 1) // Guild MOTD if (type == 1) { // Guild MOTD
msg.setMessage(guild.getMOTD()); msg.setMessage(guild.getMOTD());
else if (type == 3) // IC MOTD guild.updateDatabase();
}else if (type == 3) { // IC MOTD
msg.setMessage(guild.getICMOTD()); msg.setMessage(guild.getICMOTD());
else if (type == 0) { // Nation MOTD guild.updateDatabase();
}else if (type == 0) { // Nation MOTD
Guild nation = guild.getNation(); Guild nation = guild.getNation();
if (nation == null || !nation.isNation()) { if (nation == null || !nation.isNation()) {
ErrorPopupMsg.sendErrorMsg(playerCharacter, "You do not have such authority!"); ErrorPopupMsg.sendErrorMsg(playerCharacter, "You do not have such authority!");
return true; return true;
} }
nation.setNMOTD(msg.getMessage());
nation.updateDatabase();
for(Guild sub : nation.getSubGuildList()){
sub.setNMOTD(nation.getNMOTD());
}
msg.setMessage(nation.getMOTD()); msg.setMessage(nation.getMOTD());
} }
dispatch = Dispatch.borrow(playerCharacter, msg); dispatch = Dispatch.borrow(playerCharacter, msg);

83
src/engine/net/client/handlers/MerchantMsgHandler.java

@ -17,6 +17,7 @@ import engine.powers.PowersBase;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Objects;
/* /*
* @Author: * @Author:
@ -105,7 +106,7 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
// Validate player can obtain blessing // Validate player can obtain blessing
if (GuildStatusController.isGuildLeader(player.getGuildStatus()) == false) { if (!GuildStatusController.isGuildLeader(player.getGuildStatus())) {
ErrorPopupMsg.sendErrorPopup(player, 173); // You must be the leader of a guild to receive a blessing ErrorPopupMsg.sendErrorPopup(player, 173); // You must be the leader of a guild to receive a blessing
return; return;
} }
@ -126,12 +127,12 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
realm = RealmMap.getRealmForCity(city); realm = RealmMap.getRealmForCity(city);
if (realm.getCanBeClaimed() == false) { if (!realm.getCanBeClaimed()) {
ErrorPopupMsg.sendErrorPopup(player, 180); // This territory cannot be ruled by anyone ErrorPopupMsg.sendErrorPopup(player, 180); // This territory cannot be ruled by anyone
return; return;
} }
if (realm.isRuled() == true) { if (realm.isRuled()) {
ErrorPopupMsg.sendErrorPopup(player, 178); // This territory is already claimed ErrorPopupMsg.sendErrorPopup(player, 178); // This territory is already claimed
return; return;
} }
@ -142,12 +143,12 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
} }
private static void requestBoon(MerchantMsg msg, ClientConnection origin, PlayerCharacter player, NPC npc) { private static void requestBoon(PlayerCharacter player, NPC npc) {
Building shrineBuilding; Building shrineBuilding;
Shrine shrine; Shrine shrine;
if (npc.getGuild() != player.getGuild()) if (!npc.getGuild().getNation().equals(player.getGuild().getNation()))
return; return;
shrineBuilding = npc.getBuilding(); shrineBuilding = npc.getBuilding();
@ -155,7 +156,7 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
if (shrineBuilding == null) if (shrineBuilding == null)
return; return;
if (shrineBuilding.getBlueprint() != null && shrineBuilding.getBlueprint().getBuildingGroup() != engine.Enum.BuildingGroup.SHRINE) if (shrineBuilding.getBlueprint() != null && !shrineBuilding.getBlueprint().getBuildingGroup().equals(engine.Enum.BuildingGroup.SHRINE))
return; return;
if (shrineBuilding.getRank() == -1) if (shrineBuilding.getRank() == -1)
@ -171,11 +172,9 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
return; return;
} }
//already haz boon.
if (player.containsEffect(shrine.getShrineType().getPowerToken())) { if (player.containsEffect(shrine.getShrineType().getPowerToken())) {
ErrorPopupMsg.sendErrorPopup(player, 199); //remove old boon to apply new one, allows boon refreshing
return; player.effects.remove(PowersManager.getPowerByToken(shrine.getShrineType().getPowerToken()).name);
} }
if (!Shrine.canTakeFavor(player, shrine)) if (!Shrine.canTakeFavor(player, shrine))
@ -191,16 +190,31 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
return; return;
} }
int rank = shrine.getRank(); int trains = 0;
//R8 trees always get atleast rank 2 boons. rank uses index, where 0 is first place, 1 is second, etc... switch(npc.getRank()){
if (shrineBuilding.getCity() != null && shrineBuilding.getCity().getTOL() != null && shrineBuilding.getCity().getTOL().getRank() == 8) case 1:
if (rank != 0) trains = 10;
rank = 1; break;
int trains = 40 - (rank * 10); case 2:
if (trains < 0) trains = 15;
trains = 0; break;
case 3:
trains = 20;
break;
case 4:
trains = 25;
break;
case 5:
trains = 30;
break;
case 6:
trains = 35;
break;
case 7:
trains = 40;
break;
}
//System.out.println(trains);
PowersManager.applyPower(player, player, player.getLoc(), shrinePower.getToken(), trains, false); PowersManager.applyPower(player, player, player.getLoc(), shrinePower.getToken(), trains, false);
ChatManager.chatGuildInfo(player.getGuild(), player.getName() + " has recieved a boon costing " + 1 + " point of favor."); ChatManager.chatGuildInfo(player.getGuild(), player.getName() + " has recieved a boon costing " + 1 + " point of favor.");
shrineBuilding.addEffectBit(1000000 << 2); shrineBuilding.addEffectBit(1000000 << 2);
@ -260,9 +274,31 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
} }
} }
if (targetCity == null) if (targetCity == null){
Mine mineTele = null;
for(Mine mine : Mine.getMinesToTeleportTo(player)){
if(mine.getObjectUUID() == msg.getCityID()){
mineTele = mine;
}
}
if(mineTele == null){
return; return;
}else {
int time = MBServerStatics.TELEPORT_TIME_IN_SECONDS;
msg.setTeleportTime(time);
Building tower = Mine.getTower(mineTele);
if (tower == null)
return;
Vector3fImmutable teleportLoc = Vector3fImmutable.getRandomPointOnCircle(tower.getLoc(), 10);
ChatManager.chatSystemInfo(player, "You Will Teleport To " + mineTele.getParentZone().getParent().getName() + "'s Mine In " + time + " Seconds.");
if (time > 0) {
//TODO add timer to teleport
TeleportJob tj = new TeleportJob(player, npc, teleportLoc, origin, true);
JobScheduler.getInstance().scheduleJob(tj, time * 1000);
}
}
}else{
//finish porting to a city
//verify level required to teleport or repledge //verify level required to teleport or repledge
Guild toGuild = targetCity.getGuild(); Guild toGuild = targetCity.getGuild();
@ -316,6 +352,9 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
} }
} }
}
private static PowersBase getPowerforHermit(NPC npc) { private static PowersBase getPowerforHermit(NPC npc) {
int contractID; int contractID;
@ -420,7 +459,7 @@ public class MerchantMsgHandler extends AbstractClientMsgHandler {
if (isHermit(npc)) if (isHermit(npc))
requestHermitBlessing(msg, origin, player, npc); requestHermitBlessing(msg, origin, player, npc);
else else
requestBoon(msg, origin, player, npc); requestBoon(player, npc);
break; break;
case 15: case 15:
LeaderboardMessage lbm = new LeaderboardMessage(); LeaderboardMessage lbm = new LeaderboardMessage();

29
src/engine/net/client/handlers/ObjectActionMsgHandler.java

@ -421,31 +421,12 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
itemMan.consume(item); itemMan.consume(item);
} }
break; break;
//ANNIVERSERY GIFT
case 31: case 31:
// *** Disabled for now: Needs bootyset created
//if (ib.getUUID() == 971012) {
// int random = ThreadLocalRandom.current().nextInt(ItemBase.AnniverseryGifts.size());
// int annyID = ItemBase.AnniverseryGifts.get(random);
// ItemBase annyIB = ItemBase.getItemBase(annyID);
// if (annyIB != null) {
// Item gift = MobLoot.createItemForPlayer(player, annyIB);
// if (gift != null) {
// itemMan.addItemToInventory(gift);
// itemMan.consume(item);
// }
// }
// break;
//}
LootManager.peddleFate(player,item); LootManager.peddleFate(player,item);
break; break;
case 30: //water bucket case 30: //water bucket
case 8: //potions, tears of saedron case 8: //potions, tears of saedron
case 5: //runes, petition, warrant, scrolls case 5: //runes, petition, warrant, scrolls
if (uuid > 3000 && uuid < 3050) { //Discipline Runes if (uuid > 3000 && uuid < 3050) { //Discipline Runes
if (ApplyRuneMsg.applyRune(uuid, origin, player)) { if (ApplyRuneMsg.applyRune(uuid, origin, player)) {
@ -462,7 +443,12 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
itemMan.consume(item); itemMan.consume(item);
} }
break; break;
} else if (uuid > 252122 && uuid < 252128) { //mastery runes } else if (uuid > 252122 && uuid < 252137) { //blood runes
if (ApplyRuneMsg.applyRune(uuid, origin, player)) {
itemMan.consume(item);
}
break;
} else if (uuid > 252128 && uuid < 252128) { //mastery runes
if (ApplyRuneMsg.applyRune(uuid, origin, player)) { if (ApplyRuneMsg.applyRune(uuid, origin, player)) {
itemMan.consume(item); itemMan.consume(item);
} }
@ -528,7 +514,6 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
} }
// Send piss bucket animation // Send piss bucket animation
VisualUpdateMessage vum = new VisualUpdateMessage(player, 16323); VisualUpdateMessage vum = new VisualUpdateMessage(player, 16323);
vum.configure(); vum.configure();
DispatchMessage.sendToAllInRange(player, vum); DispatchMessage.sendToAllInRange(player, vum);
@ -543,7 +528,9 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
dispatch = Dispatch.borrow(player, msg); dispatch = Dispatch.borrow(player, msg);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
if(!item.getItemBase().getType().equals(ItemType.POTION)) {
player.cancelOnSpell(); player.cancelOnSpell();
}
break; break;
default: //shouldn't be here, consume item default: //shouldn't be here, consume item
dispatch = Dispatch.borrow(player, msg); dispatch = Dispatch.borrow(player, msg);

3
src/engine/net/client/handlers/TaxCityMsgHandler.java

@ -135,7 +135,8 @@ public class TaxCityMsgHandler extends AbstractClientMsgHandler {
msg = (TaxCityMsg) baseMsg; msg = (TaxCityMsg) baseMsg;
ViewTaxes(msg, player); //realm taxing disabled
//ViewTaxes(msg, player);
return true; return true;

164
src/engine/net/client/msg/ApplyRuneMsg.java

@ -10,6 +10,7 @@
package engine.net.client.msg; package engine.net.client.msg;
import engine.Enum; import engine.Enum;
import engine.gameManager.ChatManager;
import engine.gameManager.DbManager; import engine.gameManager.DbManager;
import engine.net.*; import engine.net.*;
import engine.net.client.ClientConnection; import engine.net.client.ClientConnection;
@ -70,18 +71,16 @@ public class ApplyRuneMsg extends ClientNetMsg {
} }
public static boolean applyRune(int runeID, ClientConnection origin, PlayerCharacter playerCharacter) { public static boolean applyRune(int runeID, ClientConnection origin, PlayerCharacter playerCharacter) {
RuneBase rb = RuneBase.getRuneBase(runeID); RuneBase rb = RuneBase.getRuneBase(runeID);
Dispatch dispatch; Dispatch dispatch;
if (playerCharacter == null || origin == null || rb == null) { if (playerCharacter == null || origin == null || rb == null) {
return false; return false;
} }
int raceID = playerCharacter.getRaceID();
//Check race is met //Check race is met
ConcurrentHashMap<Integer, Boolean> races = rb.getRace(); ConcurrentHashMap<Integer, Boolean> races = rb.getRace();
if(runeID != 3007 && runeID != 3014) {//bounty hunter and huntsman
if (races.size() > 0) { if (races.size() > 0) {
int raceID = playerCharacter.getRaceID();
boolean valid = false; boolean valid = false;
for (int validID : races.keySet()) { for (int validID : races.keySet()) {
if (validID == raceID) { if (validID == raceID) {
@ -89,11 +88,45 @@ public class ApplyRuneMsg extends ClientNetMsg {
break; break;
} }
} }
if(runeID == 3040)
valid = true;
if(runeID == 3049)
valid = true;
if(raceID == 1999){
switch(runeID){
case 2514:
case 3036:
case 3033:
case 3001:
case 3002:
case 3003:
case 3004:
case 3008:
case 3009:
case 3013:
case 3016:
case 3017:
case 3018:
case 3020:
case 3021:
case 3030:
case 3031:
case 3037:
case 3045:
case 3046:
case 3047:
case 3048:
case 3049:
valid = true;
break;
}
}
if (!valid) { if (!valid) {
return false; return false;
} }
} }
//Check base class is met //Check base class is met
ConcurrentHashMap<Integer, Boolean> baseClasses = rb.getBaseClass(); ConcurrentHashMap<Integer, Boolean> baseClasses = rb.getBaseClass();
if (baseClasses.size() > 0) { if (baseClasses.size() > 0) {
@ -105,11 +138,18 @@ public class ApplyRuneMsg extends ClientNetMsg {
break; break;
} }
} }
if(runeID == 3040)
valid = true;
if(runeID == 3036 && raceID == 1999)
valid = true;
if(runeID == 3033 && raceID == 1999)
valid = true;
if(runeID == 3035 && baseClassID == 2501)
valid = true;
if (!valid) { if (!valid) {
return false; return false;
} }
} }
//Check promotion class is met //Check promotion class is met
ConcurrentHashMap<Integer, Boolean> promotionClasses = rb.getPromotionClass(); ConcurrentHashMap<Integer, Boolean> promotionClasses = rb.getPromotionClass();
if (promotionClasses.size() > 0) { if (promotionClasses.size() > 0) {
@ -121,11 +161,25 @@ public class ApplyRuneMsg extends ClientNetMsg {
break; break;
} }
} }
if(runeID == 3040)
valid = true;
if(runeID == 3004 && (playerCharacter.getPromotionClassID() == 2505 || playerCharacter.getPromotionClassID() == 2510))
valid = true;
if(runeID == 3036 && raceID == 1999)
valid = true;
if(runeID == 3033 && raceID == 1999)
valid = true;
if(runeID == 3028 && (raceID == 2013 || raceID == 2014) && playerCharacter.getBaseClassID() == 2501)
valid = true;
if (!valid) { if (!valid) {
return false; return false;
} }
} }
} else{
if(playerCharacter.getPromotionClassID() == 2519){//priest
return false;
}
}
//Check disciplines are met //Check disciplines are met
ArrayList<CharacterRune> runes = playerCharacter.getRunes(); ArrayList<CharacterRune> runes = playerCharacter.getRunes();
ConcurrentHashMap<Integer, Boolean> disciplines = rb.getDiscipline(); ConcurrentHashMap<Integer, Boolean> disciplines = rb.getDiscipline();
@ -139,7 +193,6 @@ public class ApplyRuneMsg extends ClientNetMsg {
} }
} }
} }
int discCount = 0; int discCount = 0;
for (CharacterRune cr : runes) { for (CharacterRune cr : runes) {
int runeBaseID = cr.getRuneBaseID(); int runeBaseID = cr.getRuneBaseID();
@ -152,28 +205,35 @@ public class ApplyRuneMsg extends ClientNetMsg {
return false; return false;
} }
} }
//Check level is met //Check level is met
if (playerCharacter.getLevel() < rb.getLevelRequired()) { if (playerCharacter.getLevel() < rb.getLevelRequired()) {
return false; return false;
} }
int strTotal = 0; int strTotal = 0;
int dexTotal = 0; int dexTotal = 0;
int conTotal = 0; int conTotal = 0;
int intTotal = 0; int intTotal = 0;
int spiTotal = 0; int spiTotal = 0;
int cost = 0; int cost = 0;
//Check any attributes are met //Check any attributes are met
ArrayList<RuneBaseAttribute> attrs = rb.getAttrs(); ArrayList<RuneBaseAttribute> attrs = rb.getAttrs();
if (rb.getAttrs() != null) if (rb.getAttrs() != null)
for (RuneBaseAttribute rba : attrs) { for (RuneBaseAttribute rba : attrs) {
int attrID = rba.getAttributeID(); int attrID = rba.getAttributeID();
int mod = rba.getModValue(); int mod = rba.getModValue();
switch (attrID) { switch (attrID) {
case MBServerStatics.RUNE_COST_ATTRIBUTE_ID: case MBServerStatics.RUNE_COST_ATTRIBUTE_ID:
switch (rb.getName()) {
case "Born of the Ethyri":
case "Born of the Taripontor":
case "Born of the Gwendannen":
case "Born of the Invorri":
case "Born of the Irydnu":
case "Scion of the Dar Khelegeur":
case "Scion of the Gwaridorn":
case "Scion of the Twathedilion":
mod = 0;
}
if (mod > playerCharacter.getUnusedStatPoints()) { if (mod > playerCharacter.getUnusedStatPoints()) {
return false; return false;
} }
@ -226,25 +286,64 @@ public class ApplyRuneMsg extends ClientNetMsg {
break; break;
} }
} }
//Check if max number runes already reached //Check if max number runes already reached
if (runes.size() > 12) { if (runes.size() > 12) {
ChatManager.chatSystemInfo(playerCharacter,"You Have Too Many Runes Applied");
return false; return false;
} }
switch (rb.getName()) {
//if discipline, check number applied case "Born of the Ethyri":
if (isDiscipline(runeID)) { case "Born of the Taripontor":
if (playerCharacter.getLevel() < 70) { case "Born of the Gwendannen":
if (discCount > 2) { case "Born of the Invorri":
case "Born of the Irydnu":
for (CharacterRune charRune : playerCharacter.getRunes()) {
RuneBase rb2 = charRune.getRuneBase();
switch (rb2.getName()) {
case "Born of the Ethyri":
case "Born of the Taripontor":
case "Born of the Gwendannen":
case "Born of the Invorri":
case "Born of the Irydnu":
ChatManager.chatSystemError(playerCharacter, "You Have Already Applied A Blood Rune");
return false; return false;
} }
} else { }
if (discCount > 3) { break;
case "Scion of the Dar Khelegeur":
case "Scion of the Gwaridorn":
case "Scion of the Twathedilion":
for (CharacterRune charRune : playerCharacter.getRunes()) {
RuneBase rb2 = charRune.getRuneBase();
switch (rb2.getName()) {
case "Scion of the Dar Khelegeur":
case "Scion of the Gwaridorn":
case "Scion of the Twathedilion":
ChatManager.chatSystemError(playerCharacter, "You Have Already Applied A Blood Rune");
return false; return false;
} }
} }
break;
}
//if discipline, check number applied
if (isDiscipline(runeID)) {
switch(playerCharacter.getRank()){
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
if(discCount > 3)
return false;
break;
case 7:
case 8:
if(discCount > 5)
return false;
break;
}
} }
//Everything succeeded. Let's apply the rune //Everything succeeded. Let's apply the rune
//Attempt add rune to database //Attempt add rune to database
CharacterRune runeWithoutID = new CharacterRune(rb, playerCharacter.getObjectUUID()); CharacterRune runeWithoutID = new CharacterRune(rb, playerCharacter.getObjectUUID());
@ -258,7 +357,6 @@ public class ApplyRuneMsg extends ClientNetMsg {
if (cr == null) { if (cr == null) {
return false; return false;
} }
//remove any overridden runes from player //remove any overridden runes from player
ArrayList<Integer> overwrite = rb.getOverwrite(); ArrayList<Integer> overwrite = rb.getOverwrite();
CharacterRune toRemove = null; CharacterRune toRemove = null;
@ -267,13 +365,10 @@ public class ApplyRuneMsg extends ClientNetMsg {
toRemove = playerCharacter.removeRune(overwriteID); toRemove = playerCharacter.removeRune(overwriteID);
} }
} }
//add rune to player //add rune to player
playerCharacter.addRune(cr); playerCharacter.addRune(cr);
// recalculate all bonuses/formulas/skills/powers // recalculate all bonuses/formulas/skills/powers
playerCharacter.recalculate(); playerCharacter.recalculate();
//if overwriting a stat rune, add any amount granted from previous rune. //if overwriting a stat rune, add any amount granted from previous rune.
if (toRemove != null) { if (toRemove != null) {
RuneBase rbs = toRemove.getRuneBase(); RuneBase rbs = toRemove.getRuneBase();
@ -299,30 +394,35 @@ public class ApplyRuneMsg extends ClientNetMsg {
if (dif > 0 && spiTotal < (int) playerCharacter.statSpiMax) { if (dif > 0 && spiTotal < (int) playerCharacter.statSpiMax) {
playerCharacter.addSpi(dif); playerCharacter.addSpi(dif);
} }
// recalculate all bonuses/formulas/skills/powers // recalculate all bonuses/formulas/skills/powers
playerCharacter.recalculate(); playerCharacter.recalculate();
} }
} }
switch (rb.getName()) {
case "Born of the Ethyri":
case "Born of the Taripontor":
case "Born of the Gwendannen":
case "Born of the Invorri":
case "Born of the Irydnu":
case "Scion of the Dar Khelegeur":
case "Scion of the Gwaridorn":
case "Scion of the Twathedilion":
cost = 0;
break;
}
if (cost > 0) { if (cost > 0) {
ModifyStatMsg msm = new ModifyStatMsg((0 - cost), 0, 3); ModifyStatMsg msm = new ModifyStatMsg((0 - cost), 0, 3);
dispatch = Dispatch.borrow(playerCharacter, msm); dispatch = Dispatch.borrow(playerCharacter, msm);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
} }
//send apply rune message to client //send apply rune message to client
ApplyRuneMsg arm = new ApplyRuneMsg(playerCharacter.getObjectType().ordinal(), playerCharacter.getObjectUUID(), runeID, cr.getObjectType().ordinal(), cr.getObjectUUID(), false); ApplyRuneMsg arm = new ApplyRuneMsg(playerCharacter.getObjectType().ordinal(), playerCharacter.getObjectUUID(), runeID, cr.getObjectType().ordinal(), cr.getObjectUUID(), false);
dispatch = Dispatch.borrow(playerCharacter, arm); dispatch = Dispatch.borrow(playerCharacter, arm);
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY); DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
//alert them of success //alert them of success
ErrorPopupMsg.sendErrorPopup(playerCharacter, 160); ErrorPopupMsg.sendErrorPopup(playerCharacter, 160);
//reapply bonuses //reapply bonuses
playerCharacter.applyBonuses(); playerCharacter.applyBonuses();
return true; return true;
} }

6
src/engine/net/client/msg/BuyFromNPCWindowMsg.java

@ -112,6 +112,12 @@ public class BuyFromNPCWindowMsg extends ClientNetMsg {
if (contract != null) if (contract != null)
sellInventory = contract.getSellInventory(); sellInventory = contract.getSellInventory();
//if(npc.contract.getObjectUUID() == 890){ // default steward
// sellInventory = npc.getSellInventorySteward();
// }
//if(npc.contract.getObjectUUID() == 889){ // default builder
// sellInventory = npc.getSellInventoryBuilder();
// }
} }
if (man != null) if (man != null)

8
src/engine/net/client/msg/CityDataMsg.java

@ -104,8 +104,10 @@ public class CityDataMsg extends ClientNetMsg {
} }
temp.putInt(mineList.size()); temp.putInt(mineList.size());
for (Mine mine : mineList) for (Mine mine : mineList) {
if(mine.getParentZone() != null && !mine.getParentZone().isContinent())
Mine.serializeForClientMsg(mine, temp); Mine.serializeForClientMsg(mine, temp);
}
temp.put((byte) 0); // PAD temp.put((byte) 0); // PAD
} }
@ -178,8 +180,10 @@ public class CityDataMsg extends ClientNetMsg {
} }
writer.putInt(mineList.size()); writer.putInt(mineList.size());
for (Mine mine : mineList) for (Mine mine : mineList) {
if(mine.getParentZone() != null && !mine.getParentZone().isContinent())
Mine.serializeForClientMsg(mine, writer); Mine.serializeForClientMsg(mine, writer);
}
} else } else
writer.putInt(0); writer.putInt(0);
} catch (Exception e) { } catch (Exception e) {

23
src/engine/net/client/msg/ManageCityAssetsMsg.java

@ -275,7 +275,7 @@ public class ManageCityAssetsMsg extends ClientNetMsg {
writer.putString(npcHire.getName()); writer.putString(npcHire.getName());
writer.putInt(1); writer.putInt(1);
writer.putInt(Blueprint.getNpcMaintCost(npcHire.getRank())); writer.putInt(0);
if (npcHire.getObjectType() == GameObjectType.NPC) if (npcHire.getObjectType() == GameObjectType.NPC)
writer.putInt(((NPC) npcHire).getContract().getIconID()); // Was 60 writer.putInt(((NPC) npcHire).getContract().getIconID()); // Was 60
else if (npcHire.getObjectType() == GameObjectType.Mob) { else if (npcHire.getObjectType() == GameObjectType.Mob) {
@ -485,36 +485,19 @@ public class ManageCityAssetsMsg extends ClientNetMsg {
writer.putInt(building.getRank()); writer.putInt(building.getRank());
// Maintenance costs include resource if
// this structure is an R8 tree
if (building.getRank() == 8)
writer.putInt(5); // Resources included
else
writer.putInt(1); // Gold only writer.putInt(1); // Gold only
writer.putInt(2308551); //Gold writer.putInt(2308551); //Gold
if (building.getBlueprint() == null) if (building.getBlueprint() == null)
writer.putInt(0); writer.putInt(0);
else else
writer.putInt(building.getBlueprint().getMaintCost(building.getRank())); // maint cost writer.putInt(building.getBlueprint().getMaintCost()); // maint cost
if (building.getRank() == 8) {
writer.putInt(74856115); // Stone
writer.putInt(1500); // maint cost
writer.putInt(-1603256692); // Lumber
writer.putInt(1500); // maint cost
writer.putInt(-1596311545); // Galvor
writer.putInt(5); // maint cost
writer.putInt(1532478436); // Wormwood
writer.putInt(5); // maint cost
}
LocalDateTime maintDate = building.maintDateTime; LocalDateTime maintDate = building.maintDateTime;
if (maintDate == null) if (maintDate == null)
maintDate = LocalDateTime.now(); maintDate = LocalDateTime.now();
writer.putLocalDateTime(LocalDateTime.now()); // current time writer.putLocalDateTime(maintDate); // current time
// utc offset? // utc offset?
writer.putInt((int) java.time.Duration.between(LocalDateTime.now(), maintDate).getSeconds()); // Seconds to maint date writer.putInt((int) java.time.Duration.between(LocalDateTime.now(), maintDate).getSeconds()); // Seconds to maint date

40
src/engine/net/client/msg/ServerInfoMsg.java

@ -11,6 +11,7 @@ package engine.net.client.msg;
import engine.gameManager.ConfigManager; import engine.gameManager.ConfigManager;
import engine.gameManager.DbManager;
import engine.net.AbstractConnection; import engine.net.AbstractConnection;
import engine.net.ByteBufferReader; import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
@ -53,18 +54,45 @@ public class ServerInfoMsg extends ClientNetMsg {
writer.putInt(WorldServer.worldMapID); writer.putInt(WorldServer.worldMapID);
writer.putString(ConfigManager.MB_WORLD_NAME.getValue()); writer.putString(ConfigManager.MB_WORLD_NAME.getValue());
if (LoginServer.population < MBServerStatics.LOW_POPULATION) int TotalTrees = 21;
int currentR8Trees = DbManager.CityQueries.GET_CAPITAL_CITY_COUNT();
switch(currentR8Trees){
case 0:
case 1:
case 2:
case 3:
case 4:
writer.putInt(0); //Land Rush writer.putInt(0); //Land Rush
else if (LoginServer.population < MBServerStatics.NORMAL_POPULATION) break;
case 5:
case 6:
case 7:
case 8:
writer.putInt(1); //Low pop writer.putInt(1); //Low pop
else if (LoginServer.population < MBServerStatics.HIGH_POPULATION) break;
case 9:
case 10:
case 11:
case 12:
writer.putInt(2); //Normal pop writer.putInt(2); //Normal pop
else if (LoginServer.population < MBServerStatics.VERY_OVERPOPULATED_POPULATION) break;
case 13:
case 14:
case 15:
case 16:
writer.putInt(3); //High Pop writer.putInt(3); //High Pop
else if (LoginServer.population < MBServerStatics.FULL_POPULATION) break;
case 17:
case 18:
case 19:
case 20:
writer.putInt(4); //Very overpopulated pop writer.putInt(4); //Very overpopulated pop
else break;
default:
writer.putInt(5); //Full pop writer.putInt(5); //Full pop
break;
}
} }
/** /**

22
src/engine/net/client/msg/TeleportRepledgeListMsg.java

@ -16,7 +16,9 @@ import engine.net.ByteBufferReader;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.Protocol; import engine.net.client.Protocol;
import engine.objects.City; import engine.objects.City;
import engine.objects.Mine;
import engine.objects.PlayerCharacter; import engine.objects.PlayerCharacter;
import org.pmw.tinylog.Logger;
import java.util.ArrayList; import java.util.ArrayList;
@ -24,6 +26,7 @@ import java.util.ArrayList;
public class TeleportRepledgeListMsg extends ClientNetMsg { public class TeleportRepledgeListMsg extends ClientNetMsg {
ArrayList<City> cities; ArrayList<City> cities;
ArrayList<Mine> mines;
private PlayerCharacter player; private PlayerCharacter player;
private boolean isTeleport; private boolean isTeleport;
@ -77,10 +80,19 @@ public class TeleportRepledgeListMsg extends ClientNetMsg {
public void configure() { public void configure() {
if (isTeleport) if (isTeleport) {
cities = City.getCitiesToTeleportTo(player); cities = City.getCitiesToTeleportTo(player);
else try {
mines = Mine.getMinesToTeleportTo(player);
if(mines == null)
mines = new ArrayList<>();
}catch(Exception e){
Logger.error("Unable To Load Mines For Teleport: " + e.getMessage());
}
}else {
cities = City.getCitiesToRepledgeTo(player); cities = City.getCitiesToRepledgeTo(player);
mines = new ArrayList<>();
}
} }
/** /**
@ -96,10 +108,14 @@ public class TeleportRepledgeListMsg extends ClientNetMsg {
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
writer.putInt(0); writer.putInt(0);
writer.putInt(cities.size()); writer.putInt(cities.size() + mines.size());
for (City city : cities) for (City city : cities)
City.serializeForClientMsg(city, writer); City.serializeForClientMsg(city, writer);
for(Mine mine : mines)
Mine.serializeForClientMsgTeleport(mine, writer);
} }
public PlayerCharacter getPlayer() { public PlayerCharacter getPlayer() {

43
src/engine/net/client/msg/VendorDialogMsg.java

@ -96,6 +96,11 @@ public class VendorDialogMsg extends ClientNetMsg {
return; return;
} }
if(npc.contractUUID == 1502040){ //enrollment officer
PlayerCharacter.unboxPlayer(playerCharacter);
}
// Restrict disc trainers to only characters who have // Restrict disc trainers to only characters who have
// tht disc applied. // tht disc applied.
@ -548,18 +553,50 @@ public class VendorDialogMsg extends ClientNetMsg {
// verify race valid for profession // verify race valid for profession
Race race = pc.getRace(); Race race = pc.getRace();
if(race.getRaceRuneID() == 1999) {
boolean valid = false;
switch(promoID){
case 2504:
case 2505:
case 2506:
case 2507:
case 2510:
case 2511:
case 2512:
case 2514:
case 2515:
case 2517:
case 2518:
case 2519:
case 2520:
case 2521:
valid = true;
break;
}
if(!valid)
return;
}
else {
if (race == null || !promo.isAllowedRune(race.getToken())) { if (race == null || !promo.isAllowedRune(race.getToken())) {
// TODO send client promotion error // TODO send client promotion error
return; return;
} }
}
// verify baseclass valid for profession // verify baseclass valid for profession
BaseClass bc = pc.getBaseClass(); BaseClass bc = pc.getBaseClass();
if (bc == null || !promo.isAllowedRune(bc.getToken())) { if (bc == null) {
// TODO send client promotion error // TODO send client promotion error
return; return;
} }
if(!promo.isAllowedRune(bc.getToken())){
if(!bc.getName().equals("Rogue") && !promo.getName().equals("Druid"))
return;
}
if(race.getRaceRuneID() != 1999) {
// verify gender // verify gender
if (promoID == 2511 && pc.isMale()) // Fury if (promoID == 2511 && pc.isMale()) // Fury
return; return;
@ -567,7 +604,7 @@ public class VendorDialogMsg extends ClientNetMsg {
return; return;
if (promoID == 2517 && !pc.isMale()) // Warlock if (promoID == 2517 && !pc.isMale()) // Warlock
return; return;
}
// Everything valid. Let's promote // Everything valid. Let's promote
pc.setPromotionClass(promo.getObjectUUID()); pc.setPromotionClass(promo.getObjectUUID());

49
src/engine/objects/AbstractCharacter.java

@ -31,6 +31,7 @@ import engine.net.ByteBufferWriter;
import engine.net.DispatchMessage; import engine.net.DispatchMessage;
import engine.net.client.msg.UpdateStateMsg; import engine.net.client.msg.UpdateStateMsg;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.powers.effectmodifiers.AbstractEffectModifier;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@ -91,17 +92,17 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
protected Resists resists = new Resists("Genric"); protected Resists resists = new Resists("Genric");
protected ConcurrentHashMap<String, JobContainer> timers; protected ConcurrentHashMap<String, JobContainer> timers;
protected ConcurrentHashMap<String, Long> timestamps; protected ConcurrentHashMap<String, Long> timestamps;
protected int atrHandOne; public int atrHandOne;
protected int atrHandTwo; protected int atrHandTwo;
protected int minDamageHandOne; public int minDamageHandOne;
protected int maxDamageHandOne; public int maxDamageHandOne;
protected int minDamageHandTwo; protected int minDamageHandTwo;
protected int maxDamageHandTwo; protected int maxDamageHandTwo;
protected float rangeHandOne; protected float rangeHandOne;
protected float rangeHandTwo; protected float rangeHandTwo;
protected float speedHandOne; protected float speedHandOne;
protected float speedHandTwo; protected float speedHandTwo;
protected int defenseRating; public int defenseRating;
protected boolean isActive; // <-Do not use this for deleting character! protected boolean isActive; // <-Do not use this for deleting character!
protected float altitude = 0; // 0=on terrain, 1=tier 1, 2=tier 2, etc. protected float altitude = 0; // 0=on terrain, 1=tier 1, 2=tier 2, etc.
protected ConcurrentHashMap<Integer, JobContainer> recycleTimers; protected ConcurrentHashMap<Integer, JobContainer> recycleTimers;
@ -496,8 +497,13 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
boolean canFly = false; boolean canFly = false;
PlayerBonuses bonus = flyer.getBonuses(); PlayerBonuses bonus = flyer.getBonuses();
if (bonus != null && !bonus.getBool(ModType.NoMod, SourceType.Fly) && bonus.getBool(ModType.Fly, SourceType.None) && flyer.isAlive()) if (bonus != null && !bonus.getBool(ModType.NoMod, SourceType.Fly) && bonus.getBool(ModType.Fly, SourceType.None) && flyer.isAlive()) {
canFly = true; canFly = true;
}
if(flyer.effects.containsKey("MoveBuff")){
canFly = false;
}
return canFly; return canFly;
@ -1187,10 +1193,15 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} }
} }
public final float modifyHealth( public final float modifyHealth(float value, final AbstractCharacter attacker, final boolean fromCost) {
final float value,
final AbstractCharacter attacker, if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){
final boolean fromCost) { value *= ((PlayerCharacter)attacker).ZergMultiplier;
} // Health modifications are modified by the ZergMechanic
if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){
value *= ((Mob)attacker).getOwner().ZergMultiplier;
}// Health modifications from pets are modified by the owner's ZergMechanic
try { try {
@ -1254,11 +1265,19 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} }
public final float modifyMana( public final float modifyMana(
final float value, float value,
final AbstractCharacter attacker, final AbstractCharacter attacker,
final boolean fromCost final boolean fromCost
) { ) {
if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){
value *= ((PlayerCharacter)attacker).ZergMultiplier;
} // Health modifications are modified by the ZergMechanic
if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){
value *= ((Mob)attacker).getOwner().ZergMultiplier;
}// Health modifications from pets are modified by the owner's ZergMechanic
if (!this.isAlive()) { if (!this.isAlive()) {
return 0f; return 0f;
} }
@ -1293,11 +1312,19 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
} }
public final float modifyStamina( public final float modifyStamina(
final float value, float value,
final AbstractCharacter attacker, final AbstractCharacter attacker,
final boolean fromCost final boolean fromCost
) { ) {
if(attacker != null && attacker.getObjectType().equals(GameObjectType.PlayerCharacter)){
value *= ((PlayerCharacter)attacker).ZergMultiplier;
} // Health modifications are modified by the ZergMechanic
if(attacker != null && attacker.getObjectType().equals(GameObjectType.Mob) && ((Mob)attacker).getOwner() != null){
value *= ((Mob)attacker).getOwner().ZergMultiplier;
}// Health modifications from pets are modified by the owner's ZergMechanic
if (!this.isAlive()) { if (!this.isAlive()) {
return 0f; return 0f;
} }

94
src/engine/objects/Blueprint.java

@ -17,6 +17,7 @@ import org.pmw.tinylog.Logger;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Objects;
/* @Summary - Blueprint class is used for determining /* @Summary - Blueprint class is used for determining
characteristics of instanced player owned characteristics of instanced player owned
@ -60,13 +61,12 @@ public class Blueprint {
this.name = rs.getString("MeshName"); this.name = rs.getString("MeshName");
this.icon = rs.getInt("Icon"); this.icon = rs.getInt("Icon");
this.buildingGroup = BuildingGroup.valueOf(rs.getString("BuildingGroup")); this.buildingGroup = BuildingGroup.valueOf(rs.getString("BuildingGroup"));
this.maxRank = rs.getInt("MaxRank");
this.maxSlots = rs.getInt("MaxSlots"); this.maxSlots = rs.getInt("MaxSlots");
this.rank1UUID = rs.getInt("Rank1UUID"); this.rank1UUID = rs.getInt("Rank1UUID");
this.rank3UUID = rs.getInt("Rank3UUID"); this.rank3UUID = rs.getInt("Rank3UUID");
this.rank7UUID = rs.getInt("Rank7UUID"); this.rank7UUID = rs.getInt("Rank7UUID");
this.destroyedUUID = rs.getInt("DestroyedUUID"); this.destroyedUUID = rs.getInt("DestroyedUUID");
this.maxRank = rs.getInt("MaxRank");
} }
// Accessors // Accessors
@ -108,9 +108,11 @@ public class Blueprint {
maxShrines = 2; maxShrines = 2;
break; break;
case 7: case 7:
case 8:
maxShrines = 3; maxShrines = 3;
break; break;
case 8:
maxShrines = 4;
break;
default: default:
maxShrines = 0; maxShrines = 0;
@ -167,20 +169,48 @@ public class Blueprint {
// based upon the building's current rank // based upon the building's current rank
public static int getNpcMaintCost(int rank) { public static int getNpcMaintCost(int rank) {
int maintCost = Integer.MAX_VALUE; return 0;
maintCost = (9730 * rank) + 1890;
return maintCost;
} }
public int getMaxRank() { public int getMaxRank() {
BuildingGroup bg = this.buildingGroup;
switch(bg){
case AMAZONHALL:
case CATHEDRAL:
case GREATHALL:
case KEEP:
case THIEFHALL:
case TEMPLEHALL:
case WIZARDHALL:
case ELVENHALL:
case ELVENSANCTUM:
case IREKEIHALL:
case FORESTHALL:
return 1;
}
return maxRank; return maxRank;
} }
public int getMaxSlots() { public int getMaxSlots() {
if (this.buildingGroup != null && this.buildingGroup.equals(BuildingGroup.BARRACK)) if (this.buildingGroup != null && this.buildingGroup.equals(BuildingGroup.BARRACK))
return 1; return 1;
if (this.buildingGroup != null && this.buildingGroup.equals(BuildingGroup.TOL))
return 4;
BuildingGroup bg = this.buildingGroup;
switch(bg){
case AMAZONHALL:
case CATHEDRAL:
case GREATHALL:
case KEEP:
case THIEFHALL:
case TEMPLEHALL:
case WIZARDHALL:
case ELVENHALL:
case ELVENSANCTUM:
case IREKEIHALL:
case FORESTHALL:
return 3;
}
return maxSlots; return maxSlots;
} }
@ -312,10 +342,24 @@ public class Blueprint {
return 0; return 0;
// Early exit for buildings with single or no slots // Early exit for buildings with single or no slots
if (this.maxSlots <= 1 && !this.buildingGroup.equals(BuildingGroup.TOL))
if (this.maxSlots <= 1)
return maxSlots; return maxSlots;
BuildingGroup bg = this.buildingGroup;
switch(bg.name()) {
case "AMAZONHALL":
case "CATHEDRAL":
case "GREATHALL":
case "THIEFHALL":
case "TEMPLEHALL":
case "WIZARDHALL":
case "ELVENHALL":
case "ELVENSANCTUM":
case "IREKEIHALL":
case "FORESTHALL":
return 3;
}
if (this.maxRank == 1 && currentRank == 1) if (this.maxRank == 1 && currentRank == 1)
return getMaxSlots(); return getMaxSlots();
@ -327,20 +371,22 @@ public class Blueprint {
break; break;
case 3: case 3:
case 4: case 4:
case 5:
case 6:
availableSlots = 2; availableSlots = 2;
break; break;
case 5:
case 6:
case 7: case 7:
availableSlots = 3; availableSlots = 3;
break; break;
case 8: case 8:
availableSlots = 1; availableSlots = 4;
break; break;
default: default:
availableSlots = 0; availableSlots = 0;
break; break;
} }
if(this.buildingGroup != null && this.buildingGroup.equals(BuildingGroup.TOL))
availableSlots += 1;
return availableSlots; return availableSlots;
} }
@ -603,26 +649,14 @@ public class Blueprint {
return this.blueprintUUID; return this.blueprintUUID;
} }
public int getMaintCost(int rank) { public int getMaintCost() {
int maintCost = Integer.MAX_VALUE; int maintCost = Integer.MAX_VALUE;
switch (this.buildingGroup) { if(this.buildingGroup.equals(BuildingGroup.TOL)){
case TOL: return 3000000;
case BARRACK: }else{
maintCost = (61500 * rank) + 19500; return 0;
break;
case SPIRE:
maintCost = (4800 * rank) + 1200;
break;
default:
if (maxRank == 1)
maintCost = 22500;
else
maintCost = (15900 * rank) + 3300;
break;
} }
return maintCost;
} }
} }

41
src/engine/objects/Building.java

@ -182,6 +182,22 @@ public class Building extends AbstractWorldObject {
this.setHealth(healthMax); this.setHealth(healthMax);
} }
if(!this.ownerIsNPC){
//add extra HP for city walls of R8 trees
City city = ZoneManager.getCityAtLocation(this.loc);
if(city != null){
Building ToL = city.getTOL();
if(ToL != null){
if(ToL.rank == 8){
float currentHealth = this.health.get();
float newHealth = (currentHealth/this.healthMax) * (this.healthMax * 1.1f);
this.healthMax *= 1.1f;
this.setHealth(newHealth);
}
}
}
}
// Null out blueprint if not needed (npc building) // Null out blueprint if not needed (npc building)
if (blueprintUUID == 0) if (blueprintUUID == 0)
@ -780,24 +796,9 @@ public class Building extends AbstractWorldObject {
public int getMaintCost() { public int getMaintCost() {
int maintCost = 0; if(this.getBlueprint() != null && this.getBlueprint().getBuildingGroup().equals(BuildingGroup.TOL))
return 3000000;
// Add cost for building structure else return 0;
maintCost += this.getBlueprint().getMaintCost(rank);
// Add costs associated with hirelings
for (AbstractCharacter npc : this.hirelings.keySet()) {
if (npc.getObjectType() != GameObjectType.NPC)
continue;
maintCost += Blueprint.getNpcMaintCost(npc.getRank());
}
return maintCost;
} }
public final void submitOpenDoorJob(int doorID) { public final void submitOpenDoorJob(int doorID) {
@ -836,6 +837,10 @@ public class Building extends AbstractWorldObject {
return this.meshScale; return this.meshScale;
} }
public void setMeshScale(Vector3f scale) {
this.meshScale = scale;
}
public final int getMeshUUID() { public final int getMeshUUID() {
return this.meshUUID; return this.meshUUID;
} }

5
src/engine/objects/CharacterItemManager.java

@ -610,6 +610,8 @@ public class CharacterItemManager {
if (i == null) if (i == null)
return false; return false;
i.stripCastableEnchants();
if (!this.doesCharOwnThisItem(i.getObjectUUID())) if (!this.doesCharOwnThisItem(i.getObjectUUID()))
return false; return false;
@ -1054,6 +1056,7 @@ public class CharacterItemManager {
// add to Bank // add to Bank
this.bank.add(i); this.bank.add(i);
i.addToCache(); i.addToCache();
i.stripCastableEnchants();
calculateWeights(); calculateWeights();
@ -1202,6 +1205,7 @@ public class CharacterItemManager {
calculateWeights(); calculateWeights();
i.stripCastableEnchants();
return true; return true;
} }
@ -2009,6 +2013,7 @@ public class CharacterItemManager {
if (item.getItemBase().getType().equals(ItemType.GOLD)) { if (item.getItemBase().getType().equals(ItemType.GOLD)) {
int amt = item.getNumOfItems(); int amt = item.getNumOfItems();
item.setNumOfItems(0); item.setNumOfItems(0);
item.stripCastableEnchants();
MobLoot ml = new MobLoot(this.absCharacter, amt); MobLoot ml = new MobLoot(this.absCharacter, amt);
ml.zeroItem(); ml.zeroItem();
ml.containerType = Enum.ItemContainerType.INVENTORY; ml.containerType = Enum.ItemContainerType.INVENTORY;

13
src/engine/objects/CharacterSkill.java

@ -992,6 +992,9 @@ public class CharacterSkill extends AbstractGameObject {
//Get Base skill for unmodified stats //Get Base skill for unmodified stats
float base = 7f; float base = 7f;
if(this.skillsBase.getToken() == -660435875){
base = 0;
}
float statMod = 0.5f; float statMod = 0.5f;
if (this.skillsBase.getStrMod() > 0) if (this.skillsBase.getStrMod() > 0)
statMod += (float) this.skillsBase.getStrMod() * (float) (int) ((PlayerCharacter) CharacterSkill.GetOwner(this)).statStrBase / 100f; statMod += (float) this.skillsBase.getStrMod() * (float) (int) ((PlayerCharacter) CharacterSkill.GetOwner(this)).statStrBase / 100f;
@ -1009,7 +1012,7 @@ public class CharacterSkill extends AbstractGameObject {
statMod = 600f; statMod = 600f;
base += CharacterSkill.baseSkillValues[(int) statMod]; base += CharacterSkill.baseSkillValues[(int) statMod];
if (base + bonus < 1f) if (base + bonus < 1f && this.skillsBase.getToken() != -660435875)
this.baseAmountBeforeMods = 1f; this.baseAmountBeforeMods = 1f;
else else
this.baseAmountBeforeMods = base + bonus; this.baseAmountBeforeMods = base + bonus;
@ -1084,6 +1087,9 @@ public class CharacterSkill extends AbstractGameObject {
//Get Base skill for modified stats //Get Base skill for modified stats
//TODO this fomula needs verified //TODO this fomula needs verified
float base = 7f; float base = 7f;
if(this.skillsBase.getToken() == -660435875){
base = 0;
}
float statMod = 0.5f; float statMod = 0.5f;
if (this.skillsBase.getStrMod() > 0) if (this.skillsBase.getStrMod() > 0)
statMod += (float) this.skillsBase.getStrMod() * (float) CharacterSkill.GetOwner(this).getStatStrCurrent() / 100f; statMod += (float) this.skillsBase.getStrMod() * (float) CharacterSkill.GetOwner(this).getStatStrCurrent() / 100f;
@ -1099,6 +1105,9 @@ public class CharacterSkill extends AbstractGameObject {
statMod = 1f; statMod = 1f;
else if (statMod > 600) else if (statMod > 600)
statMod = 600f; statMod = 600f;
if(this.skillsBase.getToken() == -660435875){
statMod = 0;
}
base += CharacterSkill.baseSkillValues[(int) statMod]; base += CharacterSkill.baseSkillValues[(int) statMod];
SourceType sourceType = SourceType.GetSourceType(this.skillsBase.getNameNoSpace()); SourceType sourceType = SourceType.GetSourceType(this.skillsBase.getNameNoSpace());
@ -1109,7 +1118,7 @@ public class CharacterSkill extends AbstractGameObject {
base += bonus + CharacterSkill.GetOwner(this).getBonuses().getFloat(ModType.Skill, sourceType); base += bonus + CharacterSkill.GetOwner(this).getBonuses().getFloat(ModType.Skill, sourceType);
} }
if (base < 1f) if (base < 1f && this.skillsBase.getToken() != -660435875)
this.baseAmount = 1f; this.baseAmount = 1f;
else else
this.baseAmount = base; this.baseAmount = base;

5
src/engine/objects/City.java

@ -289,8 +289,11 @@ public class City extends AbstractWorldObject {
else else
writer.putString(rulingNation.getName()); writer.putString(rulingNation.getName());
if(city.getTOL() != null) {
writer.putInt(city.getTOL().getRank()); writer.putInt(city.getTOL().getRank());
} else{
writer.putInt(1);
}
if (city.isNoobIsle > 0) if (city.isNoobIsle > 0)
writer.putInt(1); writer.putInt(1);
else else

95
src/engine/objects/Contract.java

@ -86,6 +86,15 @@ public class Contract extends AbstractGameObject {
this.iconID = rs.getInt("iconID"); this.iconID = rs.getInt("iconID");
this.vendorID = rs.getInt("vendorID"); this.vendorID = rs.getInt("vendorID");
this.allowedBuildings = EnumBitSet.asEnumBitSet(rs.getLong("allowedBuildingTypeID"), Enum.BuildingGroup.class); this.allowedBuildings = EnumBitSet.asEnumBitSet(rs.getLong("allowedBuildingTypeID"), Enum.BuildingGroup.class);
switch(this.contractID){
case 866: //banker
case 865: //siege engineer
case 899: //alchemist
this.allowedBuildings.add(Enum.BuildingGroup.TOL);
}
if(this.getName().toLowerCase().contains("sage")){
this.allowedBuildings.add(Enum.BuildingGroup.TOL);
}
this.equipmentSet = rs.getInt("equipSetID"); this.equipmentSet = rs.getInt("equipSetID");
this.inventorySet = rs.getInt("inventorySet"); this.inventorySet = rs.getInt("inventorySet");
@ -198,6 +207,92 @@ public class Contract extends AbstractGameObject {
} }
public ArrayList<MobEquipment> getSellInventory() { public ArrayList<MobEquipment> getSellInventory() {
if(this.getObjectUUID() == 900){ //resource merchant
for(MobEquipment me : this.sellInventory){
if(me.getItemBase().getType().equals(Enum.ItemType.RESOURCE)){
int amountResource = Warehouse.getSellStackSize(me.getItemBase().getUUID());
me.magicValue = amountResource * me.getItemBase().getBaseValue();
} else{
me.magicValue = 1000000;
}
}
}
if(this.getObjectUUID() == 1202){ //rune merchant
for(MobEquipment me : this.sellInventory){
switch(me.getItemBase().getUUID()){
case 250001: //5 stats
case 250010:
case 250019:
case 250028:
case 250037:
me.magicValue = 3000000;
break;
case 250002: //10 stats
case 250011:
case 250020:
case 250029:
case 250038:
me.magicValue = 4000000;
break;
case 250003: //15 stats
case 250012:
case 250021:
case 250030:
case 250039:
me.magicValue = 5000000;
break;
case 250004: //20 stats
case 250013:
case 250022:
case 250031:
case 250040:
me.magicValue = 6000000;
break;
case 250005: //25 stats
case 250014:
case 250023:
case 250032:
case 250041:
me.magicValue = 7000000;
break;
case 250006: //30 stats
case 250015:
case 250024:
case 250033:
case 250042:
me.magicValue = 8000000;
break;
case 250007: //35 stats
case 250016:
case 250025:
case 250034:
case 250043:
me.magicValue = 9000000;
break;
default:
me.magicValue = 10000000;
break;
}
}
}
if(this.getObjectUUID() == 1201){ //disc merchant
for(MobEquipment me : this.sellInventory){
if(me.getItemBase().getName().equals("Prospector")){
me.magicValue = 500000;
}else{
me.magicValue = 10000000;
}
}
}
if(this.getObjectUUID() == 1502041) {//noob helper{
for(MobEquipment me : this.sellInventory){
me.magicValue = 1;
}
}
return this.sellInventory; return this.sellInventory;
} }

39
src/engine/objects/Experience.java

@ -9,6 +9,7 @@
package engine.objects; package engine.objects;
import engine.Enum;
import engine.Enum.TargetColor; import engine.Enum.TargetColor;
import engine.gameManager.ZoneManager; import engine.gameManager.ZoneManager;
import engine.math.Vector3fImmutable; import engine.math.Vector3fImmutable;
@ -117,6 +118,11 @@ public class Experience {
159932666, // Level 74 159932666, // Level 74
169707808, // Level 75 169707808, // Level 75
179921247, // Level 76 179921247, // Level 76
190585732, // Level 77
201714185, // Level 78
213319687, // Level 79
225415457, // Level 80
238014819 // Level 81
}; };
@ -214,7 +220,14 @@ public class Experience {
235166.21f, // Level 72 235166.21f, // Level 72
246039.34f, // Level 73 246039.34f, // Level 73
257240.58f, // Level 74 257240.58f, // Level 74
1 // 268774.71 //Level 75 268774.71f, //Level 75
280647.69f, // Level 76
292865.22f, // Level 77
305433.33f, // Level 78
318358.08f, // Level 79
// R8
1 //331645.74f // Level 80
}; };
// Used to calcuate the amount of experience a monster grants in the // Used to calcuate the amount of experience a monster grants in the
@ -268,8 +281,8 @@ public class Experience {
if (level < 1) if (level < 1)
level = 1; level = 1;
if (level > 75) if (level > MBServerStatics.LEVELCAP)
level = 75; level = MBServerStatics.LEVELCAP;
return MaxExpPerLevel[level]; return MaxExpPerLevel[level];
} }
@ -279,17 +292,17 @@ public class Experience {
switch (TargetColor.getCon(pc, mob)) { switch (TargetColor.getCon(pc, mob)) {
case Red: case Red:
return 1.25; return 1.1;
case Orange: case Orange:
return 1.15; return 1.15;
case Yellow: case Yellow:
return 1.05; return 1.2;
case Blue: case Blue:
return 1; return 1.25;
case Cyan: case Cyan:
return 0.8; return 0.9;
case Green: case Green:
return 0.5; return 0.7;
default: default:
return 0; return 0;
} }
@ -383,6 +396,9 @@ public class Experience {
if (playerCharacter.getLevel() >= MBServerStatics.LEVELCAP) if (playerCharacter.getLevel() >= MBServerStatics.LEVELCAP)
continue; continue;
if(playerCharacter.level >= 75 && !mob.getObjectType().equals(Enum.GameObjectType.PlayerCharacter))
continue; // cannot PVE higher than level 75
// Sets Max XP with server exp mod taken into account. // Sets Max XP with server exp mod taken into account.
grantedExperience = (double) LOOTMANAGER.NORMAL_EXP_RATE * maxXPPerKill(playerCharacter.getLevel()); grantedExperience = (double) LOOTMANAGER.NORMAL_EXP_RATE * maxXPPerKill(playerCharacter.getLevel());
@ -428,12 +444,15 @@ public class Experience {
} }
} else { // Give EXP to a single character } else { // Give EXP to a single character
if (!killer.isAlive()) // Skip if the player is dead. //if (!killer.isAlive()) // Skip if the player is dead.
return; // return;
if (killer.getLevel() >= MBServerStatics.LEVELCAP) if (killer.getLevel() >= MBServerStatics.LEVELCAP)
return; return;
if(killer.level >= 75 && !mob.getObjectType().equals(Enum.GameObjectType.PlayerCharacter))
return;
// Get XP and adjust for Mob Level with world xp modifier taken into account // Get XP and adjust for Mob Level with world xp modifier taken into account
grantedExperience = (double) LOOTMANAGER.NORMAL_EXP_RATE * maxXPPerKill(killer.getLevel()); grantedExperience = (double) LOOTMANAGER.NORMAL_EXP_RATE * maxXPPerKill(killer.getLevel());
grantedExperience *= getConMod(killer, mob); grantedExperience *= getConMod(killer, mob);

10
src/engine/objects/Guild.java

@ -521,6 +521,10 @@ public class Guild extends AbstractWorldObject {
public void setICMOTD(String value) { public void setICMOTD(String value) {
this.icmotd = value; this.icmotd = value;
} }
public void setNMOTD(String value) {
this.nmotd = value;
}
public String getNMOTD(){return nmotd;}
public boolean isNPCGuild() { public boolean isNPCGuild() {
@ -752,9 +756,9 @@ public class Guild extends AbstractWorldObject {
canSub = false; canSub = false;
} }
City nationCap = City.getCity(nation.cityUUID); City nationCap = City.getCity(nation.cityUUID);
if (nation.getSubGuildList().size() >= nationCap.getRank()) { //if (nation.getSubGuildList().size() >= nationCap.getRank()) {
canSub = false; // canSub = false;
} //}
return canSub; return canSub;
} }

45
src/engine/objects/Item.java

@ -23,6 +23,7 @@ import engine.net.client.ClientConnection;
import engine.net.client.msg.DeleteItemMsg; import engine.net.client.msg.DeleteItemMsg;
import engine.powers.EffectsBase; import engine.powers.EffectsBase;
import engine.powers.effectmodifiers.AbstractEffectModifier; import engine.powers.effectmodifiers.AbstractEffectModifier;
import engine.powers.effectmodifiers.WeaponProcEffectModifier;
import engine.powers.poweractions.AbstractPowerAction; import engine.powers.poweractions.AbstractPowerAction;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@ -233,7 +234,6 @@ public class Item extends AbstractWorldObject {
this.value = rs.getInt("item_value"); this.value = rs.getInt("item_value");
this.customName = rs.getString("item_name"); this.customName = rs.getString("item_name");
} }
public static void _serializeForClientMsg(Item item, ByteBufferWriter writer) public static void _serializeForClientMsg(Item item, ByteBufferWriter writer)
@ -303,7 +303,7 @@ public class Item extends AbstractWorldObject {
writer.putString(item.customName); // Unknown. pad? writer.putString(item.customName); // Unknown. pad?
writer.put((byte) 1); // End Datablock byte writer.put((byte) 1); // End Datablock byte
writer.putFloat((float) item.durabilityMax); writer.putFloat((float) item.getDurabilityMax());
writer.putFloat((float) item.durabilityCurrent); writer.putFloat((float) item.durabilityCurrent);
writer.put((byte) 1); // End Datablock byte writer.put((byte) 1); // End Datablock byte
@ -609,7 +609,7 @@ public class Item extends AbstractWorldObject {
writer.putIntAt(serialized, indexPosition); writer.putIntAt(serialized, indexPosition);
} }
public static Item createItemForPlayer(PlayerCharacter pc, ItemBase ib) { public static Item createItemForPlayer(PlayerCharacter pc, ItemBase ib, boolean fromNoob) {
Item item = null; Item item = null;
byte charges = 0; byte charges = 0;
@ -817,8 +817,29 @@ public class Item extends AbstractWorldObject {
return ownerID; return ownerID;
} }
public void stripCastableEnchants(){
ArrayList<String> keys =new ArrayList<>();
for(String eff : this.effects.keySet()){
for(AbstractEffectModifier mod : this.effects.get(eff).getEffectsBase().getModifiers()){
if(mod.modType.equals(ModType.WeaponProc)){
keys.add(eff);
}
}
}
for(String eff : keys){
try {
this.effects.get(eff).endEffect();
this.effects.remove(eff);
}catch(Exception e){
}
}
}
//Only to be used for trading //Only to be used for trading
public void setOwnerID(int ownerID) { public void setOwnerID(int ownerID) {
this.stripCastableEnchants();
this.ownerID = ownerID; this.ownerID = ownerID;
} }
@ -842,6 +863,7 @@ public class Item extends AbstractWorldObject {
public boolean setOwner(AbstractGameObject owner) { public boolean setOwner(AbstractGameObject owner) {
if (owner == null) if (owner == null)
return false; return false;
this.stripCastableEnchants();
if (owner.getObjectType().equals(GameObjectType.NPC)) if (owner.getObjectType().equals(GameObjectType.NPC))
this.ownerType = OwnerType.Npc; this.ownerType = OwnerType.Npc;
else if (owner.getObjectType().equals(GameObjectType.PlayerCharacter)) else if (owner.getObjectType().equals(GameObjectType.PlayerCharacter))
@ -885,7 +907,15 @@ public class Item extends AbstractWorldObject {
} }
public short getDurabilityMax() { public short getDurabilityMax() {
return durabilityMax; int extra = 0;
for(Effect eff : this.effects.values()){
for(AbstractEffectModifier mod : eff.getEffectModifiers()){
if(mod.modType.equals(ModType.Durability)){
extra += mod.getMaxMod();
}
}
}
return (short)(durabilityMax + extra);
} }
public boolean isCanDestroy() { public boolean isCanDestroy() {
@ -948,6 +978,7 @@ public class Item extends AbstractWorldObject {
} }
public boolean isID() { public boolean isID() {
this.flags |= 1;
return ((this.flags & 1) > 0); return ((this.flags & 1) > 0);
} }
@ -1054,6 +1085,7 @@ public class Item extends AbstractWorldObject {
this.ownerID = pc.getObjectUUID(); this.ownerID = pc.getObjectUUID();
this.ownerType = OwnerType.PlayerCharacter; this.ownerType = OwnerType.PlayerCharacter;
this.containerType = ItemContainerType.INVENTORY; this.containerType = ItemContainerType.INVENTORY;
this.stripCastableEnchants();
return true; return true;
} }
@ -1074,6 +1106,7 @@ public class Item extends AbstractWorldObject {
this.ownerID = npc.getObjectUUID(); this.ownerID = npc.getObjectUUID();
this.ownerType = OwnerType.Npc; this.ownerType = OwnerType.Npc;
this.containerType = Enum.ItemContainerType.INVENTORY; this.containerType = Enum.ItemContainerType.INVENTORY;
this.stripCastableEnchants();
return true; return true;
} }
@ -1091,6 +1124,7 @@ public class Item extends AbstractWorldObject {
this.ownerID = 0; this.ownerID = 0;
this.ownerType = null; this.ownerType = null;
this.containerType = Enum.ItemContainerType.INVENTORY; this.containerType = Enum.ItemContainerType.INVENTORY;
this.stripCastableEnchants();
return true; return true;
} }
@ -1197,6 +1231,7 @@ public class Item extends AbstractWorldObject {
} }
public int getBaseValue() { public int getBaseValue() {
if (this.getItemBase() != null) if (this.getItemBase() != null)
return this.getItemBase().getBaseValue(); return this.getItemBase().getBaseValue();
return 0; return 0;
@ -1240,6 +1275,8 @@ public class Item extends AbstractWorldObject {
continue; continue;
} }
AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString()); AbstractPowerAction apa = PowersManager.getPowerActionByIDString(effect.getIDString());
if(apa != null)
apa.applyBakedInStatsForItem(this, this.getItemBase().getBakedInStats().get(token)); apa.applyBakedInStatsForItem(this, this.getItemBase().getBakedInStats().get(token));
} }
} }

149
src/engine/objects/ItemBase.java

@ -75,7 +75,6 @@ public class ItemBase {
private boolean isStrBased; private boolean isStrBased;
private ArrayList<Integer> animations = new ArrayList<>(); private ArrayList<Integer> animations = new ArrayList<>();
private ArrayList<Integer> offHandAnimations = new ArrayList<>(); private ArrayList<Integer> offHandAnimations = new ArrayList<>();
private boolean autoID = false;
/** /**
* ResultSet Constructor * ResultSet Constructor
@ -145,8 +144,6 @@ public class ItemBase {
} }
this.autoIDItemsCheck();
try { try {
DbManager.ItemBaseQueries.LOAD_ANIMATIONS(this); DbManager.ItemBaseQueries.LOAD_ANIMATIONS(this);
} catch (Exception e) { } catch (Exception e) {
@ -232,7 +229,79 @@ public class ItemBase {
AnniverseryGifts.add(5101060); AnniverseryGifts.add(5101060);
AnniverseryGifts.add(5101080); AnniverseryGifts.add(5101080);
//fate peddler presents
AnniverseryGifts.add(971012);
AnniverseryGifts.add(971013);
AnniverseryGifts.add(971014);
AnniverseryGifts.add(971015);
AnniverseryGifts.add(971016);
AnniverseryGifts.add(971017);
AnniverseryGifts.add(971018);
AnniverseryGifts.add(971019);
AnniverseryGifts.add(971020);
AnniverseryGifts.add(971021);
AnniverseryGifts.add(971022);
AnniverseryGifts.add(971023);
}
public static int getDiscPrice(int uuid) {
if(uuid == 3040)
return 500000;
else return 10000000;
}
public static int getStatPrice(int uuid) {
switch(uuid){
case 250001: //5 stats
case 250010:
case 250019:
case 250028:
case 250037:
return 3000000;
case 250002: //10 stats
case 250011:
case 250020:
case 250029:
case 250038:
return 4000000;
case 250003: //15 stats
case 250012:
case 250021:
case 250030:
case 250039:
return 5000000;
case 250004: //20 stats
case 250013:
case 250022:
case 250031:
case 250040:
return 6000000;
case 250005: //25 stats
case 250014:
case 250023:
case 250032:
case 250041:
return 7000000;
case 250006: //30 stats
case 250015:
case 250024:
case 250033:
case 250042:
return 8000000;
case 250007: //35 stats
case 250016:
case 250025:
case 250034:
case 250043:
return 9000000;
case 250008: //40 stats
case 250017:
case 250026:
case 250035:
case 250044:
return 10000000;
}
return 10000000;
} }
/* /*
@ -372,74 +441,10 @@ public class ItemBase {
return modTable; return modTable;
} }
public int getVendorType() {
return vendorType;
}
public void setVendorType(int vendorType) {
this.vendorType = vendorType;
}
public int getHashID() { public int getHashID() {
return hashID; return hashID;
} }
public void setHashID(int hashID) {
this.hashID = hashID;
}
private void autoIDItemsCheck() {
//AUto ID Vorg and Glass
switch (uuid) {
case 27550:
case 27560:
case 27580:
case 27590:
case 188500:
case 188510:
case 188520:
case 188530:
case 188540:
case 188550:
case 189100:
case 189110:
case 189120:
case 189130:
case 189140:
case 189150:
case 189510:
case 27600:
case 181840:
case 188700:
case 188720:
case 189550:
case 189560:
case 7000100:
case 7000110:
case 7000120:
case 7000130:
case 7000140:
case 7000150:
case 7000160:
case 7000170:
case 7000180:
case 7000190:
case 7000200:
case 7000210:
case 7000220:
case 7000230:
case 7000240:
case 7000250:
case 7000270:
case 7000280:
this.autoID = true;
break;
default:
this.autoID = false;
}
}
public boolean validForSkills(ConcurrentHashMap<String, CharacterSkill> skills) { public boolean validForSkills(ConcurrentHashMap<String, CharacterSkill> skills) {
CharacterSkill characterSkill; CharacterSkill characterSkill;
@ -906,12 +911,4 @@ public class ItemBase {
public void setOffHandAnimations(ArrayList<Integer> offHandAnimations) { public void setOffHandAnimations(ArrayList<Integer> offHandAnimations) {
this.offHandAnimations = offHandAnimations; this.offHandAnimations = offHandAnimations;
} }
public boolean isAutoID() {
return autoID;
}
public void setAutoID(boolean autoID) {
this.autoID = autoID;
}
} }

53
src/engine/objects/ItemFactory.java

@ -73,7 +73,7 @@ public class ItemFactory {
itemManager.updateInventory(); itemManager.updateInventory();
} }
public static Item fillForge(NPC npc, PlayerCharacter pc, int itemsToRoll, int itemID, int pToken, int sToken, String customName) { public static Item ResourceRoll(NPC npc, PlayerCharacter pc, int itemsToRoll, int itemID, int pToken, int sToken, String customName) {
String prefixString = ""; String prefixString = "";
String suffixString = ""; String suffixString = "";
@ -215,7 +215,7 @@ public class ItemFactory {
pi.setAmount(itemsToRoll); pi.setAmount(itemsToRoll);
pi.setRandom(false); pi.setRandom(false);
ItemQueue produced = ItemQueue.borrow(pi, (long) (time * Float.parseFloat(ConfigManager.MB_PRODUCTION_RATE.getValue()))); ItemQueue produced = ItemQueue.borrow(pi, (long) time);
ItemProductionManager.send(produced); ItemProductionManager.send(produced);
return ml; return ml;
@ -410,7 +410,7 @@ public class ItemFactory {
if (overdraft > 0 && !useWarehouse) { if (overdraft > 0 && !useWarehouse) {
if (pc != null) if (pc != null)
ErrorPopupMsg.sendErrorMsg(pc, "Not enough gold in building strongbox." + ib.getName()); ErrorPopupMsg.sendErrorMsg(pc, "Not enough gold in building strongbox. " + ib.getName());
return null; return null;
} }
@ -707,7 +707,7 @@ public class ItemFactory {
if (rollPrefix < 80) { if (rollPrefix < 80) {
int randomPrefix = LootManager.TableRoll(vendor.getLevel(), false); int randomPrefix = TableRoll(vendor.getLevel());
prefixEntry = ModTableEntry.rollTable(prefixTypeTable.modTableID, randomPrefix); prefixEntry = ModTableEntry.rollTable(prefixTypeTable.modTableID, randomPrefix);
if (prefixEntry != null) if (prefixEntry != null)
@ -722,7 +722,7 @@ public class ItemFactory {
if (rollSuffix < 80 || prefixEntry == null) { if (rollSuffix < 80 || prefixEntry == null) {
int randomSuffix = LootManager.TableRoll(vendor.getLevel(), false); int randomSuffix = TableRoll(vendor.getLevel());
suffixEntry = ModTableEntry.rollTable(suffixTypeTable.modTableID, randomSuffix); suffixEntry = ModTableEntry.rollTable(suffixTypeTable.modTableID, randomSuffix);
if (suffixEntry != null) if (suffixEntry != null)
@ -774,6 +774,43 @@ public class ItemFactory {
return toRoll; return toRoll;
} }
public static int TableRoll(int vendorLevel) {
// Calculate min and max based on mobLevel
int min = 60;
int max = 120;
switch(vendorLevel){
case 20:
min = 70;
max = 140;
break;
case 30:
min = 80;
max = 160;
break;
case 40:
min = 90;
max = 180;
break;
case 50:
min = 100;
max = 200;
break;
case 60:
min = 175;
max = 260;
break;
case 70:
min = 220;
max = 320;
break;
}
int roll = ThreadLocalRandom.current().nextInt(min, max + 1);
return roll;
}
public static MobLoot produceRandomRoll(NPC npc, PlayerCharacter pc, String prefixString, String suffixString, int itemID) { public static MobLoot produceRandomRoll(NPC npc, PlayerCharacter pc, String prefixString, String suffixString, int itemID) {
boolean useWarehouse = false; boolean useWarehouse = false;
@ -885,8 +922,8 @@ public class ItemFactory {
ItemBase goldIB = ItemBase.getGoldItemBase(); ItemBase goldIB = ItemBase.getGoldItemBase();
int baseCost = ib.getBaseValue(); //int baseCost = ib.getBaseValue();
int total = (int) (baseCost + baseCost * .10); int total = ib.getBaseValue();
EffectsBase suffix = null; EffectsBase suffix = null;
@ -899,7 +936,7 @@ public class ItemFactory {
//calculate gold costs and remove from the warehouse //calculate gold costs and remove from the warehouse
if (prefix != null || suffix != null) { if (prefix != null || suffix != null) {
int costToCreate = (int) (ib.getBaseValue() + ib.getBaseValue() * .10f); int costToCreate = ib.getBaseValue();
int buildingWithdraw = BuildingManager.GetWithdrawAmountForRolling(forge, costToCreate); int buildingWithdraw = BuildingManager.GetWithdrawAmountForRolling(forge, costToCreate);
int overdraft = BuildingManager.GetOverdraft(forge, costToCreate); int overdraft = BuildingManager.GetOverdraft(forge, costToCreate);

385
src/engine/objects/Mine.java

@ -10,11 +10,11 @@
package engine.objects; package engine.objects;
import engine.Enum; import engine.Enum;
import engine.InterestManagement.InterestManager;
import engine.InterestManagement.WorldGrid; import engine.InterestManagement.WorldGrid;
import engine.gameManager.BuildingManager; import engine.gameManager.*;
import engine.gameManager.ChatManager; import engine.math.Vector3f;
import engine.gameManager.DbManager; import engine.math.Vector3fImmutable;
import engine.gameManager.ZoneManager;
import engine.net.ByteBufferWriter; import engine.net.ByteBufferWriter;
import engine.net.client.msg.ErrorPopupMsg; import engine.net.client.msg.ErrorPopupMsg;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
@ -25,6 +25,9 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static engine.gameManager.DbManager.MineQueries; import static engine.gameManager.DbManager.MineQueries;
@ -51,6 +54,18 @@ public class Mine extends AbstractGameObject {
private int buildingID; private int buildingID;
private MineProduction mineType; private MineProduction mineType;
public int openHour;
public int openMinute;
public int capSize;
public LocalDateTime liveTime;
public final HashSet<Integer> _playerMemory = new HashSet<>();
public ArrayList<PlayerCharacter> affectedPlayers = new ArrayList<>();
//stronghold stuff
public boolean isStronghold = false;
public ArrayList<Mob> strongholdMobs;
public HashMap<Integer,Integer> oldBuildings;
/** /**
* ResultSet Constructor * ResultSet Constructor
*/ */
@ -90,7 +105,15 @@ public class Mine extends AbstractGameObject {
this.production = Resource.valueOf(rs.getString("mine_resource")); this.production = Resource.valueOf(rs.getString("mine_resource"));
this.lastClaimer = null; this.lastClaimer = null;
this.openHour = rs.getInt("mineLiveHour");
this.openMinute = rs.getInt("mineLiveMinute");
this.capSize = rs.getInt("capSize");
this.liveTime = LocalDateTime.now().withHour(this.openHour).withMinute(this.openMinute);
Building tower = BuildingManager.getBuildingFromCache(this.buildingID);
if(tower != null){
tower.setMaxHitPoints(5000f * this.capSize);
tower.setCurrentHitPoints(tower.healthMax);
}
} }
public static void releaseMineClaims(PlayerCharacter playerCharacter) { public static void releaseMineClaims(PlayerCharacter playerCharacter) {
@ -143,9 +166,11 @@ public class Mine extends AbstractGameObject {
ArrayList<Mine> serverMines = MineQueries.GET_ALL_MINES_FOR_SERVER(); ArrayList<Mine> serverMines = MineQueries.GET_ALL_MINES_FOR_SERVER();
for (Mine mine : serverMines) { for (Mine mine : serverMines) {
if(mine.capSize != 0) {
Mine.mineMap.put(mine, mine.buildingID); Mine.mineMap.put(mine, mine.buildingID);
Mine.towerMap.put(mine.buildingID, mine); Mine.towerMap.put(mine.buildingID, mine);
} }
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -161,57 +186,59 @@ public class Mine extends AbstractGameObject {
} }
public static void serializeForClientMsg(Mine mine, ByteBufferWriter writer) { public static void serializeForClientMsg(Mine mine, ByteBufferWriter writer) {
try {
writer.putInt(mine.getObjectType().ordinal()); writer.putInt(mine.getObjectType().ordinal());
writer.putInt(mine.getObjectUUID()); writer.putInt(mine.getObjectUUID());
writer.putInt(mine.getObjectUUID()); //actually a hash of mine writer.putInt(mine.getObjectUUID()); //actually a hash of mine
if(mine.isStronghold){
writer.putString("STRONGHOLD");
writer.putString("");
}else {
writer.putString(mine.mineType.name); writer.putString(mine.mineType.name);
writer.putString(mine.zoneName); writer.putString(mine.capSize + " Man ");
}
//writer.putString(mine.zoneName + " " + mine.capSize + " Man ");
writer.putInt(mine.production.hash); writer.putInt(mine.production.hash);
writer.putInt(mine.production.baseProduction); writer.putInt(mine.production.baseProduction);
writer.putInt(mine.getModifiedProductionAmount()); //TODO calculate range penalty here writer.putInt(mine.getModifiedProductionAmount()); //TODO calculate range penalty here
writer.putInt(3600); //window in seconds writer.putInt(3600); //window in seconds
// Errant mines are currently open. Set time to now. LocalDateTime mineOpenTime = LocalDateTime.now().withHour(mine.openHour).withMinute(mine.openMinute).withSecond(0).withNano(0);
LocalDateTime mineOpenTime = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
// Mine times are those of the nation not individual guild.
Guild mineNatonGuild = mine.getOwningGuild().getNation();
// Adjust the serialized mine time based upon whether
// the Guild's mine window has passed or not and if it was claimed.
// If a mine is active serialize current datetime irrespective
// of any claim.
if (mineNatonGuild.isEmptyGuild() == false && mine.isActive == false) {
int guildWOO = mineNatonGuild.getNation().getMineTime();
LocalDateTime guildMineTime = mineOpenTime.withHour(guildWOO);
if (mineOpenTime.isAfter(guildMineTime) || mine.wasClaimed == true)
mineOpenTime = guildMineTime.plusDays(1);
else
mineOpenTime = guildMineTime;
}
writer.putLocalDateTime(mineOpenTime); writer.putLocalDateTime(mineOpenTime);
writer.putLocalDateTime(mineOpenTime.plusHours(1)); writer.putLocalDateTime(mineOpenTime.plusMinutes(30));
writer.put(mine.isActive ? (byte) 0x01 : (byte) 0x00); writer.put(mine.isActive ? (byte) 0x01 : (byte) 0x00);
Building mineTower = BuildingManager.getBuilding(mine.buildingID); Building mineTower = BuildingManager.getBuilding(mine.buildingID);
if (mineTower != null) {
writer.putFloat(mineTower.getLoc().x); writer.putFloat(mineTower.getLoc().x);
writer.putFloat(mineTower.getParentZone().getLoc().y); writer.putFloat(mineTower.getParentZone().getLoc().y);
writer.putFloat(mineTower.getLoc().z); writer.putFloat(mineTower.getLoc().z);
} else {
writer.putFloat(mine.parentZone.getLoc().x);
writer.putFloat(mine.parentZone.getLoc().y);
writer.putFloat(mine.parentZone.getLoc().z);
Logger.error("Mine Tower Was Null For Mine: " + mine.getObjectUUID());
}
writer.putInt(mine.isExpansion() ? mine.mineType.xpacHash : mine.mineType.hash); writer.putInt(mine.isExpansion() ? mine.mineType.xpacHash : mine.mineType.hash);
if (mine.isStronghold) {
writer.putString("");
GuildTag._serializeForDisplay(Guild.getErrantGuild().getGuildTag(), writer);
writer.putString("");
GuildTag._serializeForDisplay(Guild.getErrantGuild().getGuildTag(), writer);
}else {
writer.putString(mine.guildName); writer.putString(mine.guildName);
GuildTag._serializeForDisplay(mine.guildTag, writer); GuildTag._serializeForDisplay(mine.guildTag, writer);
writer.putString(mine.nationName); writer.putString(mine.nationName);
GuildTag._serializeForDisplay(mine.nationTag, writer); GuildTag._serializeForDisplay(mine.nationTag, writer);
} }
} catch (Exception e) {
Logger.error("Failed TO Serialize Mine Because: " + e.getMessage());
}
}
public static ArrayList<Mine> getMinesForGuild(int guildID) { public static ArrayList<Mine> getMinesForGuild(int guildID) {
@ -220,8 +247,7 @@ public class Mine extends AbstractGameObject {
// Only inactive mines are returned. // Only inactive mines are returned.
for (Mine mine : Mine.mineMap.keySet()) { for (Mine mine : Mine.mineMap.keySet()) {
if (mine.owningGuild.getObjectUUID() == guildID && if (mine.owningGuild.getObjectUUID() == guildID)
mine.isActive == false)
mineList.add(mine); mineList.add(mine);
} }
return mineList; return mineList;
@ -290,24 +316,18 @@ public class Mine extends AbstractGameObject {
if (treeRank < 1) if (treeRank < 1)
return false; return false;
if (guildUnderMineLimit(playerGuild.getNation(), treeRank) == false) {
ErrorPopupMsg.sendErrorMsg(playerCharacter, "Your nation cannot support another mine.");
return false;
}
return true; return true;
} }
private static boolean guildUnderMineLimit(Guild playerGuild, int tolRank) { public static ArrayList<Mine> getMinesToTeleportTo(PlayerCharacter player) {
ArrayList<Mine> mines = new ArrayList<>();
int mineCnt = 0; for(Mine mine : Mine.getMines())
if(!mine.isActive)
mineCnt += Mine.getMinesForGuild(playerGuild.getObjectUUID()).size(); if(mine.getOwningGuild() != null)
if(mine.getOwningGuild().getNation().equals(player.getGuild().getNation()))
mines.add(mine);
for (Guild guild : playerGuild.getSubGuildList()) return mines;
mineCnt += Mine.getMinesForGuild(guild.getObjectUUID()).size();
return mineCnt <= tolRank;
} }
public boolean changeProductionType(Resource resource) { public boolean changeProductionType(Resource resource) {
@ -378,12 +398,24 @@ public class Mine extends AbstractGameObject {
Building building = BuildingManager.getBuildingFromCache(this.buildingID); Building building = BuildingManager.getBuildingFromCache(this.buildingID);
if (building != null && !this.isActive) if (building != null && !this.isActive)
building.isDeranking.compareAndSet(true, false); building.isDeranking.compareAndSet(true, false);
if(!isAc){
for(PlayerCharacter player : this.affectedPlayers){
try {
player.ZergMultiplier = 1.0f;
} catch(Exception e){
//something went wrong resetting zerg multiplier, maybe player was deleted?
}
}
}
} }
public boolean validForMine(Resource r) { public boolean validForMine(Resource r) {
if (this.mineType == null) if (this.mineType == null) {
Logger.error("Mine Was Null Setting Resources for Mine: " + this.getObjectUUID());
return false; return false;
return this.mineType.validForMine(r, this.isExpansion()); }
return this.mineType.validForMine(r);
} }
public void serializeForMineProduction(ByteBufferWriter writer) { public void serializeForMineProduction(ByteBufferWriter writer) {
@ -394,10 +426,10 @@ public class Mine extends AbstractGameObject {
writer.putString(this.mineType.name); writer.putString(this.mineType.name);
writer.putString(this.zoneName); writer.putString(this.zoneName);
writer.putInt(this.production.hash); writer.putInt(this.production.hash);
writer.putInt(this.production.baseProduction); writer.putInt(this.getModifiedProductionAmount());
writer.putInt(this.getModifiedProductionAmount()); //TODO calculate range penalty here writer.putInt(this.getModifiedProductionAmount()); //TODO calculate range penalty here
writer.putInt(3600); //window in seconds writer.putInt(3600); //window in seconds
writer.putInt(this.isExpansion() ? this.mineType.xpacHash : this.mineType.hash); writer.putInt(this.mineType.hash);
} }
@Override @Override
@ -538,41 +570,236 @@ public class Mine extends AbstractGameObject {
} }
public int getModifiedProductionAmount() { public int getModifiedProductionAmount() {
//TODO Calculate Distance modifications. ItemBase resourceBase = ItemBase.getItemBase(this.production.UUID);
if(resourceBase == null)
return 0;
int value = resourceBase.getBaseValue();
int amount = 0;
switch(this.capSize){
case 3:
amount = 1800000;
break;
case 5:
amount = 3000000;
break;
case 10:
amount = 6000000;
break;
case 20:
amount = 12000000;
break;
}
if(this.production.UUID == 7)
value = 1;
amount = amount / value;
return amount;
}
public void onEnter() {
Building tower = BuildingManager.getBuildingFromCache(this.buildingID);
if(tower == null)
return;
// Gather current list of players within the zone bounds
HashSet<AbstractWorldObject> currentPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, Enum.CityBoundsType.GRID.extents, MBServerStatics.MASK_PLAYER);
HashMap<Guild,ArrayList<PlayerCharacter>> charactersByNation = new HashMap<>();
ArrayList<Guild> updatedNations = new ArrayList<>();
for (AbstractWorldObject playerObject : currentPlayers) {
if (playerObject == null)
continue;
PlayerCharacter player = (PlayerCharacter) playerObject;
if(this.affectedPlayers.contains(player) == false)
this.affectedPlayers.add(player);
if(!this._playerMemory.contains(player.getObjectUUID())){
this._playerMemory.add(player.getObjectUUID());
}
Guild nation = player.guild.getNation();
if(charactersByNation.containsKey(nation)){
if(!charactersByNation.get(nation).contains(player)) {
charactersByNation.get(nation).add(player);
if(!updatedNations.contains(nation)){
updatedNations.add(nation);
}
}
}else{
ArrayList<PlayerCharacter> players = new ArrayList<>();
players.add(player);
charactersByNation.put(nation,players);
if(!updatedNations.contains(nation)){
updatedNations.add(nation);
}
}
}
for(Guild nation : updatedNations){
float multiplier = ZergManager.getCurrentMultiplier(charactersByNation.get(nation).size(),this.capSize);
for(PlayerCharacter player : charactersByNation.get(nation)){
player.ZergMultiplier = multiplier;
}
}
try
{
this.onExit(this._playerMemory);
}
catch(Exception ignored){
//calculate base values. }
int baseProduction = this.production.baseProduction; }
float baseModValue = this.production.baseProduction * .1f;
float rankModValue = this.production.baseProduction * .0143f;
float totalModded = 0;
//get Mine Building. private void onExit(HashSet<Integer> currentMemory) {
Building mineBuilding = BuildingManager.getBuilding(this.buildingID);
if (mineBuilding == null) Building tower = BuildingManager.getBuildingFromCache(this.buildingID);
return this.production.baseProduction; if(tower == null)
for (AbstractCharacter harvester : mineBuilding.getHirelings().keySet()) { return;
totalModded += baseModValue; ArrayList<Integer>toRemove = new ArrayList<>();
totalModded += rankModValue * harvester.getRank(); HashSet<AbstractWorldObject> currentPlayers = WorldGrid.getObjectsInRangePartial(tower.loc, Enum.CityBoundsType.GRID.extents, MBServerStatics.MASK_PLAYER);
for(Integer id : currentMemory){
PlayerCharacter pc = PlayerCharacter.getPlayerCharacter(id);
if(currentPlayers.contains(pc) == false){
toRemove.add(id);
pc.ZergMultiplier = 1.0f;
}
} }
//add base production on top;
totalModded += baseProduction;
//skip distance check for expansion.
if (this.isExpansion())
return (int) totalModded;
if (this.owningGuild.isEmptyGuild() == false) { // Remove players from city memory
if (this.owningGuild.getOwnedCity() != null) {
float distanceSquared = this.owningGuild.getOwnedCity().getLoc().distanceSquared2D(mineBuilding.getLoc());
if (distanceSquared > sqr(10000 * 3)) _playerMemory.removeAll(toRemove);
totalModded *= .25f;
else if (distanceSquared > sqr(10000 * 2))
totalModded *= .50f;
else if (distanceSquared > sqr(10000))
totalModded *= .75f;
} }
public static Building getTower(Mine mine){
Building tower = BuildingManager.getBuildingFromCache(mine.buildingID);
if(tower != null)
return tower;
else
return null;
} }
return (int) totalModded; public static void serializeForClientMsgTeleport(Mine mine, ByteBufferWriter writer) {
AbstractCharacter guildRuler;
Guild rulingGuild;
Guild rulingNation;
java.time.LocalDateTime dateTime1900;
// Cities aren't a mine without a TOL. Time to early exit.
// No need to spam the log here as non-existant TOL's are indicated
// during bootstrap routines.
Building tower = Mine.getTower(mine);
if (tower == null) {
Logger.error("NULL TOWER FOR " + mine.zoneName + " mine");
return;
} }
// Assign mine owner
if (tower.getOwner() != null)
guildRuler = tower.getOwner();
else
guildRuler = null;
// If is an errant tree, use errant guild for serialization.
// otherwise we serialize the soverign guild
if (guildRuler == null)
rulingGuild = Guild.getErrantGuild();
else
rulingGuild = guildRuler.getGuild();
rulingNation = rulingGuild.getNation();
// Begin Serialzing soverign guild data
writer.putInt(mine.getObjectType().ordinal());
writer.putInt(mine.getObjectUUID());
writer.putString(mine.zoneName + " Mine");
writer.putInt(rulingGuild.getObjectType().ordinal());
writer.putInt(rulingGuild.getObjectUUID());
writer.putString(rulingGuild.getName());
writer.putString("");
writer.putString(rulingGuild.getLeadershipType());
// Serialize guild ruler's name
// If tree is abandoned blank out the name
// to allow them a rename.
if (guildRuler == null)
writer.putString("");
else
writer.putString(guildRuler.getFirstName() + ' ' + guildRuler.getLastName());
writer.putInt(rulingGuild.getCharter());
writer.putInt(0); // always 00000000
writer.put((byte)0);
writer.put((byte) 1);
writer.put((byte) 1); // *** Refactor: What are these flags?
writer.put((byte) 1);
writer.put((byte) 1);
writer.put((byte) 1);
GuildTag._serializeForDisplay(rulingGuild.getGuildTag(), writer);
GuildTag._serializeForDisplay(rulingNation.getGuildTag(), writer);
writer.putInt(0);// TODO Implement description text
writer.put((byte) 1);
writer.put((byte) 0);
writer.put((byte) 1);
// Begin serializing nation guild info
if (rulingNation.isEmptyGuild()) {
writer.putInt(rulingGuild.getObjectType().ordinal());
writer.putInt(rulingGuild.getObjectUUID());
} else {
writer.putInt(rulingNation.getObjectType().ordinal());
writer.putInt(rulingNation.getObjectUUID());
}
// Serialize nation name
if (rulingNation.isEmptyGuild())
writer.putString("None");
else
writer.putString(rulingNation.getName());
writer.putInt(1);
writer.putInt(0xFFFFFFFF);
writer.putInt(0);
if (rulingNation.isEmptyGuild())
writer.putString(" ");
else
writer.putString(Guild.GetGL(rulingNation).getFirstName() + ' ' + Guild.GetGL(rulingNation).getLastName());
writer.putLocalDateTime(LocalDateTime.now());
if(tower != null) {
writer.putFloat(tower.loc.x);
writer.putFloat(tower.loc.y);
writer.putFloat(tower.loc.z);
} else{
writer.putFloat(0);
writer.putFloat(0);
writer.putFloat(0);
}
writer.putInt(0);
writer.put((byte) 1);
writer.put((byte) 0);
writer.putInt(0x64);
writer.put((byte) 0);
writer.put((byte) 0);
writer.put((byte) 0);
}
} }

45
src/engine/objects/MineProduction.java

@ -13,21 +13,19 @@ import java.util.HashMap;
public enum MineProduction { public enum MineProduction {
LUMBER("Lumber Camp", new HashMap<>(), Resource.WORMWOOD, 1618637196, 1663491950), LUMBER("Lumber Camp", new HashMap<>(), 1618637196, 1663491950),
ORE("Ore Mine", new HashMap<>(), Resource.OBSIDIAN, 518103023, -788976428), ORE("Ore Mine", new HashMap<>(), 518103023, -788976428),
GOLD("Gold Mine", new HashMap<>(), Resource.GALVOR, -662193002, -1227205358), MAGIC("Magic Mine", new HashMap<>(), 504746863, -1753567069),
MAGIC("Magic Mine", new HashMap<>(), Resource.BLOODSTONE, 504746863, -1753567069); GOLDMINE("Gold Mine", new HashMap<>(), -662193002, -1227205358);
public final String name; public final String name;
public final HashMap<Integer, Resource> resources; public final HashMap<Integer, Resource> resources;
public final Resource xpac;
public final int hash; public final int hash;
public final int xpacHash; public final int xpacHash;
MineProduction(String name, HashMap<Integer, Resource> resources, Resource xpac, int hash, int xpacHash) { MineProduction(String name, HashMap<Integer, Resource> resources,int hash, int xpacHash) {
this.name = name; this.name = name;
this.resources = resources; this.resources = resources;
this.xpac = xpac;
this.hash = hash; this.hash = hash;
this.xpacHash = xpacHash; this.xpacHash = xpacHash;
} }
@ -39,6 +37,7 @@ public enum MineProduction {
MineProduction.LUMBER.resources.put(1580005, Resource.OAK); MineProduction.LUMBER.resources.put(1580005, Resource.OAK);
MineProduction.LUMBER.resources.put(1580006, Resource.BRONZEWOOD); MineProduction.LUMBER.resources.put(1580006, Resource.BRONZEWOOD);
MineProduction.LUMBER.resources.put(1580007, Resource.MANDRAKE); MineProduction.LUMBER.resources.put(1580007, Resource.MANDRAKE);
MineProduction.LUMBER.resources.put(1580018, Resource.WORMWOOD);
} }
if (MineProduction.ORE.resources.size() == 0) { if (MineProduction.ORE.resources.size() == 0) {
MineProduction.ORE.resources.put(7, Resource.GOLD); MineProduction.ORE.resources.put(7, Resource.GOLD);
@ -46,14 +45,16 @@ public enum MineProduction {
MineProduction.ORE.resources.put(1580001, Resource.TRUESTEEL); MineProduction.ORE.resources.put(1580001, Resource.TRUESTEEL);
MineProduction.ORE.resources.put(1580002, Resource.IRON); MineProduction.ORE.resources.put(1580002, Resource.IRON);
MineProduction.ORE.resources.put(1580003, Resource.ADAMANT); MineProduction.ORE.resources.put(1580003, Resource.ADAMANT);
MineProduction.ORE.resources.put(1580019, Resource.OBSIDIAN);
} }
if (MineProduction.GOLD.resources.size() == 0) { if (MineProduction.GOLDMINE.resources.size() == 0) {
MineProduction.GOLD.resources.put(7, Resource.GOLD); MineProduction.GOLDMINE.resources.put(7, Resource.GOLD);
MineProduction.GOLD.resources.put(1580000, Resource.STONE); MineProduction.GOLDMINE.resources.put(1580000, Resource.STONE);
MineProduction.GOLD.resources.put(1580008, Resource.COAL); MineProduction.GOLDMINE.resources.put(1580008, Resource.COAL);
MineProduction.GOLD.resources.put(1580009, Resource.AGATE); MineProduction.GOLDMINE.resources.put(1580009, Resource.AGATE);
MineProduction.GOLD.resources.put(1580010, Resource.DIAMOND); MineProduction.GOLDMINE.resources.put(1580010, Resource.DIAMOND);
MineProduction.GOLD.resources.put(1580011, Resource.ONYX); MineProduction.GOLDMINE.resources.put(1580011, Resource.ONYX);
MineProduction.GOLDMINE.resources.put(1580017, Resource.GALVOR);
} }
if (MineProduction.MAGIC.resources.size() == 0) { if (MineProduction.MAGIC.resources.size() == 0) {
MineProduction.MAGIC.resources.put(7, Resource.GOLD); MineProduction.MAGIC.resources.put(7, Resource.GOLD);
@ -62,27 +63,25 @@ public enum MineProduction {
MineProduction.MAGIC.resources.put(1580014, Resource.ANTIMONY); MineProduction.MAGIC.resources.put(1580014, Resource.ANTIMONY);
MineProduction.MAGIC.resources.put(1580015, Resource.SULFUR); MineProduction.MAGIC.resources.put(1580015, Resource.SULFUR);
MineProduction.MAGIC.resources.put(1580016, Resource.QUICKSILVER); MineProduction.MAGIC.resources.put(1580016, Resource.QUICKSILVER);
MineProduction.MAGIC.resources.put(1580020, Resource.BLOODSTONE);
} }
} }
public static MineProduction getByName(String name) { public static MineProduction getByName(String name) {
if (name.toLowerCase().equals("lumber")) if (name.equalsIgnoreCase("lumber"))
return MineProduction.LUMBER; return MineProduction.LUMBER;
else if (name.toLowerCase().equals("ore")) else if (name.equalsIgnoreCase("ore"))
return MineProduction.ORE; return MineProduction.ORE;
else if (name.toLowerCase().equals("gold")) else if (name.equalsIgnoreCase("gold"))
return MineProduction.GOLD; return MineProduction.GOLDMINE;
else else
return MineProduction.MAGIC; return MineProduction.MAGIC;
} }
public boolean validForMine(Resource r, boolean isXpac) { public boolean validForMine(Resource r) {
if (r == null) if (r == null)
return false; return false;
if (this.resources.containsKey(r.UUID)) return this.resources.containsKey(r.UUID);
return true;
else
return isXpac && r.UUID == this.xpac.UUID;
} }

195
src/engine/objects/Mob.java

@ -48,6 +48,7 @@ import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup;
public class Mob extends AbstractIntelligenceAgent { public class Mob extends AbstractIntelligenceAgent {
public static ArrayList<Mob> discDroppers = new ArrayList<>();
private static final ReentrantReadWriteLock createLock = new ReentrantReadWriteLock(); private static final ReentrantReadWriteLock createLock = new ReentrantReadWriteLock();
private static final ConcurrentHashMap<Integer, Mob> mobMapByDBID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW); private static final ConcurrentHashMap<Integer, Mob> mobMapByDBID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
// Variables NOT to be stored in db // Variables NOT to be stored in db
@ -100,6 +101,14 @@ public class Mob extends AbstractIntelligenceAgent {
private DeferredPowerJob weaponPower; private DeferredPowerJob weaponPower;
private DateTime upgradeDateTime = null; private DateTime upgradeDateTime = null;
private boolean lootSync = false; private boolean lootSync = false;
public boolean StrongholdCommander = false;
public boolean StrongholdGuardian = false;
public Mine stronghold = null;
public boolean StrongholdEpic = false;
public boolean isDropper = false;
/** /**
@ -264,7 +273,7 @@ public class Mob extends AbstractIntelligenceAgent {
this.notEnemy = EnumBitSet.asEnumBitSet(rs.getLong("notEnemy"), Enum.MonsterType.class); this.notEnemy = EnumBitSet.asEnumBitSet(rs.getLong("notEnemy"), Enum.MonsterType.class);
this.enemy = EnumBitSet.asEnumBitSet(rs.getLong("enemy"), Enum.MonsterType.class); this.enemy = EnumBitSet.asEnumBitSet(rs.getLong("enemy"), Enum.MonsterType.class);
this.firstName = rs.getString("mob_name"); this.firstName = rs.getString("mob_name");
this.isDropper = rs.getInt("is_dropper") == 1;
if (this.firstName.isEmpty()) if (this.firstName.isEmpty())
this.firstName = this.mobBase.getFirstName(); this.firstName = this.mobBase.getFirstName();
@ -288,6 +297,12 @@ public class Mob extends AbstractIntelligenceAgent {
Logger.error("Mobile:" + this.dbID + ": " + e); Logger.error("Mobile:" + this.dbID + ": " + e);
} }
if(this.firstName.toLowerCase().equals("guardian commander") || this.firstName.toLowerCase().equals("elite guardian")|| this.firstName.toLowerCase().equals("guardian")|| this.firstName.toLowerCase().equals("commander")){
this.despawn();
this.removeFromCache();
DbManager.MobQueries.DELETE_MOB(this);
}
} }
public static void serializeMobForClientMsgOtherPlayer(Mob mob, ByteBufferWriter writer) throws SerializationException { public static void serializeMobForClientMsgOtherPlayer(Mob mob, ByteBufferWriter writer) throws SerializationException {
@ -560,6 +575,32 @@ public class Mob extends AbstractIntelligenceAgent {
return mob; return mob;
} }
public static Mob createStrongholdMob(int loadID, Vector3fImmutable spawn, Guild guild, boolean isMob, Zone parent, Building building, int contractID, String pirateName, int level) {
// Create a new Mob instance
Mob mobWithoutID = new Mob(pirateName, "", (short) 0, (short) 0, (short) 0, (short) 0, (short) 0, (short) 1, 0, false, false, false, spawn, spawn, Vector3fImmutable.ZERO, (short) 1, (short) 1, (short) 1, guild, (byte) 0, loadID, isMob, parent, building, contractID);
// Check if mobBase is null
if (mobWithoutID.mobBase == null)
return null;
// Set mob level
mobWithoutID.level = (short) level;
// Set the parent zone and parentZoneID
mobWithoutID.parentZone = parent;
mobWithoutID.parentZoneID = parent.getObjectUUID();
// If the mob is in a building, bind it to zero position
if (mobWithoutID.building != null)
mobWithoutID.bindLoc = Vector3fImmutable.ZERO;
// Avoid database actions and directly return the created mobWithoutID
mobWithoutID.setObjectTypeMask(MBServerStatics.MASK_MOB | mobWithoutID.getTypeMasks());
return mobWithoutID;
}
public static Mob createPet(int loadID, Guild guild, Zone parent, PlayerCharacter owner, short level) { public static Mob createPet(int loadID, Guild guild, Zone parent, PlayerCharacter owner, short level) {
MobBase mobBase = MobBase.getMobBase(loadID); MobBase mobBase = MobBase.getMobBase(loadID);
Mob mob = null; Mob mob = null;
@ -574,11 +615,11 @@ public class Mob extends AbstractIntelligenceAgent {
mob = new Mob(mobBase, guild, parent, level, owner, 0); mob = new Mob(mobBase, guild, parent, level, owner, 0);
if (mob.mobBase == null) if (mob.mobBase == null)
return null; return null;
mob.runAfterLoad();
Vector3fImmutable loc = owner.getLoc();
DbManager.addToCache(mob); DbManager.addToCache(mob);
mob.setPet(owner, true); mob.setPet(owner, true);
mob.setWalkMode(false); mob.setWalkMode(false);
mob.runAfterLoad();
} catch (Exception e) { } catch (Exception e) {
Logger.error(e); Logger.error(e);
@ -1215,6 +1256,10 @@ public class Mob extends AbstractIntelligenceAgent {
@Override @Override
public void killCharacter(AbstractCharacter attacker) { public void killCharacter(AbstractCharacter attacker) {
if(this.StrongholdGuardian || this.StrongholdCommander) {
ChatManager.chatSystemChannel(this.parentZone.getParent().getName() + "'s Stronghold Is Under Attack!");
StrongholdManager.CheckToEndStronghold(this.stronghold);
}
this.stopMovement(this.getMovementLoc()); this.stopMovement(this.getMovementLoc());
@ -1267,7 +1312,7 @@ public class Mob extends AbstractIntelligenceAgent {
} }
setLoc(newLoc); setLoc(newLoc);
this.region = AbstractWorldObject.GetRegionByWorldObject(this); this.region = Regions.GetRegionForTeleport(this.loc);//AbstractWorldObject.GetRegionByWorldObject(this);
//Next update will be end Loc, lets stop him here. //Next update will be end Loc, lets stop him here.
} }
@ -1404,6 +1449,10 @@ public class Mob extends AbstractIntelligenceAgent {
WorldGrid.RemoveWorldObject(this); WorldGrid.RemoveWorldObject(this);
this.charItemManager.clearInventory(); this.charItemManager.clearInventory();
if(this.StrongholdEpic && this.stronghold != null && this.stronghold.isActive)
this.stronghold.isActive = false;
//StrongholdManager.EndStronghold(this.stronghold);
} }
@Override @Override
@ -1465,11 +1514,31 @@ public class Mob extends AbstractIntelligenceAgent {
} catch (Exception e) { } catch (Exception e) {
Logger.error(e.getMessage()); Logger.error(e.getMessage());
} }
if(this.StrongholdCommander || this.StrongholdGuardian || this.StrongholdEpic){
Resists.calculateResists(this); this.setResists(new Resists("Elite"));
}else if(Mob.discDroppers.contains(this)) {
this.setResists(new Resists("Dropper"));
} else if(this.isDropper){
this.setResists(new Resists("Dropper"));
} else{
this.setResists(new Resists());
}
this.resists.calculateResists(this, false);
} }
public void calculateMaxHealthManaStamina() { public void calculateMaxHealthManaStamina() {
if(this.StrongholdCommander){
this.healthMax = 50000;
return;
} else if(this.StrongholdGuardian){
this.healthMax = 12500;
return;
} else if(this.StrongholdEpic){
this.healthMax = 250000;
return;
}
float h; float h;
float m; float m;
float s; float s;
@ -1527,6 +1596,46 @@ public class Mob extends AbstractIntelligenceAgent {
public void calculateAtrDefenseDamage() { public void calculateAtrDefenseDamage() {
if(this.StrongholdCommander){
this.maxDamageHandOne = 3500;
this.minDamageHandOne = 1500;
int atr = 3500;
int defense = 3500;
if (this.bonuses != null) {
defense = GetDefense(defense, this);
atr = GetAttackRating(atr, this);
}
this.defenseRating = defense;
this.atrHandOne = atr;
return;
} else if(this.StrongholdGuardian){
this.maxDamageHandOne = 1550;
this.minDamageHandOne = 750;
int atr = 1800;
int defense = 2200;
if (this.bonuses != null) {
defense = GetDefense(defense, this);
atr = GetAttackRating(atr, this);
}
this.defenseRating = defense;
this.atrHandOne = atr;
return;
} else if(this.StrongholdEpic){
this.maxDamageHandOne = 5000;
this.minDamageHandOne = 2500;
int atr = 5000;
int defense = 3500;
if (this.bonuses != null) {
defense = GetDefense(defense, this);
atr = GetAttackRating(atr, this);
}
this.defenseRating = defense;
this.atrHandOne = atr;
return;
}
if (this.charItemManager == null || this.equip == null) { if (this.charItemManager == null || this.equip == null) {
Logger.error("Player " + currentID + " missing skills or equipment"); Logger.error("Player " + currentID + " missing skills or equipment");
defaultAtrAndDamage(true); defaultAtrAndDamage(true);
@ -1539,7 +1648,7 @@ public class Mob extends AbstractIntelligenceAgent {
calculateAtrDamageForWeapon(this.equip.get(MBServerStatics.SLOT_MAINHAND), true); calculateAtrDamageForWeapon(this.equip.get(MBServerStatics.SLOT_MAINHAND), true);
} catch (Exception e) { } catch (Exception e) {
this.atrHandOne = (short) this.mobBase.getAttackRating(); this.atrHandOne = GetAttackRating(this.mobBase.getAttackRating(), this);
this.minDamageHandOne = (short) this.mobBase.getMinDmg(); this.minDamageHandOne = (short) this.mobBase.getMinDmg();
this.maxDamageHandOne = (short) this.mobBase.getMaxDmg(); this.maxDamageHandOne = (short) this.mobBase.getMaxDmg();
this.rangeHandOne = 6.5f; this.rangeHandOne = 6.5f;
@ -1552,7 +1661,7 @@ public class Mob extends AbstractIntelligenceAgent {
} catch (Exception e) { } catch (Exception e) {
this.atrHandTwo = (short) this.mobBase.getAttackRating(); this.atrHandTwo = GetAttackRating(this.mobBase.getAttackRating(), this);
this.minDamageHandTwo = (short) this.mobBase.getMinDmg(); this.minDamageHandTwo = (short) this.mobBase.getMinDmg();
this.maxDamageHandTwo = (short) this.mobBase.getMaxDmg(); this.maxDamageHandTwo = (short) this.mobBase.getMaxDmg();
this.rangeHandTwo = 6.5f; this.rangeHandTwo = 6.5f;
@ -1573,36 +1682,65 @@ public class Mob extends AbstractIntelligenceAgent {
// TODO add error log here // TODO add error log here
if (this.bonuses != null) { if (this.bonuses != null) {
defense = GetDefense((int)defense, this);
} else
Logger.error("Error: missing bonuses");
defense = (defense < 1) ? 1 : defense;
this.defenseRating = (short) (defense + 0.5f);
} catch (Exception e) {
Logger.info("Mobbase ID " + this.getMobBaseID() + " returned an error. Setting to Default Defense." + e.getMessage());
this.defenseRating = (short) this.mobBase.getDefense();
}
// calculate defense for equipment
if(this.isDropper || Mob.discDroppers.contains(this)){
this.defenseRating *= 2;
this.atrHandOne *= 2;
this.atrHandTwo *= 2;
this.minDamageHandOne *= 2;
this.minDamageHandTwo *= 2;
this.maxDamageHandOne *= 2;
this.maxDamageHandTwo *= 2;
}
}
public static int GetDefense(int defense, Mob mob){
// add any bonuses // add any bonuses
defense += (short) this.bonuses.getFloat(ModType.DCV, SourceType.None); defense += (short) mob.bonuses.getFloat(ModType.DCV, SourceType.None);
// Finally, multiply any percent modifiers. DO THIS LAST! // Finally, multiply any percent modifiers. DO THIS LAST!
float pos_Bonus = 1 + this.bonuses.getFloatPercentPositive(ModType.DCV, SourceType.None); float pos_Bonus = 1 + mob.bonuses.getFloatPercentPositive(ModType.DCV, SourceType.None);
defense = (short) (defense * pos_Bonus); defense = (short) (defense * pos_Bonus);
//Lucky rune applies next //Lucky rune applies next
float neg_Bonus = this.bonuses.getFloatPercentNegative(ModType.DCV, SourceType.None); float neg_Bonus = mob.bonuses.getFloatPercentNegative(ModType.DCV, SourceType.None);
defense = (short) (defense * (1 + neg_Bonus)); return (int) (defense * (1 + neg_Bonus));
}
public static int GetAttackRating(int attackRating, Mob mob){
// add any bonuses
attackRating += (short) mob.bonuses.getFloat(ModType.OCV, SourceType.None);
} else // Finally, multiply any percent modifiers. DO THIS LAST!
Logger.error("Error: missing bonuses");
defense = (defense < 1) ? 1 : defense; float pos_Bonus = 1 + mob.bonuses.getFloatPercentPositive(ModType.OCV, SourceType.None);
this.defenseRating = (short) (defense + 0.5f);
} catch (Exception e) {
Logger.info("Mobbase ID " + this.getMobBaseID() + " returned an error. Setting to Default Defense." + e.getMessage()); attackRating = (short) (attackRating * pos_Bonus);
this.defenseRating = (short) this.mobBase.getDefense();
} //Lucky rune applies next
// calculate defense for equipment
}
float neg_Bonus = mob.bonuses.getFloatPercentNegative(ModType.OCV, SourceType.None);
return (int) (attackRating * (1 + neg_Bonus));
}
private float getWeaponDefense(HashMap<Integer, MobEquipment> equipped) { private float getWeaponDefense(HashMap<Integer, MobEquipment> equipped) {
MobEquipment weapon = equipped.get(MBServerStatics.SLOT_MAINHAND); MobEquipment weapon = equipped.get(MBServerStatics.SLOT_MAINHAND);
@ -1929,6 +2067,13 @@ public class Mob extends AbstractIntelligenceAgent {
this.charItemManager = new CharacterItemManager(this); this.charItemManager = new CharacterItemManager(this);
this.loadInventory(); this.loadInventory();
if(this.isDropper){
this.setLevel((short)65);
this.setResists(new Resists("Dropper"));
this.atrHandOne *= 2;
this.atrHandTwo *= 2;
}
try { try {
if (this.equipmentSetID != 0) if (this.equipmentSetID != 0)
this.equip = MobBase.loadEquipmentSet(this.equipmentSetID); this.equip = MobBase.loadEquipmentSet(this.equipmentSetID);
@ -2263,5 +2408,9 @@ public class Mob extends AbstractIntelligenceAgent {
} }
} }
} }
public static void AddDiscDropper(Mob mob){
discDroppers.add(mob);
mob.setLevel((short)65);
mob.setResists(new Resists("Dropper"));
}
} }

4
src/engine/objects/MobEquipment.java

@ -34,7 +34,8 @@ public class MobEquipment extends AbstractGameObject {
private AbstractPowerAction suffix; private AbstractPowerAction suffix;
private int pValue; private int pValue;
private int sValue; private int sValue;
private int magicValue; int magicValue;
public boolean fromNoob = false;
private float dropChance = 0; private float dropChance = 0;
@ -106,7 +107,6 @@ public class MobEquipment extends AbstractGameObject {
public static void serializeForVendor(MobEquipment mobEquipment, ByteBufferWriter writer, float percent) throws SerializationException { public static void serializeForVendor(MobEquipment mobEquipment, ByteBufferWriter writer, float percent) throws SerializationException {
_serializeForClientMsg(mobEquipment, writer, false); _serializeForClientMsg(mobEquipment, writer, false);
int baseValue = mobEquipment.itemBase.getBaseValue() + mobEquipment.itemBase.getMagicValue();
writer.putInt(mobEquipment.magicValue); writer.putInt(mobEquipment.magicValue);
writer.putInt(mobEquipment.magicValue); writer.putInt(mobEquipment.magicValue);
} }

2
src/engine/objects/MobLoot.java

@ -77,7 +77,7 @@ public final class MobLoot extends Item {
this.setNumOfItems(quantity); this.setNumOfItems(quantity);
this.noSteal = noSteal; this.noSteal = noSteal;
this.setIsID(this.getItemBase().isAutoID()); this.setIsID(true);
// Class is 'final'; passing 'this' should be okay at the end of the constructor // Class is 'final'; passing 'this' should be okay at the end of the constructor

116
src/engine/objects/NPC.java

@ -122,7 +122,11 @@ public class NPC extends AbstractCharacter {
// this.buyPercent = rs.getFloat("npc_buyPercent"); // this.buyPercent = rs.getFloat("npc_buyPercent");
this.buyPercent = .33f; this.buyPercent = .33f;
if(ZoneManager.findSmallestZone(this.loc) != null && ZoneManager.findSmallestZone(this.loc).getSafeZone() == 1){
this.sellPercent = 0;
}else{
this.sellPercent = 1; this.sellPercent = 1;
}
this.setRot(new Vector3f(0, rs.getFloat("npc_rotation"), 0)); this.setRot(new Vector3f(0, rs.getFloat("npc_rotation"), 0));
@ -189,6 +193,18 @@ public class NPC extends AbstractCharacter {
serializeForClientMsgOtherPlayer(npc, writer); serializeForClientMsgOtherPlayer(npc, writer);
} }
public boolean isInSafeZone() {
Zone zone = ZoneManager.findSmallestZone(this.getLoc());
if (zone != null) {
return zone.getSafeZone() == (byte) 1;
}
return false;
//return this.safeZone;
}
public static void serializeForClientMsgOtherPlayer(NPC npc, ByteBufferWriter writer) public static void serializeForClientMsgOtherPlayer(NPC npc, ByteBufferWriter writer)
throws SerializationException { throws SerializationException {
@ -1180,7 +1196,7 @@ public class NPC extends AbstractCharacter {
} }
// Cannot roll items without a warehouse. // Cannot roll items without a warehouse.
// Due to the fact fillForge references the // Due to the fact ResourceRoll references the
// warehouse and early exits. *** Refactor??? // warehouse and early exits. *** Refactor???
serverZone = this.building.getParentZone(); serverZone = this.building.getParentZone();
@ -1214,7 +1230,7 @@ public class NPC extends AbstractCharacter {
if (isRandom) if (isRandom)
item = ItemFactory.randomRoll(this, player, amount, itemID); item = ItemFactory.randomRoll(this, player, amount, itemID);
else else
item = ItemFactory.fillForge(this, player, amount, itemID, pToken, sToken, customName); item = ItemFactory.ResourceRoll(this, player, amount, itemID, pToken, sToken, customName);
if (item == null) if (item == null)
return null; return null;
@ -1347,4 +1363,100 @@ public class NPC extends AbstractCharacter {
} }
} }
public ArrayList<MobEquipment> getSellInventorySteward() {
ArrayList<MobEquipment> smallList = new ArrayList<>();
for (MobEquipment me : this.contract.getSellInventory()) {
int rankRequired = 0;
if (me.getItemBase().getType().equals(Enum.ItemType.CONTRACT)) {
switch (me.getItemBase().getUUID()) {
case 866:
case 889:
case 860:
case 850:
case 892:
case 1502003:
case 890:
case 896:
rankRequired = 1;
break;
case 899:
case 801:
case 803:
case 802:
case 821:
case 810:
case 806:
case 818:
case 800:
rankRequired = 2;
break;
case 840:
case 848:
case 813:
case 805:
case 804:
case 838:
rankRequired = 3;
break;
case 815:
rankRequired = 4;
break;
case 847:
case 830:
case 820:
rankRequired = 6;
break;
case 865:
case 252637:
rankRequired = 7;
break;
case 1502002: // harvesters don't need to exist but might one day
case 1502001: //mine guards don't need to exist but might one day
continue;
}
if(me.getItemBase().getName().toLowerCase().contains("trainer") || me.getItemBase().getName().toLowerCase().contains("refiner")){
rankRequired = 5;
}
if (this.getRank() >= rankRequired)
smallList.add(me);
}
}
return smallList;
}
public ArrayList<MobEquipment> getSellInventoryBuilder() {
ArrayList<MobEquipment> smallList = new ArrayList<>();
int maxValue = 0;
switch(this.getRank()){
case 1:
maxValue = 300000;
break;
case 2:
maxValue = 450000;
break;
case 3:
maxValue = 550000;
break;
case 4:
maxValue = 650000;
break;
case 5:
maxValue = 1000000;
break;
case 6:
case 7:
maxValue = 999999999;
break;
}
for(MobEquipment me : this.contract.getSellInventory()){
if(me.getItemBase().getBaseValue() <= maxValue)
smallList.add(me);
}
return smallList;
}
} }

130
src/engine/objects/PlayerCharacter.java

@ -26,6 +26,7 @@ import engine.job.JobScheduler;
import engine.jobs.DeferredPowerJob; import engine.jobs.DeferredPowerJob;
import engine.jobs.FinishSpireEffectJob; import engine.jobs.FinishSpireEffectJob;
import engine.jobs.NoTimeJob; import engine.jobs.NoTimeJob;
import engine.jobs.RefreshGroupJob;
import engine.math.Bounds; import engine.math.Bounds;
import engine.math.FastMath; import engine.math.FastMath;
import engine.math.Vector3fImmutable; import engine.math.Vector3fImmutable;
@ -175,6 +176,10 @@ public class PlayerCharacter extends AbstractCharacter {
private boolean dirtyLoad = true; private boolean dirtyLoad = true;
private final ReadWriteLock dirtyLock = new ReentrantReadWriteLock(true); private final ReadWriteLock dirtyLock = new ReentrantReadWriteLock(true);
public float ZergMultiplier = 1.0f;
public boolean isBoxed = false;
/** /**
* No Id Constructor * No Id Constructor
*/ */
@ -780,6 +785,9 @@ public class PlayerCharacter extends AbstractCharacter {
// Verify Race // Verify Race
int raceID = msg.getRace(); int raceID = msg.getRace();
if(raceID == 0)
raceID = 1999;
Race race = Race.getRace(raceID); Race race = Race.getRace(raceID);
if (race == null) { if (race == null) {
@ -819,6 +827,7 @@ public class PlayerCharacter extends AbstractCharacter {
int hairColorID = msg.getHairColor(); int hairColorID = msg.getHairColor();
int beardColorID = msg.getBeardColor(); int beardColorID = msg.getBeardColor();
if(raceID != 1999) {
if (!race.isValidHairStyle(hairStyleID)) { if (!race.isValidHairStyle(hairStyleID)) {
Logger.info("Invalid HairStyleID: " + hairStyleID + " for race: " + race.getName()); Logger.info("Invalid HairStyleID: " + hairStyleID + " for race: " + race.getName());
return null; return null;
@ -838,7 +847,7 @@ public class PlayerCharacter extends AbstractCharacter {
Logger.info("Invalid beardColorID: " + beardColorID + " for race: " + race.getName()); Logger.info("Invalid beardColorID: " + beardColorID + " for race: " + race.getName());
return null; return null;
} }
}
// Get stat modifiers // Get stat modifiers
int strMod = msg.getStrengthMod(); int strMod = msg.getStrengthMod();
int dexMod = msg.getDexterityMod(); int dexMod = msg.getDexterityMod();
@ -926,11 +935,12 @@ public class PlayerCharacter extends AbstractCharacter {
} }
// Validate Rune against Race // Validate Rune against Race
if(raceID != 1999) {
if (!race.isAllowedRune(runeBase)) { if (!race.isAllowedRune(runeBase)) {
Logger.info("Trait Not valid for Race"); Logger.info("Trait Not valid for Race");
return null; return null;
} }
}
// Validate BaseClass against Race // Validate BaseClass against Race
if (!baseClass.isAllowedRune(runeBase)) { if (!baseClass.isAllowedRune(runeBase)) {
Logger.info("Trait Not valid for BaseClass"); Logger.info("Trait Not valid for BaseClass");
@ -1119,9 +1129,15 @@ public class PlayerCharacter extends AbstractCharacter {
int kitID = msg.getKit(); int kitID = msg.getKit();
// get the correctKit // get the correctKit
int raceClassID = Kit.GetKitIDByRaceClass(raceID, baseClassID); int raceClassID;
if(raceID != 1999){
raceClassID = Kit.GetKitIDByRaceClass(raceID, baseClassID);
}else{
raceClassID = Kit.GetKitIDByRaceClass(2011, baseClassID);
}
ArrayList<Kit> allKits = Kit.RaceClassIDMap.get(raceClassID); ArrayList<Kit> allKits = Kit.RaceClassIDMap.get(raceClassID);
Kit kit = null; Kit kit = null;
for (Kit k : allKits) { for (Kit k : allKits) {
@ -1151,6 +1167,13 @@ public class PlayerCharacter extends AbstractCharacter {
clientConnection); clientConnection);
return null; return null;
} }
if(raceID == 1999){
hairStyleID = 0;
beardStyleID = 0;
skinColorID = 0;
hairColorID = 0;
beardColorID = 0;
}
// Make PC // Make PC
PlayerCharacter pcWithoutID = new PlayerCharacter(firstName, lastName, (short) strMod, (short) dexMod, (short) conMod, PlayerCharacter pcWithoutID = new PlayerCharacter(firstName, lastName, (short) strMod, (short) dexMod, (short) conMod,
@ -1825,20 +1848,20 @@ public class PlayerCharacter extends AbstractCharacter {
//see if we shold grant xp to attacker //see if we shold grant xp to attacker
boolean doPVPEXP = false; boolean doPVPEXP = false;
long lastKill = att.getLastKillOfTarget(this.getObjectUUID()); long lastKill = att.getLastKillOfTarget(this.getObjectUUID());
if ((System.currentTimeMillis() - lastKill) > MBServerStatics.PLAYER_KILL_XP_TIMER) //if ((System.currentTimeMillis() - lastKill) > MBServerStatics.PLAYER_KILL_XP_TIMER)
if (attacker.getLevel() > 39 && this.getLevel() > 39) { //if (attacker.getLevel() > 39 && this.getLevel() > 39) {
Guild aN = null; //Guild aN = null;
Guild tN = null; //Guild tN = null;
if (attacker.getGuild() != null) //if (attacker.getGuild() != null)
aN = attacker.getGuild().getNation(); // aN = attacker.getGuild().getNation();
if (this.getGuild() != null) //if (this.getGuild() != null)
tN = this.getGuild().getNation(); // tN = this.getGuild().getNation();
if (aN == null || tN == null || aN.isEmptyGuild() || Guild.sameGuild(aN, tN) || this.isDeathShroud()) { //if (aN == null || tN == null || aN.isEmptyGuild() || Guild.sameGuild(aN, tN) || this.isDeathShroud()) {
//skip giving xp if same guild or attacker is errant, or target is in death shroud. //skip giving xp if same guild or attacker is errant, or target is in death shroud.
} else { //} else {
doPVPEXP = true; doPVPEXP = true;
} //}
} // }
//apply death shroud to non safeholds. //apply death shroud to non safeholds.
Zone zone = ZoneManager.findSmallestZone(this.getLoc()); Zone zone = ZoneManager.findSmallestZone(this.getLoc());
@ -2025,7 +2048,8 @@ public class PlayerCharacter extends AbstractCharacter {
public void respawn(boolean setAlive, boolean enterWorld, boolean makeCorpse) { public void respawn(boolean setAlive, boolean enterWorld, boolean makeCorpse) {
// Recalculate everything // Recalculate everything
if(this.timestamps.containsKey("DeathTime"))
this.timestamps.remove("DeathTime");
this.recalculatePlayerStats(true); this.recalculatePlayerStats(true);
this.setCombat(false); this.setCombat(false);
@ -4787,15 +4811,29 @@ public class PlayerCharacter extends AbstractCharacter {
return false; return false;
} }
private static void forceRespawn(PlayerCharacter sourcePlayer) throws MsgSendException {
if (sourcePlayer == null)
return;
sourcePlayer.getClientConnection().disconnect();
}
@Override @Override
public void update() { public void update() {
if (this.updateLock.writeLock().tryLock()) { if (this.updateLock.writeLock().tryLock()) {
try { try {
if (!this.isAlive()) if (!this.isAlive() && this.isEnteredWorld()) {
if(!this.timestamps.containsKey("DeathTime")){
this.timestamps.put("DeathTime",System.currentTimeMillis());
}
if((System.currentTimeMillis() - this.timestamps.get("DeathTime")) > 600000)
forceRespawn(this);
return; return;
}
updateLocation(); updateLocation();
updateMovementState(); updateMovementState();
updateRegen(); updateRegen();
@ -4811,6 +4849,25 @@ public class PlayerCharacter extends AbstractCharacter {
updateBlessingMessage(); updateBlessingMessage();
this.safeZone = this.isInSafeZone(); this.safeZone = this.isInSafeZone();
if(!this.timestamps.containsKey("nextBoxCheck"))
this.timestamps.put("nextBoxCheck", System.currentTimeMillis() + 10000);
if(!this.isBoxed && this.timestamps.get("nextBoxCheck") < System.currentTimeMillis()) {
this.isBoxed = checkIfBoxed(this);
this.timestamps.put("nextBoxCheck", System.currentTimeMillis() + 10000);
}
if(this.isBoxed && !this.containsEffect(1672601862)) {
PowersManager.applyPower(this, this, Vector3fImmutable.ZERO, 1672601862, 40, false);
}
if(this.isFlying()){
//if (!AbstractCharacter.CanFly(this)) {
if(this.effects.containsKey("MoveBuff")){
GroundPlayer(this);
//ChatManager.chatSystemInfo(this, "You Cannot Fly While Having A MovementBuff");
}
}
} catch (Exception e) { } catch (Exception e) {
Logger.error(e); Logger.error(e);
@ -4819,7 +4876,44 @@ public class PlayerCharacter extends AbstractCharacter {
} }
} }
} }
public static void unboxPlayer(PlayerCharacter player){
String machineID = player.getClientConnection().machineID;
ArrayList<PlayerCharacter> sameMachine = new ArrayList<>();
for(PlayerCharacter pc : SessionManager.getAllActivePlayerCharacters()){
if(!pc.equals(player) && pc. isActive && pc.isEnteredWorld() && pc.getClientConnection().machineID.equals(machineID)){
sameMachine.add(pc);
}
}
for(PlayerCharacter pc : sameMachine)
pc.isBoxed = true;
player.isBoxed = false;
if(player.containsEffect(1672601862)) {
player.removeEffectBySource(EffectSourceType.DeathShroud,41,false);
}
}
public static boolean checkIfBoxed(PlayerCharacter player){
try {
String machineID = player.getClientConnection().machineID;
ArrayList<PlayerCharacter> sameMachine = new ArrayList<>();
for (PlayerCharacter pc : SessionManager.getAllActivePlayerCharacters()) {
if (!pc.equals(player) && pc.isActive && pc.isEnteredWorld() && pc.getClientConnection().machineID.equals(machineID)) {
sameMachine.add(pc);
}
}
boolean boxed = false;
for (PlayerCharacter pc : sameMachine)
if (!pc.isBoxed)
boxed = true;
return boxed;
}catch(Exception e){
return false;
}
}
@Override @Override
public void updateFlight() { public void updateFlight() {

1
src/engine/objects/PromotionClass.java

@ -150,6 +150,7 @@ public class PromotionClass extends AbstractGameObject {
return true; return true;
} }
} }
return false; return false;
} }

108
src/engine/objects/Resists.java

@ -34,6 +34,24 @@ public class Resists {
private int protectionTrains = 0; private int protectionTrains = 0;
private boolean immuneToAll; private boolean immuneToAll;
public Resists() {
this.immuneToAll = false;
this.resists.put(DamageType.Slash, 0f);
this.resists.put(DamageType.Crush, 0f);
this.resists.put(DamageType.Pierce, 0f);
this.resists.put(DamageType.Magic, 0f);
this.resists.put(DamageType.Bleed, 0f);
this.resists.put(DamageType.Poison, 0f);
this.resists.put(DamageType.Mental, 0f);
this.resists.put(DamageType.Holy, 0f);
this.resists.put(DamageType.Unholy, 0f);
this.resists.put(DamageType.Lightning, 0f);
this.resists.put(DamageType.Fire, 0f);
this.resists.put(DamageType.Cold, 0f);
this.resists.put(DamageType.Healing, 0f);
this.immuneTo.put(DamageType.Siege, true);
}
/** /**
* Generic Constructor * Generic Constructor
*/ */
@ -46,6 +64,12 @@ public class Resists {
case "Mine": case "Mine":
setMineResists(); setMineResists();
break; break;
case "Dropper":
setDropperResists();
break;
case "Elite":
setEliteResists();
break;
default: default:
setGenericResists(); setGenericResists();
break; break;
@ -231,6 +255,42 @@ public class Resists {
this.resists.put(DamageType.Siege, 0f); this.resists.put(DamageType.Siege, 0f);
} }
public final void setDropperResists() {
this.immuneToAll = false;
this.resists.put(DamageType.Slash, 50f);
this.resists.put(DamageType.Crush, 50f);
this.resists.put(DamageType.Pierce, 50f);
this.resists.put(DamageType.Magic, 50f);
this.resists.put(DamageType.Bleed, 50f);
this.resists.put(DamageType.Poison, 50f);
this.resists.put(DamageType.Mental, 50f);
this.resists.put(DamageType.Holy, 50f);
this.resists.put(DamageType.Unholy, 50f);
this.resists.put(DamageType.Lightning, 50f);
this.resists.put(DamageType.Fire, 50f);
this.resists.put(DamageType.Cold, 50f);
this.resists.put(DamageType.Healing, 0f);
this.immuneTo.put(DamageType.Siege, true);
}
public final void setEliteResists() {
this.immuneToAll = false;
this.resists.put(DamageType.Slash, 75f);
this.resists.put(DamageType.Crush, 75f);
this.resists.put(DamageType.Pierce, 75f);
this.resists.put(DamageType.Magic, 75f);
this.resists.put(DamageType.Bleed, 75f);
this.resists.put(DamageType.Poison, 75f);
this.resists.put(DamageType.Mental, 75f);
this.resists.put(DamageType.Holy, 75f);
this.resists.put(DamageType.Unholy, 75f);
this.resists.put(DamageType.Lightning, 75f);
this.resists.put(DamageType.Fire, 75f);
this.resists.put(DamageType.Cold, 75f);
this.resists.put(DamageType.Healing, 0f);
this.immuneTo.put(DamageType.Siege, true);
}
/** /**
* Create generic resists * Create generic resists
*/ */
@ -394,7 +454,7 @@ public class Resists {
*/ */
public float getResistedDamage(AbstractCharacter source, AbstractCharacter target, DamageType type, float damage, int trains) { public float getResistedDamage(AbstractCharacter source, AbstractCharacter target, DamageType type, float damage, int trains) {
//handle fortitudes //handle fortitudes
damage = handleFortitude(target, type, damage); //damage = handleFortitude(target, type, damage);
//calculate armor piercing //calculate armor piercing
float ap = source.getBonuses().getFloatPercentAll(ModType.ArmorPiercing, SourceType.None); float ap = source.getBonuses().getFloatPercentAll(ModType.ArmorPiercing, SourceType.None);
float damageAfterResists = damage * (1 - (this.getResist(type, trains) * 0.01f) + ap); float damageAfterResists = damage * (1 - (this.getResist(type, trains) * 0.01f) + ap);
@ -417,6 +477,7 @@ public class Resists {
} }
target.cancelOnTakeDamage(type, (damageAfterResists)); target.cancelOnTakeDamage(type, (damageAfterResists));
} }
damageAfterResists = handleFortitude(target, type, damageAfterResists);
return damageAfterResists; return damageAfterResists;
} }
@ -426,6 +487,38 @@ public class Resists {
// get resists for runes // get resists for runes
PlayerBonuses rb = ac.getBonuses(); PlayerBonuses rb = ac.getBonuses();
float slash = 0f, crush = 0f, pierce = 0f, magic = 0f, bleed = 0f, mental = 0f, holy = 0f, unholy = 0f, poison = 0f, lightning = 0f, fire = 0f, cold = 0f, healing = 0f; float slash = 0f, crush = 0f, pierce = 0f, magic = 0f, bleed = 0f, mental = 0f, holy = 0f, unholy = 0f, poison = 0f, lightning = 0f, fire = 0f, cold = 0f, healing = 0f;
if(ac.getObjectType().equals(Enum.GameObjectType.Mob)){
Mob mob = (Mob)ac;
if(mob.StrongholdEpic || mob.StrongholdCommander || mob.StrongholdGuardian) {
slash = 75f;
crush = 75f;
pierce = 75f;
magic = 75f;
bleed = 75f;
mental = 75f;
holy = 75f;
unholy = 75f;
poison = 75f;
lightning = 75f;
fire = 75f;
cold = 75f;
healing = 0f;
} else if(Mob.discDroppers.contains(mob) || mob.isDropper) {
slash = 200f;
crush = 200f;
pierce = 200f;
magic = 200f;
bleed = 200f;
mental = 200f;
holy = 200f;
unholy = 200f;
poison = 200f;
lightning = 200f;
fire = 200f;
cold = 200f;
healing = 0f;
}
}
if (rb != null) { if (rb != null) {
// Handle immunities // Handle immunities
@ -465,19 +558,6 @@ public class Resists {
cold += rb.getFloat(ModType.Resistance, SourceType.Cold); cold += rb.getFloat(ModType.Resistance, SourceType.Cold);
healing += rb.getFloat(ModType.Resistance, SourceType.Healing); // DamageType.Healing.name()); healing += rb.getFloat(ModType.Resistance, SourceType.Healing); // DamageType.Healing.name());
//HHO
// String protectionString = rb.getString("protection");
//
// if (protectionString.isEmpty())
// this.protection = null;
// else try {
// this.protection = DamageType.valueOf(rb.getString("protection"));
// } catch (IllegalArgumentException e) {
// Logger.error( "No enum for: " + protectionString);
// this.protection = null;
// }
// this.protectionTrains = rb.getFloat("protection");
} }
// get resists from equipment // get resists from equipment

27
src/engine/objects/Shrine.java

@ -43,7 +43,7 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
public static boolean canTakeFavor(PlayerCharacter grantee, Shrine shrine) { public static boolean canTakeFavor(PlayerCharacter grantee, Shrine shrine) {
if (shrine.shrineType.isRace()) if (shrine.shrineType.isRace()) {
switch (grantee.getRaceID()) { switch (grantee.getRaceID()) {
case 2000: case 2000:
case 2001: case 2001:
@ -96,6 +96,7 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
case 2025: case 2025:
case 2026: case 2026:
case 1999:
if (shrine.shrineType == ShrineType.Nephilim) if (shrine.shrineType == ShrineType.Nephilim)
return true; return true;
break; break;
@ -106,7 +107,7 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
break; break;
} }
else }else {
switch (grantee.getPromotionClassID()) { switch (grantee.getPromotionClassID()) {
case 2504: case 2504:
if (shrine.shrineType == ShrineType.Assassin) if (shrine.shrineType == ShrineType.Assassin)
@ -197,7 +198,7 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
return true; return true;
break; break;
} }
}
return false; return false;
} }
@ -226,26 +227,6 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
} }
public void decay() {
if (this.getFavors() == 0)
return;
int decayAmount = (int) (this.getFavors() - (this.getFavors() * .10f));
if (decayAmount < 0)
decayAmount = 0;
if (!DbManager.ShrineQueries.updateFavors(this, decayAmount, this.getFavors())) {
Logger.error("Shrine Decay", "Error writing to DB. UUID: " + this.getObjectUUID());
return;
}
this.favors = decayAmount;
Logger.info(shrineType.name() + " uuid:" + this.getObjectUUID() + " Amount: " + this.getFavors() * .10f);
}
public synchronized boolean addFavor(PlayerCharacter boonOwner, Item boonItem) { public synchronized boolean addFavor(PlayerCharacter boonOwner, Item boonItem) {
if (boonOwner == null) if (boonOwner == null)

78
src/engine/objects/Warehouse.java

@ -281,6 +281,84 @@ public class Warehouse extends AbstractWorldObject {
} }
public static int getCostForResource(int id){
int newCost = 1;
switch(id){
case 1580000://stone
newCost = 3000;
break;
case 1580001://truesteel
newCost = 50000;
break;
case 1580002://iron
newCost = 50000;
break;
case 1580003://adamant
newCost = 100000;
break;
case 1580004://lumber
newCost = 3000;
break;
case 1580005://oak
newCost = 30000;
break;
case 1580006://bronzewood
newCost = 30000;
break;
case 1580007://mandrake
newCost = 100000;
break;
case 1580008://coal
newCost = 30000;
break;
case 1580009://agate
newCost = 50000;
break;
case 1580010://diamond
newCost = 50000;
break;
case 1580011://onyx
newCost = 100000;
break;
case 1580012://azoth
newCost = 50000;
break;
case 1580013://orichalk
newCost = 30000;
break;
case 1580014://antimony
newCost = 100000;
break;
case 1580015://sulfur
newCost = 100000;
break;
case 1580016://quicksilver
newCost = 100000;
break;
case 1580017://galvor
newCost = 300000;
break;
case 1580018://wormwood
newCost = 300000;
break;
case 1580019://obsidian
newCost = 200000;
break;
case 1580020://bloodstone
newCost = 200000;
break;
case 1705032:
newCost = 100000;
break;
}
return newCost;
}
public static int getSellStackSize(int id){
if(id == 1705032)
return 10;
return 3000000 / getCostForResource(id);
}
public ConcurrentHashMap<ItemBase, Integer> getResources() { public ConcurrentHashMap<ItemBase, Integer> getResources() {
return resources; return resources;
} }

5
src/engine/objects/Zone.java

@ -101,7 +101,6 @@ public class Zone extends AbstractGameObject {
if (hash == null) if (hash == null)
setHash(); setHash();
} }
public static void serializeForClientMsg(Zone zone, ByteBufferWriter writer) { public static void serializeForClientMsg(Zone zone, ByteBufferWriter writer) {
@ -113,8 +112,8 @@ public class Zone extends AbstractGameObject {
if (zone.playerCityID > 0) { if (zone.playerCityID > 0) {
writer.put((byte) 1); // Player City - True writer.put((byte) 1); // Player City - True
writer.putFloat(Enum.CityBoundsType.ZONE.extents); writer.putFloat(Enum.CityBoundsType.GRID.extents + 128);
writer.putFloat(Enum.CityBoundsType.ZONE.extents); writer.putFloat(Enum.CityBoundsType.GRID.extents + 128);
} else } else
writer.put((byte) 0); // Player City - False writer.put((byte) 0); // Player City - False

9
src/engine/powers/poweractions/RunegateTeleportPowerAction.java

@ -45,13 +45,10 @@ public class RunegateTeleportPowerAction extends AbstractPowerAction {
Vector3fImmutable rgLoc; Vector3fImmutable rgLoc;
for (Runegate runegate : Runegate._runegates.values()) { for (Runegate runegate : Runegate._runegates.values()) {
rgLoc = runegate.gateBuilding.getLoc(); rgLoc = runegate.gateBuilding.getLoc();
float disToGate = source.getLoc().distanceSquared2D(rgLoc);
float distanceToRunegateSquared = source.getLoc().distanceSquared2D(rgLoc); if(disToGate < dist){
dist = disToGate;
if (distanceToRunegateSquared < sqr(dist)) {
dist = sqrt(distanceToRunegateSquared);
rg = runegate.gateBuilding; rg = runegate.gateBuilding;
} }
} }

19
src/engine/powers/poweractions/StealPowerAction.java

@ -78,7 +78,7 @@ public class StealPowerAction extends AbstractPowerAction {
@Override @Override
protected void _startAction(AbstractCharacter source, AbstractWorldObject awo, Vector3fImmutable targetLoc, int trains, ActionsBase ab, PowersBase pb) { protected void _startAction(AbstractCharacter source, AbstractWorldObject awo, Vector3fImmutable targetLoc, int trains, ActionsBase ab, PowersBase pb) {
if (source == null || awo == null || !(source.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) || !(awo.getObjectType().equals(Enum.GameObjectType.Item))) if (source == null || awo == null || !(source.getObjectType().equals(Enum.GameObjectType.PlayerCharacter)))
return; return;
PlayerCharacter sourcePlayer = (PlayerCharacter) source; PlayerCharacter sourcePlayer = (PlayerCharacter) source;
@ -131,8 +131,23 @@ public class StealPowerAction extends AbstractPowerAction {
//Handle target attacking back if in combat and has no other target //Handle target attacking back if in combat and has no other target
CombatManager.handleRetaliate(ownerAC, sourcePlayer); CombatManager.handleRetaliate(ownerAC, sourcePlayer);
} else } else if (owner.getObjectType().equals(Enum.GameObjectType.Mob)){
Mob ownerMob = (Mob) owner;
if (ownerMob.isSafeMode() || sourcePlayer.inSafeZone())
return;
if (ownerMob.getLoc().distanceSquared(sourcePlayer.getLoc()) > sqr(MBServerStatics.LOOT_RANGE))
return;
//mark thief and target as player aggressive
sourcePlayer.setLastPlayerAttackTime();
//Handle target attacking back if in combat and has no other target
CombatManager.handleRetaliate(ownerAC, sourcePlayer);
}else{
return; return;
}
ClientConnection origin = sourcePlayer.getClientConnection(); ClientConnection origin = sourcePlayer.getClientConnection();

2
src/engine/server/MBServerStatics.java

@ -357,7 +357,7 @@ public class MBServerStatics {
public static final int COMBAT_SEND_DODGE = 20; public static final int COMBAT_SEND_DODGE = 20;
public static final int COMBAT_SEND_BLOCK = 21; public static final int COMBAT_SEND_BLOCK = 21;
public static final int COMBAT_SEND_PARRY = 22; public static final int COMBAT_SEND_PARRY = 22;
public static final short LEVELCAP = 75; public static final short LEVELCAP = 80;
public static final int LEVEL_CON_WHITE = 7; public static final int LEVEL_CON_WHITE = 7;
public static final int RESPAWN_TIMER = 90 * 1000; public static final int RESPAWN_TIMER = 90 * 1000;
public static final int DESPAWN_TIMER = 12 * 1000; public static final int DESPAWN_TIMER = 12 * 1000;

4
src/engine/server/login/LoginServer.java

@ -210,6 +210,8 @@ public class LoginServer {
nextServerTime = LocalDateTime.now().plusSeconds(1); nextServerTime = LocalDateTime.now().plusSeconds(1);
} }
//load realm for the server pop creation screen
if (LocalDateTime.now().isAfter(nextDatabaseTime)) { if (LocalDateTime.now().isAfter(nextDatabaseTime)) {
String pop = SimulationManager.getPopulationString(); String pop = SimulationManager.getPopulationString();
Logger.info("Keepalive: " + pop); Logger.info("Keepalive: " + pop);
@ -276,6 +278,8 @@ public class LoginServer {
Logger.info("Loading All Guilds"); Logger.info("Loading All Guilds");
DbManager.GuildQueries.GET_ALL_GUILDS(); DbManager.GuildQueries.GET_ALL_GUILDS();
Logger.info("Loading All Realms");
Realm.loadAllRealms();
Logger.info("***Boot Successful***"); Logger.info("***Boot Successful***");
return true; return true;

46
src/engine/server/world/WorldServer.java

@ -40,10 +40,7 @@ import engine.net.client.msg.chat.ChatSystemMsg;
import engine.objects.*; import engine.objects.*;
import engine.server.MBServerStatics; import engine.server.MBServerStatics;
import engine.util.ThreadUtils; import engine.util.ThreadUtils;
import engine.workthreads.DisconnectTrashTask; import engine.workthreads.*;
import engine.workthreads.HourlyJobThread;
import engine.workthreads.PurgeOprhans;
import engine.workthreads.WarehousePushThread;
import org.pmw.tinylog.Configurator; import org.pmw.tinylog.Configurator;
import org.pmw.tinylog.Level; import org.pmw.tinylog.Level;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@ -60,6 +57,7 @@ import java.nio.file.Paths;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Timer; import java.util.Timer;
@ -201,6 +199,7 @@ public class WorldServer {
LocalDateTime nextPopulationFileTime = LocalDateTime.now(); LocalDateTime nextPopulationFileTime = LocalDateTime.now();
LocalDateTime nextFlashTrashCheckTime = LocalDateTime.now(); LocalDateTime nextFlashTrashCheckTime = LocalDateTime.now();
LocalDateTime nextHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0).plusHours(1); LocalDateTime nextHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0).plusHours(1);
LocalDateTime nextHalfHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0);
LocalDateTime nextWareHousePushTime = LocalDateTime.now(); LocalDateTime nextWareHousePushTime = LocalDateTime.now();
// Begin execution of main game loop // Begin execution of main game loop
@ -232,6 +231,13 @@ public class WorldServer {
nextHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0).plusHours(1); nextHourlyJobTime = LocalDateTime.now().withMinute(0).withSecond(0).plusHours(1);
} }
if (LocalDateTime.now().isAfter(nextHalfHourlyJobTime)) {
Thread halfHourlyJobThread = new Thread(new HalfHourlyJobThread());
halfHourlyJobThread.setName("halfHourlyJob");
halfHourlyJobThread.start();
nextHalfHourlyJobTime = nextHalfHourlyJobTime.plusMinutes(30);
}
if (LocalDateTime.now().isAfter(nextWareHousePushTime)) { if (LocalDateTime.now().isAfter(nextWareHousePushTime)) {
Thread warehousePushThread = new Thread(new WarehousePushThread()); Thread warehousePushThread = new Thread(new WarehousePushThread());
warehousePushThread.setName("warehousePush"); warehousePushThread.setName("warehousePush");
@ -435,9 +441,6 @@ public class WorldServer {
Logger.info("Loading Max Skills for Trainers"); Logger.info("Loading Max Skills for Trainers");
DbManager.SkillsBaseQueries.LOAD_ALL_MAX_SKILLS_FOR_CONTRACT(); DbManager.SkillsBaseQueries.LOAD_ALL_MAX_SKILLS_FOR_CONTRACT();
//pick a startup Hotzone
ZoneManager.generateAndSetRandomHotzone();
Logger.info("Loading All Players from database to Server Cache"); Logger.info("Loading All Players from database to Server Cache");
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
@ -488,8 +491,8 @@ public class WorldServer {
MobRespawnThread.startRespawnThread(); MobRespawnThread.startRespawnThread();
// Run maintenance // Run maintenance
//moved this to hourly job thread to sustain no reboot system
MaintenanceManager.dailyMaintenance(); //MaintenanceManager.dailyMaintenance();
Logger.info("Starting Orphan Item Purge"); Logger.info("Starting Orphan Item Purge");
PurgeOprhans.startPurgeThread(); PurgeOprhans.startPurgeThread();
@ -497,7 +500,7 @@ public class WorldServer {
// Open/Close mines for the current window // Open/Close mines for the current window
Logger.info("Processing mine window."); Logger.info("Processing mine window.");
HourlyJobThread.processMineWindow(); HalfHourlyJobThread.processMineWindow();
// Calculate bootstrap time and rest boot time to current time. // Calculate bootstrap time and rest boot time to current time.
@ -593,12 +596,16 @@ public class WorldServer {
mobs = DbManager.MobQueries.GET_ALL_MOBS_FOR_ZONE(zone); mobs = DbManager.MobQueries.GET_ALL_MOBS_FOR_ZONE(zone);
for (Mob m : mobs) { for (Mob m : mobs) {
try{
m.setObjectTypeMask(MBServerStatics.MASK_MOB | m.getTypeMasks()); m.setObjectTypeMask(MBServerStatics.MASK_MOB | m.getTypeMasks());
m.setLoc(m.getLoc()); m.setLoc(m.getLoc());
//ADD GUARDS HERE. //ADD GUARDS HERE.
if (m.building != null && m.building.getBlueprint() != null && m.building.getBlueprint().getBuildingGroup() == BuildingGroup.BARRACK) if (m.building != null && m.building.getBlueprint() != null && m.building.getBlueprint().getBuildingGroup() == BuildingGroup.BARRACK)
DbManager.MobQueries.LOAD_PATROL_POINTS(m); DbManager.MobQueries.LOAD_PATROL_POINTS(m);
} catch (Exception e) {
Logger.error(m.getObjectUUID() + " returned an Error Message :" + e.getMessage());
}
} }
//Handle npc's //Handle npc's
@ -669,6 +676,22 @@ public class WorldServer {
delta = 60000; delta = 60000;
} }
//get additional logout timer for enemies nearby
if(!playerCharacter.isInSafeZone()){
HashSet<AbstractWorldObject> playersClose = WorldGrid.getObjectsInRangePartial(playerCharacter.loc,MBServerStatics.CHARACTER_LOAD_RANGE, MBServerStatics.MASK_PLAYER);
boolean enemiesClose = false;
for(AbstractWorldObject awo : playersClose){
PlayerCharacter pc = (PlayerCharacter)awo;
if(!pc.guild.getNation().equals(playerCharacter.guild.getNation()))
enemiesClose = true;
}
if(enemiesClose){
delta += 60000;
}
}
playerCharacter.stopMovement(playerCharacter.getLoc()); playerCharacter.stopMovement(playerCharacter.getLoc());
UpdateStateMsg updateStateMsg = new UpdateStateMsg(); UpdateStateMsg updateStateMsg = new UpdateStateMsg();
updateStateMsg.setPlayer(playerCharacter); updateStateMsg.setPlayer(playerCharacter);
@ -686,8 +709,7 @@ public class WorldServer {
playerCharacter.getLoadedStaticObjects().clear(); playerCharacter.getLoadedStaticObjects().clear();
LogoutCharacterJob logoutJob = new LogoutCharacterJob(playerCharacter, this); LogoutCharacterJob logoutJob = new LogoutCharacterJob(playerCharacter, this);
JobContainer jc = JobScheduler.getInstance().scheduleJob(logoutJob, JobContainer jc = JobScheduler.getInstance().scheduleJob(logoutJob, System.currentTimeMillis() + delta);
System.currentTimeMillis() + delta);
playerCharacter.getTimers().put("Logout", jc); playerCharacter.getTimers().put("Logout", jc);
playerCharacter.getTimestamps().put("logout", System.currentTimeMillis()); playerCharacter.getTimestamps().put("logout", System.currentTimeMillis());

174
src/engine/workthreads/HalfHourlyJobThread.java

@ -0,0 +1,174 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.workthreads;
import engine.Enum;
import engine.InterestManagement.WorldGrid;
import engine.db.archive.DataWarehouse;
import engine.db.archive.MineRecord;
import engine.gameManager.*;
import engine.net.DispatchMessage;
import engine.net.MessageDispatcher;
import engine.net.client.msg.chat.ChatSystemMsg;
import engine.objects.*;
import engine.server.world.WorldServer;
import org.pmw.tinylog.Logger;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import static engine.gameManager.StrongholdManager.EndStronghold;
import static engine.server.MBServerStatics.MINE_LATE_WINDOW;
public class HalfHourlyJobThread implements Runnable {
public HalfHourlyJobThread() {
}
public static void processMineWindow() {
try {
ArrayList<Mine> mines = Mine.getMines();
for(Mine mine : mines){
if (mine.isStronghold)
StrongholdManager.EndStronghold(mine);
}
for (Mine mine : mines) {
try {
//handle mines opening on server reboot weird time interval
if (LocalDateTime.now().isAfter(LocalDateTime.now().withHour(mine.openHour).withMinute(mine.openMinute))) {
if (LocalDateTime.now().isBefore(LocalDateTime.now().withHour(mine.openHour).withMinute(mine.openMinute).plusMinutes(30))) {
HalfHourlyJobThread.mineWindowOpen(mine);
continue;
}
}
// set to the current mine window.
if (mine.openHour == LocalDateTime.now().getHour() && mine.openMinute == LocalDateTime.now().getMinute() && !mine.wasClaimed) {
HalfHourlyJobThread.mineWindowOpen(mine);
continue;
}
// Close the mine if it reaches this far
LocalDateTime openTime = LocalDateTime.now().withHour(mine.openHour).withMinute(mine.openMinute);
if (LocalDateTime.now().plusMinutes(1).isAfter(openTime.plusMinutes(30)))
mineWindowClose(mine);
} catch (Exception e) {
Logger.error("mineID: " + mine.getObjectUUID(), e.toString());
}
}
//StrongholdManager.processStrongholds();
} catch (Exception e) {
Logger.error(e.toString());
}
}
public static void mineWindowOpen(Mine mine) {
mine.setActive(true);
ChatManager.chatSystemChannel(mine.getZoneName() + "'s Mine is now Active!");
Logger.info(mine.getZoneName() + "'s Mine is now Active!");
}
public static boolean mineWindowClose(Mine mine) {
// No need to end the window of a mine which never opened.
if (mine.isActive == false)
return false;
Building mineBuilding = BuildingManager.getBuildingFromCache(mine.getBuildingID());
if (mineBuilding == null) {
Logger.debug("Null mine building for Mine " + mine.getObjectUUID() + " Building " + mine.getBuildingID());
return false;
}
// Mine building still stands; nothing to do.
// We can early exit here.
if (mineBuilding.getRank() > 0) {
mine.setActive(false);
mine.lastClaimer = null;
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mine.guildName + " has defended the mine in " + mine.getParentZone().getParent().getName() + ". The mine is no longer active.");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
return true;
}
// This mine does not have a valid claimer
// we will therefore set it to errant
// and keep the window open.
if (!Mine.validateClaimer(mine.lastClaimer)) {
mine.lastClaimer = null;
mine.updateGuildOwner(null);
mine.setActive(true);
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mine.getParentZone().getParent().getName() + " Was not claimed, the battle rages on!");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
return false;
}
//Update ownership to map
mine.guildName = mine.getOwningGuild().getName();
mine.guildTag = mine.getOwningGuild().getGuildTag();
Guild nation = mine.getOwningGuild().getNation();
mine.nationName = nation.getName();
mine.nationTag = nation.getGuildTag();
mineBuilding.rebuildMine();
WorldGrid.updateObject(mineBuilding);
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mine.lastClaimer.getName() + " has claimed the mine in " + mine.getParentZone().getParent().getName() + " for " + mine.getOwningGuild().getName() + ". The mine is no longer active.");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
// Warehouse this claim event
MineRecord mineRecord = MineRecord.borrow(mine, mine.lastClaimer, Enum.RecordEventType.CAPTURE);
DataWarehouse.pushToWarehouse(mineRecord);
mineBuilding.setRank(mineBuilding.getRank());
mine.lastClaimer = null;
mine.setActive(false);
mine.wasClaimed = true;
for(Integer id : mine._playerMemory){
PlayerCharacter pc = PlayerCharacter.getFromCache(id);
if(pc != null)
pc.ZergMultiplier = 1.0f;
}
return true;
}
public void run() {
Logger.info("Half-Hourly job is now running.");
// Open or Close mines for the current mine window.
processMineWindow();
}
}

257
src/engine/workthreads/HourlyJobThread.java

@ -10,13 +10,8 @@
package engine.workthreads; package engine.workthreads;
import engine.Enum; import engine.Enum;
import engine.InterestManagement.WorldGrid;
import engine.db.archive.DataWarehouse;
import engine.db.archive.MineRecord;
import engine.gameManager.*; import engine.gameManager.*;
import engine.net.DispatchMessage;
import engine.net.MessageDispatcher; import engine.net.MessageDispatcher;
import engine.net.client.msg.chat.ChatSystemMsg;
import engine.objects.*; import engine.objects.*;
import engine.server.world.WorldServer; import engine.server.world.WorldServer;
import org.pmw.tinylog.Logger; import org.pmw.tinylog.Logger;
@ -25,240 +20,18 @@ import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static engine.server.MBServerStatics.MINE_LATE_WINDOW;
public class HourlyJobThread implements Runnable { public class HourlyJobThread implements Runnable {
public HourlyJobThread() { public HourlyJobThread() {
} }
public static void decayShrines() {
ArrayList<Shrine> shrineList = new ArrayList<>();
for (Shrine shrine : Shrine.shrinesByBuildingUUID.values()) {
try {
Building shrineBuilding = (Building) DbManager.getObject(Enum.GameObjectType.Building, shrine.getBuildingID());
if (shrineBuilding == null)
continue;
if (shrineBuilding.getOwner().equals(shrineBuilding.getCity().getOwner()) == false)
shrineBuilding.claim(shrineBuilding.getCity().getOwner());
} catch (Exception e) {
Logger.info("Shrine " + shrine.getBuildingID() + " Error " + e);
}
}
// Grab list of top two shrines of each type
for (Shrine shrine : Shrine.shrinesByBuildingUUID.values()) {
if (shrine.getRank() == 0 || shrine.getRank() == 1)
shrineList.add(shrine);
}
Logger.info("Decaying " + shrineList.size() + " shrines...");
// Top 2 shrines decay by 10% a day
for (Shrine shrine : shrineList) {
try {
shrine.decay();
} catch (Exception e) {
Logger.info("Shrine " + shrine.getBuildingID() + " Error " + e);
}
}
}
public static void processMineWindow() {
try {
ArrayList<Mine> mines = Mine.getMines();
for (Mine mine : mines) {
if (LocalDateTime.now().getHour() == 1400) {
mine.wasClaimed = false;
}
try {
// Open Errant Mines
if (mine.getOwningGuild().isEmptyGuild()) {
HourlyJobThread.mineWindowOpen(mine);
continue;
}
// Open Mines owned by nations having their WOO
// set to the current mine window.
if (mine.getOwningGuild().getNation().getMineTime() ==
LocalDateTime.now().getHour() && mine.wasClaimed == false) {
HourlyJobThread.mineWindowOpen(mine);
continue;
}
// Close the mine if it reaches this far
mineWindowClose(mine);
} catch (Exception e) {
Logger.error("mineID: " + mine.getObjectUUID(), e.toString());
}
}
} catch (Exception e) {
Logger.error(e.toString());
}
}
public static void mineWindowOpen(Mine mine) {
mine.setActive(true);
ChatManager.chatSystemChannel(mine.getZoneName() + "'s Mine is now Active!");
Logger.info(mine.getZoneName() + "'s Mine is now Active!");
}
public static boolean mineWindowClose(Mine mine) {
// No need to end the window of a mine which never opened.
if (mine.isActive == false)
return false;
Building mineBuilding = BuildingManager.getBuildingFromCache(mine.getBuildingID());
if (mineBuilding == null) {
Logger.debug("Null mine building for Mine " + mine.getObjectUUID() + " Building " + mine.getBuildingID());
return false;
}
// Mine building still stands; nothing to do.
// We can early exit here.
if (mineBuilding.getRank() > 0) {
mine.setActive(false);
mine.lastClaimer = null;
return true;
}
// This mine does not have a valid claimer
// we will therefore set it to errant
// and keep the window open.
if (!Mine.validateClaimer(mine.lastClaimer)) {
mine.lastClaimer = null;
mine.updateGuildOwner(null);
mine.setActive(true);
return false;
}
//Update ownership to map
mine.guildName = mine.getOwningGuild().getName();
mine.guildTag = mine.getOwningGuild().getGuildTag();
Guild nation = mine.getOwningGuild().getNation();
mine.nationName = nation.getName();
mine.nationTag = nation.getGuildTag();
mineBuilding.rebuildMine();
WorldGrid.updateObject(mineBuilding);
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mine.lastClaimer.getName() + " has claimed the mine in " + mine.getParentZone().getParent().getName() + " for " + mine.getOwningGuild().getName() + ". The mine is no longer active.");
chatMsg.setMessageType(10);
chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID());
DispatchMessage.dispatchMsgToAll(chatMsg);
// Warehouse this claim event
MineRecord mineRecord = MineRecord.borrow(mine, mine.lastClaimer, Enum.RecordEventType.CAPTURE);
DataWarehouse.pushToWarehouse(mineRecord);
mineBuilding.setRank(mineBuilding.getRank());
mine.lastClaimer = null;
mine.setActive(false);
mine.wasClaimed = true;
return true;
}
public void run() { public void run() {
// *** REFACTOR: TRY TRY TRY TRY {{{{{{{{{{{ OMG // *** REFACTOR: TRY TRY TRY TRY {{{{{{{{{{{ OMG
Logger.info("Hourly job is now running."); Logger.info("Hourly job is now running.");
try {
// Use the same hotZone this hour up and until
// the HotZone_Duration from the ConfigManager
if (ZoneManager.hotZone == null)
ZoneManager.generateAndSetRandomHotzone();
else
ZoneManager.hotZoneCycle = ZoneManager.hotZoneCycle + 1;
if (ZoneManager.hotZoneCycle > Integer.parseInt(ConfigManager.MB_HOTZONE_DURATION.getValue()))
ZoneManager.generateAndSetRandomHotzone();
if (ZoneManager.hotZone == null) {
Logger.error("Null HotZone returned from ZoneManager");
} else {
Logger.info("HotZone switched to: " + ZoneManager.hotZone.getName());
}
} catch (Exception e) {
Logger.error(e.toString());
}
// Open or Close mines for the current mine window.
processMineWindow();
// Deposit mine resources to Guilds
for (Mine mine : Mine.getMines()) {
try {
mine.depositMineResources();
} catch (Exception e) {
Logger.info(e.getMessage() + " for Mine " + mine.getObjectUUID());
}
}
// Reset time-gated access to WOO slider.
// *** Do this after the mines open/close!
if (LocalDateTime.now().getHour() == MINE_LATE_WINDOW) {
Guild guild;
for (AbstractGameObject dbObject : DbManager.getList(Enum.GameObjectType.Guild)) {
guild = (Guild) dbObject;
if (guild != null)
guild.wooWasModified = false;
}
}
// Mines can only be claimed once per cycle.
// This will reset at 1am after the last mine
// window closes.
if (LocalDateTime.now().getHour() == MINE_LATE_WINDOW + 1) {
for (Mine mine : Mine.getMines()) {
if (mine.wasClaimed == true)
mine.wasClaimed = false;
}
}
// Decay Shrines at midnight every day
if (LocalDateTime.now().getHour() == MINE_LATE_WINDOW)
decayShrines();
// Update city population values // Update city population values
ConcurrentHashMap<Integer, AbstractGameObject> map = DbManager.getMap(Enum.GameObjectType.City); ConcurrentHashMap<Integer, AbstractGameObject> map = DbManager.getMap(Enum.GameObjectType.City);
@ -280,6 +53,36 @@ public class HourlyJobThread implements Runnable {
Logger.error("missing city map"); Logger.error("missing city map");
} }
//run maintenance every day at 2 am
if(LocalDateTime.now().getHour() == 2) {
MaintenanceManager.dailyMaintenance();
//produce mine resources once a day
for (Mine mine : Mine.getMines()) {
try {
mine.depositMineResources();
} catch (Exception e) {
Logger.info(e.getMessage() + " for Mine " + mine.getObjectUUID());
}
mine.wasClaimed = false;
}
}
switch(LocalDateTime.now().getHour()){
case 3:
case 6:
case 9:
case 12:
case 15:
case 18:
case 21:
case 0:
for(Mob mob : Mob.discDroppers)
if(!mob.isAlive())
Zone.respawnQue.add(mob);
break;
}
// Log metrics to console // Log metrics to console
Logger.info(WorldServer.getUptimeString()); Logger.info(WorldServer.getUptimeString());
Logger.info(SimulationManager.getPopulationString()); Logger.info(SimulationManager.getPopulationString());

Loading…
Cancel
Save