Compare commits

...

134 Commits

Author SHA1 Message Date
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
117 changed files with 4105 additions and 1995 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.11",
"1.12.2-recommended": "4.3.11"
}
}
-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.]
+1 -1
View File
@@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
version = "4.3.3" // There, it matches semver, happy now?
version = "4.3.11"
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "ElectroblobsWizardry"
Binary file not shown.
+1 -2
View File
@@ -1,6 +1,5 @@
#Mon Sep 14 12:28:28 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
Vendored
+61 -53
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
##############################################################################
##
@@ -6,47 +6,6 @@
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
@@ -61,9 +20,49 @@ while [ -h "$PRG" ] ; do
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -79,18 +78,18 @@ if [ -n "$JAVA_HOME" ] ; 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"
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
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
Vendored
+6 -12
View File
@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -27,7 +27,7 @@ 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
@@ -41,15 +41,14 @@ 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
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
@@ -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.11";
/**
* 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,11 +127,10 @@ public class Wizardry {
public void preInit(FMLPreInitializationEvent event){
logger = event.getModLog();
proxy.registerResourceReloadListeners();
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
settings.initConfig(event);
proxy.registerResourceReloadListeners();
Calendar calendar = Calendar.getInstance();
tisTheSeason = calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DAY_OF_MONTH) >= 24
@@ -149,34 +162,6 @@ 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();
}
}
}
settings.initConfigExtras();
// World generators
@@ -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);
@@ -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);
}
@@ -496,24 +496,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);
}
}
@@ -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().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;
}
}
@@ -382,6 +382,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);
}
@@ -32,7 +32,7 @@ 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);
@@ -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);
@@ -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;
@@ -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
@@ -182,23 +186,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 +638,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 +659,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 +695,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 +722,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 +798,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 +845,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;
/**
* SpellBindEvent 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());
}
@@ -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);
}
}
}
}
@@ -849,7 +868,12 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
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;
@@ -870,6 +894,19 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
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();
nbt.removeTag(WandHelper.SPELL_ARRAY_KEY);
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));
@@ -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 {
@@ -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,
@@ -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 % ((EntityLivingBase)target).maxHurtResistantTime == 1){
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);
}
}
@@ -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;
@@ -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;
@@ -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;
}
}
@@ -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
@@ -201,7 +201,7 @@ public final class AllyDesignationSystem {
// Owned entities inherit their owner's allies
if(allyOf instanceof IEntityOwnable){
Entity owner = ((IEntityOwnable)allyOf).getOwner();
if(owner instanceof EntityLivingBase && isAllied((EntityLivingBase)owner, possibleAlly)) return true;
if(owner instanceof EntityLivingBase && (owner == possibleAlly || isAllied((EntityLivingBase)owner, possibleAlly))) return true;
}
if(allyOf instanceof EntityPlayer && possibleAlly instanceof EntityPlayer
@@ -1,5 +1,7 @@
package electroblob.wizardry.util;
import electroblob.wizardry.Settings;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.entity.living.*;
import net.minecraft.entity.Entity;
import net.minecraft.entity.boss.EntityDragon;
@@ -195,7 +197,7 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage
* @return A damagesource object of type EntityDamageSource
*/
public static DamageSource causeDirectMagicDamage(Entity caster, DamageType type, boolean isRetaliatory){
return new MagicDamage(DIRECT_MAGIC_DAMAGE, caster, type, isRetaliatory);
return new MagicDamage(getDirectDamageNameForType(type), caster, type, isRetaliatory);
}
/**
@@ -241,7 +243,15 @@ public class MagicDamage extends EntityDamageSource implements IElementalDamage
*/
public static DamageSource causeIndirectMagicDamage(Entity magic, Entity caster, DamageType type,
boolean isRetaliatory){
return new IndirectMagicDamage(INDIRECT_MAGIC_DAMAGE, magic, caster, type, isRetaliatory);
return new IndirectMagicDamage(getIndirectDamageNameForType(type), magic, caster, type, isRetaliatory);
}
public static String getIndirectDamageNameForType(DamageType type) {
return Wizardry.settings.damageTypePerElement ? type.name().toLowerCase() + "_" + INDIRECT_MAGIC_DAMAGE : INDIRECT_MAGIC_DAMAGE;
}
public static String getDirectDamageNameForType(DamageType type) {
return Wizardry.settings.damageTypePerElement ? type.name().toLowerCase() + "_" + DIRECT_MAGIC_DAMAGE : DIRECT_MAGIC_DAMAGE;
}
@Override
@@ -34,7 +34,9 @@ import java.util.Random;
* <code>ParticleBuilder.create(Type.SPARKLE).pos(x, y, z).vel(vx, vy, vz).clr(r, g, b).spawn(world);</code>
* <p></p>
* It also goes without saying that <b>this class should only ever be used client-side</b>. Attempting to spawn particles
* on the server side will not work and will print a warning to the console.
* on the server side will not work and will print a warning to the console. {@code ParticleBuilder} is not threadsafe
* and attempting to call it from multiple threads at once will very likely cause an {@link IllegalStateException}.
*
* @author Electroblob
* @since Wizardry 4.2
*/
@@ -1,5 +1,6 @@
package electroblob.wizardry.util;
import com.google.common.collect.Sets;
import electroblob.wizardry.event.SpellCastEvent;
import io.netty.buffer.ByteBuf;
import net.minecraft.item.Item;
@@ -77,13 +78,11 @@ public final class SpellModifiers {
* @return The SpellModifiers object, allowing this method to be chained onto the constructor.
*/
public SpellModifiers combine(SpellModifiers modifiers){
for(Entry<String, Float> entry : multiplierMap.entrySet()){
float newValue = entry.getValue() * modifiers.get(entry.getKey());
entry.setValue(newValue);
for(String key : Sets.union(this.multiplierMap.keySet(), modifiers.multiplierMap.keySet())){
float newValue = this.get(key) * modifiers.get(key);
// Also need to update the synced map if the modifier is synced in either object
if(this.syncedMultiplierMap.containsKey(entry.getKey()) || modifiers.syncedMultiplierMap.containsKey(entry.getKey())){
this.syncedMultiplierMap.put(entry.getKey(), newValue);
}
boolean sync = this.syncedMultiplierMap.containsKey(key) || modifiers.syncedMultiplierMap.containsKey(key);
this.set(key, newValue, sync);
}
return this;
}
@@ -0,0 +1,32 @@
package electroblob.wizardry.util;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.spell.Spell;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* Helper class which ensures that all spellpack spell networkIDs are distributed in alphabetical order. Introducing this was necessary as mods (especially with
* (load-after) dependencies were not always registering their spells in the exact same order. This is definitely
*/
public class SpellNetworkIDSorter {
public static void init() {
//reorder network IDs based on addon modids. This is necessary as modloading order doesn't seem to be guaranteed to match between various servers and clients
Wizardry.logger.debug("Reordering all spell NetworkIDs based on addon modid alphabetical order");
// the first available ID after all default spells
int nextSpellId = (int) Spell.getAllSpells().stream().filter(spell -> spell.getRegistryName().getNamespace().equals(Wizardry.MODID)).count() + 1;
List<Spell> addonSpells = Spell.getAllSpells().stream().filter(spell -> !spell.getRegistryName().getNamespace().equals(Wizardry.MODID)).collect(Collectors.toList());
// sorting spells
addonSpells.sort(Comparator.comparing((Spell o) -> o.getRegistryName().toString()));
for (Spell spell : addonSpells) {
Wizardry.logger.debug("Updating networkID of spell " + spell.getRegistryName().toString() + " from " + spell.networkID() + " to " + nextSpellId);
spell.setId(nextSpellId++);
}
}
}
@@ -251,6 +251,7 @@ public final class WandHelper {
for(int i = 0; i < cooldowns.length; i++){
if(cooldowns[i] > 0) cooldowns[i]--;
if(cooldowns[i] < 0) cooldowns[i] = 0; // In case it got broken
}
setCooldowns(wand, cooldowns);
@@ -312,6 +313,8 @@ public final class WandHelper {
// cast, which is impossible if there are no spells.
if(cooldowns.length <= selectedSpell) cooldowns = new int[spellCount];
if(cooldown <= 0) cooldown = 1;
cooldowns[selectedSpell] = cooldown;
setCooldowns(wand, cooldowns);
@@ -83,6 +83,7 @@ item.ebwizardry\:arcane_tome.desc=Upgrades any %1$s wand with sufficient progres
item.ebwizardry\:wizard_handbook.name=The Wizard's Handbook
item.ebwizardry\:wizard_handbook.author=by %1$s
item.ebwizardry\:wizard_handbook.desc=Your not-so-pocket-sized guide to the arcane arts! A must-have for any aspiring wizard who seeks to learn the secrets of magic.\n\nRight-click while holding this book to read it.
item.ebwizardry\:wizard_handbook.disabled=This item was disabled in the config!
item.ebwizardry\:wand.generic=wand
@@ -402,6 +403,10 @@ item.ebwizardry\:generic.disabled=This item has been disabled in the config
item.ebwizardry\:ring.generic.desc=Equip this ring in the Baubles inventory or by placing it on your hotbar. Up to 2 rings may be equipped at once.
item.ebwizardry\:amulet.generic.desc=Equip this amulet in the Baubles inventory or by placing it on your hotbar. Only one amulet may be equipped at a time.
item.ebwizardry\:charm.generic.desc=Equip this charm in the Baubles inventory or by placing it on your hotbar. Only one charm may be equipped at a time.
item.ebwizardry\:belt.generic.desc=Equip this belt in the Baubles inventory or by placing it on your hotbar. Only one belt may be equipped at a time.
item.ebwizardry\:body.generic.desc=Equip this body item in the Baubles inventory or by placing it on your hotbar. Only one body item may be equipped at a time.
item.ebwizardry\:trinket.generic.desc=Equip this trinket in the Baubles inventory or by placing it on your hotbar. Only one trinklet may be equipped at a time.
item.ebwizardry\:head.generic.desc=Equip this headgear in the Baubles inventory or by placing it on your hotbar. Only one headgear may be equipped at a time.
item.ebwizardry\:ring_condensing.name=Ring of Condensing
item.ebwizardry\:ring_condensing.desc=Slowly regenerates mana for all wands on your hotbar
@@ -438,7 +443,7 @@ item.ebwizardry\:ring_hammer.desc=Lightning hammers can be picked up and thrown
item.ebwizardry\:ring_stormcloud.name=Lokenzen's Ring
item.ebwizardry\:ring_stormcloud.desc=Stormcloud moves towards targets and lasts longer with every strike
item.ebwizardry\:ring_soulbinding.name=Soulwalker's Ring
item.ebwizardry\:ring_soulbinding.desc=Creatures damaged by necromancy spells become soulbound to you
item.ebwizardry\:ring_soulbinding.desc=Creatures damaged by necromancy spells become soulbound to you for 20 seconds
item.ebwizardry\:ring_leeching.name=Ring of Leeching
item.ebwizardry\:ring_leeching.desc=All necromancy attacks have a 30%% chance to trigger a life drain effect
item.ebwizardry\:ring_necromancy_melee.name=Ring of Necrotic Touch
@@ -732,6 +737,7 @@ entity.ebwizardry\:evil_wizard.name=Wizard
entity.ebwizardry\:decoy.name=Decoy
entity.ebwizardry\:vex_minion.name=Vex
entity.ebwizardry\:remnant.name=Remnant
entity.ebwizardry\:spectral_golem.name=Spectral Golem
entity.ebwizardry\:magic_missile.name=Magic
entity.ebwizardry\:arc.name=Magic
@@ -758,6 +764,7 @@ entity.ebwizardry\:smoke_bomb.name=Magic
entity.ebwizardry\:ice_spike.name=Magic
entity.ebwizardry\:combustion_rune.name=Magic
entity.ebwizardry\:flamecatcher_arrow.name=Magic
entity.ebwizardry\:conjured_arrow.name=Magic
entity.ebwizardry\:black_hole.name=Black Hole
entity.ebwizardry\:shield.name=Shield
@@ -875,6 +882,7 @@ container.ebwizardry\:arcane_workbench.sort_tier=Sort by Tier
container.ebwizardry\:arcane_workbench.sort_element=Sort by Element
container.ebwizardry\:arcane_workbench.sort_alphabetical=Sort Alphabetically
container.ebwizardry\:arcane_workbench.search_tooltip=%1$sSearch Tips\n\ntier=%2$s, %1$st=%2$s: match tiers\n%1$selement=%2$s, %1$se=%2$s: match elements\n%1$stype=%2$s, %1$sp=%2$s: match spell types\n%1$sdiscovered=true/false%2$s, %1$sd=t/f%2$s: include only (un)discovered\n%1$smodid=%2$s, %1$sm=%2$s: match mod IDs\n\nSeparate multiple values with %1$s,%2$s\nSeparate multiple criteria with %1$s;
container.ebwizardry\:arcane_workbench.clear=Clear Spell Slots
container.ebwizardry\:bookshelf=Bookshelf
@@ -1075,7 +1083,7 @@ spell.ebwizardry\:stormcloud=Stormcloud
spell.ebwizardry\:summon_blaze=Summon Blaze
spell.ebwizardry\:summon_ice_giant=Summon Ice Giant
spell.ebwizardry\:summon_ice_wraith=Summon Ice Wraith
spell.ebwizardry\:summon_iron_golem=Summon Iron Golem
spell.ebwizardry\:summon_iron_golem=Summon Spectral Golem
spell.ebwizardry\:summon_lightning_wraith=Summon Lightning Wraith
spell.ebwizardry\:summon_phoenix=Summon Phoenix
spell.ebwizardry\:summon_shadow_wraith=Summon Shadow Wraith
@@ -1203,7 +1211,7 @@ spell.ebwizardry\:intimidate.desc=Emits an intimidating growl which causes nearb
spell.ebwizardry\:invigorating_presence.desc=Grants the caster and all nearby allies increased strength for 45 seconds.
spell.ebwizardry\:invisibility.desc=Makes the caster invisible for 30 seconds.
spell.ebwizardry\:invoke_weather.desc=Changes the weather in the world.
spell.ebwizardry\:ironflesh.desc=Greatly improves the caster's damage resistance for 30 seconds.
spell.ebwizardry\:ironflesh.desc=Greatly improves the caster's armor and knockback resistance for 30 seconds.
spell.ebwizardry\:leap.desc=Causes the caster to jump upwards several blocks and slightly forward.
spell.ebwizardry\:levitation.desc=Raises the caster upwards while the use item button is held. Will also negate fall damage if used before hitting the ground.
spell.ebwizardry\:life_drain.desc=Creates a stream of withering energy in the direction you are pointing which drains the life of the target and uses it to gradually regenerate your health.
@@ -1226,7 +1234,7 @@ spell.ebwizardry\:mine.desc=Breaks the block the caster is looking at. Potency w
spell.ebwizardry\:mirage.desc=Creates an illusion where the caster appears to be a few blocks away from their actual position, blinking around every few seconds. The illusion lasts for 20 seconds.
spell.ebwizardry\:muffle.desc=Silences any sounds made by the caster for 30 seconds. When muffled, mobs can only detect you when looking towards you.
spell.ebwizardry\:none.desc=To get a spell book with the /give command, use id\: /give [player] ebwizardry\:spell_book 1 [spell id] (if you found this book in a chest, some other mod has messed things up).
spell.ebwizardry\:oakflesh.desc=Improves the caster's damage resistance for 30 seconds.
spell.ebwizardry\:oakflesh.desc=Slightly improves the caster's vitality and damage resistance for 30 seconds.
spell.ebwizardry\:paralysis.desc=Delivers a powerful lightning bolt that paralyses targets for 5 seconds. Paralysed creatures cannot move and will still take damage - but too much will snap the creature out of paralysis.
spell.ebwizardry\:permafrost.desc=Spreads a layer of slippery ice on the ground where you are pointing, the extreme cold of which causes creatures to slowly take damage.
spell.ebwizardry\:petrify.desc=Turns the target to stone until broken out, with a chance for it to break out when it is dark. The target cannot move or do anything while petrified but is also impervious to all damage.
@@ -1363,6 +1371,7 @@ forfeit.ebwizardry\:bury_self=The ground collapses beneath you!
forfeit.ebwizardry\:spill_inventory=Your items spill themselves everywhere!
forfeit.ebwizardry\:teleport_self=You are instantly teleported somewhere!
forfeit.ebwizardry\:teleport_self_large_distance=You are instantly teleported somewhere far away!
forfeit.ebwizardry\:levitate_self=You begin to float upwards helplessly!
forfeit.ebwizardry\:vex_horde=A horde of vexes materializes around you!
forfeit.ebwizardry\:black_hole=A swirling vortex appears in front of you!
@@ -1400,6 +1409,9 @@ potion.ebwizardry\:containment=Containment
potion.ebwizardry\:frost_step=Frost Step
potion.ebwizardry\:mark_of_sacrifice=Mark of Sacrifice
potion.ebwizardry\:mirage=Mirage
potion.ebwizardry\:oakflesh=Oakflesh
potion.ebwizardry\:ironflesh=Ironflesh
potion.ebwizardry\:diamondflesh=Diamondflesh
enchantment.ebwizardry\:magic_sword=Imbuement
enchantment.ebwizardry\:magic_bow=Imbuement
@@ -1436,6 +1448,25 @@ key.ebwizardry.spell_8=Spell Slot 8
death.attack.wizardry_magic=%1$s was killed by %2$s using magic
death.attack.indirect_wizardry_magic=%1$s was killed by %2$s using magic
death.attack.magic_wizardry_magic=%1$s was killed by %2$s using magic
death.attack.magic_indirect_wizardry_magic=%1$s was killed by %2$s using magic
death.attack.fire_wizardry_magic=%1$s was killed by %2$s using fire magic
death.attack.fire_indirect_wizardry_magic=%1$s was killed by %2$s using fire magic
death.attack.frost_wizardry_magic=%1$s was killed by %2$s using frost magic
death.attack.frost_indirect_wizardry_magic=%1$s was killed by %2$s using frost magic
death.attack.shock_wizardry_magic=%1$s was killed by %2$s using a shock magic
death.attack.shock_indirect_wizardry_magic=%1$s was killed by %2$s using shock magic
death.attack.wither_wizardry_magic=%1$s was killed by %2$s using withering magic
death.attack.wither_indirect_wizardry_magic=%1$s was killed by %2$s withering magic
death.attack.poison_wizardry_magic=%1$s was killed by %2$s using poison magic
death.attack.poison_indirect_wizardry_magic=%1$s was killed by %2$s poison magic
death.attack.force_wizardry_magic=%1$s was killed by %2$s using a magical force
death.attack.force_indirect_wizardry_magic=%1$s was killed by %2$s using magical force
death.attack.blast_wizardry_magic=%1$s was killed by %2$s using a magical blast
death.attack.blast_indirect_wizardry_magic=%1$s was killed by %2$s using magical blast
death.attack.radiant_wizardry_magic=%1$s was killed by %2$s using radiant magic
death.attack.radiant_indirect_wizardry_magic=%1$s was killed by %2$s using radiant magic
soundCategory.ebwizardry_spells=Spells
@@ -1504,6 +1535,12 @@ config.ebwizardry.player_block_damage.true=Yes - kaboom!
config.ebwizardry.player_block_damage.false=No - activate anti-grief (TM)
config.ebwizardry.dispenser_block_damage=Dispenser Block Damage
config.ebwizardry.dispenser_block_damage.tooltip=Whether spells cast by dispensers can destroy blocks in the world. Wizardry makes every attempt to respect protection mods and plugins, but cannot guarantee it will work in all cases for every mod. If you need absolutely watertight anti-grief, disable this setting.
config.ebwizardry.damage_type_per_element=Damage Type Per Element
config.ebwizardry.damage_type_per_element.tooltip=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
config.ebwizardry.single_use_spell_books=Spell Books Are Consumed By Wands
config.ebwizardry.single_use_spell_books.tooltip=Whether spell books are consumed when they are bound to a wand.
config.ebwizardry.prevent_binding_same_spell_twice_to_wands=Prevent Binding The Same Spell To A Wand Multiple Times
config.ebwizardry.prevent_binding_same_spell_twice_to_wands.tooltip=Whether to prevent binding the same spell to a wand multiple times
config.ebwizardry.telekinetic_disarmament=Telekinetic Disarmament
config.ebwizardry.telekinetic_disarmament.tooltip=Whether to allow players to disarm other players using the telekinesis spell. Disable to prevent stealing of items.
config.ebwizardry.telekinetic_disarmament.true=Yes - let people steal things
@@ -1524,6 +1561,20 @@ config.ebwizardry.slow_time_affects_players=Slow Time Affects Players
config.ebwizardry.slow_time_affects_players.tooltip=Whether players are slowed when another nearby player uses the slow time spell. If this is disabled, mobs and projectiles will still be affected but players will move at normal speed.
config.ebwizardry.bonemeal_grows_crystal_flowers=Bonemeal Grows Crystal Flowers
config.ebwizardry.bonemeal_grows_crystal_flowers.tooltip=Whether using bonemeal on grass blocks has a chance to grow crystal flowers.
config.ebwizardry.wands_must_be_held_to_decrement_cooldown=Wands Must Be Held To Decrement Cooldown
config.ebwizardry.wands_must_be_held_to_decrement_cooldown.tooltip=Whether wands only decrement their cooldowns if a player holds them.
config.ebwizardry.cooldown_reduction_per_level=Cooldown Reduction Per Level
config.ebwizardry.cooldown_reduction_per_level.tooltip=The fraction by which cooldowns are reduced for each level of cooldown upgrade.
config.ebwizardry.potency_increase_per_tier=Potency Increase Per Tier
config.ebwizardry.potency_increase_per_tier.tooltip=The fraction by which potency is increased for each tier of matching wand. May cause extreme lag with high values!
config.ebwizardry.duration_increase_per_level=Duration Increase Per Level
config.ebwizardry.duration_increase_per_level.tooltip=The fraction by which spell duration is increased for each level of duration upgrade.
config.ebwizardry.range_increase_per_level=Range Increase Per Level
config.ebwizardry.range_increase_per_level.tooltip=The fraction by which spell range is increased for each level of range upgrade. May cause extreme lag with high values!
config.ebwizardry.blast_increase_per_level=Blast Increase Per Level
config.ebwizardry.blast_increase_per_level.tooltip=The fraction by which spell blast is increased for each level of blast upgrade. May cause extreme lag with high values!
config.ebwizardry.frost_slowness_increase_per_level=Frost Slowness Increase Per Level
config.ebwizardry.frost_slowness_increase_per_level.tooltip=The fraction by which movement speed is reduced per level of frost effect.
config.ebwizardry.category.difficulty=Difficulty Settings
config.ebwizardry.category.difficulty.tooltip=Configure wizardry's difficulty
@@ -1580,6 +1631,8 @@ config.ebwizardry.mob_loot_table_whitelist=Mob Loot Table Whitelist
config.ebwizardry.mob_loot_table_whitelist.tooltip=Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them.
config.ebwizardry.mob_loot_table_blacklist=Mob Loot Table Blacklist
config.ebwizardry.mob_loot_table_blacklist.tooltip=Blacklist 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 exclude them.
config.ebwizardry.inject_mob_drops=Allow Wizardry Mob Loot
config.ebwizardry.inject_mob_drops.tooltip=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!
config.ebwizardry.mob_spawn_dimensions=Mob Spawning Dimensions
config.ebwizardry.mob_spawn_dimensions.tooltip=List of ids of dimensions in which wizardry's hostile mobs can spawn.
config.ebwizardry.mob_spawn_biome_blacklist=Mob Spawning Biome Blacklist
File diff suppressed because it is too large Load Diff
@@ -53,21 +53,21 @@ tile.ebwizardry\:receptacle.name=받침
tile.ebwizardry\:imbuement_altar.name=고취의 제단
item.ebwizardry\:crystal_magic.name=마법수정
item.ebwizardry\:crystal_magic.desc=무지갯빛의 아름다운 수정, 마법의 기운이 내부에서 서서히 변화하 소용돌이치고 있다. 어쩌면 이 수정은 사용하면...
item.ebwizardry\:crystal_magic.desc=무지갯빛의 아름다운 수정, 마법의 기운이 내부에서 서서히 변화하 소용돌이치고 있습니다. 어쩌면 이 수정은 사용하면...
item.ebwizardry\:crystal_fire.name=화염의 수정
item.ebwizardry\:crystal_fire.desc=주황빛으로 불타는 수정. 어쩌면 불의 원소를 푸는 열쇠일지도 모다...
item.ebwizardry\:crystal_fire.desc=주황빛으로 불타는 수정, 어쩌면 불의 원소를 푸는 열쇠일지도 모릅니다...
item.ebwizardry\:crystal_ice.name=얼음의 수정
item.ebwizardry\:crystal_ice.desc=푸르스름한 색조의 차가운 수정. 어쩌면 서리의 힘의 비밀을 간직하고 있을지도 모다...
item.ebwizardry\:crystal_ice.desc=푸르스름한 색조의 차가운 수정, 어쩌면 서리의 힘의 비밀을 간직하고 있을지도 모릅니다...
item.ebwizardry\:crystal_lightning.name=폭풍의 수정
item.ebwizardry\:crystal_lightning.desc=어지럽게 소용돌이치고 번쩍이는 수정. 어쩌면 더 큰 힘을 숨기고 있을지도 모다...
item.ebwizardry\:crystal_lightning.desc=어지럽게 소용돌이치고 번쩍이는 수정, 어쩌면 더 큰 힘을 숨기고 있을지도 모릅니다...
item.ebwizardry\:crystal_necromancy.name=어둠의 수정
item.ebwizardry\:crystal_necromancy.desc=마치 끌어당기는 듯한 깊고 푸르스름한 수정. 어쩌면 더 어두운 곳으로 가는 관문일지도 모다...
item.ebwizardry\:crystal_necromancy.desc=마치 끌어당기는 듯한 깊고 푸르스름한 수정, 어쩌면 더 어두운 곳으로 가는 관문일지도 모릅니다...
item.ebwizardry\:crystal_earth.name=신록의 수정
item.ebwizardry\:crystal_earth.desc=녹색과 약간의 갈색으로 이루어진 수정. 어쩌면 자연의 힘과 연관이 있을지도 모다...
item.ebwizardry\:crystal_earth.desc=녹색과 약간의 갈색으로 이루어진 수정, 어쩌면 자연의 힘과 연관이 있을지도 모릅니다...
item.ebwizardry\:crystal_sorcery.name=신령의 수정
item.ebwizardry\:crystal_sorcery.desc=푸르스름한 초록빛의 반짝거리는 수정. 어쩌면 고대의 힘의 비밀을 감추고 있을지도 모다...
item.ebwizardry\:crystal_sorcery.desc=푸르스름한 초록빛의 반짝거리는 수정, 어쩌면 고대의 힘의 비밀을 감추고 있을지도 모릅니다...
item.ebwizardry\:crystal_healing.name=복사의 수정
item.ebwizardry\:crystal_healing.desc=금빛 햇살처럼 노랗게 반짝이는 수정. 어쩌면 신성한 힘의 연결고리일지도 모다...
item.ebwizardry\:crystal_healing.desc=금빛 햇살처럼 노랗게 반짝이는 수정, 어쩌면 신성한 힘의 연결고리일지도 모릅니다...
item.ebwizardry\:spell_book.name=주문서
item.ebwizardry\:spell_book.desc=고대의 상형문자와 룬 문자로 채워진 책. 노력을 통해 그 내용을 해독할 수 있을 것 같습니다...\n\n책을 읽으려면 오른쪽 버튼을 누르세요.
@@ -75,7 +75,7 @@ item.ebwizardry\:spell_book.new=아직 발견되지 않았습니다!
item.ebwizardry\:spell_book.apply_to_wizard=%1$s의 주문 %2$s을 %3$s로 대체하였습니다
item.ebwizardry\:ruined_spell_book.name=빛바랜 주문서
item.ebwizardry\:ruined_spell_book.desc=이 너덜너덜한 주문서는 너무 손상되어 제대로 읽혀지지 않지만, 어찌된 일인지, 아직도 마법의 기운이 남아있다. 만약 복원될 수만 있다면...
item.ebwizardry\:ruined_spell_book.desc=이 너덜너덜한 주문서는 너무 손상되어 제대로 읽혀지지 않지만, 어찌된 일인지, 아직도 마법의 기운이 남아있습니다. 만약 복원될 수만 있다면...
item.ebwizardry\:arcane_tome.name=마도서
item.ebwizardry\:arcane_tome.desc=아무 %1$s지팡이를 %2$s지팡이로 강화합니다
@@ -112,7 +112,7 @@ item.ebwizardry\:novice_healing_wand.name=회복 지팡이
item.ebwizardry\:apprentice_fire_wand.name=견습 화염 지팡이
item.ebwizardry\:apprentice_ice_wand.name=견습 얼음 지팡이
item.ebwizardry\:apprentice_lightning_wand.name=견습 벼락 지팡이
item.ebwizardry\:apprentice_necromancy_wand.name=견습 령 지팡이
item.ebwizardry\:apprentice_necromancy_wand.name=견습 령 지팡이
item.ebwizardry\:apprentice_earth_wand.name=견습 대지 지팡이
item.ebwizardry\:apprentice_sorcery_wand.name=견습 신비 지팡이
item.ebwizardry\:apprentice_healing_wand.name=견습 치유 지팡이
@@ -120,7 +120,7 @@ item.ebwizardry\:apprentice_healing_wand.name=견습 치유 지팡이
item.ebwizardry\:advanced_fire_wand.name=숙련 화염술사의 지팡이
item.ebwizardry\:advanced_ice_wand.name=숙련 얼음법사의 지팡이
item.ebwizardry\:advanced_lightning_wand.name=숙련 벼락술사의 지팡이
item.ebwizardry\:advanced_necromancy_wand.name=숙련 령술사의 지팡이
item.ebwizardry\:advanced_necromancy_wand.name=숙련 령술사의 지팡이
item.ebwizardry\:advanced_earth_wand.name=숙련 대지법사의 지팡이
item.ebwizardry\:advanced_sorcery_wand.name=숙련 신비술사의 지팡이
item.ebwizardry\:advanced_healing_wand.name=숙련 치유사의 지팡이
@@ -146,16 +146,16 @@ item.ebwizardry\:large_mana_flask.name=큰 마나병
item.ebwizardry\:mana_flask.desc=제작을 통해 %s마나를 지팡이나 갑옷에 충전합니다
item.ebwizardry\:grand_crystal.name=거대한 마법수정
item.ebwizardry\:grand_crystal.desc=자연적으로 발견된 것의 몇 배 크기인 거대한 마법의 수정. 누군가 인공적으로 만든 게 틀림없다. 하지만 어떻게?
item.ebwizardry\:grand_crystal.desc=자연적으로 발견된 것의 몇 배 크기인 거대한 마법의 수정, 누군가 인공적으로 만든 게 틀림없습니다. 하지만 어떻게?
item.ebwizardry\:crystal_shard.name=마법수정 조각
item.ebwizardry\:crystal_shard.desc=산산조각난 마법 수정의 작은 조각. 그 자체로는 마력이 거의 없지만, 다른 용도가 있을지도 모다...
item.ebwizardry\:crystal_shard.desc=산산조각난 마법 수정의 작은 조각, 그 자체로는 마력이 거의 없지만, 다른 용도가 있을지도 모릅니다...
item.ebwizardry\:astral_diamond.name=별의 다이아몬드
item.ebwizardry\:astral_diamond.desc=별빛 아래 밝게 빛나는 아름다운 보석. 어떠한 마법사들은 강력한 마법의 거래 대가로 별의 다이아몬드를 찾는다네.
item.ebwizardry\:astral_diamond.desc=별빛 아래 밝게 빛나는 아름다운 보석이라네. 어떠한 마법사들은 강력한 마법의 거래 대가로 별의 다이아몬드를 찾는다네.
item.ebwizardry\:purifying_elixir.name=정화의 영약
item.ebwizardry\:purifying_elixir.desc=저주를 제거합니다
item.ebwizardry\:purifying_elixir.desc_extended=특이한 금빛 액체가 담긴 작은 병으로, 강력한 회복의 특성을 보이고 있습니다.
item.ebwizardry\:purifying_elixir.desc_extended=특이한 금빛 액체가 담긴 작은 병으로, 강력한 회복을 보이고 있습니다.
item.ebwizardry\:storage_upgrade.name=지팡이 용량 강화
item.ebwizardry\:siphon_upgrade.name=지팡이 흡수 강화
@@ -194,24 +194,38 @@ item.ebwizardry\:blank_scroll.name=빈 두루마리
item.ebwizardry\:scroll.generic=두루마리
item.ebwizardry\:scroll.name=%1$s의 두루마리
item.ebwizardry\:scroll.undiscovered.name="%1$s"두루마리
item.ebwizardry\:scroll.desc=끈으로 느슨하게 묶인 마법이 부여된 종이. 두루마리에 부여된 주문을 외우면 외운 주문이 시전된다 .\n시전하려면 오른쪽 버튼을 누르세요.
item.ebwizardry\:scroll.desc=끈으로 느슨하게 묶인 마법이 부여된 종이. 두루마리에 부여된 주문을 외우면 외운 주문이 시전됩니다.\n시전하려면 오른쪽 버튼을 누르세요.
item.ebwizardry\:identification_scroll.name=지식의 두루마리
item.ebwizardry\:identification_scroll.desc=알 수 없는 주문서나 두루마리를 식별합니다
item.ebwizardry\:identification_scroll.desc_extended=오른쪽 버튼을 클릭하여 식별하지 않은 주문서를 식별할 수 있습니다.
item.ebwizardry\:identification_scroll.nothing_to_identify=식별할 주문이 없습니다!
item.ebwizardry\:armour_upgrade.name=신비로운 보호의 문양
item.ebwizardry\:armour_upgrade.desc=아무 마법사의 갑옷을 전설등급으로 만듭니다
item.ebwizardry\:armour_upgrade.desc_extended=신비로운 작업대에서 갑옷에 적용할 수 있습니다.
item.ebwizardry\:resplendent_thread.name=찬란한 실타래
item.ebwizardry\:resplendent_thread.desc=일반적인 마법사의 갑옷을 학자의 갑옷으로 강화합니다
item.ebwizardry\:resplendent_thread.desc_extended=희미하게 빛나는 실로 신비로운 무늬를 수놓아 로브의 질을 높이고, 마법 부여의 효과를 상승시킵니다.\n\n신비로운 작업대에서 마법사 갑옷에 이 강화를 적용할 수 있습니다.
item.ebwizardry\:crystal_silver_plating.name=은도금된 수정
item.ebwizardry\:crystal_silver_plating.desc=일반적인 마법사의 갑옷을 전투법사의 갑옷으로 강화합니다
item.ebwizardry\:crystal_silver_plating.desc_extended=엘다르의 대장간에서 만들어진 거의 신화적인 합금으로, 우수한 마법 굴절도를 가지고 있습니다.\n\n신비로운 작업대에서 마법사 갑옷에 이 강화를 적용할 수 있습니다.
item.ebwizardry\:ethereal_crystalweave.name=천상의 수정천
item.ebwizardry\:ethereal_crystalweave.desc=일반적인 마법사의 갑옷을 주술사의 갑옷으로 강화합니다
item.ebwizardry\:ethereal_crystalweave.desc_extended=동물의 가죽처럼 두껍지만 한 장의 종이보다 가벼운 마나의 천입니다.\n\n신비로운 작업대에서 마법사 갑옷에 이 강화를 적용할 수 있습니다.
item.ebwizardry\:magic_silk.name=마법 비단
item.ebwizardry\:spectral_dust.name=망령의 가루
item.ebwizardry\:wizard_armour.legendary=전설
item.ebwizardry\:wizard_armour.buff=%2$s 주문의 비용이 %1$s 감소
item.ebwizardry\:wizard_armour.element_cost_reduction=%2$s 주문의 마나 소모량이 %1$s 감소
item.ebwizardry\:wizard_armour.cooldown_reduction=재사용 대기시간이 %1$s%% 감소
item.ebwizardry\:wizard_armour.enchantability=마법 부여의 효과 상승
item.ebwizardry\:wizard_armour.mana=마나\: %1$s/%2$s
item.ebwizardry\:wizard_armour.full_set=전부 착용 시:
item.ebwizardry\:sage_armour.full_set_bonus=다른 원소의 주문의 마나 소모량이 %1$s%% 감소
item.ebwizardry\:battlemage_armour.full_set_bonus=보호 I 효과가 부여
item.ebwizardry\:warlock_armour.full_set_bonus=이동속도가 %1$s%% 상승
item.ebwizardry\:wizard_hat.name=마법사 모자
item.ebwizardry\:wizard_robe.name=마법사 로브
item.ebwizardry\:wizard_leggings.name=마법사 각반
@@ -232,10 +246,10 @@ item.ebwizardry\:wizard_robe_lightning.name=벼락술사 로브
item.ebwizardry\:wizard_leggings_lightning.name=벼락술사 각반
item.ebwizardry\:wizard_boots_lightning.name=벼락술사 부츠
item.ebwizardry\:wizard_hat_necromancy.name=령술사 모자
item.ebwizardry\:wizard_robe_necromancy.name=령술사 로브
item.ebwizardry\:wizard_leggings_necromancy.name=령술사 각반
item.ebwizardry\:wizard_boots_necromancy.name=령술사 부츠
item.ebwizardry\:wizard_hat_necromancy.name=령술사 모자
item.ebwizardry\:wizard_robe_necromancy.name=령술사 로브
item.ebwizardry\:wizard_leggings_necromancy.name=령술사 각반
item.ebwizardry\:wizard_boots_necromancy.name=령술사 부츠
item.ebwizardry\:wizard_hat_earth.name=대지법사 모자
item.ebwizardry\:wizard_robe_earth.name=대지법사 로브
@@ -252,6 +266,126 @@ item.ebwizardry\:wizard_robe_healing.name=치유사 로브
item.ebwizardry\:wizard_leggings_healing.name=치유사 각반
item.ebwizardry\:wizard_boots_healing.name=치유사 부츠
item.ebwizardry\:sage_hat.name=학자 모자
item.ebwizardry\:sage_robe.name=학자 로브
item.ebwizardry\:sage_leggings.name=학자 각반
item.ebwizardry\:sage_boots.name=학자 부츠
item.ebwizardry\:sage_hat_fire.name=화염학자 모자
item.ebwizardry\:sage_robe_fire.name=화염학자 로브
item.ebwizardry\:sage_leggings_fire.name=화염학자 각반
item.ebwizardry\:sage_boots_fire.name=화염학자 부츠
item.ebwizardry\:sage_hat_ice.name=얼음학자 모자
item.ebwizardry\:sage_robe_ice.name=얼음학자 로브
item.ebwizardry\:sage_leggings_ice.name=얼음학자 각반
item.ebwizardry\:sage_boots_ice.name=얼음학자 부츠
item.ebwizardry\:sage_hat_lightning.name=벼락학자 모자
item.ebwizardry\:sage_robe_lightning.name=벼락학자 로브
item.ebwizardry\:sage_leggings_lightning.name=벼락학자 각반
item.ebwizardry\:sage_boots_lightning.name=벼락학자 부츠
item.ebwizardry\:sage_hat_necromancy.name=사령학자 모자
item.ebwizardry\:sage_robe_necromancy.name=사령학자 로브
item.ebwizardry\:sage_leggings_necromancy.name=사령학자 각반
item.ebwizardry\:sage_boots_necromancy.name=사령학자 부츠
item.ebwizardry\:sage_hat_earth.name=대지학자 모자
item.ebwizardry\:sage_robe_earth.name=대지학자 로브
item.ebwizardry\:sage_leggings_earth.name=대지학자 각반
item.ebwizardry\:sage_boots_earth.name=대지학자 부츠
item.ebwizardry\:sage_hat_sorcery.name=신비학자 모자
item.ebwizardry\:sage_robe_sorcery.name=신비학자 로브
item.ebwizardry\:sage_leggings_sorcery.name=신비학자 각반
item.ebwizardry\:sage_boots_sorcery.name=신비학자 부츠
item.ebwizardry\:sage_hat_healing.name=치유학자 모자
item.ebwizardry\:sage_robe_healing.name=치유학자 로브
item.ebwizardry\:sage_leggings_healing.name=치유학자 각반
item.ebwizardry\:sage_boots_healing.name=치유학자 부츠
item.ebwizardry\:battlemage_helmet.name=전투법사 투구
item.ebwizardry\:battlemage_chestplate.name=전투법사 흉갑
item.ebwizardry\:battlemage_leggings.name=전투법사 각반
item.ebwizardry\:battlemage_boots.name=전투법사 부츠
item.ebwizardry\:battlemage_helmet_fire.name=화염 전투법사 투구
item.ebwizardry\:battlemage_chestplate_fire.name=화염 전투법사 흉갑
item.ebwizardry\:battlemage_leggings_fire.name=화염 전투법사 각반
item.ebwizardry\:battlemage_boots_fire.name=화염 전투법사 부츠
item.ebwizardry\:battlemage_helmet_ice.name=얼음 전투법사 투구
item.ebwizardry\:battlemage_chestplate_ice.name=얼음 전투법사 흉갑
item.ebwizardry\:battlemage_leggings_ice.name=얼음 전투법사 각반
item.ebwizardry\:battlemage_boots_ice.name=얼음 전투법사 부츠
item.ebwizardry\:battlemage_helmet_lightning.name=벼락 전투법사 투구
item.ebwizardry\:battlemage_chestplate_lightning.name=벼락 전투법사 흉갑
item.ebwizardry\:battlemage_leggings_lightning.name=벼락 전투법사 각반
item.ebwizardry\:battlemage_boots_lightning.name=벼락 전투법사 부츠
item.ebwizardry\:battlemage_helmet_necromancy.name=사령 전투법사 투구
item.ebwizardry\:battlemage_chestplate_necromancy.name=사령 전투법사 흉갑
item.ebwizardry\:battlemage_leggings_necromancy.name=사령 전투법사 각반
item.ebwizardry\:battlemage_boots_necromancy.name=사령 전투법사 부츠
item.ebwizardry\:battlemage_helmet_earth.name=대지 전투법사 투구
item.ebwizardry\:battlemage_chestplate_earth.name=대지 전투법사 흉갑
item.ebwizardry\:battlemage_leggings_earth.name=대지 전투법사 각반
item.ebwizardry\:battlemage_boots_earth.name=대지 전투법사 부츠
item.ebwizardry\:battlemage_helmet_sorcery.name=신비 전투법사 투구
item.ebwizardry\:battlemage_chestplate_sorcery.name=신비 전투법사 흉갑
item.ebwizardry\:battlemage_leggings_sorcery.name=신비 전투법사 각반
item.ebwizardry\:battlemage_boots_sorcery.name=신비 전투법사 부츠
item.ebwizardry\:battlemage_helmet_healing.name=치유 전투법사 투구
item.ebwizardry\:battlemage_chestplate_healing.name=치유 전투법사 흉갑
item.ebwizardry\:battlemage_leggings_healing.name=치유 전투법사 각반
item.ebwizardry\:battlemage_boots_healing.name=치유 전투법사 부츠
item.ebwizardry\:warlock_hood.name=주술사 후드
item.ebwizardry\:warlock_robe.name=주술사 로브
item.ebwizardry\:warlock_leggings.name=주술사 각반
item.ebwizardry\:warlock_boots.name=주술사 부츠
item.ebwizardry\:warlock_hood_fire.name=화염주술사 후드
item.ebwizardry\:warlock_robe_fire.name=화염주술사 로브
item.ebwizardry\:warlock_leggings_fire.name=화염주술사 각반
item.ebwizardry\:warlock_boots_fire.name=화염주술사 부츠
item.ebwizardry\:warlock_hood_ice.name=얼음주술사 후드
item.ebwizardry\:warlock_robe_ice.name=얼음주술사 로브
item.ebwizardry\:warlock_leggings_ice.name=얼음주술사 각반
item.ebwizardry\:warlock_boots_ice.name=얼음주술사 부츠
item.ebwizardry\:warlock_hood_lightning.name=벼락주술사 후드
item.ebwizardry\:warlock_robe_lightning.name=벼락주술사 로브
item.ebwizardry\:warlock_leggings_lightning.name=벼락주술사 각반
item.ebwizardry\:warlock_boots_lightning.name=벼락주술사 부츠
item.ebwizardry\:warlock_hood_necromancy.name=사령주술사 후드
item.ebwizardry\:warlock_robe_necromancy.name=사령주술사 로브
item.ebwizardry\:warlock_leggings_necromancy.name=사령주술사 각반
item.ebwizardry\:warlock_boots_necromancy.name=사령주술사 부츠
item.ebwizardry\:warlock_hood_earth.name=대지주술사 후드
item.ebwizardry\:warlock_robe_earth.name=대지주술사 로브
item.ebwizardry\:warlock_leggings_earth.name=대지주술사 각반
item.ebwizardry\:warlock_boots_earth.name=대지주술사 부츠
item.ebwizardry\:warlock_hood_sorcery.name=신비주술사 후드
item.ebwizardry\:warlock_robe_sorcery.name=신비주술사 로브
item.ebwizardry\:warlock_leggings_sorcery.name=신비주술사 각반
item.ebwizardry\:warlock_boots_sorcery.name=신비주술사 부츠
item.ebwizardry\:warlock_hood_healing.name=치유주술사 후드
item.ebwizardry\:warlock_robe_healing.name=치유주술사 로브
item.ebwizardry\:warlock_leggings_healing.name=치유주술사 각반
item.ebwizardry\:warlock_boots_healing.name=치유주술사 부츠
item.ebwizardry\:spawn_wizard.name=생성: 마법사
item.ebwizardry\:spawn_evil_wizard.name=생성: 사악한 마법사
@@ -265,9 +399,9 @@ item.ebwizardry\:flamecatcher.name=화염의 활
item.ebwizardry\:generic.disabled=이 아이템은 설정에서 사용할 수 없도록 설정됨
item.ebwizardry\:ring.generic.desc=버블즈 인벤토리에 장착하거나, 단축바에 두어 최대 2개 까지 장착할 수 있다.
item.ebwizardry\:amulet.generic.desc=버블즈 인벤토리에 장착하거나, 단축바에 두어 한 번에 한 개만 장착할 수 있다.
item.ebwizardry\:charm.generic.desc=버블즈 인벤토리에 장착하거나, 단축바에 두어 한 번에 한 개만 장착할 수 있다.
item.ebwizardry\:ring.generic.desc=버블즈 인벤토리에 장착하거나, 단축바에 올려둬 최대 2개 까지 장착할 수 있습니다.
item.ebwizardry\:amulet.generic.desc=버블즈 인벤토리에 장착하거나, 단축바에 올려둬 한 번에 한 개만 장착할 수 있습니다.
item.ebwizardry\:charm.generic.desc=버블즈 인벤토리에 장착하거나, 단축바에 올려둬 한 번에 한 개만 장착할 수 있습니다.
item.ebwizardry\:ring_condensing.name=축전의 반지
item.ebwizardry\:ring_condensing.desc=단축바에 있는 모든 지팡이의 마나를 천천히 재생시킵니다
@@ -404,7 +538,7 @@ item.ebwizardry\:charm_flight.name=에메랄드 딱정벌레 날개
item.ebwizardry\:charm_flight.desc=비행 및 활공 속도가 50%%더 빨라집니다
item.ebwizardry\:charm_growth.name=마법수정 꽃 부적
item.ebwizardry\:charm_growth.desc=수확의 축복 주문이 35%%확률로 식물을 완전히 자라게 합니다
item.ebwizardry\:charm_abseiling.name=마법이 부여된 실타래
item.ebwizardry\:charm_abseiling.name=마법이 부여된 실뭉치
item.ebwizardry\:charm_abseiling.desc=덩굴의 얽매임을 사용하며 공중에 있을 때 웅크리면 덩굴의 길이가 늘어납니다
item.ebwizardry\:charm_silk_touch.name=월광석 보주
item.ebwizardry\:charm_silk_touch.desc=채광 주문에 섬세한 손길이 적용됩니다
@@ -577,6 +711,7 @@ entity.ebwizardry\:wizard.player_combat_3=너의 부주의함이 대가를 치
entity.ebwizardry\:wizard.player_combat_4=싸울 준비나 해라, 악당아!
entity.ebwizardry\:wizard.player_combat_5=분노를 느낄 준비나 해라!
entity.ebwizardry\:zombie_minion.name=좀비
entity.ebwizardry\:husk_minion.name=허스크
entity.ebwizardry\:skeleton_minion.name=스켈레톤
entity.ebwizardry\:stray_minion.name=스트레이
@@ -599,7 +734,7 @@ entity.ebwizardry\:decoy.name=분산
entity.ebwizardry\:vex_minion.name=벡스
entity.ebwizardry\:remnant.name=잔존체
entity.ebwizardry\:마법_missile.name=마법
entity.ebwizardry\:magic_missile.name=마법
entity.ebwizardry\:arc.name=마법
entity.ebwizardry\:spark_bomb.name=마법
entity.ebwizardry\:ice_shard.name=마법
@@ -711,8 +846,12 @@ advancement.ebwizardry\:craft_lectern.desc=주문서 책장을 관리하기 위
advancement.ebwizardry\:armour_set=이제야 좀 제대로 된 마법사 같네
advancement.ebwizardry\:armour_set.desc=마법사 갑옷의 모자, 로브, 각반, 부츠를 모두 장착하세요
advancement.ebwizardry\:legendary=전설!
advancement.ebwizardry\:legendary.desc=전설 마법사 갑옷을 획득하세요
advancement.ebwizardry\:sage=학자의 길
advancement.ebwizardry\:sage.desc=학자의 갑옷을 획득하세요
advancement.ebwizardry\:battlemage=전투법사의 서약
advancement.ebwizardry\:battlemage.desc=전투법사의 갑옷을 획득하세요
advancement.ebwizardry\:warlock=주술사의 방식
advancement.ebwizardry\:warlock.desc=주술사의 갑옷을 획득하세요
advancement.ebwizardry\:enchant_scroll=두루마리!
advancement.ebwizardry\:enchant_scroll.desc=빈 두루마리를 만들고 신비로운 작업대에서 주문의 마법을 부여하세요
@@ -758,7 +897,7 @@ element.magic.wizard=마법사
element.fire.wizard=화염술사
element.ice.wizard=얼음법사
element.lightning.wizard=벼락술사
element.necromancy.wizard=령술사
element.necromancy.wizard=령술사
element.earth.wizard=대지법사
element.sorcery.wizard=신비술사
element.healing.wizard=치유사
@@ -52,8 +52,8 @@ tile.ebwizardry\:dark_oak_lectern.name=Кафедра из тёмного дуб
tile.ebwizardry\:receptacle.name=Вместилище
tile.ebwizardry\:imbuement_altar.name=Алтарь наполнения
item.ebwizardry\:crystal_magic.name=Магический кристалл
item.ebwizardry\:crystal_magic.desc=Переливающиеся цвета этого кристалла, кажется, медленно меняются и кружатся, намекая на магическую энергию внутри. Возможно, эту магию можно задействовать, как-нибудь...
item.ebwizardry\:crystal_magic.name=Волшебный кристалл
item.ebwizardry\:crystal_magic.desc=Переливающиеся цвета этого кристалла, кажется, медленно меняются и кружатся, намекая на волшебную энергию внутри. Возможно, эту магию можно задействовать, как-нибудь...
item.ebwizardry\:crystal_fire.name=Огненный кристалл
item.ebwizardry\:crystal_fire.desc=Кристалл, который светится оранжево-огненным цветом. Возможно, он - ключ к разблокировки элемента огня...
item.ebwizardry\:crystal_ice.name=Ледяной кристалл
@@ -96,7 +96,7 @@ item.ebwizardry\:wand.levelup=%1$s готов улучшиться до уров
item.ebwizardry\:wand.addally=%1$s был добавлен в Ваш список союзников.
item.ebwizardry\:wand.removeally=%1$s был убран из Вашего списка союзников.
item.ebwizardry\:magic_wand.name=Магический жезл
item.ebwizardry\:magic_wand.name=Волшебный жезл
item.ebwizardry\:apprentice_wand.name=Жезл ученика
item.ebwizardry\:advanced_wand.name=Продвинутый жезл
item.ebwizardry\:master_wand.name=Жезл мастера
@@ -145,10 +145,10 @@ item.ebwizardry\:medium_mana_flask.name=Средняя колба с маной
item.ebwizardry\:large_mana_flask.name=Большая колба с маной
item.ebwizardry\:mana_flask.desc=Изготовьте колбу с маной с использованием Жезла или части брони Волшебника, чтобы восстановить %s маны.
item.ebwizardry\:grand_crystal.name=Большой магический кристалл
item.ebwizardry\:grand_crystal.desc=Крупный магический кристалл, в несколько раз больше тех, что обнаружены естественным образом. Кто-то, видимо, вырастил его искусственно - но как?
item.ebwizardry\:crystal_shard.name=Магический кристальный осколок
item.ebwizardry\:crystal_shard.desc=Маленький кусочек раздробленного магического кристалла. Он содержит в себе немного кол-во маны, но он может иметь другое применение...
item.ebwizardry\:grand_crystal.name=Большой волшебный кристалл
item.ebwizardry\:grand_crystal.desc=Крупный волшебный кристалл, в несколько раз больше тех, что обнаружены естественным образом. Кто-то, видимо, вырастил его искусственно - но как?
item.ebwizardry\:crystal_shard.name=Волшебный кристальный осколок
item.ebwizardry\:crystal_shard.desc=Маленький кусочек раздробленного волшебного кристалла. Он содержит в себе немного количество маны, но он может иметь другое применение...
item.ebwizardry\:astral_diamond.name=Звёздный алмаз
item.ebwizardry\:astral_diamond.desc=Высоко-ценившиеся драгоценный камень, который ярко сверкает над звёздным светом. Поговаривают, что самые могущественные Волшебники ищут Звёздные алмазы в замен, на самые неуловимые Таинственные знания.
@@ -176,7 +176,7 @@ item.ebwizardry\:range_upgrade.desc=Улучшает эффективный ра
item.ebwizardry\:duration_upgrade.desc=Улучшает продолжительность эффектов брошенным Жезлом.
item.ebwizardry\:cooldown_upgrade.desc=Улучшает скорость отката заклинания Жезла.
item.ebwizardry\:blast_upgrade.desc=Улучшает область эффекта заклинаний брошенным Жезлом.
item.ebwizardry\:attunement_upgrade.desc=Улучшает кол-во заклинаний, которых можно привязать к Жезлу.
item.ebwizardry\:attunement_upgrade.desc=Улучшает количество заклинаний, которых можно привязать к Жезлу.
item.ebwizardry\:melee_upgrade.desc=Улучшает жезл на использование маны, для нанесения большего урона по мобам, при ударе.
item.ebwizardry\:flaming_axe.name=Пылающий топор
@@ -204,7 +204,7 @@ item.ebwizardry\:armour_upgrade.name=Мистическая печать защ
item.ebwizardry\:armour_upgrade.desc=Улучшает любую Броню волшебника, чтобы сделать её %1$s Легендарной.
item.ebwizardry\:armour_upgrade.desc_extended=Примените это Улучшение в часть брони Волшебника в Мистическом верстаке.
item.ebwizardry\:magic_silk.name=Магический шёлк
item.ebwizardry\:magic_silk.name=Волшебный шёлк
item.ebwizardry\:spectral_dust.name=Спектральный прах
@@ -274,7 +274,7 @@ item.ebwizardry\:ring_condensing.desc=Медленно восстанавлив
item.ebwizardry\:ring_siphoning.name=Кольцо выкачивания
item.ebwizardry\:ring_siphoning.desc=Увеличивает выкачивание маны на 30%%.
item.ebwizardry\:ring_battlemage.name=Кольцо боевого мага
item.ebwizardry\:ring_battlemage.desc=Удерживая жезл в левой руке и меч в основной руке, даёт 10%% дополнительного магического урона.
item.ebwizardry\:ring_battlemage.desc=Удерживая жезл в левой руке и меч в основной руке, даёт 10%% дополнительного волшебного урона.
item.ebwizardry\:ring_combustion.name=Кольцо горения
item.ebwizardry\:ring_combustion.desc=Существа, убитые Огненными заклинаниями, взрываются.
item.ebwizardry\:ring_fire_melee.name=Кольцо огненного прикосновения
@@ -339,7 +339,7 @@ item.ebwizardry\:ring_interdiction.desc=Ваше силовое поле пов
item.ebwizardry\:amulet_arcane_defence.name=Амулет мистической защиты
item.ebwizardry\:amulet_arcane_defence.desc=Медленно восстанавливается мана на всю одетую броню Волшебника.
item.ebwizardry\:amulet_warding.name=Амулет защиты
item.ebwizardry\:amulet_warding.desc=Сокращает весь входящий магический урон на 10%%.
item.ebwizardry\:amulet_warding.desc=Сокращает весь входящий волшебный урон на 10%%.
item.ebwizardry\:amulet_wisdom.name=Амулет мудрости
item.ebwizardry\:amulet_wisdom.desc=Существенно сокращает шанс отрицательных эффектов при использовании неоткрытых Заклинаний.
item.ebwizardry\:amulet_fire_protection.name=Амулет быстрой пламени
@@ -591,7 +591,7 @@ entity.ebwizardry\:spirit_horse.name=Призрачная лошадь
entity.ebwizardry\:ice_giant.name=Ледяной гигант
entity.ebwizardry\:phoenix.name=Феникс
entity.ebwizardry\:wizard.name=Волшебник
entity.ebwizardry\:magic_slime.name=Магический слизень
entity.ebwizardry\:magic_slime.name=Волшебный слизень
entity.ebwizardry\:silverfish_minion.name=Чешуйница
entity.ebwizardry\:storm_elemental.name=Грозовой элементаль
entity.ebwizardry\:evil_wizard.name=Злой волшебник
@@ -599,31 +599,31 @@ entity.ebwizardry\:decoy.name=Приманка
entity.ebwizardry\:vex_minion.name=Досаждатель
entity.ebwizardry\:remnant.name=Пережиток
entity.ebwizardry\:magic_missile.name=Магическая
entity.ebwizardry\:arc.name=Магическая
entity.ebwizardry\:spark_bomb.name=Магическая
entity.ebwizardry\:ice_shard.name=Магическая
entity.ebwizardry\:firebomb.name=Магическая
entity.ebwizardry\:poison_bomb.name=Магическая
entity.ebwizardry\:force_orb.name=Магическая
entity.ebwizardry\:spark.name=Магическая
entity.ebwizardry\:darkness_orb.name=Магическая
entity.ebwizardry\:fire_sigil.name=Магическая
entity.ebwizardry\:frost_sigil.name=Магическая
entity.ebwizardry\:lightning_sigil.name=Магическая
entity.ebwizardry\:lightning_arrow.name=Магическая
entity.ebwizardry\:firebolt.name=Магическая
entity.ebwizardry\:ice_charge.name=Магическая
entity.ebwizardry\:force_arrow.name=Магическая
entity.ebwizardry\:dart.name=Магическая
entity.ebwizardry\:lightning_disc.name=Магическая
entity.ebwizardry\:thunderbolt.name=Магическая
entity.ebwizardry\:decay.name=Магическая
entity.ebwizardry\:ice_lance.name=Магическая
entity.ebwizardry\:smoke_bomb.name=Магическая
entity.ebwizardry\:ice_spike.name=Магическая
entity.ebwizardry\:combustion_rune.name=Магическая
entity.ebwizardry\:flamecatcher_arrow.name=Магическая
entity.ebwizardry\:magic_missile.name=Волшебная
entity.ebwizardry\:arc.name=Волшебная
entity.ebwizardry\:spark_bomb.name=Волшебная
entity.ebwizardry\:ice_shard.name=Волшебная
entity.ebwizardry\:firebomb.name=Волшебная
entity.ebwizardry\:poison_bomb.name=Волшебная
entity.ebwizardry\:force_orb.name=Волшебная
entity.ebwizardry\:spark.name=Волшебная
entity.ebwizardry\:darkness_orb.name=Волшебная
entity.ebwizardry\:fire_sigil.name=Волшебная
entity.ebwizardry\:frost_sigil.name=Волшебная
entity.ebwizardry\:lightning_sigil.name=Волшебная
entity.ebwizardry\:lightning_arrow.name=Волшебная
entity.ebwizardry\:firebolt.name=Волшебная
entity.ebwizardry\:ice_charge.name=Волшебная
entity.ebwizardry\:force_arrow.name=Волшебная
entity.ebwizardry\:dart.name=Волшебная
entity.ebwizardry\:lightning_disc.name=Волшебная
entity.ebwizardry\:thunderbolt.name=Волшебная
entity.ebwizardry\:decay.name=Волшебная
entity.ebwizardry\:ice_lance.name=Волшебная
entity.ebwizardry\:smoke_bomb.name=Волшебная
entity.ebwizardry\:ice_spike.name=Волшебная
entity.ebwizardry\:combustion_rune.name=Волшебная
entity.ebwizardry\:flamecatcher_arrow.name=Волшебная
entity.ebwizardry\:black_hole.name=Чёрная дыра
entity.ebwizardry\:shield.name=Щит
@@ -652,9 +652,9 @@ itemGroup.ebwizardrygear=Снаряжение wizardry
advancement.ebwizardry\:root=Волшебство
advancement.ebwizardry\:root.desc=Путешествие волшебника к освоению Мистики.
advancement.ebwizardry\:crystal=Любопытный кристалл...
advancement.ebwizardry\:crystal.desc=Добудьте магический кристалл.
advancement.ebwizardry\:crystal.desc=Добудьте волшебный кристалл.
advancement.ebwizardry\:arcane_initiate=Приступить к Мистике.
advancement.ebwizardry\:arcane_initiate.desc=Создайте магический Жезл из Золотого самородка, Палки и Магического кристалла.
advancement.ebwizardry\:arcane_initiate.desc=Создайте волшебный Жезл из Золотого самородка, Палки и Волшебного кристалла.
advancement.ebwizardry\:apprentice=Ученик волшебника.
advancement.ebwizardry\:apprentice.desc=Используйте фолиант арканы, чтобы улучшить свой жезл.
@@ -665,13 +665,13 @@ advancement.ebwizardry\:advanced.desc=Улучшите свой Жезл до П
advancement.ebwizardry\:master=Мастер в Мистике.
advancement.ebwizardry\:master.desc=Получите жезл мастера.
advancement.ebwizardry\:max_out_wand=Полностью оборудован.
advancement.ebwizardry\:max_out_wand.desc=Примените максимальное кол-во улучшений в жезл Мастера.
advancement.ebwizardry\:max_out_wand.desc=Примените максимальное количество улучшений в жезл Мастера.
advancement.ebwizardry\:all_spells=Маг на все руки.
advancement.ebwizardry\:all_spells.desc=Бросьте каждое Заклинание в игре.
advancement.ebwizardry\:wizard_tower=Кто здесь живёт?
advancement.ebwizardry\:wizard_tower.desc=Посетите башню Волшебника.
advancement.ebwizardry\:wizard_trade=Магическое решение.
advancement.ebwizardry\:wizard_trade=Волшебное решение.
advancement.ebwizardry\:wizard_trade.desc=Купите предмет у Волшебника.
advancement.ebwizardry\:anger_wizard=Вы пожалеете об этом.
advancement.ebwizardry\:anger_wizard.desc=Разозлите волшебника.
@@ -815,7 +815,7 @@ spell.ebwizardry\:disintegration=Распад
spell.ebwizardry\:divination=Предсказание
spell.ebwizardry\:dragon_fireball=Огненный шар дракона
spell.ebwizardry\:earthquake=Землятресение
spell.ebwizardry\:empowering_presence=Магическое усиление
spell.ebwizardry\:empowering_presence=Волшебное усиление
spell.ebwizardry\:enrage=Разозление
spell.ebwizardry\:entrapment=Провокация
spell.ebwizardry\:evade=Уклонение
@@ -888,7 +888,7 @@ spell.ebwizardry\:lightning_pulse=Молниевый пульс
spell.ebwizardry\:lightning_ray=Молниевый луч
spell.ebwizardry\:lightning_sigil=Молниевый сигил
spell.ebwizardry\:lightning_web=Молниевая паутина
spell.ebwizardry\:magic_missile=Магический снаряд
spell.ebwizardry\:magic_missile=Волшебный снаряд
spell.ebwizardry\:mark_sacrifice=Знак жертвоприношения
spell.ebwizardry\:metamorphosis=Метаморфоз
spell.ebwizardry\:meteor=Метеор
@@ -983,7 +983,7 @@ spell.ebwizardry\:chain_lightning.desc=Стреляет искрами свет
spell.ebwizardry\:charge.desc=Заставляет заклинателя стремительно заряжаться в том направлении, куда он смотрит, повреждая и отбрасывая всё на своём пути.
spell.ebwizardry\:clairvoyance.desc=Раскрывает путь в запоминающее место. С этим выбранным заклинанием, shift + пкм по блоку, чтобы задать место. Бросьте это Заклинание как обычно, чтобы раскрыть путь. Путь исчезнет через 90 секунд.
spell.ebwizardry\:cobwebs.desc=Создаёт паутины туда, куда Вы указываете, она-же, сильно сдерживают движение любых существ пойманные среди них. Паутины пропадут через 20 секунд либо если сломать.
spell.ebwizardry\:combustion_rune.desc=Помещает магические наземные мины на землю туда, куда Вы указываете, которые взрываются когда ступите на них.
spell.ebwizardry\:combustion_rune.desc=Помещает волшебные наземные мины на землю туда, куда Вы указываете, которые взрываются когда ступите на них.
spell.ebwizardry\:conjure_armour.desc=Создаёт спектральную броню вокруг Заклинателя, обеспечивающая защиту равной по защите Железной брони. Броня длится 60 секунд. У заклинателя должен быть Пустой слот для брони.
spell.ebwizardry\:conjure_block.desc=Призывает спектральный блок туда, куда Вы указываете. Спектральный блок исчезает через 45 секунд, или Вы можете устранить его, снова бросив на него Заклинание.
spell.ebwizardry\:conjure_bow.desc=Создаёт спектральный лук с безграничными стрелами, которые длятся 60 секунд.
@@ -1005,7 +1005,7 @@ spell.ebwizardry\:disintegration.desc=Выстреливает мощной мо
spell.ebwizardry\:divination.desc=Направляет заклинателя к близлежащим Рудам и Ресурсам. Мощь, увеличит вероятность найти больше ценных руд.
spell.ebwizardry\:dragon_fireball.desc=Запускает огненный шар дракона в направлении, по которому Вы указываете, который выпускает сохраняющиеся Отравляющие облака при попадании.
spell.ebwizardry\:earthquake.desc=Истинный мастер земной магии, который может сдвинуть горы.
spell.ebwizardry\:empowering_presence.desc=Даёт Заклинателю и ближайшим Союзникам усиленный магический урон на 30 секунд.
spell.ebwizardry\:empowering_presence.desc=Даёт Заклинателю и ближайшим Союзникам усиленный волшебный урон на 30 секунд.
spell.ebwizardry\:enrage.desc=Причиняет близлежащих существ впадать в ярость, вместо этого, останавливая всё, что они делали напасть на Заклинателя.
spell.ebwizardry\:entrapment.desc=Заманивает цель в Сферу тьмы, которая беспомощно тянет её вверх и непрерывно повреждает её.
spell.ebwizardry\:evade.desc=Заставляет заклинателя быстро отпрыгнуть в сторону, чтобы увернуться от происходящих атак.
@@ -1014,7 +1014,7 @@ spell.ebwizardry\:fireball.desc=Выпускает огненный шар в н
spell.ebwizardry\:firebolt.desc=Выстреливает струёй огня на короткое расстояние перед Вами.
spell.ebwizardry\:firebomb.desc=Выпускает огненную бомбу в направлении, по которому Вы указываете, которая взрывается при попадании, поджигая цели.
spell.ebwizardry\:fire_resistance.desc=Даёт заклинателю огнестойкость на 30 секунд.
spell.ebwizardry\:fire_sigil.desc=Помещает магическую огненную ловушку на землю, которая повреждает и поджигает существо сдетонирующее её.
spell.ebwizardry\:fire_sigil.desc=Помещает волшебную огненную ловушку на землю, которая повреждает и поджигает существо сдетонирующее её.
spell.ebwizardry\:fireskin.desc=Покрывает заклинателя в пламя на 30 секунд, причиняет всё, что атакует его загореться.
spell.ebwizardry\:firestorm.desc="Очистите землю и очистите почву!\nДеревья должны гореть, а озера должны кипеть!\nСпалите дерево и подпалите камень!\nВсем склониться перед адским троном!"
spell.ebwizardry\:fire_breath.desc="Я, дракон."
@@ -1023,26 +1023,26 @@ spell.ebwizardry\:flame_ray.desc=Создаёт поток пламени в н
spell.ebwizardry\:flaming_axe.desc=Создаёт пылающий топор, который поджигает врагов при ударе. Длится 30 секунд.
spell.ebwizardry\:flaming_weapon.desc=Временно наполняет первое оружие в панели быстрого доступа Заклинателя энергией пламени, причиняя поджигание жертв. Магия выветрится через 45 секунд.
spell.ebwizardry\:flight.desc=Парить как Орёл.
spell.ebwizardry\:font_of_mana.desc="Мы были наполнены интенсивной магической энергией вытекающая из центра ..." - Отрывок из дневника забытого мага; оставшаяся часть страницы была сожжена.
spell.ebwizardry\:font_of_mana.desc="Мы были наполнены интенсивной волшебной энергией вытекающая из центра ..." - Отрывок из дневника забытого мага; оставшаяся часть страницы была сожжена.
spell.ebwizardry\:font_of_vitality.desc=Это потрясающее ощущение.
spell.ebwizardry\:force_arrow.desc=Выстреливает усиленной стрелой в направлении, по которому Вы указываете.
spell.ebwizardry\:forcefield.desc=Создаёт силовое поле вокруг Заклинателя, которое отталкивает существ и отражает большую часть снарядов.
spell.ebwizardry\:force_orb.desc=Запускает силовую сферу, которая повреждает и отталкивает ближайших существ при попадании.
spell.ebwizardry\:forests_curse.desc="Как Вы посмели войти в мой лес!"
spell.ebwizardry\:forest_of_thorns.desc=Посреди леса кроется скрытая поляна,\nВ поляне играет Волшебник,\nМагические искусства невыразимого порядка,\nГлубоко в лесу шипов.
spell.ebwizardry\:forest_of_thorns.desc=Посреди леса кроется скрытая поляна,\nВ поляне играет Волшебник,\nВолшебные искусства невыразимого порядка,\nГлубоко в лесу шипов.
spell.ebwizardry\:freeze.desc=Замораживает цель на 10 секунд. Также будет замораживать воду и создавать на земле снег.
spell.ebwizardry\:freezing_weapon.desc=Временно наполняет первое оружие в панели быстрого доступа Заклинателя силой мороза, причиняя замораживание жертв. Магия выветрится через 45 секунд.
spell.ebwizardry\:frost_axe.desc=Создаёт морозный топор, который замораживает врагов при ударе. Длится 30 секунд.
spell.ebwizardry\:frost_barrier.desc=Создаёт баррикаду льда впереди Заклинателя, которая ограждает их от поступающих атак. Барьер длится 20 секунд.
spell.ebwizardry\:frost_ray.desc=Создаёт поток мороза в направлении, по которому Вы указываете, который замедляет и регулярно повреждает цели.
spell.ebwizardry\:frost_sigil.desc=Помещает магическую ледяную ловушку на землю, которая повреждает и замораживает существо, сдетонирующее её.
spell.ebwizardry\:frost_sigil.desc=Помещает волшебную ледяную ловушку на землю, которая повреждает и замораживает существо, сдетонирующее её.
spell.ebwizardry\:frost_step.desc=Позволяет заклинателю замораживать воду пока он бродит, на 30 секунд.
spell.ebwizardry\:grapple.desc=Выстреливает магической лианой, которая позволяет Заклинателю захватываться в сторону блоков или сматывать существ. Отпустите лкм, чтобы освободить Блок или Существо.
spell.ebwizardry\:grapple.desc=Выстреливает волшебной лианой, которая позволяет Заклинателю захватываться в сторону блоков или сматывать существ. Отпустите лкм, чтобы освободить Блок или Существо.
spell.ebwizardry\:glide.desc=При удержании Лкм, позволяет Заклинателю скользить вниз, пока он находится в воздухе.
spell.ebwizardry\:greater_fireball.desc=Запускает большой огненный шар в направлении, по которому Вы указываете, который врывается при попадании.
spell.ebwizardry\:greater_heal.desc=Излечивает заклинателя 4-мя сердцами.
spell.ebwizardry\:greater_telekinesis.desc=Позволяет заклинателю подбирать блок или существо и удерживать его в воздухе до тех пор, пока зажата кнопка Лкм. Shift во время удержания блока или существа, выбросит его на короткое расстояние.
spell.ebwizardry\:greater_ward.desc=Даёт заклинателю мощный защитный эффект, который существенно сокращает входящий магический урон на 30 секунд.
spell.ebwizardry\:greater_ward.desc=Даёт заклинателю мощный защитный эффект, который существенно сокращает входящий волшебный урон на 30 секунд.
spell.ebwizardry\:group_heal.desc=Лечит заклинателя и всех поблизости союзников, и, призывает существо с 3-мя сердцами.
spell.ebwizardry\:growth_aura.desc=Выращивает все посевы рядом от Заклинателя. Также выращивает высокую траву и цветы на блоке травы.
spell.ebwizardry\:guardian_beam.desc=Стреляет лучами из глаз Стража в направлении, по которому Вы указываете, который повреждает цели и истощает их запас воздуха под водой.
@@ -1069,17 +1069,17 @@ spell.ebwizardry\:ironflesh.desc=Существенно улучшает соп
spell.ebwizardry\:leap.desc=Заставляет заклинателя прыгать выше на несколько блоков и слегка вперёд.
spell.ebwizardry\:levitation.desc=Поднимает заклинателя вверх, пока зажата кнопка Лкм. Также будет сводить на нет урон от падения, если оно используется до удара об землю.
spell.ebwizardry\:life_drain.desc=Создаёт поток иссушительной энергии в направлении, по которому Вы указываете, которая высасывает жизнь из цели и использует её, чтобы мало-помалу восстановить Ваше здоровье.
spell.ebwizardry\:light.desc=Создаёт магическую точку света, которая освещает окружающую область. Длится 30 секунд.
spell.ebwizardry\:light.desc=Создаёт волшебную точку света, которая освещает окружающую область. Длится 30 секунд.
spell.ebwizardry\:lightning_arrow.desc=Выстреливает молниевой стрелой в направлении, по которому Вы указываете.
spell.ebwizardry\:lightning_bolt.desc=Вызывает молнию ударить туда, куда Вы указываете.
spell.ebwizardry\:lightning_disc.desc=Направляет молниевый диск лететь в направлении, по которому Вы указываете, при этом разыскивает цели.
spell.ebwizardry\:lightning_hammer.desc="Я поражу Вас гневом небес!"
spell.ebwizardry\:lightning_pulse.desc=Заряжает землю около Заклинателя молнией, повреждает и отталкивает ближайших существ.
spell.ebwizardry\:lightning_ray.desc=Создаёт поток молнии в направлении, по которому Вы указываете, который непрерывно повреждает цели.
spell.ebwizardry\:lightning_sigil.desc=Размещает магическую молниевую ловушку на землю, которая повреждает существо, сдетонирующее её и зацепит других поблизости существ.
spell.ebwizardry\:lightning_sigil.desc=Размещает волшебную молниевую ловушку на землю, которая повреждает существо, сдетонирующее её и зацепит других поблизости существ.
spell.ebwizardry\:lightning_web.desc="Сконцентрируйтесь. Направьте шторм в свой разум сквозь Жезл и освободите свою ярость."
spell.ebwizardry\:magic_missile.desc=Стреляет молнией магической энергией в направлении, по которому Вы указываете.
spell.ebwizardry\:mark_sacrifice.desc=Помечает цель как божественную жертву. Следующая магическая атака на помеченного существа, нанесёт 60%% дополнительного урона с каждым уровнем эффекта.
spell.ebwizardry\:magic_missile.desc=Стреляет молнией волшебной энергией в направлении, по которому Вы указываете.
spell.ebwizardry\:mark_sacrifice.desc=Помечает цель как божественную жертву. Следующая волшебная атака на помеченного существа, нанесёт 60%% дополнительного урона с каждым уровнем эффекта.
spell.ebwizardry\:metamorphosis.desc=Преобразует цель в другую форму. Работает только на определённых существ.
spell.ebwizardry\:meteor.desc=Некоторые волшебники хотят увидеть, как горит мир...
spell.ebwizardry\:mind_control.desc=Берёт контроль над разумом цели на 30 секунд, заставив его поменяться местами и драться вместо Заклинателя. Не будет работать на существ, которые слишком сильны волей.
@@ -1099,12 +1099,12 @@ spell.ebwizardry\:pocket_workbench.desc=Позволяет заклинател
spell.ebwizardry\:poison.desc=Стреляет ядом в направлении, по которому Вы указываете.
spell.ebwizardry\:poison_bomb.desc=Запускает отравляющую бомбу в направлении, по которому Вы указываете, которая взрывается при попадании, а также отравляет ближайших существ.
spell.ebwizardry\:possession.desc="Стать своим врагом."
spell.ebwizardry\:radiant_totem.desc=Создаёт сияющий тотем, который выстреливает лучом света на поблизости существ, лечащий Союзников, но повреждает мобов. Длится 30 секунд. Мощь, повысит кол-во целей.
spell.ebwizardry\:radiant_totem.desc=Создаёт сияющий тотем, который выстреливает лучом света на поблизости существ, лечащий Союзников, но повреждает мобов. Длится 30 секунд. Мощь, повысит количество целей.
spell.ebwizardry\:ray_of_purification.desc=Испускает луч ослепительного света, который повреждает и слепит цели. Неживые существа получат 2-й урон и загорятся.
spell.ebwizardry\:remove_curse.desc=Снимает любое проклятие, которое на данный момент влияет на Заклинателя.
spell.ebwizardry\:replenish_hunger.desc=Восполняет уровень еды Заклинателя 3-мя очками голода.
spell.ebwizardry\:resurrection.desc=С мастером целителем рядом с Вами, быть мертвым... необязательно.
spell.ebwizardry\:reversal.desc=Снимает случайный отрицательный эффект зелья и наносит его на цель, который будет страдать от этого эффекта в течение оставшегося периода времени. Мощь, увеличивает кол-во эффектов, которые будут обращены.
spell.ebwizardry\:reversal.desc=Снимает случайный отрицательный эффект зелья и наносит его на цель, который будет страдать от этого эффекта в течение оставшегося периода времени. Мощь, увеличивает количество эффектов, которые будут обращены.
spell.ebwizardry\:ring_of_fire.desc=Создаёт кольцо огня вокруг Заклинателя, которое повреждает всех ближайших врагов и поджигает их.
spell.ebwizardry\:satiety.desc=Пополняет уровень еды Заклинателя 8-ю очками голода.
spell.ebwizardry\:shadow_ward.desc=Создаёт стену тьмы впереди Заклинателя, которая причиняет половину всего входящего урона наносимого нападающему.
@@ -1119,7 +1119,7 @@ spell.ebwizardry\:smoke_bomb.desc=Запускает дымовую бомбу
spell.ebwizardry\:snare.desc=Устанавливает ловушку на землю, которая повреждает и ненадолго замедляет существо, которое сдетонирует её.
spell.ebwizardry\:snowball.desc=Запускает снежок в направлении, по которому Вы указываете.
spell.ebwizardry\:spark_bomb.desc=Запускает шоковый заряд в направлении, по которому Вы указываете, который выпускает искры на ближайших врагов при попадании.
spell.ebwizardry\:spectral_pathway.desc=Создаёт несокрушимый магический мост впереди Вас, который расширяется на 15 блоков. Мост исчезнет через 1 минуту.
spell.ebwizardry\:spectral_pathway.desc=Создаёт несокрушимый волшебный мост впереди Вас, который расширяется на 15 блоков. Мост исчезнет через 1 минуту.
spell.ebwizardry\:speed_time.desc=...день, ночь, рассвет, сумерки, восход и закат\: таким образом, проходит время, которое охватывает нас в бесконечном цикле...
spell.ebwizardry\:spider_swarm.desc=Призывает рой ядовитых пауков сражающихся за Вас. Пауки пропадут через 30 секунд, либо если их убьют.
spell.ebwizardry\:static_aura.desc=Окружает заклинателя молнией на 30 секунд, стреляя искрами молнии во что-либо, кто ударит его.
@@ -1148,7 +1148,7 @@ spell.ebwizardry\:transportation.desc=Перемещает заклинател
spell.ebwizardry\:vanishing_box.desc=Даёт заклинателю доступ к хранилищу Сундуку края.
spell.ebwizardry\:vex_swarm.desc=Призывает рой летающих досаждателей сражающихся за Вас. Досаждатели пропадут через 30 секунд, либо если их убьют.
spell.ebwizardry\:wall_of_frost.desc=Зима в Ваших пальцах.
spell.ebwizardry\:ward.desc=Даёт заклинателю защитный эффект, который снижает входящий магический урон на 30 секунд.
spell.ebwizardry\:ward.desc=Даёт заклинателю защитный эффект, который снижает входящий волшебный урон на 30 секунд.
spell.ebwizardry\:water_breathing.desc=Позволяет заклинателю дышать под водой на 1 минуту.
spell.ebwizardry\:whirlwind.desc=Заставляет цель взлетать вверх и подальше от Вас на скорости.
spell.ebwizardry\:wither.desc=Стреляет лучом тьмы, которая иссушает всё, что прикоснётся.
@@ -1269,7 +1269,7 @@ enchantment.ebwizardry\:flaming_weapon=Наполнение огнём
enchantment.ebwizardry\:freezing_weapon=Наполнение морозом
enchantment.ebwizardry\:shocking_weapon=Наполнение молнией
enchantment.ebwizardry\:magic_protection=Магическая защита
enchantment.ebwizardry\:magic_protection=Волшебная защита
enchantment.ebwizardry\:frost_protection=Морозная защита
enchantment.ebwizardry\:shock_protection=Шоковая защита
@@ -1279,7 +1279,7 @@ enchantment.ebwizardry.flaming_weapon.desc=Часть заклинания Ог
enchantment.ebwizardry.freezing_weapon.desc=Часть заклинания Замороженного оружия; недостижимо в режиме Выживания (книга не сработает).
enchantment.ebwizardry.shocking_weapon.desc=Часть заклинания Шокирующего оружия; недостижимо в режиме Выживания (книга не сработает).
enchantment.ebwizardry.magic_protection.desc=Уменьшает весь магический урон.
enchantment.ebwizardry.magic_protection.desc=Уменьшает весь волшебный урон.
enchantment.ebwizardry.frost_protection.desc=Уменьшает урон от заморозки.
enchantment.ebwizardry.shock_protection.desc=Уменьшает урон от шока.
@@ -1336,6 +1336,8 @@ commands.ebwizardry\:discoverspell.removespell=Убрано %1$s из данны
config.ebwizardry.title.general=Параметры мода
config.ebwizardry.redundant_keys=В Вашем файле конфигурации содержатся лишние параметры, они ничего не сделают! [Подробности см. В журнале]
config.ebwizardry.generic.true=Вкл
config.ebwizardry.generic.false=Выкл
@@ -1463,9 +1465,9 @@ config.ebwizardry.bookshelf_blocks.tooltip=Список названий бло
config.ebwizardry.book_items=Книги
config.ebwizardry.book_items.tooltip=Список названий предметов в реестре, которых можно поместить в Книжную полку, в дополнение к стандартным. Названия предметов не чувствительны к регистру. Для предметов мода, префикс с ID мода (например: thaumcraft:thaumonomicon).
config.ebwizardry.bookshelf_search_radius=Радиус поиска Книжной полки
config.ebwizardry.bookshelf_search_radius.tooltip=Максимальное кол-во блоков может быть в Книжной полке из Мистического верстака или Кафедры, чтобы иметь возможность соединиться к ней.
config.ebwizardry.bookshelf_search_radius.tooltip=Максимальное количество блоков может быть в Книжной полке из Мистического верстака или Кафедры, чтобы иметь возможность соединиться к ней.
config.ebwizardry.currency_items=Предметы валюты
config.ebwizardry.currency_items.tooltip=Список названий предметов в реестре, который торгующийся Волшебник может использовать в качестве Валюты (в первом слоте; второй слот не затрагивается). Каждая запись в этом списке должна содержать название предмета в реестре, с последующим одним местом, затем целое число, определяющее 'значение' предмета. Более высокие значения означают, что требуется меньшее кол-во Валютных предметов для получения торговли.
config.ebwizardry.currency_items.tooltip=Список названий предметов в реестре, который торгующийся Волшебник может использовать в качестве Валюты (в первом слоте; второй слот не затрагивается). Каждая запись в этом списке должна содержать название предмета в реестре, с последующим одним местом, затем целое число, определяющее 'значение' предмета. Более высокие значения означают, что требуется меньшее количество Валютных предметов для получения торговли.
config.ebwizardry.category.worldgen=Настройки генерации мира
config.ebwizardry.category.worldgen.tooltip=Настройте возможности генерации мира Wizardry
@@ -1630,9 +1632,9 @@ integration.antiqueatlas.marker.ebwizardry.obelisk=Обелиск
integration.antiqueatlas.marker.ebwizardry.shrine=Святилища
integration.antiqueatlas.marker.ebwizardry.library_ruins=Разрушенная библиотека
spell.ebwizardry\:magic_missile_festive=Магическая омела
spell.ebwizardry\:magic_missile_festive=Волшебная омела
spell.ebwizardry\:summon_snow_golem_festive=Призывает замороженного Снеговика
spell.ebwizardry\:invigorating_presence_festive=Бодрое усиление
spell.ebwizardry\:empowering_presence_festive=Магическое усиление
spell.ebwizardry\:empowering_presence_festive=Волшебное усиление
wizard.debug=%1$s, %2$s, %3$s.
@@ -54,7 +54,6 @@ tile.ebwizardry\:imbuement_altar.name=注灵祭坛
item.ebwizardry\:crystal_magic.name=魔力水晶
item.ebwizardry\:crystal_magic.desc=水晶闪耀斑斓的色彩似乎在缓慢地变幻流转,暗示着其内蕴含的魔法能量。或许能以某种方法来驾驭这种魔力......
item.ebwizardry\:crystal_fire.name=赤焰水晶
item.ebwizardry\:crystal_fire.desc=发出烈火般橙色光彩的水晶。也许是揭示火焰元素奥秘的关键......
item.ebwizardry\:crystal_ice.name=寒霜水晶
@@ -201,18 +200,32 @@ item.ebwizardry\:identification_scroll.desc=识别的未知法术书或卷轴
item.ebwizardry\:identification_scroll.desc_extended=手持鉴定卷轴右击,以鉴定快捷栏中的第一个未鉴定的法术书或卷轴。
item.ebwizardry\:identification_scroll.nothing_to_identify=没有可鉴定的物品!
item.ebwizardry\:armour_upgrade.name=奥术护具升级圣印
item.ebwizardry\:armour_upgrade.desc=将任意巫师盔甲升级至%1$s传奇
item.ebwizardry\:armour_upgrade.desc_extended=在奥术工作台中将该升级圣附加到巫师盔甲上。
item.ebwizardry\:resplendent_thread.name=魔辉丝线
item.ebwizardry\:resplendent_thread.desc=将寻常巫师盔甲升级至贤者盔甲
item.ebwizardry\:resplendent_thread.desc_extended=一卷微光闪烁的丝线,用于将奥术符纹刺绣至绝品的长袍之上,以提升其附魔能力。\n\n在奥术工作台中将该升级圣附加到一件巫师盔甲上。
item.ebwizardry\:crystal_silver_plating.name=晶银镶板
item.ebwizardry\:crystal_silver_plating.desc=将寻常巫师盔甲升级至战斗法师盔甲
item.ebwizardry\:crystal_silver_plating.desc_extended=一片近乎神话般的合金,于艾尔达的锻炉中铸造而成,具有出色的魔力偏转特性。\n\n在奥术工作台中将该升级圣物附加到一件巫师盔甲上。
item.ebwizardry\:ethereal_crystalweave.name=缈晶纹绸
item.ebwizardry\:ethereal_crystalweave.desc=将寻常巫师盔甲升级至巫术士盔甲
item.ebwizardry\:ethereal_crystalweave.desc_extended=一块蕴含魔力的布匹,厚如动物的毛皮,但不知为何,放在手中时的感觉却比薄纸还要轻盈。\n\n在奥术工作台中将该升级圣物附加到一件巫师盔甲上。
item.ebwizardry\:magic_silk.name=魔法绸缎
item.ebwizardry\:spectral_dust.name=灵尘
item.ebwizardry\:wizard_armour.legendary=传奇
item.ebwizardry\:wizard_armour.buff=-%1$s %2$s 法术魔力损耗
item.ebwizardry\:wizard_armour.element_cost_reduction=-%1$s%% %2$s 魔力消耗
item.ebwizardry\:wizard_armour.cooldown_reduction=-%1$s%% 冷却时间
item.ebwizardry\:wizard_armour.enchantability=额外的附魔能力
item.ebwizardry\:wizard_armour.mana=魔力:%1$s/%2$s
item.ebwizardry\:wizard_armour.full_set=全套:
item.ebwizardry\:sage_armour.full_set_bonus=-%1$s%% 其他元素法术魔力损耗
item.ebwizardry\:battlemage_armour.full_set_bonus=魔法护盾 I 效果
item.ebwizardry\:warlock_armour.full_set_bonus=+%1$s%% 移动速度
item.ebwizardry\:wizard_hat.name=巫师帽
item.ebwizardry\:wizard_robe.name=巫师长袍
item.ebwizardry\:wizard_leggings.name=巫师护腿
@@ -253,6 +266,126 @@ item.ebwizardry\:wizard_robe_healing.name=治愈巫师长袍
item.ebwizardry\:wizard_leggings_healing.name=治愈巫师护腿
item.ebwizardry\:wizard_boots_healing.name=治愈巫师靴子
item.ebwizardry\:sage_hat.name=贤者帽
item.ebwizardry\:sage_robe.name=贤者长袍
item.ebwizardry\:sage_leggings.name=贤者护腿
item.ebwizardry\:sage_boots.name=贤者靴子
item.ebwizardry\:sage_hat_fire.name=烈焰贤者帽
item.ebwizardry\:sage_robe_fire.name=烈焰贤者长袍
item.ebwizardry\:sage_leggings_fire.name=烈焰贤者护腿
item.ebwizardry\:sage_boots_fire.name=烈焰贤者靴子
item.ebwizardry\:sage_hat_ice.name=冰霜贤者帽
item.ebwizardry\:sage_robe_ice.name=冰霜贤者长袍
item.ebwizardry\:sage_leggings_ice.name=冰霜贤者护腿
item.ebwizardry\:sage_boots_ice.name=冰霜贤者靴子
item.ebwizardry\:sage_hat_lightning.name=雷电贤者帽
item.ebwizardry\:sage_robe_lightning.name=雷电贤者长袍
item.ebwizardry\:sage_leggings_lightning.name=雷电贤者护腿
item.ebwizardry\:sage_boots_lightning.name=雷电贤者靴子
item.ebwizardry\:sage_hat_necromancy.name=死灵贤者帽
item.ebwizardry\:sage_robe_necromancy.name=死灵贤者长袍
item.ebwizardry\:sage_leggings_necromancy.name=死灵贤者护腿
item.ebwizardry\:sage_boots_necromancy.name=死灵贤者靴子
item.ebwizardry\:sage_hat_earth.name=自然贤者帽
item.ebwizardry\:sage_robe_earth.name=自然贤者长袍
item.ebwizardry\:sage_leggings_earth.name=自然贤者护腿
item.ebwizardry\:sage_boots_earth.name=自然贤者靴子
item.ebwizardry\:sage_hat_sorcery.name=秘法贤者帽
item.ebwizardry\:sage_robe_sorcery.name=秘法贤者长袍
item.ebwizardry\:sage_leggings_sorcery.name=秘法贤者护腿
item.ebwizardry\:sage_boots_sorcery.name=秘法贤者靴子
item.ebwizardry\:sage_hat_healing.name=治愈贤者帽
item.ebwizardry\:sage_robe_healing.name=治愈贤者长袍
item.ebwizardry\:sage_leggings_healing.name=治愈贤者护腿
item.ebwizardry\:sage_boots_healing.name=治愈贤者靴子
item.ebwizardry\:battlemage_helmet.name=战斗法师头盔
item.ebwizardry\:battlemage_chestplate.name=战斗法师胸甲
item.ebwizardry\:battlemage_leggings.name=战斗法师护腿
item.ebwizardry\:battlemage_boots.name=战斗法师靴子
item.ebwizardry\:battlemage_helmet_fire.name=烈焰战斗法师头盔
item.ebwizardry\:battlemage_chestplate_fire.name=烈焰战斗法师胸甲
item.ebwizardry\:battlemage_leggings_fire.name=烈焰战斗法师护腿
item.ebwizardry\:battlemage_boots_fire.name=烈焰战斗法师靴子
item.ebwizardry\:battlemage_helmet_ice.name=冰霜战斗法师头盔
item.ebwizardry\:battlemage_chestplate_ice.name=冰霜战斗法师胸甲
item.ebwizardry\:battlemage_leggings_ice.name=冰霜战斗法师护腿
item.ebwizardry\:battlemage_boots_ice.name=冰霜战斗法师靴子
item.ebwizardry\:battlemage_helmet_lightning.name=雷电战斗法师头盔
item.ebwizardry\:battlemage_chestplate_lightning.name=雷电战斗法师胸甲
item.ebwizardry\:battlemage_leggings_lightning.name=雷电战斗法师护腿
item.ebwizardry\:battlemage_boots_lightning.name=雷电战斗法师靴子
item.ebwizardry\:battlemage_helmet_necromancy.name=死灵战斗法师头盔
item.ebwizardry\:battlemage_chestplate_necromancy.name=死灵战斗法师胸甲
item.ebwizardry\:battlemage_leggings_necromancy.name=死灵战斗法师护腿
item.ebwizardry\:battlemage_boots_necromancy.name=死灵战斗法师靴子
item.ebwizardry\:battlemage_helmet_earth.name=自然战斗法师头盔
item.ebwizardry\:battlemage_chestplate_earth.name=自然战斗法师胸甲
item.ebwizardry\:battlemage_leggings_earth.name=自然战斗法师护腿
item.ebwizardry\:battlemage_boots_earth.name=自然战斗法师靴子
item.ebwizardry\:battlemage_helmet_sorcery.name=秘法战斗法师头盔
item.ebwizardry\:battlemage_chestplate_sorcery.name=秘法战斗法师胸甲
item.ebwizardry\:battlemage_leggings_sorcery.name=秘法战斗法师护腿
item.ebwizardry\:battlemage_boots_sorcery.name=秘法战斗法师靴子
item.ebwizardry\:battlemage_helmet_healing.name=治愈战斗法师头盔
item.ebwizardry\:battlemage_chestplate_healing.name=治愈战斗法师胸甲
item.ebwizardry\:battlemage_leggings_healing.name=治愈战斗法师护腿
item.ebwizardry\:battlemage_boots_healing.name=治愈战斗法师靴子
item.ebwizardry\:warlock_hood.name=巫术士兜帽
item.ebwizardry\:warlock_robe.name=巫术士长袍
item.ebwizardry\:warlock_leggings.name=巫术士护腿
item.ebwizardry\:warlock_boots.name=巫术士靴子
item.ebwizardry\:warlock_hood_fire.name=烈焰巫术士兜帽
item.ebwizardry\:warlock_robe_fire.name=烈焰巫术士长袍
item.ebwizardry\:warlock_leggings_fire.name=烈焰巫术士护腿
item.ebwizardry\:warlock_boots_fire.name=烈焰巫术士靴子
item.ebwizardry\:warlock_hood_ice.name=冰霜巫术士兜帽
item.ebwizardry\:warlock_robe_ice.name=冰霜巫术士长袍
item.ebwizardry\:warlock_leggings_ice.name=冰霜巫术士护腿
item.ebwizardry\:warlock_boots_ice.name=冰霜巫术士靴子
item.ebwizardry\:warlock_hood_lightning.name=雷电巫术士兜帽
item.ebwizardry\:warlock_robe_lightning.name=雷电巫术士长袍
item.ebwizardry\:warlock_leggings_lightning.name=雷电巫术士护腿
item.ebwizardry\:warlock_boots_lightning.name=雷电巫术士靴子
item.ebwizardry\:warlock_hood_necromancy.name=死灵巫术士兜帽
item.ebwizardry\:warlock_robe_necromancy.name=死灵巫术士长袍
item.ebwizardry\:warlock_leggings_necromancy.name=死灵巫术士护腿
item.ebwizardry\:warlock_boots_necromancy.name=死灵巫术士靴子
item.ebwizardry\:warlock_hood_earth.name=自然巫术士兜帽
item.ebwizardry\:warlock_robe_earth.name=自然巫术士长袍
item.ebwizardry\:warlock_leggings_earth.name=自然巫术士护腿
item.ebwizardry\:warlock_boots_earth.name=自然巫术士靴子
item.ebwizardry\:warlock_hood_sorcery.name=秘法巫术士兜帽
item.ebwizardry\:warlock_robe_sorcery.name=秘法巫术士长袍
item.ebwizardry\:warlock_leggings_sorcery.name=秘法巫术士护腿
item.ebwizardry\:warlock_boots_sorcery.name=秘法巫术士靴子
item.ebwizardry\:warlock_hood_healing.name=治愈巫术士兜帽
item.ebwizardry\:warlock_robe_healing.name=治愈巫术士长袍
item.ebwizardry\:warlock_leggings_healing.name=治愈巫术士护腿
item.ebwizardry\:warlock_boots_healing.name=治愈巫术士靴子
item.ebwizardry\:spawn_wizard.name=生成巫师
item.ebwizardry\:spawn_evil_wizard.name=生成邪恶巫师
@@ -409,7 +542,7 @@ item.ebwizardry\:charm_abseiling.desc=在施放藤蔓抓钩法术时潜行会减
item.ebwizardry\:charm_silk_touch.name=月石宝珠
item.ebwizardry\:charm_silk_touch.desc=使用挖掘魔法破坏的方块必定掉落其本身
item.ebwizardry\:charm_sixth_sense.name=恐狼毛皮
item.ebwizardry\:charm_sixth_sense.desc=第六感会被动、中立和敌对生物显示不同颜色
item.ebwizardry\:charm_sixth_sense.desc=第六感会以不同形状显示被动、中立和敌对生物
item.ebwizardry\:charm_stop_time.name=奇特怀表
item.ebwizardry\:charm_stop_time.desc=时间滞留魔法会让时间完全静止
item.ebwizardry\:charm_light.name=Elevinia 的永燃圣灯
@@ -712,8 +845,12 @@ advancement.ebwizardry\:craft_lectern.desc=合成一个览术台以随时掌握
advancement.ebwizardry\:armour_set=现在你是一名真正的巫师了
advancement.ebwizardry\:armour_set.desc=制作并装备全套巫师护甲
advancement.ebwizardry\:legendary=『传奇』
advancement.ebwizardry\:legendary.desc=获得一件传奇巫师护
advancement.ebwizardry\:sage=贤者之道
advancement.ebwizardry\:sage.desc=获得一件贤者盔
advancement.ebwizardry\:battlemage=战斗法师之证
advancement.ebwizardry\:battlemage.desc=获得一件战斗法师盔甲
advancement.ebwizardry\:warlock=巫术士之途
advancement.ebwizardry\:warlock.desc=获得一件巫术士盔甲
advancement.ebwizardry\:enchant_scroll=魔法卷轴!
advancement.ebwizardry\:enchant_scroll.desc=制作一个空白卷轴,并在奥术工作台上用法术书附魔
@@ -1337,6 +1474,8 @@ commands.ebwizardry\:discoverspell.removespell=将 %1$s 由 %2$s 的已发现法
config.ebwizardry.title.general=模组选项
config.ebwizardry.redundant_keys=你的配置文件含有多余选项,它们不会发挥任何作用! [查看日志以获取详情]
config.ebwizardry.generic.true=开启
config.ebwizardry.generic.false=关闭
@@ -363,6 +363,7 @@
"spell.zombie_apocalypse.start": {"category": "spells", "sounds": ["ebwizardry:dark_aura_start"]},
"spell.zombie_apocalypse.loop": {"category": "spells", "sounds": ["ebwizardry:dark_aura_loop"]},
"spell.zombie_apocalypse.end": {"category": "spells", "sounds": ["ebwizardry:dark_aura_end"]},
"spell.mirage": {"category": "spells", "sounds": ["ebwizardry:buff"]},
"forfeit.burn_self": {"category": "spells", "sounds": ["fire/ignite"]},
"forfeit.fireball": {"category": "spells", "sounds": ["mob/ghast/fireball4"]},
@@ -409,4 +410,4 @@
"forfeit.weaken_self": {"category": "spells", "sounds": ["mob/guardian/curse"]},
"forfeit.jam_self": {"category": "spells", "sounds": ["ebwizardry:effect1", "ebwizardry:effect2"]},
"forfeit.curse_self": {"category": "spells", "sounds": ["mob/guardian/curse"]}
}
}
@@ -17,7 +17,7 @@
"chargeup": 25,
"cooldown": 300,
"base_properties": {
"resistance_duration": 600,
"resistance_strength": 2
"diamondflesh_duration": 600,
"diamondflesh_strength": 0
}
}
@@ -14,11 +14,12 @@
"element": "healing",
"type": "buff",
"cost": 30,
"chargeup": 0,
"chargeup": 20,
"cooldown": 60,
"base_properties": {
"effect_radius": 5,
"effect_duration": 900,
"effect_strength": 1
"effect_strength": 0,
"potency_per_level": 0.15
}
}
@@ -17,7 +17,7 @@
"chargeup": 15,
"cooldown": 100,
"base_properties": {
"resistance_duration": 600,
"resistance_strength": 1
"ironflesh_duration": 600,
"ironflesh_strength": 0
}
}
@@ -17,7 +17,7 @@
"chargeup": 0,
"cooldown": 50,
"base_properties": {
"resistance_duration": 600,
"resistance_strength": 0
"oakflesh_duration": 600,
"oakflesh_strength": 0
}
}
@@ -20,6 +20,7 @@
"range": 10,
"damage": 4,
"effect_duration": 100,
"critical_health": 4
"critical_health": 4,
"player_effect_duration_multiplier": 0.5
}
}
@@ -18,6 +18,6 @@
"cooldown": 400,
"base_properties": {
"effect_radius": 8,
"wait_time": 300
"wait_time": 200
}
}
@@ -17,6 +17,8 @@
"chargeup": 20,
"cooldown": 400,
"base_properties": {
"minion_lifetime": 600,
"minion_count": 1,
"summon_radius": 2
}
}
@@ -70,6 +70,15 @@
"width": 90,
"height": 90
},
"classes": {
"location": "ebwizardry:textures/gui/handbook/pictures/classes.png",
"caption": "The Three Classes",
"u": 0,
"v": 0,
"width": 96,
"height": 32,
"border": false
},
"obelisk": {
"location": "ebwizardry:textures/gui/handbook/pictures/obelisk.png",
"caption": "An Obelisk",
@@ -496,7 +505,21 @@
"Those wizards who devote themselves to the practice of one element sometimes wear special garments which grant bonuses for that element. Full sets of such garments are very sought after among wizards and are not easy to find.",
"Legend speaks of an arcane seal used by the most powerful wizards to greatly improve their armour."
"Once they have mastered the fundamentals of magic, many wizards choose to follow a particular path, or class, to further their training. There are three main classes that a wizard may align themselves with: sage, battlemage and warlock. Members of each class can easily be distinguished by their robes, which are modified - usually with rare and exotic materials - to better suit their needs.",
"#image classes",
"The Sage",
"By devoting their life to the pursuit of knowledge, the sage has perfected the art of efficient spellcasting, allowing them to cast spells using the smallest possible amount of mana. The finery of their silken robes belies the substantial protection they provide, as the sage is also an adept enchanter - though they are still no match for solid metal plating. Spending such long periods in the safety of a library does, however, make them rather sluggish in combat.",
"The Battlemage",
"The battlemage is geared for combat, clad in a combination of toughened cloth and crystal-silver plating sourced from the most skilled of foundries. Through discipline and training, the battlemage has also improved their speed and reactions, allowing them to cast spells more often. This does not come cheap, however, and a battlemage must be careful not to burn through mana too quickly.",
"The Warlock",
"The warlock lives for exploration, pushing the boundaries of what is possible to unearth lost arcane secrets. This, along with a willingness to experiment with what others may deem forbidden, has allowed them to break the constraints of traditional training and cast spells at a formidable rate, as well as reducing their mana usage. Their lightweight robes, though good for exploration, provide less protection in combat than their counterparts."
]
},

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