Compare commits
286 Commits
1.12.2-dev
...
4.2.11
| Author | SHA1 | Date | |
|---|---|---|---|
| 937617d7af | |||
| 94751a6fd5 | |||
| 01ab50cb27 | |||
| d0bcbc8ed8 | |||
| b660b02e0e | |||
| 153ea74966 | |||
| c81830efec | |||
| 6ec2e716cb | |||
| 96e7c5885b | |||
| 41d575c9c9 | |||
| 7f31fc6259 | |||
| 817fd26dcf | |||
| 7237840a2a | |||
| 8ad6b5590b | |||
| 1c2c267e1a | |||
| e45bfb9248 | |||
| 0d48606b51 | |||
| 3c0b65c485 | |||
| 771118afde | |||
| 29b9e0de8b | |||
| f26f537f50 | |||
| 91c9a5392b | |||
| 6ae9df1204 | |||
| d46600ac86 | |||
| 004782a1e4 | |||
| b2b48cd8a1 | |||
| 2277f6b278 | |||
| ba59d9786f | |||
| bdf5aa5b64 | |||
| a384a57622 | |||
| 586840aa53 | |||
| 1ab674136b | |||
| 64e7e3844e | |||
| 51a3d2a63e | |||
| 7c2e786d0b | |||
| a7ee0ad847 | |||
| 033d90ed3e | |||
| 52214f81cf | |||
| 516d7948ee | |||
| a490168fa2 | |||
| 306137a026 | |||
| 0a5527f3d4 | |||
| 4dbe24c8ea | |||
| 5477725b7e | |||
| 81bba5e7e0 | |||
| 9c29142e6a | |||
| 3dc3a3a378 | |||
| 3151d7d626 | |||
| d68f968632 | |||
| 74d9198522 | |||
| 0b56d47022 | |||
| 587ab1338e | |||
| 4816c48aa6 | |||
| 2456589fa7 | |||
| d7849a94b1 | |||
| cfb9f4fe25 | |||
| a269cf339b | |||
| 1c8e4f86ee | |||
| f2835c245f | |||
| 462512ad30 | |||
| db5a7dcfde | |||
| 17bba5dea8 | |||
| fbdb5cd844 | |||
| 393fb1c1b0 | |||
| 08e89b1aef | |||
| 1f25d95b1b | |||
| 1f3a71797e | |||
| a821ef2aef | |||
| 6845279c49 | |||
| 79b745e005 | |||
| 6fff0e31d1 | |||
| 11efe56437 | |||
| 7f5786c28c | |||
| 85b49b330a | |||
| d797e72445 | |||
| 5f21b565cd | |||
| 9ed06c9a34 | |||
| 50f315666f | |||
| 62bdbc81e4 | |||
| 3a571fd239 | |||
| 4fb5452dc4 | |||
| 652f1d2620 | |||
| 275f514810 | |||
| 7cf09e76f8 | |||
| 61080134fd | |||
| 563bed3b25 | |||
| 75740c388f | |||
| 5d96f4d700 | |||
| df8fd21c0b | |||
| 046ecb1e41 | |||
| f3dd7bccd8 | |||
| d6b64b3576 | |||
| 22c00c47ff | |||
| 6d0e65c2b0 | |||
| 0a6fd452c1 | |||
| 28a8a4ff2a | |||
| 71c09cf16d | |||
| 794085660e | |||
| 3d89186308 | |||
| a0bd7b64d7 | |||
| 4c633c98ff | |||
| 45ff70c207 | |||
| 0328f41564 | |||
| 9ab4684aef | |||
| e64cf9a6af | |||
| f13f220564 | |||
| 311b5750df | |||
| e54aee332d | |||
| e4bf09f15a | |||
| aa166814ea | |||
| d37ab6072f | |||
| ba83cb7985 | |||
| 3052e56d03 | |||
| b682740751 | |||
| 38429cb697 | |||
| dc7b6790b8 | |||
| 7a247df3e1 | |||
| de2087c0e8 | |||
| f5da195605 | |||
| 6cd6411c25 | |||
| 40e77728ad | |||
| d50ff5729f | |||
| 76b4f2f72f | |||
| a608375433 | |||
| c3f8ba245d | |||
| 34b3fe93bb | |||
| 996ec9a7f7 | |||
| 2b38ca9a89 | |||
| 67788a2bd8 | |||
| 58fcaa8af2 | |||
| 24e89c8b8a | |||
| 1293b89905 | |||
| 807fc61541 | |||
| 9741c751b3 | |||
| d3003ae473 | |||
| 9fde24f341 | |||
| 452eb17b5f | |||
| 36963aac30 | |||
| f161cdfe7c | |||
| 455c5a5e07 | |||
| 9852f61d0f | |||
| a2c8cde4c4 | |||
| 497d28eafd | |||
| f3f3377c4d | |||
| 4c81c61644 | |||
| 31a6ab6db0 | |||
| 69f2aedef7 | |||
| e8818a4db5 | |||
| 470a7e82bc | |||
| 6439c233f1 | |||
| c931d42d62 | |||
| 5b497e107a | |||
| 324094f418 | |||
| 9ade6442b2 | |||
| ffea49bc40 | |||
| 2b89a890d0 | |||
| 3a67388ff3 | |||
| 3468bbb073 | |||
| 963178c609 | |||
| cfdb049368 | |||
| 058d83fd00 | |||
| c7ccc37dca | |||
| 74345d0c3b | |||
| 907b94c74f | |||
| 2c6b397be6 | |||
| eddcb2402d | |||
| 0301f3c300 | |||
| 7a8cfb73cd | |||
| c7c6f964bf | |||
| 91df7cfd72 | |||
| 0ed9ee64c4 | |||
| f82d2871d5 | |||
| 01cea3df06 | |||
| 591cfb5857 | |||
| bc2037f74e | |||
| 6aa3b21190 | |||
| b262b6edc0 | |||
| b7be05669b | |||
| 071e299d48 | |||
| 1e885d70c3 | |||
| e04a43e56d | |||
| 378796cdda | |||
| 48c37d1c17 | |||
| fe8f9fc5cd | |||
| ced6ab7e8d | |||
| 378e02eb6c | |||
| 4677d9ff30 | |||
| 0541b2171b | |||
| dc59a14e82 | |||
| 1a13afb6e3 | |||
| 03dd76c18a | |||
| 9426a96df3 | |||
| 382faf59c9 | |||
| cab68e23ac | |||
| 60a6c5124e | |||
| 028b753be6 | |||
| d020668e0c | |||
| 656a78962e | |||
| 5a2f5aa295 | |||
| 5e37a2322c | |||
| 3ca9f200fd | |||
| 37e3a842f5 | |||
| 4e8e2c951b | |||
| 43b66df22a | |||
| b192a431d7 | |||
| 3be98ab612 | |||
| ed950322ff | |||
| 4cde8c60bc | |||
| 9924e10f13 | |||
| eeb0640525 | |||
| 693c11ada0 | |||
| 038fd7225f | |||
| 999e32f37c | |||
| 8c2ac5adbb | |||
| 9c1e2e08c3 | |||
| e7f7960540 | |||
| a46bad4497 | |||
| 06d02ad45d | |||
| c39a213e62 | |||
| 2caca39a22 | |||
| 8d46191ff8 | |||
| fb7af9328d | |||
| 0991baf964 | |||
| bdefecbe9b | |||
| eef48f319a | |||
| 3a788c867c | |||
| 1ba723ade1 | |||
| c06105cd00 | |||
| 97c72685bb | |||
| 23fccaac9c | |||
| 74b6bdba0f | |||
| d69e3a253d | |||
| 744c7a2331 | |||
| c355cb034c | |||
| 5e321cc4cf | |||
| fbecce0543 | |||
| a6c24e9cb6 | |||
| 14a624db3f | |||
| 16a4c8231f | |||
| 931c99617c | |||
| 037f340a03 | |||
| b6cc417641 | |||
| 6565a0734a | |||
| 0aac70c5fb | |||
| 8551dc407b | |||
| 1eec7921ce | |||
| 18920a24c5 | |||
| e0c6f0f00f | |||
| a4f6391fac | |||
| a570bd57d0 | |||
| f1ff179b98 | |||
| 6d09acc78e | |||
| 960d97de49 | |||
| ebe64b06e3 | |||
| 99887f95e2 | |||
| 2e5a9fce3e | |||
| 2be6230977 | |||
| 518d69a2e2 | |||
| 93bc9b1b89 | |||
| 413d21d1d8 | |||
| 78fc00c0cc | |||
| a1d2d6a16e | |||
| d6492ee3f1 | |||
| 831f68d8d9 | |||
| f86ea2334d | |||
| d8f3ca2d01 | |||
| b262f711e2 | |||
| 4da63d6735 | |||
| be80d4863c | |||
| 62c696cd13 | |||
| f58dfea4bf | |||
| a924545457 | |||
| 290d420e6b | |||
| e4da941e40 | |||
| 8e95e830a3 | |||
| 7d0334fc5a | |||
| b352105dd4 | |||
| 05e6b53970 | |||
| e76dc4a873 | |||
| 4d164c15ad | |||
| 6b30c7923e | |||
| 97a23d0e39 | |||
| 44d1d4dbb7 | |||
| 22cb4d7f56 | |||
| 54abdb6746 | |||
| 414b773da6 |
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report a crash or something that isn't working as it should
|
||||
title: "[Give a brief, relevant title here]"
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
|
||||
|
||||
Minecraft version: 1.12.2 [change as necessary]
|
||||
Wizardry version: 4.2.11 [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.]
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Make a suggestion for improving the mod
|
||||
title: "[Give a brief, relevant title here]"
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
|
||||
|
||||
Minecraft versions: [if this suggestion only applies to some versions, list them here]
|
||||
|
||||
Suggestion details: [describe what you would like to see added to the mod and why]
|
||||
|
||||
Other mods involved: [if this suggestion involves integration with other mods, list them here]
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question about the mod or the code
|
||||
title: "[Give a brief, relevant title here]"
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
|
||||
|
||||
Minecraft version: 1.12.2 [change as necessary]
|
||||
Wizardry version: 4.2.11 [change as necessary]
|
||||
|
||||
Question details: [explain your question here]
|
||||
|
||||
Other mods involved: [if this question involves other mods, list them here]
|
||||
@@ -23,6 +23,7 @@ run
|
||||
logs
|
||||
/misc
|
||||
/libs
|
||||
libs_src
|
||||
libsfordeobf
|
||||
generated
|
||||
Thumbs.db
|
||||
@@ -8,8 +8,12 @@ When submitting an issue, I would be grateful if you could follow these few guid
|
||||
|
||||
- Please stick to the issue template, it's there to help you provide the right information so I can fix the problem more easily. If you're not sure what to put for anything, that's ok, just leave it as it is.
|
||||
|
||||
- One issue per issue please! Make a separate issue for each bug/suggestion. If you think multiple different issues may be related, reference between them using # followed by the issue number.
|
||||
|
||||
- Please give me as much information about the issue as you can, but keep it relevant. "This is really annoying me and my friend" does not help me fix the problem!
|
||||
|
||||
- Make sure your wizardry and Forge versions are both up-to-date for the game version you are using.
|
||||
|
||||
- There's no need to put 'tags' in square brackets in the issue title, I'll put proper github issue tags on it which will also help organise it. You can use them to search for issues too!
|
||||
|
||||
- Don't close an issue unless it has actually been fixed or is no longer relevant - otherwise I might not end up fixing it at all! Usually I'll take care of closing issues anyway, so you don't have to worry about it.
|
||||
+18
-4
@@ -1,7 +1,7 @@
|
||||
# Credits
|
||||
|
||||
Electroblob's Wizardry
|
||||
Version 4.1.4
|
||||
Version 4.2.11
|
||||
For Minecraft 1.12.2
|
||||
|
||||
Designed, coded and textured by Electroblob
|
||||
@@ -18,11 +18,25 @@ In addition, I'd like to thank the following individuals for their contributions
|
||||
- 12foo
|
||||
- Shadows-of-Fire
|
||||
- HellFirePvP
|
||||
- Tora-B
|
||||
- Avatair
|
||||
- Aeronica
|
||||
- UltraHex
|
||||
- Azim-Palmer
|
||||
- raoulvdberge
|
||||
- rafasoares
|
||||
|
||||
#### Translations
|
||||
|
||||
- Russian: VilagVil
|
||||
- Spanish and Mexican Spanish: MadWrist
|
||||
- Chinese: ZHENGLOC and dragon-evol
|
||||
- Spanish: MadWrist, Alsentar
|
||||
- Mexican Spanish: MadWrist
|
||||
- Russian: VilagVil, kellixon, bigenergy
|
||||
- French: Hahdrim
|
||||
- Brazilian Portuguese: lorrampi
|
||||
- Chinese: ZHENGLOC, dragon-evol, Hokorizero, TUsama, Determancer
|
||||
- Korean: shejery, rewi_wire
|
||||
- Polish: Trozuu
|
||||
- German: BirdyDragon
|
||||
- Taiwanese: chesterccj305
|
||||
|
||||
Lightning ray sound effect from OhhWowProductions
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
|
||||
|
||||
Minecraft version: 1.12.2 [change as necessary]
|
||||
Wizardry version: 4.1.4 [change as necessary]
|
||||
Wizardry version: 4.2.11 [change as necessary]
|
||||
Environment: Singleplayer/LAN game/Server [delete as necessary]
|
||||
|
||||
Issue details: [describe what you were doing when the issue occurred, what went wrong, what you expected to happen, etc.]
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
# License
|
||||
This repository is copyright © Electroblob 2018. The following license is provided to allow you to creatively contribute to and improve the repository.
|
||||
|
||||
This license applies only to the source code, assets and wiki pages present in this repository. The compiled mod (available at https://minecraft.curseforge.com/projects/electroblobs-wizardry) comes under its own separate license, see the aforementioned webpage for details.
|
||||
This license applies only to the source code, assets and wiki pages present in this repository. The compiled mod (available at https://minecraft.curseforge.com/projects/electroblobs-wizardry) comes under its own separate license, see the aforementioned webpage for details. By downloading, running, forking, contributing to or otherwise interacting with this repository, you agree to the license set out below.
|
||||
|
||||
TL;DR: Do what you want with this repo on Github, but ask me first if you want to put it anywhere else or publish your version. Don't try and make money off the repo or anything in it. I'm not responsible if the code breaks things, and if you help me out by submitting a PR, I can use and modify the contents of that PR as long as I give you credit. (This brief summary is non-binding and does not override or replace the full license below.)
|
||||
|
||||
@@ -27,7 +27,7 @@ TL;DR: Do what you want with this repo on Github, but ask me first if you want t
|
||||
|
||||
### 1. Warranty and usage
|
||||
|
||||
This repository, the source code for the Minecraft modification Electroblob's Wizardry ('Wizardry'), is provided in the hope that it will be useful and/or educational. You are free to download and modify this repository for personal use only. See section 2 for details regarding public sharing of this repository.
|
||||
This repository, the source code for the Minecraft modification Electroblob's Wizardry ('Wizardry'), is provided in the hope that it will be useful and/or educational. You are free to download and modify this repository for personal use. See section 2 for details regarding public sharing of this repository.
|
||||
|
||||
THIS REPOSITORY IS PROVIDED AS-IS WITH NO WARRANTIES, IMPLIED OR OTHERWISE. ELECTROBLOB TAKES NO RESPONSIBILITY FOR ANY DAMAGES INCURRED BY THE USE OR MISUSE OF THIS REPOSITORY.
|
||||
|
||||
@@ -37,7 +37,7 @@ In addition to private use as set out in section 1, you are free to fork this re
|
||||
|
||||
### 3. Distribution
|
||||
|
||||
Distribution, in whole or in part, of compiled versions of wizardry, and distribution of the source code anywhere except on Github, modified or otherwise, is forbidden without advance written permission from Electroblob. Electroblob reserves the right to refuse or withdraw such permission at any time.
|
||||
Distribution of this repository anywhere except on Github, in whole or in part, modified or otherwise, is forbidden without advance written permission from Electroblob. Electroblob reserves the right to refuse or withdraw such permission at any time.
|
||||
|
||||
### 4. Commercial use
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Wizardry [](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [](https://discord.gg/MTmMzMv)
|
||||
# Wizardry [](https://minecraft.curseforge.com/projects/electroblobs-wizardry) [](https://minecraft.curseforge.com/projects/electroblobs-wizardry/files) [](https://discord.gg/MTmMzMv)
|
||||
|
||||

|
||||

|
||||
|
||||
Source code for Electroblob's Wizardry, a Minecraft mod currently for versions 1.7.10, 1.10.2, 1.11.2, and 1.12.2. Wizardry adds an RPG-style system of magic spells to Minecraft with the aim of being as playable as possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master the arcane!
|
||||
|
||||
Please read the [guide for contributing](guide_for_contributing.md) before submitting an issue or a PR.
|
||||
Please read the [guide for contributing](CONTRIBUTING.md) before submitting an issue or a PR.
|
||||
|
||||
<b>Links</b>
|
||||
|
||||
|
||||
+8
-36
@@ -11,7 +11,7 @@ apply plugin: 'net.minecraftforge.gradle.forge'
|
||||
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
||||
|
||||
|
||||
version = "4.2.0" // There, it matches semver, happy now? (I am just gonna rename the file afterwards, you know that right?)
|
||||
version = "4.2.11" // There, it matches semver, happy now?
|
||||
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
archivesBaseName = "ElectroblobsWizardry"
|
||||
|
||||
@@ -31,15 +31,10 @@ repositories {
|
||||
name = "ModMaven"
|
||||
url = "modmaven.k-4u.nl"
|
||||
}
|
||||
flatDir {
|
||||
// evErYthINg hAS tO Be a mAVeN rEPoSiTOrY... (to use deobfProvided, for some reason)
|
||||
// The lack of documentation is actually quite impressive, see the following threads:
|
||||
// http://www.minecraftforge.net/forum/topic/44262-solved-how-to-build-mod-with-dependencies/
|
||||
// https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/mapping-and-modding-tutorials/2866817-setting-up-dependencies-in-minecraft-forge-with
|
||||
// http://www.minecraftforge.net/forum/topic/44534-adding-dependencies-to-a-forge-project/
|
||||
dirs "libsfordeobf" // Don't use libs or forge will think you have duplicate mods
|
||||
maven {
|
||||
name = "Curseforge Maven"
|
||||
url = "https://minecraft.curseforge.com/api/maven/"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
minecraft {
|
||||
@@ -56,37 +51,14 @@ minecraft {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// you may put jars on which you depend on in ./libs
|
||||
// or you may define them like so..
|
||||
//compile "some.group:artifact:version:classifier"
|
||||
//compile "some.group:artifact:version"
|
||||
|
||||
// compile against the JEI API but do not include it at runtime
|
||||
// Compile against the JEI API but do not include it at runtime
|
||||
deobfProvided "mezz.jei:jei_${mc_version}:${jei_version}:api"
|
||||
// at runtime, use the full JEI jar
|
||||
// At runtime, use the full JEI jar
|
||||
runtime "mezz.jei:jei_${mc_version}:${jei_version}"
|
||||
|
||||
//deobfProvided "baubles:baubles-1.12:1.5.2:api" // #ihavenoideawhatimdoing #itjustworks
|
||||
//runtime "baubles:baubles-1.12:1.5.2" // If in doubt, copy what already works
|
||||
|
||||
//deobfProvided "antiqueatlas:antiqueatlas-1.12.2:4.5.1:src"
|
||||
//runtime "antiqueatlas:antiqueatlas-1.12.2:4.5.1"
|
||||
|
||||
// real examples
|
||||
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
|
||||
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
|
||||
|
||||
// the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
|
||||
//provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||
|
||||
// the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided,
|
||||
// except that these dependencies get remapped to your current MCP mappings
|
||||
//deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||
//deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||
|
||||
// for more info...
|
||||
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
|
||||
// http://www.gradle.org/docs/current/userguide/dependency_management.html
|
||||
deobfCompile "baubles:Baubles:${mc_version_short}:${baubles_version}"
|
||||
deobfCompile "antique-atlas:antiqueatlas:${mc_version}:${antique_atlas_version}"
|
||||
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -2,4 +2,7 @@
|
||||
# This is required to provide enough memory for the Minecraft decompilation process.
|
||||
org.gradle.jvmargs=-Xmx3G
|
||||
mc_version=1.12.2
|
||||
jei_version=4.13.1.225
|
||||
mc_version_short=1.12
|
||||
jei_version=4.13.1.225
|
||||
baubles_version=1.5.2
|
||||
antique_atlas_version=4.6.3
|
||||
@@ -7,6 +7,7 @@ import electroblob.wizardry.spell.Spell;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
@@ -99,9 +100,9 @@ public class CommonProxy {
|
||||
return ((ItemSpectralBow)WizardryItems.spectral_bow).getDefaultDurabilityForDisplay(stack);
|
||||
}
|
||||
|
||||
/** Like {@link CommonProxy#addMultiLineDescription(List, String, Style)}, but style defaults to light grey. */
|
||||
public void addMultiLineDescription(List<String> tooltip, String key){
|
||||
this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY));
|
||||
/** Like {@link CommonProxy#addMultiLineDescription(List, String, Style, Object...)}, but style defaults to light grey. */
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Object... args){
|
||||
this.addMultiLineDescription(tooltip, key, new Style().setColor(TextFormatting.GRAY), args);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +113,7 @@ public class CommonProxy {
|
||||
* @param key The translation key for the description
|
||||
* @param style A style to apply
|
||||
*/
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Style style){}
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Style style, Object... args){}
|
||||
|
||||
// SECTION Packet Handlers
|
||||
// ===============================================================================================================
|
||||
@@ -139,8 +140,6 @@ public class CommonProxy {
|
||||
|
||||
public void handleAdvancementSyncPacket(PacketSyncAdvancements.Message message){}
|
||||
|
||||
public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){}
|
||||
|
||||
public void handleResurrectionPacket(PacketResurrection.Message message){}
|
||||
|
||||
public void handlePossessionPacket(PacketPossession.Message message){}
|
||||
@@ -238,6 +237,23 @@ public class CommonProxy {
|
||||
+ "of sound events, but the given array contained less than 3 sound events!");
|
||||
playSpellSoundLoop(world, x, y, z, spell, sounds[0], sounds[1], sounds[2], category, volume, pitch, duration);
|
||||
}
|
||||
|
||||
/** Starts the first-person blink overlay effect for the specified player. */
|
||||
public void playBlinkEffect(EntityPlayer player){}
|
||||
|
||||
/**
|
||||
* Starts the client-side screen shake effect for the specified player.
|
||||
* @param player The player whose screen is to be shaken
|
||||
* @param intensity The amplitude of the shaking (around 10 looks about right)
|
||||
*/
|
||||
public void shakeScreen(EntityPlayer player, float intensity){}
|
||||
|
||||
/**
|
||||
* Loads the given shader for the given player, if they have shaders enabled.
|
||||
* @param player The player to load the shader for
|
||||
* @param shader The location of the shader to load
|
||||
*/
|
||||
public void loadShader(EntityPlayer player, ResourceLocation shader){}
|
||||
|
||||
/**
|
||||
* Gets the client side world using Minecraft.getMinecraft().world. <b>Only to be called client side!</b> Returns
|
||||
|
||||
@@ -6,8 +6,10 @@ import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.AllyDesignationSystem.FriendlyFire;
|
||||
import electroblob.wizardry.util.MagicDamage;
|
||||
import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.text.translation.I18n;
|
||||
import net.minecraftforge.common.config.ConfigCategory;
|
||||
@@ -16,7 +18,10 @@ import net.minecraftforge.common.config.Property;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -67,6 +72,10 @@ public final class Settings {
|
||||
/** The unlocalised name of the compatibility config category. */
|
||||
public static final String COMPATIBILITY_CATEGORY = "compatibility";
|
||||
|
||||
private static final String[] DEFAULT_TREE_BLOCKS = {"dynamictrees:oakbranch", "dynamictrees:sprucebranch",
|
||||
"dynamictrees:birchbranch", "dynamictrees:junglebranch", "dynamictrees:darkoakbranch",
|
||||
"dynamictrees:acaciabranch", "dynamictrees:cactusbranch", "dynamictrees:leaves0", "dynamictrees:leaves1"};
|
||||
|
||||
private static final String[] DEFAULT_LOOT_INJECTION_LOCATIONS = {"minecraft:chests/simple_dungeon",
|
||||
"minecraft:chests/abandoned_mineshaft", "minecraft:chests/desert_pyramid", "minecraft:chests/jungle_temple",
|
||||
"minecraft:chests/stronghold_corridor", "minecraft:chests/stronghold_crossing",
|
||||
@@ -85,7 +94,7 @@ public final class Settings {
|
||||
/** <b>[Server-only]</b> List of dimension ids in which to generate wizard towers. */
|
||||
public int[] towerDimensions = {0};
|
||||
/** <b>[Server-only]</b> The rarity of wizard towers, used by the world generator. Larger numbers are rarer. */
|
||||
public int towerRarity = 600;
|
||||
public int towerRarity = 700;
|
||||
/** <b>[Server-only]</b> List of structure file locations for wizard towers without loot chests. */
|
||||
public ResourceLocation[] towerFiles = {new ResourceLocation(Wizardry.MODID, "wizard_tower_0"),
|
||||
new ResourceLocation(Wizardry.MODID, "wizard_tower_1"),
|
||||
@@ -99,7 +108,7 @@ public final class Settings {
|
||||
/** <b>[Server-only]</b> List of dimension ids in which to generate obelisks. */
|
||||
public int[] obeliskDimensions = {0, -1};
|
||||
/** <b>[Server-only]</b> The rarity of obelisks, used by the world generator. Larger numbers are rarer. */
|
||||
public int obeliskRarity = 550;
|
||||
public int obeliskRarity = 600;
|
||||
/** <b>[Server-only]</b> List of structure file locations for obelisks. */
|
||||
public ResourceLocation[] obeliskFiles = {new ResourceLocation(Wizardry.MODID, "obelisk_0"),
|
||||
new ResourceLocation(Wizardry.MODID, "obelisk_1"),
|
||||
@@ -109,7 +118,7 @@ public final class Settings {
|
||||
/** <b>[Server-only]</b> List of dimension ids in which to generate shrines. */
|
||||
public int[] shrineDimensions = {0, -1};
|
||||
/** <b>[Server-only]</b> The rarity of shrines, used by the world generator. Larger numbers are rarer. */
|
||||
public int shrineRarity = 1000;
|
||||
public int shrineRarity = 1100;
|
||||
/** <b>[Server-only]</b> List of structure file locations for shrines. */
|
||||
public ResourceLocation[] shrineFiles = {new ResourceLocation(Wizardry.MODID, "shrine_0"),
|
||||
new ResourceLocation(Wizardry.MODID, "shrine_1"),
|
||||
@@ -119,6 +128,8 @@ public final class Settings {
|
||||
new ResourceLocation(Wizardry.MODID, "shrine_5"),
|
||||
new ResourceLocation(Wizardry.MODID, "shrine_6"),
|
||||
new ResourceLocation(Wizardry.MODID, "shrine_7")};
|
||||
/** <b>[Server-only]</b> List of solid blocks (usually trees) which are ignored by the structure generators. */
|
||||
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;
|
||||
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
|
||||
@@ -157,11 +168,11 @@ public final class Settings {
|
||||
public boolean playerBlockDamage = true;
|
||||
/** <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 replace Minecraft's own fireballs with wizardry fireballs. */
|
||||
public boolean replaceVanillaFireballs = true;
|
||||
/** <b>[Server-only]</b> Whether to replace Minecraft's distance-based fall damage calculation with an equivalent,
|
||||
* velocity-based one. */
|
||||
public boolean replaceVanillaFallDamage = true;
|
||||
/** <b>[Server-only]</b> Whether using bonemeal on grass blocks has a chance to grow crystal flowers. */
|
||||
public boolean bonemealGrowsCrystalFlowers = true;
|
||||
/**
|
||||
* <b>[Server-only]</b> List of registry names of entities which summoned creatures are allowed to attack, in addition
|
||||
* to the defaults.
|
||||
@@ -181,15 +192,15 @@ public final class Settings {
|
||||
* <b>[Server-only]</b> List of registry names of items which cannot be smelted by the pocket furnace spell, in
|
||||
* addition to armour, tools and weapons.
|
||||
*/
|
||||
public ResourceLocation[] pocketFurnaceItemBlacklist = toResourceLocations("cobblestone", "netherrack");
|
||||
public Pair<ResourceLocation, Short>[] pocketFurnaceItemBlacklist = parseItemMetaStrings("cobblestone", "netherrack");
|
||||
/** <b>[Server-only]</b> List of registry names of blocks which can be detected by the divination spell. */
|
||||
public ResourceLocation[] divinationOreWhitelist = {};
|
||||
public Pair<ResourceLocation, Short>[] divinationOreWhitelist = parseItemMetaStrings(); // That works I guess
|
||||
/** <b>[Server-only]</b> List of registry names of items which count as swords for imbuement spells. */
|
||||
public ResourceLocation[] swordItemWhitelist = {};
|
||||
public Pair<ResourceLocation, Short>[] swordItemWhitelist = parseItemMetaStrings();
|
||||
/** <b>[Server-only]</b> List of registry names of items which count as bows for imbuement spells. */
|
||||
public ResourceLocation[] bowItemWhitelist = {};
|
||||
public Pair<ResourceLocation, Short>[] bowItemWhitelist = parseItemMetaStrings();
|
||||
/** <b>[Server-only]</b> Map of items to values which wizard trades may use as currency. */
|
||||
public Map<ResourceLocation, Integer> currencyItems = new HashMap<>();
|
||||
public Map<Pair<ResourceLocation, Short>, Integer> currencyItems = new HashMap<>();
|
||||
/** <b>[Server-only]</b> Global damage scaling factor for all player magic damage. */
|
||||
public double playerDamageScale = 1.0;
|
||||
/** <b>[Server-only]</b> Global damage scaling factor for all npc magic damage. */
|
||||
@@ -259,7 +270,9 @@ public final class Settings {
|
||||
* effect.
|
||||
*/
|
||||
public boolean slowTimeAffectsPlayers = true;
|
||||
/** <b>[Synchronised]</b> Chance of 'misreading' an undiscovered spell and triggering a forfeit instead. */
|
||||
/** <b>[Synchronised]</b> Whether to replace Minecraft's own fireballs with wizardry fireballs. */
|
||||
public boolean replaceVanillaFireballs = true;
|
||||
/** <b>[Synchronised]</b> Chance of 'misreading' an undiscovered spell and triggering a forfeit instead. */
|
||||
public double forfeitChance = 0.2;
|
||||
|
||||
// Client-only settings. These settings only affect client-side code and hence are not synced. Each client obeys
|
||||
@@ -287,6 +300,10 @@ public final class Settings {
|
||||
public boolean booksPauseGame = true;
|
||||
/** <b>[Client-only]</b> Whether to use custom shaders for certain spells. */
|
||||
public boolean useShaders = true;
|
||||
/** <b>[Client-only]</b> Whether to use the screen shake effect for certain spells. */
|
||||
public boolean screenShake = true;
|
||||
/** <b>[Client-only]</b> Whether to use the screen blink effect for teleportation spells. */
|
||||
public boolean blinkEffect = true;
|
||||
/** <b>[Client-only]</b> The position of the spell HUD. */
|
||||
public GuiPosition spellHUDPosition = GuiPosition.BOTTOM_LEFT;
|
||||
|
||||
@@ -358,7 +375,7 @@ public final class Settings {
|
||||
*/
|
||||
void initConfig(FMLPreInitializationEvent event){
|
||||
|
||||
config = new Configuration(event.getSuggestedConfigurationFile());
|
||||
config = new Configuration(new File(Wizardry.configDirectory, Wizardry.MODID + ".cfg"));
|
||||
config.load();
|
||||
|
||||
Wizardry.logger.info("Setting up main config");
|
||||
@@ -424,7 +441,7 @@ public final class Settings {
|
||||
|
||||
Property property;
|
||||
|
||||
for(Spell spell : Spell.getSpells(Spell.allSpells)){
|
||||
for(Spell spell : Spell.getAllSpells()){
|
||||
property = config.get(SPELLS_CATEGORY, spell.getRegistryName().toString(), true,
|
||||
I18n.translateToLocal("spell." + spell.getUnlocalisedName() + ".desc"));
|
||||
// Uses the same config key as the spell name, because - well, that's what it's called!
|
||||
@@ -535,6 +552,13 @@ public final class Settings {
|
||||
slowTimeAffectsPlayers = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "bonemealGrowsCrystalFlowers", true,
|
||||
"Whether using bonemeal on grass blocks has a chance to grow crystal flowers.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".bonemeal_grows_crystal_flowers");
|
||||
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||
bonemealGrowsCrystalFlowers = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "mobLootTableWhitelist", new String[0], "Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_whitelist");
|
||||
property.setRequiresMcRestart(true);
|
||||
@@ -636,41 +660,42 @@ public final class Settings {
|
||||
"List of registry names of blocks or items which cannot be smelted by the pocket furnace spell, in addition to armour, tools and weapons. Block/item names are not case sensitive. For mod items, prefix with the mod ID (e.g. " + Wizardry.MODID + ":crystal_ore).");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".pocket_furnace_item_blacklist");
|
||||
property.setRequiresWorldRestart(true);
|
||||
pocketFurnaceItemBlacklist = getResourceLocationList(property);
|
||||
pocketFurnaceItemBlacklist = parseItemMetaStrings(property.getStringList());
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "divinationOreWhitelist", new String[0], "List of registry names of ore blocks which can be detected by the divination spell. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. " + Wizardry.MODID + ":crystal_ore).");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".divination_ore_whitelist");
|
||||
property.setRequiresWorldRestart(true);
|
||||
divinationOreWhitelist = getResourceLocationList(property);
|
||||
divinationOreWhitelist = parseItemMetaStrings(property.getStringList());
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "swordItemWhitelist", new String[0], "List of registry names of items which should count as swords for imbuement spells. Most swords should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:broadsword).");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".sword_item_whitelist");
|
||||
property.setRequiresWorldRestart(true);
|
||||
swordItemWhitelist = getResourceLocationList(property);
|
||||
swordItemWhitelist = parseItemMetaStrings(property.getStringList());
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "bowItemWhitelist", new String[0], "List of registry names of items which should count as bows for imbuement spells. Most bows should work automatically, but those that don't can be added manually here. Item names are not case sensitive. For mod items, prefix with the mod ID (e.g. tconstruct:shortbow).");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".bow_item_whitelist");
|
||||
property.setRequiresWorldRestart(true);
|
||||
bowItemWhitelist = getResourceLocationList(property);
|
||||
bowItemWhitelist = parseItemMetaStrings(property.getStringList());
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "currencyItems", new String[]{"gold_ingot 3", "emerald 6"}, "List of registry names of items which wizard trades can use as currency (in the first slot; the second slot is unaffected). Each entry in this list should consist of an item registry name, followed by a single space, then an integer which defines the 'value' of the item. Higher values mean fewer of that currency item are required for a given trade.",
|
||||
Pattern.compile("[A-Za-z:_]+ [0-9]+"));
|
||||
Pattern.compile("[A-Za-z0-9:_]+ [0-9]+"));
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".currency_items");
|
||||
property.setRequiresWorldRestart(true);
|
||||
propOrder.add(property.getName());
|
||||
currencyItems = new HashMap<>();
|
||||
for(String string : property.getStringList()){
|
||||
string = string.toLowerCase(Locale.ROOT).trim();
|
||||
String[] args = string.split(" ");
|
||||
if(args.length != 2){
|
||||
Wizardry.logger.warn("Invalid entry in currency items: {}", string);
|
||||
continue; // Ignore invalid entries, the pattern above should ensure this never happens
|
||||
}
|
||||
try {
|
||||
currencyItems.put(new ResourceLocation(args[0]), Integer.parseInt(args[1]));
|
||||
currencyItems.put(parseItemMetaString(args[0]), Integer.parseInt(args[1]));
|
||||
}catch(NumberFormatException e){
|
||||
Wizardry.logger.warn("Invalid integer in currency items: {}", args[1]);
|
||||
}
|
||||
@@ -694,19 +719,23 @@ public final class Settings {
|
||||
fastWorldgen = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate.");
|
||||
property = config.get(WORLDGEN_CATEGORY, "towerDimensions", new int[]{0}, "List of dimension ids in which wizard towers will generate. Remove all dimensions to disable wizard towers completely.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".tower_dimensions");
|
||||
property.setRequiresWorldRestart(true);
|
||||
towerDimensions = property.getIntList();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "towerRarity", 600, "Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.", 20, 5000);
|
||||
property = config.get(WORLDGEN_CATEGORY, "towerRarity", 900, "Rarity of wizard towers. 1 in this many chunks will contain a wizard tower, meaning higher numbers are rarer.", 20, 5000);
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".tower_rarity");
|
||||
property.setRequiresWorldRestart(true);
|
||||
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||
towerRarity = property.getInt();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
// A bit of backwards-compatibility: predictably, people don't read my instructions and update without deleting
|
||||
// the config, resulting in wizard towers generating everywhere - so let's update it for them!
|
||||
if(towerRarity < 20) towerRarity = 600; // The old default was 8, which is outside the new allowed range
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "evilWizardChance", 0.2, "The chance for wizard towers to generate with an evil wizard and chest inside, instead of a friendly wizard.", 0, 1);
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".evil_wizard_chance");
|
||||
property.setRequiresWorldRestart(true);
|
||||
@@ -715,26 +744,26 @@ public final class Settings {
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "towerFiles", new String[]{Wizardry.MODID + ":wizard_tower_0", Wizardry.MODID + ":wizard_tower_1", Wizardry.MODID + ":wizard_tower_2", Wizardry.MODID + ":wizard_tower_3"},
|
||||
"List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
|
||||
"List of structure file locations for wizard towers without loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".tower_files");
|
||||
property.setRequiresWorldRestart(true);
|
||||
towerFiles = getResourceLocationList(property);
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "towerWithChestFiles", new String[]{Wizardry.MODID + ":wizard_tower_chest_0", Wizardry.MODID + ":wizard_tower_chest_1", Wizardry.MODID + ":wizard_tower_chest_2", Wizardry.MODID + ":wizard_tower_chest_3"},
|
||||
"List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
|
||||
"List of structure file locations for wizard towers with loot chests. One of these files will be randomly selected each time a wizard tower is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable wizard towers, use the tower dimensions setting.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".tower_with_chest_files");
|
||||
property.setRequiresWorldRestart(true);
|
||||
towerWithChestFiles = getResourceLocationList(property);
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "obeliskDimensions", new int[]{0, -1}, "List of dimension ids in which obelisks will generate.");
|
||||
property = config.get(WORLDGEN_CATEGORY, "obeliskDimensions", new int[]{0, -1}, "List of dimension ids in which obelisks will generate. Remove all dimensions to disable obelisks completely.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_dimensions");
|
||||
property.setRequiresWorldRestart(true);
|
||||
obeliskDimensions = property.getIntList();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "obeliskRarity", 550, "Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.", 20, 5000);
|
||||
property = config.get(WORLDGEN_CATEGORY, "obeliskRarity", 800, "Rarity of obelisks. 1 in this many chunks will contain an obelisk, meaning higher numbers are rarer.", 20, 5000);
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_rarity");
|
||||
property.setRequiresWorldRestart(true);
|
||||
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||
@@ -742,19 +771,19 @@ public final class Settings {
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "obeliskFiles", new String[]{Wizardry.MODID + ":obelisk_0", Wizardry.MODID + ":obelisk_1", Wizardry.MODID + ":obelisk_2", Wizardry.MODID + ":obelisk_3", Wizardry.MODID + ":obelisk_4"},
|
||||
"List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
|
||||
"List of structure file locations for obelisks. One of these files will be randomly selected each time an obelisk is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable obelisks, use the obelisk dimensions setting.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".obelisk_files");
|
||||
property.setRequiresWorldRestart(true);
|
||||
obeliskFiles = getResourceLocationList(property);
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "shrineDimensions", new int[]{0, -1}, "List of dimension ids in which shrines will generate.");
|
||||
property = config.get(WORLDGEN_CATEGORY, "shrineDimensions", new int[]{0, -1}, "List of dimension ids in which shrines will generate. Remove all dimensions to disable shrines completely.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_dimensions");
|
||||
property.setRequiresWorldRestart(true);
|
||||
shrineDimensions = property.getIntList();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "shrineRarity", 1000, "Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.", 20, 5000);
|
||||
property = config.get(WORLDGEN_CATEGORY, "shrineRarity", 1500, "Rarity of shrines. 1 in this many chunks will contain a shrine, meaning higher numbers are rarer.", 20, 5000);
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_rarity");
|
||||
property.setRequiresWorldRestart(true);
|
||||
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||
@@ -762,12 +791,18 @@ public final class Settings {
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "shrineFiles", new String[]{Wizardry.MODID + ":shrine_0", Wizardry.MODID + ":shrine_1", Wizardry.MODID + ":shrine_2", Wizardry.MODID + ":shrine_3", Wizardry.MODID + ":shrine_4", Wizardry.MODID + ":shrine_5", Wizardry.MODID + ":shrine_6", Wizardry.MODID + ":shrine_7"},
|
||||
"List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves.");
|
||||
"List of structure file locations for shrines. One of these files will be randomly selected each time a shrine is generated. File locations are of the format [mod id]:[filename], which refers to the file assets/[mod id]/structures/[filename].nbt. Duplicate entries are permitted, allowing for simple weighting without duplicating the structure files themselves. This list should not be empty; to disable shrines, use the shrine dimensions setting.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_files");
|
||||
property.setRequiresWorldRestart(true);
|
||||
shrineFiles = getResourceLocationList(property);
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "treeBlocks", DEFAULT_TREE_BLOCKS, "List of registry names of blocks which can be overwritten by wizardry's structure generators, affecting both fast and fancy structure generation. Most tree blocks and other foliage should work automatically, but those that don't can be added manually here. Block names are not case sensitive. For mod blocks, prefix with the mod ID (e.g. dynamictrees:oakbranch).");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".tree_blocks");
|
||||
property.setRequiresWorldRestart(true);
|
||||
treeBlocks = parseItemMetaStrings(property.getStringList());
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(WORLDGEN_CATEGORY, "oreDimensions", new int[]{0}, "List of dimension ids in which crystal ore will generate. Note that removing the overworld (id 0) from this list will make the mod VERY difficult to play!");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".ore_dimensions");
|
||||
property.setRequiresWorldRestart(true);
|
||||
@@ -847,6 +882,18 @@ public final class Settings {
|
||||
useShaders = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(CLIENT_CATEGORY, "screenShake", true, "Whether to use the screen shake effect for certain spells.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".screen_shake");
|
||||
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||
screenShake = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(CLIENT_CATEGORY, "blinkEffect", true, "Whether to use the screen blink effect for teleportation spells.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".blink_effect");
|
||||
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||
blinkEffect = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
config.setCategoryPropertyOrder(CLIENT_CATEGORY, propOrder);
|
||||
}
|
||||
|
||||
@@ -1056,4 +1103,45 @@ public final class Settings {
|
||||
public static ResourceLocation[] toResourceLocations(String... strings){
|
||||
return Arrays.stream(strings).map(s -> new ResourceLocation(s.toLowerCase(Locale.ROOT).trim())).toArray(ResourceLocation[]::new);
|
||||
}
|
||||
|
||||
/** Applies {@link Settings#parseItemMetaString(String)} to each input string and returns and array of the resulting
|
||||
* {@link Pair}s. */
|
||||
@SuppressWarnings("unchecked") // Shut up java
|
||||
public static Pair<ResourceLocation, Short>[] parseItemMetaStrings(String... strings){
|
||||
return Arrays.stream(strings).map(Settings::parseItemMetaString).toArray(Pair[]::new);
|
||||
}
|
||||
|
||||
/** Parses the given input string as an item of the form {@code id:metadata} and returns the resulting
|
||||
* {@link ResourceLocation} ID and metadata value as a {@link Pair} object. */
|
||||
public static Pair<ResourceLocation, Short> parseItemMetaString(String string){
|
||||
|
||||
string = string.toLowerCase(Locale.ROOT).trim();
|
||||
|
||||
String[] itemArgs = string.split(":");
|
||||
String item;
|
||||
short meta;
|
||||
|
||||
try {
|
||||
meta = Short.parseShort(itemArgs[itemArgs.length-1]);
|
||||
item = String.join(":", Arrays.copyOfRange(itemArgs, 0, itemArgs.length-1));
|
||||
}catch(NumberFormatException e){ // If no metadata is specified
|
||||
meta = OreDictionary.WILDCARD_VALUE;
|
||||
item = string;
|
||||
}
|
||||
|
||||
return Pair.of(new ResourceLocation(item), meta);
|
||||
}
|
||||
|
||||
public static boolean containsMetaBlock(Pair<ResourceLocation, Short>[] array, IBlockState block){
|
||||
return containsMetaThing(array, block.getBlock().getRegistryName(), (short)block.getBlock().getMetaFromState(block));
|
||||
}
|
||||
|
||||
public static boolean containsMetaItem(Pair<ResourceLocation, Short>[] array, ItemStack stack){
|
||||
return containsMetaThing(array, stack.getItem().getRegistryName(), (short)stack.getMetadata());
|
||||
}
|
||||
|
||||
public static boolean containsMetaThing(Pair<ResourceLocation, Short>[] array, ResourceLocation id, short metadata){
|
||||
return Arrays.asList(array).contains(Pair.of(id, metadata)) || Arrays.asList(array).contains(Pair.of(id, (short)OreDictionary.WILDCARD_VALUE));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ import electroblob.wizardry.misc.Forfeit;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.*;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.CustomSoundCategory;
|
||||
import electroblob.wizardry.util.SpellProperties;
|
||||
import electroblob.wizardry.worldgen.*;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
@@ -31,6 +31,9 @@ import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* <i>"Electroblob's Wizardry adds an RPG-like system of spells to Minecraft, with the aim of being as playable as
|
||||
* possible. No crazy constructs, no perk trees, no complex recipes - simply find spell books, cast spells, and master
|
||||
@@ -41,7 +44,10 @@ import org.apache.logging.log4j.Logger;
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.0
|
||||
*/
|
||||
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, guiFactory = "electroblob.wizardry.WizardryGuiFactory")
|
||||
|
||||
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, acceptedMinecraftVersions = "[1.12.2]",
|
||||
guiFactory = "electroblob.wizardry.WizardryGuiFactory", dependencies = "required-after:forge@[14.23.5.2814,);after:antiqueatlas@[4.6,)")
|
||||
|
||||
public class Wizardry {
|
||||
|
||||
/** Wizardry's mod ID. */
|
||||
@@ -51,14 +57,14 @@ public class Wizardry {
|
||||
/**
|
||||
* The version number for this version of wizardry. The following system is used for version numbers:
|
||||
* <p></p>
|
||||
* <center><b>[major Minecraft version].[major mod version].[minor mod version/patch]
|
||||
* <center><b>[major Minecraft version].[major mod version].[minor mod version/patch]</b>
|
||||
* <p></p>
|
||||
* </center></b> The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same
|
||||
* </center> The major mod version is consistent across Minecraft versions, i.e. Wizardry 1.1 has the same
|
||||
* features as Wizardry 2.1, but they are for different versions of Minecraft and have separate minor versioning.
|
||||
* 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft
|
||||
* 1.11.x versions, and so on.
|
||||
*/
|
||||
public static final String VERSION = "4.2.0";
|
||||
public static final String VERSION = "4.2.11";
|
||||
|
||||
// IDEA: Triggering of inbuilt Forge events in relevant places?
|
||||
// IDEA: Abstract the vanilla particles behind the particle builder
|
||||
@@ -66,9 +72,6 @@ public class Wizardry {
|
||||
// TODO: Have particles obey Minecraft's particle setting where appropriate
|
||||
// (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java)
|
||||
// TODO: TileEntityArcaneWorkbench needs looking at, esp. regarding inventory and markDirty
|
||||
// TODO: See what can be done with the illager spell sounds (and go over sounds in general)
|
||||
// TODO: Fix possession
|
||||
// TODO: Fix charge
|
||||
|
||||
/** Static instance of the {@link Settings} object for Wizardry. */
|
||||
public static final Settings settings = new Settings();
|
||||
@@ -82,6 +85,12 @@ public class Wizardry {
|
||||
* - <b>INFO</b>: Anything that might happen during normal mod operation that the user needs to know about. */
|
||||
public static Logger logger;
|
||||
|
||||
/** A {@link File} object representing wizardry's config folder, {@code config/ebwizardry}). As of wizardry 4.2.4,
|
||||
* this folder contains the main config file and the global spell properties folder, if used. */
|
||||
public static File configDirectory;
|
||||
|
||||
public static boolean tisTheSeason;
|
||||
|
||||
// The instance of wizardry that Forge uses.
|
||||
@Instance(Wizardry.MODID)
|
||||
public static Wizardry instance;
|
||||
@@ -97,8 +106,13 @@ public class Wizardry {
|
||||
|
||||
proxy.registerResourceReloadListeners();
|
||||
|
||||
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
|
||||
settings.initConfig(event);
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
tisTheSeason = calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DAY_OF_MONTH) >= 24
|
||||
&& calendar.get(Calendar.DAY_OF_MONTH) <= 26;
|
||||
|
||||
// Capabilities
|
||||
WizardData.register();
|
||||
DispenserCastingData.register();
|
||||
@@ -113,6 +127,9 @@ public class Wizardry {
|
||||
proxy.registerRenderers();
|
||||
proxy.registerKeyBindings();
|
||||
|
||||
// Commented out for 4.2.3 to get rid of the sound bug, reinstate once a fix is found.
|
||||
WizardrySounds.SPELLS = SoundCategory.PLAYERS;//CustomSoundCategory.add(Wizardry.MODID + "_spells");
|
||||
|
||||
WizardryBaublesIntegration.init();
|
||||
WizardryAntiqueAtlasIntegration.init();
|
||||
|
||||
@@ -151,8 +168,6 @@ public class Wizardry {
|
||||
proxy.initGuiBits();
|
||||
proxy.registerParticles();
|
||||
proxy.registerSoundEventListener();
|
||||
|
||||
WizardrySounds.SPELLS = CustomSoundCategory.add(Wizardry.MODID + ":spells");
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
||||
@@ -33,6 +33,9 @@ import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.storage.loot.LootContext;
|
||||
import net.minecraft.world.storage.loot.LootTable;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.event.entity.PlaySoundAtEntityEvent;
|
||||
@@ -46,6 +49,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* General-purpose event handler for things that don't fit anywhere else or groups of related behaviours that are better
|
||||
@@ -81,7 +85,7 @@ public final class WizardryEventHandler {
|
||||
}
|
||||
Spell.syncProperties(event.player);
|
||||
}
|
||||
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void onPlaySoundAtEntityEvent(PlaySoundAtEntityEvent event){
|
||||
// Muffle (there's no spell class for it so it's here instead)
|
||||
@@ -286,7 +290,7 @@ public final class WizardryEventHandler {
|
||||
EntityLivingBase attacker = (EntityLivingBase)event.getSource().getTrueSource();
|
||||
|
||||
// Players can only ever attack with their main hand, so this is the right method to use here.
|
||||
if(!attacker.getHeldItemMainhand().isEmpty() && ImbueWeapon.isSword(attacker.getHeldItemMainhand().getItem())){
|
||||
if(!attacker.getHeldItemMainhand().isEmpty() && ImbueWeapon.isSword(attacker.getHeldItemMainhand())){
|
||||
|
||||
int level = EnchantmentHelper.getEnchantmentLevel(WizardryEnchantments.flaming_weapon,
|
||||
attacker.getHeldItemMainhand());
|
||||
@@ -343,18 +347,21 @@ public final class WizardryEventHandler {
|
||||
|
||||
Spell spell = ((ISpellCaster)event.getEntity()).getContinuousSpell();
|
||||
SpellModifiers modifiers = ((ISpellCaster)event.getEntity()).getModifiers();
|
||||
int count = ((ISpellCaster)event.getEntity()).getSpellCounter();
|
||||
|
||||
if(spell != null && spell != Spells.none){ // IntelliJ is wrong, do NOT remove the null check!
|
||||
|
||||
if(!MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(SpellCastEvent.Source.NPC, spell, event.getEntityLiving(),
|
||||
modifiers, 0))){
|
||||
modifiers, count))){
|
||||
|
||||
spell.cast(event.getEntity().world, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, 0,
|
||||
spell.cast(event.getEntity().world, (EntityLiving)event.getEntity(), EnumHand.MAIN_HAND, count,
|
||||
// TODO: This implementation of modifiers relies on them being accessible client-side.
|
||||
// Right now that doesn't matter because NPCs don't use modifiers, but they might in future
|
||||
((EntityLiving)event.getEntity()).getAttackTarget(), modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
((ISpellCaster)event.getEntity()).setSpellCounter(count + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,6 +373,22 @@ public final class WizardryEventHandler {
|
||||
|
||||
EntityPlayer player = (EntityPlayer)event.getSource().getTrueSource();
|
||||
|
||||
// Compatibility with "Lycanites Mobs" -it uses custom loot drop logic which can't be hooked, given the
|
||||
// number of mobs that spawn as Lycanites when this mod is active it would massively nerf the wizard drops
|
||||
// if we didn't handle this
|
||||
if(event.getEntity().getClass().getCanonicalName().contains("lycanitesmobs"))
|
||||
{
|
||||
WorldServer world = (WorldServer)event.getEntity().getEntityWorld();
|
||||
LootTable table = world.getLootTableManager().getLootTableFromLocation(new ResourceLocation(Wizardry.MODID, "entities/mob_additions"));
|
||||
|
||||
LootContext ctx = new LootContext.Builder(world).withPlayer(player).build();
|
||||
List<ItemStack> stacks = table.generateLootForPools(world.rand, ctx);
|
||||
|
||||
for(ItemStack stack : stacks) {
|
||||
event.getEntity().entityDropItem(stack, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
for(ItemStack stack : WizardryUtilities.getPrioritisedHotbarAndOffhand(player)){
|
||||
|
||||
if(stack.getItem() instanceof IManaStoringItem && !((IManaStoringItem)stack.getItem()).isManaFull(stack)
|
||||
@@ -397,7 +420,7 @@ public final class WizardryEventHandler {
|
||||
@SubscribeEvent // Priority doesn't matter here, we're only setting event fields so if it's cancelled it won't matter
|
||||
public static void onLivingFallEvent(LivingFallEvent event){
|
||||
// Why is fall damage based on distance fallen? Why? Who on earth came up with that? It makes no sense whatsoever!
|
||||
if(Wizardry.settings.replaceVanillaFallDamage && !Loader.isModLoaded("speedbasedfalldamage")){
|
||||
if(!event.getEntity().world.isRemote && Wizardry.settings.replaceVanillaFallDamage && !Loader.isModLoaded("speedbasedfalldamage")){
|
||||
// We want to keep the fall damage EXACTLY THE SAME for free, uninterrupted falls, but fix the weirdness
|
||||
// caused when something else changes the entity's velocity
|
||||
// All living entities have a gravity of 0.08b/t^2
|
||||
@@ -444,7 +467,8 @@ public final class WizardryEventHandler {
|
||||
// Wizardry.logger.info("Replaced fall distance {} with effective distance {} based on entity velocity", event.getDistance(), y);
|
||||
// }
|
||||
|
||||
event.setDistance((float)y);
|
||||
// Don't let it increase fall damage beyond vanilla values
|
||||
if(y < event.getDistance()) event.setDistance((float)y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package electroblob.wizardry;
|
||||
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.item.ItemWizardHandbook;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
|
||||
import electroblob.wizardry.tileentity.ContainerPortableWorkbench;
|
||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||
@@ -48,9 +47,9 @@ public class WizardryGuiHandler implements IGuiHandler {
|
||||
return new electroblob.wizardry.client.gui.handbook.GuiWizardHandbook();
|
||||
}else if(id == SPELL_BOOK){
|
||||
if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){
|
||||
return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemMainhand().getItemDamage()));
|
||||
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemMainhand());
|
||||
}else if(player.getHeldItemOffhand().getItem() instanceof ItemSpellBook){
|
||||
return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.byMetadata(player.getHeldItemOffhand().getItemDamage()));
|
||||
return new electroblob.wizardry.client.gui.GuiSpellBook(player.getHeldItemOffhand());
|
||||
}
|
||||
}else if(id == PORTABLE_CRAFTING){
|
||||
return new electroblob.wizardry.client.gui.GuiPortableCrafting(player.inventory, world, new BlockPos(x, y, z));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
@@ -56,7 +57,7 @@ public class BlockCrystalFlower extends BlockBush {
|
||||
@SubscribeEvent
|
||||
public static void onBonemealEvent(BonemealEvent event){
|
||||
// Grows crystal flowers when bonemeal is used on grass
|
||||
if(event.getBlock().getBlock() == Blocks.GRASS){
|
||||
if(Wizardry.settings.bonemealGrowsCrystalFlowers && event.getBlock().getBlock() == Blocks.GRASS){
|
||||
|
||||
BlockPos pos = event.getPos().add(event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8),
|
||||
event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4),
|
||||
|
||||
@@ -107,7 +107,9 @@ public class BlockPedestal extends Block implements ITileEntityProvider {
|
||||
natural = true;
|
||||
metadata -= ELEMENT.getAllowedValues().size();
|
||||
}
|
||||
return this.getDefaultState().withProperty(ELEMENT, Element.values()[metadata]).withProperty(NATURAL, natural);
|
||||
Element element = Element.values()[metadata];
|
||||
if(!ELEMENT.getAllowedValues().contains(element)) return this.getDefaultState().withProperty(NATURAL, natural);
|
||||
return this.getDefaultState().withProperty(ELEMENT, element).withProperty(NATURAL, natural);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -69,7 +69,9 @@ public class BlockRunestone extends Block {
|
||||
|
||||
@Override
|
||||
public IBlockState getStateFromMeta(int metadata){
|
||||
return this.getDefaultState().withProperty(ELEMENT, Element.values()[metadata]);
|
||||
Element element = Element.values()[metadata];
|
||||
if(!ELEMENT.getAllowedValues().contains(element)) return this.getDefaultState();
|
||||
return this.getDefaultState().withProperty(ELEMENT, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,7 @@ import net.minecraft.item.Item;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumBlockRenderType;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
@@ -54,21 +55,24 @@ public class BlockSnare extends Block implements ITileEntityProvider {
|
||||
@Override
|
||||
public void onEntityCollision(World world, BlockPos pos, IBlockState state, Entity entity){
|
||||
|
||||
if(!world.isRemote && entity instanceof EntityLivingBase){
|
||||
if(entity instanceof EntityLivingBase){
|
||||
|
||||
if(world.getTileEntity(pos) instanceof TileEntityPlayerSave){
|
||||
|
||||
TileEntityPlayerSave tileentity = (TileEntityPlayerSave)world.getTileEntity(pos);
|
||||
|
||||
if(AllyDesignationSystem.isValidTarget(tileentity.getCaster(), entity)){
|
||||
|
||||
entity.attackEntityFrom(MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC),
|
||||
Spells.snare.getProperty(Spell.DAMAGE).floatValue());
|
||||
DamageSource source = tileentity.getCaster() == null ? DamageSource.CACTUS
|
||||
: MagicDamage.causeDirectMagicDamage(tileentity.getCaster(), DamageType.MAGIC);
|
||||
|
||||
entity.attackEntityFrom(source, Spells.snare.getProperty(Spell.DAMAGE).floatValue());
|
||||
|
||||
((EntityLivingBase)entity).addPotionEffect(new PotionEffect(MobEffects.SLOWNESS,
|
||||
Spells.snare.getProperty(Spell.EFFECT_DURATION).intValue(),
|
||||
Spells.snare.getProperty(Spell.EFFECT_STRENGTH).intValue()));
|
||||
|
||||
world.destroyBlock(pos, false);
|
||||
if(!world.isRemote) world.destroyBlock(pos, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.BlockRenderLayer;
|
||||
import net.minecraft.util.EnumBlockRenderType;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
@@ -34,26 +33,16 @@ public class BlockSpectral extends Block implements ITileEntityProvider {
|
||||
|
||||
// Replaces getRenderBlockPass
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public BlockRenderLayer getRenderLayer(){
|
||||
return BlockRenderLayer.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumBlockRenderType getRenderType(IBlockState state){
|
||||
return EnumBlockRenderType.MODEL;
|
||||
}
|
||||
|
||||
// Apparently it's OK to override this, despite it being deprecated. More importantly, it being deprecated is not
|
||||
// Forge's doing, rather it is Mojang themselves misusing the @Deprecated annotation to mean 'internal, don't call'.
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return false;
|
||||
}
|
||||
// See BlockTransportationStone for what all these do
|
||||
@Override public boolean isFullCube(IBlockState state){ return false; }
|
||||
@Override public boolean isBlockNormalCube(IBlockState state){ return false; }
|
||||
@Override public boolean isNormalCube(IBlockState state){ return false; }
|
||||
@Override public boolean isOpaqueCube(IBlockState state){ return false; }
|
||||
|
||||
@Override
|
||||
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random random){
|
||||
@@ -67,12 +56,12 @@ public class BlockSpectral extends Block implements ITileEntityProvider {
|
||||
}
|
||||
}
|
||||
|
||||
// Overriden to make the block always look full brightness despite not emitting
|
||||
// full light.
|
||||
@Override
|
||||
public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos){
|
||||
return 15;
|
||||
}
|
||||
// // Overriden to make the block always look full brightness despite not emitting
|
||||
// // full light.
|
||||
// @Override
|
||||
// public int getPackedLightmapCoords(IBlockState state, IBlockAccess source, BlockPos pos){
|
||||
// return 15;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean hasTileEntity(IBlockState state){
|
||||
|
||||
@@ -137,9 +137,11 @@ public class BlockThorns extends BlockBush implements ITileEntityProvider {
|
||||
TileEntity tileentity = world.getTileEntity(pos);
|
||||
|
||||
if(tileentity instanceof TileEntityPlayerSaveTimed){
|
||||
if(AllyDesignationSystem.isValidTarget(((TileEntityPlayerSaveTimed)tileentity).getCaster(), target)){
|
||||
source = MagicDamage.causeDirectMagicDamage(((TileEntityPlayerSaveTimed)tileentity).getCaster(),
|
||||
MagicDamage.DamageType.MAGIC);
|
||||
|
||||
EntityLivingBase caster = ((TileEntityPlayerSaveTimed)tileentity).getCaster();
|
||||
|
||||
if(caster != null && AllyDesignationSystem.isValidTarget(caster, target)){
|
||||
source = MagicDamage.causeDirectMagicDamage(caster, MagicDamage.DamageType.MAGIC);
|
||||
}else{
|
||||
return false; // Don't attack or slow allies of the caster
|
||||
}
|
||||
|
||||
@@ -62,18 +62,12 @@ public class BlockTransportationStone extends Block {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Forge version of the above method. I still need to override both though because vanilla uses the other one.
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return false;
|
||||
}
|
||||
|
||||
// ... and this one is for rendering.
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isSideSolid(IBlockState base_state, IBlockAccess world, BlockPos pos, EnumFacing side){
|
||||
return side == EnumFacing.DOWN;
|
||||
@@ -147,7 +141,8 @@ public class BlockTransportationStone extends Block {
|
||||
if(locations.isEmpty()) locations.add(here);
|
||||
else{
|
||||
locations.remove(here); // Prevents duplicates
|
||||
locations.set(locations.size() - 1, here);
|
||||
if(locations.isEmpty()) locations.add(here);
|
||||
else locations.set(Math.max(locations.size() - 1, 0), here);
|
||||
}
|
||||
if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("tile." + Wizardry.MODID + ":transportation_stone.confirm", Spells.transportation.getNameForTranslationFormatted()), true);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import electroblob.wizardry.item.ItemScroll;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.packet.*;
|
||||
import electroblob.wizardry.potion.PotionSlowTime;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.*;
|
||||
@@ -107,7 +106,7 @@ public class ClientProxy extends CommonProxy {
|
||||
// Armour Model
|
||||
public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f);
|
||||
|
||||
/** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style)}). */
|
||||
/** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style, Object...)}). */
|
||||
private static final int TOOLTIP_WRAP_WIDTH = 140;
|
||||
|
||||
// SECTION Registry
|
||||
@@ -190,6 +189,23 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playBlinkEffect(EntityPlayer player){
|
||||
if(Minecraft.getMinecraft().player == player) WizardryClientEventHandler.playBlinkEffect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shakeScreen(EntityPlayer player, float intensity){
|
||||
if(Minecraft.getMinecraft().player == player) WizardryClientEventHandler.shakeScreen(intensity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadShader(EntityPlayer player, ResourceLocation shader){
|
||||
if(Minecraft.getMinecraft().player == player && Wizardry.settings.useShaders
|
||||
&& !Minecraft.getMinecraft().entityRenderer.isShaderActive())
|
||||
Minecraft.getMinecraft().entityRenderer.loadShader(shader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSpellHUDSkins(){
|
||||
return GuiSpellDisplay.getSkinKeys();
|
||||
@@ -282,8 +298,8 @@ public class ClientProxy extends CommonProxy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Style style){
|
||||
String description = style.getFormattingCode() + I18n.format(key);
|
||||
public void addMultiLineDescription(List<String> tooltip, String key, Style style, Object... args){
|
||||
String description = style.getFormattingCode() + I18n.format(key, args);
|
||||
tooltip.addAll(Minecraft.getMinecraft().fontRenderer.listFormattedStringToWidth(description, TOOLTIP_WRAP_WIDTH));
|
||||
}
|
||||
|
||||
@@ -425,14 +441,16 @@ public class ClientProxy extends CommonProxy {
|
||||
// Again, no need to check if the spell succeeded, because the packet is only ever sent when it
|
||||
// succeeds.
|
||||
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.NPC, spell, (EntityLiving)caster, message.modifiers));
|
||||
}
|
||||
|
||||
if(caster instanceof ISpellCaster){
|
||||
if(spell.isContinuous || spell instanceof None){
|
||||
((ISpellCaster)caster).setContinuousSpell(spell);
|
||||
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
|
||||
if(caster instanceof ISpellCaster){
|
||||
if(spell.isContinuous || spell instanceof None){
|
||||
((ISpellCaster)caster).setContinuousSpell(spell);
|
||||
((ISpellCaster)caster).setSpellCounter(spell instanceof None ? 0 : 1);
|
||||
((EntityLiving)caster).setAttackTarget((EntityLivingBase)target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}else if(caster != null){
|
||||
Wizardry.logger.warn("Recieved a PacketNPCCastSpell, but the caster ID was not the ID of an EntityLiving");
|
||||
}
|
||||
@@ -474,6 +492,9 @@ public class ClientProxy extends CommonProxy {
|
||||
|
||||
World world = Minecraft.getMinecraft().world;
|
||||
Entity caster = world.getEntityByID(message.casterID);
|
||||
|
||||
if(caster == null) return; // Shouldn't happen
|
||||
|
||||
// Moved from when the packet is sent to when it is received; fixes the sound not playing in first person.
|
||||
caster.playSound(WizardrySounds.SPELL_TRANSPORTATION_TRAVEL, 1, 1);
|
||||
|
||||
@@ -538,7 +559,13 @@ public class ClientProxy extends CommonProxy {
|
||||
data.randomNames = new HashMap<>();
|
||||
data.randomDescriptions = new HashMap<>();
|
||||
|
||||
for(Spell spell : Spell.getSpells(Spell.allSpells)){
|
||||
for(Spell spell : Spell.getAllSpells()){
|
||||
|
||||
if(spell.networkID() > message.names.size()){
|
||||
Wizardry.logger.warn("Received no glyph data for spell {}, skipping", spell.getRegistryName());
|
||||
continue;
|
||||
}
|
||||
|
||||
// -1 because the none spell isn't included
|
||||
// This is a case where we must use the network ID, not the metadata
|
||||
data.randomNames.put(spell, message.names.get(spell.networkID() - 1));
|
||||
@@ -565,13 +592,6 @@ public class ClientProxy extends CommonProxy {
|
||||
GuiWizardHandbook.updateUnlockStatus(message.showToasts, message.completedAdvancements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEndSlowTimePacket(PacketEndSlowTime.Message message){
|
||||
Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.hostID);
|
||||
if(entity instanceof EntityLivingBase) PotionSlowTime.unblockNearbyEntities((EntityLivingBase)entity);
|
||||
else Wizardry.logger.warn("Received a PacketEndSlowTime, but the entity ID did not match any living entity");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResurrectionPacket(PacketResurrection.Message message){
|
||||
Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.playerID);
|
||||
|
||||
@@ -9,6 +9,7 @@ import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import electroblob.wizardry.item.ItemArtefact;
|
||||
import electroblob.wizardry.item.ItemSpectralBow;
|
||||
import electroblob.wizardry.potion.PotionSlowTime;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
@@ -23,11 +24,8 @@ import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.SharedMonsterAttributes;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.entity.item.EntityArmorStand;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -35,18 +33,17 @@ import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityDispenser;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.village.MerchantRecipe;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.*;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Event handler responsible for client-side only events, mostly rendering.
|
||||
@@ -72,23 +69,43 @@ public final class WizardryClientEventHandler {
|
||||
/** The number of ticks the blink effect lasts for. */
|
||||
private static final int BLINK_EFFECT_DURATION = 8;
|
||||
|
||||
private static final Method unpressKey;
|
||||
|
||||
static {
|
||||
unpressKey = ObfuscationReflectionHelper.findMethod(KeyBinding.class, "func_74505_d", void.class);
|
||||
}
|
||||
/** The remaining time for which the screen shake effect will be active. */
|
||||
private static int screenShakeCounter = 0;
|
||||
private static final float SHAKINESS = 0.5f;
|
||||
|
||||
/** Starts the first person blink overlay effect. */
|
||||
/** Starts the first-person blink overlay effect. */
|
||||
public static void playBlinkEffect(){
|
||||
blinkEffectTimer = BLINK_EFFECT_DURATION;
|
||||
if(Wizardry.settings.blinkEffect) blinkEffectTimer = BLINK_EFFECT_DURATION;
|
||||
}
|
||||
|
||||
/** Starts the client-side screen shake effect. */
|
||||
public static void shakeScreen(float intensity){
|
||||
if(Wizardry.settings.screenShake){
|
||||
screenShakeCounter = (int)(intensity / SHAKINESS);
|
||||
Minecraft.getMinecraft().player.rotationPitch -= intensity * 0.5f; // Start halfway down
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event){
|
||||
|
||||
if(event.player == Minecraft.getMinecraft().player){
|
||||
if(event.player == Minecraft.getMinecraft().player && event.phase == TickEvent.Phase.END){
|
||||
|
||||
if(blinkEffectTimer > 0) blinkEffectTimer--;
|
||||
if(Wizardry.settings.blinkEffect){
|
||||
if(blinkEffectTimer > 0) blinkEffectTimer--;
|
||||
}else{
|
||||
blinkEffectTimer = 0;
|
||||
}
|
||||
|
||||
if(Wizardry.settings.screenShake){
|
||||
if(screenShakeCounter > 0){
|
||||
float magnitude = screenShakeCounter * SHAKINESS;
|
||||
Minecraft.getMinecraft().player.rotationPitch += screenShakeCounter % 2 == 0 ? magnitude : -magnitude;
|
||||
screenShakeCounter--;
|
||||
}
|
||||
}else{
|
||||
screenShakeCounter = 0;
|
||||
}
|
||||
|
||||
// Only seems to work here...
|
||||
// EntityLiving victim = Possession.getPossessee(Minecraft.getMinecraft().player);
|
||||
@@ -151,7 +168,10 @@ public final class WizardryClientEventHandler {
|
||||
|
||||
if(world == null) return;
|
||||
|
||||
for(TileEntity tileentity : world.loadedTileEntityList){
|
||||
// Somehow this was throwing a CME, I have no idea why so I'm just going to cheat and copy the list
|
||||
List<TileEntity> tileEntities = new ArrayList<>(world.loadedTileEntityList);
|
||||
|
||||
for(TileEntity tileentity : tileEntities){
|
||||
if(tileentity instanceof TileEntityDispenser){
|
||||
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
|
||||
DispenserCastingData.get((TileEntityDispenser)tileentity).update();
|
||||
@@ -160,6 +180,7 @@ public final class WizardryClientEventHandler {
|
||||
}
|
||||
|
||||
SpellEmitterData.update(world);
|
||||
PotionSlowTime.cleanUpEntities(world);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ package electroblob.wizardry.client.gui;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.IManaStoringItem;
|
||||
import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import electroblob.wizardry.item.IWorkbenchItem;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.packet.PacketControlInput;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
@@ -29,6 +31,7 @@ import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
@@ -47,21 +50,25 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
private IInventory arcaneWorkbenchInventory;
|
||||
|
||||
private static final int TOOLTIP_WIDTH = 164;
|
||||
private static final int TOOLTIP_TEXT_INSET = 6;
|
||||
|
||||
/** We report the actual size of the GUI to Minecraft when a wand is in so JEI doesn't overdraw it.
|
||||
* For calculations, we use the size without the tooltip, which is stored in this constant. */
|
||||
private static final int MAIN_GUI_WIDTH = 176;
|
||||
|
||||
|
||||
private static final int RUNE_LEFT = 38;
|
||||
private static final int RUNE_TOP = 22;
|
||||
private static final int RUNE_WIDTH = 100;
|
||||
private static final int RUNE_HEIGHT = 100;
|
||||
|
||||
|
||||
private static final int PROGRESSION_BAR_WIDTH = 152;
|
||||
private static final int PROGRESSION_BAR_HEIGHT = 3;
|
||||
|
||||
private static final int HALO_DIAMETER = 156;
|
||||
|
||||
|
||||
private static final int TEXTURE_WIDTH = 512;
|
||||
private static final int TEXTURE_HEIGHT = 256;
|
||||
|
||||
|
||||
private int animationTimer = 0;
|
||||
private static final int ANIMATION_DURATION = 20;
|
||||
|
||||
@@ -113,28 +120,28 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
|
||||
|
||||
|
||||
// Animation
|
||||
|
||||
|
||||
// Grey background
|
||||
DrawingUtils.drawTexturedRect(guiLeft + RUNE_LEFT, guiTop + RUNE_TOP, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, 0,
|
||||
RUNE_WIDTH, RUNE_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
|
||||
// Yellow 'halo'
|
||||
if(animationTimer > 0){
|
||||
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
|
||||
int x = guiLeft + RUNE_LEFT + RUNE_WIDTH/2;
|
||||
int y = guiTop + RUNE_TOP + RUNE_HEIGHT/2;
|
||||
|
||||
|
||||
float scale = (animationTimer + partialTicks)/ANIMATION_DURATION;
|
||||
scale = (float)(1 - Math.pow(1-scale, 1.4f)); // Makes it slower at the start and speed up
|
||||
GlStateManager.scale(scale, scale, 1);
|
||||
GlStateManager.translate(x/scale, y/scale, 0);
|
||||
|
||||
|
||||
DrawingUtils.drawTexturedRect(-HALO_DIAMETER /2, -HALO_DIAMETER /2, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, RUNE_HEIGHT,
|
||||
HALO_DIAMETER, HALO_DIAMETER, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
@@ -232,6 +239,26 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
y += 14;
|
||||
}
|
||||
|
||||
// Progression bar
|
||||
if(stack.getItem() instanceof ItemWand && !Wizardry.settings.legacyWandLevelling){
|
||||
|
||||
y += 10;
|
||||
|
||||
Tier tier = ((ItemWand)stack.getItem()).tier;
|
||||
|
||||
float progressFraction = 1;
|
||||
|
||||
if(tier != Tier.MASTER){
|
||||
progressFraction = (float)WandHelper.getProgression(stack) / Tier.values()[tier.level + 1].progression;
|
||||
}
|
||||
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, MAIN_GUI_WIDTH, ySize + PROGRESSION_BAR_HEIGHT, PROGRESSION_BAR_WIDTH, PROGRESSION_BAR_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
int width = (int)(PROGRESSION_BAR_WIDTH * progressFraction);
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, MAIN_GUI_WIDTH, ySize, width, PROGRESSION_BAR_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
y += 8;
|
||||
}
|
||||
|
||||
if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).showSpellsInWorkbench(this.mc.player, stack)){
|
||||
|
||||
Spell[] spells = ((ISpellCastingItem)stack.getItem()).getSpells(stack);
|
||||
@@ -251,7 +278,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
.bindTexture(discovered ? spell.getElement().getIcon() : Element.MAGIC.getIcon());
|
||||
|
||||
// Renders the little element icon
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + 5, y, 8, 8);
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET - 1, y, 8, 8);
|
||||
|
||||
y += 10;
|
||||
}
|
||||
@@ -270,8 +297,8 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
if(level > 0){
|
||||
ItemStack stack1 = new ItemStack(item, level);
|
||||
GlStateManager.enableDepth();
|
||||
this.itemRender.renderItemAndEffectIntoGUI(stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y);
|
||||
this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y,
|
||||
this.itemRender.renderItemAndEffectIntoGUI(stack1, guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + x, y);
|
||||
this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack1, guiLeft + MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + x, y,
|
||||
null);
|
||||
x += 18;
|
||||
GlStateManager.disableDepth();
|
||||
@@ -311,7 +338,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
|
||||
int y = 6;
|
||||
|
||||
this.fontRenderer.drawStringWithShadow("\u00A7f" + stack.getDisplayName(), MAIN_GUI_WIDTH + 6, y, 0);
|
||||
this.fontRenderer.drawStringWithShadow("\u00A7f" + stack.getDisplayName(), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
|
||||
|
||||
if(stack.getItem() instanceof IManaStoringItem && ((IManaStoringItem)stack.getItem()).showManaInWorkbench(this.mc.player, stack)){
|
||||
y += 14;
|
||||
@@ -319,7 +346,27 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
"\u00A77" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.mana")
|
||||
+ " " + ((IManaStoringItem)stack.getItem()).getMana(stack) + "/"
|
||||
+ ((IManaStoringItem)stack.getItem()).getManaCapacity(stack),
|
||||
MAIN_GUI_WIDTH + 6, y, 0);
|
||||
MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
|
||||
}
|
||||
|
||||
// Progression tier text
|
||||
if(stack.getItem() instanceof ItemWand && !Wizardry.settings.legacyWandLevelling){
|
||||
|
||||
y += 14;
|
||||
|
||||
Tier tier = ((ItemWand)stack.getItem()).tier;
|
||||
|
||||
this.fontRenderer.drawStringWithShadow(tier.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
|
||||
|
||||
if(tier != Tier.MASTER){
|
||||
Tier nextTier = Tier.values()[tier.level + 1];
|
||||
String s = TextFormatting.DARK_GRAY.toString() + nextTier.getDisplayName();
|
||||
if(WandHelper.getProgression(stack) >= nextTier.progression) s = nextTier.getDisplayNameWithFormatting();
|
||||
this.fontRenderer.drawStringWithShadow(s, MAIN_GUI_WIDTH + TOOLTIP_WIDTH
|
||||
- TOOLTIP_TEXT_INSET - fontRenderer.getStringWidth(s), y, 0);
|
||||
}
|
||||
|
||||
y += 4;
|
||||
}
|
||||
|
||||
y += 14;
|
||||
@@ -337,10 +384,10 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
}
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + 16, y, 0);
|
||||
this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + 10, y, 0);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawStringWithShadow(
|
||||
"\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), MAIN_GUI_WIDTH + 16, y, 0);
|
||||
"\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + 10, y, 0);
|
||||
}
|
||||
y += 10;
|
||||
}
|
||||
@@ -351,7 +398,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
y += 6;
|
||||
|
||||
this.fontRenderer.drawStringWithShadow("\u00A7f" + I18n.format("container."
|
||||
+ Wizardry.MODID + ":arcane_workbench.upgrades"), MAIN_GUI_WIDTH + 6, y, 0);
|
||||
+ Wizardry.MODID + ":arcane_workbench.upgrades"), MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET, y, 0);
|
||||
|
||||
int x = 0;
|
||||
y += 10;
|
||||
@@ -364,7 +411,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
if(level > 0){
|
||||
// The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is
|
||||
// relative to the GUI but the POINT isn't.
|
||||
if(isPointInRegion(MAIN_GUI_WIDTH + 6 + x, y, 16, 16, mouseX, mouseY)){
|
||||
if(isPointInRegion(MAIN_GUI_WIDTH + TOOLTIP_TEXT_INSET + x, y, 16, 16, mouseX, mouseY)){
|
||||
ItemStack stack1 = new ItemStack(item, level);
|
||||
this.renderToolTip(stack1, mouseX - guiLeft, mouseY - guiTop);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
@@ -13,33 +13,27 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class GuiSpellBook extends GuiScreen {
|
||||
|
||||
private int xSize, ySize;
|
||||
private ItemSpellBook book;
|
||||
private Spell spell;
|
||||
|
||||
private static final Map<Tier, ResourceLocation> textures = ImmutableMap.of(
|
||||
Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"),
|
||||
Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"),
|
||||
Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"),
|
||||
Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png"));
|
||||
|
||||
public GuiSpellBook(Spell spell){
|
||||
public GuiSpellBook(ItemStack stack){
|
||||
super();
|
||||
xSize = 288;
|
||||
ySize = 180;
|
||||
this.spell = spell;
|
||||
if(!(stack.getItem() instanceof ItemSpellBook)) throw new ClassCastException("Cannot create spell book GUI for item that does not extend ItemSpellBook!");
|
||||
this.book = (ItemSpellBook)stack.getItem();
|
||||
this.spell = Spell.byMetadata(stack.getItemDamage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the screen and all the components in it.
|
||||
*/
|
||||
@Override
|
||||
public void drawScreen(int par1, int par2, float par3){
|
||||
|
||||
int xPos = this.width / 2 - xSize / 2;
|
||||
@@ -59,7 +53,7 @@ public class GuiSpellBook extends GuiScreen {
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
|
||||
DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(textures.get(spell.getTier()));
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(book.getGuiTexture(spell));
|
||||
DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
@@ -74,22 +68,18 @@ public class GuiSpellBook extends GuiScreen {
|
||||
0x777777);
|
||||
}
|
||||
|
||||
//this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0);
|
||||
// Novice is usually white but this doesn't show up
|
||||
String tier = I18n.format("gui.ebwizardry:spell_book.tier", spell.getTier() == Tier.NOVICE ?
|
||||
"\u00A77" + spell.getTier().getDisplayName() : spell.getTier().getDisplayNameWithFormatting());
|
||||
this.fontRenderer.drawString(tier, xPos + 17, yPos + 45, 0);
|
||||
|
||||
if(spell.getTier() == Tier.NOVICE){
|
||||
// Basic is usually white but this doesn't show up.
|
||||
this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0);
|
||||
}else{
|
||||
this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0);
|
||||
}
|
||||
|
||||
String element = "Element: " + spell.getElement().getFormattingCode() + spell.getElement().getDisplayName();
|
||||
if(!discovered) element = "Element: ?";
|
||||
String element = I18n.format("gui.ebwizardry:spell_book.element", spell.getElement().getFormattingCode() + spell.getElement().getDisplayName());
|
||||
if(!discovered) element = I18n.format("gui.ebwizardry:spell_book.element_undiscovered");
|
||||
this.fontRenderer.drawString(element, xPos + 17, yPos + 57, 0);
|
||||
|
||||
String manaCost = "Mana Cost: " + spell.getCost();
|
||||
if(spell.isContinuous) manaCost = "Mana Cost: " + spell.getCost() + "/second";
|
||||
if(!discovered) manaCost = "Mana Cost: ?";
|
||||
String manaCost = I18n.format("gui.ebwizardry:spell_book.mana_cost", spell.getCost());
|
||||
if(spell.isContinuous) manaCost = I18n.format("gui.ebwizardry:spell_book.mana_cost_continuous", spell.getCost());
|
||||
if(!discovered) manaCost = I18n.format("gui.ebwizardry:spell_book.mana_cost_undiscovered");
|
||||
this.fontRenderer.drawString(manaCost, xPos + 17, yPos + 69, 0);
|
||||
|
||||
if(discovered){
|
||||
@@ -100,6 +90,7 @@ public class GuiSpellBook extends GuiScreen {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui(){
|
||||
super.initGui();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
@@ -108,6 +99,7 @@ public class GuiSpellBook extends GuiScreen {
|
||||
this.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_BOOK_OPEN, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed(){
|
||||
super.onGuiClosed();
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
|
||||
@@ -96,7 +96,10 @@ public class GuiSpellDisplay {
|
||||
// Normally when extending Gui, you'd have to have an instance to access its methods. However, we're not actually
|
||||
// using any of them, so this class may as well not bother and just be a static event handler. Neat!
|
||||
@SubscribeEvent
|
||||
public static void draw(RenderGameOverlayEvent event){
|
||||
public static void draw(RenderGameOverlayEvent.Post event){
|
||||
|
||||
if(event.getType() != RenderGameOverlayEvent.ElementType.TEXT
|
||||
&& event.getType() != RenderGameOverlayEvent.ElementType.HOTBAR) return;
|
||||
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.collect.Streams;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
@@ -17,6 +18,7 @@ import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
class CraftingRecipe {
|
||||
@@ -60,8 +62,8 @@ class CraftingRecipe {
|
||||
for(ResourceLocation location : locations){
|
||||
|
||||
IRecipe recipe = CraftingManager.getRecipe(location);
|
||||
if(recipe == null) throw new JsonSyntaxException("No such recipe: " + location);
|
||||
recipes.add(recipe);
|
||||
if(recipe == null) Wizardry.logger.warn("The recipe {} used in the wizard's handbook does not exist, it will display a blank grid instead", location);
|
||||
else recipes.add(recipe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +82,7 @@ class CraftingRecipe {
|
||||
|
||||
for(int[] instance : instances){
|
||||
if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){
|
||||
renderCraftingRecipe(font, itemRenderer, left + instance[1], top + instance[2], recipes.get(index % recipes.size()));
|
||||
renderCraftingRecipe(font, itemRenderer, left + instance[1], top + instance[2], recipes.isEmpty() ? null : recipes.get(index % recipes.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,6 +98,8 @@ class CraftingRecipe {
|
||||
*/
|
||||
void drawTooltips(GuiWizardHandbook gui, FontRenderer font, RenderItem itemRenderer, int doublePage, int left, int top, int mouseX, int mouseY){
|
||||
|
||||
if(recipes.isEmpty()) return;
|
||||
|
||||
int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000;
|
||||
|
||||
for(int[] instance : instances){
|
||||
@@ -135,50 +139,53 @@ class CraftingRecipe {
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderCraftingRecipe(FontRenderer font, RenderItem itemRenderer, int x, int y, IRecipe recipe){
|
||||
|
||||
ItemStack result = recipe.getRecipeOutput();
|
||||
private static void renderCraftingRecipe(FontRenderer font, RenderItem itemRenderer, int x, int y, @Nullable IRecipe recipe){
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture);
|
||||
|
||||
DrawingUtils.drawTexturedRect(x, y, TEXTURE_INSET_X, TEXTURE_INSET_Y, WIDTH, HEIGHT, GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
GlStateManager.disableLighting();
|
||||
GlStateManager.enableRescaleNormal();
|
||||
GlStateManager.enableColorMaterial();
|
||||
itemRenderer.zLevel = 100.0F;
|
||||
if(recipe != null){
|
||||
|
||||
int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000;
|
||||
GlStateManager.pushMatrix();
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
GlStateManager.disableLighting();
|
||||
GlStateManager.enableRescaleNormal();
|
||||
GlStateManager.enableColorMaterial();
|
||||
itemRenderer.zLevel = 100.0F;
|
||||
|
||||
int i = 0;
|
||||
int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE) / 2000;
|
||||
|
||||
for(Ingredient ingredient : recipe.getIngredients()){
|
||||
int i = 0;
|
||||
|
||||
if(ingredient != Ingredient.EMPTY){
|
||||
ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length];
|
||||
if(!stack.isEmpty()){
|
||||
itemRenderer.renderItemAndEffectIntoGUI(stack, x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3));
|
||||
itemRenderer.renderItemOverlays(font, stack, x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3));
|
||||
for(Ingredient ingredient : recipe.getIngredients()){
|
||||
|
||||
if(ingredient != Ingredient.EMPTY){
|
||||
ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length];
|
||||
if(!stack.isEmpty()){
|
||||
itemRenderer.renderItemAndEffectIntoGUI(stack, x + BORDER + 18 * (i % 3), y + BORDER + 18 * (i / 3));
|
||||
itemRenderer.renderItemOverlays(font, stack, x + BORDER + 18 * (i % 3), y + BORDER + 18 * (i / 3));
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
i++;
|
||||
ItemStack result = recipe.getRecipeOutput();
|
||||
|
||||
if(!result.isEmpty()){
|
||||
itemRenderer.renderItemAndEffectIntoGUI(result, x + BORDER + 86, y + BORDER + 18);
|
||||
itemRenderer.renderItemOverlays(font, result, x + BORDER + 86, y + BORDER + 18);
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.disableColorMaterial();
|
||||
itemRenderer.zLevel = 0.0F;
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
|
||||
}
|
||||
|
||||
if(!result.isEmpty()){
|
||||
itemRenderer.renderItemAndEffectIntoGUI(result, x + BORDER + 86, y + BORDER + 18);
|
||||
itemRenderer.renderItemOverlays(font, result, x + BORDER + 86, y + BORDER + 18);
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.disableColorMaterial();
|
||||
itemRenderer.zLevel = 0.0F;
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
|
||||
}
|
||||
|
||||
private static void renderCraftingTooltips(GuiWizardHandbook gui, RenderItem itemRenderer, int x, int y, int mouseX, int mouseY, IRecipe recipe){
|
||||
|
||||
@@ -184,7 +184,7 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
addFormatTag("advanced_max_charge", "" + Tier.ADVANCED.maxCharge);
|
||||
addFormatTag("master_max_charge", "" + Tier.MASTER.maxCharge);
|
||||
addFormatTag("version", Wizardry.VERSION);
|
||||
addFormatTag("mcversion", Minecraft.getMinecraft().getVersion());
|
||||
addFormatTag("mcversion", "1.12.2");
|
||||
|
||||
addFormatTag("colour_novice", "\u00A77");
|
||||
addFormatTag("colour_apprentice", Tier.APPRENTICE.getFormattingCode());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry.client.model;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockStatue;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -13,6 +14,7 @@ public class ModelWizardArmour extends ModelArmourFixer {
|
||||
ModelRenderer hatSegment4;
|
||||
ModelRenderer hatSegment5;
|
||||
ModelRenderer hatSegment6;
|
||||
ModelRenderer hatBobble;
|
||||
ModelRenderer robe;
|
||||
|
||||
public ModelWizardArmour(float delta){
|
||||
@@ -75,6 +77,13 @@ public class ModelWizardArmour extends ModelArmourFixer {
|
||||
hatSegment6.mirror = true;
|
||||
setRotation(hatSegment6, -0.5585054F, 0F, 0F);
|
||||
|
||||
hatBobble = new ModelRenderer(this, 52, 47);
|
||||
hatBobble.addBox(0F, 0F, 0F, 3, 3, 3);
|
||||
hatBobble.setRotationPoint(-1.5F, -15.1F, 4F);
|
||||
hatBobble.setTextureSize(64, 64);
|
||||
hatBobble.mirror = true;
|
||||
setRotation(hatBobble, -0.65F, 0F, 0F);
|
||||
|
||||
bipedBody = new ModelRenderer(this, 16, 16);
|
||||
bipedBody.addBox(-4F, 0F, -2F, 8, 11, 4, delta);
|
||||
bipedBody.setRotationPoint(0F, 0F, 0F);
|
||||
@@ -97,6 +106,7 @@ public class ModelWizardArmour extends ModelArmourFixer {
|
||||
bipedHead.addChild(hatSegment4);
|
||||
bipedHead.addChild(hatSegment5);
|
||||
bipedHead.addChild(hatSegment6);
|
||||
bipedHead.addChild(hatBobble);
|
||||
}
|
||||
|
||||
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){
|
||||
@@ -129,6 +139,8 @@ public class ModelWizardArmour extends ModelArmourFixer {
|
||||
this.robe.rotateAngleX = (this.bipedLeftLeg.rotateAngleX + this.bipedRightLeg.rotateAngleX) / 2f;
|
||||
this.robe.rotateAngleY = this.bipedBody.rotateAngleY;
|
||||
this.robe.rotateAngleZ = (this.bipedLeftLeg.rotateAngleZ + this.bipedRightLeg.rotateAngleZ) / 2f;
|
||||
|
||||
this.hatBobble.showModel = Wizardry.tisTheSeason;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import electroblob.wizardry.item.ItemCrystal;
|
||||
import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ModelBakery;
|
||||
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
|
||||
import net.minecraft.client.renderer.block.statemap.StateMap;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
@@ -66,10 +67,10 @@ public final class WizardryModels {
|
||||
|
||||
registerMultiTexturedModel((ItemCrystal)WizardryItems.magic_crystal);
|
||||
|
||||
registerItemModel(WizardryItems.magic_wand);
|
||||
registerItemModel(WizardryItems.apprentice_wand);
|
||||
registerItemModel(WizardryItems.advanced_wand);
|
||||
registerItemModel(WizardryItems.master_wand);
|
||||
registerWandModel(WizardryItems.magic_wand);
|
||||
registerWandModel(WizardryItems.apprentice_wand);
|
||||
registerWandModel(WizardryItems.advanced_wand);
|
||||
registerWandModel(WizardryItems.master_wand);
|
||||
|
||||
registerItemModel(WizardryItems.spell_book);
|
||||
// Wildcard registered for wizard trades.
|
||||
@@ -77,37 +78,37 @@ public final class WizardryModels {
|
||||
registerItemModel(WizardryItems.arcane_tome);
|
||||
registerItemModel(WizardryItems.wizard_handbook);
|
||||
|
||||
registerItemModel(WizardryItems.novice_fire_wand);
|
||||
registerItemModel(WizardryItems.novice_ice_wand);
|
||||
registerItemModel(WizardryItems.novice_lightning_wand);
|
||||
registerItemModel(WizardryItems.novice_necromancy_wand);
|
||||
registerItemModel(WizardryItems.novice_earth_wand);
|
||||
registerItemModel(WizardryItems.novice_sorcery_wand);
|
||||
registerItemModel(WizardryItems.novice_healing_wand);
|
||||
registerWandModel(WizardryItems.novice_fire_wand);
|
||||
registerWandModel(WizardryItems.novice_ice_wand);
|
||||
registerWandModel(WizardryItems.novice_lightning_wand);
|
||||
registerWandModel(WizardryItems.novice_necromancy_wand);
|
||||
registerWandModel(WizardryItems.novice_earth_wand);
|
||||
registerWandModel(WizardryItems.novice_sorcery_wand);
|
||||
registerWandModel(WizardryItems.novice_healing_wand);
|
||||
|
||||
registerItemModel(WizardryItems.apprentice_fire_wand);
|
||||
registerItemModel(WizardryItems.apprentice_ice_wand);
|
||||
registerItemModel(WizardryItems.apprentice_lightning_wand);
|
||||
registerItemModel(WizardryItems.apprentice_necromancy_wand);
|
||||
registerItemModel(WizardryItems.apprentice_earth_wand);
|
||||
registerItemModel(WizardryItems.apprentice_sorcery_wand);
|
||||
registerItemModel(WizardryItems.apprentice_healing_wand);
|
||||
registerWandModel(WizardryItems.apprentice_fire_wand);
|
||||
registerWandModel(WizardryItems.apprentice_ice_wand);
|
||||
registerWandModel(WizardryItems.apprentice_lightning_wand);
|
||||
registerWandModel(WizardryItems.apprentice_necromancy_wand);
|
||||
registerWandModel(WizardryItems.apprentice_earth_wand);
|
||||
registerWandModel(WizardryItems.apprentice_sorcery_wand);
|
||||
registerWandModel(WizardryItems.apprentice_healing_wand);
|
||||
|
||||
registerItemModel(WizardryItems.advanced_fire_wand);
|
||||
registerItemModel(WizardryItems.advanced_ice_wand);
|
||||
registerItemModel(WizardryItems.advanced_lightning_wand);
|
||||
registerItemModel(WizardryItems.advanced_necromancy_wand);
|
||||
registerItemModel(WizardryItems.advanced_earth_wand);
|
||||
registerItemModel(WizardryItems.advanced_sorcery_wand);
|
||||
registerItemModel(WizardryItems.advanced_healing_wand);
|
||||
registerWandModel(WizardryItems.advanced_fire_wand);
|
||||
registerWandModel(WizardryItems.advanced_ice_wand);
|
||||
registerWandModel(WizardryItems.advanced_lightning_wand);
|
||||
registerWandModel(WizardryItems.advanced_necromancy_wand);
|
||||
registerWandModel(WizardryItems.advanced_earth_wand);
|
||||
registerWandModel(WizardryItems.advanced_sorcery_wand);
|
||||
registerWandModel(WizardryItems.advanced_healing_wand);
|
||||
|
||||
registerItemModel(WizardryItems.master_fire_wand);
|
||||
registerItemModel(WizardryItems.master_ice_wand);
|
||||
registerItemModel(WizardryItems.master_lightning_wand);
|
||||
registerItemModel(WizardryItems.master_necromancy_wand);
|
||||
registerItemModel(WizardryItems.master_earth_wand);
|
||||
registerItemModel(WizardryItems.master_sorcery_wand);
|
||||
registerItemModel(WizardryItems.master_healing_wand);
|
||||
registerWandModel(WizardryItems.master_fire_wand);
|
||||
registerWandModel(WizardryItems.master_ice_wand);
|
||||
registerWandModel(WizardryItems.master_lightning_wand);
|
||||
registerWandModel(WizardryItems.master_necromancy_wand);
|
||||
registerWandModel(WizardryItems.master_earth_wand);
|
||||
registerWandModel(WizardryItems.master_sorcery_wand);
|
||||
registerWandModel(WizardryItems.master_healing_wand);
|
||||
|
||||
registerItemModel(WizardryItems.spectral_sword);
|
||||
registerItemModel(WizardryItems.spectral_pickaxe);
|
||||
@@ -282,6 +283,9 @@ public final class WizardryModels {
|
||||
if(location.getPath().contains("runestone") || location.getPath().contains("runestone_pedestal")){
|
||||
IBakedModel original = event.getModelRegistry().getObject(location);
|
||||
event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "overlay"));
|
||||
}else if(location.getPath().contains("spectral_block")){
|
||||
IBakedModel original = event.getModelRegistry().getObject(location);
|
||||
event.getModelRegistry().putObject(location, new BakedModelGlowingOverlay(original, "spectral_block"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,24 +295,30 @@ public final class WizardryModels {
|
||||
|
||||
/**
|
||||
* Registers an item model, using the item's registry name as the model name (this convention makes it easier to
|
||||
* keep track of everything). Variant defaults to "normal". Registers the model for metadata 0 automatically, plus
|
||||
* all the other metadata values that the item can take, as defined in
|
||||
* {@link Item#getSubItems(CreativeTabs, NonNullList)}. The creative tab supplied
|
||||
* to the aforementioned method will be whichever one the item is in.
|
||||
* keep track of everything). Variant defaults to "normal". Registers the model for all metadata values.
|
||||
*/
|
||||
private static void registerItemModel(Item item){
|
||||
|
||||
if(item.getHasSubtypes()){
|
||||
NonNullList<ItemStack> items = NonNullList.create();
|
||||
item.getSubItems(item.getCreativeTab(), items); // Client-only method, but we're client-side so this is OK.
|
||||
for(ItemStack stack : items){
|
||||
ModelLoader.setCustomModelResourceLocation(item, stack.getMetadata(),
|
||||
new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||
}
|
||||
}
|
||||
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
|
||||
ModelLoader.setCustomModelResourceLocation(item, 0,
|
||||
new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||
ModelBakery.registerItemVariants(item, new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||
// Assigns the model for all metadata values
|
||||
ModelLoader.setCustomMeshDefinition(item, s -> new ModelResourceLocation(item.getRegistryName(), "inventory"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a wand model, using the item's registry name as the model name (this convention makes it easier to
|
||||
* keep track of everything).
|
||||
*/
|
||||
private static void registerWandModel(Item item){
|
||||
|
||||
if(Wizardry.tisTheSeason){
|
||||
// Changing the last parameter from null to "inventory" fixed the item/block model weirdness. No idea why!
|
||||
ModelBakery.registerItemVariants(item, new ModelResourceLocation("ebwizardry:festive_wand", "inventory"));
|
||||
// Assigns the model for all metadata values
|
||||
ModelLoader.setCustomMeshDefinition(item, s -> new ModelResourceLocation("ebwizardry:festive_wand", "inventory"));
|
||||
}else{
|
||||
registerItemModel(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,8 +40,6 @@ public class ParticlePath extends ParticleWizardry {
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ParticleTornado extends ParticleDigging {
|
||||
public ParticleTornado(World world, int maxAge, double originX, double originZ, double radius, double yPos,
|
||||
double velX, double velZ, IBlockState block){
|
||||
super(world, 0, 0, 0, 0, 0, 0, block);
|
||||
float angle = this.rand.nextFloat() * (float)Math.PI * 2;
|
||||
this.angle = this.rand.nextFloat() * (float)Math.PI * 2;
|
||||
double x = originX - MathHelper.cos(angle) * radius;
|
||||
double z = originZ + radius * MathHelper.sin(angle);
|
||||
this.radius = radius;
|
||||
|
||||
@@ -525,30 +525,42 @@ public abstract class ParticleWizardry extends Particle {
|
||||
|
||||
|
||||
// =============================================== Helper Methods ===============================================
|
||||
|
||||
|
||||
/** Internal overload for {@link ParticleWizardry#generateTextures(String, String, int)} which uses wizardry's mod
|
||||
* ID automatically. */
|
||||
public static ResourceLocation[] generateTextures(String stem, int n){
|
||||
return generateTextures(Wizardry.MODID, stem, n);
|
||||
}
|
||||
|
||||
/** Static helper method that generates an array of n ResourceLocations using the particle file naming convention,
|
||||
* which is the given stem plus an underscore plus the integer index. */
|
||||
public static ResourceLocation[] generateTextures(String stem, int n){
|
||||
public static ResourceLocation[] generateTextures(String modID, String stem, int n){
|
||||
|
||||
ResourceLocation[] textures = new ResourceLocation[n];
|
||||
|
||||
for(int i=0; i<n; i++){
|
||||
textures[i] = new ResourceLocation(Wizardry.MODID, "particle/" + stem + "_" + i);
|
||||
textures[i] = new ResourceLocation(modID, "particle/" + stem + "_" + i);
|
||||
}
|
||||
|
||||
return textures;
|
||||
}
|
||||
|
||||
/** Internal overload for {@link ParticleWizardry#generateTextures(String, String, int, int)} which uses wizardry's
|
||||
* mod ID automatically. */
|
||||
public static ResourceLocation[][] generateTextures(String stem, int m, int n){
|
||||
return generateTextures(Wizardry.MODID, stem, m, n);
|
||||
}
|
||||
|
||||
/** Static helper method that generates a 2D m x n array of ResourceLocations using the particle file naming
|
||||
* convention, which is the given stem plus an underscore plus the first index, plus an underscore plus the second
|
||||
* index. Useful for animated particles that also pick a random animation strip. */
|
||||
public static ResourceLocation[][] generateTextures(String stem, int m, int n){
|
||||
public static ResourceLocation[][] generateTextures(String modID, String stem, int m, int n){
|
||||
|
||||
ResourceLocation[][] textures = new ResourceLocation[m][n];
|
||||
|
||||
for(int i=0; i<m; i++){
|
||||
for(int j=0; j<n; j++){
|
||||
textures[i][j] = new ResourceLocation(Wizardry.MODID, "particle/" + stem + "_" + i + "_" + j);
|
||||
textures[i][j] = new ResourceLocation(modID, "particle/" + stem + "_" + i + "_" + j);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public class LayerFrost implements LayerRenderer<EntityLivingBase> {
|
||||
double scaleX = 1, scaleY = 1;
|
||||
// It's more logical to use the model's texture size, but some classes don't bother setting it properly
|
||||
// (e.g. ModelVillager), so to get the correct dimensions I'm getting them from the first box instead.
|
||||
if(model.boxList != null && model.boxList.get(0) != null){
|
||||
if(model.boxList != null && model.boxList.size() >= 1 && model.boxList.get(0) != null){
|
||||
scaleX = (double)model.boxList.get(0).textureWidth / 16d;
|
||||
scaleY = (double)model.boxList.get(0).textureHeight / 16d;
|
||||
}else{ // Fallback to model fields; should never be needed
|
||||
@@ -121,11 +121,26 @@ public class LayerFrost implements LayerRenderer<EntityLivingBase> {
|
||||
}
|
||||
GlStateManager.scale(scaleX, scaleY, 1);
|
||||
GlStateManager.matrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
|
||||
boolean headWearHidden = false;
|
||||
boolean bodyWearHidden = false;
|
||||
boolean leftArmWearHidden = false;
|
||||
boolean rightArmWearHidden = false;
|
||||
boolean leftLegWearHidden = false;
|
||||
boolean rightLegWearHidden = false;
|
||||
|
||||
// Hides the hat layer for bipeds
|
||||
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = true;
|
||||
if(this.model instanceof ModelBiped){
|
||||
headWearHidden = ((ModelBiped)this.model).bipedHeadwear.isHidden;
|
||||
((ModelBiped)this.model).bipedHeadwear.isHidden = true;
|
||||
}
|
||||
|
||||
if(this.model instanceof ModelPlayer){
|
||||
bodyWearHidden = ((ModelPlayer)this.model).bipedBodyWear.isHidden;
|
||||
leftArmWearHidden = ((ModelPlayer)this.model).bipedLeftArmwear.isHidden;
|
||||
rightArmWearHidden = ((ModelPlayer)this.model).bipedRightArmwear.isHidden;
|
||||
leftLegWearHidden = ((ModelPlayer)this.model).bipedLeftLegwear.isHidden;
|
||||
rightLegWearHidden = ((ModelPlayer)this.model).bipedRightLegwear.isHidden;
|
||||
((ModelPlayer)this.model).bipedBodyWear.isHidden = true;
|
||||
((ModelPlayer)this.model).bipedLeftArmwear.isHidden = true;
|
||||
((ModelPlayer)this.model).bipedRightArmwear.isHidden = true;
|
||||
@@ -136,7 +151,15 @@ public class LayerFrost implements LayerRenderer<EntityLivingBase> {
|
||||
this.model.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks);
|
||||
this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale);
|
||||
|
||||
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = false;
|
||||
if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = headWearHidden;
|
||||
|
||||
if(this.model instanceof ModelPlayer){
|
||||
((ModelPlayer)this.model).bipedBodyWear.isHidden = bodyWearHidden;
|
||||
((ModelPlayer)this.model).bipedLeftArmwear.isHidden = leftArmWearHidden;
|
||||
((ModelPlayer)this.model).bipedRightArmwear.isHidden = rightArmWearHidden;
|
||||
((ModelPlayer)this.model).bipedLeftLegwear.isHidden = leftLegWearHidden;
|
||||
((ModelPlayer)this.model).bipedRightLegwear.isHidden = rightLegWearHidden;
|
||||
}
|
||||
|
||||
// Undoes the texture scaling
|
||||
GlStateManager.matrixMode(GL11.GL_TEXTURE);
|
||||
|
||||
@@ -36,27 +36,43 @@ public class RenderArcaneLock {
|
||||
|
||||
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||
World world = Minecraft.getMinecraft().world;
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
Vec3d origin = player.getPositionEyes(event.getPartialTicks());
|
||||
GlStateManager.translate(-origin.x, -origin.y + player.getEyeHeight(), -origin.z);
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(textures[(player.ticksExisted % (textures.length * 2))/2]);
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
|
||||
for(TileEntity tileentity : world.loadedTileEntityList){
|
||||
boolean flag = false;
|
||||
boolean lighting = false;
|
||||
|
||||
if(tileentity.getDistanceSq(origin.x, origin.y, origin.z) <= 64*64 && tileentity.getTileData().hasUniqueId(ArcaneLock.NBT_KEY)){
|
||||
// Someone managed to get a CME here so let's iterate manually to be safe (don't copy the list, it's expensive!)
|
||||
// It's only cosmetic so if a tileentity somehow gets removed while we're rendering them it's not a big deal
|
||||
for(int i=0; i<world.loadedTileEntityList.size(); i++){
|
||||
|
||||
TileEntity tileentity = world.loadedTileEntityList.get(i);
|
||||
|
||||
if(tileentity == null) continue; // What the heck VoxelMap
|
||||
|
||||
if(tileentity.getDistanceSq(origin.x, origin.y, origin.z) <= tileentity.getMaxRenderDistanceSquared()
|
||||
&& tileentity.getTileData().hasUniqueId(ArcaneLock.NBT_KEY)){
|
||||
|
||||
if(!flag){
|
||||
|
||||
flag = true;
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
lighting = GL11.glIsEnabled(GL11.GL_LIGHTING);
|
||||
GlStateManager.disableLighting();
|
||||
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240, 240);
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GlStateManager.translate(-origin.x, -origin.y + player.getEyeHeight(), -origin.z);
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(textures[(player.ticksExisted % (textures.length * 2))/2]);
|
||||
|
||||
buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
|
||||
}
|
||||
|
||||
Vec3d[] vertices = WizardryUtilities.getVertices(world.getBlockState(tileentity.getPos()).getBoundingBox(world, tileentity.getPos()).grow(0.05).offset(tileentity.getPos()));
|
||||
|
||||
@@ -70,13 +86,19 @@ public class RenderArcaneLock {
|
||||
}
|
||||
}
|
||||
|
||||
tessellator.draw();
|
||||
if(flag){
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableTexture2D();
|
||||
if(lighting){
|
||||
GlStateManager.enableLighting();
|
||||
}
|
||||
GlStateManager.disableRescaleNormal();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableTexture2D();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.disableRescaleNormal();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
private static void drawFace(BufferBuilder buffer, Vec3d topLeft, Vec3d topRight, Vec3d bottomLeft, Vec3d bottomRight, float u1, float v1, float u2, float v2){
|
||||
|
||||
@@ -53,9 +53,8 @@ public class RenderBlackHole extends Render<EntityBlackHole> {
|
||||
(float)blackhole.ticksExisted / 10);
|
||||
}
|
||||
if(blackhole.ticksExisted > blackhole.lifetime - 10){
|
||||
GlStateManager.scale((float)(blackhole.lifetime - blackhole.ticksExisted) / 10,
|
||||
(float)(blackhole.lifetime - blackhole.ticksExisted) / 10,
|
||||
(float)(blackhole.lifetime - blackhole.ticksExisted) / 10);
|
||||
float scale = Math.max(0, (float)(blackhole.lifetime - blackhole.ticksExisted) / 10);
|
||||
GlStateManager.scale(scale, scale, scale);
|
||||
}
|
||||
|
||||
this.bindTexture(texture);
|
||||
|
||||
@@ -190,7 +190,8 @@ public class CommandCastSpell extends CommandBase {
|
||||
}
|
||||
|
||||
if(spell.isContinuous){
|
||||
|
||||
// We need not query Spell#canBeCastByDispensers since with commands there's no difference between
|
||||
// a spell that can't be cast positionally and one that can be cast positionally but fails
|
||||
if(spell.cast(world, origin.x, origin.y, origin.z, direction, 0, duration, modifiers)){
|
||||
|
||||
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Post(Source.COMMAND, spell, world, origin.x, origin.y, origin.z, direction, modifiers));
|
||||
|
||||
@@ -113,7 +113,7 @@ public class CommandDiscoverSpell extends CommandBase {
|
||||
if(server.sendCommandFeedback()) sender.sendMessage(
|
||||
new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.clear", player.getName()));
|
||||
}else if(all){
|
||||
data.spellsDiscovered.addAll(Spell.getSpells(Spell.allSpells));
|
||||
data.spellsDiscovered.addAll(Spell.getAllSpells());
|
||||
if(server.sendCommandFeedback()) sender.sendMessage(
|
||||
new TextComponentTranslation("commands." + Wizardry.MODID + ":discoverspell.all", player.getName()));
|
||||
}else{
|
||||
|
||||
@@ -4,6 +4,7 @@ import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.data.SpellEmitterData;
|
||||
import electroblob.wizardry.event.SpellCastEvent;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.NBTExtras;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
@@ -129,7 +130,7 @@ public class SpellEmitter implements ITickable {
|
||||
nbt.setDouble("z", z);
|
||||
nbt.setInteger("direction", direction.getIndex());
|
||||
nbt.setInteger("duration", duration);
|
||||
nbt.setTag("modifiers", modifiers.toNBT());
|
||||
NBTExtras.storeTagSafely(nbt, "modifiers", modifiers.toNBT());
|
||||
nbt.setInteger("castingTick", castingTick);
|
||||
|
||||
return nbt;
|
||||
|
||||
@@ -12,9 +12,9 @@ import java.util.Random;
|
||||
public enum Tier {
|
||||
|
||||
NOVICE(700, 3, 12, 0, new Style().setColor(TextFormatting.WHITE), "novice"),
|
||||
APPRENTICE(1000, 5, 5, 6000, new Style().setColor(TextFormatting.AQUA), "apprentice"),
|
||||
ADVANCED(1500, 7, 2, 9000, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
|
||||
MASTER(2500, 9, 1, 15000, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
|
||||
APPRENTICE(1000, 5, 5, 2000, new Style().setColor(TextFormatting.AQUA), "apprentice"),
|
||||
ADVANCED(1500, 7, 2, 3500, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
|
||||
MASTER(2500, 9, 1, 6000, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
|
||||
|
||||
/** Maximum mana a wand of this tier can store. */
|
||||
public final int maxCharge;
|
||||
|
||||
@@ -7,6 +7,7 @@ import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.spell.None;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.NBTExtras;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
@@ -141,7 +142,7 @@ public abstract class BlockCastingData<T extends TileEntity> implements INBTSeri
|
||||
|
||||
nbt.setInteger("spell", spell.metadata());
|
||||
nbt.setInteger("castingTick", castingTick);
|
||||
nbt.setTag("modifiers", modifiers.toNBT());
|
||||
NBTExtras.storeTagSafely(nbt, "modifiers", modifiers.toNBT());
|
||||
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@@ -166,7 +166,10 @@ public class DispenserCastingData extends BlockCastingData<TileEntityDispenser>
|
||||
// This will fire once for each dimension, but since we want dispenser-casting to work in all dimensions,
|
||||
// this is correct (the loaded tile entity list will of course be different in each case.
|
||||
|
||||
for(TileEntity tileentity : event.world.loadedTileEntityList){
|
||||
// Somehow this was throwing a CME, I have no idea why so I'm just going to cheat and copy the list
|
||||
List<TileEntity> tileEntities = new ArrayList<>(event.world.loadedTileEntityList);
|
||||
|
||||
for(TileEntity tileentity : tileEntities){
|
||||
if(tileentity instanceof TileEntityDispenser){
|
||||
if(DispenserCastingData.get((TileEntityDispenser)tileentity) != null){
|
||||
DispenserCastingData.get((TileEntityDispenser)tileentity).update();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry.data;
|
||||
|
||||
import electroblob.wizardry.util.NBTExtras;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -89,7 +90,7 @@ public interface IStoredVariable<T> extends IVariable<T> {
|
||||
|
||||
@Override
|
||||
public void write(NBTTagCompound nbt, T value){
|
||||
if(value != null) nbt.setTag(key, serialiser.apply(value));
|
||||
if(value != null) NBTExtras.storeTagSafely(nbt, key, serialiser.apply(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -91,7 +91,7 @@ public class SpellEmitterData extends WorldSavedData {
|
||||
|
||||
@Override
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound){
|
||||
compound.setTag("emitters", NBTExtras.listToNBT(emitters, SpellEmitter::toNBT));
|
||||
NBTExtras.storeTagSafely(compound, "emitters", NBTExtras.listToNBT(emitters, SpellEmitter::toNBT));
|
||||
return compound;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.packet.PacketGlyphData;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.NBTExtras;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
@@ -43,11 +44,11 @@ public class SpellGlyphData extends WorldSavedData {
|
||||
/** Generates random names and descriptions for any spells which don't already have them. */
|
||||
public void generateGlyphNames(World world){
|
||||
|
||||
for(Spell spell : Spell.getSpells(Spell.allSpells)){
|
||||
for(Spell spell : Spell.getAllSpells()){
|
||||
if(!randomNames.containsKey(spell)) randomNames.put(spell, generateRandomName(world.rand));
|
||||
}
|
||||
|
||||
for(Spell spell : Spell.getSpells(Spell.allSpells)){
|
||||
for(Spell spell : Spell.getAllSpells()){
|
||||
if(!randomDescriptions.containsKey(spell))
|
||||
randomDescriptions.put(spell, generateRandomDescription(world.rand));
|
||||
}
|
||||
@@ -161,7 +162,7 @@ public class SpellGlyphData extends WorldSavedData {
|
||||
|
||||
NBTTagList tagList = new NBTTagList();
|
||||
|
||||
for(Spell spell : Spell.getSpells(Spell.allSpells)){
|
||||
for(Spell spell : Spell.getAllSpells()){
|
||||
// Much like the enchantments tag for items, this stores a list of spell-id-to-name tag pairs
|
||||
// The description is now also included; there's no point in making a second compound tag!
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
@@ -171,7 +172,7 @@ public class SpellGlyphData extends WorldSavedData {
|
||||
tagList.appendTag(tag);
|
||||
}
|
||||
|
||||
nbt.setTag("spellGlyphData", tagList);
|
||||
NBTExtras.storeTagSafely(nbt, "spellGlyphData", tagList);
|
||||
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import electroblob.wizardry.enchantment.Imbuement;
|
||||
import electroblob.wizardry.entity.living.ISummonedCreature;
|
||||
import electroblob.wizardry.event.SpellCastEvent;
|
||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.packet.PacketCastContinuousSpell;
|
||||
import electroblob.wizardry.packet.PacketPlayerSync;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
@@ -71,7 +72,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
private static final Set<IStoredVariable> storedVariables = new HashSet<>();
|
||||
|
||||
/** The maximum number of recent spells to track. */
|
||||
public static final int MAX_RECENT_SPELLS = 10;
|
||||
public static final int MAX_RECENT_SPELLS = ItemWand.BASE_SPELL_SLOTS;
|
||||
|
||||
/** The player this WizardData instance belongs to. */
|
||||
private final EntityPlayer player;
|
||||
@@ -140,7 +141,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
// All players can recognise magic missile. This is not done using discoverSpell because that seems to cause
|
||||
// a crash on load occasionally (probably something to do with achievements being initialised)
|
||||
this.spellsDiscovered.add(Spells.magic_missile);
|
||||
this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS); // Only keeps a reference to the last 10 spells cast
|
||||
this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS); // Only keeps a reference to the last 5 spells cast
|
||||
this.castCommandSpell = Spells.none;
|
||||
this.castCommandModifiers = new SpellModifiers();
|
||||
this.castCommandTick = 0;
|
||||
@@ -272,7 +273,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
* @param spell The spell to count casts for.
|
||||
*/
|
||||
public int countRecentCasts(Spell spell){
|
||||
return (int)this.recentSpells.stream().filter(s -> s == spell).count(); // We know this can't be more than 10
|
||||
return (int)this.recentSpells.stream().filter(s -> s == spell).count(); // We know this can't be more than 5
|
||||
}
|
||||
|
||||
// Imbuements
|
||||
@@ -514,12 +515,12 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
|
||||
NBTTagCompound properties = new NBTTagCompound();
|
||||
|
||||
properties.setTag("imbuements", NBTExtras.mapToNBT(this.imbuementDurations,
|
||||
NBTExtras.storeTagSafely(properties, "imbuements", NBTExtras.mapToNBT(this.imbuementDurations,
|
||||
imbuement -> new NBTTagInt(Enchantment.getEnchantmentID((Enchantment)imbuement)), NBTTagInt::new));
|
||||
|
||||
// Mmmmmm Java 8....
|
||||
properties.setTag("allies", NBTExtras.listToNBT(this.allies, NBTUtil::createUUIDTag));
|
||||
properties.setTag("allyNames", NBTExtras.listToNBT(this.allyNames, NBTTagString::new));
|
||||
NBTExtras.storeTagSafely(properties, "allies", NBTExtras.listToNBT(this.allies, NBTUtil::createUUIDTag));
|
||||
NBTExtras.storeTagSafely(properties, "allyNames", NBTExtras.listToNBT(this.allyNames, NBTTagString::new));
|
||||
|
||||
// Might be worth converting this over to WizardryUtilities.listToNBT.
|
||||
int[] spells = new int[this.spellsDiscovered.size()];
|
||||
@@ -530,7 +531,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
}
|
||||
properties.setIntArray("discoveredSpells", spells);
|
||||
|
||||
properties.setTag("recentSpells", NBTExtras.listToNBT(recentSpells, s -> new NBTTagInt(s.metadata())));
|
||||
NBTExtras.storeTagSafely(properties, "recentSpells", NBTExtras.listToNBT(recentSpells, s -> new NBTTagInt(s.metadata())));
|
||||
|
||||
storedVariables.forEach(k -> k.write(properties, this.spellData.get(k)));
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ public class EnchantmentMagicProtection extends Enchantment {
|
||||
|
||||
public enum Type {
|
||||
|
||||
MAGIC("magic", 1, 5, 8, s -> s instanceof IElementalDamage),
|
||||
MAGIC("magic", 1, 5, 8, s -> s instanceof IElementalDamage || s.isMagicDamage()),
|
||||
FROST("frost", 2, 10, 8, s -> s instanceof IElementalDamage && ((IElementalDamage)s).getType() == MagicDamage.DamageType.FROST),
|
||||
SHOCK("shock", 2, 10, 8, s -> s instanceof IElementalDamage && ((IElementalDamage)s).getType() == MagicDamage.DamageType.SHOCK);
|
||||
// Fire already exists, and the other types aren't used enough to be worth having
|
||||
|
||||
@@ -120,9 +120,9 @@ public interface Imbuement {
|
||||
|
||||
ItemStack bow = archer.getHeldItemMainhand();
|
||||
|
||||
if(!ImbueWeapon.isBow(bow.getItem())){
|
||||
if(!ImbueWeapon.isBow(bow)){
|
||||
bow = archer.getHeldItemOffhand();
|
||||
if(!ImbueWeapon.isBow(bow.getItem())) return;
|
||||
if(!ImbueWeapon.isBow(bow)) return;
|
||||
}
|
||||
|
||||
// Taken directly from ItemBow, so it works exactly the same as the power enchantment.
|
||||
|
||||
@@ -5,6 +5,7 @@ import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.AllyDesignationSystem;
|
||||
import electroblob.wizardry.util.MagicDamage;
|
||||
import electroblob.wizardry.util.NBTExtras;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.block.Block;
|
||||
@@ -183,7 +184,7 @@ public class EntityLevitatingBlock extends EntityFallingBlock implements IEntity
|
||||
NBTBase nbtbase = this.tileEntityData.getTag(s);
|
||||
|
||||
if(!"x".equals(s) && !"y".equals(s) && !"z".equals(s)){
|
||||
nbttagcompound.setTag(s, nbtbase.copy());
|
||||
NBTExtras.storeTagSafely(nbttagcompound, s, nbtbase.copy());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@ import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryBlocks;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Meteor;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.MoverType;
|
||||
import net.minecraft.entity.item.EntityFallingBlock;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.world.World;
|
||||
@@ -61,9 +63,9 @@ public class EntityMeteor extends EntityFallingBlock {
|
||||
this.motionY *= 0.9800000190734863D;
|
||||
this.motionZ *= 0.9800000190734863D;
|
||||
|
||||
if(!this.world.isRemote){
|
||||
if(this.onGround){
|
||||
|
||||
if(this.onGround){
|
||||
if(!this.world.isRemote){
|
||||
|
||||
this.motionX *= 0.699999988079071D;
|
||||
this.motionZ *= 0.699999988079071D;
|
||||
@@ -72,8 +74,13 @@ public class EntityMeteor extends EntityFallingBlock {
|
||||
Spells.meteor.getProperty(Meteor.BLAST_STRENGTH).floatValue() * blastMultiplier,
|
||||
damageBlocks, damageBlocks);
|
||||
this.setDead();
|
||||
|
||||
}else{
|
||||
WizardryUtilities.getEntitiesWithinRadius(15, posX, posY, posZ, world, EntityPlayer.class)
|
||||
.forEach(p -> Wizardry.proxy.shakeScreen(p, 10));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -65,7 +65,7 @@ public class EntityBubble extends EntityMagicConstruct {
|
||||
if(isDarkOrb){
|
||||
|
||||
if(WizardryUtilities.getRider(this) != null
|
||||
&& this.ticksExisted % Spells.entrapment.getProperty(Entrapment.DAMAGE_INTERVAL).intValue() == 0){
|
||||
&& WizardryUtilities.getRider(this).ticksExisted % Spells.entrapment.getProperty(Entrapment.DAMAGE_INTERVAL).intValue() == 0){
|
||||
if(this.getCaster() != null){
|
||||
WizardryUtilities.getRider(this).attackEntityFrom(
|
||||
MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.MAGIC),
|
||||
|
||||
@@ -33,7 +33,8 @@ public class EntityCombustionRune extends EntityMagicConstruct {
|
||||
|
||||
float strength = Spells.combustion_rune.getProperty(Spell.BLAST_RADIUS).floatValue();
|
||||
|
||||
world.newExplosion(this.getCaster(), this.posX, this.posY, this.posZ, strength, true, true);
|
||||
world.newExplosion(this.getCaster(), this.posX, this.posY, this.posZ, strength, true,
|
||||
getCaster() != null && WizardryUtilities.canDamageBlocks(getCaster(), world));
|
||||
|
||||
// The trap is destroyed once triggered.
|
||||
this.setDead();
|
||||
|
||||
@@ -7,7 +7,6 @@ import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.item.EntityFallingBlock;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.network.play.server.SPacketEntityVelocity;
|
||||
@@ -97,18 +96,6 @@ public class EntityEarthquake extends EntityMagicConstruct {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!world.isRemote){
|
||||
// Constant 15 blocks for now
|
||||
List<EntityPlayer> targets2 = WizardryUtilities.getEntitiesWithinRadius(15, posX, posY, posZ, world, EntityPlayer.class);
|
||||
|
||||
float magnitude = 10f * ((float)(this.lifetime - this.ticksExisted))/(float)this.lifetime;
|
||||
|
||||
// Makes the screen shake
|
||||
for(EntityPlayer target : targets2){
|
||||
target.rotationPitch += this.ticksExisted % 2 == 0 ? magnitude : -magnitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,8 +80,8 @@ public class EntityHammer extends EntityMagicConstruct {
|
||||
|
||||
if(this.world.isRemote && this.ticksExisted % 3 == 0){
|
||||
ParticleBuilder.create(Type.SPARK)
|
||||
.pos(this.posX - 0.5d + rand.nextDouble(), this.posY + 2 * rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble())
|
||||
.spawn(world);
|
||||
.pos(this.posX - 0.5d + rand.nextDouble(), this.posY + 2 * rand.nextDouble(), this.posZ - 0.5d + rand.nextDouble())
|
||||
.spawn(world);
|
||||
}
|
||||
|
||||
this.prevPosX = this.posX;
|
||||
@@ -103,39 +103,37 @@ public class EntityHammer extends EntityMagicConstruct {
|
||||
this.rotationPitch = 0;
|
||||
this.spin = false;
|
||||
|
||||
if(this.ticksExisted % Spells.lightning_hammer.getProperty(LightningHammer.ATTACK_INTERVAL).floatValue() == 0){
|
||||
double seekerRange = Spells.lightning_hammer.getProperty(Spell.EFFECT_RADIUS).doubleValue();
|
||||
|
||||
double seekerRange = Spells.lightning_hammer.getProperty(Spell.EFFECT_RADIUS).doubleValue();
|
||||
List<EntityLivingBase> targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX,
|
||||
this.posY + 1, this.posZ, world);
|
||||
|
||||
List<EntityLivingBase> targets = WizardryUtilities.getEntitiesWithinRadius(seekerRange, this.posX,
|
||||
this.posY + 1, this.posZ, world);
|
||||
int maxTargets = Spells.lightning_hammer.getProperty(LightningHammer.SECONDARY_MAX_TARGETS).intValue();
|
||||
while(targets.size() > maxTargets) targets.remove(targets.size() - 1);
|
||||
|
||||
int maxTargets = Spells.lightning_hammer.getProperty(LightningHammer.SECONDARY_MAX_TARGETS).intValue();
|
||||
while(targets.size() > maxTargets) targets.remove(targets.size() - 1);
|
||||
for(EntityLivingBase target : targets){
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
if(WizardryUtilities.isLiving(target) && this.isValidTarget(target)
|
||||
&& target.ticksExisted % Spells.lightning_hammer.getProperty(LightningHammer.ATTACK_INTERVAL).floatValue() == 0){
|
||||
|
||||
if(WizardryUtilities.isLiving(target) && this.isValidTarget(target)){
|
||||
if(world.isRemote){
|
||||
|
||||
if(world.isRemote){
|
||||
ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world);
|
||||
|
||||
ParticleBuilder.create(Type.LIGHTNING).pos(posX, posY + height - 0.1, posZ) .target(target).spawn(world);
|
||||
ParticleBuilder.spawnShockParticles(world, target.posX,
|
||||
target.getEntityBoundingBox().minY + target.height, target.posZ);
|
||||
}
|
||||
|
||||
ParticleBuilder.spawnShockParticles(world, target.posX,
|
||||
target.getEntityBoundingBox().minY + target.height, target.posZ);
|
||||
}
|
||||
target.playSound(WizardrySounds.ENTITY_HAMMER_ATTACK, 1.0F, rand.nextFloat() * 0.4F + 1.5F);
|
||||
|
||||
target.playSound(WizardrySounds.ENTITY_HAMMER_ATTACK, 1.0F, rand.nextFloat() * 0.4F + 1.5F);
|
||||
float damage = Spells.lightning_hammer.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier;
|
||||
|
||||
float damage = Spells.lightning_hammer.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier;
|
||||
|
||||
if(this.getCaster() != null){
|
||||
WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage(
|
||||
this, getCaster(), DamageType.SHOCK), damage);
|
||||
WizardryUtilities.applyStandardKnockback(this, target);
|
||||
}else{
|
||||
target.attackEntityFrom(DamageSource.MAGIC, damage);
|
||||
}
|
||||
if(this.getCaster() != null){
|
||||
WizardryUtilities.attackEntityWithoutKnockback(target, MagicDamage.causeIndirectMagicDamage(
|
||||
this, getCaster(), DamageType.SHOCK), damage);
|
||||
WizardryUtilities.applyStandardKnockback(this, target);
|
||||
}else{
|
||||
target.attackEntityFrom(DamageSource.MAGIC, damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,6 +169,7 @@ public class EntityHammer extends EntityMagicConstruct {
|
||||
public void fall(float distance, float damageMultiplier){
|
||||
|
||||
if(world.isRemote){
|
||||
|
||||
for(int i = 0; i < 40; i++){
|
||||
double particleX = this.posX - 1.0d + 2 * rand.nextDouble();
|
||||
double particleZ = this.posZ - 1.0d + 2 * rand.nextDouble();
|
||||
@@ -182,6 +181,12 @@ public class EntityHammer extends EntityMagicConstruct {
|
||||
particleX - this.posX, 0, particleZ - this.posZ, Block.getStateId(block));
|
||||
}
|
||||
}
|
||||
|
||||
if(this.fallDistance > 10){
|
||||
WizardryUtilities.getEntitiesWithinRadius(10, posX, posY, posZ, world, EntityPlayer.class)
|
||||
.forEach(p -> Wizardry.proxy.shakeScreen(p, 6));
|
||||
}
|
||||
|
||||
}else{
|
||||
// Just to check the hammer has actually fallen from the sky, rather than the block under it being broken.
|
||||
if(this.fallDistance > 10){
|
||||
|
||||
@@ -62,7 +62,7 @@ public class EntityHealAura extends EntityMagicConstruct {
|
||||
target.motionZ = velZ;
|
||||
}
|
||||
|
||||
}else if(target.getHealth() < target.getMaxHealth() && this.ticksExisted % 5 == 0){
|
||||
}else if(target.getHealth() < target.getMaxHealth() && target.ticksExisted % 5 == 0){
|
||||
target.heal(Spells.healing_aura.getProperty(Spell.HEALTH).floatValue() * damageMultiplier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.MoverType;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
@@ -29,9 +30,9 @@ public class EntityIceSpike extends EntityMagicConstruct {
|
||||
this.setRotation(-facing.getHorizontalAngle(), WizardryUtilities.getPitch(facing));
|
||||
float yaw = (-facing.getHorizontalAngle()) * (float)Math.PI/180;
|
||||
float pitch = (WizardryUtilities.getPitch(facing) - 90) * (float)Math.PI/180;
|
||||
Vec3d min = new Vec3d(-width/2, 0, -width/2).rotatePitch(pitch).rotateYaw(yaw);
|
||||
Vec3d max = new Vec3d(width/2, height, width/2).rotatePitch(pitch).rotateYaw(yaw);
|
||||
this.setEntityBoundingBox(new AxisAlignedBB(this.getPositionVector().add(min), this.getPositionVector().add(max)));
|
||||
Vec3d min = this.getPositionVector().add(new Vec3d(-width/2, 0, -width/2).rotatePitch(pitch).rotateYaw(yaw));
|
||||
Vec3d max = this.getPositionVector().add(new Vec3d(width/2, height, width/2).rotatePitch(pitch).rotateYaw(yaw));
|
||||
this.setEntityBoundingBox(new AxisAlignedBB(min.x, min.y, min.z, max.x, max.y, max.z));
|
||||
}
|
||||
|
||||
public EnumFacing getFacing(){
|
||||
@@ -61,10 +62,9 @@ public class EntityIceSpike extends EntityMagicConstruct {
|
||||
if(!this.world.isRemote){
|
||||
for(Object entity : this.world.getEntitiesWithinAABBExcludingEntity(this, this.getEntityBoundingBox())){
|
||||
if(entity instanceof EntityLivingBase && this.isValidTarget((EntityLivingBase)entity)){
|
||||
DamageSource source = this.getCaster() == null ? DamageSource.MAGIC : MagicDamage.causeDirectMagicDamage(this.getCaster(), DamageType.FROST);
|
||||
// Potion effect only gets added if the damage succeeded.
|
||||
if(((EntityLivingBase)entity).attackEntityFrom(
|
||||
MagicDamage.causeDirectMagicDamage(this.getCaster(), DamageType.FROST),
|
||||
Spells.ice_spikes.getProperty(Spell.DAMAGE).floatValue() * this.damageMultiplier))
|
||||
if(((EntityLivingBase)entity).attackEntityFrom(source, Spells.ice_spikes.getProperty(Spell.DAMAGE).floatValue() * this.damageMultiplier))
|
||||
((EntityLivingBase)entity).addPotionEffect(new PotionEffect(WizardryPotions.frost,
|
||||
Spells.ice_spikes.getProperty(Spell.EFFECT_DURATION).intValue(),
|
||||
Spells.ice_spikes.getProperty(Spell.EFFECT_STRENGTH).intValue()));
|
||||
|
||||
@@ -213,6 +213,7 @@ public class EntityAIAttackSpell<T extends EntityLiving & ISpellCaster> extends
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is only called when spell casting starts so ticksInUse is always zero
|
||||
if(spell.cast(attacker.world, attacker, EnumHand.MAIN_HAND, 0, target, modifiers)){
|
||||
|
||||
if(spell.isContinuous){
|
||||
|
||||
@@ -15,6 +15,8 @@ import net.minecraft.world.World;
|
||||
|
||||
public class EntityDecoy extends EntitySummonedCreature {
|
||||
|
||||
// TODO: These guys need sounds!
|
||||
|
||||
/** Creates a new decoy in the given world. */
|
||||
public EntityDecoy(World world){
|
||||
super(world);
|
||||
|
||||
@@ -35,11 +35,17 @@ import net.minecraft.world.DifficultyInstance;
|
||||
import net.minecraft.world.EnumDifficulty;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntityAdditionalSpawnData {
|
||||
|
||||
private EntityAIAttackSpell<EntityEvilWizard> spellCastingAI = new EntityAIAttackSpell<>(this, 0.5D, 14.0F, 30, 50);
|
||||
@@ -68,6 +74,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
// Field implementations
|
||||
private List<Spell> spells = new ArrayList<Spell>(4);
|
||||
private Spell continuousSpell;
|
||||
private int spellCounter;
|
||||
|
||||
public EntityEvilWizard(World world){
|
||||
|
||||
@@ -169,6 +176,16 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
public Spell getContinuousSpell(){
|
||||
return this.continuousSpell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpellCounter(int count){
|
||||
spellCounter = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpellCounter(){
|
||||
return spellCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAimingError(EnumDifficulty difficulty){
|
||||
@@ -246,7 +263,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
// When right-clicked with a spell book in creative, sets one of the spells to that spell
|
||||
if(player.isCreative() && stack.getItem() instanceof ItemSpellBook){
|
||||
Spell spell = Spell.byMetadata(stack.getItemDamage());
|
||||
if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){
|
||||
if(this.spells.size() >= 4 && spell.canBeCastBy(this, true)){
|
||||
// The set(...) method returns the element that was replaced - neat!
|
||||
player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard",
|
||||
this.getDisplayName(), this.spells.set(rand.nextInt(3) + 1, spell).getNameForTranslationFormatted(),
|
||||
@@ -263,9 +280,9 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
super.writeEntityToNBT(nbt);
|
||||
nbt.setInteger("element", this.getElement().ordinal());
|
||||
nbt.setInteger("skin", this.textureIndex);
|
||||
nbt.setTag("spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata())));
|
||||
NBTExtras.storeTagSafely(nbt, "spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata())));
|
||||
nbt.setBoolean("hasStructure", this.hasStructure);
|
||||
nbt.setTag("groupUUIDs", NBTExtras.listToNBT(groupUUIDs, NBTUtil::createUUIDTag));
|
||||
NBTExtras.storeTagSafely(nbt, "groupUUIDs", NBTExtras.listToNBT(groupUUIDs, NBTUtil::createUUIDTag));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -283,16 +300,6 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
public int getMaxSpawnedInChunk(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCanSpawnHere(){
|
||||
// Evil wizards can only spawn in the specified dimensions
|
||||
for(int id : Wizardry.settings.mobSpawnDimensions){
|
||||
if(this.dimension == id) return super.getCanSpawnHere();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canDespawn(){
|
||||
@@ -373,7 +380,7 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
// All wizards know magic missile, even if it is disabled.
|
||||
spells.add(Spells.magic_missile);
|
||||
|
||||
Tier maxTier = EntityWizard.populateSpells(spells, element, hasStructure, 3, rand);
|
||||
Tier maxTier = EntityWizard.populateSpells(this, spells, element, hasStructure, 3, rand);
|
||||
|
||||
// Now done after the spells so it can take the tier into account. For evil wizards this is slightly different;
|
||||
// it picks a random wand which is at least a high enough tier for the spells the wizard has.
|
||||
@@ -393,4 +400,13 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
||||
textureIndex = data.readInt();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onCheckSpawnEvent(LivingSpawnEvent.CheckSpawn event){
|
||||
// We have no way of checking if it's a spawner in getCanSpawnHere() so this has to be done here instead
|
||||
if(event.getEntityLiving() instanceof EntityEvilWizard && !event.isSpawner()){
|
||||
if(!ArrayUtils.contains(Wizardry.settings.mobSpawnDimensions, event.getWorld().provider.getDimension()))
|
||||
event.setResult(Event.Result.DENY);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class EntityIceGiant extends EntityIronGolem implements ISummonedCreature
|
||||
this.tasks.addTask(6, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
|
||||
this.tasks.addTask(7, new EntityAILookIdle(this));
|
||||
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<EntityLivingBase>(this, EntityLivingBase.class,
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
|
||||
0, false, true, this.getTargetSelector()));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,13 @@ import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class EntityIceWraith extends EntityBlazeMinion {
|
||||
|
||||
/** The version from EntityLivingBase is only used in onLivingUpdate, so it can safely be copied. */
|
||||
@@ -185,12 +191,16 @@ public class EntityIceWraith extends EntityBlazeMinion {
|
||||
|
||||
@Override
|
||||
public boolean getCanSpawnHere(){
|
||||
// Only spawns in the specified dimensions
|
||||
for(int id : Wizardry.settings.mobSpawnDimensions){
|
||||
if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel();
|
||||
}
|
||||
return super.getCanSpawnHere() && this.isValidLightLevel();
|
||||
}
|
||||
|
||||
return false;
|
||||
@SubscribeEvent
|
||||
public static void onCheckSpawnEvent(LivingSpawnEvent.CheckSpawn event){
|
||||
// We have no way of checking if it's a spawner in getCanSpawnHere() so this has to be done here instead
|
||||
if(event.getEntityLiving() instanceof EntityLightningWraith && !event.isSpawner()){
|
||||
if(!ArrayUtils.contains(Wizardry.settings.mobSpawnDimensions, event.getWorld().provider.getDimension()))
|
||||
event.setResult(Event.Result.DENY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,13 @@ import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class EntityLightningWraith extends EntityBlazeMinion {
|
||||
|
||||
public EntityLightningWraith(World world){
|
||||
@@ -74,14 +80,17 @@ public class EntityLightningWraith extends EntityBlazeMinion {
|
||||
|
||||
@Override
|
||||
public boolean getCanSpawnHere(){
|
||||
// Only spawns in the specified dimensions, during thunderstorms
|
||||
if(!world.isThundering()) return false;
|
||||
return super.getCanSpawnHere() && this.isValidLightLevel();
|
||||
}
|
||||
|
||||
for(int id : Wizardry.settings.mobSpawnDimensions){
|
||||
if(this.dimension == id) return super.getCanSpawnHere() && this.isValidLightLevel();
|
||||
@SubscribeEvent
|
||||
public static void onCheckSpawnEvent(LivingSpawnEvent.CheckSpawn event){
|
||||
// We have no way of checking if it's a spawner in getCanSpawnHere() so this has to be done here instead
|
||||
if(event.getEntityLiving() instanceof EntityLightningWraith && !event.isSpawner()){
|
||||
if(!event.getWorld().isThundering()) event.setResult(Event.Result.DENY);
|
||||
if(!ArrayUtils.contains(Wizardry.settings.mobSpawnDimensions, event.getWorld().provider.getDimension()))
|
||||
event.setResult(Event.Result.DENY);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -120,8 +120,10 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature {
|
||||
&& ((EntityLivingBase)this.getRidingEntity()).getHealth() > 0){
|
||||
if(this.ticksExisted % 16 == 1){
|
||||
this.getRidingEntity().attackEntityFrom(DamageSource.MAGIC, 1);
|
||||
((EntityLivingBase)this.getRidingEntity())
|
||||
.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 20, 2));
|
||||
if(this.getRidingEntity() != null){ // Some mobs force-dismount when attacked (normally when dying)
|
||||
((EntityLivingBase)this.getRidingEntity())
|
||||
.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 20, 2));
|
||||
}
|
||||
this.playSound(WizardrySounds.ENTITY_MAGIC_SLIME_ATTACK, 1.0f, 1.0f);
|
||||
this.squishAmount = 0.5F;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste
|
||||
private EntityAIAttackSpell<EntityPhoenix> spellAttackAI = new EntityAIAttackSpell<>(this, AISpeed, 15f, 60, 140);
|
||||
|
||||
private Spell continuousSpell;
|
||||
private int spellCounter;
|
||||
|
||||
private static final List<Spell> attack = Collections.singletonList(Spells.flame_ray);
|
||||
|
||||
@@ -50,7 +51,7 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste
|
||||
this.tasks.addTask(3, new EntityAILookIdle(this));
|
||||
// this.targetTasks.addTask(0, new EntityAIMoveTowardsTarget(this, 1, 10));
|
||||
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true));
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<EntityLivingBase>(this, EntityLivingBase.class,
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
|
||||
0, false, true, this.getTargetSelector()));
|
||||
|
||||
this.setAIMoveSpeed((float)AISpeed);
|
||||
@@ -76,6 +77,16 @@ public class EntityPhoenix extends EntitySummonedCreature implements ISpellCaste
|
||||
continuousSpell = spell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpellCounter(int count){
|
||||
spellCounter = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpellCounter(){
|
||||
return spellCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRangedAttack(){
|
||||
return true;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell
|
||||
this.tasks.addTask(2, new EntityAIWander(this, AISpeed));
|
||||
this.tasks.addTask(3, new EntityAILookIdle(this));
|
||||
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true));
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<EntityLivingBase>(this, EntityLivingBase.class,
|
||||
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
|
||||
0, false, true, this.getTargetSelector()));
|
||||
|
||||
this.setAIMoveSpeed((float)AISpeed);
|
||||
@@ -61,21 +61,6 @@ public class EntityShadowWraith extends EntitySummonedCreature implements ISpell
|
||||
return attack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellModifiers getModifiers(){
|
||||
return new SpellModifiers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spell getContinuousSpell(){
|
||||
return Spells.none;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContinuousSpell(Spell spell){
|
||||
// Doesn't use continuous spells.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyEntityAttributes(){
|
||||
super.applyEntityAttributes();
|
||||
|
||||
@@ -59,21 +59,6 @@ public class EntityStormElemental extends EntitySummonedCreature implements ISpe
|
||||
return attack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellModifiers getModifiers(){
|
||||
return new SpellModifiers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spell getContinuousSpell(){
|
||||
return Spells.none;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContinuousSpell(Spell spell){
|
||||
// Doesn't use continuous spells.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyEntityAttributes(){
|
||||
super.applyEntityAttributes();
|
||||
|
||||
@@ -50,6 +50,7 @@ import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
@@ -83,6 +84,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
// Field implementations
|
||||
private List<Spell> spells = new ArrayList<Spell>(4);
|
||||
private Spell continuousSpell;
|
||||
private int spellCounter;
|
||||
|
||||
/** A set of the positions of the blocks that are part of this wizard's tower. */
|
||||
private Set<BlockPos> towerBlocks;
|
||||
@@ -187,7 +189,17 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
public Spell getContinuousSpell(){
|
||||
return this.continuousSpell;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setSpellCounter(int count){
|
||||
spellCounter = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpellCounter(){
|
||||
return spellCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAimingError(EnumDifficulty difficulty){
|
||||
// Being more intelligent than skeletons, wizards are a little more accurate.
|
||||
@@ -218,7 +230,8 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
// Copied from EntityVillager
|
||||
if(!this.world.isRemote && this.livingSoundTime > -this.getTalkInterval() + 20){
|
||||
this.livingSoundTime = -this.getTalkInterval();
|
||||
this.playSound(stack.isEmpty() ? WizardrySounds.ENTITY_WIZARD_NO : WizardrySounds.ENTITY_WIZARD_YES, this.getSoundVolume(), this.getSoundPitch());
|
||||
SoundEvent yes = Wizardry.tisTheSeason ? WizardrySounds.ENTITY_WIZARD_HOHOHO : WizardrySounds.ENTITY_WIZARD_YES;
|
||||
this.playSound(stack.isEmpty() ? WizardrySounds.ENTITY_WIZARD_NO : yes, this.getSoundVolume(), this.getSoundPitch());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,6 +269,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
|
||||
@Override
|
||||
protected SoundEvent getAmbientSound(){
|
||||
if(Wizardry.tisTheSeason) return WizardrySounds.ENTITY_WIZARD_HOHOHO;
|
||||
return this.isTrading() ? WizardrySounds.ENTITY_WIZARD_TRADING : WizardrySounds.ENTITY_WIZARD_AMBIENT;
|
||||
}
|
||||
|
||||
@@ -357,7 +371,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
// When right-clicked with a spell book in creative, sets one of the spells to that spell
|
||||
if(player.isCreative() && stack.getItem() instanceof ItemSpellBook){
|
||||
Spell spell = Spell.byMetadata(stack.getItemDamage());
|
||||
if(this.spells.size() >= 4 && spell.canBeCastByNPCs()){
|
||||
if(this.spells.size() >= 4 && spell.canBeCastBy(this, true)){
|
||||
// The set(...) method returns the element that was replaced - neat!
|
||||
player.sendMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":spell_book.apply_to_wizard",
|
||||
this.getDisplayName(), this.spells.set(rand.nextInt(3) + 1, spell).getNameForTranslationFormatted(),
|
||||
@@ -387,15 +401,15 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
super.writeEntityToNBT(nbt);
|
||||
|
||||
if(this.trades != null){
|
||||
nbt.setTag("trades", this.trades.getRecipiesAsTags());
|
||||
NBTExtras.storeTagSafely(nbt, "trades", this.trades.getRecipiesAsTags());
|
||||
}
|
||||
|
||||
nbt.setInteger("element", this.getElement().ordinal());
|
||||
nbt.setInteger("skin", this.textureIndex);
|
||||
nbt.setTag("spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata())));
|
||||
NBTExtras.storeTagSafely(nbt, "spells", NBTExtras.listToNBT(spells, spell -> new NBTTagInt(spell.metadata())));
|
||||
|
||||
if(this.towerBlocks != null && this.towerBlocks.size() > 0){
|
||||
nbt.setTag("towerBlocks", NBTExtras.listToNBT(this.towerBlocks, NBTUtil::createPosTag));
|
||||
NBTExtras.storeTagSafely(nbt, "towerBlocks", NBTExtras.listToNBT(this.towerBlocks, NBTUtil::createPosTag));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +428,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
this.spells = (List<Spell>)NBTExtras.NBTToList(nbt.getTagList("spells", NBT.TAG_INT),
|
||||
(NBTTagInt tag) -> Spell.byMetadata(tag.getInt()));
|
||||
|
||||
NBTTagList tagList = nbt.getTagList("towerBlocks", NBT.TAG_LONG);
|
||||
NBTTagList tagList = nbt.getTagList("towerBlocks", NBT.TAG_COMPOUND);
|
||||
if(!tagList.isEmpty()){
|
||||
this.towerBlocks = new HashSet<>(NBTExtras.NBTToList(tagList, NBTUtil::getPosFromTag));
|
||||
}else{
|
||||
@@ -489,7 +503,6 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
ItemStack anySpellBook = new ItemStack(WizardryItems.spell_book, 1, OreDictionary.WILDCARD_VALUE);
|
||||
ItemStack crystalStack = new ItemStack(WizardryItems.magic_crystal, 5);
|
||||
|
||||
// NOTE: For wizardry 1.2, increase the number of uses of this trade. The default is 7, for reference.
|
||||
this.trades.add(new MerchantRecipe(anySpellBook, crystalStack));
|
||||
|
||||
this.addRandomRecipes(3);
|
||||
@@ -574,12 +587,14 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
|
||||
// TODO: Switch all of this over to some kind of loot pool system?
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ItemStack getRandomPrice(Tier tier){
|
||||
|
||||
Map<ResourceLocation, Integer> map = Wizardry.settings.currencyItems;
|
||||
Map<Pair<ResourceLocation, Short>, Integer> map = Wizardry.settings.currencyItems;
|
||||
// This isn't that efficient but it's not called very often really so it doesn't matter
|
||||
ResourceLocation itemName = map.keySet().toArray(new ResourceLocation[0])[rand.nextInt(map.size())];
|
||||
Item item = Item.REGISTRY.getObject(itemName);
|
||||
Pair<ResourceLocation, Short> itemName = map.keySet().toArray(new Pair[0])[rand.nextInt(map.size())];
|
||||
Item item = Item.REGISTRY.getObject(itemName.getLeft());
|
||||
short meta = itemName.getRight();
|
||||
int value;
|
||||
|
||||
if(item == null){
|
||||
@@ -593,7 +608,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
// ((tier.ordinal() + 1) * 16 + rand.nextInt(6)) gives a 'value' for the item being bought
|
||||
// This is then divided by the value of the currency item to give a price
|
||||
// The absolute maximum stack size that can result from this calculation (with value = 1) is 64.
|
||||
return new ItemStack(item, (8 + tier.ordinal() * 16 + rand.nextInt(9)) / value);
|
||||
return new ItemStack(item, (8 + tier.ordinal() * 16 + rand.nextInt(9)) / value, meta);
|
||||
}
|
||||
|
||||
private ItemStack getRandomItemOfTier(Tier tier){
|
||||
@@ -750,7 +765,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
// All wizards know magic missile, even if it is disabled.
|
||||
spells.add(Spells.magic_missile);
|
||||
|
||||
Tier maxTier = populateSpells(spells, element, false, 3, rand);
|
||||
Tier maxTier = populateSpells(this, spells, element, false, 3, rand);
|
||||
|
||||
// Now done after the spells so it can take the tier into account.
|
||||
ItemStack wand = new ItemStack(WizardryItems.getWand(maxTier, element));
|
||||
@@ -767,19 +782,22 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
/**
|
||||
* Adds n random spells to the given list. The spells will be of the given element if possible. Extracted as a
|
||||
* separate function since it was the same in both EntityWizard and EntityEvilWizard.
|
||||
*
|
||||
*
|
||||
* @param wizard The wizard whose spells are to be populated.
|
||||
* @param spells The spell list to be populated.
|
||||
* @param e The element that the spells should belong to, or {@link Element#MAGIC} for a random element each time.
|
||||
* @param master Whether to include master spells.
|
||||
* @param n The number of spells to add.
|
||||
* @param random A random number generator to use.
|
||||
* @return The tier of the highest-tier spell that was added to the list.
|
||||
*/
|
||||
static Tier populateSpells(List<Spell> spells, Element e, boolean master, int n, Random random){
|
||||
static Tier populateSpells(final EntityLiving wizard, List<Spell> spells, Element e, boolean master, int n, Random random){
|
||||
|
||||
// This is the tier of the highest tier spell added.
|
||||
Tier maxTier = Tier.NOVICE;
|
||||
|
||||
List<Spell> npcSpells = Spell.getSpells(Spell.npcSpells);
|
||||
List<Spell> npcSpells = Spell.getSpells(s -> s.canBeCastBy(wizard, false));
|
||||
npcSpells.removeIf(s -> !s.applicableForItem(WizardryItems.spell_book));
|
||||
|
||||
for(int i = 0; i < n; i++){
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ import java.util.List;
|
||||
* packets) is handled by that class, and all the implementor needs to do is decide which spell(s) to select.
|
||||
* <p></p>
|
||||
* This class also allows Wizardry to do all the syncing necessary for continuous spell casting. All the implementor
|
||||
* needs to do is store the actual fields involved.
|
||||
* needs to do is store the actual fields involved, by implementing {@link ISpellCaster#setContinuousSpell(Spell)},
|
||||
* {@link ISpellCaster#getContinuousSpell()}, {@link ISpellCaster#setSpellCounter(int)}, {@link ISpellCaster#getSpellCounter()}
|
||||
* and {@link ISpellCaster#getModifiers()}.
|
||||
*/
|
||||
/* Perhaps this should be a capability? Though I can't help thinking they're mainly for attaching data to vanilla
|
||||
* classes, rather than custom ones. For now, the main purpose of this is to centralise code within wizardry itself, and
|
||||
@@ -36,10 +38,10 @@ public interface ISpellCaster {
|
||||
*
|
||||
* @return A list of {@link Spell} instances. A random spell from this list will be cast when the entity attacks.
|
||||
* The list will not be modified by the AI class and can therefore be an immutable list. The spells in the
|
||||
* list <b>must</b> be castable by NPCs (i.e. {@link Spell#canBeCastByNPCs()} returns true).
|
||||
* list <b>must</b> be castable by NPCs (i.e. {@link Spell#canBeCastBy(net.minecraft.entity.EntityLiving, boolean)} returns true).
|
||||
*/
|
||||
@Nonnull
|
||||
public List<Spell> getSpells();
|
||||
List<Spell> getSpells();
|
||||
|
||||
/**
|
||||
* Called each time the entity attacks to get the modifiers to apply to the spell.
|
||||
@@ -48,31 +50,47 @@ public interface ISpellCaster {
|
||||
* required, pass in an empty {@code SpellModifiers} object.
|
||||
*/
|
||||
@Nonnull
|
||||
public SpellModifiers getModifiers();
|
||||
default SpellModifiers getModifiers(){
|
||||
return new SpellModifiers(); // May seem wasteful but this should never be called so it doesn't matter
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the continuous spell that is currently being cast, or the None spell if there is none. Implementors
|
||||
* should simply store this as a private field and return it here. Will be synced by the AI class, but whether it is
|
||||
* saved to NBT is up to you. If the implementing class does not deal with continuous spells, just return
|
||||
* {@link Spells#none}. If the implementing class only ever uses one continuous spell, do <b>not</b> just return
|
||||
* that spell; the field must still be stored.
|
||||
* saved to NBT is up to you. If the implementing class only ever uses one continuous spell, do <b>not</b> just
|
||||
* return that spell; the field must still be stored.
|
||||
*/
|
||||
@Nonnull
|
||||
public Spell getContinuousSpell();
|
||||
default Spell getContinuousSpell(){
|
||||
return Spells.none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the continuous spell that is currently being cast, or the None spell if there is none. Implementors should
|
||||
* simply store this as a private field and assign it here. Will be synced by the AI class, but whether it is saved
|
||||
* to NBT is up to you. If the implementing class does not deal with continuous spells, leave this method blank.
|
||||
*/
|
||||
public void setContinuousSpell(Spell spell);
|
||||
default void setContinuousSpell(Spell spell){
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/** Returns the number of ticks the current spell has been cast for. Implementors should simply store this as a
|
||||
* private field and return it here. This is only used client-side. */
|
||||
default int getSpellCounter(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Sets the number of ticks the current spell has been cast for. Implementors should simply store this as a
|
||||
* private field and assign it here. This is only used client-side. */
|
||||
default void setSpellCounter(int count){
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the aiming arror for the given difficulty, used in projectile spells. Defaults to the values used by
|
||||
* Returns the aiming error for the given difficulty, used in projectile spells. Defaults to the values used by
|
||||
* skeletons, which are: Easy - 10, Normal - 6, Hard - 2, Peaceful - 10 (rarely used).
|
||||
*/
|
||||
// This is what default methods are actually intended for!
|
||||
public default int getAimingError(EnumDifficulty difficulty) {
|
||||
default int getAimingError(EnumDifficulty difficulty) {
|
||||
return WizardryUtilities.getDefaultAimingError(difficulty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,8 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData, IEntityOw
|
||||
* possible for implementors to override this in order to do something special when selecting a target.
|
||||
*/
|
||||
default Predicate<Entity> getTargetSelector(){
|
||||
return entity -> getCaster() == null ? entity instanceof EntityPlayer : !entity.isInvisible() && isValidTarget(entity);
|
||||
return entity -> !entity.isInvisible() && (getCaster() == null ? entity instanceof EntityPlayer &&
|
||||
!((EntityPlayer)entity).isCreative() : isValidTarget(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,6 @@ import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
@@ -48,13 +47,7 @@ public class EntityIceball extends EntityMagicProjectile {
|
||||
|
||||
}else{
|
||||
|
||||
boolean flag = true;
|
||||
|
||||
if(this.getThrower() != null && this.getThrower() instanceof EntityLiving){
|
||||
flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this.getThrower());
|
||||
}
|
||||
|
||||
if(flag){
|
||||
if(this.getThrower() == null || WizardryUtilities.canDamageBlocks(this.getThrower(), world)){
|
||||
|
||||
BlockPos pos = rayTrace.getBlockPos();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package electroblob.wizardry.entity.projectile;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.entity.projectile.EntityLargeFireball;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
@@ -50,7 +51,7 @@ public class EntityLargeMagicFireball extends EntityMagicFireball {
|
||||
protected void onImpact(RayTraceResult rayTrace){
|
||||
|
||||
if(!world.isRemote){
|
||||
boolean flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this.thrower);
|
||||
boolean flag = this.getThrower() == null || WizardryUtilities.canDamageBlocks(this.getThrower(), world);
|
||||
this.world.newExplosion(null, this.posX, this.posY, this.posZ, getExplosionPower() * blastMultiplier, flag, flag);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,18 @@ import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.MagicDamage;
|
||||
import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.projectile.EntitySmallFireball;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
@@ -80,13 +84,7 @@ public class EntityMagicFireball extends EntityMagicProjectile {
|
||||
|
||||
}else{
|
||||
|
||||
boolean flag = true;
|
||||
|
||||
if(this.getThrower() != null && this.getThrower() instanceof EntityLiving){
|
||||
flag = net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this.getThrower());
|
||||
}
|
||||
|
||||
if(flag){
|
||||
if(this.getThrower() == null || WizardryUtilities.canDamageBlocks(this.getThrower(), world)){
|
||||
|
||||
BlockPos blockpos = rayTrace.getBlockPos().offset(rayTrace.sideHit);
|
||||
|
||||
@@ -131,6 +129,54 @@ public class EntityMagicFireball extends EntityMagicProjectile {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeCollidedWith(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCollisionBorderSize(){
|
||||
return 1.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean attackEntityFrom(DamageSource source, float amount){
|
||||
|
||||
if(this.isEntityInvulnerable(source)){
|
||||
return false;
|
||||
|
||||
}else{
|
||||
|
||||
this.markVelocityChanged();
|
||||
|
||||
if(source.getTrueSource() != null){
|
||||
|
||||
Vec3d vec3d = source.getTrueSource().getLookVec();
|
||||
|
||||
if(vec3d != null){
|
||||
|
||||
double speed = MathHelper.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ);
|
||||
|
||||
this.motionX = vec3d.x * speed;
|
||||
this.motionY = vec3d.y * speed;
|
||||
this.motionZ = vec3d.z * speed;
|
||||
|
||||
this.lifetime = 160;
|
||||
|
||||
}
|
||||
|
||||
if(source.getTrueSource() instanceof EntityLivingBase){
|
||||
this.setCaster((EntityLivingBase)source.getTrueSource());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setLifetime(int lifetime){
|
||||
this.lifetime = lifetime;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry.entity.projectile;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
@@ -44,15 +45,34 @@ public class EntityMagicMissile extends EntityMagicArrow {
|
||||
public void tickInAir(){
|
||||
|
||||
if(this.world.isRemote){
|
||||
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1)
|
||||
.time(20 + rand.nextInt(10)).spawn(world);
|
||||
|
||||
if(this.ticksExisted > 1){ // Don't spawn particles behind where it started!
|
||||
double x = posX - motionX/2;
|
||||
double y = posY - motionY/2;
|
||||
double z = posZ - motionZ/2;
|
||||
ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1)
|
||||
.time(20 + rand.nextInt(10)).spawn(world);
|
||||
|
||||
if(Wizardry.tisTheSeason){
|
||||
|
||||
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(0.8f, 0.15f, 0.15f)
|
||||
.time(20 + rand.nextInt(10)).spawn(world);
|
||||
|
||||
ParticleBuilder.create(Type.SNOW).pos(posX, posY, posZ).spawn(world);
|
||||
|
||||
if(this.ticksExisted > 1){ // Don't spawn particles behind where it started!
|
||||
double x = posX - motionX / 2;
|
||||
double y = posY - motionY / 2;
|
||||
double z = posZ - motionZ / 2;
|
||||
ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(0.15f, 0.7f, 0.15f)
|
||||
.time(20 + rand.nextInt(10)).spawn(world);
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1)
|
||||
.time(20 + rand.nextInt(10)).spawn(world);
|
||||
|
||||
if(this.ticksExisted > 1){ // Don't spawn particles behind where it started!
|
||||
double x = posX - motionX / 2;
|
||||
double y = posY - motionY / 2;
|
||||
double z = posZ - motionZ / 2;
|
||||
ParticleBuilder.create(Type.SPARKLE, rand, x, y, z, 0.03, true).clr(1, 1, 0.65f).fade(0.7f, 0, 1)
|
||||
.time(20 + rand.nextInt(10)).spawn(world);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public abstract class EntityMagicProjectile extends EntityThrowable implements I
|
||||
double dy = !this.hasNoGravity() ? target.getEntityBoundingBox().minY + (double)(target.height / 3.0f) - this.posY
|
||||
: target.getEntityBoundingBox().minY + (double)(target.height / 2.0f) - this.posY;
|
||||
double dz = target.posZ - caster.posZ;
|
||||
double horizontalDistance = (double)MathHelper.sqrt(dx * dx + dz * dz);
|
||||
double horizontalDistance = MathHelper.sqrt(dx * dx + dz * dz);
|
||||
|
||||
if(horizontalDistance >= 1.0E-7D){
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
@@ -66,12 +65,11 @@ public class EntitySmokeBomb extends EntityBomb {
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
if(target != this.getThrower()){
|
||||
// Gives the target blindness if it is a player, mind trick otherwise (since this has the desired
|
||||
// Gives the target blindness, and mind trick if it's not a player (since this has the desired
|
||||
// effect of preventing targeting)
|
||||
if(target instanceof EntityPlayer){
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
|
||||
}else if(target instanceof EntityLiving){
|
||||
// New AI
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
|
||||
|
||||
if(target instanceof EntityLiving){
|
||||
((EntityLiving)target).setAttackTarget(null);
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.mind_trick, duration, 0));
|
||||
}
|
||||
|
||||
+27
-3
@@ -1,11 +1,17 @@
|
||||
package electroblob.wizardry.integration.antiqueatlas;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import hunternif.mc.atlas.AntiqueAtlasMod;
|
||||
import hunternif.mc.atlas.api.AtlasAPI;
|
||||
import hunternif.mc.atlas.marker.GlobalMarkersData;
|
||||
import hunternif.mc.atlas.marker.Marker;
|
||||
import hunternif.mc.atlas.registry.MarkerType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
import net.minecraftforge.fml.common.Loader;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
/**
|
||||
* This class handles all of wizardry's integration with the <i>Antique Atlas</i> mod. This class contains only the code
|
||||
@@ -15,6 +21,7 @@ import net.minecraftforge.fml.common.Loader;
|
||||
* @since Wizardry 4.2
|
||||
* @author Electroblob
|
||||
*/
|
||||
@Mod.EventBusSubscriber
|
||||
public class WizardryAntiqueAtlasIntegration {
|
||||
|
||||
public static final String ANTIQUE_ATLAS_MOD_ID = "antiqueatlas";
|
||||
@@ -38,7 +45,7 @@ public class WizardryAntiqueAtlasIntegration {
|
||||
* {@link electroblob.wizardry.Settings#autoTowerMarkers} is enabled. Server side only! */
|
||||
public static void markTower(World world, int x, int z){
|
||||
if(enabled() && Wizardry.settings.autoTowerMarkers){
|
||||
AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, TOWER_MARKER.toString(), "integration.antiqueatlas.marker." + TOWER_MARKER.toString(), x, z);
|
||||
AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, TOWER_MARKER.toString(), "integration.antiqueatlas.marker." + TOWER_MARKER.toString().replace(':', '.'), x, z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +53,7 @@ public class WizardryAntiqueAtlasIntegration {
|
||||
* {@link electroblob.wizardry.Settings#autoObeliskMarkers} is enabled. Server side only! */
|
||||
public static void markObelisk(World world, int x, int z){
|
||||
if(enabled() && Wizardry.settings.autoObeliskMarkers){
|
||||
AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, OBELISK_MARKER.toString(), "integration.antiqueatlas.marker." + OBELISK_MARKER.toString(), x, z);
|
||||
AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, OBELISK_MARKER.toString(), "integration.antiqueatlas.marker." + OBELISK_MARKER.toString().replace(':', '.'), x, z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +61,7 @@ public class WizardryAntiqueAtlasIntegration {
|
||||
* {@link electroblob.wizardry.Settings#autoShrineMarkers} is enabled. Server side only! */
|
||||
public static void markShrine(World world, int x, int z){
|
||||
if(enabled() && Wizardry.settings.autoShrineMarkers){
|
||||
AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, SHRINE_MARKER.toString(), "integration.antiqueatlas.marker." + SHRINE_MARKER.toString(), x, z);
|
||||
AtlasAPI.getMarkerAPI().putGlobalMarker(world, false, SHRINE_MARKER.toString(), "integration.antiqueatlas.marker." + SHRINE_MARKER.toString().replace(':', '.'), x, z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,4 +75,21 @@ public class WizardryAntiqueAtlasIntegration {
|
||||
AtlasAPI.getMarkerAPI().registerMarker(new MarkerType(OBELISK_MARKER, new ResourceLocation(Wizardry.MODID, "textures/integration/antiqueatlas/obelisk.png")));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onWorldLoadEvent(WorldEvent.Load event){
|
||||
|
||||
if(!enabled()) return;
|
||||
|
||||
// Backwards compatibility for existing markers using the old translation key format (with colons)
|
||||
GlobalMarkersData data = AntiqueAtlasMod.globalMarkersData.getData();
|
||||
for(Marker marker : data.getMarkersInDimension(event.getWorld().provider.getDimension())){
|
||||
if(marker.getLabel().contains(":")){
|
||||
// Remove old-format markers and replace them with new ones
|
||||
data.removeMarker(marker.getId());
|
||||
AtlasAPI.getMarkerAPI().putGlobalMarker(event.getWorld(), marker.isVisibleAhead(), marker.getType(),
|
||||
marker.getLabel().replace(':', '.'), marker.getX(), marker.getZ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ public interface IConjuredItem {
|
||||
*/
|
||||
default int getMaxDamageFromNBT(ItemStack stack, Spell spell){
|
||||
|
||||
if(!spell.arePropertiesInitialised()) return 600; // Failsafe, some edge-cases call this during preInit
|
||||
|
||||
float baseDuration = spell.getProperty(SpellConjuration.ITEM_LIFETIME).floatValue();
|
||||
|
||||
if(stack.hasTagCompound() && stack.getTagCompound().hasKey(DURATION_MULTIPLIER_KEY)){
|
||||
|
||||
@@ -61,11 +61,10 @@ public class ItemArcaneTome extends Item {
|
||||
|
||||
Tier tier = Tier.values()[stack.getItemDamage()];
|
||||
Tier tier2 = Tier.values()[stack.getItemDamage() - 1];
|
||||
|
||||
tooltip.add(tier.getDisplayNameWithFormatting());
|
||||
tooltip.add("\u00A77" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":arcane_tome.desc1",
|
||||
tier2.getDisplayNameWithFormatting()));
|
||||
tooltip.add("\u00A77" + net.minecraft.client.resources.I18n.format("item." + Wizardry.MODID + ":arcane_tome.desc2",
|
||||
tier.getDisplayNameWithFormatting() + "\u00A77"));
|
||||
Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc",
|
||||
tier2.getDisplayNameWithFormatting() + "\u00A77", tier.getDisplayNameWithFormatting() + "\u00A77");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ public class ItemArtefact extends Item {
|
||||
|
||||
if(artefact == WizardryItems.ring_condensing){
|
||||
|
||||
if(world.isRemote && player.ticksExisted % 150 == 0){
|
||||
if(player.ticksExisted % 150 == 0){
|
||||
for(ItemStack stack : WizardryUtilities.getHotbar(player)){
|
||||
// Needs to be both of these interfaces because this ring only recharges wands
|
||||
// (or more accurately, chargeable spellcasting items)
|
||||
@@ -276,7 +276,7 @@ public class ItemArtefact extends Item {
|
||||
|
||||
}else if(artefact == WizardryItems.amulet_arcane_defence){
|
||||
|
||||
if(world.isRemote && player.ticksExisted % 300 == 0){
|
||||
if(player.ticksExisted % 300 == 0){
|
||||
for(ItemStack stack : player.getArmorInventoryList()){
|
||||
// IManaStoringItem is sufficient, since anything in the armour slots is probably armour
|
||||
if(stack.getItem() instanceof IManaStoringItem)
|
||||
@@ -375,7 +375,7 @@ public class ItemArtefact extends Item {
|
||||
if(artefact == WizardryItems.ring_battlemage){
|
||||
|
||||
if(player.getHeldItemOffhand().getItem() instanceof ISpellCastingItem
|
||||
&& ImbueWeapon.isSword(player.getHeldItemMainhand().getItem())){
|
||||
&& ImbueWeapon.isSword(player.getHeldItemMainhand())){
|
||||
modifiers.set(SpellModifiers.POTENCY, 1.1f * potency, false);
|
||||
}
|
||||
|
||||
@@ -601,7 +601,7 @@ public class ItemArtefact extends Item {
|
||||
|
||||
}else if(artefact == WizardryItems.amulet_transience){
|
||||
|
||||
if(player.getHealth() <= 2 && player.world.rand.nextFloat() < 0.25f){
|
||||
if(player.getHealth() <= 6 && player.world.rand.nextFloat() < 0.25f){
|
||||
player.addPotionEffect(new PotionEffect(WizardryPotions.transience, 300));
|
||||
player.addPotionEffect(new PotionEffect(MobEffects.INVISIBILITY, 300, 0, false, false));
|
||||
}
|
||||
@@ -639,6 +639,7 @@ public class ItemArtefact extends Item {
|
||||
|
||||
WizardryUtilities.getEntitiesWithinRadius(3, player.posX, player.posY, player.posZ, world).stream()
|
||||
.filter(WizardryUtilities::isLiving)
|
||||
.filter(e -> e != player)
|
||||
.min(Comparator.comparingDouble(player::getDistanceSq))
|
||||
.ifPresent(target -> {
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
@@ -11,11 +12,13 @@ import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class ItemBlankScroll extends Item implements IWorkbenchItem {
|
||||
|
||||
public ItemBlankScroll(){
|
||||
this.setCreativeTab(WizardryTabs.WIZARDRY);
|
||||
this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,10 +48,14 @@ public class ItemBlankScroll extends Item implements IWorkbenchItem {
|
||||
int cost = spell.getCost() * centre.getStack().getCount();
|
||||
// Continuous spell scrolls require enough mana to cast them for the duration defined in ItemScroll.
|
||||
if(spell.isContinuous) cost *= ItemScroll.CASTING_TIME / 20;
|
||||
|
||||
int manaPerItem = Constants.MANA_PER_CRYSTAL;
|
||||
if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD;
|
||||
if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA;
|
||||
|
||||
if(crystals.getStack().getCount() * Constants.MANA_PER_CRYSTAL > cost){
|
||||
if(crystals.getStack().getCount() * manaPerItem > cost){
|
||||
// Rounds up to the nearest whole crystal
|
||||
crystals.decrStackSize(cost / Constants.MANA_PER_CRYSTAL + 1);
|
||||
crystals.decrStackSize(cost / manaPerItem + 1);
|
||||
centre.putStack(new ItemStack(WizardryItems.scroll, centre.getStack().getCount(), spell.metadata()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package electroblob.wizardry.item;
|
||||
import com.google.common.collect.Multimap;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.MagicDamage;
|
||||
import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
@@ -81,6 +82,12 @@ public class ItemFrostAxe extends ItemAxe implements IConjuredItem {
|
||||
stack.setItemDamage(damage + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multimap<String, AttributeModifier> getItemAttributeModifiers(EntityEquipmentSlot equipmentSlot){
|
||||
attackDamage = Spells.frost_axe.getProperty(Spell.DAMAGE).floatValue();
|
||||
return super.getItemAttributeModifiers(equipmentSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase wielder){
|
||||
if(!MagicDamage.isEntityImmune(DamageType.FROST, target))
|
||||
|
||||
@@ -81,7 +81,9 @@ public class ItemLightningHammer extends Item implements IConjuredItem {
|
||||
Multimap<String, AttributeModifier> multimap = super.getItemAttributeModifiers(slot);
|
||||
|
||||
if(slot == EntityEquipmentSlot.MAINHAND){
|
||||
multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", Spells.lightning_hammer.getProperty(Spell.DIRECT_DAMAGE).floatValue(), WizardryUtilities.Operations.ADD));
|
||||
float attackDamage = Spells.lightning_hammer.arePropertiesInitialised() ?
|
||||
Spells.lightning_hammer.getProperty(Spell.DIRECT_DAMAGE).floatValue() : 10; // Fallback for search tree init, value doesn't really matter
|
||||
multimap.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Weapon modifier", attackDamage, WizardryUtilities.Operations.ADD));
|
||||
multimap.put(SharedMonsterAttributes.ATTACK_SPEED.getName(), new AttributeModifier(ATTACK_SPEED_MODIFIER, "Weapon modifier", ATTACK_SPEED, WizardryUtilities.Operations.ADD));
|
||||
multimap.put(SharedMonsterAttributes.MOVEMENT_SPEED.getName(), new AttributeModifier(MOVEMENT_SPEED_MODIFIER, "Weapon modifier", MOVEMENT_SPEED_REDUCTION, WizardryUtilities.Operations.MULTIPLY_FLAT));
|
||||
}
|
||||
|
||||
@@ -13,16 +13,15 @@ import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.*;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ItemScroll extends Item implements ISpellCastingItem {
|
||||
|
||||
/** The maximum number of ticks a continuous spell scroll can be cast for (by holding the use item button). */
|
||||
@@ -33,6 +32,7 @@ public class ItemScroll extends Item implements ISpellCastingItem {
|
||||
setHasSubtypes(true);
|
||||
setMaxStackSize(16);
|
||||
setCreativeTab(WizardryTabs.SPELLS);
|
||||
this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,13 +47,14 @@ public class ItemScroll extends Item implements ISpellCastingItem {
|
||||
|
||||
@Override
|
||||
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
|
||||
|
||||
if(tab == WizardryTabs.SPELLS){
|
||||
// In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance
|
||||
// is not required, only the metadata.
|
||||
for(int i = 0; i < Spell.getTotalSpellCount(); i++){
|
||||
// i+1 is used so that the metadata ties up with the metadata() method. In other words, the none spell has metadata
|
||||
// 0 and since this is not used as a spell book the metadata starts at 1.
|
||||
list.add(new ItemStack(this, 1, i + 1));
|
||||
|
||||
List<Spell> spells = Spell.getAllSpells();
|
||||
spells.removeIf(s -> !s.applicableForItem(this));
|
||||
|
||||
for(Spell spell : spells){
|
||||
list.add(new ItemStack(this, 1, spell.metadata()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,6 +81,25 @@ public class ItemScroll extends Item implements ISpellCastingItem {
|
||||
return Wizardry.proxy.getScrollDisplayName(stack);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void addInformation(ItemStack itemstack, World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag advanced){
|
||||
|
||||
if(world != null){
|
||||
|
||||
Spell spell = Spell.byMetadata(itemstack.getItemDamage());
|
||||
|
||||
boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(spell, itemstack);
|
||||
|
||||
// Advanced tooltips display more information, mainly for searching purposes in creative
|
||||
if(discovered && advanced.isAdvanced()){ // No cheating!
|
||||
tooltip.add(spell.getTier().getDisplayName());
|
||||
tooltip.add(spell.getElement().getDisplayName());
|
||||
tooltip.add(spell.getType().getDisplayName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxItemUseDuration(ItemStack stack){
|
||||
|
||||
@@ -71,9 +71,10 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem {
|
||||
|
||||
if(!oldStack.isEmpty() || !newStack.isEmpty()){
|
||||
// We only care about the situation where we specifically want the animation NOT to play.
|
||||
if(oldStack.getItem() == newStack.getItem() && !slotChanged
|
||||
if(oldStack.getItem() == newStack.getItem() && !slotChanged)
|
||||
// This code should only run on the client side, so using Minecraft is ok.
|
||||
&& !net.minecraft.client.Minecraft.getMinecraft().player.isHandActive())
|
||||
// Why the heck was this here?
|
||||
//&& !net.minecraft.client.Minecraft.getMinecraft().player.isHandActive())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.WizardryGuiHandler;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
@@ -9,35 +11,41 @@ import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.*;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ItemSpellBook extends Item {
|
||||
|
||||
private static final Map<Tier, ResourceLocation> guiTextures = ImmutableMap.of(
|
||||
Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"),
|
||||
Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"),
|
||||
Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"),
|
||||
Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png"));
|
||||
|
||||
public ItemSpellBook(){
|
||||
super();
|
||||
setHasSubtypes(true);
|
||||
setMaxStackSize(16);
|
||||
setCreativeTab(WizardryTabs.SPELLS);
|
||||
this.addPropertyOverride(new ResourceLocation("festive"), (s, w, e) -> Wizardry.tisTheSeason ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
|
||||
|
||||
if(tab == WizardryTabs.SPELLS){
|
||||
// In this particular case, getTotalSpellCount() is a more efficient way of doing this since the spell instance
|
||||
// is not required, only the metadata.
|
||||
for(int i = 0; i < Spell.getTotalSpellCount(); i++){
|
||||
// i+1 is used so that the metadata ties up with the metadata() method. In other words, the none spell has metadata
|
||||
// 0 and since this is not used as a spell book the metadata starts at 1.
|
||||
list.add(new ItemStack(this, 1, i + 1));
|
||||
|
||||
List<Spell> spells = Spell.getAllSpells();
|
||||
spells.removeIf(s -> !s.applicableForItem(this));
|
||||
|
||||
for(Spell spell : spells){
|
||||
list.add(new ItemStack(this, 1, spell.metadata()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,10 +72,13 @@ public class ItemSpellBook extends Item {
|
||||
: "#\u00A79" + SpellGlyphData.getGlyphName(spell, world));
|
||||
|
||||
tooltip.add(spell.getTier().getDisplayNameWithFormatting());
|
||||
|
||||
// Advanced tooltips display more information, mainly for searching purposes in creative
|
||||
if(discovered && advanced.isAdvanced()){ // No cheating!
|
||||
tooltip.add(spell.getElement().getDisplayName());
|
||||
tooltip.add(spell.getType().getDisplayName());
|
||||
}
|
||||
}
|
||||
/* Removed to streamline the tooltip a bit. Information is now within the book. if(spell.isContinuous){
|
||||
* tooltip.add("\u00A79Mana Cost: " + spell.cost + " per second"); }else{ tooltip.add("\u00A79Mana Cost: " +
|
||||
* spell.cost); } */
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,4 +87,12 @@ public class ItemSpellBook extends Item {
|
||||
return Wizardry.proxy.getFontRenderer(stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GUI texture to be used when this spell book is opened.
|
||||
* @param spell The spell for the book being opened.
|
||||
*/
|
||||
public ResourceLocation getGuiTexture(Spell spell){
|
||||
return guiTextures.get(spell.getTier());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -73,6 +73,8 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
private static final int CONTINUOUS_TRACKING_INTERVAL = 20;
|
||||
/** The increase in progression for casting spells of the matching element. */
|
||||
private static final float ELEMENTAL_PROGRESSION_MODIFIER = 1.2f;
|
||||
/** The increase in progression for casting an undiscovered spell (can only happen once per spell for each player). */
|
||||
private static final float DISCOVERY_PROGRESSION_MODIFIER = 5f;
|
||||
/** The fraction of progression lost when all recently-cast spells are the same as the one being cast. */
|
||||
private static final float MAX_PROGRESSION_REDUCTION = 0.75f;
|
||||
|
||||
@@ -398,7 +400,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
if(MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Tick(Source.WAND, spell, caster, modifiers, castingTick))) return false;
|
||||
}
|
||||
|
||||
int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST));
|
||||
int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST) + 0.1f); // Weird floaty rounding
|
||||
|
||||
// As of wizardry 4.2 mana cost is only divided over two intervals each second
|
||||
if(spell.isContinuous) cost = getDistributedCost(cost, castingTick);
|
||||
@@ -434,7 +436,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
caster.setActiveHand(hand);
|
||||
|
||||
// Mana cost
|
||||
int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST));
|
||||
int cost = (int)(spell.getCost() * modifiers.get(SpellModifiers.COST) + 0.1f); // Weird floaty rounding
|
||||
// As of wizardry 4.2 mana cost is only divided over two intervals each second
|
||||
if(spell.isContinuous) cost = getDistributedCost(cost, castingTick);
|
||||
|
||||
@@ -495,7 +497,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
|
||||
int castingTick = stack.getMaxItemUseDuration() - timeLeft; // Might as well include this
|
||||
|
||||
int cost = getDistributedCost((int)(spell.getCost() * modifiers.get(SpellModifiers.COST)), castingTick);
|
||||
int cost = getDistributedCost((int)(spell.getCost() * modifiers.get(SpellModifiers.COST) + 0.1f), castingTick);
|
||||
|
||||
// Still need to check there's enough mana or the spell will finish twice, since running out of mana is
|
||||
// handled separately.
|
||||
@@ -573,6 +575,11 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
progressionModifier *= ELEMENTAL_PROGRESSION_MODIFIER;
|
||||
}
|
||||
|
||||
if(WizardData.get(player) != null && !WizardData.get(player).hasSpellBeenDiscovered(spell)){
|
||||
// Casting an undiscovered spell now grants 5x progression
|
||||
progressionModifier *= DISCOVERY_PROGRESSION_MODIFIER;
|
||||
}
|
||||
|
||||
modifiers.set(SpellModifiers.PROGRESSION, progressionModifier, false);
|
||||
|
||||
return modifiers;
|
||||
@@ -635,6 +642,8 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
// WandHelper.setProgression(centre.getStack(), WandHelper.getProgression(centre.getStack()) - tier.progression);
|
||||
// }
|
||||
|
||||
WandHelper.setProgression(centre.getStack(), 0);
|
||||
|
||||
ItemStack newWand = new ItemStack(WizardryItems.getWand(tier, this.element));
|
||||
newWand.setTagCompound(centre.getStack().getTagCompound());
|
||||
// This needs to be done after copying the tag compound so the mana capacity for the new wand
|
||||
|
||||
@@ -13,6 +13,8 @@ import electroblob.wizardry.registry.WizardryRecipes;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.enchantment.EnchantmentMending;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
@@ -57,12 +59,12 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
||||
}
|
||||
|
||||
/** Should only be used by vanilla's armour damage calculations; use {@link ItemWizardArmour#setMana(ItemStack, int)}
|
||||
* to modify wand mana from elsewhere. */
|
||||
* to modify armour mana from elsewhere. */
|
||||
@Override
|
||||
public void setDamage(ItemStack stack, int damage){
|
||||
// Overridden to stop repair things from 'repairing' the mana in wizard armour
|
||||
// This being armour, it's much easier to let its damage increase normally, but block it from being decreased
|
||||
if(stack.getItemDamage() < damage) super.setDamage(stack, damage);
|
||||
if(stack.getItemDamage() < damage) super.setDamage(stack, Math.min(damage, stack.getMaxDamage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,9 +180,14 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
||||
|
||||
String s = "wizard_armour";
|
||||
|
||||
if(this.element != null) s = s + "_" + this.element.getName();
|
||||
if(Wizardry.tisTheSeason){
|
||||
s = s + "_festive";
|
||||
}else{
|
||||
if(this.element != null) s = s + "_" + this.element.getName();
|
||||
if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) s = "legendary_" + s;
|
||||
}
|
||||
|
||||
if(slot == EntityEquipmentSlot.LEGS) s = s + "_legs";
|
||||
if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) s = "legendary_" + s;
|
||||
|
||||
return "ebwizardry:textures/armour/" + s + ".png";
|
||||
}
|
||||
@@ -189,7 +196,13 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
||||
public boolean getIsRepairable(ItemStack stack, ItemStack material){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// This is misleadingly-named, it also applies to enchanting with books at an anvil
|
||||
@Override
|
||||
public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment){
|
||||
return !(enchantment instanceof EnchantmentMending) && super.canApplyAtEnchantingTable(stack, enchantment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Properly handles the defence value of the armour. This method is responsible for the tooltip on top of
|
||||
* the armour value. It is also what handles armour toughness.
|
||||
@@ -325,7 +338,7 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
||||
IAttributeInstance attribute = event.getEntityLiving().getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE);
|
||||
double followRange = attribute == null ? 16 : attribute.getAttributeValue();
|
||||
if(event.getTarget().isSneaking()) followRange *= 0.8;
|
||||
float f = armourPieces / ((EntityPlayer)event.getTarget()).inventory.armorInventory.size();
|
||||
float f = (float)armourPieces / ((EntityPlayer)event.getTarget()).inventory.armorInventory.size();
|
||||
if(f < 0.1F) f = 0.1F;
|
||||
followRange *= (double)(0.7F * f);
|
||||
// Don't need to worry about the isSuitableTarget check since it must already have been checked to get this far
|
||||
|
||||
@@ -7,6 +7,7 @@ import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.ItemScroll;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.SpellProperties;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
@@ -16,9 +17,9 @@ import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.storage.loot.LootContext;
|
||||
import net.minecraft.world.storage.loot.conditions.LootCondition;
|
||||
import net.minecraft.world.storage.loot.functions.LootFunction;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
@@ -76,85 +77,94 @@ public class RandomSpell extends LootFunction {
|
||||
if(!(stack.getItem() instanceof ItemSpellBook) && !(stack.getItem() instanceof ItemScroll)) Wizardry.logger
|
||||
.warn("Applying the random_spell loot function to an item that isn't a spell book or scroll.");
|
||||
|
||||
Tier tier;
|
||||
Element element;
|
||||
|
||||
if(ignoreWeighting){
|
||||
if(tiers == null || tiers.isEmpty()){
|
||||
tier = Tier.values()[random.nextInt(Tier.values().length)];
|
||||
}else{
|
||||
tier = tiers.get(random.nextInt(tiers.size()));
|
||||
}
|
||||
}else{
|
||||
if(tiers == null || tiers.isEmpty()){
|
||||
tier = Tier.getWeightedRandomTier(random);
|
||||
}else{
|
||||
tier = Tier.getWeightedRandomTier(random, tiers.toArray(new Tier[0]));
|
||||
}
|
||||
}
|
||||
|
||||
// Elements aren't weighted
|
||||
if(elements == null || elements.isEmpty()){
|
||||
// Element can only be MAGIC if tier is NOVICE
|
||||
if(tier == Tier.NOVICE){
|
||||
element = Element.values()[random.nextInt(Element.values().length)];
|
||||
}else{
|
||||
Element[] elements = ArrayUtils.removeElement(Element.values(), Element.MAGIC);
|
||||
element = elements[random.nextInt(elements.length)];
|
||||
}
|
||||
}else{
|
||||
// In theory, swapping this line to the commented one should make absolutely no difference.
|
||||
element = elements.get(random.nextInt(elements.size()));
|
||||
// element = null;
|
||||
}
|
||||
|
||||
// Here's a thought: does randomly selecting the element beforehand (as opposed to leaving it null and letting
|
||||
// the spell randomiser use any element) change the overall outcome at all?
|
||||
List<Spell> spellsList = Spell.getSpells(new Spell.TierElementFilter(tier, element, SpellProperties.Context.TREASURE));
|
||||
|
||||
if(stack.getItem() instanceof ItemScroll) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.SCROLL));
|
||||
if(stack.getItem() instanceof ItemSpellBook) spellsList.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK));
|
||||
|
||||
// Ensures the tier chosen actually has spells in it, and if not uses NOVICE instead. NOVICE always has at least
|
||||
// the NONE spell since this spell cannot be disabled.
|
||||
// Commented out for now because it will interfere with the ability to specify tiers and elements.
|
||||
// To be honest, I may as well just say that if you disable enough spells to make this important, you deserve
|
||||
// less loot!
|
||||
/* if(spells.isEmpty()){ spellsList = Spell.getSpells(new Spell.TierElementFilter(EnumTier.NOVICE, null));
|
||||
* if(stack.getItem() instanceof ItemScroll) spellsList.retainAll(Spell.getSpells(Spell.nonContinuousSpells));
|
||||
* } */
|
||||
|
||||
if(spells != null && !spells.isEmpty()){
|
||||
spellsList.retainAll(spells);
|
||||
}
|
||||
SpellProperties.Context spellContext = context.getLootedEntity() == null ? SpellProperties.Context.TREASURE
|
||||
: SpellProperties.Context.LOOTING;
|
||||
|
||||
// This method is badly-named, loot chests pass a player through too, not just mobs
|
||||
// (And WHY does it only return an entity?! The underlying field is always a player so I'm casting it anyway)
|
||||
EntityPlayer player = (EntityPlayer)context.getKillerPlayer();
|
||||
|
||||
Spell spell = pickRandomSpell(stack, random, spellContext, player);
|
||||
|
||||
if(spell == Spells.none) Wizardry.logger.warn("Tried to apply the random_spell loot function to an item, but no"
|
||||
+ " enabled spells matched the criteria specified. Substituting placeholder (metadata 0) item.");
|
||||
|
||||
stack.setItemDamage(spell.metadata());
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private Spell pickRandomSpell(ItemStack stack, Random random, SpellProperties.Context spellContext, EntityPlayer player){
|
||||
|
||||
// We're now doing this first because we need to know which spells we have to play with before selecting a tier and element
|
||||
List<Spell> possibleSpells = Spell.getSpells(s -> s.isEnabled(spellContext) && s.applicableForItem(stack.getItem())
|
||||
// Remove excluded tiers/elements immediately (mainly because empty tier checks should account for excluded elements)
|
||||
&& (tiers == null || tiers.contains(s.getTier())) && (elements == null || elements.contains(s.getElement())));
|
||||
|
||||
if(spells != null && !spells.isEmpty()){
|
||||
possibleSpells.retainAll(spells); // Normally you wouldn't specify a spells list AND tiers/elements... but you could!
|
||||
}
|
||||
|
||||
if(stack.getItem() instanceof ItemScroll) possibleSpells.removeIf(s -> !s.isEnabled(SpellProperties.Context.SCROLL));
|
||||
if(stack.getItem() instanceof ItemSpellBook) possibleSpells.removeIf(s -> !s.isEnabled(SpellProperties.Context.BOOK));
|
||||
|
||||
// Select a tier...
|
||||
|
||||
List<Tier> possibleTiers = new ArrayList<>();
|
||||
|
||||
if(tiers == null || tiers.isEmpty()){
|
||||
possibleTiers.addAll(Arrays.asList(Tier.values()));
|
||||
}else{
|
||||
possibleTiers.addAll(tiers);
|
||||
}
|
||||
// Remove all empty tiers
|
||||
possibleTiers.removeIf(t -> possibleSpells.stream().noneMatch(s -> s.getTier() == t)); // Lambdaception!
|
||||
|
||||
if(possibleTiers.isEmpty()) return Spells.none; // Gotta disable a lot of spells for this to happen
|
||||
|
||||
Tier tier = ignoreWeighting ? possibleTiers.get(random.nextInt(possibleTiers.size()))
|
||||
: Tier.getWeightedRandomTier(random, possibleTiers.toArray(new Tier[0]));
|
||||
|
||||
// Remove all spells that aren't of the selected tier
|
||||
possibleSpells.removeIf(s -> s.getTier() != tier);
|
||||
if(possibleSpells.isEmpty()) return Spells.none; // Should be caught by the no-elements check but we might as well
|
||||
|
||||
// Select an element...
|
||||
|
||||
List<Element> possibleElements = new ArrayList<>();
|
||||
|
||||
// Elements aren't weighted
|
||||
if(elements == null || elements.isEmpty()){
|
||||
possibleElements.addAll(Arrays.asList(Element.values()));
|
||||
}else{
|
||||
possibleElements.addAll(elements);
|
||||
}
|
||||
// Remove all empty elements
|
||||
possibleElements.removeIf(e -> possibleSpells.stream().noneMatch(s -> s.getElement() == e));
|
||||
|
||||
if(possibleElements.isEmpty()) return Spells.none; // A bit more likely I guess, but still pretty unlikely
|
||||
|
||||
Element element = possibleElements.get(random.nextInt(possibleElements.size()));
|
||||
|
||||
// Remove all spells that aren't of the selected tier
|
||||
possibleSpells.removeIf(s -> s.getElement() != element);
|
||||
if(possibleSpells.isEmpty()) return Spells.none; // If it fails anywhere, it'll most likely be here
|
||||
|
||||
// Remove either the undiscovered spells or the discovered ones, depending on the bias
|
||||
if(undiscoveredBias > 0 && player != null){
|
||||
|
||||
WizardData data = WizardData.get(player);
|
||||
|
||||
int discoveredCount = (int)spellsList.stream().filter(data::hasSpellBeenDiscovered).count();
|
||||
int discoveredCount = (int)possibleSpells.stream().filter(data::hasSpellBeenDiscovered).count();
|
||||
// If none have been discovered or they've all been discovered, don't bother!
|
||||
if(discoveredCount > 0 && discoveredCount < spellsList.size()){
|
||||
if(discoveredCount > 0 && discoveredCount < possibleSpells.size()){
|
||||
// Kinda unintuitive but it's very neat!
|
||||
boolean keepDiscovered = random.nextFloat() < 0.5f + 0.5f * undiscoveredBias;
|
||||
spellsList.removeIf(s -> keepDiscovered != data.hasSpellBeenDiscovered(s));
|
||||
possibleSpells.removeIf(s -> keepDiscovered != data.hasSpellBeenDiscovered(s));
|
||||
}
|
||||
}
|
||||
|
||||
if(spellsList.isEmpty()){
|
||||
Wizardry.logger.warn("Tried to apply the random_spell loot function to an item, but no enabled spells"
|
||||
+ "matched the criteria specified. Substituting placeholder (metadata 0) item.");
|
||||
stack.setItemDamage(0);
|
||||
}else{
|
||||
stack.setItemDamage(spellsList.get(random.nextInt(spellsList.size())).metadata());
|
||||
}
|
||||
|
||||
return stack;
|
||||
return possibleSpells.get(random.nextInt(possibleSpells.size())); // Finally pick a spell
|
||||
}
|
||||
|
||||
public static class Serializer extends LootFunction.Serializer<RandomSpell> {
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.entity.living.ISpellCaster;
|
||||
import electroblob.wizardry.item.ItemScroll;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
@@ -33,13 +34,18 @@ public class WizardSpell extends LootFunction {
|
||||
@Override
|
||||
public ItemStack apply(ItemStack stack, Random random, LootContext context){
|
||||
|
||||
if(!(stack.getItem() instanceof ItemSpellBook)) Wizardry.logger
|
||||
if(!(stack.getItem() instanceof ItemSpellBook) && !(stack.getItem() instanceof ItemScroll)) Wizardry.logger
|
||||
.warn("Applying the wizard_spell loot function to an item that isn't a spell book or scroll.");
|
||||
|
||||
if(context.getLootedEntity() instanceof ISpellCaster){
|
||||
List<Spell> spells = ((ISpellCaster)context.getLootedEntity()).getSpells();
|
||||
spells.remove(Spells.magic_missile); // Can't drop magic missile
|
||||
stack.setItemDamage(spells.get(random.nextInt(spells.size())).metadata());
|
||||
spells.removeIf(s -> !s.applicableForItem(stack.getItem()));
|
||||
if(spells.isEmpty()){
|
||||
Wizardry.logger.warn("Tried to apply the wizard_spell loot function to an item, but none of the looted entity's spells were applicable for that item. This is probably a bug!");
|
||||
}else{
|
||||
stack.setItemDamage(spells.get(random.nextInt(spells.size())).metadata());
|
||||
}
|
||||
}else{
|
||||
Wizardry.logger.warn("Applying the wizard_spell loot function to an entity that isn't a spell caster.");
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public class BehaviourSpellDispense extends BehaviorDispenseOptional {
|
||||
if(world.isSideSolid(source.getBlockPos().offset(direction), direction.getOpposite())) return stack;
|
||||
|
||||
// If the scroll can never be cast by a dispenser, it should be dispensed as an item.
|
||||
if(!spell.canBeCastByDispensers()) return super.dispenseStack(source, stack);
|
||||
if(!spell.canBeCastBy(source.getBlockTileEntity())) return super.dispenseStack(source, stack);
|
||||
|
||||
SpellModifiers modifiers = new SpellModifiers();
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ public abstract class Forfeit {
|
||||
|
||||
event.setCanceled(true);
|
||||
|
||||
Forfeit forfeit = getRandomForfeit(event.getWorld().rand, event.getSpell().getTier(), event.getSpell().getElement());
|
||||
Forfeit forfeit = getRandomForfeit(data.synchronisedRandom, event.getSpell().getTier(), event.getSpell().getElement());
|
||||
|
||||
if(forfeit == null){ // Should never happen, but just in case...
|
||||
if(!event.getWorld().isRemote) player.sendMessage(new TextComponentTranslation("forfeit.ebwizardry:do_nothing"));
|
||||
@@ -375,7 +375,7 @@ public abstract class Forfeit {
|
||||
if(!w.isRemote){
|
||||
for(EnumFacing direction : EnumFacing.HORIZONTALS){
|
||||
BlockPos pos = p.getPosition().offset(direction);
|
||||
w.setBlockState(pos, WizardryBlocks.snare.getDefaultState());
|
||||
if(WizardryUtilities.canBlockBeReplaced(w, pos)) w.setBlockState(pos, WizardryBlocks.snare.getDefaultState());
|
||||
}
|
||||
}
|
||||
}));
|
||||
@@ -410,6 +410,7 @@ public abstract class Forfeit {
|
||||
if(!w.isRemote){
|
||||
List<BlockPos> sphere = WizardryUtilities.getBlockSphere(p.getPosition(), 4);
|
||||
sphere.removeIf(pos -> !w.getBlockState(pos).isFullCube());
|
||||
sphere.removeIf(pos -> WizardryUtilities.isBlockUnbreakable(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));
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package electroblob.wizardry.misc;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.item.IManaStoringItem;
|
||||
import electroblob.wizardry.item.ItemManaFlask;
|
||||
import net.minecraft.inventory.InventoryCrafting;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.CraftingManager;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
import net.minecraftforge.oredict.ShapelessOreRecipe;
|
||||
|
||||
/**
|
||||
* Implements a dynamic crafting recipe for recharging items with mana flasks.
|
||||
*
|
||||
* @author Corail31, Electroblob
|
||||
* @since Wizardry 4.2.2
|
||||
*/
|
||||
@Mod.EventBusSubscriber
|
||||
public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
|
||||
|
||||
private final IManaStoringItem chargeable;
|
||||
private final ItemManaFlask flask;
|
||||
|
||||
/**
|
||||
* Creates a new charging recipe for the given chargeable item using the given flask item.
|
||||
* @param chargeable The type of item to be charged
|
||||
* @param flask The mana flask used to charge the item
|
||||
*/
|
||||
public RecipeRechargeWithFlask(Item chargeable, ItemManaFlask flask){
|
||||
super(null, new ItemStack(chargeable, 1, OreDictionary.WILDCARD_VALUE),
|
||||
new ItemStack(chargeable, 1, OreDictionary.WILDCARD_VALUE), flask);
|
||||
if(!(chargeable instanceof IManaStoringItem)) throw new IllegalArgumentException("Item to be charged must be an instance of IManaStoringItem");
|
||||
this.chargeable = (IManaStoringItem)chargeable;
|
||||
this.flask = flask;
|
||||
}
|
||||
|
||||
// Commented out for now because JEI spams the log with errors about the recipe having no output
|
||||
// @Nonnull
|
||||
// @Override
|
||||
// public ItemStack getRecipeOutput(){
|
||||
// return ItemStack.EMPTY; // According to the javadoc, dynamic recipes are supposed to return an empty stack here
|
||||
// }
|
||||
|
||||
@Override
|
||||
public ItemStack getCraftingResult(InventoryCrafting inv){
|
||||
ItemStack result = super.getCraftingResult(inv);
|
||||
rechargeItemAndCopyNBT(result, inv);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(InventoryCrafting inv, World world){
|
||||
ItemStack stack = findItemToCharge(inv);
|
||||
if(!stack.isEmpty() && chargeable.isManaFull(stack)) return false;
|
||||
return super.matches(inv, world);
|
||||
}
|
||||
|
||||
private void rechargeItemAndCopyNBT(ItemStack toCharge, InventoryCrafting inv){
|
||||
if(toCharge.getItem() == chargeable){
|
||||
ItemStack stack = findItemToCharge(inv);
|
||||
if(!stack.isEmpty()) chargeable.setMana(toCharge, chargeable.getMana(stack));
|
||||
chargeable.rechargeMana(toCharge, flask.size.capacity);
|
||||
toCharge.setTagCompound(stack.getTagCompound()); // Copy NBT to new stack
|
||||
}else{
|
||||
Wizardry.logger.warn("Tried to recharge item {} with mana flask, but it did not match the recipe result {}!", toCharge.getItem(), chargeable);
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack findItemToCharge(InventoryCrafting inv){
|
||||
for(int i=0; i<inv.getSizeInventory(); i++){
|
||||
ItemStack ingredient = inv.getStackInSlot(i);
|
||||
if(ingredient.getItem() == chargeable) return ingredient;
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDynamic(){
|
||||
return true; // Stops it appearing in the recipe book
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onItemCraftedEvent(PlayerEvent.ItemCraftedEvent event){
|
||||
// getCraftingResult seems to only work for the result that's displayed, not once it is actually taken
|
||||
// This means that although I no longer have to replace the result every tick, I still need to do it here
|
||||
// ... I thought the whole point of the new recipe system was so that I DIDN'T have to do this?!
|
||||
if(event.craftMatrix instanceof InventoryCrafting){
|
||||
for(IRecipe recipe : CraftingManager.REGISTRY){
|
||||
if(recipe instanceof RecipeRechargeWithFlask
|
||||
&& recipe.matches((InventoryCrafting)event.craftMatrix, event.player.world)){
|
||||
// Have to modify the itemstack in the actual event, it cannot be replaced
|
||||
((RecipeRechargeWithFlask)recipe).rechargeItemAndCopyNBT(event.crafting, (InventoryCrafting)event.craftMatrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package electroblob.wizardry.misc;
|
||||
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.village.MerchantRecipe;
|
||||
import net.minecraft.village.MerchantRecipeList;
|
||||
import net.minecraftforge.oredict.OreDictionary;
|
||||
@@ -46,12 +48,42 @@ public class WildcardTradeList extends MerchantRecipeList {
|
||||
}
|
||||
|
||||
private boolean areItemStacksExactlyEqual(ItemStack stack1, ItemStack stack2){
|
||||
// Added to allow wildcards; this line is the only actual change.
|
||||
// Added to allow wildcards
|
||||
if((stack1.getItemDamage() == OreDictionary.WILDCARD_VALUE || stack2.getItemDamage() == OreDictionary.WILDCARD_VALUE)
|
||||
// Can't use ItemStack.areItemsEqualIgnoreDurability because that only works for items with durability, not subtypes.
|
||||
&& stack1.getItem() == stack2.getItem()) return true;
|
||||
|
||||
return ItemStack.areItemsEqual(stack1, stack2) && (!stack2.hasTagCompound() || stack1.hasTagCompound() && NBTUtil.areNBTEquals(stack2.getTagCompound(), stack1.getTagCompound(), false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToBuf(PacketBuffer buffer){
|
||||
|
||||
buffer.writeByte((byte)(this.size() & 255));
|
||||
|
||||
// Trick the client into thinking this is a normal item
|
||||
for(MerchantRecipe merchantrecipe : this){
|
||||
|
||||
ItemStack itemToBuy = merchantrecipe.getItemToBuy();
|
||||
if(itemToBuy.getMetadata() == OreDictionary.WILDCARD_VALUE) itemToBuy = WizardryUtilities.copyWithMeta(itemToBuy, 0);
|
||||
buffer.writeItemStack(itemToBuy);
|
||||
|
||||
ItemStack itemToSell = merchantrecipe.getItemToSell();
|
||||
if(itemToSell.getMetadata() == OreDictionary.WILDCARD_VALUE) itemToSell = WizardryUtilities.copyWithMeta(itemToSell, 0);
|
||||
buffer.writeItemStack(itemToSell);
|
||||
|
||||
ItemStack secondItemToBuy = merchantrecipe.getSecondItemToBuy();
|
||||
buffer.writeBoolean(!secondItemToBuy.isEmpty());
|
||||
|
||||
if(!secondItemToBuy.isEmpty()){
|
||||
if(secondItemToBuy.getMetadata() == OreDictionary.WILDCARD_VALUE) secondItemToBuy = WizardryUtilities.copyWithMeta(secondItemToBuy, 0);
|
||||
buffer.writeItemStack(secondItemToBuy);
|
||||
}
|
||||
|
||||
buffer.writeBoolean(merchantrecipe.isRecipeDisabled());
|
||||
buffer.writeInt(merchantrecipe.getToolUses());
|
||||
buffer.writeInt(merchantrecipe.getMaxTradeUses());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
package electroblob.wizardry.packet;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||
|
||||
/** <b>[Server -> Client]</b> This packet is sent when the slow time potion effect expires or is removed from an
|
||||
* entity to unblock all nearby entities' updates. */
|
||||
public class PacketEndSlowTime implements IMessageHandler<PacketEndSlowTime.Message, IMessage> {
|
||||
|
||||
@Override
|
||||
public IMessage onMessage(Message message, MessageContext ctx){
|
||||
|
||||
// Just to make sure that the side is correct
|
||||
if(ctx.side.isClient()){
|
||||
net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(() -> Wizardry.proxy.handleEndSlowTimePacket(message));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class Message implements IMessage {
|
||||
|
||||
public int hostID;
|
||||
|
||||
// This constructor is required otherwise you'll get errors (used somewhere in fml through reflection)
|
||||
public Message(){
|
||||
}
|
||||
|
||||
public Message(Entity host){
|
||||
this.hostID = host.getEntityId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf){
|
||||
this.hostID = buf.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf){
|
||||
buf.writeInt(hostID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ public class PacketSyncSettings implements IMessageHandler<Message, IMessage> {
|
||||
Wizardry.settings.discoveryMode = message.settings.discoveryMode;
|
||||
Wizardry.settings.creativeBypassesArcaneLock = message.settings.creativeBypassesArcaneLock;
|
||||
Wizardry.settings.slowTimeAffectsPlayers = message.settings.slowTimeAffectsPlayers;
|
||||
Wizardry.settings.replaceVanillaFireballs = message.settings.replaceVanillaFireballs;
|
||||
Wizardry.settings.forfeitChance = message.settings.forfeitChance;
|
||||
}
|
||||
|
||||
@@ -56,6 +57,7 @@ public class PacketSyncSettings implements IMessageHandler<Message, IMessage> {
|
||||
settings.discoveryMode = buf.readBoolean();
|
||||
settings.creativeBypassesArcaneLock = buf.readBoolean();
|
||||
settings.slowTimeAffectsPlayers = buf.readBoolean();
|
||||
settings.replaceVanillaFireballs = buf.readBoolean();
|
||||
settings.forfeitChance = buf.readFloat();
|
||||
}
|
||||
|
||||
@@ -64,6 +66,7 @@ public class PacketSyncSettings implements IMessageHandler<Message, IMessage> {
|
||||
buf.writeBoolean(settings.discoveryMode);
|
||||
buf.writeBoolean(settings.creativeBypassesArcaneLock);
|
||||
buf.writeBoolean(settings.slowTimeAffectsPlayers);
|
||||
buf.writeBoolean(settings.replaceVanillaFireballs);
|
||||
buf.writeFloat((float)settings.forfeitChance); // Configs don't have floats but this can only be 0-1 anyway
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ public class WizardryPacketHandler {
|
||||
registerMessage(PacketSpellProperties.class, PacketSpellProperties.Message.class);
|
||||
registerMessage(PacketSyncAdvancements.class, PacketSyncAdvancements.Message.class);
|
||||
registerMessage(PacketRequestAdvancementSync.class, PacketRequestAdvancementSync.Message.class);
|
||||
registerMessage(PacketEndSlowTime.class, PacketEndSlowTime.Message.class);
|
||||
registerMessage(PacketResurrection.class, PacketResurrection.Message.class);
|
||||
registerMessage(PacketCastSpellAtPos.class, PacketCastSpellAtPos.Message.class);
|
||||
registerMessage(PacketEmitterData.class, PacketEmitterData.Message.class);
|
||||
|
||||
@@ -52,7 +52,7 @@ public interface ISyncedPotion {
|
||||
@SubscribeEvent
|
||||
public static void onPotionExpiryEvent(PotionEvent.PotionExpiryEvent event){
|
||||
|
||||
if(event.getPotionEffect().getPotion() instanceof ISyncedPotion
|
||||
if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() instanceof ISyncedPotion
|
||||
&& ((ISyncedPotion)event.getPotionEffect().getPotion()).shouldSync(event.getEntityLiving())){
|
||||
|
||||
if(!event.getEntityLiving().world.isRemote){
|
||||
@@ -67,7 +67,7 @@ public interface ISyncedPotion {
|
||||
@SubscribeEvent
|
||||
public static void onPotionRemoveEvent(PotionEvent.PotionRemoveEvent event){
|
||||
|
||||
if(event.getPotionEffect().getPotion() instanceof ISyncedPotion
|
||||
if(event.getPotionEffect() != null && event.getPotionEffect().getPotion() instanceof ISyncedPotion
|
||||
&& ((ISyncedPotion)event.getPotionEffect().getPotion()).shouldSync(event.getEntityLiving())){
|
||||
|
||||
if(!event.getEntityLiving().world.isRemote){
|
||||
|
||||
@@ -2,6 +2,7 @@ package electroblob.wizardry.potion;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.util.NBTExtras;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
@@ -40,7 +41,7 @@ public class PotionContainment extends PotionMagicEffect {
|
||||
|
||||
// Initialise the containment position to the entity's position if it wasn't set already
|
||||
if(!target.getEntityData().hasKey(ENTITY_TAG)){
|
||||
target.getEntityData().setTag(ENTITY_TAG, NBTUtil.createPosTag(new BlockPos(target.getPositionVector().subtract(0.5, 0.5, 0.5))));
|
||||
NBTExtras.storeTagSafely(target.getEntityData(), ENTITY_TAG, NBTUtil.createPosTag(new BlockPos(target.getPositionVector().subtract(0.5, 0.5, 0.5))));
|
||||
}
|
||||
|
||||
Vec3d origin = WizardryUtilities.getCentre(NBTUtil.getPosFromTag(target.getEntityData().getCompoundTag(ENTITY_TAG)));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user