Compare commits

..

142 Commits

Author SHA1 Message Date
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
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
Electroblob77 4cde8c60bc Fix NPE in WandHelper#getCurrentCooldown 2019-09-05 00:47:50 +01:00
Electroblob77 9924e10f13 Rebalance progression again 2019-09-05 00:33:45 +01:00
Electroblob77 eeb0640525 Fix incorrect description for tome of the diligent 2019-09-05 00:32:40 +01:00
Electroblob77 693c11ada0 Fix wands not resetting their progression when upgraded 2019-09-05 00:28:42 +01:00
Electroblob77 038fd7225f Add progression bar to arcane workbench GUI 2019-09-05 00:28:05 +01:00
Electroblob77 999e32f37c Add lower limit checks for wand cooldown indices in NBT, fixes #155 2019-09-05 00:20:13 +01:00
Electroblob77 8c2ac5adbb Update credits 2019-09-04 23:09:00 +01:00
Electroblob77 9c1e2e08c3 Update version number 2019-09-04 13:51:41 +01:00
Electroblob77 e7f7960540 Display intended Minecraft version in handbook instead of the exact version running (used to display the ugly 1.12.2-[forge version] string) 2019-09-04 13:50:14 +01:00
Electroblob77 a46bad4497 Prevent forfeits from breaking blocks they shouldn't break, fixes #190 2019-09-04 13:21:54 +01:00
Electroblob77 06d02ad45d Swap order of attacker/target null checks in ADS, fixes #185 2019-09-04 13:11:08 +01:00
Electroblob77 c39a213e62 Add null check for side hit to ice spikes spell, fixes #188 2019-09-04 13:04:40 +01:00
Electroblob77 2caca39a22 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-09-04 12:48:19 +01:00
Electroblob 8d46191ff8 Update guide_for_contributing.md 2019-09-04 12:46:49 +01:00
Electroblob77 fb7af9328d Correct typos in lang files 2019-09-04 12:31:10 +01:00
Electroblob77 0991baf964 Fix clairvoyance particles not moving correctly 2019-09-04 12:30:59 +01:00
Electroblob77 bdefecbe9b Replace event cancellation with setting target to null, fixes #236 2019-09-04 11:51:06 +01:00
Electroblob77 eef48f319a Commented code is dead code! 2019-09-04 11:48:19 +01:00
Electroblob77 3a788c867c Reimplement fix for #68 from #110, using IManaStoringItem and multiple mana flask sizes 2019-09-04 11:47:23 +01:00
Electroblob77 1ba723ade1 Add Polish translations, courtesy of Trozuu 2019-09-03 20:59:17 +01:00
Electroblob77 c06105cd00 Add tier, element and spell type to advanced tooltips for spell books and scrolls 2019-09-03 20:55:41 +01:00
Electroblob77 97c72685bb Fix construct spells crashing the game when cast by dispensers, fixes #182 2019-09-03 18:37:56 +01:00
Electroblob77 23fccaac9c How did that happen?! 2019-09-03 18:37:17 +01:00
Electroblob77 74b6bdba0f Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-09-03 17:42:55 +01:00
Electroblob77 d69e3a253d Add check for first person player when applying/removing possession shaders, fixes #179 2019-09-03 17:37:02 +01:00
Electroblob77 744c7a2331 Rebalance resistance spells 2019-09-03 17:31:38 +01:00
Electroblob c355cb034c Update issue templates 2019-09-03 17:27:33 +01:00
Electroblob77 5e321cc4cf Require the player to be sneaking to dispel a block with conjure block 2019-09-03 17:19:09 +01:00
Electroblob77 fbecce0543 Fix spectral block lighting and make it full brightness 2019-09-03 17:18:20 +01:00
Electroblob77 a6c24e9cb6 Cleanup 2019-09-03 16:27:55 +01:00
Electroblob77 14a624db3f Helps if you actually populate the enchantment fields... fixes imbuement spells not working properly, see #217 2019-09-03 16:27:03 +01:00
Electroblob77 16a4c8231f Remove isHandActive check from spectral bow reequip method, fixes part 7 of #217 2019-09-03 15:58:43 +01:00
Electroblob77 931c99617c Move sound category initialisation to preInit and replace the colon with an underscore, fixes #198
I should learn to read, it's literally written in the javadoc for CustomSoundCategory...
2019-09-03 15:45:25 +01:00
Electroblob77 037f340a03 Add keys for WAWLA enchantment description support, fixes #210 2019-09-02 19:25:56 +01:00
Electroblob77 b6cc417641 Reduce required progression for each tier a bit 2019-09-02 19:19:45 +01:00
Electroblob77 6565a0734a Add 5x progression modifier for casting an undiscovered spell for the first time 2019-09-02 19:11:08 +01:00
Electroblob77 0aac70c5fb Reduce spells tracked for wand progression from 10 to 5 2019-09-02 19:10:11 +01:00
Electroblob77 8551dc407b Add array range checks to all cooldown methods that don't have them, fixes #183
I'm concerned this may just be convering up the problem, but without being able to recreate it there's little else I can do.
2019-09-02 19:03:08 +01:00
Electroblob77 1eec7921ce Add Minecraft and Forge version requirements 2019-09-02 18:51:51 +01:00
Electroblob77 18920a24c5 Increase default rarity of structures 2019-09-02 18:24:07 +01:00
Electroblob77 e0c6f0f00f Add null check in transportation packet handler, fixes #229 2019-09-02 17:47:19 +01:00
Electroblob77 a4f6391fac Why was that outside the check?! 2019-09-02 17:46:38 +01:00
Electroblob77 a570bd57d0 Replace call to client-side-only method setVelocity, fixes #228 2019-09-02 17:39:36 +01:00
Electroblob77 f1ff179b98 Check if spell properties are initialised when setting lightning hammer item attribute modifiers, fixes #219 2019-09-02 17:05:21 +01:00
Electroblob77 6d09acc78e Make combustion rune respect playerBlockDamage and mobGriefing settings, fixes part of #217 2019-09-02 16:32:03 +01:00
Electroblob77 960d97de49 Prevent IndexOutOfBoundsException when clicking an already-remembered stone circle, fixes second crash in #217 2019-09-02 16:03:40 +01:00
Electroblob77 ebe64b06e3 Move setBlockState call inside !world.isRemote check, fixes #216 2019-09-02 15:51:44 +01:00
Electroblob77 99887f95e2 Copy loaded tile entity list before iterating client-side, fixes #205 2019-09-02 15:18:17 +01:00
Electroblob77 2e5a9fce3e Don't call canCast() from WizardryUtilities#isCasting(), fixes #196 2019-09-02 15:15:36 +01:00
Electroblob77 2be6230977 Well that didn't merge correctly... temporarily remove custom charging recipe classes
These need a bit more work to fit into the new system
2019-08-18 23:09:03 +01:00
Electroblob77 518d69a2e2 Update version number 2019-08-18 22:46:46 +01:00
Electroblob77 93bc9b1b89 Add tree blocks config option, fixes #165 2019-08-18 22:44:09 +01:00
Electroblob77 413d21d1d8 Add backwards-compatibility to wizard tower rarity, if it's below the new minimum value (which the old default was), it automatically gets reset to the default value of 600. 2019-08-18 22:09:09 +01:00
Electroblob77 78fc00c0cc Yet another AIOOBE fix for WandHelper, fixes #176
Right, I've had enough of this. Why do other people keep getting AIOOBEs from WandHelper when I've never ever had one in my dev environment, after all the testing I've done? What gives?!
2019-08-18 22:02:47 +01:00
Electroblob77 a1d2d6a16e Render blank crafting grid instead of throwing a JsonSyntaxException on nonexistent recipe defined in the wizard's hanbook, fixes #171. 2019-08-18 21:58:18 +01:00
Electroblob77 d6492ee3f1 Cleanup 2019-08-18 21:09:42 +01:00
Electroblob77 831f68d8d9 Add null checks to potion removal and expiry event handlers, fixes #166 2019-08-18 20:17:12 +01:00
Electroblob77 f86ea2334d Merge branch '1.12.2-dev' into 1.12.2 2019-08-18 12:34:04 +01:00
Electroblob d8f3ca2d01 Update guide_for_contributing.md 2019-07-16 23:18:14 +01:00
Electroblob b262f711e2 Update issue templates 2019-07-16 23:15:11 +01:00
Electroblob 4da63d6735 Update README.md 2019-06-15 14:41:39 +01:00
Electroblob be80d4863c Update README.md 2019-06-15 14:40:56 +01:00
Electroblob 62c696cd13 Update README.md 2019-06-15 14:37:37 +01:00
Electroblob f58dfea4bf Update README.md 2019-06-15 14:33:13 +01:00
Electroblob a924545457 Remove spaces and stuff from build.gradle
I dunno, they probably break all the fancy gradle things and I usually rename the jar after compiling anyway.
2019-04-15 23:06:42 +01:00
Electroblob 290d420e6b Merge pull request #123 from lorrampi/patch-2
Create handbook_pt_br.txt
2019-03-22 23:06:41 +00:00
Electroblob e4da941e40 Merge pull request #122 from lorrampi/patch-1
Create pt_br.lang
2019-03-22 23:06:08 +00:00
lorrampi 8e95e830a3 Create handbook_pt_br.txt
Based in lastest version of handbook_en_gb.txt
2019-03-21 15:40:20 -03:00
lorrampi 7d0334fc5a Create pt_br.lang
Based in lastest version of en_gb.lang
2019-03-21 15:33:15 -03:00
Electroblob b352105dd4 Update LICENSE.md 2019-02-08 00:18:01 +00:00
Electroblob 05e6b53970 Update LICENSE.md 2019-02-08 00:15:22 +00:00
Electroblob e76dc4a873 Update LICENSE.md 2019-02-08 00:13:26 +00:00
Electroblob 4d164c15ad Merge pull request #112 from kellixon/patch-1
Update ru_ru.lang
2019-01-31 00:11:54 +00:00
Konstantin 6b30c7923e Update ru_ru.lang
MC 1.12.2. Electroblob's Wizardry 4.1.4.
2019-01-28 17:45:41 +03:00
Electroblob 97a23d0e39 Merge pull request #111 from Tora-B/1.12.2
Switch immunities to an EnumSet. Fixes #49.
2019-01-27 11:28:36 +00:00
Torabi 44d1d4dbb7 Fix Immunities
Switch to an EnumSet for immunities, both because it's more efficient for this purpose, and because adding immunities to an entity caused a crash, because of improperly attempting to extend an array through the asList wrapper.
2019-01-26 09:06:59 -07:00
Electroblob 22cb4d7f56 Merge pull request #110 from Corail31/1.12.2
Fixes #68 #108
2019-01-15 23:25:16 +00:00
Corail31 54abdb6746 fix #108 2019-01-15 14:32:51 +01:00
Corail31 414b773da6 fix 68 2019-01-15 11:50:18 +01:00
170 changed files with 3585 additions and 569 deletions
+20
View File
@@ -0,0 +1,20 @@
---
name: Bug report
about: Report a crash or something that isn't working as it should
title: "[Give a brief, relevant title here]"
labels: bug
assignees: ''
---
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.2.2 [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.]
Other mods involved: [only list mods that are relevant to the problem]
Link to crash report (if applicable): [give a link to the crash report on gist, pastebin, etc.]
+16
View File
@@ -0,0 +1,16 @@
---
name: Feature request
about: Make a suggestion for improving the mod
title: "[Give a brief, relevant title here]"
labels: enhancement
assignees: ''
---
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
Minecraft versions: [if this suggestion only applies to some versions, list them here]
Suggestion details: [describe what you would like to see added to the mod and why]
Other mods involved: [if this suggestion involves integration with other mods, list them here]
+17
View File
@@ -0,0 +1,17 @@
---
name: Question
about: Ask a question about the mod or the code
title: "[Give a brief, relevant title here]"
labels: question
assignees: ''
---
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.2.2 [change as necessary]
Question details: [explain your question here]
Other mods involved: [if this question involves other mods, list them here]
+1
View File
@@ -23,6 +23,7 @@ run
logs logs
/misc /misc
/libs /libs
libs_src
libsfordeobf libsfordeobf
generated generated
Thumbs.db Thumbs.db
@@ -8,8 +8,12 @@ When submitting an issue, I would be grateful if you could follow these few guid
- Please stick to the issue template, it's there to help you provide the right information so I can fix the problem more easily. If you're not sure what to put for anything, that's ok, just leave it as it is. - Please stick to the issue template, it's there to help you provide the right information so I can fix the problem more easily. If you're not sure what to put for anything, that's ok, just leave it as it is.
- One issue per issue please! Make a separate issue for each bug/suggestion. If you think multiple different issues may be related, reference between them using # followed by the issue number.
- Please give me as much information about the issue as you can, but keep it relevant. "This is really annoying me and my friend" does not help me fix the problem! - Please give me as much information about the issue as you can, but keep it relevant. "This is really annoying me and my friend" does not help me fix the problem!
- Make sure your wizardry and Forge versions are both up-to-date for the game version you are using.
- There's no need to put 'tags' in square brackets in the issue title, I'll put proper github issue tags on it which will also help organise it. You can use them to search for issues too! - There's no need to put 'tags' in square brackets in the issue title, I'll put proper github issue tags on it which will also help organise it. You can use them to search for issues too!
- Don't close an issue unless it has actually been fixed or is no longer relevant - otherwise I might not end up fixing it at all! Usually I'll take care of closing issues anyway, so you don't have to worry about it. - Don't close an issue unless it has actually been fixed or is no longer relevant - otherwise I might not end up fixing it at all! Usually I'll take care of closing issues anyway, so you don't have to worry about it.
+13 -4
View File
@@ -1,7 +1,7 @@
# Credits # Credits
Electroblob's Wizardry Electroblob's Wizardry
Version 4.1.4 Version 4.2.6
For Minecraft 1.12.2 For Minecraft 1.12.2
Designed, coded and textured by Electroblob Designed, coded and textured by Electroblob
@@ -18,11 +18,20 @@ In addition, I'd like to thank the following individuals for their contributions
- 12foo - 12foo
- Shadows-of-Fire - Shadows-of-Fire
- HellFirePvP - HellFirePvP
- Tora-B
- Avatair
- Aeronica
- UltraHex
- Azim-Palmer
#### Translations #### Translations
- Russian: VilagVil - Spanish and Mexican Spanish: MadWrist
- Spanish and Mexican Spanish: MadWrist - Russian: VilagVil, kellixon
- Chinese: ZHENGLOC and dragon-evol - French: Hahdrim
- Brazilian Portuguese: lorrampi
- Chinese: ZHENGLOC, dragon-evol
- Korean: shejery, rewi_wire
- Polish: Trozuu
Lightning ray sound effect from OhhWowProductions Lightning ray sound effect from OhhWowProductions
+3 -3
View File
@@ -1,7 +1,7 @@
# License # License
This repository is copyright © Electroblob 2018. The following license is provided to allow you to creatively contribute to and improve the repository. This repository is copyright © Electroblob 2018. The following license is provided to allow you to creatively contribute to and improve the repository.
This license applies only to the source code, assets and wiki pages present in this repository. The compiled mod (available at https://minecraft.curseforge.com/projects/electroblobs-wizardry) comes under its own separate license, see the aforementioned webpage for details. This license applies only to the source code, assets and wiki pages present in this repository. The compiled mod (available at https://minecraft.curseforge.com/projects/electroblobs-wizardry) comes under its own separate license, see the aforementioned webpage for details. By downloading, running, forking, contributing to or otherwise interacting with this repository, you agree to the license set out below.
TL;DR: Do what you want with this repo on Github, but ask me first if you want to put it anywhere else or publish your version. Don't try and make money off the repo or anything in it. I'm not responsible if the code breaks things, and if you help me out by submitting a PR, I can use and modify the contents of that PR as long as I give you credit. (This brief summary is non-binding and does not override or replace the full license below.) TL;DR: Do what you want with this repo on Github, but ask me first if you want to put it anywhere else or publish your version. Don't try and make money off the repo or anything in it. I'm not responsible if the code breaks things, and if you help me out by submitting a PR, I can use and modify the contents of that PR as long as I give you credit. (This brief summary is non-binding and does not override or replace the full license below.)
@@ -27,7 +27,7 @@ TL;DR: Do what you want with this repo on Github, but ask me first if you want t
### 1. Warranty and usage ### 1. Warranty and usage
This repository, the source code for the Minecraft modification Electroblob's Wizardry ('Wizardry'), is provided in the hope that it will be useful and/or educational. You are free to download and modify this repository for personal use only. See section 2 for details regarding public sharing of this repository. This repository, the source code for the Minecraft modification Electroblob's Wizardry ('Wizardry'), is provided in the hope that it will be useful and/or educational. You are free to download and modify this repository for personal use. See section 2 for details regarding public sharing of this repository.
THIS REPOSITORY IS PROVIDED AS-IS WITH NO WARRANTIES, IMPLIED OR OTHERWISE. ELECTROBLOB TAKES NO RESPONSIBILITY FOR ANY DAMAGES INCURRED BY THE USE OR MISUSE OF THIS REPOSITORY. THIS REPOSITORY IS PROVIDED AS-IS WITH NO WARRANTIES, IMPLIED OR OTHERWISE. ELECTROBLOB TAKES NO RESPONSIBILITY FOR ANY DAMAGES INCURRED BY THE USE OR MISUSE OF THIS REPOSITORY.
@@ -37,7 +37,7 @@ In addition to private use as set out in section 1, you are free to fork this re
### 3. Distribution ### 3. Distribution
Distribution, in whole or in part, of compiled versions of wizardry, and distribution of the source code anywhere except on Github, modified or otherwise, is forbidden without advance written permission from Electroblob. Electroblob reserves the right to refuse or withdraw such permission at any time. Distribution of this repository anywhere except on Github, in whole or in part, modified or otherwise, is forbidden without advance written permission from Electroblob. Electroblob reserves the right to refuse or withdraw such permission at any time.
### 4. Commercial use ### 4. Commercial use
+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) [![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! 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> <b>Links</b>
+2 -2
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. //Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
version = "4.2.0" // There, it matches semver, happy now? (I am just gonna rename the file afterwards, you know that right?) version = "4.2.6" // There, it matches semver, happy now?
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "ElectroblobsWizardry" archivesBaseName = "ElectroblobsWizardry"
@@ -37,7 +37,7 @@ repositories {
// http://www.minecraftforge.net/forum/topic/44262-solved-how-to-build-mod-with-dependencies/ // http://www.minecraftforge.net/forum/topic/44262-solved-how-to-build-mod-with-dependencies/
// https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2866817-setting-up-dependencies-in-minecraft-forge-with // https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2866817-setting-up-dependencies-in-minecraft-forge-with
// http://www.minecraftforge.net/forum/topic/44534-adding-dependencies-to-a-forge-project/ // http://www.minecraftforge.net/forum/topic/44534-adding-dependencies-to-a-forge-project/
dirs "libsfordeobf" // Don't use libs or forge will think you have duplicate mods dirs "libsfordeobf" // Don't put src jars in libs or forge will think you have duplicate mods
} }
} }
@@ -7,6 +7,7 @@ import electroblob.wizardry.spell.Spell;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundCategory;
@@ -238,6 +239,9 @@ public class CommonProxy {
+ "of sound events, but the given array contained less than 3 sound events!"); + "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); 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 * 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.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import java.io.File;
import java.util.*; import java.util.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -67,6 +68,10 @@ public final class Settings {
/** The unlocalised name of the compatibility config category. */ /** The unlocalised name of the compatibility config category. */
public static final String COMPATIBILITY_CATEGORY = "compatibility"; public static final String COMPATIBILITY_CATEGORY = "compatibility";
private static final String[] DEFAULT_TREE_BLOCKS = {"dynamictrees:oakbranch", "dynamictrees:sprucebranch",
"dynamictrees:birchbranch", "dynamictrees:junglebranch", "dynamictrees:darkoakbranch",
"dynamictrees:acaciabranch", "dynamictrees:cactusbranch", "dynamictrees:leaves0", "dynamictrees:leaves1"};
private static final String[] DEFAULT_LOOT_INJECTION_LOCATIONS = {"minecraft:chests/simple_dungeon", private static final String[] DEFAULT_LOOT_INJECTION_LOCATIONS = {"minecraft:chests/simple_dungeon",
"minecraft:chests/abandoned_mineshaft", "minecraft:chests/desert_pyramid", "minecraft:chests/jungle_temple", "minecraft:chests/abandoned_mineshaft", "minecraft:chests/desert_pyramid", "minecraft:chests/jungle_temple",
"minecraft:chests/stronghold_corridor", "minecraft:chests/stronghold_crossing", "minecraft:chests/stronghold_corridor", "minecraft:chests/stronghold_crossing",
@@ -85,7 +90,7 @@ public final class Settings {
/** <b>[Server-only]</b> List of dimension ids in which to generate wizard towers. */ /** <b>[Server-only]</b> List of dimension ids in which to generate wizard towers. */
public int[] towerDimensions = {0}; public int[] towerDimensions = {0};
/** <b>[Server-only]</b> The rarity of wizard towers, used by the world generator. Larger numbers are rarer. */ /** <b>[Server-only]</b> The rarity of wizard towers, used by the world generator. Larger numbers are rarer. */
public int towerRarity = 600; public int towerRarity = 900;
/** <b>[Server-only]</b> List of structure file locations for wizard towers without loot chests. */ /** <b>[Server-only]</b> List of structure file locations for wizard towers without loot chests. */
public ResourceLocation[] towerFiles = {new ResourceLocation(Wizardry.MODID, "wizard_tower_0"), public ResourceLocation[] towerFiles = {new ResourceLocation(Wizardry.MODID, "wizard_tower_0"),
new ResourceLocation(Wizardry.MODID, "wizard_tower_1"), new ResourceLocation(Wizardry.MODID, "wizard_tower_1"),
@@ -99,7 +104,7 @@ public final class Settings {
/** <b>[Server-only]</b> List of dimension ids in which to generate obelisks. */ /** <b>[Server-only]</b> List of dimension ids in which to generate obelisks. */
public int[] obeliskDimensions = {0, -1}; public int[] obeliskDimensions = {0, -1};
/** <b>[Server-only]</b> The rarity of obelisks, used by the world generator. Larger numbers are rarer. */ /** <b>[Server-only]</b> The rarity of obelisks, used by the world generator. Larger numbers are rarer. */
public int obeliskRarity = 550; public int obeliskRarity = 800;
/** <b>[Server-only]</b> List of structure file locations for obelisks. */ /** <b>[Server-only]</b> List of structure file locations for obelisks. */
public ResourceLocation[] obeliskFiles = {new ResourceLocation(Wizardry.MODID, "obelisk_0"), public ResourceLocation[] obeliskFiles = {new ResourceLocation(Wizardry.MODID, "obelisk_0"),
new ResourceLocation(Wizardry.MODID, "obelisk_1"), new ResourceLocation(Wizardry.MODID, "obelisk_1"),
@@ -109,7 +114,7 @@ public final class Settings {
/** <b>[Server-only]</b> List of dimension ids in which to generate shrines. */ /** <b>[Server-only]</b> List of dimension ids in which to generate shrines. */
public int[] shrineDimensions = {0, -1}; public int[] shrineDimensions = {0, -1};
/** <b>[Server-only]</b> The rarity of shrines, used by the world generator. Larger numbers are rarer. */ /** <b>[Server-only]</b> The rarity of shrines, used by the world generator. Larger numbers are rarer. */
public int shrineRarity = 1000; public int shrineRarity = 1500;
/** <b>[Server-only]</b> List of structure file locations for shrines. */ /** <b>[Server-only]</b> List of structure file locations for shrines. */
public ResourceLocation[] shrineFiles = {new ResourceLocation(Wizardry.MODID, "shrine_0"), public ResourceLocation[] shrineFiles = {new ResourceLocation(Wizardry.MODID, "shrine_0"),
new ResourceLocation(Wizardry.MODID, "shrine_1"), new ResourceLocation(Wizardry.MODID, "shrine_1"),
@@ -119,6 +124,8 @@ public final class Settings {
new ResourceLocation(Wizardry.MODID, "shrine_5"), new ResourceLocation(Wizardry.MODID, "shrine_5"),
new ResourceLocation(Wizardry.MODID, "shrine_6"), new ResourceLocation(Wizardry.MODID, "shrine_6"),
new ResourceLocation(Wizardry.MODID, "shrine_7")}; new ResourceLocation(Wizardry.MODID, "shrine_7")};
/** <b>[Server-only]</b> List of solid blocks (usually trees) which are ignored by the structure generators. */
public ResourceLocation[] treeBlocks = toResourceLocations(DEFAULT_TREE_BLOCKS);
/** <b>[Server-only]</b> The chance for wizard towers to generate with an evil wizard and chest inside. */ /** <b>[Server-only]</b> The chance for wizard towers to generate with an evil wizard and chest inside. */
public double evilWizardChance = 0.2; public double evilWizardChance = 0.2;
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */ /** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
@@ -162,6 +169,8 @@ public final class Settings {
/** <b>[Server-only]</b> Whether to replace Minecraft's distance-based fall damage calculation with an equivalent, /** <b>[Server-only]</b> Whether to replace Minecraft's distance-based fall damage calculation with an equivalent,
* velocity-based one. */ * velocity-based one. */
public boolean replaceVanillaFallDamage = true; 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 * <b>[Server-only]</b> List of registry names of entities which summoned creatures are allowed to attack, in addition
* to the defaults. * to the defaults.
@@ -358,7 +367,7 @@ public final class Settings {
*/ */
void initConfig(FMLPreInitializationEvent event){ void initConfig(FMLPreInitializationEvent event){
config = new Configuration(event.getSuggestedConfigurationFile()); config = new Configuration(new File(Wizardry.configDirectory, Wizardry.MODID + ".cfg"));
config.load(); config.load();
Wizardry.logger.info("Setting up main config"); Wizardry.logger.info("Setting up main config");
@@ -535,6 +544,13 @@ public final class Settings {
slowTimeAffectsPlayers = property.getBoolean(); slowTimeAffectsPlayers = property.getBoolean();
propOrder.add(property.getName()); 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 = 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.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_whitelist");
property.setRequiresMcRestart(true); property.setRequiresMcRestart(true);
@@ -694,19 +710,23 @@ public final class Settings {
fastWorldgen = property.getBoolean(); fastWorldgen = property.getBoolean();
propOrder.add(property.getName()); 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.setLanguageKey("config." + Wizardry.MODID + ".tower_dimensions");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
towerDimensions = property.getIntList(); towerDimensions = property.getIntList();
propOrder.add(property.getName()); propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "towerRarity", 600, "Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.", 20, 5000); property = config.get(WORLDGEN_CATEGORY, "towerRarity", 900, "Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.", 20, 5000);
property.setLanguageKey("config." + Wizardry.MODID + ".tower_rarity"); property.setLanguageKey("config." + Wizardry.MODID + ".tower_rarity");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
Wizardry.proxy.setToNumberSliderEntry(property); Wizardry.proxy.setToNumberSliderEntry(property);
towerRarity = property.getInt(); towerRarity = property.getInt();
propOrder.add(property.getName()); propOrder.add(property.getName());
// A bit of backwards-compatibility: predictably, people don't read my instructions and update without deleting
// the config, resulting in wizard towers generating everywhere - so let's update it for them!
if(towerRarity < 20) towerRarity = 600; // The old default was 8, which is outside the new allowed range
property = config.get(WORLDGEN_CATEGORY, "evilWizardChance", 0.2, "The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.", 0, 1); property = config.get(WORLDGEN_CATEGORY, "evilWizardChance", 0.2, "The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.", 0, 1);
property.setLanguageKey("config." + Wizardry.MODID + ".evil_wizard_chance"); property.setLanguageKey("config." + Wizardry.MODID + ".evil_wizard_chance");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
@@ -715,26 +735,26 @@ public final class Settings {
propOrder.add(property.getName()); 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"}, 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.setLanguageKey("config." + Wizardry.MODID + ".tower_files");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
towerFiles = getResourceLocationList(property); towerFiles = getResourceLocationList(property);
propOrder.add(property.getName()); 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"}, 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.setLanguageKey("config." + Wizardry.MODID + ".tower_with_chest_files");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
towerWithChestFiles = getResourceLocationList(property); towerWithChestFiles = getResourceLocationList(property);
propOrder.add(property.getName()); 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.setLanguageKey("config." + Wizardry.MODID + ".obelisk_dimensions");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
obeliskDimensions = property.getIntList(); obeliskDimensions = property.getIntList();
propOrder.add(property.getName()); propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "obeliskRarity", 550, "Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.", 20, 5000); property = config.get(WORLDGEN_CATEGORY, "obeliskRarity", 800, "Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.", 20, 5000);
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_rarity"); property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_rarity");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
Wizardry.proxy.setToNumberSliderEntry(property); Wizardry.proxy.setToNumberSliderEntry(property);
@@ -742,19 +762,19 @@ public final class Settings {
propOrder.add(property.getName()); 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"}, 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.setLanguageKey("config." + Wizardry.MODID + ".obelisk_files");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
obeliskFiles = getResourceLocationList(property); obeliskFiles = getResourceLocationList(property);
propOrder.add(property.getName()); 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.setLanguageKey("config." + Wizardry.MODID + ".shrine_dimensions");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
shrineDimensions = property.getIntList(); shrineDimensions = property.getIntList();
propOrder.add(property.getName()); propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "shrineRarity", 1000, "Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.", 20, 5000); property = config.get(WORLDGEN_CATEGORY, "shrineRarity", 1500, "Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.", 20, 5000);
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_rarity"); property.setLanguageKey("config." + Wizardry.MODID + ".shrine_rarity");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
Wizardry.proxy.setToNumberSliderEntry(property); Wizardry.proxy.setToNumberSliderEntry(property);
@@ -762,12 +782,18 @@ public final class Settings {
propOrder.add(property.getName()); 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"}, 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.setLanguageKey("config." + Wizardry.MODID + ".shrine_files");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
shrineFiles = getResourceLocationList(property); shrineFiles = getResourceLocationList(property);
propOrder.add(property.getName()); propOrder.add(property.getName());
property = config.get(GAMEPLAY_CATEGORY, "treeBlocks", DEFAULT_TREE_BLOCKS, "List of registry names of blocks which can be overwritten by wizardry's structure generators, affecting both fast and fancy structure generation. Most tree blocks and other foliage should work automatically, but those that don't can be added manually here. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. dynamictrees:oakbranch).");
property.setLanguageKey("config." + Wizardry.MODID + ".tree_blocks");
property.setRequiresWorldRestart(true);
treeBlocks = getResourceLocationList(property);
propOrder.add(property.getName());
property = config.get(WORLDGEN_CATEGORY, "oreDimensions", new int[]{0}, "List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!"); property = config.get(WORLDGEN_CATEGORY, "oreDimensions", new int[]{0}, "List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!");
property.setLanguageKey("config." + Wizardry.MODID + ".ore_dimensions"); property.setLanguageKey("config." + Wizardry.MODID + ".ore_dimensions");
property.setRequiresWorldRestart(true); property.setRequiresWorldRestart(true);
@@ -12,10 +12,10 @@ import electroblob.wizardry.misc.Forfeit;
import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.*; import electroblob.wizardry.registry.*;
import electroblob.wizardry.spell.Spell; import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.CustomSoundCategory;
import electroblob.wizardry.util.SpellProperties; import electroblob.wizardry.util.SpellProperties;
import electroblob.wizardry.worldgen.*; import electroblob.wizardry.worldgen.*;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.util.SoundCategory;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod; 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 net.minecraftforge.fml.common.registry.GameRegistry;
import org.apache.logging.log4j.Logger; 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 * <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 * possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master
@@ -41,7 +44,10 @@ import org.apache.logging.log4j.Logger;
* @author Electroblob * @author Electroblob
* @since Wizardry 1.0 * @since Wizardry 1.0
*/ */
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, guiFactory = "electroblob.wizardry.WizardryGuiFactory")
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, acceptedMinecraftVersions = "[1.12.2]",
guiFactory = "electroblob.wizardry.WizardryGuiFactory", dependencies = "required-after:forge@[14.23.5.2814,)")
public class Wizardry { public class Wizardry {
/** Wizardry's mod ID. */ /** Wizardry's mod ID. */
@@ -51,14 +57,14 @@ public class Wizardry {
/** /**
* The version number for this version of wizardry. The following system is used for version numbers: * The version number for this version of wizardry. The following system is used for version numbers:
* <p></p> * <p></p>
* <center><b>[major Minecraft version].[major mod version].[minor mod version/patch] * <center><b>[major Minecraft version].[major mod version].[minor mod version/patch]</b>
* <p></p> * <p></p>
* </center></b> The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same * </center> The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same
* features as Wizardry 2.1, but they are for different versions of Minecraft and have separate minor versioning. * features as Wizardry 2.1, but they are for different versions of Minecraft and have separate minor versioning.
* 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft * 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. * 1.11.x versions, and so on.
*/ */
public static final String VERSION = "4.2.0"; public static final String VERSION = "4.2.6";
// IDEA: Triggering of inbuilt Forge events in relevant places? // IDEA: Triggering of inbuilt Forge events in relevant places?
// IDEA: Abstract the vanilla particles behind the particle builder // IDEA: Abstract the vanilla particles behind the particle builder
@@ -66,9 +72,6 @@ public class Wizardry {
// TODO: Have particles obey Minecraft's particle setting where appropriate // TODO: Have particles obey Minecraft's particle setting where appropriate
// (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java) // (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java)
// TODO: TileEntityArcaneWorkbench needs looking at, esp. regarding inventory and markDirty // TODO: TileEntityArcaneWorkbench needs looking at, esp. regarding inventory and markDirty
// TODO: See what can be done with the illager spell sounds (and go over sounds in general)
// TODO: Fix possession
// TODO: Fix charge
/** Static instance of the {@link Settings} object for Wizardry. */ /** Static instance of the {@link Settings} object for Wizardry. */
public static final Settings settings = new Settings(); public static final Settings settings = new Settings();
@@ -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. */ * - <b>INFO</b>: Anything that might happen during normal mod operation that the user needs to know about. */
public static Logger logger; 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. // The instance of wizardry that Forge uses.
@Instance(Wizardry.MODID) @Instance(Wizardry.MODID)
public static Wizardry instance; public static Wizardry instance;
@@ -97,8 +106,13 @@ public class Wizardry {
proxy.registerResourceReloadListeners(); proxy.registerResourceReloadListeners();
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
settings.initConfig(event); 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 // Capabilities
WizardData.register(); WizardData.register();
DispenserCastingData.register(); DispenserCastingData.register();
@@ -113,6 +127,9 @@ public class Wizardry {
proxy.registerRenderers(); proxy.registerRenderers();
proxy.registerKeyBindings(); proxy.registerKeyBindings();
// 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(); WizardryBaublesIntegration.init();
WizardryAntiqueAtlasIntegration.init(); WizardryAntiqueAtlasIntegration.init();
@@ -151,8 +168,6 @@ public class Wizardry {
proxy.initGuiBits(); proxy.initGuiBits();
proxy.registerParticles(); proxy.registerParticles();
proxy.registerSoundEventListener(); proxy.registerSoundEventListener();
WizardrySounds.SPELLS = CustomSoundCategory.add(Wizardry.MODID + ":spells");
} }
@EventHandler @EventHandler
@@ -81,7 +81,7 @@ public final class WizardryEventHandler {
} }
Spell.syncProperties(event.player); Spell.syncProperties(event.player);
} }
@SubscribeEvent(priority = EventPriority.HIGH) @SubscribeEvent(priority = EventPriority.HIGH)
public static void onPlaySoundAtEntityEvent(PlaySoundAtEntityEvent event){ public static void onPlaySoundAtEntityEvent(PlaySoundAtEntityEvent event){
// Muffle (there's no spell class for it so it's here instead) // Muffle (there's no spell class for it so it's here instead)
@@ -2,7 +2,6 @@ package electroblob.wizardry;
import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.item.ItemWizardHandbook; import electroblob.wizardry.item.ItemWizardHandbook;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench; import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.tileentity.ContainerPortableWorkbench; import electroblob.wizardry.tileentity.ContainerPortableWorkbench;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench; import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
@@ -48,9 +47,9 @@ public class WizardryGuiHandler implements IGuiHandler {
return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook(); return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook();
}else if(id == SPELL_BOOK){ }else if(id == SPELL_BOOK){
if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){ 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){ }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){ }else if(id == PORTABLE_CRAFTING){
return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z)); return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z));
@@ -1,5 +1,6 @@
package electroblob.wizardry.block; package electroblob.wizardry.block;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryBlocks; import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.ParticleBuilder.Type;
@@ -56,7 +57,7 @@ public class BlockCrystalFlower extends BlockBush {
@SubscribeEvent @SubscribeEvent
public static void onBonemealEvent(BonemealEvent event){ public static void onBonemealEvent(BonemealEvent event){
// Grows crystal flowers when bonemeal is used on grass // 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), 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), event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4),
@@ -11,7 +11,6 @@ import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess; import net.minecraft.world.IBlockAccess;
@@ -34,26 +33,16 @@ public class BlockSpectral extends Block implements ITileEntityProvider {
// Replaces getRenderBlockPass // Replaces getRenderBlockPass
@Override @Override
@SideOnly(Side.CLIENT)
public BlockRenderLayer getRenderLayer(){ public BlockRenderLayer getRenderLayer(){
return BlockRenderLayer.TRANSLUCENT; return BlockRenderLayer.TRANSLUCENT;
} }
@Override // See BlockTransportationStone for what all these do
public EnumBlockRenderType getRenderType(IBlockState state){ @Override public boolean isFullCube(IBlockState state){ return false; }
return EnumBlockRenderType.MODEL; @Override public boolean isBlockNormalCube(IBlockState state){ return false; }
} @Override public boolean isNormalCube(IBlockState state){ return false; }
@Override public boolean isOpaqueCube(IBlockState state){ return false; }
// Apparently it's OK to override this, despite it being deprecated. More importantly, it being deprecated is not
// Forge's doing, rather it is Mojang themselves misusing the @Deprecated annotation to mean 'internal, don't call'.
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
return false;
}
@Override @Override
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){ public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
@@ -67,12 +56,12 @@ public class BlockSpectral extends Block implements ITileEntityProvider {
} }
} }
// Overriden to make the block always look full brightness despite not emitting // // Overriden to make the block always look full brightness despite not emitting
// full light. // // full light.
@Override // @Override
public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos){ // public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos){
return 15; // return 15;
} // }
@Override @Override
public boolean hasTileEntity(IBlockState state){ public boolean hasTileEntity(IBlockState state){
@@ -62,18 +62,12 @@ public class BlockTransportationStone extends Block {
return false; return false;
} }
// Forge version of the above method. I still need to override both though because vanilla uses the other one.
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
return false;
}
// ... and this one is for rendering. // ... and this one is for rendering.
@Override @Override
public boolean isOpaqueCube(IBlockState state){ public boolean isOpaqueCube(IBlockState state){
return false; return false;
} }
@Override @Override
public boolean isSideSolid(IBlockState base_state, IBlockAccess world, BlockPos pos, EnumFacing side){ public boolean isSideSolid(IBlockState base_state, IBlockAccess world, BlockPos pos, EnumFacing side){
return side == EnumFacing.DOWN; return side == EnumFacing.DOWN;
@@ -147,7 +141,8 @@ public class BlockTransportationStone extends Block {
if(locations.isEmpty()) locations.add(here); if(locations.isEmpty()) locations.add(here);
else{ else{
locations.remove(here); // Prevents duplicates locations.remove(here); // Prevents duplicates
locations.set(locations.size() - 1, 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); if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.confirm", Spells.transportation.getNameForTranslationFormatted()), true);
} }
@@ -190,6 +190,11 @@ public class ClientProxy extends CommonProxy {
} }
} }
@Override
public void playBlinkEffect(EntityPlayer player){
if(Minecraft.getMinecraft().player == player) WizardryClientEventHandler.playBlinkEffect();
}
@Override @Override
public Set<String> getSpellHUDSkins(){ public Set<String> getSpellHUDSkins(){
return GuiSpellDisplay.getSkinKeys(); return GuiSpellDisplay.getSkinKeys();
@@ -425,14 +430,15 @@ public class ClientProxy extends CommonProxy {
// Again, no need to check if the spell succeeded, because the packet is only ever sent when it // Again, no need to check if the spell succeeded, because the packet is only ever sent when it
// succeeds. // succeeds.
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.NPC, spell, (EntityLiving)caster, message.modifiers)); MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.NPC, spell, (EntityLiving)caster, message.modifiers));
}
if(caster instanceof ISpellCaster){ if(caster instanceof ISpellCaster){
if(spell.isContinuous || spell instanceof None){ if(spell.isContinuous || spell instanceof None){
((ISpellCaster)caster).setContinuousSpell(spell); ((ISpellCaster)caster).setContinuousSpell(spell);
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target); ((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
}
} }
} }
}else if(caster != null){ }else if(caster != null){
Wizardry.logger.warn("Recieved a PacketNPCCastSpell, but the caster ID was not the ID of an EntityLiving"); Wizardry.logger.warn("Recieved a PacketNPCCastSpell, but the caster ID was not the ID of an EntityLiving");
} }
@@ -474,6 +480,9 @@ public class ClientProxy extends CommonProxy {
World world = Minecraft.getMinecraft().world; World world = Minecraft.getMinecraft().world;
Entity caster = world.getEntityByID(message.casterID); Entity caster = world.getEntityByID(message.casterID);
if(caster == null) return; // Shouldn't happen
// Moved from when the packet is sent to when it is received; fixes the sound not playing in first person. // Moved from when the packet is sent to when it is received; fixes the sound not playing in first person.
caster.playSound(WizardrySounds.SPELL_TRANSPORTATION_TRAVEL, 1, 1); caster.playSound(WizardrySounds.SPELL_TRANSPORTATION_TRAVEL, 1, 1);
@@ -23,11 +23,8 @@ import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase; 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.entity.item.EntityArmorStand;
import net.minecraft.inventory.Slot; import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@@ -35,18 +32,17 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityDispenser; import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.village.MerchantRecipe; import net.minecraft.village.MerchantRecipe;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.client.event.*; import net.minecraftforge.client.event.*;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import org.lwjgl.opengl.GL11; 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. * Event handler responsible for client-side only events, mostly rendering.
@@ -71,12 +67,6 @@ public final class WizardryClientEventHandler {
private static int blinkEffectTimer; private static int blinkEffectTimer;
/** The number of ticks the blink effect lasts for. */ /** The number of ticks the blink effect lasts for. */
private static final int BLINK_EFFECT_DURATION = 8; 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. */ /** Starts the first person blink overlay effect. */
public static void playBlinkEffect(){ public static void playBlinkEffect(){
@@ -151,7 +141,10 @@ public final class WizardryClientEventHandler {
if(world == null) return; 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(tileentity instanceof TileEntityDispenser){
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){ if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
DispenserCastingData.get((TileEntityDispenser)tileentity).update(); DispenserCastingData.get((TileEntityDispenser)tileentity).update();
@@ -3,11 +3,13 @@ package electroblob.wizardry.client.gui;
import electroblob.wizardry.Wizardry; import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.client.DrawingUtils;
import electroblob.wizardry.constants.Element; import electroblob.wizardry.constants.Element;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.data.SpellGlyphData; import electroblob.wizardry.data.SpellGlyphData;
import electroblob.wizardry.data.WizardData; import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.item.IManaStoringItem; import electroblob.wizardry.item.IManaStoringItem;
import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.item.IWorkbenchItem; import electroblob.wizardry.item.IWorkbenchItem;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketControlInput; import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
@@ -29,6 +31,8 @@ import net.minecraft.inventory.Slot;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation; 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.client.event.TextureStitchEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@@ -47,21 +51,25 @@ public class GuiArcaneWorkbench extends GuiContainer {
private IInventory arcaneWorkbenchInventory; private IInventory arcaneWorkbenchInventory;
private static final int TOOLTIP_WIDTH = 164; private static final int TOOLTIP_WIDTH = 164;
private static final int TOOLTIP_TEXT_INSET = 6;
/** We report the actual size of the GUI to Minecraft when a wand is in so JEI doesn't overdraw it. /** We report the actual size of the GUI to Minecraft when a wand is in so JEI doesn't overdraw it.
* For calculations, we use the size without the tooltip, which is stored in this constant. */ * For calculations, we use the size without the tooltip, which is stored in this constant. */
private static final int MAIN_GUI_WIDTH = 176; private static final int MAIN_GUI_WIDTH = 176;
private static final int RUNE_LEFT = 38; private static final int RUNE_LEFT = 38;
private static final int RUNE_TOP = 22; private static final int RUNE_TOP = 22;
private static final int RUNE_WIDTH = 100; private static final int RUNE_WIDTH = 100;
private static final int RUNE_HEIGHT = 100; private static final int RUNE_HEIGHT = 100;
private static final int PROGRESSION_BAR_WIDTH = 152;
private static final int PROGRESSION_BAR_HEIGHT = 3;
private static final int HALO_DIAMETER = 156; private static final int HALO_DIAMETER = 156;
private static final int TEXTURE_WIDTH = 512; private static final int TEXTURE_WIDTH = 512;
private static final int TEXTURE_HEIGHT = 256; private static final int TEXTURE_HEIGHT = 256;
private int animationTimer = 0; private int animationTimer = 0;
private static final int ANIMATION_DURATION = 20; private static final int ANIMATION_DURATION = 20;
@@ -113,28 +121,28 @@ public class GuiArcaneWorkbench extends GuiContainer {
GlStateManager.color(1, 1, 1, 1); GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().renderEngine.bindTexture(texture); Minecraft.getMinecraft().renderEngine.bindTexture(texture);
// Animation // Animation
// Grey background // Grey background
DrawingUtils.drawTexturedRect(guiLeft + RUNE_LEFT, guiTop + RUNE_TOP, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, 0, DrawingUtils.drawTexturedRect(guiLeft + RUNE_LEFT, guiTop + RUNE_TOP, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, 0,
RUNE_WIDTH, RUNE_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT); RUNE_WIDTH, RUNE_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
// Yellow 'halo' // Yellow 'halo'
if(animationTimer > 0){ if(animationTimer > 0){
GlStateManager.pushMatrix(); GlStateManager.pushMatrix();
GlStateManager.enableBlend(); GlStateManager.enableBlend();
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
int x = guiLeft + RUNE_LEFT + RUNE_WIDTH/2; int x = guiLeft + RUNE_LEFT + RUNE_WIDTH/2;
int y = guiTop + RUNE_TOP + RUNE_HEIGHT/2; int y = guiTop + RUNE_TOP + RUNE_HEIGHT/2;
float scale = (animationTimer + partialTicks)/ANIMATION_DURATION; float scale = (animationTimer + partialTicks)/ANIMATION_DURATION;
scale = (float)(1 - Math.pow(1-scale, 1.4f)); // Makes it slower at the start and speed up scale = (float)(1 - Math.pow(1-scale, 1.4f)); // Makes it slower at the start and speed up
GlStateManager.scale(scale, scale, 1); GlStateManager.scale(scale, scale, 1);
GlStateManager.translate(x/scale, y/scale, 0); GlStateManager.translate(x/scale, y/scale, 0);
DrawingUtils.drawTexturedRect(-HALO_DIAMETER /2, -HALO_DIAMETER /2, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, RUNE_HEIGHT, DrawingUtils.drawTexturedRect(-HALO_DIAMETER /2, -HALO_DIAMETER /2, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, RUNE_HEIGHT,
HALO_DIAMETER, HALO_DIAMETER, TEXTURE_WIDTH, TEXTURE_HEIGHT); HALO_DIAMETER, HALO_DIAMETER, TEXTURE_WIDTH, TEXTURE_HEIGHT);
@@ -232,6 +240,26 @@ public class GuiArcaneWorkbench extends GuiContainer {
y += 14; y += 14;
} }
// Progression bar
if(stack.getItem() instanceof ItemWand && !Wizardry.settings.legacyWandLevelling){
y += 10;
Tier tier = ((ItemWand)stack.getItem()).tier;
float progressFraction = 1;
if(tier != Tier.MASTER){
progressFraction = (float)WandHelper.getProgression(stack) / Tier.values()[tier.level + 1].progression;
}
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, MAIN_GUI_WIDTH, ySize + PROGRESSION_BAR_HEIGHT, PROGRESSION_BAR_WIDTH, PROGRESSION_BAR_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
int width = (int)(PROGRESSION_BAR_WIDTH * progressFraction);
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, MAIN_GUI_WIDTH, ySize, width, PROGRESSION_BAR_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
y += 8;
}
if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).showSpellsInWorkbench(this.mc.player, stack)){ if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).showSpellsInWorkbench(this.mc.player, stack)){
Spell[] spells = ((ISpellCastingItem)stack.getItem()).getSpells(stack); Spell[] spells = ((ISpellCastingItem)stack.getItem()).getSpells(stack);
@@ -251,7 +279,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
.bindTexture(discovered ? spell.getElement().getIcon() : Element.MAGIC.getIcon()); .bindTexture(discovered ? spell.getElement().getIcon() : Element.MAGIC.getIcon());
// Renders the little element icon // Renders the little element icon
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + 5, y, 8, 8); DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET - 1, y, 8, 8);
y += 10; y += 10;
} }
@@ -270,8 +298,8 @@ public class GuiArcaneWorkbench extends GuiContainer {
if(level > 0){ if(level > 0){
ItemStack stack1 = new ItemStack(item, level); ItemStack stack1 = new ItemStack(item, level);
GlStateManager.enableDepth(); GlStateManager.enableDepth();
this.itemRender.renderItemAndEffectIntoGUI(stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y); this.itemRender.renderItemAndEffectIntoGUI(stack1, guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + x, y);
this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y, this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack1, guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + x, y,
null); null);
x += 18; x += 18;
GlStateManager.disableDepth(); GlStateManager.disableDepth();
@@ -311,7 +339,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
int y = 6; int y = 6;
this.fontRenderer.drawStringWithShadow("\u00A7f" + stack.getDisplayName(), MAIN_GUI_WIDTH + 6, y, 0); this.fontRenderer.drawStringWithShadow("\u00A7f" + stack.getDisplayName(), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
if(stack.getItem() instanceof IManaStoringItem && ((IManaStoringItem)stack.getItem()).showManaInWorkbench(this.mc.player, stack)){ if(stack.getItem() instanceof IManaStoringItem && ((IManaStoringItem)stack.getItem()).showManaInWorkbench(this.mc.player, stack)){
y += 14; y += 14;
@@ -319,7 +347,27 @@ public class GuiArcaneWorkbench extends GuiContainer {
"\u00A77" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.mana") "\u00A77" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.mana")
+ " " + ((IManaStoringItem)stack.getItem()).getMana(stack) + "/" + " " + ((IManaStoringItem)stack.getItem()).getMana(stack) + "/"
+ ((IManaStoringItem)stack.getItem()).getManaCapacity(stack), + ((IManaStoringItem)stack.getItem()).getManaCapacity(stack),
MAIN_GUI_WIDTH + 6, y, 0); MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
}
// Progression tier text
if(stack.getItem() instanceof ItemWand && !Wizardry.settings.legacyWandLevelling){
y += 14;
Tier tier = ((ItemWand)stack.getItem()).tier;
this.fontRenderer.drawStringWithShadow(tier.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
if(tier != Tier.MASTER){
Tier nextTier = Tier.values()[tier.level + 1];
String s = TextFormatting.DARK_GRAY.toString() + nextTier.getDisplayName();
if(WandHelper.getProgression(stack) >= nextTier.progression) s = nextTier.getDisplayNameWithFormatting();
this.fontRenderer.drawStringWithShadow(s, MAIN_GUI_WIDTH + TOOLTIP_WIDTH
- TOOLTIP_TEXT_INSET - fontRenderer.getStringWidth(s), y, 0);
}
y += 4;
} }
y += 14; y += 14;
@@ -337,10 +385,10 @@ public class GuiArcaneWorkbench extends GuiContainer {
} }
if(discovered){ if(discovered){
this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + 16, y, 0); this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + 10, y, 0);
}else{ }else{
this.mc.standardGalacticFontRenderer.drawStringWithShadow( this.mc.standardGalacticFontRenderer.drawStringWithShadow(
"\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), MAIN_GUI_WIDTH + 16, y, 0); "\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + 10, y, 0);
} }
y += 10; y += 10;
} }
@@ -351,7 +399,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
y += 6; y += 6;
this.fontRenderer.drawStringWithShadow("\u00A7f" + I18n.format("container." this.fontRenderer.drawStringWithShadow("\u00A7f" + I18n.format("container."
+ Wizardry.MODID + ":arcane_workbench.upgrades"), MAIN_GUI_WIDTH + 6, y, 0); + Wizardry.MODID + ":arcane_workbench.upgrades"), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
int x = 0; int x = 0;
y += 10; y += 10;
@@ -364,7 +412,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
if(level > 0){ if(level > 0){
// The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is // The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is
// relative to the GUI but the POINT isn't. // relative to the GUI but the POINT isn't.
if(isPointInRegion(MAIN_GUI_WIDTH + 6 + x, y, 16, 16, mouseX, mouseY)){ if(isPointInRegion(MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + x, y, 16, 16, mouseX, mouseY)){
ItemStack stack1 = new ItemStack(item, level); ItemStack stack1 = new ItemStack(item, level);
this.renderToolTip(stack1, mouseX - guiLeft, mouseY - guiTop); this.renderToolTip(stack1, mouseX - guiLeft, mouseY - guiTop);
} }
@@ -1,11 +1,11 @@
package electroblob.wizardry.client.gui; package electroblob.wizardry.client.gui;
import com.google.common.collect.ImmutableMap;
import electroblob.wizardry.Wizardry; import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.client.DrawingUtils;
import electroblob.wizardry.constants.Tier; import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.data.SpellGlyphData; import electroblob.wizardry.data.SpellGlyphData;
import electroblob.wizardry.data.WizardData; import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell; 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.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ResourceLocation; import net.minecraft.item.ItemStack;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
import java.util.Map;
public class GuiSpellBook extends GuiScreen { public class GuiSpellBook extends GuiScreen {
private int xSize, ySize; private int xSize, ySize;
private ItemSpellBook book;
private Spell spell; private Spell spell;
private static final Map<Tier, ResourceLocation> textures = ImmutableMap.of( public GuiSpellBook(ItemStack stack){
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){
super(); super();
xSize = 288; xSize = 288;
ySize = 180; 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()); Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128); 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); DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
super.drawScreen(par1, par2, par3); super.drawScreen(par1, par2, par3);
@@ -77,7 +72,7 @@ public class GuiSpellBook extends GuiScreen {
//this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0); //this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0);
if(spell.getTier() == Tier.NOVICE){ 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); this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0);
}else{ }else{
this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0); this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0);
@@ -4,6 +4,7 @@ import com.google.common.collect.Streams;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.DrawingUtils; import electroblob.wizardry.client.DrawingUtils;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.FontRenderer;
@@ -17,6 +18,7 @@ import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.JsonUtils; import net.minecraft.util.JsonUtils;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import javax.annotation.Nullable;
import java.util.*; import java.util.*;
class CraftingRecipe { class CraftingRecipe {
@@ -60,8 +62,8 @@ class CraftingRecipe {
for(ResourceLocation location : locations){ for(ResourceLocation location : locations){
IRecipe recipe = CraftingManager.getRecipe(location); IRecipe recipe = CraftingManager.getRecipe(location);
if(recipe == null) throw new JsonSyntaxException("No such recipe: " + location); if(recipe == null) Wizardry.logger.warn("The recipe {} used in the wizard's handbook does not exist, it will display a blank grid instead", location);
recipes.add(recipe); else recipes.add(recipe);
} }
} }
@@ -80,7 +82,7 @@ class CraftingRecipe {
for(int[] instance : instances){ for(int[] instance : instances){
if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){ if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){
renderCraftingRecipe(font, itemRenderer, left + instance[1], top + instance[2], recipes.get(index % recipes.size())); renderCraftingRecipe(font, itemRenderer, left + instance[1], top + instance[2], recipes.isEmpty() ? null : recipes.get(index % recipes.size()));
} }
} }
} }
@@ -96,6 +98,8 @@ class CraftingRecipe {
*/ */
void drawTooltips(GuiWizardHandbook gui, FontRenderer font, RenderItem itemRenderer, int doublePage, int left, int top, int mouseX, int mouseY){ void drawTooltips(GuiWizardHandbook gui, FontRenderer font, RenderItem itemRenderer, int doublePage, int left, int top, int mouseX, int mouseY){
if(recipes.isEmpty()) return;
int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000; int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000;
for(int[] instance : instances){ for(int[] instance : instances){
@@ -135,50 +139,53 @@ class CraftingRecipe {
} }
} }
private static void renderCraftingRecipe(FontRenderer font, RenderItem itemRenderer, int x, int y, IRecipe recipe){ private static void renderCraftingRecipe(FontRenderer font, RenderItem itemRenderer, int x, int y, @Nullable IRecipe recipe){
ItemStack result = recipe.getRecipeOutput();
GlStateManager.color(1, 1, 1, 1); GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture); Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture);
DrawingUtils.drawTexturedRect(x, y, TEXTURE_INSET_X, TEXTURE_INSET_Y, WIDTH, HEIGHT, GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT); DrawingUtils.drawTexturedRect(x, y, TEXTURE_INSET_X, TEXTURE_INSET_Y, WIDTH, HEIGHT, GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT);
GlStateManager.pushMatrix(); if(recipe != null){
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.disableLighting();
GlStateManager.enableRescaleNormal();
GlStateManager.enableColorMaterial();
itemRenderer.zLevel = 100.0F;
int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000; GlStateManager.pushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.disableLighting();
GlStateManager.enableRescaleNormal();
GlStateManager.enableColorMaterial();
itemRenderer.zLevel = 100.0F;
int i = 0; int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE) / 2000;
for(Ingredient ingredient : recipe.getIngredients()){ int i = 0;
if(ingredient != Ingredient.EMPTY){ for(Ingredient ingredient : recipe.getIngredients()){
ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length];
if(!stack.isEmpty()){ if(ingredient != Ingredient.EMPTY){
itemRenderer.renderItemAndEffectIntoGUI(stack, x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3)); ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length];
itemRenderer.renderItemOverlays(font, stack, x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3)); if(!stack.isEmpty()){
itemRenderer.renderItemAndEffectIntoGUI(stack, x + BORDER + 18 * (i % 3), y + BORDER + 18 * (i / 3));
itemRenderer.renderItemOverlays(font, stack, x + BORDER + 18 * (i % 3), y + BORDER + 18 * (i / 3));
}
} }
i++;
} }
i++; ItemStack result = recipe.getRecipeOutput();
if(!result.isEmpty()){
itemRenderer.renderItemAndEffectIntoGUI(result, x + BORDER + 86, y + BORDER + 18);
itemRenderer.renderItemOverlays(font, result, x + BORDER + 86, y + BORDER + 18);
}
GlStateManager.popMatrix();
GlStateManager.enableDepth();
GlStateManager.disableColorMaterial();
itemRenderer.zLevel = 0.0F;
RenderHelper.disableStandardItemLighting();
} }
if(!result.isEmpty()){
itemRenderer.renderItemAndEffectIntoGUI(result, x + BORDER + 86, y + BORDER + 18);
itemRenderer.renderItemOverlays(font, result, x + BORDER + 86, y + BORDER + 18);
}
GlStateManager.popMatrix();
GlStateManager.enableDepth();
GlStateManager.disableColorMaterial();
itemRenderer.zLevel = 0.0F;
RenderHelper.disableStandardItemLighting();
} }
private static void renderCraftingTooltips(GuiWizardHandbook gui, RenderItem itemRenderer, int x, int y, int mouseX, int mouseY, IRecipe recipe){ private static void renderCraftingTooltips(GuiWizardHandbook gui, RenderItem itemRenderer, int x, int y, int mouseX, int mouseY, IRecipe recipe){
@@ -184,7 +184,7 @@ public class GuiWizardHandbook extends GuiScreen {
addFormatTag("advanced_max_charge", "" + Tier.ADVANCED.maxCharge); addFormatTag("advanced_max_charge", "" + Tier.ADVANCED.maxCharge);
addFormatTag("master_max_charge", "" + Tier.MASTER.maxCharge); addFormatTag("master_max_charge", "" + Tier.MASTER.maxCharge);
addFormatTag("version", Wizardry.VERSION); addFormatTag("version", Wizardry.VERSION);
addFormatTag("mcversion", Minecraft.getMinecraft().getVersion()); addFormatTag("mcversion", "1.12.2");
addFormatTag("colour_novice", "\u00A77"); addFormatTag("colour_novice", "\u00A77");
addFormatTag("colour_apprentice", Tier.APPRENTICE.getFormattingCode()); addFormatTag("colour_apprentice", Tier.APPRENTICE.getFormattingCode());
@@ -1,5 +1,6 @@
package electroblob.wizardry.client.model; package electroblob.wizardry.client.model;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.block.BlockStatue;
import net.minecraft.client.model.ModelRenderer; import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@@ -13,6 +14,7 @@ public class ModelWizardArmour extends ModelArmourFixer {
ModelRenderer hatSegment4; ModelRenderer hatSegment4;
ModelRenderer hatSegment5; ModelRenderer hatSegment5;
ModelRenderer hatSegment6; ModelRenderer hatSegment6;
ModelRenderer hatBobble;
ModelRenderer robe; ModelRenderer robe;
public ModelWizardArmour(float delta){ public ModelWizardArmour(float delta){
@@ -75,6 +77,13 @@ public class ModelWizardArmour extends ModelArmourFixer {
hatSegment6.mirror = true; hatSegment6.mirror = true;
setRotation(hatSegment6, -0.5585054F, 0F, 0F); 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 = new ModelRenderer(this, 16, 16);
bipedBody.addBox(-4F, 0F, -2F, 8, 11, 4, delta); bipedBody.addBox(-4F, 0F, -2F, 8, 11, 4, delta);
bipedBody.setRotationPoint(0F, 0F, 0F); bipedBody.setRotationPoint(0F, 0F, 0F);
@@ -97,6 +106,7 @@ public class ModelWizardArmour extends ModelArmourFixer {
bipedHead.addChild(hatSegment4); bipedHead.addChild(hatSegment4);
bipedHead.addChild(hatSegment5); bipedHead.addChild(hatSegment5);
bipedHead.addChild(hatSegment6); bipedHead.addChild(hatSegment6);
bipedHead.addChild(hatBobble);
} }
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){ 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.rotateAngleX = (this.bipedLeftLeg.rotateAngleX + this.bipedRightLeg.rotateAngleX) / 2f;
this.robe.rotateAngleY = this.bipedBody.rotateAngleY; this.robe.rotateAngleY = this.bipedBody.rotateAngleY;
this.robe.rotateAngleZ = (this.bipedLeftLeg.rotateAngleZ + this.bipedRightLeg.rotateAngleZ) / 2f; 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.WizardryBlocks;
import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryItems;
import net.minecraft.client.renderer.block.model.IBakedModel; 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.model.ModelResourceLocation;
import net.minecraft.client.renderer.block.statemap.StateMap; import net.minecraft.client.renderer.block.statemap.StateMap;
import net.minecraft.creativetab.CreativeTabs; import net.minecraft.creativetab.CreativeTabs;
@@ -66,10 +67,10 @@ public final class WizardryModels {
registerMultiTexturedModel((ItemCrystal)WizardryItems.magic_crystal); registerMultiTexturedModel((ItemCrystal)WizardryItems.magic_crystal);
registerItemModel(WizardryItems.magic_wand); registerWandModel(WizardryItems.magic_wand);
registerItemModel(WizardryItems.apprentice_wand); registerWandModel(WizardryItems.apprentice_wand);
registerItemModel(WizardryItems.advanced_wand); registerWandModel(WizardryItems.advanced_wand);
registerItemModel(WizardryItems.master_wand); registerWandModel(WizardryItems.master_wand);
registerItemModel(WizardryItems.spell_book); registerItemModel(WizardryItems.spell_book);
// Wildcard registered for wizard trades. // Wildcard registered for wizard trades.
@@ -77,37 +78,37 @@ public final class WizardryModels {
registerItemModel(WizardryItems.arcane_tome); registerItemModel(WizardryItems.arcane_tome);
registerItemModel(WizardryItems.wizard_handbook); registerItemModel(WizardryItems.wizard_handbook);
registerItemModel(WizardryItems.novice_fire_wand); registerWandModel(WizardryItems.novice_fire_wand);
registerItemModel(WizardryItems.novice_ice_wand); registerWandModel(WizardryItems.novice_ice_wand);
registerItemModel(WizardryItems.novice_lightning_wand); registerWandModel(WizardryItems.novice_lightning_wand);
registerItemModel(WizardryItems.novice_necromancy_wand); registerWandModel(WizardryItems.novice_necromancy_wand);
registerItemModel(WizardryItems.novice_earth_wand); registerWandModel(WizardryItems.novice_earth_wand);
registerItemModel(WizardryItems.novice_sorcery_wand); registerWandModel(WizardryItems.novice_sorcery_wand);
registerItemModel(WizardryItems.novice_healing_wand); registerWandModel(WizardryItems.novice_healing_wand);
registerItemModel(WizardryItems.apprentice_fire_wand); registerWandModel(WizardryItems.apprentice_fire_wand);
registerItemModel(WizardryItems.apprentice_ice_wand); registerWandModel(WizardryItems.apprentice_ice_wand);
registerItemModel(WizardryItems.apprentice_lightning_wand); registerWandModel(WizardryItems.apprentice_lightning_wand);
registerItemModel(WizardryItems.apprentice_necromancy_wand); registerWandModel(WizardryItems.apprentice_necromancy_wand);
registerItemModel(WizardryItems.apprentice_earth_wand); registerWandModel(WizardryItems.apprentice_earth_wand);
registerItemModel(WizardryItems.apprentice_sorcery_wand); registerWandModel(WizardryItems.apprentice_sorcery_wand);
registerItemModel(WizardryItems.apprentice_healing_wand); registerWandModel(WizardryItems.apprentice_healing_wand);
registerItemModel(WizardryItems.advanced_fire_wand); registerWandModel(WizardryItems.advanced_fire_wand);
registerItemModel(WizardryItems.advanced_ice_wand); registerWandModel(WizardryItems.advanced_ice_wand);
registerItemModel(WizardryItems.advanced_lightning_wand); registerWandModel(WizardryItems.advanced_lightning_wand);
registerItemModel(WizardryItems.advanced_necromancy_wand); registerWandModel(WizardryItems.advanced_necromancy_wand);
registerItemModel(WizardryItems.advanced_earth_wand); registerWandModel(WizardryItems.advanced_earth_wand);
registerItemModel(WizardryItems.advanced_sorcery_wand); registerWandModel(WizardryItems.advanced_sorcery_wand);
registerItemModel(WizardryItems.advanced_healing_wand); registerWandModel(WizardryItems.advanced_healing_wand);
registerItemModel(WizardryItems.master_fire_wand); registerWandModel(WizardryItems.master_fire_wand);
registerItemModel(WizardryItems.master_ice_wand); registerWandModel(WizardryItems.master_ice_wand);
registerItemModel(WizardryItems.master_lightning_wand); registerWandModel(WizardryItems.master_lightning_wand);
registerItemModel(WizardryItems.master_necromancy_wand); registerWandModel(WizardryItems.master_necromancy_wand);
registerItemModel(WizardryItems.master_earth_wand); registerWandModel(WizardryItems.master_earth_wand);
registerItemModel(WizardryItems.master_sorcery_wand); registerWandModel(WizardryItems.master_sorcery_wand);
registerItemModel(WizardryItems.master_healing_wand); registerWandModel(WizardryItems.master_healing_wand);
registerItemModel(WizardryItems.spectral_sword); registerItemModel(WizardryItems.spectral_sword);
registerItemModel(WizardryItems.spectral_pickaxe); registerItemModel(WizardryItems.spectral_pickaxe);
@@ -282,6 +283,9 @@ public final class WizardryModels {
if(location.getPath().contains("runestone") || location.getPath().contains("runestone_pedestal")){ if(location.getPath().contains("runestone") || location.getPath().contains("runestone_pedestal")){
IBakedModel original = event.getModelRegistry().getObject(location); IBakedModel original = event.getModelRegistry().getObject(location);
event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "overlay")); event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "overlay"));
}else if(location.getPath().contains("spectral_block")){
IBakedModel original = event.getModelRegistry().getObject(location);
event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "spectral_block"));
} }
} }
} }
@@ -291,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 * 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 * keep track of everything). Variant defaults to "normal". Registers the model for all metadata values.
* 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.
*/ */
private static void registerItemModel(Item item){ 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! // Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
ModelLoader.setCustomModelResourceLocation(item, 0, ModelBakery.registerItemVariants(item, new ModelResourceLocation(item.getRegistryName(), "inventory"));
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);
}
} }
/** /**
@@ -40,8 +40,6 @@ public class ParticlePath extends ParticleWizardry {
@Override @Override
public void onUpdate(){ public void onUpdate(){
super.onUpdate();
this.prevPosX = this.posX; this.prevPosX = this.posX;
this.prevPosY = this.posY; this.prevPosY = this.posY;
@@ -19,7 +19,7 @@ public class ParticleTornado extends ParticleDigging {
public ParticleTornado(World world, int maxAge, double originX, double originZ, double radius, double yPos, public ParticleTornado(World world, int maxAge, double originX, double originZ, double radius, double yPos,
double velX, double velZ, IBlockState block){ double velX, double velZ, IBlockState block){
super(world, 0, 0, 0, 0, 0, 0, block); super(world, 0, 0, 0, 0, 0, 0, block);
float angle = this.rand.nextFloat() * (float)Math.PI * 2; this.angle = this.rand.nextFloat() * (float)Math.PI * 2;
double x = originX - MathHelper.cos(angle) * radius; double x = originX - MathHelper.cos(angle) * radius;
double z = originZ + radius * MathHelper.sin(angle); double z = originZ + radius * MathHelper.sin(angle);
this.radius = radius; this.radius = radius;
@@ -112,7 +112,7 @@ public class LayerFrost implements LayerRenderer<EntityLivingBase> {
double scaleX = 1, scaleY = 1; 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 // 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. // (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; scaleX = (double)model.boxList.get(0).textureWidth / 16d;
scaleY = (double)model.boxList.get(0).textureHeight / 16d; scaleY = (double)model.boxList.get(0).textureHeight / 16d;
}else{ // Fallback to model fields; should never be needed }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.scale(scaleX, scaleY, 1);
GlStateManager.matrixMode(GL11.GL_MODELVIEW); 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 // 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){ 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).bipedBodyWear.isHidden = true;
((ModelPlayer)this.model).bipedLeftArmwear.isHidden = true; ((ModelPlayer)this.model).bipedLeftArmwear.isHidden = true;
((ModelPlayer)this.model).bipedRightArmwear.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.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks);
this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); 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 // Undoes the texture scaling
GlStateManager.matrixMode(GL11.GL_TEXTURE); GlStateManager.matrixMode(GL11.GL_TEXTURE);
@@ -20,6 +20,9 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import java.util.ArrayList;
import java.util.List;
@Mod.EventBusSubscriber(Side.CLIENT) @Mod.EventBusSubscriber(Side.CLIENT)
public class RenderArcaneLock { public class RenderArcaneLock {
@@ -39,6 +42,7 @@ public class RenderArcaneLock {
GlStateManager.pushMatrix(); GlStateManager.pushMatrix();
GlStateManager.enableBlend(); GlStateManager.enableBlend();
boolean lighting = GL11.glIsEnabled(GL11.GL_LIGHTING);
GlStateManager.disableLighting(); GlStateManager.disableLighting();
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240); OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
@@ -54,9 +58,16 @@ public class RenderArcaneLock {
BufferBuilder buffer = tessellator.getBuffer(); BufferBuilder buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
for(TileEntity tileentity : world.loadedTileEntityList){ // Someone managed to get a CME here so let's just copy the list to be safe
// It's only cosmetic so if a tileentity somehow gets removed while we're rendering them it's not a big deal
List<TileEntity> tileentities = new ArrayList<>(world.loadedTileEntityList);
if(tileentity.getDistanceSq(origin.x, origin.y, origin.z) <= 64*64 && tileentity.getTileData().hasUniqueId(ArcaneLock.NBT_KEY)){ 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)){
Vec3d[] vertices = WizardryUtilities.getVertices(world.getBlockState(tileentity.getPos()).getBoundingBox(world, tileentity.getPos()).grow(0.05).offset(tileentity.getPos())); Vec3d[] vertices = WizardryUtilities.getVertices(world.getBlockState(tileentity.getPos()).getBoundingBox(world, tileentity.getPos()).grow(0.05).offset(tileentity.getPos()));
@@ -74,7 +85,9 @@ public class RenderArcaneLock {
GlStateManager.disableBlend(); GlStateManager.disableBlend();
GlStateManager.enableTexture2D(); GlStateManager.enableTexture2D();
GlStateManager.enableLighting(); if (lighting) {
GlStateManager.enableLighting();
}
GlStateManager.disableRescaleNormal(); GlStateManager.disableRescaleNormal();
GlStateManager.popMatrix(); GlStateManager.popMatrix();
} }
@@ -53,9 +53,8 @@ public class RenderBlackHole extends Render<EntityBlackHole> {
(float)blackhole.ticksExisted / 10); (float)blackhole.ticksExisted / 10);
} }
if(blackhole.ticksExisted > blackhole.lifetime - 10){ if(blackhole.ticksExisted > blackhole.lifetime - 10){
GlStateManager.scale((float)(blackhole.lifetime - blackhole.ticksExisted) / 10, float scale = Math.max(0, (float)(blackhole.lifetime - blackhole.ticksExisted) / 10);
(float)(blackhole.lifetime - blackhole.ticksExisted) / 10, GlStateManager.scale(scale, scale, scale);
(float)(blackhole.lifetime - blackhole.ticksExisted) / 10);
} }
this.bindTexture(texture); this.bindTexture(texture);
@@ -12,9 +12,9 @@ import java.util.Random;
public enum Tier { public enum Tier {
NOVICE(700, 3, 12, 0, new Style().setColor(TextFormatting.WHITE), "novice"), NOVICE(700, 3, 12, 0, new Style().setColor(TextFormatting.WHITE), "novice"),
APPRENTICE(1000, 5, 5, 6000, new Style().setColor(TextFormatting.AQUA), "apprentice"), APPRENTICE(1000, 5, 5, 2000, new Style().setColor(TextFormatting.AQUA), "apprentice"),
ADVANCED(1500, 7, 2, 9000, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"), ADVANCED(1500, 7, 2, 3500, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
MASTER(2500, 9, 1, 15000, new Style().setColor(TextFormatting.DARK_PURPLE), "master"); MASTER(2500, 9, 1, 6000, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
/** Maximum mana a wand of this tier can store. */ /** Maximum mana a wand of this tier can store. */
public final int maxCharge; public final int maxCharge;
@@ -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 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. // 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(tileentity instanceof TileEntityDispenser){
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){ if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
DispenserCastingData.get((TileEntityDispenser)tileentity).update(); DispenserCastingData.get((TileEntityDispenser)tileentity).update();
@@ -6,6 +6,7 @@ import electroblob.wizardry.enchantment.Imbuement;
import electroblob.wizardry.entity.living.ISummonedCreature; import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.event.SpellCastEvent.Source; import electroblob.wizardry.event.SpellCastEvent.Source;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketCastContinuousSpell; import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketPlayerSync; import electroblob.wizardry.packet.PacketPlayerSync;
import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.packet.WizardryPacketHandler;
@@ -71,7 +72,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
private static final Set<IStoredVariable> storedVariables = new HashSet<>(); private static final Set<IStoredVariable> storedVariables = new HashSet<>();
/** The maximum number of recent spells to track. */ /** The maximum number of recent spells to track. */
public static final int MAX_RECENT_SPELLS = 10; public static final int MAX_RECENT_SPELLS = ItemWand.BASE_SPELL_SLOTS;
/** The player this WizardData instance belongs to. */ /** The player this WizardData instance belongs to. */
private final EntityPlayer player; private final EntityPlayer player;
@@ -140,7 +141,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
// All players can recognise magic missile. This is not done using discoverSpell because that seems to cause // All players can recognise magic missile. This is not done using discoverSpell because that seems to cause
// a crash on load occasionally (probably something to do with achievements being initialised) // a crash on load occasionally (probably something to do with achievements being initialised)
this.spellsDiscovered.add(Spells.magic_missile); this.spellsDiscovered.add(Spells.magic_missile);
this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS); // Only keeps a reference to the last 10 spells cast this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS); // Only keeps a reference to the last 5 spells cast
this.castCommandSpell = Spells.none; this.castCommandSpell = Spells.none;
this.castCommandModifiers = new SpellModifiers(); this.castCommandModifiers = new SpellModifiers();
this.castCommandTick = 0; this.castCommandTick = 0;
@@ -272,7 +273,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
* @param spell The spell to count casts for. * @param spell The spell to count casts for.
*/ */
public int countRecentCasts(Spell spell){ public int countRecentCasts(Spell spell){
return (int)this.recentSpells.stream().filter(s -> s == spell).count(); // We know this can't be more than 10 return (int)this.recentSpells.stream().filter(s -> s == spell).count(); // We know this can't be more than 5
} }
// Imbuements // Imbuements
@@ -1,5 +1,6 @@
package electroblob.wizardry.entity.construct; package electroblob.wizardry.entity.construct;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell; import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.WizardryUtilities; import electroblob.wizardry.util.WizardryUtilities;
@@ -33,7 +34,8 @@ public class EntityCombustionRune extends EntityMagicConstruct {
float strength = Spells.combustion_rune.getProperty(Spell.BLAST_RADIUS).floatValue(); float strength = Spells.combustion_rune.getProperty(Spell.BLAST_RADIUS).floatValue();
world.newExplosion(this.getCaster(), this.posX, this.posY, this.posZ, strength, true, true); world.newExplosion(this.getCaster(), this.posX, this.posY, this.posZ, strength, true,
getCaster() != null && WizardryUtilities.canDamageBlocks(getCaster(), world));
// The trap is destroyed once triggered. // The trap is destroyed once triggered.
this.setDead(); this.setDead();
@@ -29,9 +29,9 @@ public class EntityIceSpike extends EntityMagicConstruct {
this.setRotation(-facing.getHorizontalAngle(), WizardryUtilities.getPitch(facing)); this.setRotation(-facing.getHorizontalAngle(), WizardryUtilities.getPitch(facing));
float yaw = (-facing.getHorizontalAngle()) * (float)Math.PI/180; float yaw = (-facing.getHorizontalAngle()) * (float)Math.PI/180;
float pitch = (WizardryUtilities.getPitch(facing) - 90) * (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 min = this.getPositionVector().add(new Vec3d(-width/2, 0, -width/2).rotatePitch(pitch).rotateYaw(yaw));
Vec3d max = new Vec3d(width/2, height, 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(this.getPositionVector().add(min), this.getPositionVector().add(max))); this.setEntityBoundingBox(new AxisAlignedBB(min.x, min.y, min.z, max.x, max.y, max.z));
} }
public EnumFacing getFacing(){ public EnumFacing getFacing(){
@@ -15,6 +15,8 @@ import net.minecraft.world.World;
public class EntityDecoy extends EntitySummonedCreature { public class EntityDecoy extends EntitySummonedCreature {
// TODO: These guys need sounds!
/** Creates a new decoy in the given world. */ /** Creates a new decoy in the given world. */
public EntityDecoy(World world){ public EntityDecoy(World world){
super(world); super(world);
@@ -35,11 +35,17 @@ import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.EnumDifficulty; import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants.NBT; 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 net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.*; import java.util.*;
@Mod.EventBusSubscriber
public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData { public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData {
private EntityAIAttackSpell<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50); private EntityAIAttackSpell<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50);
@@ -283,16 +289,6 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
public int getMaxSpawnedInChunk(){ public int getMaxSpawnedInChunk(){
return 1; 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 @Override
protected boolean canDespawn(){ protected boolean canDespawn(){
@@ -393,4 +389,13 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
textureIndex = data.readInt(); 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(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
this.tasks.addTask(7, new EntityAILookIdle(this)); this.tasks.addTask(7, new EntityAILookIdle(this));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false)); 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())); 0, false, true, this.getTargetSelector()));
} }
@@ -16,7 +16,13 @@ import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World; 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 { public class EntityIceWraith extends EntityBlazeMinion {
/** The version from EntityLivingBase is only used in onLivingUpdate, so it can safely be copied. */ /** 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 @Override
public boolean getCanSpawnHere(){ public boolean getCanSpawnHere(){
// Only spawns in the specified dimensions return super.getCanSpawnHere() && this.isValidLightLevel();
for(int id : Wizardry.settings.mobSpawnDimensions){ }
if(this.dimension == id) 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,16 @@ import net.minecraft.init.MobEffects;
import net.minecraft.util.DamageSource; import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHand;
import net.minecraft.world.World; 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;
import java.util.Arrays;
import java.util.function.IntPredicate;
@Mod.EventBusSubscriber
public class EntityLightningWraith extends EntityBlazeMinion { public class EntityLightningWraith extends EntityBlazeMinion {
public EntityLightningWraith(World world){ public EntityLightningWraith(World world){
@@ -74,14 +83,17 @@ public class EntityLightningWraith extends EntityBlazeMinion {
@Override @Override
public boolean getCanSpawnHere(){ public boolean getCanSpawnHere(){
// Only spawns in the specified dimensions, during thunderstorms return super.getCanSpawnHere() && this.isValidLightLevel();
if(!world.isThundering()) return false; }
for(int id : Wizardry.settings.mobSpawnDimensions){ @SubscribeEvent
if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel(); 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;
} }
/** /**
@@ -50,7 +50,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste
this.tasks.addTask(3, new EntityAILookIdle(this)); this.tasks.addTask(3, new EntityAILookIdle(this));
// this.targetTasks.addTask(0, new EntityAIMoveTowardsTarget(this, 1, 10)); // this.targetTasks.addTask(0, new EntityAIMoveTowardsTarget(this, 1, 10));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); 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())); 0, false, true, this.getTargetSelector()));
this.setAIMoveSpeed((float)AISpeed); this.setAIMoveSpeed((float)AISpeed);
@@ -45,7 +45,7 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell
this.tasks.addTask(2, new EntityAIWander(this, AISpeed)); this.tasks.addTask(2, new EntityAIWander(this, AISpeed));
this.tasks.addTask(3, new EntityAILookIdle(this)); this.tasks.addTask(3, new EntityAILookIdle(this));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true)); 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())); 0, false, true, this.getTargetSelector()));
this.setAIMoveSpeed((float)AISpeed); this.setAIMoveSpeed((float)AISpeed);
@@ -218,7 +218,8 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
// Copied from EntityVillager // Copied from EntityVillager
if(!this.world.isRemote && this.livingSoundTime > -this.getTalkInterval() + 20){ if(!this.world.isRemote && this.livingSoundTime > -this.getTalkInterval() + 20){
this.livingSoundTime = -this.getTalkInterval(); 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 +257,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
@Override @Override
protected SoundEvent getAmbientSound(){ protected SoundEvent getAmbientSound(){
if(Wizardry.tisTheSeason) return WizardrySounds.ENTITY_WIZARD_HOHOHO;
return this.isTrading() ? WizardrySounds.ENTITY_WIZARD_TRADING : WizardrySounds.ENTITY_WIZARD_AMBIENT; return this.isTrading() ? WizardrySounds.ENTITY_WIZARD_TRADING : WizardrySounds.ENTITY_WIZARD_AMBIENT;
} }
@@ -414,7 +416,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
this.spells = (List<Spell>)NBTExtras.NBTToList(nbt.getTagList("spells", NBT.TAG_INT), this.spells = (List<Spell>)NBTExtras.NBTToList(nbt.getTagList("spells", NBT.TAG_INT),
(NBTTagInt tag) -> Spell.byMetadata(tag.getInt())); (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()){ if(!tagList.isEmpty()){
this.towerBlocks = new HashSet<>(NBTExtras.NBTToList(tagList, NBTUtil::getPosFromTag)); this.towerBlocks = new HashSet<>(NBTExtras.NBTToList(tagList, NBTUtil::getPosFromTag));
}else{ }else{
@@ -780,6 +782,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
Tier maxTier = Tier.NOVICE; Tier maxTier = Tier.NOVICE;
List<Spell> npcSpells = Spell.getSpells(Spell.npcSpells); List<Spell> npcSpells = Spell.getSpells(Spell.npcSpells);
npcSpells.removeIf(s -> !s.applicableForItem(WizardryItems.spell_book));
for(int i = 0; i < n; i++){ for(int i = 0; i < n; i++){
@@ -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. * possible for implementors to override this in order to do something special when selecting a target.
*/ */
default Predicate<Entity> getTargetSelector(){ 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));
} }
/** /**
@@ -1,5 +1,6 @@
package electroblob.wizardry.entity.projectile; package electroblob.wizardry.entity.projectile;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell; import electroblob.wizardry.spell.Spell;
@@ -44,15 +45,34 @@ public class EntityMagicMissile extends EntityMagicArrow {
public void tickInAir(){ public void tickInAir(){
if(this.world.isRemote){ 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(Wizardry.tisTheSeason){
if(this.ticksExisted > 1){ // Don't spawn particles behind where it started! ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(0.8f, 0.15f, 0.15f)
double x = posX - motionX/2; .time(20 + rand.nextInt(10)).spawn(world);
double y = posY - motionY/2;
double z = posZ - motionZ/2; ParticleBuilder.create(Type.SNOW).pos(posX, posY, posZ).spawn(world);
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(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);
}
} }
} }
} }
@@ -58,6 +58,8 @@ public interface IConjuredItem {
*/ */
default int getMaxDamageFromNBT(ItemStack stack, Spell spell){ 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(); float baseDuration = spell.getProperty(SpellConjuration.ITEM_LIFETIME).floatValue();
if(stack.hasTagCompound() && stack.getTagCompound().hasKey(DURATION_MULTIPLIER_KEY)){ if(stack.hasTagCompound() && stack.getTagCompound().hasKey(DURATION_MULTIPLIER_KEY)){
@@ -265,7 +265,7 @@ public class ItemArtefact extends Item {
if(artefact == WizardryItems.ring_condensing){ if(artefact == WizardryItems.ring_condensing){
if(world.isRemote && player.ticksExisted % 150 == 0){ if(player.ticksExisted % 150 == 0){
for(ItemStack stack : WizardryUtilities.getHotbar(player)){ for(ItemStack stack : WizardryUtilities.getHotbar(player)){
// Needs to be both of these interfaces because this ring only recharges wands // Needs to be both of these interfaces because this ring only recharges wands
// (or more accurately, chargeable spellcasting items) // (or more accurately, chargeable spellcasting items)
@@ -276,7 +276,7 @@ public class ItemArtefact extends Item {
}else if(artefact == WizardryItems.amulet_arcane_defence){ }else if(artefact == WizardryItems.amulet_arcane_defence){
if(world.isRemote && player.ticksExisted % 300 == 0){ if(player.ticksExisted % 300 == 0){
for(ItemStack stack : player.getArmorInventoryList()){ for(ItemStack stack : player.getArmorInventoryList()){
// IManaStoringItem is sufficient, since anything in the armour slots is probably armour // IManaStoringItem is sufficient, since anything in the armour slots is probably armour
if(stack.getItem() instanceof IManaStoringItem) if(stack.getItem() instanceof IManaStoringItem)
@@ -601,7 +601,7 @@ public class ItemArtefact extends Item {
}else if(artefact == WizardryItems.amulet_transience){ }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(WizardryPotions.transience, 300));
player.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, 300, 0, false, false)); 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() WizardryUtilities.getEntitiesWithinRadius(3, player.posX, player.posY, player.posZ, world).stream()
.filter(WizardryUtilities::isLiving) .filter(WizardryUtilities::isLiving)
.filter(e -> e != player)
.min(Comparator.comparingDouble(player::getDistanceSq)) .min(Comparator.comparingDouble(player::getDistanceSq))
.ifPresent(target -> { .ifPresent(target -> {
@@ -1,5 +1,6 @@
package electroblob.wizardry.item; package electroblob.wizardry.item;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.data.WizardData; import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.Spells;
@@ -11,11 +12,13 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Slot; import net.minecraft.inventory.Slot;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
public class ItemBlankScroll extends Item implements IWorkbenchItem { public class ItemBlankScroll extends Item implements IWorkbenchItem {
public ItemBlankScroll(){ public ItemBlankScroll(){
this.setCreativeTab(WizardryTabs.WIZARDRY); this.setCreativeTab(WizardryTabs.WIZARDRY);
this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0);
} }
@Override @Override
@@ -3,6 +3,7 @@ package electroblob.wizardry.item;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.MagicDamage; import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType; import electroblob.wizardry.util.MagicDamage.DamageType;
import electroblob.wizardry.util.WizardryUtilities; import electroblob.wizardry.util.WizardryUtilities;
@@ -81,6 +82,12 @@ public class ItemFrostAxe extends ItemAxe implements IConjuredItem {
stack.setItemDamage(damage + 1); 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 @Override
public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase wielder){ public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase wielder){
if(!MagicDamage.isEntityImmune(DamageType.FROST, target)) if(!MagicDamage.isEntityImmune(DamageType.FROST, target))
@@ -81,7 +81,9 @@ public class ItemLightningHammer extends Item implements IConjuredItem {
Multimap<String, AttributeModifier> multimap = super.getItemAttributeModifiers(slot); Multimap<String, AttributeModifier> multimap = super.getItemAttributeModifiers(slot);
if(slot == EntityEquipmentSlot.MAINHAND){ if(slot == EntityEquipmentSlot.MAINHAND){
multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", Spells.lightning_hammer.getProperty(Spell.DIRECT_DAMAGE).floatValue(), WizardryUtilities.Operations.ADD)); float attackDamage = Spells.lightning_hammer.arePropertiesInitialised() ?
Spells.lightning_hammer.getProperty(Spell.DIRECT_DAMAGE).floatValue() : 10; // Fallback for search tree init, value doesn't really matter
multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", attackDamage, WizardryUtilities.Operations.ADD));
multimap.put(SharedMonsterAttributes.ATTACK_SPEED.getName(), new AttributeModifier(ATTACK_SPEED_MODIFIER, "Weapon modifier", ATTACK_SPEED, WizardryUtilities.Operations.ADD)); multimap.put(SharedMonsterAttributes.ATTACK_SPEED.getName(), new AttributeModifier(ATTACK_SPEED_MODIFIER, "Weapon modifier", ATTACK_SPEED, WizardryUtilities.Operations.ADD));
multimap.put(SharedMonsterAttributes.MOVEMENT_SPEED.getName(), new AttributeModifier(MOVEMENT_SPEED_MODIFIER, "Weapon modifier", MOVEMENT_SPEED_REDUCTION, WizardryUtilities.Operations.MULTIPLY_FLAT)); multimap.put(SharedMonsterAttributes.MOVEMENT_SPEED.getName(), new AttributeModifier(MOVEMENT_SPEED_MODIFIER, "Weapon modifier", MOVEMENT_SPEED_REDUCTION, WizardryUtilities.Operations.MULTIPLY_FLAT));
} }
@@ -1,6 +1,7 @@
package electroblob.wizardry.item; package electroblob.wizardry.item;
import electroblob.wizardry.Wizardry; import electroblob.wizardry.Wizardry;
import electroblob.wizardry.data.SpellGlyphData;
import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.event.SpellCastEvent.Source; import electroblob.wizardry.event.SpellCastEvent.Source;
import electroblob.wizardry.packet.PacketCastSpell; import electroblob.wizardry.packet.PacketCastSpell;
@@ -13,15 +14,15 @@ import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult; import net.minecraft.util.*;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary;
import java.util.List;
public class ItemScroll extends Item implements ISpellCastingItem { public class ItemScroll extends Item implements ISpellCastingItem {
@@ -33,6 +34,7 @@ public class ItemScroll extends Item implements ISpellCastingItem {
setHasSubtypes(true); setHasSubtypes(true);
setMaxStackSize(16); setMaxStackSize(16);
setCreativeTab(WizardryTabs.SPELLS); setCreativeTab(WizardryTabs.SPELLS);
this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0);
} }
@Override @Override
@@ -47,13 +49,14 @@ public class ItemScroll extends Item implements ISpellCastingItem {
@Override @Override
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){ public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
if(tab == WizardryTabs.SPELLS){ 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. List<Spell> spells = Spell.getSpells(Spell.allSpells);
for(int i = 0; i < Spell.getTotalSpellCount(); i++){ spells.removeIf(s -> !s.applicableForItem(this));
// 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. for(Spell spell : spells){
list.add(new ItemStack(this, 1, i + 1)); list.add(new ItemStack(this, 1, spell.metadata()));
} }
} }
} }
@@ -80,6 +83,25 @@ public class ItemScroll extends Item implements ISpellCastingItem {
return Wizardry.proxy.getScrollDisplayName(stack); return Wizardry.proxy.getScrollDisplayName(stack);
} }
@Override
@SideOnly(Side.CLIENT)
public void addInformation(ItemStack itemstack, World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag advanced){
if(world != null){
Spell spell = Spell.byMetadata(itemstack.getItemDamage());
boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(spell, itemstack);
// Advanced tooltips display more information, mainly for searching purposes in creative
if(discovered && advanced.isAdvanced()){ // No cheating!
tooltip.add(spell.getTier().getDisplayName());
tooltip.add(spell.getElement().getDisplayName());
tooltip.add(spell.getType().getDisplayName());
}
}
}
@Override @Override
public int getMaxItemUseDuration(ItemStack stack){ public int getMaxItemUseDuration(ItemStack stack){
@@ -71,9 +71,10 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem {
if(!oldStack.isEmpty() || !newStack.isEmpty()){ if(!oldStack.isEmpty() || !newStack.isEmpty()){
// We only care about the situation where we specifically want the animation NOT to play. // We only care about the situation where we specifically want the animation NOT to play.
if(oldStack.getItem() == newStack.getItem() && !slotChanged if(oldStack.getItem() == newStack.getItem() && !slotChanged)
// This code should only run on the client side, so using Minecraft is ok. // This code should only run on the client side, so using Minecraft is ok.
&& !net.minecraft.client.Minecraft.getMinecraft().player.isHandActive()) // Why the heck was this here?
//&& !net.minecraft.client.Minecraft.getMinecraft().player.isHandActive())
return false; return false;
} }
@@ -1,7 +1,9 @@
package electroblob.wizardry.item; package electroblob.wizardry.item;
import com.google.common.collect.ImmutableMap;
import electroblob.wizardry.Wizardry; import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler; import electroblob.wizardry.WizardryGuiHandler;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.data.SpellGlyphData; import electroblob.wizardry.data.SpellGlyphData;
import electroblob.wizardry.registry.WizardryTabs; import electroblob.wizardry.registry.WizardryTabs;
import electroblob.wizardry.spell.Spell; import electroblob.wizardry.spell.Spell;
@@ -9,35 +11,41 @@ import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult; import net.minecraft.util.*;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary; import net.minecraftforge.oredict.OreDictionary;
import java.util.List; import java.util.List;
import java.util.Map;
public class ItemSpellBook extends Item { 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(){ public ItemSpellBook(){
super(); super();
setHasSubtypes(true); setHasSubtypes(true);
setMaxStackSize(16); setMaxStackSize(16);
setCreativeTab(WizardryTabs.SPELLS); setCreativeTab(WizardryTabs.SPELLS);
this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0);
} }
@Override @Override
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){ public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
if(tab == WizardryTabs.SPELLS){ 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. List<Spell> spells = Spell.getSpells(Spell.allSpells);
for(int i = 0; i < Spell.getTotalSpellCount(); i++){ spells.removeIf(s -> !s.applicableForItem(this));
// 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. for(Spell spell : spells){
list.add(new ItemStack(this, 1, i + 1)); list.add(new ItemStack(this, 1, spell.metadata()));
} }
} }
} }
@@ -64,10 +72,13 @@ public class ItemSpellBook extends Item {
: "#\u00A79" + SpellGlyphData.getGlyphName(spell, world)); : "#\u00A79" + SpellGlyphData.getGlyphName(spell, world));
tooltip.add(spell.getTier().getDisplayNameWithFormatting()); tooltip.add(spell.getTier().getDisplayNameWithFormatting());
// Advanced tooltips display more information, mainly for searching purposes in creative
if(discovered && advanced.isAdvanced()){ // No cheating!
tooltip.add(spell.getElement().getDisplayName());
tooltip.add(spell.getType().getDisplayName());
}
} }
/* Removed to streamline the tooltip a bit. Information is now within the book. if(spell.isContinuous){
* tooltip.add("\u00A79Mana Cost: " + spell.cost + " per second"); }else{ tooltip.add("\u00A79Mana Cost: " +
* spell.cost); } */
} }
@Override @Override
@@ -76,4 +87,12 @@ public class ItemSpellBook extends Item {
return Wizardry.proxy.getFontRenderer(stack); 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());
}
} }
@@ -27,10 +27,7 @@ import net.minecraft.inventory.Slot;
import net.minecraft.item.EnumAction; import net.minecraft.item.EnumAction;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult; import net.minecraft.util.*;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@@ -73,6 +70,8 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
private static final int CONTINUOUS_TRACKING_INTERVAL = 20; private static final int CONTINUOUS_TRACKING_INTERVAL = 20;
/** The increase in progression for casting spells of the matching element. */ /** The increase in progression for casting spells of the matching element. */
private static final float ELEMENTAL_PROGRESSION_MODIFIER = 1.2f; private static final float ELEMENTAL_PROGRESSION_MODIFIER = 1.2f;
/** The increase in progression for casting an undiscovered spell (can only happen once per spell for each player). */
private static final float DISCOVERY_PROGRESSION_MODIFIER = 5f;
/** The fraction of progression lost when all recently-cast spells are the same as the one being cast. */ /** The fraction of progression lost when all recently-cast spells are the same as the one being cast. */
private static final float MAX_PROGRESSION_REDUCTION = 0.75f; private static final float MAX_PROGRESSION_REDUCTION = 0.75f;
@@ -573,6 +572,11 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
progressionModifier *= ELEMENTAL_PROGRESSION_MODIFIER; progressionModifier *= ELEMENTAL_PROGRESSION_MODIFIER;
} }
if(WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){
// Casting an undiscovered spell now grants 5x progression
progressionModifier *= DISCOVERY_PROGRESSION_MODIFIER;
}
modifiers.set(SpellModifiers.PROGRESSION, progressionModifier, false); modifiers.set(SpellModifiers.PROGRESSION, progressionModifier, false);
return modifiers; return modifiers;
@@ -635,6 +639,8 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
// WandHelper.setProgression(centre.getStack(), WandHelper.getProgression(centre.getStack()) - tier.progression); // WandHelper.setProgression(centre.getStack(), WandHelper.getProgression(centre.getStack()) - tier.progression);
// } // }
WandHelper.setProgression(centre.getStack(), 0);
ItemStack newWand = new ItemStack(WizardryItems.getWand(tier, this.element)); ItemStack newWand = new ItemStack(WizardryItems.getWand(tier, this.element));
newWand.setTagCompound(centre.getStack().getTagCompound()); newWand.setTagCompound(centre.getStack().getTagCompound());
// This needs to be done after copying the tag compound so the mana capacity for the new wand // This needs to be done after copying the tag compound so the mana capacity for the new wand
@@ -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)} /** 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 @Override
public void setDamage(ItemStack stack, int damage){ public void setDamage(ItemStack stack, int damage){
// Overridden to stop repair things from 'repairing' the mana in wizard armour // 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 // 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 @Override
@@ -178,9 +178,14 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
String s = "wizard_armour"; 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(slot == EntityEquipmentSlot.LEGS) s = s + "_legs";
if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) s = "legendary_" + s;
return "ebwizardry:textures/armour/" + s + ".png"; return "ebwizardry:textures/armour/" + s + ".png";
} }
@@ -108,10 +108,14 @@ public class RandomSpell extends LootFunction {
// element = null; // 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 // 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? // 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 ItemScroll) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.SCROLL));
if(stack.getItem() instanceof ItemSpellBook) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK)); 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 com.google.gson.JsonSerializationContext;
import electroblob.wizardry.Wizardry; import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.living.ISpellCaster; import electroblob.wizardry.entity.living.ISpellCaster;
import electroblob.wizardry.item.ItemScroll;
import electroblob.wizardry.item.ItemSpellBook; import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell; import electroblob.wizardry.spell.Spell;
@@ -33,13 +34,18 @@ public class WizardSpell extends LootFunction {
@Override @Override
public ItemStack apply(ItemStack stack, Random random, LootContext context){ 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."); .warn("Applying the wizard_spell loot function to an item that isn't a spell book or scroll.");
if(context.getLootedEntity() instanceof ISpellCaster){ if(context.getLootedEntity() instanceof ISpellCaster){
List<Spell> spells = ((ISpellCaster)context.getLootedEntity()).getSpells(); List<Spell> spells = ((ISpellCaster)context.getLootedEntity()).getSpells();
spells.remove(Spells.magic_missile); // Can't drop magic missile 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{ }else{
Wizardry.logger.warn("Applying the wizard_spell loot function to an entity that isn't a spell caster."); Wizardry.logger.warn("Applying the wizard_spell loot function to an entity that isn't a spell caster.");
} }
@@ -162,7 +162,7 @@ public abstract class Forfeit {
event.setCanceled(true); 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(forfeit == null){ // Should never happen, but just in case...
if(!event.getWorld().isRemote) player.sendMessage(new TextComponentTranslation("forfeit.ebwizardry:do_nothing")); if(!event.getWorld().isRemote) player.sendMessage(new TextComponentTranslation("forfeit.ebwizardry:do_nothing"));
@@ -375,7 +375,7 @@ public abstract class Forfeit {
if(!w.isRemote){ if(!w.isRemote){
for(EnumFacing direction : EnumFacing.HORIZONTALS){ for(EnumFacing direction : EnumFacing.HORIZONTALS){
BlockPos pos = p.getPosition().offset(direction); BlockPos pos = p.getPosition().offset(direction);
w.setBlockState(pos, WizardryBlocks.snare.getDefaultState()); if(WizardryUtilities.canBlockBeReplaced(w, pos)) w.setBlockState(pos, WizardryBlocks.snare.getDefaultState());
} }
} }
})); }));
@@ -410,6 +410,7 @@ public abstract class Forfeit {
if(!w.isRemote){ if(!w.isRemote){
List<BlockPos> sphere = WizardryUtilities.getBlockSphere(p.getPosition(), 4); List<BlockPos> sphere = WizardryUtilities.getBlockSphere(p.getPosition(), 4);
sphere.removeIf(pos -> !w.getBlockState(pos).isFullCube()); sphere.removeIf(pos -> !w.getBlockState(pos).isFullCube());
sphere.removeIf(pos -> WizardryUtilities.isBlockUnbreakable(w, pos));
sphere.forEach(pos -> { sphere.forEach(pos -> {
EntityFallingBlock block = new EntityFallingBlock(w, pos.getX() + 0.5, pos.getY() + 0.5, EntityFallingBlock block = new EntityFallingBlock(w, pos.getX() + 0.5, pos.getY() + 0.5,
pos.getZ() + 0.5, w.getBlockState(pos)); pos.getZ() + 0.5, w.getBlockState(pos));
@@ -0,0 +1,103 @@
package electroblob.wizardry.misc;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.item.IManaStoringItem;
import electroblob.wizardry.item.ItemManaFlask;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapelessOreRecipe;
/**
* Implements a dynamic crafting recipe for recharging items with mana flasks.
*
* @author Corail31, Electroblob
* @since Wizardry 4.2.2
*/
@Mod.EventBusSubscriber
public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
private final IManaStoringItem chargeable;
private final ItemManaFlask flask;
/**
* Creates a new charging recipe for the given chargeable item using the given flask item.
* @param chargeable The type of item to be charged
* @param flask The mana flask used to charge the item
*/
public RecipeRechargeWithFlask(Item chargeable, ItemManaFlask flask){
super(null, new ItemStack(chargeable, 1, OreDictionary.WILDCARD_VALUE),
new ItemStack(chargeable, 1, OreDictionary.WILDCARD_VALUE), flask);
if(!(chargeable instanceof IManaStoringItem)) throw new IllegalArgumentException("Item to be charged must be an instance of IManaStoringItem");
this.chargeable = (IManaStoringItem)chargeable;
this.flask = flask;
}
// 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);
rechargeItemAndCopyNBT(result, inv);
return result;
}
@Override
public boolean matches(InventoryCrafting inv, World world){
ItemStack stack = findItemToCharge(inv);
if(!stack.isEmpty() && chargeable.isManaFull(stack)) return false;
return super.matches(inv, world);
}
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);
}
}
private ItemStack findItemToCharge(InventoryCrafting inv){
for(int i=0; i<inv.getSizeInventory(); i++){
ItemStack ingredient = inv.getStackInSlot(i);
if(ingredient.getItem() == chargeable) return ingredient;
}
return ItemStack.EMPTY;
}
@Override
public boolean isDynamic(){
return true; // Stops it appearing in the recipe book
}
@SubscribeEvent
public static void onItemCraftedEvent(PlayerEvent.ItemCraftedEvent event){
// getCraftingResult seems to only work for the result that's displayed, not once it is actually taken
// This means that although I no longer have to replace the result every tick, I still need to do it here
// ... I thought the whole point of the new recipe system was so that I DIDN'T have to do this?!
if(event.craftMatrix instanceof InventoryCrafting){
for(IRecipe recipe : CraftingManager.REGISTRY){
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).rechargeItemAndCopyNBT(event.crafting, (InventoryCrafting)event.craftMatrix);
}
}
}
}
}
@@ -52,7 +52,7 @@ public interface ISyncedPotion {
@SubscribeEvent @SubscribeEvent
public static void onPotionExpiryEvent(PotionEvent.PotionExpiryEvent event){ public static void onPotionExpiryEvent(PotionEvent.PotionExpiryEvent event){
if(event.getPotionEffect().getPotion() instanceof ISyncedPotion if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() instanceof ISyncedPotion
&& ((ISyncedPotion)event.getPotionEffect().getPotion()).shouldSync(event.getEntityLiving())){ && ((ISyncedPotion)event.getPotionEffect().getPotion()).shouldSync(event.getEntityLiving())){
if(!event.getEntityLiving().world.isRemote){ if(!event.getEntityLiving().world.isRemote){
@@ -67,7 +67,7 @@ public interface ISyncedPotion {
@SubscribeEvent @SubscribeEvent
public static void onPotionRemoveEvent(PotionEvent.PotionRemoveEvent event){ public static void onPotionRemoveEvent(PotionEvent.PotionRemoveEvent event){
if(event.getPotionEffect().getPotion() instanceof ISyncedPotion if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() instanceof ISyncedPotion
&& ((ISyncedPotion)event.getPotionEffect().getPotion()).shouldSync(event.getEntityLiving())){ && ((ISyncedPotion)event.getPotionEffect().getPotion()).shouldSync(event.getEntityLiving())){
if(!event.getEntityLiving().world.isRemote){ if(!event.getEntityLiving().world.isRemote){
@@ -243,7 +243,12 @@ public final class Spells {
IForgeRegistry<Spell> registry = event.getRegistry(); IForgeRegistry<Spell> registry = event.getRegistry();
registry.register(new None()); 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 Ignite());
registry.register(new Freeze()); registry.register(new Freeze());
registry.register(new Snowball()); registry.register(new Snowball());
@@ -77,7 +77,7 @@ public final class WizardryBlocks {
public static void register(RegistryEvent.Register<Block> event){ public static void register(RegistryEvent.Register<Block> event){
IForgeRegistry<Block> registry = event.getRegistry(); IForgeRegistry<Block> registry = event.getRegistry();
registerBlock(registry, "arcane_workbench", new BlockArcaneWorkbench().setHardness(1.0F).setCreativeTab(WizardryTabs.WIZARDRY)); registerBlock(registry, "arcane_workbench", new BlockArcaneWorkbench().setHardness(1.0F).setCreativeTab(WizardryTabs.WIZARDRY));
registerBlock(registry, "crystal_ore", new BlockCrystalOre(Material.ROCK).setHardness(3.0F).setCreativeTab(WizardryTabs.WIZARDRY)); registerBlock(registry, "crystal_ore", new BlockCrystalOre(Material.ROCK).setHardness(3.0F).setCreativeTab(WizardryTabs.WIZARDRY));
registerBlock(registry, "petrified_stone", new BlockStatue(Material.ROCK).setHardness(1.5F).setResistance(10.0F)); registerBlock(registry, "petrified_stone", new BlockStatue(Material.ROCK).setHardness(1.5F).setResistance(10.0F));
@@ -86,7 +86,7 @@ public final class WizardryBlocks {
registerBlock(registry, "crystal_flower", new BlockCrystalFlower(Material.PLANTS).setHardness(0.0F).setCreativeTab(WizardryTabs.WIZARDRY)); registerBlock(registry, "crystal_flower", new BlockCrystalFlower(Material.PLANTS).setHardness(0.0F).setCreativeTab(WizardryTabs.WIZARDRY));
registerBlock(registry, "snare", new BlockSnare(Material.PLANTS).setHardness(0.0F)); registerBlock(registry, "snare", new BlockSnare(Material.PLANTS).setHardness(0.0F));
registerBlock(registry, "transportation_stone", new BlockTransportationStone(Material.ROCK).setHardness(0.3F).setLightLevel(0.5f).setLightOpacity(0).setCreativeTab(WizardryTabs.WIZARDRY)); registerBlock(registry, "transportation_stone", new BlockTransportationStone(Material.ROCK).setHardness(0.3F).setLightLevel(0.5f).setLightOpacity(0).setCreativeTab(WizardryTabs.WIZARDRY));
registerBlock(registry, "spectral_block", new BlockSpectral(Material.GLASS).setLightLevel(0.7f).setLightOpacity(0).setBlockUnbreakable().setResistance(6000000.0F)); registerBlock(registry, "spectral_block", new BlockSpectral(Material.GLASS).setLightOpacity(1).setBlockUnbreakable().setResistance(6000000.0F));
registerBlock(registry, "crystal_block", new BlockCrystal(Material.IRON).setHardness(5.0F).setResistance(10.0F).setCreativeTab(WizardryTabs.WIZARDRY)); registerBlock(registry, "crystal_block", new BlockCrystal(Material.IRON).setHardness(5.0F).setResistance(10.0F).setCreativeTab(WizardryTabs.WIZARDRY));
registerBlock(registry, "meteor", new Block(Material.ROCK).setLightLevel(1)); registerBlock(registry, "meteor", new Block(Material.ROCK).setLightLevel(1));
registerBlock(registry, "vanishing_cobweb", new BlockVanishingCobweb(Material.WEB).setLightOpacity(1).setHardness(4.0F)); registerBlock(registry, "vanishing_cobweb", new BlockVanishingCobweb(Material.WEB).setLightOpacity(1).setHardness(4.0F));
@@ -9,6 +9,7 @@ import net.minecraft.enchantment.Enchantment;
import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.GameRegistry.ObjectHolder;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -18,6 +19,7 @@ import javax.annotation.Nonnull;
* @author Electroblob * @author Electroblob
* @since Wizardry 2.1 * @since Wizardry 2.1
*/ */
@ObjectHolder(Wizardry.MODID)
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public final class WizardryEnchantments { public final class WizardryEnchantments {
@@ -57,16 +57,16 @@ public final class WizardryItems {
public static final class Materials { public static final class Materials {
public static final ToolMaterial MAGICAL = EnumHelper.addToolMaterial("MAGICAL", 3, 1000, 8.0f, 4.0f, 0); public static final ToolMaterial MAGICAL = EnumHelper.addToolMaterial("MAGICAL", 3, 1000, 8.0f, 4.0f, 0);
public static final ArmorMaterial SILK = EnumHelper.addArmorMaterial("SILK", "wizardry/textures/armour/wizard_armour", public static final ArmorMaterial SILK = EnumHelper.addArmorMaterial("SILK", "wizardry/textures/armour/wizard_armour",
15, new int[]{0, 0, 0, 0}, 15, WizardrySounds.ITEM_ARMOUR_EQUIP_SILK, 0.0F); 15, new int[]{0, 0, 0, 0}, 15, WizardrySounds.ITEM_ARMOUR_EQUIP_SILK, 0.0F);
} }
@Nonnull @Nonnull
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
private static <T> T placeholder(){ return null; } private static <T> T placeholder(){ return null; }
// This is the most concise way I can think of to register the items. Really, I'd prefer it if there was only one // This is the most concise way I can think of to register the items. Really, I'd prefer it if there was only one
// point where all the items were listed, but that's not possible within the current system unless you use an array, // point where all the items were listed, but that's not possible within the current system unless you use an array,
// which means you lose the individual fields... // which means you lose the individual fields...
@@ -478,7 +478,7 @@ public final class WizardryItems {
registerItem(registry, "poison_bomb", new ItemPoisonBomb()); registerItem(registry, "poison_bomb", new ItemPoisonBomb());
registerItem(registry, "smoke_bomb", new ItemSmokeBomb()); registerItem(registry, "smoke_bomb", new ItemSmokeBomb());
registerItem(registry, "spark_bomb", new ItemSparkBomb()); registerItem(registry, "spark_bomb", new ItemSparkBomb());
registerItem(registry, "wizard_hat", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, null), true); registerItem(registry, "wizard_hat", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.HEAD, null), true);
registerItem(registry, "wizard_robe", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, null)); registerItem(registry, "wizard_robe", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.CHEST, null));
registerItem(registry, "wizard_leggings", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, null)); registerItem(registry, "wizard_leggings", new ItemWizardArmour(Materials.SILK, 1, EntityEquipmentSlot.LEGS, null));
@@ -596,7 +596,7 @@ public final class WizardryItems {
/** Called from init() in the main mod class to register wizardry's dispenser behaviours. */ /** Called from init() in the main mod class to register wizardry's dispenser behaviours. */
public static void registerDispenseBehaviours(){ public static void registerDispenseBehaviours(){
BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(firebomb, new BehaviorProjectileDispense(){ BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(firebomb, new BehaviorProjectileDispense(){
@Override @Override
@@ -605,9 +605,9 @@ public final class WizardryItems {
entity.setPosition(position.getX(), position.getY(), position.getZ()); entity.setPosition(position.getX(), position.getY(), position.getZ());
return entity; return entity;
} }
}); });
BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(poison_bomb, new BehaviorProjectileDispense(){ BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(poison_bomb, new BehaviorProjectileDispense(){
@Override @Override
@@ -616,9 +616,9 @@ public final class WizardryItems {
entity.setPosition(position.getX(), position.getY(), position.getZ()); entity.setPosition(position.getX(), position.getY(), position.getZ());
return entity; return entity;
} }
}); });
BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(smoke_bomb, new BehaviorProjectileDispense(){ BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(smoke_bomb, new BehaviorProjectileDispense(){
@Override @Override
@@ -627,7 +627,7 @@ public final class WizardryItems {
entity.setPosition(position.getX(), position.getY(), position.getZ()); entity.setPosition(position.getX(), position.getY(), position.getZ());
return entity; return entity;
} }
}); });
BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(spark_bomb, new BehaviorProjectileDispense(){ BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(spark_bomb, new BehaviorProjectileDispense(){
@@ -640,9 +640,9 @@ public final class WizardryItems {
} }
}); });
BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(scroll, new BehaviourSpellDispense()); BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(scroll, new BehaviourSpellDispense());
} }
public static void populateWandMap(){ public static void populateWandMap(){
@@ -3,9 +3,7 @@ package electroblob.wizardry.registry;
import electroblob.wizardry.Wizardry; import electroblob.wizardry.Wizardry;
import electroblob.wizardry.item.IManaStoringItem; import electroblob.wizardry.item.IManaStoringItem;
import electroblob.wizardry.item.ItemManaFlask; import electroblob.wizardry.item.ItemManaFlask;
import net.minecraft.inventory.ContainerPlayer; import electroblob.wizardry.misc.RecipeRechargeWithFlask;
import net.minecraft.inventory.ContainerWorkbench;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.item.crafting.FurnaceRecipes;
@@ -14,9 +12,6 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapelessOreRecipe;
import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.registries.IForgeRegistry;
import java.util.LinkedList; import java.util.LinkedList;
@@ -54,84 +49,22 @@ public final class WizardryRecipes {
// Mana flask recipes // Mana flask recipes
ItemStack smallFlaskStack = new ItemStack(WizardryItems.small_mana_flask); Item chargeable;
ItemStack mediumFlaskStack = new ItemStack(WizardryItems.medium_mana_flask);
ItemStack largeFlaskStack = new ItemStack(WizardryItems.large_mana_flask);
ItemStack chargeable;
while(!chargingRecipeQueue.isEmpty()){ while(!chargingRecipeQueue.isEmpty()){
// Use remove() and not poll() because the queue shouldn't be empty in here // Use remove() and not poll() because the queue shouldn't be empty in here
chargeable = new ItemStack(chargingRecipeQueue.remove(), 1, OreDictionary.WILDCARD_VALUE); chargeable = chargingRecipeQueue.remove();
registry.register(new ShapelessOreRecipe(null, chargeable, chargeable, smallFlaskStack){ registry.register(new RecipeRechargeWithFlask(chargeable, (ItemManaFlask)WizardryItems.small_mana_flask)
@Override public boolean isDynamic(){ return true; } // Stops it appearing in the recipe book .setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/small_flask_" + chargeable.getRegistryName().getPath())));
}.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/small_flask_" + chargeable.getItem().getRegistryName().getPath())));
registry.register(new ShapelessOreRecipe(null, chargeable, chargeable, mediumFlaskStack){ registry.register(new RecipeRechargeWithFlask(chargeable, (ItemManaFlask)WizardryItems.medium_mana_flask)
@Override public boolean isDynamic(){ return true; } .setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/medium_flask_" + chargeable.getRegistryName().getPath())));
}.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/medium_flask_" + chargeable.getItem().getRegistryName().getPath())));
registry.register(new ShapelessOreRecipe(null, chargeable, chargeable, largeFlaskStack){ registry.register(new RecipeRechargeWithFlask(chargeable, (ItemManaFlask)WizardryItems.large_mana_flask)
@Override public boolean isDynamic(){ return true; } .setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/large_flask_" + chargeable.getRegistryName().getPath())));
}.setRegistryName(new ResourceLocation(Wizardry.MODID, "recipes/large_flask_" + chargeable.getItem().getRegistryName().getPath())));
} }
} }
@SubscribeEvent
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){
if(event.phase == TickEvent.Phase.START){
if(event.player.openContainer instanceof ContainerWorkbench){
IInventory craftMatrix = ((ContainerWorkbench)event.player.openContainer).craftMatrix;
ItemStack output = ((ContainerWorkbench)event.player.openContainer).craftResult.getStackInSlot(0);
processManaFlaskCrafting(craftMatrix, output);
}else if(event.player.openContainer instanceof ContainerPlayer){
IInventory craftMatrix = ((ContainerPlayer)event.player.openContainer).craftMatrix;
ItemStack output = ((ContainerPlayer)event.player.openContainer).craftResult.getStackInSlot(0);
// Unfortunately I have no choice but to call this method every tick when the player isn't using another
// inventory, since the only thing tracking whether the player is looking at their inventory is the GUI
// itself, which is client-side only.
processManaFlaskCrafting(craftMatrix, output);
}
}
}
private static void processManaFlaskCrafting(IInventory craftMatrix, ItemStack output){
// Charges wand using mana flask
ItemManaFlask flask = null;
ItemStack input = ItemStack.EMPTY;
for(int i = 0; i < craftMatrix.getSizeInventory(); i++){
ItemStack stack = craftMatrix.getStackInSlot(i);
if(stack.getItem() instanceof ItemManaFlask){
flask = (ItemManaFlask)stack.getItem();
}
if(stack.getItem() instanceof IManaStoringItem){
input = stack;
}
}
if(flask == null) return;
if(output.getItem() instanceof IManaStoringItem && !input.isEmpty()){
output.setTagCompound((input.getTagCompound()));
int currentMana = ((IManaStoringItem)input.getItem()).getMana(input);
((IManaStoringItem)output.getItem()).setMana(output, Math.min(currentMana + flask.size.capacity,
((IManaStoringItem)input.getItem()).getManaCapacity(input)));
}
}
} }
@@ -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_TRADING = createSound("entity.wizard.trading");
public static final SoundEvent ENTITY_WIZARD_HURT = createSound("entity.wizard.hurt"); 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_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_DARKNESS_ORB_HIT = createSound("entity.darkness_orb.hit");
public static final SoundEvent ENTITY_DART_HIT = createSound("entity.dart.hit"); public static final SoundEvent ENTITY_DART_HIT = createSound("entity.dart.hit");
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell; package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions; import electroblob.wizardry.registry.WizardryPotions;
@@ -18,12 +19,21 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.fml.common.Mod; 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.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.lang.reflect.Field;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class ArcaneJammer extends SpellRay { public class ArcaneJammer extends SpellRay {
private static final Field spellTicks;
static { // Yay more reflection
spellTicks = ObfuscationReflectionHelper.findField(EntitySpellcasterIllager.class, "field_193087_b");
}
public ArcaneJammer(){ public ArcaneJammer(){
super("arcane_jammer", false, EnumAction.NONE); super("arcane_jammer", false, EnumAction.NONE);
this.soundValues(0.7f, 1, 0.4f); this.soundValues(0.7f, 1, 0.4f);
@@ -68,9 +78,17 @@ public class ArcaneJammer extends SpellRay {
@SubscribeEvent @SubscribeEvent
public static void onLivingUpdateEvent(LivingEvent.LivingUpdateEvent event){ public static void onLivingUpdateEvent(LivingEvent.LivingUpdateEvent event){
if(event.getEntity() instanceof EntitySpellcasterIllager if(event.getEntity() instanceof EntitySpellcasterIllager
&& event.getEntityLiving().isPotionActive(WizardryPotions.arcane_jammer)){ && event.getEntityLiving().isPotionActive(WizardryPotions.arcane_jammer)){
((EntitySpellcasterIllager)event.getEntity()).setSpellType(EntitySpellcasterIllager.SpellType.NONE); ((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);
}
} }
} }
@@ -18,11 +18,14 @@ public class ArrowRain extends SpellConstructRanged<EntityArrowRain> {
// Moves the entity back towards the caster a bit, so the area of effect is better centred on the position. // Moves the entity back towards the caster a bit, so the area of effect is better centred on the position.
// 3 is the distance to move the entity back towards the caster. // 3 is the distance to move the entity back towards the caster.
double dx = caster.posX - x; double dx = caster == null ? side.getDirectionVec().getX() : caster.posX - x;
double dz = caster.posZ - z; double dz = caster == null ? side.getDirectionVec().getZ() : caster.posZ - z;
double distRatio = 3 / Math.sqrt(dx * dx + dz * dz); double dist = Math.sqrt(dx * dx + dz * dz);
x += dx * distRatio; if(dist != 0){
z += dz * distRatio; double distRatio = 3 / dist;
x += dx * distRatio;
z += dz * distRatio;
}
// Moves the entity up 5 blocks so that it is above mobs' heads. // Moves the entity up 5 blocks so that it is above mobs' heads.
y += 5; y += 5;
@@ -32,7 +35,11 @@ public class ArrowRain extends SpellConstructRanged<EntityArrowRain> {
@Override @Override
protected void addConstructExtras(EntityArrowRain construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ protected void addConstructExtras(EntityArrowRain construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
// Makes the arrows shoot in the direction the caster was looking when they cast the spell. // Makes the arrows shoot in the direction the caster was looking when they cast the spell.
construct.rotationYaw = caster.rotationYawHead; if(caster != null){
construct.rotationYaw = caster.rotationYawHead;
}else{
construct.rotationYaw = side.getHorizontalAngle();
}
} }
} }
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell; package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.ParticleBuilder.Type;
@@ -7,6 +8,7 @@ import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.WizardryUtilities; import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction; import net.minecraft.item.EnumAction;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.EnumParticleTypes;
@@ -78,9 +80,7 @@ public class Banish extends SpellRay {
world.rand.nextDouble() - 0.5, 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! if(entity instanceof EntityPlayer) Wizardry.proxy.playBlinkEffect((EntityPlayer)entity);
if(entity == net.minecraft.client.Minecraft.getMinecraft().player)
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect();
} }
if(y != null){ if(y != null){
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell; package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.RayTracer; import electroblob.wizardry.util.RayTracer;
import electroblob.wizardry.util.SpellModifiers; 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.spawnParticle(EnumParticleTypes.PORTAL, dx, dy, dz, world.rand.nextDouble() - 0.5,
world.rand.nextDouble() - 0.5, 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! Wizardry.proxy.playBlinkEffect(caster);
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect();
} }
if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){
@@ -33,7 +33,7 @@ public class ConjureBlock extends SpellRay {
@Override @Override
protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){ protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
if(world.getBlockState(pos).getBlock() == WizardryBlocks.spectral_block){ if(caster.isSneaking() && world.getBlockState(pos).getBlock() == WizardryBlocks.spectral_block){
if(!world.isRemote){ if(!world.isRemote){
// Dispelling of blocks // Dispelling of blocks
@@ -23,8 +23,10 @@ public class Decay extends SpellConstructRanged<EntityDecay> {
@Override @Override
protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
if(world.getBlockState(new BlockPos(x, y, z)).isNormalCube()) return false; BlockPos origin = new BlockPos(x, y, z);
if(world.getBlockState(origin).isNormalCube()) return false;
super.spawnConstruct(world, x, y, z, side, caster, modifiers); super.spawnConstruct(world, x, y, z, side, caster, modifiers);
@@ -35,7 +37,7 @@ public class Decay extends SpellConstructRanged<EntityDecay> {
int verticalRange = (int)(6 * modifiers.get(WizardryItems.blast_upgrade)); int verticalRange = (int)(6 * modifiers.get(WizardryItems.blast_upgrade));
for(int i=0; i<quantity; i++){ for(int i=0; i<quantity; i++){
BlockPos pos = WizardryUtilities.findNearbyFloorSpace(caster, horizontalRange, verticalRange); BlockPos pos = WizardryUtilities.findNearbyFloorSpace(world, origin, horizontalRange, verticalRange);
if(pos == null) break; if(pos == null) break;
super.spawnConstruct(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, side, caster, modifiers); super.spawnConstruct(world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, side, caster, modifiers);
} }
@@ -60,7 +60,9 @@ public class Disintegration extends SpellRay {
double z = (world.rand.nextDouble() - 0.5) * target.width; double z = (world.rand.nextDouble() - 0.5) * target.width;
ember.setPosition(target.posX + x, target.posY + y, target.posZ + z); ember.setPosition(target.posX + x, target.posY + y, target.posZ + z);
float speed = 0.2f; float speed = 0.2f;
ember.setVelocity(x * speed, y * 0.5f * speed, z * speed); ember.motionX = x * speed;
ember.motionY = y * 0.5f * speed;
ember.motionZ = z * speed;
world.spawnEntity(ember); world.spawnEntity(ember);
} }
} }
@@ -40,20 +40,18 @@
if(world.isRemote){ if(world.isRemote){
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, caster.posX, world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y + 0.1, z, 0, 0, 0);
caster.getEntityBoundingBox().minY + 0.1, caster.posZ, 0, 0, 0);
double particleX, particleZ; double particleX, particleZ;
for(int i=0; i<40; i++){ for(int i=0; i<40; i++){
particleX = caster.posX - 1.0d + 2 * world.rand.nextDouble(); particleX = x - 1.0d + 2 * world.rand.nextDouble();
particleZ = caster.posZ - 1.0d + 2 * world.rand.nextDouble(); particleZ = z - 1.0d + 2 * world.rand.nextDouble();
IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster); IBlockState block = WizardryUtilities.getBlockEntityIsStandingOn(caster);
world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, caster.getEntityBoundingBox().minY, world.spawnParticle(EnumParticleTypes.BLOCK_DUST, particleX, y,
particleZ, particleX - caster.posX, 0, particleZ - caster.posZ, particleZ, particleX - x, 0, particleZ - z, Block.getStateId(block));
Block.getStateId(block));
} }
} }
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell; package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Constants; import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.event.SpellCastEvent; import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryItems;
@@ -66,6 +67,11 @@ public class EmpoweringPresence extends Spell {
return true; 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 @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){ public static void onSpellCastPreEvent(SpellCastEvent.Pre event){
// Empowerment stacks extra potency on top of the existing potency. // Empowerment stacks extra potency on top of the existing potency.
@@ -78,4 +84,5 @@ public class EmpoweringPresence extends Spell {
event.getModifiers().get(SpellModifiers.POTENCY) * potency, true); event.getModifiers().get(SpellModifiers.POTENCY) * potency, true);
} }
} }
} }
@@ -11,6 +11,7 @@ public class FrostAxe extends SpellConjuration {
public FrostAxe(){ public FrostAxe(){
super("frost_axe", WizardryItems.frost_axe); super("frost_axe", WizardryItems.frost_axe);
addProperties(DAMAGE);
} }
@Override @Override
@@ -6,6 +6,8 @@ import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.world.World; import net.minecraft.world.World;
import javax.annotation.Nullable;
public class Hailstorm extends SpellConstructRanged<EntityHailstorm> { public class Hailstorm extends SpellConstructRanged<EntityHailstorm> {
public Hailstorm(){ public Hailstorm(){
@@ -14,15 +16,18 @@ public class Hailstorm extends SpellConstructRanged<EntityHailstorm> {
} }
@Override @Override
protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
// Moves the entity back towards the caster a bit, so the area of effect is better centred on the position. // Moves the entity back towards the caster a bit, so the area of effect is better centred on the position.
// 3 is the distance to move the entity back towards the caster. // 3 is the distance to move the entity back towards the caster.
double dx = caster.posX - x; double dx = caster == null ? side.getDirectionVec().getX() : caster.posX - x;
double dz = caster.posZ - z; double dz = caster == null ? side.getDirectionVec().getZ() : caster.posZ - z;
double distRatio = 3 / Math.sqrt(dx * dx + dz * dz); double dist = Math.sqrt(dx * dx + dz * dz);
x += dx * distRatio; if(dist != 0){
z += dz * distRatio; double distRatio = 3 / dist;
x += dx * distRatio;
z += dz * distRatio;
}
// Moves the entity up 5 blocks so that it is above mobs' heads. // Moves the entity up 5 blocks so that it is above mobs' heads.
y += 5; y += 5;
@@ -32,7 +37,11 @@ public class Hailstorm extends SpellConstructRanged<EntityHailstorm> {
@Override @Override
protected void addConstructExtras(EntityHailstorm construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ protected void addConstructExtras(EntityHailstorm construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
// Makes the arrows shoot in the direction the caster was looking when they cast the spell. // Makes the arrows shoot in the direction the caster was looking when they cast the spell.
if(caster != null) construct.rotationYaw = caster.rotationYawHead; if(caster != null){
construct.rotationYaw = caster.rotationYawHead;
}else{
construct.rotationYaw = side.getHorizontalAngle();
}
} }
} }
@@ -23,8 +23,10 @@ public class IceSpikes extends SpellConstructRanged<EntityIceSpike> {
@Override @Override
protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ protected boolean spawnConstruct(World world, double x, double y, double z, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
if(side == null) return false;
BlockPos blockHit = new BlockPos(x, y, z); BlockPos blockHit = new BlockPos(x, y, z);
if(side != null && side.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE) blockHit = blockHit.offset(side); if(side.getAxisDirection() == EnumFacing.AxisDirection.NEGATIVE) blockHit = blockHit.offset(side);
if(world.getBlockState(blockHit).isNormalCube()) return false; if(world.getBlockState(blockHit).isNormalCube()) return false;
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell; package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryItems; import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.AllyDesignationSystem; import electroblob.wizardry.util.AllyDesignationSystem;
import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder;
@@ -62,4 +63,9 @@ public class InvigoratingPresence extends Spell {
return true; return true;
} }
@Override
protected String getTranslationKey(){
return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey();
}
} }
@@ -43,8 +43,7 @@ public class PhaseStep extends Spell {
world.rand.nextDouble() - 0.5, 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! Wizardry.proxy.playBlinkEffect(caster);
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect();
} }
if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){ if(rayTrace != null && rayTrace.typeOfHit == RayTraceResult.Type.BLOCK){
@@ -247,7 +247,7 @@ public class Possession extends SpellRay {
} }
} }
if(possessor.world.isRemote){ if(possessor.world.isRemote && possessor == net.minecraft.client.Minecraft.getMinecraft().player){
// Shaders and effects // Shaders and effects
if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER); if(Wizardry.settings.useShaders) net.minecraft.client.Minecraft.getMinecraft().entityRenderer.loadShader(SHADER);
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); // Looks quite nice... electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); // Looks quite nice...
@@ -342,7 +342,7 @@ public class Possession extends SpellRay {
player.capabilities.isFlying = false; player.capabilities.isFlying = false;
} }
if(player.world.isRemote){ if(player.world.isRemote && player == net.minecraft.client.Minecraft.getMinecraft().player){
net.minecraft.client.Minecraft.getMinecraft().entityRenderer.stopUseShader(); net.minecraft.client.Minecraft.getMinecraft().entityRenderer.stopUseShader();
electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); // Looks quite nice... electroblob.wizardry.client.WizardryClientEventHandler.playBlinkEffect(); // Looks quite nice...
} }
@@ -624,7 +624,7 @@ public class Possession extends SpellRay {
EntityLiving possessee = getPossessee((EntityPlayer)event.getTarget()); EntityLiving possessee = getPossessee((EntityPlayer)event.getTarget());
EntityLiving attacker = (EntityLiving)event.getEntityLiving(); EntityLiving attacker = (EntityLiving)event.getEntityLiving();
if(possessee != null && !attacker.canAttackClass(possessee.getClass())){ if(possessee != null && !attacker.canAttackClass(possessee.getClass())){
event.setCanceled(true); // Mobs can't target a player possessing an entity they don't normally attack ((EntityLiving)event.getEntityLiving()).setAttackTarget(null); // Mobs can't target a player possessing an entity they don't normally attack
} }
} }
} }
@@ -10,6 +10,7 @@ import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.packet.PacketSpellProperties; import electroblob.wizardry.packet.PacketSpellProperties;
import electroblob.wizardry.packet.WizardryPacketHandler; import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells; import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardrySounds; import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.SpellProperties; import electroblob.wizardry.util.SpellProperties;
@@ -18,6 +19,7 @@ import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.EnumAction; import net.minecraft.item.EnumAction;
import net.minecraft.item.Item;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
@@ -27,6 +29,10 @@ import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.registries.ForgeRegistry; import net.minecraftforge.registries.ForgeRegistry;
@@ -82,6 +88,7 @@ import java.util.stream.Collectors;
* @see ItemScroll ItemScroll * @see ItemScroll ItemScroll
* @see Spells * @see Spells
*/ */
@Mod.EventBusSubscriber
public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements Comparable<Spell> { public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements Comparable<Spell> {
// Spell checklist: // Spell checklist:
@@ -115,6 +122,8 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
private final String unlocalisedName; private final String unlocalisedName;
/** This spell's associated SpellProperties object. */ /** This spell's associated SpellProperties object. */
private SpellProperties properties; private SpellProperties properties;
/** A reference to the global spell properties for this spell, so they are only loaded once. */
private SpellProperties globalProperties;
/** Used in initialisation. */ /** Used in initialisation. */
private Set<String> propertyKeys = new HashSet<>(); private Set<String> propertyKeys = new HashSet<>();
@@ -221,7 +230,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
// Conversely, general spell classes ONLY EVER define the properties they ACTUALLY USE. // Conversely, general spell classes ONLY EVER define the properties they ACTUALLY USE.
public final Spell addProperties(String... keys){ public final Spell addProperties(String... keys){
if(properties != null) throw new IllegalStateException("Tried to add spell properties after they were initialised"); if(arePropertiesInitialised()) throw new IllegalStateException("Tried to add spell properties after they were initialised");
for(String key : keys) if(propertyKeys.contains(key)) Wizardry.logger.warn("Tried to add a duplicate property key '" for(String key : keys) if(propertyKeys.contains(key)) Wizardry.logger.warn("Tried to add a duplicate property key '"
+ key + "' to spell " + this.getRegistryName()); + key + "' to spell " + this.getRegistryName());
@@ -236,12 +245,19 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
return propertyKeys.toArray(new String[0]); return propertyKeys.toArray(new String[0]);
} }
/** Returns true if this spell's properties have been initialised, false if not. Check this if you're attempting
* to access them from code that could be called before wizardry's {@code init()} method (e.g. item attributes). */
public final boolean arePropertiesInitialised(){
return properties != null;
}
/** Sets this spell's properties to the given {@link SpellProperties} object, but only if it doesn't already /** Sets this spell's properties to the given {@link SpellProperties} object, but only if it doesn't already
* have one. This prevents spell properties from being changed after initialisation. */ * have one. This prevents spell properties from being changed after initialisation. */
public void setProperties(@Nonnull SpellProperties properties){ public void setProperties(@Nonnull SpellProperties properties){
if(this.properties == null){ if(!arePropertiesInitialised()){
this.properties = properties; this.properties = properties;
if(this.globalProperties == null) this.globalProperties = properties;
}else{ }else{
Wizardry.logger.info("A mod attempted to set a spell's properties, but they were already initialised."); Wizardry.logger.info("A mod attempted to set a spell's properties, but they were already initialised.");
} }
@@ -258,9 +274,14 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
.map(s -> s.properties).toArray(SpellProperties[]::new))); .map(s -> s.properties).toArray(SpellProperties[]::new)));
}else{ }else{
// On the client side, wipe the spell properties so the new ones can be set // On the client side, wipe the spell properties so the new ones can be set
for(Spell spell : registry){ // TESTME: Can we guarantee this happens before the packet arrives?
spell.properties = null; // TESTME: Can we guarantee this happens before the packet arrives? clearProperties();
} }
}
private static void clearProperties(){
for(Spell spell : registry){
spell.properties = null;
} }
} }
@@ -553,6 +574,13 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
this.enabled = isEnabled; this.enabled = isEnabled;
} }
/** Returns true if the given item has a variant for this spell. By default, returns true if the given item is
* either {@link WizardryItems#spell_book} or {@link WizardryItems#scroll}. Override to give the spell a special
* type of book or scroll. */
public boolean applicableForItem(Item item){
return item == WizardryItems.spell_book || item == WizardryItems.scroll;
}
/** /**
* Returns the unlocalised name of the spell, without any prefixes or suffixes, e.g. "flame_ray". <b>This should * Returns the unlocalised name of the spell, without any prefixes or suffixes, e.g. "flame_ray". <b>This should
* only be used for translation purposes.</b> * only be used for translation purposes.</b>
@@ -569,13 +597,23 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
* translating it. If, for whatever reason, you need to supply an ITextComponent but don't want it translated * translating it. If, for whatever reason, you need to supply an ITextComponent but don't want it translated
* (perhaps a name?), you can use TextComponentString, which will simply keep the raw string it is given. */ * (perhaps a name?), you can use TextComponentString, which will simply keep the raw string it is given. */
/** Returns the translation key for this spell. */
protected String getTranslationKey(){
return "spell." + unlocalisedName;
}
/** Returns the translation key for this spell's description. */
protected String getDescriptionTranslationKey(){
return "spell." + unlocalisedName + ".desc";
}
/** /**
* Returns the translated display name of the spell, without formatting (i.e. not coloured). <b>Client-side * Returns the translated display name of the spell, without formatting (i.e. not coloured). <b>Client-side
* only!</b> On the server side, use {@link TextComponentTranslation} (see {@link Spell#getNameForTranslation()}). * only!</b> On the server side, use {@link TextComponentTranslation} (see {@link Spell#getNameForTranslation()}).
*/ */
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
public String getDisplayName(){ public String getDisplayName(){
return net.minecraft.client.resources.I18n.format("spell." + unlocalisedName); return net.minecraft.client.resources.I18n.format(getTranslationKey());
} }
/** /**
@@ -583,7 +621,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
* formatting (i.e. not coloured). * formatting (i.e. not coloured).
*/ */
public ITextComponent getNameForTranslation(){ public ITextComponent getNameForTranslation(){
return new TextComponentTranslation("spell." + unlocalisedName); return new TextComponentTranslation(getTranslationKey());
} }
/** /**
@@ -592,7 +630,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
*/ */
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
public String getDisplayNameWithFormatting(){ public String getDisplayNameWithFormatting(){
return this.getElement().getFormattingCode() + net.minecraft.client.resources.I18n.format("spell." + unlocalisedName); return this.getElement().getFormattingCode() + net.minecraft.client.resources.I18n.format(getTranslationKey());
} }
/** /**
@@ -600,7 +638,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
* formatting (i.e. coloured). * formatting (i.e. coloured).
*/ */
public ITextComponent getNameForTranslationFormatted(){ public ITextComponent getNameForTranslationFormatted(){
return new TextComponentTranslation("spell." + unlocalisedName).setStyle(this.getElement().getColour()); return new TextComponentTranslation(getTranslationKey()).setStyle(this.getElement().getColour());
} }
/** /**
@@ -609,7 +647,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
*/ */
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
public String getDescription(){ public String getDescription(){
return net.minecraft.client.resources.I18n.format("spell." + unlocalisedName + ".desc"); return net.minecraft.client.resources.I18n.format(getDescriptionTranslationKey());
} }
// ============================================ Sound methods ============================================== // ============================================ Sound methods ==============================================
@@ -856,4 +894,32 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
&& (this.element == null || spell.getElement() == this.element); && (this.element == null || spell.getElement() == this.element);
} }
} }
// ============================================ Event handlers ==============================================
// Not ideal but it solves the reloading of spell properties without breaking encapsulation
@SubscribeEvent
public static void onWorldLoadEvent(WorldEvent.Load event){
if(!event.getWorld().isRemote){
if(event.getWorld().provider.getDimension() != 0) return; // Only do it once per save file
clearProperties();
SpellProperties.loadWorldSpecificSpellProperties(event.getWorld());
for(Spell spell : Spell.registry){
if(!spell.arePropertiesInitialised()) spell.setProperties(spell.globalProperties);
}
}
}
@SubscribeEvent
public static void onClientDisconnectEvent(FMLNetworkEvent.ClientDisconnectionFromServerEvent event){
// Why does the world UNLOAD event happen during world LOADING? How does that even work?!
clearProperties();
for(Spell spell : Spell.registry){
// If someone wants to access them from the menu, they'll get the global ones (not sure why you'd want to)
// No need to sync here since the server is about to shut down anyway
spell.setProperties(spell.globalProperties);
}
}
} }
@@ -149,7 +149,7 @@ public class SpellConstruct<T extends EntityMagicConstruct> extends Spell {
* @param modifiers The modifiers with which the spell was cast. * @param modifiers The modifiers with which the spell was cast.
* @return false to cause the spell to fail, true to continue with casting. * @return false to cause the spell to fail, true to continue with casting.
*/ */
protected boolean spawnConstruct(World world, double x, double y, double z, @Nullable EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ protected boolean spawnConstruct(World world, double x, double y, double z, @Nullable EnumFacing side, @Nullable EntityLivingBase caster, SpellModifiers modifiers){
if(!world.isRemote){ if(!world.isRemote){
// Creates a new construct using the supplied factory // Creates a new construct using the supplied factory
@@ -1,5 +1,6 @@
package electroblob.wizardry.spell; package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.ParticleBuilder; import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type; import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers; import electroblob.wizardry.util.SpellModifiers;
@@ -9,7 +10,11 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction; import net.minecraft.item.EnumAction;
import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class SummonSnowGolem extends Spell { public class SummonSnowGolem extends Spell {
@@ -45,4 +50,8 @@ public class SummonSnowGolem extends Spell {
return true; return true;
} }
@Override
protected String getTranslationKey(){
return Wizardry.tisTheSeason ? super.getTranslationKey() + "_festive" : super.getTranslationKey();
}
} }
@@ -5,6 +5,10 @@ import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.EnumAction; import net.minecraft.item.EnumAction;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import javax.annotation.Nullable;
public class Tornado extends SpellConstruct<EntityTornado> { public class Tornado extends SpellConstruct<EntityTornado> {
@@ -19,7 +23,8 @@ public class Tornado extends SpellConstruct<EntityTornado> {
@Override @Override
protected void addConstructExtras(EntityTornado construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){ protected void addConstructExtras(EntityTornado construct, EnumFacing side, EntityLivingBase caster, SpellModifiers modifiers){
float speed = getProperty(SPEED).floatValue(); float speed = getProperty(SPEED).floatValue();
construct.setHorizontalVelocity(caster.getLookVec().x * speed, caster.getLookVec().z * speed); Vec3d direction = caster == null ? new Vec3d(side.getDirectionVec()) : caster.getLookVec();
construct.setHorizontalVelocity(direction.x * speed, direction.z * speed);
} }
} }
@@ -142,12 +142,17 @@ public class TileEntityShrineCore extends TileEntity implements ITickable {
double z = this.pos.getZ() + 0.5; double z = this.pos.getZ() + 0.5;
if(!world.isRemote){ if(!world.isRemote){
WizardryPacketHandler.net.sendToAllAround(new PacketConquerShrine.Message(this.pos), WizardryPacketHandler.net.sendToAllAround(new PacketConquerShrine.Message(this.pos),
new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), x, y, z, 64)); new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), x, y, z, 64));
}
world.setBlockState(pos, WizardryBlocks.runestone_pedestal.getDefaultState() if(world.getBlockState(pos).getBlock() == WizardryBlocks.runestone_pedestal){
.withProperty(BlockPedestal.ELEMENT, world.getBlockState(pos).getValue(BlockPedestal.ELEMENT))); world.setBlockState(pos, WizardryBlocks.runestone_pedestal.getDefaultState()
.withProperty(BlockPedestal.ELEMENT, world.getBlockState(pos).getValue(BlockPedestal.ELEMENT)));
}else{
Wizardry.logger.warn("What's going on?! A shrine core is being conquered but the block at its position is not a runestone pedestal!");
}
}
world.markTileEntityForRemoval(this); world.markTileEntityForRemoval(this);
@@ -111,12 +111,12 @@ public final class AllyDesignationSystem {
*/ */
public static boolean isValidTarget(Entity attacker, Entity target){ public static boolean isValidTarget(Entity attacker, Entity target){
// Always return true if the attacker is null
if(attacker == null) return true;
// Always return false if the target is null // Always return false if the target is null
if(target == null) return false; if(target == null) return false;
// Always return true if the attacker is null - this must be after the target null check!
if(attacker == null) return true;
// Tests whether the target is the attacker // Tests whether the target is the attacker
if(target == attacker) return false; if(target == attacker) return false;
@@ -44,7 +44,7 @@ public final class CustomSoundCategory {
/** /**
* Adds a new custom sound category, performing the necessary changes to GameSettings and * Adds a new custom sound category, performing the necessary changes to GameSettings and
* *
* @param name A unique name for the sound category * @param name A unique name for the sound category. <b>Must not contain any colons!</b>
* @return The resulting SoundCategory object * @return The resulting SoundCategory object
* @throws IllegalArgumentException if name is not unique * @throws IllegalArgumentException if name is not unique
*/ */
@@ -59,8 +59,8 @@ public final class CustomSoundCategory {
constantName = name.toUpperCase().replace(" ", ""); constantName = name.toUpperCase().replace(" ", "");
referenceName = constantName.toLowerCase(); referenceName = constantName.toLowerCase();
// >> Electroblob: Removed array surrounding varargs argument // >> Electroblob: Removed array surrounding varargs argument
soundCategory = EnumHelper.addEnum(SoundCategory.class , constantName, new Class[]{String.class}, referenceName); soundCategory = EnumHelper.addEnum(SoundCategory.class , constantName, new Class<?>[]{String.class}, referenceName);
SOUND_CATEGORIES = ObfuscationReflectionHelper.getPrivateValue(SoundCategory.class, SoundCategory.VOICE ,"SOUND_CATEGORIES", SRG_SOUND_CATEGORIES); SOUND_CATEGORIES = ObfuscationReflectionHelper.getPrivateValue(SoundCategory.class, SoundCategory.VOICE, SRG_SOUND_CATEGORIES);
if (SOUND_CATEGORIES.containsKey(referenceName)) if (SOUND_CATEGORIES.containsKey(referenceName))
// >> Electroblob: changed from Error to IllegalArgumentException // >> Electroblob: changed from Error to IllegalArgumentException
throw new IllegalArgumentException("Clash in Sound Category name pools! Cannot insert " + constantName); throw new IllegalArgumentException("Clash in Sound Category name pools! Cannot insert " + constantName);
@@ -79,8 +79,7 @@ public final class CustomSoundCategory {
// Replace the map in the GameSettings.class // Replace the map in the GameSettings.class
// >> Electroblob: Fully qualified names, because this class gets loaded on both sides // >> Electroblob: Fully qualified names, because this class gets loaded on both sides
ObfuscationReflectionHelper.setPrivateValue(net.minecraft.client.settings.GameSettings.class, ObfuscationReflectionHelper.setPrivateValue(net.minecraft.client.settings.GameSettings.class,
net.minecraft.client.Minecraft.getMinecraft().gameSettings, soundLevels, net.minecraft.client.Minecraft.getMinecraft().gameSettings, soundLevels, SRG_soundLevels);
"soundLevels", SRG_soundLevels);
} }
} }
@@ -49,7 +49,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage
/** The name of the damagesource for indirect magic damage from the wizardry mod. */ /** The name of the damagesource for indirect magic damage from the wizardry mod. */
public static final String INDIRECT_MAGIC_DAMAGE = "indirect_wizardry_magic"; public static final String INDIRECT_MAGIC_DAMAGE = "indirect_wizardry_magic";
// Technically, I don't need to specify that the classes in this map must extend entity, but it's good practice to. // Technically, I don't need to specify that the classes in this map must extend entity, but it's good practice to.
private static final Map<Class<? extends Entity>, DamageType[]> immunityMapping = new HashMap<>(); private static final Map<Class<? extends Entity>, EnumSet<DamageType>> immunityMapping = new HashMap<>();
private final DamageType type; private final DamageType type;
private final boolean isRetaliatory; private final boolean isRetaliatory;
@@ -131,24 +131,25 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage
public static boolean isEntityImmune(DamageType type, Entity entity){ public static boolean isEntityImmune(DamageType type, Entity entity){
if(type == DamageType.FIRE && entity.isImmuneToFire()) return true; if(type == DamageType.FIRE && entity.isImmuneToFire()) return true;
EnumSet immunities = immunityMapping.get(entity.getClass());
DamageType[] immunities = MagicDamage.immunityMapping.get(entity.getClass()); return immunities != null && immunities.contains(type);
return immunities != null && Arrays.asList(immunities).contains(type);
} }
/** Registers the given type of entity as immune to all of the passed in damage types. */ /** Registers the given type of entity as immune to all of the passed in damage types. */
public static void setEntityImmunities(Class<? extends Entity> entityType, DamageType... immunities){ public static void setEntityImmunities(Class<? extends Entity> entityType, DamageType... immunities){
immunityMapping.put(entityType, immunities); EnumSet<DamageType> immunitySet = EnumSet.noneOf(DamageType.class);
Collections.addAll(immunitySet, immunities);
immunityMapping.put(entityType, immunitySet);
} }
/** Adds the passed in damage type to the list of damage types to which the given entity is immune. */ /** Adds the passed in damage type to the list of damage types to which the given entity is immune. */
public static void addEntityImmunity(Class<? extends Entity> entityType, DamageType immunity){ public static void addEntityImmunity(Class<? extends Entity> entityType, DamageType immunity){
List<DamageType> immunities = immunityMapping.get(entityType) == null ? new ArrayList<>() EnumSet<DamageType> immunitySet = immunityMapping.get(entityType);
: Arrays.asList(immunityMapping.get(entityType)); if (immunitySet == null) immunitySet = EnumSet.of(immunity);
immunities.add(immunity); else immunitySet.add(immunity);
// Apparently putting 0 here works just fine.
immunityMapping.put(entityType, immunities.toArray(new DamageType[0])); immunityMapping.put(entityType, immunitySet);
} }
/** /**
@@ -13,13 +13,16 @@ import electroblob.wizardry.spell.Spell;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.minecraft.util.JsonUtils; import net.minecraft.util.JsonUtils;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.ModContainer;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.*; import java.util.*;
@@ -40,9 +43,6 @@ import java.util.stream.Collectors;
* @author Electroblob * @author Electroblob
* @since Wizardry 4.2 * @since Wizardry 4.2
*/ */
// There is not a particular semantic reason to separate this from the Spell class itself. However, doing so means that
// everything related to the JSON spell system is kept in one place and doesn't clutter the (already long) Spell class.
// Additionally, it allows SpellProperties objects to be passed around during loading and syncing.
public final class SpellProperties { public final class SpellProperties {
private static final Gson gson = new Gson(); private static final Gson gson = new Gson();
@@ -245,32 +245,57 @@ public final class SpellProperties {
// things don't work as expected then that may be why - pretty sure it's fine though since the properties get // things don't work as expected then that may be why - pretty sure it's fine though since the properties get
// wiped client-side on each login anyway. // wiped client-side on each login anyway.
public static void init(){ public static void init(){
// Collecting to a set should give us one of each mod ID // Collecting to a set should give us one of each mod ID
Set<String> modIDs = Spell.getSpells(Spell.allSpells).stream().map(s -> s.getRegistryName().getNamespace()).collect(Collectors.toSet()); Set<String> modIDs = Spell.getSpells(Spell.allSpells).stream().map(s -> s.getRegistryName().getNamespace()).collect(Collectors.toSet());
boolean flag = true; boolean flag = loadConfigSpellProperties();
for(String modID : modIDs){ for(String modID : modIDs){
flag &= loadSpellProperties(modID); // Don't short-circuit, or mods later on won't get loaded! flag &= loadBuiltInSpellProperties(modID); // Don't short-circuit, or mods later on won't get loaded!
} }
if(!flag) Wizardry.logger.warn("Some spell property files did not load correctly; this will likely cause problems later!"); if(!flag) Wizardry.logger.warn("Some spell property files did not load correctly; this will likely cause problems later!");
} }
// Sooooooo I just realised that resource packs - you know, that famously client-side thing - can now define // There are now three 'layers' of spell properties - in order of priority, these are:
// stuff that should be specified by the server. No wonder it all got moved to data packs in 1.13... // 1. World-specific properties, stored in saves/[world]/data/spells
// Anyway, for the time being we're in 1.12 so we're gonna have to do this instead. // 2. Global overrides, stored in config/ebwizardry/spells
// 3. Built-in properties, stored in mods/[mod jar]/assets/spells
// There's a method for loading each of these below, because that makes sense to me!
public static void loadWorldSpecificSpellProperties(World world){
Wizardry.logger.info("Loading custom spell properties for world {}", world.getWorldInfo().getWorldName());
File spellJSONDir = new File(new File(world.getSaveHandler().getWorldDirectory(), "data"), "spells");
if(spellJSONDir.mkdirs()) return; // If it just got created it can't possibly have anything inside
if(!loadSpellPropertiesFromDir(spellJSONDir)) Wizardry.logger.warn("Some spell property files did not load correctly; this will likely cause problems later!");
}
private static boolean loadConfigSpellProperties(){
Wizardry.logger.info("Loading spell properties from config folder");
File spellJSONDir = new File(Wizardry.configDirectory, "spells");
if(!spellJSONDir.exists()) return true; // If there's no global spell properties folder, do nothing
return loadSpellPropertiesFromDir(spellJSONDir);
}
// For crafting recipes, Forge does some stuff behind the scenes to load recipe JSON files from mods' namespaces. // For crafting recipes, Forge does some stuff behind the scenes to load recipe JSON files from mods' namespaces.
// This leverages the same methods. // This leverages the same methods.
private static boolean loadSpellProperties(String modID){ private static boolean loadBuiltInSpellProperties(String modID){
// Yes, I know you're not supposed to do orElse(null). But... meh. // Yes, I know you're not supposed to do orElse(null). But... meh.
ModContainer mod = Loader.instance().getModList().stream().filter(m -> m.getModId().equals(modID)).findFirst().orElse(null); ModContainer mod = Loader.instance().getModList().stream().filter(m -> m.getModId().equals(modID)).findFirst().orElse(null);
if(mod == null){ if(mod == null){
Wizardry.logger.warn("Tried to load spell properties for mod with ID '" + modID + "', but no such mod was loaded"); Wizardry.logger.warn("Tried to load built-in spell properties for mod with ID '" + modID + "', but no such mod was loaded");
return false; // Failed! return false; // Failed!
} }
@@ -279,7 +304,7 @@ public final class SpellProperties {
List<Spell> spells = Spell.getSpells(s -> s.getRegistryName().getNamespace().equals(modID)); List<Spell> spells = Spell.getSpells(s -> s.getRegistryName().getNamespace().equals(modID));
if(modID.equals(Wizardry.MODID)) spells.add(Spells.none); // In this particular case we do need the none spell if(modID.equals(Wizardry.MODID)) spells.add(Spells.none); // In this particular case we do need the none spell
Wizardry.logger.info("Loading spell properties for " + spells.size() + " spells in mod " + modID); Wizardry.logger.info("Loading built-in spell properties for " + spells.size() + " spells in mod " + modID);
// This method is used by Forge to load mod recipes and advancements, so it's a fair bet it's the right one // This method is used by Forge to load mod recipes and advancements, so it's a fair bet it's the right one
// In the absence of Javadoc, here's what the non-obvious parameters do: // In the absence of Javadoc, here's what the non-obvious parameters do:
@@ -307,12 +332,16 @@ public final class SpellProperties {
return true; return true;
} }
BufferedReader reader = null;
// We want to do this regardless of whether the JSON file got read properly, because that prints its // We want to do this regardless of whether the JSON file got read properly, because that prints its
// own separate warning // own separate warning
if(!spells.remove(spell)) Wizardry.logger.warn("What's going on?!"); if(!spells.remove(spell)) Wizardry.logger.warn("What's going on?!");
// Ignore spells overridden in the config folder
// This needs to be done AFTER the above line or it'll think there are missing spell properties files
if(spell.arePropertiesInitialised()) return true;
BufferedReader reader = null;
try{ try{
reader = Files.newBufferedReader(file); reader = Files.newBufferedReader(file);
@@ -348,6 +377,54 @@ public final class SpellProperties {
return success; return success;
} }
private static boolean loadSpellPropertiesFromDir(File dir){
boolean success = true;
for(File file : FileUtils.listFiles(dir, new String[]{"json"}, true)){
// The structure in world and config folders is subtly different in that the "spells" and mod id directories
// are in the opposite order, i.e. it's spells/modid/whatever.json instead of modid/spells/whatever.json
String relative = dir.toPath().relativize(file.toPath()).toString(); // modid\whatever.json
String nameAndModID = FilenameUtils.removeExtension(relative).replaceAll("\\\\", "/"); // modid/whatever
String modID = nameAndModID.split("/")[0]; // modid
String name = nameAndModID.substring(nameAndModID.indexOf('/') + 1); // whatever
ResourceLocation key = new ResourceLocation(modID, name);
Spell spell = Spell.registry.getValue(key);
// If no spell matches a particular file, log it and just ignore the file
if(spell == null){
Wizardry.logger.info("Spell properties file " + nameAndModID + ".json does not match any registered spells; ensure the filename is spelled correctly.");
continue;
}
BufferedReader reader = null;
try{
reader = Files.newBufferedReader(file.toPath());
JsonObject json = JsonUtils.fromJson(gson, reader, JsonObject.class);
SpellProperties properties = new SpellProperties(json, spell);
spell.setProperties(properties);
}catch(JsonParseException jsonparseexception){
Wizardry.logger.error("Parsing error loading spell property file for " + key, jsonparseexception);
success = false;
}catch(IOException ioexception){
Wizardry.logger.error("Couldn't read spell property file for " + key, ioexception);
success = false;
}finally{
IOUtils.closeQuietly(reader);
}
}
return success;
}
} }
// We probably could have used the attribute system for all of this, but I am reluctant to do so for a number of // We probably could have used the attribute system for all of this, but I am reluctant to do so for a number of
@@ -50,7 +50,7 @@ public final class WandHelper {
public static final String UPGRADES_KEY = "upgrades"; public static final String UPGRADES_KEY = "upgrades";
public static final String PROGRESSION_KEY = "progression"; public static final String PROGRESSION_KEY = "progression";
private static final HashMap<Item, String> upgradeMap = new HashMap<Item, String>(); private static final HashMap<Item, String> upgradeMap = new HashMap<>();
static { static {
upgradeMap.put(WizardryItems.condenser_upgrade, "condenser"); upgradeMap.put(WizardryItems.condenser_upgrade, "condenser");
@@ -251,11 +251,15 @@ public final class WandHelper {
/** Returns the given wand's cooldown for the currently selected spell, or 0 if the wand has no cooldown data. */ /** Returns the given wand's cooldown for the currently selected spell, or 0 if the wand has no cooldown data. */
public static int getCurrentCooldown(ItemStack wand){ public static int getCurrentCooldown(ItemStack wand){
if(wand.getTagCompound() == null) wand.setTagCompound(new NBTTagCompound());
int[] cooldowns = getCooldowns(wand); int[] cooldowns = getCooldowns(wand);
if(cooldowns.length == 0) return 0; int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY);
if(selectedSpell < 0 || cooldowns.length <= selectedSpell) return 0;
// Don't need to check if the tag compound is null since the above check is equivalent. // Don't need to check if the tag compound is null since the above check is equivalent.
return cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)]; return cooldowns[selectedSpell];
} }
/** Returns the given wand's cooldown for the spell after the currently selected spell, or 0 if the wand has no /** Returns the given wand's cooldown for the spell after the currently selected spell, or 0 if the wand has no
@@ -264,9 +268,11 @@ public final class WandHelper {
int[] cooldowns = getCooldowns(wand); int[] cooldowns = getCooldowns(wand);
if(cooldowns.length == 0) return 0; int nextSpell = getNextSpellIndex(wand);
if(nextSpell < 0 || cooldowns.length <= nextSpell) return 0;
// Don't need to check if the tag compound is null since the above check is equivalent. // Don't need to check if the tag compound is null since the above check is equivalent.
return cooldowns[getNextSpellIndex(wand)]; return cooldowns[nextSpell];
} }
/** Returns the given wand's cooldown for the spell before the currently selected spell, or 0 if the wand has no /** Returns the given wand's cooldown for the spell before the currently selected spell, or 0 if the wand has no
@@ -275,9 +281,11 @@ public final class WandHelper {
int[] cooldowns = getCooldowns(wand); int[] cooldowns = getCooldowns(wand);
if(cooldowns.length == 0) return 0; int previousSpell = getPreviousSpellIndex(wand);
if(previousSpell < 0 || cooldowns.length <= previousSpell) return 0;
// Don't need to check if the tag compound is null since the above check is equivalent. // Don't need to check if the tag compound is null since the above check is equivalent.
return cooldowns[getPreviousSpellIndex(wand)]; return cooldowns[previousSpell];
} }
/** Sets the given wand's cooldown for the currently selected spell. Will also set the maximum cooldown. */ /** Sets the given wand's cooldown for the currently selected spell. Will also set the maximum cooldown. */
@@ -287,19 +295,24 @@ public final class WandHelper {
int[] cooldowns = getCooldowns(wand); int[] cooldowns = getCooldowns(wand);
int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY);
int spellCount = getSpells(wand).length;
if(spellCount <= selectedSpell) return; // Probably shouldn't happen
// The length of the spells array must be greater than 0 since this method can only be called if a spell is // The length of the spells array must be greater than 0 since this method can only be called if a spell is
// cast, which is impossible if there are no spells. // cast, which is impossible if there are no spells.
if(cooldowns.length == 0) cooldowns = new int[getSpells(wand).length]; if(cooldowns.length <= selectedSpell) cooldowns = new int[spellCount];
cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)] = cooldown; cooldowns[selectedSpell] = cooldown;
setCooldowns(wand, cooldowns); setCooldowns(wand, cooldowns);
int[] maxCooldowns = getMaxCooldowns(wand); int[] maxCooldowns = getMaxCooldowns(wand);
if(maxCooldowns.length == 0) maxCooldowns = new int[getSpells(wand).length]; if(maxCooldowns.length <= selectedSpell) maxCooldowns = new int[spellCount];
maxCooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)] = cooldown; maxCooldowns[selectedSpell] = cooldown;
setMaxCooldowns(wand, maxCooldowns); setMaxCooldowns(wand, maxCooldowns);
} }
@@ -333,9 +346,13 @@ public final class WandHelper {
int[] cooldowns = getMaxCooldowns(wand); int[] cooldowns = getMaxCooldowns(wand);
if(cooldowns.length == 0) return 0; if(wand.getTagCompound() == null) return 0;
// Don't need to check if the tag compound is null since the above check is equivalent.
return cooldowns[wand.getTagCompound().getInteger(SELECTED_SPELL_KEY)]; int selectedSpell = wand.getTagCompound().getInteger(SELECTED_SPELL_KEY);
if(cooldowns.length <= selectedSpell) return 0;
return cooldowns[selectedSpell];
} }
// ================================================== Upgrades ================================================== // ================================================== Upgrades ==================================================
@@ -7,6 +7,7 @@ import electroblob.wizardry.entity.living.ISpellCaster;
import electroblob.wizardry.item.ISpellCastingItem; import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.spell.Spell; import electroblob.wizardry.spell.Spell;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockCactus;
import net.minecraft.block.BlockLog; import net.minecraft.block.BlockLog;
import net.minecraft.block.properties.IProperty; import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
@@ -269,7 +270,7 @@ public final class WizardryUtilities {
/** Surface criterion which defines a surface as the boundary between a block that is solid on the required side and /** Surface criterion which defines a surface as the boundary between a block that is solid on the required side and
* a block that is replaceable. This means the surface can be built on. */ * a block that is replaceable. This means the surface can be built on. */
SurfaceCriteria BUILDABLE = (world, pos, side) -> world.isSideSolid(pos, side) && world.getBlockState(pos.offset(side)).getBlock().isReplaceable(world, pos); SurfaceCriteria BUILDABLE = (world, pos, side) -> world.isSideSolid(pos, side) && world.getBlockState(pos.offset(side)).getBlock().isReplaceable(world, pos.offset(side));
/** Surface criterion which defines a surface as the boundary between a block that is solid on the required side /** Surface criterion which defines a surface as the boundary between a block that is solid on the required side
* or a liquid, and an air block. Used for freezing water and placing snow. */ * or a liquid, and an air block. Used for freezing water and placing snow. */
@@ -285,13 +286,25 @@ public final class WizardryUtilities {
/** Surface criterion which defines a surface as the boundary between a block that cannot be moved through, and /** Surface criterion which defines a surface as the boundary between a block that cannot be moved through, and
* a block that can be moved through or a tree block (log or leaves). Used for structure generation. */ * a block that can be moved through or a tree block (log or leaves). Used for structure generation. */
SurfaceCriteria COLLIDABLE_IGNORING_TREES = basedOn((world, pos) -> SurfaceCriteria COLLIDABLE_IGNORING_TREES = basedOn((world, pos) ->
world.getBlockState(pos).getMaterial().blocksMovement() world.getBlockState(pos).getMaterial().blocksMovement() && !isTreeBlock(world, pos));
&& !(world.getBlockState(pos).getBlock() instanceof BlockLog)
&& !(world.getBlockState(pos).getBlock().isLeaves(world.getBlockState(pos), world, pos)
&& !(world.getBlockState(pos).getBlock().isFoliage(world, pos))));
} }
/**
* Returns true if the block at the given position is a tree block (or other 'solid' vegetation, such as cacti).
* Used for structure generation.
* @param world The world the block is in
* @param pos The position of the block to be tested
* @return True if the given block is a tree block, false if not.
*/
public static boolean isTreeBlock(World world, BlockPos pos){
return world.getBlockState(pos).getBlock() instanceof BlockLog
|| world.getBlockState(pos).getBlock() instanceof BlockCactus
|| world.getBlockState(pos).getBlock().isLeaves(world.getBlockState(pos), world, pos)
|| world.getBlockState(pos).getBlock().isFoliage(world, pos)
|| Arrays.asList(Wizardry.settings.treeBlocks).contains(world.getBlockState(pos).getBlock().getRegistryName());
}
/** /**
* Finds the nearest floor level in the given direction from the given position, * Finds the nearest floor level in the given direction from the given position,
* within the range specified. This is a shorthand for * within the range specified. This is a shorthand for
@@ -857,9 +870,10 @@ public final class WizardryUtilities {
ItemStack stack = caster.getHeldItem(caster.getActiveHand()); ItemStack stack = caster.getHeldItem(caster.getActiveHand());
if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).getCurrentSpell(stack) == spell if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).getCurrentSpell(stack) == spell){
&& ((ISpellCastingItem)stack.getItem()).canCast(stack, spell, (EntityPlayer)caster, // Don't do this, it interferes with stuff! We effectively already tested this with caster.isHandActive() anyway
EnumHand.MAIN_HAND, 0, new SpellModifiers())){ // && ((ISpellCastingItem)stack.getItem()).canCast(stack, spell, (EntityPlayer)caster,
// EnumHand.MAIN_HAND, 0, new SpellModifiers())){
return true; return true;
} }
} }
@@ -27,7 +27,6 @@ import net.minecraft.world.gen.structure.MapGenStructureData;
import net.minecraft.world.gen.structure.StructureBoundingBox; import net.minecraft.world.gen.structure.StructureBoundingBox;
import net.minecraft.world.gen.structure.template.PlacementSettings; import net.minecraft.world.gen.structure.template.PlacementSettings;
import net.minecraft.world.gen.structure.template.Template; import net.minecraft.world.gen.structure.template.Template;
import net.minecraftforge.common.BiomeDictionary;
import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.common.IWorldGenerator; import net.minecraftforge.fml.common.IWorldGenerator;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@@ -120,6 +119,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
* @param world The world in which to spawn the structure * @param world The world in which to spawn the structure
* @param chunkX The x-coordinate of the chunk being populated * @param chunkX The x-coordinate of the chunk being populated
* @param chunkZ The z-coordinate of the chunk being populated * @param chunkZ The z-coordinate of the chunk being populated
* @param structureFile The name of the structure file, used for error messages.
* @return The coordinates of the position found, or null if no suitable position was found. The returned * @return The coordinates of the position found, or null if no suitable position was found. The returned
* {@code BlockPos} is <b>always</b> the northwest corner of the structure, and the y-coordinate is that of the * {@code BlockPos} is <b>always</b> the northwest corner of the structure, and the y-coordinate is that of the
* uppermost block at those (x, z) coordinates. If the structure is being rotated this needs to be altered using * uppermost block at those (x, z) coordinates. If the structure is being rotated this needs to be altered using
@@ -128,7 +128,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
*/ */
@Nullable @Nullable
protected BlockPos findValidPosition(Template template, PlacementSettings settings, Random random, World world, protected BlockPos findValidPosition(Template template, PlacementSettings settings, Random random, World world,
int chunkX, int chunkZ){ int chunkX, int chunkZ, String structureFile){
// Offset by (8, 8) to minimise cascading worldgen lag // Offset by (8, 8) to minimise cascading worldgen lag
// See https://www.reddit.com/r/feedthebeast/cowmments/5x0twz/investigating_extreme_worldgen_lag/?ref=share&ref_source=embed&utm_content=title&utm_medium=post_embed&utm_name=c07cbb545f74487793783012794733d8&utm_source=embedly&utm_term=5x0twz // See https://www.reddit.com/r/feedthebeast/cowmments/5x0twz/investigating_extreme_worldgen_lag/?ref=share&ref_source=embed&utm_content=title&utm_medium=post_embed&utm_name=c07cbb545f74487793783012794733d8&utm_source=embedly&utm_term=5x0twz
@@ -136,6 +136,11 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
BlockPos origin = new BlockPos(8 + (chunkX << 4) + random.nextInt(16), 0, 8 + (chunkZ << 4) + random.nextInt(16)); BlockPos origin = new BlockPos(8 + (chunkX << 4) + random.nextInt(16), 0, 8 + (chunkZ << 4) + random.nextInt(16));
BlockPos size = template.transformedSize(settings.getRotation()); BlockPos size = template.transformedSize(settings.getRotation());
if(size.getX() == 0 || size.getY() == 0 || size.getZ() == 0){
Wizardry.logger.warn("Structure template file {} is missing or empty! If you're trying to disable structure spawning, pointing to a non-existent location is NOT the correct way to do so; use the structure dimension lists instead.", structureFile);
}
// Estimate a starting height for searching for the floor // Estimate a starting height for searching for the floor
BlockPos centre = world.getTopSolidOrLiquidBlock(new BlockPos(origin.add(size.getX()/2, 0, size.getZ()/2))); BlockPos centre = world.getTopSolidOrLiquidBlock(new BlockPos(origin.add(size.getX()/2, 0, size.getZ()/2)));
Integer startingHeight = WizardryUtilities.getNearestSurface(world, centre, EnumFacing.UP, 32, true, Integer startingHeight = WizardryUtilities.getNearestSurface(world, centre, EnumFacing.UP, 32, true,
@@ -145,8 +150,8 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
if(Wizardry.settings.fastWorldgen){ if(Wizardry.settings.fastWorldgen){
BlockPos result = origin.up(startingHeight); BlockPos result = origin.up(startingHeight);
// Fast worldgen doesn't check for water, instead it checks the biome like vanilla, which is crude but fast // Fast worldgen only checks the central position for water, which isn't perfect but it is faster
return BiomeDictionary.hasType(world.getBiome(result), BiomeDictionary.Type.WATER) ? null : result; return world.getBlockState(new BlockPos(centre.getX(), startingHeight + 1, centre.getZ())).getMaterial().isLiquid() ? null : result;
} }
int[] floorHeights = new int[size.getX() * size.getZ()]; int[] floorHeights = new int[size.getX() * size.getZ()];
@@ -212,7 +217,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
BlockPos origin; BlockPos origin;
do { do {
origin = findValidPosition(template, settings, random, world, chunkX, chunkZ); origin = findValidPosition(template, settings, random, world, chunkX, chunkZ, structureFile.toString());
triesLeft--; triesLeft--;
}while(triesLeft > 0 && origin != null); }while(triesLeft > 0 && origin != null);
@@ -244,7 +249,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
spawnStructure(random, world, origin, template, settings, structureFile); spawnStructure(random, world, origin, template, settings, structureFile);
if(!Wizardry.settings.fastWorldgen) removeFloatingTrees(world, box); if(!Wizardry.settings.fastWorldgen) removeFloatingTrees(world, box, random);
structureMap.put(ChunkPos.asLong(origin.getX() >> 4, origin.getZ() >> 4), settings.getBoundingBox()); structureMap.put(ChunkPos.asLong(origin.getX() >> 4, origin.getZ() >> 4), settings.getBoundingBox());
@@ -306,7 +311,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
} }
/** Finds and removes any floating bits of tree in and above the given structure bounding box. */ /** Finds and removes any floating bits of tree in and above the given structure bounding box. */
protected static void removeFloatingTrees(World world, StructureBoundingBox boundingBox){ protected static void removeFloatingTrees(World world, StructureBoundingBox boundingBox, Random random){
boolean changed = true; boolean changed = true;
int y = boundingBox.minY; int y = boundingBox.minY;
@@ -327,8 +332,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
Block below = world.getBlockState(pos.down()).getBlock(); Block below = world.getBlockState(pos.down()).getBlock();
if(block instanceof BlockLog){ if(block instanceof BlockLog){
if(below != Blocks.GRASS && below != Blocks.DIRT && !(below instanceof BlockLog) && if(below != Blocks.GRASS && below != Blocks.DIRT && !WizardryUtilities.isTreeBlock(world, pos.down())){
!below.isLeaves(world.getBlockState(pos.down()), world, pos.down())){
world.setBlockToAir(pos); world.setBlockToAir(pos);
changed = true; changed = true;
} }
@@ -355,7 +359,7 @@ public abstract class WorldGenSurfaceStructure implements IWorldGenerator {
} }
for(int i=0; i<16; i++){ for(int i=0; i<16; i++){
leaves.forEach(p -> world.getBlockState(p).getBlock().updateTick(world, p, world.getBlockState(p), null)); leaves.forEach(p -> world.getBlockState(p).getBlock().updateTick(world, p, world.getBlockState(p), random));
} }
// Finally, remove all the items that were dropped as a result of leaf decay // Finally, remove all the items that were dropped as a result of leaf decay
@@ -313,7 +313,7 @@ item.ebwizardry\:amulet_auto_shield.desc=Grants a 25%% chance to trigger the shi
item.ebwizardry\:charm_haggler.name=Haggler's Sign item.ebwizardry\:charm_haggler.name=Haggler's Sign
item.ebwizardry\:charm_haggler.desc=Wizards are guaranteed to offer a new trade every time you trade with them item.ebwizardry\:charm_haggler.desc=Wizards are guaranteed to offer a new trade every time you trade with them
item.ebwizardry\:charm_experience_tome.name=Tome of the Diligent item.ebwizardry\:charm_experience_tome.name=Tome of the Diligent
item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 40%% item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 50%%
item.ebwizardry\:charm_auto_smelt.name=Metallurgist's Mark item.ebwizardry\:charm_auto_smelt.name=Metallurgist's Mark
item.ebwizardry\:charm_auto_smelt.desc=Pocket furnace triggers automatically when bound to a wand on your hotbar item.ebwizardry\:charm_auto_smelt.desc=Pocket furnace triggers automatically when bound to a wand on your hotbar
item.ebwizardry\:charm_lava_walking.name=Nether Ice Core item.ebwizardry\:charm_lava_walking.name=Nether Ice Core
@@ -719,14 +719,14 @@ spell.ebwizardry\:arc.desc=Fires a spark of lightning at the target.
spell.ebwizardry\:arcane_jammer.desc=Prevents the target from using magic for 15 seconds. spell.ebwizardry\:arcane_jammer.desc=Prevents the target from using magic for 15 seconds.
spell.ebwizardry\:arcane_lock.desc=Creates an impenetrable barrier of force around a container, protecting it from being opened or destroyed. The caster and their allies may still open it, however. spell.ebwizardry\:arcane_lock.desc=Creates an impenetrable barrier of force around a container, protecting it from being opened or destroyed. The caster and their allies may still open it, however.
spell.ebwizardry\:arrow_rain.desc="Archers, fire!" spell.ebwizardry\:arrow_rain.desc="Archers, fire!"
spell.ebwizardry\:banish.desc=Teleports the target against its will to a random locations within a certain range. spell.ebwizardry\:banish.desc=Teleports the target against its will to a random location within a certain range.
spell.ebwizardry\:black_hole.desc=Tear reality asunder. spell.ebwizardry\:black_hole.desc=Tear reality asunder.
spell.ebwizardry\:blink.desc=Teleports the caster over a short distance to where they are pointing. spell.ebwizardry\:blink.desc=Teleports the caster over a short distance to where they are pointing.
spell.ebwizardry\:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed. spell.ebwizardry\:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed.
spell.ebwizardry\:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged. spell.ebwizardry\:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged.
spell.ebwizardry\:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice. spell.ebwizardry\:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice.
spell.ebwizardry\:charge.desc=Causes the caster to charge rapidly in the direction they are looking, damaging and knocking back anything in their path. spell.ebwizardry\:charge.desc=Causes the caster to charge rapidly in the direction they are looking, damaging and knocking back anything in their path.
spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered locations. With this spell selected, sneak-right-click on a block to set the locations. Cast this spell normally to reveal the path. The path will fade after 90 seconds. spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered location. With this spell selected, sneak-right-click on a block to set the location. Cast this spell normally to reveal the path. The path will fade after 90 seconds.
spell.ebwizardry\:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken. spell.ebwizardry\:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken.
spell.ebwizardry\:combustion_rune.desc=Places a magical landmine on the ground where you are pointing, which explodes when stepped upon. spell.ebwizardry\:combustion_rune.desc=Places a magical landmine on the ground where you are pointing, which explodes when stepped upon.
spell.ebwizardry\:conjure_armour.desc=Creates spectral armour around the caster which offers protection equal to that of iron armour. The armour lasts for 60 seconds. The caster must have an empty armour slot. spell.ebwizardry\:conjure_armour.desc=Creates spectral armour around the caster which offers protection equal to that of iron armour. The armour lasts for 60 seconds. The caster must have an empty armour slot.
@@ -895,9 +895,9 @@ spell.ebwizardry\:transportation.undefined=You must remember the location of a s
spell.ebwizardry\:transportation.wrongdimension=No remembered stone circle in this dimension... spell.ebwizardry\:transportation.wrongdimension=No remembered stone circle in this dimension...
spell.ebwizardry\:clairvoyance.searching=Searching... spell.ebwizardry\:clairvoyance.searching=Searching...
spell.ebwizardry\:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point spell.ebwizardry\:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point
spell.ebwizardry\:clairvoyance.outofrange=Your remembered locations is too far away or inaccessible... spell.ebwizardry\:clairvoyance.outofrange=Your remembered location is too far away or inaccessible...
spell.ebwizardry\:clairvoyance.undefined=You must remember a locations first! spell.ebwizardry\:clairvoyance.undefined=You must remember a location first!
spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered locations is in another dimension... spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered location is in another dimension...
spell.ebwizardry\:possession.insufficienthealth=You don't have enough health to possess %1$s! spell.ebwizardry\:possession.insufficienthealth=You don't have enough health to possess %1$s!
spell.ebwizardry\:possession.success=Press %s to stop possessing spell.ebwizardry\:possession.success=Press %s to stop possessing
spell.ebwizardry\:divination.nothing=Nothing happened. spell.ebwizardry\:divination.nothing=Nothing happened.
@@ -1003,6 +1003,16 @@ enchantment.ebwizardry\:magic_protection=Magic Protection
enchantment.ebwizardry\:frost_protection=Frost Protection enchantment.ebwizardry\:frost_protection=Frost Protection
enchantment.ebwizardry\:shock_protection=Shock Protection enchantment.ebwizardry\:shock_protection=Shock Protection
enchantment.ebwizardry.magic_sword.desc=Part of the Imbue Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.magic_bow.desc=Part of the Imbue Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.flaming_weapon.desc=Part of the Flaming Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.freezing_weapon.desc=Part of the Freezing Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.shocking_weapon.desc=Part of the Shocking Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.magic_protection.desc=Reduces damage from all magic.
enchantment.ebwizardry.frost_protection.desc=Reduces the effects of frost damage.
enchantment.ebwizardry.shock_protection.desc=Reduces the effects of shock damage.
key.categories.ebwizardry=Wizardry key.categories.ebwizardry=Wizardry
key.ebwizardry.next_spell=Next Spell key.ebwizardry.next_spell=Next Spell
@@ -1011,7 +1021,7 @@ key.ebwizardry.previous_spell=Previous Spell
death.attack.wizardry_magic=%1$s was killed by %2$s using magic death.attack.wizardry_magic=%1$s was killed by %2$s using magic
death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic
soundCategory.ebwizardry\:spells=Spells soundCategory.ebwizardry_spells=Spells
commands.ebwizardry\:cast.usage=/%1$s <spell> [player | x y z direction] [duration] [modifiers] commands.ebwizardry\:cast.usage=/%1$s <spell> [player | x y z direction] [duration] [modifiers]
commands.ebwizardry\:cast.success=Successfully cast %s commands.ebwizardry\:cast.success=Successfully cast %s
@@ -1107,6 +1117,8 @@ config.ebwizardry.creative_bypasses_arcane_lock.true=Anyone in creative mode
config.ebwizardry.creative_bypasses_arcane_lock.false=Only ops in creative mode config.ebwizardry.creative_bypasses_arcane_lock.false=Only ops in creative mode
config.ebwizardry.slow_time_affects_players=Slow Time Affects Players config.ebwizardry.slow_time_affects_players=Slow Time Affects Players
config.ebwizardry.slow_time_affects_players.tooltip=Whether players are slowed when another nearby player uses the slow time spell. If this is disabled, mobs and projectiles will still be affected but players will move at normal speed. config.ebwizardry.slow_time_affects_players.tooltip=Whether players are slowed when another nearby player uses the slow time spell. If this is disabled, mobs and projectiles will still be affected but players will move at normal speed.
config.ebwizardry.bonemeal_grows_crystal_flowers=Bonemeal Grows Crystal Flowers
config.ebwizardry.bonemeal_grows_crystal_flowers.tooltip=Whether using bonemeal on grass blocks has a chance to grow crystal flowers.
config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist
config.ebwizardry.mob_loot_table_whitelist.tooltip=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. config.ebwizardry.mob_loot_table_whitelist.tooltip=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.
config.ebwizardry.mob_loot_table_blacklist=Mob Loot Table Blacklist config.ebwizardry.mob_loot_table_blacklist=Mob Loot Table Blacklist
@@ -1154,27 +1166,29 @@ config.ebwizardry.fast_worldgen.tooltip=Controls which algorithm wizardry uses f
config.ebwizardry.fast_worldgen.true=Fast config.ebwizardry.fast_worldgen.true=Fast
config.ebwizardry.fast_worldgen.false=Fancy config.ebwizardry.fast_worldgen.false=Fancy
config.ebwizardry.tower_dimensions=Tower Dimensions config.ebwizardry.tower_dimensions=Tower Dimensions
config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate. config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate. Remove all dimensions to disable wizard towers completely.
config.ebwizardry.tower_rarity=Tower Rarity config.ebwizardry.tower_rarity=Tower Rarity
config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer. config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.
config.ebwizardry.evil_wizard_chance=Evil Wizard Chance config.ebwizardry.evil_wizard_chance=Evil Wizard Chance
config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard. config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.
config.ebwizardry.tower_files=Tower Structure Files config.ebwizardry.tower_files=Tower Structure Files
config.ebwizardry.tower_files.tooltip=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. config.ebwizardry.tower_files.tooltip=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.
config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files
config.ebwizardry.tower_with_chest_files.tooltip=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. config.ebwizardry.tower_with_chest_files.tooltip=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.
config.ebwizardry.obelisk_dimensions=Obelisk Dimensions config.ebwizardry.obelisk_dimensions=Obelisk Dimensions
config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate. config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate. Remove all dimensions to disable obelisks completely.
config.ebwizardry.obelisk_rarity=Obelisk Rarity config.ebwizardry.obelisk_rarity=Obelisk Rarity
config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer. config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.
config.ebwizardry.obelisk_files=Obelisk Structure Files config.ebwizardry.obelisk_files=Obelisk Structure Files
config.ebwizardry.obelisk_files.tooltip=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. config.ebwizardry.obelisk_files.tooltip=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.
config.ebwizardry.shrine_dimensions=Shrine Dimensions config.ebwizardry.shrine_dimensions=Shrine Dimensions
config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate. config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate. Remove all dimensions to disable shrines completely.
config.ebwizardry.shrine_rarity=Shrine Rarity config.ebwizardry.shrine_rarity=Shrine Rarity
config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer. config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.
config.ebwizardry.shrine_files=Shrine Structure Files config.ebwizardry.shrine_files=Shrine Structure Files
config.ebwizardry.shrine_files.tooltip=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. config.ebwizardry.shrine_files.tooltip=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.
config.ebwizardry.tree_blocks=Tree Blocks
config.ebwizardry.tree_blocks.tooltip=List of registry names of blocks which can be overwritten by wizardry's structure generators, affecting both fast and fancy structure generation. Most tree blocks and other foliage should work automatically, but those that don't can be added manually here. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. dynamictrees:oakbranch).
config.ebwizardry.ore_dimensions=Ore Dimensions config.ebwizardry.ore_dimensions=Ore Dimensions
config.ebwizardry.ore_dimensions.tooltip=List of ids of dimensions in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play! config.ebwizardry.ore_dimensions.tooltip=List of ids of dimensions in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!
config.ebwizardry.flower_dimensions=Flower Dimensions config.ebwizardry.flower_dimensions=Flower Dimensions
@@ -1275,4 +1289,9 @@ integration.antiqueatlas.marker.ebwizardry\:wizard_tower=Wizard Tower
integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk
integration.antiqueatlas.marker.ebwizardry\:shrine=Shrine integration.antiqueatlas.marker.ebwizardry\:shrine=Shrine
spell.ebwizardry\:magic_missile_festive=Magic Mistletoe
spell.ebwizardry\:summon_snow_golem_festive=Summon Frosty The Snowman
spell.ebwizardry\:invigorating_presence_festive=Invigorating Presents
spell.ebwizardry\:empowering_presence_festive=Empowering Presents
wizard.debug=%1$s, %2$s, %3$s wizard.debug=%1$s, %2$s, %3$s
@@ -313,7 +313,7 @@ item.ebwizardry\:amulet_auto_shield.desc=Grants a 25%% chance to trigger the shi
item.ebwizardry\:charm_haggler.name=Haggler's Sign item.ebwizardry\:charm_haggler.name=Haggler's Sign
item.ebwizardry\:charm_haggler.desc=Wizards are guaranteed to offer a new trade every time you trade with them item.ebwizardry\:charm_haggler.desc=Wizards are guaranteed to offer a new trade every time you trade with them
item.ebwizardry\:charm_experience_tome.name=Tome of the Diligent item.ebwizardry\:charm_experience_tome.name=Tome of the Diligent
item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 40%% item.ebwizardry\:charm_experience_tome.desc=Increases the rate at which wands gain progression by 50%%
item.ebwizardry\:charm_auto_smelt.name=Metallurgist's Mark item.ebwizardry\:charm_auto_smelt.name=Metallurgist's Mark
item.ebwizardry\:charm_auto_smelt.desc=Pocket furnace triggers automatically when bound to a wand on your hotbar item.ebwizardry\:charm_auto_smelt.desc=Pocket furnace triggers automatically when bound to a wand on your hotbar
item.ebwizardry\:charm_lava_walking.name=Nether Ice Core item.ebwizardry\:charm_lava_walking.name=Nether Ice Core
@@ -719,14 +719,14 @@ spell.ebwizardry\:arc.desc=Fires a spark of lightning at the target.
spell.ebwizardry\:arcane_jammer.desc=Prevents the target from using magic for 15 seconds. spell.ebwizardry\:arcane_jammer.desc=Prevents the target from using magic for 15 seconds.
spell.ebwizardry\:arcane_lock.desc=Creates an impenetrable barrier of force around a container, protecting it from being opened or destroyed. The caster and their allies may still open it, however. spell.ebwizardry\:arcane_lock.desc=Creates an impenetrable barrier of force around a container, protecting it from being opened or destroyed. The caster and their allies may still open it, however.
spell.ebwizardry\:arrow_rain.desc="Archers, fire!" spell.ebwizardry\:arrow_rain.desc="Archers, fire!"
spell.ebwizardry\:banish.desc=Teleports the target against its will to a random locations within a certain range. spell.ebwizardry\:banish.desc=Teleports the target against its will to a random location within a certain range.
spell.ebwizardry\:black_hole.desc=Tear reality asunder. spell.ebwizardry\:black_hole.desc=Tear reality asunder.
spell.ebwizardry\:blink.desc=Teleports the caster over a short distance to where they are pointing. spell.ebwizardry\:blink.desc=Teleports the caster over a short distance to where they are pointing.
spell.ebwizardry\:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed. spell.ebwizardry\:blizzard.desc=Creates a zone of swirling icy wind which slows and continually damages anything trapped inside. The caster is immune to the damage but is still slowed.
spell.ebwizardry\:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged. spell.ebwizardry\:bubble.desc=Fires a jet of bubbles which causes anything it hits to float upwards helplessly. The target will fall after a certain time or if it is damaged.
spell.ebwizardry\:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice. spell.ebwizardry\:chain_lightning.desc=Fires a spark of lightning at the target, which then chains to additional targets up to twice.
spell.ebwizardry\:charge.desc=Causes the caster to charge rapidly in the direction they are looking, damaging and knocking back anything in their path. spell.ebwizardry\:charge.desc=Causes the caster to charge rapidly in the direction they are looking, damaging and knocking back anything in their path.
spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered locations. With this spell selected, sneak-right-click on a block to set the locations. Cast this spell normally to reveal the path. The path will fade after 90 seconds. spell.ebwizardry\:clairvoyance.desc=Reveals the path to a remembered location. With this spell selected, sneak-right-click on a block to set the location. Cast this spell normally to reveal the path. The path will fade after 90 seconds.
spell.ebwizardry\:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken. spell.ebwizardry\:cobwebs.desc=Creates cobwebs where you are pointing, which greatly hamper the movement of any creatures caught amongst them. The cobwebs will vanish after 20 seconds or if broken.
spell.ebwizardry\:combustion_rune.desc=Places a magical landmine on the ground where you are pointing, which explodes when stepped upon. spell.ebwizardry\:combustion_rune.desc=Places a magical landmine on the ground where you are pointing, which explodes when stepped upon.
spell.ebwizardry\:conjure_armour.desc=Creates spectral armor around the caster which offers protection equal to that of iron armor. The armor lasts for 60 seconds. The caster must have an empty armor slot. spell.ebwizardry\:conjure_armour.desc=Creates spectral armor around the caster which offers protection equal to that of iron armor. The armor lasts for 60 seconds. The caster must have an empty armor slot.
@@ -895,9 +895,9 @@ spell.ebwizardry\:transportation.undefined=You must remember the location of a s
spell.ebwizardry\:transportation.wrongdimension=No remembered stone circle in this dimension... spell.ebwizardry\:transportation.wrongdimension=No remembered stone circle in this dimension...
spell.ebwizardry\:clairvoyance.searching=Searching... spell.ebwizardry\:clairvoyance.searching=Searching...
spell.ebwizardry\:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point spell.ebwizardry\:clairvoyance.confirm=The path revealed upon casting %1$s will now lead back to this point
spell.ebwizardry\:clairvoyance.outofrange=Your remembered locations is too far away or inaccessible... spell.ebwizardry\:clairvoyance.outofrange=Your remembered location is too far away or inaccessible...
spell.ebwizardry\:clairvoyance.undefined=You must remember a locations first! spell.ebwizardry\:clairvoyance.undefined=You must remember a location first!
spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered locations is in another dimension... spell.ebwizardry\:clairvoyance.wrongdimension=Your remembered location is in another dimension...
spell.ebwizardry\:possession.insufficienthealth=You don't have enough health to possess %1$s! spell.ebwizardry\:possession.insufficienthealth=You don't have enough health to possess %1$s!
spell.ebwizardry\:possession.success=Press %s to stop possessing spell.ebwizardry\:possession.success=Press %s to stop possessing
spell.ebwizardry\:divination.nothing=Nothing happened. spell.ebwizardry\:divination.nothing=Nothing happened.
@@ -1003,6 +1003,16 @@ enchantment.ebwizardry\:magic_protection=Magic Protection
enchantment.ebwizardry\:frost_protection=Frost Protection enchantment.ebwizardry\:frost_protection=Frost Protection
enchantment.ebwizardry\:shock_protection=Shock Protection enchantment.ebwizardry\:shock_protection=Shock Protection
enchantment.ebwizardry.magic_sword.desc=Part of the Imbue Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.magic_bow.desc=Part of the Imbue Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.flaming_weapon.desc=Part of the Flaming Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.freezing_weapon.desc=Part of the Freezing Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.shocking_weapon.desc=Part of the Shocking Weapon spell; unobtainable in survival mode (the book won't work).
enchantment.ebwizardry.magic_protection.desc=Reduces damage from all magic.
enchantment.ebwizardry.frost_protection.desc=Reduces the effects of frost damage.
enchantment.ebwizardry.shock_protection.desc=Reduces the effects of shock damage.
key.categories.ebwizardry=Wizardry key.categories.ebwizardry=Wizardry
key.ebwizardry.next_spell=Next Spell key.ebwizardry.next_spell=Next Spell
@@ -1011,7 +1021,7 @@ key.ebwizardry.previous_spell=Previous Spell
death.attack.wizardry_magic=%1$s was killed by %2$s using magic death.attack.wizardry_magic=%1$s was killed by %2$s using magic
death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic
soundCategory.ebwizardry\:spells=Spells soundCategory.ebwizardry_spells=Spells
commands.ebwizardry\:cast.usage=/%1$s <spell> [player | x y z direction] [duration] [modifiers] commands.ebwizardry\:cast.usage=/%1$s <spell> [player | x y z direction] [duration] [modifiers]
commands.ebwizardry\:cast.success=Successfully cast %s commands.ebwizardry\:cast.success=Successfully cast %s
@@ -1107,6 +1117,8 @@ config.ebwizardry.creative_bypasses_arcane_lock.true=Anyone in creative mode
config.ebwizardry.creative_bypasses_arcane_lock.false=Only ops in creative mode config.ebwizardry.creative_bypasses_arcane_lock.false=Only ops in creative mode
config.ebwizardry.slow_time_affects_players=Slow Time Affects Players config.ebwizardry.slow_time_affects_players=Slow Time Affects Players
config.ebwizardry.slow_time_affects_players.tooltip=Whether players are slowed when another nearby player uses the slow time spell. If this is disabled, mobs and projectiles will still be affected but players will move at normal speed. config.ebwizardry.slow_time_affects_players.tooltip=Whether players are slowed when another nearby player uses the slow time spell. If this is disabled, mobs and projectiles will still be affected but players will move at normal speed.
config.ebwizardry.bonemeal_grows_crystal_flowers=Bonemeal Grows Crystal Flowers
config.ebwizardry.bonemeal_grows_crystal_flowers.tooltip=Whether using bonemeal on grass blocks has a chance to grow crystal flowers.
config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist
config.ebwizardry.mob_loot_table_whitelist.tooltip=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. config.ebwizardry.mob_loot_table_whitelist.tooltip=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.
config.ebwizardry.mob_loot_table_blacklist=Mob Loot Table Blacklist config.ebwizardry.mob_loot_table_blacklist=Mob Loot Table Blacklist
@@ -1154,27 +1166,29 @@ config.ebwizardry.fast_worldgen.tooltip=Controls which algorithm wizardry uses f
config.ebwizardry.fast_worldgen.true=Fast config.ebwizardry.fast_worldgen.true=Fast
config.ebwizardry.fast_worldgen.false=Fancy config.ebwizardry.fast_worldgen.false=Fancy
config.ebwizardry.tower_dimensions=Tower Dimensions config.ebwizardry.tower_dimensions=Tower Dimensions
config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate. config.ebwizardry.tower_dimensions.tooltip=List of ids of dimensions in which wizard towers will generate. Remove all dimensions to disable wizard towers completely.
config.ebwizardry.tower_rarity=Tower Rarity config.ebwizardry.tower_rarity=Tower Rarity
config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer. config.ebwizardry.tower_rarity.tooltip=Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.
config.ebwizardry.evil_wizard_chance=Evil Wizard Chance config.ebwizardry.evil_wizard_chance=Evil Wizard Chance
config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard. config.ebwizardry.evil_wizard_chance.tooltip=The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.
config.ebwizardry.tower_files=Tower Structure Files config.ebwizardry.tower_files=Tower Structure Files
config.ebwizardry.tower_files.tooltip=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. config.ebwizardry.tower_files.tooltip=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.
config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files config.ebwizardry.tower_with_chest_files=Tower With Chest Structure Files
config.ebwizardry.tower_with_chest_files.tooltip=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. config.ebwizardry.tower_with_chest_files.tooltip=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.
config.ebwizardry.obelisk_dimensions=Obelisk Dimensions config.ebwizardry.obelisk_dimensions=Obelisk Dimensions
config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate. config.ebwizardry.obelisk_dimensions.tooltip=List of ids of dimensions in which obelisks will generate. Remove all dimensions to disable obelisks completely.
config.ebwizardry.obelisk_rarity=Obelisk Rarity config.ebwizardry.obelisk_rarity=Obelisk Rarity
config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer. config.ebwizardry.obelisk_rarity.tooltip=Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.
config.ebwizardry.obelisk_files=Obelisk Structure Files config.ebwizardry.obelisk_files=Obelisk Structure Files
config.ebwizardry.obelisk_files.tooltip=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. config.ebwizardry.obelisk_files.tooltip=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.
config.ebwizardry.shrine_dimensions=Shrine Dimensions config.ebwizardry.shrine_dimensions=Shrine Dimensions
config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate. config.ebwizardry.shrine_dimensions.tooltip=List of ids of dimensions in which shrines will generate. Remove all dimensions to disable shrines completely.
config.ebwizardry.shrine_rarity=Shrine Rarity config.ebwizardry.shrine_rarity=Shrine Rarity
config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer. config.ebwizardry.shrine_rarity.tooltip=Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.
config.ebwizardry.shrine_files=Shrine Structure Files config.ebwizardry.shrine_files=Shrine Structure Files
config.ebwizardry.shrine_files.tooltip=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. config.ebwizardry.shrine_files.tooltip=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.
config.ebwizardry.tree_blocks=Tree Blocks
config.ebwizardry.tree_blocks.tooltip=List of registry names of blocks which can be overwritten by wizardry's structure generators, affecting both fast and fancy structure generation. Most tree blocks and other foliage should work automatically, but those that don't can be added manually here. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. dynamictrees:oakbranch).
config.ebwizardry.ore_dimensions=Ore Dimensions config.ebwizardry.ore_dimensions=Ore Dimensions
config.ebwizardry.ore_dimensions.tooltip=List of ids of dimensions in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play! config.ebwizardry.ore_dimensions.tooltip=List of ids of dimensions in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!
config.ebwizardry.flower_dimensions=Flower Dimensions config.ebwizardry.flower_dimensions=Flower Dimensions
@@ -1275,4 +1289,9 @@ integration.antiqueatlas.marker.ebwizardry\:wizard_tower=Wizard Tower
integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk integration.antiqueatlas.marker.ebwizardry\:obelisk=Obelisk
integration.antiqueatlas.marker.ebwizardry\:shrine=Shrine integration.antiqueatlas.marker.ebwizardry\:shrine=Shrine
spell.ebwizardry\:magic_missile_festive=Magic Mistletoe
spell.ebwizardry\:summon_snow_golem_festive=Summon Frosty The Snowman
spell.ebwizardry\:invigorating_presence_festive=Invigorating Presents
spell.ebwizardry\:empowering_presence_festive=Empowering Presents
wizard.debug=%1$s, %2$s, %3$s wizard.debug=%1$s, %2$s, %3$s
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,760 @@
tile.ebwizardry:arcane_workbench.name=Mesa de Trabalho Arcana
tile.ebwizardry:crystal_ore.name=Minério de Cristal
tile.ebwizardry:petrified_stone.name=Pedra Petrificada
tile.ebwizardry:ice_statue.name=Estátua de Gelo
tile.ebwizardry:crystal_flower.name=Flor de Cristal
tile.ebwizardry:snare.name=Armadilha
tile.ebwizardry:transportation_stone.name=Pedra de Transportação
tile.ebwizardry:spectral_block.name=Bloco Espectral
tile.ebwizardry:crystal_block.name=Bloco de Cristal
item.ebwizardry:magic_crystal.name=Cristal Mágico
item.ebwizardry:magic_wand.name=Varinha Mágica
item.ebwizardry:apprentice_wand.name=Varinha Aprendiz
item.ebwizardry:advanced_wand.name=Varinha Avançada
item.ebwizardry:master_wand.name=Varinha Mestra
item.ebwizardry:spell_book.name=Livro de Feitiços
item.ebwizardry:arcane_tome.name=Tomo de Arcana
item.ebwizardry:arcane_tome.desc1=Atualiza qualquer %1$s
item.ebwizardry:arcane_tome.desc2=varinha em %1$s nível
item.ebwizardry:wizard_handbook.name=O Manual do Mago
item.ebwizardry:wizard_handbook.desc=por %1$s
item.ebwizardry:wand.buff=+%1$s %2$s potência
item.ebwizardry:wand.spell=Feitiço Atual: %1$s
item.ebwizardry:wand.mana=Mana: %1$s/%2$s
item.ebwizardry:wand.addally=%1$s foi adicionado à sua lista de aliados
item.ebwizardry:wand.removeally=%1$s foi removido da sua lista de aliados
item.ebwizardry:basic_fire_wand.name=Varinha de Brasas
item.ebwizardry:basic_ice_wand.name=Varinha de Geada
item.ebwizardry:basic_lightning_wand.name=Varinha de Faíscas
item.ebwizardry:basic_necromancy_wand.name=Varinha de Sombras
item.ebwizardry:basic_earth_wand.name=Varinha da Floresta
item.ebwizardry:basic_sorcery_wand.name=Varinha de Mistério
item.ebwizardry:basic_healing_wand.name=Varinha de Cura
item.ebwizardry:apprentice_fire_wand.name=Varinha do Piromante Aprendiz
item.ebwizardry:apprentice_ice_wand.name=Varinha do Mago de Gelo Aprendiz
item.ebwizardry:apprentice_lightning_wand.name=Varinha do Mago da Tempestade Aprendiz
item.ebwizardry:apprentice_necromancy_wand.name=Varinha do Necromante Aprendiz
item.ebwizardry:apprentice_earth_wand.name=Varinha do Mago de Terra Aprendiz
item.ebwizardry:apprentice_sorcery_wand.name=Varinha do Feiticeiro Aprendiz
item.ebwizardry:apprentice_healing_wand.name=Varinha do Curandeiro Aprendiz
item.ebwizardry:advanced_fire_wand.name=Varinha do Piromante
item.ebwizardry:advanced_ice_wand.name=Varinha do Mago de Gelo
item.ebwizardry:advanced_lightning_wand.name=Varinha do Mago da Tempestade
item.ebwizardry:advanced_necromancy_wand.name=Varinha do Necromante
item.ebwizardry:advanced_earth_wand.name=Varinha do Mago de Terra
item.ebwizardry:advanced_sorcery_wand.name=Varinha do Feiticeiro
item.ebwizardry:advanced_healing_wand.name=Varinha do Curandeiro
item.ebwizardry:master_fire_wand.name=Varinha do Piromante Mestre
item.ebwizardry:master_ice_wand.name=Varinha do Mago de Gelo Mestre
item.ebwizardry:master_lightning_wand.name=Varinha do Mago da Tempestade Mestre
item.ebwizardry:master_necromancy_wand.name=Varinha do Necromante Mestre
item.ebwizardry:master_earth_wand.name=Varinha do Mago de Terra Mestre
item.ebwizardry:master_sorcery_wand.name=Varinha do Feiticeiro Mestre
item.ebwizardry:master_healing_wand.name=Varinha do Curandeiro Mestre
item.ebwizardry:spectral_sword.name=Espada Espectral
item.ebwizardry:spectral_pickaxe.name=Picareta Espectral
item.ebwizardry:spectral_bow.name=Arco Espectral
item.ebwizardry:mana_flask.name=Frasco de Mana
item.ebwizardry:storage_upgrade.name=Atualização de Armazenamento para Varinha
item.ebwizardry:siphon_upgrade.name=Atualização de Sifão para Varinha
item.ebwizardry:condenser_upgrade.name=Atualização de Condensador para Varinha
item.ebwizardry:range_upgrade.name=Atualização de Alcance para Varinha
item.ebwizardry:duration_upgrade.name=Atualização de Duração para Varinha
item.ebwizardry:cooldown_upgrade.name=Atualização de Tempo de Recarga para Varinha
item.ebwizardry:blast_upgrade.name=Atualização de Explosão para Varinha
item.ebwizardry:attunement_upgrade.name=Atualização de Sintonização para Varinha
item.ebwizardry:flaming_axe.name=Machado Flamejante
item.ebwizardry:frost_axe.name=Machado Gélido
item.ebwizardry:firebomb.name=Bomba Incendiária
item.ebwizardry:poison_bomb.name=Bomba de Veneno
item.ebwizardry:smoke_bomb.name=Bomba de Fumaça
item.ebwizardry:blank_scroll.name=Pergaminho em Branco
item.ebwizardry:scroll.name=Pergaminho de %1$s
item.ebwizardry:scroll.undiscovered.name=Pergaminho "%1$s"
item.ebwizardry:identification_scroll.name=Pergaminho de Identificação
item.ebwizardry:identification_scroll.desc1=%1$sIdentifica um desconhecido
item.ebwizardry:identification_scroll.desc2=%1$slivro de feitiços ou pergaminhos
item.ebwizardry:identification_scroll.nothing_to_identify=Nada para identificar!
item.ebwizardry:armour_upgrade.name=Selo Arcano de Proteção
item.ebwizardry:armour_upgrade.desc1=%1$sAtualiza qualquer armadura de mago
item.ebwizardry:armour_upgrade.desc2=%1$spara fazer isto %2$slendário
item.ebwizardry:magic_silk.name=Seda Mágica
item.ebwizardry:wizard_armour.legendary=Lendário
item.ebwizardry:wizard_armour.buff=-%1$s %2$s custo
item.ebwizardry:wizard_armour.mana=Mana: %1$s/%2$s
item.ebwizardry:wizard_hat.name=Chapéu de Mago
item.ebwizardry:wizard_robe.name=Túnica de Mago
item.ebwizardry:wizard_leggings.name=Calças de Mago
item.ebwizardry:wizard_boots.name=Botas de Mago
item.ebwizardry:wizard_hat_fire.name=Chapéu de Piromante
item.ebwizardry:wizard_robe_fire.name=Túnica de Piromante
item.ebwizardry:wizard_leggings_fire.name=Calças de Piromante
item.ebwizardry:wizard_boots_fire.name=Botas de Piromante
item.ebwizardry:wizard_hat_ice.name=Chapéu de Mago de Gelo
item.ebwizardry:wizard_robe_ice.name=Túnica de Mago de Gelo
item.ebwizardry:wizard_leggings_ice.name=Calças de Mago de Gelo
item.ebwizardry:wizard_boots_ice.name=Botas de Mago de Gelo
item.ebwizardry:wizard_hat_lightning.name=Chapéu de Mago da Tempestade
item.ebwizardry:wizard_robe_lightning.name=Túnica de Mago da Tempestade
item.ebwizardry:wizard_leggings_lightning.name=Calças de Mago da Tempestade
item.ebwizardry:wizard_boots_lightning.name=Botas de Mago da Tempestade
item.ebwizardry:wizard_hat_necromancy.name=Chapéu de Necromante
item.ebwizardry:wizard_robe_necromancy.name=Túnica de Necromante
item.ebwizardry:wizard_leggings_necromancy.name=Calças de Necromante
item.ebwizardry:wizard_boots_necromancy.name=Botas de Necromante
item.ebwizardry:wizard_hat_earth.name=Chapéu de Mago de Terra
item.ebwizardry:wizard_robe_earth.name=Túnica de Mago de Terra
item.ebwizardry:wizard_leggings_earth.name=Calças de Mago de Terra
item.ebwizardry:wizard_boots_earth.name=Botas de Mago de Terra
item.ebwizardry:wizard_hat_sorcery.name=Chapéu de Feiticeiro
item.ebwizardry:wizard_robe_sorcery.name=Túnica de Feiticeiro
item.ebwizardry:wizard_leggings_sorcery.name=Calças de Feiticeiro
item.ebwizardry:wizard_boots_sorcery.name=Botas de Feiticeiro
item.ebwizardry:wizard_hat_healing.name=Chapéu de Curandeiro
item.ebwizardry:wizard_robe_healing.name=Túnica de Curandeiro
item.ebwizardry:wizard_leggings_healing.name=Calças de Curandeiro
item.ebwizardry:wizard_boots_healing.name=Botas de Curandeiro
item.ebwizardry:spawn_wizard.name=Gerar Mago
item.ebwizardry:spawn_evil_wizard.name=Gerar Mago Malvado
item.ebwizardry:spectral_helmet.name=Capacete Espectral
item.ebwizardry:spectral_chestplate.name=Peitoral Espectral
item.ebwizardry:spectral_leggings.name=Calças Espectrais
item.ebwizardry:spectral_boots.name=Botas Espectrais
entity.ebwizardry:summonedcreature.nameplate=%2$s de %1$s
entity.ebwizardry:summonedcreature.nameplate_fallback=%1$s de alguém
entity.ebwizardry:zombie_minion.name=Zumbi
entity.ebwizardry:skeleton_minion.name=Esqueleto
entity.ebwizardry:spider_minion.name=Aranha
entity.ebwizardry:blaze_minion.name=Blaze
entity.ebwizardry:wither_skeleton_minion.name=Esqueleto Wither
entity.ebwizardry:ice_wraith.name=Espectro de Gelo
entity.ebwizardry:lightning_wraith.name=Espectro de Relâmpago
entity.ebwizardry:shadow_wraith.name=Espectro de Sombra
entity.ebwizardry:spirit_wolf.name=Lobo Espiritual
entity.ebwizardry:spirit_horse.name=Cavalo Espiritual
entity.ebwizardry:ice_giant.name=Gigante de Gelo
entity.ebwizardry:phoenix.name=Fênix
entity.ebwizardry:wizard.name=Mago
entity.ebwizardry:magic_slime.name=Slime Mágico
entity.ebwizardry:silverfish_minion.name=Traça
entity.ebwizardry:storm_elemental.name=Elemental da Tempestade
entity.ebwizardry:evil_wizard.name=Mago Malvado
entity.ebwizardry:decoy.name=Chamariz
entity.ebwizardry:magic_missile.name=Magia
entity.ebwizardry:arc.name=Magia
entity.ebwizardry:spark_bomb.name=Magia
entity.ebwizardry:ice_shard.name=Magia
entity.ebwizardry:firebomb.name=Magia
entity.ebwizardry:poison_bomb.name=Magia
entity.ebwizardry:force_orb.name=Magia
entity.ebwizardry:spark.name=Magia
entity.ebwizardry:darkness_orb.name=Magia
entity.ebwizardry:fire_sigil.name=Magia
entity.ebwizardry:frost_sigil.name=Magia
entity.ebwizardry:lightning_sigil.name=Magia
entity.ebwizardry:lightning_arrow.name=Magia
entity.ebwizardry:firebolt.name=Magia
entity.ebwizardry:ice_charge.name=Magia
entity.ebwizardry:force_arrow.name=Magia
entity.ebwizardry:dart.name=Magia
entity.ebwizardry:lightning_disc.name=Magia
entity.ebwizardry:thunderbolt.name=Magia
entity.ebwizardry:decay.name=Magia
entity.ebwizardry:ice_lance.name=Magia
entity.ebwizardry:smoke_bomb.name=Magia
entity.ebwizardry:ice_spike.name=Magia
entity.ebwizardry:black_hole.name=Buraco Negro
entity.ebwizardry:shield.name=Escudo
entity.ebwizardry:meteor.name=Meteoro
entity.ebwizardry:blizzard.name=Nevasca
entity.ebwizardry:bubble.name=Bolha
entity.ebwizardry:tornado.name=Tornado
entity.ebwizardry:lightning_hammer.name=Martelo Relâmpago
entity.ebwizardry:arrow_rain.name=Chuva de Flechas
entity.ebwizardry:healing_aura.name=Aura Curativa
entity.ebwizardry:forcefield.name=Campo de Força
entity.ebwizardry:ring_of_fire.name=Anel de Fogo
entity.ebwizardry:earthquake.name=Terremoto
entity.ebwizardry:falling_grass.name=Queda de Grama
entity.ebwizardry:hailstorm.name=Chuva de Granizo
entity.ebwizardry:lightning_pulse.name=Pulso de Relâmpago
item_group.ebwizardry=Wizardry
item_group.wizardryspells=Feitiços
advancement.wizardry:root=Wizardry
advancement.wizardry:root.desc=A jornada de um mago para dominar o arcano
advancement.wizardry:crystal=Um Cristal Curioso...
advancement.wizardry:crystal.desc=Minerar um cristal mágico
advancement.wizardry:arcane_initiate=Iniciado Arcano
advancement.wizardry:arcane_initiate.desc=Craftar uma varinha mágica com uma pepita de ouro, um graveto e um cristal mágico
advancement.wizardry:apprentice=Aprendiz de Mago
advancement.wizardry:apprentice.desc=Usar um tomo de arcana para atualizar sua varinha
advancement.wizardry:master=Mestre Arcano
advancement.wizardry:master.desc=Obtenha uma varinha mestre
advancement.wizardry:all_spells=Mago de Todos os Comércios
advancement.wizardry:all_spells.desc=Lance todos os feitiços do jogo
advancement.wizardry:wizard_trade=Negociação Mágica
advancement.wizardry:wizard_trade.desc=Comprar um item de um mago
advancement.wizardry:buy_master_spell=Conhecimento é Poder
advancement.wizardry:buy_master_spell.desc=Compre um feitiço mestre de um mago
advancement.wizardry:freeze_blaze=Não Tão Quente Agora
advancement.wizardry:freeze_blaze.desc=Congelar um sólido blaze
advancement.wizardry:charge_creeper=Isto Vai Explodir
advancement.wizardry:charge_creeper.desc='Acidentalmente' energizar um creeper
advancement.wizardry:frankenstein=Frankenstein
advancement.wizardry:frankenstein.desc=Transformar um porco em um Homem-porco Zumbi usando o feitiço lightning bolt
advancement.wizardry:special_upgrade=Consertando Arcano
advancement.wizardry:special_upgrade.desc=Aplique uma atualização especial para uma varinha
advancement.wizardry:craft_flask=Isto é Magia, Engarrafada!
advancement.wizardry:craft_flask.desc=Craftar um frasco de mana
advancement.wizardry:elemental=Elemental
advancement.wizardry:elemental.desc=Obtenha uma varinha elemental
advancement.wizardry:armour_set=Now Você É um Mago Adequado
advancement.wizardry:armour_set.desc=Craftar e equipar um conjunto completo de armadura de mago
advancement.wizardry:legendary=Lendário
advancement.wizardry:legendary.desc=Obtenha uma peça de armadura lendária de mago
advancement.wizardry:self_destruct=Que Saiu Pela Culatra
advancement.wizardry:self_destruct.desc=Seja morto por sua própria magia
advancement.wizardry:pig_tornado=Não de Novo...
advancement.wizardry:pig_tornado.desc=Monte num porco em um tornado
advancement.wizardry:jam_wizard=Sessão de Jamming
advancement.wizardry:jam_wizard.desc=Usar o feitiço bloqueador arcano num mago
advancement.wizardry:slime_skeleton=Situação Complicada
advancement.wizardry:slime_skeleton.desc=Engolir um esqueleto num slime
advancement.wizardry:anger_wizard=Você Vai Se Arrepender
advancement.wizardry:anger_wizard.desc=Deixe um mago irritado
advancement.wizardry:defeat_evil_wizard=Justiça
advancement.wizardry:defeat_evil_wizard.desc=Derrote um mago malvado
advancement.wizardry:max_out_wand=Totalmente Equipado
advancement.wizardry:max_out_wand.desc=Aplique o número máximo de atualizações a uma varinha mestra
advancement.wizardry:element_master=Maestria Elemental
advancement.wizardry:element_master.desc=Lançar todos os feitiços de qualquer elemento
advancement.wizardry:identify_spell=Apreciação Arcana
advancement.wizardry:identify_spell.desc=Use um pergaminho de identificação para identificar um livro de feitiços ou pergaminho
tile.ebwizardry:transportation_stone.confirm=A partir de agora você retornará a este lugar quando lançar %1$s
tile.ebwizardry:transportation_stone.invalid=Você deve fazer um círculo com 8 pedras de transportação primeiro!
container.ebwizardry:arcane_workbench=Mesa de Trabalho Arcana
container.ebwizardry:arcane_workbench.apply=Aplicar
container.ebwizardry:arcane_workbench.mana=Mana:
container.ebwizardry:arcane_workbench.upgrades=Atualizações Aplicadas:
tier.basic=Novato
tier.apprentice=Aprendiz
tier.advanced=Avançado
tier.master=Mestre
element.simple=Nenhum
element.fire=Fogo
element.ice=Gelo
element.lightning=Relâmpago
element.necromancy=Necromancia
element.earth=Terra
element.sorcery=Feitiçaria
element.healing=Cura
element.simple.wizard=Mago
element.fire.wizard=Piromante
element.ice.wizard=Mago de Gelo
element.lightning.wizard=Mago da Tempestade
element.necromancy.wizard=Necromante
element.earth.wizard=Mago da Terra
element.sorcery.wizard=Feiticeiro
element.healing.wizard=Curandeiro
spelltype.attack=Ataque
spelltype.defence=Defesa
spelltype.utility=Utilidade
spelltype.minion=Minion
spell.disabled=%1$s foi desativado na configuração
spell.resist=%1$s resistiu %2$s
spell.discover=Descobriu o feitiço %1$s!
spell.ebwizardry:agility=Agilidade
spell.ebwizardry:arc=Arco
spell.ebwizardry:arcane_jammer=Bloqueador Arcano
spell.ebwizardry:arrow_rain=Chuva de Flechas
spell.ebwizardry:banish=Banir
spell.ebwizardry:black_hole=Buraco Negro
spell.ebwizardry:blink=Lampejar
spell.ebwizardry:blizzard=Nevasca
spell.ebwizardry:bubble=Bolha
spell.ebwizardry:chain_lightning=Cadeia de Raios
spell.ebwizardry:clairvoyance=Clarividência
spell.ebwizardry:cobwebs=Teias de Aranha
spell.ebwizardry:conjure_armour=Conjurar Armadura
spell.ebwizardry:conjure_bow=Conjurar Arco
spell.ebwizardry:conjure_pickaxe=Conjurar Picareta
spell.ebwizardry:conjure_sword=Conjurar Espada
spell.ebwizardry:cure_effects=Efeitos de Cura
spell.ebwizardry:curse_of_soulbinding=Maldição de Liga-Alma
spell.ebwizardry:darkness_orb=Orbe da Escuridão
spell.ebwizardry:darkvision=Visão-Sombria
spell.ebwizardry:dart=Dardo
spell.ebwizardry:decay=Apodrecimento
spell.ebwizardry:decoy=Chamariz
spell.ebwizardry:detonate=Detonar
spell.ebwizardry:diamondflesh=Carne de Diamante
spell.ebwizardry:earthquake=Terremoto
spell.ebwizardry:entrapment=Aprisionamento
spell.ebwizardry:fireball=Bola de Fogo
spell.ebwizardry:firebolt=Disparo de Fogo
spell.ebwizardry:firebomb=Bomba de Fogo
spell.ebwizardry:fire_resistance=Resistência ao Fogo
spell.ebwizardry:fire_sigil=Sigilo de Fogo
spell.ebwizardry:fireskin=Pele de Fogo
spell.ebwizardry:firestorm=Tempestade de Fogo
spell.ebwizardry:flame_ray=Raio de Fogo
spell.ebwizardry:flaming_axe=Machado Flamejante
spell.ebwizardry:flaming_weapon=Arma Flamejante
spell.ebwizardry:flight=Vôo
spell.ebwizardry:font_of_mana=Fonte de Mana
spell.ebwizardry:font_of_vitality=Fonte de Vitalidade
spell.ebwizardry:force_arrow=Flecha de Força
spell.ebwizardry:forcefield=Campo de Força
spell.ebwizardry:force_orb=Orbe de Força
spell.ebwizardry:forests_curse=Maldição da Floresta
spell.ebwizardry:freeze=Congelar
spell.ebwizardry:freezing_weapon=Arma Congelante
spell.ebwizardry:frost_axe=Machado da Geada
spell.ebwizardry:frost_ray=Raio de Geada
spell.ebwizardry:frost_sigil=Sigilo de Geada
spell.ebwizardry:glide=Planar
spell.ebwizardry:greater_fireball=Bola de Fogo Maior
spell.ebwizardry:greater_heal=Cura Maior
spell.ebwizardry:group_heal=Cura Grupo
spell.ebwizardry:growth_aura=Aura de Crescimento
spell.ebwizardry:hailstorm=Chuva de Granizo
spell.ebwizardry:heal=Cura
spell.ebwizardry:heal_ally=Curar Aliados
spell.ebwizardry:healing_aura=Aura Curativa
spell.ebwizardry:homing_spark=Faísca Teleguiada
spell.ebwizardry:ice_age=Era do Gelo
spell.ebwizardry:ice_charge=Carga de Gelo
spell.ebwizardry:ice_lance=Lança de Gelo
spell.ebwizardry:ice_shard=Fragmento de Gelo
spell.ebwizardry:ice_shroud=Mortalha de Gelo
spell.ebwizardry:ice_spikes=Espinhos de Gelo
spell.ebwizardry:ice_statue=Estátua de Gelo
spell.ebwizardry:ignite=Incendiar
spell.ebwizardry:imbue_weapon=Imbuir Arma
spell.ebwizardry:intimidate=Intimidar
spell.ebwizardry:invigorating_presence=Presença Revigorante
spell.ebwizardry:invisibility=Invisibilidade
spell.ebwizardry:invoke_weather=Invocar Clima
spell.ebwizardry:ironflesh=Carne de Ferro
spell.ebwizardry:leap=Pulo
spell.ebwizardry:levitation=Levitação
spell.ebwizardry:life_drain=Drenar Vida
spell.ebwizardry:light=Luz
spell.ebwizardry:lightning_arrow=Flecha Relâmpago
spell.ebwizardry:lightning_bolt=Disparo de Relâmpago
spell.ebwizardry:lightning_disc=Disco de Relâmpago
spell.ebwizardry:lightning_hammer=Martelo Relâmpago
spell.ebwizardry:lightning_pulse=Pulso Relâmpago
spell.ebwizardry:lightning_ray=Raio de Relâmpago
spell.ebwizardry:lightning_sigil=Sigilo de Relâmpago
spell.ebwizardry:lightning_web=Teia Relâmpago
spell.ebwizardry:magic_missile=Míssil Mágico
spell.ebwizardry:metamorphosis=Metamorfose
spell.ebwizardry:meteor=Meteoro
spell.ebwizardry:mind_control=Controle Mental
spell.ebwizardry:mind_trick=Truque Mental
spell.ebwizardry:none=[Espaço Vazio]
spell.ebwizardry:oakflesh=Carne de Carvalho
spell.ebwizardry:petrify=Petrificar
spell.ebwizardry:phase_step=Etapa de Fase
spell.ebwizardry:plague_of_darkness=Praga da Escuridão
spell.ebwizardry:pocket_furnace=Fornalha de Bolso
spell.ebwizardry:pocket_workbench=Mesa de Trabalho de Bolso
spell.ebwizardry:poison=Veneno
spell.ebwizardry:poison_bomb=Bomba de Veneno
spell.ebwizardry:replenish_hunger=Reabastecer a Fome
spell.ebwizardry:ring_of_fire=Anel de Fogo
spell.ebwizardry:shadow_ward=Guarda das Sombras
spell.ebwizardry:shield=Escudo
spell.ebwizardry:shockwave=Onda de Choque
spell.ebwizardry:silverfish_swarm=Enxame de Traças
spell.ebwizardry:sixth_sense=Sexto Sentido
spell.ebwizardry:slime=Slime
spell.ebwizardry:smoke_bomb=Bomba de Fumaça
spell.ebwizardry:snare=Armadilha
spell.ebwizardry:snowball=Bola de Neve
spell.ebwizardry:spark_bomb=Bomba de Faíscas
spell.ebwizardry:spectral_pathway=Caminho Espectral
spell.ebwizardry:spider_swarm=Enxame de Aranhas
spell.ebwizardry:static_aura=Aura Estática
spell.ebwizardry:summon_blaze=Invocar Blaze
spell.ebwizardry:summon_ice_giant=Invocar Gigante de Ego
spell.ebwizardry:summon_ice_wraith=Invocar Espectro de Gelo
spell.ebwizardry:summon_iron_golem=Invocar Golem de Ferro
spell.ebwizardry:summon_lightning_wraith=Invocar Espectro de Relâmpago
spell.ebwizardry:summon_phoenix=Invocar Fênix
spell.ebwizardry:summon_shadow_wraith=Espectro de Sombra
spell.ebwizardry:summon_skeleton=Invocar Esqueleto
spell.ebwizardry:summon_skeleton_legion=Invocar Legião de Esqueletos
spell.ebwizardry:summon_snow_golem=Invocar Golem de Neve
spell.ebwizardry:summon_spirit_horse=Invocar Cavalo Espiritual
spell.ebwizardry:summon_spirit_wolf=Invocar Lobo Espiritual
spell.ebwizardry:summon_storm_elemental=Invocar Elemental da Tempestade
spell.ebwizardry:summon_wither_skeleton=Invocar Esqueleto Wither
spell.ebwizardry:summon_zombie=Invocar Zumbi
spell.ebwizardry:telekinesis=Telequinesia
spell.ebwizardry:thunderbolt=Disparo de Trovão
spell.ebwizardry:thunderstorm=Tempestade de Trovões
spell.ebwizardry:tornado=Tornado
spell.ebwizardry:transience=Transitoriedade
spell.ebwizardry:transportation=Transportação
spell.ebwizardry:vanishing_box=Caixa Desaparecente
spell.ebwizardry:wall_of_frost=Parede de Geada
spell.ebwizardry:water_breathing=Respiração Aquática
spell.ebwizardry:whirlwind=Redemoinho
spell.ebwizardry:wither=Wither
spell.ebwizardry:wither_skull=Crânio de Wither
spell.ebwizardry:agility.desc=Garante ao mago velocidade de movimento mais rápido e um salto mais alto por 30 segundos.
spell.ebwizardry:arc.desc=Dispara uma faísca de raio no alvo.
spell.ebwizardry:arcane_jammer.desc=Não permite que o alvo use magia nos próximos 15 segundos.
spell.ebwizardry:arrow_rain.desc=Arqueiros, fogo!
spell.ebwizardry:banish.desc=Teletransporta o alvo contra sua vontade a uma localização aleatória a uma certa distância.
spell.ebwizardry:black_hole.desc=Rasga a realidade em pedaços.
spell.ebwizardry:blink.desc=Teleporta o mago a uma curta distância para onde ele está apontando.
spell.ebwizardry:blizzard.desc=Cria uma zona de vento gelado que retarda e continuamente danifica qualquer coisa presa no interior. O conjurador é imune ao dano, mas ainda é retardado.
spell.ebwizardry:bubble.desc=Dispara um jato de bolhas que faz com que qualquer coisa que ele acerte flutue para cima, impotente. O alvo cairá após um certo tempo ou se for danificado.
spell.ebwizardry:chain_lightning.desc=Dispara uma faísca de relâmpago no alvo, que então encadeia a alvos adicionais em até duas vezes.
spell.ebwizardry:clairvoyance.desc=Revela o caminho para um local lembrado. Com esta magia selecionada, clique com o botão direito agachado em um bloco para definir a localização. Lance esta magia normalmente para revelar o caminho. O caminho desaparecerá após 90 segundos.
spell.ebwizardry:cobwebs.desc=Cria teias de aranha onde você está apontando, o que dificulta muito o movimento de quaisquer criaturas pegas entre elas. As teias de aranha desaparecerão após 20 segundos ou se quebradas.
spell.ebwizardry:conjure_armour.desc=Cria Armadura Espectral ao redor do mago a qual oferece proteção similar a armadura de ferro. A armadura dura 60 segundos. O mago deve ter o espaço de armadura vazio.
spell.ebwizardry:conjure_bow.desc=Cria um arco espectral com setas ilimitadas que dura 30 segundos.
spell.ebwizardry:conjure_pickaxe.desc=Cria um arco espectral com setas ilimitadas que dura 30 segundos.
spell.ebwizardry:conjure_sword.desc=Cria uma espada espectral de força igual a uma espada de ferro que dura 30 segundos.
spell.ebwizardry:cure_effects.desc=Remove todos os efeitos de poção atualmente afetando o mago, bons ou ruins.
spell.ebwizardry:curse_of_soulbinding.desc=Faz com que a alma do alvo esteja inextricavelmente ligada a do conjurador, significando que todo dano causado ao conjurador também é causado à vítima. Dura até que a vítima ou o conjurador morra.
spell.ebwizardry:darkness_orb.desc=Dispara um raio lento de energia escura na direção que você está apontando, que decompõe o que quer que acerte.
spell.ebwizardry:darkvision.desc=Garante ao mago visão noturna por 45 segundos.
spell.ebwizardry:dart.desc=Dispara um dardo na direção em que você está apontando, o que danifica e enfraquece seu alvo.
spell.ebwizardry:decay.desc=Cria um caminho de apodrecimento na chão que infecta qualquer criatura que toque isto, causando dano prolongado ao longo do tempo e espalhando mais apodrecimento por onde anda.
spell.ebwizardry:decoy.desc=Cria um clone ilusório do conjurador que engana os monstros para atacá-lo. O chamariz desaparecerá após 30 segundos.
spell.ebwizardry:detonate.desc=Causa uma explosão onde você está apontando, danificando todas as criaturas próximas - incluindo o conjurador, se elas estiverem muito próximas.
spell.ebwizardry:diamondflesh.desc=Suas flechas não são páreo para mim!
spell.ebwizardry:earthquake.desc=Um verdadeiro mestre de magia de terra pode mover montanhas.
spell.ebwizardry:entrapment.desc=Aprisiona o alvo em uma esfera de escuridão que puxa-o indefeso para cima e causa dano continuamente nele.
spell.ebwizardry:fireball.desc=Lança uma bola de fogo na direção que você está apontando.
spell.ebwizardry:firebolt.desc=Atira um jato de fogo a uma curta distância em frente a você.
spell.ebwizardry:firebomb.desc=Lança uma bomba de fogo na direção que você está apontando que explode no impacto, colocando fogo nos alvos.
spell.ebwizardry:fire_resistance.desc=Garante ao conjurador resistência a fogo por 30 segundos.
spell.ebwizardry:fire_sigil.desc=Coloca uma armadilha mágica de fogo no chão que danifica e coloca fogo na criatura que aciona-la.
spell.ebwizardry:fireskin.desc=Envolve o conjurador em chamas por 30 segundos, fazendo qualquer coisa que o ataque pegar fogo.
spell.ebwizardry:firestorm.desc=Eu sou um dragão.
spell.ebwizardry:flame_ray.desc=Cria um fluxo de chamas na direção que você está apontando que coloca fogo nos alvos e continuamente danifica-os.
spell.ebwizardry:flaming_axe.desc=Cria um machado flamejante que coloca fogo nos inimigos que são acertados. Dura por 30 segundos.
spell.ebwizardry:flaming_weapon.desc=Temporariamente imbue a primeira arma na barra de inventário do conjurador com o poder da chama, fazendo com que ele ateie fogo a suas vitimas. A magia desaparece após 45 segundos.
spell.ebwizardry:flight.desc=Suba como uma águia.
spell.ebwizardry:font_of_mana.desc="Fomos preenchidos com uma intensa energia mágica que parecia emanar do centro do..." - Extraído do diário de um mago esquecido; o resto da página foi queimada.
spell.ebwizardry:font_of_vitality.desc=Me sinto incrível.
spell.ebwizardry:force_arrow.desc=Atira uma flecha de força na direção que você está apontando.
spell.ebwizardry:forcefield.desc=Cria um campo de força ao redor do conjurador que repele criaturas e desvia projéteis.
spell.ebwizardry:force_orb.desc=Lança uma esfera de força que danifica e repele quaisquer criaturas no impacto.
spell.ebwizardry:forests_curse.desc=Como ousa entrar na minha floresta!
spell.ebwizardry:freeze.desc=Congela o alvo por 10 segundos. Também congelará a água e criar neve no chão.
spell.ebwizardry:freezing_weapon.desc=Temporariamente imbue a primeira arma na barra de inventário do conjurador com o poder da geada, causando com isso o congelar de suas vítimas. A magia desaparece após 45 segundos.
spell.ebwizardry:frost_axe.desc=Cria um machado congelante que congela os inimigos acertados por ele. Dura por 30 segundos.
spell.ebwizardry:frost_ray.desc=Cria um fluxo de geada na direção que você está apontando que retarda e continuamente danifica os alvos.
spell.ebwizardry:frost_sigil.desc=Coloca uma armadilha mágica de gelo no chão que causa dano e congela a criatura que aciona-la.
spell.ebwizardry:glide.desc=Permite ao conjurador a planar para baixo enquanto no ar e segurando o botão de usar item.
spell.ebwizardry:greater_fireball.desc=Lança uma grande bola de fogo na direção que você está apontando que explode no impacto.
spell.ebwizardry:greater_heal.desc=Cura o conjurador em 4 corações.
spell.ebwizardry:group_heal.desc=Cura o conjurador e todos os aliado próximos e criaturas invocadas em 3 corações.
spell.ebwizardry:growth_aura.desc=Cresce todos as plantações próximas ao conjurador. Também cresce grama alta e flores na grama.
spell.ebwizardry:hailstorm.desc=Foi durante o grande inverno da terceira era que os magos do gelo descobriram seu verdadeiro poder.
spell.ebwizardry:heal.desc=Cura o conjurador em 2 corações.
spell.ebwizardry:heal_ally.desc=Cura o alvo em 2 corações e meio.
spell.ebwizardry:healing_aura.desc=Cria uma zona de energia curativa que regenera a vida de qualquer aliado dentro dela. Qualquer morto-vivo dentro da aura curativa vai lentamente tomar dano.
spell.ebwizardry:homing_spark.desc=Cria uma faísca flutuante que se move em direção aos inimigos.
spell.ebwizardry:ice_age.desc=Você ficará congelado por uma eternidade!
spell.ebwizardry:ice_charge.desc=Lança uma carga de gelo que explode no impacto, congelando quaisquer criaturas próximas e liberando fragmentos em todas as direções.
spell.ebwizardry:ice_lance.desc=Dispara uma grande lança de gelo na direção em que você está apontando, que sobrepenetra os alvos, danificando-os e congelando-os no processo.
spell.ebwizardry:ice_shard.desc=Dispara um fragmento de gelo na direção em que você está apontando, que danifica e retarda os alvos quando atingidos.
spell.ebwizardry:ice_shroud.desc=Cria uma mortalha de gelo ao redor do conjurador por 30 segundos, fazendo qualquer coisa que o ataque ser congelado.
spell.ebwizardry:ice_spikes.desc=Faz pontas de gelo afiadas que sobem a partir do chão para onde você está apontando, espetando quaisquer criaturas pegas entre elas.
spell.ebwizardry:ice_statue.desc=Congela o alvo num sólido por 20 segundo ou até que seja quebrado. O alvo não pode se mover ou fazer qualquer coisa enquanto congelado, mas também é invulnerável a todos os danos.
spell.ebwizardry:ignite.desc=Coloca fogo no alvo por 10 segundos. Também funciona como um sílex e aço.
spell.ebwizardry:imbue_weapon.desc=Temporiamente imbui a primeira arma na barra do inventário do conjurador com magia, tornando-a mais efetiva. A mágica desaparece após 45 segundos.
spell.ebwizardry:intimidate.desc=Emite um grunhido intimidante que faz com que as criaturas próximas fujam de medo. Criaturas atingidas pelo medo se recuperam depois de 30 segundos.
spell.ebwizardry:invigorating_presence.desc=Garante ao conjurador e todos os aliados próximos aumento de força por 45 segundos.
spell.ebwizardry:invisibility.desc=Faz o conjurador invisível por 30 segundos.
spell.ebwizardry:invoke_weather.desc=Muda o clima no mundo.
spell.ebwizardry:ironflesh.desc=Melhora significativamente a resistência a dano do conjurador por 30 segundos.
spell.ebwizardry:leap.desc=Faz com que o conjurador pule para cima vários blocos e avance ligeiramente.
spell.ebwizardry:levitation.desc=Eleva o conjurador para cima enquanto o botão de usar item é pressionado. Também irá negar o dano de queda se usado antes de atingir o solo.
spell.ebwizardry:life_drain.desc=Cria um fluxo de energia decompositora na direção que você está apontando que drena a vida do alvo e o utiliza para regenerar gradualmente sua vida.
spell.ebwizardry:light.desc=Cria um ponto de luz mágico que ilumina a área circundante. Dura por 30 segundos.
spell.ebwizardry:lightning_arrow.desc=Atira uma flecha de relâmpago na direção em que você está apontando.
spell.ebwizardry:lightning_bolt.desc=Faz um relâmpago para atingir onde você está apontando.
spell.ebwizardry:lightning_disc.desc=Envia um disco de relâmpago voando na direção que você está apontando, que busca alvos.
spell.ebwizardry:lightning_hammer.desc=Eu te farei pela ira dos céus!
spell.ebwizardry:lightning_pulse.desc=Carrega o chão ao redor do conjurador com relâmpagos, danificando e repelindo criaturas próximas.
spell.ebwizardry:lightning_ray.desc=Cria um fluxo de relâmpago na direção que você está apontando que continuamente danifica os alvos.
spell.ebwizardry:lightning_sigil.desc=Coloca uma armadilha mágica de relâmpago no chão que causa dano na criatura que aciona-la e encadeia relâmpagos nas outras criaturas próximas.
spell.ebwizardry:lightning_web.desc=Foco. Canalize a tempestade em sua mente através de sua varinha e libere sua fúria.
spell.ebwizardry:magic_missile.desc=Dispara um raio de energia mágica na direção que você está apontando.
spell.ebwizardry:metamorphosis.desc=Altera o alvo em outra forma. Só funciona em algumas criaturas.
spell.ebwizardry:meteor.desc=Alguns magos só querem ver o mundo queimando...
spell.ebwizardry:mind_control.desc=Tome o controle da mente do alvo por 30 segundos, fazendo com que ele mude de lado e lute pelo conjurador. Não vai funcionar em criaturas que tem muita força de vontade.
spell.ebwizardry:mind_trick.desc=Confunde e desorienta o alvo por 15 segundos, tornando-o incapaz de atacar efetivamente. O efeito será dissipado se o alvo receber dano.
spell.ebwizardry:none.desc=Para obter um livro de feitiços com o comando /give, usar metadados: /give [jogador] ebwizardry:spell_book 1 [feitiço id] (se você encontrou este livro em um baú, algum outro mod estragou tudo).
spell.ebwizardry:oakflesh.desc=Melhora a resistência a dano do conjurador por 30 segundos.
spell.ebwizardry:petrify.desc=Transforma o alvo em pedra até que seja quebrado, com a chance de ele se soltar quando estiver escuro. O alvo não pode se mover ou fazer nada enquanto petrificado, mas também é imune a todos os danos.
spell.ebwizardry:phase_step.desc=Teleporta o conjurador através de uma parede de um bloco de espessura na frente dele. Atualizações de alcance irão aumentar a espessura pela qual você pode atravessar por teletransporte.
spell.ebwizardry:plague_of_darkness.desc=A escuridão vai consumir todos eles...
spell.ebwizardry:pocket_furnace.desc=Funda até 5 itens que podem ser fundidos no inventário do conjurador. Itens na barra do inventário serão os primeiros a ser fundidos.
spell.ebwizardry:pocket_workbench.desc=Permite ao conjurador craftar como se estivessem em uma mesa de trabalho.
spell.ebwizardry:poison.desc=Dispare veneno na direção que você está apontando.
spell.ebwizardry:poison_bomb.desc=Lance uma bomba de veneno na direção que você está apontando que explode no impacto, envenenando criaturas próximas.
spell.ebwizardry:replenish_hunger.desc=Restabelece o nível de alimento do conjurador em 6 pontos de fome.
spell.ebwizardry:ring_of_fire.desc=Crie um anel de fogo ao redor do conjurador, danificando todos os inimigos próximos e colocando fogo neles.
spell.ebwizardry:shadow_ward.desc=Crie uma parede de escuridão na frente do conjurador que causa metade de todos os danos recebidos seren infligidos ao atacante.
spell.ebwizardry:shield.desc=Cria uma barreira protetora de força que bloqueia projéteis e magia. Também concede ao conjurador uma fraca resistência a efeitos.
spell.ebwizardry:shockwave.desc=Boom.
spell.ebwizardry:silverfish_swarm.desc=Ahhhh! Eles estão MULTIPLICANDO!
spell.ebwizardry:sixth_sense.desc=Permite ao conjurador sentir os locais de criaturas próximas, mesmo através de paredes, por 20 segundos.
spell.ebwizardry:slime.desc=Engolfa o alvo em um slime que retarda e danifica continuamente ele. O slime explode após 10 segundos.
spell.ebwizardry:smoke_bomb.desc=Lança uma bomba de fumaça na direção que você está apontando que explode no impacto, liberando fumaça e cegando criaturas próximas por pouco tempo.
spell.ebwizardry:snare.desc=Pôe uma armadilha no chão que danifica retarda brevemente a criatura que acionou-a.
spell.ebwizardry:snowball.desc=Lança uma bola de neve na direção que você está apontando.
spell.ebwizardry:spark_bomb.desc=Lança uma carga de choque na direção que você está apontando que libera faíscas no impacto em inimigos próximos.
spell.ebwizardry:spectral_pathway.desc=Cria uma ponte mágica indestrutível à sua frente que se estende por 15 blocos. A ponte desaparece após 60 segundos.
spell.ebwizardry:spider_swarm.desc=Invoca um enxame de aranhas venenosas para lutar por você. As aranhas irão desaparecer após 30 segundos ou se elas forem mortas.
spell.ebwizardry:static_aura.desc=Envolve o conjurador com relâmpago por 30 segundos, disparando uma faísca de relâmpago em qualquer coisa que o atinge.
spell.ebwizardry:summon_blaze.desc=Invoca um blaze para lutar por você. O blaze irá desaparecer após 30 segundos ou se for morto.
spell.ebwizardry:summon_ice_giant.desc=Esmague eles!
spell.ebwizardry:summon_ice_wraith.desc=Invoca um espectro do gelo para lutar por você. O espectro do gelo irá desaparecer após 30 segundos ou se for morto.
spell.ebwizardry:summon_iron_golem.desc=Autômato autônomo automatizado automático.
spell.ebwizardry:summon_lightning_wraith.desc=Invoca um espectro do relâmpago para lutar por você. O espectro do relâmpago irá desaparecer após 30 segundos ou se for morto.
spell.ebwizardry:summon_phoenix.desc=Vindo das cinzas...
spell.ebwizardry:summon_shadow_wraith.desc=Invoque um espectro da sombra para lutar por você.
spell.ebwizardry:summon_skeleton.desc=Invoca um esqueleto para lutar por você. O esqueleto irá desaparecer após 30 segundos ou se for morto.
spell.ebwizardry:summon_skeleton_legion.desc=Ascenda, exército morto-vivo!
spell.ebwizardry:summon_snow_golem.desc=Cria um golem de neve para lutar por você. Dura até que o golem de neve morra.
spell.ebwizardry:summon_spirit_horse.desc=Invoca um cavalo espiritual para você montar. O cavalo espiritual irá desaparecer um pouco depois de ser desmontado, ou você poderá dispensá-lo clicando com o botão direito e shift sobre elecom qualquer varinha.
spell.ebwizardry:summon_spirit_wolf.desc=Invoca um companheiro lobo espiritual para lutar por você. O lobo espiritual irá somente desaparecer se for morto, ou você pode dispensá-lo clicando com o botão direito e shift sobre ele com qualquer varinha.
spell.ebwizardry:summon_storm_elemental.desc="Elemental da Tempestade: Uma antiga manifestação dos elementos, dificilmente pode conter o poder bruto que se agita dentro dele." - Guia do Mago para Seres Arcanos, Volume I_i
spell.ebwizardry:summon_wither_skeleton.desc=Invoque um esqueleto wither para lutar por você. O esqueleto wither irá desaparecer após 30 segundos ou se for morto.
spell.ebwizardry:summon_zombie.desc=Invoca um zumbi para lutar por você. O zumbi irá desaparecer após 30 segundos ou se for morto.
spell.ebwizardry:telekinesis.desc=Move um item ou outro objeto pequeno para você, ou clique direito no bloco que você estiver olhando. Também pode ser usado para desarmar jogadores.
spell.ebwizardry:thunderbolt.desc=Atira um raio de trovão que derruba alvos.
spell.ebwizardry:thunderstorm.desc=Mwahahahahahaha!
spell.ebwizardry:tornado.desc=Libera um tornado na direção que você está apontando que atira violentamente qualquer coisa em seu caminho para o céu.
spell.ebwizardry:transience.desc=Faz o conjurador transitório por 20 segundos. O conjurador é imune a todos os danos enquanto transiente, mas não pode quebrar ou colocar blocos ou causar qualquer dano.
spell.ebwizardry:transportation.desc=Transporta o conjurador para um círculo de pedra lembrado. Para usar esse feitiço, faça um círculo de pedras de transportação, e com uma varinha clique com o botão direito.
spell.ebwizardry:vanishing_box.desc=Concede ao conjurador acessa o armazenamento do seu baú do ender.
spell.ebwizardry:wall_of_frost.desc=Inverno na ponta dos seus dedos.
spell.ebwizardry:water_breathing.desc=Permite que o conjurador respire debaixo d'água por 60 segundos.
spell.ebwizardry:whirlwind.desc=Faz o alvo ser soprado para cima e longe de você em velocidade.
spell.ebwizardry:wither.desc=Dispara um raio de escuridão que decompõe tudo o que toca.
spell.ebwizardry:wither_skull.desc=Lança um crânio de wither na direção que você está apontando.
spell.ebwizardry:invoke_weather.sun=A chuva começa a parar...
spell.ebwizardry:invoke_weather.rain=Os céus abem...
spell.ebwizardry:transportation.missing=Seu círculo de pedra lembrado está faltando ou está obstruído...
spell.ebwizardry:transportation.undefined=Você deve se lembrar da localização de um círculo de pedra primeiro!
spell.ebwizardry:transportation.wrongdimension=Seu círculo de pedra lembrado está em outro dimensão...
spell.ebwizardry:clairvoyance.searching=Procurando...
spell.ebwizardry:clairvoyance.confirm=O caminho revelado sobre conjuração %1$s irá agora levar de volta a este ponto
spell.ebwizardry:clairvoyance.outofrange=Sua localização lembrada está muito longe ou está inacessível...
spell.ebwizardry:clairvoyance.undefined=Você deve se lembrar de um local primeiro!
spell.ebwizardry:clairvoyance.wrongdimension=Seu local lembrado está em outra dimensão...
potion.ebwizardry:frost=Congelamento
potion.ebwizardry:fireskin=Pele de Fogo
potion.ebwizardry:ice_shroud=Mortalha de Gelo
potion.ebwizardry:static_aura=Aura Estática
potion.ebwizardry:transience=Transitoriedade
potion.ebwizardry:decay=Apodrecimento
potion.ebwizardry:sixth_sense=Sexto Sentido
potion.ebwizardry:arcane_jammer=Bloqueador Arcano
potion.ebwizardry:mind_trick=Truque Mental
potion.ebwizardry:mind_control=Controle Mental
potion.ebwizardry:font_of_mana=Fonte de Mana
potion.ebwizardry:fear=Medo
enchantment.ebwizardry:magic_sword=Imbuimento
enchantment.ebwizardry:magic_bow=Imbuimento
enchantment.ebwizardry:flaming_weapon=Imbuimento de Fogo
enchantment.ebwizardry:freezing_weapon=Imbuimento de Geada
key.categories.ebwizardry=Wizardry
key.ebwizardry.next_spell=Próximo Feitiço
key.ebwizardry.previous_spell=Feitiço Anterior
death.attack.wizardry_magic=%1$s foi morto por %2$s usando magia
death.attack.indirect_wizardry_magic=%1$s foi morto por %2$s usando magia
commands.ebwizardry:cast.usage=/%1$s <spell> [jogador] [multiplicador de dano] [multiplicador de alcance] [multiplicador de duração] [multiplicador de onda destrutiva]
commands.ebwizardry:cast.success=Com sucesso conjura %1$s
commands.ebwizardry:cast.success_continuous=Com sucesso conjura %1$s; repita o comando para parar
commands.ebwizardry:cast.success_remote=Com sucesso conjura %1$s como %2$s
commands.ebwizardry:cast.success_remote_continuous=Com sucesso conjura %1$s como %2$s; repita o comando para parar
commands.ebwizardry:cast.fail=Não é possível conjurar %1$s
commands.ebwizardry:cast.not_found=Não existe tal feitiço com ID %1$s
commands.ebwizardry:cast.tag_error=Análise da tag de dados falhou: %s
commands.ebwizardry:ally.usage=/%1$s <player> [jogador]
commands.ebwizardry:ally.addally=%1$s foi adicionado a lista de aliados de %2$s
commands.ebwizardry:ally.removeally=%1$s foi removido da lista de aliados de %2$s
commands.ebwizardry:ally.self=Os jogadores não podem ser um aliado deles mesmos!
commands.ebwizardry:ally.permission=Você não tem permissão para mudar os aliados de outros jogadores
commands.ebwizardry:allies.usage=/%1$s [jogador]
commands.ebwizardry:allies.list=Jogadores aliados a você: %1$s
commands.ebwizardry:allies.list_other=Jogadores aliados a %1$s: %2$s
commands.ebwizardry:allies.permission=Você não tem permissão para ver aliados de outros jogadores
commands.ebwizardry:allies.none=Nenhum
commands.ebwizardry:discoverspell.usage=/%1$s <spell/all/clear> [jogador]
commands.ebwizardry:discoverspell.not_found=Não existe tal mágica com ID %1$s
commands.ebwizardry:discoverspell.clear=Limpou todos os dados de descoberta de feitiços para %1$s
commands.ebwizardry:discoverspell.all=Adicionado todos os feitiços para os dados de descoberta de feitiços de %1$s
commands.ebwizardry:discoverspell.addspell=Adicionado %1$s para os dados de descoberta de feitiços de %2$s
commands.ebwizardry:discoverspell.removespell=Removido %1$s dos dados de descoberta de feitiços de %2$s
config.ebwizardry.title.general=Opções do Mod
config.ebwizardry.category.gameplay=Definições de Jogabilidade
config.ebwizardry.category.gameplay.tooltip=Configure a jogabilidade geral de wizardry
config.ebwizardry.title.gameplay=Definições de Jogabilidade
config.ebwizardry.subtitle.gameplay=Definições globais que afetam as mecânicas do jogo.
config.ebwizardry.category.worldgen=Definições de Geração de Mundo
config.ebwizardry.category.worldgen.tooltip=Configure os recursos de geração de mundo de wizardry
config.ebwizardry.title.worldgen=Definições de Geração de Mundo
config.ebwizardry.subtitle.worldgen=Definições que afetam a geração de mundo.
config.ebwizardry.category.commands=Definições de Comando
config.ebwizardry.category.commands.tooltip=Configure os comandos de wizardry
config.ebwizardry.title.commands=Definições de Comando
config.ebwizardry.subtitle.commands=Definições para os comandos adicionados pelo Wizardry.
config.ebwizardry.category.client=Definições de Cliente
config.ebwizardry.category.client.tooltip=Configure o vídeo e controles de wizardry
config.ebwizardry.title.client=Definições de Cliente
config.ebwizardry.subtitle.client=Definições do lado do cliente que somente afetam o jogo de minecraft local.
config.ebwizardry.category.spells=Configuração de Feitiço
config.ebwizardry.category.spells.tooltip=Selecione que feitiços estão habiliados
config.ebwizardry.title.spells=Configuração de Feitiço
config.ebwizardry.subtitle.spells=Defina um feitiço para falso para desabilitá-lo.
config.ebwizardry.category.resistances=Configuração de Resistência
config.ebwizardry.category.resistances.tooltip=Configure quais mobs são imunes aos diferentes tipos de magia
config.ebwizardry.title.resistances=Configuração de Resistência
config.ebwizardry.subtitle.resistances=Definições que permitem que entidades sejam imunes a certos tipos de magia.
config.ebwizardry.tower_rarity=Raridade de Torre
config.ebwizardry.ore_dimensions=Dimensões do Minério
config.ebwizardry.flower_dimensions=Dimensões da Flor
config.ebwizardry.tower_dimensions=Dimensões da Torre
config.ebwizardry.spell_book_drop_chance=Chance de Drop de Livro de Feitiços
config.ebwizardry.generate_loot=Gerar Loot
config.ebwizardry.firebomb_is_craftable=Bomba de Fogo É Craftável
config.ebwizardry.poison_bomb_is_craftable=Bomba de Veneno É Craftável
config.ebwizardry.smoke_bomb_is_craftable=Bomba de Fumaça É Craftável
config.ebwizardry.use_alternate_scroll_recipe=Usar Receita de Pergaminho Alternativa
config.ebwizardry.teleport_through_unbreakable_blocks=Teletransportar Através de Blocos Inquebráveis
config.ebwizardry.show_summoned_creature_names=Mostrar Nomes de Criaturas Invocadas
config.ebwizardry.friendly_fire=Fogo Amigo
config.ebwizardry.telekinetic_disarmament=Desarmamento Telequinético
config.ebwizardry.discovery_mode=Modo de Descoberta
config.ebwizardry.enable_shift_scrolling=Habilitar Rolagem com shift
config.ebwizardry.minion_revenge_targeting=Na Mira da Vingança Minion
config.ebwizardry.player_damage_scaling=Fator de Escala de Dano de Jogador
config.ebwizardry.npc_damage_scaling=Fator de Escala de Dano de NPC
config.ebwizardry.cast_command_multiplier_limit=Limite do Multiplicador de Lançar Comando
config.ebwizardry.summoned_creature_targets_whitelist=Lista de permissões de Alvo de Criatura Invocada
config.ebwizardry.summoned_creature_targets_blacklist=Lista negra de Alvo de Criatura Invocada
config.ebwizardry.spell_hud_position=Posição de HUD de Feitiços
config.ebwizardry.cast_command_name=Nome de Comando de Lançar Feitiço
config.ebwizardry.discoverspell_command_name=Nome de Comando de Descobrir Feitiço
config.ebwizardry.ally_command_name=Definir Nome de Comando Aliado
config.ebwizardry.allies_command_name=Ver Nome de Comando Aliados
config.ebwizardry.mind_control_targets_blacklist=Lista negra de Alvos de Controle Mental
config.ebwizardry.evil_wizard_dimensions=Dimensões do Mago Malvado
config.ebwizardry.mobs_immune_to_fire=Mobs Imunes a Fogo
config.ebwizardry.mobs_immune_to_ice=Mobs Imunes a Gelo
config.ebwizardry.mobs_immune_to_lightning=Mobs Imunes a Relâmpago
config.ebwizardry.mobs_immune_to_wither=Mobs Imunes a Wither
config.ebwizardry.mobs_immune_to_poison=Mobs Imunes a Veneno
config.ebwizardry.tower_rarity.tooltip=Raridade das torres de mago. Números mais altos são mais raros. Defina como 0 para desabilitar completamente as torres de mago.
config.ebwizardry.ore_dimensions.tooltip=Lista de IDs de dimensão em que o minério de cristal será gerado. Note que removendo o mundo superior (id 0) desta lista tornará o mod MUITO difícil de jogar!
config.ebwizardry.flower_dimensions.tooltip=Lista de IDs de dimensão em que as flores de cristal serão geradas.
config.ebwizardry.tower_dimensions.tooltip=Lista de IDs de dimensão em que as torres de mago serão geradas.
config.ebwizardry.spell_book_drop_chance.tooltip=A chance de mobs droparem um livro de feitiços quando mortos. Quanto maior esse número, mais freqüentemente eles irão dropar. Defina como 0 para desativar os drops de livro de feitiços. Defina como 200 para drop garantidos.
config.ebwizardry.generate_loot.tooltip=Se deve gerar loot mágico em baús de masmorras.
config.ebwizardry.firebomb_is_craftable.tooltip=Se as bombas de fogo podem ser craftadas ou não.
config.ebwizardry.poison_bomb_is_craftable.tooltip=Se as bombas de veneno podem ser craftadas ou não.
config.ebwizardry.smoke_bomb_is_craftable.tooltip=Se as bombas de fumaça podem ser craftadas ou não.
config.ebwizardry.use_alternate_scroll_recipe.tooltip=Seja para exigir um cristal mágico na receita de fabricação disforme para pergaminhos em branco. Defina como verdadeiro se outro mod adicionar uma receita conflitante.
config.ebwizardry.teleport_through_unbreakable_blocks.tooltip=Se os jogadores podem se teletransportar através de blocos inquebráveis (por exemplo, rocha matriz) usando o feitiço de etapa de fase.
config.ebwizardry.show_summoned_creature_names.tooltip=Seja para mostrar nomes e proprietários de criaturas invocadas acima de suas cabeças.
config.ebwizardry.friendly_fire.tooltip=Seja para permitir que os jogadores danifiquem seus aliados designados usando magia.
config.ebwizardry.telekinetic_disarmament.tooltip=Seja para permitir que os jogadores desarmem outros jogadores usando o feitiço telequinesia. Defina como falso para evitar roubo de itens.
config.ebwizardry.discovery_mode.tooltip=Para quem gosta de um senso de mistério! Quando definido como verdadeiro, as mágicas que você ainda não tiver lançado serão ilegíveis até que você as lance (em uma base mundial). Não tem efeito quando no modo criativo. Feitiços de identificação serão impossíveis de obter no modo de sobrevivência se isso for falso.
config.ebwizardry.enable_shift_scrolling.tooltip=Se você pode alternar entre magias em uma varinha rolando com a roda do mouse enquanto se agacha. Note que isso só afetará você; outros jogadores conectados ao mesmo servidor obedecem às suas próprias configurações.
config.ebwizardry.minion_revenge_targeting.tooltip=Se as criaturas convocadas podem se vingar atacando seu dono se seu dono as atacar.
config.ebwizardry.player_damage_scaling.tooltip=Fator de escala de dano global para o dano causado por jogadores lançando feitiços, em relação a 1.
config.ebwizardry.npc_damage_scaling.tooltip=Fator de escala de dano global para o dano causado por feitiços de conjuração de NPCs, relativo a 1.
config.ebwizardry.cast_command_multiplier_limit.tooltip=Limite superior para os multiplicadores passados para o comando / conjurar. Isso está aqui para impedir que os jogadores quebrem acidentalmente um mundo / servidor. Grandes mutiplicadores de onda destrutiva podem causar lags extremos - você foi avisado!
config.ebwizardry.summoned_creature_targets_whitelist.tooltip=Lista de nomes de entidades cujas criaturas invocadas e magos podem atacar, além dos padrões. Adicione criaturas de mod a esta lista se você quiser criaturas invocadas a atacá-los e eles já não estiverem fazendo isso. Nomes de entidades não diferenciam maiúsculas de minúsculas. Para entidades de mod, prefixar com o ID do mod (por exemplo, ebwizardry: wizard).
config.ebwizardry.summoned_creature_targets_blacklist.tooltip=Lista de nomes de entidades que criaturas invocadas e magos especificamente não têm permissão para atacar, substituindo os padrões e a lista de desbloqueio. Adicione criaturas a esta lista se permitir que elas sejam atacadas causem problemas ou sejam muito destrutivas (remover creepers desta lista é feito para por sua conta em risco!). Nomes de entidades não diferenciam maiúsculas de minúsculas. Para entidades de mod, prefixar com o ID mod (por exemplo, ebwizardry: wizard).
config.ebwizardry.spell_hud_position.tooltip=A posição do HUD de Feitiços.
config.ebwizardry.cast_command_name.tooltip=O nome do comando /cast. Isto é o que você digita diretamente após o /; por exemplo se isso for definido para 'magic' então, ao invés de estar digitando /cast em vez disso você digitará /magic.
config.ebwizardry.discoverspell_command_name.tooltip=O nome do comando /discoverspell. Isso é o que você digita diretamente após o /; por exemplo se isso for definido para 'magic' então, ao invés de estar digitando /discoverspell você em vez disso irá digitar /magic.
config.ebwizardry.ally_command_name.tooltip=O nome do comando /ally. Isso é o que você digita diretamente após o /; por exemplo se isso for definido para 'magic' então, ao invés de estar digitando /ally você em vez disso irá digitar /magic.
config.ebwizardry.allies_command_name.tooltip=O nome do comando /allies. Isso é o que você digita diretamente após o /; por exemplo se isso for definido para 'magic' então, ao invés de estar digitando /allies você em vez disso irá digitar /magic.
config.ebwizardry.mind_control_targets_blacklist.tooltip=Lista de nomes de entidades que não podem ter a mente controlada, além das padrões. Adicione criaturas a essa lista se permitir que elas sejam controladas mentalmente que causem problemas ou que isso possa ser exploradas. Nomes de entidades não diferenciam maiúsculas de minúsculas. Para entidades de mod, prefixar com o ID mod (por exemplo, ebwizardry: wizard).
config.ebwizardry.evil_wizard_dimensions.tooltip=Lista de ids de dimensões em que magos malvados podem ser gerar.
config.ebwizardry.mobs_immune_to_fire.tooltip=Lista de nomes de entidades que são imunes a fogo, em adição aos padrões. Adicione criaturas de mod nessa lista se você deseja que elas sejam imunes a magia de fogo e elas não estiverem sendo. Nomes de entidades não diferenciam maiúsculas de minúsculas. Para entidades de mod, prefixar com o ID mod (por exemplo, ebwizardry: wizard).
config.ebwizardry.mobs_immune_to_ice.tooltip=Lista de nomes de entidades que são imunes a gelo, em adição aos padrões. Adicione criaturas de mod nessa lista se você deseja que elas sejam imunes a magia de gelo e elas não estiverem sendo. Nomes de entidades não diferenciam maiúsculas de minúsculas. Para entidades de mod, prefixar com o ID mod (por exemplo, ebwizardry: wizard).
config.ebwizardry.mobs_immune_to_lightning.tooltip=Lista de nomes de entidades que são imunes a relâmpago, em adição aos padrões. Adicione criaturas de mod nessa lista se você deseja que elas sejam imunes a magia de relâmpago e elas não estiverem sendo. Nomes de entidades não diferenciam maiúsculas de minúsculas. Para entidades de mod, prefixar com o ID mod (por exemplo, ebwizardry: wizard).
config.ebwizardry.mobs_immune_to_wither.tooltip=Lista de nomes de entidades que são imunes a efeitos de wither, em adição aos padrões. Adicione criaturas de mod nessa lista se você deseja que elas sejam imunes a magia de wither e elas não estiverem sendo. Nomes de entidades não diferenciam maiúsculas de minúsculas. Para entidades de mod, prefixar com o ID mod (por exemplo, ebwizardry: wizard).
config.ebwizardry.mobs_immune_to_poison.tooltip=Lista de nomes de entidades que são imunes a veneno, em adição aos padrões. Adicione criaturas de mod nessa lista se você deseja que elas sejam imunes a magia de veneno e elas não estiverem sendo. Nomes de entidades não diferenciam maiúsculas de minúsculas. Para entidades de mod, prefixar com o ID mod (por exemplo, ebwizardry: wizard).
wizard.debug=%1$s, %2$s, %3$s
@@ -103,7 +103,7 @@
{ {
"type": "item", "type": "item",
"name": "ebwizardry:astral_diamond", "name": "ebwizardry:astral_diamond",
"weight": 1 "weight": 2
}, },
{ {
"type": "item", "type": "item",
@@ -113,7 +113,7 @@
{ {
"type": "item", "type": "item",
"name": "ebwizardry:grand_crystal", "name": "ebwizardry:grand_crystal",
"weight": 1 "weight": 2
} }
] ]
} }
@@ -108,7 +108,7 @@
{ {
"type": "item", "type": "item",
"name": "ebwizardry:astral_diamond", "name": "ebwizardry:astral_diamond",
"weight": 1 "weight": 2
}, },
{ {
"type": "item", "type": "item",
@@ -118,7 +118,7 @@
{ {
"type": "item", "type": "item",
"name": "ebwizardry:grand_crystal", "name": "ebwizardry:grand_crystal",
"weight": 1 "weight": 2
} }
] ]
}, },
@@ -2,5 +2,13 @@
"parent": "item/generated", "parent": "item/generated",
"textures": { "textures": {
"layer0": "ebwizardry:items/scroll" "layer0": "ebwizardry:items/scroll"
} },
"overrides": [
{
"predicate": {
"festive": 1
},
"model": "ebwizardry:item/festive_scroll"
}
]
} }

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