Compare commits

..

153 Commits

Author SHA1 Message Date
WinDanesz f9cf1b39db Fix telekineticDisarmament setting and Amulet of Anchoring 2024-03-29 18:07:19 +01:00
WinDanesz 3fb3c1c039 feat: made EntityWizard.trades public so that addon devs can manipulate trades 2024-03-28 01:00:26 +01:00
WinDanesz e8bc6ca725 version bump to 4.3.13 2024-03-28 01:00:26 +01:00
WinDanesz df531d3724 fix: Fixed all synchronized WizardData stored variables on dedicated servers. This issue was causing e.g. the Ancient Compass to not display its targets on servers. Fixes #857 2024-03-28 00:46:32 +01:00
ScoTWT 2728012f33 Update zh_tw.lang (#709) 2024-03-27 22:19:46 +01:00
red1854th 853df2eb42 Update ko_kr.lang (#714)
* Update Korean translations, courtesy of red1854th

* Update Korean translations, courtesy of red1854th
2024-03-27 22:18:20 +01:00
ipdnaeip 0cb2165ddf Added methods for retrieving entities within a cylinder, replaced radius-based methods, implemented DPS check for heal aura, adjusted targeting criteria for summoned creatures, tweaked heal method, fixed flamecatcher ammo loss, updated Enrage target and expanded spellcasting item compatibility for movement speed charm. - by ipdnaeip (#864)
Added getEntitiesWithinCylinder and getLivingWithinCylinder methods to return all entities within a cylinder.

Replaced getLivingWithinRadius for spells that should use a cylinder instead. The height of the cylinder is determined by the height of the entities.

Added a DPS checker on the heal aura damage just in case someone has damage immunity disabled.

Modified the AllyDesignationSystem and Wizard classes to no longer target summoned creatures automatically. They will still target hostile summoned creatures or creatures from players that have aggressed on them.

Modified the heal method in the Heal class to not reduce absorption amount. It should never really happen, but just in case.

Modified the flamecatcher to no longer lose ammo if it was used but no arrow was fired.

Enrage now targets EntityLiving instead of EntityCreature.

The movement speed charm now works with any spellcasting item as opposed to just wands.
2024-03-27 22:11:29 +01:00
WinDanesz ca7e9034ed feat: Added WandHelper.rechargeManaOnApplyButtonPressed static method for easier mana recharging across addons 2024-03-27 22:03:01 +01:00
WinDanesz 1322c920f5 fix: Spells are now sorted alphabetically by their names, instead of first being sorted by modid 2024-03-15 01:31:51 +01:00
WinDanesz e5c00e3882 feat: The Amulet of Anchoring also prevents the Telekinesis spell to knock items out of the wearer's hand. (Previously it only granted protection against being moved by Greater Telekinesis) 2024-03-14 00:05:40 +01:00
WinDanesz c030629bab fix: Fixed clear button and Attunement 2023-12-30 21:08:14 +01:00
WinDanesz 165d079251 Added getApplicableItems() to Spell.java 2023-10-25 10:10:20 +02:00
WinDanesz 7cc9200adf feat: added teleport_self_large_distance forfeit 2023-10-18 22:53:00 +02:00
WinDanesz 01a9d8c075 chore: 4.3.11 -> 4.3.12 version bump 2023-10-18 22:53:00 +02:00
WinDanesz 0a0a08d220 fix: Probably fixed a recurring Handbook crash for good 2023-10-18 22:53:00 +02:00
WinDanesz 410768e6f3 feat: Support for addon Wizard's Handbook
content
2023-10-18 22:53:00 +02:00
WinDanesz bbbe024bb3 build: Updated to ForgeGradle5 with FancyGradle 2023-10-18 22:53:00 +02:00
WinDanesz 93112d5192 docs: Update ArtefactCheckEvent.java javadoc 2023-09-10 16:10:15 +02:00
ipdnaeip 112a562b2d fix: Increased the tick rate of continuous spells (#849)
... and added some checks to make sure the spells don't deal too much with mods that interact with the hurt resistance timer.
2023-09-09 18:08:38 +02:00
WinDanesz 85ca4fd100 build: 4.3.10 -> 4.3.11 version bump 2023-06-30 16:55:40 +02:00
WinDanesz 136b1cc924 feat: Added preventBindingSameSpellTwiceToWands setting (disabled by default). Controls whether to prevent binding the same spell to a wand multiple times 2023-06-30 16:06:01 +02:00
WinDanesz e4b7d528f5 feat: Added singleUseSpellBooks setting (disabled by default). Controls whether spell books are consumed when they are bound to a wand 2023-06-30 15:47:24 +02:00
WinDanesz 2903ebfbac feat: Added damageTypePerElement setting (disabled by default). Pack makers now can implement support for .e.g Distinct Damage Definitions or other mods 2023-06-30 15:41:26 +02:00
WinDanesz 931ca1b2c0 feat: Added a Clear button to the Arcane Workbench. Clicking it removes all spell bindings of the item in the center slot 2023-06-28 20:53:55 +02:00
WinDanesz 85e724d88a fix: Allied spell casters of a player (owned by the player as an IEntityOwnable creature) now have their spells affect the player too where applicable. Previously spells like Group Heal casted by the NPC was not affecting the owner. 2023-06-28 19:14:53 +02:00
WinDanesz e41f83a2dd build: 4.3.9 -> 4.3.10 version bump 2023-06-28 16:06:37 +02:00
WinDanesz 69b52cfe88 feat: A new ArtefactCheckEvent for addons, allowing devs to consider an artefact active (in slot) conditionally, or even prevent its usage based on custom conditions 2023-06-28 16:06:07 +02:00
WinDanesz 7591821e57 feat: A more Wizardry-native support for BELT, BODY, HEAD and TRINKET artefact types (expanded ItemArtefact.Type) intended for addons 2023-06-28 16:02:32 +02:00
WinDanesz 0ce0dcf2e9 feat: Configuration options for the values of: POTENCY_INCREASE_PER_TIER, COOLDOWN_REDUCTION_PER_LEVEL, DURATION_INCREASE_PER_LEVEL, RANGE_INCREASE_PER_LEVEL, BLAST_RADIUS_INCREASE_PER_LEVEL, RANGE_INCREASE_PER_LEVEL 2023-06-28 15:20:00 +02:00
WinDanesz 73811c3a6b feat: Config option to toggle wands not decrementing cooldowns outside of hands 2023-06-28 14:56:01 +02:00
WinDanesz 2a887b7794 fix: Fixed bug with wands not decrementing cooldowns in the offhand 2023-06-28 14:25:15 +02:00
WinDanesz ad9f482e76 fix: Fixed a bug that prevented NPCs (wizards) from casting certain buff spells 2023-06-28 13:55:09 +02:00
WinDanesz 6eaef94459 Fixed Mark Sacrifice reducing damage at amplifier level 0 2023-03-23 22:01:51 +01:00
ZettaSword 4f5c616240 Added missing sound for the Mirage spell (#835)
Because of "[Client thread/WARN]: Missing sound for event: ebwizardry:spell.mirage" in latest.log i found that Mirage spell has no effect, even if it's registered. That's why with this request i add it to sounds.json.
2023-01-11 15:50:07 +01:00
WinDanesz f5947dded9 chore: version bump to 4.3.9 2022-12-31 20:23:14 +01:00
WinDanesz 77e0acc16b fix: Fixed Curse of Undeath breaking wizard headgear. It no longer breaks hats, and the curse sets the player on fire if the hat has no mana. Fixes #820 2022-12-31 20:21:19 +01:00
WinDanesz e48646c5ff feat: Conjured bows will now shoot conjured arrows 2022-12-31 20:14:47 +01:00
WinDanesz 5e48fe51ea fix: Added missing import 2022-12-31 19:58:02 +01:00
WinDanesz 6b30dbef65 fix: Fixed onImbuementRemoval() not being called for imbuements expired in the inventory. Currently this bug was only affecting adons. Fixes #833 2022-12-31 19:52:11 +01:00
WinDanesz d6508a2be4 fix: Fixed Fire Skin potion effect's retaliatory burn duration (was 20x shorter than intended) 2022-12-31 19:51:43 +01:00
WinDanesz dfcadfb3bd fix: No more console spam from Muffle spell 2022-10-04 00:55:06 +02:00
ZettaSword 7888b92129 feat: Wand cooldown only decrements if the player holds the wand 2022-08-04 22:17:31 +02:00
ZettaSword 5b48dffa77 fix: Fixed the adaptive brightness of Oak/Iron/Diamondflesh 2022-08-04 22:15:06 +02:00
WinDanesz 5bf4650da1 fix: Fixed wizards not using addon book spells 2022-07-11 21:14:45 +02:00
WinDanesz 8e9c270b77 fix: Fixed wizards selling addon book spells with the default book 2022-07-11 21:13:38 +02:00
WinDanesz 00080331df feat: Reworked the Summon Iron Golem spell, its new name is Summon Spectral Golem 2022-07-08 22:18:59 +02:00
WinDanesz 27e40e2069 fix: Fixed the opacity of conjured arrows 2022-07-08 21:37:55 +02:00
WinDanesz 3a93877de3 fix: Fire Ring shouldn't instantly melt away players on servers anymore 2022-07-08 21:11:10 +02:00
WinDanesz 7f70784cd3 fix: Fixed Scrolls of continuous spells having a cooldown in creative mode 2022-07-08 20:36:46 +02:00
WinDanesz ed6e3df66e feat: The Arrow Rain spell summons conjured arrows 2022-07-08 20:32:22 +02:00
WinDanesz eb5becbbd4 fix: Fixed some addon crystals restoring more mana than they should
Fixes #816
2022-07-08 19:41:25 +02:00
WinDanesz 9599316fbc fix: Added a config option to prevent crash with guidebook loading on some locales. Note that if you use this config, you won't have the Wizard's Handbook in an usable state!
Fixes #815, Fixes #814, Fixes #800, Fixes #768
2022-07-08 19:30:03 +02:00
WinDanesz cc1c951ef8 feat: Soulwalker's Ring only soulbounds an entity for 20 seconds 2022-07-08 19:20:16 +02:00
WinDanesz d23c4cba18 feat: Forcefield loses 1% durability each time it repulses an enemy or a projectile 2022-07-08 19:16:54 +02:00
WinDanesz 3d30b0b96f feat: Forcefield loses 2% durability each time it repulses an enemy or a projectile 2022-06-22 22:38:54 +02:00
WinDanesz ad1e5d555a feat: Reworked the Oakflesh, Ironflesh and Diamondflesh spells 2022-06-22 22:24:30 +02:00
WinDanesz 14ea5f1c72 fix: Fixed Containment spell for entities 2022-06-19 23:25:36 +02:00
WinDanesz 709d44e4d9 feat: Class Armour sets (Sage, Warlock, Battlemage) only grant their set bonuses if each armour piece has mana 2022-06-19 12:44:14 +02:00
WinDanesz 8df00e9c41 feat: Added potency_per_level spell property for Empowerment, reduced potency gain per level 0.25->0.15 2022-06-13 23:12:14 +02:00
WinDanesz 8dbb0ec058 fix: Fixed 'Ward I' effect not giving any protection against magic 2022-06-12 23:33:07 +02:00
WinDanesz b8310eedae feat: Added a player_effect_duration_multiplier for the Paralysis spell, defaults to 0.5 2022-06-12 00:12:24 +02:00
WinDanesz c04754afe1 chore: version bump to v4.3.7 2022-04-17 21:37:20 +02:00
WinDanesz 3155aa6815 fix: Should fix the disconnect issue when pretty much all existing spell packs are present in the game
Mods were registering spells on the client and server side in a different order (perhaps related to the OS), causing a mismatch in spell networkIDs. This will ensure that spells are sorted alphabetically and redistributes a new ID.
2022-04-17 20:43:59 +02:00
WinDanesz ea27b1a081 Revert "Merge pull request #750 from WinDanesz/patch-1226-2" 2022-04-17 15:53:48 +02:00
WinDanesz 4d078f9597 Revert "Fixed crash on dedicated servers (PacketSpellProperties), Fixes #780, #779, #773, #774, #771, #768"
This reverts commit 6690564017.
2022-04-17 15:46:11 +02:00
WinDanesz 67459cbbbd chore: Delete feature_request.md 2022-04-15 14:06:33 +02:00
WinDanesz 932de4e969 chore: Delete question.md 2022-04-15 13:58:44 +02:00
WinDanesz 41e28291ad chore: create config.yml 2022-04-15 13:58:29 +02:00
WinDanesz 6ae6324368 chore: Rename bug_report.md to bug_report.yml 2022-04-15 13:52:10 +02:00
WinDanesz 4858716f05 chore: update bug_report.md 2022-04-15 13:51:44 +02:00
WinDanesz 24fb4cfe4a v4.3.6 2022-03-06 19:26:45 +01:00
WinDanesz 186138d0c0 fixed visibility modifier of ImbuementActivateEvent's fields 2022-03-06 19:26:04 +01:00
WinDanesz 6690564017 Fixed crash on dedicated servers (PacketSpellProperties), Fixes #780, #779, #773, #774, #771, #768 2022-03-06 19:14:47 +01:00
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
140 changed files with 8628 additions and 5756 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.13",
"1.12.2-recommended": "4.3.13"
}
}
-20
View File
@@ -1,20 +0,0 @@
---
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.
Minecraft version: 1.12.2 [change as necessary]
Wizardry version: 4.3.3 [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.]
+85
View File
@@ -0,0 +1,85 @@
name: 🐛 Bug Report
description: Something is not working as expected
title: "[Bug] <write the title here>"
labels: [ "bug", "Needs Triage" ]
body:
- type: markdown
attributes:
value: |
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.
Please try the latest version of the mod and check if the issue persist before submitting a report.
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing issues
required: true
- type: textarea
id: observed
attributes:
label: Observed behaviour
description: Describe what happened and when this happened
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behaviour
description: Describe what you expected to happen
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Steps to reproduce
description: Step by step instructions on how to reproduce the observed behaviour
placeholder: |
1. Join a server
2. Cast the [spell]
3. ...
validations:
required: true
- type: input
id: crashlog
attributes:
label: Crashlog
description: If this was a crash, grab [minecraft instance]/logs/debug.log, upload it as a [gist](https://gist.github.com/) and paste the link here. Alternatively, give a link to the crash report on gist, pastebin if you already have one there.
placeholder: https://gist.github.com/<your-user>/abcdef124
- type: dropdown
id: environment
attributes:
label: Environment (Singleplayer/Server, etc.)
options:
- Singleplayer
- LAN game/Server
- Issue present on both sides
- Not sure
validations:
required: true
- type: input
id: mod-version
attributes:
label: Mod version
placeholder: 1.0.0
validations:
required: true
- type: input
id: minecraft-version
attributes:
label: Minecraft version
placeholder: 12.2.2
validations:
required: true
- type: input
id: forge-version
attributes:
label: Forge version
placeholder: 1.12.2 - 14.23.5.2860
validations:
required: true
- type: textarea
id: other-mods
attributes:
label: Other mods
description: List any other mods present when the bug was encountered, include the mod versions. You only have to fill this if no crash log was attached
+14
View File
@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: 📖 Mod Wiki Page
url: https://github.com/Electroblob77/Wizardry/wiki
about: Most features are documented in the mod's wiki page --- Link --->
- name: 💬 Electroblob's Wizardry discord
url: https://discord.gg/hs8yJP2
about: Ask for help or get more info on Discord. --- Discord Server link --->
- name: 💡 Feature requests / suggestions
url: https://discord.gg/hs8yJP2
about: Please use the discord server to suggest stuff. --- Discord Server link --->
- name: ❓ Question
url: https://discord.gg/hs8yJP2
about: Ask a question about the mod or the code. --- Discord Server link --->
-16
View File
@@ -1,16 +0,0 @@
---
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
@@ -1,17 +0,0 @@
---
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: 4.3.3 [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}}
+8 -2
View File
@@ -1,7 +1,7 @@
# Credits
Electroblob's Wizardry
Version 4.3.3
Version 4.3.7
For Minecraft 1.12.2
Designed, coded and textured by Electroblob
@@ -12,6 +12,11 @@ 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
@@ -27,13 +32,14 @@ In addition, I'd like to thank the following individuals for their contributions
- rafasoares
- xinyuan-liu
- SettingDust
- Aralu115
#### Translations
- Spanish: MadWrist, Alsentar
- Mexican Spanish: MadWrist
- Russian: VilagVil, kellixon, bigenergy, MugGod2, DrHesperus
- French: Hahdrim
- French: Hahdrim, Crowller
- Brazilian Portuguese: lorrampi
- Chinese (Simplified): ZHENGLOC, dragon-evol, Hokorizero, TUsama, Determancer
- Korean: shejery, rewi_wire, 방통, red1854th
+2 -2
View File
@@ -1,7 +1,7 @@
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
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: 4.3.3 [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.]
+112 -50
View File
@@ -1,64 +1,127 @@
import groovy.json.JsonOutput
buildscript {
repositories {
jcenter()
maven { url = "http://files.minecraftforge.net/maven" }
gradlePluginPortal()
maven {
name 'MinecraftForge'
url 'https://maven.minecraftforge.net/'
}
maven {
name 'Garden of Fancy'
url 'https://maven.gofancy.wtf/releases'
}
//fallback for fancygradle maven
//mavenLocal()
maven {
name 'Sponge'
url 'https://repo.spongepowered.org/repository/maven-public/'
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
classpath 'net.minecraftforge.gradle:ForgeGradle:5.+'
classpath 'org.ajoberstar.grgit:grgit-gradle:3.1.1'
classpath group: 'wtf.gofancy.fancygradle', name: 'wtf.gofancy.fancygradle.gradle.plugin', version: '1.1.+'
}
repositories.each {
if (it instanceof MavenArtifactRepository && it.url.toString() == "https://files.minecraftforge.net/maven") {
it.url = "https://maven.minecraftforge.net"
}
}
}
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.
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'idea'
apply plugin: 'maven-publish'
apply plugin: org.ajoberstar.grgit.gradle.GrgitPlugin
apply plugin: 'wtf.gofancy.fancygradle'
version = "4.3.3" // There, it matches semver, happy now?
version = "4.3.13"
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"
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
minecraft {
// 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 channel: 'snapshot', version: '20171003-1.12'
mappings channel: "stable", version: "39-1.12"
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
// accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
// Default run configurations.
// These can be tweaked, removed, or duplicated as needed.
runs {
client {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
// Recommended logging level for the console
property 'forge.logging.console.level', 'info'
}
server {
// Recommended logging data for a userdev environment
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
// Recommended logging level for the console
property 'forge.logging.console.level', 'info'
}
}
}
repositories {
google()
mavenCentral()
maven {
// location of the maven that hosts JEI files
name = "Progwml6 maven"
url = "http://dvs1.progwml6.com/files/maven"
url = uri('https://www.cursemaven.com')
content {
includeGroup 'curse.maven'
}
}
maven {
// location of a maven mirror for JEI files, as a fallback
name = "ModMaven"
url = "modmaven.k-4u.nl"
name = 'Modrinth'
url = uri('https://api.modrinth.com/maven')
content {
includeGroup 'maven.modrinth'
}
}
maven {
name = "Curseforge Maven"
url = "https://minecraft.curseforge.com/api/maven/"
name = 'Sponge'
url = uri('https://repo.spongepowered.org/maven')
}
maven {
url = uri('https://maven.blamejared.com')
}
maven {
url = uri('https://m2.dv8tion.net/releases')
}
maven {
url = uri('https://jitpack.io')
}
}
minecraft {
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 {
// 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}"
//// MC version ////
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft "net.minecraftforge:forge:${project.mc_version}-${project.forge_version}"
//// MC version ////
implementation fg.deobf("curse.maven:baubles-${baubles_projectid}:${baubles_fileid}")
implementation fg.deobf("mezz.jei:jei_${mc_version}:${jei_version}")
implementation fg.deobf("curse.maven:antique-atlas-${antiqueatlas_projectid}:${antiqueatlas_fileid}")
}
@@ -68,20 +131,19 @@ task deobfJar(type: Jar) {
}
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
// replace stuff in mcmod.info, nothing else
// replace tokens in mcmod.info, and pack.mcmeta
from(sourceSets.main.resources.srcDirs) {
include 'pack.mcmeta'
include 'mcmod.info'
// replace version and mcversion
expand 'version':project.version, 'mcversion':project.minecraft.version
}
// copy everything else except the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
duplicatesStrategy = 'include'
}
fancyGradle {
patches {
resources
coremods
asm
}
}
+15 -1
View File
@@ -1,8 +1,22 @@
# 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
mod_id=ebwizardry
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
antique_atlas_version=4.6.3
forge_version=14.23.5.2860
mappings_version=39
mappings_channel=stable
mappings_mc_version=1.12
baubles_projectid=227083
baubles_fileid=2518667
jei_projectid=238222
artemislib_projectid=313590
artemislib_version=1.0.6
artemislib_fileid=2741812
antiqueatlas_projectid=227795
antiqueatlas_fileid=2823030
org.gradle.daemon=false
Binary file not shown.
+2 -3
View File
@@ -1,6 +1,5 @@
#Mon Sep 14 12:28:28 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
zipStorePath=wrapper/dists
Vendored
+188 -120
View File
@@ -1,164 +1,232 @@
#!/usr/bin/env bash
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn ( ) {
warn () {
echo "$*"
}
} >&2
die ( ) {
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# 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
;;
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=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"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
locations of your Java installation."
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
locations of your Java installation."
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
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=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
+29 -30
View File
@@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@@ -8,26 +24,29 @@
@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 Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@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="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo locations of your Java installation.
echo location of your Java installation.
goto fail
@@ -35,44 +54,24 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo locations of your Java installation.
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz 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.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
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
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
@@ -87,4 +86,4 @@ exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
:omega
@@ -156,6 +156,12 @@ public final class Settings {
public Pair<ResourceLocation, Short>[] treeBlocks = parseItemMetaStrings(DEFAULT_TREE_BLOCKS);
/** <b>[Server-only]</b> The chance for wizard towers to generate with an evil wizard and chest inside. */
public double evilWizardChance = 0.2;
public double cooldownReductionPerLevel = 0.15;
public double potencyIncreasePerTier = 0.15;
public double durationIncreasePerLevel = 0.25;
public double rangeIncreasePerLevel = 0.25;
public double blastIncreasePerLevel = 0.25;
public double frostSlownessIncreasePerLevel = 0.5;
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
public int[] oreDimensions = {0};
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal flowers. */
@@ -192,12 +198,23 @@ public final class Settings {
public boolean playerBlockDamage = true;
/** <b>[Server-only]</b> Whether spells cast by dispensers can destroy blocks in the world. */
public boolean dispenserBlockDamage = true;
/** <b>[Server-only]</b> Whether damage should be registered with the old system (wizardry_magic/indirect_wizardry_magic) prefixed damage with the elements like
* necromancy_indirect_wizardry_magic, necromancy_wizardry_magic*/
public boolean damageTypePerElement = false;
/** <b>[Server-only]</b> Whether spell books are consumed when they are bound to a wand.*/
public boolean singleUseSpellBooks = false;
/** <b>[Server-only]</b> Whether to prevent binding the same spell to a wand multiple times*/
public boolean preventBindingSameSpellTwiceToWands = false;
/** <b>[Server-only]</b> Whether to revert to the old wand upgrade system, which only requires tomes of arcana. */
public boolean legacyWandLevelling = false;
/** <b>[Server-only]</b> Whether to tweak the blindness effect to reduce follow distance when used on non-players. */
public boolean blindnessTweak = true;
/** <b>[Server-only]</b> Whether using bonemeal on grass blocks has a chance to grow crystal flowers. */
public boolean bonemealGrowsCrystalFlowers = true;
/** <b>[Server-only]</b> Whether wands only decrement their cooldowns if a player holds them. */
public boolean wandsMustBeHeldToDecrementCooldown = false;
/** <b>[Server-only]</b> Whether to enable Wizardry mob loot injection. Allows an easier switch instead of blacklisting all entities. */
public boolean injectMobDrops = true;
/**
* <b>[Server-only]</b> List of registry names of entities which summoned creatures are allowed to attack, in addition
* to the defaults.
@@ -377,6 +394,9 @@ public final class Settings {
public boolean showSpellHUD = true;
/** <b>[Client-only]</b> Whether to show the charge meter when charging up a spell. */
public boolean showChargeMeter = true;
/** <b>[Client-only]</b> Whether to initialise the handbook's data. Setting this to false will break the in-game handbook, but might help with some
* startup crashes */
public boolean loadHandbook = true;
/** <b>[Client-only]</b> The position of the spell HUD. */
public GuiPosition spellHUDPosition = GuiPosition.BOTTOM_LEFT;
@@ -612,6 +632,29 @@ public final class Settings {
dispenserBlockDamage = property.getBoolean();
propOrder.add(property.getName());
property = config.get(GAMEPLAY_CATEGORY, "damageTypePerElement", false,
"Whether damage should be registered with the old system (wizardry_magic/indirect_wizardry_magic) prefixed damage with the elements like "
+ "necromancy_indirect_wizardry_magic, necromancy_wizardry_magic. This is disabled by default to not break existing modpacks."
+ "The intention of this setting is to allow differentiating various damage types for e.g. the Distinct Damage Descriptions mod");
property.setLanguageKey("config." + Wizardry.MODID + ".damage_type_per_element");
Wizardry.proxy.setToNamedBooleanEntry(property);
damageTypePerElement = property.getBoolean();
propOrder.add(property.getName());
property = config.get(GAMEPLAY_CATEGORY, "singleUseSpellBooks", false,
"Whether spell books are consumed when they are bound to a wand.");
property.setLanguageKey("config." + Wizardry.MODID + ".single_use_spell_books");
Wizardry.proxy.setToNamedBooleanEntry(property);
singleUseSpellBooks = property.getBoolean();
propOrder.add(property.getName());
property = config.get(GAMEPLAY_CATEGORY, "preventBindingSameSpellTwiceToWands", false,
"Whether to prevent binding the same spell to a wand multiple times");
property.setLanguageKey("config." + Wizardry.MODID + ".prevent_binding_same_spell_twice_to_wands");
Wizardry.proxy.setToNamedBooleanEntry(property);
preventBindingSameSpellTwiceToWands = property.getBoolean();
propOrder.add(property.getName());
property = config.get(GAMEPLAY_CATEGORY, "playersMoveEachOther", true,
"Whether to allow players to move other players around using magic.");
property.setLanguageKey("config." + Wizardry.MODID + ".players_move_each_other");
@@ -663,6 +706,13 @@ public final class Settings {
bonemealGrowsCrystalFlowers = property.getBoolean();
propOrder.add(property.getName());
property = config.get(GAMEPLAY_CATEGORY, "wandsMustBeHeldToDecrementCooldown", false,
"Whether wands only decrement their cooldowns if a player holds them.");
property.setLanguageKey("config." + Wizardry.MODID + ".wands_must_be_held_to_decrement_cooldown");
Wizardry.proxy.setToNamedBooleanEntry(property);
wandsMustBeHeldToDecrementCooldown = property.getBoolean();
propOrder.add(property.getName());
checkForRedundantOptions(GAMEPLAY_CATEGORY, propOrder); // Must be before the order is set!
config.setCategoryPropertyOrder(GAMEPLAY_CATEGORY, propOrder);
@@ -807,6 +857,13 @@ public final class Settings {
blindnessTweak = property.getBoolean();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "injectMobDrops", true,
"Whether to inject Wizardry loot to mobs, based on the loot table 'Mob Loot Table Whitelist' / 'Mob Loot Table Blacklist' settings. If disabled, the lists won't have any effect!");
property.setLanguageKey("config." + Wizardry.MODID + ".inject_mob_drops");
Wizardry.proxy.setToNamedBooleanEntry(property);
injectMobDrops = property.getBoolean();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "mobLootTableWhitelist", new String[0], "Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them.");
property.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_whitelist");
property.setRequiresMcRestart(true);
@@ -914,6 +971,50 @@ public final class Settings {
}
}
property = config.get(TWEAKS_CATEGORY, "cooldown_reduction_per_level", 0.15,
"The fraction by which cooldowns are reduced for each level of cooldown upgrade.",
0.05, Integer.MAX_VALUE); // Sure, I mean you COULD set it to 2^31-1... what could possibly go wrong?
property.setLanguageKey("config." + Wizardry.MODID + ".cast_command_multiplier_limit");
cooldownReductionPerLevel = property.getDouble();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "potency_increase_per_tier", 0.15,
"The fraction by which potency is increased for each tier of matching wand. May cause extreme lag with high values!",
0.05, Integer.MAX_VALUE);
property.setLanguageKey("config." + Wizardry.MODID + ".potency_increase_per_tier");
potencyIncreasePerTier = property.getDouble();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "duration_increase_per_level", 0.25,
"The fraction by which spell duration is increased for each level of duration upgrade.",
0.05, Integer.MAX_VALUE);
property.setLanguageKey("config." + Wizardry.MODID + ".duration_increase_per_level");
durationIncreasePerLevel = property.getDouble();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "range_increase_per_level", 0.25,
"The fraction by which spell range is increased for each level of range upgrade. May cause extreme lag with high values!",
0.05, Integer.MAX_VALUE);
property.setLanguageKey("config." + Wizardry.MODID + ".range_increase_per_level");
rangeIncreasePerLevel = property.getDouble();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "blast_increase_per_level", 0.25,
"The fraction by which spell blast is increased for each level of blast upgrade. May cause extreme lag with high values!",
0.05, Integer.MAX_VALUE);
property.setLanguageKey("config." + Wizardry.MODID + ".blast_increase_per_level");
blastIncreasePerLevel = property.getDouble();
propOrder.add(property.getName());
property = config.get(TWEAKS_CATEGORY, "frost_slowness_increase_per_level", 0.5,
"The fraction by which movement speed is reduced per level of frost effect.",
0.05, Integer.MAX_VALUE);
property.setLanguageKey("config." + Wizardry.MODID + ".frost_slowness_increase_per_level");
frostSlownessIncreasePerLevel = property.getDouble();
propOrder.add(property.getName());
checkForRedundantOptions(TWEAKS_CATEGORY, propOrder); // Must be before the order is set!
config.setCategoryPropertyOrder(TWEAKS_CATEGORY, propOrder);
@@ -1103,6 +1204,13 @@ public final class Settings {
showChargeMeter = property.getBoolean();
propOrder.add(property.getName());
property = config.get(CLIENT_CATEGORY, "loadHandbook", true, "Whether to initialise the in-game handbook. Setting this to false will brick the in-game handbook, but it might help if you have startup crashes.");
property.setLanguageKey("config." + Wizardry.MODID + ".load_handbook");
property.setRequiresWorldRestart(false);
Wizardry.proxy.setToNamedBooleanEntry(property);
loadHandbook = property.getBoolean();
propOrder.add(property.getName());
property = config.get(CLIENT_CATEGORY, "spellHUDPosition", GuiPosition.BOTTOM_LEFT.name, "The position of the spell HUD.", GuiPosition.names);
property.setLanguageKey("config." + Wizardry.MODID + ".spell_hud_position");
spellHUDPosition = GuiPosition.fromName(property.getString());
@@ -1,8 +1,5 @@
package electroblob.wizardry;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import electroblob.wizardry.block.BlockBookshelf;
import electroblob.wizardry.command.CommandCastSpell;
import electroblob.wizardry.command.CommandDiscoverSpell;
@@ -16,11 +13,23 @@ import electroblob.wizardry.inventory.ContainerBookshelf;
import electroblob.wizardry.misc.DonationPerksHandler;
import electroblob.wizardry.misc.Forfeit;
import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.*;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryAdvancementTriggers;
import electroblob.wizardry.registry.WizardryBlocks;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryLoot;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.SpellNetworkIDSorter;
import electroblob.wizardry.util.SpellProperties;
import electroblob.wizardry.util.WandHelper;
import electroblob.wizardry.worldgen.*;
import electroblob.wizardry.worldgen.WorldGenCrystalFlower;
import electroblob.wizardry.worldgen.WorldGenCrystalOre;
import electroblob.wizardry.worldgen.WorldGenLibraryRuins;
import electroblob.wizardry.worldgen.WorldGenObelisk;
import electroblob.wizardry.worldgen.WorldGenShrine;
import electroblob.wizardry.worldgen.WorldGenUndergroundLibraryRuins;
import electroblob.wizardry.worldgen.WorldGenWizardTower;
import net.minecraft.item.Item;
import net.minecraft.util.SoundCategory;
import net.minecraftforge.common.MinecraftForge;
@@ -39,8 +48,6 @@ import net.minecraftforge.fml.common.registry.GameRegistry;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Calendar;
/**
@@ -56,6 +63,7 @@ import java.util.Calendar;
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, acceptedMinecraftVersions = "[1.12.2]",
guiFactory = "electroblob.wizardry.WizardryGuiFactory",
updateJSON = Wizardry.updateJSON,
dependencies = "required-after:forge@[14.23.5.2847,);after:jei@[4.15.0,);after:baubles@[1.5.2,);after:antiqueatlas@[4.6,)")
public class Wizardry {
@@ -74,7 +82,13 @@ public class Wizardry {
* 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft
* 1.11.x versions, and so on.
*/
public static final String VERSION = "4.3.3";
public static final String VERSION = "4.3.13";
/**
* Json file used by Forge's built-in <a href="https://mcforge.readthedocs.io/en/1.12.x/gettingstarted/autoupdate/">update checker</a>.
* Used by the in-game mod menu to show that green icon whenever a newer version is available of the mod.
*/
public static final String updateJSON = "https://github.com/Electroblob77/Wizardry/blob/1.12.2/.forge/update.json";
// IDEA: Triggering of inbuilt Forge events in relevant places?
// IDEA: Abstract the vanilla particles behind the particle builder
@@ -113,8 +127,6 @@ public class Wizardry {
public void preInit(FMLPreInitializationEvent event){
logger = event.getModLog();
proxy.registerResourceReloadListeners();
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
settings.initConfig(event);
@@ -148,34 +160,7 @@ public class Wizardry {
@EventHandler
public void init(FMLInitializationEvent event){
Gson gson = new GsonBuilder().setPrettyPrinting().create();
for(Item item : Item.REGISTRY){
if(item.getRegistryName().getNamespace().equals(MODID)){
try{
FileWriter writer = new FileWriter("generated\\" + item.getRegistryName().getPath() + ".json");
JsonObject json = new JsonObject();
json.addProperty("parent", "item/generated");
JsonObject textures = new JsonObject();
textures.addProperty("layer0", MODID + ":items/" + item.getRegistryName().getPath());
json.add("textures", textures);
gson.toJson(json, writer);
writer.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
proxy.registerResourceReloadListeners();
settings.initConfigExtras();
@@ -217,6 +202,8 @@ public class Wizardry {
public void postInit(FMLPostInitializationEvent event){
proxy.initialiseLayers();
proxy.initialiseAnimations();
SpellNetworkIDSorter.init();
}
@EventHandler
@@ -203,7 +203,6 @@ public final class WizardryEventHandler {
// Find the angle between the direction the mob is looking and the direction the player is in
// Angle between a and b = acos((a.b) / (|a|*|b|))
double angle = Math.acos(vec.dotProduct(event.getEntity().getLookVec()) / vec.length());
System.out.println(angle);
// If the player is not within the 144-degree arc in front of the mob, it won't detect them
if(angle > 0.4 * Math.PI){
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
@@ -269,7 +268,7 @@ public final class WizardryEventHandler {
// Fireskin
if(event.getEntityLiving().isPotionActive(WizardryPotions.fireskin)
&& !MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving()))
attacker.setFire(Spells.fire_breath.getProperty(Spell.BURN_DURATION).intValue());
attacker.setFire(Spells.fire_breath.getProperty(Spell.BURN_DURATION).intValue() * 20);
// Ice Shroud
if(event.getEntityLiving().isPotionActive(WizardryPotions.ice_shroud)
@@ -307,7 +306,7 @@ public final class WizardryEventHandler {
PotionEffect effect = event.getEntityLiving().getActivePotionEffect(WizardryPotions.ward);
if(effect != null && event.getSource().isMagicDamage()){
event.setAmount(event.getAmount() * Math.max(0, 1 - 0.4f * effect.getAmplifier())); // Resistance is 20%
event.setAmount(event.getAmount() * Math.max(0, 1 - 0.2f * (1 + effect.getAmplifier()))); // Resistance is 20%
}
// Flaming and freezing swords
@@ -491,4 +490,4 @@ public final class WizardryEventHandler {
}
}
}
}
@@ -1,6 +1,7 @@
package electroblob.wizardry.client;
import electroblob.wizardry.CommonProxy;
import electroblob.wizardry.Settings;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.block.BlockBookshelf;
import electroblob.wizardry.client.animation.ActionAnimation;
@@ -19,6 +20,7 @@ import electroblob.wizardry.client.model.ModelSageArmour;
import electroblob.wizardry.client.model.ModelWizardArmour;
import electroblob.wizardry.client.particle.*;
import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory;
import electroblob.wizardry.client.renderer.RenderSpectralGolem;
import electroblob.wizardry.client.renderer.entity.*;
import electroblob.wizardry.client.renderer.entity.layers.*;
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
@@ -164,7 +166,8 @@ public class ClientProxy extends CommonProxy {
IResourceManager manager = Minecraft.getMinecraft().getResourceManager();
if(manager instanceof IReloadableResourceManager){
((IReloadableResourceManager)manager).registerReloadListener(GuiSpellDisplay::loadSkins);
((IReloadableResourceManager)manager).registerReloadListener(GuiWizardHandbook::loadHandbookFile);
if (Wizardry.settings.loadHandbook)
((IReloadableResourceManager)manager).registerReloadListener(GuiWizardHandbook::loadHandbookFile);
}
}
@@ -728,6 +731,9 @@ public class ClientProxy extends CommonProxy {
LayerTiledOverlay.initialiseLayers(LayerMindControl::new);
LayerTiledOverlay.initialiseLayers(LayerSummonAnimation::new);
LayerTiledOverlay.initialiseLayers(LayerDisintegrateAnimation::new);
LayerTiledOverlay.initialiseLayers(LayerOak::new);
LayerTiledOverlay.initialiseLayers(LayerIron::new);
LayerTiledOverlay.initialiseLayers(LayerDiamond::new);
}
@Override
@@ -766,6 +772,7 @@ public class ClientProxy extends CommonProxy {
RenderingRegistry.registerEntityRenderingHandler(EntityIceGiant.class, RenderIceGiant::new);
RenderingRegistry.registerEntityRenderingHandler(EntityPhoenix.class, RenderPhoenix::new);
RenderingRegistry.registerEntityRenderingHandler(EntitySpectralGolem.class, RenderSpectralGolem::new);
// Projectiles
RenderingRegistry.registerEntityRenderingHandler(EntityMagicMissile.class, manager -> new RenderMagicArrow(manager,
@@ -780,6 +787,7 @@ public class ClientProxy extends CommonProxy {
new ResourceLocation(Wizardry.MODID, "textures/entity/ice_lance.png"), false, 16.0, 3.0, 22, 5, false));
RenderingRegistry.registerEntityRenderingHandler(EntityFlamecatcherArrow.class, manager -> new RenderMagicArrow(manager,
new ResourceLocation(Wizardry.MODID, "textures/entity/flamecatcher_arrow.png"), false, 8, 2.0, 16, 5, true));
RenderingRegistry.registerEntityRenderingHandler(EntityConjuredArrow.class, RenderConjuredArrow::new);
RenderingRegistry.registerEntityRenderingHandler(EntityForceArrow.class, RenderForceArrow::new);
@@ -3,10 +3,7 @@ package electroblob.wizardry.client;
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.item.*;
import electroblob.wizardry.potion.PotionSlowTime;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
@@ -120,6 +117,7 @@ public final class WizardryClientEventHandler {
Minecraft.getMinecraft().player.prevRotationPitch = 0;
Minecraft.getMinecraft().player.rotationYaw = 0;
Minecraft.getMinecraft().player.rotationPitch = 0;
}
}
@@ -133,10 +131,10 @@ public final class WizardryClientEventHandler {
event.getMovementInput().jump = false;
event.getMovementInput().sneak = false;
}
if(ItemArtefact.isArtefactActive(event.getEntityPlayer(), WizardryItems.charm_move_speed)
&& event.getEntityPlayer().isHandActive()
&& event.getEntityPlayer().getActiveItemStack().getItem() instanceof ItemWand){
&& event.getEntityPlayer().getActiveItemStack().getItem() instanceof ISpellCastingItem){
// Normally speed is set to 20% when using items, this makes it 80%
event.getMovementInput().moveStrafe *= 4;
event.getMovementInput().moveForward *= 4;
@@ -93,6 +93,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
private ContainerArcaneWorkbench arcaneWorkbenchContainer;
private GuiButton applyBtn;
private GuiButton clearBtn;
private GuiButton[] sortButtons = new GuiButton[3];
private GuiTextField searchField;
@@ -126,6 +127,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
this.buttonList.clear();
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 64, this.height / 2 + 3));
this.buttonList.add(this.clearBtn = new GuiButtonClear(0, this.width / 2 + 64, this.height / 2 - 16));
this.buttonList.add(sortButtons[0] = new GuiButtonSpellSort(1, this.guiLeft - 44, this.guiTop + 8, ISpellSortable.SortType.TIER, arcaneWorkbenchContainer, this));
this.buttonList.add(sortButtons[1] = new GuiButtonSpellSort(2, this.guiLeft - 31, this.guiTop + 8, ISpellSortable.SortType.ELEMENT, arcaneWorkbenchContainer, this));
this.buttonList.add(sortButtons[2] = new GuiButtonSpellSort(3, this.guiLeft - 18, this.guiTop + 8, ISpellSortable.SortType.ALPHABETICAL, arcaneWorkbenchContainer, this));
@@ -205,6 +207,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
// Show/hide the relevant gui elements
this.applyBtn.enabled = centreSlot.getHasStack();
this.clearBtn.enabled = centreSlot.getHasStack() && centreSlot.getStack().getItem() instanceof IWorkbenchItem && ((IWorkbenchItem) centreSlot.getStack().getItem()).isClearable();
for(GuiButton button : this.sortButtons) button.visible = arcaneWorkbenchContainer.hasBookshelves();
this.searchField.setVisible(arcaneWorkbenchContainer.hasBookshelves());
@@ -444,6 +447,17 @@ public class GuiArcaneWorkbench extends GuiContainer {
animationTimer = 20;
}
if(button == clearBtn){
// Packet building
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.CLEAR_BUTTON);
WizardryPacketHandler.net.sendToServer(msg);
// Sound
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(
WizardrySounds.BLOCK_ARCANE_WORKBENCH_SPELLBIND, 0.8f));
// Animation
animationTimer = 20;
}
if(button instanceof GuiButtonSpellSort) this.arcaneWorkbenchContainer.setSortType(((GuiButtonSpellSort)button).sortType);
}
}
@@ -1006,4 +1020,36 @@ public class GuiArcaneWorkbench extends GuiContainer {
}
}
private static class GuiButtonClear extends GuiButton {
public GuiButtonClear(int id, int x, int y){
super(id, x, y, 16, 16, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.clear"));
}
@Override
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
// Whether the button is highlighted
this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
int k = 72;
int l = 236;
//int colour = 14737632;
if(this.enabled){
if(this.hovered){
k += this.width * 2;
//colour = 16777120;
}
}else{
k += this.width;
//colour = 10526880;
}
DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, TEXTURE_WIDTH, TEXTURE_HEIGHT);
//this.drawCenteredString(minecraft.fontRenderer, this.displayString, this.x + this.width / 2,
// this.y + (this.height - 8) / 2, colour);
}
}
}
@@ -151,7 +151,7 @@ class Contents {
int x = GuiWizardHandbook.isRightPage(startPage) ? left + GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : left + GuiWizardHandbook.TEXT_INSET_X;
int y = top + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT;
list.add(new GuiButtonHyperlink.Internal(0, x, y, font, entry.title, entry, 0, "", maxLineNumber-startLine, GuiWizardHandbook.isRightPage(startPage)));
list.add(new GuiButtonHyperlink.Internal(0, x, y, font, entry.title, entry, 0, "", maxLineNumber-startLine, GuiWizardHandbook.isRightPage(startPage), false));
startLine++;
@@ -28,15 +28,17 @@ public abstract class GuiButtonHyperlink extends GuiButton {
final List<String> lines;
final int linesLeft;
GuiButtonHyperlink(int id, int x, int y, FontRenderer font, String text, int indent, String suffix, int linesLeft, boolean rightPage){
GuiButtonHyperlink(int id, int x, int y, FontRenderer font, String text, int indent, String suffix, int linesLeft, boolean rightPage, boolean spaceless){
super(id, x, y, font.getStringWidth(text), font.FONT_HEIGHT, text);
// Sometimes a link has punctuation or something after it that causes it to wrap onto a new line
String linkWithSuffix = text + suffix;
// If the string won't fit any words at the end of the current line, treat it as if we started a new line
if(font.getStringWidth(linkWithSuffix.split("\\s")[0]) > GuiWizardHandbook.PAGE_WIDTH - indent){
// If the string won't fit any words (or characters in a spaceless language) at the end of the current line,
// treat it as if we started a new line
String firstWord = spaceless ? linkWithSuffix.substring(0, 1) : linkWithSuffix.split("\\s")[0];
if(font.getStringWidth(firstWord) > GuiWizardHandbook.PAGE_WIDTH - indent){
indent = 0;
this.y += font.FONT_HEIGHT;
}
@@ -149,7 +151,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
* @throws IllegalArgumentException if the given argument array is empty or contains more than 2 arguments
* @throws JsonSyntaxException if the specified link target is not a URL or a valid section ID
*/
public static GuiButtonHyperlink create(int x, int y, FontRenderer font, List<String> upToLink, String[] arguments, String suffix, int linesLeft, boolean rightPage){
public static GuiButtonHyperlink create(int x, int y, FontRenderer font, List<String> upToLink, String[] arguments, String suffix, int linesLeft, boolean rightPage, boolean spaceless){
if(arguments.length == 0 || arguments.length > 2) throw new IllegalArgumentException("Incorrect array length!");
@@ -158,7 +160,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
if(arguments[0].matches(URL_REGEX)){
button = new GuiButtonHyperlink.External(0, x, y, font, arguments[arguments.length - 1], arguments[0],
font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage);
font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage, spaceless);
}else{
@@ -167,7 +169,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
if(target == null) throw new JsonSyntaxException("Hyperlink points to nonexistent section id " + arguments[0]);
button = new GuiButtonHyperlink.Internal(0, x, y, font, arguments[arguments.length - 1],
target, font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage);
target, font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage, spaceless);
}
return button;
@@ -177,8 +179,8 @@ public abstract class GuiButtonHyperlink extends GuiButton {
final Section target;
Internal(int id, int x, int y, FontRenderer font, String text, Section target, int indent, String suffix, int linesLeft, boolean rightPage){
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage);
Internal(int id, int x, int y, FontRenderer font, String text, Section target, int indent, String suffix, int linesLeft, boolean rightPage, boolean spaceless){
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage, spaceless);
this.target = target;
}
@@ -216,8 +218,8 @@ public abstract class GuiButtonHyperlink extends GuiButton {
final ITextComponent link;
External(int id, int x, int y, FontRenderer font, String text, String url, int indent, String suffix, int linesLeft, boolean rightPage){
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage);
External(int id, int x, int y, FontRenderer font, String text, String url, int indent, String suffix, int linesLeft, boolean rightPage, boolean spaceless){
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage, spaceless);
this.link = new TextComponentString(text);
link.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)).setColor(TextFormatting.DARK_BLUE);
}
@@ -33,9 +33,13 @@ import java.awt.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* GUI class for the wizard's handbook. Like any GUI class, this is instantiated each time the book is opened. As of
@@ -55,6 +59,8 @@ public class GuiWizardHandbook extends GuiScreen {
private static final ResourceLocation DEFAULT = new ResourceLocation(Wizardry.MODID, "texts/handbook_en_us.json");
private static List<String> ADDONS = new ArrayList<>();
static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook/handbook.png");
/** Global Gson instance for the handbook. */
@@ -406,9 +412,10 @@ public class GuiWizardHandbook extends GuiScreen {
return;
}
IResource handbookFile = getHandbookResource(manager);
// IResource handbookFile = getHandbookResource(manager);
List<IResource> handbookFiles = getHandbookResource(manager);
if(handbookFile != null){
if(!handbookFiles.isEmpty()){
// Wipes all the maps before repopulating them
images.clear();
@@ -418,28 +425,31 @@ public class GuiWizardHandbook extends GuiScreen {
bookmarkSection = null; // Also need to wipe the reference to the old bookmarked section
BufferedReader reader = new BufferedReader(new InputStreamReader(handbookFile.getInputStream(), StandardCharsets.UTF_8));
for (IResource handbookFile : handbookFiles) {
JsonElement je = gson.fromJson(reader, JsonElement.class);
JsonObject json = je.getAsJsonObject();
BufferedReader reader = new BufferedReader(new InputStreamReader(handbookFile.getInputStream(), StandardCharsets.UTF_8));
JsonUtils.getJsonObject(json, "colours").entrySet().forEach(e -> colours.put(e.getKey(),
Color.decode(e.getValue().getAsString()).getRGB()));
JsonElement je = gson.fromJson(reader, JsonElement.class);
JsonObject json = je.getAsJsonObject();
// Repopulates the remaining maps
Image.populate(images, json);
CraftingRecipe.populate(recipes, json);
Section.populate(sections, json);
JsonUtils.getJsonObject(json, "colours").entrySet().forEach(e -> colours.put(e.getKey(),
Color.decode(e.getValue().getAsString()).getRGB()));
sectionList = Collections.unmodifiableList(new ArrayList<>(sections.values()));
// Repopulates the remaining maps
Image.populate(images, json);
CraftingRecipe.populate(recipes, json);
Section.populate(sections, json);
if(sections.isEmpty()){
Wizardry.logger.warn("Handbook has no sections! Aborting loading...");
return;
sectionList = Collections.unmodifiableList(new ArrayList<>(sections.values()));
if(sections.isEmpty()){
Wizardry.logger.warn("Handbook has no sections! Aborting loading...");
return;
}
bookmarkSection = JsonUtils.getString(json, "bookmark_start_section");
if(!sections.containsKey(bookmarkSection)) throw new JsonSyntaxException("Section with id " + bookmarkSection + " is undefined");
}
bookmarkSection = JsonUtils.getString(json, "bookmark_start_section");
if(!sections.containsKey(bookmarkSection)) throw new JsonSyntaxException("Section with id " + bookmarkSection + " is undefined");
}
// The first resource load on startup is done before the packet handler is loaded
@@ -455,16 +465,17 @@ public class GuiWizardHandbook extends GuiScreen {
* @param manager The resource manager instance to use.
* @return The handbook JSON file, as an IResource, or null if it was not found.
*/
private static IResource getHandbookResource(IResourceManager manager){
private static List<IResource> getHandbookResource(IResourceManager manager){
// TODO: Implement resource pack stacking to allow addon mods and texture packs to add/overwrite content
IResource handbookFile = null;
List<IResource> handbookFiles = new ArrayList<>();
try{
handbookFile = manager.getResource(new ResourceLocation(Wizardry.MODID, "texts/handbook_"
+ Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".json"));
}catch(IOException e){
}catch(Exception e){
Wizardry.logger.info("Wizard handbook JSON file missing for the current language (" + Minecraft.getMinecraft()
.getLanguageManager().getCurrentLanguage() + "). Using default (English-US) instead.");
@@ -476,7 +487,29 @@ public class GuiWizardHandbook extends GuiScreen {
}
}
return handbookFile;
handbookFiles.add(handbookFile);
for (String modid : ADDONS) {
// Addons
Wizardry.logger.info("Registering addon Wizard's Handbook contents for " + modid);
try{
handbookFile = manager.getResource(new ResourceLocation(modid, "texts/handbook_"
+ Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".json"));
}catch(Exception e){
Wizardry.logger.info("Wizard handbook JSON file missing for the current language (" + Minecraft.getMinecraft()
.getLanguageManager().getCurrentLanguage() + "). Using default (English-US) instead.");
try{
handbookFile = manager.getResource(new ResourceLocation(modid, "texts/handbook_en_us.json"));
}catch(IOException x){
Wizardry.logger.error("Couldn't find file: " + DEFAULT + ". The file may be missing; please try re-downloading and reinstalling Wizardry.", x);
}
}
handbookFiles.add(handbookFile);
}
return handbookFiles;
}
// Controls
@@ -496,24 +529,30 @@ public class GuiWizardHandbook extends GuiScreen {
Section currentSection = null;
for(Section section : sections.values()){
// We always want this button to do something, and taking the right-hand page means it always does
if(section.containsPage(doubleToSinglePage(currentPage, true))){
currentSection = section;
break;
if(currentPage < singleToDoublePage(pageCount)){
// Find current section
for(Section section : sections.values()){
// Take the right-hand page if going to the next section, and the left-hand page otherwise
if(section.containsPage(doubleToSinglePage(currentPage, button == nextSection))){
currentSection = section;
break;
}
}
}
if(currentSection != null){
List<Section> visibleSections = new ArrayList<>(sectionList);
visibleSections.removeIf(s -> !s.isUnlocked());
List<Section> visibleSections = new ArrayList<>(sectionList);
visibleSections.removeIf(s -> !s.isUnlocked());
int index = currentSection == null ? visibleSections.size() : visibleSections.indexOf(currentSection);
int index = visibleSections.indexOf(currentSection);
if(button == nextSection && index + 1 < visibleSections.size()){
if(button == nextSection){
if(index + 1 < visibleSections.size()){
currentPage = singleToDoublePage(visibleSections.get(index + 1).startPage);
}else if(index > 0){
}else{
currentPage = singleToDoublePage(pageCount);
}
}else{
if(index > 0){
currentPage = singleToDoublePage(visibleSections.get(index - 1).startPage);
}
}
@@ -570,4 +609,9 @@ public class GuiWizardHandbook extends GuiScreen {
sections.values().forEach(s -> s.updateUnlockStatus(showToasts, completedAdvancements));
}
public static void registerAddonHandbookContent(String modid) {
if (!ADDONS.contains(modid)) {
ADDONS.add(modid);
}
}
}
@@ -1,5 +1,6 @@
package electroblob.wizardry.client.gui.handbook;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -35,6 +36,8 @@ import java.util.*;
// be a non-static inner class
class Section {
private static final Set<String> SPACELESS_LANGUAGES = ImmutableSet.of("zh_cn", "zh_tw");
// Final fields are mandatory (none here though), the rest are optional
String title;
private String[] rawText;
@@ -293,7 +296,11 @@ class Section {
String linkRaw = paragraph.substring(linkStart, linkEnd + 1);
String[] arguments = paragraph.substring(linkStart + 1, linkEnd).split("\\s", 2);
String suffix = paragraph.substring(linkEnd).split("\\s", 2)[0].substring(1); // substring(1) to remove the @
String suffix = "";
// Account for trailing punctuation, except in languages that don't use spaces such as Chinese
boolean spaceless = SPACELESS_LANGUAGES.contains(Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage() == null ? "en_us" : Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode());
if(!spaceless) paragraph.substring(linkEnd).split("\\s", 2)[0].substring(1); // substring(1) to remove the @
// The index of the single page currently being formatted, relative to the section
int pageRelative = (lines.size() + upToLink.size() - 1) / maxLineNumber;
@@ -311,7 +318,7 @@ class Section {
}
// The button id only does what you use it for, so we're just not using it at all.
this.buttons.get(pageRelative).add(GuiButtonHyperlink.create(x, y, font, upToLink, arguments, suffix, maxLineNumber - lineNumber - 1, GuiWizardHandbook.isRightPage(page)));
this.buttons.get(pageRelative).add(GuiButtonHyperlink.create(x, y, font, upToLink, arguments, suffix, maxLineNumber - lineNumber - 1, GuiWizardHandbook.isRightPage(page), spaceless));
// The link button should exactly overlay the display text in the main string
// If the link has no display text specified, it displays the unformatted target string
@@ -13,17 +13,17 @@ import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.common.model.IModelState;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.*;
import java.util.function.Function;
public class ModelBookshelf implements IModel {
private static final ResourceLocation DEFAULT_BOOK_TEXTURE = new ResourceLocation(Wizardry.MODID, "blocks/books");
//private static final ResourceLocation DEFAULT_BOOK_TEXTURE = new ResourceLocation(Wizardry.MODID, "blocks/books");
private static final List<ResourceLocation> bookModelLocations = new ArrayList<>();
private static final Map<String, IBakedModel[][]> bakedBookModels = new HashMap<>();
private final ModelResourceLocation bookshelfModelLocation;
private final String variant;
@@ -49,19 +49,7 @@ public class ModelBookshelf implements IModel {
// I don't know why default state works here (surely it ought to be the state param?), but it works so who cares
IBakedModel bookshelf = bookshelfModel.bake(bookshelfModel.getDefaultState(), format, bakedTextureGetter);
ImmutableList<ResourceLocation> textures = BlockBookshelf.getBookTextures();
IBakedModel[][] books = new IBakedModel[textures.size()][BlockBookshelf.SLOT_COUNT];
for(int i = 0; i < textures.size(); i++){
ImmutableMap<String, String> retexturer = ImmutableMap.of("books", textures.get(i).toString());
for(int j = 0; j < BlockBookshelf.SLOT_COUNT; j++){
IModel bookModel = ModelLoaderRegistry.getModel(new ModelResourceLocation(bookModelLocations.get(j), variant)).retexture(retexturer);
books[i][j] = bookModel.bake(bookModel.getDefaultState(), format, bakedTextureGetter); // Same here!
}
}
IBakedModel[][] books = getBakedBookModels(format, bakedTextureGetter);
// To clarify: the whole point of doing this was to avoid having to bake 4 * 2^12 models per bookshelf type
// Therefore we have to have a baked bookshelf model that's kind of dynamic
@@ -74,6 +62,29 @@ public class ModelBookshelf implements IModel {
}
/** Retrieves the baked book models, or bakes them if they haven't been created yet. */
protected IBakedModel[][] getBakedBookModels(VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter) throws Exception{
if(bakedBookModels.get(variant) == null){
ImmutableList<ResourceLocation> textures = BlockBookshelf.getBookTextures();
bakedBookModels.put(variant, new IBakedModel[textures.size()][BlockBookshelf.SLOT_COUNT]);
for(int i = 0; i < textures.size(); i++){
ImmutableMap<String, String> retexturer = ImmutableMap.of("books", textures.get(i).toString());
for(int j = 0; j < BlockBookshelf.SLOT_COUNT; j++){
IModel bookModel = ModelLoaderRegistry.getModel(new ModelResourceLocation(bookModelLocations.get(j), variant)).retexture(retexturer);
bakedBookModels.get(variant)[i][j] = bookModel.bake(bookModel.getDefaultState(), format, bakedTextureGetter); // Same here!
}
}
}
return bakedBookModels.get(variant);
}
@Override
public Collection<ResourceLocation> getDependencies(){
return bookModelLocations;
@@ -0,0 +1,52 @@
package electroblob.wizardry.client.renderer;
import electroblob.wizardry.Wizardry;
import net.minecraft.client.model.ModelIronGolem;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.opengl.GL11;
@SideOnly(Side.CLIENT)
public class RenderSpectralGolem extends RenderLiving<EntityIronGolem>
{
private static final ResourceLocation SPECTRAL_GOLEM_TEXTURES = new ResourceLocation(Wizardry.MODID, "textures/entity/spectral_golem.png");
public RenderSpectralGolem(RenderManager renderManagerIn)
{
super(renderManagerIn, new ModelIronGolem(), 0.5F);
}
/**
* Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture.
*/
protected ResourceLocation getEntityTexture(EntityIronGolem entity)
{
return SPECTRAL_GOLEM_TEXTURES;
}
@Override
protected void preRenderCallback(EntityIronGolem entity, float partialTickTime){
super.preRenderCallback(entity, partialTickTime);
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.color(1, 1, 1, 0.7f);
}
protected void applyRotations(EntityIronGolem entityLiving, float ageInTicks, float rotationYaw, float partialTicks)
{
super.applyRotations(entityLiving, ageInTicks, rotationYaw, partialTicks);
if ((double)entityLiving.limbSwingAmount >= 0.01D)
{
float f = 13.0F;
float f1 = entityLiving.limbSwing - entityLiving.limbSwingAmount * (1.0F - partialTicks) + 6.0F;
float f2 = (Math.abs(f1 % 13.0F - 6.5F) - 3.25F) / 3.25F;
GlStateManager.rotate(6.5F * f2, 0.0F, 0.0F, 1.0F);
}
}
}
@@ -0,0 +1,37 @@
package electroblob.wizardry.client.renderer.entity;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.projectile.EntityConjuredArrow;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.RenderArrow;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.opengl.GL11;
@SideOnly(Side.CLIENT)
public class RenderConjuredArrow extends RenderArrow<EntityConjuredArrow> {
public static final ResourceLocation CONJURED_ARROW_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/conjured_arrow.png");
public RenderConjuredArrow(RenderManager manager) {
super(manager);
}
@Override
protected ResourceLocation getEntityTexture(EntityConjuredArrow entity) {
return CONJURED_ARROW_TEXTURE;
}
@Override
public void doRender(EntityConjuredArrow entity, double x, double y, double z, float entityYaw, float partialTicks) {
GlStateManager.pushMatrix();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GlStateManager.color(1, 1, 1, 0.4f);
super.doRender(entity, x, y, z, entityYaw, partialTicks);
GlStateManager.popMatrix();
}
}
@@ -0,0 +1,53 @@
package electroblob.wizardry.client.renderer.entity.layers;
import electroblob.wizardry.registry.WizardryPotions;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.RenderLivingBase;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.ResourceLocation;
/**
* Layer used to render the diamondflesh texture on creatures with the diamondflesh effect.
*
* @author WinDanesz
* @since Wizardry 4.3.7
*/
public class LayerDiamond extends LayerTiledOverlay<EntityLivingBase> {
private static final ResourceLocation TEXTURE = new ResourceLocation("textures/blocks/diamond_block.png");
public LayerDiamond(RenderLivingBase<?> renderer){
super(renderer);
}
@Override
public boolean shouldRender(EntityLivingBase entity, float partialTicks){
return !entity.isInvisible() && entity.isPotionActive(WizardryPotions.diamondflesh);
}
@Override
public ResourceLocation getTexture(EntityLivingBase entity, float partialTicks){
return TEXTURE;
}
@Override
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
float ageInTicks, float netHeadYaw, float headPitch, float scale){
GlStateManager.enableBlend();
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
int j = entity.getBrightnessForRender();
int k = j % 65536;
int l = j / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float) k, (float) l);
super.doRenderLayer(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
GlStateManager.disableBlend();
}
}
@@ -0,0 +1,53 @@
package electroblob.wizardry.client.renderer.entity.layers;
import electroblob.wizardry.registry.WizardryPotions;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.RenderLivingBase;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.ResourceLocation;
/**
* Layer used to render the ironflesh texture on creatures with the ironflesh effect.
*
* @author WinDanesz
* @since Wizardry 4.3.7
*/
public class LayerIron extends LayerTiledOverlay<EntityLivingBase> {
private static final ResourceLocation TEXTURE = new ResourceLocation("textures/blocks/iron_block.png");
public LayerIron(RenderLivingBase<?> renderer){
super(renderer);
}
@Override
public boolean shouldRender(EntityLivingBase entity, float partialTicks){
return !entity.isInvisible() && entity.isPotionActive(WizardryPotions.ironflesh);
}
@Override
public ResourceLocation getTexture(EntityLivingBase entity, float partialTicks){
return TEXTURE;
}
@Override
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
float ageInTicks, float netHeadYaw, float headPitch, float scale){
GlStateManager.enableBlend();
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
int j = entity.getBrightnessForRender();
int k = j % 65536;
int l = j / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float) k, (float) l);
super.doRenderLayer(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
GlStateManager.disableBlend();
}
}
@@ -0,0 +1,53 @@
package electroblob.wizardry.client.renderer.entity.layers;
import electroblob.wizardry.registry.WizardryPotions;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.GlStateManager.DestFactor;
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.RenderLivingBase;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.ResourceLocation;
/**
* Layer used to render the oakflesh texture on creatures with the oakflesh effect.
*
* @author WinDanesz
* @since Wizardry 4.3.7
*/
public class LayerOak extends LayerTiledOverlay<EntityLivingBase> {
private static final ResourceLocation TEXTURE = new ResourceLocation("textures/blocks/log_oak.png");
public LayerOak(RenderLivingBase<?> renderer){
super(renderer);
}
@Override
public boolean shouldRender(EntityLivingBase entity, float partialTicks){
return !entity.isInvisible() && entity.isPotionActive(WizardryPotions.oakflesh);
}
@Override
public ResourceLocation getTexture(EntityLivingBase entity, float partialTicks){
return TEXTURE;
}
@Override
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
float ageInTicks, float netHeadYaw, float headPitch, float scale){
GlStateManager.enableBlend();
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
int j = entity.getBrightnessForRender();
int k = j % 65536;
int l = j / 65536;
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float) k, (float) l);
super.doRenderLayer(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
GlStateManager.disableBlend();
}
}
@@ -1,5 +1,6 @@
package electroblob.wizardry.constants;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.WizardryEventHandler;
/** Stores various global constants used in Wizardry. */
@@ -17,17 +18,17 @@ public final class Constants {
/** The bonus amount of wand upgrades that can be applied to a non-elemental wand. */
public static final int NON_ELEMENTAL_UPGRADE_BONUS = 3;
/** The fraction by which cooldowns are reduced for each level of cooldown upgrade. */
public static final float COOLDOWN_REDUCTION_PER_LEVEL = 0.15f;
public static float COOLDOWN_REDUCTION_PER_LEVEL = 0.15f;
/** The fraction by which maximum charge is increased for each level of storage upgrade. */
public static final float STORAGE_INCREASE_PER_LEVEL = 0.15f;
/** The fraction by which potency is increased for each tier of matching wand. */
public static final float POTENCY_INCREASE_PER_TIER = 0.15f;
public static float POTENCY_INCREASE_PER_TIER = 0.15f;
/** The fraction by which spell duration is increased for each level of duration upgrade. */
public static final float DURATION_INCREASE_PER_LEVEL = 0.25f;
public static float DURATION_INCREASE_PER_LEVEL = 0.25f;
/** The fraction by which spell range is increased for each level of range upgrade. */
public static final float RANGE_INCREASE_PER_LEVEL = 0.25f;
public static float RANGE_INCREASE_PER_LEVEL = 0.25f;
/** The fraction by which spell blast radius is increased for each level of range upgrade. */
public static final float BLAST_RADIUS_INCREASE_PER_LEVEL = 0.25f;
public static float BLAST_RADIUS_INCREASE_PER_LEVEL = 0.25f;
/** The fraction by which movement speed is reduced per level of frost effect. */
public static final double FROST_SLOWNESS_PER_LEVEL = 0.5;
/** The fraction by which movement speed is reduced per level of decay effect. */
@@ -46,7 +47,15 @@ public final class Constants {
* won't spawn again if something is already standing in it.
*/
public static final int DECAY_SPREAD_INTERVAL = 8;
/** The fraction by which potency is increased per level of the empowerment effect. */
public static final float EMPOWERMENT_POTENCY_PER_LEVEL = 0.25f;
// making this as an update to the existing values to not break addons directly relying on the fields
static {
POTENCY_INCREASE_PER_TIER = (float) Wizardry.settings.potencyIncreasePerTier;
COOLDOWN_REDUCTION_PER_LEVEL = (float) Wizardry.settings.cooldownReductionPerLevel;
DURATION_INCREASE_PER_LEVEL = (float) Wizardry.settings.durationIncreasePerLevel;
RANGE_INCREASE_PER_LEVEL = (float) Wizardry.settings.rangeIncreasePerLevel;
BLAST_RADIUS_INCREASE_PER_LEVEL = (float) Wizardry.settings.blastIncreasePerLevel;
RANGE_INCREASE_PER_LEVEL = (float) Wizardry.settings.frostSlownessIncreasePerLevel;
}
}
@@ -64,6 +64,11 @@ public interface IStoredVariable<T> extends IVariable<T> {
this.ticker = (p, t) -> t; // Initialise this with a do-nothing function, can be overwritten later
}
@Override
public String getKey() {
return key;
}
/**
* Replaces this variable's update method with the given update function. <i>Beware of auto-unboxing of
* primitive types! For lambda expressions, check the second parameter isn't null before operating on it.
@@ -47,7 +47,10 @@ public interface IVariable<T> {
*/
void write(ByteBuf buf, T value);
String getKey();
/**
*
* Reads this variable's value from the given {@link ByteBuf}.
*/
T read(ByteBuf buf);
@@ -110,6 +113,11 @@ public interface IVariable<T> {
// NYI
}
@Override
public String getKey() {
return "none"; // we don't mind as these are never synced (electroblob.wizardry.data.IVariable.Variable.isSynced)
}
@Override
public T read(ByteBuf buf){
return null; // NYI
@@ -199,9 +199,14 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
}
/** Returns a set containing the registered {@link IStoredVariable} objects for which {@link IVariable#isSynced()}
* returns true. Used internally for packet reading. */
public static Set<IVariable> getSyncedVariables(){
return storedVariables.stream().filter(IVariable::isSynced).collect(Collectors.toSet());
* returns true, ordered by their keys obtained from {@link IVariable#getKey()}. Used internally for packets. */
public static Set<IVariable> getSyncedVariablesOrderedByKey(){
Comparator<IVariable> keyComparator = Comparator.comparing(IVariable::getKey);
return storedVariables.stream()
.filter(IVariable::isSynced)
.sorted(keyComparator)
.collect(Collectors.toCollection(LinkedHashSet::new));
}
/**
@@ -382,6 +387,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
activeImbuements.add((Imbuement)enchantment);
}else{
// Otherwise, removes the enchantment from the item
((Imbuement) enchantment).onImbuementRemoval(stack);
iterator.remove(); // FIXME: Apparently this can cause a CME
}
}
@@ -33,7 +33,7 @@ import java.util.Iterator;
* than having to deal with each of them separately, which would be inefficient and cumbersome (the former of those
* classes cannot extend the latter because they both need to extend different subclasses of
* {@link net.minecraft.enchantment.Enchantment}).
*
*
* @since Wizardry 1.2
*/
@Mod.EventBusSubscriber
@@ -69,12 +69,16 @@ public interface Imbuement {
Enchantment enchantment = Enchantment.getEnchantmentByID(enchantmentTag.getShort("id"));
// If the item contains a magic weapon enchantment, remove it from the item
if(enchantment instanceof Imbuement){
((Imbuement) enchantment).onImbuementRemoval(stack);
enchantmentIt.remove();
}
}
}
}
/** Allows executing some custom logic before this imbuement is being removed from the stack. Called when the imbuement is about to be removed. */
default void onImbuementRemoval(ItemStack stack){}
@SubscribeEvent
public static void onPlayerOpenContainerEvent(PlayerContainerEvent event){
// Brute-force fix to stop enchanted books in dungeon chests from having imbuements on them.
@@ -1,10 +1,8 @@
package electroblob.wizardry.entity.construct;
import electroblob.wizardry.entity.projectile.EntityConjuredArrow;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.spell.Spell;
import net.minecraft.entity.projectile.EntityTippedArrow;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
@@ -30,7 +28,7 @@ public class EntityArrowRain extends EntityScaledConstruct {
double y = posY + world.rand.nextDouble() * (double)height;
double z = posZ + (world.rand.nextDouble() - 0.5D) * (double)width;
EntityTippedArrow arrow = new EntityTippedArrow(world, x, y, z);
EntityConjuredArrow arrow = new EntityConjuredArrow(world, x, y, z);
arrow.motionX = MathHelper.cos((float)Math.toRadians(this.rotationYaw + 90));
arrow.motionY = -0.6;
@@ -38,7 +36,6 @@ public class EntityArrowRain extends EntityScaledConstruct {
arrow.shootingEntity = this.getCaster();
arrow.setDamage(7.0d * damageMultiplier);
arrow.setPotionEffect(new ItemStack(Items.ARROW));
this.world.spawnEntity(arrow);
}
@@ -35,8 +35,8 @@ public class EntityDecay extends EntityMagicConstruct {
0.6F + rand.nextFloat() * 0.15F);
if(!this.world.isRemote){
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(1.0d, this.posX, this.posY,
this.posZ, this.world);
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2f, this.posX, this.posY,
this.posZ, this.height, this.world);
for(EntityLivingBase target : targets){
if(target != this.getCaster()){
// If this check wasn't here the potion would be reapplied every tick and hence the entity would be
@@ -32,9 +32,9 @@ public class EntityFireRing extends EntityScaledConstruct {
super.onUpdate();
if(!this.world.isRemote){
if(this.ticksExisted % 5 == 0 && !this.world.isRemote){
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, this.posX, this.posY, this.posZ, this.world);
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2, this.posX, this.posY, this.posZ, this.height, this.world);
for(EntityLivingBase target : targets){
@@ -34,7 +34,7 @@ public class EntityFireSigil extends EntityScaledConstruct {
if(!this.world.isRemote){
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, posX, posY, posZ, world);
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2, this.posX, this.posY, this.posZ, this.height, this.world);
for(EntityLivingBase target : targets){
@@ -168,6 +168,10 @@ public class EntityForcefield extends EntityMagicConstruct implements ICustomHit
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
}
if (this.ticksExisted % 5 == 0) {
this.lifetime = (int) (lifetime * 0.99);
}
}else{
Vec3d relativeImpactPos = targetRelativePos.normalize().scale(radius);
@@ -36,8 +36,8 @@ public class EntityFrostSigil extends EntityScaledConstruct {
if(!this.world.isRemote){
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, this.posX, this.posY,
this.posZ, this.world);
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(width/2, this.posX, this.posY,
this.posZ, this.height, this.world);
for(EntityLivingBase target : targets){
@@ -33,30 +33,32 @@ public class EntityHealAura extends EntityScaledConstruct {
if(!this.world.isRemote){
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, posX, posY, posZ, world);
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(width/2, posX, posY, posZ, this.height, world);
for(EntityLivingBase target : targets){
if(this.isValidTarget(target)){
if(target.isEntityUndead()){
if(target.isEntityUndead()) {
double velX = target.motionX;
double velY = target.motionY;
double velZ = target.motionZ;
if(this.getCaster() != null){
target.attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.RADIANT),
Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
}else{
target.attackEntityFrom(DamageSource.MAGIC, Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
}
if (this.ticksExisted % 10 == 1) {
if (this.getCaster() != null) {
target.attackEntityFrom(
MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.RADIANT),
Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
} else {
target.attackEntityFrom(DamageSource.MAGIC, Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
}
// Removes knockback
target.motionX = velX;
target.motionY = velY;
target.motionZ = velZ;
// Removes knockback
target.motionX = velX;
target.motionY = velY;
target.motionZ = velZ;
}
}
}else if(target.getHealth() < target.getMaxHealth() && target.ticksExisted % 5 == 0){
@@ -39,8 +39,8 @@ public class EntityLightningSigil extends EntityScaledConstruct {
this.setDead();
}
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, this.posX, this.posY,
this.posZ, this.world);
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2, this.posX, this.posY,
this.posZ, this.height, this.world);
for(EntityLivingBase target : targets){
@@ -68,13 +68,15 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
/** Data parameter for the wizard's element. */
private static final DataParameter<Integer> ELEMENT = EntityDataManager.createKey(EntityEvilWizard.class,
DataSerializers.VARINT);
/** Data parameters for the wizard's current continuous spell. */
private static final DataParameter<String> CONTINUOUS_SPELL = EntityDataManager.createKey(EntityEvilWizard.class, DataSerializers.STRING);
private static final DataParameter<Integer> SPELL_COUNTER = EntityDataManager.createKey(EntityEvilWizard.class, DataSerializers.VARINT);
/** The resource location for the evil wizard's loot table. */
private static final ResourceLocation LOOT_TABLE = new ResourceLocation(Wizardry.MODID, "entities/evil_wizard");
// Field implementations
private List<Spell> spells = new ArrayList<Spell>(4);
private Spell continuousSpell;
private int spellCounter;
public EntityEvilWizard(World world){
@@ -93,6 +95,8 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
super.entityInit();
this.dataManager.register(HEAL_COOLDOWN, -1);
this.dataManager.register(ELEMENT, -1);
this.dataManager.register(CONTINUOUS_SPELL, "ebwizardry:none");
this.dataManager.register(SPELL_COUNTER, 0);
}
@Override
@@ -168,23 +172,23 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
}
@Override
public void setContinuousSpell(Spell spell){
this.continuousSpell = spell;
public void setContinuousSpell(Spell spell) {
this.dataManager.set(CONTINUOUS_SPELL, spell.getRegistryName().toString());
}
@Override
public Spell getContinuousSpell(){
return this.continuousSpell;
public Spell getContinuousSpell() {
return Spell.get(this.dataManager.get(CONTINUOUS_SPELL));
}
@Override
public void setSpellCounter(int count){
spellCounter = count;
public void setSpellCounter(int count) {
this.dataManager.set(SPELL_COUNTER, count);
}
@Override
public int getSpellCounter(){
return spellCounter;
public int getSpellCounter() {
return this.dataManager.get(SPELL_COUNTER);
}
@Override
@@ -52,7 +52,7 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature {
super(world);
this.setPosition(target.posX, target.posY, target.posZ);
this.startRiding(target);
this.setOwnerId(caster.getUniqueID());
if (caster != null) this.setOwnerId(caster.getUniqueID());
this.setSlimeSize(2, false); // Needs to be called before setting the experience value to 0
this.experienceValue = 0;
this.lifetime = lifetime;
@@ -0,0 +1,192 @@
package electroblob.wizardry.entity.living;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.ParticleBuilder;
import net.minecraft.entity.EntityFlying;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.EntityAIAttackMelee;
import net.minecraft.entity.ai.EntityAIHurtByTarget;
import net.minecraft.entity.ai.EntityAILookAtVillager;
import net.minecraft.entity.ai.EntityAILookIdle;
import net.minecraft.entity.ai.EntityAIMoveThroughVillage;
import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction;
import net.minecraft.entity.ai.EntityAIMoveTowardsTarget;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.EnumHand;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World;
import java.util.UUID;
public class EntitySpectralGolem extends EntityIronGolem implements ISummonedCreature {
private static final DataParameter<Boolean> SPAWN_PARTICLES = EntityDataManager.createKey(EntitySpectralGolem.class, DataSerializers.BOOLEAN);
// Field implementations
private int lifetime = -1;
private UUID casterUUID;
// Setter + getter implementations
@Override public int getLifetime(){ return lifetime; }
@Override public void setLifetime(int lifetime){ this.lifetime = lifetime; }
@Override public UUID getOwnerId(){ return casterUUID; }
@Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; }
/** Creates a new golem minion in the given world. */
public EntitySpectralGolem(World world){
super(world);
this.experienceValue = 0;
}
@Override
protected void entityInit(){
super.entityInit();
this.dataManager.register(SPAWN_PARTICLES, true);
}
@Override
protected void initEntityAI() {
this.tasks.addTask(1, new EntityAIAttackMelee(this, 1.0D, true));
this.tasks.addTask(2, new EntityAIMoveTowardsTarget(this, 0.9D, 32.0F));
this.tasks.addTask(3, new EntityAIMoveThroughVillage(this, 0.6D, true));
this.tasks.addTask(4, new EntityAIMoveTowardsRestriction(this, 1.0D));
this.tasks.addTask(5, new EntityAILookAtVillager(this));
this.tasks.addTask(6, new EntityAIWanderAvoidWater(this, 0.6D));
this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
this.tasks.addTask(8, new EntityAILookIdle(this));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
0, false, true, this.getTargetSelector()));
}
@Override protected void setEquipmentBasedOnDifficulty(DifficultyInstance difficulty){} // They don't have equipment!
// Implementations
@Override
public void setRevengeTarget(EntityLivingBase entity){
if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity);
}
@Override
public void onUpdate(){
super.onUpdate();
this.updateDelegate();
// Adds a dust particle effect
if(this.world.isRemote){
double x = this.posX - this.width / 2 + this.rand.nextFloat() * width;
double y = this.posY + this.height * this.rand.nextFloat() + 0.2f;
double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width;
ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(x, y, z).clr(0.7f, 0.9f, 1).shaded(true).spawn(world);
}
}
@Override
public void onSpawn(){
if(this.dataManager.get(SPAWN_PARTICLES)) this.spawnParticleEffect();
}
@Override
public void onDespawn(){
this.spawnParticleEffect();
}
private void spawnParticleEffect(){
if(this.world.isRemote){
for(int i = 0; i < 15; i++){
this.world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + this.rand.nextFloat() - 0.5f,
this.posY + this.rand.nextFloat() * 2, this.posZ + this.rand.nextFloat() - 0.5f, 0, 0, 0);
}
}
}
@Override
public boolean hasParticleEffect(){
return true;
}
@Override
public boolean hasAnimation(){
return this.dataManager.get(SPAWN_PARTICLES) || this.ticksExisted > 20;
}
public void hideParticles(){
this.dataManager.set(SPAWN_PARTICLES, false);
}
@Override
protected boolean processInteract(EntityPlayer player, EnumHand hand){
// In this case, the delegate method determines whether super is called.
// Rather handily, we can make use of Java's short-circuiting method of evaluating OR statements.
return this.interactDelegate(player, hand) || super.processInteract(player, hand);
}
@Override
public void writeEntityToNBT(NBTTagCompound nbttagcompound){
super.writeEntityToNBT(nbttagcompound);
this.writeNBTDelegate(nbttagcompound);
}
@Override
public void readEntityFromNBT(NBTTagCompound nbttagcompound){
super.readEntityFromNBT(nbttagcompound);
this.readNBTDelegate(nbttagcompound);
}
// Recommended overrides
@Override protected int getExperiencePoints(EntityPlayer player){ return 0; }
@Override protected boolean canDropLoot(){ return false; }
@Override protected Item getDropItem(){ return null; }
@Override protected ResourceLocation getLootTable(){ return null; }
@Override public boolean canPickUpLoot(){ return false; }
// This vanilla method has nothing to do with the custom despawn() method.
@Override protected boolean canDespawn(){
return getCaster() == null && getOwnerId() == null;
}
@Override
public boolean getCanSpawnHere(){
return this.world.getDifficulty() != EnumDifficulty.PEACEFUL;
}
@Override
public boolean canAttackClass(Class<? extends EntityLivingBase> entityType){
// Returns true unless the given entity type is a flying entity.
return !EntityFlying.class.isAssignableFrom(entityType);
}
@Override
public ITextComponent getDisplayName(){
if(getCaster() != null){
return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(),
new TextComponentTranslation("entity." + this.getEntityString() + ".name"));
}else{
return super.getDisplayName();
}
}
@Override
public boolean hasCustomName(){
// If this returns true, the renderer will show the nameplate when looking directly at the entity
return Wizardry.settings.summonedCreatureNames && getCaster() != null;
}
}
@@ -47,6 +47,7 @@ import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@@ -67,7 +68,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
protected Predicate<Entity> targetSelector;
/** The wizard's trades. */
private MerchantRecipeList trades;
public MerchantRecipeList trades;
/** The wizard's current customer. */
@Nullable
private EntityPlayer customer;
@@ -81,11 +82,12 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
private static final DataParameter<Integer> HEAL_COOLDOWN = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT);
/** Data parameter for the wizard's element. */
private static final DataParameter<Integer> ELEMENT = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT);
/** Data parameters for the wizard's current continuous spell. */
private static final DataParameter<String> CONTINUOUS_SPELL = EntityDataManager.createKey(EntityWizard.class, DataSerializers.STRING);
private static final DataParameter<Integer> SPELL_COUNTER = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT);
// Field implementations
private List<Spell> spells = new ArrayList<Spell>(4);
private Spell continuousSpell;
private int spellCounter;
/** A set of the positions of the blocks that are part of this wizard's tower. */
private Set<BlockPos> towerBlocks;
@@ -102,6 +104,8 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
super.entityInit();
this.dataManager.register(HEAL_COOLDOWN, -1);
this.dataManager.register(ELEMENT, 0);
this.dataManager.register(CONTINUOUS_SPELL, "ebwizardry:none");
this.dataManager.register(SPELL_COUNTER, 0);
}
@Override
@@ -126,8 +130,12 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
if(entity != null && !entity.isInvisible()
&& AllyDesignationSystem.isValidTarget(EntityWizard.this, entity)){
// ... and is a mob, a summoned creature ...
if((entity instanceof IMob || entity instanceof ISummonedCreature
// ... and is a non summoned creature mob ...
if((entity instanceof IMob && !(entity instanceof ISummonedCreature)
// or is a summoned creature with a mob owner or an owner who has attacked the wizard ...
|| entity instanceof ISummonedCreature && (((ISummonedCreature)entity).getOwner() instanceof IMob || ((ISummonedCreature)entity).getOwner() == this.getRevengeTarget() || ((ISummonedCreature) entity).getOwner() == this.getAttackTarget())
// ... or in the whitelist ...
|| Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist)
.contains(EntityList.getKey(entity.getClass())))
@@ -182,23 +190,23 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
}
@Override
public void setContinuousSpell(Spell spell){
this.continuousSpell = spell;
public void setContinuousSpell(Spell spell) {
this.dataManager.set(CONTINUOUS_SPELL, spell.getRegistryName().toString());
}
@Override
public Spell getContinuousSpell(){
return this.continuousSpell;
public Spell getContinuousSpell() {
return Spell.get(this.dataManager.get(CONTINUOUS_SPELL));
}
@Override
public void setSpellCounter(int count){
spellCounter = count;
public void setSpellCounter(int count) {
this.dataManager.set(SPELL_COUNTER, count);
}
@Override
public int getSpellCounter(){
return spellCounter;
public int getSpellCounter() {
return this.dataManager.get(SPELL_COUNTER);
}
@Override
@@ -634,10 +642,9 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){
// This means it is more likely for spell books sold to be of the same element as the wizard if the
// wizard has an element.
return new ItemStack(WizardryItems.spell_book, 1,
specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata());
return getBookStackForSpell(specialismSpells.get(rand.nextInt(specialismSpells.size())));
}else{
return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).metadata());
return getBookStackForSpell(spells.get(rand.nextInt(spells.size())));
}
}else{
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
@@ -656,10 +663,9 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){
// This means it is more likely for spell books sold to be of the same element as the wizard if the
// wizard has an element.
return new ItemStack(WizardryItems.spell_book, 1,
specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata());
return getBookStackForSpell(specialismSpells.get(rand.nextInt(specialismSpells.size())));
}else{
return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).metadata());
return getBookStackForSpell(spells.get(rand.nextInt(spells.size())));
}
}else if(randomiser < 6){
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
@@ -693,10 +699,9 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){
// This means it is more likely for spell books sold to be of the same element as the wizard if the
// wizard has an element.
return new ItemStack(WizardryItems.spell_book, 1,
specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata());
return getBookStackForSpell(specialismSpells.get(rand.nextInt(specialismSpells.size())));
}else{
return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).metadata());
return getBookStackForSpell(spells.get(rand.nextInt(spells.size())));
}
}else if(randomiser < 6){
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
@@ -721,8 +726,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
if(randomiser < 5 && this.getElement() != Element.MAGIC && !specialismSpells.isEmpty()){
// Master spells can only be sold by a specialist in that element.
return new ItemStack(WizardryItems.spell_book, 1,
specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata());
return getBookStackForSpell(specialismSpells.get(rand.nextInt(specialismSpells.size())));
}else if(randomiser < 6){
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
@@ -798,7 +802,6 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
Tier maxTier = Tier.NOVICE;
List<Spell> npcSpells = Spell.getSpells(s -> s.canBeCastBy(wizard, false));
npcSpells.removeIf(s -> !s.applicableForItem(WizardryItems.spell_book));
for(int i = 0; i < n; i++){
@@ -846,6 +849,22 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
return maxTier;
}
/**
* Helper method to handle addon spell books.
* @param spell the spell to look up.
* @return Checks all items of the spell's namespace (modid) if they are applicable for the spell and returns the first match, or falls back to WizardryItems.spell_book if no match was found.
*/
public static ItemStack getBookStackForSpell(Spell spell) {
String modid = spell.getRegistryName().getNamespace();
if (modid.equals(Wizardry.MODID)) {
return new ItemStack(WizardryItems.spell_book, 1, spell.metadata());
}
Optional<Item> firstMatch = ForgeRegistries.ITEMS.getValuesCollection().stream().filter(v -> v instanceof ItemSpellBook && spell.applicableForItem(v)
&& v.getRegistryName().getNamespace().equals(modid)).findFirst();
return firstMatch.map(item -> new ItemStack(item, 1, spell.metadata())).orElseGet(() -> new ItemStack(WizardryItems.spell_book, 1, spell.metadata()));
}
@Override
public void writeSpawnData(ByteBuf data){
data.writeInt(textureIndex);
@@ -0,0 +1,34 @@
package electroblob.wizardry.entity.projectile;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public class EntityConjuredArrow extends EntityArrow {
public EntityConjuredArrow(World worldIn) {
super(worldIn);
}
public EntityConjuredArrow(World worldIn, double x, double y, double z) {
super(worldIn, x, y, z);
}
public EntityConjuredArrow(World worldIn, EntityLivingBase shooter) {
super(worldIn, shooter);
}
@Override
public void onUpdate() {
super.onUpdate();
if (this.timeInGround > 400) {
this.setDead();
}
}
@Override
protected ItemStack getArrowStack() {
return ItemStack.EMPTY;
}
}
@@ -0,0 +1,45 @@
package electroblob.wizardry.event;
import electroblob.wizardry.item.ItemArtefact;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import net.minecraftforge.fml.common.eventhandler.Event;
/**
* ArtefactCheckEvent is fired when a check happens for an ItemArtefact using {@link electroblob.wizardry.item.ItemArtefact#isArtefactActive(net.minecraft.entity.player.EntityPlayer, net.minecraft.item.Item)}
* <i>Fired on both sides.</i><br>
* <br>
* This event is {@link Cancelable}. <br>
* <br>
* This event has a result. {@link HasResult}. Set the result to Result.ALLOW to consider an artefact "active"<br>
* <br>
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
*
* @author WinDanesz
* @since Wizardry 4.3.10
*/
@Cancelable
@Event.HasResult
public class ArtefactCheckEvent extends PlayerEvent {
ItemArtefact artefact;
EntityPlayer player;
public ArtefactCheckEvent(EntityPlayer player, ItemArtefact artefact) {
super(player);
this.player = player;
this.artefact = artefact;
setResult(Result.DENY);
}
public ItemArtefact getArtefact() {
return artefact;
}
public EntityPlayer getPlayer() {
return player;
}
}
@@ -0,0 +1,56 @@
package electroblob.wizardry.event;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.tileentity.TileEntityImbuementAltar;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
import net.minecraftforge.fml.common.eventhandler.Event;
/**
* ImbuementActivateEvent is fired when {@link TileEntityImbuementAltar#getImbuementResult(net.minecraft.item.ItemStack, electroblob.wizardry.constants.Element[],
* boolean, net.minecraft.world.World, net.minecraft.entity.player.EntityPlayer)} is called to allow adding in imbuement "recipes" dynamically, based on the
* contents of the Imbuement altar's receptacles and the item placed on the altar.
*
* <i>Note that this event is only fired on the server side.</i><br>
* <br>
* To alter the result of the imbuement process, change the {@link electroblob.wizardry.event.ImbuementActivateEvent#result} result of the process.<br>
* <br>
* This event is {@link Cancelable}. If this event is canceled, no further processing takes place.<br>
* <br>
* This event does not have a result. {@link Event.HasResult}<br>
* <br>
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
*
* @author WinDanesz
* @since Wizardry 4.3.5
*/
@Cancelable
public class ImbuementActivateEvent extends Event {
/** The item stack being imbued */
public ItemStack input;
/** The elements of the four receptacles */
public Element[] receptacleElements;
/** A reference to the current world object (may be null if {@code fullLootGen} is false) */
public World world;
/** The player that last interacted with the imbuement altar, or null if there isn't one (or if this is being queried for other reasons, e.g. JEI) */
public EntityPlayer lastUser;
/** The resulting item stack of the imbuement process */
public ItemStack result;
public ImbuementActivateEvent(ItemStack input, Element[] receptacleElements, World world, EntityPlayer lastUser, ItemStack result) {
super();
this.input = input;
this.receptacleElements = receptacleElements;
this.world = world;
this.lastUser = lastUser;
this.result = result;
}
}
@@ -0,0 +1,37 @@
package electroblob.wizardry.event;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.fml.common.eventhandler.Cancelable;
/**
* ResurrectionEvent is fired when a player is about to be resurrected, after all other checks have been performed.
* <i>Note that this event is only fired on the server side.</i><br>
* <br>
* This event is {@link Cancelable}. If this event is canceled, the player is not resurrected.<br>
* <br>
* This event does not have a result. {@link HasResult}<br>
* <br>
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
*
* @author Electroblob
* @since Wizardry 2.1
*/
@Cancelable
public class ResurrectionEvent extends PlayerEvent {
private final EntityPlayer caster;
public ResurrectionEvent(EntityPlayer player, EntityPlayer caster){
super(player);
this.caster = caster;
}
/** Returns the player that cast the resurrection spell. If the player resurrected themselves, this will be the
* same as {@link ResurrectionEvent#getEntityPlayer()}. */
public EntityPlayer getCaster(){
return caster;
}
}
@@ -46,6 +46,10 @@ public final class WizardryBaublesIntegration {
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.RING, BaubleType.RING);
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.AMULET, BaubleType.AMULET);
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.CHARM, BaubleType.CHARM);
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.BELT, BaubleType.BELT);
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.BODY, BaubleType.BODY);
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.HEAD, BaubleType.HEAD);
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.TRINKET, BaubleType.TRINKET);
}
public static boolean enabled(){
@@ -452,6 +452,24 @@ public class ContainerArcaneWorkbench extends Container implements ISpellSortabl
}
}
/**
* Called (via {@link electroblob.wizardry.packet.PacketControlInput PacketControlInput}) when the clear button in
* the arcane workbench GUI is pressed.
*/
// As of 2.1, for the sake of events and neatness of code, this was moved here from TileEntityArcaneWorkbench.
// As of 4.2, the spell binding/charging/upgrading code was delegated (via IWorkbenchItem) to the items themselves.
public void onClearButtonPressed(EntityPlayer player){
Slot centre = this.getSlot(CENTRE_SLOT);
if(centre.getStack().getItem() instanceof IWorkbenchItem){ // Should always be true, but no harm in checking.
Slot[] spellBooks = this.inventorySlots.subList(0, 8).toArray(new Slot[8]);
((IWorkbenchItem) centre.getStack().getItem()).onClearButtonPressed(player, centre, this.getSlot(CRYSTAL_SLOT), this.getSlot(UPGRADE_SLOT), spellBooks);
}
}
/** Scrolls to the given row number. */
public void scrollTo(int row){
this.scroll = row;
@@ -55,6 +55,26 @@ public interface IWorkbenchItem {
*/
boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks);
/**
* Called when this item is in the central slot of an arcane workbench and the apply clear is pressed. Items must
* implement this method to define what happens when the apply button is pressed.
* @param player The player that pressed the apply button.
* @param centre The central slot in the arcane workbench. This slot will always contain a stack of the implementing
* item, or in other words, <i>it is guaranteed that</i> {@code this == centre.getStack().getItem()}.
* @param crystals The magic crystal slot of the arcane workbench.
* @param upgrade The upgrade slot of the arcane workbench.
* @param spellBooks An array of the <i>active</i> (visible) spell book slots in the arcane workbench. The length of
* the array will be equal to the value returned by {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}.
* */
default void onClearButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){};
/**
* Must be overridden in the item class to make the clear button in the Arcane Workbench clickable.
* */
default boolean isClearable() {
return false;
}
/**
* Returns whether the tooltip (dark grey box) should be drawn when this item is in an arcane workbench. Only
* called client-side.
@@ -10,6 +10,7 @@ import electroblob.wizardry.entity.living.ISummonedCreature;
import electroblob.wizardry.entity.projectile.EntityDart;
import electroblob.wizardry.entity.projectile.EntityForceOrb;
import electroblob.wizardry.entity.projectile.EntityIceShard;
import electroblob.wizardry.event.ArtefactCheckEvent;
import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.event.SpellCastEvent.Source;
import electroblob.wizardry.integration.DamageSafetyChecker;
@@ -37,6 +38,7 @@ import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraftforge.common.BiomeDictionary;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingEvent;
@@ -88,7 +90,11 @@ public class ItemArtefact extends Item {
/** An artefact that improves attacking spells. Two of these can be active at any one time. */ RING(2),
/** An artefact that improves defensive spells. One of these can be active at any one time. */ AMULET(1),
/** An artefact that improves utility spells. One of these can be active at any one time. */ CHARM(1);
/** An artefact that improves utility spells. One of these can be active at any one time. */ CHARM(1),
/** Added for add-on artefacts. */ BELT(1),
/** Added for add-on artefacts. */ BODY(1),
/** Added for add-on artefacts. */ HEAD(1),
/** Added for add-on artefacts. */ TRINKET(1);
public final int maxAtOnce;
@@ -123,6 +129,8 @@ public class ItemArtefact extends Item {
this.enabled = enabled;
}
public boolean isEnabled() { return enabled; }
@Override
public EnumRarity getRarity(ItemStack stack){
return rarity;
@@ -176,6 +184,13 @@ public class ItemArtefact extends Item {
if(!((ItemArtefact)artefact).enabled) return false; // Disabled in the config
ArtefactCheckEvent event = new ArtefactCheckEvent(player, (ItemArtefact) artefact);
if(MinecraftForge.EVENT_BUS.post(event)) return false;
if (event.getResult() == Event.Result.ALLOW) {
return true;
}
if(WizardryBaublesIntegration.enabled()){
return WizardryBaublesIntegration.isBaubleEquipped(player, artefact);
}else{
@@ -344,6 +359,8 @@ public class ItemArtefact extends Item {
findMatchingWandAndExecute(player, Spells.shield, wand -> {
if(wand.getItem() instanceof ItemScroll) return; // Ignore scrolls since they shouldn't work
List<Entity> projectiles = EntityUtils.getEntitiesWithinRadius(5, player.posX, player.posY, player.posZ, world, Entity.class);
projectiles.removeIf(e -> !(e instanceof IProjectile));
Vec3d look = player.getLookVec();
@@ -765,6 +782,7 @@ public class ItemArtefact extends Item {
&& Streams.stream(player.getHeldEquipment()).anyMatch(s -> s.getItem() instanceof ISpellCastingItem
&& ((ISpellCastingItem)s.getItem()).getCurrentSpell(s).getElement() == Element.NECROMANCY))){
event.getEntityLiving().addPotionEffect(new PotionEffect(WizardryPotions.curse_of_soulbinding, 400));
CurseOfSoulbinding.getSoulboundCreatures(WizardData.get(player)).add(event.getEntity().getUniqueID());
}
@@ -193,14 +193,6 @@ public class ItemFlamecatcher extends ItemBow implements IConjuredItem {
charge = net.minecraftforge.event.ForgeEventFactory.onArrowLoose(stack, world, (EntityPlayer)entity, charge, true);
if(charge < 0) return;
if(stack.getTagCompound() != null){
int shotsLeft = stack.getTagCompound().getInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY) - 1;
stack.getTagCompound().setInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY, shotsLeft);
if(shotsLeft == 0 && !world.isRemote){
stack.setItemDamage(getMaxDamage(stack) - getAnimationFrames());
}
}
float velocity = (float)charge / DRAW_TIME;
velocity = (velocity * velocity + velocity * 2) / 3;
@@ -208,6 +200,14 @@ public class ItemFlamecatcher extends ItemBow implements IConjuredItem {
if((double)velocity >= 0.1D){
if(stack.getTagCompound() != null){
int shotsLeft = stack.getTagCompound().getInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY) - 1;
stack.getTagCompound().setInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY, shotsLeft);
if(shotsLeft == 0 && !world.isRemote){
stack.setItemDamage(getMaxDamage(stack) - getAnimationFrames());
}
}
if(!world.isRemote){
EntityFlamecatcherArrow arrow = new EntityFlamecatcherArrow(world);
arrow.aim(player, EntityFlamecatcherArrow.SPEED * velocity);
@@ -84,8 +84,15 @@ public class ItemManaFlask extends Item {
stacks.addAll(player.inventory.armorInventory); // player#getArmorInventoryList() only returns an Iterable
if(stacks.stream().anyMatch(s -> s.getItem() instanceof IManaStoringItem && !((IManaStoringItem)s.getItem()).isManaFull(s))){
player.setActiveHand(hand);
if(player.capabilities.isCreativeMode){
findAndChargeItem(flask, player);
}else{
player.setActiveHand(hand);
}
return new ActionResult<>(EnumActionResult.SUCCESS, flask);
}else{
return new ActionResult<>(EnumActionResult.FAIL, flask);
}
@@ -106,30 +113,32 @@ public class ItemManaFlask extends Item {
public ItemStack onItemUseFinish(ItemStack stack, World world, EntityLivingBase entity){
if(entity instanceof EntityPlayer){
EntityPlayer player = (EntityPlayer)entity;
List<ItemStack> stacks = InventoryUtils.getPrioritisedHotbarAndOffhand(player);
stacks.addAll(player.inventory.armorInventory); // player#getArmorInventoryList() only returns an Iterable
// Find the chargeable item with the least mana
ItemStack toCharge = stacks.stream()
.filter(s -> s.getItem() instanceof IManaStoringItem && !((IManaStoringItem)s.getItem()).isManaFull(s))
.min(Comparator.comparingDouble(s -> ((IManaStoringItem)s.getItem()).getFullness(s))).orElse(null);
if(toCharge != null){
((IManaStoringItem)toCharge.getItem()).rechargeMana(toCharge, size.capacity);
EntityUtils.playSoundAtPlayer(player, WizardrySounds.ITEM_MANA_FLASK_USE, 1, 1);
EntityUtils.playSoundAtPlayer(player, WizardrySounds.ITEM_MANA_FLASK_RECHARGE, 0.7f, 1.1f);
if(!player.isCreative()) stack.shrink(1);
player.getCooldownTracker().setCooldown(this, 20);
}
findAndChargeItem(stack, (EntityPlayer)entity);
}
return stack;
}
private void findAndChargeItem(ItemStack stack, EntityPlayer player){
List<ItemStack> stacks = InventoryUtils.getPrioritisedHotbarAndOffhand(player);
stacks.addAll(player.inventory.armorInventory); // player#getArmorInventoryList() only returns an Iterable
// Find the chargeable item with the least mana
ItemStack toCharge = stacks.stream()
.filter(s -> s.getItem() instanceof IManaStoringItem && !((IManaStoringItem)s.getItem()).isManaFull(s))
.min(Comparator.comparingDouble(s -> ((IManaStoringItem)s.getItem()).getFullness(s))).orElse(null);
if(toCharge != null){
((IManaStoringItem)toCharge.getItem()).rechargeMana(toCharge, size.capacity);
EntityUtils.playSoundAtPlayer(player, WizardrySounds.ITEM_MANA_FLASK_USE, 1, 1);
EntityUtils.playSoundAtPlayer(player, WizardrySounds.ITEM_MANA_FLASK_RECHARGE, 0.7f, 1.1f);
if(!player.isCreative()) stack.shrink(1);
player.getCooldownTracker().setCooldown(this, 20);
}
}
}
@@ -15,9 +15,16 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.*;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@@ -100,6 +107,13 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
tooltip.add(spell.getElement().getDisplayName());
tooltip.add(spell.getType().getDisplayName());
}
// Advanced tooltips displays the source mod's name if the spell is not from Wizardry
if (advanced.isAdvanced() && this.getRegistryName().toString().equals(Wizardry.MODID + ":scroll") && !spell.getRegistryName().getNamespace().equals(Wizardry.MODID)) {
String modId = spell.getRegistryName().getNamespace();
String name = new Style().setColor(TextFormatting.BLUE).setItalic(true).getFormattingCode() +
Loader.instance().getIndexedModList().get(modId).getMetadata().name;
tooltip.add(name);
}
}
}
@@ -195,7 +209,7 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
if(!spell.isContinuous && !caster.isCreative()) stack.shrink(1);
// Now uses the vanilla cooldown mechanic to prevent spamming of spells
if(!spell.isContinuous) caster.getCooldownTracker().setCooldown(this, spell.getCooldown());
if(!spell.isContinuous && !caster.isCreative()) caster.getCooldownTracker().setCooldown(this, spell.getCooldown());
}
return true;
@@ -230,7 +244,7 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Finish(Source.SCROLL, spell, user, modifiers, castingTick));
spell.finishCasting(user.world, user, Double.NaN, Double.NaN, Double.NaN, null, castingTick, modifiers);
if(user instanceof EntityPlayer){
if(user instanceof EntityPlayer && !((EntityPlayer)user).isCreative()){
((EntityPlayer)user).getCooldownTracker().setCooldown(this, spell.getCooldown());
}
}
@@ -1,6 +1,7 @@
package electroblob.wizardry.item;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.projectile.EntityConjuredArrow;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.util.InventoryUtils;
import net.minecraft.enchantment.EnchantmentHelper;
@@ -14,6 +15,7 @@ import net.minecraft.init.SoundEvents;
import net.minecraft.item.IItemPropertyGetter;
import net.minecraft.item.ItemArrow;
import net.minecraft.item.ItemBow;
import net.minecraft.item.ItemSpectralArrow;
import net.minecraft.item.ItemStack;
import net.minecraft.stats.StatList;
import net.minecraft.util.*;
@@ -197,8 +199,7 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem {
if(!world.isRemote){
ItemArrow itemarrow = (ItemArrow)Items.ARROW;
EntityArrow entityarrow = itemarrow.createArrow(world, new ItemStack(itemarrow), entityplayer);
EntityConjuredArrow entityarrow = new EntityConjuredArrow(world, entityplayer);
entityarrow.shoot(entityplayer, entityplayer.rotationPitch, entityplayer.rotationYaw, 0.0F,
f * 3.0F, 1.0F);
@@ -12,10 +12,15 @@ import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.*;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary;
@@ -96,6 +101,13 @@ public class ItemSpellBook extends Item {
tooltip.add(spell.getElement().getDisplayName());
tooltip.add(spell.getType().getDisplayName());
}
// Advanced tooltips displays the source mod's name if the spell is not from Wizardry
if (advanced.isAdvanced() && this.getRegistryName().toString().equals(Wizardry.MODID + ":spell_book") && !spell.getRegistryName().getNamespace().equals(Wizardry.MODID)) {
String modId = spell.getRegistryName().getNamespace();
String name = new Style().setColor(TextFormatting.BLUE).setItalic(true).getFormattingCode() +
Loader.instance().getIndexedModList().get(modId).getMetadata().name;
tooltip.add(name);
}
}
}
@@ -28,6 +28,7 @@ import net.minecraft.inventory.Slot;
import net.minecraft.item.EnumAction;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
@@ -45,6 +46,7 @@ import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
@@ -226,9 +228,15 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
}
@Override
public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean isHeld){
public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean isHeldInMainhand){
boolean isHeld = isHeldInMainhand || entity instanceof EntityLivingBase && ItemStack.areItemStacksEqual(stack, ((EntityLivingBase) entity).getHeldItemOffhand());
WandHelper.decrementCooldowns(stack);
// If Wizardry.settings.wandsMustBeHeldToDecrementCooldown is false, the cooldowns will be decremented.
// If Wizardry.settings.wandsMustBeHeldToDecrementCooldown is true and isHeld is true, the cooldowns will also be decremented.
// If Wizardry.settings.wandsMustBeHeldToDecrementCooldown is true and isHeld is false, the cooldowns will not be decremented.
if (!Wizardry.settings.wandsMustBeHeldToDecrementCooldown || isHeld) {
WandHelper.decrementCooldowns(stack);
}
// Decrements wand damage (increases mana) every 1.5 seconds if it has a condenser upgrade
if(!world.isRemote && !this.isManaFull(stack) && world.getTotalWorldTime() % Constants.CONDENSER_TICK_INTERVAL == 0){
@@ -836,8 +844,19 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
Spell spell = Spell.byMetadata(spellBooks[i].getStack().getItemDamage());
// If the wand is powerful enough for the spell, it's not already bound to that slot and it's enabled for wands
if(!(spell.getTier().level > this.tier.level) && spells[i] != spell && spell.isEnabled(SpellProperties.Context.WANDS)){
// Decide if we can bind this multiple times
if (Wizardry.settings.preventBindingSameSpellTwiceToWands && Arrays.stream(spells).anyMatch(s -> s == spell)) {
continue;
}
spells[i] = spell;
changed = true;
// setting to consume books upon use
if (Wizardry.settings.singleUseSpellBooks) {
spellBooks[i].getStack().shrink(1);
}
}
}
}
@@ -845,31 +864,35 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
WandHelper.setSpells(centre.getStack(), spells);
// Charges wand by appropriate amount
if(crystals.getStack() != ItemStack.EMPTY && !this.isManaFull(centre.getStack())){
int chargeDepleted = this.getManaCapacity(centre.getStack()) - this.getMana(centre.getStack());
int manaPerItem = Constants.MANA_PER_CRYSTAL;
if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD;
if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA;
if(crystals.getStack().getCount() * manaPerItem < chargeDepleted){
// If there aren't enough crystals to fully charge the wand
this.rechargeMana(centre.getStack(), crystals.getStack().getCount() * manaPerItem);
crystals.decrStackSize(crystals.getStack().getCount());
}else{
// If there are excess crystals (or just enough)
this.setMana(centre.getStack(), this.getManaCapacity(centre.getStack()));
crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / manaPerItem));
}
if (WandHelper.rechargeManaOnApplyButtonPressed(centre, crystals)) {
changed = true;
}
return changed;
}
@Override
public void onClearButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){
ItemStack stack = centre.getStack();
if (stack.hasTagCompound() && stack.getTagCompound().hasKey(WandHelper.SPELL_ARRAY_KEY)) {
NBTTagCompound nbt = stack.getTagCompound();
int[] spells = nbt.getIntArray(WandHelper.SPELL_ARRAY_KEY);
int expectedSlotCount = BASE_SPELL_SLOTS + WandHelper.getUpgradeLevel(stack,
WizardryItems.attunement_upgrade);
// unbrick broken wands
if (spells.length < expectedSlotCount) {
spells = new int[expectedSlotCount];
}
Arrays.fill(spells, 0);
nbt.setIntArray(WandHelper.SPELL_ARRAY_KEY, spells);
stack.setTagCompound(nbt);
}
}
@Override
public boolean isClearable() { return true; }
// hitEntity is only called server-side, so we'll have to use events
@SubscribeEvent
public static void onAttackEntityEvent(AttackEntityEvent event){
@@ -1,5 +1,7 @@
package electroblob.wizardry.item;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Streams;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.client.DrawingUtils;
@@ -44,7 +46,11 @@ import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nullable;
import java.util.*;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier;
@Mod.EventBusSubscriber
@@ -54,13 +60,35 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
private static final float SAGE_OTHER_COST_REDUCTION = 0.2f;
private static final float WARLOCK_SPEED_BOOST = 0.2f;
private static final UUID WARLOCK_SPEED_BOOST_UUID = UUID.fromString("4bad7152-2663-4b1b-bb59-552e92847031");
// Standard ItemArmor modifiers
private static final UUID[] ARMOR_MODIFIERS = new UUID[] {UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")};
@Override
public Multimap<String, AttributeModifier> getItemAttributeModifiers(EntityEquipmentSlot slot) {
// The vanilla armor handling logic from ItemArmor.getItemAttributeModifiers was moved to ItemWizardArmour.getAttributeModifiers to allow checking if the stack has enough mana
Multimap<String, AttributeModifier> multimap = ArrayListMultimap.create();
return multimap;
}
@Override
public Multimap<String, AttributeModifier> getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack) {
Multimap<String, AttributeModifier> multimap = super.getAttributeModifiers(slot, stack);
// only grant armor if the equipment has mana
if (slot == this.armorType && !((ItemWizardArmour) stack.getItem()).isManaEmpty(stack)) {
multimap.put(SharedMonsterAttributes.ARMOR.getName(), new AttributeModifier(ARMOR_MODIFIERS[slot.getIndex()], "Armor modifier", this.damageReduceAmount, 0));
multimap.put(SharedMonsterAttributes.ARMOR_TOUGHNESS.getName(), new AttributeModifier(ARMOR_MODIFIERS[slot.getIndex()], "Armor toughness", this.toughness, 0));
}
return multimap;
}
public enum ArmourClass {
WIZARD(Materials.SILK, () -> null, "wizard", 0.1f, 0, "hat", "robe", "leggings", "boots"),
SAGE(Materials.SAGE, () -> WizardryItems.resplendent_thread, "sage", 0.2f, 0, "hat", "robe", "leggings", "boots"),
BATTLEMAGE(Materials.BATTLEMAGE, () -> WizardryItems.crystal_silver_plating, "battlemage", 0.05f, 0.15f, "helmet", "chestplate", "leggings", "boots"),
WARLOCK(Materials.WARLOCK, () -> WizardryItems.ethereal_crystalweave, "warlock", 0.1f, 0.3f, "hood", "robe", "leggings", "boots");
BATTLEMAGE(Materials.BATTLEMAGE, () -> WizardryItems.crystal_silver_plating, "battlemage", 0.05f, 0.05f, "helmet", "chestplate", "leggings", "boots"),
WARLOCK(Materials.WARLOCK, () -> WizardryItems.ethereal_crystalweave, "warlock", 0.1f, 0.1f, "hood", "robe", "leggings", "boots");
/** The armour material to use for this armour class. */
final ArmorMaterial material;
@@ -181,8 +209,8 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
@Override
public void onArmorTick(World world, EntityPlayer player, ItemStack itemStack){
if(armorType == EntityEquipmentSlot.HEAD && isWearingFullSet(player, element, ArmourClass.BATTLEMAGE)
&& player.ticksExisted % 20 == 0){
if(armorType == EntityEquipmentSlot.HEAD && player.ticksExisted % 20 == 0
&& isWearingFullSet(player, element, ArmourClass.BATTLEMAGE) && doAllArmourPiecesHaveMana(player)){
player.addPotionEffect(new PotionEffect(WizardryPotions.ward, 219, 0, true, false));
}
}
@@ -209,7 +237,7 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
modifiers.set(WizardryItems.cooldown_upgrade, modifiers.get(WizardryItems.cooldown_upgrade) - armourClass.cooldownReduction, true);
// Full set bonuses
if(this.armorType == EntityEquipmentSlot.HEAD && isWearingFullSet(caster, element, armourClass)){
if(this.armorType == EntityEquipmentSlot.HEAD && isWearingFullSet(caster, element, armourClass) && doAllArmourPiecesHaveMana(caster)){
if(armourClass == ArmourClass.SAGE && spell.getElement() != this.element){
modifiers.set(SpellModifiers.COST, 1 - SAGE_OTHER_COST_REDUCTION, false);
}
@@ -277,7 +305,7 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
if(this.armourClass == ArmourClass.WIZARD){
for(ArmourClass armourClass : ArmourClass.values()){
if(upgrade.getItem() == armourClass.upgradeItem.get()){
Item newArmour = getArmour(this.element, armourClass, this.getEquipmentSlot());
Item newArmour = getArmour(this.element, armourClass, this.armorType);
ItemStack newStack = new ItemStack(newArmour);
((ItemWizardArmour)newArmour).setMana(newStack, this.getMana(stack));
newStack.setTagCompound(stack.getTagCompound());
@@ -306,7 +334,12 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
int chargeDepleted = this.getManaCapacity(centre.getStack()) - this.getMana(centre.getStack());
int manaPerItem = Constants.MANA_PER_CRYSTAL;
// Not too pretty but allows addons implementing the IManaStoringItem interface to provide their mana amount for custom crystals,
// previously this was defaulted to the regular crystal's amount, allowing players to exploit it if a crystal was worth less mana than that.
int manaPerItem = crystals.getStack().getItem() instanceof IManaStoringItem ?
((IManaStoringItem) crystals.getStack().getItem()).getMana(crystals.getStack()) :
crystals.getStack().getItem() instanceof ItemCrystal ? Constants.MANA_PER_CRYSTAL : Constants.MANA_PER_SHARD;
if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD;
if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA;
@@ -335,7 +368,7 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
IAttributeInstance movementSpeed = event.getEntityLiving().getAttributeMap().getAttributeInstance(SharedMonsterAttributes.MOVEMENT_SPEED);
if(isWearingFullSet(event.getEntityLiving(), null, ArmourClass.WARLOCK)){
if(isWearingFullSet(event.getEntityLiving(), null, ArmourClass.WARLOCK) && doAllArmourPiecesHaveMana(event.getEntityLiving())){
// Only apply the modifier once (can't just check this is the helmet since it might not be the last piece equipped)
if(movementSpeed.getModifier(WARLOCK_SPEED_BOOST_UUID) == null){
movementSpeed.applyModifier(new AttributeModifier(WARLOCK_SPEED_BOOST_UUID, "Warlock set bonus", WARLOCK_SPEED_BOOST, Operations.MULTIPLY_FLAT));
@@ -405,7 +438,7 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
* @param armourClass The class to check, or null to accept any class as long as they are all the same.
* @return True if the entity is wearing a full set of the given element and class, false otherwise.
*/
private static boolean isWearingFullSet(EntityLivingBase entity, @Nullable Element element, @Nullable ArmourClass armourClass){
public static boolean isWearingFullSet(EntityLivingBase entity, @Nullable Element element, @Nullable ArmourClass armourClass){
ItemStack helmet = entity.getItemStackFromSlot(EntityEquipmentSlot.HEAD);
if(!(helmet.getItem() instanceof ItemWizardArmour)) return false;
Element e = element == null ? ((ItemWizardArmour)helmet.getItem()).element : element;
@@ -416,6 +449,16 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
&& ((ItemWizardArmour)entity.getItemStackFromSlot(s).getItem()).armourClass == ac);
}
/**
* Returns whether the given entity's armour pieces which implement {@link IManaStoringItem} has mana. Ignores pieces which doesn't have a mana storage.
* @param entity The entity to query.
* @return True if all armour pieces which implement {@link IManaStoringItem} has mana, false otherwise.
*/
public static boolean doAllArmourPiecesHaveMana(EntityLivingBase entity){
return Arrays.stream(InventoryUtils.ARMOUR_SLOTS).noneMatch(s -> entity.getItemStackFromSlot(s).getItem() instanceof IManaStoringItem
&& ((IManaStoringItem) entity.getItemStackFromSlot(s).getItem()).isManaEmpty(entity.getItemStackFromSlot(s)));
}
@SubscribeEvent
public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){
// Undo the mob detection penalty for wearing armour when invisible
@@ -10,6 +10,7 @@ import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.text.Style;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
@@ -36,7 +37,11 @@ public class ItemWizardHandbook extends Item {
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
ItemStack stack = player.getHeldItem(hand);
player.openGui(Wizardry.instance, WizardryGuiHandler.WIZARD_HANDBOOK, world, 0, 0, 0);
if (Wizardry.settings.loadHandbook) {
player.openGui(Wizardry.instance, WizardryGuiHandler.WIZARD_HANDBOOK, world, 0, 0, 0);
} else if (!world.isRemote){
player.sendStatusMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":wizard_handbook.disabled"), false);
}
return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
}
@@ -12,12 +12,15 @@ import electroblob.wizardry.entity.living.*;
import electroblob.wizardry.entity.projectile.EntityFirebomb;
import electroblob.wizardry.entity.projectile.EntityMagicFireball;
import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.event.SpellCastEvent.Source;
import electroblob.wizardry.item.IManaStoringItem;
import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.registry.*;
import electroblob.wizardry.spell.Banish;
import electroblob.wizardry.spell.Spell;
import electroblob.wizardry.util.BlockUtils;
import electroblob.wizardry.util.EntityUtils;
import electroblob.wizardry.util.SpellModifiers;
import electroblob.wizardry.util.SpellProperties.Context;
import net.minecraft.entity.effect.EntityLightningBolt;
import net.minecraft.entity.item.EntityFallingBlock;
@@ -174,6 +177,23 @@ public abstract class Forfeit {
forfeit.apply(event.getWorld(), player);
ItemStack stack = player.getHeldItemMainhand();
if(!(stack.getItem() instanceof ISpellCastingItem)){
stack = player.getHeldItemOffhand();
if(!(stack.getItem() instanceof ISpellCastingItem)) stack = ItemStack.EMPTY;
}
if(!stack.isEmpty()){
// Still need to charge the player mana or consume the scroll
if(event.getSource() == Source.SCROLL){
if(!player.isCreative()) stack.shrink(1);
}else if(stack.getItem() instanceof IManaStoringItem){
int cost = (int)(event.getSpell().getCost() * event.getModifiers().get(SpellModifiers.COST) + 0.1f); // Weird floaty rounding
((IManaStoringItem)stack.getItem()).consumeMana(stack, cost, player);
}
}
WizardryAdvancementTriggers.spell_failure.triggerFor(player);
EntityUtils.playSoundAtPlayer(player, forfeit.getSound(), WizardrySounds.SPELLS, 1, 1);
@@ -222,10 +242,11 @@ public abstract class Forfeit {
}));
add(Tier.MASTER, Element.FIRE, create("burn_surroundings", (w, p) -> {
if(!w.isRemote){
if(!w.isRemote && EntityUtils.canDamageBlocks(p, w)){
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition(), 6);
for(BlockPos pos : sphere){
if(w.rand.nextBoolean() && w.isAirBlock(pos)) w.setBlockState(pos, Blocks.FIRE.getDefaultState());
if(w.rand.nextBoolean() && w.isAirBlock(pos) && BlockUtils.canPlaceBlock(p, w, pos))
w.setBlockState(pos, Blocks.FIRE.getDefaultState());
}
}
}));
@@ -376,10 +397,11 @@ public abstract class Forfeit {
}));
add(Tier.NOVICE, Element.EARTH, create("snares", (w, p) -> {
if(!w.isRemote){
if(!w.isRemote && EntityUtils.canDamageBlocks(p, w)){
for(EnumFacing direction : EnumFacing.HORIZONTALS){
BlockPos pos = p.getPosition().offset(direction);
if(BlockUtils.canBlockBeReplaced(w, pos)) w.setBlockState(pos, WizardryBlocks.snare.getDefaultState());
if(BlockUtils.canBlockBeReplaced(w, pos) && BlockUtils.canPlaceBlock(p, w, pos))
w.setBlockState(pos, WizardryBlocks.snare.getDefaultState());
}
}
}));
@@ -393,9 +415,9 @@ public abstract class Forfeit {
}));
add(Tier.APPRENTICE, Element.EARTH, create("uproot_plants", (w, p) -> {
if(!w.isRemote){
if(!w.isRemote && EntityUtils.canDamageBlocks(p, w)){
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition(), 5);
sphere.removeIf(pos -> !(w.getBlockState(pos).getBlock() instanceof IPlantable));
sphere.removeIf(pos -> !(w.getBlockState(pos).getBlock() instanceof IPlantable) || !BlockUtils.canBreakBlock(p, w, pos));
sphere.forEach(pos -> w.destroyBlock(pos, true));
}
}));
@@ -403,9 +425,9 @@ public abstract class Forfeit {
add(Tier.APPRENTICE, Element.EARTH, create("poison_self", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.POISON, 400, 1))));
add(Tier.ADVANCED, Element.EARTH, create("flood", (w, p) -> {
if(!w.isRemote){
if(!w.isRemote && EntityUtils.canDamageBlocks(p, w)){
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition().up(), 2);
sphere.removeIf(pos -> !BlockUtils.canBlockBeReplaced(w, pos, true));
sphere.removeIf(pos -> !BlockUtils.canBlockBeReplaced(w, pos, true) || !BlockUtils.canPlaceBlock(p, w, pos));
sphere.forEach(pos -> w.setBlockState(pos, Blocks.WATER.getDefaultState()));
}
}));
@@ -413,8 +435,7 @@ public abstract class Forfeit {
add(Tier.MASTER, Element.EARTH, create("bury_self", (w, p) -> {
if(!w.isRemote){
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition(), 4);
sphere.removeIf(pos -> !w.getBlockState(pos).isFullCube());
sphere.removeIf(pos -> BlockUtils.isBlockUnbreakable(w, pos));
sphere.removeIf(pos -> !w.getBlockState(pos).isFullCube() || BlockUtils.isBlockUnbreakable(w, pos) || BlockUtils.canBreakBlock(p, w, pos));
sphere.forEach(pos -> {
EntityFallingBlock block = new EntityFallingBlock(w, pos.getX() + 0.5, pos.getY() + 0.5,
pos.getZ() + 0.5, w.getBlockState(pos));
@@ -465,6 +486,8 @@ public abstract class Forfeit {
}
}));
add(Tier.MASTER, Element.SORCERY, create("teleport_self_large_distance", (w, p) -> ((Banish)Spells.banish).teleport(p, w, 8 + w.rand.nextDouble() * 700)));
add(Tier.NOVICE, Element.HEALING, create("damage_self", (w, p) -> p.attackEntityFrom(DamageSource.MAGIC, 4)));
add(Tier.NOVICE, Element.HEALING, create("spill_armour", (w, p) -> {
@@ -1,13 +1,13 @@
package electroblob.wizardry.misc;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.item.IManaStoringItem;
import electroblob.wizardry.item.ItemManaFlask;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@@ -15,6 +15,8 @@ import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapelessOreRecipe;
import java.util.Collection;
/**
* Implements a dynamic crafting recipe for recharging items with mana flasks.
*
@@ -24,6 +26,8 @@ import net.minecraftforge.oredict.ShapelessOreRecipe;
@Mod.EventBusSubscriber
public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
private static final Multimap<Item, RecipeRechargeWithFlask> FLASK_RECIPES = HashMultimap.create();
private final IManaStoringItem chargeable;
private final ItemManaFlask flask;
@@ -38,6 +42,7 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
if(!(chargeable instanceof IManaStoringItem)) throw new IllegalArgumentException("Item to be charged must be an instance of IManaStoringItem");
this.chargeable = (IManaStoringItem)chargeable;
this.flask = flask;
FLASK_RECIPES.put(chargeable, this);
}
// Commented out for now because JEI spams the log with errors about the recipe having no output
@@ -91,11 +96,11 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
// This means that although I no longer have to replace the result every tick, I still need to do it here
// ... I thought the whole point of the new recipe system was so that I DIDN'T have to do this?!
if(event.craftMatrix instanceof InventoryCrafting){
for(IRecipe recipe : CraftingManager.REGISTRY){
if(recipe instanceof RecipeRechargeWithFlask
&& recipe.matches((InventoryCrafting)event.craftMatrix, event.player.world)){
Collection<RecipeRechargeWithFlask> recipes = FLASK_RECIPES.get(event.crafting.getItem());
for(RecipeRechargeWithFlask recipe : recipes){
if(recipe.matches((InventoryCrafting)event.craftMatrix, event.player.world)){
// Have to modify the itemstack in the actual event, it cannot be replaced
((RecipeRechargeWithFlask)recipe).rechargeItemAndCopyNBT(event.crafting, (InventoryCrafting)event.craftMatrix);
recipe.rechargeItemAndCopyNBT(event.crafting, (InventoryCrafting)event.craftMatrix);
}
}
}
@@ -1,6 +1,7 @@
package electroblob.wizardry.packet;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.event.ResurrectionEvent;
import electroblob.wizardry.inventory.ContainerArcaneWorkbench;
import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.packet.PacketControlInput.Message;
@@ -13,6 +14,7 @@ import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
@@ -49,6 +51,17 @@ public class PacketControlInput implements IMessageHandler<Message, IMessage> {
break;
case CLEAR_BUTTON:
if(!(player.openContainer instanceof ContainerArcaneWorkbench)){
Wizardry.logger.warn("Received a PacketControlInput, but the player that sent it was not " +
"currently using an arcane workbench. This should not happen!");
}else{
((ContainerArcaneWorkbench)player.openContainer).onClearButtonPressed(player);
}
break;
case NEXT_SPELL_KEY:
if(wand.getItem() instanceof ISpellCastingItem){
@@ -79,6 +92,7 @@ public class PacketControlInput implements IMessageHandler<Message, IMessage> {
.filter(s -> Resurrection.canStackResurrect(s, player)).findFirst().orElse(null);
if(stack != null){
if(MinecraftForge.EVENT_BUS.post(new ResurrectionEvent(player, player))) break;
// This should suffice, since this is the only way a player can cast resurrection when dead!
((ISpellCastingItem)stack.getItem()).cast(stack, Spells.resurrection, player, EnumHand.MAIN_HAND, 0, new SpellModifiers());
break;
@@ -130,7 +144,7 @@ public class PacketControlInput implements IMessageHandler<Message, IMessage> {
}
public enum ControlType {
APPLY_BUTTON, NEXT_SPELL_KEY, PREVIOUS_SPELL_KEY, RESURRECT_BUTTON, CANCEL_RESURRECT, POSSESSION_PROJECTILE
APPLY_BUTTON, NEXT_SPELL_KEY, PREVIOUS_SPELL_KEY, RESURRECT_BUTTON, CANCEL_RESURRECT, POSSESSION_PROJECTILE, CLEAR_BUTTON
}
public static class Message implements IMessage {
@@ -10,7 +10,11 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* <b>[Server -> Client]</b> This packet is sent to synchronise any fields that need synchronising in
@@ -54,9 +58,8 @@ public class PacketPlayerSync implements IMessageHandler<Message, IMessage> {
this.seed = buf.readLong();
this.selectedMinionID = buf.readInt();
this.spellData = new HashMap<>();
WizardData.getSyncedVariables().forEach(v -> spellData.put(v, v.read(buf)));
WizardData.getSyncedVariablesOrderedByKey().forEach(v -> spellData.put(v, v.read(buf)));
// Have to send empty tags to guarantee correct ByteBuf size/order, but no point keeping the resulting nulls
spellData.values().removeIf(Objects::isNull);
@@ -73,7 +76,7 @@ public class PacketPlayerSync implements IMessageHandler<Message, IMessage> {
buf.writeLong(seed);
buf.writeInt(selectedMinionID);
WizardData.getSyncedVariables().forEach(v -> v.write(buf, spellData.get(v)));
WizardData.getSyncedVariablesOrderedByKey().forEach(v -> v.write(buf, spellData.get(v)));
if(this.spellsDiscovered == null) return;
for(Spell spell : this.spellsDiscovered){
@@ -1,11 +1,14 @@
package electroblob.wizardry.potion;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.item.ItemWizardArmour;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DamageSource;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.ISpecialArmor;
public class CurseUndeath extends Curse {
@@ -25,7 +28,7 @@ public class CurseUndeath extends Curse {
// Adapted from EntityZombie
if(entitylivingbase.world.isDaytime() && !entitylivingbase.world.isRemote){
float f = entitylivingbase.getBrightness();
if(f > 0.5F && entitylivingbase.world.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F
@@ -35,14 +38,21 @@ public class CurseUndeath extends Curse {
boolean flag = true;
ItemStack itemstack = entitylivingbase.getItemStackFromSlot(EntityEquipmentSlot.HEAD);
if(!itemstack.isEmpty()){
if(itemstack.isItemStackDamageable()){
if (!itemstack.isEmpty()) {
if (itemstack.isItemStackDamageable()) {
itemstack.setItemDamage(itemstack.getItemDamage() + entitylivingbase.world.rand.nextInt(2));
if(itemstack.getItemDamage() >= itemstack.getMaxDamage()){
entitylivingbase.renderBrokenItemStack(itemstack);
entitylivingbase.setItemStackToSlot(EntityEquipmentSlot.HEAD, ItemStack.EMPTY);
if (itemstack.getItem() instanceof ISpecialArmor) {
((ISpecialArmor) itemstack.getItem()).damageArmor(entitylivingbase, itemstack, DamageSource.ON_FIRE, entitylivingbase.world.rand.nextInt(2), EntityEquipmentSlot.HEAD.getSlotIndex());
} else {
itemstack.setItemDamage(itemstack.getItemDamage() + entitylivingbase.world.rand.nextInt(2));
if (itemstack.getItemDamage() >= itemstack.getMaxDamage()) {
if (itemstack.getItem() instanceof ItemWizardArmour) {
entitylivingbase.setFire(8);
} else {
entitylivingbase.renderBrokenItemStack(itemstack);
entitylivingbase.setItemStackToSlot(EntityEquipmentSlot.HEAD, ItemStack.EMPTY);
}
}
}
}
@@ -2,17 +2,14 @@ package electroblob.wizardry.potion;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.EntityUtils;
import electroblob.wizardry.util.GeometryUtils;
import electroblob.wizardry.util.NBTExtras;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.network.play.server.SPacketEntityVelocity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.fml.common.Mod;
@@ -23,8 +20,6 @@ public class PotionContainment extends PotionMagicEffect {
public static final String ENTITY_TAG = "containmentPos";
private static final double RUBBERBAND_THRESHOLD = 0.24;
public PotionContainment(boolean isBadEffect, int liquidColour){
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/containment.png"));
this.setPotionName("potion." + Wizardry.MODID + ":containment");
@@ -41,7 +36,6 @@ public class PotionContainment extends PotionMagicEffect {
@Override
public void performEffect(EntityLivingBase target, int strength){
float maxDistance = getContainmentDistance(strength);
// Initialise the containment position to the entity's position if it wasn't set already
@@ -63,59 +57,14 @@ public class PotionContainment extends PotionMagicEffect {
if(target.getEntityBoundingBox().maxZ > origin.z + maxDistance) z = origin.z + maxDistance - target.width/2;
if(target.getEntityBoundingBox().minZ < origin.z - maxDistance) z = origin.z - maxDistance + target.width/2;
if(x != target.posX || y != target.posY || z != target.posZ){
// if(target.world.isRemote){
//
// if(x != target.posX){
// for(int i = 0; i < 20; i++){
// ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(
// x,
// target.posY + target.height * target.world.rand.nextFloat(),
// target.posZ + target.width * (target.world.rand.nextFloat() - 0.5f))
// .face(EnumFacing.EAST).clr(0.8f, 0.9f, 1).spawn(target.world);
// }
// }
//
// if(y != target.posY){
// for(int i = 0; i < 20; i++){
// ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(
// target.posX + target.width * (target.world.rand.nextFloat() - 0.5f),
// y,
// target.posZ + target.width * (target.world.rand.nextFloat() - 0.5f))
// .face(EnumFacing.UP).clr(0.8f, 0.9f, 1).spawn(target.world);
// }
// }
//
// if(z != target.posZ){
// for(int i = 0; i < 20; i++){
// ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(
// target.posX + target.width * (target.world.rand.nextFloat() - 0.5f),
// target.posY + target.height * target.world.rand.nextFloat(),
// z)
// .face(EnumFacing.SOUTH).clr(0.8f, 0.9f, 1).spawn(target.world);
// }
// }
// }
// Rubberbanding prevention (the 0.25 limit is from NetHandlerPlayServer, just search "moved wrongly"
if(target instanceof EntityPlayer){
x = MathHelper.clamp(x, target.posX - RUBBERBAND_THRESHOLD, target.posX + RUBBERBAND_THRESHOLD);
y = MathHelper.clamp(y, target.posY - RUBBERBAND_THRESHOLD, target.posY + RUBBERBAND_THRESHOLD);
z = MathHelper.clamp(z, target.posZ - RUBBERBAND_THRESHOLD, target.posZ + RUBBERBAND_THRESHOLD);
}
if(x != target.posX || y != target.posY || z != target.posZ)
{
target.addVelocity(0.15 * Math.signum(x - target.posX), 0.15 * Math.signum(y - target.posY), 0.15 * Math.signum(z - target.posZ));
EntityUtils.undoGravity(target);
target.addVelocity(0.35 * Math.signum(x - target.posX), 0.35 * Math.signum(y - target.posY), 0.35 * Math.signum(z - target.posZ));
target.setPositionAndUpdate(x, y, z); // FIXME: This line must be causing the server rubberbanding, not sure why
// Player motion is handled on that player's client so needs packets
if(target instanceof EntityPlayerMP){
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
if(target.world.isRemote){
target.world.playSound(target.posX, target.posY, target.posZ, WizardrySounds.ENTITY_FORCEFIELD_DEFLECT,
WizardrySounds.SPELLS, 0.3f, 1f, false);
}
//
// target.world.playSound(target.posX, target.posY, target.posZ, WizardrySounds.ENTITY_FORCEFIELD_DEFLECT,
// WizardrySounds.SPELLS, 0.3f, 1f, false);
}
// Need to do this here because it's the only way to hook into potion ending both client- and server-side
@@ -0,0 +1,28 @@
package electroblob.wizardry.potion;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.EntityUtils;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class PotionDiamondflesh extends PotionMagicEffect {
public PotionDiamondflesh(boolean isBadEffect, int liquidColour) {
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/diamondflesh.png"));
// This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet.
this.setPotionName("potion." + Wizardry.MODID + ":ironflesh");
this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED,
"158a8af2-6db0-4340-a01c-a7b60d10ddf4", -0.1f, EntityUtils.Operations.MULTIPLY_CUMULATIVE);
this.registerPotionAttributeModifier(SharedMonsterAttributes.ARMOR_TOUGHNESS,
"a68d4532-5847-426c-9b03-d541b113cec2", 3.0f, EntityUtils.Operations.ADD);
this.registerPotionAttributeModifier(SharedMonsterAttributes.ARMOR,
"46a095be-82dd-43fd-8b67-13f51591eb8e", 4.0f, EntityUtils.Operations.ADD);
}
@Override
public boolean isReady(int duration, int amplifier) {
return true;
}
}
@@ -5,6 +5,7 @@ import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
@@ -50,4 +51,18 @@ public class PotionFrost extends PotionMagicEffect implements ICustomPotionParti
}
}
@Override
public void performEffect(EntityLivingBase entitylivingbase, int strength) {
if (entitylivingbase.isBurning()) {
if (entitylivingbase.isPotionActive(WizardryPotions.frost)) {
entitylivingbase.removePotionEffect(WizardryPotions.frost);
entitylivingbase.extinguish();
}
}
}
@Override
public boolean isReady(int duration, int amplifier) {
return true;
}
}
@@ -0,0 +1,28 @@
package electroblob.wizardry.potion;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.EntityUtils;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class PotionIronflesh extends PotionMagicEffect {
public PotionIronflesh(boolean isBadEffect, int liquidColour) {
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/ironflesh.png"));
// This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet.
this.setPotionName("potion." + Wizardry.MODID + ":ironflesh");
this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED,
"fe607d55-50e3-4f4f-a959-6571503f92f4", -0.1f, EntityUtils.Operations.MULTIPLY_CUMULATIVE);
this.registerPotionAttributeModifier(SharedMonsterAttributes.KNOCKBACK_RESISTANCE,
"6f78206e-8dd4-4d44-9792-d7a882111951", 0.3f, EntityUtils.Operations.ADD);
this.registerPotionAttributeModifier(SharedMonsterAttributes.ARMOR,
"e1adff1e-8510-4a09-96ed-ef677cad20c1", 4.0f, EntityUtils.Operations.ADD);
}
@Override
public boolean isReady(int duration, int amplifier) {
return true;
}
}
@@ -0,0 +1,28 @@
package electroblob.wizardry.potion;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.util.EntityUtils;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class PotionOakflesh extends PotionMagicEffect {
public PotionOakflesh(boolean isBadEffect, int liquidColour) {
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/oakflesh.png"));
// This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet.
this.setPotionName("potion." + Wizardry.MODID + ":ironflesh");
this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED,
"98b4ba66-7c50-4a4c-9f3f-40bcb37313b5", -0.1f, EntityUtils.Operations.MULTIPLY_CUMULATIVE);
this.registerPotionAttributeModifier(SharedMonsterAttributes.MAX_HEALTH,
"ed9d0423-60f4-4998-bd8d-dc7c33bd45b8", 0.2f, EntityUtils.Operations.MULTIPLY_FLAT);
this.registerPotionAttributeModifier(SharedMonsterAttributes.ARMOR,
"0b607c3f-fb14-43d7-96b5-1c1b6f6da242", 3.0f, EntityUtils.Operations.ADD);
}
@Override
public boolean isReady(int duration, int amplifier) {
return true;
}
}
@@ -359,7 +359,7 @@ public final class Spells {
registry.register(new GreaterHeal());
registry.register(new SpellConstruct<>("healing_aura", SpellActions.POINT_DOWN, EntityHealAura::new, false).addProperties(Spell.EFFECT_RADIUS, Spell.DAMAGE, Spell.HEALTH));
registry.register(new Forcefield());
registry.register(new SpellBuff("ironflesh", 0.4f, 0.5f, 0.6f, () -> MobEffects.RESISTANCE).soundValues(0.7f, 1.2f, 0.4f));
registry.register(new SpellBuff("ironflesh", 0.4f, 0.5f, 0.6f, () -> WizardryPotions.ironflesh).soundValues(0.7f, 1.2f, 0.4f));
registry.register(new Transience());
registry.register(new Meteor());
@@ -378,9 +378,10 @@ public final class Spells {
registry.register(new SpellMinion<>("silverfish_swarm", EntitySilverfishMinion::new).soundValues(1, 1.1f, 0.1f));
registry.register(new SpellConstructRanged<>("black_hole", EntityBlackHole::new, false).addProperties(Spell.EFFECT_RADIUS).soundValues(2, 0.7f, 0));
registry.register(new Shockwave());
registry.register(new SummonIronGolem());
registry.register(new SpellMinion<>("summon_iron_golem", EntitySpectralGolem::new).soundValues(1, 1.1f, 0.1f));
registry.register(new ArrowRain());
registry.register(new SpellBuff("diamondflesh", 0.1f, 0.7f, 1, () -> MobEffects.RESISTANCE).soundValues(0.7f, 1.2f, 0.4f));
registry.register(new SpellBuff("diamondflesh", 0.1f, 0.7f, 1, () -> WizardryPotions.diamondflesh).soundValues(0.7f, 1.2f, 0.4f));
registry.register(new SpellBuff("font_of_vitality", 1, 0.8f, 0.3f, () -> MobEffects.ABSORPTION, () -> MobEffects.REGENERATION).soundValues(0.7f, 1.2f, 0.4f));
// Wizardry 1.1 spells
@@ -398,7 +399,7 @@ public final class Spells {
registry.register(new PocketWorkbench());
registry.register(new ImbueWeapon());
registry.register(new InvigoratingPresence());
registry.register(new SpellBuff("oakflesh", 0.6f, 0.5f, 0.4f, () -> MobEffects.RESISTANCE).soundValues(0.7f, 1.2f, 0.4f));
registry.register(new SpellBuff("oakflesh", 0.6f, 0.5f, 0.4f, () -> WizardryPotions.oakflesh).soundValues(0.7f, 1.2f, 0.4f));
registry.register(new SpellProjectile<>("greater_fireball", EntityLargeMagicFireball::new).addProperties(Spell.DAMAGE, EntityLargeMagicFireball.EXPLOSION_POWER));//new GreaterFireball());
registry.register(new FlamingWeapon());
@@ -88,6 +88,7 @@ public class WizardryEntities {
registry.register(createEntry(EntitySpiritHorse.class, "spirit_horse", TrackingType.LIVING).egg(0x5464c6, 0xbcc2e8).build());
registry.register(createEntry(EntityPhoenix.class, "phoenix", TrackingType.LIVING).egg(0xff4900, 0xfde535).build());
registry.register(createEntry(EntityIceGiant.class, "ice_giant", TrackingType.LIVING).egg(0x5bacd9, 0xeffaff).build());
registry.register(createEntry(EntitySpectralGolem.class, "spectral_golem", TrackingType.LIVING).egg(0x5bacd9, 0xeffaff).build());
registry.register(createEntry(EntityMagicSlime.class, "magic_slime", TrackingType.LIVING).build());
registry.register(createEntry(EntityDecoy.class, "decoy", TrackingType.LIVING).build());
@@ -113,6 +114,7 @@ public class WizardryEntities {
registry.register(createEntry(EntityDart.class, "dart", TrackingType.PROJECTILE).build());
registry.register(createEntry(EntityIceLance.class, "ice_lance", TrackingType.PROJECTILE).build());
registry.register(createEntry(EntityFlamecatcherArrow.class, "flamecatcher_arrow", TrackingType.PROJECTILE).build());
registry.register(createEntry(EntityConjuredArrow.class, "conjured_arrow", TrackingType.PROJECTILE).build());
// Directionless projectiles
registry.register(createEntry(EntityFirebomb.class, "firebomb", TrackingType.PROJECTILE).build());
@@ -6,7 +6,11 @@ import electroblob.wizardry.loot.RandomSpell;
import electroblob.wizardry.loot.WizardSpell;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.loot.*;
import net.minecraft.world.storage.loot.LootEntry;
import net.minecraft.world.storage.loot.LootEntryTable;
import net.minecraft.world.storage.loot.LootPool;
import net.minecraft.world.storage.loot.LootTableList;
import net.minecraft.world.storage.loot.RandomValueRange;
import net.minecraft.world.storage.loot.conditions.LootCondition;
import net.minecraft.world.storage.loot.functions.LootFunctionManager;
import net.minecraftforge.event.LootTableLoadEvent;
@@ -90,23 +94,27 @@ public final class WizardryLoot {
event.getTable().addPool(getAdditive(Wizardry.MODID + ":chests/jungle_dispenser_additions", Wizardry.MODID + "_additional_dispenser_loot"));
}
// Mob drops
// Let's hope mods will play nice and store their entity loot tables under 'entities' or 'entity'
// If not, packmakers will have to sort it out themselves using the whitelist/blacklist
if(Arrays.asList(Wizardry.settings.mobLootTableWhitelist).contains(event.getName())){
event.getTable().addPool(getAdditive(Wizardry.MODID + ":entities/mob_additions", Wizardry.MODID + "_additional_mob_drops"));
}else if(!Arrays.asList(Wizardry.settings.mobLootTableBlacklist).contains(event.getName())
&& event.getName().getPath().contains("entities") || event.getName().getPath().contains("entity")){
// Get the filename of the loot table json, for well-behaved mods this will be the entity name
String[] split = event.getName().getPath().split("/");
String entityName = split[split.length - 1];
EntityEntry entry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(entityName));
if(entry == null) return; // If this is true it didn't work :(
Class entityClass = entry.getEntityClass();
if(EnumCreatureType.MONSTER.getCreatureClass().isAssignableFrom(entityClass)){
if (Wizardry.settings.injectMobDrops) {
// Let's hope mods will play nice and store their entity loot tables under 'entities' or 'entity'
// If not, packmakers will have to sort it out themselves using the whitelist/blacklist
if (Arrays.asList(Wizardry.settings.mobLootTableWhitelist).contains(event.getName())) {
event.getTable().addPool(getAdditive(Wizardry.MODID + ":entities/mob_additions", Wizardry.MODID + "_additional_mob_drops"));
} else if (!Arrays.asList(Wizardry.settings.mobLootTableBlacklist).contains(event.getName())
&& event.getName().getPath().contains("entities") || event.getName().getPath().contains("entity")) {
// Get the filename of the loot table json, for well-behaved mods this will be the entity name
String[] split = event.getName().getPath().split("/");
String entityName = split[split.length - 1];
EntityEntry entry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(entityName));
if (entry == null) {
return; // If this is true it didn't work :(
}
Class entityClass = entry.getEntityClass();
if (EnumCreatureType.MONSTER.getCreatureClass().isAssignableFrom(entityClass)) {
event.getTable().addPool(getAdditive(Wizardry.MODID + ":entities/mob_additions", Wizardry.MODID + "_additional_mob_drops"));
}
}
}
// Fishing loot
@@ -57,6 +57,9 @@ public final class WizardryPotions {
public static final Potion frost_step = placeholder();
public static final Potion mark_of_sacrifice = placeholder();
public static final Potion mirage = placeholder();
public static final Potion oakflesh = placeholder();
public static final Potion ironflesh = placeholder();
public static final Potion diamondflesh = placeholder();
/**
* Sets both the registry and unlocalised names of the given potion, then registers it with the given registry. Use
@@ -201,6 +204,10 @@ public final class WizardryPotions {
public void spawnCustomParticle(World world, double x, double y, double z){} // We only want the syncing
}.setBeneficial());
registerPotion(registry, "oakflesh", new PotionOakflesh(false, 0).setBeneficial());
registerPotion(registry, "ironflesh", new PotionIronflesh(false, 0).setBeneficial());
registerPotion(registry, "diamondflesh", new PotionDiamondflesh(false, 0).setBeneficial());
}
}
@@ -33,7 +33,7 @@ public class ConjureBlock extends SpellRay {
@Override
protected boolean onBlockHit(World world, BlockPos pos, EnumFacing side, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
if(caster.isSneaking() && world.getBlockState(pos).getBlock() == WizardryBlocks.spectral_block){
if(caster != null && caster.isSneaking() && world.getBlockState(pos).getBlock() == WizardryBlocks.spectral_block){
if(!world.isRemote){
// Dispelling of blocks
@@ -53,7 +53,7 @@ public class CurseOfSoulbinding extends SpellRay {
@Override
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
if(EntityUtils.isLiving(target) && caster instanceof EntityPlayer){
WizardData data = WizardData.get((EntityPlayer)caster);
if(data != null){
@@ -66,7 +66,7 @@ public class CurseOfSoulbinding extends SpellRay {
}
}
}
return true;
}
@@ -79,7 +79,7 @@ public class CurseOfSoulbinding extends SpellRay {
protected boolean onMiss(World world, EntityLivingBase caster, Vec3d origin, Vec3d direction, int ticksInUse, SpellModifiers modifiers){
return true;
}
@Override
protected void spawnParticle(World world, double x, double y, double z, double vx, double vy, double vz){
ParticleBuilder.create(Type.DARK_MAGIC).pos(x, y, z).clr(0.4f, 0, 0).spawn(world);
@@ -103,9 +103,9 @@ public class CurseOfSoulbinding extends SpellRay {
Entity entity = EntityUtils.getEntityByUUID(player.world, iterator.next());
if(entity == null) iterator.remove();
if(entity instanceof EntityLivingBase){
if (entity == null || (entity instanceof EntityLivingBase && !((EntityLivingBase) entity).isPotionActive(WizardryPotions.curse_of_soulbinding))) {
iterator.remove();
} else if (entity instanceof EntityLivingBase) {
// Retaliatory effect
if(DamageSafetyChecker.attackEntitySafely(entity, MagicDamage.causeDirectMagicDamage(player,
MagicDamage.DamageType.MAGIC, true), event.getAmount(), event.getSource().getDamageType(),
@@ -5,6 +5,7 @@ import electroblob.wizardry.constants.Constants;
import electroblob.wizardry.entity.living.ISpellCaster;
import electroblob.wizardry.event.SpellCastEvent;
import electroblob.wizardry.item.SpellActions;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardryPotions;
import electroblob.wizardry.util.ParticleBuilder;
@@ -24,11 +25,14 @@ import javax.annotation.Nullable;
@Mod.EventBusSubscriber
public class EmpoweringPresence extends SpellAreaEffect {
/** The fraction by which potency is increased per level of the empowerment effect. */
public static final String POTENCY_PER_LEVEL = "potency_per_level";
public EmpoweringPresence(){
super("empowering_presence", SpellActions.POINT_UP, false);
this.alwaysSucceed(true);
this.targetAllies(true);
addProperties(EFFECT_DURATION, EFFECT_STRENGTH);
addProperties(EFFECT_DURATION, EFFECT_STRENGTH, POTENCY_PER_LEVEL);
}
@Override
@@ -62,7 +66,7 @@ public class EmpoweringPresence extends SpellAreaEffect {
if(event.getCaster() != null && event.getCaster().isPotionActive(WizardryPotions.empowerment)
&& !(event.getSpell() instanceof EmpoweringPresence)){ // Prevent exponential empowerment stacking!
float potency = 1 + Constants.EMPOWERMENT_POTENCY_PER_LEVEL
float potency = 1 + Spells.empowering_presence.getProperty(POTENCY_PER_LEVEL).floatValue()
* (event.getCaster().getActivePotionEffect(WizardryPotions.empowerment).getAmplifier() + 1);
event.getModifiers().set(SpellModifiers.POTENCY,
@@ -4,7 +4,7 @@ import electroblob.wizardry.item.SpellActions;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.tileentity.TileEntityDispenser;
import net.minecraft.util.math.Vec3d;
@@ -29,7 +29,7 @@ public class Enrage extends SpellAreaEffect {
@Override
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
if(caster != null && target instanceof EntityCreature){
if(caster != null && target instanceof EntityLiving){
target.setRevengeTarget(caster); // Yours truly, angry mobs
}
@@ -53,7 +53,7 @@ public class FireBreath extends SpellRay {
this.getNameForTranslationFormatted()), true);
// This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle
// with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry.
}else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){
}else if(ticksInUse % 10 == 0){
target.setFire((int)(getProperty(BURN_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)));
EntityUtils.attackEntityWithoutKnockback(target,
MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE),
@@ -56,7 +56,7 @@ public class FlameRay extends SpellRay {
this.getNameForTranslationFormatted()), true);
// This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle
// with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry.
}else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){
}else if(ticksInUse % 10 == 0){
target.setFire((int)(getProperty(BURN_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)));
EntityUtils.attackEntityWithoutKnockback(target,
MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE),
@@ -59,18 +59,19 @@ public class FrostRay extends SpellRay {
this.getNameForTranslationFormatted()), true);
// This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle
// with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry.
}else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){
}else{
// For frost ray the entity can move slightly, unlike freeze
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost,
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
getProperty(EFFECT_STRENGTH).intValue()));
float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY);
if(target instanceof EntityBlaze || target instanceof EntityMagmaCube) damage *= 2;
EntityUtils.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster,
DamageType.FROST), damage);
if(ticksInUse % 10 == 0){
float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY);
if(target instanceof EntityBlaze || target instanceof EntityMagmaCube) damage *= 2;
EntityUtils.attackEntityWithoutKnockback(target, MagicDamage.causeDirectMagicDamage(caster,
DamageType.FROST), damage);
}
}
}
@@ -8,6 +8,7 @@ import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.EnumHand;
import net.minecraft.world.World;
@@ -24,14 +25,14 @@ public class Glide extends Spell {
@Override
protected void playSound(World world, EntityLivingBase entity, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){
if(ticksInUse == 0 && world.isRemote) Wizardry.proxy.playSpellSoundLoop(entity, this, this.sounds[0], this.sounds[0], this.sounds[0],
if(ticksInUse == 0 && world.isRemote) Wizardry.proxy.playSpellSoundLoop(entity, this, this.sounds[0], this.sounds[0], SoundEvents.UI_TOAST_OUT,
WizardrySounds.SPELLS, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f));
}
@Override
protected void playSound(World world, double x, double y, double z, int ticksInUse, int duration, SpellModifiers modifiers, String... sounds){
if(ticksInUse == 0 && world.isRemote){
Wizardry.proxy.playSpellSoundLoop(world, x, y, z, this, this.sounds[0], this.sounds[0], this.sounds[0],
Wizardry.proxy.playSpellSoundLoop(world, x, y, z, this, this.sounds[0], this.sounds[0], SoundEvents.UI_TOAST_OUT,
WizardrySounds.SPELLS, volume, pitch + pitchVariation * (world.rand.nextFloat() - 0.5f), duration);
}
}
@@ -38,7 +38,7 @@ public class Heal extends SpellBuff {
entity.heal(health);
// If the player is able to heal, they can't possibly have absorption hearts, so no need to check!
if(excessHealth > 0 && entity instanceof EntityPlayer
if(excessHealth > entity.getAbsorptionAmount() && entity instanceof EntityPlayer
&& ItemArtefact.isArtefactActive((EntityPlayer)entity, WizardryItems.amulet_absorption)){
entity.setAbsorptionAmount(excessHealth);
}
@@ -47,7 +47,7 @@ public class LifeDrain extends SpellRay {
if(EntityUtils.isLiving(target)){
if(ticksInUse % 12 == 0){
if(ticksInUse % 10 == 0){
float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY);
@@ -51,7 +51,7 @@ public class LightningRay extends SpellRay {
this.getNameForTranslationFormatted()), true);
// This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle
// with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry.
}else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){
}else if(ticksInUse % 10 == 0){
EntityUtils.attackEntityWithoutKnockback(target,
MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK),
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
@@ -53,7 +53,7 @@ public class LightningWeb extends SpellRay {
@Override
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
if(EntityUtils.isLiving(target)){
if(EntityUtils.isLiving(target) && ticksInUse % 10 == 0){
electrocute(world, caster, origin, target, getProperty(PRIMARY_DAMAGE).floatValue()
* modifiers.get(SpellModifiers.POTENCY), ticksInUse);
@@ -63,7 +63,7 @@ public class MarkSacrifice extends SpellRay {
PotionEffect effect = event.getEntityLiving().getActivePotionEffect(WizardryPotions.mark_of_sacrifice);
if(effect != null && event.getSource().isMagicDamage()){
event.setAmount(event.getAmount() * (1 + effect.getAmplifier() * DAMAGE_INCREASE_PER_LEVEL));
event.setAmount(event.getAmount() * (1 + (1 + effect.getAmplifier()) * DAMAGE_INCREASE_PER_LEVEL));
event.getEntityLiving().removePotionEffect(WizardryPotions.mark_of_sacrifice);
}
}
@@ -111,6 +111,9 @@ public class MindControl extends SpellRay {
/** Returns true if the given entity can be mind controlled (i.e. is not a player, npc, evil wizard or boss). */
public static boolean canControl(Entity target){
// TODO: Add a max health limit that scales with potency
return target instanceof EntityLiving && target.isNonBoss() && !(target instanceof INpc)
&& !(target instanceof EntityEvilWizard) && !Arrays.asList(Wizardry.settings.mindControlTargetsBlacklist)
.contains(EntityList.getKey(target.getClass()));
@@ -30,9 +30,14 @@ public class Paralysis extends SpellRay {
* will end. */
private static final String CRITICAL_HEALTH = "critical_health";
/**
* Multiplier for affecting players
*/
private static final String PLAYER_EFFECT_DURATION_MULTIPLIER = "player_effect_duration_multiplier";
public Paralysis(){
super("paralysis", SpellActions.POINT, false);
addProperties(DAMAGE, EFFECT_DURATION, CRITICAL_HEALTH);
addProperties(DAMAGE, EFFECT_DURATION, CRITICAL_HEALTH, PLAYER_EFFECT_DURATION_MULTIPLIER);
}
@Override
@@ -57,9 +62,10 @@ public class Paralysis extends SpellRay {
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK),
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
}
float durationMultiplier = target instanceof EntityPlayer ? modifiers.get(PLAYER_EFFECT_DURATION_MULTIPLIER) : 1.0f;
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.paralysis,
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)), 0));
(int)(getProperty(EFFECT_DURATION).floatValue() * durationMultiplier * modifiers.get(WizardryItems.duration_upgrade)), 0));
}
return false;
@@ -58,7 +58,7 @@ public class RayOfPurification extends SpellRay {
if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster)
.sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(),
this.getNameForTranslationFormatted()), true);
}else{
}else if (ticksInUse % 10 == 0) {
float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY);
// Fire
@@ -1,6 +1,8 @@
package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.event.ResurrectionEvent;
import electroblob.wizardry.item.ISpellCastingItem;
import electroblob.wizardry.item.SpellActions;
import electroblob.wizardry.packet.PacketResurrection;
@@ -8,6 +10,7 @@ import electroblob.wizardry.packet.WizardryPacketHandler;
import electroblob.wizardry.registry.Spells;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
@@ -16,11 +19,16 @@ import net.minecraft.util.EnumHand;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import java.util.Arrays;
import java.util.Comparator;
@EventBusSubscriber
public class Resurrection extends Spell {
public static final String WAIT_TIME = "wait_time";
@@ -55,6 +63,9 @@ public class Resurrection extends Spell {
.orElse(null);
if(nearestDeadAlly != null){
if(MinecraftForge.EVENT_BUS.post(new ResurrectionEvent(nearestDeadAlly, caster))) return false;
// When the player entity dies, it is removed from world#loadedEntityList. However, it is NOT removed
// from playerEntityList (and probably a few other places) until respawn is clicked, and since that
// never happens here we need to clean up those references or the player will have duplicate entries
@@ -112,4 +123,42 @@ public class Resurrection extends Spell {
&& ((ISpellCastingItem)stack.getItem()).canCast(stack, Spells.resurrection, player, EnumHand.MAIN_HAND, 0, new SpellModifiers());
}
}
@SubscribeEvent
public static void onPlayerTickEvent(LivingUpdateEvent event){
if(event.getEntity() instanceof EntityPlayer){
EntityPlayer player = (EntityPlayer)event.getEntity();
if(player.world.isRemote && !player.isEntityAlive()){
EntityPlayer firstPersonPlayer = Wizardry.proxy.getThePlayer();
if(WizardData.get(firstPersonPlayer).isPlayerAlly(player)){
ItemStack wand = firstPersonPlayer.getHeldItemMainhand();
if(!(wand.getItem() instanceof ISpellCastingItem)){
wand = firstPersonPlayer.getHeldItemOffhand();
if(!(wand.getItem() instanceof ISpellCastingItem)) return;
}
if(((ISpellCastingItem)wand.getItem()).getCurrentSpell(wand) == Spells.resurrection){
// TODO: Find some way of getting at the modifiers before the spell is cast
int waitTime = Spells.resurrection.getProperty(WAIT_TIME).intValue();
if(player.deathTime > waitTime){
ParticleBuilder.create(Type.SPARKLE, player.world.rand, player.posX, player.posY + 0.5, player.posZ, 0.5, false)
.clr(1, 1, 0.3f).vel(0, 0.02, 0).spawn(player.world);
}else{
ParticleBuilder.create(Type.DUST, player.world.rand, player.posX, player.posY + 0.5, player.posZ, 0.5, false)
.clr(1, 1, 0.3f).vel(0, 0.02, 0).time(50).spawn(player.world);
}
}
}
}
}
}
}
@@ -189,7 +189,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
private static int nextSpellId = 0;
/** The spell's integer ID, mainly used for networking. */
// This was added after I learnt the hard way why you can't assume Forge's registry IDs are sequential...
private final int id;
private int id;
/**
* This constructor should be called from any subclasses, either feeding in the constants directly or through their
@@ -225,6 +225,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
this.icon = new ResourceLocation(modID, "textures/spells/" + name + ".png");
this.sounds = createSounds();
this.id = nextSpellId++;
Wizardry.logger.debug("Registering spell " + this.unlocalisedName +" with networkID " + id);
this.items(WizardryItems.spell_book, WizardryItems.scroll);
this.npcSelector((e, o) -> false);
}
@@ -560,6 +561,11 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
return id;
}
/** Sets the networkID of this spell. Do not call this or it will cause all packets to fail. */
public void setId(int id) {
this.id = id;
}
/** Returns the {@code ResourceLocation} for this spell's icon. */
public final ResourceLocation getIcon(){
return icon;
@@ -916,6 +922,11 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
return Arrays.asList(applicableItems).contains(item);
}
/** Returns the list of items this spell is applicable to. */
public List<Item> getApplicableItems() {
return Arrays.asList(applicableItems);
}
/**
* Sets which items this spell can appear on (these default to the regular spell book and scroll).
* @param applicableItems The items this spell should naturally appear on (or no items at all).
@@ -125,7 +125,8 @@ public class SpellBuff extends Spell {
@Override
public boolean cast(World world, EntityLiving caster, EnumHand hand, int ticksInUse, EntityLivingBase target, SpellModifiers modifiers){
// Wizards can only cast a buff spell if they don't already have its effects.
if(caster.getActivePotionMap().keySet().containsAll(potionSet)) return false;
// Some buff spells doesn't add any potion effects, those are ignored by this check
if(!potionSet.isEmpty() && caster.getActivePotionMap().keySet().containsAll(potionSet)) return false;
// Only return on the server side or the client probably won't spawn particles
if(!this.applyEffects(caster, modifiers) && !world.isRemote) return false;
if(world.isRemote) this.spawnParticles(world, caster, modifiers);
@@ -1,51 +0,0 @@
package electroblob.wizardry.spell;
import electroblob.wizardry.item.SpellActions;
import electroblob.wizardry.util.BlockUtils;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class SummonIronGolem extends Spell {
public SummonIronGolem(){
super("summon_iron_golem", SpellActions.SUMMON, false);
addProperties(SpellMinion.SUMMON_RADIUS);
soundValues(1, 1.1f, 0.2f);
}
@Override
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
BlockPos pos = BlockUtils.findNearbyFloorSpace(caster, getProperty(SpellMinion.SUMMON_RADIUS).intValue(),
getProperty(SpellMinion.SUMMON_RADIUS).intValue());
if(pos == null) return false;
if(!world.isRemote){
EntityIronGolem golem = new EntityIronGolem(world);
golem.setPosition(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5);
golem.setPlayerCreated(true);
world.spawnEntity(golem);
}else{
for(int i=0; i<10; i++){
double x = pos.getX() + world.rand.nextDouble() * 2 - 1;
double y = pos.getY() + 0.5 + world.rand.nextDouble();
double z = pos.getZ() + world.rand.nextDouble() * 2 - 1;
ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).clr(0.6f, 0.6f, 1).spawn(world);
}
}
this.playSound(world, caster, ticksInUse, -1, modifiers);
return true;
}
}
@@ -1,7 +1,9 @@
package electroblob.wizardry.spell;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.item.ItemArtefact;
import electroblob.wizardry.item.SpellActions;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.util.SpellModifiers;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
@@ -34,7 +36,7 @@ public class Telekinesis extends SpellRay {
target.motionZ = (origin.z - target.posZ) / 6;
return true;
}else if(target instanceof EntityPlayer && (Wizardry.settings.telekineticDisarmament || !(caster instanceof EntityPlayer))){
} else if (target instanceof EntityPlayer && (Wizardry.settings.telekineticDisarmament && !ItemArtefact.isArtefactActive((EntityPlayer) target, WizardryItems.amulet_anchoring)) {
EntityPlayer player = (EntityPlayer)target;
@@ -2,6 +2,7 @@ package electroblob.wizardry.tileentity;
import electroblob.wizardry.block.BlockReceptacle;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.event.ImbuementActivateEvent;
import electroblob.wizardry.item.IManaStoringItem;
import electroblob.wizardry.item.ItemWizardArmour;
import electroblob.wizardry.registry.*;
@@ -24,6 +25,7 @@ import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootTable;
import net.minecraftforge.common.MinecraftForge;
import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nullable;
@@ -233,6 +235,14 @@ public class TileEntityImbuementAltar extends TileEntity implements ITickable {
*/
public static ItemStack getImbuementResult(ItemStack input, Element[] receptacleElements, boolean fullLootGen, World world, EntityPlayer lastUser){
ItemStack eventResult = ItemStack.EMPTY;
if (world != null && MinecraftForge.EVENT_BUS.post(new ImbuementActivateEvent(input, receptacleElements, world, lastUser, eventResult))) {
// return the stack if something changes the result from an empty stack.
//noinspection ConstantConditions
if (eventResult != ItemStack.EMPTY) return eventResult;
}
if(input.getItem() instanceof ItemWizardArmour && ((ItemWizardArmour)input.getItem()).element == null){
if(Arrays.stream(receptacleElements).distinct().count() == 1 && receptacleElements[0] != null){ // All the same element

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