Compare commits

..

1135 Commits

Author SHA1 Message Date
WinDanesz 89a0a900cc v4.3.5 2022-02-07 23:06:39 +01:00
WinDanesz 391a24db3f Fixes integration with Construct's Armory and other mod's unbreakable helmets. #547 2022-02-07 22:10:28 +01:00
WinDanesz 4b546af642 Added a new ImbuementActivateEvent to allow addons hooking into the imbuement process 2022-02-07 21:50:26 +01:00
WinDanesz ee8aabbf97 This might fix the lingering Frost effect (from Frost Ray) 2022-02-07 21:37:01 +01:00
Rodro 45994e2b94 Fixed player rubberbanding when touching the wall of a containment field. Fixes #469 (Rodrogamby)
This fixed player rubberbanding when touching the wall of a containment field for me.

I took the liberty of uncommenting some code which produces a sound when the player tries to leave the field, and also deleted line 113 along with everything related to it since it seemed unnecessary.

I've tested this on singleplayer and on my 200ms multiplayer server and appears to be working perfectly in both.
(It works even if allow-flight is set to false on server.properties; I also tried using an elytra, levitation effect and extra speed, which all worked well too).
All tests were done using Forge-2860
2022-02-06 22:19:32 +01:00
WinDanesz 13bdc69da8 Added support for Forge's in-game mod version update notifier 2022-02-05 23:04:14 +01:00
WinDanesz c0184fde8e Fixed a bug with EntityWizard using one of EntityEvilWizard's DataParameter 2022-02-05 22:48:35 +01:00
WinDanesz cbd297e59d updated gradle version 2022-02-05 22:48:34 +01:00
WinDanesz c6cf7c950e increased duplicate detect threshold 2022-02-03 14:49:37 +01:00
WinDanesz fe5d80e017 Fixed dispenser crash with Conjure Block spell. Fixes #735 2022-02-03 11:57:22 +01:00
WinDanesz e985a8f15b Fixed dispenser crash with Slime spell. Fixes #735 2022-02-03 11:57:22 +01:00
Electroblob 615767f758 Merge pull request #688 from WinDanesz/1.12.2.dev
added onImbuementRemoval(ItemStack stack) to Imbuement interface
2022-02-01 18:34:24 +00:00
Electroblob 65a24b2295 Merge pull request #744 from WinDanesz/patch-2
Added duplicate issue detector & labeling tool
2022-02-01 18:33:18 +00:00
Electroblob 94c2afe67a Merge pull request #747 from WinDanesz/patch-1225-2
Fixes Mark Sacrifice not doing damage with low spell potency
2022-02-01 18:32:02 +00:00
Electroblob 9bbca37ecd Merge pull request #749 from WinDanesz/patch-1225-4
Scrolls no longer have cooldown in Creative mode
2022-02-01 18:30:47 +00:00
Electroblob 58241a0f5c Merge pull request #748 from WinDanesz/patch-1225-3
Added getter for ItemArtefact.enabled
2022-02-01 18:28:21 +00:00
Electroblob a960a01ca1 Merge pull request #750 from WinDanesz/patch-1226-2
Splitting PacketSpellProperties into batches of 100 spells.
2022-02-01 18:27:47 +00:00
Electroblob 67d8ee773c Merge pull request #751 from WinDanesz/patch-1227-1
Added tooltip for Spell Book and Scroll items, displaying the spell's…
2022-02-01 18:27:25 +00:00
Electroblob c6f2675278 Merge pull request #753 from WinDanesz/patch-1228-1
Fixed bug with wizard armours always providing protection even withou…
2022-02-01 18:26:54 +00:00
Electroblob77 2380be230e Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2022-02-01 18:24:34 +00:00
Electroblob77 833276b7b3 TODOs 2022-02-01 18:24:26 +00:00
Electroblob77 9b32835720 Add resurrection event 2022-02-01 18:24:17 +00:00
Electroblob77 61634a9cc3 Change resurrection wait time and add particles to indicate where an ally died 2022-02-01 18:23:47 +00:00
Electroblob 408a35db8d Merge pull request #754 from WinDanesz/patch-1228-2
Remove soulbinding curse effect if the potion is no longer active. fi…
2022-02-01 18:20:37 +00:00
Electroblob 9695a85131 Merge pull request #755 from WinDanesz/patch-0102-1
Frostbite effect and burning now cancels each other
2022-02-01 18:20:20 +00:00
Electroblob d027cf4f2a Merge pull request #756 from WinDanesz/patch-0103-1
Added injectMobDrops setting to easily disable mob loot injection for…
2022-02-01 18:19:29 +00:00
WinDanesz c2f8bfc5b4 Added injectMobDrops setting to easily disable mob loot injection for all entities 2022-01-03 14:47:33 +01:00
WinDanesz 486425a62c Frostbite effect and entity burning now cancels each other 2022-01-02 22:07:05 +01:00
WinDanesz f9681d4c66 Remove soulbinding curse effect if the potion is no longer active. fixes #619. 2021-12-28 16:10:31 +01:00
WinDanesz cd0671dc59 Fixed bug with wizard armours always providing protection even without mana. Fixes #752 2021-12-28 16:08:18 +01:00
WinDanesz 7ebca16948 Added tooltip for Spell Book and Scroll items, displaying the spell's source mod if it's from an addon 2021-12-27 11:31:07 +01:00
WinDanesz e8cbdde518 Splitting PacketSpellProperties into batches of 100 spells. Fixes world load issue with large list of spells 2021-12-26 22:08:29 +01:00
WinDanesz 7ca6f05151 Scrolls no longer have cooldown in Creative mode 2021-12-25 18:16:32 +01:00
WinDanesz f4f17e90e5 Added getter for ItemArtefact.enabled 2021-12-25 18:10:09 +01:00
WinDanesz 3ea48efb1d Fixes Mark Sacrifice not doing damage with a potion amplifier of 0 2021-12-25 18:01:43 +01:00
WinDanesz ffc3533688 Create potential-duplicates.yml 2021-12-20 18:36:08 +01:00
Electroblob bd309855a2 Merge pull request #721 from WinDanesz/1.12.2-PR-10-02
Fixes wizards being stuck in a continuous, client-side only spellcast…
2021-10-03 18:10:51 +01:00
WinDanesz 1473c7e9b7 Fixes wizards being stuck in a continuous, client-side only spellcasting loop of their continuous spells if their target dies 2021-10-02 00:26:31 +02:00
WinDanesz 15cc7b6d18 added isEnabled() public method to ItemArtefact 2021-07-07 13:26:21 +02:00
WinDanesz 1c89c5f779 added onImbuementRemoval(ItemStack stack) to Imbuement interface 2021-07-07 12:40:05 +02:00
Electroblob77 ca7f1cc8ca Prevent Hyeleth's amulet from casting the shield spell from a scroll, fixes #680 2021-06-20 23:44:04 +01:00
Electroblob77 8fd1de84e4 Fix next/previous section button weirdness 2021-06-19 16:19:22 +01:00
Electroblob77 95d9168b6b Fix hyperlink wrapping for spaceless languages and remove remaining newlines 2021-06-19 16:01:23 +01:00
Electroblob77 c1db827132 Remove manual newline characters from Chinese handbook translations
I'm not 100% sure which to remove so I've only removed single newlines in block text for now
2021-06-19 13:01:58 +01:00
Electroblob77 d10b78ab46 Ignore hyperlink suffixes in spaceless languages, fixes #620
There's no real way to do this other than hardcoding which languages are exceptions (currently only the two Chinese locales)
2021-06-19 13:01:47 +01:00
Electroblob77 2d70523f43 Remove obsolete plain text Russian handbook translation 2021-06-19 12:47:00 +01:00
Electroblob77 42fb7ad3df Have all the baked bookshelf models use the same set of book models, fixes #621
This effectively cuts the number of book models by a factor equal to the number of bookshelf variants, which is 6 in the base mod
2021-06-19 00:01:24 +01:00
Electroblob77 e90d0950d4 Replace glide end sound with dummy sound (which for some reason seems not to play at all? Oh well ¯\_(ツ)_/¯), fixes #646 2021-06-18 17:47:55 +01:00
Electroblob77 888d4190d1 Store static map of mana flask charging recipes rather than iterating, fixes #671 2021-06-18 17:26:40 +01:00
Electroblob77 57696b2538 Make all forfeits respect claims via the methods in BlockUtils, fixes #672 2021-06-18 16:27:57 +01:00
Electroblob77 1440537f6b Missed one! 2021-06-18 14:23:40 +01:00
Electroblob77 a16ff88c8d Update credits (and put the discord mods in their rightful place at the top of the list <3) 2021-06-18 14:21:21 +01:00
Electroblob77 041de12ea7 Update Russian translations, courtesy of DrHesperus 2021-06-18 13:52:01 +01:00
Electroblob77 5e36f66c4e Update Korean translations, courtesy of red1854th 2021-06-18 13:51:32 +01:00
Electroblob77 a6a5a6104d Update French translations, courtesy of Crowller 2021-06-18 13:50:53 +01:00
Electroblob77 6f7b225ce8 ParticleBuilder is not thread-safe! 2021-06-18 13:49:45 +01:00
Electroblob77 81a85883d2 Consume mana/scrolls when forfeits are triggered, fixes #673 2021-06-18 13:49:29 +01:00
Electroblob 3f06d2fea4 Update bug_report.md 2021-06-18 00:08:29 +01:00
Electroblob 26b390268a Update ISSUE_TEMPLATE.md 2021-06-18 00:08:12 +01:00
Electroblob 486d55f349 Merge pull request #636 from LWHK/class-build
Add LF for CHS translation
2021-03-03 16:08:01 +00:00
TUsama 5948090d63 add LF manually
add LF manually
2021-03-01 17:55:32 +08:00
Electroblob77 32340191de Update version number 2021-02-01 16:49:30 +00:00
Electroblob77 0b09875bb3 Fix problems with combining spell modifiers 2021-02-01 16:41:31 +00:00
Electroblob77 078a36d304 Update The Wizard's Handbook 2021-01-31 20:34:57 +00:00
Electroblob77 3ef4ec522b Make mana flasks instant-use in creative mode 2021-01-31 16:17:18 +00:00
Electroblob77 cd6fa03990 Limit cooldowns to a minimum of 1 tick and replace armour cooldown reductions with correct values, fixes #603 2021-01-31 15:50:55 +00:00
Electroblob77 bba9fb68e6 Fix Hungarian handbook translation syntax error, fixes #610 2021-01-30 18:11:16 +00:00
Electroblob77 dcb7038833 Remove JSON generator code, fixes #615 2021-01-30 17:50:29 +00:00
Electroblob77 f8a058259d ItemArmor#getEquipmentSlot() is client-side only for some reason... fixes #608 2021-01-30 17:47:30 +00:00
Electroblob77 1696d5daeb Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2021-01-30 17:46:25 +00:00
Electroblob77 ac69af012a Update Korean translations, courtesy of red1854th 2021-01-30 17:46:19 +00:00
Electroblob 692546a232 Merge pull request #606 from LWHK/armor-build
Update zh_cn.lang
2021-01-30 17:17:57 +00:00
TUsama b0478b627f some changes 2021-01-28 18:44:16 +08:00
Determancer 2cdca4b990 Merge pull request #1 from LWHK/Determancer-patch-1 2021-01-19 13:07:37 +08:00
Determancer 4c0b2adef4 武士 -> 巫师 2021-01-19 13:07:07 +08:00
Determancer 191dd078b8 Update src/main/resources/assets/ebwizardry/lang/zh_cn.lang
Co-authored-by: Clefal <1716976420@qq.com>
2021-01-19 13:04:35 +08:00
Determancer 2de7807bec Update src/main/resources/assets/ebwizardry/lang/zh_cn.lang
Co-authored-by: Clefal <1716976420@qq.com>
2021-01-19 13:04:13 +08:00
Determancer 9d4f1dd370 Translating All 2021-01-19 11:41:07 +08:00
Determancer 6f769150b1 Sync en_us.lang 2021-01-18 16:01:59 +08:00
TUsama 155dc0b621 update 2021-01-18 15:54:22 +08:00
Electroblob77 07acea53e3 A couple of tweaks for backwards compatiblity 2021-01-17 21:33:09 +00:00
Electroblob77 1fcb3a2b1b Reduce capacity of medium mana flask and reduce number of crystals required to craft it accordingly 2021-01-17 20:27:21 +00:00
Electroblob77 16eabc8deb Update version number 2021-01-17 20:23:28 +00:00
Electroblob77 e0efd8d407 Make mana flasks take time to use 2021-01-17 19:25:14 +00:00
Electroblob77 969f0b96fd Have custom large fireballs deal magic damage to ghasts in order to get around vanilla's hardcoded instanceof check, fixes #443 2021-01-17 17:40:09 +00:00
Electroblob77 8a9d88c9ac Guard against null item entities in LivingDropsEvent, fixes #464 2021-01-17 17:19:07 +00:00
Electroblob77 3b55728c75 Actually register font of mana with the event bus, fixes #477 2021-01-17 15:26:30 +00:00
Electroblob77 240bffa7ed Sometimes, I surprise even myself with my own stupidity... fixes #594
(This is literally why I have a helper method. To prevent exactly this error :/)
2021-01-17 15:14:23 +00:00
Electroblob77 c313236eec Disable weather forfeit when invoke weather is disabled, closes #554 2021-01-17 15:08:34 +00:00
Electroblob77 21f7928b9c Guard against null target in remant AI, fixes #600 2021-01-17 14:58:59 +00:00
Electroblob77 1304c11381 People don't listen to me, so let's spell it out to them 2021-01-17 14:41:21 +00:00
Electroblob77 79932e15ab Allow class armour to be imbued properly at the imbuement altar 2021-01-17 13:36:56 +00:00
Electroblob77 25ee166e41 Derp 2021-01-17 13:32:38 +00:00
Electroblob77 299510e663 Add armour classes!
- Added 3 new armour variants - the sage, the battlemage and the warlock - each in the 8 elemental varieties
- Added resplendent thread, crystal silver plating and ethereal crystalweave, used to upgrade regular armour into class armour
- Added the new armour upgrades to loot tables
- Added recipes for the new armour to JEI, along with info pages for the 3 upgrade items
- Added advancements for the new armour classes
- Removed legendary wizard armour
- Removed arcane seal of protection
- Removed the 'legendary' advancement
2021-01-16 23:02:03 +00:00
Electroblob77 d3d76cae16 Update Russian translations, courtesy of DrHesperus 2021-01-05 20:35:42 +00:00
Electroblob77 0e815c676d Fix conjured items not disappearing in offhand (actually fixes #493) 2021-01-04 00:18:37 +00:00
Electroblob77 f81ad670ed Change donation perk element sync to per-dimension and use EntityJoinWorldEvent instead of PlayerLoggedInEvent, fixes #541 2021-01-03 23:42:27 +00:00
Electroblob77 5b3aebaba1 Update version number 2021-01-03 23:40:57 +00:00
Electroblob77 3ef1afce2f Update credits 2021-01-03 23:27:53 +00:00
Electroblob77 a3c15d673b Set arcane lock data server-side and sync the tile entity properly, fixes #580 2021-01-03 23:18:20 +00:00
Electroblob77 d8f1c5f77c Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2021-01-01 23:26:43 +00:00
Electroblob77 1ddcdafe50 Fix the utter mess that is spell property syncing (what was I thinking when I wrote this? and how did it ever work in the first place?!)
This fix is kinda cheating but I don't care, it works and it's certainly better than the mess that was there before
2021-01-01 23:26:24 +00:00
Electroblob 3c35eaaf54 Merge pull request #584 from SettingDust/bugfix/lighting-web-concurrent-modification
Try to fix lighting web concurrent modification
2020-12-21 16:39:15 +00:00
SettingDust 094ce5a427 Try to fix #513 #567
Try to fix  ConcurrentModificationException in LightningWeb
2020-12-21 22:38:15 +08:00
Electroblob77 e19d324dca Include offhand inventory in imbued item updating (and armour, while we're at it), fixes #493 2020-12-20 23:32:12 +00:00
Electroblob77 58f6d55b0d Add timeout when crystal flower charm's effect activates to prevent infinite looping when mod plants don't behave, fixes #488 2020-12-20 23:29:05 +00:00
Electroblob77 32e92b4b04 Guard against null element in writeEntityToNBT for wizards and evil wizards, fixes #491 2020-12-20 23:24:30 +00:00
Electroblob77 24a06e0bac Change dire wolf pelt's effect from different marker colours to different marker shapes 2020-12-20 23:12:27 +00:00
Electroblob77 ae9da5b7c1 Query the position using the block at that position, not the one below... 🤦Fixes #519. 2020-12-20 19:13:41 +00:00
Electroblob77 2e39a8bfc1 Remove spaces around hyperlinks in Chinese handbook translation file, fixes #527 2020-12-20 19:02:34 +00:00
Electroblob77 e3130ca936 Cleanup 2020-12-20 18:57:23 +00:00
Electroblob 378e19a614 Add translation tips for languages without spaces 2020-12-20 18:45:27 +00:00
Electroblob77 e2fd978d8b Catch NPEs when accessing IBakedModel#getOverrides from ModelBakeEvent, fixes #537 2020-12-20 17:07:58 +00:00
Electroblob77 8f8ce7a453 Populate model lists in PlayerAnimator when a new player renderer is found, fixes #551
Also adds the missing null check to RenderPlayerPostEvent, just in case
2020-12-20 14:45:20 +00:00
Electroblob77 ddfffd3d31 Guard against IOOBEs when rendering the new spell trade icon, fixes #565 2020-12-20 00:16:17 +00:00
Electroblob77 d23c15476a Guard against null spell HUD skins in all places, fixes #566 2020-12-20 00:10:16 +00:00
Electroblob77 55bb40a684 Copy contents of imbuement altar to new tile entity when activated or deactivated, fixes #576 2020-12-20 00:02:10 +00:00
Electroblob77 c056c490da Update credits 2020-12-19 23:47:46 +00:00
Electroblob77 c483591ea8 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2
# Conflicts:
#	src/main/resources/assets/ebwizardry/lang/ru_ru.lang
2020-12-19 23:41:22 +00:00
Electroblob77 4c3dfb3bc9 Update Russian translations, courtesy of DrHesperus 2020-12-19 23:34:02 +00:00
Electroblob77 0010fafc13 Update German translations, courtesy of Lemopav 2020-12-19 23:25:38 +00:00
Electroblob77 f4cf98089c New contributors 2020-12-19 23:24:38 +00:00
Electroblob77 8e3a33b084 Update Korean translations, courtesy of red1854th 2020-12-19 23:24:26 +00:00
Electroblob b1478de6fe Merge pull request #577 from Aralu115/Fix-Layer-Issue-LycaniteMobs
Re-implement layer fix from Pull Request 312
2020-12-18 16:23:01 +00:00
Aralu 1d247e2d56 Re-implment layer fix from Pull Request 312 2020-12-17 11:39:50 -06:00
Electroblob e8292f1e96 Merge pull request #574 from LWHK/TC
Fix uncorrect file path and add untranslated content to zh_tw.json
2020-12-13 12:00:22 +00:00
TUsama bc0b712e2b add untranslated content
2
2020-12-13 16:33:46 +08:00
TUsama 47135f00d7 fix the file path error 2020-12-13 16:21:53 +08:00
Electroblob c615ad365c Merge pull request #568 from LWHK/TC
Rollback the zh_tw.json to the last UTF-8 code version due to the bug fix
2020-12-11 11:56:30 +00:00
Electroblob 39c3989796 Merge pull request #571 from WinDanesz/patch-1
Update ru_ru.lang fixing mana info on the arcane workbench
2020-12-11 11:55:32 +00:00
WinDanesz e808ab2b1f Update ru_ru.lang fixing mana info on the arcane workbench 2020-12-11 00:37:17 +01:00
TUsama a25f942722 Rollback the zh_tw to the last UTF-8 code version because of the bug fix 2020-12-09 10:16:43 +08:00
Electroblob 14e481a71d Merge pull request #543 from Determancer/patch-3
New Chinese Simplified Translation for Imbuement
2020-11-05 11:39:07 +00:00
Determancer ac226f1444 an untranslated one, oops 2020-11-05 10:49:31 +08:00
Determancer 741d918d9b another tweak 2020-11-05 10:46:53 +08:00
Determancer f504505bf5 New Translation for Imbuement
Changing the current translation based on the latest discussion.
2020-11-05 10:44:49 +08:00
Electroblob77 fb010d3726 Update version number 2020-11-03 01:36:16 +00:00
Electroblob77 c64731e7a9 Fix ClassCastException in player animations, fixes #533
Somehow some unwrapped model parts managed to slip through (exactly *how* is a mystery!) so we're just safety-checking everything, I doubt this incurs much performance cost in the scheme of things.
2020-11-03 01:33:22 +00:00
Electroblob77 d3837a6185 Update credits 2020-11-03 01:20:16 +00:00
Electroblob77 80cf77ecc6 Fix GL stack overflow / weird rendering when arrows are stuck in the player, fixes #529 and #530 2020-11-03 01:08:14 +00:00
Electroblob77 3d3806c20b Prevent receptacles dropping on neighbour change when attached to an imbuement altar, fixes #520 2020-11-03 01:08:11 +00:00
Electroblob77 d952e9b255 Update Polish translations, courtesy of Olej 2020-11-01 15:06:49 +00:00
Electroblob77 33c8f08adf Update spanish handbook translations, courtesy of Alsentar 2020-11-01 10:41:45 +00:00
Electroblob77 315f2e4b02 Reinstate missing null check in SpellRay, fixes part of #519 2020-10-28 23:43:08 +00:00
Electroblob77 d3df59df73 Have PlayerAnimator ignore renderers for which no layers/models are stored, fixes #518
This will stop the crashing but might well mean broken animations - for now there's not much I can do about that
2020-10-28 23:37:51 +00:00
Electroblob77 cfd3e796e1 Make PlayerAnimator disable itself when MoBends is installed 2020-10-28 23:27:04 +00:00
Electroblob77 d97e843f7b Guard against all possible nulls to be on the safe side, fixes #517 2020-10-28 23:20:48 +00:00
Electroblob77 15a153fe11 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2020-10-28 23:20:13 +00:00
Electroblob77 d00b7279ee Update Hungarian translations, courtesy of Bombadil 2020-10-28 23:20:06 +00:00
Electroblob77 0142cc05bc Update Korean translations, courtesy of 방통 2020-10-28 23:19:47 +00:00
Electroblob 23621b8045 Merge pull request #526 from LWHK/1.12.2
Update CHS  translation version to 4.3
2020-10-26 23:26:18 +00:00
TUsama 7f2978bc7a Enhance some details
Co-Authored-By: Determancer <49300241+Determancer@users.noreply.github.com>
Co-Authored-By: WuzgXY <62000315+WuzgXY-GitHub@users.noreply.github.com>
2020-10-26 23:08:26 +08:00
TUsama 312364ba77 Update CHS translation version to 4.3
Co-Authored-By: Determancer <49300241+Determancer@users.noreply.github.com>
Co-Authored-By: Hokorizero <50108932+Hokorizero@users.noreply.github.com>
2020-10-26 09:50:21 +08:00
Electroblob77 3b4ce68606 Third time lucky 2020-10-23 15:55:03 +01:00
Electroblob77 164e9dbe36 And that one 2020-10-23 15:48:59 +01:00
Electroblob77 2a21eb4392 Fix NPE in donor perk packet 2020-10-23 15:38:29 +01:00
Electroblob77 97061f7a32 Merge branch '4.3-dev' into 1.12.2 2020-10-23 15:14:53 +01:00
Electroblob77 7f84f3daef Temporary fix for lag in imbuement updating, ultimately this needs a rewrite but *effort*... 2020-10-23 15:09:19 +01:00
Electroblob77 9f3e09498d Hopefully fixes #469 2020-10-23 15:06:41 +01:00
Electroblob77 55bcd92860 Replace dummy criteria with proper generic imbuement altar criterion 2020-10-23 14:48:02 +01:00
Electroblob77 1030a2a4f3 Disable this for now, it's not a big deal 2020-10-23 14:34:21 +01:00
Electroblob77 bc407187e1 This works now 2020-10-23 14:13:35 +01:00
Electroblob77 62c7b6b7bb Fix imbuement altar not dropping its contents 2020-10-23 14:13:26 +01:00
Electroblob77 35ac115e8b Change imbuement altar face shapes back to how they should be and give receptacles a special case for attachment 2020-10-23 14:13:09 +01:00
Electroblob77 f99f8c271e Add the rest of the new spells to the advancements 2020-10-23 13:23:32 +01:00
Electroblob77 21dabc9cfc Probably should be this one 2020-10-23 13:07:02 +01:00
Electroblob77 77d9bfc772 Blast modifier support for permafrost, plus various fixes and an attempt at slipperiness 2020-10-23 13:06:54 +01:00
Electroblob77 29617451d8 Add permafrost spell and fix dry frosted ice not being very icy 2020-10-23 01:22:28 +01:00
Electroblob77 e530695f54 Give conjured items a blue timer (durability) bar 2020-10-22 23:50:49 +01:00
Electroblob77 1f4de65356 Cleanup 2020-10-21 22:46:30 +01:00
Electroblob77 9dc186abf4 Fix the charge meter showing when holding a wand in the offhand but using the main hand item 2020-10-21 22:41:26 +01:00
Electroblob77 086d9f6af6 A few tweaks and fixes for flamecatcher 2020-10-21 22:37:53 +01:00
Electroblob77 7e658d74b5 Probably shouldn't be rendering the ends of this 2020-10-21 22:24:07 +01:00
Electroblob77 2bb242e6fb Add flamecatcher spell, and addItemExtras hook for SpellConjuration 2020-10-21 22:23:54 +01:00
Electroblob77 d85441867e Remove knockback from celestial smite 2020-10-21 21:20:18 +01:00
Electroblob77 38aa80d60a That didn't work :( 2020-10-20 00:22:17 +01:00
Electroblob77 5e35e53eb3 Update artefact advancements with new artefacts 2020-10-20 00:14:03 +01:00
Electroblob77 f41effd44f Add config option to change progression requirements 2020-10-19 23:52:27 +01:00
Electroblob77 17fad8b33c Reduce progression requirement for novice tier 2020-10-19 23:37:36 +01:00
Electroblob77 1c96c88082 Remove shadow from players under the effects of mirage 2020-10-19 23:37:12 +01:00
Electroblob77 2b884d0aea Add localisation for mark of sacrifice effect 2020-10-18 22:12:27 +01:00
Electroblob77 89345d4fbc Add mirage spell 2020-10-18 22:12:14 +01:00
Electroblob77 cf8de05d1b Make celestial smite ignore mobs when raytracing 2020-10-18 20:37:43 +01:00
Electroblob77 f9432c7c05 Add celestial smite spell 2020-10-18 01:17:31 +01:00
Electroblob77 d6f30d6519 Change guardian beam to use a single sound event and time it with the damage 2020-10-18 00:56:30 +01:00
Electroblob77 eb864338b4 Bring range for lightning bolt in line with other 'attack from above' spells 2020-10-18 00:24:10 +01:00
Electroblob77 bf13491987 A healthy splash of optimise imports 2020-10-18 00:12:29 +01:00
Electroblob77 0dd26de905 Add guardian beam spell 2020-10-17 15:28:51 +01:00
Electroblob77 795bdcd427 Fix player animations being applied to all instances of the model 2020-10-17 13:02:09 +01:00
Electroblob77 6f57d2366e Fix healing totem beam origin for healing allies 2020-10-16 19:43:13 +01:00
Electroblob77 8b86bb1b31 Add Lokenzen's ring 2020-10-16 19:42:56 +01:00
Electroblob77 0db343c959 Add enrage spell 2020-10-10 19:15:15 +01:00
Electroblob77 f5cd740497 Add amulet of esundor, plus fixes for frost barrier 2020-10-10 18:30:54 +01:00
Electroblob77 b6c67ddf34 Add ring of volthraa 2020-10-06 00:34:19 +01:00
Electroblob77 c51b08c827 Goddamnit you yanks 2020-10-03 00:55:32 +01:00
Electroblob77 970894ea21 Comments and TODOs 2020-10-03 00:54:29 +01:00
Electroblob77 d5d933b4e6 Add dire wolf pelt 2020-10-03 00:54:20 +01:00
Electroblob77 7e32263946 These should stack to 16 now or it'll be a bit too easy to take loads of mana with you 2020-09-30 19:21:24 +01:00
Electroblob77 543cc22c44 Nerf mark sacrifice 2020-09-30 19:19:47 +01:00
Electroblob77 c86cd88a57 Improvements to shield rendering, now with trippy animations! 2020-09-30 18:37:49 +01:00
Electroblob77 ac5b3466e7 A few little optimisations for PlayerAnimator 2020-09-30 17:05:57 +01:00
Electroblob77 3cdd564228 Allow frost barrier to be cast by dispensers 2020-09-27 22:02:24 +01:00
Electroblob77 a5fb3c6ac5 Send packets for player motion 2020-09-27 17:54:13 +01:00
Electroblob77 3f36f933ff Only display search tips on the spells tab! 2020-09-27 17:49:46 +01:00
Electroblob77 22b284063b Should be server-side only 2020-09-27 17:49:24 +01:00
Electroblob77 f32bcae8d3 Better particle interaction for custom hitboxes (now they can't pass through thin stuff) 2020-09-27 17:49:11 +01:00
Electroblob77 c05f4001fd Add frost barrier spell 2020-09-27 17:48:37 +01:00
Electroblob77 a72ac33768 Add a bit of aim assist to telekinesis to help with item entity hitboxes being weird 2020-09-25 17:53:29 +01:00
Electroblob77 c53c9b1793 Fix decay not saving properly 2020-09-24 18:56:35 +01:00
Electroblob77 c56128a7e2 Don't rely on class load order, do this properly during the init phase (and tell addon devs when to do theirs) 2020-09-24 18:47:41 +01:00
Electroblob77 b4e9d86d1d Make replaceVanillaFallDamae a synchronised setting, should fix the problems people were having on servers where turning the option off seemed to do nothing 2020-09-24 18:46:43 +01:00
Electroblob77 aac931f6b2 Clean up a bunch of TODOs that are no longer relevant 2020-09-23 23:49:36 +01:00
Electroblob77 ed9e9110e5 Remove all references to WandHelper from GuiSpellDisplay and abstract them behind ISpellCastingItem 2020-09-23 23:22:11 +01:00
Electroblob77 c4194e2b76 Fix being able to use master tomes on master wands 2020-09-23 14:05:00 +01:00
Electroblob77 84236093c8 Plug spell property value into black hole radius calculations 2020-09-23 14:04:23 +01:00
Electroblob77 77f698397a Add 2 new spell HUD skins 2020-09-23 14:04:03 +01:00
Electroblob77 b7329299f9 Make dispensers trigger break events properly too 2020-09-23 01:28:42 +01:00
Electroblob77 127723a1e7 Finish the job properly, EB 2020-09-23 01:02:37 +01:00
Electroblob77 4a7b8a2bb9 Various fixes for arcane lock 2020-09-23 00:59:46 +01:00
Electroblob77 2f91573284 Block protection compat overhaul
- Unifies all block protection checks into helper methods in BlockUtils which trigger all the necessary forge events and vanilla methods
- Implements these checks in all the appropriate places and removes calls to EntityUtils#canDamageBlocks(...) where they are no longer needed
- Changes the mine spell to respect the config settings in line with the rest of the spells
- Fixes earthquake not respecting the settings at all
- Adds a separate config option for dispenser block damage and updates the description for the existing settings to reflect the changes
2020-09-23 00:57:55 +01:00
Electroblob77 f49ef7594d Evade is now 140% less cheesable 2020-09-21 22:20:44 +01:00
Electroblob77 0022de499d Altar the weighting a bit :P 2020-09-21 18:15:44 +01:00
Electroblob77 359da9a688 Not that one 2020-09-21 16:59:34 +01:00
Electroblob77 1a636c8c40 Ugh really, Forge? 2020-09-21 16:54:21 +01:00
Electroblob77 2c95793293 Have the elements of spectral dust in the receptacles affect the element weighting for the resulting spell book 2020-09-21 16:43:51 +01:00
Electroblob77 93d2100546 Every day I'm shufflin' 2020-09-21 14:02:49 +01:00
Electroblob77 eeb408c68c Add imbuement altar 'recipes' to JEI 2020-09-21 13:55:55 +01:00
Electroblob77 d5ed705f22 Defer loading of TileEntityImbuementAltar#lastUser until after the world is set 2020-09-21 13:36:40 +01:00
Electroblob77 adf07a7c98 Tweak arcane workbench jei background to match vanilla output slots 2020-09-14 16:11:17 +01:00
Electroblob77 ea4e07b2c9 Add ability to restore ruined spell books with the imbuement altar
For now this ignores dust elements but may change this in future
2020-09-14 15:37:05 +01:00
Electroblob77 ac7e2fda94 Fix wizard armour charging always using 100 mana regardless of shards/grand crystals 2020-09-14 15:33:59 +01:00
Electroblob77 8690d406f3 Make spell enabled default to true, fixes the none spell displaying the disabled in config message 2020-09-14 15:12:57 +01:00
Electroblob77 ebcfd3963d Remove all references to Minecraft.getMinecraft().player from RenderPlayerEvent receivers because some mods render players in the main menu, fixes #497
(Actually, it probably doesn't matter because all the references were moved inside the situational checks, but it's better to use the event parameters anyway)
2020-09-12 14:16:59 +01:00
Electroblob77 ea9c9edff1 Add CME fix from remove curse to cure effects, fixes #489 2020-09-12 14:09:31 +01:00
Electroblob77 2e49f1d06b Replace some spell books dropped by mobs and found in library ruins with ruined spell books 2020-09-09 23:22:56 +01:00
Electroblob77 0981768c72 Drop a few more ruined spell books into the sea, and make them stack to 16 2020-09-09 23:13:33 +01:00
Electroblob77 70a55d1175 Chuck more ruined spell books into the ocean, and fish all the master spells back out 2020-09-09 22:40:55 +01:00
Electroblob77 7ae041595a Gone fishin' 🐟🐠🐡
Add spell books and ruined spell books to treasure and junk fishing loot respectively
2020-09-09 22:36:07 +01:00
Electroblob77 ac14c8f931 Add ruined spell book item (usage will be added later) 2020-09-06 23:24:36 +01:00
Electroblob77 e147ce5d37 Intimidate should be an alteration spell 2020-09-06 18:32:45 +01:00
Electroblob77 472727552e Fix CME in remove curse 2020-09-06 18:23:41 +01:00
Electroblob77 373ab0c3dc Handy as the search tips are, maybe we shouldn't show them *everywhere*... 2020-08-30 00:26:20 +01:00
Electroblob77 5bca261582 Add tip-top tooltip with top tips for snazzy super-speedy spell searching system
And confusingly convoluted commit comments
2020-08-30 00:06:01 +01:00
Electroblob77 99f71874c0 Various fixes for artefact loot tables 2020-08-28 23:51:55 +01:00
Electroblob77 1c8011ff74 It never fails to amaze me how many things that should never be null somehow end up being null for one single user... 2020-08-24 21:22:10 +01:00
Electroblob77 f9cd90bd49 Better layout 2020-08-22 00:01:11 +01:00
Electroblob77 988596075c More updates to the handbook 2020-08-21 23:53:55 +01:00
Electroblob77 2b27729062 Hey lectern, stop doing that, it's really annoying 2020-08-21 23:27:57 +01:00
Electroblob77 dac40ecf98 Extend mind control overlay effect to possessed creatures 2020-08-21 23:24:18 +01:00
Electroblob77 c48b4ea0fe Shorten description for withering totem 2020-08-21 23:23:17 +01:00
Electroblob77 7380da7b5e Update wizard's handbook and tidy up embedded image naming convention 2020-08-21 00:34:04 +01:00
Electroblob77 815bcf176c Retexture forest of thorns icon 2020-08-21 00:08:47 +01:00
Electroblob77 ba487bea41 Add withering totem spell 2020-08-21 00:08:31 +01:00
Electroblob77 6cdff07180 Derp 2020-08-16 00:21:39 +01:00
Electroblob77 87705f7e4b Add localisations for radiant totem entity 2020-08-15 23:58:17 +01:00
Electroblob77 c90ec248cd Still need to check this, since not being allied and being a valid target are not necessarily equivalent 2020-08-15 23:21:32 +01:00
Electroblob77 0c046e8c29 Add elemental crystal and crystal block recipes to imbuement altar 2020-08-15 23:09:57 +01:00
Electroblob77 b7a503e5c4 Add sound for mark sacrifice 2020-08-13 22:45:57 +01:00
Electroblob77 aaf5f1ff71 Automatic item model registry, because I'm fed up with registering all my items twice 2020-08-13 22:23:58 +01:00
Electroblob77 a5dd5ce9df Add evoker's ring 2020-08-09 23:23:12 +01:00
Electroblob77 b08e5e1d96 Add chapter on library ruins to wizards handbook 2020-08-09 22:47:41 +01:00
Electroblob77 b6bda04a7a Better advancement description 2020-08-08 22:02:54 +01:00
Electroblob77 1cf5808f4f So many things to fix... 2020-08-03 22:47:26 +01:00
Electroblob77 7401a8e3b4 First pass trying to optimise LivingUpdateEvent handlers, see issue #484 2020-08-03 22:47:08 +01:00
Electroblob c3ca12edb9 Merge pull request #483 from Determancer/patch-1
Fix an error in en_us and sync it to zh_cn
2020-08-03 22:00:28 +01:00
Electroblob77 9d8b0b3a90 Add advancements for library update features 2020-08-01 23:24:33 +01:00
Determancer 0a75e34f3f Update en_us.lang 2020-08-01 20:49:11 +08:00
Determancer 2f0fd9fd7b Update zh_cn.lang
error fix sync
2020-08-01 20:30:08 +08:00
Electroblob77 0d7d36c0b5 Add mark sacrifice spell 2020-07-30 22:54:37 +01:00
Electroblob77 a321e4ef66 Add Russian handbook translations, courtesy of MugGod2 2020-07-30 21:55:44 +01:00
Electroblob77 041f54352c Forgot that bit :/ 2020-07-30 21:54:55 +01:00
Electroblob77 09cc0a5c34 Actually make ward do something... oops :0 2020-07-27 23:49:20 +01:00
Electroblob 1e4117fcab Update CONTRIBUTING.md 2020-07-27 14:12:00 +01:00
Electroblob cfb537dc0f Merge pull request #479 from xinyuan-liu/1.12.2
USE UTF-8 TO DECODE EVERYTHING AS ANY OTHER MODS DOES!
2020-07-27 13:33:58 +01:00
Electroblob77 e5e01dca88 Client event handlers should be specified as such! 2020-07-27 13:10:05 +01:00
Electroblob77 eba219bcce Add getter for SpellBuff#potionSet 2020-07-27 12:32:05 +01:00
xinyuan liu 8632d71ed6 One more thing 2020-07-27 18:50:56 +08:00
xinyuan liu 5e0d096ec0 USE UTF-8 instead of gbk. 2020-07-27 17:24:21 +08:00
xinyuan liu 7c463c9eb9 Use UTF-8 too. 2020-07-27 17:15:14 +08:00
xinyuan liu cd83bbb67d Use UTF-8 to decode EVERYTHING! 2020-07-27 17:13:23 +08:00
Electroblob77 476b7a6a45 Add more users to donation perks 2020-07-23 23:03:22 +01:00
Electroblob77 e4290598d5 Tweak colours 2020-07-19 16:07:54 +01:00
Electroblob77 3343385a7c Add donor perks and tweak generalise rendering of healing totem 2020-07-19 15:56:07 +01:00
Electroblob77 a831c2ada3 Separate surface and underground library marker options 2020-07-15 00:30:08 +01:00
Electroblob77 a945201cec Use the same test in the new spell icon as the new spell book tooltip 2020-07-15 00:21:37 +01:00
Electroblob77 2e3df272ec Eliminate ALL cascading worldgen lag, with the following changes:
- Offset structures by minus half their width in x/z (as well as the usual +8), so they can't ever spill out of the 2x2 chunk area being generated (provided they are less than 16 blocks wide, which mine are)
- Pass the block placement flags 16 | 2 to Template#addBlocksToWorld instead of just 2, to prevent neighbour updates
- Ignore unloaded blocks when removing floating trees (in theory there can't be trees there anyway)
2020-07-13 21:38:37 +01:00
Electroblob77 ded4caca2f Tweak bookshelf model texture for special wand upgrades 2020-07-13 16:54:48 +01:00
Electroblob77 a12fc6e344 TODOs and cleanup 2020-07-13 16:54:13 +01:00
Electroblob77 fa0875e63b Add library ruins
- Adds two variants of library ruins: surface (generates in forested biomes) and underground (generates everywhere)
- Adds loot table support to bookshelves
- Adds antique atlas markers for library ruins
- Adds bookshelves and lecterns to the wood type template processor
- Makes bookshelves and lecterns rotate correctly in structure templates
- Generalises most of the methods in WorldGenSurfaceStructure to a new superclass WorldGenWizardryStructure
2020-07-13 16:51:01 +01:00
Electroblob77 05d33ec58e Fix broken encoding for traditional Chinese translations courtesy of alan 67160, fixes #440 2020-07-09 18:29:29 +01:00
Electroblob77 7013cffeaa Allow scrolls to be placed in bookshelves and add in-world textures for them 2020-07-07 00:19:36 +01:00
Electroblob77 a1a5af034d Make owned entities inherit their owner's allies (as well as their own - if, for example, you summon a mob that then summons its own mob, that mob will no longer attack you) 2020-07-06 23:02:03 +01:00
Electroblob77 9aac386ec9 Last few tweaks to make bookshelf loot generation work properly 2020-07-06 22:54:10 +01:00
Electroblob77 651eb8834b Make sure ParticleBuilder warnings only trigger when appropriate, plus misc cleanup 2020-07-06 22:53:10 +01:00
Electroblob77 48221582c3 Move archivist's eyeglass code inside null check, fixes NPE when generating loot 2020-07-06 17:47:03 +01:00
Electroblob77 e04e1e70af Change TileEntityBookshelf to extend TileEntityLockableLoot, allowing it to generate loot from a loot table when opened 2020-07-06 17:46:14 +01:00
Electroblob77 a78a4147db Fix summon animation being stuck on frame 0 for permanent summoned creatures 2020-07-06 15:18:10 +01:00
Electroblob77 657a014cae Boulder sound and credits 2020-07-06 12:09:56 +01:00
Electroblob77 de7226f792 Various tweaks to boulder 2020-07-05 15:46:49 +01:00
Electroblob77 22a125d720 Add boulder spell 2020-07-05 00:39:06 +01:00
Electroblob77 8ae6bc9102 Tidy up entity geometry stuff:
- Add a getCentre method for entities to GeometryUtils
- Replace getPositionEyes(0) with getPositionEyes(1) since it's more efficient, and by definition they must be the same
- Remove all the silly getEntityBoundingBox().minY stuff, this bug has been fixed since 1.8! (which begs the question: if it was considered a bug, how on earth did it go unfixed for that long?)
- A few other small things
2020-07-04 13:34:11 +01:00
Electroblob77 3f19e89b91 Add bonus special upgrade slots to non-elemental wands 2020-07-03 12:30:40 +01:00
Electroblob77 399c3017ad Downgrade talisman of transformation to uncommon 2020-07-03 12:05:14 +01:00
Electroblob77 183d5a2416 Add demonic seal 2020-07-03 12:04:48 +01:00
Electroblob77 ddd67c6034 Defaults should be true 2020-07-02 23:47:44 +01:00
Electroblob77 202552a967 Add cursed helm 2020-07-02 23:47:36 +01:00
Electroblob77 9d3439b25c Rename no icon skin to compact 2020-07-02 21:51:39 +01:00
Electroblob77 b6ccee010b Add config options to show/hide spell HUD and charge meter 2020-07-02 17:28:02 +01:00
Electroblob77 02ab4a9014 Make all radiant damage set fire to undead entities 2020-06-30 16:10:46 +01:00
Electroblob77 429f74393e Fix sixth sense colour 2020-06-30 15:53:25 +01:00
Electroblob77 a547b3a384 Fix spirit horse dispel sound/behaviour 2020-06-30 15:53:15 +01:00
Electroblob77 8e2b367e94 More mind control fixes 2020-06-30 15:38:00 +01:00
Electroblob77 ea6d338d71 Fix a stack overflow 2020-06-30 15:25:21 +01:00
Electroblob77 c2396bcd5e Fix NPE 2020-06-30 15:17:35 +01:00
Electroblob77 4e0b63f06b Apply lightning bolt changes to thunderstorm 2020-06-30 15:12:37 +01:00
Electroblob77 323b1e1799 Make fangs ignore allies 2020-06-30 15:11:54 +01:00
Electroblob77 148f527504 Damage modifier support for vanilla entities (throwables, shulker bullet and fangs) 2020-06-30 15:11:27 +01:00
Electroblob77 6a8951ab39 Event priority 2020-06-30 14:06:41 +01:00
Electroblob77 b76374fb58 Make lightning bolt count as player damage and support damage modifiers 2020-06-30 14:06:27 +01:00
Electroblob77 c435ca5fa7 Allow fangs to be cast by npcs and dispensers 2020-06-30 00:04:29 +01:00
Electroblob77 c9735e9a98 Prevent casting fangs directly down or up 2020-06-30 00:02:49 +01:00
Electroblob77 0400e9276d Normalise direction vectors 2020-06-29 23:56:45 +01:00
Electroblob77 632790fabd Don't spawn fangs at the caster's feet 2020-06-29 23:54:05 +01:00
Electroblob77 b61bbda668 Fix radiant totem sound causing a CME 2020-06-29 23:52:41 +01:00
Electroblob77 c2e99e2ce6 Add fangs spell 2020-06-29 23:52:05 +01:00
Electroblob77 cfca8f1fdd Also apply targeting fix when mind control effect is removed manually 2020-06-29 21:28:32 +01:00
Electroblob77 b0d44738c7 Refactoring and cleanup 2020-06-29 21:26:04 +01:00
Electroblob77 8088e21ba4 Remove attack target as soon as mind control wears off, fixes mind controlled entities continuing to attack a target that dies after the mind control wears off 2020-06-29 21:22:01 +01:00
Electroblob77 68dad2a148 Add mind control overlay 2020-06-29 21:16:10 +01:00
Electroblob77 a25b642164 Add sounds to radiant totem and update sounds for ray of purification 2020-06-29 18:43:54 +01:00
Electroblob77 b37fa47211 Tweaks to firestorm and ice age particles and sound 2020-06-29 18:43:07 +01:00
Electroblob77 aea65b3753 World#isBlockFullCube is different to Block#isFullCube, and it turns out we actually want Block#isNormalCube :/ 2020-06-28 20:22:27 +01:00
Electroblob77 3a68ba8927 Implement blast modifier support for all applicable constructs, plus misc construct-related cleanup and fixes 2020-06-28 16:56:18 +01:00
Electroblob77 97c21b5057 Remove unnecessary reflection 2020-06-28 14:56:35 +01:00
Electroblob77 5be939a39f Add key aliases to spell matching 2020-06-28 12:45:54 +01:00
Electroblob77 080022127c Add radiant totem spell 2020-06-26 17:46:47 +01:00
Electroblob eb017c01a9 Update README.md 2020-06-26 14:57:56 +01:00
Electroblob77 1ea6355a9e Update Discord link 2020-06-26 14:55:26 +01:00
Electroblob77 f6f766c5b6 Convert firestorm sound to mono 2020-06-25 14:06:45 +01:00
Electroblob77 d8bf437214 Update advancements with new spells and artefacts 2020-06-25 13:22:35 +01:00
Electroblob77 5dc3ebed4f Add firestorm spell 2020-06-25 13:21:26 +01:00
Electroblob77 43690ace29 Trigger unlock of tiers handbook section when a wand levels up, in addition to finding a tome of arcana 2020-06-25 11:24:28 +01:00
Electroblob77 e6696a1758 Add comparator output for receptacles 2020-06-24 16:01:56 +01:00
Electroblob77 93b0aa948f Disable depth mask for magical light rendering 2020-06-23 23:44:44 +01:00
Electroblob77 439faf425f Fix random spell loot function working in reverse 2020-06-23 22:09:30 +01:00
Electroblob77 33c5f79ed7 Add archivist's eyeglass and spectral tether, plus some improvements to teleportation 2020-06-23 22:09:06 +01:00
Electroblob77 0ca86eb01b Improve javadoc for RayTracer 2020-06-23 13:25:10 +01:00
Electroblob77 d69b736a72 Fix shockwave not casting with no targets within range 2020-06-20 22:54:32 +01:00
Electroblob77 ac4bb8bc11 Shady particles 2020-06-20 22:47:55 +01:00
Electroblob77 fbf8e7155c Cleanup 2020-06-20 21:50:22 +01:00
Electroblob77 f2de40e096 Put these arguments the right way round 2020-06-20 21:50:12 +01:00
Electroblob77 c6a3f090cd Add blinding flash spell 2020-06-20 21:43:10 +01:00
Electroblob77 46a467de46 Finish implementing SpellAreaEffect and retrofit various spell classes to extend it 2020-06-20 21:42:37 +01:00
Electroblob77 62b06f8fc6 Remove stray javadoc 2020-06-20 21:40:52 +01:00
Electroblob77 f18f1d20f3 Make NPCs respect continuous spell cooldowns 2020-06-20 18:35:43 +01:00
Electroblob77 a88aa57ef0 Use the more concise method 2020-06-20 18:35:15 +01:00
Electroblob77 ba1ed773af Increase distance for blindness tweak 2020-06-20 18:34:42 +01:00
Electroblob77 76f2145072 Remove hardcoded full brightness for flash particles 2020-06-20 13:27:01 +01:00
Electroblob77 ba856346a9 Should be @Nullable 2020-06-20 13:22:46 +01:00
Electroblob77 39e33848aa Rename to getLivingWithinRadius for clarity 2020-06-20 13:14:16 +01:00
Electroblob77 dfe6ecadac Generalise isAllied to all living entities 2020-06-20 13:10:44 +01:00
Electroblob77 e9093b9360 FastTESRs are a thing, they might be useful... 2020-06-20 13:10:16 +01:00
Electroblob77 cbc778bff7 Centralise some more particle stuff, still not fixed though :( 2020-06-20 13:08:55 +01:00
Electroblob77 b65709fca4 Add blindness tweak and stop smoke bombs giving the mind trick effect 2020-06-20 13:08:16 +01:00
Electroblob77 d45bdbc3d0 Reinstate arm swinging for ray spells with extra action check 2020-06-19 22:40:02 +01:00
Electroblob77 50f0072c7a Prevent forest of thorns overwriting blocks 2020-06-19 21:52:38 +01:00
Electroblob77 c443e0d39c Don't transfer slow time when possession ends, fixes #459 2020-06-19 21:36:29 +01:00
Electroblob77 14483629e5 Fade growth sound in and out 2020-06-19 21:08:32 +01:00
Electroblob77 3a5a97c6b9 Add potency modifier support for forest of thorns 2020-06-19 21:03:35 +01:00
Electroblob77 9936388600 Sync snare too 2020-06-19 21:03:12 +01:00
Electroblob77 6aacebcc74 Stop setting the block each tick to make thorns grow and do it properly in the tile entity and getActualState
Also fixes ownerless thorns not dealing damage and removes knockback
2020-06-19 20:46:46 +01:00
Electroblob77 c842fef2f7 Remove unnecessary tile entity from upper thorn blocks, and reminder to do the same for statue blocks 2020-06-19 16:37:03 +01:00
Electroblob77 a87eca3bd8 Store the caster UUID regardless of whether the entity actually exists, and only read the UUID if it exists in the tag compound 2020-06-19 16:33:57 +01:00
Electroblob77 daf174ec3f Remove unused summon particles, we have a fancier layer system now :D 2020-06-18 18:04:49 +01:00
Electroblob77 7afcdce21e Fix some particle weirdness (somehow the interp pos is wrong by the time it gets to fx layer 3) 2020-06-18 17:42:16 +01:00
Electroblob77 3bc2ff2853 Cleanup 2020-06-18 16:27:09 +01:00
Electroblob77 f7f9190227 For some reason getTotalWorldTime isn't incrementing client-side in some cases when the doDaylightCycle is off, so replace them with alternatives wherever possible
What's really weird is sometimes it works just fine, even in client-side stuff
2020-06-18 16:20:10 +01:00
Electroblob77 bfd7f6e5a5 Improvements to sound loops to try and remove gaps between parts 2020-06-18 15:41:04 +01:00
Electroblob77 8e8e249426 Add imbuement altar
- Adds imbuement altar block and associated tile entity
- Adds basic functionality for imbuing wizard armour (other stuff to be decided)
- Incorporates imbuement altar into glowing overlay model event (this could do with being tidied up and generalised)
- Adds a TESR for the ray effect (based on some of the oldest code in the entire mod, which definitely needs improving!)
- Adds a simple sound effect for the imbuement process, needs upgrading to a ticked sound later
2020-06-17 23:44:02 +01:00
Electroblob77 99d0d115c7 Retexture earth crystals 2020-06-17 23:12:25 +01:00
Electroblob77 798c015944 Retexture ice giant 2020-06-14 18:39:38 +01:00
Electroblob77 732621f37c Fix invisible entities showing the frost layer 2020-06-14 14:54:41 +01:00
Electroblob77 238b9d04bb Split up and reorganise WizardryUtilities 2020-06-13 23:29:01 +01:00
Electroblob77 57e96458d5 Fix squelch sound not playing for the slime spell 2020-06-13 17:24:41 +01:00
Electroblob77 9dbdd2b830 Sort out various problems with freezing things, fixes #460 2020-06-13 17:23:50 +01:00
Electroblob77 d60238a400 Remove animation from magic slime 2020-06-13 14:14:46 +01:00
Electroblob77 7319651ac4 Blacklist decoys from being possessed 2020-06-13 12:55:20 +01:00
Electroblob77 36a228489b Limit currency item stack size to between 1 and 64 (inclusive) 2020-06-13 12:45:27 +01:00
Electroblob77 27e9b1d6f2 Add play sound call to empowering presence, fixes #454 2020-06-13 12:21:03 +01:00
Electroblob77 4bf8aff2e6 Make ice age give frostbite II to players for 20 seconds 2020-06-12 23:31:50 +01:00
Electroblob77 1c0e046236 Snowstorms! 2020-06-12 23:27:20 +01:00
Electroblob77 a65c56eb41 Mooore smoooooth animations 2020-06-12 23:12:37 +01:00
Electroblob77 00f958a71e Increase volume of charge up sound 2020-06-12 22:20:43 +01:00
Electroblob77 8aadf5a446 Various improvements to sounds
- Added several new sounds, mostly for ice spells
- Added automatic registering of sound events
- Finally fixed the frost ray and wall of frost sounds
- Removed a few unused sound files
2020-06-12 22:15:44 +01:00
Electroblob77 a344011486 Limit the number of blocks black hole can unhook per tick 2020-06-12 14:34:31 +01:00
Electroblob77 a17a20fe8b Add spell charge-up sound 2020-06-12 14:28:37 +01:00
Electroblob77 ee56aa50be Cleanup 2020-06-12 13:48:21 +01:00
Electroblob77 b4b32d52e3 Update credits 2020-06-12 13:09:01 +01:00
Electroblob77 526dbaf396 Make isCasting account for charge up 2020-06-12 12:55:50 +01:00
Electroblob77 737f896070 Add support for charge-up modifiers 2020-06-11 22:49:08 +01:00
Electroblob77 fb56190f6f Allow the cooldown bar to render properly for continuous spells 2020-06-11 22:23:15 +01:00
Electroblob77 c4ac1d7e6c Add cooldowns for more powerful continuous spells 2020-06-11 22:20:58 +01:00
Electroblob77 7d650ebbc3 Add charge-up mechanic for more powerful spells
- Implements spell charge-up in ItemWand
- Assigns chargeup values in json files for spells that should have one
- Adds a charge meter to the crosshair in first-person
- Updates some javadoc comments appropriately
2020-06-11 22:20:04 +01:00
Electroblob77 72971b5f16 Fix continuous scrolls not tracking spell modifiers properly 2020-06-11 22:11:34 +01:00
Electroblob77 937c791196 Goddamnit MCP, neither of these two methods do what the comments say they do! 2020-06-09 23:25:30 +01:00
Electroblob77 3348938d46 Finally got the animation timings right 2020-06-09 17:55:04 +01:00
Electroblob77 f95819cf37 Only show new spell message in survival with discovery mode on 2020-06-09 17:43:39 +01:00
Electroblob77 9563d730bd Remove various unused textures 2020-06-09 17:28:46 +01:00
Electroblob77 5be8c8ed36 This should be in here 2020-06-09 17:15:48 +01:00
Electroblob77 38b6643d1d Optimise imports 2020-06-09 17:08:25 +01:00
Electroblob77 038ead0d55 Tidy up 2020-06-09 17:07:36 +01:00
Electroblob77 a4d342caa1 Nudge the zombies 2020-06-09 17:01:17 +01:00
Electroblob77 c00c04acd2 Must've missed that one 2020-06-09 16:55:28 +01:00
Electroblob77 7772f2e97f Add new spell indicator icon and tooltip to the wizard trade GUI 2020-06-09 16:55:13 +01:00
Electroblob77 99a9524ee7 Add config option to disable player animations 2020-06-07 23:05:50 +01:00
Electroblob77 840ef3b3a5 Cleanup 2020-06-06 23:40:20 +01:00
Electroblob77 009321d905 Some more cleanup 2020-06-06 23:30:24 +01:00
Electroblob77 1a094e1970 Reorganise and clean up client event handlers 2020-06-06 23:25:56 +01:00
Electroblob77 6df0d2dc6e Allow permanent constructs to be dispelled by shift-right-clicking with any wand 2020-06-06 22:16:39 +01:00
Electroblob77 5011246e79 Don't disable depth 2020-06-05 17:12:45 +01:00
Electroblob77 c8e07cf857 Make zombie apocalypse account for ceilings 2020-06-05 17:12:31 +01:00
Electroblob77 a54f00875f Add disintegrate animation, plus misc tweaks to disintegration 2020-06-05 17:11:19 +01:00
Electroblob77 ce92d564f4 Cleanup 2020-06-04 23:16:43 +01:00
Electroblob77 afabcbde49 Huskpocalypse! 2020-06-04 23:02:29 +01:00
Electroblob77 88d0780d69 Sort out summoned creature particles 2020-06-04 22:48:35 +01:00
Electroblob77 33d4652758 Add summoned creature appear/disappear animation 2020-06-04 22:45:39 +01:00
Electroblob77 09967ac256 This was indeed no longer necessary - presumably a hangover from older versions 2020-06-04 15:53:16 +01:00
Electroblob77 aa84b2b8cd Introduce abstract superclass for LayerFrost and LayerStone, and fix some weirdness in the process 2020-06-04 15:35:50 +01:00
Electroblob77 a8f1ac38fa Derp 2020-06-04 14:50:02 +01:00
Electroblob77 d11c3fcc2f Carry excess progression over when upgrading 2020-06-04 12:37:57 +01:00
Electroblob77 92b54edb4a Add 1.5x progression modifier for tiers the player has already reached 2020-06-04 12:27:10 +01:00
Electroblob77 e54453e6c6 Animation tweak 2020-06-04 12:07:48 +01:00
Electroblob77 c7e7bb5c25 Move conjure armour to sorcery 2020-06-03 23:16:12 +01:00
Electroblob77 596a17453d Reduce jump strength with the frostbite effect 2020-06-03 21:24:19 +01:00
Electroblob77 70a3dee588 Animate bottled thundercloud texture 2020-06-03 21:23:57 +01:00
Electroblob77 b4fc50ad71 Add amulet of vitality 2020-06-02 23:41:16 +01:00
Electroblob77 930ad77db5 ...well this is embarrassing :/ 2020-06-02 23:12:42 +01:00
Electroblob77 20de12792f Update banner textures 2020-06-01 23:21:12 +01:00
Electroblob77 6eaccb9976 Fix permanent magic light rendering 2020-06-01 22:56:20 +01:00
Electroblob77 a877275916 Add Hungarian translations, courtesy of Bombadil 2020-06-01 22:50:57 +01:00
Electroblob77 e4e8e0a444 Add elemental banner patterns 2020-06-01 22:34:53 +01:00
Electroblob77 ef222e66f2 Change arcane jammer so it only has a chance of preventing spells 2020-05-31 23:16:57 +01:00
Electroblob77 31eed1cb48 Add 'glitch' effect to spell HUD when arcane jammed 2020-05-31 21:15:21 +01:00
Electroblob77 0cd61b758e More tweaks 2020-05-31 19:03:24 +01:00
Electroblob77 4ef54cf8cb Add sounds to zombie apocalypse spell, plus misc tweaks 2020-05-31 18:47:24 +01:00
Electroblob77 5066439fef Cleanup 2020-05-31 17:34:21 +01:00
Electroblob77 dd12d2ebcb Hide zombie particles properly 2020-05-31 17:31:31 +01:00
Electroblob77 cfdda5716d Smooooooth animations 2020-05-31 17:22:23 +01:00
Electroblob77 a33715ad51 Add zombie apocalypse spell 2020-05-31 17:16:55 +01:00
Electroblob77 05aac02966 A good ol' splash of optimise imports 2020-05-24 23:59:13 +01:00
Electroblob77 1af0186886 Add config options for disabling specific artefacts 2020-05-24 23:58:20 +01:00
Electroblob77 3e0dbb9755 It's about time we sorted out all these translations 2020-05-24 23:57:46 +01:00
Electroblob77 d9f7d94115 Remove unused translation keys 2020-05-24 22:55:51 +01:00
Electroblob77 94f4e680af Sync tile entities with casters properly, and tidy up a few other related things 2020-05-24 22:09:09 +01:00
Electroblob77 e17b5d2300 Remove incorrect !world.isRemote check and redundant constructor, fixes #446 2020-05-23 21:04:29 +01:00
Electroblob77 601f8a97fa Helps if you actually save the settings... 2020-05-22 18:08:05 +01:00
Electroblob77 e6b7f25932 Apparently the default is false 2020-05-22 17:57:17 +01:00
Electroblob77 6c08b21f7f More accurate descriptions, and make it synchronised 2020-05-22 17:54:53 +01:00
Electroblob77 d22c530f79 Default value should be false 2020-05-22 17:37:58 +01:00
Electroblob77 ddcaffc1b1 Add config option to treat passive creatures as allies 2020-05-22 17:34:07 +01:00
Electroblob77 6696be59a4 Allow crystal flowers to be placed in flower pots 2020-05-22 16:43:24 +01:00
Electroblob77 e1df468d93 Change remnant spawn egg colours 2020-05-22 12:52:55 +01:00
Electroblob77 5a57e8341a Add icarus medallion and void opal 2020-05-22 12:49:45 +01:00
Electroblob77 dd137c68f6 Make remnants spawn from obelisk spawners (bye bye mobelisks o/) 2020-05-21 20:55:10 +01:00
Electroblob77 1275f1d31f Add remnants 2020-05-21 18:40:01 +01:00
Electroblob 27d53b4e93 Update README.md 2020-05-21 14:15:18 +01:00
Electroblob 46691e9934 Update README.md 2020-05-21 14:14:49 +01:00
Electroblob77 30f2a99a2c Not sure what was going on here 2020-05-19 22:08:36 +01:00
Electroblob77 650344a0c8 Add stormcloud spell 2020-05-18 20:41:41 +01:00
Electroblob77 ebde514c98 Fix scrolls not triggering spell casting finish method and event 2020-05-17 00:35:56 +01:00
Electroblob77 4739d9f9fc Add cooldowns (using the vanilla mechanic) to various consumable items 2020-05-17 00:32:02 +01:00
Electroblob77 ef39757229 Add right-click use for mana flasks - right-click while holding a mana flask to charge the emptiest item from the hotbar, offhand or armour slots 2020-05-17 00:04:38 +01:00
Electroblob77 e09f9313f9 This is nullable 2020-05-16 23:35:23 +01:00
Electroblob77 94a17a63c1 Sync tile entity when book texture changes 2020-05-16 22:24:14 +01:00
Electroblob77 594c546f11 Make all valid books work with shift-clicking and hopper insertion 2020-05-16 18:33:53 +01:00
Electroblob77 cda9947e17 All synchronised settings require world restart! 2020-05-16 18:26:59 +01:00
Electroblob77 48a350b63a Allow any book to be placed in a bookshelf
- Modifies the bookshelf model and blockstate to choose a texture dynamically based on the book item
- Changes bookshelf slots to accept all books from wizardry and vanilla minecraft by default
- Adds a couple of hooks to allow addons to register their own book items and model textures
- Adds a config option to allow modpack makers to add more book items
2020-05-15 22:52:32 +01:00
Electroblob77 28da6810d7 Oops 2020-05-15 21:21:21 +01:00
Electroblob77 f5ce186a7d Well this hasn't been looked at in a while 2020-05-15 20:30:56 +01:00
Electroblob77 04bebe5910 Allow receptacles to be ignited using dispensers 2020-05-14 17:20:19 +01:00
Electroblob77 fe5060a2c0 Don't decrement spell index if spells haven't been initialised, and add the missing safety check to getCurrentMaxCooldown - fixes #428 2020-05-13 12:06:41 +01:00
Electroblob 8de990fdde Merge pull request #439 from TUsama/1.12.2
update lang file and book
2020-05-13 11:18:42 +01:00
TUsama 8a92773a17 fix some problems 2020-05-13 12:06:02 +08:00
TUsama 9f8b2fee1e update lang file and book
resolve2

转码以及修改了部分标点符号

update lang file and book
2020-05-13 10:20:50 +08:00
Electroblob77 9205f082f1 Rename texture variable to something more sensible 2020-05-12 23:56:36 +01:00
Electroblob77 ff4c17d1c1 Add crafting recipe for receptacle 2020-05-12 23:49:18 +01:00
Electroblob77 34a4609af2 Tweak receptacle model 2020-05-12 23:46:05 +01:00
Electroblob77 25475632d9 Require line-of-sight for summoning spells 2020-05-12 23:28:05 +01:00
Electroblob77 bfc23ce6f7 Remove a bunch of deprecated methods 2020-05-12 23:09:48 +01:00
Electroblob77 a97abd26d0 Add receptacles 2020-05-11 18:42:00 +01:00
Electroblob77 11821ff14d Apparently we don't need this any more 2020-05-11 18:38:18 +01:00
Electroblob77 5c34b379d1 Update French translations, courtesy of Crowller 2020-05-11 18:36:58 +01:00
Electroblob77 c4d4c67302 Well this is awkward :/ 2020-05-11 18:35:37 +01:00
Electroblob77 c04ee35fc3 Helps if you actually define the curative items... fixes #435 2020-05-11 18:29:32 +01:00
Electroblob77 09b52a4586 Reorganise block registry 2020-05-10 16:21:24 +01:00
Electroblob77 1f9f5a1cc5 Add spectral dust 2020-05-10 11:10:52 +01:00
Electroblob77 be250e218e Add player animation system!
- Hooks into ModelRenderer by wrapping it in an extended version that allows modification of angles after the model has set them
- Is compatible with pretty much everything, yay (even modded armour!)
- Adds property overrides to ItemWand so that gets animated too
- Adds a system for generating override models from a template at runtime so I don't have to duplicate all the wand models
- Tweaks particles and ray spells so they line up with the end of the newly-animated wand
- Fixes a long-standing bug where wand usage actions would stop immediately for all non-continuous spells
2020-05-09 20:17:15 +01:00
Electroblob77 cf38a16f49 A slightly better way of loading the book model texture 2020-05-07 23:22:52 +01:00
Electroblob77 a31b1c79e3 Make indirect magic damage count as magic damage, fixes #396 2020-05-06 20:21:49 +01:00
Electroblob ad520eff77 Update CONTRIBUTING.md 2020-05-06 12:52:02 +01:00
Electroblob77 0354f99bd2 Make wizardry-specific overloads package-private where possible to avoid confusion 2020-04-25 13:00:40 +01:00
Electroblob77 301ec86c27 Add comparator behaviour to bookshelves 2020-04-22 17:14:21 +01:00
Electroblob77 ee96ff3ddd Reflect into Block#getSilkTouchDrop instead of copying it, fixes #418 2020-04-22 17:13:55 +01:00
Electroblob77 53f545caad Replace use of deprecated ReflectionHelper with ObfuscationReflectionHelper 2020-04-21 23:05:48 +01:00
Electroblob77 755933486c Also prevent these two from being cast through walls 2020-04-21 22:10:55 +01:00
Electroblob77 5d8a90167c Prevent ray spells being cast through walls (oops, my bad :P) 2020-04-21 18:55:58 +01:00
Electroblob77 f89c71f314 Make spell scrolls implement IWorkbenchItem and have 1 slot
This means the book doesn't leave the workbench until the scrolls are taken out, which is good for automation - however, canPlace always returns false so they can't be put back in, kinda like the furnace output
2020-04-21 18:55:13 +01:00
Electroblob77 5ad4cc0610 Fix hoppers putting spell books in hidden slots 2020-04-19 17:41:12 +01:00
Electroblob77 f0752317e6 Add spell quick access keys 2020-04-18 21:45:01 +01:00
Electroblob77 ed63704184 Add descriptions to mana flasks 2020-04-18 21:10:02 +01:00
Electroblob77 3316c8e5cb Note to self: syncing is important 2020-04-18 19:14:47 +01:00
Electroblob77 0a2368650a Tweak particle brightness and lifetime 2020-04-18 18:11:43 +01:00
Electroblob77 b9958ce16f Add cloud particle from TF spell pack, and change smoke bomb to use it instead of vanilla's large_smoke particles 2020-04-18 18:06:22 +01:00
Electroblob77 8cbe5dd602 Assign key conflict contexts to wizardry's keybinds, fixes them showing up as conflicting with GUI keys 2020-04-18 17:12:29 +01:00
Electroblob77 f1cb7dbbbe Make arcane lock work on both halves of a double chest at once 2020-04-18 16:12:05 +01:00
Electroblob77 5f8477a4ad Snowballs were a projectile last time I checked... 2020-04-17 23:56:38 +01:00
Electroblob77 d4c2397a68 Fix lectern model rotation in first person 2020-04-17 23:25:48 +01:00
Electroblob77 a7b608a06e This description was correct in the first place! Turns out it was the upgrading recipes' fault. 2020-04-17 23:16:48 +01:00
Electroblob77 50ad3655c9 IntelliJ is too clever for its own good sometimes 2020-04-17 23:08:58 +01:00
Electroblob77 abc598a722 Remove deprecated fields 2020-04-17 23:03:16 +01:00
Electroblob77 b23136d568 Add method for checking if a spell property exists 2020-04-17 23:02:45 +01:00
Electroblob77 8291373427 Say something a bit more useful about scrolls of identification 2020-04-17 21:53:05 +01:00
Electroblob77 618df1c668 Add descriptions to some wizardry items in JEI
Covers most of the items players might stumble across
2020-04-17 21:49:01 +01:00
Electroblob77 cdc326e36c Remove the none spell from scroll recipes in JEI 2020-04-17 21:42:39 +01:00
Electroblob77 4c024f9e46 Hmmm I hope this incorrect description hasn't resulted in any bugs :/ 2020-04-17 21:38:21 +01:00
Electroblob77 d93b9a6765 Make bottomless provisions work with satiety, and have them trigger as soon as the player has enough hunger to fill 2020-04-16 15:49:10 +01:00
Electroblob77 7b1283c418 Yes it does, I fixed that! 2020-04-16 15:46:50 +01:00
Electroblob77 6882fb4519 Prevent imbuements from showing up on enchanted books in JEI 2020-04-15 23:34:41 +01:00
Electroblob77 57f4704e18 Update Forge 2020-04-15 23:24:06 +01:00
Electroblob77 50ca70b0db Specify JEI and Baubles as dependencies 2020-04-15 23:23:31 +01:00
Electroblob77 821361f9bf Update JEI 2020-04-15 23:11:43 +01:00
Electroblob77 2c05e52912 Update spanish handbook translations, courtesy of Alsentar 2020-04-15 23:02:04 +01:00
Electroblob77 8301a24afe Just enough wizardry!
- Adds JEI support for arcane workbench 'recipes' (charging, upgrading, and scroll enchantment)
- Adds an item transfer handler for said recipes, including bookshelf virtual slot support
- Prevents conjured items from showing up in JEI
2020-04-15 23:01:45 +01:00
Electroblob77 945c789482 Must have missed those 2020-04-15 20:13:36 +01:00
Electroblob77 13ba19c1ff Purple mana bars for wizard robes too! 2020-04-15 18:57:31 +01:00
Electroblob77 9bc920073b Fix animation positions 2020-04-14 23:42:19 +01:00
Electroblob77 df526dc76f Search trees don't like this very much :( 2020-04-14 23:06:49 +01:00
Electroblob77 702398dd34 Fix spell book tooltips not showing up in JEI 2020-04-14 22:33:48 +01:00
Electroblob77 1e5add914e Fix incorrect rounding for whole numbers of crystals 2020-04-14 22:33:12 +01:00
Electroblob77 4980beea87 Wooden things are now more wooden 2020-04-14 18:42:50 +01:00
Electroblob77 91b2ee1a13 Merge branch '1.12.2' into 4.3-dev 2020-04-14 17:41:33 +01:00
Electroblob77 937617d7af Update credits 2020-04-13 22:02:21 +01:00
Electroblob77 94751a6fd5 Remove the debug particle from the divination spell 2020-04-13 21:08:47 +01:00
Electroblob77 01ab50cb27 Make targets dismount whatever they are riding when they get possessed 2020-04-13 21:04:11 +01:00
Electroblob77 d0bcbc8ed8 Let's do this properly, shall we? Fixes #397 2020-04-13 20:53:14 +01:00
Electroblob77 b660b02e0e Fix crash when throwing things with greater telekinesis using commands 2020-04-13 19:10:20 +01:00
Electroblob77 153ea74966 The translators seem to have used exotic characters that require fancy encoding 🤷‍♂️ 2020-04-13 19:07:57 +01:00
Electroblob77 c81830efec Neither of these should be null. I should not have to check they aren't null. But apparently they can be. So I do. Fixes #402. 2020-04-13 19:04:01 +01:00
Electroblob77 6ec2e716cb Register artefact loot tables properly so addon mods can inject loot into them, fixes #403 2020-04-13 19:00:21 +01:00
Electroblob77 96e7c5885b Try to optimise arcane lock rendering, fixes #399 2020-04-13 18:59:07 +01:00
Electroblob77 41d575c9c9 Add config options to disable the screen shake and blink effects
We're all about that accessibility here!
2020-04-13 18:48:30 +01:00
Electroblob77 7f31fc6259 Thanks for warning me, IntelliJ :/ 2020-04-13 18:38:06 +01:00
Electroblob77 817fd26dcf Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2020-04-13 18:35:40 +01:00
Electroblob77 aecc8b0889 Okay it really is fixed now I promise 2020-04-13 17:20:43 +01:00
Electroblob77 b45c202ac5 Add tint to background for book-style GUIs 2020-04-13 15:41:59 +01:00
Electroblob77 16ad8543d8 Purple mana (durability) bar! 2020-04-13 15:32:07 +01:00
Electroblob77 e985bc6f69 Since we're syncing anyway, make the client do a deferred refresh to allow syncing to occur, rather than trying to keep track of prev stacks itself 2020-04-12 23:00:23 +01:00
Electroblob77 8682fcbe91 Only prevent syncing when first loading the world 2020-04-12 22:51:24 +01:00
Electroblob77 e8ca773557 Don't sync when loading from NBT 2020-04-12 21:59:22 +01:00
Electroblob77 c622158818 Fix syncing of everything 2020-04-12 18:35:30 +01:00
Electroblob 7237840a2a Merge pull request #400 from Hokorizero/1.12.2
Update Simplified Chinese Translation
2020-04-12 16:12:18 +01:00
Electroblob77 6254020024 Ugh just why 2020-04-11 00:12:07 +01:00
Electroblob77 1d161e613c Comments 2020-04-10 23:56:00 +01:00
Electroblob77 e8c1b4d581 All the synchronised settings require world restart 2020-04-10 23:55:54 +01:00
Electroblob77 b5f61205eb Implement custom search behaviour for the spells tab, so it works like the bookshelf interface 2020-04-10 23:42:05 +01:00
Electroblob77 6f0636da9f These don't need world restarts! Also I forgot the default values for bookshelf blocks... 2020-04-10 22:49:40 +01:00
Electroblob77 b3fd39c42c Add config options for bookshelf blocks and bookshelf search radius 2020-04-10 22:42:31 +01:00
Electroblob77 40ed431ee2 Fix crash when throwing stuff with greater telekinesis via commands 2020-04-10 16:01:18 +01:00
Electroblob77 15d3d9e70b Arcane workbench tooltip refactoring
- Reorganises the huge amount of code in the draw background/foreground methods into a hierarchical object system
- Makes the tooltip box change height to fit the content
- Adds text wrapping support for items/spells with super long names
- Adds proper format arguments to the mana readout translation
- The tooltip now shows the new spells that will be applied with a flashing animation
2020-04-10 15:56:34 +01:00
Clefal 8ad6b5590b Merge branch '1.12.2' into 1.12.2 2020-04-10 14:03:56 +08:00
Hokorizero 1c2c267e1a Update handbook_zh_cn.json 2020-04-10 12:47:00 +08:00
Hokorizero e45bfb9248 Update zh_cn.lang 2020-04-10 12:45:51 +08:00
Electroblob77 5df98d5b95 Was bound to mess up at least one of them 🙃 2020-04-10 00:21:13 +01:00
Electroblob77 a4fd88f21d Organise texture folders and misc cleanup 2020-04-10 00:17:01 +01:00
Electroblob77 793ba0eb05 Fix the scroll bar 2020-04-09 23:47:03 +01:00
Electroblob77 531700378f Use the correct progression bar width 2020-04-09 23:44:06 +01:00
Electroblob77 4875d5a970 Put excess upgrades onto a second row so they don't go off the edge 2020-04-09 23:33:40 +01:00
Electroblob77 3ff6be4cb0 Ignore empty slot books in the lectern GUI 2020-04-09 23:18:23 +01:00
Electroblob77 c418757042 Hide bookshelf interface when there are no nearby bookshelves 2020-04-09 23:13:05 +01:00
Electroblob77 e272d4f999 Add recipes for lecterns 2020-04-09 21:35:37 +01:00
Electroblob77 c50b344041 Remove usage of deprecated server-side I18n 2020-04-09 21:28:48 +01:00
Electroblob77 bd11c9c759 Cleanup 2020-04-09 21:22:43 +01:00
Electroblob77 f7b678e291 Reminder to fix this 2020-04-09 21:18:56 +01:00
Electroblob77 6cabe7ffd4 Make sure the slot order is retained! 2020-04-09 21:07:32 +01:00
Electroblob77 f973099fd3 Add sound for locating spells using the lectern 2020-04-09 21:07:06 +01:00
Electroblob77 1833ed9c56 Tweak block highlight scale to remove the tiny gap due to the anti-z-fighting offset 2020-04-09 20:09:13 +01:00
Electroblob77 d56cf37f2b Make spell books return to the slots they came from (provided the container isn't closed) 2020-04-09 20:08:28 +01:00
Electroblob77 c5b5172481 Add lecterns 2020-04-08 00:16:12 +01:00
Electroblob77 938d0df95c TODO: Convert magic light to a non-tileentity block 2020-04-05 16:12:46 +01:00
Electroblob77 525b7e13dd Super method should do just fine! 2020-04-05 15:33:40 +01:00
Electroblob77 a67eb2381d Improve bookshelf search and account for undiscovered spells 2020-04-04 21:32:57 +01:00
Clefal 0d48606b51 Merge pull request #4 from Hokorizero/Mineversion
Update zh_cn.lang
2020-04-03 13:21:07 +08:00
Determancer 3c0b65c485 Update zh_cn.lang 2020-04-03 12:15:31 +08:00
Hokorizero 771118afde Merge pull request #2 from Hokorizero/TUsama-patch-2
比对1
2020-04-03 11:49:45 +08:00
Determancer 29b9e0de8b Update zh_cn.lang 2020-04-03 11:45:47 +08:00
Clefal f26f537f50 比对1 2020-04-03 11:40:50 +08:00
Electroblob77 91c9a5392b Make replenish hunger and satiety fill the correct amount of food, and make them say the correct number in their descriptions 2020-03-31 23:16:44 +01:00
Electroblob77 6ae9df1204 Only receive RenderGameOverlayEvent.Post, and only process when it will actually draw something 2020-03-31 23:16:21 +01:00
Electroblob77 d46600ac86 Update version number 2020-03-31 22:06:49 +01:00
Electroblob77 004782a1e4 Update credits 2020-03-31 22:05:00 +01:00
Electroblob77 b2b48cd8a1 Remove old handbook translations 2020-03-31 21:59:02 +01:00
Electroblob77 2277f6b278 Helps if you actually copy the setting over after synchronising it... fixes #395 2020-03-31 21:57:37 +01:00
Electroblob77 ba59d9786f Add null check for grapple target when cast by NPCs, fixes #394 2020-03-31 21:56:20 +01:00
Electroblob77 bdf5aa5b64 Skip spells with missing glyph data and print a warning to the console instead, fixes #384 2020-03-31 21:54:15 +01:00
Electroblob77 a384a57622 Prevent mending enchantment being applied to wizard armour, closes #383 2020-03-31 21:47:53 +01:00
Electroblob77 586840aa53 Add safety checks to prevent itemblocks with invalid metadata turning into invalid blockstates, fixes #382
(Because *some* mod authors are not very careful...)
2020-03-31 21:42:16 +01:00
Electroblob77 1ab674136b Add null check for riding entity to magic slimes, fixes #379 2020-03-31 21:37:38 +01:00
Electroblob77 71302b3219 Add recipes for bookshelves 2020-03-31 21:33:18 +01:00
Electroblob77 c161a74d73 Add bookshelf interface to arcane workbench
Implements the main functionality:
- Access bookshelves from within the workbench
- Search by spell name, tier, element and type
- Sort by tier, element or alphabetically, ascending or descending
- Three-way shift-clicking support
- Automatic return of books to bookshelves when wand is removed
2020-03-31 21:33:10 +01:00
Electroblob77 df1f737539 Fancy new advancement background 2020-03-31 21:26:23 +01:00
Electroblob 64e7e3844e Merge pull request #391 from rafasoares/patch-1
Make Magic Silk recipe use ore_dict for string
2020-03-31 18:14:12 +01:00
Clefal 51a3d2a63e Update zh_cn.lang 2020-03-30 13:42:27 +08:00
Electroblob77 53a053bfff Make replenish hunger and satiety fill the correct amount of food, and make them say the correct number in their descriptions 2020-03-29 17:00:07 +01:00
Electroblob77 220bf15cfb Don't process unless the event type means it will actually draw something 2020-03-29 16:56:52 +01:00
Electroblob77 885e58c85c Receive only RenderGameOverlayEvent.Post, not both 2020-03-29 16:55:04 +01:00
Rafael Soares 7c2e786d0b Remove whitespace changes 2020-03-27 20:53:25 -03:00
Rafael Soares a7ee0ad847 Make Magic Silk recipe use ore_dict for string
Currently, the recipe requires string to be a Vanilla string, which might cause problems in packs with different methods for obtaining strings (eg: Mystical World's Silk Thread from silkworms).

This PR makes it compatible with Ore Dictionary, so the recipe accepts any type of string.
2020-03-27 20:49:51 -03:00
Clefal 033d90ed3e Update zh_cn.lang 2020-03-26 16:39:59 +08:00
Electroblob77 849066de8a Apparently we do need this after all 2020-03-25 15:20:24 +00:00
Electroblob77 eb65b7d7b7 Reorganise config again 2020-03-25 15:14:58 +00:00
Electroblob77 97499eb523 Update version number 2020-03-25 15:08:15 +00:00
Electroblob77 02480db158 Reorganise config file 2020-03-25 15:05:32 +00:00
Electroblob77 e35ee9d126 Merge branch '1.12.2' into 4.3-dev 2020-03-25 14:29:53 +00:00
Electroblob77 004c4c09e3 Add bookshelves 2020-03-25 14:29:27 +00:00
Clefal 52214f81cf Update zh_cn.lang 2020-03-25 11:49:38 +08:00
Clefal 516d7948ee Update zh_cn.lang
附魔
2020-03-25 11:21:18 +08:00
Electroblob77 a490168fa2 Derp 2020-03-19 15:46:42 +00:00
Electroblob77 306137a026 Update version number 2020-03-19 15:38:19 +00:00
Electroblob77 0a5527f3d4 Add backwards compatibility to convert old-format atlas markers to new ones 2020-03-19 15:35:09 +00:00
Electroblob77 4dbe24c8ea This is the problem with everything being a string... 2020-03-19 15:13:25 +00:00
Hokorizero 5477725b7e Update zh_cn.lang 2020-03-19 23:08:18 +08:00
Electroblob77 81bba5e7e0 Add null check to ice spikes, fixes #371 2020-03-19 13:35:36 +00:00
Electroblob77 9c29142e6a Maven-ify all the things and update Antique Atlas 2020-03-19 13:33:34 +00:00
Clefal 3dc3a3a378 二次润色,改掉了所有的“咒语”,修改了部分的语法排序 2020-03-19 11:05:59 +08:00
Electroblob77 3151d7d626 Require Antique Atlas 4.6 or newer 2020-03-18 17:18:41 +00:00
Electroblob77 d68f968632 Make sure fall damage stuff is processed on the server only, and reactivate the config option by default 2020-03-18 16:00:23 +00:00
Electroblob77 74d9198522 Convert replaceVanillaFireballs to a synchronised option, fixes #351 2020-03-18 15:50:01 +00:00
Electroblob77 0b56d47022 Replace wildcard with metadata 0 for display purposes, fixes #370
N.B. The output is still not visible for non-zero inputs when using wildcard trades, but for now this is good enough
2020-03-18 15:32:59 +00:00
Electroblob77 587ab1338e Make Magic Protection protect against vanilla magic damage, closes #337 2020-03-18 14:57:04 +00:00
Electroblob77 4816c48aa6 Disable replaceVanillaFallDamage by default 2020-03-18 14:49:12 +00:00
Hokorizero 2456589fa7 Update zh_cn.lang 2020-03-18 17:27:03 +08:00
Hokorizero d7849a94b1 Update zh_cn.lang 2020-03-18 17:13:11 +08:00
Hokorizero cfb9f4fe25 Update zh_cn.lang 2020-03-18 16:47:49 +08:00
Hokorizero a269cf339b Update zh_cn.lang 2020-03-18 16:20:48 +08:00
Hokorizero 1c8e4f86ee Update zh_cn.lang 2020-03-18 15:35:56 +08:00
Hokorizero f2835c245f Update zh_cn.lang 2020-03-18 15:30:49 +08:00
Hokorizero 462512ad30 Update zh_cn.lang 2020-03-18 15:17:43 +08:00
Hokorizero db5a7dcfde Update zh_cn.lang 2020-03-18 15:13:30 +08:00
Hokorizero 17bba5dea8 Update zh_cn.lang 2020-03-18 15:09:18 +08:00
Clefal fbdb5cd844 医命师修改 2020-03-18 14:58:13 +08:00
Hokorizero 393fb1c1b0 Merge pull request #1 from Hokorizero/润色1
润色
2020-03-18 14:56:42 +08:00
Hokorizero 08e89b1aef Update zh_cn.lang 2020-03-18 14:49:55 +08:00
Clefal 1f25d95b1b 润色 2020-03-18 14:48:27 +08:00
Hokorizero 1f3a71797e Update zh_cn.lang 2020-03-18 14:10:51 +08:00
Clefal a821ef2aef 小修改,图片标题,语法润色 2020-03-18 14:07:57 +08:00
Clefal 6845279c49 手册进度→进度 2020-03-18 13:37:24 +08:00
Electroblob77 79b745e005 Randomise y coordinate to search from when spawning structures in 'cavern' dimensions, fixes #372 2020-03-17 23:54:52 +00:00
Electroblob77 6fff0e31d1 *Facepalm* 2020-03-17 23:45:40 +00:00
Electroblob77 11efe56437 Replace old hardcoded spell book text with translation keys, fixes #368 2020-03-17 23:38:25 +00:00
Electroblob77 7f5786c28c Override override override! 2020-03-17 23:22:54 +00:00
Electroblob77 85b49b330a Make tomes of arcana more common in obelisks, shrines and wizard towers, and make tomes generated as loot more likely to be apprentice tier 2020-03-17 23:16:04 +00:00
Electroblob77 d797e72445 Reduce rarity of all structures a bit 2020-03-17 23:13:17 +00:00
Electroblob77 5f21b565cd Make fireballs, large fireballs and iceballs respect the playerBlockDamage config option 2020-03-17 22:44:30 +00:00
Electroblob77 9ed06c9a34 Stop wizards casting heal ally 2020-03-17 22:34:34 +00:00
Electroblob77 50f315666f Fix spanish handbook translations, fixes #365 2020-03-15 19:23:50 +00:00
Electroblob77 62bdbc81e4 Prevent players from picking up items when possessing and prevent players from possessing whilst sneaking, fixes #376 2020-03-15 19:15:28 +00:00
Electroblob77 d9c3d15b9b Fix gilded wood models and move to wizardry tab 2020-03-01 13:39:59 +00:00
Electroblob77 bb6bb78163 IntelliJ broke my formatting again >:( 2020-03-01 13:07:55 +00:00
Electroblob77 3f80c56163 Add gilded wood 2020-03-01 13:04:15 +00:00
Electroblob77 3a571fd239 Update credits 2020-02-29 11:25:35 +00:00
Electroblob 4fb5452dc4 Merge pull request #363 from chesterccj305/patch-1
Create handbook_zh_tw.json
2020-02-24 16:51:28 +00:00
Electroblob 652f1d2620 Merge pull request #364 from chesterccj305/patch-2
Create zh_tw.lang
2020-02-24 16:51:15 +00:00
Electroblob77 275f514810 Substitute generic damage when caster is null, fixes #362 2020-02-22 11:12:14 +00:00
Electroblob77 7cf09e76f8 Update version number 2020-02-22 00:49:18 +00:00
Electroblob77 61080134fd Add wildcard support for item/block configs 2020-02-22 00:46:37 +00:00
Electroblob77 563bed3b25 Update credits 2020-02-22 00:46:16 +00:00
Electroblob77 75740c388f Add German and Spanish translations 2020-02-22 00:17:52 +00:00
Electroblob77 5d96f4d700 I can't string, and unboxing is weird 2020-02-21 17:55:45 +00:00
Electroblob77 df8fd21c0b Add metadata support to block/item list config options, fixes #353 2020-02-21 17:40:08 +00:00
chesterccj305 046ecb1e41 Create zh_tw.lang 2020-02-21 22:56:45 +08:00
chesterccj305 f3dd7bccd8 Create handbook_zh_tw.json 2020-02-21 22:55:22 +08:00
Electroblob77 d6b64b3576 Move !world.isRemote check to just the block breaking, potentially fixes #359 2020-02-19 21:32:54 +00:00
Electroblob77 22c00c47ff Antique Atlas doesn't like my colons :(
Fixes #323
2020-02-19 21:17:52 +00:00
Electroblob77 6d0e65c2b0 Hmmm so we were ticking this twice all along... 2020-02-19 01:09:12 +00:00
Electroblob77 0a6fd452c1 This is why we test things! 2020-02-19 01:00:32 +00:00
Electroblob77 28a8a4ff2a Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2020-02-19 00:22:24 +00:00
Electroblob77 71c09cf16d Bye bye empty slot books, it was good knowing ya 2020-02-19 00:12:20 +00:00
Electroblob77 794085660e Move screen shaking effect into a proper method in the client proxy, fix earthquake's version not working and add screen shake to meteor, lightning hammer and shockwave 2020-02-19 00:11:33 +00:00
Electroblob 3d89186308 Merge pull request #352 from Hokorizero/1.12.2
Update Chinese item translation and handbook translation
2020-02-09 13:37:10 +00:00
Hokorizero a0bd7b64d7 Enchantment Descriptions translation done 2020-02-07 18:23:40 +08:00
Hokorizero 4c633c98ff Add files via upload 2020-02-05 19:06:34 +08:00
Hokorizero 45ff70c207 Add files via upload
Thanks by @TUsama,we finally finished the Chinese handbook translation.
2020-02-05 19:05:39 +08:00
Electroblob77 0328f41564 Prevent potion core applying its health fix (whatever that is) when resurrecting, fixes #178 2020-01-28 21:19:37 +00:00
Electroblob77 9ab4684aef Update version number 2020-01-28 19:44:27 +00:00
Electroblob77 e64cf9a6af Update credits 2020-01-28 18:44:37 +00:00
Electroblob77 f13f220564 Change tome of arcana description to be more accurate, closes #330. Also adds format args support to multi-line item descriptions and fixes the 1st argument being used instead of the 2nd in the lang files. 2020-01-28 18:36:34 +00:00
Electroblob77 311b5750df Add parrying mechanic to custom fireballs, fixes #335 2020-01-28 18:14:17 +00:00
Electroblob77 e54aee332d Rework slow time to use an NBT tag to unblock entity updates when not in a slow time zone, fixes #336 (and related issues with teleporting)
It also simplifies the code and removes the end slow time packet entirely
2020-01-28 13:20:32 +00:00
Electroblob77 e4bf09f15a Implement client-side spell counter for NPCs, fixes #345
Also makes all the continuous-spell-related methods in ISpellCaster default methods so they don't need implementing unless actually necessary.
2020-01-27 23:27:56 +00:00
Electroblob77 aa166814ea Add SpellThrowable and replace Snowball class with a simple instance of it 2020-01-27 18:40:10 +00:00
Electroblob77 d37ab6072f Add chainable method for assigning spell NPC selector 2020-01-27 17:51:32 +00:00
Electroblob77 ba83cb7985 Add chainable method for assigning spell items 2020-01-27 16:43:05 +00:00
Electroblob77 3052e56d03 Add entity- and tileentity-sensitive versions of Spell#canBeCastByNPCs and Spell#canBeCastByDispensers 2020-01-27 16:42:28 +00:00
Electroblob77 b682740751 *facepalm* 2020-01-27 15:09:54 +00:00
Electroblob77 38429cb697 Update credits 2020-01-27 14:50:55 +00:00
Electroblob77 dc7b6790b8 Automatic spell sound creation, hurrah! 2020-01-27 14:39:47 +00:00
Electroblob77 7a247df3e1 Encourage users to report the circular NBT reference error 2020-01-27 14:33:45 +00:00
Electroblob77 de2087c0e8 Clean up after testing 2020-01-27 13:46:50 +00:00
Electroblob77 f5da195605 Wrap NBTTagCompound#setTag in static helper with safeguards against circular references, fixes #299 2020-01-27 13:45:47 +00:00
Electroblob77 6cd6411c25 Use target lifetime rather than construct lifetime when dealing periodic damage; means targets don't all get damaged at once 2020-01-25 22:50:45 +00:00
Electroblob77 40e77728ad Do proper floaty division, the error was kinda invisible (pun intended) but intellij spotted it 2020-01-21 20:16:59 +00:00
Electroblob77 d50ff5729f Prevent unlimited exponential stacking of the empowerment effect, fixes #317 2020-01-16 18:40:52 +00:00
Electroblob77 76b4f2f72f Change default behaviour of Spell#createSoundWithSuffix to point to assets/modid/sounds.json rather than assets/ebwizardry/sounds.json, so addons don't have to override it 2020-01-14 14:39:09 +00:00
Electroblob77 a608375433 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2020-01-13 18:59:19 +00:00
Electroblob77 c3f8ba245d Fixing the really important bugs
(What? That pixel was annoying me...)
2020-01-13 18:58:21 +00:00
Electroblob77 34b3fe93bb Bit of an oversight there, this is supposed to be an API after all 2020-01-13 18:55:36 +00:00
Electroblob77 996ec9a7f7 Electroblob hit the ground too hard 2020-01-13 18:54:43 +00:00
Electroblob 2b38ca9a89 Merge pull request #331 from bigenergy/patch-2
Update russian lang
2019-12-31 11:02:52 +00:00
Big Energy 67788a2bd8 Ring translation 2019-12-27 20:23:35 +03:00
Big Energy 58fcaa8af2 Update ru_ru.lang 2019-12-27 20:09:30 +03:00
Big Energy 24e89c8b8a Update ru_ru.lang 2019-12-27 20:01:35 +03:00
Big Energy 1293b89905 Update ru_ru.lang 2019-12-27 19:55:41 +03:00
Electroblob77 807fc61541 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-12-22 18:39:45 +00:00
Electroblob77 9741c751b3 Update version number 2019-12-22 18:37:25 +00:00
Electroblob d3003ae473 Merge pull request #311 from Azim-Palmer/1.12.2
Adding support for Lycanites Mobs to drop loot from the mob_additions table
2019-12-22 18:25:52 +00:00
Electroblob77 9fde24f341 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-12-22 15:15:40 +00:00
Electroblob 452eb17b5f Update question.md 2019-12-22 15:13:57 +00:00
Electroblob 36963aac30 Update feature_request.md 2019-12-22 15:13:47 +00:00
Electroblob f161cdfe7c Update bug_report.md 2019-12-22 15:13:36 +00:00
Electroblob77 455c5a5e07 Fix weird floaty rounding so continuous spells cost the correct amount of mana
Grapple ain't free anymore, sorry folks!
2019-12-22 14:58:12 +00:00
Electroblob77 9852f61d0f Extend smoke bomb blindness effect to mobs as well as players, closes #324 2019-12-22 14:37:19 +00:00
Electroblob77 a2c8cde4c4 Use correct mana values for grand crystals and crystal shards in scroll creation 2019-12-22 12:30:04 +00:00
Electroblob77 497d28eafd Somehow this went missing... 2019-12-22 11:45:42 +00:00
Electroblob77 f3f3377c4d Fix formatting 2019-12-17 18:02:15 +00:00
Electroblob77 4c81c61644 Update credits 2019-12-17 18:01:04 +00:00
Electroblob77 31a6ab6db0 Update version number 2019-12-17 17:57:38 +00:00
Electroblob77 69f2aedef7 Correctly hide/unhide skin overlay parts when rendering frost layer, fixes #261 2019-12-17 17:52:44 +00:00
Electroblob77 e8818a4db5 Correct requested tag type for tower blocks list in wizard data loading, fixes #291 2019-12-17 17:45:27 +00:00
Electroblob77 470a7e82bc Iterate over copy of loaded TE list, fixes #298 and #304 2019-12-17 17:12:31 +00:00
Electroblob77 6439c233f1 Add creative mode check to target selector for summoned creatures, fixes #262 2019-12-17 16:55:00 +00:00
Electroblob77 c931d42d62 Tweaks to loot rarity 2019-12-17 16:35:34 +00:00
Electroblob77 5b497e107a Reinstate max damage check, fixes #294 2019-12-17 16:31:42 +00:00
Electroblob77 324094f418 'Tis the season!
- Decked the halls
- Jingled the bells
- Wrapped the presents
- Loaded up the sleigh
2019-12-17 15:53:40 +00:00
Electroblob77 9ade6442b2 Add config option to turn off growing crystal flowers with bonemeal, closes #308 2019-12-16 15:53:32 +00:00
Electroblob77 ffea49bc40 Copy neat fix for negative scaling of magic light on desync to black hole 2019-12-16 15:39:23 +00:00
Electroblob77 2b89a890d0 Route blink effect through the proxies and make the blink spell check for the first-person player, fixes #280 2019-12-16 15:25:15 +00:00
Electroblob77 3a67388ff3 Don't need that 2019-12-16 15:20:15 +00:00
Electroblob77 3468bbb073 Oops 2019-12-16 13:12:24 +00:00
Electroblob77 963178c609 Cleanup 2019-12-16 13:10:57 +00:00
Electroblob77 cfdb049368 Add failsafe for conjured item max damage, fixes #288 2019-12-16 13:06:32 +00:00
Electroblob77 058d83fd00 Stop ring of chaining attacking its wearer, fixes #303 2019-12-16 12:36:37 +00:00
Electroblob77 c7ccc37dca Add damage property to frost axe spell, fixes #322 2019-12-16 12:33:48 +00:00
Electroblob77 74345d0c3b Check if list is empty after removing current location, fixes #307 2019-12-16 12:18:46 +00:00
Electroblob77 907b94c74f Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-12-16 12:14:47 +00:00
Electroblob77 2c6b397be6 Check for null tile entities when rendering arcane lock, fixes #305 2019-12-16 12:14:43 +00:00
Electroblob77 eddcb2402d Don't use client-side-only vector-based AxisAlignedBB constructor, fixes #306 2019-12-16 12:14:01 +00:00
Electroblob 0301f3c300 Merge pull request #312 from Azim-Palmer/Fix/LayerRender
Fix : LayerRender breaks on non-standard models
2019-12-16 00:31:34 +00:00
Electroblob 7a8cfb73cd Merge pull request #319 from UltraHex/1.12.2
Fixes #170
2019-12-16 00:29:47 +00:00
Matthew William Noel c7c6f964bf Fix Electroblob77/Wizardry#170 the right way 2019-12-07 12:46:40 -08:00
Matthew William Noel 91df7cfd72 Fix Electroblob77/Wizardry#170 2019-12-06 19:54:55 -08:00
Az 0ed9ee64c4 Fix : when rendering models that don't have any entries in the boxList (Such as Lycanite's mobs) this function throws and exception and the renderer goes crazy. 2019-11-23 19:25:23 +00:00
Az f82d2871d5 Adding support for Lycanites Mobs to drop loot from the mob_additions table 2019-11-23 12:44:10 +00:00
Electroblob77 01cea3df06 Update version number 2019-10-05 23:14:29 +01:00
Electroblob77 591cfb5857 Check we're dealing with the type of mob whose class we're in, fixes #274 2019-10-05 23:13:48 +01:00
Electroblob77 bc2037f74e Update version number 2019-10-05 17:15:56 +01:00
Electroblob77 6aa3b21190 Convert all in-world sounds from stereo to mono, fixes #218 2019-10-05 17:12:33 +01:00
Electroblob77 b262b6edc0 Oops 2019-10-05 17:04:26 +01:00
Electroblob77 b7be05669b Increase health threshold for amulet of transience from 2 to 6, fixes #192 2019-10-05 16:43:17 +01:00
Electroblob77 071e299d48 Set evoker spell timer as well as spell type when under the arcane jammer effect, fixes #244 2019-10-05 16:40:57 +01:00
Electroblob77 1e885d70c3 Gently encourage people to disable structures the intended way, and stop it crashing if they try and do it the wrong way.
What's wrong with my structures anyway? :'(
2019-10-05 16:28:24 +01:00
Electroblob77 e04a43e56d Why on earth was that there?! Fixes #257 2019-10-05 15:46:05 +01:00
Electroblob77 378796cdda Make fast worldgen check the central position for water rather than checking the biome 2019-10-05 15:34:41 +01:00
Electroblob77 48c37d1c17 Helps if you actually use the synchronised random... fixes #245 2019-10-05 15:24:20 +01:00
Electroblob77 fe8f9fc5cd Update javadoc 2019-10-05 15:23:01 +01:00
Electroblob77 ced6ab7e8d Use a custom mesh definition instead of registering models for each individual metadata, fixes #256
#256 was partially fixed in 60a6c51; this completes the fix by preventing spell books missing models when different worlds have different spell metadata
2019-10-05 14:40:03 +01:00
Electroblob77 378e02eb6c Ignore special spawn conditions for mobs from mob spawners, fixes #260 2019-10-05 14:34:29 +01:00
Electroblob77 4677d9ff30 Unleash the full potential of spell properties files!
- Spell properties files can now be overridden globally in config/ebwizardry/spells
- Spell properties files can now be overridden for specific worlds in [world save]/data/spells
- Moved the main config file to the new ebwizardry folder because it makes more sense for it to be there now
- Probably broke something in the process
2019-10-02 20:13:44 +01:00
Electroblob77 0541b2171b Even more tweaks to progression 2019-10-02 20:04:17 +01:00
Electroblob77 dc59a14e82 Update .gitignore 2019-10-02 20:03:31 +01:00
Electroblob77 1a13afb6e3 Don't pass null into leaf update tick, fixes #186 and #269 2019-10-01 23:06:47 +01:00
Electroblob77 03dd76c18a Fix the blockpos passed into the block being the blockpos a block below the blockpos of the blockstate where the block was from, fixes #267
Easy mistake to make, but how has it avoided detection for so long...?
2019-09-30 11:30:53 +01:00
Electroblob77 9426a96df3 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2019-09-27 23:16:07 +01:00
Electroblob 382faf59c9 Update README.md 2019-09-27 23:15:53 +01:00
Electroblob cab68e23ac Rename guide_for_contributing.md to CONTRIBUTING.md 2019-09-27 23:14:43 +01:00
Electroblob77 60a6c5124e API improvements to spell books:
- Allow spells to set which book/scroll items they can appear on
- Allow spell books to set custom GUI textures
- Tweaks to loot functions and wizards to accommodate the changes
2019-09-27 15:46:09 +01:00
Electroblob77 028b753be6 Cleanup 2019-09-27 15:30:15 +01:00
Electroblob77 d020668e0c Update crystal ore picture in handbook 2019-09-27 12:57:55 +01:00
Electroblob77 656a78962e Rebalance progression yet again 2019-09-27 12:57:27 +01:00
Electroblob77 5a2f5aa295 Reimplement looting spell context 2019-09-27 12:55:31 +01:00
Electroblob 5e37a2322c Update CREDITS.md 2019-09-26 11:37:04 +01:00
Electroblob 3ca9f200fd Update README.md 2019-09-13 15:03:04 +01:00
Electroblob 37e3a842f5 Update README.md 2019-09-13 15:02:12 +01:00
Electroblob 4e8e2c951b Update README.md 2019-09-10 00:14:13 +01:00
Electroblob77 43b66df22a Update version number 2019-09-09 00:06:01 +01:00
Electroblob77 b192a431d7 Copy NBT to new stack in mana flask charging recipes, fixes #242 2019-09-09 00:03:38 +01:00
Electroblob77 3be98ab612 Fix JEI log spam about mana flask recharging recipes having empty output
Either JEI shouldn't be erroring or the Forge javadoc is wrong. Either way, it seems to make no difference so let's not bother with it.
2019-09-08 23:43:10 +01:00
Electroblob77 ed950322ff Temporarily disable the spells sound category to stop issue #238 from happening 2019-09-08 23:40:13 +01:00
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
Electroblob77 f37812be3e That's one heck of a commit you've got there...
I may have got a bit behind with version control. A lot behind, in fact. Maybe I'll go back and split this sometime - then again, I probably won't. But hey, at least it's here!
2019-08-18 00:04:18 +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
Electroblob77 2680d02304 Reduce excessive call limits based on crash report in issue #72 2019-01-06 18:00:24 +00:00
Electroblob77 f564fdce60 Add DamageSafetyChecker, which implements an if-all-else-fails fix for cross-mod infinite looping in attack/hurt/damage events, and changes relevant calls to attack methods to use the safety checker methods instead. Also adds damage source blacklist and compatibility warnings config options. Fixes #72. 2019-01-06 17:51:41 +00:00
Electroblob77 3bdee06738 Merge branch '1.12.2' into 1.12.2-dev 2019-01-06 16:26:02 +00:00
Electroblob77 31673cf247 Missed in b374f71 2019-01-06 15:35:56 +00:00
Electroblob77 f6f36a30fd Register resource reload listener for handbook, missed in 1356905 2019-01-06 15:35:18 +00:00
Electroblob77 2db96cf18d Change spell chat messages to hotbar toast notifications 2019-01-06 15:31:48 +00:00
Electroblob77 b8ba7d1ea4 Transportation stone tweak 2019-01-06 15:21:08 +00:00
Electroblob77 b33037fd1b Missed in 1356905 2019-01-05 23:18:52 +00:00
Electroblob77 a378fe86f5 Retexture all the things! 2019-01-05 23:18:30 +00:00
Electroblob77 5dfa58bf27 Add more spell HUD skins! 2019-01-05 23:12:54 +00:00
Electroblob77 740bfb1a8f Replace old spell book GUI texture with four retextured tiered variants and tweak the layout a tiny bit 2019-01-05 23:12:03 +00:00
Electroblob77 03e8682260 Replace calls to Item#isInCreativeTab(...) with a direct check, fixes metadata items not being displayed correctly in the creative inventory 2019-01-05 23:04:02 +00:00
Electroblob77 4ca89b2dca Increase all conjured item durations 2019-01-05 23:00:49 +00:00
Electroblob77 212fbe51df Move block, item, potion and enchantment registries over to the @ObjectHolder system and reorganise the potion classes a bit 2019-01-05 22:59:45 +00:00
Electroblob77 eb2abdfbe9 Move wand and armour map retrieval methods to WizardryItems, encapsulating the underlying maps 2019-01-05 22:52:45 +00:00
Electroblob77 f8cfc59415 Missed in b374f71 2019-01-05 22:48:38 +00:00
Electroblob77 13569058ae Handbook rewrite part 1: Formatting and JSON-ification!
- Everything is now defined in a JSON file
- Formatting is now done dynamically and content wraps properly no matter what font is used
- Added inline hyperlinks
- Added a movable bookmark for quick access to a specific page
- Added next section and previous section buttons to flip through entire sections at once
- Added a contents button visible on every page, which navigates directly to the main contents
2019-01-05 22:38:06 +00:00
Electroblob77 78189ed862 Fix a few things in the HUD skin chooser screen 2019-01-05 22:30:06 +00:00
Electroblob77 09185e5f1c Introduce DrawingUtils to centralise GUI rendering utility methods 2019-01-05 22:28:57 +00:00
Electroblob77 201f276c8b More cleanup 2019-01-05 22:19:22 +00:00
Electroblob77 224ee281ef Cleanup 2019-01-05 22:18:14 +00:00
Electroblob77 f907d50333 Fix deobf jar task 2019-01-05 21:14:55 +00:00
Electroblob77 95ce659ec3 Add dev jar task to build.gradle 2019-01-05 18:45:18 +00:00
Electroblob77 f9f6b34549 Update version number 2019-01-05 18:28:06 +00:00
Electroblob77 bee7e51d06 Change key handler to static event handler and remove initialisation from main mod class, fixes #104 2019-01-05 16:42:21 +00:00
Electroblob77 51a2ff0976 Update version number 2019-01-04 22:12:37 +00:00
Electroblob77 1b298ff18b Update credits (all locations) 2019-01-04 22:12:06 +00:00
Electroblob77 86d13d3a6e Swap canSnowAt for canPlaceBlockAt, so it actually works... 2019-01-04 21:58:45 +00:00
Electroblob77 5421372754 Unike input events, tick events fire before the player is initialised, so add a check to stop it crashing with an NPE. 2019-01-04 21:53:39 +00:00
Electroblob77 53b29939f1 Change key handler to listen for ClientTickEvent instead of KeyInputEvent, swap isPressed() to isKeyDown() and restructure code; fixes 'lag'/inconsistent behaviour with mouse button keybinds. (See also #79, not sure if this fixes it since I can't reproduce the problem.) 2019-01-04 21:48:35 +00:00
Electroblob77 7bda8db86f Add check for wand before sending control packets, prevents unnecessary packets being sent 2019-01-04 21:04:06 +00:00
Electroblob77 a7a48cd32b Add a less than max timer check so that magic light does not keep growing indefinitely if the block fails to disappear. Helps reduce the effects of #101 but does not fix it. 2019-01-04 20:53:01 +00:00
Electroblob77 b8e0836a6d Add test for fake players in retaliatory ice shroud effect, fixes #93 2019-01-04 20:48:03 +00:00
Electroblob77 a7e6b2892c Add check to prevent ArrayIndexOutOfBoundsException in WandHelper, fixes #90 (and duplicate issues #80, #91, #97 and #98) 2019-01-04 20:07:02 +00:00
Electroblob77 f886ebfd75 Prevent ice age from placing snow layers at invalid locations, fixes #64 2019-01-04 20:05:09 +00:00
Electroblob77 98b334e6d7 Add condition to only write magic projectile thrower to spawn data if the thrower exists and tweak overrides so it is always written/read last, fixes #71 2019-01-04 20:04:43 +00:00
Electroblob77 83edb8007e Replace direct translation in /allies command with text component, fixes #70 2019-01-04 20:02:57 +00:00
Electroblob77 67dda448f3 Add background tint to arcane workbench GUI, fixes #96 2019-01-04 19:58:31 +00:00
Electroblob77 09953c0299 Add bottom of world check to wizard tower foundation worldgen, fixes #73 2019-01-04 19:57:33 +00:00
Electroblob77 38b0fa65bc Comment out scroll translation console message, fixes #56 2019-01-04 19:56:39 +00:00
Electroblob 7200182c82 Merge pull request #102 from dragon-evol/1.12.2
[zh_cn_handbook update]minor, minor, minor fixes (sorry for disturbing...)
2019-01-03 23:08:10 +00:00
dragon-evol e73e998de2 minor fixes 2019-01-03 13:19:53 +08:00
Electroblob77 b374f71533 The great particle refactoring part 2: Splitting and Streamlining!
- Splits all particle textures into individual files intead of sprite sheets
- Replaces arc and lightning pulse entities with particles
- Pulls particle code up to the general ParticleWizardry so behaviours such as spin can be applied to all particle types
- Renames a few ParticleBuilder methods for conciseness.
- Adds a few new particle effects to various spells and entities, with a slight tweak to EntityMagicArrow#onBlockHit to facilitate impact effects
2019-01-01 21:40:04 +00:00
Electroblob a69da2eb2a Merge pull request #94 from dragon-evol/1.12.2
Update zh_cn.lang and translate the handbook
2018-12-18 00:23:36 +00:00
dragon-evol a00c594d83 Add files via upload 2018-12-17 14:23:23 +08:00
dragon-evol 3df99552e1 Merge pull request #1 from dragon-evol/dragon-evol-patch-1
Update zh_cn.lang
2018-12-17 14:22:20 +08:00
dragon-evol e2bc2824f6 Add files via upload 2018-12-17 14:11:18 +08:00
Electroblob 36f4728f3a Merge pull request #88 from Avatair/feature/mapping-update
Updated MCP Mapping to stable39
2018-11-24 18:20:08 +00:00
alesto 6ca72e7965 Undid adding wizardry dependency. 2018-11-24 09:56:35 +01:00
alesto 151dcc06da Updated mappings 2018-11-22 16:02:40 +01:00
Electroblob 5737109dec Merge pull request #82 from HellFirePvP/1.12.2
Switch enchantment-writing related code to a more direct data-driven approach
2018-11-10 00:48:16 +00:00
HellFirePvP 4bd3a46f32 Switch enchantment-writing related code to a more direct data-driven approach 2018-11-01 13:19:46 +01:00
Electroblob 73e2d64fcd Update guide_for_contributing.md 2018-08-17 23:06:46 +01:00
Electroblob 1f008b405d Update ISSUE_TEMPLATE.md 2018-08-01 23:13:43 +01:00
Electroblob 00e1e2602f Update guide_for_contributing.md 2018-08-01 23:11:27 +01:00
Electroblob 98445da971 Update ISSUE_TEMPLATE.md 2018-08-01 22:59:42 +01:00
Electroblob ad363c64af Correct missing return in lang file 2018-07-03 00:26:44 +01:00
Electroblob 82eed83dcc Correct default scroll direction 2018-07-03 00:24:16 +01:00
Electroblob 7c7a69c755 Add config option to reverse the spell switching scroll direction 2018-07-02 22:56:04 +01:00
Electroblob af01beb583 Spell HUD rewrite and retexturing:
- Replaces the old hardcoded drawing methods with a new json-based system with support for multiple inbuilt and resource pack-defined skins.
- Adds a config option for choosing the spell HUD skin, along with a custom config GUI screen allowing the user to select from a list of available skins with a preview of the currently selected skin.
- Replaces the HUD texture file with a spell_hud subfolder, containing all the necessary textures and json files for the 12 inbuilt skins.
- Adds a subtle sound effect and scroling animation when switching spells
- Reorganises the control event code into a single handler class and converts this class and the spell HUD class to static event handlers.
- Fixes the HUD position option which got broken in the previous spell HUD commit
2018-07-02 22:33:09 +01:00
Electroblob b7cd3db8bc Rename armour fix model 2018-07-02 22:05:19 +01:00
Electroblob 056c35ac3f Add back face to renderer for force arrow 2018-06-24 19:16:11 +01:00
Electroblob f6a24038cc Retexture spell HUD, add different textures for survival/creative mode, and tidy up the GUI code 2018-06-24 19:14:48 +01:00
Electroblob fde5935adc Add visual first person blink effect 2018-06-24 19:11:59 +01:00
Electroblob f8eecfc6d5 Retexture wands 2018-06-24 16:14:17 +01:00
Electroblob 53aa19d1a1 Fix darkness orb spell shooting thunderbolts instead of darkness orbs 2018-06-24 16:13:40 +01:00
Electroblob a49756ddaa Add vector-based position and velocity methods to ParticleBuilder 2018-06-24 16:13:04 +01:00
Electroblob ee3fca35bd Particle tweaks and fixes 2018-06-24 16:12:40 +01:00
Electroblob 55ae4b1161 Miscellaneous cleanup and commenting 2018-06-24 16:08:28 +01:00
Electroblob 76473f7185 Rewrite raytracing methods and optimise their usage 2018-06-24 16:02:34 +01:00
Electroblob ff87729ee8 Missed in 75e5de6 2018-06-24 15:52:59 +01:00
Electroblob 9464b3a084 Retexture leaf particles and move colouring to code 2018-06-24 15:51:28 +01:00
Electroblob d0bf90b900 Retexture flight wings 2018-06-24 15:50:02 +01:00
Electroblob fec4b755bd Remove old unused textures 2018-06-24 15:49:13 +01:00
Electroblob 73d973783d Add continuous spell casting with scrolls and increase scroll and spell book stack sizes to 16 2018-06-24 15:48:48 +01:00
Electroblob 75e5de603e Delegate workbench apply button and slot behaviour to item classes 2018-06-24 12:52:55 +01:00
Electroblob 6da42a18c7 Update references to moved GUI classes 2018-06-24 12:45:49 +01:00
Electroblob f3c9fbdd2e Move GUI classes to separate package 2018-06-24 12:23:08 +01:00
Electroblob c7c7d57e7e Change target blacklist/whitelist checking to use the correct method for retrieving an entity key from EntityList 2018-06-20 23:58:50 +01:00
Electroblob c3abdcf68b Fix NPE in immunity initialisation, fixes #49 2018-06-20 23:57:05 +01:00
Electroblob 8f0727403d Correct fallback translation key for spirit horse 2018-06-20 23:36:15 +01:00
Electroblob 2301e54de4 Prevent potions with custom particles from mixing their particle colour (black) with other potions 2018-06-20 23:35:07 +01:00
Electroblob be952e65f4 Fix incorrect position input in ParticleBuilder's spherical particle spawning convenience method 2018-06-20 23:33:53 +01:00
Electroblob 24457ebe36 Add error prevention and console warning for trying to spawn particles on the server side using ParticleBuilder 2018-06-20 23:32:14 +01:00
Electroblob a523d3dd2b Fix incorrect default scale for flash particles 2018-06-20 23:30:52 +01:00
Electroblob 373fd4c8e8 Add chat readout for applying spells to wizards in creative mode 2018-06-20 23:30:07 +01:00
Electroblob 106148fd9e Miscellaneous cleanup and commenting 2018-06-20 23:28:56 +01:00
Electroblob 29261082f1 Spell hierarchisation and refactoring, plus miscellaneous renaming and minor refactoring
- Adds new generic spell superclasses which aim to group spells such that duplicate code is eliminated, and functions standardised, as much as possible.
- Removes numerous spell classes which are no longer required as a result of this change, and replaces them with instances of the relevant generic spell classes.
- Changes the remaining spell classes to fit with the new system, mostly by having them extend the generic spell classes.
- Completes the transfer of particle spawning to the ParticleBuilder system.
2018-06-20 22:25:54 +01:00
Electroblob dbc1490e10 Merge pull request #53 from ZHENGLOC/1.12.2
Update zh_cn.lang
2018-06-17 11:21:23 +01:00
Electroblob b6400c72a7 Genericise spell casting AI class 2018-06-09 17:36:54 +01:00
Electroblob 719c6d5fbb Add new spell types 2018-06-09 17:33:37 +01:00
ZLOCK_1911 f33a0aceb2 Update zh_cn.lang 2018-06-09 12:02:45 +08:00
Electroblob 7141ae9544 Update CREDITS.md 2018-06-07 17:34:36 +01:00
Electroblob af638ab2f7 Merge pull request #51 from ZHENGLOC/1.12.2
Create zh_cn.lang
2018-06-07 17:32:32 +01:00
ZLOCK_1911 a75a6c6114 Create zh_cn.lang 2018-06-07 18:31:37 +08:00
Electroblob 438f5d7a2e Merge branch '1.12.2' into 1.12.2-dev 2018-06-05 21:44:17 +01:00
Electroblob dec5b1ac2c Add witty/stupid comments to a few classes 2018-06-05 21:26:07 +01:00
Electroblob 726a306830 Delete redundant classes 2018-06-05 21:25:41 +01:00
Electroblob 330c78a92c Change non-evil wizard health from 20 to 30 2018-06-05 21:24:47 +01:00
Electroblob dcec7c7281 Miscellaneous cleanup and commenting 2018-06-05 21:24:09 +01:00
Electroblob b9ba25c116 Add test cases for new particle effects; to be applied to everything once spells have been reorganised 2018-06-05 21:18:01 +01:00
Electroblob 0341a603d5 Missed the imports on that one... 2018-06-05 21:15:02 +01:00
Electroblob d91a3e056a The great particle refactoring part 1: Introducing ParticleBuilder!
Adds ParticleBuilder to replace the particle spawning methods in the proxies, and changes all particle spawning to use the builder except for in the spell classes, which are to be reorganised first.
2018-06-05 21:13:41 +01:00
Electroblob 9c1042f686 Update version number 2018-06-05 17:01:04 +01:00
Electroblob cad3fee1b9 Update mcmod.info 2018-06-05 16:58:33 +01:00
Electroblob 5947b2ee62 Fix smoke bomb recipe and allow charcoal to be used 2018-06-05 16:00:47 +01:00
Electroblob 177a39bad1 Cleanup 2018-06-05 15:43:56 +01:00
Electroblob cdf8f6e32d Remove now-redundant recipe config options 2018-06-05 15:43:48 +01:00
Electroblob f88aac11e9 Convert all non-dynamic recipes to JSON, add ore dictionary support where appropriate and change incorrect "amount" tag to "count", fixes #18 2018-06-05 15:43:14 +01:00
Electroblob 05b905b988 Fix light level detection for petrified creatures breaking out 2018-06-05 14:12:33 +01:00
Electroblob 669cd2892d Add check for valid special wand upgrades, fixes #48 2018-06-05 11:12:03 +01:00
Electroblob dd07d08ff0 Return true in ADS methods when passed a null attacker, acting as a fallback for when caster does not save properly; fixes #40 2018-06-04 23:45:10 +01:00
Electroblob 54bb327fdf Properly sync thrower field for all throwable projectiles, fixes #42 (does not fix vanilla throwables though) 2018-06-04 23:42:12 +01:00
Electroblob 2cd8b46c1f Add toughness to legendary wizard armour 2018-06-04 18:32:32 +01:00
Electroblob b61413f7f1 Remove ISpecialArmor from ItemWizardArmour since it is no longer necessary, fixes #44 2018-06-04 18:20:55 +01:00
Electroblob 4e7765a7e7 Allow tab-completion of spell names in commands without specifying the modid 2018-06-04 18:04:36 +01:00
Electroblob 49a6dc43c1 Cleanup 2018-06-04 17:20:39 +01:00
Electroblob b82bc6698f Make crystal ore drop xp when mined 2018-06-04 17:17:58 +01:00
Electroblob 1e43c67660 Tweak summoned creature targeting so that non-evil wizards' minions no longer attack players unless the player in question has angered the wizard 2018-06-04 17:17:33 +01:00
Electroblob c129571167 Change EntityWizard to implement IMerchant and INpc directly rather than extending EntityVillager, fixes #38 plus a number of other bugs 2018-06-04 16:36:20 +01:00
Electroblob b23a643c0e Make arcane workbench drop items correctly when broken, fixes #20 2018-06-04 15:00:02 +01:00
Electroblob 194bff3e6a Miscellaneous lang file fixes 2018-06-04 13:09:23 +01:00
Electroblob 426ca78288 Sort config options into a more logical order 2018-06-04 12:51:12 +01:00
Electroblob f15919fdce Organise the config file and GUI into categories 2018-06-04 12:39:56 +01:00
Electroblob 2124842136 Fix transportation stone not dropping when unsupported, fixes #23 2018-06-03 23:57:22 +01:00
Electroblob 70e697876b Centralise code for config GUI category classes 2018-06-03 23:24:42 +01:00
Electroblob 9b5e5a871c Add dimension whitelist option for evil wizard spawning and restrict numbers to 1 per chunk, closes #26 2018-06-03 22:22:18 +01:00
Electroblob 5ba92e5de5 Change whitelist/blacklist storage from strings to resourcelocations to bring it in line with the registry system 2018-06-03 22:17:57 +01:00
Electroblob 4e6780a3cf Replace getEntityString with getKey(...).toString() 2018-06-03 18:19:10 +01:00
Electroblob 00584ad635 Move resistances config setup from preInit to init 2018-06-03 18:18:29 +01:00
Electroblob f72ed33515 Add mind control targets blacklist config option 2018-06-03 18:17:05 +01:00
Electroblob c2366ed1ba Change crystal ore drop quantity to drop the intended 1-3 crystals (rather than the previous 1-2) and change fortune behaviour to work like vanilla ores, see discussion in #43 2018-06-03 15:52:13 +01:00
Electroblob 46df8d7311 Add smelting recipe for crystal ore, closes #43 2018-06-03 15:15:50 +01:00
Electroblob d4579b9184 Remove all calls to GlStateManager.pushAttrib() and pullAttrib() and a few other tweaks to gl calls, fixes #12, #46 and #47 2018-06-03 12:39:25 +01:00
Electroblob ee6f0cfe70 Correct death message lang key in code, fixes #41 2018-06-02 16:08:48 +01:00
Electroblob 6155fd9c68 Display non-keyboard keybinds correctly, fixes #36 2018-06-02 15:14:32 +01:00
Electroblob 32c0608b51 Stop spirit horses dropping leather, fixes #37. Also adds the same overrides to spirit wolves; since regular wolves don't drop anything this wasn't noticeable. 2018-06-02 13:39:21 +01:00
Electroblob 404df6af23 Fixes #32 2018-06-02 13:35:37 +01:00
Electroblob 764e10538b Update LICENSE.md 2018-05-21 10:45:11 +01:00
Electroblob 6b1b590e30 Merge pull request #25 from Shadows-of-Fire/client
Fixes #17, #22, and maybe #12
2018-05-04 19:50:11 +01:00
Shadows_of_Fire 8360e520cd De-duplicate armor value 2018-05-04 14:34:09 -04:00
Shadows_of_Fire 005a17d750 Fix armor value tooltips 2018-05-04 14:23:57 -04:00
Shadows_of_Fire 28abe036a0 Armor properly has 0 damage reduction when oom
tooltip is being buggy, won't display armor reduction values.
2018-05-04 08:18:15 -04:00
Shadows_of_Fire ca96112b67 Fix wizard armor breaking 2018-05-04 07:35:51 -04:00
Shadows_of_Fire b8e847c6a6 Fixes #22 2018-05-04 06:53:11 -04:00
Shadows_of_Fire 35cb2c31fc Convert to GlStateManager calls
also removes the weird reflection being used to access the RenderItem
2018-05-04 06:45:57 -04:00
Electroblob 30dd587d34 Move wiki resources to wiki git repository 2018-05-03 20:47:46 +01:00
Electroblob 4644814582 Add wiki resources 2018-05-03 20:31:25 +01:00
Electroblob 7db3151d8a Change hardness of transportation to 0.3, fixes #19 2018-05-02 18:23:07 +01:00
Electroblob c8ca73cca9 Fix incorrect event handler annotation 2018-05-02 13:35:47 +01:00
Electroblob d5a0479ebe Update .gitignore 2018-05-02 13:19:30 +01:00
Electroblob 466b3bbc27 Update .gitignore 2018-05-02 13:17:15 +01:00
Electroblob df14912693 Add new files for the particle refactoring 2018-05-02 13:17:04 +01:00
Electroblob 8a53cc6150 Fix incorrect event handler annotation 2018-05-02 13:03:14 +01:00
Electroblob 339ec69a72 Update version number 2018-04-14 15:53:51 +01:00
Electroblob b2cb717aa3 Cleanup 2018-04-14 15:47:31 +01:00
Electroblob cf4a02f37f Fix crash related to creative tab sorting with HQM installed 2018-04-14 15:28:19 +01:00
Electroblob 84304dd7ce Prevent possible server crash with static initialiser block 2018-04-14 15:26:47 +01:00
Electroblob e3b44eb194 Make entities attacked by summoned creatures revenge-target the summoned creature rather than its summoner 2018-04-14 14:09:16 +01:00
Electroblob 2cbb0a590f Correct position of spell cooldown bar when spell HUD is at top of screen; fixes #14 2018-04-14 13:22:53 +01:00
Electroblob 6b9c864890 Move target position references inside null checks; fixes #13 2018-04-14 13:19:17 +01:00
Electroblob f5730bf945 Replace crossed quads arc renderer with new 3D box-based rendering 2018-04-14 12:51:18 +01:00
Electroblob a1ae3a2b8b Update version number 2018-04-14 12:49:45 +01:00
Electroblob c15a0763d5 Merge branch '1.12.2' of https://github.com/Electroblob77/Wizardry into 1.12.2 2018-04-10 16:04:35 +01:00
Electroblob 4a23d88f30 Add obfuscated names to reflective field access 2018-04-10 16:03:23 +01:00
Electroblob 286705c79b Update README.md 2018-04-09 23:11:23 +01:00
Electroblob 3895f5c531 Cleanup 2018-04-09 17:29:41 +01:00
Electroblob c51e0bd218 Fix mods list logo 2018-04-09 17:29:18 +01:00
Electroblob 766570aeb2 Fix spell book for crystals trade not working 2018-04-09 17:28:59 +01:00
Electroblob 4e91b0d19d Fix broken lang key in config GUI 2018-04-08 00:04:35 +01:00
Electroblob 65f7630546 Update minecraft version number in wizard's handbook 2018-04-08 00:04:06 +01:00
Electroblob 8cf7572041 Update mcmod.info 2018-04-08 00:03:39 +01:00
Electroblob db057a5ca9 Update credits 2018-04-08 00:03:15 +01:00
Electroblob 267fb2daf4 Cleanup 2018-04-07 22:50:08 +01:00
Electroblob b96526b284 Fix ice wraith not attacking 2018-04-07 22:49:44 +01:00
Electroblob e01b5c728c Flip the item on the arcane workbench the right way up 2018-04-07 22:48:10 +01:00
Electroblob 0cf1d74fd5 Fix buttons rendering incorrectly in wizard's handbook 2018-04-07 20:31:48 +01:00
Electroblob 8316dcad70 Change some advancement icon frames and add new background 2018-04-07 17:49:59 +01:00
Electroblob df1eb68f35 Remove last few harcoded mod ID strings 2018-04-07 12:47:18 +01:00
Electroblob 416868bafb More cleanup 2018-04-07 00:08:43 +01:00
Electroblob 0424e409fc Fix root advancement localisations and rename all advancement translation keys to bring them in line with everything else 2018-04-07 00:08:26 +01:00
Electroblob a5b38e8f83 Stop mana flask charging recipes appearing in recipe book; fixes #11 2018-04-06 23:52:30 +01:00
Electroblob 1e0613c949 Cleanup 2018-04-06 22:53:53 +01:00
Electroblob d33290d890 Fix various warnings (deprecated method usage, etc.) 2018-04-06 22:53:41 +01:00
Electroblob e22d428016 Update version number 2018-04-06 22:51:07 +01:00
Electroblob baa407ce61 Merge pull request #10 from 12foo/1.12.2-corail
1.12 port update
2018-03-18 16:27:49 +00:00
Philipp Rustemeier ea11910af2 Post-merge fixups
In particular, act as if a spellbook has been discovered during tooltip
generation if player is null. This allows JEI to index all the spell
names.
2018-03-16 18:09:40 +01:00
Philipp Rustemeier 873b5a4f4d Fix Arcane Workbench GUI
- Explicitly render inventory mouseover tooltips (this is apparently required now for them to appear)
- When a wand is in, report the actual new xSize to Minecraft so things like JEI don't overdraw the tooltip on the right
2018-03-16 18:08:55 +01:00
Philipp Rustemeier 6890ae765a Fix JSON recipe crafting with ore dictionary
In current Forge, you can use OD entries in normal crafting recipes; using the special forge crafting recipe types is no longer necessary.
2018-03-16 18:08:55 +01:00
Philipp Rustemeier b9d240799d Finish changing modid to 'ebwizardry'
- Fix up translations, resource IDs, paths etc.
- Where possible, the modid part in most strings now just reuses Wizardry.MODID
2018-03-16 18:08:47 +01:00
Philipp Rustemeier 612bbdb64d Replace Achievements with Advancements
- Advancements are now in JSON files, converted by the included migration script.
- WizardryAdvancementTrigger is a generic achievement trigger that can be reused throughout the code to trigger custom advancements not covered by the JSON conditions.
- Plus some other small and obvious fixes.
2018-03-16 18:08:34 +01:00
Philipp Rustemeier 62c2a9e9b8 Various small fixes for 1.12 2018-03-16 18:07:37 +01:00
Electroblob bc3051fcf0 Merge pull request #8 from Corail31/1.12.2
1.12 conversion
2018-03-16 00:00:53 +00:00
Corail31 489fb82fbd 1.12 conversion 2018-03-09 11:56:31 +01:00
Electroblob edff82acca Update README.md 2018-03-09 10:05:01 +00:00
Electroblob 15e2a36518 Fix broken crafting recipes and Minecraft version number in wizard's handbook 2018-03-07 11:00:47 +00:00
Electroblob c5402285d8 Fix crash when viewing recipe pages of wizard's handbook 2018-03-06 23:36:16 +00:00
Electroblob b4fdf181be Fix incorrect achievement description keys in lang files 2018-02-27 23:41:18 +00:00
Electroblob ddd70b954c Change transportation stone item to use 2D texture instead of 3D model 2018-02-27 23:39:45 +00:00
Electroblob f17f01dc4b Rename handbook_ru_RU.txt to handbook_ru_ru.txt 2018-02-27 18:19:52 +00:00
Electroblob 257d5c28a1 Rename handbook_es_MX.txt to handbook_es_mx.txt 2018-02-27 18:19:32 +00:00
Electroblob 3cc410192c Rename handbook_es_ES.txt to handbook_es_es.txt 2018-02-27 18:19:15 +00:00
Electroblob b033a53f82 Rename handbook_en_US.txt to handbook_en_us.txt 2018-02-27 18:18:53 +00:00
Electroblob d189991c65 Rename handbook_en_GB.txt to handbook_en_gb.txt 2018-02-27 18:18:33 +00:00
Electroblob edb2a2d5a5 Merge branch '1.11.2' of https://github.com/Electroblob77/Wizardry into 1.11.2 2018-02-26 23:18:44 +00:00
Electroblob de66c3abba Update README.md 2018-02-26 22:55:54 +00:00
Electroblob f9b546daa9 Fix incorrect method call in summoned creature classes; was causing caster not be loaded properly
I can't believe I didn't notice this before...
2018-02-26 19:02:14 +00:00
Electroblob 6f776fbae6 Cleanup 2018-02-26 18:37:52 +00:00
Electroblob 13444f1de3 Additional method for 76f6d43 2018-02-26 18:37:09 +00:00
Electroblob 1581d18a43 Temporarily fix shadow ward not damaging its caster 2018-02-26 18:36:13 +00:00
Electroblob 46eae53313 Fix phase step missing sound 2018-02-26 18:35:12 +00:00
Electroblob 76f6d431bb Fix metamorphosis making entities disappear 2018-02-26 18:34:18 +00:00
Electroblob 2ad2b9988b Fix NBT copying for metamorphosis 2018-02-25 18:44:46 +00:00
Electroblob 8b363b6b4f Update ru_ru.lang (credit: VilagVil) 2018-02-25 18:43:55 +00:00
Electroblob 76d4e3d029 Cleanup and minor code tweaks 2018-02-24 13:49:27 +00:00
Electroblob 74ddcd79ca Rewrite metamorphosis to work with husks/strays and skeleton minions 2018-02-24 13:47:33 +00:00
Electroblob 6cd3e16939 Fix decay spawning too infrequently 2018-02-24 12:42:50 +00:00
Electroblob d462acc489 Add wither skeleton minion localisations 2018-02-23 17:40:29 +00:00
Electroblob eeb2785899 Rewrote some of the mind control logic to properly fix targeting 2018-02-23 13:25:05 +00:00
Electroblob 11af545bd2 Cleanup 2018-02-23 12:40:03 +00:00
Electroblob d4c9242b14 Fix mind-controlled entities not attacking any more after their initial target is killed
This problem arose as a result of the previous bugfix a4695bc
2018-02-23 12:39:44 +00:00
Electroblob db9812eac9 Register wither skeleton minions properly 2018-02-23 12:37:48 +00:00
Electroblob d792d50f92 Fix various problems caused by armour stands being a subclass of EntityLivingBase 2018-02-23 12:37:14 +00:00
Electroblob 3632511983 Add fixes from 52d12c0, a4695bc and f4d7ba6 to 1.11.2 branch 2018-02-22 14:50:20 +00:00
Electroblob f54b92be16 Replace hasKey with hasUniqueId where appropriate, should fix some weirdness with a few spells 2018-02-22 13:32:09 +00:00
Electroblob a567281183 Fix null itemstack error 2018-02-22 12:56:03 +00:00
Electroblob 56a24ee7b5 Fix problems with pocket furnace spell caused by incorrect itemstack check 2018-02-22 12:37:31 +00:00
Electroblob 5715928dbd Actually fix spell chat readout localisations 2018-02-22 12:21:05 +00:00
Electroblob e0001b5d37 Fix broken localisations for spell chat readouts 2018-02-21 10:51:31 +00:00
Electroblob 15fb75a7c3 Fix magic projectiles hitting their thrower on the client side 2018-02-21 10:50:52 +00:00
Electroblob d7750ad80c Merge pull request #5 from Electroblob77/Electroblob77-filename-case-fix
Rename lang files to all lowercase
2018-02-18 22:38:34 +00:00
Electroblob 9940908485 Rename ru_RU.lang to ru_ru.lang 2018-02-18 22:35:26 +00:00
Electroblob b7895ca744 Rename es_MX.lang to es_mx.lang 2018-02-18 22:35:01 +00:00
Electroblob 574ffa891d Rename es_ES.lang to es_es.lang 2018-02-18 22:33:31 +00:00
Electroblob 67069c818f Rename en_US.lang to en_us.lang 2018-02-18 22:33:03 +00:00
Electroblob d2900e5692 Rename en_GB.lang to en_gb.lang 2018-02-18 22:31:27 +00:00
Electroblob a1fa1d91c2 Fix broken entity localisations 2018-02-18 01:58:10 +00:00
Electroblob 338f6d54d0 Even more cleanup 2018-02-16 22:36:26 +00:00
Electroblob 3be254a247 Remove unnecessary empty itemstack checks, see comments on d0fda72 2018-02-16 22:28:00 +00:00
Electroblob bec52edce4 More cleanup 2018-02-16 22:26:28 +00:00
Electroblob 2dd52ce6b1 Fix x/z coordinate error, see comment on d0fda72 2018-02-16 16:14:28 +00:00
Electroblob d0d6f3a1fc Cleanup 2018-02-16 16:05:46 +00:00
Electroblob 9bf657aeab Add wizardry loot to woodland mansions and end cities 2018-02-16 16:01:01 +00:00
Electroblob c4ea81432f Replace Minecraft version number in text files with substitute value 2018-02-16 15:46:13 +00:00
Electroblob b08651c11e Replace deprecated slipperiness field access with getter 2018-02-16 15:45:18 +00:00
Electroblob aabcf43c1d Update build.gradle 2018-02-16 15:36:54 +00:00
Electroblob 066d6858c3 Update README.md 2018-02-13 16:29:49 +00:00
Electroblob 9c626d6756 Update CREDITS.md 2018-02-13 16:28:50 +00:00
Electroblob 00db03f546 Update CREDITS.md 2018-02-13 16:27:51 +00:00
Electroblob 071eb45d3c Merge pull request #4 from Corail31/1.11.2
More updating to 1.11.2 and stable_32 mcp mappings
2018-02-12 17:57:19 +00:00
Corail31 d0fda72a59 First Checkup 2018-02-11 22:51:13 +01:00
Electroblob 7f7605c089 Miscellaneous fixes and cleanup 2018-02-11 18:53:50 +00:00
Electroblob 2b24c3fb2a Add fix from 6d77918 to 1.11.2 branch 2018-02-09 18:26:11 +00:00
Electroblob e5c02cd0df Merge branch '1.11.2' of https://github.com/Electroblob77/Wizardry into 1.11.2 2018-02-07 21:42:22 +00:00
Electroblob 037611f1c3 Update build.gradle 2018-02-07 21:41:33 +00:00
Electroblob 2284f6db24 Update README.md 2018-02-07 21:31:11 +00:00
Electroblob 3df5597dcc Initial 1.11.2 update 2018-02-07 21:15:50 +00:00
Electroblob 67f6be0671 Update README.md 2018-02-06 17:28:56 +00:00
3214 changed files with 120843 additions and 44758 deletions
+7
View File
@@ -0,0 +1,7 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/electroblobs-wizardry",
"promos": {
"1.12.2-latest": "4.3.5",
"1.12.2-recommended": "4.3.5"
}
}
+2
View File
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
+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/CONTRIBUTING.md) before posting. You may also find the [troubleshooting page](https://github.com/Electroblob77/Wizardry/wiki/Troubleshooting) helpful.
Minecraft version: 1.12.2 [change as necessary]
Wizardry version: 4.3.5 [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/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/CONTRIBUTING.md) before posting.
Minecraft version: 1.12.2 [change as necessary]
Wizardry version: [change as necessary]
Question details: [explain your question here]
Other mods involved: [if this question involves other mods, list them here]
@@ -0,0 +1,38 @@
name: Potential Duplicates
on:
issues:
types: [opened, edited]
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: bubkoo/potential-duplicates@v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
label: potential duplicate
exclude: |
adding
add
creating
create
icons
icon
logos
logo
missing
miss
needing
need
please
requesting
request
1.12.2
wizardry
state: all
threshold: 0.7
comment: |
This issue is potentially a duplicate of one of the following issues:
{{#issues}}
- [#{{ number }}] {{ title }} ({{ accuracy }}% match)
{{/issues}}
+6 -1
View File
@@ -20,5 +20,10 @@ build
# other
eclipse
run
misc
logs
/misc
/libs
libs_src
libsfordeobf
generated
Thumbs.db
+59
View File
@@ -0,0 +1,59 @@
# Guide for contributing to this repository
## Submitting an issue
When submitting an issue, I would be grateful if you could follow these few guidelines:
- First and foremost, please check your issue hasn't already been posted. The issue tracker is searchable, so try typing in a few keywords and see if anything comes up.
- 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, and github will automagically link them.
- 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!
- 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.
- Please don't revive old issues, _especially_ if they have been fixed, because I don't routinely check them. Make a new issue and link the old one to it if you think it's related.
- Most importantly, use gist or pastebin to post crash reports. Do not paste the entire crash report inline, not even in a code block!
> If you've got a git account (which you do, if you're posting an issue) you can access gist, and pastebin doesn't require an account at all, so there's no excuse!
## Submitting a PR
I like my code to be tidy, so it saves me time if yours is too. Here are a few general guidelines for how to submit a good PR:
- Use proper indentation and try to space your code out nicely. This really goes without saying - select all your code and hit ctrl-i before you submit it, and try to use my spacing if you can (for instance, don't do what the Minecraft source does and put a { on a separate line, it's a waste of space).
- Commented code is dead code, UNLESS it has an accompanying comment detailing an appropriate reason for it being commented. (something like "DO NOT REMOVE, commented because it will be useful in 1.12" or "DO NOT REMOVE, commented for debugging purposes, uncomment when fixed")
- Please comment your methods/fields/classes! Preferably using Javadoc, but for small/private methods one line comments are OK. I find it hard enough to remember what I wrote a method for if it isn't commented, let alone trying to work out what yours are for. That said, you should try to name the method/field/class so it's obvious what it is anyway.
- Please use @Override when overriding any methods.
- Follow naming conventions. BLOCK_CAPITALS for constants, CapitalisedWords for classes, camelCase for almost everything else.
- This isn't code related, but when you submit a PR, please tell me what it does! You don't need much, just something like "Makes item X do X" or "Fixes #162". If you're resolving an issue, put "Fixes", "Closes" or "Resolves" and then the issue number and Github will close it automatically.
## Guide for translators
Pull requests aren't just for code - if you would like to help translate Wizardry, you can do that here too! Simply fork the repository, add your translations and submit a PR when you're done. Wizardry has TWO files you'll need to translate: the usual .lang file and the handbook text file, which can be found in resources/assets/wizardry/texts.
- Firstly, the .lang file: if you're familiar with translating mods, this is all pretty standard - it holds the names of blocks, items, mobs and so on. Ignore the %X$s bits, they're placeholders for stuff that gets put in by Wizardry when the game is running.
- Secondly, the handbook JSON file: the US english version is named handbook_en_us.json, and (rather obviously) other languages' text files replace 'en_us' with the name of their corresponding .lang file. Make sure you only change the _values_ (after each `:`), not the identifiers - for a summary of JSON syntax, see the [JSON webpage](https://www.json.org/json-en.html). If you're familiar with advancements, loot tables and similar files, this won't be new to you. The handbook file also applies its own form of markup to the main text, with the following features:
- `#image tag` adds an image to the text with the given tag. Image tags are defined in the `"images": {...}` block at the start of the file. Each named entry in this block defines a single image with that name as its tag. Each entry is a JSON object containing a file location and optional caption/dimensions.
- `#recipe tag` adds a crafting recipe to the text with the given tag. Similar to image tags, recipe tags are defined in the `"recipes": {...}` block at the start of the file. Each named entry in this block defines a recipe with that name as its tag. Each entry contains a list of one or more locations or recipes to display (if more than one is specified, the display will cycle through the different recipes).
- Anything else with a `#` directly before it (with no space) will be treated as a format argument if possible. This means the text after the `#` will be replaced with something else at runtime, similar to the `%X$s` bits in a normal .lang file, if it matches one of the available format arguments. The current format arguments can be found [here](https://github.com/Electroblob77/Wizardry/blob/1.12.2/src/main/java/electroblob/wizardry/client/gui/handbook/GuiWizardHandbook.java#L177-L203).
- `@section@` adds a hyperlink to the given section, which will display as the name of that section. `@section alt text@` is the same, except alt text is displayed instead of the section name (alt text may contain spaces). It is also possible to hyperlink to a webpage, simply replace the section name with the url (e.g. `@https://example.com/@` or `@https://example.com/ alt text@`).
> Translators for Chinese, Japanese, Korean and similar East Asian languages: Due to how Minecraft's word wrapping works, for best results you should _remove spaces before and after hyperlinks and formatting tags_, excluding images and recipes. However, do not remove the space between a hyperlink's destination and its alt text or the link will break!
If all of that confused you, the simple rule is: _Don't translate anything directly after an `@` symbol, directly after a `#`, or the first word after `#image` or `#recipe`_. However, you should translate the `"caption"` entries in the `images` block.
**Please ensure all translation files are encoded in UTF-8 format, otherwise they might crash the game!**
+43 -5
View File
@@ -1,8 +1,8 @@
# Credits
Electroblob's Wizardry
Version 2.1.0
For Minecraft 1.10.2
Version 4.3.5
For Minecraft 1.12.2
Designed, coded and textured by Electroblob
@@ -12,9 +12,47 @@ Thanks also to the Minecraft modding community, which always has an answer to my
In addition, I'd like to thank the following individuals for their contributions to the mod:
#### Discord Moderators (and all-round awesome people)
- FavouriteDragon
- WinDanesz
#### Code
- Corail31
- 12foo
- Shadows-of-Fire
- HellFirePvP
- Tora-B
- Avatair
- Aeronica
- UltraHex
- Azim-Palmer
- raoulvdberge
- rafasoares
- xinyuan-liu
- SettingDust
- Aralu115
#### Translations
- Russian: VilagVil
- Spanish and Mexican Spanish: MadWrist
- Spanish: MadWrist, Alsentar
- Mexican Spanish: MadWrist
- Russian: VilagVil, kellixon, bigenergy, MugGod2, DrHesperus
- French: Hahdrim, Crowller
- Brazilian Portuguese: lorrampi
- Chinese (Simplified): ZHENGLOC, dragon-evol, Hokorizero, TUsama, Determancer
- Korean: shejery, rewi_wire, 방통, red1854th
- Polish: Trozuu, Olej
- German: BirdyDragon, Lemopav
- Chinese (Traditional): chesterccj305
- Hungarian: Bombadil
Lightning ray sound effect from OhhWowProductions
#### Sound Effects
- OhhWowProductions
- fredzed
- deleted_user_3277771
- DiscoveryME
- OGSoundFX
- leosalom
- juskiddink
+4 -2
View File
@@ -1,5 +1,7 @@
Minecraft version: 1.10.2 [change as necessary]
Wizardry version: 2.1.0 [change as necessary]
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting. You may also find the [troubleshooting page](https://github.com/Electroblob77/Wizardry/wiki/Troubleshooting) helpful.
Minecraft version: 1.12.2 [change as necessary]
Wizardry version: [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.]
+4 -4
View File
@@ -1,7 +1,7 @@
# License
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 and assets 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.)
@@ -17,7 +17,7 @@ TL;DR: Do what you want with this repo on Github, but ask me first if you want t
'Electroblob's Wizardry', 'Wizardry', 'the mod' - The Minecraft modification Electroblob's Wizardry
'Repository' - This repository on Github, containing this license, other informational files, configurations, code and assets which are part of Electroblob's Wizardry
'Repository' - This repository on Github, containing this license, the wiki, other informational files, configurations, code and assets which are part of Electroblob's Wizardry
'Curseforge' - The webpage https://minecraft.curseforge.com/projects/electroblobs-wizardry
@@ -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
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.
@@ -37,7 +37,7 @@ In addition to private use as set out in section 1, you are free to fork this re
### 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
+3 -3
View File
@@ -1,10 +1,10 @@
# Wizardry &nbsp;[![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 &nbsp;[![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/hs8yJP2)
![Image not found](https://media-elerium.cursecdn.com/attachments/203/387/banner7.png)
![Image not found](https://raw.githubusercontent.com/wiki/Electroblob77/Wizardry/en_gb/images/banners/art_banner.png)
Source code for Electroblob's Wizardry, a Minecraft mod currently for versions 1.7.10, 1.10.2, 1.11.2, and 1.12.2. Wizardry adds an RPG-style system of magic spells to Minecraft with the aim of being as playable as possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master the arcane!
Please read the [guide for contributing](guide_for_contributing.md) before submitting an issue or a PR.
Please read the [guide for contributing](CONTRIBUTING.md) before submitting an issue or a PR.
<b>Links</b>
+56 -47
View File
@@ -1,64 +1,73 @@
buildscript {
repositories {
mavenCentral()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {
name = "sonatype"
url = "https://oss.sonatype.org/content/repositories/snapshots/"
}
jcenter()
maven { url = "http://files.minecraftforge.net/maven" }
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
version = "4.3.5" // There, it matches semver, happy now?
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "ElectroblobsWizardry"
sourceCompatibility = targetCompatibility = "1.8" // Need this here so eclipse task generates correctly.
compileJava {
sourceCompatibility = targetCompatibility = "1.8"
}
repositories {
maven {
// location of the maven that hosts JEI files
name = "Progwml6 maven"
url = "http://dvs1.progwml6.com/files/maven"
}
maven {
// location of a maven mirror for JEI files, as a fallback
name = "ModMaven"
url = "modmaven.k-4u.nl"
}
maven {
name = "Curseforge Maven"
url = "https://minecraft.curseforge.com/api/maven/"
}
}
apply plugin: 'forge'
version = " 1.1.4 - MC 1.7.10"
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "Electroblob's Wizardry "
minecraft {
version = "1.7.10-10.13.4.1558-1.7.10"
runDir = "eclipse"
}
task deobfJar(type: Jar) { // Generate deobfuscated
from sourceSets.main.output
classifier = 'deobf'
}
task sourceJar(type: Jar) { // Generate sources
from sourceSets.main.allSource
classifier = 'sources'
}
tasks.build.dependsOn('sourceJar', 'deobfJar')
artifacts {
archives deobfJar
archives sourceJar
archives jar
version = "1.12.2-14.23.5.2847"
runDir = "run"
// the mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD snapshot are built nightly.
// stable_# stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not always work.
// simply re-run your setup task after changing the mappings to update your workspace.
mappings = "stable_39"
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
}
dependencies {
// you may put jars on which you depend on in ./libs
// or you may define them like so..
//compile "some.group:artifact:version:classifier"
//compile "some.group:artifact:version"
// real examples
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// for more info...
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html
// Compile against the JEI API but do not include it at runtime
deobfProvided "mezz.jei:jei_${mc_version}:${jei_version}:api"
// At runtime, use the full JEI jar
runtime "mezz.jei:jei_${mc_version}:${jei_version}"
deobfCompile "baubles:Baubles:${mc_version_short}:${baubles_version}"
deobfCompile "antique-atlas:antiqueatlas:${mc_version}:${antique_atlas_version}"
}
processResources
{
task deobfJar(type: Jar) {
from sourceSets.main.output
classifier = 'deobf'
}
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
@@ -71,7 +80,7 @@ processResources
expand 'version':project.version, 'mcversion':project.minecraft.version
}
// copy everything else, thats not the mcmod.info
// copy everything else except the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
+8
View File
@@ -0,0 +1,8 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G
mc_version=1.12.2
mc_version_short=1.12
jei_version=4.15.0.291
baubles_version=1.5.2
antique_atlas_version=4.6.3
Binary file not shown.
+1 -2
View File
@@ -1,6 +1,5 @@
#Wed Jul 02 15:54:47 CDT 2014
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
Vendored
+59 -51
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
##############################################################################
##
@@ -6,47 +6,6 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -61,9 +20,49 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -90,7 +89,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
Vendored
+4 -10
View File
@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +46,9 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
-29
View File
@@ -1,29 +0,0 @@
# Guide for contributing to this repository
## Submitting an issue
When submitting an issue, please stick to the issue template. 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! Most importantly, use gist or pastebin to post crash reports.
## Submitting a PR
I like my code to be tidy, so it saves me time if yours is too. Here are a few general guidelines for how to submit a good PR:
- Use proper indentation and try to space your code out nicely. This really goes without saying - select all your code and hit ctrl-i before you submit it, and try to use my spacing if you can (for instance, don't do what the Minecraft source does and put a { on a separate line, it's a waste of space).
- Commented code is dead code, UNLESS it has an accompanying comment detailing an appropriate reason for it being commented. (something like "DO NOT REMOVE, commented because it will be useful in 1.12" or "DO NOT REMOVE, commented for debugging purposes, uncomment when fixed")
- Please comment your methods/fields/classes! Preferably using Javadoc, but for small/private methods one line comments are OK. I find it hard enough to remember what I wrote a method for if it isn't commented, let alone trying to work out what yours are for. That said, you should try to name the method/field/class so it's obvious what it is anyway.
- Please use @Override when overriding any methods.
- Follow naming conventions. BLOCK_CAPITALS for constants, CapitalisedWords for classes, camelCase for almost everything else.
- This isn't code related, but when you submit a PR, please tell me what it does! You don't need much, just something like "Makes item X do X" or "Fixes #162". If you're resolving an issue, put "Fixes", "Closes" or "Resolves" and then the issue number and Github will close it automatically.
## Guide for translators
Pull requests aren't just for code - if you would like to help translate Wizardry, you can do that here too! Simply fork the repository, add your translations and submit a PR when you're done. Wizardry has TWO files you'll need to translate: the usual .lang file and the handbook text file, which can be found in resources/assets/wizardry/texts.
- Firstly, the .lang file: if you're familiar with translating mods, this is all pretty standard - it holds the names of blocks, items, mobs and so on. Ignore the %X$s bits, they're placeholders for stuff that gets put in by Wizardry when the game is running.
- Secondly, the handbook text file: the US english version is named handbook_en_US.txt, and (rather obviously) other languages' text files replace 'en_US' with the name of their corresponding .lang file. Anything wirtten in BLOCK CAPITALS should be left alone, because Wizardry replaces it with the appropriate text when the game is running.
Binary file not shown.
Binary file not shown.
@@ -1,203 +1,334 @@
package electroblob.wizardry;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import cpw.mods.fml.common.FMLCommonHandler;
import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketCastSpell;
import electroblob.wizardry.packet.PacketClairvoyance;
import electroblob.wizardry.packet.PacketGlyphData;
import electroblob.wizardry.packet.PacketPlayerSync;
import electroblob.wizardry.packet.PacketTransportation;
import electroblob.wizardry.block.BlockBookshelf;
import electroblob.wizardry.inventory.ContainerArcaneWorkbench;
import electroblob.wizardry.item.ItemSpectralBow;
import electroblob.wizardry.packet.*;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.spell.Spell;
import net.minecraft.block.Block;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemArmor.ArmorMaterial;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.StatCollector;
import net.minecraft.util.Vec3;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.translation.I18n;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Property;
/** The common proxy for wizardry, serving the usual purpose of dealing with all things that need to be handled
* differently on the client and the server. A lot of the methods here appear to do absolutely nothing; this is
* because they do client-only things which are only handled in the client proxy.
* @see {@link electroblob.wizardry.client.ClientProxy} */
import javax.annotation.Nullable;
import java.util.List;
import java.util.Set;
/**
* The common proxy for wizardry, serving the usual purpose of dealing with all things that need to be handled
* differently on the client and the server. A lot of the methods here appear to do absolutely nothing; this is because
* they do client-only things which are only handled in the client proxy.
*
* @see electroblob.wizardry.client.ClientProxy ClientProxy
* @author Electroblob
* @since Wizardry 1.0
*/
@SuppressWarnings("deprecation")
public class CommonProxy {
/** Used to store IExtendedEntityProperties data temporarily between player death and respawn */
private static final Map<String, NBTTagCompound> extendedEntityData = new HashMap<String, NBTTagCompound>();
public void registerRenderers(){}
public void registerKeyBindings(){}
public void registerSpellHUD(){}
public ModelBiped getWizardArmourModel(){
// SECTION Registry
// ===============================================================================================================
public void registerRenderers(){}
public void initialiseLayers(){}
public void initialiseAnimations(){}
public void registerKeyBindings(){}
public net.minecraft.client.model.ModelBiped getWizardArmourModel(ArmorMaterial material){
return null;
}
public void initGuiBits(){}
/**
* Adds an entity's custom data to the map for temporary storage
* @param compound An NBT Tag Compound that stores the IExtendedEntityProperties data only
*/
public static void storeEntityData(String name, NBTTagCompound compound){
extendedEntityData.put(name, compound);
}
public void registerResourceReloadListeners(){}
/**
* Removes the compound from the map and returns the NBT tag stored for name or null if none exists
*/
public static NBTTagCompound getEntityData(String name){
return extendedEntityData.remove(name);
}
public double getPlayerEyesPos(EntityPlayer player){
return player.posY + player.eyeHeight;
}
/** Gets the absolute coordinates of the tip of the wand belonging to the given entity. If this is a client in
* first person view, the coordinates will instead be the entity's position + 1.2. */
public Vec3 getWandTipPosition(EntityLivingBase entity){
// 0.7 forwards, 0.4 to the right, and 1.35 upwards.
double x = entity.posX - 0.7*Math.sin(Math.toRadians(entity.renderYawOffset)) - 0.4*Math.cos(Math.toRadians(entity.renderYawOffset));
double y = entity.boundingBox.minY + 1.35;
double z = entity.posZ + 0.7*Math.cos(Math.toRadians(entity.renderYawOffset)) - 0.4*Math.sin(Math.toRadians(entity.renderYawOffset));
return Vec3.createVectorHelper(x, y, z);
}
/**
* Spawns a custom particle of the specified type.
*
* @param type EnumParticleType of the particle
* @param world Reference to the World object
* @param x Particle x position
* @param y Particle y position
* @param z Particle z position
* @param velX Particle x velocity
* @param velY Particle y velocity
* @param velZ Particle z velocity
* @param maxAge Lifetime of the particle in ticks
* @param r Red component of particle colour
* @param g Red component of particle colour
* @param b Red component of particle colour
* @param doGravity Whether the particle is affected by gravity (only affects SPARKLE at the moment)
* @param radius The radius of the particle's motion, for cirular motion particles
*/
public void spawnParticle(EnumParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b, boolean doGravity, double radius){
// Does nothing since particles are client-side only
}
/** Spawns a custom particle of the specified type. doGravity defaults to false and radius defaults to 0.
* Note that some of these settings may not affect the particle; some particles are always affected by
* gravity, for instance.
*
* @param type EnumParticleType of the particle
* @param world Reference to the World object
* @param x Particle x position
* @param y Particle y position
* @param z Particle z position
* @param velX Particle x velocity
* @param velY Particle y velocity
* @param velZ Particle z velocity
* @param maxAge Lifetime of the particle in ticks
* @param r Red component of particle colour (unless this is a MAGIC_FIRE particle, in which case this is the scale)
* @param g Red component of particle colour
* @param b Red component of particle colour
*/
public void spawnParticle(EnumParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge, float r, float g, float b){
this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, r, g, b, false, 0);
}
/** Spawns a custom particle of the specified type. Colour defaults to white, doGravity defaults to false and radius
* defaults to 0. Note that some of these settings may not affect the particle; some particles are always affected by
* gravity, for instance.
*
* @param type EnumParticleType of the particle
* @param world Reference to the World object
* @param x Particle x position
* @param y Particle y position
* @param z Particle z position
* @param velX Particle x velocity
* @param velY Particle y velocity
* @param velZ Particle z velocity
* @param maxAge Lifetime of the particle in ticks
*/
public void spawnParticle(EnumParticleType type, World world, double x, double y, double z, double velX, double velY, double velZ, int maxAge){
this.spawnParticle(type, world, x, y, z, velX, velY, velZ, maxAge, 1, 1, 1, false, 0);
}
public void spawnDigParticle(World world, double x, double y, double z, double velX, double velY, double velZ, Block block){}
public void registerSoundEventListener(){}
public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius, int maxAge, Block block, int metadata){}
/** Plays a sound which moves with the given entity.
*
* @param entity The source of the sound
* @param soundName String resource path of the sound
* @param volume Volume relative to 1
* @param pitch Pitch relative to 1
* @param repeat Whether to repeat the sound for as long as the entity is alive (or until stopped manually)
*/
public void playMovingSound(Entity entity, String soundName, float volume, float pitch, boolean repeat){}
public void handleCastSpellPacket(PacketCastSpell.Message message){}
public double getWandDisplayDamage(ItemStack stack){
return 1.0d;
}
public int getConjuredItemDisplayDamage(ItemStack stack){
return 0;
}
public void registerAtlasMarkers(){}
public void registerEventHandlers(){
MinecraftForge.EVENT_BUS.register(new WizardryEventHandler());
}
// SECTION Particles
// ===============================================================================================================
public void handleTransportationPacket(PacketTransportation.Message message){}
/** Called from init() in the main mod class to initialise the particle factories. */
public void registerParticles(){} // Does nothing since particles are client-side only
public FontRenderer getFontRenderer(ItemStack stack) {
/** Creates a new particle of the specified type from the appropriate particle factory. <i>Does not actually spawn the
* particle; use {@link electroblob.wizardry.util.ParticleBuilder ParticleBuilder} to spawn particles.</i> */
public electroblob.wizardry.client.particle.ParticleWizardry createParticle(ResourceLocation type, World world, double x, double y, double z){
return null;
}
/** Returns the translated name of the scroll, taking spell discovery into account. If, for some reason, this gets
* called server-side, it uses the deprecated server version of I18n, with a warning. Since any likely server-side
* use of this method will be for text-based logic purposes (like Bibliocraft's book checking system), and since no
* particular player instance can be accessed, spell discovery is ignored. */
public void spawnTornadoParticle(World world, double x, double y, double z, double velX, double velZ, double radius,
int maxAge, IBlockState block, BlockPos pos){
}
// SECTION Items
// ===============================================================================================================
public boolean shouldDisplayDiscovered(Spell spell, @Nullable ItemStack stack){
return false;
}
public net.minecraft.client.gui.FontRenderer getFontRenderer(ItemStack stack){
return null;
}
/**
* Returns the translated name of the scroll, taking spell discovery into account. If, for some reason, this gets
* called server-side, it uses the deprecated server version of I18n. Since any likely server-side
* use of this method will be for text-based logic purposes (like Bibliocraft's book checking system), and since
* no particular player instance can be accessed, spell discovery is ignored.
*/
public String getScrollDisplayName(ItemStack scroll){
// I have now learnt that the server side I18n always translates to the default en_US, so I could just return
// a hardcoded name in English instead.
//Wizardry.logger.info("A mod has called ItemScroll#getItemStackDisplayName from the server side. Using the"
// + "deprecated server-side translation methods as a fallback.");
// Displays [Empty slot] if spell is continuous.
Spell spell = Spell.get(scroll.getItemDamage());
if(spell.isContinuous) spell = WizardryRegistry.none;
return StatCollector.translateToLocalFormatted("item.scroll.name", StatCollector.translateToLocal("spell." + spell.getUnlocalisedName())).trim();
Spell spell = Spell.byMetadata(scroll.getItemDamage());
return I18n.translateToLocalFormatted("item." + Wizardry.MODID + ":scroll.name",
I18n.translateToLocal("spell." + spell.getUnlocalisedName())).trim();
}
public double getConjuredBowDurability(ItemStack stack){
return ((ItemSpectralBow)WizardryItems.spectral_bow).getDefaultDurabilityForDisplay(stack);
}
/**
* Translates the given key with no specified style. Client-side only; on the server this simply returns
* the given translation key. Useful whenever translation from common classes is required, e.g. item tooltips.
* @param key The unlocalised name to be translated.
* @param args The format arguments to pass into the translation, if any.
* @return The resulting translated text.
*/
public String translate(String key, Object... args){
return translate(key, new Style(), args);
}
/**
* Translates the given key and formats it with the given style. Client-side only; on the server this simply returns
* the given translation key. Useful whenever translation from common classes is required, e.g. item tooltips.
* @param key The unlocalised name to be translated.
* @param style The {@link Style} to use for the displayed text.
* @param args The format arguments to pass into the translation, if any.
* @return The resulting translated text.
*/
public String translate(String key, Style style, Object... args){
return key;
}
/** Like {@link CommonProxy#addMultiLineDescription(List, String, Style, Object...)}, but style defaults to light grey. */
public void addMultiLineDescription(List<String> tooltip, String key, Object... args){
this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY), args);
}
/**
* Adds a multi-line description to the given tooltip list. The description is first translated using the given
* translation key, then the formatting code for the given style is appended, and finally the string is word-wrapped
* to the standard width (100).
* @param tooltip The tooltip list to add to
* @param key The translation key for the description
* @param style A style to apply
*/
public void addMultiLineDescription(List<String> tooltip, String key, Style style, Object... args){}
// SECTION Packet Handlers
// ===============================================================================================================
public void handlePlayerSyncPacket(PacketPlayerSync.Message message){}
public void handleGlyphDataPacket(PacketGlyphData.Message message){}
public void handleEmitterDataPacket(PacketEmitterData.Message message){}
public void handleCastSpellPacket(PacketCastSpell.Message message){}
public void handleCastContinuousSpellPacket(PacketCastContinuousSpell.Message message){}
public void setToNumberSliderEntry(Property property){}
public void handleNPCCastSpellPacket(PacketNPCCastSpell.Message message){}
public void handleDispenserCastSpellPacket(PacketDispenserCastSpell.Message message){}
public void handleCastSpellAtPosPacket(PacketCastSpellAtPos.Message message){}
public void handleTransportationPacket(PacketTransportation.Message message){}
public void handleClairvoyancePacket(PacketClairvoyance.Message message){}
public void handleAdvancementSyncPacket(PacketSyncAdvancements.Message message){}
public void handleResurrectionPacket(PacketResurrection.Message message){}
public void handlePossessionPacket(PacketPossession.Message message){}
public void handleConquerShrinePacket(PacketConquerShrine.Message message){}
// SECTION Misc
// ===============================================================================================================
public void setToNumberSliderEntry(Property property){}
public void setToHUDChooserEntry(Property property){}
public void setToNamedBooleanEntry(Property property){}
// public void setToEntityNameEntry(Property property){}
/**
* Plays a sound which moves with the given entity.
*
* @param entity The source of the sound
* @param sound The SoundEvent to play
* @param category The SoundCategory to use
* @param volume Volume relative to 1
* @param pitch Pitch relative to 1
* @param repeat Whether to repeat the sound for as long as the entity is alive (or until stopped manually)
*/
public void playMovingSound(Entity entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){}
/**
* Plays the spell charge-up sound at the given entity.
* @param entity The source of the sound
*/
public void playChargeupSound(EntityLivingBase entity){}
/**
* Plays a continuous spell sound which moves with the given entity.
*
* @param entity The source of the sound
* @param spell The spell this sound is associated with
* @param start The starting SoundEvent to play
* @param loop The main looped SoundEvent to play
* @param end The ending SoundEvent to play
* @param category The SoundCategory to use
* @param volume Volume relative to 1
* @param pitch Pitch relative to 1
*/
public void playSpellSoundLoop(EntityLivingBase entity, Spell spell, SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, float volume, float pitch){}
/**
* Plays a continuous spell sound which moves with the given entity.
*
* @param entity The source of the sound
* @param spell The spell this sound is associated with
* @param sounds An array of the sound events to play, which must have three elements in the order: start, loop, end
* @param category The SoundCategory to use
* @param volume Volume relative to 1
* @param pitch Pitch relative to 1
* @throws IllegalArgumentException if the given array contains less than 3 sound events
*/
public void playSpellSoundLoop(EntityLivingBase entity, Spell spell, SoundEvent[] sounds, SoundCategory category, float volume, float pitch){
if(sounds.length < 3) throw new IllegalArgumentException("Tried to play a continuous spell sound using an array "
+ "of sound events, but the given array contained less than 3 sound events!");
playSpellSoundLoop(entity, spell, sounds[0], sounds[1], sounds[2], category, volume, pitch);
}
/**
* Plays a continuous spell sound at the given position.
* @param world The world in which to play the sound
* @param x The x coordinate to play the sound at
* @param y The y coordinate to play the sound at
* @param z The z coordinate to play the sound at
* @param spell The spell this sound is associated with
* @param start The starting SoundEvent to play
* @param loop The main looped SoundEvent to play
* @param end The ending SoundEvent to play
* @param category The SoundCategory to use
* @param volume Volume relative to 1
* @param pitch Pitch relative to 1
* @param duration The duration of the sound, or -1 to link it to a dispenser at the given coordinates
*/
public void playSpellSoundLoop(World world, double x, double y, double z, Spell spell, SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, float volume, float pitch, int duration){}
/**
* Plays a continuous spell sound at the given position.
*
* @param world The world in which to play the sound
* @param x The x coordinate to play the sound at
* @param y The y coordinate to play the sound at
* @param z The z coordinate to play the sound at
* @param spell The spell this sound is associated with
* @param sounds An array of the sound events to play, which must have three elements in the order: start, loop, end
* @param category The SoundCategory to use
* @param volume Volume relative to 1
* @param pitch Pitch relative to 1
* @param duration The duration of the sound, or -1 to link it to a dispenser at the given coordinates
* @throws IllegalArgumentException if the given array contains less than 3 sound events
*/
public void playSpellSoundLoop(World world, double x, double y, double z, Spell spell, SoundEvent[] sounds, SoundCategory category, float volume, float pitch, int duration){
if(sounds.length < 3) throw new IllegalArgumentException("Tried to play a continuous spell sound using an array "
+ "of sound events, but the given array contained less than 3 sound events!");
playSpellSoundLoop(world, x, y, z, spell, sounds[0], sounds[1], sounds[2], category, volume, pitch, duration);
}
/** Starts the first-person blink overlay effect for the specified player. */
public void playBlinkEffect(EntityPlayer player){}
/**
* Starts the client-side screen shake effect for the specified player.
* @param player The player whose screen is to be shaken
* @param intensity The amplitude of the shaking (around 10 looks about right)
*/
public void shakeScreen(EntityPlayer player, float intensity){}
/**
* Loads the given shader for the given player, if they have shaders enabled.
* @param player The player to load the shader for
* @param shader The location of the shader to load
*/
public void loadShader(EntityPlayer player, ResourceLocation shader){}
/**
* Gets the client-side world using {@code Minecraft.getMinecraft().world}. <b>Only to be called client side!</b>
* Returns null on the server side.
*/
public World getTheWorld(){
return null;
}
/**
* Gets the client-side player using Minecraft.getMinecraft().player. <b>Only to be called client side!</b> Returns
* null on the server side.
*/
public EntityPlayer getThePlayer(){
return null;
}
/**
* Returns true if the game is being viewed from the perspective of the given entity and is set to first-person
* view. Always returns false on the server side.
*/
public boolean isFirstPerson(Entity entity){
return false;
}
/** Returns an unmodifiable set of the string keys for all of the loaded spell HUD skins. */
public Set<String> getSpellHUDSkins(){
return null;
}
/** Notifies nearby players of a bookshelf change, causing any lectern or arcane workbench GUI (client-side) or
* container (both sides) to refresh its linked bookshelves (does not send packets). */
public void notifyBookshelfChange(World world, BlockPos pos){
for(EntityPlayer player : world.playerEntities){
if(player.getDistanceSq(pos) < BlockBookshelf.PLAYER_NOTIFY_RANGE * BlockBookshelf.PLAYER_NOTIFY_RANGE){
if(player.openContainer instanceof ContainerArcaneWorkbench){
((ContainerArcaneWorkbench)player.openContainer).refreshBookshelfSlots();
}
}
}
}
}
@@ -1,39 +0,0 @@
package electroblob.wizardry;
import net.minecraft.util.StatCollector;
public enum EnumElement {
MAGIC("\u00A77", "simple"),
FIRE("\u00A74", "fire"),
ICE("\u00A7b", "ice"),
LIGHTNING("\u00A73", "lightning"),
NECROMANCY("\u00A75", "necromancy"),
EARTH("\u00A72", "earth"),
SORCERY("\u00A7a", "sorcery"),
HEALING("\u00A7e", "healing");
/** Display colour for this element */
public final String colour;
/** Unlocalised name for this element */
public final String unlocalisedName;
private EnumElement(String colour, String name){
this.colour = colour;
this.unlocalisedName = name;
}
public EnumElement get(int id){
return this.values()[id];
}
/** Returns the translated display name of this element, without formatting. */
public String getDisplayName() {
return StatCollector.translateToLocal("element." + unlocalisedName);
}
/** Returns the translated display name for wizards of this element, shown in the trading GUI */
public String getWizardName() {
return StatCollector.translateToLocal("element." + unlocalisedName + ".wizard");
}
}
@@ -1,16 +0,0 @@
package electroblob.wizardry;
public enum EnumParticleType {
BLIZZARD,
BRIGHT_DUST,
DARK_MAGIC,
DUST,
ICE,
LEAF,
MAGIC_BUBBLE,
MAGIC_FIRE,
PATH,
SNOW,
SPARK,
SPARKLE
}
@@ -1,21 +0,0 @@
package electroblob.wizardry;
import net.minecraft.util.StatCollector;
public enum EnumSpellType {
ATTACK("attack"),
DEFENCE("defence"),
UTILITY("utility"),
MINION("minion");
private final String unlocalisedName;
EnumSpellType(String name){
this.unlocalisedName = name;
}
public String getDisplayName() {
return StatCollector.translateToLocal("spelltype." + unlocalisedName);
}
}
@@ -1,38 +0,0 @@
package electroblob.wizardry;
import net.minecraft.util.StatCollector;
public enum EnumTier {
BASIC(700, 3, "\u00A7f", "basic"),
APPRENTICE(1000, 4, "\u00A7b", "apprentice"),
ADVANCED(1500, 5, "\u00A71", "advanced"),
MASTER(2500, 6, "\u00A75", "master");
/** Maximum mana a wand of this tier can store. */
public final int maxCharge;
/** Just an ordinal. Shouldn't really be needed but no point changing it now. */
public final int level;
/** The maximum number of upgrades that can be applied to a wand of this tier. */
public final int upgradeLimit;
/** The colour of text associated with this tier */
public final String colour;
private final String unlocalisedName;
private EnumTier(int maxCharge, int upgradeLimit, String colour, String name){
this.maxCharge = maxCharge;
this.level = ordinal();
this.upgradeLimit = upgradeLimit;
this.colour = colour;
this.unlocalisedName = name;
}
public String getDisplayName() {
return StatCollector.translateToLocal("tier." + unlocalisedName);
}
public String getDisplayNameWithFormatting() {
return this.colour + StatCollector.translateToLocal("tier." + unlocalisedName);
}
}
@@ -1,485 +0,0 @@
package electroblob.wizardry;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import java.util.UUID;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import electroblob.wizardry.MagicDamage.DamageType;
import electroblob.wizardry.entity.EntityShield;
import electroblob.wizardry.entity.living.EntitySummonedCreature;
import electroblob.wizardry.packet.PacketCastContinuousSpell;
import electroblob.wizardry.packet.PacketPlayerSync;
import electroblob.wizardry.packet.PacketTransportation;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.None;
import electroblob.wizardry.spell.Spell;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.world.World;
import net.minecraftforge.common.IExtendedEntityProperties;
import net.minecraftforge.common.util.Constants.NBT;
/** IExtendedEntityProperties for players. Everything player-data-related that is needed by wizardry is handled here,
* including the ADS, soulbinding, conjured items, summoned wolves and horses, transportation and clairvoyance. */
public class ExtendedPlayer implements IExtendedEntityProperties {
public final static String name = "WizardryExtendedPlayer";
private final EntityPlayer player;
public int damageToApply;
// These were originally done using the item damage directly, but this caused the annoying re-equip animation
// to keep happening so they were moved to here instead.
public int conjuredSwordDuration;
public int conjuredPickaxeDuration;
public int conjuredBowDuration;
public int conjuredArmourDuration;
public int flamingAxeDuration;
public int frostAxeDuration;
public int magicWeaponDuration;
public int flamingWeaponDuration;
public int freezingWeaponDuration;
public boolean hasSpiritWolf;
public boolean hasSpiritHorse;
/** Whether this player is currently casting a continuous spell via commands. Not saved over world reload
* and reset on player death. */
private Spell currentlyCasting;
/** The time for which this player has been casting a continuous spell via commands. Increments by 1 each tick.
* Not saved over world reload and reset on player death. */
private int castingTick;
/** The damage multiplier for the current continuous spell cast via commands. Not saved over world reload and
* reset on player death. */
private float spellDamageMultiplier;
/** The range multiplier for the current continuous spell cast via commands. Not saved over world reload and
* reset on player death. */
private float spellRangeMultiplier;
/** The duration multiplier for the current continuous spell cast via commands. Not saved over world reload and
* reset on player death. */
private float spellDurationMultiplier;
/** The blast multiplier for the current continuous spell cast via commands. Not saved over world reload and
* reset on player death. */
private float spellBlastMultiplier;
/** Coordinate for the saved transportation stone location. Will be -1 if no location is saved. */
public int transportX, transportY, transportZ;
/** Dimension id which the saved stone circle is in. */
public int transportDimension;
/** Time left until the player teleports under the effect of transportation */
public int tpTimer;
/** Coordinate for the saved clairvoyance location. Will be -1 if no location is saved. */
public int clairvoyanceX, clairvoyanceY, clairvoyanceZ;
/** Dimension id which the saved clairvoyance point is in. */
public int clairvoyanceDimension;
public EntityShield shield;
public WeakReference<EntitySummonedCreature> selectedMinion;
public HashSet<Spell> spellsDiscovered;
private HashSet<UUID> allies;
/** List of usernames of this player's allies. May not be accurate 100% of the time. This is here so that a player
* can view the usernames of their allies even when those allies are not online.
* <b> Do not use this for any other purpose than displaying the names! */
public HashSet<String> allyNames;
private HashSet<UUID> soulboundCreatures;
public ExtendedPlayer(EntityPlayer player){
this.player = player;
this.damageToApply = 0;
this.conjuredSwordDuration = 0;
this.conjuredPickaxeDuration = 0;
this.conjuredBowDuration = 0;
this.conjuredArmourDuration = 0;
this.flamingAxeDuration = 0;
this.frostAxeDuration = 0;
this.magicWeaponDuration = 0;
this.flamingWeaponDuration = 0;
this.freezingWeaponDuration = 0;
this.spellsDiscovered = new HashSet<Spell>();
// 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 initalised)
this.spellsDiscovered.add(WizardryRegistry.magicMissile);
this.hasSpiritWolf = false;
this.hasSpiritHorse = false;
this.currentlyCasting = WizardryRegistry.none;
this.spellDamageMultiplier = 1;
this.spellRangeMultiplier = 1;
this.spellDurationMultiplier = 1;
this.spellBlastMultiplier = 1;
this.castingTick = 0;
this.transportX = -1;
this.transportY = -1;
this.transportZ = -1;
this.transportDimension = 0;
this.clairvoyanceX = -1;
this.clairvoyanceY = -1;
this.clairvoyanceZ = -1;
this.clairvoyanceDimension = 0;
this.tpTimer = 0;
this.allies = new HashSet<UUID>();
this.allyNames = new HashSet<String>();
this.soulboundCreatures = new HashSet<UUID>();
}
public boolean hasSpellBeenDiscovered(Spell spell){
return spellsDiscovered.contains(spell) || spell instanceof None;
}
/**
* Adds the spell to the list of discovered spells for this player. Automatically takes into account
* whether the spell has been discovered. Use this method rather than adding directly to the list
* because it handles the mage of all trades achievement.
* @param spell
*/
public void discoverSpell(Spell spell){
if(spellsDiscovered == null){
spellsDiscovered = new HashSet<Spell>();
}
if(!(spell instanceof None)){
spellsDiscovered.add(spell);
}
if(spellsDiscovered.containsAll(Spell.getSpells(Spell.enabledSpells))){
this.player.triggerAchievement(Wizardry.allSpells);
}
for(EnumElement element : EnumElement.values()){
if(element != EnumElement.MAGIC && spellsDiscovered.containsAll(Spell.getSpells(new Spell.TierElementFilter(null, element)))){
this.player.triggerAchievement(Wizardry.elementMaster);
}
}
}
/** Sets the player's saved transportation stone location. */
public void setStoneLocation(int x, int y, int z, int dimensionID){
this.transportX = x;
this.transportY = y;
this.transportZ = z;
this.transportDimension = dimensionID;
}
/** Sets the player's saved clairvoyance location. */
public void setClairvoyancePoint(int x, int y, int z, int dimensionID){
this.clairvoyanceX = x;
this.clairvoyanceY = y;
this.clairvoyanceZ = z;
this.clairvoyanceDimension = dimensionID;
}
/** Adds the given player to the list of allies belonging to the associated player, or removes the player if
* they are already in the list of allies. Returns true if the player was added, false if they were removed. */
public boolean toggleAlly(EntityPlayer player){
if(this.isPlayerAlly(player)){
this.allies.remove(player.getUniqueID());
// The remove method uses .equals() rather than == so this will work fine.
this.allyNames.remove(player.getCommandSenderName());
return false;
}else{
this.allies.add(player.getUniqueID());
this.allyNames.add(player.getCommandSenderName());
return true;
}
}
/** Returns whether the given player is in this player's list of allies, or is on the same team as this player. */
public boolean isPlayerAlly(EntityPlayer player){
return this.allies.contains(player.getUniqueID()) || this.player.isOnSameTeam(player);
}
/** Adds the given entity to this player's list of soulbound creatures, and returns whether it succeeded. */
public boolean soulbind(EntityLivingBase target){
return this.soulboundCreatures.add(target.getUniqueID());
}
/** Returns whether the given entity has been soulbound to this player. */
public boolean isCreatureSoulbound(EntityPlayer target){
return this.soulboundCreatures.contains(target.getUniqueID());
}
/** Damages all creatures soulbound to this player by the given amount, and removes from the list any that no
* longer exist. */
public void damageAllSoulboundCreatures(float damage){
for(Iterator<UUID> iterator = this.soulboundCreatures.iterator(); iterator.hasNext();){
Entity entity = WizardryUtilities.getEntityByUUID(this.player.worldObj, iterator.next());
if(entity == null) iterator.remove();
if(entity instanceof EntityLivingBase){
if(entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(this.player, DamageType.MAGIC), damage)){
// Sound only plays if the damage succeeds
player.worldObj.playSoundAtEntity(entity, "mob.wither.hurt", 1.0F, player.worldObj.rand.nextFloat() * 0.2F + 1.0F);
}
}
}
}
/** Starts casting the given spell with the given modifiers. */
public void startCastingContinuousSpell(Spell spell, float damageMultiplier, float rangeMultiplier, float durationMultiplier, float blastMultiplier){
this.currentlyCasting = spell;
this.spellDamageMultiplier = damageMultiplier;
this.spellRangeMultiplier = rangeMultiplier;
this.spellDurationMultiplier = durationMultiplier;
this.spellBlastMultiplier = blastMultiplier;
if(!this.player.worldObj.isRemote){
PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(), spell.id(), damageMultiplier, rangeMultiplier, blastMultiplier);
WizardryPacketHandler.net.sendToDimension(message, this.player.worldObj.provider.dimensionId);
}
}
/** Stops casting the current spell. */
public void stopCastingContinuousSpell(){
this.currentlyCasting = WizardryRegistry.none;
this.castingTick = 0;
this.spellDamageMultiplier = 1;
this.spellRangeMultiplier = 1;
this.spellDurationMultiplier = 1;
this.spellBlastMultiplier = 1;
if(!this.player.worldObj.isRemote){
PacketCastContinuousSpell.Message message = new PacketCastContinuousSpell.Message(this.player.getEntityId(), WizardryRegistry.none.id(), 1, 1, 1);
WizardryPacketHandler.net.sendToDimension(message, this.player.worldObj.provider.dimensionId);
}
}
/** Returns whether this player is currently casting a continuous spell via commands. */
public boolean isCasting(){
return this.currentlyCasting != null && this.currentlyCasting != WizardryRegistry.none;
}
/** Returns the continuous spell this player is currently casting via commands, or the 'none' spell if they aren't
* casting anything. */
public Spell currentlyCasting(){
return currentlyCasting;
}
/** Called from the event handler each time the associated player is updated. */
public void update(EntityPlayer entityplayer){
if(this.selectedMinion != null && this.selectedMinion.get() == null) this.selectedMinion = null;
Random random = entityplayer.worldObj.rand;
// Annoyingly, it seems that the armour inventory is dealt with completely separately.
if(entityplayer.inventory.hasItem(Wizardry.spectralHelmet)
|| entityplayer.inventory.hasItem(Wizardry.spectralChestplate)
|| entityplayer.inventory.hasItem(Wizardry.spectralLeggings)
|| entityplayer.inventory.hasItem(Wizardry.spectralBoots)
|| (entityplayer.inventory.armorInventory[3] != null && entityplayer.inventory.armorInventory[3].getItem() == Wizardry.spectralHelmet)
|| (entityplayer.inventory.armorInventory[2] != null && entityplayer.inventory.armorInventory[2].getItem() == Wizardry.spectralChestplate)
|| (entityplayer.inventory.armorInventory[1] != null && entityplayer.inventory.armorInventory[1].getItem() == Wizardry.spectralLeggings)
|| (entityplayer.inventory.armorInventory[0] != null && entityplayer.inventory.armorInventory[0].getItem() == Wizardry.spectralBoots)){
this.conjuredArmourDuration++;
}else{
this.conjuredArmourDuration = 0;
}
if(!entityplayer.worldObj.isRemote){
if(tpTimer == 1){
entityplayer.setPositionAndUpdate(this.transportX + 0.5, this.transportY, this.transportZ + 0.5);
entityplayer.worldObj.playSoundAtEntity(entityplayer, "portal.travel", 1.0f, 1.0f);
entityplayer.addPotionEffect(new PotionEffect(Potion.blindness.id, 50, 0));
IMessage msg = new PacketTransportation.Message(entityplayer.getEntityId());
WizardryPacketHandler.net.sendToDimension(msg, entityplayer.worldObj.provider.dimensionId);
}
if(tpTimer > 0){
tpTimer--;
}
}
if(this.currentlyCasting != null && this.currentlyCasting.isContinuous){
this.currentlyCasting.cast(player.worldObj, player, castingTick++, spellDamageMultiplier, spellRangeMultiplier, spellDurationMultiplier, spellBlastMultiplier);
}else{
this.castingTick = 0;
}
}
/** Called from the event handler each time the associated player dies. Used to reset any variables that shouldn't
* persist over player death. */
public void onPlayerDeath(){
this.conjuredSwordDuration = 0;
this.conjuredPickaxeDuration = 0;
this.conjuredBowDuration = 0;
this.conjuredArmourDuration = 0;
this.flamingAxeDuration = 0;
this.frostAxeDuration = 0;
this.magicWeaponDuration = 0;
this.flamingWeaponDuration = 0;
this.freezingWeaponDuration = 0;
// Death cancels transportation spell.
this.tpTimer = 0;
this.soulboundCreatures = new HashSet<UUID>();
this.currentlyCasting = WizardryRegistry.none;
this.castingTick = 0;
this.spellDamageMultiplier = 1;
this.spellRangeMultiplier = 1;
this.spellDurationMultiplier = 1;
this.spellBlastMultiplier = 1;
}
/**
* Returns the string key to be used when saving and loading the extended player data on respawn.
*/
public static String getSaveKey(EntityPlayer player) {
return player.getUniqueID().toString() + ":" + name;
}
/**
* Used to register these extended properties for the player during EntityConstructing event
* This method is for convenience only; it will make your code look nicer
*/
public static final void register(EntityPlayer player){
player.registerExtendedProperties(ExtendedPlayer.name, new ExtendedPlayer(player));
}
/**
* Returns the ExtendedPlayer properties for the specified player.
*/
public static final ExtendedPlayer get(EntityPlayer player){
return (ExtendedPlayer) player.getExtendedProperties(name);
}
/** Sends a packet to this player's client to synchronise necessary information. Only called server side. */
public void sync(){
if(this.player instanceof EntityPlayerMP){
int id = -1;
if(this.selectedMinion != null && this.selectedMinion.get() != null) id = this.selectedMinion.get().getEntityId();
IMessage msg = new PacketPlayerSync.Message(this.spellsDiscovered, id);
WizardryPacketHandler.net.sendTo(msg, (EntityPlayerMP)this.player);
}
}
@Override
public void saveNBTData(NBTTagCompound compound) {
// NBTTagCompound is for Maps, NBTTagList is for Lists/Sets
NBTTagCompound properties = new NBTTagCompound();
properties.setInteger("conjuredSwordDuration", this.conjuredSwordDuration);
properties.setInteger("conjuredPickaxeDuration", this.conjuredPickaxeDuration);
properties.setInteger("conjuredBowDuration", this.conjuredBowDuration);
properties.setInteger("conjuredArmourDuration", this.conjuredArmourDuration);
properties.setInteger("flamingAxeDuration", this.flamingAxeDuration);
properties.setInteger("frostAxeDuration", this.frostAxeDuration);
properties.setInteger("magicWeaponDuration", this.magicWeaponDuration);
properties.setInteger("flamingWeaponDuration", this.flamingWeaponDuration);
properties.setInteger("freezingWeaponDuration", this.freezingWeaponDuration);
properties.setBoolean("hasSpiritWolf", this.hasSpiritWolf);
properties.setBoolean("hasSpiritHorse", this.hasSpiritHorse);
properties.setInteger("x", this.transportX);
properties.setInteger("y", this.transportY);
properties.setInteger("z", this.transportZ);
properties.setInteger("dimension", this.transportDimension);
properties.setInteger("x2", this.clairvoyanceX);
properties.setInteger("y2", this.clairvoyanceY);
properties.setInteger("z2", this.clairvoyanceZ);
properties.setInteger("dimension2", this.clairvoyanceDimension);
properties.setInteger("tpTimer", this.tpTimer);
NBTTagList tagList = new NBTTagList();
for(UUID id : this.allies){
tagList.appendTag(new NBTTagString(id.toString()));
}
properties.setTag("allies", tagList);
NBTTagList tagList2 = new NBTTagList();
for(String name : this.allyNames){
tagList2.appendTag(new NBTTagString(name));
}
properties.setTag("allyNames", tagList2);
NBTTagList tagList3 = new NBTTagList();
for(UUID id : this.soulboundCreatures){
tagList3.appendTag(new NBTTagString(id.toString()));
}
properties.setTag("soulboundCreatures", tagList3);
int[] spells = new int[this.spellsDiscovered.size()];
int i=0;
for(Spell spell : this.spellsDiscovered){
spells[i] = spell.id();
i++;
}
properties.setIntArray("discoveredSpells", spells);
compound.setTag(name, properties);
}
@Override
public void loadNBTData(NBTTagCompound compound) {
NBTTagCompound properties = (NBTTagCompound) compound.getTag(name);
if(properties != null){
this.conjuredSwordDuration = properties.getInteger("conjuredSwordDuration");
this.conjuredPickaxeDuration = properties.getInteger("conjuredPickaxeDuration");
this.conjuredBowDuration = properties.getInteger("conjuredBowDuration");
this.conjuredArmourDuration = properties.getInteger("conjuredArmourDuration");
this.flamingAxeDuration = properties.getInteger("flamingAxeDuration");
this.frostAxeDuration = properties.getInteger("frostAxeDuration");
this.magicWeaponDuration = properties.getInteger("magicWeaponDuration");
this.flamingWeaponDuration = properties.getInteger("flamingWeaponDuration");
this.freezingWeaponDuration = properties.getInteger("freezingWeaponDuration");
this.hasSpiritWolf = properties.getBoolean("hasSpiritWolf");
this.hasSpiritHorse = properties.getBoolean("hasSpiritHorse");
this.transportX = properties.getInteger("x");
this.transportY = properties.getInteger("y");
this.transportZ = properties.getInteger("z");
this.transportDimension = properties.getInteger("dimension");
this.clairvoyanceX = properties.getInteger("x2");
this.clairvoyanceY = properties.getInteger("y2");
this.clairvoyanceZ = properties.getInteger("z2");
this.clairvoyanceDimension = properties.getInteger("dimension2");
this.tpTimer = properties.getInteger("tpTimer");
this.allies = new HashSet<UUID>();
NBTTagList tagList = properties.getTagList("allies", NBT.TAG_STRING);
for(int i=0; i<tagList.tagCount(); i++){
allies.add(UUID.fromString(tagList.getStringTagAt(i)));
}
this.allyNames = new HashSet<String>();
NBTTagList tagList2 = properties.getTagList("allyNames", NBT.TAG_STRING);
for(int i=0; i<tagList2.tagCount(); i++){
allyNames.add(tagList2.getStringTagAt(i));
}
this.soulboundCreatures = new HashSet<UUID>();
NBTTagList tagList3 = properties.getTagList("soulboundCreatures", NBT.TAG_STRING);
for(int i=0; i<tagList3.tagCount(); i++){
soulboundCreatures.add(UUID.fromString(tagList3.getStringTagAt(i)));
}
this.spellsDiscovered = new HashSet<Spell>();
for(int id : properties.getIntArray("discoveredSpells")){
spellsDiscovered.add(Spell.get(id));
}
}
}
@Override
public void init(Entity entity, World world) {
// For reference, apparently there is a strange error that causes 'this' to be null here.
}
}
@@ -1,16 +0,0 @@
package electroblob.wizardry;
import electroblob.wizardry.MagicDamage.DamageType;
import net.minecraft.entity.Entity;
import scala.actors.threadpool.Arrays;
/** This interface allows {@link MagicDamage} and {@link IndirectMagicDamage} to both be treated as instances of a
* single type so that the damage type field can be accessed, rather than having to deal with each of them separately,
* which would be inefficient and cumbersome (the latter of those classes cannot extend the former because they both
* need to extend different subclasses of {@link net.minecraft.util.DamageSource DamageSource}).
* @since Wizardry 1.1 */
public interface IElementalDamage {
DamageType getType();
}
@@ -1,21 +0,0 @@
package electroblob.wizardry;
import electroblob.wizardry.MagicDamage.DamageType;
import net.minecraft.entity.Entity;
import net.minecraft.util.EntityDamageSourceIndirect;
public class IndirectMagicDamage extends EntityDamageSourceIndirect implements IElementalDamage {
private final DamageType type;
public IndirectMagicDamage(String name, Entity magic, Entity caster, DamageType type) {
super(name, magic, caster);
this.type = type;
}
@Override
public DamageType getType(){
return type;
}
}
@@ -1,216 +0,0 @@
package electroblob.wizardry;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import electroblob.wizardry.entity.living.EntityBlazeMinion;
import electroblob.wizardry.entity.living.EntityIceGiant;
import electroblob.wizardry.entity.living.EntityIceWraith;
import electroblob.wizardry.entity.living.EntityLightningWraith;
import electroblob.wizardry.entity.living.EntityPhoenix;
import electroblob.wizardry.entity.living.EntityShadowWraith;
import electroblob.wizardry.entity.living.EntitySkeletonMinion;
import electroblob.wizardry.entity.living.EntitySpiderMinion;
import electroblob.wizardry.entity.living.EntityStormElemental;
import electroblob.wizardry.entity.living.EntityZombieMinion;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.boss.EntityDragon;
import net.minecraft.entity.boss.EntityWither;
import net.minecraft.entity.monster.EntityBlaze;
import net.minecraft.entity.monster.EntityCaveSpider;
import net.minecraft.entity.monster.EntityGhast;
import net.minecraft.entity.monster.EntityMagmaCube;
import net.minecraft.entity.monster.EntityPigZombie;
import net.minecraft.entity.monster.EntitySkeleton;
import net.minecraft.entity.monster.EntitySnowman;
import net.minecraft.entity.monster.EntitySpider;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSource;
// A note on the use of the vanilla damagesources:
// When using indirect damage sources, the SECOND argument is the original entity (i.e. the caster), and the
// FIRST argument is the actual projectile or whatever that does the damage. getEntity() will return
// the original entity, and getSourceOfDamage() will return the projectile.
// The vanilla approach to damage types is inconsistent, to say the least. Poison is simply 'magic', and relies on
// EntityLivingBase.isPotionApplicable to determine whether an entity is affected or not. Wither, on the other hand, is
// its own damage type, but again relies on the potion to determine what is immune (which in this case is nothing). Fire
// has a proper implementation of course, with both block-based and projectile-based types, and any other damagesource
// can also be designated as fire damage with setFireDamage(). Likewise, projectile and explosion damage can also be
// applied to any damagesource, but these aren't condsidered types in their own right; rather, they seem to be damage
// type 'attributes'.
/** As of wizardry 1.1, this class has replaced the damagesource-related methods in WizardryUtilities, allowing a
* {@link DamageType} to be specified with the damage. The main reason for this is so that damage sources can fit with the
* vanilla behaviour on armour enchantments and such like whilst still being classified as wizardry damage for the purposes
* of friendly fire, etc.
* <p><i>
* In the future, there is scope for an entirely standalone mod based on this idea. Perhaps 'Elemental Damage' could be
* a config-only mod which allows its users to define any number of specific damage types, then give any creature a
* resistance, immunity or vulnerability to each, as well as being able to specify the sources for each type, such as
* enchantments, potions, specific items, certain entities, even particular situations and string damagesource names
* from other mods.
* </i>
* @see IndirectMagicDamage
* @see IElementalDamage
* @since Wizardry 1.1 */
public class MagicDamage extends EntityDamageSource implements IElementalDamage {
/** The name of the damagesource for direct magic damage from the wizardry mod. Defined here so that any
* references get changed automatically. */
public static final String DIRECT_MAGIC_DAMAGE = "wizardryMagic";
/** The name of the damagesource for indirect magic damage from the wizardry mod. Defined here so that any
* references get changed automatically. */
public static final String INDIRECT_MAGIC_DAMAGE = "indirectWizardryMagic";
// 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<Class<? extends Entity>, DamageType[]>();
private final DamageType type;
/** A simple set of constants for the types of damage. The names are deliberately different to those in EnumElement
* to avoid confusion. All types are classified as magic damage in the vanilla system, so witches are resistant to them. */
public enum DamageType {
/** Generic magic damage from the wizardry mod. Like vanilla magic damage, except it doesn't bypass armour. */
MAGIC,
/** Fire damage from the wizardry mod. Counts as fire damage in the vanilla system, so is blocked by any mobs that
* are immune to fire and entities with the fire resistance effect. */
FIRE,
/** Frost (ice) damage from the wizardry mod. Snow golems, ice wraiths and ice giants are immune. */
FROST,
/** Shock (lightning) damage from the wizardry mod. Lightning wraiths and storm elementals are immune. */
SHOCK,
/** Wither damage from the wizardry mod. Withers, wither skeletons and shadow wraiths are immune. */
WITHER,
/** Poison damage from the wizardry mod. Spiders, cave spiders and undead mobs are immune. */
POISON,
/** Force damage from the wizardry mod. Insubstantial creatures (ghast, shadow wraith, etc.) are immune. */
FORCE,
/** Blast damage from the wizardry mod. Affected by the blast protection enchantment. */
BLAST,
/** Radiant damage from the wizardry mod. */
RADIANT;
}
static {
// Of course, the entities that are immune to fire already are since there's a vanilla system for that, but
// they're included here anyway for completeness and in case anyone wants to check if an entity is immune to
// an unspecified element for reasons other than dealing damage.
setEntityImmunities(EntityPhoenix.class, DamageType.FIRE);
setEntityImmunities(EntityBlaze.class, DamageType.FIRE);
setEntityImmunities(EntityBlazeMinion.class, DamageType.FIRE);
setEntityImmunities(EntityPigZombie.class, DamageType.FIRE, DamageType.POISON);
setEntityImmunities(EntityMagmaCube.class, DamageType.FIRE);
setEntityImmunities(EntityGhast.class, DamageType.FIRE);
setEntityImmunities(EntityDragon.class, DamageType.FIRE);
setEntityImmunities(EntityStormElemental.class, DamageType.FIRE, DamageType.SHOCK);
setEntityImmunities(EntityWither.class, DamageType.FIRE, DamageType.WITHER);
setEntityImmunities(EntitySnowman.class, DamageType.FROST);
setEntityImmunities(EntityIceWraith.class, DamageType.FROST);
setEntityImmunities(EntityIceGiant.class, DamageType.FROST);
setEntityImmunities(EntityLightningWraith.class, DamageType.SHOCK);
setEntityImmunities(EntityShadowWraith.class, DamageType.WITHER);
setEntityImmunities(EntitySpider.class, DamageType.POISON);
setEntityImmunities(EntitySpiderMinion.class, DamageType.POISON);
setEntityImmunities(EntityCaveSpider.class, DamageType.POISON);
setEntityImmunities(EntityZombie.class, DamageType.POISON);
setEntityImmunities(EntitySkeleton.class, DamageType.POISON);
setEntityImmunities(EntityZombieMinion.class, DamageType.POISON);
setEntityImmunities(EntitySkeletonMinion.class, DamageType.POISON);
}
public MagicDamage(String name, Entity caster, DamageType type) {
super(name, caster);
this.type = type;
this.setMagicDamage();
if(type == DamageType.FIRE) this.setFireDamage();
if(type == DamageType.BLAST) this.setExplosion();
}
/** Returns true if the given entity is immune to the given damage type according to the entity immunity mappings,
* false otherwise. When you want to check for resistances, check this method rather than just checking the result
* of attackEntityFrom, since that could return false for all sorts of reasons besides immunities. However, if you
* don't need to know whether the damage succeeded or not, there's no point in checking this method. A common use
* of this method is to check for immunity and if so display the "[mob] resisted [spell]" chat message. See
* {@link electroblob.wizardry.spell.Arc Arc} for a good example of this, and also of when not to use it. */
public static boolean isEntityImmune(DamageType type, Entity entity){
// Because Mojang, in their infinite wisdom, did not make wither skeletons their own separate class (despite the
// fact that cave spiders are), I have to test for this manually. Realistically, no mod author would be stupid
// enough to put two entities in one class, so this should be the only time I ever have to do this.
if(type == DamageType.WITHER && (
(entity instanceof EntitySkeleton && ((EntitySkeleton)entity).getSkeletonType() == 1)
|| (entity instanceof EntitySkeletonMinion && ((EntitySkeletonMinion)entity).getSkeletonType() == 1))){
return true;
}
if(type == DamageType.FIRE && entity.isImmuneToFire()) return true;
DamageType[] immunities = MagicDamage.immunityMapping.get(entity.getClass());
return immunities != null && Arrays.asList(immunities).contains(type);
}
// I found a use for varargs!
/** 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){
immunityMapping.put(entityType, immunities);
}
/** Registers the given type of entity as immune to all of the passed in damage types. */
public static void addEntityImmunity(Class<? extends Entity> entityType, DamageType immunity){
List<DamageType> immunities = Arrays.asList(immunityMapping.get(entityType));
immunities.add(immunity);
// Apparently putting 0 here works just fine.
immunityMapping.put(entityType, immunities.toArray(new DamageType[0]));
}
/**
* Returns a DamageSource called "wizardryMagic" with the given entity as the caster. Use in preference to vanilla
* types to allow things to distinguish between magic and regular melee/swords. Unlike DamageSource.magic, it does
* not bypass armour and has a player as the source (rather than nothing). It is still classed as magic damage (for
* the record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway).
* <p>
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire
* mod just to get rid of this method and use the constructor instead.
* @param caster The player or other living entity causing the damage
* @param type The type that this damage belongs to; used for resistances and wand perks. Use
* {@link EnumElement#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might
* reasonably affect creatures that are ususally immune to wither effects).
* @return A damagesource object of type EntityDamageSource
*/
public static DamageSource causeDirectMagicDamage(EntityLivingBase caster, DamageType type)
{
return new MagicDamage(DIRECT_MAGIC_DAMAGE, caster, type);
}
/**
* Returns a DamageSource called "indirectWizardryMagic" with the player as the caster. Use in preference to vanilla
* types to allow things to distinguish between magic and regular arrows/throwables. Unlike
* DamageSource.causeIndirectMagicDamage, it does not bypass armour. It is still classed as magic damage (for the
* record, all this does in vanilla is make witches 85% resistant to it - but that seems kinda right anyway).
* <p>
* Now that this is its own class, this static method is largely redundant, but it's not worth refactoring the entire
* mod just to get rid of this method and use the constructor instead.
* @param magic The entity that actually caused the damage
* @param caster The player or other living entity that cast the spell originally
* @param type The type that this damage belongs to; used for resistances and wand perks. Use
* {@link EnumElement#MAGIC} for regular, non-elemental magic damage (sometimes you might not want an element
* even though the spell has one - for example, not all necromancy spells are 'withery', so some of them might
* reasonably affect creatures that are ususally immune to wither effects).
* @return A damagesource object of type EntityDamageSourceIndirect
*/
public static DamageSource causeIndirectEntityMagicDamage(Entity magic, EntityLivingBase caster, DamageType type)
{
return new IndirectMagicDamage(INDIRECT_MAGIC_DAMAGE, magic, caster, type);
}
@Override
public DamageType getType(){
return type;
}
}
File diff suppressed because it is too large Load Diff
@@ -1,277 +0,0 @@
package electroblob.wizardry;
import java.util.HashMap;
import java.util.Set;
import electroblob.wizardry.spell.Spell;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
/** Much like {@link net.minecraft.enchantment.EnchantmentHelper EnchantmentHelper}, this class has some static methods
* which allow cleaner and more concise interaction with the wand NBT data, which is quite a complex structure. Such
* interaction previously resulted in rather verbose and repetitive code which was hard to read and even harder to debug!
* For example, this class allowed {@link electroblob.wizardry.item.ItemWand ItemWand} to be shortened by about 80 lines.
* In addition, by having all the various null checks and array size checks in one place, the chance of accidental errors
* due to forgetting to check these things is greatly reduced.
* <p>
* Note that these methods contain no game logic at all; they are purely for interacting with the NBT data. Conversely,
* you should never need to access the wand's NBT data directly when using this class, but the keys are public in the
* unlikely case that this is necessary.
* <p>
* Also note that none of the methods in this class actually check that the given ItemStack contains an ItemWand; you
* can, for example, pass in a stack of snowballs without causing problems, but that is of course pointless!
* <p>
* All <b>get</b> methods in this class return some kind of default if the passed-in wand stack has no nbt data.<br>
* All <b>set</b> methods in this class create a new nbt data for the passed-in wand if it has none, before doing
* whatever else they do.
* @see electroblob.wizardry.item.ItemWand ItemWand
* @see electroblob.wizardry.packet.PacketControlInput PacketControlInput
* @since Wizardry 1.1 */
public class WandHelper {
// NBT tag keys
public static final String SPELL_ARRAY_KEY = "spells";
public static final String SELECTED_SPELL_KEY = "selectedSpell";
public static final String COOLDOWN_ARRAY_KEY = "cooldown";
public static final String UPGRADES_KEY = "upgrades";
private static final HashMap<Item, String> upgradeMap = new HashMap<Item, String>();
static {
upgradeMap.put(Wizardry.condenserUpgrade, "condenser");
upgradeMap.put(Wizardry.storageUpgrade, "storage");
upgradeMap.put(Wizardry.siphonUpgrade, "siphon");
upgradeMap.put(Wizardry.rangeUpgrade, "range");
upgradeMap.put(Wizardry.durationUpgrade, "duration");
upgradeMap.put(Wizardry.cooldownUpgrade, "cooldown");
upgradeMap.put(Wizardry.blastUpgrade, "blast");
upgradeMap.put(Wizardry.attunementUpgrade, "attunement");
}
/** Returns an array containing the spells currently bound to the given wand. As of Wizardry 1.1, this array is not
* always the same size; it can be anywhere between 5 and 8 (inclusive) in length. If the wand has no spell data,
* returns an array of length 0. */
public static Spell[] getSpells(ItemStack wand){
Spell[] spells = new Spell[0];
if(wand.stackTagCompound != null){
int[] spellIDs = wand.stackTagCompound.getIntArray(SPELL_ARRAY_KEY);
spells = new Spell[spellIDs.length];
for(int i=0; i<spellIDs.length; i++){
spells[i] = Spell.get(spellIDs[i]);
}
}
return spells;
}
/** Binds the given array of spells to the given wand. The array can be anywhere between 5 and 8 (inclusive) in length. */
public static void setSpells(ItemStack wand, Spell[] spells){
if(wand.stackTagCompound == null) wand.stackTagCompound = new NBTTagCompound();
int[] spellIDs = new int[spells.length];
for(int i=0; i<spells.length; i++){
spellIDs[i] = spells[i] != null ? spells[i].id() : WizardryRegistry.none.id();
}
wand.stackTagCompound.setIntArray(SPELL_ARRAY_KEY, spellIDs);
}
/** Returns the currently selected spell for the given wand, or the 'none' spell if the wand has no spell data. */
public static Spell getCurrentSpell(ItemStack wand){
Spell[] spells = getSpells(wand);
if(wand.stackTagCompound != null){
int selectedSpell = wand.stackTagCompound.getInteger(SELECTED_SPELL_KEY);
if(selectedSpell < spells.length){
return spells[selectedSpell];
}
}
return WizardryRegistry.none;
}
/** Selects the next spell in this wand's list of spells. */
public static void selectNextSpell(ItemStack wand){
// 5 here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades
if(getSpells(wand).length < 0) setSpells(wand, new Spell[5]);
if(wand.stackTagCompound != null){
int numberOfSpells = getSpells(wand).length;
int selectedSpell = wand.stackTagCompound.getInteger(SELECTED_SPELL_KEY);
// Greater than or equal to so that if attunement upgrades are somehow removed by NBT modification it just
// resets.
if(selectedSpell >= numberOfSpells - 1){
selectedSpell = 0;
}else{
selectedSpell++;
}
wand.stackTagCompound.setInteger(SELECTED_SPELL_KEY, selectedSpell);
}
}
/** Selects the previous spell in this wand's list of spells. */
public static void selectPreviousSpell(ItemStack wand){
// 5 here because if the spell array doesn't exist, the wand can't possibly have attunement upgrades
if(getSpells(wand).length < 0) setSpells(wand, new Spell[5]);
// This cannot possibly be null here, and yet I am getting an NPE...
if(wand.stackTagCompound != null){
int numberOfSpells = getSpells(wand).length;
int selectedSpell = wand.stackTagCompound.getInteger(SELECTED_SPELL_KEY);
if(selectedSpell <= 0){
selectedSpell = numberOfSpells - 1;
}else{
selectedSpell--;
}
wand.stackTagCompound.setInteger(SELECTED_SPELL_KEY, selectedSpell);
}
}
/** Returns an array of the cooldowns for each spell bound to the given wand. As of Wizardry 1.1, this array is not
* always the same size; it can be anywhere between 5 and 8 (inclusive) in length. If the wand has no cooldown data,
* returns an array of length 0. */
public static int[] getCooldowns(ItemStack wand){
int[] cooldowns = new int[0];
if(wand.stackTagCompound != null){
return wand.stackTagCompound.getIntArray(COOLDOWN_ARRAY_KEY);
}
return cooldowns;
}
/** Sets the given wand's cooldown array. The array can be anywhere between 5 and 8 (inclusive) in length. */
public static void setCooldowns(ItemStack wand, int[] cooldowns){
if(wand.stackTagCompound == null) wand.stackTagCompound = new NBTTagCompound();
wand.stackTagCompound.setIntArray(COOLDOWN_ARRAY_KEY, cooldowns);
}
/** Decrements the cooldown for each spell bound to the given wand by 1, if that cooldown is greater than 0. */
public static void decrementCooldowns(ItemStack wand){
int[] cooldowns = getCooldowns(wand);
// If there are no cooldowns, it is assumed that they are all zero and therefore nothing needs to be done.
if(cooldowns.length == 0) return;
for(int i=0; i<cooldowns.length; i++){
if(cooldowns[i] > 0) cooldowns[i]--;
}
setCooldowns(wand, cooldowns);
}
/** 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){
int[] cooldowns = getCooldowns(wand);
if(cooldowns.length == 0) return 0;
// Don't need to check if the tag compound is null since the above check is equivalent.
return cooldowns[wand.stackTagCompound.getInteger(SELECTED_SPELL_KEY)];
}
/** Sets the given wand's cooldown for the currently selected spell. */
public static void setCurrentCooldown(ItemStack wand, int cooldown){
if(wand.stackTagCompound == null) wand.stackTagCompound = new NBTTagCompound();
int[] cooldowns = getCooldowns(wand);
// 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.
if(cooldowns.length == 0) cooldowns = new int[getSpells(wand).length];
cooldowns[wand.stackTagCompound.getInteger(SELECTED_SPELL_KEY)] = cooldown;
setCooldowns(wand, cooldowns);
}
/** Returns the number of upgrades of the given type that have been applied to the given wand, or 0 if the wand has
* no upgrade data or the given item is not a valid wand upgrade. */
public static int getUpgradeLevel(ItemStack wand, Item upgrade){
String key = upgradeMap.get(upgrade);
if(wand.stackTagCompound != null && wand.stackTagCompound.hasKey(UPGRADES_KEY) && key != null){
return wand.stackTagCompound.getCompoundTag(UPGRADES_KEY).getInteger(key);
}
return 0;
}
/** Returns the total number of upgrades that have been applied to the given wand, or 0 if the wand has no upgrade
* data. */
public static int getTotalUpgrades(ItemStack wand){
int totalUpgrades = 0;
for(Item item : upgradeMap.keySet()){
totalUpgrades += getUpgradeLevel(wand, item);
}
return totalUpgrades;
}
/** Applies the given upgrade to the given wand, or in other words increases the level for that upgrade by 1. This
* does <b>not</b> account for the individual or total upgrade stack limits. */
public static void applyUpgrade(ItemStack wand, Item upgrade){
if(wand.stackTagCompound == null) wand.stackTagCompound = new NBTTagCompound();
if(!wand.stackTagCompound.hasKey(UPGRADES_KEY)) wand.stackTagCompound.setTag(UPGRADES_KEY, new NBTTagCompound());
NBTTagCompound upgrades = wand.stackTagCompound.getCompoundTag(UPGRADES_KEY);
String key = upgradeMap.get(upgrade);
if(key != null) upgrades.setInteger(key, upgrades.getInteger(key) + 1);
wand.stackTagCompound.setTag(UPGRADES_KEY, upgrades);
}
/** Returns true if the given item is a valid special wand upgrade. */
public static boolean isWandUpgrade(Item upgrade){
return upgradeMap.containsKey(upgrade);
}
/** Returns a set of all the items which are valid special wand upgrades. */
public static Set<Item> getSpecialUpgrades(){
return WandHelper.upgradeMap.keySet();
}
/** Registers a special upgrade with wizardry. Not used in the base mod, but I've put it here to make it easy
* for add-ons to add new wand upgrades.
* @param upgrade The wand upgrade item
* @param identifier A unique string, used as a key for wand nbt tags
* @throws IllegalArgumentException if the passed in identifier is already used for another wand upgrade */
public static void registerSpecialUpgrade(Item upgrade, String identifier){
// Throwing an exception is the best thing to do here, since if a duplicate was allowed weird things would
// happen later with wand NBT.
if(upgradeMap.containsValue(identifier)) throw new IllegalArgumentException("Duplicate wand upgrade identifier: " + identifier);
upgradeMap.put(upgrade, identifier);
}
}
@@ -1,64 +0,0 @@
package electroblob.wizardry;
import java.util.Random;
import electroblob.wizardry.item.ItemScroll;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.item.ItemWizardArmour;
import electroblob.wizardry.spell.Spell;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.WeightedRandomChestContent;
import net.minecraftforge.common.ChestGenHooks;
public class WeightedRandomSpellBook extends WeightedRandomChestContent{
public WeightedRandomSpellBook(ItemStack par1ItemStack, int par2, int par3,
int par4) {
super(par1ItemStack, par2, par3, par4);
}
/* A brief comment about dungeon loot:
* Tiers are weighted as per usual. Elements all have equal chance, INCLUDING simple stuff. The main reason for
* this is that dungeon loot is not that common anyway, so making elemental gear even rarer would be too much.
*/
protected ItemStack[] generateChestContent(Random random, IInventory newInventory){
if(theItemId.getItem() instanceof ItemSpellBook){
theItemId = new ItemStack(theItemId.getItem(), 1, WizardryUtilities.getStandardWeightedRandomSpellId(random));
}else if(theItemId.getItem() instanceof ItemWand){
theItemId = new ItemStack(WizardryUtilities.getWand(EnumTier.BASIC, EnumElement.values()[random.nextInt(EnumElement.values().length)]));
}else if(theItemId.getItem() instanceof ItemWizardArmour){
theItemId = new ItemStack(WizardryUtilities.getArmour(EnumElement.values()[random.nextInt(EnumElement.values().length)], random.nextInt(3)));
}else if(theItemId.getItem() instanceof ItemScroll){
int spellId = WizardryUtilities.getStandardWeightedRandomSpellId(random, true);
theItemId = new ItemStack(theItemId.getItem(), 1, spellId);
}else if(theItemId.getItem() == Wizardry.condenserUpgrade){
switch(random.nextInt(8)){
case 0: theItemId = new ItemStack(Wizardry.condenserUpgrade); break;
case 1: theItemId = new ItemStack(Wizardry.siphonUpgrade); break;
case 2: theItemId = new ItemStack(Wizardry.rangeUpgrade); break;
case 3: theItemId = new ItemStack(Wizardry.cooldownUpgrade); break;
case 4: theItemId = new ItemStack(Wizardry.durationUpgrade); break;
case 5: theItemId = new ItemStack(Wizardry.storageUpgrade); break;
case 6: theItemId = new ItemStack(Wizardry.blastUpgrade); break;
case 7: theItemId = new ItemStack(Wizardry.attunementUpgrade); break;
}
}
return ChestGenHooks.generateStacks(random, theItemId, theMinimumChanceToGenerateItem, theMaximumChanceToGenerateItem);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,35 +1,30 @@
package electroblob.wizardry;
import electroblob.wizardry.client.gui.config.GuiConfigWizardry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.IModGuiFactory;
import java.util.Set;
import cpw.mods.fml.client.IModGuiFactory;
import electroblob.wizardry.client.GuiConfigWizardry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
public class WizardryGuiFactory implements IModGuiFactory {
@Override
public void initialize(Minecraft minecraftInstance)
{
}
@Override
public Class<? extends GuiScreen> mainConfigGuiClass()
{
return GuiConfigWizardry.class;
}
@Override
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories()
{
return null;
}
@Override
public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element)
{
return null;
}
@Override
public void initialize(Minecraft minecraftInstance){
}
@Override
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories(){
return null;
}
@Override
public boolean hasConfigGui(){
return true;
}
@Override
public GuiScreen createConfigGui(GuiScreen parentScreen){
return new GuiConfigWizardry(parentScreen);
}
}
@@ -1,63 +1,104 @@
package electroblob.wizardry;
import cpw.mods.fml.common.network.IGuiHandler;
import electroblob.wizardry.client.GuiArcaneWorkbench;
import electroblob.wizardry.client.GuiPortableCrafting;
import electroblob.wizardry.client.GuiSpellBook;
import electroblob.wizardry.client.GuiWizardHandbook;
import electroblob.wizardry.inventory.ContainerArcaneWorkbench;
import electroblob.wizardry.inventory.ContainerBookshelf;
import electroblob.wizardry.inventory.ContainerPortableWorkbench;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.item.ItemWizardHandbook;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.tileentity.ContainerPortableWorkbench;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityBookshelf;
import electroblob.wizardry.tileentity.TileEntityLectern;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.IGuiHandler;
public class WizardryGuiHandler implements IGuiHandler {
/** Incrementable index for the gui ID */
private static int nextGuiId = 0;
public static final int SPELL_BOOK = nextGuiId++;
public static final int ARCANE_WORKBENCH = nextGuiId++;
public static final int WIZARD_HANDBOOK = nextGuiId++;
public static final int PORTABLE_CRAFTING = nextGuiId++;
public static final int BOOKSHELF = nextGuiId++;
public static final int LECTERN = nextGuiId++;
@Override
public Object getServerGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z){
if(id == ARCANE_WORKBENCH){
TileEntity tileEntity = world.getTileEntity(x, y, z);
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
if(tileEntity instanceof TileEntityArcaneWorkbench){
return new ContainerArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench) tileEntity);
return new ContainerArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench)tileEntity);
}
}else if(id == PORTABLE_CRAFTING){
return new ContainerPortableWorkbench(player.inventory, world, new BlockPos(x, y, z));
}else if(id == BOOKSHELF){
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
if(tileEntity instanceof TileEntityBookshelf){
return new ContainerBookshelf(player.inventory, (TileEntityBookshelf)tileEntity);
}
}
else if(id == PORTABLE_CRAFTING){
return new ContainerPortableWorkbench(player.inventory, world, x, y, z);
}
return null;
}
@Override
public Object getClientGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z){
if(id == ARCANE_WORKBENCH){
TileEntity tileEntity = world.getTileEntity(x, y, z);
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
if(tileEntity instanceof TileEntityArcaneWorkbench){
return new GuiArcaneWorkbench(player.inventory, (TileEntityArcaneWorkbench) tileEntity);
return new electroblob.wizardry.client.gui.GuiArcaneWorkbench(player.inventory,
(TileEntityArcaneWorkbench)tileEntity);
}
}else if(id == WIZARD_HANDBOOK && (player.getHeldItemMainhand().getItem() instanceof ItemWizardHandbook
|| player.getHeldItemOffhand().getItem() instanceof ItemWizardHandbook)){
return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook();
}else if(id == SPELL_BOOK){
if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemMainhand());
}else if(player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemOffhand());
}
}else if(id == PORTABLE_CRAFTING){
return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z));
}else if(id == BOOKSHELF){
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
if(tileEntity instanceof TileEntityBookshelf){
return new electroblob.wizardry.client.gui.GuiBookshelf(player.inventory,
(TileEntityBookshelf)tileEntity);
}
}else if(id == LECTERN){
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
if(tileEntity instanceof TileEntityLectern){
return new electroblob.wizardry.client.gui.GuiLectern((TileEntityLectern)tileEntity);
}
}
else if(id == WIZARD_HANDBOOK && player.getHeldItem().getItem() instanceof ItemWizardHandbook){
return new GuiWizardHandbook();
}
else if(id == SPELL_BOOK && player.getHeldItem().getItem() instanceof ItemSpellBook){
return new GuiSpellBook(Spell.get(player.getHeldItem().getItemDamage()));
}
else if(id == PORTABLE_CRAFTING){
return new GuiPortableCrafting(player.inventory, world, x, y, z);
}
return null;
}
}
@@ -1,69 +0,0 @@
package electroblob.wizardry;
import org.lwjgl.input.Keyboard;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.InputEvent;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import electroblob.wizardry.client.ClientProxy;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import net.minecraft.client.Minecraft;
public class WizardryKeyHandler {
boolean NkeyPressed = false;
boolean BkeyPressed = false;
boolean NkeyAlreadyPressed = false;
boolean BkeyAlreadyPressed = false;
@SubscribeEvent
public void onKeyInput(InputEvent.KeyInputEvent event) {
// Key pressed
if(Keyboard.getEventKeyState()){
if(Wizardry.proxy instanceof ClientProxy){
ClientProxy proxy = (ClientProxy)Wizardry.proxy;
if(proxy.nextSpell.isPressed() && Minecraft.getMinecraft().inGameHasFocus){
if(!NkeyPressed){
NkeyPressed = true;
}else{
NkeyAlreadyPressed = true;
}
if(!NkeyAlreadyPressed){
// Packet building
IMessage msg = new PacketControlInput.Message(1);
WizardryPacketHandler.net.sendToServer(msg);
}
}
if(proxy.previousSpell.isPressed() && Minecraft.getMinecraft().inGameHasFocus){
if(!BkeyPressed){
BkeyPressed = true;
}else{
BkeyAlreadyPressed = true;
}
if(!BkeyAlreadyPressed){
// Packet building
IMessage msg = new PacketControlInput.Message(2);
WizardryPacketHandler.net.sendToServer(msg);
}
}
}
}
// Key released
else{
if(NkeyPressed){
NkeyPressed = false;
NkeyAlreadyPressed = false;
}else if(BkeyPressed){
BkeyPressed = false;
BkeyAlreadyPressed = false;
}
}
}
}
@@ -1,631 +0,0 @@
package electroblob.wizardry;
import java.util.ArrayList;
import java.util.List;
import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.entity.EntityFallingGrass;
import electroblob.wizardry.entity.EntityMagicSlime;
import electroblob.wizardry.entity.EntityMeteor;
import electroblob.wizardry.entity.EntityShield;
import electroblob.wizardry.entity.construct.EntityArrowRain;
import electroblob.wizardry.entity.construct.EntityBlackHole;
import electroblob.wizardry.entity.construct.EntityBlizzard;
import electroblob.wizardry.entity.construct.EntityBubble;
import electroblob.wizardry.entity.construct.EntityDecay;
import electroblob.wizardry.entity.construct.EntityEarthquake;
import electroblob.wizardry.entity.construct.EntityFireRing;
import electroblob.wizardry.entity.construct.EntityFireSigil;
import electroblob.wizardry.entity.construct.EntityForcefield;
import electroblob.wizardry.entity.construct.EntityFrostSigil;
import electroblob.wizardry.entity.construct.EntityHailstorm;
import electroblob.wizardry.entity.construct.EntityHammer;
import electroblob.wizardry.entity.construct.EntityHealAura;
import electroblob.wizardry.entity.construct.EntityIceSpike;
import electroblob.wizardry.entity.construct.EntityLightningPulse;
import electroblob.wizardry.entity.construct.EntityLightningSigil;
import electroblob.wizardry.entity.construct.EntityTornado;
import electroblob.wizardry.entity.living.EntityBlazeMinion;
import electroblob.wizardry.entity.living.EntityDecoy;
import electroblob.wizardry.entity.living.EntityEvilWizard;
import electroblob.wizardry.entity.living.EntityIceGiant;
import electroblob.wizardry.entity.living.EntityIceWraith;
import electroblob.wizardry.entity.living.EntityLightningWraith;
import electroblob.wizardry.entity.living.EntityPhoenix;
import electroblob.wizardry.entity.living.EntityShadowWraith;
import electroblob.wizardry.entity.living.EntitySilverfishMinion;
import electroblob.wizardry.entity.living.EntitySkeletonMinion;
import electroblob.wizardry.entity.living.EntitySpiderMinion;
import electroblob.wizardry.entity.living.EntitySpiritHorse;
import electroblob.wizardry.entity.living.EntitySpiritWolf;
import electroblob.wizardry.entity.living.EntityStormElemental;
import electroblob.wizardry.entity.living.EntityWizard;
import electroblob.wizardry.entity.living.EntityZombieMinion;
import electroblob.wizardry.entity.projectile.EntityDarknessOrb;
import electroblob.wizardry.entity.projectile.EntityDart;
import electroblob.wizardry.entity.projectile.EntityFirebolt;
import electroblob.wizardry.entity.projectile.EntityFirebomb;
import electroblob.wizardry.entity.projectile.EntityForceArrow;
import electroblob.wizardry.entity.projectile.EntityForceOrb;
import electroblob.wizardry.entity.projectile.EntityIceCharge;
import electroblob.wizardry.entity.projectile.EntityIceLance;
import electroblob.wizardry.entity.projectile.EntityIceShard;
import electroblob.wizardry.entity.projectile.EntityLightningArrow;
import electroblob.wizardry.entity.projectile.EntityLightningDisc;
import electroblob.wizardry.entity.projectile.EntityMagicMissile;
import electroblob.wizardry.entity.projectile.EntityPoisonBomb;
import electroblob.wizardry.entity.projectile.EntitySmokeBomb;
import electroblob.wizardry.entity.projectile.EntitySpark;
import electroblob.wizardry.entity.projectile.EntitySparkBomb;
import electroblob.wizardry.entity.projectile.EntityThunderbolt;
import electroblob.wizardry.spell.*;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityMagicLight;
import electroblob.wizardry.tileentity.TileEntityPlayerSave;
import electroblob.wizardry.tileentity.TileEntityStatue;
import electroblob.wizardry.tileentity.TileEntityTimer;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.WeightedRandomChestContent;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraftforge.common.ChestGenHooks;
import net.minecraftforge.oredict.OreDictionary;
public final class WizardryRegistry {
// Usage note on ChestGenHooks: First number is minimum, second is maximum. Third is rarity, lower numbers are more rare [bread = 100].
// i starts at 1 here so that 'none' does not spawn.
// Earlier problem solved using clever forge hook - extend WeightedRandomChestContent and override generateChestContent.
// Apparently this seems to be incompatible with roguelike dungeons (any others?), in that it generates the same spell book in
// all of the chests that have a spell book in the same dungeon (usually, though it has been known to do different ones on
// different floors). It also appears to be able to generate the 'none' book, which should be impossible... never mind.
// I don't think that's my fault, or I would have seen a 'none' book in a vanilla dungeon by now.
// Another curious observation: Recurrent complex's generators also seem to always generate the same book/wand/armour
// until you restart the game and can generate the 'none' book as well.
// My best guess as to what's happening is that some mods hook into the dungeon loot differently to others, in that
// they take all the WeightedRandomChestContent objects once and pick from them each time rather than making new ones
// for each chest - which is, in theory, a more efficient way of doing things and will speed up world gen a bit, but
// does of course result in custom chest content implementations behaving strangely. The 'none' book thing remains a
// mystery, however.
/** Called from the preInit method in the main mod class to register the custom dungeon loot. */
public static void registerLoot(){
// The generate loot option only applies to vanilla chests, not wizard tower chests.
if(Wizardry.generateLoot){
String[] chestTypes = {
ChestGenHooks.DUNGEON_CHEST,
ChestGenHooks.PYRAMID_JUNGLE_CHEST,
ChestGenHooks.PYRAMID_DESERT_CHEST,
ChestGenHooks.MINESHAFT_CORRIDOR,
ChestGenHooks.STRONGHOLD_CORRIDOR,
ChestGenHooks.STRONGHOLD_CROSSING,
ChestGenHooks.STRONGHOLD_LIBRARY
};
for(String chest : chestTypes){
ChestGenHooks.addItem(chest, new WeightedRandomSpellBook(new ItemStack(Wizardry.spellBook), 1, 1, Wizardry.SPELL_BOOK_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomSpellBook(new ItemStack(Wizardry.magicWand), 1, 1, Wizardry.WAND_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomSpellBook(new ItemStack(Wizardry.wizardHat), 1, 1, Wizardry.ARMOUR_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomSpellBook(new ItemStack(Wizardry.scroll), 1, 1, Wizardry.SCROLL_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomSpellBook(new ItemStack(Wizardry.condenserUpgrade), 1, 1, Wizardry.WAND_UPGRADE_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomChestContent(new ItemStack(Wizardry.magicCrystal), 1, 4, Wizardry.CRYSTAL_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomChestContent(new ItemStack(Wizardry.arcaneTome, 1, 1), 1, 1, Wizardry.APPRENTICE_TOME_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomChestContent(new ItemStack(Wizardry.arcaneTome, 1, 2), 1, 1, Wizardry.ADVANCED_TOME_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomChestContent(new ItemStack(Wizardry.arcaneTome, 1, 3), 1, 1, Wizardry.MASTER_TOME_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomChestContent(new ItemStack(Wizardry.armourUpgrade), 1, 1, Wizardry.ARMOUR_UPGRADE_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomChestContent(new ItemStack(Wizardry.firebomb), 1, 5, Wizardry.FIREBOMB_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomChestContent(new ItemStack(Wizardry.poisonBomb), 1, 5, Wizardry.POISON_BOMB_FREQUENCY));
ChestGenHooks.addItem(chest, new WeightedRandomChestContent(new ItemStack(Wizardry.smokeBomb), 1, 5, Wizardry.SMOKE_BOMB_FREQUENCY));
if(Wizardry.discoveryMode) ChestGenHooks.addItem(chest, new WeightedRandomChestContent(new ItemStack(Wizardry.identificationScroll), 1, 1, Wizardry.IDENTIFICATION_SCROLL_FREQUENCY));
}
}
// Creates a new ChestGenHooks for wizard towers.
ChestGenHooks chestGen = ChestGenHooks.getInfo(WizardryWorldGenerator.WIZARD_TOWER);
chestGen.setMax(7);
chestGen.setMin(3);
// Wizard tower chests use exactly the same things, minus the firebombs, poison bombs and smoke bombs
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomSpellBook(new ItemStack(Wizardry.spellBook), 1, 1, Wizardry.SPELL_BOOK_FREQUENCY));
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomSpellBook(new ItemStack(Wizardry.magicWand), 1, 1, Wizardry.WAND_FREQUENCY));
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomSpellBook(new ItemStack(Wizardry.wizardHat), 1, 1, Wizardry.ARMOUR_FREQUENCY));
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomSpellBook(new ItemStack(Wizardry.scroll), 1, 1, Wizardry.SCROLL_FREQUENCY));
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomSpellBook(new ItemStack(Wizardry.condenserUpgrade), 1, 1, Wizardry.WAND_UPGRADE_FREQUENCY));
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomChestContent(new ItemStack(Wizardry.magicCrystal), 1, 4, Wizardry.CRYSTAL_FREQUENCY));
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomChestContent(new ItemStack(Wizardry.arcaneTome, 1, 1), 1, 1, Wizardry.APPRENTICE_TOME_FREQUENCY));
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomChestContent(new ItemStack(Wizardry.arcaneTome, 1, 2), 1, 1, Wizardry.ADVANCED_TOME_FREQUENCY));
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomChestContent(new ItemStack(Wizardry.arcaneTome, 1, 3), 1, 1, Wizardry.MASTER_TOME_FREQUENCY));
ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomChestContent(new ItemStack(Wizardry.armourUpgrade), 1, 1, Wizardry.ARMOUR_UPGRADE_FREQUENCY));
if(Wizardry.discoveryMode) ChestGenHooks.addItem(WizardryWorldGenerator.WIZARD_TOWER, new WeightedRandomChestContent(new ItemStack(Wizardry.identificationScroll), 1, 1, Wizardry.IDENTIFICATION_SCROLL_FREQUENCY));
}
/* The name defined here in the regitry is the one Minecraft uses in game for commands like /give, as
* opposed to the one defined earlier with setBlockName() or setUnlocalizedName() which is the one used by
* the lang files. Ideally these should both be the same, but I've written the lang file now, so... */
/** Called from the preInit method in the main mod class to register all the blocks. */
public static void registerBlocks(){
GameRegistry.registerBlock(Wizardry.arcaneWorkbench, "arcane_workbench");
GameRegistry.registerBlock(Wizardry.crystalOre, "crystal_ore");
GameRegistry.registerBlock(Wizardry.petrifiedStone, "petrified_stone");
GameRegistry.registerBlock(Wizardry.iceStatue, "ice_statue");
GameRegistry.registerBlock(Wizardry.magicLight, "magic_light");
GameRegistry.registerBlock(Wizardry.crystalFlower, "crystal_flower");
GameRegistry.registerBlock(Wizardry.snare, "snare");
GameRegistry.registerBlock(Wizardry.transportationStone, "transportation_stone");
GameRegistry.registerBlock(Wizardry.spectralBlock, "spectral_block");
GameRegistry.registerBlock(Wizardry.crystalBlock, "crystal_block");
GameRegistry.registerBlock(Wizardry.meteor, "meteor");
GameRegistry.registerBlock(Wizardry.vanishingCobweb, "vanishing_cobweb");
}
/** Called from the preInit method in the main mod class to register all the items. */
public static void registerItems(){
GameRegistry.registerItem(Wizardry.magicCrystal, "magic_crystal");
GameRegistry.registerItem(Wizardry.magicWand, "magic_wand");
GameRegistry.registerItem(Wizardry.apprenticeWand, "apprentice_wand");
GameRegistry.registerItem(Wizardry.advancedWand, "advanced_wand");
GameRegistry.registerItem(Wizardry.masterWand, "master_wand");
GameRegistry.registerItem(Wizardry.spellBook, "spell_book");
GameRegistry.registerItem(Wizardry.arcaneTome, "arcane_tome");
GameRegistry.registerItem(Wizardry.wizardHandbook, "wizard_handbook");
GameRegistry.registerItem(Wizardry.basicFireWand, "basic_fire_wand");
GameRegistry.registerItem(Wizardry.basicIceWand, "basic_ice_wand");
GameRegistry.registerItem(Wizardry.basicLightningWand, "basic_lightning_wand");
GameRegistry.registerItem(Wizardry.basicNecromancyWand, "basic_necromancy_wand");
GameRegistry.registerItem(Wizardry.basicEarthWand, "basic_earth_wand");
GameRegistry.registerItem(Wizardry.basicSorceryWand, "basic_sorcery_wand");
GameRegistry.registerItem(Wizardry.basicHealingWand, "basic_healing_wand");
GameRegistry.registerItem(Wizardry.apprenticeFireWand, "apprentice_fire_wand");
GameRegistry.registerItem(Wizardry.apprenticeIceWand, "apprentice_ice_wand");
GameRegistry.registerItem(Wizardry.apprenticeLightningWand, "apprentice_lightning_wand");
GameRegistry.registerItem(Wizardry.apprenticeNecromancyWand, "apprentice_necromancy_wand");
GameRegistry.registerItem(Wizardry.apprenticeEarthWand, "apprentice_earth_wand");
GameRegistry.registerItem(Wizardry.apprenticeSorceryWand, "apprentice_sorcery_wand");
GameRegistry.registerItem(Wizardry.apprenticeHealingWand, "apprentice_healing_wand");
GameRegistry.registerItem(Wizardry.advancedFireWand, "advanced_fire_wand");
GameRegistry.registerItem(Wizardry.advancedIceWand, "advanced_ice_wand");
GameRegistry.registerItem(Wizardry.advancedLightningWand, "advanced_lightning_wand");
GameRegistry.registerItem(Wizardry.advancedNecromancyWand, "advanced_necromancy_wand");
GameRegistry.registerItem(Wizardry.advancedEarthWand, "advanced_earth_wand");
GameRegistry.registerItem(Wizardry.advancedSorceryWand, "advanced_sorcery_wand");
GameRegistry.registerItem(Wizardry.advancedHealingWand, "advanced_healing_wand");
GameRegistry.registerItem(Wizardry.masterFireWand, "master_fire_wand");
GameRegistry.registerItem(Wizardry.masterIceWand, "master_ice_wand");
GameRegistry.registerItem(Wizardry.masterLightningWand, "master_lightning_wand");
GameRegistry.registerItem(Wizardry.masterNecromancyWand, "master_necromancy_wand");
GameRegistry.registerItem(Wizardry.masterEarthWand, "master_earth_wand");
GameRegistry.registerItem(Wizardry.masterSorceryWand, "master_sorcery_wand");
GameRegistry.registerItem(Wizardry.masterHealingWand, "master_healing_wand");
GameRegistry.registerItem(Wizardry.spectralSword, "spectral_sword");
GameRegistry.registerItem(Wizardry.spectralPickaxe, "spectral_pickaxe");
GameRegistry.registerItem(Wizardry.spectralBow, "spectral_bow");
GameRegistry.registerItem(Wizardry.manaFlask, "mana_flask");
GameRegistry.registerItem(Wizardry.storageUpgrade, "storage_upgrade");
GameRegistry.registerItem(Wizardry.siphonUpgrade, "siphon_upgrade");
GameRegistry.registerItem(Wizardry.condenserUpgrade, "condenser_upgrade");
GameRegistry.registerItem(Wizardry.rangeUpgrade, "range_upgrade");
GameRegistry.registerItem(Wizardry.durationUpgrade, "duration_upgrade");
GameRegistry.registerItem(Wizardry.cooldownUpgrade, "cooldown_upgrade");
GameRegistry.registerItem(Wizardry.blastUpgrade, "blast_upgrade");
GameRegistry.registerItem(Wizardry.attunementUpgrade, "attunement_upgrade");
GameRegistry.registerItem(Wizardry.flamingAxe, "flaming_axe");
GameRegistry.registerItem(Wizardry.frostAxe, "frost_axe");
GameRegistry.registerItem(Wizardry.firebomb, "firebomb");
GameRegistry.registerItem(Wizardry.poisonBomb, "poison_bomb");
GameRegistry.registerItem(Wizardry.blankScroll, "blank_scroll");
GameRegistry.registerItem(Wizardry.scroll, "scroll");
GameRegistry.registerItem(Wizardry.armourUpgrade, "armour_upgrade");
GameRegistry.registerItem(Wizardry.magicSilk, "magic_silk");
GameRegistry.registerItem(Wizardry.wizardHat, "wizard_hat");
GameRegistry.registerItem(Wizardry.wizardRobe, "wizard_robe");
GameRegistry.registerItem(Wizardry.wizardLeggings, "wizard_leggings");
GameRegistry.registerItem(Wizardry.wizardBoots, "wizard_boots");
GameRegistry.registerItem(Wizardry.wizardHatFire, "wizard_hat_fire");
GameRegistry.registerItem(Wizardry.wizardRobeFire, "wizard_robe_fire");
GameRegistry.registerItem(Wizardry.wizardLeggingsFire, "wizard_leggings_fire");
GameRegistry.registerItem(Wizardry.wizardBootsFire, "wizard_boots_fire");
GameRegistry.registerItem(Wizardry.wizardHatIce, "wizard_hat_ice");
GameRegistry.registerItem(Wizardry.wizardRobeIce, "wizard_robe_ice");
GameRegistry.registerItem(Wizardry.wizardLeggingsIce, "wizard_leggings_ice");
GameRegistry.registerItem(Wizardry.wizardBootsIce, "wizard_boots_ice");
GameRegistry.registerItem(Wizardry.wizardHatLightning, "wizard_hat_lightning");
GameRegistry.registerItem(Wizardry.wizardRobeLightning, "wizard_robe_lightning");
GameRegistry.registerItem(Wizardry.wizardLeggingsLightning, "wizard_leggings_lightning");
GameRegistry.registerItem(Wizardry.wizardBootsLightning, "wizard_boots_lightning");
GameRegistry.registerItem(Wizardry.wizardHatNecromancy, "wizard_hat_necromancy");
GameRegistry.registerItem(Wizardry.wizardRobeNecromancy, "wizard_robe_necromancy");
GameRegistry.registerItem(Wizardry.wizardLeggingsNecromancy, "wizard_leggings_necromancy");
GameRegistry.registerItem(Wizardry.wizardBootsNecromancy, "wizard_boots_necromancy");
GameRegistry.registerItem(Wizardry.wizardHatEarth, "wizard_hat_earth");
GameRegistry.registerItem(Wizardry.wizardRobeEarth, "wizard_robe_earth");
GameRegistry.registerItem(Wizardry.wizardLeggingsEarth, "wizard_leggings_earth");
GameRegistry.registerItem(Wizardry.wizardBootsEarth, "wizard_boots_earth");
GameRegistry.registerItem(Wizardry.wizardHatSorcery, "wizard_hat_sorcery");
GameRegistry.registerItem(Wizardry.wizardRobeSorcery, "wizard_robe_sorcery");
GameRegistry.registerItem(Wizardry.wizardLeggingsSorcery, "wizard_leggings_sorcery");
GameRegistry.registerItem(Wizardry.wizardBootsSorcery, "wizard_boots_sorcery");
GameRegistry.registerItem(Wizardry.wizardHatHealing, "wizard_hat_healing");
GameRegistry.registerItem(Wizardry.wizardRobeHealing, "wizard_robe_healing");
GameRegistry.registerItem(Wizardry.wizardLeggingsHealing, "wizard_leggings_healing");
GameRegistry.registerItem(Wizardry.wizardBootsHealing, "wizard_boots_healing");
GameRegistry.registerItem(Wizardry.spawnWizard, "spawn_wizard");
GameRegistry.registerItem(Wizardry.spectralHelmet, "spectral_helmet");
GameRegistry.registerItem(Wizardry.spectralChestplate, "spectral_chestplate");
GameRegistry.registerItem(Wizardry.spectralLeggings, "spectral_leggings");
GameRegistry.registerItem(Wizardry.spectralBoots, "spectral_boots");
GameRegistry.registerItem(Wizardry.smokeBomb, "smoke_bomb");
GameRegistry.registerItem(Wizardry.identificationScroll, "identification_scroll");
}
/** Called from the preInit method in the main mod class to register all the tileentities. */
public static void registerTileEntities(){
GameRegistry.registerTileEntity(TileEntityArcaneWorkbench.class, Wizardry.MODID + "ArcaneWorkbenchTileEntity");
GameRegistry.registerTileEntity(TileEntityStatue.class, Wizardry.MODID + "PetrifiedStoneTileEntity");
GameRegistry.registerTileEntity(TileEntityMagicLight.class, Wizardry.MODID + "MagicLightTileEntity");
GameRegistry.registerTileEntity(TileEntityTimer.class, Wizardry.MODID + "TimerTileEntity");
GameRegistry.registerTileEntity(TileEntityPlayerSave.class, Wizardry.MODID + "TileEntityPlayerSave");
}
/** Called from the preInit method in the main mod class to register all the entities. */
public static void registerEntities(Wizardry wizardry){
int id = 0; // Incrementable index for the mod specific entity id.
EntityRegistry.registerModEntity(EntityZombieMinion.class, "Zombie Minion", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntityMagicMissile.class, "Magic Missile", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityArc.class, "Arc", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntitySkeletonMinion.class, "Skeleton Minion", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntitySparkBomb.class, "Spark Bomb", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntitySpiritWolf.class, "Spirit Wolf", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntityIceShard.class, "Ice Shard", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityBlazeMinion.class, "Blaze Minion", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityIceWraith.class, "Ice Wraith", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityLightningWraith.class, "Lightning Wraith", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityBlackHole.class, "Black Hole", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityShield.class, "Shield", id++, wizardry, 128, 1, true);
EntityRegistry.registerModEntity(EntityMeteor.class, "Meteor", id++, wizardry, 128, 5, true);
EntityRegistry.registerModEntity(EntityBlizzard.class, "Blizzard", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityWizard.class, "Wizard", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntityBubble.class, "Bubble", id++, wizardry, 128, 3, false);
EntityRegistry.registerModEntity(EntityTornado.class, "Tornado", id++, wizardry, 128, 1, false);
EntityRegistry.registerModEntity(EntityHammer.class, "Lightning Hammer", id++, wizardry, 128, 1, true);
EntityRegistry.registerModEntity(EntityFirebomb.class, "Firebomb", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityForceOrb.class, "Force Orb", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityArrowRain.class, "Arrow Rain", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntitySpark.class, "Spark", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityShadowWraith.class, "Shadow Wraith", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityDarknessOrb.class, "Darkness Orb", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntitySpiderMinion.class, "Spider Minion", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntityHealAura.class, "Healing Aura", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityFireSigil.class, "Fire Sigil", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityFrostSigil.class, "Frost Sigil", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityLightningSigil.class, "Lightning Sigil", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityLightningArrow.class, "Lightning Arrow", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityFirebolt.class, "Firebolt", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityPoisonBomb.class, "Poison Bomb", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityIceCharge.class, "Ice Charge", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityForceArrow.class, "Force Arrow", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityDart.class, "Dart", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityMagicSlime.class, "Magic Slime", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntityForcefield.class, "Forcefield", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityFireRing.class, "Ring of Fire", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityLightningDisc.class, "Lightning Disc", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityThunderbolt.class, "Thunderbolt", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityIceGiant.class, "Ice Giant", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntitySpiritHorse.class, "Spirit Horse", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntityPhoenix.class, "Phoenix", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntitySilverfishMinion.class, "Silverfish Minion", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntityDecay.class, "Decay", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityStormElemental.class, "Storm Elemental", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityEarthquake.class, "Earthquake", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntityFallingGrass.class, "Falling Grass", id++, wizardry, 128, 5, true);
EntityRegistry.registerModEntity(EntityIceLance.class, "Ice Lance", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityHailstorm.class, "Hailstorm", id++, wizardry, 128, 10, false);
EntityRegistry.registerModEntity(EntitySmokeBomb.class, "Smoke Bomb", id++, wizardry, 128, 10, true);
EntityRegistry.registerModEntity(EntityEvilWizard.class, "Evil Wizard", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntityDecoy.class, "Decoy", id++, wizardry, 128, 3, true);
EntityRegistry.registerModEntity(EntityIceSpike.class, "Ice Spike", id++, wizardry, 128, 1, true);
EntityRegistry.registerModEntity(EntityLightningPulse.class, "Lightning Pulse", id++, wizardry, 128, 10, false);
List<BiomeGenBase> biomes = new ArrayList<BiomeGenBase>();
for(BiomeGenBase biome : BiomeGenBase.getBiomeGenArray()){
if(biome != null){
biomes.add(biome);
}
}
// For reference: 5, 1, 1 are the parameters for the witch in vanilla.
EntityRegistry.addSpawn(EntityEvilWizard.class, 3, 1, 1, EnumCreatureType.monster, biomes.toArray(new BiomeGenBase[biomes.size()]));
}
/** Static instance of the none spell, used for various purposes. */
public static Spell none;
/** Static instance of the magic missile spell, used for crafting spell books and by wizards. */
public static Spell magicMissile;
/** Static instance of the transportation spell, used for chat messages. */
public static Spell transportation;
/** Static instance of the clairvoyance spell, used for chat messages. */
public static Spell clairvoyance;
/** Called from the preInit method in the main mod class to register all the spells in wizardry. */
public static void registerSpells(){
// Wizardry 1.0 spells
Spell.register(none = new None());
Spell.register(magicMissile = new MagicMissile());
Spell.register(new Ignite());
Spell.register(new Freeze());
Spell.register(new Snowball());
Spell.register(new Arc());
Spell.register(new Thunderbolt());
Spell.register(new SummonZombie());
Spell.register(new Snare());
Spell.register(new Dart());
Spell.register(new Light());
Spell.register(new Telekinesis());
Spell.register(new Heal());
Spell.register(new Fireball());
Spell.register(new FlameRay());
Spell.register(new Firebomb());
Spell.register(new FireSigil());
Spell.register(new Firebolt());
Spell.register(new FrostRay());
Spell.register(new SummonSnowGolem());
Spell.register(new IceShard());
Spell.register(new IceStatue());
Spell.register(new FrostSigil());
Spell.register(new LightningRay());
Spell.register(new SparkBomb());
Spell.register(new HomingSpark());
Spell.register(new LightningSigil());
Spell.register(new LightningArrow());
Spell.register(new LifeDrain());
Spell.register(new SummonSkeleton());
Spell.register(new Metamorphosis());
Spell.register(new Wither());
Spell.register(new Poison());
Spell.register(new GrowthAura());
Spell.register(new Bubble());
Spell.register(new Whirlwind());
Spell.register(new PoisonBomb());
Spell.register(new SummonSpiritWolf());
Spell.register(new Blink());
Spell.register(new Agility());
Spell.register(new ConjureSword());
Spell.register(new ConjurePickaxe());
Spell.register(new ConjureBow());
Spell.register(new ForceArrow());
Spell.register(new Shield());
Spell.register(new ReplenishHunger());
Spell.register(new CureEffects());
Spell.register(new HealAlly());
Spell.register(new SummonBlaze());
Spell.register(new RingOfFire());
Spell.register(new Detonate());
Spell.register(new FireResistance());
Spell.register(new Fireskin());
Spell.register(new FlamingAxe());
Spell.register(new Blizzard());
Spell.register(new SummonIceWraith());
Spell.register(new IceShroud());
Spell.register(new IceCharge());
Spell.register(new FrostAxe());
Spell.register(new InvokeWeather());
Spell.register(new ChainLightning());
Spell.register(new LightningBolt());
Spell.register(new SummonLightningWraith());
Spell.register(new StaticAura());
Spell.register(new LightningDisc());
Spell.register(new MindControl());
Spell.register(new SummonWitherSkeleton());
Spell.register(new Entrapment());
Spell.register(new WitherSkull());
Spell.register(new DarknessOrb());
Spell.register(new ShadowWard());
Spell.register(new Decay());
Spell.register(new WaterBreathing());
Spell.register(new Tornado());
Spell.register(new Glide());
Spell.register(new SummonSpiritHorse());
Spell.register(new SpiderSwarm());
Spell.register(new Slime());
Spell.register(new Petrify());
Spell.register(new Invisibility());
Spell.register(new Levitation());
Spell.register(new ForceOrb());
Spell.register(transportation = new Transportation());
Spell.register(new SpectralPathway());
Spell.register(new PhaseStep());
Spell.register(new VanishingBox());
Spell.register(new GreaterHeal());
Spell.register(new HealingAura());
Spell.register(new Forcefield());
Spell.register(new Ironflesh());
Spell.register(new Transience());
Spell.register(new Meteor());
Spell.register(new Firestorm());
Spell.register(new SummonPhoenix());
Spell.register(new IceAge());
Spell.register(new WallOfFrost());
Spell.register(new SummonIceGiant());
Spell.register(new Thunderstorm());
Spell.register(new LightningHammer());
Spell.register(new PlagueOfDarkness());
Spell.register(new SummonSkeletonLegion());
Spell.register(new SummonShadowWraith());
Spell.register(new ForestsCurse());
Spell.register(new Flight());
Spell.register(new SilverfishSwarm());
Spell.register(new BlackHole());
Spell.register(new Shockwave());
Spell.register(new SummonIronGolem());
Spell.register(new ArrowRain());
Spell.register(new Diamondflesh());
Spell.register(new FontOfVitality());
// Wizardry 1.1 spells
Spell.register(new SmokeBomb());
Spell.register(new MindTrick());
Spell.register(new Leap());
Spell.register(new PocketFurnace());
Spell.register(new Intimidate());
Spell.register(new Banish());
Spell.register(new SixthSense());
Spell.register(new Darkvision());
Spell.register(clairvoyance = new Clairvoyance());
Spell.register(new PocketWorkbench());
Spell.register(new ImbueWeapon());
Spell.register(new InvigoratingPresence());
Spell.register(new Oakflesh());
Spell.register(new GreaterFireball());
Spell.register(new FlamingWeapon());
Spell.register(new IceLance());
Spell.register(new FreezingWeapon());
Spell.register(new IceSpikes());
Spell.register(new LightningPulse());
Spell.register(new CurseOfSoulbinding());
Spell.register(new Cobwebs());
Spell.register(new Decoy());
Spell.register(new ArcaneJammer());
Spell.register(new ConjureArmour());
Spell.register(new GroupHeal());
Spell.register(new Hailstorm());
Spell.register(new LightningWeb());
Spell.register(new SummonStormElemental());
Spell.register(new Earthquake());
Spell.register(new FontOfMana());
}
/** Called from the init method in the main mod class to register all the recipes. */
public static void registerRecipes(){
ItemStack ironIngotStack = new ItemStack(Items.iron_ingot);
ItemStack magicCrystalStack = new ItemStack(Wizardry.magicCrystal);
ItemStack magicWandStack = new ItemStack(Wizardry.magicWand, 1, EnumTier.BASIC.maxCharge);
ItemStack goldNuggetStack = new ItemStack(Items.gold_nugget);
ItemStack stickStack = new ItemStack(Items.stick);
ItemStack bookStack = new ItemStack(Items.book);
ItemStack stringStack = new ItemStack(Items.string);
ItemStack spellBookStack = new ItemStack(Wizardry.spellBook, 1, WizardryRegistry.magicMissile.id());
ItemStack arcaneWorkbenchStack = new ItemStack(Wizardry.arcaneWorkbench);
ItemStack stoneStack = new ItemStack(Blocks.stone);
ItemStack lapisBlockStack = new ItemStack(Blocks.lapis_block);
ItemStack purpleCarpetStack = new ItemStack(Blocks.carpet, 1, 10);
ItemStack wizardHandbookStack = new ItemStack(Wizardry.wizardHandbook);
ItemStack crystalFlowerStack = new ItemStack(Wizardry.crystalFlower);
ItemStack magicCrystalStack1 = new ItemStack(Wizardry.magicCrystal, 2);
ItemStack magicCrystalStack2 = new ItemStack(Wizardry.magicCrystal, 9);
ItemStack crystalBlockStack = new ItemStack(Wizardry.crystalBlock);
ItemStack manaFlaskStack = new ItemStack(Wizardry.manaFlask);
ItemStack bottleStack = new ItemStack(Items.glass_bottle);
ItemStack gunpowderStack = new ItemStack(Items.gunpowder);
ItemStack blazePowderStack = new ItemStack(Items.blaze_powder);
ItemStack spiderEyeStack = new ItemStack(Items.spider_eye);
// Coal or charcoal is equally fine, hence the wildcard value
ItemStack coalStack = new ItemStack(Items.coal, 1, OreDictionary.WILDCARD_VALUE);
ItemStack firebombStack = new ItemStack(Wizardry.firebomb, 3);
ItemStack poisonBombStack = new ItemStack(Wizardry.poisonBomb, 3);
ItemStack smokeBombStack = new ItemStack(Wizardry.smokeBomb, 3);
ItemStack transportationStoneStack = new ItemStack(Wizardry.transportationStone, 2);
ItemStack silkStack = new ItemStack(Wizardry.magicSilk);
ItemStack silkStack1 = new ItemStack(Wizardry.magicSilk, 2);
ItemStack hatStack = new ItemStack(Wizardry.wizardHat);
ItemStack robeStack = new ItemStack(Wizardry.wizardRobe);
ItemStack leggingsStack = new ItemStack(Wizardry.wizardLeggings);
ItemStack bootsStack = new ItemStack(Wizardry.wizardBoots);
ItemStack scrollStack = new ItemStack(Wizardry.blankScroll);
ItemStack paperStack = new ItemStack(Items.paper);
GameRegistry.addRecipe(magicWandStack, " x", " y ", "z ", 'x', magicCrystalStack, 'y', stickStack, 'z', goldNuggetStack);
GameRegistry.addRecipe(spellBookStack, " x ", "xyx", " x ", 'x', magicCrystalStack, 'y', bookStack);
GameRegistry.addRecipe(arcaneWorkbenchStack, "vwv", "xyx", "zzz", 'v', goldNuggetStack, 'w', purpleCarpetStack, 'x', magicCrystalStack, 'y', lapisBlockStack, 'z', stoneStack);
GameRegistry.addRecipe(manaFlaskStack, "yyy", "yxy", "yyy", 'x', bottleStack, 'y', magicCrystalStack);
GameRegistry.addRecipe(transportationStoneStack, " x ", "xyx", " x ", 'x', stoneStack, 'y', magicCrystalStack);
GameRegistry.addRecipe(hatStack, "yyy", "y y", 'y', silkStack);
GameRegistry.addRecipe(robeStack, "y y", "yyy", "yyy", 'y', silkStack);
GameRegistry.addRecipe(leggingsStack, "yyy", "y y", "y y", 'y', silkStack);
GameRegistry.addRecipe(bootsStack, "y y", "y y", 'y', silkStack);
GameRegistry.addRecipe(silkStack1, " x ", "xyx", " x ", 'x', stringStack, 'y', magicCrystalStack);
GameRegistry.addRecipe(crystalBlockStack, "zzz", "zzz", "zzz", 'z', magicCrystalStack);
GameRegistry.addShapelessRecipe(wizardHandbookStack, bookStack, magicCrystalStack);
GameRegistry.addShapelessRecipe(magicCrystalStack1, crystalFlowerStack);
GameRegistry.addShapelessRecipe(magicCrystalStack2, crystalBlockStack);
if(Wizardry.firebombIsCraftable) GameRegistry.addShapelessRecipe(firebombStack, bottleStack, gunpowderStack, blazePowderStack, blazePowderStack);
if(Wizardry.poisonBombIsCraftable) GameRegistry.addShapelessRecipe(poisonBombStack, bottleStack, gunpowderStack, spiderEyeStack, spiderEyeStack);
if(Wizardry.smokeBombIsCraftable) GameRegistry.addShapelessRecipe(smokeBombStack, bottleStack, gunpowderStack, coalStack, coalStack);
if(Wizardry.useAlternateScrollRecipe){
GameRegistry.addShapelessRecipe(scrollStack, paperStack, stringStack, magicCrystalStack);
}else{
GameRegistry.addShapelessRecipe(scrollStack, paperStack, stringStack);
}
// Mana flask recipes
ItemStack miscWandStack;
for(int i=0; i<EnumElement.values().length; i++){
for(int j=0; j<EnumTier.values().length; j++){
miscWandStack = new ItemStack(WizardryUtilities.getWand(EnumTier.values()[j], EnumElement.values()[i]), 1, OreDictionary.WILDCARD_VALUE);
GameRegistry.addShapelessRecipe(miscWandStack, miscWandStack, manaFlaskStack);
}
}
ItemStack miscArmourStack;
for(int i=0; i<EnumElement.values().length; i++){
for(int j=0; j<4; j++){
miscArmourStack = new ItemStack(WizardryUtilities.getArmour(EnumElement.values()[i], j), 1, OreDictionary.WILDCARD_VALUE);
GameRegistry.addShapelessRecipe(miscArmourStack, miscArmourStack, manaFlaskStack);
}
}
}
}
@@ -1,881 +0,0 @@
package electroblob.wizardry;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import cpw.mods.fml.common.registry.EntityRegistry;
import electroblob.wizardry.entity.living.EntitySummonedCreature;
import electroblob.wizardry.entity.living.EntityWizard;
import electroblob.wizardry.spell.MindControl;
import electroblob.wizardry.spell.Spell;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.command.IEntitySelector;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityList.EntityEggInfo;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.Potion;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
/** This class contains some useful static methods for use anywhere - items, entities, spells, events, blocks, etc.
* @see CommonProxy
* @see WandHelper
* @since Wizardry 1.0 */
public final class WizardryUtilities {
/**
* Finds the nearest floor level to the given y coord within the range specified at the given x and z coords.
* Liquids and other blocks that cannot be built on top of do not count, but stuff like signs does.
* (Technically any block is allowed to be the floor according to the code, but seeing as it searches upwards and
* non-solid blocks usually need a supporting block, the floor is likely to always be solid).
* @param world
* @param x The x coordinate to search in
* @param y The y coordinate to search from
* @param z The z coordinate to search in
* @param range The maximum distance from the given y coordinate to search.
* @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the floor
* as would be seen in the debug screen when the player is standing on it.
* @see WizardryUtilities#getNearestFloorLevelB(World, int, int, int, int)
*/
public static int getNearestFloorLevel(World world, int x, int y, int z, int range){
int yCoord = -2;
for(int i=y-range;i<=y+range;i++){
// The last bit determines whether the block found to be a suitable floor is closer than the previous one found.
// Edit: Changed the first condition from blockExists() since that method includes air blocks!
if(world.doesBlockHaveSolidTopSurface(world, x, i, z) && (world.isAirBlock(x, i+1, z) || !world.doesBlockHaveSolidTopSurface(world, x, i+1, z))
&& (i-y < yCoord-y || yCoord == -2)){
yCoord = i;
}
}
return yCoord + 1;
}
/**
* Returns whether the block at the given coordinates can be replaced by another one (works as if a block is being placed by a player).
* True for air, liquids, vines, tall grass and snow layers but not for flowers, signs etc.
* This is a shortcut for world.getBlock(x, y, z).isReplaceable(world, x, y, z);
* Not much of a shortcut any more, since block ids have been phased out.
* @see WizardryUtilities#canBlockBeReplacedB(World, int, int, int)
*/
public static boolean canBlockBeReplaced(World world, int x, int y, int z){
// Why does isReplaceable have those arguments? I don't know. They aren't used. It's probably for overriding
// stuff in case these arguments affect whether it is replaceable or not. It is a forge method, after all.
return world.isAirBlock(x, y, z) || world.getBlock(x, y, z).isReplaceable(world, x, y, z);
}
/**
* Returns whether the block at the given coordinates can be replaced by another one (works as if a block is being placed by a player)
* and is not a liquid.
* True for air, vines, tall grass and snow layers but not for flowers, signs etc. or any liquids.
* @see WizardryUtilities#canBlockBeReplaced(World, int, int, int)
*/
public static boolean canBlockBeReplacedB(World world, int x, int y, int z){
return (world.isAirBlock(x, y, z) || world.getBlock(x, y, z).isReplaceable(world, x, y, z)) && !world.getBlock(x, y, z).getMaterial().isLiquid();
}
/**
* Returns whether the block at the given coordinates is unbreakable in survival mode. In vanilla this is true for
* bedrock and end portal frame, for example.
* This is a shortcut for world.getBlockId(x, y, z).getBlockHardness == -1.0f;
* Not much of a shortcut any more, since block ids have been phased out.
*/
public static boolean isBlockUnbreakable(World world, int x, int y, int z){
return world.isAirBlock(x, y, z) ? false : world.getBlock(x, y, z).getBlockHardness(world, x, y, z) == -1.0f;
}
/**
* Finds the nearest floor level to the given y coord within the range specified at the given x and z coords.
* Only works if the block above the floor is actually air and the floor is solid or a liquid.
* @param world
* @param x The x coordinate to search in
* @param y The y coordinate to search from
* @param z The z coordinate to search in
* @param range The maximum distance from the given y coordinate to search.
* @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the floor
* as would be seen in the debug screen when the player is standing on it.
* @see WizardryUtilities#getNearestFloorLevel(World, int, int, int, int)
*/
public static int getNearestFloorLevelB(World world, int x, int y, int z, int range){
int yCoord = -2;
for(int i=y-range;i<=y+range;i++){
if(world.isAirBlock(x, i+1, z) && (world.getBlock(x, i, z).getMaterial().isLiquid() || world.doesBlockHaveSolidTopSurface(world, x, i, z))
&& (i-y < yCoord-y || yCoord == -2)){
// The last bit determines whether the block found to be a suitable floor is closer than the previous one found.
yCoord = i;
}
}
return yCoord + 1;
}
/**
* Finds the nearest floor level to the given y coord within the range specified at the given x and z coords.
* Everything that is not air is treated as floor, even stuff that can't be walked on.
* @param world
* @param x The x coordinate to search in
* @param y The y coordinate to search from
* @param z The z coordinate to search in
* @param range The maximum distance from the given y coordinate to search.
* @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the floor
* as would be seen in the debug screen when the player is standing on it.
* @see WizardryUtilities#getNearestFloorLevel(World, int, int, int, int)
*/
public static int getNearestFloorLevelC(World world, int x, int y, int z, int range){
int yCoord = -2;
for(int i=y-range;i<=y+range;i++){
if(world.isAirBlock(x, i+1, z) && (i-y < yCoord-y || yCoord == -2)){
// The last bit determines whether the block found to be a suitable floor is closer than the previous one found.
yCoord = i;
}
}
return yCoord + 1;
}
/**
* Gets the block the specified entity is standing on. Uses {@link MathHelper#floor_double(double)} because casting to int will not
* return the correct coordinate when x or z is negative.
*/
public static Block getBlockEntityIsStandingOn(Entity entity){
return entity.worldObj.getBlock(MathHelper.floor_double(entity.posX), (int)WizardryUtilities.getEntityFeetPos(entity)-1, MathHelper.floor_double(entity.posZ));
}
/**
* Shorthand for {@link WizardryUtilities#getEntitiesWithinRadius(double, double, double, double, World, Class)}
* with EntityLivingBase as the entity type. This is by far the most common use for that method, which is why this
* shorthand exists.
* @param radius The search radius
* @param x The x coordinate to search around
* @param y The y coordinate to search around
* @param z The z coordinate to search around
* @param world The world to search in
*/
public static List<EntityLivingBase> getEntitiesWithinRadius(double radius, double x, double y, double z, World world){
return getEntitiesWithinRadius(radius, x, y, z, world, EntityLivingBase.class);
}
/**
* Returns all entities of the specified type within the specified radius of the given coordinates. This is different to using
* a raw AABB because a raw AABB will search in a cube volume rather than a sphere.
* Note that this does not exclude any entities; if any specific entities are to be excluded this must be
* checked when iterating through the list.
* @see {@link WizardryUtilities#getEntitiesWithinRadius(double, double, double, double, World)}
* @param radius The search radius
* @param x The x coordinate to search around
* @param y The y coordinate to search around
* @param z The z coordinate to search around
* @param world The world to search in
* @param entityType The class of entity to search for; pass in Entity.class for all entities
*/
public static <T extends Entity> List<T> getEntitiesWithinRadius(double radius, double x, double y, double z, World world, Class<T> entityType){
AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox(x - radius, y - radius, z - radius, x + radius, y + radius, z + radius);
List entityList = world.getEntitiesWithinAABB(entityType, aabb);
for(int i=0;i<entityList.size();i++){
if(((Entity)entityList.get(i)).getDistance(x, y, z) > radius){
entityList.remove(i);
}
}
return entityList;
}
// ^ Handy syntax using type parameters here!
// I *think* that eclipse, for whatever reason, was not showing an 'unchecked' warning here. If you think about it,
// if this method returns a generic list type I could, in theory, put strings or something in it and then when
// invoking the method store its result as a List<EntityLivingBase>, which would cause a ClassCastException. Using
// this handy syntax prevents that from happening. TL;DR: Always use type parameters when available, they're there
// for a reason. Minecraft is bad in this respect because it doesn't use them in places like World.
/**
* Gets an entity from its UUID. Note that you should check this isn't null.
* @param world The world the entity is in
* @param id The entity's UUID
* @return The Entity that has the given UUID, or null if no such entity exists in the specified world.
*/
public static Entity getEntityByUUID(World world, UUID id){
for(Object object : world.loadedEntityList){
if(object instanceof Entity){
Entity entity = (Entity)object;
// This is a perfect example of where you need to use .equals() and not ==. For most applications,
// this was unnoticeable until world reload because the UUID instance or entity instance is stored.
// Fixed now though. Of course, you could alternatively compare the string representations.
if(entity.getUniqueID().equals(id)){
return entity;
}
}
}
return null;
}
/**
* Does a block ray trace (NOT entities) from an entity's eyes (i.e. properly...)
*/
public static MovingObjectPosition rayTrace(double range, World world, EntityLivingBase entity, boolean hitLiquids)
{
Vec3 vec3 = Vec3.createVectorHelper(entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ);
Vec3 vec31 = entity.getLookVec();
Vec3 vec32 = vec3.addVector(vec31.xCoord * range, vec31.yCoord * range, vec31.zCoord * range);
return world.rayTraceBlocks(vec3, vec32, hitLiquids);
}
/**
* Helper method which does a rayTrace for entities from an entity's eye level in the direction they are looking
* with a specified range, using the tracePath method. Tidies up the code a bit. Border size defaults to 1.
*
* @param world
* @param entity
* @param range
* @return
*/
public static MovingObjectPosition standardEntityRayTrace(World world, EntityLivingBase entity, double range){
double dx = entity.getLookVec().xCoord * range;
double dy = entity.getLookVec().yCoord * range;
double dz = entity.getLookVec().zCoord * range;
HashSet hashset = new HashSet(1);
hashset.add(entity);
return WizardryUtilities.tracePath(world, (float)entity.posX, (float)(entity.posY + entity.getEyeHeight()), (float)entity.posZ, (float)(entity.posX + dx), (float)(entity.posY + entity.getEyeHeight() + dy), (float)(entity.posZ + dz), 1.0f, hashset, false);
}
/**
* Helper method which does a rayTrace for entities from a entity's eye level in the direction they are looking
* with a specified range and radius, using the tracePath method. Tidies up the code a bit.
*
* @param world
* @param entity
* @param range
* @param borderSize
* @return
*/
public static MovingObjectPosition standardEntityRayTrace(World world, EntityLivingBase entity, double range, float borderSize){
double dx = entity.getLookVec().xCoord * range;
double dy = entity.getLookVec().yCoord * range;
double dz = entity.getLookVec().zCoord * range;
HashSet hashset = new HashSet(1);
hashset.add(entity);
return WizardryUtilities.tracePath(world, (float)entity.posX, (float)(entity.posY + entity.getEyeHeight()), (float)entity.posZ, (float)(entity.posX + dx), (float)(entity.posY + entity.getEyeHeight() + dy), (float)(entity.posZ + dz), borderSize, hashset, false);
}
/**
* Method for ray tracing entities (the useless default method doesn't work, despite EnumHitType having an ENTITY field...)
* You can also use this for seeking.
*
* @param world
* @param x startX
* @param y startY
* @param z startZ
* @param tx endX
* @param ty endY
* @param tz endZ
* @param borderSize extra area to examine around line for entities
* @param excluded any excluded entities (the player, etc)
* @return a MovingObjectPosition of either the block hit (no entity hit), the entity hit (hit an entity), or null for nothing hit
*/
public static MovingObjectPosition tracePath(World world, float x, float y, float z, float tx, float ty, float tz, float borderSize, HashSet<Entity> excluded, boolean collideablesOnly){
Vec3 startVec = Vec3.createVectorHelper(x, y, z);
Vec3 lookVec = Vec3.createVectorHelper(tx-x, ty-y, tz-z);
Vec3 endVec = Vec3.createVectorHelper(tx, ty, tz);
float minX = x < tx ? x : tx;
float minY = y < ty ? y : ty;
float minZ = z < tz ? z : tz;
float maxX = x > tx ? x : tx;
float maxY = y > ty ? y : ty;
float maxZ = z > tz ? z : tz;
AxisAlignedBB bb = AxisAlignedBB.getBoundingBox(minX, minY, minZ, maxX, maxY, maxZ).expand(borderSize, borderSize, borderSize);
List<Entity> allEntities = world.getEntitiesWithinAABBExcludingEntity(null, bb);
MovingObjectPosition blockHit = world.rayTraceBlocks(startVec, endVec);
startVec = Vec3.createVectorHelper(x, y, z);
endVec = Vec3.createVectorHelper(tx, ty, tz);
float maxDistance = (float) endVec.distanceTo(startVec);
if(blockHit!=null)
{
maxDistance = (float) blockHit.hitVec.distanceTo(startVec);
}
Entity closestHitEntity = null;
float closestHit = maxDistance;
float currentHit = 0.f;
AxisAlignedBB entityBb;// = ent.getBoundingBox();
MovingObjectPosition intercept;
for(Entity ent : allEntities)
{
if((ent.canBeCollidedWith() || !collideablesOnly) && ((excluded != null && !excluded.contains(ent)) || excluded == null))
{
float entBorder = ent.getCollisionBorderSize();
entityBb = ent.boundingBox;
if(entityBb!=null)
{
entityBb = entityBb.expand(entBorder, entBorder, entBorder);
intercept = entityBb.calculateIntercept(startVec, endVec);
if(intercept!=null)
{
currentHit = (float) intercept.hitVec.distanceTo(startVec);
if(currentHit < closestHit || currentHit==0)
{
closestHit = currentHit;
closestHitEntity = ent;
}
}
}
}
}
if(closestHitEntity!=null)
{
blockHit = new MovingObjectPosition(closestHitEntity);
}
return blockHit;
}
// Just what benefit does having posY be the eye position on the first person client actually give?
/**
* Gets the y coordinate of the given player's eyes. This is to cover an inconsistency between the value of
* EntityPlayer.posY on the first person client and everywhere else; in first person (i.e. when
* Minecraft.getMinecraft().thePlayer == player) player.posY is the eye position, but everywhere else it is the
* feet position. This is intended for use when spawning particles, since this is the only situation where the
* discrepancy is likely to matter.
*/
public static double getPlayerEyesPos(EntityPlayer player){
return Wizardry.proxy.getPlayerEyesPos(player);
}
/**
* Gets the y coordinate of the given entity's feet. This is to cover an inconsistency between the value of
* EntityPlayer.posY on the first person client and everywhere else; in first person (i.e. when
* Minecraft.getMinecraft().thePlayer == player) player.posY is the eye position, but everywhere else it is the
* feet position. This is intended for use when spawning particles, since this is the only situation where the
* discrepancy is likely to matter.
*/
public static double getEntityFeetPos(Entity entity){
if(entity instanceof EntityPlayer){
// For some reason, EntityPlayer.getEyeHeight() always returns 0.12, so I have replicated the behaviour
// of the same method from EntityLivingBase and subtracted that instead.
return getPlayerEyesPos((EntityPlayer)entity) - entity.height*0.85f;
}else{
return entity.posY;
}
}
/**
* Verifies that the given string is a valid string representation of a UUID. More specifically, returns true if and
* only if the given string is not null and matches the regular expression:<p>
* <center><code>/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/<p></code></center>
* which is the regex equivlent of the standard string representation of a UUID as described in {@link UUID#toString()}.
* This method is intended to be used as a check to prevent an {@link IllegalArgumentException} from occurring when
* calling {@link UUID#fromString(String)}.
* @param string The string to be checked
* @return Whether the given string is a valid string representation of a UUID
*/
public static boolean verifyUUIDString(String string){
return string != null && string.matches("/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/");
}
/**
* Returns whether the given target can be attacked by the given attacker. It is up to the caller of this method
* to work out what this means; it doesn't necessarily mean the target is completely immune (for example, revenge
* targeting might reasonably bypass this). This method is intended for use where the damage is indirect and/or
* unavoidable; direct attacks should not check this method. Currently this means the following situations check
* this method:
* <p>
* - AI targeting for summoned creatures<br>
* - AI targeting for mind-controlled creatures<br>
* - Constructs with an area of effect<br>
* - Instantaneous spells with an area of effect around the caster (e.g. forest's curse, thunderstorm)<br>
* - Any lightning chaining effects<br>
* - Any projectiles which seek targets
* <p>
* Also note that the friendly fire option is dealt with
* in the event handler. This method acts as a sort of wrapper for all the ADS stuff in {@link ExtendedPlayer}; more
* details about the ally designation system can be found there.
*
* @param attacker The entity that cast the spell originally
* @param target The entity being attacked
*
* @return False under any of the following circumstances, true otherwise:
* <p>
* - The target is the attacker (this isn't as stupid as it sounds - anything with an AoE might cause this to be
* true, as can summoned creatures)
* <p>
* - The target and the attacker are both players and the target is an ally of the attacker (but the
* attacker need not be an ally of the target)
* <p>
* - The target is a creature that was summoned/controlled by the attacker or by an ally of the attacker.
*/
public static boolean isValidTarget(Entity attacker, Entity target){
// Don't need to check if either entity is null since instanceof does this anyway.
// Tests whether the target is the attacker
if(target == attacker) return false;
// Tests whether the target is a creature that was summoned by the attacker
if(target instanceof EntitySummonedCreature && ((EntitySummonedCreature)target).getCaster() == attacker){
return false;
}
// Tests whether the target is a creature that was mind controlled by the attacker
if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(Wizardry.mindControl)){
NBTTagCompound entityNBT = target.getEntityData();
if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){
if(attacker == WizardryUtilities.getEntityByUUID(target.worldObj, UUID.fromString(entityNBT.getString(MindControl.NBT_KEY)))){
return false;
}
}
}
// Ally section
if(attacker instanceof EntityPlayer && ExtendedPlayer.get((EntityPlayer)attacker) != null){
if(target instanceof EntityPlayer){
// Tests whether the target is an ally of the attacker
if(ExtendedPlayer.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)target)){
return false;
}
}else if(target instanceof EntitySummonedCreature){
// Tests whether the target is a creature that was summoned by an ally of the attacker
if(((EntitySummonedCreature)target).getCaster() instanceof EntityPlayer
&& ExtendedPlayer.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)((EntitySummonedCreature)target).getCaster())){
return false;
}
}else if(target instanceof EntityLiving && ((EntityLivingBase)target).isPotionActive(Wizardry.mindControl)){
// Tests whether the target is a creature that was mind controlled by an ally of the attacker
NBTTagCompound entityNBT = target.getEntityData();
if(entityNBT != null && entityNBT.hasKey(MindControl.NBT_KEY)){
Entity controller = WizardryUtilities.getEntityByUUID(target.worldObj, UUID.fromString(entityNBT.getString(MindControl.NBT_KEY)));
if(controller instanceof EntityPlayer && ExtendedPlayer.get((EntityPlayer)attacker).isPlayerAlly((EntityPlayer)controller)){
return false;
}
}
}
}
return true;
}
/** Helper method for testing if the second player is an ally of the first player. Makes the code neater. */
public static boolean isPlayerAlly(EntityPlayer allyOf, EntityPlayer possibleAlly) {
ExtendedPlayer properties = ExtendedPlayer.get(allyOf);
if(properties != null && properties.isPlayerAlly(possibleAlly)) return true;
return false;
}
/**
* See {@link WizardryUtilities#getStandardWeightedRandomSpellId(Random, boolean)}. isContinuous defaults to false.
*/
public static int getStandardWeightedRandomSpellId(Random random){
return getStandardWeightedRandomSpellId(random, false);
}
/**
* Helper method which gets a spell id according to the standard weighting. The tier is a weighted random value;
* the actual spell within that tier is completely random. Will not return the id of a spell which has been
* disabled in the config. This is for simple stuff like chests and drops; more complex generators like wizard
* trades don't use this method.
* <p>
* For reference, the standard weighting is as follows:
* Basic: 60%, Apprentice: 25%, Advanced: 10%, Master: 5%
*
* @param random An instance of the Random class
* @param nonContinuous Whether the spells must be non-continuous (used for scrolls)
* @return A random spell id number
*/
public static int getStandardWeightedRandomSpellId(Random random, boolean nonContinuous){
int randomiser = random.nextInt(20);
EnumTier tier;
if(randomiser < 12){
tier = EnumTier.BASIC;
}else if(randomiser < 17){
tier = EnumTier.APPRENTICE;
}else if(randomiser < 19){
tier = EnumTier.ADVANCED;
}else{
tier = EnumTier.MASTER;
}
List<Spell> spells = Spell.getSpells(new Spell.TierElementFilter(tier, null));
if(nonContinuous) spells.retainAll(Spell.getSpells(Spell.nonContinuousSpells));
// Ensures the tier chosen actually has spells in it, and if not uses BASIC instead. BASIC always has at least
// the NONE spell since this spell cannot be disabled.
if(spells.isEmpty()){
spells = Spell.getSpells(new Spell.TierElementFilter(EnumTier.BASIC, null));
if(nonContinuous) spells.retainAll(Spell.getSpells(Spell.nonContinuousSpells));
}
// Finds a random spell in the list and returns its id.
return spells.get(random.nextInt(spells.size())).id();
}
/**
* Helper method to return the appropriate armour item based on element and slot.
* Currently used to iterate through armour for registering charging recipes and for chest generation.
* @param slot 0 = head, 1 = body, 2 = legs, 3 = feet
*/
public static Item getArmour(EnumElement element, int slot){
Item armour = null;
if(element == null){
switch(slot){
case 0:
armour = Wizardry.wizardHat;
break;
case 1:
armour = Wizardry.wizardRobe;
break;
case 2:
armour = Wizardry.wizardLeggings;
break;
case 3:
armour = Wizardry.wizardBoots;
break;
default:
break;
}
}else{
switch(element){
case FIRE:
switch(slot){
case 0:
armour = Wizardry.wizardHatFire;
break;
case 1:
armour = Wizardry.wizardRobeFire;
break;
case 2:
armour = Wizardry.wizardLeggingsFire;
break;
case 3:
armour = Wizardry.wizardBootsFire;
break;
default:
break;
}
break;
case HEALING:
switch(slot){
case 0:
armour = Wizardry.wizardHatHealing;
break;
case 1:
armour = Wizardry.wizardRobeHealing;
break;
case 2:
armour = Wizardry.wizardLeggingsHealing;
break;
case 3:
armour = Wizardry.wizardBootsHealing;
break;
default:
break;
}
break;
case ICE:
switch(slot){
case 0:
armour = Wizardry.wizardHatIce;
break;
case 1:
armour = Wizardry.wizardRobeIce;
break;
case 2:
armour = Wizardry.wizardLeggingsIce;
break;
case 3:
armour = Wizardry.wizardBootsIce;
break;
default:
break;
}
break;
case LIGHTNING:
switch(slot){
case 0:
armour = Wizardry.wizardHatLightning;
break;
case 1:
armour = Wizardry.wizardRobeLightning;
break;
case 2:
armour = Wizardry.wizardLeggingsLightning;
break;
case 3:
armour = Wizardry.wizardBootsLightning;
break;
default:
break;
}
break;
case NECROMANCY:
switch(slot){
case 0:
armour = Wizardry.wizardHatNecromancy;
break;
case 1:
armour = Wizardry.wizardRobeNecromancy;
break;
case 2:
armour = Wizardry.wizardLeggingsNecromancy;
break;
case 3:
armour = Wizardry.wizardBootsNecromancy;
break;
default:
break;
}
break;
case SORCERY:
switch(slot){
case 0:
armour = Wizardry.wizardHatSorcery;
break;
case 1:
armour = Wizardry.wizardRobeSorcery;
break;
case 2:
armour = Wizardry.wizardLeggingsSorcery;
break;
case 3:
armour = Wizardry.wizardBootsSorcery;
break;
default:
break;
}
break;
case EARTH:
switch(slot){
case 0:
armour = Wizardry.wizardHatEarth;
break;
case 1:
armour = Wizardry.wizardRobeEarth;
break;
case 2:
armour = Wizardry.wizardLeggingsEarth;
break;
case 3:
armour = Wizardry.wizardBootsEarth;
break;
default:
break;
}
break;
default:
switch(slot){
case 0:
armour = Wizardry.wizardHat;
break;
case 1:
armour = Wizardry.wizardRobe;
break;
case 2:
armour = Wizardry.wizardLeggings;
break;
case 3:
armour = Wizardry.wizardBoots;
break;
default:
break;
}
break;
}
}
return armour;
}
/**
* Helper method to return the appropriate wand based on tier and element.
* Currently used in the packet handler for upgrading wands, for chest generation and to iterate through
* wands for charging recipes.
*/
public static Item getWand(EnumTier tier, EnumElement element){
Item wand = null;
if(element == null){
switch(tier){
case BASIC:
wand = Wizardry.magicWand;
break;
case APPRENTICE:
wand = Wizardry.apprenticeWand;
break;
case ADVANCED:
wand = Wizardry.advancedWand;
break;
case MASTER:
wand = Wizardry.masterWand;
break;
default:
break;
}
}else{
switch(element){
case FIRE:
switch(tier){
case BASIC:
wand = Wizardry.basicFireWand;
break;
case APPRENTICE:
wand = Wizardry.apprenticeFireWand;
break;
case ADVANCED:
wand = Wizardry.advancedFireWand;
break;
case MASTER:
wand = Wizardry.masterFireWand;
break;
default:
break;
}
break;
case HEALING:
switch(tier){
case BASIC:
wand = Wizardry.basicHealingWand;
break;
case APPRENTICE:
wand = Wizardry.apprenticeHealingWand;
break;
case ADVANCED:
wand = Wizardry.advancedHealingWand;
break;
case MASTER:
wand = Wizardry.masterHealingWand;
break;
default:
break;
}
break;
case ICE:
switch(tier){
case BASIC:
wand = Wizardry.basicIceWand;
break;
case APPRENTICE:
wand = Wizardry.apprenticeIceWand;
break;
case ADVANCED:
wand = Wizardry.advancedIceWand;
break;
case MASTER:
wand = Wizardry.masterIceWand;
break;
default:
break;
}
break;
case LIGHTNING:
switch(tier){
case BASIC:
wand = Wizardry.basicLightningWand;
break;
case APPRENTICE:
wand = Wizardry.apprenticeLightningWand;
break;
case ADVANCED:
wand = Wizardry.advancedLightningWand;
break;
case MASTER:
wand = Wizardry.masterLightningWand;
break;
default:
break;
}
break;
case NECROMANCY:
switch(tier){
case BASIC:
wand = Wizardry.basicNecromancyWand;
break;
case APPRENTICE:
wand = Wizardry.apprenticeNecromancyWand;
break;
case ADVANCED:
wand = Wizardry.advancedNecromancyWand;
break;
case MASTER:
wand = Wizardry.masterNecromancyWand;
break;
default:
break;
}
break;
case SORCERY:
switch(tier){
case BASIC:
wand = Wizardry.basicSorceryWand;
break;
case APPRENTICE:
wand = Wizardry.apprenticeSorceryWand;
break;
case ADVANCED:
wand = Wizardry.advancedSorceryWand;
break;
case MASTER:
wand = Wizardry.masterSorceryWand;
break;
default:
break;
}
break;
case EARTH:
switch(tier){
case BASIC:
wand = Wizardry.basicEarthWand;
break;
case APPRENTICE:
wand = Wizardry.apprenticeEarthWand;
break;
case ADVANCED:
wand = Wizardry.advancedEarthWand;
break;
case MASTER:
wand = Wizardry.masterEarthWand;
break;
default:
break;
}
break;
default:
switch(tier){
case BASIC:
wand = Wizardry.magicWand;
break;
case APPRENTICE:
wand = Wizardry.apprenticeWand;
break;
case ADVANCED:
wand = Wizardry.advancedWand;
break;
case MASTER:
wand = Wizardry.masterWand;
break;
default:
break;
}
break;
}
}
return wand;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,81 @@
package electroblob.wizardry.advancement;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import electroblob.wizardry.Wizardry;
import net.minecraft.advancements.ICriterionInstance;
import net.minecraft.advancements.ICriterionTrigger;
import net.minecraft.advancements.PlayerAdvancements;
import net.minecraft.advancements.critereon.AbstractCriterionInstance;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.ResourceLocation;
/**
* This class implements a generic custom advancement trigger that can be fired from any point in
* the code. This replaces the achievement system in instances where the JSON advancement descriptions
* cannot properly capture the advancement-worthy events. Where possible, advancement conditions
* should be triggered by JSON descriptions and vanilla advancement triggers.
*
* @author 12foo
* @since 4.1.0
*/
public class CustomAdvancementTrigger implements ICriterionTrigger<CustomAdvancementTrigger.Instance> {
private final ResourceLocation id;
private final SetMultimap<PlayerAdvancements, Listener<? extends ICriterionInstance>> listeners = HashMultimap.create();
/**
* This is a dummy criterion instance that does nothing on its own (but it is bound to this
* trigger, and via listeners to the player). We later fire this manually when we want the
* advancement to happen.
*/
public static class Instance extends AbstractCriterionInstance {
public Instance(ResourceLocation triggerId) {
super(triggerId);
}
}
public CustomAdvancementTrigger(String name) {
super();
id = new ResourceLocation(Wizardry.MODID, name);
}
@Override
public ResourceLocation getId() {
return id;
}
@Override
public void addListener(PlayerAdvancements playerAdvancementsIn, Listener<Instance> listener) {
listeners.put(playerAdvancementsIn, listener);
}
@Override
public void removeListener(PlayerAdvancements playerAdvancementsIn, Listener<Instance> listener) {
listeners.remove(playerAdvancementsIn, listener);
}
@Override
public void removeAllListeners(PlayerAdvancements playerAdvancementsIn) {
listeners.removeAll(playerAdvancementsIn);
}
@Override
public Instance deserializeInstance(JsonObject json, JsonDeserializationContext context) {
// Every time a trigger with this name is deserialized from the JSON, we just return a new
// dummy criterion instance.
return new CustomAdvancementTrigger.Instance(id);
}
public void triggerFor(EntityPlayer player) {
// Fire our dummy criterion manually on all advancements of the player, thereby granting
// the ones that match it.
if (player instanceof EntityPlayerMP) {
final PlayerAdvancements advances = ((EntityPlayerMP) player).getAdvancements();
listeners.get(advances).forEach((listener) -> listener.grantCriterion(advances));
}
}
}
@@ -0,0 +1,139 @@
package electroblob.wizardry.advancement;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import electroblob.wizardry.spell.Spell;
import net.minecraft.advancements.ICriterionTrigger;
import net.minecraft.advancements.PlayerAdvancements;
import net.minecraft.advancements.critereon.AbstractCriterionInstance;
import net.minecraft.advancements.critereon.ItemPredicate;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Advancement trigger which is triggered when a spell is cast. The majority of any
* ICriterionTrigger class is just boilerplate, and this is no exception. */
public class SpellCastTrigger implements ICriterionTrigger<SpellCastTrigger.Instance> {
private final ResourceLocation id;
private final Map<PlayerAdvancements, SpellCastTrigger.Listeners> listeners = Maps.newHashMap();
public SpellCastTrigger(ResourceLocation id){
this.id = id;
}
public ResourceLocation getId(){
return this.id;
}
public void addListener(PlayerAdvancements advancements, Listener<SpellCastTrigger.Instance> listener){
SpellCastTrigger.Listeners listeners = this.listeners.get(advancements);
if(listeners == null){
listeners = new SpellCastTrigger.Listeners(advancements);
this.listeners.put(advancements, listeners);
}
listeners.add(listener);
}
public void removeListener(PlayerAdvancements advancements, Listener<SpellCastTrigger.Instance> listener){
SpellCastTrigger.Listeners listeners = this.listeners.get(advancements);
if(listeners != null){
listeners.remove(listener);
if(listeners.isEmpty()){
this.listeners.remove(advancements);
}
}
}
public void removeAllListeners(PlayerAdvancements advancements){
this.listeners.remove(advancements);
}
public SpellCastTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){
return new SpellCastTrigger.Instance(this.id, SpellPredicate.deserialize(json.get("spell")),
ItemPredicate.deserialize(json.get("item")));
}
public void trigger(EntityPlayerMP player, Spell spell, ItemStack stack){
SpellCastTrigger.Listeners listeners = this.listeners.get(player.getAdvancements());
if(listeners != null){
listeners.trigger(spell, stack);
}
}
public static class Instance extends AbstractCriterionInstance {
private final SpellPredicate spell;
private final ItemPredicate item;
public Instance(ResourceLocation criterion, SpellPredicate spell, ItemPredicate item){
super(criterion);
this.spell = spell;
this.item = item;
}
public boolean test(Spell spell, ItemStack stack){
return this.spell.test(spell) && item.test(stack);
}
}
static class Listeners {
private final PlayerAdvancements playerAdvancements;
private final Set<Listener<SpellCastTrigger.Instance>> listeners = Sets.newHashSet();
public Listeners(PlayerAdvancements advancements){
this.playerAdvancements = advancements;
}
public boolean isEmpty(){
return this.listeners.isEmpty();
}
public void add(Listener<SpellCastTrigger.Instance> listener){
this.listeners.add(listener);
}
public void remove(Listener<SpellCastTrigger.Instance> listener){
this.listeners.remove(listener);
}
public void trigger(Spell spell, ItemStack stack){
List<Listener<SpellCastTrigger.Instance>> list = null;
for(Listener<SpellCastTrigger.Instance> listener : this.listeners){
if(listener.getCriterionInstance().test(spell, stack)){
if(list == null){
list = Lists.newArrayList();
}
list.add(listener);
}
}
if(list != null){
for(Listener<SpellCastTrigger.Instance> listener : list){
listener.grantCriterion(this.playerAdvancements);
}
}
}
}
}
@@ -0,0 +1,143 @@
package electroblob.wizardry.advancement;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import electroblob.wizardry.event.DiscoverSpellEvent;
import electroblob.wizardry.spell.Spell;
import net.minecraft.advancements.ICriterionTrigger;
import net.minecraft.advancements.PlayerAdvancements;
import net.minecraft.advancements.critereon.AbstractCriterionInstance;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.JsonUtils;
import net.minecraft.util.ResourceLocation;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Advancement trigger that is triggered when a spell is discovered. The majority of any
* ICriterionTrigger class is just boilerplate, and this is no exception. */
public class SpellDiscoveryTrigger implements ICriterionTrigger<SpellDiscoveryTrigger.Instance> {
private final ResourceLocation id;
private final Map<PlayerAdvancements, SpellDiscoveryTrigger.Listeners> listeners = Maps.newHashMap();
public SpellDiscoveryTrigger(ResourceLocation id){
this.id = id;
}
public ResourceLocation getId(){
return this.id;
}
public void addListener(PlayerAdvancements advancements, Listener<SpellDiscoveryTrigger.Instance> listener){
SpellDiscoveryTrigger.Listeners listeners = this.listeners.get(advancements);
if(listeners == null){
listeners = new SpellDiscoveryTrigger.Listeners(advancements);
this.listeners.put(advancements, listeners);
}
listeners.add(listener);
}
public void removeListener(PlayerAdvancements advancements, Listener<SpellDiscoveryTrigger.Instance> listener){
SpellDiscoveryTrigger.Listeners listeners = this.listeners.get(advancements);
if(listeners != null){
listeners.remove(listener);
if(listeners.isEmpty()){
this.listeners.remove(advancements);
}
}
}
public void removeAllListeners(PlayerAdvancements advancements){
this.listeners.remove(advancements);
}
public SpellDiscoveryTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){
String s = JsonUtils.getString(json, "source");
DiscoverSpellEvent.Source source = DiscoverSpellEvent.Source.byName(s);
if(source == null) throw new JsonSyntaxException("No such spell discovery source: " + s);
return new SpellDiscoveryTrigger.Instance(this.id, SpellPredicate.deserialize(json.get("spell")), source);
}
public void trigger(EntityPlayerMP player, Spell spell, DiscoverSpellEvent.Source source){
SpellDiscoveryTrigger.Listeners listeners = this.listeners.get(player.getAdvancements());
if(listeners != null){
listeners.trigger(spell, source);
}
}
public static class Instance extends AbstractCriterionInstance {
private final SpellPredicate spell;
private final DiscoverSpellEvent.Source source;
public Instance(ResourceLocation criterion, SpellPredicate spell, DiscoverSpellEvent.Source source){
super(criterion);
this.spell = spell;
this.source = source;
}
public boolean test(Spell spell, DiscoverSpellEvent.Source source){
return this.spell.test(spell) && source == this.source;
}
}
static class Listeners {
private final PlayerAdvancements playerAdvancements;
private final Set<Listener<SpellDiscoveryTrigger.Instance>> listeners = Sets.newHashSet();
public Listeners(PlayerAdvancements advancements){
this.playerAdvancements = advancements;
}
public boolean isEmpty(){
return this.listeners.isEmpty();
}
public void add(Listener<SpellDiscoveryTrigger.Instance> listener){
this.listeners.add(listener);
}
public void remove(Listener<SpellDiscoveryTrigger.Instance> listener){
this.listeners.remove(listener);
}
public void trigger(Spell spell, DiscoverSpellEvent.Source source){
List<Listener<SpellDiscoveryTrigger.Instance>> list = null;
for(Listener<SpellDiscoveryTrigger.Instance> listener : this.listeners){
if(listener.getCriterionInstance().test(spell, source)){
if(list == null){
list = Lists.newArrayList();
}
list.add(listener);
}
}
if(list != null){
for(Listener<SpellDiscoveryTrigger.Instance> listener : list){
listener.grantCriterion(this.playerAdvancements);
}
}
}
}
}
@@ -0,0 +1,117 @@
package electroblob.wizardry.advancement;
import com.google.common.collect.Streams;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.spell.Spell;
import net.minecraft.util.JsonUtils;
import javax.annotation.Nullable;
import java.util.Arrays;
/** Predicate used by advancement triggers to match spells. */
public class SpellPredicate {
public static final SpellPredicate ANY = new SpellPredicate();
private final Spell spell;
private final Tier[] tiers;
private final Element[] elements;
public SpellPredicate(){
this.spell = null;
this.tiers = Tier.values();
this.elements = Element.values();
}
public SpellPredicate(@Nullable Spell spell, Tier[] tiers, Element[] elements){
this.spell = spell;
this.tiers = tiers;
this.elements = elements;
}
public boolean test(Spell spell){
if(this.spell != null && spell != this.spell){
return false;
}else if(!Arrays.asList(this.tiers).contains(spell.getTier())){
return false;
}else if(!Arrays.asList(this.elements).contains(spell.getElement())){
return false;
}
return true;
}
public static SpellPredicate deserialize(@Nullable JsonElement element){
if(element != null && !element.isJsonNull()){
JsonObject jsonobject = JsonUtils.getJsonObject(element, "spell");
Spell spell = null;
if(jsonobject.has("spell")){
String s = JsonUtils.getString(jsonobject, "spell");
spell = Spell.get(s);
if(spell == null){
throw new JsonSyntaxException("Unknown spell id '" + s + "'");
}
}
Tier[] tiers = Tier.values();
if(jsonobject.has("tiers")){
try{
JsonArray array = JsonUtils.getJsonArray(jsonobject, "tiers");
tiers = Streams.stream(array)
.map(je -> Tier.fromName(JsonUtils.getString(je, "element of array tiers")))
.toArray(Tier[]::new);
}catch(IllegalArgumentException e){
throw new JsonSyntaxException("Incorrect spell predicate value", e);
}
}
Element[] elements = Element.values();
if(jsonobject.has("elements")){
try{
JsonArray array = JsonUtils.getJsonArray(jsonobject, "elements");
elements = Streams.stream(array)
.map(je -> Element.fromName(JsonUtils.getString(je, "element of array elements")))
.toArray(Element[]::new);
}catch(IllegalArgumentException e){
throw new JsonSyntaxException("Incorrect spell predicate value", e);
}
}
return new SpellPredicate(spell, tiers, elements);
}else{
return ANY;
}
}
public static SpellPredicate[] deserializeArray(@Nullable JsonElement element){
if(element != null && !element.isJsonNull()){
JsonArray jsonarray = JsonUtils.getJsonArray(element, "spells");
SpellPredicate[] predicates = new SpellPredicate[jsonarray.size()];
for(int i = 0; i < predicates.length; ++i){
predicates[i] = deserialize(jsonarray.get(i));
}
return predicates;
}else{
return new SpellPredicate[0];
}
}
}
@@ -0,0 +1,136 @@
package electroblob.wizardry.advancement;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import electroblob.wizardry.worldgen.WorldGenWizardryStructure;
import net.minecraft.advancements.ICriterionTrigger;
import net.minecraft.advancements.PlayerAdvancements;
import net.minecraft.advancements.critereon.AbstractCriterionInstance;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.JsonUtils;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.WorldServer;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Copied from PositionTrigger and modified to work with wizardry's structures. The majority of any
* ICriterionTrigger class is just boilerplate, and this is no exception. */
public class StructureTrigger implements ICriterionTrigger<StructureTrigger.Instance> {
private final ResourceLocation id;
private final Map<PlayerAdvancements, StructureTrigger.Listeners> listeners = Maps.newHashMap();
public StructureTrigger(ResourceLocation id){
this.id = id;
}
public ResourceLocation getId(){
return this.id;
}
public void addListener(PlayerAdvancements advancements, Listener<StructureTrigger.Instance> listener){
StructureTrigger.Listeners listeners = this.listeners.get(advancements);
if(listeners == null){
listeners = new StructureTrigger.Listeners(advancements);
this.listeners.put(advancements, listeners);
}
listeners.add(listener);
}
public void removeListener(PlayerAdvancements advancements, Listener<StructureTrigger.Instance> listener){
StructureTrigger.Listeners listeners = this.listeners.get(advancements);
if(listeners != null){
listeners.remove(listener);
if(listeners.isEmpty()){
this.listeners.remove(advancements);
}
}
}
public void removeAllListeners(PlayerAdvancements advancements){
this.listeners.remove(advancements);
}
public StructureTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){
return new StructureTrigger.Instance(this.id, JsonUtils.getString(json, "structure_type"));
}
public void trigger(EntityPlayerMP player){
StructureTrigger.Listeners listeners = this.listeners.get(player.getAdvancements());
if(listeners != null){
listeners.trigger(player.getServerWorld(), player.posX, player.posY, player.posZ);
}
}
public static class Instance extends AbstractCriterionInstance {
private final WorldGenWizardryStructure structureType;
public Instance(ResourceLocation criterionIn, String name){
super(criterionIn);
this.structureType = WorldGenWizardryStructure.byName(name);
}
public boolean test(WorldServer world, double x, double y, double z){
return structureType.isInsideStructure(world, x, y, z);
}
}
static class Listeners {
private final PlayerAdvancements playerAdvancements;
private final Set<Listener<StructureTrigger.Instance>> listeners = Sets.newHashSet();
public Listeners(PlayerAdvancements advancements){
this.playerAdvancements = advancements;
}
public boolean isEmpty(){
return this.listeners.isEmpty();
}
public void add(Listener<StructureTrigger.Instance> listener){
this.listeners.add(listener);
}
public void remove(Listener<StructureTrigger.Instance> listener){
this.listeners.remove(listener);
}
public void trigger(WorldServer world, double x, double y, double z){
List<Listener<StructureTrigger.Instance>> list = null;
for(Listener<StructureTrigger.Instance> listener : this.listeners){
if(listener.getCriterionInstance().test(world, x, y, z)){
if(list == null){
list = Lists.newArrayList();
}
list.add(listener);
}
}
if(list != null){
for(Listener<StructureTrigger.Instance> listener : list){
listener.grantCriterion(this.playerAdvancements);
}
}
}
}
}
@@ -0,0 +1,135 @@
package electroblob.wizardry.advancement;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import net.minecraft.advancements.ICriterionTrigger;
import net.minecraft.advancements.PlayerAdvancements;
import net.minecraft.advancements.critereon.AbstractCriterionInstance;
import net.minecraft.advancements.critereon.ItemPredicate;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Advancement trigger for things done in the arcane workbench or imbuement altar. The majority of any
* ICriterionTrigger class is just boilerplate, and this is no exception. */
public class WizardryContainerTrigger implements ICriterionTrigger<WizardryContainerTrigger.Instance> {
private final ResourceLocation id;
private final Map<PlayerAdvancements, WizardryContainerTrigger.Listeners> listeners = Maps.newHashMap();
public WizardryContainerTrigger(ResourceLocation id){
this.id = id;
}
public ResourceLocation getId(){
return this.id;
}
public void addListener(PlayerAdvancements advancements, Listener<WizardryContainerTrigger.Instance> listener){
WizardryContainerTrigger.Listeners listeners = this.listeners.get(advancements);
if(listeners == null){
listeners = new WizardryContainerTrigger.Listeners(advancements);
this.listeners.put(advancements, listeners);
}
listeners.add(listener);
}
public void removeListener(PlayerAdvancements advancements, Listener<WizardryContainerTrigger.Instance> listener){
WizardryContainerTrigger.Listeners listeners = this.listeners.get(advancements);
if(listeners != null){
listeners.remove(listener);
if(listeners.isEmpty()){
this.listeners.remove(advancements);
}
}
}
public void removeAllListeners(PlayerAdvancements advancements){
this.listeners.remove(advancements);
}
public WizardryContainerTrigger.Instance deserializeInstance(JsonObject json, JsonDeserializationContext context){
return new WizardryContainerTrigger.Instance(this.id, ItemPredicate.deserialize(json.get("item")));
}
public void trigger(EntityPlayerMP player, ItemStack stack){
WizardryContainerTrigger.Listeners listeners = this.listeners.get(player.getAdvancements());
if(listeners != null){
listeners.trigger(stack);
}
}
public static class Instance extends AbstractCriterionInstance {
private final ItemPredicate item;
public Instance(ResourceLocation criterionIn, ItemPredicate item){
super(criterionIn);
this.item = item;
}
public boolean test(ItemStack stack){
return this.item.test(stack);
}
}
static class Listeners {
private final PlayerAdvancements playerAdvancements;
private final Set<Listener<WizardryContainerTrigger.Instance>> listeners = Sets.newHashSet();
public Listeners(PlayerAdvancements advancements){
this.playerAdvancements = advancements;
}
public boolean isEmpty(){
return this.listeners.isEmpty();
}
public void add(Listener<WizardryContainerTrigger.Instance> listener){
this.listeners.add(listener);
}
public void remove(Listener<WizardryContainerTrigger.Instance> listener){
this.listeners.remove(listener);
}
public void trigger(ItemStack stack){
List<Listener<WizardryContainerTrigger.Instance>> list = null;
for(Listener<WizardryContainerTrigger.Instance> listener : this.listeners){
if(listener.getCriterionInstance().test(stack)){
if(list == null){
list = Lists.newArrayList();
}
list.add(listener);
}
}
if(list != null){
for(Listener<WizardryContainerTrigger.Instance> listener : list){
listener.grantCriterion(this.playerAdvancements);
}
}
}
}
}
@@ -0,0 +1,96 @@
package electroblob.wizardry.api;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.constants.SpellType;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.util.SpellProperties;
import net.minecraft.util.text.Style;
import net.minecraftforge.common.util.EnumHelper;
/**
* This class contains methods similar to those in {@link EnumHelper} specific to wizardry's enum types.
*
* @author Electroblob
* @since Wizardry 4.2
*/
public final class WizardryEnumHelper {
// Make sure these are updated if the relevant constructors are updated!
// Can't we do some kind of reflection to access them and generate these arrays?
private static final Class[] TIER_ARGUMENTS = new Class[]{Integer.class, Integer.class, Integer.class, Style.class, String.class};
private static final Class[] ELEMENT_ARGUMENTS = new Class[]{Style.class, String.class, String.class};
private static final Class[] SPELL_TYPE_ARGUMENTS = new Class[]{String.class};
private static final Class[] SPELL_CONTEXT_ARGUMENTS = new Class[]{String.class};
/**
* Wrapper for the generic method {@link EnumHelper#addEnum(Class, String, Class[], Object...)} which is
* specifically for adding new tiers. Use this method in preference to the generic one in case the constructor
* parameters change for {@code Tier}.
* <p></p>
* As of version 4.2, wizardry now has partial support for externally-added tiers; you'll need to do some of the
* legwork yourself though.
*
* @param codeName The name of the enum constant in the code. This will be returned if you call toString() on the
* resulting enum constant; other than that it doesn't really make much difference.
* @param maxCharge The maximum charge for wands of this tier.
* @param upgradeLimit The maximum total number of special upgrades that can be applied to wands of this tier.
* @param weight The weight of this tier in the standard weighting.
* @param colour The colour of text associated with this tier, as a style object.
* @param name The unlocalised name of this tier, as used in translation keys.
* @return The resulting {@code Tier} enum constant.
*/
public static Tier addTier(String codeName, int maxCharge, int upgradeLimit, int weight, Style colour, String name){
return EnumHelper.addEnum(Tier.class, codeName, TIER_ARGUMENTS, maxCharge, upgradeLimit, weight, colour, name);
}
/**
* Wrapper for the generic method {@link EnumHelper#addEnum(Class, String, Class[], Object...)} which is
* specifically for adding new elements. Use this method in preference to the generic one in case the constructor
* parameters change for {@code Element}.
* <p></p>
* As of version 4.2, wizardry now has full support for externally-added elements.
*
* @param codeName The name of the enum constant in the code. This will be returned if you call toString() on the
* resulting enum constant; other than that it doesn't really make much difference.
* @param colour The colour of text associated with this element, as a style object.
* @param name The unlocalised name of this element, as used in translation keys.
* @param modID The mod ID of the mod that added this element, for icon rendering purposes.
* @return The resulting {@code Element} enum constant.
*/
// This is the only one that needs the mod ID argument because elements are the only ones that have icons
// For some reason Minecraft doesn't seem to care about the resource domain for lang files, it just pools them
public static Element addElement(String codeName, Style colour, String name, String modID){
return EnumHelper.addEnum(Element.class, codeName, ELEMENT_ARGUMENTS, colour, name, modID);
}
/**
* Wrapper for the generic method {@link EnumHelper#addEnum(Class, String, Class[], Object...)} which is
* specifically for adding new spell types. Use this method in preference to the generic one in case the constructor
* parameters change for {@code SpellType}.
* <p></p>
* As of version 4.2, wizardry now has full support for externally-added spell types.
*
* @param codeName The name of the enum constant in the code. This will be returned if you call toString() on the
* resulting enum constant; other than that it doesn't really make much difference.
* @param name The unlocalised name of this spell type, as used in translation keys.
* @return The resulting {@code SpellType} enum constant.
*/
public static SpellType addSpellType(String codeName, String name){
return EnumHelper.addEnum(SpellType.class, codeName, SPELL_TYPE_ARGUMENTS, name);
}
/**
* Wrapper for the generic method {@link EnumHelper#addEnum(Class, String, Class[], Object...)} which is
* specifically for adding new spell contexts (for use in spell property JSON files). Use this method in preference
* to the generic one in case the constructor parameters change for {@code Context}.
*
* @param codeName The name of the enum constant in the code. This will be returned if you call toString() on the
* resulting enum constant; other than that it doesn't really make much difference.
* @param name The identifier for this spell context, as used in the JSON file.
* @return The resulting {@code Context} enum constant.
*/
public static SpellProperties.Context addSpellContext(String codeName, String name){
return EnumHelper.addEnum(SpellProperties.Context.class, codeName, SPELL_CONTEXT_ARGUMENTS, name);
}
}
@@ -1,126 +1,91 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler;
import electroblob.wizardry.client.GuiArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.IIcon;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockArcaneWorkbench extends BlockContainer{
public IIcon[] icons = new IIcon[6];
public class BlockArcaneWorkbench extends BlockContainer {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.75D, 1.0D);
public BlockArcaneWorkbench(){
super(Material.rock);
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.75F, 1.0F);
this.setLightLevel(0.8f);
this.setCreativeTab(CreativeTabs.tabDecorations);
this.setBlockTextureName("wizardry:arcane_workbench");
super(Material.ROCK);
this.setLightLevel(0.8f);
}
@Override
public void registerBlockIcons(IIconRegister par1IconRegister) {
this.icons[0] = par1IconRegister.registerIcon(this.textureName + "_bottom");
this.icons[1] = par1IconRegister.registerIcon(this.textureName + "_top");
this.icons[2] = par1IconRegister.registerIcon(this.textureName + "_side");
this.icons[3] = par1IconRegister.registerIcon(this.textureName + "_side");
this.icons[4] = par1IconRegister.registerIcon(this.textureName + "_side");
this.icons[5] = par1IconRegister.registerIcon(this.textureName + "_side");
}
@Override
public IIcon getIcon(int side, int meta) {
return this.icons[side];
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
public TileEntity createNewTileEntity(World world, int metadata){
return new TileEntityArcaneWorkbench();
}
@Override
public boolean renderAsNormalBlock()
{
return false;
}
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
return false;
}
@Override
public boolean isOpaqueCube()
{
return false;
}
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.MODEL;
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int metadata, float what, float these, float are) {
TileEntity tileEntity = world.getTileEntity(x, y, z);
if (tileEntity == null || player.isSneaking()) {
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Override
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
return face == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, EnumHand hand,
EnumFacing side, float hitX, float hitY, float hitZ){
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity == null || player.isSneaking()){
return false;
}
player.openGui(Wizardry.instance, WizardryGuiHandler.ARCANE_WORKBENCH, world, x, y, z);
player.openGui(Wizardry.instance, WizardryGuiHandler.ARCANE_WORKBENCH, world, pos.getX(), pos.getY(), pos.getZ());
return true;
}
@Override
public void breakBlock(World par1World, int par2, int par3, int par4, Block block, int par6)
{
Random random = new Random();
TileEntityArcaneWorkbench tileentityarcaneworkbench = (TileEntityArcaneWorkbench)par1World.getTileEntity(par2, par3, par4);
public void breakBlock(World world, BlockPos pos, IBlockState block){
TileEntity tileentity = world.getTileEntity(pos);
if (tileentityarcaneworkbench != null)
{
for (int j1 = 0; j1 < tileentityarcaneworkbench.getSizeInventory(); ++j1)
{
ItemStack itemstack = tileentityarcaneworkbench.getStackInSlot(j1);
if (itemstack != null)
{
float f = random.nextFloat() * 0.8F + 0.1F;
float f1 = random.nextFloat() * 0.8F + 0.1F;
EntityItem entityitem;
for (float f2 = random.nextFloat() * 0.8F + 0.1F; itemstack.stackSize > 0; par1World.spawnEntityInWorld(entityitem))
{
int k1 = random.nextInt(21) + 10;
if (k1 > itemstack.stackSize)
{
k1 = itemstack.stackSize;
}
itemstack.stackSize -= k1;
entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.getItem(), k1, itemstack.getItemDamage()));
float f3 = 0.05F;
entityitem.motionX = (double)((float)random.nextGaussian() * f3);
entityitem.motionY = (double)((float)random.nextGaussian() * f3 + 0.2F);
entityitem.motionZ = (double)((float)random.nextGaussian() * f3);
if (itemstack.hasTagCompound())
{
entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
}
}
}
}
//par1World.func_96440_m(par2, par3, par4, block);
if(tileentity instanceof TileEntityArcaneWorkbench){
InventoryHelper.dropInventoryItems(world, pos, (TileEntityArcaneWorkbench)tileentity);
}
super.breakBlock(par1World, par2, par3, par4, block, par6);
}
super.breakBlock(world, pos, block);
}
}
@@ -0,0 +1,367 @@
package electroblob.wizardry.block;
import com.google.common.collect.ImmutableList;
import electroblob.wizardry.Settings;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryTabs;
import electroblob.wizardry.tileentity.TileEntityBookshelf;
import net.minecraft.block.BlockHorizontal;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.Item;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.World;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.Properties;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
@Mod.EventBusSubscriber
public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvider {
/** When a bookshelf block (of any kind specified in the config) is added or removed, players within this range will
* be notified of the change. */
public static final double PLAYER_NOTIFY_RANGE = 32;
public static final int SLOT_COUNT = 12;
public static final UnlistedPropertyInt[] BOOKS = new UnlistedPropertyInt[SLOT_COUNT];
private static final Map<Supplier<Item>, ResourceLocation> BOOK_TEXTURE_MAP = new HashMap<>();
private static ImmutableList<Item> bookItems;
private static ImmutableList<ResourceLocation> bookTextures;
public BlockBookshelf(){
super(Material.WOOD);
this.setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH));
this.setCreativeTab(WizardryTabs.WIZARDRY);
this.setHardness(2.0F);
this.setResistance(5.0F);
this.setSoundType(SoundType.WOOD);
}
@Override
protected BlockStateContainer createBlockState(){
// IProperty<?>[] properties = { FACING };
// return new BlockStateContainer(this, ArrayUtils.addAll(properties, BOOKS));
return new BlockStateContainer.Builder(this).add(FACING).add(BOOKS).build();
}
@Override
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
return state.getValue(FACING).getAxis() == face.getAxis() ? BlockFaceShape.UNDEFINED : BlockFaceShape.SOLID;
}
@Override
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer){
return this.getDefaultState().withProperty(FACING, placer.getHorizontalFacing().getOpposite());
}
// Why on earth are these two not in BlockHorizontal?
@Override
public IBlockState withRotation(IBlockState state, Rotation rotation){
return state.withProperty(FACING, rotation.rotate(state.getValue(FACING)));
}
@Override
public IBlockState withMirror(IBlockState state, Mirror mirror){
return state.withRotation(mirror.toRotation(state.getValue(FACING)));
}
@Override
public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state){
super.onBlockAdded(worldIn, pos, state);
}
@Override
public void breakBlock(World world, BlockPos pos, IBlockState block){
TileEntity tileentity = world.getTileEntity(pos);
if(tileentity instanceof TileEntityBookshelf){
InventoryHelper.dropInventoryItems(world, pos, (TileEntityBookshelf)tileentity);
}
super.breakBlock(world, pos, block); // For blocks that don't extend BlockContainer, this removes the TE
}
@Override
public IBlockState getStateFromMeta(int meta){
EnumFacing enumfacing = EnumFacing.byIndex(meta);
if(enumfacing.getAxis() == EnumFacing.Axis.Y) enumfacing = EnumFacing.NORTH;
return this.getDefaultState().withProperty(FACING, enumfacing);
}
@Override
public int getMetaFromState(IBlockState state){
return state.getValue(FACING).getIndex();
}
@Override
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos){
IExtendedBlockState s = (IExtendedBlockState)super.getExtendedState(state, world, pos);
if(world.getTileEntity(pos) instanceof TileEntityBookshelf){
TileEntityBookshelf tileentity = ((TileEntityBookshelf)world.getTileEntity(pos));
for(int i = 0; i < tileentity.getSizeInventory(); i++){
if(tileentity.getStackInSlot(i).isEmpty()){
s = s.withProperty(BOOKS[i], bookItems.size());
}else{
Item item = tileentity.getStackInSlot(i).getItem();
// Default to the standard spell book texture, which will always be the first item in the list
s = s.withProperty(BOOKS[i], bookItems.contains(item) ? bookItems.indexOf(item) : 0);
}
}
}
return s;
}
@Nullable
@Override
public TileEntity createNewTileEntity(World world, int meta){
return new TileEntityBookshelf();
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, EnumHand hand,
EnumFacing side, float hitX, float hitY, float hitZ){
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity == null || player.isSneaking()){
return false;
}
player.openGui(Wizardry.instance, WizardryGuiHandler.BOOKSHELF, world, pos.getX(), pos.getY(), pos.getZ());
return true;
}
@Override
public boolean hasComparatorInputOverride(IBlockState state){
return true;
}
@Override
public int getComparatorInputOverride(IBlockState state, World world, BlockPos pos){
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity instanceof TileEntityBookshelf){
int slotsOccupied = 0;
for(int i = 0; i < ((TileEntityBookshelf)tileEntity).getSizeInventory(); i++){
if(!((TileEntityBookshelf)tileEntity).getStackInSlot(i).isEmpty()) slotsOccupied++;
}
return slotsOccupied;
}
return super.getComparatorInputOverride(state, world, pos);
}
@Override
public boolean eventReceived(IBlockState state, World world, BlockPos pos, int id, int param){
super.eventReceived(state, world, pos, id, param);
TileEntity tileentity = world.getTileEntity(pos);
return tileentity != null && tileentity.receiveClientEvent(id, param);
}
/** Returns the list of book textures, in ID order. */
public static ImmutableList<ResourceLocation> getBookTextures(){
// ModelBookshelf calls this before init() so we need to return the map values as a fallback
return bookTextures == null ? ImmutableList.copyOf(BOOK_TEXTURE_MAP.values()) : bookTextures;
}
/** Returns the list of registered book items, in ID order. */
public static ImmutableList<Item> getBookItems(){
return bookItems;
}
/** Called during block registration to initialise the block properties for each book. */
public static void initBookProperties(){
for(int i=0; i<SLOT_COUNT; i++){
BOOKS[i] = new UnlistedPropertyInt("book" + i);
}
}
// Based on BlockFluid's UnlistedPropertyBool; this is only needed because of Java's weird restrictions on generics
private static final class UnlistedPropertyInt extends Properties.PropertyAdapter<Integer> {
public UnlistedPropertyInt(String name){
// Max is inclusive here, but we're using the largest value for no book so there's an extra one (can't use -1)
super(PropertyInteger.create(name, 0, BOOK_TEXTURE_MAP.size()));
}
}
/** Called from {@link Wizardry#init(FMLInitializationEvent)} to retrieve the actual book items and compile them
* and their textures into immutable lists. */
public static void compileBookModelTextures(){
ImmutableList.Builder<Item> itemListBuider = ImmutableList.builder();
ImmutableList.Builder<ResourceLocation> textureListBuilder = ImmutableList.builder();
for(Map.Entry<Supplier<Item>, ResourceLocation> entry : BOOK_TEXTURE_MAP.entrySet()){
itemListBuider.add(entry.getKey().get());
textureListBuilder.add(entry.getValue());
}
bookItems = itemListBuider.build();
bookTextures = textureListBuilder.build();
}
/** Called from {@link Wizardry#preInit(FMLPreInitializationEvent)} to register the default set of book textures. */
public static void registerStandardBookModelTextures(){
// Vanilla Minecraft books
// Regular brown books are the default so they're registered first
registerBookModelTexture(() -> Items.BOOK, new ResourceLocation(Wizardry.MODID, "blocks/books_brown"));
registerBookModelTexture(() -> Items.WRITABLE_BOOK, new ResourceLocation(Wizardry.MODID, "blocks/books_brown"));
registerBookModelTexture(() -> Items.WRITTEN_BOOK, new ResourceLocation(Wizardry.MODID, "blocks/books_brown"));
registerBookModelTexture(() -> Items.ENCHANTED_BOOK, new ResourceLocation(Wizardry.MODID, "blocks/books_enchanted"));
// Wizardry books
registerBookModelTexture(() -> WizardryItems.spell_book, new ResourceLocation(Wizardry.MODID, "blocks/books_red"));
registerBookModelTexture(() -> WizardryItems.wizard_handbook, new ResourceLocation(Wizardry.MODID, "blocks/books_blue"));
registerBookModelTexture(() -> WizardryItems.arcane_tome, new ResourceLocation(Wizardry.MODID, "blocks/books_purple"));
registerBookModelTexture(() -> WizardryItems.ruined_spell_book, new ResourceLocation(Wizardry.MODID, "blocks/books_brown"));
registerBookModelTexture(() -> WizardryItems.scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_blue"));
registerBookModelTexture(() -> WizardryItems.blank_scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_blue"));
registerBookModelTexture(() -> WizardryItems.identification_scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_purple"));
// Can't use the map in WandHelper because this is called from preInit (addons will have to add theirs manually)
registerBookModelTexture(() -> WizardryItems.storage_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
registerBookModelTexture(() -> WizardryItems.siphon_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
registerBookModelTexture(() -> WizardryItems.condenser_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
registerBookModelTexture(() -> WizardryItems.range_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
registerBookModelTexture(() -> WizardryItems.duration_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
registerBookModelTexture(() -> WizardryItems.cooldown_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
registerBookModelTexture(() -> WizardryItems.blast_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
registerBookModelTexture(() -> WizardryItems.attunement_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
registerBookModelTexture(() -> WizardryItems.melee_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
}
/**
* Registers a book texture to be used for the book model when the given item is placed in a bookshelf. This method
* <b>must</b> be called from {@code preInit} as the registered item count is required during block registration.
* This also necessitates the use of a supplier to fetch the item, since the items will not yet be registered.
* @param itemFactory A {@link Supplier} that returns the book item to link the texture to. This item need not
* be an instance of {@link electroblob.wizardry.item.ItemSpellBook ItemSpellBook}. Duplicate
* items will result in an {@link IllegalArgumentException} being thrown later.
* @param texture The texture to apply to the book model.
*/
public static void registerBookModelTexture(Supplier<Item> itemFactory, ResourceLocation texture){
BOOK_TEXTURE_MAP.put(itemFactory, texture);
}
/**
* Returns a list of nearby bookshelves' inventories, where 'bookshelves' are any tile entities with inventories
* whose blocks are specified in the config file under the {@code bookshelfBlocks} option.
* @param world The world to search in
* @param centre The position to search around
* @param exclude Any tile entities that should be excluded from the returned list
* @return A list of nearby {@link IInventory} objects that count as valid bookshelves
*/
public static List<IInventory> findNearbyBookshelves(World world, BlockPos centre, TileEntity... exclude){
List<IInventory> bookshelves = new ArrayList<>();
int searchRadius = Wizardry.settings.bookshelfSearchRadius;
for(int x = -searchRadius; x <= searchRadius; x++){
for(int y = -searchRadius; y <= searchRadius; y++){
for(int z = -searchRadius; z <= searchRadius; z++){
BlockPos pos = centre.add(x, y, z);
if(Settings.containsMetaBlock(Wizardry.settings.bookshelfBlocks, world.getBlockState(pos))){
TileEntity te = world.getTileEntity(pos);
if(te instanceof IInventory && !ArrayUtils.contains(exclude, te)) bookshelves.add((IInventory)te);
}
}
}
}
return bookshelves;
}
@SubscribeEvent
public static void onWorldLoadEvent(WorldEvent.Load event){
event.getWorld().addEventListener(Listener.instance);
}
@SubscribeEvent
public static void onWorldUnloadEvent(WorldEvent.Unload event){
event.getWorld().removeEventListener(Listener.instance);
}
public static class Listener implements IWorldEventListener {
public static final Listener instance = new Listener();
private Listener(){}
@Override
public void notifyBlockUpdate(World world, BlockPos pos, IBlockState oldState, IBlockState newState, int flags){
if(oldState == newState) return; // Probably won't happen but just in case
if(Settings.containsMetaBlock(Wizardry.settings.bookshelfBlocks, oldState) // Bookshelf removed
|| Settings.containsMetaBlock(Wizardry.settings.bookshelfBlocks, newState)){ // Bookshelf placed
// It is also possible (with commands) for a bookshelf to be replaced with another bookshelf, in which
// case this should still just be called once
Wizardry.proxy.notifyBookshelfChange(world, pos);
}
}
// Dummy implementations
@Override public void notifyLightSet(BlockPos pos){}
@Override public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2){}
@Override public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch){}
@Override public void playRecord(SoundEvent soundIn, BlockPos pos){}
@Override public void spawnParticle(int particleID, boolean ignoreRange, double xCoord, double yCoord, double zCoord, double xSpeed, double ySpeed, double zSpeed, int... parameters){}
@Override public void spawnParticle(int id, boolean ignoreRange, boolean minimiseParticleLevel, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed, int... parameters){}
@Override public void onEntityAdded(Entity entityIn){}
@Override public void onEntityRemoved(Entity entityIn){}
@Override public void broadcastSound(int soundID, BlockPos pos, int data){}
@Override public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data){}
@Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress){}
}
}
@@ -1,16 +1,76 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.registry.WizardryTabs;
import net.minecraft.block.Block;
import net.minecraft.block.material.MapColor;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import java.util.EnumMap;
public class BlockCrystal extends Block {
public BlockCrystal(Material material) {
super(material);
setHarvestLevel("pickaxe", 2);
public static final PropertyEnum<Element> ELEMENT = PropertyEnum.create("element", Element.class);
private static final EnumMap<Element, MapColor> map_colours = new EnumMap<>(Element.class);
static {
map_colours.put(Element.MAGIC, MapColor.PINK);
map_colours.put(Element.FIRE, MapColor.ORANGE_STAINED_HARDENED_CLAY);
map_colours.put(Element.ICE, MapColor.LIGHT_BLUE);
map_colours.put(Element.LIGHTNING, MapColor.CYAN);
map_colours.put(Element.NECROMANCY, MapColor.PURPLE);
map_colours.put(Element.EARTH, MapColor.GREEN);
map_colours.put(Element.SORCERY, MapColor.LIME);
map_colours.put(Element.HEALING, MapColor.YELLOW);
}
public BlockCrystal(Material material){
super(material);
this.setDefaultState(this.blockState.getBaseState().withProperty(ELEMENT, Element.MAGIC));
this.setCreativeTab(WizardryTabs.WIZARDRY);
this.setHarvestLevel("pickaxe", 2);
}
@Override
public int damageDropped(IBlockState state){
return (state.getValue(ELEMENT)).ordinal();
}
@Override
public MapColor getMapColor(IBlockState state, IBlockAccess world, BlockPos pos){
return map_colours.get(state.getProperties().get(ELEMENT));
}
@Override
public void getSubBlocks(CreativeTabs tab, NonNullList<ItemStack> items){
if(this.getCreativeTab() == tab){
for(Element element : Element.values()){
items.add(new ItemStack(this, 1, element.ordinal()));
}
}
}
@Override
public IBlockState getStateFromMeta(int metadata){
return this.getDefaultState().withProperty(ELEMENT, Element.values()[metadata]);
}
@Override
public int getMetaFromState(IBlockState state){
return (state.getValue(ELEMENT)).ordinal();
}
@Override
protected BlockStateContainer createBlockState(){
return new BlockStateContainer(this, ELEMENT);
}
}
@@ -1,143 +1,73 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.EnumParticleType;
import electroblob.wizardry.Wizardry;
import net.minecraft.block.Block;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.block.BlockBush;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.EnumPlantType;
import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.event.entity.player.BonemealEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
public class BlockCrystalFlower extends Block implements IPlantable {
import java.util.Random;
public BlockCrystalFlower(Material par2Material) {
// Extending BlockBush allows me to remove nearly everything from this class.
@Mod.EventBusSubscriber
public class BlockCrystalFlower extends BlockBush {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.5F - 0.2f, 0.0F, 0.5F - 0.2f, 0.5F + 0.2f,
0.2f * 3.0F, 0.5F + 0.2f);
public BlockCrystalFlower(Material par2Material){
super(par2Material);
this.setLightLevel(0.5f);
this.setBlockBounds(0.5F - 0.2f, 0.0F, 0.5F - 0.2f, 0.5F + 0.2f, 0.2f * 3.0F, 0.5F + 0.2f);
this.setTickRandomly(true);
this.setTickRandomly(true);
this.setSoundType(SoundType.PLANT);
}
@Override
public void randomDisplayTick(World world, int x, int y, int z, Random random){
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
if(world.isRemote && random.nextBoolean()){
Wizardry.proxy.spawnParticle(EnumParticleType.SPARKLE, world, x+random.nextDouble(), y+random.nextDouble()/2+0.5, z+random.nextDouble(), 0d, 0.01, 0d, 20 + random.nextInt(10), 0.5f + (random.nextFloat()/2), 0.5f + (random.nextFloat()/2), 0.5f + (random.nextFloat()/2));
ParticleBuilder.create(Type.SPARKLE)
.pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble() / 2 + 0.5, pos.getZ() + random.nextDouble()).vel(0, 0.01, 0)
.time(20 + random.nextInt(10)).clr(0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2),
0.5f + (random.nextFloat() / 2)).spawn(world);
}
}
/**
* Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
*/
@Override
public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
{
return super.canPlaceBlockAt(par1World, par2, par3, par4) && canBlockStay(par1World, par2, par3, par4);
}
/**
* Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
* cleared to be reused)
*/
@Override
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
{
return null;
}
/**
* Gets passed in the blockID of the block below and supposed to return true if its allowed to grow on the type of
* blockID passed in. Args: blockID
*/
protected boolean canThisPlantGrowOnThisBlockID(Block par1)
{
return par1 == Blocks.grass || par1 == Blocks.dirt || par1 == Blocks.farmland;
}
/**
* Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
* their own) Args: x, y, z, neighbor blockID
*/
@Override
public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, Block par5)
{
super.onNeighborBlockChange(par1World, par2, par3, par4, par5);
this.checkFlowerChange(par1World, par2, par3, par4);
}
/**
* Ticks the block if it's been scheduled
*/
@Override
public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
{
this.checkFlowerChange(par1World, par2, par3, par4);
}
protected final void checkFlowerChange(World par1World, int par2, int par3, int par4)
{
if (!this.canBlockStay(par1World, par2, par3, par4))
{
this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
par1World.setBlock(par2, par3, par4, Blocks.air, 0, 2);
}
}
/**
* Can this block stay at this position. Similar to canPlaceBlockAt except gets checked often with plants.
*/
@Override
public boolean canBlockStay(World par1World, int par2, int par3, int par4)
{
Block soil = par1World.getBlock(par2, par3 - 1, par4);
return (par1World.getFullBlockLightValue(par2, par3, par4) >= 8 || par1World.canBlockSeeTheSky(par2, par3, par4)) &&
(soil != null && soil.canSustainPlant(par1World, par2, par3 - 1, par4, ForgeDirection.UP, this));
}
/**
* Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
* adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
*/
@Override
public boolean isOpaqueCube()
{
return false;
}
/**
* If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
*/
@Override
public boolean renderAsNormalBlock()
{
return false;
}
/**
* The type of render function that is called for this block
*/
@Override
public int getRenderType()
{
return 1;
}
@Override
public EnumPlantType getPlantType(IBlockAccess world, int x, int y, int z) {
public EnumPlantType getPlantType(IBlockAccess world, BlockPos pos){
return EnumPlantType.Plains;
}
@Override
public Block getPlant(IBlockAccess world, int x, int y, int z) {
return this;
}
@SubscribeEvent
public static void onBonemealEvent(BonemealEvent event){
// Grows crystal flowers when bonemeal is used on grass
if(Wizardry.settings.bonemealGrowsCrystalFlowers && event.getBlock().getBlock() == Blocks.GRASS){
@Override
public int getPlantMetadata(IBlockAccess world, int x, int y, int z) {
return 0;
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(8) - event.getWorld().rand.nextInt(8));
if(event.getWorld().isAirBlock(new BlockPos(pos))
&& (!event.getWorld().provider.isNether() || pos.getY() < 127)
&& WizardryBlocks.crystal_flower.canPlaceBlockAt(event.getWorld(), pos)){
event.getWorld().setBlockState(pos, WizardryBlocks.crystal_flower.getDefaultState(), 2);
}
}
}
}
@@ -0,0 +1,148 @@
package electroblob.wizardry.block;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityFlowerPot;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import java.util.Random;
public class BlockCrystalFlowerPot extends Block {
protected static final AxisAlignedBB BOUNDING_BOX = new AxisAlignedBB(0.3125D, 0.0D, 0.3125D, 0.6875D, 0.375D, 0.6875D);
public BlockCrystalFlowerPot(){
super(Material.CIRCUITS);
this.setLightLevel(0.4f);
this.setTickRandomly(true);
}
@Override
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
if(world.isRemote && random.nextBoolean()){
ParticleBuilder.create(Type.SPARKLE)
.pos(pos.getX() + 0.3 + random.nextDouble() * 0.4, pos.getY() + 0.6 + random.nextDouble() * 0.3, pos.getZ() + 0.3 + random.nextDouble() * 0.4)
.vel(0, 0.01, 0)
.time(20 + random.nextInt(10))
.clr(0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2), 0.5f + (random.nextFloat() / 2))
.spawn(world);
}
}
@Nullable
@Override
public TileEntity createTileEntity(World world, IBlockState state){
return new TileEntityFlowerPot(Item.getItemFromBlock(WizardryBlocks.crystal_flower), 0);
}
@Override
public boolean hasTileEntity(IBlockState state){
return true;
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ){
ItemStack stack = new ItemStack(WizardryBlocks.crystal_flower);
if(player.getHeldItem(hand).isEmpty()){
player.setHeldItem(hand, stack);
}else if(!player.addItemStackToInventory(stack)){
player.dropItem(stack, false);
}
world.setBlockState(pos, Blocks.FLOWER_POT.getDefaultState());
return true;
}
@Override
public ItemStack getPickBlock(IBlockState state, RayTraceResult target, World world, BlockPos pos, EntityPlayer player){
return new ItemStack(WizardryBlocks.crystal_flower);
}
@Override
public void getDrops(net.minecraft.util.NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, IBlockState state, int fortune){
super.getDrops(drops, world, pos, state, fortune);
drops.add(new ItemStack(WizardryBlocks.crystal_flower));
}
@Override
public Item getItemDropped(IBlockState state, Random rand, int fortune){
return Items.FLOWER_POT;
}
// The rest are identical behaviour to BlockFlowerPot
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return BOUNDING_BOX;
}
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Override
public boolean canPlaceBlockAt(World world, BlockPos pos){
IBlockState downState = world.getBlockState(pos.down());
return super.canPlaceBlockAt(world, pos) && (downState.isTopSolid() || downState.getBlockFaceShape(world, pos.down(), EnumFacing.UP) == BlockFaceShape.SOLID);
}
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos neighbour){
IBlockState downState = world.getBlockState(pos.down());
if(!downState.isTopSolid() && downState.getBlockFaceShape(world, pos.down(), EnumFacing.UP) != BlockFaceShape.SOLID){
this.dropBlockAsItem(world, pos, state, 0);
world.setBlockToAir(pos);
}
}
@Override
public BlockRenderLayer getRenderLayer(){
return BlockRenderLayer.CUTOUT;
}
@Override
public BlockFaceShape getBlockFaceShape(IBlockAccess worldIn, IBlockState state, BlockPos pos, EnumFacing face){
return BlockFaceShape.UNDEFINED;
}
@Override
public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest){
if(willHarvest) return true; // If it will harvest, delay deletion of the block until after getDrops
return super.removedByPlayer(state, world, pos, player, willHarvest);
}
@Override
public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, @Nullable TileEntity te, ItemStack tool){
super.harvestBlock(world, player, pos, state, te, tool);
world.setBlockToAir(pos);
}
}
@@ -1,34 +1,57 @@
package electroblob.wizardry.block;
import electroblob.wizardry.registry.WizardryItems;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.Item;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import java.util.Random;
import electroblob.wizardry.Wizardry;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.item.Item;
public class BlockCrystalOre extends Block {
public BlockCrystalOre(Material material) {
public BlockCrystalOre(Material material){
super(material);
setStepSound(Block.soundTypeStone);
setBlockName("crystalOre");
this.setSoundType(SoundType.STONE);
setResistance(5.0F);
setHarvestLevel("pickaxe", 2);
}
@Override
public int quantityDropped(int meta, int fortune, Random random)
{
public int quantityDropped(IBlockState state, int fortune, Random random){
// This now works the same way as vanilla ores
if(fortune > 0){
return random.nextInt(2) + 1 + random.nextInt(fortune);
int i = random.nextInt(fortune + 2) - 1;
if(i < 0) i = 0;
return (random.nextInt(3) + 1) * (i + 1);
}else{
return random.nextInt(2) + 1;
return random.nextInt(3) + 1;
}
}
}
@Override
public Item getItemDropped(IBlockState state, Random random, int fortune){
return WizardryItems.magic_crystal;
}
@Override
public Item getItemDropped(int Metadata, Random random, int fortune){
return Wizardry.magicCrystal;
public int getExpDrop(IBlockState state, IBlockAccess world, BlockPos pos, int fortune){
Random rand = world instanceof World ? ((World)world).rand : RANDOM;
if(this.getItemDropped(state, rand, fortune) != Item.getItemFromBlock(this)){
return MathHelper.getInt(rand, 1, 4);
}
return 0;
}
}
@@ -0,0 +1,41 @@
package electroblob.wizardry.block;
import net.minecraft.block.BlockFrostedIce;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import java.util.Random;
/** Like {@link BlockFrostedIce}, but melting does not depend on light level or neighbouring blocks, and it just
* disappears instead of turning to water. */
public class BlockDryFrostedIce extends BlockFrostedIce {
public BlockDryFrostedIce(){
super();
setDefaultSlipperiness(0.98f); // For some strange reason BlockFrostedIce overrides BlockIce's icy-ness...
setSoundType(SoundType.GLASS);
}
@Override
public Material getMaterial(IBlockState state){
return Material.ICE; // For goodness sake
}
@Override
protected void turnIntoWater(World world, BlockPos pos){
world.destroyBlock(pos, false);
}
@Override
public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand){
if(rand.nextInt(3) == 0){
this.slightlyMelt(worldIn, pos, state, rand, true);
}else{
worldIn.scheduleUpdate(pos, this, MathHelper.getInt(rand, 20, 40));
}
}
}
@@ -0,0 +1,17 @@
package electroblob.wizardry.block;
import electroblob.wizardry.registry.WizardryTabs;
import net.minecraft.block.BlockPlanks;
import net.minecraft.block.SoundType;
public class BlockGildedWood extends BlockPlanks {
public BlockGildedWood(){
super();
this.setCreativeTab(WizardryTabs.WIZARDRY);
this.setHardness(2.0F);
this.setResistance(5.0F);
this.setSoundType(SoundType.WOOD); // Why is this protected?!
}
}
@@ -0,0 +1,179 @@
package electroblob.wizardry.block;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryTabs;
import electroblob.wizardry.tileentity.TileEntityImbuementAltar;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import java.util.Arrays;
public class BlockImbuementAltar extends Block implements ITileEntityProvider {
public static final PropertyBool ACTIVE = PropertyBool.create("active");
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.75, 1.0);
public BlockImbuementAltar(){
super(Material.ROCK);
this.setBlockUnbreakable();
this.setResistance(6000000);
this.setLightLevel(0.4f);
this.setCreativeTab(WizardryTabs.WIZARDRY);
this.setDefaultState(this.blockState.getBaseState().withProperty(ACTIVE, false));
}
@Override
protected BlockStateContainer createBlockState(){
return new BlockStateContainer(this, ACTIVE);
}
@Override
public IBlockState getStateFromMeta(int meta){
return this.getDefaultState().withProperty(ACTIVE, meta == 1);
}
@Override
public int getMetaFromState(IBlockState state){
return state.getValue(ACTIVE) ? 1 : 0;
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata){
return new TileEntityImbuementAltar();
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
return false;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.MODEL;
}
@Override
public BlockRenderLayer getRenderLayer(){
return BlockRenderLayer.CUTOUT; // Required to shade parts of the block faces differently to others
}
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Override
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
return face == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
}
@Override
public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos){
return state.getValue(ACTIVE) ? super.getLightValue(state, world, pos) : 0;
}
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos neighbour){
boolean shouldBeActive = Arrays.stream(EnumFacing.HORIZONTALS)
.allMatch(s -> world.getBlockState(pos.offset(s)).getBlock() == WizardryBlocks.receptacle
&& world.getBlockState(pos.offset(s)).getValue(BlockReceptacle.FACING) == s);
if(world.getBlockState(pos).getValue(ACTIVE) != shouldBeActive){ // Only set when it actually needs changing
// Get contents of altar before replacing it
TileEntity te = world.getTileEntity(pos);
ItemStack stack = ItemStack.EMPTY;
if(te instanceof TileEntityImbuementAltar) stack = ((TileEntityImbuementAltar)te).getStack();
world.setBlockState(pos, world.getBlockState(pos).withProperty(ACTIVE, shouldBeActive));
// Copy over contents of altar from before to new tile entity
te = world.getTileEntity(pos);
if(te instanceof TileEntityImbuementAltar) ((TileEntityImbuementAltar)te).setStack(stack);
world.checkLight(pos);
}
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity instanceof TileEntityImbuementAltar){
((TileEntityImbuementAltar)tileEntity).checkRecipe();
}
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, EnumHand hand,
EnumFacing side, float hitX, float hitY, float hitZ){
TileEntity tileEntity = world.getTileEntity(pos);
if(!(tileEntity instanceof TileEntityImbuementAltar) || player.isSneaking()){
return false;
}
ItemStack currentStack = ((TileEntityImbuementAltar)tileEntity).getStack();
ItemStack toInsert = player.getHeldItem(hand);
if(currentStack.isEmpty()){
ItemStack stack = toInsert.copy();
stack.setCount(1);
((TileEntityImbuementAltar)tileEntity).setStack(stack);
((TileEntityImbuementAltar)tileEntity).setLastUser(player);
if(!player.isCreative()) toInsert.shrink(1);
}else{
if(toInsert.isEmpty()){
player.setHeldItem(hand, currentStack);
}else if(!player.addItemStackToInventory(currentStack)){
player.dropItem(currentStack, false);
}
((TileEntityImbuementAltar)tileEntity).setStack(ItemStack.EMPTY);
((TileEntityImbuementAltar)tileEntity).setLastUser(null);
}
return true;
}
@Override
public void breakBlock(World world, BlockPos pos, IBlockState block){
TileEntity tileentity = world.getTileEntity(pos);
if(tileentity instanceof TileEntityImbuementAltar){
InventoryHelper.spawnItemStack(world, pos.getX(), pos.getY(), pos.getZ(), ((TileEntityImbuementAltar)tileentity).getStack());
}
super.breakBlock(world, pos, block);
}
}
@@ -0,0 +1,138 @@
package electroblob.wizardry.block;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler;
import electroblob.wizardry.registry.WizardryTabs;
import electroblob.wizardry.tileentity.TileEntityLectern;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.block.BlockHorizontal;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nullable;
import java.util.Random;
public class BlockLectern extends BlockHorizontal implements ITileEntityProvider {
public BlockLectern(){
super(Material.WOOD);
this.setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH));
this.setCreativeTab(WizardryTabs.WIZARDRY);
this.setHardness(2.0F);
this.setResistance(5.0F);
this.setSoundType(SoundType.WOOD);
}
@Override
protected BlockStateContainer createBlockState(){
return new BlockStateContainer.Builder(this).add(FACING).build();
}
@Override
public IBlockState getStateFromMeta(int meta){
EnumFacing enumfacing = EnumFacing.byIndex(meta);
if(enumfacing.getAxis() == EnumFacing.Axis.Y) enumfacing = EnumFacing.NORTH;
return this.getDefaultState().withProperty(FACING, enumfacing);
}
@Override
public int getMetaFromState(IBlockState state){
return state.getValue(FACING).getIndex();
}
@Override
@SideOnly(Side.CLIENT)
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random rand){
EntityPlayer entityplayer = world.getClosestPlayer(pos.getX() + 0.5, pos.getY() + 0.5,
pos.getZ() + 0.5, TileEntityLectern.BOOK_OPEN_DISTANCE, false);
if(entityplayer != null){
ParticleBuilder.create(Type.DUST).pos(pos.getX() + rand.nextFloat(), pos.getY() + 1, pos.getZ() + rand.nextFloat())
.vel(0, 0.03, 0).clr(1, 1, 0.65f).fade(0.7f, 0, 1).shaded(false).spawn(world);
}
}
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Override
public boolean isFullBlock(IBlockState state){
return false;
}
@Override
public boolean isNormalCube(IBlockState state){
return false;
}
@Override
public boolean canPlaceTorchOnTop(IBlockState state, IBlockAccess world, BlockPos pos){
return false;
}
@Override
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
return face == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
}
@Override
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer){
return this.getDefaultState().withProperty(FACING, placer.getHorizontalFacing().getOpposite());
}
@Override
public IBlockState withRotation(IBlockState state, Rotation rotation){
return state.withProperty(FACING, rotation.rotate(state.getValue(FACING)));
}
@Override
public IBlockState withMirror(IBlockState state, Mirror mirror){
return state.withRotation(mirror.toRotation(state.getValue(FACING)));
}
@Nullable
@Override
public TileEntity createNewTileEntity(World world, int meta){
return new TileEntityLectern();
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, EnumHand hand,
EnumFacing side, float hitX, float hitY, float hitZ){
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity == null || player.isSneaking()){
return false;
}
player.openGui(Wizardry.instance, WizardryGuiHandler.LECTERN, world, pos.getX(), pos.getY(), pos.getZ());
return true;
}
}
@@ -1,40 +1,92 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.tileentity.TileEntityMagicLight;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockMagicLight extends BlockContainer {
public class BlockMagicLight extends Block implements ITileEntityProvider {
public BlockMagicLight(Material par2Material) {
super(par2Material);
//private static final AxisAlignedBB AABB = new AxisAlignedBB(0, 0, 0, 0, 0, 0);
public BlockMagicLight(Material material){
super(material);
this.setLightLevel(1.0f);
this.setBlockBounds(0, 0, 0, 0, 0, 0);
this.setBlockUnbreakable();
}
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
{
return null;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, IBlockAccess worldIn, BlockPos pos){
// The other two bounding box methods in Block aren't nullable, so this is the
// only one that can return NULL_AABB.
return NULL_AABB;
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ){
// Let the player dispel any lights if they have the lantern charm, not just the permanent ones because that would be annoying!
if(player.getHeldItem(hand).getItem() instanceof ISpellCastingItem && ItemArtefact.isArtefactActive(player, WizardryItems.charm_light)){
world.setBlockToAir(pos);
return true;
}else{
return super.onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ);
}
}
// @Override
// public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
// return AABB;
// }
@Override
public boolean isCollidable(){
// This method has nothing to do with entity movement, it's just for raytracing
return true;
}
@Override
public boolean addDestroyEffects(World world, BlockPos pos, net.minecraft.client.particle.ParticleManager manager){
if(world.getBlockState(pos).getBlock() == this) return true; // No break particles!
else return super.addDestroyEffects(world, pos, manager);
}
@Override
public boolean hasTileEntity(IBlockState state){
return true;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata){
return new TileEntityMagicLight(600);
}
@Override
public boolean renderAsNormalBlock()
{
return false;
}
@Override
public boolean isOpaqueCube(){
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
return false;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.ENTITYBLOCK_ANIMATED;
}
}
@@ -0,0 +1,116 @@
package electroblob.wizardry.block;
import net.minecraft.block.Block;
import net.minecraft.block.BlockObsidian;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import java.util.Random;
/** Like {@link net.minecraft.block.BlockFrostedIce}, but for lava instead of water. */
// This is mostly copied from that class, with a few changes
public class BlockObsidianCrust extends BlockObsidian {
public static final PropertyInteger AGE = PropertyInteger.create("age", 0, 3);
public BlockObsidianCrust(){
this.setDefaultState(this.blockState.getBaseState().withProperty(AGE, 0));
}
@Override
public int getMetaFromState(IBlockState state){
return state.getValue(AGE);
}
@Override
public IBlockState getStateFromMeta(int meta){
return this.getDefaultState().withProperty(AGE, MathHelper.clamp(meta, 0, 3));
}
@Override
public void updateTick(World world, BlockPos pos, IBlockState state, Random random){
if((random.nextInt(3) == 0 || this.countNeighbors(world, pos) < 4) && world.getLightFromNeighbors(pos) > 11 - state.getValue(AGE) - state.getLightOpacity()){
this.slightlyMelt(world, pos, state, random, true);
}else{
world.scheduleUpdate(pos, this, MathHelper.getInt(random, 20, 40));
}
}
@Override
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos fromPos){
if(block == this){
int i = this.countNeighbors(world, pos);
if(i < 2){
this.melt(world, pos);
}
}
}
private int countNeighbors(World world, BlockPos pos){
int i = 0;
for(EnumFacing enumfacing : EnumFacing.values()){
if(world.getBlockState(pos.offset(enumfacing)).getBlock() == this){
++i;
if(i >= 4){
return i;
}
}
}
return i;
}
protected void slightlyMelt(World world, BlockPos pos, IBlockState state, Random random, boolean meltNeighbours){
int i = state.getValue(AGE);
if(i < 3){
world.setBlockState(pos, state.withProperty(AGE, i + 1), 2);
world.scheduleUpdate(pos, this, MathHelper.getInt(random, 20, 40));
}else{
this.melt(world, pos);
if(meltNeighbours){
for(EnumFacing enumfacing : EnumFacing.values()){
BlockPos blockpos = pos.offset(enumfacing);
IBlockState iblockstate = world.getBlockState(blockpos);
if(iblockstate.getBlock() == this){
this.slightlyMelt(world, blockpos, iblockstate, random, false);
}
}
}
}
}
protected void melt(World world, BlockPos pos){
world.setBlockState(pos, Blocks.LAVA.getDefaultState());
world.neighborChanged(pos, Blocks.LAVA, pos);
}
@Override
protected BlockStateContainer createBlockState(){
return new BlockStateContainer(this, AGE);
}
@Override
public ItemStack getItem(World world, BlockPos pos, IBlockState state){
return ItemStack.EMPTY;
}
}
@@ -0,0 +1,125 @@
package electroblob.wizardry.block;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.registry.WizardryTabs;
import electroblob.wizardry.tileentity.TileEntityShrineCore;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.MapColor;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.EnumMap;
public class BlockPedestal extends Block implements ITileEntityProvider {
public static final PropertyEnum<Element> ELEMENT = PropertyEnum.create("element", Element.class,
Arrays.copyOfRange(Element.values(), 1, Element.values().length)); // Everything except MAGIC
// A 'natural' pedestal is one that was generated as part of a structure, is unbreakable and has a tileentity
public static final PropertyBool NATURAL = PropertyBool.create("natural");
private static final EnumMap<Element, MapColor> map_colours = new EnumMap<>(Element.class);
static {
map_colours.put(Element.FIRE, MapColor.RED_STAINED_HARDENED_CLAY);
map_colours.put(Element.ICE, MapColor.LIGHT_BLUE_STAINED_HARDENED_CLAY);
map_colours.put(Element.LIGHTNING, MapColor.CYAN_STAINED_HARDENED_CLAY);
map_colours.put(Element.NECROMANCY, MapColor.PURPLE_STAINED_HARDENED_CLAY);
map_colours.put(Element.EARTH, MapColor.BROWN_STAINED_HARDENED_CLAY);
map_colours.put(Element.SORCERY, MapColor.GRAY);
map_colours.put(Element.HEALING, MapColor.YELLOW_STAINED_HARDENED_CLAY);
}
public BlockPedestal(Material material){
super(material);
this.setDefaultState(this.blockState.getBaseState().withProperty(ELEMENT, Element.FIRE).withProperty(NATURAL, false));
this.setCreativeTab(WizardryTabs.WIZARDRY);
this.setHardness(1.5F);
this.setResistance(10.0F);
}
@Override
public int damageDropped(IBlockState state){
return state.getValue(ELEMENT).ordinal(); // Ignore the NATURAL state here, it's unobtainable
}
@Override
public MapColor getMapColor(IBlockState state, IBlockAccess world, BlockPos pos){
return map_colours.get(state.getProperties().get(ELEMENT));
}
@Override
public void getSubBlocks(CreativeTabs tab, NonNullList<ItemStack> items){
// Ignore the NATURAL state here, it's unobtainable
if(this.getCreativeTab() == tab){
for(Element element : Arrays.copyOfRange(Element.values(), 1, Element.values().length)){
items.add(new ItemStack(this, 1, element.ordinal()));
}
}
}
@Override
public BlockRenderLayer getRenderLayer(){
return BlockRenderLayer.CUTOUT; // Required to shade parts of the block faces differently to others
}
@Override
public float getBlockHardness(IBlockState state, World world, BlockPos pos){
return state.getValue(NATURAL) ? -1 : super.getBlockHardness(state, world, pos);
}
@Override
public float getExplosionResistance(World world, BlockPos pos, @Nullable Entity exploder, Explosion explosion){
return world.getBlockState(pos).getValue(NATURAL) ? 6000000.0F : super.getExplosionResistance(world, pos, exploder, explosion);
}
@Override
public boolean hasTileEntity(IBlockState state){
return state.getValue(NATURAL); // Only naturally-generated pedestals have a (shrine core) tile entity
}
@Nullable
@Override
public TileEntity createNewTileEntity(World world, int meta){
return new TileEntityShrineCore();
}
@Override
public IBlockState getStateFromMeta(int metadata){
boolean natural = false;
if(metadata > ELEMENT.getAllowedValues().size()){
natural = true;
metadata -= ELEMENT.getAllowedValues().size();
}
Element element = Element.values()[metadata];
if(!ELEMENT.getAllowedValues().contains(element)) return this.getDefaultState().withProperty(NATURAL, natural);
return this.getDefaultState().withProperty(ELEMENT, element).withProperty(NATURAL, natural);
}
@Override
public int getMetaFromState(IBlockState state){
return state.getValue(ELEMENT).ordinal() + (state.getValue(NATURAL) ? ELEMENT.getAllowedValues().size() : 0);
}
@Override
protected BlockStateContainer createBlockState(){
return new BlockStateContainer(this, ELEMENT, NATURAL);
}
}
@@ -0,0 +1,91 @@
package electroblob.wizardry.block;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.EntityUtils;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nullable;
public class BlockPermafrost extends BlockDryFrostedIce {
protected static final AxisAlignedBB BOUNDING_BOX = new AxisAlignedBB(0, 0, 0, 1, 0, 1);
protected static final AxisAlignedBB SELECTION_BOUNDING_BOX = new AxisAlignedBB(0, 0, 0, 1, 0.125, 1);
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return BOUNDING_BOX;
}
@Override
public AxisAlignedBB getSelectedBoundingBox(IBlockState state, World worldIn, BlockPos pos){
return SELECTION_BOUNDING_BOX;
}
@Nullable
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, IBlockAccess worldIn, BlockPos pos){
return super.getCollisionBoundingBox(blockState, worldIn, pos);
}
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Override
public boolean isNormalCube(IBlockState state){
return false;
}
@Override
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
return face == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
}
@Override
public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){
if(EntityUtils.isLiving(entity) && entity.ticksExisted % 30 == 0){
// Can't make it player damage unless we make this block a tile entity, but there will be too many for that
entity.attackEntityFrom(DamageSource.MAGIC, Spells.permafrost.getProperty(Spell.DAMAGE).floatValue());
int duration = Spells.permafrost.getProperty(Spell.EFFECT_DURATION).intValue();
int amplifier = Spells.permafrost.getProperty(Spell.EFFECT_STRENGTH).intValue();
((EntityLivingBase)entity).addPotionEffect(new PotionEffect(WizardryPotions.frost, duration, amplifier));
}
// EntityLivingBase's slipperiness code doesn't get the block below it properly so slipperiness only works for
// full blocks...
if(entity.onGround){
// Not brilliant but it's about the best I can do
entity.motionX *= 1.12 - entity.motionX * entity.motionX;
entity.motionZ *= 1.12 - entity.motionZ * entity.motionZ;
// if(entity instanceof EntityLivingBase){
// double maxVel = 0.8;
// double x = entity.motionX;
// double y = entity.motionY;
// double z = entity.motionZ;
// double vel = MathHelper.sqrt(x*x + y*y + z*z);
// double m = vel / maxVel;
// if(m > 1){
// entity.motionX /= m;
// entity.motionZ /= m;
// }
// }
}
}
}
@@ -0,0 +1,310 @@
package electroblob.wizardry.block;
import com.google.common.collect.Maps;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.item.ItemSpectralDust;
import electroblob.wizardry.registry.*;
import electroblob.wizardry.tileentity.TileEntityReceptacle;
import electroblob.wizardry.util.GeometryUtils;
import electroblob.wizardry.util.ParticleBuilder;
import net.minecraft.block.Block;
import net.minecraft.block.BlockTorch;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.SoundType;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Map;
import java.util.Random;
public class BlockReceptacle extends BlockTorch implements ITileEntityProvider {
protected static final AxisAlignedBB STANDING_AABB = new AxisAlignedBB(4 / 16d, 0 / 16d, 4 / 16d, 12 / 16d, 8 / 16d, 12 / 16d);
protected static final AxisAlignedBB NORTH_WALL_AABB = new AxisAlignedBB(4 / 16d, 2 / 16d, 7 / 16d, 12 / 16d, 10 / 16d, 16 / 16d);
protected static final AxisAlignedBB SOUTH_WALL_AABB = new AxisAlignedBB(4 / 16d, 2 / 16d, 0 / 16d, 12 / 16d, 10 / 16d, 9 / 16d);
protected static final AxisAlignedBB WEST_WALL_AABB = new AxisAlignedBB(7 / 16d, 2 / 16d, 4 / 16d, 16 / 16d, 10 / 16d, 12 / 16d);
protected static final AxisAlignedBB EAST_WALL_AABB = new AxisAlignedBB(0 / 16d, 2 / 16d, 4 / 16d, 9 / 16d, 10 / 16d, 12 / 16d);
private static final double WALL_PARTICLE_OFFSET = 3 / 16d;
public static final Map<Element, int[]> PARTICLE_COLOURS;
static{
Map<Element, int[]> map = Maps.newEnumMap(Element.class);
map.put(Element.MAGIC, new int[]{0xe4c7cd, 0xfeffbe, 0x9d2cf3});
map.put(Element.FIRE, new int[]{0xff9600, 0xfffe67, 0xd02700});
map.put(Element.ICE, new int[]{0xa3e8f4, 0xe9f9fc, 0x138397});
map.put(Element.LIGHTNING, new int[]{0x409ee1, 0xf5f0ff, 0x225474});
map.put(Element.NECROMANCY, new int[]{0xa811ce, 0xf575f5, 0x382366});
map.put(Element.EARTH, new int[]{0xa8f408, 0xc8ffb2, 0x795c28});
map.put(Element.SORCERY, new int[]{0x56e8e3, 0xe8fcfc, 0x16a64d});
map.put(Element.HEALING, new int[]{0xfff69e, 0xfffff6, 0xa18200});
PARTICLE_COLOURS = Maps.immutableEnumMap(map);
}
public BlockReceptacle(){
super();
this.setCreativeTab(WizardryTabs.WIZARDRY);
this.setHardness(0);
this.setLightLevel(0.5f);
this.setSoundType(SoundType.STONE);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
switch(state.getValue(FACING)){
case EAST:
return EAST_WALL_AABB;
case WEST:
return WEST_WALL_AABB;
case SOUTH:
return SOUTH_WALL_AABB;
case NORTH:
return NORTH_WALL_AABB;
default:
return STANDING_AABB;
}
}
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
return state.getBoundingBox(world, pos);
}
@Override
public int getLightValue(IBlockState state, IBlockAccess world, BlockPos pos){
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity instanceof TileEntityReceptacle && ((TileEntityReceptacle)tileEntity).getElement() != null){
return super.getLightValue(state, world, pos); // Return super to use float value from constructor
}
return 0;
}
@Override
public void getDrops(NonNullList<ItemStack> drops, IBlockAccess world, BlockPos pos, IBlockState state, int fortune){
super.getDrops(drops, world, pos, state, fortune);
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity instanceof TileEntityReceptacle){
Element element = ((TileEntityReceptacle)tileEntity).getElement();
if(element != null) drops.add(new ItemStack(WizardryItems.spectral_dust, 1, element.ordinal()));
}
}
@Override
public boolean canPlaceBlockOnSide(World world, BlockPos pos, EnumFacing side){
if(side != EnumFacing.UP && side != EnumFacing.DOWN
&& world.getBlockState(pos.offset(side.getOpposite())).getBlock() instanceof BlockImbuementAltar){
return true;
}
return super.canPlaceBlockOnSide(world, pos, side);
}
@Override
protected boolean checkForDrop(World world, BlockPos pos, IBlockState state){
if(state.getBlock() == this && this.canPlaceAt(world, pos, state.getValue(FACING))){
return true;
}
return super.checkForDrop(world, pos, state);
}
@Override
protected boolean onNeighborChangeInternal(World world, BlockPos pos, IBlockState state){
// This is so stupid, BlockTorch DUPLICATES the code that checks for valid placement in the super method instead
// of checking the existing methods...
return !this.checkForDrop(world, pos, state); // Literally all we need. None of the rubbish in super.
}
@Override
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer){
if(this.canPlaceAt(world, pos, facing)){
return this.getDefaultState().withProperty(FACING, facing);
}else{
for(EnumFacing enumfacing : EnumFacing.Plane.HORIZONTAL){
if(this.canPlaceAt(world, pos, enumfacing)){
return this.getDefaultState().withProperty(FACING, enumfacing);
}
}
return this.getDefaultState();
}
}
// Why is everything in BlockTorch private, for goodness sake...
private boolean canPlaceAt(World world, BlockPos pos, EnumFacing facing){
BlockPos blockpos = pos.offset(facing.getOpposite());
IBlockState state = world.getBlockState(blockpos);
Block block = state.getBlock();
BlockFaceShape blockfaceshape = state.getBlockFaceShape(world, blockpos, facing);
if(facing.equals(EnumFacing.UP) && this.canPlaceOn(world, blockpos)){
return true;
}else if(facing != EnumFacing.UP && facing != EnumFacing.DOWN){
return !isExceptBlockForAttachWithPiston(block) && (blockfaceshape == BlockFaceShape.SOLID || block instanceof BlockImbuementAltar);
}else{
return false;
}
}
private boolean canPlaceOn(World world, BlockPos pos){
IBlockState state = world.getBlockState(pos);
return state.getBlock().canPlaceTorchOnTop(state, world, pos);
}
// See BlockFlowerPot for these two (this class is essentially based on a flower pot)
@Override
public boolean removedByPlayer(IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest){
if(willHarvest) return true; // If it will harvest, delay deletion of the block until after getDrops
return super.removedByPlayer(state, world, pos, player, willHarvest);
}
@Override
public void harvestBlock(World world, EntityPlayer player, BlockPos pos, IBlockState state, @Nullable TileEntity te, ItemStack tool){
super.harvestBlock(world, player, pos, state, te, tool);
world.setBlockToAir(pos);
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ){
TileEntity tileEntity = world.getTileEntity(pos);
ItemStack stack = player.getHeldItem(hand);
if(tileEntity instanceof TileEntityReceptacle){
Element currentElement = ((TileEntityReceptacle)tileEntity).getElement();
if(currentElement == null){
if(stack.getItem() instanceof ItemSpectralDust && stack.getMetadata() >= 0
&& stack.getMetadata() < Element.values().length){
((TileEntityReceptacle)tileEntity).setElement(Element.values()[stack.getMetadata()]);
if(!player.capabilities.isCreativeMode) stack.shrink(1);
world.playSound(pos.getX(), pos.getY(), pos.getZ(), WizardrySounds.BLOCK_RECEPTACLE_IGNITE,
SoundCategory.BLOCKS, 0.7f, 0.7f, false);
return true;
}
}else{
((TileEntityReceptacle)tileEntity).setElement(null);
ItemStack dust = new ItemStack(WizardryItems.spectral_dust, 1, currentElement.ordinal());
if(stack.isEmpty()){
player.setHeldItem(hand, dust);
}else if(!player.addItemStackToInventory(dust)){
player.dropItem(dust, false);
}
return true;
}
}
return super.onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ);
}
@Override
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random rand){
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity instanceof TileEntityReceptacle){
Element element = ((TileEntityReceptacle)tileEntity).getElement();
if(element != null){
EnumFacing facing = state.getValue(FACING).getOpposite();
Vec3d centre = GeometryUtils.getCentre(pos);
if(facing.getAxis().isHorizontal()){
centre = centre.add(new Vec3d(facing.getDirectionVec()).scale(WALL_PARTICLE_OFFSET)).add(0, 0.125, 0);
}
int[] colours = PARTICLE_COLOURS.get(element);
ParticleBuilder.create(ParticleBuilder.Type.FLASH).pos(centre).scale(0.35f).time(48).clr(colours[0]).spawn(world);
double r = 0.12;
for(int i = 0; i < 3; i++){
double x = r * (rand.nextDouble() * 2 - 1);
double y = r * (rand.nextDouble() * 2 - 1);
double z = r * (rand.nextDouble() * 2 - 1);
ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(centre.x + x, centre.y + y, centre.z + z)
.vel(x * -0.03, 0.02, z * -0.03).time(24 + rand.nextInt(8)).clr(colours[1]).fade(colours[2]).spawn(world);
}
}
}
}
@Override
public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack){
if(placer instanceof EntityPlayer){
BlockPos centre = pos.offset(world.getBlockState(pos).getValue(FACING).getOpposite());
if(world.getBlockState(centre).getBlock() == WizardryBlocks.imbuement_altar
&& Arrays.stream(EnumFacing.HORIZONTALS).allMatch(f -> world.getBlockState(centre.offset(f)).getBlock() == WizardryBlocks.receptacle)){
WizardryAdvancementTriggers.restore_imbuement_altar.triggerFor((EntityPlayer)placer);
}
}
}
@Nullable
@Override
public TileEntity createNewTileEntity(World world, int meta){
return new TileEntityReceptacle();
}
@Override
public boolean hasComparatorInputOverride(IBlockState state){
return true;
}
@Override
public int getComparatorInputOverride(IBlockState state, World world, BlockPos pos){
TileEntity tileEntity = world.getTileEntity(pos);
if(tileEntity instanceof TileEntityReceptacle){
Element element = ((TileEntityReceptacle)tileEntity).getElement();
return element == null ? 0 : element.ordinal() + 1;
}
return super.getComparatorInputOverride(state, world, pos);
}
}
@@ -0,0 +1,87 @@
package electroblob.wizardry.block;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.registry.WizardryTabs;
import net.minecraft.block.Block;
import net.minecraft.block.material.MapColor;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemStack;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import java.util.Arrays;
import java.util.EnumMap;
public class BlockRunestone extends Block {
public static final PropertyEnum<Element> ELEMENT = PropertyEnum.create("element", Element.class,
Arrays.copyOfRange(Element.values(), 1, Element.values().length)); // Everything except MAGIC
private static final EnumMap<Element, MapColor> map_colours = new EnumMap<>(Element.class);
static {
map_colours.put(Element.FIRE, MapColor.RED_STAINED_HARDENED_CLAY);
map_colours.put(Element.ICE, MapColor.LIGHT_BLUE_STAINED_HARDENED_CLAY);
map_colours.put(Element.LIGHTNING, MapColor.CYAN_STAINED_HARDENED_CLAY);
map_colours.put(Element.NECROMANCY, MapColor.PURPLE_STAINED_HARDENED_CLAY);
map_colours.put(Element.EARTH, MapColor.BROWN_STAINED_HARDENED_CLAY);
map_colours.put(Element.SORCERY, MapColor.GRAY);
map_colours.put(Element.HEALING, MapColor.YELLOW_STAINED_HARDENED_CLAY);
}
public BlockRunestone(Material material){
super(material);
this.setDefaultState(this.blockState.getBaseState().withProperty(ELEMENT, Element.FIRE));
this.setCreativeTab(WizardryTabs.WIZARDRY);
this.setHardness(1.5F);
this.setResistance(10.0F);
}
@Override
public int damageDropped(IBlockState state){
return state.getValue(ELEMENT).ordinal();
}
@Override
public MapColor getMapColor(IBlockState state, IBlockAccess world, BlockPos pos){
return map_colours.get(state.getProperties().get(ELEMENT));
}
@Override
public void getSubBlocks(CreativeTabs tab, NonNullList<ItemStack> items){
if(this.getCreativeTab() == tab){
for(Element element : Arrays.copyOfRange(Element.values(), 1, Element.values().length)){
items.add(new ItemStack(this, 1, element.ordinal()));
}
}
}
@Override
public BlockRenderLayer getRenderLayer(){
return BlockRenderLayer.CUTOUT; // Required to shade parts of the block faces differently to others
}
@Override
public IBlockState getStateFromMeta(int metadata){
Element element = Element.values()[metadata];
if(!ELEMENT.getAllowedValues().contains(element)) return this.getDefaultState();
return this.getDefaultState().withProperty(ELEMENT, element);
}
@Override
public int getMetaFromState(IBlockState state){
return state.getValue(ELEMENT).ordinal();
}
@Override
protected BlockStateContainer createBlockState(){
return new BlockStateContainer(this, ELEMENT);
}
}
@@ -1,90 +1,120 @@
package electroblob.wizardry.block;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.TileEntityPlayerSave;
import electroblob.wizardry.util.AllyDesignationSystem;
import electroblob.wizardry.util.MagicDamage;
import electroblob.wizardry.util.MagicDamage.DamageType;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.MobEffects;
import net.minecraft.item.Item;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import java.util.Random;
import electroblob.wizardry.EnumElement;
import electroblob.wizardry.MagicDamage;
import electroblob.wizardry.MagicDamage.DamageType;
import electroblob.wizardry.WizardryUtilities;
import electroblob.wizardry.tileentity.TileEntityPlayerSave;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.Item;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
public class BlockSnare extends Block implements ITileEntityProvider {
public class BlockSnare extends BlockContainer {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0f, 0.0f, 0.0f, 1.0f, 0.0625f, 1.0f);
public BlockSnare(Material par2Material){
super(par2Material);
this.setBlockBounds(0.0f, 0.0f, 0.0f, 1.0f, 0.0625f, 1.0f);
public BlockSnare(Material material){
super(material);
this.setSoundType(SoundType.PLANT);
}
@Override
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4){
return null;
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
@Override
public boolean hasTileEntity(int metadata){
public AxisAlignedBB getCollisionBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
return NULL_AABB;
}
@Override
public boolean hasTileEntity(IBlockState state){
return true;
}
@Override
public void onEntityCollidedWithBlock(World world, int x, int y, int z, Entity entity){
if(!world.isRemote && entity instanceof EntityLivingBase){
if(world.getTileEntity(x, y, z) instanceof TileEntityPlayerSave){
TileEntityPlayerSave tileentity = (TileEntityPlayerSave)world.getTileEntity(x, y, z);
if(WizardryUtilities.isValidTarget(tileentity.getCaster(), entity)){
((EntityLivingBase)entity).attackEntityFrom(MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC), 6);
((EntityLivingBase)entity).addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, 100, 2));
world.func_147480_a(x, y, z, false);
public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){
if(entity instanceof EntityLivingBase){
if(world.getTileEntity(pos) instanceof TileEntityPlayerSave){
TileEntityPlayerSave tileentity = (TileEntityPlayerSave)world.getTileEntity(pos);
if(AllyDesignationSystem.isValidTarget(tileentity.getCaster(), entity)){
DamageSource source = tileentity.getCaster() == null ? DamageSource.CACTUS
: MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC);
entity.attackEntityFrom(source, Spells.snare.getProperty(Spell.DAMAGE).floatValue());
((EntityLivingBase)entity).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS,
Spells.snare.getProperty(Spell.EFFECT_DURATION).intValue(),
Spells.snare.getProperty(Spell.EFFECT_STRENGTH).intValue()));
if(!world.isRemote) world.destroyBlock(pos, false);
}
}
}
}
// The similarly named onNeighborChange method does NOT do the same thing.
@SuppressWarnings("deprecation")
@Override
public void onNeighborBlockChange(World world, int x, int y, int z, Block block)
{
super.onNeighborBlockChange(world, x, y, z, block);
if(!world.isSideSolid(x, y-1, z, ForgeDirection.UP)){
world.setBlockToAir(x, y, z);
}
}
@Override
public boolean renderAsNormalBlock()
{
return false;
}
@Override
public boolean isOpaqueCube()
{
return false;
}
@Override
public int getRenderType(){
return 23;
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos fromPos){
super.neighborChanged(state, world, pos, block, fromPos);
if(!world.isSideSolid(pos.down(), EnumFacing.UP, false)){
world.setBlockToAir(pos);
}
}
@Override
public Item getItemDropped(int a, Random random, int b){
public BlockRenderLayer getRenderLayer() {
return BlockRenderLayer.CUTOUT;
}
@Override
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.MODEL;
}
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Override
public Item getItemDropped(IBlockState state, Random rand, int fortune){
return null;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
public TileEntity createNewTileEntity(World world, int metadata){
return new TileEntityPlayerSave();
}
@@ -1,74 +1,101 @@
package electroblob.wizardry.block;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.tileentity.TileEntityTimer;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.util.Random;
import electroblob.wizardry.EnumParticleType;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.tileentity.TileEntityTimer;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
@Mod.EventBusSubscriber
public class BlockSpectral extends Block implements ITileEntityProvider {
// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on block break.
public class BlockSpectral extends BlockContainer {
public BlockSpectral(Material material) {
public BlockSpectral(Material material){
super(material);
this.setSoundType(SoundType.GLASS);
}
// Replaces getRenderBlockPass
@Override
public int getRenderBlockPass()
{
return 1;
}
@SideOnly(Side.CLIENT)
public BlockRenderLayer getRenderLayer(){
return BlockRenderLayer.TRANSLUCENT;
}
// See BlockTransportationStone for what all these do
@Override public boolean isFullCube(IBlockState state){ return false; }
@Override public boolean isBlockNormalCube(IBlockState state){ return false; }
@Override public boolean isNormalCube(IBlockState state){ return false; }
@Override public boolean isOpaqueCube(IBlockState state){ return false; }
@Override
public boolean isOpaqueCube()
{
return false;
}
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
for(int i=0; i<2; i++){
ParticleBuilder.create(Type.DUST)
.pos(pos.getX() + random.nextDouble(), pos.getY() + random.nextDouble(), pos.getZ() + random.nextDouble())
.time((int)(16.0D / (Math.random() * 0.8D + 0.2D)))
.clr(0.4f + random.nextFloat() * 0.2f, 0.6f + random.nextFloat() * 0.4f, 0.6f + random.nextFloat() * 0.4f)
.shaded(true).spawn(world);
}
}
// // Overriden to make the block always look full brightness despite not emitting
// // full light.
// @Override
// public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos){
// return 15;
// }
@Override
public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
{
Block block = par1IBlockAccess.getBlock(par2, par3, par4);
return block == this ? false : super.shouldSideBeRendered(par1IBlockAccess, par2, par3, par4, par5);
}
public boolean hasTileEntity(IBlockState state){
return true;
}
@Override
public void randomDisplayTick(World world, int x, int y, int z, Random random){
// Middle of block
Wizardry.proxy.spawnParticle(EnumParticleType.DUST, world, x+random.nextDouble(), y+random.nextDouble(), z+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)),
0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f);
// Top surface
Wizardry.proxy.spawnParticle(EnumParticleType.DUST, world, x+random.nextDouble(), y+1, z+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)),
0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f);
Wizardry.proxy.spawnParticle(EnumParticleType.DUST, world, x+random.nextDouble(), y+1, z+random.nextDouble(), 0, 0, 0, (int)(16.0D / (Math.random() * 0.8D + 0.2D)),
0.4f + random.nextFloat()*0.2f, 0.6f + random.nextFloat()*0.4f, 0.6f + random.nextFloat()*0.4f);
}
// Overriden to make the block always look full brightness despite not emitting full light.
@Override
public int getMixedBrightnessForBlock(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
{
return 15;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
public TileEntity createNewTileEntity(World world, int metadata){
return new TileEntityTimer(1200);
}
/**
* Returns the quantity of items to drop on block destruction.
*/
@Override
public int quantityDropped(Random par1Random)
{
return 0;
}
@Override
public int quantityDropped(Random par1Random){
return 0;
}
@SuppressWarnings("deprecation")
@SideOnly(Side.CLIENT)
@Override
public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos,
EnumFacing side){
IBlockState iblockstate = blockAccess.getBlockState(pos.offset(side));
Block block = iblockstate.getBlock();
return block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side);
}
@SubscribeEvent
public static void onBlockPlaceEvent(BlockEvent.PlaceEvent event){
// Spectral blocks cannot be built on
if(event.getPlacedAgainst() == WizardryBlocks.spectral_block){
event.setCanceled(true);
}
}
}
@@ -1,172 +1,262 @@
package electroblob.wizardry.block;
import java.util.Random;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import electroblob.wizardry.tileentity.TileEntityStatue;
import electroblob.wizardry.util.BlockUtils;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.init.Blocks;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.Facing;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class BlockStatue extends BlockContainer {
import javax.annotation.Nullable;
import java.util.Random;
public class BlockStatue extends Block implements ITileEntityProvider {
private boolean isIce;
public BlockStatue(Material par2Material) {
super(par2Material);
this.isIce = par2Material == Material.ice;
/** The NBT tag name for storing the petrified flag (used for rendering) in the target's tag compound. */
public static final String PETRIFIED_NBT_KEY = "petrified";
/** The NBT tag name for storing the frozen flag (used for rendering) in the target's tag compound. */
public static final String FROZEN_NBT_KEY = "frozen";
public BlockStatue(Material material){
super(material);
this.isIce = material == Material.ICE;
if(this.isIce){
this.slipperiness = 0.98F;
this.setDefaultSlipperiness(0.98f);
this.setSoundType(SoundType.GLASS);
}
}
@Override
public void setBlockBoundsBasedOnState(IBlockAccess world, int x, int y, int z) {
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
// Not a good idea to call getBlockBoundsMinX() or whatever from in here, since this method changes those!
if(!this.isIce){
if(world.getTileEntity(x, y, z) instanceof TileEntityStatue){
if(world.getTileEntity(pos) instanceof TileEntityStatue){
TileEntityStatue statue = (TileEntityStatue)world.getTileEntity(x, y, z);
TileEntityStatue statue = (TileEntityStatue)world.getTileEntity(pos);
if(statue.creature != null){
// Block bounds are set to match the width and height of the entity, clamped to within 1 block.
this.setBlockBounds((float)Math.max(0.5 - statue.creature.width/2, 0), 0,
(float)Math.max(0.5 - statue.creature.width/2, 0),
(float)Math.min(0.5 + statue.creature.width/2, 1),
// This checks if the block is the top one and if so reduces its height so the top lines up with
return new AxisAlignedBB((float)Math.max(0.5 - statue.creature.width / 2, 0), 0,
(float)Math.max(0.5 - statue.creature.width / 2, 0),
(float)Math.min(0.5 + statue.creature.width / 2, 1),
// This checks if the block is the top one and if so reduces its height so the top lines up
// with
// the top of the entity model.
statue.position == statue.parts ? (float)Math.min(statue.creature.height - statue.parts + 1, 1) : 1,
(float)Math.min(0.5 + statue.creature.width/2, 1));
}
}
}
}
@Override
public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) {
if(!this.isIce){
if(world.getTileEntity(x, y, z) instanceof TileEntityStatue){
TileEntityStatue statue = (TileEntityStatue)world.getTileEntity(x, y, z);
if(statue.creature != null){
// Block bounds are set to match the width and height of the entity, clamped to within 1 block.
return AxisAlignedBB.getBoundingBox(x + Math.max(0.5 - statue.creature.width/2, 0),
y, z + Math.max(0.5 - statue.creature.width/2, 0),
x + Math.min(0.5 + statue.creature.width/2, 1),
// This checks if the block is the top one and if so reduces its height so the top lines up with
// the top of the entity model
statue.position == statue.parts ? y + (float)Math.min(statue.creature.height - statue.parts + 1, 1) : y + 1,
z + Math.min(0.5 + statue.creature.width/2, 1));
statue.position == statue.parts
? (float)Math.min(statue.creature.height - statue.parts + 1, 1)
: 1,
(float)Math.min(0.5 + statue.creature.width / 2, 1));
}
}
}
return super.getCollisionBoundingBoxFromPool(world, x, y, z);
return FULL_BLOCK_AABB;
}
// getCollisionBoundingBox eventually calls getBoundingBox anyway, and since I want the collision box and the block
// outline to be the same here, I've removed that getCollisionBoundingBox entirely.
// The number of these methods is quite simply ridiculous. This one seems to be for placement logic and block
// connections (fences, glass panes, etc.)...
@Override
public boolean renderAsNormalBlock(){
public boolean isFullCube(IBlockState state){
return false;
}
// ...this one isn't used much but has something to do with redstone...
@Override
public boolean isBlockNormalCube(IBlockState state){
return false;
}
// ... this one is for most other game logic...
@Override
public boolean isNormalCube(IBlockState state){
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.
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean canRenderInPass(int pass){
return this.isIce ? super.canRenderInPass(pass) : false;
public BlockRenderLayer getRenderLayer(){
return this.isIce ? BlockRenderLayer.TRANSLUCENT : BlockRenderLayer.SOLID;
}
@Override
public boolean isOpaqueCube(){
return false;// !this.isIce;
public EnumBlockRenderType getRenderType(IBlockState state){
return this.isIce ? EnumBlockRenderType.MODEL : EnumBlockRenderType.ENTITYBLOCK_ANIMATED;
}
@Override
public int getRenderBlockPass()
{
return this.isIce? 1 : 0;
public boolean hasTileEntity(IBlockState state){
return true;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
public TileEntity createNewTileEntity(World world, int metadata){
return new TileEntityStatue(this.isIce);
}
/*
@Override
public void randomDisplayTick(World world, int x, int y, int z, Random random){
if(this.isIce){
float brightness = 0.5f + (random.nextFloat()/2);
Minecraft.getMinecraft().effectRenderer.addEffect(new EntitySparkleFX(world, x + random.nextDouble(), y + random.nextDouble(), z + random.nextDouble(), 0, 0, 0, null, brightness, brightness + 0.1f, 1.0f, true));
}
}
*/
/**
* Returns the quantity of items to drop on block destruction.
*/
@Override
public int quantityDropped(Random par1Random)
{
public int quantityDropped(Random random){
return 0;
}
/**
* Returns true if the given side of this block type should be rendered, if the adjacent block is at the given
* coordinates. Args: blockAccess, x, y, z, side
*/
@Override
@SideOnly(Side.CLIENT)
public boolean shouldSideBeRendered(IBlockAccess p_149646_1_, int p_149646_2_, int p_149646_3_, int p_149646_4_, int p_149646_5_)
{
Block block = p_149646_1_.getBlock(p_149646_2_, p_149646_3_, p_149646_4_);
public void breakBlock(World world, BlockPos pos, IBlockState state){
return block == this ? false : super.shouldSideBeRendered(p_149646_1_, p_149646_2_, p_149646_3_, p_149646_4_, p_149646_5_);
}
if(!world.isRemote){
TileEntityStatue tileentity = (TileEntityStatue)world.getTileEntity(pos);
@Override
public void breakBlock(World par1World, int x, int y, int z, Block block, int par6)
{
if(!par1World.isRemote){
TileEntityStatue tileentity = (TileEntityStatue)par1World.getTileEntity(x, y, z);
if(tileentity != null){
if(tileentity.parts == 2){
if(tileentity.position == 2){
// func_147480_a is the method that causes the block to smash as if broken by a player.
// Used to be called destroyBlock. The boolean is whether the block should drop items.
par1World.func_147480_a(x, y-1, z, false);
world.destroyBlock(pos.down(), false);
}else{
par1World.func_147480_a(x, y+1, z, false);
world.destroyBlock(pos.up(), false);
}
}else if(tileentity.parts == 3){
if(tileentity.position == 3){
par1World.func_147480_a(x, y-1, z, false);
par1World.func_147480_a(x, y-2, z, false);
world.destroyBlock(pos.down(), false);
world.destroyBlock(pos.down(2), false);
}else if(tileentity.position == 2){
par1World.func_147480_a(x, y-1, z, false);
par1World.func_147480_a(x, y+1, z, false);
world.destroyBlock(pos.down(), false);
world.destroyBlock(pos.up(), false);
}else{
par1World.func_147480_a(x, y+1, z, false);
par1World.func_147480_a(x, y+2, z, false);
world.destroyBlock(pos.up(), false);
world.destroyBlock(pos.up(2), false);
}
}
}
// This is only when position == 1 because world.destroyBlock calls this function for the other blocks.
if(tileentity != null && tileentity.position == 1 && tileentity.creature != null){
tileentity.creature.getEntityData().removeTag(BlockStatue.PETRIFIED_NBT_KEY);
tileentity.creature.isDead = false;
par1World.spawnEntityInWorld(tileentity.creature);
world.spawnEntity(tileentity.creature);
}
}
super.breakBlock(par1World, x, y, z, block, par6);
super.breakBlock(world, pos, state);
}
@SuppressWarnings("deprecation")
@SideOnly(Side.CLIENT)
@Override
public boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos,
EnumFacing side){
IBlockState iblockstate = blockAccess.getBlockState(pos.offset(side));
Block block = iblockstate.getBlock();
return this.isIce && block == this ? false : super.shouldSideBeRendered(blockState, blockAccess, pos, side);
}
/**
* Turns the given entity into a statue. The type of statue depends on the block instance this method was invoked on.
* @param target The entity to turn into a statue.
* @param caster The entity that caused it, or null if it was not caused by an entity
* @param duration The time for which the entity should remain a statue. For petrified creatures, this is the minimum
* time it can stay as a statue.
* @return True if the entity was successfully turned into a statue, false if not (i.e. something was in the way).
*/
// Making this an instance method means it works equally well for both types of statue
public boolean convertToStatue(EntityLiving target, @Nullable EntityLivingBase caster, int duration){
if(target.deathTime > 0) return false;
BlockPos pos = new BlockPos(target);
World world = target.world;
target.hurtTime = 0; // Stops the entity looking red while frozen and the resulting z-fighting
target.extinguish();
// Short mobs such as spiders and pigs
if((target.height < 1.2 || target.isChild()) && BlockUtils.canBlockBeReplaced(world, pos) && BlockUtils.canPlaceBlock(caster, world, pos)){
world.setBlockState(pos, this.getDefaultState());
if(world.getTileEntity(pos) instanceof TileEntityStatue){
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 1);
((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration);
}
target.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
target.setDead();
return true;
}
// Normal sized mobs like zombies and skeletons
else if(target.height < 2.5 && BlockUtils.canBlockBeReplaced(world, pos) && BlockUtils.canBlockBeReplaced(world, pos.up())
&& BlockUtils.canPlaceBlock(caster, world, pos) && BlockUtils.canPlaceBlock(caster, world, pos.up())){
world.setBlockState(pos, this.getDefaultState());
if(world.getTileEntity(pos) instanceof TileEntityStatue){
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 2);
((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration);
}
world.setBlockState(pos.up(), this.getDefaultState());
if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){
((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 2);
}
target.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
target.setDead();
return true;
}
// Tall mobs like endermen
else if(BlockUtils.canBlockBeReplaced(world, pos) && BlockUtils.canBlockBeReplaced(world, pos.up()) && BlockUtils.canBlockBeReplaced(world, pos.up(2))
&& BlockUtils.canPlaceBlock(caster, world, pos) && BlockUtils.canPlaceBlock(caster, world, pos.up()) && BlockUtils.canPlaceBlock(caster, world, pos.up(2))){
world.setBlockState(pos, this.getDefaultState());
if(world.getTileEntity(pos) instanceof TileEntityStatue){
((TileEntityStatue)world.getTileEntity(pos)).setCreatureAndPart(target, 1, 3);
((TileEntityStatue)world.getTileEntity(pos)).setLifetime(duration);
}
world.setBlockState(pos.up(), this.getDefaultState());
if(world.getTileEntity(pos.up()) instanceof TileEntityStatue){
((TileEntityStatue)world.getTileEntity(pos.up())).setCreatureAndPart(target, 2, 3);
}
world.setBlockState(pos.up(2), this.getDefaultState());
if(world.getTileEntity(pos.up(2)) instanceof TileEntityStatue){
((TileEntityStatue)world.getTileEntity(pos.up(2))).setCreatureAndPart(target, 3, 3);
}
target.getEntityData().setBoolean(this.isIce ? FROZEN_NBT_KEY : PETRIFIED_NBT_KEY, true);
target.setDead();
return true;
}
return false;
}
}
@@ -0,0 +1,180 @@
package electroblob.wizardry.block;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.TileEntityThorns;
import electroblob.wizardry.util.AllyDesignationSystem;
import electroblob.wizardry.util.EntityUtils;
import electroblob.wizardry.util.MagicDamage;
import net.minecraft.block.*;
import net.minecraft.block.BlockDoublePlant.EnumBlockHalf;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ChunkCache;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.util.Random;
@Mod.EventBusSubscriber
public class BlockThorns extends BlockBush implements ITileEntityProvider {
public static final int GROWTH_STAGES = 8;
public static final int GROWTH_STAGE_DURATION = 2;
public static final PropertyInteger AGE = PropertyInteger.create("age", 0, GROWTH_STAGES-1);
public static final PropertyEnum<EnumBlockHalf> HALF = PropertyEnum.create("half", EnumBlockHalf.class);
public BlockThorns(){
this.setDefaultState(this.blockState.getBaseState().withProperty(HALF, EnumBlockHalf.LOWER).withProperty(AGE, 7));
this.setHardness(4);
this.setSoundType(SoundType.PLANT);
this.setCreativeTab(null);
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return FULL_BLOCK_AABB;
}
@Override
public IBlockState getStateFromMeta(int meta){
return this.getDefaultState().withProperty(HALF, meta == 0 ? EnumBlockHalf.LOWER : EnumBlockHalf.UPPER);
}
@Override
public int getMetaFromState(IBlockState state){
return state.getValue(HALF).ordinal();
}
@Override
public IBlockState getActualState(IBlockState state, IBlockAccess world, BlockPos pos){
if(state.getValue(HALF) == EnumBlockHalf.UPPER) pos = pos.down();
// Copied from BlockFlowerPot on authority of the Forge docs, which say it needs to be here
TileEntity tileentity = world instanceof ChunkCache ? ((ChunkCache)world).getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK) : world.getTileEntity(pos);
if(tileentity instanceof TileEntityThorns){
return state.withProperty(AGE, ((TileEntityThorns)tileentity).getAge());
}else{
return state.withProperty(AGE, 7);
}
}
@Override
protected BlockStateContainer createBlockState(){
return new BlockStateContainer(this, HALF, AGE);
}
public void placeAt(World world, BlockPos lowerPos, int flags){
world.setBlockState(lowerPos, this.getDefaultState().withProperty(HALF, EnumBlockHalf.LOWER).withProperty(AGE, 0), flags);
world.setBlockState(lowerPos.up(), this.getDefaultState().withProperty(HALF, EnumBlockHalf.UPPER).withProperty(AGE, 0), flags);
}
@Override
public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack){
world.setBlockState(pos.up(), this.getDefaultState().withProperty(HALF, EnumBlockHalf.UPPER), 2);
}
@Override
public void breakBlock(World world, BlockPos pos, IBlockState state){
super.breakBlock(world, pos, state);
if(state.getValue(HALF) == EnumBlockHalf.LOWER){
if(world.getBlockState(pos.up()).getBlock() == this){
world.destroyBlock(pos.up(), false);
}
}else{
if(world.getBlockState(pos.down()).getBlock() == this){
world.destroyBlock(pos.down(), false);
}
}
}
public boolean canBlockStay(World worldIn, BlockPos pos, IBlockState state){
if(state.getValue(HALF) == BlockDoublePlant.EnumBlockHalf.UPPER){
return worldIn.getBlockState(pos.down()).getBlock() == this;
}else{
IBlockState iblockstate = worldIn.getBlockState(pos.up());
return iblockstate.getBlock() == this && this.canSustainBush(worldIn.getBlockState(pos.down()));
}
}
@Override
public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){
if(applyThornDamage(world, pos, state, entity)){
entity.setInWeb(); // Needs to be called client-side for players (and besides, all of this is common code)
}
}
private static boolean applyThornDamage(World world, BlockPos pos, IBlockState state, Entity target){
DamageSource source = DamageSource.CACTUS;
float damage = Spells.forest_of_thorns.getProperty(Spell.DAMAGE).floatValue();
TileEntity tileentity = world.getTileEntity(state.getValue(HALF) == EnumBlockHalf.UPPER ? pos.down() : pos);
if(tileentity instanceof TileEntityThorns){
damage *= ((TileEntityThorns)tileentity).damageMultiplier;
EntityLivingBase caster = ((TileEntityThorns)tileentity).getCaster();
if(!AllyDesignationSystem.isValidTarget(caster, target)) return false; // Don't attack or slow allies of the caster
if(caster != null){
source = MagicDamage.causeDirectMagicDamage(caster, MagicDamage.DamageType.MAGIC);
}
}
if(target.ticksExisted % 20 == 0){
EntityUtils.attackEntityWithoutKnockback(target, source, damage);
}
return true;
}
@Override
public Block.EnumOffsetType getOffsetType(){
return Block.EnumOffsetType.XZ;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata){
return new TileEntityThorns();
}
@Override
public boolean hasTileEntity(IBlockState state){
return state.getValue(HALF) == EnumBlockHalf.LOWER;
}
@Override public boolean isReplaceable(IBlockAccess world, BlockPos pos){ return false; }
@Override protected boolean canSustainBush(IBlockState state){ return state.isNormalCube(); }
@Override public Item getItemDropped(IBlockState state, Random rand, int fortune){ return Items.AIR; }
@Override public boolean canSilkHarvest(World world, BlockPos pos, IBlockState state, EntityPlayer player){ return false; }
@SubscribeEvent
public static void onLeftClickBlockEvent(PlayerInteractEvent.LeftClickBlock event){
if(!event.getWorld().isRemote && event.getWorld().getBlockState(event.getPos()).getBlock() == WizardryBlocks.thorns){
applyThornDamage(event.getWorld(), event.getPos(), event.getWorld().getBlockState(event.getPos()), event.getEntity());
}
}
}
@@ -1,149 +1,228 @@
package electroblob.wizardry.block;
import java.util.Random;
import electroblob.wizardry.ExtendedPlayer;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryRegistry;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.spell.Transportation;
import electroblob.wizardry.util.GeometryUtils;
import electroblob.wizardry.util.Location;
import electroblob.wizardry.util.ParticleBuilder;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
public class BlockTransportationStone extends Block{
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class BlockTransportationStone extends Block {
private static final AxisAlignedBB AABB = new AxisAlignedBB(0.0625f * 5, 0, 0.0625f * 5, 0.0625f * 11, 0.0625f * 6,
0.0625f * 11);
public BlockTransportationStone(Material material){
super(material);
this.setBlockBounds(0.0625f*5, 0, 0.0625f*5, 0.0625f*11, 0.0625f*6, 0.0625f*11);
this.setTickRandomly(true);
this.setTickRandomly(true);
}
@Override
public boolean isOpaqueCube(){
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos){
return AABB;
}
// The number of these methods is quite simply ridiculous. This one seems to be for placement logic and block
// connections (fences, glass panes, etc.)...
@Override
public boolean isFullCube(IBlockState state){
return false;
}
// ...this one isn't used much but has something to do with redstone...
@Override
public boolean renderAsNormalBlock(){
public boolean isBlockNormalCube(IBlockState state){
return false;
}
// ... this one is for most other game logic...
@Override
public void onNeighborBlockChange(World world, int x, int y, int z, Block block)
{
super.onNeighborBlockChange(world, x, y, z, block);
if(!world.isSideSolid(x, y-1, z, ForgeDirection.UP)){
this.dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0);
world.setBlockToAir(x, y, z);
}
}
public boolean isNormalCube(IBlockState state){
return false;
}
// ... and this one is for rendering.
@Override
public void updateTick(World world, int x, int y, int z, Random random)
{
if(!world.isSideSolid(x, y-1, z, ForgeDirection.UP)){
this.dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0);
world.setBlockToAir(x, y, z);
}
}
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public boolean canPlaceBlockAt(World par1World, int x, int y, int z)
{
return super.canPlaceBlockAt(par1World, x, y, z) && par1World.isSideSolid(x, y-1, z, ForgeDirection.UP);
}
public boolean isSideSolid(IBlockState base_state, IBlockAccess world, BlockPos pos, EnumFacing side){
return side == EnumFacing.DOWN;
}
@SuppressWarnings("deprecation")
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer entityplayer, int par6, float par7, float par8, float par9)
{
if(entityplayer.getHeldItem() != null && entityplayer.getHeldItem().getItem() instanceof ItemWand){
if(ExtendedPlayer.get(entityplayer) != null){
ExtendedPlayer extendedplayer = ExtendedPlayer.get(entityplayer);
int x1=x-1, z1=z-1;
if(testForCircle(world, x1, y, z1)){
extendedplayer.setStoneLocation(x1, y, z1, world.provider.dimensionId);
if(!world.isRemote) entityplayer.addChatMessage(new ChatComponentTranslation("tile.transportationStone.confirm", WizardryRegistry.transportation.getDisplayNameWithFormatting()));//"You will now be returned here upon casting " + EnumSpell.TRANSPORTATION.name);
return true;
public void neighborChanged(IBlockState state, World world, BlockPos pos, Block block, BlockPos fromPos){
super.neighborChanged(state, world, pos, block, fromPos);
if(!world.isSideSolid(pos.down(), EnumFacing.UP, false)){
this.dropBlockAsItem(world, pos, world.getBlockState(pos), 0);
world.setBlockToAir(pos);
}
}
@Override
public void updateTick(World world, BlockPos pos, IBlockState state, Random random){
if(!world.isSideSolid(pos.down(), EnumFacing.UP)){
this.dropBlockAsItem(world, pos, world.getBlockState(pos), 0);
world.setBlockToAir(pos);
}
}
@Override
public boolean canPlaceBlockAt(World world, BlockPos pos){
return super.canPlaceBlockAt(world, pos) && world.isSideSolid(pos.down(), EnumFacing.UP);
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand,
EnumFacing side, float hitX, float hitY, float hitZ){
ItemStack stack = player.getHeldItem(hand);
if(stack.getItem() instanceof ISpellCastingItem){
if(WizardData.get(player) != null){
WizardData data = WizardData.get(player);
for(int x = -1; x <= 1; x++){
for(int z = -1; z <= 1; z++){
BlockPos pos1 = pos.add(x, 0, z);
if(testForCircle(world, pos1)){
Location here = new Location(pos1, player.dimension);
List<Location> locations = data.getVariable(Transportation.LOCATIONS_KEY);
if(locations == null) data.setVariable(Transportation.LOCATIONS_KEY, locations = new ArrayList<>(Transportation.MAX_REMEMBERED_LOCATIONS));
if(ItemArtefact.isArtefactActive(player, WizardryItems.charm_transportation)){
if(locations.contains(here)){
locations.remove(here);
if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.forget", here.pos.getX(), here.pos.getY(), here.pos.getZ(), here.dimension), true);
}else{
locations.add(here);
if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.remember", here.pos.getX(), here.pos.getY(), here.pos.getZ(), here.dimension), true);
if(locations.size() > Transportation.MAX_REMEMBERED_LOCATIONS){
Location removed = locations.remove(0);
if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.forget", removed.pos.getX(), removed.pos.getY(), removed.pos.getZ(), removed.dimension), true);
}
}
}else{
if(locations.isEmpty()) locations.add(here);
else{
locations.remove(here); // Prevents duplicates
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);
}
return true;
}
}
}
x1=x;
z1=z-1;
if(testForCircle(world, x1, y, z1)){
extendedplayer.setStoneLocation(x1, y, z1, world.provider.dimensionId);
if(!world.isRemote) entityplayer.addChatMessage(new ChatComponentTranslation("tile.transportationStone.confirm", WizardryRegistry.transportation.getDisplayNameWithFormatting()));//"You will now be returned here upon casting " + EnumSpell.TRANSPORTATION.name);
return true;
if(!world.isRemote){
player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.invalid"), true);
}else{
BlockPos centre = findMostLikelyCircle(world, pos);
// Displays particles in the required shape
for(int x = -1; x <= 1; x++){
for(int z = -1; z <= 1; z++){
if(x == 0 && z == 0) continue;
ParticleBuilder.create(ParticleBuilder.Type.PATH)
.pos(GeometryUtils.getCentre(centre).add(x, -0.3125, z)).clr(0x86ff65)
.time(200).scale(2).spawn(world);
}
}
}
x1=x+1;
z1=z-1;
if(testForCircle(world, x1, y, z1)){
extendedplayer.setStoneLocation(x1, y, z1, world.provider.dimensionId);
if(!world.isRemote) entityplayer.addChatMessage(new ChatComponentTranslation("tile.transportationStone.confirm", WizardryRegistry.transportation.getDisplayNameWithFormatting()));//"You will now be returned here upon casting " + EnumSpell.TRANSPORTATION.name);
return true;
}
x1=x-1;
z1=z;
if(testForCircle(world, x1, y, z1)){
extendedplayer.setStoneLocation(x1, y, z1, world.provider.dimensionId);
if(!world.isRemote) entityplayer.addChatMessage(new ChatComponentTranslation("tile.transportationStone.confirm", WizardryRegistry.transportation.getDisplayNameWithFormatting()));//"You will now be returned here upon casting " + EnumSpell.TRANSPORTATION.name);
return true;
}
x1=x+1;
z1=z;
if(testForCircle(world, x1, y, z1)){
extendedplayer.setStoneLocation(x1, y, z1, world.provider.dimensionId);
if(!world.isRemote) entityplayer.addChatMessage(new ChatComponentTranslation("tile.transportationStone.confirm", WizardryRegistry.transportation.getDisplayNameWithFormatting()));//"You will now be returned here upon casting " + EnumSpell.TRANSPORTATION.name);
return true;
}
x1=x-1;
z1=z+1;
if(testForCircle(world, x1, y, z1)){
extendedplayer.setStoneLocation(x1, y, z1, world.provider.dimensionId);
if(!world.isRemote) entityplayer.addChatMessage(new ChatComponentTranslation("tile.transportationStone.confirm", WizardryRegistry.transportation.getDisplayNameWithFormatting()));//"You will now be returned here upon casting " + EnumSpell.TRANSPORTATION.name);
return true;
}
x1=x;
z1=z+1;
if(testForCircle(world, x1, y, z1)){
extendedplayer.setStoneLocation(x1, y, z1, world.provider.dimensionId);
if(!world.isRemote) entityplayer.addChatMessage(new ChatComponentTranslation("tile.transportationStone.confirm", WizardryRegistry.transportation.getDisplayNameWithFormatting()));//"You will now be returned here upon casting " + EnumSpell.TRANSPORTATION.name);
return true;
}
x1=x+1;
z1=z+1;
if(testForCircle(world, x1, y, z1)){
extendedplayer.setStoneLocation(x1, y, z1, world.provider.dimensionId);
if(!world.isRemote) entityplayer.addChatMessage(new ChatComponentTranslation("tile.transportationStone.confirm", WizardryRegistry.transportation.getDisplayNameWithFormatting()));//"You will now be returned here upon casting " + EnumSpell.TRANSPORTATION.name);
return true;
}
if(!world.isRemote) entityplayer.addChatMessage(new ChatComponentTranslation("tile.transportationStone.invalid"));//"You must make a circle with 8 stones of transportation first!");
return true;
}
}
return false;
}
/** Returns whether the specified location is surrounded by a complete cicle of 8 transportation stones. */
public static boolean testForCircle(World world, int x, int y, int z){
return world.getBlock(x-1, y, z-1) == Wizardry.transportationStone
&& world.getBlock(x, y, z-1) == Wizardry.transportationStone
&& world.getBlock(x+1, y, z-1) == Wizardry.transportationStone
&& world.getBlock(x-1, y, z) == Wizardry.transportationStone
&& !world.getBlock(x, y, z).getMaterial().blocksMovement()
&& world.getBlock(x+1, y, z) == Wizardry.transportationStone
&& world.getBlock(x-1, y, z+1) == Wizardry.transportationStone
&& world.getBlock(x, y, z+1) == Wizardry.transportationStone
&& world.getBlock(x+1, y, z+1) == Wizardry.transportationStone;
return false;
}
/** Returns whether the specified location is surrounded by a complete circle of 8 transportation stones. */
public static boolean testForCircle(World world, BlockPos pos){
if(world.getBlockState(pos).getMaterial().blocksMovement() || world.getBlockState(pos.up()).getMaterial()
.blocksMovement()) return false;
for(int x = -1; x <= 1; x++){
for(int z = -1; z <= 1; z++){
if(x == 0 && z == 0) continue;
if(world.getBlockState(pos.add(x, 0, z)).getBlock() != WizardryBlocks.transportation_stone){
return false;
}
}
}
return true;
}
private static BlockPos findMostLikelyCircle(World world, BlockPos pos){
int bestSoFar = 0;
BlockPos result = null;
for(int x = -1; x <= 1; x++){
for(int z = -1; z <= 1; z++){
if(x == 0 && z == 0) continue;
BlockPos pos1 = pos.add(x, 0, z);
int n = getCircleCompleteness(world, pos1);
if(n > bestSoFar){
bestSoFar = n;
result = pos1;
}
}
}
return result;
}
private static int getCircleCompleteness(World world, BlockPos pos){
int n = 0;
for(int x = -1; x <= 1; x++){
for(int z = -1; z <= 1; z++){
if(x == 0 && z == 0) continue;
if(world.getBlockState(pos.add(x, 0, z)).getBlock() == WizardryBlocks.transportation_stone) n++;
}
}
return n;
}
}
@@ -1,61 +1,73 @@
package electroblob.wizardry.block;
import electroblob.wizardry.tileentity.TileEntityTimer;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.EnumBlockRenderType;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.util.Random;
import electroblob.wizardry.EnumParticleType;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.tileentity.TileEntityTimer;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
public class BlockVanishingCobweb extends Block implements ITileEntityProvider {
// For future reference - extend BlockContainer whenever possible because it has methods for removing tile entities on block break.
public class BlockVanishingCobweb extends BlockContainer {
public BlockVanishingCobweb(Material material) {
public BlockVanishingCobweb(Material material){
super(material);
}
@SideOnly(Side.CLIENT)
@Override
public int getRenderType()
{
return 1;
}
public BlockRenderLayer getRenderLayer(){
return BlockRenderLayer.CUTOUT;
}
@Override
public boolean isOpaqueCube()
{
return false;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata) {
public EnumBlockRenderType getRenderType(IBlockState state){
return EnumBlockRenderType.MODEL;
}
@Override
public boolean isOpaqueCube(IBlockState state){
return false;
}
@Override
public AxisAlignedBB getCollisionBoundingBox(IBlockState state, IBlockAccess world, BlockPos pos){
return NULL_AABB;
}
@Override
public boolean isFullCube(IBlockState state){
return false;
}
@Override
public boolean hasTileEntity(IBlockState state){
return true;
}
@Override
public TileEntity createNewTileEntity(World world, int metadata){
return new TileEntityTimer(400);
}
@Override
public void onEntityCollidedWithBlock(World world, int x, int y, int z, Entity entity)
{
entity.setInWeb();
}
@Override
public AxisAlignedBB getCollisionBoundingBoxFromPool(World p_149668_1_, int p_149668_2_, int p_149668_3_, int p_149668_4_) {
return null;
}
/**
* Returns the quantity of items to drop on block destruction.
*/
@Override
public int quantityDropped(Random par1Random)
{
return 0;
}
@Override
public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){
entity.setInWeb();
}
@Override
public int quantityDropped(Random par1Random){
return 0;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,304 @@
package electroblob.wizardry.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.*;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.MathHelper;
import org.lwjgl.opengl.GL11;
import java.util.Random;
/**
* Utility class containing some useful static methods for drawing GUIs, as well as general rendering.
*
* @author Electroblob
* @since Wizardry 4.2
* @see MixedFontRenderer
*/
//@SideOnly(Side.CLIENT)
public final class DrawingUtils {
/**
* The integer colour for black passed into the font renderer methods. This used to be 0 but that's now white for
* some reason, so I've made a it a constant in case it changes again.
*/
// I think this is actually ever-so-slightly lighter than pure black, but the difference is unnoticeable.
public static final int BLACK = 1;
/**
* Shorthand for {@link DrawingUtils#drawTexturedRect(int, int, int, int, int, int, int, int)} which draws the
* entire texture (u and v are set to 0 and textureWidth and textureHeight are the same as width and height).
*/
public static void drawTexturedRect(int x, int y, int width, int height){
drawTexturedRect(x, y, 0, 0, width, height, width, height);
}
/**
* Draws a textured rectangle, taking the size of the image and the bit needed into
* account, unlike {@link net.minecraft.client.gui.Gui#drawTexturedModalRect(int, int, int, int, int, int)
* Gui.drawTexturedModalRect(int, int, int, int, int, int)}, which is harcoded for only 256x256 textures. Also handy
* for custom potion icons.
*
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted
* @param v The y position of the top left corner of the section of the image wanted
* @param width The width of the section
* @param height The height of the section
* @param textureWidth The width of the actual image.
* @param textureHeight The height of the actual image.
*/
public static void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight){
DrawingUtils.drawTexturedFlippedRect(x, y, u, v, width, height, textureWidth, textureHeight, false, false);
}
/**
* Draws a textured rectangle, taking the size of the image and the bit needed into
* account, unlike {@link net.minecraft.client.gui.Gui#drawTexturedModalRect(int, int, int, int, int, int)
* Gui.drawTexturedModalRect(int, int, int, int, int, int)}, which is harcoded for only 256x256 textures. Also handy
* for custom potion icons. This version allows the texture to additionally be flipped in x and/or y.
*
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted
* @param v The y position of the top left corner of the section of the image wanted
* @param width The width of the section
* @param height The height of the section
* @param textureWidth The width of the actual image.
* @param textureHeight The height of the actual image.
* @param flipX Whether to flip the texture in the x direction.
* @param flipY Whether to flip the texture in the y direction.
*/
public static void drawTexturedFlippedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, boolean flipX, boolean flipY){
float f = 1F / (float)textureWidth;
float f1 = 1F / (float)textureHeight;
int u1 = flipX ? u + width : u;
int u2 = flipX ? u : u + width;
int v1 = flipY ? v + height : v;
int v2 = flipY ? v : v + height;
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin(org.lwjgl.opengl.GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.POSITION_TEX);
buffer.pos((double)(x), (double)(y + height), 0).tex((double)((float)(u1) * f), (double)((float)(v2) * f1)).endVertex();
buffer.pos((double)(x + width), (double)(y + height), 0).tex((double)((float)(u2) * f), (double)((float)(v2) * f1)).endVertex();
buffer.pos((double)(x + width), (double)(y), 0).tex((double)((float)(u2) * f), (double)((float)(v1) * f1)).endVertex();
buffer.pos((double)(x), (double)(y), 0).tex((double)((float)(u1) * f), (double)((float)(v1) * f1)).endVertex();
tessellator.draw();
}
/**
* Draws a textured rectangle, stretching the section of the image to fit the size given.
*
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted, expressed as a fraction of the
* image width
* @param v The y position of the top left corner of the section of the image wanted, expressed as a fraction of the
* image width
* @param finalWidth The width as rendered
* @param finalHeight The height as rendered
* @param width The width of the section, expressed as a fraction of the image width
* @param height The height of the section, expressed as a fraction of the image width
*/
public static void drawTexturedStretchedRect(int x, int y, int u, int v, int finalWidth, int finalHeight, int width,
int height){
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos((x), y + finalHeight, 0).tex(u, v + height).endVertex();
buffer.pos(x + finalWidth, y + finalHeight, 0).tex(u + width, v + height).endVertex();
buffer.pos(x + finalWidth, (y), 0).tex(u + width, v).endVertex();
buffer.pos((x), (y), 0).tex(u, v).endVertex();
tessellator.draw();
}
/**
* Draws a 'glitch' rectangle, with some rows of pixels shifted randomly to give a broken effect.
*
* @param random A random number generator to use
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted
* @param v The y position of the top left corner of the section of the image wanted
* @param width The width of the section
* @param height The height of the section
* @param textureWidth The width of the actual image.
* @param textureHeight The height of the actual image.
* @param flipX Whether to flip the texture in the x direction.
* @param flipY Whether to flip the texture in the y direction.
*/
public static void drawGlitchRect(Random random, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight, boolean flipX, boolean flipY){
for(int i=0; i<height; i++){
if(flipY) i = height - i - 1;
int offset = random.nextInt(4) == 0 ? random.nextInt(6) - 3 : 0;
drawTexturedFlippedRect(x + offset, y + i, u, v + i, width, 1, textureWidth, textureHeight, flipX, flipY);
}
}
/**
* Mixes the two given opaque colours in the proportion specified.
* @param colour1 The first colour to mix, as a 6-digit hexadecimal.
* @param colour2 The second colour to mix, as a 6-digit hexadecimal.
* @param proportion The proportion of the second colour; will be clamped to between 0 and 1.
* @return The resulting colour, as a 6-digit hexadecimal.
*/
public static int mix(int colour1, int colour2, float proportion){
proportion = MathHelper.clamp(proportion, 0, 1);
int r1 = colour1 >> 16 & 255;
int g1 = colour1 >> 8 & 255;
int b1 = colour1 & 255;
int r2 = colour2 >> 16 & 255;
int g2 = colour2 >> 8 & 255;
int b2 = colour2 & 255;
int r = (int)(r1 + (r2-r1) * proportion);
int g = (int)(g1 + (g2-g1) * proportion);
int b = (int)(b1 + (b2-b1) * proportion);
return (r << 16) + (g << 8) + b;
}
/**
* Makes the given opaque colour translucent with the given opacity.
* @param colour An integer colour code, should be a 6-digit hexadecimal (i.e. opaque).
* @param opacity The opacity to apply to the given colour, as a fraction between 0 and 1.
* @return The resulting integer colour code, which will be an 8-digit hexadecimal.
*/
public static int makeTranslucent(int colour, float opacity){
return colour + ((int)(opacity * 0xff) << 24);
}
/**
* Draws the given string at the given position, scaling it if it does not fit within the given width.
* @param font A {@code FontRenderer} object.
* @param text The text to display.
* @param x The x position of the top-left corner of the text.
* @param y The y position of the top-left corner of the text.
* @param scale The scale that the text should normally be if it does not exceed the maximum width.
* @param colour The colour to render the text in, supports translucency.
* @param width The maximum width of the text. <i>This is not scaled; you should pass in the width of the actual
* area of the screen in which the text needs to fit, regardless of the scale parameter.</i>
* @param centre Whether to adjust the y position such that the centre of the text lines up with where its centre
* would be if it was not scaled (automatically or manually).
* @param alignR True to right-align the text, false for normal left alignment.
*/
public static void drawScaledStringToWidth(FontRenderer font, String text, float x, float y, float scale, int colour, float width, boolean centre, boolean alignR){
float textWidth = font.getStringWidth(text) * scale;
float textHeight = font.FONT_HEIGHT * scale;
if(textWidth > width){
scale *= width/textWidth;
}else if(alignR){ // Alignment makes no difference if the string fills the entire width
x += width - textWidth;
}
if(centre) y += (font.FONT_HEIGHT - textHeight)/2;
DrawingUtils.drawScaledTranslucentString(font, text, x, y, scale, colour);
}
/** Draws the given string at the given position, scaling the text by the specified factor. Also enables blending to
* render text in semitransparent colours (e.g. 0x88ffffff). */
public static void drawScaledTranslucentString(FontRenderer font, String text, float x, float y, float scale, int colour){
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.scale(scale, scale, scale);
// Because we scaled the entire rendering space, the coordinates have to be scaled inversely
x /= scale;
y /= scale;
font.drawStringWithShadow(text, x, y, colour);
GlStateManager.disableBlend();
GlStateManager.popMatrix();
}
/**
* Draws an itemstack and (optionally) its tooltip, directly. Mainly intended for use outside of GUI classes, since
* most of the GL state changes done in this method (which are the main reason it exists at all) are already done
* when drawing a GUI.
*
* @param gui An instance of a GUI class.
* @param stack The itemstack to draw.
* @param x The x position of the left-hand edge of the itemstack.
* @param y The y position of the top edge of the itemstack.
* @param mouseX The x position of the mouse, used for tooltip positioning.
* @param mouseY The y position of the mouse, used for tooltip positioning.
* @param tooltip Whether to draw the tooltip.
*/
public static void drawItemAndTooltip(GuiContainer gui, ItemStack stack, int x, int y, int mouseX, int mouseY, boolean tooltip){
RenderItem renderItem = Minecraft.getMinecraft().getRenderItem();
GlStateManager.pushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GlStateManager.disableLighting();
GlStateManager.enableRescaleNormal();
GlStateManager.enableColorMaterial();
GlStateManager.enableLighting();
renderItem.zLevel = 100.0F;
if(!stack.isEmpty()){
renderItem.renderItemAndEffectIntoGUI(stack, x, y);
renderItem.renderItemOverlays(Minecraft.getMinecraft().fontRenderer, stack, x, y);
if(tooltip){
gui.drawHoveringText(gui.getItemToolTip(stack), mouseX + gui.getXSize()/2 - gui.width/2,
mouseY + gui.getYSize()/2 - gui.height/2);
}
}
GlStateManager.popMatrix();
GlStateManager.enableLighting();
GlStateManager.enableDepth();
RenderHelper.enableStandardItemLighting();
}
/**
* Calculates a factor between 0 and 1 that results in a smooth, aesthetically-pleasing animation when used to scale
* things. Mainly for rendering, but can be used anywhere since it's just a mathematical formula.
* @param lifetime The lifetime of the thing being animated, in ticks (if this is negative, disappearing is ignored)
* @param ticksExisted The current age of the thing being animated, in ticks
* @param partialTicks The current partial tick time
* @param startLength The length of the appearing animation, in ticks
* @param endLength The length of the disappearing animation, in ticks
* @return A fraction between 0 and 1, with the value at the very start and end being 0 and the constant middle
* section having a value of 1.
*/
public static float smoothScaleFactor(int lifetime, int ticksExisted, float partialTicks, int startLength, int endLength){
float age = ticksExisted + partialTicks;
float s = MathHelper.clamp(age < startLength || lifetime < 0 ? age/startLength : (lifetime - age) / endLength, 0, 1);
s = (float)Math.pow(s, 0.4); // Smooths the animation
return s;
}
/**
* Tests if the point with the given coordinates lies within the rectangle specified. The check is identical to
* {@link GuiContainer#isPointInRegion(int, int, int, int, int, int)}, but without the adjustment relative to the GUI.
* @param left The minimum x coordinate of the rectangle
* @param top The minimum y coordinate of the rectangle
* @param width The width of the rectangle
* @param height The height of the rectangle
* @param x The x coordinate of the point to test
* @param y The y coordinate of the point to test
* @return True if the given point is in the rectangle, false otherwise
*/
public static boolean isPointInRegion(int left, int top, int width, int height, int x, int y){
return x >= left - 1 && x < left + width + 1 && y >= top - 1 && y < top + height + 1;
}
}
@@ -1,77 +0,0 @@
package electroblob.wizardry.client;
import cpw.mods.fml.client.config.GuiButtonExt;
import cpw.mods.fml.client.config.GuiEditArray;
import cpw.mods.fml.client.config.GuiEditArrayEntries;
import cpw.mods.fml.client.config.GuiSelectString;
import cpw.mods.fml.client.config.GuiUtils;
import cpw.mods.fml.client.config.GuiEditArrayEntries.StringEntry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.EntityList;
import cpw.mods.fml.client.config.IConfigElement;
public class EntityNameEntry extends StringEntry {
protected final GuiButtonExt btnValue;
protected Object entityClass;
public EntityNameEntry(GuiEditArray owningScreen, GuiEditArrayEntries owningEntryList, IConfigElement configElement, Object value)
{
super(owningScreen, owningEntryList, configElement, value);
this.btnValue = new GuiButtonExt(0, 0, 0, owningEntryList.controlWidth, 18, I18n.format(this.textFieldValue.getText()));
//this.btnValue.enabled = owningScreen.enabled;
}
@Override
public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, Tessellator tessellator, int mouseX, int mouseY, boolean isSelected)
{
//super.drawEntry(slotIndex, x, y, listWidth, slotHeight, tessellator, mouseX, mouseY, isSelected);
this.btnValue.xPosition = listWidth / 4;
this.btnValue.yPosition = y;
String trans = I18n.format(this.textFieldValue.getText());
if (!trans.equals(this.textFieldValue.getText()))
this.btnValue.displayString = trans;
else
this.btnValue.displayString = this.textFieldValue.getText();
//btnValue.packedFGColour = value ? GuiUtils.getColorCode('2', true) : GuiUtils.getColorCode('4', true);
this.btnValue.drawButton(owningEntryList.mc, mouseX, mouseY);
}
/**
* Returns true if the mouse has been pressed on this control.
*/
@Override
public boolean mousePressed(int index, int x, int y, int mouseEvent, int relativeX, int relativeY)
{
if (this.btnValue.mousePressed(owningEntryList.mc, x, y))
{
btnValue.func_146113_a(owningEntryList.mc.getSoundHandler());
Minecraft.getMinecraft().displayGuiScreen(new GuiSelectString(this.owningScreen, configElement, index, EntityList.classToStringMapping, this.getValue(), true));
owningEntryList.recalculateState();
return true;
}
return super.mousePressed(index, x, y, mouseEvent, relativeX, relativeY);
}
/**
* Fired when the mouse button is released. Arguments: index, x, y, mouseEvent, relativeX, relativeY
*/
@Override
public void mouseReleased(int index, int x, int y, int mouseEvent, int relativeX, int relativeY)
{
this.btnValue.mouseReleased(x, y);
super.mouseReleased(index, x, y, mouseEvent, relativeX, relativeY);
}
@Override
public Object getValue()
{
return this.textFieldValue.getText();
}
}
@@ -1,364 +0,0 @@
package electroblob.wizardry.client;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import electroblob.wizardry.ExtendedPlayer;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WandHelper;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
import electroblob.wizardry.tileentity.SlotWizardry;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
public class GuiArcaneWorkbench extends GuiContainer {
private GuiButton applyBtn;
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png");
private IInventory playerInventory;
private IInventory arcaneWorkbenchInventory;
private final int tooltipWidth = 164;
public GuiArcaneWorkbench(InventoryPlayer invPlayer, TileEntityArcaneWorkbench entity) {
super(new ContainerArcaneWorkbench(invPlayer, entity));
this.playerInventory = invPlayer;
this.arcaneWorkbenchInventory = entity;
xSize = 176;
ySize = 220;
}
@Override
public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_){
// Tests if there is a wand in the workbench and edits the positioning accordingly
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){
guiLeft = (this.width - this.xSize - tooltipWidth)/2;
this.applyBtn.xPosition = (this.width - tooltipWidth)/2 + 48;
}else{
guiLeft = (this.width - this.xSize)/2;
this.applyBtn.xPosition = this.width/2 + 48;
}
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack()){
this.applyBtn.enabled = true;
}else{
this.applyBtn.enabled = false;
}
super.drawScreen(p_73863_1_, p_73863_2_, p_73863_3_);
}
/**
* Draw the foreground layer for the GuiContainer (everything in front of the items)
*/
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){
this.fontRendererObj.drawString(this.arcaneWorkbenchInventory.hasCustomInventoryName() ? this.arcaneWorkbenchInventory.getInventoryName() : I18n.format(this.arcaneWorkbenchInventory.getInventoryName()), 8, 6, 4210752);
this.fontRendererObj.drawString(this.playerInventory.hasCustomInventoryName() ? this.playerInventory.getInventoryName() : I18n.format(this.playerInventory.getInventoryName()), 8, this.ySize - 96 + 2, 4210752);
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){
ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack();
this.fontRendererObj.drawStringWithShadow("\u00A7f" + wand.getDisplayName(), xSize + 6, 6, 0);
this.fontRendererObj.drawStringWithShadow("\u00A77" + StatCollector.translateToLocal("container.arcaneWorkbench.mana") + " " + (wand.getMaxDamage() - wand.getItemDamage()) + "/" + wand.getMaxDamage(), xSize + 6, 20, 0);
Spell[] spells = WandHelper.getSpells(wand);
int y = 34;
for(Spell spell : spells){
boolean discovered = true;
if(!this.mc.thePlayer.capabilities.isCreativeMode && ExtendedPlayer.get(this.mc.thePlayer) != null){
discovered = ExtendedPlayer.get(this.mc.thePlayer).hasSpellBeenDiscovered(spell);
}
if(discovered){
this.fontRendererObj.drawStringWithShadow(spell.getDisplayNameWithFormatting(), xSize + 16, y, 0);
}else{
this.mc.standardGalacticFontRenderer.drawStringWithShadow("\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.theWorld), xSize + 16, y, 0);
}
y += 10;
}
if(WandHelper.getTotalUpgrades(wand) > 0){
this.fontRendererObj.drawStringWithShadow("\u00A7f" + StatCollector.translateToLocal("container.arcaneWorkbench.upgrades"), xSize + 6, y + 6, 0);
int x = 0;
y = guiTop + 50 + spells.length*10;
// Wand upgrade tooltips
for(Item item : WandHelper.getSpecialUpgrades()){
int level = WandHelper.getUpgradeLevel(wand, item);
if(level > 0){
// No idea why this is -16 instead of +6, but it works!
if(isPointInRegion(xSize -16 + x, y, 16, 16, mouseX + guiLeft, mouseY + guiTop)){
ItemStack stack = new ItemStack(item, level);
this.drawItemStackTooltip(stack, mouseX - guiLeft, mouseY - guiTop);
}
x += 18;
}
}
}
}
}
@Override
public void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
GL11.glColor4f(1F, 1F, 1F, 1F);
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
// Main inventory
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize);
// Changing slots
for(int i=0; i<ContainerArcaneWorkbench.CRYSTAL_SLOT; i++){
Slot slot = this.inventorySlots.getSlot(i);
if(slot.xDisplayPosition >=0 && slot.yDisplayPosition >= 0)
this.drawTexturedModalRect(guiLeft + slot.xDisplayPosition - 10, guiTop + slot.yDisplayPosition - 10,
64, 220, 36, 36);
}
// Tooltip only drawn if there is a wand
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getHasStack() && this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack().getItem() instanceof ItemWand){
// Tooltip box
drawTexturedModalRect(guiLeft + xSize, guiTop, xSize, 0, 256 - xSize - 4, ySize);
drawTexturedModalRect(guiLeft + 252, guiTop, xSize + 4, 0, tooltipWidth - 2*(256 - xSize - 4), ySize);
drawTexturedModalRect(guiLeft + xSize + tooltipWidth - (256 - xSize - 4), guiTop, xSize + 4, 0, 256 - xSize - 4, ySize);
ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.WAND_SLOT).getStack();
Spell[] spells = WandHelper.getSpells(wand);
int i=0;
for(Spell spell : spells){
boolean discovered = true;
if(!this.mc.thePlayer.capabilities.isCreativeMode && ExtendedPlayer.get(this.mc.thePlayer) != null){
discovered = ExtendedPlayer.get(this.mc.thePlayer).hasSpellBeenDiscovered(spell);
}
// Renders the little element icon if there is an element
this.drawTexturedModalRect(guiLeft + xSize + 5, guiTop + 34 + 10*i++, discovered ? spell.element.ordinal()*8 : 0, 220, 8, 8);
}
int x = 0;
int y = guiTop + 50 + spells.length*10;
// Look how much shorter this is with the WandHelper class!
for(Item item : WandHelper.getSpecialUpgrades()){
int level = WandHelper.getUpgradeLevel(wand, item);
if(level > 0){
ItemStack stack = new ItemStack(item, level);
this.itemRender.renderItemAndEffectIntoGUI(this.fontRendererObj, this.mc.getTextureManager(), stack, guiLeft + xSize + 6 + x, y);
this.itemRender.renderItemOverlayIntoGUI(this.fontRendererObj, this.mc.getTextureManager(), stack, guiLeft + xSize + 6 + x, y);
x += 18;
}
}
}
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
for(Object object : this.inventorySlots.inventorySlots){
if(object instanceof Slot){
Slot slot = (Slot)object;
// Tests whether I have added a background texture and if so actually renders it
if(!slot.getHasStack() && slot instanceof SlotWizardry && ((SlotWizardry)slot).backgroundIndex > -1){
// Taken directly from GuiContainer#func_146977_a, with a few changes.
this.zLevel = 100.0F;
itemRender.zLevel = 100.0F;
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_BLEND);
this.drawTexturedModalRect(guiLeft + slot.xDisplayPosition, guiTop + slot.yDisplayPosition, ((SlotWizardry)slot).backgroundIndex*16, 240, 16, 16);
GL11.glDisable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_LIGHTING);
itemRender.zLevel = 0.0F;
this.zLevel = 0.0F;
}
}
}
}
public void initGui()
{
this.mc.thePlayer.openContainer = this.inventorySlots;
this.guiLeft = (this.width - this.xSize) / 2;
this.guiTop = (this.height - this.ySize) / 2;
Keyboard.enableRepeatEvents(true);
this.buttonList.clear();
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width/2 + 48, this.height/2 + 3));
}
public void onGuiClosed()
{
super.onGuiClosed();
Keyboard.enableRepeatEvents(false);
}
/**
* Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e).
*/
protected void actionPerformed(GuiButton par1GuiButton)
{
if (par1GuiButton.enabled)
{
if (par1GuiButton.id == 0)
{
// Packet building
IMessage msg = new PacketControlInput.Message(0);
WizardryPacketHandler.net.sendToServer(msg);
}
}
}
protected boolean isPointInRegion(int par1, int par2, int par3, int par4, int par5, int par6)
{
int k1 = this.width/2 - xSize/2;
int l1 = this.height/2 - this.ySize/2;
par5 -= k1;
par6 -= l1;
return par5 >= par1 - 1 && par5 < par1 + par3 + 1 && par6 >= par2 - 1 && par6 < par2 + par4 + 1;
}
protected void drawItemStackTooltip(ItemStack par1ItemStack, int par2, int par3)
{
List list = par1ItemStack.getTooltip(this.mc.thePlayer, this.mc.gameSettings.advancedItemTooltips);
for (int k = 0; k < list.size(); ++k)
{
if (k == 0)
{
list.set(k, par1ItemStack.getRarity().rarityColor + (String)list.get(k));
}
else
{
list.set(k, EnumChatFormatting.GRAY + (String)list.get(k));
}
}
FontRenderer font = par1ItemStack.getItem().getFontRenderer(par1ItemStack);
drawHoveringText(list, par2, par3, (font == null ? fontRendererObj : font));
}
protected void drawHoveringText(List par1List, int par2, int par3, FontRenderer font)
{
if (!par1List.isEmpty())
{
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
RenderHelper.disableStandardItemLighting();
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_DEPTH_TEST);
int k = 0;
Iterator iterator = par1List.iterator();
while (iterator.hasNext())
{
String s = (String)iterator.next();
int l = font.getStringWidth(s);
if (l > k)
{
k = l;
}
}
int i1 = par2 + 12;
int j1 = par3 - 12;
int k1 = 8;
if (par1List.size() > 1)
{
k1 += 2 + (par1List.size() - 1) * 10;
}
if (i1 + k > this.width)
{
i1 -= 28 + k;
}
if (j1 + k1 + 6 > this.height)
{
j1 = this.height - k1 - 6;
}
this.zLevel = 300.0F;
itemRender.zLevel = 300.0F;
int l1 = -267386864;
this.drawGradientRect(i1 - 3, j1 - 4, i1 + k + 3, j1 - 3, l1, l1);
this.drawGradientRect(i1 - 3, j1 + k1 + 3, i1 + k + 3, j1 + k1 + 4, l1, l1);
this.drawGradientRect(i1 - 3, j1 - 3, i1 + k + 3, j1 + k1 + 3, l1, l1);
this.drawGradientRect(i1 - 4, j1 - 3, i1 - 3, j1 + k1 + 3, l1, l1);
this.drawGradientRect(i1 + k + 3, j1 - 3, i1 + k + 4, j1 + k1 + 3, l1, l1);
int i2 = 1347420415;
int j2 = (i2 & 16711422) >> 1 | i2 & -16777216;
this.drawGradientRect(i1 - 3, j1 - 3 + 1, i1 - 3 + 1, j1 + k1 + 3 - 1, i2, j2);
this.drawGradientRect(i1 + k + 2, j1 - 3 + 1, i1 + k + 3, j1 + k1 + 3 - 1, i2, j2);
this.drawGradientRect(i1 - 3, j1 - 3, i1 + k + 3, j1 - 3 + 1, i2, i2);
this.drawGradientRect(i1 - 3, j1 + k1 + 2, i1 + k + 3, j1 + k1 + 3, j2, j2);
for(int k2 = 0; k2 < par1List.size(); ++k2){
String s1 = (String)par1List.get(k2);
font.drawStringWithShadow(s1, i1, j1, -1);
if(k2 == 0){
j1 += 2;
}
j1 += 10;
}
this.zLevel = 0.0F;
itemRender.zLevel = 0.0F;
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
}
}
}
@@ -1,73 +0,0 @@
package electroblob.wizardry.client;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import org.lwjgl.opengl.GL11;
@SideOnly(Side.CLIENT)
class GuiButtonApply extends GuiButton {
private static final ResourceLocation texture = new ResourceLocation("wizardry:textures/gui/handbook.png");
public GuiButtonApply(int id, int x, int y){
super(id, x, y, 32, 16, StatCollector.translateToLocal("container.arcaneWorkbench.apply"));
}
/**
* Draws this button to the screen.
*/
public void drawButton(Minecraft minecraft, int par2, int par3){
// Whether the button is highlighted
this.field_146123_n = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height;
int k = 100;
int l = 220;
int colour = 14737632;
if(this.enabled){
if(this.field_146123_n){
k += this.width*2;
colour = 16777120;
}
}else{
k += this.width;
colour = 10526880;
}
this.drawTexturedRect(this.xPosition, this.yPosition, k, l, this.width, this.height, 256, 256);
this.drawCenteredString(minecraft.fontRenderer, this.displayString, this.xPosition + this.width / 2, this.yPosition + (this.height - 8) / 2, colour);
}
/**
* Draws a textured rectangle, taking the size of the image and the bit needed into account.
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted
* @param v The y position of the top left corner of the section of the image wanted
* @param width The width of the section
* @param height The height of the section
* @param textureWidth The width of the actual image.
* @param textureHeight The height of the actual image.
*/
public void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight)
{
float f = 1F / (float)textureWidth;
float f1 = 1F / (float)textureHeight;
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV((double)(x), (double)(y + height), 0, (double)((float)(u) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y + height), 0, (double)((float)(u + width) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y), 0, (double)((float)(u + width) * f), (double)((float)(v) * f1));
tessellator.addVertexWithUV((double)(x), (double)(y), 0, (double)((float)(u) * f), (double)((float)(v) * f1));
tessellator.draw();
}
}
@@ -1,27 +0,0 @@
package electroblob.wizardry.client;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
@SideOnly(Side.CLIENT)
class GuiButtonInvisible extends GuiButton {
public GuiButtonInvisible(int id, int x, int y, int width, int height){
super(id, x, y, width, height, "");
}
/**
* Draws this button to the screen.
*/
public void drawButton(Minecraft par1Minecraft, int par2, int par3){
this.field_146123_n = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height;
}
}
@@ -1,78 +0,0 @@
package electroblob.wizardry.client;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
@SideOnly(Side.CLIENT)
class GuiButtonNextPage extends GuiButton
{
/**
* True for pointing right (next page), false for pointing left (previous page).
*/
private final boolean nextPage;
private static final ResourceLocation texture = new ResourceLocation("wizardry:textures/gui/handbook.png");
public GuiButtonNextPage(int id, int x, int y, boolean par4)
{
super(id, x, y, 23, 13, "");
this.nextPage = par4;
}
/**
* Draws this button to the screen.
*/
public void drawButton(Minecraft par1Minecraft, int par2, int par3)
{
if (this.visible)
{
boolean flag = par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height;
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
par1Minecraft.getTextureManager().bindTexture(texture);
int k = 0;
int l = 192;
if (flag)
{
k += 23;
}
if (!this.nextPage)
{
l += 13;
}
this.drawTexturedRect(this.xPosition, this.yPosition, k, l, 23, 13, 288, 256);
}
}
/**
* Draws a textured rectangle, taking the size of the image and the bit needed into account.
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted
* @param v The y position of the top left corner of the section of the image wanted
* @param width The width of the section
* @param height The height of the section
* @param textureWidth The width of the actual image.
* @param textureHeight The height of the actual image.
*/
public void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight)
{
float f = 1F / (float)textureWidth;
float f1 = 1F / (float)textureHeight;
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV((double)(x), (double)(y + height), 0, (double)((float)(u) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y + height), 0, (double)((float)(u + width) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y), 0, (double)((float)(u + width) * f), (double)((float)(v) * f1));
tessellator.addVertexWithUV((double)(x), (double)(y), 0, (double)((float)(u) * f), (double)((float)(v) * f1));
tessellator.draw();
}
}
@@ -1,104 +0,0 @@
package electroblob.wizardry.client;
import java.util.ArrayList;
import java.util.List;
import cpw.mods.fml.client.config.DummyConfigElement.DummyCategoryElement;
import cpw.mods.fml.client.config.GuiConfig;
import cpw.mods.fml.client.config.GuiConfigEntries;
import cpw.mods.fml.client.config.GuiConfigEntries.CategoryEntry;
import cpw.mods.fml.client.config.IConfigElement;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.StatCollector;
import net.minecraftforge.common.config.ConfigElement;
import net.minecraftforge.common.config.Configuration;
public class GuiConfigWizardry extends GuiConfig {
public GuiConfigWizardry(GuiScreen parent){
super(parent, getConfigEntries(), Wizardry.MODID, false, false, Wizardry.NAME + " - " + StatCollector.translateToLocal("config.title.general"));
//this.titleLine2 = "File location: " + Wizardry.config.getConfigFile().getAbsolutePath();
}
private static List<IConfigElement> getConfigEntries(){
List<IConfigElement> configList = new ArrayList<IConfigElement>(1);
configList.add(new DummyCategoryElement("spellsConfig", "config.category.spells", SpellsCategory.class));
configList.add(new DummyCategoryElement("resistancesConfig", "config.category.resistances", ResistancesCategory.class));
configList.add(new DummyCategoryElement("idsConfig", "config.category.ids", IDsCategory.class));
configList.addAll(new ConfigElement(Wizardry.config.getCategory(Configuration.CATEGORY_GENERAL)).getChildElements());
return configList;
}
/** Spells category of the config gui. This adds a button which opens up the spells category config. */
public static class SpellsCategory extends CategoryEntry
{
public SpellsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
{
super(owningScreen, owningEntryList, prop);
}
@Override
protected GuiScreen buildChildScreen()
{
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed.
// The parent GuiConfig object's entryList will also be refreshed to reflect the changes.
GuiConfig spellsMenu = new GuiConfig(this.owningScreen,
(new ConfigElement(Wizardry.config.getCategory(Wizardry.SPELLS_CATEGORY))).getChildElements(),
this.owningScreen.modID, Wizardry.SPELLS_CATEGORY, false, false,
Wizardry.NAME + " - " + StatCollector.translateToLocal("config.title.spells"));
spellsMenu.titleLine2 = StatCollector.translateToLocal("config.subtitle.spells");
return spellsMenu;
}
}
/** Resistances category of the config gui. */
public static class ResistancesCategory extends CategoryEntry
{
public ResistancesCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
{
super(owningScreen, owningEntryList, prop);
}
@Override
protected GuiScreen buildChildScreen()
{
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed.
// The parent GuiConfig object's entryList will also be refreshed to reflect the changes.
GuiConfig idsMenu = new GuiConfig(this.owningScreen,
(new ConfigElement(Wizardry.config.getCategory(Wizardry.RESISTANCES_CATEGORY))).getChildElements(),
this.owningScreen.modID, Wizardry.RESISTANCES_CATEGORY, false, false,
Wizardry.NAME + " - " + StatCollector.translateToLocal("config.title.resistances"));
idsMenu.titleLine2 = StatCollector.translateToLocal("config.subtitle.resistances");
return idsMenu;
}
}
/** IDs category of the config gui. */
public static class IDsCategory extends CategoryEntry
{
public IDsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop)
{
super(owningScreen, owningEntryList, prop);
}
@Override
protected GuiScreen buildChildScreen()
{
// This GuiConfig object specifies the configID of the object and as such will force-save when it is closed.
// The parent GuiConfig object's entryList will also be refreshed to reflect the changes.
GuiConfig idsMenu = new GuiConfig(this.owningScreen,
(new ConfigElement(Wizardry.config.getCategory(Wizardry.IDS_CATEGORY))).getChildElements(),
this.owningScreen.modID, Wizardry.IDS_CATEGORY, false, false,
Wizardry.NAME + " - " + StatCollector.translateToLocal("config.title.ids"));
idsMenu.titleLine2 = StatCollector.translateToLocal("config.subtitle.ids");
return idsMenu;
}
}
}
@@ -1,40 +0,0 @@
package electroblob.wizardry.client;
import org.lwjgl.opengl.GL11;
import electroblob.wizardry.WizardryGuiHandler;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.ContainerWorkbench;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
/** Crafting table GUI that doesn't require a crafting table container object. */
public class GuiPortableCrafting extends GuiContainer {
private static final ResourceLocation craftingTableGuiTextures = new ResourceLocation("textures/gui/container/crafting_table.png");
public GuiPortableCrafting(InventoryPlayer p_i1084_1_, World p_i1084_2_, int p_i1084_3_, int p_i1084_4_, int p_i1084_5_)
{
super(new ContainerWorkbench(p_i1084_1_, p_i1084_2_, p_i1084_3_, p_i1084_4_, p_i1084_5_));
}
/**
* Draw the foreground layer for the GuiContainer (everything in front of the items)
*/
protected void drawGuiContainerForegroundLayer(int p_146979_1_, int p_146979_2_)
{
this.fontRendererObj.drawString(I18n.format("container.crafting"), 28, 6, 4210752);
this.fontRendererObj.drawString(I18n.format("container.inventory"), 8, this.ySize - 96 + 2, 4210752);
}
protected void drawGuiContainerBackgroundLayer(float p_146976_1_, int p_146976_2_, int p_146976_3_)
{
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.getTextureManager().bindTexture(craftingTableGuiTextures);
int k = (this.width - this.xSize) / 2;
int l = (this.height - this.ySize) / 2;
this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.ySize);
}
}
@@ -1,153 +0,0 @@
package electroblob.wizardry.client;
import org.lwjgl.input.Keyboard;
import electroblob.wizardry.EnumTier;
import electroblob.wizardry.ExtendedPlayer;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler;
import electroblob.wizardry.WizardryRegistry;
import electroblob.wizardry.spell.Spell;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
public class GuiSpellBook extends GuiScreen {
private int xSize, ySize;
private Spell spell;
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/spellbook.png");
public GuiSpellBook(Spell spell) {
super();
xSize = 288;
ySize = 180;
this.spell = spell;
}
/**
* Draws the screen and all the components in it.
*/
public void drawScreen(int par1, int par2, float par3) {
int xPos = this.width/2 - xSize/2;
int yPos = this.height/2 - this.ySize/2;
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
boolean discovered = true;
if(Wizardry.discoveryMode && !player.capabilities.isCreativeMode && ExtendedPlayer.get(player) != null
&& !ExtendedPlayer.get(player).hasSpellBeenDiscovered(spell)){
discovered = false;
}
// Draws spell illustration on opposite page, underneath the book so it shows through the hole.
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.icon : WizardryRegistry.none.icon);
this.drawTexturedRect(xPos + 145, yPos + 20, 0, 0, 128, 128, 128, 128);
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
this.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
super.drawScreen(par1, par2, par3);
if(discovered){
this.fontRendererObj.drawString(spell.getDisplayName(), xPos+17, yPos+14, 0);
this.fontRendererObj.drawString(spell.type.getDisplayName(), xPos+17, yPos+25, 0x777777);
}else{
this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(spell, player.worldObj), xPos+17, yPos+14, 0);
this.mc.standardGalacticFontRenderer.drawString(spell.type.getDisplayName(), xPos+17, yPos+25, 0x777777);
}
this.fontRendererObj.drawString("-------------------", xPos+17, yPos+34, 0);
if(spell.tier == EnumTier.BASIC){
// Basic is usually white but this doesn't show up.
this.fontRendererObj.drawString("Tier: \u00A77" + EnumTier.BASIC.getDisplayName(), xPos+17, yPos+44, 0);
}else{
this.fontRendererObj.drawString("Tier: " + spell.tier.getDisplayNameWithFormatting(), xPos+17, yPos+44, 0);
}
String element = "Element: " + spell.element.colour + spell.element.getDisplayName();
if(!discovered) element = "Element: ?";
this.fontRendererObj.drawString(element, xPos+17, yPos+56, 0);
String manaCost = "Mana Cost: " + spell.cost;
if(spell.isContinuous) manaCost = "Mana Cost: " + spell.cost + "/second";
if(!discovered) manaCost = "Mana Cost: ?";
this.fontRendererObj.drawString(manaCost, xPos+17, yPos+68, 0);
if(discovered){
this.fontRendererObj.drawSplitString(spell.getDescription(), xPos+17, yPos+82, 118, 0);
}else{
this.mc.standardGalacticFontRenderer.drawSplitString(SpellGlyphData.getGlyphDescription(spell, player.worldObj), xPos+17, yPos+82, 118, 0);
}
/*
// Word wrapping
int charNumber = 0;
int lineNumber = 0;
while(charNumber < spell.desc.length()){
int lineLength = 0;
String line;
if(spell.desc.length() - charNumber > 22){
for(int i = charNumber; i < charNumber+23; i++){
if(spell.desc.charAt(i) == ' '){
lineLength = i - charNumber;
}
}
line = spell.desc.substring(charNumber, charNumber + lineLength);
}else{
line = spell.desc.substring(charNumber, spell.desc.length());
charNumber = spell.desc.length();
}
this.fontRendererObj.drawString("\u00A7o" + line, xPos+17, yPos+82+10*lineNumber, 0);
charNumber+=(lineLength+1);
lineNumber++;
}
*/
}
public void initGui()
{
super.initGui();
Keyboard.enableRepeatEvents(true);
this.buttonList.clear();
}
public void onGuiClosed()
{
super.onGuiClosed();
Keyboard.enableRepeatEvents(false);
}
/**
* Draws a textured rectangle, taking the size of the image and the bit needed into account. Client side only, of course.
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted
* @param v The y position of the top left corner of the section of the image wanted
* @param width The width of the section
* @param height The height of the section
* @param textureWidth The width of the actual image.
* @param textureHeight The height of the actual image.
*/
public static void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight)
{
float f = 1F / (float)textureWidth;
float f1 = 1F / (float)textureHeight;
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV((double)(x), (double)(y + height), 0, (double)((float)(u) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y + height), 0, (double)((float)(u + width) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y), 0, (double)((float)(u + width) * f), (double)((float)(v) * f1));
tessellator.addVertexWithUV((double)(x), (double)(y), 0, (double)((float)(u) * f), (double)((float)(v) * f1));
tessellator.draw();
}
}
@@ -1,169 +0,0 @@
package electroblob.wizardry.client;
import java.util.List;
import org.lwjgl.opengl.GL11;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import electroblob.wizardry.ExtendedPlayer;
import electroblob.wizardry.SpellGlyphData;
import electroblob.wizardry.WandHelper;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryRegistry;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.spell.None;
import electroblob.wizardry.spell.Spell;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagIntArray;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
public class GuiSpellDisplay extends Gui {
private Minecraft mc;
private static final ResourceLocation hudTexture = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_hud.png");
public GuiSpellDisplay(Minecraft par1Minecraft) {
super();
this.mc = par1Minecraft;
}
@SubscribeEvent
public void draw(RenderGameOverlayEvent event){
EntityPlayer player = this.mc.thePlayer;
if(player.getHeldItem() != null && player.getHeldItem().getItem() instanceof ItemWand){
int width = event.resolution.getScaledWidth();
int height = event.resolution.getScaledHeight();
Spell spell = WandHelper.getCurrentSpell(player.getHeldItem());
int cooldown = WandHelper.getCurrentCooldown(player.getHeldItem());
float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(player.getHeldItem(), Wizardry.cooldownUpgrade)*Wizardry.COOLDOWN_REDUCTION_PER_LEVEL;
if(player.isPotionActive(Wizardry.fontOfMana)){
// Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously
cooldownMultiplier /= 2 + player.getActivePotionEffect(Wizardry.fontOfMana).getAmplifier();
}
// Coordinates of the top left corner of the HUD.
int left = 0;
int top = 0;
boolean mirror = false;
if(Wizardry.spellHUDPosition.equals("Bottom left")){
left = 0;
top = height-36;
}else if(Wizardry.spellHUDPosition.equals("Top left")){
left = 0;
top = 0;
}else if(Wizardry.spellHUDPosition.equals("Top right")){
left = width-128;
top = 0;
mirror = true;
}else if(Wizardry.spellHUDPosition.equals("Bottom right")){
left = width-128;
top = height-36;
mirror = true;
}
boolean discovered = true;
if(!player.capabilities.isCreativeMode && ExtendedPlayer.get(player) != null){
discovered = ExtendedPlayer.get(player).hasSpellBeenDiscovered(spell);
}
if(event.type == RenderGameOverlayEvent.ElementType.TEXT){
// Makes spells greyed out if they are in cooldown or if the player has the arcane jammer effect
String colour = cooldown > 0 || player.isPotionActive(Wizardry.arcaneJammer) ? "\u00A78" : spell.element.colour;
if(!discovered) colour = "\u00A79";
String spellName = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.worldObj);
FontRenderer font = discovered ? this.mc.fontRenderer : this.mc.standardGalacticFontRenderer;
int maxWidth = 90;
if(font.getStringWidth(spellName) <= maxWidth){
// Single line is rendered more centrally
font.drawStringWithShadow(colour + spellName, mirror ? left+5 : left+41, top+13, 0xffffffff);
}else{
int lineNumber = 0;
List lines = font.listFormattedStringToWidth(spellName, maxWidth);
for(Object line : lines){
if(line instanceof String){
font.drawStringWithShadow(colour + (String)line, mirror ? left+5 : left+41, top+6 + 11*lineNumber, 0xffffffff);
}
lineNumber++;
}
}
}else if(event.type == RenderGameOverlayEvent.ElementType.HOTBAR){
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor3f(1.0f, 1.0f, 1.0f);
this.mc.renderEngine.bindTexture(hudTexture);
// Background of spell hud
this.drawTexturedModalRect(left, top, 0, mirror ? 36 : 0, 128, 36);
// Cooldown bar
if(cooldown > 0){
this.drawTexturedModalRect(mirror ? left+5 : left+41, height-8, 128, 6, 82, 6);
int l = (int)(((double)(spell.cooldown * cooldownMultiplier - cooldown)
/ (double)(spell.cooldown * cooldownMultiplier)) * 82);
this.drawTexturedModalRect(mirror ? left+5 : left+41, height-8, 128, 0, l, 6);
}
// Spell illustration
this.mc.renderEngine.bindTexture(discovered ? spell.icon : WizardryRegistry.none.icon);
this.drawTexturedRect(mirror ? left+94 : left+2, top+2, 0, 0, 32, 32, 32, 32);
GL11.glDisable(GL11.GL_BLEND);
GL11.glPopMatrix();
}
}
}
/**
* Draws a textured rectangle, taking the size of the image and the bit needed into account. Client side only, of course.
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted
* @param v The y position of the top left corner of the section of the image wanted
* @param width The width of the section
* @param height The height of the section
* @param textureWidth The width of the actual image.
* @param textureHeight The height of the actual image.
*/
public static void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight)
{
float f = 1F / (float)textureWidth;
float f1 = 1F / (float)textureHeight;
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV((double)(x), (double)(y + height), 0, (double)((float)(u) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y + height), 0, (double)((float)(u + width) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y), 0, (double)((float)(u + width) * f), (double)((float)(v) * f1));
tessellator.addVertexWithUV((double)(x), (double)(y), 0, (double)((float)(u) * f), (double)((float)(v) * f1));
tessellator.draw();
}
}
@@ -1,945 +0,0 @@
package electroblob.wizardry.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.io.Charsets;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import electroblob.wizardry.EnumElement;
import electroblob.wizardry.EnumTier;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryGuiHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.resources.LanguageManager;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
public class GuiWizardHandbook extends GuiScreen {
private GuiButtonNextPage nextPageBtn, prevPageBtn;
private int xSize, ySize;
private int pageNumber = 0;
private static final int pageWidth = 120;
public static final ResourceLocation regularHandbook = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png");
public static final ResourceLocation ore = new ResourceLocation(Wizardry.MODID, "textures/gui/ore_picture.png");
public static final ResourceLocation crystal = new ResourceLocation(Wizardry.MODID, "textures/items/magic_crystal.png");
public static final ResourceLocation workbenchGui = new ResourceLocation(Wizardry.MODID, "textures/gui/arcane_workbench.png");
public static final ResourceLocation craftingGrids = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook_recipes.png");
private ArrayList<ArrayList<String>> text;
private ArrayList<Section> sections;
private int guiPage, imagePage;
public GuiWizardHandbook() {
super();
xSize = 288;
ySize = 180;
}
/**
* Draws the screen and all the components in it.
*/
public void drawScreen(int mouseX, int mouseY, float par3){
int xPos = this.width/2 - xSize/2;
int yPos = this.height/2 - this.ySize/2;
// Tests for crafting recipes section
if(pageNumber >= (sections.get(sections.size()-1).pageNumber-1)/2 && pageNumber < (sections.get(sections.size()-1).pageNumber-1)/2 + 4){
Minecraft.getMinecraft().renderEngine.bindTexture(craftingGrids);
}else{
Minecraft.getMinecraft().renderEngine.bindTexture(regularHandbook);
}
drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
// Arcane workbench gui picture
if(pageNumber == (this.guiPage-1)/2){
Minecraft.getMinecraft().renderEngine.bindTexture(workbenchGui);
this.drawTexturedModalRect(this.guiPage % 2 == 1 ? xPos + 17 : this.width/2 + 7, yPos + 14, 28, 12, 120, 118);
}
// Magic crystal and crystal ore images
if(pageNumber == (this.imagePage-1)/2){
Minecraft.getMinecraft().renderEngine.bindTexture(ore);
drawTexturedRect(this.imagePage % 2 == 1 ? xPos + 17 : this.width/2 + 7, yPos + 80, 0, 0, 64, 64, 64, 64);
Minecraft.getMinecraft().renderEngine.bindTexture(crystal);
drawTexturedStretchedRect(this.imagePage % 2 == 1 ? xPos + 17 + 64 : this.width/2 + 7 + 62, yPos + 80, 0, 0, 64, 64, 1, 1);
}
this.fontRendererObj.drawString("" + (pageNumber*2 + 1), xPos + xSize/4 - 3, yPos + ySize - 20, 0);
this.fontRendererObj.drawString("" + (pageNumber*2 + 2), xPos + 3*xSize/4 - 5, yPos + ySize - 20, 0);
super.drawScreen(mouseX, mouseY, par3);
int lineNumber = 0;
if(pageNumber == 1){
int row = 2;
for(Section s : sections){
s.drawContents();
row++;
}
}else{
for(Section s : sections){
s.hideButton();
}
}
for(String paragraph : text.get(pageNumber*2)){
this.fontRendererObj.drawSplitString(paragraph, xPos + 17, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, pageWidth, 0);
ArrayList list = new ArrayList(this.fontRendererObj.listFormattedStringToWidth(paragraph, this.pageWidth));
lineNumber += list.size();
}
lineNumber = 0;
// Prevents crash when the last page is blank (and hence is not in the list of pages)
if(text.size() > pageNumber*2 + 1){
for(String paragraph : text.get(pageNumber*2 + 1)){
// First page is centred
if(pageNumber == 0){
int startX = this.width/2 + 7 + pageWidth/2 - this.fontRendererObj.getStringWidth(paragraph)/2;
this.fontRendererObj.drawSplitString(paragraph, startX, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, pageWidth, 0);
}else{
this.fontRendererObj.drawSplitString(paragraph, this.width/2 + 7, yPos + 14 + lineNumber*this.fontRendererObj.FONT_HEIGHT, pageWidth, 0);
}
ArrayList list = new ArrayList(this.fontRendererObj.listFormattedStringToWidth(paragraph, this.pageWidth));
lineNumber += list.size();
}
}
/*
for(int i=0;i<(Math.min(text[pageNumber].length, 14));i++){
this.fontRendererObj.drawString(text[pageNumber][i], xPos + 16, yPos + 14 + i*10, 0);
}
for(int i=0;i<(Math.min(text[pageNumber].length - 14, 14));i++){
this.fontRendererObj.drawString(text[pageNumber][i+14], this.width/2 + 5, yPos + 14 + i*10, 0);
}
*/
ItemStack[][] craftingGrid;
ItemStack craftingResult;
// Tooltips are rendered after recipes to prevent tooltips on the left appearing behind items on the right.
if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.gold_nugget);
craftingGrid[1][0] = new ItemStack(Blocks.carpet, 1, 10);
craftingGrid[2][0] = new ItemStack(Items.gold_nugget);
craftingGrid[0][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][1] = new ItemStack(Blocks.lapis_block);
craftingGrid[2][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[0][2] = new ItemStack(Blocks.stone);
craftingGrid[1][2] = new ItemStack(Blocks.stone);
craftingGrid[2][2] = new ItemStack(Blocks.stone);
craftingResult = new ItemStack(Wizardry.arcaneWorkbench);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[2][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][1] = new ItemStack(Items.stick);
craftingGrid[0][2] = new ItemStack(Items.gold_nugget);
craftingResult = new ItemStack(Wizardry.magicWand);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[0][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][1] = new ItemStack(Items.book);
craftingGrid[1][2] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[2][1] = new ItemStack(Wizardry.magicCrystal);
craftingResult = new ItemStack(Wizardry.spellBook, 1, 1);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.book);
craftingGrid[1][0] = new ItemStack(Wizardry.magicCrystal);
craftingResult = new ItemStack(Wizardry.wizardHandbook);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 1){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.crystalFlower);
craftingResult = new ItemStack(Wizardry.magicCrystal, 2);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[2][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[0][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][1] = new ItemStack(Items.glass_bottle);
craftingGrid[2][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[0][2] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][2] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[2][2] = new ItemStack(Wizardry.magicCrystal);
craftingResult = new ItemStack(Wizardry.manaFlask);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Blocks.stone);
craftingGrid[0][1] = new ItemStack(Blocks.stone);
craftingGrid[1][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][2] = new ItemStack(Blocks.stone);
craftingGrid[2][1] = new ItemStack(Blocks.stone);
craftingResult = new ItemStack(Wizardry.transportationStone, 2);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Items.string);
craftingGrid[0][1] = new ItemStack(Items.string);
craftingGrid[1][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][2] = new ItemStack(Items.string);
craftingGrid[2][1] = new ItemStack(Items.string);
craftingResult = new ItemStack(Wizardry.magicSilk, 2);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[1][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][1] = new ItemStack(Wizardry.magicSilk);
craftingResult = new ItemStack(Wizardry.wizardHat);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[1][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][2] = new ItemStack(Wizardry.magicSilk);
craftingGrid[1][2] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][2] = new ItemStack(Wizardry.magicSilk);
craftingResult = new ItemStack(Wizardry.wizardRobe);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[1][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][2] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][2] = new ItemStack(Wizardry.magicSilk);
craftingResult = new ItemStack(Wizardry.wizardLeggings);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][1] = new ItemStack(Wizardry.magicSilk);
craftingResult = new ItemStack(Wizardry.wizardBoots);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 3){
if(Wizardry.useAlternateScrollRecipe){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.paper);
craftingGrid[1][0] = new ItemStack(Items.string);
craftingGrid[2][0] = new ItemStack(Wizardry.magicCrystal);
craftingResult = new ItemStack(Wizardry.blankScroll);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}else{
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.paper);
craftingGrid[1][0] = new ItemStack(Items.string);
craftingResult = new ItemStack(Wizardry.blankScroll);
this.renderCraftingRecipe(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.firebombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.blaze_powder);
craftingGrid[1][0] = new ItemStack(Items.blaze_powder);
craftingGrid[0][1] = new ItemStack(Items.glass_bottle);
craftingGrid[1][1] = new ItemStack(Items.gunpowder);
craftingResult = new ItemStack(Wizardry.firebomb, 3);
this.renderCraftingRecipe(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.poisonBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.spider_eye);
craftingGrid[1][0] = new ItemStack(Items.spider_eye);
craftingGrid[0][1] = new ItemStack(Items.glass_bottle);
craftingGrid[1][1] = new ItemStack(Items.gunpowder);
craftingResult = new ItemStack(Wizardry.poisonBomb, 3);
this.renderCraftingRecipe(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.smokeBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.coal);
craftingGrid[1][0] = new ItemStack(Items.coal);
craftingGrid[0][1] = new ItemStack(Items.glass_bottle);
craftingGrid[1][1] = new ItemStack(Items.gunpowder);
craftingResult = new ItemStack(Wizardry.smokeBomb, 3);
this.renderCraftingRecipe(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
}
if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.gold_nugget);
craftingGrid[1][0] = new ItemStack(Blocks.carpet, 1, 10);
craftingGrid[2][0] = new ItemStack(Items.gold_nugget);
craftingGrid[0][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][1] = new ItemStack(Blocks.lapis_block);
craftingGrid[2][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[0][2] = new ItemStack(Blocks.stone);
craftingGrid[1][2] = new ItemStack(Blocks.stone);
craftingGrid[2][2] = new ItemStack(Blocks.stone);
craftingResult = new ItemStack(Wizardry.arcaneWorkbench);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[2][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][1] = new ItemStack(Items.stick);
craftingGrid[0][2] = new ItemStack(Items.gold_nugget);
craftingResult = new ItemStack(Wizardry.magicWand);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[0][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][1] = new ItemStack(Items.book);
craftingGrid[1][2] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[2][1] = new ItemStack(Wizardry.magicCrystal);
craftingResult = new ItemStack(Wizardry.spellBook, 1, 1);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.book);
craftingGrid[1][0] = new ItemStack(Wizardry.magicCrystal);
craftingResult = new ItemStack(Wizardry.wizardHandbook);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 1){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.crystalFlower);
craftingResult = new ItemStack(Wizardry.magicCrystal, 2);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[2][0] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[0][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][1] = new ItemStack(Items.glass_bottle);
craftingGrid[2][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[0][2] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][2] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[2][2] = new ItemStack(Wizardry.magicCrystal);
craftingResult = new ItemStack(Wizardry.manaFlask);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Blocks.stone);
craftingGrid[0][1] = new ItemStack(Blocks.stone);
craftingGrid[1][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][2] = new ItemStack(Blocks.stone);
craftingGrid[2][1] = new ItemStack(Blocks.stone);
craftingResult = new ItemStack(Wizardry.transportationStone, 2);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[1][0] = new ItemStack(Items.string);
craftingGrid[0][1] = new ItemStack(Items.string);
craftingGrid[1][1] = new ItemStack(Wizardry.magicCrystal);
craftingGrid[1][2] = new ItemStack(Items.string);
craftingGrid[2][1] = new ItemStack(Items.string);
craftingResult = new ItemStack(Wizardry.magicSilk, 2);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 2){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[1][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][1] = new ItemStack(Wizardry.magicSilk);
craftingResult = new ItemStack(Wizardry.wizardHat);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[1][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][2] = new ItemStack(Wizardry.magicSilk);
craftingGrid[1][2] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][2] = new ItemStack(Wizardry.magicSilk);
craftingResult = new ItemStack(Wizardry.wizardRobe);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[1][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][2] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][2] = new ItemStack(Wizardry.magicSilk);
craftingResult = new ItemStack(Wizardry.wizardLeggings);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][0] = new ItemStack(Wizardry.magicSilk);
craftingGrid[0][1] = new ItemStack(Wizardry.magicSilk);
craftingGrid[2][1] = new ItemStack(Wizardry.magicSilk);
craftingResult = new ItemStack(Wizardry.wizardBoots);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}else if(pageNumber == (sections.get(sections.size()-1).pageNumber-1)/2 + 3){
if(Wizardry.useAlternateScrollRecipe){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.paper);
craftingGrid[1][0] = new ItemStack(Items.string);
craftingGrid[2][0] = new ItemStack(Wizardry.magicCrystal);
craftingResult = new ItemStack(Wizardry.blankScroll);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}else{
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.paper);
craftingGrid[1][0] = new ItemStack(Items.string);
craftingResult = new ItemStack(Wizardry.blankScroll);
this.renderCraftingTooltips(xPos + 23, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.firebombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.blaze_powder);
craftingGrid[1][0] = new ItemStack(Items.blaze_powder);
craftingGrid[0][1] = new ItemStack(Items.glass_bottle);
craftingGrid[1][1] = new ItemStack(Items.gunpowder);
craftingResult = new ItemStack(Wizardry.firebomb, 3);
this.renderCraftingTooltips(xPos + 23, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.poisonBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.spider_eye);
craftingGrid[1][0] = new ItemStack(Items.spider_eye);
craftingGrid[0][1] = new ItemStack(Items.glass_bottle);
craftingGrid[1][1] = new ItemStack(Items.gunpowder);
craftingResult = new ItemStack(Wizardry.poisonBomb, 3);
this.renderCraftingTooltips(xPos + 156, yPos + 39, mouseX, mouseY, craftingGrid, craftingResult);
}
if(Wizardry.smokeBombIsCraftable){
craftingGrid = new ItemStack[3][3];
craftingGrid[0][0] = new ItemStack(Items.coal);
craftingGrid[1][0] = new ItemStack(Items.coal);
craftingGrid[0][1] = new ItemStack(Items.glass_bottle);
craftingGrid[1][1] = new ItemStack(Items.gunpowder);
craftingResult = new ItemStack(Wizardry.smokeBomb, 3);
this.renderCraftingTooltips(xPos + 156, yPos + 98, mouseX, mouseY, craftingGrid, craftingResult);
}
}
}
private void renderCraftingRecipe(int xPos, int yPos, int mouseX, int mouseY, ItemStack[][] craftingGrid, ItemStack craftingResult) {
int guiLeft = this.width/2 - xSize/2;
int guiTop = this.height/2 - this.ySize/2;
GL11.glPushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
GL11.glEnable(GL11.GL_LIGHTING);
itemRender.zLevel = 100.0F;
for(int i=0; i<craftingGrid.length; i++){
for(int j=0; j<craftingGrid[i].length; j++){
if(craftingGrid[i][j] != null){
itemRender.renderItemAndEffectIntoGUI(this.fontRendererObj, this.mc.getTextureManager(), craftingGrid[i][j], xPos + 18*i, yPos + 18*j);
itemRender.renderItemOverlayIntoGUI(this.fontRendererObj, this.mc.getTextureManager(), craftingGrid[i][j], xPos + 18*i, yPos + 18*j);
}
}
}
if(craftingResult != null){
itemRender.renderItemAndEffectIntoGUI(this.fontRendererObj, this.mc.getTextureManager(), craftingResult, xPos + 86, yPos + 18);
itemRender.renderItemOverlayIntoGUI(this.fontRendererObj, this.mc.getTextureManager(), craftingResult, xPos + 86, yPos + 18);
}
GL11.glPopMatrix();
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
}
private void renderCraftingTooltips(int xPos, int yPos, int mouseX, int mouseY, ItemStack[][] craftingGrid, ItemStack craftingResult) {
int guiLeft = this.width/2 - xSize/2;
int guiTop = this.height/2 - this.ySize/2;
GL11.glPushMatrix();
RenderHelper.enableGUIStandardItemLighting();
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
itemRender.zLevel = 0.0F;
GL11.glDisable(GL11.GL_LIGHTING);
for(int i=0; i<craftingGrid.length; i++){
for(int j=0; j<craftingGrid[i].length; j++){
if(craftingGrid[i][j] != null && isPointInRegion(xPos + 18*i, yPos + 18*j, 16, 16, mouseX + guiLeft, mouseY + guiTop)){
this.drawItemStackTooltip(craftingGrid[i][j], mouseX, mouseY);
}
}
}
if(craftingResult != null && isPointInRegion(xPos + 86, yPos + 18, 16, 16, mouseX + guiLeft, mouseY + guiTop)){
this.drawItemStackTooltip(craftingResult, mouseX, mouseY);
}
GL11.glPopMatrix();
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
}
@Override
public void initGui(){
super.initGui();
Keyboard.enableRepeatEvents(true);
int nextButtonId = 0;
this.buttonList.clear();
this.buttonList.add(this.nextPageBtn = new GuiButtonNextPage(nextButtonId++, this.width/2 + this.xSize/2 - 22 - 23, this.height/2 + this.ySize/2 - 10 - 13, true));
this.buttonList.add(this.prevPageBtn = new GuiButtonNextPage(nextButtonId++, this.width/2 - this.xSize/2 + 21, this.height/2 + this.ySize/2 - 10 - 13, false));
text = new ArrayList<ArrayList<String>>(1);
sections = new ArrayList<Section>(1);
BufferedReader bufferedreader = null;
String textFilepath = "wizardry:texts/handbook_" + Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".txt";
try {
bufferedreader = new BufferedReader(new InputStreamReader(this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), Charsets.UTF_8));
} catch (IOException e){
System.out.println("Warning: wizard handbook text file missing for the current language. Using default (English - US) instead.");
textFilepath = "wizardry:texts/handbook_en_US.txt";
try {
bufferedreader = new BufferedReader(new InputStreamReader(this.mc.getResourceManager().getResource(new ResourceLocation(textFilepath)).getInputStream(), Charsets.UTF_8));
} catch (IOException x){
System.err.println("Couldn't find file: wizardry:assets/texts/handbook_en_US.txt. The file may be missing; please try re-downloading and reinstalling wizardry.");
x.printStackTrace();
}
}
if(bufferedreader != null){
try {
String paragraph = bufferedreader.readLine();
ArrayList<String> page = new ArrayList<String>(1);
int linesPerPage = 16;
int lineNumber = 0;
while(paragraph != null){
//System.out.println(paragraph);
if(paragraph.contains("PAGEBREAK") || lineNumber >= linesPerPage){
text.add(page);
page = new ArrayList<String>(1);
lineNumber = 0;
if(paragraph.contains("PAGEBREAK")) paragraph = bufferedreader.readLine();
}else if(paragraph.contains("LINEBREAK")){
lineNumber++;
page.add("");
paragraph = bufferedreader.readLine();
}else if(paragraph.contains("SECTION")){
sections.add(new Section(paragraph.replace("SECTION ", ""), text.size() + 1, this.width/2 + 7,
this.height/2 - this.ySize/2 + 14 + (sections.size()+2)*this.fontRendererObj.FONT_HEIGHT, nextButtonId++));
paragraph = bufferedreader.readLine();
}else if(paragraph.contains("IMAGE")){
if(paragraph.contains("WORKBENCH")){
this.guiPage = text.size() + 1;
}else if(paragraph.contains("CRYSTAL")){
this.imagePage = text.size() + 1;
}
paragraph = bufferedreader.readLine();
}else{
paragraph = paragraph.replaceAll("NEXT_SPELL_KEY", Keyboard.getKeyName(ClientProxy.nextSpell.getKeyCode()));
paragraph = paragraph.replaceAll("PREVIOUS_SPELL_KEY", Keyboard.getKeyName(ClientProxy.previousSpell.getKeyCode()));
paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL_MINUS_30", "" + (Wizardry.MANA_PER_CRYSTAL - 30));
paragraph = paragraph.replaceAll("MANA_PER_CRYSTAL", "" + Wizardry.MANA_PER_CRYSTAL);
paragraph = paragraph.replaceAll("BASIC_MAX_CHARGE", "" + EnumTier.BASIC.maxCharge);
paragraph = paragraph.replaceAll("APPRENTICE_MAX_CHARGE", "" + EnumTier.APPRENTICE.maxCharge);
paragraph = paragraph.replaceAll("ADVANCED_MAX_CHARGE", "" + EnumTier.ADVANCED.maxCharge);
paragraph = paragraph.replaceAll("MASTER_MAX_CHARGE", "" + EnumTier.MASTER.maxCharge);
paragraph = paragraph.replaceAll("BASIC_COLOUR", "\u00A77");
paragraph = paragraph.replaceAll("APPRENTICE_COLOUR", EnumTier.APPRENTICE.colour);
paragraph = paragraph.replaceAll("ADVANCED_COLOUR", EnumTier.ADVANCED.colour);
paragraph = paragraph.replaceAll("MASTER_COLOUR", EnumTier.MASTER.colour);
paragraph = paragraph.replaceAll("FIRE_COLOUR", EnumElement.FIRE.colour);
paragraph = paragraph.replaceAll("ICE_COLOUR", EnumElement.ICE.colour);
paragraph = paragraph.replaceAll("LIGHTNING_COLOUR", EnumElement.LIGHTNING.colour);
paragraph = paragraph.replaceAll("NECROMANCY_COLOUR", EnumElement.NECROMANCY.colour);
paragraph = paragraph.replaceAll("EARTH_COLOUR", EnumElement.EARTH.colour);
paragraph = paragraph.replaceAll("SORCERY_COLOUR", EnumElement.SORCERY.colour);
paragraph = paragraph.replaceAll("HEALING_COLOUR", EnumElement.HEALING.colour);
paragraph = paragraph.replaceAll("RESET_COLOUR", "\u00A70");
paragraph = paragraph.replaceAll("VERSION", Wizardry.VERSION);
int linesInParagraph = this.fontRendererObj.listFormattedStringToWidth(paragraph, this.pageWidth).size();
// Ignores empty lines at the top of a page.
if(paragraph.isEmpty() && lineNumber == 0){
paragraph = bufferedreader.readLine();
// Normal paragraph, all on one page
}else if(lineNumber + linesInParagraph <= linesPerPage){
page.add(paragraph);
lineNumber += linesInParagraph;
paragraph = bufferedreader.readLine();
// Paragraphs split across two pages (or more?)
}else{
int linesInFirstPart = linesPerPage - lineNumber;
String paragraphFirstPart = "";
String paragraphLastPart = "";
int i = 0;
List strings = this.fontRendererObj.listFormattedStringToWidth(paragraph, this.pageWidth);
for(Object s : strings){
if(i < linesInFirstPart){
paragraphFirstPart = paragraphFirstPart.concat((String)s + " ");
}else{
paragraphLastPart = paragraphLastPart.concat((String)s + " ");
}
i++;
}
//System.out.println("Paragraph crosses page boundary; string split into: \"" + paragraphFirstPart + "\" and \"" + paragraphLastPart + "\"");
page.add(paragraphFirstPart);
lineNumber += linesInFirstPart;
paragraph = paragraphLastPart;
}
}
}
text.add(page);
} catch (IOException e){
System.err.println("Something went wrong reading file: " + textFilepath + ". The file may be damaged; please try re-downloading and reinstalling wizardry.");
e.printStackTrace();
}
}
/*
for(ArrayList<String> a : text){
for(String s : a){
System.out.println(s);
}
}
*/
}
private class Section {
String name;
int pageNumber;
int x, y;
int buttonId;
Section(String name, int pageNumber, int x, int y, int id){
this.name = name;
this.pageNumber = pageNumber;
this.x = x;
this.y = y;
this.buttonId = id;
GuiWizardHandbook.this.buttonList.add(new GuiButtonInvisible(id, x, y, GuiWizardHandbook.this.pageWidth, GuiWizardHandbook.this.fontRendererObj.FONT_HEIGHT));
}
void hideButton(){
((GuiButton)GuiWizardHandbook.this.buttonList.get(buttonId)).visible = false;
}
void drawContents(){
((GuiButton)GuiWizardHandbook.this.buttonList.get(buttonId)).visible = true;
GuiWizardHandbook.this.fontRendererObj.drawString(name, x, y, ((GuiButton)GuiWizardHandbook.this.buttonList.get(buttonId)).func_146115_a() ? 0xdd4c1d : 0);
int nameWidth = GuiWizardHandbook.this.fontRendererObj.getStringWidth(name);
String dotsAndNumber = " " + this.pageNumber;
while(GuiWizardHandbook.this.fontRendererObj.getStringWidth(dotsAndNumber) < GuiWizardHandbook.pageWidth - nameWidth - 2){
dotsAndNumber = "." + dotsAndNumber;
}
GuiWizardHandbook.this.fontRendererObj.drawString(dotsAndNumber, x + GuiWizardHandbook.pageWidth - GuiWizardHandbook.this.fontRendererObj.getStringWidth(dotsAndNumber), y, 0);
}
}
public void onGuiClosed()
{
super.onGuiClosed();
Keyboard.enableRepeatEvents(false);
}
/**
* Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e).
*/
protected void actionPerformed(GuiButton par1GuiButton){
if(par1GuiButton.enabled){
if(par1GuiButton.id == 0){
if(pageNumber < (text.size()-1)/2) pageNumber++;
}else if(par1GuiButton.id == 1){
if(pageNumber > 0) pageNumber--;
}else{
if(pageNumber == 1) pageNumber = (sections.get(par1GuiButton.id - 2).pageNumber-1)/2;
}
}
}
/**
* Args: left, top, width, height, pointX, pointY. Note: left, top are local to Gui, pointX, pointY are local to
* screen
*/
protected boolean isPointInRegion(int par1, int par2, int par3, int par4, int par5, int par6)
{
int k1 = this.width/2 - xSize/2;
int l1 = this.height/2 - this.ySize/2;
par5 -= k1;
par6 -= l1;
return par5 >= par1 - 1 && par5 < par1 + par3 + 1 && par6 >= par2 - 1 && par6 < par2 + par4 + 1;
}
protected void drawItemStackTooltip(ItemStack par1ItemStack, int par2, int par3)
{
List list = par1ItemStack.getTooltip(this.mc.thePlayer, this.mc.gameSettings.advancedItemTooltips);
for (int k = 0; k < list.size(); ++k)
{
if (k == 0)
{
list.set(k, par1ItemStack.getRarity().rarityColor + (String)list.get(k));
}
else
{
list.set(k, EnumChatFormatting.GRAY + (String)list.get(k));
}
}
FontRenderer font = par1ItemStack.getItem().getFontRenderer(par1ItemStack);
drawHoveringText(list, par2, par3, (font == null ? fontRendererObj : font));
}
protected void drawHoveringText(List par1List, int par2, int par3, FontRenderer font)
{
if (!par1List.isEmpty())
{
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
RenderHelper.disableStandardItemLighting();
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_DEPTH_TEST);
int k = 0;
Iterator iterator = par1List.iterator();
while (iterator.hasNext())
{
String s = (String)iterator.next();
int l = font.getStringWidth(s);
if (l > k)
{
k = l;
}
}
int i1 = par2 + 12;
int j1 = par3 - 12;
int k1 = 8;
if (par1List.size() > 1)
{
k1 += 2 + (par1List.size() - 1) * 10;
}
if (i1 + k > this.width)
{
i1 -= 28 + k;
}
if (j1 + k1 + 6 > this.height)
{
j1 = this.height - k1 - 6;
}
this.zLevel = 300.0F;
itemRender.zLevel = 300.0F;
int l1 = -267386864;
this.drawGradientRect(i1 - 3, j1 - 4, i1 + k + 3, j1 - 3, l1, l1);
this.drawGradientRect(i1 - 3, j1 + k1 + 3, i1 + k + 3, j1 + k1 + 4, l1, l1);
this.drawGradientRect(i1 - 3, j1 - 3, i1 + k + 3, j1 + k1 + 3, l1, l1);
this.drawGradientRect(i1 - 4, j1 - 3, i1 - 3, j1 + k1 + 3, l1, l1);
this.drawGradientRect(i1 + k + 3, j1 - 3, i1 + k + 4, j1 + k1 + 3, l1, l1);
int i2 = 1347420415;
int j2 = (i2 & 16711422) >> 1 | i2 & -16777216;
this.drawGradientRect(i1 - 3, j1 - 3 + 1, i1 - 3 + 1, j1 + k1 + 3 - 1, i2, j2);
this.drawGradientRect(i1 + k + 2, j1 - 3 + 1, i1 + k + 3, j1 + k1 + 3 - 1, i2, j2);
this.drawGradientRect(i1 - 3, j1 - 3, i1 + k + 3, j1 - 3 + 1, i2, i2);
this.drawGradientRect(i1 - 3, j1 + k1 + 2, i1 + k + 3, j1 + k1 + 3, j2, j2);
for(int k2 = 0; k2 < par1List.size(); ++k2){
String s1 = (String)par1List.get(k2);
font.drawStringWithShadow(s1, i1, j1, -1);
if(k2 == 0){
j1 += 2;
}
j1 += 10;
}
this.zLevel = 0.0F;
itemRender.zLevel = 0.0F;
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
RenderHelper.enableStandardItemLighting();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
}
}
/**
* Draws a textured rectangle, taking the size of the image and the bit needed into account.
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted
* @param v The y position of the top left corner of the section of the image wanted
* @param width The width of the section
* @param height The height of the section
* @param textureWidth The width of the actual image.
* @param textureHeight The height of the actual image.
*/
public void drawTexturedRect(int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight)
{
float f = 1F / (float)textureWidth;
float f1 = 1F / (float)textureHeight;
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV((double)(x), (double)(y + height), 0, (double)((float)(u) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y + height), 0, (double)((float)(u + width) * f), (double)((float)(v + height) * f1));
tessellator.addVertexWithUV((double)(x + width), (double)(y), 0, (double)((float)(u + width) * f), (double)((float)(v) * f1));
tessellator.addVertexWithUV((double)(x), (double)(y), 0, (double)((float)(u) * f), (double)((float)(v) * f1));
tessellator.draw();
}
/**
* Draws a textured rectangle, stretching the section of the image to fit the size given.
* @param x The x position of the rectangle
* @param y The y position of the rectangle
* @param u The x position of the top left corner of the section of the image wanted, expressed as a fraction of the image width
* @param v The y position of the top left corner of the section of the image wanted, expressed as a fraction of the image width
* @param finalWidth The width as rendered
* @param finalHeight The height as rendered
* @param width The width of the section, expressed as a fraction of the image width
* @param height The height of the section, expressed as a fraction of the image width
*/
public void drawTexturedStretchedRect(int x, int y, int u, int v, int finalWidth, int finalHeight, int width, int height)
{
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV((double)(x), (double)(y + finalHeight), 0, u, v + height);
tessellator.addVertexWithUV((double)(x + finalWidth), (double)(y + finalHeight), 0, u + width, v + height);
tessellator.addVertexWithUV((double)(x + finalWidth), (double)(y), 0, u + width, v);
tessellator.addVertexWithUV((double)(x), (double)(y), 0, u, v);
tessellator.draw();
}
}
@@ -1,97 +1,96 @@
package electroblob.wizardry.client;
import java.util.ArrayList;
import java.util.List;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.util.ResourceLocation;
/** Font renderer that renders parts of strings surrounded by '#' (without quotes) in the SGA instead of normal text.
* @since Wizardry 1.1 */
@SideOnly(Side.CLIENT)
/**
* Font renderer that renders parts of strings surrounded by '#' (without quotes) in the SGA instead of normal text.
*
* @since Wizardry 1.1
*/
//@SideOnly(Side.CLIENT)
public class MixedFontRenderer extends FontRenderer {
public MixedFontRenderer(GameSettings p_i1035_1_, ResourceLocation p_i1035_2_, TextureManager p_i1035_3_,
boolean p_i1035_4_) {
boolean p_i1035_4_){
super(p_i1035_1_, p_i1035_2_, p_i1035_3_, p_i1035_4_);
}
@Override
public int drawString(String string, int x, int y, int colour, boolean shadow){
public int drawString(String string, float x, float y, int colour, boolean shadow){
int l = 0;
boolean sga = false;
while(string.indexOf('#') > -1){
String section = string.substring(0, string.indexOf('#'));
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(section, x, y, colour, shadow);
l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(section, x, y, colour, shadow);
x += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(section);
}else{
l += Minecraft.getMinecraft().fontRenderer.drawString(section, x, y, colour, shadow);
}else{
l += Minecraft.getMinecraft().fontRenderer.drawString(section, x, y, colour, shadow);
x += Minecraft.getMinecraft().fontRenderer.getStringWidth(section);
}
}
string = string.substring(string.indexOf('#') + 1);
sga = !sga;
}
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(string, x, y, colour, shadow);
}else{
l += Minecraft.getMinecraft().fontRenderer.drawString(string, x, y, colour, shadow);
}
return l;
}
l += Minecraft.getMinecraft().standardGalacticFontRenderer.drawString(string, x, y, colour, shadow);
}else{
l += Minecraft.getMinecraft().fontRenderer.drawString(string, x, y, colour, shadow);
}
return l;
}
@Override
public int getStringWidth(String string){
int l = 0;
boolean sga = false;
while(string.indexOf('#') > -1){
String section = string.substring(0, string.indexOf('#'));
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(section);
}else{
l += Minecraft.getMinecraft().fontRenderer.getStringWidth(section);
}
l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(section);
}else{
l += Minecraft.getMinecraft().fontRenderer.getStringWidth(section);
}
string = string.substring(string.indexOf('#') + 1);
sga = !sga;
}
if(sga){
l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(string);
}else{
l += Minecraft.getMinecraft().fontRenderer.getStringWidth(string);
}
return l;
l += Minecraft.getMinecraft().standardGalacticFontRenderer.getStringWidth(string);
}else{
l += Minecraft.getMinecraft().fontRenderer.getStringWidth(string);
}
return l;
}
// This doesn't work the same way yet
@Override
public void drawSplitString(String string, int x, int y, int width, int colour){
public void drawSplitString(String string, int x, int y, int width, int colour){
if(string.contains("#")){
Minecraft.getMinecraft().standardGalacticFontRenderer.drawSplitString(string.substring(1), x, y, width, colour);
}else{
Minecraft.getMinecraft().fontRenderer.drawSplitString(string, x, y, width, colour);
}
}
Minecraft.getMinecraft().standardGalacticFontRenderer.drawSplitString(string.substring(1), x, y, width,
colour);
}else{
Minecraft.getMinecraft().fontRenderer.drawSplitString(string, x, y, width, colour);
}
}
}
@@ -1,55 +0,0 @@
package electroblob.wizardry.client;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.audio.MovingSound;
import net.minecraft.entity.Entity;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
@SideOnly(Side.CLIENT)
public class MovingSoundEntity extends MovingSound
{
private final Entity source;
private float pitch = 0.0F;
public MovingSoundEntity(Entity entity, String soundName, float volume, float pitch, boolean repeat)
{
super(new ResourceLocation(soundName));
this.source = entity;
this.repeat = repeat;
this.volume = volume;
this.field_147663_c = pitch;
this.field_147665_h = 0;
}
/**
* Updates the JList with a new model.
*/
public void update()
{
if (this.source.isDead && repeat)
{
this.donePlaying = true;
}
else
{
this.xPosF = (float)this.source.posX;
this.yPosF = (float)this.source.posY;
this.zPosF = (float)this.source.posZ;
float f = MathHelper.sqrt_double(this.source.motionX * this.source.motionX + this.source.motionY * this.source.motionY + this.source.motionZ * this.source.motionZ);
// Is this something to do with the Doppler effect?
if ((double)f >= 0.01D)
{
this.pitch = MathHelper.clamp_float(this.pitch + 0.0025F, 0.0F, 1.0F);
this.volume = 0.0F + MathHelper.clamp_float(f, 0.0F, 0.5F) * 0.7F;
}
else
{
//this.pitch = 0.0F;
//this.volume = 0.0F;
}
}
}
}
@@ -0,0 +1,42 @@
package electroblob.wizardry.client;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
@EventBusSubscriber(Side.CLIENT)
public class ScreenShakeHandler {
/** The remaining time for which the screen shake effect will be active. */
private static int screenShakeCounter = 0;
private static final float SHAKINESS = 0.5f;
/** Starts the client-side screen shake effect. */
public static void shakeScreen(float intensity){
if(Wizardry.settings.screenShake){
screenShakeCounter = (int)(intensity / SHAKINESS);
Minecraft.getMinecraft().player.rotationPitch -= intensity * 0.5f; // Start halfway down
}
}
@SubscribeEvent
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){
if(event.player == Minecraft.getMinecraft().player && event.phase == TickEvent.Phase.END){
if(Wizardry.settings.screenShake){
if(screenShakeCounter > 0){
float magnitude = screenShakeCounter * SHAKINESS;
Minecraft.getMinecraft().player.rotationPitch += screenShakeCounter % 2 == 0 ? magnitude : -magnitude;
screenShakeCounter--;
}
}else{
screenShakeCounter = 0;
}
}
}
}
@@ -1,793 +1,222 @@
package electroblob.wizardry.client;
import org.lwjgl.opengl.GL11;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import electroblob.wizardry.ExtendedPlayer;
import electroblob.wizardry.WandHelper;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryUtilities;
import electroblob.wizardry.entity.EntityShield;
import electroblob.wizardry.item.ItemSpectralArmour;
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
import electroblob.wizardry.data.DispenserCastingData;
import electroblob.wizardry.data.SpellEmitterData;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.item.ItemFlamecatcher;
import electroblob.wizardry.item.ItemSpectralBow;
import electroblob.wizardry.item.ItemWand;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.spell.Flight;
import electroblob.wizardry.spell.ShadowWard;
import electroblob.wizardry.spell.Shield;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.potion.PotionSlowTime;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.spell.Possession;
import electroblob.wizardry.spell.SixthSense;
import electroblob.wizardry.spell.SlowTime;
import electroblob.wizardry.spell.Transience;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.EntityLiving;
import net.minecraft.item.Item;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.client.event.FOVUpdateEvent;
import net.minecraftforge.client.event.InputUpdateEvent;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
import org.lwjgl.opengl.GL11;
/** Event handler responsible for all client-side only events, mostly rendering.
* @since Wizardry 1.0 */
public class WizardryClientEventHandler {
import java.util.ArrayList;
import java.util.List;
private static final ResourceLocation shieldTexture = new ResourceLocation("wizardry:textures/entity/shield.png");
private static final ResourceLocation wingTexture = new ResourceLocation("wizardry:textures/entity/wing.png");
private static final ResourceLocation shadowWardTexture = new ResourceLocation("wizardry:textures/entity/shadow_ward.png");
private static final ResourceLocation sixthSenseTexture = new ResourceLocation("wizardry:textures/entity/sixth_sense.png");
private static final ResourceLocation sixthSenseOverlayTexture = new ResourceLocation("wizardry:textures/gui/sixth_sense_overlay.png");
private static final ResourceLocation frostOverlayTexture = new ResourceLocation("wizardry:textures/gui/frost_overlay.png");
private static final ResourceLocation pointerTexture = new ResourceLocation("wizardry:textures/entity/pointer.png");
private static final ResourceLocation targetPointerTexture = new ResourceLocation("wizardry:textures/entity/target_pointer.png");
/**
* General-purpose client-side event handler for things that don't fit anywhere else or groups of related behaviours
* that are better kept together.
*
* @author Electroblob
* @since Wizardry 1.0
*/
//@SideOnly(Side.CLIENT)
@Mod.EventBusSubscriber(Side.CLIENT)
public final class WizardryClientEventHandler {
private WizardryClientEventHandler(){} // No instances!
// Tick Events
// ===============================================================================================================
@SubscribeEvent
public void onRenderPlayerArmourEvent(RenderPlayerEvent.SetArmorModel event){
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){
ItemStack stack = event.entityPlayer.inventory.armorInventory[event.slot];
if(event.player == Minecraft.getMinecraft().player && event.phase == TickEvent.Phase.END){
if(stack != null && stack.getItem() instanceof ItemSpectralArmour){
GL11.glEnable(GL11.GL_BLEND);
}
}
// Reset shaders if their respective potions aren't active
// This is a player so the potion effects are synced by vanilla
if(Minecraft.getMinecraft().entityRenderer.getShaderGroup() != null){ // IntelliJ is wrong, this can be null
// Shift-scrolling to change spells
@SubscribeEvent
public void onMouseEvent(MouseEvent event){
if(Minecraft.getMinecraft().inGameHasFocus && Minecraft.getMinecraft().thePlayer.getHeldItem() != null
&& Minecraft.getMinecraft().thePlayer.getHeldItem().getItem() instanceof ItemWand && event.dwheel != 0
&& Minecraft.getMinecraft().thePlayer.isSneaking() && Wizardry.enableShiftScrolling){
String activeShader = Minecraft.getMinecraft().entityRenderer.getShaderGroup().getShaderGroupName();
event.setCanceled(true);
if((activeShader.equals(SlowTime.SHADER.toString()) && !Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.slow_time))
|| (activeShader.equals(SixthSense.SHADER.toString()) && !Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.sixth_sense))
|| (activeShader.equals(Transience.SHADER.toString()) && !Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.transience))){
if(event.dwheel > 0){
// Packet building
IMessage msg = new PacketControlInput.Message(2);
WizardryPacketHandler.net.sendToServer(msg);
if(activeShader.equals(SixthSense.SHADER.toString())
|| activeShader.equals(Transience.SHADER.toString())) RenderBlinkEffect.playBlinkEffect();
}else if(event.dwheel < 0){
// Packet building
IMessage msg = new PacketControlInput.Message(1);
WizardryPacketHandler.net.sendToServer(msg);
}
}
}
@SubscribeEvent
public void onFOVUpdateEvent(FOVUpdateEvent event){
// Bow zoom. Taken directly from EntityPlayerSP so it works exactly like vanilla.
if (event.entity.isUsingItem() && event.entity.getItemInUse().getItem() instanceof ItemSpectralBow)
{
int i = event.entity.getItemInUseDuration();
float f1 = (float)i / 20.0F;
if (f1 > 1.0F)
{
f1 = 1.0F;
}
else
{
f1 *= f1;
}
event.newfov *= 1.0F - f1 * 0.15F;
}
}
// Third person
@SubscribeEvent
public void onRenderPlayerEvent(RenderPlayerEvent.Specials.Post event){
renderShieldIfActive(event.entityPlayer);
renderWingsIfActive(event.entityPlayer, event.partialRenderTick);
renderShadowWardIfActive(event.entityPlayer);
}
// First person
@SubscribeEvent
public void onRenderWorldLastEvent(RenderWorldLastEvent event){
// Now only fires in first person.
if(Minecraft.getMinecraft().gameSettings.thirdPersonView == 0){
renderShieldFirstPerson(Minecraft.getMinecraft().thePlayer);
renderShadowWardFirstPerson(Minecraft.getMinecraft().thePlayer);
}
}
@SubscribeEvent
public void onRenderLivingEvent(RenderLivingEvent.Post event){
/*
// Frost effect
if(event.entity.isPotionActive(Wizardry.frost)){
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
float someScalingFactor = 0.0625f;
float yaw = event.entity.prevRotationYaw;
//int brightness = event.entity.getBrightnessForRender(0);
//int j = brightness % 65536;
//int k = brightness / 65536;
//OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F);
//GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glTranslated(event.x, event.y, event.z);
GL11.glRotatef(-yaw + 180, 0F, 1F, 0F);
Render render = RenderManager.instance.getEntityRenderObject(event.entity);
RendererLivingEntity renderliving = event.renderer;
// Reflection
try {
Timer timer = ReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "timer");
// Chooses the appropriate zombie model, normal or villager
// Fixed by moving before the model fields are accessed
if(render instanceof RenderZombie && event.entity instanceof EntityZombie){
// The second argument is never used...
ReflectionHelper.findMethod(RenderZombie.class, (RenderZombie)render, new String[]{"func_82427_a"}, EntityZombie.class)
.invoke(renderliving, (EntityZombie)event.entity);
Minecraft.getMinecraft().entityRenderer.stopUseShader();
}
// Turns out that java automatically infers the type parameter T in this method from the type
// I am assigning the returned value to. Neat!
ModelBase mainModel = ReflectionHelper.getPrivateValue(RendererLivingEntity.class, renderliving, "mainModel");
mainModel.isRiding = event.entity.isRiding();
mainModel.isChild = event.entity.isChild();
}
}
}
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glScalef(-1.0F, -1.0F, 1.0F);
// The classes referenced here used to handle their own client tick events, but since they're not client-only
// classes, that crashed the dedicated server...
@SubscribeEvent
public static void onClientTickEvent(TickEvent.ClientTickEvent event){
// The second argument is never used...
ReflectionHelper.findMethod(RendererLivingEntity.class, renderliving, new String[]{"preRenderCallback"}, EntityLivingBase.class, float.class)
.invoke(renderliving, event.entity, someScalingFactor);
if(event.phase == TickEvent.Phase.END && !net.minecraft.client.Minecraft.getMinecraft().isGamePaused()){
// Why is this -1.5f? No idea!
GL11.glTranslatef(0, -1.5f, 0);
float f6 = event.entity.prevLimbSwingAmount + (event.entity.limbSwingAmount - event.entity.prevLimbSwingAmount) * timer.renderPartialTicks;
float f7 = event.entity.limbSwing - event.entity.limbSwingAmount * (1.0F - timer.renderPartialTicks);
World world = net.minecraft.client.Minecraft.getMinecraft().world;
if (event.entity.isChild())
{
f7 *= 3.0F;
}
if(world == null) return;
if (f6 > 1.0F)
{
f6 = 1.0F;
}
mainModel.setLivingAnimations(event.entity, f7, f6, timer.renderPartialTicks);
// 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);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glColor4f(0.5f, 0.7f, 1, 0.5f);
mainModel.render(event.entity, f7, f6, 0, 0, 0, someScalingFactor);
GL11.glDepthMask(true);
// 'Pokemon' exception handling... Because why not?!
} catch (Exception e) {
System.err.println("Something went very wrong! Error while rendering frost effect:");
e.printStackTrace();
for(TileEntity tileentity : tileEntities){
if(tileentity instanceof TileEntityDispenser){
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
DispenserCastingData.get((TileEntityDispenser)tileentity).update();
}
}
}
GL11.glDisable(GL11.GL_ALPHA_TEST);
GL11.glDisable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glPopMatrix();
SpellEmitterData.update(world);
PotionSlowTime.cleanUpEntities(world);
}
*/
Minecraft mc = Minecraft.getMinecraft();
ExtendedPlayer properties = ExtendedPlayer.get(mc.thePlayer);
MovingObjectPosition rayTrace = WizardryUtilities.standardEntityRayTrace(mc.theWorld, mc.thePlayer, 16);
// Target selection pointer
if(mc.thePlayer.isSneaking() && mc.thePlayer.getHeldItem() != null
&& mc.thePlayer.getHeldItem().getItem() instanceof ItemWand && rayTrace != null
&& rayTrace.entityHit instanceof EntityLivingBase && rayTrace.entityHit == event.entity
&& properties != null && properties.selectedMinion != null){
Tessellator tessellator = Tessellator.instance;
}
GL11.glPushMatrix();
// Input and Controls
// ===============================================================================================================
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glDisable(GL11.GL_LIGHTING);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
// Disabling depth test allows it to be seen through everything.
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glColor4f(1, 1, 1, 1);
@SubscribeEvent
public static void onMouseEvent(MouseEvent event){
GL11.glTranslated(event.x, event.y + event.entity.height + 0.5, event.z);
// Prevents the player looking around when paralysed
if(Minecraft.getMinecraft().player.isPotionActive(WizardryPotions.paralysis)
&& Minecraft.getMinecraft().inGameHasFocus){
event.setCanceled(true);
Minecraft.getMinecraft().player.prevRotationYaw = 0;
Minecraft.getMinecraft().player.prevRotationPitch = 0;
Minecraft.getMinecraft().player.rotationYaw = 0;
Minecraft.getMinecraft().player.rotationPitch = 0;
}
}
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = mc.gameSettings.thirdPersonView == 2 ? RenderManager.instance.playerViewX : -RenderManager.instance.playerViewX;
GL11.glRotatef(180 - RenderManager.instance.playerViewY, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(yaw, 1.0F, 0.0F, 0.0F);
tessellator.startDrawingQuads();
mc.renderEngine.bindTexture(targetPointerTexture);
tessellator.addVertexWithUV(-0.2, 0.24, 0, 0, 0);
tessellator.addVertexWithUV(0.2, 0.24, 0, 9f/16f, 0);
tessellator.addVertexWithUV(0.2, -0.24, 0, 9f/16f, 11f/16f);
tessellator.addVertexWithUV(-0.2, -0.24, 0, 0, 11f/16f);
tessellator.draw();
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glPopMatrix();
// This event is called every tick, not just when a movement key is pressed
@SubscribeEvent
public static void onInputUpdateEvent(InputUpdateEvent event){
// Prevents the player moving when paralysed
if(event.getEntityPlayer().isPotionActive(WizardryPotions.paralysis)){
event.getMovementInput().moveForward = 0;
event.getMovementInput().moveStrafe = 0;
event.getMovementInput().jump = false;
event.getMovementInput().sneak = false;
}
// Summoned creature selection pointer
if(properties != null && properties.selectedMinion != null && properties.selectedMinion.get() == event.entity){
Tessellator tessellator = Tessellator.instance;
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glDisable(GL11.GL_LIGHTING);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
// Disabling depth test allows it to be seen through everything.
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glColor4f(1, 1, 1, 1);
GL11.glTranslated(event.x, event.y + event.entity.height + 0.5, event.z);
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = mc.gameSettings.thirdPersonView == 2 ? RenderManager.instance.playerViewX : -RenderManager.instance.playerViewX;
GL11.glRotatef(180 - RenderManager.instance.playerViewY, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(yaw, 1.0F, 0.0F, 0.0F);
tessellator.startDrawingQuads();
mc.renderEngine.bindTexture(pointerTexture);
tessellator.addVertexWithUV(-0.2, 0.24, 0, 0, 0);
tessellator.addVertexWithUV(0.2, 0.24, 0, 9f/16f, 0);
tessellator.addVertexWithUV(0.2, -0.24, 0, 9f/16f, 11f/16f);
tessellator.addVertexWithUV(-0.2, -0.24, 0, 0, 11f/16f);
tessellator.draw();
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glPopMatrix();
if(ItemArtefact.isArtefactActive(event.getEntityPlayer(), WizardryItems.charm_move_speed)
&& event.getEntityPlayer().isHandActive()
&& event.getEntityPlayer().getActiveItemStack().getItem() instanceof ItemWand){
// Normally speed is set to 20% when using items, this makes it 80%
event.getMovementInput().moveStrafe *= 4;
event.getMovementInput().moveForward *= 4;
}
// Sixth sense
if(mc.thePlayer.isPotionActive(Wizardry.sixthSense) && event.entity != mc.thePlayer
&& mc.thePlayer.getActivePotionEffect(Wizardry.sixthSense) != null
&& event.entity.getDistanceToEntity(mc.thePlayer) < 20*(1+mc.thePlayer.getActivePotionEffect(Wizardry.sixthSense).getAmplifier()*Wizardry.RANGE_INCREASE_PER_LEVEL)){
}
Tessellator tessellator = Tessellator.instance;
// Rendering
// ===============================================================================================================
GL11.glPushMatrix();
@SubscribeEvent
public static void onRenderHandEvent(RenderHandEvent event){
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glDisable(GL11.GL_LIGHTING);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// Disabling depth test allows it to be seen through everything.
GL11.glDisable(GL11.GL_DEPTH_TEST);
// Hide the player's empty hand in first-person when possessing
EntityLiving victim = Possession.getPossessee(Minecraft.getMinecraft().player);
GL11.glTranslated(event.x, event.y + event.entity.height * 0.6, event.z);
if(victim != null){
// This counteracts the reverse rotation behaviour when in front f5 view.
// Fun fact: this is a bug with vanilla too! Look at a snowball in front f5 view, for example.
float yaw = mc.gameSettings.thirdPersonView == 2 ? RenderManager.instance.playerViewX : -RenderManager.instance.playerViewX;
GL11.glRotatef(180 - RenderManager.instance.playerViewY, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(yaw, 1.0F, 0.0F, 0.0F);
victim.rotationYawHead = Minecraft.getMinecraft().player.rotationYaw;
tessellator.startDrawingQuads();
mc.renderEngine.bindTexture(sixthSenseTexture);
tessellator.addVertexWithUV(-0.6, 0.6, 0, 0, 0);
tessellator.addVertexWithUV(0.6, 0.6, 0, 1, 0);
tessellator.addVertexWithUV(0.6, -0.6, 0, 1, 1);
tessellator.addVertexWithUV(-0.6, -0.6, 0, 0, 1);
tessellator.draw();
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glDisable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glPopMatrix();
if(Minecraft.getMinecraft().player.getHeldItemMainhand().isEmpty()){
event.setCanceled(true);
}
}
}
@SubscribeEvent
public void onRenderGameOverlayEvent(RenderGameOverlayEvent.Post event){
if(event.type == RenderGameOverlayEvent.ElementType.HELMET
&& Minecraft.getMinecraft().thePlayer.isPotionActive(Wizardry.sixthSense)){
public static void onFOVUpdateEvent(FOVUpdateEvent event){
GL11.glPushMatrix();
// Bow zoom. Taken directly from AbstractClientPlayer so it works exactly like vanilla.
if(event.getEntity().isHandActive()){
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDepthMask(false);
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glDisable(GL11.GL_ALPHA_TEST);
Minecraft.getMinecraft().renderEngine.bindTexture(sixthSenseOverlayTexture);
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0.0D, (double)event.resolution.getScaledHeight(), -90.0D, 0.0D, 1.0D);
tessellator.addVertexWithUV((double)event.resolution.getScaledWidth(), (double)event.resolution.getScaledHeight(), -90.0D, 1.0D, 1.0D);
tessellator.addVertexWithUV((double)event.resolution.getScaledWidth(), 0.0D, -90.0D, 1.0D, 0.0D);
tessellator.addVertexWithUV(0.0D, 0.0D, -90.0D, 0.0D, 0.0D);
tessellator.draw();
GL11.glDepthMask(true);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
Item item = event.getEntity().getActiveItemStack().getItem();
GL11.glPopMatrix();
}
if(item instanceof ItemSpectralBow || item instanceof ItemFlamecatcher){
if(event.type == RenderGameOverlayEvent.ElementType.HELMET
&& Minecraft.getMinecraft().thePlayer.isPotionActive(Wizardry.frost)){
int maxUseTicks = event.getEntity().getItemInUseMaxCount();
GL11.glPushMatrix();
float maxUseSeconds = (float)maxUseTicks / (item instanceof ItemFlamecatcher ? ItemFlamecatcher.DRAW_TIME : 20);
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDepthMask(false);
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glDisable(GL11.GL_ALPHA_TEST);
Minecraft.getMinecraft().renderEngine.bindTexture(frostOverlayTexture);
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0.0D, (double)event.resolution.getScaledHeight(), -90.0D, 0.0D, 1.0D);
tessellator.addVertexWithUV((double)event.resolution.getScaledWidth(), (double)event.resolution.getScaledHeight(), -90.0D, 1.0D, 1.0D);
tessellator.addVertexWithUV((double)event.resolution.getScaledWidth(), 0.0D, -90.0D, 1.0D, 0.0D);
tessellator.addVertexWithUV(0.0D, 0.0D, -90.0D, 0.0D, 0.0D);
tessellator.draw();
GL11.glDepthMask(true);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
if(maxUseSeconds > 1.0F){
maxUseSeconds = 1.0F;
}else{
maxUseSeconds = maxUseSeconds * maxUseSeconds;
}
GL11.glPopMatrix();
event.setNewfov(event.getFov() * 1.0F - maxUseSeconds * 0.15F);
}
}
}
private static void renderShadowWardFirstPerson(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getHeldItem();
if(ExtendedPlayer.get(entityplayer).currentlyCasting() instanceof ShadowWard || (entityplayer.isUsingItem() && wand != null && wand.getItemDamage() < wand.getMaxDamage()
&& wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_LIGHTING);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GL11.glRotatef(-1*entityplayer.rotationYaw, 0, 1, 0);
GL11.glRotatef(entityplayer.rotationPitch, 1, 0, 0);
Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture);
Tessellator tessellator = Tessellator.instance;
GL11.glPushMatrix();
GL11.glTranslated(0, -0.3, 1.2);
GL11.glRotated(entityplayer.worldObj.getWorldTime()*-2, 0, 0, 1);
GL11.glScaled(1.1, 1.1, 1.1);
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(-0.5, 0.5, -0.5, 0, 0);
tessellator.addVertexWithUV(0.5, 0.5, -0.5, 1, 0);
tessellator.addVertexWithUV(0.5, -0.5, -0.5, 1, 1);
tessellator.addVertexWithUV(-0.5, -0.5, -0.5, 0, 1);
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(-0.5, 0.5, -0.5, 0, 0);
tessellator.addVertexWithUV(-0.5, -0.5, -0.5, 0, 1);
tessellator.addVertexWithUV(0.5, -0.5, -0.5, 1, 1);
tessellator.addVertexWithUV(0.5, 0.5, -0.5, 1, 0);
tessellator.draw();
GL11.glPopMatrix();
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_BLEND);
GL11.glPopMatrix();
}
}
private static void renderShadowWardIfActive(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getHeldItem();
if(ExtendedPlayer.get(entityplayer).currentlyCasting() instanceof ShadowWard || (entityplayer.isUsingItem() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof ShadowWard)){
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_LIGHTING);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GL11.glRotatef(180, 0, 1, 0);
//GL11.glRotatef(entityplayer.rotationYaw, 0, 1, 0);
//GL11.glRotatef(-entityplayer.rotationPitch, 1, 0, 0);
Minecraft.getMinecraft().renderEngine.bindTexture(shadowWardTexture);
Tessellator tessellator = Tessellator.instance;
GL11.glPushMatrix();
// was 0, -0.3, 1.2
GL11.glTranslated(0, 0, 1.2);
GL11.glRotated(entityplayer.worldObj.getWorldTime()*-2, 0, 0, 1);
GL11.glScaled(1.1, 1.1, 1.1);
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(-0.5, 0.5, -0.5, 0, 0);
tessellator.addVertexWithUV(0.5, 0.5, -0.5, 1, 0);
tessellator.addVertexWithUV(0.5, -0.5, -0.5, 1, 1);
tessellator.addVertexWithUV(-0.5, -0.5, -0.5, 0, 1);
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(-0.5, 0.5, -0.5, 0, 0);
tessellator.addVertexWithUV(-0.5, -0.5, -0.5, 0, 1);
tessellator.addVertexWithUV(0.5, -0.5, -0.5, 1, 1);
tessellator.addVertexWithUV(0.5, 0.5, -0.5, 1, 0);
tessellator.draw();
GL11.glPopMatrix();
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_BLEND);
GL11.glPopMatrix();
}
}
private static void renderWingsIfActive(EntityPlayer entityplayer, float partialTickTime){
ItemStack wand = entityplayer.getHeldItem();
if(ExtendedPlayer.get(entityplayer).currentlyCasting() instanceof Flight || (entityplayer.isUsingItem() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Flight)){
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_LIGHTING);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GL11.glRotatef(-entityplayer.rotationYawHead, 0, 1, 0);
GL11.glRotatef(entityplayer.rotationYaw, 0, 1, 0);
GL11.glRotatef(180, 1, 0, 0);
Minecraft.getMinecraft().renderEngine.bindTexture(wingTexture);
Tessellator tessellator = Tessellator.instance;
GL11.glPushMatrix();
GL11.glTranslated(0.1, -1.0, -0.15);
GL11.glRotatef(20 + 20*(float)Math.sin(entityplayer.worldObj.getWorldTime()*0.3), 0, 1, 0);
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, 2, 0, 0, 0);
tessellator.addVertexWithUV(2, 2, 0, 1, 0);
tessellator.addVertexWithUV(2, 0, 0, 1, 1);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, 2, 0, 0, 0);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.addVertexWithUV(2, 0, 0, 1, 1);
tessellator.addVertexWithUV(2, 2, 0, 1, 0);
tessellator.draw();
GL11.glPopMatrix();
GL11.glPushMatrix();
GL11.glTranslated(-0.1, -1.0, -0.15);
GL11.glRotatef(-200 - 20*(float)Math.sin(entityplayer.worldObj.getWorldTime()*0.3), 0, 1, 0);
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, 2, 0, 0, 0);
tessellator.addVertexWithUV(2, 2, 0, 1, 0);
tessellator.addVertexWithUV(2, 0, 0, 1, 1);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.draw();
tessellator.startDrawingQuads();
tessellator.addVertexWithUV(0, 2, 0, 0, 0);
tessellator.addVertexWithUV(0, 0, 0, 0, 1);
tessellator.addVertexWithUV(2, 0, 0, 1, 1);
tessellator.addVertexWithUV(2, 2, 0, 1, 0);
tessellator.draw();
GL11.glPopMatrix();
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glDisable(GL11.GL_BLEND);
GL11.glPopMatrix();
}
}
private static void renderShieldFirstPerson(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getHeldItem();
if(ExtendedPlayer.get(entityplayer).shield != null && (ExtendedPlayer.get(entityplayer).currentlyCasting() instanceof Shield || (entityplayer.isUsingItem() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Shield))){
double x = entityplayer.posX;
double y = entityplayer.posY;
double z = entityplayer.posZ;
EntityShield shield = (EntityShield)ExtendedPlayer.get(entityplayer).shield;
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA);
GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glDisable(GL11.GL_LIGHTING);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GL11.glTranslated(0, -0.3, 0);
GL11.glRotatef(-1*entityplayer.rotationYaw, 0, 1, 0);
GL11.glRotatef(entityplayer.rotationPitch, 1, 0, 0);
GL11.glTranslated(0, 0, 0.8);
Tessellator tessellator = Tessellator.instance;
Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture);
renderShield(tessellator, -1);
// Enchantment effect
/*
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_LIGHTING);
//this.bindTexture(RES_ITEM_GLINT);
GL11.glBlendFunc(GL11.GL_SRC_COLOR, GL11.GL_ONE);
float f7 = 0.76F;
GL11.glColor4f(0.5F * f7, 0.25F * f7, 0.8F * f7, 1.0F);
float f8 = 0.125F;
//GL11.glScalef(f8, f8, f8);
float f9 = (float)(Minecraft.getSystemTime() % 3000L) / 3000.0F * 0.8f;
//GL11.glTranslatef(f9, 0.0F, 0.0F);
//GL11.glRotatef(-50.0F, 0.0F, 0.0F, 1.0F);
//this.renderShield(tessellator, f9);
GL11.glPopMatrix();
*/
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glShadeModel(GL11.GL_FLAT);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glDisable(GL11.GL_BLEND);
//RenderHelper.enableStandardItemLighting();
GL11.glPopMatrix();
}
}
private static void renderShieldIfActive(EntityPlayer entityplayer){
ItemStack wand = entityplayer.getHeldItem();
if(ExtendedPlayer.get(entityplayer).shield != null && (ExtendedPlayer.get(entityplayer).currentlyCasting() instanceof Shield || (entityplayer.isUsingItem() && wand != null
&& wand.getItemDamage() < wand.getMaxDamage() && wand.getItem() instanceof ItemWand && WandHelper.getCurrentSpell(wand) instanceof Shield))){
double x = entityplayer.posX;
double y = entityplayer.posY;
double z = entityplayer.posZ;
EntityShield shield = (EntityShield)ExtendedPlayer.get(entityplayer).shield;
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_SRC_ALPHA);
GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glDisable(GL11.GL_LIGHTING);
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240f, 240f);
GL11.glTranslated(0, 0, 0);
GL11.glRotatef(180, 0, 1, 0);
//GL11.glRotatef(entityplayer.rotationYaw, 0, 1, 0);
//GL11.glRotatef(-entityplayer.rotationPitch, 1, 0, 0);
GL11.glTranslated(0, 0, 0.8);
Tessellator tessellator = Tessellator.instance;
Minecraft.getMinecraft().renderEngine.bindTexture(shieldTexture);
renderShield(tessellator, -1);
// Enchantment effect
/*
GL11.glPushMatrix();
GL11.glDisable(GL11.GL_LIGHTING);
//this.bindTexture(RES_ITEM_GLINT);
GL11.glBlendFunc(GL11.GL_SRC_COLOR, GL11.GL_ONE);
float f7 = 0.76F;
GL11.glColor4f(0.5F * f7, 0.25F * f7, 0.8F * f7, 1.0F);
float f8 = 0.125F;
//GL11.glScalef(f8, f8, f8);
float f9 = (float)(Minecraft.getSystemTime() % 3000L) / 3000.0F * 0.8f;
//GL11.glTranslatef(f9, 0.0F, 0.0F);
//GL11.glRotatef(-50.0F, 0.0F, 0.0F, 1.0F);
//this.renderShield(tessellator, f9);
GL11.glPopMatrix();
*/
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glShadeModel(GL11.GL_FLAT);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glDisable(GL11.GL_BLEND);
//RenderHelper.enableStandardItemLighting();
GL11.glPopMatrix();
}
}
private static void renderShield(Tessellator tessellator, float textureOffset){
double widthOuter = 0.6d;
double heightOuter = 0.7d;
double widthInner = 0.3d;
double heightInner = 0.4d;
double depth = 0.2d;
double textureSection = 1.0d;
double textureU = 0.0d;
if(textureOffset != -1){
textureSection = 0.2d;
textureU = textureOffset;
}
tessellator.startDrawing(5);
tessellator.setColorRGBA(0, 0, 0, 255);
tessellator.addVertexWithUV(-widthOuter, heightOuter - 0.3, -depth, 0, 0);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(-widthInner, heightInner, 0, textureU, 0.2);
tessellator.setColorRGBA(0, 0, 0, 255);
tessellator.addVertexWithUV(-widthOuter + 0.3, heightOuter, -depth, 0, 0);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(-widthInner, heightInner, 0, textureU, 0.2);
tessellator.setColorRGBA(0, 0, 0, 255);
tessellator.addVertexWithUV(widthOuter - 0.3, heightOuter, -depth, 1, 0);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(widthInner, heightInner, 0, textureU + textureSection, 0.2);
tessellator.setColorRGBA(0, 0, 0, 255);
tessellator.addVertexWithUV(widthOuter, heightOuter - 0.3, -depth, 1, 0);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(widthInner, heightInner, 0, textureU + textureSection, 0.2);
tessellator.setColorRGBA(0, 0, 0, 255);
tessellator.addVertexWithUV(widthOuter, -heightOuter + 0.3, -depth, 1, 1);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(widthInner, -heightInner, 0, textureU + textureSection, 0.8);
tessellator.setColorRGBA(0, 0, 0, 255);
tessellator.addVertexWithUV(widthOuter - 0.3, -heightOuter, -depth, 1, 1);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(widthInner, -heightInner, 0, textureU + textureSection, 0.8);
tessellator.setColorRGBA(0, 0, 0, 255);
tessellator.addVertexWithUV(-widthOuter + 0.3, -heightOuter, -depth, 0, 1);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(-widthInner, -heightInner, 0, textureU, 0.8);
tessellator.setColorRGBA(0, 0, 0, 255);
tessellator.addVertexWithUV(-widthOuter, -heightOuter + 0.3, -depth, 0, 1);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(-widthInner, -heightInner, 0, textureU, 0.8);
tessellator.setColorRGBA(0, 0, 0, 255);
tessellator.addVertexWithUV(-widthOuter, heightOuter - 0.3, -depth, 0, 0);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(-widthInner, heightInner, 0, textureU, 0.2);
/**
* Renders an overlay across the entire screen.
* @param resolution The screen resolution
* @param texture The overlay texture to display
*/
public static void renderScreenOverlay(ScaledResolution resolution, ResourceLocation texture){
GlStateManager.pushMatrix();
GlStateManager.disableDepth();
GlStateManager.depthMask(false);
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
buffer.pos(0, resolution.getScaledHeight(), -90).tex(0, 1).endVertex();
buffer.pos(resolution.getScaledWidth(), resolution.getScaledHeight(), -90).tex(1, 1).endVertex();
buffer.pos(resolution.getScaledWidth(), 0, -90).tex(1, 0).endVertex();
buffer.pos(0, 0, -90).tex(0, 0).endVertex();
tessellator.draw();
GlStateManager.depthMask(true);
GlStateManager.enableDepth();
tessellator.startDrawing(5);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(-widthInner, heightInner, 0, textureU, 0.2);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(widthInner, heightInner, 0, textureU + textureSection, 0.2);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(-widthInner, -heightInner, 0, textureU, 0.8);
tessellator.setColorOpaque(200, 200, 255);
tessellator.addVertexWithUV(widthInner, -heightInner, 0, textureU + textureSection, 0.8);
tessellator.draw();
GlStateManager.popMatrix();
}
}
@@ -0,0 +1,149 @@
package electroblob.wizardry.client;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.gui.GuiSpellDisplay;
import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.PacketSpellQuickAccess;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.WizardrySounds;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
/** Event handler class responsible for handling wizardry's controls. */
//@SideOnly(Side.CLIENT)
@Mod.EventBusSubscriber(Side.CLIENT)
public class WizardryControlHandler {
static boolean NkeyPressed = false;
static boolean BkeyPressed = false;
static boolean[] quickAccessKeyPressed = new boolean[ClientProxy.SPELL_QUICK_ACCESS.length];
// Changed to a tick event to allow mouse button keybinds
// The 'lag' that happened previously was actually because the code only fired when a keyboard key was pressed!
@SubscribeEvent
public static void onTickEvent(TickEvent.ClientTickEvent event){
if(event.phase == TickEvent.Phase.END) return; // Only really needs to be once per tick
if(Wizardry.proxy instanceof ClientProxy){
EntityPlayer player = Minecraft.getMinecraft().player;
if(player != null){
ItemStack wand = getWandInUse(player);
if(wand == null) return;
if(ClientProxy.NEXT_SPELL.isKeyDown() && Minecraft.getMinecraft().inGameHasFocus){
if(!NkeyPressed){
NkeyPressed = true;
selectNextSpell(wand);
}
}else{
NkeyPressed = false;
}
if(ClientProxy.PREVIOUS_SPELL.isKeyDown() && Minecraft.getMinecraft().inGameHasFocus){
if(!BkeyPressed){
BkeyPressed = true;
// Packet building
selectPreviousSpell(wand);
}
}else{
BkeyPressed = false;
}
for(int i = 0; i < ClientProxy.SPELL_QUICK_ACCESS.length; i++){
if(ClientProxy.SPELL_QUICK_ACCESS[i].isKeyDown() && Minecraft.getMinecraft().inGameHasFocus){
if(!quickAccessKeyPressed[i]){
quickAccessKeyPressed[i] = true;
// Packet building
selectSpell(wand, i);
}
}else{
quickAccessKeyPressed[i] = false;
}
}
}
}
}
// Shift-scrolling to change spells
@SubscribeEvent
public static void onMouseEvent(MouseEvent event){
EntityPlayer player = Minecraft.getMinecraft().player;
ItemStack wand = getWandInUse(player);
if(wand == null) return;
if(Minecraft.getMinecraft().inGameHasFocus && !wand.isEmpty() && event.getDwheel() != 0 && player.isSneaking()
&& Wizardry.settings.shiftScrolling){
event.setCanceled(true);
int d = Wizardry.settings.reverseScrollDirection ? -event.getDwheel() : event.getDwheel();
if(d > 0){
selectNextSpell(wand);
}else if(d < 0){
selectPreviousSpell(wand);
}
}
}
private static ItemStack getWandInUse(EntityPlayer player){
ItemStack wand = player.getHeldItemMainhand();
// Only bother sending packets if the player is holding a spellcasting item with more than one spell slot
if(!(wand.getItem() instanceof ISpellCastingItem) || ((ISpellCastingItem)wand.getItem()).getSpells(wand).length < 2){
wand = player.getHeldItemOffhand();
if(!(wand.getItem() instanceof ISpellCastingItem) || ((ISpellCastingItem)wand.getItem()).getSpells(wand).length < 2) return null;
}
return wand;
}
private static void selectNextSpell(ItemStack wand){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.NEXT_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
// GUI switch animation
((ISpellCastingItem)wand.getItem()).selectNextSpell(wand); // Makes sure the spell is set immediately for the client
GuiSpellDisplay.playSpellSwitchAnimation(true);
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.ITEM_WAND_SWITCH_SPELL, 1));
}
private static void selectPreviousSpell(ItemStack wand){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.PREVIOUS_SPELL_KEY);
WizardryPacketHandler.net.sendToServer(msg);
// GUI switch animation
((ISpellCastingItem)wand.getItem()).selectPreviousSpell(wand); // Makes sure the spell is set immediately for the client
GuiSpellDisplay.playSpellSwitchAnimation(false);
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.ITEM_WAND_SWITCH_SPELL, 1));
}
private static void selectSpell(ItemStack wand, int index){
// GUI switch animation
if(((ISpellCastingItem)wand.getItem()).selectSpell(wand, index)){ // Makes sure the spell is set immediately for the client
// Packet building (no point sending it unless the client-side spell selection succeeded
IMessage msg = new PacketSpellQuickAccess.Message(index);
WizardryPacketHandler.net.sendToServer(msg);
GuiSpellDisplay.playSpellSwitchAnimation(true); // This will do, it's only an animation
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.ITEM_WAND_SWITCH_SPELL, 1));
}
}
}
@@ -0,0 +1,155 @@
package electroblob.wizardry.client.animation;
import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.item.SpellActions;
import electroblob.wizardry.spell.Grapple;
import electroblob.wizardry.util.GeometryUtils;
import electroblob.wizardry.util.InventoryUtils;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction;
import net.minecraft.util.EnumHandSide;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
/**
* An animation that is associated with a particular {@link net.minecraft.item.EnumAction}. This animation will display
* when a player is using an item with that action.
* @author Electroblob
* @since Wizardry 4.3
* @see electroblob.wizardry.item.SpellActions
*/
public abstract class ActionAnimation extends Animation {
private final EnumAction action;
public ActionAnimation(EnumAction action){
super(action.name());
this.action = action;
}
@Override
public boolean shouldDisplay(EntityPlayer player, boolean firstPerson){
return !firstPerson && player.getItemInUseMaxCount() > 0 && player.getActiveItemStack().getItemUseAction() == action;
}
/** Called from the client proxy to register all of wizardry's action animations. */
public static void register(){
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.POINT){
@Override
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
// Something (probably some sort of race condition) causes getActiveItemStack to sometimes be wrong
if(player.getActiveItemStack() != player.getHeldItem(player.getActiveHand())) return;
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
float pitch = (float)Math.toRadians(player.prevRotationPitch + (player.rotationPitch - player.prevRotationPitch) * partialTicks);
float yaw = (float)Math.toRadians(player.prevRotationYawHead + (player.rotationYawHead - player.prevRotationYawHead) * partialTicks)
- (float)Math.toRadians(player.prevRenderYawOffset + (player.renderYawOffset - player.prevRenderYawOffset) * partialTicks);
float x = -((float)Math.PI / 2) + pitch + 0.2f;
float y = (side == EnumHandSide.RIGHT ? -0.25f : 0.25f) + yaw;
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
arm.setRotation(x, y, 0);
}
});
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.POINT_UP){
@Override
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
if(player.getActiveItemStack() != player.getHeldItem(player.getActiveHand())) return;
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
arm.addRotation(-2.2f, side == EnumHandSide.RIGHT ? 0.2f : -0.2f, 0);
}
});
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.POINT_DOWN){
@Override
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
float tick = player.getItemInUseMaxCount() + partialTicks; // It's not the "max" use count at all!
float y = Math.min(0.4f + tick * 0.05f, 0.7f);
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
arm.addRotation(-0.2f, side == EnumHandSide.RIGHT ? y : -y, 0);
}
});
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.SUMMON){
@Override
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
float tick = player.getItemInUseMaxCount() + partialTicks; // It's not the "max" use count at all!
float x = -Math.min(0.4f + tick * 0.2f, 2f);
((ModelRendererExtended)getArmForSide(model, EnumHandSide.RIGHT)).addRotation(x, 1.2f, 0);
((ModelRendererExtended)getArmForSide(model, EnumHandSide.LEFT)).addRotation(x, -1.2f, 0);
}
});
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.GRAPPLE){
@Override
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
WizardData data = WizardData.get(player);
RayTraceResult hit = data.getVariable(Grapple.TARGET_KEY);
if(hit == null || hit.typeOfHit == RayTraceResult.Type.MISS) return;
Vec3d target = hit.hitVec;
if(hit.entityHit instanceof EntityLivingBase){
// If the target is an entity, we need to use the entity's centre rather than the original hit position
// because the entity will have moved!
target = GeometryUtils.getCentre(hit.entityHit);
}
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
Vec3d direction = target.subtract(player.getPositionEyes(partialTicks));
float yaw = player.prevRenderYawOffset + (player.renderYawOffset - player.prevRenderYawOffset) * partialTicks;
float pitch = (float)MathHelper.atan2(MathHelper.sqrt(direction.x*direction.x + direction.z*direction.z), direction.y);
float x = pitch - (float)Math.PI * 0.9f;
float y = -(float)Math.toRadians(yaw) - (float)MathHelper.atan2(direction.x, direction.z);
y += (side == EnumHandSide.RIGHT ? -0.25f : 0.25f);
if(Math.abs(pitch) < 0.2f) y = arm.rotateAngleY;
arm.setRotation(x, y, 0);
}
});
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.IMBUE){
@Override
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
float tick = player.getItemInUseMaxCount() + partialTicks; // It's not the "max" use count at all!
float z = Math.max(1.5f - tick * 0.1f, 0.8f);
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
arm.addRotation(-1.2f, side == EnumHandSide.RIGHT ? -0.2f : 0.2f, side == EnumHandSide.RIGHT ? z : -z);
if(!player.getHeldItem(InventoryUtils.getHandForSide(player, side.opposite())).isEmpty()){
((ModelRendererExtended)getArmForSide(model, side.opposite())).addRotation(-0.8f, side == EnumHandSide.LEFT ? 0.3f : -0.3f, 0);
}
}
});
PlayerAnimator.registerAnimation(new ActionAnimation(SpellActions.THRUST){
@Override
public void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson){
if(player.getActiveItemStack() != player.getHeldItem(player.getActiveHand())) return;
EnumHandSide side = InventoryUtils.getSideForHand(player, player.getActiveHand());
ModelRendererExtended arm = (ModelRendererExtended)getArmForSide(model, side);
float y = side == EnumHandSide.RIGHT ? -0.6f : 0.6f;
arm.addRotation(-1.2f, y, 0);
if(player.getHeldItem(InventoryUtils.getHandForSide(player, side.opposite())).isEmpty()){
ModelRendererExtended otherArm = (ModelRendererExtended)getArmForSide(model, side.opposite());
otherArm.setRotation(arm.rotateAngleX - 1.2f, -arm.rotateAngleY - y, otherArm.rotateAngleZ);
}
}
});
}
}
@@ -0,0 +1,77 @@
package electroblob.wizardry.client.animation;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumHandSide;
/**
* Represents a player animation. Use one of the predefined subclasses below for common animation types, or extend this
* class directly to define a completely custom animation. Register instances of this class using
* {@link PlayerAnimator#registerAnimation(Animation)}.
* @author Electroblob
* @since Wizardry 4.3
* @see ActionAnimation
*/
public abstract class Animation {
private final String name;
public Animation(String name){
this.name = name;
}
/** Returns the name of this animation, currently only used for warning messages / debugging. */
public String getName(){
return name;
}
/**
* Returns whether this animation should be displayed for the given player. <i>Note that if two registered
* animations have overlapping conditions, both will attempt to display simultaneously, so if they both animate the
* same model part, that part may not behave as expected.</i>
* @param player The player being animated
* @param firstPerson True if the player being animated is the local client player, and they are in first-person
* view. In first-person, animations are only useful for animating the player's empty hand.
* @return True if the animation should be displayed, false if not.
*/
public abstract boolean shouldDisplay(EntityPlayer player, boolean firstPerson);
/**
* Sets the rotation of the model parts for this animation. This method is called every time the player is rendered
* when {@link Animation#shouldDisplay(EntityPlayer, boolean)} returns true.
* @param player The player being animated
* @param model The model to animate. All of the standard {@link ModelBiped} parts will already be wrapped and may
* be safely cast to {@code ModelRendererExtended} in order to override the rotations set by the model
* itself - see {@link ModelRendererExtended ModelRendererExtended} for details.
* @param partialTicks The current partial tick time
* @param firstPerson True if the player being animated is the local client player, and they are in first-person
* view. In first-person, animations are only useful for animating the player's empty hand.
*/
public abstract void setRotationAngles(EntityPlayer player, ModelBiped model, float partialTicks, boolean firstPerson);
/**
* Returns whether the boxes that form the second layer of the player's skin (for models that are instances of
* {@link net.minecraft.client.model.ModelPlayer ModelPlayer}) should automatically be set to the same angles as
* their corresponding first-layer parts.
* @param player The player being rendered, for reference
* @param firstPerson True if the player being animated is the local client player, and they are in first-person
* view. In first-person, animations are only useful for animating the player's empty hand.
* @return True to let {@link PlayerAnimator} auto-rotate the second skin layer, false to rotate them manually.
*/
public boolean autoRotateSecondLayer(EntityPlayer player, boolean firstPerson){
return true;
}
/**
* Returns the arm of the given model corresponding to the given side. Function is identical to the method of the
* same name in {@link ModelBiped}.
* @param model The model to get the arm of
* @param side The {@link EnumHandSide} to return the arm for
* @return The {@link ModelRenderer} corresponding to the given arm
*/
public static ModelRenderer getArmForSide(ModelBiped model, EnumHandSide side){
return side == EnumHandSide.LEFT ? model.bipedLeftArm : model.bipedRightArm;
}
}
@@ -0,0 +1,205 @@
package electroblob.wizardry.client.animation;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.model.ModelPlayer;
import net.minecraft.client.model.ModelRenderer;
/**
* A wrapper around {@link ModelRenderer} which can be swapped into models to allow render pre/post events to
* circumvent {@code ModelBase.setRotationAngles(...)} and set model part rotations themselves. Instances of this class
* keep a reference to the original {@code ModelRenderer} and delegate all the actual rendering to it.
* <p></p>
* {@link PlayerAnimator PlayerAnimator} does all the necessary setup with this
* class for player animations. It is also possible to set up custom animations for non-player entities with this class,
* see {@link ModelRendererExtended#wrap(ModelBiped)} and {@link ModelRendererExtended#wrap(ModelBase, ModelRenderer)}.
* @author Electroblob
* @since Wizardry 4.3
*/
public class ModelRendererExtended extends ModelRenderer {
// We probably could have copied all the fields over instead, but this way if anyone else modifies the boxes we
// won't overwrite their changes
// This way also avoids reflection because we don't need to copy private fields, which is better for performance
private ModelRenderer delegate;
private float actualRotationX;
private float actualRotationY;
private float actualRotationZ;
private float extraRotationX;
private float extraRotationY;
private float extraRotationZ;
private ModelRendererExtended(ModelBase baseModel, ModelRenderer delegate){
super(baseModel, delegate.boxName);
this.delegate = delegate;
// Copy over any public fields that might get changed
this.textureWidth = delegate.textureWidth;
this.textureHeight = delegate.textureHeight;
this.showModel = delegate.showModel;
this.isHidden = delegate.isHidden;
this.rotationPointX = delegate.rotationPointX;
this.rotationPointY = delegate.rotationPointY;
this.rotationPointZ = delegate.rotationPointZ;
this.cubeList = delegate.cubeList;
this.childModels = delegate.childModels;
this.resetRotation();
}
// Static initialisers
/**
* Replaces the given part of the given {@link ModelBase} with a new {@code ModelRendererExtended} that wraps the
* original part. This method takes care of modifying the model's box list, but <b>is unable to change any
* individual {@link ModelRenderer} fields</b> - this method instead returns the resulting
* {@code ModelRendererExtended} to be assigned to the appropriate field.
* @param model The model whose part is to be wrapped
* @param box The part of the model to wrap, must belong to the above model
* @return The resulting wrapped model part, this should be assigned to the appropriate part field in the model. If
* the given model part was already wrapped, this method simply returns it unchanged.
* @throws IllegalArgumentException if the given box does not belong to the given model
*/
public static ModelRendererExtended wrap(ModelBase model, ModelRenderer box){
if(box instanceof ModelRendererExtended) return (ModelRendererExtended)box; // Ignore already-wrapped parts
ModelRendererExtended wrapper = new ModelRendererExtended(model, box);
int index = model.boxList.indexOf(box);
if(index < 0) throw new IllegalArgumentException(String.format("The given ModelRenderer %s does not belong to the given model %s", box, model));
model.boxList.set(index, wrapper); // I doubt the order matters but we may as well put it at the same index
return wrapper;
}
/**
* Replaces the given {@link ModelBiped}'s parts with new {@code ModelRendererExtended} versions that wrap the
* original parts. If the given model is a {@link ModelPlayer}, the extra boxes for player skin overlays will also
* be wrapped.
*/
public static void wrap(ModelBiped model){
// MMmmmmmm wraps
model.bipedHead = wrap(model, model.bipedHead);
model.bipedBody = wrap(model, model.bipedBody);
model.bipedRightArm = wrap(model, model.bipedRightArm);
model.bipedLeftArm = wrap(model, model.bipedLeftArm);
model.bipedRightLeg = wrap(model, model.bipedRightLeg);
model.bipedLeftLeg = wrap(model, model.bipedLeftLeg);
model.bipedHeadwear = wrap(model, model.bipedHeadwear);
if(model instanceof ModelPlayer){
((ModelPlayer)model).bipedBodyWear = wrap(model, ((ModelPlayer)model).bipedBodyWear);
((ModelPlayer)model).bipedRightArmwear = wrap(model, ((ModelPlayer)model).bipedRightArmwear);
((ModelPlayer)model).bipedLeftArmwear = wrap(model, ((ModelPlayer)model).bipedLeftArmwear);
((ModelPlayer)model).bipedRightLegwear = wrap(model, ((ModelPlayer)model).bipedRightLegwear);
((ModelPlayer)model).bipedLeftLegwear = wrap(model, ((ModelPlayer)model).bipedLeftLegwear);
}
}
/**
* Returns whether the given {@link ModelBiped} is fully wrapped, i.e. all its parts are instances of
* {@code ModelRendererExtended}. If the given model is a {@link ModelPlayer}, this also checks the extra boxes for
* player skin overlays.
*/
public static boolean isWrapped(ModelBiped model){
boolean flag = true;
if(model instanceof ModelPlayer){
flag = flag && ((ModelPlayer)model).bipedBodyWear instanceof ModelRendererExtended;
flag = flag && ((ModelPlayer)model).bipedRightArmwear instanceof ModelRendererExtended;
flag = flag && ((ModelPlayer)model).bipedLeftArmwear instanceof ModelRendererExtended;
flag = flag && ((ModelPlayer)model).bipedRightLegwear instanceof ModelRendererExtended;
flag = flag && ((ModelPlayer)model).bipedLeftLegwear instanceof ModelRendererExtended;
}
return flag
&& model.bipedHead instanceof ModelRendererExtended
&& model.bipedBody instanceof ModelRendererExtended
&& model.bipedRightArm instanceof ModelRendererExtended
&& model.bipedLeftArm instanceof ModelRendererExtended
&& model.bipedRightLeg instanceof ModelRendererExtended
&& model.bipedLeftLeg instanceof ModelRendererExtended
&& model.bipedHeadwear instanceof ModelRendererExtended;
}
/** Resets the rotation of this model part to the angle set by the parent model. */
public void resetRotation(){
this.actualRotationX = Float.NaN;
this.actualRotationY = Float.NaN;
this.actualRotationZ = Float.NaN;
this.extraRotationX = 0;
this.extraRotationY = 0;
this.extraRotationZ = 0;
}
/** Sets the rotation of this model part, which will overwrite the angle set by the parent model. */
public void setRotation(float x, float y, float z){
this.actualRotationX = x;
this.actualRotationY = y;
this.actualRotationZ = z;
}
/** Sets the extra rotation of this model part, which will be added onto the angle set by the parent model. */
public void addRotation(float x, float y, float z){
this.extraRotationX = x;
this.extraRotationY = y;
this.extraRotationZ = z;
}
/** Sets the rotation of this model part to the same values as the given box. */
public void setRotationTo(ModelRendererExtended box){
this.actualRotationX = box.actualRotationX;
this.actualRotationY = box.actualRotationY;
this.actualRotationZ = box.actualRotationZ;
this.extraRotationX = box.extraRotationX;
this.extraRotationY = box.extraRotationY;
this.extraRotationZ = box.extraRotationZ;
}
// Delegate rendering, but fiddle with the angles first
@Override
public void render(float scale){
// Need to copy these over each time in case they were changed
delegate.showModel = this.showModel;
delegate.isHidden = this.isHidden;
delegate.rotationPointX = this.rotationPointX;
delegate.rotationPointY = this.rotationPointY;
delegate.rotationPointZ = this.rotationPointZ;
if(!Float.isNaN(actualRotationX) && !Float.isNaN(actualRotationY) && !Float.isNaN(actualRotationZ)){
delegate.rotateAngleX = actualRotationX;
delegate.rotateAngleY = actualRotationY;
delegate.rotateAngleZ = actualRotationZ;
}else{
delegate.rotateAngleX = this.rotateAngleX + extraRotationX;
delegate.rotateAngleY = this.rotateAngleY + extraRotationY;
delegate.rotateAngleZ = this.rotateAngleZ + extraRotationZ;
}
delegate.render(scale);
}
// Delegate all other methods
@Override
public void addChild(ModelRenderer renderer){
delegate.addChild(renderer);
}
@Override
public void renderWithRotation(float scale){
delegate.renderWithRotation(scale);
}
@Override
public void postRender(float scale){
// Exactly the same setup as above, just add item rotation/translation fields and setters
// float angle = 1;
// float radius = 10;
// delegate.rotationPointY -= radius * MathHelper.cos(angle);
// delegate.rotationPointZ -= radius * MathHelper.sin(angle);
// delegate.rotateAngleX += angle;
delegate.postRender(scale);
}
}
@@ -0,0 +1,255 @@
package electroblob.wizardry.client.animation;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.item.SpellActions;
import electroblob.wizardry.util.InventoryUtils;
import electroblob.wizardry.util.JavaUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.AbstractClientPlayer;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.model.ModelPlayer;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderLivingBase;
import net.minecraft.client.renderer.entity.RenderPlayer;
import net.minecraft.client.renderer.entity.layers.LayerBipedArmor;
import net.minecraft.client.renderer.entity.layers.LayerRenderer;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.EnumAction;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumHandSide;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.client.event.RenderSpecificHandEvent;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Handles the setup and rendering events for custom player animations, as well as registering of animations. Addons
* can also register their own animations here, see {@link PlayerAnimator#registerAnimation(Animation)}.
* @author Electroblob
* @since Wizardry 4.3
* @see electroblob.wizardry.item.SpellActions SpellActions
*/
@Mod.EventBusSubscriber(Side.CLIENT)
public class PlayerAnimator {
// TODO: Attempt to extend this to all bipeds
private static final List<Animation> animations = new ArrayList<>();
/** Stores all registered layer renderers for lazy-loading of armour models later. */
private static final Map<RenderPlayer, List<LayerRenderer<? extends EntityLivingBase>>> playerLayers = new HashMap<>();
/** Stores the main model for each renderer plus all models for registered layer renderers. */
private static final Map<RenderPlayer, List<ModelBiped>> playerLayerModels = new HashMap<>();
/** Reflected into {@link RenderLivingBase}{@code #layerRenderers}. */
private static final Field layerRenderers;
/** True if wizardry's player animations have been overridden with another mod (currently only MoBends) */
private static boolean overridden;
static {
layerRenderers = ObfuscationReflectionHelper.findField(RenderLivingBase.class, "field_177097_h");
}
/**
* Registers a new player animation. This method should be called from the {@code init()} phase via a client proxy.
* @param animation The animation to register
*/
// N.B. This can (and will) be called before PlayerAnimator#init() is called
public static void registerAnimation(Animation animation){
if(animations.contains(animation)){
Wizardry.logger.warn("Animation {} is already registered!", animation.getName());
}else{
animations.add(animation);
}
}
/** Returns true if spellcasting animations are enabled, false otherwise. */
public static boolean areAnimationsEnabled(){
return Wizardry.settings.spellcastingAnimations && !overridden;
}
public static void init(){
if(Loader.isModLoaded("mobends")) overridden = true;
if(!areAnimationsEnabled()) return;
for(RenderPlayer renderer : Minecraft.getMinecraft().getRenderManager().getSkinMap().values()){
loadLayersForRenderer(renderer);
}
}
@SuppressWarnings("unchecked")
private static void loadLayersForRenderer(RenderPlayer renderer){
List<ModelBiped> models = new ArrayList<>();
ModelRendererExtended.wrap(renderer.getMainModel());
models.add(renderer.getMainModel());
try {
List<LayerRenderer<? extends EntityLivingBase>> layers = (List<LayerRenderer<? extends EntityLivingBase>>)layerRenderers.get(renderer);
// Save armour layers for lazy-loading later (ignore other layers so iteration is faster)
playerLayers.put(renderer, layers.stream().filter(l -> l instanceof LayerBipedArmor).collect(Collectors.toList()));
for(LayerRenderer<?> layer : layers){
for(Field field : JavaUtils.getAllFields(layer.getClass())){
field.setAccessible(true);
// If your layer model doesn't extend ModelBiped, you DESERVE to be incompatible!
// (Just kidding... there's nothing I can do about it anyway)
if(field.get(layer) instanceof ModelBiped){
ModelBiped model = (ModelBiped)field.get(layer);
ModelRendererExtended.wrap(model);
models.add(model);
}
}
}
}catch(IllegalAccessException e){
Wizardry.logger.error("Error during reflective access of render layers: ", e);
}
playerLayerModels.put(renderer, models);
}
private static void updateModels(EntityPlayer player, Render<?> renderer, float partialTicks, boolean firstPerson){
// Lazy-load models from custom renderers (some mods assign their custom renderers in postInit, so they might
// not be picked up from PlayerAnimator#init)
if(renderer instanceof RenderPlayer && !playerLayerModels.containsKey(renderer)){
loadLayersForRenderer((RenderPlayer)renderer);
}
List<ModelBiped> models = playerLayerModels.get(renderer);
// If no models were registered for the given renderer, don't do anything
if(models != null){
List<LayerRenderer<? extends EntityLivingBase>> layers = playerLayers.get(renderer);
// If no layers were registered for the given renderer there's no point trying to lazy-load anything!
if(layers != null){
// Biped armour is special because of Forge's armour item render hook
// This needs to be lazy-loaded because we need access to an actual item
for(LayerRenderer<? extends EntityLivingBase> layer : layers){
if(layer instanceof LayerBipedArmor){
for(EntityEquipmentSlot slot : InventoryUtils.ARMOUR_SLOTS){
ItemStack armour = player.getItemStackFromSlot(slot);
// This method could behave dynamically depending on stuff like NBT so there's not really any way to
// optimise it further, we *have* to retrieve the model every time (shouldn't be too bad though)
ModelBiped model = ForgeHooksClient.getArmorModel(player, armour, slot, ((LayerBipedArmor)layer).getModelFromSlot(slot));
if(!models.contains(model)){ // Ignore already-wrapped models
models.add(model);
ModelRendererExtended.wrap(model);
}
}
}
}
}
for(Animation animation : animations){
if(animation.shouldDisplay(player, firstPerson)){
boolean autoRotateSecondLayer = animation.autoRotateSecondLayer(player, firstPerson);
for(ModelBiped model : models){
if(!ModelRendererExtended.isWrapped(model)) continue; // Should never happen but somehow it does
animation.setRotationAngles(player, model, partialTicks, firstPerson);
if(autoRotateSecondLayer && model instanceof ModelPlayer){
alignSecondLayer((ModelPlayer)model);
}
}
}
}
}
}
/** Rotates the second layer boxes of the given (wrapped) player model to match the first layer. */
public static void alignSecondLayer(ModelPlayer model){
((ModelRendererExtended)model.bipedBodyWear) .setRotationTo((ModelRendererExtended)model.bipedBody);
((ModelRendererExtended)model.bipedRightArmwear).setRotationTo((ModelRendererExtended)model.bipedRightArm);
((ModelRendererExtended)model.bipedLeftArmwear) .setRotationTo((ModelRendererExtended)model.bipedLeftArm);
((ModelRendererExtended)model.bipedRightLegwear).setRotationTo((ModelRendererExtended)model.bipedBody);
((ModelRendererExtended)model.bipedLeftLegwear) .setRotationTo((ModelRendererExtended)model.bipedBody);
}
@SubscribeEvent
public static void onRenderHandEvent(RenderSpecificHandEvent event){
if(!areAnimationsEnabled()) return;
AbstractClientPlayer player = Minecraft.getMinecraft().player;
EnumAction action = event.getItemStack().getItemUseAction();
if(player.isHandActive() && player.getActiveHand() == event.getHand() && SpellActions.getSpellActions().contains(action)){
// Minecraft's item renderer helpfully doesn't have a default case for the usage action so it doesn't do any
// transformations at all (which is VERY ANNOYING!) - the following lines are from ItemRenderer#transformSideFirstPerson
int i = (player.getPrimaryHand() == EnumHandSide.RIGHT) == (event.getHand() == EnumHand.MAIN_HAND) ? 1 : -1;
GlStateManager.translate((float)i * 0.56F, -0.52F + event.getEquipProgress() * -0.6F, -0.72F);
}
updateModels(player, Minecraft.getMinecraft().getRenderManager().getEntityRenderObject(player), event.getPartialTicks(), true);
}
@SubscribeEvent
public static void onRenderPlayerPreEvent(RenderPlayerEvent.Pre event){
if(!areAnimationsEnabled()) return;
// boolean firstPerson = event.getEntityPlayer() == Minecraft.getMinecraft().player
// && Minecraft.getMinecraft().gameSettings.thirdPersonView == 0;
updateModels(event.getEntityPlayer(), event.getRenderer(), event.getPartialRenderTick(), false);
}
@SubscribeEvent
public static void onRenderPlayerPostEvent(RenderPlayerEvent.Post event){
if(!areAnimationsEnabled()) return;
List<ModelBiped> models = playerLayerModels.get(event.getRenderer());
if(models != null){
for(ModelBiped model : models){
for(ModelRenderer box : model.boxList){ // For ModelPlayer, this will include the second layer
// Some models have extra boxes, they (probably) don't need wrapping but we need this check!
if(box instanceof ModelRendererExtended){
((ModelRendererExtended)box).resetRotation();
}
}
}
}
}
}
@@ -0,0 +1,35 @@
package electroblob.wizardry.client.audio;
import net.minecraft.client.audio.MovingSound;
import net.minecraft.entity.Entity;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
// Copied from MovingSoundMinecart; if it ever breaks between updates take a look at that.
//@SideOnly(Side.CLIENT)
public class MovingSoundEntity<T extends Entity> extends MovingSound {
protected final T source;
protected float distance = 0.0F;
public MovingSoundEntity(T entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){
super(sound, category);
this.source = entity;
this.repeat = repeat;
this.volume = volume;
this.pitch = pitch;
this.repeatDelay = 0;
}
@Override
public void update(){
if(this.source.isDead){
this.donePlaying = true;
}else{
this.xPosF = (float)this.source.posX;
this.yPosF = (float)this.source.posY;
this.zPosF = (float)this.source.posZ;
}
}
}
@@ -0,0 +1,36 @@
package electroblob.wizardry.client.audio;
import electroblob.wizardry.item.ISpellCastingItem;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
/** A special type of moving sound that stops when the player stops charging up a spell, either by releasing the mouse
* button or when the charge-up time has elapsed. */
public class MovingSoundSpellCharge extends MovingSoundEntity<EntityLivingBase> {
public MovingSoundSpellCharge(EntityLivingBase entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){
super(entity, sound, category, volume, pitch, repeat);
}
@Override
public void update(){
if(source.isHandActive()){
ItemStack stack = source.getActiveItemStack();
if(stack.getItem() instanceof ISpellCastingItem){
if(source.getItemInUseMaxCount() < ((ISpellCastingItem)stack.getItem()).getCurrentSpell(stack).getChargeup()){
super.update();
return;
}
}
}
this.donePlaying = true;
}
}
@@ -0,0 +1,112 @@
package electroblob.wizardry.client.audio;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.ISound;
import net.minecraft.util.ITickable;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
import java.util.HashSet;
import java.util.Set;
/**
* Instances of this class represent a set of sounds which together form a looped sound: start, loop and end.
* Currently this is only used for continuous spell sounds in wizardry itself, but feel free to make your own
* implementations - this class will take care of the internals.
*
* @since Wizardry 4.2
* @author Electroblob
*/
// See MusicTicker, this is the same idea of just storing the sounds statically client-side and ticking them
@Mod.EventBusSubscriber(Side.CLIENT)
public abstract class SoundLoop implements ITickable {
private static final Set<SoundLoop> activeLoops = new HashSet<>();
// The issue we had here was that there is no way of hooking into the client tick loop between the sound manager
// update and the world tick (other than via the sounds themselves, but playing other sounds from there results in
// CMEs, which is why we made this class in the first place). This meant there was always a gap between consecutive
// sounds, which could be heard in-game as a weird audio artefact. The solution is simply to overlap the sounds by
// 1 tick, which is fairly straightforward for the end sound, but because the start sound has to finish for us to
// know when to play the others, this doubling-up solution is required (bit of a waste of resources but meh).
/** A dummy sound with effectively zero volume, played one tick in advance of the actual start sound so the loop
* sound can start one tick before the actual start sound ends. */
private final ISound dummyStart; // It's the stupidest system ever but it works!
private final ISound start;
private final ISound loop;
private final ISound end;
private boolean looping = false;
private boolean needsRemoving = false;
public SoundLoop(SoundEvent start, SoundEvent loop, SoundEvent end, SoundCategory category, float volume, ISoundFactory factory){
// The reason I've gone to the effort of having a factory for these is that we need SoundLoop to have control
// over which sounds are repeated and which aren't whilst keeping them private.
this.dummyStart = factory.create(start, category, 0.00001f, false); // Inaudible but not actually 0
this.start = factory.create(start, category, volume, false);
this.loop = factory.create(loop, category, volume, true);
this.end = factory.create(end, category, volume, false);
}
@Override
public void update(){
// Check every tick if the start sound is done playing and if so, start the loop sound
if(!looping && !Minecraft.getMinecraft().getSoundHandler().isSoundPlaying(dummyStart)){
Minecraft.getMinecraft().getSoundHandler().playSound(loop);
looping = true;
}
}
/** Starts playing the end part immediately and marks the loop part to stop next tick. This may be called from
* subclasses or externally depending on the implementation. */
// For continuous spell sounds it's internally
public void endLoop(){
Minecraft.getMinecraft().getSoundHandler().playSound(end);
// Can't modify activeLoops directly since we'll probably be calling this method from update(), which is
// during iteration of activeLoops so it could cause a ConcurrentModificationException
this.markForRemoval();
}
/** Marks this sound loop to be removed next tick. */
protected void markForRemoval(){
this.needsRemoving = true;
}
/** Stops the start and loop sounds immediately. */
protected void stopStartAndLoop(){
Minecraft.getMinecraft().getSoundHandler().stopSound(dummyStart);
Minecraft.getMinecraft().getSoundHandler().stopSound(start);
Minecraft.getMinecraft().getSoundHandler().stopSound(loop);
}
// Static methods
public static void addLoop(SoundLoop loop){
activeLoops.add(loop);
// Do this here rather than in the constructor in case someone wants to play the loop later or reuse it
Minecraft.getMinecraft().getSoundHandler().playSound(loop.dummyStart);
Minecraft.getMinecraft().getSoundHandler().playDelayedSound(loop.start, 2); // 1 seems to be insufficient
}
@SubscribeEvent
public static void tick(TickEvent.ClientTickEvent event){
// Using the END phase means we can check for stopped sounds as soon as they are stopped (effectively),
// meaning we don't get the 'cut' between the start and loop sounds
// FIXME: Apparently this only works for dispensers. What the heck is the difference?!
if(event.phase == TickEvent.Phase.END){
activeLoops.stream().filter(s -> s.needsRemoving).forEach(SoundLoop::stopStartAndLoop);
activeLoops.removeIf(s -> s.needsRemoving);
activeLoops.forEach(SoundLoop::update); // Do this last to allow a 1-tick overlap
}
}
@FunctionalInterface
public interface ISoundFactory {
ISound create(SoundEvent sound, SoundCategory category, float volume, boolean repeat);
}
}
@@ -0,0 +1,117 @@
package electroblob.wizardry.client.audio;
import electroblob.wizardry.data.DispenserCastingData;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.EntityUtils;
import net.minecraft.client.audio.PositionedSound;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
/** Abstract base class for sound loops associated with spells; see subclasses below for implementations. */
public abstract class SoundLoopSpell extends SoundLoop {
private final Spell spell;
public SoundLoopSpell(SoundEvent start, SoundEvent loop, SoundEvent end, float volume, ISoundFactory factory, Spell spell){
super(start, loop, end, WizardrySounds.SPELLS, volume, factory);
this.spell = spell;
}
@Override
public void update(){
// This may be a bit overkill but I might as well put functionality in superclasses where possible
if(stillCasting(spell)){
// This can't called in the same tick as endLoop because otherwise, if the spell casting stops during the
// same tick as the transition to the loop sound it will try and stop the loop immediately after it has
// started - and for whatever reason, this causes the 'Channel null in method stop' error.
super.update();
}else{
endLoop();
}
}
protected abstract boolean stillCasting(Spell spell);
/** Implements a sound loop for continuous spells cast by entities. */
public static class SoundLoopSpellEntity extends SoundLoopSpell {
private final EntityLivingBase source;
public SoundLoopSpellEntity(SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell, EntityLivingBase source, float volume, float pitch){
super(start, loop, end, volume, (sound, category, v, repeat) -> new MovingSoundEntity<>(source, sound, category, v, pitch, repeat), spell);
this.source = source;
}
@Override
protected boolean stillCasting(Spell spell){
return EntityUtils.isCasting(source, spell);
}
}
public static abstract class SoundLoopSpellPosition extends SoundLoopSpell {
public SoundLoopSpellPosition (SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell,
double x, double y, double z, float sndVolume, float sndPitch){
// Huh, I actually found a use for a non-static initialiser block - hence the double curly brackets...
super(start, loop, end, sndVolume, (sound, category, v, r) -> new PositionedSound(sound, category){{
// ...et voila, we can just set protected fields as we please using external variables
this.xPosF = (float)x;
this.yPosF = (float)y;
this.zPosF = (float)z;
this.repeat = r;
this.volume = v;
this.pitch = sndPitch;
}}, spell);
}
}
/** Implements a sound loop for continuous spells cast by dispensers. */
public static class SoundLoopSpellDispenser extends SoundLoopSpellPosition {
private final TileEntityDispenser source;
public SoundLoopSpellDispenser(SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell, World world,
double x, double y, double z, float sndVolume, float sndPitch){
super(start, loop, end, spell, x, y, z, sndVolume, sndPitch);
TileEntity tileentity = world.getTileEntity(new BlockPos(x, y, z));
if(tileentity instanceof TileEntityDispenser) this.source = (TileEntityDispenser)tileentity;
else throw new NullPointerException(String.format("Playing continuous spell sound: no dispenser found at %s, %s, %s", x, y, z));
}
@Override
protected boolean stillCasting(Spell spell){
return DispenserCastingData.get(source).currentlyCasting() == spell;
}
}
/** Implements a sound loop for continuous spells cast at a position (via commands). */
public static class SoundLoopSpellPosTimed extends SoundLoopSpellPosition {
private int timeLeft;
public SoundLoopSpellPosTimed(SoundEvent start, SoundEvent loop, SoundEvent end, Spell spell, int duration,
double x, double y, double z, float sndVolume, float sndPitch){
super(start, loop, end, spell, x, y, z, sndVolume, sndPitch);
this.timeLeft = duration;
}
@Override
public void update(){
super.update();
timeLeft--;
}
@Override
protected boolean stillCasting(Spell spell){
return timeLeft > 0;
}
}
}
@@ -0,0 +1,109 @@
package electroblob.wizardry.client.gui;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.DrawingUtils;
import electroblob.wizardry.registry.WizardryTabs;
import electroblob.wizardry.spell.Spell;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.gui.inventory.GuiContainerCreative;
import net.minecraft.client.resources.I18n;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.relauncher.Side;
import java.lang.reflect.Field;
import java.util.Locale;
@EventBusSubscriber(Side.CLIENT)
public class CustomCreativeSearchHandler {
private static final int SEARCH_TOOLTIP_HOVER_TIME = 20;
private static final Style TOOLTIP_SYNTAX = new Style().setColor(TextFormatting.YELLOW);
private static final Style TOOLTIP_BODY = new Style().setColor(TextFormatting.WHITE);
/** Reflected into {@code GuiContainerCreative#searchField} */
private static final Field searchField;
private static GuiTextField currentSearchField = null;
private static int searchBarHoverTime;
static {
searchField = ObfuscationReflectionHelper.findField(GuiContainerCreative.class, "field_147062_A");
}
@SubscribeEvent
public static void onInitGuiEvent(GuiScreenEvent.InitGuiEvent.Post event){
// Reduces reflection as much as possible - searchField is created on GUI init and never reassigned so we need
// not (and should not!) use reflection to retrieve it every time a key is typed
if(event.getGui() instanceof GuiContainerCreative){
try{
currentSearchField = (GuiTextField)searchField.get(event.getGui());
}catch(IllegalAccessException e){
e.printStackTrace();
}
}
}
@SubscribeEvent
public static void onKeyboardInputEvent(GuiScreenEvent.KeyboardInputEvent.Post event){
// Custom creative tab search behaviour
if(event.getGui() instanceof GuiContainerCreative){
GuiContainerCreative gui = (GuiContainerCreative)event.getGui();
CreativeTabs tab = CreativeTabs.CREATIVE_TAB_ARRAY[gui.getSelectedTabIndex()];
if(tab == WizardryTabs.SPELLS){
GuiContainerCreative.ContainerCreative container = (GuiContainerCreative.ContainerCreative)gui.inventorySlots;
container.itemList.clear(); // Required or duplicates will appear!
String searchText = currentSearchField.getText().toLowerCase(Locale.ROOT);
tab.displayAllRelevantItems(container.itemList);
if(!searchText.isEmpty()){
container.itemList.removeIf(s -> !Spell.byMetadata(s.getMetadata()).matches(searchText));
container.scrollTo(0); // Seems to refresh the GUI somehow so it displays correctly
}
}
}
}
@SubscribeEvent
public static void onClientTickEvent(ClientTickEvent event){
if(event.phase == Phase.END && searchBarHoverTime > 0 && searchBarHoverTime < SEARCH_TOOLTIP_HOVER_TIME){
searchBarHoverTime++;
}
}
@SubscribeEvent
public static void onDrawScreenPostEvent(GuiScreenEvent.DrawScreenEvent.Post event){
if(event.getGui() instanceof GuiContainerCreative && currentSearchField != null){
GuiContainerCreative gui = (GuiContainerCreative)event.getGui();
CreativeTabs tab = CreativeTabs.CREATIVE_TAB_ARRAY[gui.getSelectedTabIndex()];
if(tab == WizardryTabs.SPELLS && DrawingUtils.isPointInRegion(currentSearchField.x, currentSearchField.y, currentSearchField.width, currentSearchField.height, event.getMouseX(), event.getMouseY())){
if(searchBarHoverTime == 0){
searchBarHoverTime++;
}else if(searchBarHoverTime == SEARCH_TOOLTIP_HOVER_TIME){
event.getGui().drawHoveringText(I18n.format("container." + Wizardry.MODID + ":arcane_workbench.search_tooltip",
TOOLTIP_SYNTAX.getFormattingCode(), TOOLTIP_BODY.getFormattingCode()), event.getMouseX(), event.getMouseY());
}
}
}else{
searchBarHoverTime = 0;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,54 @@
package electroblob.wizardry.client.gui;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.inventory.ContainerBookshelf;
import electroblob.wizardry.tileentity.TileEntityBookshelf;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class GuiBookshelf extends GuiContainer {
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/gui/container/bookshelf.png");
/** The player inventory bound to this GUI. */
private final InventoryPlayer playerInventory;
/** The inventory contained within the corresponding bookshelf. */
public IInventory bookshelfInventory;
public GuiBookshelf(InventoryPlayer playerInv, TileEntityBookshelf bookshelfInv){
super(new ContainerBookshelf(playerInv, bookshelfInv));
this.playerInventory = playerInv;
this.bookshelfInventory = bookshelfInv;
this.allowUserInput = false;
this.ySize = 148;
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks){
this.drawDefaultBackground();
super.drawScreen(mouseX, mouseY, partialTicks);
this.renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){
String s = this.bookshelfInventory.getDisplayName().getUnformattedText();
this.fontRenderer.drawString(s, 8, 6, 4210752);
this.fontRenderer.drawString(this.playerInventory.getDisplayName().getUnformattedText(), 8, this.ySize - 96 + 2, 4210752);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY){
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.getTextureManager().bindTexture(TEXTURE);
int i = (this.width - this.xSize) / 2;
int j = (this.height - this.ySize) / 2;
this.drawTexturedModalRect(i, j, 0, 0, this.xSize, this.ySize);
}
}
@@ -0,0 +1,18 @@
package electroblob.wizardry.client.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
//@SideOnly(Side.CLIENT)
public class GuiButtonInvisible extends GuiButton {
public GuiButtonInvisible(int id, int x, int y, int width, int height){
super(id, x, y, width, height, "");
}
@Override
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
}
}
@@ -0,0 +1,90 @@
package electroblob.wizardry.client.gui;
import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.packet.PacketControlInput;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.spell.Resurrection;
import electroblob.wizardry.util.InventoryUtils;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiGameOver;
import net.minecraft.client.resources.I18n;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.Side;
@Mod.EventBusSubscriber(Side.CLIENT)
public class GuiButtonResurrect extends GuiButton {
private static int timeSinceDeath = -1;
private final String translationKey;
public GuiButtonResurrect(int id, int x, int y, String translationKey){
super(id, x, y, I18n.format(translationKey + "_wait", Resurrection.getRemainingWaitTime(timeSinceDeath)));
this.translationKey = translationKey;
}
@Override
public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks){
int waitTime = Resurrection.getRemainingWaitTime(timeSinceDeath);
this.enabled = waitTime == 0;
this.displayString = I18n.format(translationKey + (waitTime == 0 ? "_ready" : "_wait"), waitTime);
super.drawButton(mc, mouseX, mouseY, partialTicks);
}
// Event handlers
@SubscribeEvent
public static void onClientTickEvent(TickEvent.ClientTickEvent event){
if(event.phase == TickEvent.Phase.START && timeSinceDeath >= 0) timeSinceDeath++;
}
@SubscribeEvent
public static void onGuiScreenInitEvent(GuiScreenEvent.InitGuiEvent event){
if(event.getGui() instanceof GuiGameOver && ItemArtefact.isArtefactActive(Minecraft.getMinecraft().player, WizardryItems.amulet_resurrection)
&& InventoryUtils.getHotbar(Minecraft.getMinecraft().player).stream().anyMatch(s -> Resurrection.canStackResurrect(s, Minecraft.getMinecraft().player))){
event.getButtonList().add(new GuiButtonResurrect(event.getButtonList().size(), event.getGui().width / 2 - 100,
event.getGui().height / 4 + 120, "spell." + Spells.resurrection.getRegistryName() + ".button"));
timeSinceDeath = 0;
}
}
@SubscribeEvent
public static void onGuiScreenActionPerformedEvent(GuiScreenEvent.ActionPerformedEvent event){
if(event.getGui() instanceof GuiGameOver){
ItemStack stack = InventoryUtils.getHotbar(Minecraft.getMinecraft().player).stream()
.filter(s -> Resurrection.canStackResurrect(s, Minecraft.getMinecraft().player)).findFirst().orElse(null);
if(stack != null){
if(event.getButton() instanceof GuiButtonResurrect && timeSinceDeath >= 0){
// Cast resurrection on the client player and notify the server to do the same
// ISpellCastingItem#canCast already checked in Resurrection#canStackResurrect
((ISpellCastingItem)stack.getItem()).cast(stack, Spells.resurrection, Minecraft.getMinecraft().player, EnumHand.MAIN_HAND, 0, new SpellModifiers());
WizardryPacketHandler.net.sendToServer(new PacketControlInput.Message(PacketControlInput.ControlType.RESURRECT_BUTTON));
}else if(!Minecraft.getMinecraft().world.getGameRules().getBoolean("keepInventory")){
// Any other button drops the wand (N.B. this should be inside the stack != null check or it'll send
// packets unnecessarily and generate incorrect warnings
WizardryPacketHandler.net.sendToServer(new PacketControlInput.Message(PacketControlInput.ControlType.CANCEL_RESURRECT));
}
timeSinceDeath = -1;
}
}
}
}

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