Compare commits

...

105 Commits

Author SHA1 Message Date
Electroblob77 0328f41564 Prevent potion core applying its health fix (whatever that is) when resurrecting, fixes #178 2020-01-28 21:19:37 +00:00
Electroblob77 9ab4684aef Update version number 2020-01-28 19:44:27 +00:00
Electroblob77 e64cf9a6af Update credits 2020-01-28 18:44:37 +00:00
Electroblob77 f13f220564 Change tome of arcana description to be more accurate, closes #330. Also adds format args support to multi-line item descriptions and fixes the 1st argument being used instead of the 2nd in the lang files. 2020-01-28 18:36:34 +00:00
Electroblob77 311b5750df Add parrying mechanic to custom fireballs, fixes #335 2020-01-28 18:14:17 +00:00
Electroblob77 e54aee332d Rework slow time to use an NBT tag to unblock entity updates when not in a slow time zone, fixes #336 (and related issues with teleporting)
It also simplifies the code and removes the end slow time packet entirely
2020-01-28 13:20:32 +00:00
Electroblob77 e4bf09f15a Implement client-side spell counter for NPCs, fixes #345
Also makes all the continuous-spell-related methods in ISpellCaster default methods so they don't need implementing unless actually necessary.
2020-01-27 23:27:56 +00:00
Electroblob77 aa166814ea Add SpellThrowable and replace Snowball class with a simple instance of it 2020-01-27 18:40:10 +00:00
Electroblob77 d37ab6072f Add chainable method for assigning spell NPC selector 2020-01-27 17:51:32 +00:00
Electroblob77 ba83cb7985 Add chainable method for assigning spell items 2020-01-27 16:43:05 +00:00
Electroblob77 3052e56d03 Add entity- and tileentity-sensitive versions of Spell#canBeCastByNPCs and Spell#canBeCastByDispensers 2020-01-27 16:42:28 +00:00
Electroblob77 b682740751 *facepalm* 2020-01-27 15:09:54 +00:00
Electroblob77 38429cb697 Update credits 2020-01-27 14:50:55 +00:00
Electroblob77 dc7b6790b8 Automatic spell sound creation, hurrah! 2020-01-27 14:39:47 +00:00
Electroblob77 7a247df3e1 Encourage users to report the circular NBT reference error 2020-01-27 14:33:45 +00:00
Electroblob77 de2087c0e8 Clean up after testing 2020-01-27 13:46:50 +00:00
Electroblob77 f5da195605 Wrap NBTTagCompound#setTag in static helper with safeguards against circular references, fixes #299 2020-01-27 13:45:47 +00:00
Electroblob77 6cd6411c25 Use target lifetime rather than construct lifetime when dealing periodic damage; means targets don't all get damaged at once 2020-01-25 22:50:45 +00:00
Electroblob77 40e77728ad Do proper floaty division, the error was kinda invisible (pun intended) but intellij spotted it 2020-01-21 20:16:59 +00:00
Electroblob77 d50ff5729f Prevent unlimited exponential stacking of the empowerment effect, fixes #317 2020-01-16 18:40:52 +00:00
Electroblob77 76b4f2f72f Change default behaviour of Spell#createSoundWithSuffix to point to assets/modid/sounds.json rather than assets/ebwizardry/sounds.json, so addons don't have to override it 2020-01-14 14:39:09 +00:00
Electroblob77 a608375433 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2020-01-13 18:59:19 +00:00
Electroblob77 c3f8ba245d Fixing the really important bugs
(What? That pixel was annoying me...)
2020-01-13 18:58:21 +00:00
Electroblob77 34b3fe93bb Bit of an oversight there, this is supposed to be an API after all 2020-01-13 18:55:36 +00:00
Electroblob77 996ec9a7f7 Electroblob hit the ground too hard 2020-01-13 18:54:43 +00:00
Electroblob 2b38ca9a89 Merge pull request #331 from bigenergy/patch-2
Update russian lang
2019-12-31 11:02:52 +00:00
Big Energy 67788a2bd8 Ring translation 2019-12-27 20:23:35 +03:00
Big Energy 58fcaa8af2 Update ru_ru.lang 2019-12-27 20:09:30 +03:00
Big Energy 24e89c8b8a Update ru_ru.lang 2019-12-27 20:01:35 +03:00
Big Energy 1293b89905 Update ru_ru.lang 2019-12-27 19:55:41 +03:00
Electroblob77 807fc61541 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-12-22 18:39:45 +00:00
Electroblob77 9741c751b3 Update version number 2019-12-22 18:37:25 +00:00
Electroblob d3003ae473 Merge pull request #311 from Azim-Palmer/1.12.2
Adding support for Lycanites Mobs to drop loot from the mob_additions table
2019-12-22 18:25:52 +00:00
Electroblob77 9fde24f341 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-12-22 15:15:40 +00:00
Electroblob 452eb17b5f Update question.md 2019-12-22 15:13:57 +00:00
Electroblob 36963aac30 Update feature_request.md 2019-12-22 15:13:47 +00:00
Electroblob f161cdfe7c Update bug_report.md 2019-12-22 15:13:36 +00:00
Electroblob77 455c5a5e07 Fix weird floaty rounding so continuous spells cost the correct amount of mana
Grapple ain't free anymore, sorry folks!
2019-12-22 14:58:12 +00:00
Electroblob77 9852f61d0f Extend smoke bomb blindness effect to mobs as well as players, closes #324 2019-12-22 14:37:19 +00:00
Electroblob77 a2c8cde4c4 Use correct mana values for grand crystals and crystal shards in scroll creation 2019-12-22 12:30:04 +00:00
Electroblob77 497d28eafd Somehow this went missing... 2019-12-22 11:45:42 +00:00
Electroblob77 f3f3377c4d Fix formatting 2019-12-17 18:02:15 +00:00
Electroblob77 4c81c61644 Update credits 2019-12-17 18:01:04 +00:00
Electroblob77 31a6ab6db0 Update version number 2019-12-17 17:57:38 +00:00
Electroblob77 69f2aedef7 Correctly hide/unhide skin overlay parts when rendering frost layer, fixes #261 2019-12-17 17:52:44 +00:00
Electroblob77 e8818a4db5 Correct requested tag type for tower blocks list in wizard data loading, fixes #291 2019-12-17 17:45:27 +00:00
Electroblob77 470a7e82bc Iterate over copy of loaded TE list, fixes #298 and #304 2019-12-17 17:12:31 +00:00
Electroblob77 6439c233f1 Add creative mode check to target selector for summoned creatures, fixes #262 2019-12-17 16:55:00 +00:00
Electroblob77 c931d42d62 Tweaks to loot rarity 2019-12-17 16:35:34 +00:00
Electroblob77 5b497e107a Reinstate max damage check, fixes #294 2019-12-17 16:31:42 +00:00
Electroblob77 324094f418 'Tis the season!
- Decked the halls
- Jingled the bells
- Wrapped the presents
- Loaded up the sleigh
2019-12-17 15:53:40 +00:00
Electroblob77 9ade6442b2 Add config option to turn off growing crystal flowers with bonemeal, closes #308 2019-12-16 15:53:32 +00:00
Electroblob77 ffea49bc40 Copy neat fix for negative scaling of magic light on desync to black hole 2019-12-16 15:39:23 +00:00
Electroblob77 2b89a890d0 Route blink effect through the proxies and make the blink spell check for the first-person player, fixes #280 2019-12-16 15:25:15 +00:00
Electroblob77 3a67388ff3 Don't need that 2019-12-16 15:20:15 +00:00
Electroblob77 3468bbb073 Oops 2019-12-16 13:12:24 +00:00
Electroblob77 963178c609 Cleanup 2019-12-16 13:10:57 +00:00
Electroblob77 cfdb049368 Add failsafe for conjured item max damage, fixes #288 2019-12-16 13:06:32 +00:00
Electroblob77 058d83fd00 Stop ring of chaining attacking its wearer, fixes #303 2019-12-16 12:36:37 +00:00
Electroblob77 c7ccc37dca Add damage property to frost axe spell, fixes #322 2019-12-16 12:33:48 +00:00
Electroblob77 74345d0c3b Check if list is empty after removing current location, fixes #307 2019-12-16 12:18:46 +00:00
Electroblob77 907b94c74f Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-12-16 12:14:47 +00:00
Electroblob77 2c6b397be6 Check for null tile entities when rendering arcane lock, fixes #305 2019-12-16 12:14:43 +00:00
Electroblob77 eddcb2402d Don't use client-side-only vector-based AxisAlignedBB constructor, fixes #306 2019-12-16 12:14:01 +00:00
Electroblob 0301f3c300 Merge pull request #312 from Azim-Palmer/Fix/LayerRender
Fix : LayerRender breaks on non-standard models
2019-12-16 00:31:34 +00:00
Electroblob 7a8cfb73cd Merge pull request #319 from UltraHex/1.12.2
Fixes #170
2019-12-16 00:29:47 +00:00
Matthew William Noel c7c6f964bf Fix Electroblob77/Wizardry#170 the right way 2019-12-07 12:46:40 -08:00
Matthew William Noel 91df7cfd72 Fix Electroblob77/Wizardry#170 2019-12-06 19:54:55 -08:00
Az 0ed9ee64c4 Fix : when rendering models that don't have any entries in the boxList (Such as Lycanite's mobs) this function throws and exception and the renderer goes crazy. 2019-11-23 19:25:23 +00:00
Az f82d2871d5 Adding support for Lycanites Mobs to drop loot from the mob_additions table 2019-11-23 12:44:10 +00:00
Electroblob77 01cea3df06 Update version number 2019-10-05 23:14:29 +01:00
Electroblob77 591cfb5857 Check we're dealing with the type of mob whose class we're in, fixes #274 2019-10-05 23:13:48 +01:00
Electroblob77 bc2037f74e Update version number 2019-10-05 17:15:56 +01:00
Electroblob77 6aa3b21190 Convert all in-world sounds from stereo to mono, fixes #218 2019-10-05 17:12:33 +01:00
Electroblob77 b262b6edc0 Oops 2019-10-05 17:04:26 +01:00
Electroblob77 b7be05669b Increase health threshold for amulet of transience from 2 to 6, fixes #192 2019-10-05 16:43:17 +01:00
Electroblob77 071e299d48 Set evoker spell timer as well as spell type when under the arcane jammer effect, fixes #244 2019-10-05 16:40:57 +01:00
Electroblob77 1e885d70c3 Gently encourage people to disable structures the intended way, and stop it crashing if they try and do it the wrong way.
What's wrong with my structures anyway? :'(
2019-10-05 16:28:24 +01:00
Electroblob77 e04a43e56d Why on earth was that there?! Fixes #257 2019-10-05 15:46:05 +01:00
Electroblob77 378796cdda Make fast worldgen check the central position for water rather than checking the biome 2019-10-05 15:34:41 +01:00
Electroblob77 48c37d1c17 Helps if you actually use the synchronised random... fixes #245 2019-10-05 15:24:20 +01:00
Electroblob77 fe8f9fc5cd Update javadoc 2019-10-05 15:23:01 +01:00
Electroblob77 ced6ab7e8d Use a custom mesh definition instead of registering models for each individual metadata, fixes #256
#256 was partially fixed in 60a6c51; this completes the fix by preventing spell books missing models when different worlds have different spell metadata
2019-10-05 14:40:03 +01:00
Electroblob77 378e02eb6c Ignore special spawn conditions for mobs from mob spawners, fixes #260 2019-10-05 14:34:29 +01:00
Electroblob77 4677d9ff30 Unleash the full potential of spell properties files!
- Spell properties files can now be overridden globally in config/ebwizardry/spells
- Spell properties files can now be overridden for specific worlds in [world save]/data/spells
- Moved the main config file to the new ebwizardry folder because it makes more sense for it to be there now
- Probably broke something in the process
2019-10-02 20:13:44 +01:00
Electroblob77 0541b2171b Even more tweaks to progression 2019-10-02 20:04:17 +01:00
Electroblob77 dc59a14e82 Update .gitignore 2019-10-02 20:03:31 +01:00
Electroblob77 1a13afb6e3 Don't pass null into leaf update tick, fixes #186 and #269 2019-10-01 23:06:47 +01:00
Electroblob77 03dd76c18a Fix the blockpos passed into the block being the blockpos a block below the blockpos of the blockstate where the block was from, fixes #267
Easy mistake to make, but how has it avoided detection for so long...?
2019-09-30 11:30:53 +01:00
Electroblob77 9426a96df3 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-09-27 23:16:07 +01:00
Electroblob 382faf59c9 Update README.md 2019-09-27 23:15:53 +01:00
Electroblob cab68e23ac Rename guide_for_contributing.md to CONTRIBUTING.md 2019-09-27 23:14:43 +01:00
Electroblob77 60a6c5124e API improvements to spell books:
- Allow spells to set which book/scroll items they can appear on
- Allow spell books to set custom GUI textures
- Tweaks to loot functions and wizards to accommodate the changes
2019-09-27 15:46:09 +01:00
Electroblob77 028b753be6 Cleanup 2019-09-27 15:30:15 +01:00
Electroblob77 d020668e0c Update crystal ore picture in handbook 2019-09-27 12:57:55 +01:00
Electroblob77 656a78962e Rebalance progression yet again 2019-09-27 12:57:27 +01:00
Electroblob77 5a2f5aa295 Reimplement looting spell context 2019-09-27 12:55:31 +01:00
Electroblob 5e37a2322c Update CREDITS.md 2019-09-26 11:37:04 +01:00
Electroblob 3ca9f200fd Update README.md 2019-09-13 15:03:04 +01:00
Electroblob 37e3a842f5 Update README.md 2019-09-13 15:02:12 +01:00
Electroblob 4e8e2c951b Update README.md 2019-09-10 00:14:13 +01:00
Electroblob77 43b66df22a Update version number 2019-09-09 00:06:01 +01:00
Electroblob77 b192a431d7 Copy NBT to new stack in mana flask charging recipes, fixes #242 2019-09-09 00:03:38 +01:00
Electroblob77 3be98ab612 Fix JEI log spam about mana flask recharging recipes having empty output
Either JEI shouldn't be erroring or the Forge javadoc is wrong. Either way, it seems to make no difference so let's not bother with it.
2019-09-08 23:43:10 +01:00
Electroblob77 ed950322ff Temporarily disable the spells sound category to stop issue #238 from happening 2019-09-08 23:40:13 +01:00
197 changed files with 1549 additions and 659 deletions
+2 -2
View File
@@ -7,10 +7,10 @@ assignees: ''
---
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
Minecraft version: 1.12.2 [change as necessary]
Wizardry version: 4.2.2 [change as necessary]
Wizardry version: 4.2.8 [change as necessary]
Environment: Singleplayer/LAN game/Server [delete as necessary]
Issue details: [describe what you were doing when the issue occurred, what went wrong, what you expected to happen, etc.]
+1 -1
View File
@@ -7,7 +7,7 @@ assignees: ''
---
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
Minecraft versions: [if this suggestion only applies to some versions, list them here]
+2 -2
View File
@@ -7,10 +7,10 @@ assignees: ''
---
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
Minecraft version: 1.12.2 [change as necessary]
Wizardry version: 4.2.2 [change as necessary]
Wizardry version: 4.2.8 [change as necessary]
Question details: [explain your question here]
+1
View File
@@ -23,6 +23,7 @@ run
logs
/misc
/libs
libs_src
libsfordeobf
generated
Thumbs.db
+10 -7
View File
@@ -1,7 +1,7 @@
# Credits
Electroblob's Wizardry
Version 4.1.4
Version 4.2.8
For Minecraft 1.12.2
Designed, coded and textured by Electroblob
@@ -21,15 +21,18 @@ In addition, I'd like to thank the following individuals for their contributions
- Tora-B
- Avatair
- Aeronica
- UltraHex
- Azim-Palmer
- raoulvdberge
#### Translations
- Spanish and Mexican Spanish: MadWrist
- Russian: VilagVil, kellixon
- French: Hahdrim
- Brazilian Portuguese: lorrampi
- Chinese: ZHENGLOC, dragon-evol
- Korean: shejery, rewi_wire
- Spanish and Mexican Spanish: MadWrist
- Russian: VilagVil, kellixon, bigenergy
- French: Hahdrim
- Brazilian Portuguese: lorrampi
- Chinese: ZHENGLOC, dragon-evol
- Korean: shejery, rewi_wire
- Polish: Trozuu
Lightning ray sound effect from OhhWowProductions
+1 -1
View File
@@ -1,7 +1,7 @@
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
Minecraft version: 1.12.2 [change as necessary]
Wizardry version: 4.1.4 [change as necessary]
Wizardry version: 4.2.8 [change as necessary]
Environment: Singleplayer/LAN game/Server [delete as necessary]
Issue details: [describe what you were doing when the issue occurred, what went wrong, what you expected to happen, etc.]
+3 -3
View File
@@ -1,10 +1,10 @@
# Wizardry  [![Curseforge](http://cf.way2muchnoise.eu/full_electroblobs-wizardry_downloads.svg)](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [![Curseforge](http://cf.way2muchnoise.eu/versions/For%20MC_electroblobs-wizardry_all.svg)](https://minecraft.curseforge.com/projects/electroblobs-wizardry/files) [![Packs](https://images1-focus-opensocial.googleusercontent.com/gadgets/proxy?container=focus&url=https://cf.way2muchnoise.eu/packs/full_electroblobs-wizardry_in_packs.svg)](https://minecraft.curseforge.com/projects/electroblobs-wizardry/relations/dependents) [![Discord](https://img.shields.io/discord/417798297265242145.svg?colorB=7289DA&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHYAAABWAgMAAABnZYq0AAAACVBMVEUAAB38%2FPz%2F%2F%2F%2Bm8P%2F9AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfhBxwQJhxy2iqrAAABoElEQVRIx7WWzdGEIAyGgcMeKMESrMJ6rILZCiiBg4eYKr%2Fd1ZAfgXFm98sJfAyGNwno3G9sLucgYGpQ4OGVRxQTREMDZjF7ILSWjoiHo1n%2BE03Aw8p7CNY5IhkYd%2F%2F6MtO3f8BNhR1QWnarCH4tr6myl0cWgUVNcfMcXACP1hKrGMt8wcAyxide7Ymcgqale7hN6846uJCkQxw6GG7h2MH4Czz3cLqD1zHu0VOXMfZjHLoYvsdd0Q7ZvsOkafJ1P4QXxrWFd14wMc60h8JKCbyQvImzlFjyGoZTKzohwWR2UzSONHhYXBQOaKKsySsahwGGDnb%2FiYPJw22sCqzirSULYy1qtHhXGbtgrM0oagBV4XiTJok3GoLoDNH8ooTmBm7ZMsbpFzi2bgPGoXWXME6XT%2BRJ4GLddxJ4PpQy7tmfoU2HPN6cKg%2BledKHBKlF8oNSt5w5g5o8eXhu1IOlpl5kGerDxIVT%2BztzKepulD8utXqpChamkzzuo7xYGk%2FkpSYuviLXun5bzdRf0Krejzqyz7Z3p0I1v2d6HmA07dofmS48njAiuMgAAAAASUVORK5CYII%3D)](https://discord.gg/MTmMzMv)
# Wizardry  [![Curseforge](http://cf.way2muchnoise.eu/full_electroblobs-wizardry_downloads.svg)](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [![Curseforge](http://cf.way2muchnoise.eu/versions/For%20MC_electroblobs-wizardry_all.svg)](https://minecraft.curseforge.com/projects/electroblobs-wizardry/files) [![Discord](https://img.shields.io/discord/417798297265242145.svg?colorB=7289DA&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHYAAABWAgMAAABnZYq0AAAACVBMVEUAAB38%2FPz%2F%2F%2F%2Bm8P%2F9AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfhBxwQJhxy2iqrAAABoElEQVRIx7WWzdGEIAyGgcMeKMESrMJ6rILZCiiBg4eYKr%2Fd1ZAfgXFm98sJfAyGNwno3G9sLucgYGpQ4OGVRxQTREMDZjF7ILSWjoiHo1n%2BE03Aw8p7CNY5IhkYd%2F%2F6MtO3f8BNhR1QWnarCH4tr6myl0cWgUVNcfMcXACP1hKrGMt8wcAyxide7Ymcgqale7hN6846uJCkQxw6GG7h2MH4Czz3cLqD1zHu0VOXMfZjHLoYvsdd0Q7ZvsOkafJ1P4QXxrWFd14wMc60h8JKCbyQvImzlFjyGoZTKzohwWR2UzSONHhYXBQOaKKsySsahwGGDnb%2FiYPJw22sCqzirSULYy1qtHhXGbtgrM0oagBV4XiTJok3GoLoDNH8ooTmBm7ZMsbpFzi2bgPGoXWXME6XT%2BRJ4GLddxJ4PpQy7tmfoU2HPN6cKg%2BledKHBKlF8oNSt5w5g5o8eXhu1IOlpl5kGerDxIVT%2BztzKepulD8utXqpChamkzzuo7xYGk%2FkpSYuviLXun5bzdRf0Krejzqyz7Z3p0I1v2d6HmA07dofmS48njAiuMgAAAAASUVORK5CYII%3D)](https://discord.gg/MTmMzMv)
![Image not found](https://media-elerium.cursecdn.com/attachments/203/387/banner7.png)
![Image not found](https://raw.githubusercontent.com/wiki/Electroblob77/Wizardry/images/banners/art_banner.png)
Source code for Electroblob's Wizardry, a Minecraft mod currently for versions 1.7.10, 1.10.2, 1.11.2, and 1.12.2. Wizardry adds an RPG-style system of magic spells to Minecraft with the aim of being as playable as possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master the arcane!
Please read the [guide for contributing](guide_for_contributing.md) before submitting an issue or a PR.
Please read the [guide for contributing](CONTRIBUTING.md) before submitting an issue or a PR.
<b>Links</b>
+1 -1
View File
@@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
version = "4.2.2" // There, it matches semver, happy now?
version = "4.2.8" // There, it matches semver, happy now?
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "ElectroblobsWizardry"
@@ -7,6 +7,7 @@ import electroblob.wizardry.spell.Spell;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
@@ -99,9 +100,9 @@ public class CommonProxy {
return ((ItemSpectralBow)WizardryItems.spectral_bow).getDefaultDurabilityForDisplay(stack);
}
/** Like {@link CommonProxy#addMultiLineDescription(List, String, Style)}, but style defaults to light grey. */
public void addMultiLineDescription(List<String> tooltip, String key){
this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY));
/** Like {@link CommonProxy#addMultiLineDescription(List, String, Style, Object...)}, but style defaults to light grey. */
public void addMultiLineDescription(List<String> tooltip, String key, Object... args){
this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY), args);
}
/**
@@ -112,7 +113,7 @@ public class CommonProxy {
* @param key The translation key for the description
* @param style A style to apply
*/
public void addMultiLineDescription(List<String> tooltip, String key, Style style){}
public void addMultiLineDescription(List<String> tooltip, String key, Style style, Object... args){}
// SECTION Packet Handlers
// ===============================================================================================================
@@ -139,8 +140,6 @@ public class CommonProxy {
public void handleAdvancementSyncPacket(PacketSyncAdvancements.Message message){}
public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){}
public void handleResurrectionPacket(PacketResurrection.Message message){}
public void handlePossessionPacket(PacketPossession.Message message){}
@@ -238,6 +237,9 @@ public class CommonProxy {
+ "of sound events, but the given array contained less than 3 sound events!");
playSpellSoundLoop(world, x, y, z, spell, sounds[0], sounds[1], sounds[2], category, volume, pitch, duration);
}
/** Starts the first-person blink overlay effect for the specified player. */
public void playBlinkEffect(EntityPlayer player){}
/**
* Gets the client side world using Minecraft.getMinecraft().world. <b>Only to be called client side!</b> Returns
@@ -17,6 +17,7 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
import java.io.File;
import java.util.*;
import java.util.regex.Pattern;
@@ -168,6 +169,8 @@ public final class Settings {
/** <b>[Server-only]</b> Whether to replace Minecraft's distance-based fall damage calculation with an equivalent,
* velocity-based one. */
public boolean replaceVanillaFallDamage = true;
/** <b>[Server-only]</b> Whether using bonemeal on grass blocks has a chance to grow crystal flowers. */
public boolean bonemealGrowsCrystalFlowers = true;
/**
* <b>[Server-only]</b> List of registry names of entities which summoned creatures are allowed to attack, in addition
* to the defaults.
@@ -364,7 +367,7 @@ public final class Settings {
*/
void initConfig(FMLPreInitializationEvent event){
config = new Configuration(event.getSuggestedConfigurationFile());
config = new Configuration(new File(Wizardry.configDirectory, Wizardry.MODID + ".cfg"));
config.load();
Wizardry.logger.info("Setting up main config");
@@ -430,7 +433,7 @@ public final class Settings {
Property property;
for(Spell spell : Spell.getSpells(Spell.allSpells)){
for(Spell spell : Spell.getAllSpells()){
property = config.get(SPELLS_CATEGORY, spell.getRegistryName().toString(), true,
I18n.translateToLocal("spell." + spell.getUnlocalisedName() + ".desc"));
// Uses the same config key as the spell name, because - well, that's what it's called!
@@ -541,6 +544,13 @@ public final class Settings {
slowTimeAffectsPlayers = property.getBoolean();
propOrder.add(property.getName());
property = config.get(GAMEPLAY_CATEGORY, "bonemealGrowsCrystalFlowers", true,
"Whether using bonemeal on grass blocks has a chance to grow crystal flowers.");
property.setLanguageKey("config." + Wizardry.MODID + ".bonemeal_grows_crystal_flowers");
Wizardry.proxy.setToNamedBooleanEntry(property);
bonemealGrowsCrystalFlowers = property.getBoolean();
propOrder.add(property.getName());
property = config.get(GAMEPLAY_CATEGORY, "mobLootTableWhitelist", new String[0], "Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them.");
property.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_whitelist");
property.setRequiresMcRestart(true);
@@ -700,7 +710,7 @@ public final class Settings {
fastWorldgen = property.getBoolean();
propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate.");
property = config.get(WORLDGEN_CATEGORY, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate. Remove all dimensions to disable wizard towers completely.");
property.setLanguageKey("config." + Wizardry.MODID + ".tower_dimensions");
property.setRequiresWorldRestart(true);
towerDimensions = property.getIntList();
@@ -725,20 +735,20 @@ public final class Settings {
propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "towerFiles", new String[]{Wizardry.MODID + ":wizard_tower_0", Wizardry.MODID + ":wizard_tower_1", Wizardry.MODID + ":wizard_tower_2", Wizardry.MODID + ":wizard_tower_3"},
"List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
"List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.");
property.setLanguageKey("config." + Wizardry.MODID + ".tower_files");
property.setRequiresWorldRestart(true);
towerFiles = getResourceLocationList(property);
propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "towerWithChestFiles", new String[]{Wizardry.MODID + ":wizard_tower_chest_0", Wizardry.MODID + ":wizard_tower_chest_1", Wizardry.MODID + ":wizard_tower_chest_2", Wizardry.MODID + ":wizard_tower_chest_3"},
"List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
"List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.");
property.setLanguageKey("config." + Wizardry.MODID + ".tower_with_chest_files");
property.setRequiresWorldRestart(true);
towerWithChestFiles = getResourceLocationList(property);
propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "obeliskDimensions", new int[]{0, -1}, "List of dimension ids in which obelisks will generate.");
property = config.get(WORLDGEN_CATEGORY, "obeliskDimensions", new int[]{0, -1}, "List of dimension ids in which obelisks will generate. Remove all dimensions to disable obelisks completely.");
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_dimensions");
property.setRequiresWorldRestart(true);
obeliskDimensions = property.getIntList();
@@ -752,13 +762,13 @@ public final class Settings {
propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "obeliskFiles", new String[]{Wizardry.MODID + ":obelisk_0", Wizardry.MODID + ":obelisk_1", Wizardry.MODID + ":obelisk_2", Wizardry.MODID + ":obelisk_3", Wizardry.MODID + ":obelisk_4"},
"List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
"List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable obelisks, use the obelisk dimensions setting.");
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_files");
property.setRequiresWorldRestart(true);
obeliskFiles = getResourceLocationList(property);
propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "shrineDimensions", new int[]{0, -1}, "List of dimension ids in which shrines will generate.");
property = config.get(WORLDGEN_CATEGORY, "shrineDimensions", new int[]{0, -1}, "List of dimension ids in which shrines will generate. Remove all dimensions to disable shrines completely.");
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_dimensions");
property.setRequiresWorldRestart(true);
shrineDimensions = property.getIntList();
@@ -772,7 +782,7 @@ public final class Settings {
propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "shrineFiles", new String[]{Wizardry.MODID + ":shrine_0", Wizardry.MODID + ":shrine_1", Wizardry.MODID + ":shrine_2", Wizardry.MODID + ":shrine_3", Wizardry.MODID + ":shrine_4", Wizardry.MODID + ":shrine_5", Wizardry.MODID + ":shrine_6", Wizardry.MODID + ":shrine_7"},
"List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
"List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable shrines, use the shrine dimensions setting.");
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_files");
property.setRequiresWorldRestart(true);
shrineFiles = getResourceLocationList(property);
@@ -12,10 +12,10 @@ import electroblob.wizardry.misc.Forfeit;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.*;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.CustomSoundCategory;
import electroblob.wizardry.util.SpellProperties;
import electroblob.wizardry.worldgen.*;
import net.minecraft.item.Item;
import net.minecraft.util.SoundCategory;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
@@ -31,6 +31,9 @@ import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.util.Calendar;
/**
* <i>"Electroblob's Wizardry adds an RPG-like system of spells to Minecraft, with the aim of being as playable as
* possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master
@@ -61,7 +64,7 @@ public class Wizardry {
* 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft
* 1.11.x versions, and so on.
*/
public static final String VERSION = "4.2.2";
public static final String VERSION = "4.2.8";
// IDEA: Triggering of inbuilt Forge events in relevant places?
// IDEA: Abstract the vanilla particles behind the particle builder
@@ -82,6 +85,12 @@ public class Wizardry {
* - <b>INFO</b>: Anything that might happen during normal mod operation that the user needs to know about. */
public static Logger logger;
/** A {@link File} object representing wizardry's config folder, {@code config/ebwizardry}). As of wizardry 4.2.4,
* this folder contains the main config file and the global spell properties folder, if used. */
public static File configDirectory;
public static boolean tisTheSeason;
// The instance of wizardry that Forge uses.
@Instance(Wizardry.MODID)
public static Wizardry instance;
@@ -97,8 +106,13 @@ public class Wizardry {
proxy.registerResourceReloadListeners();
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
settings.initConfig(event);
Calendar calendar = Calendar.getInstance();
tisTheSeason = calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DAY_OF_MONTH) >= 24
&& calendar.get(Calendar.DAY_OF_MONTH) <= 26;
// Capabilities
WizardData.register();
DispenserCastingData.register();
@@ -113,7 +127,8 @@ public class Wizardry {
proxy.registerRenderers();
proxy.registerKeyBindings();
WizardrySounds.SPELLS = CustomSoundCategory.add(Wizardry.MODID + "_spells");
// Commented out for 4.2.3 to get rid of the sound bug, reinstate once a fix is found.
WizardrySounds.SPELLS = SoundCategory.PLAYERS;//CustomSoundCategory.add(Wizardry.MODID + "_spells");
WizardryBaublesIntegration.init();
WizardryAntiqueAtlasIntegration.init();
@@ -33,6 +33,9 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootTable;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.entity.PlaySoundAtEntityEvent;
@@ -46,6 +49,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
import java.util.ArrayList;
import java.util.List;
/**
* General-purpose event handler for things that don't fit anywhere else or groups of related behaviours that are better
@@ -343,18 +347,21 @@ public final class WizardryEventHandler {
Spell spell = ((ISpellCaster)event.getEntity()).getContinuousSpell();
SpellModifiers modifiers = ((ISpellCaster)event.getEntity()).getModifiers();
int count = ((ISpellCaster)event.getEntity()).getSpellCounter();
if(spell != null && spell != Spells.none){ // IntelliJ is wrong, do NOT remove the null check!
if(!MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(SpellCastEvent.Source.NPC, spell, event.getEntityLiving(),
modifiers, 0))){
modifiers, count))){
spell.cast(event.getEntity().world, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, 0,
spell.cast(event.getEntity().world, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, count,
// TODO: This implementation of modifiers relies on them being accessible client-side.
// Right now that doesn't matter because NPCs don't use modifiers, but they might in future
((EntityLiving)event.getEntity()).getAttackTarget(), modifiers);
}
}
((ISpellCaster)event.getEntity()).setSpellCounter(count + 1);
}
}
}
@@ -366,6 +373,22 @@ public final class WizardryEventHandler {
EntityPlayer player = (EntityPlayer)event.getSource().getTrueSource();
// Compatibility with "Lycanites Mobs" -it uses custom loot drop logic which can't be hooked, given the
// number of mobs that spawn as Lycanites when this mod is active it would massively nerf the wizard drops
// if we didn't handle this
if(event.getEntity().getClass().getCanonicalName().contains("lycanitesmobs"))
{
WorldServer world = (WorldServer)event.getEntity().getEntityWorld();
LootTable table = world.getLootTableManager().getLootTableFromLocation(new ResourceLocation(Wizardry.MODID, "entities/mob_additions"));
LootContext ctx = new LootContext.Builder(world).withPlayer(player).build();
List<ItemStack> stacks = table.generateLootForPools(world.rand, ctx);
for(ItemStack stack : stacks) {
event.getEntity().entityDropItem(stack, 0f);
}
}
for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){
if(stack.getItem() instanceof IManaStoringItem && !((IManaStoringItem)stack.getItem()).isManaFull(stack)
@@ -444,7 +467,8 @@ public final class WizardryEventHandler {
// Wizardry.logger.info("Replaced fall distance {} with effective distance {} based on entity velocity", event.getDistance(), y);
// }
event.setDistance((float)y);
// Don't let it increase fall damage beyond vanilla values
if(y < event.getDistance()) event.setDistance((float)y);
}
}
}
@@ -2,7 +2,6 @@ package electroblob.wizardry;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.item.ItemWizardHandbook;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.tileentity.ContainerPortableWorkbench;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
@@ -48,9 +47,9 @@ public class WizardryGuiHandler implements IGuiHandler {
return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook();
}else if(id == SPELL_BOOK){
if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){
return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemMainhand().getItemDamage()));
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemMainhand());
}else if(player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){
return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemOffhand().getItemDamage()));
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemOffhand());
}
}else if(id == PORTABLE_CRAFTING){
return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z));
@@ -1,5 +1,6 @@
package electroblob.wizardry.block;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
@@ -56,7 +57,7 @@ public class BlockCrystalFlower extends BlockBush {
@SubscribeEvent
public static void onBonemealEvent(BonemealEvent event){
// Grows crystal flowers when bonemeal is used on grass
if(event.getBlock().getBlock() == Blocks.GRASS){
if(Wizardry.settings.bonemealGrowsCrystalFlowers && event.getBlock().getBlock() == Blocks.GRASS){
BlockPos pos = event.getPos().add(event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8),
event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4),
@@ -141,7 +141,8 @@ public class BlockTransportationStone extends Block {
if(locations.isEmpty()) locations.add(here);
else{
locations.remove(here); // Prevents duplicates
locations.set(Math.max(locations.size() - 1, 0), here);
if(locations.isEmpty()) locations.add(here);
else locations.set(Math.max(locations.size() - 1, 0), here);
}
if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.confirm", Spells.transportation.getNameForTranslationFormatted()), true);
}
@@ -107,7 +107,7 @@ public class ClientProxy extends CommonProxy {
// Armour Model
public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f);
/** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style)}). */
/** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style, Object...)}). */
private static final int TOOLTIP_WRAP_WIDTH = 140;
// SECTION Registry
@@ -190,6 +190,11 @@ public class ClientProxy extends CommonProxy {
}
}
@Override
public void playBlinkEffect(EntityPlayer player){
if(Minecraft.getMinecraft().player == player) WizardryClientEventHandler.playBlinkEffect();
}
@Override
public Set<String> getSpellHUDSkins(){
return GuiSpellDisplay.getSkinKeys();
@@ -282,8 +287,8 @@ public class ClientProxy extends CommonProxy {
}
@Override
public void addMultiLineDescription(List<String> tooltip, String key, Style style){
String description = style.getFormattingCode() + I18n.format(key);
public void addMultiLineDescription(List<String> tooltip, String key, Style style, Object... args){
String description = style.getFormattingCode() + I18n.format(key, args);
tooltip.addAll(Minecraft.getMinecraft().fontRenderer.listFormattedStringToWidth(description, TOOLTIP_WRAP_WIDTH));
}
@@ -429,6 +434,7 @@ public class ClientProxy extends CommonProxy {
if(caster instanceof ISpellCaster){
if(spell.isContinuous || spell instanceof None){
((ISpellCaster)caster).setContinuousSpell(spell);
((ISpellCaster)caster).setSpellCounter(spell instanceof None ? 0 : 1);
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
}
}
@@ -542,7 +548,7 @@ public class ClientProxy extends CommonProxy {
data.randomNames = new HashMap<>();
data.randomDescriptions = new HashMap<>();
for(Spell spell : Spell.getSpells(Spell.allSpells)){
for(Spell spell : Spell.getAllSpells()){
// -1 because the none spell isn't included
// This is a case where we must use the network ID, not the metadata
data.randomNames.put(spell, message.names.get(spell.networkID() - 1));
@@ -569,13 +575,6 @@ public class ClientProxy extends CommonProxy {
GuiWizardHandbook.updateUnlockStatus(message.showToasts, message.completedAdvancements);
}
@Override
public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){
Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.hostID);
if(entity instanceof EntityLivingBase) PotionSlowTime.unblockNearbyEntities((EntityLivingBase)entity);
else Wizardry.logger.warn("Received a PacketEndSlowTime, but the entity ID did not match any living entity");
}
@Override
public void handleResurrectionPacket(PacketResurrection.Message message){
Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.playerID);
@@ -9,6 +9,7 @@ import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.item.ItemSpectralBow;
import electroblob.wizardry.potion.PotionSlowTime;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
@@ -23,11 +24,8 @@ import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.item.EntityArmorStand;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
@@ -35,18 +33,17 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.village.MerchantRecipe;
import net.minecraft.world.World;
import net.minecraftforge.client.event.*;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
import org.lwjgl.opengl.GL11;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* Event handler responsible for client-side only events, mostly rendering.
@@ -71,12 +68,6 @@ public final class WizardryClientEventHandler {
private static int blinkEffectTimer;
/** The number of ticks the blink effect lasts for. */
private static final int BLINK_EFFECT_DURATION = 8;
private static final Method unpressKey;
static {
unpressKey = ObfuscationReflectionHelper.findMethod(KeyBinding.class, "func_74505_d", void.class);
}
/** Starts the first person blink overlay effect. */
public static void playBlinkEffect(){
@@ -151,7 +142,10 @@ public final class WizardryClientEventHandler {
if(world == null) return;
for(TileEntity tileentity : world.loadedTileEntityList){
// Somehow this was throwing a CME, I have no idea why so I'm just going to cheat and copy the list
List<TileEntity> tileEntities = new ArrayList<>(world.loadedTileEntityList);
for(TileEntity tileentity : tileEntities){
if(tileentity instanceof TileEntityDispenser){
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
DispenserCastingData.get((TileEntityDispenser)tileentity).update();
@@ -160,6 +154,7 @@ public final class WizardryClientEventHandler {
}
SpellEmitterData.update(world);
PotionSlowTime.cleanUpEntities(world);
}
}
@@ -31,7 +31,6 @@ import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.fml.common.Mod;
@@ -1,11 +1,11 @@
package electroblob.wizardry.client.gui;
import com.google.common.collect.ImmutableMap;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.DrawingUtils;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.data.SpellGlyphData;
import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell;
@@ -14,27 +14,22 @@ import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation;
import net.minecraft.item.ItemStack;
import org.lwjgl.input.Keyboard;
import java.util.Map;
public class GuiSpellBook extends GuiScreen {
private int xSize, ySize;
private ItemSpellBook book;
private Spell spell;
private static final Map<Tier, ResourceLocation> textures = ImmutableMap.of(
Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"),
Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"),
Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"),
Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png"));
public GuiSpellBook(Spell spell){
public GuiSpellBook(ItemStack stack){
super();
xSize = 288;
ySize = 180;
this.spell = spell;
if(!(stack.getItem() instanceof ItemSpellBook)) throw new ClassCastException("Cannot create spell book GUI for item that does not extend ItemSpellBook!");
this.book = (ItemSpellBook)stack.getItem();
this.spell = Spell.byMetadata(stack.getItemDamage());
}
/**
@@ -59,7 +54,7 @@ public class GuiSpellBook extends GuiScreen {
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128);
Minecraft.getMinecraft().renderEngine.bindTexture(textures.get(spell.getTier()));
Minecraft.getMinecraft().renderEngine.bindTexture(book.getGuiTexture(spell));
DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
super.drawScreen(par1, par2, par3);
@@ -77,7 +72,7 @@ public class GuiSpellBook extends GuiScreen {
//this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0);
if(spell.getTier() == Tier.NOVICE){
// Basic is usually white but this doesn't show up.
// Novice is usually white but this doesn't show up.
this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0);
}else{
this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0);
@@ -1,5 +1,6 @@
package electroblob.wizardry.client.model;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.block.BlockStatue;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
@@ -13,6 +14,7 @@ public class ModelWizardArmour extends ModelArmourFixer {
ModelRenderer hatSegment4;
ModelRenderer hatSegment5;
ModelRenderer hatSegment6;
ModelRenderer hatBobble;
ModelRenderer robe;
public ModelWizardArmour(float delta){
@@ -75,6 +77,13 @@ public class ModelWizardArmour extends ModelArmourFixer {
hatSegment6.mirror = true;
setRotation(hatSegment6, -0.5585054F, 0F, 0F);
hatBobble = new ModelRenderer(this, 52, 47);
hatBobble.addBox(0F, 0F, 0F, 3, 3, 3);
hatBobble.setRotationPoint(-1.5F, -15.1F, 4F);
hatBobble.setTextureSize(64, 64);
hatBobble.mirror = true;
setRotation(hatBobble, -0.65F, 0F, 0F);
bipedBody = new ModelRenderer(this, 16, 16);
bipedBody.addBox(-4F, 0F, -2F, 8, 11, 4, delta);
bipedBody.setRotationPoint(0F, 0F, 0F);
@@ -97,6 +106,7 @@ public class ModelWizardArmour extends ModelArmourFixer {
bipedHead.addChild(hatSegment4);
bipedHead.addChild(hatSegment5);
bipedHead.addChild(hatSegment6);
bipedHead.addChild(hatBobble);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){
@@ -129,6 +139,8 @@ public class ModelWizardArmour extends ModelArmourFixer {
this.robe.rotateAngleX = (this.bipedLeftLeg.rotateAngleX + this.bipedRightLeg.rotateAngleX) / 2f;
this.robe.rotateAngleY = this.bipedBody.rotateAngleY;
this.robe.rotateAngleZ = (this.bipedLeftLeg.rotateAngleZ + this.bipedRightLeg.rotateAngleZ) / 2f;
this.hatBobble.showModel = Wizardry.tisTheSeason;
}
}
@@ -10,6 +10,7 @@ import electroblob.wizardry.item.ItemCrystal;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryItems;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.block.statemap.StateMap;
import net.minecraft.creativetab.CreativeTabs;
@@ -66,10 +67,10 @@ public final class WizardryModels {
registerMultiTexturedModel((ItemCrystal)WizardryItems.magic_crystal);
registerItemModel(WizardryItems.magic_wand);
registerItemModel(WizardryItems.apprentice_wand);
registerItemModel(WizardryItems.advanced_wand);
registerItemModel(WizardryItems.master_wand);
registerWandModel(WizardryItems.magic_wand);
registerWandModel(WizardryItems.apprentice_wand);
registerWandModel(WizardryItems.advanced_wand);
registerWandModel(WizardryItems.master_wand);
registerItemModel(WizardryItems.spell_book);
// Wildcard registered for wizard trades.
@@ -77,37 +78,37 @@ public final class WizardryModels {
registerItemModel(WizardryItems.arcane_tome);
registerItemModel(WizardryItems.wizard_handbook);
registerItemModel(WizardryItems.novice_fire_wand);
registerItemModel(WizardryItems.novice_ice_wand);
registerItemModel(WizardryItems.novice_lightning_wand);
registerItemModel(WizardryItems.novice_necromancy_wand);
registerItemModel(WizardryItems.novice_earth_wand);
registerItemModel(WizardryItems.novice_sorcery_wand);
registerItemModel(WizardryItems.novice_healing_wand);
registerWandModel(WizardryItems.novice_fire_wand);
registerWandModel(WizardryItems.novice_ice_wand);
registerWandModel(WizardryItems.novice_lightning_wand);
registerWandModel(WizardryItems.novice_necromancy_wand);
registerWandModel(WizardryItems.novice_earth_wand);
registerWandModel(WizardryItems.novice_sorcery_wand);
registerWandModel(WizardryItems.novice_healing_wand);
registerItemModel(WizardryItems.apprentice_fire_wand);
registerItemModel(WizardryItems.apprentice_ice_wand);
registerItemModel(WizardryItems.apprentice_lightning_wand);
registerItemModel(WizardryItems.apprentice_necromancy_wand);
registerItemModel(WizardryItems.apprentice_earth_wand);
registerItemModel(WizardryItems.apprentice_sorcery_wand);
registerItemModel(WizardryItems.apprentice_healing_wand);
registerWandModel(WizardryItems.apprentice_fire_wand);
registerWandModel(WizardryItems.apprentice_ice_wand);
registerWandModel(WizardryItems.apprentice_lightning_wand);
registerWandModel(WizardryItems.apprentice_necromancy_wand);
registerWandModel(WizardryItems.apprentice_earth_wand);
registerWandModel(WizardryItems.apprentice_sorcery_wand);
registerWandModel(WizardryItems.apprentice_healing_wand);
registerItemModel(WizardryItems.advanced_fire_wand);
registerItemModel(WizardryItems.advanced_ice_wand);
registerItemModel(WizardryItems.advanced_lightning_wand);
registerItemModel(WizardryItems.advanced_necromancy_wand);
registerItemModel(WizardryItems.advanced_earth_wand);
registerItemModel(WizardryItems.advanced_sorcery_wand);
registerItemModel(WizardryItems.advanced_healing_wand);
registerWandModel(WizardryItems.advanced_fire_wand);
registerWandModel(WizardryItems.advanced_ice_wand);
registerWandModel(WizardryItems.advanced_lightning_wand);
registerWandModel(WizardryItems.advanced_necromancy_wand);
registerWandModel(WizardryItems.advanced_earth_wand);
registerWandModel(WizardryItems.advanced_sorcery_wand);
registerWandModel(WizardryItems.advanced_healing_wand);
registerItemModel(WizardryItems.master_fire_wand);
registerItemModel(WizardryItems.master_ice_wand);
registerItemModel(WizardryItems.master_lightning_wand);
registerItemModel(WizardryItems.master_necromancy_wand);
registerItemModel(WizardryItems.master_earth_wand);
registerItemModel(WizardryItems.master_sorcery_wand);
registerItemModel(WizardryItems.master_healing_wand);
registerWandModel(WizardryItems.master_fire_wand);
registerWandModel(WizardryItems.master_ice_wand);
registerWandModel(WizardryItems.master_lightning_wand);
registerWandModel(WizardryItems.master_necromancy_wand);
registerWandModel(WizardryItems.master_earth_wand);
registerWandModel(WizardryItems.master_sorcery_wand);
registerWandModel(WizardryItems.master_healing_wand);
registerItemModel(WizardryItems.spectral_sword);
registerItemModel(WizardryItems.spectral_pickaxe);
@@ -294,24 +295,30 @@ public final class WizardryModels {
/**
* Registers an item model, using the item's registry name as the model name (this convention makes it easier to
* keep track of everything). Variant defaults to "normal". Registers the model for metadata 0 automatically, plus
* all the other metadata values that the item can take, as defined in
* {@link Item#getSubItems(CreativeTabs, NonNullList)}. The creative tab supplied
* to the aforementioned method will be whichever one the item is in.
* keep track of everything). Variant defaults to "normal". Registers the model for all metadata values.
*/
private static void registerItemModel(Item item){
if(item.getHasSubtypes()){
NonNullList<ItemStack> items = NonNullList.create();
item.getSubItems(item.getCreativeTab(), items); // Client-only method, but we're client-side so this is OK.
for(ItemStack stack : items){
ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(),
new ModelResourceLocation(item.getRegistryName(), "inventory"));
}
}
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
ModelLoader.setCustomModelResourceLocation(item, 0,
new ModelResourceLocation(item.getRegistryName(), "inventory"));
ModelBakery.registerItemVariants(item, new ModelResourceLocation(item.getRegistryName(), "inventory"));
// Assigns the model for all metadata values
ModelLoader.setCustomMeshDefinition(item, s -> new ModelResourceLocation(item.getRegistryName(), "inventory"));
}
/**
* Registers a wand model, using the item's registry name as the model name (this convention makes it easier to
* keep track of everything).
*/
private static void registerWandModel(Item item){
if(Wizardry.tisTheSeason){
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
ModelBakery.registerItemVariants(item, new ModelResourceLocation("ebwizardry:festive_wand", "inventory"));
// Assigns the model for all metadata values
ModelLoader.setCustomMeshDefinition(item, s -> new ModelResourceLocation("ebwizardry:festive_wand", "inventory"));
}else{
registerItemModel(item);
}
}
/**
@@ -525,30 +525,42 @@ public abstract class ParticleWizardry extends Particle {
// =============================================== Helper Methods ===============================================
/** Internal overload for {@link ParticleWizardry#generateTextures(String, String, int)} which uses wizardry's mod
* ID automatically. */
public static ResourceLocation[] generateTextures(String stem, int n){
return generateTextures(Wizardry.MODID, stem, n);
}
/** Static helper method that generates an array of n ResourceLocations using the particle file naming convention,
* which is the given stem plus an underscore plus the integer index. */
public static ResourceLocation[] generateTextures(String stem, int n){
public static ResourceLocation[] generateTextures(String modID, String stem, int n){
ResourceLocation[] textures = new ResourceLocation[n];
for(int i=0; i<n; i++){
textures[i] = new ResourceLocation(Wizardry.MODID, "particle/" + stem + "_" + i);
textures[i] = new ResourceLocation(modID, "particle/" + stem + "_" + i);
}
return textures;
}
/** Internal overload for {@link ParticleWizardry#generateTextures(String, String, int, int)} which uses wizardry's
* mod ID automatically. */
public static ResourceLocation[][] generateTextures(String stem, int m, int n){
return generateTextures(Wizardry.MODID, stem, m, n);
}
/** Static helper method that generates a 2D m x n array of ResourceLocations using the particle file naming
* convention, which is the given stem plus an underscore plus the first index, plus an underscore plus the second
* index. Useful for animated particles that also pick a random animation strip. */
public static ResourceLocation[][] generateTextures(String stem, int m, int n){
public static ResourceLocation[][] generateTextures(String modID, String stem, int m, int n){
ResourceLocation[][] textures = new ResourceLocation[m][n];
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
textures[i][j] = new ResourceLocation(Wizardry.MODID, "particle/" + stem + "_" + i + "_" + j);
textures[i][j] = new ResourceLocation(modID, "particle/" + stem + "_" + i + "_" + j);
}
}
@@ -112,7 +112,7 @@ public class LayerFrost implements LayerRenderer<EntityLivingBase> {
double scaleX = 1, scaleY = 1;
// It's more logical to use the model's texture size, but some classes don't bother setting it properly
// (e.g. ModelVillager), so to get the correct dimensions I'm getting them from the first box instead.
if(model.boxList != null && model.boxList.get(0) != null){
if(model.boxList != null && model.boxList.size() >= 1 && model.boxList.get(0) != null){
scaleX = (double)model.boxList.get(0).textureWidth / 16d;
scaleY = (double)model.boxList.get(0).textureHeight / 16d;
}else{ // Fallback to model fields; should never be needed
@@ -121,11 +121,26 @@ public class LayerFrost implements LayerRenderer<EntityLivingBase> {
}
GlStateManager.scale(scaleX, scaleY, 1);
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
boolean headWearHidden = false;
boolean bodyWearHidden = false;
boolean leftArmWearHidden = false;
boolean rightArmWearHidden = false;
boolean leftLegWearHidden = false;
boolean rightLegWearHidden = false;
// Hides the hat layer for bipeds
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = true;
if(this.model instanceof ModelBiped){
headWearHidden = ((ModelBiped)this.model).bipedHeadwear.isHidden;
((ModelBiped)this.model).bipedHeadwear.isHidden = true;
}
if(this.model instanceof ModelPlayer){
bodyWearHidden = ((ModelPlayer)this.model).bipedBodyWear.isHidden;
leftArmWearHidden = ((ModelPlayer)this.model).bipedLeftArmwear.isHidden;
rightArmWearHidden = ((ModelPlayer)this.model).bipedRightArmwear.isHidden;
leftLegWearHidden = ((ModelPlayer)this.model).bipedLeftLegwear.isHidden;
rightLegWearHidden = ((ModelPlayer)this.model).bipedRightLegwear.isHidden;
((ModelPlayer)this.model).bipedBodyWear.isHidden = true;
((ModelPlayer)this.model).bipedLeftArmwear.isHidden = true;
((ModelPlayer)this.model).bipedRightArmwear.isHidden = true;
@@ -136,7 +151,15 @@ public class LayerFrost implements LayerRenderer<EntityLivingBase> {
this.model.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks);
this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale);
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = false;
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = headWearHidden;
if(this.model instanceof ModelPlayer){
((ModelPlayer)this.model).bipedBodyWear.isHidden = bodyWearHidden;
((ModelPlayer)this.model).bipedLeftArmwear.isHidden = leftArmWearHidden;
((ModelPlayer)this.model).bipedRightArmwear.isHidden = rightArmWearHidden;
((ModelPlayer)this.model).bipedLeftLegwear.isHidden = leftLegWearHidden;
((ModelPlayer)this.model).bipedRightLegwear.isHidden = rightLegWearHidden;
}
// Undoes the texture scaling
GlStateManager.matrixMode(GL11.GL_TEXTURE);
@@ -42,6 +42,7 @@ public class RenderArcaneLock {
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
boolean lighting = GL11.glIsEnabled(GL11.GL_LIGHTING);
GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
@@ -62,6 +63,8 @@ public class RenderArcaneLock {
List<TileEntity> tileentities = new ArrayList<>(world.loadedTileEntityList);
for(TileEntity tileentity : tileentities){
if(tileentity == null) continue; // What the heck VoxelMap
if(tileentity.getDistanceSq(origin.x, origin.y, origin.z) <= tileentity.getMaxRenderDistanceSquared()
&& tileentity.getTileData().hasUniqueId(ArcaneLock.NBT_KEY)){
@@ -82,7 +85,9 @@ public class RenderArcaneLock {
GlStateManager.disableBlend();
GlStateManager.enableTexture2D();
GlStateManager.enableLighting();
if (lighting) {
GlStateManager.enableLighting();
}
GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix();
}
@@ -53,9 +53,8 @@ public class RenderBlackHole extends Render<EntityBlackHole> {
(float)blackhole.ticksExisted / 10);
}
if(blackhole.ticksExisted > blackhole.lifetime - 10){
GlStateManager.scale((float)(blackhole.lifetime - blackhole.ticksExisted) / 10,
(float)(blackhole.lifetime - blackhole.ticksExisted) / 10,
(float)(blackhole.lifetime - blackhole.ticksExisted) / 10);
float scale = Math.max(0, (float)(blackhole.lifetime - blackhole.ticksExisted) / 10);
GlStateManager.scale(scale, scale, scale);
}
this.bindTexture(texture);
@@ -190,7 +190,8 @@ public class CommandCastSpell extends CommandBase {
}
if(spell.isContinuous){
// We need not query Spell#canBeCastByDispensers since with commands there's no difference between
// a spell that can't be cast positionally and one that can be cast positionally but fails
if(spell.cast(world, origin.x, origin.y, origin.z, direction, 0, duration, modifiers)){
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.COMMAND, spell, world, origin.x, origin.y, origin.z, direction, modifiers));
@@ -113,7 +113,7 @@ public class CommandDiscoverSpell extends CommandBase {
if(server.sendCommandFeedback()) sender.sendMessage(
new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.clear", player.getName()));
}else if(all){
data.spellsDiscovered.addAll(Spell.getSpells(Spell.allSpells));
data.spellsDiscovered.addAll(Spell.getAllSpells());
if(server.sendCommandFeedback()) sender.sendMessage(
new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.all", player.getName()));
}else{
@@ -4,6 +4,7 @@ import electroblob.wizardry.Wizardry;
import electroblob.wizardry.data.SpellEmitterData;
import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.NBTExtras;
import electroblob.wizardry.util.SpellModifiers;
import io.netty.buffer.ByteBuf;
import net.minecraft.nbt.NBTTagCompound;
@@ -129,7 +130,7 @@ public class SpellEmitter implements ITickable {
nbt.setDouble("z", z);
nbt.setInteger("direction", direction.getIndex());
nbt.setInteger("duration", duration);
nbt.setTag("modifiers", modifiers.toNBT());
NBTExtras.storeTagSafely(nbt, "modifiers", modifiers.toNBT());
nbt.setInteger("castingTick", castingTick);
return nbt;
@@ -12,9 +12,9 @@ import java.util.Random;
public enum Tier {
NOVICE(700, 3, 12, 0, new Style().setColor(TextFormatting.WHITE), "novice"),
APPRENTICE(1000, 5, 5, 4000, new Style().setColor(TextFormatting.AQUA), "apprentice"),
ADVANCED(1500, 7, 2, 6000, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
MASTER(2500, 9, 1, 10000, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
APPRENTICE(1000, 5, 5, 2000, new Style().setColor(TextFormatting.AQUA), "apprentice"),
ADVANCED(1500, 7, 2, 3500, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
MASTER(2500, 9, 1, 6000, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
/** Maximum mana a wand of this tier can store. */
public final int maxCharge;
@@ -7,6 +7,7 @@ import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.None;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.NBTExtras;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
@@ -141,7 +142,7 @@ public abstract class BlockCastingData<T extends TileEntity> implements INBTSeri
nbt.setInteger("spell", spell.metadata());
nbt.setInteger("castingTick", castingTick);
nbt.setTag("modifiers", modifiers.toNBT());
NBTExtras.storeTagSafely(nbt, "modifiers", modifiers.toNBT());
return nbt;
}
@@ -166,7 +166,10 @@ public class DispenserCastingData extends BlockCastingData<TileEntityDispenser>
// This will fire once for each dimension, but since we want dispenser-casting to work in all dimensions,
// this is correct (the loaded tile entity list will of course be different in each case.
for(TileEntity tileentity : event.world.loadedTileEntityList){
// Somehow this was throwing a CME, I have no idea why so I'm just going to cheat and copy the list
List<TileEntity> tileEntities = new ArrayList<>(event.world.loadedTileEntityList);
for(TileEntity tileentity : tileEntities){
if(tileentity instanceof TileEntityDispenser){
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
DispenserCastingData.get((TileEntityDispenser)tileentity).update();
@@ -1,5 +1,6 @@
package electroblob.wizardry.data;
import electroblob.wizardry.util.NBTExtras;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
@@ -89,7 +90,7 @@ public interface IStoredVariable<T> extends IVariable<T> {
@Override
public void write(NBTTagCompound nbt, T value){
if(value != null) nbt.setTag(key, serialiser.apply(value));
if(value != null) NBTExtras.storeTagSafely(nbt, key, serialiser.apply(value));
}
@Override
@@ -91,7 +91,7 @@ public class SpellEmitterData extends WorldSavedData {
@Override
public NBTTagCompound writeToNBT(NBTTagCompound compound){
compound.setTag("emitters", NBTExtras.listToNBT(emitters, SpellEmitter::toNBT));
NBTExtras.storeTagSafely(compound, "emitters", NBTExtras.listToNBT(emitters, SpellEmitter::toNBT));
return compound;
}
@@ -4,6 +4,7 @@ import electroblob.wizardry.Wizardry;
import electroblob.wizardry.packet.PacketGlyphData;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.NBTExtras;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
@@ -43,11 +44,11 @@ public class SpellGlyphData extends WorldSavedData {
/** Generates random names and descriptions for any spells which don't already have them. */
public void generateGlyphNames(World world){
for(Spell spell : Spell.getSpells(Spell.allSpells)){
for(Spell spell : Spell.getAllSpells()){
if(!randomNames.containsKey(spell)) randomNames.put(spell, generateRandomName(world.rand));
}
for(Spell spell : Spell.getSpells(Spell.allSpells)){
for(Spell spell : Spell.getAllSpells()){
if(!randomDescriptions.containsKey(spell))
randomDescriptions.put(spell, generateRandomDescription(world.rand));
}
@@ -161,7 +162,7 @@ public class SpellGlyphData extends WorldSavedData {
NBTTagList tagList = new NBTTagList();
for(Spell spell : Spell.getSpells(Spell.allSpells)){
for(Spell spell : Spell.getAllSpells()){
// Much like the enchantments tag for items, this stores a list of spell-id-to-name tag pairs
// The description is now also included; there's no point in making a second compound tag!
NBTTagCompound tag = new NBTTagCompound();
@@ -171,7 +172,7 @@ public class SpellGlyphData extends WorldSavedData {
tagList.appendTag(tag);
}
nbt.setTag("spellGlyphData", tagList);
NBTExtras.storeTagSafely(nbt, "spellGlyphData", tagList);
return nbt;
}
@@ -515,12 +515,12 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
NBTTagCompound properties = new NBTTagCompound();
properties.setTag("imbuements", NBTExtras.mapToNBT(this.imbuementDurations,
NBTExtras.storeTagSafely(properties, "imbuements", NBTExtras.mapToNBT(this.imbuementDurations,
imbuement -> new NBTTagInt(Enchantment.getEnchantmentID((Enchantment)imbuement)), NBTTagInt::new));
// Mmmmmm Java 8....
properties.setTag("allies", NBTExtras.listToNBT(this.allies, NBTUtil::createUUIDTag));
properties.setTag("allyNames", NBTExtras.listToNBT(this.allyNames, NBTTagString::new));
NBTExtras.storeTagSafely(properties, "allies", NBTExtras.listToNBT(this.allies, NBTUtil::createUUIDTag));
NBTExtras.storeTagSafely(properties, "allyNames", NBTExtras.listToNBT(this.allyNames, NBTTagString::new));
// Might be worth converting this over to WizardryUtilities.listToNBT.
int[] spells = new int[this.spellsDiscovered.size()];
@@ -531,7 +531,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
}
properties.setIntArray("discoveredSpells", spells);
properties.setTag("recentSpells", NBTExtras.listToNBT(recentSpells, s -> new NBTTagInt(s.metadata())));
NBTExtras.storeTagSafely(properties, "recentSpells", NBTExtras.listToNBT(recentSpells, s -> new NBTTagInt(s.metadata())));
storedVariables.forEach(k -> k.write(properties, this.spellData.get(k)));
@@ -5,6 +5,7 @@ import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.AllyDesignationSystem;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.NBTExtras;
import electroblob.wizardry.util.WizardryUtilities;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
@@ -183,7 +184,7 @@ public class EntityLevitatingBlock extends EntityFallingBlock implements IEntity
NBTBase nbtbase = this.tileEntityData.getTag(s);
if(!"x".equals(s) && !"y".equals(s) && !"z".equals(s)){
nbttagcompound.setTag(s, nbtbase.copy());
NBTExtras.storeTagSafely(nbttagcompound, s, nbtbase.copy());
}
}
@@ -65,7 +65,7 @@ public class EntityBubble extends EntityMagicConstruct {
if(isDarkOrb){
if(WizardryUtilities.getRider(this) != null
&& this.ticksExisted % Spells.entrapment.getProperty(Entrapment.DAMAGE_INTERVAL).intValue() == 0){
&& WizardryUtilities.getRider(this).ticksExisted % Spells.entrapment.getProperty(Entrapment.DAMAGE_INTERVAL).intValue() == 0){
if(this.getCaster() != null){
WizardryUtilities.getRider(this).attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC),
@@ -1,6 +1,5 @@
package electroblob.wizardry.entity.construct;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.WizardryUtilities;
@@ -80,8 +80,8 @@ public class EntityHammer extends EntityMagicConstruct {
if(this.world.isRemote && this.ticksExisted % 3 == 0){
ParticleBuilder.create(Type.SPARK)
.pos(this.posX - 0.5d + rand.nextDouble(), this.posY + 2 * rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble())
.spawn(world);
.pos(this.posX - 0.5d + rand.nextDouble(), this.posY + 2 * rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble())
.spawn(world);
}
this.prevPosX = this.posX;
@@ -103,39 +103,37 @@ public class EntityHammer extends EntityMagicConstruct {
this.rotationPitch = 0;
this.spin = false;
if(this.ticksExisted % Spells.lightning_hammer.getProperty(LightningHammer.ATTACK_INTERVAL).floatValue() == 0){
double seekerRange = Spells.lightning_hammer.getProperty(Spell.EFFECT_RADIUS).doubleValue();
double seekerRange = Spells.lightning_hammer.getProperty(Spell.EFFECT_RADIUS).doubleValue();
List<EntityLivingBase> targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX,
this.posY + 1, this.posZ, world);
List<EntityLivingBase> targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX,
this.posY + 1, this.posZ, world);
int maxTargets = Spells.lightning_hammer.getProperty(LightningHammer.SECONDARY_MAX_TARGETS).intValue();
while(targets.size() > maxTargets) targets.remove(targets.size() - 1);
int maxTargets = Spells.lightning_hammer.getProperty(LightningHammer.SECONDARY_MAX_TARGETS).intValue();
while(targets.size() > maxTargets) targets.remove(targets.size() - 1);
for(EntityLivingBase target : targets){
for(EntityLivingBase target : targets){
if(WizardryUtilities.isLiving(target) && this.isValidTarget(target)
&& target.ticksExisted % Spells.lightning_hammer.getProperty(LightningHammer.ATTACK_INTERVAL).floatValue() == 0){
if(WizardryUtilities.isLiving(target) && this.isValidTarget(target)){
if(world.isRemote){
if(world.isRemote){
ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world);
ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world);
ParticleBuilder.spawnShockParticles(world, target.posX,
target.getEntityBoundingBox().minY + target.height, target.posZ);
}
ParticleBuilder.spawnShockParticles(world, target.posX,
target.getEntityBoundingBox().minY + target.height, target.posZ);
}
target.playSound(WizardrySounds.ENTITY_HAMMER_ATTACK, 1.0F, rand.nextFloat() * 0.4F + 1.5F);
target.playSound(WizardrySounds.ENTITY_HAMMER_ATTACK, 1.0F, rand.nextFloat() * 0.4F + 1.5F);
float damage = Spells.lightning_hammer.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier;
float damage = Spells.lightning_hammer.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier;
if(this.getCaster() != null){
WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage(
this, getCaster(), DamageType.SHOCK), damage);
WizardryUtilities.applyStandardKnockback(this, target);
}else{
target.attackEntityFrom(DamageSource.MAGIC, damage);
}
if(this.getCaster() != null){
WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage(
this, getCaster(), DamageType.SHOCK), damage);
WizardryUtilities.applyStandardKnockback(this, target);
}else{
target.attackEntityFrom(DamageSource.MAGIC, damage);
}
}
}
@@ -62,7 +62,7 @@ public class EntityHealAura extends EntityMagicConstruct {
target.motionZ = velZ;
}
}else if(target.getHealth() < target.getMaxHealth() && this.ticksExisted % 5 == 0){
}else if(target.getHealth() < target.getMaxHealth() && target.ticksExisted % 5 == 0){
target.heal(Spells.healing_aura.getProperty(Spell.HEALTH).floatValue() * damageMultiplier);
}
}
@@ -29,9 +29,9 @@ public class EntityIceSpike extends EntityMagicConstruct {
this.setRotation(-facing.getHorizontalAngle(), WizardryUtilities.getPitch(facing));
float yaw = (-facing.getHorizontalAngle()) * (float)Math.PI/180;
float pitch = (WizardryUtilities.getPitch(facing) - 90) * (float)Math.PI/180;
Vec3d min = new Vec3d(-width/2, 0, -width/2).rotatePitch(pitch).rotateYaw(yaw);
Vec3d max = new Vec3d(width/2, height, width/2).rotatePitch(pitch).rotateYaw(yaw);
this.setEntityBoundingBox(new AxisAlignedBB(this.getPositionVector().add(min), this.getPositionVector().add(max)));
Vec3d min = this.getPositionVector().add(new Vec3d(-width/2, 0, -width/2).rotatePitch(pitch).rotateYaw(yaw));
Vec3d max = this.getPositionVector().add(new Vec3d(width/2, height, width/2).rotatePitch(pitch).rotateYaw(yaw));
this.setEntityBoundingBox(new AxisAlignedBB(min.x, min.y, min.z, max.x, max.y, max.z));
}
public EnumFacing getFacing(){
@@ -213,6 +213,7 @@ public class EntityAIAttackSpell<T extends EntityLiving & ISpellCaster> extends
return false;
}
// This is only called when spell casting starts so ticksInUse is always zero
if(spell.cast(attacker.world, attacker, EnumHand.MAIN_HAND, 0, target, modifiers)){
if(spell.isContinuous){
@@ -35,11 +35,17 @@ import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.Event;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nullable;
import java.util.*;
@Mod.EventBusSubscriber
public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData {
private EntityAIAttackSpell<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50);
@@ -68,6 +74,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
// Field implementations
private List<Spell> spells = new ArrayList<Spell>(4);
private Spell continuousSpell;
private int spellCounter;
public EntityEvilWizard(World world){
@@ -169,6 +176,16 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
public Spell getContinuousSpell(){
return this.continuousSpell;
}
@Override
public void setSpellCounter(int count){
spellCounter = count;
}
@Override
public int getSpellCounter(){
return spellCounter;
}
@Override
public int getAimingError(EnumDifficulty difficulty){
@@ -246,7 +263,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
// When right-clicked with a spell book in creative, sets one of the spells to that spell
if(player.isCreative() && stack.getItem() instanceof ItemSpellBook){
Spell spell = Spell.byMetadata(stack.getItemDamage());
if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){
if(this.spells.size() >= 4 && spell.canBeCastBy(this, true)){
// The set(...) method returns the element that was replaced - neat!
player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard",
this.getDisplayName(), this.spells.set(rand.nextInt(3) + 1, spell).getNameForTranslationFormatted(),
@@ -263,9 +280,9 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
super.writeEntityToNBT(nbt);
nbt.setInteger("element", this.getElement().ordinal());
nbt.setInteger("skin", this.textureIndex);
nbt.setTag("spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata())));
NBTExtras.storeTagSafely(nbt, "spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata())));
nbt.setBoolean("hasStructure", this.hasStructure);
nbt.setTag("groupUUIDs", NBTExtras.listToNBT(groupUUIDs, NBTUtil::createUUIDTag));
NBTExtras.storeTagSafely(nbt, "groupUUIDs", NBTExtras.listToNBT(groupUUIDs, NBTUtil::createUUIDTag));
}
@Override
@@ -283,16 +300,6 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
public int getMaxSpawnedInChunk(){
return 1;
}
@Override
public boolean getCanSpawnHere(){
// Evil wizards can only spawn in the specified dimensions
for(int id : Wizardry.settings.mobSpawnDimensions){
if(this.dimension == id) return super.getCanSpawnHere();
}
return false;
}
@Override
protected boolean canDespawn(){
@@ -373,7 +380,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
// All wizards know magic missile, even if it is disabled.
spells.add(Spells.magic_missile);
Tier maxTier = EntityWizard.populateSpells(spells, element, hasStructure, 3, rand);
Tier maxTier = EntityWizard.populateSpells(this, spells, element, hasStructure, 3, rand);
// Now done after the spells so it can take the tier into account. For evil wizards this is slightly different;
// it picks a random wand which is at least a high enough tier for the spells the wizard has.
@@ -393,4 +400,13 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
textureIndex = data.readInt();
}
@SubscribeEvent
public static void onCheckSpawnEvent(LivingSpawnEvent.CheckSpawn event){
// We have no way of checking if it's a spawner in getCanSpawnHere() so this has to be done here instead
if(event.getEntityLiving() instanceof EntityEvilWizard && !event.isSpawner()){
if(!ArrayUtils.contains(Wizardry.settings.mobSpawnDimensions, event.getWorld().provider.getDimension()))
event.setResult(Event.Result.DENY);
}
}
}
@@ -52,7 +52,7 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature
this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
this.tasks.addTask(7, new EntityAILookIdle(this));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<EntityLivingBase>(this, EntityLivingBase.class,
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
0, false, true, this.getTargetSelector()));
}
@@ -16,7 +16,13 @@ import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.Event;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.commons.lang3.ArrayUtils;
@Mod.EventBusSubscriber
public class EntityIceWraith extends EntityBlazeMinion {
/** The version from EntityLivingBase is only used in onLivingUpdate, so it can safely be copied. */
@@ -185,12 +191,16 @@ public class EntityIceWraith extends EntityBlazeMinion {
@Override
public boolean getCanSpawnHere(){
// Only spawns in the specified dimensions
for(int id : Wizardry.settings.mobSpawnDimensions){
if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel();
}
return super.getCanSpawnHere() && this.isValidLightLevel();
}
return false;
@SubscribeEvent
public static void onCheckSpawnEvent(LivingSpawnEvent.CheckSpawn event){
// We have no way of checking if it's a spawner in getCanSpawnHere() so this has to be done here instead
if(event.getEntityLiving() instanceof EntityLightningWraith && !event.isSpawner()){
if(!ArrayUtils.contains(Wizardry.settings.mobSpawnDimensions, event.getWorld().provider.getDimension()))
event.setResult(Event.Result.DENY);
}
}
/**
@@ -13,7 +13,13 @@ import net.minecraft.init.MobEffects;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumHand;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.Event;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.commons.lang3.ArrayUtils;
@Mod.EventBusSubscriber
public class EntityLightningWraith extends EntityBlazeMinion {
public EntityLightningWraith(World world){
@@ -74,14 +80,17 @@ public class EntityLightningWraith extends EntityBlazeMinion {
@Override
public boolean getCanSpawnHere(){
// Only spawns in the specified dimensions, during thunderstorms
if(!world.isThundering()) return false;
return super.getCanSpawnHere() && this.isValidLightLevel();
}
for(int id : Wizardry.settings.mobSpawnDimensions){
if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel();
@SubscribeEvent
public static void onCheckSpawnEvent(LivingSpawnEvent.CheckSpawn event){
// We have no way of checking if it's a spawner in getCanSpawnHere() so this has to be done here instead
if(event.getEntityLiving() instanceof EntityLightningWraith && !event.isSpawner()){
if(!event.getWorld().isThundering()) event.setResult(Event.Result.DENY);
if(!ArrayUtils.contains(Wizardry.settings.mobSpawnDimensions, event.getWorld().provider.getDimension()))
event.setResult(Event.Result.DENY);
}
return false;
}
/**
@@ -30,6 +30,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste
private EntityAIAttackSpell<EntityPhoenix> spellAttackAI = new EntityAIAttackSpell<>(this, AISpeed, 15f, 60, 140);
private Spell continuousSpell;
private int spellCounter;
private static final List<Spell> attack = Collections.singletonList(Spells.flame_ray);
@@ -50,7 +51,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste
this.tasks.addTask(3, new EntityAILookIdle(this));
// this.targetTasks.addTask(0, new EntityAIMoveTowardsTarget(this, 1, 10));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<EntityLivingBase>(this, EntityLivingBase.class,
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
0, false, true, this.getTargetSelector()));
this.setAIMoveSpeed((float)AISpeed);
@@ -76,6 +77,16 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste
continuousSpell = spell;
}
@Override
public void setSpellCounter(int count){
spellCounter = count;
}
@Override
public int getSpellCounter(){
return spellCounter;
}
@Override
public boolean hasRangedAttack(){
return true;
@@ -45,7 +45,7 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell
this.tasks.addTask(2, new EntityAIWander(this, AISpeed));
this.tasks.addTask(3, new EntityAILookIdle(this));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<EntityLivingBase>(this, EntityLivingBase.class,
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
0, false, true, this.getTargetSelector()));
this.setAIMoveSpeed((float)AISpeed);
@@ -61,21 +61,6 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell
return attack;
}
@Override
public SpellModifiers getModifiers(){
return new SpellModifiers();
}
@Override
public Spell getContinuousSpell(){
return Spells.none;
}
@Override
public void setContinuousSpell(Spell spell){
// Doesn't use continuous spells.
}
@Override
protected void applyEntityAttributes(){
super.applyEntityAttributes();
@@ -59,21 +59,6 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe
return attack;
}
@Override
public SpellModifiers getModifiers(){
return new SpellModifiers();
}
@Override
public Spell getContinuousSpell(){
return Spells.none;
}
@Override
public void setContinuousSpell(Spell spell){
// Doesn't use continuous spells.
}
@Override
protected void applyEntityAttributes(){
super.applyEntityAttributes();
@@ -83,6 +83,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
// Field implementations
private List<Spell> spells = new ArrayList<Spell>(4);
private Spell continuousSpell;
private int spellCounter;
/** A set of the positions of the blocks that are part of this wizard's tower. */
private Set<BlockPos> towerBlocks;
@@ -187,7 +188,17 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
public Spell getContinuousSpell(){
return this.continuousSpell;
}
@Override
public void setSpellCounter(int count){
spellCounter = count;
}
@Override
public int getSpellCounter(){
return spellCounter;
}
@Override
public int getAimingError(EnumDifficulty difficulty){
// Being more intelligent than skeletons, wizards are a little more accurate.
@@ -218,7 +229,8 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
// Copied from EntityVillager
if(!this.world.isRemote && this.livingSoundTime > -this.getTalkInterval() + 20){
this.livingSoundTime = -this.getTalkInterval();
this.playSound(stack.isEmpty() ? WizardrySounds.ENTITY_WIZARD_NO : WizardrySounds.ENTITY_WIZARD_YES, this.getSoundVolume(), this.getSoundPitch());
SoundEvent yes = Wizardry.tisTheSeason ? WizardrySounds.ENTITY_WIZARD_HOHOHO : WizardrySounds.ENTITY_WIZARD_YES;
this.playSound(stack.isEmpty() ? WizardrySounds.ENTITY_WIZARD_NO : yes, this.getSoundVolume(), this.getSoundPitch());
}
}
@@ -256,6 +268,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
@Override
protected SoundEvent getAmbientSound(){
if(Wizardry.tisTheSeason) return WizardrySounds.ENTITY_WIZARD_HOHOHO;
return this.isTrading() ? WizardrySounds.ENTITY_WIZARD_TRADING : WizardrySounds.ENTITY_WIZARD_AMBIENT;
}
@@ -357,7 +370,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
// When right-clicked with a spell book in creative, sets one of the spells to that spell
if(player.isCreative() && stack.getItem() instanceof ItemSpellBook){
Spell spell = Spell.byMetadata(stack.getItemDamage());
if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){
if(this.spells.size() >= 4 && spell.canBeCastBy(this, true)){
// The set(...) method returns the element that was replaced - neat!
player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard",
this.getDisplayName(), this.spells.set(rand.nextInt(3) + 1, spell).getNameForTranslationFormatted(),
@@ -387,15 +400,15 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
super.writeEntityToNBT(nbt);
if(this.trades != null){
nbt.setTag("trades", this.trades.getRecipiesAsTags());
NBTExtras.storeTagSafely(nbt, "trades", this.trades.getRecipiesAsTags());
}
nbt.setInteger("element", this.getElement().ordinal());
nbt.setInteger("skin", this.textureIndex);
nbt.setTag("spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata())));
NBTExtras.storeTagSafely(nbt, "spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata())));
if(this.towerBlocks != null && this.towerBlocks.size() > 0){
nbt.setTag("towerBlocks", NBTExtras.listToNBT(this.towerBlocks, NBTUtil::createPosTag));
NBTExtras.storeTagSafely(nbt, "towerBlocks", NBTExtras.listToNBT(this.towerBlocks, NBTUtil::createPosTag));
}
}
@@ -414,7 +427,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
this.spells = (List<Spell>)NBTExtras.NBTToList(nbt.getTagList("spells", NBT.TAG_INT),
(NBTTagInt tag) -> Spell.byMetadata(tag.getInt()));
NBTTagList tagList = nbt.getTagList("towerBlocks", NBT.TAG_LONG);
NBTTagList tagList = nbt.getTagList("towerBlocks", NBT.TAG_COMPOUND);
if(!tagList.isEmpty()){
this.towerBlocks = new HashSet<>(NBTExtras.NBTToList(tagList, NBTUtil::getPosFromTag));
}else{
@@ -750,7 +763,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
// All wizards know magic missile, even if it is disabled.
spells.add(Spells.magic_missile);
Tier maxTier = populateSpells(spells, element, false, 3, rand);
Tier maxTier = populateSpells(this, spells, element, false, 3, rand);
// Now done after the spells so it can take the tier into account.
ItemStack wand = new ItemStack(WizardryItems.getWand(maxTier, element));
@@ -767,19 +780,22 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
/**
* Adds n random spells to the given list. The spells will be of the given element if possible. Extracted as a
* separate function since it was the same in both EntityWizard and EntityEvilWizard.
*
*
* @param wizard The wizard whose spells are to be populated.
* @param spells The spell list to be populated.
* @param e The element that the spells should belong to, or {@link Element#MAGIC} for a random element each time.
* @param master Whether to include master spells.
* @param n The number of spells to add.
* @param random A random number generator to use.
* @return The tier of the highest-tier spell that was added to the list.
*/
static Tier populateSpells(List<Spell> spells, Element e, boolean master, int n, Random random){
static Tier populateSpells(final EntityLiving wizard, List<Spell> spells, Element e, boolean master, int n, Random random){
// This is the tier of the highest tier spell added.
Tier maxTier = Tier.NOVICE;
List<Spell> npcSpells = Spell.getSpells(Spell.npcSpells);
List<Spell> npcSpells = Spell.getSpells(s -> s.canBeCastBy(wizard, false));
npcSpells.removeIf(s -> !s.applicableForItem(WizardryItems.spell_book));
for(int i = 0; i < n; i++){
@@ -19,7 +19,9 @@ import java.util.List;
* packets) is handled by that class, and all the implementor needs to do is decide which spell(s) to select.
* <p></p>
* This class also allows Wizardry to do all the syncing necessary for continuous spell casting. All the implementor
* needs to do is store the actual fields involved.
* needs to do is store the actual fields involved, by implementing {@link ISpellCaster#setContinuousSpell(Spell)},
* {@link ISpellCaster#getContinuousSpell()}, {@link ISpellCaster#setSpellCounter(int)}, {@link ISpellCaster#getSpellCounter()}
* and {@link ISpellCaster#getModifiers()}.
*/
/* Perhaps this should be a capability? Though I can't help thinking they're mainly for attaching data to vanilla
* classes, rather than custom ones. For now, the main purpose of this is to centralise code within wizardry itself, and
@@ -36,10 +38,10 @@ public interface ISpellCaster {
*
* @return A list of {@link Spell} instances. A random spell from this list will be cast when the entity attacks.
* The list will not be modified by the AI class and can therefore be an immutable list. The spells in the
* list <b>must</b> be castable by NPCs (i.e. {@link Spell#canBeCastByNPCs()} returns true).
* list <b>must</b> be castable by NPCs (i.e. {@link Spell#canBeCastBy(net.minecraft.entity.EntityLiving, boolean)} returns true).
*/
@Nonnull
public List<Spell> getSpells();
List<Spell> getSpells();
/**
* Called each time the entity attacks to get the modifiers to apply to the spell.
@@ -48,31 +50,47 @@ public interface ISpellCaster {
* required, pass in an empty {@code SpellModifiers} object.
*/
@Nonnull
public SpellModifiers getModifiers();
default SpellModifiers getModifiers(){
return new SpellModifiers(); // May seem wasteful but this should never be called so it doesn't matter
}
/**
* Returns the continuous spell that is currently being cast, or the None spell if there is none. Implementors
* should simply store this as a private field and return it here. Will be synced by the AI class, but whether it is
* saved to NBT is up to you. If the implementing class does not deal with continuous spells, just return
* {@link Spells#none}. If the implementing class only ever uses one continuous spell, do <b>not</b> just return
* that spell; the field must still be stored.
* saved to NBT is up to you. If the implementing class only ever uses one continuous spell, do <b>not</b> just
* return that spell; the field must still be stored.
*/
@Nonnull
public Spell getContinuousSpell();
default Spell getContinuousSpell(){
return Spells.none;
}
/**
* Sets the continuous spell that is currently being cast, or the None spell if there is none. Implementors should
* simply store this as a private field and assign it here. Will be synced by the AI class, but whether it is saved
* to NBT is up to you. If the implementing class does not deal with continuous spells, leave this method blank.
*/
public void setContinuousSpell(Spell spell);
default void setContinuousSpell(Spell spell){
// Do nothing
}
/** Returns the number of ticks the current spell has been cast for. Implementors should simply store this as a
* private field and return it here. This is only used client-side. */
default int getSpellCounter(){
return 0;
}
/** Sets the number of ticks the current spell has been cast for. Implementors should simply store this as a
* private field and assign it here. This is only used client-side. */
default void setSpellCounter(int count){
// Do nothing
}
/**
* Returns the aiming arror for the given difficulty, used in projectile spells. Defaults to the values used by
* Returns the aiming error for the given difficulty, used in projectile spells. Defaults to the values used by
* skeletons, which are: Easy - 10, Normal - 6, Hard - 2, Peaceful - 10 (rarely used).
*/
// This is what default methods are actually intended for!
public default int getAimingError(EnumDifficulty difficulty) {
default int getAimingError(EnumDifficulty difficulty) {
return WizardryUtilities.getDefaultAimingError(difficulty);
}
}
@@ -221,7 +221,8 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData, IEntityOw
* possible for implementors to override this in order to do something special when selecting a target.
*/
default Predicate<Entity> getTargetSelector(){
return entity -> getCaster() == null ? entity instanceof EntityPlayer : !entity.isInvisible() && isValidTarget(entity);
return entity -> !entity.isInvisible() && (getCaster() == null ? entity instanceof EntityPlayer &&
!((EntityPlayer)entity).isCreative() : isValidTarget(entity));
}
/**
@@ -9,11 +9,15 @@ import electroblob.wizardry.util.ParticleBuilder;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.projectile.EntitySmallFireball;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.fml.common.Mod;
@@ -131,6 +135,54 @@ public class EntityMagicFireball extends EntityMagicProjectile {
}
}
@Override
public boolean canBeCollidedWith(){
return true;
}
@Override
public float getCollisionBorderSize(){
return 1.0F;
}
@Override
public boolean attackEntityFrom(DamageSource source, float amount){
if(this.isEntityInvulnerable(source)){
return false;
}else{
this.markVelocityChanged();
if(source.getTrueSource() != null){
Vec3d vec3d = source.getTrueSource().getLookVec();
if(vec3d != null){
double speed = MathHelper.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ);
this.motionX = vec3d.x * speed;
this.motionY = vec3d.y * speed;
this.motionZ = vec3d.z * speed;
this.lifetime = 160;
}
if(source.getTrueSource() instanceof EntityLivingBase){
this.setCaster((EntityLivingBase)source.getTrueSource());
}
return true;
}else{
return false;
}
}
}
public void setLifetime(int lifetime){
this.lifetime = lifetime;
}
@@ -1,5 +1,6 @@
package electroblob.wizardry.entity.projectile;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell;
@@ -44,15 +45,34 @@ public class EntityMagicMissile extends EntityMagicArrow {
public void tickInAir(){
if(this.world.isRemote){
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1)
.time(20 + rand.nextInt(10)).spawn(world);
if(this.ticksExisted > 1){ // Don't spawn particles behind where it started!
double x = posX - motionX/2;
double y = posY - motionY/2;
double z = posZ - motionZ/2;
ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1)
.time(20 + rand.nextInt(10)).spawn(world);
if(Wizardry.tisTheSeason){
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(0.8f, 0.15f, 0.15f)
.time(20 + rand.nextInt(10)).spawn(world);
ParticleBuilder.create(Type.SNOW).pos(posX, posY, posZ).spawn(world);
if(this.ticksExisted > 1){ // Don't spawn particles behind where it started!
double x = posX - motionX / 2;
double y = posY - motionY / 2;
double z = posZ - motionZ / 2;
ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(0.15f, 0.7f, 0.15f)
.time(20 + rand.nextInt(10)).spawn(world);
}
}else{
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1)
.time(20 + rand.nextInt(10)).spawn(world);
if(this.ticksExisted > 1){ // Don't spawn particles behind where it started!
double x = posX - motionX / 2;
double y = posY - motionY / 2;
double z = posZ - motionZ / 2;
ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1)
.time(20 + rand.nextInt(10)).spawn(world);
}
}
}
}
@@ -71,7 +71,7 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I
double dy = !this.hasNoGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0f) - this.posY
: target.getEntityBoundingBox().minY + (double)(target.height / 2.0f) - this.posY;
double dz = target.posZ - caster.posZ;
double horizontalDistance = (double)MathHelper.sqrt(dx * dx + dz * dz);
double horizontalDistance = MathHelper.sqrt(dx * dx + dz * dz);
if(horizontalDistance >= 1.0E-7D){
@@ -9,7 +9,6 @@ import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.EnumParticleTypes;
@@ -66,12 +65,11 @@ public class EntitySmokeBomb extends EntityBomb {
for(EntityLivingBase target : targets){
if(target != this.getThrower()){
// Gives the target blindness if it is a player, mind trick otherwise (since this has the desired
// Gives the target blindness, and mind trick if it's not a player (since this has the desired
// effect of preventing targeting)
if(target instanceof EntityPlayer){
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
}else if(target instanceof EntityLiving){
// New AI
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
if(target instanceof EntityLiving){
((EntityLiving)target).setAttackTarget(null);
target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, duration, 0));
}
@@ -58,6 +58,8 @@ public interface IConjuredItem {
*/
default int getMaxDamageFromNBT(ItemStack stack, Spell spell){
if(!spell.arePropertiesInitialised()) return 600; // Failsafe, some edge-cases call this during preInit
float baseDuration = spell.getProperty(SpellConjuration.ITEM_LIFETIME).floatValue();
if(stack.hasTagCompound() && stack.getTagCompound().hasKey(DURATION_MULTIPLIER_KEY)){
@@ -61,11 +61,10 @@ public class ItemArcaneTome extends Item {
Tier tier = Tier.values()[stack.getItemDamage()];
Tier tier2 = Tier.values()[stack.getItemDamage() - 1];
tooltip.add(tier.getDisplayNameWithFormatting());
tooltip.add("\u00A77" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":arcane_tome.desc1",
tier2.getDisplayNameWithFormatting()));
tooltip.add("\u00A77" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":arcane_tome.desc2",
tier.getDisplayNameWithFormatting() + "\u00A77"));
Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc",
tier2.getDisplayNameWithFormatting() + "\u00A77", tier.getDisplayNameWithFormatting() + "\u00A77");
}
}
@@ -265,7 +265,7 @@ public class ItemArtefact extends Item {
if(artefact == WizardryItems.ring_condensing){
if(world.isRemote && player.ticksExisted % 150 == 0){
if(player.ticksExisted % 150 == 0){
for(ItemStack stack : WizardryUtilities.getHotbar(player)){
// Needs to be both of these interfaces because this ring only recharges wands
// (or more accurately, chargeable spellcasting items)
@@ -276,7 +276,7 @@ public class ItemArtefact extends Item {
}else if(artefact == WizardryItems.amulet_arcane_defence){
if(world.isRemote && player.ticksExisted % 300 == 0){
if(player.ticksExisted % 300 == 0){
for(ItemStack stack : player.getArmorInventoryList()){
// IManaStoringItem is sufficient, since anything in the armour slots is probably armour
if(stack.getItem() instanceof IManaStoringItem)
@@ -601,7 +601,7 @@ public class ItemArtefact extends Item {
}else if(artefact == WizardryItems.amulet_transience){
if(player.getHealth() <= 2 && player.world.rand.nextFloat() < 0.25f){
if(player.getHealth() <= 6 && player.world.rand.nextFloat() < 0.25f){
player.addPotionEffect(new PotionEffect(WizardryPotions.transience, 300));
player.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, 300, 0, false, false));
}
@@ -639,6 +639,7 @@ public class ItemArtefact extends Item {
WizardryUtilities.getEntitiesWithinRadius(3, player.posX, player.posY, player.posZ, world).stream()
.filter(WizardryUtilities::isLiving)
.filter(e -> e != player)
.min(Comparator.comparingDouble(player::getDistanceSq))
.ifPresent(target -> {
@@ -1,5 +1,6 @@
package electroblob.wizardry.item;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.registry.Spells;
@@ -11,11 +12,13 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
public class ItemBlankScroll extends Item implements IWorkbenchItem {
public ItemBlankScroll(){
this.setCreativeTab(WizardryTabs.WIZARDRY);
this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0);
}
@Override
@@ -45,10 +48,14 @@ public class ItemBlankScroll extends Item implements IWorkbenchItem {
int cost = spell.getCost() * centre.getStack().getCount();
// Continuous spell scrolls require enough mana to cast them for the duration defined in ItemScroll.
if(spell.isContinuous) cost *= ItemScroll.CASTING_TIME / 20;
int manaPerItem = Constants.MANA_PER_CRYSTAL;
if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD;
if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA;
if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL > cost){
if(crystals.getStack().getCount() * manaPerItem > cost){
// Rounds up to the nearest whole crystal
crystals.decrStackSize(cost / Constants.MANA_PER_CRYSTAL + 1);
crystals.decrStackSize(cost / manaPerItem + 1);
centre.putStack(new ItemStack(WizardryItems.scroll, centre.getStack().getCount(), spell.metadata()));
return true;
}
@@ -3,6 +3,7 @@ package electroblob.wizardry.item;
import com.google.common.collect.Multimap;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.WizardryUtilities;
@@ -81,6 +82,12 @@ public class ItemFrostAxe extends ItemAxe implements IConjuredItem {
stack.setItemDamage(damage + 1);
}
@Override
public Multimap<String, AttributeModifier> getItemAttributeModifiers(EntityEquipmentSlot equipmentSlot){
attackDamage = Spells.frost_axe.getProperty(Spell.DAMAGE).floatValue();
return super.getItemAttributeModifiers(equipmentSlot);
}
@Override
public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase wielder){
if(!MagicDamage.isEntityImmune(DamageType.FROST, target))
@@ -1,7 +1,6 @@
package electroblob.wizardry.item;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.data.SpellGlyphData;
import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.event.SpellCastEvent.Source;
import electroblob.wizardry.packet.PacketCastSpell;
@@ -14,16 +13,12 @@ import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.*;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary;
import java.util.List;
@@ -37,6 +32,7 @@ public class ItemScroll extends Item implements ISpellCastingItem {
setHasSubtypes(true);
setMaxStackSize(16);
setCreativeTab(WizardryTabs.SPELLS);
this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0);
}
@Override
@@ -51,13 +47,14 @@ public class ItemScroll extends Item implements ISpellCastingItem {
@Override
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
if(tab == WizardryTabs.SPELLS){
// In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance
// is not required, only the metadata.
for(int i = 0; i < Spell.getTotalSpellCount(); i++){
// i+1 is used so that the metadata ties up with the metadata() method. In other words, the none spell has metadata
// 0 and since this is not used as a spell book the metadata starts at 1.
list.add(new ItemStack(this, 1, i + 1));
List<Spell> spells = Spell.getAllSpells();
spells.removeIf(s -> !s.applicableForItem(this));
for(Spell spell : spells){
list.add(new ItemStack(this, 1, spell.metadata()));
}
}
}
@@ -1,7 +1,9 @@
package electroblob.wizardry.item;
import com.google.common.collect.ImmutableMap;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.data.SpellGlyphData;
import electroblob.wizardry.registry.WizardryTabs;
import electroblob.wizardry.spell.Spell;
@@ -9,35 +11,41 @@ import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.*;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary;
import java.util.List;
import java.util.Map;
public class ItemSpellBook extends Item {
private static final Map<Tier, ResourceLocation> guiTextures = ImmutableMap.of(
Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"),
Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"),
Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"),
Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png"));
public ItemSpellBook(){
super();
setHasSubtypes(true);
setMaxStackSize(16);
setCreativeTab(WizardryTabs.SPELLS);
this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0);
}
@Override
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
if(tab == WizardryTabs.SPELLS){
// In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance
// is not required, only the metadata.
for(int i = 0; i < Spell.getTotalSpellCount(); i++){
// i+1 is used so that the metadata ties up with the metadata() method. In other words, the none spell has metadata
// 0 and since this is not used as a spell book the metadata starts at 1.
list.add(new ItemStack(this, 1, i + 1));
List<Spell> spells = Spell.getAllSpells();
spells.removeIf(s -> !s.applicableForItem(this));
for(Spell spell : spells){
list.add(new ItemStack(this, 1, spell.metadata()));
}
}
}
@@ -79,4 +87,12 @@ public class ItemSpellBook extends Item {
return Wizardry.proxy.getFontRenderer(stack);
}
/**
* Returns the GUI texture to be used when this spell book is opened.
* @param spell The spell for the book being opened.
*/
public ResourceLocation getGuiTexture(Spell spell){
return guiTextures.get(spell.getTier());
}
}
@@ -400,7 +400,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(Source.WAND, spell, caster, modifiers, castingTick))) return false;
}
int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST));
int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST) + 0.1f); // Weird floaty rounding
// As of wizardry 4.2 mana cost is only divided over two intervals each second
if(spell.isContinuous) cost = getDistributedCost(cost, castingTick);
@@ -436,7 +436,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
caster.setActiveHand(hand);
// Mana cost
int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST));
int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST) + 0.1f); // Weird floaty rounding
// As of wizardry 4.2 mana cost is only divided over two intervals each second
if(spell.isContinuous) cost = getDistributedCost(cost, castingTick);
@@ -497,7 +497,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
int castingTick = stack.getMaxItemUseDuration() - timeLeft; // Might as well include this
int cost = getDistributedCost((int)(spell.getCost() * modifiers.get(SpellModifiers.COST)), castingTick);
int cost = getDistributedCost((int)(spell.getCost() * modifiers.get(SpellModifiers.COST) + 0.1f), castingTick);
// Still need to check there's enough mana or the spell will finish twice, since running out of mana is
// handled separately.
@@ -57,12 +57,12 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
}
/** Should only be used by vanilla's armour damage calculations; use {@link ItemWizardArmour#setMana(ItemStack, int)}
* to modify wand mana from elsewhere. */
* to modify armour mana from elsewhere. */
@Override
public void setDamage(ItemStack stack, int damage){
// Overridden to stop repair things from 'repairing' the mana in wizard armour
// This being armour, it's much easier to let its damage increase normally, but block it from being decreased
if(stack.getItemDamage() < damage) super.setDamage(stack, damage);
if(stack.getItemDamage() < damage) super.setDamage(stack, Math.min(damage, stack.getMaxDamage()));
}
@Override
@@ -178,9 +178,14 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
String s = "wizard_armour";
if(this.element != null) s = s + "_" + this.element.getName();
if(Wizardry.tisTheSeason){
s = s + "_festive";
}else{
if(this.element != null) s = s + "_" + this.element.getName();
if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) s = "legendary_" + s;
}
if(slot == EntityEquipmentSlot.LEGS) s = s + "_legs";
if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) s = "legendary_" + s;
return "ebwizardry:textures/armour/" + s + ".png";
}
@@ -325,7 +330,7 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
IAttributeInstance attribute = event.getEntityLiving().getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE);
double followRange = attribute == null ? 16 : attribute.getAttributeValue();
if(event.getTarget().isSneaking()) followRange *= 0.8;
float f = armourPieces / ((EntityPlayer)event.getTarget()).inventory.armorInventory.size();
float f = (float)armourPieces / ((EntityPlayer)event.getTarget()).inventory.armorInventory.size();
if(f < 0.1F) f = 0.1F;
followRange *= (double)(0.7F * f);
// Don't need to worry about the isSuitableTarget check since it must already have been checked to get this far
@@ -108,10 +108,14 @@ public class RandomSpell extends LootFunction {
// element = null;
}
SpellProperties.Context spellContext = context.getLootedEntity() == null ? SpellProperties.Context.TREASURE
: SpellProperties.Context.LOOTING;
// Here's a thought: does randomly selecting the element beforehand (as opposed to leaving it null and letting
// the spell randomiser use any element) change the overall outcome at all?
List<Spell> spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element, SpellProperties.Context.TREASURE));
List<Spell> spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element, spellContext));
spellsList.removeIf(s -> !s.applicableForItem(stack.getItem()));
if(stack.getItem() instanceof ItemScroll) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.SCROLL));
if(stack.getItem() instanceof ItemSpellBook) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK));
@@ -5,6 +5,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.living.ISpellCaster;
import electroblob.wizardry.item.ItemScroll;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell;
@@ -33,13 +34,18 @@ public class WizardSpell extends LootFunction {
@Override
public ItemStack apply(ItemStack stack, Random random, LootContext context){
if(!(stack.getItem() instanceof ItemSpellBook)) Wizardry.logger
if(!(stack.getItem() instanceof ItemSpellBook) && !(stack.getItem() instanceof ItemScroll)) Wizardry.logger
.warn("Applying the wizard_spell loot function to an item that isn't a spell book or scroll.");
if(context.getLootedEntity() instanceof ISpellCaster){
List<Spell> spells = ((ISpellCaster)context.getLootedEntity()).getSpells();
spells.remove(Spells.magic_missile); // Can't drop magic missile
stack.setItemDamage(spells.get(random.nextInt(spells.size())).metadata());
spells.removeIf(s -> !s.applicableForItem(stack.getItem()));
if(spells.isEmpty()){
Wizardry.logger.warn("Tried to apply the wizard_spell loot function to an item, but none of the looted entity's spells were applicable for that item. This is probably a bug!");
}else{
stack.setItemDamage(spells.get(random.nextInt(spells.size())).metadata());
}
}else{
Wizardry.logger.warn("Applying the wizard_spell loot function to an entity that isn't a spell caster.");
}
@@ -62,7 +62,7 @@ public class BehaviourSpellDispense extends BehaviorDispenseOptional {
if(world.isSideSolid(source.getBlockPos().offset(direction), direction.getOpposite())) return stack;
// If the scroll can never be cast by a dispenser, it should be dispensed as an item.
if(!spell.canBeCastByDispensers()) return super.dispenseStack(source, stack);
if(!spell.canBeCastBy(source.getBlockTileEntity())) return super.dispenseStack(source, stack);
SpellModifiers modifiers = new SpellModifiers();
@@ -162,7 +162,7 @@ public abstract class Forfeit {
event.setCanceled(true);
Forfeit forfeit = getRandomForfeit(event.getWorld().rand, event.getSpell().getTier(), event.getSpell().getElement());
Forfeit forfeit = getRandomForfeit(data.synchronisedRandom, event.getSpell().getTier(), event.getSpell().getElement());
if(forfeit == null){ // Should never happen, but just in case...
if(!event.getWorld().isRemote) player.sendMessage(new TextComponentTranslation("forfeit.ebwizardry:do_nothing"));
@@ -15,8 +15,6 @@ import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapelessOreRecipe;
import javax.annotation.Nonnull;
/**
* Implements a dynamic crafting recipe for recharging items with mana flasks.
*
@@ -42,16 +40,17 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
this.flask = flask;
}
@Nonnull
@Override
public ItemStack getRecipeOutput(){
return ItemStack.EMPTY; // According to the javadoc, dynamic recipes are supposed to return an empty stack here
}
// Commented out for now because JEI spams the log with errors about the recipe having no output
// @Nonnull
// @Override
// public ItemStack getRecipeOutput(){
// return ItemStack.EMPTY; // According to the javadoc, dynamic recipes are supposed to return an empty stack here
// }
@Override
public ItemStack getCraftingResult(InventoryCrafting inv){
ItemStack result = super.getCraftingResult(inv);
rechargeItem(result, inv);
rechargeItemAndCopyNBT(result, inv);
return result;
}
@@ -62,11 +61,12 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
return super.matches(inv, world);
}
private void rechargeItem(ItemStack toCharge, InventoryCrafting inv){
private void rechargeItemAndCopyNBT(ItemStack toCharge, InventoryCrafting inv){
if(toCharge.getItem() == chargeable){
ItemStack stack = findItemToCharge(inv);
if(!stack.isEmpty()) chargeable.setMana(toCharge, chargeable.getMana(stack));
chargeable.rechargeMana(toCharge, flask.size.capacity);
toCharge.setTagCompound(stack.getTagCompound()); // Copy NBT to new stack
}else{
Wizardry.logger.warn("Tried to recharge item {} with mana flask, but it did not match the recipe result {}!", toCharge.getItem(), chargeable);
}
@@ -95,7 +95,7 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
if(recipe instanceof RecipeRechargeWithFlask
&& recipe.matches((InventoryCrafting)event.craftMatrix, event.player.world)){
// Have to modify the itemstack in the actual event, it cannot be replaced
((RecipeRechargeWithFlask)recipe).rechargeItem(event.crafting, (InventoryCrafting)event.craftMatrix);
((RecipeRechargeWithFlask)recipe).rechargeItemAndCopyNBT(event.crafting, (InventoryCrafting)event.craftMatrix);
}
}
}
@@ -1,47 +0,0 @@
package electroblob.wizardry.packet;
import electroblob.wizardry.Wizardry;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.Entity;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
/** <b>[Server -> Client]</b> This packet is sent when the slow time potion effect expires or is removed from an
* entity to unblock all nearby entities' updates. */
public class PacketEndSlowTime implements IMessageHandler<PacketEndSlowTime.Message, IMessage> {
@Override
public IMessage onMessage(Message message, MessageContext ctx){
// Just to make sure that the side is correct
if(ctx.side.isClient()){
net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleEndSlowTimePacket(message));
}
return null;
}
public static class Message implements IMessage {
public int hostID;
// This constructor is required otherwise you'll get errors (used somewhere in fml through reflection)
public Message(){
}
public Message(Entity host){
this.hostID = host.getEntityId();
}
@Override
public void fromBytes(ByteBuf buf){
this.hostID = buf.readInt();
}
@Override
public void toBytes(ByteBuf buf){
buf.writeInt(hostID);
}
}
}
@@ -26,7 +26,6 @@ public class WizardryPacketHandler {
registerMessage(PacketSpellProperties.class, PacketSpellProperties.Message.class);
registerMessage(PacketSyncAdvancements.class, PacketSyncAdvancements.Message.class);
registerMessage(PacketRequestAdvancementSync.class, PacketRequestAdvancementSync.Message.class);
registerMessage(PacketEndSlowTime.class, PacketEndSlowTime.Message.class);
registerMessage(PacketResurrection.class, PacketResurrection.Message.class);
registerMessage(PacketCastSpellAtPos.class, PacketCastSpellAtPos.Message.class);
registerMessage(PacketEmitterData.class, PacketEmitterData.Message.class);
@@ -2,6 +2,7 @@ package electroblob.wizardry.potion;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.util.NBTExtras;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayerMP;
@@ -40,7 +41,7 @@ public class PotionContainment extends PotionMagicEffect {
// Initialise the containment position to the entity's position if it wasn't set already
if(!target.getEntityData().hasKey(ENTITY_TAG)){
target.getEntityData().setTag(ENTITY_TAG, NBTUtil.createPosTag(new BlockPos(target.getPositionVector().subtract(0.5, 0.5, 0.5))));
NBTExtras.storeTagSafely(target.getEntityData(), ENTITY_TAG, NBTUtil.createPosTag(new BlockPos(target.getPositionVector().subtract(0.5, 0.5, 0.5))));
}
Vec3d origin = WizardryUtilities.getCentre(NBTUtil.getPosFromTag(target.getEntityData().getCompoundTag(ENTITY_TAG)));
@@ -2,8 +2,6 @@ package electroblob.wizardry.potion;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.packet.PacketEndSlowTime;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
@@ -17,11 +15,15 @@ import net.minecraft.entity.IProjectile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.event.entity.living.PotionEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import java.util.ArrayList;
import java.util.List;
@Mod.EventBusSubscriber
@@ -29,6 +31,8 @@ public class PotionSlowTime extends PotionMagicEffect implements ISyncedPotion {
// FIXME: Minecarts with entities in them (and, I suspect, any other ridden entities) go crazy when time-slowed
public static final String NBT_KEY = "time_slowed";
public PotionSlowTime(boolean isBadEffect, int liquidColour){
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icon_slow_time.png"));
this.setPotionName("potion." + Wizardry.MODID + ":slow_time");
@@ -61,6 +65,8 @@ public class PotionSlowTime extends PotionMagicEffect implements ISyncedPotion {
for(Entity entity : targetsInRange){
entity.getEntityData().setBoolean(NBT_KEY, true);
// If time is stopped, block all updates; otherwise block all updates except every [interval] ticks
entity.updateBlocked = stopTime || host.ticksExisted % interval != 0;
@@ -130,6 +136,29 @@ public class PotionSlowTime extends PotionMagicEffect implements ISyncedPotion {
}
/**
* Goes through every entity in the given world and does the following:<br>
* 1. Checks if they have the slow time NBT tag<br>
* 2. If so, scans the area nearby for players or NPCs with the slow time effect<br>
* 3. If none are found, removes the slow time NBT tag and unblocks the entity's updates
*/
public static void cleanUpEntities(World world){
// Had trouble with accessing loadedTileEntityList from tick events causing random CMEs so I'm making a
// copy of this too just in case
List<Entity> loadedEntityList = new ArrayList<>(world.loadedEntityList);
for(Entity entity : loadedEntityList){
if(entity.getEntityData().getBoolean(NBT_KEY)){
// Currently only players can cast slow time, but you could apply the effect to NPCs with commands
List<EntityLivingBase> nearby = WizardryUtilities.getEntitiesWithinRadius(getEffectRadius(), entity.posX, entity.posY, entity.posZ, entity.world, EntityLivingBase.class);
if(nearby.stream().noneMatch(e -> e.isPotionActive(WizardryPotions.slow_time))){
entity.getEntityData().removeTag(NBT_KEY);
entity.updateBlocked = false;
}
}
}
}
@SubscribeEvent
public static void onLivingUpdateEvent(LivingUpdateEvent event){
@@ -150,23 +179,16 @@ public class PotionSlowTime extends PotionMagicEffect implements ISyncedPotion {
}
@SubscribeEvent
public static void onPotionExpiryEvent(PotionEvent.PotionExpiryEvent event){
if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() == WizardryPotions.slow_time){
unblockNearbyEntities(event.getEntityLiving());
if(!event.getEntity().world.isRemote){
WizardryPacketHandler.net.sendToDimension(new PacketEndSlowTime.Message(event.getEntityLiving()), event.getEntity().dimension);
}
}
public static void tick(TickEvent.WorldTickEvent event){
if(!event.world.isRemote && event.phase == TickEvent.Phase.END) cleanUpEntities(event.world);
}
// We still need this as well as tick events because the player hasn't moved anywhere, they just logged out
// In fact, it won't really matter since the tick event fixes it on login anyway, but if the mod is uninstalled or
// something else weird happens...
@SubscribeEvent
public static void onPotionRemoveEvent(PotionEvent.PotionRemoveEvent event){
if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() == WizardryPotions.slow_time){
unblockNearbyEntities(event.getEntityLiving());
if(!event.getEntity().world.isRemote){
WizardryPacketHandler.net.sendToDimension(new PacketEndSlowTime.Message(event.getEntityLiving()), event.getEntity().dimension);
}
}
public static void onPlayerLoggedOutEvent(PlayerEvent.PlayerLoggedOutEvent event){
if(event.player.updateBlocked) event.player.updateBlocked = false;
}
}
@@ -5,6 +5,7 @@ import electroblob.wizardry.entity.construct.*;
import electroblob.wizardry.entity.living.*;
import electroblob.wizardry.entity.projectile.*;
import electroblob.wizardry.spell.*;
import net.minecraft.entity.projectile.EntitySnowball;
import net.minecraft.init.MobEffects;
import net.minecraft.item.EnumAction;
import net.minecraft.util.ResourceLocation;
@@ -243,10 +244,15 @@ public final class Spells {
IForgeRegistry<Spell> registry = event.getRegistry();
registry.register(new None());
registry.register(new SpellArrow<>("magic_missile", EntityMagicMissile::new).addProperties(Spell.DAMAGE).soundValues(1, 1.4f, 0.4f));
registry.register(new SpellArrow<EntityMagicMissile>("magic_missile", EntityMagicMissile::new){
@Override
protected String getTranslationKey(){
return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey();
}
}.addProperties(Spell.DAMAGE).soundValues(1, 1.4f, 0.4f));
registry.register(new Ignite());
registry.register(new Freeze());
registry.register(new Snowball());
registry.register(new SpellThrowable<>("snowball", EntitySnowball::new).npcSelector((e, o) -> o).soundValues(0.5f, 0.4f, 0.2f)); // Let's spare wizards the pain of the snowball spell
registry.register(new Arc());
registry.register(new SpellProjectile<>("thunderbolt", EntityThunderbolt::new).addProperties(Spell.DAMAGE, EntityThunderbolt.KNOCKBACK_STRENGTH).soundValues(0.8f, 0.9f, 0.2f));
registry.register(new SummonZombie());
@@ -316,7 +322,7 @@ public final class Spells {
registry.register(new SpellProjectile<>("darkness_orb", EntityDarknessOrb::new).addProperties(Spell.DAMAGE, Spell.EFFECT_DURATION, Spell.EFFECT_STRENGTH).soundValues(0.5f, 0.4f, 0.2f));
registry.register(new ShadowWard());
registry.register(new Decay());
registry.register(new SpellBuff("water_breathing", 0.3f, 0.3f, 1, () -> MobEffects.WATER_BREATHING){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f));
registry.register(new SpellBuff("water_breathing", 0.3f, 0.3f, 1, () -> MobEffects.WATER_BREATHING).npcSelector((e, o) -> false).soundValues(0.7f, 1.2f, 0.4f));
registry.register(new Tornado());
registry.register(new Glide());
registry.register(new SummonSpiritHorse());
@@ -367,7 +373,7 @@ public final class Spells {
registry.register(new Intimidate());
registry.register(new Banish());
registry.register(new SixthSense());
registry.register(new SpellBuff("darkvision", 0, 0.4f, 0.7f, () -> MobEffects.NIGHT_VISION){ @Override public boolean canBeCastByNPCs(){ return false; } }.soundValues(0.7f, 1.2f, 0.4f));
registry.register(new SpellBuff("darkvision", 0, 0.4f, 0.7f, () -> MobEffects.NIGHT_VISION).npcSelector((e, o) -> false).soundValues(0.7f, 1.2f, 0.4f));
registry.register(new Clairvoyance());
registry.register(new PocketWorkbench());
registry.register(new ImbueWeapon());
@@ -5,7 +5,6 @@ import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.loot.RandomSpell;
import electroblob.wizardry.loot.WizardSpell;
import electroblob.wizardry.spell.Spell;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.*;
@@ -88,6 +88,7 @@ public final class WizardrySounds {
public static final SoundEvent ENTITY_WIZARD_TRADING = createSound("entity.wizard.trading");
public static final SoundEvent ENTITY_WIZARD_HURT = createSound("entity.wizard.hurt");
public static final SoundEvent ENTITY_WIZARD_DEATH = createSound("entity.wizard.death");
public static final SoundEvent ENTITY_WIZARD_HOHOHO = createSound("entity.wizard.hohoho");
public static final SoundEvent ENTITY_DARKNESS_ORB_HIT = createSound("entity.darkness_orb.hit");
public static final SoundEvent ENTITY_DART_HIT = createSound("entity.dart.hit");
@@ -132,10 +133,17 @@ public final class WizardrySounds {
public static final SoundEvent MISC_PAGE_TURN = createSound("misc.page_turn");
public static final SoundEvent MISC_FREEZE = createSound("misc.freeze");
/** Trick borrowed from the Twilight Forest, makes things neater. */
// Trick borrowed from the Twilight Forest, makes things neater.
/** Overload for {@link WizardrySounds#createSound(String, String)} which assigns wizardry's mod ID automatically. */
public static SoundEvent createSound(String name){
return createSound(Wizardry.MODID, name);
}
/** Creates a sound with the given name, to be read from {@code assets/[modID]/sounds.json}. */
public static SoundEvent createSound(String modID, String name){
// All the setRegistryName methods delegate to this one, it doesn't matter which you use.
return new SoundEvent(new ResourceLocation(Wizardry.MODID, name)).setRegistryName(name);
return new SoundEvent(new ResourceLocation(modID, name)).setRegistryName(name);
}
// For some reason, sound events seem to work even when they aren't registered, without even so much as a warning.
@@ -250,7 +258,7 @@ public final class WizardrySounds {
event.getRegistry().register(MISC_PAGE_TURN);
event.getRegistry().register(MISC_FREEZE);
for(Spell spell : Spell.getSpells(Spell.allSpells)){
for(Spell spell : Spell.getAllSpells()){
event.getRegistry().registerAll(spell.getSounds());
}
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
@@ -18,12 +19,21 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.lang.reflect.Field;
@Mod.EventBusSubscriber
public class ArcaneJammer extends SpellRay {
private static final Field spellTicks;
static { // Yay more reflection
spellTicks = ObfuscationReflectionHelper.findField(EntitySpellcasterIllager.class, "field_193087_b");
}
public ArcaneJammer(){
super("arcane_jammer", false, EnumAction.NONE);
this.soundValues(0.7f, 1, 0.4f);
@@ -68,9 +78,17 @@ public class ArcaneJammer extends SpellRay {
@SubscribeEvent
public static void onLivingUpdateEvent(LivingEvent.LivingUpdateEvent event){
if(event.getEntity() instanceof EntitySpellcasterIllager
&& event.getEntityLiving().isPotionActive(WizardryPotions.arcane_jammer)){
((EntitySpellcasterIllager)event.getEntity()).setSpellType(EntitySpellcasterIllager.SpellType.NONE);
try{
spellTicks.set(event.getEntity(), 10);
}catch(IllegalAccessException e){
Wizardry.logger.error("Error setting evoker spell timer:", e);
}
}
}
@@ -6,11 +6,13 @@ import electroblob.wizardry.util.NBTExtras;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
@@ -32,9 +34,9 @@ public class ArcaneLock extends SpellRay {
@Override public boolean requiresPacket(){ return true; }
@Override public boolean canBeCastByDispensers(){ return false; }
@Override public boolean canBeCastBy(TileEntityDispenser dispenser){ return false; }
@Override public boolean canBeCastByNPCs(){ return false; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return false; }
@Override
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
@@ -7,6 +8,7 @@ import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes;
@@ -78,9 +80,7 @@ public class Banish extends SpellRay {
world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5);
}
// Can't be bothered to route this through the proxies!
if(entity == net.minecraft.client.Minecraft.getMinecraft().player)
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect();
if(entity instanceof EntityPlayer) Wizardry.proxy.playBlinkEffect((EntityPlayer)entity);
}
if(y != null){
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.RayTracer;
import electroblob.wizardry.util.SpellModifiers;
@@ -41,9 +42,8 @@ public class Blink extends Spell {
world.spawnParticle(EnumParticleTypes.PORTAL, dx, dy, dz, world.rand.nextDouble() - 0.5,
world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5);
}
// Can't be bothered to route this through the proxies!
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect();
Wizardry.proxy.playBlinkEffect(caster);
}
if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){
@@ -136,7 +136,7 @@ public class Blink extends Spell {
}
@Override
public boolean canBeCastByNPCs(){
public boolean canBeCastBy(EntityLiving npc, boolean override){
return true;
}
@@ -12,6 +12,7 @@ import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.entity.player.EntityPlayer;
@@ -21,6 +22,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.pathfinding.Path;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.pathfinding.PathPoint;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
@@ -44,8 +46,8 @@ public class Clairvoyance extends Spell {
WizardData.registerStoredVariables(LOCATION_KEY, DIMENSION_KEY);
}
@Override public boolean canBeCastByNPCs() { return false; }
@Override public boolean canBeCastByDispensers() { return false; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; }
@Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; }
@Override
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
@@ -3,6 +3,7 @@ package electroblob.wizardry.spell;
import com.google.common.collect.ImmutableMap;
import electroblob.wizardry.item.IConjuredItem;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.NBTExtras;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.player.EntityPlayer;
@@ -40,7 +41,7 @@ public class ConjureArmour extends SpellConjuration {
armour = new ItemStack(SPECTRAL_ARMOUR_MAP.get(slot));
IConjuredItem.setDurationMultiplier(armour, modifiers.get(WizardryItems.duration_upgrade));
// Sets a blank "ench" tag to trick the renderer into showing the enchantment effect on the armour model
armour.getTagCompound().setTag("ench", new NBTTagList());
NBTExtras.storeTagSafely(armour.getTagCompound(), "ench", new NBTTagList());
caster.setItemStackToSlot(slot, armour);
flag = true;
}
@@ -9,12 +9,14 @@ import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.*;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
@@ -45,9 +47,9 @@ public class CurseOfSoulbinding extends SpellRay {
WizardData.registerStoredVariables(TARGETS_KEY);
}
@Override public boolean canBeCastByNPCs() { return false; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; }
// You can't damage a dispenser so this would be nonsense!
@Override public boolean canBeCastByDispensers() { return false; }
@Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; }
@Override
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
@@ -21,7 +21,7 @@ public class Decoy extends Spell {
addProperties(DECOY_LIFETIME, MOB_TRICK_CHANCE);
}
@Override public boolean canBeCastByNPCs(){ return true; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return true; }
@Override
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
@@ -85,7 +85,7 @@ public class DragonFireball extends Spell {
}
@Override
public boolean canBeCastByNPCs(){
public boolean canBeCastBy(EntityLiving npc, boolean override){
return true;
}
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.registry.WizardryItems;
@@ -66,10 +67,16 @@ public class EmpoweringPresence extends Spell {
return true;
}
@Override
protected String getTranslationKey(){
return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey();
}
@SubscribeEvent(priority = EventPriority.LOW) // Doesn't really matter but there's no point processing it if casting is blocked
public static void onSpellCastPreEvent(SpellCastEvent.Pre event){
// Empowerment stacks extra potency on top of the existing potency.
if(event.getCaster() != null && event.getCaster().isPotionActive(WizardryPotions.empowerment)){
if(event.getCaster() != null && event.getCaster().isPotionActive(WizardryPotions.empowerment)
&& !(event.getSpell() instanceof EmpoweringPresence)){ // Prevent exponential empowerment stacking!
float potency = 1 + Constants.EMPOWERMENT_POTENCY_PER_LEVEL
* (event.getCaster().getActivePotionEffect(WizardryPotions.empowerment).getAmplifier() + 1);
@@ -78,4 +85,5 @@ public class EmpoweringPresence extends Spell {
event.getModifiers().get(SpellModifiers.POTENCY) * potency, true);
}
}
}
@@ -11,6 +11,7 @@ import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
@@ -29,8 +30,8 @@ public class ForestOfThorns extends Spell {
}
@Override public boolean requiresPacket(){ return false; }
@Override public boolean canBeCastByNPCs(){ return true; }
@Override public boolean canBeCastByDispensers(){ return true; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return true; }
@Override public boolean canBeCastBy(TileEntityDispenser dispenser){ return true; }
@Override
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
@@ -11,6 +11,7 @@ public class FrostAxe extends SpellConjuration {
public FrostAxe(){
super("frost_axe", WizardryItems.frost_axe);
addProperties(DAMAGE);
}
@Override
@@ -9,7 +9,6 @@ import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundEvent;
import net.minecraft.world.World;
public class Glide extends Spell {
@@ -19,6 +19,7 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.EnumAction;
import net.minecraft.network.play.server.SPacketEntityVelocity;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundEvent;
@@ -58,12 +59,12 @@ public class Grapple extends Spell {
}
@Override
public boolean canBeCastByNPCs(){
return super.canBeCastByNPCs();
public boolean canBeCastBy(EntityLiving npc, boolean override){
return true;
}
@Override
public boolean canBeCastByDispensers(){
public boolean canBeCastBy(TileEntityDispenser dispenser){
return true;
}
@@ -9,12 +9,14 @@ import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityTNTPrimed;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.EnumAction;
import net.minecraft.network.play.server.SPacketEntityVelocity;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
@@ -41,8 +43,8 @@ public class GreaterTelekinesis extends SpellRay {
this.soundValues(0.8f, 1, 0.2f);
}
@Override public boolean canBeCastByNPCs() { return false; }
@Override public boolean canBeCastByDispensers() { return false; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; }
@Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; }
@Override
protected SoundEvent[] createSounds(){
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.AllyDesignationSystem;
import electroblob.wizardry.util.ParticleBuilder;
@@ -62,4 +63,9 @@ public class InvigoratingPresence extends Spell {
return true;
}
@Override
protected String getTranslationKey(){
return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey();
}
}
@@ -10,6 +10,7 @@ import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.*;
import net.minecraft.entity.passive.*;
@@ -52,7 +53,7 @@ public class Metamorphosis extends SpellRay {
this.soundValues(0.5f, 1f, 0);
}
@Override public boolean canBeCastByNPCs() { return false; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; }
@Override
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
@@ -19,6 +19,7 @@ import net.minecraft.item.EnumAction;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
@@ -43,8 +44,8 @@ public class MindControl extends SpellRay {
addProperties(EFFECT_DURATION);
}
@Override public boolean canBeCastByNPCs() { return false; }
@Override public boolean canBeCastByDispensers() { return false; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; }
@Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; }
@Override
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
@@ -43,8 +43,7 @@ public class PhaseStep extends Spell {
world.rand.nextDouble() - 0.5, world.rand.nextDouble() - 0.5);
}
// Can't be bothered to route this through the proxies!
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect();
Wizardry.proxy.playBlinkEffect(caster);
}
if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){
@@ -8,6 +8,7 @@ import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects;
@@ -28,7 +29,7 @@ public class Poison extends SpellRay {
}
@Override
public boolean canBeCastByNPCs(){
public boolean canBeCastBy(EntityLiving npc, boolean override){
return true;
}
@@ -16,6 +16,7 @@ import electroblob.wizardry.packet.PacketPossession;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.NBTExtras;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
@@ -43,6 +44,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.potion.PotionEffect;
import net.minecraft.potion.PotionUtils;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
@@ -123,8 +125,8 @@ public class Possession extends SpellRay {
addProperties(EFFECT_DURATION, CRITICAL_HEALTH);
}
@Override public boolean canBeCastByNPCs() { return false; }
@Override public boolean canBeCastByDispensers() { return false; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override) { return false; }
@Override public boolean canBeCastBy(TileEntityDispenser dispenser) { return false; }
@Override
public boolean requiresPacket(){
@@ -267,7 +269,7 @@ public class Possession extends SpellRay {
// Inventory and items
if(possessor.getEntityData() != null){
possessor.getEntityData().setTag(INVENTORY_NBT_KEY, possessor.inventory.writeToNBT(new NBTTagList()));
NBTExtras.storeTagSafely(possessor.getEntityData(), INVENTORY_NBT_KEY, possessor.inventory.writeToNBT(new NBTTagList()));
}
possessor.inventory.clear();
@@ -1,6 +1,7 @@
package electroblob.wizardry.spell;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumHand;
@@ -17,7 +18,7 @@ public class ReplenishHunger extends SpellBuff {
addProperties(HUNGER_POINTS, SATURATION_MODIFIER);
}
@Override public boolean canBeCastByNPCs(){ return false; }
@Override public boolean canBeCastBy(EntityLiving npc, boolean override){ return false; }
@Override
protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){

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